PageSourceSearch

https://prextra.com/wp-content/themes/cdid/assets/dist/js/bundle.js?ver=1771519431

js prextra.com collected 2026-09-26 18:23:25 UTC 1,174,480 bytes, 2 lines download raw bytes

1"use strict";function _typeof(n){return(_typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n})(n)}!function(t){var r={};function o(n){if(r[n])return r[n].exports;var e=r[n]={i:n,l:!1,exports:{}};return t[n].call(e.exports,e,e.exports,o),e.l=!0,e.exports}o.m=t,o.c=r,o.d=function(n,e,t){o.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:t})},o.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},o.t=function(e,n){if(1&n&&(e=o(e)),8&n)return e;if(4&n&&"object"===_typeof(e)&&e&&e.__esModule)return e;var t=Object.create(null);if(o.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)o.d(t,r,function(n){return e[n]}.bind(null,r));return t},o.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return o.d(e,"a",e),e},o.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},o.p="",o(o.s="./assets/src/js/main.js")}({
1"./assets/src/js/main.js":function assetsSrcJsMainJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "filters", function() { return filters; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "marquee", function() { return marquee; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "scroll", function() { return scroll; });\n/* harmony import */ var _libraries_prx_filters_prx_filters__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../../libraries/prx-filters/prx-filters */ "./libraries/prx-filters/prx-filters.js");\n/* harmony import */ var _libraries_prx_marquee_prx_marquee__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../../libraries/prx-marquee/prx-marquee */ "./libraries/prx-marquee/prx-marquee.js");\n/* harmony import */ var _libraries_prx_scroll_prx_scroll__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../libraries/prx-scroll/prx-scroll */ "./libraries/prx-scroll/prx-scroll.js");\n/* harmony import */ var _modules_gsap_eases__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./modules/gsap/eases */ "./assets/src/js/modules/gsap/eases.js");\n/* harmony import */ var _modules_gsap_intro__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./modules/gsap/intro */ "./assets/src/js/modules/gsap/intro.js");\n/* harmony import */ var _modules_gsap_curtain__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./modules/gsap/curtain */ "./assets/src/js/modules/gsap/curtain.js");\n/* harmony import */ var _modules_gsap_scrollTrigger__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./modules/gsap/scrollTrigger */ "./assets/src/js/modules/gsap/scrollTrigger.js");\n/* harmony import */ var _modules_gsap_features__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./modules/gsap/features */ "./assets/src/js/modules/gsap/features.js");\n/* harmony import */ var _modules_accordion__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./modules/accordion */ "./assets/src/js/modules/accordion.js");\n/* harmony import */ var _modules_carousel__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./modules/carousel */ "./assets/src/js/modules/carousel.js");\n/* harmony import */ var _modules_cf7__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./modules/cf7 */ "./assets/src/js/modules/cf7.js");
1\n/* harmony import */ var _modules_cursor__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./modules/cursor */ "./assets/src/js/modules/cursor.js");\n/* harmony import */ var _modules_file__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./modules/file */ "./assets/src/js/modules/file.js");\n/* harmony import */ var _modules_helper__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./modules/helper */ "./assets/src/js/modules/helper.js");\n/* harmony import */ var _modules_menus__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./modules/menus */ "./assets/src/js/modules/menus.js");\n/* harmony import */ var _modules_inclusion__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./modules/inclusion */ "./assets/src/js/modules/inclusion.js");\n/* harmony import */ var _modules_footer__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./modules/footer */ "./assets/src/js/modules/footer.js");\n/* harmony import */ var _modules_aside__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./modules/aside */ "./assets/src/js/modules/aside.js");\n/* harmony import */ var _modules_media__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./modules/media */ "./assets/src/js/modules/media.js");\n/* harmony import */ var _modules_blogFilters__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./modules/blogFilters */ "./assets/src/js/modules/blogFilters.js");\n/* harmony import */ var _modules_section__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./modules/section */ "./assets/src/js/modules/section.js");\n/* harmony import */ var _modules_matter__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ./modules/matter */ "./assets/src/js/modules/matter.js");\n/* harmony import */ var _modules_job__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ./modules/job */ "./assets/src/js/modules/job.js");\n/*\r\n * Import librairies\r\n */\r\n\r\n\r\n\r\n\r\n/*\r\n * Import modules\r\n */\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n/*\r\n * Init librairies\r\n */\r\ngsap.registerPlugin(DrawSVGPlugin);\r\n\r\ngsap.config({\r\n\tnullTargetWarn: false,\r\n\ttrialWarn: false,\r\n});\r\n\r\n// Prx Filters\r\nvar filtersInstance;\r\n\r\nif (options.activate_prx_filters) {\r\n\tfiltersInstance = new _libraries_prx_filters_prx_filters__WEBPACK_IMPORTED_MODULE_0__["PrxFilters"]();\r\n}\r\n\r\nconst filters = filtersInstance;\r\n\r\n// Prx Marquee\r\nvar marqueeInstance;\r\n\r\nif (options.activate_prx_marquee) {\r\n\tmarqueeInstance = new _libraries_prx_marquee_prx_marquee__WEBPACK_IMPORTED_MODULE_1__["PrxMarquee"]();\r\n}\r\n\r\nconst marquee = marqueeInstance;\r\n\r\n// Prx Scroll\r\nvar scrollInstance;\r\n\r\nif (options.activate_prx_scroll) {\r\n\tscrollInstance = new _libraries_prx_scroll_prx_scroll__WEBPACK_IMPORTED_MODULE_2__["PrxScroll"]();\r\n}\r\n\r\nconst scroll = scrollInstance;\r\n\r\n/*\r\n * Init modules\r\n */\r\n\r\nif (options.activate_gsap) {\r\n\tObject(_modules_gsap_eases__WEBPACK_IMPORTED_MODULE_3__["default"])();\r\n\tObject(_modules_gsap_intro__WEBPACK_IMPORTED_MODULE_4__["default"])();\r\n\tObject(_modules_gsap_curtain__WEBPACK_IMPORTED_MODULE_5__["default"])();\r\n\tObject(_modules_gsap_scrollTrigger__WEBPACK_IMPORTED_MODULE_6__["default"])();\r\n\tObject(_modules_gsap_features__WEBPACK_IMPORTED_MODULE_7__["default"])();\r\n}\r\nObject(_modules_accordion__WEBPACK_IMPORTED_MODULE_8__["default"])();\r\nif (options.activate_flickity) {\r\n\tObject(_modules_carousel__WEBPACK_IMPORTED_MODULE_9__["default"])();\r\n}\r\nObject(_modules_cf7__WEBPACK_IMPORTED_MODULE_10__["default"])();
1\r\nObject(_modules_cursor__WEBPACK_IMPORTED_MODULE_11__["default"])();\r\nObject(_modules_file__WEBPACK_IMPORTED_MODULE_12__["default"])();\r\nObject(_modules_helper__WEBPACK_IMPORTED_MODULE_13__["default"])();\r\nObject(_modules_menus__WEBPACK_IMPORTED_MODULE_14__["default"])();\r\nObject(_modules_inclusion__WEBPACK_IMPORTED_MODULE_15__["default"])();\r\nObject(_modules_footer__WEBPACK_IMPORTED_MODULE_16__["default"])();\r\nObject(_modules_aside__WEBPACK_IMPORTED_MODULE_17__["default"])();\r\nObject(_modules_media__WEBPACK_IMPORTED_MODULE_18__["default"])();\r\nObject(_modules_blogFilters__WEBPACK_IMPORTED_MODULE_19__["default"])();\r\nObject(_modules_matter__WEBPACK_IMPORTED_MODULE_21__["default"])();\r\nObject(_modules_section__WEBPACK_IMPORTED_MODULE_20__["default"])();\r\nObject(_modules_job__WEBPACK_IMPORTED_MODULE_22__["default"])();\n\n//# sourceURL=webpack:///./assets/src/js/main.js?')},
1"./assets/src/js/modules/accordion.js":function assetsSrcJsModulesAccordionJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/**\r\n * Adds basic functionality to the accordion component.\r\n *\r\n * @link   https://lesprx.monday.com/docs/4822735351?blockId=93a6f639-566e-45ac-a363-b623d1e75f36\r\n * @author Les Prétentieux\r\n */\r\n\r\n/* harmony default export */ __webpack_exports__["default"] = (function () {\r\n\tvar $ = jQuery;\r\n\r\n\tinit();\r\n\r\n\t/**\r\n\t * Initializes accordions when the window has been loaded.\r\n\t */\r\n\t$(window).on("load", function () {\r\n\t\tinit();\r\n\t});\r\n\r\n\t/**\r\n\t * Initializes accordions when the window resizes.\r\n\t */\r\n\t$(window).resize(function () {\r\n\t\tinit();\r\n\t});\r\n\r\n\t/**\r\n\t * Toggles the accordion state when the accordion head is clicked.\r\n\t */\r\n\t$(".c-accordion_head").click(function () {\r\n\t\tvar $component = $(this).closest(".c-accordion");\r\n\r\n\t\t$component.toggleClass("is-expanded");\r\n\t\t$component.attr("aria-expanded", $component.attr("aria-expanded") == "true" ? "false" : "true");\r\n\t});\r\n\r\n\t/**\r\n\t * Sets the accordions body height.\r\n\t */\r\n\tfunction init() {\r\n\t\t$(".c-accordion").each(function () {\r\n\t\t\tvar $component = $(this);\r\n\t\t\tvar $content = $(this).find(".c-accordion_content");\r\n\r\n\t\t\t$component[0].style.setProperty("--height", $content.outerHeight() + "px");\r\n\t\t});\r\n\t}\r\n});\r\n\n\n//# sourceURL=webpack:///./assets/src/js/modules/accordion.js?')},
1"./assets/src/js/modules/aside.js":function assetsSrcJsModulesAsideJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (function () {\n\tvar $ = jQuery;\n\n\t$(".c-share_button").click(function () {\n\t\t$(".c-share").toggleClass("-toggled");\n\t});\n\n\t$(".o-section h3").each(function (index) {\n\t\tif ($(this).html() !== "Postuler à l\'offre") {\n\t\t\t$(".o-section_aside ul").append("<a href=\'#section" + index + "\' class=\'c-anchor\' data-scroll-anchor>" + $(this).html() + "</a>");\n\t\t}\n\t});\n\n\t$(".o-section_content.-post h3").each(function (index) {\n\t\t$(this).attr("id", "section" + index + "");\n\t});\n\n\t// Anchors\n\n\t// $(document).ready(function () {\n\t// \t$(".c-anchor").each(function () {\n\t// \t\tvar href = $(this).attr("href");\n\t// \t\tvar $this = $(this);\n\t// \t\tvar $prev = $this.prev();\n\t// \t\tvar $next = $this.next();\n\n\t// \t\tconsole.log(href);\n\n\t// \t\tScrollTrigger.create({\n\t// \t\t\ttrigger: href,\n\t// \t\t\tstart: "top 25",\n\n\t// \t\t\tonLeave: function () {\n\t// \t\t\t\ttoggleSection($next);\n\t// \t\t\t},\n\n\t// \t\t\tonLeaveBack: function () {\n\t// \t\t\t\ttoggleSection($prev);\n\t// \t\t\t},\n\n\t// \t\t\tonEnter: function () {\n\t// \t\t\t\ttoggleSection($this);\n\t// \t\t\t},\n\n\t// \t\t\tonEnterBack: function () {\n\t// \t\t\t\ttoggleSection($this);\n\t// \t\t\t},\n\t// \t\t});\n\t// \t});\n\t// });\n\n\t// function toggleSection($activeSection) {\n\t// \t$(".c-anchor").removeClass("-active");\n\t// \t$activeSection.addClass("-active");\n\t// }\n});\n\n\n//# sourceURL=webpack:///./assets/src/js/modules/aside.js?')},
1"./assets/src/js/modules/blogFilters.js":function assetsSrcJsModulesBlogFiltersJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (function () {\n\tvar $ = jQuery;\n\n\t$(".c-filter").click(function () {\n\t\t$(".c-filter").removeClass("-active");\n\t\t$(this).addClass("-active");\n\t});\n});\n\n\n//# sourceURL=webpack:///./assets/src/js/modules/blogFilters.js?')},
1"./assets/src/js/modules/carousel.js":function assetsSrcJsModulesCarouselJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/**\r\n * Flickity carousels helpers and extends functions.\r\n *\r\n * @link   https://lesprx.monday.com/docs/2595799162?blockId=57c17c4b-b1a1-4910-a48b-adb4c6c6e800\r\n * @author Les Prétentieux\r\n */\r\n\r\n/* harmony default export */ __webpack_exports__["default"] = (function () {\r\n\tvar $ = jQuery;\r\n\r\n\t/**\r\n\t * Resizes the carousels when document is ready\r\n\t */\r\n\t$(document).ready(function () {\r\n\t\tresizeCarousels();\r\n\t});\r\n\r\n\t/**\r\n\t * Resizes the carousels when window is loaded\r\n\t * and updates carousel buttons\r\n\t */\r\n\t$(window).on("load", function () {\r\n\t\tresizeCarousels();\r\n\t\tupdateCarouselsActions();\r\n\t\tcarouselDots();\r\n\t});\r\n\r\n\t/**\r\n\t * Updates carousel buttons when window resizes\r\n\t */\r\n\t$(window).on("resize", function () {\r\n\t\tupdateCarouselsActions();\r\n\t});\r\n\r\n\t/**\r\n\t * Disables the carousel\'s cells pointers events to prevent user from clicking the cell while dragging\r\n\t */\r\n\t$(".o-carousel").each(function () {\r\n\t\t$(this).on("dragStart.flickity", () =>
1 $(this).find(".o-carousel_cell").css("pointer-events", "none"));\r\n\t\t$(this).on("dragEnd.flickity", () => $(this).find(".o-carousel_cell").css("pointer-events", "all"));\r\n\t});\r\n\r\n\t/**\r\n\t * Selects the carousel\'s previous cell and stops the autoplay\r\n\t */\r\n\t$(".o-carousel_btn.-prev").on("click", function () {\r\n\t\tvar $actions = $(this).closest(".o-carousel_actions");\r\n\t\tvar carouselID = $actions.data("carousel-for");\r\n\t\tvar $carousel = $(\'.o-carousel[data-carousel-id="\' + carouselID + \'"]\');\r\n\t\tvar flkty = Flickity.data($carousel[0]);\r\n\t\tflkty.previous();\r\n\t\tflkty.stopPlayer();\r\n\t});\r\n\r\n\t/**\r\n\t * Selects the carousel\'s next cell and stops the autoplay\r\n\t */\r\n\t$(".o-carousel_btn.-next").on("click", function () {\r\n\t\tvar $actions = $(this).closest(".o-carousel_actions");\r\n\t\tvar carouselID = $actions.data("carousel-for");\r\n\t\tvar $carousel = $(\'.o-carousel[data-carousel-id="\' + carouselID + \'"]\');\r\n\t\tvar flkty = Flickity.data($carousel[0]);\r\n\t\tflkty.next();\r\n\t\tflkty.stopPlayer();\r\n\t});\r\n\r\n\t/**\r\n\t * Resizes the carousels to make sure they are properly positioned\r\n\t */\r\n\tfunction resizeCarousels() {\r\n\t\t$(".o-carousel").each(function () {\r\n\t\t\tvar flkty = Flickity.data($(this)[0]);\r\n\t\t\tflkty.resize();\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * Hides or shows the carousel\'s buttons when the number of slides is smaller than 2\r\n\t * (only works with groupCells enabled)\r\n\t */\r\n\tfunction updateCarouselsActions() {\r\n\t\t$(".o-carousel").each(function () {\r\n\t\t\tvar carouselID = jQuery(this).data("carousel-id");\r\n\t\t\tvar flkty = Flickity.data($(this)[0]);\r\n\r\n\t\t\tif (flkty.slides.length < 2) {\r\n\t\t\t\tjQuery(".o-carousel_actions[data-carousel-for=\'" + carouselID + "\']").hide();\r\n\t\t\t} else {\r\n\t\t\t\tjQuery(".o-carousel_actions[data-carousel-for=\'" + carouselID + "\']").show();\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tfunction carouselDots() {\r\n\t\tvar $container = $("body");\r\n\t\tvar $slider = $container.find(".o-carousel.-js-dots");\r\n\t\tvar flkty = $slider.data("flickity");\r\n\t\tif (flkty) {\r\n\t\t\tvar slideCount = flkty.slides.length;\r\n\t\t\tvar $pagers = $slider.closest(".o-section_inner").find(".o-carousel_dots");\r\n\r\n\t\t\tfor (var i = 0; i < slideCount; i++) {\r\n\t\t\t\t$pagers.append("<span></span>");\r\n\t\t\t}\r\n\r\n\t\t\tvar $pager = $pagers.find("span");\r\n\r\n\t\t\t$pager.first().addClass("is-selected");\r\n\r\n\t\t\t$slider.on("select.flickity", function () {\r\n\t\t\t\t$pager.filter(".is-selected").removeClass("is-selected");\r\n\t\t\t\t$pager.eq(flkty.selectedIndex).addClass("is-selected");\r\n\t\t\t});\r\n\r\n\t\t\t$pagers.on("click", "span", function () {\r\n\t\t\t\tvar index = $(this).index();\r\n\t\t\t\t$slider.flickity("select", index);\r\n\t\t\t});\r\n\t\t}\r\n\t}\r\n});\r\n\n\n//# sourceURL=webpack:///./assets/src/js/modules/carousel.js?')},
1"./assets/src/js/modules/cf7.js":function assetsSrcJsModulesCf7Js(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (function () {\r\n\tvar $ = jQuery;\r\n\r\n\tvar timeout;\r\n\tvar $wpcf7Forms = $(".wpcf7-form");\r\n\r\n\tfunction callback(mutationsList, observer) {\r\n\t\tmutationsList.forEach((mutation) => {\r\n\t\t\tif (mutation.attributeName === "data-status") {\r\n\t\t\t\tif (mutation.oldValue != "init" && mutation.oldValue != "validating" && mutation.oldValue != "resetting") {\r\n\t\t\t\t\tclearTimeout(timeout);\r\n\t\t\t\t\t$(mutation.target).find(".wpcf7-response-output").addClass("is-active");\r\n\r\n\t\t\t\t\ttimeout = setTimeout(function () {\r\n\t\t\t\t\t\t$(mutation.target).find(".wpcf7-response-output").removeClass("is-active");\r\n\t\t\t\t\t}, 5000);\r\n\r\n\t\t\t\t\tif (mutation.target.className == "wpcf7-form submitting") {\r\n\t\t\t\t\t\tif ($("html").attr("lang") == "fr") {\r\n\t\t\t\t\t\t\t$(mutation.target).find(".wpcf7-response-output").text("Envoi...");\r\n\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t$(mutation.target).find(".wpcf7-response-output").text("Sending...");\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\tconst mutationObserver = new MutationObserver(callback);\r\n\r\n\t$wpcf7Forms.each(function () {\r\n\t\tmutationObserver.observe(this, { attributes: true, attributeOldValue: true });\r\n\t});\r\n});\r\n\n\n//# sourceURL=webpack:///./assets/src/js/modules/cf7.js?')},
1"./assets/src/js/modules/cursor.js":function assetsSrcJsModulesCursorJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/**\r\n * Basic custom cursor with lerp easing.\r\n *\r\n * @link   https://lesprx.monday.com/docs/4822735351?blockId=a8379820-9890-4af2-a838-cbe0bfc8d3eb\r\n * @author Les Prétentieux\r\n */\r\n\r\n/* harmony default export */ __webpack_exports__["default"] = (function () {\r\n\tvar $ = jQuery;\r\n\r\n\t// The lerp easing (how smoothly the cursor follows the mouse pointer)\r\n\tvar easing = 0.35;\r\n\tvar $cursor = $(".c-cursor");\r\n\r\n\tvar mouseX = 0;\r\n\tvar mouseY = 0;\r\n\r\n\tvar cursorTranslateX = 0;\r\n\tvar cursorTranslateY = 0;\r\n\r\n\twindow.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;\r\n\r\n\trequestAnimationFrame(animate);\r\n\r\n\t$(".o-carousel").on("dragMove.flickity", function (event) {\r\n\t\tmouseX = event.clientX;\r\n\t\tmouseY = event.clientY;\r\n\t});\r\n\r\n\t$(window).mousemove(function (event) {\r\n\t\tmouseX = event.clientX;\r\n\t\tmouseY = event.clientY;\r\n\t});\r\n\r\n\tfunction animate() {\r\n\t\tvar cursorWidth = $cursor.outerWidth();\r\n\t\tvar cursorHeight = $cursor.outerHeight();\r\n\r\n\t\tcursorTranslateX = lerp(cursorTranslateX, mouseX, easing);\r\n\t\tcursorTranslateY = lerp(cursorTranslateY, mouseY, easing);\r\n\r\n\t\t$cursor.css("transform", "translate3d(" + (cursorTranslateX - cursorWidth / 2) + "px, " + (cursorTranslateY - cursorHeight / 2) + "px, 0)");\r\n\r\n\t\trequestAnimationFrame(animate);\r\n\t}\r\n\r\n\tfunction lerp(start, end, amt) {\r\n\t\treturn (1 - amt) * start + amt * end;\r\n\t}\r\n\r\n\t/**\r\n     * To change the cursor\'s state depending on what is being hovered\r\n\t$(document).on(\r\n\t\t{\r\n\t\t\tmouseover: function (event) {\r\n\t\t\t\tevent.stopPropagation();\r\n\t\t\t\t$(".c-cursor").addClass("is-pointer");\r\n\t\t\t},\r\n\t\t\tmouseout: function (event) {\r\n\t\t\t\tevent.stopPropagation();\r\n\t\t\t\t$(".c-cursor").removeClass("is-pointer");\r\n\t\t\t},\r\n\t\t},\r\n\t\t".js-cursor-is-pointer"\r\n\t); \r\n    */\r\n});\r\n\n\n//# sourceURL=webpack:///./assets/src/js/modules/cursor.js?')},
1"./assets/src/js/modules/file.js":function assetsSrcJsModulesFileJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/**\r\n * Adds basic functionality to the file component.\r\n *\r\n * @link   https://lesprx.monday.com/docs/4822735351?blockId=fb4f577a-a56e-4fec-a172-c2eea1a4a3a7\r\n * @author Les Prétentieux\r\n */\r\n\r\n/* harmony default export */ __webpack_exports__["default"] = (function () {\r\n\tvar $ = jQuery;\r\n\r\n\t/**\r\n\t * Generates markup when file input changes\r\n\t */\r\n\t$(".c-file input").change(function () {\r\n\t\tvar $file = $(this).closest(".c-file");\r\n\t\tvar filename = $(this)\r\n\t\t\t.val()\r\n\t\t\t.replace(/C:\\\\fakepath\\\\/i, "");\r\n\t\tvar filesize = jQuery(this)[0].files[0].size;\r\n\t\tvar filesize = filesize / 1000;\r\n\t\tvar fileunit = "ko";\r\n\r\n\t\tif (filesize >= 1000) {\r\n\t\t\tfilesize = filesize / 1000;\r\n\t\t\tfileunit = "mo";\r\n\t\t}\r\n\r\n\t\t$(".c-file").addClass("is-toggled");\r\n\r\n\t\tfilesize = Math.round(filesize * 10) / 10;\r\n\r\n\t\t$file.find(".c-file_document").remove();\r\n\r\n\t\t$file.append(\'<div class="c-file_document"><div class="c-file_meta"><span class="c-file_name">\' + filename + \'</span><span class="c-file_size">\' + filesize + " " + fileunit + \'</span></div><span class="c-file_clear"></span></div>\');\r\n\t});\r\n\r\n\t/**\r\n\t * Clear file input when clear button is clicked.\r\n\t */\r\n\t$(document).on("click", ".c-file_clear", function () {\r\n\t\tvar $file = $(this).closest(".c-file");\r\n\r\n\t\t$file.find(".c-file_document").remove();\r\n\t\t$file.find("input").val("");\r\n\t\t$file.removeClass("is-toggled");\r\n\t});\r\n\r\n\t/**\r\n\t * Clear file input when form is submitted\r\n\t */\r\n\tdocument.addEventListener(\r\n\t\t"wpcf7submit",\r\n\t\tfunction (event) {\r\n\t\t\t$(".c-file_document").remove();\r\n\t\t\t$(".c-file").removeClass("is-toggled");\r\n\t\t},\r\n\t\tfalse\r\n\t);\r\n});\r\n\n\n//# sourceURL=webpack:///./assets/src/js/modules/file.js?')},
1"./assets/src/js/modules/footer.js":function assetsSrcJsModulesFooterJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (function () {\n\tvar $ = jQuery;\n\n\t// Hide first element of footer menu\n\t$(".c-footer_submenu .c-footer_link:nth-child(1)").css("display", "none");\n\n\t// Change href link of footer heading link to nothing if screen is less than 768px\n\tvar width = $(window).width();\n\tvar mobileScreen = 768;\n\n\tif (width <= mobileScreen) {\n\t\t$(".c-footer_heading").attr("href", "javascript:void(0)");\n\n\t\t$(".c-footer_heading").click(function () {\n\t\t\tvar isToggled = $(this).hasClass("-toggled");\n\n\t\t\t$(".c-footer_heading").removeClass("-toggled");\n\t\t\t$(".c-footer_submenu").removeClass("-toggled");\n\n\t\t\tif (!isToggled) {\n\t\t\t\t$(this).addClass("-toggled");\n\t\t\t\t$(this).next().addClass("-toggled");\n\t\t\t}\n\t\t});\n\t}\n\n\t// Add padding-top to footer-cta section if last section of main is not neutral-100\n\tvar lastSection = $("main .o-section:last-child");\n\n\tif (!lastSection.hasClass("-neutral-100")) {\n\t\t$("footer").removeClass("-no-spacing").addClass("-no-spacing-bottom");\n\t}\n});\n\n\n//# sourceURL=webpack:///./assets/src/js/modules/footer.js?')},
1"./assets/src/js/modules/gsap/curtain.js":function assetsSrcJsModulesGsapCurtainJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (function () {\n\tvar $ = jQuery;\n\n\tif (history.scrollRestoration) {\n\t\thistory.scrollRestoration = "manual";\n\t}\n\n\tif ($("body").hasClass("home")) {\n\t\t$(document).ready(function () {\n\t\t\t$("html").addClass("is-lock-scroll");\n\t\t\tvar tl = gsap.timeline();\n\n\t\t\ttl.to(".home .c-curtain_top .c-curtain_first", {\n\t\t\t\tduration: 0.6,\n\t\t\t\tyPercent: -250,\n\t\t\t\txPercent: -600,\n\t\t\t\tdelay: 0.5,\n\t\t\t\tease: "ease-out-power-3",\n\t\t\t\tonComplete: function () {\n\t\t\t\t\t$(".home .c-curtain_shape").css("z-index", "0");\n\t\t\t\t},\n\t\t\t});\n\n\t\t\ttl.to(".home .c-curtain_top .c-curtain_last", {\n\t\t\t\tduration: 0.6,\n\t\t\t\tyPercent: -200,\n\t\t\t\txPercent: 1000,\n\t\t\t\tdelay: -0.5,\n\t\t\t\tease: "ease-out-power-3",\n\t\t\t});\n\n\t\t\ttl.to(".home .c-curtain_bottom .c-curtain_first", {\n\t\t\t\tduration: 0.6,\n\t\t\t\tyPercent: 600,\n\t\t\t\txPercent: -600,\n\t\t\t\tdelay: -0.5,\n\t\t\t\tease: "ease-out-power-3",\n\t\t\t});\n\n\t\t\ttl.to(".home .c-curtain_bottom .c-curtain_last", {\n\t\t\t\tduration: 0.6,\n\t\t\t\tyPercent: 700,\n\t\t\t\txPercent: 700,\n\t\t\t\tdelay: -0.5,\n\t\t\t\tease: "ease-out-power-3",\n\t\t\t});\n\n\t\t\ttl.to(".home .c-curtain_line", {\n\t\t\t\topacity: 1,\n\t\t\t\tduration: 0.1,\n\t\t\t\tdelay: -0.9,\n\t\t\t\tautoAlpha: 1,\n\t\t\t});\n\n\t\t\ttl.to(".home .c-curtain_line:nth-child(1)", {\n\t\t\t\ty: -1500,\n\t\t\t\tduration: 2,\n\t\t\t\tdelay: -0.9,\n\t\t\t});\n\n\t\t\ttl.to(".home .c-curtain_line:nth-child(2)", {\n\t\t\t\ty: -1500,\n\t\t\t\tx: 1500,\n\t\t\t\tduration: 2,\n\t\t\t\tdelay: -2,\n\t\t\t});\n\n\t\t\ttl.to(".home .c-curtain_line:nth-child(3)", {\n\t\t\t\tx: 1500,\n\t\t\t\tduration: 2,\n\t\t\t\tdelay: -2,\n\t\t\t});\n\n\t\t\ttl.to(".home .c-curtain_line:nth-child(4)", {\n\t\t\t\ty: 1500,\n\t\t\t\tx: 1500,\n\t\t\t\tduration: 2,\n\t\t\t\tdelay: -2,\n\t\t\t});\n\n\t\t\ttl.to(".home .c-curtain_line:nth-child(5)", {\n\t\t\t\ty: 1500,\n\t\t\t\tduration: 2,\n\t\t\t\tdelay: -2,\n\t\t\t});\n\n\t\t\ttl.to(".home .c-curtain_line:nth-child(6)", {\n\t\t\t\ty: 1500,\n\t\t\t\tx: -1500,\n\t\t\t\tduration: 2,\n\t\t\t\tdelay: -2,\n\t\t\t});\n\n\t\t\ttl.to(".home .c-curtain_line:nth-child(7)", {\n\t\t\t\tx: -1500,\n\t\t\t\tduration: 2,\n\t\t\t\tdelay: -2,\n\t\t\t});\n\n\t\t\ttl.to(".home .c-curtain_line:nth-child(8)", {\n\t\t\t\ty: -1500,\n\t\t\t\tx: -1500,\n\t\t\t\tduration: 2,\n\t\t\t\tdelay: -2,\n\t\t\t});\n\n\t\t\ttl.to(".home .c-curtain", {\n\t\t\t\tduration: 1,\n\t\t\t\tease: "ease-out-power-3",\n\t\t\t\tyPercent: -100,\n\t\t\t\tdelay: -1.5,\n\t\t\t\tonComplete: function () {\n\t\t\t\t\t$("html").removeClass("is-lock-scroll");\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\t}\n});\n\n\n//# sourceURL=webpack:///./assets/src/js/modules/gsap/curtain.js?')},
1"./assets/src/js/modules/gsap/eases.js":function assetsSrcJsModulesGsapEasesJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (function () {\r\n\tvar $ = jQuery;\r\n\r\n\t$(document).ready(function () {\r\n\t\t// Ease-in\r\n\t\tCustomEase.create("ease-in-power-1", "0.55, 0.085, 0.68, 0.53");\r\n\t\tCustomEase.create("ease-in-power-2", "0.55, 0.055, 0.675, 0.19");\r\n\t\tCustomEase.create("ease-in-power-3", "0.895, 0.03, 0.685, 0.22");\r\n\t\tCustomEase.create("ease-in-power-4", "0.755, 0.05, 0.855, 0.06");\r\n\t\tCustomEase.create("ease-in-exponential", "0.95, 0.05, 0.795, 0.035");\r\n\t\tCustomEase.create("ease-in-sine", "0.47, 0, 0.745, 0.715");\r\n\r\n\t\t// Ease-out\r\n\t\tCustomEase.create("ease-out-power-1", "0.25, 0.46, 0.45, 0.94");\r\n\t\tCustomEase.create("ease-out-power-2", "0.215, 0.61, 0.355, 1");\r\n\t\tCustomEase.create("ease-out-power-3", "0.165, 0.84, 0.44, 1");\r\n\t\tCustomEase.create("ease-out-power-4", "0.23, 1, 0.32, 1");\r\n\t\tCustomEase.create("ease-out-exponential", "0.19, 1, 0.22, 1");\r\n\t\tCustomEase.create("ease-out-sine", "0.39, 0.575, 0.565, 1");\r\n\r\n\t\t// Ease-in-out\r\n\t\tCustomEase.create("ease-in-out-power-1", "0.455, 0.03, 0.515, 0.955");\r\n\t\tCustomEase.create("ease-in-out-power-2", "0.645, 0.045, 0.355, 1");\r\n\t\tCustomEase.create("ease-in-out-power-3", "0.77, 0, 0.175, 1");\r\n\t\tCustomEase.create("ease-in-out-power-4", "0.86, 0, 0.07, 1");\r\n\t\tCustomEase.create("ease-in-out-exponential", "1, 0, 0, 1");\r\n\t\tCustomEase.create("ease-in-out-sine", "0.45, 0.05, 0.55, 0.95");\r\n\r\n\t\t// Other\r\n\t\tCustomEase.create("easing-bounce", "0.17, 0.67, 0.3, 1.33");\r\n\t\tCustomEase.create("easing-gravity", "0.33333, 0, 0.66667, 0.33333");\r\n\t});\r\n});\r\n\n\n//# sourceURL=webpack:///./assets/src/js/modules/gsap/eases.js?')},
1"./assets/src/js/modules/gsap/features.js":function assetsSrcJsModulesGsapFeaturesJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (function () {\n\tvar $ = jQuery;\n\n\tgsap.from(".c-feature .js-graph path", {\n\t\tduration: 1.8,\n\t\tstagger: 0.4,\n\t\tdrawSVG: 0,\n\t\tscrollTrigger: ".c-feature",\n\t});\n\n\tgsap.from(".c-feature-listing .js-graph path", {\n\t\tduration: 1.8,\n\t\tstagger: 0.4,\n\t\tdrawSVG: 0,\n\t\tscrollTrigger: ".c-feature-listing",\n\t\trepeat: -1,\n\n\t\t// onComplete: function () {\n\t\t// \tgsap.to(".c-feature-listing .js-graph path", {\n\t\t// \t\tduration: 1.8,\n\t\t// \t\tstagger: 0.4,\n\t\t// \t\tdrawSVG: 1,\n\t\t// \t});\n\t\t// },\n\t});\n\n\tgsap.from(".c-illustration-header_media .js-graph path", {\n\t\tduration: 1.8,\n\t\tstagger: 0.4,\n\t\tdrawSVG: 0,\n\t\tease: "ease-out-power-2",\n\t});\n\n\tgsap.from(".c-feature .js-pie .js-pie_float", {\n\t\tduration: 1.4,\n\t\tx: 0,\n\t\ty: 0,\n\t\tyoyo: true,\n\t\trepeat: -1,\n\t\tease: "ease-in-out-power-4",\n\t\tscrollTrigger: ".c-feature",\n\t});\n\n\tgsap.from(".c-feature-listing .js-pie .js-pie_float", {\n\t\tduration: 1.4,\n\t\tx: 0,\n\t\ty: 0,\n\t\tyoyo: true,\n\t\trepeat: -1,\n\t\tease: "ease-in-out-power-4",\n\t\tscrollTrigger: ".c-feature-listing",\n\t});\n\n\tgsap.from(".c-illustration-header_media .js-pie .js-pie_float", {\n\t\tduration: 1.8,\n\t\tx: 0,\n\t\ty: 0,\n\t\tyoyo: true,\n\t\trepeat: -1,\n\t\tease: "ease-in-out-power-4",\n\t});\n\n\tgsap.to(".c-feature .js-dots_yellow", {\n\t\tduration: 1.8,\n\t\txPercent: 300,\n\t\tstagger: 0.8,\n\t\tyoyo: true,\n\t\trepeat: -1,\n\t\tscrollTrigger: ".c-feature",\n\t\tease: "ease-in-out-power-3",\n\t});\n\n\tgsap.to(".c-feature .js-dots_red", {\n\t\tduration: 2.5,\n\t\txPercent: 300,\n\t\tstagger: 0.8,\n\t\tyoyo: true,\n\t\trepeat: -1,\n\t\tscrollTrigger: ".c-feature",\n\t\tease: "ease-in-out-power-3",\n\t});\n\n\tgsap.to(".c-feature .js-dots_blue", {\n\t\tduration: 2,\n\t\txPercent: 300,\n\t\tstagger: 0.8,\n\t\tyoyo: true,\n\t\tease: "ease-in-out-power-3",\n\t\trepeat: -1,\n\t\tscrollTrigger: ".c-feature",\n\t});\n\n\tgsap.to(".c-feature-listing .js-dots_yellow", {\n\t\tduration: 1.8,\n\t\txPercent: 300,\n\t\tstagger: 0.8,\n\t\tyoyo: true,\n\t\trepeat: -1,\n\t\tscrollTrigger: ".c-feature-listing",\n\t\tease: "ease-in-out-power-3",\n\t});\n\n\tgsap.to(".c-feature-listing .js-dots_red", {\n\t\tduration: 2.5,\n\t\txPercent: 300,\n\t\tstagger: 0.8,\n\t\tyoyo: true,\n\t\trepeat: -1,\n\t\tscrollTrigger: ".c-feature-listing",\n\t\tease: "ease-in-out-power-3",\n\t});\n\n\tgsap.to(".c-feature-listing .js-dots_blue", {\n\t\tduration: 2,\n\t\txPercent: 300,\n\t\tstagger: 0.8,\n\t\tyoyo: true,\n\t\tease: "ease-in-out-power-3",\n\t\trepeat: -1,\n\t\tscrollTrigger: ".c-feature-listing",\n\t});\n\n\tgsap.to(".c-illustration-header_media .js-dots_yellow", {\n\t\tduration: 1.8,\n\t\txPercent: 300,\n\t\tstagger: 0.8,\n\t\tyoyo: true,\n\t\trepeat: -1,\n\t\tease: "ease-in-out-power-3",\n\t});\n\n\tgsap.to(".c-illustration-header_media .js-dots_red", {\n\t\tduration: 2.5,\n\t\txPercent: 300,\n\t\tstagger: 0.8,\n\t\tyoyo: true,\n\t\trepeat: -1,\n\t\tease: "ease-in-out-power-3",\n\t});\n\n\tgsap.to(".c-illustration-header_media .js-dots_blue", {\n\t\tduration: 2,\n\t\txPercent: 300,\n\t\tstagger: 0.8,\n\t\tyoyo: true,\n\t\tease: "ease-in-out-power-3",\n\t\trepeat: -1,\n\t});\n\n\tgsap.to(\n\t\t".js-stairs_darkblue",\n\t\t{\n\t\t\tduration: 2,\n\t\t\txPercent: 300,\n\t\t\tyoyo: true,\n\t\t\trepeat: -1,\n\t\t},\n\t\t"rectAnim"\n\t);\n\n\tgsap.to(\n\t\t".js-stairs_blue",\n\t\t{\n\t\t\tduration: 2,\n\t\t\txPercent: 300,\n\t\t\tyoyo: true,\n\t\t\trepeat: -1,\n\t\t},\n\t\t"rectAnim+=.5"\n\t);\n\n\tgsap.to(\n\t\t".js-stairs_lightblue",\n\t\t{\n\t\t\tduration: 2,\n\t\t\txPercent: 300,\n\t\t\tyoyo: true,\n\t\t\trepeat: -1,\n\t\t},\n\t\t"rectAnim+=1"\n\t);\n\n\tgsap.to(\n\t\t".js-stairs_yellow",\n\t\t{\n\t\t\tduration: 2,\n\t\t\txPercent: 300,\n\t\t\tyoyo: true,\n\t\t\trepeat: -1,\n\t\t},\n\t\t"rectAnim+=1.5"\n\t);\n\n\tgsap.to(\n\t\t".js-stairs_grey",\n\t\t{\n\t\t\tduration: 2,\n\t\t\txPercent: 300,\n\t\t\tyoyo: true,\n\t\t\trepeat: -1,\n\t\t},\n\t\t"rectAnim+=2"\n\t);\n});\n\n\n//# sourceURL=webpack:///./assets/src/js/modules/gsap/features.js?')},
1"./assets/src/js/modules/gsap/intro.js":function assetsSrcJsModulesGsapIntroJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (function () {\n\tvar $ = jQuery;\n\n\t$(document).ready(function () {\n\t\tvar tl = gsap.timeline({\n\t\t\tscrollTrigger: {\n\t\t\t\ttrigger: ".c-advantage",\n\t\t\t\tscrub: 1,\n\t\t\t\tstart: "top 20%",\n\t\t\t},\n\t\t});\n\n\t\ttl.to(\n\t\t\t".c-advantages_shape.-third",\n\t\t\t{\n\t\t\t\tduration: 1,\n\t\t\t\tease: "none",\n\t\t\t\txPercent: 100,\n\t\t\t\tyPercent: 100,\n\t\t\t},\n\t\t\t"<="\n\t\t);\n\n\t\ttl.to(\n\t\t\t".c-advantages_shape.-fourth",\n\t\t\t{\n\t\t\t\tduration: 1,\n\t\t\t\tease: "none",\n\t\t\t\txPercent: -100,\n\t\t\t\tyPercent: 100,\n\t\t\t},\n\t\t\t"<="\n\t\t);\n\n\t\ttl.to(\n\t\t\t".c-advantages_shape.-first",\n\t\t\t{\n\t\t\t\tduration: 3,\n\t\t\t\tease: "none",\n\t\t\t\txPercent: 100,\n\t\t\t\tyPercent: -100,\n\t\t\t},\n\t\t\t"<="\n\t\t);\n\n\t\ttl.to(\n\t\t\t".c-advantages_shape.-second",\n\t\t\t{\n\t\t\t\tduration: 3,\n\t\t\t\tease: "none",\n\t\t\t\txPercent: -100,\n\t\t\t\tyPercent: -100,\n\t\t\t},\n\t\t\t"<="\n\t\t);\n\t});\n});\n\n\n//# sourceURL=webpack:///./assets/src/js/modules/gsap/intro.js?')},
1"./assets/src/js/modules/gsap/scrollTrigger.js":function assetsSrcJsModulesGsapScrollTriggerJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (function () {\n\tvar $ = jQuery;\n\tvar tlAdvantages = gsap.timeline({\n\t\tscrollTrigger: {\n\t\t\ttrigger: ".c-advantages_content",\n\t\t},\n\t});\n\n\t$(document).ready(function () {\n\t\ttlAdvantages.from(".c-advantages_single", {\n\t\t\tduration: 0.4,\n\t\t\tease: "ease-out-power-2",\n\t\t\ty: 24,\n\t\t\tclipPath: "inset(0% 0% 100% 0%)",\n\t\t\tstagger: 0.06,\n\t\t});\n\t});\n});\n\n\n//# sourceURL=webpack:///./assets/src/js/modules/gsap/scrollTrigger.js?')},
1"./assets/src/js/modules/helper.js":function assetsSrcJsModulesHelperJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (function () {\r\n\tvar $ = jQuery;\r\n\r\n\tvar lastScrollTop = 0;\r\n\r\n\t$(window).on("scroll", function () {\r\n\t\tvar scrollY = window.pageYOffset;\r\n\r\n\t\tif (scrollY > lastScrollTop) {\r\n\t\t\t$("html").removeClass("is-scroll-up");\r\n\t\t\t$("html").addClass("is-scroll-down");\r\n\t\t} else if (scrollY < lastScrollTop) {\r\n\t\t\t$("html").removeClass("is-scroll-down");\r\n\t\t\t$("html").addClass("is-scroll-up");\r\n\t\t}\r\n\r\n\t\tif (scrollY > 160) {\r\n\t\t\t$("html").addClass("is-over-content");\r\n\t\t} else {\r\n\t\t\t$("html").removeClass("is-over-content");\r\n\t\t}\r\n\r\n\t\tlastScrollTop = window.pageYOffset;\r\n\t});\r\n});\r\n\n\n//# sourceURL=webpack:///./assets/src/js/modules/helper.js?')},
1"./assets/src/js/modules/inclusion.js":function assetsSrcJsModulesInclusionJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (function () {\n\tvar $ = jQuery;\n\n\tvar sectionHeight = 0;\n\n\t$(".c-inclusion").each(function () {\n\t\tconsole.log($(this).outerHeight());\n\t});\n});\n\n\n//# sourceURL=webpack:///./assets/src/js/modules/inclusion.js?')},
1"./assets/src/js/modules/job.js":function assetsSrcJsModulesJobJs(module,__webpack_exports__,__webpack_require__){eval("__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__[\"default\"] = (function () {\n    const targetNode = document.body;\n\n    // Configuration of the observer: watch for children being added\n    const config = { childList: true, subtree: true };\n\n    const callback = function (mutationsList, observer) {\n        const wrapper = document.querySelector('.job-form-wrapper');\n        const jobField = document.querySelector('.js-job-field');\n\n        // Check if our specific elements exist yet\n        if (wrapper && jobField) {\n            const title = wrapper.getAttribute('data-job-title');\n\n            if (title) {\n                jobField.value = title;\n\n                // Trigger events so UI scripts (like floating labels) update\n                jobField.dispatchEvent(new Event('input', { bubbles: true }));\n                jobField.dispatchEvent(new Event('change', { bubbles: true }));\n\n                // Success! Stop watching the DOM to save performance\n                observer.disconnect();\n            }\n        }\n    };\n\n    // Create the observer instance linked to the callback function\n    const observer = new MutationObserver(callback);\n\n    // Start observing\n    observer.observe(targetNode, config);\n\n    // Also run it once immediately in case the element is already there\n    callback([], observer);\n});\n\n//# sourceURL=webpack:///./assets/src/js/modules/job.js?")},
1"./assets/src/js/modules/matter.js":function assetsSrcJsModulesMatterJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var matter_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! matter-js */ "./node_modules/matter-js/build/matter.js");\n/* harmony import */ var matter_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(matter_js__WEBPACK_IMPORTED_MODULE_0__);\n\r\n\r\n/* harmony default export */ __webpack_exports__["default"] = (function () {\r\n\tvar $ = jQuery;\r\n\r\n\t$(".js-matter").each(function () {\r\n\t\tlet $this = $(this);\r\n\t\tScrollTrigger.create({\r\n\t\t\ttrigger: $this,\r\n\t\t\tstart: "top bottom",\r\n\t\t\tonce: true,\r\n\r\n\t\t\tonEnter: function () {\r\n\t\t\t\tvar Engine = matter_js__WEBPACK_IMPORTED_MODULE_0___default.a.Engine,\r\n\t\t\t\t\tRender = matter_js__WEBPACK_IMPORTED_MODULE_0___default.a.Render,\r\n\t\t\t\t\tWorld = matter_js__WEBPACK_IMPORTED_MODULE_0___default.a.World,\r\n\t\t\t\t\tRunner = matter_js__WEBPACK_IMPORTED_MODULE_0___default.a.Runner,\r\n\t\t\t\t\tBodies = matter_js__WEBPACK_IMPORTED_MODULE_0___default.a.Bodies,\r\n\t\t\t\t\tComposite = matter_js__WEBPACK_IMPORTED_MODULE_0___default.a.Composite,\r\n\t\t\t\t\tMouseConstraint = matter_js__WEBPACK_IMPORTED_MODULE_0___default.a.MouseConstraint;\r\n\r\n\t\t\t\tvar render;\r\n\t\t\t\tvar engine;\r\n\r\n\t\t\t\tfunction init() {\r\n\t\t\t\t\tEngine = matter_js__WEBPACK_IMPORTED_MODULE_0___default.a.Engine;\r\n\t\t\t\t\tRender = matter_js__WEBPACK_IMPORTED_MODULE_0___default.a.Render;\r\n\t\t\t\t\tWorld = matter_js__WEBPACK_IMPORTED_MODULE_0___default.a.World;\r\n\t\t\t\t\tRunner = matter_js__WEBPACK_IMPORTED_MODULE_0___default.a.Runner;\r\n\t\t\t\t\tBodies = matter_js__WEBPACK_IMPORTED_MODULE_0___default.a.Bodies;\r\n\t\t\t\t\tComposite = matter_js__WEBPACK_IMPORTED_MODULE_0___default.a.Composite;\r\n\t\t\t\t\tMouseConstraint = matter_js__WEBPACK_IMPORTED_MODULE_0___default.a.MouseConstraint;\r\n\r\n\t\t\t\t\tengine = Engine.create();\r\n\r\n\t\t\t\t\tvar w = $this[0].getBoundingClientRect().width;\r\n\t\t\t\t\tvar h = $this[0].getBoundingClientRect().height;\r\n\r\n\t\t\t\t\tconst element = $this.find(".shapes")[0];\r\n\t\t\t\t\trender = Render.create({\r\n\t\t\t\t\t\telement: element,\r\n\t\t\t\t\t\tengine: engine,\r\n\t\t\t\t\t\toptions: {\r\n\t\t\t\t\t\t\twidth: w,\r\n\t\t\t\t\t\t\theight: h,\r\n\t\t\t\t\t\t\tbackground: "#012f55",\r\n\t\t\t\t\t\t\twireframes: false,\r\n\t\t\t\t\t\t\tpixelRatio: window.devicePixelRatio,\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t});\r\n\r\n\t\t\t\t\t///\r\n\r\n\t\t\t\t\tconst shapes = [];\r\n\t\t\t\t\tvar index = 0;\r\n\r\n\t\t\t\t\t$this.find(".js-matter_shape").each(function () {\r\n\t\t\t\t\t\t$(this)\r\n\t\t\t\t\t\t\t.find("path")\r\n\t\t\t\t\t\t\t.each(function (i, path) {\r\n\t\t\t\t\t\t\t\tlet color = "";\r\n\t\t\t\t\t\t\t\tindex++;\r\n\r\n\t\t\t\t\t\t\t\tif ($(this).hasClass("matter-path-1")) {\r\n\t\t\t\t\t\t\t\t\tcolor = "#313CFA";\r\n\t\t\t\t\t\t\t\t} else if ($(this).hasClass("matter-path-2")) {\r\n\t\t\t\t\t\t\t\t\tcolor = "#E9B133";\r\n\t\t\t\t\t\t\t\t} else if ($(this).hasClass("matter-path-3")) {\r\n\t\t\t\t\t\t\t\t\tcolor = "#CD383E";\r\n\t\t\t\t\t\t\t\t} else if ($(this).hasClass("matter-path-4")) {\r\n\t\t\t\t\t\t\t\t\tcolor = "#65B9EC";\r\n\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\tvar v = Bodies.fromVertices(w / index, 0, matter_js__WEBPACK_IMPORTED_MODULE_0___default.a.Svg.pathToVertices(path, 5), {\r\n\t\t\t\t\t\t\t\t\trender: {\r\n\t\t\t\t\t\t\t\t\t\tfillStyle: color,\r\n\t\t\t\t\t\t\t\t\t\tstrokeStyle: color,\r\n\t\t\t\t\t\t\t\t\t},\r\n\t\t\t\t\t\t\t\t});\r\n\r\n\t\t\t\t\t\t\t\tshapes.push(v);\r\n\t\t\t\t\t\t\t});\r\n\t\t\t\t\t});\r\n\r\n\t\t\t\t\tComposite.add(engine.world, shapes);\r\n\r\n\t\t\t\t\t///\r\n\r\n\t\t\t\t\tconst wallOptions = {\r\n\t\t\t\t\t\tisStatic: true,\r\n\t\t\t\t\t\trender: {\r\n\t\t\t\t\t\t\tvisible: true,\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t};\r\n\r\n\t\t\t\t\tconst ground = Bodies.rectangle(w / 2, h + 50, w + 100, 100, wallOptions);\r\n\t\t\t\t\tconst ceiling = Bodies.rectangle(w / 2, -50, w + 100, 100, wallOptions);\r\n\t\t\t\t\tconst leftWall = Bodies.rectangle(-50, h / 2, 100, h + 100, wallOptions);\r\n\t\t\t\t\tconst rightWall = Bodies.rectangle(w + 50, h / 2, 100, h + 100, wallOptions);\r\n\r\n\t\t\t\t\tComposite.add(engine.world, [ground, ceiling, leftWall, rightWall]);\r\n\r\n\t\t\t\t\tconst mouseControl = MouseConstraint.create(engine, {\r\n\t\t\t\t\t\telement: $this.find(".shapes")[0],\r\n\t\t\t\t\t\tconstraint: {\r\n\t\t\t\t\t\t\trender: {\r\n\t\t\t\t\t\t\t\tvisible: false,\r\n\t\t\t\t\t\t\t},\r\n\t\t\t\t\t\t},\r\n\t\t\t\t\t});\r\n\r\n\t\t\t\t\tComposite.add(engine.world, mouseControl);\r\n\r\n\t\t\t\t\t// run the renderer\r\n\t\t\t\t\tRender.run(render);\r\n\r\n\t\t\t\t\t// create runner\r\n\t\t\t\t\tvar runner = Runner.create();\r\n\r\n\t\t\t\t\t// run the engine\r\n\t\t\t\t\tRunner.run(runner, engine);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tinit();\r\n\r\n\t\t\t\twindow.addEventListener("resize", function () {\r\n\t\t\t\t\tRender.stop(render);\r\n\t\t\t\t\tWorld.clear(engine.world);\r\n\t\t\t\t\tEngine.clear(engine);\r\n\t\t\t\t\trender.canvas.remove();\r\n\t\t\t\t\trender.canvas = null;\r\n\t\t\t\t\trender.context = null;\r\n\t\t\t\t\trender.textures = {};\r\n\r\n\t\t\t\t\tinit();\r\n\t\t\t\t});\r\n\t\t\t},\r\n\t\t});\r\n\t});\r\n});\r\n\n\n//# sourceURL=webpack:///./assets/src/js/modules/matter.js?')},
1"./assets/src/js/modules/media.js":function assetsSrcJsModulesMediaJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (function () {\n\tvar $ = jQuery;\n\n\t$(".c-media_btn").click(function () {\n\t\t$(this).closest(".c-media_media").find(".c-media_media img").addClass("-hidden");\n\t\t$(this).addClass("-hidden");\n\t\t$(".c-media_video").addClass("-active");\n\n\t\t$(".c-media_video").trigger("play");\n\t});\n});\n\n\n//# sourceURL=webpack:///./assets/src/js/modules/media.js?')},
1"./assets/src/js/modules/menus.js":function assetsSrcJsModulesMenusJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (function () {\n\tvar $ = jQuery;\n\n\t// Menu interaction\n\n\t$(".c-header_link.-has-children").click(function () {\n\t\tvar id = $(this).attr("id");\n\t\tvar isActive = $(this).hasClass("-active");\n\n\t\t$(".c-header_link").removeClass("-active");\n\t\t$(".c-submenu").removeClass("-active");\n\n\t\tif (!isActive) {\n\t\t\t$(this).addClass("-active");\n\t\t\t$(".c-submenu#" + id).addClass("-active");\n\t\t}\n\t});\n\n\t$(window).scroll(function () {\n\t\t$(".c-header_link").removeClass("-active");\n\t\t$(".c-submenu").removeClass("-active");\n\t});\n\n\t// Mobile menu interaction\n\t$(".c-mobile-menu_link.-has-children").click(function () {\n\t\tvar isToggled = $(this).hasClass("-toggled");\n\n\t\t$(".c-mobile-menu_link").removeClass("-toggled");\n\t\t$(".c-mobile-menu_submenu").removeClass("-toggled");\n\n\t\tif (!isToggled) {\n\t\t\t$(this).addClass("-toggled");\n\t\t\t$(this).next().addClass("-toggled");\n\t\t}\n\t});\n\n\t// Burger\n\t$(".c-burger").click(function () {\n\t\t$(this).toggleClass("-toggled");\n\t\t$(".c-mobile-menu").toggleClass("-toggled");\n\t\t$("html").toggleClass("is-lock-scroll");\n\t});\n\n\t// Banner\n\n\t$(".c-header_close").click(function () {\n\t\t$(".c-header_top").addClass("-close");\n\t\tdocument.cookie = "modal=closed; path=/";\n\t});\n\n\tif (getCookie("modal")) {\n\t\t$(".c-header_top").addClass("-close");\n\t}\n\n\tfunction getCookie(name) {\n\t\tvar dc = document.cookie;\n\t\tvar prefix = name + "=";\n\t\tvar begin = dc.indexOf("; " + prefix);\n\t\tif (begin == -1) {\n\t\t\tbegin = dc.indexOf(prefix);\n\t\t\tif (begin != 0) return null;\n\t\t} else {\n\t\t\tbegin += 2;\n\t\t\tvar end = document.cookie.indexOf(";", begin);\n\t\t\tif (end == -1) {\n\t\t\t\tend = dc.length;\n\t\t\t}\n\t\t}\n\t\t// because unescape has been deprecated, replaced with decodeURI\n\t\t//return unescape(dc.substring(begin + prefix.length, end));\n\t\treturn decodeURI(dc.substring(begin + prefix.length, end));\n\t}\n\n\t// var sectionColor = $("main .o-section:first");\n\n\t// if (sectionColor.hasClass("-neutral-800")) {\n\t// \t$(".c-header").addClass("-light");\n\t// \t$(".c-header img").attr("src", "/wp-content/themes/cdid/assets/src/images/logo-dark.svg");\n\t// }\n\n\t// Change the background-color of header if first section is not neutral-100\n\tif ($(".o-section:first").hasClass("-neutral-800") || $(".o-section:first").hasClass("-neutral-700") || $(".c-shapes-header").length > 0) {\n\t\t$(".c-header").addClass("-light");\n\t\t$(".c-header img").attr("src", "/wp-content/themes/cdid/assets/src/images/logo-dark.svg");\n\t}\n});\n\n\n//# sourceURL=webpack:///./assets/src/js/modules/menus.js?')},
1"./assets/src/js/modules/section.js":function assetsSrcJsModulesSectionJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (function () {\n\tvar $ = jQuery;\n\n\t// $(".o-section").each(function () {\n\t// \tif ($(this).hasClass("-top") || $(this).hasClass("-bottom")) {\n\t// \t\tif ($(this).hasClass("-bottom")) {\n\t// \t\t\t$(this).prev().addClass("-padding-bottom-xl");\n\t// \t\t}\n\n\t// \t\tif ($(this).hasClass("-top")) {\n\t// \t\t\t$(this).prev().addClass("-padding-top-xl");\n\t// \t\t}\n\t// \t}\n\t// });\n});\n\n\n//# sourceURL=webpack:///./assets/src/js/modules/section.js?')},
1"./libraries/prx-filters/prx-filters.js":function librariesPrxFiltersPrxFiltersJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PrxFilters", function() { return PrxFilters; });\n/* harmony import */ var fuzzysort__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! fuzzysort */ "./node_modules/fuzzysort/fuzzysort.js");\n/* harmony import */ var fuzzysort__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(fuzzysort__WEBPACK_IMPORTED_MODULE_0__);\n/**\r\n * Simple filters.\r\n *\r\n * @link https://lesprx.monday.com/docs/4822789543\r\n * @author Les Prétentieux\r\n * @version 1.0.0\r\n *\r\n * */\r\n\r\n\r\n\r\n\r\n\r\nclass PrxFilters {\r\n\t/**\r\n\t * Init our class.\r\n\t *\r\n\t * @param {object} [options] - PrxFilters options.\r\n\t * @param {number} [options.searchThreshold=-Infinity] - Minimum relevancy score to consider a search result as valid.\r\n\t */\r\n\tconstructor({ searchThreshold = -Infinity } = {}) {\r\n\t\tthis.searchThreshold = searchThreshold;\r\n\r\n\t\tthis.filtersElems = [];\r\n\r\n\t\tthis.init();\r\n\t}\r\n\r\n\t/**\r\n\t * Initialize filters.\r\n\t */\r\n\tinit() {\r\n\t\t// Get all filters\r\n\t\tthis.filtersElems = document.querySelectorAll("[data-filters]");\r\n\r\n\t\tthis.filtersElems.forEach((filtersElem) => {\r\n\t\t\t// Get the filters params\r\n\t\t\tvar filtersParams = filtersElem.dataset.filters;\r\n\t\t\tfiltersParams = JSON.parse(filtersParams);\r\n\r\n\t\t\t// Store those params in the filters node\r\n\t\t\tvar paramsObj = {\r\n\t\t\t\tfor: filtersParams.for,\r\n\t\t\t\turlHash: filtersParams.urlHash ? filtersParams.urlHash : false,\r\n\t\t\t\tonSubmit: filtersParams.onSubmit ? filtersParams.onSubmit : false,\r\n\t\t\t};\r\n\t\t\tfiltersElem = Object.assign(filtersElem, paramsObj);\r\n\r\n\t\t\t// Preemptively build filters object\r\n\t\t\tthis.buildFiltersObject(filtersElem);\r\n\r\n\t\t\t// Get the filters filter elements\r\n\t\t\tvar filterElems = filtersElem.querySelectorAll("[data-filter]");\r\n\r\n\t\t\t// Build filters object on input\r\n\t\t\tif (filtersElem.onSubmit) {\r\n\t\t\t\tvar filterSubmit = filtersElem.querySelector("[data-filter-submit]");\r\n\t\t\t\tfilterSubmit.addEventListener("click", () => this.buildFiltersObject(filtersElem));\r\n\t\t\t}
1 else {\r\n\t\t\t\tfilterElems.forEach((filterElem) => {\r\n\t\t\t\t\tfilterElem.addEventListener("input", () => this.buildFiltersObject(filtersElem));\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * Build filters object for a given filters element.\r\n\t *\r\n\t * @param {HTMLElement} filtersElem - The filters element.\r\n\t */\r\n\tbuildFiltersObject(filtersElem) {\r\n\t\tvar filtersObj = [];\r\n\r\n\t\t// Get filter groups\r\n\t\tvar filterGroups = filtersElem.querySelectorAll("[data-filter-group]");\r\n\r\n\t\tfilterGroups.forEach((filterGroup) => {\r\n\t\t\tvar filtersGroupObj = {};\r\n\t\t\tvar filterElems = filterGroup.querySelectorAll("[data-filter]");\r\n\r\n\t\t\t// Loop through each filters of the group\r\n\t\t\tfilterElems.forEach((filterElem) => {\r\n\t\t\t\tvar key = filterElem.dataset.filter;\r\n\t\t\t\tvar value = "";\r\n\t\t\t\tvar type = filterElem.type;\r\n\r\n\t\t\t\tif (type == "radio" || type == "checkbox") {\r\n\t\t\t\t\tif (filterElem.checked) {\r\n\t\t\t\t\t\tvalue = filterElem.value;\r\n\t\t\t\t\t}\r\n\t\t\t\t} else {\r\n\t\t\t\t\tvalue = filterElem.value;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (filtersGroupObj[key] == undefined) {\r\n\t\t\t\t\tfiltersGroupObj[key] = [];\r\n\t\t\t\t}\r\n\r\n\t\t\t\tif (value) {\r\n\t\t\t\t\tfiltersGroupObj[key].push(value);\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t\t// Add filters group object to the main filters object\r\n\t\t\tfiltersObj.push(filtersGroupObj);\r\n\t\t});\r\n\r\n\t\t// Store filters object in the filters node\r\n\t\tfiltersElem = Object.assign(filtersElem, { filtersObj: filtersObj });\r\n\r\n\t\tif (filtersElem.urlHash) {\r\n\t\t\tthis.buildUrl(filtersElem);\r\n\t\t}\r\n\r\n\t\tthis.updateView();\r\n\t}\r\n\r\n\t/**\r\n\t * Builds the URL hash.\r\n\t *\r\n\t * @param {HTMLElement} filtersElem - The filters element.\r\n\t */\r\n\tbuildUrl(filtersElem) {\r\n\t\tconst url = new URL(window.location.href);\r\n\r\n\t\tvar filtersObj = filtersElem.filtersObj;\r\n\r\n\t\tfiltersObj.forEach((filtersGroupObj) => {\r\n\t\t\tfor (var key in filtersGroupObj) {\r\n\t\t\t\tif (filtersGroupObj[key] != "") {\r\n\t\t\t\t\turl.searchParams.set(key, filtersGroupObj[key]);\r\n\t\t\t\t} else {\r\n\t\t\t\t\turl.searchParams.delete(key);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\twindow.history.pushState("", "", url);\r\n\t}\r\n\r\n\t/**\r\n\t * Updates view.\r\n\t */\r\n\tupdateView() {\r\n\t\tthis.filtersElems.forEach((filtersElem) => {\r\n\t\t\tvar resultsObj = [];\r\n\t\t\tvar filtersObj = filtersElem.filtersObj;\r\n\t\t\tvar filterFor = filtersElem.for;\r\n\r\n\t\t\tvar filterItemsElems = document.querySelectorAll(\'[data-filter-items="\' + filterFor + \'"]\');\r\n\r\n\t\t\tfilterItemsElems.forEach((filterItemsElem) => {\r\n\t\t\t\tvar isEmpty = true;\r\n\r\n\t\t\t\tfilterItemsElem.querySelectorAll("[data-filter-item]").forEach((filterItem) => {\r\n\t\t\t\t\tvar groupMatches = 0;\r\n\t\t\t\t\tvar filterItemObj = filterItem.dataset.filterItem;\r\n\t\t\t\t\tfilterItemObj = JSON.parse(filterItemObj);\r\n\r\n\t\t\t\t\tfiltersObj.forEach((filtersGroupObj) => {\r\n\t\t\t\t\t\tvar match = false;\r\n\t\t\t\t\t\tvar groupActive = false;\r\n\r\n\t\t\t\t\t\tfor (var key in filtersGroupObj) {\r\n\t\t\t\t\t\t\tvar filterItemValue = filterItemObj[key];\r\n\r\n\t\t\t\t\t\t\tif (filterItemValue) {\r\n\t\t\t\t\t\t\t\tfilterItemValue = filterItemValue.split(",");\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\tfilterItemValue = [];\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tvar filtersObjValue = filtersGroupObj[key];\r\n\r\n\t\t\t\t\t\t\tif (key == "fsearch") {\r\n\t\t\t\t\t\t\t\tif (filtersObjValue.length) {\r\n\t\t\t\t\t\t\t\t\tgroupActive = true;\r\n\r\n\t\t\t\t\t\t\t\t\tvar search = filtersObjValue[0];\r\n\t\t\t\t\t\t\t\t\tconst targets = [filterItemObj];\r\n\t\t\t\t\t\t\t\t\tconst options = {\r\n\t\t\t\t\t\t\t\t\t\tthreshold: this.searchThreshold,\r\n\t\t\t\t\t\t\t\t\t\tkeys: Object.keys(filterItemObj),\r\n\t\t\t\t\t\t\t\t\t};\r\n\r\n\t\t\t\t\t\t\t\t\tconst results = fuzzysort__WEBPACK_IMPORTED_MODULE_0___default.a.go(search, targets, options);\r\n\r\n\t\t\t\t\t\t\t\t\tif (results.total > 0) {\r\n\t\t\t\t\t\t\t\t\t\tvar resultsArr = [];\r\n\t\t\t\t\t\t\t\t\t\tmatch = true;
1\r\n\r\n\t\t\t\t\t\t\t\t\t\tresults.forEach((result) => {\r\n\t\t\t\t\t\t\t\t\t\t\tfor (let index = 0; index < Object.keys(filterItemObj).length; index++) {\r\n\t\t\t\t\t\t\t\t\t\t\t\tif (result[index]) {\r\n\t\t\t\t\t\t\t\t\t\t\t\t\tresultsArr.push({\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tkey: Object.keys(filterItemObj)[index],\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\thightlight: fuzzysort__WEBPACK_IMPORTED_MODULE_0___default.a.highlight(result[index], "<x-searchmatch>", "</x-searchmatch>"),\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tscore: result.score,\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t});\r\n\t\t\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\t\t});\r\n\r\n\t\t\t\t\t\t\t\t\t\tresultsObj.push({\r\n\t\t\t\t\t\t\t\t\t\t\tnode: filterItem,\r\n\t\t\t\t\t\t\t\t\t\t\tresults: resultsArr,\r\n\t\t\t\t\t\t\t\t\t\t});\r\n\r\n\t\t\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\tif (filtersObjValue.length && filterItemValue.length) {\r\n\t\t\t\t\t\t\t\t\tgroupActive = true;\r\n\r\n\t\t\t\t\t\t\t\t\tif (filtersObjValue.some((item) => filterItemValue.includes(item))) {\r\n\t\t\t\t\t\t\t\t\t\tmatch = true;\r\n\t\t\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\tif ((groupActive && match) || !groupActive) {\r\n\t\t\t\t\t\t\tgroupMatches++;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t});\r\n\r\n\t\t\t\t\tif (groupMatches == filtersObj.length) {\r\n\t\t\t\t\t\tfilterItem.classList.add("is-match");\r\n\t\t\t\t\t\tisEmpty = false;\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tfilterItem.classList.remove("is-match");\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\r\n\t\t\t\tif (isEmpty) {\r\n\t\t\t\t\tfilterItemsElem.classList.add("is-empty");\r\n\t\t\t\t} else {\r\n\t\t\t\t\tfilterItemsElem.classList.remove("is-empty");\r\n\t\t\t\t}\r\n\r\n\t\t\t\tfiltersElem.dispatchEvent(\r\n\t\t\t\t\tnew CustomEvent("filters:after", {\r\n\t\t\t\t\t\tdetail: { isEmpty: isEmpty, searchResults: resultsObj },\r\n\t\t\t\t\t})\r\n\t\t\t\t);\r\n\t\t\t});\r\n\t\t});\r\n\t}\r\n}\r\n\n\n//# sourceURL=webpack:///./libraries/prx-filters/prx-filters.js?')},
1"./libraries/prx-helpers/prx-helpers.js":function librariesPrxHelpersPrxHelpersJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "lerp", function() { return lerp; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "outerWidth", function() { return outerWidth; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "round", function() { return round; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isTouchDevice", function() { return isTouchDevice; });\n/**\r\n * Utility function to linear interpolate values.\r\n *\r\n * @param {number} start - Value to lerp.\r\n * @param {number} end - Target value.\r\n * @param {number} amount - Easing.\r\n *\r\n * @returns {number} Lerped value.\r\n */\r\nfunction lerp(start, end, amt) {\r\n\treturn (1 - amt) * start + amt * end;\r\n}\r\n\r\n/**\r\n * Utility function to get width with margins included.\r\n *\r\n * @param {HTMLElement} el - Element you want to calculate the outer width of.\r\n *\r\n * @returns {number} - The element\'s outer with.\r\n */\r\nfunction outerWidth(el) {\r\n\tvar width = el.offsetWidth;\r\n\tvar style = getComputedStyle(el);\r\n\r\n\twidth += parseInt(style.marginLeft) + parseInt(style.marginRight);\r\n\treturn width;\r\n}\r\n\r\n/**\r\n * Shortcut for rounding number to second decimal place.\r\n *\r\n * @param {number} numer - Number to round.\r\n *\r\n * @returns {number} - Rounded number to second decimal place.\r\n */\r\nfunction round(number) {\r\n\treturn Math.round((number + Number.EPSILON) * 100) / 100;\r\n}\r\n\r\n/**\r\n * Utility function to check of the device is a touch device.\r\n *\r\n * @returns {boolean} - If device is a touch device or not.\r\n */\r\nfunction isTouchDevice() {\r\n\treturn "ontouchstart" in window || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0;\r\n}\r\n\n\n//# sourceURL=webpack:///./libraries/prx-helpers/prx-helpers.js?')},
1"./libraries/prx-marquee/prx-marquee.js":function librariesPrxMarqueePrxMarqueeJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PrxMarquee", function() { return PrxMarquee; });\n/* harmony import */ var _prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../prx-helpers/prx-helpers */ "./libraries/prx-helpers/prx-helpers.js");\n/**\r\n * Basic marquee with mouse wheel acceleration.\r\n *\r\n * @link https://lesprx.monday.com/docs/4822788437\r\n * @author Les Prétentieux\r\n * @version 1.0.1\r\n *\r\n * */\r\n\r\n\r\n\r\n\r\n\r\nclass PrxMarquee {\r\n\t/**\r\n\t * Init our class.\r\n\t */\r\n\tconstructor() {\r\n\t\tthis.easing = 0.04;\r\n\r\n\t\tthis.defaultSpeed = 1;\r\n\t\tthis.defaultScrollAcceleration = 0.1;\r\n\r\n\t\tthis.scrollSpeed = 0;\r\n\r\n\t\t// Store our marquee values\r\n\t\tthis.prxMarquee = {};\r\n\r\n\t\tthis.marqueeElems = [];\r\n\r\n\t\t// Add our event listeners\r\n\t\twindow.addEventListener("wheel", (event) => this.wheelEvent(event), { passive: true });\r\n\t\twindow.addEventListener("resize", () => this.refresh(), { passive: true });\r\n\r\n\t\tthis.init();\r\n\t}\r\n\r\n\t/**\r\n\t * Update scroll speed on mouse wheel input.\r\n\t *\r\n\t * @param {object} event - The wheel event.\r\n\t */\r\n\twheelEvent(event) {\r\n\t\tthis.scrollSpeed = Math.abs(event.deltaY);\r\n\t}\r\n\r\n\t/**\r\n\t * Initialize marquees.\r\n\t */\r\n\tinit() {\r\n\t\twindow.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;\r\n\r\n\t\tthis.refresh();\r\n\r\n\t\trequestAnimationFrame(() => this.tick());\r\n\t}\r\n\r\n\t/**\r\n\t * Update our marquee related elements.\r\n\t */\r\n\trefresh() {\r\n\t\t// Get all our elements\r\n\t\tthis.marqueeElems = document.querySelectorAll("[data-marquee]");
1\r\n\r\n\t\tthis.marqueeElems.forEach((marqueeElem) => {\r\n\t\t\t// Set defaults\r\n\t\t\tvar direction = marqueeElem.dataset.direction;\r\n\t\t\tvar speed = marqueeElem.dataset.speed;\r\n\t\t\tvar scrollAcceleration = marqueeElem.dataset.scrollAcceleration;\r\n\r\n\t\t\tdirection = direction ? direction : "forwards";\r\n\t\t\tspeed = speed ? speed : this.defaultSpeed;\r\n\t\t\tscrollAcceleration = scrollAcceleration ? scrollAcceleration : this.defaultScrollAcceleration;\r\n\r\n\t\t\t// Create the appropriate amount of content duplicates\r\n\t\t\tvar clonedContentElems = marqueeElem.querySelectorAll(".c-marquee_content.is-clone");\r\n\r\n\t\t\tvar wrapperEl = marqueeElem.querySelector(".c-marquee_wrapper");\r\n\t\t\tvar contentEl = marqueeElem.querySelector(".c-marquee_content");\r\n\r\n\t\t\tclonedContentElems.forEach((clonedContentElem) => {\r\n\t\t\t\tclonedContentElem.remove();\r\n\t\t\t});\r\n\r\n\t\t\tvar marqueeWidth = Object(_prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__["outerWidth"])(marqueeElem);\r\n\t\t\tvar wrapperWidth = Object(_prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__["outerWidth"])(wrapperEl);\r\n\r\n\t\t\tif (wrapperWidth >
1 0) {\r\n\t\t\t\tvar diff = marqueeWidth / wrapperWidth;\r\n\t\t\t\tvar duplications = Math.ceil(diff + 1);\r\n\r\n\t\t\t\tfor (var x = 0; x < duplications; x++) {\r\n\t\t\t\t\tvar clone = wrapperEl.appendChild(contentEl.cloneNode(true));\r\n\t\t\t\t\tclone.classList.add("is-clone");\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Store our marquee object values in the node\r\n\t\t\tthis.prxMarquee = {\r\n\t\t\t\tdirection: direction,\r\n\t\t\t\tspeed: speed,\r\n\t\t\t\tscrollAcceleration: scrollAcceleration,\r\n\t\t\t\ttransform: direction == "reverse" ? -wrapperWidth : 0,\r\n\t\t\t};\r\n\r\n\t\t\tmarqueeElem = Object.assign(marqueeElem, this.prxMarquee);\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * Tick 60 times per second with requestAnimationFrame.\r\n\t */\r\n\ttick() {\r\n\t\t// Todo: if in view\r\n\t\tthis.render();\r\n\r\n\t\trequestAnimationFrame(() => this.tick());\r\n\t}\r\n\r\n\t/**\r\n\t * Render/animate our marquee.\r\n\t */\r\n\trender() {\r\n\t\t// Get smoothed out scroll speed offset\r\n\t\tthis.scrollSpeed = Object(_prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__["round"])(this.scrollSpeed);\r\n\t\tthis.scrollSpeed = Object(_prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__["lerp"])(this.scrollSpeed, 0, 0.04);
1\r\n\r\n\t\tthis.marqueeElems.forEach((marqueeElem) => {\r\n\t\t\tvar direction = marqueeElem.direction;\r\n\t\t\tvar speed = marqueeElem.speed;\r\n\t\t\tvar scrollAcceleration = marqueeElem.scrollAcceleration;\r\n\r\n\t\t\tvar wrapperEl = marqueeElem.querySelector(".c-marquee_wrapper");\r\n\t\t\tvar contentEl = marqueeElem.querySelector(".c-marquee_content");\r\n\r\n\t\t\tvar transformX = marqueeElem.transform;\r\n\r\n\t\t\tif (direction == "reverse") {\r\n\t\t\t\tif (transformX > 0) {\r\n\t\t\t\t\ttransformX = -Object(_prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__["outerWidth"])(contentEl);\r\n\t\t\t\t}\r\n\t\t\t\ttransformX = transformX + (speed * 2 + this.scrollSpeed * scrollAcceleration);\r\n\t\t\t} else {\r\n\t\t\t\tif (-transformX > Object(_prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__["outerWidth"])(contentEl)) {\r\n\t\t\t\t\ttransformX = 0;\r\n\t\t\t\t}\r\n\t\t\t\ttransformX = transformX - (speed * 2 + this.scrollSpeed * scrollAcceleration);\r\n\t\t\t}\r\n\r\n\t\t\ttransformX = Object(_prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__["round"])(transformX);\r\n\r\n\t\t\tmarqueeElem.transform = transformX;\r\n\r\n\t\t\twrapperEl.style.transform = "translate3d(" + transformX + "px, 0, 0)";\r\n\t\t});\r\n\t}\r\n}\r\n\n\n//# sourceURL=webpack:///./libraries/prx-marquee/prx-marquee.js?')},
1"./libraries/prx-scroll/prx-scroll.js":function librariesPrxScrollPrxScrollJs(module,__webpack_exports__,__webpack_require__){eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "PrxScroll", function() { return PrxScroll; });\n/* harmony import */ var _prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../prx-helpers/prx-helpers */ "./libraries/prx-helpers/prx-helpers.js");\n/**\r\n * Native smooth scroll, detection of elements in the viewport and parallax effects.\r\n *\r\n * @link https://lesprx.monday.com/docs/4822787305\r\n * @author Les Prétentieux\r\n * @version 1.0.3\r\n *\r\n * */\r\n\r\n\r\n\r\n\r\n\r\nclass PrxScroll {\r\n\t/**\r\n\t * Init our class.\r\n\t *\r\n\t * @param {object} [options] - PrxScroll options.\r\n\t * @param {number} [options.lerp=0.1] - Easing value.\r\n\t * @param {number} [options.anchorOffset=0] - Offset to the anchor target in pixels.\r\n\t * @param {number} [options.horizontalScrollBreakpoint=1201] - Breakpoint at which the horizontal scroll is disabled.\r\n\t */\r\n\tconstructor({ lerp = 0.1, anchorOffset = 0, horizontalScrollBreakpoint = 1201 } = {}) {\r\n\t\t// Set our constructor options\r\n\t\tthis.easing = lerp;\r\n\t\tthis.anchorOffset = anchorOffset;\r\n\t\tthis.horizontalScrollBreakpoint = horizontalScrollBreakpoint;\r\n\r\n\t\t// Stores the scroll values\r\n\t\tthis.scroll = {};\r\n\r\n\t\t// Stores the scroll inertia values\r\n\t\tthis.inertia = {\r\n\t\t\tcurrent: 0,\r\n\t\t\ttarget: 0,\r\n\t\t};\r\n\r\n\t\t// Global state variables\r\n\t\tthis.isTouch = false;\r\n\t\tthis.isHorizontalScrollActive = false;\r\n\r\n\t\t// Store all our scroll elements\r\n\t\tthis.inViewElems = [];\r\n\t\tthis.parallaxElems = [];\r\n\t\tthis.anchorElems = [];\r\n\t\tthis.horizontalScrollSections = [];\r\n\t\tthis.progressElems = [];\r\n\t\tthis.inertiaElems = [];\r\n\r\n\t\t// Add our event listeners\r\n\t\twindow.addEventListener("wheel", (event) => this.wheelEvent(event), { passive: false });\r\n\t\twindow.addEventListener("scroll", () => this.scrollEvent(), { passive: true });\r\n\t\twindow.addEventListener("resize", () => this.resizeEvent(), { passive: true });\r\n\r\n\t\tthis.init();\r\n\t}\r\n\r\n\t/**\r\n\t * Initialize smooth scroll and add events.\r\n\t */\r\n\tinit() {\r\n\t\twindow.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;\r\n\r\n\t\t// Set ours scroll values to the current scroll value\r\n\t\tthis.syncPos();\r\n\r\n\t\t// Check if device is touch\r\n\t\tif (Object(_prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__["isTouchDevice"])()) {\r\n\t\t\tthis.isTouch = true;\r\n\t\t}\r\n\r\n\t\t// If device is not touch, initialize smooth scroll\r\n\t\tif (!this.isTouch) {\r\n\t\t\trequestAnimationFrame(() => this.tick());\r\n\t\t\tdocument.querySelector("html").classList.add("is-smooth-scroll");\r\n\t\t}\r\n\r\n\t\t// Check if horizontal scroll\r\n\t\tthis.isHorizontalScrollActive = window.matchMedia("(min-width: " + this.horizontalScrollBreakpoint + "px)").matches && !this.isTouch;\r\n\r\n\t\t// Get all our elements\r\n\t\tthis.getScrollElements();\r\n\r\n\t\t// Update scroll elements\r\n\t\tthis.updateScrollElements();\r\n\r\n\t\t// Set anchor events\r\n\t\tthis.setAnchorEvents();\r\n\t}\r\n\r\n\t/**\r\n\t * Update our scroll related elements.\r\n\t */\r\n\trefresh() {\r\n\t\t// Empty all elements\r\n\t\tthis.clearScrollElements();\r\n\r\n\t\t// Get all our elements\r\n\t\tthis.getScrollElements();\r\n\r\n\t\t// Update in view and parallax elements\r\n\t\tthis.updateScrollElements();\r\n\r\n\t\tthis.setAnchorEvents();\r\n\t}\r\n\r\n\t/**\r\n\t * Update our scroll related events on scroll.\r\n\t */\r\n\tscrollEvent() {\r\n\t\tthis.updateScrollElements();\r\n\t}\r\n\r\n\t/**\r\n\t * Update our scroll related events on resize.\r\n\t */\r\n\tresizeEvent() {\r\n\t\tthis.updateScrollElements();\r\n\t}\r\n\r\n\t/**\r\n\t * Clear our scroll related elements.\r\n\t */\r\n\tclearScrollElements() {\r\n\t\tthis.inViewElems = [];\r\n\t\tthis.parallaxElems = [];\r\n\t\tthis.anchorElems = [];\r\n\t\tthis.horizontalScrollSections = [];\r\n\t\tthis.progressElems = [];\r\n\t\tthis.inertiaElems = [];\r\n\t}\r\n\r\n\t/**\r\n\t * Set our scroll related elements.\r\n\t */\r\n\tgetScrollElements() {\r\n\t\tthis.inViewElems = document.querySelectorAll("[data-scroll-in-view]");\r\n\t\tthis.parallaxElems = document.querySelectorAll("[data-scroll-parallax]");\r\n\t\tthis.anchorElems = document.querySelectorAll("[data-scroll-anchor]");\r\n\t\tthis.horizontalScrollSections = document.querySelectorAll("[data-scroll-horizontal]");\r\n\t\tthis.progressElems = document.querySelectorAll("[data-scroll-progress]");\r\n\t\tthis.inertiaElems = document.querySelectorAll("[data-scroll-inertia]");\r\n\t}\r\n\r\n\t/**\r\n\t * Update our scroll related elements.\r\n\t */\r\n\tupdateScrollElements() {\r\n\t\tthis.updateInView();\r\n\t\tthis.updateParallax();\r\n\t\tthis.updateProgress();\r\n\r\n\t\tif (this.isHorizontalScrollActive) {\r\n\t\t\tdocument.querySelector("html").classList.add("is-horizontal-scroll-active");\r\n\t\t\tthis.initHorizontalScroll();\r\n\t\t\tthis.updateHorizontalScroll();\r\n\t\t} else {\r\n\t\t\tdocument.querySelector("html").classList.remove("is-horizontal-scroll-active");\r\n\t\t}\r\n\r\n\t\tthis.updateHorizontalScrollStickyElements();\r\n\t}\r\n\r\n\t/**\r\n\t * Update scroll target on mouse wheel input.\r\n\t */\r\n\twheelEvent(event) {\r\n\t\tvar hoveredElems = document.querySelectorAll(":hover");\r\n\t\tvar scrollableElems = 0;
1\r\n\r\n\t\thoveredElems.forEach((hoveredElem) => {\r\n\t\t\tif (this.isScrollable(hoveredElem)) {\r\n\t\t\t\tscrollableElems++;\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t// This means we\'re scrolling in the document (so if we were to scroll anywhere else, the default scroll would be taking place instead)\r\n\t\tif (scrollableElems < 1 && !this.isTouch) {\r\n\t\t\tevent.preventDefault();\r\n\t\t\tvar scrollSpeed = event.deltaY;\r\n\t\t\tthis.scroll.target = this.capScrollPosition(this.scroll.target + scrollSpeed);\r\n\t\t}\r\n\t}\r\n\r\n\tsetAnchorEvents() {\r\n\t\tthis.anchorElems.forEach((anchorElem) => {\r\n\t\t\tanchorElem.addEventListener("click", (event) => this.anchorClick(event, anchorElem));\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * Scroll to specified section when user clicks on a smooth anchor link.\r\n\t * @param {object} event - The click event.\r\n\t * @param {HTMLElement} anchorElem - The clicked anchor element.\r\n\t */\r\n\tanchorClick(event, anchorElem) {\r\n\t\tevent.preventDefault();\r\n\t\tvar href = anchorElem.getAttribute("href");\r\n\t\tthis.scrollTo(href, false, this.anchorOffset);\r\n\t}\r\n\r\n\t/**\r\n\t * Tick 60 times per second with requestAnimationFrame.\r\n\t */\r\n\ttick() {\r\n\t\t// Only render when our scroll position is different from our scroll target (when moving)\r\n\t\tif (Math.round(this.scroll.pos) != Math.round(this.scroll.target)) {\r\n\t\t\tthis.render();\r\n\t\t} else {\r\n\t\t\t// Sync scroll position when user stops scrolling\r\n\t\t\tthis.syncPos();\r\n\t\t}\r\n\r\n\t\t// Update our scroll intertia in the "tick" function so it can keep easing after the scroll has finished\r\n\t\tthis.updateScrollInertia();\r\n\r\n\t\trequestAnimationFrame(() => this.tick());\r\n\t}\r\n\r\n\t/**\r\n\t * Render/animate our scroll\r\n\t */\r\n\trender() {\r\n\t\tif (!document.querySelector("html").classList.contains("is-lock-scroll")) {\r\n\t\t\tthis.scroll.pos = Object(_prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__["round"])(Object(_prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__["lerp"])(this.scroll.pos, this.scroll.target, this.easing));\r\n\t\t\twindow.scroll(0, this.scroll.pos);\r\n\t\t} else {\r\n\t\t\tthis.syncPos();\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Scroll to a specified target or fixed pixel value.\r\n\t *\r\n\t * @param {string|number} target - Selector to scroll to or fixed position to scroll to (in pixels).\r\n\t * @param {boolean} instant - Specify if the transition is instant or smooth.\r\n\t */\r\n\tscrollTo(target, instant = false, offset = 0) {\r\n\t\tvar pos = 0;\r\n\r\n\t\t// If target is not a number, interpret it as a query selector\r\n\t\tif (isNaN(target)) {\r\n\t\t\t// Get position of target element\r\n\t\t\tvar targetEl = document.querySelector(target);\r\n\t\t\tvar rect = targetEl.getBoundingClientRect();\r\n\t\t\tpos = this.capScrollPosition(rect.top + window.scrollY);\r\n\t\t} else {\r\n\t\t\tpos = target;\r\n\t\t}\r\n\r\n\t\tpos = Object(_prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__["round"])(pos - offset);\r\n\r\n\t\t// If device is touch, scroll to position instantly\r\n\t\tif (this.isTouch) {\r\n\t\t\twindow.scroll(0, pos);\r\n\t\t} else {\r\n\t\t\tthis.scroll.target = pos;\r\n\r\n\t\t\tif (instant) {\r\n\t\t\t\tthis.scroll.pos = pos;\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Update our parallax elements\' values.\r\n\t */\r\n\tupdateParallax() {\r\n\t\tthis.parallaxElems.forEach((parallaxElem) => {\r\n\t\t\tvar parallaxDirection = parallaxElem.getAttribute("data-parallax-direction") ? parallaxElem.getAttribute("data-parallax-direction") : "vertical";\r\n\t\t\tvar parallaxSpeed = parallaxElem.getAttribute("data-parallax-speed") ? parallaxElem.getAttribute("data-parallax-speed") : 1;\r\n\r\n\t\t\t// Get progress of element on scroll (from 0 to 1)\r\n\t\t\tvar progress = this.getProgress(parallaxElem);\r\n\t\t\t// Convert the scale to -0.5 to 0.5 so we reach 0 when element is centered in the viewport\r\n\t\t\tvar scale = progress - 0.5;\r\n\t\t\t// Reverse and multiply scale to accentuate transform\r\n\t\t\tvar transform = scale * -100;\r\n\t\t\t// Add our parallax speed multiplier\r\n\t\t\ttransform = transform * parallaxSpeed;\r\n\t\t\t// Round our transform to 2 decimal places\r\n\t\t\ttransform = Object(_prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__["round"])(transform);\r\n\r\n\t\t\tvar transformValue;\r\n\r\n\t\t\tif (parallaxDirection == "vertical") {\r\n\t\t\t\ttransformValue = "translate3d(0, " + transform + "px, 0)";\r\n\t\t\t} else {\r\n\t\t\t\ttransformValue = "translate3d(" + transform + "px, 0, 0)";\r\n\t\t\t}\r\n\r\n\t\t\tparallaxElem.style.transform = transformValue;\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * Update our in-view elements.\r\n\t */\r\n\tupdateInView() {\r\n\t\tthis.inViewElems.forEac
1h((inViewElem) => {\r\n\t\t\tvar inViewOffset = inViewElem.dataset.inViewOffset;\r\n\t\t\tinViewOffset = inViewOffset ? inViewOffset : 0;\r\n\r\n\t\t\tif (this.elementInViewport(inViewElem, inViewOffset)) {\r\n\t\t\t\tinViewElem.classList.add("is-inview");\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * Update our progress elements.\r\n\t */\r\n\tupdateProgress() {\r\n\t\tthis.progressElems.forEach((progressElem) => {\r\n\t\t\tvar progressOrigin = progressElem.dataset.progressOrigin;\r\n\t\t\tvar progress = this.getProgress(progressElem, progressOrigin);\r\n\t\t\tprogressElem.style.setProperty("--progress", progress);\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * Init our horizontal scroll sections.\r\n\t */\r\n\tinitHorizontalScroll() {\r\n\t\tthis.horizontalScrollSections.forEach((horizontalScrollSection) => {\r\n\t\t\tvar horizontalScrollSectionInner = horizontalScrollSection.querySelector(".o-horizontal-layout_inner");\r\n\t\t\tvar windowWidth = document.documentElement.clientWidth;\r\n\r\n\t\t\tvar elOuterWidth = 0;\r\n\t\t\tArray.from(horizontalScrollSectionInner.children).forEach((element) => {\r\n\t\t\t\telOuterWidth += Object(_prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__["outerWidth"])(element);\r\n\t\t\t});\r\n\r\n\t\t\tvar horizontalScrollOffset = elOuterWidth - windowWidth;\r\n\r\n\t\t\thorizontalScrollSection.style.setProperty("--offset", horizontalScrollOffset + "px");\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * Update our horizontal scroll sections.\r\n\t */\r\n\tupdateHorizontalScroll() {\r\n\t\tthis.horizontalScrollSections.forEach((horizontalScrollSection) => {\r\n\t\t\tvar horizontalScrollSectionInner = horizontalScrollSection.querySelector(".o-horizontal-layout_inner");\r\n\t\t\tvar rect = horizontalScrollSection.getBoundingClientRect();\r\n\t\t\tvar initialScrollOffset = horizontalScrollSection.offsetTop;\r\n\t\t\tvar horizontalScrollOffset = parseInt(getComputedStyle(horizontalScrollSection).getPropertyValue("--offset"));\r\n\r\n\t\t\tif (rect.top <= 0 && rect.bottom > document.documentElement.clientHeight) {\r\n\t\t\t\thorizontalScrollSectionInner.style.transform = "translate3d(" + Math.max(Math.min(initialScrollOffset - this.scroll.pos, 0), -horizontalScrollOffset) + "px, 0, 0)";\r\n\t\t\t\thorizontalScrollSectionInner.classList.remove("is-before");\r\n\t\t\t\thorizontalScrollSectionInner.classList.remove("is-after");\r\n\t\t\t\thorizontalScrollSectionInner.classList.add("is-inside");\r\n\t\t\t} else if (rect.top > 0) {\r\n\t\t\t\thorizontalScrollSectionInner.classList.remove("is-inside");\r\n\t\t\t\thorizontalScrollSectionInner.classList.remove("is-after");\r\n\t\t\t\thorizontalScrollSectionInner.classList.add("is-before");\r\n\t\t\t} else if (rect.bottom <= document.documentElement.clientHeight) {\r\n\t\t\t\thorizontalScrollSectionInner.classList.remove("is-before");\r\n\t\t\t\thorizontalScrollSectionInner.classList.remove("is-inside");\r\n\t\t\t\thorizontalScrollSectionInner.classList.add("is-after");\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * Update our horizontal scroll sticky elements.\r\n\t */\r\n\tupdateHorizontalScrollStickyElements() {\r\n\t\tthis.horizontalScrollSections.forEach((horizontalScrollSection) => {\r\n\t\t\tvar horizontalScrollSectionInner = horizontalScrollSection.querySelector(".o-horizontal-layout_inner");\r\n\t\t\tvar rect = horizontalScrollSection.getBoundingClientRect();\r\n\r\n\t\t\tif (this.isHorizontalScrollActive) {\r\n\t\t\t\tif (rect.top <= 0 && rect.bottom > document.documentElement.clientHeight) {\r\n\t\t\t\t\tvar horizontalScrollStickyElems = horizontalScrollSection.querySelectorAll("[data-scroll-sticky]");\r\n\r\n\t\t\t\t\thorizontalScrollStickyElems.forEach((horizontalScrollStickyElem) => {\r\n\t\t\t\t\t\tvar wrapper = horizontalScrollStickyElem.parentElement;\r\n\t\t\t\t\t\tvar offset = horizontalScrollStickyElem.getBoundingClientRect().width;\r\n\t\t\t\t\t\tvar rect = wrapper.getBoundingClientRect();\r\n\t\t\t\t\t\tvar numerator = -rect.left;\r\n\t\t\t\t\t\tvar denominator = rect.width - offset;\r\n\r\n\t\t\t\t\t\tvar progress = Math.min(Math.max(numerator / denominator, 0), 1);\r\n\r\n\t\t\t\t\t\tif (progress > 0 && progress < 1) {\r\n\t\t\t\t\t\t\thorizontalScrollStickyElem.style.transform = "translate3d(" + (this.scroll.pos - (wrapper.getBoundingClientRect().left - horizontalScrollSectionInner.getBoundingClientRect().left)) + "px, 0, 0)";\r\n\t\t\t\t\t\t} else if (progress <= 0) {\r\n\t\t\t\t\t\t\thorizontalScrollStickyElem.style.transform = "translate3d(0, 0, 0)";\r\n\t\t\t\t\t\t} else if (progress >= 1) {\r\n\t\t\t\t\t\t\thorizontalScrollStickyElem.style.transform = "translate3d(" + (wrapper.getBoundingClientRect().width - horizontalScrollStickyElem.getBoundingClientRect().width) + "px, 0, 0)";\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t});\r\n\t\t\t\t}\r\n\t\t\t} else {\r\n\t\t\t\tvar horizontalScrollStickyElems = horizontalScrollSection.querySelectorAll("[data-scroll-sticky]");
1\r\n\r\n\t\t\t\thorizontalScrollStickyElems.forEach((horizontalScrollStickyElem) => {\r\n\t\t\t\t\tvar wrapper = horizontalScrollStickyElem.parentElement;\r\n\t\t\t\t\tvar offset = horizontalScrollStickyElem.getBoundingClientRect().height;\r\n\t\t\t\t\tvar rect = wrapper.getBoundingClientRect();\r\n\t\t\t\t\tvar numerator = -rect.top;\r\n\t\t\t\t\tvar denominator = rect.height - offset;\r\n\r\n\t\t\t\t\tvar progress = Math.min(Math.max(numerator / denominator, 0), 1);\r\n\r\n\t\t\t\t\tif (progress > 0 && progress < 1) {\r\n\t\t\t\t\t\thorizontalScrollStickyElem.style.position = "fixed";\r\n\t\t\t\t\t\thorizontalScrollStickyElem.style.top = "0px";\r\n\t\t\t\t\t\thorizontalScrollStickyElem.style.transform = "none";\r\n\t\t\t\t\t} else if (progress <= 0) {\r\n\t\t\t\t\t\thorizontalScrollStickyElem.style.position = "relative";\r\n\t\t\t\t\t} else if (progress >= 1) {\r\n\t\t\t\t\t\twrapper.style.position = "relative";\r\n\t\t\t\t\t\thorizontalScrollStickyElem.style.position = "absolute";\r\n\t\t\t\t\t\thorizontalScrollStickyElem.style.top = "";\r\n\t\t\t\t\t\thorizontalScrollStickyElem.style.bottom = "0px";\r\n\t\t\t\t\t}\r\n\t\t\t\t});\r\n\t\t\t}\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * Update scroll inertia.\r\n\t */\r\n\tupdateScrollInertia() {\r\n\t\tthis.inertia.target = this.scroll.target - this.scroll.pos;\r\n\r\n\t\tthis.inertia.current = Object(_prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__["round"])(Object(_prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__["lerp"])(this.inertia.current, this.inertia.target, this.easing));\r\n\r\n\t\tvar inertia = this.inertia.current;\r\n\t\tinertia = inertia / 100;\r\n\t\tinertia = Math.min(Math.max(inertia, -1), 1);\r\n\t\tinertia = Object(_prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__["round"])(inertia);\r\n\r\n\t\tthis.inertiaElems.forEach((inertiaElem) => {\r\n\t\t\tinertiaElem.style.setProperty("--scroll-inertia", inertia);\r\n\t\t});\r\n\t}\r\n\r\n\t/**\r\n\t * Sync the scroll position to the current scroll position of the window.\r\n\t */\r\n\tsyncPos() {\r\n\t\tthis.scroll.pos = Object(_prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__["round"])(window.pageYOffset);\r\n\t\tthis.scroll.target = Object(_prx_helpers_prx_helpers__WEBPACK_IMPORTED_MODULE_0__["round"])(window.pageYOffset);\r\n\t}\r\n\r\n\t/**\r\n\t * Get the progress of an element in the viewport (from 0 to 1).\r\n\t *\r\n\t * @param {HTMLElement} el - The element to return the progress of.\r\n\t * @param {string} [progressOrigin=center] - The origin from where the progress should be calculated. Defaults to "center".\r\n\t */\r\n\tgetProgress(el, progressOrigin = "center") {\r\n\t\tvar rect = el.getBoundingClientRect();\r\n\t\tvar numerator;\r\n\t\tvar denominator;\r\n\t\tvar progress;\r\n\r\n\t\tif (el.closest("[data-scroll-horizontal]") && this.isHorizontalScrollActive) {\r\n\t\t\tswitch (progressOrigin) {\r\n\t\t\t\tcase "center":\r\n\t\t\t\t\tprogressOrigin = "center-horizontal";\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase "top":\r\n\t\t\t\t\tprogressOrigin = "left";\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase "bottom":\r\n\t\t\t\t\tprogressOrigin = "right";\r\n\t\t\t\t\tbreak;\r\n\t\t\t\tcase "between":\r\n\t\t\t\t\tprogressOrigin = "between-horizontal";\r\n\t\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (progressOrigin == "top") {\r\n\t\t\tnumerator = -rect.top;\r\n\t\t\tdenominator = rect.height;\r\n\t\t} else if (progressOrigin == "bottom") {\r\n\t\t\tnumerator = (rect.top - document.documentElement.clientHeight) * -1;\r\n\t\t\tdenominator = rect.height;\r\n\t\t} else if (progressOrigin == "between") {\r\n\t\t\tnumerator = -rect.top;\r\n\t\t\tdenominator = rect.height - document.documentElement.clientHeight;\r\n\t\t} else if (progressOrigin == "left") {\r\n\t\t\tnumerator = -rect.left;\r\n\t\t\tdenominator = rect.width;\r\n\t\t} else if (progressOrigin == "right") {\r\n\t\t\tnumerator = (rect.left - document.documentElement.clientWidth) * -1;\r\n\t\t\tdenominator = rect.width;\r\n\t\t} else if (progressOrigin == "center-horizontal") {\r\n\t\t\tnumerator = (rect.left - document.documentElement.clientWidth) * -1;\r\n\t\t\tdenominator = rect.width + document.documentElement.clientWidth;\r\n\t\t} else if (progressOrigin == "between-horizontal") {\r\n\t\t\tnumerator = -rect.left;\r\n\t\t\tdenominator = rect.width - document.documentElement.clientWidth;\r\n\t\t} else {\r\n\t\t\tnumerator = (rect.top - document.documentElement.clientHeight) * -1;\r\n\t\t\tdenominator = rect.height + document.documentElement.clientHeight;\r\n\t\t}\r\n\r\n\t\tprogress = Math.min(Math.max(numerator / denominator, 0), 1);\r\n\r\n\t\treturn progress;\r\n\t}\r\n\r\n\t/**\r\n\t * Keep scroll position between 0 and the end of the document.\r\n\t *\r\n\t * @param {number} pos - The scroll position to cap.\r\n\t */\r\n\tcapScrollPosition(pos) {\r\n\t\treturn Math.min(Math.max(pos, 0), document.documentElement.scrollHeight - document.documentElement.clientHeight);\r\n\t}\r\n\r\n\t/**\r\n\t * Utility function to check of a given element is in the viewport.\r\n\t *\r\n\t * @param {HTMLElement} el - Element to check if in viewport.\r\n\t * @param {number} offset - Offset in percent.\r\n\t *\r\n\t * @returns {boolean} If element in viewport or not.\r\n\t */\r\n\telementInViewport(el, offset = 0) {\r\n\t\tvar rect = el.getBoundingClientRect();\r\n\r\n\t\t// If element is in horizontal scroll container\r\n\t\tif (el.closest("[data-scroll-horizontal]")) {\r\n\t\t\treturn rect.left - document.documentElement.clientWidth + document.documentElement.clientWidth * offset <= 0;\r\n\t\t} else {\r\n\t\t\treturn rect.top - document.documentElement.clientHeight + document.documentElement.clientHeight * offset <= 0;\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Utility function to check if element is scrollable.\r\n\t *\r\n\t * @param {HTMLElement} el - Element to check.\r\n\t *\r\n\t * @returns {boolean} - If element is scrollable or not.\r\n\t */\r\n\tisScrollable(el) {\r\n\t\treturn el.scrollHeight > el.clientHeight && ["scroll", "auto"].indexOf(getComputedStyle(el).overflowY) >= 0;\r\n\t}\r\n}\r\n\n\n//# sourceURL=webpack:///./libraries/prx-scroll/prx-scroll.js?')},
vendor: 24,137 bytes, line 1
1"./node_modules/fuzzysort/fuzzysort.js":function node_modulesFuzzysortFuzzysortJs(module,exports,__webpack_require__){eval("var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;// https://github.com/farzher/fuzzysort v2.0.4\r\n/*\r\n  SublimeText-like Fuzzy Search\r\n\r\n  fuzzysort.single('fs', 'Fuzzy Search') // {score: -16}\r\n  fuzzysort.single('test', 'test') // {score: 0}\r\n  fuzzysort.single('doesnt exist', 'target') // null\r\n\r\n  fuzzysort.go('mr', [{file:'Monitor.cpp'}, {file:'MeshRenderer.cpp'}], {key:'file'})\r\n  // [{score:-18, obj:{file:'MeshRenderer.cpp'}}, {score:-6009, obj:{file:'Monitor.cpp'}}]\r\n\r\n  fuzzysort.go('mr', ['Monitor.cpp', 'MeshRenderer.cpp'])\r\n  // [{score: -18, target: \"MeshRenderer.cpp\"}, {score: -6009, target: \"Monitor.cpp\"}]\r\n\r\n  fuzzysort.highlight(fuzzysort.single('fs', 'Fuzzy Search'), '<b>', '</b>')\r\n  // <b>F</b>uzzy <b>S</b>earch\r\n*/\r\n\r\n// UMD (Universal Module Definition) for fuzzysort\r\n;((root, UMD) => {\r\n  if(true) !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (UMD),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?\n\t\t\t\t(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__))\r\n  else {}\r\n})(this, _ => {\r\n  'use strict'\r\n\r\n  var single = (search, target) => {                                                                                                                                                                                                                        if(search=='farzher')return{target:\"farzher was here (^-^*)/\",score:0,_indexes:[0]}\r\n    if(!search || !target) return NULL\r\n\r\n    var preparedSearch = getPreparedSearch(search)\r\n    if(!isObj(target)) target = getPrepared(target)\r\n\r\n    var searchBitflags = preparedSearch.bitflags\r\n    if((searchBitflags & target._bitflags) !== searchBitflags) return NULL\r\n\r\n    return algorithm(preparedSearch, target)\r\n  }\r\n\r\n\r\n  var go = (search, targets, options) => {                                                                                                                                                                                                                  if(search=='farzher')return[{target:\"farzher was here (^-^*)/\",score:0,_indexes:[0],obj:targets?targets[0]:NULL}]\r\n    if(!search) return options&&options.all ? all(search, targets, options) : noResults\r\n\r\n    var preparedSearch = getPreparedSearch(search)\r\n    var searchBitflags = preparedSearch.bitflags\r\n    var containsSpace  = preparedSearch.containsSpace\r\n\r\n    var threshold = options&&options.threshold || INT_MIN\r\n    var limit     = options&&options['limit']  || INT_MAX // for some reason only limit breaks when minified\r\n\r\n    var resultsLen = 0; var limitedCount = 0\r\n    var targetsLen = targets.length\r\n\r\n    // This code is copy/pasted 3 times for performance reasons [options.keys, options.key, no keys]\r\n\r\n    // options.key\r\n    if(options && options.key) {\r\n      var key = options.key\r\n      for(var i = 0; i < targetsLen; ++i) { var obj = targets[i]\r\n        var target = getValue(obj, key)\r\n        if(!target) continue\r\n        if(!isObj(target)) target = getPrepared(target)\r\n\r\n        if((searchBitflags & target._bitflags) !== searchBitflags) continue\r\n        var result = algorithm(preparedSearch, target)\r\n        if(result === NULL) continue\r\n        if(result.score < threshold) continue\r\n\r\n        // have to clone result so duplicate targets from different obj can each reference the correct obj\r\n        result = {target:result.target, _targetLower:'', _targetLowerCodes:NULL, _nextBeginningIndexes:NULL, _bitflags:0, score:result.score, _indexes:result._indexes, obj:obj} // hidden\r\n\r\n        if(resultsLen < limit) { q.add(result); ++resultsLen }\r\n        else {\r\n          ++limitedCount\r\n          if(result.score > q.peek().score) q.replaceTop(result)\r\n        }\r\n      }\r\n\r\n    // options.keys\r\n    } else if(options && options.keys) {\r\n      var scoreFn = options['scoreFn'] || defaultScoreFn\r\n      var keys = options.keys\r\n      var keysLen = keys.length\r\n      for(var i = 0; i < targetsLen; ++i) { var obj = targets[i]\r\n        var objResults = new Array(keysLen)\r\n        for (var keyI = 0; keyI < keysLen; ++keyI) {\r\n          var key = keys[keyI]\r\n          var target = getValue(obj, key)\r\n          if(!target) { objResults[keyI] = NULL; continue }\r\n          if(!isObj(target)) target = getPrepared(target)\r\n\r\n          if((searchBitflags & target._bitflags) !== searchBitflags) objResults[keyI] = NULL\r\n          else objResults[keyI] = algorithm(preparedSearch, target)\r\n        }\r\n        objResults.obj = obj // before scoreFn so scoreFn can use it\r\n        var score = scoreFn(objResults)\r\n        if(score === NULL) continue\r\n        if(score < threshold) continue\r\n        objResults.score = score\r\n        if(resultsLen < limit) { q.add(objResults); ++resultsLen }\r\n        else {\r\n          ++limitedCount\r\n          if(score > q.peek().score) q.replaceTop(objResults)\r\n        }\r\n      }\r\n\r\n    // no keys\r\n    } else {\r\n      for(var i = 0; i < targetsLen; ++i) { var target = targets[i]\r\n        if(!target) continue\r\n        if(!isObj(target)) target = getPrepared(target)\r\n\r\n        if((searchBitflags & target._bitflags) !== searchBitflags) continue\r\n        var result = algorithm(preparedSearch, target)\r\n        if(result === NULL) continue\r\n        if(result.score < threshold) continue\r\n        if(resultsLen < limit) { q.add(result); ++resultsLen }\r\n        else {\r\n          ++limitedCount\r\n          if(result.score > q.peek().score) q.replaceTop(result)\r\n        }\r\n      }\r\n    }\r\n\r\n    if(resultsLen === 0) return noResults\r\n    var results = new Array(resultsLen)\r\n    for(var i = resultsLen - 1; i >= 0; --i) results[i] = q.poll()\r\n    results.total = resultsLen + limitedCount\r\n    return results\r\n  }\r\n\r\n\r\n  var highlight = (result, hOpen, hClose) => {\r\n    if(typeof hOpen === 'function') return highlightCallback(result, hOpen)\r\n    if(result === NULL) return NULL\r\n    if(hOpen === undefined) hOpen = '<b>'\r\n    if(hClose === undefined) hClose = '</b>'\r\n    var highlighted = ''\r\n    var matchesIndex = 0\r\n    var opened = false\r\n    var target = result.target\r\n    var targetLen = target.length\r\n    var indexes = result._indexes\r\n    indexes = indexes.slice(0, indexes.len).sort((a,b)=>a-b)\r\n    for(var i = 0; i < targetLen; ++i) { var char = target[i]\r\n      if(indexes[matchesIndex] === i) {\r\n        ++matchesIndex\r\n        if(!opened) { opened = true\r\n          highlighted += hOpen\r\n        }\r\n\r\n        if(matchesIndex === indexes.length) {\r\n          highlighted += char + hClose + target.substr(i+1)\r\n          break\r\n        }\r\n      } else {\r\n        if(opened) { opened = false\r\n          highlighted += hClose\r\n        }\r\n      }\r\n      highlighted += char\r\n    }\r\n\r\n    return highlighted\r\n  }\r\n  var highlightCallback = (result, cb) => {\r\n    if(result === NULL) return NULL\r\n    var target = result.target\r\n    var targetLen = target.length\r\n    var indexes = result._indexes\r\n    indexes = indexes.slice(0, indexes.len).sort((a,b)=>a-b)\r\n    var highlighted = ''\r\n    var matchI = 0\r\n    var indexesI = 0\r\n    var opened = false\r\n    var result = []\r\n    for(var i = 0; i < targetLen; ++i) { var char = target[i]\r\n      if(indexes[indexesI] === i) {\r\n        ++indexesI\r\n        if(!opened) { opened = true\r\n          result.push(highlighted); highlighted = ''\r\n        }\r\n\r\n        if(indexesI === indexes.length) {\r\n          highlighted += char\r\n          result.push(cb(highlighted, matchI++)); highlighted = ''\r\n          result.push(target.substr(i+1))\r\n          break\r\n        }\r\n      } else {\r\n        if(opened) { opened = false\r\n          result.push(cb(highlighted, matchI++)); highlighted = ''\r\n        }\r\n      }\r\n      highlighted += char\r\n    }\r\n    return result\r\n  }\r\n\r\n\r\n  var indexes = result => result._indexes.slice(0, result._indexes.len).sort((a,b)=>a-b)\r\n\r\n\r\n  var prepare = (target) => {\r\n    if(typeof target !== 'string') target = ''\r\n    var info = prepareLowerInfo(target)\r\n    return {'target':target, _targetLower:info._lower, _targetLowerCodes:info.lowerCodes, _nextBeginningIndexes:NULL, _bitflags:info.bitflags, 'score':NULL, _indexes:[0], 'obj':NULL} // hidden\r\n  }\r\n\r\n\r\n  // Below this point is only internal code\r\n  // Below this point is only internal code\r\n  // Below this point is only internal code\r\n  // Below this point is only internal code\r\n\r\n\r\n  var prepareSearch = (search) => {\r\n    if(typeof search !== 'string') search = ''\r\n    search = search.trim()\r\n    var info = prepareLowerInfo(search)\r\n\r\n    var spaceSearches = []\r\n    if(info.containsSpace) {\r\n      var searches = search.split(/\\s+/)\r\n      searches = [...new Set(searches)] // distinct\r\n      for(var i=0; i<searches.length; i++) {\r\n        if(searches[i] === '') continue\r\n        var _info = prepareLowerInfo(searches[i])\r\n        spaceSearches.push({lowerCodes:_info.lowerCodes, _lower:searches[i].toLowerCase(), containsSpace:false})\r\n      }\r\n    }\r\n\r\n    return {lowerCodes: info.lowerCodes, bitflags: info.bitflags, containsSpace: info.containsSpace, _lower: info._lower, spaceSearches: spaceSearches}\r\n  }\r\n\r\n\r\n\r\n  var getPrepared = (target) => {\r\n    if(target.length > 999) return prepare(target) // don't cache huge targets\r\n    var targetPrepared = preparedCache.get(target)\r\n    if(targetPrepared !== undefined) return targetPrepared\r\n    targetPrepared = prepare(target)\r\n    preparedCache.set(target, targetPrepared)\r\n    return targetPrepared\r\n  }\r\n  var getPreparedSearch = (search) => {\r\n    if(search.length > 999) return prepareSearch(search) // don't cache huge searches\r\n    var searchPrepared = preparedSearchCache.get(search)\r\n    if(searchPrepared !== undefined) return searchPrepared\r\n    searchPrepared = prepareSearch(search)\r\n    preparedSearchCache.set(search, searchPrepared)\r\n    return searchPrepared\r\n  }\r\n\r\n\r\n  var all = (search, targets, options) => {\r\n    var results = []; results.total = targets.length\r\n\r\n    var limit = options && options.limit || INT_MAX\r\n\r\n    if(options && options.key) {\r\n      for(var i=0;i<targets.length;i++) { var obj = targets[i]\r\n        var target = getValue(obj, options.key)\r\n        if(!target) continue\r\n        if(!isObj(target)) target = getPrepared(target)\r\n        target.score = INT_MIN\r\n        target._indexes.len = 0\r\n        var result = target\r\n        result = {target:result.target, _targetLower:'', _targetLowerCodes:NULL, _nextBeginningIndexes:NULL, _bitflags:0, score:target.score, _indexes:NULL, obj:obj} // hidden\r\n        results.push(result); if(results.length >= limit) return results\r\n      }\r\n    } else if(options && options.keys) {\r\n      for(var i=0;i<targets.length;i++) { var obj = targets[i]\r\n        var objResults = new Array(options.keys.length)\r\n        for (var keyI = options.keys.length - 1; keyI >= 0; --keyI) {\r\n          var target = getValue(obj, options.keys[keyI])\r\n          if(!target) { objResults[keyI] = NULL; continue }\r\n          if(!isObj(target)) target = getPrepared(target)\r\n          target.score = INT_MIN\r\n          target._indexes.len = 0\r\n          objResults[keyI] = target\r\n        }\r\n        objResults.obj = obj\r\n        objResults.score = INT_MIN\r\n        results.push(objResults); if(results.length >= limit) return results\r\n      }\r\n    } else {\r\n      for(var i=0;i<targets.length;i++) { var target = targets[i]\r\n        if(!target) continue\r\n        if(!isObj(target)) target = getPrepared(target)\r\n        target.score = INT_MIN\r\n        target._indexes.len = 0\r\n        results.push(target); if(results.length >= limit) return results\r\n      }\r\n    }\r\n\r\n    return results\r\n  }\r\n\r\n\r\n  var algorithm = (preparedSearch, prepared, allowSpaces=false) => {\r\n    if(allowSpaces===false && preparedSearch.containsSpace) return algorithmSpaces(preparedSearch, prepared)\r\n\r\n    var searchLower = preparedSearch._lower\r\n    var searchLowerCodes = preparedSearch.lowerCodes\r\n    var searchLowerCode = searchLowerCodes[0]\r\n    var targetLowerCodes = prepared._targetLowerCodes\r\n    var searchLen = searchLowerCodes.length\r\n    var targetLen = targetLowerCodes.length\r\n    var searchI = 0 // where we at\r\n    var targetI = 0 // where you at\r\n    var matchesSimpleLen = 0\r\n\r\n    // very basic fuzzy match; to remove non-matching targets ASAP!\r\n    // walk through target. find sequential matches.\r\n    // if all chars aren't found then exit\r\n    for(;;) {\r\n      var isMatch = searchLowerCode === targetLowerCodes[targetI]\r\n      if(isMatch) {\r\n        matchesSimple[matchesSimpleLen++] = targetI\r\n        ++searchI; if(searchI === searchLen) break\r\n        searchLowerCode = searchLowerCodes[searchI]\r\n      }\r\n      ++targetI; if(targetI >= targetLen) return NULL // Failed to find searchI\r\n    }\r\n\r\n    var searchI = 0\r\n    var successStrict = false\r\n    var matchesStrictLen = 0\r\n\r\n    var nextBeginningIndexes = prepared._nextBeginningIndexes\r\n    if(nextBeginningIndexes === NULL) nextBeginningIndexes = prepared._nextBeginningIndexes = prepareNextBeginningIndexes(prepared.target)\r\n    var firstPossibleI = targetI = matchesSimple[0]===0 ? 0 : nextBeginningIndexes[matchesSimple[0]-1]\r\n\r\n    // Our target string successfully matched all characters in sequence!\r\n    // Let's try a more advanced and strict test to improve the score\r\n    // only count it as a match if it's consecutive or a beginning character!\r\n    var backtrackCount = 0\r\n    if(targetI !== targetLen) for(;;) {\r\n      if(targetI >= targetLen) {\r\n        // We failed to find a good spot for this search char, go back to the previous search char and force it forward\r\n        if(searchI <= 0) break // We failed to push chars forward for a better match\r\n\r\n        ++backtrackCount; if(backtrackCount > 200) break // exponential backtracking is taking too long, just give up and return a bad match\r\n\r\n        --searchI\r\n        var lastMatch = matchesStrict[--matchesStrictLen]\r\n        targetI = nextBeginningIndexes[lastMatch]\r\n\r\n      } else {\r\n        var isMatch = searchLowerCodes[searchI] === targetLowerCodes[targetI]\r\n        if(isMatch) {\r\n          matchesStrict[matchesStrictLen++] = targetI\r\n          ++searchI; if(searchI === searchLen) { successStrict = true; break }\r\n          ++targetI\r\n        } else {\r\n          targetI = nextBeginningIndexes[targetI]\r\n        }\r\n      }\r\n    }\r\n\r\n    // check if it's a substring match\r\n    var substringIndex = prepared._targetLower.indexOf(searchLower, matchesSimple[0]) // perf: this is slow\r\n    var isSubstring = ~substringIndex\r\n    if(isSubstring && !successStrict) { // rewrite the indexes from basic to the substring\r\n      for(var i=0; i<matchesSimpleLen; ++i) matchesSimple[i] = substringIndex+i\r\n    }\r\n    var isSubstringBeginning = false\r\n    if(isSubstring) {\r\n      isSubstringBeginning = prepared._nextBeginningIndexes[substringIndex-1] === substringIndex\r\n    }\r\n\r\n    { // tally up the score & keep track of matches for highlighting later\r\n      if(successStrict) { var matchesBest = matchesStrict; var matchesBestLen = matchesStrictLen }\r\n      else { var matchesBest = matchesSimple; var matchesBestLen = matchesSimpleLen }\r\n\r\n      var score = 0\r\n\r\n      var extraMatchGroupCount = 0\r\n      for(var i = 1; i < searchLen; ++i) {\r\n        if(matchesBest[i] - matchesBest[i-1] !== 1) {score -= matchesBest[i]; ++extraMatchGroupCount}\r\n      }\r\n      var unmatchedDistance = matchesBest[searchLen-1] - matchesBest[0] - (searchLen-1)\r\n\r\n      score -= (12+unmatchedDistance) * extraMatchGroupCount // penality for more groups\r\n\r\n      if(matchesBest[0] !== 0) score -= matchesBest[0]*matchesBest[0]*.2 // penality for not starting near the beginning\r\n\r\n      if(!successStrict) {\r\n        score *= 1000\r\n      } else {\r\n        // successStrict on a target with too many beginning indexes loses points for being a bad target\r\n        var uniqueBeginningIndexes = 1\r\n        for(var i = nextBeginningIndexes[0]; i < targetLen; i=nextBeginningIndexes[i]) ++uniqueBeginningIndexes\r\n\r\n        if(uniqueBeginningIndexes > 24) score *= (uniqueBeginningIndexes-24)*10 // quite arbitrary numbers here ...\r\n      }\r\n\r\n      if(isSubstring)          score /= 1+searchLen*searchLen*1 // bonus for being a full substring\r\n      if(isSubstringBeginning) score /= 1+searchLen*searchLen*1 // bonus for substring starting on a beginningIndex\r\n\r\n      score -= targetLen - searchLen // penality for longer targets\r\n      prepared.score = score\r\n\r\n      for(var i = 0; i < matchesBestLen; ++i) prepared._indexes[i] = matchesBest[i]\r\n      prepared._indexes.len = matchesBestLen\r\n\r\n      return prepared\r\n    }\r\n  }\r\n  var algorithmSpaces = (preparedSearch, target) => {\r\n    var seen_indexes = new Set()\r\n    var score = 0\r\n    var result = NULL\r\n\r\n    var first_seen_index_last_search = 0\r\n    var searches = preparedSearch.spaceSearches\r\n    for(var i=0; i<searches.length; ++i) {\r\n      var search = searches[i]\r\n\r\n      result = algorithm(search, target)\r\n      if(result === NULL) return NULL\r\n\r\n      score += result.score\r\n\r\n      // dock points based on order otherwise \"c man\" returns Manifest.cpp instead of CheatManager.h\r\n      if(result._indexes[0] < first_seen_index_last_search) {\r\n        score -= first_seen_index_last_search - result._indexes[0]\r\n      }\r\n      first_seen_index_last_search = result._indexes[0]\r\n\r\n      for(var j=0; j<result._indexes.len; ++j) seen_indexes.add(result._indexes[j])\r\n    }\r\n\r\n    // allows a search with spaces that's an exact substring to score well\r\n    var allowSpacesResult = algorithm(preparedSearch, target, /*allowSpaces=*/true)\r\n    if(allowSpacesResult !== NULL && allowSpacesResult.score > score) {\r\n      return allowSpacesResult\r\n    }\r\n\r\n    result.score = score\r\n\r\n    var i = 0\r\n    for (let index of seen_indexes) result._indexes[i++] = index\r\n    result._indexes.len = i\r\n\r\n    return result\r\n  }\r\n\r\n\r\n  var prepareLowerInfo = (str) => {\r\n    var strLen = str.length\r\n    var lower = str.toLowerCase()\r\n    var lowerCodes = [] // new Array(strLen)    sparse array is too slow\r\n    var bitflags = 0\r\n    var containsSpace = false // space isn't stored in bitflags because of how searching with a space works\r\n\r\n    for(var i = 0; i < strLen; ++i) {\r\n      var lowerCode = lowerCodes[i] = lower.charCodeAt(i)\r\n\r\n      if(lowerCode === 32) {\r\n        containsSpace = true\r\n        continue // it's important that we don't set any bitflags for space\r\n      }\r\n\r\n      var bit = lowerCode>=97&&lowerCode<=122 ? lowerCode-97 // alphabet\r\n              : lowerCode>=48&&lowerCode<=57  ? 26           // numbers\r\n                                                             // 3 bits available\r\n              : lowerCode<=127                ? 30           // other ascii\r\n              :                                 31           // other utf8\r\n      bitflags |= 1<<bit\r\n    }\r\n\r\n    return {lowerCodes:lowerCodes, bitflags:bitflags, containsSpace:containsSpace, _lower:lower}\r\n  }\r\n  var prepareBeginningIndexes = (target) => {\r\n    var targetLen = target.length\r\n    var beginningIndexes = []; var beginningIndexesLen = 0\r\n    var wasUpper = false\r\n    var wasAlphanum = false\r\n    for(var i = 0; i < targetLen; ++i) {\r\n      var targetCode = target.charCodeAt(i)\r\n      var isUpper = targetCode>=65&&targetCode<=90\r\n      var isAlphanum = isUpper || targetCode>=97&&targetCode<=122 || targetCode>=48&&targetCode<=57\r\n      var isBeginning = isUpper && !wasUpper || !wasAlphanum || !isAlphanum\r\n      wasUpper = isUpper\r\n      wasAlphanum = isAlphanum\r\n      if(isBeginning) beginningIndexes[beginningIndexesLen++] = i\r\n    }\r\n    return beginningIndexes\r\n  }\r\n  var prepareNextBeginningIndexes = (target) => {\r\n    var targetLen = target.length\r\n    var beginningIndexes = prepareBeginningIndexes(target)\r\n    var nextBeginningIndexes = [] // new Array(targetLen)     sparse array is too slow\r\n    var lastIsBeginning = beginningIndexes[0]\r\n    var lastIsBeginningI = 0\r\n    for(var i = 0; i < targetLen; ++i) {\r\n      if(lastIsBeginning > i) {\r\n        nextBeginningIndexes[i] = lastIsBeginning\r\n      } else {\r\n        lastIsBeginning = beginningIndexes[++lastIsBeginningI]\r\n        nextBeginningIndexes[i] = lastIsBeginning===undefined ? targetLen : lastIsBeginning\r\n      }\r\n    }\r\n    return nextBeginningIndexes\r\n  }\r\n\r\n\r\n  var cleanup = () => { preparedCache.clear(); preparedSearchCache.clear(); matchesSimple = []; matchesStrict = [] }\r\n\r\n  var preparedCache       = new Map()\r\n  var preparedSearchCache = new Map()\r\n  var matchesSimple = []; var matchesStrict = []\r\n\r\n\r\n  // for use with keys. just returns the maximum score\r\n  var defaultScoreFn = (a) => {\r\n    var max = INT_MIN\r\n    var len = a.length\r\n    for (var i = 0; i < len; ++i) {\r\n      var result = a[i]; if(result === NULL) continue\r\n      var score = result.score\r\n      if(score > max) max = score\r\n    }\r\n    if(max === INT_MIN) return NULL\r\n    return max\r\n  }\r\n\r\n  // prop = 'key'              2.5ms optimized for this case, seems to be about as fast as direct obj[prop]\r\n  // prop = 'key1.key2'        10ms\r\n  // prop = ['key1', 'key2']   27ms\r\n  var getValue = (obj, prop) => {\r\n    var tmp = obj[prop]; if(tmp !== undefined) return tmp\r\n    var segs = prop\r\n    if(!Array.isArray(prop)) segs = prop.split('.')\r\n    var len = segs.length\r\n    var i = -1\r\n    while (obj && (++i < len)) obj = obj[segs[i]]\r\n    return obj\r\n  }\r\n\r\n  var isObj = (x) => { return typeof x === 'object' } // faster as a function\r\n  // var INT_MAX = 9007199254740991; var INT_MIN = -INT_MAX\r\n  var INT_MAX = Infinity; var INT_MIN = -INT_MAX\r\n  var noResults = []; noResults.total = 0\r\n  var NULL = null\r\n\r\n\r\n  // Hacked version of https://github.com/lemire/FastPriorityQueue.js\r\n  var fastpriorityqueue=r=>{var e=[],o=0,a={},v=r=>{for(var a=0,v=e[a],c=1;c<o;){var s=c+1;a=c,s<o&&e[s].score<e[c].score&&(a=s),e[a-1>>1]=e[a],c=1+(a<<1)}for(var f=a-1>>1;a>0&&v.score<e[f].score;f=(a=f)-1>>1)e[a]=e[f];e[a]=v};return a.add=(r=>{var a=o;e[o++]=r;for(var v=a-1>>1;a>0&&r.score<e[v].score;v=(a=v)-1>>1)e[a]=e[v];e[a]=r}),a.poll=(r=>{if(0!==o){var a=e[0];return e[0]=e[--o],v(),a}}),a.peek=(r=>{if(0!==o)return e[0]}),a.replaceTop=(r=>{e[0]=r,v()}),a}\r\n  var q = fastpriorityqueue() // reuse this\r\n\r\n\r\n  // fuzzysort is written this way for minification. all names are mangeled unless quoted\r\n  return {'single':single, 'go':go, 'highlight':highlight, 'prepare':prepare, 'indexes':indexes, 'cleanup':cleanup}\r\n}) // UMD\r\n\r\n// TODO: (feature) frecency\r\n// TODO: (perf) use different sorting algo depending on the # of results?\r\n// TODO: (perf) preparedCache is a memory leak\r\n// TODO: (like sublime) backslash === forwardslash\r\n// TODO: (perf) prepareSearch seems slow\r\n\n\n//# sourceURL=webpack:///./node_modules/fuzzysort/fuzzysort.js?")},
vendor: 369,181 bytes, line 1
1"./node_modules/matter-js/build/matter.js":function node_modulesMatterJsBuildMatterJs(module,exports,__webpack_require__){eval("/* WEBPACK VAR INJECTION */(function(global) {/*!\n * matter-js 0.19.0 by @liabru\n * http://brm.io/matter-js/\n * License MIT\n * \n * The MIT License (MIT)\n * \n * Copyright (c) Liam Brummitt 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\n * all 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\n * THE SOFTWARE.\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(true)\n\t\tmodule.exports = factory();\n\telse {}\n})(this, function() {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId]) {\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\ti: moduleId,\n/******/ \t\t\tl: false,\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.l = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// define getter function for harmony exports\n/******/ \t__webpack_require__.d = function(exports, name, getter) {\n/******/ \t\tif(!__webpack_require__.o(exports, name)) {\n/******/ \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n/******/ \t\t}\n/******/ \t};\n/******/\n/******/ \t// define __esModule on exports\n/******/ \t__webpack_require__.r = function(exports) {\n/******/ \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n/******/ \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n/******/ \t\t}\n/******/ \t\tObject.defineProperty(exports, '__esModule', { value: true });\n/******/ \t};\n/******/\n/******/ \t// create a fake namespace object\n/******/ \t// mode & 1: value is a module id, require it\n/******/ \t// mode & 2: merge all properties of value into the ns\n/******/ \t// mode & 4: return value when already ns object\n/******/ \t// mode & 8|1: behave like require\n/******/ \t__webpack_require__.t = function(value, mode) {\n/******/ \t\tif(mode & 1) value = __webpack_require__(value);\n/******/ \t\tif(mode & 8) return value;\n/******/ \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n/******/ \t\tvar ns = Object.create(null);\n/******/ \t\t__webpack_require__.r(ns);\n/******/ \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n/******/ \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n/******/ \t\treturn ns;\n/******/ \t};\n/******/\n/******/ \t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t__webpack_require__.n = function(module) {\n/******/ \t\tvar getter = module && module.__esModule ?\n/******/ \t\t\tfunction getDefault() { return module['default']; } :\n/******/ \t\t\tfunction getModuleExports() { return module; };\n/******/ \t\t__webpack_require__.d(getter, 'a', getter);\n/******/ \t\treturn getter;\n/******/ \t};\n/******/\n/******/ \t// Object.prototype.hasOwnProperty.call\n/******/ \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(__webpack_require__.s = 20);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, exports) {\n\n/**\n* The `Matter.Common` module contains utility functions that are common to all modules.\n*\n* @class Common\n*/\n\nvar Common = {};\n\nmodule.exports = Common;\n\n(function() {\n\n    Common._baseDelta = 1000 / 60;\n    Common._nextId = 0;\n    Common._seed = 0;\n    Common._nowStartTime = +(new Date());\n    Common._warnedOnce = {};\n    Common._decomp = null;\n    \n    /**\n     * Extends the object in the first argument using the object in the second argument.\n     * @method extend\n     * @param {} obj\n     * @param {boolean} deep\n     * @return {} obj extended\n     */\n    Common.extend = function(obj, deep) {\n        var argsStart,\n            args,\n            deepClone;\n\n        if (typeof deep === 'boolean') {\n            argsStart = 2;\n            deepClone = deep;\n        } else {\n            argsStart = 1;\n            deepClone = true;\n        }\n\n        for (var i = argsStart; i < arguments.length; i++) {\n            var source = arguments[i];\n\n            if (source) {\n                for (var prop in source) {\n                    if (deepClone && source[prop] && source[prop].constructor === Object) {\n                        if (!obj[prop] || obj[prop].constructor === Object) {\n                            obj[prop] = obj[prop] || {};\n                            Common.extend(obj[prop], deepClone, source[prop]);\n                        } else {\n                            obj[prop] = source[prop];\n                        }\n                    } else {\n                        obj[prop] = source[prop];\n                    }\n                }\n            }\n        }\n        \n        return obj;\n    };\n\n    /**\n     * Creates a new clone of the object, if deep is true references will also be cloned.\n     * @method clone\n     * @param {} obj\n     * @param {bool} deep\n     * @return {} obj cloned\n     */\n    Common.clone = function(obj, deep) {\n        return Common.extend({}, deep, obj);\n    };\n\n    /**\n     * Returns the list of keys for the given object.\n     * @method keys\n     * @param {} obj\n     * @return {string[]} keys\n     */\n    Common.keys = function(obj) {\n        if (Object.keys)\n            return Object.keys(obj);\n\n        // avoid hasOwnProperty for performance\n        var keys = [];\n        for (var key in obj)\n            keys.push(key);\n        return keys;\n    };\n\n    /**\n     * Returns the list of values for the given object.\n     * @method values\n     * @param {} obj\n     * @return {array} Array of the objects property values\n     */\n    Common.values = function(obj) {\n        var values = [];\n        \n        if (Object.keys) {\n            var keys = Object.keys(obj);\n            for (var i = 0; i < keys.length; i++) {\n                values.push(obj[keys[i]]);\n            }\n            return values;\n        }\n        \n        // avoid hasOwnProperty for performance\n        for (var key in obj)\n            values.push(obj[key]);\n        return values;\n    };\n\n    /**\n     * Gets a value from `base` relative to the `path` string.\n     * @method get\n     * @param {} obj The base object\n     * @param {string} path The path relative to `base`, e.g. 'Foo.Bar.baz'\n     * @param {number} [begin] Path slice begin\n     * @param {number} [end] Path slice end\n     * @return {} The object at the given path\n     */\n    Common.get = function(obj, path, begin, end) {\n        path = path.split('.').slice(begin, end);\n\n        for (var i = 0; i < path.length; i += 1) {\n            obj = obj[path[i]];\n        }\n\n        return obj;\n    };\n\n    /**\n     * Sets a value on `base` relative to the given `path` string.\n     * @method set\n     * @param {} obj The base object\n     * @param {string} path The path relative to `base`, e.g. 'Foo.Bar.baz'\n     * @param {} val The value to set\n     * @param {number} [begin] Path slice begin\n     * @param {number} [end] Path slice end\n     * @return {} Pass through `val` for chaining\n     */\n    Common.set = function(obj, path, val, begin, end) {\n        var parts = path.split('.').slice(begin, end);\n        Common.get(obj, path, 0, -1)[parts[parts.length - 1]] = val;\n        return val;\n    };\n\n    /**\n     * Shuffles the given array in-place.\n     * The function uses a seeded random generator.\n     * @method shuffle\n     * @param {array} array\n     * @return {array} array shuffled randomly\n     */\n    Common.shuffle = function(array) {\n        for (var i = array.length - 1; i > 0; i--) {\n            var j = Math.floor(Common.random() * (i + 1));\n            var temp = array[i];\n            array[i] = array[j];\n            array[j] = temp;\n        }\n        return array;\n    };\n\n    /**\n     * Randomly chooses a value from a list with equal probability.\n     * The function uses a seeded random generator.\n     * @method choose\n     * @param {array} choices\n     * @return {object} A random choice object from the array\n     */\n    Common.choose = function(choices) {\n        return choices[Math.floor(Common.random() * choices.length)];\n    };\n\n    /**\n     * Returns true if the object is a HTMLElement, otherwise false.\n     * @method isElement\n     * @param {object} obj\n     * @return {boolean} True if the object is a HTMLElement, otherwise false\n     */\n    Common.isElement = function(obj) {\n        if (typeof HTMLElement !== 'undefined') {\n            return obj instanceof HTMLElement;\n        }\n\n        return !!(obj && obj.nodeType && obj.nodeName);\n    };\n\n    /**\n     * Returns true if the object is an array.\n     * @method isArray\n     * @param {object} obj\n     * @return {boolean} True if the object is an array, otherwise false\n     */\n    Common.isArray = function(obj) {\n        return Object.prototype.toString.call(obj) === '[object Array]';\n    };\n\n    /**\n     * Returns true if the object is a function.\n     * @method isFunction\n     * @param {object} obj\n     * @return {boolean} True if the object is a function, otherwise false\n     */\n    Common.isFunction = function(obj) {\n        return typeof obj === \"function\";\n    };\n\n    /**\n     * Returns true if the object is a plain object.\n     * @method isPlainObject\n     * @param {object} obj\n     * @return {boolean} True if the object is a plain object, otherwise false\n     */\n    Common.isPlainObject = function(obj) {\n        return typeof obj === 'object' && obj.constructor === Object;\n    };\n\n    /**\n     * Returns true if the object is a string.\n     * @method isString\n     * @param {object} obj\n     * @return {boolean} True if the object is a string, otherwise false\n     */\n    Common.isString = function(obj) {\n        return toString.call(obj) === '[object String]';\n    };\n    \n    /**\n     * Returns the given value clamped between a minimum and maximum value.\n     * @method clamp\n     * @param {number} value\n     * @param {number} min\n     * @param {number} max\n     * @return {number} The value clamped between min and max inclusive\n     */\n    Common.clamp = function(value, min, max) {\n        if (value < min)\n            return min;\n        if (value > max)\n            return max;\n        return value;\n    };\n    \n    /**\n     * Returns the sign of the given value.\n     * @method sign\n     * @param {number} value\n     * @return {number} -1 if negative, +1 if 0 or positive\n     */\n    Common.sign = function(value) {\n        return value < 0 ? -1 : 1;\n    };\n    \n    /**\n     * Returns the current timestamp since the time origin (e.g. from page load).\n     * The result is in milliseconds and will use high-resolution timing if available.\n     * @method now\n     * @return {number} the current timestamp in milliseconds\n     */\n    Common.now = function() {\n        if (typeof window !== 'undefined' && window.performance) {\n            if (window.performance.now) {\n                return window.performance.now();\n            } else if (window.performance.webkitNow) {\n                return window.performance.webkitNow();\n            }\n        }\n\n        if (Date.now) {\n            return Date.now();\n        }\n\n        return (new Date()) - Common._nowStartTime;\n    };\n    \n    /**\n     * Returns a random value between a minimum and a maximum value inclusive.\n     * The function uses a seeded random generator.\n     * @method random\n     * @param {number} min\n     * @param {number} max\n     * @return {number} A random number between min and max inclusive\n     */\n    Common.random = function(min, max) {\n        min = (typeof min !== \"undefined\") ? min : 0;\n        max = (typeof max !== \"undefined\") ? max : 1;\n        return min + _seededRandom() * (max - min);\n    };\n\n    var _seededRandom = function() {\n        // https://en.wikipedia.org/wiki/Linear_congruential_generator\n        Common._seed = (Common._seed * 9301 + 49297) % 233280;\n        return Common._seed / 233280;\n    };\n\n    /**\n     * Converts a CSS hex colour string into an integer.\n     * @method colorToNumber\n     * @param {string} colorString\n     * @return {number} An integer representing the CSS hex string\n     */\n    Common.colorToNumber = function(colorString) {\n        colorString = colorString.replace('#','');\n\n        if (colorString.length == 3) {\n            colorString = colorString.charAt(0) + colorString.charAt(0)\n                        + colorString.charAt(1) + colorString.charAt(1)\n                        + colorString.charAt(2) + colorString.charAt(2);\n        }\n\n        return parseInt(colorString, 16);\n    };\n\n    /**\n     * The console logging level to use, where each level includes all levels above and excludes the levels below.\n     * The default level is 'debug' which shows all console messages.  \n     *\n     * Possible level values are:\n     * - 0 = None\n     * - 1 = Debug\n     * - 2 = Info\n     * - 3 = Warn\n     * - 4 = Error\n     * @static\n     * @property logLevel\n     * @type {Number}\n     * @default 1\n     */\n    Common.logLevel = 1;\n\n    /**\n     * Shows a `console.log` message only if the current `Common.logLevel` allows it.\n     * The message will be prefixed with 'matter-js' to make it easily identifiable.\n     * @method log\n     * @param ...objs {} The objects to log.\n     */\n    Common.log = function() {\n        if (console && Common.logLevel > 0 && Common.logLevel <= 3) {\n            console.log.apply(console, ['matter-js:'].concat(Array.prototype.slice.call(arguments)));\n        }\n    };\n\n    /**\n     * Shows a `console.info` message only if the current `Common.logLevel` allows it.\n     * The message will be prefixed with 'matter-js' to make it easily identifiable.\n     * @method info\n     * @param ...objs {} The objects to log.\n     */\n    Common.info = function() {\n        if (console && Common.logLevel > 0 && Common.logLevel <= 2) {\n            console.info.apply(console, ['matter-js:'].concat(Array.prototype.slice.call(arguments)));\n        }\n    };\n\n    /**\n     * Shows a `console.warn` message only if the current `Common.logLevel` allows it.\n     * The message will be prefixed with 'matter-js' to make it easily identifiable.\n     * @method warn\n     * @param ...objs {} The objects to log.\n     */\n    Common.warn = function() {\n        if (console && Common.logLevel > 0 && Common.logLevel <= 3) {\n            console.warn.apply(console, ['matter-js:'].concat(Array.prototype.slice.call(arguments)));\n        }\n    };\n\n    /**\n     * Uses `Common.warn` to log the given message one time only.\n     * @method warnOnce\n     * @param ...objs {} The objects to log.\n     */\n    Common.warnOnce = function() {\n        var message = Array.prototype.slice.call(arguments).join(' ');\n\n        if (!Common._warnedOnce[message]) {\n            Common.warn(message);\n            Common._warnedOnce[message] = true;\n        }\n    };\n\n    /**\n     * Shows a deprecated console warning when the function on the given object is called.\n     * The target function will be replaced with a new function that first shows the warning\n     * and then calls the original function.\n     * @method deprecated\n     * @param {object} obj The object or module\n     * @param {string} name The property name of the function on obj\n     * @param {string} warning The one-time message to show if the function is called\n     */\n    Common.deprecated = function(obj, prop, warning) {\n        obj[prop] = Common.chain(function() {\n            Common.warnOnce('🔅 deprecated 🔅', warning);\n        }, obj[prop]);\n    };\n\n    /**\n     * Returns the next unique sequential ID.\n     * @method nextId\n     * @return {Number} Unique sequential ID\n     */\n    Common.nextId = function() {\n        return Common._nextId++;\n    };\n\n    /**\n     * A cross browser compatible indexOf implementation.\n     * @method indexOf\n     * @param {array} haystack\n     * @param {object} needle\n     * @return {number} The position of needle in haystack, otherwise -1.\n     */\n    Common.indexOf = function(haystack, needle) {\n        if (haystack.indexOf)\n            return haystack.indexOf(needle);\n\n        for (var i = 0; i < haystack.length; i++) {\n            if (haystack[i] === needle)\n                return i;\n        }\n\n        return -1;\n    };\n\n    /**\n     * A cross browser compatible array map implementation.\n     * @method map\n     * @param {array} list\n     * @param {function} func\n     * @return {array} Values from list transformed by func.\n     */\n    Common.map = function(list, func) {\n        if (list.map) {\n            return list.map(func);\n        }\n\n        var mapped = [];\n\n        for (var i = 0; i < list.length; i += 1) {\n            mapped.push(func(list[i]));\n        }\n\n        return mapped;\n    };\n\n    /**\n     * Takes a directed graph and returns the partially ordered set of vertices in topological order.\n     * Circular dependencies are allowed.\n     * @method topologicalSort\n     * @param {object} graph\n     * @return {array} Partially ordered set of vertices in topological order.\n     */\n    Common.topologicalSort = function(graph) {\n        // https://github.com/mgechev/javascript-algorithms\n        // Copyright (c) Minko Gechev (MIT license)\n        // Modifications: tidy formatting and naming\n        var result = [],\n            visited = [],\n            temp = [];\n\n        for (var node in graph) {\n            if (!visited[node] && !temp[node]) {\n                Common._topologicalSort(node, visited, temp, graph, result);\n            }\n        }\n\n        return result;\n    };\n\n    Common._topologicalSort = function(node, visited, temp, graph, result) {\n        var neighbors = graph[node] || [];\n        temp[node] = true;\n\n        for (var i = 0; i < neighbors.length; i += 1) {\n            var neighbor = neighbors[i];\n\n            if (temp[neighbor]) {\n                // skip circular dependencies\n                continue;\n            }\n\n            if (!visited[neighbor]) {\n                Common._topologicalSort(neighbor, visited, temp, graph, result);\n            }\n        }\n\n        temp[node] = false;\n        visited[node] = true;\n\n        result.push(node);\n    };\n\n    /**\n     * Takes _n_ functions as arguments and returns a new function that calls them in order.\n     * The arguments applied when calling the new function will also be applied to every function passed.\n     * The value of `this` refers to the last value returned in the chain that was not `undefined`.\n     * Therefore if a passed function does not return a value, the previously returned value is maintained.\n     * After all passed functions have been called the new function returns the last returned value (if any).\n     * If any of the passed functions are a chain, then the chain will be flattened.\n     * @method chain\n     * @param ...funcs {function} The functions to chain.\n     * @return {function} A new function that calls the passed functions in order.\n     */\n    Common.chain = function() {\n        var funcs = [];\n\n        for (var i = 0; i < arguments.length; i += 1) {\n            var func = arguments[i];\n\n            if (func._chained) {\n                // flatten already chained functions\n                funcs.push.apply(funcs, func._chained);\n            } else {\n                funcs.push(func);\n            }\n        }\n\n        var chain = function() {\n            // https://github.com/GoogleChrome/devtools-docs/issues/53#issuecomment-51941358\n            var lastResult,\n                args = new Array(arguments.length);\n\n            for (var i = 0, l = arguments.length; i < l; i++) {\n                args[i] = arguments[i];\n            }\n\n            for (i = 0; i < funcs.length; i += 1) {\n                var result = funcs[i].apply(lastResult, args);\n\n                if (typeof result !== 'undefined') {\n                    lastResult = result;\n                }\n            }\n\n            return lastResult;\n        };\n\n        chain._chained = funcs;\n\n        return chain;\n    };\n\n    /**\n     * Chains a function to excute before the original function on the given `path` relative to `base`.\n     * See also docs for `Common.chain`.\n     * @method chainPathBefore\n     * @param {} base The base object\n     * @param {string} path The path relative to `base`\n     * @param {function} func The function to chain before the original\n     * @return {function} The chained function that replaced the original\n     */\n    Common.chainPathBefore = function(base, path, func) {\n        return Common.set(base, path, Common.chain(\n            func,\n            Common.get(base, path)\n        ));\n    };\n\n    /**\n     * Chains a function to excute after the original function on the given `path` relative to `base`.\n     * See also docs for `Common.chain`.\n     * @method chainPathAfter\n     * @param {} base The base object\n     * @param {string} path The path relative to `base`\n     * @param {function} func The function to chain after the original\n     * @return {function} The chained function that replaced the original\n     */\n    Common.chainPathAfter = function(base, path, func) {\n        return Common.set(base, path, Common.chain(\n            Common.get(base, path),\n            func\n        ));\n    };\n\n    /**\n     * Provide the [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module to enable\n     * concave vertex decomposition support when using `Bodies.fromVertices` e.g. `Common.setDecomp(require('poly-decomp'))`.\n     * @method setDecomp\n     * @param {} decomp The [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module.\n     */\n    Common.setDecomp = function(decomp) {\n        Common._decomp = decomp;\n    };\n\n    /**\n     * Returns the [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module provided through `Common.setDecomp`,\n     * otherwise returns the global `decomp` if set.\n     * @method getDecomp\n     * @return {} The [poly-decomp](https://github.com/schteppe/poly-decomp.js) library module if provided.\n     */\n    Common.getDecomp = function() {\n        // get user provided decomp if set\n        var decomp = Common._decomp;\n\n        try {\n            // otherwise from window global\n            if (!decomp && typeof window !== 'undefined') {\n                decomp = window.decomp;\n            }\n    \n            // otherwise from node global\n            if (!decomp && typeof global !== 'undefined') {\n                decomp = global.decomp;\n            }\n        } catch (e) {\n            // decomp not available\n            decomp = null;\n        }\n\n        return decomp;\n    };\n})();\n\n\n/***/ }),\n/* 1 */\n/***/ (function(module, exports) {\n\n/**\n* The `Matter.Bounds` module contains methods for creating and manipulating axis-aligned bounding boxes (AABB).\n*\n* @class Bounds\n*/\n\nvar Bounds = {};\n\nmodule.exports = Bounds;\n\n(function() {\n\n    /**\n     * Creates a new axis-aligned bounding box (AABB) for the given vertices.\n     * @method create\n     * @param {vertices} vertices\n     * @return {bounds} A new bounds object\n     */\n    Bounds.create = function(vertices) {\n        var bounds = { \n            min: { x: 0, y: 0 }, \n            max: { x: 0, y: 0 }\n        };\n\n        if (vertices)\n            Bounds.update(bounds, vertices);\n        \n        return bounds;\n    };\n\n    /**\n     * Updates bounds using the given vertices and extends the bounds given a velocity.\n     * @method update\n     * @param {bounds} bounds\n     * @param {vertices} vertices\n     * @param {vector} velocity\n     */\n    Bounds.update = function(bounds, vertices, velocity) {\n        bounds.min.x = Infinity;\n        bounds.max.x = -Infinity;\n        bounds.min.y = Infinity;\n        bounds.max.y = -Infinity;\n\n        for (var i = 0; i < vertices.length; i++) {\n            var vertex = vertices[i];\n            if (vertex.x > bounds.max.x) bounds.max.x = vertex.x;\n            if (vertex.x < bounds.min.x) bounds.min.x = vertex.x;\n            if (vertex.y > bounds.max.y) bounds.max.y = vertex.y;\n            if (vertex.y < bounds.min.y) bounds.min.y = vertex.y;\n        }\n        \n        if (velocity) {\n            if (velocity.x > 0) {\n                bounds.max.x += velocity.x;\n            } else {\n                bounds.min.x += velocity.x;\n            }\n            \n            if (velocity.y > 0) {\n                bounds.max.y += velocity.y;\n            } else {\n                bounds.min.y += velocity.y;\n            }\n        }\n    };\n\n    /**\n     * Returns true if the bounds contains the given point.\n     * @method contains\n     * @param {bounds} bounds\n     * @param {vector} point\n     * @return {boolean} True if the bounds contain the point, otherwise false\n     */\n    Bounds.contains = function(bounds, point) {\n        return point.x >= bounds.min.x && point.x <= bounds.max.x \n               && point.y >= bounds.min.y && point.y <= bounds.max.y;\n    };\n\n    /**\n     * Returns true if the two bounds intersect.\n     * @method overlaps\n     * @param {bounds} boundsA\n     * @param {bounds} boundsB\n     * @return {boolean} True if the bounds overlap, otherwise false\n     */\n    Bounds.overlaps = function(boundsA, boundsB) {\n        return (boundsA.min.x <= boundsB.max.x && boundsA.max.x >= boundsB.min.x\n                && boundsA.max.y >= boundsB.min.y && boundsA.min.y <= boundsB.max.y);\n    };\n\n    /**\n     * Translates the bounds by the given vector.\n     * @method translate\n     * @param {bounds} bounds\n     * @param {vector} vector\n     */\n    Bounds.translate = function(bounds, vector) {\n        bounds.min.x += vector.x;\n        bounds.max.x += vector.x;\n        bounds.min.y += vector.y;\n        bounds.max.y += vector.y;\n    };\n\n    /**\n     * Shifts the bounds to the given position.\n     * @method shift\n     * @param {bounds} bounds\n     * @param {vector} position\n     */\n    Bounds.shift = function(bounds, position) {\n        var deltaX = bounds.max.x - bounds.min.x,\n            deltaY = bounds.max.y - bounds.min.y;\n            \n        bounds.min.x = position.x;\n        bounds.max.x = position.x + deltaX;\n        bounds.min.y = position.y;\n        bounds.max.y = position.y + deltaY;\n    };\n    \n})();\n\n\n/***/ }),\n/* 2 */\n/***/ (function(module, exports) {\n\n/**\n* The `Matter.Vector` module contains methods for creating and manipulating vectors.\n* Vectors are the basis of all the geometry related operations in the engine.\n* A `Matter.Vector` object is of the form `{ x: 0, y: 0 }`.\n*\n* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).\n*\n* @class Vector\n*/\n\n// TODO: consider params for reusing vector objects\n\nvar Vector = {};\n\nmodule.exports = Vector;\n\n(function() {\n\n    /**\n     * Creates a new vector.\n     * @method create\n     * @param {number} x\n     * @param {number} y\n     * @return {vector} A new vector\n     */\n    Vector.create = function(x, y) {\n        return { x: x || 0, y: y || 0 };\n    };\n\n    /**\n     * Returns a new vector with `x` and `y` copied from the given `vector`.\n     * @method clone\n     * @param {vector} vector\n     * @return {vector} A new cloned vector\n     */\n    Vector.clone = function(vector) {\n        return { x: vector.x, y: vector.y };\n    };\n\n    /**\n     * Returns the magnitude (length) of a vector.\n     * @method magnitude\n     * @param {vector} vector\n     * @return {number} The magnitude of the vector\n     */\n    Vector.magnitude = function(vector) {\n        return Math.sqrt((vector.x * vector.x) + (vector.y * vector.y));\n    };\n\n    /**\n     * Returns the magnitude (length) of a vector (therefore saving a `sqrt` operation).\n     * @method magnitudeSquared\n     * @param {vector} vector\n     * @return {number} The squared magnitude of the vector\n     */\n    Vector.magnitudeSquared = function(vector) {\n        return (vector.x * vector.x) + (vector.y * vector.y);\n    };\n\n    /**\n     * Rotates the vector about (0, 0) by specified angle.\n     * @method rotate\n     * @param {vector} vector\n     * @param {number} angle\n     * @param {vector} [output]\n     * @return {vector} The vector rotated about (0, 0)\n     */\n    Vector.rotate = function(vector, angle, output) {\n        var cos = Math.cos(angle), sin = Math.sin(angle);\n        if (!output) output = {};\n        var x = vector.x * cos - vector.y * sin;\n        output.y = vector.x * sin + vector.y * cos;\n        output.x = x;\n        return output;\n    };\n\n    /**\n     * Rotates the vector about a specified point by specified angle.\n     * @method rotateAbout\n     * @param {vector} vector\n     * @param {number} angle\n     * @param {vector} point\n     * @param {vector} [output]\n     * @return {vector} A new vector rotated about the point\n     */\n    Vector.rotateAbout = function(vector, angle, point, output) {\n        var cos = Math.cos(angle), sin = Math.sin(angle);\n        if (!output) output = {};\n        var x = point.x + ((vector.x - point.x) * cos - (vector.y - point.y) * sin);\n        output.y = point.y + ((vector.x - point.x) * sin + (vector.y - point.y) * cos);\n        output.x = x;\n        return output;\n    };\n\n    /**\n     * Normalises a vector (such that its magnitude is `1`).\n     * @method normalise\n     * @param {vector} vector\n     * @return {vector} A new vector normalised\n     */\n    Vector.normalise = function(vector) {\n        var magnitude = Vector.magnitude(vector);\n        if (magnitude === 0)\n            return { x: 0, y: 0 };\n        return { x: vector.x / magnitude, y: vector.y / magnitude };\n    };\n\n    /**\n     * Returns the dot-product of two vectors.\n     * @method dot\n     * @param {vector} vectorA\n     * @param {vector} vectorB\n     * @return {number} The dot product of the two vectors\n     */\n    Vector.dot = function(vectorA, vectorB) {\n        return (vectorA.x * vectorB.x) + (vectorA.y * vectorB.y);\n    };\n\n    /**\n     * Returns the cross-product of two vectors.\n     * @method cross\n     * @param {vector} vectorA\n     * @param {vector} vectorB\n     * @return {number} The cross product of the two vectors\n     */\n    Vector.cross = function(vectorA, vectorB) {\n        return (vectorA.x * vectorB.y) - (vectorA.y * vectorB.x);\n    };\n\n    /**\n     * Returns the cross-product of three vectors.\n     * @method cross3\n     * @param {vector} vectorA\n     * @param {vector} vectorB\n     * @param {vector} vectorC\n     * @return {number} The cross product of the three vectors\n     */\n    Vector.cross3 = function(vectorA, vectorB, vectorC) {\n        return (vectorB.x - vectorA.x) * (vectorC.y - vectorA.y) - (vectorB.y - vectorA.y) * (vectorC.x - vectorA.x);\n    };\n\n    /**\n     * Adds the two vectors.\n     * @method add\n     * @param {vector} vectorA\n     * @param {vector} vectorB\n     * @param {vector} [output]\n     * @return {vector} A new vector of vectorA and vectorB added\n     */\n    Vector.add = function(vectorA, vectorB, output) {\n        if (!output) output = {};\n        output.x = vectorA.x + vectorB.x;\n        output.y = vectorA.y + vectorB.y;\n        return output;\n    };\n\n    /**\n     * Subtracts the two vectors.\n     * @method sub\n     * @param {vector} vectorA\n     * @param {vector} vectorB\n     * @param {vector} [output]\n     * @return {vector} A new vector of vectorA and vectorB subtracted\n     */\n    Vector.sub = function(vectorA, vectorB, output) {\n        if (!output) output = {};\n        output.x = vectorA.x - vectorB.x;\n        output.y = vectorA.y - vectorB.y;\n        return output;\n    };\n\n    /**\n     * Multiplies a vector and a scalar.\n     * @method mult\n     * @param {vector} vector\n     * @param {number} scalar\n     * @return {vector} A new vector multiplied by scalar\n     */\n    Vector.mult = function(vector, scalar) {\n        return { x: vector.x * scalar, y: vector.y * scalar };\n    };\n\n    /**\n     * Divides a vector and a scalar.\n     * @method div\n     * @param {vector} vector\n     * @param {number} scalar\n     * @return {vector} A new vector divided by scalar\n     */\n    Vector.div = function(vector, scalar) {\n        return { x: vector.x / scalar, y: vector.y / scalar };\n    };\n\n    /**\n     * Returns the perpendicular vector. Set `negate` to true for the perpendicular in the opposite direction.\n     * @method perp\n     * @param {vector} vector\n     * @param {bool} [negate=false]\n     * @return {vector} The perpendicular vector\n     */\n    Vector.perp = function(vector, negate) {\n        negate = negate === true ? -1 : 1;\n        return { x: negate * -vector.y, y: negate * vector.x };\n    };\n\n    /**\n     * Negates both components of a vector such that it points in the opposite direction.\n     * @method neg\n     * @param {vector} vector\n     * @return {vector} The negated vector\n     */\n    Vector.neg = function(vector) {\n        return { x: -vector.x, y: -vector.y };\n    };\n\n    /**\n     * Returns the angle between the vector `vectorB - vectorA` and the x-axis in radians.\n     * @method angle\n     * @param {vector} vectorA\n     * @param {vector} vectorB\n     * @return {number} The angle in radians\n     */\n    Vector.angle = function(vectorA, vectorB) {\n        return Math.atan2(vectorB.y - vectorA.y, vectorB.x - vectorA.x);\n    };\n\n    /**\n     * Temporary vector pool (not thread-safe).\n     * @property _temp\n     * @type {vector[]}\n     * @private\n     */\n    Vector._temp = [\n        Vector.create(), Vector.create(), \n        Vector.create(), Vector.create(), \n        Vector.create(), Vector.create()\n    ];\n\n})();\n\n/***/ }),\n/* 3 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Vertices` module contains methods for creating and manipulating sets of vertices.\n* A set of vertices is an array of `Matter.Vector` with additional indexing properties inserted by `Vertices.create`.\n* A `Matter.Body` maintains a set of vertices to represent the shape of the object (its convex hull).\n*\n* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).\n*\n* @class Vertices\n*/\n\nvar Vertices = {};\n\nmodule.exports = Vertices;\n\nvar Vector = __webpack_require__(2);\nvar Common = __webpack_require__(0);\n\n(function() {\n\n    /**\n     * Creates a new set of `Matter.Body` compatible vertices.\n     * The `points` argument accepts an array of `Matter.Vector` points orientated around the origin `(0, 0)`, for example:\n     *\n     *     [{ x: 0, y: 0 }, { x: 25, y: 50 }, { x: 50, y: 0 }]\n     *\n     * The `Vertices.create` method returns a new array of vertices, which are similar to Matter.Vector objects,\n     * but with some additional references required for efficient collision detection routines.\n     *\n     * Vertices must be specified in clockwise order.\n     *\n     * Note that the `body` argument is not optional, a `Matter.Body` reference must be provided.\n     *\n     * @method create\n     * @param {vector[]} points\n     * @param {body} body\n     */\n    Vertices.create = function(points, body) {\n        var vertices = [];\n\n        for (var i = 0; i < points.length; i++) {\n            var point = points[i],\n                vertex = {\n                    x: point.x,\n                    y: point.y,\n                    index: i,\n                    body: body,\n                    isInternal: false\n                };\n\n            vertices.push(vertex);\n        }\n\n        return vertices;\n    };\n\n    /**\n     * Parses a string containing ordered x y pairs separated by spaces (and optionally commas), \n     * into a `Matter.Vertices` object for the given `Matter.Body`.\n     * For parsing SVG paths, see `Svg.pathToVertices`.\n     * @method fromPath\n     * @param {string} path\n     * @param {body} body\n     * @return {vertices} vertices\n     */\n    Vertices.fromPath = function(path, body) {\n        var pathPattern = /L?\\s*([-\\d.e]+)[\\s,]*([-\\d.e]+)*/ig,\n            points = [];\n\n        path.replace(pathPattern, function(match, x, y) {\n            points.push({ x: parseFloat(x), y: parseFloat(y) });\n        });\n\n        return Vertices.create(points, body);\n    };\n\n    /**\n     * Returns the centre (centroid) of the set of vertices.\n     * @method centre\n     * @param {vertices} vertices\n     * @return {vector} The centre point\n     */\n    Vertices.centre = function(vertices) {\n        var area = Vertices.area(vertices, true),\n            centre = { x: 0, y: 0 },\n            cross,\n            temp,\n            j;\n\n        for (var i = 0; i < vertices.length; i++) {\n            j = (i + 1) % vertices.length;\n            cross = Vector.cross(vertices[i], vertices[j]);\n            temp = Vector.mult(Vector.add(vertices[i], vertices[j]), cross);\n            centre = Vector.add(centre, temp);\n        }\n\n        return Vector.div(centre, 6 * area);\n    };\n\n    /**\n     * Returns the average (mean) of the set of vertices.\n     * @method mean\n     * @param {vertices} vertices\n     * @return {vector} The average point\n     */\n    Vertices.mean = function(vertices) {\n        var average = { x: 0, y: 0 };\n\n        for (var i = 0; i < vertices.length; i++) {\n            average.x += vertices[i].x;\n            average.y += vertices[i].y;\n        }\n\n        return Vector.div(average, vertices.length);\n    };\n\n    /**\n     * Returns the area of the set of vertices.\n     * @method area\n     * @param {vertices} vertices\n     * @param {bool} signed\n     * @return {number} The area\n     */\n    Vertices.area = function(vertices, signed) {\n        var area = 0,\n            j = vertices.length - 1;\n\n        for (var i = 0; i < vertices.length; i++) {\n            area += (vertices[j].x - vertices[i].x) * (vertices[j].y + vertices[i].y);\n            j = i;\n        }\n\n        if (signed)\n            return area / 2;\n\n        return Math.abs(area) / 2;\n    };\n\n    /**\n     * Returns the moment of inertia (second moment of area) of the set of vertices given the total mass.\n     * @method inertia\n     * @param {vertices} vertices\n     * @param {number} mass\n     * @return {number} The polygon's moment of inertia\n     */\n    Vertices.inertia = function(vertices, mass) {\n        var numerator = 0,\n            denominator = 0,\n            v = vertices,\n            cross,\n            j;\n\n        // find the polygon's moment of inertia, using second moment of area\n        // from equations at http://www.physicsforums.com/showthread.php?t=25293\n        for (var n = 0; n < v.length; n++) {\n            j = (n + 1) % v.length;\n            cross = Math.abs(Vector.cross(v[j], v[n]));\n            numerator += cross * (Vector.dot(v[j], v[j]) + Vector.dot(v[j], v[n]) + Vector.dot(v[n], v[n]));\n            denominator += cross;\n        }\n\n        return (mass / 6) * (numerator / denominator);\n    };\n\n    /**\n     * Translates the set of vertices in-place.\n     * @method translate\n     * @param {vertices} vertices\n     * @param {vector} vector\n     * @param {number} scalar\n     */\n    Vertices.translate = function(vertices, vector, scalar) {\n        scalar = typeof scalar !== 'undefined' ? scalar : 1;\n\n        var verticesLength = vertices.length,\n            translateX = vector.x * scalar,\n            translateY = vector.y * scalar,\n            i;\n        \n        for (i = 0; i < verticesLength; i++) {\n            vertices[i].x += translateX;\n            vertices[i].y += translateY;\n        }\n\n        return vertices;\n    };\n\n    /**\n     * Rotates the set of vertices in-place.\n     * @method rotate\n     * @param {vertices} vertices\n     * @param {number} angle\n     * @param {vector} point\n     */\n    Vertices.rotate = function(vertices, angle, point) {\n        if (angle === 0)\n            return;\n\n        var cos = Math.cos(angle),\n            sin = Math.sin(angle),\n            pointX = point.x,\n            pointY = point.y,\n            verticesLength = vertices.length,\n            vertex,\n            dx,\n            dy,\n            i;\n\n        for (i = 0; i < verticesLength; i++) {\n            vertex = vertices[i];\n            dx = vertex.x - pointX;\n            dy = vertex.y - pointY;\n            vertex.x = pointX + (dx * cos - dy * sin);\n            vertex.y = pointY + (dx * sin + dy * cos);\n        }\n\n        return vertices;\n    };\n\n    /**\n     * Returns `true` if the `point` is inside the set of `vertices`.\n     * @method contains\n     * @param {vertices} vertices\n     * @param {vector} point\n     * @return {boolean} True if the vertices contains point, otherwise false\n     */\n    Vertices.contains = function(vertices, point) {\n        var pointX = point.x,\n            pointY = point.y,\n            verticesLength = vertices.length,\n            vertex = vertices[verticesLength - 1],\n            nextVertex;\n\n        for (var i = 0; i < verticesLength; i++) {\n            nextVertex = vertices[i];\n\n            if ((pointX - vertex.x) * (nextVertex.y - vertex.y) \n                + (pointY - vertex.y) * (vertex.x - nextVertex.x) > 0) {\n                return false;\n            }\n\n            vertex = nextVertex;\n        }\n\n        return true;\n    };\n\n    /**\n     * Scales the vertices from a point (default is centre) in-place.\n     * @method scale\n     * @param {vertices} vertices\n     * @param {number} scaleX\n     * @param {number} scaleY\n     * @param {vector} point\n     */\n    Vertices.scale = function(vertices, scaleX, scaleY, point) {\n        if (scaleX === 1 && scaleY === 1)\n            return vertices;\n\n        point = point || Vertices.centre(vertices);\n\n        var vertex,\n            delta;\n\n        for (var i = 0; i < vertices.length; i++) {\n            vertex = vertices[i];\n            delta = Vector.sub(vertex, point);\n            vertices[i].x = point.x + delta.x * scaleX;\n            vertices[i].y = point.y + delta.y * scaleY;\n        }\n\n        return vertices;\n    };\n\n    /**\n     * Chamfers a set of vertices by giving them rounded corners, returns a new set of vertices.\n     * The radius parameter is a single number or an array to specify the radius for each vertex.\n     * @method chamfer\n     * @param {vertices} vertices\n     * @param {number[]} radius\n     * @param {number} quality\n     * @param {number} qualityMin\n     * @param {number} qualityMax\n     */\n    Vertices.chamfer = function(vertices, radius, quality, qualityMin, qualityMax) {\n        if (typeof radius === 'number') {\n            radius = [radius];\n        } else {\n            radius = radius || [8];\n        }\n\n        // quality defaults to -1, which is auto\n        quality = (typeof quality !== 'undefined') ? quality : -1;\n        qualityMin = qualityMin || 2;\n        qualityMax = qualityMax || 14;\n\n        var newVertices = [];\n\n        for (var i = 0; i < vertices.length; i++) {\n            var prevVertex = vertices[i - 1 >= 0 ? i - 1 : vertices.length - 1],\n                vertex = vertices[i],\n                nextVertex = vertices[(i + 1) % vertices.length],\n                currentRadius = radius[i < radius.length ? i : radius.length - 1];\n\n            if (currentRadius === 0) {\n                newVertices.push(vertex);\n                continue;\n            }\n\n            var prevNormal = Vector.normalise({ \n                x: vertex.y - prevVertex.y, \n                y: prevVertex.x - vertex.x\n            });\n\n            var nextNormal = Vector.normalise({ \n                x: nextVertex.y - vertex.y, \n                y: vertex.x - nextVertex.x\n            });\n\n            var diagonalRadius = Math.sqrt(2 * Math.pow(currentRadius, 2)),\n                radiusVector = Vector.mult(Common.clone(prevNormal), currentRadius),\n                midNormal = Vector.normalise(Vector.mult(Vector.add(prevNormal, nextNormal), 0.5)),\n                scaledVertex = Vector.sub(vertex, Vector.mult(midNormal, diagonalRadius));\n\n            var precision = quality;\n\n            if (quality === -1) {\n                // automatically decide precision\n                precision = Math.pow(currentRadius, 0.32) * 1.75;\n            }\n\n            precision = Common.clamp(precision, qualityMin, qualityMax);\n\n            // use an even value for precision, more likely to reduce axes by using symmetry\n            if (precision % 2 === 1)\n                precision += 1;\n\n            var alpha = Math.acos(Vector.dot(prevNormal, nextNormal)),\n                theta = alpha / precision;\n\n            for (var j = 0; j < precision; j++) {\n                newVertices.push(Vector.add(Vector.rotate(radiusVector, theta * j), scaledVertex));\n            }\n        }\n\n        return newVertices;\n    };\n\n    /**\n     * Sorts the input vertices into clockwise order in place.\n     * @method clockwiseSort\n     * @param {vertices} vertices\n     * @return {vertices} vertices\n     */\n    Vertices.clockwiseSort = function(vertices) {\n        var centre = Vertices.mean(vertices);\n\n        vertices.sort(function(vertexA, vertexB) {\n            return Vector.angle(centre, vertexA) - Vector.angle(centre, vertexB);\n        });\n\n        return vertices;\n    };\n\n    /**\n     * Returns true if the vertices form a convex shape (vertices must be in clockwise order).\n     * @method isConvex\n     * @param {vertices} vertices\n     * @return {bool} `true` if the `vertices` are convex, `false` if not (or `null` if not computable).\n     */\n    Vertices.isConvex = function(vertices) {\n        // http://paulbourke.net/geometry/polygonmesh/\n        // Copyright (c) Paul Bourke (use permitted)\n\n        var flag = 0,\n            n = vertices.length,\n            i,\n            j,\n            k,\n            z;\n\n        if (n < 3)\n            return null;\n\n        for (i = 0; i < n; i++) {\n            j = (i + 1) % n;\n            k = (i + 2) % n;\n            z = (vertices[j].x - vertices[i].x) * (vertices[k].y - vertices[j].y);\n            z -= (vertices[j].y - vertices[i].y) * (vertices[k].x - vertices[j].x);\n\n            if (z < 0) {\n                flag |= 1;\n            } else if (z > 0) {\n                flag |= 2;\n            }\n\n            if (flag === 3) {\n                return false;\n            }\n        }\n\n        if (flag !== 0){\n            return true;\n        } else {\n            return null;\n        }\n    };\n\n    /**\n     * Returns the convex hull of the input vertices as a new array of points.\n     * @method hull\n     * @param {vertices} vertices\n     * @return [vertex] vertices\n     */\n    Vertices.hull = function(vertices) {\n        // http://geomalgorithms.com/a10-_hull-1.html\n\n        var upper = [],\n            lower = [], \n            vertex,\n            i;\n\n        // sort vertices on x-axis (y-axis for ties)\n        vertices = vertices.slice(0);\n        vertices.sort(function(vertexA, vertexB) {\n            var dx = vertexA.x - vertexB.x;\n            return dx !== 0 ? dx : vertexA.y - vertexB.y;\n        });\n\n        // build lower hull\n        for (i = 0; i < vertices.length; i += 1) {\n            vertex = vertices[i];\n\n            while (lower.length >= 2 \n                   && Vector.cross3(lower[lower.length - 2], lower[lower.length - 1], vertex) <= 0) {\n                lower.pop();\n            }\n\n            lower.push(vertex);\n        }\n\n        // build upper hull\n        for (i = vertices.length - 1; i >= 0; i -= 1) {\n            vertex = vertices[i];\n\n            while (upper.length >= 2 \n                   && Vector.cross3(upper[upper.length - 2], upper[upper.length - 1], vertex) <= 0) {\n                upper.pop();\n            }\n\n            upper.push(vertex);\n        }\n\n        // concatenation of the lower and upper hulls gives the convex hull\n        // omit last points because they are repeated at the beginning of the other list\n        upper.pop();\n        lower.pop();\n\n        return upper.concat(lower);\n    };\n\n})();\n\n\n/***/ }),\n/* 4 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Body` module contains methods for creating and manipulating rigid bodies.\n* For creating bodies with common configurations such as rectangles, circles and other polygons see the module `Matter.Bodies`.\n*\n* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).\n\n* @class Body\n*/\n\nvar Body = {};\n\nmodule.exports = Body;\n\nvar Vertices = __webpack_require__(3);\nvar Vector = __webpack_require__(2);\nvar Sleeping = __webpack_require__(7);\nvar Common = __webpack_require__(0);\nvar Bounds = __webpack_require__(1);\nvar Axes = __webpack_require__(11);\n\n(function() {\n\n    Body._timeCorrection = true;\n    Body._inertiaScale = 4;\n    Body._nextCollidingGroupId = 1;\n    Body._nextNonCollidingGroupId = -1;\n    Body._nextCategory = 0x0001;\n    Body._baseDelta = 1000 / 60;\n\n    /**\n     * Creates a new rigid body model. The options parameter is an object that specifies any properties you wish to override the defaults.\n     * All properties have default values, and many are pre-calculated automatically based on other properties.\n     * Vertices must be specified in clockwise order.\n     * See the properties section below for detailed information on what you can pass via the `options` object.\n     * @method create\n     * @param {} options\n     * @return {body} body\n     */\n    Body.create = function(options) {\n        var defaults = {\n            id: Common.nextId(),\n            type: 'body',\n            label: 'Body',\n            parts: [],\n            plugin: {},\n            angle: 0,\n            vertices: Vertices.fromPath('L 0 0 L 40 0 L 40 40 L 0 40'),\n            position: { x: 0, y: 0 },\n            force: { x: 0, y: 0 },\n            torque: 0,\n            positionImpulse: { x: 0, y: 0 },\n            constraintImpulse: { x: 0, y: 0, angle: 0 },\n            totalContacts: 0,\n            speed: 0,\n            angularSpeed: 0,\n            velocity: { x: 0, y: 0 },\n            angularVelocity: 0,\n            isSensor: false,\n            isStatic: false,\n            isSleeping: false,\n            motion: 0,\n            sleepThreshold: 60,\n            density: 0.001,\n            restitution: 0,\n            friction: 0.1,\n            frictionStatic: 0.5,\n            frictionAir: 0.01,\n            collisionFilter: {\n                category: 0x0001,\n                mask: 0xFFFFFFFF,\n                group: 0\n            },\n            slop: 0.05,\n            timeScale: 1,\n            render: {\n                visible: true,\n                opacity: 1,\n                strokeStyle: null,\n                fillStyle: null,\n                lineWidth: null,\n                sprite: {\n                    xScale: 1,\n                    yScale: 1,\n                    xOffset: 0,\n                    yOffset: 0\n                }\n            },\n            events: null,\n            bounds: null,\n            chamfer: null,\n            circleRadius: 0,\n            positionPrev: null,\n            anglePrev: 0,\n            parent: null,\n            axes: null,\n            area: 0,\n            mass: 0,\n            inertia: 0,\n            deltaTime: 1000 / 60,\n            _original: null\n        };\n\n        var body = Common.extend(defaults, options);\n\n        _initProperties(body, options);\n\n        return body;\n    };\n\n    /**\n     * Returns the next unique group index for which bodies will collide.\n     * If `isNonColliding` is `true`, returns the next unique group index for which bodies will _not_ collide.\n     * See `body.collisionFilter` for more information.\n     * @method nextGroup\n     * @param {bool} [isNonColliding=false]\n     * @return {Number} Unique group index\n     */\n    Body.nextGroup = function(isNonColliding) {\n        if (isNonColliding)\n            return Body._nextNonCollidingGroupId--;\n\n        return Body._nextCollidingGroupId++;\n    };\n\n    /**\n     * Returns the next unique category bitfield (starting after the initial default category `0x0001`).\n     * There are 32 available. See `body.collisionFilter` for more information.\n     * @method nextCategory\n     * @return {Number} Unique category bitfield\n     */\n    Body.nextCategory = function() {\n        Body._nextCategory = Body._nextCategory << 1;\n        return Body._nextCategory;\n    };\n\n    /**\n     * Initialises body properties.\n     * @method _initProperties\n     * @private\n     * @param {body} body\n     * @param {} [options]\n     */\n    var _initProperties = function(body, options) {\n        options = options || {};\n\n        // init required properties (order is important)\n        Body.set(body, {\n            bounds: body.bounds || Bounds.create(body.vertices),\n            positionPrev: body.positionPrev || Vector.clone(body.position),\n            anglePrev: body.anglePrev || body.angle,\n            vertices: body.vertices,\n            parts: body.parts || [body],\n            isStatic: body.isStatic,\n            isSleeping: body.isSleeping,\n            parent: body.parent || body\n        });\n\n        Vertices.rotate(body.vertices, body.angle, body.position);\n        Axes.rotate(body.axes, body.angle);\n        Bounds.update(body.bounds, body.vertices, body.velocity);\n\n        // allow options to override the automatically calculated properties\n        Body.set(body, {\n            axes: options.axes || body.axes,\n            area: options.area || body.area,\n            mass: options.mass || body.mass,\n            inertia: options.inertia || body.inertia\n        });\n\n        // render properties\n        var defaultFillStyle = (body.isStatic ? '#14151f' : Common.choose(['#f19648', '#f5d259', '#f55a3c', '#063e7b', '#ececd1'])),\n            defaultStrokeStyle = body.isStatic ? '#555' : '#ccc',\n            defaultLineWidth = body.isStatic && body.render.fillStyle === null ? 1 : 0;\n        body.render.fillStyle = body.render.fillStyle || defaultFillStyle;\n        body.render.strokeStyle = body.render.strokeStyle || defaultStrokeStyle;\n        body.render.lineWidth = body.render.lineWidth || defaultLineWidth;\n        body.render.sprite.xOffset += -(body.bounds.min.x - body.position.x) / (body.bounds.max.x - body.bounds.min.x);\n        body.render.sprite.yOffset += -(body.bounds.min.y - body.position.y) / (body.bounds.max.y - body.bounds.min.y);\n    };\n\n    /**\n     * Given a property and a value (or map of), sets the property(s) on the body, using the appropriate setter functions if they exist.\n     * Prefer to use the actual setter functions in performance critical situations.\n     * @method set\n     * @param {body} body\n     * @param {} settings A property name (or map of properties and values) to set on the body.\n     * @param {} value The value to set if `settings` is a single property name.\n     */\n    Body.set = function(body, settings, value) {\n        var property;\n\n        if (typeof settings === 'string') {\n            property = settings;\n            settings = {};\n            settings[property] = value;\n        }\n\n        for (property in settings) {\n            if (!Object.prototype.hasOwnProperty.call(settings, property))\n                continue;\n\n            value = settings[property];\n            switch (property) {\n\n            case 'isStatic':\n                Body.setStatic(body, value);\n                break;\n            case 'isSleeping':\n                Sleeping.set(body, value);\n                break;\n            case 'mass':\n                Body.setMass(body, value);\n                break;\n            case 'density':\n                Body.setDensity(body, value);\n                break;\n            case 'inertia':\n                Body.setInertia(body, value);\n                break;\n            case 'vertices':\n                Body.setVertices(body, value);\n                break;\n            case 'position':\n                Body.setPosition(body, value);\n                break;\n            case 'angle':\n                Body.setAngle(body, value);\n                break;\n            case 'velocity':\n                Body.setVelocity(body, value);\n                break;\n            case 'angularVelocity':\n                Body.setAngularVelocity(body, value);\n                break;\n            case 'speed':\n                Body.setSpeed(body, value);\n                break;\n            case 'angularSpeed':\n                Body.setAngularSpeed(body, value);\n                break;\n            case 'parts':\n                Body.setParts(body, value);\n                break;\n            case 'centre':\n                Body.setCentre(body, value);\n                break;\n            default:\n                body[property] = value;\n\n            }\n        }\n    };\n\n    /**\n     * Sets the body as static, including isStatic flag and setting mass and inertia to Infinity.\n     * @method setStatic\n     * @param {body} body\n     * @param {bool} isStatic\n     */\n    Body.setStatic = function(body, isStatic) {\n        for (var i = 0; i < body.parts.length; i++) {\n            var part = body.parts[i];\n            part.isStatic = isStatic;\n\n            if (isStatic) {\n                part._original = {\n                    restitution: part.restitution,\n                    friction: part.friction,\n                    mass: part.mass,\n                    inertia: part.inertia,\n                    density: part.density,\n                    inverseMass: part.inverseMass,\n                    inverseInertia: part.inverseInertia\n                };\n\n                part.restitution = 0;\n                part.friction = 1;\n                part.mass = part.inertia = part.density = Infinity;\n                part.inverseMass = part.inverseInertia = 0;\n\n                part.positionPrev.x = part.position.x;\n                part.positionPrev.y = part.position.y;\n                part.anglePrev = part.angle;\n                part.angularVelocity = 0;\n                part.speed = 0;\n                part.angularSpeed = 0;\n                part.motion = 0;\n            } else if (part._original) {\n                part.restitution = part._original.restitution;\n                part.friction = part._original.friction;\n                part.mass = part._original.mass;\n                part.inertia = part._original.inertia;\n                part.density = part._original.density;\n                part.inverseMass = part._original.inverseMass;\n                part.inverseInertia = part._original.inverseInertia;\n\n                part._original = null;\n            }\n        }\n    };\n\n    /**\n     * Sets the mass of the body. Inverse mass, density and inertia are automatically updated to reflect the change.\n     * @method setMass\n     * @param {body} body\n     * @param {number} mass\n     */\n    Body.setMass = function(body, mass) {\n        var moment = body.inertia / (body.mass / 6);\n        body.inertia = moment * (mass / 6);\n        body.inverseInertia = 1 / body.inertia;\n\n        body.mass = mass;\n        body.inverseMass = 1 / body.mass;\n        body.density = body.mass / body.area;\n    };\n\n    /**\n     * Sets the density of the body. Mass and inertia are automatically updated to reflect the change.\n     * @method setDensity\n     * @param {body} body\n     * @param {number} density\n     */\n    Body.setDensity = function(body, density) {\n        Body.setMass(body, density * body.area);\n        body.density = density;\n    };\n\n    /**\n     * Sets the moment of inertia of the body. This is the second moment of area in two dimensions.\n     * Inverse inertia is automatically updated to reflect the change. Mass is not changed.\n     * @method setInertia\n     * @param {body} body\n     * @param {number} inertia\n     */\n    Body.setInertia = function(body, inertia) {\n        body.inertia = inertia;\n        body.inverseInertia = 1 / body.inertia;\n    };\n\n    /**\n     * Sets the body's vertices and updates body properties accordingly, including inertia, area and mass (with respect to `body.density`).\n     * Vertices will be automatically transformed to be orientated around their centre of mass as the origin.\n     * They are then automatically translated to world space based on `body.position`.\n     *\n     * The `vertices` argument should be passed as an array of `Matter.Vector` points (or a `Matter.Vertices` array).\n     * Vertices must form a convex hull. Concave vertices must be decomposed into convex parts.\n     * \n     * @method setVertices\n     * @param {body} body\n     * @param {vector[]} vertices\n     */\n    Body.setVertices = function(body, vertices) {\n        // change vertices\n        if (vertices[0].body === body) {\n            body.vertices = vertices;\n        } else {\n            body.vertices = Vertices.create(vertices, body);\n        }\n\n        // update properties\n        body.axes = Axes.fromVertices(body.vertices);\n        body.area = Vertices.area(body.vertices);\n        Body.setMass(body, body.density * body.area);\n\n        // orient vertices around the centre of mass at origin (0, 0)\n        var centre = Vertices.centre(body.vertices);\n        Vertices.translate(body.vertices, centre, -1);\n\n        // update inertia while vertices are at origin (0, 0)\n        Body.setInertia(body, Body._inertiaScale * Vertices.inertia(body.vertices, body.mass));\n\n        // update geometry\n        Vertices.translate(body.vertices, body.position);\n        Bounds.update(body.bounds, body.vertices, body.velocity);\n    };\n\n    /**\n     * Sets the parts of the `body` and updates mass, inertia and centroid.\n     * Each part will have its parent set to `body`.\n     * By default the convex hull will be automatically computed and set on `body`, unless `autoHull` is set to `false.`\n     * Note that this method will ensure that the first part in `body.parts` will always be the `body`.\n     * @method setParts\n     * @param {body} body\n     * @param {body[]} parts\n     * @param {bool} [autoHull=true]\n     */\n    Body.setParts = function(body, parts, autoHull) {\n        var i;\n\n        // add all the parts, ensuring that the first part is always the parent body\n        parts = parts.slice(0);\n        body.parts.length = 0;\n        body.parts.push(body);\n        body.parent = body;\n\n        for (i = 0; i < parts.length; i++) {\n            var part = parts[i];\n            if (part !== body) {\n                part.parent = body;\n                body.parts.push(part);\n            }\n        }\n\n        if (body.parts.length === 1)\n            return;\n\n        autoHull = typeof autoHull !== 'undefined' ? autoHull : true;\n\n        // find the convex hull of all parts to set on the parent body\n        if (autoHull) {\n            var vertices = [];\n            for (i = 0; i < parts.length; i++) {\n                vertices = vertices.concat(parts[i].vertices);\n            }\n\n            Vertices.clockwiseSort(vertices);\n\n            var hull = Vertices.hull(vertices),\n                hullCentre = Vertices.centre(hull);\n\n            Body.setVertices(body, hull);\n            Vertices.translate(body.vertices, hullCentre);\n        }\n\n        // sum the properties of all compound parts of the parent body\n        var total = Body._totalProperties(body);\n\n        body.area = total.area;\n        body.parent = body;\n        body.position.x = total.centre.x;\n        body.position.y = total.centre.y;\n        body.positionPrev.x = total.centre.x;\n        body.positionPrev.y = total.centre.y;\n\n        Body.setMass(body, total.mass);\n        Body.setInertia(body, total.inertia);\n        Body.setPosition(body, total.centre);\n    };\n\n    /**\n     * Set the centre of mass of the body. \n     * The `centre` is a vector in world-space unless `relative` is set, in which case it is a translation.\n     * The centre of mass is the point the body rotates about and can be used to simulate non-uniform density.\n     * This is equal to moving `body.position` but not the `body.vertices`.\n     * Invalid if the `centre` falls outside the body's convex hull.\n     * @method setCentre\n     * @param {body} body\n     * @param {vector} centre\n     * @param {bool} relative\n     */\n    Body.setCentre = function(body, centre, relative) {\n        if (!relative) {\n            body.positionPrev.x = centre.x - (body.position.x - body.positionPrev.x);\n            body.positionPrev.y = centre.y - (body.position.y - body.positionPrev.y);\n            body.position.x = centre.x;\n            body.position.y = centre.y;\n        } else {\n            body.positionPrev.x += centre.x;\n            body.positionPrev.y += centre.y;\n            body.position.x += centre.x;\n            body.position.y += centre.y;\n        }\n    };\n\n    /**\n     * Sets the position of the body. By default velocity is unchanged.\n     * If `updateVelocity` is `true` then velocity is inferred from the change in position.\n     * @method setPosition\n     * @param {body} body\n     * @param {vector} position\n     * @param {boolean} [updateVelocity=false]\n     */\n    Body.setPosition = function(body, position, updateVelocity) {\n        var delta = Vector.sub(position, body.position);\n\n        if (updateVelocity) {\n            body.positionPrev.x = body.position.x;\n            body.positionPrev.y = body.position.y;\n            body.velocity.x = delta.x;\n            body.velocity.y = delta.y;\n            body.speed = Vector.magnitude(delta);\n        } else {\n            body.positionPrev.x += delta.x;\n            body.positionPrev.y += delta.y;\n        }\n\n        for (var i = 0; i < body.parts.length; i++) {\n            var part = body.parts[i];\n            part.position.x += delta.x;\n            part.position.y += delta.y;\n            Vertices.translate(part.vertices, delta);\n            Bounds.update(part.bounds, part.vertices, body.velocity);\n        }\n    };\n\n    /**\n     * Sets the angle of the body. By default angular velocity is unchanged.\n     * If `updateVelocity` is `true` then angular velocity is inferred from the change in angle.\n     * @method setAngle\n     * @param {body} body\n     * @param {number} angle\n     * @param {boolean} [updateVelocity=false]\n     */\n    Body.setAngle = function(body, angle, updateVelocity) {\n        var delta = angle - body.angle;\n        \n        if (updateVelocity) {\n            body.anglePrev = body.angle;\n            body.angularVelocity = delta;\n            body.angularSpeed = Math.abs(delta);\n        } else {\n            body.anglePrev += delta;\n        }\n\n        for (var i = 0; i < body.parts.length; i++) {\n            var part = body.parts[i];\n            part.angle += delta;\n            Vertices.rotate(part.vertices, delta, body.position);\n            Axes.rotate(part.axes, delta);\n            Bounds.update(part.bounds, part.vertices, body.velocity);\n            if (i > 0) {\n                Vector.rotateAbout(part.position, delta, body.position, part.position);\n            }\n        }\n    };\n\n    /**\n     * Sets the current linear velocity of the body.  \n     * Affects body speed.\n     * @method setVelocity\n     * @param {body} body\n     * @param {vector} velocity\n     */\n    Body.setVelocity = function(body, velocity) {\n        var timeScale = body.deltaTime / Body._baseDelta;\n        body.positionPrev.x = body.position.x - velocity.x * timeScale;\n        body.positionPrev.y = body.position.y - velocity.y * timeScale;\n        body.velocity.x = (body.position.x - body.positionPrev.x) / timeScale;\n        body.velocity.y = (body.position.y - body.positionPrev.y) / timeScale;\n        body.speed = Vector.magnitude(body.velocity);\n    };\n\n    /**\n     * Gets the current linear velocity of the body.\n     * @method getVelocity\n     * @param {body} body\n     * @return {vector} velocity\n     */\n    Body.getVelocity = function(body) {\n        var timeScale = Body._baseDelta / body.deltaTime;\n\n        return {\n            x: (body.position.x - body.positionPrev.x) * timeScale,\n            y: (body.position.y - body.positionPrev.y) * timeScale\n        };\n    };\n\n    /**\n     * Gets the current linear speed of the body.  \n     * Equivalent to the magnitude of its velocity.\n     * @method getSpeed\n     * @param {body} body\n     * @return {number} speed\n     */\n    Body.getSpeed = function(body) {\n        return Vector.magnitude(Body.getVelocity(body));\n    };\n\n    /**\n     * Sets the current linear speed of the body.  \n     * Direction is maintained. Affects body velocity.\n     * @method setSpeed\n     * @param {body} body\n     * @param {number} speed\n     */\n    Body.setSpeed = function(body, speed) {\n        Body.setVelocity(body, Vector.mult(Vector.normalise(Body.getVelocity(body)), speed));\n    };\n\n    /**\n     * Sets the current rotational velocity of the body.  \n     * Affects body angular speed.\n     * @method setAngularVelocity\n     * @param {body} body\n     * @param {number} velocity\n     */\n    Body.setAngularVelocity = function(body, velocity) {\n        var timeScale = body.deltaTime / Body._baseDelta;\n        body.anglePrev = body.angle - velocity * timeScale;\n        body.angularVelocity = (body.angle - body.anglePrev) / timeScale;\n        body.angularSpeed = Math.abs(body.angularVelocity);\n    };\n\n    /**\n     * Gets the current rotational velocity of the body.\n     * @method getAngularVelocity\n     * @param {body} body\n     * @return {number} angular velocity\n     */\n    Body.getAngularVelocity = function(body) {\n        return (body.angle - body.anglePrev) * Body._baseDelta / body.deltaTime;\n    };\n\n    /**\n     * Gets the current rotational speed of the body.  \n     * Equivalent to the magnitude of its angular velocity.\n     * @method getAngularSpeed\n     * @param {body} body\n     * @return {number} angular speed\n     */\n    Body.getAngularSpeed = function(body) {\n        return Math.abs(Body.getAngularVelocity(body));\n    };\n\n    /**\n     * Sets the current rotational speed of the body.  \n     * Direction is maintained. Affects body angular velocity.\n     * @method setAngularSpeed\n     * @param {body} body\n     * @param {number} speed\n     */\n    Body.setAngularSpeed = function(body, speed) {\n        Body.setAngularVelocity(body, Common.sign(Body.getAngularVelocity(body)) * speed);\n    };\n\n    /**\n     * Moves a body by a given vector relative to its current position. By default velocity is unchanged.\n     * If `updateVelocity` is `true` then velocity is inferred from the change in position.\n     * @method translate\n     * @param {body} body\n     * @param {vector} translation\n     * @param {boolean} [updateVelocity=false]\n     */\n    Body.translate = function(body, translation, updateVelocity) {\n        Body.setPosition(body, Vector.add(body.position, translation), updateVelocity);\n    };\n\n    /**\n     * Rotates a body by a given angle relative to its current angle. By default angular velocity is unchanged.\n     * If `updateVelocity` is `true` then angular velocity is inferred from the change in angle.\n     * @method rotate\n     * @param {body} body\n     * @param {number} rotation\n     * @param {vector} [point]\n     * @param {boolean} [updateVelocity=false]\n     */\n    Body.rotate = function(body, rotation, point, updateVelocity) {\n        if (!point) {\n            Body.setAngle(body, body.angle + rotation, updateVelocity);\n        } else {\n            var cos = Math.cos(rotation),\n                sin = Math.sin(rotation),\n                dx = body.position.x - point.x,\n                dy = body.position.y - point.y;\n                \n            Body.setPosition(body, {\n                x: point.x + (dx * cos - dy * sin),\n                y: point.y + (dx * sin + dy * cos)\n            }, updateVelocity);\n\n            Body.setAngle(body, body.angle + rotation, updateVelocity);\n        }\n    };\n\n    /**\n     * Scales the body, including updating physical properties (mass, area, axes, inertia), from a world-space point (default is body centre).\n     * @method scale\n     * @param {body} body\n     * @param {number} scaleX\n     * @param {number} scaleY\n     * @param {vector} [point]\n     */\n    Body.scale = function(body, scaleX, scaleY, point) {\n        var totalArea = 0,\n            totalInertia = 0;\n\n        point = point || body.position;\n\n        for (var i = 0; i < body.parts.length; i++) {\n            var part = body.parts[i];\n\n            // scale vertices\n            Vertices.scale(part.vertices, scaleX, scaleY, point);\n\n            // update properties\n            part.axes = Axes.fromVertices(part.vertices);\n            part.area = Vertices.area(part.vertices);\n            Body.setMass(part, body.density * part.area);\n\n            // update inertia (requires vertices to be at origin)\n            Vertices.translate(part.vertices, { x: -part.position.x, y: -part.position.y });\n            Body.setInertia(part, Body._inertiaScale * Vertices.inertia(part.vertices, part.mass));\n            Vertices.translate(part.vertices, { x: part.position.x, y: part.position.y });\n\n            if (i > 0) {\n                totalArea += part.area;\n                totalInertia += part.inertia;\n            }\n\n            // scale position\n            part.position.x = point.x + (part.position.x - point.x) * scaleX;\n            part.position.y = point.y + (part.position.y - point.y) * scaleY;\n\n            // update bounds\n            Bounds.update(part.bounds, part.vertices, body.velocity);\n        }\n\n        // handle parent body\n        if (body.parts.length > 1) {\n            body.area = totalArea;\n\n            if (!body.isStatic) {\n                Body.setMass(body, body.density * totalArea);\n                Body.setInertia(body, totalInertia);\n            }\n        }\n\n        // handle circles\n        if (body.circleRadius) { \n            if (scaleX === scaleY) {\n                body.circleRadius *= scaleX;\n            } else {\n                // body is no longer a circle\n                body.circleRadius = null;\n            }\n        }\n    };\n\n    /**\n     * Performs an update by integrating the equations of motion on the `body`.\n     * This is applied every update by `Matter.Engine` automatically.\n     * @method update\n     * @param {body} body\n     * @param {number} [deltaTime=16.666]\n     */\n    Body.update = function(body, deltaTime) {\n        deltaTime = (typeof deltaTime !== 'undefined' ? deltaTime : (1000 / 60)) * body.timeScale;\n\n        var deltaTimeSquared = deltaTime * deltaTime,\n            correction = Body._timeCorrection ? deltaTime / (body.deltaTime || deltaTime) : 1;\n\n        // from the previous step\n        var frictionAir = 1 - body.frictionAir * (deltaTime / Common._baseDelta),\n            velocityPrevX = (body.position.x - body.positionPrev.x) * correction,\n            velocityPrevY = (body.position.y - body.positionPrev.y) * correction;\n\n        // update velocity with Verlet integration\n        body.velocity.x = (velocityPrevX * frictionAir) + (body.force.x / body.mass) * deltaTimeSquared;\n        body.velocity.y = (velocityPrevY * frictionAir) + (body.force.y / body.mass) * deltaTimeSquared;\n\n        body.positionPrev.x = body.position.x;\n        body.positionPrev.y = body.position.y;\n        body.position.x += body.velocity.x;\n        body.position.y += body.velocity.y;\n        body.deltaTime = deltaTime;\n\n        // update angular velocity with Verlet integration\n        body.angularVelocity = ((body.angle - body.anglePrev) * frictionAir * correction) + (body.torque / body.inertia) * deltaTimeSquared;\n        body.anglePrev = body.angle;\n        body.angle += body.angularVelocity;\n\n        // transform the body geometry\n        for (var i = 0; i < body.parts.length; i++) {\n            var part = body.parts[i];\n\n            Vertices.translate(part.vertices, body.velocity);\n            \n            if (i > 0) {\n                part.position.x += body.velocity.x;\n                part.position.y += body.velocity.y;\n            }\n\n            if (body.angularVelocity !== 0) {\n                Vertices.rotate(part.vertices, body.angularVelocity, body.position);\n                Axes.rotate(part.axes, body.angularVelocity);\n                if (i > 0) {\n                    Vector.rotateAbout(part.position, body.angularVelocity, body.position, part.position);\n                }\n            }\n\n            Bounds.update(part.bounds, part.vertices, body.velocity);\n        }\n    };\n\n    /**\n     * Updates properties `body.velocity`, `body.speed`, `body.angularVelocity` and `body.angularSpeed` which are normalised in relation to `Body._baseDelta`.\n     * @method updateVelocities\n     * @param {body} body\n     */\n    Body.updateVelocities = function(body) {\n        var timeScale = Body._baseDelta / body.deltaTime,\n            bodyVelocity = body.velocity;\n\n        bodyVelocity.x = (body.position.x - body.positionPrev.x) * timeScale;\n        bodyVelocity.y = (body.position.y - body.positionPrev.y) * timeScale;\n        body.speed = Math.sqrt((bodyVelocity.x * bodyVelocity.x) + (bodyVelocity.y * bodyVelocity.y));\n\n        body.angularVelocity = (body.angle - body.anglePrev) * timeScale;\n        body.angularSpeed = Math.abs(body.angularVelocity);\n    };\n\n    /**\n     * Applies the `force` to the `body` from the force origin `position` in world-space, over a single timestep, including applying any resulting angular torque.\n     * \n     * Forces are useful for effects like gravity, wind or rocket thrust, but can be difficult in practice when precise control is needed. In these cases see `Body.setVelocity` and `Body.setPosition` as an alternative.\n     * \n     * The force from this function is only applied once for the duration of a single timestep, in other words the duration depends directly on the current engine update `delta` and the rate of calls to this function.\n     * \n     * Therefore to account for time, you should apply the force constantly over as many engine updates as equivalent to the intended duration.\n     * \n     * If all or part of the force duration is some fraction of a timestep, first multiply the force by `duration / timestep`.\n     * \n     * The force origin `position` in world-space must also be specified. Passing `body.position` will result in zero angular effect as the force origin would be at the centre of mass.\n     * \n     * The `body` will take time to accelerate under a force, the resulting effect depends on duration of the force, the body mass and other forces on the body including friction combined.\n     * @method applyForce\n     * @param {body} body\n     * @param {vector} position The force origin in world-space. Pass `body.position` to avoid angular torque.\n     * @param {vector} force\n     */\n    Body.applyForce = function(body, position, force) {\n        var offset = { x: position.x - body.position.x, y: position.y - body.position.y };\n        body.force.x += force.x;\n        body.force.y += force.y;\n        body.torque += offset.x * force.y - offset.y * force.x;\n    };\n\n    /**\n     * Returns the sums of the properties of all compound parts of the parent body.\n     * @method _totalProperties\n     * @private\n     * @param {body} body\n     * @return {}\n     */\n    Body._totalProperties = function(body) {\n        // from equations at:\n        // https://ecourses.ou.edu/cgi-bin/ebook.cgi?doc=&topic=st&chap_sec=07.2&page=theory\n        // http://output.to/sideway/default.asp?qno=121100087\n\n        var properties = {\n            mass: 0,\n            area: 0,\n            inertia: 0,\n            centre: { x: 0, y: 0 }\n        };\n\n        // sum the properties of all compound parts of the parent body\n        for (var i = body.parts.length === 1 ? 0 : 1; i < body.parts.length; i++) {\n            var part = body.parts[i],\n                mass = part.mass !== Infinity ? part.mass : 1;\n\n            properties.mass += mass;\n            properties.area += part.area;\n            properties.inertia += part.inertia;\n            properties.centre = Vector.add(properties.centre, Vector.mult(part.position, mass));\n        }\n\n        properties.centre = Vector.div(properties.centre, properties.mass);\n\n        return properties;\n    };\n\n    /*\n    *\n    *  Events Documentation\n    *\n    */\n\n    /**\n    * Fired when a body starts sleeping (where `this` is the body).\n    *\n    * @event sleepStart\n    * @this {body} The body that has started sleeping\n    * @param {} event An event object\n    * @param {} event.source The source object of the event\n    * @param {} event.name The name of the event\n    */\n\n    /**\n    * Fired when a body ends sleeping (where `this` is the body).\n    *\n    * @event sleepEnd\n    * @this {body} The body that has ended sleeping\n    * @param {} event An event object\n    * @param {} event.source The source object of the event\n    * @param {} event.name The name of the event\n    */\n\n    /*\n    *\n    *  Properties Documentation\n    *\n    */\n\n    /**\n     * An integer `Number` uniquely identifying number generated in `Body.create` by `Common.nextId`.\n     *\n     * @property id\n     * @type number\n     */\n\n    /**\n     * _Read only_. Set by `Body.create`.\n     * \n     * A `String` denoting the type of object.\n     *\n     * @readOnly\n     * @property type\n     * @type string\n     * @default \"body\"\n     */\n\n    /**\n     * An arbitrary `String` name to help the user identify and manage bodies.\n     *\n     * @property label\n     * @type string\n     * @default \"Body\"\n     */\n\n    /**\n     * _Read only_. Use `Body.setParts` to set. \n     * \n     * An array of bodies that make up this body. \n     * The first body in the array must always be a self reference to the current body instance.\n     * All bodies in the `parts` array together form a single rigid compound body.\n     * Parts are allowed to overlap, have gaps or holes or even form concave bodies.\n     * Parts themselves should never be added to a `World`, only the parent body should be.\n     * Use `Body.setParts` when setting parts to ensure correct updates of all properties.\n     *\n     * @readOnly\n     * @property parts\n     * @type body[]\n     */\n\n    /**\n     * An object reserved for storing plugin-specific properties.\n     *\n     * @property plugin\n     * @type {}\n     */\n\n    /**\n     * _Read only_. Updated by `Body.setParts`.\n     * \n     * A reference to the body that this is a part of. See `body.parts`.\n     * This is a self reference if the body is not a part of another body.\n     *\n     * @readOnly\n     * @property parent\n     * @type body\n     */\n\n    /**\n     * A `Number` specifying the angle of the body, in radians.\n     *\n     * @property angle\n     * @type number\n     * @default 0\n     */\n\n    /**\n     * _Read only_. Use `Body.setVertices` or `Body.setParts` to set. See also `Bodies.fromVertices`.\n     * \n     * An array of `Vector` objects that specify the convex hull of the rigid body.\n     * These should be provided about the origin `(0, 0)`. E.g.\n     *\n     * `[{ x: 0, y: 0 }, { x: 25, y: 50 }, { x: 50, y: 0 }]`\n     * \n     * Vertices must always be convex, in clockwise order and must not contain any duplicate points.\n     * \n     * Concave vertices should be decomposed into convex `parts`, see `Bodies.fromVertices` and `Body.setParts`.\n     *\n     * When set the vertices are translated such that `body.position` is at the centre of mass.\n     * Many other body properties are automatically calculated from these vertices when set including `density`, `area` and `inertia`.\n     * \n     * The module `Matter.Vertices` contains useful methods for working with vertices.\n     *\n     * @readOnly\n     * @property vertices\n     * @type vector[]\n     */\n\n    /**\n     * _Read only_. Use `Body.setPosition` to set. \n     * \n     * A `Vector` that specifies the current world-space position of the body.\n     * \n     * @readOnly\n     * @property position\n     * @type vector\n     * @default { x: 0, y: 0 }\n     */\n\n    /**\n     * A `Vector` that accumulates the total force applied to the body for a single update.\n     * Force is zeroed after every `Engine.update`, so constant forces should be applied for every update they are needed. See also `Body.applyForce`.\n     * \n     * @property force\n     * @type vector\n     * @default { x: 0, y: 0 }\n     */\n\n    /**\n     * A `Number` that accumulates the total torque (turning force) applied to the body for a single update. See also `Body.applyForce`.\n     * Torque is zeroed after every `Engine.update`, so constant torques should be applied for every update they are needed.\n     *\n     * Torques result in angular acceleration on every update, which depends on body inertia and the engine update delta.\n     * \n     * @property torque\n     * @type number\n     * @default 0\n     */\n\n    /**\n     * _Read only_. Use `Body.setSpeed` to set. \n     * \n     * See `Body.getSpeed` for details.\n     * \n     * Equivalent to the magnitude of `body.velocity` (always positive).\n     * \n     * @readOnly\n     * @property speed\n     * @type number\n     * @default 0\n     */\n\n    /**\n     * _Read only_. Use `Body.setVelocity` to set. \n     * \n     * See `Body.getVelocity` for details.\n     * \n     * Equivalent to the magnitude of `body.angularVelocity` (always positive).\n     * \n     * @readOnly\n     * @property velocity\n     * @type vector\n     * @default { x: 0, y: 0 }\n     */\n\n    /**\n     * _Read only_. Use `Body.setAngularSpeed` to set. \n     * \n     * See `Body.getAngularSpeed` for details.\n     * \n     * \n     * @readOnly\n     * @property angularSpeed\n     * @type number\n     * @default 0\n     */\n\n    /**\n     * _Read only_. Use `Body.setAngularVelocity` to set. \n     * \n     * See `Body.getAngularVelocity` for details.\n     * \n     *\n     * @readOnly\n     * @property angularVelocity\n     * @type number\n     * @default 0\n     */\n\n    /**\n     * _Read only_. Use `Body.setStatic` to set. \n     * \n     * A flag that indicates whether a body is considered static. A static body can never change position or angle and is completely fixed.\n     *\n     * @readOnly\n     * @property isStatic\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * A flag that indicates whether a body is a sensor. Sensor triggers collision events, but doesn't react with colliding body physically.\n     *\n     * @property isSensor\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * _Read only_. Use `Sleeping.set` to set. \n     * \n     * A flag that indicates whether the body is considered sleeping. A sleeping body acts similar to a static body, except it is only temporary and can be awoken.\n     *\n     * @readOnly\n     * @property isSleeping\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * _Read only_. Calculated during engine update only when sleeping is enabled.\n     * \n     * A `Number` that loosely measures the amount of movement a body currently has.\n     *\n     * Derived from `body.speed^2 + body.angularSpeed^2`. See `Sleeping.update`.\n     * \n     * @readOnly\n     * @property motion\n     * @type number\n     * @default 0\n     */\n\n    /**\n     * A `Number` that defines the length of time during which this body must have near-zero velocity before it is set as sleeping by the `Matter.Sleeping` module (if sleeping is enabled by the engine).\n     * \n     * @property sleepThreshold\n     * @type number\n     * @default 60\n     */\n\n    /**\n     * _Read only_. Use `Body.setDensity` to set. \n     * \n     * A `Number` that defines the density of the body (mass per unit area).\n     * \n     * Mass will also be updated when set.\n     *\n     * @readOnly\n     * @property density\n     * @type number\n     * @default 0.001\n     */\n\n    /**\n     * _Read only_. Use `Body.setMass` to set. \n     * \n     * A `Number` that defines the mass of the body.\n     * \n     * Density will also be updated when set.\n     * \n     * @readOnly\n     * @property mass\n     * @type number\n     */\n\n    /**\n     * _Read only_. Use `Body.setMass` to set. \n     * \n     * A `Number` that defines the inverse mass of the body (`1 / mass`).\n     *\n     * @readOnly\n     * @property inverseMass\n     * @type number\n     */\n\n    /**\n     * _Read only_. Automatically calculated when vertices, mass or density are set or set through `Body.setInertia`.\n     * \n     * A `Number` that defines the moment of inertia of the body. This is the second moment of area in two dimensions.\n     * \n     * Can be manually set to `Infinity` to prevent rotation of the body. See `Body.setInertia`.\n     * \n     * @readOnly\n     * @property inertia\n     * @type number\n     */\n\n    /**\n     * _Read only_. Automatically calculated when vertices, mass or density are set or calculated by `Body.setInertia`.\n     * \n     * A `Number` that defines the inverse moment of inertia of the body (`1 / inertia`).\n     * \n     * @readOnly\n     * @property inverseInertia\n     * @type number\n     */\n\n    /**\n     * A `Number` that defines the restitution (elasticity) of the body. The value is always positive and is in the range `(0, 1)`.\n     * A value of `0` means collisions may be perfectly inelastic and no bouncing may occur. \n     * A value of `0.8` means the body may bounce back with approximately 80% of its kinetic energy.\n     * Note that collision response is based on _pairs_ of bodies, and that `restitution` values are _combined_ with the following formula:\n     *\n     * `Math.max(bodyA.restitution, bodyB.restitution)`\n     *\n     * @property restitution\n     * @type number\n     * @default 0\n     */\n\n    /**\n     * A `Number` that defines the friction of the body. The value is always positive and is in the range `(0, 1)`.\n     * A value of `0` means that the body may slide indefinitely.\n     * A value of `1` means the body may come to a stop almost instantly after a force is applied.\n     *\n     * The effects of the value may be non-linear. \n     * High values may be unstable depending on the body.\n     * The engine uses a Coulomb friction model including static and kinetic friction.\n     * Note that collision response is based on _pairs_ of bodies, and that `friction` values are _combined_ with the following formula:\n     *\n     * `Math.min(bodyA.friction, bodyB.friction)`\n     *\n     * @property friction\n     * @type number\n     * @default 0.1\n     */\n\n    /**\n     * A `Number` that defines the static friction of the body (in the Coulomb friction model). \n     * A value of `0` means the body will never 'stick' when it is nearly stationary and only dynamic `friction` is used.\n     * The higher the value (e.g. `10`), the more force it will take to initially get the body moving when nearly stationary.\n     * This value is multiplied with the `friction` property to make it easier to change `friction` and maintain an appropriate amount of static friction.\n     *\n     * @property frictionStatic\n     * @type number\n     * @default 0.5\n     */\n\n    /**\n     * A `Number` that defines the air friction of the body (air resistance). \n     * A value of `0` means the body will never slow as it moves through space.\n     * The higher the value, the faster a body slows when moving through space.\n     * The effects of the value are non-linear. \n     *\n     * @property frictionAir\n     * @type number\n     * @default 0.01\n     */\n\n    /**\n     * An `Object` that specifies the collision filtering properties of this body.\n     *\n     * Collisions between two bodies will obey the following rules:\n     * - If the two bodies have the same non-zero value of `collisionFilter.group`,\n     *   they will always collide if the value is positive, and they will never collide\n     *   if the value is negative.\n     * - If the two bodies have different values of `collisionFilter.group` or if one\n     *   (or both) of the bodies has a value of 0, then the category/mask rules apply as follows:\n     *\n     * Each body belongs to a collision category, given by `collisionFilter.category`. This\n     * value is used as a bit field and the category should have only one bit set, meaning that\n     * the value of this property is a power of two in the range [1, 2^31]. Thus, there are 32\n     * different collision categories available.\n     *\n     * Each body also defines a collision bitmask, given by `collisionFilter.mask` which specifies\n     * the categories it collides with (the value is the bitwise AND value of all these categories).\n     *\n     * Using the category/mask rules, two bodies `A` and `B` collide if each includes the other's\n     * category in its mask, i.e. `(categoryA & maskB) !== 0` and `(categoryB & maskA) !== 0`\n     * are both true.\n     *\n     * @property collisionFilter\n     * @type object\n     */\n\n    /**\n     * An Integer `Number`, that specifies the collision group this body belongs to.\n     * See `body.collisionFilter` for more information.\n     *\n     * @property collisionFilter.group\n     * @type object\n     * @default 0\n     */\n\n    /**\n     * A bit field that specifies the collision category this body belongs to.\n     * The category value should have only one bit set, for example `0x0001`.\n     * This means there are up to 32 unique collision categories available.\n     * See `body.collisionFilter` for more information.\n     *\n     * @property collisionFilter.category\n     * @type object\n     * @default 1\n     */\n\n    /**\n     * A bit mask that specifies the collision categories this body may collide with.\n     * See `body.collisionFilter` for more information.\n     *\n     * @property collisionFilter.mask\n     * @type object\n     * @default -1\n     */\n\n    /**\n     * A `Number` that specifies a thin boundary around the body where it is allowed to slightly sink into other bodies.\n     * \n     * This is required for proper collision response, including friction and restitution effects.\n     * \n     * The default should generally suffice in most cases. You may need to decrease this value for very small bodies that are nearing the default value in scale.\n     *\n     * @property slop\n     * @type number\n     * @default 0.05\n     */\n\n    /**\n     * A `Number` that specifies per-body time scaling.\n     *\n     * @property timeScale\n     * @type number\n     * @default 1\n     */\n\n    /**\n     * _Read only_. Updated during engine update.\n     * \n     * A `Number` that records the last delta time value used to update this body.\n     * Used to calculate speed and velocity.\n     *\n     * @readOnly\n     * @property deltaTime\n     * @type number\n     * @default 1000 / 60\n     */\n\n    /**\n     * An `Object` that defines the rendering properties to be consumed by the module `Matter.Render`.\n     *\n     * @property render\n     * @type object\n     */\n\n    /**\n     * A flag that indicates if the body should be rendered.\n     *\n     * @property render.visible\n     * @type boolean\n     * @default true\n     */\n\n    /**\n     * Sets the opacity to use when rendering.\n     *\n     * @property render.opacity\n     * @type number\n     * @default 1\n    */\n\n    /**\n     * An `Object` that defines the sprite properties to use when rendering, if any.\n     *\n     * @property render.sprite\n     * @type object\n     */\n\n    /**\n     * An `String` that defines the path to the image to use as the sprite texture, if any.\n     *\n     * @property render.sprite.texture\n     * @type string\n     */\n     \n    /**\n     * A `Number` that defines the scaling in the x-axis for the sprite, if any.\n     *\n     * @property render.sprite.xScale\n     * @type number\n     * @default 1\n     */\n\n    /**\n     * A `Number` that defines the scaling in the y-axis for the sprite, if any.\n     *\n     * @property render.sprite.yScale\n     * @type number\n     * @default 1\n     */\n\n    /**\n      * A `Number` that defines the offset in the x-axis for the sprite (normalised by texture width).\n      *\n      * @property render.sprite.xOffset\n      * @type number\n      * @default 0\n      */\n\n    /**\n      * A `Number` that defines the offset in the y-axis for the sprite (normalised by texture height).\n      *\n      * @property render.sprite.yOffset\n      * @type number\n      * @default 0\n      */\n\n    /**\n     * A `Number` that defines the line width to use when rendering the body outline (if a sprite is not defined).\n     * A value of `0` means no outline will be rendered.\n     *\n     * @property render.lineWidth\n     * @type number\n     * @default 0\n     */\n\n    /**\n     * A `String` that defines the fill style to use when rendering the body (if a sprite is not defined).\n     * It is the same as when using a canvas, so it accepts CSS style property values.\n     *\n     * @property render.fillStyle\n     * @type string\n     * @default a random colour\n     */\n\n    /**\n     * A `String` that defines the stroke style to use when rendering the body outline (if a sprite is not defined).\n     * It is the same as when using a canvas, so it accepts CSS style property values.\n     *\n     * @property render.strokeStyle\n     * @type string\n     * @default a random colour\n     */\n\n    /**\n     * _Read only_. Calculated automatically when vertices are set.\n     * \n     * An array of unique axis vectors (edge normals) used for collision detection.\n     * These are automatically calculated when vertices are set.\n     * They are constantly updated by `Body.update` during the simulation.\n     *\n     * @readOnly\n     * @property axes\n     * @type vector[]\n     */\n     \n    /**\n     * _Read only_. Calculated automatically when vertices are set.\n     * \n     * A `Number` that measures the area of the body's convex hull.\n     * \n     * @readOnly\n     * @property area\n     * @type string\n     * @default \n     */\n\n    /**\n     * A `Bounds` object that defines the AABB region for the body.\n     * It is automatically calculated when vertices are set and constantly updated by `Body.update` during simulation.\n     * \n     * @property bounds\n     * @type bounds\n     */\n\n})();\n\n\n/***/ }),\n/* 5 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Events` module contains methods to fire and listen to events on other objects.\n*\n* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).\n*\n* @class Events\n*/\n\nvar Events = {};\n\nmodule.exports = Events;\n\nvar Common = __webpack_require__(0);\n\n(function() {\n\n    /**\n     * Subscribes a callback function to the given object's `eventName`.\n     * @method on\n     * @param {} object\n     * @param {string} eventNames\n     * @param {function} callback\n     */\n    Events.on = function(object, eventNames, callback) {\n        var names = eventNames.split(' '),\n            name;\n\n        for (var i = 0; i < names.length; i++) {\n            name = names[i];\n            object.events = object.events || {};\n            object.events[name] = object.events[name] || [];\n            object.events[name].push(callback);\n        }\n\n        return callback;\n    };\n\n    /**\n     * Removes the given event callback. If no callback, clears all callbacks in `eventNames`. If no `eventNames`, clears all events.\n     * @method off\n     * @param {} object\n     * @param {string} eventNames\n     * @param {function} callback\n     */\n    Events.off = function(object, eventNames, callback) {\n        if (!eventNames) {\n            object.events = {};\n            return;\n        }\n\n        // handle Events.off(object, callback)\n        if (typeof eventNames === 'function') {\n            callback = eventNames;\n            eventNames = Common.keys(object.events).join(' ');\n        }\n\n        var names = eventNames.split(' ');\n\n        for (var i = 0; i < names.length; i++) {\n            var callbacks = object.events[names[i]],\n                newCallbacks = [];\n\n            if (callback && callbacks) {\n                for (var j = 0; j < callbacks.length; j++) {\n                    if (callbacks[j] !== callback)\n                        newCallbacks.push(callbacks[j]);\n                }\n            }\n\n            object.events[names[i]] = newCallbacks;\n        }\n    };\n\n    /**\n     * Fires all the callbacks subscribed to the given object's `eventName`, in the order they subscribed, if any.\n     * @method trigger\n     * @param {} object\n     * @param {string} eventNames\n     * @param {} event\n     */\n    Events.trigger = function(object, eventNames, event) {\n        var names,\n            name,\n            callbacks,\n            eventClone;\n\n        var events = object.events;\n        \n        if (events && Common.keys(events).length > 0) {\n            if (!event)\n                event = {};\n\n            names = eventNames.split(' ');\n\n            for (var i = 0; i < names.length; i++) {\n                name = names[i];\n                callbacks = events[name];\n\n                if (callbacks) {\n                    eventClone = Common.clone(event, false);\n                    eventClone.name = name;\n                    eventClone.source = object;\n\n                    for (var j = 0; j < callbacks.length; j++) {\n                        callbacks[j].apply(object, [eventClone]);\n                    }\n                }\n            }\n        }\n    };\n\n})();\n\n\n/***/ }),\n/* 6 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* A composite is a collection of `Matter.Body`, `Matter.Constraint` and other `Matter.Composite` objects.\n*\n* They are a container that can represent complex objects made of multiple parts, even if they are not physically connected.\n* A composite could contain anything from a single body all the way up to a whole world.\n* \n* When making any changes to composites, use the included functions rather than changing their properties directly.\n*\n* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).\n*\n* @class Composite\n*/\n\nvar Composite = {};\n\nmodule.exports = Composite;\n\nvar Events = __webpack_require__(5);\nvar Common = __webpack_require__(0);\nvar Bounds = __webpack_require__(1);\nvar Body = __webpack_require__(4);\n\n(function() {\n\n    /**\n     * Creates a new composite. The options parameter is an object that specifies any properties you wish to override the defaults.\n     * See the properites section below for detailed information on what you can pass via the `options` object.\n     * @method create\n     * @param {} [options]\n     * @return {composite} A new composite\n     */\n    Composite.create = function(options) {\n        return Common.extend({ \n            id: Common.nextId(),\n            type: 'composite',\n            parent: null,\n            isModified: false,\n            bodies: [], \n            constraints: [], \n            composites: [],\n            label: 'Composite',\n            plugin: {},\n            cache: {\n                allBodies: null,\n                allConstraints: null,\n                allComposites: null\n            }\n        }, options);\n    };\n\n    /**\n     * Sets the composite's `isModified` flag. \n     * If `updateParents` is true, all parents will be set (default: false).\n     * If `updateChildren` is true, all children will be set (default: false).\n     * @private\n     * @method setModified\n     * @param {composite} composite\n     * @param {boolean} isModified\n     * @param {boolean} [updateParents=false]\n     * @param {boolean} [updateChildren=false]\n     */\n    Composite.setModified = function(composite, isModified, updateParents, updateChildren) {\n        composite.isModified = isModified;\n\n        if (isModified && composite.cache) {\n            composite.cache.allBodies = null;\n            composite.cache.allConstraints = null;\n            composite.cache.allComposites = null;\n        }\n\n        if (updateParents && composite.parent) {\n            Composite.setModified(composite.parent, isModified, updateParents, updateChildren);\n        }\n\n        if (updateChildren) {\n            for (var i = 0; i < composite.composites.length; i++) {\n                var childComposite = composite.composites[i];\n                Composite.setModified(childComposite, isModified, updateParents, updateChildren);\n            }\n        }\n    };\n\n    /**\n     * Generic single or multi-add function. Adds a single or an array of body(s), constraint(s) or composite(s) to the given composite.\n     * Triggers `beforeAdd` and `afterAdd` events on the `composite`.\n     * @method add\n     * @param {composite} composite\n     * @param {object|array} object A single or an array of body(s), constraint(s) or composite(s)\n     * @return {composite} The original composite with the objects added\n     */\n    Composite.add = function(composite, object) {\n        var objects = [].concat(object);\n\n        Events.trigger(composite, 'beforeAdd', { object: object });\n\n        for (var i = 0; i < objects.length; i++) {\n            var obj = objects[i];\n\n            switch (obj.type) {\n\n            case 'body':\n                // skip adding compound parts\n                if (obj.parent !== obj) {\n                    Common.warn('Composite.add: skipped adding a compound body part (you must add its parent instead)');\n                    break;\n                }\n\n                Composite.addBody(composite, obj);\n                break;\n            case 'constraint':\n                Composite.addConstraint(composite, obj);\n                break;\n            case 'composite':\n                Composite.addComposite(composite, obj);\n                break;\n            case 'mouseConstraint':\n                Composite.addConstraint(composite, obj.constraint);\n                break;\n\n            }\n        }\n\n        Events.trigger(composite, 'afterAdd', { object: object });\n\n        return composite;\n    };\n\n    /**\n     * Generic remove function. Removes one or many body(s), constraint(s) or a composite(s) to the given composite.\n     * Optionally searching its children recursively.\n     * Triggers `beforeRemove` and `afterRemove` events on the `composite`.\n     * @method remove\n     * @param {composite} composite\n     * @param {object|array} object\n     * @param {boolean} [deep=false]\n     * @return {composite} The original composite with the objects removed\n     */\n    Composite.remove = function(composite, object, deep) {\n        var objects = [].concat(object);\n\n        Events.trigger(composite, 'beforeRemove', { object: object });\n\n        for (var i = 0; i < objects.length; i++) {\n            var obj = objects[i];\n\n            switch (obj.type) {\n\n            case 'body':\n                Composite.removeBody(composite, obj, deep);\n                break;\n            case 'constraint':\n                Composite.removeConstraint(composite, obj, deep);\n                break;\n            case 'composite':\n                Composite.removeComposite(composite, obj, deep);\n                break;\n            case 'mouseConstraint':\n                Composite.removeConstraint(composite, obj.constraint);\n                break;\n\n            }\n        }\n\n        Events.trigger(composite, 'afterRemove', { object: object });\n\n        return composite;\n    };\n\n    /**\n     * Adds a composite to the given composite.\n     * @private\n     * @method addComposite\n     * @param {composite} compositeA\n     * @param {composite} compositeB\n     * @return {composite} The original compositeA with the objects from compositeB added\n     */\n    Composite.addComposite = function(compositeA, compositeB) {\n        compositeA.composites.push(compositeB);\n        compositeB.parent = compositeA;\n        Composite.setModified(compositeA, true, true, false);\n        return compositeA;\n    };\n\n    /**\n     * Removes a composite from the given composite, and optionally searching its children recursively.\n     * @private\n     * @method removeComposite\n     * @param {composite} compositeA\n     * @param {composite} compositeB\n     * @param {boolean} [deep=false]\n     * @return {composite} The original compositeA with the composite removed\n     */\n    Composite.removeComposite = function(compositeA, compositeB, deep) {\n        var position = Common.indexOf(compositeA.composites, compositeB);\n        if (position !== -1) {\n            Composite.removeCompositeAt(compositeA, position);\n        }\n\n        if (deep) {\n            for (var i = 0; i < compositeA.composites.length; i++){\n                Composite.removeComposite(compositeA.composites[i], compositeB, true);\n            }\n        }\n\n        return compositeA;\n    };\n\n    /**\n     * Removes a composite from the given composite.\n     * @private\n     * @method removeCompositeAt\n     * @param {composite} composite\n     * @param {number} position\n     * @return {composite} The original composite with the composite removed\n     */\n    Composite.removeCompositeAt = function(composite, position) {\n        composite.composites.splice(position, 1);\n        Composite.setModified(composite, true, true, false);\n        return composite;\n    };\n\n    /**\n     * Adds a body to the given composite.\n     * @private\n     * @method addBody\n     * @param {composite} composite\n     * @param {body} body\n     * @return {composite} The original composite with the body added\n     */\n    Composite.addBody = function(composite, body) {\n        composite.bodies.push(body);\n        Composite.setModified(composite, true, true, false);\n        return composite;\n    };\n\n    /**\n     * Removes a body from the given composite, and optionally searching its children recursively.\n     * @private\n     * @method removeBody\n     * @param {composite} composite\n     * @param {body} body\n     * @param {boolean} [deep=false]\n     * @return {composite} The original composite with the body removed\n     */\n    Composite.removeBody = function(composite, body, deep) {\n        var position = Common.indexOf(composite.bodies, body);\n        if (position !== -1) {\n            Composite.removeBodyAt(composite, position);\n        }\n\n        if (deep) {\n            for (var i = 0; i < composite.composites.length; i++){\n                Composite.removeBody(composite.composites[i], body, true);\n            }\n        }\n\n        return composite;\n    };\n\n    /**\n     * Removes a body from the given composite.\n     * @private\n     * @method removeBodyAt\n     * @param {composite} composite\n     * @param {number} position\n     * @return {composite} The original composite with the body removed\n     */\n    Composite.removeBodyAt = function(composite, position) {\n        composite.bodies.splice(position, 1);\n        Composite.setModified(composite, true, true, false);\n        return composite;\n    };\n\n    /**\n     * Adds a constraint to the given composite.\n     * @private\n     * @method addConstraint\n     * @param {composite} composite\n     * @param {constraint} constraint\n     * @return {composite} The original composite with the constraint added\n     */\n    Composite.addConstraint = function(composite, constraint) {\n        composite.constraints.push(constraint);\n        Composite.setModified(composite, true, true, false);\n        return composite;\n    };\n\n    /**\n     * Removes a constraint from the given composite, and optionally searching its children recursively.\n     * @private\n     * @method removeConstraint\n     * @param {composite} composite\n     * @param {constraint} constraint\n     * @param {boolean} [deep=false]\n     * @return {composite} The original composite with the constraint removed\n     */\n    Composite.removeConstraint = function(composite, constraint, deep) {\n        var position = Common.indexOf(composite.constraints, constraint);\n        if (position !== -1) {\n            Composite.removeConstraintAt(composite, position);\n        }\n\n        if (deep) {\n            for (var i = 0; i < composite.composites.length; i++){\n                Composite.removeConstraint(composite.composites[i], constraint, true);\n            }\n        }\n\n        return composite;\n    };\n\n    /**\n     * Removes a body from the given composite.\n     * @private\n     * @method removeConstraintAt\n     * @param {composite} composite\n     * @param {number} position\n     * @return {composite} The original composite with the constraint removed\n     */\n    Composite.removeConstraintAt = function(composite, position) {\n        composite.constraints.splice(position, 1);\n        Composite.setModified(composite, true, true, false);\n        return composite;\n    };\n\n    /**\n     * Removes all bodies, constraints and composites from the given composite.\n     * Optionally clearing its children recursively.\n     * @method clear\n     * @param {composite} composite\n     * @param {boolean} keepStatic\n     * @param {boolean} [deep=false]\n     */\n    Composite.clear = function(composite, keepStatic, deep) {\n        if (deep) {\n            for (var i = 0; i < composite.composites.length; i++){\n                Composite.clear(composite.composites[i], keepStatic, true);\n            }\n        }\n        \n        if (keepStatic) {\n            composite.bodies = composite.bodies.filter(function(body) { return body.isStatic; });\n        } else {\n            composite.bodies.length = 0;\n        }\n\n        composite.constraints.length = 0;\n        composite.composites.length = 0;\n\n        Composite.setModified(composite, true, true, false);\n\n        return composite;\n    };\n\n    /**\n     * Returns all bodies in the given composite, including all bodies in its children, recursively.\n     * @method allBodies\n     * @param {composite} composite\n     * @return {body[]} All the bodies\n     */\n    Composite.allBodies = function(composite) {\n        if (composite.cache && composite.cache.allBodies) {\n            return composite.cache.allBodies;\n        }\n\n        var bodies = [].concat(composite.bodies);\n\n        for (var i = 0; i < composite.composites.length; i++)\n            bodies = bodies.concat(Composite.allBodies(composite.composites[i]));\n\n        if (composite.cache) {\n            composite.cache.allBodies = bodies;\n        }\n\n        return bodies;\n    };\n\n    /**\n     * Returns all constraints in the given composite, including all constraints in its children, recursively.\n     * @method allConstraints\n     * @param {composite} composite\n     * @return {constraint[]} All the constraints\n     */\n    Composite.allConstraints = function(composite) {\n        if (composite.cache && composite.cache.allConstraints) {\n            return composite.cache.allConstraints;\n        }\n\n        var constraints = [].concat(composite.constraints);\n\n        for (var i = 0; i < composite.composites.length; i++)\n            constraints = constraints.concat(Composite.allConstraints(composite.composites[i]));\n\n        if (composite.cache) {\n            composite.cache.allConstraints = constraints;\n        }\n\n        return constraints;\n    };\n\n    /**\n     * Returns all composites in the given composite, including all composites in its children, recursively.\n     * @method allComposites\n     * @param {composite} composite\n     * @return {composite[]} All the composites\n     */\n    Composite.allComposites = function(composite) {\n        if (composite.cache && composite.cache.allComposites) {\n            return composite.cache.allComposites;\n        }\n\n        var composites = [].concat(composite.composites);\n\n        for (var i = 0; i < composite.composites.length; i++)\n            composites = composites.concat(Composite.allComposites(composite.composites[i]));\n\n        if (composite.cache) {\n            composite.cache.allComposites = composites;\n        }\n\n        return composites;\n    };\n\n    /**\n     * Searches the composite recursively for an object matching the type and id supplied, null if not found.\n     * @method get\n     * @param {composite} composite\n     * @param {number} id\n     * @param {string} type\n     * @return {object} The requested object, if found\n     */\n    Composite.get = function(composite, id, type) {\n        var objects,\n            object;\n\n        switch (type) {\n        case 'body':\n            objects = Composite.allBodies(composite);\n            break;\n        case 'constraint':\n            objects = Composite.allConstraints(composite);\n            break;\n        case 'composite':\n            objects = Composite.allComposites(composite).concat(composite);\n            break;\n        }\n\n        if (!objects)\n            return null;\n\n        object = objects.filter(function(object) { \n            return object.id.toString() === id.toString(); \n        });\n\n        return object.length === 0 ? null : object[0];\n    };\n\n    /**\n     * Moves the given object(s) from compositeA to compositeB (equal to a remove followed by an add).\n     * @method move\n     * @param {compositeA} compositeA\n     * @param {object[]} objects\n     * @param {compositeB} compositeB\n     * @return {composite} Returns compositeA\n     */\n    Composite.move = function(compositeA, objects, compositeB) {\n        Composite.remove(compositeA, objects);\n        Composite.add(compositeB, objects);\n        return compositeA;\n    };\n\n    /**\n     * Assigns new ids for all objects in the composite, recursively.\n     * @method rebase\n     * @param {composite} composite\n     * @return {composite} Returns composite\n     */\n    Composite.rebase = function(composite) {\n        var objects = Composite.allBodies(composite)\n            .concat(Composite.allConstraints(composite))\n            .concat(Composite.allComposites(composite));\n\n        for (var i = 0; i < objects.length; i++) {\n            objects[i].id = Common.nextId();\n        }\n\n        return composite;\n    };\n\n    /**\n     * Translates all children in the composite by a given vector relative to their current positions, \n     * without imparting any velocity.\n     * @method translate\n     * @param {composite} composite\n     * @param {vector} translation\n     * @param {bool} [recursive=true]\n     */\n    Composite.translate = function(composite, translation, recursive) {\n        var bodies = recursive ? Composite.allBodies(composite) : composite.bodies;\n\n        for (var i = 0; i < bodies.length; i++) {\n            Body.translate(bodies[i], translation);\n        }\n\n        return composite;\n    };\n\n    /**\n     * Rotates all children in the composite by a given angle about the given point, without imparting any angular velocity.\n     * @method rotate\n     * @param {composite} composite\n     * @param {number} rotation\n     * @param {vector} point\n     * @param {bool} [recursive=true]\n     */\n    Composite.rotate = function(composite, rotation, point, recursive) {\n        var cos = Math.cos(rotation),\n            sin = Math.sin(rotation),\n            bodies = recursive ? Composite.allBodies(composite) : composite.bodies;\n\n        for (var i = 0; i < bodies.length; i++) {\n            var body = bodies[i],\n                dx = body.position.x - point.x,\n                dy = body.position.y - point.y;\n                \n            Body.setPosition(body, {\n                x: point.x + (dx * cos - dy * sin),\n                y: point.y + (dx * sin + dy * cos)\n            });\n\n            Body.rotate(body, rotation);\n        }\n\n        return composite;\n    };\n\n    /**\n     * Scales all children in the composite, including updating physical properties (mass, area, axes, inertia), from a world-space point.\n     * @method scale\n     * @param {composite} composite\n     * @param {number} scaleX\n     * @param {number} scaleY\n     * @param {vector} point\n     * @param {bool} [recursive=true]\n     */\n    Composite.scale = function(composite, scaleX, scaleY, point, recursive) {\n        var bodies = recursive ? Composite.allBodies(composite) : composite.bodies;\n\n        for (var i = 0; i < bodies.length; i++) {\n            var body = bodies[i],\n                dx = body.position.x - point.x,\n                dy = body.position.y - point.y;\n                \n            Body.setPosition(body, {\n                x: point.x + dx * scaleX,\n                y: point.y + dy * scaleY\n            });\n\n            Body.scale(body, scaleX, scaleY);\n        }\n\n        return composite;\n    };\n\n    /**\n     * Returns the union of the bounds of all of the composite's bodies.\n     * @method bounds\n     * @param {composite} composite The composite.\n     * @returns {bounds} The composite bounds.\n     */\n    Composite.bounds = function(composite) {\n        var bodies = Composite.allBodies(composite),\n            vertices = [];\n\n        for (var i = 0; i < bodies.length; i += 1) {\n            var body = bodies[i];\n            vertices.push(body.bounds.min, body.bounds.max);\n        }\n\n        return Bounds.create(vertices);\n    };\n\n    /*\n    *\n    *  Events Documentation\n    *\n    */\n\n    /**\n    * Fired when a call to `Composite.add` is made, before objects have been added.\n    *\n    * @event beforeAdd\n    * @param {} event An event object\n    * @param {} event.object The object(s) to be added (may be a single body, constraint, composite or a mixed array of these)\n    * @param {} event.source The source object of the event\n    * @param {} event.name The name of the event\n    */\n\n    /**\n    * Fired when a call to `Composite.add` is made, after objects have been added.\n    *\n    * @event afterAdd\n    * @param {} event An event object\n    * @param {} event.object The object(s) that have been added (may be a single body, constraint, composite or a mixed array of these)\n    * @param {} event.source The source object of the event\n    * @param {} event.name The name of the event\n    */\n\n    /**\n    * Fired when a call to `Composite.remove` is made, before objects have been removed.\n    *\n    * @event beforeRemove\n    * @param {} event An event object\n    * @param {} event.object The object(s) to be removed (may be a single body, constraint, composite or a mixed array of these)\n    * @param {} event.source The source object of the event\n    * @param {} event.name The name of the event\n    */\n\n    /**\n    * Fired when a call to `Composite.remove` is made, after objects have been removed.\n    *\n    * @event afterRemove\n    * @param {} event An event object\n    * @param {} event.object The object(s) that have been removed (may be a single body, constraint, composite or a mixed array of these)\n    * @param {} event.source The source object of the event\n    * @param {} event.name The name of the event\n    */\n\n    /*\n    *\n    *  Properties Documentation\n    *\n    */\n\n    /**\n     * An integer `Number` uniquely identifying number generated in `Composite.create` by `Common.nextId`.\n     *\n     * @property id\n     * @type number\n     */\n\n    /**\n     * A `String` denoting the type of object.\n     *\n     * @property type\n     * @type string\n     * @default \"composite\"\n     * @readOnly\n     */\n\n    /**\n     * An arbitrary `String` name to help the user identify and manage composites.\n     *\n     * @property label\n     * @type string\n     * @default \"Composite\"\n     */\n\n    /**\n     * A flag that specifies whether the composite has been modified during the current step.\n     * This is automatically managed when bodies, constraints or composites are added or removed.\n     *\n     * @property isModified\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * The `Composite` that is the parent of this composite. It is automatically managed by the `Matter.Composite` methods.\n     *\n     * @property parent\n     * @type composite\n     * @default null\n     */\n\n    /**\n     * An array of `Body` that are _direct_ children of this composite.\n     * To add or remove bodies you should use `Composite.add` and `Composite.remove` methods rather than directly modifying this property.\n     * If you wish to recursively find all descendants, you should use the `Composite.allBodies` method.\n     *\n     * @property bodies\n     * @type body[]\n     * @default []\n     */\n\n    /**\n     * An array of `Constraint` that are _direct_ children of this composite.\n     * To add or remove constraints you should use `Composite.add` and `Composite.remove` methods rather than directly modifying this property.\n     * If you wish to recursively find all descendants, you should use the `Composite.allConstraints` method.\n     *\n     * @property constraints\n     * @type constraint[]\n     * @default []\n     */\n\n    /**\n     * An array of `Composite` that are _direct_ children of this composite.\n     * To add or remove composites you should use `Composite.add` and `Composite.remove` methods rather than directly modifying this property.\n     * If you wish to recursively find all descendants, you should use the `Composite.allComposites` method.\n     *\n     * @property composites\n     * @type composite[]\n     * @default []\n     */\n\n    /**\n     * An object reserved for storing plugin-specific properties.\n     *\n     * @property plugin\n     * @type {}\n     */\n\n    /**\n     * An object used for storing cached results for performance reasons.\n     * This is used internally only and is automatically managed.\n     *\n     * @private\n     * @property cache\n     * @type {}\n     */\n\n})();\n\n\n/***/ }),\n/* 7 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Sleeping` module contains methods to manage the sleeping state of bodies.\n*\n* @class Sleeping\n*/\n\nvar Sleeping = {};\n\nmodule.exports = Sleeping;\n\nvar Body = __webpack_require__(4);\nvar Events = __webpack_require__(5);\nvar Common = __webpack_require__(0);\n\n(function() {\n\n    Sleeping._motionWakeThreshold = 0.18;\n    Sleeping._motionSleepThreshold = 0.08;\n    Sleeping._minBias = 0.9;\n\n    /**\n     * Puts bodies to sleep or wakes them up depending on their motion.\n     * @method update\n     * @param {body[]} bodies\n     * @param {number} delta\n     */\n    Sleeping.update = function(bodies, delta) {\n        var timeScale = delta / Common._baseDelta,\n            motionSleepThreshold = Sleeping._motionSleepThreshold;\n        \n        // update bodies sleeping status\n        for (var i = 0; i < bodies.length; i++) {\n            var body = bodies[i],\n                speed = Body.getSpeed(body),\n                angularSpeed = Body.getAngularSpeed(body),\n                motion = speed * speed + angularSpeed * angularSpeed;\n\n            // wake up bodies if they have a force applied\n            if (body.force.x !== 0 || body.force.y !== 0) {\n                Sleeping.set(body, false);\n                continue;\n            }\n\n            var minMotion = Math.min(body.motion, motion),\n                maxMotion = Math.max(body.motion, motion);\n        \n            // biased average motion estimation between frames\n            body.motion = Sleeping._minBias * minMotion + (1 - Sleeping._minBias) * maxMotion;\n\n            if (body.sleepThreshold > 0 && body.motion < motionSleepThreshold) {\n                body.sleepCounter += 1;\n                \n                if (body.sleepCounter >= body.sleepThreshold / timeScale) {\n                    Sleeping.set(body, true);\n                }\n            } else if (body.sleepCounter > 0) {\n                body.sleepCounter -= 1;\n            }\n        }\n    };\n\n    /**\n     * Given a set of colliding pairs, wakes the sleeping bodies involved.\n     * @method afterCollisions\n     * @param {pair[]} pairs\n     */\n    Sleeping.afterCollisions = function(pairs) {\n        var motionSleepThreshold = Sleeping._motionSleepThreshold;\n\n        // wake up bodies involved in collisions\n        for (var i = 0; i < pairs.length; i++) {\n            var pair = pairs[i];\n            \n            // don't wake inactive pairs\n            if (!pair.isActive)\n                continue;\n\n            var collision = pair.collision,\n                bodyA = collision.bodyA.parent, \n                bodyB = collision.bodyB.parent;\n        \n            // don't wake if at least one body is static\n            if ((bodyA.isSleeping && bodyB.isSleeping) || bodyA.isStatic || bodyB.isStatic)\n                continue;\n        \n            if (bodyA.isSleeping || bodyB.isSleeping) {\n                var sleepingBody = (bodyA.isSleeping && !bodyA.isStatic) ? bodyA : bodyB,\n                    movingBody = sleepingBody === bodyA ? bodyB : bodyA;\n\n                if (!sleepingBody.isStatic && movingBody.motion > motionSleepThreshold) {\n                    Sleeping.set(sleepingBody, false);\n                }\n            }\n        }\n    };\n  \n    /**\n     * Set a body as sleeping or awake.\n     * @method set\n     * @param {body} body\n     * @param {boolean} isSleeping\n     */\n    Sleeping.set = function(body, isSleeping) {\n        var wasSleeping = body.isSleeping;\n\n        if (isSleeping) {\n            body.isSleeping = true;\n            body.sleepCounter = body.sleepThreshold;\n\n            body.positionImpulse.x = 0;\n            body.positionImpulse.y = 0;\n\n            body.positionPrev.x = body.position.x;\n            body.positionPrev.y = body.position.y;\n\n            body.anglePrev = body.angle;\n            body.speed = 0;\n            body.angularSpeed = 0;\n            body.motion = 0;\n\n            if (!wasSleeping) {\n                Events.trigger(body, 'sleepStart');\n            }\n        } else {\n            body.isSleeping = false;\n            body.sleepCounter = 0;\n\n            if (wasSleeping) {\n                Events.trigger(body, 'sleepEnd');\n            }\n        }\n    };\n\n})();\n\n\n/***/ }),\n/* 8 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Collision` module contains methods for detecting collisions between a given pair of bodies.\n*\n* For efficient detection between a list of bodies, see `Matter.Detector` and `Matter.Query`.\n*\n* See `Matter.Engine` for collision events.\n*\n* @class Collision\n*/\n\nvar Collision = {};\n\nmodule.exports = Collision;\n\nvar Vertices = __webpack_require__(3);\nvar Pair = __webpack_require__(9);\n\n(function() {\n    var _supports = [];\n\n    var _overlapAB = {\n        overlap: 0,\n        axis: null\n    };\n\n    var _overlapBA = {\n        overlap: 0,\n        axis: null\n    };\n\n    /**\n     * Creates a new collision record.\n     * @method create\n     * @param {body} bodyA The first body part represented by the collision record\n     * @param {body} bodyB The second body part represented by the collision record\n     * @return {collision} A new collision record\n     */\n    Collision.create = function(bodyA, bodyB) {\n        return { \n            pair: null,\n            collided: false,\n            bodyA: bodyA,\n            bodyB: bodyB,\n            parentA: bodyA.parent,\n            parentB: bodyB.parent,\n            depth: 0,\n            normal: { x: 0, y: 0 },\n            tangent: { x: 0, y: 0 },\n            penetration: { x: 0, y: 0 },\n            supports: []\n        };\n    };\n\n    /**\n     * Detect collision between two bodies.\n     * @method collides\n     * @param {body} bodyA\n     * @param {body} bodyB\n     * @param {pairs} [pairs] Optionally reuse collision records from existing pairs.\n     * @return {collision|null} A collision record if detected, otherwise null\n     */\n    Collision.collides = function(bodyA, bodyB, pairs) {\n        Collision._overlapAxes(_overlapAB, bodyA.vertices, bodyB.vertices, bodyA.axes);\n\n        if (_overlapAB.overlap <= 0) {\n            return null;\n        }\n\n        Collision._overlapAxes(_overlapBA, bodyB.vertices, bodyA.vertices, bodyB.axes);\n\n        if (_overlapBA.overlap <= 0) {\n            return null;\n        }\n\n        // reuse collision records for gc efficiency\n        var pair = pairs && pairs.table[Pair.id(bodyA, bodyB)],\n            collision;\n\n        if (!pair) {\n            collision = Collision.create(bodyA, bodyB);\n            collision.collided = true;\n            collision.bodyA = bodyA.id < bodyB.id ? bodyA : bodyB;\n            collision.bodyB = bodyA.id < bodyB.id ? bodyB : bodyA;\n            collision.parentA = collision.bodyA.parent;\n            collision.parentB = collision.bodyB.parent;\n        } else {\n            collision = pair.collision;\n        }\n\n        bodyA = collision.bodyA;\n        bodyB = collision.bodyB;\n\n        var minOverlap;\n\n        if (_overlapAB.overlap < _overlapBA.overlap) {\n            minOverlap = _overlapAB;\n        } else {\n            minOverlap = _overlapBA;\n        }\n\n        var normal = collision.normal,\n            supports = collision.supports,\n            minAxis = minOverlap.axis,\n            minAxisX = minAxis.x,\n            minAxisY = minAxis.y;\n\n        // ensure normal is facing away from bodyA\n        if (minAxisX * (bodyB.position.x - bodyA.position.x) + minAxisY * (bodyB.position.y - bodyA.position.y) < 0) {\n            normal.x = minAxisX;\n            normal.y = minAxisY;\n        } else {\n            normal.x = -minAxisX;\n            normal.y = -minAxisY;\n        }\n        \n        collision.tangent.x = -normal.y;\n        collision.tangent.y = normal.x;\n\n        collision.depth = minOverlap.overlap;\n\n        collision.penetration.x = normal.x * collision.depth;\n        collision.penetration.y = normal.y * collision.depth;\n\n        // find support points, there is always either exactly one or two\n        var supportsB = Collision._findSupports(bodyA, bodyB, normal, 1),\n            supportCount = 0;\n\n        // find the supports from bodyB that are inside bodyA\n        if (Vertices.contains(bodyA.vertices, supportsB[0])) {\n            supports[supportCount++] = supportsB[0];\n        }\n\n        if (Vertices.contains(bodyA.vertices, supportsB[1])) {\n            supports[supportCount++] = supportsB[1];\n        }\n\n        // find the supports from bodyA that are inside bodyB\n        if (supportCount < 2) {\n            var supportsA = Collision._findSupports(bodyB, bodyA, normal, -1);\n\n            if (Vertices.contains(bodyB.vertices, supportsA[0])) {\n                supports[supportCount++] = supportsA[0];\n            }\n\n            if (supportCount < 2 && Vertices.contains(bodyB.vertices, supportsA[1])) {\n                supports[supportCount++] = supportsA[1];\n            }\n        }\n\n        // account for the edge case of overlapping but no vertex containment\n        if (supportCount === 0) {\n            supports[supportCount++] = supportsB[0];\n        }\n\n        // update supports array size\n        supports.length = supportCount;\n\n        return collision;\n    };\n\n    /**\n     * Find the overlap between two sets of vertices.\n     * @method _overlapAxes\n     * @private\n     * @param {object} result\n     * @param {vertices} verticesA\n     * @param {vertices} verticesB\n     * @param {axes} axes\n     */\n    Collision._overlapAxes = function(result, verticesA, verticesB, axes) {\n        var verticesALength = verticesA.length,\n            verticesBLength = verticesB.length,\n            verticesAX = verticesA[0].x,\n            verticesAY = verticesA[0].y,\n            verticesBX = verticesB[0].x,\n            verticesBY = verticesB[0].y,\n            axesLength = axes.length,\n            overlapMin = Number.MAX_VALUE,\n            overlapAxisNumber = 0,\n            overlap,\n            overlapAB,\n            overlapBA,\n            dot,\n            i,\n            j;\n\n        for (i = 0; i < axesLength; i++) {\n            var axis = axes[i],\n                axisX = axis.x,\n                axisY = axis.y,\n                minA = verticesAX * axisX + verticesAY * axisY,\n                minB = verticesBX * axisX + verticesBY * axisY,\n                maxA = minA,\n                maxB = minB;\n            \n            for (j = 1; j < verticesALength; j += 1) {\n                dot = verticesA[j].x * axisX + verticesA[j].y * axisY;\n\n                if (dot > maxA) { \n                    maxA = dot;\n                } else if (dot < minA) { \n                    minA = dot;\n                }\n            }\n\n            for (j = 1; j < verticesBLength; j += 1) {\n                dot = verticesB[j].x * axisX + verticesB[j].y * axisY;\n\n                if (dot > maxB) { \n                    maxB = dot;\n                } else if (dot < minB) { \n                    minB = dot;\n                }\n            }\n\n            overlapAB = maxA - minB;\n            overlapBA = maxB - minA;\n            overlap = overlapAB < overlapBA ? overlapAB : overlapBA;\n\n            if (overlap < overlapMin) {\n                overlapMin = overlap;\n                overlapAxisNumber = i;\n\n                if (overlap <= 0) {\n                    // can not be intersecting\n                    break;\n                }\n            } \n        }\n\n        result.axis = axes[overlapAxisNumber];\n        result.overlap = overlapMin;\n    };\n\n    /**\n     * Projects vertices on an axis and returns an interval.\n     * @method _projectToAxis\n     * @private\n     * @param {} projection\n     * @param {} vertices\n     * @param {} axis\n     */\n    Collision._projectToAxis = function(projection, vertices, axis) {\n        var min = vertices[0].x * axis.x + vertices[0].y * axis.y,\n            max = min;\n\n        for (var i = 1; i < vertices.length; i += 1) {\n            var dot = vertices[i].x * axis.x + vertices[i].y * axis.y;\n\n            if (dot > max) { \n                max = dot; \n            } else if (dot < min) { \n                min = dot; \n            }\n        }\n\n        projection.min = min;\n        projection.max = max;\n    };\n\n    /**\n     * Finds supporting vertices given two bodies along a given direction using hill-climbing.\n     * @method _findSupports\n     * @private\n     * @param {body} bodyA\n     * @param {body} bodyB\n     * @param {vector} normal\n     * @param {number} direction\n     * @return [vector]\n     */\n    Collision._findSupports = function(bodyA, bodyB, normal, direction) {\n        var vertices = bodyB.vertices,\n            verticesLength = vertices.length,\n            bodyAPositionX = bodyA.position.x,\n            bodyAPositionY = bodyA.position.y,\n            normalX = normal.x * direction,\n            normalY = normal.y * direction,\n            nearestDistance = Number.MAX_VALUE,\n            vertexA,\n            vertexB,\n            vertexC,\n            distance,\n            j;\n\n        // find deepest vertex relative to the axis\n        for (j = 0; j < verticesLength; j += 1) {\n            vertexB = vertices[j];\n            distance = normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y);\n\n            // convex hill-climbing\n            if (distance < nearestDistance) {\n                nearestDistance = distance;\n                vertexA = vertexB;\n            }\n        }\n\n        // measure next vertex\n        vertexC = vertices[(verticesLength + vertexA.index - 1) % verticesLength];\n        nearestDistance = normalX * (bodyAPositionX - vertexC.x) + normalY * (bodyAPositionY - vertexC.y);\n\n        // compare with previous vertex\n        vertexB = vertices[(vertexA.index + 1) % verticesLength];\n        if (normalX * (bodyAPositionX - vertexB.x) + normalY * (bodyAPositionY - vertexB.y) < nearestDistance) {\n            _supports[0] = vertexA;\n            _supports[1] = vertexB;\n\n            return _supports;\n        }\n\n        _supports[0] = vertexA;\n        _supports[1] = vertexC;\n\n        return _supports;\n    };\n\n    /*\n    *\n    *  Properties Documentation\n    *\n    */\n\n    /**\n     * A reference to the pair using this collision record, if there is one.\n     *\n     * @property pair\n     * @type {pair|null}\n     * @default null\n     */\n\n    /**\n     * A flag that indicates if the bodies were colliding when the collision was last updated.\n     * \n     * @property collided\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * The first body part represented by the collision (see also `collision.parentA`).\n     * \n     * @property bodyA\n     * @type body\n     */\n\n    /**\n     * The second body part represented by the collision (see also `collision.parentB`).\n     * \n     * @property bodyB\n     * @type body\n     */\n\n    /**\n     * The first body represented by the collision (i.e. `collision.bodyA.parent`).\n     * \n     * @property parentA\n     * @type body\n     */\n\n    /**\n     * The second body represented by the collision (i.e. `collision.bodyB.parent`).\n     * \n     * @property parentB\n     * @type body\n     */\n\n    /**\n     * A `Number` that represents the minimum separating distance between the bodies along the collision normal.\n     *\n     * @readOnly\n     * @property depth\n     * @type number\n     * @default 0\n     */\n\n    /**\n     * A normalised `Vector` that represents the direction between the bodies that provides the minimum separating distance.\n     *\n     * @property normal\n     * @type vector\n     * @default { x: 0, y: 0 }\n     */\n\n    /**\n     * A normalised `Vector` that is the tangent direction to the collision normal.\n     *\n     * @property tangent\n     * @type vector\n     * @default { x: 0, y: 0 }\n     */\n\n    /**\n     * A `Vector` that represents the direction and depth of the collision.\n     *\n     * @property penetration\n     * @type vector\n     * @default { x: 0, y: 0 }\n     */\n\n    /**\n     * An array of body vertices that represent the support points in the collision.\n     * These are the deepest vertices (along the collision normal) of each body that are contained by the other body's vertices.\n     *\n     * @property supports\n     * @type vector[]\n     * @default []\n     */\n\n})();\n\n\n/***/ }),\n/* 9 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Pair` module contains methods for creating and manipulating collision pairs.\n*\n* @class Pair\n*/\n\nvar Pair = {};\n\nmodule.exports = Pair;\n\nvar Contact = __webpack_require__(16);\n\n(function() {\n    \n    /**\n     * Creates a pair.\n     * @method create\n     * @param {collision} collision\n     * @param {number} timestamp\n     * @return {pair} A new pair\n     */\n    Pair.create = function(collision, timestamp) {\n        var bodyA = collision.bodyA,\n            bodyB = collision.bodyB;\n\n        var pair = {\n            id: Pair.id(bodyA, bodyB),\n            bodyA: bodyA,\n            bodyB: bodyB,\n            collision: collision,\n            contacts: [],\n            activeContacts: [],\n            separation: 0,\n            isActive: true,\n            confirmedActive: true,\n            isSensor: bodyA.isSensor || bodyB.isSensor,\n            timeCreated: timestamp,\n            timeUpdated: timestamp,\n            inverseMass: 0,\n            friction: 0,\n            frictionStatic: 0,\n            restitution: 0,\n            slop: 0\n        };\n\n        Pair.update(pair, collision, timestamp);\n\n        return pair;\n    };\n\n    /**\n     * Updates a pair given a collision.\n     * @method update\n     * @param {pair} pair\n     * @param {collision} collision\n     * @param {number} timestamp\n     */\n    Pair.update = function(pair, collision, timestamp) {\n        var contacts = pair.contacts,\n            supports = collision.supports,\n            activeContacts = pair.activeContacts,\n            parentA = collision.parentA,\n            parentB = collision.parentB,\n            parentAVerticesLength = parentA.vertices.length;\n        \n        pair.isActive = true;\n        pair.timeUpdated = timestamp;\n        pair.collision = collision;\n        pair.separation = collision.depth;\n        pair.inverseMass = parentA.inverseMass + parentB.inverseMass;\n        pair.friction = parentA.friction < parentB.friction ? parentA.friction : parentB.friction;\n        pair.frictionStatic = parentA.frictionStatic > parentB.frictionStatic ? parentA.frictionStatic : parentB.frictionStatic;\n        pair.restitution = parentA.restitution > parentB.restitution ? parentA.restitution : parentB.restitution;\n        pair.slop = parentA.slop > parentB.slop ? parentA.slop : parentB.slop;\n\n        collision.pair = pair;\n        activeContacts.length = 0;\n        \n        for (var i = 0; i < supports.length; i++) {\n            var support = supports[i],\n                contactId = support.body === parentA ? support.index : parentAVerticesLength + support.index,\n                contact = contacts[contactId];\n\n            if (contact) {\n                activeContacts.push(contact);\n            } else {\n                activeContacts.push(contacts[contactId] = Contact.create(support));\n            }\n        }\n    };\n    \n    /**\n     * Set a pair as active or inactive.\n     * @method setActive\n     * @param {pair} pair\n     * @param {bool} isActive\n     * @param {number} timestamp\n     */\n    Pair.setActive = function(pair, isActive, timestamp) {\n        if (isActive) {\n            pair.isActive = true;\n            pair.timeUpdated = timestamp;\n        } else {\n            pair.isActive = false;\n            pair.activeContacts.length = 0;\n        }\n    };\n\n    /**\n     * Get the id for the given pair.\n     * @method id\n     * @param {body} bodyA\n     * @param {body} bodyB\n     * @return {string} Unique pairId\n     */\n    Pair.id = function(bodyA, bodyB) {\n        if (bodyA.id < bodyB.id) {\n            return 'A' + bodyA.id + 'B' + bodyB.id;\n        } else {\n            return 'A' + bodyB.id + 'B' + bodyA.id;\n        }\n    };\n\n})();\n\n\n/***/ }),\n/* 10 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Constraint` module contains methods for creating and manipulating constraints.\n* Constraints are used for specifying that a fixed distance must be maintained between two bodies (or a body and a fixed world-space position).\n* The stiffness of constraints can be modified to create springs or elastic.\n*\n* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).\n*\n* @class Constraint\n*/\n\nvar Constraint = {};\n\nmodule.exports = Constraint;\n\nvar Vertices = __webpack_require__(3);\nvar Vector = __webpack_require__(2);\nvar Sleeping = __webpack_require__(7);\nvar Bounds = __webpack_require__(1);\nvar Axes = __webpack_require__(11);\nvar Common = __webpack_require__(0);\n\n(function() {\n\n    Constraint._warming = 0.4;\n    Constraint._torqueDampen = 1;\n    Constraint._minLength = 0.000001;\n\n    /**\n     * Creates a new constraint.\n     * All properties have default values, and many are pre-calculated automatically based on other properties.\n     * To simulate a revolute constraint (or pin joint) set `length: 0` and a high `stiffness` value (e.g. `0.7` or above).\n     * If the constraint is unstable, try lowering the `stiffness` value and / or increasing `engine.constraintIterations`.\n     * For compound bodies, constraints must be applied to the parent body (not one of its parts).\n     * See the properties section below for detailed information on what you can pass via the `options` object.\n     * @method create\n     * @param {} options\n     * @return {constraint} constraint\n     */\n    Constraint.create = function(options) {\n        var constraint = options;\n\n        // if bodies defined but no points, use body centre\n        if (constraint.bodyA && !constraint.pointA)\n            constraint.pointA = { x: 0, y: 0 };\n        if (constraint.bodyB && !constraint.pointB)\n            constraint.pointB = { x: 0, y: 0 };\n\n        // calculate static length using initial world space points\n        var initialPointA = constraint.bodyA ? Vector.add(constraint.bodyA.position, constraint.pointA) : constraint.pointA,\n            initialPointB = constraint.bodyB ? Vector.add(constraint.bodyB.position, constraint.pointB) : constraint.pointB,\n            length = Vector.magnitude(Vector.sub(initialPointA, initialPointB));\n    \n        constraint.length = typeof constraint.length !== 'undefined' ? constraint.length : length;\n\n        // option defaults\n        constraint.id = constraint.id || Common.nextId();\n        constraint.label = constraint.label || 'Constraint';\n        constraint.type = 'constraint';\n        constraint.stiffness = constraint.stiffness || (constraint.length > 0 ? 1 : 0.7);\n        constraint.damping = constraint.damping || 0;\n        constraint.angularStiffness = constraint.angularStiffness || 0;\n        constraint.angleA = constraint.bodyA ? constraint.bodyA.angle : constraint.angleA;\n        constraint.angleB = constraint.bodyB ? constraint.bodyB.angle : constraint.angleB;\n        constraint.plugin = {};\n\n        // render\n        var render = {\n            visible: true,\n            lineWidth: 2,\n            strokeStyle: '#ffffff',\n            type: 'line',\n            anchors: true\n        };\n\n        if (constraint.length === 0 && constraint.stiffness > 0.1) {\n            render.type = 'pin';\n            render.anchors = false;\n        } else if (constraint.stiffness < 0.9) {\n            render.type = 'spring';\n        }\n\n        constraint.render = Common.extend(render, constraint.render);\n\n        return constraint;\n    };\n\n    /**\n     * Prepares for solving by constraint warming.\n     * @private\n     * @method preSolveAll\n     * @param {body[]} bodies\n     */\n    Constraint.preSolveAll = function(bodies) {\n        for (var i = 0; i < bodies.length; i += 1) {\n            var body = bodies[i],\n                impulse = body.constraintImpulse;\n\n            if (body.isStatic || (impulse.x === 0 && impulse.y === 0 && impulse.angle === 0)) {\n                continue;\n            }\n\n            body.position.x += impulse.x;\n            body.position.y += impulse.y;\n            body.angle += impulse.angle;\n        }\n    };\n\n    /**\n     * Solves all constraints in a list of collisions.\n     * @private\n     * @method solveAll\n     * @param {constraint[]} constraints\n     * @param {number} delta\n     */\n    Constraint.solveAll = function(constraints, delta) {\n        var timeScale = Common.clamp(delta / Common._baseDelta, 0, 1);\n\n        // Solve fixed constraints first.\n        for (var i = 0; i < constraints.length; i += 1) {\n            var constraint = constraints[i],\n                fixedA = !constraint.bodyA || (constraint.bodyA && constraint.bodyA.isStatic),\n                fixedB = !constraint.bodyB || (constraint.bodyB && constraint.bodyB.isStatic);\n\n            if (fixedA || fixedB) {\n                Constraint.solve(constraints[i], timeScale);\n            }\n        }\n\n        // Solve free constraints last.\n        for (i = 0; i < constraints.length; i += 1) {\n            constraint = constraints[i];\n            fixedA = !constraint.bodyA || (constraint.bodyA && constraint.bodyA.isStatic);\n            fixedB = !constraint.bodyB || (constraint.bodyB && constraint.bodyB.isStatic);\n\n            if (!fixedA && !fixedB) {\n                Constraint.solve(constraints[i], timeScale);\n            }\n        }\n    };\n\n    /**\n     * Solves a distance constraint with Gauss-Siedel method.\n     * @private\n     * @method solve\n     * @param {constraint} constraint\n     * @param {number} timeScale\n     */\n    Constraint.solve = function(constraint, timeScale) {\n        var bodyA = constraint.bodyA,\n            bodyB = constraint.bodyB,\n            pointA = constraint.pointA,\n            pointB = constraint.pointB;\n\n        if (!bodyA && !bodyB)\n            return;\n\n        // update reference angle\n        if (bodyA && !bodyA.isStatic) {\n            Vector.rotate(pointA, bodyA.angle - constraint.angleA, pointA);\n            constraint.angleA = bodyA.angle;\n        }\n        \n        // update reference angle\n        if (bodyB && !bodyB.isStatic) {\n            Vector.rotate(pointB, bodyB.angle - constraint.angleB, pointB);\n            constraint.angleB = bodyB.angle;\n        }\n\n        var pointAWorld = pointA,\n            pointBWorld = pointB;\n\n        if (bodyA) pointAWorld = Vector.add(bodyA.position, pointA);\n        if (bodyB) pointBWorld = Vector.add(bodyB.position, pointB);\n\n        if (!pointAWorld || !pointBWorld)\n            return;\n\n        var delta = Vector.sub(pointAWorld, pointBWorld),\n            currentLength = Vector.magnitude(delta);\n\n        // prevent singularity\n        if (currentLength < Constraint._minLength) {\n            currentLength = Constraint._minLength;\n        }\n\n        // solve distance constraint with Gauss-Siedel method\n        var difference = (currentLength - constraint.length) / currentLength,\n            isRigid = constraint.stiffness >= 1 || constraint.length === 0,\n            stiffness = isRigid ? constraint.stiffness * timeScale \n                : constraint.stiffness * timeScale * timeScale,\n            damping = constraint.damping * timeScale,\n            force = Vector.mult(delta, difference * stiffness),\n            massTotal = (bodyA ? bodyA.inverseMass : 0) + (bodyB ? bodyB.inverseMass : 0),\n            inertiaTotal = (bodyA ? bodyA.inverseInertia : 0) + (bodyB ? bodyB.inverseInertia : 0),\n            resistanceTotal = massTotal + inertiaTotal,\n            torque,\n            share,\n            normal,\n            normalVelocity,\n            relativeVelocity;\n    \n        if (damping > 0) {\n            var zero = Vector.create();\n            normal = Vector.div(delta, currentLength);\n\n            relativeVelocity = Vector.sub(\n                bodyB && Vector.sub(bodyB.position, bodyB.positionPrev) || zero,\n                bodyA && Vector.sub(bodyA.position, bodyA.positionPrev) || zero\n            );\n\n            normalVelocity = Vector.dot(normal, relativeVelocity);\n        }\n\n        if (bodyA && !bodyA.isStatic) {\n            share = bodyA.inverseMass / massTotal;\n\n            // keep track of applied impulses for post solving\n            bodyA.constraintImpulse.x -= force.x * share;\n            bodyA.constraintImpulse.y -= force.y * share;\n\n            // apply forces\n            bodyA.position.x -= force.x * share;\n            bodyA.position.y -= force.y * share;\n\n            // apply damping\n            if (damping > 0) {\n                bodyA.positionPrev.x -= damping * normal.x * normalVelocity * share;\n                bodyA.positionPrev.y -= damping * normal.y * normalVelocity * share;\n            }\n\n            // apply torque\n            torque = (Vector.cross(pointA, force) / resistanceTotal) * Constraint._torqueDampen * bodyA.inverseInertia * (1 - constraint.angularStiffness);\n            bodyA.constraintImpulse.angle -= torque;\n            bodyA.angle -= torque;\n        }\n\n        if (bodyB && !bodyB.isStatic) {\n            share = bodyB.inverseMass / massTotal;\n\n            // keep track of applied impulses for post solving\n            bodyB.constraintImpulse.x += force.x * share;\n            bodyB.constraintImpulse.y += force.y * share;\n            \n            // apply forces\n            bodyB.position.x += force.x * share;\n            bodyB.position.y += force.y * share;\n\n            // apply damping\n            if (damping > 0) {\n                bodyB.positionPrev.x += damping * normal.x * normalVelocity * share;\n                bodyB.positionPrev.y += damping * normal.y * normalVelocity * share;\n            }\n\n            // apply torque\n            torque = (Vector.cross(pointB, force) / resistanceTotal) * Constraint._torqueDampen * bodyB.inverseInertia * (1 - constraint.angularStiffness);\n            bodyB.constraintImpulse.angle += torque;\n            bodyB.angle += torque;\n        }\n\n    };\n\n    /**\n     * Performs body updates required after solving constraints.\n     * @private\n     * @method postSolveAll\n     * @param {body[]} bodies\n     */\n    Constraint.postSolveAll = function(bodies) {\n        for (var i = 0; i < bodies.length; i++) {\n            var body = bodies[i],\n                impulse = body.constraintImpulse;\n\n            if (body.isStatic || (impulse.x === 0 && impulse.y === 0 && impulse.angle === 0)) {\n                continue;\n            }\n\n            Sleeping.set(body, false);\n\n            // update geometry and reset\n            for (var j = 0; j < body.parts.length; j++) {\n                var part = body.parts[j];\n                \n                Vertices.translate(part.vertices, impulse);\n\n                if (j > 0) {\n                    part.position.x += impulse.x;\n                    part.position.y += impulse.y;\n                }\n\n                if (impulse.angle !== 0) {\n                    Vertices.rotate(part.vertices, impulse.angle, body.position);\n                    Axes.rotate(part.axes, impulse.angle);\n                    if (j > 0) {\n                        Vector.rotateAbout(part.position, impulse.angle, body.position, part.position);\n                    }\n                }\n\n                Bounds.update(part.bounds, part.vertices, body.velocity);\n            }\n\n            // dampen the cached impulse for warming next step\n            impulse.angle *= Constraint._warming;\n            impulse.x *= Constraint._warming;\n            impulse.y *= Constraint._warming;\n        }\n    };\n\n    /**\n     * Returns the world-space position of `constraint.pointA`, accounting for `constraint.bodyA`.\n     * @method pointAWorld\n     * @param {constraint} constraint\n     * @returns {vector} the world-space position\n     */\n    Constraint.pointAWorld = function(constraint) {\n        return {\n            x: (constraint.bodyA ? constraint.bodyA.position.x : 0) \n                + (constraint.pointA ? constraint.pointA.x : 0),\n            y: (constraint.bodyA ? constraint.bodyA.position.y : 0) \n                + (constraint.pointA ? constraint.pointA.y : 0)\n        };\n    };\n\n    /**\n     * Returns the world-space position of `constraint.pointB`, accounting for `constraint.bodyB`.\n     * @method pointBWorld\n     * @param {constraint} constraint\n     * @returns {vector} the world-space position\n     */\n    Constraint.pointBWorld = function(constraint) {\n        return {\n            x: (constraint.bodyB ? constraint.bodyB.position.x : 0) \n                + (constraint.pointB ? constraint.pointB.x : 0),\n            y: (constraint.bodyB ? constraint.bodyB.position.y : 0) \n                + (constraint.pointB ? constraint.pointB.y : 0)\n        };\n    };\n\n    /*\n    *\n    *  Properties Documentation\n    *\n    */\n\n    /**\n     * An integer `Number` uniquely identifying number generated in `Composite.create` by `Common.nextId`.\n     *\n     * @property id\n     * @type number\n     */\n\n    /**\n     * A `String` denoting the type of object.\n     *\n     * @property type\n     * @type string\n     * @default \"constraint\"\n     * @readOnly\n     */\n\n    /**\n     * An arbitrary `String` name to help the user identify and manage bodies.\n     *\n     * @property label\n     * @type string\n     * @default \"Constraint\"\n     */\n\n    /**\n     * An `Object` that defines the rendering properties to be consumed by the module `Matter.Render`.\n     *\n     * @property render\n     * @type object\n     */\n\n    /**\n     * A flag that indicates if the constraint should be rendered.\n     *\n     * @property render.visible\n     * @type boolean\n     * @default true\n     */\n\n    /**\n     * A `Number` that defines the line width to use when rendering the constraint outline.\n     * A value of `0` means no outline will be rendered.\n     *\n     * @property render.lineWidth\n     * @type number\n     * @default 2\n     */\n\n    /**\n     * A `String` that defines the stroke style to use when rendering the constraint outline.\n     * It is the same as when using a canvas, so it accepts CSS style property values.\n     *\n     * @property render.strokeStyle\n     * @type string\n     * @default a random colour\n     */\n\n    /**\n     * A `String` that defines the constraint rendering type. \n     * The possible values are 'line', 'pin', 'spring'.\n     * An appropriate render type will be automatically chosen unless one is given in options.\n     *\n     * @property render.type\n     * @type string\n     * @default 'line'\n     */\n\n    /**\n     * A `Boolean` that defines if the constraint's anchor points should be rendered.\n     *\n     * @property render.anchors\n     * @type boolean\n     * @default true\n     */\n\n    /**\n     * The first possible `Body` that this constraint is attached to.\n     *\n     * @property bodyA\n     * @type body\n     * @default null\n     */\n\n    /**\n     * The second possible `Body` that this constraint is attached to.\n     *\n     * @property bodyB\n     * @type body\n     * @default null\n     */\n\n    /**\n     * A `Vector` that specifies the offset of the constraint from center of the `constraint.bodyA` if defined, otherwise a world-space position.\n     *\n     * @property pointA\n     * @type vector\n     * @default { x: 0, y: 0 }\n     */\n\n    /**\n     * A `Vector` that specifies the offset of the constraint from center of the `constraint.bodyB` if defined, otherwise a world-space position.\n     *\n     * @property pointB\n     * @type vector\n     * @default { x: 0, y: 0 }\n     */\n\n    /**\n     * A `Number` that specifies the stiffness of the constraint, i.e. the rate at which it returns to its resting `constraint.length`.\n     * A value of `1` means the constraint should be very stiff.\n     * A value of `0.2` means the constraint acts like a soft spring.\n     *\n     * @property stiffness\n     * @type number\n     * @default 1\n     */\n\n    /**\n     * A `Number` that specifies the damping of the constraint, \n     * i.e. the amount of resistance applied to each body based on their velocities to limit the amount of oscillation.\n     * Damping will only be apparent when the constraint also has a very low `stiffness`.\n     * A value of `0.1` means the constraint will apply heavy damping, resulting in little to no oscillation.\n     * A value of `0` means the constraint will apply no damping.\n     *\n     * @property damping\n     * @type number\n     * @default 0\n     */\n\n    /**\n     * A `Number` that specifies the target resting length of the constraint. \n     * It is calculated automatically in `Constraint.create` from initial positions of the `constraint.bodyA` and `constraint.bodyB`.\n     *\n     * @property length\n     * @type number\n     */\n\n    /**\n     * An object reserved for storing plugin-specific properties.\n     *\n     * @property plugin\n     * @type {}\n     */\n\n})();\n\n\n/***/ }),\n/* 11 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Axes` module contains methods for creating and manipulating sets of axes.\n*\n* @class Axes\n*/\n\nvar Axes = {};\n\nmodule.exports = Axes;\n\nvar Vector = __webpack_require__(2);\nvar Common = __webpack_require__(0);\n\n(function() {\n\n    /**\n     * Creates a new set of axes from the given vertices.\n     * @method fromVertices\n     * @param {vertices} vertices\n     * @return {axes} A new axes from the given vertices\n     */\n    Axes.fromVertices = function(vertices) {\n        var axes = {};\n\n        // find the unique axes, using edge normal gradients\n        for (var i = 0; i < vertices.length; i++) {\n            var j = (i + 1) % vertices.length, \n                normal = Vector.normalise({ \n                    x: vertices[j].y - vertices[i].y, \n                    y: vertices[i].x - vertices[j].x\n                }),\n                gradient = (normal.y === 0) ? Infinity : (normal.x / normal.y);\n            \n            // limit precision\n            gradient = gradient.toFixed(3).toString();\n            axes[gradient] = normal;\n        }\n\n        return Common.values(axes);\n    };\n\n    /**\n     * Rotates a set of axes by the given angle.\n     * @method rotate\n     * @param {axes} axes\n     * @param {number} angle\n     */\n    Axes.rotate = function(axes, angle) {\n        if (angle === 0)\n            return;\n        \n        var cos = Math.cos(angle),\n            sin = Math.sin(angle);\n\n        for (var i = 0; i < axes.length; i++) {\n            var axis = axes[i],\n                xx;\n            xx = axis.x * cos - axis.y * sin;\n            axis.y = axis.x * sin + axis.y * cos;\n            axis.x = xx;\n        }\n    };\n\n})();\n\n\n/***/ }),\n/* 12 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Bodies` module contains factory methods for creating rigid body models \n* with commonly used body configurations (such as rectangles, circles and other polygons).\n*\n* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).\n*\n* @class Bodies\n*/\n\n// TODO: true circle bodies\n\nvar Bodies = {};\n\nmodule.exports = Bodies;\n\nvar Vertices = __webpack_require__(3);\nvar Common = __webpack_require__(0);\nvar Body = __webpack_require__(4);\nvar Bounds = __webpack_require__(1);\nvar Vector = __webpack_require__(2);\n\n(function() {\n\n    /**\n     * Creates a new rigid body model with a rectangle hull. \n     * The options parameter is an object that specifies any properties you wish to override the defaults.\n     * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object.\n     * @method rectangle\n     * @param {number} x\n     * @param {number} y\n     * @param {number} width\n     * @param {number} height\n     * @param {object} [options]\n     * @return {body} A new rectangle body\n     */\n    Bodies.rectangle = function(x, y, width, height, options) {\n        options = options || {};\n\n        var rectangle = { \n            label: 'Rectangle Body',\n            position: { x: x, y: y },\n            vertices: Vertices.fromPath('L 0 0 L ' + width + ' 0 L ' + width + ' ' + height + ' L 0 ' + height)\n        };\n\n        if (options.chamfer) {\n            var chamfer = options.chamfer;\n            rectangle.vertices = Vertices.chamfer(rectangle.vertices, chamfer.radius, \n                chamfer.quality, chamfer.qualityMin, chamfer.qualityMax);\n            delete options.chamfer;\n        }\n\n        return Body.create(Common.extend({}, rectangle, options));\n    };\n    \n    /**\n     * Creates a new rigid body model with a trapezoid hull. \n     * The options parameter is an object that specifies any properties you wish to override the defaults.\n     * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object.\n     * @method trapezoid\n     * @param {number} x\n     * @param {number} y\n     * @param {number} width\n     * @param {number} height\n     * @param {number} slope\n     * @param {object} [options]\n     * @return {body} A new trapezoid body\n     */\n    Bodies.trapezoid = function(x, y, width, height, slope, options) {\n        options = options || {};\n\n        slope *= 0.5;\n        var roof = (1 - (slope * 2)) * width;\n        \n        var x1 = width * slope,\n            x2 = x1 + roof,\n            x3 = x2 + x1,\n            verticesPath;\n\n        if (slope < 0.5) {\n            verticesPath = 'L 0 0 L ' + x1 + ' ' + (-height) + ' L ' + x2 + ' ' + (-height) + ' L ' + x3 + ' 0';\n        } else {\n            verticesPath = 'L 0 0 L ' + x2 + ' ' + (-height) + ' L ' + x3 + ' 0';\n        }\n\n        var trapezoid = { \n            label: 'Trapezoid Body',\n            position: { x: x, y: y },\n            vertices: Vertices.fromPath(verticesPath)\n        };\n\n        if (options.chamfer) {\n            var chamfer = options.chamfer;\n            trapezoid.vertices = Vertices.chamfer(trapezoid.vertices, chamfer.radius, \n                chamfer.quality, chamfer.qualityMin, chamfer.qualityMax);\n            delete options.chamfer;\n        }\n\n        return Body.create(Common.extend({}, trapezoid, options));\n    };\n\n    /**\n     * Creates a new rigid body model with a circle hull. \n     * The options parameter is an object that specifies any properties you wish to override the defaults.\n     * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object.\n     * @method circle\n     * @param {number} x\n     * @param {number} y\n     * @param {number} radius\n     * @param {object} [options]\n     * @param {number} [maxSides]\n     * @return {body} A new circle body\n     */\n    Bodies.circle = function(x, y, radius, options, maxSides) {\n        options = options || {};\n\n        var circle = {\n            label: 'Circle Body',\n            circleRadius: radius\n        };\n        \n        // approximate circles with polygons until true circles implemented in SAT\n        maxSides = maxSides || 25;\n        var sides = Math.ceil(Math.max(10, Math.min(maxSides, radius)));\n\n        // optimisation: always use even number of sides (half the number of unique axes)\n        if (sides % 2 === 1)\n            sides += 1;\n\n        return Bodies.polygon(x, y, sides, radius, Common.extend({}, circle, options));\n    };\n\n    /**\n     * Creates a new rigid body model with a regular polygon hull with the given number of sides. \n     * The options parameter is an object that specifies any properties you wish to override the defaults.\n     * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object.\n     * @method polygon\n     * @param {number} x\n     * @param {number} y\n     * @param {number} sides\n     * @param {number} radius\n     * @param {object} [options]\n     * @return {body} A new regular polygon body\n     */\n    Bodies.polygon = function(x, y, sides, radius, options) {\n        options = options || {};\n\n        if (sides < 3)\n            return Bodies.circle(x, y, radius, options);\n\n        var theta = 2 * Math.PI / sides,\n            path = '',\n            offset = theta * 0.5;\n\n        for (var i = 0; i < sides; i += 1) {\n            var angle = offset + (i * theta),\n                xx = Math.cos(angle) * radius,\n                yy = Math.sin(angle) * radius;\n\n            path += 'L ' + xx.toFixed(3) + ' ' + yy.toFixed(3) + ' ';\n        }\n\n        var polygon = { \n            label: 'Polygon Body',\n            position: { x: x, y: y },\n            vertices: Vertices.fromPath(path)\n        };\n\n        if (options.chamfer) {\n            var chamfer = options.chamfer;\n            polygon.vertices = Vertices.chamfer(polygon.vertices, chamfer.radius, \n                chamfer.quality, chamfer.qualityMin, chamfer.qualityMax);\n            delete options.chamfer;\n        }\n\n        return Body.create(Common.extend({}, polygon, options));\n    };\n\n    /**\n     * Utility to create a compound body based on set(s) of vertices.\n     * \n     * _Note:_ To optionally enable automatic concave vertices decomposition the [poly-decomp](https://github.com/schteppe/poly-decomp.js) \n     * package must be first installed and provided see `Common.setDecomp`, otherwise the convex hull of each vertex set will be used.\n     * \n     * The resulting vertices are reorientated about their centre of mass,\n     * and offset such that `body.position` corresponds to this point.\n     * \n     * The resulting offset may be found if needed by subtracting `body.bounds` from the original input bounds.\n     * To later move the centre of mass see `Body.setCentre`.\n     * \n     * Note that automatic conconcave decomposition results are not always optimal. \n     * For best results, simplify the input vertices as much as possible first.\n     * By default this function applies some addtional simplification to help.\n     * \n     * Some outputs may also require further manual processing afterwards to be robust.\n     * In particular some parts may need to be overlapped to avoid collision gaps.\n     * Thin parts and sharp points should be avoided or removed where possible.\n     *\n     * The options parameter object specifies any `Matter.Body` properties you wish to override the defaults.\n     * \n     * See the properties section of the `Matter.Body` module for detailed information on what you can pass via the `options` object.\n     * @method fromVertices\n     * @param {number} x\n     * @param {number} y\n     * @param {array} vertexSets One or more arrays of vertex points e.g. `[[{ x: 0, y: 0 }...], ...]`.\n     * @param {object} [options] The body options.\n     * @param {bool} [flagInternal=false] Optionally marks internal edges with `isInternal`.\n     * @param {number} [removeCollinear=0.01] Threshold when simplifying vertices along the same edge.\n     * @param {number} [minimumArea=10] Threshold when removing small parts.\n     * @param {number} [removeDuplicatePoints=0.01] Threshold when simplifying nearby vertices.\n     * @return {body}\n     */\n    Bodies.fromVertices = function(x, y, vertexSets, options, flagInternal, removeCollinear, minimumArea, removeDuplicatePoints) {\n        var decomp = Common.getDecomp(),\n            canDecomp,\n            body,\n            parts,\n            isConvex,\n            isConcave,\n            vertices,\n            i,\n            j,\n            k,\n            v,\n            z;\n\n        // check decomp is as expected\n        canDecomp = Boolean(decomp && decomp.quickDecomp);\n\n        options = options || {};\n        parts = [];\n\n        flagInternal = typeof flagInternal !== 'undefined' ? flagInternal : false;\n        removeCollinear = typeof removeCollinear !== 'undefined' ? removeCollinear : 0.01;\n        minimumArea = typeof minimumArea !== 'undefined' ? minimumArea : 10;\n        removeDuplicatePoints = typeof removeDuplicatePoints !== 'undefined' ? removeDuplicatePoints : 0.01;\n\n        // ensure vertexSets is an array of arrays\n        if (!Common.isArray(vertexSets[0])) {\n            vertexSets = [vertexSets];\n        }\n\n        for (v = 0; v < vertexSets.length; v += 1) {\n            vertices = vertexSets[v];\n            isConvex = Vertices.isConvex(vertices);\n            isConcave = !isConvex;\n\n            if (isConcave && !canDecomp) {\n                Common.warnOnce(\n                    'Bodies.fromVertices: Install the \\'poly-decomp\\' library and use Common.setDecomp or provide \\'decomp\\' as a global to decompose concave vertices.'\n                );\n            }\n\n            if (isConvex || !canDecomp) {\n                if (isConvex) {\n                    vertices = Vertices.clockwiseSort(vertices);\n                } else {\n                    // fallback to convex hull when decomposition is not possible\n                    vertices = Vertices.hull(vertices);\n                }\n\n                parts.push({\n                    position: { x: x, y: y },\n                    vertices: vertices\n                });\n            } else {\n                // initialise a decomposition\n                var concave = vertices.map(function(vertex) {\n                    return [vertex.x, vertex.y];\n                });\n\n                // vertices are concave and simple, we can decompose into parts\n                decomp.makeCCW(concave);\n                if (removeCollinear !== false)\n                    decomp.removeCollinearPoints(concave, removeCollinear);\n                if (removeDuplicatePoints !== false && decomp.removeDuplicatePoints)\n                    decomp.removeDuplicatePoints(concave, removeDuplicatePoints);\n\n                // use the quick decomposition algorithm (Bayazit)\n                var decomposed = decomp.quickDecomp(concave);\n\n                // for each decomposed chunk\n                for (i = 0; i < decomposed.length; i++) {\n                    var chunk = decomposed[i];\n\n                    // convert vertices into the correct structure\n                    var chunkVertices = chunk.map(function(vertices) {\n                        return {\n                            x: vertices[0],\n                            y: vertices[1]\n                        };\n                    });\n\n                    // skip small chunks\n                    if (minimumArea > 0 && Vertices.area(chunkVertices) < minimumArea)\n                        continue;\n\n                    // create a compound part\n                    parts.push({\n                        position: Vertices.centre(chunkVertices),\n                        vertices: chunkVertices\n                    });\n                }\n            }\n        }\n\n        // create body parts\n        for (i = 0; i < parts.length; i++) {\n            parts[i] = Body.create(Common.extend(parts[i], options));\n        }\n\n        // flag internal edges (coincident part edges)\n        if (flagInternal) {\n            var coincident_max_dist = 5;\n\n            for (i = 0; i < parts.length; i++) {\n                var partA = parts[i];\n\n                for (j = i + 1; j < parts.length; j++) {\n                    var partB = parts[j];\n\n                    if (Bounds.overlaps(partA.bounds, partB.bounds)) {\n                        var pav = partA.vertices,\n                            pbv = partB.vertices;\n\n                        // iterate vertices of both parts\n                        for (k = 0; k < partA.vertices.length; k++) {\n                            for (z = 0; z < partB.vertices.length; z++) {\n                                // find distances between the vertices\n                                var da = Vector.magnitudeSquared(Vector.sub(pav[(k + 1) % pav.length], pbv[z])),\n                                    db = Vector.magnitudeSquared(Vector.sub(pav[k], pbv[(z + 1) % pbv.length]));\n\n                                // if both vertices are very close, consider the edge concident (internal)\n                                if (da < coincident_max_dist && db < coincident_max_dist) {\n                                    pav[k].isInternal = true;\n                                    pbv[z].isInternal = true;\n                                }\n                            }\n                        }\n\n                    }\n                }\n            }\n        }\n\n        if (parts.length > 1) {\n            // create the parent body to be returned, that contains generated compound parts\n            body = Body.create(Common.extend({ parts: parts.slice(0) }, options));\n\n            // offset such that body.position is at the centre off mass\n            Body.setPosition(body, { x: x, y: y });\n\n            return body;\n        } else {\n            return parts[0];\n        }\n    };\n\n})();\n\n\n/***/ }),\n/* 13 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Detector` module contains methods for efficiently detecting collisions between a list of bodies using a broadphase algorithm.\n*\n* @class Detector\n*/\n\nvar Detector = {};\n\nmodule.exports = Detector;\n\nvar Common = __webpack_require__(0);\nvar Collision = __webpack_require__(8);\n\n(function() {\n\n    /**\n     * Creates a new collision detector.\n     * @method create\n     * @param {} options\n     * @return {detector} A new collision detector\n     */\n    Detector.create = function(options) {\n        var defaults = {\n            bodies: [],\n            pairs: null\n        };\n\n        return Common.extend(defaults, options);\n    };\n\n    /**\n     * Sets the list of bodies in the detector.\n     * @method setBodies\n     * @param {detector} detector\n     * @param {body[]} bodies\n     */\n    Detector.setBodies = function(detector, bodies) {\n        detector.bodies = bodies.slice(0);\n    };\n\n    /**\n     * Clears the detector including its list of bodies.\n     * @method clear\n     * @param {detector} detector\n     */\n    Detector.clear = function(detector) {\n        detector.bodies = [];\n    };\n\n    /**\n     * Efficiently finds all collisions among all the bodies in `detector.bodies` using a broadphase algorithm.\n     * \n     * _Note:_ The specific ordering of collisions returned is not guaranteed between releases and may change for performance reasons.\n     * If a specific ordering is required then apply a sort to the resulting array.\n     * @method collisions\n     * @param {detector} detector\n     * @return {collision[]} collisions\n     */\n    Detector.collisions = function(detector) {\n        var collisions = [],\n            pairs = detector.pairs,\n            bodies = detector.bodies,\n            bodiesLength = bodies.length,\n            canCollide = Detector.canCollide,\n            collides = Collision.collides,\n            i,\n            j;\n\n        bodies.sort(Detector._compareBoundsX);\n\n        for (i = 0; i < bodiesLength; i++) {\n            var bodyA = bodies[i],\n                boundsA = bodyA.bounds,\n                boundXMax = bodyA.bounds.max.x,\n                boundYMax = bodyA.bounds.max.y,\n                boundYMin = bodyA.bounds.min.y,\n                bodyAStatic = bodyA.isStatic || bodyA.isSleeping,\n                partsALength = bodyA.parts.length,\n                partsASingle = partsALength === 1;\n\n            for (j = i + 1; j < bodiesLength; j++) {\n                var bodyB = bodies[j],\n                    boundsB = bodyB.bounds;\n\n                if (boundsB.min.x > boundXMax) {\n                    break;\n                }\n\n                if (boundYMax < boundsB.min.y || boundYMin > boundsB.max.y) {\n                    continue;\n                }\n\n                if (bodyAStatic && (bodyB.isStatic || bodyB.isSleeping)) {\n                    continue;\n                }\n\n                if (!canCollide(bodyA.collisionFilter, bodyB.collisionFilter)) {\n                    continue;\n                }\n\n                var partsBLength = bodyB.parts.length;\n\n                if (partsASingle && partsBLength === 1) {\n                    var collision = collides(bodyA, bodyB, pairs);\n\n                    if (collision) {\n                        collisions.push(collision);\n                    }\n                } else {\n                    var partsAStart = partsALength > 1 ? 1 : 0,\n                        partsBStart = partsBLength > 1 ? 1 : 0;\n                    \n                    for (var k = partsAStart; k < partsALength; k++) {\n                        var partA = bodyA.parts[k],\n                            boundsA = partA.bounds;\n\n                        for (var z = partsBStart; z < partsBLength; z++) {\n                            var partB = bodyB.parts[z],\n                                boundsB = partB.bounds;\n\n                            if (boundsA.min.x > boundsB.max.x || boundsA.max.x < boundsB.min.x\n                                || boundsA.max.y < boundsB.min.y || boundsA.min.y > boundsB.max.y) {\n                                continue;\n                            }\n\n                            var collision = collides(partA, partB, pairs);\n\n                            if (collision) {\n                                collisions.push(collision);\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        return collisions;\n    };\n\n    /**\n     * Returns `true` if both supplied collision filters will allow a collision to occur.\n     * See `body.collisionFilter` for more information.\n     * @method canCollide\n     * @param {} filterA\n     * @param {} filterB\n     * @return {bool} `true` if collision can occur\n     */\n    Detector.canCollide = function(filterA, filterB) {\n        if (filterA.group === filterB.group && filterA.group !== 0)\n            return filterA.group > 0;\n\n        return (filterA.mask & filterB.category) !== 0 && (filterB.mask & filterA.category) !== 0;\n    };\n\n    /**\n     * The comparison function used in the broadphase algorithm.\n     * Returns the signed delta of the bodies bounds on the x-axis.\n     * @private\n     * @method _sortCompare\n     * @param {body} bodyA\n     * @param {body} bodyB\n     * @return {number} The signed delta used for sorting\n     */\n    Detector._compareBoundsX = function(bodyA, bodyB) {\n        return bodyA.bounds.min.x - bodyB.bounds.min.x;\n    };\n\n    /*\n    *\n    *  Properties Documentation\n    *\n    */\n\n    /**\n     * The array of `Matter.Body` between which the detector finds collisions.\n     * \n     * _Note:_ The order of bodies in this array _is not fixed_ and will be continually managed by the detector.\n     * @property bodies\n     * @type body[]\n     * @default []\n     */\n\n    /**\n     * Optional. A `Matter.Pairs` object from which previous collision objects may be reused. Intended for internal `Matter.Engine` usage.\n     * @property pairs\n     * @type {pairs|null}\n     * @default null\n     */\n\n})();\n\n\n/***/ }),\n/* 14 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Mouse` module contains methods for creating and manipulating mouse inputs.\n*\n* @class Mouse\n*/\n\nvar Mouse = {};\n\nmodule.exports = Mouse;\n\nvar Common = __webpack_require__(0);\n\n(function() {\n\n    /**\n     * Creates a mouse input.\n     * @method create\n     * @param {HTMLElement} element\n     * @return {mouse} A new mouse\n     */\n    Mouse.create = function(element) {\n        var mouse = {};\n\n        if (!element) {\n            Common.log('Mouse.create: element was undefined, defaulting to document.body', 'warn');\n        }\n        \n        mouse.element = element || document.body;\n        mouse.absolute = { x: 0, y: 0 };\n        mouse.position = { x: 0, y: 0 };\n        mouse.mousedownPosition = { x: 0, y: 0 };\n        mouse.mouseupPosition = { x: 0, y: 0 };\n        mouse.offset = { x: 0, y: 0 };\n        mouse.scale = { x: 1, y: 1 };\n        mouse.wheelDelta = 0;\n        mouse.button = -1;\n        mouse.pixelRatio = parseInt(mouse.element.getAttribute('data-pixel-ratio'), 10) || 1;\n\n        mouse.sourceEvents = {\n            mousemove: null,\n            mousedown: null,\n            mouseup: null,\n            mousewheel: null\n        };\n        \n        mouse.mousemove = function(event) { \n            var position = Mouse._getRelativeMousePosition(event, mouse.element, mouse.pixelRatio),\n                touches = event.changedTouches;\n\n            if (touches) {\n                mouse.button = 0;\n                event.preventDefault();\n            }\n\n            mouse.absolute.x = position.x;\n            mouse.absolute.y = position.y;\n            mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x;\n            mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y;\n            mouse.sourceEvents.mousemove = event;\n        };\n        \n        mouse.mousedown = function(event) {\n            var position = Mouse._getRelativeMousePosition(event, mouse.element, mouse.pixelRatio),\n                touches = event.changedTouches;\n\n            if (touches) {\n                mouse.button = 0;\n                event.preventDefault();\n            } else {\n                mouse.button = event.button;\n            }\n\n            mouse.absolute.x = position.x;\n            mouse.absolute.y = position.y;\n            mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x;\n            mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y;\n            mouse.mousedownPosition.x = mouse.position.x;\n            mouse.mousedownPosition.y = mouse.position.y;\n            mouse.sourceEvents.mousedown = event;\n        };\n        \n        mouse.mouseup = function(event) {\n            var position = Mouse._getRelativeMousePosition(event, mouse.element, mouse.pixelRatio),\n                touches = event.changedTouches;\n\n            if (touches) {\n                event.preventDefault();\n            }\n            \n            mouse.button = -1;\n            mouse.absolute.x = position.x;\n            mouse.absolute.y = position.y;\n            mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x;\n            mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y;\n            mouse.mouseupPosition.x = mouse.position.x;\n            mouse.mouseupPosition.y = mouse.position.y;\n            mouse.sourceEvents.mouseup = event;\n        };\n\n        mouse.mousewheel = function(event) {\n            mouse.wheelDelta = Math.max(-1, Math.min(1, event.wheelDelta || -event.detail));\n            event.preventDefault();\n        };\n\n        Mouse.setElement(mouse, mouse.element);\n\n        return mouse;\n    };\n\n    /**\n     * Sets the element the mouse is bound to (and relative to).\n     * @method setElement\n     * @param {mouse} mouse\n     * @param {HTMLElement} element\n     */\n    Mouse.setElement = function(mouse, element) {\n        mouse.element = element;\n\n        element.addEventListener('mousemove', mouse.mousemove);\n        element.addEventListener('mousedown', mouse.mousedown);\n        element.addEventListener('mouseup', mouse.mouseup);\n        \n        element.addEventListener('mousewheel', mouse.mousewheel);\n        element.addEventListener('DOMMouseScroll', mouse.mousewheel);\n\n        element.addEventListener('touchmove', mouse.mousemove);\n        element.addEventListener('touchstart', mouse.mousedown);\n        element.addEventListener('touchend', mouse.mouseup);\n    };\n\n    /**\n     * Clears all captured source events.\n     * @method clearSourceEvents\n     * @param {mouse} mouse\n     */\n    Mouse.clearSourceEvents = function(mouse) {\n        mouse.sourceEvents.mousemove = null;\n        mouse.sourceEvents.mousedown = null;\n        mouse.sourceEvents.mouseup = null;\n        mouse.sourceEvents.mousewheel = null;\n        mouse.wheelDelta = 0;\n    };\n\n    /**\n     * Sets the mouse position offset.\n     * @method setOffset\n     * @param {mouse} mouse\n     * @param {vector} offset\n     */\n    Mouse.setOffset = function(mouse, offset) {\n        mouse.offset.x = offset.x;\n        mouse.offset.y = offset.y;\n        mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x;\n        mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y;\n    };\n\n    /**\n     * Sets the mouse position scale.\n     * @method setScale\n     * @param {mouse} mouse\n     * @param {vector} scale\n     */\n    Mouse.setScale = function(mouse, scale) {\n        mouse.scale.x = scale.x;\n        mouse.scale.y = scale.y;\n        mouse.position.x = mouse.absolute.x * mouse.scale.x + mouse.offset.x;\n        mouse.position.y = mouse.absolute.y * mouse.scale.y + mouse.offset.y;\n    };\n    \n    /**\n     * Gets the mouse position relative to an element given a screen pixel ratio.\n     * @method _getRelativeMousePosition\n     * @private\n     * @param {} event\n     * @param {} element\n     * @param {number} pixelRatio\n     * @return {}\n     */\n    Mouse._getRelativeMousePosition = function(event, element, pixelRatio) {\n        var elementBounds = element.getBoundingClientRect(),\n            rootNode = (document.documentElement || document.body.parentNode || document.body),\n            scrollX = (window.pageXOffset !== undefined) ? window.pageXOffset : rootNode.scrollLeft,\n            scrollY = (window.pageYOffset !== undefined) ? window.pageYOffset : rootNode.scrollTop,\n            touches = event.changedTouches,\n            x, y;\n        \n        if (touches) {\n            x = touches[0].pageX - elementBounds.left - scrollX;\n            y = touches[0].pageY - elementBounds.top - scrollY;\n        } else {\n            x = event.pageX - elementBounds.left - scrollX;\n            y = event.pageY - elementBounds.top - scrollY;\n        }\n\n        return { \n            x: x / (element.clientWidth / (element.width || element.clientWidth) * pixelRatio),\n            y: y / (element.clientHeight / (element.height || element.clientHeight) * pixelRatio)\n        };\n    };\n\n})();\n\n\n/***/ }),\n/* 15 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Plugin` module contains functions for registering and installing plugins on modules.\n*\n* @class Plugin\n*/\n\nvar Plugin = {};\n\nmodule.exports = Plugin;\n\nvar Common = __webpack_require__(0);\n\n(function() {\n\n    Plugin._registry = {};\n\n    /**\n     * Registers a plugin object so it can be resolved later by name.\n     * @method register\n     * @param plugin {} The plugin to register.\n     * @return {object} The plugin.\n     */\n    Plugin.register = function(plugin) {\n        if (!Plugin.isPlugin(plugin)) {\n            Common.warn('Plugin.register:', Plugin.toString(plugin), 'does not implement all required fields.');\n        }\n\n        if (plugin.name in Plugin._registry) {\n            var registered = Plugin._registry[plugin.name],\n                pluginVersion = Plugin.versionParse(plugin.version).number,\n                registeredVersion = Plugin.versionParse(registered.version).number;\n\n            if (pluginVersion > registeredVersion) {\n                Common.warn('Plugin.register:', Plugin.toString(registered), 'was upgraded to', Plugin.toString(plugin));\n                Plugin._registry[plugin.name] = plugin;\n            } else if (pluginVersion < registeredVersion) {\n                Common.warn('Plugin.register:', Plugin.toString(registered), 'can not be downgraded to', Plugin.toString(plugin));\n            } else if (plugin !== registered) {\n                Common.warn('Plugin.register:', Plugin.toString(plugin), 'is already registered to different plugin object');\n            }\n        } else {\n            Plugin._registry[plugin.name] = plugin;\n        }\n\n        return plugin;\n    };\n\n    /**\n     * Resolves a dependency to a plugin object from the registry if it exists. \n     * The `dependency` may contain a version, but only the name matters when resolving.\n     * @method resolve\n     * @param dependency {string} The dependency.\n     * @return {object} The plugin if resolved, otherwise `undefined`.\n     */\n    Plugin.resolve = function(dependency) {\n        return Plugin._registry[Plugin.dependencyParse(dependency).name];\n    };\n\n    /**\n     * Returns a pretty printed plugin name and version.\n     * @method toString\n     * @param plugin {} The plugin.\n     * @return {string} Pretty printed plugin name and version.\n     */\n    Plugin.toString = function(plugin) {\n        return typeof plugin === 'string' ? plugin : (plugin.name || 'anonymous') + '@' + (plugin.version || plugin.range || '0.0.0');\n    };\n\n    /**\n     * Returns `true` if the object meets the minimum standard to be considered a plugin.\n     * This means it must define the following properties:\n     * - `name`\n     * - `version`\n     * - `install`\n     * @method isPlugin\n     * @param obj {} The obj to test.\n     * @return {boolean} `true` if the object can be considered a plugin otherwise `false`.\n     */\n    Plugin.isPlugin = function(obj) {\n        return obj && obj.name && obj.version && obj.install;\n    };\n\n    /**\n     * Returns `true` if a plugin with the given `name` been installed on `module`.\n     * @method isUsed\n     * @param module {} The module.\n     * @param name {string} The plugin name.\n     * @return {boolean} `true` if a plugin with the given `name` been installed on `module`, otherwise `false`.\n     */\n    Plugin.isUsed = function(module, name) {\n        return module.used.indexOf(name) > -1;\n    };\n\n    /**\n     * Returns `true` if `plugin.for` is applicable to `module` by comparing against `module.name` and `module.version`.\n     * If `plugin.for` is not specified then it is assumed to be applicable.\n     * The value of `plugin.for` is a string of the format `'module-name'` or `'module-name@version'`.\n     * @method isFor\n     * @param plugin {} The plugin.\n     * @param module {} The module.\n     * @return {boolean} `true` if `plugin.for` is applicable to `module`, otherwise `false`.\n     */\n    Plugin.isFor = function(plugin, module) {\n        var parsed = plugin.for && Plugin.dependencyParse(plugin.for);\n        return !plugin.for || (module.name === parsed.name && Plugin.versionSatisfies(module.version, parsed.range));\n    };\n\n    /**\n     * Installs the plugins by calling `plugin.install` on each plugin specified in `plugins` if passed, otherwise `module.uses`.\n     * For installing plugins on `Matter` see the convenience function `Matter.use`.\n     * Plugins may be specified either by their name or a reference to the plugin object.\n     * Plugins themselves may specify further dependencies, but each plugin is installed only once.\n     * Order is important, a topological sort is performed to find the best resulting order of installation.\n     * This sorting attempts to satisfy every dependency's requested ordering, but may not be exact in all cases.\n     * This function logs the resulting status of each dependency in the console, along with any warnings.\n     * - A green tick ✅ indicates a dependency was resolved and installed.\n     * - An orange diamond 🔶 indicates a dependency was resolved but a warning was thrown for it or one if its dependencies.\n     * - A red cross ❌ indicates a dependency could not be resolved.\n     * Avoid calling this function multiple times on the same module unless you intend to manually control installation order.\n     * @method use\n     * @param module {} The module install plugins on.\n     * @param [plugins=module.uses] {} The plugins to install on module (optional, defaults to `module.uses`).\n     */\n    Plugin.use = function(module, plugins) {\n        module.uses = (module.uses || []).concat(plugins || []);\n\n        if (module.uses.length === 0) {\n            Common.warn('Plugin.use:', Plugin.toString(module), 'does not specify any dependencies to install.');\n            return;\n        }\n\n        var dependencies = Plugin.dependencies(module),\n            sortedDependencies = Common.topologicalSort(dependencies),\n            status = [];\n\n        for (var i = 0; i < sortedDependencies.length; i += 1) {\n            if (sortedDependencies[i] === module.name) {\n                continue;\n            }\n\n            var plugin = Plugin.resolve(sortedDependencies[i]);\n\n            if (!plugin) {\n                status.push('❌ ' + sortedDependencies[i]);\n                continue;\n            }\n\n            if (Plugin.isUsed(module, plugin.name)) {\n                continue;\n            }\n\n            if (!Plugin.isFor(plugin, module)) {\n                Common.warn('Plugin.use:', Plugin.toString(plugin), 'is for', plugin.for, 'but installed on', Plugin.toString(module) + '.');\n                plugin._warned = true;\n            }\n\n            if (plugin.install) {\n                plugin.install(module);\n            } else {\n                Common.warn('Plugin.use:', Plugin.toString(plugin), 'does not specify an install function.');\n                plugin._warned = true;\n            }\n\n            if (plugin._warned) {\n                status.push('🔶 ' + Plugin.toString(plugin));\n                delete plugin._warned;\n            } else {\n                status.push('✅ ' + Plugin.toString(plugin));\n            }\n\n            module.used.push(plugin.name);\n        }\n\n        if (status.length > 0) {\n            Common.info(status.join('  '));\n        }\n    };\n\n    /**\n     * Recursively finds all of a module's dependencies and returns a flat dependency graph.\n     * @method dependencies\n     * @param module {} The module.\n     * @return {object} A dependency graph.\n     */\n    Plugin.dependencies = function(module, tracked) {\n        var parsedBase = Plugin.dependencyParse(module),\n            name = parsedBase.name;\n\n        tracked = tracked || {};\n\n        if (name in tracked) {\n            return;\n        }\n\n        module = Plugin.resolve(module) || module;\n\n        tracked[name] = Common.map(module.uses || [], function(dependency) {\n            if (Plugin.isPlugin(dependency)) {\n                Plugin.register(dependency);\n            }\n\n            var parsed = Plugin.dependencyParse(dependency),\n                resolved = Plugin.resolve(dependency);\n\n            if (resolved && !Plugin.versionSatisfies(resolved.version, parsed.range)) {\n                Common.warn(\n                    'Plugin.dependencies:', Plugin.toString(resolved), 'does not satisfy',\n                    Plugin.toString(parsed), 'used by', Plugin.toString(parsedBase) + '.'\n                );\n\n                resolved._warned = true;\n                module._warned = true;\n            } else if (!resolved) {\n                Common.warn(\n                    'Plugin.dependencies:', Plugin.toString(dependency), 'used by',\n                    Plugin.toString(parsedBase), 'could not be resolved.'\n                );\n\n                module._warned = true;\n            }\n\n            return parsed.name;\n        });\n\n        for (var i = 0; i < tracked[name].length; i += 1) {\n            Plugin.dependencies(tracked[name][i], tracked);\n        }\n\n        return tracked;\n    };\n\n    /**\n     * Parses a dependency string into its components.\n     * The `dependency` is a string of the format `'module-name'` or `'module-name@version'`.\n     * See documentation for `Plugin.versionParse` for a description of the format.\n     * This function can also handle dependencies that are already resolved (e.g. a module object).\n     * @method dependencyParse\n     * @param dependency {string} The dependency of the format `'module-name'` or `'module-name@version'`.\n     * @return {object} The dependency parsed into its components.\n     */\n    Plugin.dependencyParse = function(dependency) {\n        if (Common.isString(dependency)) {\n            var pattern = /^[\\w-]+(@(\\*|[\\^~]?\\d+\\.\\d+\\.\\d+(-[0-9A-Za-z-+]+)?))?$/;\n\n            if (!pattern.test(dependency)) {\n                Common.warn('Plugin.dependencyParse:', dependency, 'is not a valid dependency string.');\n            }\n\n            return {\n                name: dependency.split('@')[0],\n                range: dependency.split('@')[1] || '*'\n            };\n        }\n\n        return {\n            name: dependency.name,\n            range: dependency.range || dependency.version\n        };\n    };\n\n    /**\n     * Parses a version string into its components.  \n     * Versions are strictly of the format `x.y.z` (as in [semver](http://semver.org/)).\n     * Versions may optionally have a prerelease tag in the format `x.y.z-alpha`.\n     * Ranges are a strict subset of [npm ranges](https://docs.npmjs.com/misc/semver#advanced-range-syntax).\n     * Only the following range types are supported:\n     * - Tilde ranges e.g. `~1.2.3`\n     * - Caret ranges e.g. `^1.2.3`\n     * - Greater than ranges e.g. `>1.2.3`\n     * - Greater than or equal ranges e.g. `>=1.2.3`\n     * - Exact version e.g. `1.2.3`\n     * - Any version `*`\n     * @method versionParse\n     * @param range {string} The version string.\n     * @return {object} The version range parsed into its components.\n     */\n    Plugin.versionParse = function(range) {\n        var pattern = /^(\\*)|(\\^|~|>=|>)?\\s*((\\d+)\\.(\\d+)\\.(\\d+))(-[0-9A-Za-z-+]+)?$/;\n\n        if (!pattern.test(range)) {\n            Common.warn('Plugin.versionParse:', range, 'is not a valid version or range.');\n        }\n\n        var parts = pattern.exec(range);\n        var major = Number(parts[4]);\n        var minor = Number(parts[5]);\n        var patch = Number(parts[6]);\n\n        return {\n            isRange: Boolean(parts[1] || parts[2]),\n            version: parts[3],\n            range: range,\n            operator: parts[1] || parts[2] || '',\n            major: major,\n            minor: minor,\n            patch: patch,\n            parts: [major, minor, patch],\n            prerelease: parts[7],\n            number: major * 1e8 + minor * 1e4 + patch\n        };\n    };\n\n    /**\n     * Returns `true` if `version` satisfies the given `range`.\n     * See documentation for `Plugin.versionParse` for a description of the format.\n     * If a version or range is not specified, then any version (`*`) is assumed to satisfy.\n     * @method versionSatisfies\n     * @param version {string} The version string.\n     * @param range {string} The range string.\n     * @return {boolean} `true` if `version` satisfies `range`, otherwise `false`.\n     */\n    Plugin.versionSatisfies = function(version, range) {\n        range = range || '*';\n\n        var r = Plugin.versionParse(range),\n            v = Plugin.versionParse(version);\n\n        if (r.isRange) {\n            if (r.operator === '*' || version === '*') {\n                return true;\n            }\n\n            if (r.operator === '>') {\n                return v.number > r.number;\n            }\n\n            if (r.operator === '>=') {\n                return v.number >= r.number;\n            }\n\n            if (r.operator === '~') {\n                return v.major === r.major && v.minor === r.minor && v.patch >= r.patch;\n            }\n\n            if (r.operator === '^') {\n                if (r.major > 0) {\n                    return v.major === r.major && v.number >= r.number;\n                }\n\n                if (r.minor > 0) {\n                    return v.minor === r.minor && v.patch >= r.patch;\n                }\n\n                return v.patch === r.patch;\n            }\n        }\n\n        return version === range || version === '*';\n    };\n\n})();\n\n\n/***/ }),\n/* 16 */\n/***/ (function(module, exports) {\n\n/**\n* The `Matter.Contact` module contains methods for creating and manipulating collision contacts.\n*\n* @class Contact\n*/\n\nvar Contact = {};\n\nmodule.exports = Contact;\n\n(function() {\n\n    /**\n     * Creates a new contact.\n     * @method create\n     * @param {vertex} vertex\n     * @return {contact} A new contact\n     */\n    Contact.create = function(vertex) {\n        return {\n            vertex: vertex,\n            normalImpulse: 0,\n            tangentImpulse: 0\n        };\n    };\n\n})();\n\n\n/***/ }),\n/* 17 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Engine` module contains methods for creating and manipulating engines.\n* An engine is a controller that manages updating the simulation of the world.\n* See `Matter.Runner` for an optional game loop utility.\n*\n* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).\n*\n* @class Engine\n*/\n\nvar Engine = {};\n\nmodule.exports = Engine;\n\nvar Sleeping = __webpack_require__(7);\nvar Resolver = __webpack_require__(18);\nvar Detector = __webpack_require__(13);\nvar Pairs = __webpack_require__(19);\nvar Events = __webpack_require__(5);\nvar Composite = __webpack_require__(6);\nvar Constraint = __webpack_require__(10);\nvar Common = __webpack_require__(0);\nvar Body = __webpack_require__(4);\n\n(function() {\n\n    /**\n     * Creates a new engine. The options parameter is an object that specifies any properties you wish to override the defaults.\n     * All properties have default values, and many are pre-calculated automatically based on other properties.\n     * See the properties section below for detailed information on what you can pass via the `options` object.\n     * @method create\n     * @param {object} [options]\n     * @return {engine} engine\n     */\n    Engine.create = function(options) {\n        options = options || {};\n\n        var defaults = {\n            positionIterations: 6,\n            velocityIterations: 4,\n            constraintIterations: 2,\n            enableSleeping: false,\n            events: [],\n            plugin: {},\n            gravity: {\n                x: 0,\n                y: 1,\n                scale: 0.001\n            },\n            timing: {\n                timestamp: 0,\n                timeScale: 1,\n                lastDelta: 0,\n                lastElapsed: 0\n            }\n        };\n\n        var engine = Common.extend(defaults, options);\n\n        engine.world = options.world || Composite.create({ label: 'World' });\n        engine.pairs = options.pairs || Pairs.create();\n        engine.detector = options.detector || Detector.create();\n\n        // for temporary back compatibility only\n        engine.grid = { buckets: [] };\n        engine.world.gravity = engine.gravity;\n        engine.broadphase = engine.grid;\n        engine.metrics = {};\n        \n        return engine;\n    };\n\n    /**\n     * Moves the simulation forward in time by `delta` milliseconds.\n     * Triggers `beforeUpdate` and `afterUpdate` events.\n     * Triggers `collisionStart`, `collisionActive` and `collisionEnd` events.\n     * @method update\n     * @param {engine} engine\n     * @param {number} [delta=16.666]\n     */\n    Engine.update = function(engine, delta) {\n        var startTime = Common.now();\n\n        var world = engine.world,\n            detector = engine.detector,\n            pairs = engine.pairs,\n            timing = engine.timing,\n            timestamp = timing.timestamp,\n            i;\n\n        delta = typeof delta !== 'undefined' ? delta : Common._baseDelta;\n        delta *= timing.timeScale;\n\n        // increment timestamp\n        timing.timestamp += delta;\n        timing.lastDelta = delta;\n\n        // create an event object\n        var event = {\n            timestamp: timing.timestamp,\n            delta: delta\n        };\n\n        Events.trigger(engine, 'beforeUpdate', event);\n\n        // get all bodies and all constraints in the world\n        var allBodies = Composite.allBodies(world),\n            allConstraints = Composite.allConstraints(world);\n\n        // if the world has changed\n        if (world.isModified) {\n            // update the detector bodies\n            Detector.setBodies(detector, allBodies);\n\n            // reset all composite modified flags\n            Composite.setModified(world, false, false, true);\n        }\n\n        // update sleeping if enabled\n        if (engine.enableSleeping)\n            Sleeping.update(allBodies, delta);\n\n        // apply gravity to all bodies\n        Engine._bodiesApplyGravity(allBodies, engine.gravity);\n\n        // update all body position and rotation by integration\n        if (delta > 0) {\n            Engine._bodiesUpdate(allBodies, delta);\n        }\n\n        // update all constraints (first pass)\n        Constraint.preSolveAll(allBodies);\n        for (i = 0; i < engine.constraintIterations; i++) {\n            Constraint.solveAll(allConstraints, delta);\n        }\n        Constraint.postSolveAll(allBodies);\n\n        // find all collisions\n        detector.pairs = engine.pairs;\n        var collisions = Detector.collisions(detector);\n\n        // update collision pairs\n        Pairs.update(pairs, collisions, timestamp);\n\n        // wake up bodies involved in collisions\n        if (engine.enableSleeping)\n            Sleeping.afterCollisions(pairs.list);\n\n        // trigger collision events\n        if (pairs.collisionStart.length > 0)\n            Events.trigger(engine, 'collisionStart', { pairs: pairs.collisionStart });\n\n        // iteratively resolve position between collisions\n        var positionDamping = Common.clamp(20 / engine.positionIterations, 0, 1);\n        \n        Resolver.preSolvePosition(pairs.list);\n        for (i = 0; i < engine.positionIterations; i++) {\n            Resolver.solvePosition(pairs.list, delta, positionDamping);\n        }\n        Resolver.postSolvePosition(allBodies);\n\n        // update all constraints (second pass)\n        Constraint.preSolveAll(allBodies);\n        for (i = 0; i < engine.constraintIterations; i++) {\n            Constraint.solveAll(allConstraints, delta);\n        }\n        Constraint.postSolveAll(allBodies);\n\n        // iteratively resolve velocity between collisions\n        Resolver.preSolveVelocity(pairs.list);\n        for (i = 0; i < engine.velocityIterations; i++) {\n            Resolver.solveVelocity(pairs.list, delta);\n        }\n\n        // update body speed and velocity properties\n        Engine._bodiesUpdateVelocities(allBodies);\n\n        // trigger collision events\n        if (pairs.collisionActive.length > 0)\n            Events.trigger(engine, 'collisionActive', { pairs: pairs.collisionActive });\n\n        if (pairs.collisionEnd.length > 0)\n            Events.trigger(engine, 'collisionEnd', { pairs: pairs.collisionEnd });\n\n        // clear force buffers\n        Engine._bodiesClearForces(allBodies);\n\n        Events.trigger(engine, 'afterUpdate', event);\n\n        // log the time elapsed computing this update\n        engine.timing.lastElapsed = Common.now() - startTime;\n\n        return engine;\n    };\n    \n    /**\n     * Merges two engines by keeping the configuration of `engineA` but replacing the world with the one from `engineB`.\n     * @method merge\n     * @param {engine} engineA\n     * @param {engine} engineB\n     */\n    Engine.merge = function(engineA, engineB) {\n        Common.extend(engineA, engineB);\n        \n        if (engineB.world) {\n            engineA.world = engineB.world;\n\n            Engine.clear(engineA);\n\n            var bodies = Composite.allBodies(engineA.world);\n\n            for (var i = 0; i < bodies.length; i++) {\n                var body = bodies[i];\n                Sleeping.set(body, false);\n                body.id = Common.nextId();\n            }\n        }\n    };\n\n    /**\n     * Clears the engine pairs and detector.\n     * @method clear\n     * @param {engine} engine\n     */\n    Engine.clear = function(engine) {\n        Pairs.clear(engine.pairs);\n        Detector.clear(engine.detector);\n    };\n\n    /**\n     * Zeroes the `body.force` and `body.torque` force buffers.\n     * @method _bodiesClearForces\n     * @private\n     * @param {body[]} bodies\n     */\n    Engine._bodiesClearForces = function(bodies) {\n        var bodiesLength = bodies.length;\n\n        for (var i = 0; i < bodiesLength; i++) {\n            var body = bodies[i];\n\n            // reset force buffers\n            body.force.x = 0;\n            body.force.y = 0;\n            body.torque = 0;\n        }\n    };\n\n    /**\n     * Applies gravitational acceleration to all `bodies`.\n     * This models a [uniform gravitational field](https://en.wikipedia.org/wiki/Gravity_of_Earth), similar to near the surface of a planet.\n     * \n     * @method _bodiesApplyGravity\n     * @private\n     * @param {body[]} bodies\n     * @param {vector} gravity\n     */\n    Engine._bodiesApplyGravity = function(bodies, gravity) {\n        var gravityScale = typeof gravity.scale !== 'undefined' ? gravity.scale : 0.001,\n            bodiesLength = bodies.length;\n\n        if ((gravity.x === 0 && gravity.y === 0) || gravityScale === 0) {\n            return;\n        }\n        \n        for (var i = 0; i < bodiesLength; i++) {\n            var body = bodies[i];\n\n            if (body.isStatic || body.isSleeping)\n                continue;\n\n            // add the resultant force of gravity\n            body.force.y += body.mass * gravity.y * gravityScale;\n            body.force.x += body.mass * gravity.x * gravityScale;\n        }\n    };\n\n    /**\n     * Applies `Body.update` to all given `bodies`.\n     * @method _bodiesUpdate\n     * @private\n     * @param {body[]} bodies\n     * @param {number} delta The amount of time elapsed between updates\n     */\n    Engine._bodiesUpdate = function(bodies, delta) {\n        var bodiesLength = bodies.length;\n\n        for (var i = 0; i < bodiesLength; i++) {\n            var body = bodies[i];\n\n            if (body.isStatic || body.isSleeping)\n                continue;\n\n            Body.update(body, delta);\n        }\n    };\n\n    /**\n     * Applies `Body.updateVelocities` to all given `bodies`.\n     * @method _bodiesUpdateVelocities\n     * @private\n     * @param {body[]} bodies\n     */\n    Engine._bodiesUpdateVelocities = function(bodies) {\n        var bodiesLength = bodies.length;\n\n        for (var i = 0; i < bodiesLength; i++) {\n            Body.updateVelocities(bodies[i]);\n        }\n    };\n\n    /**\n     * A deprecated alias for `Runner.run`, use `Matter.Runner.run(engine)` instead and see `Matter.Runner` for more information.\n     * @deprecated use Matter.Runner.run(engine) instead\n     * @method run\n     * @param {engine} engine\n     */\n\n    /**\n    * Fired just before an update\n    *\n    * @event beforeUpdate\n    * @param {object} event An event object\n    * @param {number} event.timestamp The engine.timing.timestamp of the event\n    * @param {number} event.delta The delta time in milliseconds value used in the update\n    * @param {engine} event.source The source object of the event\n    * @param {string} event.name The name of the event\n    */\n\n    /**\n    * Fired after engine update and all collision events\n    *\n    * @event afterUpdate\n    * @param {object} event An event object\n    * @param {number} event.timestamp The engine.timing.timestamp of the event\n    * @param {number} event.delta The delta time in milliseconds value used in the update\n    * @param {engine} event.source The source object of the event\n    * @param {string} event.name The name of the event\n    */\n\n    /**\n    * Fired after engine update, provides a list of all pairs that have started to collide in the current tick (if any)\n    *\n    * @event collisionStart\n    * @param {object} event An event object\n    * @param {pair[]} event.pairs List of affected pairs\n    * @param {number} event.timestamp The engine.timing.timestamp of the event\n    * @param {number} event.delta The delta time in milliseconds value used in the update\n    * @param {engine} event.source The source object of the event\n    * @param {string} event.name The name of the event\n    */\n\n    /**\n    * Fired after engine update, provides a list of all pairs that are colliding in the current tick (if any)\n    *\n    * @event collisionActive\n    * @param {object} event An event object\n    * @param {pair[]} event.pairs List of affected pairs\n    * @param {number} event.timestamp The engine.timing.timestamp of the event\n    * @param {number} event.delta The delta time in milliseconds value used in the update\n    * @param {engine} event.source The source object of the event\n    * @param {string} event.name The name of the event\n    */\n\n    /**\n    * Fired after engine update, provides a list of all pairs that have ended collision in the current tick (if any)\n    *\n    * @event collisionEnd\n    * @param {object} event An event object\n    * @param {pair[]} event.pairs List of affected pairs\n    * @param {number} event.timestamp The engine.timing.timestamp of the event\n    * @param {number} event.delta The delta time in milliseconds value used in the update\n    * @param {engine} event.source The source object of the event\n    * @param {string} event.name The name of the event\n    */\n\n    /*\n    *\n    *  Properties Documentation\n    *\n    */\n\n    /**\n     * An integer `Number` that specifies the number of position iterations to perform each update.\n     * The higher the value, the higher quality the simulation will be at the expense of performance.\n     *\n     * @property positionIterations\n     * @type number\n     * @default 6\n     */\n\n    /**\n     * An integer `Number` that specifies the number of velocity iterations to perform each update.\n     * The higher the value, the higher quality the simulation will be at the expense of performance.\n     *\n     * @property velocityIterations\n     * @type number\n     * @default 4\n     */\n\n    /**\n     * An integer `Number` that specifies the number of constraint iterations to perform each update.\n     * The higher the value, the higher quality the simulation will be at the expense of performance.\n     * The default value of `2` is usually very adequate.\n     *\n     * @property constraintIterations\n     * @type number\n     * @default 2\n     */\n\n    /**\n     * A flag that specifies whether the engine should allow sleeping via the `Matter.Sleeping` module.\n     * Sleeping can improve stability and performance, but often at the expense of accuracy.\n     *\n     * @property enableSleeping\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * An `Object` containing properties regarding the timing systems of the engine. \n     *\n     * @property timing\n     * @type object\n     */\n\n    /**\n     * A `Number` that specifies the global scaling factor of time for all bodies.\n     * A value of `0` freezes the simulation.\n     * A value of `0.1` gives a slow-motion effect.\n     * A value of `1.2` gives a speed-up effect.\n     *\n     * @property timing.timeScale\n     * @type number\n     * @default 1\n     */\n\n    /**\n     * A `Number` that specifies the current simulation-time in milliseconds starting from `0`. \n     * It is incremented on every `Engine.update` by the given `delta` argument. \n     * \n     * @property timing.timestamp\n     * @type number\n     * @default 0\n     */\n\n    /**\n     * A `Number` that represents the total execution time elapsed during the last `Engine.update` in milliseconds.\n     * It is updated by timing from the start of the last `Engine.update` call until it ends.\n     *\n     * This value will also include the total execution time of all event handlers directly or indirectly triggered by the engine update.\n     * \n     * @property timing.lastElapsed\n     * @type number\n     * @default 0\n     */\n\n    /**\n     * A `Number` that represents the `delta` value used in the last engine update.\n     * \n     * @property timing.lastDelta\n     * @type number\n     * @default 0\n     */\n\n    /**\n     * A `Matter.Detector` instance.\n     *\n     * @property detector\n     * @type detector\n     * @default a Matter.Detector instance\n     */\n\n    /**\n     * A `Matter.Grid` instance.\n     *\n     * @deprecated replaced by `engine.detector`\n     * @property grid\n     * @type grid\n     * @default a Matter.Grid instance\n     */\n\n    /**\n     * Replaced by and now alias for `engine.grid`.\n     *\n     * @deprecated replaced by `engine.detector`\n     * @property broadphase\n     * @type grid\n     * @default a Matter.Grid instance\n     */\n\n    /**\n     * The root `Matter.Composite` instance that will contain all bodies, constraints and other composites to be simulated by this engine.\n     *\n     * @property world\n     * @type composite\n     * @default a Matter.Composite instance\n     */\n\n    /**\n     * An object reserved for storing plugin-specific properties.\n     *\n     * @property plugin\n     * @type {}\n     */\n\n    /**\n     * An optional gravitational acceleration applied to all bodies in `engine.world` on every update.\n     * \n     * This models a [uniform gravitational field](https://en.wikipedia.org/wiki/Gravity_of_Earth), similar to near the surface of a planet. For gravity in other contexts, disable this and apply forces as needed.\n     * \n     * To disable set the `scale` component to `0`.\n     * \n     * This is split into three components for ease of use:  \n     * a normalised direction (`x` and `y`) and magnitude (`scale`).\n     *\n     * @property gravity\n     * @type object\n     */\n\n    /**\n     * The gravitational direction normal `x` component, to be multiplied by `gravity.scale`.\n     * \n     * @property gravity.x\n     * @type object\n     * @default 0\n     */\n\n    /**\n     * The gravitational direction normal `y` component, to be multiplied by `gravity.scale`.\n     *\n     * @property gravity.y\n     * @type object\n     * @default 1\n     */\n\n    /**\n     * The magnitude of the gravitational acceleration.\n     * \n     * @property gravity.scale\n     * @type object\n     * @default 0.001\n     */\n\n})();\n\n\n/***/ }),\n/* 18 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Resolver` module contains methods for resolving collision pairs.\n*\n* @class Resolver\n*/\n\nvar Resolver = {};\n\nmodule.exports = Resolver;\n\nvar Vertices = __webpack_require__(3);\nvar Common = __webpack_require__(0);\nvar Bounds = __webpack_require__(1);\n\n(function() {\n\n    Resolver._restingThresh = 2;\n    Resolver._restingThreshTangent = Math.sqrt(6);\n    Resolver._positionDampen = 0.9;\n    Resolver._positionWarming = 0.8;\n    Resolver._frictionNormalMultiplier = 5;\n    Resolver._frictionMaxStatic = Number.MAX_VALUE;\n\n    /**\n     * Prepare pairs for position solving.\n     * @method preSolvePosition\n     * @param {pair[]} pairs\n     */\n    Resolver.preSolvePosition = function(pairs) {\n        var i,\n            pair,\n            activeCount,\n            pairsLength = pairs.length;\n\n        // find total contacts on each body\n        for (i = 0; i < pairsLength; i++) {\n            pair = pairs[i];\n            \n            if (!pair.isActive)\n                continue;\n            \n            activeCount = pair.activeContacts.length;\n            pair.collision.parentA.totalContacts += activeCount;\n            pair.collision.parentB.totalContacts += activeCount;\n        }\n    };\n\n    /**\n     * Find a solution for pair positions.\n     * @method solvePosition\n     * @param {pair[]} pairs\n     * @param {number} delta\n     * @param {number} [damping=1]\n     */\n    Resolver.solvePosition = function(pairs, delta, damping) {\n        var i,\n            pair,\n            collision,\n            bodyA,\n            bodyB,\n            normal,\n            contactShare,\n            positionImpulse,\n            positionDampen = Resolver._positionDampen * (damping || 1),\n            slopDampen = Common.clamp(delta / Common._baseDelta, 0, 1),\n            pairsLength = pairs.length;\n\n        // find impulses required to resolve penetration\n        for (i = 0; i < pairsLength; i++) {\n            pair = pairs[i];\n            \n            if (!pair.isActive || pair.isSensor)\n                continue;\n\n            collision = pair.collision;\n            bodyA = collision.parentA;\n            bodyB = collision.parentB;\n            normal = collision.normal;\n\n            // get current separation between body edges involved in collision\n            pair.separation = \n                normal.x * (bodyB.positionImpulse.x + collision.penetration.x - bodyA.positionImpulse.x)\n                + normal.y * (bodyB.positionImpulse.y + collision.penetration.y - bodyA.positionImpulse.y);\n        }\n        \n        for (i = 0; i < pairsLength; i++) {\n            pair = pairs[i];\n\n            if (!pair.isActive || pair.isSensor)\n                continue;\n            \n            collision = pair.collision;\n            bodyA = collision.parentA;\n            bodyB = collision.parentB;\n            normal = collision.normal;\n            positionImpulse = pair.separation - pair.slop * slopDampen;\n\n            if (bodyA.isStatic || bodyB.isStatic)\n                positionImpulse *= 2;\n            \n            if (!(bodyA.isStatic || bodyA.isSleeping)) {\n                contactShare = positionDampen / bodyA.totalContacts;\n                bodyA.positionImpulse.x += normal.x * positionImpulse * contactShare;\n                bodyA.positionImpulse.y += normal.y * positionImpulse * contactShare;\n            }\n\n            if (!(bodyB.isStatic || bodyB.isSleeping)) {\n                contactShare = positionDampen / bodyB.totalContacts;\n                bodyB.positionImpulse.x -= normal.x * positionImpulse * contactShare;\n                bodyB.positionImpulse.y -= normal.y * positionImpulse * contactShare;\n            }\n        }\n    };\n\n    /**\n     * Apply position resolution.\n     * @method postSolvePosition\n     * @param {body[]} bodies\n     */\n    Resolver.postSolvePosition = function(bodies) {\n        var positionWarming = Resolver._positionWarming,\n            bodiesLength = bodies.length,\n            verticesTranslate = Vertices.translate,\n            boundsUpdate = Bounds.update;\n\n        for (var i = 0; i < bodiesLength; i++) {\n            var body = bodies[i],\n                positionImpulse = body.positionImpulse,\n                positionImpulseX = positionImpulse.x,\n                positionImpulseY = positionImpulse.y,\n                velocity = body.velocity;\n\n            // reset contact count\n            body.totalContacts = 0;\n\n            if (positionImpulseX !== 0 || positionImpulseY !== 0) {\n                // update body geometry\n                for (var j = 0; j < body.parts.length; j++) {\n                    var part = body.parts[j];\n                    verticesTranslate(part.vertices, positionImpulse);\n                    boundsUpdate(part.bounds, part.vertices, velocity);\n                    part.position.x += positionImpulseX;\n                    part.position.y += positionImpulseY;\n                }\n\n                // move the body without changing velocity\n                body.positionPrev.x += positionImpulseX;\n                body.positionPrev.y += positionImpulseY;\n\n                if (positionImpulseX * velocity.x + positionImpulseY * velocity.y < 0) {\n                    // reset cached impulse if the body has velocity along it\n                    positionImpulse.x = 0;\n                    positionImpulse.y = 0;\n                } else {\n                    // warm the next iteration\n                    positionImpulse.x *= positionWarming;\n                    positionImpulse.y *= positionWarming;\n                }\n            }\n        }\n    };\n\n    /**\n     * Prepare pairs for velocity solving.\n     * @method preSolveVelocity\n     * @param {pair[]} pairs\n     */\n    Resolver.preSolveVelocity = function(pairs) {\n        var pairsLength = pairs.length,\n            i,\n            j;\n        \n        for (i = 0; i < pairsLength; i++) {\n            var pair = pairs[i];\n            \n            if (!pair.isActive || pair.isSensor)\n                continue;\n            \n            var contacts = pair.activeContacts,\n                contactsLength = contacts.length,\n                collision = pair.collision,\n                bodyA = collision.parentA,\n                bodyB = collision.parentB,\n                normal = collision.normal,\n                tangent = collision.tangent;\n    \n            // resolve each contact\n            for (j = 0; j < contactsLength; j++) {\n                var contact = contacts[j],\n                    contactVertex = contact.vertex,\n                    normalImpulse = contact.normalImpulse,\n                    tangentImpulse = contact.tangentImpulse;\n    \n                if (normalImpulse !== 0 || tangentImpulse !== 0) {\n                    // total impulse from contact\n                    var impulseX = normal.x * normalImpulse + tangent.x * tangentImpulse,\n                        impulseY = normal.y * normalImpulse + tangent.y * tangentImpulse;\n                    \n                    // apply impulse from contact\n                    if (!(bodyA.isStatic || bodyA.isSleeping)) {\n                        bodyA.positionPrev.x += impulseX * bodyA.inverseMass;\n                        bodyA.positionPrev.y += impulseY * bodyA.inverseMass;\n                        bodyA.anglePrev += bodyA.inverseInertia * (\n                            (contactVertex.x - bodyA.position.x) * impulseY\n                            - (contactVertex.y - bodyA.position.y) * impulseX\n                        );\n                    }\n    \n                    if (!(bodyB.isStatic || bodyB.isSleeping)) {\n                        bodyB.positionPrev.x -= impulseX * bodyB.inverseMass;\n                        bodyB.positionPrev.y -= impulseY * bodyB.inverseMass;\n                        bodyB.anglePrev -= bodyB.inverseInertia * (\n                            (contactVertex.x - bodyB.position.x) * impulseY \n                            - (contactVertex.y - bodyB.position.y) * impulseX\n                        );\n                    }\n                }\n            }\n        }\n    };\n\n    /**\n     * Find a solution for pair velocities.\n     * @method solveVelocity\n     * @param {pair[]} pairs\n     * @param {number} delta\n     */\n    Resolver.solveVelocity = function(pairs, delta) {\n        var timeScale = delta / Common._baseDelta,\n            timeScaleSquared = timeScale * timeScale,\n            timeScaleCubed = timeScaleSquared * timeScale,\n            restingThresh = -Resolver._restingThresh * timeScale,\n            restingThreshTangent = Resolver._restingThreshTangent,\n            frictionNormalMultiplier = Resolver._frictionNormalMultiplier * timeScale,\n            frictionMaxStatic = Resolver._frictionMaxStatic,\n            pairsLength = pairs.length,\n            tangentImpulse,\n            maxFriction,\n            i,\n            j;\n\n        for (i = 0; i < pairsLength; i++) {\n            var pair = pairs[i];\n            \n            if (!pair.isActive || pair.isSensor)\n                continue;\n            \n            var collision = pair.collision,\n                bodyA = collision.parentA,\n                bodyB = collision.parentB,\n                bodyAVelocity = bodyA.velocity,\n                bodyBVelocity = bodyB.velocity,\n                normalX = collision.normal.x,\n                normalY = collision.normal.y,\n                tangentX = collision.tangent.x,\n                tangentY = collision.tangent.y,\n                contacts = pair.activeContacts,\n                contactsLength = contacts.length,\n                contactShare = 1 / contactsLength,\n                inverseMassTotal = bodyA.inverseMass + bodyB.inverseMass,\n                friction = pair.friction * pair.frictionStatic * frictionNormalMultiplier;\n\n            // update body velocities\n            bodyAVelocity.x = bodyA.position.x - bodyA.positionPrev.x;\n            bodyAVelocity.y = bodyA.position.y - bodyA.positionPrev.y;\n            bodyBVelocity.x = bodyB.position.x - bodyB.positionPrev.x;\n            bodyBVelocity.y = bodyB.position.y - bodyB.positionPrev.y;\n            bodyA.angularVelocity = bodyA.angle - bodyA.anglePrev;\n            bodyB.angularVelocity = bodyB.angle - bodyB.anglePrev;\n\n            // resolve each contact\n            for (j = 0; j < contactsLength; j++) {\n                var contact = contacts[j],\n                    contactVertex = contact.vertex;\n\n                var offsetAX = contactVertex.x - bodyA.position.x,\n                    offsetAY = contactVertex.y - bodyA.position.y,\n                    offsetBX = contactVertex.x - bodyB.position.x,\n                    offsetBY = contactVertex.y - bodyB.position.y;\n \n                var velocityPointAX = bodyAVelocity.x - offsetAY * bodyA.angularVelocity,\n                    velocityPointAY = bodyAVelocity.y + offsetAX * bodyA.angularVelocity,\n                    velocityPointBX = bodyBVelocity.x - offsetBY * bodyB.angularVelocity,\n                    velocityPointBY = bodyBVelocity.y + offsetBX * bodyB.angularVelocity;\n\n                var relativeVelocityX = velocityPointAX - velocityPointBX,\n                    relativeVelocityY = velocityPointAY - velocityPointBY;\n\n                var normalVelocity = normalX * relativeVelocityX + normalY * relativeVelocityY,\n                    tangentVelocity = tangentX * relativeVelocityX + tangentY * relativeVelocityY;\n\n                // coulomb friction\n                var normalOverlap = pair.separation + normalVelocity;\n                var normalForce = Math.min(normalOverlap, 1);\n                normalForce = normalOverlap < 0 ? 0 : normalForce;\n\n                var frictionLimit = normalForce * friction;\n\n                if (tangentVelocity < -frictionLimit || tangentVelocity > frictionLimit) {\n                    maxFriction = (tangentVelocity > 0 ? tangentVelocity : -tangentVelocity);\n                    tangentImpulse = pair.friction * (tangentVelocity > 0 ? 1 : -1) * timeScaleCubed;\n                    \n                    if (tangentImpulse < -maxFriction) {\n                        tangentImpulse = -maxFriction;\n                    } else if (tangentImpulse > maxFriction) {\n                        tangentImpulse = maxFriction;\n                    }\n                } else {\n                    tangentImpulse = tangentVelocity;\n                    maxFriction = frictionMaxStatic;\n                }\n\n                // account for mass, inertia and contact offset\n                var oAcN = offsetAX * normalY - offsetAY * normalX,\n                    oBcN = offsetBX * normalY - offsetBY * normalX,\n                    share = contactShare / (inverseMassTotal + bodyA.inverseInertia * oAcN * oAcN + bodyB.inverseInertia * oBcN * oBcN);\n\n                // raw impulses\n                var normalImpulse = (1 + pair.restitution) * normalVelocity * share;\n                tangentImpulse *= share;\n\n                // handle high velocity and resting collisions separately\n                if (normalVelocity < restingThresh) {\n                    // high normal velocity so clear cached contact normal impulse\n                    contact.normalImpulse = 0;\n                } else {\n                    // solve resting collision constraints using Erin Catto's method (GDC08)\n                    // impulse constraint tends to 0\n                    var contactNormalImpulse = contact.normalImpulse;\n                    contact.normalImpulse += normalImpulse;\n                    if (contact.normalImpulse > 0) contact.normalImpulse = 0;\n                    normalImpulse = contact.normalImpulse - contactNormalImpulse;\n                }\n\n                // handle high velocity and resting collisions separately\n                if (tangentVelocity < -restingThreshTangent || tangentVelocity > restingThreshTangent) {\n                    // high tangent velocity so clear cached contact tangent impulse\n                    contact.tangentImpulse = 0;\n                } else {\n                    // solve resting collision constraints using Erin Catto's method (GDC08)\n                    // tangent impulse tends to -tangentSpeed or +tangentSpeed\n                    var contactTangentImpulse = contact.tangentImpulse;\n                    contact.tangentImpulse += tangentImpulse;\n                    if (contact.tangentImpulse < -maxFriction) contact.tangentImpulse = -maxFriction;\n                    if (contact.tangentImpulse > maxFriction) contact.tangentImpulse = maxFriction;\n                    tangentImpulse = contact.tangentImpulse - contactTangentImpulse;\n                }\n\n                // total impulse from contact\n                var impulseX = normalX * normalImpulse + tangentX * tangentImpulse,\n                    impulseY = normalY * normalImpulse + tangentY * tangentImpulse;\n                \n                // apply impulse from contact\n                if (!(bodyA.isStatic || bodyA.isSleeping)) {\n                    bodyA.positionPrev.x += impulseX * bodyA.inverseMass;\n                    bodyA.positionPrev.y += impulseY * bodyA.inverseMass;\n                    bodyA.anglePrev += (offsetAX * impulseY - offsetAY * impulseX) * bodyA.inverseInertia;\n                }\n\n                if (!(bodyB.isStatic || bodyB.isSleeping)) {\n                    bodyB.positionPrev.x -= impulseX * bodyB.inverseMass;\n                    bodyB.positionPrev.y -= impulseY * bodyB.inverseMass;\n                    bodyB.anglePrev -= (offsetBX * impulseY - offsetBY * impulseX) * bodyB.inverseInertia;\n                }\n            }\n        }\n    };\n\n})();\n\n\n/***/ }),\n/* 19 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Pairs` module contains methods for creating and manipulating collision pair sets.\n*\n* @class Pairs\n*/\n\nvar Pairs = {};\n\nmodule.exports = Pairs;\n\nvar Pair = __webpack_require__(9);\nvar Common = __webpack_require__(0);\n\n(function() {\n\n    /**\n     * Creates a new pairs structure.\n     * @method create\n     * @param {object} options\n     * @return {pairs} A new pairs structure\n     */\n    Pairs.create = function(options) {\n        return Common.extend({ \n            table: {},\n            list: [],\n            collisionStart: [],\n            collisionActive: [],\n            collisionEnd: []\n        }, options);\n    };\n\n    /**\n     * Updates pairs given a list of collisions.\n     * @method update\n     * @param {object} pairs\n     * @param {collision[]} collisions\n     * @param {number} timestamp\n     */\n    Pairs.update = function(pairs, collisions, timestamp) {\n        var pairsList = pairs.list,\n            pairsListLength = pairsList.length,\n            pairsTable = pairs.table,\n            collisionsLength = collisions.length,\n            collisionStart = pairs.collisionStart,\n            collisionEnd = pairs.collisionEnd,\n            collisionActive = pairs.collisionActive,\n            collision,\n            pairIndex,\n            pair,\n            i;\n\n        // clear collision state arrays, but maintain old reference\n        collisionStart.length = 0;\n        collisionEnd.length = 0;\n        collisionActive.length = 0;\n\n        for (i = 0; i < pairsListLength; i++) {\n            pairsList[i].confirmedActive = false;\n        }\n\n        for (i = 0; i < collisionsLength; i++) {\n            collision = collisions[i];\n            pair = collision.pair;\n\n            if (pair) {\n                // pair already exists (but may or may not be active)\n                if (pair.isActive) {\n                    // pair exists and is active\n                    collisionActive.push(pair);\n                } else {\n                    // pair exists but was inactive, so a collision has just started again\n                    collisionStart.push(pair);\n                }\n\n                // update the pair\n                Pair.update(pair, collision, timestamp);\n                pair.confirmedActive = true;\n            } else {\n                // pair did not exist, create a new pair\n                pair = Pair.create(collision, timestamp);\n                pairsTable[pair.id] = pair;\n\n                // push the new pair\n                collisionStart.push(pair);\n                pairsList.push(pair);\n            }\n        }\n\n        // find pairs that are no longer active\n        var removePairIndex = [];\n        pairsListLength = pairsList.length;\n\n        for (i = 0; i < pairsListLength; i++) {\n            pair = pairsList[i];\n            \n            if (!pair.confirmedActive) {\n                Pair.setActive(pair, false, timestamp);\n                collisionEnd.push(pair);\n\n                if (!pair.collision.bodyA.isSleeping && !pair.collision.bodyB.isSleeping) {\n                    removePairIndex.push(i);\n                }\n            }\n        }\n\n        // remove inactive pairs\n        for (i = 0; i < removePairIndex.length; i++) {\n            pairIndex = removePairIndex[i] - i;\n            pair = pairsList[pairIndex];\n            pairsList.splice(pairIndex, 1);\n            delete pairsTable[pair.id];\n        }\n    };\n\n    /**\n     * Clears the given pairs structure.\n     * @method clear\n     * @param {pairs} pairs\n     * @return {pairs} pairs\n     */\n    Pairs.clear = function(pairs) {\n        pairs.table = {};\n        pairs.list.length = 0;\n        pairs.collisionStart.length = 0;\n        pairs.collisionActive.length = 0;\n        pairs.collisionEnd.length = 0;\n        return pairs;\n    };\n\n})();\n\n\n/***/ }),\n/* 20 */\n/***/ (function(module, exports, __webpack_require__) {\n\nvar Matter = module.exports = __webpack_require__(21);\r\n\r\nMatter.Axes = __webpack_require__(11);\r\nMatter.Bodies = __webpack_require__(12);\r\nMatter.Body = __webpack_require__(4);\r\nMatter.Bounds = __webpack_require__(1);\r\nMatter.Collision = __webpack_require__(8);\r\nMatter.Common = __webpack_require__(0);\r\nMatter.Composite = __webpack_require__(6);\r\nMatter.Composites = __webpack_require__(22);\r\nMatter.Constraint = __webpack_require__(10);\r\nMatter.Contact = __webpack_require__(16);\r\nMatter.Detector = __webpack_require__(13);\r\nMatter.Engine = __webpack_require__(17);\r\nMatter.Events = __webpack_require__(5);\r\nMatter.Grid = __webpack_require__(23);\r\nMatter.Mouse = __webpack_require__(14);\r\nMatter.MouseConstraint = __webpack_require__(24);\r\nMatter.Pair = __webpack_require__(9);\r\nMatter.Pairs = __webpack_require__(19);\r\nMatter.Plugin = __webpack_require__(15);\r\nMatter.Query = __webpack_require__(25);\r\nMatter.Render = __webpack_require__(26);\r\nMatter.Resolver = __webpack_require__(18);\r\nMatter.Runner = __webpack_require__(27);\r\nMatter.SAT = __webpack_require__(28);\r\nMatter.Sleeping = __webpack_require__(7);\r\nMatter.Svg = __webpack_require__(29);\r\nMatter.Vector = __webpack_require__(2);\r\nMatter.Vertices = __webpack_require__(3);\r\nMatter.World = __webpack_require__(30);\r\n\r\n// temporary back compatibility\r\nMatter.Engine.run = Matter.Runner.run;\r\nMatter.Common.deprecated(Matter.Engine, 'run', 'Engine.run ➤ use Matter.Runner.run(engine) instead');\r\n\n\n/***/ }),\n/* 21 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\r\n* The `Matter` module is the top level namespace. It also includes a function for installing plugins on top of the library.\r\n*\r\n* @class Matter\r\n*/\r\n\r\nvar Matter = {};\r\n\r\nmodule.exports = Matter;\r\n\r\nvar Plugin = __webpack_require__(15);\r\nvar Common = __webpack_require__(0);\r\n\r\n(function() {\r\n\r\n    /**\r\n     * The library name.\r\n     * @property name\r\n     * @readOnly\r\n     * @type {String}\r\n     */\r\n    Matter.name = 'matter-js';\r\n\r\n    /**\r\n     * The library version.\r\n     * @property version\r\n     * @readOnly\r\n     * @type {String}\r\n     */\r\n    Matter.version =  true ? \"0.19.0\" : undefined;\r\n\r\n    /**\r\n     * A list of plugin dependencies to be installed. These are normally set and installed through `Matter.use`.\r\n     * Alternatively you may set `Matter.uses` manually and install them by calling `Plugin.use(Matter)`.\r\n     * @property uses\r\n     * @type {Array}\r\n     */\r\n    Matter.uses = [];\r\n\r\n    /**\r\n     * The plugins that have been installed through `Matter.Plugin.install`. Read only.\r\n     * @property used\r\n     * @readOnly\r\n     * @type {Array}\r\n     */\r\n    Matter.used = [];\r\n\r\n    /**\r\n     * Installs the given plugins on the `Matter` namespace.\r\n     * This is a short-hand for `Plugin.use`, see it for more information.\r\n     * Call this function once at the start of your code, with all of the plugins you wish to install as arguments.\r\n     * Avoid calling this function multiple times unless you intend to manually control installation order.\r\n     * @method use\r\n     * @param ...plugin {Function} The plugin(s) to install on `base` (multi-argument).\r\n     */\r\n    Matter.use = function() {\r\n        Plugin.use(Matter, Array.prototype.slice.call(arguments));\r\n    };\r\n\r\n    /**\r\n     * Chains a function to excute before the original function on the given `path` relative to `Matter`.\r\n     * See also docs for `Common.chain`.\r\n     * @method before\r\n     * @param {string} path The path relative to `Matter`\r\n     * @param {function} func The function to chain before the original\r\n     * @return {function} The chained function that replaced the original\r\n     */\r\n    Matter.before = function(path, func) {\r\n        path = path.replace(/^Matter./, '');\r\n        return Common.chainPathBefore(Matter, path, func);\r\n    };\r\n\r\n    /**\r\n     * Chains a function to excute after the original function on the given `path` relative to `Matter`.\r\n     * See also docs for `Common.chain`.\r\n     * @method after\r\n     * @param {string} path The path relative to `Matter`\r\n     * @param {function} func The function to chain after the original\r\n     * @return {function} The chained function that replaced the original\r\n     */\r\n    Matter.after = function(path, func) {\r\n        path = path.replace(/^Matter./, '');\r\n        return Common.chainPathAfter(Matter, path, func);\r\n    };\r\n\r\n})();\r\n\n\n/***/ }),\n/* 22 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Composites` module contains factory methods for creating composite bodies\n* with commonly used configurations (such as stacks and chains).\n*\n* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).\n*\n* @class Composites\n*/\n\nvar Composites = {};\n\nmodule.exports = Composites;\n\nvar Composite = __webpack_require__(6);\nvar Constraint = __webpack_require__(10);\nvar Common = __webpack_require__(0);\nvar Body = __webpack_require__(4);\nvar Bodies = __webpack_require__(12);\nvar deprecated = Common.deprecated;\n\n(function() {\n\n    /**\n     * Create a new composite containing bodies created in the callback in a grid arrangement.\n     * This function uses the body's bounds to prevent overlaps.\n     * @method stack\n     * @param {number} xx\n     * @param {number} yy\n     * @param {number} columns\n     * @param {number} rows\n     * @param {number} columnGap\n     * @param {number} rowGap\n     * @param {function} callback\n     * @return {composite} A new composite containing objects created in the callback\n     */\n    Composites.stack = function(xx, yy, columns, rows, columnGap, rowGap, callback) {\n        var stack = Composite.create({ label: 'Stack' }),\n            x = xx,\n            y = yy,\n            lastBody,\n            i = 0;\n\n        for (var row = 0; row < rows; row++) {\n            var maxHeight = 0;\n            \n            for (var column = 0; column < columns; column++) {\n                var body = callback(x, y, column, row, lastBody, i);\n                    \n                if (body) {\n                    var bodyHeight = body.bounds.max.y - body.bounds.min.y,\n                        bodyWidth = body.bounds.max.x - body.bounds.min.x; \n\n                    if (bodyHeight > maxHeight)\n                        maxHeight = bodyHeight;\n                    \n                    Body.translate(body, { x: bodyWidth * 0.5, y: bodyHeight * 0.5 });\n\n                    x = body.bounds.max.x + columnGap;\n\n                    Composite.addBody(stack, body);\n                    \n                    lastBody = body;\n                    i += 1;\n                } else {\n                    x += columnGap;\n                }\n            }\n            \n            y += maxHeight + rowGap;\n            x = xx;\n        }\n\n        return stack;\n    };\n    \n    /**\n     * Chains all bodies in the given composite together using constraints.\n     * @method chain\n     * @param {composite} composite\n     * @param {number} xOffsetA\n     * @param {number} yOffsetA\n     * @param {number} xOffsetB\n     * @param {number} yOffsetB\n     * @param {object} options\n     * @return {composite} A new composite containing objects chained together with constraints\n     */\n    Composites.chain = function(composite, xOffsetA, yOffsetA, xOffsetB, yOffsetB, options) {\n        var bodies = composite.bodies;\n        \n        for (var i = 1; i < bodies.length; i++) {\n            var bodyA = bodies[i - 1],\n                bodyB = bodies[i],\n                bodyAHeight = bodyA.bounds.max.y - bodyA.bounds.min.y,\n                bodyAWidth = bodyA.bounds.max.x - bodyA.bounds.min.x, \n                bodyBHeight = bodyB.bounds.max.y - bodyB.bounds.min.y,\n                bodyBWidth = bodyB.bounds.max.x - bodyB.bounds.min.x;\n        \n            var defaults = {\n                bodyA: bodyA,\n                pointA: { x: bodyAWidth * xOffsetA, y: bodyAHeight * yOffsetA },\n                bodyB: bodyB,\n                pointB: { x: bodyBWidth * xOffsetB, y: bodyBHeight * yOffsetB }\n            };\n            \n            var constraint = Common.extend(defaults, options);\n        \n            Composite.addConstraint(composite, Constraint.create(constraint));\n        }\n\n        composite.label += ' Chain';\n        \n        return composite;\n    };\n\n    /**\n     * Connects bodies in the composite with constraints in a grid pattern, with optional cross braces.\n     * @method mesh\n     * @param {composite} composite\n     * @param {number} columns\n     * @param {number} rows\n     * @param {boolean} crossBrace\n     * @param {object} options\n     * @return {composite} The composite containing objects meshed together with constraints\n     */\n    Composites.mesh = function(composite, columns, rows, crossBrace, options) {\n        var bodies = composite.bodies,\n            row,\n            col,\n            bodyA,\n            bodyB,\n            bodyC;\n        \n        for (row = 0; row < rows; row++) {\n            for (col = 1; col < columns; col++) {\n                bodyA = bodies[(col - 1) + (row * columns)];\n                bodyB = bodies[col + (row * columns)];\n                Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyA, bodyB: bodyB }, options)));\n            }\n\n            if (row > 0) {\n                for (col = 0; col < columns; col++) {\n                    bodyA = bodies[col + ((row - 1) * columns)];\n                    bodyB = bodies[col + (row * columns)];\n                    Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyA, bodyB: bodyB }, options)));\n\n                    if (crossBrace && col > 0) {\n                        bodyC = bodies[(col - 1) + ((row - 1) * columns)];\n                        Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyC, bodyB: bodyB }, options)));\n                    }\n\n                    if (crossBrace && col < columns - 1) {\n                        bodyC = bodies[(col + 1) + ((row - 1) * columns)];\n                        Composite.addConstraint(composite, Constraint.create(Common.extend({ bodyA: bodyC, bodyB: bodyB }, options)));\n                    }\n                }\n            }\n        }\n\n        composite.label += ' Mesh';\n        \n        return composite;\n    };\n    \n    /**\n     * Create a new composite containing bodies created in the callback in a pyramid arrangement.\n     * This function uses the body's bounds to prevent overlaps.\n     * @method pyramid\n     * @param {number} xx\n     * @param {number} yy\n     * @param {number} columns\n     * @param {number} rows\n     * @param {number} columnGap\n     * @param {number} rowGap\n     * @param {function} callback\n     * @return {composite} A new composite containing objects created in the callback\n     */\n    Composites.pyramid = function(xx, yy, columns, rows, columnGap, rowGap, callback) {\n        return Composites.stack(xx, yy, columns, rows, columnGap, rowGap, function(x, y, column, row, lastBody, i) {\n            var actualRows = Math.min(rows, Math.ceil(columns / 2)),\n                lastBodyWidth = lastBody ? lastBody.bounds.max.x - lastBody.bounds.min.x : 0;\n            \n            if (row > actualRows)\n                return;\n            \n            // reverse row order\n            row = actualRows - row;\n            \n            var start = row,\n                end = columns - 1 - row;\n\n            if (column < start || column > end)\n                return;\n            \n            // retroactively fix the first body's position, since width was unknown\n            if (i === 1) {\n                Body.translate(lastBody, { x: (column + (columns % 2 === 1 ? 1 : -1)) * lastBodyWidth, y: 0 });\n            }\n\n            var xOffset = lastBody ? column * lastBodyWidth : 0;\n            \n            return callback(xx + xOffset + column * columnGap, y, column, row, lastBody, i);\n        });\n    };\n\n    /**\n     * This has now moved to the [newtonsCradle example](https://github.com/liabru/matter-js/blob/master/examples/newtonsCradle.js), follow that instead as this function is deprecated here.\n     * @deprecated moved to newtonsCradle example\n     * @method newtonsCradle\n     * @param {number} xx\n     * @param {number} yy\n     * @param {number} number\n     * @param {number} size\n     * @param {number} length\n     * @return {composite} A new composite newtonsCradle body\n     */\n    Composites.newtonsCradle = function(xx, yy, number, size, length) {\n        var newtonsCradle = Composite.create({ label: 'Newtons Cradle' });\n\n        for (var i = 0; i < number; i++) {\n            var separation = 1.9,\n                circle = Bodies.circle(xx + i * (size * separation), yy + length, size, \n                    { inertia: Infinity, restitution: 1, friction: 0, frictionAir: 0.0001, slop: 1 }),\n                constraint = Constraint.create({ pointA: { x: xx + i * (size * separation), y: yy }, bodyB: circle });\n\n            Composite.addBody(newtonsCradle, circle);\n            Composite.addConstraint(newtonsCradle, constraint);\n        }\n\n        return newtonsCradle;\n    };\n\n    deprecated(Composites, 'newtonsCradle', 'Composites.newtonsCradle ➤ moved to newtonsCradle example');\n    \n    /**\n     * This has now moved to the [car example](https://github.com/liabru/matter-js/blob/master/examples/car.js), follow that instead as this function is deprecated here.\n     * @deprecated moved to car example\n     * @method car\n     * @param {number} xx\n     * @param {number} yy\n     * @param {number} width\n     * @param {number} height\n     * @param {number} wheelSize\n     * @return {composite} A new composite car body\n     */\n    Composites.car = function(xx, yy, width, height, wheelSize) {\n        var group = Body.nextGroup(true),\n            wheelBase = 20,\n            wheelAOffset = -width * 0.5 + wheelBase,\n            wheelBOffset = width * 0.5 - wheelBase,\n            wheelYOffset = 0;\n    \n        var car = Composite.create({ label: 'Car' }),\n            body = Bodies.rectangle(xx, yy, width, height, { \n                collisionFilter: {\n                    group: group\n                },\n                chamfer: {\n                    radius: height * 0.5\n                },\n                density: 0.0002\n            });\n    \n        var wheelA = Bodies.circle(xx + wheelAOffset, yy + wheelYOffset, wheelSize, { \n            collisionFilter: {\n                group: group\n            },\n            friction: 0.8\n        });\n                    \n        var wheelB = Bodies.circle(xx + wheelBOffset, yy + wheelYOffset, wheelSize, { \n            collisionFilter: {\n                group: group\n            },\n            friction: 0.8\n        });\n                    \n        var axelA = Constraint.create({\n            bodyB: body,\n            pointB: { x: wheelAOffset, y: wheelYOffset },\n            bodyA: wheelA,\n            stiffness: 1,\n            length: 0\n        });\n                        \n        var axelB = Constraint.create({\n            bodyB: body,\n            pointB: { x: wheelBOffset, y: wheelYOffset },\n            bodyA: wheelB,\n            stiffness: 1,\n            length: 0\n        });\n        \n        Composite.addBody(car, body);\n        Composite.addBody(car, wheelA);\n        Composite.addBody(car, wheelB);\n        Composite.addConstraint(car, axelA);\n        Composite.addConstraint(car, axelB);\n\n        return car;\n    };\n\n    deprecated(Composites, 'car', 'Composites.car ➤ moved to car example');\n\n    /**\n     * This has now moved to the [softBody example](https://github.com/liabru/matter-js/blob/master/examples/softBody.js)\n     * and the [cloth example](https://github.com/liabru/matter-js/blob/master/examples/cloth.js), follow those instead as this function is deprecated here.\n     * @deprecated moved to softBody and cloth examples\n     * @method softBody\n     * @param {number} xx\n     * @param {number} yy\n     * @param {number} columns\n     * @param {number} rows\n     * @param {number} columnGap\n     * @param {number} rowGap\n     * @param {boolean} crossBrace\n     * @param {number} particleRadius\n     * @param {} particleOptions\n     * @param {} constraintOptions\n     * @return {composite} A new composite softBody\n     */\n    Composites.softBody = function(xx, yy, columns, rows, columnGap, rowGap, crossBrace, particleRadius, particleOptions, constraintOptions) {\n        particleOptions = Common.extend({ inertia: Infinity }, particleOptions);\n        constraintOptions = Common.extend({ stiffness: 0.2, render: { type: 'line', anchors: false } }, constraintOptions);\n\n        var softBody = Composites.stack(xx, yy, columns, rows, columnGap, rowGap, function(x, y) {\n            return Bodies.circle(x, y, particleRadius, particleOptions);\n        });\n\n        Composites.mesh(softBody, columns, rows, crossBrace, constraintOptions);\n\n        softBody.label = 'Soft Body';\n\n        return softBody;\n    };\n\n    deprecated(Composites, 'softBody', 'Composites.softBody ➤ moved to softBody and cloth examples');\n})();\n\n\n/***/ }),\n/* 23 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* This module has now been replaced by `Matter.Detector`.\n*\n* All usage should be migrated to `Matter.Detector` or another alternative.\n* For back-compatibility purposes this module will remain for a short term and then later removed in a future release.\n*\n* The `Matter.Grid` module contains methods for creating and manipulating collision broadphase grid structures.\n*\n* @class Grid\n* @deprecated\n*/\n\nvar Grid = {};\n\nmodule.exports = Grid;\n\nvar Pair = __webpack_require__(9);\nvar Common = __webpack_require__(0);\nvar deprecated = Common.deprecated;\n\n(function() {\n\n    /**\n     * Creates a new grid.\n     * @deprecated replaced by Matter.Detector\n     * @method create\n     * @param {} options\n     * @return {grid} A new grid\n     */\n    Grid.create = function(options) {\n        var defaults = {\n            buckets: {},\n            pairs: {},\n            pairsList: [],\n            bucketWidth: 48,\n            bucketHeight: 48\n        };\n\n        return Common.extend(defaults, options);\n    };\n\n    /**\n     * The width of a single grid bucket.\n     *\n     * @property bucketWidth\n     * @type number\n     * @default 48\n     */\n\n    /**\n     * The height of a single grid bucket.\n     *\n     * @property bucketHeight\n     * @type number\n     * @default 48\n     */\n\n    /**\n     * Updates the grid.\n     * @deprecated replaced by Matter.Detector\n     * @method update\n     * @param {grid} grid\n     * @param {body[]} bodies\n     * @param {engine} engine\n     * @param {boolean} forceUpdate\n     */\n    Grid.update = function(grid, bodies, engine, forceUpdate) {\n        var i, col, row,\n            world = engine.world,\n            buckets = grid.buckets,\n            bucket,\n            bucketId,\n            gridChanged = false;\n\n        for (i = 0; i < bodies.length; i++) {\n            var body = bodies[i];\n\n            if (body.isSleeping && !forceUpdate)\n                continue;\n\n            // temporary back compatibility bounds check\n            if (world.bounds && (body.bounds.max.x < world.bounds.min.x || body.bounds.min.x > world.bounds.max.x\n                || body.bounds.max.y < world.bounds.min.y || body.bounds.min.y > world.bounds.max.y))\n                continue;\n\n            var newRegion = Grid._getRegion(grid, body);\n\n            // if the body has changed grid region\n            if (!body.region || newRegion.id !== body.region.id || forceUpdate) {\n\n                if (!body.region || forceUpdate)\n                    body.region = newRegion;\n\n                var union = Grid._regionUnion(newRegion, body.region);\n\n                // update grid buckets affected by region change\n                // iterate over the union of both regions\n                for (col = union.startCol; col <= union.endCol; col++) {\n                    for (row = union.startRow; row <= union.endRow; row++) {\n                        bucketId = Grid._getBucketId(col, row);\n                        bucket = buckets[bucketId];\n\n                        var isInsideNewRegion = (col >= newRegion.startCol && col <= newRegion.endCol\n                                                && row >= newRegion.startRow && row <= newRegion.endRow);\n\n                        var isInsideOldRegion = (col >= body.region.startCol && col <= body.region.endCol\n                                                && row >= body.region.startRow && row <= body.region.endRow);\n\n                        // remove from old region buckets\n                        if (!isInsideNewRegion && isInsideOldRegion) {\n                            if (isInsideOldRegion) {\n                                if (bucket)\n                                    Grid._bucketRemoveBody(grid, bucket, body);\n                            }\n                        }\n\n                        // add to new region buckets\n                        if (body.region === newRegion || (isInsideNewRegion && !isInsideOldRegion) || forceUpdate) {\n                            if (!bucket)\n                                bucket = Grid._createBucket(buckets, bucketId);\n                            Grid._bucketAddBody(grid, bucket, body);\n                        }\n                    }\n                }\n\n                // set the new region\n                body.region = newRegion;\n\n                // flag changes so we can update pairs\n                gridChanged = true;\n            }\n        }\n\n        // update pairs list only if pairs changed (i.e. a body changed region)\n        if (gridChanged)\n            grid.pairsList = Grid._createActivePairsList(grid);\n    };\n\n    deprecated(Grid, 'update', 'Grid.update ➤ replaced by Matter.Detector');\n\n    /**\n     * Clears the grid.\n     * @deprecated replaced by Matter.Detector\n     * @method clear\n     * @param {grid} grid\n     */\n    Grid.clear = function(grid) {\n        grid.buckets = {};\n        grid.pairs = {};\n        grid.pairsList = [];\n    };\n\n    deprecated(Grid, 'clear', 'Grid.clear ➤ replaced by Matter.Detector');\n\n    /**\n     * Finds the union of two regions.\n     * @method _regionUnion\n     * @deprecated replaced by Matter.Detector\n     * @private\n     * @param {} regionA\n     * @param {} regionB\n     * @return {} region\n     */\n    Grid._regionUnion = function(regionA, regionB) {\n        var startCol = Math.min(regionA.startCol, regionB.startCol),\n            endCol = Math.max(regionA.endCol, regionB.endCol),\n            startRow = Math.min(regionA.startRow, regionB.startRow),\n            endRow = Math.max(regionA.endRow, regionB.endRow);\n\n        return Grid._createRegion(startCol, endCol, startRow, endRow);\n    };\n\n    /**\n     * Gets the region a given body falls in for a given grid.\n     * @method _getRegion\n     * @deprecated replaced by Matter.Detector\n     * @private\n     * @param {} grid\n     * @param {} body\n     * @return {} region\n     */\n    Grid._getRegion = function(grid, body) {\n        var bounds = body.bounds,\n            startCol = Math.floor(bounds.min.x / grid.bucketWidth),\n            endCol = Math.floor(bounds.max.x / grid.bucketWidth),\n            startRow = Math.floor(bounds.min.y / grid.bucketHeight),\n            endRow = Math.floor(bounds.max.y / grid.bucketHeight);\n\n        return Grid._createRegion(startCol, endCol, startRow, endRow);\n    };\n\n    /**\n     * Creates a region.\n     * @method _createRegion\n     * @deprecated replaced by Matter.Detector\n     * @private\n     * @param {} startCol\n     * @param {} endCol\n     * @param {} startRow\n     * @param {} endRow\n     * @return {} region\n     */\n    Grid._createRegion = function(startCol, endCol, startRow, endRow) {\n        return { \n            id: startCol + ',' + endCol + ',' + startRow + ',' + endRow,\n            startCol: startCol, \n            endCol: endCol, \n            startRow: startRow, \n            endRow: endRow \n        };\n    };\n\n    /**\n     * Gets the bucket id at the given position.\n     * @method _getBucketId\n     * @deprecated replaced by Matter.Detector\n     * @private\n     * @param {} column\n     * @param {} row\n     * @return {string} bucket id\n     */\n    Grid._getBucketId = function(column, row) {\n        return 'C' + column + 'R' + row;\n    };\n\n    /**\n     * Creates a bucket.\n     * @method _createBucket\n     * @deprecated replaced by Matter.Detector\n     * @private\n     * @param {} buckets\n     * @param {} bucketId\n     * @return {} bucket\n     */\n    Grid._createBucket = function(buckets, bucketId) {\n        var bucket = buckets[bucketId] = [];\n        return bucket;\n    };\n\n    /**\n     * Adds a body to a bucket.\n     * @method _bucketAddBody\n     * @deprecated replaced by Matter.Detector\n     * @private\n     * @param {} grid\n     * @param {} bucket\n     * @param {} body\n     */\n    Grid._bucketAddBody = function(grid, bucket, body) {\n        var gridPairs = grid.pairs,\n            pairId = Pair.id,\n            bucketLength = bucket.length,\n            i;\n\n        // add new pairs\n        for (i = 0; i < bucketLength; i++) {\n            var bodyB = bucket[i];\n\n            if (body.id === bodyB.id || (body.isStatic && bodyB.isStatic))\n                continue;\n\n            // keep track of the number of buckets the pair exists in\n            // important for Grid.update to work\n            var id = pairId(body, bodyB),\n                pair = gridPairs[id];\n\n            if (pair) {\n                pair[2] += 1;\n            } else {\n                gridPairs[id] = [body, bodyB, 1];\n            }\n        }\n\n        // add to bodies (after pairs, otherwise pairs with self)\n        bucket.push(body);\n    };\n\n    /**\n     * Removes a body from a bucket.\n     * @method _bucketRemoveBody\n     * @deprecated replaced by Matter.Detector\n     * @private\n     * @param {} grid\n     * @param {} bucket\n     * @param {} body\n     */\n    Grid._bucketRemoveBody = function(grid, bucket, body) {\n        var gridPairs = grid.pairs,\n            pairId = Pair.id,\n            i;\n\n        // remove from bucket\n        bucket.splice(Common.indexOf(bucket, body), 1);\n\n        var bucketLength = bucket.length;\n\n        // update pair counts\n        for (i = 0; i < bucketLength; i++) {\n            // keep track of the number of buckets the pair exists in\n            // important for _createActivePairsList to work\n            var pair = gridPairs[pairId(body, bucket[i])];\n\n            if (pair)\n                pair[2] -= 1;\n        }\n    };\n\n    /**\n     * Generates a list of the active pairs in the grid.\n     * @method _createActivePairsList\n     * @deprecated replaced by Matter.Detector\n     * @private\n     * @param {} grid\n     * @return [] pairs\n     */\n    Grid._createActivePairsList = function(grid) {\n        var pair,\n            gridPairs = grid.pairs,\n            pairKeys = Common.keys(gridPairs),\n            pairKeysLength = pairKeys.length,\n            pairs = [],\n            k;\n\n        // iterate over grid.pairs\n        for (k = 0; k < pairKeysLength; k++) {\n            pair = gridPairs[pairKeys[k]];\n\n            // if pair exists in at least one bucket\n            // it is a pair that needs further collision testing so push it\n            if (pair[2] > 0) {\n                pairs.push(pair);\n            } else {\n                delete gridPairs[pairKeys[k]];\n            }\n        }\n\n        return pairs;\n    };\n    \n})();\n\n\n/***/ }),\n/* 24 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.MouseConstraint` module contains methods for creating mouse constraints.\n* Mouse constraints are used for allowing user interaction, providing the ability to move bodies via the mouse or touch.\n*\n* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).\n*\n* @class MouseConstraint\n*/\n\nvar MouseConstraint = {};\n\nmodule.exports = MouseConstraint;\n\nvar Vertices = __webpack_require__(3);\nvar Sleeping = __webpack_require__(7);\nvar Mouse = __webpack_require__(14);\nvar Events = __webpack_require__(5);\nvar Detector = __webpack_require__(13);\nvar Constraint = __webpack_require__(10);\nvar Composite = __webpack_require__(6);\nvar Common = __webpack_require__(0);\nvar Bounds = __webpack_require__(1);\n\n(function() {\n\n    /**\n     * Creates a new mouse constraint.\n     * All properties have default values, and many are pre-calculated automatically based on other properties.\n     * See the properties section below for detailed information on what you can pass via the `options` object.\n     * @method create\n     * @param {engine} engine\n     * @param {} options\n     * @return {MouseConstraint} A new MouseConstraint\n     */\n    MouseConstraint.create = function(engine, options) {\n        var mouse = (engine ? engine.mouse : null) || (options ? options.mouse : null);\n\n        if (!mouse) {\n            if (engine && engine.render && engine.render.canvas) {\n                mouse = Mouse.create(engine.render.canvas);\n            } else if (options && options.element) {\n                mouse = Mouse.create(options.element);\n            } else {\n                mouse = Mouse.create();\n                Common.warn('MouseConstraint.create: options.mouse was undefined, options.element was undefined, may not function as expected');\n            }\n        }\n\n        var constraint = Constraint.create({ \n            label: 'Mouse Constraint',\n            pointA: mouse.position,\n            pointB: { x: 0, y: 0 },\n            length: 0.01, \n            stiffness: 0.1,\n            angularStiffness: 1,\n            render: {\n                strokeStyle: '#90EE90',\n                lineWidth: 3\n            }\n        });\n\n        var defaults = {\n            type: 'mouseConstraint',\n            mouse: mouse,\n            element: null,\n            body: null,\n            constraint: constraint,\n            collisionFilter: {\n                category: 0x0001,\n                mask: 0xFFFFFFFF,\n                group: 0\n            }\n        };\n\n        var mouseConstraint = Common.extend(defaults, options);\n\n        Events.on(engine, 'beforeUpdate', function() {\n            var allBodies = Composite.allBodies(engine.world);\n            MouseConstraint.update(mouseConstraint, allBodies);\n            MouseConstraint._triggerEvents(mouseConstraint);\n        });\n\n        return mouseConstraint;\n    };\n\n    /**\n     * Updates the given mouse constraint.\n     * @private\n     * @method update\n     * @param {MouseConstraint} mouseConstraint\n     * @param {body[]} bodies\n     */\n    MouseConstraint.update = function(mouseConstraint, bodies) {\n        var mouse = mouseConstraint.mouse,\n            constraint = mouseConstraint.constraint,\n            body = mouseConstraint.body;\n\n        if (mouse.button === 0) {\n            if (!constraint.bodyB) {\n                for (var i = 0; i < bodies.length; i++) {\n                    body = bodies[i];\n                    if (Bounds.contains(body.bounds, mouse.position) \n                            && Detector.canCollide(body.collisionFilter, mouseConstraint.collisionFilter)) {\n                        for (var j = body.parts.length > 1 ? 1 : 0; j < body.parts.length; j++) {\n                            var part = body.parts[j];\n                            if (Vertices.contains(part.vertices, mouse.position)) {\n                                constraint.pointA = mouse.position;\n                                constraint.bodyB = mouseConstraint.body = body;\n                                constraint.pointB = { x: mouse.position.x - body.position.x, y: mouse.position.y - body.position.y };\n                                constraint.angleB = body.angle;\n\n                                Sleeping.set(body, false);\n                                Events.trigger(mouseConstraint, 'startdrag', { mouse: mouse, body: body });\n\n                                break;\n                            }\n                        }\n                    }\n                }\n            } else {\n                Sleeping.set(constraint.bodyB, false);\n                constraint.pointA = mouse.position;\n            }\n        } else {\n            constraint.bodyB = mouseConstraint.body = null;\n            constraint.pointB = null;\n\n            if (body)\n                Events.trigger(mouseConstraint, 'enddrag', { mouse: mouse, body: body });\n        }\n    };\n\n    /**\n     * Triggers mouse constraint events.\n     * @method _triggerEvents\n     * @private\n     * @param {mouse} mouseConstraint\n     */\n    MouseConstraint._triggerEvents = function(mouseConstraint) {\n        var mouse = mouseConstraint.mouse,\n            mouseEvents = mouse.sourceEvents;\n\n        if (mouseEvents.mousemove)\n            Events.trigger(mouseConstraint, 'mousemove', { mouse: mouse });\n\n        if (mouseEvents.mousedown)\n            Events.trigger(mouseConstraint, 'mousedown', { mouse: mouse });\n\n        if (mouseEvents.mouseup)\n            Events.trigger(mouseConstraint, 'mouseup', { mouse: mouse });\n\n        // reset the mouse state ready for the next step\n        Mouse.clearSourceEvents(mouse);\n    };\n\n    /*\n    *\n    *  Events Documentation\n    *\n    */\n\n    /**\n    * Fired when the mouse has moved (or a touch moves) during the last step\n    *\n    * @event mousemove\n    * @param {} event An event object\n    * @param {mouse} event.mouse The engine's mouse instance\n    * @param {} event.source The source object of the event\n    * @param {} event.name The name of the event\n    */\n\n    /**\n    * Fired when the mouse is down (or a touch has started) during the last step\n    *\n    * @event mousedown\n    * @param {} event An event object\n    * @param {mouse} event.mouse The engine's mouse instance\n    * @param {} event.source The source object of the event\n    * @param {} event.name The name of the event\n    */\n\n    /**\n    * Fired when the mouse is up (or a touch has ended) during the last step\n    *\n    * @event mouseup\n    * @param {} event An event object\n    * @param {mouse} event.mouse The engine's mouse instance\n    * @param {} event.source The source object of the event\n    * @param {} event.name The name of the event\n    */\n\n    /**\n    * Fired when the user starts dragging a body\n    *\n    * @event startdrag\n    * @param {} event An event object\n    * @param {mouse} event.mouse The engine's mouse instance\n    * @param {body} event.body The body being dragged\n    * @param {} event.source The source object of the event\n    * @param {} event.name The name of the event\n    */\n\n    /**\n    * Fired when the user ends dragging a body\n    *\n    * @event enddrag\n    * @param {} event An event object\n    * @param {mouse} event.mouse The engine's mouse instance\n    * @param {body} event.body The body that has stopped being dragged\n    * @param {} event.source The source object of the event\n    * @param {} event.name The name of the event\n    */\n\n    /*\n    *\n    *  Properties Documentation\n    *\n    */\n\n    /**\n     * A `String` denoting the type of object.\n     *\n     * @property type\n     * @type string\n     * @default \"constraint\"\n     * @readOnly\n     */\n\n    /**\n     * The `Mouse` instance in use. If not supplied in `MouseConstraint.create`, one will be created.\n     *\n     * @property mouse\n     * @type mouse\n     * @default mouse\n     */\n\n    /**\n     * The `Body` that is currently being moved by the user, or `null` if no body.\n     *\n     * @property body\n     * @type body\n     * @default null\n     */\n\n    /**\n     * The `Constraint` object that is used to move the body during interaction.\n     *\n     * @property constraint\n     * @type constraint\n     */\n\n    /**\n     * An `Object` that specifies the collision filter properties.\n     * The collision filter allows the user to define which types of body this mouse constraint can interact with.\n     * See `body.collisionFilter` for more information.\n     *\n     * @property collisionFilter\n     * @type object\n     */\n\n})();\n\n\n/***/ }),\n/* 25 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Query` module contains methods for performing collision queries.\n*\n* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).\n*\n* @class Query\n*/\n\nvar Query = {};\n\nmodule.exports = Query;\n\nvar Vector = __webpack_require__(2);\nvar Collision = __webpack_require__(8);\nvar Bounds = __webpack_require__(1);\nvar Bodies = __webpack_require__(12);\nvar Vertices = __webpack_require__(3);\n\n(function() {\n\n    /**\n     * Returns a list of collisions between `body` and `bodies`.\n     * @method collides\n     * @param {body} body\n     * @param {body[]} bodies\n     * @return {collision[]} Collisions\n     */\n    Query.collides = function(body, bodies) {\n        var collisions = [],\n            bodiesLength = bodies.length,\n            bounds = body.bounds,\n            collides = Collision.collides,\n            overlaps = Bounds.overlaps;\n\n        for (var i = 0; i < bodiesLength; i++) {\n            var bodyA = bodies[i],\n                partsALength = bodyA.parts.length,\n                partsAStart = partsALength === 1 ? 0 : 1;\n            \n            if (overlaps(bodyA.bounds, bounds)) {\n                for (var j = partsAStart; j < partsALength; j++) {\n                    var part = bodyA.parts[j];\n\n                    if (overlaps(part.bounds, bounds)) {\n                        var collision = collides(part, body);\n\n                        if (collision) {\n                            collisions.push(collision);\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        return collisions;\n    };\n\n    /**\n     * Casts a ray segment against a set of bodies and returns all collisions, ray width is optional. Intersection points are not provided.\n     * @method ray\n     * @param {body[]} bodies\n     * @param {vector} startPoint\n     * @param {vector} endPoint\n     * @param {number} [rayWidth]\n     * @return {collision[]} Collisions\n     */\n    Query.ray = function(bodies, startPoint, endPoint, rayWidth) {\n        rayWidth = rayWidth || 1e-100;\n\n        var rayAngle = Vector.angle(startPoint, endPoint),\n            rayLength = Vector.magnitude(Vector.sub(startPoint, endPoint)),\n            rayX = (endPoint.x + startPoint.x) * 0.5,\n            rayY = (endPoint.y + startPoint.y) * 0.5,\n            ray = Bodies.rectangle(rayX, rayY, rayLength, rayWidth, { angle: rayAngle }),\n            collisions = Query.collides(ray, bodies);\n\n        for (var i = 0; i < collisions.length; i += 1) {\n            var collision = collisions[i];\n            collision.body = collision.bodyB = collision.bodyA;            \n        }\n\n        return collisions;\n    };\n\n    /**\n     * Returns all bodies whose bounds are inside (or outside if set) the given set of bounds, from the given set of bodies.\n     * @method region\n     * @param {body[]} bodies\n     * @param {bounds} bounds\n     * @param {bool} [outside=false]\n     * @return {body[]} The bodies matching the query\n     */\n    Query.region = function(bodies, bounds, outside) {\n        var result = [];\n\n        for (var i = 0; i < bodies.length; i++) {\n            var body = bodies[i],\n                overlaps = Bounds.overlaps(body.bounds, bounds);\n            if ((overlaps && !outside) || (!overlaps && outside))\n                result.push(body);\n        }\n\n        return result;\n    };\n\n    /**\n     * Returns all bodies whose vertices contain the given point, from the given set of bodies.\n     * @method point\n     * @param {body[]} bodies\n     * @param {vector} point\n     * @return {body[]} The bodies matching the query\n     */\n    Query.point = function(bodies, point) {\n        var result = [];\n\n        for (var i = 0; i < bodies.length; i++) {\n            var body = bodies[i];\n            \n            if (Bounds.contains(body.bounds, point)) {\n                for (var j = body.parts.length === 1 ? 0 : 1; j < body.parts.length; j++) {\n                    var part = body.parts[j];\n\n                    if (Bounds.contains(part.bounds, point)\n                        && Vertices.contains(part.vertices, point)) {\n                        result.push(body);\n                        break;\n                    }\n                }\n            }\n        }\n\n        return result;\n    };\n\n})();\n\n\n/***/ }),\n/* 26 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Render` module is a simple canvas based renderer for visualising instances of `Matter.Engine`.\n* It is intended for development and debugging purposes, but may also be suitable for simple games.\n* It includes a number of drawing options including wireframe, vector with support for sprites and viewports.\n*\n* @class Render\n*/\n\nvar Render = {};\n\nmodule.exports = Render;\n\nvar Body = __webpack_require__(4);\nvar Common = __webpack_require__(0);\nvar Composite = __webpack_require__(6);\nvar Bounds = __webpack_require__(1);\nvar Events = __webpack_require__(5);\nvar Vector = __webpack_require__(2);\nvar Mouse = __webpack_require__(14);\n\n(function() {\n\n    var _requestAnimationFrame,\n        _cancelAnimationFrame;\n\n    if (typeof window !== 'undefined') {\n        _requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame\n                                      || window.mozRequestAnimationFrame || window.msRequestAnimationFrame\n                                      || function(callback){ window.setTimeout(function() { callback(Common.now()); }, 1000 / 60); };\n\n        _cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame\n                                      || window.webkitCancelAnimationFrame || window.msCancelAnimationFrame;\n    }\n\n    Render._goodFps = 30;\n    Render._goodDelta = 1000 / 60;\n\n    /**\n     * Creates a new renderer. The options parameter is an object that specifies any properties you wish to override the defaults.\n     * All properties have default values, and many are pre-calculated automatically based on other properties.\n     * See the properties section below for detailed information on what you can pass via the `options` object.\n     * @method create\n     * @param {object} [options]\n     * @return {render} A new renderer\n     */\n    Render.create = function(options) {\n        var defaults = {\n            engine: null,\n            element: null,\n            canvas: null,\n            mouse: null,\n            frameRequestId: null,\n            timing: {\n                historySize: 60,\n                delta: 0,\n                deltaHistory: [],\n                lastTime: 0,\n                lastTimestamp: 0,\n                lastElapsed: 0,\n                timestampElapsed: 0,\n                timestampElapsedHistory: [],\n                engineDeltaHistory: [],\n                engineElapsedHistory: [],\n                elapsedHistory: []\n            },\n            options: {\n                width: 800,\n                height: 600,\n                pixelRatio: 1,\n                background: '#14151f',\n                wireframeBackground: '#14151f',\n                hasBounds: !!options.bounds,\n                enabled: true,\n                wireframes: true,\n                showSleeping: true,\n                showDebug: false,\n                showStats: false,\n                showPerformance: false,\n                showBounds: false,\n                showVelocity: false,\n                showCollisions: false,\n                showSeparations: false,\n                showAxes: false,\n                showPositions: false,\n                showAngleIndicator: false,\n                showIds: false,\n                showVertexNumbers: false,\n                showConvexHulls: false,\n                showInternalEdges: false,\n                showMousePosition: false\n            }\n        };\n\n        var render = Common.extend(defaults, options);\n\n        if (render.canvas) {\n            render.canvas.width = render.options.width || render.canvas.width;\n            render.canvas.height = render.options.height || render.canvas.height;\n        }\n\n        render.mouse = options.mouse;\n        render.engine = options.engine;\n        render.canvas = render.canvas || _createCanvas(render.options.width, render.options.height);\n        render.context = render.canvas.getContext('2d');\n        render.textures = {};\n\n        render.bounds = render.bounds || {\n            min: {\n                x: 0,\n                y: 0\n            },\n            max: {\n                x: render.canvas.width,\n                y: render.canvas.height\n            }\n        };\n\n        // for temporary back compatibility only\n        render.controller = Render;\n        render.options.showBroadphase = false;\n\n        if (render.options.pixelRatio !== 1) {\n            Render.setPixelRatio(render, render.options.pixelRatio);\n        }\n\n        if (Common.isElement(render.element)) {\n            render.element.appendChild(render.canvas);\n        }\n\n        return render;\n    };\n\n    /**\n     * Continuously updates the render canvas on the `requestAnimationFrame` event.\n     * @method run\n     * @param {render} render\n     */\n    Render.run = function(render) {\n        (function loop(time){\n            render.frameRequestId = _requestAnimationFrame(loop);\n            \n            _updateTiming(render, time);\n\n            Render.world(render, time);\n\n            if (render.options.showStats || render.options.showDebug) {\n                Render.stats(render, render.context, time);\n            }\n\n            if (render.options.showPerformance || render.options.showDebug) {\n                Render.performance(render, render.context, time);\n            }\n        })();\n    };\n\n    /**\n     * Ends execution of `Render.run` on the given `render`, by canceling the animation frame request event loop.\n     * @method stop\n     * @param {render} render\n     */\n    Render.stop = function(render) {\n        _cancelAnimationFrame(render.frameRequestId);\n    };\n\n    /**\n     * Sets the pixel ratio of the renderer and updates the canvas.\n     * To automatically detect the correct ratio, pass the string `'auto'` for `pixelRatio`.\n     * @method setPixelRatio\n     * @param {render} render\n     * @param {number} pixelRatio\n     */\n    Render.setPixelRatio = function(render, pixelRatio) {\n        var options = render.options,\n            canvas = render.canvas;\n\n        if (pixelRatio === 'auto') {\n            pixelRatio = _getPixelRatio(canvas);\n        }\n\n        options.pixelRatio = pixelRatio;\n        canvas.setAttribute('data-pixel-ratio', pixelRatio);\n        canvas.width = options.width * pixelRatio;\n        canvas.height = options.height * pixelRatio;\n        canvas.style.width = options.width + 'px';\n        canvas.style.height = options.height + 'px';\n    };\n\n    /**\n     * Positions and sizes the viewport around the given object bounds.\n     * Objects must have at least one of the following properties:\n     * - `object.bounds`\n     * - `object.position`\n     * - `object.min` and `object.max`\n     * - `object.x` and `object.y`\n     * @method lookAt\n     * @param {render} render\n     * @param {object[]} objects\n     * @param {vector} [padding]\n     * @param {bool} [center=true]\n     */\n    Render.lookAt = function(render, objects, padding, center) {\n        center = typeof center !== 'undefined' ? center : true;\n        objects = Common.isArray(objects) ? objects : [objects];\n        padding = padding || {\n            x: 0,\n            y: 0\n        };\n\n        // find bounds of all objects\n        var bounds = {\n            min: { x: Infinity, y: Infinity },\n            max: { x: -Infinity, y: -Infinity }\n        };\n\n        for (var i = 0; i < objects.length; i += 1) {\n            var object = objects[i],\n                min = object.bounds ? object.bounds.min : (object.min || object.position || object),\n                max = object.bounds ? object.bounds.max : (object.max || object.position || object);\n\n            if (min && max) {\n                if (min.x < bounds.min.x)\n                    bounds.min.x = min.x;\n\n                if (max.x > bounds.max.x)\n                    bounds.max.x = max.x;\n\n                if (min.y < bounds.min.y)\n                    bounds.min.y = min.y;\n\n                if (max.y > bounds.max.y)\n                    bounds.max.y = max.y;\n            }\n        }\n\n        // find ratios\n        var width = (bounds.max.x - bounds.min.x) + 2 * padding.x,\n            height = (bounds.max.y - bounds.min.y) + 2 * padding.y,\n            viewHeight = render.canvas.height,\n            viewWidth = render.canvas.width,\n            outerRatio = viewWidth / viewHeight,\n            innerRatio = width / height,\n            scaleX = 1,\n            scaleY = 1;\n\n        // find scale factor\n        if (innerRatio > outerRatio) {\n            scaleY = innerRatio / outerRatio;\n        } else {\n            scaleX = outerRatio / innerRatio;\n        }\n\n        // enable bounds\n        render.options.hasBounds = true;\n\n        // position and size\n        render.bounds.min.x = bounds.min.x;\n        render.bounds.max.x = bounds.min.x + width * scaleX;\n        render.bounds.min.y = bounds.min.y;\n        render.bounds.max.y = bounds.min.y + height * scaleY;\n\n        // center\n        if (center) {\n            render.bounds.min.x += width * 0.5 - (width * scaleX) * 0.5;\n            render.bounds.max.x += width * 0.5 - (width * scaleX) * 0.5;\n            render.bounds.min.y += height * 0.5 - (height * scaleY) * 0.5;\n            render.bounds.max.y += height * 0.5 - (height * scaleY) * 0.5;\n        }\n\n        // padding\n        render.bounds.min.x -= padding.x;\n        render.bounds.max.x -= padding.x;\n        render.bounds.min.y -= padding.y;\n        render.bounds.max.y -= padding.y;\n\n        // update mouse\n        if (render.mouse) {\n            Mouse.setScale(render.mouse, {\n                x: (render.bounds.max.x - render.bounds.min.x) / render.canvas.width,\n                y: (render.bounds.max.y - render.bounds.min.y) / render.canvas.height\n            });\n\n            Mouse.setOffset(render.mouse, render.bounds.min);\n        }\n    };\n\n    /**\n     * Applies viewport transforms based on `render.bounds` to a render context.\n     * @method startViewTransform\n     * @param {render} render\n     */\n    Render.startViewTransform = function(render) {\n        var boundsWidth = render.bounds.max.x - render.bounds.min.x,\n            boundsHeight = render.bounds.max.y - render.bounds.min.y,\n            boundsScaleX = boundsWidth / render.options.width,\n            boundsScaleY = boundsHeight / render.options.height;\n\n        render.context.setTransform(\n            render.options.pixelRatio / boundsScaleX, 0, 0, \n            render.options.pixelRatio / boundsScaleY, 0, 0\n        );\n        \n        render.context.translate(-render.bounds.min.x, -render.bounds.min.y);\n    };\n\n    /**\n     * Resets all transforms on the render context.\n     * @method endViewTransform\n     * @param {render} render\n     */\n    Render.endViewTransform = function(render) {\n        render.context.setTransform(render.options.pixelRatio, 0, 0, render.options.pixelRatio, 0, 0);\n    };\n\n    /**\n     * Renders the given `engine`'s `Matter.World` object.\n     * This is the entry point for all rendering and should be called every time the scene changes.\n     * @method world\n     * @param {render} render\n     */\n    Render.world = function(render, time) {\n        var startTime = Common.now(),\n            engine = render.engine,\n            world = engine.world,\n            canvas = render.canvas,\n            context = render.context,\n            options = render.options,\n            timing = render.timing;\n\n        var allBodies = Composite.allBodies(world),\n            allConstraints = Composite.allConstraints(world),\n            background = options.wireframes ? options.wireframeBackground : options.background,\n            bodies = [],\n            constraints = [],\n            i;\n\n        var event = {\n            timestamp: engine.timing.timestamp\n        };\n\n        Events.trigger(render, 'beforeRender', event);\n\n        // apply background if it has changed\n        if (render.currentBackground !== background)\n            _applyBackground(render, background);\n\n        // clear the canvas with a transparent fill, to allow the canvas background to show\n        context.globalCompositeOperation = 'source-in';\n        context.fillStyle = \"transparent\";\n        context.fillRect(0, 0, canvas.width, canvas.height);\n        context.globalCompositeOperation = 'source-over';\n\n        // handle bounds\n        if (options.hasBounds) {\n            // filter out bodies that are not in view\n            for (i = 0; i < allBodies.length; i++) {\n                var body = allBodies[i];\n                if (Bounds.overlaps(body.bounds, render.bounds))\n                    bodies.push(body);\n            }\n\n            // filter out constraints that are not in view\n            for (i = 0; i < allConstraints.length; i++) {\n                var constraint = allConstraints[i],\n                    bodyA = constraint.bodyA,\n                    bodyB = constraint.bodyB,\n                    pointAWorld = constraint.pointA,\n                    pointBWorld = constraint.pointB;\n\n                if (bodyA) pointAWorld = Vector.add(bodyA.position, constraint.pointA);\n                if (bodyB) pointBWorld = Vector.add(bodyB.position, constraint.pointB);\n\n                if (!pointAWorld || !pointBWorld)\n                    continue;\n\n                if (Bounds.contains(render.bounds, pointAWorld) || Bounds.contains(render.bounds, pointBWorld))\n                    constraints.push(constraint);\n            }\n\n            // transform the view\n            Render.startViewTransform(render);\n\n            // update mouse\n            if (render.mouse) {\n                Mouse.setScale(render.mouse, {\n                    x: (render.bounds.max.x - render.bounds.min.x) / render.options.width,\n                    y: (render.bounds.max.y - render.bounds.min.y) / render.options.height\n                });\n\n                Mouse.setOffset(render.mouse, render.bounds.min);\n            }\n        } else {\n            constraints = allConstraints;\n            bodies = allBodies;\n\n            if (render.options.pixelRatio !== 1) {\n                render.context.setTransform(render.options.pixelRatio, 0, 0, render.options.pixelRatio, 0, 0);\n            }\n        }\n\n        if (!options.wireframes || (engine.enableSleeping && options.showSleeping)) {\n            // fully featured rendering of bodies\n            Render.bodies(render, bodies, context);\n        } else {\n            if (options.showConvexHulls)\n                Render.bodyConvexHulls(render, bodies, context);\n\n            // optimised method for wireframes only\n            Render.bodyWireframes(render, bodies, context);\n        }\n\n        if (options.showBounds)\n            Render.bodyBounds(render, bodies, context);\n\n        if (options.showAxes || options.showAngleIndicator)\n            Render.bodyAxes(render, bodies, context);\n\n        if (options.showPositions)\n            Render.bodyPositions(render, bodies, context);\n\n        if (options.showVelocity)\n            Render.bodyVelocity(render, bodies, context);\n\n        if (options.showIds)\n            Render.bodyIds(render, bodies, context);\n\n        if (options.showSeparations)\n            Render.separations(render, engine.pairs.list, context);\n\n        if (options.showCollisions)\n            Render.collisions(render, engine.pairs.list, context);\n\n        if (options.showVertexNumbers)\n            Render.vertexNumbers(render, bodies, context);\n\n        if (options.showMousePosition)\n            Render.mousePosition(render, render.mouse, context);\n\n        Render.constraints(constraints, context);\n\n        if (options.hasBounds) {\n            // revert view transforms\n            Render.endViewTransform(render);\n        }\n\n        Events.trigger(render, 'afterRender', event);\n\n        // log the time elapsed computing this update\n        timing.lastElapsed = Common.now() - startTime;\n    };\n\n    /**\n     * Renders statistics about the engine and world useful for debugging.\n     * @private\n     * @method stats\n     * @param {render} render\n     * @param {RenderingContext} context\n     * @param {Number} time\n     */\n    Render.stats = function(render, context, time) {\n        var engine = render.engine,\n            world = engine.world,\n            bodies = Composite.allBodies(world),\n            parts = 0,\n            width = 55,\n            height = 44,\n            x = 0,\n            y = 0;\n        \n        // count parts\n        for (var i = 0; i < bodies.length; i += 1) {\n            parts += bodies[i].parts.length;\n        }\n\n        // sections\n        var sections = {\n            'Part': parts,\n            'Body': bodies.length,\n            'Cons': Composite.allConstraints(world).length,\n            'Comp': Composite.allComposites(world).length,\n            'Pair': engine.pairs.list.length\n        };\n\n        // background\n        context.fillStyle = '#0e0f19';\n        context.fillRect(x, y, width * 5.5, height);\n\n        context.font = '12px Arial';\n        context.textBaseline = 'top';\n        context.textAlign = 'right';\n\n        // sections\n        for (var key in sections) {\n            var section = sections[key];\n            // label\n            context.fillStyle = '#aaa';\n            context.fillText(key, x + width, y + 8);\n\n            // value\n            context.fillStyle = '#eee';\n            context.fillText(section, x + width, y + 26);\n\n            x += width;\n        }\n    };\n\n    /**\n     * Renders engine and render performance information.\n     * @private\n     * @method performance\n     * @param {render} render\n     * @param {RenderingContext} context\n     */\n    Render.performance = function(render, context) {\n        var engine = render.engine,\n            timing = render.timing,\n            deltaHistory = timing.deltaHistory,\n            elapsedHistory = timing.elapsedHistory,\n            timestampElapsedHistory = timing.timestampElapsedHistory,\n            engineDeltaHistory = timing.engineDeltaHistory,\n            engineElapsedHistory = timing.engineElapsedHistory,\n            lastEngineDelta = engine.timing.lastDelta;\n        \n        var deltaMean = _mean(deltaHistory),\n            elapsedMean = _mean(elapsedHistory),\n            engineDeltaMean = _mean(engineDeltaHistory),\n            engineElapsedMean = _mean(engineElapsedHistory),\n            timestampElapsedMean = _mean(timestampElapsedHistory),\n            rateMean = (timestampElapsedMean / deltaMean) || 0,\n            fps = (1000 / deltaMean) || 0;\n\n        var graphHeight = 4,\n            gap = 12,\n            width = 60,\n            height = 34,\n            x = 10,\n            y = 69;\n\n        // background\n        context.fillStyle = '#0e0f19';\n        context.fillRect(0, 50, gap * 4 + width * 5 + 22, height);\n\n        // show FPS\n        Render.status(\n            context, x, y, width, graphHeight, deltaHistory.length, \n            Math.round(fps) + ' fps', \n            fps / Render._goodFps,\n            function(i) { return (deltaHistory[i] / deltaMean) - 1; }\n        );\n\n        // show engine delta\n        Render.status(\n            context, x + gap + width, y, width, graphHeight, engineDeltaHistory.length,\n            lastEngineDelta.toFixed(2) + ' dt', \n            Render._goodDelta / lastEngineDelta,\n            function(i) { return (engineDeltaHistory[i] / engineDeltaMean) - 1; }\n        );\n\n        // show engine update time\n        Render.status(\n            context, x + (gap + width) * 2, y, width, graphHeight, engineElapsedHistory.length,\n            engineElapsedMean.toFixed(2) + ' ut', \n            1 - (engineElapsedMean / Render._goodFps),\n            function(i) { return (engineElapsedHistory[i] / engineElapsedMean) - 1; }\n        );\n\n        // show render time\n        Render.status(\n            context, x + (gap + width) * 3, y, width, graphHeight, elapsedHistory.length,\n            elapsedMean.toFixed(2) + ' rt', \n            1 - (elapsedMean / Render._goodFps),\n            function(i) { return (elapsedHistory[i] / elapsedMean) - 1; }\n        );\n\n        // show effective speed\n        Render.status(\n            context, x + (gap + width) * 4, y, width, graphHeight, timestampElapsedHistory.length, \n            rateMean.toFixed(2) + ' x', \n            rateMean * rateMean * rateMean,\n            function(i) { return (((timestampElapsedHistory[i] / deltaHistory[i]) / rateMean) || 0) - 1; }\n        );\n    };\n\n    /**\n     * Renders a label, indicator and a chart.\n     * @private\n     * @method status\n     * @param {RenderingContext} context\n     * @param {number} x\n     * @param {number} y\n     * @param {number} width\n     * @param {number} height\n     * @param {number} count\n     * @param {string} label\n     * @param {string} indicator\n     * @param {function} plotY\n     */\n    Render.status = function(context, x, y, width, height, count, label, indicator, plotY) {\n        // background\n        context.strokeStyle = '#888';\n        context.fillStyle = '#444';\n        context.lineWidth = 1;\n        context.fillRect(x, y + 7, width, 1);\n\n        // chart\n        context.beginPath();\n        context.moveTo(x, y + 7 - height * Common.clamp(0.4 * plotY(0), -2, 2));\n        for (var i = 0; i < width; i += 1) {\n            context.lineTo(x + i, y + 7 - (i < count ? height * Common.clamp(0.4 * plotY(i), -2, 2) : 0));\n        }\n        context.stroke();\n\n        // indicator\n        context.fillStyle = 'hsl(' + Common.clamp(25 + 95 * indicator, 0, 120) + ',100%,60%)';\n        context.fillRect(x, y - 7, 4, 4);\n\n        // label\n        context.font = '12px Arial';\n        context.textBaseline = 'middle';\n        context.textAlign = 'right';\n        context.fillStyle = '#eee';\n        context.fillText(label, x + width, y - 5);\n    };\n\n    /**\n     * Description\n     * @private\n     * @method constraints\n     * @param {constraint[]} constraints\n     * @param {RenderingContext} context\n     */\n    Render.constraints = function(constraints, context) {\n        var c = context;\n\n        for (var i = 0; i < constraints.length; i++) {\n            var constraint = constraints[i];\n\n            if (!constraint.render.visible || !constraint.pointA || !constraint.pointB)\n                continue;\n\n            var bodyA = constraint.bodyA,\n                bodyB = constraint.bodyB,\n                start,\n                end;\n\n            if (bodyA) {\n                start = Vector.add(bodyA.position, constraint.pointA);\n            } else {\n                start = constraint.pointA;\n            }\n\n            if (constraint.render.type === 'pin') {\n                c.beginPath();\n                c.arc(start.x, start.y, 3, 0, 2 * Math.PI);\n                c.closePath();\n            } else {\n                if (bodyB) {\n                    end = Vector.add(bodyB.position, constraint.pointB);\n                } else {\n                    end = constraint.pointB;\n                }\n\n                c.beginPath();\n                c.moveTo(start.x, start.y);\n\n                if (constraint.render.type === 'spring') {\n                    var delta = Vector.sub(end, start),\n                        normal = Vector.perp(Vector.normalise(delta)),\n                        coils = Math.ceil(Common.clamp(constraint.length / 5, 12, 20)),\n                        offset;\n\n                    for (var j = 1; j < coils; j += 1) {\n                        offset = j % 2 === 0 ? 1 : -1;\n\n                        c.lineTo(\n                            start.x + delta.x * (j / coils) + normal.x * offset * 4,\n                            start.y + delta.y * (j / coils) + normal.y * offset * 4\n                        );\n                    }\n                }\n\n                c.lineTo(end.x, end.y);\n            }\n\n            if (constraint.render.lineWidth) {\n                c.lineWidth = constraint.render.lineWidth;\n                c.strokeStyle = constraint.render.strokeStyle;\n                c.stroke();\n            }\n\n            if (constraint.render.anchors) {\n                c.fillStyle = constraint.render.strokeStyle;\n                c.beginPath();\n                c.arc(start.x, start.y, 3, 0, 2 * Math.PI);\n                c.arc(end.x, end.y, 3, 0, 2 * Math.PI);\n                c.closePath();\n                c.fill();\n            }\n        }\n    };\n\n    /**\n     * Description\n     * @private\n     * @method bodies\n     * @param {render} render\n     * @param {body[]} bodies\n     * @param {RenderingContext} context\n     */\n    Render.bodies = function(render, bodies, context) {\n        var c = context,\n            engine = render.engine,\n            options = render.options,\n            showInternalEdges = options.showInternalEdges || !options.wireframes,\n            body,\n            part,\n            i,\n            k;\n\n        for (i = 0; i < bodies.length; i++) {\n            body = bodies[i];\n\n            if (!body.render.visible)\n                continue;\n\n            // handle compound parts\n            for (k = body.parts.length > 1 ? 1 : 0; k < body.parts.length; k++) {\n                part = body.parts[k];\n\n                if (!part.render.visible)\n                    continue;\n\n                if (options.showSleeping && body.isSleeping) {\n                    c.globalAlpha = 0.5 * part.render.opacity;\n                } else if (part.render.opacity !== 1) {\n                    c.globalAlpha = part.render.opacity;\n                }\n\n                if (part.render.sprite && part.render.sprite.texture && !options.wireframes) {\n                    // part sprite\n                    var sprite = part.render.sprite,\n                        texture = _getTexture(render, sprite.texture);\n\n                    c.translate(part.position.x, part.position.y);\n                    c.rotate(part.angle);\n\n                    c.drawImage(\n                        texture,\n                        texture.width * -sprite.xOffset * sprite.xScale,\n                        texture.height * -sprite.yOffset * sprite.yScale,\n                        texture.width * sprite.xScale,\n                        texture.height * sprite.yScale\n                    );\n\n                    // revert translation, hopefully faster than save / restore\n                    c.rotate(-part.angle);\n                    c.translate(-part.position.x, -part.position.y);\n                } else {\n                    // part polygon\n                    if (part.circleRadius) {\n                        c.beginPath();\n                        c.arc(part.position.x, part.position.y, part.circleRadius, 0, 2 * Math.PI);\n                    } else {\n                        c.beginPath();\n                        c.moveTo(part.vertices[0].x, part.vertices[0].y);\n\n                        for (var j = 1; j < part.vertices.length; j++) {\n                            if (!part.vertices[j - 1].isInternal || showInternalEdges) {\n                                c.lineTo(part.vertices[j].x, part.vertices[j].y);\n                            } else {\n                                c.moveTo(part.vertices[j].x, part.vertices[j].y);\n                            }\n\n                            if (part.vertices[j].isInternal && !showInternalEdges) {\n                                c.moveTo(part.vertices[(j + 1) % part.vertices.length].x, part.vertices[(j + 1) % part.vertices.length].y);\n                            }\n                        }\n\n                        c.lineTo(part.vertices[0].x, part.vertices[0].y);\n                        c.closePath();\n                    }\n\n                    if (!options.wireframes) {\n                        c.fillStyle = part.render.fillStyle;\n\n                        if (part.render.lineWidth) {\n                            c.lineWidth = part.render.lineWidth;\n                            c.strokeStyle = part.render.strokeStyle;\n                            c.stroke();\n                        }\n\n                        c.fill();\n                    } else {\n                        c.lineWidth = 1;\n                        c.strokeStyle = '#bbb';\n                        c.stroke();\n                    }\n                }\n\n                c.globalAlpha = 1;\n            }\n        }\n    };\n\n    /**\n     * Optimised method for drawing body wireframes in one pass\n     * @private\n     * @method bodyWireframes\n     * @param {render} render\n     * @param {body[]} bodies\n     * @param {RenderingContext} context\n     */\n    Render.bodyWireframes = function(render, bodies, context) {\n        var c = context,\n            showInternalEdges = render.options.showInternalEdges,\n            body,\n            part,\n            i,\n            j,\n            k;\n\n        c.beginPath();\n\n        // render all bodies\n        for (i = 0; i < bodies.length; i++) {\n            body = bodies[i];\n\n            if (!body.render.visible)\n                continue;\n\n            // handle compound parts\n            for (k = body.parts.length > 1 ? 1 : 0; k < body.parts.length; k++) {\n                part = body.parts[k];\n\n                c.moveTo(part.vertices[0].x, part.vertices[0].y);\n\n                for (j = 1; j < part.vertices.length; j++) {\n                    if (!part.vertices[j - 1].isInternal || showInternalEdges) {\n                        c.lineTo(part.vertices[j].x, part.vertices[j].y);\n                    } else {\n                        c.moveTo(part.vertices[j].x, part.vertices[j].y);\n                    }\n\n                    if (part.vertices[j].isInternal && !showInternalEdges) {\n                        c.moveTo(part.vertices[(j + 1) % part.vertices.length].x, part.vertices[(j + 1) % part.vertices.length].y);\n                    }\n                }\n\n                c.lineTo(part.vertices[0].x, part.vertices[0].y);\n            }\n        }\n\n        c.lineWidth = 1;\n        c.strokeStyle = '#bbb';\n        c.stroke();\n    };\n\n    /**\n     * Optimised method for drawing body convex hull wireframes in one pass\n     * @private\n     * @method bodyConvexHulls\n     * @param {render} render\n     * @param {body[]} bodies\n     * @param {RenderingContext} context\n     */\n    Render.bodyConvexHulls = function(render, bodies, context) {\n        var c = context,\n            body,\n            part,\n            i,\n            j,\n            k;\n\n        c.beginPath();\n\n        // render convex hulls\n        for (i = 0; i < bodies.length; i++) {\n            body = bodies[i];\n\n            if (!body.render.visible || body.parts.length === 1)\n                continue;\n\n            c.moveTo(body.vertices[0].x, body.vertices[0].y);\n\n            for (j = 1; j < body.vertices.length; j++) {\n                c.lineTo(body.vertices[j].x, body.vertices[j].y);\n            }\n\n            c.lineTo(body.vertices[0].x, body.vertices[0].y);\n        }\n\n        c.lineWidth = 1;\n        c.strokeStyle = 'rgba(255,255,255,0.2)';\n        c.stroke();\n    };\n\n    /**\n     * Renders body vertex numbers.\n     * @private\n     * @method vertexNumbers\n     * @param {render} render\n     * @param {body[]} bodies\n     * @param {RenderingContext} context\n     */\n    Render.vertexNumbers = function(render, bodies, context) {\n        var c = context,\n            i,\n            j,\n            k;\n\n        for (i = 0; i < bodies.length; i++) {\n            var parts = bodies[i].parts;\n            for (k = parts.length > 1 ? 1 : 0; k < parts.length; k++) {\n                var part = parts[k];\n                for (j = 0; j < part.vertices.length; j++) {\n                    c.fillStyle = 'rgba(255,255,255,0.2)';\n                    c.fillText(i + '_' + j, part.position.x + (part.vertices[j].x - part.position.x) * 0.8, part.position.y + (part.vertices[j].y - part.position.y) * 0.8);\n                }\n            }\n        }\n    };\n\n    /**\n     * Renders mouse position.\n     * @private\n     * @method mousePosition\n     * @param {render} render\n     * @param {mouse} mouse\n     * @param {RenderingContext} context\n     */\n    Render.mousePosition = function(render, mouse, context) {\n        var c = context;\n        c.fillStyle = 'rgba(255,255,255,0.8)';\n        c.fillText(mouse.position.x + '  ' + mouse.position.y, mouse.position.x + 5, mouse.position.y - 5);\n    };\n\n    /**\n     * Draws body bounds\n     * @private\n     * @method bodyBounds\n     * @param {render} render\n     * @param {body[]} bodies\n     * @param {RenderingContext} context\n     */\n    Render.bodyBounds = function(render, bodies, context) {\n        var c = context,\n            engine = render.engine,\n            options = render.options;\n\n        c.beginPath();\n\n        for (var i = 0; i < bodies.length; i++) {\n            var body = bodies[i];\n\n            if (body.render.visible) {\n                var parts = bodies[i].parts;\n                for (var j = parts.length > 1 ? 1 : 0; j < parts.length; j++) {\n                    var part = parts[j];\n                    c.rect(part.bounds.min.x, part.bounds.min.y, part.bounds.max.x - part.bounds.min.x, part.bounds.max.y - part.bounds.min.y);\n                }\n            }\n        }\n\n        if (options.wireframes) {\n            c.strokeStyle = 'rgba(255,255,255,0.08)';\n        } else {\n            c.strokeStyle = 'rgba(0,0,0,0.1)';\n        }\n\n        c.lineWidth = 1;\n        c.stroke();\n    };\n\n    /**\n     * Draws body angle indicators and axes\n     * @private\n     * @method bodyAxes\n     * @param {render} render\n     * @param {body[]} bodies\n     * @param {RenderingContext} context\n     */\n    Render.bodyAxes = function(render, bodies, context) {\n        var c = context,\n            engine = render.engine,\n            options = render.options,\n            part,\n            i,\n            j,\n            k;\n\n        c.beginPath();\n\n        for (i = 0; i < bodies.length; i++) {\n            var body = bodies[i],\n                parts = body.parts;\n\n            if (!body.render.visible)\n                continue;\n\n            if (options.showAxes) {\n                // render all axes\n                for (j = parts.length > 1 ? 1 : 0; j < parts.length; j++) {\n                    part = parts[j];\n                    for (k = 0; k < part.axes.length; k++) {\n                        var axis = part.axes[k];\n                        c.moveTo(part.position.x, part.position.y);\n                        c.lineTo(part.position.x + axis.x * 20, part.position.y + axis.y * 20);\n                    }\n                }\n            } else {\n                for (j = parts.length > 1 ? 1 : 0; j < parts.length; j++) {\n                    part = parts[j];\n                    for (k = 0; k < part.axes.length; k++) {\n                        // render a single axis indicator\n                        c.moveTo(part.position.x, part.position.y);\n                        c.lineTo((part.vertices[0].x + part.vertices[part.vertices.length-1].x) / 2,\n                            (part.vertices[0].y + part.vertices[part.vertices.length-1].y) / 2);\n                    }\n                }\n            }\n        }\n\n        if (options.wireframes) {\n            c.strokeStyle = 'indianred';\n            c.lineWidth = 1;\n        } else {\n            c.strokeStyle = 'rgba(255, 255, 255, 0.4)';\n            c.globalCompositeOperation = 'overlay';\n            c.lineWidth = 2;\n        }\n\n        c.stroke();\n        c.globalCompositeOperation = 'source-over';\n    };\n\n    /**\n     * Draws body positions\n     * @private\n     * @method bodyPositions\n     * @param {render} render\n     * @param {body[]} bodies\n     * @param {RenderingContext} context\n     */\n    Render.bodyPositions = function(render, bodies, context) {\n        var c = context,\n            engine = render.engine,\n            options = render.options,\n            body,\n            part,\n            i,\n            k;\n\n        c.beginPath();\n\n        // render current positions\n        for (i = 0; i < bodies.length; i++) {\n            body = bodies[i];\n\n            if (!body.render.visible)\n                continue;\n\n            // handle compound parts\n            for (k = 0; k < body.parts.length; k++) {\n                part = body.parts[k];\n                c.arc(part.position.x, part.position.y, 3, 0, 2 * Math.PI, false);\n                c.closePath();\n            }\n        }\n\n        if (options.wireframes) {\n            c.fillStyle = 'indianred';\n        } else {\n            c.fillStyle = 'rgba(0,0,0,0.5)';\n        }\n        c.fill();\n\n        c.beginPath();\n\n        // render previous positions\n        for (i = 0; i < bodies.length; i++) {\n            body = bodies[i];\n            if (body.render.visible) {\n                c.arc(body.positionPrev.x, body.positionPrev.y, 2, 0, 2 * Math.PI, false);\n                c.closePath();\n            }\n        }\n\n        c.fillStyle = 'rgba(255,165,0,0.8)';\n        c.fill();\n    };\n\n    /**\n     * Draws body velocity\n     * @private\n     * @method bodyVelocity\n     * @param {render} render\n     * @param {body[]} bodies\n     * @param {RenderingContext} context\n     */\n    Render.bodyVelocity = function(render, bodies, context) {\n        var c = context;\n\n        c.beginPath();\n\n        for (var i = 0; i < bodies.length; i++) {\n            var body = bodies[i];\n\n            if (!body.render.visible)\n                continue;\n\n            var velocity = Body.getVelocity(body);\n\n            c.moveTo(body.position.x, body.position.y);\n            c.lineTo(body.position.x + velocity.x, body.position.y + velocity.y);\n        }\n\n        c.lineWidth = 3;\n        c.strokeStyle = 'cornflowerblue';\n        c.stroke();\n    };\n\n    /**\n     * Draws body ids\n     * @private\n     * @method bodyIds\n     * @param {render} render\n     * @param {body[]} bodies\n     * @param {RenderingContext} context\n     */\n    Render.bodyIds = function(render, bodies, context) {\n        var c = context,\n            i,\n            j;\n\n        for (i = 0; i < bodies.length; i++) {\n            if (!bodies[i].render.visible)\n                continue;\n\n            var parts = bodies[i].parts;\n            for (j = parts.length > 1 ? 1 : 0; j < parts.length; j++) {\n                var part = parts[j];\n                c.font = \"12px Arial\";\n                c.fillStyle = 'rgba(255,255,255,0.5)';\n                c.fillText(part.id, part.position.x + 10, part.position.y - 10);\n            }\n        }\n    };\n\n    /**\n     * Description\n     * @private\n     * @method collisions\n     * @param {render} render\n     * @param {pair[]} pairs\n     * @param {RenderingContext} context\n     */\n    Render.collisions = function(render, pairs, context) {\n        var c = context,\n            options = render.options,\n            pair,\n            collision,\n            corrected,\n            bodyA,\n            bodyB,\n            i,\n            j;\n\n        c.beginPath();\n\n        // render collision positions\n        for (i = 0; i < pairs.length; i++) {\n            pair = pairs[i];\n\n            if (!pair.isActive)\n                continue;\n\n            collision = pair.collision;\n            for (j = 0; j < pair.activeContacts.length; j++) {\n                var contact = pair.activeContacts[j],\n                    vertex = contact.vertex;\n                c.rect(vertex.x - 1.5, vertex.y - 1.5, 3.5, 3.5);\n            }\n        }\n\n        if (options.wireframes) {\n            c.fillStyle = 'rgba(255,255,255,0.7)';\n        } else {\n            c.fillStyle = 'orange';\n        }\n        c.fill();\n\n        c.beginPath();\n\n        // render collision normals\n        for (i = 0; i < pairs.length; i++) {\n            pair = pairs[i];\n\n            if (!pair.isActive)\n                continue;\n\n            collision = pair.collision;\n\n            if (pair.activeContacts.length > 0) {\n                var normalPosX = pair.activeContacts[0].vertex.x,\n                    normalPosY = pair.activeContacts[0].vertex.y;\n\n                if (pair.activeContacts.length === 2) {\n                    normalPosX = (pair.activeContacts[0].vertex.x + pair.activeContacts[1].vertex.x) / 2;\n                    normalPosY = (pair.activeContacts[0].vertex.y + pair.activeContacts[1].vertex.y) / 2;\n                }\n\n                if (collision.bodyB === collision.supports[0].body || collision.bodyA.isStatic === true) {\n                    c.moveTo(normalPosX - collision.normal.x * 8, normalPosY - collision.normal.y * 8);\n                } else {\n                    c.moveTo(normalPosX + collision.normal.x * 8, normalPosY + collision.normal.y * 8);\n                }\n\n                c.lineTo(normalPosX, normalPosY);\n            }\n        }\n\n        if (options.wireframes) {\n            c.strokeStyle = 'rgba(255,165,0,0.7)';\n        } else {\n            c.strokeStyle = 'orange';\n        }\n\n        c.lineWidth = 1;\n        c.stroke();\n    };\n\n    /**\n     * Description\n     * @private\n     * @method separations\n     * @param {render} render\n     * @param {pair[]} pairs\n     * @param {RenderingContext} context\n     */\n    Render.separations = function(render, pairs, context) {\n        var c = context,\n            options = render.options,\n            pair,\n            collision,\n            corrected,\n            bodyA,\n            bodyB,\n            i,\n            j;\n\n        c.beginPath();\n\n        // render separations\n        for (i = 0; i < pairs.length; i++) {\n            pair = pairs[i];\n\n            if (!pair.isActive)\n                continue;\n\n            collision = pair.collision;\n            bodyA = collision.bodyA;\n            bodyB = collision.bodyB;\n\n            var k = 1;\n\n            if (!bodyB.isStatic && !bodyA.isStatic) k = 0.5;\n            if (bodyB.isStatic) k = 0;\n\n            c.moveTo(bodyB.position.x, bodyB.position.y);\n            c.lineTo(bodyB.position.x - collision.penetration.x * k, bodyB.position.y - collision.penetration.y * k);\n\n            k = 1;\n\n            if (!bodyB.isStatic && !bodyA.isStatic) k = 0.5;\n            if (bodyA.isStatic) k = 0;\n\n            c.moveTo(bodyA.position.x, bodyA.position.y);\n            c.lineTo(bodyA.position.x + collision.penetration.x * k, bodyA.position.y + collision.penetration.y * k);\n        }\n\n        if (options.wireframes) {\n            c.strokeStyle = 'rgba(255,165,0,0.5)';\n        } else {\n            c.strokeStyle = 'orange';\n        }\n        c.stroke();\n    };\n\n    /**\n     * Description\n     * @private\n     * @method inspector\n     * @param {inspector} inspector\n     * @param {RenderingContext} context\n     */\n    Render.inspector = function(inspector, context) {\n        var engine = inspector.engine,\n            selected = inspector.selected,\n            render = inspector.render,\n            options = render.options,\n            bounds;\n\n        if (options.hasBounds) {\n            var boundsWidth = render.bounds.max.x - render.bounds.min.x,\n                boundsHeight = render.bounds.max.y - render.bounds.min.y,\n                boundsScaleX = boundsWidth / render.options.width,\n                boundsScaleY = boundsHeight / render.options.height;\n\n            context.scale(1 / boundsScaleX, 1 / boundsScaleY);\n            context.translate(-render.bounds.min.x, -render.bounds.min.y);\n        }\n\n        for (var i = 0; i < selected.length; i++) {\n            var item = selected[i].data;\n\n            context.translate(0.5, 0.5);\n            context.lineWidth = 1;\n            context.strokeStyle = 'rgba(255,165,0,0.9)';\n            context.setLineDash([1,2]);\n\n            switch (item.type) {\n\n            case 'body':\n\n                // render body selections\n                bounds = item.bounds;\n                context.beginPath();\n                context.rect(Math.floor(bounds.min.x - 3), Math.floor(bounds.min.y - 3),\n                    Math.floor(bounds.max.x - bounds.min.x + 6), Math.floor(bounds.max.y - bounds.min.y + 6));\n                context.closePath();\n                context.stroke();\n\n                break;\n\n            case 'constraint':\n\n                // render constraint selections\n                var point = item.pointA;\n                if (item.bodyA)\n                    point = item.pointB;\n                context.beginPath();\n                context.arc(point.x, point.y, 10, 0, 2 * Math.PI);\n                context.closePath();\n                context.stroke();\n\n                break;\n\n            }\n\n            context.setLineDash([]);\n            context.translate(-0.5, -0.5);\n        }\n\n        // render selection region\n        if (inspector.selectStart !== null) {\n            context.translate(0.5, 0.5);\n            context.lineWidth = 1;\n            context.strokeStyle = 'rgba(255,165,0,0.6)';\n            context.fillStyle = 'rgba(255,165,0,0.1)';\n            bounds = inspector.selectBounds;\n            context.beginPath();\n            context.rect(Math.floor(bounds.min.x), Math.floor(bounds.min.y),\n                Math.floor(bounds.max.x - bounds.min.x), Math.floor(bounds.max.y - bounds.min.y));\n            context.closePath();\n            context.stroke();\n            context.fill();\n            context.translate(-0.5, -0.5);\n        }\n\n        if (options.hasBounds)\n            context.setTransform(1, 0, 0, 1, 0, 0);\n    };\n\n    /**\n     * Updates render timing.\n     * @method _updateTiming\n     * @private\n     * @param {render} render\n     * @param {number} time\n     */\n    var _updateTiming = function(render, time) {\n        var engine = render.engine,\n            timing = render.timing,\n            historySize = timing.historySize,\n            timestamp = engine.timing.timestamp;\n\n        timing.delta = time - timing.lastTime || Render._goodDelta;\n        timing.lastTime = time;\n\n        timing.timestampElapsed = timestamp - timing.lastTimestamp || 0;\n        timing.lastTimestamp = timestamp;\n\n        timing.deltaHistory.unshift(timing.delta);\n        timing.deltaHistory.length = Math.min(timing.deltaHistory.length, historySize);\n\n        timing.engineDeltaHistory.unshift(engine.timing.lastDelta);\n        timing.engineDeltaHistory.length = Math.min(timing.engineDeltaHistory.length, historySize);\n\n        timing.timestampElapsedHistory.unshift(timing.timestampElapsed);\n        timing.timestampElapsedHistory.length = Math.min(timing.timestampElapsedHistory.length, historySize);\n\n        timing.engineElapsedHistory.unshift(engine.timing.lastElapsed);\n        timing.engineElapsedHistory.length = Math.min(timing.engineElapsedHistory.length, historySize);\n\n        timing.elapsedHistory.unshift(timing.lastElapsed);\n        timing.elapsedHistory.length = Math.min(timing.elapsedHistory.length, historySize);\n    };\n\n    /**\n     * Returns the mean value of the given numbers.\n     * @method _mean\n     * @private\n     * @param {Number[]} values\n     * @return {Number} the mean of given values\n     */\n    var _mean = function(values) {\n        var result = 0;\n        for (var i = 0; i < values.length; i += 1) {\n            result += values[i];\n        }\n        return (result / values.length) || 0;\n    };\n\n    /**\n     * @method _createCanvas\n     * @private\n     * @param {} width\n     * @param {} height\n     * @return canvas\n     */\n    var _createCanvas = function(width, height) {\n        var canvas = document.createElement('canvas');\n        canvas.width = width;\n        canvas.height = height;\n        canvas.oncontextmenu = function() { return false; };\n        canvas.onselectstart = function() { return false; };\n        return canvas;\n    };\n\n    /**\n     * Gets the pixel ratio of the canvas.\n     * @method _getPixelRatio\n     * @private\n     * @param {HTMLElement} canvas\n     * @return {Number} pixel ratio\n     */\n    var _getPixelRatio = function(canvas) {\n        var context = canvas.getContext('2d'),\n            devicePixelRatio = window.devicePixelRatio || 1,\n            backingStorePixelRatio = context.webkitBackingStorePixelRatio || context.mozBackingStorePixelRatio\n                                      || context.msBackingStorePixelRatio || context.oBackingStorePixelRatio\n                                      || context.backingStorePixelRatio || 1;\n\n        return devicePixelRatio / backingStorePixelRatio;\n    };\n\n    /**\n     * Gets the requested texture (an Image) via its path\n     * @method _getTexture\n     * @private\n     * @param {render} render\n     * @param {string} imagePath\n     * @return {Image} texture\n     */\n    var _getTexture = function(render, imagePath) {\n        var image = render.textures[imagePath];\n\n        if (image)\n            return image;\n\n        image = render.textures[imagePath] = new Image();\n        image.src = imagePath;\n\n        return image;\n    };\n\n    /**\n     * Applies the background to the canvas using CSS.\n     * @method applyBackground\n     * @private\n     * @param {render} render\n     * @param {string} background\n     */\n    var _applyBackground = function(render, background) {\n        var cssBackground = background;\n\n        if (/(jpg|gif|png)$/.test(background))\n            cssBackground = 'url(' + background + ')';\n\n        render.canvas.style.background = cssBackground;\n        render.canvas.style.backgroundSize = \"contain\";\n        render.currentBackground = background;\n    };\n\n    /*\n    *\n    *  Events Documentation\n    *\n    */\n\n    /**\n    * Fired before rendering\n    *\n    * @event beforeRender\n    * @param {} event An event object\n    * @param {number} event.timestamp The engine.timing.timestamp of the event\n    * @param {} event.source The source object of the event\n    * @param {} event.name The name of the event\n    */\n\n    /**\n    * Fired after rendering\n    *\n    * @event afterRender\n    * @param {} event An event object\n    * @param {number} event.timestamp The engine.timing.timestamp of the event\n    * @param {} event.source The source object of the event\n    * @param {} event.name The name of the event\n    */\n\n    /*\n    *\n    *  Properties Documentation\n    *\n    */\n\n    /**\n     * A back-reference to the `Matter.Render` module.\n     *\n     * @deprecated\n     * @property controller\n     * @type render\n     */\n\n    /**\n     * A reference to the `Matter.Engine` instance to be used.\n     *\n     * @property engine\n     * @type engine\n     */\n\n    /**\n     * A reference to the element where the canvas is to be inserted (if `render.canvas` has not been specified)\n     *\n     * @property element\n     * @type HTMLElement\n     * @default null\n     */\n\n    /**\n     * The canvas element to render to. If not specified, one will be created if `render.element` has been specified.\n     *\n     * @property canvas\n     * @type HTMLCanvasElement\n     * @default null\n     */\n\n    /**\n     * A `Bounds` object that specifies the drawing view region.\n     * Rendering will be automatically transformed and scaled to fit within the canvas size (`render.options.width` and `render.options.height`).\n     * This allows for creating views that can pan or zoom around the scene.\n     * You must also set `render.options.hasBounds` to `true` to enable bounded rendering.\n     *\n     * @property bounds\n     * @type bounds\n     */\n\n    /**\n     * The 2d rendering context from the `render.canvas` element.\n     *\n     * @property context\n     * @type CanvasRenderingContext2D\n     */\n\n    /**\n     * The sprite texture cache.\n     *\n     * @property textures\n     * @type {}\n     */\n\n    /**\n     * The mouse to render if `render.options.showMousePosition` is enabled.\n     *\n     * @property mouse\n     * @type mouse\n     * @default null\n     */\n\n    /**\n     * The configuration options of the renderer.\n     *\n     * @property options\n     * @type {}\n     */\n\n    /**\n     * The target width in pixels of the `render.canvas` to be created.\n     * See also the `options.pixelRatio` property to change render quality.\n     *\n     * @property options.width\n     * @type number\n     * @default 800\n     */\n\n    /**\n     * The target height in pixels of the `render.canvas` to be created.\n     * See also the `options.pixelRatio` property to change render quality.\n     *\n     * @property options.height\n     * @type number\n     * @default 600\n     */\n\n    /**\n     * The [pixel ratio](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio) to use when rendering.\n     *\n     * @property options.pixelRatio\n     * @type number\n     * @default 1\n     */\n\n    /**\n     * A CSS background color string to use when `render.options.wireframes` is disabled.\n     * This may be also set to `'transparent'` or equivalent.\n     *\n     * @property options.background\n     * @type string\n     * @default '#14151f'\n     */\n\n    /**\n     * A CSS background color string to use when `render.options.wireframes` is enabled.\n     * This may be also set to `'transparent'` or equivalent.\n     *\n     * @property options.wireframeBackground\n     * @type string\n     * @default '#14151f'\n     */\n\n    /**\n     * A flag that specifies if `render.bounds` should be used when rendering.\n     *\n     * @property options.hasBounds\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * A flag to enable or disable all debug information overlays together.  \n     * This includes and has priority over the values of:\n     *\n     * - `render.options.showStats`\n     * - `render.options.showPerformance`\n     *\n     * @property options.showDebug\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * A flag to enable or disable the engine stats info overlay.  \n     * From left to right, the values shown are:\n     *\n     * - body parts total\n     * - body total\n     * - constraints total\n     * - composites total\n     * - collision pairs total\n     *\n     * @property options.showStats\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * A flag to enable or disable performance charts.  \n     * From left to right, the values shown are:\n     *\n     * - average render frequency (e.g. 60 fps)\n     * - exact engine delta time used for last update (e.g. 16.66ms)\n     * - average engine execution duration (e.g. 5.00ms)\n     * - average render execution duration (e.g. 0.40ms)\n     * - average effective play speed (e.g. '1.00x' is 'real-time')\n     *\n     * Each value is recorded over a fixed sample of past frames (60 frames).\n     *\n     * A chart shown below each value indicates the variance from the average over the sample.\n     * The more stable or fixed the value is the flatter the chart will appear.\n     *\n     * @property options.showPerformance\n     * @type boolean\n     * @default false\n     */\n    \n    /**\n     * A flag to enable or disable rendering entirely.\n     *\n     * @property options.enabled\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * A flag to toggle wireframe rendering otherwise solid fill rendering is used.\n     *\n     * @property options.wireframes\n     * @type boolean\n     * @default true\n     */\n\n    /**\n     * A flag to enable or disable sleeping bodies indicators.\n     *\n     * @property options.showSleeping\n     * @type boolean\n     * @default true\n     */\n\n    /**\n     * A flag to enable or disable the debug information overlay.\n     *\n     * @property options.showDebug\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * A flag to enable or disable the collision broadphase debug overlay.\n     *\n     * @deprecated no longer implemented\n     * @property options.showBroadphase\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * A flag to enable or disable the body bounds debug overlay.\n     *\n     * @property options.showBounds\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * A flag to enable or disable the body velocity debug overlay.\n     *\n     * @property options.showVelocity\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * A flag to enable or disable the body collisions debug overlay.\n     *\n     * @property options.showCollisions\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * A flag to enable or disable the collision resolver separations debug overlay.\n     *\n     * @property options.showSeparations\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * A flag to enable or disable the body axes debug overlay.\n     *\n     * @property options.showAxes\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * A flag to enable or disable the body positions debug overlay.\n     *\n     * @property options.showPositions\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * A flag to enable or disable the body angle debug overlay.\n     *\n     * @property options.showAngleIndicator\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * A flag to enable or disable the body and part ids debug overlay.\n     *\n     * @property options.showIds\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * A flag to enable or disable the body vertex numbers debug overlay.\n     *\n     * @property options.showVertexNumbers\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * A flag to enable or disable the body convex hulls debug overlay.\n     *\n     * @property options.showConvexHulls\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * A flag to enable or disable the body internal edges debug overlay.\n     *\n     * @property options.showInternalEdges\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * A flag to enable or disable the mouse position debug overlay.\n     *\n     * @property options.showMousePosition\n     * @type boolean\n     * @default false\n     */\n\n})();\n\n\n/***/ }),\n/* 27 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Runner` module is an optional utility which provides a game loop, \n* that handles continuously updating a `Matter.Engine` for you within a browser.\n* It is intended for development and debugging purposes, but may also be suitable for simple games.\n* If you are using your own game loop instead, then you do not need the `Matter.Runner` module.\n* Instead just call `Engine.update(engine, delta)` in your own loop.\n*\n* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).\n*\n* @class Runner\n*/\n\nvar Runner = {};\n\nmodule.exports = Runner;\n\nvar Events = __webpack_require__(5);\nvar Engine = __webpack_require__(17);\nvar Common = __webpack_require__(0);\n\n(function() {\n\n    var _requestAnimationFrame,\n        _cancelAnimationFrame;\n\n    if (typeof window !== 'undefined') {\n        _requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame\n                                      || window.mozRequestAnimationFrame || window.msRequestAnimationFrame;\n   \n        _cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame \n                                      || window.webkitCancelAnimationFrame || window.msCancelAnimationFrame;\n    }\n\n    if (!_requestAnimationFrame) {\n        var _frameTimeout;\n\n        _requestAnimationFrame = function(callback){ \n            _frameTimeout = setTimeout(function() { \n                callback(Common.now()); \n            }, 1000 / 60);\n        };\n\n        _cancelAnimationFrame = function() {\n            clearTimeout(_frameTimeout);\n        };\n    }\n\n    /**\n     * Creates a new Runner. The options parameter is an object that specifies any properties you wish to override the defaults.\n     * @method create\n     * @param {} options\n     */\n    Runner.create = function(options) {\n        var defaults = {\n            fps: 60,\n            deltaSampleSize: 60,\n            counterTimestamp: 0,\n            frameCounter: 0,\n            deltaHistory: [],\n            timePrev: null,\n            frameRequestId: null,\n            isFixed: false,\n            enabled: true\n        };\n\n        var runner = Common.extend(defaults, options);\n\n        runner.delta = runner.delta || 1000 / runner.fps;\n        runner.deltaMin = runner.deltaMin || 1000 / runner.fps;\n        runner.deltaMax = runner.deltaMax || 1000 / (runner.fps * 0.5);\n        runner.fps = 1000 / runner.delta;\n\n        return runner;\n    };\n\n    /**\n     * Continuously ticks a `Matter.Engine` by calling `Runner.tick` on the `requestAnimationFrame` event.\n     * @method run\n     * @param {engine} engine\n     */\n    Runner.run = function(runner, engine) {\n        // create runner if engine is first argument\n        if (typeof runner.positionIterations !== 'undefined') {\n            engine = runner;\n            runner = Runner.create();\n        }\n\n        (function run(time){\n            runner.frameRequestId = _requestAnimationFrame(run);\n\n            if (time && runner.enabled) {\n                Runner.tick(runner, engine, time);\n            }\n        })();\n\n        return runner;\n    };\n\n    /**\n     * A game loop utility that updates the engine and renderer by one step (a 'tick').\n     * Features delta smoothing, time correction and fixed or dynamic timing.\n     * Consider just `Engine.update(engine, delta)` if you're using your own loop.\n     * @method tick\n     * @param {runner} runner\n     * @param {engine} engine\n     * @param {number} time\n     */\n    Runner.tick = function(runner, engine, time) {\n        var timing = engine.timing,\n            delta;\n\n        if (runner.isFixed) {\n            // fixed timestep\n            delta = runner.delta;\n        } else {\n            // dynamic timestep based on wall clock between calls\n            delta = (time - runner.timePrev) || runner.delta;\n            runner.timePrev = time;\n\n            // optimistically filter delta over a few frames, to improve stability\n            runner.deltaHistory.push(delta);\n            runner.deltaHistory = runner.deltaHistory.slice(-runner.deltaSampleSize);\n            delta = Math.min.apply(null, runner.deltaHistory);\n\n            // limit delta\n            delta = delta < runner.deltaMin ? runner.deltaMin : delta;\n            delta = delta > runner.deltaMax ? runner.deltaMax : delta;\n\n            // update engine timing object\n            runner.delta = delta;\n        }\n\n        // create an event object\n        var event = {\n            timestamp: timing.timestamp\n        };\n\n        Events.trigger(runner, 'beforeTick', event);\n\n        // fps counter\n        runner.frameCounter += 1;\n        if (time - runner.counterTimestamp >= 1000) {\n            runner.fps = runner.frameCounter * ((time - runner.counterTimestamp) / 1000);\n            runner.counterTimestamp = time;\n            runner.frameCounter = 0;\n        }\n\n        Events.trigger(runner, 'tick', event);\n\n        // update\n        Events.trigger(runner, 'beforeUpdate', event);\n\n        Engine.update(engine, delta);\n\n        Events.trigger(runner, 'afterUpdate', event);\n\n        Events.trigger(runner, 'afterTick', event);\n    };\n\n    /**\n     * Ends execution of `Runner.run` on the given `runner`, by canceling the animation frame request event loop.\n     * If you wish to only temporarily pause the engine, see `engine.enabled` instead.\n     * @method stop\n     * @param {runner} runner\n     */\n    Runner.stop = function(runner) {\n        _cancelAnimationFrame(runner.frameRequestId);\n    };\n\n    /**\n     * Alias for `Runner.run`.\n     * @method start\n     * @param {runner} runner\n     * @param {engine} engine\n     */\n    Runner.start = function(runner, engine) {\n        Runner.run(runner, engine);\n    };\n\n    /*\n    *\n    *  Events Documentation\n    *\n    */\n\n    /**\n    * Fired at the start of a tick, before any updates to the engine or timing\n    *\n    * @event beforeTick\n    * @param {} event An event object\n    * @param {number} event.timestamp The engine.timing.timestamp of the event\n    * @param {} event.source The source object of the event\n    * @param {} event.name The name of the event\n    */\n\n    /**\n    * Fired after engine timing updated, but just before update\n    *\n    * @event tick\n    * @param {} event An event object\n    * @param {number} event.timestamp The engine.timing.timestamp of the event\n    * @param {} event.source The source object of the event\n    * @param {} event.name The name of the event\n    */\n\n    /**\n    * Fired at the end of a tick, after engine update and after rendering\n    *\n    * @event afterTick\n    * @param {} event An event object\n    * @param {number} event.timestamp The engine.timing.timestamp of the event\n    * @param {} event.source The source object of the event\n    * @param {} event.name The name of the event\n    */\n\n    /**\n    * Fired before update\n    *\n    * @event beforeUpdate\n    * @param {} event An event object\n    * @param {number} event.timestamp The engine.timing.timestamp of the event\n    * @param {} event.source The source object of the event\n    * @param {} event.name The name of the event\n    */\n\n    /**\n    * Fired after update\n    *\n    * @event afterUpdate\n    * @param {} event An event object\n    * @param {number} event.timestamp The engine.timing.timestamp of the event\n    * @param {} event.source The source object of the event\n    * @param {} event.name The name of the event\n    */\n\n    /*\n    *\n    *  Properties Documentation\n    *\n    */\n\n    /**\n     * A flag that specifies whether the runner is running or not.\n     *\n     * @property enabled\n     * @type boolean\n     * @default true\n     */\n\n    /**\n     * A `Boolean` that specifies if the runner should use a fixed timestep (otherwise it is variable).\n     * If timing is fixed, then the apparent simulation speed will change depending on the frame rate (but behaviour will be deterministic).\n     * If the timing is variable, then the apparent simulation speed will be constant (approximately, but at the cost of determininism).\n     *\n     * @property isFixed\n     * @type boolean\n     * @default false\n     */\n\n    /**\n     * A `Number` that specifies the time step between updates in milliseconds.\n     * If `engine.timing.isFixed` is set to `true`, then `delta` is fixed.\n     * If it is `false`, then `delta` can dynamically change to maintain the correct apparent simulation speed.\n     *\n     * @property delta\n     * @type number\n     * @default 1000 / 60\n     */\n\n})();\n\n\n/***/ }),\n/* 28 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* This module has now been replaced by `Matter.Collision`.\n*\n* All usage should be migrated to `Matter.Collision`.\n* For back-compatibility purposes this module will remain for a short term and then later removed in a future release.\n*\n* The `Matter.SAT` module contains methods for detecting collisions using the Separating Axis Theorem.\n*\n* @class SAT\n* @deprecated\n*/\n\nvar SAT = {};\n\nmodule.exports = SAT;\n\nvar Collision = __webpack_require__(8);\nvar Common = __webpack_require__(0);\nvar deprecated = Common.deprecated;\n\n(function() {\n\n    /**\n     * Detect collision between two bodies using the Separating Axis Theorem.\n     * @deprecated replaced by Collision.collides\n     * @method collides\n     * @param {body} bodyA\n     * @param {body} bodyB\n     * @return {collision} collision\n     */\n    SAT.collides = function(bodyA, bodyB) {\n        return Collision.collides(bodyA, bodyB);\n    };\n\n    deprecated(SAT, 'collides', 'SAT.collides ➤ replaced by Collision.collides');\n\n})();\n\n\n/***/ }),\n/* 29 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* The `Matter.Svg` module contains methods for converting SVG images into an array of vector points.\n*\n* To use this module you also need the SVGPathSeg polyfill: https://github.com/progers/pathseg\n*\n* See the included usage [examples](https://github.com/liabru/matter-js/tree/master/examples).\n*\n* @class Svg\n*/\n\nvar Svg = {};\n\nmodule.exports = Svg;\n\nvar Bounds = __webpack_require__(1);\nvar Common = __webpack_require__(0);\n\n(function() {\n\n    /**\n     * Converts an SVG path into an array of vector points.\n     * If the input path forms a concave shape, you must decompose the result into convex parts before use.\n     * See `Bodies.fromVertices` which provides support for this.\n     * Note that this function is not guaranteed to support complex paths (such as those with holes).\n     * You must load the `pathseg.js` polyfill on newer browsers.\n     * @method pathToVertices\n     * @param {SVGPathElement} path\n     * @param {Number} [sampleLength=15]\n     * @return {Vector[]} points\n     */\n    Svg.pathToVertices = function(path, sampleLength) {\n        if (typeof window !== 'undefined' && !('SVGPathSeg' in window)) {\n            Common.warn('Svg.pathToVertices: SVGPathSeg not defined, a polyfill is required.');\n        }\n\n        // https://github.com/wout/svg.topoly.js/blob/master/svg.topoly.js\n        var i, il, total, point, segment, segments, \n            segmentsQueue, lastSegment, \n            lastPoint, segmentIndex, points = [],\n            lx, ly, length = 0, x = 0, y = 0;\n\n        sampleLength = sampleLength || 15;\n\n        var addPoint = function(px, py, pathSegType) {\n            // all odd-numbered path types are relative except PATHSEG_CLOSEPATH (1)\n            var isRelative = pathSegType % 2 === 1 && pathSegType > 1;\n\n            // when the last point doesn't equal the current point add the current point\n            if (!lastPoint || px != lastPoint.x || py != lastPoint.y) {\n                if (lastPoint && isRelative) {\n                    lx = lastPoint.x;\n                    ly = lastPoint.y;\n                } else {\n                    lx = 0;\n                    ly = 0;\n                }\n\n                var point = {\n                    x: lx + px,\n                    y: ly + py\n                };\n\n                // set last point\n                if (isRelative || !lastPoint) {\n                    lastPoint = point;\n                }\n\n                points.push(point);\n\n                x = lx + px;\n                y = ly + py;\n            }\n        };\n\n        var addSegmentPoint = function(segment) {\n            var segType = segment.pathSegTypeAsLetter.toUpperCase();\n\n            // skip path ends\n            if (segType === 'Z') \n                return;\n\n            // map segment to x and y\n            switch (segType) {\n\n            case 'M':\n            case 'L':\n            case 'T':\n            case 'C':\n            case 'S':\n            case 'Q':\n                x = segment.x;\n                y = segment.y;\n                break;\n            case 'H':\n                x = segment.x;\n                break;\n            case 'V':\n                y = segment.y;\n                break;\n            }\n\n            addPoint(x, y, segment.pathSegType);\n        };\n\n        // ensure path is absolute\n        Svg._svgPathToAbsolute(path);\n\n        // get total length\n        total = path.getTotalLength();\n\n        // queue segments\n        segments = [];\n        for (i = 0; i < path.pathSegList.numberOfItems; i += 1)\n            segments.push(path.pathSegList.getItem(i));\n\n        segmentsQueue = segments.concat();\n\n        // sample through path\n        while (length < total) {\n            // get segment at position\n            segmentIndex = path.getPathSegAtLength(length);\n            segment = segments[segmentIndex];\n\n            // new segment\n            if (segment != lastSegment) {\n                while (segmentsQueue.length && segmentsQueue[0] != segment)\n                    addSegmentPoint(segmentsQueue.shift());\n\n                lastSegment = segment;\n            }\n\n            // add points in between when curving\n            // TODO: adaptive sampling\n            switch (segment.pathSegTypeAsLetter.toUpperCase()) {\n\n            case 'C':\n            case 'T':\n            case 'S':\n            case 'Q':\n            case 'A':\n                point = path.getPointAtLength(length);\n                addPoint(point.x, point.y, 0);\n                break;\n\n            }\n\n            // increment by sample value\n            length += sampleLength;\n        }\n\n        // add remaining segments not passed by sampling\n        for (i = 0, il = segmentsQueue.length; i < il; ++i)\n            addSegmentPoint(segmentsQueue[i]);\n\n        return points;\n    };\n\n    Svg._svgPathToAbsolute = function(path) {\n        // http://phrogz.net/convert-svg-path-to-all-absolute-commands\n        // Copyright (c) Gavin Kistner\n        // http://phrogz.net/js/_ReuseLicense.txt\n        // Modifications: tidy formatting and naming\n        var x0, y0, x1, y1, x2, y2, segs = path.pathSegList,\n            x = 0, y = 0, len = segs.numberOfItems;\n\n        for (var i = 0; i < len; ++i) {\n            var seg = segs.getItem(i),\n                segType = seg.pathSegTypeAsLetter;\n\n            if (/[MLHVCSQTA]/.test(segType)) {\n                if ('x' in seg) x = seg.x;\n                if ('y' in seg) y = seg.y;\n            } else {\n                if ('x1' in seg) x1 = x + seg.x1;\n                if ('x2' in seg) x2 = x + seg.x2;\n                if ('y1' in seg) y1 = y + seg.y1;\n                if ('y2' in seg) y2 = y + seg.y2;\n                if ('x' in seg) x += seg.x;\n                if ('y' in seg) y += seg.y;\n\n                switch (segType) {\n\n                case 'm':\n                    segs.replaceItem(path.createSVGPathSegMovetoAbs(x, y), i);\n                    break;\n                case 'l':\n                    segs.replaceItem(path.createSVGPathSegLinetoAbs(x, y), i);\n                    break;\n                case 'h':\n                    segs.replaceItem(path.createSVGPathSegLinetoHorizontalAbs(x), i);\n                    break;\n                case 'v':\n                    segs.replaceItem(path.createSVGPathSegLinetoVerticalAbs(y), i);\n                    break;\n                case 'c':\n                    segs.replaceItem(path.createSVGPathSegCurvetoCubicAbs(x, y, x1, y1, x2, y2), i);\n                    break;\n                case 's':\n                    segs.replaceItem(path.createSVGPathSegCurvetoCubicSmoothAbs(x, y, x2, y2), i);\n                    break;\n                case 'q':\n                    segs.replaceItem(path.createSVGPathSegCurvetoQuadraticAbs(x, y, x1, y1), i);\n                    break;\n                case 't':\n                    segs.replaceItem(path.createSVGPathSegCurvetoQuadraticSmoothAbs(x, y), i);\n                    break;\n                case 'a':\n                    segs.replaceItem(path.createSVGPathSegArcAbs(x, y, seg.r1, seg.r2, seg.angle, seg.largeArcFlag, seg.sweepFlag), i);\n                    break;\n                case 'z':\n                case 'Z':\n                    x = x0;\n                    y = y0;\n                    break;\n\n                }\n            }\n\n            if (segType == 'M' || segType == 'm') {\n                x0 = x;\n                y0 = y;\n            }\n        }\n    };\n\n})();\n\n/***/ }),\n/* 30 */\n/***/ (function(module, exports, __webpack_require__) {\n\n/**\n* This module has now been replaced by `Matter.Composite`.\n*\n* All usage should be migrated to the equivalent functions found on `Matter.Composite`.\n* For example `World.add(world, body)` now becomes `Composite.add(world, body)`.\n*\n* The property `world.gravity` has been moved to `engine.gravity`.\n*\n* For back-compatibility purposes this module will remain as a direct alias to `Matter.Composite` in the short term during migration.\n* Eventually this alias module will be marked as deprecated and then later removed in a future release.\n*\n* @class World\n*/\n\nvar World = {};\n\nmodule.exports = World;\n\nvar Composite = __webpack_require__(6);\nvar Common = __webpack_require__(0);\n\n(function() {\n\n    /**\n     * See above, aliases for back compatibility only\n     */\n    World.create = Composite.create;\n    World.add = Composite.add;\n    World.remove = Composite.remove;\n    World.clear = Composite.clear;\n    World.addComposite = Composite.addComposite;\n    World.addBody = Composite.addBody;\n    World.addConstraint = Composite.addConstraint;\n\n})();\n\n\n/***/ })\n/******/ ]);\n});\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../../webpack/buildin/global.js */ \"./node_modules/webpack/buildin/global.js\")))\n\n//# sourceURL=webpack:///./node_modules/matter-js/build/matter.js?")},
vendor: 667 bytes, line 1
1"./node_modules/webpack/buildin/global.js":function node_modulesWebpackBuildinGlobalJs(module,exports){eval('var g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || new Function("return this")();\n} catch (e) {\n\t// This works if the window reference is available\n\tif (typeof window === "object") g = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it\'s\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n\n\n//# sourceURL=webpack:///(webpack)/buildin/global.js?')}
1});
2//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVuZGxlLmpzIiwic291cmNlcyI6WyJidW5kbGUuanMiXSwic291cmNlc0NvbnRlbnQiOlsiXCJ1c2Ugc3RyaWN0XCI7XG5cbmZ1bmN0aW9uIF90eXBlb2Yob2JqKSB7IFwiQGJhYmVsL2hlbHBlcnMgLSB0eXBlb2ZcIjsgaWYgKHR5cGVvZiBTeW1ib2wgPT09IFwiZnVuY3Rpb25cIiAmJiB0eXBlb2YgU3ltYm9sLml0ZXJhdG9yID09PSBcInN5bWJvbFwiKSB7IF90eXBlb2YgPSBmdW5jdGlvbiBfdHlwZW9mKG9iaikgeyByZXR1cm4gdHlwZW9mIG9iajsgfTsgfSBlbHNlIHsgX3R5cGVvZiA9IGZ1bmN0aW9uIF90eXBlb2Yob2JqKSB7IHJldHVybiBvYmogJiYgdHlwZW9mIFN5bWJvbCA9PT0gXCJmdW5jdGlvblwiICYmIG9iai5jb25zdHJ1Y3RvciA9PT0gU3ltYm9sICYmIG9iaiAhPT0gU3ltYm9sLnByb3RvdHlwZSA/IFwic3ltYm9sXCIgOiB0eXBlb2Ygb2JqOyB9OyB9IHJldHVybiBfdHlwZW9mKG9iaik7IH1cblxuLyoqKioqKi9cbihmdW5jdGlvbiAobW9kdWxlcykge1xuICAvLyB3ZWJwYWNrQm9vdHN0cmFwXG5cbiAgLyoqKioqKi9cbiAgLy8gVGhlIG1vZHVsZSBjYWNoZVxuXG4gIC8qKioqKiovXG4gIHZhciBpbnN0YWxsZWRNb2R1bGVzID0ge307XG4gIC8qKioqKiovXG5cbiAgLyoqKioqKi9cbiAgLy8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cblxuICAvKioqKioqL1xuXG4gIGZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcbiAgICAvKioqKioqL1xuXG4gICAgLyoqKioqKi9cbiAgICAvLyBDaGVjayBpZiBtb2R1bGUgaXMgaW4gY2FjaGVcblxuICAgIC8qKioqKiovXG4gICAgaWYgKGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdKSB7XG4gICAgICAvKioqKioqL1xuICAgICAgcmV0dXJuIGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdLmV4cG9ydHM7XG4gICAgICAvKioqKioqL1xuICAgIH1cbiAgICAvKioqKioqL1xuICAgIC8vIENyZWF0ZSBhIG5ldyBtb2R1bGUgKGFuZCBwdXQgaXQgaW50byB0aGUgY2FjaGUpXG5cbiAgICAvKioqKioqL1xuXG5cbiAgICB2YXIgbW9kdWxlID0gaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0gPSB7XG4gICAgICAvKioqKioqL1xuICAgICAgaTogbW9kdWxlSWQsXG5cbiAgICAgIC8qKioqKiovXG4gICAgICBsOiBmYWxzZSxcblxuICAgICAgLyoqKioqKi9cbiAgICAgIGV4cG9ydHM6IHt9XG4gICAgICAvKioqKioqL1xuXG4gICAgfTtcbiAgICAvKioqKioqL1xuXG4gICAgLyoqKioqKi9cbiAgICAvLyBFeGVjdXRlIHRoZSBtb2R1bGUgZnVuY3Rpb25cblxuICAgIC8qKioqKiovXG5cbiAgICBtb2R1bGVzW21vZHVsZUlkXS5jYWxsKG1vZHVsZS5leHBvcnRzLCBtb2R1bGUsIG1vZHVsZS5leHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKTtcbiAgICAvKioqKioqL1xuXG4gICAgLyoqKioqKi9cbiAgICAvLyBGbGFnIHRoZSBtb2R1bGUgYXMgbG9hZGVkXG5cbiAgICAvKioqKioqL1xuXG4gICAgbW9kdWxlLmwgPSB0cnVlO1xuICAgIC8qKioqKiovXG5cbiAgICAvKioqKioqL1xuICAgIC8vIFJldHVybiB0aGUgZXhwb3J0cyBvZiB0aGUgbW9kdWxlXG5cbiAgICAvKioqKioqL1xuXG4gICAgcmV0dXJuIG1vZHVsZS5leHBvcnRzO1xuICAgIC8qKioqKiovXG4gIH1cbiAgLyoqKioqKi9cblxuICAvKioqKioqL1xuXG4gIC8qKioqKiovXG4gIC8vIGV4cG9zZSB0aGUgbW9kdWxlcyBvYmplY3QgKF9fd2VicGFja19tb2R1bGVzX18pXG5cbiAgLyoqKioqKi9cblxuXG4gIF9fd2VicGFja19yZXF1aXJlX18ubSA9IG1vZHVsZXM7XG4gIC8qKioqKiovXG5cbiAgLyoqKioqKi9cbiAgLy8gZXhwb3NlIHRoZSBtb2R1bGUgY2FjaGVcblxuICAvKioqKioqL1xuXG4gIF9fd2VicGFja19yZXF1aXJlX18uYyA9IGluc3RhbGxlZE1vZHVsZXM7XG4gIC8qKioqKiovXG5cbiAgLyoqKioqKi9cbiAgLy8gZGVmaW5lIGdldHRlciBmdW5jdGlvbiBmb3IgaGFybW9ueSBleHBvcnRzXG5cbiAgLyoqKioqKi9cblxuICBfX3dlYnBhY2tfcmVxdWlyZV9fLmQgPSBmdW5jdGlvbiAoZXhwb3J0cywgbmFtZSwgZ2V0dGVyKSB7XG4gICAgLyoqKioqKi9cbiAgICBpZiAoIV9fd2VicGFja19yZXF1aXJlX18ubyhleHBvcnRzLCBuYW1lKSkge1xuICAgICAgLyoqKioqKi9cbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBuYW1lLCB7XG4gICAgICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgICAgIGdldDogZ2V0dGVyXG4gICAgICB9KTtcbiAgICAgIC8qKioqKiovXG4gICAgfVxuICAgIC8qKioqKiovXG5cbiAgfTtcbiAgLyoqKioqKi9cblxuICAvKioqKioqL1xuICAvLyBkZWZpbmUgX19lc01vZHVsZSBvbiBleHBvcnRzXG5cbiAgLyoqKioqKi9cblxuXG4gIF9fd2VicGFja19yZXF1aXJlX18uciA9IGZ1bmN0aW9uIChleHBvcnRzKSB7XG4gICAgLyoqKioqKi9cbiAgICBpZiAodHlwZW9mIFN5bWJvbCAhPT0gJ3VuZGVmaW5lZCcgJiYgU3ltYm9sLnRvU3RyaW5nVGFnKSB7XG4gICAgICAvKioqKioqL1xuICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFN5bWJvbC50b1N0cmluZ1RhZywge1xuICAgICAgICB2YWx1ZTogJ01vZHVsZSdcbiAgICAgIH0pO1xuICAgICAgLyoqKioqKi9cbiAgICB9XG4gICAgLyoqKioqKi9cblxuXG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsICdfX2VzTW9kdWxlJywge1xuICAgICAgdmFsdWU6IHRydWVcbiAgICB9KTtcbiAgICAvKioqKioqL1xuICB9O1xuICAvKioqKioqL1xuXG4gIC8qKioqKiovXG4gIC8vIGNyZWF0ZSBhIGZha2UgbmFtZXNwYWNlIG9iamVjdFxuXG4gIC8qKioqKiovXG4gIC8vIG1vZGUgJiAxOiB2YWx1ZSBpcyBhIG1vZHVsZSBpZCwgcmVxdWlyZSBpdFxuXG4gIC8qKioqKiovXG4gIC8vIG1vZGUgJiAyOiBtZXJnZSBhbGwgcHJvcGVydGllcyBvZiB2YWx1ZSBpbnRvIHRoZSBuc1xuXG4gIC8qKioqKiovXG4gIC8vIG1vZGUgJiA0OiByZXR1cm4gdmFsdWUgd2hlbiBhbHJlYWR5IG5zIG9iamVjdFxuXG4gIC8qKioqKiovXG4gIC8vIG1vZGUgJiA4fDE6IGJlaGF2ZSBsaWtlIHJlcXVpcmVcblxuICAvKioqKioqL1xuXG5cbiAgX193ZWJwYWNrX3JlcXVpcmVfXy50ID0gZnVuY3Rpb24gKHZhbHVlLCBtb2RlKSB7XG4gICAgLyoqKioqKi9cbiAgICBpZiAobW9kZSAmIDEpIHZhbHVlID0gX193ZWJwYWNrX3JlcXVpcmVfXyh2YWx1ZSk7XG4gICAgLyoqKioqKi9cblxuICAgIGlmIChtb2RlICYgOCkgcmV0dXJuIHZhbHVlO1xuICAgIC8qKioqKiovXG5cbiAgICBpZiAobW9kZSAmIDQgJiYgX3R5cGVvZih2YWx1ZSkgPT09ICdvYmplY3QnICYmIHZhbHVlICYmIHZhbHVlLl9fZXNNb2R1bGUpIHJldHVybi
2B2YWx1ZTtcbiAgICAvKioqKioqL1xuXG4gICAgdmFyIG5zID0gT2JqZWN0LmNyZWF0ZShudWxsKTtcbiAgICAvKioqKioqL1xuXG4gICAgX193ZWJwYWNrX3JlcXVpcmVfXy5yKG5zKTtcbiAgICAvKioqKioqL1xuXG5cbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkobnMsICdkZWZhdWx0Jywge1xuICAgICAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgICAgIHZhbHVlOiB2YWx1ZVxuICAgIH0pO1xuICAgIC8qKioqKiovXG5cbiAgICBpZiAobW9kZSAmIDIgJiYgdHlwZW9mIHZhbHVlICE9ICdzdHJpbmcnKSBmb3IgKHZhciBrZXkgaW4gdmFsdWUpIHtcbiAgICAgIF9fd2VicGFja19yZXF1aXJlX18uZChucywga2V5LCBmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgIHJldHVybiB2YWx1ZVtrZXldO1xuICAgICAgfS5iaW5kKG51bGwsIGtleSkpO1xuICAgIH1cbiAgICAvKioqKioqL1xuXG4gICAgcmV0dXJuIG5zO1xuICAgIC8qKioqKiovXG4gIH07XG4gIC8qKioqKiovXG5cbiAgLyoqKioqKi9cbiAgLy8gZ2V0RGVmYXVsdEV4cG9ydCBmdW5jdGlvbiBmb3IgY29tcGF0aWJpbGl0eSB3aXRoIG5vbi1oYXJtb255IG1vZHVsZXNcblxuICAvKioqKioqL1xuXG5cbiAgX193ZWJwYWNrX3JlcXVpcmVfXy5uID0gZnVuY3Rpb24gKG1vZHVsZSkge1xuICAgIC8qKioqKiovXG4gICAgdmFyIGdldHRlciA9IG1vZHVsZSAmJiBtb2R1bGUuX19lc01vZHVsZSA/XG4gICAgLyoqKioqKi9cbiAgICBmdW5jdGlvbiBnZXREZWZhdWx0KCkge1xuICAgICAgcmV0dXJuIG1vZHVsZVsnZGVmYXVsdCddO1xuICAgIH0gOlxuICAgIC8qKioqKiovXG4gICAgZnVuY3Rpb24gZ2V0TW9kdWxlRXhwb3J0cygpIHtcbiAgICAgIHJldHVybiBtb2R1bGU7XG4gICAgfTtcbiAgICAvKioqKioqL1xuXG4gICAgX193ZWJwYWNrX3JlcXVpcmVfXy5kKGdldHRlciwgJ2EnLCBnZXR0ZXIpO1xuICAgIC8qKioqKiovXG5cblxuICAgIHJldHVybiBnZXR0ZXI7XG4gICAgLyoqKioqKi9cbiAgfTtcbiAgLyoqKioqKi9cblxuICAvKioqKioqL1xuICAvLyBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGxcblxuICAvKioqKioqL1xuXG5cbiAgX193ZWJwYWNrX3JlcXVpcmVfXy5vID0gZnVuY3Rpb24gKG9iamVjdCwgcHJvcGVydHkpIHtcbiAgICByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdCwgcHJvcGVydHkpO1xuICB9O1xuICAvKioqKioqL1xuXG4gIC8qKioqKiovXG4gIC8vIF9fd2VicGFja19wdWJsaWNfcGF0aF9fXG5cbiAgLyoqKioqKi9cblxuXG4gIF9fd2VicGFja19yZXF1aXJlX18ucCA9IFwiXCI7XG4gIC8qKioqKiovXG5cbiAgLyoqKioqKi9cblxuICAvKioqKioqL1xuICAvLyBMb2FkIGVudHJ5IG1vZHVsZSBhbmQgcmV0dXJuIGV4cG9ydHNcblxuICAvKioqKioqL1xuXG4gIHJldHVybiBfX3dlYnBhY2tfcmVxdWlyZV9fKF9fd2VicGFja19yZXF1aXJlX18ucyA9IFwiLi9hc3NldHMvc3JjL2pzL21haW4uanNcIik7XG4gIC8qKioqKiovXG59XG4vKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4vKioqKioqL1xuKSh7XG4gIC8qKiovXG4gIFwiLi9hc3NldHMvc3JjL2pzL21haW4uanNcIjpcbiAgLyohKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiEqXFxcbiAgICAhKioqIC4vYXNzZXRzL3NyYy9qcy9tYWluLmpzICoqKiFcbiAgICBcXCoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbiAgLyohIGV4cG9ydHMgcHJvdmlkZWQ6IGZpbHRlcnMsIG1hcnF1ZWUsIHNjcm9sbCAqL1xuXG4gIC8qKiovXG4gIGZ1bmN0aW9uIGFzc2V0c1NyY0pzTWFpbkpzKG1vZHVsZSwgX193ZWJwYWNrX2V4cG9ydHNfXywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgZXZhbChcIl9fd2VicGFja19yZXF1aXJlX18ucihfX3dlYnBhY2tfZXhwb3J0c19fKTtcXG4vKiBoYXJtb255IGV4cG9ydCAoYmluZGluZykgKi8gX193ZWJwYWNrX3JlcXVpcmVfXy5kKF9fd2VicGFja19leHBvcnRzX18sIFxcXCJmaWx0ZXJzXFxcIiwgZnVuY3Rpb24oKSB7IHJldHVybiBmaWx0ZXJzOyB9KTtcXG4vKiBoYXJtb255IGV4cG9ydCAoYmluZGluZykgKi8gX193ZWJwYWNrX3JlcXVpcmVfXy5kKF9fd2VicGFja19leHBvcnRzX18sIFxcXCJtYXJxdWVlXFxcIiwgZnVuY3Rpb24oKSB7IHJldHVybiBtYXJxdWVlOyB9KTtcXG4vKiBoYXJtb255IGV4cG9ydCAoYmluZGluZykgKi8gX193ZWJwYWNrX3JlcXVpcmVfXy5kKF9fd2VicGFja19leHBvcnRzX18sIFxcXCJzY3JvbGxcXFwiLCBmdW5jdGlvbigpIHsgcmV0dXJuIHNjcm9sbDsgfSk7XFxuLyogaGFybW9ueSBpbXBvcnQgKi8gdmFyIF9saWJyYXJpZXNfcHJ4X2ZpbHRlcnNfcHJ4X2ZpbHRlcnNfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzBfXyA9IF9fd2VicGFja19yZXF1aXJlX18oLyohIC4uLy4uLy4uL2xpYnJhcmllcy9wcngtZmlsdGVycy9wcngtZmlsdGVycyAqLyBcXFwiLi9saWJyYXJpZXMvcHJ4LWZpbHRlcnMvcHJ4LWZpbHRlcnMuanNcXFwiKTtcXG4vKiBoYXJtb255IGltcG9ydCAqLyB2YXIgX2xpYnJhcmllc19wcnhfbWFycXVlZV9wcnhfbWFycXVlZV9fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMV9fID0gX193ZWJwYWNrX3JlcXVpcmVfXygvKiEgLi4vLi4vLi4vbGlicmFyaWVzL3ByeC1tYXJxdWVlL3ByeC1tYXJxdWVlICovIFxcXCIuL2xpYnJhcmllcy9wcngtbWFycXVlZS9wcngtbWFycXVlZS5qc1xcXCIpO1xcbi8qIGhhcm1vbnkgaW1wb3J0ICovIHZhciBfbGlicmFyaWVzX3ByeF9zY3JvbGxfcHJ4X3Njcm9sbF9fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMl9fID0gX193ZWJwYWNrX3JlcXVpcmVfXygvKiEgLi4vLi4vLi4vbGlicmFyaWVzL3ByeC1zY3JvbGwvcHJ4LXNjcm9sbCAqLyBcXFwiLi9saWJyYXJpZXMvcHJ4LXNjcm9sbC9wcngtc2Nyb2xsLmpzXFxcIik7XFxuLyogaGFybW9ueSBpbXBvcnQgKi8gdmFyIF9tb2R1bGVzX2dzYXBfZWFzZXNfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzNfXyA9IF9fd2VicGFja19yZXF1aXJlX18oLyohIC4vbW9kdWxlcy9nc2FwL2Vhc2VzICovIFxcXCIuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9nc2FwL2Vhc2VzLmpzXFxcIik7XFxuLyogaGFybW9ueSBpbXBvcnQgKi8gdmFyIF9tb2R1bGVzX2dzYXBfaW50cm9fX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzRfXyA9IF9fd2VicGFja19yZXF1aXJlX18oLyohIC4vbW9kdWxlcy9nc2FwL2ludHJvICovIFxcXCIuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9nc2FwL2ludHJvLmpzXFxcIik7XFxuLyogaGFybW9ueSBpbXBvcnQgKi8gdmFyIF9tb2R1bGVzX2dzYXBfY3VydGFpbl9fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfNV9fID0gX193ZWJwYWNrX3JlcXVpcmVfXygvKiEgLi9tb2R1bGVzL2dzYXAvY3VydGFpbiAqLyBcXFwiLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvZ3NhcC9jdXJ0YWluLmpzXFxcIik7XFxuLyogaGFybW9ueSBpbXBvcnQgKi8gdmFyIF9tb2R1bGVzX2dzYXBfc2Nyb2xsVHJpZ2dlcl9fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfNl9fID0gX193ZWJwYWNrX3JlcXVpcmVfXygvKiEgLi9tb2R1bGVzL2dzYXAvc2Nyb2xsVHJpZ2dlciAqLyBcXFwiLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvZ3NhcC9zY3JvbGxUcmlnZ2VyLmpzXFxcIik7XFxuLyogaGFybW9ueSBpbXBvcnQgKi8gdmFyIF9tb2R1bGVzX2dzYXBfZmVhdHVyZXNfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzdfXyA9IF9fd2VicGFja19yZXF1aXJlX18oLyohIC4vbW9kdWxlcy9nc2FwL2ZlYXR1cmVzICovIFxcXCIuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9nc2FwL2ZlYXR1cmVzLmpzXFxcIik7XFxuLyogaGFybW9ueSBpbXBvcnQgKi8gdmFyIF9tb2R1bGVzX2FjY29yZGlvbl9fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfOF9fID0gX193ZWJwYWNrX3JlcXVpcmVfXygvKiEgLi9tb2R1bGVzL2FjY29yZGlvbiAqLyBcXFwiLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvYWNjb3JkaW9uLmpzXFxcIik7XFxuLyogaGFybW9ueSBpbXBvcnQgKi8gdmFyIF9tb2R1bGVzX2Nhcm91c2VsX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV85X18gPSBfX3dlYnBhY2tfcmVxdWlyZV9fKC8qISAuL21vZHVsZXMvY2Fyb3VzZWwgKi8gXFxcIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2Nhcm91c2VsLmpzXFxcIik7XFxuLyogaGFybW9ueSBpbXBvcnQgKi8gdmFyIF9tb2R1bGVzX2NmN19fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMTBfXyA9IF9fd2VicGFja19yZXF1aXJlX18oLyohIC4vbW9kdWxlcy9jZjcgKi8gXFxcIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2NmNy5qc1xcXCIpO1xcbi8qIGhhcm1vbnkgaW1wb3J0ICovIHZhciBfbW9kdWxlc19jdXJzb3JfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzExX18gPSBfX3dlYnBhY2tfcmVxdWlyZV9fKC8qISAuL21vZHVsZXMvY3Vyc29yICovIFxcXCIuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9jdXJzb3IuanNcXFwiKTtcXG4vKiBoYXJtb255IGltcG9ydCAqLyB2YXIgX21vZHVsZXNfZmlsZV9fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMTJfXyA9IF9fd2VicGFja19yZXF1aXJlX18oLyohIC4vbW9kdWxlcy9maWxlICovIFxcXCIuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9maWxlLmpzXFxcIik7XFxuLyogaGFybW9ueSBpbXBvcnQgKi8gdmFyIF9tb2R1bGVzX2hlbHBlcl9fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMTNfXyA9IF9fd2VicGFja19yZXF1aXJlX18oLyohIC4vbW9kdWxlcy9oZWxwZXIgKi8gXFxcIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2hlbHBlci5qc1xcXCIpO1xcbi8qIGhhcm1vbnkgaW1wb3J0ICovIHZhciBfbW9kdWxlc19tZW51c19fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMTRfXyA9IF9fd2VicGFja19yZXF1aXJlX18oLyohIC4vbW9kdWxlcy9tZW51cyAqLyBcXFwiLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvbWVudXMuanNcXFwiKTtcXG4vKiBoYXJtb255IGltcG9ydCAqLyB2YXIgX21vZHVsZXNfaW5jbHVzaW9uX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8xNV9fID0gX193ZWJwYWNrX3JlcXVpcmVfXygvKiEgLi9tb2R1bGVzL2luY2x1c2lvbiAqLyBcXFwiLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvaW5jbHVzaW9uLmpzXFxcIik7XFxuLyogaGFybW9ueSBpbXBvcnQgKi8gdmFyIF9tb2R1bGVzX2Zvb3Rlcl9fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMTZfXyA9IF9fd2VicGFja19yZXF1aXJlX18oLyohIC4vbW9kdWxlcy9mb290ZXIgKi8gXFxcIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2Zvb3Rlci5qc1xcXCIpO1xcbi8qIGhhcm1vbnkgaW1wb3J0ICovIHZhciBfbW9kdWxlc19hc2lkZV9fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMTdfXyA9IF9fd2VicGFja19yZXF1aXJlX18oLyohIC4vbW9kdWxlcy9hc2lkZSAqLyBcXFwiLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvYXNpZGUuanNcXFwiKTtcXG4vKiBoYXJtb255IGltcG9ydCAqLyB2YXIgX21vZHVsZXNfbWVkaWFfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzE4X18gPSBfX3dlYnBhY2tfcmVxdWlyZV9fKC8qISAuL21vZHVsZXMvbWVkaWEgKi8gXFxcIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL21lZGlhLmpzXFxcIik7XFxuLyogaGFybW9ueSBpbXBvcnQgKi8gdmFyIF9tb2R1bGVzX2Jsb2dGaWx0ZXJzX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8xOV9fID0gX193ZWJwYWNrX3JlcXVpcmVfXygvKiEgLi9tb2R1bGVzL2Jsb2dGaWx0ZXJzICovIFxcXCIuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9ibG9nRmlsdGVycy5qc1xcXCIpO1xcbi8qIGhhcm1vbnkgaW1wb3J0ICovIHZhciBfbW9kdWxlc19zZWN0aW9uX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8yMF9fID0gX193ZWJwYWNrX3JlcXVpcmVfXygvKiEgLi9tb2R1bGVzL3NlY3Rpb24gKi8gXFxcIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL3NlY3Rpb24uanNcXFwiKTtcXG4vKiBoYXJtb255IGltcG9ydCAqLyB2YXIgX21vZHVsZXNfbWF0dGVyX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8yMV9fID0gX193ZWJwYWNrX3JlcXVpcmVfXygvKiEgLi9tb2R1bGVzL21hdHRlciAqLyBcXFwiLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvbWF0dGVyLmpzXFxcIik7XFxuLyogaGFybW9ueSBpbXBvcnQgKi8gdmFyIF9tb2R1bGVzX2pvYl9fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMjJfXyA9IF9fd2VicGFja19yZXF1aXJlX18oLyohIC4vbW9kdWxlcy9qb2IgKi8gXFxcIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2pvYi5qc1xcXCIpO1xcbi8qXFxyXFxuICogSW1wb3J0IGxpYnJhaXJpZXNcXHJcXG4gKi9cXHJcXG5cXHJcXG5cXHJcXG5cXHJcXG5cXHJcXG4vKlxcclxcbiAqIEltcG9ydCBtb2R1bGVzXFxyXFxuICovXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuXFxyXFxuLypcXHJcXG4gKiBJbml0IGxpYnJhaXJpZXNcXHJcXG4gKi9cXHJcXG5nc2FwLnJlZ2lzdGVyUGx1Z2luKERyYXdTVkdQbHVnaW4pO1xcclxcblxcclxcbmdzYXAuY29uZmlnKHtcXHJcXG5cXHRudWxsVGFyZ2V0V2FybjogZmFsc2UsXFxyXFxuXFx0dHJpYWxXYXJuOiBmYWxzZSxcXHJcXG59KTtcXHJcXG5cXHJcXG4vLyBQcnggRmlsdGVyc1xcclxcbnZhciBmaWx0ZXJzSW5zdGFuY2U7XFxyXFxuXFxyXFxuaWYgKG9wdGlvbnMuYWN0aXZhdGVfcHJ4X2ZpbHRlcnMpIHtcXHJcXG5cXHRmaWx0ZXJzSW5zdGFuY2UgPSBuZXcgX2xpYnJhcmllc19wcnhfZmlsdGVyc19wcnhfZmlsdGVyc19fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMF9fW1xcXCJQcnhGaWx0ZXJzXFxcIl0oKTtcXHJcXG59XFxyXFxuXFxyXFxuY29uc3QgZmlsdGVycyA9IGZpbHRlcnNJbnN0YW5jZTtcXHJcXG5cXHJcXG4vLyBQcnggTWFycXVlZVxcclxcbnZhciBtYXJxdWVlSW5zdGFuY2U7XFxyXFxuXFxyXFxuaWYgKG9wdGlvbnMuYWN0aXZhdGVfcHJ4X21hcnF1ZWUpIHtcXHJcXG5cXHRtYXJxdWVlSW5zdGFuY2UgPSBuZXcgX2xpYnJhcmllc19wcnhfbWFycXVlZV9wcnhfbWFycXVlZV9fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMV9fW1xcXCJQcnhNYXJxdWVlXFxcIl0oKTtcXHJcXG59XFxyXFxuXFxyXFxuY29uc3QgbWFycXVlZSA9IG1hcnF1ZWVJbnN0YW5jZTtcXHJcXG5cXHJcXG4vLyBQcnggU2Nyb2xsXFxyXFxudmFyIHNjcm9sbEluc3RhbmNlO1xcclxcblxcclxcbmlmIChvcHRpb25zLmFjdGl2YXRlX3ByeF9zY3JvbGwpIHtcXHJcXG5cXHRzY3JvbGxJbnN0YW5jZSA9IG5ldyBfbGlicmFyaWVzX3ByeF9zY3JvbGxfcHJ4X3Njcm9sbF9fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMl9fW1xcXCJQcnhTY3JvbGxcXFwiXSgpO1xcclxcbn1cXHJcXG5cXHJcXG5jb25zdCBzY3JvbGwgP
2SBzY3JvbGxJbnN0YW5jZTtcXHJcXG5cXHJcXG4vKlxcclxcbiAqIEluaXQgbW9kdWxlc1xcclxcbiAqL1xcclxcblxcclxcbmlmIChvcHRpb25zLmFjdGl2YXRlX2dzYXApIHtcXHJcXG5cXHRPYmplY3QoX21vZHVsZXNfZ3NhcF9lYXNlc19fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfM19fW1xcXCJkZWZhdWx0XFxcIl0pKCk7XFxyXFxuXFx0T2JqZWN0KF9tb2R1bGVzX2dzYXBfaW50cm9fX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzRfX1tcXFwiZGVmYXVsdFxcXCJdKSgpO1xcclxcblxcdE9iamVjdChfbW9kdWxlc19nc2FwX2N1cnRhaW5fX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzVfX1tcXFwiZGVmYXVsdFxcXCJdKSgpO1xcclxcblxcdE9iamVjdChfbW9kdWxlc19nc2FwX3Njcm9sbFRyaWdnZXJfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzZfX1tcXFwiZGVmYXVsdFxcXCJdKSgpO1xcclxcblxcdE9iamVjdChfbW9kdWxlc19nc2FwX2ZlYXR1cmVzX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV83X19bXFxcImRlZmF1bHRcXFwiXSkoKTtcXHJcXG59XFxyXFxuT2JqZWN0KF9tb2R1bGVzX2FjY29yZGlvbl9fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfOF9fW1xcXCJkZWZhdWx0XFxcIl0pKCk7XFxyXFxuaWYgKG9wdGlvbnMuYWN0aXZhdGVfZmxpY2tpdHkpIHtcXHJcXG5cXHRPYmplY3QoX21vZHVsZXNfY2Fyb3VzZWxfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzlfX1tcXFwiZGVmYXVsdFxcXCJdKSgpO1xcclxcbn1cXHJcXG5PYmplY3QoX21vZHVsZXNfY2Y3X19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8xMF9fW1xcXCJkZWZhdWx0XFxcIl0pKCk7XFxyXFxuT2JqZWN0KF9tb2R1bGVzX2N1cnNvcl9fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMTFfX1tcXFwiZGVmYXVsdFxcXCJdKSgpO1xcclxcbk9iamVjdChfbW9kdWxlc19maWxlX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8xMl9fW1xcXCJkZWZhdWx0XFxcIl0pKCk7XFxyXFxuT2JqZWN0KF9tb2R1bGVzX2hlbHBlcl9fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMTNfX1tcXFwiZGVmYXVsdFxcXCJdKSgpO1xcclxcbk9iamVjdChfbW9kdWxlc19tZW51c19fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMTRfX1tcXFwiZGVmYXVsdFxcXCJdKSgpO1xcclxcbk9iamVjdChfbW9kdWxlc19pbmNsdXNpb25fX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzE1X19bXFxcImRlZmF1bHRcXFwiXSkoKTtcXHJcXG5PYmplY3QoX21vZHVsZXNfZm9vdGVyX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8xNl9fW1xcXCJkZWZhdWx0XFxcIl0pKCk7XFxyXFxuT2JqZWN0KF9tb2R1bGVzX2FzaWRlX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8xN19fW1xcXCJkZWZhdWx0XFxcIl0pKCk7XFxyXFxuT2JqZWN0KF9tb2R1bGVzX21lZGlhX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8xOF9fW1xcXCJkZWZhdWx0XFxcIl0pKCk7XFxyXFxuT2JqZWN0KF9tb2R1bGVzX2Jsb2dGaWx0ZXJzX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8xOV9fW1xcXCJkZWZhdWx0XFxcIl0pKCk7XFxyXFxuT2JqZWN0KF9tb2R1bGVzX21hdHRlcl9fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMjFfX1tcXFwiZGVmYXVsdFxcXCJdKSgpO1xcclxcbk9iamVjdChfbW9kdWxlc19zZWN0aW9uX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8yMF9fW1xcXCJkZWZhdWx0XFxcIl0pKCk7XFxyXFxuT2JqZWN0KF9tb2R1bGVzX2pvYl9fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMjJfX1tcXFwiZGVmYXVsdFxcXCJdKSgpO1xcblxcbi8vIyBzb3VyY2VVUkw9d2VicGFjazovLy8uL2Fzc2V0cy9zcmMvanMvbWFpbi5qcz9cIik7XG4gICAgLyoqKi9cbiAgfSxcblxuICAvKioqL1xuICBcIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2FjY29yZGlvbi5qc1wiOlxuICAvKiEqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiEqXFxcbiAgICAhKioqIC4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2FjY29yZGlvbi5qcyAqKiohXG4gICAgXFwqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuICAvKiEgZXhwb3J0cyBwcm92aWRlZDogZGVmYXVsdCAqL1xuXG4gIC8qKiovXG4gIGZ1bmN0aW9uIGFzc2V0c1NyY0pzTW9kdWxlc0FjY29yZGlvbkpzKG1vZHVsZSwgX193ZWJwYWNrX2V4cG9ydHNfXywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgZXZhbChcIl9fd2VicGFja19yZXF1aXJlX18ucihfX3dlYnBhY2tfZXhwb3J0c19fKTtcXG4vKipcXHJcXG4gKiBBZGRzIGJhc2ljIGZ1bmN0aW9uYWxpdHkgdG8gdGhlIGFjY29yZGlvbiBjb21wb25lbnQuXFxyXFxuICpcXHJcXG4gKiBAbGluayAgIGh0dHBzOi8vbGVzcHJ4Lm1vbmRheS5jb20vZG9jcy80ODIyNzM1MzUxP2Jsb2NrSWQ9OTNhNmY2MzktNTY2ZS00NWFjLWEzNjMtYjYyM2QxZTc1ZjM2XFxyXFxuICogQGF1dGhvciBMZXMgUHLDqXRlbnRpZXV4XFxyXFxuICovXFxyXFxuXFxyXFxuLyogaGFybW9ueSBkZWZhdWx0IGV4cG9ydCAqLyBfX3dlYnBhY2tfZXhwb3J0c19fW1xcXCJkZWZhdWx0XFxcIl0gPSAoZnVuY3Rpb24gKCkge1xcclxcblxcdHZhciAkID0galF1ZXJ5O1xcclxcblxcclxcblxcdGluaXQoKTtcXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBJbml0aWFsaXplcyBhY2NvcmRpb25zIHdoZW4gdGhlIHdpbmRvdyBoYXMgYmVlbiBsb2FkZWQuXFxyXFxuXFx0ICovXFxyXFxuXFx0JCh3aW5kb3cpLm9uKFxcXCJsb2FkXFxcIiwgZnVuY3Rpb24gKCkge1xcclxcblxcdFxcdGluaXQoKTtcXHJcXG5cXHR9KTtcXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBJbml0aWFsaXplcyBhY2NvcmRpb25zIHdoZW4gdGhlIHdpbmRvdyByZXNpemVzLlxcclxcblxcdCAqL1xcclxcblxcdCQod2luZG93KS5yZXNpemUoZnVuY3Rpb24gKCkge1xcclxcblxcdFxcdGluaXQoKTtcXHJcXG5cXHR9KTtcXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBUb2dnbGVzIHRoZSBhY2NvcmRpb24gc3RhdGUgd2hlbiB0aGUgYWNjb3JkaW9uIGhlYWQgaXMgY2xpY2tlZC5cXHJcXG5cXHQgKi9cXHJcXG5cXHQkKFxcXCIuYy1hY2NvcmRpb25faGVhZFxcXCIpLmNsaWNrKGZ1bmN0aW9uICgpIHtcXHJcXG5cXHRcXHR2YXIgJGNvbXBvbmVudCA9ICQodGhpcykuY2xvc2VzdChcXFwiLmMtYWNjb3JkaW9uXFxcIik7XFxyXFxuXFxyXFxuXFx0XFx0JGNvbXBvbmVudC50b2dnbGVDbGFzcyhcXFwiaXMtZXhwYW5kZWRcXFwiKTtcXHJcXG5cXHRcXHQkY29tcG9uZW50LmF0dHIoXFxcImFyaWEtZXhwYW5kZWRcXFwiLCAkY29tcG9uZW50LmF0dHIoXFxcImFyaWEtZXhwYW5kZWRcXFwiKSA9PSBcXFwidHJ1ZVxcXCIgPyBcXFwiZmFsc2VcXFwiIDogXFxcInRydWVcXFwiKTtcXHJcXG5cXHR9KTtcXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBTZXRzIHRoZSBhY2NvcmRpb25zIGJvZHkgaGVpZ2h0LlxcclxcblxcdCAqL1xcclxcblxcdGZ1bmN0aW9uIGluaXQoKSB7XFxyXFxuXFx0XFx0JChcXFwiLmMtYWNjb3JkaW9uXFxcIikuZWFjaChmdW5jdGlvbiAoKSB7XFxyXFxuXFx0XFx0XFx0dmFyICRjb21wb25lbnQgPSAkKHRoaXMpO1xcclxcblxcdFxcdFxcdHZhciAkY29udGVudCA9ICQodGhpcykuZmluZChcXFwiLmMtYWNjb3JkaW9uX2NvbnRlbn
2RcXFwiKTtcXHJcXG5cXHJcXG5cXHRcXHRcXHQkY29tcG9uZW50WzBdLnN0eWxlLnNldFByb3BlcnR5KFxcXCItLWhlaWdodFxcXCIsICRjb250ZW50Lm91dGVySGVpZ2h0KCkgKyBcXFwicHhcXFwiKTtcXHJcXG5cXHRcXHR9KTtcXHJcXG5cXHR9XFxyXFxufSk7XFxyXFxuXFxuXFxuLy8jIHNvdXJjZVVSTD13ZWJwYWNrOi8vLy4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2FjY29yZGlvbi5qcz9cIik7XG4gICAgLyoqKi9cbiAgfSxcblxuICAvKioqL1xuICBcIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2FzaWRlLmpzXCI6XG4gIC8qISoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiohKlxcXG4gICAgISoqKiAuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9hc2lkZS5qcyAqKiohXG4gICAgXFwqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4gIC8qISBleHBvcnRzIHByb3ZpZGVkOiBkZWZhdWx0ICovXG5cbiAgLyoqKi9cbiAgZnVuY3Rpb24gYXNzZXRzU3JjSnNNb2R1bGVzQXNpZGVKcyhtb2R1bGUsIF9fd2VicGFja19leHBvcnRzX18sIF9fd2VicGFja19yZXF1aXJlX18pIHtcbiAgICBcInVzZSBzdHJpY3RcIjtcblxuICAgIGV2YWwoXCJfX3dlYnBhY2tfcmVxdWlyZV9fLnIoX193ZWJwYWNrX2V4cG9ydHNfXyk7XFxuLyogaGFybW9ueSBkZWZhdWx0IGV4cG9ydCAqLyBfX3dlYnBhY2tfZXhwb3J0c19fW1xcXCJkZWZhdWx0XFxcIl0gPSAoZnVuY3Rpb24gKCkge1xcblxcdHZhciAkID0galF1ZXJ5O1xcblxcblxcdCQoXFxcIi5jLXNoYXJlX2J1dHRvblxcXCIpLmNsaWNrKGZ1bmN0aW9uICgpIHtcXG5cXHRcXHQkKFxcXCIuYy1zaGFyZVxcXCIpLnRvZ2dsZUNsYXNzKFxcXCItdG9nZ2xlZFxcXCIpO1xcblxcdH0pO1xcblxcblxcdCQoXFxcIi5vLXNlY3Rpb24gaDNcXFwiKS5lYWNoKGZ1bmN0aW9uIChpbmRleCkge1xcblxcdFxcdGlmICgkKHRoaXMpLmh0bWwoKSAhPT0gXFxcIlBvc3R1bGVyIMOgIGwnb2ZmcmVcXFwiKSB7XFxuXFx0XFx0XFx0JChcXFwiLm8tc2VjdGlvbl9hc2lkZSB1bFxcXCIpLmFwcGVuZChcXFwiPGEgaHJlZj0nI3NlY3Rpb25cXFwiICsgaW5kZXggKyBcXFwiJyBjbGFzcz0nYy1hbmNob3InIGRhdGEtc2Nyb2xsLWFuY2hvcj5cXFwiICsgJCh0aGlzKS5odG1sKCkgKyBcXFwiPC9hPlxcXCIpO1xcblxcdFxcdH1cXG5cXHR9KTtcXG5cXG5cXHQkKFxcXCIuby1zZWN0aW9uX2NvbnRlbnQuLXBvc3QgaDNcXFwiKS5lYWNoKGZ1bmN0aW9uIChpbmRleCkge1xcblxcdFxcdCQodGhpcykuYXR0cihcXFwiaWRcXFwiLCBcXFwic2VjdGlvblxcXCIgKyBpbmRleCArIFxcXCJcXFwiKTtcXG5cXHR9KTtcXG5cXG5cXHQvLyBBbmNob3JzXFxuXFxuXFx0Ly8gJChkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24gKCkge1xcblxcdC8vIFxcdCQoXFxcIi5jLWFuY2hvclxcXCIpLmVhY2goZnVuY3Rpb24gKCkge1xcblxcdC8vIFxcdFxcdHZhciBocmVmID0gJCh0aGlzKS5hdHRyKFxcXCJocmVmXFxcIik7XFxuXFx0Ly8gXFx0XFx0dmFyICR0aGlzID0gJCh0aGlzKTtcXG5cXHQvLyBcXHRcXHR2YXIgJHByZXYgPSAkdGhpcy5wcmV2KCk7XFxuXFx0Ly8gXFx0XFx0dmFyICRuZXh0ID0gJHRoaXMubmV4dCgpO1xcblxcblxcdC8vIFxcdFxcdGNvbnNvbGUubG9nKGhyZWYpO1xcblxcblxcdC8vIFxcdFxcdFNjcm9sbFRyaWdnZXIuY3JlYXRlKHtcXG5cXHQvLyBcXHRcXHRcXHR0cmlnZ2VyOiBocmVmLFxcblxcdC8vIFxcdFxcdFxcdHN0YXJ0OiBcXFwidG9wIDI1XFxcIixcXG5cXG5cXHQvLyBcXHRcXHRcXHRvbkxlYXZlOiBmdW5jdGlvbiAoKSB7XFxuXFx0Ly8gXFx0XFx0XFx0XFx0dG9nZ2xlU2VjdGlvbigkbmV4dCk7XFxuXFx0Ly8gXFx0XFx0XFx0fSxcXG5cXG5cXHQvLyBcXHRcXHRcXHRvbkxlYXZlQmFjazogZnVuY3Rpb24gKCkge1xcblxcdC8vIFxcdFxcdFxcdFxcdHRvZ2dsZVNlY3Rpb24oJHByZXYpO1xcblxcdC8vIFxcdFxcdFxcdH0sXFxuXFxuXFx0Ly8gXFx0XFx0XFx0b25FbnRlcjogZnVuY3Rpb24gKCkge1xcblxcdC8vIFxcdFxcdFxcdFxcdHRvZ2dsZVNlY3Rpb24oJHRoaXMpO1xcblxcdC8vIFxcdFxcdFxcdH0sXFxuXFxuXFx0Ly8gXFx0XFx0XFx0b25FbnRlckJhY2s6IGZ1bmN0aW9uICgpIHtcXG5cXHQvLyBcXHRcXHRcXHRcXHR0b2dnbGVTZWN0aW9uKCR0aGlzKTtcXG5cXHQvLyBcXHRcXHRcXHR9LFxcblxcdC8vIFxcdFxcdH0pO1xcblxcdC8vIFxcdH0pO1xcblxcdC8vIH0pO1xcblxcblxcdC8vIGZ1bmN0aW9uIHRvZ2dsZVNlY3Rpb24oJGFjdGl2ZVNlY3Rpb24pIHtcXG5cXHQvLyBcXHQkKFxcXCIuYy1hbmNob3JcXFwiKS5yZW1vdmVDbGFzcyhcXFwiLWFjdGl2ZVxcXCIpO1xcblxcdC8vIFxcdCRhY3RpdmVTZWN0aW9uLmFkZENsYXNzKFxcXCItYWN0aXZlXFxcIik7XFxuXFx0Ly8gfVxcbn0pO1xcblxcblxcbi8vIyBzb3VyY2VVUkw9d2VicGFjazovLy8uL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9hc2lkZS5qcz9cIik7XG4gICAgLyoqKi9cbiAgfSxcblxuICAvKioqL1xuICBcIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2Jsb2dGaWx0ZXJzLmpzXCI6XG4gIC8qISoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiohKlxcXG4gICAgISoqKiAuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9ibG9nRmlsdGVycy5qcyAqKiohXG4gICAgXFwqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4gIC8qISBleHBvcnRzIHByb3ZpZGVkOiBkZWZhdWx0ICovXG5cbiAgLyoqKi9cbiAgZnVuY3Rpb24gYXNzZXRzU3JjSnNNb2R1bGVzQmxvZ0ZpbHRlcnNKcyhtb2R1bGUsIF9fd2VicGFja19leHBvcnRzX18sIF9fd2VicGFja19yZXF1aXJlX18pIHtcbiAgICBcInVzZSBzdHJpY3RcIjtcblxuICAgIGV2YWwoXCJfX3dlYnBhY2tfcmVxdWlyZV9fLnIoX193ZWJwYWNrX2V4cG9ydHNfXyk7XFxuLyogaGFybW9ueSBkZWZhdWx0IGV4cG9ydCAqLyBfX3dlYnBhY2tfZXhwb3J0c19fW1xcXCJkZWZhdWx0XFxcIl0gPSAoZnVuY3Rpb24gKCkge1xcblxcdHZhciAkID0galF1ZXJ5O1xcblxcblxcdCQoXFxcIi5jLWZpbHRlclxcXCIpLmNsaWNrKGZ1bmN0aW9uICgpIHtcXG5cXHRcXHQkKFxcXCIuYy1maWx0ZXJcXFwiKS5yZW1vdmVDbGFzcyhcXFwiLWFjdGl2ZVxcXCIpO1xcblxcdFxcdCQodGhpcykuYWRk
2Q2xhc3MoXFxcIi1hY3RpdmVcXFwiKTtcXG5cXHR9KTtcXG59KTtcXG5cXG5cXG4vLyMgc291cmNlVVJMPXdlYnBhY2s6Ly8vLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvYmxvZ0ZpbHRlcnMuanM/XCIpO1xuICAgIC8qKiovXG4gIH0sXG5cbiAgLyoqKi9cbiAgXCIuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9jYXJvdXNlbC5qc1wiOlxuICAvKiEqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqISpcXFxuICAgICEqKiogLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvY2Fyb3VzZWwuanMgKioqIVxuICAgIFxcKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuICAvKiEgZXhwb3J0cyBwcm92aWRlZDogZGVmYXVsdCAqL1xuXG4gIC8qKiovXG4gIGZ1bmN0aW9uIGFzc2V0c1NyY0pzTW9kdWxlc0Nhcm91c2VsSnMobW9kdWxlLCBfX3dlYnBhY2tfZXhwb3J0c19fLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICBldmFsKFwiX193ZWJwYWNrX3JlcXVpcmVfXy5yKF9fd2VicGFja19leHBvcnRzX18pO1xcbi8qKlxcclxcbiAqIEZsaWNraXR5IGNhcm91c2VscyBoZWxwZXJzIGFuZCBleHRlbmRzIGZ1bmN0aW9ucy5cXHJcXG4gKlxcclxcbiAqIEBsaW5rICAgaHR0cHM6Ly9sZXNwcngubW9uZGF5LmNvbS9kb2NzLzI1OTU3OTkxNjI/YmxvY2tJZD01N2MxN2M0Yi1iMWExLTQ5MTAtYTQ4Yi1hZGI0YzZjNmU4MDBcXHJcXG4gKiBAYXV0aG9yIExlcyBQcsOpdGVudGlldXhcXHJcXG4gKi9cXHJcXG5cXHJcXG4vKiBoYXJtb255IGRlZmF1bHQgZXhwb3J0ICovIF9fd2VicGFja19leHBvcnRzX19bXFxcImRlZmF1bHRcXFwiXSA9IChmdW5jdGlvbiAoKSB7XFxyXFxuXFx0dmFyICQgPSBqUXVlcnk7XFxyXFxuXFxyXFxuXFx0LyoqXFxyXFxuXFx0ICogUmVzaXplcyB0aGUgY2Fyb3VzZWxzIHdoZW4gZG9jdW1lbnQgaXMgcmVhZHlcXHJcXG5cXHQgKi9cXHJcXG5cXHQkKGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbiAoKSB7XFxyXFxuXFx0XFx0cmVzaXplQ2Fyb3VzZWxzKCk7XFxyXFxuXFx0fSk7XFxyXFxuXFxyXFxuXFx0LyoqXFxyXFxuXFx0ICogUmVzaXplcyB0aGUgY2Fyb3VzZWxzIHdoZW4gd2luZG93IGlzIGxvYWRlZFxcclxcblxcdCAqIGFuZCB1cGRhdGVzIGNhcm91c2VsIGJ1dHRvbnNcXHJcXG5cXHQgKi9cXHJcXG5cXHQkKHdpbmRvdykub24oXFxcImxvYWRcXFwiLCBmdW5jdGlvbiAoKSB7XFxyXFxuXFx0XFx0cmVzaXplQ2Fyb3VzZWxzKCk7XFxyXFxuXFx0XFx0dXBkYXRlQ2Fyb3VzZWxzQWN0aW9ucygpO1xcclxcblxcdFxcdGNhcm91c2VsRG90cygpO1xcclxcblxcdH0pO1xcclxcblxcclxcblxcdC8qKlxcclxcblxcdCAqIFVwZGF0ZXMgY2Fyb3VzZWwgYnV0dG9ucyB3aGVuIHdpbmRvdyByZXNpemVzXFxyXFxuXFx0ICovXFxyXFxuXFx0JCh3aW5kb3cpLm9uKFxcXCJyZXNpemVcXFwiLCBmdW5jdGlvbiAoKSB7XFxyXFxuXFx0XFx0dXBkYXRlQ2Fyb3VzZWxzQWN0aW9ucygpO1xcclxcblxcdH0pO1xcclxcblxcclxcblxcdC8qKlxcclxcblxcdCAqIERpc2FibGVzIHRoZSBjYXJvdXNlbCdzIGNlbGxzIHBvaW50ZXJzIGV2ZW50cyB0byBwcmV2ZW50IHVzZXIgZnJvbSBjbGlja2luZyB0aGUgY2VsbCB3aGlsZSBkcmFnZ2luZ1xcclxcblxcdCAqL1xcclxcblxcdCQoXFxcIi5vLWNhcm91c2VsXFxcIikuZWFjaChmdW5jdGlvbiAoKSB7XFxyXFxuXFx0XFx0JCh0aGlzKS5vbihcXFwiZHJhZ1N0YXJ0LmZsaWNraXR5XFxcIiwgKCkgPT4gJCh0aGlzKS5maW5kKFxcXCIuby1jYXJvdXNlbF9jZWxsXFxcIikuY3NzKFxcXCJwb2ludGVyLWV2ZW50c1xcXCIsIFxcXCJub25lXFxcIikpO1xcclxcblxcdFxcdCQodGhpcykub24oXFxcImRyYWdFbmQuZmxpY2tpdHlcXFwiLCAoKSA9PiAkKHRoaXMpLmZpbmQoXFxcIi5vLWNhcm91c2VsX2NlbGxcXFwiKS5jc3MoXFxcInBvaW50ZXItZXZlbnRzXFxcIiwgXFxcImFsbFxcXCIpKTtcXHJcXG5cXHR9KTtcXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBTZWxlY3RzIHRoZSBjYXJvdXNlbCdzIHByZXZpb3VzIGNlbGwgYW5kIHN0b3BzIHRoZSBhdXRvcGxheVxcclxcblxcdCAqL1xcclxcblxcdCQoXFxcIi5vLWNhcm91c2VsX2J0bi4tcHJldlxcXCIpLm9uKFxcXCJjbGlja1xcXCIsIGZ1bmN0aW9uICgpIHtcXHJcXG5cXHRcXHR2YXIgJGFjdGlvbnMgPSAkKHRoaXMpLmNsb3Nlc3QoXFxcIi5vLWNhcm91c2VsX2FjdGlvbnNcXFwiKTtcXHJcXG5cXHRcXHR2YXIgY2Fyb3VzZWxJRCA9ICRhY3Rpb25zLmRh
2dGEoXFxcImNhcm91c2VsLWZvclxcXCIpO1xcclxcblxcdFxcdHZhciAkY2Fyb3VzZWwgPSAkKCcuby1jYXJvdXNlbFtkYXRhLWNhcm91c2VsLWlkPVxcXCInICsgY2Fyb3VzZWxJRCArICdcXFwiXScpO1xcclxcblxcdFxcdHZhciBmbGt0eSA9IEZsaWNraXR5LmRhdGEoJGNhcm91c2VsWzBdKTtcXHJcXG5cXHRcXHRmbGt0eS5wcmV2aW91cygpO1xcclxcblxcdFxcdGZsa3R5LnN0b3BQbGF5ZXIoKTtcXHJcXG5cXHR9KTtcXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBTZWxlY3RzIHRoZSBjYXJvdXNlbCdzIG5leHQgY2VsbCBhbmQgc3RvcHMgdGhlIGF1dG9wbGF5XFxyXFxuXFx0ICovXFxyXFxuXFx0JChcXFwiLm8tY2Fyb3VzZWxfYnRuLi1uZXh0XFxcIikub24oXFxcImNsaWNrXFxcIiwgZnVuY3Rpb24gKCkge1xcclxcblxcdFxcdHZhciAkYWN0aW9ucyA9ICQodGhpcykuY2xvc2VzdChcXFwiLm8tY2Fyb3VzZWxfYWN0aW9uc1xcXCIpO1xcclxcblxcdFxcdHZhciBjYXJvdXNlbElEID0gJGFjdGlvbnMuZGF0YShcXFwiY2Fyb3VzZWwtZm9yXFxcIik7XFxyXFxuXFx0XFx0dmFyICRjYXJvdXNlbCA9ICQoJy5vLWNhcm91c2VsW2RhdGEtY2Fyb3VzZWwtaWQ9XFxcIicgKyBjYXJvdXNlbElEICsgJ1xcXCJdJyk7XFxyXFxuXFx0XFx0dmFyIGZsa3R5ID0gRmxpY2tpdHkuZGF0YSgkY2Fyb3VzZWxbMF0pO1xcclxcblxcdFxcdGZsa3R5Lm5leHQoKTtcXHJcXG5cXHRcXHRmbGt0eS5zdG9wUGxheWVyKCk7XFxyXFxuXFx0fSk7XFxyXFxuXFxyXFxuXFx0LyoqXFxyXFxuXFx0ICogUmVzaXplcyB0aGUgY2Fyb3VzZWxzIHRvIG1ha2Ugc3VyZSB0aGV5IGFyZSBwcm9wZXJseSBwb3NpdGlvbmVkXFxyXFxuXFx0ICovXFxyXFxuXFx0ZnVuY3Rpb24gcmVzaXplQ2Fyb3VzZWxzKCkge1xcclxcblxcdFxcdCQoXFxcIi5vLWNhcm91c2VsXFxcIikuZWFjaChmdW5jdGlvbiAoKSB7XFxyXFxuXFx0XFx0XFx0dmFyIGZsa3R5ID0gRmxpY2tpdHkuZGF0YSgkKHRoaXMpWzBdKTtcXHJcXG5cXHRcXHRcXHRmbGt0eS5yZXNpemUoKTtcXHJcXG5cXHRcXHR9KTtcXHJcXG5cXHR9XFxyXFxuXFxyXFxuXFx0LyoqXFxyXFxuXFx0ICogSGlkZXMgb3Igc2hvd3MgdGhlIGNhcm91c2VsJ3MgYnV0dG9ucyB3aGVuIHRoZSBudW1iZXIgb2Ygc2xpZGVzIGlzIHNtYWxsZXIgdGhhbiAyXFxyXFxuXFx0ICogKG9ubHkgd29ya3Mgd2l0aCBncm91cENlbGxzIGVuYWJsZWQpXFxyXFxuXFx0ICovXFxyXFxuXFx0ZnVuY3Rpb24gdXBkYXRlQ2Fyb3VzZWxzQWN0aW9ucygpIHtcXHJcXG5cXHRcXHQkKFxcXCIuby1jYXJvdXNlbFxcXCIpLmVhY2goZnVuY3Rpb24gKCkge1xcclxcblxcdFxcdFxcdHZhciBjYXJvdXNlbElEID0galF1ZXJ5KHRoaXMpLmRhdGEoXFxcImNhcm91c2VsLWlkXFxcIik7XFxyXFxuXFx0XFx0XFx0dmFyIGZsa3R5ID0gRmxpY2tpdHkuZGF0YSgkKHRoaXMpWzBdKTtcXHJcXG5cXHJcXG5cXHRcXHRcXHRpZiAoZmxrdHkuc2xpZGVzLmxlbmd0aCA8IDIpIHtcXHJcXG5cXHRcXHRcXHRcXHRqUXVlcnkoXFxcIi5vLWNhcm91c2VsX2FjdGlvbnNbZGF0YS1jYXJvdXNlbC1mb3I9J1xcXCIgKyBjYXJvdXNlbElEICsgXFxcIiddXFxcIikuaGlkZSgpO1xcclxcblxcdFxcdFxcdH0gZWxzZSB7XFxyXFxuXFx0XFx0XFx0XFx0alF1ZXJ5KFxcXCIuby1jYXJvdXNlbF9hY3Rpb25zW2RhdGEtY2Fyb3VzZWwtZm9yPSdcXFwiICsgY2Fyb3VzZWxJRCArIFxcXCInXVxcXCIpLnNob3coKTtcXHJcXG5cXHRcXHRcXHR9XFxyXFxuXFx0XFx0fSk7XFxyXFxuXFx0fVxcclxcblxcclxcblxcdGZ1bmN0aW9uIGNhcm91c2VsRG90cygpIHtcXHJcXG5cXHRcXHR2YXIgJGNvbnRhaW5lciA9ICQoXFxcImJvZHlcXFwiKTtcXHJcXG5cXHRcXHR2YXIgJHNsaWRlciA9ICRjb250YWluZXIuZmluZChcXFwiLm8tY2Fyb3VzZWwuLWpzLWRvdHNcXFwiKTtcXHJcXG5cXHRcXHR2YXIgZmxrdHkgPSAkc2xpZGVyLmRhdGEoXFxcImZsaWNraXR5XFxcIik7XFxyXFxuXFx0XFx0aWYgKGZsa3R5KSB7XFxyXFxuXFx0XFx0XFx0dmFyIHNsaWRlQ291bnQgPSBmbGt0eS5zbGlkZXMubGVuZ3RoO1xcclxcblxcdFxcdFxcdHZhciAkcGFnZXJzID0gJHNsaWRlci5jbG9zZXN0KFxcXCIuby1zZWN0aW9uX2lubmVyXFxcIikuZmluZChcXFwiLm8tY2Fyb3VzZWxfZG90c1xcXCIpO1xcclxcblxcclxcblxcdFxcdFxcdGZvciAodmFyIGkgPSAwOyBpIDwgc2xpZGVDb3VudDsgaSsrKSB7XFxyXFxuXFx0XFx0XFx0XFx0JHBhZ2Vycy5hcHBlbmQoXFxcIjxzcGFuPjwvc3Bhbj5cXFwiKTtcXHJcXG5cXHRcXHRcXHR9XFxyXFxuXFxyXFxuXFx0XFx0XFx0dmFyICRwYWdlciA9ICRwYWdlcnMuZmluZChcXFwic3BhblxcXCIpO1xcclxcblxcclxcblxcdFxcdFxcdCRwYWdlci5maXJzdCgpLmFkZENsYXNzKFxcXCJpcy1zZWxlY3RlZFxcXCIpO1xcclxcblxcclxcblxcdFxcdFxcdCRzbGlkZXIub24oXFxcInNlbGVjdC5mbGlja2l0eVxcXCIsIGZ1bmN0aW9uICgpIHtcXHJcXG5cXHRcXHRcXHRcXHQkcGFnZXIuZmlsdGVyKFxcXCIuaXMtc2VsZWN0ZWRcXFwiKS5yZW1vdmVDbGFzcyhcXFwiaXMtc2VsZWN0ZWRcXFwiKTtcXHJcXG5cXHRcXHRcXHRcXHQkcGFnZXIuZXEoZmxrdHkuc2VsZWN0ZWRJbmRleCkuYWRkQ2xhc3MoXFxcImlzLXNlbGVjdGVkXFxcIik7XFxyXFxuXFx0XFx0XFx0fSk7XFxyXFxuXFxyXFxuXFx0XFx0XFx0JHBhZ2Vycy5vbihcXFwiY2xpY2tcXFwiLCBcXFwic3BhblxcXCIsIGZ1bmN0aW9uICgpIHtcXHJcXG5cXHRcXHRcXHRcXHR2YXIgaW5kZXggPSAkKHRoaXMpLmluZGV4KCk7XFxyXFxuXFx0XFx0XFx0XFx0JHNsaWRlci5mbGlja2l0eShcXFwic2VsZWN0XFxcIiwgaW5kZXgpO1xcclxcblxcdFxcdFxcdH0pO1xcclxcblxcdFxcdH1cXHJcXG5cXHR9XFxyXFxufSk7XFxyXFxuXFxuXFxuLy8jIHNvdXJjZVVSTD13ZWJwYWNrOi8vLy4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2Nhcm91c2VsLmpzP1wiKTtcbiAgICAvKioqL1xuICB9LFxuXG4gIC8qKiovXG4gIFwiLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvY2Y3LmpzXCI6XG4gIC8qISoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqISpcXFxuICAgICEqKiogLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvY2Y3LmpzICoqKiFcbiAgICBcXCoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4gIC8qISBleHBvcnRzIHByb3ZpZGVkOiBkZWZhdWx0ICovXG5cbiAgLyoqKi9cbiAgZnVuY3Rpb24gYXNzZXRzU3JjSnNNb2R1bGVzQ2Y3SnMobW9kdWxlLCBfX3dlYnBhY2tfZXhwb3J0c19fLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICBldmFsKFwiX193ZWJwYWNrX3JlcXVpcmVfXy5yKF9fd2VicGFja19leHBvcnRzX18pO1xcbi8qIGhhcm1vbnkgZGVmYXVsdCBleHBvcnQgKi8gX193ZWJwYWNrX2V4cG9ydHNfX1tcXFwiZGVmYXVsdFxcXCJdID0gKGZ1bmN0aW9uICgpIHtcXHJcXG5cXHR2YXIgJCA9IGpRdWVyeTtcXHJcXG5cXHJcXG5cXHR2YXIgdGltZW91dDtcXHJcXG5cXHR2YXIgJHdwY2Y3Rm9ybXMgPSAkKFxcXCIud3BjZjctZm9ybVxcXCIpO1xcclxcblxcclxcblxcdGZ1bmN0aW9uIGNhbGxiYWNrKG11dGF0aW9uc0xpc3QsIG9ic2VydmVyKSB7XFxyXFxuXFx0XFx0bXV0YXRpb25zTGlzdC5mb3JFYWNoKChtdXRhdGlvbikgPT4ge1xcclxcblxcdFxcdFxcdGlmIChtdXRhdGlvbi5hdHRyaWJ1dGVOYW1lID09PSBcXFwiZGF0YS1zdGF0dXNcXFwiKSB7XFxyXFxuXFx0XFx0XFx0XFx0aWYgKG11dGF0aW9uLm9sZFZhbHVlICE9IFxcXCJpbml0XFxcIiAmJiBtdXRhdGlvbi5vbGRWYWx1ZSAhPSBcXFwidmFsaWRhdGluZ1xcXCIgJiYgbXV0YXRpb24ub2xkVmFsdWUgIT0gXFxcInJlc2V0dGluZ1xcXCIpIHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRjbGVhclRpbWVvdXQodGltZW91dCk7XFxyXFxuXFx0XFx0XFx0XFx0XFx0JChtdXRhdGlvbi50YXJnZXQpLmZpbmQoXFxcIi53cGNm
2Ny1yZXNwb25zZS1vdXRwdXRcXFwiKS5hZGRDbGFzcyhcXFwiaXMtYWN0aXZlXFxcIik7XFxyXFxuXFxyXFxuXFx0XFx0XFx0XFx0XFx0dGltZW91dCA9IHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdCQobXV0YXRpb24udGFyZ2V0KS5maW5kKFxcXCIud3BjZjctcmVzcG9uc2Utb3V0cHV0XFxcIikucmVtb3ZlQ2xhc3MoXFxcImlzLWFjdGl2ZVxcXCIpO1xcclxcblxcdFxcdFxcdFxcdFxcdH0sIDUwMDApO1xcclxcblxcclxcblxcdFxcdFxcdFxcdFxcdGlmIChtdXRhdGlvbi50YXJnZXQuY2xhc3NOYW1lID09IFxcXCJ3cGNmNy1mb3JtIHN1Ym1pdHRpbmdcXFwiKSB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0aWYgKCQoXFxcImh0bWxcXFwiKS5hdHRyKFxcXCJsYW5nXFxcIikgPT0gXFxcImZyXFxcIikge1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdCQobXV0YXRpb24udGFyZ2V0KS5maW5kKFxcXCIud3BjZjctcmVzcG9uc2Utb3V0cHV0XFxcIikudGV4dChcXFwiRW52b2kuLi5cXFwiKTtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHR9IGVsc2Uge1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdCQobXV0YXRpb24udGFyZ2V0KS5maW5kKFxcXCIud3BjZjctcmVzcG9uc2Utb3V0cHV0XFxcIikudGV4dChcXFwiU2VuZGluZy4uLlxcXCIpO1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdH1cXHJcXG5cXHRcXHRcXHRcXHRcXHR9XFxyXFxuXFx0XFx0XFx0XFx0fVxcclxcblxcdFxcdFxcdH1cXHJcXG5cXHRcXHR9KTtcXHJcXG5cXHR9XFxyXFxuXFxyXFxuXFx0Y29uc3QgbXV0YXRpb25PYnNlcnZlciA9IG5ldyBNdXRhdGlvbk9ic2VydmVyKGNhbGxiYWNrKTtcXHJcXG5cXHJcXG5cXHQkd3BjZjdGb3Jtcy5lYWNoKGZ1bmN0aW9uICgpIHtcXHJcXG5cXHRcXHRtdXRhdGlvbk9ic2VydmVyLm9ic2VydmUodGhpcywgeyBhdHRyaWJ1dGVzOiB0cnVlLCBhdHRyaWJ1dGVPbGRWYWx1ZTogdHJ1ZSB9KTtcXHJcXG5cXHR9KTtcXHJcXG59KTtcXHJcXG5cXG5cXG4vLyMgc291cmNlVVJMPXdlYnBhY2s6Ly8vLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvY2Y3LmpzP1wiKTtcbiAgICAvKioqL1xuICB9LFxuXG4gIC8qKiovXG4gIFwiLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvY3Vyc29yLmpzXCI6XG4gIC8qISoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqISpcXFxuICAgICEqKiogLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvY3Vyc29yLmpzICoqKiFcbiAgICBcXCoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4gIC8qISBleHBvcnRzIHByb3ZpZGVkOiBkZWZhdWx0ICovXG5cbiAgLyoqKi9cbiAgZnVuY3Rpb24gYXNzZXRzU3JjSnNNb2R1bGVzQ3Vyc29ySnMobW9kdWxlLCBfX3dlYnBhY2tfZXhwb3J0c19fLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICBldmFsKFwiX193ZWJwYWNrX3JlcXVpcmVfXy5yKF9fd2VicGFja19leHBvcnRzX18pO1xcbi8qKlxcclxcbiAqIEJhc2ljIGN1c3RvbSBjdXJzb3Igd2l0aCBsZXJwIGVhc2luZy5cXHJcXG4gKlxcclxcbiAqIEBsaW5rICAgaHR0cHM6Ly9sZXNwcngubW9uZGF5LmNvbS9kb2NzLzQ4MjI3MzUzNTE/YmxvY2tJZD1hODM3OTgyMC05ODkwLTRhZjItYTgzOC1jYmUwYmZjOGQzZWJcXHJcXG4gKiBAYXV0aG9yIExlcyBQcsOpdGVudGlldXhcXHJcXG4gKi9cXHJcXG5cXHJcXG4vKiBoYXJtb255IGRlZmF1bHQgZXhwb3J0ICovIF9fd2VicGFja19leHBvcnRzX19bXFxcImRlZmF1bHRcXFwiXSA9IChmdW5jdGlvbiAoKSB7XFxyXFxuXFx0dmFyICQgPSBqUXVlcnk7XFxyXFxuXFxyXFxuXFx0Ly8gVGhlIGxlcnAgZWFzaW5nIChob3cgc21vb3RobHkgdGhlIGN1cnNvciBmb2xsb3dzIHRoZSBtb3VzZSBwb2ludGVyKVxcclxcblxcdHZhciBlYXNpbmcgPSAwLjM1O1xcclxcblxcdHZhciAkY3Vyc29yID0gJChcXFwiLmMtY3Vyc29yXFxcIik7XFxyXFxuXFxyXFxuXFx0dmFyIG1vdXNlWCA9IDA7XFxyXFxuXFx0dmFyIG1vdXNlWSA9IDA7XFxyXFxuXFxyXFxuXFx0dmFyIGN1cnNvclRyYW5zbGF0ZVggPSAwO1xcclxcblxcdHZhciBjdXJzb3JUcmFuc2xhdGVZID0gMDtcXHJcXG5cXHJcXG5cXHR3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lID0gd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSB8fCB3aW5kb3cubW96UmVxdWVzdEFuaW1hdGlvbkZyYW1lIHx8IHdpbmRvdy53ZWJraXRSZXF1ZXN0QW5pbWF0aW9uRnJhbWUgfHwgd2luZG93Lm1zUmVxdWVzdEFuaW1hdGlvbkZyYW1lO1xcclxcblxcclxcblxcdHJlcXVlc3RBbmltYXRpb25GcmFtZShhbmltYXRlKTtcXHJcXG5cXHJcXG5cXHQkKFxcXCIuby1jYXJvdXNlbFxcXCIpLm9uKFxcXCJkcmFnTW92ZS5mbGlja2l0eVxcXCIsIGZ1bmN0aW9uIChldmVudCkge1xcclxcblxcdFxcdG1vdXNlWCA9IGV2ZW50LmNsaWVudFg7XFxyXFxuXFx0XFx0bW91c2VZID0gZXZlbnQuY2xpZW50WTtcXHJcXG5cXHR9KTtcXHJcXG5cXHJcXG5cXHQkKHdpbmRvdykubW91c2Vtb3ZlKGZ1bmN0aW9uIChldmVudCkge1xcclxcblxcdFxcdG1vdXNlWCA9IGV2ZW50LmNsaWVudFg7XFxyXFxuXFx0XFx0bW91c2VZID0gZXZlbnQuY2xpZW50WTtcXHJcXG5cXHR9KTtcXHJcXG5cXHJcXG5cXHRmdW5jdGlvbiBhbmltYXRlKCkge1xcclxcblxcdFxcdHZhciBjdXJzb3JXaWR0aCA9ICRjdXJzb3Iub3V0ZXJXaWR0aCgpO1xcclxcblxcdFxcdHZhciBjdXJzb3JIZWlnaHQgPSAkY3Vyc29yLm91dGVySGVpZ2h0KCk7XFxyXFxuXFxyXFxuXFx0XFx0Y3Vyc29yVHJhbnNsYXRlWCA9IGxlcnAoY3Vyc29yVHJhbnNsYXRlWCwgbW91c2VYLCBlYXNpbmcpO1xcclxcblxcdFxcdGN1cnNvclRyYW5zbGF0ZVkgPSBsZXJwKGN1cnNvclRyYW5zbGF0ZVksIG1vdXNlWSwgZWFzaW5nKTtcXHJcXG5cXHJcXG5cXHRcXHQkY3Vyc29yLmNzcyhcXFwidHJhbnNmb3JtXFxcIiwgXFxcInRyYW5zbGF0ZTNkKFxcXCIgKyAoY3Vyc29yVHJhbnNsYXRlWCAtIGN1cnNvcldpZHRoIC8gMikgKyBcXFwicHgsIFxcXCIgKyAoY3Vyc29yVHJhbnNsYXRlWSAtIGN1cnNvckhlaWdodCAvID
2IpICsgXFxcInB4LCAwKVxcXCIpO1xcclxcblxcclxcblxcdFxcdHJlcXVlc3RBbmltYXRpb25GcmFtZShhbmltYXRlKTtcXHJcXG5cXHR9XFxyXFxuXFxyXFxuXFx0ZnVuY3Rpb24gbGVycChzdGFydCwgZW5kLCBhbXQpIHtcXHJcXG5cXHRcXHRyZXR1cm4gKDEgLSBhbXQpICogc3RhcnQgKyBhbXQgKiBlbmQ7XFxyXFxuXFx0fVxcclxcblxcclxcblxcdC8qKlxcclxcbiAgICAgKiBUbyBjaGFuZ2UgdGhlIGN1cnNvcidzIHN0YXRlIGRlcGVuZGluZyBvbiB3aGF0IGlzIGJlaW5nIGhvdmVyZWRcXHJcXG5cXHQkKGRvY3VtZW50KS5vbihcXHJcXG5cXHRcXHR7XFxyXFxuXFx0XFx0XFx0bW91c2VvdmVyOiBmdW5jdGlvbiAoZXZlbnQpIHtcXHJcXG5cXHRcXHRcXHRcXHRldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcXHJcXG5cXHRcXHRcXHRcXHQkKFxcXCIuYy1jdXJzb3JcXFwiKS5hZGRDbGFzcyhcXFwiaXMtcG9pbnRlclxcXCIpO1xcclxcblxcdFxcdFxcdH0sXFxyXFxuXFx0XFx0XFx0bW91c2VvdXQ6IGZ1bmN0aW9uIChldmVudCkge1xcclxcblxcdFxcdFxcdFxcdGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xcclxcblxcdFxcdFxcdFxcdCQoXFxcIi5jLWN1cnNvclxcXCIpLnJlbW92ZUNsYXNzKFxcXCJpcy1wb2ludGVyXFxcIik7XFxyXFxuXFx0XFx0XFx0fSxcXHJcXG5cXHRcXHR9LFxcclxcblxcdFxcdFxcXCIuanMtY3Vyc29yLWlzLXBvaW50ZXJcXFwiXFxyXFxuXFx0KTsgXFxyXFxuICAgICovXFxyXFxufSk7XFxyXFxuXFxuXFxuLy8jIHNvdXJjZVVSTD13ZWJwYWNrOi8vLy4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2N1cnNvci5qcz9cIik7XG4gICAgLyoqKi9cbiAgfSxcblxuICAvKioqL1xuICBcIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2ZpbGUuanNcIjpcbiAgLyohKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqISpcXFxuICAgICEqKiogLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvZmlsZS5qcyAqKiohXG4gICAgXFwqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbiAgLyohIGV4cG9ydHMgcHJvdmlkZWQ6IGRlZmF1bHQgKi9cblxuICAvKioqL1xuICBmdW5jdGlvbiBhc3NldHNTcmNKc01vZHVsZXNGaWxlSnMobW9kdWxlLCBfX3dlYnBhY2tfZXhwb3J0c19fLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICBldmFsKFwiX193ZWJwYWNrX3JlcXVpcmVfXy5yKF9fd2VicGFja19leHBvcnRzX18pO1xcbi8qKlxcclxcbiAqIEFkZHMgYmFzaWMgZnVuY3Rpb25hbGl0eSB0byB0aGUgZmlsZSBjb21wb25lbnQuXFxyXFxuICpcXHJcXG4gKiBAbGluayAgIGh0dHBzOi8vbGVzcHJ4Lm1vbmRheS5jb20vZG9jcy80ODIyNzM1MzUxP2Jsb2NrSWQ9ZmI0ZjU3N2EtYTU2ZS00ZmVjLWExNzItYzJlZWExYTRhM2E3XFxyXFxuICogQGF1dGhvciBMZXMgUHLDqXRlbnRpZXV4XFxyXFxuICovXFxyXFxuXFxyXFxuLyogaGFybW9ueSBkZWZhdWx0IGV4cG9ydCAqLyBfX3dlYnBhY2tfZXhwb3J0c19fW1xcXCJkZWZhdWx0XFxcIl0gPSAoZnVuY3Rpb24gKCkge1xcclxcblxcdHZhciAkID0galF1ZXJ5O1xcclxcblxcclxcblxcdC8qKlxcclxcblxcdCAqIEdlbmVyYXRlcyBtYXJrdXAgd2hlbiBmaWxlIGlucHV0IGNoYW5nZXNcXHJcXG5cXHQgKi9cXHJcXG5cXHQkKFxcXCIuYy1maWxlIGlucHV0XFxcIikuY2hhbmdlKGZ1bmN0aW9uICgpIHtcXHJcXG5cXHRcXHR2YXIgJGZpbGUgPSAkKHRoaXMpLmNsb3Nlc3QoXFxcIi5jLWZpbGVcXFwiKTtcXHJcXG5cXHRcXHR2YXIgZmlsZW5hbWUgPSAkKHRoaXMpXFxyXFxuXFx0XFx0XFx0LnZhbCgpXFxyXFxuXFx0XFx0XFx0LnJlcGxhY2UoL0M6XFxcXFxcXFxmYWtlcGF0aFxcXFxcXFxcL2ksIFxcXCJcXFwiKTtcXHJcXG5cXHRcXHR2YXIgZmlsZXNpemUgPSBqUXVlcnkodGhpcylbMF0uZmlsZXNbMF0uc2l6ZTtcXHJcXG5cXHRcXHR2YXIgZmlsZXNpemUgPSBmaWxlc2l6ZSAvIDEwMDA7XFxyXFxuXFx0XFx0dmFyIGZpbGV1bml0ID0gXFxcImtvXFxcIjtcXHJcXG5cXHJcXG5cXHRcXHRpZiAoZmlsZXNpemUgPj0gMTAwMCkge1xcclxcblxcdFxcdFxcdGZpbGVzaXplID0gZmlsZXNpemUgLyAxMDAwO1xcclxcblxcdFxcdFxcdGZpbGV1bml0ID0gXFxcIm1vXFxcIjtcXHJcXG5cXHRcXHR9XFxyXFxuXFxyXFxuXFx0XFx0JChcXFwiLmMtZmlsZVxcXCIpLmFkZENsYXNzKFxcXCJpcy10b2dnbGVkXFxcIik7XFxyXFxuXFxyXFxuXFx0XFx0ZmlsZXNpemUgPSBNYXRoLnJvdW5kKGZpbGVzaXplICogMTApIC8gMTA7XFxyXFxuXFxyXFxuXFx0XFx0JGZpbGUuZmluZChcXFwiLmMtZmlsZV9kb2N1bWVudFxcXCIpLnJlbW92ZSgpO1xcclxcblxcclxcblxcdFxcdCRmaWxlLmFwcGVuZCgnPGRpdiBjbGFzcz1cXFwiYy1maWxlX2RvY3VtZW50XFxcIj48ZGl2IGNsYXNzPVxcXCJjLWZpbGVfbWV0YVxcXCI+PHNwYW4gY2xhc3M9XFxcImMtZmlsZV9uYW1lXFxcIj4nICsgZmlsZW5hbWUgKyAnPC9zcGFuPjxzcGFuIGNsYXNzPVxcXCJjLWZpbGVfc2l6ZVxcXCI+JyArIGZpbGVzaXplICsgXFxcIiBcXFwiICsgZmlsZXVuaXQgKyAnPC9zcGFuPjwvZGl2PjxzcGFuIGNsYXNzPVxcXCJjLWZpbGVfY2xlYXJcXFwiPjwvc3Bhbj48L2Rpdj4nKTtcXHJcXG5cXHR9KTtcXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBDbGVhciBmaWxlIGlucHV0IHdoZW4gY2xlYXIgYnV0dG9uIGlzIGNsaWNrZWQuXFxyXFxuXFx0ICovXFxyXFxuXFx0JChkb2N1bWVudCkub24oXFxcImNsaWNrXFxcIiwgXFxcIi5jLWZpbGVfY2xlYXJcXFwiLCBmdW5jdGlvbiAoKSB7XFxyXFxuXFx0XFx0dmFyICRmaWxlID0gJCh0aGlzKS5jbG9zZXN0KFxcXCIuYy1maWxlXFxcIik7XFxyXFxuXFxyXFxuXFx0XFx0JGZpbGUuZmluZChcXFwiLmMtZmlsZV9kb2N1bWVudFxcXCIpLnJlbW92ZSgpO1xcclxcblxcdFxcdCRmaWxlLmZpbmQoXFxcImlucHV0XFxcIikudmFsKFxcXCJcXFwiKTtcXHJcXG5cXHRcXHQkZmlsZS5yZW1vdmVDbGFzcyhcXFwiaXMtdG9nZ2xlZFxcXCIpO1xcclxcblxcdH0pO1xcclxcblxcclxcblxcdC8qKlxcclxcblxcdCAqIENsZWFyIGZpbGUgaW5wdXQgd2hlbiBmb3JtIGlzIHN1Ym1pdHRlZFxcclxcblxcdCAqL1xcclxcblxcdGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoXFxyXFxuXFx0XFx0XFxcIndwY2Y3c3VibWl0XFxcIixcXHJcXG5cXHRcXHRmdW5jdGlvbiAoZXZlbnQpIHtcXHJcXG5cXHRcXHRcXHQkKFxcXCIuYy1maWxlX2RvY3VtZW50XFxcIikucmVtb3ZlKCk7XFxyXFxuXFx0XFx0XFx0JChcXFwiLmMtZmlsZVxcXCIpLnJlbW92ZUNsYXNzKFxcXCJpcy10b2dnbGVkXFxcIik7XFxyXFxuXFx0XFx0fSxcXHJcXG5cXHRcXHRmYWxzZVxcclxcblxcdCk7XFxyXFxufSk7XFxyXFxuXFxuXFxuLy8jIHNvdXJjZVVSTD13ZWJwYWNrOi8vLy4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2ZpbGUuanM/XCIpO1xuICAgIC8qKiovXG4gIH0sXG5cbiAgLyoqKi9cbiAgXCIuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9mb290ZXIuanNcIjpcbiAgLyohKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiohKlxcXG4gICAgISoqKiAuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9mb290ZXIuanMgKioqIVxuICAgIFxcKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbiAgLyohIGV4cG9ydHMgcHJvdmlkZWQ6IGRlZmF1bHQgKi9cblxuICAvKioqL1xuICBmdW5jdGlvbiBhc3NldHNTcmNKc01vZHVsZXNGb290ZXJKcyhtb2R1bGUsIF9fd2VicGFja19leHBvcnRzX18sIF9fd2VicGFja19yZXF1aXJlX18pIHtcbiAgICBcInVzZSBzdHJpY3RcIjtcblxuICAgIGV2YWw
2oXCJfX3dlYnBhY2tfcmVxdWlyZV9fLnIoX193ZWJwYWNrX2V4cG9ydHNfXyk7XFxuLyogaGFybW9ueSBkZWZhdWx0IGV4cG9ydCAqLyBfX3dlYnBhY2tfZXhwb3J0c19fW1xcXCJkZWZhdWx0XFxcIl0gPSAoZnVuY3Rpb24gKCkge1xcblxcdHZhciAkID0galF1ZXJ5O1xcblxcblxcdC8vIEhpZGUgZmlyc3QgZWxlbWVudCBvZiBmb290ZXIgbWVudVxcblxcdCQoXFxcIi5jLWZvb3Rlcl9zdWJtZW51IC5jLWZvb3Rlcl9saW5rOm50aC1jaGlsZCgxKVxcXCIpLmNzcyhcXFwiZGlzcGxheVxcXCIsIFxcXCJub25lXFxcIik7XFxuXFxuXFx0Ly8gQ2hhbmdlIGhyZWYgbGluayBvZiBmb290ZXIgaGVhZGluZyBsaW5rIHRvIG5vdGhpbmcgaWYgc2NyZWVuIGlzIGxlc3MgdGhhbiA3NjhweFxcblxcdHZhciB3aWR0aCA9ICQod2luZG93KS53aWR0aCgpO1xcblxcdHZhciBtb2JpbGVTY3JlZW4gPSA3Njg7XFxuXFxuXFx0aWYgKHdpZHRoIDw9IG1vYmlsZVNjcmVlbikge1xcblxcdFxcdCQoXFxcIi5jLWZvb3Rlcl9oZWFkaW5nXFxcIikuYXR0cihcXFwiaHJlZlxcXCIsIFxcXCJqYXZhc2NyaXB0OnZvaWQoMClcXFwiKTtcXG5cXG5cXHRcXHQkKFxcXCIuYy1mb290ZXJfaGVhZGluZ1xcXCIpLmNsaWNrKGZ1bmN0aW9uICgpIHtcXG5cXHRcXHRcXHR2YXIgaXNUb2dnbGVkID0gJCh0aGlzKS5oYXNDbGFzcyhcXFwiLXRvZ2dsZWRcXFwiKTtcXG5cXG5cXHRcXHRcXHQkKFxcXCIuYy1mb290ZXJfaGVhZGluZ1xcXCIpLnJlbW92ZUNsYXNzKFxcXCItdG9nZ2xlZFxcXCIpO1xcblxcdFxcdFxcdCQoXFxcIi5jLWZvb3Rlcl9zdWJtZW51XFxcIikucmVtb3ZlQ2xhc3MoXFxcIi10b2dnbGVkXFxcIik7XFxuXFxuXFx0XFx0XFx0aWYgKCFpc1RvZ2dsZWQpIHtcXG5cXHRcXHRcXHRcXHQkKHRoaXMpLmFkZENsYXNzKFxcXCItdG9nZ2xlZFxcXCIpO1xcblxcdFxcdFxcdFxcdCQodGhpcykubmV4dCgpLmFkZENsYXNzKFxcXCItdG9nZ2xlZFxcXCIpO1xcblxcdFxcdFxcdH1cXG5cXHRcXHR9KTtcXG5cXHR9XFxuXFxuXFx0Ly8gQWRkIHBhZGRpbmctdG9wIHRvIGZvb3Rlci1jdGEgc2VjdGlvbiBpZiBsYXN0IHNlY3Rpb24gb2YgbWFpbiBpcyBub3QgbmV1dHJhbC0xMDBcXG5cXHR2YXIgbGFzdFNlY3Rpb24gPSAkKFxcXCJtYWluIC5vLXNlY3Rpb246bGFzdC1jaGlsZFxcXCIpO1xcblxcblxcdGlmICghbGFzdFNlY3Rpb24uaGFzQ2xhc3MoXFxcIi1uZXV0cmFsLTEwMFxcXCIpKSB7XFxuXFx0XFx0JChcXFwiZm9vdGVyXFxcIikucmVtb3ZlQ2xhc3MoXFxcIi1uby1zcGFjaW5nXFxcIikuYWRkQ2xhc3MoXFxcIi1uby1zcGFjaW5nLWJvdHRvbVxcXCIpO1xcblxcdH1cXG59KTtcXG5cXG5cXG4vLyMgc291cmNlVVJMPXdlYnBhY2s6Ly8vLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvZm9vdGVyLmpzP1wiKTtcbiAgICAvKioqL1xuICB9LFxuXG4gIC8qKiovXG4gIFwiLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvZ3NhcC9jdXJ0YWluLmpzXCI6XG4gIC8qISoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqISpcXFxuICAgICEqKiogLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvZ3NhcC9jdXJ0YWluLmpzICoqKiFcbiAgICBcXCoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4gIC8qISBleHBvcnRzIHByb3ZpZGVkOiBkZWZhdWx0ICovXG5cbiAgLyoqKi9cbiAgZnVuY3Rpb24gYXNzZXRzU3JjSnNNb2R1bGVzR3NhcEN1cnRhaW5Kcyhtb2R1bGUsIF9fd2VicGFja19leHBvcnRzX18sIF9fd2VicGFja19yZXF1aXJlX18pIHtcbiAgICBcInVzZSBzdHJpY3RcIjtcblxuICAgIGV2YWwoXCJfX3dlYnBhY2tfcmVxdWlyZV9fLnIoX193ZWJwYWNrX2V4cG9ydHNfXyk7XFxuLyogaGFybW9ueSBkZWZhdWx0IGV4cG9ydCAqLyBfX3dlYnBhY2tfZXhwb3J0c19fW1xcXCJkZWZhdWx0XFxcIl0gPSAoZnVuY3Rpb24gKCkge1xcblxcdHZhciAkID0galF1ZXJ5O1xcblxcblxcdGlmIChoaXN0b3J5LnNjcm9sbFJlc3RvcmF0aW9uKSB7XFxuXFx0XFx0aGlzdG9yeS5zY3JvbGxSZXN0b3JhdGlvbiA9IFxcXCJtYW51YWxcXFwiO1xcblxcdH1cXG5cXG5cXHRpZiAoJChcXFwiYm9keVxcXCIpLmhhc0NsYXNzKFxcXCJob21lXFxcIikpIHtcXG5cXHRcXHQkKGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbiAoKSB7XFxuXFx0XFx0XFx0JChcXFwiaHRtbFxcXCIpLmFkZENsYXNzKFxcXCJpcy1sb2NrLXNjcm9sbFxcXCIpO1xcblxcdFxcdFxcdHZhciB0bCA9IGdzYXAudGltZWxpbmUoKTtcXG5cXG5cXHRcXHRcXHR0bC50byhcXFwiLmhvbWUgLmMtY3VydGFpbl90b3AgLmMtY3VydGFpbl9maXJzdFxcXCIsIHtcXG5cXHRcXHRcXHRcXHRkdXJhdGlvbjogMC42LFxcblxcdFxcdFxcdFxcdHlQZXJjZW50OiAtMjUwLFxcblxcdFxcdFxcdFxcdHhQZXJjZW50OiAtNjAwLFxcblxcdFxcdFxcdFxcdGRlbGF5OiAwLjUsXFxuXFx0XFx0XFx0XFx0ZWFzZTogXFxcImVhc2Utb3V0LXBvd2VyLTNcXFwiLFxcblxcdFxcdFxcdFxcdG9uQ29tcGxldGU6IGZ1bmN0aW9uICgpIHtcXG5cXHRcXHRcXHRcXHRcXHQkKFxcXCIuaG9tZSAuYy1jdXJ0YWluX3NoYXBlXFxcIikuY3NzKFxcXCJ6LWluZGV4XFxcIiwgXFxcIjBcXFwiKTtcXG5cXHRcXHRcXHRcXHR9LFxcblxcdFxcdFxcdH0pO1xcblxcblxcdFxcdFxcdHRsLnRvKFxcXCIuaG9tZSAuYy1jdXJ0YWluX3RvcCAuYy1jdXJ0YWluX2xhc3RcXFwiLCB7XFxuXFx0XFx0XFx0XFx0ZHVyYXRpb246IDAuNixcXG5cXHRcXHRcXHRcXHR5UGVyY2VudDogLTIwMCxcXG5cXHRcXHRcXHRcXHR4UGVyY2VudDogMTAwMCxcXG5cXHRcXHRcXHRcXHRkZWxheTogLTAuNSxcXG5cXHRcXHRcXHRcXHRlYXNlOiBcXFwiZWFzZS1vdXQtcG93ZXItM1xcXCIsXFxuXFx0XFx0XFx0fSk7XFxuXFxuXFx0XFx0XFx0dGwudG8oXFxcIi5ob21lIC5jLWN1cnRhaW5fYm90dG9tIC5jLWN1cnRhaW5fZmlyc3RcXFwiLCB7XFxuXFx0XFx0XFx0XFx0ZHVyYXRpb246IDAuNixcXG5cXHRcXHRcXHRcXHR5UGVyY2VudDogNjAwLFxcblxcdFxcdFxcdFxcdHhQZXJjZW50OiAtNjAwLFxcblxcdFxcdFxcdFxcdGRlbGF5OiAtMC41LFxcblxcdFxcdFxcdFxcdGVhc2U6IFxcXCJlYXNlLW91dC1wb3dlci0zXFxcIixcXG5cXHRcXHRcXHR9KTtcXG5cXG5cXHRcXHRcXHR0bC50byhcXFwiLmhvbWUgLmMtY3VydGFpbl9ib3R0b20gLmMtY3VydGFpbl9sYXN0XFxcIiwge1xcblxcdFxcdFxcdFxcdGR1cmF0aW9uOiAwLjYsXFxuXFx0XFx0XFx0XFx0eVBlcmNlbnQ6IDcwMCxcXG5cXHRcXHRcXHRcXHR4UGVyY2VudDogNzAwLFxcblxcdFxcdFxcdFxcdGRlbGF5OiAtMC41LFxcblxcdFxcdFxcdFxcdGVhc2U6IFxcXCJlYXNlLW91dC1wb3dlci0zXFxcIixcXG5cXHRcXHRcXHR9KTtcXG5cXG5cXHRcXHRcXHR0bC50byhcXFwiLmhvbWUgLmMtY3VydGFpbl9saW5lXFxcIiwge1xcblxcdFxcdFxcdFxcdG9wYWNpdHk6IDEsXFxuXFx0XFx0XFx0XFx0ZHVyYXRpb246IDAuMSxcXG5cXHRcXHRcXHRcXHRkZWxheTogLTAuOSxcXG5cXHRcXHRcXHRcXHRhdXRvQWxwaGE6IDEsXFxuXFx0XFx0XFx0fSk7XFxuXFxuXFx0XFx0XFx0dGwudG8oXFxcIi5ob21lIC5jLWN1cnRhaW5fbGluZTpudGgtY2hpbGQoMSlcXFwiLCB7XFxuXFx0XFx0XFx0XFx0eTogLTE1MDAsXFxuXFx0XFx0XFx0XFx0ZHVyYXRpb246IDIsXFxuXFx0XFx0XFx0XFx0ZGVsYXk6IC0wLjksXFxuXFx0XFx0XFx0fSk7XFxuXFxuXFx0XFx0XFx0dGwudG8oXFxcIi5ob21lIC5jLWN1cnRhaW5fbGluZTpudGgtY2hpbGQoMilcXFwiLCB7XFxuXFx0XFx0XFx0XFx0eTogLTE1MDAsXFxuXFx0XFx0XFx0XFx0eDogMTUwMCxcXG5cXHRcXHRcXHRcXHRkdXJhdGlvbj
2ogMixcXG5cXHRcXHRcXHRcXHRkZWxheTogLTIsXFxuXFx0XFx0XFx0fSk7XFxuXFxuXFx0XFx0XFx0dGwudG8oXFxcIi5ob21lIC5jLWN1cnRhaW5fbGluZTpudGgtY2hpbGQoMylcXFwiLCB7XFxuXFx0XFx0XFx0XFx0eDogMTUwMCxcXG5cXHRcXHRcXHRcXHRkdXJhdGlvbjogMixcXG5cXHRcXHRcXHRcXHRkZWxheTogLTIsXFxuXFx0XFx0XFx0fSk7XFxuXFxuXFx0XFx0XFx0dGwudG8oXFxcIi5ob21lIC5jLWN1cnRhaW5fbGluZTpudGgtY2hpbGQoNClcXFwiLCB7XFxuXFx0XFx0XFx0XFx0eTogMTUwMCxcXG5cXHRcXHRcXHRcXHR4OiAxNTAwLFxcblxcdFxcdFxcdFxcdGR1cmF0aW9uOiAyLFxcblxcdFxcdFxcdFxcdGRlbGF5OiAtMixcXG5cXHRcXHRcXHR9KTtcXG5cXG5cXHRcXHRcXHR0bC50byhcXFwiLmhvbWUgLmMtY3VydGFpbl9saW5lOm50aC1jaGlsZCg1KVxcXCIsIHtcXG5cXHRcXHRcXHRcXHR5OiAxNTAwLFxcblxcdFxcdFxcdFxcdGR1cmF0aW9uOiAyLFxcblxcdFxcdFxcdFxcdGRlbGF5OiAtMixcXG5cXHRcXHRcXHR9KTtcXG5cXG5cXHRcXHRcXHR0bC50byhcXFwiLmhvbWUgLmMtY3VydGFpbl9saW5lOm50aC1jaGlsZCg2KVxcXCIsIHtcXG5cXHRcXHRcXHRcXHR5OiAxNTAwLFxcblxcdFxcdFxcdFxcdHg6IC0xNTAwLFxcblxcdFxcdFxcdFxcdGR1cmF0aW9uOiAyLFxcblxcdFxcdFxcdFxcdGRlbGF5OiAtMixcXG5cXHRcXHRcXHR9KTtcXG5cXG5cXHRcXHRcXHR0bC50byhcXFwiLmhvbWUgLmMtY3VydGFpbl9saW5lOm50aC1jaGlsZCg3KVxcXCIsIHtcXG5cXHRcXHRcXHRcXHR4OiAtMTUwMCxcXG5cXHRcXHRcXHRcXHRkdXJhdGlvbjogMixcXG5cXHRcXHRcXHRcXHRkZWxheTogLTIsXFxuXFx0XFx0XFx0fSk7XFxuXFxuXFx0XFx0XFx0dGwudG8oXFxcIi5ob21lIC5jLWN1cnRhaW5fbGluZTpudGgtY2hpbGQoOClcXFwiLCB7XFxuXFx0XFx0XFx0XFx0eTogLTE1MDAsXFxuXFx0XFx0XFx0XFx0eDogLTE1MDAsXFxuXFx0XFx0XFx0XFx0ZHVyYXRpb246IDIsXFxuXFx0XFx0XFx0XFx0ZGVsYXk6IC0yLFxcblxcdFxcdFxcdH0pO1xcblxcblxcdFxcdFxcdHRsLnRvKFxcXCIuaG9tZSAuYy1jdXJ0YWluXFxcIiwge1xcblxcdFxcdFxcdFxcdGR1cmF0aW9uOiAxLFxcblxcdFxcdFxcdFxcdGVhc2U6IFxcXCJlYXNlLW91dC1wb3dlci0zXFxcIixcXG5cXHRcXHRcXHRcXHR5UGVyY2VudDogLTEwMCxcXG5cXHRcXHRcXHRcXHRkZWxheTogLTEuNSxcXG5cXHRcXHRcXHRcXHRvbkNvbXBsZXRlOiBmdW5jdGlvbiAoKSB7XFxuXFx0XFx0XFx0XFx0XFx0JChcXFwiaHRtbFxcXCIpLnJlbW92ZUNsYXNzKFxcXCJpcy1sb2NrLXNjcm9sbFxcXCIpO1xcblxcdFxcdFxcdFxcdH0sXFxuXFx0XFx0XFx0fSk7XFxuXFx0XFx0fSk7XFxuXFx0fVxcbn0pO1xcblxcblxcbi8vIyBzb3VyY2VVUkw9d2VicGFjazovLy8uL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9nc2FwL2N1cnRhaW4uanM/XCIpO1xuICAgIC8qKiovXG4gIH0sXG5cbiAgLyoqKi9cbiAgXCIuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9nc2FwL2Vhc2VzLmpzXCI6XG4gIC8qISoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiEqXFxcbiAgICAhKioqIC4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2dzYXAvZWFzZXMuanMgKioqIVxuICAgIFxcKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4gIC8qISBleHBvcnRzIHByb3ZpZGVkOiBkZWZhdWx0ICovXG5cbiAgLyoqKi9cbiAgZnVuY3Rpb24gYXNzZXRzU3JjSnNNb2R1bGVzR3NhcEVhc2VzSnMobW9kdWxlLCBfX3dlYnBhY2tfZXhwb3J0c19fLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICBldmFsKFwiX193ZWJwYWNrX3JlcXVpcmVfXy5yKF9fd2VicGFja19leHBvcnRzX18pO1xcbi8qIGhhcm1vbnkgZGVmYXVsdCBleHBvcnQgKi8gX193ZWJwYWNrX2V4cG9ydHNfX1tcXFwiZGVmYXVsdFxcXCJdID0gKGZ1bmN0aW9uICgpIHtcXHJcXG5cXHR2YXIgJCA9IGpRdWVyeTtcXHJcXG5cXHJcXG5cXHQkKGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbiAoKSB7XFxyXFxuXFx0XFx0Ly8gRWFzZS1pblxcclxcblxcdFxcdEN1c3RvbUVhc2UuY3JlYXRlKFxcXCJlYXNlLWluLXBvd2VyLTFcXFwiLCBcXFwiMC41NSwgMC4wODUsIDAuNjgsIDAuNTNcXFwiKTtcXHJcXG5cXHRcXHRDdXN0b21FYXNlLmNyZWF0ZShcXFwiZWFzZS1pbi1wb3dlci0yXFxcIiwgXFxcIjAuNTUsIDAuMDU1LCAwLjY3NSwgMC4xOVxcXCIpO1xcclxcblxcdFxcdEN1c3RvbUVhc2UuY3JlYXRlKFxcXCJlYXNlLWluLXBvd2VyLTNcXFwiLCBcXFwiMC44OTUsIDAuMDMsIDAuNjg1LCAwLjIyXFxcIik7XFxyXFxuXFx0XFx0Q3VzdG9tRWFzZS5jcmVhdGUoXFxcImVhc2UtaW4tcG93ZXItNFxcXCIsIFxcXCIwLjc1NSwgMC4wNSwgMC44NTUsIDAuMDZcXFwiKTtcXHJcXG5cXHRcXHRDdXN0b21FYXNlLmNyZWF0ZShcXFwiZWFzZS1pbi1leHBvbmVudGlhbFxcXCIsIFxcXCIwLjk1LCAwLjA1LCAwLjc5NSwgMC4wMzVcXFwiKTtcXHJcXG5cXHRcXHRDdXN0b21FYXNlLmNyZWF0ZShcXFwiZWFzZS1pbi1zaW5lXFxcIiwgXFxcIjAuNDcsIDAsIDAuNzQ1LCAwLjcxNVxcXCIpO1xcclxcblxcclxcblxcdFxcdC8vIEVhc2Utb3V0XFxyXFxuXFx0XFx0Q3VzdG9tRWFzZS5jcmVhdGUoXFxcImVhc2Utb3V0LXBvd2VyLTFcXFwiLCBcXFwiMC4yNSwgMC40NiwgMC40NSwgMC45NFxcXCIpO1xcclxcblxcdFxcdEN1c3RvbUVhc2UuY3JlYXRlKFxcXCJlYXNlLW91dC1wb3dlci0yXFxcIiwgXFxcIjAuMjE1LCAwLjYxLCAwLjM1NSwgMVxcXCIpO1xcclxcblxcdFxcdEN1c3RvbUVhc2UuY3JlYXRlKFxcXCJlYXNlLW91dC1wb3dlci0zXFxcIiwgXFxcIjAuMTY1LCAwLjg0LCAwLjQ0LCAxXFxcIik7XFxyXFxuXFx0XFx0Q3VzdG9tRWFzZS5jcmVhdGUoXFxcImVhc2Utb3V0LXBvd2VyLTRcXFwiLCBcXFwiMC4yMywgMSwgMC4zMiwgMVxcXCIpO1xcclxcblxcdFxcdEN1c3RvbUVhc2UuY3JlYXRlKFxcXCJlYXNlLW91dC1leHBvbmVudGlhbFxcXCIsIFxcXCIwLjE5LCAxLCAwLjIyLCAxXFxcIik7XFxyXFxuXFx0XFx0Q3VzdG9tRWFzZS5jcmVhdGUoXFxcImVhc2Utb3V0LXNpbmVcXFwiLCBcXFwiMC4zOSwgMC41NzUsIDAuNTY1LCAxXFxcIik7XFxyXFxuXFxyXFxuXFx0XFx0Ly8gRWFzZS1pbi1vdXRcXHJcXG5cXHRcXHRDdXN0b21FYXNlLmNyZWF0ZShcXFwiZWFzZS1pbi1vdXQtcG93ZXItMVxcXCIsIFxcXCIwLjQ1NSwgMC4wMywgMC41MTUsIDAuOTU1XFxcIik7XFxyXFxuXFx0XFx0Q3VzdG9tRWFzZS5jcmVhdGUoXFxcImVhc2UtaW4tb3V0LXBvd2VyLTJcXFwiLCBcXFwiMC42NDUsIDAuMDQ1LCAwLjM1NSwgMVxcXCIpO1xcclxcblxcdFxcdEN1c3RvbUVhc2UuY3JlYXRlKFxcXCJlYXNlLWluLW91dC1wb3dlci0zXFxcIiwgXFxcIjAuNzcsIDAsIDAuMTc1LCAxXFxcIik7XFxyXFxuXFx0XFx0Q3VzdG9tRWFzZS5jcmVhdGUoXFxcImVhc2UtaW4tb3V0LXBvd2VyLTRcXFwiLCBcXFwiMC44NiwgMCwgMC4wNywgMVxcXCIpO1xcclxcblxcdFxcdEN1c3RvbUVhc2UuY3JlYXRlKFxcXCJlYXNlLWluLW91dC1leHBvbmVudGlhbFxcXCIsIFxcXCIxLCAwLCAwLCAxXFxcIik7XFxyXFxuXFx0XFx0Q3VzdG9tRWFzZS5jcmVhdGUoXFxcImVhc2UtaW4tb3V0LXNpbmVcXFwiLCBcXFwiMC40NSwgMC4wNSwgMC41NSwgMC45NVxcXCIpO1xcclxcblxcclxcblxcdFxcdC8vIE90aGVyX
2FxyXFxuXFx0XFx0Q3VzdG9tRWFzZS5jcmVhdGUoXFxcImVhc2luZy1ib3VuY2VcXFwiLCBcXFwiMC4xNywgMC42NywgMC4zLCAxLjMzXFxcIik7XFxyXFxuXFx0XFx0Q3VzdG9tRWFzZS5jcmVhdGUoXFxcImVhc2luZy1ncmF2aXR5XFxcIiwgXFxcIjAuMzMzMzMsIDAsIDAuNjY2NjcsIDAuMzMzMzNcXFwiKTtcXHJcXG5cXHR9KTtcXHJcXG59KTtcXHJcXG5cXG5cXG4vLyMgc291cmNlVVJMPXdlYnBhY2s6Ly8vLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvZ3NhcC9lYXNlcy5qcz9cIik7XG4gICAgLyoqKi9cbiAgfSxcblxuICAvKioqL1xuICBcIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2dzYXAvZmVhdHVyZXMuanNcIjpcbiAgLyohKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqISpcXFxuICAgICEqKiogLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvZ3NhcC9mZWF0dXJlcy5qcyAqKiohXG4gICAgXFwqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbiAgLyohIGV4cG9ydHMgcHJvdmlkZWQ6IGRlZmF1bHQgKi9cblxuICAvKioqL1xuICBmdW5jdGlvbiBhc3NldHNTcmNKc01vZHVsZXNHc2FwRmVhdHVyZXNKcyhtb2R1bGUsIF9fd2VicGFja19leHBvcnRzX18sIF9fd2VicGFja19yZXF1aXJlX18pIHtcbiAgICBcInVzZSBzdHJpY3RcIjtcblxuICAgIGV2YWwoXCJfX3dlYnBhY2tfcmVxdWlyZV9fLnIoX193ZWJwYWNrX2V4cG9ydHNfXyk7XFxuLyogaGFybW9ueSBkZWZhdWx0IGV4cG9ydCAqLyBfX3dlYnBhY2tfZXhwb3J0c19fW1xcXCJkZWZhdWx0XFxcIl0gPSAoZnVuY3Rpb24gKCkge1xcblxcdHZhciAkID0galF1ZXJ5O1xcblxcblxcdGdzYXAuZnJvbShcXFwiLmMtZmVhdHVyZSAuanMtZ3JhcGggcGF0aFxcXCIsIHtcXG5cXHRcXHRkdXJhdGlvbjogMS44LFxcblxcdFxcdHN0YWdnZXI6IDAuNCxcXG5cXHRcXHRkcmF3U1ZHOiAwLFxcblxcdFxcdHNjcm9sbFRyaWdnZXI6IFxcXCIuYy1mZWF0dXJlXFxcIixcXG5cXHR9KTtcXG5cXG5cXHRnc2FwLmZyb20oXFxcIi5jLWZlYXR1cmUtbGlzdGluZyAuanMtZ3JhcGggcGF0aFxcXCIsIHtcXG5cXHRcXHRkdXJhdGlvbjogMS44LFxcblxcdFxcdHN0YWdnZXI6IDAuNCxcXG5cXHRcXHRkcmF3U1ZHOiAwLFxcblxcdFxcdHNjcm9sbFRyaWdnZXI6IFxcXCIuYy1mZWF0dXJlLWxpc3RpbmdcXFwiLFxcblxcdFxcdHJlcGVhdDogLTEsXFxuXFxuXFx0XFx0Ly8gb25Db21wbGV0ZTogZnVuY3Rpb24gKCkge1xcblxcdFxcdC8vIFxcdGdzYXAudG8oXFxcIi5jLWZlYXR1cmUtbGlzdGluZyAuanMtZ3JhcGggcGF0aFxcXCIsIHtcXG5cXHRcXHQvLyBcXHRcXHRkdXJhdGlvbjogMS44LFxcblxcdFxcdC8vIFxcdFxcdHN0YWdnZXI6IDAuNCxcXG5cXHRcXHQvLyBcXHRcXHRkcmF3U1ZHOiAxLFxcblxcdFxcdC8vIFxcdH0pO1xcblxcdFxcdC8vIH0sXFxuXFx0fSk7XFxuXFxuXFx0Z3NhcC5mcm9tKFxcXCIuYy1pbGx1c3RyYXRpb24taGVhZGVyX21lZGlhIC5qcy1ncmFwaCBwYXRoXFxcIiwge1xcblxcdFxcdGR1cmF0aW9uOiAxLjgsXFxuXFx0XFx0c3RhZ2dlcjogMC40LFxcblxcdFxcdGRyYXdTVkc6IDAsXFxuXFx0XFx0ZWFzZTogXFxcImVhc2Utb3V0LXBvd2VyLTJcXFwiLFxcblxcdH0pO1xcblxcblxcdGdzYXAuZnJvbShcXFwiLmMtZmVhdHVyZSAuanMtcGllIC5qcy1waWVfZmxvYXRcXFwiLCB7XFxuXFx0XFx0ZHVyYXRpb246IDEuNCxcXG5cXHRcXHR4OiAwLFxcblxcdFxcdHk6IDAsXFxuXFx0XFx0eW95bzogdHJ1ZSxcXG5cXHRcXHRyZXBlYXQ6IC0xLFxcblxcdFxcdGVhc2U6IFxcXCJlYXNlLWluLW91dC1wb3dlci00XFxcIixcXG5cXHRcXHRzY3JvbGxUcmlnZ2VyOiBcXFwiLmMtZmVhdHVyZVxcXCIsXFxuXFx0fSk7XFxuXFxuXFx0Z3NhcC5mcm9tKFxcXCIuYy1mZWF0dXJlLWxpc3RpbmcgLmpzLXBpZSAuanMtcGllX2Zsb2F0XFxcIiwge1xcblxcdFxcdGR1cmF0aW9uOiAxLjQsXFxuXFx0XFx0eDogMCxcXG5cXHRcXHR5OiAwLFxcblxcdFxcdHlveW86IHRydWUsXFxuXFx0XFx0cmVwZWF0OiAtMSxcXG5cXHRcXHRlYXNlOiBcXFwiZWFzZS1pbi1vdXQtcG93ZXItNFxcXCIsXFxuXFx0XFx0c2Nyb2xsVHJpZ2dlcjogXFxcIi5jLWZlYXR1cmUtbGlzdGluZ1xcXCIsXFxuXFx0fSk7XFxuXFxuXFx0Z3NhcC5mcm9tKFxcXCIuYy1pbGx1c3RyYXRpb24taGVhZGVyX21lZGlhIC5qcy1waWUgLmpzLXBpZV9mbG9hdFxcXCIsIHtcXG5cXHRcXHRkdXJhdGlvbjogMS44LFxcblxcdFxcdHg6IDAsXFxuXFx0XFx0eTogMCxcXG5cXHRcXHR5b3lvOiB0cnVlLFxcblxcdFxcdHJlcGVhdDogLTEsXFxuXFx0XFx0ZWFzZTogXFxcImVhc2UtaW4tb3V0LXBvd2VyLTRcXFwiLFxcblxcdH0pO1xcblxcblxcdGdzYXAudG8oXFxcIi5jLWZlYXR1cmUgLmpzLWRvdHNfeWVsbG93XFxcIiwge1xcblxcdFxcdGR1cmF0aW9uOiAxLjgsXFxuXFx0XFx0eFBlcmNlbnQ6IDMwMCxcXG5cXHRcXHRzdGFnZ2VyOiAwLjgsXFxuXFx0XFx0eW95bzogdHJ1ZSxcXG5cXHRcXHRyZXBlYXQ6IC0xLFxcblxcdFxcdHNjcm9sbFRyaWdnZXI6IFxcXCIuYy1mZWF0dXJlXFxcIixcXG5cXHRcXHRlYXNlOiBcXFwiZWFzZS1pbi1vdXQtcG93ZXItM1xcXCIsXFxuXFx0fSk7XFxuXFxuXFx0Z3NhcC50byhcXFwiLmMtZmVhdHVyZSAuanMtZG90c19yZWRcXFwiLCB7XFxuXFx0XFx0ZHVyYXRpb246IDIuNSxcXG5cXHRcXHR4UGVyY2VudDogMzAwLFxcblxcdFxcdHN0YWdnZXI6IDAuOCxcXG5cXHRcXHR5b3lvOiB0cnVlLFxcblxcdFxcdHJlcGVhdDogLTEsXFxuXFx0XFx0c2Nyb2xsVHJpZ2dlcjogXFxcIi5jLWZlYXR1cmVcXFwiLFxcblxcdFxcdGVhc2U6IFxcXCJlYXNlLWluLW91dC1wb3dlci0zXFxcIixcXG5cXHR9KTtcXG5cXG5cXHRnc2FwLnRvKFxcXCIuYy1mZWF0dXJlIC5qcy1kb3RzX2JsdWVcXFwiLCB7XFxuXFx0XFx0ZHVyYXRpb246IDIsXFxuXFx0XFx0eFBlcmNlbnQ6IDMwMCxcXG5cXHRcXHRzdGFnZ2VyOiAwLjgsXFxuXFx0XFx0eW95bzogdHJ1ZSxcXG5cXHRcXHRlYXNlOiBcXFwiZWFzZS1pbi1vdXQtcG93ZXItM1xcXCIsXFxuXFx0XFx0cmVwZWF0OiAtMSxcXG5cXHRcXHRzY3JvbGxUcmlnZ2VyOiBcXFwiLmMtZmVhdHVyZVxcXCIsXFxuXFx0fSk7XFxuXFxuXFx0Z3NhcC50byhcXFwiLmMtZmVhdHVyZS1saXN0aW5nIC5qcy1kb3RzX3llbGxvd1xcXCIsIHtcXG5cXHRcXHRkdXJhdGlvbj
2ogMS44LFxcblxcdFxcdHhQZXJjZW50OiAzMDAsXFxuXFx0XFx0c3RhZ2dlcjogMC44LFxcblxcdFxcdHlveW86IHRydWUsXFxuXFx0XFx0cmVwZWF0OiAtMSxcXG5cXHRcXHRzY3JvbGxUcmlnZ2VyOiBcXFwiLmMtZmVhdHVyZS1saXN0aW5nXFxcIixcXG5cXHRcXHRlYXNlOiBcXFwiZWFzZS1pbi1vdXQtcG93ZXItM1xcXCIsXFxuXFx0fSk7XFxuXFxuXFx0Z3NhcC50byhcXFwiLmMtZmVhdHVyZS1saXN0aW5nIC5qcy1kb3RzX3JlZFxcXCIsIHtcXG5cXHRcXHRkdXJhdGlvbjogMi41LFxcblxcdFxcdHhQZXJjZW50OiAzMDAsXFxuXFx0XFx0c3RhZ2dlcjogMC44LFxcblxcdFxcdHlveW86IHRydWUsXFxuXFx0XFx0cmVwZWF0OiAtMSxcXG5cXHRcXHRzY3JvbGxUcmlnZ2VyOiBcXFwiLmMtZmVhdHVyZS1saXN0aW5nXFxcIixcXG5cXHRcXHRlYXNlOiBcXFwiZWFzZS1pbi1vdXQtcG93ZXItM1xcXCIsXFxuXFx0fSk7XFxuXFxuXFx0Z3NhcC50byhcXFwiLmMtZmVhdHVyZS1saXN0aW5nIC5qcy1kb3RzX2JsdWVcXFwiLCB7XFxuXFx0XFx0ZHVyYXRpb246IDIsXFxuXFx0XFx0eFBlcmNlbnQ6IDMwMCxcXG5cXHRcXHRzdGFnZ2VyOiAwLjgsXFxuXFx0XFx0eW95bzogdHJ1ZSxcXG5cXHRcXHRlYXNlOiBcXFwiZWFzZS1pbi1vdXQtcG93ZXItM1xcXCIsXFxuXFx0XFx0cmVwZWF0OiAtMSxcXG5cXHRcXHRzY3JvbGxUcmlnZ2VyOiBcXFwiLmMtZmVhdHVyZS1saXN0aW5nXFxcIixcXG5cXHR9KTtcXG5cXG5cXHRnc2FwLnRvKFxcXCIuYy1pbGx1c3RyYXRpb24taGVhZGVyX21lZGlhIC5qcy1kb3RzX3llbGxvd1xcXCIsIHtcXG5cXHRcXHRkdXJhdGlvbjogMS44LFxcblxcdFxcdHhQZXJjZW50OiAzMDAsXFxuXFx0XFx0c3RhZ2dlcjogMC44LFxcblxcdFxcdHlveW86IHRydWUsXFxuXFx0XFx0cmVwZWF0OiAtMSxcXG5cXHRcXHRlYXNlOiBcXFwiZWFzZS1pbi1vdXQtcG93ZXItM1xcXCIsXFxuXFx0fSk7XFxuXFxuXFx0Z3NhcC50byhcXFwiLmMtaWxsdXN0cmF0aW9uLWhlYWRlcl9tZWRpYSAuanMtZG90c19yZWRcXFwiLCB7XFxuXFx0XFx0ZHVyYXRpb246IDIuNSxcXG5cXHRcXHR4UGVyY2VudDogMzAwLFxcblxcdFxcdHN0YWdnZXI6IDAuOCxcXG5cXHRcXHR5b3lvOiB0cnVlLFxcblxcdFxcdHJlcGVhdDogLTEsXFxuXFx0XFx0ZWFzZTogXFxcImVhc2UtaW4tb3V0LXBvd2VyLTNcXFwiLFxcblxcdH0pO1xcblxcblxcdGdzYXAudG8oXFxcIi5jLWlsbHVzdHJhdGlvbi1oZWFkZXJfbWVkaWEgLmpzLWRvdHNfYmx1ZVxcXCIsIHtcXG5cXHRcXHRkdXJhdGlvbjogMixcXG5cXHRcXHR4UGVyY2VudDogMzAwLFxcblxcdFxcdHN0YWdnZXI6IDAuOCxcXG5cXHRcXHR5b3lvOiB0cnVlLFxcblxcdFxcdGVhc2U6IFxcXCJlYXNlLWluLW91dC1wb3dlci0zXFxcIixcXG5cXHRcXHRyZXBlYXQ6IC0xLFxcblxcdH0pO1xcblxcblxcdGdzYXAudG8oXFxuXFx0XFx0XFxcIi5qcy1zdGFpcnNfZGFya2JsdWVcXFwiLFxcblxcdFxcdHtcXG5cXHRcXHRcXHRkdXJhdGlvbjogMixcXG5cXHRcXHRcXHR4UGVyY2VudDogMzAwLFxcblxcdFxcdFxcdHlveW86IHRydWUsXFxuXFx0XFx0XFx0cmVwZWF0OiAtMSxcXG5cXHRcXHR9LFxcblxcdFxcdFxcXCJyZWN0QW5pbVxcXCJcXG5cXHQpO1xcblxcblxcdGdzYXAudG8oXFxuXFx0XFx0XFxcIi5qcy1zdGFpcnNfYmx1ZVxcXCIsXFxuXFx0XFx0e1xcblxcdFxcdFxcdGR1cmF0aW9uOiAyLFxcblxcdFxcdFxcdHhQZXJjZW50OiAzMDAsXFxuXFx0XFx0XFx0eW95bzogdHJ1ZSxcXG5cXHRcXHRcXHRyZXBlYXQ6IC0xLFxcblxcdFxcdH0sXFxuXFx0XFx0XFxcInJlY3RBbmltKz0uNVxcXCJcXG5cXHQpO1xcblxcblxcdGdzYXAudG8oXFxuXFx0XFx0XFxcIi5qcy1zdGFpcnNfbGlnaHRibHVlXFxcIixcXG5cXHRcXHR7XFxuXFx0XFx0XFx0ZHVyYXRpb246IDIsXFxuXFx0XFx0XFx0eFBlcmNlbnQ6IDMwMCxcXG5cXHRcXHRcXHR5b3lvOiB0cnVlLFxcblxcdFxcdFxcdHJlcGVhdDogLTEsXFxuXFx0XFx0fSxcXG5cXHRcXHRcXFwicmVjdEFuaW0rPTFcXFwiXFxuXFx0KTtcXG5cXG5cXHRnc2FwLnRvKFxcblxcdFxcdFxcXCIuanMtc3RhaXJzX3llbGxvd1xcXCIsXFxuXFx0XFx0e1xcblxcdFxcdFxcdGR1cmF0aW9uOiAyLFxcblxcdFxcdFxcdHhQZXJjZW50OiAzMDAsXFxuXFx0XFx0XFx0eW95bzogdHJ1ZSxcXG5cXHRcXHRcXHRyZXBlYXQ6IC0xLFxcblxcdFxcdH0sXFxuXFx0XFx0XFxcInJlY3RBbmltKz0xLjVcXFwiXFxuXFx0KTtcXG5cXG5cXHRnc2FwLnRvKFxcblxcdFxcdFxcXCIuanMtc3RhaXJzX2dyZXlcXFwiLFxcblxcdFxcdHtcXG5cXHRcXHRcXHRkdXJhdGlvbjogMixcXG5cXHRcXHRcXHR4UGVyY2VudDogMzAwLFxcblxcdFxcdFxcdHlveW86IHRydWUsXFxuXFx0XFx0XFx0cmVwZWF0OiAtMSxcXG5cXHRcXHR9LFxcblxcdFxcdFxcXCJyZWN0QW5pbSs9MlxcXCJcXG5cXHQpO1xcbn0pO1xcblxcblxcbi8vIyBzb3VyY2VVUkw9d2VicGFjazovLy8uL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9nc2FwL2ZlYXR1cmVzLmpzP1wiKTtcbiAgICAvKioqL1xuICB9LFxuXG4gIC8qKiovXG4gIFwiLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvZ3NhcC9pbnRyby5qc1wiOlxuICAvKiEqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiohKlxcXG4gICAgISoqKiAuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9nc2FwL2ludHJvLmpzICoqKiFcbiAgICBcXCoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuICAvKiEgZXhwb3J0cyBwcm92aWRlZDogZGVmYXVsdCAqL1xuXG4gIC8qKiovXG4gIGZ1bmN0aW9uIGFzc2V0c1NyY0pzTW9kdWxlc0dzYXBJbnRyb0pzKG1vZHVsZSwgX193ZWJwYWNrX2V4cG9ydHNfXywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgZXZhbChcIl9fd2VicGFja19yZXF1aXJlX18ucihfX3dlYnBhY2tfZXhwb3J0c19fKTtcXG4vKiBoYXJtb255IGRlZmF1bHQgZXhwb3J0ICovIF9fd2VicGFja19leHBvcnRzX19bXFxcImRlZmF1bHRcXFwiXSA9IChmdW5jdGlvbiAoKSB7XFxuXFx0dmFyICQgPSBqUXVlcnk7XFxuXFxuXFx0JChkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24gKCkge1xcblxcdFxcdHZhciB0bCA9IGdzYXAudGltZWxpbmUoe1xcblxcdFxcdFxcdHNjcm9sbFRyaWdnZXI6IHtcXG5cXHRcXHRcXHRcXHR0cmlnZ2VyOiBcXFwiLmMtYWR2YW50YWdlXFxcIixcXG5cXHRcXHRcXHRcXHRzY3J1YjogMSxcXG5cXHRcXHRcXHRcXHRzdGFydDogXFxcInRvcCAyMCVcXFwiLFxcblxcdFxcdFxcdH0sXFxuXFx0XFx0fSk7XFxuXFxuXFx0XFx0dGwudG8oXFxuXFx0XFx0XFx0XFxcIi5jLWFkdmFudGFnZXNfc2hhcGUuLXRoaXJkXFxcIixcXG5cXHRcXHRcXHR7XFxuXFx0XFx0XFx0XFx0ZHVyYXRpb246IDEsXFxuXFx0XFx0XFx0XFx0ZWFzZTogXFxcIm5vbmVcXFwiLFxcblxcdFxcdFxcdFxcdHhQZXJjZW50OiAxMDAsXFxuXFx0XFx0XFx0XFx0eVBlcmNlbnQ6IDEwMCxcXG5cXHRcXHRcXHR9LFxcblxcdFxcdFxcdFxcXCI8PVxcXCJcXG5cXHRcXHQpO1xcblxcblxcdFxcdHRsLnRvKFxcblxcdFxcdFxcdFxcXCIuYy1hZHZhbnRhZ2VzX3NoYXBlLi1mb3VydGhcXFwiLFxcblxcdFxcdFxcdHtcXG5cXHRcXHRcXHRcXHRkdXJhdGlvbj
2ogMSxcXG5cXHRcXHRcXHRcXHRlYXNlOiBcXFwibm9uZVxcXCIsXFxuXFx0XFx0XFx0XFx0eFBlcmNlbnQ6IC0xMDAsXFxuXFx0XFx0XFx0XFx0eVBlcmNlbnQ6IDEwMCxcXG5cXHRcXHRcXHR9LFxcblxcdFxcdFxcdFxcXCI8PVxcXCJcXG5cXHRcXHQpO1xcblxcblxcdFxcdHRsLnRvKFxcblxcdFxcdFxcdFxcXCIuYy1hZHZhbnRhZ2VzX3NoYXBlLi1maXJzdFxcXCIsXFxuXFx0XFx0XFx0e1xcblxcdFxcdFxcdFxcdGR1cmF0aW9uOiAzLFxcblxcdFxcdFxcdFxcdGVhc2U6IFxcXCJub25lXFxcIixcXG5cXHRcXHRcXHRcXHR4UGVyY2VudDogMTAwLFxcblxcdFxcdFxcdFxcdHlQZXJjZW50OiAtMTAwLFxcblxcdFxcdFxcdH0sXFxuXFx0XFx0XFx0XFxcIjw9XFxcIlxcblxcdFxcdCk7XFxuXFxuXFx0XFx0dGwudG8oXFxuXFx0XFx0XFx0XFxcIi5jLWFkdmFudGFnZXNfc2hhcGUuLXNlY29uZFxcXCIsXFxuXFx0XFx0XFx0e1xcblxcdFxcdFxcdFxcdGR1cmF0aW9uOiAzLFxcblxcdFxcdFxcdFxcdGVhc2U6IFxcXCJub25lXFxcIixcXG5cXHRcXHRcXHRcXHR4UGVyY2VudDogLTEwMCxcXG5cXHRcXHRcXHRcXHR5UGVyY2VudDogLTEwMCxcXG5cXHRcXHRcXHR9LFxcblxcdFxcdFxcdFxcXCI8PVxcXCJcXG5cXHRcXHQpO1xcblxcdH0pO1xcbn0pO1xcblxcblxcbi8vIyBzb3VyY2VVUkw9d2VicGFjazovLy8uL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9nc2FwL2ludHJvLmpzP1wiKTtcbiAgICAvKioqL1xuICB9LFxuXG4gIC8qKiovXG4gIFwiLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvZ3NhcC9zY3JvbGxUcmlnZ2VyLmpzXCI6XG4gIC8qISoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqISpcXFxuICAgICEqKiogLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvZ3NhcC9zY3JvbGxUcmlnZ2VyLmpzICoqKiFcbiAgICBcXCoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4gIC8qISBleHBvcnRzIHByb3ZpZGVkOiBkZWZhdWx0ICovXG5cbiAgLyoqKi9cbiAgZnVuY3Rpb24gYXNzZXRzU3JjSnNNb2R1bGVzR3NhcFNjcm9sbFRyaWdnZXJKcyhtb2R1bGUsIF9fd2VicGFja19leHBvcnRzX18sIF9fd2VicGFja19yZXF1aXJlX18pIHtcbiAgICBcInVzZSBzdHJpY3RcIjtcblxuICAgIGV2YWwoXCJfX3dlYnBhY2tfcmVxdWlyZV9fLnIoX193ZWJwYWNrX2V4cG9ydHNfXyk7XFxuLyogaGFybW9ueSBkZWZhdWx0IGV4cG9ydCAqLyBfX3dlYnBhY2tfZXhwb3J0c19fW1xcXCJkZWZhdWx0XFxcIl0gPSAoZnVuY3Rpb24gKCkge1xcblxcdHZhciAkID0galF1ZXJ5O1xcblxcdHZhciB0bEFkdmFudGFnZXMgPSBnc2FwLnRpbWVsaW5lKHtcXG5cXHRcXHRzY3JvbGxUcmlnZ2VyOiB7XFxuXFx0XFx0XFx0dHJpZ2dlcjogXFxcIi5jLWFkdmFudGFnZXNfY29udGVudFxcXCIsXFxuXFx0XFx0fSxcXG5cXHR9KTtcXG5cXG5cXHQkKGRvY3VtZW50KS5yZWFkeShmdW5jdGlvbiAoKSB7XFxuXFx0XFx0dGxBZHZhbnRhZ2VzLmZyb20oXFxcIi5jLWFkdmFudGFnZXNfc2luZ2xlXFxcIiwge1xcblxcdFxcdFxcdGR1cmF0aW9uOiAwLjQsXFxuXFx0XFx0XFx0ZWFzZTogXFxcImVhc2Utb3V0LXBvd2VyLTJcXFwiLFxcblxcdFxcdFxcdHk6IDI0LFxcblxcdFxcdFxcdGNsaXBQYXRoOiBcXFwiaW5zZXQoMCUgMCUgMTAwJSAwJSlcXFwiLFxcblxcdFxcdFxcdHN0YWdnZXI6IDAuMDYsXFxuXFx0XFx0fSk7XFxuXFx0fSk7XFxufSk7XFxuXFxuXFxuLy8jIHNvdXJjZVVSTD13ZWJwYWNrOi8vLy4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2dzYXAvc2Nyb2xsVHJpZ2dlci5qcz9cIik7XG4gICAgLyoqKi9cbiAgfSxcblxuICAvKioqL1xuICBcIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2hlbHBlci5qc1wiOlxuICAvKiEqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiEqXFxcbiAgICAhKioqIC4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2hlbHBlci5qcyAqKiohXG4gICAgXFwqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuICAvKiEgZXhwb3J0cyBwcm92aWRlZDogZGVmYXVsdCAqL1xuXG4gIC8qKiovXG4gIGZ1bmN0aW9uIGFzc2V0c1NyY0pzTW9kdWxlc0hlbHBlckpzKG1vZHVsZSwgX193ZWJwYWNrX2V4cG9ydHNfXywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgZXZhbChcIl9fd2VicGFja19yZXF1aXJlX18ucihfX3dlYnBhY2tfZXhwb3J0c19fKTtcXG4vKiBoYXJtb255IGRlZmF1bHQgZXhwb3J0ICovIF9fd2VicGFja19leHBvcnRzX19bXFxcImRlZmF1bHRcXFwiXSA9IChmdW5jdGlvbiAoKSB7XFxyXFxuXFx0dmFyICQgPSBqUXVlcnk7XFxyXFxuXFxyXFxuXFx0dmFyIGxhc3RTY3JvbGxUb3AgPSAwO1xcclxcblxcclxcblxcdCQod2luZG93KS5vbihcXFwic2Nyb2xsXFxcIiwgZnVuY3Rpb24gKCkge1xcclxcblxcdFxcdHZhciBzY3JvbGxZID0gd2luZG93LnBhZ2VZT2Zmc2V0O1xcclxcblxcclxcblxcdFxcdGlmIChzY3JvbGxZID4gbGFzdFNjcm9sbFRvcCkge1xcclxcblxcdFxcdFxcdCQoXFxcImh0bWxcXFwiKS5yZW1vdmVDbGFzcyhcXFwiaXMtc2Nyb2xsLXVwXFxcIik7XFxyXFxuXFx0XFx0XFx0JChcXFwiaHRtbFxcXCIpLmFkZENsYXNzKFxcXCJpcy1zY3JvbGwtZG93blxcXCIpO1xcclxcblxcdFxcdH0gZWxzZSBpZiAoc2Nyb2xsWSA8IGxhc3RTY3JvbGxUb3ApIHtcXHJcXG5cXHRcXHRcXHQkKFxcXCJodG1sXFxcIikucmVtb3ZlQ2xhc3MoXFxcImlzLXNjcm9sbC1kb3duXFxcIik7XFxyXFxuXFx0XFx0XFx0JChcXFwiaHRtbFxcXCIpLmFkZENsYXNzKFxcXCJpcy1zY3JvbGwtdXBcXFwiKTtcXHJcXG5cXHRcXHR9XFxyXFxuXFxyXFxuXFx0XFx0aWYgKHNjcm9sbFkgPiAxNjApIHtcXHJcXG5cXHRcXHRcXHQkKFxcXCJodG1sXFxcIikuYWRkQ2xhc3MoXFxcImlzLW92ZXItY29udGVudFxcXCIpO1xcclxcblxcdFxcdH0gZWxzZSB7XFxyXFxuXFx0XFx0XFx0JChcXFwiaHRtbFxcXCIpLnJlbW92ZUNsYXNzKFxcXCJpcy1vdmVyLWNvbnRlbn
2RcXFwiKTtcXHJcXG5cXHRcXHR9XFxyXFxuXFxyXFxuXFx0XFx0bGFzdFNjcm9sbFRvcCA9IHdpbmRvdy5wYWdlWU9mZnNldDtcXHJcXG5cXHR9KTtcXHJcXG59KTtcXHJcXG5cXG5cXG4vLyMgc291cmNlVVJMPXdlYnBhY2s6Ly8vLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvaGVscGVyLmpzP1wiKTtcbiAgICAvKioqL1xuICB9LFxuXG4gIC8qKiovXG4gIFwiLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvaW5jbHVzaW9uLmpzXCI6XG4gIC8qISoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqISpcXFxuICAgICEqKiogLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvaW5jbHVzaW9uLmpzICoqKiFcbiAgICBcXCoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4gIC8qISBleHBvcnRzIHByb3ZpZGVkOiBkZWZhdWx0ICovXG5cbiAgLyoqKi9cbiAgZnVuY3Rpb24gYXNzZXRzU3JjSnNNb2R1bGVzSW5jbHVzaW9uSnMobW9kdWxlLCBfX3dlYnBhY2tfZXhwb3J0c19fLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICBldmFsKFwiX193ZWJwYWNrX3JlcXVpcmVfXy5yKF9fd2VicGFja19leHBvcnRzX18pO1xcbi8qIGhhcm1vbnkgZGVmYXVsdCBleHBvcnQgKi8gX193ZWJwYWNrX2V4cG9ydHNfX1tcXFwiZGVmYXVsdFxcXCJdID0gKGZ1bmN0aW9uICgpIHtcXG5cXHR2YXIgJCA9IGpRdWVyeTtcXG5cXG5cXHR2YXIgc2VjdGlvbkhlaWdodCA9IDA7XFxuXFxuXFx0JChcXFwiLmMtaW5jbHVzaW9uXFxcIikuZWFjaChmdW5jdGlvbiAoKSB7XFxuXFx0XFx0Y29uc29sZS5sb2coJCh0aGlzKS5vdXRlckhlaWdodCgpKTtcXG5cXHR9KTtcXG59KTtcXG5cXG5cXG4vLyMgc291cmNlVVJMPXdlYnBhY2s6Ly8vLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvaW5jbHVzaW9uLmpzP1wiKTtcbiAgICAvKioqL1xuICB9LFxuXG4gIC8qKiovXG4gIFwiLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvam9iLmpzXCI6XG4gIC8qISoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqISpcXFxuICAgICEqKiogLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvam9iLmpzICoqKiFcbiAgICBcXCoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4gIC8qISBleHBvcnRzIHByb3ZpZGVkOiBkZWZhdWx0ICovXG5cbiAgLyoqKi9cbiAgZnVuY3Rpb24gYXNzZXRzU3JjSnNNb2R1bGVzSm9iSnMobW9kdWxlLCBfX3dlYnBhY2tfZXhwb3J0c19fLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICBldmFsKFwiX193ZWJwYWNrX3JlcXVpcmVfXy5yKF9fd2VicGFja19leHBvcnRzX18pO1xcbi8qIGhhcm1vbnkgZGVmYXVsdCBleHBvcnQgKi8gX193ZWJwYWNrX2V4cG9ydHNfX1tcXFwiZGVmYXVsdFxcXCJdID0gKGZ1bmN0aW9uICgpIHtcXG4gICAgY29uc3QgdGFyZ2V0Tm9kZSA9IGRvY3VtZW50LmJvZHk7XFxuXFxuICAgIC8vIENvbmZpZ3VyYXRpb24gb2YgdGhlIG9ic2VydmVyOiB3YXRjaCBmb3IgY2hpbGRyZW4gYmVpbmcgYWRkZWRcXG4gICAgY29uc3QgY29uZmlnID0geyBjaGlsZExpc3Q6IHRydWUsIHN1YnRyZWU6IHRydWUgfTtcXG5cXG4gICAgY29uc3QgY2FsbGJhY2sgPSBmdW5jdGlvbiAobXV0YXRpb25zTGlzdCwgb2JzZXJ2ZXIpIHtcXG4gICAgICAgIGNvbnN0IHdyYXBwZXIgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuam9iLWZvcm0td3JhcHBlcicpO1xcbiAgICAgICAgY29uc3Qgam9iRmllbGQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcuanMtam9iLWZpZWxkJyk7XFxuXFxuICAgICAgICAvLyBDaGVjayBpZiBvdXIgc3BlY2lmaWMgZWxlbWVudHMgZXhpc3QgeWV0XFxuICAgICAgICBpZiAod3JhcHBlciAmJiBqb2JGaWVsZCkge1xcbiAgICAgICAgICAgIGNvbnN0IHRpdGxlID0gd3JhcHBlci5nZXRBdHRyaWJ1dGUoJ2RhdGEtam9iLXRpdGxlJyk7XFxuXFxuICAgICAgICAgICAgaWYgKHRpdGxlKSB7XFxuICAgICAgICAgICAgICAgIGpvYkZpZWxkLnZhbHVlID0gdGl0bGU7XFxuXFxuICAgICAgICAgICAgICAgIC8vIFRyaWdnZXIgZXZlbnRzIHNvIFVJIHNjcmlwdHMgKGxpa2UgZmxvYXRpbmcgbGFiZWxzKSB1cGRhdGVcXG4gICAgICAgICAgICAgICAgam9iRmllbGQuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoJ2lucHV0JywgeyBidWJibGVzOiB0cnVlIH0pKTtcXG4gICAgICAgICAgICAgICAgam9iRmllbGQuZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoJ2NoYW5nZScsIHsgYnViYmxlczogdHJ1ZSB9KSk7XFxuXFxuICAgICAgICAgICAgICAgIC8vIFN1Y2Nlc3MhIFN0b3Agd2F0Y2hpbmcgdGhlIERPTSB0byBzYXZlIHBlcmZvcm1hbmNlXFxuICAgICAgICAgICAgICAgIG9ic2VydmVyLmRpc2Nvbm5lY3QoKTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuICAgIH07XFxuXFxuICAgIC8vIENyZWF0ZSB0aGUgb2JzZXJ2ZXIgaW5zdGFuY2UgbGlua2VkIHRvIHRoZSBjYWxsYmFjayBmdW5jdGlvblxcbiAgICBjb25zdCBvYnNlcnZlciA9IG5ldyBNdXRhdGlvbk9ic2VydmVyKGNhbGxiYWNrKTtcXG5cXG4gICAgLy8gU3RhcnQgb2JzZXJ2aW5nXFxuICAgIG9ic2VydmVyLm9ic2VydmUodGFyZ2V0Tm9kZSwgY29uZmlnKTtcXG5cXG4gICAgLy8gQWxzbyBydW4gaXQgb25jZSBpbW1lZGlhdGVseSBpbiBjYXNlIHRoZSBlbGVtZW50IGlzIGFscmVhZHkgdGhlcmVcXG4gICAgY2FsbGJhY2soW10sIG9ic2VydmVyKTtcXG59KTtcXG5cXG4vLyMgc291cmNlVVJMPXdlYnBhY2s6Ly8vLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvam9iLmpzP1wiKTtcbiAgICAvKioqL1xuICB9LFxuXG4gIC8qKiovXG4gIFwiLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvbWF0dGVyLmpzXCI6XG4gIC8qISoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqISpcXFxuICAgICEqKiogLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvbWF0dGVyLmpzICoqKiFcbiAgICBcXCoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4gIC8qISBleHBvcnRzIHByb3ZpZGVkOiBkZWZhdWx0ICovXG5cbiAgLyoqKi9cbiAgZnVuY3Rpb24gYXNzZXRzU3JjSnNNb2R1bGVzTWF0dGVySnMobW9kdWxlLCBfX3dlYnBhY2tfZXhwb3J0c19fLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICBldmFsKFwiX193ZWJwYWNrX3JlcXVpcmVfXy5yKF9fd2VicGFja19leHBvcnRzX18pO1xcbi8qIGhhcm1vbnkgaW1wb3J0ICovIHZhciBtYXR0ZXJfanNfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzBfXyA9IF9fd2VicGFja19yZXF1aXJlX18oLyohIG1hdHRlci1qcyAqLyBcXFwiLi9ub2RlX21vZHVsZXMvbWF0dGVyLWpzL2J1aWxkL21hdHRlci5qc1xcXCIpO1xcbi8qIGhhcm1vbnkgaW1wb3J0ICovIHZhciBtYXR0ZXJfanNfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzBfX19kZWZhdWx0ID0gLyojX19QVVJFX18qL19fd2VicGFja19yZXF1aXJlX18ubihtYXR0ZXJfanNfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzBfXyk7XFxuXFxyXFxuXFxyXFxuLyogaGFybW9ueSBkZWZhdWx0IGV4cG9ydCAqLyBfX3dlYnBhY2tfZXhwb3J0c19fW1xcXCJkZWZhdWx0XFxcIl0gPSAoZnVuY3Rpb24gKCkge1xcclxcblxcdHZhciAkID0galF1ZXJ5O1xcclxcblxcclxcblxcdCQoXFxcIi5qcy1tYXR0ZXJcXFwiKS5lYWNoKGZ1bmN0aW9uICgpIHtcXHJcXG5cXHRcXHRsZXQgJHRoaXMgPSAkKHRoaXMpO1xcclxcblxcdFxcdFNjcm9sbFRyaWdnZXIuY3JlYXRlKHtcXHJcXG5cXHRcXHRcXHR0cmlnZ2VyOiAkdGhpcyxcXHJcXG5cXHRcXHRcXHRzdGFydDogXFxcInRvcCBib3R0b21cXFwiLFxcclxcblxcdFxcdFxcdG9uY2U6IHRydWUsXFxyXFxuXFxyXFxuXFx0XFx0XFx0b25FbnRlcjogZnVuY3Rpb24gKCkge1xcclxcblxcdFxcdFxcdFxcdHZhciBFbmdpbmUgPSBtYXR0ZXJfanNfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzBfX19kZWZhdWx0LmEuRW5naW5lLFxcclxcblxcdFxcdFxcdFxcdFxcdFJlbmRlciA9IG1hdHRlcl9qc19fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMF9fX2RlZmF1bHQuYS5SZW5kZXIsXFxyXFxuXFx0XFx0XFx0XFx0XFx0V29ybGQgPSBtYXR0ZXJfanNfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzBfX19kZWZhdWx0LmEuV29ybGQsXFxyXFxuXFx0XFx0XFx0XFx0XFx0UnVubmVyID0gbWF0dGVyX2pzX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8wX19fZGVmYXVsdC5hLlJ1bm5lcixcXHJcXG5cXHRcXHRcXHRcXHRcXHRCb2RpZXMgPSBtYXR0ZXJfanNfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzBfX19kZWZhdWx0LmEuQm9kaWVzLFxcclxcblxcdFxcdFxcdFxcdFxcdENvbXBvc2l0ZSA9IG1hdHRlcl9qc19fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMF9fX2RlZmF1bHQuYS5Db21wb3NpdGUsXFxyXFxuXFx0XFx0XFx0XFx0XFx0TW91c2VDb25zdHJhaW50ID0gbWF0dGVyX2pzX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8wX19fZGVmYXVsdC5hLk1vdXNlQ29uc3RyYWludDtcXHJcXG5cXHJcXG5cXHRcXHRcXHRcXHR2YXIgcmVuZGVyO1xcclxcblxcdFxcdFxcdFxcdHZhciBlbmdpbmU7XFxyXFxuXFxyXFxuXFx0XFx0XFx0XFx0ZnVuY3Rpb24gaW5pdCgpIHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRFbmdpbmUgPSBtYXR0ZXJfanNfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzBfX19kZWZhdWx0LmEuRW5naW5lO1xcclxcblxcdFxcdFxcdFxcdFxcdFJlbmRlciA9IG1hdHRlcl9qc19fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMF9fX2RlZmF1bHQuYS5SZW5kZXI7XFxyXFxuXFx0XFx0XFx0XFx0XFx0V29ybGQgPSBtYXR0ZXJfanNfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzBfX19kZWZhdWx0LmEuV29ybGQ7XFxyXFxuXFx0XFx0XFx0XFx0XFx0UnVubmVyID0gbWF0dGVyX2pzX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8wX19fZGVmYXVsdC5hLlJ1bm5lcjtcXHJcXG5cXHRcXHRcXHRcXHRcXHRCb2RpZXMgPSBtYXR0ZXJfanNfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzBfX19kZWZhdWx0LmEuQm9kaWVzO1xcclxcblxcdFxcdFxcdFxcdFxcdENvbXBvc2l0ZSA9IG1hdHRlcl9qc19fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMF9fX2RlZmF1bHQuYS5Db21wb3NpdGU7XFxyXFxuXFx0XFx0XFx0XFx0XFx0TW91c2VDb25zdHJhaW50ID0gbWF0dGVyX2pzX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8wX19fZGVmYXVsdC5hLk1vdXNlQ29uc3RyYWludDtcXHJcXG5cXHJcXG5cXHRcXHRcXHRcXHRcXHRlbmdpbmUgPSBFbmdpbmUuY3JlYXRlKCk7XFxyXFxuXFxyXFxuXFx0XFx0XFx0XFx0XFx0dmFyIHcgPSAkdGhpc1swXS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS53aWR0aDtcXHJcXG5cXHRcXHRcXHRcXHRcXHR2YXIgaCA9ICR0aGlzWzBdLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmhlaWdodDtcXHJcXG5cXHJcXG5cXHRcXHRcXHRcXHRcXHRjb25zdCBlbGVtZW50ID0gJHRoaXMuZmluZChcXFwiLnNoYXBlc1xcXCIpWzBdO1xcclxcblxcdFxcdFxcdFxcdFxcdHJlbmRlciA9IFJlbmRlci5jcmVhdGUoe1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdGVsZW1lbnQ6IGVsZW1lbnQsXFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0ZW5naW5lOiBlbmdpbmUsXFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0b3B0aW9uczoge1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdHdpZHRoOiB3LFxcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdGhlaWdodDogaCxcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRiYWNrZ3JvdW5kOiBcXFwiIzAxMmY1NVxcXCIsXFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0d2lyZWZyYW1lczogZmFsc2UsXFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0cGl4ZWxSYXRpbzogd2luZG93LmRldmljZVBpeGVsUmF0aW8sXFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0fSxcXHJcXG5cXHRcXHRcXHRcXHRcXHR9KTtcXHJcXG5cXHJcXG5cXHRcXHRcXHRcXHRcXHQvLy9cXHJcXG5cXHJcXG5cXHRcXHRcXHRcXHRcXHRjb25zdCBzaGFwZXMgPSBbXTtcXHJcXG5cXHRcXHRcXHRcXHRcXHR2YXIgaW5kZXggPSAwO1xcclxcblxcclxcblxcdFxcdFxcdFxcdFxcdCR0aGlzLmZpbmQoXFxcIi5qcy1tYXR0ZXJfc2hhcGVcXFwiKS5lYWNoKGZ1bmN0aW9uICgpIHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHQkKHRoaXMpXFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0LmZpbmQoXFxcInBhdGhcXFwiKVxcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdC5lYWNoKGZ1bmN0aW9uIChpLCBwYXRoKSB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0bGV0IGNvbG9yID0gXFxcIlxcXCI7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0aW5kZXgrKztcXHJcXG5cXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRpZiAoJCh0aGlzKS5oYXNDbGFzcyhcXFwibWF0dGVyLXBhdGgtMVxcXCIpKSB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0Y29sb3IgPSBcXFwiIzMxM0NGQVxcXCI7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0fSBlbHNlIGlmICgkKHRoaXMpLmhhc0NsYXNzKFxcXCJtYXR0ZXItcGF0aC0yXFxcIikpIHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRjb2xvciA9IFxcXCIjRTlCMTMzXFxcIjtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHR9IGVsc2UgaWYgKCQodGhpcykuaGFzQ2xhc3MoXFxcIm1hdHRlci1wYXRoLTNcXFwiKSkge1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdGNvbG9yID0gXFxcIiNDRDM4M0VcXFwiO1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdH0gZWxzZSBpZiAoJCh0aGlzKS5oYXNDbGFzcyhcXFwibWF0dGVyLXBhdGgtNFxcXCIpKSB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0Y29sb3IgPSBcXFwiIzY1QjlFQ1xcXCI7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0fVxcclxcblxcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdHZhciB2ID0gQm9kaWVzLmZyb21WZXJ0aWNlcyh3IC8gaW5kZXgsIDAsIG1hdHRlcl9qc19fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMF9fX2RlZmF1bHQuYS5TdmcucGF0aFRvVmVydGljZXMocGF0aCwgNSksIHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRyZW5kZXI6IHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRmaWxsU3R5bGU6IGNvbG9yLFxcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdHN0cm9rZVN0eWxlOiBjb2xvcixcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHR9LFxcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdH0pO1xcclxcblxcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdHNoYXBlcy5wdXNoKHYpO1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdH0pO1xcclxcblxcdFxcdFxcdFxcdFxcdH0pO1xcclxcblxcclxcblxcdFxcdFxcdFxcdFxcdENvbXBvc2l0ZS5hZGQoZW5naW5lLndvcmxkLCBzaGFwZXMpO1xcclxcblxcclxcblxcdFxcdFxcdFxcdFxcdC8vL1xcclxcblxcclxcblxcdFxcdFxcdFxcdFxcdGNvbnN0IHdhbGxPcHRpb25zID0ge1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdGlzU3RhdGljOiB0cnVlLFxcclxcblxcdFxcdFxcdFxcdFxcdFxcdHJlbmRlcjoge1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdHZpc2libGU6IHRydWUsXFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0fSxcXHJcXG5cXHRcXHRcXHRcXHRcXHR9O1xcclxcblxcclxcblxcdFxcdFxcdFxcdFxcdGNvbnN0IGdyb3VuZCA9IEJvZGllcy5yZWN0YW5nbGUodyAvIDIsIGggKyA1MCwgdyArIDEwMCwgMTAwLCB3YWxsT3B0aW9ucyk7XFxyXFxuXFx0XFx0XFx0XFx0XFx0Y29uc3QgY2VpbGluZyA9IEJvZGllcy5yZWN0YW5nbGUodyAvIDIsIC01MCwgdyArIDEwMCwgMTAwLCB3YWxsT3B0aW9ucyk7XFxyXFxuXFx0XFx0XFx0XFx0XFx0Y29uc3QgbGVmdFdhbGwgPSBCb2RpZXMucmVjdGFuZ2xlKC01MCwgaCAvIDIsIDEwMCwgaCArIDEwMCwgd2FsbE9wdGlvbnMpO1xcclxcblxcdFxcdFxcdFxcdFxcdGNvbnN0IHJpZ2h0V2FsbCA9IEJvZGllcy5yZWN0YW5nbGUodyArIDUwLCBoIC8gMiwgMTAwLCBoICsgMTAwLCB3YWxsT3B0aW9ucyk7XFxyXFxuXFxyXFxuXFx0XFx0XFx0XFx0XFx0Q29tcG9zaXRlLmFkZChlbmdpbmUud29ybGQsIFtncm91bmQsIGNlaWxpbmcsIGxlZnRXYWxsLCByaWdodFdhbGxdKTtcXHJcXG5cXHJcXG5cXHRcXHRcXHRcXHRcXHRjb25zdCBtb3VzZUNvbnRyb2wgPSBNb3VzZUNvbnN0cmFpbnQuY3JlYXRlKGVuZ2luZSwge1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdGVsZW1lbnQ6ICR0aGlzLmZpbmQoXFxcIi5zaGFwZXNcXFwiKVswXSxcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRjb25zdHJhaW50OiB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0cmVuZGVyOiB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0dmlzaWJsZTogZmFsc2UsXFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0fSxcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHR9LFxcclxcblxcdFxcdFxcdFxcdFxcdH0pO1xcclxcblxcclxcblxcdFxcdFxcdFxcdFxcdENvbXBvc2l0ZS5hZGQoZW5naW5lLndvcmxkLCBtb3VzZUNvbnRyb2wpO1xcclxcblxcclxcblxcdFxcdFxcdFxcdFxcdC8vIHJ1biB0aGUgcmVuZGVyZXJcXHJcXG5cXHRcXHRcXHRcXHRcXHRSZW5kZXIucnVuKHJlbmRlcik7XFxyXFxuXFxyXFxuXFx0XFx0XFx0XFx0XFx0Ly8gY3JlYXRlIHJ1bm5lclxcclxcblxcdFxcdFxcdFxcdFxcdHZhciBydW5uZXIgPSBSdW5uZXIuY3JlYXRlKCk7XFxyXFxuXFxyXFxuXFx0XFx0XFx0XFx0XFx0Ly8gcnVuIHRoZSBlbmdpbmVcXHJcXG5cXHRcXHRcXHRcXHRcXHRSdW5uZXIucnVuKHJ1bm5lciwgZW5naW5lKTtcXHJcXG5cXHRcXHRcXHRcXHR9XFxyXFxuXFxyXFxuXFx0XFx0XFx0XFx0aW5pdCgpO1xcclxcblxcclxcblxcdFxcdFxcdFxcdHdpbmRvdy5hZGR
2FdmVudExpc3RlbmVyKFxcXCJyZXNpemVcXFwiLCBmdW5jdGlvbiAoKSB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0UmVuZGVyLnN0b3AocmVuZGVyKTtcXHJcXG5cXHRcXHRcXHRcXHRcXHRXb3JsZC5jbGVhcihlbmdpbmUud29ybGQpO1xcclxcblxcdFxcdFxcdFxcdFxcdEVuZ2luZS5jbGVhcihlbmdpbmUpO1xcclxcblxcdFxcdFxcdFxcdFxcdHJlbmRlci5jYW52YXMucmVtb3ZlKCk7XFxyXFxuXFx0XFx0XFx0XFx0XFx0cmVuZGVyLmNhbnZhcyA9IG51bGw7XFxyXFxuXFx0XFx0XFx0XFx0XFx0cmVuZGVyLmNvbnRleHQgPSBudWxsO1xcclxcblxcdFxcdFxcdFxcdFxcdHJlbmRlci50ZXh0dXJlcyA9IHt9O1xcclxcblxcclxcblxcdFxcdFxcdFxcdFxcdGluaXQoKTtcXHJcXG5cXHRcXHRcXHRcXHR9KTtcXHJcXG5cXHRcXHRcXHR9LFxcclxcblxcdFxcdH0pO1xcclxcblxcdH0pO1xcclxcbn0pO1xcclxcblxcblxcbi8vIyBzb3VyY2VVUkw9d2VicGFjazovLy8uL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9tYXR0ZXIuanM/XCIpO1xuICAgIC8qKiovXG4gIH0sXG5cbiAgLyoqKi9cbiAgXCIuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9tZWRpYS5qc1wiOlxuICAvKiEqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqISpcXFxuICAgICEqKiogLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvbWVkaWEuanMgKioqIVxuICAgIFxcKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuICAvKiEgZXhwb3J0cyBwcm92aWRlZDogZGVmYXVsdCAqL1xuXG4gIC8qKiovXG4gIGZ1bmN0aW9uIGFzc2V0c1NyY0pzTW9kdWxlc01lZGlhSnMobW9kdWxlLCBfX3dlYnBhY2tfZXhwb3J0c19fLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICBldmFsKFwiX193ZWJwYWNrX3JlcXVpcmVfXy5yKF9fd2VicGFja19leHBvcnRzX18pO1xcbi8qIGhhcm1vbnkgZGVmYXVsdCBleHBvcnQgKi8gX193ZWJwYWNrX2V4cG9ydHNfX1tcXFwiZGVmYXVsdFxcXCJdID0gKGZ1bmN0aW9uICgpIHtcXG5cXHR2YXIgJCA9IGpRdWVyeTtcXG5cXG5cXHQkKFxcXCIuYy1tZWRpYV9idG5cXFwiKS5jbGljayhmdW5jdGlvbiAoKSB7XFxuXFx0XFx0JCh0aGlzKS5jbG9zZXN0KFxcXCIuYy1tZWRpYV9tZWRpYVxcXCIpLmZpbmQoXFxcIi5jLW1lZGlhX21lZGlhIGltZ1xcXCIpLmFkZENsYXNzKFxcXCItaGlkZGVuXFxcIik7XFxuXFx0XFx0JCh0aGlzKS5hZGRDbGFzcyhcXFwiLWhpZGRlblxcXCIpO1xcblxcdFxcdCQoXFxcIi5jLW1lZGlhX3ZpZGVvXFxcIikuYWRkQ2xhc3MoXFxcIi1hY3RpdmVcXFwiKTtcXG5cXG5cXHRcXHQkKFxcXCIuYy1tZWRpYV92aWRlb1xcXCIpLnRyaWdnZXIoXFxcInBsYXlcXFwiKTtcXG5cXHR9KTtcXG59KTtcXG5cXG5cXG4vLyMgc291cmNlVVJMPXdlYnBhY2s6Ly8vLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvbWVkaWEuanM/XCIpO1xuICAgIC8qKiovXG4gIH0sXG5cbiAgLyoqKi9cbiAgXCIuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9tZW51cy5qc1wiOlxuICAvKiEqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqISpcXFxuICAgICEqKiogLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvbWVudXMuanMgKioqIVxuICAgIFxcKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuICAvKiEgZXhwb3J0cyBwcm92aWRlZDogZGVmYXVsdCAqL1xuXG4gIC8qKiovXG4gIGZ1bmN0aW9uIGFzc2V0c1NyY0pzTW9kdWxlc01lbnVzSnMobW9kdWxlLCBfX3dlYnBhY2tfZXhwb3J0c19fLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICBldmFsKFwiX193ZWJwYWNrX3JlcXVpcmVfXy5yKF9fd2VicGFja19leHBvcnRzX18pO1xcbi8qIGhhcm1vbnkgZGVmYXVsdCBleHBvcnQgKi8gX193ZWJwYWNrX2V4cG9ydHNfX1tcXFwiZGVmYXVsdFxcXCJdID0gKGZ1bmN0aW9uICgpIHtcXG5cXHR2YXIgJCA9IGpRdWVyeTtcXG5cXG5cXHQvLyBNZW51IGludGVyYWN0aW9uXFxuXFxuXFx0JChcXFwiLmMtaGVhZGVyX2xpbmsuLWhhcy1jaGlsZHJlblxcXCIpLmNsaWNrKGZ1bmN0aW9uICgpIHtcXG5cXHRcXHR2YXIgaWQgPSAkKHRoaXMpLmF0dHIoXFxcImlkXFxcIik7XFxuXFx0XFx0dmFyIGlzQWN0aXZlID0gJCh0aGlzKS5oYXNDbGFzcyhcXFwiLWFjdGl2ZVxcXCIpO1xcblxcblxcdFxcdCQoXFxcIi5jLWhlYWRlcl9saW5rXFxcIikucmVtb3ZlQ2xhc3MoXFxcIi1hY3RpdmVcXFwiKTtcXG5cXHRcXHQkKFxcXCIuYy1zdWJtZW51XFxcIikucmVtb3ZlQ2xhc3MoXFxcIi1hY3RpdmVcXFwiKTtcXG5cXG5cXHRcXHRpZiAoIWlzQWN0aXZlKSB7XFxuXFx0XFx0XFx0JCh0aGlzKS5hZGRDbGFzcyhcXFwiLWFjdGl2ZVxcXCIpO1xcblxcdFxcdFxcdCQoXFxcIi5jLXN1Ym1lbnUjXFxcIiArIGlkKS5hZGRDbGFzcyhcXFwiLWFjdGl2ZVxcXCIpO1xcblxcdFxcdH1cXG5cXHR9KTtcXG5cXG5cXHQkKHdpbmRvdykuc2Nyb2xsKGZ1bmN0aW9uICgpIHtcXG5cXHRcXHQkKFxcXCIuYy1oZWFkZXJfbGlua1xcXCIpLnJlbW92ZUNsYXNzKFxcXCItYWN0aXZlXFxcIik7XFxuXFx0XFx0JChcXFwiLmMtc3VibWVudVxcXCIpLnJlbW92ZUNsYXNzKFxcXCItYWN0aXZlXFxcIik7XFxuXFx0fSk7XFxuXFxuXFx0Ly8gTW9iaWxlIG1lbnUgaW50ZXJhY3Rpb25cXG5cXHQkKFxcXCIuYy1tb2JpbGUtbWVudV9saW5rLi1oYXMtY2hpbGRyZW5cXFwiKS5jbGljayhmdW5jdGlvbiAoKSB7XFxuXFx0XFx0dmFyIGlzVG9nZ2xlZCA9ICQodGhpcykuaGFzQ2xhc3MoXFxcIi10b2dnbGVkXFxcIik7XFxuXFxuXFx0XFx0JChcXFwiLmMtbW9iaWxlLW1lbnVfbGlua1xcXCIpLnJlbW92ZUNsYXNzKFxcXCItdG9nZ2xlZFxcXCIpO1xcblxcdFxcdCQoXFxcIi5jLW1vYmlsZS1tZW51X3N1Ym1lbnVcXFwiKS5yZW1vdmVDbGFzcyhcXFwiLXRvZ2dsZWRcXFwiKTtcXG5cXG5cXHRcXHRpZiAoIWlzVG9nZ2xlZCkge1xcblxcdFxcdFxcdCQodGhpcykuYWRkQ2xhc3MoXFxcIi10b2dnbGVkXFxcIik7XFxuXFx0XFx0XFx0JCh0aGlzKS5uZXh0KCkuYWRkQ2xhc3MoXFxcIi10b2dnbGVkXFxcIik7XFxuXFx0XFx0fVxcblxcdH0pO1xcblxcblxcdC8vIEJ1cmdlclxcblxcdCQoXFxcIi5jLWJ1cmdlclxcXCIpLmNsaWNrKGZ1bmN0aW9uICgpIHtcXG5cXHRcXHQkKHRoaXMpLnRvZ2dsZUNsYXNzKFxcXCItdG9nZ2xlZFxcXCIpO1xcblxcdFxcdCQoXFxcIi5jLW1vYmlsZS1tZW51XFxcIikudG9nZ2xlQ2xhc3MoXFxcIi10b2dnbGVkXFxcIik7XFxuXFx0XFx0JChcXFwiaHRtbFxcXCIpLnRvZ2dsZUNsYXNzKFxcXCJpcy1sb2NrLXNjcm9sbFxcXCIpO1xcblxcdH0pO1xcblxcblxcdC8vIEJhbm5lclxcblxcblxcdCQoXFxcIi5jLWhlYWRlcl9jbG9zZVxcXCIpLmNsaWNrKGZ1bmN0aW9uICgpIHtcXG5cXHRcXHQkKFxcXCIuYy1oZWFkZXJfdG9wXFxcIikuYWRkQ2xhc3MoXFxcIi1jbG9zZVxcXCIpO1xcblxcdFxcdGRvY3VtZW50LmNvb2tpZSA9IFxcXCJtb2RhbD1jbG9zZWQ7IHBhdGg9L1xcXCI7XFxuXFx0fSk7XFxuXFxuXFx0aWYgKGdldENvb2tpZShcXFwibW9kYWxcXFwiKSkge1xcblxcdFxcdCQoXFxcIi5jLWhlYWRlcl90b3BcXFwiKS5hZGRDbGFzcyhcXFwiLWNsb3NlXFxcIik7XFxuXFx0fVxcblxcblxcdGZ1bmN0aW9uIGdldENvb2tpZShuYW1lKSB7XFxuXFx0XFx0dmFyIGRjID0gZG9jdW1lbnQuY29va2llO1xcblxcdFxcdHZhciBwcmVmaXggPSBuYW1lICsgXFxcIj1cXFwiO1xcblxcdFxcdHZhciBiZWdpbiA9IGRjLmluZGV4T2YoXFxcIjsgXFxcIiArIHByZWZpeCk7XFxuXFx0XFx0aWYgKGJlZ2luID09IC0xKSB7XFxuXFx0XFx0XFx0YmVnaW4gPSBkYy5pbmRleE9mKHByZWZpeCk7XFxuXFx0XFx0XFx0aWYgKGJlZ2luICE9IDApIHJldHVybi
2BudWxsO1xcblxcdFxcdH0gZWxzZSB7XFxuXFx0XFx0XFx0YmVnaW4gKz0gMjtcXG5cXHRcXHRcXHR2YXIgZW5kID0gZG9jdW1lbnQuY29va2llLmluZGV4T2YoXFxcIjtcXFwiLCBiZWdpbik7XFxuXFx0XFx0XFx0aWYgKGVuZCA9PSAtMSkge1xcblxcdFxcdFxcdFxcdGVuZCA9IGRjLmxlbmd0aDtcXG5cXHRcXHRcXHR9XFxuXFx0XFx0fVxcblxcdFxcdC8vIGJlY2F1c2UgdW5lc2NhcGUgaGFzIGJlZW4gZGVwcmVjYXRlZCwgcmVwbGFjZWQgd2l0aCBkZWNvZGVVUklcXG5cXHRcXHQvL3JldHVybiB1bmVzY2FwZShkYy5zdWJzdHJpbmcoYmVnaW4gKyBwcmVmaXgubGVuZ3RoLCBlbmQpKTtcXG5cXHRcXHRyZXR1cm4gZGVjb2RlVVJJKGRjLnN1YnN0cmluZyhiZWdpbiArIHByZWZpeC5sZW5ndGgsIGVuZCkpO1xcblxcdH1cXG5cXG5cXHQvLyB2YXIgc2VjdGlvbkNvbG9yID0gJChcXFwibWFpbiAuby1zZWN0aW9uOmZpcnN0XFxcIik7XFxuXFxuXFx0Ly8gaWYgKHNlY3Rpb25Db2xvci5oYXNDbGFzcyhcXFwiLW5ldXRyYWwtODAwXFxcIikpIHtcXG5cXHQvLyBcXHQkKFxcXCIuYy1oZWFkZXJcXFwiKS5hZGRDbGFzcyhcXFwiLWxpZ2h0XFxcIik7XFxuXFx0Ly8gXFx0JChcXFwiLmMtaGVhZGVyIGltZ1xcXCIpLmF0dHIoXFxcInNyY1xcXCIsIFxcXCIvd3AtY29udGVudC90aGVtZXMvY2RpZC9hc3NldHMvc3JjL2ltYWdlcy9sb2dvLWRhcmsuc3ZnXFxcIik7XFxuXFx0Ly8gfVxcblxcblxcdC8vIENoYW5nZSB0aGUgYmFja2dyb3VuZC1jb2xvciBvZiBoZWFkZXIgaWYgZmlyc3Qgc2VjdGlvbiBpcyBub3QgbmV1dHJhbC0xMDBcXG5cXHRpZiAoJChcXFwiLm8tc2VjdGlvbjpmaXJzdFxcXCIpLmhhc0NsYXNzKFxcXCItbmV1dHJhbC04MDBcXFwiKSB8fCAkKFxcXCIuby1zZWN0aW9uOmZpcnN0XFxcIikuaGFzQ2xhc3MoXFxcIi1uZXV0cmFsLTcwMFxcXCIpIHx8ICQoXFxcIi5jLXNoYXBlcy1oZWFkZXJcXFwiKS5sZW5ndGggPiAwKSB7XFxuXFx0XFx0JChcXFwiLmMtaGVhZGVyXFxcIikuYWRkQ2xhc3MoXFxcIi1saWdodFxcXCIpO1xcblxcdFxcdCQoXFxcIi5jLWhlYWRlciBpbWdcXFwiKS5hdHRyKFxcXCJzcmNcXFwiLCBcXFwiL3dwLWNvbnRlbnQvdGhlbWVzL2NkaWQvYXNzZXRzL3NyYy9pbWFnZXMvbG9nby1kYXJrLnN2Z1xcXCIpO1xcblxcdH1cXG59KTtcXG5cXG5cXG4vLyMgc291cmNlVVJMPXdlYnBhY2s6Ly8vLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvbWVudXMuanM/XCIpO1xuICAgIC8qKiovXG4gIH0sXG5cbiAgLyoqKi9cbiAgXCIuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9zZWN0aW9uLmpzXCI6XG4gIC8qISoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiEqXFxcbiAgICAhKioqIC4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL3NlY3Rpb24uanMgKioqIVxuICAgIFxcKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4gIC8qISBleHBvcnRzIHByb3ZpZGVkOiBkZWZhdWx0ICovXG5cbiAgLyoqKi9cbiAgZnVuY3Rpb24gYXNzZXRzU3JjSnNNb2R1bGVzU2VjdGlvbkpzKG1vZHVsZSwgX193ZWJwYWNrX2V4cG9ydHNfXywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgZXZhbChcIl9fd2VicGFja19yZXF1aXJlX18ucihfX3dlYnBhY2tfZXhwb3J0c19fKTtcXG4vKiBoYXJtb255IGRlZmF1bHQgZXhwb3J0ICovIF9fd2VicGFja19leHBvcnRzX19bXFxcImRlZmF1bHRcXFwiXSA9IChmdW5jdGlvbiAoKSB7XFxuXFx0dmFyICQgPSBqUXVlcnk7XFxuXFxuXFx0Ly8gJChcXFwiLm8tc2VjdGlvblxcXCIpLmVhY2goZnVuY3Rpb24gKCkge1xcblxcdC8vIFxcdGlmICgkKHRoaXMpLmhhc0NsYXNzKFxcXCItdG9wXFxcIikgfHwgJCh0aGlzKS5oYXNDbGFzcyhcXFwiLWJvdHRvbVxcXCIpKSB7XFxuXFx0Ly8gXFx0XFx0aWYgKCQodGhpcykuaGFzQ2xhc3MoXFxcIi1ib3R0b21cXFwiKSkge1xcblxcdC8vIFxcdFxcdFxcdCQodGhpcykucHJldigpLmFkZENsYXNzKFxcXCItcGFkZGluZy1ib3R0b20teGxcXFwiKTtcXG5cXHQvLyBcXHRcXHR9XFxuXFxuXFx0Ly8gXFx0XFx0aWYgKCQodGhpcykuaGFzQ2xhc3MoXFxcIi10b3BcXFwiKSkge1xcblxcdC8vIFxcdFxcdFxcdCQodGhpcykucHJldigpLmFkZENsYXNzKFxcXCItcGFkZGluZy10b3AteGxcXFwiKTtcXG5cXHQvLyBcXHRcXHR9XFxuXFx0Ly8gXFx0fVxcblxcdC8vIH0pO1xcbn0pO1xcblxcblxcbi8vIyBzb3VyY2VVUkw9d2VicGFjazovLy8uL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9zZWN0aW9uLmpzP1wiKTtcbiAgICAvKioqL1xuICB9LFxuXG4gIC8qKiovXG4gIFwiLi9saWJyYXJpZXMvcHJ4LWZpbHRlcnMvcHJ4LWZpbHRlcnMuanNcIjpcbiAgLyohKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiEqXFxcbiAgICAhKioqIC4vbGlicmFyaWVzL3ByeC1maWx0ZXJzL3ByeC1maWx0ZXJzLmpzICoqKiFcbiAgICBcXCoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbiAgLyohIGV4cG9ydHMgcHJvdmlkZWQ6IFByeEZpbHRlcnMgKi9cblxuICAvKioqL1xuICBmdW5jdGlvbiBsaWJyYXJpZXNQcnhGaWx0ZXJzUHJ4RmlsdGVyc0pzKG1vZHVsZSwgX193ZWJwYWNrX2V4cG9ydHNfXywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgZXZhbChcIl9fd2VicGFja19yZXF1aXJlX18ucihfX3dlYnBhY2tfZXhwb3J0c19fKTtcXG4vKiBoYXJtb255IGV4cG9ydCAoYmluZGluZykgKi8gX193ZWJwYWNrX3JlcXVpcmVfXy5kKF9fd2VicGFja19leHBvcnRzX18sIFxcXCJQcnhGaWx0ZXJzXFxcIiwgZnVuY3Rpb24oKSB7IHJldHVybiBQcnhGaWx0ZXJzOyB9KTtcXG4vKiBoYXJtb255IGltcG9ydCAqLyB2YXIgZnV6enlzb3J0X19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8wX18gPSBfX3dlYnBhY2tfcmVxdWlyZV9fKC8qISBmdXp6eXNvcnQgKi8gXFxcIi4vbm9kZV9tb2R1bGVzL2Z1enp5c29ydC9mdXp6eXNvcnQuanNcXFwiKTtcXG4vKiBoYXJtb255IGltcG9ydCAqLyB2YXIgZnV6enlzb3J0X19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8wX19fZGVmYXVsdCA9IC8qI19fUFVSRV9fKi9fX3dlYnBhY2tfcmVxdWlyZV9fLm4oZnV6enlzb3J0X19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8wX18pO1xcbi8qKlxcclxcbiAqIFNpbXBsZSBmaWx0ZXJzLlxcclxcbiAqXFxyXFxuICogQGxpbmsgaHR0cHM6Ly9sZXNwcngubW9uZGF5LmNvbS9kb2NzLzQ4MjI3ODk1NDNcXHJcXG4gKiBAYXV0aG9yIExlcyBQcsOpdGVudGlldXhcXHJcXG4gKiBAdmVyc2lvbiAxLjAuMFxcclxcbiAqXFxyXFxuICogKi9cXHJcXG5cXHJcXG5cXHJcXG5cXHJcXG5cXHJcXG5cXHJcXG5jbGFzcyBQcnhGaWx0ZXJzIHtcXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBJbml0IG91ciBjbGFzcy5cXHJcXG5cXHQgKlxcclxcblxcdCAqIEBwYXJhbSB7b2JqZWN0fSBbb3B0aW9uc10gLSBQcnhGaWx0ZXJzIG9wdGlvbnMuXFxyXFxuXFx0ICogQHBhcmFtIHtudW1iZXJ9IFtvcHRpb25zLnNlYXJjaFRocmVzaG9sZD0tSW5maW5pdHldIC0gTWluaW11bSByZWxldmFuY3kgc2NvcmUgdG8gY29uc2lkZXIgYSBzZWFyY2ggcmVzdWx0IGFzIHZhbGlkLlxcclxcblxcdCAqL1xcclxcblxcdGNvbnN0cnVjdG9yKHsgc2VhcmNoVGhyZXNob2xkID0gLUluZmluaXR5IH0gPSB7fSkge1xcclxcblxcdFxcdHRoaXMuc2VhcmNoVGhyZXNob2xkID0gc2VhcmNoVGhyZXNob2xkO1xcclxcblxcclxcblxcdFxcdHRoaXMuZmlsdGVyc0VsZW1zID0gW107XFxyXFxuXFxyXFxuXFx0XFx0dGhpcy5pbml0KCk7XFxyXFxuXFx0fVxcclxcblxcclxcblxcdC8qKlxcclxcblxcdCAqIEluaXRpYWxpemUgZmlsdGVycy5cXHJcXG5cXHQgKi9cXHJcXG5cXHRpbml0KCkge1xcclxcblxcdFxcdC8vIEdldCBhbGwgZmlsdGVyc1xcclxcblxcdFxcdHRoaXMuZmlsdGVyc0VsZW1zID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbChcXFwiW2RhdGEtZmlsdGVyc11cXFwiKTtcXHJcXG5cXHJcXG5cXHRcXHR0aGlzLmZpbHRlcnNFbGVtcy5mb3JFYWNoKChmaWx0ZXJzRWxlbSkgPT4ge1xcclxcblxcdFxcdFxcdC8vIEdldCB0aGUgZmlsdGVycyBwYXJhbXNcXHJcXG5cXHRcXHRcXHR2YXIgZmlsdGVyc1BhcmFtcyA9IGZpbHRlcnNFbGVtLmRhdGFzZXQuZmlsdGVycztcXHJcXG5cXHRcXHRcXHRmaWx0ZXJzUGFyYW1zID0gSlNPTi5wYXJzZShmaWx0ZXJzUGFyYW1zKTtcX
2HJcXG5cXHJcXG5cXHRcXHRcXHQvLyBTdG9yZSB0aG9zZSBwYXJhbXMgaW4gdGhlIGZpbHRlcnMgbm9kZVxcclxcblxcdFxcdFxcdHZhciBwYXJhbXNPYmogPSB7XFxyXFxuXFx0XFx0XFx0XFx0Zm9yOiBmaWx0ZXJzUGFyYW1zLmZvcixcXHJcXG5cXHRcXHRcXHRcXHR1cmxIYXNoOiBmaWx0ZXJzUGFyYW1zLnVybEhhc2ggPyBmaWx0ZXJzUGFyYW1zLnVybEhhc2ggOiBmYWxzZSxcXHJcXG5cXHRcXHRcXHRcXHRvblN1Ym1pdDogZmlsdGVyc1BhcmFtcy5vblN1Ym1pdCA/IGZpbHRlcnNQYXJhbXMub25TdWJtaXQgOiBmYWxzZSxcXHJcXG5cXHRcXHRcXHR9O1xcclxcblxcdFxcdFxcdGZpbHRlcnNFbGVtID0gT2JqZWN0LmFzc2lnbihmaWx0ZXJzRWxlbSwgcGFyYW1zT2JqKTtcXHJcXG5cXHJcXG5cXHRcXHRcXHQvLyBQcmVlbXB0aXZlbHkgYnVpbGQgZmlsdGVycyBvYmplY3RcXHJcXG5cXHRcXHRcXHR0aGlzLmJ1aWxkRmlsdGVyc09iamVjdChmaWx0ZXJzRWxlbSk7XFxyXFxuXFxyXFxuXFx0XFx0XFx0Ly8gR2V0IHRoZSBmaWx0ZXJzIGZpbHRlciBlbGVtZW50c1xcclxcblxcdFxcdFxcdHZhciBmaWx0ZXJFbGVtcyA9IGZpbHRlcnNFbGVtLnF1ZXJ5U2VsZWN0b3JBbGwoXFxcIltkYXRhLWZpbHRlcl1cXFwiKTtcXHJcXG5cXHJcXG5cXHRcXHRcXHQvLyBCdWlsZCBmaWx0ZXJzIG9iamVjdCBvbiBpbnB1dFxcclxcblxcdFxcdFxcdGlmIChmaWx0ZXJzRWxlbS5vblN1Ym1pdCkge1xcclxcblxcdFxcdFxcdFxcdHZhciBmaWx0ZXJTdWJtaXQgPSBmaWx0ZXJzRWxlbS5xdWVyeVNlbGVjdG9yKFxcXCJbZGF0YS1maWx0ZXItc3VibWl0XVxcXCIpO1xcclxcblxcdFxcdFxcdFxcdGZpbHRlclN1Ym1pdC5hZGRFdmVudExpc3RlbmVyKFxcXCJjbGlja1xcXCIsICgpID0+IHRoaXMuYnVpbGRGaWx0ZXJzT2JqZWN0KGZpbHRlcnNFbGVtKSk7XFxyXFxuXFx0XFx0XFx0fSBlbHNlIHtcXHJcXG5cXHRcXHRcXHRcXHRmaWx0ZXJFbGVtcy5mb3JFYWNoKChmaWx0ZXJFbGVtKSA9PiB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0ZmlsdGVyRWxlbS5hZGRFdmVudExpc3RlbmVyKFxcXCJpbnB1dFxcXCIsICgpID0+IHRoaXMuYnVpbGRGaWx0ZXJzT2JqZWN0KGZpbHRlcnNFbGVtKSk7XFxyXFxuXFx0XFx0XFx0XFx0fSk7XFxyXFxuXFx0XFx0XFx0fVxcclxcblxcdFxcdH0pO1xcclxcblxcdH1cXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBCdWlsZCBmaWx0ZXJzIG9iamVjdCBmb3IgYSBnaXZlbiBmaWx0ZXJzIGVsZW1lbnQuXFxyXFxuXFx0ICpcXHJcXG5cXHQgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBmaWx0ZXJzRWxlbSAtIFRoZSBmaWx0ZXJzIGVsZW1lbnQuXFxyXFxuXFx0ICovXFxyXFxuXFx0YnVpbGRGaWx0ZXJzT2JqZWN0KGZpbHRlcnNFbGVtKSB7XFxyXFxuXFx0XFx0dmFyIGZpbHRlcnNPYmogPSBbXTtcXHJcXG5cXHJcXG5cXHRcXHQvLyBHZXQgZmlsdGVyIGdyb3Vwc1xcclxcblxcdFxcdHZhciBmaWx0ZXJHcm91cHMgPSBmaWx0ZXJzRWxlbS5xdWVyeVNlbGVjdG9yQWxsKFxcXCJbZGF0YS1maWx0ZXItZ3JvdXBdXFxcIik7XFxyXFxuXFxyXFxuXFx0XFx0ZmlsdGVyR3JvdXBzLmZvckVhY2goKGZpbHRlckdyb3VwKSA9PiB7XFxyXFxuXFx0XFx0XFx0dmFyIGZpbHRlcnNHcm91cE9iaiA9IHt9O1xcclxcblxcdFxcdFxcdHZhciBmaWx0ZXJFbGVtcyA9IGZpbHRlckdyb3VwLnF1ZXJ5U2VsZWN0b3JBbGwoXFxcIltkYXRhLWZpbHRlcl1cXFwiKTtcXHJcXG5cXHJcXG5cXHRcXHRcXHQvLyBMb29wIHRocm91Z2ggZWFjaCBmaWx0ZXJzIG9mIHRoZSBncm91cFxcclxcblxcdFxcdFxcdGZpbHRlckVsZW1zLmZvckVhY2goKGZpbHRlckVsZW0pID0+IHtcXHJcXG5cXHRcXHRcXHRcXHR2YXIga2V5ID0gZmlsdGVyRWxlbS5kYXRhc2V0LmZpbHRlcjtcXHJcXG5cXHRcXHRcXHRcXHR2YXIgdmFsdWUgPSBcXFwiXFxcIjtcXHJcXG5cXHRcXHRcXHRcXHR2YXIgdHlwZSA9IGZpbHRlckVsZW0udHlwZTtcXHJcXG5cXHJcXG5cXHRcXHRcXHRcXHRpZiAodHlwZSA9PSBcXFwicmFkaW9cXFwiIHx8IHR5cGUgPT0gXFxcImNoZWNrYm94XFxcIikge1xcclxcblxcdFxcdFxcdFxcdFxcdGlmIChmaWx0ZXJFbGVtLmNoZWNrZWQpIHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHR2YWx1ZSA9IGZpbHRlckVsZW0udmFsdWU7XFxyXFxuXFx0XFx0XFx0XFx0XFx0fVxcclxcblxcdFxcdFxcdFxcdH0gZWxzZSB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0dmFsdWUgPSBmaWx0ZXJFbGVtLnZhbHVlO1xcclxcblxcdFxcdFxcdFxcdH1cXHJcXG5cXHJcXG5cXHRcXHRcXHRcXHRpZiAoZmlsdGVyc0dyb3VwT2JqW2tleV0gPT0gdW5kZWZpbmVkKSB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0ZmlsdGVyc0dyb3VwT2JqW2tleV0gPSBbXTtcXHJcXG5cXHRcXHRcXHRcXHR9XFxyXFxuXFxyXFxuXFx0XFx0XFx0XFx0aWYgKHZhbHVlKSB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0ZmlsdGVyc0dyb3VwT2JqW2tleV0ucHVzaCh2YWx1ZSk7XFxyXFxuXFx0XFx0XFx0XFx0fVxcclxcblxcdFxcdFxcdH0pO1xcclxcblxcclxcblxcdFxcdFxcdC8vIEFkZCBmaWx0ZXJzIGdyb3VwIG9iamVjdCB0byB0aGUgbWFpbiBmaWx0ZXJzIG9iamVjdFxcclxcblxcdFxcdFxcdGZpbHRlcnNPYmoucHVzaChmaWx0ZXJzR3JvdXBPYmopO1xcclxcblxcdFxcdH0pO1xcclxcblxcclxcblxcdFxcdC8vIFN0b3JlIGZpbHRlcnMgb2JqZWN0IGluIHRoZSBmaWx0ZXJzIG5vZGVcXHJcXG5cXHRcXHRmaWx0ZXJzRWxlbSA9IE9iamVjdC5hc3NpZ24oZmlsdGVyc0VsZW0sIHsgZmlsdGVyc09iajogZmlsdGVyc09iaiB9KTtcXHJcXG5cXHJcXG5cXHRcXHRpZiAoZmlsdGVyc0VsZW0udXJsSGFzaCkge1xcclxcblxcdFxcdFxcdHRoaXMuYnVpbGRVcmwoZmlsdGVyc0VsZW0pO1xcclxcblxcdFxcdH1cXHJcXG5cXHJcXG5cXHRcXHR0aGlzLnVwZGF0ZVZpZXcoKTtcXHJcXG5cXHR9XFxyXFxuXFxyXFxuXFx0LyoqXFxyXFxuXFx0ICogQnVpbGRzIHRoZSBVUkwgaGFzaC5cXHJcXG5cXHQgKlxcclxcblxcdCAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IGZpbHRlcnNFbGVtIC0gVGhlIGZpbHRlcnMgZWxlbWVudC5cXHJcXG5cXHQgKi9cXHJcXG5cXHRidWlsZFVybChmaWx0ZXJzRWxlbSkge1xcclxcblxcdFxcdGNvbnN0IHVybCA9IG5ldyBVUkwod2luZG93LmxvY2F0aW9uLmhy
2ZWYpO1xcclxcblxcclxcblxcdFxcdHZhciBmaWx0ZXJzT2JqID0gZmlsdGVyc0VsZW0uZmlsdGVyc09iajtcXHJcXG5cXHJcXG5cXHRcXHRmaWx0ZXJzT2JqLmZvckVhY2goKGZpbHRlcnNHcm91cE9iaikgPT4ge1xcclxcblxcdFxcdFxcdGZvciAodmFyIGtleSBpbiBmaWx0ZXJzR3JvdXBPYmopIHtcXHJcXG5cXHRcXHRcXHRcXHRpZiAoZmlsdGVyc0dyb3VwT2JqW2tleV0gIT0gXFxcIlxcXCIpIHtcXHJcXG5cXHRcXHRcXHRcXHRcXHR1cmwuc2VhcmNoUGFyYW1zLnNldChrZXksIGZpbHRlcnNHcm91cE9ialtrZXldKTtcXHJcXG5cXHRcXHRcXHRcXHR9IGVsc2Uge1xcclxcblxcdFxcdFxcdFxcdFxcdHVybC5zZWFyY2hQYXJhbXMuZGVsZXRlKGtleSk7XFxyXFxuXFx0XFx0XFx0XFx0fVxcclxcblxcdFxcdFxcdH1cXHJcXG5cXHRcXHR9KTtcXHJcXG5cXHJcXG5cXHRcXHR3aW5kb3cuaGlzdG9yeS5wdXNoU3RhdGUoXFxcIlxcXCIsIFxcXCJcXFwiLCB1cmwpO1xcclxcblxcdH1cXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBVcGRhdGVzIHZpZXcuXFxyXFxuXFx0ICovXFxyXFxuXFx0dXBkYXRlVmlldygpIHtcXHJcXG5cXHRcXHR0aGlzLmZpbHRlcnNFbGVtcy5mb3JFYWNoKChmaWx0ZXJzRWxlbSkgPT4ge1xcclxcblxcdFxcdFxcdHZhciByZXN1bHRzT2JqID0gW107XFxyXFxuXFx0XFx0XFx0dmFyIGZpbHRlcnNPYmogPSBmaWx0ZXJzRWxlbS5maWx0ZXJzT2JqO1xcclxcblxcdFxcdFxcdHZhciBmaWx0ZXJGb3IgPSBmaWx0ZXJzRWxlbS5mb3I7XFxyXFxuXFxyXFxuXFx0XFx0XFx0dmFyIGZpbHRlckl0ZW1zRWxlbXMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKCdbZGF0YS1maWx0ZXItaXRlbXM9XFxcIicgKyBmaWx0ZXJGb3IgKyAnXFxcIl0nKTtcXHJcXG5cXHJcXG5cXHRcXHRcXHRmaWx0ZXJJdGVtc0VsZW1zLmZvckVhY2goKGZpbHRlckl0ZW1zRWxlbSkgPT4ge1xcclxcblxcdFxcdFxcdFxcdHZhciBpc0VtcHR5ID0gdHJ1ZTtcXHJcXG5cXHJcXG5cXHRcXHRcXHRcXHRmaWx0ZXJJdGVtc0VsZW0ucXVlcnlTZWxlY3RvckFsbChcXFwiW2RhdGEtZmlsdGVyLWl0ZW1dXFxcIikuZm9yRWFjaCgoZmlsdGVySXRlbSkgPT4ge1xcclxcblxcdFxcdFxcdFxcdFxcdHZhciBncm91cE1hdGNoZXMgPSAwO1xcclxcblxcdFxcdFxcdFxcdFxcdHZhciBmaWx0ZXJJdGVtT2JqID0gZmlsdGVySXRlbS5kYXRhc2V0LmZpbHRlckl0ZW07XFxyXFxuXFx0XFx0XFx0XFx0XFx0ZmlsdGVySXRlbU9iaiA9IEpTT04ucGFyc2UoZmlsdGVySXRlbU9iaik7XFxyXFxuXFxyXFxuXFx0XFx0XFx0XFx0XFx0ZmlsdGVyc09iai5mb3JFYWNoKChmaWx0ZXJzR3JvdXBPYmopID0+IHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHR2YXIgbWF0Y2ggPSBmYWxzZTtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHR2YXIgZ3JvdXBBY3RpdmUgPSBmYWxzZTtcXHJcXG5cXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRmb3IgKHZhciBrZXkgaW4gZmlsdGVyc0dyb3VwT2JqKSB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0dmFyIGZpbHRlckl0ZW1WYWx1ZSA9IGZpbHRlckl0ZW1PYmpba2V5XTtcXHJcXG5cXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRpZiAoZmlsdGVySXRlbVZhbHVlKSB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0ZmlsdGVySXRlbVZhbHVlID0gZmlsdGVySXRlbVZhbHVlLnNwbGl0KFxcXCIsXFxcIik7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0fSBlbHNlIHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRmaWx0ZXJJdGVtVmFsdWUgPSBbXTtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHR9XFxyXFxuXFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0dmFyIGZpbHRlcnNPYmpWYWx1ZSA9IGZpbHRlcnNHcm91cE9ialtrZXldO1xcclxcblxcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdGlmIChrZXkgPT0gXFxcImZzZWFyY2hcXFwiKSB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0aWYgKGZpbHRlcnNPYmpWYWx1ZS5sZW5ndGgpIHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRncm91cEFjdGl2ZSA9IHRydWU7XFxyXFxuXFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0dmFyIHNlYXJjaCA9IGZpbHRlcnNPYmpWYWx1ZVswXTtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRjb25zdCB0YXJnZXRzID0gW2ZpbHRlckl0ZW1PYmpdO1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdGNvbnN0IG9wdGlvbnMgPSB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0dGhyZXNob2xkOiB0aGlzLnNlYXJjaFRocmVzaG9sZCxcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRrZXlzOiBPYmplY3Qua2V5cyhmaWx0ZXJJdGVtT2JqKSxcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHR9O1xcclxcblxcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdGNvbnN0IHJlc3VsdHMgPSBmdXp6eXNvcnRfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzBfX19kZWZhdWx0LmEuZ28oc2VhcmNoLCB0YXJnZXRzLCBvcHRpb25zKTtcXHJcXG5cXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRpZiAocmVzdWx0cy50b3RhbCA+IDApIHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHR2YXIgcmVzdWx0c0FyciA9IFtdO1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdG1hdGNoID0gdHJ1ZTtcXHJcXG5cXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRyZXN1bHRzLmZvckVhY2goKHJlc3VsdCkgPT4ge1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdGZvciAobGV0IGluZGV4ID0gMDsgaW5kZXggPCBPYmplY3Qua2V5cyhmaWx0ZXJJdGVtT2JqKS5sZW5ndGg7IGluZGV4KyspIHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRpZiAocmVzdWx0W2luZGV4XSkge1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdHJlc3VsdHNBcnIucHVzaCh7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0a2V5OiBPYmplY3Qua2V5cyhmaWx0ZXJJdGVtT2JqKVtpbmRleF0sXFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0aGlnaHRsaWdodDogZnV6enlzb3J0X19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8wX19fZGVmYXVsdC5hLmhpZ2hsaWdodChyZXN1bHRbaW5kZXhdLCBcXFwiPHgtc2VhcmNobWF0Y2g+XFxcIiwgXFxcIjwveC1zZWFyY2htYXRjaD5cXFwiKSxcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRzY29yZTogcmVzdWx0LnNjb3JlLFxcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdH0pO1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdH1cXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHR9XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0fSk7XFxyXFxuXFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0cmVzdWx0c09iai5wdXNoKHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRub2RlOiBmaWx0ZXJJdGVtLFxcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdHJlc3VsdHM6IHJlc3VsdHNBcnIsXFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0fSk7XFxyXFxuXFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0YnJlYWs7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0fVxcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdH1cXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHR9IGVsc2Uge1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdGlmIChmaWx0ZXJzT2JqVmFsdWUubGVuZ3RoICYmIGZpbHRlckl0ZW1WYWx1ZS
25sZW5ndGgpIHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHRncm91cEFjdGl2ZSA9IHRydWU7XFxyXFxuXFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0aWYgKGZpbHRlcnNPYmpWYWx1ZS5zb21lKChpdGVtKSA9PiBmaWx0ZXJJdGVtVmFsdWUuaW5jbHVkZXMoaXRlbSkpKSB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0XFx0bWF0Y2ggPSB0cnVlO1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdGJyZWFrO1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdFxcdH1cXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRcXHR9XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0fVxcclxcblxcdFxcdFxcdFxcdFxcdFxcdH1cXHJcXG5cXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRpZiAoKGdyb3VwQWN0aXZlICYmIG1hdGNoKSB8fCAhZ3JvdXBBY3RpdmUpIHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRncm91cE1hdGNoZXMrKztcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHR9XFxyXFxuXFx0XFx0XFx0XFx0XFx0fSk7XFxyXFxuXFxyXFxuXFx0XFx0XFx0XFx0XFx0aWYgKGdyb3VwTWF0Y2hlcyA9PSBmaWx0ZXJzT2JqLmxlbmd0aCkge1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdGZpbHRlckl0ZW0uY2xhc3NMaXN0LmFkZChcXFwiaXMtbWF0Y2hcXFwiKTtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRpc0VtcHR5ID0gZmFsc2U7XFxyXFxuXFx0XFx0XFx0XFx0XFx0fSBlbHNlIHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRmaWx0ZXJJdGVtLmNsYXNzTGlzdC5yZW1vdmUoXFxcImlzLW1hdGNoXFxcIik7XFxyXFxuXFx0XFx0XFx0XFx0XFx0fVxcclxcblxcdFxcdFxcdFxcdH0pO1xcclxcblxcclxcblxcdFxcdFxcdFxcdGlmIChpc0VtcHR5KSB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0ZmlsdGVySXRlbXNFbGVtLmNsYXNzTGlzdC5hZGQoXFxcImlzLWVtcHR5XFxcIik7XFxyXFxuXFx0XFx0XFx0XFx0fSBlbHNlIHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRmaWx0ZXJJdGVtc0VsZW0uY2xhc3NMaXN0LnJlbW92ZShcXFwiaXMtZW1wdHlcXFwiKTtcXHJcXG5cXHRcXHRcXHRcXHR9XFxyXFxuXFxyXFxuXFx0XFx0XFx0XFx0ZmlsdGVyc0VsZW0uZGlzcGF0Y2hFdmVudChcXHJcXG5cXHRcXHRcXHRcXHRcXHRuZXcgQ3VzdG9tRXZlbnQoXFxcImZpbHRlcnM6YWZ0ZXJcXFwiLCB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0ZGV0YWlsOiB7IGlzRW1wdHk6IGlzRW1wdHksIHNlYXJjaFJlc3VsdHM6IHJlc3VsdHNPYmogfSxcXHJcXG5cXHRcXHRcXHRcXHRcXHR9KVxcclxcblxcdFxcdFxcdFxcdCk7XFxyXFxuXFx0XFx0XFx0fSk7XFxyXFxuXFx0XFx0fSk7XFxyXFxuXFx0fVxcclxcbn1cXHJcXG5cXG5cXG4vLyMgc291cmNlVVJMPXdlYnBhY2s6Ly8vLi9saWJyYXJpZXMvcHJ4LWZpbHRlcnMvcHJ4LWZpbHRlcnMuanM/XCIpO1xuICAgIC8qKiovXG4gIH0sXG5cbiAgLyoqKi9cbiAgXCIuL2xpYnJhcmllcy9wcngtaGVscGVycy9wcngtaGVscGVycy5qc1wiOlxuICAvKiEqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqISpcXFxuICAgICEqKiogLi9saWJyYXJpZXMvcHJ4LWhlbHBlcnMvcHJ4LWhlbHBlcnMuanMgKioqIVxuICAgIFxcKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuICAvKiEgZXhwb3J0cyBwcm92aWRlZDogbGVycCwgb3V0ZXJXaWR0aCwgcm91bmQsIGlzVG91Y2hEZXZpY2UgKi9cblxuICAvKioqL1xuICBmdW5jdGlvbiBsaWJyYXJpZXNQcnhIZWxwZXJzUHJ4SGVscGVyc0pzKG1vZHVsZSwgX193ZWJwYWNrX2V4cG9ydHNfXywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgZXZhbChcIl9fd2VicGFja19yZXF1aXJlX18ucihfX3dlYnBhY2tfZXhwb3J0c19fKTtcXG4vKiBoYXJtb255IGV4cG9ydCAoYmluZGluZykgKi8gX193ZWJwYWNrX3JlcXVpcmVfXy5kKF9fd2VicGFja19leHBvcnRzX18sIFxcXCJsZXJwXFxcIiwgZnVuY3Rpb24oKSB7IHJldHVybiBsZXJwOyB9KTtcXG4vKiBoYXJtb255IGV4cG9ydCAoYmluZGluZykgKi8gX193ZWJwYWNrX3JlcXVpcmVfXy5kKF9fd2VicGFja19leHBvcnRzX18sIFxcXCJvdXRlcldpZHRoXFxcIiwgZnVuY3Rpb24oKSB7IHJldHVybiBvdXRlcldpZHRoOyB9KTtcXG4vKiBoYXJtb255IGV4cG9ydCAoYmluZGluZykgKi8gX193ZWJwYWNrX3JlcXVpcmVfXy5kKF9fd2VicGFja19leHBvcnRzX18sIFxcXCJyb3VuZFxcXCIsIGZ1bmN0aW9uKCkgeyByZXR1cm4gcm91bmQ7IH0pO1xcbi8qIGhhcm1vbnkgZXhwb3J0IChiaW5kaW5nKSAqLyBfX3dlYnBhY2tfcmVxdWlyZV9fLmQoX193ZWJwYWNrX2V4cG9ydHNfXywgXFxcImlzVG91Y2hEZXZpY2VcXFwiLCBmdW5jdGlvbigpIHsgcmV0dXJuIGlzVG91Y2hEZXZpY2U7IH0pO1xcbi8qKlxcclxcbiAqIFV0aWxpdHkgZnVuY3Rpb24gdG8gbGluZWFyIGludGVycG9sYXRlIHZhbHVlcy5cXHJcXG4gKlxcclxcbiAqIEBwYXJhbSB7bnVtYmVyfSBzdGFydCAtIFZhbHVlIHRvIGxlcnAuXFxyXFxuICogQHBhcmFtIHtudW1iZXJ9IGVuZCAtIFRhcmdldCB2YWx1ZS5cXHJcXG4gKiBAcGFyYW0ge251bWJlcn0gYW1vdW50IC0gRWFzaW5nLlxcclxcbiAqXFxyXFxuICogQHJldHVybnMge251bWJlcn0gTGVycGVkIHZhbHVlLlxcclxcbiAqL1xcclxcbmZ1bmN0aW9uIGxlcnAoc3RhcnQsIGVuZCwgYW10KSB7XFxyXFxuXFx0cmV0dXJuICgxIC0gYW10KSAqIHN0YXJ0ICsgYW10ICogZW5kO1xcclxcbn1cXHJcXG5cXHJcXG4vKipcXHJcXG4gKiBVdGlsaXR5IGZ1bmN0aW9uIHRvIGdldCB3aWR0aCB3aXRoIG1hcmdpbnMgaW5jbHVkZWQuXFxyXFxuICpcXHJcXG4gKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBlbCAtIEVsZW1lbnQgeW91IHdhbnQgdG8gY2FsY3VsYXRlIHRoZSBvdXRlciB3aWR0aCBvZi5cXHJcXG4gKlxcclxcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0gVGhlIGVsZW1lbnQncyBvdXRlciB3aXRoLlxcclxcbiAqL1xcclxcbmZ1bmN0aW9uIG91dGVyV2lkdGgoZWwpIHtcXHJcXG5cXHR2YXIgd2lkdGggPSBlbC5vZmZzZXRXaWR0aDtcXHJcXG5cXHR2YXIgc3R5bGUgPSBnZXRDb21wdXRlZFN0eWxlKGVsKTtcXHJcXG5cXHJcXG5cXHR3aWR0aCArPSBwYXJzZUludChzdHlsZS5tYXJnaW5MZWZ0KSArIHBhcnNlSW50KHN0eWxlLm1hcmdpblJpZ2h0KTtcXHJcXG5cXHRyZXR1cm4gd2lkdGg7XFxyXFxufVxcclxcblxcclxcbi8qKlxcclxcbiAqIFNob3J0Y3V0IGZvciByb3VuZGluZyBudW1iZXIgdG8gc2Vjb25kIGRlY2ltYWwgcGxhY2UuXFxyXFxuICpcXHJcXG4gKiBAcGFyYW0ge251bWJlcn0gbnVtZXIgLSBOdW1iZXIgdG8gcm91bmQuXFxyXFxuICpcXHJcXG4gKiBAcmV0dXJucyB7bnVtYmVyfSAtIFJvdW5kZWQgbnVtYmVyIHRvIHNlY29uZCBkZWNpbWFsIHBsYWNlLlxcclxcbiAqL1xcclxcbmZ1bmN0aW9uIHJvdW5kKG51bWJlcikge1xcclxcblxcdHJldHVybi
2BNYXRoLnJvdW5kKChudW1iZXIgKyBOdW1iZXIuRVBTSUxPTikgKiAxMDApIC8gMTAwO1xcclxcbn1cXHJcXG5cXHJcXG4vKipcXHJcXG4gKiBVdGlsaXR5IGZ1bmN0aW9uIHRvIGNoZWNrIG9mIHRoZSBkZXZpY2UgaXMgYSB0b3VjaCBkZXZpY2UuXFxyXFxuICpcXHJcXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBJZiBkZXZpY2UgaXMgYSB0b3VjaCBkZXZpY2Ugb3Igbm90LlxcclxcbiAqL1xcclxcbmZ1bmN0aW9uIGlzVG91Y2hEZXZpY2UoKSB7XFxyXFxuXFx0cmV0dXJuIFxcXCJvbnRvdWNoc3RhcnRcXFwiIGluIHdpbmRvdyB8fCBuYXZpZ2F0b3IubWF4VG91Y2hQb2ludHMgPiAwIHx8IG5hdmlnYXRvci5tc01heFRvdWNoUG9pbnRzID4gMDtcXHJcXG59XFxyXFxuXFxuXFxuLy8jIHNvdXJjZVVSTD13ZWJwYWNrOi8vLy4vbGlicmFyaWVzL3ByeC1oZWxwZXJzL3ByeC1oZWxwZXJzLmpzP1wiKTtcbiAgICAvKioqL1xuICB9LFxuXG4gIC8qKiovXG4gIFwiLi9saWJyYXJpZXMvcHJ4LW1hcnF1ZWUvcHJ4LW1hcnF1ZWUuanNcIjpcbiAgLyohKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiEqXFxcbiAgICAhKioqIC4vbGlicmFyaWVzL3ByeC1tYXJxdWVlL3ByeC1tYXJxdWVlLmpzICoqKiFcbiAgICBcXCoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbiAgLyohIGV4cG9ydHMgcHJvdmlkZWQ6IFByeE1hcnF1ZWUgKi9cblxuICAvKioqL1xuICBmdW5jdGlvbiBsaWJyYXJpZXNQcnhNYXJxdWVlUHJ4TWFycXVlZUpzKG1vZHVsZSwgX193ZWJwYWNrX2V4cG9ydHNfXywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgZXZhbChcIl9fd2VicGFja19yZXF1aXJlX18ucihfX3dlYnBhY2tfZXhwb3J0c19fKTtcXG4vKiBoYXJtb255IGV4cG9ydCAoYmluZGluZykgKi8gX193ZWJwYWNrX3JlcXVpcmVfXy5kKF9fd2VicGFja19leHBvcnRzX18sIFxcXCJQcnhNYXJxdWVlXFxcIiwgZnVuY3Rpb24oKSB7IHJldHVybiBQcnhNYXJxdWVlOyB9KTtcXG4vKiBoYXJtb255IGltcG9ydCAqLyB2YXIgX3ByeF9oZWxwZXJzX3ByeF9oZWxwZXJzX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8wX18gPSBfX3dlYnBhY2tfcmVxdWlyZV9fKC8qISAuLi9wcngtaGVscGVycy9wcngtaGVscGVycyAqLyBcXFwiLi9saWJyYXJpZXMvcHJ4LWhlbHBlcnMvcHJ4LWhlbHBlcnMuanNcXFwiKTtcXG4vKipcXHJcXG4gKiBCYXNpYyBtYXJxdWVlIHdpdGggbW91c2Ugd2hlZWwgYWNjZWxlcmF0aW9uLlxcclxcbiAqXFxyXFxuICogQGxpbmsgaHR0cHM6Ly9sZXNwcngubW9uZGF5LmNvbS9kb2NzLzQ4MjI3ODg0MzdcXHJcXG4gKiBAYXV0aG9yIExlcyBQcsOpdGVudGlldXhcXHJcXG4gKiBAdmVyc2lvbiAxLjAuMVxcclxcbiAqXFxyXFxuICogKi9cXHJcXG5cXHJcXG5cXHJcXG5cXHJcXG5cXHJcXG5cXHJcXG5jbGFzcyBQcnhNYXJxdWVlIHtcXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBJbml0IG91ciBjbGFzcy5cXHJcXG5cXHQgKi9cXHJcXG5cXHRjb25zdHJ1Y3RvcigpIHtcXHJcXG5cXHRcXHR0aGlzLmVhc2luZyA9IDAuMDQ7XFxyXFxuXFxyXFxuXFx0XFx0dGhpcy5kZWZhdWx0U3BlZWQgPSAxO1xcclxcblxcdFxcdHRoaXMuZGVmYXVsdFNjcm9sbEFjY2VsZXJhdGlvbiA9IDAuMTtcXHJcXG5cXHJcXG5cXHRcXHR0aGlzLnNjcm9sbFNwZWVkID0gMDtcXHJcXG5cXHJcXG5cXHRcXHQvLyBTdG9yZSBvdXIgbWFycXVlZSB2YWx1ZXNcXHJcXG5cXHRcXHR0aGlzLnByeE1hcnF1ZWUgPSB7fTtcXHJcXG5cXHJcXG5cXHRcXHR0aGlzLm1hcnF1ZWVFbGVtcyA9IFtdO1xcclxcblxcclxcblxcdFxcdC8vIEFkZCBvdXIgZXZlbnQgbGlzdGVuZXJzXFxyXFxuXFx0XFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoXFxcIndoZWVsXFxcIiwgKGV2ZW50KSA9PiB0aGlzLndoZWVsRXZlbnQoZXZlbnQpLCB7IHBhc3NpdmU6IHRydWUgfSk7XFxyXFxuXFx0XFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoXFxcInJlc2l6ZVxcXCIsICgpID0+IHRoaXMucmVmcmVzaCgpLCB7IHBhc3NpdmU6IHRydWUgfSk7XFxyXFxuXFxyXFxuXFx0XFx0dGhpcy5pbml0KCk7XFxyXFxuXFx0fVxcclxcblxcclxcblxcdC8qKlxcclxcblxcdCAqIFVwZGF0ZSBzY3JvbGwgc3BlZWQgb24gbW91c2Ugd2hlZWwgaW5wdXQuXFxyXFxuXFx0ICpcXHJcXG5cXHQgKiBAcGFyYW0ge29iamVjdH0gZXZlbnQgLSBUaGUgd2hlZWwgZXZlbnQuXFxyXFxuXFx0ICovXFxyXFxuXFx0d2hlZWxFdmVudChldmVudCkge1xcclxcblxcdFxcdHRoaXMuc2Nyb2xsU3BlZWQgPSBNYXRoLmFicyhldmVudC5kZWx0YVkpO1xcclxcblxcdH1cXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBJbml0aWFsaXplIG1hcnF1ZWVzLlxcclxcblxcdCAqL1xcclxcblxcdGluaXQoKSB7XFxyXFxuXFx0XFx0d2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSA9IHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUgfHwgd2luZG93Lm1velJlcXVlc3RBbmltYXRpb25GcmFtZSB8fCB3aW5kb3cud2Via2l0UmVxdWVzdEFuaW1hdGlvbkZyYW1lIHx8IHdpbmRvdy5tc1JlcXVlc3RBbmltYXRpb25GcmFtZTtcXHJcXG5cXHJcXG5cXHRcXHR0aGlzLnJlZnJlc2goKTtcXHJcXG5cXHJcXG5cXHRcXHRyZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4gdGhpcy50aWNrKCkpO1xcclxcblxcdH1cXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBVcGRhdGUgb3VyIG1hcnF1ZWUgcmVsYXRlZCBlbGVtZW50cy5cXHJcXG5cXHQgKi9cXHJcXG5cXHRyZWZyZXNoKCkge1xcclxcblxcdFxcdC8vIEdldCBhbGwgb3VyIGVsZW1lbnRzXFxyXFxuXFx0XFx0dGhpcy5tYXJxdWVlRWxlbXMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKFxcXCJbZGF0YS1tYXJxdWVlXVxcXCIpO1xcclxcblxcclxcblxcdFxcdHRoaXMubWFycXVlZUVsZW1zLmZvckVhY2goKG1hcnF1ZWVFbGVtKSA9PiB7XFxyXFxuXFx0XFx0XFx0Ly8gU2V0IGRlZmF1bHRzXFxyXFxuXFx0XFx0XFx0dmFyIGRpcmVjdGlvbiA9IG1hcnF1ZWVFbGVtLmRhdGFzZXQuZGlyZWN0aW9uO1xcclxcblxcdFxcdFxcdHZhciBzcGVlZCA9IG1hcnF1ZWVFbGVtLmRhdGFzZXQuc3BlZWQ7XFxyXFxuXFx0XFx0XFx0dmFyIHNjcm9sbEFjY2VsZXJhdGlvbiA9IG1hcnF1ZWVFbGVtLmRhdGFzZXQuc2Nyb2xsQWNjZWxlcmF0aW9uO1xcclxcblxcclxcblxcdFxcdFxcdGRpcmVjdGlvbiA9IGRpcmVjdGlvbiA/IGRpcmVjdGlvbiA6IFxcXCJmb3J3YXJkc1xcXCI7XFxyXFxuXFx0XFx0XFx0c3BlZWQgPSBzcGVlZCA/IHNwZWVkIDogdGhpcy5kZWZh
2dWx0U3BlZWQ7XFxyXFxuXFx0XFx0XFx0c2Nyb2xsQWNjZWxlcmF0aW9uID0gc2Nyb2xsQWNjZWxlcmF0aW9uID8gc2Nyb2xsQWNjZWxlcmF0aW9uIDogdGhpcy5kZWZhdWx0U2Nyb2xsQWNjZWxlcmF0aW9uO1xcclxcblxcclxcblxcdFxcdFxcdC8vIENyZWF0ZSB0aGUgYXBwcm9wcmlhdGUgYW1vdW50IG9mIGNvbnRlbnQgZHVwbGljYXRlc1xcclxcblxcdFxcdFxcdHZhciBjbG9uZWRDb250ZW50RWxlbXMgPSBtYXJxdWVlRWxlbS5xdWVyeVNlbGVjdG9yQWxsKFxcXCIuYy1tYXJxdWVlX2NvbnRlbnQuaXMtY2xvbmVcXFwiKTtcXHJcXG5cXHJcXG5cXHRcXHRcXHR2YXIgd3JhcHBlckVsID0gbWFycXVlZUVsZW0ucXVlcnlTZWxlY3RvcihcXFwiLmMtbWFycXVlZV93cmFwcGVyXFxcIik7XFxyXFxuXFx0XFx0XFx0dmFyIGNvbnRlbnRFbCA9IG1hcnF1ZWVFbGVtLnF1ZXJ5U2VsZWN0b3IoXFxcIi5jLW1hcnF1ZWVfY29udGVudFxcXCIpO1xcclxcblxcclxcblxcdFxcdFxcdGNsb25lZENvbnRlbnRFbGVtcy5mb3JFYWNoKChjbG9uZWRDb250ZW50RWxlbSkgPT4ge1xcclxcblxcdFxcdFxcdFxcdGNsb25lZENvbnRlbnRFbGVtLnJlbW92ZSgpO1xcclxcblxcdFxcdFxcdH0pO1xcclxcblxcclxcblxcdFxcdFxcdHZhciBtYXJxdWVlV2lkdGggPSBPYmplY3QoX3ByeF9oZWxwZXJzX3ByeF9oZWxwZXJzX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8wX19bXFxcIm91dGVyV2lkdGhcXFwiXSkobWFycXVlZUVsZW0pO1xcclxcblxcdFxcdFxcdHZhciB3cmFwcGVyV2lkdGggPSBPYmplY3QoX3ByeF9oZWxwZXJzX3ByeF9oZWxwZXJzX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8wX19bXFxcIm91dGVyV2lkdGhcXFwiXSkod3JhcHBlckVsKTtcXHJcXG5cXHJcXG5cXHRcXHRcXHRpZiAod3JhcHBlcldpZHRoID4gMCkge1xcclxcblxcdFxcdFxcdFxcdHZhciBkaWZmID0gbWFycXVlZVdpZHRoIC8gd3JhcHBlcldpZHRoO1xcclxcblxcdFxcdFxcdFxcdHZhciBkdXBsaWNhdGlvbnMgPSBNYXRoLmNlaWwoZGlmZiArIDEpO1xcclxcblxcclxcblxcdFxcdFxcdFxcdGZvciAodmFyIHggPSAwOyB4IDwgZHVwbGljYXRpb25zOyB4KyspIHtcXHJcXG5cXHRcXHRcXHRcXHRcXHR2YXIgY2xvbmUgPSB3cmFwcGVyRWwuYXBwZW5kQ2hpbGQoY29udGVudEVsLmNsb25lTm9kZSh0cnVlKSk7XFxyXFxuXFx0XFx0XFx0XFx0XFx0Y2xvbmUuY2xhc3NMaXN0LmFkZChcXFwiaXMtY2xvbmVcXFwiKTtcXHJcXG5cXHRcXHRcXHRcXHR9XFxyXFxuXFx0XFx0XFx0fVxcclxcblxcclxcblxcdFxcdFxcdC8vIFN0b3JlIG91ciBtYXJxdWVlIG9iamVjdCB2YWx1ZXMgaW4gdGhlIG5vZGVcXHJcXG5cXHRcXHRcXHR0aGlzLnByeE1hcnF1ZWUgPSB7XFxyXFxuXFx0XFx0XFx0XFx0ZGlyZWN0aW9uOiBkaXJlY3Rpb24sXFxyXFxuXFx0XFx0XFx0XFx0c3BlZWQ6IHNwZWVkLFxcclxcblxcdFxcdFxcdFxcdHNjcm9sbEFjY2VsZXJhdGlvbjogc2Nyb2xsQWNjZWxlcmF0aW9uLFxcclxcblxcdFxcdFxcdFxcdHRyYW5zZm9ybTogZGlyZWN0aW9uID09IFxcXCJyZXZlcnNlXFxcIiA/IC13cmFwcGVyV2lkdGggOiAwLFxcclxcblxcdFxcdFxcdH07XFxyXFxuXFxyXFxuXFx0XFx0XFx0bWFycXVlZUVsZW0gPSBPYmplY3QuYXNzaWduKG1hcnF1ZWVFbGVtLCB0aGlzLnByeE1hcnF1ZWUpO1xcclxcblxcdFxcdH0pO1xcclxcblxcdH1cXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBUaWNrIDYwIHRpbWVzIHBlciBzZWNvbmQgd2l0aCByZXF1ZXN0QW5pbWF0aW9uRnJhbWUuXFxyXFxuXFx0ICovXFxyXFxuXFx0dGljaygpIHtcXHJcXG5cXHRcXHQvLyBUb2RvOiBpZiBpbiB2aWV3XFxyXFxuXFx0XFx0dGhpcy5yZW5kZXIoKTtcXHJcXG5cXHJcXG5cXHRcXHRyZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4gdGhpcy50aWNrKCkpO1xcclxcblxcdH1cXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBSZW5kZXIvYW5pbWF0ZSBvdXIgbWFycXVlZS5cXHJcXG5cXHQgKi9cXHJcXG5cXHRyZW5kZXIoKSB7XFxyXFxuXFx0XFx0Ly8gR2V0IHNtb290aGVkIG91dCBzY3JvbGwgc3BlZWQgb2Zmc2V0XFxyXFxuXFx0XFx0dGhpcy5zY3JvbGxTcGVlZCA9IE9iamVjdChfcHJ4X2hlbHBlcnNfcHJ4X2hlbHBlcnNfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzBfX1tcXFwicm91bmRcXFwiXSkodGhpcy5zY3JvbGxTcGVlZCk7XFxyXFxuXFx0XFx0dGhpcy5zY3JvbGxTcGVlZCA9IE9iamVjdChfcHJ4X2hlbHBlcnNfcHJ4X2hlbHBlcnNfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzBfX1tcXFwibGVycFxcXCJdKSh0aGlzLnNjcm9sbFNwZWVkLCAwLCAwLjA0KTtcXHJcXG5cXHJcXG5cXHRcXHR0aGlzLm1hcnF1ZWVFbGVtcy5mb3JFYWNoKChtYXJxdWVlRWxlbSkgPT4ge1xcclxcblxcdFxcdFxcdHZhciBkaXJlY3Rpb24gPSBtYXJxdWVlRWxlbS5kaXJlY3Rpb247XFxyXFxuXFx0XFx0XFx0dmFyIHNwZWVkID0gbWFycXVlZUVsZW0uc3BlZWQ7XFxyXFxuXFx0XFx0XFx0dmFyIHNjcm9sbEFjY2VsZXJhdGlvbiA9IG1hcnF1ZWVFbGVtLnNjcm9sbEFjY2VsZXJhdGlvbjtcXHJcXG5cXHJcXG5cXHRcXHRcXHR2YXIgd3JhcHBlckVsID0gbWFycXVlZUVsZW0ucXVlcnlTZWxlY3RvcihcXFwiLmMtbWFycXVlZV93cmFwcGVyXFxcIik7XFxyXFxuXFx0XFx0XFx0dmFyIGNvbnRlbnRFbCA9IG1hcnF1ZWVFbGVtLnF1ZXJ5U2VsZWN0b3IoXFxcIi5jLW1hcnF1ZWVfY29udGVudFxcXCIpO1xcclxcblxcclxcblxcdFxcdFxcdHZhciB0cmFuc2Zvcm1YID0gbWFycXVlZUVsZW0udHJhbnNmb3JtO1xcclxcblxcclxcblxcdFxcdFxcdGlmIChkaXJlY3Rpb24gPT0gXFxcInJldmVyc2VcXFwiKSB7XFxyXFxuXFx0XFx0XFx0XFx0aWYgKHRyYW5zZm9ybVggPiAwKSB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0dHJhbnNmb3JtWCA9IC1PYmplY3QoX3ByeF9oZWxwZXJzX3ByeF9oZWxwZXJzX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8wX19bXFxcIm91dGVyV2lkdGhcXFwiXSkoY29udGVudEVsKTtcXHJcXG5cXHRcXHRcXHRcXHR9XFxyXFxuXFx0XFx0XFx0XFx0dHJhbnNmb3JtWCA9IHRyYW5zZm9ybVggKyAoc3BlZWQgKiAyICsgdGhpcy5zY3JvbGxTcGVlZCAqIHNjcm9sbEFjY2VsZXJhdGlvbik7XFxyXFxuXFx0XFx0XFx0fSBlbHNlIHtcXHJcXG5cXHRcXHRcXHRcXHRpZiAoLXRyYW5zZm9ybVggPiBPYmplY3QoX3ByeF9oZWxwZXJzX3ByeF9oZWxwZXJzX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8wX19bXFxcIm91dGVyV2lkdGhcXFwiXSkoY29udGVudEVsKSkge1xcclxcblxcdFxcdFxcdFxcdFxcdHRyYW5zZm9ybVggPSAwO1xcclxcblxcdFxcdFxcdFxcdH1cXHJcXG5cXHRcXHRcXHRcXHR0cmFuc2Zvcm1YID0gdHJhbnNmb3JtWCAtIChzcGVlZCAqIDIgKyB0aGlzLnNjcm9sbFNwZWVkICogc2Nyb2xsQWNjZWxlcmF0aW9uKTtcXHJcXG5cXHRcXHRcXHR9XFxyXFxuXFxyXFxuXFx0XFx0XFx0dHJhbnNmb3JtWCA9IE9iamVjdChfcHJ4X2hlbHBlcnNfcHJ4X2hlbHBlcnNfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzBfX1tcXFwicm91bmRcXFwiXSkodHJhbnNmb3JtWCk7XFxyXFxuXFxyXFxuXFx0XFx0XFx0bWFycXVlZUVsZW0udHJhbnNmb3JtID0gdHJhbnNmb3JtWDtcXHJcXG5cXHJcXG5cXHRcXHRcXHR3cmFwcGVyRWwuc3R5bGUudHJhbnNmb3JtID0gXFxcInRyYW5zbGF0ZTNkKFxcXCIgKyB0cmFuc2Zvcm1YICsgXFxcInB4LCAwLCAwKVxcXCI7XFxyXFxuXFx0XFx0fSk7XFxyXFxuXFx0fVxcclxcbn1cXHJcXG5cXG5cXG4vLyMgc291cmNlVVJMPXdlYnBhY2s6Ly8vLi9saWJyYXJpZXMvcHJ4LW1hcnF1ZWUvcHJ4LW1hcnF1ZWUuanM/XCIpO1xuICAgIC8qKiovXG4gIH0sXG5cbiAgLyoqKi9cbiAgXCIuL2xpYnJhcmllcy9wcngtc2Nyb2xsL3ByeC1zY3JvbGwuanNcIjpcbiAgLyohKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiohKlxcXG4gICAgISoqKiAuL2xpYnJhcmllcy9wcngtc2Nyb2xsL3ByeC1zY3JvbGwuanMgKioqIVxuICAgIFxcKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbiAgLyohIGV4cG9ydHMgcHJvdmlkZWQ6IFByeFNjcm9sbCAqL1xuXG4gIC8qKiovXG4gIGZ1bmN0aW9uIGxpYnJhcmllc1ByeFNjcm9sbFByeFNjcm9sbEpzKG1vZHVsZSwgX193ZWJwYWNrX2V4cG9ydHNfXywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgZXZhbChcIl9fd2VicGFja19yZXF1aXJlX18ucihfX3dlYnBhY2tfZXhwb3J0c19fKTtcXG4vKiBoYXJtb255IGV4cG9ydCAoYmluZGluZykgKi8gX193ZWJwYWNrX3JlcXVpcmVfXy5kKF9fd2VicGFja19leHBvcnRzX18sIFxcXCJQcnhTY3JvbGxcXFwiLCBmdW5jdGlvbigpIHsgcmV0dXJuIFByeFNjcm9sbDsgfSk7XFxuLyogaGFybW9ueSBpbXBvcnQgKi8gdmFyIF9wcnhfaGVscGVyc19wcnhfaGVscGVyc19fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMF9fID0gX193ZWJwYWNrX3JlcXVpcmVfXygvKiEgLi4vcHJ4LWhlbHBlcnMvcHJ4LWhlbHBlcnMgKi8gXFxcIi4vbGlicmFyaWVzL3ByeC1oZWxwZXJzL3ByeC1oZWxwZXJzLmpzXFxcIik7XFxuLyoqXFxyXFxuICogTmF0aXZlIHNtb290aCBzY3JvbGwsIGRldGVjdGlvbiBvZiBlbGVtZW50cyBpbiB0aGUgdmlld3BvcnQgYW5kIHBhcmFsbGF4IGVmZmVjdHMuXFxyXFxuICpcXHJcXG4gKiBAbGluayBodHRwczovL2xlc3ByeC5tb25kYXkuY29tL2RvY3MvNDgyMjc4NzMwNVxcclxcbiAqIEBhdXRob3IgTGVzIFByw6l0ZW50aWV1eFxcclxcbiAqIEB2ZXJzaW9uIDEuMC4zXFxyXFxuICpcXHJcXG4gKiAqL1xcclxcblxcclxcblxcclxcblxcclxcblxcclxcblxcclxcbmNsYXNzIFByeFNjcm9sbCB7XFxyXFxuXFx0LyoqXFxyXFxuXFx0ICogSW5pdCBvdXIgY2xhc3MuXFxyXFxuXFx0ICpcXHJcXG5cXHQgKiBAcGFyYW0ge29iamVjdH0gW29wdGlvbnNdIC0gUHJ4U2Nyb2xsIG9wdGlvbnMuXFxyXFxuXFx0ICogQHBhcmFtIHtudW1iZXJ9IFtvcHRpb25zLmxlcnA9MC4xXSAtIEVhc2luZyB2YWx1ZS
25cXHJcXG5cXHQgKiBAcGFyYW0ge251bWJlcn0gW29wdGlvbnMuYW5jaG9yT2Zmc2V0PTBdIC0gT2Zmc2V0IHRvIHRoZSBhbmNob3IgdGFyZ2V0IGluIHBpeGVscy5cXHJcXG5cXHQgKiBAcGFyYW0ge251bWJlcn0gW29wdGlvbnMuaG9yaXpvbnRhbFNjcm9sbEJyZWFrcG9pbnQ9MTIwMV0gLSBCcmVha3BvaW50IGF0IHdoaWNoIHRoZSBob3Jpem9udGFsIHNjcm9sbCBpcyBkaXNhYmxlZC5cXHJcXG5cXHQgKi9cXHJcXG5cXHRjb25zdHJ1Y3Rvcih7IGxlcnAgPSAwLjEsIGFuY2hvck9mZnNldCA9IDAsIGhvcml6b250YWxTY3JvbGxCcmVha3BvaW50ID0gMTIwMSB9ID0ge30pIHtcXHJcXG5cXHRcXHQvLyBTZXQgb3VyIGNvbnN0cnVjdG9yIG9wdGlvbnNcXHJcXG5cXHRcXHR0aGlzLmVhc2luZyA9IGxlcnA7XFxyXFxuXFx0XFx0dGhpcy5hbmNob3JPZmZzZXQgPSBhbmNob3JPZmZzZXQ7XFxyXFxuXFx0XFx0dGhpcy5ob3Jpem9udGFsU2Nyb2xsQnJlYWtwb2ludCA9IGhvcml6b250YWxTY3JvbGxCcmVha3BvaW50O1xcclxcblxcclxcblxcdFxcdC8vIFN0b3JlcyB0aGUgc2Nyb2xsIHZhbHVlc1xcclxcblxcdFxcdHRoaXMuc2Nyb2xsID0ge307XFxyXFxuXFxyXFxuXFx0XFx0Ly8gU3RvcmVzIHRoZSBzY3JvbGwgaW5lcnRpYSB2YWx1ZXNcXHJcXG5cXHRcXHR0aGlzLmluZXJ0aWEgPSB7XFxyXFxuXFx0XFx0XFx0Y3VycmVudDogMCxcXHJcXG5cXHRcXHRcXHR0YXJnZXQ6IDAsXFxyXFxuXFx0XFx0fTtcXHJcXG5cXHJcXG5cXHRcXHQvLyBHbG9iYWwgc3RhdGUgdmFyaWFibGVzXFxyXFxuXFx0XFx0dGhpcy5pc1RvdWNoID0gZmFsc2U7XFxyXFxuXFx0XFx0dGhpcy5pc0hvcml6b250YWxTY3JvbGxBY3RpdmUgPSBmYWxzZTtcXHJcXG5cXHJcXG5cXHRcXHQvLyBTdG9yZSBhbGwgb3VyIHNjcm9sbCBlbGVtZW50c1xcclxcblxcdFxcdHRoaXMuaW5WaWV3RWxlbXMgPSBbXTtcXHJcXG5cXHRcXHR0aGlzLnBhcmFsbGF4RWxlbXMgPSBbXTtcXHJcXG5cXHRcXHR0aGlzLmFuY2hvckVsZW1zID0gW107XFxyXFxuXFx0XFx0dGhpcy5ob3Jpem9udGFsU2Nyb2xsU2VjdGlvbnMgPSBbXTtcXHJcXG5cXHRcXHR0aGlzLnByb2dyZXNzRWxlbXMgPSBbXTtcXHJcXG5cXHRcXHR0aGlzLmluZXJ0aWFFbGVtcyA9IFtdO1xcclxcblxcclxcblxcdFxcdC8vIEFkZCBvdXIgZXZlbnQgbGlzdGVuZXJzXFxyXFxuXFx0XFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoXFxcIndoZWVsXFxcIiwgKGV2ZW50KSA9PiB0aGlzLndoZWVsRXZlbnQoZXZlbnQpLCB7IHBhc3NpdmU6IGZhbHNlIH0pO1xcclxcblxcdFxcdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFxcXCJzY3JvbGxcXFwiLCAoKSA9PiB0aGlzLnNjcm9sbEV2ZW50KCksIHsgcGFzc2l2ZTogdHJ1ZSB9KTtcXHJcXG5cXHRcXHR3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcXFwicmVzaXplXFxcIiwgKCkgPT4gdGhpcy5yZXNpemVFdmVudCgpLCB7IHBhc3NpdmU6IHRydWUgfSk7XFxyXFxuXFxyXFxuXFx0XFx0dGhpcy5pbml0KCk7XFxyXFxuXFx0fVxcclxcblxcclxcblxcdC8qKlxcclxcblxcdCAqIEluaXRpYWxpemUgc21vb3RoIHNjcm9sbCBhbmQgYWRkIGV2ZW50cy5cXHJcXG5cXHQgKi9cXHJcXG5cXHRpbml0KCkge1xcclxcblxcdFxcdHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUgPSB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lIHx8IHdpbmRvdy5tb3pSZXF1ZXN0QW5pbWF0aW9uRnJhbWUgfHwgd2luZG93LndlYmtpdFJlcXVlc3RBbmltYXRpb25GcmFtZSB8fCB3aW5kb3cubXNSZXF1ZXN0QW5pbWF0aW9uRnJhbWU7XFxyXFxuXFxyXFxuXFx0XFx0Ly8gU2V0IG91cnMgc2Nyb2xsIHZhbHVlcyB0byB0aGUgY3VycmVudCBzY3JvbGwgdmFsdWVcXHJcXG5cXHRcXHR0aGlzLnN5bmNQb3MoKTtcXHJcXG5cXHJcXG5cXHRcXHQvLyBDaGVjayBpZiBkZXZpY2UgaXMgdG91Y2hcXHJcXG5cXHRcXHRpZiAoT2JqZWN0KF9wcnhfaGVscGVyc19wcnhfaGVscGVyc19fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMF9fW1xcXCJpc1RvdWNoRGV2aWNlXFxcIl0pKCkpIHtcXHJcXG5cXHRcXHRcXHR0aGlzLmlzVG91Y2ggPSB0cnVlO1xcclxcblxcdFxcdH1cXHJcXG5cXHJcXG5cXHRcXHQvLyBJZiBkZXZpY2UgaXMgbm90IHRvdWNoLCBpbml0aWFsaXplIHNtb290aCBzY3JvbGxcXHJcXG5cXHRcXHRpZiAoIXRoaXMuaXNUb3VjaCkge1xcclxcblxcdFxcdFxcdHJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB0aGlzLnRpY2soKSk7XFxyXFxuXFx0XFx0XFx0ZG9jdW1lbnQucXVlcnlTZWxlY3RvcihcXFwiaHRtbFxcXCIpLmNsYXNzTGlzdC5hZGQoXFxcImlzLXNtb290aC1zY3JvbGxcXFwiKTtcXHJcXG5cXHRcXHR9XFxyXFxuXFxyXFxuXFx0XFx0Ly8gQ2hlY2sgaWYgaG9yaXpvbn
2RhbCBzY3JvbGxcXHJcXG5cXHRcXHR0aGlzLmlzSG9yaXpvbnRhbFNjcm9sbEFjdGl2ZSA9IHdpbmRvdy5tYXRjaE1lZGlhKFxcXCIobWluLXdpZHRoOiBcXFwiICsgdGhpcy5ob3Jpem9udGFsU2Nyb2xsQnJlYWtwb2ludCArIFxcXCJweClcXFwiKS5tYXRjaGVzICYmICF0aGlzLmlzVG91Y2g7XFxyXFxuXFxyXFxuXFx0XFx0Ly8gR2V0IGFsbCBvdXIgZWxlbWVudHNcXHJcXG5cXHRcXHR0aGlzLmdldFNjcm9sbEVsZW1lbnRzKCk7XFxyXFxuXFxyXFxuXFx0XFx0Ly8gVXBkYXRlIHNjcm9sbCBlbGVtZW50c1xcclxcblxcdFxcdHRoaXMudXBkYXRlU2Nyb2xsRWxlbWVudHMoKTtcXHJcXG5cXHJcXG5cXHRcXHQvLyBTZXQgYW5jaG9yIGV2ZW50c1xcclxcblxcdFxcdHRoaXMuc2V0QW5jaG9yRXZlbnRzKCk7XFxyXFxuXFx0fVxcclxcblxcclxcblxcdC8qKlxcclxcblxcdCAqIFVwZGF0ZSBvdXIgc2Nyb2xsIHJlbGF0ZWQgZWxlbWVudHMuXFxyXFxuXFx0ICovXFxyXFxuXFx0cmVmcmVzaCgpIHtcXHJcXG5cXHRcXHQvLyBFbXB0eSBhbGwgZWxlbWVudHNcXHJcXG5cXHRcXHR0aGlzLmNsZWFyU2Nyb2xsRWxlbWVudHMoKTtcXHJcXG5cXHJcXG5cXHRcXHQvLyBHZXQgYWxsIG91ciBlbGVtZW50c1xcclxcblxcdFxcdHRoaXMuZ2V0U2Nyb2xsRWxlbWVudHMoKTtcXHJcXG5cXHJcXG5cXHRcXHQvLyBVcGRhdGUgaW4gdmlldyBhbmQgcGFyYWxsYXggZWxlbWVudHNcXHJcXG5cXHRcXHR0aGlzLnVwZGF0ZVNjcm9sbEVsZW1lbnRzKCk7XFxyXFxuXFxyXFxuXFx0XFx0dGhpcy5zZXRBbmNob3JFdmVudHMoKTtcXHJcXG5cXHR9XFxyXFxuXFxyXFxuXFx0LyoqXFxyXFxuXFx0ICogVXBkYXRlIG91ciBzY3JvbGwgcmVsYXRlZCBldmVudHMgb24gc2Nyb2xsLlxcclxcblxcdCAqL1xcclxcblxcdHNjcm9sbEV2ZW50KCkge1xcclxcblxcdFxcdHRoaXMudXBkYXRlU2Nyb2xsRWxlbWVudHMoKTtcXHJcXG5cXHR9XFxyXFxuXFxyXFxuXFx0LyoqXFxyXFxuXFx0ICogVXBkYXRlIG91ciBzY3JvbGwgcmVsYXRlZCBldmVudHMgb24gcmVzaXplLlxcclxcblxcdCAqL1xcclxcblxcdHJlc2l6ZUV2ZW50KCkge1xcclxcblxcdFxcdHRoaXMudXBkYXRlU2Nyb2xsRWxlbWVudHMoKTtcXHJcXG5cXHR9XFxyXFxuXFxyXFxuXFx0LyoqXFxyXFxuXFx0ICogQ2xlYXIgb3VyIHNjcm9sbCByZWxhdGVkIGVsZW1lbnRzLlxcclxcblxcdCAqL1xcclxcblxcdGNsZWFyU2Nyb2xsRWxlbWVudHMoKSB7XFxyXFxuXFx0XFx0dGhpcy5pblZpZXdFbGVtcyA9IFtdO1xcclxcblxcdFxcdHRoaXMucGFyYWxsYXhFbGVtcyA9IFtdO1xcclxcblxcdFxcdHRoaXMuYW5jaG9yRWxlbXMgPSBbXTtcXHJcXG5cXHRcXHR0aGlzLmhvcml6b250YWxTY3JvbGxTZWN0aW9ucyA9IFtdO1xcclxcblxcdFxcdHRoaXMucHJvZ3Jlc3NFbGVtcyA9IFtdO1xcclxcblxcdFxcdHRoaXMuaW5lcnRpYUVsZW1zID0gW107XFxyXFxuXFx0fVxcclxcblxcclxcblxcdC8qKlxcclxcblxcdCAqIFNldCBvdXIgc2Nyb2xsIHJlbGF0ZWQgZWxlbWVudHMuXFxyXFxuXFx0ICovXFxyXFxuXFx0Z2V0U2Nyb2xsRWxlbWVudHMoKSB7XFxyXFxuXFx0XFx0dGhpcy5pblZpZXdFbGVtcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoXFxcIltkYXRhLXNjcm9sbC1pbi12aWV3XVxcXCIpO1xcclxcblxcdFxcdHRoaXMucGFyYWxsYXhFbGVtcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoXFxcIltkYXRhLXNjcm9sbC1wYXJhbGxheF1cXFwiKTtcXHJcXG5cXHRcXHR0aGlzLmFuY2hvckVsZW1zID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbChcXFwiW2RhdGEtc2Nyb2xsLWFuY2hvcl1cXFwiKTtcXHJcXG5cXHRcXHR0aGlzLmhvcml6b250YWxTY3JvbGxTZWN0aW9ucyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoXFxcIltkYXRhLXNjcm9sbC1ob3Jpem9udGFsXVxcXCIpO1xcclxcblxcdFxcdHRoaXMucHJvZ3Jlc3NFbGVtcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoXFxcIltkYXRhLXNjcm9sbC1wcm9ncmVzc11cXFwiKTtcXHJcXG5cXHRcXHR0aGlzLmluZXJ0aWFFbGVtcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoXFxcIltkYXRhLXNjcm9sbC1pbmVydGlhXVxcXCIpO1xcclxcblxcdH1cXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBVcGRhdGUgb3VyIHNjcm9sbCByZWxhdGVkIGVsZW1lbnRzLlxcclxcblxcdCAqL1xcclxcblxcdHVwZGF0ZVNjcm9sbEVsZW1lbnRzKCkge1xcclxcblxcdFxcdHRoaXMudXBkYXRlSW5WaWV3KCk7XFxyXFxuXFx0XFx0dGhpcy51cGRhdGVQYXJhbGxheCgpO1xcclxcblxcdFxcdHRoaXMudXBkYXRlUHJvZ3Jlc3MoKTtcXHJcXG5cXHJcXG5cXHRcXHRpZiAodGhpcy5pc0hvcml6b250YWxTY3JvbGxBY3RpdmUpIHtcXHJcXG5cXHRcXHRcXHRkb2N1bWVudC5xdWVyeVNlbGVjdG9yKFxcXCJodG1sXFxcIikuY2xhc3NMaXN0LmFkZChcXFwiaXMtaG9yaXpvbnRhbC1zY3JvbGwtYWN0aXZlXFxcIik7XFxyXFxuXFx0XFx0XFx0dGhpcy5pbml0SG9yaXpvbnRhbFNjcm9sbCgpO1xcclxcblxcdFxcdFxcdHRoaXMudXBkYXRlSG9yaXpvbnRhbFNjcm9sbCgpO1xcclxcblxcdFxcdH0gZWxzZSB7XFxyXFxuXFx0XFx0XFx0ZG9jdW1lbnQucXVlcnlTZWxlY3RvcihcXFwiaHRtbFxcXCIpLmNsYXNzTGlzdC5yZW1vdmUoXFxcImlzLWhvcml6b250YWwtc2Nyb2xsLWFjdGl2ZVxcXCIpO1xcclxcblxcdFxcdH1cXHJcXG5cXHJcXG5cXHRcXHR0aGlzLnVwZGF0ZUhvcml6b250YWxTY3JvbGxTdGlja3lFbGVtZW50cygpO1xcclxcblxcdH1cXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBVcGRhdGUgc2Nyb2xsIHRhcmdldCBvbiBtb3VzZSB3aGVlbCBpbnB1dC5cXHJcXG5cXHQgKi9cXHJcXG5cXHR3aGVlbEV2ZW50KGV2ZW50KSB7XFxyXFxuXFx0XFx0dmFyIGhvdmVyZWRFbGVtcyA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoXFxcIjpob3ZlclxcXCIpO1xcclxcblxcdFxcdHZhciBzY3JvbGxhYmxlRWxlbXMgPSAwO1xcclxcblxcclxcblxcdFxcdGhvdmVyZWRFbGVtcy5mb3JFYWNoKChob3ZlcmVkRWxlbSkgPT4ge1xcclxcblxcdFxcdFxcdGlmICh0aGlzLmlzU2Nyb2xsYWJsZShob3ZlcmVkRWxlbSkpIHtcXHJcXG5cXHRcXHRcXHRcXHRzY3JvbGxhYmxlRWxlbXMrKztcXHJcXG5cXHRcXHRcXHR9XFxyXFxuXFx0XFx0fSk7XFxyXFxuXFxyXFxuXFx0XFx0Ly8gVGhpcyBtZWFucyB3ZSdyZSBzY3JvbGxpbmcgaW4gdGhlIGRvY3VtZW50IChzbyBpZiB3ZSB3ZXJlIHRvIHNjcm9sbCBhbnl3aGVyZSBlbHNlLCB0aGUgZGVmYXVsdCBzY3JvbGwgd291bGQgYmUgdGFraW5nIHBsYWNlIGluc3RlYWQpXFxyXFxuXFx0XFx0aWYgKHNjcm9sbGFibGVFbGVtcyA8IDEgJiYgIXRoaXMuaXNUb3VjaCkge1xcclxcblxcdFxcdFxcdGV2ZW50LnByZXZlbn
2REZWZhdWx0KCk7XFxyXFxuXFx0XFx0XFx0dmFyIHNjcm9sbFNwZWVkID0gZXZlbnQuZGVsdGFZO1xcclxcblxcdFxcdFxcdHRoaXMuc2Nyb2xsLnRhcmdldCA9IHRoaXMuY2FwU2Nyb2xsUG9zaXRpb24odGhpcy5zY3JvbGwudGFyZ2V0ICsgc2Nyb2xsU3BlZWQpO1xcclxcblxcdFxcdH1cXHJcXG5cXHR9XFxyXFxuXFxyXFxuXFx0c2V0QW5jaG9yRXZlbnRzKCkge1xcclxcblxcdFxcdHRoaXMuYW5jaG9yRWxlbXMuZm9yRWFjaCgoYW5jaG9yRWxlbSkgPT4ge1xcclxcblxcdFxcdFxcdGFuY2hvckVsZW0uYWRkRXZlbnRMaXN0ZW5lcihcXFwiY2xpY2tcXFwiLCAoZXZlbnQpID0+IHRoaXMuYW5jaG9yQ2xpY2soZXZlbnQsIGFuY2hvckVsZW0pKTtcXHJcXG5cXHRcXHR9KTtcXHJcXG5cXHR9XFxyXFxuXFxyXFxuXFx0LyoqXFxyXFxuXFx0ICogU2Nyb2xsIHRvIHNwZWNpZmllZCBzZWN0aW9uIHdoZW4gdXNlciBjbGlja3Mgb24gYSBzbW9vdGggYW5jaG9yIGxpbmsuXFxyXFxuXFx0ICogQHBhcmFtIHtvYmplY3R9IGV2ZW50IC0gVGhlIGNsaWNrIGV2ZW50LlxcclxcblxcdCAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IGFuY2hvckVsZW0gLSBUaGUgY2xpY2tlZCBhbmNob3IgZWxlbWVudC5cXHJcXG5cXHQgKi9cXHJcXG5cXHRhbmNob3JDbGljayhldmVudCwgYW5jaG9yRWxlbSkge1xcclxcblxcdFxcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XFxyXFxuXFx0XFx0dmFyIGhyZWYgPSBhbmNob3JFbGVtLmdldEF0dHJpYnV0ZShcXFwiaHJlZlxcXCIpO1xcclxcblxcdFxcdHRoaXMuc2Nyb2xsVG8oaHJlZiwgZmFsc2UsIHRoaXMuYW5jaG9yT2Zmc2V0KTtcXHJcXG5cXHR9XFxyXFxuXFxyXFxuXFx0LyoqXFxyXFxuXFx0ICogVGljayA2MCB0aW1lcyBwZXIgc2Vjb25kIHdpdGggcmVxdWVzdEFuaW1hdGlvbkZyYW1lLlxcclxcblxcdCAqL1xcclxcblxcdHRpY2soKSB7XFxyXFxuXFx0XFx0Ly8gT25seSByZW5kZXIgd2hlbiBvdXIgc2Nyb2xsIHBvc2l0aW9uIGlzIGRpZmZlcmVudCBmcm9tIG91ciBzY3JvbGwgdGFyZ2V0ICh3aGVuIG1vdmluZylcXHJcXG5cXHRcXHRpZiAoTWF0aC5yb3VuZCh0aGlzLnNjcm9sbC5wb3MpICE9IE1hdGgucm91bmQodGhpcy5zY3JvbGwudGFyZ2V0KSkge1xcclxcblxcdFxcdFxcdHRoaXMucmVuZGVyKCk7XFxyXFxuXFx0XFx0fSBlbHNlIHtcXHJcXG5cXHRcXHRcXHQvLyBTeW5jIHNjcm9sbCBwb3NpdGlvbiB3aGVuIHVzZXIgc3RvcHMgc2Nyb2xsaW5nXFxyXFxuXFx0XFx0XFx0dGhpcy5zeW5jUG9zKCk7XFxyXFxuXFx0XFx0fVxcclxcblxcclxcblxcdFxcdC8vIFVwZGF0ZSBvdXIgc2Nyb2xsIGludGVydGlhIGluIHRoZSBcXFwidGlja1xcXCIgZnVuY3Rpb24gc28gaXQgY2FuIGtlZXAgZWFzaW5nIGFmdGVyIHRoZSBzY3JvbGwgaGFzIGZpbmlzaGVkXFxyXFxuXFx0XFx0dGhpcy51cGRhdGVTY3JvbGxJbmVydGlhKCk7XFxyXFxuXFxyXFxuXFx0XFx0cmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHRoaXMudGljaygpKTtcXHJcXG5cXHR9XFxyXFxuXFxyXFxuXFx0LyoqXFxyXFxuXFx0ICogUmVuZGVyL2FuaW1hdGUgb3VyIHNjcm9sbFxcclxcblxcdCAqL1xcclxcblxcdHJlbmRlcigpIHtcXHJcXG5cXHRcXHRpZiAoIWRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXFxcImh0bWxcXFwiKS5jbGFzc0xpc3QuY29udGFpbnMoXFxcImlzLWxvY2stc2Nyb2xsXFxcIikpIHtcXHJcXG5cXHRcXHRcXHR0aGlzLnNjcm9sbC5wb3MgPSBPYmplY3QoX3ByeF9oZWxwZXJzX3ByeF9oZWxwZXJzX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8wX19bXFxcInJvdW5kXFxcIl0pKE9iamVjdChfcHJ4X2hlbHBlcnNfcHJ4X2hlbHBlcnNfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzBfX1tcXFwibGVycFxcXCJdKSh0aGlzLnNjcm9sbC5wb3MsIHRoaXMuc2Nyb2xsLnRhcmdldCwgdGhpcy5lYXNpbmcpKTtcXHJcXG5cXHRcXHRcXHR3aW5kb3cuc2Nyb2xsKDAsIHRoaXMuc2Nyb2xsLnBvcyk7XFxyXFxuXFx0XFx0fSBlbHNlIHtcXHJcXG5cXHRcXHRcXHR0aGlzLnN5bmNQb3MoKTtcXHJcXG5cXHRcXHR9XFxyXFxuXFx0fVxcclxcblxcclxcblxcdC8qKlxcclxcblxcdCAqIFNjcm9sbCB0byBhIHNwZWNpZmllZCB0YXJnZXQgb3IgZml4ZWQgcGl4ZWwgdmFsdWUuXFxyXFxuXFx0ICpcXHJcXG5cXHQgKiBAcGFyYW0ge3N0cmluZ3xudW1iZXJ9IHRhcmdldCAtIFNlbGVjdG9yIHRvIHNjcm9sbCB0byBvciBmaXhlZCBwb3NpdGlvbiB0byBzY3JvbGwgdG8gKGluIHBpeGVscykuXFxyXFxuXFx0ICogQHBhcmFtIHtib29sZWFufSBpbnN0YW50IC0gU3BlY2lmeSBpZiB0aGUgdHJhbnNpdGlvbiBpcyBpbnN0YW50IG9yIHNtb290aC5cXHJcXG5cXHQgKi9cXHJcXG5cXHRzY3JvbGxUbyh0YXJnZXQsIGluc3RhbnQgPSBmYWxzZSwgb2Zmc2V0ID0gMCkge1xcclxcblxcdFxcdHZhciBwb3MgPSAwO1xcclxcblxcclxcblxcdFxcdC8vIElmIHRhcmdldCBpcyBub3QgYSBudW1iZXIsIGludGVycHJldCBpdCBhcyBh
2IHF1ZXJ5IHNlbGVjdG9yXFxyXFxuXFx0XFx0aWYgKGlzTmFOKHRhcmdldCkpIHtcXHJcXG5cXHRcXHRcXHQvLyBHZXQgcG9zaXRpb24gb2YgdGFyZ2V0IGVsZW1lbnRcXHJcXG5cXHRcXHRcXHR2YXIgdGFyZ2V0RWwgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRhcmdldCk7XFxyXFxuXFx0XFx0XFx0dmFyIHJlY3QgPSB0YXJnZXRFbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcXHJcXG5cXHRcXHRcXHRwb3MgPSB0aGlzLmNhcFNjcm9sbFBvc2l0aW9uKHJlY3QudG9wICsgd2luZG93LnNjcm9sbFkpO1xcclxcblxcdFxcdH0gZWxzZSB7XFxyXFxuXFx0XFx0XFx0cG9zID0gdGFyZ2V0O1xcclxcblxcdFxcdH1cXHJcXG5cXHJcXG5cXHRcXHRwb3MgPSBPYmplY3QoX3ByeF9oZWxwZXJzX3ByeF9oZWxwZXJzX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8wX19bXFxcInJvdW5kXFxcIl0pKHBvcyAtIG9mZnNldCk7XFxyXFxuXFxyXFxuXFx0XFx0Ly8gSWYgZGV2aWNlIGlzIHRvdWNoLCBzY3JvbGwgdG8gcG9zaXRpb24gaW5zdGFudGx5XFxyXFxuXFx0XFx0aWYgKHRoaXMuaXNUb3VjaCkge1xcclxcblxcdFxcdFxcdHdpbmRvdy5zY3JvbGwoMCwgcG9zKTtcXHJcXG5cXHRcXHR9IGVsc2Uge1xcclxcblxcdFxcdFxcdHRoaXMuc2Nyb2xsLnRhcmdldCA9IHBvcztcXHJcXG5cXHJcXG5cXHRcXHRcXHRpZiAoaW5zdGFudCkge1xcclxcblxcdFxcdFxcdFxcdHRoaXMuc2Nyb2xsLnBvcyA9IHBvcztcXHJcXG5cXHRcXHRcXHR9XFxyXFxuXFx0XFx0fVxcclxcblxcdH1cXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBVcGRhdGUgb3VyIHBhcmFsbGF4IGVsZW1lbnRzJyB2YWx1ZXMuXFxyXFxuXFx0ICovXFxyXFxuXFx0dXBkYXRlUGFyYWxsYXgoKSB7XFxyXFxuXFx0XFx0dGhpcy5wYXJhbGxheEVsZW1zLmZvckVhY2goKHBhcmFsbGF4RWxlbSkgPT4ge1xcclxcblxcdFxcdFxcdHZhciBwYXJhbGxheERpcmVjdGlvbiA9IHBhcmFsbGF4RWxlbS5nZXRBdHRyaWJ1dGUoXFxcImRhdGEtcGFyYWxsYXgtZGlyZWN0aW9uXFxcIikgPyBwYXJhbGxheEVsZW0uZ2V0QXR0cmlidXRlKFxcXCJkYXRhLXBhcmFsbGF4LWRpcmVjdGlvblxcXCIpIDogXFxcInZlcnRpY2FsXFxcIjtcXHJcXG5cXHRcXHRcXHR2YXIgcGFyYWxsYXhTcGVlZCA9IHBhcmFsbGF4RWxlbS5nZXRBdHRyaWJ1dGUoXFxcImRhdGEtcGFyYWxsYXgtc3BlZWRcXFwiKSA/IHBhcmFsbGF4RWxlbS5nZXRBdHRyaWJ1dGUoXFxcImRhdGEtcGFyYWxsYXgtc3BlZWRcXFwiKSA6IDE7XFxyXFxuXFxyXFxuXFx0XFx0XFx0Ly8gR2V0IHByb2dyZXNzIG9mIGVsZW1lbnQgb24gc2Nyb2xsIChmcm9tIDAgdG8gMSlcXHJcXG5cXHRcXHRcXHR2YXIgcHJvZ3Jlc3MgPSB0aGlzLmdldFByb2dyZXNzKHBhcmFsbGF4RWxlbSk7XFxyXFxuXFx0XFx0XFx0Ly8gQ29udmVydCB0aGUgc2NhbGUgdG8gLTAuNSB0byAwLjUgc28gd2UgcmVhY2ggMCB3aGVuIGVsZW1lbnQgaXMgY2VudGVyZWQgaW4gdGhlIHZpZXdwb3J0XFxyXFxuXFx0XFx0XFx0dmFyIHNjYWxlID0gcHJvZ3Jlc3MgLSAwLjU7XFxyXFxuXFx0XFx0XFx0Ly8gUmV2ZXJzZSBhbmQgbXVsdGlwbHkgc2NhbGUgdG8gYWNjZW50dWF0ZSB0cmFuc2Zvcm1cXHJcXG5cXHRcXHRcXHR2YXIgdHJhbnNmb3JtID0gc2NhbGUgKiAtMTAwO1xcclxcblxcdFxcdFxcdC8vIEFkZCBvdXIgcGFyYWxsYXggc3BlZWQgbXVsdGlwbGllclxcclxcblxcdFxcdFxcdHRyYW5zZm9ybSA9IHRyYW5zZm9ybSAqIHBhcmFsbGF4U3BlZWQ7XFxyXFxuXFx0XFx0XFx0Ly8gUm91bmQgb3VyIHRyYW5zZm9ybSB0byAyIGRlY2ltYWwgcGxhY2VzXFxyXFxuXFx0XFx0XFx0dHJhbnNmb3JtID0gT2JqZWN0KF9wcnhfaGVscGVyc19wcnhfaGVscGVyc19fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMF9fW1xcXCJyb3VuZFxcXCJdKSh0cmFuc2Zvcm0pO1xcclxcblxcclxcblxcdFxcdFxcdHZhciB0cmFuc2Zvcm1WYWx1ZTtcXHJcXG5cXHJcXG5cXHRcXHRcXHRpZiAocGFyYWxsYXhEaXJlY3Rpb24gPT0gXFxcInZlcnRpY2FsXFxcIikge1xcclxcblxcdFxcdFxcdFxcdHRyYW5zZm9ybVZhbHVlID0gXFxcInRyYW5zbGF0ZTNkKDAsIFxcXCIgKyB0cmFuc2Zvcm0gKyBcXFwicHgsIDApXFxcIjtcXHJcXG5cXHRcXHRcXHR9IGVsc2Uge1xcclxcblxcdFxcdFxcdFxcdHRyYW5zZm9ybVZhbHVlID0gXFxcInRyYW5zbGF0ZTNkKFxcXCIgKyB0cmFuc2Zvcm0gKyBcXFwicHgsIDAsIDApXFxcIjtcXHJcXG5cXHRcXHRcXHR9XFxyXFxuXFxyXFxuXFx0XFx0XFx0cGFyYWxsYXhFbGVtLnN0eWxlLnRyYW5zZm9ybSA9IHRyYW5zZm9ybVZhbHVlO1xcclxcblxcdFxcdH0pO1xcclxcblxcdH1cXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBVcGRhdGUgb3VyIGluLXZpZXcgZWxlbWVudHMuXFxyXFxuXFx0ICovXFxyXFxuXFx0dXBkYXRlSW5WaWV3KCkge1xcclxcblxcdFxcdHRoaXMuaW5WaWV3RWxlbXMuZm9yRWFjaCgoaW5WaWV3RWxlbSkgPT4ge1xcclxcblxcdFxcdFxcdHZhciBpblZpZXdPZmZzZXQgPSBpblZpZXdFbGVtLmRhdGFzZXQuaW5WaWV3T2Zmc2V0O1xcclxcblxcdFxcdFxcdGluVmlld09mZnNldCA9IGluVmlld09mZnNldCA/IGluVmlld09mZnNldCA6IDA7XFxyXFxuXFxyXFxuXFx0XFx0XFx0aWYgKHRoaXMuZWxlbWVudEluVmlld3BvcnQoaW5WaWV3RWxlbSwgaW5WaWV3T2Zmc2V0KSkge1xcclxcblxcdFxcdFxcdFxcdGluVmlld0VsZW0uY2xhc3NMaXN0LmFkZChcXFwiaXMtaW52aWV3XFxcIik7XFxyXFxuXFx0XFx0XFx0fVxcclxcblxcdFxcdH0pO1xcclxcblxcdH1cXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBVcGRhdGUgb3VyIHByb2dyZXNzIGVsZW1lbnRzLlxcclxcblxcdCAqL1xcclxcblxcdHVwZGF0ZVByb2dyZXNzKCkge1xcclxcblxcdFxcdHRoaXMucHJvZ3Jlc3NFbGVtcy5mb3JFYWNoKChwcm9ncmVzc0VsZW0pID0+IHtcXHJcXG5cXHRcXHRcXHR2YXIgcHJvZ3Jlc3NPcmlnaW4gPSBwcm9ncmVzc0VsZW0uZGF0YXNldC5wcm9ncmVzc09yaWdpbjtcXHJcXG5cXHRcXHRcXHR2YXIgcHJvZ3Jlc3MgPSB0aGlzLmdldFByb2dyZXNzKHByb2dyZXNzRWxlbSwgcHJvZ3Jlc3NPcmlnaW4pO1xcclxcblxcdFxcdFxcdHByb2dyZXNzRWxlbS5zdHlsZS5zZXRQcm9wZXJ0eShcXFwiLS1wcm9ncmVzc1xcXCIsIHByb2dyZXNzKTtcXHJcXG5cXHRcXHR9KTtcXHJcXG5cXHR9XFxyXFxuXFxyXFxuXFx0LyoqXFxyXFxuXFx0ICogSW5pdCBvdXIgaG9yaXpvbn
2RhbCBzY3JvbGwgc2VjdGlvbnMuXFxyXFxuXFx0ICovXFxyXFxuXFx0aW5pdEhvcml6b250YWxTY3JvbGwoKSB7XFxyXFxuXFx0XFx0dGhpcy5ob3Jpem9udGFsU2Nyb2xsU2VjdGlvbnMuZm9yRWFjaCgoaG9yaXpvbnRhbFNjcm9sbFNlY3Rpb24pID0+IHtcXHJcXG5cXHRcXHRcXHR2YXIgaG9yaXpvbnRhbFNjcm9sbFNlY3Rpb25Jbm5lciA9IGhvcml6b250YWxTY3JvbGxTZWN0aW9uLnF1ZXJ5U2VsZWN0b3IoXFxcIi5vLWhvcml6b250YWwtbGF5b3V0X2lubmVyXFxcIik7XFxyXFxuXFx0XFx0XFx0dmFyIHdpbmRvd1dpZHRoID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudFdpZHRoO1xcclxcblxcclxcblxcdFxcdFxcdHZhciBlbE91dGVyV2lkdGggPSAwO1xcclxcblxcdFxcdFxcdEFycmF5LmZyb20oaG9yaXpvbnRhbFNjcm9sbFNlY3Rpb25Jbm5lci5jaGlsZHJlbikuZm9yRWFjaCgoZWxlbWVudCkgPT4ge1xcclxcblxcdFxcdFxcdFxcdGVsT3V0ZXJXaWR0aCArPSBPYmplY3QoX3ByeF9oZWxwZXJzX3ByeF9oZWxwZXJzX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8wX19bXFxcIm91dGVyV2lkdGhcXFwiXSkoZWxlbWVudCk7XFxyXFxuXFx0XFx0XFx0fSk7XFxyXFxuXFxyXFxuXFx0XFx0XFx0dmFyIGhvcml6b250YWxTY3JvbGxPZmZzZXQgPSBlbE91dGVyV2lkdGggLSB3aW5kb3dXaWR0aDtcXHJcXG5cXHJcXG5cXHRcXHRcXHRob3Jpem9udGFsU2Nyb2xsU2VjdGlvbi5zdHlsZS5zZXRQcm9wZXJ0eShcXFwiLS1vZmZzZXRcXFwiLCBob3Jpem9udGFsU2Nyb2xsT2Zmc2V0ICsgXFxcInB4XFxcIik7XFxyXFxuXFx0XFx0fSk7XFxyXFxuXFx0fVxcclxcblxcclxcblxcdC8qKlxcclxcblxcdCAqIFVwZGF0ZSBvdXIgaG9yaXpvbnRhbCBzY3JvbGwgc2VjdGlvbnMuXFxyXFxuXFx0ICovXFxyXFxuXFx0dXBkYXRlSG9yaXpvbnRhbFNjcm9sbCgpIHtcXHJcXG5cXHRcXHR0aGlzLmhvcml6b250YWxTY3JvbGxTZWN0aW9ucy5mb3JFYWNoKChob3Jpem9udGFsU2Nyb2xsU2VjdGlvbikgPT4ge1xcclxcblxcdFxcdFxcdHZhciBob3Jpem9udGFsU2Nyb2xsU2VjdGlvbklubmVyID0gaG9yaXpvbnRhbFNjcm9sbFNlY3Rpb24ucXVlcnlTZWxlY3RvcihcXFwiLm8taG9yaXpvbn
2RhbC1sYXlvdXRfaW5uZXJcXFwiKTtcXHJcXG5cXHRcXHRcXHR2YXIgcmVjdCA9IGhvcml6b250YWxTY3JvbGxTZWN0aW9uLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xcclxcblxcdFxcdFxcdHZhciBpbml0aWFsU2Nyb2xsT2Zmc2V0ID0gaG9yaXpvbnRhbFNjcm9sbFNlY3Rpb24ub2Zmc2V0VG9wO1xcclxcblxcdFxcdFxcdHZhciBob3Jpem9udGFsU2Nyb2xsT2Zmc2V0ID0gcGFyc2VJbnQoZ2V0Q29tcHV0ZWRTdHlsZShob3Jpem9udGFsU2Nyb2xsU2VjdGlvbikuZ2V0UHJvcGVydHlWYWx1ZShcXFwiLS1vZmZzZXRcXFwiKSk7XFxyXFxuXFxyXFxuXFx0XFx0XFx0aWYgKHJlY3QudG9wIDw9IDAgJiYgcmVjdC5ib3R0b20gPiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xpZW50SGVpZ2h0KSB7XFxyXFxuXFx0XFx0XFx0XFx0aG9yaXpvbnRhbFNjcm9sbFNlY3Rpb25Jbm5lci5zdHlsZS50cmFuc2Zvcm0gPSBcXFwidHJhbnNsYXRlM2QoXFxcIiArIE1hdGgubWF4KE1hdGgubWluKGluaXRpYWxTY3JvbGxPZmZzZXQgLSB0aGlzLnNjcm9sbC5wb3MsIDApLCAtaG9yaXpvbnRhbFNjcm9sbE9mZnNldCkgKyBcXFwicHgsIDAsIDApXFxcIjtcXHJcXG5cXHRcXHRcXHRcXHRob3Jpem9udGFsU2Nyb2xsU2VjdGlvbklubmVyLmNsYXNzTGlzdC5yZW1vdmUoXFxcImlzLWJlZm9yZVxcXCIpO1xcclxcblxcdFxcdFxcdFxcdGhvcml6b250YWxTY3JvbGxTZWN0aW9uSW5uZXIuY2xhc3NMaXN0LnJlbW92ZShcXFwiaXMtYWZ0ZXJcXFwiKTtcXHJcXG5cXHRcXHRcXHRcXHRob3Jpem9udGFsU2Nyb2xsU2VjdGlvbklubmVyLmNsYXNzTGlzdC5hZGQoXFxcImlzLWluc2lkZVxcXCIpO1xcclxcblxcdFxcdFxcdH0gZWxzZSBpZiAocmVjdC50b3AgPiAwKSB7XFxyXFxuXFx0XFx0XFx0XFx0aG9yaXpvbnRhbFNjcm9sbFNlY3Rpb25Jbm5lci5jbGFzc0xpc3QucmVtb3ZlKFxcXCJpcy1pbnNpZGVcXFwiKTtcXHJcXG5cXHRcXHRcXHRcXHRob3Jpem9udGFsU2Nyb2xsU2VjdGlvbklubmVyLmNsYXNzTGlzdC5yZW1vdmUoXFxcImlzLWFmdGVyXFxcIik7XFxyXFxuXFx0XFx0XFx0XFx0aG9yaXpvbnRhbFNjcm9sbFNlY3Rpb25Jbm5lci5jbGFzc0xpc3QuYWRkKFxcXCJpcy1iZWZvcmVcXFwiKTtcXHJcXG5cXHRcXHRcXHR9IGVsc2UgaWYgKHJlY3QuYm90dG9tIDw9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRIZWlnaHQpIHtcXHJcXG5cXHRcXHRcXHRcXHRob3Jpem9udGFsU2Nyb2xsU2VjdGlvbklubmVyLmNsYXNzTGlzdC5yZW1vdmUoXFxcImlzLWJlZm9yZVxcXCIpO1xcclxcblxcdFxcdFxcdFxcdGhvcml6b250YWxTY3JvbGxTZWN0aW9uSW5uZXIuY2xhc3NMaXN0LnJlbW92ZShcXFwiaXMtaW5zaWRlXFxcIik7XFxyXFxuXFx0XFx0XFx0XFx0aG9yaXpvbnRhbFNjcm9sbFNlY3Rpb25Jbm5lci5jbGFzc0xpc3QuYWRkKFxcXCJpcy1hZnRlclxcXCIpO1xcclxcblxcdFxcdFxcdH1cXHJcXG5cXHRcXHR9KTtcXHJcXG5cXHR9XFxyXFxuXFxyXFxuXFx0LyoqXFxyXFxuXFx0ICogVXBkYXRlIG91ciBob3Jpem9udGFsIHNjcm9sbCBzdGlja3kgZWxlbWVudHMuXFxyXFxuXFx0ICovXFxyXFxuXFx0dXBkYXRlSG9yaXpvbnRhbFNjcm9sbFN0aWNreUVsZW1lbnRzKCkge1xcclxcblxcdFxcdHRoaXMuaG9yaXpvbn
2RhbFNjcm9sbFNlY3Rpb25zLmZvckVhY2goKGhvcml6b250YWxTY3JvbGxTZWN0aW9uKSA9PiB7XFxyXFxuXFx0XFx0XFx0dmFyIGhvcml6b250YWxTY3JvbGxTZWN0aW9uSW5uZXIgPSBob3Jpem9udGFsU2Nyb2xsU2VjdGlvbi5xdWVyeVNlbGVjdG9yKFxcXCIuby1ob3Jpem9udGFsLWxheW91dF9pbm5lclxcXCIpO1xcclxcblxcdFxcdFxcdHZhciByZWN0ID0gaG9yaXpvbnRhbFNjcm9sbFNlY3Rpb24uZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XFxyXFxuXFxyXFxuXFx0XFx0XFx0aWYgKHRoaXMuaXNIb3Jpem9udGFsU2Nyb2xsQWN0aXZlKSB7XFxyXFxuXFx0XFx0XFx0XFx0aWYgKHJlY3QudG9wIDw9IDAgJiYgcmVjdC5ib3R0b20gPiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xpZW50SGVpZ2h0KSB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0dmFyIGhvcml6b250YWxTY3JvbGxTdGlja3lFbGVtcyA9IGhvcml6b250YWxTY3JvbGxTZWN0aW9uLnF1ZXJ5U2VsZWN0b3JBbGwoXFxcIltkYXRhLXNjcm9sbC1zdGlja3ldXFxcIik7XFxyXFxuXFxyXFxuXFx0XFx0XFx0XFx0XFx0aG9yaXpvbnRhbFNjcm9sbFN0aWNreUVsZW1zLmZvckVhY2goKGhvcml6b250YWxTY3JvbGxTdGlja3lFbGVtKSA9PiB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0dmFyIHdyYXBwZXIgPSBob3Jpem9udGFsU2Nyb2xsU3RpY2t5RWxlbS5wYXJlbnRFbGVtZW50O1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdHZhciBvZmZzZXQgPSBob3Jpem9udGFsU2Nyb2xsU3RpY2t5RWxlbS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS53aWR0aDtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHR2YXIgcmVjdCA9IHdyYXBwZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0dmFyIG51bWVyYXRvciA9IC1yZWN0LmxlZnQ7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0dmFyIGRlbm9taW5hdG9yID0gcmVjdC53aWR0aCAtIG9mZnNldDtcXHJcXG5cXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHR2YXIgcHJvZ3Jlc3MgPSBNYXRoLm1pbihNYXRoLm1heChudW1lcmF0b3IgLyBkZW5vbWluYXRvciwgMCksIDEpO1xcclxcblxcclxcblxcdFxcdFxcdFxcdFxcdFxcdGlmIChwcm9ncmVzcyA+IDAgJiYgcHJvZ3Jlc3MgPCAxKSB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0aG9yaXpvbnRhbFNjcm9sbFN0aWNreUVsZW0uc3R5bGUudHJhbnNmb3JtID0gXFxcInRyYW5zbGF0ZTNkKFxcXCIgKyAodGhpcy5zY3JvbGwucG9zIC0gKHdyYXBwZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkubGVmdCAtIGhvcml6b250YWxTY3JvbGxTZWN0aW9uSW5uZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkubGVmdCkpICsgXFxcInB4LCAwLCAwKVxcXCI7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0fSBlbHNlIGlmIChwcm9ncmVzcyA8PSAwKSB7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0XFx0aG9yaXpvbnRhbFNjcm9sbFN0aWNreUVsZW0uc3R5bGUudHJhbnNmb3JtID0gXFxcInRyYW5zbGF0ZTNkKDAsIDAsIDApXFxcIjtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHR9IGVsc2UgaWYgKHByb2dyZXNzID49IDEpIHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRcXHRob3Jpem9udGFsU2Nyb2xsU3R
2pY2t5RWxlbS5zdHlsZS50cmFuc2Zvcm0gPSBcXFwidHJhbnNsYXRlM2QoXFxcIiArICh3cmFwcGVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLndpZHRoIC0gaG9yaXpvbnRhbFNjcm9sbFN0aWNreUVsZW0uZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkud2lkdGgpICsgXFxcInB4LCAwLCAwKVxcXCI7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0fVxcclxcblxcdFxcdFxcdFxcdFxcdH0pO1xcclxcblxcdFxcdFxcdFxcdH1cXHJcXG5cXHRcXHRcXHR9IGVsc2Uge1xcclxcblxcdFxcdFxcdFxcdHZhciBob3Jpem9udGFsU2Nyb2xsU3RpY2t5RWxlbXMgPSBob3Jpem9udGFsU2Nyb2xsU2VjdGlvbi5xdWVyeVNlbGVjdG9yQWxsKFxcXCJbZGF0YS1zY3JvbGwtc3RpY2t5XVxcXCIpO1xcclxcblxcclxcblxcdFxcdFxcdFxcdGhvcml6b250YWxTY3JvbGxTdGlja3lFbGVtcy5mb3JFYWNoKChob3Jpem9udGFsU2Nyb2xsU3RpY2t5RWxlbSkgPT4ge1xcclxcblxcdFxcdFxcdFxcdFxcdHZhciB3cmFwcGVyID0gaG9yaXpvbnRhbFNjcm9sbFN0aWNreUVsZW0ucGFyZW50RWxlbWVudDtcXHJcXG5cXHRcXHRcXHRcXHRcXHR2YXIgb2Zmc2V0ID0gaG9yaXpvbnRhbFNjcm9sbFN0aWNreUVsZW0uZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkuaGVpZ2h0O1xcclxcblxcdFxcdFxcdFxcdFxcdHZhciByZWN0ID0gd3JhcHBlci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcXHJcXG5cXHRcXHRcXHRcXHRcXHR2YXIgbnVtZXJhdG9yID0gLXJlY3QudG9wO1xcclxcblxcdFxcdFxcdFxcdFxcdHZhciBkZW5vbWluYXRvciA9IHJlY3QuaGVpZ2h0IC0gb2Zmc2V0O1xcclxcblxcclxcblxcdFxcdFxcdFxcdFxcdHZhciBwcm9ncmVzcyA9IE1hdGgubWluKE1hdGgubWF4KG51bWVyYXRvciAvIGRlbm9taW5hdG9yLCAwKSwgMSk7XFxyXFxuXFxyXFxuXFx0XFx0XFx0XFx0XFx0aWYgKHByb2dyZXNzID4gMCAmJiBwcm9ncmVzcyA8IDEpIHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRob3Jpem9udGFsU2Nyb2xsU3R
2pY2t5RWxlbS5zdHlsZS5wb3NpdGlvbiA9IFxcXCJmaXhlZFxcXCI7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0aG9yaXpvbnRhbFNjcm9sbFN0aWNreUVsZW0uc3R5bGUudG9wID0gXFxcIjBweFxcXCI7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0aG9yaXpvbnRhbFNjcm9sbFN0aWNreUVsZW0uc3R5bGUudHJhbnNmb3JtID0gXFxcIm5vbmVcXFwiO1xcclxcblxcdFxcdFxcdFxcdFxcdH0gZWxzZSBpZiAocHJvZ3Jlc3MgPD0gMCkge1xcclxcblxcdFxcdFxcdFxcdFxcdFxcdGhvcml6b250YWxTY3JvbGxTdGlja3lFbGVtLnN0eWxlLnBvc2l0aW9uID0gXFxcInJlbGF0aXZlXFxcIjtcXHJcXG5cXHRcXHRcXHRcXHRcXHR9IGVsc2UgaWYgKHByb2dyZXNzID49IDEpIHtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHR3cmFwcGVyLnN0eWxlLnBvc2l0aW9uID0gXFxcInJlbGF0aXZlXFxcIjtcXHJcXG5cXHRcXHRcXHRcXHRcXHRcXHRob3Jpem9udGFsU2Nyb2xsU3RpY2t5RWxlbS5zdHlsZS5wb3NpdGlvbiA9IFxcXCJhYnNvbHV0ZVxcXCI7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0aG9yaXpvbnRhbFNjcm9sbFN0aWNreUVsZW0uc3R5bGUudG9wID0gXFxcIlxcXCI7XFxyXFxuXFx0XFx0XFx0XFx0XFx0XFx0aG9yaXpvbnRhbFNjcm9sbFN0aWNreUVsZW0uc3R5bGUuYm90dG9tID0gXFxcIjBweFxcXCI7XFxyXFxuXFx0XFx0XFx0XFx0XFx0fVxcclxcblxcdFxcdFxcdFxcdH0pO1xcclxcblxcdFxcdFxcdH1cXHJcXG5cXHRcXHR9KTtcXHJcXG5cXHR9XFxyXFxuXFxyXFxuXFx0LyoqXFxyXFxuXFx0ICogVXBkYXRlIHNjcm9sbCBpbmVydGlhLlxcclxcblxcdCAqL1xcclxcblxcdHVwZGF0ZVNjcm9sbEluZXJ0aWEoKSB7XFxyXFxuXFx0XFx0dGhpcy5pbmVydGlhLnRhcmdldCA9IHRoaXMuc2Nyb2xsLnRhcmdldCAtIHRoaXMuc2Nyb2xsLnBvcztcXHJcXG5cXHJcXG5cXHRcXHR0aGlzLmluZXJ0aWEuY3VycmVudCA9IE9iamVjdChfcHJ4X2hlbHBlcnNfcHJ4X2hlbHBlcnNfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzBfX1tcXFwicm91bmRcXFwiXSkoT2JqZWN0KF9wcnhfaGVscGVyc19wcnhfaGVscGVyc19fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMF9fW1xcXCJsZXJwXFxcIl0pKHRoaXMuaW5lcnRpYS5jdXJyZW50LCB0aGlzLmluZXJ0aWEudGFyZ2V0LCB0aGlzLmVhc2luZykpO1xcclxcblxcclxcblxcdFxcdHZhciBpbmVydGlhID0gdGhpcy5pbmVydGlhLmN1cnJlbnQ7XFxyXFxuXFx0XFx0aW5lcnRpYSA9IGluZXJ0aWEgLyAxMDA7XFxyXFxuXFx0XFx0aW5lcnRpYSA9IE1hdGgubWluKE1hdGgubWF4KGluZXJ0aWEsIC0xKSwgMSk7XFxyXFxuXFx0XFx0aW5lcnRpYSA9IE9iamVjdChfcHJ4X2hlbHBlcnNfcHJ4X2hlbHBlcnNfX1dFQlBBQ0tfSU1QT1JURURfTU9EVUxFXzBfX1tcXFwicm91bmRcXFwiXSkoaW5lcnRpYSk7XFxyXFxuXFxyXFxuXFx0XFx0dGhpcy5pbmVydGlhRWxlbXMuZm9yRWFjaCgoaW5lcnRpYUVsZW0pID0+IHtcXHJcXG5cXHRcXHRcXHRpbmVydGlhRWxlbS5zdHlsZS5zZXRQcm9wZXJ0eShcXFwiLS1zY3JvbGwtaW5lcnRpYVxcXCIsIGluZXJ0aWEpO1xcclxcblxcdFxcdH0pO1xcclxcblxcdH1cXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBTeW5jIHRoZSBzY3JvbGwgcG9zaXRpb24gdG8gdGhlIGN1cnJlbnQgc2Nyb2xsIHBvc2l0aW9uIG9mIHRoZSB3aW5kb3cuXFxyXFxuXFx0ICovXFxyXFxuXFx0c3luY1BvcygpIHtcXHJcXG5cXHRcXHR0aGlzLnNjcm9sbC5wb3MgPSBPYmplY3QoX3ByeF9oZWxwZXJzX3ByeF9oZWxwZXJzX19XRUJQQUNLX0lNUE9SVEVEX01PRFVMRV8wX19bXFxcInJvdW5kXFxcIl0pKHdpbmRvdy5wYWdlWU9mZnNldCk7XFxyXFxuXFx0XFx0dGhpcy5zY3JvbGwudGFyZ2V0ID0gT2JqZWN0KF9wcnhfaGVscGVyc19wcnhfaGVscGVyc19fV0VCUEFDS19JTVBPUlRFRF9NT0RVTEVfMF9fW1xcXCJyb3VuZFxcXCJdKSh3aW5kb3cucGFnZVlPZmZzZXQpO1xcclxcblxcdH1cXHJcXG5cXHJcXG5cXHQvKipcXHJcXG5cXHQgKiBHZXQgdGhlIHByb2dyZXNzIG9mIGFuIGVsZW1lbnQgaW4gdGhlIHZpZXdwb3J0IChmcm9tIDAgdG8gMSkuXFxyXFxuXFx0ICpcXHJcXG5cXHQgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBlbCAtIFRoZSBlbGVtZW50IHRvIHJldHVybiB0aGUgcHJvZ3Jlc3Mgb2YuXFxyXFxuXFx0ICogQHBhcmFtIHtzdHJpbmd9IFtwcm9ncmVzc09yaWdpbj1jZW50ZXJdIC0gVGhlIG9yaWdpbiBmcm9tIHdoZXJlIHRoZSBwcm9ncmVzcyBzaG91bGQgYmUgY2FsY3VsYXRlZC4gRGVmYXVsdHMgdG8gXFxcImNlbnRlclxcXCIuXFxyXFxuXFx0ICovXFxyXFxuXFx0Z2V0UHJvZ3Jlc3MoZWwsIHByb2dyZXNzT3JpZ2luID0gXFxcImNlbnRlclxcXCIpIHtcXHJcXG5cXHRcXHR2YXIgcmVjdCA9IGVsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xcclxcblxcdFxcdHZhciBudW1lcmF0b3I7XFxyXFxuXFx0XFx0dmFyIGRlbm9taW5hdG9yO1xcclxcblxcdFxcdHZhciBwcm9ncmVzcztcXHJcXG5cXHJcXG5cXHRcXHRpZiAoZWwuY2xvc2VzdChcXFwiW2RhdGEtc2Nyb2xsLWhvcml6b250YWxdXFxcIikgJiYgdGhpcy5pc0hvcml6b250YWxTY3JvbGxBY3RpdmUpIHtcXHJcXG5cXHRcXHRcXHRzd2l0Y2ggKHByb2dyZXNzT3JpZ2luKSB7XFxyXFxuXFx0XFx0XFx0XFx0Y2FzZSBcXFwiY2VudGVyXFxcIjpcXHJcXG5cXHRcXHRcXHRcXHRcXHRwcm9ncmVzc09yaWdpbiA9IFxcXCJjZW50ZXItaG9yaXpvbnRhbFxcXCI7XFxyXFxuXFx0XFx0XFx0XFx0XFx0YnJlYWs7XFxyXFxuXFx0XFx0XFx0XFx0Y2FzZSBcXFwidG9wXFxcIjpcXHJcXG5cXHRcXHRcXHRcXHRcXHRwcm9ncmVzc09yaWdpbiA9IFxcXCJsZWZ0XFxcIjtcXHJcXG5cXHRcXHRcXHRcXHRcXHRicmVhaztcXHJcXG5cXHRcXHRcXHRcXHRjYXNlIFxcXCJib3R0b21cXFwiOlxcclxcblxcdFxcdFxcdFxcdFxcdHByb2dyZXNzT3JpZ2luID0gXFxcInJpZ2h0XFxcIjtcXHJcXG5cXHRcXHRcXHRcXHRcXHRicmVhaztcXHJcXG5cXHRcXHRcXHRcXHRjYXNlIFxcXCJiZXR3ZWVuXFxcIjpcXHJcXG5cXHRcXHRcXHRcXHRcXHRwcm9ncmVzc09yaWdpbiA9IFxcXCJiZXR3ZWVuLWhvcml6b250YWxcXFwiO1xcclxcblxcdFxcdFxcdFxcdFxcdGJyZWFrO1xcclxcblxcdFxcdFxcdH1cXHJcXG5cXHRcXHR9XFxyXFxuXFxyXFxuXFx0XFx0aWYgKHByb2dyZXNzT3JpZ2luID09IFxcXCJ0b3BcXFwiKSB7XFxyXFxuXFx0XFx0XFx0bnVtZXJhdG9yID0gLXJlY3QudG9wO1xcclxcblxcdFxcdFxcdGRlbm9taW5hdG9yID0gcmVjdC5oZWlnaHQ7XFxyXFxuXFx0XFx0fSBlbHNlIGlmIChwcm9ncmVzc09yaWdpbiA9PSBcXFwiYm90dG9tXFxcIikge1xcclxcblxcdFxcdFxcdG51bWVyYXRvciA9IChyZWN0LnRvcCAtIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRIZWlnaHQpICogLTE7XFxyXFxuXFx0XFx0XFx0ZGVub21pbmF0b3IgPSByZWN0LmhlaWdodDtcXHJcXG5cXHRcXHR9IGVsc2UgaWYgKHByb2dyZXNzT3JpZ2luID09IFxcXCJiZXR3ZWVuXFxcIikge1xcclxcblxcdFxcdFxcdG51bWVyYXRvciA9IC1yZWN0LnRvcDtcXHJcXG5cXHRcXHRcXHRkZW5vbWluYXRvciA9IHJlY3QuaGVpZ2h0IC0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudE
2hlaWdodDtcXHJcXG5cXHRcXHR9IGVsc2UgaWYgKHByb2dyZXNzT3JpZ2luID09IFxcXCJsZWZ0XFxcIikge1xcclxcblxcdFxcdFxcdG51bWVyYXRvciA9IC1yZWN0LmxlZnQ7XFxyXFxuXFx0XFx0XFx0ZGVub21pbmF0b3IgPSByZWN0LndpZHRoO1xcclxcblxcdFxcdH0gZWxzZSBpZiAocHJvZ3Jlc3NPcmlnaW4gPT0gXFxcInJpZ2h0XFxcIikge1xcclxcblxcdFxcdFxcdG51bWVyYXRvciA9IChyZWN0LmxlZnQgLSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xpZW50V2lkdGgpICogLTE7XFxyXFxuXFx0XFx0XFx0ZGVub21pbmF0b3IgPSByZWN0LndpZHRoO1xcclxcblxcdFxcdH0gZWxzZSBpZiAocHJvZ3Jlc3NPcmlnaW4gPT0gXFxcImNlbnRlci1ob3Jpem9udGFsXFxcIikge1xcclxcblxcdFxcdFxcdG51bWVyYXRvciA9IChyZWN0LmxlZnQgLSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xpZW50V2lkdGgpICogLTE7XFxyXFxuXFx0XFx0XFx0ZGVub21pbmF0b3IgPSByZWN0LndpZHRoICsgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudFdpZHRoO1xcclxcblxcdFxcdH0gZWxzZSBpZiAocHJvZ3Jlc3NPcmlnaW4gPT0gXFxcImJldHdlZW4taG9yaXpvbnRhbFxcXCIpIHtcXHJcXG5cXHRcXHRcXHRudW1lcmF0b3IgPSAtcmVjdC5sZWZ0O1xcclxcblxcdFxcdFxcdGRlbm9taW5hdG9yID0gcmVjdC53aWR0aCAtIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRXaWR0aDtcXHJcXG5cXHRcXHR9IGVsc2Uge1xcclxcblxcdFxcdFxcdG51bWVyYXRvciA9IChyZWN0LnRvcCAtIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRIZWlnaHQpICogLTE7XFxyXFxuXFx0XFx0XFx0ZGVub21pbmF0b3IgPSByZWN0LmhlaWdodCArIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRIZWlnaHQ7XFxyXFxuXFx0XFx0fVxcclxcblxcclxcblxcdFxcdHByb2dyZXNzID0gTWF0aC5taW4oTWF0aC5tYXgobnVtZXJhdG9yIC8gZGVub21pbmF0b3IsIDApLCAxKTtcXHJcXG5cXHJcXG5cXHRcXHRyZXR1cm4gcHJvZ3Jlc3M7XFxyXFxuXFx0fVxcclxcblxcclxcblxcdC8qKlxcclxcblxcdCAqIEtlZXAgc2Nyb2xsIHBvc2l0aW9uIGJldHdlZW4gMCBhbmQgdGhlIGVuZCBvZiB0aGUgZG9jdW1lbnQuXFxyXFxuXFx0ICpcXHJcXG5cXHQgKiBAcGFyYW0ge251bWJlcn0gcG9zIC0gVGhlIHNjcm9sbCBwb3NpdGlvbiB0byBjYXAuXFxyXFxuXFx0ICovXFxyXFxuXFx0Y2FwU2Nyb2xsUG9zaXRpb24ocG9zKSB7XFxyXFxuXFx0XFx0cmV0dXJuIE1hdGgubWluKE1hdGgubWF4KHBvcywgMCksIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zY3JvbGxIZWlnaHQgLSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xpZW50SGVpZ2h0KTtcXHJcXG5cXHR9XFxyXFxuXFxyXFxuXFx0LyoqXFxyXFxuXFx0ICogVXRpbGl0eSBmdW5jdGlvbiB0byBjaGVjayBvZiBhIGdpdmVuIGVsZW1lbnQgaXMgaW4gdGhlIHZpZXdwb3J0LlxcclxcblxcdCAqXFxyXFxuXFx0ICogQHBhcmFtIHtIVE1MRWxlbWVudH0gZWwgLSBFbGVtZW50IHRvIGNoZWNrIGlmIGluIHZpZXdwb3J0LlxcclxcblxcdCAqIEBwYXJhbSB7bnVtYmVyfSBvZmZzZXQgLSBPZmZzZXQgaW4gcGVyY2VudC5cXHJcXG5cXHQgKlxcclxcblxcdCAqIEByZXR1cm5zIHtib29sZWFufSBJZiBlbGVtZW50IGluIHZpZXdwb3J0IG9yIG5vdC5cXHJcXG5cXHQgKi9cXHJcXG5cXHRlbGVtZW50SW5WaWV3cG9ydChlbCwgb2Zmc2V0ID0gMCkge1xcclxcblxcdFxcdHZhciByZWN0ID0gZWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XFxyXFxuXFxyXFxuXFx0XFx0Ly8gSWYgZWxlbWVudCBpcyBpbiBob3Jpem9udGFsIHNjcm9sbCBjb250YWluZXJcXHJcXG5cXHRcXHRpZiAoZWwuY2xvc2VzdChcXFwiW2RhdGEtc2Nyb2xsLWhvcml6b250YWxdXFxcIikpIHtcXHJcXG5cXHRcXHRcXHRyZXR1cm4gcmVjdC5sZWZ0IC0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudFdpZHRoICsgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudFdpZHRoICogb2Zmc2V0IDw9IDA7XFxyXFxuXFx0XFx0fSBlbHNlIHtcXHJcXG5cXHRcXHRcXHRyZXR1cm4gcmVjdC50b3AgLSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xpZW50SGVpZ2h0ICsgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudEhlaWdodCAqIG9mZnNldCA8PSAwO1xcclxcblxcdFxcdH1cXHJcXG5cXHR9XFxyXFxuXFxyXFxuXFx0LyoqXFxyXFxuXFx0ICogVXRpbGl0eSBmdW5jdGlvbiB0byBjaGVjayBpZiBlbGVtZW50IGlzIHNjcm9sbGFibGUuXFxyXFxuXFx0ICpcXHJcXG5cXHQgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBlbCAtIEVsZW1lbnQgdG8gY2hlY2suXFxyXFxuXFx0ICpcXHJcXG5cXHQgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBJZiBlbGVtZW50IGlzIHNjcm9sbGFibGUgb3Igbm90LlxcclxcblxcdCAqL1xcclxcblxcdGlzU2Nyb2xsYWJsZShlbCkge1xcclxcblxcdFxcdHJldHVybiBlbC5zY3JvbGxIZWlnaHQgPiBlbC5jbGllbnRIZWlnaHQgJiYgW1xcXCJzY3JvbGxcXFwiLCBcXFwiYXV0b1xcXCJdLmluZGV4T2YoZ2V0Q29tcHV0ZWRTdHlsZShlbCkub3ZlcmZsb3dZKSA+PSAwO1xcclxcblxcdH1cXHJcXG59XFxyXFxuXFxuXFxuLy8jIHNvdXJjZVVSTD13ZWJwYWNrOi8vLy4vbGlicmFyaWVzL3ByeC1zY3JvbGwvcHJ4LXNjcm9sbC5qcz9cIik7XG4gICAgLyoqKi9cbiAgfSxcblxuICAvKioqL1xuICBcIi4vbm9kZV9tb2R1bGVzL2Z1enp5c29ydC9mdXp6eXNvcnQuanNcIjpcbiAgLyohKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqISpcXFxuICAgICEqKiogLi9ub2RlX21vZHVsZXMvZnV6enlzb3J0L2Z1enp5c29ydC5qcyAqKiohXG4gICAgXFwqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbiAgLyohIG5vIHN0YXRpYyBleHBvcnRzIGZvdW5kICovXG5cbiAgLyoqKi9cbiAgZnVuY3Rpb24gbm9kZV9tb2R1bGVzRnV6enlzb3J0RnV6enlzb3J0SnMobW9kdWxlLCBleHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XG4gICAgZXZhbChcInZhciBfX1dFQlBBQ0tfQU1EX0RFRklORV9GQUNUT1JZX18sIF9fV0VCUEFDS19BTURfREVGSU5FX0FSUkFZX18sIF9fV0VCUEFDS19BTURfREVGSU5FX1JFU1VMVF9fOy8vIGh0dHBzOi8vZ2l0aHViLmNvbS9mYXJ6aGVyL2Z1enp5c29ydCB2Mi4wLjRcXHJcXG4vKlxcclxcbiAgU3VibGltZVRleHQtbGlrZSBGdXp6eSBTZWFyY2hcXHJcXG5cXHJcXG4gIGZ1enp5c29ydC5zaW5nbGUoJ2ZzJywgJ0Z1enp5IFNlYXJjaCcpIC8vIHtzY29yZTogLTE2fVxcclxcbiAgZnV6enlzb3J0LnNpbmdsZSgndGVzdCcsICd0ZXN0JykgLy8ge3Njb3JlOiAwfVxcclxcbiAgZnV6enlzb3J0LnNpbmdsZSgnZG9lc250IGV4aXN0JywgJ3RhcmdldCcpIC8vIG51bGxcXHJcXG5cXHJcXG4gIGZ1enp5c29ydC5nbygnbXInLCBbe2ZpbGU6J01vbml0b3IuY3BwJ30sIHtmaWxlOidNZXNoUmVuZGVyZXIuY3BwJ31dLCB7a2V5OidmaWxlJ30pXFxyXFxuICAvLyBbe3Njb3JlOi0xOCwgb2JqOntmaWxlOidNZXNoUmVuZGVyZXIuY3BwJ319LCB7c2NvcmU6LTYwMDksIG9iajp7ZmlsZTonTW9uaXRvci5jcHAnfX1dXFxyXFxuXFxyXFxuICBmdXp6eXNvcnQuZ28oJ21yJywgWydNb25pdG9yLmNwcCcsICdNZXNoUmVuZGVyZXIuY3BwJ10pXFxyXFxuICAvLyBbe3Njb3JlOiAtMTgsIHRhcmdldDogXFxcIk1lc2hSZW5kZXJlci5jcHBcXFwifSwge3Njb3JlOiAtNjAwOSwgdGFyZ2V0OiBcXFwiTW9uaXRvci5jcHBcXFwifV1cXHJcXG5cXHJcXG4gIGZ1enp5c29ydC5oaWdobGlnaHQoZnV6enlzb3J0LnNpbmdsZSgnZnMnLCAnRnV6enkgU2VhcmNoJyksICc8Yj4nLCAnPC9iPicpXFxyXFxuICAvLyA8Yj5GPC9iPnV6enkgPGI+UzwvYj5lYXJjaF
2xcclxcbiovXFxyXFxuXFxyXFxuLy8gVU1EIChVbml2ZXJzYWwgTW9kdWxlIERlZmluaXRpb24pIGZvciBmdXp6eXNvcnRcXHJcXG47KChyb290LCBVTUQpID0+IHtcXHJcXG4gIGlmKHRydWUpICEoX19XRUJQQUNLX0FNRF9ERUZJTkVfQVJSQVlfXyA9IFtdLCBfX1dFQlBBQ0tfQU1EX0RFRklORV9GQUNUT1JZX18gPSAoVU1EKSxcXG5cXHRcXHRcXHRcXHRfX1dFQlBBQ0tfQU1EX0RFRklORV9SRVNVTFRfXyA9ICh0eXBlb2YgX19XRUJQQUNLX0FNRF9ERUZJTkVfRkFDVE9SWV9fID09PSAnZnVuY3Rpb24nID9cXG5cXHRcXHRcXHRcXHQoX19XRUJQQUNLX0FNRF9ERUZJTkVfRkFDVE9SWV9fLmFwcGx5KGV4cG9ydHMsIF9fV0VCUEFDS19BTURfREVGSU5FX0FSUkFZX18pKSA6IF9fV0VCUEFDS19BTURfREVGSU5FX0ZBQ1RPUllfXyksXFxuXFx0XFx0XFx0XFx0X19XRUJQQUNLX0FNRF9ERUZJTkVfUkVTVUxUX18gIT09IHVuZGVmaW5lZCAmJiAobW9kdWxlLmV4cG9ydHMgPSBfX1dFQlBBQ0tfQU1EX0RFRklORV9SRVNVTFRfXykpXFxyXFxuICBlbHNlIHt9XFxyXFxufSkodGhpcywgXyA9PiB7XFxyXFxuICAndXNlIHN0cmljdCdcXHJcXG5cXHJcXG4gIHZhciBzaW5nbGUgPSAoc2VhcmNoLCB0YXJnZXQpID0+IHsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZihzZWFyY2g9PSdmYXJ6aGVyJylyZXR1cm57dGFyZ2V0OlxcXCJmYXJ6aGVyIHdhcyBoZXJlICheLV4qKS9cXFwiLHNjb3JlOjAsX2luZGV4ZXM6WzBdfVxcclxcbiAgICBpZighc2VhcmNoIHx8ICF0YXJnZXQpIHJldHVybiBOVUxMXFxyXFxuXFxyXFxuICAgIHZhciBwcmVwYXJlZFNlYXJjaCA9IGdldFByZXBhcmVkU2VhcmNoKHNlYXJjaClcXHJcXG4gICAgaWYoIWlzT2JqKHRhcmdldCkpIHRhcmdldCA9IGdldFByZXBhcmVkKHRhcmdldClcXHJcXG5cXHJcXG4gICAgdmFyIHNlYXJjaEJpdGZsYWdzID0gcHJlcGFyZWRTZWFyY2guYml0ZmxhZ3NcXHJcXG4gICAgaWYoKHNlYXJjaEJpdGZsYWdzICYgdGFyZ2V0Ll9iaXRmbGFncykgIT09IHNlYXJjaEJpdGZsYWdzKSByZXR1cm4gTlVMTFxcclxcblxcclxcbiAgICByZXR1cm4gYWxnb3JpdGhtKHByZXBhcmVkU2VhcmNoLCB0YXJnZXQpXFxyXFxuICB9XFxyXFxuXFxyXFxuXFxyXFxuICB2YXIgZ28gPSAoc2VhcmNoLCB0YXJnZXRzLCBvcHRpb25zKSA9PiB7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYoc2VhcmNoPT0nZmFyemhlcicpcmV0dXJuW3t0YXJnZXQ6XFxcImZhcnpoZXIgd2FzIGhlcmUgKF4tXiopL1xcXCIsc2NvcmU6MCxfaW5kZXhlczpbMF0sb2JqOnRhcmdldHM/dGFyZ2V0c1swXTpOVUxMfV1cXHJcXG4gICAgaWYoIXNlYXJjaCkgcmV0dXJuIG9wdGlvbnMmJm9wdGlvbnMuYWxsID8gYWxsKHNlYXJjaCwgdGFyZ2V0cywgb3B0aW9ucykgOiBub1Jlc3VsdHNcXHJcXG5cXHJcXG4gICAgdmFyIHByZXBhcmVkU2VhcmNoID0gZ2V0UHJlcGFyZWRTZWFyY2goc2VhcmNoKVxcclxcbiAgICB2YXIgc2VhcmNoQml0ZmxhZ3MgPSBwcmVwYXJlZFNlYXJjaC5iaXRmbGFnc1xcclxcbiAgICB2YXIgY29udGFpbnNTcGFjZSAgPSBwcmVwYXJlZFNlYXJjaC5jb250YWluc1NwYWNlXFxyXFxuXFxyXFxuICAgIHZhciB0aHJlc2hvbGQgPSBvcHRpb25zJiZvcHRpb25zLnRocmVzaG9sZCB8fCBJTlRfTUlOXFxyXFxuICAgIHZhciBsaW1pdCAgICAgPSBvcHRpb25zJiZvcHRpb25zWydsaW1pdCddICB8fCBJTlRfTUFYIC8vIGZvciBzb21lIHJlYXNvbiBvbmx5IGxpbWl0IGJyZWFrcyB3aGVuIG1pbmlmaWVkXFxyXFxuXFxyXFxuICAgIHZhciByZXN1bHRzTGVuID0gMDsgdmFyIGxpbWl0ZWRDb3VudCA9IDBcXHJcXG4gICAgdmFyIHRhcmdldHNMZW4gPSB0YXJnZXRzLmxlbmd0aFxcclxcblxcclxcbiAgICAvLyBUaGlzIGNvZGUgaXMgY29weS9wYXN0ZWQgMyB0aW1lcyBmb3IgcGVyZm9ybWFuY2UgcmVhc29ucyBbb3B0aW9ucy5rZXlzLCBvcHRpb25zLmtleSwgbm8ga2V5c11cXHJcXG5cXHJcXG4gICAgLy8gb3B0aW9ucy5rZXlcXHJcXG4gICAgaWYob3B0aW9ucyAmJiBvcHRpb25zLmtleSkge1xcclxcbiAgICAgIHZhciBrZXkgPSBvcHRpb25zLmtleVxcclxcbiAgICAgIGZvcih2YXIgaSA9IDA7IGkgPCB0YXJnZXRzTGVuOyArK2kpIHsgdmFyIG9iaiA9IHRhcmdldHNbaV1cXHJcXG4gICAgICAgIHZhciB0YXJnZXQgPSBnZXRWYWx1ZShvYmosIGtleSlcXHJcXG4gICAgICAgIGlmKCF0YXJnZXQpIGNvbnRpbnVlXFxyXFxuICAgICAgICBpZighaXNPYmoodGFyZ2V0KSkgdGFyZ2V0ID0gZ2V0UHJlcGFyZWQodGFyZ2V0KVxcclxcblxcclxcbiAgICAgICAgaWYoKHNlYXJjaEJpdGZsYWdzICYgdGFyZ2V0Ll9iaXRmbGFncykgIT09IHNlYXJjaEJpdGZsYWdzKSBjb250aW51ZVxcclxcbiAgICAgICAgdmFyIHJlc3VsdCA9IGFsZ29yaXRobShwcmVwYXJlZFNlYXJjaCwgdGFyZ2V0KVxcclxcbiAgICAgICAgaWYocmVzdWx0ID09PSBOVUxMKSBjb250aW51ZVxcclxcbiAgICAgICAgaWYocmVzdWx0LnNjb3JlIDwgdGhyZXNob2xkKSBjb250aW51ZVxcclxcblxcclxcbiAgICAgICAgLy8gaGF2ZSB0byBjbG9uZSByZXN1bHQgc28gZHVwbGljYXRlIHRhcmdldHMgZnJvbSBkaWZmZXJlbnQgb2JqIGNhbiBlYWNoIHJlZmVyZW5jZSB0aGUgY29ycmVjdCBvYmpcXHJcXG4gICAgICAgIHJlc3VsdCA9IHt0YXJnZXQ6cmVzdWx0LnRhcmdldCwgX3RhcmdldExvd2VyOicnLCBfdGFyZ2V0TG93ZXJDb2RlczpOVUxMLCBfbmV4dEJlZ2lubmluZ0luZGV4ZXM6TlVMTCwgX2JpdGZsYWdzOjAsIHNjb3JlOnJlc3VsdC5zY29yZSwgX2luZGV4ZXM6cmVzdWx0Ll9pbmRleGVzLCBvYmo6b2JqfSAvLyBoaWRkZW5cXHJcXG5cXHJcXG4gICAgICAgIGlmKHJlc3VsdHNMZW4gPCBsaW
21pdCkgeyBxLmFkZChyZXN1bHQpOyArK3Jlc3VsdHNMZW4gfVxcclxcbiAgICAgICAgZWxzZSB7XFxyXFxuICAgICAgICAgICsrbGltaXRlZENvdW50XFxyXFxuICAgICAgICAgIGlmKHJlc3VsdC5zY29yZSA+IHEucGVlaygpLnNjb3JlKSBxLnJlcGxhY2VUb3AocmVzdWx0KVxcclxcbiAgICAgICAgfVxcclxcbiAgICAgIH1cXHJcXG5cXHJcXG4gICAgLy8gb3B0aW9ucy5rZXlzXFxyXFxuICAgIH0gZWxzZSBpZihvcHRpb25zICYmIG9wdGlvbnMua2V5cykge1xcclxcbiAgICAgIHZhciBzY29yZUZuID0gb3B0aW9uc1snc2NvcmVGbiddIHx8IGRlZmF1bHRTY29yZUZuXFxyXFxuICAgICAgdmFyIGtleXMgPSBvcHRpb25zLmtleXNcXHJcXG4gICAgICB2YXIga2V5c0xlbiA9IGtleXMubGVuZ3RoXFxyXFxuICAgICAgZm9yKHZhciBpID0gMDsgaSA8IHRhcmdldHNMZW47ICsraSkgeyB2YXIgb2JqID0gdGFyZ2V0c1tpXVxcclxcbiAgICAgICAgdmFyIG9ialJlc3VsdHMgPSBuZXcgQXJyYXkoa2V5c0xlbilcXHJcXG4gICAgICAgIGZvciAodmFyIGtleUkgPSAwOyBrZXlJIDwga2V5c0xlbjsgKytrZXlJKSB7XFxyXFxuICAgICAgICAgIHZhciBrZXkgPSBrZXlzW2tleUldXFxyXFxuICAgICAgICAgIHZhciB0YXJnZXQgPSBnZXRWYWx1ZShvYmosIGtleSlcXHJcXG4gICAgICAgICAgaWYoIXRhcmdldCkgeyBvYmpSZXN1bHRzW2tleUldID0gTlVMTDsgY29udGludWUgfVxcclxcbiAgICAgICAgICBpZighaXNPYmoodGFyZ2V0KSkgdGFyZ2V0ID0gZ2V0UHJlcGFyZWQodGFyZ2V0KVxcclxcblxcclxcbiAgICAgICAgICBpZigoc2VhcmNoQml0ZmxhZ3MgJiB0YXJnZXQuX2JpdGZsYWdzKSAhPT0gc2VhcmNoQml0ZmxhZ3MpIG9ialJlc3VsdHNba2V5SV0gPSBOVUxMXFxyXFxuICAgICAgICAgIGVsc2Ugb2JqUmVzdWx0c1trZXlJXSA9IGFsZ29yaXRobShwcmVwYXJlZFNlYXJjaCwgdGFyZ2V0KVxcclxcbiAgICAgICAgfVxcclxcbiAgICAgICAgb2JqUmVzdWx0cy5vYmogPSBvYmogLy8gYmVmb3JlIHNjb3JlRm4gc28gc2NvcmVGbiBjYW4gdXNlIGl0XFxyXFxuICAgICAgICB2Y
2XIgc2NvcmUgPSBzY29yZUZuKG9ialJlc3VsdHMpXFxyXFxuICAgICAgICBpZihzY29yZSA9PT0gTlVMTCkgY29udGludWVcXHJcXG4gICAgICAgIGlmKHNjb3JlIDwgdGhyZXNob2xkKSBjb250aW51ZVxcclxcbiAgICAgICAgb2JqUmVzdWx0cy5zY29yZSA9IHNjb3JlXFxyXFxuICAgICAgICBpZihyZXN1bHRzTGVuIDwgbGltaXQpIHsgcS5hZGQob2JqUmVzdWx0cyk7ICsrcmVzdWx0c0xlbiB9XFxyXFxuICAgICAgICBlbHNlIHtcXHJcXG4gICAgICAgICAgKytsaW1pdGVkQ291bnRcXHJcXG4gICAgICAgICAgaWYoc2NvcmUgPiBxLnBlZWsoKS5zY29yZSkgcS5yZXBsYWNlVG9wKG9ialJlc3VsdHMpXFxyXFxuICAgICAgICB9XFxyXFxuICAgICAgfVxcclxcblxcclxcbiAgICAvLyBubyBrZXlzXFxyXFxuICAgIH0gZWxzZSB7XFxyXFxuICAgICAgZm9yKHZhciBpID0gMDsgaSA8IHRhcmdldHNMZW47ICsraSkgeyB2YXIgdGFyZ2V0ID0gdGFyZ2V0c1tpXVxcclxcbiAgICAgICAgaWYoIXRhcmdldCkgY29udGludWVcXHJcXG4gICAgICAgIGlmKCFpc09iaih0YXJnZXQpKSB0YXJnZXQgPSBnZXRQcmVwYXJlZCh0YXJnZXQpXFxyXFxuXFxyXFxuICAgICAgICBpZigoc2VhcmNoQml0ZmxhZ3MgJiB0YXJnZXQuX2JpdGZsYWdzKSAhPT0gc2VhcmNoQml0ZmxhZ3MpIGNvbnRpbnVlXFxyXFxuICAgICAgICB2YXIgcmVzdWx0ID0gYWxnb3JpdGhtKHByZXBhcmVkU2VhcmNoLCB0YXJnZXQpXFxyXFxuICAgICAgICBpZihyZXN1bHQgPT09IE5VTEwpIGNvbnRpbnVlXFxyXFxuICAgICAgICBpZihyZXN1bHQuc2NvcmUgPCB0aHJlc2hvbGQpIGNvbnRpbnVlXFxyXFxuICAgICAgICBpZihyZXN1bHRzTGVuIDwgbGltaXQpIHsgcS
25hZGQocmVzdWx0KTsgKytyZXN1bHRzTGVuIH1cXHJcXG4gICAgICAgIGVsc2Uge1xcclxcbiAgICAgICAgICArK2xpbWl0ZWRDb3VudFxcclxcbiAgICAgICAgICBpZihyZXN1bHQuc2NvcmUgPiBxLnBlZWsoKS5zY29yZSkgcS5yZXBsYWNlVG9wKHJlc3VsdClcXHJcXG4gICAgICAgIH1cXHJcXG4gICAgICB9XFxyXFxuICAgIH1cXHJcXG5cXHJcXG4gICAgaWYocmVzdWx0c0xlbiA9PT0gMCkgcmV0dXJuIG5vUmVzdWx0c1xcclxcbiAgICB2YXIgcmVzdWx0cyA9IG5ldyBBcnJheShyZXN1bHRzTGVuKVxcclxcbiAgICBmb3IodmFyIGkgPSByZXN1bHRzTGVuIC0gMTsgaSA+PSAwOyAtLWkpIHJlc3VsdHNbaV0gPSBxLnBvbGwoKVxcclxcbiAgICByZXN1bHRzLnRvdGFsID0gcmVzdWx0c0xlbiArIGxpbWl0ZWRDb3VudFxcclxcbiAgICByZXR1cm4gcmVzdWx0c1xcclxcbiAgfVxcclxcblxcclxcblxcclxcbiAgdmFyIGhpZ2hsaWdodCA9IChyZXN1bHQsIGhPcGVuLCBoQ2xvc2UpID0+IHtcXHJcXG4gICAgaWYodHlwZW9mIGhPcGVuID09PSAnZnVuY3Rpb24nKSByZXR1cm4gaGlnaGxpZ2h0Q2FsbGJhY2socmVzdWx0LCBoT3BlbilcXHJcXG4gICAgaWYocmVzdWx0ID09PSBOVUxMKSByZXR1cm4gTlVMTFxcclxcbiAgICBpZihoT3BlbiA9PT0gdW5kZWZpbmVkKSBoT3BlbiA9ICc8Yj4nXFxyXFxuICAgIGlmKGhDbG9zZSA9PT0gdW5kZWZpbmVkKSBoQ2xvc2UgPSAnPC9iPidcXHJcXG4gICAgdmFyIGhpZ2hsaWdodGVkID0gJydcXHJcXG4gICAgdmFyIG1hdGNoZXNJbmRleCA9IDBcXHJcXG4gICAgdmFyIG9wZW5lZCA9IGZhbHNlXFxyXFxuICAgIHZhciB0YXJnZXQgPSByZXN1bHQudGFyZ2V0XFxyXFxuICAgIHZhciB0YXJnZXRMZW4gPSB0YXJnZXQubGVuZ3RoXFxyXFxuICAgIHZhciBpbmRleGVzID0gcmVzdWx0Ll9pbmRleGVzXFxyXFxuICAgIGluZGV4ZXMgPSBpbmRleGVzLnNsaWNlKDAsIGluZGV4ZXMubGVuKS5zb3J0KChhLGIpPT5hLWIpXFxyXFxuICAgIGZvcih2YXIgaSA9IDA7IGkgPCB0YXJnZXRMZW47ICsraSkgeyB2YXIgY2hhciA9IHRhcmdldFtpXVxcclxcbiAgICAgIGlmKGluZGV4ZXNbbWF0Y2hlc0luZGV4XSA9PT0gaSkge1xcclxcbiAgICAgICAgKyttYXRjaGVzSW5kZXhcXHJcXG4gICAgICAgIGlmKCFvcGVuZWQpIHsgb3BlbmVkID0gdHJ1ZVxcclxcbiAgICAgICAgICBoaWdobGlnaHRlZCArPSBoT3BlblxcclxcbiAgICAgICAgfVxcclxcblxcclxcbiAgICAgICAgaWYobWF0Y2hlc0luZGV4ID09PSBpbmRleGVzLmxlbmd0aCkge1xcclxcbiAgICAgICAgICBoaWdobGlnaHRlZCArPSBjaGFyICsgaENsb3NlICsgdGFyZ2V0LnN1YnN0cihpKzEpXFxyXFxuICAgICAgICAgIGJyZWFrXFxyXFxuICAgICAgICB9XFxyXFxuICAgICAgfSBlbHNlIHtcXHJcXG4gICAgICAgIGlmKG9wZW5lZCkgeyBvcGVuZWQgPSBmYWxzZVxcclxcbiAgICAgICAgICBoaWdobGlnaHRlZCArPSBoQ2xvc2VcXHJcXG4gICAgICAgIH1cXHJcXG4gICAgICB9XFxyXFxuICAgICAgaGlnaGxpZ2h0ZWQgKz0gY2hhclxcclxcbiAgICB9XFxyXFxuXFxyXFxuICAgIHJldHVybiBoaWdobGlnaHRlZFxcclxcbiAgfVxcclxcbiAgdmFyIGhpZ2hsaWdodENhbGxiYWNrID0gKHJlc3VsdCwgY2IpID0+IHtcXHJcXG4gICAgaWYocmVzdWx0ID09PSBOVUxMKSByZXR1cm4gTlVMTFxcclxcbiAgICB2YXIgdGFyZ2V0ID0gcmVzdWx0LnRhcmdldFxcclxcbiAgICB2YXIgdGFyZ2V0TGVuID0gdGFyZ2V0Lmxlbmd0aFxcclxcbiAgICB2YXIgaW5kZXhlcyA9IHJlc3VsdC5faW5kZXhlc1xcclxcbiAgICBpbmRleGVzID0gaW5kZXhlcy5zbGljZSgwLCBpbmRleGVzLmxlbikuc29ydCgoYSxiKT0+YS1iKVxcclxcbiAgICB2YXIgaGlnaGxpZ2h0ZWQgPSAnJ1xcclxcbiAgICB2YXIgbWF0Y2hJID0gMFxcclxcbiAgICB2YXIgaW5kZXhlc0kgPSAwXFxyXFxuICAgIHZhciBvcGVuZWQgPSBmYWxzZVxcclxcbiAgICB2YXIgcmVzdWx0ID0gW11cXHJcXG4gICAgZm9yKHZhciBpID0gMDsgaSA8IHRhcmdldExlbjsgKytpKSB7IHZhciBjaGFyID0gdGFyZ2V0W2ldXFxyXFxuICAgICAgaWYoaW5kZXhlc1tpbmRleGVzSV0gPT09IGkpIHtcXHJcXG4gICAgICAgICsraW5kZXhlc0lcXHJcXG4gICAgICAgIGlmKCFvcGVuZWQpIHsgb3BlbmVkID0gdHJ1ZVxcclxcbiAgICAgICAgICByZXN1bHQucHVzaChoaWdobGlnaHRlZCk7IGhpZ2hsaWdodGVkID0gJydcXHJcXG4gICAgICAgIH1cXHJcXG5cXHJcXG4gICAgICAgIGlmKGluZGV4ZXNJID09PSBpbmRleGVzLmxlbmd0aCkge1xcclxcbiAgICAgICAgICBoaWdobGlnaHRlZCArPSBjaGFyXFxyXFxuICAgICAgICAgIHJlc3VsdC5wdXNoKGNiKGhpZ2hsaWdodGVkLCBtYXRjaEkrKykpOyBoaWdobGlnaHRlZCA9ICcnXFxyXFxuICAgICAgICAgIHJlc3VsdC5wdXNoKHRhcmdldC5zdWJzdHIoaSsxKSlcXHJcXG4gICAgICAgICAgYnJlYWtcXHJcXG4gICAgICAgIH1cXHJcXG4gICAgICB9IGVsc2Uge1xcclxcbiAgICAgICAgaWYob3BlbmVkKSB7IG9wZW5lZCA9IGZhbHNlXFxyXFxuICAgICAgICAgIHJlc3VsdC5wdXNoKGNiKGhpZ2hsaWdodGVkLCBtYXRjaEkrKykpOyBoaWdobGlnaHRlZCA9ICcnXFxyXFxuICAgICAgICB9XFxyXFxuICAgICAgfVxcclxcbiAgICAgIGhpZ2hsaWdodGVkICs9IGNoYXJcXHJcXG4gICAgfVxcclxcbiAgICByZXR1cm4gcmVzdWx0XFxyXFxuICB9XFxyXFxuXFxyXFxuXFxyXFxuICB2YXIgaW5kZXhlcyA9IHJlc3VsdCA9PiByZXN1bHQuX2luZGV4ZXMuc2xpY2UoMCwgcmVzdWx0Ll9pbmRleGVzLmxlbikuc29ydCgoYSxiKT0+YS1iKVxcclxcblxcclxcblxcclxcbiAgdmFyIHByZXBhcmUgPSAodGFyZ2V0KSA9PiB7XFxyXFxuICAgIGlmKHR5cGVvZiB0YXJnZXQgIT09ICdzdHJpbmcnKSB0YXJnZXQgPSAnJ1xcclxcbiAgICB2YXIgaW5mbyA9IHByZXBhcmVMb3dlckluZm8odGFyZ2V0KVxcclxcbiAgICByZXR1cm4geyd0YXJnZXQnOnRhcmdldCwgX3RhcmdldExvd2VyOmluZm8uX2xvd2VyLCBfdGFyZ2V0TG93ZXJDb2RlczppbmZvLmxvd2VyQ29kZXMsIF9uZXh0QmVnaW5uaW5nSW5kZXhlczpOVUxMLCBfYml0ZmxhZ3M6aW5mby5iaXRmbGFncywgJ3Njb3JlJzpOVUxMLCBfaW5kZXhlczpbMF0sICdvYmonOk5VTEx9IC8vIGhpZGRlblxcclxcbiAgfVxcclxcblxcclxcblxcclxcbiAgLy8gQmVsb3cgdGhpcyBwb2ludCBpcyBvbmx5IGludGVybmFsIGNvZGVcXHJcXG4gIC8vIEJlbG93IHRoaXMgcG9pbnQgaXMgb25seSBpbnRlcm5hbCBjb2RlXFxyX
2FxuICAvLyBCZWxvdyB0aGlzIHBvaW50IGlzIG9ubHkgaW50ZXJuYWwgY29kZVxcclxcbiAgLy8gQmVsb3cgdGhpcyBwb2ludCBpcyBvbmx5IGludGVybmFsIGNvZGVcXHJcXG5cXHJcXG5cXHJcXG4gIHZhciBwcmVwYXJlU2VhcmNoID0gKHNlYXJjaCkgPT4ge1xcclxcbiAgICBpZih0eXBlb2Ygc2VhcmNoICE9PSAnc3RyaW5nJykgc2VhcmNoID0gJydcXHJcXG4gICAgc2VhcmNoID0gc2VhcmNoLnRyaW0oKVxcclxcbiAgICB2YXIgaW5mbyA9IHByZXBhcmVMb3dlckluZm8oc2VhcmNoKVxcclxcblxcclxcbiAgICB2YXIgc3BhY2VTZWFyY2hlcyA9IFtdXFxyXFxuICAgIGlmKGluZm8uY29udGFpbnNTcGFjZSkge1xcclxcbiAgICAgIHZhciBzZWFyY2hlcyA9IHNlYXJjaC5zcGxpdCgvXFxcXHMrLylcXHJcXG4gICAgICBzZWFyY2hlcyA9IFsuLi5uZXcgU2V0KHNlYXJjaGVzKV0gLy8gZGlzdGluY3RcXHJcXG4gICAgICBmb3IodmFyIGk9MDsgaTxzZWFyY2hlcy5sZW5ndGg7IGkrKykge1xcclxcbiAgICAgICAgaWYoc2VhcmNoZXNbaV0gPT09ICcnKSBjb250aW51ZVxcclxcbiAgICAgICAgdmFyIF9pbmZvID0gcHJlcGFyZUxvd2VySW5mbyhzZWFyY2hlc1tpXSlcXHJcXG4gICAgICAgIHNwYWNlU2VhcmNoZXMucHVzaCh7bG93ZXJDb2RlczpfaW5mby5sb3dlckNvZGVzLCBfbG93ZXI6c2VhcmNoZXNbaV0udG9Mb3dlckNhc2UoKSwgY29udGFpbnNTcGFjZTpmYWxzZX0pXFxyXFxuICAgICAgfVxcclxcbiAgICB9XFxyXFxuXFxyXFxuICAgIHJldHVybiB7bG93ZXJDb2RlczogaW5mby5sb3dlckNvZGVzLCBiaXRmbGFnczogaW5mby5iaXRmbGFncywgY29udGFpbnNTcGFjZTogaW5mby5jb250YWluc1NwYWNlLCBfbG93ZXI6IGluZm8uX2xvd2VyLCBzcGFjZVNlYXJjaGVzOiBzcGFjZVNlYXJjaGVzfVxcclxcbiAgfVxcclxcblxcclxcblxcclxcblxcclxcbiAgdmFyIGdldFByZXBhcmVkID0gKHRhcmdldCkgPT4ge1xcclxcbiAgICBpZih0YXJnZXQubGVuZ3RoID4gOTk5KSByZXR1cm4gcHJlcGFyZSh0YXJnZXQpIC8vIGRvbid0IGNhY2hlIGh1Z2UgdGFyZ2V0c1xcclxcbiAgICB2YXIgdGFyZ2V0UHJlcGFyZWQgPSBwcmVwYXJlZENhY2hlLmdldCh0YXJnZXQpXFxyXFxuICAgIGlmKHRhcmdldFByZXBhcmVkICE9PSB1bmRlZmluZWQpIHJldHVybiB0YXJnZXRQcmVwYXJlZFxcclxcbiAgICB0YXJnZXRQcmVwYXJlZCA9IHByZXBhcmUodGFyZ2V0KVxcclxcbiAgICBwcmVwYXJlZENhY2hlLnNldCh0YXJnZXQsIHRhcmdldFByZXBhcmVkKVxcclxcbiAgICByZXR1cm4gdGFyZ2V0UHJlcGFyZWRcXHJcXG4gIH1cXHJcXG4gIHZhciBnZXRQcmVwYXJlZFNlYXJjaCA9IChzZWFyY2gpID0+IHtcXHJcXG4gICAgaWYoc2VhcmNoLmxlbmd0aCA+IDk5OSkgcmV0dXJuIHByZXBhcmVTZWFyY2goc2VhcmNoKSAvLyBkb24ndCBjYWNoZSBodWdlIHNlYXJjaGVzXFxyXFxuICAgIHZhciBzZWFyY2hQcmVwYXJlZCA9IHByZXBhcmVkU2VhcmNoQ2FjaGUuZ2V0KHNlYXJjaClcXHJcXG4gICAgaWYoc2VhcmNoUHJlcGFyZWQgIT09IHVuZGVmaW5lZCkgcmV0dXJuIHNlYXJjaFByZXBhcmVkXFxyXFxuICAgIHNlYXJjaFByZXBhcmVkID0gcHJlcGFyZVNlYXJjaChzZWFyY2gpXFxyXFxuICAgIHByZXBhcmVkU2VhcmNoQ2FjaGUuc2V0KHNlYXJjaCwgc2VhcmNoUHJlcGFyZWQpXFxyXFxuICAgIHJldHVybiBzZWFyY2hQcmVwYXJlZFxcclxcbiAgfVxcclxcblxcclxcblxcclxcbiAgdmFyIGFsbCA9IChzZWFyY2gsIHRhcmdldHMsIG9wdGlvbnMpID0+IHtcXHJcXG4gICAgdmFyIHJlc3VsdHMgPSBbXTsgcmVzdWx0cy50b3RhbCA9IHRhcmdldHMubGVuZ3RoXFxyXFxuXFxyXFxuICAgIHZhciBsaW1pdCA9IG9wdGlvbnMgJiYgb3B0aW9ucy5saW1pdCB8fCBJTlRfTUFYXFxyXFxuXFxyXFxuICAgIGlmKG9wdGlvbnMgJiYgb3B0aW9ucy5rZXkpIHtcXHJcXG4gICAgICBmb3IodmFyIGk9MDtpPHRhcmdldHMubGVuZ3RoO2krKykgeyB2YXIgb2JqID0gdGFyZ2V0c1tpXVxcclxcbiAgICAgICAgdmFyIHRhcmdldCA9IGdldFZhbHVlKG9iaiwgb3B0aW9ucy5rZXkpXFxyXFxuICAgICAgICBpZighdGFyZ2V0KSBjb250aW51ZVxcclxcbiAgICAgICAgaWYoIWlzT2JqKHRhcmdldCkpIHRhcmdldCA9IGdldFByZXBhcmVkKHRhcmdldClcXHJcXG4gICAgICAgIHRhcmdldC5zY29yZSA9IElOVF9NSU5cXHJcXG4gICAgICAgIHRhcmdldC5faW5kZXhlcy5sZW4gPSAwXFxyXFxuICAgICAgICB2Y
2XIgcmVzdWx0ID0gdGFyZ2V0XFxyXFxuICAgICAgICByZXN1bHQgPSB7dGFyZ2V0OnJlc3VsdC50YXJnZXQsIF90YXJnZXRMb3dlcjonJywgX3RhcmdldExvd2VyQ29kZXM6TlVMTCwgX25leHRCZWdpbm5pbmdJbmRleGVzOk5VTEwsIF9iaXRmbGFnczowLCBzY29yZTp0YXJnZXQuc2NvcmUsIF9pbmRleGVzOk5VTEwsIG9iajpvYmp9IC8vIGhpZGRlblxcclxcbiAgICAgICAgcmVzdWx0cy5wdXNoKHJlc3VsdCk7IGlmKHJlc3VsdHMubGVuZ3RoID49IGxpbWl0KSByZXR1cm4gcmVzdWx0c1xcclxcbiAgICAgIH1cXHJcXG4gICAgfSBlbHNlIGlmKG9wdGlvbnMgJiYgb3B0aW9ucy5rZXlzKSB7XFxyXFxuICAgICAgZm9yKHZhciBpPTA7aTx0YXJnZXRzLmxlbmd0aDtpKyspIHsgdmFyIG9iaiA9IHRhcmdldHNbaV1cXHJcXG4gICAgICAgIHZhciBvYmpSZXN1bHRzID0gbmV3IEFycmF5KG9wdGlvbnMua2V5cy5sZW5ndGgpXFxyXFxuICAgICAgICBmb3IgKHZhciBrZXlJID0gb3B0aW9ucy5rZXlzLmxlbmd0aCAtIDE7IGtleUkgPj0gMDsgLS1rZXlJKSB7XFxyXFxuICAgICAgICAgIHZhciB0YXJnZXQgPSBnZXRWYWx1ZShvYmosIG9wdGlvbnMua2V5c1trZXlJXSlcXHJcXG4gICAgICAgICAgaWYoIXRhcmdldCkgeyBvYmpSZXN1bHRzW2tleUldID0gTlVMTDsgY29udGludWUgfVxcclxcbiAgICAgICAgICBpZighaXNPYmoodGFyZ2V0KSkgdGFyZ2V0ID0gZ2V0UHJlcGFyZWQodGFyZ2V0KVxcclxcbiAgICAgICAgICB0YXJnZXQuc2NvcmUgPSBJTlRfTUlOXFxyXFxuICAgICAgICAgIHRhcmdldC5faW5kZXhlcy5sZW4gPSAwXFxyXFxuICAgICAgICAgIG9ialJlc3VsdHNba2V5SV0gPSB0YXJnZXRcXHJcXG4gICAgICAgIH1cXHJcXG4gICAgICAgIG9ialJlc3VsdHMub2JqID0gb2JqXFxyXFxuICAgICAgICBvYmpSZXN1bHRzLnNjb3JlID0gSU5UX01JTlxcclxcbiAgICAgICAgcmVzdWx0cy5wdXNoKG9ialJlc3VsdHMpOyBpZihyZXN1bHRzLmxlbmd0aCA+PSBsaW1pdCkgcmV0dXJuIHJlc3VsdHNcXHJcXG4gICAgICB9XFxyXFxuICAgIH0gZWxzZSB7XFxyXFxuICAgICAgZm9yKHZhciBpPTA7aTx0YXJnZXRzLmxlbmd0aDtpKyspIHsgdmFyIHRhcmdldCA9IHRhcmdldHNbaV1cXHJcXG4gICAgICAgIGlmKCF0YXJnZXQpIGNvbnRpbnVlXFxyXFxuICAgICAgICBpZighaXNPYmoodGFyZ2V0KSkgdGFyZ2V0ID0gZ2V0UHJlcGFyZWQodGFyZ2V0KVxcclxcbiAgICAgICAgdGFyZ2V0LnNjb3JlID0gSU5UX01JTlxcclxcbiAgICAgICAgdGFyZ2V0Ll9pbmRleGVzLmxlbiA9IDBcXHJcXG4gICAgICAgIHJlc3VsdHMucHVzaCh0YXJnZXQpOyBpZihyZXN1bHRzLmxlbmd0aCA+PSBsaW1pdCkgcmV0dXJuIHJlc3VsdHNcXHJcXG4gICAgICB9XFxyXFxuICAgIH1cXHJcXG5cXHJcXG4gICAgcmV0dXJuIHJlc3VsdHNcXHJcXG4gIH1cXHJcXG5cXHJcXG5cXHJcXG4gIHZhciBhbGdvcml0aG0gPSAocHJlcGFyZWRTZWFyY2gsIHByZXBhcmVkLCBhbGxvd1NwYWNlcz1mYWxzZSkgPT4ge1xcclxcbiAgICBpZihhbGxvd1NwYWNlcz09PWZhbHNlICYmIHByZXBhcmVkU2VhcmNoLmNvbnRhaW5zU3BhY2UpIHJldHVybiBhbGdvcml0aG1TcGFjZXMocHJlcGFyZWRTZWFyY2gsIHByZXBhcmVkKVxcclxcblxcclxcbiAgICB2YXIgc2VhcmNoTG93ZXIgPSBwcmVwYXJlZFNlYXJjaC5fbG93ZXJcXHJcXG4gICAgdmFyIHNlYXJjaExvd2VyQ29kZXMgPSBwcmVwYXJlZFNlYXJjaC5sb3dlckNvZGVzXFxyXFxuICAgIHZhciBzZWFyY2hMb3dlckNvZGUgPSBzZWFyY2hMb3dlckNvZGVzWzBdXFxyXFxuICAgIHZhciB0YXJnZXRMb3dlckNvZGVzID0gcHJlcGFyZWQuX3RhcmdldExvd2VyQ29kZXNcXHJcXG4gICAgdmFyIHNlYXJjaExlbiA9IHNlYXJjaExvd2VyQ29kZXMubGVuZ3RoXFxyXFxuICAgIHZhciB0YXJnZXRMZW4gPSB0YXJnZXRMb3dlckNvZGVzLmxlbmd0aFxcclxcbiAgICB2YXIgc2VhcmNoSSA9IDAgLy8gd2hlcmUgd2UgYXRcXHJcXG4gICAgdmFyIHRhcmdldEkgPSAwIC8vIHdoZXJlIHlvdSBhdFxcclxcbiAgICB2YXIgbWF0Y2hlc1NpbXBsZUxlbiA9IDBcXHJcXG5cXHJcXG4gICAgLy8gdmVyeSBiYXNpYyBmdXp6eSBtYXRjaDsgdG8gcmVtb3ZlIG5vbi1tYXRjaGluZyB0YXJnZXRzIEFTQVAhXFxyXFxuICAgIC8vIHdhbGsgdGhyb3VnaCB0YXJnZXQuIGZpbmQgc2VxdWVudGlhbCBtYXRjaGVzLlxcclxcbiAgICAvLyBpZiBhbGwgY2hhcnMgYXJlbid0IGZvdW5kIHRoZW4gZXhpdFxcclxcbiAgICBmb3IoOzspIHtcXHJcXG4gICAgICB2Y
2XIgaXNNYXRjaCA9IHNlYXJjaExvd2VyQ29kZSA9PT0gdGFyZ2V0TG93ZXJDb2Rlc1t0YXJnZXRJXVxcclxcbiAgICAgIGlmKGlzTWF0Y2gpIHtcXHJcXG4gICAgICAgIG1hdGNoZXNTaW1wbGVbbWF0Y2hlc1NpbXBsZUxlbisrXSA9IHRhcmdldElcXHJcXG4gICAgICAgICsrc2VhcmNoSTsgaWYoc2VhcmNoSSA9PT0gc2VhcmNoTGVuKSBicmVha1xcclxcbiAgICAgICAgc2VhcmNoTG93ZXJDb2RlID0gc2VhcmNoTG93ZXJDb2Rlc1tzZWFyY2hJXVxcclxcbiAgICAgIH1cXHJcXG4gICAgICArK3RhcmdldEk7IGlmKHRhcmdldEkgPj0gdGFyZ2V0TGVuKSByZXR1cm4gTlVMTCAvLyBGYWlsZWQgdG8gZmluZCBzZWFyY2hJXFxyXFxuICAgIH1cXHJcXG5cXHJcXG4gICAgdmFyIHNlYXJjaEkgPSAwXFxyXFxuICAgIHZhciBzdWNjZXNzU3RyaWN0ID0gZmFsc2VcXHJcXG4gICAgdmFyIG1hdGNoZXNTdHJpY3RMZW4gPSAwXFxyXFxuXFxyXFxuICAgIHZhciBuZXh0QmVnaW5uaW5nSW5kZXhlcyA9IHByZXBhcmVkLl9uZXh0QmVnaW5uaW5nSW5kZXhlc1xcclxcbiAgICBpZihuZXh0QmVnaW5uaW5nSW5kZXhlcyA9PT0gTlVMTCkgbmV4dEJlZ2lubmluZ0luZGV4ZXMgPSBwcmVwYXJlZC5fbmV4dEJlZ2lubmluZ0luZGV4ZXMgPSBwcmVwYXJlTmV4dEJlZ2lubmluZ0luZGV4ZXMocHJlcGFyZWQudGFyZ2V0KVxcclxcbiAgICB2YXIgZmlyc3RQb3NzaWJsZUkgPSB0YXJnZXRJID0gbWF0Y2hlc1NpbXBsZVswXT09PTAgPyAwIDogbmV4dEJlZ2lubmluZ0luZGV4ZXNbbWF0Y2hlc1NpbXBsZVswXS0xXVxcclxcblxcclxcbiAgICAvLyBPdXIgdGFyZ2V0IHN0cmluZyBzdWNjZXNzZnVsbHkgbWF0Y2hlZCBhbGwgY2hhcmFjdGVycyBpbiBzZXF1ZW5jZSFcXHJcXG4gICAgLy8gTGV0J3MgdHJ5IGEgbW9yZSBhZHZhbmNlZCBhbmQgc3RyaWN0IHRlc3QgdG8gaW1wcm92ZSB0aGUgc2NvcmVcXHJcXG4gICAgLy8gb25seSBjb3VudCBpdCBhcyBh
2IG1hdGNoIGlmIGl0J3MgY29uc2VjdXRpdmUgb3IgYSBiZWdpbm5pbmcgY2hhcmFjdGVyIVxcclxcbiAgICB2YXIgYmFja3RyYWNrQ291bnQgPSAwXFxyXFxuICAgIGlmKHRhcmdldEkgIT09IHRhcmdldExlbikgZm9yKDs7KSB7XFxyXFxuICAgICAgaWYodGFyZ2V0SSA+PSB0YXJnZXRMZW4pIHtcXHJcXG4gICAgICAgIC8vIFdlIGZhaWxlZCB0byBmaW5kIGEgZ29vZCBzcG90IGZvciB0aGlzIHNlYXJjaCBjaGFyLCBnbyBiYWNrIHRvIHRoZSBwcmV2aW91cyBzZWFyY2ggY2hhciBhbmQgZm9yY2UgaXQgZm9yd2FyZFxcclxcbiAgICAgICAgaWYoc2VhcmNoSSA8PSAwKSBicmVhayAvLyBXZSBmYWlsZWQgdG8gcHVzaCBjaGFycyBmb3J3YXJkIGZvciBhIGJldHRlciBtYXRjaFxcclxcblxcclxcbiAgICAgICAgKytiYWNrdHJhY2tDb3VudDsgaWYoYmFja3RyYWNrQ291bnQgPiAyMDApIGJyZWFrIC8vIGV4cG9uZW50aWFsIGJhY2t0cmFja2luZyBpcyB0YWtpbmcgdG9vIGxvbmcsIGp1c3QgZ2l2ZSB1cCBhbmQgcmV0dXJuIGEgYmFkIG1hdGNoXFxyXFxuXFxyXFxuICAgICAgICAtLXNlYXJjaElcXHJcXG4gICAgICAgIHZhciBsYXN0TWF0Y2ggPSBtYXRjaGVzU3RyaWN0Wy0tbWF0Y2hlc1N0cmljdExlbl1cXHJcXG4gICAgICAgIHRhcmdldEkgPSBuZXh0QmVnaW5uaW5nSW5kZXhlc1tsYXN0TWF0Y2hdXFxyXFxuXFxyXFxuICAgICAgfSBlbHNlIHtcXHJcXG4gICAgICAgIHZhciBpc01hdGNoID0gc2VhcmNoTG93ZXJDb2Rlc1tzZWFyY2hJXSA9PT0gdGFyZ2V0TG93ZXJDb2Rlc1t0YXJnZXRJXVxcclxcbiAgICAgICAgaWYoaXNNYXRjaCkge1xcclxcbiAgICAgICAgICBtYXRjaGVzU3RyaWN0W21hdGNoZXNTdHJpY3RMZW4rK10gPSB0YXJnZXRJXFxyXFxuICAgICAgICAgICsrc2VhcmNoSTsgaWYoc2VhcmNoSSA9PT0gc2VhcmNoTGVuKSB7IHN1Y2Nlc3NTdHJpY3QgPSB0cnVlOyBicmVhayB9XFxyXFxuICAgICAgICAgICsrdGFyZ2V0SVxcclxcbiAgICAgICAgfSBlbHNlIHtcXHJcXG4gICAgICAgICAgdGFyZ2V0SSA9IG5leHRCZWdpbm5pbmdJbmRleGVzW3RhcmdldEldXFxyXFxuICAgICAgICB9XFxyXFxuICAgICAgfVxcclxcbiAgICB9XFxyXFxuXFxyXFxuICAgIC8vIGNoZWNrIGlmIGl0J3MgYSBzdWJzdHJpbmcgbWF0Y2hcXHJcXG4gICAgdmFyIHN1YnN0cmluZ0luZGV4ID0gcHJlcGFyZWQuX3RhcmdldExvd2VyLmluZGV4T2Yoc2VhcmNoTG93ZXIsIG1hdGNoZXNTaW1wbGVbMF0pIC8vIHBlcmY6IHRoaXMgaXMgc2xvd1xcclxcbiAgICB2YXIgaXNTdWJzdHJpbmcgPSB+c3Vic3RyaW5nSW5kZXhcXHJcXG4gICAgaWYoaXNTdWJzdHJpbmcgJiYgIXN1Y2Nlc3NTdHJpY3QpIHsgLy8gcmV3cml0ZSB0aGUgaW5kZXhlcyBmcm9tIGJhc2ljIHRvIHRoZSBzdWJzdHJpbmdcXHJcXG4gICAgICBmb3IodmFyIGk9MDsgaTxtYXRjaGVzU2ltcGxlTGVuOyArK2kpIG1hdGNoZXNTaW1wbGVbaV0gPSBzdWJzdHJpbmdJbmRleCtpXFxyXFxuICAgIH1cXHJcXG4gICAgdmFyIGlzU3Vic3RyaW5nQmVnaW5uaW5nID0gZmFsc2VcXHJcXG4gICAgaWYoaXNTdWJzdHJpbmcpIHtcXHJcXG4gICAgICBpc1N1YnN0cmluZ0JlZ2lubmluZyA9IHByZXBhcmVkLl9uZXh0QmVnaW5uaW5nSW5kZXhlc1tzdWJzdHJpbmdJbmRleC0xXSA9PT0gc3Vic3RyaW5nSW5kZXhcXHJcXG4gICAgfVxcclxcblxcclxcbiAgICB7IC8vIHRhbGx5IHVwIHRoZSBzY29yZSAmIGtlZXAgdHJhY2sgb2YgbWF0Y2hlcyBmb3IgaGlnaGxpZ2h0aW5nIGxhdGVyXFxyXFxuICAgICAgaWYoc3VjY2Vzc1N0cmljdCkgeyB2YXIgbWF0Y2hlc0Jlc3QgPSBtYXRjaGVzU3RyaWN0OyB2YXIgbWF0Y2hlc0Jlc3RMZW4gPSBtYXRjaGVzU3RyaWN0TGVuIH1cXHJcXG4gICAgICBlbHNlIHsgdmFyIG1hdGNoZXNCZXN0ID0gbWF0Y2hlc1NpbXBsZTsgdmFyIG1hdGNoZXNCZXN0TGVuID0gbWF0Y2hlc1NpbXBsZUxlbiB9XFxyXFxuXFxyXFxuICAgICAgdmFyIHNjb3JlID0gMFxcclxcblxcclxcbiAgICAgIHZhciBleHRyYU1hdGNoR3JvdXBDb3VudCA9IDBcXHJcXG4gICAgICBmb3IodmFyIGkgPSAxOyBpIDwgc2VhcmNoTGVuOyArK2kpIHtcXHJcXG4gICAgICAgIGlmKG1hdGNoZXNCZXN0W2ldIC0gbWF0Y2hlc0Jlc3RbaS0xXSAhPT0gMSkge3Njb3JlIC09IG1hdGNoZXNCZXN0W2ldOyArK2V4dHJhTWF0Y2hHcm91cENvdW50fVxcclxcbiAgICAgIH1cXHJcXG4gICAgICB2Y
2XIgdW5tYXRjaGVkRGlzdGFuY2UgPSBtYXRjaGVzQmVzdFtzZWFyY2hMZW4tMV0gLSBtYXRjaGVzQmVzdFswXSAtIChzZWFyY2hMZW4tMSlcXHJcXG5cXHJcXG4gICAgICBzY29yZSAtPSAoMTIrdW5tYXRjaGVkRGlzdGFuY2UpICogZXh0cmFNYXRjaEdyb3VwQ291bnQgLy8gcGVuYWxpdHkgZm9yIG1vcmUgZ3JvdXBzXFxyXFxuXFxyXFxuICAgICAgaWYobWF0Y2hlc0Jlc3RbMF0gIT09IDApIHNjb3JlIC09IG1hdGNoZXNCZXN0WzBdKm1hdGNoZXNCZXN0WzBdKi4yIC8vIHBlbmFsaXR5IGZvciBub3Qgc3RhcnRpbmcgbmVhciB0aGUgYmVnaW5uaW5nXFxyXFxuXFxyXFxuICAgICAgaWYoIXN1Y2Nlc3NTdHJpY3QpIHtcXHJcXG4gICAgICAgIHNjb3JlICo9IDEwMDBcXHJcXG4gICAgICB9IGVsc2Uge1xcclxcbiAgICAgICAgLy8gc3VjY2Vzc1N0cmljdCBvbiBhIHRhcmdldCB3aXRoIHRvbyBtYW55IGJlZ2lubmluZyBpbmRleGVzIGxvc2VzIHBvaW50cyBmb3IgYmVpbmcgYSBiYWQgdGFyZ2V0XFxyXFxuICAgICAgICB2YXIgdW5pcXVlQmVnaW5uaW5nSW5kZXhlcyA9IDFcXHJcXG4gICAgICAgIGZvcih2YXIgaSA9IG5leHRCZWdpbm5pbmdJbmRleGVzWzBdOyBpIDwgdGFyZ2V0TGVuOyBpPW5leHRCZWdpbm5pbmdJbmRleGVzW2ldKSArK3VuaXF1ZUJlZ2lubmluZ0luZGV4ZXNcXHJcXG5cXHJcXG4gICAgICAgIGlmKHVuaXF1ZUJlZ2lubmluZ0luZGV4ZXMgPiAyNCkgc2NvcmUgKj0gKHVuaXF1ZUJlZ2lubmluZ0luZGV4ZXMtMjQpKjEwIC8vIHF1aXRlIGFyYml0cmFyeSBudW1iZXJzIGhlcmUgLi4uXFxyXFxuICAgICAgfVxcclxcblxcclxcbiAgICAgIGlmKGlzU3Vic3RyaW5nKSAgICAgICAgICBzY29yZSAvPSAxK3NlYXJjaExlbipzZWFyY2hMZW4qMSAvLyBib251cyBmb3IgYmVpbmcgYSBmdWxsIHN1YnN0cmluZ1xcclxcbiAgICAgIGlmKGlzU3Vic3RyaW5nQmVnaW5uaW5nKSBzY29yZSAvPSAxK3NlYXJjaExlbipzZWFyY2hMZW4qMSAvLyBib251cyBmb3Igc3Vic3RyaW5nIHN0YXJ0aW5nIG9uIGEgYmVnaW5uaW5nSW5kZXhcXHJcXG5cXHJcXG4gICAgICBzY29yZSAtPSB0YXJnZXRMZW4gLSBzZWFyY2hMZW4gLy8gcGVuYWxpdHkgZm9yIGxvbmdlciB0YXJnZXRzXFxyXFxuICAgICAgcHJlcGFyZWQuc2NvcmUgPSBzY29yZVxcclxcblxcclxcbiAgICAgIGZvcih2YXIgaSA9IDA7IGkgPCBtYXRjaGVzQmVzdExlbjsgKytpKSBwcmVwYXJlZC5faW5kZXhlc1tpXSA9IG1hdGNoZXNCZXN0W2ldXFxyXFxuICAgICAgcHJlcGFyZWQuX2luZGV4ZXMubGVuID0gbWF0Y2hlc0Jlc3RMZW5cXHJcXG5cXHJcXG4gICAgICByZXR1cm4gcHJlcGFyZWRcXHJcXG4gICAgfVxcclxcbiAgfVxcclxcbiAgdmFyIGFsZ29yaXRobVNwYWNlcyA9IChwcmVwYXJlZFNlYXJjaCwgdGFyZ2V0KSA9PiB7XFxyXFxuICAgIHZhciBzZWVuX2luZGV4ZXMgPSBuZXcgU2V0KClcXHJcXG4gICAgdmFyIHNjb3JlID0gMFxcclxcbiAgICB2YXIgcmVzdWx0ID0gTlVMTFxcclxcblxcclxcbiAgICB2YXIgZmlyc3Rfc2Vlbl9pbmRleF9sYXN0X3NlYXJjaCA9IDBcXHJcXG4gICAgdmFyIHNlYXJjaGVzID0gcHJlcGFyZWRTZWFyY2guc3BhY2VTZWFyY2hlc1xcclxcbiAgICBmb3IodmFyIGk9MDsgaTxzZWFyY2hlcy5sZW5ndGg7ICsraSkge1xcclxcbiAgICAgIHZhciBzZWFyY2ggPSBzZWFyY2hlc1tpXVxcclxcblxcclxcbiAgICAgIHJlc3VsdCA9IGFsZ29yaXRobShzZWFyY2gsIHRhcmdldClcXHJcXG4gICAgICBpZihyZXN1bHQgPT09IE5VTEwpIHJldHVybiBOVUxMXFxyXFxuXFxyXFxuICAgICAgc2NvcmUgKz0gcmVzdWx0LnNjb3JlXFxyXFxuXFxyXFxuICAgICAgLy8gZG9jayBwb2ludHMgYmFzZWQgb24gb3JkZXIgb3RoZXJ3aXNlIFxcXCJjIG1hblxcXCIgcmV0dXJucyBNYW5pZmVzdC5jcHAgaW5zdGVhZCBvZiBDaGVhdE1hbmFnZXIuaFxcclxcbiAgICAgIGlmKHJlc3VsdC5faW5kZXhlc1swXSA8IGZpcnN0X3NlZW5faW5kZXhfbGFzdF9zZWFyY2gpIHtcXHJcXG4gICAgICAgIHNjb3JlIC09IGZpcnN0X3NlZW5faW5kZXhfbGFzdF9zZWFyY2ggLSByZXN1bHQuX2luZGV4ZXNbMF1cXHJcXG4gICAgICB9XFxyXFxuICAgICAgZmlyc3Rfc2Vlbl9pbmRleF9sYXN0X3NlYXJjaCA9IHJlc3VsdC5faW5kZXhlc1swXVxcclxcblxcclxcbiAgICAgIGZvcih2YXIgaj0wOyBqPHJlc3VsdC5faW5kZXhlcy5sZW47ICsraikgc2Vlbl9pbmRleGVzLmFkZChyZXN1bHQuX2luZGV4ZXNbal0pXFxyXFxuICAgIH1cXHJcXG5cXHJcXG4gICAgLy8gYWxsb3dzIGEgc2VhcmNoIHdpdGggc3BhY2VzIHRoYXQncyBhbiBleGFjdCBzdWJzdHJpbmcgdG8gc2NvcmUgd2VsbFxcclxcbiAgICB2YXIgYWxsb3dTcGFjZXNSZXN1bHQgPSBhbGdvcml0aG0ocHJlcGFyZWRTZWFyY2gsIHRhcmdldCwgLyphbGxvd1NwYWNlcz0qL3RydWUpXFxyXFxuICAgIGlmKGFsbG93U3BhY2VzUmVzdWx0ICE9PSBOVUxMICYmIGFsbG93U3BhY2VzUmVzdWx0LnNjb3JlID4gc2NvcmUpIHtcXHJcXG4gICAgICByZXR1cm4gYWxsb3dTcGFjZXNSZXN1bHRcXHJcXG4gICAgfVxcclxcblxcclxcbiAgICByZXN1bHQuc2NvcmUgPSBzY29yZVxcclxcblxcclxcbiAgICB2YXIgaSA9IDBcXHJcXG4gICAgZm9yIChsZXQgaW5kZXggb2Ygc2Vlbl9pbmRleGVzKSByZXN1bHQuX2luZGV4ZXNbaSsrXSA9IGluZGV4XFxyXFxuICAgIHJlc3VsdC5faW5kZXhlcy5sZW4gPSBpXFxyXFxuXFxyXFxuICAgIHJldHVybiByZXN1bHRcXHJcXG4gIH1cXHJcXG5cXHJcXG5cXHJcXG4gIHZhciBwcmVwYXJlTG93ZXJJbmZvID0gKHN0cikgPT4ge1xcclxcbiAgICB2YXIgc3RyTGVuID0gc3RyLmxlbmd0aFxcclxcbiAgICB2YXIgbG93ZXIgPSBzdHIudG9Mb3dlckNhc2UoKVxcclxcbiAgICB2YXIgbG93ZXJDb2RlcyA9IFtdIC8vIG5ldyBBcnJheShzdHJMZW4pICAgIHNwYXJzZSBhcnJheSBpcyB0b28gc2xvd1xcclxcbiAgICB2YXIgYml0ZmxhZ3MgPSAwXFxyXFxuICAgIHZhciBjb250YWluc1NwYWNlID0gZmFsc2UgLy8gc3BhY2UgaXNuJ3Qgc3RvcmVkIGluIGJpdGZsYWdzIGJlY2F1c2Ugb2YgaG93IHNlYXJjaGluZyB3aXRoIGEgc3BhY2Ugd29ya3NcXHJcXG5cXHJcXG4gICAgZm9yKHZhciBpID0gMDsgaSA8IHN0ckxlbjsgKytpKSB7XFxyXFxuICAgICAgdmFyIGxvd2VyQ29kZSA9IGxvd2VyQ29kZXNbaV0gPSBsb3dlci5jaGFyQ29kZUF0KGkpXFxyXFxuXFxyXFxuICAgICAgaWYobG93ZXJDb2RlID09PSAzMikge1xcclxcbiAgICAgICAgY29udGFpbnNTcGFjZSA9IHRydWVcXHJcXG4gICAgICAgIGNvbnRpbnVlIC8vIGl0J3MgaW1wb3J0YW50IHRoYXQgd2UgZG9uJ3Qgc2V0IGFueSBiaXRmbGFncyBmb3Igc3BhY2VcXHJcXG4gICAgICB9XFxyX
2FxuXFxyXFxuICAgICAgdmFyIGJpdCA9IGxvd2VyQ29kZT49OTcmJmxvd2VyQ29kZTw9MTIyID8gbG93ZXJDb2RlLTk3IC8vIGFscGhhYmV0XFxyXFxuICAgICAgICAgICAgICA6IGxvd2VyQ29kZT49NDgmJmxvd2VyQ29kZTw9NTcgID8gMjYgICAgICAgICAgIC8vIG51bWJlcnNcXHJcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gMyBiaXRzIGF2YWlsYWJsZVxcclxcbiAgICAgICAgICAgICAgOiBsb3dlckNvZGU8PTEyNyAgICAgICAgICAgICAgICA/IDMwICAgICAgICAgICAvLyBvdGhlciBhc2NpaVxcclxcbiAgICAgICAgICAgICAgOiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDMxICAgICAgICAgICAvLyBvdGhlciB1dGY4XFxyXFxuICAgICAgYml0ZmxhZ3MgfD0gMTw8Yml0XFxyXFxuICAgIH1cXHJcXG5cXHJcXG4gICAgcmV0dXJuIHtsb3dlckNvZGVzOmxvd2VyQ29kZXMsIGJpdGZsYWdzOmJpdGZsYWdzLCBjb250YWluc1NwYWNlOmNvbnRhaW5zU3BhY2UsIF9sb3dlcjpsb3dlcn1cXHJcXG4gIH1cXHJcXG4gIHZhciBwcmVwYXJlQmVnaW5uaW5nSW5kZXhlcyA9ICh0YXJnZXQpID0+IHtcXHJcXG4gICAgdmFyIHRhcmdldExlbiA9IHRhcmdldC5sZW5ndGhcXHJcXG4gICAgdmFyIGJlZ2lubmluZ0luZGV4ZXMgPSBbXTsgdmFyIGJlZ2lubmluZ0luZGV4ZXNMZW4gPSAwXFxyXFxuICAgIHZhciB3YXNVcHBlciA9IGZhbHNlXFxyXFxuICAgIHZhciB3YXNBbHBoYW51bSA9IGZhbHNlXFxyXFxuICAgIGZvcih2YXIgaSA9IDA7IGkgPCB0YXJnZXRMZW47ICsraSkge1xcclxcbiAgICAgIHZhciB0YXJnZXRDb2RlID0gdGFyZ2V0LmNoYXJDb2RlQXQoaSlcXHJcXG4gICAgICB2Y
2XIgaXNVcHBlciA9IHRhcmdldENvZGU+PTY1JiZ0YXJnZXRDb2RlPD05MFxcclxcbiAgICAgIHZhciBpc0FscGhhbnVtID0gaXNVcHBlciB8fCB0YXJnZXRDb2RlPj05NyYmdGFyZ2V0Q29kZTw9MTIyIHx8IHRhcmdldENvZGU+PTQ4JiZ0YXJnZXRDb2RlPD01N1xcclxcbiAgICAgIHZhciBpc0JlZ2lubmluZyA9IGlzVXBwZXIgJiYgIXdhc1VwcGVyIHx8ICF3YXNBbHBoYW51bSB8fCAhaXNBbHBoYW51bVxcclxcbiAgICAgIHdhc1VwcGVyID0gaXNVcHBlclxcclxcbiAgICAgIHdhc0FscGhhbnVtID0gaXNBbHBoYW51bVxcclxcbiAgICAgIGlmKGlzQmVnaW5uaW5nKSBiZWdpbm5pbmdJbmRleGVzW2JlZ2lubmluZ0luZGV4ZXNMZW4rK10gPSBpXFxyXFxuICAgIH1cXHJcXG4gICAgcmV0dXJuIGJlZ2lubmluZ0luZGV4ZXNcXHJcXG4gIH1cXHJcXG4gIHZhciBwcmVwYXJlTmV4dEJlZ2lubmluZ0luZGV4ZXMgPSAodGFyZ2V0KSA9PiB7XFxyXFxuICAgIHZhciB0YXJnZXRMZW4gPSB0YXJnZXQubGVuZ3RoXFxyXFxuICAgIHZhciBiZWdpbm5pbmdJbmRleGVzID0gcHJlcGFyZUJlZ2lubmluZ0luZGV4ZXModGFyZ2V0KVxcclxcbiAgICB2YXIgbmV4dEJlZ2lubmluZ0luZGV4ZXMgPSBbXSAvLyBuZXcgQXJyYXkodGFyZ2V0TGVuKSAgICAgc3BhcnNlIGFycmF5IGlzIHRvbyBzbG93XFxyXFxuICAgIHZhciBsYXN0SXNCZWdpbm5pbmcgPSBiZWdpbm5pbmdJbmRleGVzWzBdXFxyXFxuICAgIHZhciBsYXN0SXNCZWdpbm5pbmdJID0gMFxcclxcbiAgICBmb3IodmFyIGkgPSAwOyBpIDwgdGFyZ2V0TGVuOyArK2kpIHtcXHJcXG4gICAgICBpZihsYXN0SXNCZWdpbm5pbmcgPiBpKSB7XFxyXFxuICAgICAgICBuZXh0QmVnaW5uaW5nSW5kZXhlc1tpXSA9IGxhc3RJc0JlZ2lubmluZ1xcclxcbiAgICAgIH0gZWxzZSB7XFxyXFxuICAgICAgICBsYXN0SXNCZWdpbm5pbmcgPSBiZWdpbm5pbmdJbmRleGVzWysrbGFzdElzQmVnaW5uaW5nSV1cXHJcXG4gICAgICAgIG5leHRCZWdpbm5pbmdJbmRleGVzW2ldID0gbGFzdElzQmVnaW5uaW5nPT09dW5kZWZpbmVkID8gdGFyZ2V0TGVuIDogbGFzdElzQmVnaW5uaW5nXFxyXFxuICAgICAgfVxcclxcbiAgICB9XFxyXFxuICAgIHJldHVybiBuZXh0QmVnaW5uaW5nSW5kZXhlc1xcclxcbiAgfVxcclxcblxcclxcblxcclxcbiAgdmFyIGNsZWFudXAgPSAoKSA9PiB7IHByZXBhcmVkQ2FjaGUuY2xlYXIoKTsgcHJlcGFyZWRTZWFyY2hDYWNoZS5jbGVhcigpOyBtYXRjaGVzU2ltcGxlID0gW107IG1hdGNoZXNTdHJpY3QgPSBbXSB9XFxyX
2FxuXFxyXFxuICB2YXIgcHJlcGFyZWRDYWNoZSAgICAgICA9IG5ldyBNYXAoKVxcclxcbiAgdmFyIHByZXBhcmVkU2VhcmNoQ2FjaGUgPSBuZXcgTWFwKClcXHJcXG4gIHZhciBtYXRjaGVzU2ltcGxlID0gW107IHZhciBtYXRjaGVzU3RyaWN0ID0gW11cXHJcXG5cXHJcXG5cXHJcXG4gIC8vIGZvciB1c2Ugd2l0aCBrZXlzLiBqdXN0IHJldHVybnMgdGhlIG1heGltdW0gc2NvcmVcXHJcXG4gIHZhciBkZWZhdWx0U2NvcmVGbiA9IChhKSA9PiB7XFxyXFxuICAgIHZhciBtYXggPSBJTlRfTUlOXFxyXFxuICAgIHZhciBsZW4gPSBhLmxlbmd0aFxcclxcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbjsgKytpKSB7XFxyXFxuICAgICAgdmFyIHJlc3VsdCA9IGFbaV07IGlmKHJlc3VsdCA9PT0gTlVMTCkgY29udGludWVcXHJcXG4gICAgICB2YXIgc2NvcmUgPSByZXN1bHQuc2NvcmVcXHJcXG4gICAgICBpZihzY29yZSA+IG1heCkgbWF4ID0gc2NvcmVcXHJcXG4gICAgfVxcclxcbiAgICBpZihtYXggPT09IElOVF9NSU4pIHJldHVybiBOVUxMXFxyXFxuICAgIHJldHVybiBtYXhcXHJcXG4gIH1cXHJcXG5cXHJcXG4gIC8vIHByb3AgPSAna2V5JyAgICAgICAgICAgICAgMi41bXMgb3B0aW1pemVkIGZvciB0aGlzIGNhc2UsIHNlZW1zIHRvIGJlIGFib3V0IGFzIGZhc3QgYXMgZGlyZWN0IG9ialtwcm9wXVxcclxcbiAgLy8gcHJvcCA9ICdrZXkxLmtleTInICAgICAgICAxMG1zXFxyXFxuICAvLyBwcm9wID0gWydrZXkxJywgJ2tleTInXSAgIDI3bXNcXHJcXG4gIHZhciBnZXRWYWx1ZSA9IChvYmosIHByb3ApID0+IHtcXHJcXG4gICAgdmFyIHRtcCA9IG9ialtwcm9wXTsgaWYodG1wICE9PSB1bmRlZmluZWQpIHJldHVybiB0bXBcXHJcXG4gICAgdmFyIHNlZ3MgPSBwcm9wXFxyXFxuICAgIGlmKCFBcnJheS5pc0FycmF5KHByb3ApKSBzZWdzID0gcHJvcC5zcGxpdCgnLicpXFxyXFxuICAgIHZhciBsZW4gPSBzZWdzLmxlbmd0aFxcclxcbiAgICB2YXIgaSA9IC0xXFxyXFxuICAgIHdoaWxlIChvYmogJiYgKCsraSA8IGxlbikpIG9iaiA9IG9ialtzZWdzW2ldXVxcclxcbiAgICByZXR1cm4gb2JqXFxyXFxuICB9XFxyXFxuXFxyXFxuICB2YXIgaXNPYmogPSAoeCkgPT4geyByZXR1cm4gdHlwZW9mIHggPT09ICdvYmplY3QnIH0gLy8gZmFzdGVyIGFzIGEgZnVuY3Rpb25cXHJcXG4gIC8vIHZhciBJTlRfTUFYID0gOTAwNzE5OTI1NDc0MDk5MTsgdmFyIElOVF9NSU4gPSAtSU5UX01BWFxcclxcbiAgdmFyIElOVF9NQVggPSBJbmZpbml0eTsgdmFyIElOVF9NSU4gPSAtSU5UX01BWFxcclxcbiAgdmFyIG5vUmVzdWx0cyA9IFtdOyBub1Jlc3VsdHMudG90YWwgPSAwXFxyXFxuICB2YXIgTlVMTCA9IG51bGxcXHJcXG5cXHJcXG5cXHJcXG4gIC8vIEhhY2tlZCB2ZXJzaW9uIG9mIGh0dHBzOi8vZ2l0aHViLmNvbS9sZW1pcmUvRmFzdFByaW9yaXR5UXVldWUuanNcXHJcXG4gIHZhciBmYXN0cHJpb3JpdHlxdWV1ZT1yPT57dmFyIGU9W10sbz0wLGE9e30sdj1yPT57Zm9yKHZhciBhPTAsdj1lW2FdLGM9MTtjPG87KXt2YXIgcz1jKzE7YT1jLHM8byYmZVtzXS5zY29yZTxlW2NdLnNjb3JlJiYoYT1zKSxlW2EtMT4+MV09ZVthXSxjPTErKGE8PDEpfWZvcih2YXIgZj1hLTE+PjE7YT4wJiZ2LnNjb3JlPGVbZl0uc2NvcmU7Zj0oYT1mKS0xPj4xKWVbYV09ZVtmXTtlW2FdPXZ9O3JldHVybiBhLmFkZD0ocj0+e3ZhciBhPW87ZVtvKytdPXI7Zm9yKHZhciB2PWEtMT4+MTthPjAmJnIuc2NvcmU8ZVt2XS5zY29yZTt2PShhPXYpLTE+PjEpZVthXT1lW3ZdO2VbYV09cn0pLGEucG9sbD0ocj0+e2lmKDAhPT1vKXt2YXIgYT1lWzBdO3JldHVybiBlWzBdPWVbLS1vXSx2KCksYX19KSxhLnBlZWs9KHI9PntpZigwIT09bylyZXR1cm4gZVswXX0pLGEucmVwbGFjZVRvcD0ocj0+e2VbMF09cix2KCl9KSxhfVxcclxcbiAgdmFyIHEgPSBmYXN0cHJpb3JpdHlxdWV1ZSgpIC8vIHJldXNlIHRoaXNcXHJcXG5cXHJcXG5cXHJcXG4gIC8vIGZ1enp5c29ydCBpcyB3cml0dGVuIHRoaXMgd2F5IGZvciBtaW5pZmljYXRpb24uIGFsbCBuYW1lcyBhcmUgbWFuZ2VsZWQgdW5sZXNzIHF1b3RlZFxcclxcbiAgcmV0dXJuIHsnc2luZ2xlJzpzaW5nbGUsICdnbyc6Z28sICdoaWdobGlnaHQnOmhpZ2hsaWdodCwgJ3ByZXBhcmUnOnByZXBhcmUsICdpbmRleGVzJzppbmRleGVzLCAnY2xlYW51cCc6Y2xlYW51cH1cXHJcXG59KSAvLyBVTURcXHJcXG5cXHJcXG4vLyBUT0RPOiAoZmVhdHVyZSkgZnJlY2VuY3lcXHJcXG4vLyBUT0RPOiAocGVyZikgdXNlIGRpZmZlcmVudCBzb3J0aW5nIGFsZ28gZGVwZW5kaW5nIG9uIHRoZSAjIG9mIHJlc3VsdHM/XFxyXFxuLy8gVE9ETzogKHBlcmYpIHByZXBhcmVkQ2FjaGUgaXMgYSBtZW1vcnkgbGVha1xcclxcbi8vIFRPRE86IChsaWtlIHN1YmxpbWUpIGJhY2tzbGFzaCA9PT0gZm9yd2FyZHNsYXNoXFxyXFxuLy8gVE9ETzogKHBlcmYpIHByZXBhcmVTZWFyY2ggc2VlbXMgc2xvd1xcclxcblxcblxcbi8vIyBzb3VyY2VVUkw9d2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9mdXp6eXNvcnQvZnV6enlzb3J0LmpzP1wiKTtcbiAgICAvKioqL1xuICB9LFxuXG4gIC8qKiovXG4gIFwiLi9ub2RlX21vZHVsZXMvbWF0dGVyLWpzL2J1aWxkL21hdHRlci5qc1wiOlxuICAvKiEqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiohKlxcXG4gICAgISoqKiAuL25vZGVfbW9kdWxlcy9tYXR0ZXItanMvYnVpbGQvbWF0dGVyLmpzICoqKiFcbiAgICBcXCoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuICAvKiEgbm8gc3RhdGljIGV4cG9ydHMgZm91bmQgKi9cblxuICAvKioqL1xuICBmdW5jdGlvbiBub2RlX21vZHVsZXNNYXR0ZXJKc0J1aWxkTWF0dGVySnMobW9kdWxlLCBleHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XG4gICAgZXZhbChcIi8qIFdFQlBBQ0sgVkFSIElOSkVDVElPTiAqLyhmdW5jdGlvbihnbG9iYWwpIHsvKiFcXG4gKiBtYXR0ZXItanMgMC4xOS4wIGJ5IEBsaWFicnVcXG4gKiBodHRwOi8vYnJtLmlvL21hdHRlci1qcy9cXG4gKiBMaWNlbnNlIE1JVFxcbiAqIFxcbiAqIFRoZSBNSVQgTGljZW5zZSAoTUlUKVxcbiAqIFxcbiAqIENvcHlyaWdodCAoYykgTGlhbSBCcnVtbWl0dCBhbmQgY29udHJpYnV0b3JzLlxcbiAqIFxcbiAqIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcXG4gKiBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdG
2VkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcXFwiU29mdHdhcmVcXFwiKSwgdG8gZGVhbFxcbiAqIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHNcXG4gKiB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsXFxuICogY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzXFxuICogZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcXG4gKiBcXG4gKiBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpblxcbiAqIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxcbiAqIFxcbiAqIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCBcXFwiQVMgSVNcXFwiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXFxuICogSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXFxuICogRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXFxuICogQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxcbiAqIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXFxuICogT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTlxcbiAqIFRIRSBTT0ZUV0FSRS5cXG4gKi9cXG4oZnVuY3Rpb24gd2VicGFja1VuaXZlcnNhbE1vZHVsZURlZmluaXRpb24ocm9vdCwgZmFjdG9yeSkge1xcblxcdGlmKHRydWUpXFxuXFx0XFx0bW9kdWxlLmV4cG9ydHMgPSBmYWN0b3J5KCk7XFxuXFx0ZWxzZSB7fVxcbn0pKHRoaXMsIGZ1bmN0aW9uKCkge1xcbnJldHVybiAvKioqKioqLyAoZnVuY3Rpb24obW9kdWxlcykgeyAvLyB3ZWJwYWNrQm9vdHN0cmFwXFxuLyoqKioqKi8gXFx0Ly8gVGhlIG1vZHVsZSBjYWNoZVxcbi8qKioqKiovIFxcdHZhciBpbnN0YWxsZWRNb2R1bGVzID0ge307XFxuLyoqKioqKi9cXG4vKioqKioqLyBcXHQvLyBUaGUgcmVxdWlyZSBmdW5jdGlvblxcbi8qKioqKiovIFxcdGZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcXG4vKioqKioqL1xcbi8qKioqKiovIFxcdFxcdC8vIENoZWNrIGlmIG1vZHVsZSBpcyBpbiBjYWNoZVxcbi8qKioqKiovIFxcdFxcdGlmKGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdKSB7XFxuLyoqKioqKi8gXFx0XFx0XFx0cmV0dXJuIGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdLmV4cG9ydHM7XFxuLyoqKioqKi8gXFx0XFx0fVxcbi8qKioqKiovIFxcdFxcdC8vIENyZWF0ZSBhIG5ldyBtb2R1bGUgKGFuZCBwdXQgaXQgaW50byB0aGUgY2FjaGUpXFxuLyoqKioqKi8gXFx0XFx0dmFyIG1vZHVsZSA9IGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdID0ge1xcbi8qKioqKiovIFxcdFxcdFxcdGk6IG1vZHVsZUlkLFxcbi8qKioqKiovIFxcdFxcdFxcdGw6IGZhbHNlLFxcbi8qKioqKiovIFxcdFxcdFxcdGV4cG9ydHM6IHt9XFxuLyoqKioqKi8gXFx0XFx0fTtcXG4vKioqKioqL1xcbi8qKioqKiovIFxcdFxcdC8vIEV4ZWN1dGUgdGhlIG1vZHVsZSBmdW5jdGlvblxcbi8qKioqKiovIFxcdFxcdG1vZHVsZXNbbW9kdWxlSWRdLmNhbGwobW9kdWxlLmV4cG9ydHMsIG1vZHVsZSwgbW9kdWxlLmV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pO1xcbi8qKioqKiovXFxuLyoqKioqKi8gXFx0XFx0Ly8gRmxhZyB0aGUgbW9kdWxlIGFzIGxvYWRlZFxcbi8qKioqKiovIFxcdFxcdG1vZHVsZS5sID0gdHJ1ZTtcXG4vKioqKioqL1xcbi8qKioqKiovIFxcdFxcdC8vIFJldHVybiB0aGUgZXhwb3J0cyBvZiB0aGUgbW9kdWxlXFxuLyoqKioqKi8gXFx0XFx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xcbi8qKioqKiovIFxcdH1cXG4vKioqKioqL1xcbi8qKioqKiovXFxuLyoqKioqKi8gXFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGVzIG9iamVjdCAoX193ZWJwYWNrX21vZHVsZXNfXylcXG4vKioqKioqLyBcXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm0gPSBtb2R1bGVzO1xcbi8qKioqKiovXFxuLyoqKioqKi8gXFx0Ly8gZXhwb3NlIHRoZSBtb2R1bGUgY2FjaGVcXG4vKioqKioqLyBcXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmMgPSBpbnN0YWxsZWRNb2R1bGVzO1xcbi8qKioqKiovXFxuLyoqKioqKi8gXFx0Ly8gZGVmaW5lIGdldHRlciBmdW5jdGlvbiBmb3IgaGFybW9ueSBleHBvcnRzXFxuLyoqKioqKi8gXFx0X193ZWJwYWNrX3JlcXVpcmVfXy5kID0gZnVuY3Rpb24oZXhwb3J0cywgbmFtZSwgZ2V0dGVyKSB7XFxuLyoqKioqKi8gXFx0XFx0aWYoIV9fd2VicGFja19yZXF1aXJlX18ubyhleHBvcnRzLCBuYW1lKSkge1xcbi8qKioqKiovIFxcdFxcdFxcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBuYW1lLCB7IGVudW1lcmFibGU6IHRydWUsIGdldDogZ2V0dGVyIH0pO1xcbi8qKioqKiovIFxcdFxcdH1cXG4vKioqKioqLyBcXHR9O1xcbi8qKioqKiovXFxuLyoqKioqKi8gXFx0Ly8gZGVmaW5lIF9fZXNNb2R1bGUgb24gZXhwb3J0c1xcbi8qKioqKiovIFxcdF9fd2VicGFja19yZXF1aXJlX18uciA9IGZ1bmN0aW9uKGV4cG9ydHMpIHtcXG4vKioqKioqLyBcXHRcXHRpZih0eXBlb2YgU3ltYm9sICE9PSAndW5kZWZpbmVkJyAmJiBTeW1ib2wudG9TdHJpbmdUYWcpIHtcXG4vKioqKioqLyBcXHRcXHRcXHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgU3ltYm9sLnRvU3RyaW5nVGFnLCB7IHZhbHVlOiAnTW9kdWxlJyB9KTtcXG4vKioqKioqLyBcXHRcXHR9XFxuLyoqKioqKi8gXFx0XFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsICdfX2VzTW9kdWxlJywgeyB2YWx1ZTogdHJ1ZSB9KTtcXG4vKioqKioqLyBcXHR9O1xcbi8qKioqKiovXFxuLyoqKioqKi8gXFx0Ly8gY3JlYXRlIGEgZmFrZSBuYW1lc3BhY2Ugb2JqZWN0XFxuLyoqKioqKi8gXFx0Ly8gbW9kZSAmIDE6IHZhbHVlIGlzIGEgbW9kdWxlIGlkLCByZXF1aXJlIGl0XFxuLyoqKioqKi8gXFx0Ly8gbW9kZSAmIDI6IG1lcmdlIGFsbCBwcm9wZXJ0aWVzIG9mIHZhbHVlIGludG8gdGhlIG5zXFxuLyoqKioqKi8gXFx0Ly8gbW9kZSAmIDQ6IHJldHVybi
2B2YWx1ZSB3aGVuIGFscmVhZHkgbnMgb2JqZWN0XFxuLyoqKioqKi8gXFx0Ly8gbW9kZSAmIDh8MTogYmVoYXZlIGxpa2UgcmVxdWlyZVxcbi8qKioqKiovIFxcdF9fd2VicGFja19yZXF1aXJlX18udCA9IGZ1bmN0aW9uKHZhbHVlLCBtb2RlKSB7XFxuLyoqKioqKi8gXFx0XFx0aWYobW9kZSAmIDEpIHZhbHVlID0gX193ZWJwYWNrX3JlcXVpcmVfXyh2YWx1ZSk7XFxuLyoqKioqKi8gXFx0XFx0aWYobW9kZSAmIDgpIHJldHVybiB2YWx1ZTtcXG4vKioqKioqLyBcXHRcXHRpZigobW9kZSAmIDQpICYmIHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgJiYgdmFsdWUgJiYgdmFsdWUuX19lc01vZHVsZSkgcmV0dXJuIHZhbHVlO1xcbi8qKioqKiovIFxcdFxcdHZhciBucyA9IE9iamVjdC5jcmVhdGUobnVsbCk7XFxuLyoqKioqKi8gXFx0XFx0X193ZWJwYWNrX3JlcXVpcmVfXy5yKG5zKTtcXG4vKioqKioqLyBcXHRcXHRPYmplY3QuZGVmaW5lUHJvcGVydHkobnMsICdkZWZhdWx0JywgeyBlbnVtZXJhYmxlOiB0cnVlLCB2YWx1ZTogdmFsdWUgfSk7XFxuLyoqKioqKi8gXFx0XFx0aWYobW9kZSAmIDIgJiYgdHlwZW9mIHZhbHVlICE9ICdzdHJpbmcnKSBmb3IodmFyIGtleSBpbiB2YWx1ZSkgX193ZWJwYWNrX3JlcXVpcmVfXy5kKG5zLCBrZXksIGZ1bmN0aW9uKGtleSkgeyByZXR1cm4gdmFsdWVba2V5XTsgfS5iaW5kKG51bGwsIGtleSkpO1xcbi8qKioqKiovIFxcdFxcdHJldHVybiBucztcXG4vKioqKioqLyBcXHR9O1xcbi8qKioqKiovXFxuLyoqKioqKi8gXFx0Ly8gZ2V0RGVmYXVsdEV4cG9ydCBmdW5jdGlvbiBmb3IgY29tcGF0aWJpbGl0eSB3aXRoIG5vbi1oYXJtb255IG1vZHVsZXNcXG4vKioqKioqLyBcXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm4gPSBmdW5jdGlvbihtb2R1bGUpIHtcXG4vKioqKioqLyBcXHRcXHR2YXIgZ2V0dGVyID0gbW9kdWxlICYmIG1vZHVsZS5fX2VzTW9kdWxlID9cXG4vKioqKioqLyBcXHRcXHRcXHRmdW5jdGlvbiBnZXREZWZhdWx0KCkgeyByZXR1cm4gbW9kdWxlWydkZWZhdWx0J107IH0gOlxcbi8qKioqKiovIFxcdFxcdFxcdGZ1bmN0aW9uIGdldE1vZHVsZUV4cG9ydHMoKSB7IHJldHVybiBtb2R1bGU7IH07XFxuLyoqKioqKi8gXFx0XFx0X193ZWJwYWNrX3JlcXVpcmVfXy5kKGdldHRlciwgJ2EnLCBnZXR0ZXIpO1xcbi8qKioqKiovIFxcdFxcdHJldHVybiBnZXR0ZXI7XFxuLyoqKioqKi8gXFx0fTtcXG4vKioqKioqL1xcbi8qKioqKiovIFxcdC8vIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbFxcbi8qKioqKiovIFxcdF9fd2VicGFja19yZXF1aXJlX18ubyA9IGZ1bmN0aW9uKG9iamVjdCwgcHJvcGVydHkpIHsgcmV0dXJuIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmplY3QsIHByb3BlcnR5KTsgfTtcXG4vKioqKioqL1xcbi8qKioqKiovIFxcdC8vIF9fd2VicGFja19wdWJsaWNfcGF0aF9fXFxuLyoqKioqKi8gXFx0X193ZWJwYWNrX3JlcXVpcmVfXy5wID0gXFxcIlxcXCI7XFxuLyoqKioqKi9cXG4vKioqKioqL1xcbi8qKioqKiovIFxcdC8vIExvYWQgZW50cnkgbW9kdWxlIGFuZCByZXR1cm4gZXhwb3J0c1xcbi8qKioqKiovIFxcdHJldHVybiBfX3dlYnBhY2tfcmVxdWlyZV9fKF9fd2VicGFja19yZXF1aXJlX18ucyA9IDIwKTtcXG4vKioqKioqLyB9KVxcbi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXFxuLyoqKioqKi8gKFtcXG4vKiAwICovXFxuLyoqKi8gKGZ1bmN0aW9uKG1vZHVsZSwgZXhwb3J0cykge1xcblxcbi8qKlxcbiogVGhlIGBNYXR0ZXIuQ29tbW9uYCBtb2R1bGUgY29udGFpbnMgdXRpbGl0eSBmdW5jdGlvbnMgdGhhdCBhcmUgY29tbW9uIHRvIGFsbCBtb2R1bGVzLlxcbipcXG4qIEBjbGFzcyBDb21tb25cXG4qL1xcblxcbnZhciBDb21tb24gPSB7fTtcXG5cXG5tb2R1bGUuZXhwb3J0cyA9IENvbW1vbjtcXG5cXG4oZnVuY3Rpb24oKSB7XFxuXFxuICAgIENvbW1vbi5fYmFzZURlbHRhID0gMTAwMCAvIDYwO1xcbiAgICBDb21tb24uX25leHRJZCA9IDA7XFxuICAgIENvbW1vbi5fc2VlZCA9IDA7XFxuICAgIENvbW1vbi5fbm93U3RhcnRUaW1lID0gKyhuZXcgRGF0ZSgpKTtcXG4gICAgQ29tbW9uLl93YXJuZWRPbmNlID0ge307XFxuICAgIENvbW1vbi5fZGVjb21wID0gbnVsbDtcXG4gICAgXFxuICAgIC8qKlxcbiAgICAgKiBFeHRlbmRzIHRoZSBvYmplY3QgaW4gdGhlIGZpcnN0IGFyZ3VtZW50IHVzaW5nIHRoZSBvYmplY3QgaW4gdGhlIHNlY29uZCBhcmd1bWVudC5cXG4gICAgICogQG1ldGhvZCBleHRlbmRcXG4gICAgICogQHBhcmFtIHt9IG9ialxcbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IGRlZXBcXG4gICAgICogQHJldHVybiB7fSBvYmogZXh0ZW5kZWRcXG4gICAgICovXFxuICAgIENvbW1vbi5leHRlbmQgPSBmdW5jdGlvbihvYmosIGRlZXApIHtcXG4gICAgICAgIHZhciBhcmdzU3RhcnQsXFxuICAgICAgICAgICAgYXJncyxcXG4gICAgICAgICAgICBkZWVwQ2xvbmU7XFxuXFxuICAgICAgICBpZiAodHlwZW9mIGRlZXAgPT09ICdib29sZWFuJykge1xcbiAgICAgICAgICAgIGFyZ3NTdGFydCA9IDI7XFxuICAgICAgICAgICAgZGVlcENsb25lID0gZGVlcDtcXG4gICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgYXJnc1N0YXJ0ID0gMTtcXG4gICAgICAgICAgICBkZWVwQ2xvbmUgPSB0cnVlO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IGFyZ3NTdGFydDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHZhciBzb3VyY2UgPSBhcmd1bWVudHNbaV07XFxuXFxuICAgICAgICAgICAgaWYgKHNvdXJjZSkge1xcbiAgICAgICAgICAgICAgICBmb3IgKHZhciBwcm9wIGluIHNvdXJjZSkge1xcbiAgICAgICAgICAgICAgICAgICAgaWYgKGRlZXBDbG9uZSAmJiBzb3VyY2VbcHJvcF0gJiYgc291cmNlW3Byb3BdLmNvbnN0cnVjdG9yID09PSBPYmplY3QpIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIW9ialtwcm9wXSB8fCBvYmpbcHJvcF0uY29uc3RydWN0b3IgPT09IE9iamVjdCkge1xcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvYmpbcHJvcF0gPSBvYmpbcHJvcF0gfHwge307XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIENvbW1vbi5leHRlbmQob2JqW3Byb3BdLCBk
2ZWVwQ2xvbmUsIHNvdXJjZVtwcm9wXSk7XFxuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb2JqW3Byb3BdID0gc291cmNlW3Byb3BdO1xcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cXG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgICAgICAgICAgICAgb2JqW3Byb3BdID0gc291cmNlW3Byb3BdO1xcbiAgICAgICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgICAgICB9XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcbiAgICAgICAgXFxuICAgICAgICByZXR1cm4gb2JqO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogQ3JlYXRlcyBhIG5ldyBjbG9uZSBvZiB0aGUgb2JqZWN0LCBpZiBkZWVwIGlzIHRydWUgcmVmZXJlbmNlcyB3aWxsIGFsc28gYmUgY2xvbmVkLlxcbiAgICAgKiBAbWV0aG9kIGNsb25lXFxuICAgICAqIEBwYXJhbSB7fSBvYmpcXG4gICAgICogQHBhcmFtIHtib29sfSBkZWVwXFxuICAgICAqIEByZXR1cm4ge30gb2JqIGNsb25lZFxcbiAgICAgKi9cXG4gICAgQ29tbW9uLmNsb25lID0gZnVuY3Rpb24ob2JqLCBkZWVwKSB7XFxuICAgICAgICByZXR1cm4gQ29tbW9uLmV4dGVuZCh7fSwgZGVlcCwgb2JqKTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFJldHVybnMgdGhlIGxpc3Qgb2Yga2V5cyBmb3IgdGhlIGdpdmVuIG9iamVjdC5cXG4gICAgICogQG1ldGhvZCBrZXlzXFxuICAgICAqIEBwYXJhbSB7fSBvYmpcXG4gICAgICogQHJldHVybiB7c3RyaW5nW119IGtleXNcXG4gICAgICovXFxuICAgIENvbW1vbi5rZXlzID0gZnVuY3Rpb24ob2JqKSB7XFxuICAgICAgICBpZiAoT2JqZWN0LmtleXMpXFxuICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5rZXlzKG9iaik7XFxuXFxuICAgICAgICAvLyBhdm9pZCBoYXNPd25Qcm9wZXJ0eSBmb3IgcGVyZm9ybWFuY2VcXG4gICAgICAgIHZhciBrZXlzID0gW107XFxuICAgICAgICBmb3IgKHZhciBrZXkgaW4gb2JqKVxcbiAgICAgICAgICAgIGtleXMucHVzaChrZXkpO1xcbiAgICAgICAgcmV0dXJuIGtleXM7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIHRoZSBsaXN0IG9mIHZhbHVlcyBmb3IgdGhlIGdpdmVuIG9iamVjdC5cXG4gICAgICogQG1ldGhvZCB2YWx1ZXNcXG4gICAgICogQHBhcmFtIHt9IG9ialxcbiAgICAgKiBAcmV0dXJuIHthcnJheX0gQXJyYXkgb2YgdGhlIG9iamVjdHMgcHJvcGVydHkgdmFsdWVzXFxuICAgICAqL1xcbiAgICBDb21tb24udmFsdWVzID0gZnVuY3Rpb24ob2JqKSB7XFxuICAgICAgICB2Y
2XIgdmFsdWVzID0gW107XFxuICAgICAgICBcXG4gICAgICAgIGlmIChPYmplY3Qua2V5cykge1xcbiAgICAgICAgICAgIHZhciBrZXlzID0gT2JqZWN0LmtleXMob2JqKTtcXG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGtleXMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICAgICAgdmFsdWVzLnB1c2gob2JqW2tleXNbaV1dKTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICAgICAgcmV0dXJuIHZhbHVlcztcXG4gICAgICAgIH1cXG4gICAgICAgIFxcbiAgICAgICAgLy8gYXZvaWQgaGFzT3duUHJvcGVydHkgZm9yIHBlcmZvcm1hbmNlXFxuICAgICAgICBmb3IgKHZhciBrZXkgaW4gb2JqKVxcbiAgICAgICAgICAgIHZhbHVlcy5wdXNoKG9ialtrZXldKTtcXG4gICAgICAgIHJldHVybiB2YWx1ZXM7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBHZXRzIGEgdmFsdWUgZnJvbSBgYmFzZWAgcmVsYXRpdmUgdG8gdGhlIGBwYXRoYCBzdHJpbmcuXFxuICAgICAqIEBtZXRob2QgZ2V0XFxuICAgICAqIEBwYXJhbSB7fSBvYmogVGhlIGJhc2Ugb2JqZWN0XFxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIFRoZSBwYXRoIHJlbGF0aXZlIHRvIGBiYXNlYCwgZS5nLiAnRm9vLkJhci5iYXonXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbYmVnaW5dIFBhdGggc2xpY2UgYmVnaW5cXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IFtlbmRdIFBhdGggc2xpY2UgZW5kXFxuICAgICAqIEByZXR1cm4ge30gVGhlIG9iamVjdCBhdCB0aGUgZ2l2ZW4gcGF0aFxcbiAgICAgKi9cXG4gICAgQ29tbW9uLmdldCA9IGZ1bmN0aW9uKG9iaiwgcGF0aCwgYmVnaW4sIGVuZCkge1xcbiAgICAgICAgcGF0aCA9IHBhdGguc3BsaXQoJy4nKS5zbGljZShiZWdpbiwgZW5kKTtcXG5cXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcGF0aC5sZW5ndGg7IGkgKz0gMSkge1xcbiAgICAgICAgICAgIG9iaiA9IG9ialtwYXRoW2ldXTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHJldHVybiBvYmo7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBTZXRzIGEgdmFsdWUgb24gYGJhc2VgIHJlbGF0aXZlIHRvIHRoZSBnaXZlbiBgcGF0aGAgc3RyaW5nLlxcbiAgICAgKiBAbWV0aG9kIHNldFxcbiAgICAgKiBAcGFyYW0ge30gb2JqIFRoZSBiYXNlIG9iamVjdFxcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGF0aCBUaGUgcGF0aCByZWxhdGl2ZSB0byBgYmFzZWAsIGUuZy4gJ0Zvby5CYXIuYmF6J1xcbiAgICAgKiBAcGFyYW0ge30gdmFsIFRoZSB2YWx1ZSB0byBzZXRcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IFtiZWdpbl0gUGF0aCBzbGljZSBiZWdpblxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gW2VuZF0gUGF0aCBzbGljZSBlbmRcXG4gICAgICogQHJldHVybiB7fSBQYXNzIHRocm91Z2ggYHZhbGAgZm9yIGNoYWluaW5nXFxuICAgICAqL1xcbiAgICBDb21tb24uc2V0ID0gZnVuY3Rpb24ob2JqLCBwYXRoLCB2YWwsIGJlZ2luLCBlbmQpIHtcXG4gICAgICAgIHZhciBwYXJ0cyA9IHBhdGguc3BsaXQoJy4nKS5zbGljZShiZWdpbiwgZW5kKTtcXG4gICAgICAgIENvbW1vbi5nZXQob2JqLCBwYXRoLCAwLCAtMSlbcGFydHNbcGFydHMubGVuZ3RoIC0gMV1dID0gdmFsO1xcbiAgICAgICAgcmV0dXJuIHZhbDtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFNodWZmbGVzIHRoZSBnaXZlbiBhcnJheSBpbi1wbGFjZS5cXG4gICAgICogVGhlIGZ1bmN0aW9uIHVzZXMgYSBzZWVkZWQgcmFuZG9tIGdlbmVyYXRvci5cXG4gICAgICogQG1ldGhvZCBzaHVmZmxlXFxuICAgICAqIEBwYXJhbSB7YXJyYXl9IGFycmF5XFxuICAgICAqIEByZXR1cm4ge2FycmF5fSBhcnJheSBzaHVmZmxlZCByYW5kb21seVxcbiAgICAgKi9cXG4gICAgQ29tbW9uLnNodWZmbGUgPSBmdW5jdGlvbihhcnJheSkge1xcbiAgICAgICAgZm9yICh2YXIgaSA9IGFycmF5Lmxlbmd0aCAtIDE7IGkgPiAwOyBpLS0pIHtcXG4gICAgICAgICAgICB2Y
2XIgaiA9IE1hdGguZmxvb3IoQ29tbW9uLnJhbmRvbSgpICogKGkgKyAxKSk7XFxuICAgICAgICAgICAgdmFyIHRlbXAgPSBhcnJheVtpXTtcXG4gICAgICAgICAgICBhcnJheVtpXSA9IGFycmF5W2pdO1xcbiAgICAgICAgICAgIGFycmF5W2pdID0gdGVtcDtcXG4gICAgICAgIH1cXG4gICAgICAgIHJldHVybiBhcnJheTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFJhbmRvbWx5IGNob29zZXMgYSB2YWx1ZSBmcm9tIGEgbGlzdCB3aXRoIGVxdWFsIHByb2JhYmlsaXR5LlxcbiAgICAgKiBUaGUgZnVuY3Rpb24gdXNlcyBhIHNlZWRlZCByYW5kb20gZ2VuZXJhdG9yLlxcbiAgICAgKiBAbWV0aG9kIGNob29zZVxcbiAgICAgKiBAcGFyYW0ge2FycmF5fSBjaG9pY2VzXFxuICAgICAqIEByZXR1cm4ge29iamVjdH0gQSByYW5kb20gY2hvaWNlIG9iamVjdCBmcm9tIHRoZSBhcnJheVxcbiAgICAgKi9cXG4gICAgQ29tbW9uLmNob29zZSA9IGZ1bmN0aW9uKGNob2ljZXMpIHtcXG4gICAgICAgIHJldHVybiBjaG9pY2VzW01hdGguZmxvb3IoQ29tbW9uLnJhbmRvbSgpICogY2hvaWNlcy5sZW5ndGgpXTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgb2JqZWN0IGlzIGEgSFRNTEVsZW1lbnQsIG90aGVyd2lzZSBmYWxzZS5cXG4gICAgICogQG1ldGhvZCBpc0VsZW1lbnRcXG4gICAgICogQHBhcmFtIHtvYmplY3R9IG9ialxcbiAgICAgKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIHRoZSBvYmplY3QgaXMgYSBIVE1MRWxlbWVudCwgb3RoZXJ3aXNlIGZhbHNlXFxuICAgICAqL1xcbiAgICBDb21tb24uaXNFbGVtZW50ID0gZnVuY3Rpb24ob2JqKSB7XFxuICAgICAgICBpZiAodHlwZW9mIEhUTUxFbGVtZW50ICE9PSAndW5kZWZpbmVkJykge1xcbiAgICAgICAgICAgIHJldHVybiBvYmogaW5zdGFuY2VvZiBIVE1MRWxlbWVudDtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHJldHVybiAhIShvYmogJiYgb2JqLm5vZGVUeXBlICYmIG9iai5ub2RlTmFtZSk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIHRydWUgaWYgdGhlIG9iamVjdCBpcyBhbiBhcnJheS5cXG4gICAgICogQG1ldGhvZCBpc0FycmF5XFxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvYmpcXG4gICAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgb2JqZWN0IGlzIGFuIGFycmF5LCBvdGhlcndpc2UgZmFsc2VcXG4gICAgICovXFxuICAgIENvbW1vbi5pc0FycmF5ID0gZnVuY3Rpb24ob2JqKSB7XFxuICAgICAgICByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG9iaikgPT09ICdbb2JqZWN0IEFycmF5XSc7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIHRydWUgaWYgdGhlIG9iamVjdCBpcyBhIGZ1bmN0aW9uLlxcbiAgICAgKiBAbWV0aG9kIGlzRnVuY3Rpb25cXG4gICAgICogQHBhcmFtIHtvYmplY3R9IG9ialxcbiAgICAgKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIHRoZSBvYmplY3QgaXMgYSBmdW5jdGlvbiwgb3RoZXJ3aXNlIGZhbHNlXFxuICAgICAqL1xcbiAgICBDb21tb24uaXNGdW5jdGlvbiA9IGZ1bmN0aW9uKG9iaikge1xcbiAgICAgICAgcmV0dXJuIHR5cGVvZiBvYmogPT09IFxcXCJmdW5jdGlvblxcXCI7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIHRydWUgaWYgdGhlIG9iamVjdCBpcyBhIHBsYWluIG9iamVjdC5cXG4gICAgICogQG1ldGhvZCBpc1BsYWluT2JqZWN0XFxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvYmpcXG4gICAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgb2JqZWN0IGlzIGEgcGxhaW4gb2JqZWN0LCBvdGhlcndpc2UgZmFsc2VcXG4gICAgICovXFxuICAgIENvbW1vbi5pc1BsYWluT2JqZWN0ID0gZnVuY3Rpb24ob2JqKSB7XFxuICAgICAgICByZXR1cm4gdHlwZW9mIG9iaiA9PT0gJ29iamVjdCcgJiYgb2JqLmNvbnN0cnVjdG9yID09PSBPYmplY3Q7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIHRydWUgaWYgdGhlIG9iamVjdCBpcyBhIHN0cmluZy5cXG4gICAgICogQG1ldGhvZCBpc1N0cmluZ1xcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gb2JqXFxuICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgdGhlIG9iamVjdCBpcyBhIHN0cmluZywgb3RoZXJ3aXNlIGZhbHNlXFxuICAgICAqL1xcbiAgICBDb21tb24uaXNTdHJpbmcgPSBmdW5jdGlvbihvYmopIHtcXG4gICAgICAgIHJldHVybiB0b1N0cmluZy5jYWxsKG9iaikgPT09ICdbb2JqZWN0IFN0cmluZ10nO1xcbiAgICB9O1xcbiAgICBcXG4gICAgLyoqXFxuICAgICAqIFJldHVybnMgdGhlIGdpdmVuIHZhbHVlIGNsYW1wZWQgYmV0d2VlbiBhIG1pbmltdW0gYW5kIG1heGltdW0gdmFsdWUuXFxuICAgICAqIEBtZXRob2QgY2xhbXBcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBtaW5cXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IG1heFxcbiAgICAgKiBAcmV0dXJuIHtudW1iZXJ9IFRoZSB2YWx1ZSBjbGFtcGVkIGJldHdlZW4gbWluIGFuZCBtYXggaW5jbHVzaXZlXFxuICAgICAqL1xcbiAgICBDb21tb24uY2xhbXAgPSBmdW5jdGlvbih2YWx1ZSwgbWluLCBtYXgpIHtcXG4gICAgICAgIGlmICh2YWx1ZSA8IG1pbilcXG4gICAgICAgICAgICByZXR1cm4gbWluO1xcbiAgICAgICAgaWYgKHZhbHVlID4gbWF4KVxcbiAgICAgICAgICAgIHJldHVybiBtYXg7XFxuICAgICAgICByZXR1cm4gdmFsdWU7XFxuICAgIH07XFxuICAgIFxcbiAgICAvKipcXG4gICAgICogUmV0dXJucyB0aGUgc2lnbiBvZiB0aGUgZ2l2ZW4gdmFsdWUuXFxuICAgICAqIEBtZXRob2Qgc2lnblxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gdmFsdWVcXG4gICAgICogQHJldHVybiB7bnVtYmVyfSAtMSBpZiBuZWdhdGl2ZSwgKzEgaWYgMCBvciBwb3NpdGl2ZVxcbiAgICAgKi9cXG4gICAgQ29tbW9uLnNpZ24gPSBmdW5jdGlvbih2YWx1ZSkge1xcbiAgICAgICAgcmV0dXJuIHZhbHVlIDwgMCA/IC0xIDogMTtcXG4gICAgfTtcXG4gICAgXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IHRpbWVzdGFtcCBzaW5jZSB0aGUgdGltZSBvcmlnaW4gKGUuZy4gZnJvbSBwYWdlIGxvYWQpLlxcbiAgICAgKiBUaGUgcmVzdWx0IGlzIGluIG1pbGxpc2Vjb25kcyBhbmQgd2lsbCB1c2UgaGlnaC1yZXNvbHV0aW9uIHRpbWluZyBpZiBhdmFpbGFibGUuXFxuICAgICAqIEBtZXRob2Qgbm93XFxuICAgICAqIEByZXR1cm4ge251bWJlcn0gdGhlIGN1cnJlbnQgdGltZXN0YW1wIGluIG1pbGxpc2Vjb25kc1xcbiAgICAgKi9cXG4gICAgQ29tbW9uLm5vdyA9IGZ1bmN0aW9uKCkge1xcbiAgICAgICAgaWYgKHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnICYmIHdpbmRvdy5wZXJmb3JtYW5jZSkge1xcbiAgICAgICAgICAgIGlmICh3aW5kb3cucGVyZm9ybWFuY2Uubm93KSB7XFxuICAgICAgICAgICAgICAgI
2HJldHVybiB3aW5kb3cucGVyZm9ybWFuY2Uubm93KCk7XFxuICAgICAgICAgICAgfSBlbHNlIGlmICh3aW5kb3cucGVyZm9ybWFuY2Uud2Via2l0Tm93KSB7XFxuICAgICAgICAgICAgICAgIHJldHVybiB3aW5kb3cucGVyZm9ybWFuY2Uud2Via2l0Tm93KCk7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcblxcbiAgICAgICAgaWYgKERhdGUubm93KSB7XFxuICAgICAgICAgICAgcmV0dXJuIERhdGUubm93KCk7XFxuICAgICAgICB9XFxuXFxuICAgICAgICByZXR1cm4gKG5ldyBEYXRlKCkpIC0gQ29tbW9uLl9ub3dTdGFydFRpbWU7XFxuICAgIH07XFxuICAgIFxcbiAgICAvKipcXG4gICAgICogUmV0dXJucyBhIHJhbmRvbSB2YWx1ZSBiZXR3ZWVuIGEgbWluaW11bSBhbmQgYSBtYXhpbXVtIHZhbHVlIGluY2x1c2l2ZS5cXG4gICAgICogVGhlIGZ1bmN0aW9uIHVzZXMgYSBzZWVkZWQgcmFuZG9tIGdlbmVyYXRvci5cXG4gICAgICogQG1ldGhvZCByYW5kb21cXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IG1pblxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gbWF4XFxuICAgICAqIEByZXR1cm4ge251bWJlcn0gQSByYW5kb20gbnVtYmVyIGJldHdlZW4gbWluIGFuZCBtYXggaW5jbHVzaXZlXFxuICAgICAqL1xcbiAgICBDb21tb24ucmFuZG9tID0gZnVuY3Rpb24obWluLCBtYXgpIHtcXG4gICAgICAgIG1pbiA9ICh0eXBlb2YgbWluICE9PSBcXFwidW5kZWZpbmVkXFxcIikgPyBtaW4gOiAwO1xcbiAgICAgICAgbWF4ID0gKHR5cGVvZiBtYXggIT09IFxcXCJ1bmRlZmluZWRcXFwiKSA/IG1heCA6IDE7XFxuICAgICAgICByZXR1cm4gbWluICsgX3NlZWRlZFJhbmRvbSgpICogKG1heCAtIG1pbik7XFxuICAgIH07XFxuXFxuICAgIHZhciBfc2VlZGVkUmFuZG9tID0gZnVuY3Rpb24oKSB7XFxuICAgICAgICAvLyBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9MaW5lYXJfY29uZ3J1ZW50aWFsX2dlbmVyYXRvclxcbiAgICAgICAgQ29tbW9uLl9zZWVkID0gKENvbW1vbi5fc2VlZCAqIDkzMDEgKyA0OTI5NykgJSAyMzMyODA7XFxuICAgICAgICByZXR1cm4gQ29tbW9uLl9zZWVkIC8gMjMzMjgwO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogQ29udmVydHMgYSBDU1MgaGV4IGNvbG91ciBzdHJpbmcgaW50byBhbiBpbnRlZ2VyLlxcbiAgICAgKiBAbWV0aG9kIGNvbG9yVG9OdW1iZXJcXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGNvbG9yU3RyaW5nXFxuICAgICAqIEByZXR1cm4ge251bWJlcn0gQW4gaW50ZWdlciByZXByZXNlbnRpbmcgdGhlIENTUyBoZXggc3RyaW5nXFxuICAgICAqL1xcbiAgICBDb21tb24uY29sb3JUb051bWJlciA9IGZ1bmN0aW9uKGNvbG9yU3RyaW5nKSB7XFxuICAgICAgICBjb2xvclN0cmluZyA9IGNvbG9yU3RyaW5nLnJlcGxhY2UoJyMnLCcnKTtcXG5cXG4gICAgICAgIGlmIChjb2xvclN0cmluZy5sZW5ndGggPT0gMykge1xcbiAgICAgICAgICAgIGNvbG9yU3RyaW5nID0gY29sb3JTdHJpbmcuY2hhckF0KDApICsgY29sb3JTdHJpbmcuY2hhckF0KDApXFxuICAgICAgICAgICAgICAgICAgICAgICAgKyBjb2xvclN0cmluZy5jaGFyQXQoMSkgKyBjb2xvclN0cmluZy5jaGFyQXQoMSlcXG4gICAgICAgICAgICAgICAgICAgICAgICArIGNvbG9yU3RyaW5nLmNoYXJBdCgyKSArIGNvbG9yU3RyaW5nLmNoYXJBdCgyKTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHJldHVybiBwYXJzZUludChjb2xvclN0cmluZywgMTYpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogVGhlIGNvbnNvbGUgbG9nZ2luZyBsZXZlbCB0byB1c2UsIHdoZXJlIGVhY2ggbGV2ZWwgaW5jbHVkZXMgYWxsIGxldmVscyBhYm92ZSBhbmQgZXhjbHVkZXMgdGhlIGxldmVscyBiZWxvdy5cXG4gICAgICogVGhlIGRlZmF1bHQgbGV2ZWwgaXMgJ2RlYnVnJyB3aGljaCBzaG93cyBhbGwgY29uc29sZSBtZXNzYWdlcy4gIFxcbiAgICAgKlxcbiAgICAgKiBQb3NzaWJsZSBsZXZlbCB2YWx1ZXMgYXJlOlxcbiAgICAgKiAtIDAgPSBOb25lXFxuICAgICAqIC0gMSA9IERlYnVnXFxuICAgICAqIC0gMiA9IEluZm9cXG4gICAgICogLSAzID0gV2FyblxcbiAgICAgKiAtIDQgPSBFcnJvclxcbiAgICAgKiBAc3RhdGljXFxuICAgICAqIEBwcm9wZXJ0eSBsb2dMZXZlbFxcbiAgICAgKiBAdHlwZSB7TnVtYmVyfVxcbiAgICAgKiBAZGVmYXVsdCAxXFxuICAgICAqL1xcbiAgICBDb21tb24ubG9nTGV2ZWwgPSAxO1xcblxcbiAgICAvKipcXG4gICAgICogU2hvd3MgYSBgY29uc29sZS5sb2dgIG1lc3NhZ2Ugb25seSBpZiB0aGUgY3VycmVudCBgQ29tbW9uLmxvZ0xldmVsYCBhbGxvd3MgaXQuXFxuICAgICAqIFRoZSBtZXNzYWdlIHdpbGwgYmUgcHJlZml4ZWQgd2l0aCAnbWF0dGVyLWpzJyB0byBtYWtlIGl0IGVhc2lseSBpZGVudGlmaWFibGUuXFxuICAgICAqIEBtZXRob2QgbG9nXFxuICAgICAqIEBwYXJhbSAuLi5vYmpzIHt9IFRoZSBvYmplY3RzIHRvIGxvZy5cXG4gICAgICovXFxuICAgIENvbW1vbi5sb2cgPSBmdW5jdGlvbigpIHtcXG4gICAgICAgIGlmIChjb25zb2xlICYmIENvbW1vbi5sb2dMZXZlbCA+IDAgJiYgQ29tbW9uLmxvZ0xldmVsIDw9IDMpIHtcXG4gICAgICAgICAgICBjb25zb2xlLmxvZy5hcHBseShjb25zb2xlLCBbJ21hdHRlci1qczonXS5jb25jYXQoQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xcbiAgICAgICAgfVxcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogU2hvd3MgYSBgY29uc29sZS5pbmZvYCBtZXNzYWdlIG9ubHkgaWYgdGhlIGN1cnJlbnQgYENvbW1vbi5sb2dMZXZlbGAgYWxsb3dzIGl0LlxcbiAgICAgKiBUaGUgbWVzc2FnZSB3aWxsIGJlIHByZWZpeGVkIHdpdGggJ21hdHRlci1qcycgdG8gbWFrZSBpdCBlYXNpbHkgaWRlbnRpZmlhYmxlLlxcbiAgICAgKiBAbWV0aG9kIGluZm9cXG4gICAgICogQHBhcmFtIC4uLm9ianMge30gVGhlIG9iamVjdHMgdG8gbG9nLlxcbiAgICAgKi9cXG4gICAgQ29tbW9uLmluZm8gPSBmdW5jdGlvbigpIHtcXG4gICAgICAgIGlmIChjb25zb2xlICYmIENvbW1vbi5sb2dMZXZlbCA+IDAgJiYgQ29tbW9uLmxvZ0xldmVsIDw9IDIpIHtcXG4gICAgICAgICAgICBjb25zb2xlLmluZm8uYXBwbHkoY29uc29sZSwgWydtYXR0ZXItanM6J10uY29uY2F0KEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcXG4gICAgICAgI
2H1cXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFNob3dzIGEgYGNvbnNvbGUud2FybmAgbWVzc2FnZSBvbmx5IGlmIHRoZSBjdXJyZW50IGBDb21tb24ubG9nTGV2ZWxgIGFsbG93cyBpdC5cXG4gICAgICogVGhlIG1lc3NhZ2Ugd2lsbCBiZSBwcmVmaXhlZCB3aXRoICdtYXR0ZXItanMnIHRvIG1ha2UgaXQgZWFzaWx5IGlkZW50aWZpYWJsZS5cXG4gICAgICogQG1ldGhvZCB3YXJuXFxuICAgICAqIEBwYXJhbSAuLi5vYmpzIHt9IFRoZSBvYmplY3RzIHRvIGxvZy5cXG4gICAgICovXFxuICAgIENvbW1vbi53YXJuID0gZnVuY3Rpb24oKSB7XFxuICAgICAgICBpZiAoY29uc29sZSAmJiBDb21tb24ubG9nTGV2ZWwgPiAwICYmIENvbW1vbi5sb2dMZXZlbCA8PSAzKSB7XFxuICAgICAgICAgICAgY29uc29sZS53YXJuLmFwcGx5KGNvbnNvbGUsIFsnbWF0dGVyLWpzOiddLmNvbmNhdChBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XFxuICAgICAgICB9XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBVc2VzIGBDb21tb24ud2FybmAgdG8gbG9nIHRoZSBnaXZlbiBtZXNzYWdlIG9uZSB0aW1lIG9ubHkuXFxuICAgICAqIEBtZXRob2Qgd2Fybk9uY2VcXG4gICAgICogQHBhcmFtIC4uLm9ianMge30gVGhlIG9iamVjdHMgdG8gbG9nLlxcbiAgICAgKi9cXG4gICAgQ29tbW9uLndhcm5PbmNlID0gZnVuY3Rpb24oKSB7XFxuICAgICAgICB2YXIgbWVzc2FnZSA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cykuam9pbignICcpO1xcblxcbiAgICAgICAgaWYgKCFDb21tb24uX3dhcm5lZE9uY2VbbWVzc2FnZV0pIHtcXG4gICAgICAgICAgICBDb21tb24ud2FybihtZXNzYWdlKTtcXG4gICAgICAgICAgICBDb21tb24uX3dhcm5lZE9uY2VbbWVzc2FnZV0gPSB0cnVlO1xcbiAgICAgICAgfVxcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogU2hvd3MgYSBkZXByZWNhdGVkIGNvbnNvbGUgd2FybmluZyB3aGVuIHRoZSBmdW5jdGlvbiBvbiB0aGUgZ2l2ZW4gb2JqZWN0IGlzIGNhbGxlZC5cXG4gICAgICogVGhlIHRhcmdldCBmdW5jdGlvbiB3aWxsIGJlIHJlcGxhY2VkIHdpdGggYSBuZXcgZnVuY3Rpb24gdGhhdCBmaXJzdCBzaG93cyB0aGUgd2FybmluZ1xcbiAgICAgKiBhbmQgdGhlbiBjYWxscyB0aGUgb3JpZ2luYWwgZnVuY3Rpb24uXFxuICAgICAqIEBtZXRob2QgZGVwcmVjYXRlZFxcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gb2JqIFRoZSBvYmplY3Qgb3IgbW9kdWxlXFxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIFRoZSBwcm9wZXJ0eSBuYW1lIG9mIHRoZSBmdW5jdGlvbiBvbiBvYmpcXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHdhcm5pbmcgVGhlIG9uZS10aW1lIG1lc3NhZ2UgdG8gc2hvdyBpZiB0aGUgZnVuY3Rpb24gaXMgY2FsbGVkXFxuICAgICAqL1xcbiAgICBDb21tb24uZGVwcmVjYXRlZCA9IGZ1bmN0aW9uKG9iaiwgcHJvcCwgd2FybmluZykge1xcbiAgICAgICAgb2JqW3Byb3BdID0gQ29tbW9uLmNoYWluKGZ1bmN0aW9uKCkge1xcbiAgICAgICAgICAgIENvbW1vbi53YXJuT25jZSgn8J+UhSBkZXByZWNhdGVkIPCflIUnLCB3YXJuaW5nKTtcXG4gICAgICAgIH0sIG9ialtwcm9wXSk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIHRoZSBuZXh0IHVuaXF1ZSBzZXF1ZW50aWFsIElELlxcbiAgICAgKiBAbWV0aG9kIG5leHRJZFxcbiAgICAgKiBAcmV0dXJuIHtOdW1iZXJ9IFVuaXF1ZSBzZXF1ZW50aWFsIElEXFxuICAgICAqL1xcbiAgICBDb21tb24ubmV4dElkID0gZnVuY3Rpb24oKSB7XFxuICAgICAgICByZXR1cm4gQ29tbW9uLl9uZXh0SWQrKztcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIEEgY3Jvc3MgYnJvd3NlciBjb21wYXRpYmxlIGluZGV4T2YgaW1wbGVtZW50YXRpb24uXFxuICAgICAqIEBtZXRob2QgaW5kZXhPZlxcbiAgICAgKiBAcGFyYW0ge2FycmF5fSBoYXlzdGFja1xcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gbmVlZGxlXFxuICAgICAqIEByZXR1cm4ge251bWJlcn0gVGhlIHBvc2l0aW9uIG9mIG5lZWRsZSBpbiBoYXlzdGFjaywgb3RoZXJ3aXNlIC0xLlxcbiAgICAgKi9cXG4gICAgQ29tbW9uLmluZGV4T2YgPSBmdW5jdGlvbihoYXlzdGFjaywgbmVlZGxlKSB7XFxuICAgICAgICBpZiAoaGF5c3RhY2suaW5kZXhPZilcXG4gICAgICAgICAgICByZXR1cm4gaGF5c3RhY2suaW5kZXhPZihuZWVkbGUpO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBoYXlzdGFjay5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIGlmIChoYXlzdGFja1tpXSA9PT0gbmVlZGxlKVxcbiAgICAgICAgICAgICAgICByZXR1cm4gaTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHJldHVybiAtMTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIEEgY3Jvc3MgYnJvd3NlciBjb21wYXRpYmxlIGFycmF5IG1hcCBpbXBsZW1lbnRhdGlvbi5cXG4gICAgICogQG1ldGhvZCBtYXBcXG4gICAgICogQHBhcmFtIHthcnJheX0gbGlzdFxcbiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBmdW5jXFxuICAgICAqIEByZXR1cm4ge2FycmF5fSBWYWx1ZXMgZnJvbSBsaXN0IHRyYW5zZm9ybWVkIGJ5IGZ1bmMuXFxuICAgICAqL1xcbiAgICBDb21tb24ubWFwID0gZnVuY3Rpb24obGlzdCwgZnVuYykge1xcbiAgICAgICAgaWYgKGxpc3QubWFwKSB7XFxuICAgICAgICAgICAgcmV0dXJuIGxpc3QubWFwKGZ1bmMpO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgdmFyIG1hcHBlZCA9IFtdO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsaXN0Lmxlbmd0aDsgaSArPSAxKSB7XFxuICAgICAgICAgICAgbWFwcGVkLnB1c2goZnVuYyhsaXN0W2ldKSk7XFxuICAgICAgICB9XFxuXFxuICAgICAgICByZXR1cm4gbWFwcGVkO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogVGFrZXMgYSBkaXJlY3RlZCBncmFwaCBhbmQgcmV0dXJucyB0aGUgcGFydGlhbGx5IG9yZGVyZWQgc2V0IG9mIHZlcnRpY2VzIGluIHRvcG9sb2dpY2FsIG9yZGVyLlxcbiAgICAgKiBDaXJjdWxhciBkZXBlbmRlbmNpZXMgYXJlIGFsbG93ZWQuXFxuICAgICAqIEBtZXRob2QgdG9wb2xvZ2ljYWxTb3J0XFxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBncmFwaFxcbiAgICAgKiBAcmV0dXJuIHthcnJheX0gUGFydGlhbGx5IG9yZGVyZWQgc2V0IG9mIHZlcnRpY2VzIGluIHRvcG9sb2dpY2FsIG9yZGVyLlxcbiAgICAgKi9cXG4gICAgQ29tbW9uLnRvcG9sb2dpY2FsU29ydCA9IGZ1bmN0aW9uKGdyYXBoKSB7XFxuICAgICAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vbWdlY2hldi9qYXZhc2NyaXB0LWFsZ29yaXRobXNcXG4gICAgICAgIC8vIENvcHlyaWdodCAoYykgTWlua28gR2VjaGV2IChNSVQgbGljZW5zZSlcXG4gICAgICAgIC8vIE1vZGlmaWNhdGlvbnM6IHRpZHkgZm9ybWF0dGluZyBhbmQgbmFtaW5nXFxuICAgICAgICB2Y
2XIgcmVzdWx0ID0gW10sXFxuICAgICAgICAgICAgdmlzaXRlZCA9IFtdLFxcbiAgICAgICAgICAgIHRlbXAgPSBbXTtcXG5cXG4gICAgICAgIGZvciAodmFyIG5vZGUgaW4gZ3JhcGgpIHtcXG4gICAgICAgICAgICBpZiAoIXZpc2l0ZWRbbm9kZV0gJiYgIXRlbXBbbm9kZV0pIHtcXG4gICAgICAgICAgICAgICAgQ29tbW9uLl90b3BvbG9naWNhbFNvcnQobm9kZSwgdmlzaXRlZCwgdGVtcCwgZ3JhcGgsIHJlc3VsdCk7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcblxcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcXG4gICAgfTtcXG5cXG4gICAgQ29tbW9uLl90b3BvbG9naWNhbFNvcnQgPSBmdW5jdGlvbihub2RlLCB2aXNpdGVkLCB0ZW1wLCBncmFwaCwgcmVzdWx0KSB7XFxuICAgICAgICB2YXIgbmVpZ2hib3JzID0gZ3JhcGhbbm9kZV0gfHwgW107XFxuICAgICAgICB0ZW1wW25vZGVdID0gdHJ1ZTtcXG5cXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbmVpZ2hib3JzLmxlbmd0aDsgaSArPSAxKSB7XFxuICAgICAgICAgICAgdmFyIG5laWdoYm9yID0gbmVpZ2hib3JzW2ldO1xcblxcbiAgICAgICAgICAgIGlmICh0ZW1wW25laWdoYm9yXSkge1xcbiAgICAgICAgICAgICAgICAvLyBza2lwIGNpcmN1bGFyIGRlcGVuZGVuY2llc1xcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcXG4gICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgaWYgKCF2aXNpdGVkW25laWdoYm9yXSkge1xcbiAgICAgICAgICAgICAgICBDb21tb24uX3RvcG9sb2dpY2FsU29ydChuZWlnaGJvciwgdmlzaXRlZCwgdGVtcCwgZ3JhcGgsIHJlc3VsdCk7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcblxcbiAgICAgICAgdGVtcFtub2RlXSA9IGZhbHNlO1xcbiAgICAgICAgdmlzaXRlZFtub2RlXSA9IHRydWU7XFxuXFxuICAgICAgICByZXN1bHQucHVzaChub2RlKTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFRha2VzIF9uXyBmdW5jdGlvbnMgYXMgYXJndW1lbnRzIGFuZCByZXR1cm5zIGEgbmV3IGZ1bmN0aW9uIHRoYXQgY2FsbHMgdGhlbSBpbiBvcmRlci5cXG4gICAgICogVGhlIGFyZ3VtZW50cyBhcHBsaWVkIHdoZW4gY2FsbGluZyB0aGUgbmV3IGZ1bmN0aW9uIHdpbGwgYWxzbyBiZSBhcHBsaWVkIHRvIGV2ZXJ5IGZ1bmN0aW9uIHBhc3NlZC5cXG4gICAgICogVGhlIHZhbHVlIG9mIGB0aGlzYCByZWZlcnMgdG8gdGhlIGxhc3QgdmFsdWUgcmV0dXJuZWQgaW4gdGhlIGNoYWluIHRoYXQgd2FzIG5vdCBgdW5kZWZpbmVkYC5cXG4gICAgICogVGhlcmVmb3JlIGlmIGEgcGFzc2VkIGZ1bmN0aW9uIGRvZXMgbm90IHJldHVybiBhIHZhbHVlLCB0aGUgcHJldmlvdXNseSByZXR1cm5lZCB2YWx1ZSBpcyBtYWludGFpbmVkLlxcbiAgICAgKiBBZnRlciBhbGwgcGFzc2VkIGZ1bmN0aW9ucyBoYXZlIGJlZW4gY2FsbGVkIHRoZSBuZXcgZnVuY3Rpb24gcmV0dXJucyB0aGUgbGFzdCByZXR1cm5lZCB2YWx1ZSAoaWYgYW55KS5cXG4gICAgICogSWYgYW55IG9mIHRoZSBwYXNzZWQgZnVuY3Rpb25zIGFyZSBhIGNoYWluLCB0aGVuIHRoZSBjaGFpbiB3aWxsIGJlIGZsYXR0ZW5lZC5cXG4gICAgICogQG1ldGhvZCBjaGFpblxcbiAgICAgKiBAcGFyYW0gLi4uZnVuY3Mge2Z1bmN0aW9ufSBUaGUgZnVuY3Rpb25zIHRvIGNoYWluLlxcbiAgICAgKiBAcmV0dXJuIHtmdW5jdGlvbn0gQSBuZXcgZnVuY3Rpb24gdGhhdCBjYWxscyB0aGUgcGFzc2VkIGZ1bmN0aW9ucyBpbiBvcmRlci5cXG4gICAgICovXFxuICAgIENvbW1vbi5jaGFpbiA9IGZ1bmN0aW9uKCkge1xcbiAgICAgICAgdmFyIGZ1bmNzID0gW107XFxuXFxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkgKz0gMSkge1xcbiAgICAgICAgICAgIHZhciBmdW5jID0gYXJndW1lbnRzW2ldO1xcblxcbiAgICAgICAgICAgIGlmIChmdW5jLl9jaGFpbmVkKSB7XFxuICAgICAgICAgICAgICAgIC8vIGZsYXR0ZW4gYWxyZWFkeSBjaGFpbmVkIGZ1bmN0aW9uc1xcbiAgICAgICAgICAgICAgICBmdW5jcy5wdXNoLmFwcGx5KGZ1bmNzLCBmdW5jLl9jaGFpbmVkKTtcXG4gICAgICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgICAgICBmdW5jcy5wdXNoKGZ1bmMpO1xcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHZhciBjaGFpbiA9IGZ1bmN0aW9uKCkge1xcbiAgICAgICAgICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9Hb29nbGVDaHJvbWUvZGV2dG9vbHMtZG9jcy9pc3N1ZXMvNTMjaXNzdWVjb21tZW50LTUxOTQxMzU4XFxuICAgICAgICAgICAgdmFyIGxhc3RSZXN1bHQsXFxuICAgICAgICAgICAgICAgIGFyZ3MgPSBuZXcgQXJyYXkoYXJndW1lbnRzLmxlbmd0aCk7XFxuXFxuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDAsIGwgPSBhcmd1bWVudHMubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XFxuICAgICAgICAgICAgICAgIGFyZ3NbaV0gPSBhcmd1bWVudHNbaV07XFxuICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBmdW5jcy5sZW5ndGg7IGkgKz0gMSkge1xcbiAgICAgICAgICAgICAgICB2Y
2XIgcmVzdWx0ID0gZnVuY3NbaV0uYXBwbHkobGFzdFJlc3VsdCwgYXJncyk7XFxuXFxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgcmVzdWx0ICE9PSAndW5kZWZpbmVkJykge1xcbiAgICAgICAgICAgICAgICAgICAgbGFzdFJlc3VsdCA9IHJlc3VsdDtcXG4gICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICByZXR1cm4gbGFzdFJlc3VsdDtcXG4gICAgICAgIH07XFxuXFxuICAgICAgICBjaGFpbi5fY2hhaW5lZCA9IGZ1bmNzO1xcblxcbiAgICAgICAgcmV0dXJuIGNoYWluO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogQ2hhaW5zIGEgZnVuY3Rpb24gdG8gZXhjdXRlIGJlZm9yZSB0aGUgb3JpZ2luYWwgZnVuY3Rpb24gb24gdGhlIGdpdmVuIGBwYXRoYCByZWxhdGl2ZSB0byBgYmFzZWAuXFxuICAgICAqIFNlZSBhbHNvIGRvY3MgZm9yIGBDb21tb24uY2hhaW5gLlxcbiAgICAgKiBAbWV0aG9kIGNoYWluUGF0aEJlZm9yZVxcbiAgICAgKiBAcGFyYW0ge30gYmFzZSBUaGUgYmFzZSBvYmplY3RcXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHBhdGggVGhlIHBhdGggcmVsYXRpdmUgdG8gYGJhc2VgXFxuICAgICAqIEBwYXJhbSB7ZnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIGNoYWluIGJlZm9yZSB0aGUgb3JpZ2luYWxcXG4gICAgICogQHJldHVybiB7ZnVuY3Rpb259IFRoZSBjaGFpbmVkIGZ1bmN0aW9uIHRoYXQgcmVwbGFjZWQgdGhlIG9yaWdpbmFsXFxuICAgICAqL1xcbiAgICBDb21tb24uY2hhaW5QYXRoQmVmb3JlID0gZnVuY3Rpb24oYmFzZSwgcGF0aCwgZnVuYykge1xcbiAgICAgICAgcmV0dXJuIENvbW1vbi5zZXQoYmFzZSwgcGF0aCwgQ29tbW9uLmNoYWluKFxcbiAgICAgICAgICAgIGZ1bmMsXFxuICAgICAgICAgICAgQ29tbW9uLmdldChiYXNlLCBwYXRoKVxcbiAgICAgICAgKSk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBDaGFpbnMgYSBmdW5jdGlvbiB0byBleGN1dGUgYWZ0ZXIgdGhlIG9yaWdpbmFsIGZ1bmN0aW9uIG9uIHRoZSBnaXZlbiBgcGF0aGAgcmVsYXRpdmUgdG8gYGJhc2VgLlxcbiAgICAgKiBTZWUgYWxzbyBkb2NzIGZvciBgQ29tbW9uLmNoYWluYC5cXG4gICAgICogQG1ldGhvZCBjaGFpblBhdGhBZnRlclxcbiAgICAgKiBAcGFyYW0ge30gYmFzZSBUaGUgYmFzZSBvYmplY3RcXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHBhdGggVGhlIHBhdGggcmVsYXRpdmUgdG8gYGJhc2VgXFxuICAgICAqIEBwYXJhbSB7ZnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIGNoYWluIGFmdGVyIHRoZSBvcmlnaW5hbFxcbiAgICAgKiBAcmV0dXJuIHtmdW5jdGlvbn0gVGhlIGNoYWluZWQgZnVuY3Rpb24gdGhhdCByZXBsYWNlZCB0aGUgb3JpZ2luYWxcXG4gICAgICovXFxuICAgIENvbW1vbi5jaGFpblBhdGhBZnRlciA9IGZ1bmN0aW9uKGJhc2UsIHBhdGgsIGZ1bmMpIHtcXG4gICAgICAgIHJldHVybiBDb21tb24uc2V0KGJhc2UsIHBhdGgsIENvbW1vbi5jaGFpbihcXG4gICAgICAgICAgICBDb21tb24uZ2V0KGJhc2UsIHBhdGgpLFxcbiAgICAgICAgICAgIGZ1bmNcXG4gICAgICAgICkpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUHJvdmlkZSB0aGUgW3BvbHktZGVjb21wXShodHRwczovL2dpdGh1Yi5jb20vc2NodGVwcGUvcG9seS1kZWNvbXAuanMpIGxpYnJhcnkgbW9kdWxlIHRvIGVuYWJsZVxcbiAgICAgKiBjb25jYXZlIHZlcnRleCBkZWNvbXBvc2l0aW9uIHN1cHBvcnQgd2hlbiB1c2luZyBgQm9kaWVzLmZyb21WZXJ0aWNlc2AgZS5nLiBgQ29tbW9uLnNldERlY29tcChyZXF1aXJlKCdwb2x5LWRlY29tcCcpKWAuXFxuICAgICAqIEBtZXRob2Qgc2V0RGVjb21wXFxuICAgICAqIEBwYXJhbSB7fSBkZWNvbXAgVGhlIFtwb2x5LWRlY29tcF0oaHR0cHM6Ly9naXRodWIuY29tL3NjaHRlcHBlL3BvbHktZGVjb21wLmpzKSBsaWJyYXJ5IG1vZHVsZS5cXG4gICAgICovXFxuICAgIENvbW1vbi5zZXREZWNvbXAgPSBmdW5jdGlvbihkZWNvbXApIHtcXG4gICAgICAgIENvbW1vbi5fZGVjb21wID0gZGVjb21wO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmV0dXJucyB0aGUgW3BvbHktZGVjb21wXShodHRwczovL2dpdGh1Yi5jb20vc2NodGVwcGUvcG9seS1kZWNvbXAuanMpIGxpYnJhcnkgbW9kdWxlIHByb3ZpZGVkIHRocm91Z2ggYENvbW1vbi5zZXREZWNvbXBgLFxcbiAgICAgKiBvdGhlcndpc2UgcmV0dXJucyB0aGUgZ2xvYmFsIGBkZWNvbXBgIGlmIHNldC5cXG4gICAgICogQG1ldGhvZCBnZXREZWNvbXBcXG4gICAgICogQHJldHVybiB7fSBUaGUgW3BvbHktZGVjb21wXShodHRwczovL2dpdGh1Yi5jb20vc2NodGVwcGUvcG9seS1kZWNvbXAuanMpIGxpYnJhcnkgbW9kdWxlIGlmIHByb3ZpZGVkLlxcbiAgICAgKi9cXG4gICAgQ29tbW9uLmdldERlY29tcCA9IGZ1bmN0aW9uKCkge1xcbiAgICAgICAgLy8gZ2V0IHVzZXIgcHJvdmlkZWQgZGVjb21wIGlmIHNldFxcbiAgICAgICAgdmFyIGRlY29tcCA9IENvbW1vbi5fZGVjb21wO1xcblxcbiAgICAgICAgdHJ5IHtcXG4gICAgICAgICAgICAvLyBvdGhlcndpc2UgZnJvbSB3aW5kb3cgZ2xvYmFsXFxuICAgICAgICAgICAgaWYgKCFkZWNvbXAgJiYgdHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcpIHtcXG4gICAgICAgICAgICAgICAgZGVjb21wID0gd2luZG93LmRlY29tcDtcXG4gICAgICAgICAgICB9XFxuICAgIFxcbiAgICAgICAgICAgIC8vIG90aGVyd2lzZSBmcm9tIG5vZGUgZ2xvYmFsXFxuICAgICAgICAgICAgaWYgKCFkZWNvbXAgJiYgdHlwZW9mIGdsb2JhbCAhPT0gJ3VuZGVmaW5lZCcpIHtcXG4gICAgICAgICAgICAgICAgZGVjb21wID0gZ2xvYmFsLmRlY29tcDtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9IGNhdGNoIChlKSB7XFxuICAgICAgICAgICAgLy8gZGVjb21wIG5vdCBhdmFpbGFibGVcXG4gICAgICAgICAgICBkZWNvbXAgPSBudWxsO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgcmV0dXJuIGRlY29tcDtcXG4gICAgfTtcXG59KSgpO1xcblxcblxcbi8qKiovIH0pLFxcbi8qIDEgKi9cXG4vKioqLyAoZnVuY3Rpb24obW9kdWxlLCBleHBvcnRzKSB7XFxuXFxuLyoqXFxuKiBUaGUgYE1hdHRlci5Cb3VuZHNgIG1vZHVsZSBjb250YWlucyBtZXRob2RzIGZvciBjcmVhdGluZyBhbmQgbWFuaXB1bGF0aW5nIGF4aXMtYWxpZ25lZCBib3VuZGluZyBib3hlcyAoQUFCQikuXFxuKlxcbiogQGNsYXNzIEJvdW5kc1xcbiovXFxuXFxudmFyIEJvdW5kcyA9IHt9O1xcblxcbm1vZHVsZS5leHBvcnRzID0gQm91bmRzO1xcblxcbihmdW5jdGlvbigpIHtcXG5cXG4gICAgLyoqXFxuICAgICAqIENyZWF0ZXMgYSBuZXcgYXhpcy1hbGlnbmVkIGJvdW5kaW5nIGJveCAoQUFCQikgZm9yIHRoZSBnaXZlbiB2ZXJ0aWNlcy5cXG4gICAgICogQG1ldGhvZCBjcmVhdGVcXG4gICAgICogQHBhcmFtIHt2ZXJ0aWNlc30gdmVydGljZXNcXG4gICAgICogQHJldHVybi
2B7Ym91bmRzfSBBIG5ldyBib3VuZHMgb2JqZWN0XFxuICAgICAqL1xcbiAgICBCb3VuZHMuY3JlYXRlID0gZnVuY3Rpb24odmVydGljZXMpIHtcXG4gICAgICAgIHZhciBib3VuZHMgPSB7IFxcbiAgICAgICAgICAgIG1pbjogeyB4OiAwLCB5OiAwIH0sIFxcbiAgICAgICAgICAgIG1heDogeyB4OiAwLCB5OiAwIH1cXG4gICAgICAgIH07XFxuXFxuICAgICAgICBpZiAodmVydGljZXMpXFxuICAgICAgICAgICAgQm91bmRzLnVwZGF0ZShib3VuZHMsIHZlcnRpY2VzKTtcXG4gICAgICAgIFxcbiAgICAgICAgcmV0dXJuIGJvdW5kcztcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFVwZGF0ZXMgYm91bmRzIHVzaW5nIHRoZSBnaXZlbiB2ZXJ0aWNlcyBhbmQgZXh0ZW5kcyB0aGUgYm91bmRzIGdpdmVuIGEgdmVsb2NpdHkuXFxuICAgICAqIEBtZXRob2QgdXBkYXRlXFxuICAgICAqIEBwYXJhbSB7Ym91bmRzfSBib3VuZHNcXG4gICAgICogQHBhcmFtIHt2ZXJ0aWNlc30gdmVydGljZXNcXG4gICAgICogQHBhcmFtIHt2ZWN0b3J9IHZlbG9jaXR5XFxuICAgICAqL1xcbiAgICBCb3VuZHMudXBkYXRlID0gZnVuY3Rpb24oYm91bmRzLCB2ZXJ0aWNlcywgdmVsb2NpdHkpIHtcXG4gICAgICAgIGJvdW5kcy5taW4ueCA9IEluZmluaXR5O1xcbiAgICAgICAgYm91bmRzLm1heC54ID0gLUluZmluaXR5O1xcbiAgICAgICAgYm91bmRzLm1pbi55ID0gSW5maW5pdHk7XFxuICAgICAgICBib3VuZHMubWF4LnkgPSAtSW5maW5pdHk7XFxuXFxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHZlcnRpY2VzLmxlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgdmFyIHZlcnRleCA9IHZlcnRpY2VzW2ldO1xcbiAgICAgICAgICAgIGlmICh2ZXJ0ZXgueCA+IGJvdW5kcy5tYXgueCkgYm91bmRzLm1heC54ID0gdmVydGV4Lng7XFxuICAgICAgICAgICAgaWYgKHZlcnRleC54IDwgYm91bmRzLm1pbi54KSBib3VuZHMubWluLnggPSB2ZXJ0ZXgueDtcXG4gICAgICAgICAgICBpZiAodmVydGV4LnkgPiBib3VuZHMubWF4LnkpIGJvdW5kcy5tYXgueSA9IHZlcnRleC55O1xcbiAgICAgICAgICAgIGlmICh2ZXJ0ZXgueSA8IGJvdW5kcy5taW4ueSkgYm91bmRzLm1pbi55ID0gdmVydGV4Lnk7XFxuICAgICAgICB9XFxuICAgICAgICBcXG4gICAgICAgIGlmICh2ZWxvY2l0eSkge1xcbiAgICAgICAgICAgIGlmICh2ZWxvY2l0eS54ID4gMCkge1xcbiAgICAgICAgICAgICAgICBib3VuZHMubWF4LnggKz0gdmVsb2NpdHkueDtcXG4gICAgICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgICAgICBib3VuZHMubWluLnggKz0gdmVsb2NpdHkueDtcXG4gICAgICAgICAgICB9XFxuICAgICAgICAgICAgXFxuICAgICAgICAgICAgaWYgKHZlbG9jaXR5LnkgPiAwKSB7XFxuICAgICAgICAgICAgICAgIGJvdW5kcy5tYXgueSArPSB2ZWxvY2l0eS55O1xcbiAgICAgICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgICAgIGJvdW5kcy5taW4ueSArPSB2ZWxvY2l0eS55O1xcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgYm91bmRzIGNvbnRhaW5zIHRoZSBnaXZlbiBwb2ludC5cXG4gICAgICogQG1ldGhvZCBjb250YWluc1xcbiAgICAgKiBAcGFyYW0ge2JvdW5kc30gYm91bmRzXFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSBwb2ludFxcbiAgICAgKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIHRoZSBib3VuZHMgY29udGFpbiB0aGUgcG9pbnQsIG90aGVyd2lzZSBmYWxzZVxcbiAgICAgKi9cXG4gICAgQm91bmRzLmNvbnRhaW5zID0gZnVuY3Rpb24oYm91bmRzLCBwb2ludCkge1xcbiAgICAgICAgcmV0dXJuIHBvaW50LnggPj0gYm91bmRzLm1pbi54ICYmIHBvaW50LnggPD0gYm91bmRzLm1heC54IFxcbiAgICAgICAgICAgICAgICYmIHBvaW50LnkgPj0gYm91bmRzLm1pbi55ICYmIHBvaW50LnkgPD0gYm91bmRzLm1heC55O1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmV0dXJucyB0cnVlIGlmIHRoZSB0d28gYm91bmRzIGludGVyc2VjdC5cXG4gICAgICogQG1ldGhvZCBvdmVybGFwc1xcbiAgICAgKiBAcGFyYW0ge2JvdW5kc30gYm91bmRzQVxcbiAgICAgKiBAcGFyYW0ge2JvdW5kc30gYm91bmRzQlxcbiAgICAgKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIHRoZSBib3VuZHMgb3ZlcmxhcCwgb3RoZXJ3aXNlIGZhbHNlXFxuICAgICAqL1xcbiAgICBCb3VuZHMub3ZlcmxhcHMgPSBmdW5jdGlvbihib3VuZHNBLCBib3VuZHNCKSB7XFxuICAgICAgICByZXR1cm4gKGJvdW5kc0EubWluLnggPD0gYm91bmRzQi5tYXgueCAmJiBib3VuZHNBLm1heC54ID49IGJvdW5kc0IubWluLnhcXG4gICAgICAgICAgICAgICAgJiYgYm91bmRzQS5tYXgueSA+PSBib3VuZHNCLm1pbi55ICYmIGJvdW5kc0EubWluLnkgPD0gYm91bmRzQi5tYXgueSk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBUcmFuc2xhdGVzIHRoZSBib3VuZHMgYnkgdGhlIGdpdmVuIHZlY3Rvci5cXG4gICAgICogQG1ldGhvZCB0cmFuc2xhdGVcXG4gICAgICogQHBhcmFtIHtib3VuZHN9IGJvdW5kc1xcbiAgICAgKiBAcGFyYW0ge3ZlY3Rvcn0gdmVjdG9yXFxuICAgICAqL1xcbiAgICBCb3VuZHMudHJhbnNsYXRlID0gZnVuY3Rpb24oYm91bmRzLCB2ZWN0b3IpIHtcXG4gICAgICAgIGJvdW5kcy5taW4ueCArPSB2ZWN0b3IueDtcXG4gICAgICAgIGJvdW5kcy5tYXgueCArPSB2ZWN0b3IueDtcXG4gICAgICAgIGJvdW5kcy5taW4ueSArPSB2ZWN0b3IueTtcXG4gICAgICAgIGJvdW5kcy5tYXgueSArPSB2ZWN0b3IueTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFNoaWZ0cyB0aGUgYm91bmRzIHRvIHRoZSBnaXZlbiBwb3NpdGlvbi5cXG4gICAgICogQG1ldGhvZCBzaGlmdFxcbiAgICAgKiBAcGFyYW0ge2JvdW5kc30gYm91bmRzXFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSBwb3NpdGlvblxcbiAgICAgKi9cXG4gICAgQm91bmRzLnNoaWZ0ID0gZnVuY3Rpb24oYm91bmRzLCBwb3NpdGlvbikge1xcbiAgICAgICAgdmFyIGRlbHRhWCA9IGJvdW5kcy5tYXgueCAtIGJvdW5kcy5taW4ueCxcXG4gICAgICAgICAgICBkZWx0YVkgPSBib3VuZHMubWF4LnkgLSBib3VuZHMubWluLnk7XFxuICAgICAgICAgICAgXFxuICAgICAgICBib3VuZHMubWluLnggPSBwb3NpdGlvbi54O1xcbiAgICAgICAgYm91bmRzLm1heC54ID0gcG9zaXRpb24ueCArIGRlbHRhWDtcXG4gICAgICAgIGJvdW5kcy5taW4ueSA9IHBvc2l0aW9uLnk7XFxuICAgICAgICBib3VuZHMubWF4LnkgPSBwb3NpdGlvbi55ICsgZGVsdGFZO1xcbiAgICB9O1xcbiAgICBcXG59KSgpO1xcblxcblxcbi8qKiovIH0pLFxcbi8qIDIgKi9cXG4vKioqLyAoZnVuY3Rpb24obW9kdWxlLCBleHBvcnRzKSB7XFxuXFxuLyoqXFxuKiBUaGUgYE1hdHRlci5WZWN0b3JgIG1vZHVsZSBjb250YWlucyBtZXRob2RzIGZvciBjcmVhdGluZyBhbmQgbWFuaXB1bGF0aW5nIHZlY3RvcnMuXFxuKiBWZWN0b3JzIGFyZSB0aGUgYmFzaXMgb2YgYWxsIHRoZSBnZW9tZXRyeSByZWxhdGVkIG9wZXJhdGlvbnMgaW4gdGhlIGVuZ2luZS5cXG4qIEEgYE1hdHRlci5WZWN0b3JgIG9iamVjdCBpcyBvZiB0aGUgZm9ybSBgeyB4OiAwLCB5OiAwIH1gLlxcbipcXG4qIFNlZSB0aGUgaW5jbHVkZWQgdXNhZ2UgW2V4YW1wbGVzXShodHRwczovL2dpdGh1Yi5jb20vbGlhYnJ1L21hdHRlci1qcy90cmVlL21hc3Rlci9leGFtcGxlcykuXFxuKlxcbiogQGNsYXNzIFZlY3RvclxcbiovXFxuXFxuLy8gVE9ETzogY29uc2lkZXIgcGFyYW1zIGZvciByZXVzaW5nIHZlY3RvciBvYmplY3RzXFxuXFxudmFyIFZlY3RvciA9IHt9O1xcblxcbm1vZHVsZS5leHBvcnRzID0gVmVjdG9yO1xcblxcbihmdW5jdGlvbigpIHtcXG5cXG4gICAgLyoqXFxuICAgICAqIENyZWF0ZXMgYSBuZXcgdmVjdG9yLlxcbiAgICAgKiBAbWV0aG9kIGNyZWF0ZVxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0geFxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0geVxcbiAgICAgKiBAcmV0dXJuIHt2ZWN0b3J9IEEgbmV3IHZlY3RvclxcbiAgICAgKi9cXG4gICAgVmVjdG9yLmNyZWF0ZSA9IGZ1bmN0aW9uKHgsIHkpIHtcXG4gICAgICAgI
2HJldHVybiB7IHg6IHggfHwgMCwgeTogeSB8fCAwIH07XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIGEgbmV3IHZlY3RvciB3aXRoIGB4YCBhbmQgYHlgIGNvcGllZCBmcm9tIHRoZSBnaXZlbiBgdmVjdG9yYC5cXG4gICAgICogQG1ldGhvZCBjbG9uZVxcbiAgICAgKiBAcGFyYW0ge3ZlY3Rvcn0gdmVjdG9yXFxuICAgICAqIEByZXR1cm4ge3ZlY3Rvcn0gQSBuZXcgY2xvbmVkIHZlY3RvclxcbiAgICAgKi9cXG4gICAgVmVjdG9yLmNsb25lID0gZnVuY3Rpb24odmVjdG9yKSB7XFxuICAgICAgICByZXR1cm4geyB4OiB2ZWN0b3IueCwgeTogdmVjdG9yLnkgfTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFJldHVybnMgdGhlIG1hZ25pdHVkZSAobGVuZ3RoKSBvZiBhIHZlY3Rvci5cXG4gICAgICogQG1ldGhvZCBtYWduaXR1ZGVcXG4gICAgICogQHBhcmFtIHt2ZWN0b3J9IHZlY3RvclxcbiAgICAgKiBAcmV0dXJuIHtudW1iZXJ9IFRoZSBtYWduaXR1ZGUgb2YgdGhlIHZlY3RvclxcbiAgICAgKi9cXG4gICAgVmVjdG9yLm1hZ25pdHVkZSA9IGZ1bmN0aW9uKHZlY3Rvcikge1xcbiAgICAgICAgcmV0dXJuIE1hdGguc3FydCgodmVjdG9yLnggKiB2ZWN0b3IueCkgKyAodmVjdG9yLnkgKiB2ZWN0b3IueSkpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmV0dXJucyB0aGUgbWFnbml0dWRlIChsZW5ndGgpIG9mIGEgdmVjdG9yICh0aGVyZWZvcmUgc2F2aW5nIGEgYHNxcnRgIG9wZXJhdGlvbikuXFxuICAgICAqIEBtZXRob2QgbWFnbml0dWRlU3F1YXJlZFxcbiAgICAgKiBAcGFyYW0ge3ZlY3Rvcn0gdmVjdG9yXFxuICAgICAqIEByZXR1cm4ge251bWJlcn0gVGhlIHNxdWFyZWQgbWFnbml0dWRlIG9mIHRoZSB2ZWN0b3JcXG4gICAgICovXFxuICAgIFZlY3Rvci5tYWduaXR1ZGVTcXVhcmVkID0gZnVuY3Rpb24odmVjdG9yKSB7XFxuICAgICAgICByZXR1cm4gKHZlY3Rvci54ICogdmVjdG9yLngpICsgKHZlY3Rvci55ICogdmVjdG9yLnkpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUm90YXRlcyB0aGUgdmVjdG9yIGFib3V0ICgwLCAwKSBieSBzcGVjaWZpZWQgYW5nbGUuXFxuICAgICAqIEBtZXRob2Qgcm90YXRlXFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSB2ZWN0b3JcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGFuZ2xlXFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSBbb3V0cHV0XVxcbiAgICAgKiBAcmV0dXJuIHt2ZWN0b3J9IFRoZSB2ZWN0b3Igcm90YXRlZCBhYm91dCAoMCwgMClcXG4gICAgICovXFxuICAgIFZlY3Rvci5yb3RhdGUgPSBmdW5jdGlvbih2ZWN0b3IsIGFuZ2xlLCBvdXRwdXQpIHtcXG4gICAgICAgIHZhciBjb3MgPSBNYXRoLmNvcyhhbmdsZSksIHNpbiA9IE1hdGguc2luKGFuZ2xlKTtcXG4gICAgICAgIGlmICghb3V0cHV0KSBvdXRwdXQgPSB7fTtcXG4gICAgICAgIHZhciB4ID0gdmVjdG9yLnggKiBjb3MgLSB2ZWN0b3IueSAqIHNpbjtcXG4gICAgICAgIG91dHB1dC55ID0gdmVjdG9yLnggKiBzaW4gKyB2ZWN0b3IueSAqIGNvcztcXG4gICAgICAgIG91dHB1dC54ID0geDtcXG4gICAgICAgIHJldHVybiBvdXRwdXQ7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSb3RhdGVzIHRoZSB2ZWN0b3IgYWJvdXQgYSBzcGVjaWZpZWQgcG9pbnQgYnkgc3BlY2lmaWVkIGFuZ2xlLlxcbiAgICAgKiBAbWV0aG9kIHJvdGF0ZUFib3V0XFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSB2ZWN0b3JcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGFuZ2xlXFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSBwb2ludFxcbiAgICAgKiBAcGFyYW0ge3ZlY3Rvcn0gW291dHB1dF1cXG4gICAgICogQHJldHVybiB7dmVjdG9yfSBBIG5ldyB2ZWN0b3Igcm90YXRlZCBhYm91dCB0aGUgcG9pbnRcXG4gICAgICovXFxuICAgIFZlY3Rvci5yb3RhdGVBYm91dCA9IGZ1bmN0aW9uKHZlY3RvciwgYW5nbGUsIHBvaW50LCBvdXRwdXQpIHtcXG4gICAgICAgIHZhciBjb3MgPSBNYXRoLmNvcyhhbmdsZSksIHNpbiA9IE1hdGguc2luKGFuZ2xlKTtcXG4gICAgICAgIGlmICghb3V0cHV0KSBvdXRwdXQgPSB7fTtcXG4gICAgICAgIHZhciB4ID0gcG9pbnQueCArICgodmVjdG9yLnggLSBwb2ludC54KSAqIGNvcyAtICh2ZWN0b3IueSAtIHBvaW50LnkpICogc2luKTtcXG4gICAgICAgIG91dHB1dC55ID0gcG9pbnQueSArICgodmVjdG9yLnggLSBwb2ludC54KSAqIHNpbiArICh2ZWN0b3IueSAtIHBvaW50LnkpICogY29zKTtcXG4gICAgICAgIG91dHB1dC54ID0geDtcXG4gICAgICAgIHJldHVybiBvdXRwdXQ7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBOb3JtYWxpc2VzIGEgdmVjdG9yIChzdWNoIHRoYXQgaXRzIG1hZ25pdHVkZSBpcyBgMWApLlxcbiAgICAgKiBAbWV0aG9kIG5vcm1hbGlzZVxcbiAgICAgKiBAcGFyYW0ge3ZlY3Rvcn0gdmVjdG9yXFxuICAgICAqIEByZXR1cm4ge3ZlY3Rvcn0gQSBuZXcgdmVjdG9yIG5vcm1hbGlzZWRcXG4gICAgICovXFxuICAgIFZlY3Rvci5ub3JtYWxpc2UgPSBmdW5jdGlvbih2ZWN0b3IpIHtcXG4gICAgICAgIHZhciBtYWduaXR1ZGUgPSBWZWN0b3IubWFnbml0dWRlKHZlY3Rvcik7XFxuICAgICAgICBpZiAobWFnbml0dWRlID09PSAwKVxcbiAgICAgICAgICAgIHJldHVybiB7IHg6IDAsIHk6IDAgfTtcXG4gICAgICAgIHJldHVybiB7IHg6IHZlY3Rvci54IC8gbWFnbml0dWRlLCB5OiB2ZWN0b3IueSAvIG1hZ25pdHVkZSB9O1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmV0dXJucyB0aGUgZG90LXByb2R1Y3Qgb2YgdHdvIHZlY3RvcnMuXFxuICAgICAqIEBtZXRob2QgZG90XFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSB2ZWN0b3JBXFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSB2ZWN0b3JCXFxuICAgICAqIEByZXR1cm4ge251bWJlcn0gVGhlIGRvdCBwcm9kdWN0IG9mIHRoZSB0d28gdmVjdG9yc1xcbiAgICAgKi9cXG4gICAgVmVjdG9yLmRvdCA9IGZ1bmN0aW9uKHZlY3RvckEsIHZlY3RvckIpIHtcXG4gICAgICAgIHJldHVybiAodmVjdG9yQS54ICogdmVjdG9yQi54KSArICh2ZWN0b3JBLnkgKiB2ZWN0b3JCLnkpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmV0dXJucyB0aGUgY3Jvc3MtcHJvZHVjdCBvZiB0d28gdmVjdG9ycy5cXG4gICAgICogQG1ldGhvZCBjcm9zc1xcbiAgICAgKiBAcGFyYW0ge3ZlY3Rvcn0gdmVjdG9yQVxcbiAgICAgKiBAcGFyYW0ge3ZlY3Rvcn0gdmVjdG9yQlxcbiAgICAgKiBAcmV0dXJuIHtudW1iZXJ9IFRoZSBjcm9zcyBwcm9kdWN0IG9mIHRoZSB0d28gdmVjdG9yc1xcbiAgICAgKi9cXG4gICAgVmVjdG9yLmNyb3NzID0gZnVuY3Rpb24odmVjdG9yQSwgdmVjdG9yQikge1xcbiAgICAgICAgcmV0dXJuICh2ZWN0b3JBLnggKiB2ZWN0b3JCLnkpIC0gKHZlY3RvckEueSAqIHZlY3RvckIueCk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIHRoZSBjcm9zcy1wcm9kdWN0IG9mIHRocmVlIHZlY3RvcnMuXFxuICAgICAqIEBtZXRob2QgY3Jvc3MzXFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSB2ZWN0b3JBXFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSB2ZWN0b3JCXFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSB2ZWN0b3JDXFxuICAgICAqIEByZXR1cm4ge251bWJlcn0gVGhlIGNyb3NzIHByb2R1Y3Qgb2YgdGhlIHRocmVlIHZlY3RvcnNcXG4gICAgICovXFxuICAgIFZlY3Rvci5jcm9zczMgPSBmdW5jdGlvbih2ZWN0b3JBLCB2ZWN0b3JCLCB2ZWN0b3JDKSB7XFxuICAgICAgICByZXR1cm4gKHZlY3RvckIueCAtIHZlY3RvckEueCkgKiAodmVjdG9yQy55
2IC0gdmVjdG9yQS55KSAtICh2ZWN0b3JCLnkgLSB2ZWN0b3JBLnkpICogKHZlY3RvckMueCAtIHZlY3RvckEueCk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBBZGRzIHRoZSB0d28gdmVjdG9ycy5cXG4gICAgICogQG1ldGhvZCBhZGRcXG4gICAgICogQHBhcmFtIHt2ZWN0b3J9IHZlY3RvckFcXG4gICAgICogQHBhcmFtIHt2ZWN0b3J9IHZlY3RvckJcXG4gICAgICogQHBhcmFtIHt2ZWN0b3J9IFtvdXRwdXRdXFxuICAgICAqIEByZXR1cm4ge3ZlY3Rvcn0gQSBuZXcgdmVjdG9yIG9mIHZlY3RvckEgYW5kIHZlY3RvckIgYWRkZWRcXG4gICAgICovXFxuICAgIFZlY3Rvci5hZGQgPSBmdW5jdGlvbih2ZWN0b3JBLCB2ZWN0b3JCLCBvdXRwdXQpIHtcXG4gICAgICAgIGlmICghb3V0cHV0KSBvdXRwdXQgPSB7fTtcXG4gICAgICAgIG91dHB1dC54ID0gdmVjdG9yQS54ICsgdmVjdG9yQi54O1xcbiAgICAgICAgb3V0cHV0LnkgPSB2ZWN0b3JBLnkgKyB2ZWN0b3JCLnk7XFxuICAgICAgICByZXR1cm4gb3V0cHV0O1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogU3VidHJhY3RzIHRoZSB0d28gdmVjdG9ycy5cXG4gICAgICogQG1ldGhvZCBzdWJcXG4gICAgICogQHBhcmFtIHt2ZWN0b3J9IHZlY3RvckFcXG4gICAgICogQHBhcmFtIHt2ZWN0b3J9IHZlY3RvckJcXG4gICAgICogQHBhcmFtIHt2ZWN0b3J9IFtvdXRwdXRdXFxuICAgICAqIEByZXR1cm4ge3ZlY3Rvcn0gQSBuZXcgdmVjdG9yIG9mIHZlY3RvckEgYW5kIHZlY3RvckIgc3VidHJhY3RlZFxcbiAgICAgKi9cXG4gICAgVmVjdG9yLnN1YiA9IGZ1bmN0aW9uKHZlY3RvckEsIHZlY3RvckIsIG91dHB1dCkge1xcbiAgICAgICAgaWYgKCFvdXRwdXQpIG91dHB1dCA9IHt9O1xcbiAgICAgICAgb3V0cHV0LnggPSB2ZWN0b3JBLnggLSB2ZWN0b3JCLng7XFxuICAgICAgICBvdXRwdXQueSA9IHZlY3RvckEueSAtIHZlY3RvckIueTtcXG4gICAgICAgIHJldHVybiBvdXRwdXQ7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBNdWx0aXBsaWVzIGEgdmVjdG9yIGFuZCBhIHNjYWxhci5cXG4gICAgICogQG1ldGhvZCBtdWx0XFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSB2ZWN0b3JcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHNjYWxhclxcbiAgICAgKiBAcmV0dXJuIHt2ZWN0b3J9IEEgbmV3IHZlY3RvciBtdWx0aXBsaWVkIGJ5IHNjYWxhclxcbiAgICAgKi9cXG4gICAgVmVjdG9yLm11bHQgPSBmdW5jdGlvbih2ZWN0b3IsIHNjYWxhcikge1xcbiAgICAgICAgcmV0dXJuIHsgeDogdmVjdG9yLnggKiBzY2FsYXIsIHk6IHZlY3Rvci55ICogc2NhbGFyIH07XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBEaXZpZGVzIGEgdmVjdG9yIGFuZCBhIHNjYWxhci5cXG4gICAgICogQG1ldGhvZCBkaXZcXG4gICAgICogQHBhcmFtIHt2ZWN0b3J9IHZlY3RvclxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gc2NhbGFyXFxuICAgICAqIEByZXR1cm4ge3ZlY3Rvcn0gQSBuZXcgdmVjdG9yIGRpdmlkZWQgYnkgc2NhbGFyXFxuICAgICAqL1xcbiAgICBWZWN0b3IuZGl2ID0gZnVuY3Rpb24odmVjdG9yLCBzY2FsYXIpIHtcXG4gICAgICAgIHJldHVybiB7IHg6IHZlY3Rvci54IC8gc2NhbGFyLCB5OiB2ZWN0b3IueSAvIHNjYWxhciB9O1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmV0dXJucyB0aGUgcGVycGVuZGljdWxhciB2ZWN0b3IuIFNldCBgbmVnYXRlYCB0byB0cnVlIGZvciB0aGUgcGVycGVuZGljdWxhciBpbiB0aGUgb3Bwb3NpdGUgZGlyZWN0aW9uLlxcbiAgICAgKiBAbWV0aG9kIHBlcnBcXG4gICAgICogQHBhcmFtIHt2ZWN0b3J9IHZlY3RvclxcbiAgICAgKiBAcGFyYW0ge2Jvb2x9IFtuZWdhdGU9ZmFsc2VdXFxuICAgICAqIEByZXR1cm4ge3ZlY3Rvcn0gVGhlIHBlcnBlbmRpY3VsYXIgdmVjdG9yXFxuICAgICAqL1xcbiAgICBWZWN0b3IucGVycCA9IGZ1bmN0aW9uKHZlY3RvciwgbmVnYXRlKSB7XFxuICAgICAgICBuZWdhdGUgPSBuZWdhdGUgPT09IHRydWUgPyAtMSA6IDE7XFxuICAgICAgICByZXR1cm4geyB4OiBuZWdhdGUgKiAtdmVjdG9yLnksIHk6IG5lZ2F0ZSAqIHZlY3Rvci54IH07XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBOZWdhdGVzIGJvdGggY29tcG9uZW50cyBvZiBhIHZlY3RvciBzdWNoIHRoYXQgaXQgcG9pbnRzIGluIHRoZSBvcHBvc2l0ZSBkaXJlY3Rpb24uXFxuICAgICAqIEBtZXRob2QgbmVnXFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSB2ZWN0b3JcXG4gICAgICogQHJldHVybiB7dmVjdG9yfSBUaGUgbmVnYXRlZCB2ZWN0b3JcXG4gICAgICovXFxuICAgIFZlY3Rvci5uZWcgPSBmdW5jdGlvbih2ZWN0b3IpIHtcXG4gICAgICAgIHJldHVybiB7IHg6IC12ZWN0b3IueCwgeTogLXZlY3Rvci55IH07XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIHRoZSBhbmdsZSBiZXR3ZWVuIHRoZSB2ZWN0b3IgYHZlY3RvckIgLSB2ZWN0b3JBYCBhbmQgdGhlIHgtYXhpcyBpbiByYWRpYW5zLlxcbiAgICAgKiBAbWV0aG9kIGFuZ2xlXFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSB2ZWN0b3JBXFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSB2ZWN0b3JCXFxuICAgICAqIEByZXR1cm4ge251bWJlcn0gVGhlIGFuZ2xlIGluIHJhZGlhbnNcXG4gICAgICovXFxuICAgIFZlY3Rvci5hbmdsZSA9IGZ1bmN0aW9uKHZlY3RvckEsIHZlY3RvckIpIHtcXG4gICAgICAgIHJldHVybiBNYXRoLmF0YW4yKHZlY3RvckIueSAtIHZlY3RvckEueSwgdmVjdG9yQi54IC0gdmVjdG9yQS54KTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFRlbXBvcmFyeSB2ZWN0b3IgcG9vbCAobm90IHRocmVhZC1zYWZlKS5cXG4gICAgICogQHByb3BlcnR5IF90ZW1wXFxuICAgICAqIEB0eXBlIHt2ZWN0b3JbXX1cXG4gICAgICogQHByaXZhdGVcXG4gICAgICovXFxuICAgIFZlY3Rvci5fdGVtcCA9IFtcXG4gICAgICAgIFZlY3Rvci5jcmVhdGUoKSwgVmVjdG9yLmNyZWF0ZSgpLCBcXG4gICAgICAgIFZlY3Rvci5jcmVhdGUoKSwgVmVjdG9yLmNyZWF0ZSgpLCBcXG4gICAgICAgIFZlY3Rvci5jcmVhdGUoKSwgVmVjdG9yLmNyZWF0ZSgpXFxuICAgIF07XFxuXFxufSkoKTtcXG5cXG4vKioqLyB9KSxcXG4vKiAzICovXFxuLyoqKi8gKGZ1bmN0aW9uKG1vZHVsZSwgZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xcblxcbi8qKlxcbiogVGhlIGBNYXR0ZXIuVmVydGljZXNgIG1vZHVsZSBjb250YWlucyBtZXRob2RzIGZvciBjcmVhdGluZyBhbmQgbWFuaXB1bGF0aW5nIHNldHMgb2YgdmVydGljZXMuXFxuKiBBIHNldCBvZiB2ZXJ0aWNlcyBpcyBhbiBhcnJheSBvZiBgTWF0dGVyLlZlY3RvcmAgd2l0aCBhZGRpdGlvbmFsIGluZGV4aW5nIHByb3BlcnRpZXMgaW5zZXJ0ZWQgYnkgYFZlcnRpY2VzLmNyZWF0ZWAuXFxuKiBBIGBNYXR0ZXIuQm9keWAgbWFpbnRhaW5zIGEgc2V0IG9mIHZlcnRpY2VzIHRvIHJlcHJlc2VudCB0aGUgc2hhcGUgb2YgdGhlIG9iamVjdCAoaXRzIGNvbnZleCBodWxsKS5cXG4qXFxuKiBTZWUgdGhlIGluY2x1ZGVkIHVzYWdlIFtleGFtcGxlc10oaHR0cHM6Ly9naXRodWIuY29tL2xpYWJydS9tYXR0ZXItanMvdHJlZS9tYXN0ZXIvZXhhbXBsZXMpLlxcbipcXG4qIEBjbGFzcyBWZXJ0aWNlc1xcbiovXFxuXFxudmFyIFZlcnRpY2VzID0ge307XFxuXFxubW9kdWxlLmV4cG9ydHMgPSBWZXJ0aWNlcztcXG5cXG52YXIgVmVjdG9yID0gX193ZWJwYWNrX3JlcXVpcmVfXygyKTtcXG52YXIgQ29tbW9uID0gX193ZWJwYWNrX3JlcXVpcmVfXygwKTtcXG5cXG4oZnVuY3Rpb24oKSB7XFxuXFxuICAgIC8qKlxcbiAgICAgKiBDcmVhdGVzIGEgbmV3IHNldCBvZiBgTWF0dGVyLkJvZHlgIGNvbXBhdGlibGUgdmVydGljZXMuXFxuICAgICAqIFRoZSBgcG9pbnRzYCBhcmd1bWVudCBhY2NlcHRzIGFuIGFycmF5IG9mIGBNYXR0ZXIuVmVjdG9yYCBwb2ludHMgb3JpZW50YXRlZCBhcm91bmQgdGhlIG9yaWdpbiBgKDAsIDApYCwgZm9yIGV4YW1wbGU6XFxuICAgICAqXFxuICAgICAqICAgICBbeyB4OiAwLCB5OiAwIH0sIHsgeDogMjUsIHk6IDUwIH0sIHsgeDogNTAsIHk6IDAgfV1cXG4gICAgICpcXG4gICAgICogVGhlIGBWZXJ0aWNlcy5jcmVhdGVgIG1ldGhvZCByZXR1cm5zIGEgbmV3IGFycmF5IG9mIHZlcnRpY2VzLCB3aGljaCBhcmUgc2ltaWxhciB0byBNYXR0ZXIuVmVjdG9yIG9iamVjdHMsXFxuICAgICAqIGJ1dCB3aXRoIHNvbWUgYWRkaXRpb25hbCByZWZlcmVuY2VzIHJlcXVpcmVkIGZvciBlZmZpY2llbnQgY29sbGlzaW9uIGRldGVjdGlvbiByb3V0aW5lcy5cXG4gICAgICpcXG4gICAgICogVmVydGljZXMgbXVzdCBiZSBzcGVjaWZpZWQgaW4gY2xvY2t3aXNlIG9yZGVyLlxcbiAgICAgKlxcbiAgICAgKiBOb3RlIHRoYXQgdGhlIGBib2R5YCBhcmd1bWVudCBpcyBub3Qgb3B0aW9uYWwsIGEgYE1hdHRlci5Cb2R5YCByZWZlcmVuY2UgbXVzdCBiZSBwcm92aWRlZC5cXG4gICAgICpcXG4gICAgICogQG1ldGhvZCBjcmVhdGVcXG4gICAgICogQHBhcmFtIHt2ZWN0b3JbXX0gcG9pbnRzXFxuICAgICAqIEBwYXJhbSB7Ym9keX0gYm9keVxcbiAgICAgKi9cXG4gICAgVmVydGljZXMuY3JlYXRlID0gZnVuY3Rpb24ocG9pbnRzLCBib2R5KSB7XFxuICAgICAgICB2Y
2XIgdmVydGljZXMgPSBbXTtcXG5cXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcG9pbnRzLmxlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgdmFyIHBvaW50ID0gcG9pbnRzW2ldLFxcbiAgICAgICAgICAgICAgICB2ZXJ0ZXggPSB7XFxuICAgICAgICAgICAgICAgICAgICB4OiBwb2ludC54LFxcbiAgICAgICAgICAgICAgICAgICAgeTogcG9pbnQueSxcXG4gICAgICAgICAgICAgICAgICAgIGluZGV4OiBpLFxcbiAgICAgICAgICAgICAgICAgICAgYm9keTogYm9keSxcXG4gICAgICAgICAgICAgICAgICAgIGlzSW50ZXJuYWw6IGZhbHNlXFxuICAgICAgICAgICAgICAgIH07XFxuXFxuICAgICAgICAgICAgdmVydGljZXMucHVzaCh2ZXJ0ZXgpO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgcmV0dXJuIHZlcnRpY2VzO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUGFyc2VzIGEgc3RyaW5nIGNvbnRhaW5pbmcgb3JkZXJlZCB4IHkgcGFpcnMgc2VwYXJhdGVkIGJ5IHNwYWNlcyAoYW5kIG9wdGlvbmFsbHkgY29tbWFzKSwgXFxuICAgICAqIGludG8gYSBgTWF0dGVyLlZlcnRpY2VzYCBvYmplY3QgZm9yIHRoZSBnaXZlbiBgTWF0dGVyLkJvZHlgLlxcbiAgICAgKiBGb3IgcGFyc2luZyBTVkcgcGF0aHMsIHNlZSBgU3ZnLnBhdGhUb1ZlcnRpY2VzYC5cXG4gICAgICogQG1ldGhvZCBmcm9tUGF0aFxcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGF0aFxcbiAgICAgKiBAcGFyYW0ge2JvZHl9IGJvZHlcXG4gICAgICogQHJldHVybiB7dmVydGljZXN9IHZlcnRpY2VzXFxuICAgICAqL1xcbiAgICBWZXJ0aWNlcy5mcm9tUGF0aCA9IGZ1bmN0aW9uKHBhdGgsIGJvZHkpIHtcXG4gICAgICAgIHZhciBwYXRoUGF0dGVybiA9IC9MP1xcXFxzKihbLVxcXFxkLmVdKylbXFxcXHMsXSooWy1cXFxcZC5lXSspKi9pZyxcXG4gICAgICAgICAgICBwb2ludHMgPSBbXTtcXG5cXG4gICAgICAgIHBhdGgucmVwbGFjZShwYXRoUGF0dGVybiwgZnVuY3Rpb24obWF0Y2gsIHgsIHkpIHtcXG4gICAgICAgICAgICBwb2ludHMucHVzaCh7IHg6IHBhcnNlRmxvYXQoeCksIHk6IHBhcnNlRmxvYXQoeSkgfSk7XFxuICAgICAgICB9KTtcXG5cXG4gICAgICAgIHJldHVybiBWZXJ0aWNlcy5jcmVhdGUocG9pbnRzLCBib2R5KTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFJldHVybnMgdGhlIGNlbnRyZSAoY2VudHJvaWQpIG9mIHRoZSBzZXQgb2YgdmVydGljZXMuXFxuICAgICAqIEBtZXRob2QgY2VudHJlXFxuICAgICAqIEBwYXJhbSB7dmVydGljZXN9IHZlcnRpY2VzXFxuICAgICAqIEByZXR1cm4ge3ZlY3Rvcn0gVGhlIGNlbnRyZSBwb2ludFxcbiAgICAgKi9cXG4gICAgVmVydGljZXMuY2VudHJlID0gZnVuY3Rpb24odmVydGljZXMpIHtcXG4gICAgICAgIHZhciBhcmVhID0gVmVydGljZXMuYXJlYSh2ZXJ0aWNlcywgdHJ1ZSksXFxuICAgICAgICAgICAgY2VudHJlID0geyB4OiAwLCB5OiAwIH0sXFxuICAgICAgICAgICAgY3Jvc3MsXFxuICAgICAgICAgICAgdGVtcCxcXG4gICAgICAgICAgICBqO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB2ZXJ0aWNlcy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIGogPSAoaSArIDEpICUgdmVydGljZXMubGVuZ3RoO1xcbiAgICAgICAgICAgIGNyb3NzID0gVmVjdG9yLmNyb3NzKHZlcnRpY2VzW2ldLCB2ZXJ0aWNlc1tqXSk7XFxuICAgICAgICAgICAgdGVtcCA9IFZlY3Rvci5tdWx0KFZlY3Rvci5hZGQodmVydGljZXNbaV0sIHZlcnRpY2VzW2pdKSwgY3Jvc3MpO1xcbiAgICAgICAgICAgIGNlbnRyZSA9IFZlY3Rvci5hZGQoY2Vud
2HJlLCB0ZW1wKTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHJldHVybiBWZWN0b3IuZGl2KGNlbnRyZSwgNiAqIGFyZWEpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmV0dXJucyB0aGUgYXZlcmFnZSAobWVhbikgb2YgdGhlIHNldCBvZiB2ZXJ0aWNlcy5cXG4gICAgICogQG1ldGhvZCBtZWFuXFxuICAgICAqIEBwYXJhbSB7dmVydGljZXN9IHZlcnRpY2VzXFxuICAgICAqIEByZXR1cm4ge3ZlY3Rvcn0gVGhlIGF2ZXJhZ2UgcG9pbnRcXG4gICAgICovXFxuICAgIFZlcnRpY2VzLm1lYW4gPSBmdW5jdGlvbih2ZXJ0aWNlcykge1xcbiAgICAgICAgdmFyIGF2ZXJhZ2UgPSB7IHg6IDAsIHk6IDAgfTtcXG5cXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdmVydGljZXMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICBhdmVyYWdlLnggKz0gdmVydGljZXNbaV0ueDtcXG4gICAgICAgICAgICBhdmVyYWdlLnkgKz0gdmVydGljZXNbaV0ueTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHJldHVybiBWZWN0b3IuZGl2KGF2ZXJhZ2UsIHZlcnRpY2VzLmxlbmd0aCk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIHRoZSBhcmVhIG9mIHRoZSBzZXQgb2YgdmVydGljZXMuXFxuICAgICAqIEBtZXRob2QgYXJlYVxcbiAgICAgKiBAcGFyYW0ge3ZlcnRpY2VzfSB2ZXJ0aWNlc1xcbiAgICAgKiBAcGFyYW0ge2Jvb2x9IHNpZ25lZFxcbiAgICAgKiBAcmV0dXJuIHtudW1iZXJ9IFRoZSBhcmVhXFxuICAgICAqL1xcbiAgICBWZXJ0aWNlcy5hcmVhID0gZnVuY3Rpb24odmVydGljZXMsIHNpZ25lZCkge1xcbiAgICAgICAgdmFyIGFyZWEgPSAwLFxcbiAgICAgICAgICAgIGogPSB2ZXJ0aWNlcy5sZW5ndGggLSAxO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB2ZXJ0aWNlcy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIGFyZWEgKz0gKHZlcnRpY2VzW2pdLnggLSB2ZXJ0aWNlc1tpXS54KSAqICh2ZXJ0aWNlc1tqXS55ICsgdmVydGljZXNbaV0ueSk7XFxuICAgICAgICAgICAgaiA9IGk7XFxuICAgICAgICB9XFxuXFxuICAgICAgICBpZiAoc2lnbmVkKVxcbiAgICAgICAgICAgIHJldHVybiBhcmVhIC8gMjtcXG5cXG4gICAgICAgIHJldHVybiBNYXRoLmFicyhhcmVhKSAvIDI7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIHRoZSBtb21lbnQgb2YgaW5lcnRpYSAoc2Vjb25kIG1vbWVudCBvZiBhcmVhKSBvZiB0aGUgc2V0IG9mIHZlcnRpY2VzIGdpdmVuIHRoZSB0b3RhbCBtYXNzLlxcbiAgICAgKiBAbWV0aG9kIGluZXJ0aWFcXG4gICAgICogQHBhcmFtIHt2ZXJ0aWNlc30gdmVydGljZXNcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IG1hc3NcXG4gICAgICogQHJldHVybiB7bnVtYmVyfSBUaGUgcG9seWdvbidzIG1vbWVudCBvZiBpbmVydGlhXFxuICAgICAqL1xcbiAgICBWZXJ0aWNlcy5pbmVydGlhID0gZnVuY3Rpb24odmVydGljZXMsIG1hc3MpIHtcXG4gICAgICAgIHZhciBudW1lcmF0b3IgPSAwLFxcbiAgICAgICAgICAgIGRlbm9taW5hdG9yID0gMCxcXG4gICAgICAgICAgICB2ID0gdmVydGljZXMsX
2FxuICAgICAgICAgICAgY3Jvc3MsXFxuICAgICAgICAgICAgajtcXG5cXG4gICAgICAgIC8vIGZpbmQgdGhlIHBvbHlnb24ncyBtb21lbnQgb2YgaW5lcnRpYSwgdXNpbmcgc2Vjb25kIG1vbWVudCBvZiBhcmVhXFxuICAgICAgICAvLyBmcm9tIGVxdWF0aW9ucyBhdCBodHRwOi8vd3d3LnBoeXNpY3Nmb3J1bXMuY29tL3Nob3d0aHJlYWQucGhwP3Q9MjUyOTNcXG4gICAgICAgIGZvciAodmFyIG4gPSAwOyBuIDwgdi5sZW5ndGg7IG4rKykge1xcbiAgICAgICAgICAgIGogPSAobiArIDEpICUgdi5sZW5ndGg7XFxuICAgICAgICAgICAgY3Jvc3MgPSBNYXRoLmFicyhWZWN0b3IuY3Jvc3ModltqXSwgdltuXSkpO1xcbiAgICAgICAgICAgIG51bWVyYXRvciArPSBjcm9zcyAqIChWZWN0b3IuZG90KHZbal0sIHZbal0pICsgVmVjdG9yLmRvdCh2W2pdLCB2W25dKSArIFZlY3Rvci5kb3QodltuXSwgdltuXSkpO1xcbiAgICAgICAgICAgIGRlbm9taW5hdG9yICs9IGNyb3NzO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgcmV0dXJuIChtYXNzIC8gNikgKiAobnVtZXJhdG9yIC8gZGVub21pbmF0b3IpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogVHJhbnNsYXRlcyB0aGUgc2V0IG9mIHZlcnRpY2VzIGluLXBsYWNlLlxcbiAgICAgKiBAbWV0aG9kIHRyYW5zbGF0ZVxcbiAgICAgKiBAcGFyYW0ge3ZlcnRpY2VzfSB2ZXJ0aWNlc1xcbiAgICAgKiBAcGFyYW0ge3ZlY3Rvcn0gdmVjdG9yXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBzY2FsYXJcXG4gICAgICovXFxuICAgIFZlcnRpY2VzLnRyYW5zbGF0ZSA9IGZ1bmN0aW9uKHZlcnRpY2VzLCB2ZWN0b3IsIHNjYWxhcikge1xcbiAgICAgICAgc2NhbGFyID0gdHlwZW9mIHNjYWxhciAhPT0gJ3VuZGVmaW5lZCcgPyBzY2FsYXIgOiAxO1xcblxcbiAgICAgICAgdmFyIHZlcnRpY2VzTGVuZ3RoID0gdmVydGljZXMubGVuZ3RoLFxcbiAgICAgICAgICAgIHRyYW5zbGF0ZVggPSB2ZWN0b3IueCAqIHNjYWxhcixcXG4gICAgICAgICAgICB0cmFuc2xhdGVZID0gdmVjdG9yLnkgKiBzY2FsYXIsXFxuICAgICAgICAgICAgaTtcXG4gICAgICAgIFxcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IHZlcnRpY2VzTGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICB2ZXJ0aWNlc1tpXS54ICs9IHRyYW5zbGF0ZVg7XFxuICAgICAgICAgICAgdmVydGljZXNbaV0ueSArPSB0cmFuc2xhdGVZO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgcmV0dXJuIHZlcnRpY2VzO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUm90YXRlcyB0aGUgc2V0IG9mIHZlcnRpY2VzIGluLXBsYWNlLlxcbiAgICAgKiBAbWV0aG9kIHJvdGF0ZVxcbiAgICAgKiBAcGFyYW0ge3ZlcnRpY2VzfSB2ZXJ0aWNlc1xcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gYW5nbGVcXG4gICAgICogQHBhcmFtIHt2ZWN0b3J9IHBvaW50XFxuICAgICAqL1xcbiAgICBWZXJ0aWNlcy5yb3RhdGUgPSBmdW5jdGlvbih2ZXJ0aWNlcywgYW5nbGUsIHBvaW50KSB7XFxuICAgICAgICBpZiAoYW5nbGUgPT09IDApX
2FxuICAgICAgICAgICAgcmV0dXJuO1xcblxcbiAgICAgICAgdmFyIGNvcyA9IE1hdGguY29zKGFuZ2xlKSxcXG4gICAgICAgICAgICBzaW4gPSBNYXRoLnNpbihhbmdsZSksXFxuICAgICAgICAgICAgcG9pbnRYID0gcG9pbnQueCxcXG4gICAgICAgICAgICBwb2ludFkgPSBwb2ludC55LFxcbiAgICAgICAgICAgIHZlcnRpY2VzTGVuZ3RoID0gdmVydGljZXMubGVuZ3RoLFxcbiAgICAgICAgICAgIHZlcnRleCxcXG4gICAgICAgICAgICBkeCxcXG4gICAgICAgICAgICBkeSxcXG4gICAgICAgICAgICBpO1xcblxcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IHZlcnRpY2VzTGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICB2ZXJ0ZXggPSB2ZXJ0aWNlc1tpXTtcXG4gICAgICAgICAgICBkeCA9IHZlcnRleC54IC0gcG9pbnRYO1xcbiAgICAgICAgICAgIGR5ID0gdmVydGV4LnkgLSBwb2ludFk7XFxuICAgICAgICAgICAgdmVydGV4LnggPSBwb2ludFggKyAoZHggKiBjb3MgLSBkeSAqIHNpbik7XFxuICAgICAgICAgICAgdmVydGV4LnkgPSBwb2ludFkgKyAoZHggKiBzaW4gKyBkeSAqIGNvcyk7XFxuICAgICAgICB9XFxuXFxuICAgICAgICByZXR1cm4gdmVydGljZXM7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgYHBvaW50YCBpcyBpbnNpZGUgdGhlIHNldCBvZiBgdmVydGljZXNgLlxcbiAgICAgKiBAbWV0aG9kIGNvbnRhaW5zXFxuICAgICAqIEBwYXJhbSB7dmVydGljZXN9IHZlcnRpY2VzXFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSBwb2ludFxcbiAgICAgKiBAcmV0dXJuIHtib29sZWFufSBUcnVlIGlmIHRoZSB2ZXJ0aWNlcyBjb250YWlucyBwb2ludCwgb3RoZXJ3aXNlIGZhbHNlXFxuICAgICAqL1xcbiAgICBWZXJ0aWNlcy5jb250YWlucyA9IGZ1bmN0aW9uKHZlcnRpY2VzLCBwb2ludCkge1xcbiAgICAgICAgdmFyIHBvaW50WCA9IHBvaW50LngsXFxuICAgICAgICAgICAgcG9pbnRZID0gcG9pbnQueSxcXG4gICAgICAgICAgICB2ZXJ0aWNlc0xlbmd0aCA9IHZlcnRpY2VzLmxlbmd0aCxcXG4gICAgICAgICAgICB2ZXJ0ZXggPSB2ZXJ0aWNlc1t2ZXJ0aWNlc0xlbmd0aCAtIDFdLFxcbiAgICAgICAgICAgIG5leHRWZXJ0ZXg7XFxuXFxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHZlcnRpY2VzTGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICBuZXh0VmVydGV4ID0gdmVydGljZXNbaV07XFxuXFxuICAgICAgICAgICAgaWYgKChwb2ludFggLSB2ZXJ0ZXgueCkgKiAobmV4dFZlcnRleC55IC0gdmVydGV4LnkpIFxcbiAgICAgICAgICAgICAgICArIChwb2ludFkgLSB2ZXJ0ZXgueSkgKiAodmVydGV4LnggLSBuZXh0VmVydGV4LngpID4gMCkge1xcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XFxuICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgIHZlcnRleCA9IG5leHRWZXJ0ZXg7XFxuICAgICAgICB9XFxuXFxuICAgICAgICByZXR1cm4gdHJ1ZTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFNjYWxlcyB0aGUgdmVydGljZXMgZnJvbSBhIHBvaW50IChkZWZhdWx0IGlzIGNlbnRyZSkgaW4tcGxhY2UuXFxuICAgICAqIEBtZXRob2Qgc2NhbGVcXG4gICAgICogQHBhcmFtIHt2ZXJ0aWNlc30gdmVydGljZXNcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHNjYWxlWFxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gc2NhbGVZXFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSBwb2ludFxcbiAgICAgKi9cXG4gICAgVmVydGljZXMuc2NhbGUgPSBmdW5jdGlvbih2ZXJ0aWNlcywgc2NhbGVYLCBzY2FsZVksIHBvaW50KSB7XFxuICAgICAgICBpZiAoc2NhbGVYID09PSAxICYmIHNjYWxlWSA9PT0gMSlcXG4gICAgICAgICAgICByZXR1cm4gdmVydGljZXM7XFxuXFxuICAgICAgICBwb2ludCA9IHBvaW50IHx8IFZlcnRpY2VzLmNlbnRyZSh2ZXJ0aWNlcyk7XFxuXFxuICAgICAgICB2Y
2XIgdmVydGV4LFxcbiAgICAgICAgICAgIGRlbHRhO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB2ZXJ0aWNlcy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHZlcnRleCA9IHZlcnRpY2VzW2ldO1xcbiAgICAgICAgICAgIGRlbHRhID0gVmVjdG9yLnN1Yih2ZXJ0ZXgsIHBvaW50KTtcXG4gICAgICAgICAgICB2ZXJ0aWNlc1tpXS54ID0gcG9pbnQueCArIGRlbHRhLnggKiBzY2FsZVg7XFxuICAgICAgICAgICAgdmVydGljZXNbaV0ueSA9IHBvaW50LnkgKyBkZWx0YS55ICogc2NhbGVZO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgcmV0dXJuIHZlcnRpY2VzO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogQ2hhbWZlcnMgYSBzZXQgb2YgdmVydGljZXMgYnkgZ2l2aW5nIHRoZW0gcm91bmRlZCBjb3JuZXJzLCByZXR1cm5zIGEgbmV3IHNldCBvZiB2ZXJ0aWNlcy5cXG4gICAgICogVGhlIHJhZGl1cyBwYXJhbWV0ZXIgaXMgYSBzaW5nbGUgbnVtYmVyIG9yIGFuIGFycmF5IHRvIHNwZWNpZnkgdGhlIHJhZGl1cyBmb3IgZWFjaCB2ZXJ0ZXguXFxuICAgICAqIEBtZXRob2QgY2hhbWZlclxcbiAgICAgKiBAcGFyYW0ge3ZlcnRpY2VzfSB2ZXJ0aWNlc1xcbiAgICAgKiBAcGFyYW0ge251bWJlcltdfSByYWRpdXNcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHF1YWxpdHlcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHF1YWxpdHlNaW5cXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHF1YWxpdHlNYXhcXG4gICAgICovXFxuICAgIFZlcnRpY2VzLmNoYW1mZXIgPSBmdW5jdGlvbih2ZXJ0aWNlcywgcmFkaXVzLCBxdWFsaXR5LCBxdWFsaXR5TWluLCBxdWFsaXR5TWF4KSB7XFxuICAgICAgICBpZiAodHlwZW9mIHJhZGl1cyA9PT0gJ251bWJlcicpIHtcXG4gICAgICAgICAgICByYWRpdXMgPSBbcmFkaXVzXTtcXG4gICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgcmFkaXVzID0gcmFkaXVzIHx8IFs4XTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIC8vIHF1YWxpdHkgZGVmYXVsdHMgdG8gLTEsIHdoaWNoIGlzIGF1dG9cXG4gICAgICAgIHF1YWxpdHkgPSAodHlwZW9mIHF1YWxpdHkgIT09ICd1bmRlZmluZWQnKSA/IHF1YWxpdHkgOiAtMTtcXG4gICAgICAgIHF1YWxpdHlNaW4gPSBxdWFsaXR5TWluIHx8IDI7XFxuICAgICAgICBxdWFsaXR5TWF4ID0gcXVhbGl0eU1heCB8fCAxNDtcXG5cXG4gICAgICAgIHZhciBuZXdWZXJ0aWNlcyA9IFtdO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB2ZXJ0aWNlcy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHZhciBwcmV2VmVydGV4ID0gdmVydGljZXNbaSAtIDEgPj0gMCA/IGkgLSAxIDogdmVydGljZXMubGVuZ3RoIC0gMV0sXFxuICAgICAgICAgICAgICAgIHZlcnRleCA9IHZlcnRpY2VzW2ldLFxcbiAgICAgICAgICAgICAgICBuZXh0VmVydGV4ID0gdmVydGljZXNbKGkgKyAxKSAlIHZlcnRpY2VzLmxlbmd0aF0sXFxuICAgICAgICAgICAgICAgIGN1cnJlbnRSYWRpdXMgPSByYWRpdXNbaSA8IHJhZGl1cy5sZW5ndGggPyBpIDogcmFkaXVzLmxlbmd0aCAtIDFdO1xcblxcbiAgICAgICAgICAgIGlmIChjdXJyZW50UmFkaXVzID09PSAwKSB7XFxuICAgICAgICAgICAgICAgIG5ld1ZlcnRpY2VzLnB1c2godmVydGV4KTtcXG4gICAgICAgICAgICAgICAgY29udGludWU7XFxuICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgIHZhciBwcmV2Tm9ybWFsID0gVmVjdG9yLm5vcm1hbGlzZSh7IFxcbiAgICAgICAgICAgICAgICB4OiB2ZXJ0ZXgueSAtIHByZXZWZXJ0ZXgueSwgXFxuICAgICAgICAgICAgICAgIHk6IHByZXZWZXJ0ZXgueCAtIHZlcnRleC54XFxuICAgICAgICAgICAgfSk7XFxuXFxuICAgICAgICAgICAgdmFyIG5leHROb3JtYWwgPSBWZWN0b3Iubm9ybWFsaXNlKHsgXFxuICAgICAgICAgICAgICAgIHg6IG5leHRWZXJ0ZXgueSAtIHZlcnRleC55LCBcXG4gICAgICAgICAgICAgICAgeTogdmVydGV4LnggLSBuZXh0VmVydGV4LnhcXG4gICAgICAgICAgICB9KTtcXG5cXG4gICAgICAgICAgICB2Y
2XIgZGlhZ29uYWxSYWRpdXMgPSBNYXRoLnNxcnQoMiAqIE1hdGgucG93KGN1cnJlbnRSYWRpdXMsIDIpKSxcXG4gICAgICAgICAgICAgICAgcmFkaXVzVmVjdG9yID0gVmVjdG9yLm11bHQoQ29tbW9uLmNsb25lKHByZXZOb3JtYWwpLCBjdXJyZW50UmFkaXVzKSxcXG4gICAgICAgICAgICAgICAgbWlkTm9ybWFsID0gVmVjdG9yLm5vcm1hbGlzZShWZWN0b3IubXVsdChWZWN0b3IuYWRkKHByZXZOb3JtYWwsIG5leHROb3JtYWwpLCAwLjUpKSxcXG4gICAgICAgICAgICAgICAgc2NhbGVkVmVydGV4ID0gVmVjdG9yLnN1Yih2ZXJ0ZXgsIFZlY3Rvci5tdWx0KG1pZE5vcm1hbCwgZGlhZ29uYWxSYWRpdXMpKTtcXG5cXG4gICAgICAgICAgICB2YXIgcHJlY2lzaW9uID0gcXVhbGl0eTtcXG5cXG4gICAgICAgICAgICBpZiAocXVhbGl0eSA9PT0gLTEpIHtcXG4gICAgICAgICAgICAgICAgLy8gYXV0b21hdGljYWxseSBkZWNpZGUgcHJlY2lzaW9uXFxuICAgICAgICAgICAgICAgIHByZWNpc2lvbiA9IE1hdGgucG93KGN1cnJlbnRSYWRpdXMsIDAuMzIpICogMS43NTtcXG4gICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgcHJlY2lzaW9uID0gQ29tbW9uLmNsYW1wKHByZWNpc2lvbiwgcXVhbGl0eU1pbiwgcXVhbGl0eU1heCk7XFxuXFxuICAgICAgICAgICAgLy8gdXNlIGFuIGV2ZW4gdmFsdWUgZm9yIHByZWNpc2lvbiwgbW9yZSBsaWtlbHkgdG8gcmVkdWNlIGF4ZXMgYnkgdXNpbmcgc3ltbWV0cnlcXG4gICAgICAgICAgICBpZiAocHJlY2lzaW9uICUgMiA9PT0gMSlcXG4gICAgICAgICAgICAgICAgcHJlY2lzaW9uICs9IDE7XFxuXFxuICAgICAgICAgICAgdmFyIGFscGhhID0gTWF0aC5hY29zKFZlY3Rvci5kb3QocHJldk5vcm1hbCwgbmV4dE5vcm1hbCkpLFxcbiAgICAgICAgICAgICAgICB0aGV0YSA9IGFscGhhIC8gcHJlY2lzaW9uO1xcblxcbiAgICAgICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgcHJlY2lzaW9uOyBqKyspIHtcXG4gICAgICAgICAgICAgICAgbmV3VmVydGljZXMucHVzaChWZWN0b3IuYWRkKFZlY3Rvci5yb3RhdGUocmFkaXVzVmVjdG9yLCB0aGV0YSAqIGopLCBzY2FsZWRWZXJ0ZXgpKTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuXFxuICAgICAgICByZXR1cm4gbmV3VmVydGljZXM7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBTb3J0cyB0aGUgaW5wdXQgdmVydGljZXMgaW50byBjbG9ja3dpc2Ugb3JkZXIgaW4gcGxhY2UuXFxuICAgICAqIEBtZXRob2QgY2xvY2t3aXNlU29ydFxcbiAgICAgKiBAcGFyYW0ge3ZlcnRpY2VzfSB2ZXJ0aWNlc1xcbiAgICAgKiBAcmV0dXJuIHt2ZXJ0aWNlc30gdmVydGljZXNcXG4gICAgICovXFxuICAgIFZlcnRpY2VzLmNsb2Nrd2lzZVNvcnQgPSBmdW5jdGlvbih2ZXJ0aWNlcykge1xcbiAgICAgICAgdmFyIGNlbnRyZSA9IFZlcnRpY2VzLm1lYW4odmVydGljZXMpO1xcblxcbiAgICAgICAgdmVydGljZXMuc29ydChmdW5jdGlvbih2ZXJ0ZXhBLCB2ZXJ0ZXhCKSB7XFxuICAgICAgICAgICAgcmV0dXJuIFZlY3Rvci5hbmdsZShjZW50cmUsIHZlcnRleEEpIC0gVmVjdG9yLmFuZ2xlKGNlbnRyZSwgdmVydGV4Qik7XFxuICAgICAgICB9KTtcXG5cXG4gICAgICAgIHJldHVybiB2ZXJ0aWNlcztcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgdmVydGljZXMgZm9ybSBhIGNvbnZleCBzaGFwZSAodmVydGljZXMgbXVzdCBiZSBpbiBjbG9ja3dpc2Ugb3JkZXIpLlxcbiAgICAgKiBAbWV0aG9kIGlzQ29udmV4XFxuICAgICAqIEBwYXJhbSB7dmVydGljZXN9IHZlcnRpY2VzXFxuICAgICAqIEByZXR1cm4ge2Jvb2x9IGB0cnVlYCBpZiB0aGUgYHZlcnRpY2VzYCBhcmUgY29udmV4LCBgZmFsc2VgIGlmIG5vdCAob3IgYG51bGxgIGlmIG5vdCBjb21wdXRhYmxlKS5cXG4gICAgICovXFxuICAgIFZlcnRpY2VzLmlzQ29udmV4ID0gZnVuY3Rpb24odmVydGljZXMpIHtcXG4gICAgICAgIC8vIGh0dHA6Ly9wYXVsYm91cmtlLm5ldC9nZW9tZXRyeS9wb2x5Z29ubWVzaC9cXG4gICAgICAgIC8vIENvcHlyaWdodCAoYykgUGF1bCBCb3Vya2UgKHVzZSBwZXJtaXR0ZWQpXFxuXFxuICAgICAgICB2Y
2XIgZmxhZyA9IDAsXFxuICAgICAgICAgICAgbiA9IHZlcnRpY2VzLmxlbmd0aCxcXG4gICAgICAgICAgICBpLFxcbiAgICAgICAgICAgIGosXFxuICAgICAgICAgICAgayxcXG4gICAgICAgICAgICB6O1xcblxcbiAgICAgICAgaWYgKG4gPCAzKVxcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xcblxcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IG47IGkrKykge1xcbiAgICAgICAgICAgIGogPSAoaSArIDEpICUgbjtcXG4gICAgICAgICAgICBrID0gKGkgKyAyKSAlIG47XFxuICAgICAgICAgICAgeiA9ICh2ZXJ0aWNlc1tqXS54IC0gdmVydGljZXNbaV0ueCkgKiAodmVydGljZXNba10ueSAtIHZlcnRpY2VzW2pdLnkpO1xcbiAgICAgICAgICAgIHogLT0gKHZlcnRpY2VzW2pdLnkgLSB2ZXJ0aWNlc1tpXS55KSAqICh2ZXJ0aWNlc1trXS54IC0gdmVydGljZXNbal0ueCk7XFxuXFxuICAgICAgICAgICAgaWYgKHogPCAwKSB7XFxuICAgICAgICAgICAgICAgIGZsYWcgfD0gMTtcXG4gICAgICAgICAgICB9IGVsc2UgaWYgKHogPiAwKSB7XFxuICAgICAgICAgICAgICAgIGZsYWcgfD0gMjtcXG4gICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgaWYgKGZsYWcgPT09IDMpIHtcXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG5cXG4gICAgICAgIGlmIChmbGFnICE9PSAwKXtcXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcXG4gICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XFxuICAgICAgICB9XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIHRoZSBjb252ZXggaHVsbCBvZiB0aGUgaW5wdXQgdmVydGljZXMgYXMgYSBuZXcgYXJyYXkgb2YgcG9pbnRzLlxcbiAgICAgKiBAbWV0aG9kIGh1bGxcXG4gICAgICogQHBhcmFtIHt2ZXJ0aWNlc30gdmVydGljZXNcXG4gICAgICogQHJldHVybiBbdmVydGV4XSB2ZXJ0aWNlc1xcbiAgICAgKi9cXG4gICAgVmVydGljZXMuaHVsbCA9IGZ1bmN0aW9uKHZlcnRpY2VzKSB7XFxuICAgICAgICAvLyBodHRwOi8vZ2VvbWFsZ29yaXRobXMuY29tL2ExMC1faHVsbC0xLmh0bWxcXG5cXG4gICAgICAgIHZhciB1cHBlciA9IFtdLFxcbiAgICAgICAgICAgIGxvd2VyID0gW10sIFxcbiAgICAgICAgICAgIHZlcnRleCxcXG4gICAgICAgICAgICBpO1xcblxcbiAgICAgICAgLy8gc29ydCB2ZXJ0aWNlcyBvbiB4LWF4aXMgKHktYXhpcyBmb3IgdGllcylcXG4gICAgICAgIHZlcnRpY2VzID0gdmVydGljZXMuc2xpY2UoMCk7XFxuICAgICAgICB2ZXJ0aWNlcy5zb3J0KGZ1bmN0aW9uKHZlcnRleEEsIHZlcnRleEIpIHtcXG4gICAgICAgICAgICB2Y
2XIgZHggPSB2ZXJ0ZXhBLnggLSB2ZXJ0ZXhCLng7XFxuICAgICAgICAgICAgcmV0dXJuIGR4ICE9PSAwID8gZHggOiB2ZXJ0ZXhBLnkgLSB2ZXJ0ZXhCLnk7XFxuICAgICAgICB9KTtcXG5cXG4gICAgICAgIC8vIGJ1aWxkIGxvd2VyIGh1bGxcXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCB2ZXJ0aWNlcy5sZW5ndGg7IGkgKz0gMSkge1xcbiAgICAgICAgICAgIHZlcnRleCA9IHZlcnRpY2VzW2ldO1xcblxcbiAgICAgICAgICAgIHdoaWxlIChsb3dlci5sZW5ndGggPj0gMiBcXG4gICAgICAgICAgICAgICAgICAgJiYgVmVjdG9yLmNyb3NzMyhsb3dlcltsb3dlci5sZW5ndGggLSAyXSwgbG93ZXJbbG93ZXIubGVuZ3RoIC0gMV0sIHZlcnRleCkgPD0gMCkge1xcbiAgICAgICAgICAgICAgICBsb3dlci5wb3AoKTtcXG4gICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgbG93ZXIucHVzaCh2ZXJ0ZXgpO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgLy8gYnVpbGQgdXBwZXIgaHVsbFxcbiAgICAgICAgZm9yIChpID0gdmVydGljZXMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpIC09IDEpIHtcXG4gICAgICAgICAgICB2ZXJ0ZXggPSB2ZXJ0aWNlc1tpXTtcXG5cXG4gICAgICAgICAgICB3aGlsZSAodXBwZXIubGVuZ3RoID49IDIgXFxuICAgICAgICAgICAgICAgICAgICYmIFZlY3Rvci5jcm9zczModXBwZXJbdXBwZXIubGVuZ3RoIC0gMl0sIHVwcGVyW3VwcGVyLmxlbmd0aCAtIDFdLCB2ZXJ0ZXgpIDw9IDApIHtcXG4gICAgICAgICAgICAgICAgdXBwZXIucG9wKCk7XFxuICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgIHVwcGVyLnB1c2godmVydGV4KTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIC8vIGNvbmNhdGVuYXRpb24gb2YgdGhlIGxvd2VyIGFuZCB1cHBlciBodWxscyBnaXZlcyB0aGUgY29udmV4IGh1bGxcXG4gICAgICAgIC8vIG9taXQgbGFzdCBwb2ludHMgYmVjYXVzZSB0aGV5IGFyZSByZXBlYXRlZCBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBvdGhlciBsaXN0XFxuICAgICAgICB1cHBlci5wb3AoKTtcXG4gICAgICAgIGxvd2VyLnBvcCgpO1xcblxcbiAgICAgICAgcmV0dXJuIHVwcGVyLmNvbmNhdChsb3dlcik7XFxuICAgIH07XFxuXFxufSkoKTtcXG5cXG5cXG4vKioqLyB9KSxcXG4vKiA0ICovXFxuLyoqKi8gKGZ1bmN0aW9uKG1vZHVsZSwgZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xcblxcbi8qKlxcbiogVGhlIGBNYXR0ZXIuQm9keWAgbW9kdWxlIGNvbnRhaW5zIG1ldGhvZHMgZm9yIGNyZWF0aW5nIGFuZCBtYW5pcHVsYXRpbmcgcmlnaWQgYm9kaWVzLlxcbiogRm9yIGNyZWF0aW5nIGJvZGllcyB3aXRoIGNvbW1vbiBjb25maWd1cmF0aW9ucyBzdWNoIGFzIHJlY3RhbmdsZXMsIGNpcmNsZXMgYW5kIG90aGVyIHBvbHlnb25zIHNlZSB0aGUgbW9kdWxlIGBNYXR0ZXIuQm9kaWVzYC5cXG4qXFxuKiBTZWUgdGhlIGluY2x1ZGVkIHVzYWdlIFtleGFtcGxlc10oaHR0cHM6Ly9naXRodWIuY29tL2xpYWJydS9tYXR0ZXItanMvdHJlZS9tYXN0ZXIvZXhhbXBsZXMpLlxcblxcbiogQGNsYXNzIEJvZHlcXG4qL1xcblxcbnZhciBCb2R5ID0ge307XFxuXFxubW9kdWxlLmV4cG9ydHMgPSBCb2R5O1xcblxcbnZhciBWZXJ0aWNlcyA9IF9fd2VicGFja19yZXF1aXJlX18oMyk7XFxudmFyIFZlY3RvciA9IF9fd2VicGFja19yZXF1aXJlX18oMik7XFxudmFyIFNsZWVwaW5nID0gX193ZWJwYWNrX3JlcXVpcmVfXyg3KTtcXG52YXIgQ29tbW9uID0gX193ZWJwYWNrX3JlcXVpcmVfXygwKTtcXG52YXIgQm91bmRzID0gX193ZWJwYWNrX3JlcXVpcmVfXygxKTtcXG52YXIgQXhlcyA9IF9fd2VicGFja19yZXF1aXJlX18oMTEpO1xcblxcbihmdW5jdGlvbigpIHtcXG5cXG4gICAgQm9keS5fdGltZUNvcnJlY3Rpb24gPSB0cnVlO1xcbiAgICBCb2R5Ll9pbmVydGlhU2NhbGUgPSA0O1xcbiAgICBCb2R5Ll9uZXh0Q29sbGlkaW5nR3JvdXBJZCA9IDE7XFxuICAgIEJvZHkuX25leHROb25Db2xsaWRpbmdHcm91cElkID0gLTE7XFxuICAgIEJvZHkuX25leHRDYXRlZ29yeSA9IDB4MDAwMTtcXG4gICAgQm9keS5fYmFzZURlbHRhID0gMTAwMCAvIDYwO1xcblxcbiAgICAvKipcXG4gICAgICogQ3JlYXRlcyBhIG5ldyByaWdpZCBib2R5IG1vZGVsLiBUaGUgb3B0aW9ucyBwYXJhbWV0ZXIgaXMgYW4gb2JqZWN0IHRoYXQgc3BlY2lmaWVzIGFueSBwcm9wZXJ0aWVzIHlvdSB3aXNoIHRvIG92ZXJyaWRlIHRoZSBkZWZhdWx0cy5cXG4gICAgICogQWxsIHByb3BlcnRpZXMgaGF2ZSBkZWZhdWx0IHZhbHVlcywgYW5kIG1hbnkgYXJlIHByZS1jYWxjdWxhdGVkIGF1dG9tYXRpY2FsbHkgYmFzZWQgb24gb3RoZXIgcHJvcGVydGllcy5cXG4gICAgICogVmVydGljZXMgbXVzdCBiZSBzcGVjaWZpZWQgaW4gY2xvY2t3aXNlIG9yZGVyLlxcbiAgICAgKiBTZWUgdGhlIHByb3BlcnRpZXMgc2VjdGlvbiBiZWxvdyBmb3IgZGV0YWlsZWQgaW5mb3JtYXRpb24gb24gd2hhdCB5b3UgY2FuIHBhc3MgdmlhIHRoZSBgb3B0aW9uc2Agb2JqZWN0LlxcbiAgICAgKiBAbWV0aG9kIGNyZWF0ZVxcbiAgICAgKiBAcGFyYW0ge30gb3B0aW9uc1xcbiAgICAgKiBAcmV0dXJuIHtib2R5fSBib2R5XFxuICAgICAqL1xcbiAgICBCb2R5LmNyZWF0ZSA9IGZ1bmN0aW9uKG9wdGlvbnMpIHtcXG4gICAgICAgIHZhciBkZWZhdWx0cyA9IHtcXG4gICAgICAgICAgICBpZDogQ29tbW9uLm5leHRJZCgpLFxcbiAgICAgICAgICAgIHR5cGU6ICdib2R5JyxcXG4gICAgICAgICAgICBsYWJlbDogJ0JvZHknLFxcbiAgICAgICAgICAgIHBhcnRzOiBbXSxcXG4gICAgICAgICAgICBwbHVnaW46IHt9LFxcbiAgICAgICAgICAgIGFuZ2xlOiAwLFxcbiAgICAgICAgICAgIHZlcnRpY2VzOiBWZXJ0aWNlcy5mcm9tUGF0aCgnTCAwIDAgTCA0MCAwIEwgNDAgNDAgTCAwIDQwJyksXFxuICAgICAgICAgICAgcG9zaXRpb246IHsgeDogMCwgeTogMCB9LFxcbiAgICAgICAgICAgIGZvcmNlOiB7IHg6IDAsIHk6IDAgfSxcXG4gICAgICAgICAgICB0b3JxdWU6IDAsXFxuICAgICAgICAgICAgcG9zaXRpb25JbXB1bHNlOiB7IHg6IDAsIHk6IDAgfSxcXG4gICAgICAgICAgICBjb25zdHJhaW50SW1wdWxzZTogeyB4OiAwLCB5OiAwLCBhbmdsZTogMCB9LFxcbiAgICAgICAgICAgI
2HRvdGFsQ29udGFjdHM6IDAsXFxuICAgICAgICAgICAgc3BlZWQ6IDAsXFxuICAgICAgICAgICAgYW5ndWxhclNwZWVkOiAwLFxcbiAgICAgICAgICAgIHZlbG9jaXR5OiB7IHg6IDAsIHk6IDAgfSxcXG4gICAgICAgICAgICBhbmd1bGFyVmVsb2NpdHk6IDAsXFxuICAgICAgICAgICAgaXNTZW5zb3I6IGZhbHNlLFxcbiAgICAgICAgICAgIGlzU3RhdGljOiBmYWxzZSxcXG4gICAgICAgICAgICBpc1NsZWVwaW5nOiBmYWxzZSxcXG4gICAgICAgICAgICBtb3Rpb246IDAsXFxuICAgICAgICAgICAgc2xlZXBUaHJlc2hvbGQ6IDYwLFxcbiAgICAgICAgICAgIGRlbnNpdHk6IDAuMDAxLFxcbiAgICAgICAgICAgIHJlc3RpdHV0aW9uOiAwLFxcbiAgICAgICAgICAgIGZyaWN0aW9uOiAwLjEsXFxuICAgICAgICAgICAgZnJpY3Rpb25TdGF0aWM6IDAuNSxcXG4gICAgICAgICAgICBmcmljdGlvbkFpcjogMC4wMSxcXG4gICAgICAgICAgICBjb2xsaXNpb25GaWx0ZXI6IHtcXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IDB4MDAwMSxcXG4gICAgICAgICAgICAgICAgbWFzazogMHhGRkZGRkZGRixcXG4gICAgICAgICAgICAgICAgZ3JvdXA6IDBcXG4gICAgICAgICAgICB9LFxcbiAgICAgICAgICAgIHNsb3A6IDAuMDUsXFxuICAgICAgICAgICAgdGltZVNjYWxlOiAxLFxcbiAgICAgICAgICAgIHJlbmRlcjoge1xcbiAgICAgICAgICAgICAgICB2aXNpYmxlOiB0cnVlLFxcbiAgICAgICAgICAgICAgICBvcGFjaXR5OiAxLFxcbiAgICAgICAgICAgICAgICBzdHJva2VTdHlsZTogbnVsbCxcXG4gICAgICAgICAgICAgICAgZmlsbFN0eWxlOiBudWxsLFxcbiAgICAgICAgICAgICAgICBsaW5lV2lkdGg6IG51bGwsXFxuICAgICAgICAgICAgICAgIHNwcml0ZToge1xcbiAgICAgICAgICAgICAgICAgICAgeFNjYWxlOiAxLFxcbiAgICAgICAgICAgICAgICAgICAgeVNjYWxlOiAxLFxcbiAgICAgICAgICAgICAgICAgICAgeE9mZnNldDogMCxcXG4gICAgICAgICAgICAgICAgICAgIHlPZmZzZXQ6IDBcXG4gICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgIH0sXFxuICAgICAgICAgICAgZXZlbnRzOiBudWxsLFxcbiAgICAgICAgICAgIGJvdW5kczogbnVsbCxcXG4gICAgICAgICAgICBjaGFtZmVyOiBudWxsLFxcbiAgICAgICAgICAgIGNpcmNsZVJhZGl1czogMCxcXG4gICAgICAgICAgICBwb3NpdGlvblByZXY6IG51bGwsXFxuICAgICAgICAgICAgYW5nbGVQcmV2OiAwLFxcbiAgICAgICAgICAgIHBhcmVudDogbnVsbCxcXG4gICAgICAgICAgICBheGVzOiBudWxsLFxcbiAgICAgICAgICAgIGFyZWE6IDAsXFxuICAgICAgICAgICAgbWFzczogMCxcXG4gICAgICAgICAgICBpbmVydGlhOiAwLFxcbiAgICAgICAgICAgIGRlbHRhVGltZTogMTAwMCAvIDYwLFxcbiAgICAgICAgICAgIF9vcmlnaW5hbDogbnVsbFxcbiAgICAgICAgfTtcXG5cXG4gICAgICAgIHZhciBib2R5ID0gQ29tbW9uLmV4dGVuZChkZWZhdWx0cywgb3B0aW9ucyk7XFxuXFxuICAgICAgICBfaW5pdFByb3BlcnRpZXMoYm9keSwgb3B0aW9ucyk7XFxuXFxuICAgICAgICByZXR1cm4gYm9keTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFJldHVybnMgdGhlIG5leHQgdW5pcXVlIGdyb3VwIGluZGV4IGZvciB3aGljaCBib2RpZXMgd2lsbCBjb2xsaWRlLlxcbiAgICAgKiBJZiBgaXNOb25Db2xsaWRpbmdgIGlzIGB0cnVlYCwgcmV0dXJucyB0aGUgbmV4dCB1bmlxdWUgZ3JvdXAgaW5kZXggZm9yIHdoaWNoIGJvZGllcyB3aWxsIF9ub3RfIGNvbGxpZGUuXFxuICAgICAqIFNlZSBgYm9keS5jb2xsaXNpb25GaWx0ZXJgIGZvciBtb3JlIGluZm9ybWF0aW9uLlxcbiAgICAgKiBAbWV0aG9kIG5leHRHcm91cFxcbiAgICAgKiBAcGFyYW0ge2Jvb2x9IFtpc05vbkNvbGxpZGluZz1mYWxzZV1cXG4gICAgICogQHJldHVybiB7TnVtYmVyfSBVbmlxdWUgZ3JvdXAgaW5kZXhcXG4gICAgICovXFxuICAgIEJvZHkubmV4dEdyb3VwID0gZnVuY3Rpb24oaXNOb25Db2xsaWRpbmcpIHtcXG4gICAgICAgIGlmIChpc05vbkNvbGxpZGluZylcXG4gICAgICAgICAgICByZXR1cm4gQm9keS5fbmV4dE5vbkNvbGxpZGluZ0dyb3VwSWQtLTtcXG5cXG4gICAgICAgIHJldHVybiBCb2R5Ll9uZXh0Q29sbGlkaW5nR3JvdXBJZCsrO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmV0dXJucyB0aGUgbmV4dCB1bmlxdWUgY2F0ZWdvcnkgYml0ZmllbGQgKHN0YXJ0aW5nIGFmdGVyIHRoZSBpbml0aWFsIGRlZmF1bHQgY2F0ZWdvcnkgYDB4MDAwMWApLlxcbiAgICAgKiBUaGVyZSBhcmUgMzIgYXZhaWxhYmxlLiBTZWUgYGJvZHkuY29sbGlzaW9uRmlsdGVyYCBmb3IgbW9yZSBpbmZvcm1hdGlvbi5cXG4gICAgICogQG1ldGhvZCBuZXh0Q2F0ZWdvcnlcXG4gICAgICogQHJldHVybiB7TnVtYmVyfSBVbmlxdWUgY2F0ZWdvcnkgYml0ZmllbGRcXG4gICAgICovXFxuICAgIEJvZHkubmV4dENhdGVnb3J5ID0gZnVuY3Rpb24oKSB7XFxuICAgICAgICBCb2R5Ll9uZXh0Q2F0ZWdvcnkgPSBCb2R5Ll9uZXh0Q2F0ZWdvcnkgPDwgMTtcXG4gICAgICAgIHJldHVybiBCb2R5Ll9uZXh0Q2F0ZWdvcnk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBJbml0aWFsaXNlcyBib2R5IHByb3BlcnRpZXMuXFxuICAgICAqIEBtZXRob2QgX2luaXRQcm9wZXJ0aWVzXFxuICAgICAqIEBwcml2YXRlXFxuICAgICAqIEBwYXJhbSB7Ym9keX0gYm9keVxcbiAgICAgKiBAcGFyYW0ge30gW29wdGlvbnNdXFxuICAgICAqL1xcbiAgICB2YXIgX2luaXRQcm9wZXJ0aWVzID0gZnVuY3Rpb24oYm9keSwgb3B0aW9ucykge1xcbiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XFxuXFxuICAgICAgICAvLyBpbml0IHJlcXVpcmVkIHByb3BlcnRpZXMgKG9yZGVyIGlzIGltcG9ydGFudClcXG4gICAgICAgIEJvZHkuc2V0KGJvZHksIHtcXG4gICAgICAgICAgICBib3VuZHM6IGJvZHkuYm91bmRzIHx8IEJvdW5kcy5jcmVhdGUoYm9keS52ZXJ0aWNlcyksXFxuICAgICAgICAgICAgcG9zaXRpb25QcmV2OiBib2R5LnBvc2l0aW9uUHJldiB8fCBWZWN0b3IuY2xvbmUoYm9keS5wb3NpdGlvbiksXFxuICAgICAgICAgICAgYW5nbGVQcmV2OiBib2R5LmFuZ2xlUHJldiB8fCBib2R5LmFuZ2xlLFxcbiAgICAgICAgICAgI
2HZlcnRpY2VzOiBib2R5LnZlcnRpY2VzLFxcbiAgICAgICAgICAgIHBhcnRzOiBib2R5LnBhcnRzIHx8IFtib2R5XSxcXG4gICAgICAgICAgICBpc1N0YXRpYzogYm9keS5pc1N0YXRpYyxcXG4gICAgICAgICAgICBpc1NsZWVwaW5nOiBib2R5LmlzU2xlZXBpbmcsXFxuICAgICAgICAgICAgcGFyZW50OiBib2R5LnBhcmVudCB8fCBib2R5XFxuICAgICAgICB9KTtcXG5cXG4gICAgICAgIFZlcnRpY2VzLnJvdGF0ZShib2R5LnZlcnRpY2VzLCBib2R5LmFuZ2xlLCBib2R5LnBvc2l0aW9uKTtcXG4gICAgICAgIEF4ZXMucm90YXRlKGJvZHkuYXhlcywgYm9keS5hbmdsZSk7XFxuICAgICAgICBCb3VuZHMudXBkYXRlKGJvZHkuYm91bmRzLCBib2R5LnZlcnRpY2VzLCBib2R5LnZlbG9jaXR5KTtcXG5cXG4gICAgICAgIC8vIGFsbG93IG9wdGlvbnMgdG8gb3ZlcnJpZGUgdGhlIGF1dG9tYXRpY2FsbHkgY2FsY3VsYXRlZCBwcm9wZXJ0aWVzXFxuICAgICAgICBCb2R5LnNldChib2R5LCB7XFxuICAgICAgICAgICAgYXhlczogb3B0aW9ucy5heGVzIHx8IGJvZHkuYXhlcyxcXG4gICAgICAgICAgICBhcmVhOiBvcHRpb25zLmFyZWEgfHwgYm9keS5hcmVhLFxcbiAgICAgICAgICAgIG1hc3M6IG9wdGlvbnMubWFzcyB8fCBib2R5Lm1hc3MsXFxuICAgICAgICAgICAgaW5lcnRpYTogb3B0aW9ucy5pbmVydGlhIHx8IGJvZHkuaW5lcnRpYVxcbiAgICAgICAgfSk7XFxuXFxuICAgICAgICAvLyByZW5kZXIgcHJvcGVydGllc1xcbiAgICAgICAgdmFyIGRlZmF1bHRGaWxsU3R5bGUgPSAoYm9keS5pc1N0YXRpYyA/ICcjMTQxNTFmJyA6IENvbW1vbi5jaG9vc2UoWycjZjE5NjQ4JywgJyNmNWQyNTknLCAnI2Y1NWEzYycsICcjMDYzZTdiJywgJyNlY2VjZDEnXSkpLFxcbiAgICAgICAgICAgIGRlZmF1bHRTdHJva2VTdHlsZSA9IGJvZHkuaXNTdGF0aWMgPyAnIzU1NScgOiAnI2NjYycsXFxuICAgICAgICAgICAgZGVmYXVsdExpbmVXaWR0aCA9IGJvZHkuaXNTdGF0aWMgJiYgYm9keS5yZW5kZXIuZmlsbFN0eWxlID09PSBudWxsID8gMSA6IDA7XFxuICAgICAgICBib2R5LnJlbmRlci5maWxsU3R5bGUgPSBib2R5LnJlbmRlci5maWxsU3R5bGUgfHwgZGVmYXVsdEZpbGxTdHlsZTtcXG4gICAgICAgIGJvZHkucmVuZGVyLnN0cm9rZVN0eWxlID0gYm9keS5yZW5kZXIuc3Ryb2tlU3R5bGUgfHwgZGVmYXVsdFN0cm9rZVN0eWxlO1xcbiAgICAgICAgYm9keS5yZW5kZXIubGluZVdpZHRoID0gYm9keS5yZW5kZXIubGluZVdpZHRoIHx8IGRlZmF1bHRMaW5lV2lkdGg7XFxuICAgICAgICBib2R5LnJlbmRlci5zcHJpdGUueE9mZnNldCArPSAtKGJvZHkuYm91bmRzLm1pbi54IC0gYm9keS5wb3NpdGlvbi54KSAvIChib2R5LmJvdW5kcy5tYXgueCAtIGJvZHkuYm91bmRzLm1pbi54KTtcXG4gICAgICAgIGJvZHkucmVuZGVyLnNwcml0ZS55T2Zmc2V0ICs9IC0oYm9keS5ib3VuZHMubWluLnkgLSBib2R5LnBvc2l0aW9uLnkpIC8gKGJvZHkuYm91bmRzLm1heC55IC0gYm9keS5ib3VuZHMubWluLnkpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogR2l2ZW4gYSBwcm9wZXJ0eSBhbmQgYSB2YWx1ZSAob3IgbWFwIG9mKSwgc2V0cyB0aGUgcHJvcGVydHkocykgb24gdGhlIGJvZHksIHVzaW5nIHRoZSBhcHByb3ByaWF0ZSBzZXR0ZXIgZnVuY3Rpb25zIGlmIHRoZXkgZXhpc3QuXFxuICAgICAqIFByZWZlciB0byB1c2UgdGhlIGFjdHVhbCBzZXR0ZXIgZnVuY3Rpb25zIGluIHBlcmZvcm1hbmNlIGNyaXRpY2FsIHNpdHVhdGlvbnMuXFxuICAgICAqIEBtZXRob2Qgc2V0XFxuICAgICAqIEBwYXJhbSB7Ym9keX0gYm9keVxcbiAgICAgKiBAcGFyYW0ge30gc2V0dGluZ3MgQSBwcm9wZXJ0eSBuYW1lIChvciBtYXAgb2YgcHJvcGVydGllcyBhbmQgdmFsdWVzKSB0byBzZXQgb24gdGhlIGJvZHkuXFxuICAgICAqIEBwYXJhbSB7fSB2YWx1ZSBUaGUgdmFsdWUgdG8gc2V0IGlmIGBzZXR0aW5nc2AgaXMgYSBzaW5nbGUgcHJvcGVydHkgbmFtZS5cXG4gICAgICovXFxuICAgIEJvZHkuc2V0ID0gZnVuY3Rpb24oYm9keSwgc2V0dGluZ3MsIHZhbHVlKSB7XFxuICAgICAgICB2Y
2XIgcHJvcGVydHk7XFxuXFxuICAgICAgICBpZiAodHlwZW9mIHNldHRpbmdzID09PSAnc3RyaW5nJykge1xcbiAgICAgICAgICAgIHByb3BlcnR5ID0gc2V0dGluZ3M7XFxuICAgICAgICAgICAgc2V0dGluZ3MgPSB7fTtcXG4gICAgICAgICAgICBzZXR0aW5nc1twcm9wZXJ0eV0gPSB2YWx1ZTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIGZvciAocHJvcGVydHkgaW4gc2V0dGluZ3MpIHtcXG4gICAgICAgICAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChzZXR0aW5ncywgcHJvcGVydHkpKVxcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcXG5cXG4gICAgICAgICAgICB2YWx1ZSA9IHNldHRpbmdzW3Byb3BlcnR5XTtcXG4gICAgICAgICAgICBzd2l0Y2ggKHByb3BlcnR5KSB7XFxuXFxuICAgICAgICAgICAgY2FzZSAnaXNTdGF0aWMnOlxcbiAgICAgICAgICAgICAgICBCb2R5LnNldFN0YXRpYyhib2R5LCB2YWx1ZSk7XFxuICAgICAgICAgICAgICAgIGJyZWFrO1xcbiAgICAgICAgICAgIGNhc2UgJ2lzU2xlZXBpbmcnOlxcbiAgICAgICAgICAgICAgICBTbGVlcGluZy5zZXQoYm9keSwgdmFsdWUpO1xcbiAgICAgICAgICAgICAgICBicmVhaztcXG4gICAgICAgICAgICBjYXNlICdtYXNzJzpcXG4gICAgICAgICAgICAgICAgQm9keS5zZXRNYXNzKGJvZHksIHZhbHVlKTtcXG4gICAgICAgICAgICAgICAgYnJlYWs7XFxuICAgICAgICAgICAgY2FzZSAnZGVuc2l0eSc6XFxuICAgICAgICAgICAgICAgIEJvZHkuc2V0RGVuc2l0eShib2R5LCB2YWx1ZSk7XFxuICAgICAgICAgICAgICAgIGJyZWFrO1xcbiAgICAgICAgICAgIGNhc2UgJ2luZXJ0aWEnOlxcbiAgICAgICAgICAgICAgICBCb2R5LnNldEluZXJ0aWEoYm9keSwgdmFsdWUpO1xcbiAgICAgICAgICAgICAgICBicmVhaztcXG4gICAgICAgICAgICBjYXNlICd2ZXJ0aWNlcyc6XFxuICAgICAgICAgICAgICAgIEJvZHkuc2V0VmVydGljZXMoYm9keSwgdmFsdWUpO1xcbiAgICAgICAgICAgICAgICBicmVhaztcXG4gICAgICAgICAgICBjYXNlICdwb3NpdGlvbic6XFxuICAgICAgICAgICAgICAgIEJvZHkuc2V0UG9zaXRpb24oYm9keSwgdmFsdWUpO1xcbiAgICAgICAgICAgICAgICBicmVhaztcXG4gICAgICAgICAgICBjYXNlICdhbmdsZSc6XFxuICAgICAgICAgICAgICAgIEJvZHkuc2V0QW5nbGUoYm9keSwgdmFsdWUpO1xcbiAgICAgICAgICAgICAgICBicmVhaztcXG4gICAgICAgICAgICBjYXNlICd2ZWxvY2l0eSc6XFxuICAgICAgICAgICAgICAgIEJvZHkuc2V0VmVsb2NpdHkoYm9keSwgdmFsdWUpO1xcbiAgICAgICAgICAgICAgICBicmVhaztcXG4gICAgICAgICAgICBjYXNlICdhbmd1bGFyVmVsb2NpdHknOlxcbiAgICAgICAgICAgICAgICBCb2R5LnNldEFuZ3VsYXJWZWxvY2l0eShib2R5LCB2YWx1ZSk7XFxuICAgICAgICAgICAgICAgIGJyZWFrO1xcbiAgICAgICAgICAgIGNhc2UgJ3NwZWVkJzpcXG4gICAgICAgICAgICAgICAgQm9keS5zZXRTcGVlZChib2R5LCB2YWx1ZSk7XFxuICAgICAgICAgICAgICAgIGJyZWFrO1xcbiAgICAgICAgICAgIGNhc2UgJ2FuZ3VsYXJTcGVlZCc6XFxuICAgICAgICAgICAgICAgIEJvZHkuc2V0QW5ndWxhclNwZWVkKGJvZHksIHZhbHVlKTtcXG4gICAgICAgICAgICAgICAgYnJlYWs7XFxuICAgICAgICAgICAgY2FzZSAncGFydHMnOlxcbiAgICAgICAgICAgICAgICBCb2R5LnNldFBhcnRzKGJvZHksIHZhbHVlKTtcXG4gICAgICAgICAgICAgICAgYnJlYWs7XFxuICAgICAgICAgICAgY2FzZSAnY2VudHJlJzpcXG4gICAgICAgICAgICAgICAgQm9keS5zZXRDZW50cmUoYm9keSwgdmFsdWUpO1xcbiAgICAgICAgICAgICAgICBicmVhaztcXG4gICAgICAgICAgICBkZWZhdWx0OlxcbiAgICAgICAgICAgICAgICBib2R5W3Byb3BlcnR5XSA9IHZhbHVlO1xcblxcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFNldHMgdGhlIGJvZHkgYXMgc3RhdGljLCBpbmNsdWRpbmcgaXNTdGF0aWMgZmxhZyBhbmQgc2V0dGluZyBtYXNzIGFuZCBpbmVydGlhIHRvIEluZmluaXR5LlxcbiAgICAgKiBAbWV0aG9kIHNldFN0YXRpY1xcbiAgICAgKiBAcGFyYW0ge2JvZHl9IGJvZHlcXG4gICAgICogQHBhcmFtIHtib29sfSBpc1N0YXRpY1xcbiAgICAgKi9cXG4gICAgQm9keS5zZXRTdGF0aWMgPSBmdW5jdGlvbihib2R5LCBpc1N0YXRpYykge1xcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBib2R5LnBhcnRzLmxlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgdmFyIHBhcnQgPSBib2R5LnBhcnRzW2ldO1xcbiAgICAgICAgICAgIHBhcnQuaXNTdGF0aWMgPSBpc1N0YXRpYztcXG5cXG4gICAgICAgICAgICBpZiAoaXNTdGF0aWMpIHtcXG4gICAgICAgICAgICAgICAgcGFydC5fb3JpZ2luYWwgPSB7XFxuICAgICAgICAgICAgICAgICAgICByZXN0aXR1dGlvbjogcGFydC5yZXN0aXR1dGlvbixcXG4gICAgICAgICAgICAgICAgICAgIGZyaWN0aW9uOiBwYXJ0LmZyaWN0aW9uLFxcbiAgICAgICAgICAgICAgICAgICAgbWFzczogcGFydC5tYXNzLFxcbiAgICAgICAgICAgICAgICAgICAgaW5lcnRpYTogcGFydC5pbmVydGlhLFxcbiAgICAgICAgICAgICAgICAgICAgZGVuc2l0eTogcGFydC5kZW5zaXR5LFxcbiAgICAgICAgICAgICAgICAgICAgaW52ZXJzZU1hc3M6IHBhcnQuaW52ZXJzZU1hc3MsXFxuICAgICAgICAgICAgICAgICAgICBpbnZlcnNlSW5lcnRpYTogcGFydC5pbnZlcnNlSW5lcnRpYVxcbiAgICAgICAgICAgICAgICB9O1xcblxcbiAgICAgICAgICAgICAgICBwYXJ0LnJlc3RpdHV0aW9uID0gMDtcXG4gICAgICAgICAgICAgICAgcGFydC5mcmljdGlvbiA9IDE7XFxuICAgICAgICAgICAgICAgIHBhcnQubWFzcyA9IHBhcnQuaW5lcnRpYSA9IHBhcnQuZGVuc2l0eSA9IEluZmluaXR5O1xcbiAgICAgICAgICAgICAgICBwYXJ0LmludmVyc2VNYXNzID0gcGFydC5pbnZlcnNlSW5lcnRpYSA9IDA7XFxuXFxuICAgICAgICAgICAgICAgIHBhcnQucG9zaXRpb25QcmV2LnggPSBwYXJ0LnBvc2l0aW9uLng7XFxuICAgICAgICAgICAgICAgI
2HBhcnQucG9zaXRpb25QcmV2LnkgPSBwYXJ0LnBvc2l0aW9uLnk7XFxuICAgICAgICAgICAgICAgIHBhcnQuYW5nbGVQcmV2ID0gcGFydC5hbmdsZTtcXG4gICAgICAgICAgICAgICAgcGFydC5hbmd1bGFyVmVsb2NpdHkgPSAwO1xcbiAgICAgICAgICAgICAgICBwYXJ0LnNwZWVkID0gMDtcXG4gICAgICAgICAgICAgICAgcGFydC5hbmd1bGFyU3BlZWQgPSAwO1xcbiAgICAgICAgICAgICAgICBwYXJ0Lm1vdGlvbiA9IDA7XFxuICAgICAgICAgICAgfSBlbHNlIGlmIChwYXJ0Ll9vcmlnaW5hbCkge1xcbiAgICAgICAgICAgICAgICBwYXJ0LnJlc3RpdHV0aW9uID0gcGFydC5fb3JpZ2luYWwucmVzdGl0dXRpb247XFxuICAgICAgICAgICAgICAgIHBhcnQuZnJpY3Rpb24gPSBwYXJ0Ll9vcmlnaW5hbC5mcmljdGlvbjtcXG4gICAgICAgICAgICAgICAgcGFydC5tYXNzID0gcGFydC5fb3JpZ2luYWwubWFzcztcXG4gICAgICAgICAgICAgICAgcGFydC5pbmVydGlhID0gcGFydC5fb3JpZ2luYWwuaW5lcnRpYTtcXG4gICAgICAgICAgICAgICAgcGFydC5kZW5zaXR5ID0gcGFydC5fb3JpZ2luYWwuZGVuc2l0eTtcXG4gICAgICAgICAgICAgICAgcGFydC5pbnZlcnNlTWFzcyA9IHBhcnQuX29yaWdpbmFsLmludmVyc2VNYXNzO1xcbiAgICAgICAgICAgICAgICBwYXJ0LmludmVyc2VJbmVydGlhID0gcGFydC5fb3JpZ2luYWwuaW52ZXJzZUluZXJ0aWE7XFxuXFxuICAgICAgICAgICAgICAgIHBhcnQuX29yaWdpbmFsID0gbnVsbDtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBTZXRzIHRoZSBtYXNzIG9mIHRoZSBib2R5LiBJbnZlcnNlIG1hc3MsIGRlbnNpdHkgYW5kIGluZXJ0aWEgYXJlIGF1dG9tYXRpY2FsbHkgdXBkYXRlZCB0byByZWZsZWN0IHRoZSBjaGFuZ2UuXFxuICAgICAqIEBtZXRob2Qgc2V0TWFzc1xcbiAgICAgKiBAcGFyYW0ge2JvZHl9IGJvZHlcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IG1hc3NcXG4gICAgICovXFxuICAgIEJvZHkuc2V0TWFzcyA9IGZ1bmN0aW9uKGJvZHksIG1hc3MpIHtcXG4gICAgICAgIHZhciBtb21lbnQgPSBib2R5LmluZXJ0aWEgLyAoYm9keS5tYXNzIC8gNik7XFxuICAgICAgICBib2R5LmluZXJ0aWEgPSBtb21lbnQgKiAobWFzcyAvIDYpO1xcbiAgICAgICAgYm9keS5pbnZlcnNlSW5lcnRpYSA9IDEgLyBib2R5LmluZXJ0aWE7XFxuXFxuICAgICAgICBib2R5Lm1hc3MgPSBtYXNzO1xcbiAgICAgICAgYm9keS5pbnZlcnNlTWFzcyA9IDEgLyBib2R5Lm1hc3M7XFxuICAgICAgICBib2R5LmRlbnNpdHkgPSBib2R5Lm1hc3MgLyBib2R5LmFyZWE7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBTZXRzIHRoZSBkZW5zaXR5IG9mIHRoZSBib2R5LiBNYXNzIGFuZCBpbmVydGlhIGFyZSBhdXRvbWF0aWNhbGx5IHVwZGF0ZWQgdG8gcmVmbGVjdCB0aGUgY2hhbmdlLlxcbiAgICAgKiBAbWV0aG9kIHNldERlbnNpdHlcXG4gICAgICogQHBhcmFtIHtib2R5fSBib2R5XFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBkZW5zaXR5XFxuICAgICAqL1xcbiAgICBCb2R5LnNldERlbnNpdHkgPSBmdW5jdGlvbihib2R5LCBkZW5zaXR5KSB7XFxuICAgICAgICBCb2R5LnNldE1hc3MoYm9keSwgZGVuc2l0eSAqIGJvZHkuYXJlYSk7XFxuICAgICAgICBib2R5LmRlbnNpdHkgPSBkZW5zaXR5O1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogU2V0cyB0aGUgbW9tZW50IG9mIGluZXJ0aWEgb2YgdGhlIGJvZHkuIFRoaXMgaXMgdGhlIHNlY29uZCBtb21lbnQgb2YgYXJlYSBpbiB0d28gZGltZW5zaW9ucy5cXG4gICAgICogSW52ZXJzZSBpbmVydGlhIGlzIGF1dG9tYXRpY2FsbHkgdXBkYXRlZCB0byByZWZsZWN0IHRoZSBjaGFuZ2UuIE1hc3MgaXMgbm90IGNoYW5nZWQuXFxuICAgICAqIEBtZXRob2Qgc2V0SW5lcnRpYVxcbiAgICAgKiBAcGFyYW0ge2JvZHl9IGJvZHlcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGluZXJ0aWFcXG4gICAgICovXFxuICAgIEJvZHkuc2V0SW5lcnRpYSA9IGZ1bmN0aW9uKGJvZHksIGluZXJ0aWEpIHtcXG4gICAgICAgIGJvZHkuaW5lcnRpYSA9IGluZXJ0aWE7XFxuICAgICAgICBib2R5LmludmVyc2VJbmVydGlhID0gMSAvIGJvZHkuaW5lcnRpYTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFNldHMgdGhlIGJvZHkncyB2ZXJ0aWNlcyBhbmQgdXBkYXRlcyBib2R5IHByb3BlcnRpZXMgYWNjb3JkaW5nbHksIGluY2x1ZGluZyBpbmVydGlhLCBhcmVhIGFuZCBtYXNzICh3aXRoIHJlc3BlY3QgdG8gYGJvZHkuZGVuc2l0eWApLlxcbiAgICAgKiBWZXJ0aWNlcyB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgdHJhbnNmb3JtZWQgdG8gYmUgb3JpZW50YXRlZCBhcm91bmQgdGhlaXIgY2VudHJlIG9mIG1hc3MgYXMgdGhlIG9yaWdpbi5cXG4gICAgICogVGhleSBhcmUgdGhlbiBhdXRvbWF0aWNhbGx5IHRyYW5zbGF0ZWQgdG8gd29ybGQgc3BhY2UgYmFzZWQgb24gYGJvZHkucG9zaXRpb25gLlxcbiAgICAgKlxcbiAgICAgKiBUaGUgYHZlcnRpY2VzYCBhcmd1bWVudCBzaG91bGQgYmUgcGFzc2VkIGFzIGFuIGFycmF5IG9mIGBNYXR0ZXIuVmVjdG9yYCBwb2ludHMgKG9yIGEgYE1hdHRlci5WZXJ0aWNlc2AgYXJyYXkpLlxcbiAgICAgKiBWZXJ0aWNlcyBtdXN0IGZvcm0gYSBjb252ZXggaHVsbC4gQ29uY2F2ZSB2ZXJ0aWNlcyBtdXN0IGJlIGRlY29tcG9zZWQgaW50byBjb252ZXggcGFydHMuXFxuICAgICAqIFxcbiAgICAgKiBAbWV0aG9kIHNldFZlcnRpY2VzXFxuICAgICAqIEBwYXJhbSB7Ym9keX0gYm9keVxcbiAgICAgKiBAcGFyYW0ge3ZlY3RvcltdfSB2ZXJ0aWNlc1xcbiAgICAgKi9cXG4gICAgQm9keS5zZXRWZXJ0aWNlcyA9IGZ1bmN0aW9uKGJvZHksIHZlcnRpY2VzKSB7XFxuICAgICAgICAvLyBjaGFuZ2UgdmVydGljZXNcXG4gICAgICAgIGlmICh2ZXJ0aWNlc1swXS5ib2R5ID09PSBib2R5KSB7XFxuICAgICAgICAgICAgYm9keS52ZXJ0aWNlcyA9IHZlcnRpY2VzO1xcbiAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICBib2R5LnZlcnRpY2VzID0gVmVydGljZXMuY3JlYXRlKHZlcnRpY2VzLCBib2R5KTtcXG4gICAgICAgI
2H1cXG5cXG4gICAgICAgIC8vIHVwZGF0ZSBwcm9wZXJ0aWVzXFxuICAgICAgICBib2R5LmF4ZXMgPSBBeGVzLmZyb21WZXJ0aWNlcyhib2R5LnZlcnRpY2VzKTtcXG4gICAgICAgIGJvZHkuYXJlYSA9IFZlcnRpY2VzLmFyZWEoYm9keS52ZXJ0aWNlcyk7XFxuICAgICAgICBCb2R5LnNldE1hc3MoYm9keSwgYm9keS5kZW5zaXR5ICogYm9keS5hcmVhKTtcXG5cXG4gICAgICAgIC8vIG9yaWVudCB2ZXJ0aWNlcyBhcm91bmQgdGhlIGNlbnRyZSBvZiBtYXNzIGF0IG9yaWdpbiAoMCwgMClcXG4gICAgICAgIHZhciBjZW50cmUgPSBWZXJ0aWNlcy5jZW50cmUoYm9keS52ZXJ0aWNlcyk7XFxuICAgICAgICBWZXJ0aWNlcy50cmFuc2xhdGUoYm9keS52ZXJ0aWNlcywgY2VudHJlLCAtMSk7XFxuXFxuICAgICAgICAvLyB1cGRhdGUgaW5lcnRpYSB3aGlsZSB2ZXJ0aWNlcyBhcmUgYXQgb3JpZ2luICgwLCAwKVxcbiAgICAgICAgQm9keS5zZXRJbmVydGlhKGJvZHksIEJvZHkuX2luZXJ0aWFTY2FsZSAqIFZlcnRpY2VzLmluZXJ0aWEoYm9keS52ZXJ0aWNlcywgYm9keS5tYXNzKSk7XFxuXFxuICAgICAgICAvLyB1cGRhdGUgZ2VvbWV0cnlcXG4gICAgICAgIFZlcnRpY2VzLnRyYW5zbGF0ZShib2R5LnZlcnRpY2VzLCBib2R5LnBvc2l0aW9uKTtcXG4gICAgICAgIEJvdW5kcy51cGRhdGUoYm9keS5ib3VuZHMsIGJvZHkudmVydGljZXMsIGJvZHkudmVsb2NpdHkpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogU2V0cyB0aGUgcGFydHMgb2YgdGhlIGBib2R5YCBhbmQgdXBkYXRlcyBtYXNzLCBpbmVydGlhIGFuZCBjZW50cm9pZC5cXG4gICAgICogRWFjaCBwYXJ0IHdpbGwgaGF2ZSBpdHMgcGFyZW50IHNldCB0byBgYm9keWAuXFxuICAgICAqIEJ5IGRlZmF1bHQgdGhlIGNvbnZleCBodWxsIHdpbGwgYmUgYXV0b21hdGljYWxseSBjb21wdXRlZCBhbmQgc2V0IG9uIGBib2R5YCwgdW5sZXNzIGBhdXRvSHVsbGAgaXMgc2V0IHRvIGBmYWxzZS5gXFxuICAgICAqIE5vdGUgdGhhdCB0aGlzIG1ldGhvZCB3aWxsIGVuc3VyZSB0aGF0IHRoZSBmaXJzdCBwYXJ0IGluIGBib2R5LnBhcnRzYCB3aWxsIGFsd2F5cyBiZSB0aGUgYGJvZHlgLlxcbiAgICAgKiBAbWV0aG9kIHNldFBhcnRzXFxuICAgICAqIEBwYXJhbSB7Ym9keX0gYm9keVxcbiAgICAgKiBAcGFyYW0ge2JvZHlbXX0gcGFydHNcXG4gICAgICogQHBhcmFtIHtib29sfSBbYXV0b0h1bGw9dHJ1ZV1cXG4gICAgICovXFxuICAgIEJvZHkuc2V0UGFydHMgPSBmdW5jdGlvbihib2R5LCBwYXJ0cywgYXV0b0h1bGwpIHtcXG4gICAgICAgIHZhciBpO1xcblxcbiAgICAgICAgLy8gYWRkIGFsbCB0aGUgcGFydHMsIGVuc3VyaW5nIHRoYXQgdGhlIGZpcnN0IHBhcnQgaXMgYWx3YXlzIHRoZSBwYXJlbnQgYm9keVxcbiAgICAgICAgcGFydHMgPSBwYXJ0cy5zbGljZSgwKTtcXG4gICAgICAgIGJvZHkucGFydHMubGVuZ3RoID0gMDtcXG4gICAgICAgIGJvZHkucGFydHMucHVzaChib2R5KTtcXG4gICAgICAgIGJvZHkucGFyZW50ID0gYm9keTtcXG5cXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBwYXJ0cy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHZhciBwYXJ0ID0gcGFydHNbaV07XFxuICAgICAgICAgICAgaWYgKHBhcnQgIT09IGJvZHkpIHtcXG4gICAgICAgICAgICAgICAgcGFydC5wYXJlbnQgPSBib2R5O1xcbiAgICAgICAgICAgICAgICBib2R5LnBhcnRzLnB1c2gocGFydCk7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcblxcbiAgICAgICAgaWYgKGJvZHkucGFydHMubGVuZ3RoID09PSAxKVxcbiAgICAgICAgICAgIHJldHVybjtcXG5cXG4gICAgICAgIGF1dG9IdWxsID0gdHlwZW9mIGF1dG9IdWxsICE9PSAndW5kZWZpbmVkJyA/IGF1dG9IdWxsIDogdHJ1ZTtcXG5cXG4gICAgICAgIC8vIGZpbmQgdGhlIGNvbnZleCBodWxsIG9mIGFsbCBwYXJ0cyB0byBzZXQgb24gdGhlIHBhcmVudCBib2R5XFxuICAgICAgICBpZiAoYXV0b0h1bGwpIHtcXG4gICAgICAgICAgICB2Y
2XIgdmVydGljZXMgPSBbXTtcXG4gICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgcGFydHMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICAgICAgdmVydGljZXMgPSB2ZXJ0aWNlcy5jb25jYXQocGFydHNbaV0udmVydGljZXMpO1xcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICBWZXJ0aWNlcy5jbG9ja3dpc2VTb3J0KHZlcnRpY2VzKTtcXG5cXG4gICAgICAgICAgICB2YXIgaHVsbCA9IFZlcnRpY2VzLmh1bGwodmVydGljZXMpLFxcbiAgICAgICAgICAgICAgICBodWxsQ2VudHJlID0gVmVydGljZXMuY2VudHJlKGh1bGwpO1xcblxcbiAgICAgICAgICAgIEJvZHkuc2V0VmVydGljZXMoYm9keSwgaHVsbCk7XFxuICAgICAgICAgICAgVmVydGljZXMudHJhbnNsYXRlKGJvZHkudmVydGljZXMsIGh1bGxDZW50cmUpO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgLy8gc3VtIHRoZSBwcm9wZXJ0aWVzIG9mIGFsbCBjb21wb3VuZCBwYXJ0cyBvZiB0aGUgcGFyZW50IGJvZHlcXG4gICAgICAgIHZhciB0b3RhbCA9IEJvZHkuX3RvdGFsUHJvcGVydGllcyhib2R5KTtcXG5cXG4gICAgICAgIGJvZHkuYXJlYSA9IHRvdGFsLmFyZWE7XFxuICAgICAgICBib2R5LnBhcmVudCA9IGJvZHk7XFxuICAgICAgICBib2R5LnBvc2l0aW9uLnggPSB0b3RhbC5jZW50cmUueDtcXG4gICAgICAgIGJvZHkucG9zaXRpb24ueSA9IHRvdGFsLmNlbnRyZS55O1xcbiAgICAgICAgYm9keS5wb3NpdGlvblByZXYueCA9IHRvdGFsLmNlbnRyZS54O1xcbiAgICAgICAgYm9keS5wb3NpdGlvblByZXYueSA9IHRvdGFsLmNlbnRyZS55O1xcblxcbiAgICAgICAgQm9keS5zZXRNYXNzKGJvZHksIHRvdGFsLm1hc3MpO1xcbiAgICAgICAgQm9keS5zZXRJbmVydGlhKGJvZHksIHRvdGFsLmluZXJ0aWEpO1xcbiAgICAgICAgQm9keS5zZXRQb3NpdGlvbihib2R5LCB0b3RhbC5jZW50cmUpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogU2V0IHRoZSBjZW50cmUgb2YgbWFzcyBvZiB0aGUgYm9keS4gXFxuICAgICAqIFRoZSBgY2VudHJlYCBpcyBhIHZlY3RvciBpbiB3b3JsZC1zcGFjZSB1bmxlc3MgYHJlbGF0aXZlYCBpcyBzZXQsIGluIHdoaWNoIGNhc2UgaXQgaXMgYSB0cmFuc2xhdGlvbi5cXG4gICAgICogVGhlIGNlbnRyZSBvZiBtYXNzIGlzIHRoZSBwb2ludCB0aGUgYm9keSByb3RhdGVzIGFib3V0IGFuZCBjYW4gYmUgdXNlZCB0byBzaW11bGF0ZSBub24tdW5pZm9ybSBkZW5zaXR5LlxcbiAgICAgKiBUaGlzIGlzIGVxdWFsIHRvIG1vdmluZyBgYm9keS5wb3NpdGlvbmAgYnV0IG5vdCB0aGUgYGJvZHkudmVydGljZXNgLlxcbiAgICAgKiBJbnZhbGlkIGlmIHRoZSBgY2VudHJlYCBmYWxscyBvdXRzaWRlIHRoZSBib2R5J3MgY29udmV4IGh1bGwuXFxuICAgICAqIEBtZXRob2Qgc2V0Q2VudHJlXFxuICAgICAqIEBwYXJhbSB7Ym9keX0gYm9keVxcbiAgICAgKiBAcGFyYW0ge3ZlY3Rvcn0gY2VudHJlXFxuICAgICAqIEBwYXJhbSB7Ym9vbH0gcmVsYXRpdmVcXG4gICAgICovXFxuICAgIEJvZHkuc2V0Q2VudHJlID0gZnVuY3Rpb24oYm9keSwgY2VudHJlLCByZWxhdGl2ZSkge1xcbiAgICAgICAgaWYgKCFyZWxhdGl2ZSkge1xcbiAgICAgICAgICAgIGJvZHkucG9zaXRpb25QcmV2LnggPSBjZW50cmUueCAtIChib2R5LnBvc2l0aW9uLnggLSBib2R5LnBvc2l0aW9uUHJldi54KTtcXG4gICAgICAgICAgICBib2R5LnBvc2l0aW9uUHJldi55ID0gY2VudHJlLnkgLSAoYm9keS5wb3NpdGlvbi55IC0gYm9keS5wb3NpdGlvblByZXYueSk7XFxuICAgICAgICAgICAgYm9keS5wb3NpdGlvbi54ID0gY2VudHJlLng7XFxuICAgICAgICAgICAgYm9keS5wb3NpdGlvbi55ID0gY2VudHJlLnk7XFxuICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgIGJvZHkucG9zaXRpb25QcmV2LnggKz0gY2VudHJlLng7XFxuICAgICAgICAgICAgYm9keS5wb3NpdGlvblByZXYueSArPSBjZW50cmUueTtcXG4gICAgICAgICAgICBib2R5LnBvc2l0aW9uLnggKz0gY2VudHJlLng7XFxuICAgICAgICAgICAgYm9keS5wb3NpdGlvbi55ICs9IGNlbnRyZS55O1xcbiAgICAgICAgfVxcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogU2V0cyB0aGUgcG9zaXRpb24gb2YgdGhlIGJvZHkuIEJ5IGRlZmF1bHQgdmVsb2NpdHkgaXMgdW5jaGFuZ2VkLlxcbiAgICAgKiBJZiBgdXBkYXRlVmVsb2NpdHlgIGlzIGB0cnVlYCB0aGVuIHZlbG9jaXR5IGlzIGluZmVycmVkIGZyb20gdGhlIGNoYW5nZSBpbiBwb3NpdGlvbi5cXG4gICAgICogQG1ldGhvZCBzZXRQb3NpdGlvblxcbiAgICAgKiBAcGFyYW0ge2JvZHl9IGJvZHlcXG4gICAgICogQHBhcmFtIHt2ZWN0b3J9IHBvc2l0aW9uXFxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW3VwZGF0ZVZlbG9jaXR5PWZhbHNlXVxcbiAgICAgKi9cXG4gICAgQm9keS5zZXRQb3NpdGlvbiA9IGZ1bmN0aW9uKGJvZHksIHBvc2l0aW9uLCB1cGRhdGVWZWxvY2l0eSkge1xcbiAgICAgICAgdmFyIGRlbHRhID0gVmVjdG9yLnN1Yihwb3NpdGlvbiwgYm9keS5wb3NpdGlvbik7XFxuXFxuICAgICAgICBpZiAodXBkYXRlVmVsb2NpdHkpIHtcXG4gICAgICAgICAgICBib2R5LnBvc2l0aW9uUHJldi54ID0gYm9keS5wb3NpdGlvbi54O1xcbiAgICAgICAgICAgIGJvZHkucG9zaXRpb25QcmV2LnkgPSBib2R5LnBvc2l0aW9uLnk7XFxuICAgICAgICAgICAgYm9keS52ZWxvY2l0eS54ID0gZGVsdGEueDtcXG4gICAgICAgICAgICBib2R5LnZlbG9jaXR5LnkgPSBkZWx0YS55O1xcbiAgICAgICAgICAgIGJvZHkuc3BlZWQgPSBWZWN0b3IubWFnbml0dWRlKGRlbHRhKTtcXG4gICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgYm9keS5wb3NpdGlvblByZXYueCArPSBkZWx0YS54O1xcbiAgICAgICAgICAgIGJvZHkucG9zaXRpb25QcmV2LnkgKz0gZGVsdGEueTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYm9keS5wYXJ0cy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHZhciBwYXJ0ID0gYm9keS5wYXJ0c1tpXTtcXG4gICAgICAgICAgICBwYXJ0LnBvc2l0aW9uLnggKz0gZGVsdGEueDtcXG4gICAgICAgICAgICBwYXJ0LnBvc2l0aW9uLnkgKz0gZGVsdGEueTtcXG4gICAgICAgICAgICBWZXJ0aWNlcy50cmFuc2xhdGUocGFydC52ZXJ0aWNlcywgZGVsdGEpO1xcbiAgICAgICAgICAgIEJvdW5kcy51cGRhdGUocGFydC5ib3VuZHMsIHBhcnQudmVydGljZXMsIGJvZHkudmVsb2NpdHkpO1xcbiAgICAgICAgfVxcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogU2V0cyB0aGUgYW5nbGUgb2YgdGhlIGJvZHkuIEJ5IGRlZmF1bHQgYW5ndWxhciB2ZWxvY2l0eSBpcyB1bmNoYW5nZWQuXFxuICAgICAqIElmIGB1cGRhdGVWZWxvY2l0eWAgaXMgYHRydWVgIHRoZW4gYW5ndWxhciB2ZWxvY2l0eSBpcyBpbmZlcnJlZCBmcm9tIHRoZSBjaGFuZ2UgaW4gYW5nbGUuXFxuICAgICAqIEBtZXRob2Qgc2V0QW5nbGVcXG4gICAgICogQHBhcmFtIHtib2R5fSBib2R5XFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBhbmdsZVxcbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFt1cGRhdGVWZWxvY2l0eT1mYWxzZV1cXG4gICAgICovXFxuICAgIEJvZHkuc2V0QW5nbGUgPSBmdW5jdGlvbihib2R5LCBhbmdsZSwgdXBkYXRlVmVsb2NpdHkpIHtcXG4gICAgICAgI
2HZhciBkZWx0YSA9IGFuZ2xlIC0gYm9keS5hbmdsZTtcXG4gICAgICAgIFxcbiAgICAgICAgaWYgKHVwZGF0ZVZlbG9jaXR5KSB7XFxuICAgICAgICAgICAgYm9keS5hbmdsZVByZXYgPSBib2R5LmFuZ2xlO1xcbiAgICAgICAgICAgIGJvZHkuYW5ndWxhclZlbG9jaXR5ID0gZGVsdGE7XFxuICAgICAgICAgICAgYm9keS5hbmd1bGFyU3BlZWQgPSBNYXRoLmFicyhkZWx0YSk7XFxuICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgIGJvZHkuYW5nbGVQcmV2ICs9IGRlbHRhO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBib2R5LnBhcnRzLmxlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgdmFyIHBhcnQgPSBib2R5LnBhcnRzW2ldO1xcbiAgICAgICAgICAgIHBhcnQuYW5nbGUgKz0gZGVsdGE7XFxuICAgICAgICAgICAgVmVydGljZXMucm90YXRlKHBhcnQudmVydGljZXMsIGRlbHRhLCBib2R5LnBvc2l0aW9uKTtcXG4gICAgICAgICAgICBBeGVzLnJvdGF0ZShwYXJ0LmF4ZXMsIGRlbHRhKTtcXG4gICAgICAgICAgICBCb3VuZHMudXBkYXRlKHBhcnQuYm91bmRzLCBwYXJ0LnZlcnRpY2VzLCBib2R5LnZlbG9jaXR5KTtcXG4gICAgICAgICAgICBpZiAoaSA+IDApIHtcXG4gICAgICAgICAgICAgICAgVmVjdG9yLnJvdGF0ZUFib3V0KHBhcnQucG9zaXRpb24sIGRlbHRhLCBib2R5LnBvc2l0aW9uLCBwYXJ0LnBvc2l0aW9uKTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBTZXRzIHRoZSBjdXJyZW50IGxpbmVhciB2ZWxvY2l0eSBvZiB0aGUgYm9keS4gIFxcbiAgICAgKiBBZmZlY3RzIGJvZHkgc3BlZWQuXFxuICAgICAqIEBtZXRob2Qgc2V0VmVsb2NpdHlcXG4gICAgICogQHBhcmFtIHtib2R5fSBib2R5XFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSB2ZWxvY2l0eVxcbiAgICAgKi9cXG4gICAgQm9keS5zZXRWZWxvY2l0eSA9IGZ1bmN0aW9uKGJvZHksIHZlbG9jaXR5KSB7XFxuICAgICAgICB2Y
2XIgdGltZVNjYWxlID0gYm9keS5kZWx0YVRpbWUgLyBCb2R5Ll9iYXNlRGVsdGE7XFxuICAgICAgICBib2R5LnBvc2l0aW9uUHJldi54ID0gYm9keS5wb3NpdGlvbi54IC0gdmVsb2NpdHkueCAqIHRpbWVTY2FsZTtcXG4gICAgICAgIGJvZHkucG9zaXRpb25QcmV2LnkgPSBib2R5LnBvc2l0aW9uLnkgLSB2ZWxvY2l0eS55ICogdGltZVNjYWxlO1xcbiAgICAgICAgYm9keS52ZWxvY2l0eS54ID0gKGJvZHkucG9zaXRpb24ueCAtIGJvZHkucG9zaXRpb25QcmV2LngpIC8gdGltZVNjYWxlO1xcbiAgICAgICAgYm9keS52ZWxvY2l0eS55ID0gKGJvZHkucG9zaXRpb24ueSAtIGJvZHkucG9zaXRpb25QcmV2LnkpIC8gdGltZVNjYWxlO1xcbiAgICAgICAgYm9keS5zcGVlZCA9IFZlY3Rvci5tYWduaXR1ZGUoYm9keS52ZWxvY2l0eSk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBHZXRzIHRoZSBjdXJyZW50IGxpbmVhciB2ZWxvY2l0eSBvZiB0aGUgYm9keS5cXG4gICAgICogQG1ldGhvZCBnZXRWZWxvY2l0eVxcbiAgICAgKiBAcGFyYW0ge2JvZHl9IGJvZHlcXG4gICAgICogQHJldHVybiB7dmVjdG9yfSB2ZWxvY2l0eVxcbiAgICAgKi9cXG4gICAgQm9keS5nZXRWZWxvY2l0eSA9IGZ1bmN0aW9uKGJvZHkpIHtcXG4gICAgICAgIHZhciB0aW1lU2NhbGUgPSBCb2R5Ll9iYXNlRGVsdGEgLyBib2R5LmRlbHRhVGltZTtcXG5cXG4gICAgICAgIHJldHVybiB7XFxuICAgICAgICAgICAgeDogKGJvZHkucG9zaXRpb24ueCAtIGJvZHkucG9zaXRpb25QcmV2LngpICogdGltZVNjYWxlLFxcbiAgICAgICAgICAgIHk6IChib2R5LnBvc2l0aW9uLnkgLSBib2R5LnBvc2l0aW9uUHJldi55KSAqIHRpbWVTY2FsZVxcbiAgICAgICAgfTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIEdldHMgdGhlIGN1cnJlbnQgbGluZWFyIHNwZWVkIG9mIHRoZSBib2R5LiAgXFxuICAgICAqIEVxdWl2YWxlbnQgdG8gdGhlIG1hZ25pdHVkZSBvZiBpdHMgdmVsb2NpdHkuXFxuICAgICAqIEBtZXRob2QgZ2V0U3BlZWRcXG4gICAgICogQHBhcmFtIHtib2R5fSBib2R5XFxuICAgICAqIEByZXR1cm4ge251bWJlcn0gc3BlZWRcXG4gICAgICovXFxuICAgIEJvZHkuZ2V0U3BlZWQgPSBmdW5jdGlvbihib2R5KSB7XFxuICAgICAgICByZXR1cm4gVmVjdG9yLm1hZ25pdHVkZShCb2R5LmdldFZlbG9jaXR5KGJvZHkpKTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFNldHMgdGhlIGN1cnJlbnQgbGluZWFyIHNwZWVkIG9mIHRoZSBib2R5LiAgXFxuICAgICAqIERpcmVjdGlvbiBpcyBtYWludGFpbmVkLiBBZmZlY3RzIGJvZHkgdmVsb2NpdHkuXFxuICAgICAqIEBtZXRob2Qgc2V0U3BlZWRcXG4gICAgICogQHBhcmFtIHtib2R5fSBib2R5XFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBzcGVlZFxcbiAgICAgKi9cXG4gICAgQm9keS5zZXRTcGVlZCA9IGZ1bmN0aW9uKGJvZHksIHNwZWVkKSB7XFxuICAgICAgICBCb2R5LnNldFZlbG9jaXR5KGJvZHksIFZlY3Rvci5tdWx0KFZlY3Rvci5ub3JtYWxpc2UoQm9keS5nZXRWZWxvY2l0eShib2R5KSksIHNwZWVkKSk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBTZXRzIHRoZSBjdXJyZW50IHJvdGF0aW9uYWwgdmVsb2NpdHkgb2YgdGhlIGJvZHkuICBcXG4gICAgICogQWZmZWN0cyBib2R5IGFuZ3VsYXIgc3BlZWQuXFxuICAgICAqIEBtZXRob2Qgc2V0QW5ndWxhclZlbG9jaXR5XFxuICAgICAqIEBwYXJhbSB7Ym9keX0gYm9keVxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gdmVsb2NpdHlcXG4gICAgICovXFxuICAgIEJvZHkuc2V0QW5ndWxhclZlbG9jaXR5ID0gZnVuY3Rpb24oYm9keSwgdmVsb2NpdHkpIHtcXG4gICAgICAgIHZhciB0aW1lU2NhbGUgPSBib2R5LmRlbHRhVGltZSAvIEJvZHkuX2Jhc2VEZWx0YTtcXG4gICAgICAgIGJvZHkuYW5nbGVQcmV2ID0gYm9keS5hbmdsZSAtIHZlbG9jaXR5ICogdGltZVNjYWxlO1xcbiAgICAgICAgYm9keS5hbmd1bGFyVmVsb2NpdHkgPSAoYm9keS5hbmdsZSAtIGJvZHkuYW5nbGVQcmV2KSAvIHRpbWVTY2FsZTtcXG4gICAgICAgIGJvZHkuYW5ndWxhclNwZWVkID0gTWF0aC5hYnMoYm9keS5hbmd1bGFyVmVsb2NpdHkpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogR2V0cyB0aGUgY3VycmVudCByb3RhdGlvbmFsIHZlbG9jaXR5IG9mIHRoZSBib2R5LlxcbiAgICAgKiBAbWV0aG9kIGdldEFuZ3VsYXJWZWxvY2l0eVxcbiAgICAgKiBAcGFyYW0ge2JvZHl9IGJvZHlcXG4gICAgICogQHJldHVybiB7bnVtYmVyfSBhbmd1bGFyIHZlbG9jaXR5XFxuICAgICAqL1xcbiAgICBCb2R5LmdldEFuZ3VsYXJWZWxvY2l0eSA9IGZ1bmN0aW9uKGJvZHkpIHtcXG4gICAgICAgIHJldHVybiAoYm9keS5hbmdsZSAtIGJvZHkuYW5nbGVQcmV2KSAqIEJvZHkuX2Jhc2VEZWx0YSAvIGJvZHkuZGVsdGFUaW1lO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogR2V0cyB0aGUgY3VycmVudCByb3RhdGlvbmFsIHNwZWVkIG9mIHRoZSBib2R5LiAgXFxuICAgICAqIEVxdWl2YWxlbnQgdG8gdGhlIG1hZ25pdHVkZSBvZiBpdHMgYW5ndWxhciB2ZWxvY2l0eS5cXG4gICAgICogQG1ldGhvZCBnZXRBbmd1bGFyU3BlZWRcXG4gICAgICogQHBhcmFtIHtib2R5fSBib2R5XFxuICAgICAqIEByZXR1cm4ge251bWJlcn0gYW5ndWxhciBzcGVlZFxcbiAgICAgKi9cXG4gICAgQm9keS5nZXRBbmd1bGFyU3BlZWQgPSBmdW5jdGlvbihib2R5KSB7XFxuICAgICAgICByZXR1cm4gTWF0aC5hYnMoQm9keS5nZXRBbmd1bGFyVmVsb2NpdHkoYm9keSkpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogU2V0cyB0aGUgY3VycmVudCByb3RhdGlvbmFsIHNwZWVkIG9mIHRoZSBib2R5LiAgXFxuICAgICAqIERpcmVjdGlvbiBpcyBtYWludGFpbmVkLiBBZmZlY3RzIGJvZHkgYW5ndWxhciB2ZWxvY2l0eS5cXG4gICAgICogQG1ldGhvZCBzZXRBbmd1bGFyU3BlZWRcXG4gICAgICogQHBhcmFtIHtib2R5fSBib2R5XFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBzcGVlZFxcbiAgICAgKi9cXG4gICAgQm9keS5zZXRBbmd1bGFyU3BlZWQgPSBmdW5jdGlvbihib2R5LCBzcGVlZCkge1xcbiAgICAgICAgQm9keS5zZXRBbmd1bGFyVmVsb2NpdHkoYm9keSwgQ29tbW9uLnNpZ24oQm9keS5nZXRBbmd1bGFyVmVsb2NpdHkoYm9keSkpICogc3BlZWQpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogTW92ZXMgYSBib2R5IGJ5IGEgZ2l2ZW4gdmVjdG9yIHJlbGF0aXZlIHRvIGl0cyBjdXJyZW50IHBvc2l0aW9uLiBCeSBkZWZh
2dWx0IHZlbG9jaXR5IGlzIHVuY2hhbmdlZC5cXG4gICAgICogSWYgYHVwZGF0ZVZlbG9jaXR5YCBpcyBgdHJ1ZWAgdGhlbiB2ZWxvY2l0eSBpcyBpbmZlcnJlZCBmcm9tIHRoZSBjaGFuZ2UgaW4gcG9zaXRpb24uXFxuICAgICAqIEBtZXRob2QgdHJhbnNsYXRlXFxuICAgICAqIEBwYXJhbSB7Ym9keX0gYm9keVxcbiAgICAgKiBAcGFyYW0ge3ZlY3Rvcn0gdHJhbnNsYXRpb25cXG4gICAgICogQHBhcmFtIHtib29sZWFufSBbdXBkYXRlVmVsb2NpdHk9ZmFsc2VdXFxuICAgICAqL1xcbiAgICBCb2R5LnRyYW5zbGF0ZSA9IGZ1bmN0aW9uKGJvZHksIHRyYW5zbGF0aW9uLCB1cGRhdGVWZWxvY2l0eSkge1xcbiAgICAgICAgQm9keS5zZXRQb3NpdGlvbihib2R5LCBWZWN0b3IuYWRkKGJvZHkucG9zaXRpb24sIHRyYW5zbGF0aW9uKSwgdXBkYXRlVmVsb2NpdHkpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUm90YXRlcyBhIGJvZHkgYnkgYSBnaXZlbiBhbmdsZSByZWxhdGl2ZSB0byBpdHMgY3VycmVudCBhbmdsZS4gQnkgZGVmYXVsdCBhbmd1bGFyIHZlbG9jaXR5IGlzIHVuY2hhbmdlZC5cXG4gICAgICogSWYgYHVwZGF0ZVZlbG9jaXR5YCBpcyBgdHJ1ZWAgdGhlbiBhbmd1bGFyIHZlbG9jaXR5IGlzIGluZmVycmVkIGZyb20gdGhlIGNoYW5nZSBpbiBhbmdsZS5cXG4gICAgICogQG1ldGhvZCByb3RhdGVcXG4gICAgICogQHBhcmFtIHtib2R5fSBib2R5XFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSByb3RhdGlvblxcbiAgICAgKiBAcGFyYW0ge3ZlY3Rvcn0gW3BvaW50XVxcbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFt1cGRhdGVWZWxvY2l0eT1mYWxzZV1cXG4gICAgICovXFxuICAgIEJvZHkucm90YXRlID0gZnVuY3Rpb24oYm9keSwgcm90YXRpb24sIHBvaW50LCB1cGRhdGVWZWxvY2l0eSkge1xcbiAgICAgICAgaWYgKCFwb2ludCkge1xcbiAgICAgICAgICAgIEJvZHkuc2V0QW5nbGUoYm9keSwgYm9keS5hbmdsZSArIHJvdGF0aW9uLCB1cGRhdGVWZWxvY2l0eSk7XFxuICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgIHZhciBjb3MgPSBNYXRoLmNvcyhyb3RhdGlvbiksXFxuICAgICAgICAgICAgICAgIHNpbiA9IE1hdGguc2luKHJvdGF0aW9uKSxcXG4gICAgICAgICAgICAgICAgZHggPSBib2R5LnBvc2l0aW9uLnggLSBwb2ludC54LFxcbiAgICAgICAgICAgICAgICBkeSA9IGJvZHkucG9zaXRpb24ueSAtIHBvaW50Lnk7XFxuICAgICAgICAgICAgICAgIFxcbiAgICAgICAgICAgIEJvZHkuc2V0UG9zaXRpb24oYm9keSwge1xcbiAgICAgICAgICAgICAgICB4OiBwb2ludC54ICsgKGR4ICogY29zIC0gZHkgKiBzaW4pLFxcbiAgICAgICAgICAgICAgICB5OiBwb2ludC55ICsgKGR4ICogc2luICsgZHkgKiBjb3MpXFxuICAgICAgICAgICAgfSwgdXBkYXRlVmVsb2NpdHkpO1xcblxcbiAgICAgICAgICAgIEJvZHkuc2V0QW5nbGUoYm9keSwgYm9keS5hbmdsZSArIHJvdGF0aW9uLCB1cGRhdGVWZWxvY2l0eSk7XFxuICAgICAgICB9XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBTY2FsZXMgdGhlIGJvZHksIGluY2x1ZGluZyB1cGRhdGluZyBwaHlzaWNhbCBwcm9wZXJ0aWVzIChtYXNzLCBhcmVhLCBheGVzLCBpbmVydGlhKSwgZnJvbSBhIHdvcmxkLXNwYWNlIHBvaW50IChkZWZhdWx0IGlzIGJvZHkgY2VudHJlKS5cXG4gICAgICogQG1ldGhvZCBzY2FsZVxcbiAgICAgKiBAcGFyYW0ge2JvZHl9IGJvZHlcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHNjYWxlWFxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gc2NhbGVZXFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSBbcG9pbnRdXFxuICAgICAqL1xcbiAgICBCb2R5LnNjYWxlID0gZnVuY3Rpb24oYm9keSwgc2NhbGVYLCBzY2FsZVksIHBvaW50KSB7XFxuICAgICAgICB2Y
2XIgdG90YWxBcmVhID0gMCxcXG4gICAgICAgICAgICB0b3RhbEluZXJ0aWEgPSAwO1xcblxcbiAgICAgICAgcG9pbnQgPSBwb2ludCB8fCBib2R5LnBvc2l0aW9uO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBib2R5LnBhcnRzLmxlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgdmFyIHBhcnQgPSBib2R5LnBhcnRzW2ldO1xcblxcbiAgICAgICAgICAgIC8vIHNjYWxlIHZlcnRpY2VzXFxuICAgICAgICAgICAgVmVydGljZXMuc2NhbGUocGFydC52ZXJ0aWNlcywgc2NhbGVYLCBzY2FsZVksIHBvaW50KTtcXG5cXG4gICAgICAgICAgICAvLyB1cGRhdGUgcHJvcGVydGllc1xcbiAgICAgICAgICAgIHBhcnQuYXhlcyA9IEF4ZXMuZnJvbVZlcnRpY2VzKHBhcnQudmVydGljZXMpO1xcbiAgICAgICAgICAgIHBhcnQuYXJlYSA9IFZlcnRpY2VzLmFyZWEocGFydC52ZXJ0aWNlcyk7XFxuICAgICAgICAgICAgQm9keS5zZXRNYXNzKHBhcnQsIGJvZHkuZGVuc2l0eSAqIHBhcnQuYXJlYSk7XFxuXFxuICAgICAgICAgICAgLy8gdXBkYXRlIGluZXJ0aWEgKHJlcXVpcmVzIHZlcnRpY2VzIHRvIGJlIGF0IG9yaWdpbilcXG4gICAgICAgICAgICBWZXJ0aWNlcy50cmFuc2xhdGUocGFydC52ZXJ0aWNlcywgeyB4OiAtcGFydC5wb3NpdGlvbi54LCB5OiAtcGFydC5wb3NpdGlvbi55IH0pO1xcbiAgICAgICAgICAgIEJvZHkuc2V0SW5lcnRpYShwYXJ0LCBCb2R5Ll9pbmVydGlhU2NhbGUgKiBWZXJ0aWNlcy5pbmVydGlhKHBhcnQudmVydGljZXMsIHBhcnQubWFzcykpO1xcbiAgICAgICAgICAgIFZlcnRpY2VzLnRyYW5zbGF0ZShwYXJ0LnZlcnRpY2VzLCB7IHg6IHBhcnQucG9zaXRpb24ueCwgeTogcGFydC5wb3NpdGlvbi55IH0pO1xcblxcbiAgICAgICAgICAgIGlmIChpID4gMCkge1xcbiAgICAgICAgICAgICAgICB0b3RhbEFyZWEgKz0gcGFydC5hcmVhO1xcbiAgICAgICAgICAgICAgICB0b3RhbEluZXJ0aWEgKz0gcGFydC5pbmVydGlhO1xcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICAvLyBzY2FsZSBwb3NpdGlvblxcbiAgICAgICAgICAgIHBhcnQucG9zaXRpb24ueCA9IHBvaW50LnggKyAocGFydC5wb3NpdGlvbi54IC0gcG9pbnQueCkgKiBzY2FsZVg7XFxuICAgICAgICAgICAgcGFydC5wb3NpdGlvbi55ID0gcG9pbnQueSArIChwYXJ0LnBvc2l0aW9uLnkgLSBwb2ludC55KSAqIHNjYWxlWTtcXG5cXG4gICAgICAgICAgICAvLyB1cGRhdGUgYm91bmRzXFxuICAgICAgICAgICAgQm91bmRzLnVwZGF0ZShwYXJ0LmJvdW5kcywgcGFydC52ZXJ0aWNlcywgYm9keS52ZWxvY2l0eSk7XFxuICAgICAgICB9XFxuXFxuICAgICAgICAvLyBoYW5kbGUgcGFyZW50IGJvZHlcXG4gICAgICAgIGlmIChib2R5LnBhcnRzLmxlbmd0aCA+IDEpIHtcXG4gICAgICAgICAgICBib2R5LmFyZWEgPSB0b3RhbEFyZWE7XFxuXFxuICAgICAgICAgICAgaWYgKCFib2R5LmlzU3RhdGljKSB7XFxuICAgICAgICAgICAgICAgIEJvZHkuc2V0TWFzcyhib2R5LCBib2R5LmRlbnNpdHkgKiB0b3RhbEFyZWEpO1xcbiAgICAgICAgICAgICAgICBCb2R5LnNldEluZXJ0aWEoYm9keSwgdG90YWxJbmVydGlhKTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuXFxuICAgICAgICAvLyBoYW5kbGUgY2lyY2xlc1xcbiAgICAgICAgaWYgKGJvZHkuY2lyY2xlUmFkaXVzKSB7IFxcbiAgICAgICAgICAgIGlmIChzY2FsZVggPT09IHNjYWxlWSkge1xcbiAgICAgICAgICAgICAgICBib2R5LmNpcmNsZVJhZGl1cyAqPSBzY2FsZVg7XFxuICAgICAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICAgICAgLy8gYm9keSBpcyBubyBsb25nZXIgYSBjaXJjbGVcXG4gICAgICAgICAgICAgICAgYm9keS5jaXJjbGVSYWRpdXMgPSBudWxsO1xcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFBlcmZvcm1zIGFuIHVwZGF0ZSBieSBpbnRlZ3JhdGluZyB0aGUgZXF1YXRpb25zIG9mIG1vdGlvbiBvbiB0aGUgYGJvZHlgLlxcbiAgICAgKiBUaGlzIGlzIGFwcGxpZWQgZXZlcnkgdXBkYXRlIGJ5IGBNYXR0ZXIuRW5naW5lYCBhdXRvbWF0aWNhbGx5LlxcbiAgICAgKiBAbWV0aG9kIHVwZGF0ZVxcbiAgICAgKiBAcGFyYW0ge2JvZHl9IGJvZHlcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IFtkZWx0YVRpbWU9MTYuNjY2XVxcbiAgICAgKi9cXG4gICAgQm9keS51cGRhdGUgPSBmdW5jdGlvbihib2R5LCBkZWx0YVRpbWUpIHtcXG4gICAgICAgIGRlbHRhVGltZSA9ICh0eXBlb2YgZGVsdGFUaW1lICE9PSAndW5kZWZpbmVkJyA/IGRlbHRhVGltZSA6ICgxMDAwIC8gNjApKSAqIGJvZHkudGltZVNjYWxlO1xcblxcbiAgICAgICAgdmFyIGRlbHRhVGltZVNxdWFyZWQgPSBkZWx0YVRpbWUgKiBkZWx0YVRpbWUsXFxuICAgICAgICAgICAgY29ycmVjdGlvbiA9IEJvZHkuX3RpbWVDb3JyZWN0aW9uID8gZGVsdGFUaW1lIC8gKGJvZHkuZGVsdGFUaW1lIHx8IGRlbHRhVGltZSkgOiAxO1xcblxcbiAgICAgICAgLy8gZnJvbSB0aGUgcHJldmlvdXMgc3RlcFxcbiAgICAgICAgdmFyIGZyaWN0aW9uQWlyID0gMSAtIGJvZHkuZnJpY3Rpb25BaXIgKiAoZGVsdGFUaW1lIC8gQ29tbW9uLl9iYXNlRGVsdGEpLFxcbiAgICAgICAgICAgIHZlbG9jaXR5UHJldlggPSAoYm9keS5wb3NpdGlvbi54IC0gYm9keS5wb3NpdGlvblByZXYueCkgKiBjb3JyZWN0aW9uLFxcbiAgICAgICAgICAgIHZlbG9jaXR5UHJldlkgPSAoYm9keS5wb3NpdGlvbi55IC0gYm9keS5wb3NpdGlvblByZXYueSkgKiBjb3JyZWN0aW9uO1xcblxcbiAgICAgICAgLy8gdXBkYXRlIHZlbG9jaXR5IHdpdGggVmVybGV0IGludGVncmF0aW9uXFxuICAgICAgICBib2R5LnZlbG9jaXR5LnggPSAodmVsb2NpdHlQcmV2WCAqIGZyaWN0aW9uQWlyKSArIChib2R5LmZvcmNlLnggLyBib2R5Lm1hc3MpICogZGVsdGFUaW1lU3F1YXJlZDtcXG4gICAgICAgIGJvZHkudmVsb2NpdHkueSA9ICh2ZWxvY2l0eVByZXZZICogZnJpY3Rpb25BaXIpICsgKGJvZHkuZm9yY2UueSAvIGJvZHkubWFzcykgKiBkZWx0YVRpbWVTcXVhcmVkO1xcblxcbiAgICAgICAgYm9keS5wb3NpdGlvblByZXYueCA9IGJvZHkucG9zaXRpb24ueDtcXG4gICAgICAgIGJvZHkucG9zaXRpb25QcmV2LnkgPSBib2R5LnBvc2l0aW9uLnk7XFxuICAgICAgICBib2R5LnBvc2l0aW9uLnggKz0gYm9keS52ZWxvY2l0eS54O1xcbiAgICAgICAgYm9keS5wb3NpdGlvbi55ICs9IGJvZHkudmVsb2NpdHkueTtcXG4gICAgICAgIGJvZHkuZGVsdGFUaW1lID0gZGVsdGFUaW1lO1xcblxcbiAgICAgICAgLy8gdXBkYXRlIGFuZ3VsYXIgdmVsb2NpdHkgd2l0aCBWZXJsZXQgaW50ZWdyYXRpb25cXG4gICAgICAgIGJvZHkuYW5ndWxhclZlbG9jaXR5ID0gKChib2R5LmFuZ2xlIC0gYm9keS5hbmdsZVByZXYpICogZnJpY3Rpb25BaXIgKiBjb3JyZWN0aW9uKSArIChib2R5LnRvcnF1ZSAvIGJvZHkuaW5lcnRpYSkgKiBkZWx0YVRpbWVTcXVhcmVkO1xcbiAgICAgICAgYm9keS5hbmdsZVByZXYgPSBib2R5LmFuZ2xlO1xcbiAgICAgICAgYm9keS5hbmdsZSArPSBib2R5LmFuZ3VsYXJWZWxvY2l0eTtcXG5cXG4gICAgICAgIC8vIHRyYW5zZm9ybSB0aGUgYm9keSBnZW9tZXRyeVxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBib2R5LnBhcnRzLmxlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgdmFyIHBhcnQgPSBib2R5LnBhcnRzW2ldO1xcblxcbiAgICAgICAgICAgIFZlcnRpY2VzLnRyYW5zbGF0ZShwYXJ0LnZlcnRpY2VzLCBib2R5LnZlbG9jaXR5KTtcXG4gICAgICAgICAgICBcXG4gICAgICAgICAgICBpZiAoaSA+IDApIHtcXG4gICAgICAgICAgICAgICAgcGFydC5wb3NpdGlvbi54ICs9IGJvZHkudmVsb2NpdHkueDtcXG4gICAgICAgICAgICAgICAgcGFydC5wb3NpdGlvbi55ICs9IGJvZHkudmVsb2NpdHkueTtcXG4gICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgaWYgKGJvZHkuYW5ndWxhclZlbG9jaXR5ICE9PSAwKSB7XFxuICAgICAgICAgICAgICAgIFZlcnRpY2VzLnJvdGF0ZShwYXJ0LnZlcnRpY2VzLCBib2R5LmFuZ3VsYXJWZWxvY2l0eSwgYm9keS5wb3NpdGlvbik7XFxuICAgICAgICAgICAgICAgIEF4ZXMucm90YXRlKHBhcnQuYXhlcywgYm9keS5hbmd1bGFyVmVsb2NpdHkpO1xcbiAgICAgICAgICAgICAgICBpZiAoaSA+IDApIHtcXG4gICAgICAgICAgICAgICAgICAgIFZlY3Rvci5yb3RhdGVBYm91dChwYXJ0LnBvc2l0aW9uLCBib2R5LmFuZ3VsYXJWZWxvY2l0eSwgYm9keS5wb3NpdGlvbiwgcGFydC5wb3NpdGlvbik7XFxuICAgICAgICAgICAgICAgI
2H1cXG4gICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgQm91bmRzLnVwZGF0ZShwYXJ0LmJvdW5kcywgcGFydC52ZXJ0aWNlcywgYm9keS52ZWxvY2l0eSk7XFxuICAgICAgICB9XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBVcGRhdGVzIHByb3BlcnRpZXMgYGJvZHkudmVsb2NpdHlgLCBgYm9keS5zcGVlZGAsIGBib2R5LmFuZ3VsYXJWZWxvY2l0eWAgYW5kIGBib2R5LmFuZ3VsYXJTcGVlZGAgd2hpY2ggYXJlIG5vcm1hbGlzZWQgaW4gcmVsYXRpb24gdG8gYEJvZHkuX2Jhc2VEZWx0YWAuXFxuICAgICAqIEBtZXRob2QgdXBkYXRlVmVsb2NpdGllc1xcbiAgICAgKiBAcGFyYW0ge2JvZHl9IGJvZHlcXG4gICAgICovXFxuICAgIEJvZHkudXBkYXRlVmVsb2NpdGllcyA9IGZ1bmN0aW9uKGJvZHkpIHtcXG4gICAgICAgIHZhciB0aW1lU2NhbGUgPSBCb2R5Ll9iYXNlRGVsdGEgLyBib2R5LmRlbHRhVGltZSxcXG4gICAgICAgICAgICBib2R5VmVsb2NpdHkgPSBib2R5LnZlbG9jaXR5O1xcblxcbiAgICAgICAgYm9keVZlbG9jaXR5LnggPSAoYm9keS5wb3NpdGlvbi54IC0gYm9keS5wb3NpdGlvblByZXYueCkgKiB0aW1lU2NhbGU7XFxuICAgICAgICBib2R5VmVsb2NpdHkueSA9IChib2R5LnBvc2l0aW9uLnkgLSBib2R5LnBvc2l0aW9uUHJldi55KSAqIHRpbWVTY2FsZTtcXG4gICAgICAgIGJvZHkuc3BlZWQgPSBNYXRoLnNxcnQoKGJvZHlWZWxvY2l0eS54ICogYm9keVZlbG9jaXR5LngpICsgKGJvZHlWZWxvY2l0eS55ICogYm9keVZlbG9jaXR5LnkpKTtcXG5cXG4gICAgICAgIGJvZHkuYW5ndWxhclZlbG9jaXR5ID0gKGJvZHkuYW5nbGUgLSBib2R5LmFuZ2xlUHJldikgKiB0aW1lU2NhbGU7XFxuICAgICAgICBib2R5LmFuZ3VsYXJTcGVlZCA9IE1hdGguYWJzKGJvZHkuYW5ndWxhclZlbG9jaXR5KTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIEFwcGxpZXMgdGhlIGBmb3JjZWAgdG8gdGhlIGBib2R5YCBmcm9tIHRoZSBmb3JjZSBvcmlnaW4gYHBvc2l0aW9uYCBpbiB3b3JsZC1zcGFjZSwgb3ZlciBhIHNpbmdsZSB0aW1lc3RlcCwgaW5jbHVkaW5nIGFwcGx5aW5nIGFueSByZXN1bHRpbmcgYW5ndWxhciB0b3JxdWUuXFxuICAgICAqIFxcbiAgICAgKiBGb3JjZXMgYXJlIHVzZWZ1bCBmb3IgZWZmZWN0cyBsaWtlIGdyYXZpdHksIHdpbmQgb3Igcm9ja2V0IHRocnVzdCwgYnV0IGNhbiBiZSBkaWZmaWN1bHQgaW4gcHJhY3RpY2Ugd2hlbiBwcmVjaXNlIGNvbnRyb2wgaXMgbmVlZGVkLiBJbiB0aGVzZSBjYXNlcyBzZWUgYEJvZHkuc2V0VmVsb2NpdHlgIGFuZCBgQm9keS5zZXRQb3NpdGlvbmAgYXMgYW4gYWx0ZXJuYXRpdmUuXFxuICAgICAqIFxcbiAgICAgKiBUaGUgZm9yY2UgZnJvbSB0aGlzIGZ1bmN0aW9uIGlzIG9ubHkgYXBwbGllZCBvbmNlIGZvciB0aGUgZHVyYXRpb24gb2YgYSBzaW5nbGUgdGltZXN0ZXAsIGluIG90aGVyIHdvcmRzIHRoZSBkdXJhdGlvbiBkZXBlbmRzIGRpcmVjdGx5IG9uIHRoZSBjdXJyZW50IGVuZ2luZSB1cGRhdGUgYGRlbHRhYCBhbmQgdGhlIHJhdGUgb2YgY2FsbHMgdG8gdGhpcyBmdW5jdGlvbi5cXG4gICAgICogXFxuICAgICAqIFRoZXJlZm9yZSB0byBhY2NvdW50IGZvciB0aW1lLCB5b3Ugc2hvdWxkIGFwcGx5IHRoZSBmb3JjZSBjb25zdGFudGx5IG92ZXIgYXMgbWFueSBlbmdpbmUgdXBkYXRlcyBhcyBlcXVpdmFsZW50IHRvIHRoZSBpbnRlbmRlZCBkdXJhdGlvbi5cXG4gICAgICogXFxuICAgICAqIElmIGFsbCBvciBwYXJ0IG9mIHRoZSBmb3JjZSBkdXJhdGlvbiBpcyBzb21lIGZyYWN0aW9uIG9mIGEgdGltZXN0ZXAsIGZpcnN0IG11bHRpcGx5IHRoZSBmb3JjZSBieSBgZHVyYXRpb24gLyB0aW1lc3RlcGAuXFxuICAgICAqIFxcbiAgICAgKiBUaGUgZm9yY2Ugb3JpZ2luIGBwb3NpdGlvbmAgaW4gd29ybGQtc3BhY2UgbXVzdCBhbHNvIGJlIHNwZWNpZmllZC4gUGFzc2luZyBgYm9keS5wb3NpdGlvbmAgd2lsbCByZXN1bHQgaW4gemVybyBhbmd1bGFyIGVmZmVjdCBhcyB0aGUgZm9yY2Ugb3JpZ2luIHdvdWxkIGJlIGF0IHRoZSBjZW50cmUgb2YgbWFzcy5cXG4gICAgICogXFxuICAgICAqIFRoZSBgYm9keWAgd2lsbCB0YWtlIHRpbWUgdG8gYWNjZWxlcmF0ZSB1bmRlciBhIGZvcmNlLCB0aGUgcmVzdWx0aW5nIGVmZmVjdCBkZXBlbmRzIG9uIGR1cmF0aW9uIG9mIHRoZSBmb3JjZSwgdGhlIGJvZHkgbWFzcyBhbmQgb3RoZXIgZm9yY2VzIG9uIHRoZSBib2R5IGluY2x1ZGluZyBmcmljdGlvbiBjb21iaW5lZC5cXG4gICAgICogQG1ldGhvZCBhcHBseUZvcmNlXFxuICAgICAqIEBwYXJhbSB7Ym9keX0gYm9keVxcbiAgICAgKiBAcGFyYW0ge3ZlY3Rvcn0gcG9zaXRpb24gVGhlIGZvcmNlIG9yaWdpbiBpbiB3b3JsZC1zcGFjZS4gUGFzcyBgYm9keS5wb3NpdGlvbmAgdG8gYXZvaWQgYW5ndWxhciB0b3JxdWUuXFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSBmb3JjZVxcbiAgICAgKi9cXG4gICAgQm9keS5hcHBseUZvcmNlID0gZnVuY3Rpb24oYm9keSwgcG9zaXRpb24sIGZvcmNlKSB7XFxuICAgICAgICB2Y
2XIgb2Zmc2V0ID0geyB4OiBwb3NpdGlvbi54IC0gYm9keS5wb3NpdGlvbi54LCB5OiBwb3NpdGlvbi55IC0gYm9keS5wb3NpdGlvbi55IH07XFxuICAgICAgICBib2R5LmZvcmNlLnggKz0gZm9yY2UueDtcXG4gICAgICAgIGJvZHkuZm9yY2UueSArPSBmb3JjZS55O1xcbiAgICAgICAgYm9keS50b3JxdWUgKz0gb2Zmc2V0LnggKiBmb3JjZS55IC0gb2Zmc2V0LnkgKiBmb3JjZS54O1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmV0dXJucyB0aGUgc3VtcyBvZiB0aGUgcHJvcGVydGllcyBvZiBhbGwgY29tcG91bmQgcGFydHMgb2YgdGhlIHBhcmVudCBib2R5LlxcbiAgICAgKiBAbWV0aG9kIF90b3RhbFByb3BlcnRpZXNcXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQHBhcmFtIHtib2R5fSBib2R5XFxuICAgICAqIEByZXR1cm4ge31cXG4gICAgICovXFxuICAgIEJvZHkuX3RvdGFsUHJvcGVydGllcyA9IGZ1bmN0aW9uKGJvZHkpIHtcXG4gICAgICAgIC8vIGZyb20gZXF1YXRpb25zIGF0OlxcbiAgICAgICAgLy8gaHR0cHM6Ly9lY291cnNlcy5vdS5lZHUvY2dpLWJpbi9lYm9vay5jZ2k/ZG9jPSZ0b3BpYz1zdCZjaGFwX3NlYz0wNy4yJnBhZ2U9dGhlb3J5XFxuICAgICAgICAvLyBodHRwOi8vb3V0cHV0LnRvL3NpZGV3YXkvZGVmYXVsdC5hc3A/cW5vPTEyMTEwMDA4N1xcblxcbiAgICAgICAgdmFyIHByb3BlcnRpZXMgPSB7XFxuICAgICAgICAgICAgbWFzczogMCxcXG4gICAgICAgICAgICBhcmVhOiAwLFxcbiAgICAgICAgICAgIGluZXJ0aWE6IDAsXFxuICAgICAgICAgICAgY2VudHJlOiB7IHg6IDAsIHk6IDAgfVxcbiAgICAgICAgfTtcXG5cXG4gICAgICAgIC8vIHN1bSB0aGUgcHJvcGVydGllcyBvZiBhbGwgY29tcG91bmQgcGFydHMgb2YgdGhlIHBhcmVudCBib2R5XFxuICAgICAgICBmb3IgKHZhciBpID0gYm9keS5wYXJ0cy5sZW5ndGggPT09IDEgPyAwIDogMTsgaSA8IGJvZHkucGFydHMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICB2Y
2XIgcGFydCA9IGJvZHkucGFydHNbaV0sXFxuICAgICAgICAgICAgICAgIG1hc3MgPSBwYXJ0Lm1hc3MgIT09IEluZmluaXR5ID8gcGFydC5tYXNzIDogMTtcXG5cXG4gICAgICAgICAgICBwcm9wZXJ0aWVzLm1hc3MgKz0gbWFzcztcXG4gICAgICAgICAgICBwcm9wZXJ0aWVzLmFyZWEgKz0gcGFydC5hcmVhO1xcbiAgICAgICAgICAgIHByb3BlcnRpZXMuaW5lcnRpYSArPSBwYXJ0LmluZXJ0aWE7XFxuICAgICAgICAgICAgcHJvcGVydGllcy5jZW50cmUgPSBWZWN0b3IuYWRkKHByb3BlcnRpZXMuY2VudHJlLCBWZWN0b3IubXVsdChwYXJ0LnBvc2l0aW9uLCBtYXNzKSk7XFxuICAgICAgICB9XFxuXFxuICAgICAgICBwcm9wZXJ0aWVzLmNlbnRyZSA9IFZlY3Rvci5kaXYocHJvcGVydGllcy5jZW50cmUsIHByb3BlcnRpZXMubWFzcyk7XFxuXFxuICAgICAgICByZXR1cm4gcHJvcGVydGllcztcXG4gICAgfTtcXG5cXG4gICAgLypcXG4gICAgKlxcbiAgICAqICBFdmVudHMgRG9jdW1lbnRhdGlvblxcbiAgICAqXFxuICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAqIEZpcmVkIHdoZW4gYSBib2R5IHN0YXJ0cyBzbGVlcGluZyAod2hlcmUgYHRoaXNgIGlzIHRoZSBib2R5KS5cXG4gICAgKlxcbiAgICAqIEBldmVudCBzbGVlcFN0YXJ0XFxuICAgICogQHRoaXMge2JvZHl9IFRoZSBib2R5IHRoYXQgaGFzIHN0YXJ0ZWQgc2xlZXBpbmdcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQgQW4gZXZlbnQgb2JqZWN0XFxuICAgICogQHBhcmFtIHt9IGV2ZW50LnNvdXJjZSBUaGUgc291cmNlIG9iamVjdCBvZiB0aGUgZXZlbnRcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQubmFtZSBUaGUgbmFtZSBvZiB0aGUgZXZlbnRcXG4gICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICogRmlyZWQgd2hlbiBhIGJvZHkgZW5kcyBzbGVlcGluZyAod2hlcmUgYHRoaXNgIGlzIHRoZSBib2R5KS5cXG4gICAgKlxcbiAgICAqIEBldmVudCBzbGVlcEVuZFxcbiAgICAqIEB0aGlzIHtib2R5fSBUaGUgYm9keSB0aGF0IGhhcyBlbmRlZCBzbGVlcGluZ1xcbiAgICAqIEBwYXJhbSB7fSBldmVudCBBbiBldmVudCBvYmplY3RcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQuc291cmNlIFRoZSBzb3VyY2Ugb2JqZWN0IG9mIHRoZSBldmVudFxcbiAgICAqIEBwYXJhbSB7fSBldmVudC5uYW1lIFRoZSBuYW1lIG9mIHRoZSBldmVudFxcbiAgICAqL1xcblxcbiAgICAvKlxcbiAgICAqXFxuICAgICogIFByb3BlcnRpZXMgRG9jdW1lbnRhdGlvblxcbiAgICAqXFxuICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBbiBpbnRlZ2VyIGBOdW1iZXJgIHVuaXF1ZWx5IGlkZW50aWZ5aW5nIG51bWJlciBnZW5lcmF0ZWQgaW4gYEJvZHkuY3JlYXRlYCBieSBgQ29tbW9uLm5leHRJZGAuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBpZFxcbiAgICAgKiBAdHlwZSBudW1iZXJcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBfUmVhZCBvbmx5Xy4gU2V0IGJ5IGBCb2R5LmNyZWF0ZWAuXFxuICAgICAqIFxcbiAgICAgKiBBIGBTdHJpbmdgIGRlbm90aW5nIHRoZSB0eXBlIG9mIG9iamVjdC5cXG4gICAgICpcXG4gICAgICogQHJlYWRPbmx5XFxuICAgICAqIEBwcm9wZXJ0eSB0eXBlXFxuICAgICAqIEB0eXBlIHN0cmluZ1xcbiAgICAgKiBAZGVmYXVsdCBcXFwiYm9keVxcXCJcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBbiBhcmJpdHJhcnkgYFN0cmluZ2AgbmFtZSB0byBoZWxwIHRoZSB1c2VyIGlkZW50aWZ5IGFuZCBtYW5hZ2UgYm9kaWVzLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgbGFiZWxcXG4gICAgICogQHR5cGUgc3RyaW5nXFxuICAgICAqIEBkZWZhdWx0IFxcXCJCb2R5XFxcIlxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIF9SZWFkIG9ubHlfLiBVc2UgYEJvZHkuc2V0UGFydHNgIHRvIHNldC4gXFxuICAgICAqIFxcbiAgICAgKiBBbiBhcnJheSBvZiBib2RpZXMgdGhhdCBtYWtlIHVwIHRoaXMgYm9keS4gXFxuICAgICAqIFRoZSBmaXJzdCBib2R5IGluIHRoZSBhcnJheSBtdXN0IGFsd2F5cyBiZSBhIHNlbGYgcmVmZXJlbmNlIHRvIHRoZSBjdXJyZW50IGJvZHkgaW5zdGFuY2UuXFxuICAgICAqIEFsbCBib2RpZXMgaW4gdGhlIGBwYXJ0c2AgYXJyYXkgdG9nZXRoZXIgZm9ybSBhIHNpbmdsZSByaWdpZCBjb21wb3VuZCBib2R5LlxcbiAgICAgKiBQYXJ0cyBhcmUgYWxsb3dlZCB0byBvdmVybGFwLCBoYXZlIGdhcHMgb3IgaG9sZXMgb3IgZXZlbiBmb3JtIGNvbmNhdmUgYm9kaWVzLlxcbiAgICAgKiBQYXJ0cyB0aGVtc2VsdmVzIHNob3VsZCBuZXZlciBiZSBhZGRlZCB0byBhIGBXb3JsZGAsIG9ubHkgdGhlIHBhcmVudCBib2R5IHNob3VsZCBiZS5cXG4gICAgICogVXNlIGBCb2R5LnNldFBhcnRzYCB3aGVuIHNldHRpbmcgcGFydHMgdG8gZW5zdXJlIGNvcnJlY3QgdXBkYXRlcyBvZiBhbGwgcHJvcGVydGllcy5cXG4gICAgICpcXG4gICAgICogQHJlYWRPbmx5XFxuICAgICAqIEBwcm9wZXJ0eSBwYXJ0c1xcbiAgICAgKiBAdHlwZSBib2R5W11cXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBbiBvYmplY3QgcmVzZXJ2ZWQgZm9yIHN0b3JpbmcgcGx1Z2luLXNwZWNpZmljIHByb3BlcnRpZXMuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBwbHVnaW5cXG4gICAgICogQHR5cGUge31cXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBfUmVhZCBvbmx5Xy4gVXBkYXRlZCBieSBgQm9keS5zZXRQYXJ0c2AuXFxuICAgICAqIFxcbiAgICAgKiBBIHJlZmVyZW5jZSB0byB0aGUgYm9keSB0aGF0IHRoaXMgaXMgYSBwYXJ0IG9mLiBTZWUgYGJvZHkucGFydHNgLlxcbiAgICAgKiBUaGlzIGlzIGEgc2VsZiByZWZlcmVuY2UgaWYgdGhlIGJvZHkgaXMgbm90IGEgcGFydCBvZiBhbm90aGVyIGJvZHkuXFxuICAgICAqXFxuICAgICAqIEByZWFkT25seVxcbiAgICAgKiBAcHJvcGVydHkgcGFyZW50XFxuICAgICAqIEB0eXBlIGJvZHlcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGBOdW1iZXJgIHNwZWNpZnlpbmcgdGhlIGFuZ2xlIG9mIHRoZSBib2R5LCBpbiByYWRpYW5zLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgYW5nbGVcXG4gICAgICogQHR5cGUgbnVtYmVyXFxuICAgICAqIEBkZWZhdWx0IDBcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBfUmVhZCBvbmx5Xy4gVXNlIGBCb2R5LnNldFZlcnRpY2VzYCBvciBgQm9keS5zZXRQYXJ0c2AgdG8gc2V0LiBTZWUgYWxzbyBgQm9kaWVzLmZyb21WZXJ0aWNlc2AuXFxuICAgICAqIFxcbiAgICAgKiBBbiBhcnJheSBvZiBgVmVjdG9yYCBvYmplY3RzIHRoYXQgc3BlY2lmeSB0aGUgY29udmV4IGh1bGwgb2YgdGhlIHJpZ2lkIGJvZHkuXFxuICAgICAqIFRoZXNlIHNob3VsZCBiZSBwcm92aWRlZCBhYm91dCB0aGUgb3JpZ2luIGAoMCwgMClgLiBFLmcuXFxuICAgICAqXFxuICAgICAqIGBbeyB4OiAwLCB5OiAwIH0sIHsgeDogMjUsIHk6IDUwIH0sIHsgeDogNTAsIHk6IDAgfV1gXFxuICAgICAqIFxcbiAgICAgKiBWZXJ0aWNlcyBtdXN0IGFsd2F5cyBiZSBjb252ZXgsIGluIGNsb2Nrd2lzZSBvcmRlciBhbmQgbXVzdCBub3QgY29udGFpbiBhbnkgZHVwbGljYXRlIHBvaW50cy5cXG4gICAgICogXFxuICAgICAqIENvbmNhdmUgdmVydGljZXMgc2hvdWxkIGJlIGRlY29tcG9zZWQgaW50byBjb252ZXggYHBhcnRzYCwgc2VlIGBCb2RpZXMuZnJvbVZlcnRpY2VzYCBhbmQgYEJvZHkuc2V0UGFydHNgLlxcbiAgICAgKlxcbiAgICAgKiBXaGVuIHNldCB0aGUgdmVydGljZXMgYXJlIHRyYW5zbGF0ZWQgc3VjaCB0aGF0IGBib2R5LnBvc2l0aW9uYCBpcyBhdCB0aGUgY2VudHJlIG9mIG1hc3MuXFxuICAgICAqIE1hbnkgb3RoZXIgYm9keSBwcm9wZXJ0aWVzIGFyZSBhdXRvbWF0aWNhbGx5IGNhbGN1bGF0ZWQgZnJvbSB0aGVzZSB2ZXJ0aWNlcyB3aGVuIHNldCBpbmNsdWRpbmcgYGRlbnNpdHlgLCBgYXJlYWAgYW5kIGBpbmVydGlhYC5cXG4gICAgICogXFxuICAgICAqIFRoZSBtb2R1bGUgYE1hdHRlci5WZXJ0aWNlc2AgY29udGFpbnMgdXNlZnVsIG1ldGhvZHMgZm9yIHdvcmtpbmcgd2l0aCB2ZXJ0aWNlcy5cXG4gICAgICpcXG4gICAgICogQHJlYWRPbmx5XFxuICAgICAqIEBwcm9wZXJ0eSB2ZXJ0aWNlc1xcbiAgICAgKiBAdHlwZSB2ZWN0b3JbXVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIF9SZWFkIG9ubHlfLiBVc2UgYEJvZHkuc2V0UG9zaXRpb25gIHRvIHNldC4gXFxuICAgICAqIFxcbiAgICAgKiBBIGBWZWN0b3JgIHRoYXQgc3BlY2lmaWVzIHRoZSBjdXJyZW50IHdvcmxkLXNwYWNlIHBvc2l0aW9uIG9mIHRoZSBib2R5LlxcbiAgICAgKiBcXG4gICAgICogQHJlYWRPbmx5XFxuICAgICAqIEBwcm9wZXJ0eSBwb3NpdGlvblxcbiAgICAgKiBAdHlwZSB2ZWN0b3JcXG4gICAgICogQGRlZmF1bHQgeyB4OiAwLCB5OiAwIH1cXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGBWZWN0b3JgIHRoYXQgYWNjdW11bGF0ZXMgdGhlIHRvdGFsIGZvcmNlIGFwcGxpZWQgdG8gdGhlIGJvZHkgZm9yIGEgc2luZ2xlIHVwZGF0ZS5cXG4gICAgICogRm9yY2UgaXMgemVyb2VkIGFmdGVyIGV2ZXJ5IGBFbmdpbmUudXBkYXRlYCwgc28gY29uc3RhbnQgZm9yY2VzIHNob3VsZCBiZSBhcHBsaWVkIGZvciBldmVyeSB1cGRhdGUgdGhleSBhcmUgbmVlZGVkLiBTZWUgYWxzbyBgQm9keS5hcHBseUZvcmNlYC5cXG4gICAgICogXFxuICAgICAqIEBwcm9wZXJ0eSBmb3JjZVxcbiAgICAgKiBAdHlwZSB2ZWN0b3JcXG4gICAgICogQGRlZmF1bHQgeyB4OiAwLCB5OiAwIH1cXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGBOdW1iZXJgIHRoYXQgYWNjdW11bGF0ZXMgdGhlIHRvdGFsIHRvcnF1ZSAodHVybmluZyBmb3JjZSkgYXBwbGllZCB0byB0aGUgYm9keSBmb3IgYSBzaW5nbGUgdXBkYXRlLiBTZWUgYWxzbyBgQm9keS5hcHBseUZvcmNlYC5cXG4gICAgICogVG9ycXVlIGlzIHplcm9lZCBhZnRlciBldmVyeSBgRW5naW5lLnVwZGF0ZWAsIHNvIGNvbnN0YW50IHRvcnF1ZXMgc2hvdWxkIGJlIGFwcGxpZWQgZm9yIGV2ZXJ5IHVwZGF0ZSB0aGV5IGFyZSBuZWVkZWQuXFxuICAgICAqXFxuICAgICAqIFRvcnF1ZXMgcmVzdWx0IGluIGFuZ3VsYXIgYWNjZWxlcmF0aW9uIG9uIGV2ZXJ5IHVwZGF0ZSwgd2hpY2ggZGVwZW5kcyBvbiBib2R5IGluZXJ0aWEgYW5kIHR
2oZSBlbmdpbmUgdXBkYXRlIGRlbHRhLlxcbiAgICAgKiBcXG4gICAgICogQHByb3BlcnR5IHRvcnF1ZVxcbiAgICAgKiBAdHlwZSBudW1iZXJcXG4gICAgICogQGRlZmF1bHQgMFxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIF9SZWFkIG9ubHlfLiBVc2UgYEJvZHkuc2V0U3BlZWRgIHRvIHNldC4gXFxuICAgICAqIFxcbiAgICAgKiBTZWUgYEJvZHkuZ2V0U3BlZWRgIGZvciBkZXRhaWxzLlxcbiAgICAgKiBcXG4gICAgICogRXF1aXZhbGVudCB0byB0aGUgbWFnbml0dWRlIG9mIGBib2R5LnZlbG9jaXR5YCAoYWx3YXlzIHBvc2l0aXZlKS5cXG4gICAgICogXFxuICAgICAqIEByZWFkT25seVxcbiAgICAgKiBAcHJvcGVydHkgc3BlZWRcXG4gICAgICogQHR5cGUgbnVtYmVyXFxuICAgICAqIEBkZWZhdWx0IDBcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBfUmVhZCBvbmx5Xy4gVXNlIGBCb2R5LnNldFZlbG9jaXR5YCB0byBzZXQuIFxcbiAgICAgKiBcXG4gICAgICogU2VlIGBCb2R5LmdldFZlbG9jaXR5YCBmb3IgZGV0YWlscy5cXG4gICAgICogXFxuICAgICAqIEVxdWl2YWxlbnQgdG8gdGhlIG1hZ25pdHVkZSBvZiBgYm9keS5hbmd1bGFyVmVsb2NpdHlgIChhbHdheXMgcG9zaXRpdmUpLlxcbiAgICAgKiBcXG4gICAgICogQHJlYWRPbmx5XFxuICAgICAqIEBwcm9wZXJ0eSB2ZWxvY2l0eVxcbiAgICAgKiBAdHlwZSB2ZWN0b3JcXG4gICAgICogQGRlZmF1bHQgeyB4OiAwLCB5OiAwIH1cXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBfUmVhZCBvbmx5Xy4gVXNlIGBCb2R5LnNldEFuZ3VsYXJTcGVlZGAgdG8gc2V0LiBcXG4gICAgICogXFxuICAgICAqIFNlZSBgQm9keS5nZXRBbmd1bGFyU3BlZWRgIGZvciBkZXRhaWxzLlxcbiAgICAgKiBcXG4gICAgICogXFxuICAgICAqIEByZWFkT25seVxcbiAgICAgKiBAcHJvcGVydHkgYW5ndWxhclNwZWVkXFxuICAgICAqIEB0eXBlIG51bWJlclxcbiAgICAgKiBAZGVmYXVsdCAwXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogX1JlYWQgb25seV8uIFVzZSBgQm9keS5zZXRBbmd1bGFyVmVsb2NpdHlgIHRvIHNldC4gXFxuICAgICAqIFxcbiAgICAgKiBTZWUgYEJvZHkuZ2V0QW5ndWxhclZlbG9jaXR5YCBmb3IgZGV0YWlscy5cXG4gICAgICogXFxuICAgICAqXFxuICAgICAqIEByZWFkT25seVxcbiAgICAgKiBAcHJvcGVydHkgYW5ndWxhclZlbG9jaXR5XFxuICAgICAqIEB0eXBlIG51bWJlclxcbiAgICAgKiBAZGVmYXVsdCAwXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogX1JlYWQgb25seV8uIFVzZSBgQm9keS5zZXRTdGF0aWNgIHRvIHNldC4gXFxuICAgICAqIFxcbiAgICAgKiBBIGZsYWcgdGhhdCBpbmRpY2F0ZXMgd2hldGhlciBhIGJvZHkgaXMgY29uc2lkZXJlZCBzdGF0aWMuIEEgc3RhdGljIGJvZHkgY2FuIG5ldmVyIGNoYW5nZSBwb3NpdGlvbiBvciBhbmdsZSBhbmQgaXMgY29tcGxldGVseSBmaXhlZC5cXG4gICAgICpcXG4gICAgICogQHJlYWRPbmx5XFxuICAgICAqIEBwcm9wZXJ0eSBpc1N0YXRpY1xcbiAgICAgKiBAdHlwZSBib29sZWFuXFxuICAgICAqIEBkZWZhdWx0IGZhbHNlXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBmbGFnIHRoYXQgaW5kaWNhdGVzIHdoZXRoZXIgYSBib2R5IGlzIGEgc2Vuc29yLiBTZW5zb3IgdHJpZ2dlcnMgY29sbGlzaW9uIGV2ZW50cywgYnV0IGRvZXNuJ3QgcmVhY3Qgd2l0aCBjb2xsaWRpbmcgYm9keSBwaHlzaWNhbGx5LlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgaXNTZW5zb3JcXG4gICAgICogQHR5cGUgYm9vbGVhblxcbiAgICAgKiBAZGVmYXVsdCBmYWxzZVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIF9SZWFkIG9ubHlfLiBVc2UgYFNsZWVwaW5nLnNldGAgdG8gc2V0LiBcXG4gICAgICogXFxuICAgICAqIEEgZmxhZyB0aGF0IGluZGljYXRlcyB3aGV0aGVyIHR
2oZSBib2R5IGlzIGNvbnNpZGVyZWQgc2xlZXBpbmcuIEEgc2xlZXBpbmcgYm9keSBhY3RzIHNpbWlsYXIgdG8gYSBzdGF0aWMgYm9keSwgZXhjZXB0IGl0IGlzIG9ubHkgdGVtcG9yYXJ5IGFuZCBjYW4gYmUgYXdva2VuLlxcbiAgICAgKlxcbiAgICAgKiBAcmVhZE9ubHlcXG4gICAgICogQHByb3BlcnR5IGlzU2xlZXBpbmdcXG4gICAgICogQHR5cGUgYm9vbGVhblxcbiAgICAgKiBAZGVmYXVsdCBmYWxzZVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIF9SZWFkIG9ubHlfLiBDYWxjdWxhdGVkIGR1cmluZyBlbmdpbmUgdXBkYXRlIG9ubHkgd2hlbiBzbGVlcGluZyBpcyBlbmFibGVkLlxcbiAgICAgKiBcXG4gICAgICogQSBgTnVtYmVyYCB0aGF0IGxvb3NlbHkgbWVhc3VyZXMgdGhlIGFtb3VudCBvZiBtb3ZlbWVudCBhIGJvZHkgY3VycmVudGx5IGhhcy5cXG4gICAgICpcXG4gICAgICogRGVyaXZlZCBmcm9tIGBib2R5LnNwZWVkXjIgKyBib2R5LmFuZ3VsYXJTcGVlZF4yYC4gU2VlIGBTbGVlcGluZy51cGRhdGVgLlxcbiAgICAgKiBcXG4gICAgICogQHJlYWRPbmx5XFxuICAgICAqIEBwcm9wZXJ0eSBtb3Rpb25cXG4gICAgICogQHR5cGUgbnVtYmVyXFxuICAgICAqIEBkZWZhdWx0IDBcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGBOdW1iZXJgIHRoYXQgZGVmaW5lcyB0aGUgbGVuZ3RoIG9mIHRpbWUgZHVyaW5nIHdoaWNoIHRoaXMgYm9keSBtdXN0IGhhdmUgbmVhci16ZXJvIHZlbG9jaXR5IGJlZm9yZSBpdCBpcyBzZXQgYXMgc2xlZXBpbmcgYnkgdGhlIGBNYXR0ZXIuU2xlZXBpbmdgIG1vZHVsZSAoaWYgc2xlZXBpbmcgaXMgZW5hYmxlZCBieSB0aGUgZW5naW5lKS5cXG4gICAgICogXFxuICAgICAqIEBwcm9wZXJ0eSBzbGVlcFRocmVzaG9sZFxcbiAgICAgKiBAdHlwZSBudW1iZXJcXG4gICAgICogQGRlZmF1bHQgNjBcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBfUmVhZCBvbmx5Xy4gVXNlIGBCb2R5LnNldERlbnNpdHlgIHRvIHNldC4gXFxuICAgICAqIFxcbiAgICAgKiBBIGBOdW1iZXJgIHRoYXQgZGVmaW5lcyB0aGUgZGVuc2l0eSBvZiB0aGUgYm9keSAobWFzcyBwZXIgdW5pdCBhcmVhKS5cXG4gICAgICogXFxuICAgICAqIE1hc3Mgd2lsbCBhbHNvIGJlIHVwZGF0ZWQgd2hlbiBzZXQuXFxuICAgICAqXFxuICAgICAqIEByZWFkT25seVxcbiAgICAgKiBAcHJvcGVydHkgZGVuc2l0eVxcbiAgICAgKiBAdHlwZSBudW1iZXJcXG4gICAgICogQGRlZmF1bHQgMC4wMDFcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBfUmVhZCBvbmx5Xy4gVXNlIGBCb2R5LnNldE1hc3NgIHRvIHNldC4gXFxuICAgICAqIFxcbiAgICAgKiBBIGBOdW1iZXJgIHRoYXQgZGVmaW5lcyB0aGUgbWFzcyBvZiB0aGUgYm9keS5cXG4gICAgICogXFxuICAgICAqIERlbnNpdHkgd2lsbCBhbHNvIGJlIHVwZGF0ZWQgd2hlbiBzZXQuXFxuICAgICAqIFxcbiAgICAgKiBAcmVhZE9ubHlcXG4gICAgICogQHByb3BlcnR5IG1hc3NcXG4gICAgICogQHR5cGUgbnVtYmVyXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogX1JlYWQgb25seV8uIFVzZSBgQm9keS5zZXRNYXNzYCB0byBzZXQuIFxcbiAgICAgKiBcXG4gICAgICogQSBgTnVtYmVyYCB0aGF0IGRlZmluZXMgdGhlIGludmVyc2UgbWFzcyBvZiB0aGUgYm9keSAoYDEgLyBtYXNzYCkuXFxuICAgICAqXFxuICAgICAqIEByZWFkT25seVxcbiAgICAgKiBAcHJvcGVydHkgaW52ZXJzZU1hc3NcXG4gICAgICogQHR5cGUgbnVtYmVyXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogX1JlYWQgb25seV8uIEF1dG9tYXRpY2FsbHkgY2FsY3VsYXRlZCB3aGVuIHZlcnRpY2VzLCBtYXNzIG9yIGRlbnNpdHkgYXJlIHNldCBvciBzZXQgdGhyb3VnaCBgQm9keS5zZXRJbmVydGlhYC5cXG4gICAgICogXFxuICAgICAqIEEgYE51bWJlcmAgdGhhdCBkZWZpbmVzIHRoZSBtb21lbnQgb2YgaW5lcnRpYSBvZiB0aGUgYm9keS4gVGhpcyBpcyB0aGUgc2Vjb25kIG1vbWVudCBvZiBhcmVhIGluIHR3byBkaW1lbnNpb25zLlxcbiAgICAgKiBcXG4gICAgICogQ2FuIGJlIG1hbnVhbGx5IHNldCB0byBgSW5maW5pdHlgIHRvIHByZXZlbnQgcm90YXRpb24gb2YgdGhlIGJvZHkuIFNlZSBgQm9keS5zZXRJbmVydGlhYC5cXG4gICAgICogXFxuICAgICAqIEByZWFkT25seVxcbiAgICAgKiBAcHJvcGVydHkgaW5lcnRpYVxcbiAgICAgKiBAdHlwZSBudW1iZXJcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBfUmVhZCBvbmx5Xy4gQXV0b21hdGljYWxseSBjYWxjdWxhdGVkIHdoZW4gdmVydGljZXMsIG1hc3Mgb3IgZGVuc2l0eSBhcmUgc2V0IG9yIGNhbGN1bGF0ZWQgYnkgYEJvZHkuc2V0SW5lcnRpYWAuXFxuICAgICAqIFxcbiAgICAgKiBBIGBOdW1iZXJgIHRoYXQgZGVmaW5lcyB0aGUgaW52ZXJzZSBtb21lbnQgb2YgaW5lcnRpYSBvZiB0aGUgYm9keSAoYDEgLyBpbmVydGlhYCkuXFxuICAgICAqIFxcbiAgICAgKiBAcmVhZE9ubHlcXG4gICAgICogQHByb3BlcnR5IGludmVyc2VJbmVydGlhXFxuICAgICAqIEB0eXBlIG51bWJlclxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEEgYE51bWJlcmAgdGhhdCBkZWZpbmVzIHRoZSByZXN0aXR1dGlvbiAoZWxhc3RpY2l0eSkgb2YgdGhlIGJvZHkuIFRoZSB2YWx1ZSBpcyBhbHdheXMgcG9zaXRpdmUgYW5kIGlzIGluIHRoZSByYW5nZSBgKDAsIDEpYC5cXG4gICAgICogQSB2YWx1ZSBvZiBgMGAgbWVhbnMgY29sbGlzaW9ucyBtYXkgYmUgcGVyZmVjdGx5IGluZWxhc3RpYyBhbmQgbm8gYm91bmNpbmcgbWF5IG9jY3VyLiBcXG4gICAgICogQSB2YWx1ZSBvZiBgMC44YCBtZWFucyB0aGUgYm9keSBtYXkgYm91bmNlIGJhY2sgd2l0aCBhcHByb3hpbWF0ZWx5IDgwJSBvZiBpdHMga2luZXRpYyBlbmVyZ3kuXFxuICAgICAqIE5vdGUgdGhhdCBjb2xsaXNpb24gcmVzcG9uc2UgaXMgYmFzZWQgb24gX3BhaXJzXyBvZiBib2RpZXMsIGFuZCB0aGF0IGByZXN0aXR1dGlvbmAgdmFsdWVzIGFyZSBfY29tYmluZWRfIHdpdGggdGhlIGZvbGxvd2luZyBmb3JtdWxhOlxcbiAgICAgKlxcbiAgICAgKiBgTWF0aC5tYXgoYm9keUEucmVzdGl0dXRpb24sIGJvZHlCLnJlc3Rp
2dHV0aW9uKWBcXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IHJlc3RpdHV0aW9uXFxuICAgICAqIEB0eXBlIG51bWJlclxcbiAgICAgKiBAZGVmYXVsdCAwXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBgTnVtYmVyYCB0aGF0IGRlZmluZXMgdGhlIGZyaWN0aW9uIG9mIHRoZSBib2R5LiBUaGUgdmFsdWUgaXMgYWx3YXlzIHBvc2l0aXZlIGFuZCBpcyBpbiB0aGUgcmFuZ2UgYCgwLCAxKWAuXFxuICAgICAqIEEgdmFsdWUgb2YgYDBgIG1lYW5zIHRoYXQgdGhlIGJvZHkgbWF5IHNsaWRlIGluZGVmaW5pdGVseS5cXG4gICAgICogQSB2YWx1ZSBvZiBgMWAgbWVhbnMgdGhlIGJvZHkgbWF5IGNvbWUgdG8gYSBzdG9wIGFsbW9zdCBpbnN0YW50bHkgYWZ0ZXIgYSBmb3JjZSBpcyBhcHBsaWVkLlxcbiAgICAgKlxcbiAgICAgKiBUaGUgZWZmZWN0cyBvZiB0aGUgdmFsdWUgbWF5IGJlIG5vbi1saW5lYXIuIFxcbiAgICAgKiBIaWdoIHZhbHVlcyBtYXkgYmUgdW5zdGFibGUgZGVwZW5kaW5nIG9uIHRoZSBib2R5LlxcbiAgICAgKiBUaGUgZW5naW5lIHVzZXMgYSBDb3Vsb21iIGZyaWN0aW9uIG1vZGVsIGluY2x1ZGluZyBzdGF0aWMgYW5kIGtpbmV0aWMgZnJpY3Rpb24uXFxuICAgICAqIE5vdGUgdGhhdCBjb2xsaXNpb24gcmVzcG9uc2UgaXMgYmFzZWQgb24gX3BhaXJzXyBvZiBib2RpZXMsIGFuZCB0aGF0IGBmcmljdGlvbmAgdmFsdWVzIGFyZSBfY29tYmluZWRfIHdpdGggdGhlIGZvbGxvd2luZyBmb3JtdWxhOlxcbiAgICAgKlxcbiAgICAgKiBgTWF0aC5taW4oYm9keUEuZnJpY3Rpb24sIGJvZHlCLmZyaWN0aW9uKWBcXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IGZyaWN0aW9uXFxuICAgICAqIEB0eXBlIG51bWJlclxcbiAgICAgKiBAZGVmYXVsdCAwLjFcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGBOdW1iZXJgIHRoYXQgZGVmaW5lcyB0aGUgc3RhdGljIGZyaWN0aW9uIG9mIHRoZSBib2R5IChpbiB0aGUgQ291bG9tYiBmcmljdGlvbiBtb2RlbCkuIFxcbiAgICAgKiBBIHZhbHVlIG9mIGAwYCBtZWFucyB0aGUgYm9keSB3aWxsIG5ldmVyICdzdGljaycgd2hlbiBpdCBpcyBuZWFybHkgc3RhdGlvbmFyeSBhbmQgb25seSBkeW5hbWljIGBmcmljdGlvbmAgaXMgdXNlZC5cXG4gICAgICogVGhlIGhpZ2hlciB0aGUgdmFsdWUgKGUuZy4gYDEwYCksIHRoZSBtb3JlIGZvcmNlIGl0IHdpbGwgdGFrZSB0byBpbml0aWFsbHkgZ2V0IHRoZSBib2R5IG1vdmluZyB3aGVuIG5lYXJseSBzdGF0aW9uYXJ5LlxcbiAgICAgKiBUaGlzIHZhbHVlIGlzIG11bHRpcGxpZWQgd2l0aCB0aGUgYGZyaWN0aW9uYCBwcm9wZXJ0eSB0byBtYWtlIGl0IGVhc2llciB0byBjaGFuZ2UgYGZyaWN0aW9uYCBhbmQgbWFpbnRhaW4gYW4gYXBwcm9wcmlhdGUgYW1vdW50IG9mIHN0YXRpYyBmcmljdGlvbi5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IGZyaWN0aW9uU3RhdGljXFxuICAgICAqIEB0eXBlIG51bWJlclxcbiAgICAgKiBAZGVmYXVsdCAwLjVcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGBOdW1iZXJgIHRoYXQgZGVmaW5lcyB0aGUgYWlyIGZyaWN0aW9uIG9mIHRoZSBib2R5IChhaXIgcmVzaXN0YW5jZSkuIFxcbiAgICAgKiBBIHZhbHVlIG9mIGAwYCBtZWFucyB0aGUgYm9keSB3aWxsIG5ldmVyIHNsb3cgYXMgaXQgbW92ZXMgdGhyb3VnaCBzcGFjZS5cXG4gICAgICogVGhlIGhpZ2hlciB0aGUgdmFsdWUsIHRoZSBmYXN0ZXIgYSBib2R5IHNsb3dzIHdoZW4gbW92aW5nIHRocm91Z2ggc3BhY2UuXFxuICAgICAqIFRoZSBlZmZlY3RzIG9mIHRoZSB2YWx1ZSBhcmUgbm9uLWxpbmVhci4gXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBmcmljdGlvbkFpclxcbiAgICAgKiBAdHlwZSBudW1iZXJcXG4gICAgICogQGRlZmF1bHQgMC4wMVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEFuIGBPYmplY3RgIHRoYXQgc3BlY2lmaWVzIHRoZSBjb2xsaXNpb24gZmlsdGVyaW5nIHByb3BlcnRpZXMgb2YgdGhpcyBib2R5LlxcbiAgICAgKlxcbiAgICAgKiBDb2xsaXNpb25zIGJldHdlZW4gdHdvIGJvZGllcyB3aWxsIG9iZXkgdGhlIGZvbGxvd2luZyBydWxlczpcXG4gICAgICogLSBJZiB0aGUgdHdvIGJvZGllcyBoYXZlIHRoZSBzYW1lIG5vbi16ZXJvIHZhbHVlIG9mIGBjb2xsaXNpb25GaWx0ZXIuZ3JvdXBgLFxcbiAgICAgKiAgIHRoZXkgd2lsbCBhbHdheXMgY29sbGlkZSBpZiB0aGUgdmFsdWUgaXMgcG9zaXRpdmUsIGFuZCB0aGV5IHdpbGwgbmV2ZXIgY29sbGlkZVxcbiAgICAgKiAgIGlmIHRoZSB2YWx1ZSBpcyBuZWdhdGl2ZS5cXG4gICAgICogLSBJZiB0aGUgdHdvIGJvZGllcyBoYXZlIGRpZmZlcmVudCB2YWx1ZXMgb2YgYGNvbGxpc2lvbkZpbHRlci5ncm91cGAgb3IgaWYgb25lXFxuICAgICAqICAgKG9yIGJvdGgpIG9mIHRoZSBib2RpZXMgaGFzIGEgdmFsdWUgb2YgMCwgdGhlbiB0aGUgY2F0ZWdvcnkvbWFzayBydWxlcyBhcHBseSBhcyBmb2xsb3dzOlxcbiAgICAgKlxcbiAgICAgKiBFYWNoIGJvZHkgYmVsb25ncyB0byBhIGNvbGxpc2lvbiBjYXRlZ29yeSwgZ2l2ZW4gYnkgYGNvbGxpc2lvbkZpbHRlci5jYXRlZ29yeWAuIFRoaXNcXG4gICAgICogdmFsdWUgaXMgdXNlZCBhcyBhIGJpdCBmaWVsZCBhbmQgdGhlIGNhdGVnb3J5IHNob3VsZCBoYXZlIG9ubHkgb25lIGJpdCBzZXQsIG1lYW5pbmcgdGhhdFxcbiAgICAgKiB0aGUgdmFsdWUgb2YgdGhpcyBwcm9wZXJ0eSBpcyBhIHBvd2VyIG9mIHR3byBpbiB0aGUgcmFuZ2UgWzEsIDJeMzFdLiBUaHVzLCB0aGVyZSBhcmUgMzJcXG4gICAgICogZGlmZmVyZW50IGNvbGxpc2lvbiBjYXRlZ29yaWVzIGF2YWlsYWJsZS5cXG4gICAgICpcXG4gICAgICogRWFjaCBib2R5IGFsc28gZGVmaW5lcyBhIGNvbGxpc2lvbiBiaXRtYXNrLCBnaXZlbiBieSBgY29sbGlzaW9uRmlsdGVyLm1hc2tgIHdoaWNoIHNwZWNpZmllc1xcbiAgICAgKiB0aGUgY2F0ZWdvcmllcyBpdCBjb2xsaWRlcyB3aXRoICh0aGUgdmFsdWUgaXMgdGhlIGJpdHdpc2UgQU5EIHZhbHVlIG9mIGFsbCB0aGVzZSBjYXRlZ29yaWVzKS5cXG4gICAgICpcXG4gICAgICogVXNpbmcgdGhlIGNhdGVnb3J5L21hc2sgcnVsZXMsIHR3byBib2RpZXMgYEFgIGFuZCBgQmAgY29sbGlkZSBpZiBlYWNoIGluY2x1ZGVzIHRoZSBvdGhlcidzXFxuICAgICAqIGNhdGVnb3J5IGluIGl0cyBtYXNrLCBpLmUuIGAoY2F0ZWdvcnlBICYgbWFza0IpICE9PSAwYCBhbmQgYChjYXRlZ29yeUIgJiBtYXNrQSkgIT09IDBgXFxuICAgICAqIGFyZSBib3RoIHRydWUuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBjb2xsaXNpb25GaWx0ZXJcXG4gICAgICogQHR5cGUgb2JqZWN0XFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQW4gSW50ZWdlciBgTnVtYmVyYCwgdGhhdCBzcGVjaWZpZXMgdGhlIGNvbGxpc2lvbiBncm91cCB0aGlzIGJvZHkgYmVsb25ncyB0by5cXG4gICAgICogU2VlIGBib2R5LmNvbGxpc2lvbkZpbHRlcmAgZm9yIG1vcmUgaW5mb3JtYXRpb24uXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBjb2xsaXNpb25GaWx0ZXIuZ3JvdXBcXG4gICAgICogQHR5cGUgb2JqZWN0XFxuICAgICAqIEBkZWZhdWx0IDBcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGJpdCBmaWVsZCB0aGF0IHNwZWNpZmllcyB0aGUgY29sbGlzaW9uIGNhdGVnb3J5IHRoaXMgYm9keSBiZWxvbmdzIHRvLlxcbiAgICAgKiBUaGUgY2F0ZWdvcnkgdmFsdWUgc2hvdWxkIGhh
2dmUgb25seSBvbmUgYml0IHNldCwgZm9yIGV4YW1wbGUgYDB4MDAwMWAuXFxuICAgICAqIFRoaXMgbWVhbnMgdGhlcmUgYXJlIHVwIHRvIDMyIHVuaXF1ZSBjb2xsaXNpb24gY2F0ZWdvcmllcyBhdmFpbGFibGUuXFxuICAgICAqIFNlZSBgYm9keS5jb2xsaXNpb25GaWx0ZXJgIGZvciBtb3JlIGluZm9ybWF0aW9uLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgY29sbGlzaW9uRmlsdGVyLmNhdGVnb3J5XFxuICAgICAqIEB0eXBlIG9iamVjdFxcbiAgICAgKiBAZGVmYXVsdCAxXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBiaXQgbWFzayB0aGF0IHNwZWNpZmllcyB0aGUgY29sbGlzaW9uIGNhdGVnb3JpZXMgdGhpcyBib2R5IG1heSBjb2xsaWRlIHdpdGguXFxuICAgICAqIFNlZSBgYm9keS5jb2xsaXNpb25GaWx0ZXJgIGZvciBtb3JlIGluZm9ybWF0aW9uLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgY29sbGlzaW9uRmlsdGVyLm1hc2tcXG4gICAgICogQHR5cGUgb2JqZWN0XFxuICAgICAqIEBkZWZhdWx0IC0xXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBgTnVtYmVyYCB0aGF0IHNwZWNpZmllcyBhIHRoaW4gYm91bmRhcnkgYXJvdW5kIHRoZSBib2R5IHdoZXJlIGl0IGlzIGFsbG93ZWQgdG8gc2xpZ2h0bHkgc2luayBpbnRvIG90aGVyIGJvZGllcy5cXG4gICAgICogXFxuICAgICAqIFRoaXMgaXMgcmVxdWlyZWQgZm9yIHByb3BlciBjb2xsaXNpb24gcmVzcG9uc2UsIGluY2x1ZGluZyBmcmljdGlvbiBhbmQgcmVzdGl0dXRpb24gZWZmZWN0cy5cXG4gICAgICogXFxuICAgICAqIFRoZSBkZWZhdWx0IHNob3VsZCBnZW5lcmFsbHkgc3VmZmljZSBpbiBtb3N0IGNhc2VzLiBZb3UgbWF5IG5lZWQgdG8gZGVjcmVhc2UgdGhpcyB2YWx1ZSBmb3IgdmVyeSBzbWFsbCBib2RpZXMgdGhhdCBhcmUgbmVhcmluZyB0aGUgZGVmYXVsdCB2YWx1ZSBpbiBzY2FsZS5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IHNsb3BcXG4gICAgICogQHR5cGUgbnVtYmVyXFxuICAgICAqIEBkZWZhdWx0IDAuMDVcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGBOdW1iZXJgIHRoYXQgc3BlY2lmaWVzIHBlci1ib2R5IHRpbWUgc2NhbGluZy5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IHRpbWVTY2FsZVxcbiAgICAgKiBAdHlwZSBudW1iZXJcXG4gICAgICogQGRlZmF1bHQgMVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIF9SZWFkIG9ubHlfLiBVcGRhdGVkIGR1cmluZyBlbmdpbmUgdXBkYXRlLlxcbiAgICAgKiBcXG4gICAgICogQSBgTnVtYmVyYCB0aGF0IHJlY29yZHMgdGhlIGxhc3QgZGVsdGEgdGltZSB2YWx1ZSB1c2VkIHRvIHVwZGF0ZSB0aGlzIGJvZHkuXFxuICAgICAqIFVzZWQgdG8gY2FsY3VsYXRlIHNwZWVkIGFuZCB2ZWxvY2l0eS5cXG4gICAgICpcXG4gICAgICogQHJlYWRPbmx5XFxuICAgICAqIEBwcm9wZXJ0eSBkZWx0YVRpbWVcXG4gICAgICogQHR5cGUgbnVtYmVyXFxuICAgICAqIEBkZWZhdWx0IDEwMDAgLyA2MFxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEFuIGBPYmplY3RgIHRoYXQgZGVmaW5lcyB0aGUgcmVuZGVyaW5nIHByb3BlcnRpZXMgdG8gYmUgY29uc3VtZWQgYnkgdGhlIG1vZHVsZSBgTWF0dGVyLlJlbmRlcmAuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSByZW5kZXJcXG4gICAgICogQHR5cGUgb2JqZWN0XFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBmbGFnIHRoYXQgaW5kaWNhdGVzIGlmIHRoZSBib2R5IHNob3VsZCBiZSByZW5kZXJlZC5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IHJlbmRlci52aXNpYmxlXFxuICAgICAqIEB0eXBlIGJvb2xlYW5cXG4gICAgICogQGRlZmF1bHQgdHJ1ZVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIFNldHMgdGhlIG9wYWNpdHkgdG8gdXNlIHdoZW4gcmVuZGVyaW5nLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgcmVuZGVyLm9wYWNpdHlcXG4gICAgICogQHR5cGUgbnVtYmVyXFxuICAgICAqIEBkZWZhdWx0IDFcXG4gICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEFuIGBPYmplY3RgIHRoYXQgZGVmaW5lcyB0aGUgc3ByaXRlIHByb3BlcnRpZXMgdG8gdXNlIHdoZW4gcmVuZGVyaW5nLCBpZiBhbnkuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSByZW5kZXIuc3ByaXRlXFxuICAgICAqIEB0eXBlIG9iamVjdFxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEFuIGBTdHJpbmdgIHRoYXQgZGVmaW5lcyB0aGUgcGF0aCB0byB0aGUgaW1hZ2UgdG8gdXNlIGFzIHRoZSBzcHJpdGUgdGV4dHVyZSwgaWYgYW55LlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgcmVuZGVyLnNwcml0ZS50ZXh0dXJlXFxuICAgICAqIEB0eXBlIHN0cmluZ1xcbiAgICAgKi9cXG4gICAgIFxcbiAgICAvKipcXG4gICAgICogQSBgTnVtYmVyYCB0aGF0IGRlZmluZXMgdGhlIHNjYWxpbmcgaW4gdGhlIHgtYXhpcyBmb3IgdGhlIHNwcml0ZSwgaWYgYW55LlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgcmVuZGVyLnNwcml0ZS54U2NhbGVcXG4gICAgICogQHR5cGUgbnVtYmVyXFxuICAgICAqIEBkZWZhdWx0IDFcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGBOdW1iZXJgIHRoYXQgZGVmaW5lcyB0aGUgc2NhbGluZyBpbiB0aGUgeS1heGlzIGZvciB0aGUgc3ByaXRlLCBpZiBhbnkuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSByZW5kZXIuc3ByaXRlLnlTY2FsZVxcbiAgICAgKiBAdHlwZSBudW1iZXJcXG4gICAgICogQGRlZmF1bHQgMVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAgKiBBIGBOdW1iZXJgIHRoYXQgZGVmaW5lcyB0aGUgb2Zmc2V0IGluIHRoZSB4LWF4aXMgZm9yIHRoZSBzcHJpdGUgKG5vcm1hbGlzZWQgYnkgdGV4dHVyZSB3aWR0aCkuXFxuICAgICAgKlxcbiAgICAgICogQHByb3BlcnR5IHJlbmRlci5zcHJpdGUueE9mZnNldFxcbiAgICAgICogQHR5cGUgbnVtYmVyXFxuICAgICAgKiBAZGVmYXVsdCAwXFxuICAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAgKiBBIGBOdW1iZXJgIHRoYXQgZGVmaW5lcyB0aGUgb2Zmc2V0IGluIHRoZSB5LWF4aXMgZm9yIHRoZSBzcHJpdGUgKG5vcm1hbGlzZWQgYnkgdGV4dHVyZSBoZWlnaHQpLlxcbiAgICAgICpcXG4gICAgICAqIEBwcm9wZXJ0eSByZW5kZXIuc3ByaXRlLnlPZmZzZXRcXG4gICAgICAqIEB0eXBlIG51bWJlclxcbiAgICAgICogQGRlZmF1bHQgMFxcbiAgICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGBOdW1iZXJgIHRoYXQgZGVmaW5lcyB0aGUgbGluZSB3aWR0aCB0byB1c2Ugd2hlbiByZW5kZXJpbmcgdGhlIGJvZHkgb3V0bGluZSAoaWYgYSBzcHJpdGUgaXMgbm90IGRlZmluZWQpLlxcbiAgICAgKiBBIHZhbHVlIG9mIGAwYCBtZWFucyBubyBvdXRsaW5lIHdpbGwgYmUgcmVuZGVyZWQuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSByZW5kZXIubGluZVdpZHRoXFxuICAgICAqIEB0eXBlIG51bWJlclxcbiAgICAgKiBAZGVmYXVsdCAwXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBgU3RyaW5nYCB0aGF0IGRlZmluZXMgdGhlIGZpbGwgc3R5bGUgdG8gdXNlIHdoZW4gcmVuZGVyaW5nIHRoZSBib2R5IChpZiBhIHNwcml0ZSBpcyBub3QgZGVmaW5lZCkuXFxuICAgICAqIEl0IGlzIHRoZSBzYW1lIGFzIHdoZW4gdXNpbmcgYSBjYW52YXMsIHNvIGl0IGFjY2VwdHMgQ1NTIHN0eWxlIHByb3BlcnR5IHZhbHVlcy5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IHJlbmRlci5maWxsU3R5bGVcXG4gICAgICogQHR5cGUgc3RyaW5nXFxuICAgICAqIEBkZWZhdWx0IGEgcmFuZG9tIGNvbG91clxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEEgYFN0cmluZ2AgdGhhdCBkZWZpbmVzIHRoZSBzdHJva2Ugc3R5bGUgdG8gdXNlIHdoZW4gcmVuZGVyaW5nIHRoZSBib2R5IG91dGxpbmUgKGlmIGEgc3ByaXRlIGlzIG5vdCBkZWZpbmVkKS5cXG4gICAgICogSXQgaXMgdGhlIHNhbWUgYXMgd2hlbiB1c2luZyBhIGNhbnZhcywgc28gaXQgYWNjZXB0cyBDU1Mgc3R5bGUgcHJvcGVydHkgdmFsdWVzLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgcmVuZGVyLnN0cm9rZVN0eWxlXFxuICAgICAqIEB0eXBlIHN0cmluZ1xcbiAgICAgKiBAZGVmYXVsdCBhIHJhbmRvbSBjb2xvdXJcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBfUmVhZCBvbmx5Xy4gQ2FsY3VsYXRlZCBhdXRvbWF0aWNhbGx5IHdoZW4gdmVydGljZXMgYXJlIHNldC5cXG4gICAgICogXFxuICAgICAqIEFuIGFycmF5IG9mIHVuaXF1ZSBheGlzIHZlY3RvcnMgKG
2VkZ2Ugbm9ybWFscykgdXNlZCBmb3IgY29sbGlzaW9uIGRldGVjdGlvbi5cXG4gICAgICogVGhlc2UgYXJlIGF1dG9tYXRpY2FsbHkgY2FsY3VsYXRlZCB3aGVuIHZlcnRpY2VzIGFyZSBzZXQuXFxuICAgICAqIFRoZXkgYXJlIGNvbnN0YW50bHkgdXBkYXRlZCBieSBgQm9keS51cGRhdGVgIGR1cmluZyB0aGUgc2ltdWxhdGlvbi5cXG4gICAgICpcXG4gICAgICogQHJlYWRPbmx5XFxuICAgICAqIEBwcm9wZXJ0eSBheGVzXFxuICAgICAqIEB0eXBlIHZlY3RvcltdXFxuICAgICAqL1xcbiAgICAgXFxuICAgIC8qKlxcbiAgICAgKiBfUmVhZCBvbmx5Xy4gQ2FsY3VsYXRlZCBhdXRvbWF0aWNhbGx5IHdoZW4gdmVydGljZXMgYXJlIHNldC5cXG4gICAgICogXFxuICAgICAqIEEgYE51bWJlcmAgdGhhdCBtZWFzdXJlcyB0aGUgYXJlYSBvZiB0aGUgYm9keSdzIGNvbnZleCBodWxsLlxcbiAgICAgKiBcXG4gICAgICogQHJlYWRPbmx5XFxuICAgICAqIEBwcm9wZXJ0eSBhcmVhXFxuICAgICAqIEB0eXBlIHN0cmluZ1xcbiAgICAgKiBAZGVmYXVsdCBcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGBCb3VuZHNgIG9iamVjdCB0aGF0IGRlZmluZXMgdGhlIEFBQkIgcmVnaW9uIGZvciB0aGUgYm9keS5cXG4gICAgICogSXQgaXMgYXV0b21hdGljYWxseSBjYWxjdWxhdGVkIHdoZW4gdmVydGljZXMgYXJlIHNldCBhbmQgY29uc3RhbnRseSB1cGRhdGVkIGJ5IGBCb2R5LnVwZGF0ZWAgZHVyaW5nIHNpbXVsYXRpb24uXFxuICAgICAqIFxcbiAgICAgKiBAcHJvcGVydHkgYm91bmRzXFxuICAgICAqIEB0eXBlIGJvdW5kc1xcbiAgICAgKi9cXG5cXG59KSgpO1xcblxcblxcbi8qKiovIH0pLFxcbi8qIDUgKi9cXG4vKioqLyAoZnVuY3Rpb24obW9kdWxlLCBleHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XFxuXFxuLyoqXFxuKiBUaGUgYE1hdHRlci5FdmVudHNgIG1vZHVsZSBjb250YWlucyBtZXRob2RzIHRvIGZpcmUgYW5kIGxpc3RlbiB0byBldmVudHMgb24gb3RoZXIgb2JqZWN0cy5cXG4qXFxuKiBTZWUgdGhlIGluY2x1ZGVkIHVzYWdlIFtleGFtcGxlc10oaHR0cHM6Ly9naXRodWIuY29tL2xpYWJydS9tYXR0ZXItanMvdHJlZS9tYXN0ZXIvZXhhbXBsZXMpLlxcbipcXG4qIEBjbGFzcyBFdmVudHNcXG4qL1xcblxcbnZhciBFdmVudHMgPSB7fTtcXG5cXG5tb2R1bGUuZXhwb3J0cyA9IEV2ZW50cztcXG5cXG52YXIgQ29tbW9uID0gX193ZWJwYWNrX3JlcXVpcmVfXygwKTtcXG5cXG4oZnVuY3Rpb24oKSB7XFxuXFxuICAgIC8qKlxcbiAgICAgKiBTdWJzY3JpYmVzIGEgY2FsbGJhY2sgZnVuY3Rpb24gdG8gdGhlIGdpdmVuIG9iamVjdCdzIGBldmVudE5hbWVgLlxcbiAgICAgKiBAbWV0aG9kIG9uXFxuICAgICAqIEBwYXJhbSB7fSBvYmplY3RcXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZXNcXG4gICAgICogQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2tcXG4gICAgICovXFxuICAgIEV2ZW50cy5vbiA9IGZ1bmN0aW9uKG9iamVjdCwgZXZlbnROYW1lcywgY2FsbGJhY2spIHtcXG4gICAgICAgIHZhciBuYW1lcyA9IGV2ZW50TmFtZXMuc3BsaXQoJyAnKSxcXG4gICAgICAgICAgICBuYW1lO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBuYW1lcy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIG5hbWUgPSBuYW1lc1tpXTtcXG4gICAgICAgICAgICBvYmplY3QuZXZlbnRzID0gb2JqZWN0LmV2ZW50cyB8fCB7fTtcXG4gICAgICAgICAgICBvYmplY3QuZXZlbnRzW25hbWVdID0gb2JqZWN0LmV2ZW50c1tuYW1lXSB8fCBbXTtcXG4gICAgICAgICAgICBvYmplY3QuZXZlbnRzW25hbWVdLnB1c2goY2FsbGJhY2spO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgcmV0dXJuIGNhbGxiYWNrO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmVtb3ZlcyB0aGUgZ2l2ZW4gZXZlbnQgY2FsbGJhY2suIElmIG5vIGNhbGxiYWNrLCBjbGVhcnMgYWxsIGNhbGxiYWNrcyBpbiBgZXZlbnROYW1lc2AuIElmIG5vIGBldmVudE5hbWVzYCwgY2xlYXJzIGFsbCBldmVudHMuXFxuICAgICAqIEBtZXRob2Qgb2ZmXFxuICAgICAqIEBwYXJhbSB7fSBvYmplY3RcXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZXNcXG4gICAgICogQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2tcXG4gICAgICovXFxuICAgIEV2ZW50cy5vZmYgPSBmdW5jdGlvbihvYmplY3QsIGV2ZW50TmFtZXMsIGNhbGxiYWNrKSB7XFxuICAgICAgICBpZiAoIWV2ZW50TmFtZXMpIHtcXG4gICAgICAgICAgICBvYmplY3QuZXZlbnRzID0ge307XFxuICAgICAgICAgICAgcmV0dXJuO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgLy8gaGFuZGxlIEV2ZW50cy5vZmYob2JqZWN0LCBjYWxsYmFjaylcXG4gICAgICAgIGlmICh0eXBlb2YgZXZlbnROYW1lcyA9PT0gJ2Z1bmN0aW9uJykge1xcbiAgICAgICAgICAgIGNhbGxiYWNrID0gZXZlbnROYW1lcztcXG4gICAgICAgICAgICBldmVudE5hbWVzID0gQ29tbW9uLmtleXMob2JqZWN0LmV2ZW50cykuam9pbignICcpO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgdmFyIG5hbWVzID0gZXZlbnROYW1lcy5zcGxpdCgnICcpO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBuYW1lcy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHZhciBjYWxsYmFja3MgPSBvYmplY3QuZXZlbnRzW25hbWVzW2ldXSxcXG4gICAgICAgICAgICAgICAgbmV3Q2FsbGJhY2tzID0gW107XFxuXFxuICAgICAgICAgICAgaWYgKGNhbGxiYWNrICYmIGNhbGxiYWNrcykge1xcbiAgICAgICAgICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGNhbGxiYWNrcy5sZW5ndGg7IGorKykge1xcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNhbGxiYWNrc1tqXSAhPT0gY2FsbGJhY2spXFxuICAgICAgICAgICAgICAgICAgICAgICAgbmV3Q2FsbGJhY2tzLnB1c2goY2FsbGJhY2tzW2pdKTtcXG4gICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICBvYmplY3QuZXZlbnRzW25hbWVzW2ldXSA9IG5ld0NhbGxiYWNrcztcXG4gICAgICAgIH1cXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIEZpcmVzIGFsbCB0aGUgY2FsbGJhY2tzIHN1YnNjcmliZWQgdG8gdGhlIGdpdmVuIG9iamVjdCdzIGBldmVudE5hbWVgLCBpbiB0aGUgb3JkZXIgdGhleSBzdWJzY3JpYmVkLCBpZiBhbnkuXFxuICAgICAqIEBtZXRob2QgdHJpZ2dlclxcbiAgICAgKiBAcGFyYW0ge30gb2JqZWN0XFxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudE5hbWVzXFxuICAgICAqIEBwYXJhbSB7fSBldmVudFxcbiAgICAgKi9cXG4gICAgRXZlbnRzLnRyaWdnZXIgPSBmdW5jdGlvbihvYmplY3QsIGV2ZW50TmFtZXMsIGV2ZW50KSB7XFxuICAgICAgICB2Y
2XIgbmFtZXMsXFxuICAgICAgICAgICAgbmFtZSxcXG4gICAgICAgICAgICBjYWxsYmFja3MsXFxuICAgICAgICAgICAgZXZlbnRDbG9uZTtcXG5cXG4gICAgICAgIHZhciBldmVudHMgPSBvYmplY3QuZXZlbnRzO1xcbiAgICAgICAgXFxuICAgICAgICBpZiAoZXZlbnRzICYmIENvbW1vbi5rZXlzKGV2ZW50cykubGVuZ3RoID4gMCkge1xcbiAgICAgICAgICAgIGlmICghZXZlbnQpXFxuICAgICAgICAgICAgICAgIGV2ZW50ID0ge307XFxuXFxuICAgICAgICAgICAgbmFtZXMgPSBldmVudE5hbWVzLnNwbGl0KCcgJyk7XFxuXFxuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBuYW1lcy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgICAgICBuYW1lID0gbmFtZXNbaV07XFxuICAgICAgICAgICAgICAgIGNhbGxiYWNrcyA9IGV2ZW50c1tuYW1lXTtcXG5cXG4gICAgICAgICAgICAgICAgaWYgKGNhbGxiYWNrcykge1xcbiAgICAgICAgICAgICAgICAgICAgZXZlbnRDbG9uZSA9IENvbW1vbi5jbG9uZShldmVudCwgZmFsc2UpO1xcbiAgICAgICAgICAgICAgICAgICAgZXZlbnRDbG9uZS5uYW1lID0gbmFtZTtcXG4gICAgICAgICAgICAgICAgICAgIGV2ZW50Q2xvbmUuc291cmNlID0gb2JqZWN0O1xcblxcbiAgICAgICAgICAgICAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBjYWxsYmFja3MubGVuZ3RoOyBqKyspIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICBjYWxsYmFja3Nbal0uYXBwbHkob2JqZWN0LCBbZXZlbnRDbG9uZV0pO1xcbiAgICAgICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgICAgICB9XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcbiAgICB9O1xcblxcbn0pKCk7XFxuXFxuXFxuLyoqKi8gfSksXFxuLyogNiAqL1xcbi8qKiovIChmdW5jdGlvbihtb2R1bGUsIGV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pIHtcXG5cXG4vKipcXG4qIEEgY29tcG9zaXRlIGlzIGEgY29sbGVjdGlvbiBvZiBgTWF0dGVyLkJvZHlgLCBgTWF0dGVyLkNvbnN0cmFpbnRgIGFuZCBvdGhlciBgTWF0dGVyLkNvbXBvc2l0ZWAgb2JqZWN0cy5cXG4qXFxuKiBUaGV5IGFyZSBhIGNvbnRhaW5lciB0aGF0IGNhbiByZXByZXNlbnQgY29tcGxleCBvYmplY3RzIG1hZGUgb2YgbXVsdGlwbGUgcGFydHMsIGV2ZW4gaWYgdGhleSBhcmUgbm90IHBoeXNpY2FsbHkgY29ubmVjdGVkLlxcbiogQSBjb21wb3NpdGUgY291bGQgY29udGFpbiBhbnl0aGluZyBmcm9tIGEgc2luZ2xlIGJvZHkgYWxsIHRoZSB3YXkgdXAgdG8gYSB3aG9sZSB3b3JsZC5cXG4qIFxcbiogV2hlbiBtYWtpbmcgYW55IGNoYW5nZXMgdG8gY29tcG9zaXRlcywgdXNlIHRoZSBpbmNsdWRlZCBmdW5jdGlvbnMgcmF0aGVyIHRoYW4gY2hhbmdpbmcgdGhlaXIgcHJvcGVydGllcyBkaXJlY3RseS5cXG4qXFxuKiBTZWUgdGhlIGluY2x1ZGVkIHVzYWdlIFtleGFtcGxlc10oaHR0cHM6Ly9naXRodWIuY29tL2xpYWJydS9tYXR0ZXItanMvdHJlZS9tYXN0ZXIvZXhhbXBsZXMpLlxcbipcXG4qIEBjbGFzcyBDb21wb3NpdGVcXG4qL1xcblxcbnZhciBDb21wb3NpdGUgPSB7fTtcXG5cXG5tb2R1bGUuZXhwb3J0cyA9IENvbXBvc2l0ZTtcXG5cXG52YXIgRXZlbnRzID0gX193ZWJwYWNrX3JlcXVpcmVfXyg1KTtcXG52YXIgQ29tbW9uID0gX193ZWJwYWNrX3JlcXVpcmVfXygwKTtcXG52YXIgQm91bmRzID0gX193ZWJwYWNrX3JlcXVpcmVfXygxKTtcXG52YXIgQm9keSA9IF9fd2VicGFja19yZXF1aXJlX18oNCk7XFxuXFxuKGZ1bmN0aW9uKCkge1xcblxcbiAgICAvKipcXG4gICAgICogQ3JlYXRlcyBhIG5ldyBjb21wb3NpdGUuIFRoZSBvcHRpb25zIHBhcmFtZXRlciBpcyBhbiBvYmplY3QgdGhhdCBzcGVjaWZpZXMgYW55IHByb3BlcnRpZXMgeW91IHdpc2ggdG8gb3ZlcnJpZGUgdGhlIGRlZmF1bHRzLlxcbiAgICAgKiBTZWUgdGhlIHByb3Blcml0ZXMgc2VjdGlvbiBiZWxvdyBmb3IgZGV0YWlsZWQgaW5mb3JtYXRpb24gb24gd2hhdCB5b3UgY2FuIHBhc3MgdmlhIHRoZSBgb3B0aW9uc2Agb2JqZWN0LlxcbiAgICAgKiBAbWV0aG9kIGNyZWF0ZVxcbiAgICAgKiBAcGFyYW0ge30gW29wdGlvbnNdXFxuICAgICAqIEByZXR1cm4ge2NvbXBvc2l0ZX0gQSBuZXcgY29tcG9zaXRlXFxuICAgICAqL1xcbiAgICBDb21wb3NpdGUuY3JlYXRlID0gZnVuY3Rpb24ob3B0aW9ucykge1xcbiAgICAgICAgcmV0dXJuIENvbW1vbi5leHRlbmQoeyBcXG4gICAgICAgICAgICBpZDogQ29tbW9uLm5leHRJZCgpLFxcbiAgICAgICAgICAgIHR5cGU6ICdjb21wb3NpdGUnLFxcbiAgICAgICAgICAgIHBhcmVudDogbnVsbCxcXG4gICAgICAgICAgICBpc01vZGlmaWVkOiBmYWxzZSxcXG4gICAgICAgICAgICBib2RpZXM6IFtdLCBcXG4gICAgICAgICAgICBjb25zdHJhaW50czogW10sIFxcbiAgICAgICAgICAgIGNvbXBvc2l0ZXM6IFtdLFxcbiAgICAgICAgICAgIGxhYmVsOiAnQ29tcG9zaXRlJyxcXG4gICAgICAgICAgICBwbHVnaW46IHt9LFxcbiAgICAgICAgICAgIGNhY2hlOiB7XFxuICAgICAgICAgICAgICAgIGFsbEJvZGllczogbnVsbCxcXG4gICAgICAgICAgICAgICAgYWxsQ29uc3RyYWludHM6IG51bGwsXFxuICAgICAgICAgICAgICAgIGFsbENvbXBvc2l0ZXM6IG51bGxcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9LCBvcHRpb25zKTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFNldHMgdGhlIGNvbXBvc2l0ZSdzIGBpc01vZGlmaWVkYCBmbGFnLiBcXG4gICAgICogSWYgYHVwZGF0ZVBhcmVudHNgIGlzIHRydWUsIGFsbCBwYXJlbnRzIHdpbGwgYmUgc2V0IChkZWZhdWx0OiBmYWxzZSkuXFxuICAgICAqIElmIGB1cGRhdGVDaGlsZHJlbmAgaXMgdHJ1ZSwgYWxsIGNoaWxkcmVuIHdpbGwgYmUgc2V0IChkZWZhdWx0OiBmYWxzZSkuXFxuICAgICAqIEBwcml2YXRlXFxuICAgICAqIEBtZXRob2Qgc2V0TW9kaWZpZWRcXG4gICAgICogQHBhcmFtIHtjb21wb3NpdGV9IGNvbXBvc2l0ZVxcbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IGlzTW9kaWZpZWRcXG4gICAgICogQHBhcmFtIHtib29sZWFufSBbdXBkYXRlUGFyZW50cz1mYWxzZV1cXG4gICAgICogQHBhcmFtIHtib29sZWFufSBbdXBkYXRlQ2hpbGRyZW49ZmFsc2VdXFxuICAgICAqL1xcbiAgICBDb21wb3NpdGUuc2V0TW9kaWZpZWQgPSBmdW5jdGlvbihjb21wb3NpdGUsIGlzTW9kaWZpZWQsIHVwZGF0ZVBhcmVudHMsIHVwZGF0ZUNoaWxkcmVuKSB7XFxuICAgICAgICBjb21wb3NpdGUuaXNNb2RpZmllZCA9IGlzTW9kaWZpZWQ7XFxuXFxuICAgICAgICBpZiAoaXNNb2RpZmllZCAmJiBjb21wb3NpdGUuY2FjaGUpIHtcXG4gICAgICAgICAgICBjb21wb3NpdGUuY2FjaGUuYWxsQm9kaWVzID0gbnVsbDtcXG4gICAgICAgICAgICBjb21wb3NpdGUuY2FjaGUuYWxsQ29uc3RyYWludHMgPSBudWxsO1xcbiAgICAgICAgICAgIGNvbXBvc2l0ZS5jYWNoZS5hbGxDb21wb3NpdGVzID0gbnVsbDtcXG4gICAgICAgI
2H1cXG5cXG4gICAgICAgIGlmICh1cGRhdGVQYXJlbnRzICYmIGNvbXBvc2l0ZS5wYXJlbnQpIHtcXG4gICAgICAgICAgICBDb21wb3NpdGUuc2V0TW9kaWZpZWQoY29tcG9zaXRlLnBhcmVudCwgaXNNb2RpZmllZCwgdXBkYXRlUGFyZW50cywgdXBkYXRlQ2hpbGRyZW4pO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgaWYgKHVwZGF0ZUNoaWxkcmVuKSB7XFxuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjb21wb3NpdGUuY29tcG9zaXRlcy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgICAgICB2YXIgY2hpbGRDb21wb3NpdGUgPSBjb21wb3NpdGUuY29tcG9zaXRlc1tpXTtcXG4gICAgICAgICAgICAgICAgQ29tcG9zaXRlLnNldE1vZGlmaWVkKGNoaWxkQ29tcG9zaXRlLCBpc01vZGlmaWVkLCB1cGRhdGVQYXJlbnRzLCB1cGRhdGVDaGlsZHJlbik7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogR2VuZXJpYyBzaW5nbGUgb3IgbXVsdGktYWRkIGZ1bmN0aW9uLiBBZGRzIGEgc2luZ2xlIG9yIGFuIGFycmF5IG9mIGJvZHkocyksIGNvbnN0cmFpbnQocykgb3IgY29tcG9zaXRlKHMpIHRvIHRoZSBnaXZlbiBjb21wb3NpdGUuXFxuICAgICAqIFRyaWdnZXJzIGBiZWZvcmVBZGRgIGFuZCBgYWZ0ZXJBZGRgIGV2ZW50cyBvbiB0aGUgYGNvbXBvc2l0ZWAuXFxuICAgICAqIEBtZXRob2QgYWRkXFxuICAgICAqIEBwYXJhbSB7Y29tcG9zaXRlfSBjb21wb3NpdGVcXG4gICAgICogQHBhcmFtIHtvYmplY3R8YXJyYXl9IG9iamVjdCBBIHNpbmdsZSBvciBhbiBhcnJheSBvZiBib2R5KHMpLCBjb25zdHJhaW50KHMpIG9yIGNvbXBvc2l0ZShzKVxcbiAgICAgKiBAcmV0dXJuIHtjb21wb3NpdGV9IFRoZSBvcmlnaW5hbCBjb21wb3NpdGUgd2l0aCB0aGUgb2JqZWN0cyBhZGRlZFxcbiAgICAgKi9cXG4gICAgQ29tcG9zaXRlLmFkZCA9IGZ1bmN0aW9uKGNvbXBvc2l0ZSwgb2JqZWN0KSB7XFxuICAgICAgICB2Y
2XIgb2JqZWN0cyA9IFtdLmNvbmNhdChvYmplY3QpO1xcblxcbiAgICAgICAgRXZlbnRzLnRyaWdnZXIoY29tcG9zaXRlLCAnYmVmb3JlQWRkJywgeyBvYmplY3Q6IG9iamVjdCB9KTtcXG5cXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgb2JqZWN0cy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHZhciBvYmogPSBvYmplY3RzW2ldO1xcblxcbiAgICAgICAgICAgIHN3aXRjaCAob2JqLnR5cGUpIHtcXG5cXG4gICAgICAgICAgICBjYXNlICdib2R5JzpcXG4gICAgICAgICAgICAgICAgLy8gc2tpcCBhZGRpbmcgY29tcG91bmQgcGFydHNcXG4gICAgICAgICAgICAgICAgaWYgKG9iai5wYXJlbnQgIT09IG9iaikge1xcbiAgICAgICAgICAgICAgICAgICAgQ29tbW9uLndhcm4oJ0NvbXBvc2l0ZS5hZGQ6IHNraXBwZWQgYWRkaW5nIGEgY29tcG91bmQgYm9keSBwYXJ0ICh5b3UgbXVzdCBhZGQgaXRzIHBhcmVudCBpbnN0ZWFkKScpO1xcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XFxuICAgICAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICAgICAgQ29tcG9zaXRlLmFkZEJvZHkoY29tcG9zaXRlLCBvYmopO1xcbiAgICAgICAgICAgICAgICBicmVhaztcXG4gICAgICAgICAgICBjYXNlICdjb25zdHJhaW50JzpcXG4gICAgICAgICAgICAgICAgQ29tcG9zaXRlLmFkZENvbnN0cmFpbnQoY29tcG9zaXRlLCBvYmopO1xcbiAgICAgICAgICAgICAgICBicmVhaztcXG4gICAgICAgICAgICBjYXNlICdjb21wb3NpdGUnOlxcbiAgICAgICAgICAgICAgICBDb21wb3NpdGUuYWRkQ29tcG9zaXRlKGNvbXBvc2l0ZSwgb2JqKTtcXG4gICAgICAgICAgICAgICAgYnJlYWs7XFxuICAgICAgICAgICAgY2FzZSAnbW91c2VDb25zdHJhaW50JzpcXG4gICAgICAgICAgICAgICAgQ29tcG9zaXRlLmFkZENvbnN0cmFpbnQoY29tcG9zaXRlLCBvYmouY29uc3RyYWludCk7XFxuICAgICAgICAgICAgICAgIGJyZWFrO1xcblxcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG5cXG4gICAgICAgIEV2ZW50cy50cmlnZ2VyKGNvbXBvc2l0ZSwgJ2FmdGVyQWRkJywgeyBvYmplY3Q6IG9iamVjdCB9KTtcXG5cXG4gICAgICAgIHJldHVybiBjb21wb3NpdGU7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBHZW5lcmljIHJlbW92ZSBmdW5jdGlvbi4gUmVtb3ZlcyBvbmUgb3IgbWFueSBib2R5KHMpLCBjb25zdHJhaW50KHMpIG9yIGEgY29tcG9zaXRlKHMpIHRvIHRoZSBnaXZlbiBjb21wb3NpdGUuXFxuICAgICAqIE9wdGlvbmFsbHkgc2VhcmNoaW5nIGl0cyBjaGlsZHJlbiByZWN1cnNpdmVseS5cXG4gICAgICogVHJpZ2dlcnMgYGJlZm9yZVJlbW92ZWAgYW5kIGBhZnRlclJlbW92ZWAgZXZlbnRzIG9uIHRoZSBgY29tcG9zaXRlYC5cXG4gICAgICogQG1ldGhvZCByZW1vdmVcXG4gICAgICogQHBhcmFtIHtjb21wb3NpdGV9IGNvbXBvc2l0ZVxcbiAgICAgKiBAcGFyYW0ge29iamVjdHxhcnJheX0gb2JqZWN0XFxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2RlZXA9ZmFsc2VdXFxuICAgICAqIEByZXR1cm4ge2NvbXBvc2l0ZX0gVGhlIG9yaWdpbmFsIGNvbXBvc2l0ZSB3aXRoIHRoZSBvYmplY3RzIHJlbW92ZWRcXG4gICAgICovXFxuICAgIENvbXBvc2l0ZS5yZW1vdmUgPSBmdW5jdGlvbihjb21wb3NpdGUsIG9iamVjdCwgZGVlcCkge1xcbiAgICAgICAgdmFyIG9iamVjdHMgPSBbXS5jb25jYXQob2JqZWN0KTtcXG5cXG4gICAgICAgIEV2ZW50cy50cmlnZ2VyKGNvbXBvc2l0ZSwgJ2JlZm9yZVJlbW92ZScsIHsgb2JqZWN0OiBvYmplY3QgfSk7XFxuXFxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG9iamVjdHMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICB2Y
2XIgb2JqID0gb2JqZWN0c1tpXTtcXG5cXG4gICAgICAgICAgICBzd2l0Y2ggKG9iai50eXBlKSB7XFxuXFxuICAgICAgICAgICAgY2FzZSAnYm9keSc6XFxuICAgICAgICAgICAgICAgIENvbXBvc2l0ZS5yZW1vdmVCb2R5KGNvbXBvc2l0ZSwgb2JqLCBkZWVwKTtcXG4gICAgICAgICAgICAgICAgYnJlYWs7XFxuICAgICAgICAgICAgY2FzZSAnY29uc3RyYWludCc6XFxuICAgICAgICAgICAgICAgIENvbXBvc2l0ZS5yZW1vdmVDb25zdHJhaW50KGNvbXBvc2l0ZSwgb2JqLCBkZWVwKTtcXG4gICAgICAgICAgICAgICAgYnJlYWs7XFxuICAgICAgICAgICAgY2FzZSAnY29tcG9zaXRlJzpcXG4gICAgICAgICAgICAgICAgQ29tcG9zaXRlLnJlbW92ZUNvbXBvc2l0ZShjb21wb3NpdGUsIG9iaiwgZGVlcCk7XFxuICAgICAgICAgICAgICAgIGJyZWFrO1xcbiAgICAgICAgICAgIGNhc2UgJ21vdXNlQ29uc3RyYWludCc6XFxuICAgICAgICAgICAgICAgIENvbXBvc2l0ZS5yZW1vdmVDb25zdHJhaW50KGNvbXBvc2l0ZSwgb2JqLmNvbnN0cmFpbnQpO1xcbiAgICAgICAgICAgICAgICBicmVhaztcXG5cXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuXFxuICAgICAgICBFdmVudHMudHJpZ2dlcihjb21wb3NpdGUsICdhZnRlclJlbW92ZScsIHsgb2JqZWN0OiBvYmplY3QgfSk7XFxuXFxuICAgICAgICByZXR1cm4gY29tcG9zaXRlO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogQWRkcyBhIGNvbXBvc2l0ZSB0byB0aGUgZ2l2ZW4gY29tcG9zaXRlLlxcbiAgICAgKiBAcHJpdmF0ZVxcbiAgICAgKiBAbWV0aG9kIGFkZENvbXBvc2l0ZVxcbiAgICAgKiBAcGFyYW0ge2NvbXBvc2l0ZX0gY29tcG9zaXRlQVxcbiAgICAgKiBAcGFyYW0ge2NvbXBvc2l0ZX0gY29tcG9zaXRlQlxcbiAgICAgKiBAcmV0dXJuIHtjb21wb3NpdGV9IFRoZSBvcmlnaW5hbCBjb21wb3NpdGVBIHdpdGggdGhlIG9iamVjdHMgZnJvbSBjb21wb3NpdGVCIGFkZGVkXFxuICAgICAqL1xcbiAgICBDb21wb3NpdGUuYWRkQ29tcG9zaXRlID0gZnVuY3Rpb24oY29tcG9zaXRlQSwgY29tcG9zaXRlQikge1xcbiAgICAgICAgY29tcG9zaXRlQS5jb21wb3NpdGVzLnB1c2goY29tcG9zaXRlQik7XFxuICAgICAgICBjb21wb3NpdGVCLnBhcmVudCA9IGNvbXBvc2l0ZUE7XFxuICAgICAgICBDb21wb3NpdGUuc2V0TW9kaWZpZWQoY29tcG9zaXRlQSwgdHJ1ZSwgdHJ1ZSwgZmFsc2UpO1xcbiAgICAgICAgcmV0dXJuIGNvbXBvc2l0ZUE7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZW1vdmVzIGEgY29tcG9zaXRlIGZyb20gdGhlIGdpdmVuIGNvbXBvc2l0ZSwgYW5kIG9wdGlvbmFsbHkgc2VhcmNoaW5nIGl0cyBjaGlsZHJlbiByZWN1cnNpdmVseS5cXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQG1ldGhvZCByZW1vdmVDb21wb3NpdGVcXG4gICAgICogQHBhcmFtIHtjb21wb3NpdGV9IGNvbXBvc2l0ZUFcXG4gICAgICogQHBhcmFtIHtjb21wb3NpdGV9IGNvbXBvc2l0ZUJcXG4gICAgICogQHBhcmFtIHtib29sZWFufSBbZGVlcD1mYWxzZV1cXG4gICAgICogQHJldHVybiB7Y29tcG9zaXRlfSBUaGUgb3JpZ2luYWwgY29tcG9zaXRlQSB3aXRoIHRoZSBjb21wb3NpdGUgcmVtb3ZlZFxcbiAgICAgKi9cXG4gICAgQ29tcG9zaXRlLnJlbW92ZUNvbXBvc2l0ZSA9IGZ1bmN0aW9uKGNvbXBvc2l0ZUEsIGNvbXBvc2l0ZUIsIGRlZXApIHtcXG4gICAgICAgIHZhciBwb3NpdGlvbiA9IENvbW1vbi5pbmRleE9mKGNvbXBvc2l0ZUEuY29tcG9zaXRlcywgY29tcG9zaXRlQik7XFxuICAgICAgICBpZiAocG9zaXRpb24gIT09IC0xKSB7XFxuICAgICAgICAgICAgQ29tcG9zaXRlLnJlbW92ZUNvbXBvc2l0ZUF0KGNvbXBvc2l0ZUEsIHBvc2l0aW9uKTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIGlmIChkZWVwKSB7XFxuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjb21wb3NpdGVBLmNvbXBvc2l0ZXMubGVuZ3RoOyBpKyspe1xcbiAgICAgICAgICAgICAgICBDb21wb3NpdGUucmVtb3ZlQ29tcG9zaXRlKGNvbXBvc2l0ZUEuY29tcG9zaXRlc1tpXSwgY29tcG9zaXRlQiwgdHJ1ZSk7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcblxcbiAgICAgICAgcmV0dXJuIGNvbXBvc2l0ZUE7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZW1vdmVzIGEgY29tcG9zaXRlIGZyb20gdGhlIGdpdmVuIGNvbXBvc2l0ZS5cXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQG1ldGhvZCByZW1vdmVDb21wb3NpdGVBdFxcbiAgICAgKiBAcGFyYW0ge2NvbXBvc2l0ZX0gY29tcG9zaXRlXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBwb3NpdGlvblxcbiAgICAgKiBAcmV0dXJuIHtjb21wb3NpdGV9IFRoZSBvcmlnaW5hbCBjb21wb3NpdGUgd2l0aCB0aGUgY29tcG9zaXRlIHJlbW92ZWRcXG4gICAgICovXFxuICAgIENvbXBvc2l0ZS5yZW1vdmVDb21wb3NpdGVBdCA9IGZ1bmN0aW9uKGNvbXBvc2l0ZSwgcG9zaXRpb24pIHtcXG4gICAgICAgIGNvbXBvc2l0ZS5jb21wb3NpdGVzLnNwbGljZShwb3NpdGlvbiwgMSk7XFxuICAgICAgICBDb21wb3NpdGUuc2V0TW9kaWZpZWQoY29tcG9zaXRlLCB0cnVlLCB0cnVlLCBmYWxzZSk7XFxuICAgICAgICByZXR1cm4gY29tcG9zaXRlO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogQWRkcyBhIGJvZHkgdG8gdGhlIGdpdmVuIGNvbXBvc2l0ZS5cXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQG1ldGhvZCBhZGRCb2R5XFxuICAgICAqIEBwYXJhbSB7Y29tcG9zaXRlfSBjb21wb3NpdGVcXG4gICAgICogQHBhcmFtIHtib2R5fSBib2R5XFxuICAgICAqIEByZXR1cm4ge2NvbXBvc2l0ZX0gVGhlIG9yaWdpbmFsIGNvbXBvc2l0ZSB3aXRoIHRoZSBib2R5IGFkZGVkXFxuICAgICAqL1xcbiAgICBDb21wb3NpdGUuYWRkQm9keSA9IGZ1bmN0aW9uKGNvbXBvc2l0ZSwgYm9keSkge1xcbiAgICAgICAgY29tcG9zaXRlLmJvZGllcy5wdXNoKGJvZHkpO1xcbiAgICAgICAgQ29tcG9zaXRlLnNldE1vZGlmaWVkKGNvbXBvc2l0ZSwgdHJ1ZSwgdHJ1ZSwgZmFsc2UpO1xcbiAgICAgICAgcmV0dXJuIGNvbXBvc2l0ZTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFJlbW92ZXMgYSBib2R5IGZyb20gdGhlIGdpdmVuIGNvbXBvc2l0ZSwgYW5kIG9wdGlvbmFsbHkgc2VhcmNoaW5nIGl0cyBjaGlsZHJlbiByZWN1cnNpdmVseS5cXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQG1ldGhvZCByZW1vdmVCb2R5XFxuICAgICAqIEBwYXJhbSB7Y29tcG9zaXRlfSBjb21wb3NpdGVcXG4gICAgICogQHBhcmFtIHtib2R5fSBib2R5XFxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2RlZXA9ZmFsc2VdXFxuICAgICAqIEByZXR1cm4ge2NvbXBvc2l0ZX0gVGhlIG9yaWdpbmFsIGNvbXBvc2l0ZSB3aXRoIHRoZSBib2R5IHJlbW92ZWRcXG4gICAgICovXFxuICAgIENvbXBvc2l0ZS5yZW1vdmVCb2R5ID0gZnVuY3Rpb24oY29tcG9zaXRlLCBib2R5LCBkZWVwKSB7XFxuICAgICAgICB2Y
2XIgcG9zaXRpb24gPSBDb21tb24uaW5kZXhPZihjb21wb3NpdGUuYm9kaWVzLCBib2R5KTtcXG4gICAgICAgIGlmIChwb3NpdGlvbiAhPT0gLTEpIHtcXG4gICAgICAgICAgICBDb21wb3NpdGUucmVtb3ZlQm9keUF0KGNvbXBvc2l0ZSwgcG9zaXRpb24pO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgaWYgKGRlZXApIHtcXG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNvbXBvc2l0ZS5jb21wb3NpdGVzLmxlbmd0aDsgaSsrKXtcXG4gICAgICAgICAgICAgICAgQ29tcG9zaXRlLnJlbW92ZUJvZHkoY29tcG9zaXRlLmNvbXBvc2l0ZXNbaV0sIGJvZHksIHRydWUpO1xcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHJldHVybiBjb21wb3NpdGU7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZW1vdmVzIGEgYm9keSBmcm9tIHRoZSBnaXZlbiBjb21wb3NpdGUuXFxuICAgICAqIEBwcml2YXRlXFxuICAgICAqIEBtZXRob2QgcmVtb3ZlQm9keUF0XFxuICAgICAqIEBwYXJhbSB7Y29tcG9zaXRlfSBjb21wb3NpdGVcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHBvc2l0aW9uXFxuICAgICAqIEByZXR1cm4ge2NvbXBvc2l0ZX0gVGhlIG9yaWdpbmFsIGNvbXBvc2l0ZSB3aXRoIHRoZSBib2R5IHJlbW92ZWRcXG4gICAgICovXFxuICAgIENvbXBvc2l0ZS5yZW1vdmVCb2R5QXQgPSBmdW5jdGlvbihjb21wb3NpdGUsIHBvc2l0aW9uKSB7XFxuICAgICAgICBjb21wb3NpdGUuYm9kaWVzLnNwbGljZShwb3NpdGlvbiwgMSk7XFxuICAgICAgICBDb21wb3NpdGUuc2V0TW9kaWZpZWQoY29tcG9zaXRlLCB0cnVlLCB0cnVlLCBmYWxzZSk7XFxuICAgICAgICByZXR1cm4gY29tcG9zaXRlO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogQWRkcyBhIGNvbnN0cmFpbnQgdG8gdGhlIGdpdmVuIGNvbXBvc2l0ZS5cXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQG1ldGhvZCBhZGRDb25zdHJhaW50XFxuICAgICAqIEBwYXJhbSB7Y29tcG9zaXRlfSBjb21wb3NpdGVcXG4gICAgICogQHBhcmFtIHtjb25zdHJhaW50fSBjb25zdHJhaW50XFxuICAgICAqIEByZXR1cm4ge2NvbXBvc2l0ZX0gVGhlIG9yaWdpbmFsIGNvbXBvc2l0ZSB3aXRoIHRoZSBjb25zdHJhaW50IGFkZGVkXFxuICAgICAqL1xcbiAgICBDb21wb3NpdGUuYWRkQ29uc3RyYWludCA9IGZ1bmN0aW9uKGNvbXBvc2l0ZSwgY29uc3RyYWludCkge1xcbiAgICAgICAgY29tcG9zaXRlLmNvbnN0cmFpbnRzLnB1c2goY29uc3RyYWludCk7XFxuICAgICAgICBDb21wb3NpdGUuc2V0TW9kaWZpZWQoY29tcG9zaXRlLCB0cnVlLCB0cnVlLCBmYWxzZSk7XFxuICAgICAgICByZXR1cm4gY29tcG9zaXRlO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmVtb3ZlcyBhIGNvbnN0cmFpbnQgZnJvbSB0aGUgZ2l2ZW4gY29tcG9zaXRlLCBhbmQgb3B0aW9uYWxseSBzZWFyY2hpbmcgaXRzIGNoaWxkcmVuIHJlY3Vyc2l2ZWx5LlxcbiAgICAgKiBAcHJpdmF0ZVxcbiAgICAgKiBAbWV0aG9kIHJlbW92ZUNvbnN0cmFpbnRcXG4gICAgICogQHBhcmFtIHtjb21wb3NpdGV9IGNvbXBvc2l0ZVxcbiAgICAgKiBAcGFyYW0ge2NvbnN0cmFpbnR9IGNvbnN0cmFpbnRcXG4gICAgICogQHBhcmFtIHtib29sZWFufSBbZGVlcD1mYWxzZV1cXG4gICAgICogQHJldHVybiB7Y29tcG9zaXRlfSBUaGUgb3JpZ2luYWwgY29tcG9zaXRlIHdpdGggdGhlIGNvbnN0cmFpbnQgcmVtb3ZlZFxcbiAgICAgKi9cXG4gICAgQ29tcG9zaXRlLnJlbW92ZUNvbnN0cmFpbnQgPSBmdW5jdGlvbihjb21wb3NpdGUsIGNvbnN0cmFpbnQsIGRlZXApIHtcXG4gICAgICAgIHZhciBwb3NpdGlvbiA9IENvbW1vbi5pbmRleE9mKGNvbXBvc2l0ZS5jb25zdHJhaW50cywgY29uc3RyYWludCk7XFxuICAgICAgICBpZiAocG9zaXRpb24gIT09IC0xKSB7XFxuICAgICAgICAgICAgQ29tcG9zaXRlLnJlbW92ZUNvbnN0cmFpbnRBdChjb21wb3NpdGUsIHBvc2l0aW9uKTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIGlmIChkZWVwKSB7XFxuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjb21wb3NpdGUuY29tcG9zaXRlcy5sZW5ndGg7IGkrKyl7XFxuICAgICAgICAgICAgICAgIENvbXBvc2l0ZS5yZW1vdmVDb25zdHJhaW50KGNvbXBvc2l0ZS5jb21wb3NpdGVzW2ldLCBjb25zdHJhaW50LCB0cnVlKTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuXFxuICAgICAgICByZXR1cm4gY29tcG9zaXRlO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmVtb3ZlcyBhIGJvZHkgZnJvbSB0aGUgZ2l2ZW4gY29tcG9zaXRlLlxcbiAgICAgKiBAcHJpdmF0ZVxcbiAgICAgKiBAbWV0aG9kIHJlbW92ZUNvbnN0cmFpbnRBdFxcbiAgICAgKiBAcGFyYW0ge2NvbXBvc2l0ZX0gY29tcG9zaXRlXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBwb3NpdGlvblxcbiAgICAgKiBAcmV0dXJuIHtjb21wb3NpdGV9IFRoZSBvcmlnaW5hbCBjb21wb3NpdGUgd2l0aCB0aGUgY29uc3RyYWludCByZW1vdmVkXFxuICAgICAqL1xcbiAgICBDb21wb3NpdGUucmVtb3ZlQ29uc3RyYWludEF0ID0gZnVuY3Rpb24oY29tcG9zaXRlLCBwb3NpdGlvbikge1xcbiAgICAgICAgY29tcG9zaXRlLmNvbnN0cmFpbnRzLnNwbGljZShwb3NpdGlvbiwgMSk7XFxuICAgICAgICBDb21wb3NpdGUuc2V0TW9kaWZpZWQoY29tcG9zaXRlLCB0cnVlLCB0cnVlLCBmYWxzZSk7XFxuICAgICAgICByZXR1cm4gY29tcG9zaXRlO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmVtb3ZlcyBhbGwgYm9kaWVzLCBjb25zdHJhaW50cyBhbmQgY29tcG9zaXRlcyBmcm9tIHRoZSBnaXZlbiBjb21wb3NpdGUuXFxuICAgICAqIE9wdGlvbmFsbHkgY2xlYXJpbmcgaXRzIGNoaWxkcmVuIHJlY3Vyc2l2ZWx5LlxcbiAgICAgKiBAbWV0aG9kIGNsZWFyXFxuICAgICAqIEBwYXJhbSB7Y29tcG9zaXRlfSBjb21wb3NpdGVcXG4gICAgICogQHBhcmFtIHtib29sZWFufSBrZWVwU3RhdGljXFxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW2RlZXA9ZmFsc2VdXFxuICAgICAqL1xcbiAgICBDb21wb3NpdGUuY2xlYXIgPSBmdW5jdGlvbihjb21wb3NpdGUsIGtlZXBTdGF0aWMsIGRlZXApIHtcXG4gICAgICAgIGlmIChkZWVwKSB7XFxuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjb21wb3NpdGUuY29tcG9zaXRlcy5sZW5ndGg7IGkrKyl7XFxuICAgICAgICAgICAgICAgIENvbXBvc2l0ZS5jbGVhcihjb21wb3NpdGUuY29tcG9zaXRlc1tpXSwga2VlcFN0YXRpYywgdHJ1ZSk7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcbiAgICAgICAgXFxuICAgICAgICBpZiAoa2VlcFN0YXRpYykge1xcbiAgICAgICAgICAgIGNvbXBvc2l0ZS5ib2RpZXMgPSBjb21wb3NpdGUuYm9kaWVzLmZpbHRlcihmdW5jdGlvbihib2R5KSB7IHJldHVybi
2Bib2R5LmlzU3RhdGljOyB9KTtcXG4gICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgY29tcG9zaXRlLmJvZGllcy5sZW5ndGggPSAwO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgY29tcG9zaXRlLmNvbnN0cmFpbnRzLmxlbmd0aCA9IDA7XFxuICAgICAgICBjb21wb3NpdGUuY29tcG9zaXRlcy5sZW5ndGggPSAwO1xcblxcbiAgICAgICAgQ29tcG9zaXRlLnNldE1vZGlmaWVkKGNvbXBvc2l0ZSwgdHJ1ZSwgdHJ1ZSwgZmFsc2UpO1xcblxcbiAgICAgICAgcmV0dXJuIGNvbXBvc2l0ZTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFJldHVybnMgYWxsIGJvZGllcyBpbiB0aGUgZ2l2ZW4gY29tcG9zaXRlLCBpbmNsdWRpbmcgYWxsIGJvZGllcyBpbiBpdHMgY2hpbGRyZW4sIHJlY3Vyc2l2ZWx5LlxcbiAgICAgKiBAbWV0aG9kIGFsbEJvZGllc1xcbiAgICAgKiBAcGFyYW0ge2NvbXBvc2l0ZX0gY29tcG9zaXRlXFxuICAgICAqIEByZXR1cm4ge2JvZHlbXX0gQWxsIHRoZSBib2RpZXNcXG4gICAgICovXFxuICAgIENvbXBvc2l0ZS5hbGxCb2RpZXMgPSBmdW5jdGlvbihjb21wb3NpdGUpIHtcXG4gICAgICAgIGlmIChjb21wb3NpdGUuY2FjaGUgJiYgY29tcG9zaXRlLmNhY2hlLmFsbEJvZGllcykge1xcbiAgICAgICAgICAgIHJldHVybiBjb21wb3NpdGUuY2FjaGUuYWxsQm9kaWVzO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgdmFyIGJvZGllcyA9IFtdLmNvbmNhdChjb21wb3NpdGUuYm9kaWVzKTtcXG5cXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY29tcG9zaXRlLmNvbXBvc2l0ZXMubGVuZ3RoOyBpKyspXFxuICAgICAgICAgICAgYm9kaWVzID0gYm9kaWVzLmNvbmNhdChDb21wb3NpdGUuYWxsQm9kaWVzKGNvbXBvc2l0ZS5jb21wb3NpdGVzW2ldKSk7XFxuXFxuICAgICAgICBpZiAoY29tcG9zaXRlLmNhY2hlKSB7XFxuICAgICAgICAgICAgY29tcG9zaXRlLmNhY2hlLmFsbEJvZGllcyA9IGJvZGllcztcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHJldHVybiBib2RpZXM7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIGFsbCBjb25zdHJhaW50cyBpbiB0aGUgZ2l2ZW4gY29tcG9zaXRlLCBpbmNsdWRpbmcgYWxsIGNvbnN0cmFpbnRzIGluIGl0cyBjaGlsZHJlbiwgcmVjdXJzaXZlbHkuXFxuICAgICAqIEBtZXRob2QgYWxsQ29uc3RyYWludHNcXG4gICAgICogQHBhcmFtIHtjb21wb3NpdGV9IGNvbXBvc2l0ZVxcbiAgICAgKiBAcmV0dXJuIHtjb25zdHJhaW50W119IEFsbCB0aGUgY29uc3RyYWludHNcXG4gICAgICovXFxuICAgIENvbXBvc2l0ZS5hbGxDb25zdHJhaW50cyA9IGZ1bmN0aW9uKGNvbXBvc2l0ZSkge1xcbiAgICAgICAgaWYgKGNvbXBvc2l0ZS5jYWNoZSAmJiBjb21wb3NpdGUuY2FjaGUuYWxsQ29uc3RyYWludHMpIHtcXG4gICAgICAgICAgICByZXR1cm4gY29tcG9zaXRlLmNhY2hlLmFsbENvbnN0cmFpbnRzO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgdmFyIGNvbnN0cmFpbnRzID0gW10uY29uY2F0KGNvbXBvc2l0ZS5jb25zdHJhaW50cyk7XFxuXFxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNvbXBvc2l0ZS5jb21wb3NpdGVzLmxlbmd0aDsgaSsrKVxcbiAgICAgICAgICAgIGNvbnN0cmFpbnRzID0gY29uc3RyYWludHMuY29uY2F0KENvbXBvc2l0ZS5hbGxDb25zdHJhaW50cyhjb21wb3NpdGUuY29tcG9zaXRlc1tpXSkpO1xcblxcbiAgICAgICAgaWYgKGNvbXBvc2l0ZS5jYWNoZSkge1xcbiAgICAgICAgICAgIGNvbXBvc2l0ZS5jYWNoZS5hbGxDb25zdHJhaW50cyA9IGNvbnN0cmFpbnRzO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgcmV0dXJuIGNvbnN0cmFpbnRzO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmV0dXJucyBhbGwgY29tcG9zaXRlcyBpbiB0aGUgZ2l2ZW4gY29tcG9zaXRlLCBpbmNsdWRpbmcgYWxsIGNvbXBvc2l0ZXMgaW4gaXRzIGNoaWxkcmVuLCByZWN1cnNpdmVseS5cXG4gICAgICogQG1ldGhvZCBhbGxDb21wb3NpdGVzXFxuICAgICAqIEBwYXJhbSB7Y29tcG9zaXRlfSBjb21wb3NpdGVcXG4gICAgICogQHJldHVybiB7Y29tcG9zaXRlW119IEFsbCB0aGUgY29tcG9zaXRlc1xcbiAgICAgKi9cXG4gICAgQ29tcG9zaXRlLmFsbENvbXBvc2l0ZXMgPSBmdW5jdGlvbihjb21wb3NpdGUpIHtcXG4gICAgICAgIGlmIChjb21wb3NpdGUuY2FjaGUgJiYgY29tcG9zaXRlLmNhY2hlLmFsbENvbXBvc2l0ZXMpIHtcXG4gICAgICAgICAgICByZXR1cm4gY29tcG9zaXRlLmNhY2hlLmFsbENvbXBvc2l0ZXM7XFxuICAgICAgICB9XFxuXFxuICAgICAgICB2Y
2XIgY29tcG9zaXRlcyA9IFtdLmNvbmNhdChjb21wb3NpdGUuY29tcG9zaXRlcyk7XFxuXFxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNvbXBvc2l0ZS5jb21wb3NpdGVzLmxlbmd0aDsgaSsrKVxcbiAgICAgICAgICAgIGNvbXBvc2l0ZXMgPSBjb21wb3NpdGVzLmNvbmNhdChDb21wb3NpdGUuYWxsQ29tcG9zaXRlcyhjb21wb3NpdGUuY29tcG9zaXRlc1tpXSkpO1xcblxcbiAgICAgICAgaWYgKGNvbXBvc2l0ZS5jYWNoZSkge1xcbiAgICAgICAgICAgIGNvbXBvc2l0ZS5jYWNoZS5hbGxDb21wb3NpdGVzID0gY29tcG9zaXRlcztcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHJldHVybiBjb21wb3NpdGVzO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogU2VhcmNoZXMgdGhlIGNvbXBvc2l0ZSByZWN1cnNpdmVseSBmb3IgYW4gb2JqZWN0IG1hdGNoaW5nIHRoZSB0eXBlIGFuZCBpZCBzdXBwbGllZCwgbnVsbCBpZiBub3QgZm91bmQuXFxuICAgICAqIEBtZXRob2QgZ2V0XFxuICAgICAqIEBwYXJhbSB7Y29tcG9zaXRlfSBjb21wb3NpdGVcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGlkXFxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlXFxuICAgICAqIEByZXR1cm4ge29iamVjdH0gVGhlIHJlcXVlc3RlZCBvYmplY3QsIGlmIGZvdW5kXFxuICAgICAqL1xcbiAgICBDb21wb3NpdGUuZ2V0ID0gZnVuY3Rpb24oY29tcG9zaXRlLCBpZCwgdHlwZSkge1xcbiAgICAgICAgdmFyIG9iamVjdHMsXFxuICAgICAgICAgICAgb2JqZWN0O1xcblxcbiAgICAgICAgc3dpdGNoICh0eXBlKSB7XFxuICAgICAgICBjYXNlICdib2R5JzpcXG4gICAgICAgICAgICBvYmplY3RzID0gQ29tcG9zaXRlLmFsbEJvZGllcyhjb21wb3NpdGUpO1xcbiAgICAgICAgICAgIGJyZWFrO1xcbiAgICAgICAgY2FzZSAnY29uc3RyYWludCc6XFxuICAgICAgICAgICAgb2JqZWN0cyA9IENvbXBvc2l0ZS5hbGxDb25zdHJhaW50cyhjb21wb3NpdGUpO1xcbiAgICAgICAgICAgIGJyZWFrO1xcbiAgICAgICAgY2FzZSAnY29tcG9zaXRlJzpcXG4gICAgICAgICAgICBvYmplY3RzID0gQ29tcG9zaXRlLmFsbENvbXBvc2l0ZXMoY29tcG9zaXRlKS5jb25jYXQoY29tcG9zaXRlKTtcXG4gICAgICAgICAgICBicmVhaztcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIGlmICghb2JqZWN0cylcXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcXG5cXG4gICAgICAgIG9iamVjdCA9IG9iamVjdHMuZmlsdGVyKGZ1bmN0aW9uKG9iamVjdCkgeyBcXG4gICAgICAgICAgICByZXR1cm4gb2JqZWN0LmlkLnRvU3RyaW5nKCkgPT09IGlkLnRvU3RyaW5nKCk7IFxcbiAgICAgICAgfSk7XFxuXFxuICAgICAgICByZXR1cm4gb2JqZWN0Lmxlbmd0aCA9PT0gMCA/IG51bGwgOiBvYmplY3RbMF07XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBNb3ZlcyB0aGUgZ2l2ZW4gb2JqZWN0KHMpIGZyb20gY29tcG9zaXRlQSB0byBjb21wb3NpdGVCIChlcXVhbCB0byBhIHJlbW92ZSBmb2xsb3dlZCBieSBhbiBhZGQpLlxcbiAgICAgKiBAbWV0aG9kIG1vdmVcXG4gICAgICogQHBhcmFtIHtjb21wb3NpdGVBfSBjb21wb3NpdGVBXFxuICAgICAqIEBwYXJhbSB7b2JqZWN0W119IG9iamVjdHNcXG4gICAgICogQHBhcmFtIHtjb21wb3NpdGVCfSBjb21wb3NpdGVCXFxuICAgICAqIEByZXR1cm4ge2NvbXBvc2l0ZX0gUmV0dXJucyBjb21wb3NpdGVBXFxuICAgICAqL1xcbiAgICBDb21wb3NpdGUubW92ZSA9IGZ1bmN0aW9uKGNvbXBvc2l0ZUEsIG9iamVjdHMsIGNvbXBvc2l0ZUIpIHtcXG4gICAgICAgIENvbXBvc2l0ZS5yZW1vdmUoY29tcG9zaXRlQSwgb2JqZWN0cyk7XFxuICAgICAgICBDb21wb3NpdGUuYWRkKGNvbXBvc2l0ZUIsIG9iamVjdHMpO1xcbiAgICAgICAgcmV0dXJuIGNvbXBvc2l0ZUE7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBBc3NpZ25zIG5ldyBpZHMgZm9yIGFsbCBvYmplY3RzIGluIHRoZSBjb21wb3NpdGUsIHJlY3Vyc2l2ZWx5LlxcbiAgICAgKiBAbWV0aG9kIHJlYmFzZVxcbiAgICAgKiBAcGFyYW0ge2NvbXBvc2l0ZX0gY29tcG9zaXRlXFxuICAgICAqIEByZXR1cm4ge2NvbXBvc2l0ZX0gUmV0dXJucyBjb21wb3NpdGVcXG4gICAgICovXFxuICAgIENvbXBvc2l0ZS5yZWJhc2UgPSBmdW5jdGlvbihjb21wb3NpdGUpIHtcXG4gICAgICAgIHZhciBvYmplY3RzID0gQ29tcG9zaXRlLmFsbEJvZGllcyhjb21wb3NpdGUpXFxuICAgICAgICAgICAgLmNvbmNhdChDb21wb3NpdGUuYWxsQ29uc3RyYWludHMoY29tcG9zaXRlKSlcXG4gICAgICAgICAgICAuY29uY2F0KENvbXBvc2l0ZS5hbGxDb21wb3NpdGVzKGNvbXBvc2l0ZSkpO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBvYmplY3RzLmxlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgb2JqZWN0c1tpXS5pZCA9IENvbW1vbi5uZXh0SWQoKTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHJldHVybiBjb21wb3NpdGU7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBUcmFuc2xhdGVzIGFsbCBjaGlsZHJlbiBpbiB0aGUgY29tcG9zaXRlIGJ5IGEgZ2l2ZW4gdmVjdG9yIHJlbGF0aXZlIHRvIHRoZWlyIGN1cnJlbnQgcG9zaXRpb25zLCBcXG4gICAgICogd2l0aG91dCBpbXBhcnRpbmcgYW55IHZlbG9jaXR5LlxcbiAgICAgKiBAbWV0aG9kIHRyYW5zbGF0ZVxcbiAgICAgKiBAcGFyYW0ge2NvbXBvc2l0ZX0gY29tcG9zaXRlXFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSB0cmFuc2xhdGlvblxcbiAgICAgKiBAcGFyYW0ge2Jvb2x9IFtyZWN1cnNpdmU9dHJ1ZV1cXG4gICAgICovXFxuICAgIENvbXBvc2l0ZS50cmFuc2xhdGUgPSBmdW5jdGlvbihjb21wb3NpdGUsIHRyYW5zbGF0aW9uLCByZWN1cnNpdmUpIHtcXG4gICAgICAgIHZhciBib2RpZXMgPSByZWN1cnNpdmUgPyBDb21wb3NpdGUuYWxsQm9kaWVzKGNvbXBvc2l0ZSkgOiBjb21wb3NpdGUuYm9kaWVzO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBib2RpZXMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICBCb2R5LnRyYW5zbGF0ZShib2RpZXNbaV0sIHRyYW5zbGF0aW9uKTtcXG4gICAgICAgI
2H1cXG5cXG4gICAgICAgIHJldHVybiBjb21wb3NpdGU7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSb3RhdGVzIGFsbCBjaGlsZHJlbiBpbiB0aGUgY29tcG9zaXRlIGJ5IGEgZ2l2ZW4gYW5nbGUgYWJvdXQgdGhlIGdpdmVuIHBvaW50LCB3aXRob3V0IGltcGFydGluZyBhbnkgYW5ndWxhciB2ZWxvY2l0eS5cXG4gICAgICogQG1ldGhvZCByb3RhdGVcXG4gICAgICogQHBhcmFtIHtjb21wb3NpdGV9IGNvbXBvc2l0ZVxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gcm90YXRpb25cXG4gICAgICogQHBhcmFtIHt2ZWN0b3J9IHBvaW50XFxuICAgICAqIEBwYXJhbSB7Ym9vbH0gW3JlY3Vyc2l2ZT10cnVlXVxcbiAgICAgKi9cXG4gICAgQ29tcG9zaXRlLnJvdGF0ZSA9IGZ1bmN0aW9uKGNvbXBvc2l0ZSwgcm90YXRpb24sIHBvaW50LCByZWN1cnNpdmUpIHtcXG4gICAgICAgIHZhciBjb3MgPSBNYXRoLmNvcyhyb3RhdGlvbiksXFxuICAgICAgICAgICAgc2luID0gTWF0aC5zaW4ocm90YXRpb24pLFxcbiAgICAgICAgICAgIGJvZGllcyA9IHJlY3Vyc2l2ZSA/IENvbXBvc2l0ZS5hbGxCb2RpZXMoY29tcG9zaXRlKSA6IGNvbXBvc2l0ZS5ib2RpZXM7XFxuXFxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJvZGllcy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHZhciBib2R5ID0gYm9kaWVzW2ldLFxcbiAgICAgICAgICAgICAgICBkeCA9IGJvZHkucG9zaXRpb24ueCAtIHBvaW50LngsXFxuICAgICAgICAgICAgICAgIGR5ID0gYm9keS5wb3NpdGlvbi55IC0gcG9pbnQueTtcXG4gICAgICAgICAgICAgICAgXFxuICAgICAgICAgICAgQm9keS5zZXRQb3NpdGlvbihib2R5LCB7XFxuICAgICAgICAgICAgICAgIHg6IHBvaW50LnggKyAoZHggKiBjb3MgLSBkeSAqIHNpbiksXFxuICAgICAgICAgICAgICAgIHk6IHBvaW50LnkgKyAoZHggKiBzaW4gKyBkeSAqIGNvcylcXG4gICAgICAgICAgICB9KTtcXG5cXG4gICAgICAgICAgICBCb2R5LnJvdGF0ZShib2R5LCByb3RhdGlvbik7XFxuICAgICAgICB9XFxuXFxuICAgICAgICByZXR1cm4gY29tcG9zaXRlO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogU2NhbGVzIGFsbCBjaGlsZHJlbiBpbiB0aGUgY29tcG9zaXRlLCBpbmNsdWRpbmcgdXBkYXRpbmcgcGh5c2ljYWwgcHJvcGVydGllcyAobWFzcywgYXJlYSwgYXhlcywgaW5lcnRpYSksIGZyb20gYSB3b3JsZC1zcGFjZSBwb2ludC5cXG4gICAgICogQG1ldGhvZCBzY2FsZVxcbiAgICAgKiBAcGFyYW0ge2NvbXBvc2l0ZX0gY29tcG9zaXRlXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBzY2FsZVhcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHNjYWxlWVxcbiAgICAgKiBAcGFyYW0ge3ZlY3Rvcn0gcG9pbnRcXG4gICAgICogQHBhcmFtIHtib29sfSBbcmVjdXJzaXZlPXRydWVdXFxuICAgICAqL1xcbiAgICBDb21wb3NpdGUuc2NhbGUgPSBmdW5jdGlvbihjb21wb3NpdGUsIHNjYWxlWCwgc2NhbGVZLCBwb2ludCwgcmVjdXJzaXZlKSB7XFxuICAgICAgICB2Y
2XIgYm9kaWVzID0gcmVjdXJzaXZlID8gQ29tcG9zaXRlLmFsbEJvZGllcyhjb21wb3NpdGUpIDogY29tcG9zaXRlLmJvZGllcztcXG5cXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYm9kaWVzLmxlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgdmFyIGJvZHkgPSBib2RpZXNbaV0sXFxuICAgICAgICAgICAgICAgIGR4ID0gYm9keS5wb3NpdGlvbi54IC0gcG9pbnQueCxcXG4gICAgICAgICAgICAgICAgZHkgPSBib2R5LnBvc2l0aW9uLnkgLSBwb2ludC55O1xcbiAgICAgICAgICAgICAgICBcXG4gICAgICAgICAgICBCb2R5LnNldFBvc2l0aW9uKGJvZHksIHtcXG4gICAgICAgICAgICAgICAgeDogcG9pbnQueCArIGR4ICogc2NhbGVYLFxcbiAgICAgICAgICAgICAgICB5OiBwb2ludC55ICsgZHkgKiBzY2FsZVlcXG4gICAgICAgICAgICB9KTtcXG5cXG4gICAgICAgICAgICBCb2R5LnNjYWxlKGJvZHksIHNjYWxlWCwgc2NhbGVZKTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHJldHVybiBjb21wb3NpdGU7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIHRoZSB1bmlvbiBvZiB0aGUgYm91bmRzIG9mIGFsbCBvZiB0aGUgY29tcG9zaXRlJ3MgYm9kaWVzLlxcbiAgICAgKiBAbWV0aG9kIGJvdW5kc1xcbiAgICAgKiBAcGFyYW0ge2NvbXBvc2l0ZX0gY29tcG9zaXRlIFRoZSBjb21wb3NpdGUuXFxuICAgICAqIEByZXR1cm5zIHtib3VuZHN9IFRoZSBjb21wb3NpdGUgYm91bmRzLlxcbiAgICAgKi9cXG4gICAgQ29tcG9zaXRlLmJvdW5kcyA9IGZ1bmN0aW9uKGNvbXBvc2l0ZSkge1xcbiAgICAgICAgdmFyIGJvZGllcyA9IENvbXBvc2l0ZS5hbGxCb2RpZXMoY29tcG9zaXRlKSxcXG4gICAgICAgICAgICB2ZXJ0aWNlcyA9IFtdO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBib2RpZXMubGVuZ3RoOyBpICs9IDEpIHtcXG4gICAgICAgICAgICB2Y
2XIgYm9keSA9IGJvZGllc1tpXTtcXG4gICAgICAgICAgICB2ZXJ0aWNlcy5wdXNoKGJvZHkuYm91bmRzLm1pbiwgYm9keS5ib3VuZHMubWF4KTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHJldHVybiBCb3VuZHMuY3JlYXRlKHZlcnRpY2VzKTtcXG4gICAgfTtcXG5cXG4gICAgLypcXG4gICAgKlxcbiAgICAqICBFdmVudHMgRG9jdW1lbnRhdGlvblxcbiAgICAqXFxuICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAqIEZpcmVkIHdoZW4gYSBjYWxsIHRvIGBDb21wb3NpdGUuYWRkYCBpcyBtYWRlLCBiZWZvcmUgb2JqZWN0cyBoYXZlIGJlZW4gYWRkZWQuXFxuICAgICpcXG4gICAgKiBAZXZlbnQgYmVmb3JlQWRkXFxuICAgICogQHBhcmFtIHt9IGV2ZW50IEFuIGV2ZW50IG9iamVjdFxcbiAgICAqIEBwYXJhbSB7fSBldmVudC5vYmplY3QgVGhlIG9iamVjdChzKSB0byBiZSBhZGRlZCAobWF5IGJlIGEgc2luZ2xlIGJvZHksIGNvbnN0cmFpbnQsIGNvbXBvc2l0ZSBvciBhIG1peGVkIGFycmF5IG9mIHRoZXNlKVxcbiAgICAqIEBwYXJhbSB7fSBldmVudC5zb3VyY2UgVGhlIHNvdXJjZSBvYmplY3Qgb2YgdGhlIGV2ZW50XFxuICAgICogQHBhcmFtIHt9IGV2ZW50Lm5hbWUgVGhlIG5hbWUgb2YgdGhlIGV2ZW50XFxuICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAqIEZpcmVkIHdoZW4gYSBjYWxsIHRvIGBDb21wb3NpdGUuYWRkYCBpcyBtYWRlLCBhZnRlciBvYmplY3RzIGhhdmUgYmVlbiBhZGRlZC5cXG4gICAgKlxcbiAgICAqIEBldmVudCBhZnRlckFkZFxcbiAgICAqIEBwYXJhbSB7fSBldmVudCBBbiBldmVudCBvYmplY3RcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQub2JqZWN0IFRoZSBvYmplY3QocykgdGhhdCBoYXZlIGJlZW4gYWRkZWQgKG1heSBiZSBhIHNpbmdsZSBib2R5LCBjb25zdHJhaW50LCBjb21wb3NpdGUgb3IgYSBtaXhlZCBhcnJheSBvZiB0aGVzZSlcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQuc291cmNlIFRoZSBzb3VyY2Ugb2JqZWN0IG9mIHRoZSBldmVudFxcbiAgICAqIEBwYXJhbSB7fSBldmVudC5uYW1lIFRoZSBuYW1lIG9mIHRoZSBldmVudFxcbiAgICAqL1xcblxcbiAgICAvKipcXG4gICAgKiBGaXJlZCB3aGVuIGEgY2FsbCB0byBgQ29tcG9zaXRlLnJlbW92ZWAgaXMgbWFkZSwgYmVmb3JlIG9iamVjdHMgaGF2ZSBiZWVuIHJlbW92ZWQuXFxuICAgICpcXG4gICAgKiBAZXZlbnQgYmVmb3JlUmVtb3ZlXFxuICAgICogQHBhcmFtIHt9IGV2ZW50IEFuIGV2ZW50IG9iamVjdFxcbiAgICAqIEBwYXJhbSB7fSBldmVudC5vYmplY3QgVGhlIG9iamVjdChzKSB0byBiZSByZW1vdmVkIChtYXkgYmUgYSBzaW5nbGUgYm9keSwgY29uc3RyYWludCwgY29tcG9zaXRlIG9yIGEgbWl4ZWQgYXJyYXkgb2YgdGhlc2UpXFxuICAgICogQHBhcmFtIHt9IGV2ZW50LnNvdXJjZSBUaGUgc291cmNlIG9iamVjdCBvZiB0aGUgZXZlbnRcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQubmFtZSBUaGUgbmFtZSBvZiB0aGUgZXZlbnRcXG4gICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICogRmlyZWQgd2hlbiBhIGNhbGwgdG8gYENvbXBvc2l0ZS5yZW1vdmVgIGlzIG1hZGUsIGFmdGVyIG9iamVjdHMgaGF2ZSBiZWVuIHJlbW92ZWQuXFxuICAgICpcXG4gICAgKiBAZXZlbnQgYWZ0ZXJSZW1vdmVcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQgQW4gZXZlbnQgb2JqZWN0XFxuICAgICogQHBhcmFtIHt9IGV2ZW50Lm9iamVjdCBUaGUgb2JqZWN0KHMpIHRoYXQgaGF2ZSBiZWVuIHJlbW92ZWQgKG1heSBiZSBhIHNpbmdsZSBib2R5LCBjb25zdHJhaW50LCBjb21wb3NpdGUgb3IgYSBtaXhlZCBhcnJheSBvZiB0aGVzZSlcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQuc291cmNlIFRoZSBzb3VyY2Ugb2JqZWN0IG9mIHRoZSBldmVudFxcbiAgICAqIEBwYXJhbSB7fSBldmVudC5uYW1lIFRoZSBuYW1lIG9mIHRoZSBldmVudFxcbiAgICAqL1xcblxcbiAgICAvKlxcbiAgICAqXFxuICAgICogIFByb3BlcnRpZXMgRG9jdW1lbnRhdGlvblxcbiAgICAqXFxuICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBbiBpbnRlZ2VyIGBOdW1iZXJgIHVuaXF1ZWx5IGlkZW50aWZ5aW5nIG51bWJlciBnZW5lcmF0ZWQgaW4gYENvbXBvc2l0ZS5jcmVhdGVgIGJ5IGBDb21tb24ubmV4dElkYC5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IGlkXFxuICAgICAqIEB0eXBlIG51bWJlclxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEEgYFN0cmluZ2AgZGVub3RpbmcgdGhlIHR5cGUgb2Ygb2JqZWN0LlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgdHlwZVxcbiAgICAgKiBAdHlwZSBzdHJpbmdcXG4gICAgICogQGRlZmF1bHQgXFxcImNvbXBvc2l0ZVxcXCJcXG4gICAgICogQHJlYWRPbmx5XFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQW4gYXJiaXRyYXJ5IGBTdHJpbmdgIG5hbWUgdG8gaGVscCB0aGUgdXNlciBpZGVudGlmeSBhbmQgbWFuYWdlIGNvbXBvc2l0ZXMuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBsYWJlbFxcbiAgICAgKiBAdHlwZSBzdHJpbmdcXG4gICAgICogQGRlZmF1bHQgXFxcIkNvbXBvc2l0ZVxcXCJcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGZsYWcgdGhhdCBzcGVjaWZpZXMgd2hldGhlciB0aGUgY29tcG9zaXRlIGhhcyBiZWVuIG1vZGlmaWVkIGR1cmluZyB0aGUgY3VycmVudCBzdGVwLlxcbiAgICAgKiBUaGlzIGlzIGF1dG9tYXRpY2FsbHkgbWFuYWdlZCB3aGVuIGJvZGllcywgY29uc3RyYWludHMgb3IgY29tcG9zaXRlcyBhcmUgYWRkZWQgb3IgcmVtb3ZlZC5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IGlzTW9kaWZpZWRcXG4gICAgICogQHR5cGUgYm9vbGVhblxcbiAgICAgKiBAZGVmYXVsdCBmYWxzZVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIFRoZSBgQ29tcG9zaXRlYCB0aGF0IGlzIHRoZSBwYXJlbnQgb2YgdGhpcyBjb21wb3NpdGUuIEl0IGlzIGF1dG9tYXRpY2FsbHkgbWFuYWdlZCBieSB0aGUgYE1hdHRlci5Db21wb3NpdGVgIG1ldGhvZHMuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBwYXJlbnRcXG4gICAgICogQHR5cGUgY29tcG9zaXRlXFxuICAgICAqIEBkZWZhdWx0IG51bGxcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBbiBhcnJheSBvZiBgQm9keWAgdGhhdCBhcmUgX2RpcmVjdF8gY2hpbGRyZW4gb2YgdGhpcyBjb21wb3NpdGUuXFxuICAgICAqIFRvIGFkZCBvciByZW1vdmUgYm9k
2aWVzIHlvdSBzaG91bGQgdXNlIGBDb21wb3NpdGUuYWRkYCBhbmQgYENvbXBvc2l0ZS5yZW1vdmVgIG1ldGhvZHMgcmF0aGVyIHRoYW4gZGlyZWN0bHkgbW9kaWZ5aW5nIHRoaXMgcHJvcGVydHkuXFxuICAgICAqIElmIHlvdSB3aXNoIHRvIHJlY3Vyc2l2ZWx5IGZpbmQgYWxsIGRlc2NlbmRhbnRzLCB5b3Ugc2hvdWxkIHVzZSB0aGUgYENvbXBvc2l0ZS5hbGxCb2RpZXNgIG1ldGhvZC5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IGJvZGllc1xcbiAgICAgKiBAdHlwZSBib2R5W11cXG4gICAgICogQGRlZmF1bHQgW11cXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBbiBhcnJheSBvZiBgQ29uc3RyYWludGAgdGhhdCBhcmUgX2RpcmVjdF8gY2hpbGRyZW4gb2YgdGhpcyBjb21wb3NpdGUuXFxuICAgICAqIFRvIGFkZCBvciByZW1vdmUgY29uc3RyYWludHMgeW91IHNob3VsZCB1c2UgYENvbXBvc2l0ZS5hZGRgIGFuZCBgQ29tcG9zaXRlLnJlbW92ZWAgbWV0aG9kcyByYXRoZXIgdGhhbiBkaXJlY3RseSBtb2RpZnlpbmcgdGhpcyBwcm9wZXJ0eS5cXG4gICAgICogSWYgeW91IHdpc2ggdG8gcmVjdXJzaXZlbHkgZmluZCBhbGwgZGVzY2VuZGFudHMsIHlvdSBzaG91bGQgdXNlIHRoZSBgQ29tcG9zaXRlLmFsbENvbnN0cmFpbnRzYCBtZXRob2QuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBjb25zdHJhaW50c1xcbiAgICAgKiBAdHlwZSBjb25zdHJhaW50W11cXG4gICAgICogQGRlZmF1bHQgW11cXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBbiBhcnJheSBvZiBgQ29tcG9zaXRlYCB0aGF0IGFyZSBfZGlyZWN0XyBjaGlsZHJlbiBvZiB0aGlzIGNvbXBvc2l0ZS5cXG4gICAgICogVG8gYWRkIG9yIHJlbW92ZSBjb21wb3NpdGVzIHlvdSBzaG91bGQgdXNlIGBDb21wb3NpdGUuYWRkYCBhbmQgYENvbXBvc2l0ZS5yZW1vdmVgIG1ldGhvZHMgcmF0aGVyIHRoYW4gZGlyZWN0bHkgbW9kaWZ5aW5nIHRoaXMgcHJvcGVydHkuXFxuICAgICAqIElmIHlvdSB3aXNoIHRvIHJlY3Vyc2l2ZWx5IGZpbmQgYWxsIGRlc2NlbmRhbnRzLCB5b3Ugc2hvdWxkIHVzZSB0aGUgYENvbXBvc2l0ZS5hbGxDb21wb3NpdGVzYCBtZXRob2QuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBjb21wb3NpdGVzXFxuICAgICAqIEB0eXBlIGNvbXBvc2l0ZVtdXFxuICAgICAqIEBkZWZhdWx0IFtdXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQW4gb2JqZWN0IHJlc2VydmVkIGZvciBzdG9yaW5nIHBsdWdpbi1zcGVjaWZpYyBwcm9wZXJ0aWVzLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgcGx1Z2luXFxuICAgICAqIEB0eXBlIHt9XFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQW4gb2JqZWN0IHVzZWQgZm9yIHN0b3JpbmcgY2FjaGVkIHJlc3VsdHMgZm9yIHBlcmZvcm1hbmNlIHJlYXNvbnMuXFxuICAgICAqIFRoaXMgaXMgdXNlZCBpbnRlcm5hbGx5IG9ubHkgYW5kIGlzIGF1dG9tYXRpY2FsbHkgbWFuYWdlZC5cXG4gICAgICpcXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQHByb3BlcnR5IGNhY2hlXFxuICAgICAqIEB0eXBlIHt9XFxuICAgICAqL1xcblxcbn0pKCk7XFxuXFxuXFxuLyoqKi8gfSksXFxuLyogNyAqL1xcbi8qKiovIChmdW5jdGlvbihtb2R1bGUsIGV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pIHtcXG5cXG4vKipcXG4qIFRoZSBgTWF0dGVyLlNsZWVwaW5nYCBtb2R1bGUgY29udGFpbnMgbWV0aG9kcyB0byBtYW5hZ2UgdGhlIHNsZWVwaW5nIHN0YXRlIG9mIGJvZGllcy5cXG4qXFxuKiBAY2xhc3MgU2xlZXBpbmdcXG4qL1xcblxcbnZhciBTbGVlcGluZyA9IHt9O1xcblxcbm1vZHVsZS5leHBvcnRzID0gU2xlZXBpbmc7XFxuXFxudmFyIEJvZHkgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDQpO1xcbnZhciBFdmVudHMgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDUpO1xcbnZhciBDb21tb24gPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDApO1xcblxcbihmdW5jdGlvbigpIHtcXG5cXG4gICAgU2xlZXBpbmcuX21vdGlvbldha2VUaHJlc2hvbGQgPSAwLjE4O1xcbiAgICBTbGVlcGluZy5fbW90aW9uU2xlZXBUaHJlc2hvbGQgPSAwLjA4O1xcbiAgICBTbGVlcGluZy5fbWluQmlhcyA9IDAuOTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFB1dHMgYm9kaWVzIHRvIHNsZWVwIG9yIHdha2VzIHRoZW0gdXAgZGVwZW5kaW5nIG9uIHRoZWlyIG1vdGlvbi5cXG4gICAgICogQG1ldGhvZCB1cGRhdGVcXG4gICAgICogQHBhcmFtIHtib2R5W119IGJvZGllc1xcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gZGVsdGFcXG4gICAgICovXFxuICAgIFNsZWVwaW5nLnVwZGF0ZSA9IGZ1bmN0aW9uKGJvZGllcywgZGVsdGEpIHtcXG4gICAgICAgIHZhciB0aW1lU2NhbGUgPSBkZWx0YSAvIENvbW1vbi5fYmFzZURlbHRhLFxcbiAgICAgICAgICAgIG1vdGlvblNsZWVwVGhyZXNob2xkID0gU2xlZXBpbmcuX21vdGlvblNsZWVwVGhyZXNob2xkO1xcbiAgICAgICAgXFxuICAgICAgICAvLyB1cGRhdGUgYm9kaWVzIHNsZWVwaW5nIHN0YXR1c1xcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBib2RpZXMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICB2Y
2XIgYm9keSA9IGJvZGllc1tpXSxcXG4gICAgICAgICAgICAgICAgc3BlZWQgPSBCb2R5LmdldFNwZWVkKGJvZHkpLFxcbiAgICAgICAgICAgICAgICBhbmd1bGFyU3BlZWQgPSBCb2R5LmdldEFuZ3VsYXJTcGVlZChib2R5KSxcXG4gICAgICAgICAgICAgICAgbW90aW9uID0gc3BlZWQgKiBzcGVlZCArIGFuZ3VsYXJTcGVlZCAqIGFuZ3VsYXJTcGVlZDtcXG5cXG4gICAgICAgICAgICAvLyB3YWtlIHVwIGJvZGllcyBpZiB0aGV5IGhhdmUgYSBmb3JjZSBhcHBsaWVkXFxuICAgICAgICAgICAgaWYgKGJvZHkuZm9yY2UueCAhPT0gMCB8fCBib2R5LmZvcmNlLnkgIT09IDApIHtcXG4gICAgICAgICAgICAgICAgU2xlZXBpbmcuc2V0KGJvZHksIGZhbHNlKTtcXG4gICAgICAgICAgICAgICAgY29udGludWU7XFxuICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgIHZhciBtaW5Nb3Rpb24gPSBNYXRoLm1pbihib2R5Lm1vdGlvbiwgbW90aW9uKSxcXG4gICAgICAgICAgICAgICAgbWF4TW90aW9uID0gTWF0aC5tYXgoYm9keS5tb3Rpb24sIG1vdGlvbik7XFxuICAgICAgICBcXG4gICAgICAgICAgICAvLyBiaWFzZWQgYXZlcmFnZSBtb3Rpb24gZXN0aW1hdGlvbiBiZXR3ZWVuIGZyYW1lc1xcbiAgICAgICAgICAgIGJvZHkubW90aW9uID0gU2xlZXBpbmcuX21pbkJpYXMgKiBtaW5Nb3Rpb24gKyAoMSAtIFNsZWVwaW5nLl9taW5CaWFzKSAqIG1heE1vdGlvbjtcXG5cXG4gICAgICAgICAgICBpZiAoYm9keS5zbGVlcFRocmVzaG9sZCA+IDAgJiYgYm9keS5tb3Rpb24gPCBtb3Rpb25TbGVlcFRocmVzaG9sZCkge1xcbiAgICAgICAgICAgICAgICBib2R5LnNsZWVwQ291bnRlciArPSAxO1xcbiAgICAgICAgICAgICAgICBcXG4gICAgICAgICAgICAgICAgaWYgKGJvZHkuc2xlZXBDb3VudGVyID49IGJvZHkuc2xlZXBUaHJlc2hvbGQgLyB0aW1lU2NhbGUpIHtcXG4gICAgICAgICAgICAgICAgICAgIFNsZWVwaW5nLnNldChib2R5LCB0cnVlKTtcXG4gICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoYm9keS5zbGVlcENvdW50ZXIgPiAwKSB7XFxuICAgICAgICAgICAgICAgIGJvZHkuc2xlZXBDb3VudGVyIC09IDE7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogR2l2ZW4gYSBzZXQgb2YgY29sbGlkaW5nIHBhaXJzLCB3YWtlcyB0aGUgc2xlZXBpbmcgYm9kaWVzIGludm9sdmVkLlxcbiAgICAgKiBAbWV0aG9kIGFmdGVyQ29sbGlzaW9uc1xcbiAgICAgKiBAcGFyYW0ge3BhaXJbXX0gcGFpcnNcXG4gICAgICovXFxuICAgIFNsZWVwaW5nLmFmdGVyQ29sbGlzaW9ucyA9IGZ1bmN0aW9uKHBhaXJzKSB7XFxuICAgICAgICB2Y
2XIgbW90aW9uU2xlZXBUaHJlc2hvbGQgPSBTbGVlcGluZy5fbW90aW9uU2xlZXBUaHJlc2hvbGQ7XFxuXFxuICAgICAgICAvLyB3YWtlIHVwIGJvZGllcyBpbnZvbHZlZCBpbiBjb2xsaXNpb25zXFxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHBhaXJzLmxlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgdmFyIHBhaXIgPSBwYWlyc1tpXTtcXG4gICAgICAgICAgICBcXG4gICAgICAgICAgICAvLyBkb24ndCB3YWtlIGluYWN0aXZlIHBhaXJzXFxuICAgICAgICAgICAgaWYgKCFwYWlyLmlzQWN0aXZlKVxcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcXG5cXG4gICAgICAgICAgICB2YXIgY29sbGlzaW9uID0gcGFpci5jb2xsaXNpb24sXFxuICAgICAgICAgICAgICAgIGJvZHlBID0gY29sbGlzaW9uLmJvZHlBLnBhcmVudCwgXFxuICAgICAgICAgICAgICAgIGJvZHlCID0gY29sbGlzaW9uLmJvZHlCLnBhcmVudDtcXG4gICAgICAgIFxcbiAgICAgICAgICAgIC8vIGRvbid0IHdha2UgaWYgYXQgbGVhc3Qgb25lIGJvZHkgaXMgc3RhdGljXFxuICAgICAgICAgICAgaWYgKChib2R5QS5pc1NsZWVwaW5nICYmIGJvZHlCLmlzU2xlZXBpbmcpIHx8IGJvZHlBLmlzU3RhdGljIHx8IGJvZHlCLmlzU3RhdGljKVxcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcXG4gICAgICAgIFxcbiAgICAgICAgICAgIGlmIChib2R5QS5pc1NsZWVwaW5nIHx8IGJvZHlCLmlzU2xlZXBpbmcpIHtcXG4gICAgICAgICAgICAgICAgdmFyIHNsZWVwaW5nQm9keSA9IChib2R5QS5pc1NsZWVwaW5nICYmICFib2R5QS5pc1N0YXRpYykgPyBib2R5QSA6IGJvZHlCLFxcbiAgICAgICAgICAgICAgICAgICAgbW92aW5nQm9keSA9IHNsZWVwaW5nQm9keSA9PT0gYm9keUEgPyBib2R5QiA6IGJvZHlBO1xcblxcbiAgICAgICAgICAgICAgICBpZiAoIXNsZWVwaW5nQm9keS5pc1N0YXRpYyAmJiBtb3ZpbmdCb2R5Lm1vdGlvbiA+IG1vdGlvblNsZWVwVGhyZXNob2xkKSB7XFxuICAgICAgICAgICAgICAgICAgICBTbGVlcGluZy5zZXQoc2xlZXBpbmdCb2R5LCBmYWxzZSk7XFxuICAgICAgICAgICAgICAgIH1cXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuICAgIH07XFxuICBcXG4gICAgLyoqXFxuICAgICAqIFNldCBhIGJvZHkgYXMgc2xlZXBpbmcgb3IgYXdha2UuXFxuICAgICAqIEBtZXRob2Qgc2V0XFxuICAgICAqIEBwYXJhbSB7Ym9keX0gYm9keVxcbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IGlzU2xlZXBpbmdcXG4gICAgICovXFxuICAgIFNsZWVwaW5nLnNldCA9IGZ1bmN0aW9uKGJvZHksIGlzU2xlZXBpbmcpIHtcXG4gICAgICAgIHZhciB3YXNTbGVlcGluZyA9IGJvZHkuaXNTbGVlcGluZztcXG5cXG4gICAgICAgIGlmIChpc1NsZWVwaW5nKSB7XFxuICAgICAgICAgICAgYm9keS5pc1NsZWVwaW5nID0gdHJ1ZTtcXG4gICAgICAgICAgICBib2R5LnNsZWVwQ291bnRlciA9IGJvZHkuc2xlZXBUaHJlc2hvbGQ7XFxuXFxuICAgICAgICAgICAgYm9keS5wb3NpdGlvbkltcHVsc2UueCA9IDA7XFxuICAgICAgICAgICAgYm9keS5wb3NpdGlvbkltcHVsc2UueSA9IDA7XFxuXFxuICAgICAgICAgICAgYm9keS5wb3NpdGlvblByZXYueCA9IGJvZHkucG9zaXRpb24ueDtcXG4gICAgICAgICAgICBib2R5LnBvc2l0aW9uUHJldi55ID0gYm9keS5wb3NpdGlvbi55O1xcblxcbiAgICAgICAgICAgIGJvZHkuYW5nbGVQcmV2ID0gYm9keS5hbmdsZTtcXG4gICAgICAgICAgICBib2R5LnNwZWVkID0gMDtcXG4gICAgICAgICAgICBib2R5LmFuZ3VsYXJTcGVlZCA9IDA7XFxuICAgICAgICAgICAgYm9keS5tb3Rpb24gPSAwO1xcblxcbiAgICAgICAgICAgIGlmICghd2FzU2xlZXBpbmcpIHtcXG4gICAgICAgICAgICAgICAgRXZlbnRzLnRyaWdnZXIoYm9keSwgJ3NsZWVwU3RhcnQnKTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgIGJvZHkuaXNTbGVlcGluZyA9IGZhbHNlO1xcbiAgICAgICAgICAgIGJvZHkuc2xlZXBDb3VudGVyID0gMDtcXG5cXG4gICAgICAgICAgICBpZiAod2FzU2xlZXBpbmcpIHtcXG4gICAgICAgICAgICAgICAgRXZlbnRzLnRyaWdnZXIoYm9keSwgJ3NsZWVwRW5kJyk7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcbiAgICB9O1xcblxcbn0pKCk7XFxuXFxuXFxuLyoqKi8gfSksXFxuLyogOCAqL1xcbi8qKiovIChmdW5jdGlvbihtb2R1bGUsIGV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pIHtcXG5cXG4vKipcXG4qIFRoZSBgTWF0dGVyLkNvbGxpc2lvbmAgbW9kdWxlIGNvbnRhaW5zIG1ldGhvZHMgZm9yIGRldGVjdGluZyBjb2xsaXNpb25zIGJldHdlZW4gYSBnaXZlbiBwYWlyIG9mIGJvZGllcy5cXG4qXFxuKiBGb3IgZWZmaWNpZW50IGRldGVjdGlvbiBiZXR3ZWVuIGEgbGlzdCBvZiBib2RpZXMsIHNlZSBgTWF0dGVyLkRldGVjdG9yYCBhbmQgYE1hdHRlci5RdWVyeWAuXFxuKlxcbiogU2VlIGBNYXR0ZXIuRW5naW5lYCBmb3IgY29sbGlzaW9uIGV2ZW50cy5cXG4qXFxuKiBAY2xhc3MgQ29sbGlzaW9uXFxuKi9cXG5cXG52YXIgQ29sbGlzaW9uID0ge307XFxuXFxubW9kdWxlLmV4cG9ydHMgPSBDb2xsaXNpb247XFxuXFxudmFyIFZlcnRpY2VzID0gX193ZWJwYWNrX3JlcXVpcmVfXygzKTtcXG52YXIgUGFpciA9IF9fd2VicGFja19yZXF1aXJlX18oOSk7XFxuXFxuKGZ1bmN0aW9uKCkge1xcbiAgICB2YXIgX3N1cHBvcnRzID0gW107XFxuXFxuICAgIHZhciBfb3ZlcmxhcEFCID0ge1xcbiAgICAgICAgb3ZlcmxhcDogMCxcXG4gICAgICAgIGF4aXM6IG51bGxcXG4gICAgfTtcXG5cXG4gICAgdmFyIF9vdmVybGFwQkEgPSB7XFxuICAgICAgICBvdmVybGFwOiAwLFxcbiAgICAgICAgYXhpczogbnVsbFxcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogQ3JlYXRlcyBhIG5ldyBjb2xsaXNpb24gcmVjb3JkLlxcbiAgICAgKiBAbWV0aG9kIGNyZWF0ZVxcbiAgICAgKiBAcGFyYW0ge2JvZHl9IGJvZHlBIFRoZSBmaXJzdCBib2R5IHBhcnQgcmVwcmVzZW50ZWQgYnkgdGhlIGNvbGxpc2lvbiByZWNvcmRcXG4gICAgICogQHBhcmFtIHtib2R5fSBib2R5QiBUaGUgc2Vjb25kIGJvZHkgcGFydCByZXByZXNlbnRlZCBieSB0aGUgY29sbGlzaW9uIHJlY29yZFxcbiAgICAgKiBAcmV0dXJuIHtjb2xsaXNpb259IEEgbmV3IGNvbGxpc2lvbiByZWNvcmRcXG4gICAgICovXFxuICAgIENvbGxpc2lvbi5jcmVhdGUgPSBmdW5jdGlvbihib2R5QSwgYm9keUIpIHtcXG4gICAgICAgI
2HJldHVybiB7IFxcbiAgICAgICAgICAgIHBhaXI6IG51bGwsXFxuICAgICAgICAgICAgY29sbGlkZWQ6IGZhbHNlLFxcbiAgICAgICAgICAgIGJvZHlBOiBib2R5QSxcXG4gICAgICAgICAgICBib2R5QjogYm9keUIsXFxuICAgICAgICAgICAgcGFyZW50QTogYm9keUEucGFyZW50LFxcbiAgICAgICAgICAgIHBhcmVudEI6IGJvZHlCLnBhcmVudCxcXG4gICAgICAgICAgICBkZXB0aDogMCxcXG4gICAgICAgICAgICBub3JtYWw6IHsgeDogMCwgeTogMCB9LFxcbiAgICAgICAgICAgIHRhbmdlbnQ6IHsgeDogMCwgeTogMCB9LFxcbiAgICAgICAgICAgIHBlbmV0cmF0aW9uOiB7IHg6IDAsIHk6IDAgfSxcXG4gICAgICAgICAgICBzdXBwb3J0czogW11cXG4gICAgICAgIH07XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBEZXRlY3QgY29sbGlzaW9uIGJldHdlZW4gdHdvIGJvZGllcy5cXG4gICAgICogQG1ldGhvZCBjb2xsaWRlc1xcbiAgICAgKiBAcGFyYW0ge2JvZHl9IGJvZHlBXFxuICAgICAqIEBwYXJhbSB7Ym9keX0gYm9keUJcXG4gICAgICogQHBhcmFtIHtwYWlyc30gW3BhaXJzXSBPcHRpb25hbGx5IHJldXNlIGNvbGxpc2lvbiByZWNvcmRzIGZyb20gZXhpc3RpbmcgcGFpcnMuXFxuICAgICAqIEByZXR1cm4ge2NvbGxpc2lvbnxudWxsfSBBIGNvbGxpc2lvbiByZWNvcmQgaWYgZGV0ZWN0ZWQsIG90aGVyd2lzZSBudWxsXFxuICAgICAqL1xcbiAgICBDb2xsaXNpb24uY29sbGlkZXMgPSBmdW5jdGlvbihib2R5QSwgYm9keUIsIHBhaXJzKSB7XFxuICAgICAgICBDb2xsaXNpb24uX292ZXJsYXBBeGVzKF9vdmVybGFwQUIsIGJvZHlBLnZlcnRpY2VzLCBib2R5Qi52ZXJ0aWNlcywgYm9keUEuYXhlcyk7XFxuXFxuICAgICAgICBpZiAoX292ZXJsYXBBQi5vdmVybGFwIDw9IDApIHtcXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIENvbGxpc2lvbi5fb3ZlcmxhcEF4ZXMoX292ZXJsYXBCQSwgYm9keUIudmVydGljZXMsIGJvZHlBLnZlcnRpY2VzLCBib2R5Qi5heGVzKTtcXG5cXG4gICAgICAgIGlmIChfb3ZlcmxhcEJBLm92ZXJsYXAgPD0gMCkge1xcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgLy8gcmV1c2UgY29sbGlzaW9uIHJlY29yZHMgZm9yIGdjIGVmZmljaWVuY3lcXG4gICAgICAgIHZhciBwYWlyID0gcGFpcnMgJiYgcGFpcnMudGFibGVbUGFpci5pZChib2R5QSwgYm9keUIpXSxcXG4gICAgICAgICAgICBjb2xsaXNpb247XFxuXFxuICAgICAgICBpZiAoIXBhaXIpIHtcXG4gICAgICAgICAgICBjb2xsaXNpb24gPSBDb2xsaXNpb24uY3JlYXRlKGJvZHlBLCBib2R5Qik7XFxuICAgICAgICAgICAgY29sbGlzaW9uLmNvbGxpZGVkID0gdHJ1ZTtcXG4gICAgICAgICAgICBjb2xsaXNpb24uYm9keUEgPSBib2R5QS5pZCA8IGJvZHlCLmlkID8gYm9keUEgOiBib2R5QjtcXG4gICAgICAgICAgICBjb2xsaXNpb24uYm9keUIgPSBib2R5QS5pZCA8IGJvZHlCLmlkID8gYm9keUIgOiBib2R5QTtcXG4gICAgICAgICAgICBjb2xsaXNpb24ucGFyZW50QSA9IGNvbGxpc2lvbi5ib2R5QS5wYXJlbnQ7XFxuICAgICAgICAgICAgY29sbGlzaW9uLnBhcmVudEIgPSBjb2xsaXNpb24uYm9keUIucGFyZW50O1xcbiAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICBjb2xsaXNpb24gPSBwYWlyLmNvbGxpc2lvbjtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIGJvZHlBID0gY29sbGlzaW9uLmJvZHlBO1xcbiAgICAgICAgYm9keUIgPSBjb2xsaXNpb24uYm9keUI7XFxuXFxuICAgICAgICB2Y
2XIgbWluT3ZlcmxhcDtcXG5cXG4gICAgICAgIGlmIChfb3ZlcmxhcEFCLm92ZXJsYXAgPCBfb3ZlcmxhcEJBLm92ZXJsYXApIHtcXG4gICAgICAgICAgICBtaW5PdmVybGFwID0gX292ZXJsYXBBQjtcXG4gICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgbWluT3ZlcmxhcCA9IF9vdmVybGFwQkE7XFxuICAgICAgICB9XFxuXFxuICAgICAgICB2YXIgbm9ybWFsID0gY29sbGlzaW9uLm5vcm1hbCxcXG4gICAgICAgICAgICBzdXBwb3J0cyA9IGNvbGxpc2lvbi5zdXBwb3J0cyxcXG4gICAgICAgICAgICBtaW5BeGlzID0gbWluT3ZlcmxhcC5heGlzLFxcbiAgICAgICAgICAgIG1pbkF4aXNYID0gbWluQXhpcy54LFxcbiAgICAgICAgICAgIG1pbkF4aXNZID0gbWluQXhpcy55O1xcblxcbiAgICAgICAgLy8gZW5zdXJlIG5vcm1hbCBpcyBmYWNpbmcgYXdheSBmcm9tIGJvZHlBXFxuICAgICAgICBpZiAobWluQXhpc1ggKiAoYm9keUIucG9zaXRpb24ueCAtIGJvZHlBLnBvc2l0aW9uLngpICsgbWluQXhpc1kgKiAoYm9keUIucG9zaXRpb24ueSAtIGJvZHlBLnBvc2l0aW9uLnkpIDwgMCkge1xcbiAgICAgICAgICAgIG5vcm1hbC54ID0gbWluQXhpc1g7XFxuICAgICAgICAgICAgbm9ybWFsLnkgPSBtaW5BeGlzWTtcXG4gICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgbm9ybWFsLnggPSAtbWluQXhpc1g7XFxuICAgICAgICAgICAgbm9ybWFsLnkgPSAtbWluQXhpc1k7XFxuICAgICAgICB9XFxuICAgICAgICBcXG4gICAgICAgIGNvbGxpc2lvbi50YW5nZW50LnggPSAtbm9ybWFsLnk7XFxuICAgICAgICBjb2xsaXNpb24udGFuZ2VudC55ID0gbm9ybWFsLng7XFxuXFxuICAgICAgICBjb2xsaXNpb24uZGVwdGggPSBtaW5PdmVybGFwLm92ZXJsYXA7XFxuXFxuICAgICAgICBjb2xsaXNpb24ucGVuZXRyYXRpb24ueCA9IG5vcm1hbC54ICogY29sbGlzaW9uLmRlcHRoO1xcbiAgICAgICAgY29sbGlzaW9uLnBlbmV0cmF0aW9uLnkgPSBub3JtYWwueSAqIGNvbGxpc2lvbi5kZXB0aDtcXG5cXG4gICAgICAgIC8vIGZpbmQgc3VwcG9ydCBwb2ludHMsIHRoZXJlIGlzIGFsd2F5cyBlaXRoZXIgZXhhY3RseSBvbmUgb3IgdHdvXFxuICAgICAgICB2Y
2XIgc3VwcG9ydHNCID0gQ29sbGlzaW9uLl9maW5kU3VwcG9ydHMoYm9keUEsIGJvZHlCLCBub3JtYWwsIDEpLFxcbiAgICAgICAgICAgIHN1cHBvcnRDb3VudCA9IDA7XFxuXFxuICAgICAgICAvLyBmaW5kIHRoZSBzdXBwb3J0cyBmcm9tIGJvZHlCIHRoYXQgYXJlIGluc2lkZSBib2R5QVxcbiAgICAgICAgaWYgKFZlcnRpY2VzLmNvbnRhaW5zKGJvZHlBLnZlcnRpY2VzLCBzdXBwb3J0c0JbMF0pKSB7XFxuICAgICAgICAgICAgc3VwcG9ydHNbc3VwcG9ydENvdW50KytdID0gc3VwcG9ydHNCWzBdO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgaWYgKFZlcnRpY2VzLmNvbnRhaW5zKGJvZHlBLnZlcnRpY2VzLCBzdXBwb3J0c0JbMV0pKSB7XFxuICAgICAgICAgICAgc3VwcG9ydHNbc3VwcG9ydENvdW50KytdID0gc3VwcG9ydHNCWzFdO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgLy8gZmluZCB0aGUgc3VwcG9ydHMgZnJvbSBib2R5QSB0aGF0IGFyZSBpbnNpZGUgYm9keUJcXG4gICAgICAgIGlmIChzdXBwb3J0Q291bnQgPCAyKSB7XFxuICAgICAgICAgICAgdmFyIHN1cHBvcnRzQSA9IENvbGxpc2lvbi5fZmluZFN1cHBvcnRzKGJvZHlCLCBib2R5QSwgbm9ybWFsLCAtMSk7XFxuXFxuICAgICAgICAgICAgaWYgKFZlcnRpY2VzLmNvbnRhaW5zKGJvZHlCLnZlcnRpY2VzLCBzdXBwb3J0c0FbMF0pKSB7XFxuICAgICAgICAgICAgICAgIHN1cHBvcnRzW3N1cHBvcnRDb3VudCsrXSA9IHN1cHBvcnRzQVswXTtcXG4gICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgaWYgKHN1cHBvcnRDb3VudCA8IDIgJiYgVmVydGljZXMuY29udGFpbnMoYm9keUIudmVydGljZXMsIHN1cHBvcnRzQVsxXSkpIHtcXG4gICAgICAgICAgICAgICAgc3VwcG9ydHNbc3VwcG9ydENvdW50KytdID0gc3VwcG9ydHNBWzFdO1xcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG5cXG4gICAgICAgIC8vIGFjY291bnQgZm9yIHRoZSBlZGdlIGNhc2Ugb2Ygb3ZlcmxhcHBpbmcgYnV0IG5vIHZlcnRleCBjb250YWlubWVudFxcbiAgICAgICAgaWYgKHN1cHBvcnRDb3VudCA9PT0gMCkge1xcbiAgICAgICAgICAgIHN1cHBvcnRzW3N1cHBvcnRDb3VudCsrXSA9IHN1cHBvcnRzQlswXTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIC8vIHVwZGF0ZSBzdXBwb3J0cyBhcnJheSBzaXplXFxuICAgICAgICBzdXBwb3J0cy5sZW5ndGggPSBzdXBwb3J0Q291bnQ7XFxuXFxuICAgICAgICByZXR1cm4gY29sbGlzaW9uO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogRmluZCB0aGUgb3ZlcmxhcCBiZXR3ZWVuIHR3byBzZXRzIG9mIHZlcnRpY2VzLlxcbiAgICAgKiBAbWV0aG9kIF9vdmVybGFwQXhlc1xcbiAgICAgKiBAcHJpdmF0ZVxcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gcmVzdWx0XFxuICAgICAqIEBwYXJhbSB7dmVydGljZXN9IHZlcnRpY2VzQVxcbiAgICAgKiBAcGFyYW0ge3ZlcnRpY2VzfSB2ZXJ0aWNlc0JcXG4gICAgICogQHBhcmFtIHtheGVzfSBheGVzXFxuICAgICAqL1xcbiAgICBDb2xsaXNpb24uX292ZXJsYXBBeGVzID0gZnVuY3Rpb24ocmVzdWx0LCB2ZXJ0aWNlc0EsIHZlcnRpY2VzQiwgYXhlcykge1xcbiAgICAgICAgdmFyIHZlcnRpY2VzQUxlbmd0aCA9IHZlcnRpY2VzQS5sZW5ndGgsXFxuICAgICAgICAgICAgdmVydGljZXNCTGVuZ3RoID0gdmVydGljZXNCLmxlbmd0aCxcXG4gICAgICAgICAgICB2ZXJ0aWNlc0FYID0gdmVydGljZXNBWzBdLngsXFxuICAgICAgICAgICAgdmVydGljZXNBWSA9IHZlcnRpY2VzQVswXS55LFxcbiAgICAgICAgICAgIHZlcnRpY2VzQlggPSB2ZXJ0aWNlc0JbMF0ueCxcXG4gICAgICAgICAgICB2ZXJ0aWNlc0JZID0gdmVydGljZXNCWzBdLnksXFxuICAgICAgICAgICAgYXhlc0xlbmd0aCA9IGF4ZXMubGVuZ3RoLFxcbiAgICAgICAgICAgIG92ZXJsYXBNaW4gPSBOdW1iZXIuTUFYX1ZBTFVFLFxcbiAgICAgICAgICAgIG92ZXJsYXBBeGlzTnVtYmVyID0gMCxcXG4gICAgICAgICAgICBvdmVybGFwLFxcbiAgICAgICAgICAgIG92ZXJsYXBBQixcXG4gICAgICAgICAgICBvdmVybGFwQkEsXFxuICAgICAgICAgICAgZG90LFxcbiAgICAgICAgICAgIGksXFxuICAgICAgICAgICAgajtcXG5cXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBheGVzTGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICB2Y
2XIgYXhpcyA9IGF4ZXNbaV0sXFxuICAgICAgICAgICAgICAgIGF4aXNYID0gYXhpcy54LFxcbiAgICAgICAgICAgICAgICBheGlzWSA9IGF4aXMueSxcXG4gICAgICAgICAgICAgICAgbWluQSA9IHZlcnRpY2VzQVggKiBheGlzWCArIHZlcnRpY2VzQVkgKiBheGlzWSxcXG4gICAgICAgICAgICAgICAgbWluQiA9IHZlcnRpY2VzQlggKiBheGlzWCArIHZlcnRpY2VzQlkgKiBheGlzWSxcXG4gICAgICAgICAgICAgICAgbWF4QSA9IG1pbkEsXFxuICAgICAgICAgICAgICAgIG1heEIgPSBtaW5CO1xcbiAgICAgICAgICAgIFxcbiAgICAgICAgICAgIGZvciAoaiA9IDE7IGogPCB2ZXJ0aWNlc0FMZW5ndGg7IGogKz0gMSkge1xcbiAgICAgICAgICAgICAgICBkb3QgPSB2ZXJ0aWNlc0Fbal0ueCAqIGF4aXNYICsgdmVydGljZXNBW2pdLnkgKiBheGlzWTtcXG5cXG4gICAgICAgICAgICAgICAgaWYgKGRvdCA+IG1heEEpIHsgXFxuICAgICAgICAgICAgICAgICAgICBtYXhBID0gZG90O1xcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGRvdCA8IG1pbkEpIHsgXFxuICAgICAgICAgICAgICAgICAgICBtaW5BID0gZG90O1xcbiAgICAgICAgICAgICAgICB9XFxuICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgIGZvciAoaiA9IDE7IGogPCB2ZXJ0aWNlc0JMZW5ndGg7IGogKz0gMSkge1xcbiAgICAgICAgICAgICAgICBkb3QgPSB2ZXJ0aWNlc0Jbal0ueCAqIGF4aXNYICsgdmVydGljZXNCW2pdLnkgKiBheGlzWTtcXG5cXG4gICAgICAgICAgICAgICAgaWYgKGRvdCA+IG1heEIpIHsgXFxuICAgICAgICAgICAgICAgICAgICBtYXhCID0gZG90O1xcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGRvdCA8IG1pbkIpIHsgXFxuICAgICAgICAgICAgICAgICAgICBtaW5CID0gZG90O1xcbiAgICAgICAgICAgICAgICB9XFxuICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgIG92ZXJsYXBBQiA9IG1heEEgLSBtaW5CO1xcbiAgICAgICAgICAgIG92ZXJsYXBCQSA9IG1heEIgLSBtaW5BO1xcbiAgICAgICAgICAgIG92ZXJsYXAgPSBvdmVybGFwQUIgPCBvdmVybGFwQkEgPyBvdmVybGFwQUIgOiBvdmVybGFwQkE7XFxuXFxuICAgICAgICAgICAgaWYgKG92ZXJsYXAgPCBvdmVybGFwTWluKSB7XFxuICAgICAgICAgICAgICAgIG92ZXJsYXBNaW4gPSBvdmVybGFwO1xcbiAgICAgICAgICAgICAgICBvdmVybGFwQXhpc051bWJlciA9IGk7XFxuXFxuICAgICAgICAgICAgICAgIGlmIChvdmVybGFwIDw9IDApIHtcXG4gICAgICAgICAgICAgICAgICAgIC8vIGNhbiBub3QgYmUgaW50ZXJzZWN0aW5nXFxuICAgICAgICAgICAgICAgICAgICBicmVhaztcXG4gICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgIH0gXFxuICAgICAgICB9XFxuXFxuICAgICAgICByZXN1bHQuYXhpcyA9IGF4ZXNbb3ZlcmxhcEF4aXNOdW1iZXJdO1xcbiAgICAgICAgcmVzdWx0Lm92ZXJsYXAgPSBvdmVybGFwTWluO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUHJvamVjdHMgdmVydGljZXMgb24gYW4gYXhpcyBhbmQgcmV0dXJucyBhbiBpbnRlcnZhbC5cXG4gICAgICogQG1ldGhvZCBfcHJvamVjdFRvQXhpc1xcbiAgICAgKiBAcHJpdmF0ZVxcbiAgICAgKiBAcGFyYW0ge30gcHJvamVjdGlvblxcbiAgICAgKiBAcGFyYW0ge30gdmVydGljZXNcXG4gICAgICogQHBhcmFtIHt9IGF4aXNcXG4gICAgICovXFxuICAgIENvbGxpc2lvbi5fcHJvamVjdFRvQXhpcyA9IGZ1bmN0aW9uKHByb2plY3Rpb24sIHZlcnRpY2VzLCBheGlzKSB7XFxuICAgICAgICB2Y
2XIgbWluID0gdmVydGljZXNbMF0ueCAqIGF4aXMueCArIHZlcnRpY2VzWzBdLnkgKiBheGlzLnksXFxuICAgICAgICAgICAgbWF4ID0gbWluO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDE7IGkgPCB2ZXJ0aWNlcy5sZW5ndGg7IGkgKz0gMSkge1xcbiAgICAgICAgICAgIHZhciBkb3QgPSB2ZXJ0aWNlc1tpXS54ICogYXhpcy54ICsgdmVydGljZXNbaV0ueSAqIGF4aXMueTtcXG5cXG4gICAgICAgICAgICBpZiAoZG90ID4gbWF4KSB7IFxcbiAgICAgICAgICAgICAgICBtYXggPSBkb3Q7IFxcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoZG90IDwgbWluKSB7IFxcbiAgICAgICAgICAgICAgICBtaW4gPSBkb3Q7IFxcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHByb2plY3Rpb24ubWluID0gbWluO1xcbiAgICAgICAgcHJvamVjdGlvbi5tYXggPSBtYXg7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBGaW5kcyBzdXBwb3J0aW5nIHZlcnRpY2VzIGdpdmVuIHR3byBib2RpZXMgYWxvbmcgYSBnaXZlbiBkaXJlY3Rpb24gdXNpbmcgaGlsbC1jbGltYmluZy5cXG4gICAgICogQG1ldGhvZCBfZmluZFN1cHBvcnRzXFxuICAgICAqIEBwcml2YXRlXFxuICAgICAqIEBwYXJhbSB7Ym9keX0gYm9keUFcXG4gICAgICogQHBhcmFtIHtib2R5fSBib2R5QlxcbiAgICAgKiBAcGFyYW0ge3ZlY3Rvcn0gbm9ybWFsXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBkaXJlY3Rpb25cXG4gICAgICogQHJldHVybiBbdmVjdG9yXVxcbiAgICAgKi9cXG4gICAgQ29sbGlzaW9uLl9maW5kU3VwcG9ydHMgPSBmdW5jdGlvbihib2R5QSwgYm9keUIsIG5vcm1hbCwgZGlyZWN0aW9uKSB7XFxuICAgICAgICB2Y
2XIgdmVydGljZXMgPSBib2R5Qi52ZXJ0aWNlcyxcXG4gICAgICAgICAgICB2ZXJ0aWNlc0xlbmd0aCA9IHZlcnRpY2VzLmxlbmd0aCxcXG4gICAgICAgICAgICBib2R5QVBvc2l0aW9uWCA9IGJvZHlBLnBvc2l0aW9uLngsXFxuICAgICAgICAgICAgYm9keUFQb3NpdGlvblkgPSBib2R5QS5wb3NpdGlvbi55LFxcbiAgICAgICAgICAgIG5vcm1hbFggPSBub3JtYWwueCAqIGRpcmVjdGlvbixcXG4gICAgICAgICAgICBub3JtYWxZID0gbm9ybWFsLnkgKiBkaXJlY3Rpb24sXFxuICAgICAgICAgICAgbmVhcmVzdERpc3RhbmNlID0gTnVtYmVyLk1BWF9WQUxVRSxcXG4gICAgICAgICAgICB2ZXJ0ZXhBLFxcbiAgICAgICAgICAgIHZlcnRleEIsXFxuICAgICAgICAgICAgdmVydGV4QyxcXG4gICAgICAgICAgICBkaXN0YW5jZSxcXG4gICAgICAgICAgICBqO1xcblxcbiAgICAgICAgLy8gZmluZCBkZWVwZXN0IHZlcnRleCByZWxhdGl2ZSB0byB0aGUgYXhpc1xcbiAgICAgICAgZm9yIChqID0gMDsgaiA8IHZlcnRpY2VzTGVuZ3RoOyBqICs9IDEpIHtcXG4gICAgICAgICAgICB2ZXJ0ZXhCID0gdmVydGljZXNbal07XFxuICAgICAgICAgICAgZGlzdGFuY2UgPSBub3JtYWxYICogKGJvZHlBUG9zaXRpb25YIC0gdmVydGV4Qi54KSArIG5vcm1hbFkgKiAoYm9keUFQb3NpdGlvblkgLSB2ZXJ0ZXhCLnkpO1xcblxcbiAgICAgICAgICAgIC8vIGNvbnZleCBoaWxsLWNsaW1iaW5nXFxuICAgICAgICAgICAgaWYgKGRpc3RhbmNlIDwgbmVhcmVzdERpc3RhbmNlKSB7XFxuICAgICAgICAgICAgICAgIG5lYXJlc3REaXN0YW5jZSA9IGRpc3RhbmNlO1xcbiAgICAgICAgICAgICAgICB2ZXJ0ZXhBID0gdmVydGV4QjtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuXFxuICAgICAgICAvLyBtZWFzdXJlIG5leHQgdmVydGV4XFxuICAgICAgICB2ZXJ0ZXhDID0gdmVydGljZXNbKHZlcnRpY2VzTGVuZ3RoICsgdmVydGV4QS5pbmRleCAtIDEpICUgdmVydGljZXNMZW5ndGhdO1xcbiAgICAgICAgbmVhcmVzdERpc3RhbmNlID0gbm9ybWFsWCAqIChib2R5QVBvc2l0aW9uWCAtIHZlcnRleEMueCkgKyBub3JtYWxZICogKGJvZHlBUG9zaXRpb25ZIC0gdmVydGV4Qy55KTtcXG5cXG4gICAgICAgIC8vIGNvbXBhcmUgd2l0aCBwcmV2aW91cyB2ZXJ0ZXhcXG4gICAgICAgIHZlcnRleEIgPSB2ZXJ0aWNlc1sodmVydGV4QS5pbmRleCArIDEpICUgdmVydGljZXNMZW5ndGhdO1xcbiAgICAgICAgaWYgKG5vcm1hbFggKiAoYm9keUFQb3NpdGlvblggLSB2ZXJ0ZXhCLngpICsgbm9ybWFsWSAqIChib2R5QVBvc2l0aW9uWSAtIHZlcnRleEIueSkgPCBuZWFyZXN0RGlzdGFuY2UpIHtcXG4gICAgICAgICAgICBfc3VwcG9ydHNbMF0gPSB2ZXJ0ZXhBO1xcbiAgICAgICAgICAgIF9zdXBwb3J0c1sxXSA9IHZlcnRleEI7XFxuXFxuICAgICAgICAgICAgcmV0dXJuIF9zdXBwb3J0cztcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIF9zdXBwb3J0c1swXSA9IHZlcnRleEE7XFxuICAgICAgICBfc3VwcG9ydHNbMV0gPSB2ZXJ0ZXhDO1xcblxcbiAgICAgICAgcmV0dXJuIF9zdXBwb3J0cztcXG4gICAgfTtcXG5cXG4gICAgLypcXG4gICAgKlxcbiAgICAqICBQcm9wZXJ0aWVzIERvY3VtZW50YXRpb25cXG4gICAgKlxcbiAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSByZWZlcmVuY2UgdG8gdGhlIHBhaXIgdXNpbmcgdGhpcyBjb2xsaXNpb24gcmVjb3JkLCBpZiB0aGVyZSBpcyBvbmUuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBwYWlyXFxuICAgICAqIEB0eXBlIHtwYWlyfG51bGx9XFxuICAgICAqIEBkZWZhdWx0IG51bGxcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGZsYWcgdGhhdCBpbmRpY2F0ZXMgaWYgdGhlIGJvZGllcyB3ZXJlIGNvbGxpZGluZyB3aGVuIHRoZSBjb2xsaXNpb24gd2FzIGxhc3QgdXBkYXRlZC5cXG4gICAgICogXFxuICAgICAqIEBwcm9wZXJ0eSBjb2xsaWRlZFxcbiAgICAgKiBAdHlwZSBib29sZWFuXFxuICAgICAqIEBkZWZhdWx0IGZhbHNlXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogVGhlIGZpcnN0IGJvZHkgcGFydCByZXByZXNlbnRlZCBieSB0aGUgY29sbGlzaW9uIChzZWUgYWxzbyBgY29sbGlzaW9uLnBhcmVudEFgKS5cXG4gICAgICogXFxuICAgICAqIEBwcm9wZXJ0eSBib2R5QVxcbiAgICAgKiBAdHlwZSBib2R5XFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogVGhlIHNlY29uZCBib2R5IHBhcnQgcmVwcmVzZW50ZWQgYnkgdGhlIGNvbGxpc2lvbiAoc2VlIGFsc28gYGNvbGxpc2lvbi5wYXJlbnRCYCkuXFxuICAgICAqIFxcbiAgICAgKiBAcHJvcGVydHkgYm9keUJcXG4gICAgICogQHR5cGUgYm9keVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIFRoZSBmaXJzdCBib2R5IHJlcHJlc2VudGVkIGJ5IHRoZSBjb2xsaXNpb24gKGkuZS4gYGNvbGxpc2lvbi5ib2R5QS5wYXJlbnRgKS5cXG4gICAgICogXFxuICAgICAqIEBwcm9wZXJ0eSBwYXJlbnRBXFxuICAgICAqIEB0eXBlIGJvZHlcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBUaGUgc2Vjb25kIGJvZHkgcmVwcmVzZW50ZWQgYnkgdGhlIGNvbGxpc2lvbiAoaS5lLiBgY29sbGlzaW9uLmJvZHlCLnBhcmVudGApLlxcbiAgICAgKiBcXG4gICAgICogQHByb3BlcnR5IHBhcmVudEJcXG4gICAgICogQHR5cGUgYm9keVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEEgYE51bWJlcmAgdGhhdCByZXByZXNlbnRzIHRoZSBtaW5pbXVtIHNlcGFyYXRpbmcgZGlzdGFuY2UgYmV0d2VlbiB0aGUgYm9kaWVzIGFsb25nIHRoZSBjb2xsaXNpb24gbm9ybWFsLlxcbiAgICAgKlxcbiAgICAgKiBAcmVhZE9ubHlcXG4gICAgICogQHByb3BlcnR5IGRlcHRoXFxuICAgICAqIEB0eXBlIG51bWJlclxcbiAgICAgKiBAZGVmYXVsdCAwXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBub3JtYWxpc2VkIGBWZWN0b3JgIHRoYXQgcmVwcmVzZW50cyB0aGUgZGlyZWN0aW9uIGJldHdlZW4gdGhlIGJvZGllcyB0aGF0IHByb3ZpZGVzIHRoZSBtaW5pbXVtIHNlcGFyYXRpbmcgZGlzdGFuY2UuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBub3JtYWxcXG4gICAgICogQHR5cGUgdmVjdG9yXFxuICAgICAqIEBkZWZhdWx0IHsgeDogMCwgeTogMCB9XFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBub3JtYWxpc2VkIGBWZWN0b3JgIHRoYXQgaXMgdGhlIHRhbmdlbnQgZGlyZWN0aW9uIHRvIHRoZSBjb2xsaXNpb24gbm9ybWFsLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgdGFuZ2VudFxcbiAgICAgKiBAdHlwZSB2ZWN0b3JcXG4gICAgICogQGRlZmF1bHQgeyB4OiAwLCB5OiAwIH1cXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGBWZWN0b3JgIHRoYXQgcmVwcmVzZW50cyB0aGUgZGlyZWN0aW9uIGFuZCBkZXB0aCBvZiB0aGUgY29sbGlzaW9uLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgcGVuZXRyYXRpb25cXG4gICAgICogQHR5cGUgdmVjdG9yXFxuICAgICAqIEBkZWZhdWx0IHsgeDogMCwgeTogMCB9XFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQW4gYXJyYXkgb2YgYm9keSB2ZXJ0aWNlcyB0aGF0IHJlcHJlc2VudCB0aGUgc3VwcG9ydCBwb2ludHMgaW4gdGhlIGNvbGxpc2lvbi5cXG4gICAgICogVGhlc2UgYXJlIHRoZSBkZWVwZXN0IHZlcnRpY2VzIChhbG9uZyB0aGUgY29sbGlzaW9uIG5vcm1hbCkgb2YgZWFjaCBib2R5IHRoYXQgYXJlIGNvbnRhaW5lZCBieSB0aGUgb3RoZXIgYm9keSdzIHZlcnRpY2VzLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgc3VwcG9ydHNcXG4gICAgICogQHR5cGUgdmVjdG9yW11cXG4gICAgICogQGRlZmF1bHQgW11cXG4gICAgICovXFxuXFxufSkoKTtcXG5cXG5cXG4vKioqLyB9KSxcXG4vKiA5ICovXFxuLyoqKi8gKGZ1bmN0aW9uKG1vZHVsZSwgZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xcblxcbi8qKlxcbiogVGhlIGBNYXR0ZXIuUGFpcmAgbW9kdWxlIGNvbnRhaW5zIG1ldGhvZHMgZm9yIGNyZWF0aW5nIGFuZCBtYW5pcHVsYXRpbmcgY29sbGlzaW9uIHBhaXJzLlxcbipcXG4qIEBjbGFzcyBQYWlyXFxuKi9cXG5cXG52YXIgUGFpciA9IHt9O1xcblxcbm1vZHVsZS5leHBvcnRzID0gUGFpcjtcXG5cXG52YXIgQ29udGFjdCA9IF9fd2VicGFja19yZXF1aXJlX18oMTYpO1xcblxcbihmdW5jdGlvbigpIHtcXG4gICAgXFxuICAgIC8qKlxcbiAgICAgKiBDcmVhdGVzIGEgcGFpci5cXG4gICAgICogQG1ldGhvZCBjcmVhdGVcXG4gICAgICogQHBhcmFtIHtjb2xsaXNpb259IGNvbGxpc2lvblxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gdGltZXN0YW1wXFxuICAgICAqIEByZXR1cm4ge3Bh
2aXJ9IEEgbmV3IHBhaXJcXG4gICAgICovXFxuICAgIFBhaXIuY3JlYXRlID0gZnVuY3Rpb24oY29sbGlzaW9uLCB0aW1lc3RhbXApIHtcXG4gICAgICAgIHZhciBib2R5QSA9IGNvbGxpc2lvbi5ib2R5QSxcXG4gICAgICAgICAgICBib2R5QiA9IGNvbGxpc2lvbi5ib2R5QjtcXG5cXG4gICAgICAgIHZhciBwYWlyID0ge1xcbiAgICAgICAgICAgIGlkOiBQYWlyLmlkKGJvZHlBLCBib2R5QiksXFxuICAgICAgICAgICAgYm9keUE6IGJvZHlBLFxcbiAgICAgICAgICAgIGJvZHlCOiBib2R5QixcXG4gICAgICAgICAgICBjb2xsaXNpb246IGNvbGxpc2lvbixcXG4gICAgICAgICAgICBjb250YWN0czogW10sXFxuICAgICAgICAgICAgYWN0aXZlQ29udGFjdHM6IFtdLFxcbiAgICAgICAgICAgIHNlcGFyYXRpb246IDAsXFxuICAgICAgICAgICAgaXNBY3RpdmU6IHRydWUsXFxuICAgICAgICAgICAgY29uZmlybWVkQWN0aXZlOiB0cnVlLFxcbiAgICAgICAgICAgIGlzU2Vuc29yOiBib2R5QS5pc1NlbnNvciB8fCBib2R5Qi5pc1NlbnNvcixcXG4gICAgICAgICAgICB0aW1lQ3JlYXRlZDogdGltZXN0YW1wLFxcbiAgICAgICAgICAgIHRpbWVVcGRhdGVkOiB0aW1lc3RhbXAsXFxuICAgICAgICAgICAgaW52ZXJzZU1hc3M6IDAsXFxuICAgICAgICAgICAgZnJpY3Rpb246IDAsXFxuICAgICAgICAgICAgZnJpY3Rpb25TdGF0aWM6IDAsXFxuICAgICAgICAgICAgcmVzdGl0dXRpb246IDAsXFxuICAgICAgICAgICAgc2xvcDogMFxcbiAgICAgICAgfTtcXG5cXG4gICAgICAgIFBhaXIudXBkYXRlKHBhaXIsIGNvbGxpc2lvbiwgdGltZXN0YW1wKTtcXG5cXG4gICAgICAgIHJldHVybiBwYWlyO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogVXBkYXRlcyBhIHBhaXIgZ2l2ZW4gYSBjb2xsaXNpb24uXFxuICAgICAqIEBtZXRob2QgdXBkYXRlXFxuICAgICAqIEBwYXJhbSB7cGFpcn0gcGFpclxcbiAgICAgKiBAcGFyYW0ge2NvbGxpc2lvbn0gY29sbGlzaW9uXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB0aW1lc3RhbXBcXG4gICAgICovXFxuICAgIFBhaXIudXBkYXRlID0gZnVuY3Rpb24ocGFpciwgY29sbGlzaW9uLCB0aW1lc3RhbXApIHtcXG4gICAgICAgIHZhciBjb250YWN0cyA9IHBhaXIuY29udGFjdHMsXFxuICAgICAgICAgICAgc3VwcG9ydHMgPSBjb2xsaXNpb24uc3VwcG9ydHMsXFxuICAgICAgICAgICAgYWN0aXZlQ29udGFjdHMgPSBwYWlyLmFjdGl2ZUNvbnRhY3RzLFxcbiAgICAgICAgICAgIHBhcmVudEEgPSBjb2xsaXNpb24ucGFyZW50QSxcXG4gICAgICAgICAgICBwYXJlbnRCID0gY29sbGlzaW9uLnBhcmVudEIsXFxuICAgICAgICAgICAgcGFyZW50QVZlcnRpY2VzTGVuZ3RoID0gcGFyZW50QS52ZXJ0aWNlcy5sZW5ndGg7XFxuICAgICAgICBcXG4gICAgICAgIHBhaXIuaXNBY3RpdmUgPSB0cnVlO1xcbiAgICAgICAgcGFpci50aW1lVXBkYXRlZCA9IHRpbWVzdGFtcDtcXG4gICAgICAgIHBhaXIuY29sbGlzaW9uID0gY29sbGlzaW9uO1xcbiAgICAgICAgcGFpci5zZXBhcmF0aW9uID0gY29sbGlzaW9uLmRlcHRoO1xcbiAgICAgICAgcGFpci5pbnZlcnNlTWFzcyA9IHBhcmVudEEuaW52ZXJzZU1hc3MgKyBwYXJlbnRCLmludmVyc2VNYXNzO1xcbiAgICAgICAgcGFpci5mcmljdGlvbiA9IHBhcmVudEEuZnJpY3Rpb24gPCBwYXJlbnRCLmZyaWN0aW9uID8gcGFyZW50QS5mcmljdGlvbiA6IHBhcmVudEIuZnJpY3Rpb247XFxuICAgICAgICBwYWlyLmZyaWN0aW9uU3RhdGljID0gcGFyZW50QS5mcmljdGlvblN0YXRpYyA+IHBhcmVudEIuZnJpY3Rpb25TdGF0aWMgPyBwYXJlbnRBLmZyaWN0aW9uU3RhdGljIDogcGFyZW50Qi5mcmljdGlvblN0YXRpYztcXG4gICAgICAgIHBhaXIucmVzdGl0dXRpb24gPSBwYXJlbnRBLnJlc3RpdHV0aW9uID4gcGFyZW50Qi5yZXN0aXR1dGlvbiA/IHBhcmVudEEucmVzdGl0dXRpb24gOiBwYXJlbnRCLnJlc3RpdHV0aW9uO1xcbiAgICAgICAgcGFpci5zbG9wID0gcGFyZW50QS5zbG9wID4gcGFyZW50Qi5zbG9wID8gcGFyZW50QS5zbG9wIDogcGFyZW50Qi5zbG9wO1xcblxcbiAgICAgICAgY29sbGlzaW9uLnBhaXIgPSBwYWlyO1xcbiAgICAgICAgYWN0aXZlQ29udGFjdHMubGVuZ3RoID0gMDtcXG4gICAgICAgIFxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdXBwb3J0cy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHZhciBzdXBwb3J0ID0gc3VwcG9ydHNbaV0sXFxuICAgICAgICAgICAgICAgIGNvbnRhY3RJZCA9IHN1cHBvcnQuYm9keSA9PT0gcGFyZW50QSA/IHN1cHBvcnQuaW5kZXggOiBwYXJlbnRBVmVydGljZXNMZW5ndGggKyBzdXBwb3J0LmluZGV4LFxcbiAgICAgICAgICAgICAgICBjb250YWN0ID0gY29udGFjdHNbY29udGFjdElkXTtcXG5cXG4gICAgICAgICAgICBpZiAoY29udGFjdCkge1xcbiAgICAgICAgICAgICAgICBhY3RpdmVDb250YWN0cy5wdXNoKGNvbnRhY3QpO1xcbiAgICAgICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgICAgIGFjdGl2ZUNvbnRhY3RzLnB1c2goY29udGFjdHNbY29udGFjdElkXSA9IENvbnRhY3QuY3JlYXRlKHN1cHBvcnQpKTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuICAgIH07XFxuICAgIFxcbiAgICAvKipcXG4gICAgICogU2V0IGEgcGFpciBhcyBhY3RpdmUgb3IgaW5hY3RpdmUuXFxuICAgICAqIEBtZXRob2Qgc2V0QWN0aXZlXFxuICAgICAqIEBwYXJhbSB7cGFpcn0gcGFpclxcbiAgICAgKiBAcGFyYW0ge2Jvb2x9IGlzQWN0aXZlXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB0aW1lc3RhbXBcXG4gICAgICovXFxuICAgIFBhaXIuc2V0QWN0aXZlID0gZnVuY3Rpb24ocGFpciwgaXNBY3RpdmUsIHRpbWVzdGFtcCkge1xcbiAgICAgICAgaWYgKGlzQWN0aXZlKSB7XFxuICAgICAgICAgICAgcGFpci5pc0FjdGl2ZSA9IHRydWU7XFxuICAgICAgICAgICAgcGFpci50aW1lVXBkYXRlZCA9IHRpbWVzdGFtcDtcXG4gICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgcGFpci5pc0FjdGl2ZSA9IGZhbHNlO1xcbiAgICAgICAgICAgIHBhaXIuYWN0aXZlQ29udGFjdHMubGVuZ3RoID0gMDtcXG4gICAgICAgI
2H1cXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIEdldCB0aGUgaWQgZm9yIHRoZSBnaXZlbiBwYWlyLlxcbiAgICAgKiBAbWV0aG9kIGlkXFxuICAgICAqIEBwYXJhbSB7Ym9keX0gYm9keUFcXG4gICAgICogQHBhcmFtIHtib2R5fSBib2R5QlxcbiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9IFVuaXF1ZSBwYWlySWRcXG4gICAgICovXFxuICAgIFBhaXIuaWQgPSBmdW5jdGlvbihib2R5QSwgYm9keUIpIHtcXG4gICAgICAgIGlmIChib2R5QS5pZCA8IGJvZHlCLmlkKSB7XFxuICAgICAgICAgICAgcmV0dXJuICdBJyArIGJvZHlBLmlkICsgJ0InICsgYm9keUIuaWQ7XFxuICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgIHJldHVybiAnQScgKyBib2R5Qi5pZCArICdCJyArIGJvZHlBLmlkO1xcbiAgICAgICAgfVxcbiAgICB9O1xcblxcbn0pKCk7XFxuXFxuXFxuLyoqKi8gfSksXFxuLyogMTAgKi9cXG4vKioqLyAoZnVuY3Rpb24obW9kdWxlLCBleHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XFxuXFxuLyoqXFxuKiBUaGUgYE1hdHRlci5Db25zdHJhaW50YCBtb2R1bGUgY29udGFpbnMgbWV0aG9kcyBmb3IgY3JlYXRpbmcgYW5kIG1hbmlwdWxhdGluZyBjb25zdHJhaW50cy5cXG4qIENvbnN0cmFpbnRzIGFyZSB1c2VkIGZvciBzcGVjaWZ5aW5nIHRoYXQgYSBmaXhlZCBkaXN0YW5jZSBtdXN0IGJlIG1haW50YWluZWQgYmV0d2VlbiB0d28gYm9kaWVzIChvciBhIGJvZHkgYW5kIGEgZml4ZWQgd29ybGQtc3BhY2UgcG9zaXRpb24pLlxcbiogVGhlIHN0aWZmbmVzcyBvZiBjb25zdHJhaW50cyBjYW4gYmUgbW9kaWZpZWQgdG8gY3JlYXRlIHNwcmluZ3Mgb3IgZWxhc3RpYy5cXG4qXFxuKiBTZWUgdGhlIGluY2x1ZGVkIHVzYWdlIFtleGFtcGxlc10oaHR0cHM6Ly9naXRodWIuY29tL2xpYWJydS9tYXR0ZXItanMvdHJlZS9tYXN0ZXIvZXhhbXBsZXMpLlxcbipcXG4qIEBjbGFzcyBDb25zdHJhaW50XFxuKi9cXG5cXG52YXIgQ29uc3RyYWludCA9IHt9O1xcblxcbm1vZHVsZS5leHBvcnRzID0gQ29uc3RyYWludDtcXG5cXG52YXIgVmVydGljZXMgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDMpO1xcbnZhciBWZWN0b3IgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDIpO1xcbnZhciBTbGVlcGluZyA9IF9fd2VicGFja19yZXF1aXJlX18oNyk7XFxudmFyIEJvdW5kcyA9IF9fd2VicGFja19yZXF1aXJlX18oMSk7XFxudmFyIEF4ZXMgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDExKTtcXG52YXIgQ29tbW9uID0gX193ZWJwYWNrX3JlcXVpcmVfXygwKTtcXG5cXG4oZnVuY3Rpb24oKSB7XFxuXFxuICAgIENvbnN0cmFpbnQuX3dhcm1pbmcgPSAwLjQ7XFxuICAgIENvbnN0cmFpbnQuX3RvcnF1ZURhbXBlbiA9IDE7XFxuICAgIENvbnN0cmFpbnQuX21pbkxlbmd0aCA9IDAuMDAwMDAxO1xcblxcbiAgICAvKipcXG4gICAgICogQ3JlYXRlcyBhIG5ldyBjb25zdHJhaW50LlxcbiAgICAgKiBBbGwgcHJvcGVydGllcyBoYXZlIGRlZmF1bHQgdmFsdWVzLCBhbmQgbWFueSBhcmUgcHJlLWNhbGN1bGF0ZWQgYXV0b21hdGljYWxseSBiYXNlZCBvbiBvdGhlciBwcm9wZXJ0aWVzLlxcbiAgICAgKiBUbyBzaW11bGF0ZSBhIHJldm9sdXRlIGNvbnN0cmFpbnQgKG9yIHBpbiBqb2ludCkgc2V0IGBsZW5ndGg6IDBgIGFuZCBhIGhpZ2ggYHN0aWZmbmVzc2AgdmFsdWUgKGUuZy4gYDAuN2Agb3IgYWJvdmUpLlxcbiAgICAgKiBJZiB0aGUgY29uc3RyYWludCBpcyB1bnN0YWJsZSwgdHJ5IGxvd2VyaW5nIHRoZSBgc3RpZmZuZXNzYCB2YWx1ZSBhbmQgLyBvciBpbmNyZWFzaW5nIGBlbmdpbmUuY29uc3RyYWludEl0ZXJhdGlvbnNgLlxcbiAgICAgKiBGb3IgY29tcG91bmQgYm9kaWVzLCBjb25zdHJhaW50cyBtdXN0IGJlIGFwcGxpZWQgdG8gdGhlIHBhcmVudCBib2R5IChub3Qgb25lIG9mIGl0cyBwYXJ0cykuXFxuICAgICAqIFNlZSB0aGUgcHJvcGVydGllcyBzZWN0aW9uIGJlbG93IGZvciBkZXRhaWxlZCBpbmZvcm1hdGlvbiBvbiB3aGF0IHlvdSBjYW4gcGFzcyB2aWEgdGhlIGBvcHRpb25zYCBvYmplY3QuXFxuICAgICAqIEBtZXRob2QgY3JlYXRlXFxuICAgICAqIEBwYXJhbSB7fSBvcHRpb25zXFxuICAgICAqIEByZXR1cm4ge2NvbnN0cmFpbnR9IGNvbnN0cmFpbnRcXG4gICAgICovXFxuICAgIENvbnN0cmFpbnQuY3JlYXRlID0gZnVuY3Rpb24ob3B0aW9ucykge1xcbiAgICAgICAgdmFyIGNvbnN0cmFpbnQgPSBvcHRpb25zO1xcblxcbiAgICAgICAgLy8gaWYgYm9kaWVzIGRlZmluZWQgYnV0IG5vIHBvaW50cywgdXNlIGJvZHkgY2VudHJlXFxuICAgICAgICBpZiAoY29uc3RyYWludC5ib2R5QSAmJiAhY29uc3RyYWludC5wb2ludEEpXFxuICAgICAgICAgICAgY29uc3RyYWludC5wb2ludEEgPSB7IHg6IDAsIHk6IDAgfTtcXG4gICAgICAgIGlmIChjb25zdHJhaW50LmJvZHlCICYmICFjb25zdHJhaW50LnBvaW50QilcXG4gICAgICAgICAgICBjb25zdHJhaW50LnBvaW50QiA9IHsgeDogMCwgeTogMCB9O1xcblxcbiAgICAgICAgLy8gY2FsY3VsYXRlIHN0YXRpYyBsZW5ndGggdXNpbmcgaW5pdGlhbCB3b3JsZCBzcGFjZSBwb2ludHNcXG4gICAgICAgIHZhciBpbml0aWFsUG9pbnRBID0gY29uc3RyYWludC5ib2R5QSA/IFZlY3Rvci5hZGQoY29uc3RyYWludC5ib2R5QS5wb3NpdGlvbiwgY29uc3RyYWludC5wb2ludEEpIDogY29uc3RyYWludC5wb2ludEEsXFxuICAgICAgICAgICAgaW5pdGlhbFBvaW50QiA9IGNvbnN0cmFpbnQuYm9keUIgPyBWZWN0b3IuYWRkKGNvbnN0cmFpbnQuYm9keUIucG9zaXRpb24sIGNvbnN0cmFpbnQucG9pbnRCKSA6IGNvbnN0cmFpbnQucG9pbnRCLFxcbiAgICAgICAgICAgIGxlbmd0aCA9IFZlY3Rvci5tYWduaXR1ZGUoVmVjdG9yLnN1Yihpbml0aWFsUG9pbnRBLCBpbml0aWFsUG9pbnRCKSk7XFxuICAgIFxcbiAgICAgICAgY29uc3RyYWludC5sZW5ndGggPSB0eXBlb2YgY29uc3RyYWludC5sZW5ndGggIT09ICd1bmRlZmluZWQnID8gY29uc3RyYWludC5sZW5ndGggOiBsZW5ndGg7XFxuXFxuICAgICAgICAvLyBvcHRpb24gZGVmYXVsdHNcXG4gICAgICAgIGNvbnN0cmFpbnQuaWQgPSBjb25zdHJhaW50LmlkIHx8IENvbW1vbi5uZXh0SWQoKTtcXG4gICAgICAgIGNvbnN0cmFpbnQubGFiZWwgPSBjb25zdHJhaW50LmxhYmVsIHx8ICdDb25zdHJhaW50JztcXG4gICAgICAgIGNvbnN0cmFpbnQudHlwZSA9ICdjb25zdHJhaW50JztcXG4gICAgICAgIGNvbnN0cmFpbnQuc3RpZmZuZXNzID0gY29uc3RyYWludC5zdGlmZm5lc3MgfHwgKGNvbnN0cmFpbnQubGVuZ3RoID4gMCA/IDEgOiAwLjcpO1xcbiAgICAgICAgY29uc3RyYWludC5kYW1waW5nID0gY29uc3RyYWludC5kYW1waW5nIHx8IDA7XFxuICAgICAgICBjb25zdHJhaW50LmFuZ3VsYXJTdGlmZm5lc3MgPSBjb25zdHJhaW50LmFuZ3VsYXJTdGlmZm5lc3MgfHwgMDtcXG4gICAgICAgIGNvbnN0cmFpbnQuYW5nbGVBID0gY29uc3RyYWludC5ib2R5QSA/IGNvbnN0cmFpbnQuYm9keUEuYW5nbGUgOiBjb25zdHJhaW50LmFuZ2xlQTtcXG4gICAgICAgIGNvbnN0cmFpbnQuYW5nbGVCID0gY29uc3RyYWludC5ib2R5QiA/IGNvbnN0cmFpbnQuYm9keUIuYW5nbGUgOiBjb25zdHJhaW50LmFuZ2xlQjtcXG4gICAgICAgIGNvbnN0cmFpbnQucGx1Z2luID0ge307XFxuXFxuICAgICAgICAvLyByZW5kZXJcXG4gICAgICAgI
2HZhciByZW5kZXIgPSB7XFxuICAgICAgICAgICAgdmlzaWJsZTogdHJ1ZSxcXG4gICAgICAgICAgICBsaW5lV2lkdGg6IDIsXFxuICAgICAgICAgICAgc3Ryb2tlU3R5bGU6ICcjZmZmZmZmJyxcXG4gICAgICAgICAgICB0eXBlOiAnbGluZScsXFxuICAgICAgICAgICAgYW5jaG9yczogdHJ1ZVxcbiAgICAgICAgfTtcXG5cXG4gICAgICAgIGlmIChjb25zdHJhaW50Lmxlbmd0aCA9PT0gMCAmJiBjb25zdHJhaW50LnN0aWZmbmVzcyA+IDAuMSkge1xcbiAgICAgICAgICAgIHJlbmRlci50eXBlID0gJ3Bpbic7XFxuICAgICAgICAgICAgcmVuZGVyLmFuY2hvcnMgPSBmYWxzZTtcXG4gICAgICAgIH0gZWxzZSBpZiAoY29uc3RyYWludC5zdGlmZm5lc3MgPCAwLjkpIHtcXG4gICAgICAgICAgICByZW5kZXIudHlwZSA9ICdzcHJpbmcnO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgY29uc3RyYWludC5yZW5kZXIgPSBDb21tb24uZXh0ZW5kKHJlbmRlciwgY29uc3RyYWludC5yZW5kZXIpO1xcblxcbiAgICAgICAgcmV0dXJuIGNvbnN0cmFpbnQ7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBQcmVwYXJlcyBmb3Igc29sdmluZyBieSBjb25zdHJhaW50IHdhcm1pbmcuXFxuICAgICAqIEBwcml2YXRlXFxuICAgICAqIEBtZXRob2QgcHJlU29sdmVBbGxcXG4gICAgICogQHBhcmFtIHtib2R5W119IGJvZGllc1xcbiAgICAgKi9cXG4gICAgQ29uc3RyYWludC5wcmVTb2x2ZUFsbCA9IGZ1bmN0aW9uKGJvZGllcykge1xcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBib2RpZXMubGVuZ3RoOyBpICs9IDEpIHtcXG4gICAgICAgICAgICB2Y
2XIgYm9keSA9IGJvZGllc1tpXSxcXG4gICAgICAgICAgICAgICAgaW1wdWxzZSA9IGJvZHkuY29uc3RyYWludEltcHVsc2U7XFxuXFxuICAgICAgICAgICAgaWYgKGJvZHkuaXNTdGF0aWMgfHwgKGltcHVsc2UueCA9PT0gMCAmJiBpbXB1bHNlLnkgPT09IDAgJiYgaW1wdWxzZS5hbmdsZSA9PT0gMCkpIHtcXG4gICAgICAgICAgICAgICAgY29udGludWU7XFxuICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgIGJvZHkucG9zaXRpb24ueCArPSBpbXB1bHNlLng7XFxuICAgICAgICAgICAgYm9keS5wb3NpdGlvbi55ICs9IGltcHVsc2UueTtcXG4gICAgICAgICAgICBib2R5LmFuZ2xlICs9IGltcHVsc2UuYW5nbGU7XFxuICAgICAgICB9XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBTb2x2ZXMgYWxsIGNvbnN0cmFpbnRzIGluIGEgbGlzdCBvZiBjb2xsaXNpb25zLlxcbiAgICAgKiBAcHJpdmF0ZVxcbiAgICAgKiBAbWV0aG9kIHNvbHZlQWxsXFxuICAgICAqIEBwYXJhbSB7Y29uc3RyYWludFtdfSBjb25zdHJhaW50c1xcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gZGVsdGFcXG4gICAgICovXFxuICAgIENvbnN0cmFpbnQuc29sdmVBbGwgPSBmdW5jdGlvbihjb25zdHJhaW50cywgZGVsdGEpIHtcXG4gICAgICAgIHZhciB0aW1lU2NhbGUgPSBDb21tb24uY2xhbXAoZGVsdGEgLyBDb21tb24uX2Jhc2VEZWx0YSwgMCwgMSk7XFxuXFxuICAgICAgICAvLyBTb2x2ZSBmaXhlZCBjb25zdHJhaW50cyBmaXJzdC5cXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY29uc3RyYWludHMubGVuZ3RoOyBpICs9IDEpIHtcXG4gICAgICAgICAgICB2Y
2XIgY29uc3RyYWludCA9IGNvbnN0cmFpbnRzW2ldLFxcbiAgICAgICAgICAgICAgICBmaXhlZEEgPSAhY29uc3RyYWludC5ib2R5QSB8fCAoY29uc3RyYWludC5ib2R5QSAmJiBjb25zdHJhaW50LmJvZHlBLmlzU3RhdGljKSxcXG4gICAgICAgICAgICAgICAgZml4ZWRCID0gIWNvbnN0cmFpbnQuYm9keUIgfHwgKGNvbnN0cmFpbnQuYm9keUIgJiYgY29uc3RyYWludC5ib2R5Qi5pc1N0YXRpYyk7XFxuXFxuICAgICAgICAgICAgaWYgKGZpeGVkQSB8fCBmaXhlZEIpIHtcXG4gICAgICAgICAgICAgICAgQ29uc3RyYWludC5zb2x2ZShjb25zdHJhaW50c1tpXSwgdGltZVNjYWxlKTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuXFxuICAgICAgICAvLyBTb2x2ZSBmcmVlIGNvbnN0cmFpbnRzIGxhc3QuXFxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgY29uc3RyYWludHMubGVuZ3RoOyBpICs9IDEpIHtcXG4gICAgICAgICAgICBjb25zdHJhaW50ID0gY29uc3RyYWludHNbaV07XFxuICAgICAgICAgICAgZml4ZWRBID0gIWNvbnN0cmFpbnQuYm9keUEgfHwgKGNvbnN0cmFpbnQuYm9keUEgJiYgY29uc3RyYWludC5ib2R5QS5pc1N0YXRpYyk7XFxuICAgICAgICAgICAgZml4ZWRCID0gIWNvbnN0cmFpbnQuYm9keUIgfHwgKGNvbnN0cmFpbnQuYm9keUIgJiYgY29uc3RyYWludC5ib2R5Qi5pc1N0YXRpYyk7XFxuXFxuICAgICAgICAgICAgaWYgKCFmaXhlZEEgJiYgIWZpeGVkQikge1xcbiAgICAgICAgICAgICAgICBDb25zdHJhaW50LnNvbHZlKGNvbnN0cmFpbnRzW2ldLCB0aW1lU2NhbGUpO1xcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFNvbHZlcyBhIGRpc3RhbmNlIGNvbnN0cmFpbnQgd2l0aCBHYXVzcy1TaWVkZWwgbWV0aG9kLlxcbiAgICAgKiBAcHJpdmF0ZVxcbiAgICAgKiBAbWV0aG9kIHNvbHZlXFxuICAgICAqIEBwYXJhbSB7Y29uc3RyYWludH0gY29uc3RyYWludFxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gdGltZVNjYWxlXFxuICAgICAqL1xcbiAgICBDb25zdHJhaW50LnNvbHZlID0gZnVuY3Rpb24oY29uc3RyYWludCwgdGltZVNjYWxlKSB7XFxuICAgICAgICB2Y
2XIgYm9keUEgPSBjb25zdHJhaW50LmJvZHlBLFxcbiAgICAgICAgICAgIGJvZHlCID0gY29uc3RyYWludC5ib2R5QixcXG4gICAgICAgICAgICBwb2ludEEgPSBjb25zdHJhaW50LnBvaW50QSxcXG4gICAgICAgICAgICBwb2ludEIgPSBjb25zdHJhaW50LnBvaW50QjtcXG5cXG4gICAgICAgIGlmICghYm9keUEgJiYgIWJvZHlCKVxcbiAgICAgICAgICAgIHJldHVybjtcXG5cXG4gICAgICAgIC8vIHVwZGF0ZSByZWZlcmVuY2UgYW5nbGVcXG4gICAgICAgIGlmIChib2R5QSAmJiAhYm9keUEuaXNTdGF0aWMpIHtcXG4gICAgICAgICAgICBWZWN0b3Iucm90YXRlKHBvaW50QSwgYm9keUEuYW5nbGUgLSBjb25zdHJhaW50LmFuZ2xlQSwgcG9pbnRBKTtcXG4gICAgICAgICAgICBjb25zdHJhaW50LmFuZ2xlQSA9IGJvZHlBLmFuZ2xlO1xcbiAgICAgICAgfVxcbiAgICAgICAgXFxuICAgICAgICAvLyB1cGRhdGUgcmVmZXJlbmNlIGFuZ2xlXFxuICAgICAgICBpZiAoYm9keUIgJiYgIWJvZHlCLmlzU3RhdGljKSB7XFxuICAgICAgICAgICAgVmVjdG9yLnJvdGF0ZShwb2ludEIsIGJvZHlCLmFuZ2xlIC0gY29uc3RyYWludC5hbmdsZUIsIHBvaW50Qik7XFxuICAgICAgICAgICAgY29uc3RyYWludC5hbmdsZUIgPSBib2R5Qi5hbmdsZTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHZhciBwb2ludEFXb3JsZCA9IHBvaW50QSxcXG4gICAgICAgICAgICBwb2ludEJXb3JsZCA9IHBvaW50QjtcXG5cXG4gICAgICAgIGlmIChib2R5QSkgcG9pbnRBV29ybGQgPSBWZWN0b3IuYWRkKGJvZHlBLnBvc2l0aW9uLCBwb2ludEEpO1xcbiAgICAgICAgaWYgKGJvZHlCKSBwb2ludEJXb3JsZCA9IFZlY3Rvci5hZGQoYm9keUIucG9zaXRpb24sIHBvaW50Qik7XFxuXFxuICAgICAgICBpZiAoIXBvaW50QVdvcmxkIHx8ICFwb2ludEJXb3JsZClcXG4gICAgICAgICAgICByZXR1cm47XFxuXFxuICAgICAgICB2Y
2XIgZGVsdGEgPSBWZWN0b3Iuc3ViKHBvaW50QVdvcmxkLCBwb2ludEJXb3JsZCksXFxuICAgICAgICAgICAgY3VycmVudExlbmd0aCA9IFZlY3Rvci5tYWduaXR1ZGUoZGVsdGEpO1xcblxcbiAgICAgICAgLy8gcHJldmVudCBzaW5ndWxhcml0eVxcbiAgICAgICAgaWYgKGN1cnJlbnRMZW5ndGggPCBDb25zdHJhaW50Ll9taW5MZW5ndGgpIHtcXG4gICAgICAgICAgICBjdXJyZW50TGVuZ3RoID0gQ29uc3RyYWludC5fbWluTGVuZ3RoO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgLy8gc29sdmUgZGlzdGFuY2UgY29uc3RyYWludCB3aXRoIEdhdXNzLVNpZWRlbCBtZXRob2RcXG4gICAgICAgIHZhciBkaWZmZXJlbmNlID0gKGN1cnJlbnRMZW5ndGggLSBjb25zdHJhaW50Lmxlbmd0aCkgLyBjdXJyZW50TGVuZ3RoLFxcbiAgICAgICAgICAgIGlzUmlnaWQgPSBjb25zdHJhaW50LnN0aWZmbmVzcyA+PSAxIHx8IGNvbnN0cmFpbnQubGVuZ3RoID09PSAwLFxcbiAgICAgICAgICAgIHN0aWZmbmVzcyA9IGlzUmlnaWQgPyBjb25zdHJhaW50LnN0aWZmbmVzcyAqIHRpbWVTY2FsZSBcXG4gICAgICAgICAgICAgICAgOiBjb25zdHJhaW50LnN0aWZmbmVzcyAqIHRpbWVTY2FsZSAqIHRpbWVTY2FsZSxcXG4gICAgICAgICAgICBkYW1waW5nID0gY29uc3RyYWludC5kYW1waW5nICogdGltZVNjYWxlLFxcbiAgICAgICAgICAgIGZvcmNlID0gVmVjdG9yLm11bHQoZGVsdGEsIGRpZmZlcmVuY2UgKiBzdGlmZm5lc3MpLFxcbiAgICAgICAgICAgIG1hc3NUb3RhbCA9IChib2R5QSA/IGJvZHlBLmludmVyc2VNYXNzIDogMCkgKyAoYm9keUIgPyBib2R5Qi5pbnZlcnNlTWFzcyA6IDApLFxcbiAgICAgICAgICAgIGluZXJ0aWFUb3RhbCA9IChib2R5QSA/IGJvZHlBLmludmVyc2VJbmVydGlhIDogMCkgKyAoYm9keUIgPyBib2R5Qi5pbnZlcnNlSW5lcnRpYSA6IDApLFxcbiAgICAgICAgICAgIHJlc2lzdGFuY2VUb3RhbCA9IG1hc3NUb3RhbCArIGluZXJ0aWFUb3RhbCxcXG4gICAgICAgICAgICB0b3JxdWUsXFxuICAgICAgICAgICAgc2hhcmUsXFxuICAgICAgICAgICAgbm9ybWFsLFxcbiAgICAgICAgICAgIG5vcm1hbFZlbG9jaXR5LFxcbiAgICAgICAgICAgIHJlbGF0aXZlVmVsb2NpdHk7XFxuICAgIFxcbiAgICAgICAgaWYgKGRhbXBpbmcgPiAwKSB7XFxuICAgICAgICAgICAgdmFyIHplcm8gPSBWZWN0b3IuY3JlYXRlKCk7XFxuICAgICAgICAgICAgbm9ybWFsID0gVmVjdG9yLmRpdihkZWx0YSwgY3VycmVudExlbmd0aCk7XFxuXFxuICAgICAgICAgICAgcmVsYXRpdmVWZWxvY2l0eSA9IFZlY3Rvci5zdWIoXFxuICAgICAgICAgICAgICAgIGJvZHlCICYmIFZlY3Rvci5zdWIoYm9keUIucG9zaXRpb24sIGJvZHlCLnBvc2l0aW9uUHJldikgfHwgemVybyxcXG4gICAgICAgICAgICAgICAgYm9keUEgJiYgVmVjdG9yLnN1Yihib2R5QS5wb3NpdGlvbiwgYm9keUEucG9zaXRpb25QcmV2KSB8fCB6ZXJvXFxuICAgICAgICAgICAgKTtcXG5cXG4gICAgICAgICAgICBub3JtYWxWZWxvY2l0eSA9IFZlY3Rvci5kb3Qobm9ybWFsLCByZWxhdGl2ZVZlbG9jaXR5KTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIGlmIChib2R5QSAmJiAhYm9keUEuaXNTdGF0aWMpIHtcXG4gICAgICAgICAgICBzaGFyZSA9IGJvZHlBLmludmVyc2VNYXNzIC8gbWFzc1RvdGFsO1xcblxcbiAgICAgICAgICAgIC8vIGtlZXAgdHJhY2sgb2YgYXBwbGllZCBpbXB1bHNlcyBmb3IgcG9zdCBzb2x2aW5nXFxuICAgICAgICAgICAgYm9keUEuY29uc3RyYWludEltcHVsc2UueCAtPSBmb3JjZS54ICogc2hhcmU7XFxuICAgICAgICAgICAgYm9keUEuY29uc3RyYWludEltcHVsc2UueSAtPSBmb3JjZS55ICogc2hhcmU7XFxuXFxuICAgICAgICAgICAgLy8gYXBwbHkgZm9yY2VzXFxuICAgICAgICAgICAgYm9keUEucG9zaXRpb24ueCAtPSBmb3JjZS54ICogc2hhcmU7XFxuICAgICAgICAgICAgYm9keUEucG9zaXRpb24ueSAtPSBmb3JjZS55ICogc2hhcmU7XFxuXFxuICAgICAgICAgICAgLy8gYXBwbHkgZGFtcGluZ1xcbiAgICAgICAgICAgIGlmIChkYW1waW5nID4gMCkge1xcbiAgICAgICAgICAgICAgICBib2R5QS5wb3NpdGlvblByZXYueCAtPSBkYW1waW5nICogbm9ybWFsLnggKiBub3JtYWxWZWxvY2l0eSAqIHNoYXJlO1xcbiAgICAgICAgICAgICAgICBib2R5QS5wb3NpdGlvblByZXYueSAtPSBkYW1waW5nICogbm9ybWFsLnkgKiBub3JtYWxWZWxvY2l0eSAqIHNoYXJlO1xcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICAvLyBhcHBseSB0b3JxdWVcXG4gICAgICAgICAgICB0b3JxdWUgPSAoVmVjdG9yLmNyb3NzKHBvaW50QSwgZm9yY2UpIC8gcmVzaXN0YW5jZVRvdGFsKSAqIENvbnN0cmFpbnQuX3RvcnF1ZURhbXBlbiAqIGJvZHlBLmludmVyc2VJbmVydGlhICogKDEgLSBjb25zdHJhaW50LmFuZ3VsYXJTdGlmZm5lc3MpO1xcbiAgICAgICAgICAgIGJvZHlBLmNvbnN0cmFpbnRJbXB1bHNlLmFuZ2xlIC09IHRvcnF1ZTtcXG4gICAgICAgICAgICBib2R5QS5hbmdsZSAtPSB0b3JxdWU7XFxuICAgICAgICB9XFxuXFxuICAgICAgICBpZiAoYm9keUIgJiYgIWJvZHlCLmlzU3RhdGljKSB7XFxuICAgICAgICAgICAgc2hhcmUgPSBib2R5Qi5pbnZlcnNlTWFzcyAvIG1hc3NUb3RhbDtcXG5cXG4gICAgICAgICAgICAvLyBrZWVwIHRyYWNrIG9mIGFwcGxpZWQgaW1wdWxzZXMgZm9yIHBvc3Qgc29sdmluZ1xcbiAgICAgICAgICAgIGJvZHlCLmNvbnN0cmFpbnRJbXB1bHNlLnggKz0gZm9yY2UueCAqIHNoYXJlO1xcbiAgICAgICAgICAgIGJvZHlCLmNvbnN0cmFpbnRJbXB1bHNlLnkgKz0gZm9yY2UueSAqIHNoYXJlO1xcbiAgICAgICAgICAgIFxcbiAgICAgICAgICAgIC8vIGFwcGx5IGZvcmNlc1xcbiAgICAgICAgICAgIGJvZHlCLnBvc2l0aW9uLnggKz0gZm9yY2UueCAqIHNoYXJlO1xcbiAgICAgICAgICAgIGJvZHlCLnBvc2l0aW9uLnkgKz0gZm9yY2UueSAqIHNoYXJlO1xcblxcbiAgICAgICAgICAgIC8vIGFwcGx5IGRhbXBpbmdcXG4gICAgICAgICAgICBpZiAoZGFtcGluZyA+IDApIHtcXG4gICAgICAgICAgICAgICAgYm9keUIucG9zaXRpb25QcmV2LnggKz0gZGFtcGluZyAqIG5vcm1hbC54ICogbm9ybWFsVmVsb2NpdHkgKiBzaGFyZTtcXG4gICAgICAgICAgICAgICAgYm9keUIucG9zaXRpb25QcmV2LnkgKz0gZGFtcGluZyAqIG5vcm1hbC55ICogbm9ybWFsVmVsb2NpdHkgKiBzaGFyZTtcXG4gICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgLy8gYXBwbHkgdG9ycXVlXFxuICAgICAgICAgICAgdG9ycXVlID0gKFZlY3Rvci5jcm9zcyhwb2ludEIsIGZvcmNlKSAvIHJlc2lzdGFuY2VUb3RhbCkgKiBDb25zdHJhaW50Ll90b3JxdWVEYW1wZW4gKiBib2R5Qi5pbnZlcnNlSW5lcnRpYSAqICgxIC0gY29uc3RyYWludC5hbmd1bGFyU3RpZmZuZXNzKTtcXG4gICAgICAgICAgICBib2R5Qi5jb25zdHJhaW50SW1wdWxzZS5hbmdsZSArPSB0b3JxdWU7XFxuICAgICAgICAgICAgYm9keUIuYW5nbGUgKz0gdG9ycXVlO1xcbiAgICAgICAgfVxcblxcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUG
2VyZm9ybXMgYm9keSB1cGRhdGVzIHJlcXVpcmVkIGFmdGVyIHNvbHZpbmcgY29uc3RyYWludHMuXFxuICAgICAqIEBwcml2YXRlXFxuICAgICAqIEBtZXRob2QgcG9zdFNvbHZlQWxsXFxuICAgICAqIEBwYXJhbSB7Ym9keVtdfSBib2RpZXNcXG4gICAgICovXFxuICAgIENvbnN0cmFpbnQucG9zdFNvbHZlQWxsID0gZnVuY3Rpb24oYm9kaWVzKSB7XFxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJvZGllcy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHZhciBib2R5ID0gYm9kaWVzW2ldLFxcbiAgICAgICAgICAgICAgICBpbXB1bHNlID0gYm9keS5jb25zdHJhaW50SW1wdWxzZTtcXG5cXG4gICAgICAgICAgICBpZiAoYm9keS5pc1N0YXRpYyB8fCAoaW1wdWxzZS54ID09PSAwICYmIGltcHVsc2UueSA9PT0gMCAmJiBpbXB1bHNlLmFuZ2xlID09PSAwKSkge1xcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcXG4gICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgU2xlZXBpbmcuc2V0KGJvZHksIGZhbHNlKTtcXG5cXG4gICAgICAgICAgICAvLyB1cGRhdGUgZ2VvbWV0cnkgYW5kIHJlc2V0XFxuICAgICAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBib2R5LnBhcnRzLmxlbmd0aDsgaisrKSB7XFxuICAgICAgICAgICAgICAgIHZhciBwYXJ0ID0gYm9keS5wYXJ0c1tqXTtcXG4gICAgICAgICAgICAgICAgXFxuICAgICAgICAgICAgICAgIFZlcnRpY2VzLnRyYW5zbGF0ZShwYXJ0LnZlcnRpY2VzLCBpbXB1bHNlKTtcXG5cXG4gICAgICAgICAgICAgICAgaWYgKGogPiAwKSB7XFxuICAgICAgICAgICAgICAgICAgICBwYXJ0LnBvc2l0aW9uLnggKz0gaW1wdWxzZS54O1xcbiAgICAgICAgICAgICAgICAgICAgcGFydC5wb3NpdGlvbi55ICs9IGltcHVsc2UueTtcXG4gICAgICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgICAgICBpZiAoaW1wdWxzZS5hbmdsZSAhPT0gMCkge1xcbiAgICAgICAgICAgICAgICAgICAgVmVydGljZXMucm90YXRlKHBhcnQudmVydGljZXMsIGltcHVsc2UuYW5nbGUsIGJvZHkucG9zaXRpb24pO1xcbiAgICAgICAgICAgICAgICAgICAgQXhlcy5yb3RhdGUocGFydC5heGVzLCBpbXB1bHNlLmFuZ2xlKTtcXG4gICAgICAgICAgICAgICAgICAgIGlmIChqID4gMCkge1xcbiAgICAgICAgICAgICAgICAgICAgICAgIFZlY3Rvci5yb3RhdGVBYm91dChwYXJ0LnBvc2l0aW9uLCBpbXB1bHNlLmFuZ2xlLCBib2R5LnBvc2l0aW9uLCBwYXJ0LnBvc2l0aW9uKTtcXG4gICAgICAgICAgICAgICAgICAgIH1cXG4gICAgICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgICAgICBCb3VuZHMudXBkYXRlKHBhcnQuYm91bmRzLCBwYXJ0LnZlcnRpY2VzLCBib2R5LnZlbG9jaXR5KTtcXG4gICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgLy8gZGFtcGVuIHRoZSBjYWNoZWQgaW1wdWxzZSBmb3Igd2FybWluZyBuZXh0IHN0ZXBcXG4gICAgICAgICAgICBpbXB1bHNlLmFuZ2xlICo9IENvbnN0cmFpbnQuX3dhcm1pbmc7XFxuICAgICAgICAgICAgaW1wdWxzZS54ICo9IENvbnN0cmFpbnQuX3dhcm1pbmc7XFxuICAgICAgICAgICAgaW1wdWxzZS55ICo9IENvbnN0cmFpbnQuX3dhcm1pbmc7XFxuICAgICAgICB9XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIHRoZSB3b3JsZC1zcGFjZSBwb3NpdGlvbiBvZiBgY29uc3RyYWludC5wb2ludEFgLCBhY2NvdW50aW5nIGZvciBgY29uc3RyYWludC5ib2R5QWAuXFxuICAgICAqIEBtZXRob2QgcG9pbnRBV29ybGRcXG4gICAgICogQHBhcmFtIHtjb25zdHJhaW50fSBjb25zdHJhaW50XFxuICAgICAqIEByZXR1cm5zIHt2ZWN0b3J9IHRoZSB3b3JsZC1zcGFjZSBwb3NpdGlvblxcbiAgICAgKi9cXG4gICAgQ29uc3RyYWludC5wb2ludEFXb3JsZCA9IGZ1bmN0aW9uKGNvbnN0cmFpbnQpIHtcXG4gICAgICAgIHJldHVybiB7XFxuICAgICAgICAgICAgeDogKGNvbnN0cmFpbnQuYm9keUEgPyBjb25zdHJhaW50LmJvZHlBLnBvc2l0aW9uLnggOiAwKSBcXG4gICAgICAgICAgICAgICAgKyAoY29uc3RyYWludC5wb2ludEEgPyBjb25zdHJhaW50LnBvaW50QS54IDogMCksXFxuICAgICAgICAgICAgeTogKGNvbnN0cmFpbnQuYm9keUEgPyBjb25zdHJhaW50LmJvZHlBLnBvc2l0aW9uLnkgOiAwKSBcXG4gICAgICAgICAgICAgICAgKyAoY29uc3RyYWludC5wb2ludEEgPyBjb25zdHJhaW50LnBvaW50QS55IDogMClcXG4gICAgICAgIH07XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIHRoZSB3b3JsZC1zcGFjZSBwb3NpdGlvbiBvZiBgY29uc3RyYWludC5wb2ludEJgLCBhY2NvdW50aW5nIGZvciBgY29uc3RyYWludC5ib2R5QmAuXFxuICAgICAqIEBtZXRob2QgcG9pbnRCV29ybGRcXG4gICAgICogQHBhcmFtIHtjb25zdHJhaW50fSBjb25zdHJhaW50XFxuICAgICAqIEByZXR1cm5zIHt2ZWN0b3J9IHRoZSB3b3JsZC1zcGFjZSBwb3NpdGlvblxcbiAgICAgKi9cXG4gICAgQ29uc3RyYWludC5wb2ludEJXb3JsZCA9IGZ1bmN0aW9uKGNvbnN0cmFpbnQpIHtcXG4gICAgICAgIHJldHVybiB7XFxuICAgICAgICAgICAgeDogKGNvbnN0cmFpbnQuYm9keUIgPyBjb25zdHJhaW50LmJvZHlCLnBvc2l0aW9uLnggOiAwKSBcXG4gICAgICAgICAgICAgICAgKyAoY29uc3RyYWludC5wb2ludEIgPyBjb25zdHJhaW50LnBvaW50Qi54IDogMCksXFxuICAgICAgICAgICAgeTogKGNvbnN0cmFpbnQuYm9keUIgPyBjb25zdHJhaW50LmJvZHlCLnBvc2l0aW9uLnkgOiAwKSBcXG4gICAgICAgICAgICAgICAgKyAoY29uc3RyYWludC5wb2ludEIgPyBjb25zdHJhaW50LnBvaW50Qi55IDogMClcXG4gICAgICAgIH07XFxuICAgIH07XFxuXFxuICAgIC8qXFxuICAgICpcXG4gICAgKiAgUHJvcGVydGllcyBEb2N1bWVudGF0aW9uXFxuICAgICpcXG4gICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEFuIGludGVnZXIgYE51bWJlcmAgdW5pcXVlbHkgaWRlbnRpZnlpbmcgbnVtYmVyIGdlbmVyYXRlZCBpbiBgQ29tcG9zaXRlLmNyZWF0ZWAgYnkgYENvbW1vbi5uZXh0SWRgLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgaWRcXG4gICAgICogQHR5cGUgbnVtYmVyXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBgU3RyaW5nYCBkZW5vdGluZyB0aGUgdHlwZSBvZiBvYmplY3QuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSB0eXBlXFxuICAgICAqIEB0eXBlIHN0cmluZ1xcbiAgICAgKiBAZGVmYXVsdCBcXFwiY29uc3RyYWludFxcXCJcXG4gICAgICogQHJlYWRPbmx5XFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQW4gYXJiaXRyYXJ5IGBTdHJpbmdgIG5hbWUgdG8gaGVscCB0aGUgdXNlciBpZGVudGlmeSBhbmQgbWFuYWdlIGJvZGllcy5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IGxhYmVsXFxuICAgICAqIEB0eXBlIHN0cmluZ1xcbiAgICAgKiBAZGVmYXVsdCBcXFwiQ29uc3RyYWludFxcXCJcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBbiBgT2JqZWN0YCB0aGF0IGRlZmluZXMgdGhlIHJlbmRlcmluZyBwcm9wZXJ0aWVzIHRvIGJlIGNvbnN1bWVkIGJ5IHRoZSBtb2R1bGUgYE1hdHRlci5SZW5kZXJgLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgcmVuZGVyXFxuICAgICAqIEB0eXBlIG9iamVjdFxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEEgZmxhZyB0aGF0IGluZGljYXRlcyBpZiB0aGUgY29uc3RyYWludCBzaG91bGQgYmUgcmVuZGVyZWQuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSByZW5kZXIudmlzaWJsZVxcbiAgICAgKiBAdHlwZSBib29sZWFuXFxuICAgICAqIEBkZWZhdWx0IHRydWVcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGBOdW1iZXJgIHRoYXQgZGVmaW5lcyB0aGUgbGluZSB3aWR0aCB0byB1c2Ugd2hlbiByZW5kZXJpbmcgdGhlIGNvbnN0cmFpbnQgb3V0bGluZS5cXG4gICAgICogQSB2YWx1ZSBvZiBgMGAgbWVhbnMgbm8gb3V0bGluZSB3aWxsIGJlIHJlbmRlcmVkLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgcmVuZGVyLmxpbmVXaWR0aFxcbiAgICAgKiBAdHlwZSBudW1iZXJcXG4gICAgICogQGRlZmF1bHQgMlxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEEgYFN0cmluZ2AgdGhhdCBkZWZpbmVzIHRoZSBzdHJva2Ugc3R5bGUgdG8gdXNlIHdoZW4gcmVuZGVyaW5nIHRoZSBjb25zdHJhaW50IG91dGxpbmUuXFxuICAgICAqIEl0IGlzIHRoZSBzYW1lIGFzIHdoZW4gdXNpbmcgYSBjYW52YXMsIHNvIGl0IGFjY2VwdHMgQ1NTIHN0eWxlIHByb3BlcnR5IHZhbHVlcy5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IHJlbmRlci5zdHJva2VTdHlsZVxcbiAgICAgKiBAdHlwZSBzdHJpbmdcXG4gICAgICogQGRlZmF1bHQgYSByYW5kb20gY29sb3VyXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBgU3RyaW5nYCB0aGF0IGRlZmluZXMgdGhlIGNvbnN0cmFpbnQgcmVuZGVyaW5nIHR5cGUuIFxcbiAgICAgKiBUaGUgcG9zc2libGUgdmFsdWVzIGFyZSAnbGluZScsICdwaW4nLCAnc3ByaW5nJy5cXG4gICAgICogQW4gYXBwcm9wcmlhdGUgcmVuZGVyIHR5cGUgd2lsbCBiZSBhdXRvbWF0aWNhbGx5IGNob3NlbiB1bmxlc3Mgb25lIGlzIGdpdmVuIGluIG9wdGlvbnMuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSByZW5kZXIudHlwZVxcbiAgICAgKiBAdHlwZSBzdHJpbmdcXG4gICAgICogQGRlZmF1bHQgJ2xpbmUnXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBgQm9vbGVhbmAgdGhhdCBkZWZpbmVzIGlmIHRoZSBjb25zdHJhaW50J3MgYW5jaG9yIHBvaW50cyBzaG91bGQgYmUgcmVuZGVyZWQuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSByZW5kZXIuYW5jaG9yc1xcbiAgICAgKiBAdHlwZSBib29sZWFuXFxuICAgICAqIEBkZWZhdWx0IHRydWVcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBUaGUgZmlyc3QgcG9zc2libGUgYEJvZHlgIHRoYXQgdGhpcyBjb25zdHJhaW50IGlzIGF0dGFjaGVkIHRvLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgYm9keUFcXG4gICAgICogQHR5cGUgYm9keVxcbiAgICAgKiBAZGVmYXVsdCBudWxsXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogVGhlIHNlY29uZCBwb3NzaWJsZSBgQm9keWAgdGhhdCB0aGlzIGNvbnN0cmFpbnQgaXMgYXR0YWNoZWQgdG8uXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBib2R5QlxcbiAgICAgKiBAdHlwZSBib2R5XFxuICAgICAqIEBkZWZhdWx0IG51bGxcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGBWZWN0b3JgIHRoYXQgc3BlY2lmaWVzIHRoZSBvZmZzZXQgb2YgdGhlIGNvbnN0cmFpbnQgZnJvbSBjZW50ZXIgb2YgdGhlIGBjb25zdHJhaW50LmJvZHlBYCBpZiBkZWZpbmVkLCBvdGhlcndpc2UgYSB3b3JsZC1zcGFjZSBwb3NpdGlvbi5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IHBvaW50QVxcbiAgICAgKiBAdHlwZSB2ZWN0b3JcXG4gICAgICogQGRlZmF1bHQgeyB4OiAwLCB5OiAwIH1cXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGBWZWN0b3JgIHRoYXQgc3BlY2lmaWVzIHRoZSBvZmZzZXQgb2YgdGhlIGNvbnN0cmFpbnQgZnJvbSBjZW50ZXIgb2YgdGhlIGBjb25zdHJhaW50LmJvZHlCYCBpZiBkZWZpbmVkLCBvdGhlcndpc2UgYSB3b3JsZC1zcGFjZSBwb3NpdGlvbi5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IHBvaW50QlxcbiAgICAgKiBAdHlwZSB2ZWN0b3JcXG4gICAgICogQGRlZmF1bHQgeyB4OiAwLCB5OiAwIH1cXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGBOdW1iZXJgIHRoYXQgc3BlY2lmaWVzIHRoZSBzdGlmZm5lc3Mgb2YgdGhlIGNvbnN0cmFpbnQsIGkuZS4gdGhlIHJhdGUgYXQgd2hpY2ggaXQgcmV0dXJucyB0byBpdHMgcmVzdGluZyBgY29uc3RyYWludC5sZW5ndGhgLlxcbiAgICAgKiBBIHZhbHVlIG9mIGAxYCBtZWFucyB0aGUgY29uc3RyYWludCBzaG91bGQgYmUgdmVyeSBzdGlmZi5cXG4gICAgICogQSB2YWx1ZSBvZiBgMC4yYCBtZWFucyB0aGUgY29uc3RyYWludCBhY3RzIGxpa2UgYSBzb2Z0IHNwcmluZy5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IHN0aWZmbmVzc1xcbiAgICAgKiBAdHlwZSBudW1iZXJcXG4gICAgICogQGRlZmF1bHQgMVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEEgYE51bWJlcmAgdGhhdCBzcGVjaWZpZXMgdGhlIGRhbXBpbmcgb2YgdGhlIGNvbnN0cmFpbnQsIFxcbiAgICAgKiBpLmUuIHRoZSBhbW91bnQgb2YgcmVzaXN0YW5jZSBhcHBsaWVkIHRvIGVhY2ggYm9keSBiYXNlZCBvbiB0aGVpciB2ZWxvY2l0aWVzIHRvIGxpbWl0IHRoZSBhbW91bnQgb2Ygb3NjaWxsYXRpb24uXFxuICAgICAqIERhbXBpbmcgd2lsbCBvbmx5IGJlIGFwcGFyZW50IHdoZW4gdGhlIGNvbnN0cmFpbnQgYWxzbyBoYXMgYSB2ZXJ5IGxvdyBgc3RpZmZuZXNzYC5cXG4gICAgICogQSB2YWx1ZSBvZiBgMC4xYC
2BtZWFucyB0aGUgY29uc3RyYWludCB3aWxsIGFwcGx5IGhlYXZ5IGRhbXBpbmcsIHJlc3VsdGluZyBpbiBsaXR0bGUgdG8gbm8gb3NjaWxsYXRpb24uXFxuICAgICAqIEEgdmFsdWUgb2YgYDBgIG1lYW5zIHRoZSBjb25zdHJhaW50IHdpbGwgYXBwbHkgbm8gZGFtcGluZy5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IGRhbXBpbmdcXG4gICAgICogQHR5cGUgbnVtYmVyXFxuICAgICAqIEBkZWZhdWx0IDBcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGBOdW1iZXJgIHRoYXQgc3BlY2lmaWVzIHRoZSB0YXJnZXQgcmVzdGluZyBsZW5ndGggb2YgdGhlIGNvbnN0cmFpbnQuIFxcbiAgICAgKiBJdCBpcyBjYWxjdWxhdGVkIGF1dG9tYXRpY2FsbHkgaW4gYENvbnN0cmFpbnQuY3JlYXRlYCBmcm9tIGluaXRpYWwgcG9zaXRpb25zIG9mIHRoZSBgY29uc3RyYWludC5ib2R5QWAgYW5kIGBjb25zdHJhaW50LmJvZHlCYC5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IGxlbmd0aFxcbiAgICAgKiBAdHlwZSBudW1iZXJcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBbiBvYmplY3QgcmVzZXJ2ZWQgZm9yIHN0b3JpbmcgcGx1Z2luLXNwZWNpZmljIHByb3BlcnRpZXMuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBwbHVnaW5cXG4gICAgICogQHR5cGUge31cXG4gICAgICovXFxuXFxufSkoKTtcXG5cXG5cXG4vKioqLyB9KSxcXG4vKiAxMSAqL1xcbi8qKiovIChmdW5jdGlvbihtb2R1bGUsIGV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pIHtcXG5cXG4vKipcXG4qIFRoZSBgTWF0dGVyLkF4ZXNgIG1vZHVsZSBjb250YWlucyBtZXRob2RzIGZvciBjcmVhdGluZyBhbmQgbWFuaXB1bGF0aW5nIHNldHMgb2YgYXhlcy5cXG4qXFxuKiBAY2xhc3MgQXhlc1xcbiovXFxuXFxudmFyIEF4ZXMgPSB7fTtcXG5cXG5tb2R1bGUuZXhwb3J0cyA9IEF4ZXM7XFxuXFxudmFyIFZlY3RvciA9IF9fd2VicGFja19yZXF1aXJlX18oMik7XFxudmFyIENvbW1vbiA9IF9fd2VicGFja19yZXF1aXJlX18oMCk7XFxuXFxuKGZ1bmN0aW9uKCkge1xcblxcbiAgICAvKipcXG4gICAgICogQ3JlYXRlcyBhIG5ldyBzZXQgb2YgYXhlcyBmcm9tIHRoZSBnaXZlbiB2ZXJ0aWNlcy5cXG4gICAgICogQG1ldGhvZCBmcm9tVmVydGljZXNcXG4gICAgICogQHBhcmFtIHt2ZXJ0aWNlc30gdmVydGljZXNcXG4gICAgICogQHJldHVybiB7YXhlc30gQSBuZXcgYXhlcyBmcm9tIHRoZSBnaXZlbiB2ZXJ0aWNlc1xcbiAgICAgKi9cXG4gICAgQXhlcy5mcm9tVmVydGljZXMgPSBmdW5jdGlvbih2ZXJ0aWNlcykge1xcbiAgICAgICAgdmFyIGF4ZXMgPSB7fTtcXG5cXG4gICAgICAgIC8vIGZpbmQgdGhlIHVuaXF1ZSBheGVzLCB1c2luZyBlZGdlIG5vcm1hbCBncmFkaWVudHNcXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdmVydGljZXMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICB2Y
2XIgaiA9IChpICsgMSkgJSB2ZXJ0aWNlcy5sZW5ndGgsIFxcbiAgICAgICAgICAgICAgICBub3JtYWwgPSBWZWN0b3Iubm9ybWFsaXNlKHsgXFxuICAgICAgICAgICAgICAgICAgICB4OiB2ZXJ0aWNlc1tqXS55IC0gdmVydGljZXNbaV0ueSwgXFxuICAgICAgICAgICAgICAgICAgICB5OiB2ZXJ0aWNlc1tpXS54IC0gdmVydGljZXNbal0ueFxcbiAgICAgICAgICAgICAgICB9KSxcXG4gICAgICAgICAgICAgICAgZ3JhZGllbnQgPSAobm9ybWFsLnkgPT09IDApID8gSW5maW5pdHkgOiAobm9ybWFsLnggLyBub3JtYWwueSk7XFxuICAgICAgICAgICAgXFxuICAgICAgICAgICAgLy8gbGltaXQgcHJlY2lzaW9uXFxuICAgICAgICAgICAgZ3JhZGllbnQgPSBncmFkaWVudC50b0ZpeGVkKDMpLnRvU3RyaW5nKCk7XFxuICAgICAgICAgICAgYXhlc1tncmFkaWVudF0gPSBub3JtYWw7XFxuICAgICAgICB9XFxuXFxuICAgICAgICByZXR1cm4gQ29tbW9uLnZhbHVlcyhheGVzKTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFJvdGF0ZXMgYSBzZXQgb2YgYXhlcyBieSB0aGUgZ2l2ZW4gYW5nbGUuXFxuICAgICAqIEBtZXRob2Qgcm90YXRlXFxuICAgICAqIEBwYXJhbSB7YXhlc30gYXhlc1xcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gYW5nbGVcXG4gICAgICovXFxuICAgIEF4ZXMucm90YXRlID0gZnVuY3Rpb24oYXhlcywgYW5nbGUpIHtcXG4gICAgICAgIGlmIChhbmdsZSA9PT0gMClcXG4gICAgICAgICAgICByZXR1cm47XFxuICAgICAgICBcXG4gICAgICAgIHZhciBjb3MgPSBNYXRoLmNvcyhhbmdsZSksXFxuICAgICAgICAgICAgc2luID0gTWF0aC5zaW4oYW5nbGUpO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBheGVzLmxlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgdmFyIGF4aXMgPSBheGVzW2ldLFxcbiAgICAgICAgICAgICAgICB4eDtcXG4gICAgICAgICAgICB4eCA9IGF4aXMueCAqIGNvcyAtIGF4aXMueSAqIHNpbjtcXG4gICAgICAgICAgICBheGlzLnkgPSBheGlzLnggKiBzaW4gKyBheGlzLnkgKiBjb3M7XFxuICAgICAgICAgICAgYXhpcy54ID0geHg7XFxuICAgICAgICB9XFxuICAgIH07XFxuXFxufSkoKTtcXG5cXG5cXG4vKioqLyB9KSxcXG4vKiAxMiAqL1xcbi8qKiovIChmdW5jdGlvbihtb2R1bGUsIGV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pIHtcXG5cXG4vKipcXG4qIFRoZSBgTWF0dGVyLkJvZGllc2AgbW9kdWxlIGNvbnRhaW5zIGZhY3RvcnkgbWV0aG9kcyBmb3IgY3JlYXRpbmcgcmlnaWQgYm9keSBtb2RlbHMgXFxuKiB3aXRoIGNvbW1vbmx5IHVzZWQgYm9keSBjb25maWd1cmF0aW9ucyAoc3VjaCBhcyByZWN0YW5nbGVzLCBjaXJjbGVzIGFuZCBvdGhlciBwb2x5Z29ucykuXFxuKlxcbiogU2VlIHRoZSBpbmNsdWRlZCB1c2FnZSBbZXhhbXBsZXNdKGh0dHBzOi8vZ2l0aHViLmNvbS9saWFicnUvbWF0dGVyLWpzL3RyZWUvbWFzdGVyL2V4YW1wbGVzKS5cXG4qXFxuKiBAY2xhc3MgQm9kaWVzXFxuKi9cXG5cXG4vLyBUT0RPOiB0cnVlIGNpcmNsZSBib2RpZXNcXG5cXG52YXIgQm9kaWVzID0ge307XFxuXFxubW9kdWxlLmV4cG9ydHMgPSBCb2RpZXM7XFxuXFxudmFyIFZlcnRpY2VzID0gX193ZWJwYWNrX3JlcXVpcmVfXygzKTtcXG52YXIgQ29tbW9uID0gX193ZWJwYWNrX3JlcXVpcmVfXygwKTtcXG52YXIgQm9keSA9IF9fd2VicGFja19yZXF1aXJlX18oNCk7XFxudmFyIEJvdW5kcyA9IF9fd2VicGFja19yZXF1aXJlX18oMSk7XFxudmFyIFZlY3RvciA9IF9fd2VicGFja19yZXF1aXJlX18oMik7XFxuXFxuKGZ1bmN0aW9uKCkge1xcblxcbiAgICAvKipcXG4gICAgICogQ3JlYXRlcyBhIG5ldyByaWdpZCBib2R5IG1vZGVsIHdpdGggYSByZWN0YW5nbGUgaHVsbC4gXFxuICAgICAqIFRoZSBvcHRpb25zIHBhcmFtZXRlciBpcyBhbiBvYmplY3QgdGhhdCBzcGVjaWZpZXMgYW55IHByb3BlcnRpZXMgeW91IHdpc2ggdG8gb3ZlcnJpZGUgdGhlIGRlZmF1bHRzLlxcbiAgICAgKiBTZWUgdGhlIHByb3BlcnRpZXMgc2VjdGlvbiBvZiB0aGUgYE1hdHRlci5Cb2R5YCBtb2R1bGUgZm9yIGRldGFpbGVkIGluZm9ybWF0aW9uIG9uIHdoYXQgeW91IGNhbiBwYXNzIHZpYSB0aGUgYG9wdGlvbnNgIG9iamVjdC5cXG4gICAgICogQG1ldGhvZCByZWN0YW5nbGVcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHhcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHlcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHRcXG4gICAgICogQHBhcmFtIHtvYmplY3R9IFtvcHRpb25zXVxcbiAgICAgKiBAcmV0dXJuIHtib2R5fSBBIG5ldyByZWN0YW5nbGUgYm9keVxcbiAgICAgKi9cXG4gICAgQm9kaWVzLnJlY3RhbmdsZSA9IGZ1bmN0aW9uKHgsIHksIHdpZHRoLCBoZWlnaHQsIG9wdGlvbnMpIHtcXG4gICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xcblxcbiAgICAgICAgdmFyIHJlY3RhbmdsZSA9IHsgXFxuICAgICAgICAgICAgbGFiZWw6ICdSZWN0YW5nbGUgQm9keScsXFxuICAgICAgICAgICAgcG9zaXRpb246IHsgeDogeCwgeTogeSB9LFxcbiAgICAgICAgICAgIHZlcnRpY2VzOiBWZXJ0aWNlcy5mcm9tUGF0aCgnTCAwIDAgTCAnICsgd2lkdGggKyAnIDAgTCAnICsgd2lkdGggKyAnICcgKyBoZWlnaHQgKyAnIEwgMCAnICsgaGVpZ2h0KVxcbiAgICAgICAgfTtcXG5cXG4gICAgICAgIGlmIChvcHRpb25zLmNoYW1mZXIpIHtcXG4gICAgICAgICAgICB2Y
2XIgY2hhbWZlciA9IG9wdGlvbnMuY2hhbWZlcjtcXG4gICAgICAgICAgICByZWN0YW5nbGUudmVydGljZXMgPSBWZXJ0aWNlcy5jaGFtZmVyKHJlY3RhbmdsZS52ZXJ0aWNlcywgY2hhbWZlci5yYWRpdXMsIFxcbiAgICAgICAgICAgICAgICBjaGFtZmVyLnF1YWxpdHksIGNoYW1mZXIucXVhbGl0eU1pbiwgY2hhbWZlci5xdWFsaXR5TWF4KTtcXG4gICAgICAgICAgICBkZWxldGUgb3B0aW9ucy5jaGFtZmVyO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgcmV0dXJuIEJvZHkuY3JlYXRlKENvbW1vbi5leHRlbmQoe30sIHJlY3RhbmdsZSwgb3B0aW9ucykpO1xcbiAgICB9O1xcbiAgICBcXG4gICAgLyoqXFxuICAgICAqIENyZWF0ZXMgYSBuZXcgcmlnaWQgYm9keSBtb2RlbCB3aXRoIGEgdHJhcGV6b2lkIGh1bGwuIFxcbiAgICAgKiBUaGUgb3B0aW9ucyBwYXJhbWV0ZXIgaXMgYW4gb2JqZWN0IHRoYXQgc3BlY2lmaWVzIGFueSBwcm9wZXJ0aWVzIHlvdSB3aXNoIHRvIG92ZXJyaWRlIHRoZSBkZWZhdWx0cy5cXG4gICAgICogU2VlIHRoZSBwcm9wZXJ0aWVzIHNlY3Rpb24gb2YgdGhlIGBNYXR0ZXIuQm9keWAgbW9kdWxlIGZvciBkZXRhaWxlZCBpbmZvcm1hdGlvbiBvbiB3aGF0IHlvdSBjYW4gcGFzcyB2aWEgdGhlIGBvcHRpb25zYCBvYmplY3QuXFxuICAgICAqIEBtZXRob2QgdHJhcGV6b2lkXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB4XFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB5XFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aFxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0XFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBzbG9wZVxcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gW29wdGlvbnNdXFxuICAgICAqIEByZXR1cm4ge2JvZHl9IEEgbmV3IHRyYXBlem9pZCBib2R5XFxuICAgICAqL1xcbiAgICBCb2RpZXMudHJhcGV6b2lkID0gZnVuY3Rpb24oeCwgeSwgd2lkdGgsIGhlaWdodCwgc2xvcGUsIG9wdGlvbnMpIHtcXG4gICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xcblxcbiAgICAgICAgc2xvcGUgKj0gMC41O1xcbiAgICAgICAgdmFyIHJvb2YgPSAoMSAtIChzbG9wZSAqIDIpKSAqIHdpZHRoO1xcbiAgICAgICAgXFxuICAgICAgICB2Y
2XIgeDEgPSB3aWR0aCAqIHNsb3BlLFxcbiAgICAgICAgICAgIHgyID0geDEgKyByb29mLFxcbiAgICAgICAgICAgIHgzID0geDIgKyB4MSxcXG4gICAgICAgICAgICB2ZXJ0aWNlc1BhdGg7XFxuXFxuICAgICAgICBpZiAoc2xvcGUgPCAwLjUpIHtcXG4gICAgICAgICAgICB2ZXJ0aWNlc1BhdGggPSAnTCAwIDAgTCAnICsgeDEgKyAnICcgKyAoLWhlaWdodCkgKyAnIEwgJyArIHgyICsgJyAnICsgKC1oZWlnaHQpICsgJyBMICcgKyB4MyArICcgMCc7XFxuICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgIHZlcnRpY2VzUGF0aCA9ICdMIDAgMCBMICcgKyB4MiArICcgJyArICgtaGVpZ2h0KSArICcgTCAnICsgeDMgKyAnIDAnO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgdmFyIHRyYXBlem9pZCA9IHsgXFxuICAgICAgICAgICAgbGFiZWw6ICdUcmFwZXpvaWQgQm9keScsXFxuICAgICAgICAgICAgcG9zaXRpb246IHsgeDogeCwgeTogeSB9LFxcbiAgICAgICAgICAgIHZlcnRpY2VzOiBWZXJ0aWNlcy5mcm9tUGF0aCh2ZXJ0aWNlc1BhdGgpXFxuICAgICAgICB9O1xcblxcbiAgICAgICAgaWYgKG9wdGlvbnMuY2hhbWZlcikge1xcbiAgICAgICAgICAgIHZhciBjaGFtZmVyID0gb3B0aW9ucy5jaGFtZmVyO1xcbiAgICAgICAgICAgIHRyYXBlem9pZC52ZXJ0aWNlcyA9IFZlcnRpY2VzLmNoYW1mZXIodHJhcGV6b2lkLnZlcnRpY2VzLCBjaGFtZmVyLnJhZGl1cywgXFxuICAgICAgICAgICAgICAgIGNoYW1mZXIucXVhbGl0eSwgY2hhbWZlci5xdWFsaXR5TWluLCBjaGFtZmVyLnF1YWxpdHlNYXgpO1xcbiAgICAgICAgICAgIGRlbGV0ZSBvcHRpb25zLmNoYW1mZXI7XFxuICAgICAgICB9XFxuXFxuICAgICAgICByZXR1cm4gQm9keS5jcmVhdGUoQ29tbW9uLmV4dGVuZCh7fSwgdHJhcGV6b2lkLCBvcHRpb25zKSk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBDcmVhdGVzIGEgbmV3IHJpZ2lkIGJvZHkgbW9kZWwgd2l0aCBhIGNpcmNsZSBodWxsLiBcXG4gICAgICogVGhlIG9wdGlvbnMgcGFyYW1ldGVyIGlzIGFuIG9iamVjdCB0aGF0IHNwZWNpZmllcyBhbnkgcHJvcGVydGllcyB5b3Ugd2lzaCB0byBvdmVycmlkZSB0aGUgZGVmYXVsdHMuXFxuICAgICAqIFNlZSB0aGUgcHJvcGVydGllcyBzZWN0aW9uIG9mIHRoZSBgTWF0dGVyLkJvZHlgIG1vZHVsZSBmb3IgZGV0YWlsZWQgaW5mb3JtYXRpb24gb24gd2hhdCB5b3UgY2FuIHBhc3MgdmlhIHRoZSBgb3B0aW9uc2Agb2JqZWN0LlxcbiAgICAgKiBAbWV0aG9kIGNpcmNsZVxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0geFxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0geVxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gcmFkaXVzXFxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBbb3B0aW9uc11cXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IFttYXhTaWRlc11cXG4gICAgICogQHJldHVybiB7Ym9keX0gQSBuZXcgY2lyY2xlIGJvZHlcXG4gICAgICovXFxuICAgIEJvZGllcy5jaXJjbGUgPSBmdW5jdGlvbih4LCB5LCByYWRpdXMsIG9wdGlvbnMsIG1heFNpZGVzKSB7XFxuICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcXG5cXG4gICAgICAgIHZhciBjaXJjbGUgPSB7XFxuICAgICAgICAgICAgbGFiZWw6ICdDaXJjbGUgQm9keScsXFxuICAgICAgICAgICAgY2lyY2xlUmFkaXVzOiByYWRpdXNcXG4gICAgICAgIH07XFxuICAgICAgICBcXG4gICAgICAgIC8vIGFwcHJveGltYXRlIGNpcmNsZXMgd2l0aCBwb2x5Z29ucyB1bnRpbCB0cnVlIGNpcmNsZXMgaW1wbGVtZW50ZWQgaW4gU0FUXFxuICAgICAgICBtYXhTaWRlcyA9IG1heFNpZGVzIHx8IDI1O1xcbiAgICAgICAgdmFyIHNpZGVzID0gTWF0aC5jZWlsKE1hdGgubWF4KDEwLCBNYXRoLm1pbihtYXhTaWRlcywgcmFkaXVzKSkpO1xcblxcbiAgICAgICAgLy8gb3B0aW1pc2F0aW9uOiBhbHdheXMgdXNlIGV2ZW4gbnVtYmVyIG9mIHNpZGVzIChoYWxmIHRoZSBudW1iZXIgb2YgdW5pcXVlIGF4ZXMpXFxuICAgICAgICBpZiAoc2lkZXMgJSAyID09PSAxKVxcbiAgICAgICAgICAgIHNpZGVzICs9IDE7XFxuXFxuICAgICAgICByZXR1cm4gQm9kaWVzLnBvbHlnb24oeCwgeSwgc2lkZXMsIHJhZGl1cywgQ29tbW9uLmV4dGVuZCh7fSwgY2lyY2xlLCBvcHRpb25zKSk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBDcmVhdGVzIGEgbmV3IHJpZ2lkIGJvZHkgbW9kZWwgd2l0aCBhIHJlZ3VsYXIgcG9seWdvbiBodWxsIHdpdGggdGhlIGdpdmVuIG51bWJlciBvZiBzaWRlcy4gXFxuICAgICAqIFRoZSBvcHRpb25zIHBhcmFtZXRlciBpcyBhbiBvYmplY3QgdGhhdCBzcGVjaWZpZXMgYW55IHByb3BlcnRpZXMgeW91IHdpc2ggdG8gb3ZlcnJpZGUgdGhlIGRlZmF1bHRzLlxcbiAgICAgKiBTZWUgdGhlIHByb3BlcnRpZXMgc2VjdGlvbiBvZiB0aGUgYE1hdHRlci5Cb2R5YCBtb2R1bGUgZm9yIGRldGFpbGVkIGluZm9ybWF0aW9uIG9uIHdoYXQgeW91IGNhbiBwYXNzIHZpYSB0aGUgYG9wdGlvbnNgIG9iamVjdC5cXG4gICAgICogQG1ldGhvZCBwb2x5Z29uXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB4XFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB5XFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBzaWRlc1xcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gcmFkaXVzXFxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBbb3B0aW9uc11cXG4gICAgICogQHJldHVybiB7Ym9keX0gQSBuZXcgcmVndWxhciBwb2x5Z29uIGJvZHlcXG4gICAgICovXFxuICAgIEJvZGllcy5wb2x5Z29uID0gZnVuY3Rpb24oeCwgeSwgc2lkZXMsIHJhZGl1cywgb3B0aW9ucykge1xcbiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XFxuXFxuICAgICAgICBpZiAoc2lkZXMgPCAzKVxcbiAgICAgICAgICAgIHJldHVybiBCb2RpZXMuY2lyY2xlKHgsIHksIHJhZGl1cywgb3B0aW9ucyk7XFxuXFxuICAgICAgICB2Y
2XIgdGhldGEgPSAyICogTWF0aC5QSSAvIHNpZGVzLFxcbiAgICAgICAgICAgIHBhdGggPSAnJyxcXG4gICAgICAgICAgICBvZmZzZXQgPSB0aGV0YSAqIDAuNTtcXG5cXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2lkZXM7IGkgKz0gMSkge1xcbiAgICAgICAgICAgIHZhciBhbmdsZSA9IG9mZnNldCArIChpICogdGhldGEpLFxcbiAgICAgICAgICAgICAgICB4eCA9IE1hdGguY29zKGFuZ2xlKSAqIHJhZGl1cyxcXG4gICAgICAgICAgICAgICAgeXkgPSBNYXRoLnNpbihhbmdsZSkgKiByYWRpdXM7XFxuXFxuICAgICAgICAgICAgcGF0aCArPSAnTCAnICsgeHgudG9GaXhlZCgzKSArICcgJyArIHl5LnRvRml4ZWQoMykgKyAnICc7XFxuICAgICAgICB9XFxuXFxuICAgICAgICB2YXIgcG9seWdvbiA9IHsgXFxuICAgICAgICAgICAgbGFiZWw6ICdQb2x5Z29uIEJvZHknLFxcbiAgICAgICAgICAgIHBvc2l0aW9uOiB7IHg6IHgsIHk6IHkgfSxcXG4gICAgICAgICAgICB2ZXJ0aWNlczogVmVydGljZXMuZnJvbVBhdGgocGF0aClcXG4gICAgICAgIH07XFxuXFxuICAgICAgICBpZiAob3B0aW9ucy5jaGFtZmVyKSB7XFxuICAgICAgICAgICAgdmFyIGNoYW1mZXIgPSBvcHRpb25zLmNoYW1mZXI7XFxuICAgICAgICAgICAgcG9seWdvbi52ZXJ0aWNlcyA9IFZlcnRpY2VzLmNoYW1mZXIocG9seWdvbi52ZXJ0aWNlcywgY2hhbWZlci5yYWRpdXMsIFxcbiAgICAgICAgICAgICAgICBjaGFtZmVyLnF1YWxpdHksIGNoYW1mZXIucXVhbGl0eU1pbiwgY2hhbWZlci5xdWFsaXR5TWF4KTtcXG4gICAgICAgICAgICBkZWxldGUgb3B0aW9ucy5jaGFtZmVyO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgcmV0dXJuIEJvZHkuY3JlYXRlKENvbW1vbi5leHRlbmQoe30sIHBvbHlnb24sIG9wdGlvbnMpKTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFV0aWxpdHkgdG8gY3JlYXRlIGEgY29tcG91bmQgYm9keSBiYXNlZCBvbiBzZXQocykgb2YgdmVydGljZXMuXFxuICAgICAqIFxcbiAgICAgKiBfTm90ZTpfIFRvIG9wdGlvbmFsbHkgZW5hYmxlIGF1dG9tYXRpYyBjb25jYXZlIHZlcnRpY2VzIGRlY29tcG9zaXRpb24gdGhlIFtwb2x5LWRlY29tcF0oaHR0cHM6Ly9naXRodWIuY29tL3NjaHRlcHBlL3BvbHktZGVjb21wLmpzKSBcXG4gICAgICogcGFja2FnZSBtdXN0IGJlIGZpcnN0IGluc3RhbGxlZCBhbmQgcHJvdmlkZWQgc2VlIGBDb21tb24uc2V0RGVjb21wYCwgb3RoZXJ3aXNlIHRoZSBjb252ZXggaHVsbCBvZiBlYWNoIHZlcnRleCBzZXQgd2lsbCBiZSB1c2VkLlxcbiAgICAgKiBcXG4gICAgICogVGhlIHJlc3VsdGluZyB2ZXJ0aWNlcyBhcmUgcmVvcmllbnRhdGVkIGFib3V0IHRoZWlyIGNlbnRyZSBvZiBtYXNzLFxcbiAgICAgKiBhbmQgb2Zmc2V0IHN1Y2ggdGhhdCBgYm9keS5wb3NpdGlvbmAgY29ycmVzcG9uZHMgdG8gdGhpcyBwb2ludC5cXG4gICAgICogXFxuICAgICAqIFRoZSByZXN1bHRpbmcgb2Zmc2V0IG1heSBiZSBmb3VuZCBpZiBuZWVkZWQgYnkgc3VidHJhY3RpbmcgYGJvZHkuYm91bmRzYCBmcm9tIHRoZSBvcmlnaW5hbCBpbnB1dCBib3VuZHMuXFxuICAgICAqIFRvIGxhdGVyIG1vdmUgdGhlIGNlbnRyZSBvZiBtYXNzIHNlZSBgQm9keS5zZXRDZW50cmVgLlxcbiAgICAgKiBcXG4gICAgICogTm90ZSB0aGF0IGF1dG9tYXRpYyBjb25jb25jYXZlIGRlY29tcG9zaXRpb24gcmVzdWx0cyBhcmUgbm90IGFsd2F5cyBvcHRpbWFsLiBcXG4gICAgICogRm9yIGJlc3QgcmVzdWx0cywgc2ltcGxpZnkgdGhlIGlucHV0IHZlcnRpY2VzIGFzIG11Y2ggYXMgcG9zc2libGUgZmlyc3QuXFxuICAgICAqIEJ5IGRlZmF1bHQgdGhpcyBmdW5jdGlvbiBhcHBsaWVzIHNvbWUgYWRkdGlvbmFsIHNpbXBsaWZpY2F0aW9uIHRvIGhlbHAuXFxuICAgICAqIFxcbiAgICAgKiBTb21lIG91dHB1dHMgbWF5IGFsc28gcmVxdWlyZSBmdXJ0aGVyIG1hbnVhbCBwcm9jZXNzaW5nIGFmdGVyd2FyZHMgdG8gYmUgcm9idXN0LlxcbiAgICAgKiBJbiBwYXJ0aWN1bGFyIHNvbWUgcGFydHMgbWF5IG5lZWQgdG8gYmUgb3ZlcmxhcHBlZCB0byBhdm9pZCBjb2xsaXNpb24gZ2Fwcy5cXG4gICAgICogVGhpbiBwYXJ0cyBhbmQgc2hhcnAgcG9pbnRzIHNob3VsZCBiZSBhdm9pZGVkIG9yIHJlbW92ZWQgd2hlcmUgcG9zc2libGUuXFxuICAgICAqXFxuICAgICAqIFRoZSBvcHRpb25zIHBhcmFtZXRlciBvYmplY3Qgc3BlY2lmaWVzIGFueSBgTWF0dGVyLkJvZHlgIHByb3BlcnRpZXMgeW91IHdpc2ggdG8gb3ZlcnJpZGUgdGhlIGRlZmF1bHRzLlxcbiAgICAgKiBcXG4gICAgICogU2VlIHRoZSBwcm9wZXJ0aWVzIHNlY3Rpb24gb2YgdGhlIGBNYXR0ZXIuQm9keWAgbW9kdWxlIGZvciBkZXRhaWxlZCBpbmZvcm1hdGlvbiBvbiB3aGF0IHlvdSBjYW4gcGFzcyB2aWEgdGhlIGBvcHRpb25zYCBvYmplY3QuXFxuICAgICAqIEBtZXRob2QgZnJvbVZlcnRpY2VzXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB4XFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB5XFxuICAgICAqIEBwYXJhbSB7YXJyYXl9IHZlcnRleFNldHMgT25lIG9yIG1vcmUgYXJyYXlzIG9mIHZlcnRleCBwb2ludHMgZS5nLiBgW1t7IHg6IDAsIHk6IDAgfS4uLl0sIC4uLl1gLlxcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gW29wdGlvbnNdIFRoZSBib2R5IG9wdGlvbnMuXFxuICAgICAqIEBwYXJhbSB7Ym9vbH0gW2ZsYWdJbnRlcm5hbD1mYWxzZV0gT3B0aW9uYWxseSBtYXJrcyBpbnRlcm5hbCBlZGdlcyB3aXRoIGBpc0ludGVybmFsYC5cXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IFtyZW1vdmVDb2xsaW5lYXI9MC4wMV0gVGhyZXNob2xkIHdoZW4gc2ltcGxpZnlpbmcgdmVydGljZXMgYWxvbmcgdGhlIHNhbWUgZWRnZS5cXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IFttaW5pbXVtQXJlYT0xMF0gVGhyZXNob2xkIHdoZW4gcmVtb3Zpbmcgc21hbGwgcGFydHMuXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbcmVtb3ZlRHVwbGljYXRlUG9pbnRzPTAuMDFdIFRocmVzaG9sZCB3aGVuIHNpbXBsaWZ5aW5nIG5lYXJieSB2ZXJ0aWNlcy5cXG4gICAgICogQHJldHVybiB7Ym9keX1cXG4gICAgICovXFxuICAgIEJvZGllcy5mcm9tVmVydGljZXMgPSBmdW5jdGlvbih4LCB5LCB2ZXJ0ZXhTZXRzLCBvcHRpb25zLCBmbGFnSW50ZXJuYWwsIHJlbW92ZUNvbGxpbmVhciwgbWluaW11bUFyZWEsIHJlbW92ZUR1cGxpY2F0ZVBvaW50cykge1xcbiAgICAgICAgdmFyIGRlY29tcCA9IENvbW1vbi5nZXREZWNvbXAoKSxcXG4gICAgICAgICAgICBjYW5EZWNvbXAsXFxuICAgICAgICAgICAgYm9keSxcXG4gICAgICAgICAgICBwYXJ0cyxcXG4gICAgICAgICAgICBpc0NvbnZleCxcXG4gICAgICAgICAgICBpc0NvbmNhdmUsXFxuICAgICAgICAgICAgdmVydGljZXMsX
2FxuICAgICAgICAgICAgaSxcXG4gICAgICAgICAgICBqLFxcbiAgICAgICAgICAgIGssXFxuICAgICAgICAgICAgdixcXG4gICAgICAgICAgICB6O1xcblxcbiAgICAgICAgLy8gY2hlY2sgZGVjb21wIGlzIGFzIGV4cGVjdGVkXFxuICAgICAgICBjYW5EZWNvbXAgPSBCb29sZWFuKGRlY29tcCAmJiBkZWNvbXAucXVpY2tEZWNvbXApO1xcblxcbiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XFxuICAgICAgICBwYXJ0cyA9IFtdO1xcblxcbiAgICAgICAgZmxhZ0ludGVybmFsID0gdHlwZW9mIGZsYWdJbnRlcm5hbCAhPT0gJ3VuZGVmaW5lZCcgPyBmbGFnSW50ZXJuYWwgOiBmYWxzZTtcXG4gICAgICAgIHJlbW92ZUNvbGxpbmVhciA9IHR5cGVvZiByZW1vdmVDb2xsaW5lYXIgIT09ICd1bmRlZmluZWQnID8gcmVtb3ZlQ29sbGluZWFyIDogMC4wMTtcXG4gICAgICAgIG1pbmltdW1BcmVhID0gdHlwZW9mIG1pbmltdW1BcmVhICE9PSAndW5kZWZpbmVkJyA/IG1pbmltdW1BcmVhIDogMTA7XFxuICAgICAgICByZW1vdmVEdXBsaWNhdGVQb2ludHMgPSB0eXBlb2YgcmVtb3ZlRHVwbGljYXRlUG9pbnRzICE9PSAndW5kZWZpbmVkJyA/IHJlbW92ZUR1cGxpY2F0ZVBvaW50cyA6IDAuMDE7XFxuXFxuICAgICAgICAvLyBlbnN1cmUgdmVydGV4U2V0cyBpcyBhbiBhcnJheSBvZiBhcnJheXNcXG4gICAgICAgIGlmICghQ29tbW9uLmlzQXJyYXkodmVydGV4U2V0c1swXSkpIHtcXG4gICAgICAgICAgICB2ZXJ0ZXhTZXRzID0gW3ZlcnRleFNldHNdO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgZm9yICh2ID0gMDsgdiA8IHZlcnRleFNldHMubGVuZ3RoOyB2ICs9IDEpIHtcXG4gICAgICAgICAgICB2ZXJ0aWNlcyA9IHZlcnRleFNldHNbdl07XFxuICAgICAgICAgICAgaXNDb252ZXggPSBWZXJ0aWNlcy5pc0NvbnZleCh2ZXJ0aWNlcyk7XFxuICAgICAgICAgICAgaXNDb25jYXZlID0gIWlzQ29udmV4O1xcblxcbiAgICAgICAgICAgIGlmIChpc0NvbmNhdmUgJiYgIWNhbkRlY29tcCkge1xcbiAgICAgICAgICAgICAgICBDb21tb24ud2Fybk9uY2UoXFxuICAgICAgICAgICAgICAgICAgICAnQm9kaWVzLmZyb21WZXJ0aWNlczogSW5zdGFsbCB0aGUgXFxcXCdwb2x5LWRlY29tcFxcXFwnIGxpYnJhcnkgYW5kIHVzZSBDb21tb24uc2V0RGVjb21wIG9yIHByb3ZpZGUgXFxcXCdkZWNvbXBcXFxcJyBhcyBhIGdsb2JhbCB0byBkZWNvbXBvc2UgY29uY2F2ZSB2ZXJ0aWNlcy4nXFxuICAgICAgICAgICAgICAgICk7XFxuICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgIGlmIChpc0NvbnZleCB8fCAhY2FuRGVjb21wKSB7XFxuICAgICAgICAgICAgICAgIGlmIChpc0NvbnZleCkge1xcbiAgICAgICAgICAgICAgICAgICAgdmVydGljZXMgPSBWZXJ0aWNlcy5jbG9ja3dpc2VTb3J0KHZlcnRpY2VzKTtcXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICAgICAgICAgIC8vIGZhbGxiYWNrIHRvIGNvbnZleCBodWxsIHdoZW4gZGVjb21wb3NpdGlvbiBpcyBub3QgcG9zc2libGVcXG4gICAgICAgICAgICAgICAgICAgIHZlcnRpY2VzID0gVmVydGljZXMuaHVsbCh2ZXJ0aWNlcyk7XFxuICAgICAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICAgICAgcGFydHMucHVzaCh7XFxuICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbjogeyB4OiB4LCB5OiB5IH0sXFxuICAgICAgICAgICAgICAgICAgICB2ZXJ0aWNlczogdmVydGljZXNcXG4gICAgICAgICAgICAgICAgfSk7XFxuICAgICAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICAgICAgLy8gaW5pdGlhbGlzZSBhIGRlY29tcG9zaXRpb25cXG4gICAgICAgICAgICAgICAgdmFyIGNvbmNhdmUgPSB2ZXJ0aWNlcy5tYXAoZnVuY3Rpb24odmVydGV4KSB7XFxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gW3ZlcnRleC54LCB2ZXJ0ZXgueV07XFxuICAgICAgICAgICAgICAgIH0pO1xcblxcbiAgICAgICAgICAgICAgICAvLyB2ZXJ0aWNlcyBhcmUgY29uY2F2ZSBhbmQgc2ltcGxlLCB3ZSBjYW4gZGVjb21wb3NlIGludG8gcGFydHNcXG4gICAgICAgICAgICAgICAgZGVjb21wLm1ha2VDQ1coY29uY2F2ZSk7XFxuICAgICAgICAgICAgICAgIGlmIChyZW1vdmVDb2xsaW5lYXIgIT09IGZhbHNlKVxcbiAgICAgICAgICAgICAgICAgICAgZGVjb21wLnJlbW92ZUNvbGxpbmVhclBvaW50cyhjb25jYXZlLCByZW1vdmVDb2xsaW5lYXIpO1xcbiAgICAgICAgICAgICAgICBpZiAocmVtb3ZlRHVwbGljYXRlUG9pbnRzICE9PSBmYWxzZSAmJiBkZWNvbXAucmVtb3ZlRHVwbGljYXRlUG9pbnRzKVxcbiAgICAgICAgICAgICAgICAgICAgZGVjb21wLnJlbW92ZUR1cGxpY2F0ZVBvaW50cyhjb25jYXZlLCByZW1vdmVEdXBsaWNhdGVQb2ludHMpO1xcblxcbiAgICAgICAgICAgICAgICAvLyB1c2UgdGhlIHF1aWNrIGRlY29tcG9zaXRpb24gYWxnb3JpdGhtIChCYXlheml0KVxcbiAgICAgICAgICAgICAgICB2Y
2XIgZGVjb21wb3NlZCA9IGRlY29tcC5xdWlja0RlY29tcChjb25jYXZlKTtcXG5cXG4gICAgICAgICAgICAgICAgLy8gZm9yIGVhY2ggZGVjb21wb3NlZCBjaHVua1xcbiAgICAgICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgZGVjb21wb3NlZC5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgICAgICAgICAgdmFyIGNodW5rID0gZGVjb21wb3NlZFtpXTtcXG5cXG4gICAgICAgICAgICAgICAgICAgIC8vIGNvbnZlcnQgdmVydGljZXMgaW50byB0aGUgY29ycmVjdCBzdHJ1Y3R1cmVcXG4gICAgICAgICAgICAgICAgICAgIHZhciBjaHVua1ZlcnRpY2VzID0gY2h1bmsubWFwKGZ1bmN0aW9uKHZlcnRpY2VzKSB7XFxuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgeDogdmVydGljZXNbMF0sXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk6IHZlcnRpY2VzWzFdXFxuICAgICAgICAgICAgICAgICAgICAgICAgfTtcXG4gICAgICAgICAgICAgICAgICAgIH0pO1xcblxcbiAgICAgICAgICAgICAgICAgICAgLy8gc2tpcCBzbWFsbCBjaHVua3NcXG4gICAgICAgICAgICAgICAgICAgIGlmIChtaW5pbXVtQXJlYSA+IDAgJiYgVmVydGljZXMuYXJlYShjaHVua1ZlcnRpY2VzKSA8IG1pbmltdW1BcmVhKVxcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xcblxcbiAgICAgICAgICAgICAgICAgICAgLy8gY3JlYXRlIGEgY29tcG91bmQgcGFydFxcbiAgICAgICAgICAgICAgICAgICAgcGFydHMucHVzaCh7XFxuICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb246IFZlcnRpY2VzLmNlbnRyZShjaHVua1ZlcnRpY2VzKSxcXG4gICAgICAgICAgICAgICAgICAgICAgICB2ZXJ0aWNlczogY2h1bmtWZXJ0aWNlc1xcbiAgICAgICAgICAgICAgICAgICAgfSk7XFxuICAgICAgICAgICAgICAgIH1cXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuXFxuICAgICAgICAvLyBjcmVhdGUgYm9keSBwYXJ0c1xcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IHBhcnRzLmxlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgcGFydHNbaV0gPSBCb2R5LmNyZWF0ZShDb21tb24uZXh0ZW5kKHBhcnRzW2ldLCBvcHRpb25zKSk7XFxuICAgICAgICB9XFxuXFxuICAgICAgICAvLyBmbGFnIGludGVybmFsIGVkZ2VzIChjb2luY2lkZW50IHBhcnQgZWRnZXMpXFxuICAgICAgICBpZiAoZmxhZ0ludGVybmFsKSB7XFxuICAgICAgICAgICAgdmFyIGNvaW5jaWRlbnRfbWF4X2Rpc3QgPSA1O1xcblxcbiAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBwYXJ0cy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgICAgICB2Y
2XIgcGFydEEgPSBwYXJ0c1tpXTtcXG5cXG4gICAgICAgICAgICAgICAgZm9yIChqID0gaSArIDE7IGogPCBwYXJ0cy5sZW5ndGg7IGorKykge1xcbiAgICAgICAgICAgICAgICAgICAgdmFyIHBhcnRCID0gcGFydHNbal07XFxuXFxuICAgICAgICAgICAgICAgICAgICBpZiAoQm91bmRzLm92ZXJsYXBzKHBhcnRBLmJvdW5kcywgcGFydEIuYm91bmRzKSkge1xcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBwYXYgPSBwYXJ0QS52ZXJ0aWNlcyxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcGJ2ID0gcGFydEIudmVydGljZXM7XFxuXFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gaXRlcmF0ZSB2ZXJ0aWNlcyBvZiBib3RoIHBhcnRzXFxuICAgICAgICAgICAgICAgICAgICAgICAgZm9yIChrID0gMDsgayA8IHBhcnRBLnZlcnRpY2VzLmxlbmd0aDsgaysrKSB7XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoeiA9IDA7IHogPCBwYXJ0Qi52ZXJ0aWNlcy5sZW5ndGg7IHorKykge1xcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gZmluZCBkaXN0YW5jZXMgYmV0d2VlbiB0aGUgdmVydGljZXNcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBkYSA9IFZlY3Rvci5tYWduaXR1ZGVTcXVhcmVkKFZlY3Rvci5zdWIocGF2WyhrICsgMSkgJSBwYXYubGVuZ3RoXSwgcGJ2W3pdKSksXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGIgPSBWZWN0b3IubWFnbml0dWRlU3F1YXJlZChWZWN0b3Iuc3ViKHBhdltrXSwgcGJ2Wyh6ICsgMSkgJSBwYnYubGVuZ3RoXSkpO1xcblxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaWYgYm90aCB2ZXJ0aWNlcyBhcmUgdmVyeSBjbG9zZSwgY29uc2lkZXIgdGhlIGVkZ2UgY29uY2lkZW50IChpbnRlcm5hbClcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChkYSA8IGNvaW5jaWRlbnRfbWF4X2Rpc3QgJiYgZGIgPCBjb2luY2lkZW50X21heF9kaXN0KSB7XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF2W2tdLmlzSW50ZXJuYWwgPSB0cnVlO1xcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBidlt6XS5pc0ludGVybmFsID0gdHJ1ZTtcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICAgICAgICAgIH1cXG4gICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG5cXG4gICAgICAgIGlmIChwYXJ0cy5sZW5ndGggPiAxKSB7XFxuICAgICAgICAgICAgLy8gY3JlYXRlIHRoZSBwYXJlbnQgYm9keSB0byBiZSByZXR1cm5lZCwgdGhhdCBjb250YWlucyBnZW5lcmF0ZWQgY29tcG91bmQgcGFydHNcXG4gICAgICAgICAgICBib2R5ID0gQm9keS5jcmVhdGUoQ29tbW9uLmV4dGVuZCh7IHBhcnRzOiBwYXJ0cy5zbGljZSgwKSB9LCBvcHRpb25zKSk7XFxuXFxuICAgICAgICAgICAgLy8gb2Zmc2V0IHN1Y2ggdGhhdCBib2R5LnBvc2l0aW9uIGlzIGF0IHRoZSBjZW50cmUgb2ZmIG1hc3NcXG4gICAgICAgICAgICBCb2R5LnNldFBvc2l0aW9uKGJvZHksIHsgeDogeCwgeTogeSB9KTtcXG5cXG4gICAgICAgICAgICByZXR1cm4gYm9keTtcXG4gICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgcmV0dXJuIHBhcnRzWzBdO1xcbiAgICAgICAgfVxcbiAgICB9O1xcblxcbn0pKCk7XFxuXFxuXFxuLyoqKi8gfSksXFxuLyogMTMgKi9cXG4vKioqLyAoZnVuY3Rpb24obW9kdWxlLCBleHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XFxuXFxuLyoqXFxuKiBUaGUgYE1hdHRlci5EZXRlY3RvcmAgbW9kdWxlIGNvbnRhaW5zIG1ldGhvZHMgZm9yIGVmZmljaWVudGx5IGRldGVjdGluZyBjb2xsaXNpb25zIGJldHdlZW4gYSBsaXN0IG9mIGJvZGllcyB1c2luZyBhIGJyb2FkcGhhc2UgYWxnb3JpdGhtLlxcbipcXG4qIEBjbGFzcyBEZXRlY3RvclxcbiovXFxuXFxudmFyIERldGVjdG9yID0ge307XFxuXFxubW9kdWxlLmV4cG9ydHMgPSBEZXRlY3RvcjtcXG5cXG52YXIgQ29tbW9uID0gX193ZWJwYWNrX3JlcXVpcmVfXygwKTtcXG52YXIgQ29sbGlzaW9uID0gX193ZWJwYWNrX3JlcXVpcmVfXyg4KTtcXG5cXG4oZnVuY3Rpb24oKSB7XFxuXFxuICAgIC8qKlxcbiAgICAgKiBDcmVhdGVzIGEgbmV3IGNvbGxpc2lvbiBkZXRlY3Rvci5cXG4gICAgICogQG1ldGhvZCBjcmVhdGVcXG4gICAgICogQHBhcmFtIHt9IG9wdGlvbnNcXG4gICAgICogQHJldHVybiB7ZGV0ZWN0b3J9IEEgbmV3IGNvbGxpc2lvbiBkZXRlY3RvclxcbiAgICAgKi9cXG4gICAgRGV0ZWN0b3IuY3JlYXRlID0gZnVuY3Rpb24ob3B0aW9ucykge1xcbiAgICAgICAgdmFyIGRlZmF1bHRzID0ge1xcbiAgICAgICAgICAgIGJvZGllczogW10sXFxuICAgICAgICAgICAgcGFpcnM6IG51bGxcXG4gICAgICAgIH07XFxuXFxuICAgICAgICByZXR1cm4gQ29tbW9uLmV4dGVuZChkZWZhdWx0cywgb3B0aW9ucyk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBTZXRzIHRoZSBsaXN0IG9mIGJvZGllcyBpbiB0aGUgZGV0ZWN0b3IuXFxuICAgICAqIEBtZXRob2Qgc2V0Qm9kaWVzXFxuICAgICAqIEBwYXJhbSB7ZGV0ZWN0b3J9IGRldGVjdG9yXFxuICAgICAqIEBwYXJhbSB7Ym9keVtdfSBib2RpZXNcXG4gICAgICovXFxuICAgIERldGVjdG9yLnNldEJvZGllcyA9IGZ1bmN0aW9uKGRldGVjdG9yLCBib2RpZXMpIHtcXG4gICAgICAgIGRldGVjdG9yLmJvZGllcyA9IGJvZGllcy5zbGljZSgwKTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIENsZWFycyB0aGUgZGV0ZWN0b3IgaW5jbHVkaW5nIGl0cyBsaXN0IG9mIGJvZGllcy5cXG4gICAgICogQG1ldGhvZCBjbGVhclxcbiAgICAgKiBAcGFyYW0ge2RldGVjdG9yfSBkZXRlY3RvclxcbiAgICAgKi9cXG4gICAgRGV0ZWN0b3IuY2xlYXIgPSBmdW5jdGlvbihkZXRlY3Rvcikge1xcbiAgICAgICAgZGV0ZWN0b3IuYm9kaWVzID0gW107XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBFZmZpY2llbnRseSBmaW5kcyBhbGwgY29sbGlzaW9ucyBhbW9uZyBhbGwgdGhlIGJvZGllcyBpbiBgZGV0ZWN0b3IuYm9kaWVzYCB1c2luZyBhIGJyb2FkcGhhc2UgYWxnb3JpdGhtLlxcbiAgICAgKiBcXG4gICAgICogX05vdGU6XyBUaGUgc3BlY2lmaWMgb3J
2kZXJpbmcgb2YgY29sbGlzaW9ucyByZXR1cm5lZCBpcyBub3QgZ3VhcmFudGVlZCBiZXR3ZWVuIHJlbGVhc2VzIGFuZCBtYXkgY2hhbmdlIGZvciBwZXJmb3JtYW5jZSByZWFzb25zLlxcbiAgICAgKiBJZiBhIHNwZWNpZmljIG9yZGVyaW5nIGlzIHJlcXVpcmVkIHRoZW4gYXBwbHkgYSBzb3J0IHRvIHRoZSByZXN1bHRpbmcgYXJyYXkuXFxuICAgICAqIEBtZXRob2QgY29sbGlzaW9uc1xcbiAgICAgKiBAcGFyYW0ge2RldGVjdG9yfSBkZXRlY3RvclxcbiAgICAgKiBAcmV0dXJuIHtjb2xsaXNpb25bXX0gY29sbGlzaW9uc1xcbiAgICAgKi9cXG4gICAgRGV0ZWN0b3IuY29sbGlzaW9ucyA9IGZ1bmN0aW9uKGRldGVjdG9yKSB7XFxuICAgICAgICB2YXIgY29sbGlzaW9ucyA9IFtdLFxcbiAgICAgICAgICAgIHBhaXJzID0gZGV0ZWN0b3IucGFpcnMsXFxuICAgICAgICAgICAgYm9kaWVzID0gZGV0ZWN0b3IuYm9kaWVzLFxcbiAgICAgICAgICAgIGJvZGllc0xlbmd0aCA9IGJvZGllcy5sZW5ndGgsXFxuICAgICAgICAgICAgY2FuQ29sbGlkZSA9IERldGVjdG9yLmNhbkNvbGxpZGUsXFxuICAgICAgICAgICAgY29sbGlkZXMgPSBDb2xsaXNpb24uY29sbGlkZXMsXFxuICAgICAgICAgICAgaSxcXG4gICAgICAgICAgICBqO1xcblxcbiAgICAgICAgYm9kaWVzLnNvcnQoRGV0ZWN0b3IuX2NvbXBhcmVCb3VuZHNYKTtcXG5cXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBib2RpZXNMZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHZhciBib2R5QSA9IGJvZGllc1tpXSxcXG4gICAgICAgICAgICAgICAgYm91bmRzQSA9IGJvZHlBLmJvdW5kcyxcXG4gICAgICAgICAgICAgICAgYm91bmRYTWF4ID0gYm9keUEuYm91bmRzLm1heC54LFxcbiAgICAgICAgICAgICAgICBib3VuZFlNYXggPSBib2R5QS5ib3VuZHMubWF4LnksXFxuICAgICAgICAgICAgICAgIGJvdW5kWU1pbiA9IGJvZHlBLmJvdW5kcy5taW4ueSxcXG4gICAgICAgICAgICAgICAgYm9keUFTdGF0aWMgPSBib2R5QS5pc1N0YXRpYyB8fCBib2R5QS5pc1NsZWVwaW5nLFxcbiAgICAgICAgICAgICAgICBwYXJ0c0FMZW5ndGggPSBib2R5QS5wYXJ0cy5sZW5ndGgsXFxuICAgICAgICAgICAgICAgIHBhcnRzQVNpbmdsZSA9IHBhcnRzQUxlbmd0aCA9PT0gMTtcXG5cXG4gICAgICAgICAgICBmb3IgKGogPSBpICsgMTsgaiA8IGJvZGllc0xlbmd0aDsgaisrKSB7XFxuICAgICAgICAgICAgICAgIHZhciBib2R5QiA9IGJvZGllc1tqXSxcXG4gICAgICAgICAgICAgICAgICAgIGJvdW5kc0IgPSBib2R5Qi5ib3VuZHM7XFxuXFxuICAgICAgICAgICAgICAgIGlmIChib3VuZHNCLm1pbi54ID4gYm91bmRYTWF4KSB7XFxuICAgICAgICAgICAgICAgICAgICBicmVhaztcXG4gICAgICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgICAgICBpZiAoYm91bmRZTWF4IDwgYm91bmRzQi5taW4ueSB8fCBib3VuZFlNaW4gPiBib3VuZHNCLm1heC55KSB7XFxuICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcXG4gICAgICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgICAgICBpZiAoYm9keUFTdGF0aWMgJiYgKGJvZHlCLmlzU3RhdGljIHx8IGJvZHlCLmlzU2xlZXBpbmcpKSB7XFxuICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcXG4gICAgICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgICAgICBpZiAoIWNhbkNvbGxpZGUoYm9keUEuY29sbGlzaW9uRmlsdGVyLCBib2R5Qi5jb2xsaXNpb25GaWx0ZXIpKSB7XFxuICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcXG4gICAgICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgICAgICB2Y
2XIgcGFydHNCTGVuZ3RoID0gYm9keUIucGFydHMubGVuZ3RoO1xcblxcbiAgICAgICAgICAgICAgICBpZiAocGFydHNBU2luZ2xlICYmIHBhcnRzQkxlbmd0aCA9PT0gMSkge1xcbiAgICAgICAgICAgICAgICAgICAgdmFyIGNvbGxpc2lvbiA9IGNvbGxpZGVzKGJvZHlBLCBib2R5QiwgcGFpcnMpO1xcblxcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNvbGxpc2lvbikge1xcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbGxpc2lvbnMucHVzaChjb2xsaXNpb24pO1xcbiAgICAgICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgICAgICAgICAgdmFyIHBhcnRzQVN0YXJ0ID0gcGFydHNBTGVuZ3RoID4gMSA/IDEgOiAwLFxcbiAgICAgICAgICAgICAgICAgICAgICAgIHBhcnRzQlN0YXJ0ID0gcGFydHNCTGVuZ3RoID4gMSA/IDEgOiAwO1xcbiAgICAgICAgICAgICAgICAgICAgXFxuICAgICAgICAgICAgICAgICAgICBmb3IgKHZhciBrID0gcGFydHNBU3RhcnQ7IGsgPCBwYXJ0c0FMZW5ndGg7IGsrKykge1xcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBwYXJ0QSA9IGJvZHlBLnBhcnRzW2tdLFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBib3VuZHNBID0gcGFydEEuYm91bmRzO1xcblxcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAodmFyIHogPSBwYXJ0c0JTdGFydDsgeiA8IHBhcnRzQkxlbmd0aDsgeisrKSB7XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBwYXJ0QiA9IGJvZHlCLnBhcnRzW3pdLFxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYm91bmRzQiA9IHBhcnRCLmJvdW5kcztcXG5cXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGJvdW5kc0EubWluLnggPiBib3VuZHNCLm1heC54IHx8IGJvdW5kc0EubWF4LnggPCBib3VuZHNCLm1pbi54XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8fCBib3VuZHNBLm1heC55IDwgYm91bmRzQi5taW4ueSB8fCBib3VuZHNBLm1pbi55ID4gYm91bmRzQi5tYXgueSkge1xcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udGludWU7XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGNvbGxpc2lvbiA9IGNvbGxpZGVzKHBhcnRBLCBwYXJ0QiwgcGFpcnMpO1xcblxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoY29sbGlzaW9uKSB7XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xsaXNpb25zLnB1c2goY29sbGlzaW9uKTtcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cXG4gICAgICAgICAgICAgICAgICAgIH1cXG4gICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHJldHVybiBjb2xsaXNpb25zO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmV0dXJucyBgdHJ1ZWAgaWYgYm90aCBzdXBwbGllZCBjb2xsaXNpb24gZmlsdGVycyB3aWxsIGFsbG93IGEgY29sbGlzaW9uIHRvIG9jY3VyLlxcbiAgICAgKiBTZWUgYGJvZHkuY29sbGlzaW9uRmlsdGVyYCBmb3IgbW9yZSBpbmZvcm1hdGlvbi5cXG4gICAgICogQG1ldGhvZCBjYW5Db2xsaWRlXFxuICAgICAqIEBwYXJhbSB7fSBmaWx0ZXJBXFxuICAgICAqIEBwYXJhbSB7fSBmaWx0ZXJCXFxuICAgICAqIEByZXR1cm4ge2Jvb2x9IGB0cnVlYCBpZiBjb2xsaXNpb24gY2FuIG9jY3VyXFxuICAgICAqL1xcbiAgICBEZXRlY3Rvci5jYW5Db2xsaWRlID0gZnVuY3Rpb24oZmlsdGVyQSwgZmlsdGVyQikge1xcbiAgICAgICAgaWYgKGZpbHRlckEuZ3JvdXAgPT09IGZpbHRlckIuZ3JvdXAgJiYgZmlsdGVyQS5ncm91cCAhPT0gMClcXG4gICAgICAgICAgICByZXR1cm4gZmlsdGVyQS5ncm91cCA+IDA7XFxuXFxuICAgICAgICByZXR1cm4gKGZpbHRlckEubWFzayAmIGZpbHRlckIuY2F0ZWdvcnkpICE9PSAwICYmIChmaWx0ZXJCLm1hc2sgJiBmaWx0ZXJBLmNhdGVnb3J5KSAhPT0gMDtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFRoZSBjb21wYXJpc29uIGZ1bmN0aW9uIHVzZWQgaW4gdGhlIGJyb2FkcGhhc2UgYWxnb3JpdGhtLlxcbiAgICAgKiBSZXR1cm5zIHRoZSBzaWduZWQgZGVsdGEgb2YgdGhlIGJvZGllcyBib3VuZHMgb24gdGhlIHgtYXhpcy5cXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQG1ldGhvZCBfc29ydENvbXBhcmVcXG4gICAgICogQHBhcmFtIHtib2R5fSBib2R5QVxcbiAgICAgKiBAcGFyYW0ge2JvZHl9IGJvZHlCXFxuICAgICAqIEByZXR1cm4ge251bWJlcn0gVGhlIHNpZ25lZCBkZWx0YSB1c2VkIGZvciBzb3J0aW5nXFxuICAgICAqL1xcbiAgICBEZXRlY3Rvci5fY29tcGFyZUJvdW5kc1ggPSBmdW5jdGlvbihib2R5QSwgYm9keUIpIHtcXG4gICAgICAgIHJldHVybiBib2R5QS5ib3VuZHMubWluLnggLSBib2R5Qi5ib3VuZHMubWluLng7XFxuICAgIH07XFxuXFxuICAgIC8qXFxuICAgICpcXG4gICAgKiAgUHJvcGVydGllcyBEb2N1bWVudGF0aW9uXFxuICAgICpcXG4gICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIFRoZSBhcnJheSBvZiBgTWF0dGVyLkJvZHlgIGJldHdlZW4gd2hpY2ggdGhlIGRldGVjdG9yIGZpbmRzIGNvbGxpc2lvbnMuXFxuICAgICAqIFxcbiAgICAgKiBfTm90ZTpfIFRoZSBvcmRlciBvZiBib2RpZXMgaW4gdGhpcyBhcnJheSBfaXMgbm90IGZpeGVkXyBhbmQgd2lsbCBiZSBjb250aW51YWxseSBtYW5hZ2VkIGJ5IHRoZSBkZXRlY3Rvci5cXG4gICAgICogQHByb3BlcnR5IGJvZGllc1xcbiAgICAgKiBAdHlwZSBib2R5W11cXG4gICAgICogQGRlZmF1bHQgW11cXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBPcHRpb25hbC4gQSBgTWF0dGVyLlBhaXJzYCBvYmplY3QgZnJvbSB3aGljaCBwcmV2aW91cyBjb2xsaXNpb24gb2JqZWN0cyBtYXkgYmUgcmV1c2VkLiBJbnRlbmRlZCBmb3IgaW50ZXJuYWwgYE1hdHRlci5FbmdpbmVgIHVzYWdlLlxcbiAgICAgKiBAcHJvcGVydHkgcGFpcnNcXG4gICAgICogQHR5cGUge3BhaXJzfG51bGx9XFxuICAgICAqIEBkZWZhdWx0IG51bGxcXG4gICAgICovXFxuXFxufSkoKTtcXG5cXG5cXG4vKioqLyB9KSxcXG4vKiAxNCAqL1xcbi8qKiovIChmdW5jdGlvbihtb2R1bGUsIGV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pIHtcXG5cXG4vKipcXG4qIFRoZSBgTWF0dGVyLk1vdXNlYCBtb2R1bGUgY29udGFpbnMgbWV0aG9kcyBmb3IgY3JlYXRpbmcgYW5kIG1hbmlwdWxhdGluZyBtb3VzZSBpbnB1dHMuXFxuKlxcbiogQGNsYXNzIE1vdXNlXFxuKi9cXG5cXG52YXIgTW91c2UgPSB7fTtcXG5cXG5tb2R1bGUuZXhwb3J0cyA9IE1vdXNlO1xcblxcbnZhciBDb21tb24gPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDApO1xcblxcbihmdW5jdGlvbigpIHtcXG5cXG4gICAgLyoqXFxuICAgICAqIENyZWF0ZXMgYSBtb3VzZSBpbnB1dC5cXG4gICAgICogQG1ldGhvZCBjcmVhdGVcXG4gICAgICogQHBhcmFtIHtIVE1MRWxlbWVudH0gZWxlbWVudFxcbiAgICAgKiBAcmV0dXJuIHttb3VzZX0gQSBuZXcgbW91c2VcXG4gICAgICovXFxuICAgIE1vdXNlLmNyZWF0ZSA9IGZ1bmN0aW9uKGVsZW1lbnQpIHtcXG4gICAgICAgI
2HZhciBtb3VzZSA9IHt9O1xcblxcbiAgICAgICAgaWYgKCFlbGVtZW50KSB7XFxuICAgICAgICAgICAgQ29tbW9uLmxvZygnTW91c2UuY3JlYXRlOiBlbGVtZW50IHdhcyB1bmRlZmluZWQsIGRlZmF1bHRpbmcgdG8gZG9jdW1lbnQuYm9keScsICd3YXJuJyk7XFxuICAgICAgICB9XFxuICAgICAgICBcXG4gICAgICAgIG1vdXNlLmVsZW1lbnQgPSBlbGVtZW50IHx8IGRvY3VtZW50LmJvZHk7XFxuICAgICAgICBtb3VzZS5hYnNvbHV0ZSA9IHsgeDogMCwgeTogMCB9O1xcbiAgICAgICAgbW91c2UucG9zaXRpb24gPSB7IHg6IDAsIHk6IDAgfTtcXG4gICAgICAgIG1vdXNlLm1vdXNlZG93blBvc2l0aW9uID0geyB4OiAwLCB5OiAwIH07XFxuICAgICAgICBtb3VzZS5tb3VzZXVwUG9zaXRpb24gPSB7IHg6IDAsIHk6IDAgfTtcXG4gICAgICAgIG1vdXNlLm9mZnNldCA9IHsgeDogMCwgeTogMCB9O1xcbiAgICAgICAgbW91c2Uuc2NhbGUgPSB7IHg6IDEsIHk6IDEgfTtcXG4gICAgICAgIG1vdXNlLndoZWVsRGVsdGEgPSAwO1xcbiAgICAgICAgbW91c2UuYnV0dG9uID0gLTE7XFxuICAgICAgICBtb3VzZS5waXhlbFJhdGlvID0gcGFyc2VJbnQobW91c2UuZWxlbWVudC5nZXRBdHRyaWJ1dGUoJ2RhdGEtcGl4ZWwtcmF0aW8nKSwgMTApIHx8IDE7XFxuXFxuICAgICAgICBtb3VzZS5zb3VyY2VFdmVudHMgPSB7XFxuICAgICAgICAgICAgbW91c2Vtb3ZlOiBudWxsLFxcbiAgICAgICAgICAgIG1vdXNlZG93bjogbnVsbCxcXG4gICAgICAgICAgICBtb3VzZXVwOiBudWxsLFxcbiAgICAgICAgICAgIG1vdXNld2hlZWw6IG51bGxcXG4gICAgICAgIH07XFxuICAgICAgICBcXG4gICAgICAgIG1vdXNlLm1vdXNlbW92ZSA9IGZ1bmN0aW9uKGV2ZW50KSB7IFxcbiAgICAgICAgICAgIHZhciBwb3NpdGlvbiA9IE1vdXNlLl9nZXRSZWxhdGl2ZU1vdXNlUG9zaXRpb24oZXZlbnQsIG1vdXNlLmVsZW1lbnQsIG1vdXNlLnBpeGVsUmF0aW8pLFxcbiAgICAgICAgICAgICAgICB0b3VjaGVzID0gZXZlbnQuY2hhbmdlZFRvdWNoZXM7XFxuXFxuICAgICAgICAgICAgaWYgKHRvdWNoZXMpIHtcXG4gICAgICAgICAgICAgICAgbW91c2UuYnV0dG9uID0gMDtcXG4gICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcXG4gICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgbW91c2UuYWJzb2x1dGUueCA9IHBvc2l0aW9uLng7XFxuICAgICAgICAgICAgbW91c2UuYWJzb2x1dGUueSA9IHBvc2l0aW9uLnk7XFxuICAgICAgICAgICAgbW91c2UucG9zaXRpb24ueCA9IG1vdXNlLmFic29sdXRlLnggKiBtb3VzZS5zY2FsZS54ICsgbW91c2Uub2Zmc2V0Lng7XFxuICAgICAgICAgICAgbW91c2UucG9zaXRpb24ueSA9IG1vdXNlLmFic29sdXRlLnkgKiBtb3VzZS5zY2FsZS55ICsgbW91c2Uub2Zmc2V0Lnk7XFxuICAgICAgICAgICAgbW91c2Uuc291cmNlRXZlbnRzLm1vdXNlbW92ZSA9IGV2ZW50O1xcbiAgICAgICAgfTtcXG4gICAgICAgIFxcbiAgICAgICAgbW91c2UubW91c2Vkb3duID0gZnVuY3Rpb24oZXZlbnQpIHtcXG4gICAgICAgICAgICB2Y
2XIgcG9zaXRpb24gPSBNb3VzZS5fZ2V0UmVsYXRpdmVNb3VzZVBvc2l0aW9uKGV2ZW50LCBtb3VzZS5lbGVtZW50LCBtb3VzZS5waXhlbFJhdGlvKSxcXG4gICAgICAgICAgICAgICAgdG91Y2hlcyA9IGV2ZW50LmNoYW5nZWRUb3VjaGVzO1xcblxcbiAgICAgICAgICAgIGlmICh0b3VjaGVzKSB7XFxuICAgICAgICAgICAgICAgIG1vdXNlLmJ1dHRvbiA9IDA7XFxuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XFxuICAgICAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICAgICAgbW91c2UuYnV0dG9uID0gZXZlbnQuYnV0dG9uO1xcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICBtb3VzZS5hYnNvbHV0ZS54ID0gcG9zaXRpb24ueDtcXG4gICAgICAgICAgICBtb3VzZS5hYnNvbHV0ZS55ID0gcG9zaXRpb24ueTtcXG4gICAgICAgICAgICBtb3VzZS5wb3NpdGlvbi54ID0gbW91c2UuYWJzb2x1dGUueCAqIG1vdXNlLnNjYWxlLnggKyBtb3VzZS5vZmZzZXQueDtcXG4gICAgICAgICAgICBtb3VzZS5wb3NpdGlvbi55ID0gbW91c2UuYWJzb2x1dGUueSAqIG1vdXNlLnNjYWxlLnkgKyBtb3VzZS5vZmZzZXQueTtcXG4gICAgICAgICAgICBtb3VzZS5tb3VzZWRvd25Qb3NpdGlvbi54ID0gbW91c2UucG9zaXRpb24ueDtcXG4gICAgICAgICAgICBtb3VzZS5tb3VzZWRvd25Qb3NpdGlvbi55ID0gbW91c2UucG9zaXRpb24ueTtcXG4gICAgICAgICAgICBtb3VzZS5zb3VyY2VFdmVudHMubW91c2Vkb3duID0gZXZlbnQ7XFxuICAgICAgICB9O1xcbiAgICAgICAgXFxuICAgICAgICBtb3VzZS5tb3VzZXVwID0gZnVuY3Rpb24oZXZlbnQpIHtcXG4gICAgICAgICAgICB2Y
2XIgcG9zaXRpb24gPSBNb3VzZS5fZ2V0UmVsYXRpdmVNb3VzZVBvc2l0aW9uKGV2ZW50LCBtb3VzZS5lbGVtZW50LCBtb3VzZS5waXhlbFJhdGlvKSxcXG4gICAgICAgICAgICAgICAgdG91Y2hlcyA9IGV2ZW50LmNoYW5nZWRUb3VjaGVzO1xcblxcbiAgICAgICAgICAgIGlmICh0b3VjaGVzKSB7XFxuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgICAgIFxcbiAgICAgICAgICAgIG1vdXNlLmJ1dHRvbiA9IC0xO1xcbiAgICAgICAgICAgIG1vdXNlLmFic29sdXRlLnggPSBwb3NpdGlvbi54O1xcbiAgICAgICAgICAgIG1vdXNlLmFic29sdXRlLnkgPSBwb3NpdGlvbi55O1xcbiAgICAgICAgICAgIG1vdXNlLnBvc2l0aW9uLnggPSBtb3VzZS5hYnNvbHV0ZS54ICogbW91c2Uuc2NhbGUueCArIG1vdXNlLm9mZnNldC54O1xcbiAgICAgICAgICAgIG1vdXNlLnBvc2l0aW9uLnkgPSBtb3VzZS5hYnNvbHV0ZS55ICogbW91c2Uuc2NhbGUueSArIG1vdXNlLm9mZnNldC55O1xcbiAgICAgICAgICAgIG1vdXNlLm1vdXNldXBQb3NpdGlvbi54ID0gbW91c2UucG9zaXRpb24ueDtcXG4gICAgICAgICAgICBtb3VzZS5tb3VzZXVwUG9zaXRpb24ueSA9IG1vdXNlLnBvc2l0aW9uLnk7XFxuICAgICAgICAgICAgbW91c2Uuc291cmNlRXZlbnRzLm1vdXNldXAgPSBldmVudDtcXG4gICAgICAgIH07XFxuXFxuICAgICAgICBtb3VzZS5tb3VzZXdoZWVsID0gZnVuY3Rpb24oZXZlbnQpIHtcXG4gICAgICAgICAgICBtb3VzZS53aGVlbERlbHRhID0gTWF0aC5tYXgoLTEsIE1hdGgubWluKDEsIGV2ZW50LndoZWVsRGVsdGEgfHwgLWV2ZW50LmRldGFpbCkpO1xcbiAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XFxuICAgICAgICB9O1xcblxcbiAgICAgICAgTW91c2Uuc2V0RWxlbWVudChtb3VzZSwgbW91c2UuZWxlbWVudCk7XFxuXFxuICAgICAgICByZXR1cm4gbW91c2U7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBTZXRzIHRoZSBlbGVtZW50IHRoZSBtb3VzZSBpcyBib3VuZCB0byAoYW5kIHJlbGF0aXZlIHRvKS5cXG4gICAgICogQG1ldGhvZCBzZXRFbGVtZW50XFxuICAgICAqIEBwYXJhbSB7bW91c2V9IG1vdXNlXFxuICAgICAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IGVsZW1lbnRcXG4gICAgICovXFxuICAgIE1vdXNlLnNldEVsZW1lbnQgPSBmdW5jdGlvbihtb3VzZSwgZWxlbWVudCkge1xcbiAgICAgICAgbW91c2UuZWxlbWVudCA9IGVsZW1lbnQ7XFxuXFxuICAgICAgICBlbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlbW92ZScsIG1vdXNlLm1vdXNlbW92ZSk7XFxuICAgICAgICBlbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlZG93bicsIG1vdXNlLm1vdXNlZG93bik7XFxuICAgICAgICBlbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNldXAnLCBtb3VzZS5tb3VzZXVwKTtcXG4gICAgICAgIFxcbiAgICAgICAgZWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZXdoZWVsJywgbW91c2UubW91c2V3aGVlbCk7XFxuICAgICAgICBlbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ0RPTU1vdXNlU2Nyb2xsJywgbW91c2UubW91c2V3aGVlbCk7XFxuXFxuICAgICAgICBlbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3RvdWNobW92ZScsIG1vdXNlLm1vdXNlbW92ZSk7XFxuICAgICAgICBlbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3RvdWNoc3RhcnQnLCBtb3VzZS5tb3VzZWRvd24pO1xcbiAgICAgICAgZWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCd0b3VjaGVuZCcsIG1vdXNlLm1vdXNldXApO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogQ2xlYXJzIGFsbCBjYXB0dXJlZCBzb3VyY2UgZXZlbnRzLlxcbiAgICAgKiBAbWV0aG9kIGNsZWFyU291cmNlRXZlbnRzXFxuICAgICAqIEBwYXJhbSB7bW91c2V9IG1vdXNlXFxuICAgICAqL1xcbiAgICBNb3VzZS5jbGVhclNvdXJjZUV2ZW50cyA9IGZ1bmN0aW9uKG1vdXNlKSB7XFxuICAgICAgICBtb3VzZS5zb3VyY2VFdmVudHMubW91c2Vtb3ZlID0gbnVsbDtcXG4gICAgICAgIG1vdXNlLnNvdXJjZUV2ZW50cy5tb3VzZWRvd24gPSBudWxsO1xcbiAgICAgICAgbW91c2Uuc291cmNlRXZlbnRzLm1vdXNldXAgPSBudWxsO1xcbiAgICAgICAgbW91c2Uuc291cmNlRXZlbnRzLm1vdXNld2hlZWwgPSBudWxsO1xcbiAgICAgICAgbW91c2Uud2hlZWxEZWx0YSA9IDA7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBTZXRzIHRoZSBtb3VzZSBwb3NpdGlvbiBvZmZzZXQuXFxuICAgICAqIEBtZXRob2Qgc2V0T2Zmc2V0XFxuICAgICAqIEBwYXJhbSB7bW91c2V9IG1vdXNlXFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSBvZmZzZXRcXG4gICAgICovXFxuICAgIE1vdXNlLnNldE9mZnNldCA9IGZ1bmN0aW9uKG1vdXNlLCBvZmZzZXQpIHtcXG4gICAgICAgIG1vdXNlLm9mZnNldC54ID0gb2Zmc2V0Lng7XFxuICAgICAgICBtb3VzZS5vZmZzZXQueSA9IG9mZnNldC55O1xcbiAgICAgICAgbW91c2UucG9zaXRpb24ueCA9IG1vdXNlLmFic29sdXRlLnggKiBtb3VzZS5zY2FsZS54ICsgbW91c2Uub2Zmc2V0Lng7XFxuICAgICAgICBtb3VzZS5wb3NpdGlvbi55ID0gbW91c2UuYWJzb2x1dGUueSAqIG1vdXNlLnNjYWxlLnkgKyBtb3VzZS5vZmZzZXQueTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFNldHMgdGhlIG1vdXNlIHBvc2l0aW9uIHNjYWxlLlxcbiAgICAgKiBAbWV0aG9kIHNldFNjYWxlXFxuICAgICAqIEBwYXJhbSB7bW91c2V9IG1vdXNlXFxuICAgICAqIEBwYXJhbSB7dmVjdG9yfSBzY2FsZVxcbiAgICAgKi9cXG4gICAgTW91c2Uuc2V0U2NhbGUgPSBmdW5jdGlvbihtb3VzZSwgc2NhbGUpIHtcXG4gICAgICAgIG1vdXNlLnNjYWxlLnggPSBzY2FsZS54O1xcbiAgICAgICAgbW91c2Uuc2NhbGUueSA9IHNjYWxlLnk7XFxuICAgICAgICBtb3VzZS5wb3NpdGlvbi54ID0gbW91c2UuYWJzb2x1dGUueCAqIG1vdXNlLnNjYWxlLnggKyBtb3VzZS5vZmZzZXQueDtcXG4gICAgICAgIG1vdXNlLnBvc2l0aW9uLnkgPSBtb3VzZS5hYnNvbHV0ZS55ICogbW91c2Uuc2NhbGUueSArIG1vdXNlLm9mZnNldC55O1xcbiAgICB9O1xcbiAgICBcXG4gICAgLyoqXFxuICAgICAqIEdldHMgdGhlIG1vdXNlIHBvc2l0aW9uIHJlbGF0aXZlIHRvIGFuIGVsZW1lbnQgZ2l2ZW4gYSBzY3JlZW4gcGl4ZWwgcmF0aW8uXFxuICAgICAqIEBtZXRob2QgX2dldFJlbGF0aXZlTW91c2VQb3NpdGlvblxcbiAgICAgKiBAcHJpdmF0ZVxcbiAgICAgKiBAcGFyYW0ge30gZXZlbnRcXG4gICAgICogQHBhcmFtIHt9IGVsZW1lbnRcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHBpeGVsUmF0aW9cXG4gICAgICogQHJldHVybi
2B7fVxcbiAgICAgKi9cXG4gICAgTW91c2UuX2dldFJlbGF0aXZlTW91c2VQb3NpdGlvbiA9IGZ1bmN0aW9uKGV2ZW50LCBlbGVtZW50LCBwaXhlbFJhdGlvKSB7XFxuICAgICAgICB2YXIgZWxlbWVudEJvdW5kcyA9IGVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCksXFxuICAgICAgICAgICAgcm9vdE5vZGUgPSAoZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50IHx8IGRvY3VtZW50LmJvZHkucGFyZW50Tm9kZSB8fCBkb2N1bWVudC5ib2R5KSxcXG4gICAgICAgICAgICBzY3JvbGxYID0gKHdpbmRvdy5wYWdlWE9mZnNldCAhPT0gdW5kZWZpbmVkKSA/IHdpbmRvdy5wYWdlWE9mZnNldCA6IHJvb3ROb2RlLnNjcm9sbExlZnQsXFxuICAgICAgICAgICAgc2Nyb2xsWSA9ICh3aW5kb3cucGFnZVlPZmZzZXQgIT09IHVuZGVmaW5lZCkgPyB3aW5kb3cucGFnZVlPZmZzZXQgOiByb290Tm9kZS5zY3JvbGxUb3AsXFxuICAgICAgICAgICAgdG91Y2hlcyA9IGV2ZW50LmNoYW5nZWRUb3VjaGVzLFxcbiAgICAgICAgICAgIHgsIHk7XFxuICAgICAgICBcXG4gICAgICAgIGlmICh0b3VjaGVzKSB7XFxuICAgICAgICAgICAgeCA9IHRvdWNoZXNbMF0ucGFnZVggLSBlbGVtZW50Qm91bmRzLmxlZnQgLSBzY3JvbGxYO1xcbiAgICAgICAgICAgIHkgPSB0b3VjaGVzWzBdLnBhZ2VZIC0gZWxlbWVudEJvdW5kcy50b3AgLSBzY3JvbGxZO1xcbiAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICB4ID0gZXZlbnQucGFnZVggLSBlbGVtZW50Qm91bmRzLmxlZnQgLSBzY3JvbGxYO1xcbiAgICAgICAgICAgIHkgPSBldmVudC5wYWdlWSAtIGVsZW1lbnRCb3VuZHMudG9wIC0gc2Nyb2xsWTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHJldHVybiB7IFxcbiAgICAgICAgICAgIHg6IHggLyAoZWxlbWVudC5jbGllbnRXaWR0aCAvIChlbGVtZW50LndpZHRoIHx8IGVsZW1lbnQuY2xpZW50V2lkdGgpICogcGl4ZWxSYXRpbyksXFxuICAgICAgICAgICAgeTogeSAvIChlbGVtZW50LmNsaWVudEhlaWdodCAvIChlbGVtZW50LmhlaWdodCB8fCBlbGVtZW50LmNsaWVudEhlaWdodCkgKiBwaXhlbFJhdGlvKVxcbiAgICAgICAgfTtcXG4gICAgfTtcXG5cXG59KSgpO1xcblxcblxcbi8qKiovIH0pLFxcbi8qIDE1ICovXFxuLyoqKi8gKGZ1bmN0aW9uKG1vZHVsZSwgZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xcblxcbi8qKlxcbiogVGhlIGBNYXR0ZXIuUGx1Z2luYCBtb2R1bGUgY29udGFpbnMgZnVuY3Rpb25zIGZvciByZWdpc3RlcmluZyBhbmQgaW5zdGFsbGluZyBwbHVnaW5zIG9uIG1vZHVsZXMuXFxuKlxcbiogQGNsYXNzIFBsdWdpblxcbiovXFxuXFxudmFyIFBsdWdpbiA9IHt9O1xcblxcbm1vZHVsZS5leHBvcnRzID0gUGx1Z2luO1xcblxcbnZhciBDb21tb24gPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDApO1xcblxcbihmdW5jdGlvbigpIHtcXG5cXG4gICAgUGx1Z2luLl9yZWdpc3RyeSA9IHt9O1xcblxcbiAgICAvKipcXG4gICAgICogUmVnaXN0ZXJzIGEgcGx1Z2luIG9iamVjdCBzbyBpdCBjYW4gYmUgcmVzb2x2ZWQgbGF0ZXIgYnkgbmFtZS5cXG4gICAgICogQG1ldGhvZCByZWdpc3RlclxcbiAgICAgKiBAcGFyYW0gcGx1Z2luIHt9IFRoZSBwbHVnaW4gdG8gcmVnaXN0ZXIuXFxuICAgICAqIEByZXR1cm4ge29iamVjdH0gVGhlIHBsdWdpbi5cXG4gICAgICovXFxuICAgIFBsdWdpbi5yZWdpc3RlciA9IGZ1bmN0aW9uKHBsdWdpbikge1xcbiAgICAgICAgaWYgKCFQbHVnaW4uaXNQbHVnaW4ocGx1Z2luKSkge1xcbiAgICAgICAgICAgIENvbW1vbi53YXJuKCdQbHVnaW4ucmVnaXN0ZXI6JywgUGx1Z2luLnRvU3RyaW5nKHBsdWdpbiksICdkb2VzIG5vdCBpbXBsZW1lbnQgYWxsIHJlcXVpcmVkIGZpZWxkcy4nKTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIGlmIChwbHVnaW4ubmFtZSBpbiBQbHVnaW4uX3JlZ2lzdHJ5KSB7XFxuICAgICAgICAgICAgdmFyIHJlZ2lzdGVyZWQgPSBQbHVnaW4uX3JlZ2lzdHJ5W3BsdWdpbi5uYW1lXSxcXG4gICAgICAgICAgICAgICAgcGx1Z2luVmVyc2lvbiA9I
2FBsdWdpbi52ZXJzaW9uUGFyc2UocGx1Z2luLnZlcnNpb24pLm51bWJlcixcXG4gICAgICAgICAgICAgICAgcmVnaXN0ZXJlZFZlcnNpb24gPSBQbHVnaW4udmVyc2lvblBhcnNlKHJlZ2lzdGVyZWQudmVyc2lvbikubnVtYmVyO1xcblxcbiAgICAgICAgICAgIGlmIChwbHVnaW5WZXJzaW9uID4gcmVnaXN0ZXJlZFZlcnNpb24pIHtcXG4gICAgICAgICAgICAgICAgQ29tbW9uLndhcm4oJ1BsdWdpbi5yZWdpc3RlcjonLCBQbHVnaW4udG9TdHJpbmcocmVnaXN0ZXJlZCksICd3YXMgdXBncmFkZWQgdG8nLCBQbHVnaW4udG9TdHJpbmcocGx1Z2luKSk7XFxuICAgICAgICAgICAgICAgIFBsdWdpbi5fcmVnaXN0cnlbcGx1Z2luLm5hbWVdID0gcGx1Z2luO1xcbiAgICAgICAgICAgIH0gZWxzZSBpZiAocGx1Z2luVmVyc2lvbiA8IHJlZ2lzdGVyZWRWZXJzaW9uKSB7XFxuICAgICAgICAgICAgICAgIENvbW1vbi53YXJuKCdQbHVnaW4ucmVnaXN0ZXI6JywgUGx1Z2luLnRvU3RyaW5nKHJlZ2lzdGVyZWQpLCAnY2FuIG5vdCBiZSBkb3duZ3JhZGVkIHRvJywgUGx1Z2luLnRvU3RyaW5nKHBsdWdpbikpO1xcbiAgICAgICAgICAgIH0gZWxzZSBpZiAocGx1Z2luICE9PSByZWdpc3RlcmVkKSB7XFxuICAgICAgICAgICAgICAgIENvbW1vbi53YXJuKCdQbHVnaW4ucmVnaXN0ZXI6JywgUGx1Z2luLnRvU3RyaW5nKHBsdWdpbiksICdpcyBhbHJlYWR5IHJlZ2lzdGVyZWQgdG8gZGlmZmVyZW50IHBsdWdpbiBvYmplY3QnKTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgIFBsdWdpbi5fcmVnaXN0cnlbcGx1Z2luLm5hbWVdID0gcGx1Z2luO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgcmV0dXJuIHBsdWdpbjtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFJlc29sdmVzIGEgZGVwZW5kZW5jeSB0byBhIHBsdWdpbiBvYmplY3QgZnJvbSB0aGUgcmVnaXN0cnkgaWYgaXQgZXhpc3RzLiBcXG4gICAgICogVGhlIGBkZXBlbmRlbmN5YCBtYXkgY29udGFpbiBhIHZlcnNpb24sIGJ1dCBvbmx5IHRoZSBuYW1lIG1hdHRlcnMgd2hlbiByZXNvbHZpbmcuXFxuICAgICAqIEBtZXRob2QgcmVzb2x2ZVxcbiAgICAgKiBAcGFyYW0gZGVwZW5kZW5jeSB7c3RyaW5nfSBUaGUgZGVwZW5kZW5jeS5cXG4gICAgICogQHJldHVybiB7b2JqZWN0fSBUaGUgcGx1Z2luIGlmIHJlc29sdmVkLCBvdGhlcndpc2UgYHVuZGVmaW5lZGAuXFxuICAgICAqL1xcbiAgICBQbHVnaW4ucmVzb2x2ZSA9IGZ1bmN0aW9uKGRlcGVuZGVuY3kpIHtcXG4gICAgICAgIHJldHVybiBQbHVnaW4uX3JlZ2lzdHJ5W1BsdWdpbi5kZXBlbmRlbmN5UGFyc2UoZGVwZW5kZW5jeSkubmFtZV07XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIGEgcHJldHR5IHByaW50ZWQgcGx1Z2luIG5hbWUgYW5kIHZlcnNpb24uXFxuICAgICAqIEBtZXRob2QgdG9TdHJpbmdcXG4gICAgICogQHBhcmFtIHBsdWdpbiB7fSBUaGUgcGx1Z2luLlxcbiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9IFByZXR0eSBwcmludGVkIHBsdWdpbiBuYW1lIGFuZCB2ZXJzaW9uLlxcbiAgICAgKi9cXG4gICAgUGx1Z2luLnRvU3RyaW5nID0gZnVuY3Rpb24ocGx1Z2luKSB7XFxuICAgICAgICByZXR1cm4gdHlwZW9mIHBsdWdpbiA9PT0gJ3N0cmluZycgPyBwbHVnaW4gOiAocGx1Z2luLm5hbWUgfHwgJ2Fub255bW91cycpICsgJ0AnICsgKHBsdWdpbi52ZXJzaW9uIHx8IHBsdWdpbi5yYW5nZSB8fCAnMC4wLjAnKTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFJldHVybnMgYHRydWVgIGlmIHRoZSBvYmplY3QgbWVldHMgdGhlIG1pbmltdW0gc3RhbmRhcmQgdG8gYmUgY29uc2lkZXJlZCBhIHBsdWdpbi5cXG4gICAgICogVGhpcyBtZWFucyBpdCBtdXN0IGRlZmluZSB0aGUgZm9sbG93aW5nIHByb3BlcnRpZXM6XFxuICAgICAqIC0gYG5hbWVgXFxuICAgICAqIC0gYHZlcnNpb25gXFxuICAgICAqIC0gYGluc3RhbGxgXFxuICAgICAqIEBtZXRob2QgaXNQbHVnaW5cXG4gICAgICogQHBhcmFtIG9iaiB7fSBUaGUgb2JqIHRvIHRlc3QuXFxuICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IGB0cnVlYCBpZiB0aGUgb2JqZWN0IGNhbiBiZSBjb25zaWRlcmVkIGEgcGx1Z2luIG90aGVyd2lzZSBgZmFsc2VgLlxcbiAgICAgKi9cXG4gICAgUGx1Z2luLmlzUGx1Z2luID0gZnVuY3Rpb24ob2JqKSB7XFxuICAgICAgICByZXR1cm4gb2JqICYmIG9iai5uYW1lICYmIG9iai52ZXJzaW9uICYmIG9iai5pbnN0YWxsO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmV0dXJucyBgdHJ1ZWAgaWYgYSBwbHVnaW4gd2l0aCB0aGUgZ2l2ZW4gYG5hbWVgIGJlZW4gaW5zdGFsbGVkIG9uIGBtb2R1bGVgLlxcbiAgICAgKiBAbWV0aG9kIGlzVXNlZFxcbiAgICAgKiBAcGFyYW0gbW9kdWxlIHt9IFRoZSBtb2R1bGUuXFxuICAgICAqIEBwYXJhbSBuYW1lIHtzdHJpbmd9IFRoZSBwbHVnaW4gbmFtZS5cXG4gICAgICogQHJldHVybiB7Ym9vbGVhbn0gYHRydWVgIGlmIGEgcGx1Z2luIHdpdGggdGhlIGdpdmVuIGBuYW1lYCBiZWVuIGluc3RhbGxlZCBvbiBgbW9kdWxlYCwgb3RoZXJ3aXNlIGBmYWxzZWAuXFxuICAgICAqL1xcbiAgICBQbHVnaW4uaXNVc2VkID0gZnVuY3Rpb24obW9kdWxlLCBuYW1lKSB7XFxuICAgICAgICByZXR1cm4gbW9kdWxlLnVzZWQuaW5kZXhPZihuYW1lKSA+IC0xO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmV0dXJucyBgdHJ1ZWAgaWYgYHBsdWdpbi5mb3JgIGlzIGFwcGxpY2FibGUgdG8gYG1vZHVsZWAgYnkgY29tcGFyaW5nIGFnYWluc3QgYG1vZHVsZS5uYW1lYCBhbmQgYG1vZHVsZS52ZXJzaW9uYC5cXG4gICAgICogSWYgYHBsdWdpbi5mb3JgIGlzIG5vdCBzcGVjaWZpZWQgdGhlbiBpdCBpcyBhc3N1bWVkIHRvIGJlIGFwcGxpY2FibGUuXFxuICAgICAqIFRoZSB2YWx1ZSBvZiBgcGx1Z2luLmZvcmAgaXMgYSBzdHJpbmcgb2YgdGhlIGZvcm1hdCBgJ21vZHVsZS1uYW1lJ2Agb3IgYCdtb2R1bGUtbmFtZUB2ZXJzaW9uJ2AuXFxuICAgICAqIEBtZXRob2QgaXNGb3JcXG4gICAgICogQHBhcmFtIHBsdWdpbiB7fSBUaGUgcGx1Z2luLlxcbiAgICAgKiBAcGFyYW0gbW9kdWxlIHt9IFRoZSBtb2R1bGUuXFxuICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IGB0cnVlYCBpZiBgcGx1Z2luLmZvcmAgaXMgYXBwbGljYWJsZSB0byBgbW9kdWxlYCwgb3RoZXJ3aXNlIGBmYWxzZWAuXFxuICAgICAqL1xcbiAgICBQbHVnaW4uaXNGb3IgPSBmdW5jdGlvbihwbHVnaW4sIG1vZHVsZSkge1xcbiAgICAgICAgdmFyIHBhcnNlZCA9IHBsdWdpbi5mb3IgJiYgUGx1Z2luLmRlcG
2VuZGVuY3lQYXJzZShwbHVnaW4uZm9yKTtcXG4gICAgICAgIHJldHVybiAhcGx1Z2luLmZvciB8fCAobW9kdWxlLm5hbWUgPT09IHBhcnNlZC5uYW1lICYmIFBsdWdpbi52ZXJzaW9uU2F0aXNmaWVzKG1vZHVsZS52ZXJzaW9uLCBwYXJzZWQucmFuZ2UpKTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIEluc3RhbGxzIHRoZSBwbHVnaW5zIGJ5IGNhbGxpbmcgYHBsdWdpbi5pbnN0YWxsYCBvbiBlYWNoIHBsdWdpbiBzcGVjaWZpZWQgaW4gYHBsdWdpbnNgIGlmIHBhc3NlZCwgb3RoZXJ3aXNlIGBtb2R1bGUudXNlc2AuXFxuICAgICAqIEZvciBpbnN0YWxsaW5nIHBsdWdpbnMgb24gYE1hdHRlcmAgc2VlIHRoZSBjb252ZW5pZW5jZSBmdW5jdGlvbiBgTWF0dGVyLnVzZWAuXFxuICAgICAqIFBsdWdpbnMgbWF5IGJlIHNwZWNpZmllZCBlaXRoZXIgYnkgdGhlaXIgbmFtZSBvciBhIHJlZmVyZW5jZSB0byB0aGUgcGx1Z2luIG9iamVjdC5cXG4gICAgICogUGx1Z2lucyB0aGVtc2VsdmVzIG1heSBzcGVjaWZ5IGZ1cnRoZXIgZGVwZW5kZW5jaWVzLCBidXQgZWFjaCBwbHVnaW4gaXMgaW5zdGFsbGVkIG9ubHkgb25jZS5cXG4gICAgICogT3JkZXIgaXMgaW1wb3J0YW50LCBhIHRvcG9sb2dpY2FsIHNvcnQgaXMgcGVyZm9ybWVkIHRvIGZpbmQgdGhlIGJlc3QgcmVzdWx0aW5nIG9yZGVyIG9mIGluc3RhbGxhdGlvbi5cXG4gICAgICogVGhpcyBzb3J0aW5nIGF0dGVtcHRzIHRvIHNhdGlzZnkgZXZlcnkgZGVwZW5kZW5jeSdzIHJlcXVlc3RlZCBvcmRlcmluZywgYnV0IG1heSBub3QgYmUgZXhhY3QgaW4gYWxsIGNhc2VzLlxcbiAgICAgKiBUaGlzIGZ1bmN0aW9uIGxvZ3MgdGhlIHJlc3VsdGluZyBzdGF0dXMgb2YgZWFjaCBkZXBlbmRlbmN5IGluIHRoZSBjb25zb2xlLCBhbG9uZyB3aXRoIGFueSB3YXJuaW5ncy5cXG4gICAgICogLSBBIGdyZWVuIHRpY2sg4pyFIGluZGljYXRlcyBhIGRlcGVuZGVuY3kgd2FzIHJlc29sdmVkIGFuZCBpbnN0YWxsZWQuXFxuICAgICAqIC0gQW4gb3JhbmdlIGRpYW1vbmQg8J+UtiBpbmRpY2F0ZXMgYSBkZXBlbmRlbmN5IHdhcyByZXNvbHZlZCBidXQgYSB3YXJuaW5nIHdhcyB0aHJvd24gZm9yIGl0IG9yIG9uZSBpZiBpdHMgZGVwZW5kZW5jaWVzLlxcbiAgICAgKiAtIEEgcmVkIGNyb3NzIOKdjCBpbmRpY2F0ZXMgYSBkZXBlbmRlbmN5IGNvdWxkIG5vdCBiZSByZXNvbHZlZC5cXG4gICAgICogQXZvaWQgY2FsbGluZyB0aGlzIGZ1bmN0aW9uIG11bHRpcGxlIHRpbWVzIG9uIHRoZSBzYW1lIG1vZHVsZSB1bmxlc3MgeW91IGludGVuZCB0byBtYW51YWxseSBjb250cm9sIGluc3RhbGxhdGlvbiBvcmRlci5cXG4gICAgICogQG1ldGhvZCB1c2VcXG4gICAgICogQHBhcmFtIG1vZHVsZSB7fSBUaGUgbW9kdWxlIGluc3RhbGwgcGx1Z2lucyBvbi5cXG4gICAgICogQHBhcmFtIFtwbHVnaW5zPW1vZHVsZS51c2VzXSB7fSBUaGUgcGx1Z2lucyB0byBpbnN0YWxsIG9uIG1vZHVsZSAob3B0aW9uYWwsIGRlZmF1bHRzIHRvIGBtb2R1bGUudXNlc2ApLlxcbiAgICAgKi9cXG4gICAgUGx1Z2luLnVzZSA9IGZ1bmN0aW9uKG1vZHVsZSwgcGx1Z2lucykge1xcbiAgICAgICAgbW9kdWxlLnVzZXMgPSAobW9kdWxlLnVzZXMgfHwgW10pLmNvbmNhdChwbHVnaW5zIHx8IFtdKTtcXG5cXG4gICAgICAgIGlmIChtb2R1bGUudXNlcy5sZW5ndGggPT09IDApIHtcXG4gICAgICAgICAgICBDb21tb24ud2FybignUGx1Z2luLnVzZTonLCBQbHVnaW4udG9TdHJpbmcobW9kdWxlKSwgJ2RvZXMgbm90IHNwZWNpZnkgYW55IGRlcGVuZGVuY2llcyB0byBpbnN0YWxsLicpO1xcbiAgICAgICAgICAgIHJldHVybjtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHZhciBkZXBlbmRlbmNpZXMgPSBQbHVnaW4uZGVwZW5kZW5jaWVzKG1vZHVsZSksXFxuICAgICAgICAgICAgc29ydGVkRGVwZW5kZW5jaWVzID0gQ29tbW9uLnRvcG9sb2dpY2FsU29ydChkZXBlbmRlbmNpZXMpLFxcbiAgICAgICAgICAgIHN0YXR1cyA9IFtdO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzb3J0ZWREZXBlbmRlbmNpZXMubGVuZ3RoOyBpICs9IDEpIHtcXG4gICAgICAgICAgICBpZiAoc29ydGVkRGVwZW5kZW5jaWVzW2ldID09PSBtb2R1bGUubmFtZSkge1xcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcXG4gICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgdmFyIHBsdWdpbiA9IFBsdWdpbi5yZXNvbHZlKHNvcnRlZERlcGVuZGVuY2llc1tpXSk7XFxuXFxuICAgICAgICAgICAgaWYgKCFwbHVnaW4pIHtcXG4gICAgICAgICAgICAgICAgc3RhdHVzLnB1c2goJ+KdjCAnICsgc29ydGVkRGVwZW5kZW5jaWVzW2ldKTtcXG4gICAgICAgICAgICAgICAgY29udGludWU7XFxuICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgIGlmIChQbHVnaW4uaXNVc2VkKG1vZHVsZSwgcGx1Z2luLm5hbWUpKSB7XFxuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICBpZiAoIVBsdWdpbi5pc0ZvcihwbHVnaW4sIG1vZHVsZSkpIHtcXG4gICAgICAgICAgICAgICAgQ29tbW9uLndhcm4oJ1BsdWdpbi51c2U6JywgUGx1Z2luLnRvU3RyaW5nKHBsdWdpbiksICdpcyBmb3InLCBwbHVnaW4uZm9yLCAnYnV0IGluc3RhbGxlZCBvbicsIFBsdWdpbi50b1N0cmluZyhtb2R1bGUpICsgJy4nKTtcXG4gICAgICAgICAgICAgICAgcGx1Z2luLl93YXJuZWQgPSB0cnVlO1xcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICBpZiAocGx1Z2luLmluc3RhbGwpIHtcXG4gICAgICAgICAgICAgICAgcGx1Z2luLmluc3RhbGwobW9kdWxlKTtcXG4gICAgICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgICAgICBDb21tb24ud2FybignUGx1Z2luLnVzZTonLCBQbHVnaW4udG9TdHJpbmcocGx1Z2luKSwgJ2RvZXMgbm90IHNwZWNpZnkgYW4gaW5zdGFsbCBmdW5jdGlvbi4nKTtcXG4gICAgICAgICAgICAgICAgcGx1Z2luLl93YXJuZWQgPSB0cnVlO1xcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICBpZiAocGx1Z2luLl93YXJuZWQpIHtcXG4gICAgICAgICAgICAgICAgc3RhdHVzLnB1c2goJ/CflLYgJyArIFBsdWdpbi50b1N0cmluZyhwbHVnaW4pKTtcXG4gICAgICAgICAgICAgICAgZGVsZXRlIHBsdWdpbi5fd2FybmVkO1xcbiAgICAgICAgICAgI
2H0gZWxzZSB7XFxuICAgICAgICAgICAgICAgIHN0YXR1cy5wdXNoKCfinIUgJyArIFBsdWdpbi50b1N0cmluZyhwbHVnaW4pKTtcXG4gICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgbW9kdWxlLnVzZWQucHVzaChwbHVnaW4ubmFtZSk7XFxuICAgICAgICB9XFxuXFxuICAgICAgICBpZiAoc3RhdHVzLmxlbmd0aCA+IDApIHtcXG4gICAgICAgICAgICBDb21tb24uaW5mbyhzdGF0dXMuam9pbignICAnKSk7XFxuICAgICAgICB9XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZWN1cnNpdmVseSBmaW5kcyBhbGwgb2YgYSBtb2R1bGUncyBkZXBlbmRlbmNpZXMgYW5kIHJldHVybnMgYSBmbGF0IGRlcGVuZGVuY3kgZ3JhcGguXFxuICAgICAqIEBtZXRob2QgZGVwZW5kZW5jaWVzXFxuICAgICAqIEBwYXJhbSBtb2R1bGUge30gVGhlIG1vZHVsZS5cXG4gICAgICogQHJldHVybiB7b2JqZWN0fSBBIGRlcGVuZGVuY3kgZ3JhcGguXFxuICAgICAqL1xcbiAgICBQbHVnaW4uZGVwZW5kZW5jaWVzID0gZnVuY3Rpb24obW9kdWxlLCB0cmFja2VkKSB7XFxuICAgICAgICB2YXIgcGFyc2VkQmFzZSA9IFBsdWdpbi5kZXBlbmRlbmN5UGFyc2UobW9kdWxlKSxcXG4gICAgICAgICAgICBuYW1lID0gcGFyc2VkQmFzZS5uYW1lO1xcblxcbiAgICAgICAgdHJhY2tlZCA9IHRyYWNrZWQgfHwge307XFxuXFxuICAgICAgICBpZiAobmFtZSBpbiB0cmFja2VkKSB7XFxuICAgICAgICAgICAgcmV0dXJuO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgbW9kdWxlID0gUGx1Z2luLnJlc29sdmUobW9kdWxlKSB8fCBtb2R1bGU7XFxuXFxuICAgICAgICB0cmFja2VkW25hbWVdID0gQ29tbW9uLm1hcChtb2R1bGUudXNlcyB8fCBbXSwgZnVuY3Rpb24oZGVwZW5kZW5jeSkge1xcbiAgICAgICAgICAgIGlmIChQbHVnaW4uaXNQbHVnaW4oZGVwZW5kZW5jeSkpIHtcXG4gICAgICAgICAgICAgICAgUGx1Z2luLnJlZ2lzdGVyKGRlcGVuZGVuY3kpO1xcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICB2Y
2XIgcGFyc2VkID0gUGx1Z2luLmRlcGVuZGVuY3lQYXJzZShkZXBlbmRlbmN5KSxcXG4gICAgICAgICAgICAgICAgcmVzb2x2ZWQgPSBQbHVnaW4ucmVzb2x2ZShkZXBlbmRlbmN5KTtcXG5cXG4gICAgICAgICAgICBpZiAocmVzb2x2ZWQgJiYgIVBsdWdpbi52ZXJzaW9uU2F0aXNmaWVzKHJlc29sdmVkLnZlcnNpb24sIHBhcnNlZC5yYW5nZSkpIHtcXG4gICAgICAgICAgICAgICAgQ29tbW9uLndhcm4oXFxuICAgICAgICAgICAgICAgICAgICAnUGx1Z2luLmRlcGVuZGVuY2llczonLCBQbHVnaW4udG9TdHJpbmcocmVzb2x2ZWQpLCAnZG9lcyBub3Qgc2F0aXNmeScsXFxuICAgICAgICAgICAgICAgICAgICBQbHVnaW4udG9TdHJpbmcocGFyc2VkKSwgJ3VzZWQgYnknLCBQbHVnaW4udG9TdHJpbmcocGFyc2VkQmFzZSkgKyAnLidcXG4gICAgICAgICAgICAgICAgKTtcXG5cXG4gICAgICAgICAgICAgICAgcmVzb2x2ZWQuX3dhcm5lZCA9IHRydWU7XFxuICAgICAgICAgICAgICAgIG1vZHVsZS5fd2FybmVkID0gdHJ1ZTtcXG4gICAgICAgICAgICB9IGVsc2UgaWYgKCFyZXNvbHZlZCkge1xcbiAgICAgICAgICAgICAgICBDb21tb24ud2FybihcXG4gICAgICAgICAgICAgICAgICAgICdQbHVnaW4uZGVwZW5kZW5jaWVzOicsIFBsdWdpbi50b1N0cmluZyhkZXBlbmRlbmN5KSwgJ3VzZWQgYnknLFxcbiAgICAgICAgICAgICAgICAgICAgUGx1Z2luLnRvU3RyaW5nKHBhcnNlZEJhc2UpLCAnY291bGQgbm90IGJlIHJlc29sdmVkLidcXG4gICAgICAgICAgICAgICAgKTtcXG5cXG4gICAgICAgICAgICAgICAgbW9kdWxlLl93YXJuZWQgPSB0cnVlO1xcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICByZXR1cm4gcGFyc2VkLm5hbWU7XFxuICAgICAgICB9KTtcXG5cXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdHJhY2tlZFtuYW1lXS5sZW5ndGg7IGkgKz0gMSkge1xcbiAgICAgICAgICAgIFBsdWdpbi5kZXBlbmRlbmNpZXModHJhY2tlZFtuYW1lXVtpXSwgdHJhY2tlZCk7XFxuICAgICAgICB9XFxuXFxuICAgICAgICByZXR1cm4gdHJhY2tlZDtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFBhcnNlcyBhIGRlcGVuZGVuY3kgc3RyaW5nIGludG8gaXRzIGNvbXBvbmVudHMuXFxuICAgICAqIFRoZSBgZGVwZW5kZW5jeWAgaXMgYSBzdHJpbmcgb2YgdGhlIGZvcm1hdCBgJ21vZHVsZS1uYW1lJ2Agb3IgYCdtb2R1bGUtbmFtZUB2ZXJzaW9uJ2AuXFxuICAgICAqIFNlZSBkb2N1bWVudGF0aW9uIGZvciBgUGx1Z2luLnZlcnNpb25QYXJzZWAgZm9yIGEgZGVzY3JpcHRpb24gb2YgdGhlIGZvcm1hdC5cXG4gICAgICogVGhpcyBmdW5jdGlvbiBjYW4gYWxzbyBoYW5kbGUgZGVwZW5kZW5jaWVzIHRoYXQgYXJlIGFscmVhZHkgcmVzb2x2ZWQgKGUuZy4gYSBtb2R1bGUgb2JqZWN0KS5cXG4gICAgICogQG1ldGhvZCBkZXBlbmRlbmN5UGFyc2VcXG4gICAgICogQHBhcmFtIGRlcGVuZGVuY3kge3N0cmluZ30gVGhlIGRlcGVuZGVuY3kgb2YgdGhlIGZvcm1hdCBgJ21vZHVsZS1uYW1lJ2Agb3IgYCdtb2R1bGUtbmFtZUB2ZXJzaW9uJ2AuXFxuICAgICAqIEByZXR1cm4ge29iamVjdH0gVGhlIGRlcGVuZGVuY3kgcGFyc2VkIGludG8gaXRzIGNvbXBvbmVudHMuXFxuICAgICAqL1xcbiAgICBQbHVnaW4uZGVwZW5kZW5jeVBhcnNlID0gZnVuY3Rpb24oZGVwZW5kZW5jeSkge1xcbiAgICAgICAgaWYgKENvbW1vbi5pc1N0cmluZyhkZXBlbmRlbmN5KSkge1xcbiAgICAgICAgICAgIHZhciBwYXR0ZXJuID0gL15bXFxcXHctXSsoQChcXFxcKnxbXFxcXF5+XT9cXFxcZCtcXFxcLlxcXFxkK1xcXFwuXFxcXGQrKC1bMC05QS1aYS16LStdKyk/KSk/JC87XFxuXFxuICAgICAgICAgICAgaWYgKCFwYXR0ZXJuLnRlc3QoZGVwZW5kZW5jeSkpIHtcXG4gICAgICAgICAgICAgICAgQ29tbW9uLndhcm4oJ1BsdWdpbi5kZXBlbmRlbmN5UGFyc2U6JywgZGVwZW5kZW5jeSwgJ2lzIG5vdCBhIHZhbGlkIGRlcGVuZGVuY3kgc3RyaW5nLicpO1xcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICByZXR1cm4ge1xcbiAgICAgICAgICAgICAgICBuYW1lOiBkZXBlbmRlbmN5LnNwbGl0KCdAJylbMF0sXFxuICAgICAgICAgICAgICAgIHJhbmdlOiBkZXBlbmRlbmN5LnNwbGl0KCdAJylbMV0gfHwgJyonXFxuICAgICAgICAgICAgfTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHJldHVybiB7XFxuICAgICAgICAgICAgbmFtZTogZGVwZW5kZW5jeS5uYW1lLFxcbiAgICAgICAgICAgIHJhbmdlOiBkZXBlbmRlbmN5LnJhbmdlIHx8IGRlcGVuZGVuY3kudmVyc2lvblxcbiAgICAgICAgfTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFBhcnNlcyBhIHZlcnNpb24gc3RyaW5nIGludG8gaXRzIGNvbXBvbmVudHMuICBcXG4gICAgICogVmVyc2lvbnMgYXJlIHN0cmljdGx5IG9mIHRoZSBmb3JtYXQgYHgueS56YCAoYXMgaW4gW3NlbXZlcl0oaHR0cDovL3NlbXZlci5vcmcvKSkuXFxuICAgICAqIFZlcnNpb25zIG1heSBvcHRpb25hbGx5IGhhdmUgYSBwcmVyZWxlYXNlIHRhZyBpbiB0aGUgZm9ybWF0IGB4Lnkuei1hbHBoYWAuXFxuICAgICAqIFJhbmdlcyBhcmUgYSBzdHJpY3Qgc3Vic2V0IG9mIFtucG0gcmFuZ2VzXShodHRwczovL2RvY3MubnBtanMuY29tL21pc2Mvc2VtdmVyI2FkdmFuY2VkLXJhbmdlLXN5bnRheCkuXFxuICAgICAqIE9ubHkgdGhlIGZvbGxvd2luZyByYW5nZSB0eXBlcyBhcmUgc3VwcG9ydGVkOlxcbiAgICAgKiAtIFRpbGRlIHJhbmdlcyBlLmcuIGB+MS4yLjNgXFxuICAgICAqIC0gQ2FyZXQgcmFuZ2VzIGUuZy4gYF4xLjIuM2BcXG4gICAgICogLSBHcmVhdGVyIHRoYW4gcmFuZ2VzIGUuZy4gYD4xLjIuM2BcXG4gICAgICogLSBHcmVhdGVyIHRoYW4gb3IgZXF1YWwgcmFuZ2VzIGUuZy4gYD49MS4yLjNgXFxuICAgICAqIC0gRXhhY3QgdmVyc2lvbiBlLmcuIGAxLjIuM2BcXG4gICAgICogLSBBbnkgdmVyc2lvbiBgKmBcXG4gICAgICogQG1ldGhvZCB2ZXJzaW9uUGFyc2VcXG4gICAgICogQHBhcmFtIHJhbmdlIHtzdHJpbmd9IFRoZSB2ZXJzaW9uIHN0cmluZy5cXG4gICAgICogQHJldHVybiB7b2JqZWN0fSBUaGUgdmVyc2lvbiByYW5nZSBwYXJzZWQgaW50byBpdHMgY29tcG9uZW50cy5cXG4gICAgICovXFxuICAgIFBsdWdpbi52ZXJzaW9uUGFyc2UgPSBmdW5jdGlvbihyYW5nZSkge1xcbiAgICAgICAgdmFyIHBhdHRlcm4gPSAvXihcXFxcKil8KFxcXFxefH58Pj18Pik/XFxcXHMqKChcXFxcZCspXFxcXC4oXFxcXGQrKVxcXFwuKFxcXFxkKykpKC1bMC05QS1aYS16LStdKyk/JC87X
2FxuXFxuICAgICAgICBpZiAoIXBhdHRlcm4udGVzdChyYW5nZSkpIHtcXG4gICAgICAgICAgICBDb21tb24ud2FybignUGx1Z2luLnZlcnNpb25QYXJzZTonLCByYW5nZSwgJ2lzIG5vdCBhIHZhbGlkIHZlcnNpb24gb3IgcmFuZ2UuJyk7XFxuICAgICAgICB9XFxuXFxuICAgICAgICB2YXIgcGFydHMgPSBwYXR0ZXJuLmV4ZWMocmFuZ2UpO1xcbiAgICAgICAgdmFyIG1ham9yID0gTnVtYmVyKHBhcnRzWzRdKTtcXG4gICAgICAgIHZhciBtaW5vciA9IE51bWJlcihwYXJ0c1s1XSk7XFxuICAgICAgICB2YXIgcGF0Y2ggPSBOdW1iZXIocGFydHNbNl0pO1xcblxcbiAgICAgICAgcmV0dXJuIHtcXG4gICAgICAgICAgICBpc1JhbmdlOiBCb29sZWFuKHBhcnRzWzFdIHx8IHBhcnRzWzJdKSxcXG4gICAgICAgICAgICB2ZXJzaW9uOiBwYXJ0c1szXSxcXG4gICAgICAgICAgICByYW5nZTogcmFuZ2UsXFxuICAgICAgICAgICAgb3BlcmF0b3I6IHBhcnRzWzFdIHx8IHBhcnRzWzJdIHx8ICcnLFxcbiAgICAgICAgICAgIG1ham9yOiBtYWpvcixcXG4gICAgICAgICAgICBtaW5vcjogbWlub3IsXFxuICAgICAgICAgICAgcGF0Y2g6IHBhdGNoLFxcbiAgICAgICAgICAgIHBhcnRzOiBbbWFqb3IsIG1pbm9yLCBwYXRjaF0sXFxuICAgICAgICAgICAgcHJlcmVsZWFzZTogcGFydHNbN10sXFxuICAgICAgICAgICAgbnVtYmVyOiBtYWpvciAqIDFlOCArIG1pbm9yICogMWU0ICsgcGF0Y2hcXG4gICAgICAgIH07XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIGB0cnVlYCBpZiBgdmVyc2lvbmAgc2F0aXNmaWVzIHRoZSBnaXZlbiBgcmFuZ2VgLlxcbiAgICAgKiBTZWUgZG9jdW1lbnRhdGlvbiBmb3IgYFBsdWdpbi52ZXJzaW9uUGFyc2VgIGZvciBhIGRlc2NyaXB0aW9uIG9mIHRoZSBmb3JtYXQuXFxuICAgICAqIElmIGEgdmVyc2lvbiBvciByYW5nZSBpcyBub3Qgc3BlY2lmaWVkLCB0aGVuIGFueSB2ZXJzaW9uIChgKmApIGlzIGFzc3VtZWQgdG8gc2F0aXNmeS5cXG4gICAgICogQG1ldGhvZCB2ZXJzaW9uU2F0aXNmaWVzXFxuICAgICAqIEBwYXJhbSB2ZXJzaW9uIHtzdHJpbmd9IFRoZSB2ZXJzaW9uIHN0cmluZy5cXG4gICAgICogQHBhcmFtIHJhbmdlIHtzdHJpbmd9IFRoZSByYW5nZSBzdHJpbmcuXFxuICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IGB0cnVlYCBpZiBgdmVyc2lvbmAgc2F0aXNmaWVzIGByYW5nZWAsIG90aGVyd2lzZSBgZmFsc2VgLlxcbiAgICAgKi9cXG4gICAgUGx1Z2luLnZlcnNpb25TYXRpc2ZpZXMgPSBmdW5jdGlvbih2ZXJzaW9uLCByYW5nZSkge1xcbiAgICAgICAgcmFuZ2UgPSByYW5nZSB8fCAnKic7XFxuXFxuICAgICAgICB2Y
2XIgciA9IFBsdWdpbi52ZXJzaW9uUGFyc2UocmFuZ2UpLFxcbiAgICAgICAgICAgIHYgPSBQbHVnaW4udmVyc2lvblBhcnNlKHZlcnNpb24pO1xcblxcbiAgICAgICAgaWYgKHIuaXNSYW5nZSkge1xcbiAgICAgICAgICAgIGlmIChyLm9wZXJhdG9yID09PSAnKicgfHwgdmVyc2lvbiA9PT0gJyonKSB7XFxuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICBpZiAoci5vcGVyYXRvciA9PT0gJz4nKSB7XFxuICAgICAgICAgICAgICAgIHJldHVybiB2Lm51bWJlciA+IHIubnVtYmVyO1xcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICBpZiAoci5vcGVyYXRvciA9PT0gJz49Jykge1xcbiAgICAgICAgICAgICAgICByZXR1cm4gdi5udW1iZXIgPj0gci5udW1iZXI7XFxuICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgIGlmIChyLm9wZXJhdG9yID09PSAnficpIHtcXG4gICAgICAgICAgICAgICAgcmV0dXJuIHYubWFqb3IgPT09IHIubWFqb3IgJiYgdi5taW5vciA9PT0gci5taW5vciAmJiB2LnBhdGNoID49IHIucGF0Y2g7XFxuICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgIGlmIChyLm9wZXJhdG9yID09PSAnXicpIHtcXG4gICAgICAgICAgICAgICAgaWYgKHIubWFqb3IgPiAwKSB7XFxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdi5tYWpvciA9PT0gci5tYWpvciAmJiB2Lm51bWJlciA+PSByLm51bWJlcjtcXG4gICAgICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgICAgICBpZiAoci5taW5vciA+IDApIHtcXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB2Lm1pbm9yID09PSByLm1pbm9yICYmIHYucGF0Y2ggPj0gci5wYXRjaDtcXG4gICAgICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgICAgICByZXR1cm4gdi5wYXRjaCA9PT0gci5wYXRjaDtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuXFxuICAgICAgICByZXR1cm4gdmVyc2lvbiA9PT0gcmFuZ2UgfHwgdmVyc2lvbiA9PT0gJyonO1xcbiAgICB9O1xcblxcbn0pKCk7XFxuXFxuXFxuLyoqKi8gfSksXFxuLyogMTYgKi9cXG4vKioqLyAoZnVuY3Rpb24obW9kdWxlLCBleHBvcnRzKSB7XFxuXFxuLyoqXFxuKiBUaGUgYE1hdHRlci5Db250YWN0YCBtb2R1bGUgY29udGFpbnMgbWV0aG9kcyBmb3IgY3JlYXRpbmcgYW5kIG1hbmlwdWxhdGluZyBjb2xsaXNpb24gY29udGFjdHMuXFxuKlxcbiogQGNsYXNzIENvbnRhY3RcXG4qL1xcblxcbnZhciBDb250YWN0ID0ge307XFxuXFxubW9kdWxlLmV4cG9ydHMgPSBDb250YWN0O1xcblxcbihmdW5jdGlvbigpIHtcXG5cXG4gICAgLyoqXFxuICAgICAqIENyZWF0ZXMgYSBuZXcgY29udGFjdC5cXG4gICAgICogQG1ldGhvZCBjcmVhdGVcXG4gICAgICogQHBhcmFtIHt2ZXJ0ZXh9IHZlcnRleFxcbiAgICAgKiBAcmV0dXJuIHtjb250YWN0fSBBIG5ldyBjb250YWN0XFxuICAgICAqL1xcbiAgICBDb250YWN0LmNyZWF0ZSA9IGZ1bmN0aW9uKHZlcnRleCkge1xcbiAgICAgICAgcmV0dXJuIHtcXG4gICAgICAgICAgICB2ZXJ0ZXg6IHZlcnRleCxcXG4gICAgICAgICAgICBub3JtYWxJbXB1bHNlOiAwLFxcbiAgICAgICAgICAgIHRhbmdlbnRJbXB1bHNlOiAwXFxuICAgICAgICB9O1xcbiAgICB9O1xcblxcbn0pKCk7XFxuXFxuXFxuLyoqKi8gfSksXFxuLyogMTcgKi9cXG4vKioqLyAoZnVuY3Rpb24obW9kdWxlLCBleHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XFxuXFxuLyoqXFxuKiBUaGUgYE1hdHRlci5FbmdpbmVgIG1vZHVsZSBjb250YWlucyBtZXRob2RzIGZvciBjcmVhdGluZyBhbmQgbWFuaXB1bGF0aW5nIGVuZ2luZXMuXFxuKiBBbiBlbmdpbmUgaXMgYSBjb250cm9sbGVyIHRoYXQgbWFuYWdlcyB1cGRhdGluZyB0aGUgc2ltdWxhdGlvbiBvZiB0aGUgd29ybGQuXFxuKiBTZWUgYE1hdHRlci5SdW5uZXJgIGZvciBhbiBvcHRpb25hbCBnYW1lIGxvb3AgdXRpbGl0eS5cXG4qXFxuKiBTZWUgdGhlIGluY2x1ZGVkIHVzYWdlIFtleGFtcGxlc10oaHR0cHM6Ly9naXRodWIuY29tL2xpYWJydS9tYXR0ZXItanMvdHJlZS9tYXN0ZXIvZXhhbXBsZXMpLlxcbipcXG4qIEBjbGFzcyBFbmdpbmVcXG4qL1xcblxcbnZhciBFbmdpbmUgPSB7fTtcXG5cXG5tb2R1bGUuZXhwb3J0cyA9IEVuZ2luZTtcXG5cXG52YXIgU2xlZXBpbmcgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDcpO1xcbnZhciBSZXNvbHZlciA9IF9fd2VicGFja19yZXF1aXJlX18oMTgpO1xcbnZhciBEZXRlY3RvciA9IF9fd2VicGFja19yZXF1aXJlX18oMTMpO1xcbnZhciBQYWlycyA9IF9fd2VicGFja19yZXF1aXJlX18oMTkpO1xcbnZhciBFdmVudHMgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDUpO1xcbnZhciBDb21wb3NpdGUgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDYpO1xcbnZhciBDb25zdHJhaW50ID0gX193ZWJwYWNrX3JlcXVpcmVfXygxMCk7XFxudmFyIENvbW1vbiA9IF9fd2VicGFja19yZXF1aXJlX18oMCk7XFxudmFyIEJvZHkgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDQpO1xcblxcbihmdW5jdGlvbigpIHtcXG5cXG4gICAgLyoqXFxuICAgICAqIENyZWF0ZXMgYSBuZXcgZW5naW5lLiBUaGUgb3B0aW9ucyBwYXJhbWV0ZXIgaXMgYW4gb2JqZWN0IHRoYXQgc3BlY2lmaWVzIGFueSBwcm9wZXJ0aWVzIHlvdSB3aXNoIHRvIG92ZXJyaWRlIHRoZSBkZWZhdWx0cy5cXG4gICAgICogQWxsIHByb3BlcnRpZXMgaGF2ZSBkZWZhdWx0IHZhbHVlcywgYW5kIG1hbnkgYXJlIHByZS1jYWxjdWxhdGVkIGF1dG9tYXRpY2FsbHkgYmFzZWQgb24gb3RoZXIgcHJvcGVydGllcy5cXG4gICAgICogU2VlIHRoZSBwcm9wZXJ0aWVzIHNlY3Rpb24gYmVsb3cgZm9yIGRldGFpbGVkIGluZm9ybWF0aW9uIG9uIHdoYXQgeW91IGNhbiBwYXNzIHZpYSB0aGUgYG9wdGlvbnNgIG9iamVjdC5cXG4gICAgICogQG1ldGhvZCBjcmVhdGVcXG4gICAgICogQHBhcmFtIHtvYmplY3R9IFtvcHRpb25zXVxcbiAgICAgKiBAcmV0dXJuIHtlbmdpbmV9IGVuZ2luZVxcbiAgICAgKi9cXG4gICAgRW5naW5lLmNyZWF0ZSA9IGZ1bmN0aW9uKG9wdGlvbnMpIHtcXG4gICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xcblxcbiAgICAgICAgdmFyIGRlZmF1bHRzID0ge1xcbiAgICAgICAgICAgI
2HBvc2l0aW9uSXRlcmF0aW9uczogNixcXG4gICAgICAgICAgICB2ZWxvY2l0eUl0ZXJhdGlvbnM6IDQsXFxuICAgICAgICAgICAgY29uc3RyYWludEl0ZXJhdGlvbnM6IDIsXFxuICAgICAgICAgICAgZW5hYmxlU2xlZXBpbmc6IGZhbHNlLFxcbiAgICAgICAgICAgIGV2ZW50czogW10sXFxuICAgICAgICAgICAgcGx1Z2luOiB7fSxcXG4gICAgICAgICAgICBncmF2aXR5OiB7XFxuICAgICAgICAgICAgICAgIHg6IDAsXFxuICAgICAgICAgICAgICAgIHk6IDEsXFxuICAgICAgICAgICAgICAgIHNjYWxlOiAwLjAwMVxcbiAgICAgICAgICAgIH0sXFxuICAgICAgICAgICAgdGltaW5nOiB7XFxuICAgICAgICAgICAgICAgIHRpbWVzdGFtcDogMCxcXG4gICAgICAgICAgICAgICAgdGltZVNjYWxlOiAxLFxcbiAgICAgICAgICAgICAgICBsYXN0RGVsdGE6IDAsXFxuICAgICAgICAgICAgICAgIGxhc3RFbGFwc2VkOiAwXFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfTtcXG5cXG4gICAgICAgIHZhciBlbmdpbmUgPSBDb21tb24uZXh0ZW5kKGRlZmF1bHRzLCBvcHRpb25zKTtcXG5cXG4gICAgICAgIGVuZ2luZS53b3JsZCA9IG9wdGlvbnMud29ybGQgfHwgQ29tcG9zaXRlLmNyZWF0ZSh7IGxhYmVsOiAnV29ybGQnIH0pO1xcbiAgICAgICAgZW5naW5lLnBhaXJzID0gb3B0aW9ucy5wYWlycyB8fCBQYWlycy5jcmVhdGUoKTtcXG4gICAgICAgIGVuZ2luZS5kZXRlY3RvciA9IG9wdGlvbnMuZGV0ZWN0b3IgfHwgRGV0ZWN0b3IuY3JlYXRlKCk7XFxuXFxuICAgICAgICAvLyBmb3IgdGVtcG9yYXJ5IGJhY2sgY29tcGF0aWJpbGl0eSBvbmx5XFxuICAgICAgICBlbmdpbmUuZ3JpZCA9IHsgYnVja2V0czogW10gfTtcXG4gICAgICAgIGVuZ2luZS53b3JsZC5ncmF2aXR5ID0gZW5naW5lLmdyYXZpdHk7XFxuICAgICAgICBlbmdpbmUuYnJvYWRwaGFzZSA9IGVuZ2luZS5ncmlkO1xcbiAgICAgICAgZW5naW5lLm1ldHJpY3MgPSB7fTtcXG4gICAgICAgIFxcbiAgICAgICAgcmV0dXJuIGVuZ2luZTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIE1vdmVzIHRoZSBzaW11bGF0aW9uIGZvcndhcmQgaW4gdGltZSBieSBgZGVsdGFgIG1pbGxpc2Vjb25kcy5cXG4gICAgICogVHJpZ2dlcnMgYGJlZm9yZVVwZGF0ZWAgYW5kIGBhZnRlclVwZGF0ZWAgZXZlbnRzLlxcbiAgICAgKiBUcmlnZ2VycyBgY29sbGlzaW9uU3RhcnRgLCBgY29sbGlzaW9uQWN0aXZlYCBhbmQgYGNvbGxpc2lvbkVuZGAgZXZlbnRzLlxcbiAgICAgKiBAbWV0aG9kIHVwZGF0ZVxcbiAgICAgKiBAcGFyYW0ge2VuZ2luZX0gZW5naW5lXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbZGVsdGE9MTYuNjY2XVxcbiAgICAgKi9cXG4gICAgRW5naW5lLnVwZGF0ZSA9IGZ1bmN0aW9uKGVuZ2luZSwgZGVsdGEpIHtcXG4gICAgICAgIHZhciBzdGFydFRpbWUgPSBDb21tb24ubm93KCk7XFxuXFxuICAgICAgICB2Y
2XIgd29ybGQgPSBlbmdpbmUud29ybGQsXFxuICAgICAgICAgICAgZGV0ZWN0b3IgPSBlbmdpbmUuZGV0ZWN0b3IsXFxuICAgICAgICAgICAgcGFpcnMgPSBlbmdpbmUucGFpcnMsXFxuICAgICAgICAgICAgdGltaW5nID0gZW5naW5lLnRpbWluZyxcXG4gICAgICAgICAgICB0aW1lc3RhbXAgPSB0aW1pbmcudGltZXN0YW1wLFxcbiAgICAgICAgICAgIGk7XFxuXFxuICAgICAgICBkZWx0YSA9IHR5cGVvZiBkZWx0YSAhPT0gJ3VuZGVmaW5lZCcgPyBkZWx0YSA6IENvbW1vbi5fYmFzZURlbHRhO1xcbiAgICAgICAgZGVsdGEgKj0gdGltaW5nLnRpbWVTY2FsZTtcXG5cXG4gICAgICAgIC8vIGluY3JlbWVudCB0aW1lc3RhbXBcXG4gICAgICAgIHRpbWluZy50aW1lc3RhbXAgKz0gZGVsdGE7XFxuICAgICAgICB0aW1pbmcubGFzdERlbHRhID0gZGVsdGE7XFxuXFxuICAgICAgICAvLyBjcmVhdGUgYW4gZXZlbnQgb2JqZWN0XFxuICAgICAgICB2YXIgZXZlbnQgPSB7XFxuICAgICAgICAgICAgdGltZXN0YW1wOiB0aW1pbmcudGltZXN0YW1wLFxcbiAgICAgICAgICAgIGRlbHRhOiBkZWx0YVxcbiAgICAgICAgfTtcXG5cXG4gICAgICAgIEV2ZW50cy50cmlnZ2VyKGVuZ2luZSwgJ2JlZm9yZVVwZGF0ZScsIGV2ZW50KTtcXG5cXG4gICAgICAgIC8vIGdldCBhbGwgYm9kaWVzIGFuZCBhbGwgY29uc3RyYWludHMgaW4gdGhlIHdvcmxkXFxuICAgICAgICB2YXIgYWxsQm9kaWVzID0gQ29tcG9zaXRlLmFsbEJvZGllcyh3b3JsZCksXFxuICAgICAgICAgICAgYWxsQ29uc3RyYWludHMgPSBDb21wb3NpdGUuYWxsQ29uc3RyYWludHMod29ybGQpO1xcblxcbiAgICAgICAgLy8gaWYgdGhlIHdvcmxkIGhhcyBjaGFuZ2VkXFxuICAgICAgICBpZiAod29ybGQuaXNNb2RpZmllZCkge1xcbiAgICAgICAgICAgIC8vIHVwZGF0ZSB0aGUgZGV0ZWN0b3IgYm9kaWVzXFxuICAgICAgICAgICAgRGV0ZWN0b3Iuc2V0Qm9kaWVzKGRldGVjdG9yLCBhbGxCb2RpZXMpO1xcblxcbiAgICAgICAgICAgIC8vIHJlc2V0IGFsbCBjb21wb3NpdGUgbW9kaWZpZWQgZmxhZ3NcXG4gICAgICAgICAgICBDb21wb3NpdGUuc2V0TW9kaWZpZWQod29ybGQsIGZhbHNlLCBmYWxzZSwgdHJ1ZSk7XFxuICAgICAgICB9XFxuXFxuICAgICAgICAvLyB1cGRhdGUgc2xlZXBpbmcgaWYgZW5hYmxlZFxcbiAgICAgICAgaWYgKGVuZ2luZS5lbmFibGVTbGVlcGluZylcXG4gICAgICAgICAgICBTbGVlcGluZy51cGRhdGUoYWxsQm9kaWVzLCBkZWx0YSk7XFxuXFxuICAgICAgICAvLyBhcHBseSBncmF2aXR5IHRvIGFsbCBib2RpZXNcXG4gICAgICAgIEVuZ2luZS5fYm9kaWVzQXBwbHlHcmF2aXR5KGFsbEJvZGllcywgZW5naW5lLmdyYXZpdHkpO1xcblxcbiAgICAgICAgLy8gdXBkYXRlIGFsbCBib2R5IHBvc2l0aW9uIGFuZCByb3RhdGlvbiBieSBpbnRlZ3JhdGlvblxcbiAgICAgICAgaWYgKGRlbHRhID4gMCkge1xcbiAgICAgICAgICAgIEVuZ2luZS5fYm9kaWVzVXBkYXRlKGFsbEJvZGllcywgZGVsdGEpO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgLy8gdXBkYXRlIGFsbCBjb25zdHJhaW50cyAoZmlyc3QgcGFzcylcXG4gICAgICAgIENvbnN0cmFpbnQucHJlU29sdmVBbGwoYWxsQm9kaWVzKTtcXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBlbmdpbmUuY29uc3RyYWludEl0ZXJhdGlvbnM7IGkrKykge1xcbiAgICAgICAgICAgIENvbnN0cmFpbnQuc29sdmVBbGwoYWxsQ29uc3RyYWludHMsIGRlbHRhKTtcXG4gICAgICAgIH1cXG4gICAgICAgIENvbnN0cmFpbnQucG9zdFNvbHZlQWxsKGFsbEJvZGllcyk7XFxuXFxuICAgICAgICAvLyBmaW5kIGFsbCBjb2xsaXNpb25zXFxuICAgICAgICBkZXRlY3Rvci5wYWlycyA9IGVuZ2luZS5wYWlycztcXG4gICAgICAgIHZhciBjb2xsaXNpb25zID0gRGV0ZWN0b3IuY29sbGlzaW9ucyhkZXRlY3Rvcik7XFxuXFxuICAgICAgICAvLyB1cGRhdGUgY29sbGlzaW9uIHBhaXJzXFxuICAgICAgICBQYWlycy51cGRhdGUocGFpcnMsIGNvbGxpc2lvbnMsIHRpbWVzdGFtcCk7XFxuXFxuICAgICAgICAvLyB3YWtlIHVwIGJvZGllcyBpbnZvbHZlZCBpbiBjb2xsaXNpb25zXFxuICAgICAgICBpZiAoZW5naW5lLmVuYWJsZVNsZWVwaW5nKVxcbiAgICAgICAgICAgIFNsZWVwaW5nLmFmdGVyQ29sbGlzaW9ucyhwYWlycy5saXN0KTtcXG5cXG4gICAgICAgIC8vIHRyaWdnZXIgY29sbGlzaW9uIGV2ZW50c1xcbiAgICAgICAgaWYgKHBhaXJzLmNvbGxpc2lvblN0YXJ0Lmxlbmd0aCA+IDApXFxuICAgICAgICAgICAgRXZlbnRzLnRyaWdnZXIoZW5naW5lLCAnY29sbGlzaW9uU3RhcnQnLCB7IHBhaXJzOiBwYWlycy5jb2xsaXNpb25TdGFydCB9KTtcXG5cXG4gICAgICAgIC8vIGl0ZXJhdGl2ZWx5IHJlc29sdmUgcG9zaXRpb24gYmV0d2VlbiBjb2xsaXNpb25zXFxuICAgICAgICB2Y
2XIgcG9zaXRpb25EYW1waW5nID0gQ29tbW9uLmNsYW1wKDIwIC8gZW5naW5lLnBvc2l0aW9uSXRlcmF0aW9ucywgMCwgMSk7XFxuICAgICAgICBcXG4gICAgICAgIFJlc29sdmVyLnByZVNvbHZlUG9zaXRpb24ocGFpcnMubGlzdCk7XFxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgZW5naW5lLnBvc2l0aW9uSXRlcmF0aW9uczsgaSsrKSB7XFxuICAgICAgICAgICAgUmVzb2x2ZXIuc29sdmVQb3NpdGlvbihwYWlycy5saXN0LCBkZWx0YSwgcG9zaXRpb25EYW1waW5nKTtcXG4gICAgICAgIH1cXG4gICAgICAgIFJlc29sdmVyLnBvc3RTb2x2ZVBvc2l0aW9uKGFsbEJvZGllcyk7XFxuXFxuICAgICAgICAvLyB1cGRhdGUgYWxsIGNvbnN0cmFpbnRzIChzZWNvbmQgcGFzcylcXG4gICAgICAgIENvbnN0cmFpbnQucHJlU29sdmVBbGwoYWxsQm9kaWVzKTtcXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBlbmdpbmUuY29uc3RyYWludEl0ZXJhdGlvbnM7IGkrKykge1xcbiAgICAgICAgICAgIENvbnN0cmFpbnQuc29sdmVBbGwoYWxsQ29uc3RyYWludHMsIGRlbHRhKTtcXG4gICAgICAgIH1cXG4gICAgICAgIENvbnN0cmFpbnQucG9zdFNvbHZlQWxsKGFsbEJvZGllcyk7XFxuXFxuICAgICAgICAvLyBpdGVyYXRpdmVseSByZXNvbHZlIHZlbG9jaXR5IGJldHdlZW4gY29sbGlzaW9uc1xcbiAgICAgICAgUmVzb2x2ZXIucHJlU29sdmVWZWxvY2l0eShwYWlycy5saXN0KTtcXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBlbmdpbmUudmVsb2NpdHlJdGVyYXRpb25zOyBpKyspIHtcXG4gICAgICAgICAgICBSZXNvbHZlci5zb2x2ZVZlbG9jaXR5KHBhaXJzLmxpc3QsIGRlbHRhKTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIC8vIHVwZGF0ZSBib2R5IHNwZWVkIGFuZCB2ZWxvY2l0eSBwcm9wZXJ0aWVzXFxuICAgICAgICBFbmdpbmUuX2JvZGllc1VwZGF0ZVZlbG9jaXRpZXMoYWxsQm9kaWVzKTtcXG5cXG4gICAgICAgIC8vIHRyaWdnZXIgY29sbGlzaW9uIGV2ZW50c1xcbiAgICAgICAgaWYgKHBhaXJzLmNvbGxpc2lvbkFjdGl2ZS5sZW5ndGggPiAwKVxcbiAgICAgICAgICAgIEV2ZW50cy50cmlnZ2VyKGVuZ2luZSwgJ2NvbGxpc2lvbkFjdGl2ZScsIHsgcGFpcnM6IHBhaXJzLmNvbGxpc2lvbkFjdGl2ZSB9KTtcXG5cXG4gICAgICAgIGlmIChwYWlycy5jb2xsaXNpb25FbmQubGVuZ3RoID4gMClcXG4gICAgICAgICAgICBFdmVudHMudHJpZ2dlcihlbmdpbmUsICdjb2xsaXNpb25FbmQnLCB7IHBhaXJzOiBwYWlycy5jb2xsaXNpb25FbmQgfSk7XFxuXFxuICAgICAgICAvLyBjbGVhciBmb3JjZSBidWZmZXJzXFxuICAgICAgICBFbmdpbmUuX2JvZGllc0NsZWFyRm9yY2VzKGFsbEJvZGllcyk7XFxuXFxuICAgICAgICBFdmVudHMudHJpZ2dlcihlbmdpbmUsICdhZnRlclVwZGF0ZScsIGV2ZW50KTtcXG5cXG4gICAgICAgIC8vIGxvZyB0aGUgdGltZSBlbGFwc2VkIGNvbXB1dGluZyB0aGlzIHVwZGF0ZVxcbiAgICAgICAgZW5naW5lLnRpbWluZy5sYXN0RWxhcHNlZCA9IENvbW1vbi5ub3coKSAtIHN0YXJ0VGltZTtcXG5cXG4gICAgICAgIHJldHVybiBlbmdpbmU7XFxuICAgIH07XFxuICAgIFxcbiAgICAvKipcXG4gICAgICogTWVyZ2VzIHR3byBlbmdpbmVzIGJ5IGtlZXBpbmcgdGhlIGNvbmZpZ3VyYXRpb24gb2YgYGVuZ2luZUFgIGJ1dCByZXBsYWNpbmcgdGhlIHdvcmxkIHdpdGggdGhlIG9uZSBmcm9tIGBlbmdpbmVCYC5cXG4gICAgICogQG1ldGhvZCBtZXJnZVxcbiAgICAgKiBAcGFyYW0ge2VuZ2luZX0gZW5naW5lQVxcbiAgICAgKiBAcGFyYW0ge2VuZ2luZX0gZW5naW5lQlxcbiAgICAgKi9cXG4gICAgRW5naW5lLm1lcmdlID0gZnVuY3Rpb24oZW5naW5lQSwgZW5naW5lQikge1xcbiAgICAgICAgQ29tbW9uLmV4dGVuZChlbmdpbmVBLCBlbmdpbmVCKTtcXG4gICAgICAgIFxcbiAgICAgICAgaWYgKGVuZ2luZUIud29ybGQpIHtcXG4gICAgICAgICAgICBlbmdpbmVBLndvcmxkID0gZW5naW5lQi53b3JsZDtcXG5cXG4gICAgICAgICAgICBFbmdpbmUuY2xlYXIoZW5naW5lQSk7XFxuXFxuICAgICAgICAgICAgdmFyIGJvZGllcyA9IENvbXBvc2l0ZS5hbGxCb2RpZXMoZW5naW5lQS53b3JsZCk7XFxuXFxuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBib2RpZXMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICAgICAgdmFyIGJvZHkgPSBib2RpZXNbaV07XFxuICAgICAgICAgICAgICAgIFNsZWVwaW5nLnNldChib2R5LCBmYWxzZSk7XFxuICAgICAgICAgICAgICAgIGJvZHkuaWQgPSBDb21tb24ubmV4dElkKCk7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogQ2xlYXJzIHRoZSBlbmdpbmUgcGFpcnMgYW5kIGRldGVjdG9yLlxcbiAgICAgKiBAbWV0aG9kIGNsZWFyXFxuICAgICAqIEBwYXJhbSB7ZW5naW5lfSBlbmdpbmVcXG4gICAgICovXFxuICAgIEVuZ2luZS5jbGVhciA9IGZ1bmN0aW9uKGVuZ2luZSkge1xcbiAgICAgICAgUGFpcnMuY2xlYXIoZW5naW5lLnBhaXJzKTtcXG4gICAgICAgIERldGVjdG9yLmNsZWFyKGVuZ2luZS5kZXRlY3Rvcik7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBaZXJvZXMgdGhlIGBib2R5LmZvcmNlYCBhbmQgYGJvZHkudG9ycXVlYCBmb3JjZSBidWZmZXJzLlxcbiAgICAgKiBAbWV0aG9kIF9ib2RpZXNDbGVhckZvcmNlc1xcbiAgICAgKiBAcHJpdmF0ZVxcbiAgICAgKiBAcGFyYW0ge2JvZHlbXX0gYm9kaWVzXFxuICAgICAqL1xcbiAgICBFbmdpbmUuX2JvZGllc0NsZWFyRm9yY2VzID0gZnVuY3Rpb24oYm9kaWVzKSB7XFxuICAgICAgICB2Y
2XIgYm9kaWVzTGVuZ3RoID0gYm9kaWVzLmxlbmd0aDtcXG5cXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYm9kaWVzTGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICB2YXIgYm9keSA9IGJvZGllc1tpXTtcXG5cXG4gICAgICAgICAgICAvLyByZXNldCBmb3JjZSBidWZmZXJzXFxuICAgICAgICAgICAgYm9keS5mb3JjZS54ID0gMDtcXG4gICAgICAgICAgICBib2R5LmZvcmNlLnkgPSAwO1xcbiAgICAgICAgICAgIGJvZHkudG9ycXVlID0gMDtcXG4gICAgICAgIH1cXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIEFwcGxpZXMgZ3Jhdml0YXRpb25hbCBhY2NlbGVyYXRpb24gdG8gYWxsIGBib2RpZXNgLlxcbiAgICAgKiBUaGlzIG1vZGVscyBhIFt1bmlmb3JtIGdyYXZpdGF0aW9uYWwgZmllbGRdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0dyYXZpdHlfb2ZfRWFydGgpLCBzaW1pbGFyIHRvIG5lYXIgdGhlIHN1cmZhY2Ugb2YgYSBwbGFuZXQuXFxuICAgICAqIFxcbiAgICAgKiBAbWV0aG9kIF9ib2RpZXNBcHBseUdyYXZpdHlcXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQHBhcmFtIHtib2R5W119IGJvZGllc1xcbiAgICAgKiBAcGFyYW0ge3ZlY3Rvcn0gZ3Jhdml0eVxcbiAgICAgKi9cXG4gICAgRW5naW5lLl9ib2RpZXNBcHBseUdyYXZpdHkgPSBmdW5jdGlvbihib2RpZXMsIGdyYXZpdHkpIHtcXG4gICAgICAgIHZhciBncmF2aXR5U2NhbGUgPSB0eXBlb2YgZ3Jhdml0eS5zY2FsZSAhPT0gJ3VuZGVmaW5lZCcgPyBncmF2aXR5LnNjYWxlIDogMC4wMDEsXFxuICAgICAgICAgICAgYm9kaWVzTGVuZ3RoID0gYm9kaWVzLmxlbmd0aDtcXG5cXG4gICAgICAgIGlmICgoZ3Jhdml0eS54ID09PSAwICYmIGdyYXZpdHkueSA9PT0gMCkgfHwgZ3Jhdml0eVNjYWxlID09PSAwKSB7XFxuICAgICAgICAgICAgcmV0dXJuO1xcbiAgICAgICAgfVxcbiAgICAgICAgXFxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJvZGllc0xlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgdmFyIGJvZHkgPSBib2RpZXNbaV07XFxuXFxuICAgICAgICAgICAgaWYgKGJvZHkuaXNTdGF0aWMgfHwgYm9keS5pc1NsZWVwaW5nKVxcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcXG5cXG4gICAgICAgICAgICAvLyBhZGQgdGhlIHJlc3VsdGFudCBmb3JjZSBvZiBncmF2aXR5XFxuICAgICAgICAgICAgYm9keS5mb3JjZS55ICs9IGJvZHkubWFzcyAqIGdyYXZpdHkueSAqIGdyYXZpdHlTY2FsZTtcXG4gICAgICAgICAgICBib2R5LmZvcmNlLnggKz0gYm9keS5tYXNzICogZ3Jhdml0eS54ICogZ3Jhdml0eVNjYWxlO1xcbiAgICAgICAgfVxcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogQXBwbGllcyBgQm9keS51cGRhdGVgIHRvIGFsbCBnaXZlbiBgYm9kaWVzYC5cXG4gICAgICogQG1ldGhvZCBfYm9kaWVzVXBkYXRlXFxuICAgICAqIEBwcml2YXRlXFxuICAgICAqIEBwYXJhbSB7Ym9keVtdfSBib2RpZXNcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGRlbHRhIFRoZSBhbW91bnQgb2YgdGltZSBlbGFwc2VkIGJldHdlZW4gdXBkYXRlc1xcbiAgICAgKi9cXG4gICAgRW5naW5lLl9ib2RpZXNVcGRhdGUgPSBmdW5jdGlvbihib2RpZXMsIGRlbHRhKSB7XFxuICAgICAgICB2Y
2XIgYm9kaWVzTGVuZ3RoID0gYm9kaWVzLmxlbmd0aDtcXG5cXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYm9kaWVzTGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICB2YXIgYm9keSA9IGJvZGllc1tpXTtcXG5cXG4gICAgICAgICAgICBpZiAoYm9keS5pc1N0YXRpYyB8fCBib2R5LmlzU2xlZXBpbmcpXFxuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xcblxcbiAgICAgICAgICAgIEJvZHkudXBkYXRlKGJvZHksIGRlbHRhKTtcXG4gICAgICAgIH1cXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIEFwcGxpZXMgYEJvZHkudXBkYXRlVmVsb2NpdGllc2AgdG8gYWxsIGdpdmVuIGBib2RpZXNgLlxcbiAgICAgKiBAbWV0aG9kIF9ib2RpZXNVcGRhdGVWZWxvY2l0aWVzXFxuICAgICAqIEBwcml2YXRlXFxuICAgICAqIEBwYXJhbSB7Ym9keVtdfSBib2RpZXNcXG4gICAgICovXFxuICAgIEVuZ2luZS5fYm9kaWVzVXBkYXRlVmVsb2NpdGllcyA9IGZ1bmN0aW9uKGJvZGllcykge1xcbiAgICAgICAgdmFyIGJvZGllc0xlbmd0aCA9IGJvZGllcy5sZW5ndGg7XFxuXFxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJvZGllc0xlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgQm9keS51cGRhdGVWZWxvY2l0aWVzKGJvZGllc1tpXSk7XFxuICAgICAgICB9XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGRlcHJlY2F0ZWQgYWxpYXMgZm9yIGBSdW5uZXIucnVuYCwgdXNlIGBNYXR0ZXIuUnVubmVyLnJ1bihlbmdpbmUpYCBpbnN0ZWFkIGFuZCBzZWUgYE1hdHRlci5SdW5uZXJgIGZvciBtb3JlIGluZm9ybWF0aW9uLlxcbiAgICAgKiBAZGVwcmVjYXRlZCB1c2UgTWF0dGVyLlJ1bm5lci5ydW4oZW5naW5lKSBpbnN0ZWFkXFxuICAgICAqIEBtZXRob2QgcnVuXFxuICAgICAqIEBwYXJhbSB7ZW5naW5lfSBlbmdpbmVcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAqIEZpcmVkIGp1c3QgYmVmb3JlIGFuIHVwZGF0ZVxcbiAgICAqXFxuICAgICogQGV2ZW50IGJlZm9yZVVwZGF0ZVxcbiAgICAqIEBwYXJhbSB7b2JqZWN0fSBldmVudCBBbiBldmVudCBvYmplY3RcXG4gICAgKiBAcGFyYW0ge251bWJlcn0gZXZlbnQudGltZXN0YW1wIFRoZSBlbmdpbmUudGltaW5nLnRpbWVzdGFtcCBvZiB0aGUgZXZlbnRcXG4gICAgKiBAcGFyYW0ge251bWJlcn0gZXZlbnQuZGVsdGEgVGhlIGRlbHRhIHRpbWUgaW4gbWlsbGlzZWNvbmRzIHZhbHVlIHVzZWQgaW4gdGhlIHVwZGF0ZVxcbiAgICAqIEBwYXJhbSB7ZW5naW5lfSBldmVudC5zb3VyY2UgVGhlIHNvdXJjZSBvYmplY3Qgb2YgdGhlIGV2ZW50XFxuICAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50Lm5hbWUgVGhlIG5hbWUgb2YgdGhlIGV2ZW50XFxuICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAqIEZpcmVkIGFmdGVyIGVuZ2luZSB1cGRhdGUgYW5kIGFsbCBjb2xsaXNpb24gZXZlbnRzXFxuICAgICpcXG4gICAgKiBAZXZlbnQgYWZ0ZXJVcGRhdGVcXG4gICAgKiBAcGFyYW0ge29iamVjdH0gZXZlbnQgQW4gZXZlbnQgb2JqZWN0XFxuICAgICogQHBhcmFtIHtudW1iZXJ9IGV2ZW50LnRpbWVzdGFtcCBUaGUgZW5naW5lLnRpbWluZy50aW1lc3RhbXAgb2YgdGhlIGV2ZW50XFxuICAgICogQHBhcmFtIHtudW1iZXJ9IGV2ZW50LmRlbHRhIFRoZSBkZWx0YSB0aW1lIGluIG1pbGxpc2Vjb25kcyB2YWx1ZSB1c2VkIGluIHRoZSB1cGRhdGVcXG4gICAgKiBAcGFyYW0ge2VuZ2luZX0gZXZlbnQuc291cmNlIFRoZSBzb3VyY2Ugb2JqZWN0IG9mIHRoZSBldmVudFxcbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudC5uYW1lIFRoZSBuYW1lIG9mIHRoZSBldmVudFxcbiAgICAqL1xcblxcbiAgICAvKipcXG4gICAgKiBGaXJlZCBhZnRlciBlbmdpbmUgdXBkYXRlLCBwcm92aWRlcyBhIGxpc3Qgb2YgYWxsIHBhaXJzIHRoYXQgaGF2ZSBzdGFydGVkIHRvIGNvbGxpZGUgaW4gdGhlIGN1cnJlbnQgdGljayAoaWYgYW55KVxcbiAgICAqXFxuICAgICogQGV2ZW50IGNvbGxpc2lvblN0YXJ0XFxuICAgICogQHBhcmFtIHtvYmplY3R9IGV2ZW50IEFuIGV2ZW50IG9iamVjdFxcbiAgICAqIEBwYXJhbSB7cGFpcltdfSBldmVudC5wYWlycyBMaXN0IG9mIGFmZmVjdGVkIHBhaXJzXFxuICAgICogQHBhcmFtIHtudW1iZXJ9IGV2ZW50LnRpbWVzdGFtcCBUaGUgZW5naW5lLnRpbWluZy50aW1lc3RhbXAgb2YgdGhlIGV2ZW50XFxuICAgICogQHBhcmFtIHtudW1iZXJ9IGV2ZW50LmRlbHRhIFRoZSBkZWx0YSB0aW1lIGluIG1pbGxpc2Vjb25kcyB2YWx1ZSB1c2VkIGluIHRoZSB1cGRhdGVcXG4gICAgKiBAcGFyYW0ge2VuZ2luZX0gZXZlbnQuc291cmNlIFRoZSBzb3VyY2Ugb2JqZWN0IG9mIHRoZSBldmVudFxcbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudC5uYW1lIFRoZSBuYW1lIG9mIHRoZSBldmVudFxcbiAgICAqL1xcblxcbiAgICAvKipcXG4gICAgKiBGaXJlZCBhZnRlciBlbmdpbmUgdXBkYXRlLCBwcm92aWRlcyBhIGxpc3Qgb2YgYWxsIHBhaXJzIHRoYXQgYXJlIGNvbGxpZGluZyBpbiB0aGUgY3VycmVudCB0aWNrIChpZiBhbnkpXFxuICAgICpcXG4gICAgKiBAZXZlbnQgY29sbGlzaW9uQWN0aXZlXFxuICAgICogQHBhcmFtIHtvYmplY3R9IGV2ZW50IEFuIGV2ZW50IG9iamVjdFxcbiAgICAqIEBwYXJhbSB7cGFpcltdfSBldmVudC5wYWlycyBMaXN0IG9mIGFmZmVjdGVkIHBhaXJzXFxuICAgICogQHBhcmFtIHtudW1iZXJ9IGV2ZW50LnRpbWVzdGFtcCBUaGUgZW5naW5lLnRpbWluZy50aW1lc3RhbXAgb2YgdGhlIGV2ZW50XFxuICAgICogQHBhcmFtIHtudW1iZXJ9IGV2ZW50LmRlbHRhIFRoZSBkZWx0YSB0aW1lIGluIG1pbGxpc2Vjb25kcyB2YWx1ZSB1c2VkIGluIHRoZSB1cGRhdGVcXG4gICAgKiBAcGFyYW0ge2VuZ2luZX0gZXZlbnQuc291cmNlIFRoZSBzb3VyY2Ugb2JqZWN0IG9mIHRoZSBldmVudFxcbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBldmVudC5uYW1lIFRoZSBuYW1lIG9mIHRoZSBldmVudFxcbiAgICAqL1xcblxcbiAgICAvKipcXG4gICAgKiBGaXJlZCBhZnRlciBlbmdpbmUgdXBkYXRlLCBwcm92aWRlcyBhIGxpc3Qgb2YgYWxsIHBhaXJzIHRoYXQgaGF2ZSBlbmRlZCBjb2xsaXNpb24gaW4gdGhlIGN1cnJlbnQgdGljayAoaWYgYW55KVxcbiAgICAqXFxuICAgICogQGV2ZW50IGNvbGxpc2lvbkVuZFxcbiAgICAqIEBwYXJhbSB7b2JqZWN0fSBldmVudCB
2BbiBldmVudCBvYmplY3RcXG4gICAgKiBAcGFyYW0ge3BhaXJbXX0gZXZlbnQucGFpcnMgTGlzdCBvZiBhZmZlY3RlZCBwYWlyc1xcbiAgICAqIEBwYXJhbSB7bnVtYmVyfSBldmVudC50aW1lc3RhbXAgVGhlIGVuZ2luZS50aW1pbmcudGltZXN0YW1wIG9mIHRoZSBldmVudFxcbiAgICAqIEBwYXJhbSB7bnVtYmVyfSBldmVudC5kZWx0YSBUaGUgZGVsdGEgdGltZSBpbiBtaWxsaXNlY29uZHMgdmFsdWUgdXNlZCBpbiB0aGUgdXBkYXRlXFxuICAgICogQHBhcmFtIHtlbmdpbmV9IGV2ZW50LnNvdXJjZSBUaGUgc291cmNlIG9iamVjdCBvZiB0aGUgZXZlbnRcXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gZXZlbnQubmFtZSBUaGUgbmFtZSBvZiB0aGUgZXZlbnRcXG4gICAgKi9cXG5cXG4gICAgLypcXG4gICAgKlxcbiAgICAqICBQcm9wZXJ0aWVzIERvY3VtZW50YXRpb25cXG4gICAgKlxcbiAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQW4gaW50ZWdlciBgTnVtYmVyYCB0aGF0IHNwZWNpZmllcyB0aGUgbnVtYmVyIG9mIHBvc2l0aW9uIGl0ZXJhdGlvbnMgdG8gcGVyZm9ybSBlYWNoIHVwZGF0ZS5cXG4gICAgICogVGhlIGhpZ2hlciB0aGUgdmFsdWUsIHRoZSBoaWdoZXIgcXVhbGl0eSB0aGUgc2ltdWxhdGlvbiB3aWxsIGJlIGF0IHRoZSBleHBlbnNlIG9mIHBlcmZvcm1hbmNlLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgcG9zaXRpb25JdGVyYXRpb25zXFxuICAgICAqIEB0eXBlIG51bWJlclxcbiAgICAgKiBAZGVmYXVsdCA2XFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQW4gaW50ZWdlciBgTnVtYmVyYCB0aGF0IHNwZWNpZmllcyB0aGUgbnVtYmVyIG9mIHZlbG9jaXR5IGl0ZXJhdGlvbnMgdG8gcGVyZm9ybSBlYWNoIHVwZGF0ZS5cXG4gICAgICogVGhlIGhpZ2hlciB0aGUgdmFsdWUsIHRoZSBoaWdoZXIgcXVhbGl0eSB0aGUgc2ltdWxhdGlvbiB3aWxsIGJlIGF0IHRoZSBleHBlbnNlIG9mIHBlcmZvcm1hbmNlLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgdmVsb2NpdHlJdGVyYXRpb25zXFxuICAgICAqIEB0eXBlIG51bWJlclxcbiAgICAgKiBAZGVmYXVsdCA0XFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQW4gaW50ZWdlciBgTnVtYmVyYCB0aGF0IHNwZWNpZmllcyB0aGUgbnVtYmVyIG9mIGNvbnN0cmFpbnQgaXRlcmF0aW9ucyB0byBwZXJmb3JtIGVhY2ggdXBkYXRlLlxcbiAgICAgKiBUaGUgaGlnaGVyIHRoZSB2YWx1ZSwgdGhlIGhpZ2hlciBxdWFsaXR5IHRoZSBzaW11bGF0aW9uIHdpbGwgYmUgYXQgdGhlIGV4cGVuc2Ugb2YgcGVyZm9ybWFuY2UuXFxuICAgICAqIFRoZSBkZWZhdWx0IHZhbHVlIG9mIGAyYCBpcyB1c3VhbGx5IHZlcnkgYWRlcXVhdGUuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBjb25zdHJhaW50SXRlcmF0aW9uc1xcbiAgICAgKiBAdHlwZSBudW1iZXJcXG4gICAgICogQGRlZmF1bHQgMlxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEEgZmxhZyB0aGF0IHNwZWNpZmllcyB3aGV0aGVyIHR
2oZSBlbmdpbmUgc2hvdWxkIGFsbG93IHNsZWVwaW5nIHZpYSB0aGUgYE1hdHRlci5TbGVlcGluZ2AgbW9kdWxlLlxcbiAgICAgKiBTbGVlcGluZyBjYW4gaW1wcm92ZSBzdGFiaWxpdHkgYW5kIHBlcmZvcm1hbmNlLCBidXQgb2Z0ZW4gYXQgdGhlIGV4cGVuc2Ugb2YgYWNjdXJhY3kuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBlbmFibGVTbGVlcGluZ1xcbiAgICAgKiBAdHlwZSBib29sZWFuXFxuICAgICAqIEBkZWZhdWx0IGZhbHNlXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQW4gYE9iamVjdGAgY29udGFpbmluZyBwcm9wZXJ0aWVzIHJlZ2FyZGluZyB0aGUgdGltaW5nIHN5c3RlbXMgb2YgdGhlIGVuZ2luZS4gXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSB0aW1pbmdcXG4gICAgICogQHR5cGUgb2JqZWN0XFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBgTnVtYmVyYCB0aGF0IHNwZWNpZmllcyB0aGUgZ2xvYmFsIHNjYWxpbmcgZmFjdG9yIG9mIHRpbWUgZm9yIGFsbCBib2RpZXMuXFxuICAgICAqIEEgdmFsdWUgb2YgYDBgIGZyZWV6ZXMgdGhlIHNpbXVsYXRpb24uXFxuICAgICAqIEEgdmFsdWUgb2YgYDAuMWAgZ2l2ZXMgYSBzbG93LW1vdGlvbiBlZmZlY3QuXFxuICAgICAqIEEgdmFsdWUgb2YgYDEuMmAgZ2l2ZXMgYSBzcGVlZC11cCBlZmZlY3QuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSB0aW1pbmcudGltZVNjYWxlXFxuICAgICAqIEB0eXBlIG51bWJlclxcbiAgICAgKiBAZGVmYXVsdCAxXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBgTnVtYmVyYCB0aGF0IHNwZWNpZmllcyB0aGUgY3VycmVudCBzaW11bGF0aW9uLXRpbWUgaW4gbWlsbGlzZWNvbmRzIHN0YXJ0aW5nIGZyb20gYDBgLiBcXG4gICAgICogSXQgaXMgaW5jcmVtZW50ZWQgb24gZXZlcnkgYEVuZ2luZS51cGRhdGVgIGJ5IHRoZSBnaXZlbiBgZGVsdGFgIGFyZ3VtZW50LiBcXG4gICAgICogXFxuICAgICAqIEBwcm9wZXJ0eSB0aW1pbmcudGltZXN0YW1wXFxuICAgICAqIEB0eXBlIG51bWJlclxcbiAgICAgKiBAZGVmYXVsdCAwXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBgTnVtYmVyYCB0aGF0IHJlcHJlc2VudHMgdGhlIHRvdGFsIGV4ZWN1dGlvbiB0aW1lIGVsYXBzZWQgZHVyaW5nIHRoZSBsYXN0IGBFbmdpbmUudXBkYXRlYCBpbiBtaWxsaXNlY29uZHMuXFxuICAgICAqIEl0IGlzIHVwZGF0ZWQgYnkgdGltaW5nIGZyb20gdGhlIHN0YXJ0IG9mIHRoZSBsYXN0IGBFbmdpbmUudXBkYXRlYCBjYWxsIHVudGlsIGl0IGVuZHMuXFxuICAgICAqXFxuICAgICAqIFRoaXMgdmFsdWUgd2lsbCBhbHNvIGluY2x1ZGUgdGhlIHRvdGFsIGV4ZWN1dGlvbiB0aW1lIG9mIGFsbCBldmVudCBoYW5kbGVycyBkaXJlY3RseSBvciBpbmRpcmVjdGx5IHRyaWdnZXJlZCBieSB0aGUgZW5naW5lIHVwZGF0ZS5cXG4gICAgICogXFxuICAgICAqIEBwcm9wZXJ0eSB0aW1pbmcubGFzdEVsYXBzZWRcXG4gICAgICogQHR5cGUgbnVtYmVyXFxuICAgICAqIEBkZWZhdWx0IDBcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGBOdW1iZXJgIHRoYXQgcmVwcmVzZW50cyB0aGUgYGRlbHRhYCB2YWx1ZSB1c2VkIGluIHRoZSBsYXN0IGVuZ2luZSB1cGRhdGUuXFxuICAgICAqIFxcbiAgICAgKiBAcHJvcGVydHkgdGltaW5nLmxhc3REZWx0YVxcbiAgICAgKiBAdHlwZSBudW1iZXJcXG4gICAgICogQGRlZmF1bHQgMFxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEEgYE1hdHRlci5EZXRlY3RvcmAgaW5zdGFuY2UuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBkZXRlY3RvclxcbiAgICAgKiBAdHlwZSBkZXRlY3RvclxcbiAgICAgKiBAZGVmYXVsdCBhIE1hdHRlci5EZXRlY3RvciBpbnN0YW5jZVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEEgYE1hdHRlci5HcmlkYCBpbnN0YW5jZS5cXG4gICAgICpcXG4gICAgICogQGRlcHJlY2F0ZWQgcmVwbGFjZWQgYnkgYGVuZ2luZS5kZXRlY3RvcmBcXG4gICAgICogQHByb3BlcnR5IGdyaWRcXG4gICAgICogQHR5cGUgZ3JpZFxcbiAgICAgKiBAZGVmYXVsdCBhIE1hdHRlci5HcmlkIGluc3RhbmNlXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogUmVwbGFjZWQgYnkgYW5kIG5vdyBhbGlhcyBmb3IgYGVuZ2luZS5ncmlkYC5cXG4gICAgICpcXG4gICAgICogQGRlcHJlY2F0ZWQgcmVwbGFjZWQgYnkgYGVuZ2luZS5kZXRlY3RvcmBcXG4gICAgICogQHByb3BlcnR5IGJyb2FkcGhhc2VcXG4gICAgICogQHR5cGUgZ3JpZFxcbiAgICAgKiBAZGVmYXVsdCBhIE1hdHRlci5HcmlkIGluc3RhbmNlXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogVGhlIHJvb3QgYE1hdHRlci5Db21wb3NpdGVgIGluc3RhbmNlIHRoYXQgd2lsbCBjb250YWluIGFsbCBib2RpZXMsIGNvbnN0cmFpbnRzIGFuZCBvdGhlciBjb21wb3NpdGVzIHRvIGJlIHNpbXVsYXRlZCBieSB0aGlzIGVuZ2luZS5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IHdvcmxkXFxuICAgICAqIEB0eXBlIGNvbXBvc2l0ZVxcbiAgICAgKiBAZGVmYXVsdCBhIE1hdHRlci5Db21wb3NpdGUgaW5zdGFuY2VcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBbiBvYmplY3QgcmVzZXJ2ZWQgZm9yIHN0b3JpbmcgcGx1Z2luLXNwZWNpZmljIHByb3BlcnRpZXMuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBwbHVnaW5cXG4gICAgICogQHR5cGUge31cXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBbiBvcHRpb25hbCBncmF2aXRhdGlvbmFsIGFjY2VsZXJhdGlvbiBhcHBsaWVkIHRvIGFsbCBib2RpZXMgaW4gYGVuZ2luZS53b3JsZGAgb24gZXZlcnkgdXBkYXRlLlxcbiAgICAgKiBcXG4gICAgICogVGhpcyBtb2RlbHMgYSBbdW5pZm9ybSBncmF2aXRhdGlvbmFsIGZpZWxkXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9HcmF2aXR5X29mX0VhcnRoKSwgc2ltaWxhciB0byBuZWFyIHRoZSBzdXJmYWNlIG9mIGEgcGxhbmV0LiBGb3IgZ3Jhdml0eSBpbiBvdGhlciBjb250ZXh0cywgZGlzYWJsZSB0aGlzIGFuZCBhcHBseSBmb3JjZXMgYXMgbmVlZGVkLlxcbiAgICAgKiBcXG4gICAgICogVG8gZGlzYWJsZSBzZXQgdGhlIGBzY2FsZWAgY29tcG9uZW50IHRvIGAwYC5cXG4gICAgICogXFxuICAgICAqIFRoaXMgaXMgc3BsaXQgaW50byB0aHJlZSBjb21wb25lbnRzIGZvciBlYXNlIG9mIHVzZTogIFxcbiAgICAgKiBhIG5vcm1hbGlzZWQgZGlyZWN0aW9uIChgeGAgYW5kIGB5YCkgYW5kIG1hZ25pdHVkZSAoYHNjYWxlYCkuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBncmF2aXR5XFxuICAgICAqIEB0eXBlIG9iamVjdFxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIFRoZSBncmF2aXRhdGlvbmFsIGRpcmVjdGlvbiBub3JtYWwgYHhgIGNvbXBvbmVudCwgdG8gYmUgbXVsdGlwbGllZCBieSBgZ3Jhdml0eS5zY2FsZWAuXFxuICAgICAqIFxcbiAgICAgKiBAcHJvcGVydHkgZ3Jhdml0eS54XFxuICAgICAqIEB0eXBlIG9iamVjdFxcbiAgICAgKiBAZGVmYXVsdCAwXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogVGhlIGdyYXZpdGF0aW9uYWwgZGlyZWN0aW9uIG5vcm1hbCBgeWAgY29tcG9uZW50LCB0byBiZSBtdWx0aXBsaWVkIGJ5IGBncmF2aXR5LnNjYWxlYC5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IGdyYXZpdHkueVxcbiAgICAgKiBAdHlwZSBvYmplY3RcXG4gICAgICogQGRlZmF1bHQgMVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIFRoZSBtYWduaXR1ZGUgb2YgdGhlIGdyYXZpdGF0aW9uYWwgYWNjZWxlcmF0aW9uLlxcbiAgICAgKiBcXG4gICAgICogQHByb3BlcnR5IGdyYXZpdHkuc2NhbGVcXG4gICAgICogQHR5cGUgb2JqZWN0XFxuICAgICAqIEBkZWZhdWx0IDAuMDAxXFxuICAgICAqL1xcblxcbn0pKCk7XFxuXFxuXFxuLyoqKi8gfSksXFxuLyogMTggKi9cXG4vKioqLyAoZnVuY3Rpb24obW9kdWxlLCBleHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XFxuXFxuLyoqXFxuKiBUaGUgYE1hdHRlci5SZXNvbHZlcmAgbW9kdWxlIGNvbnRhaW5zIG1ldGhvZHMgZm9yIHJlc29sdmluZyBjb2xsaXNpb24gcGF
2pcnMuXFxuKlxcbiogQGNsYXNzIFJlc29sdmVyXFxuKi9cXG5cXG52YXIgUmVzb2x2ZXIgPSB7fTtcXG5cXG5tb2R1bGUuZXhwb3J0cyA9IFJlc29sdmVyO1xcblxcbnZhciBWZXJ0aWNlcyA9IF9fd2VicGFja19yZXF1aXJlX18oMyk7XFxudmFyIENvbW1vbiA9IF9fd2VicGFja19yZXF1aXJlX18oMCk7XFxudmFyIEJvdW5kcyA9IF9fd2VicGFja19yZXF1aXJlX18oMSk7XFxuXFxuKGZ1bmN0aW9uKCkge1xcblxcbiAgICBSZXNvbHZlci5fcmVzdGluZ1RocmVzaCA9IDI7XFxuICAgIFJlc29sdmVyLl9yZXN0aW5nVGhyZXNoVGFuZ2VudCA9IE1hdGguc3FydCg2KTtcXG4gICAgUmVzb2x2ZXIuX3Bvc2l0aW9uRGFtcGVuID0gMC45O1xcbiAgICBSZXNvbHZlci5fcG9zaXRpb25XYXJtaW5nID0gMC44O1xcbiAgICBSZXNvbHZlci5fZnJpY3Rpb25Ob3JtYWxNdWx0aXBsaWVyID0gNTtcXG4gICAgUmVzb2x2ZXIuX2ZyaWN0aW9uTWF4U3RhdGljID0gTnVtYmVyLk1BWF9WQUxVRTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFByZXBhcmUgcGFpcnMgZm9yIHBvc2l0aW9uIHNvbHZpbmcuXFxuICAgICAqIEBtZXRob2QgcHJlU29sdmVQb3NpdGlvblxcbiAgICAgKiBAcGFyYW0ge3BhaXJbXX0gcGFpcnNcXG4gICAgICovXFxuICAgIFJlc29sdmVyLnByZVNvbHZlUG9zaXRpb24gPSBmdW5jdGlvbihwYWlycykge1xcbiAgICAgICAgdmFyIGksXFxuICAgICAgICAgICAgcGFpcixcXG4gICAgICAgICAgICBhY3RpdmVDb3VudCxcXG4gICAgICAgICAgICBwYWlyc0xlbmd0aCA9IHBhaXJzLmxlbmd0aDtcXG5cXG4gICAgICAgIC8vIGZpbmQgdG90YWwgY29udGFjdHMgb24gZWFjaCBib2R5XFxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgcGFpcnNMZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHBhaXIgPSBwYWlyc1tpXTtcXG4gICAgICAgICAgICBcXG4gICAgICAgICAgICBpZiAoIXBhaXIuaXNBY3RpdmUpXFxuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xcbiAgICAgICAgICAgIFxcbiAgICAgICAgICAgIGFjdGl2ZUNvdW50ID0gcGFpci5hY3RpdmVDb250YWN0cy5sZW5ndGg7XFxuICAgICAgICAgICAgcGFpci5jb2xsaXNpb24ucGFyZW50QS50b3RhbENvbnRhY3RzICs9IGFjdGl2ZUNvdW50O1xcbiAgICAgICAgICAgIHBhaXIuY29sbGlzaW9uLnBhcmVudEIudG90YWxDb250YWN0cyArPSBhY3RpdmVDb3VudDtcXG4gICAgICAgIH1cXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIEZpbmQgYS
2Bzb2x1dGlvbiBmb3IgcGFpciBwb3NpdGlvbnMuXFxuICAgICAqIEBtZXRob2Qgc29sdmVQb3NpdGlvblxcbiAgICAgKiBAcGFyYW0ge3BhaXJbXX0gcGFpcnNcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGRlbHRhXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBbZGFtcGluZz0xXVxcbiAgICAgKi9cXG4gICAgUmVzb2x2ZXIuc29sdmVQb3NpdGlvbiA9IGZ1bmN0aW9uKHBhaXJzLCBkZWx0YSwgZGFtcGluZykge1xcbiAgICAgICAgdmFyIGksXFxuICAgICAgICAgICAgcGFpcixcXG4gICAgICAgICAgICBjb2xsaXNpb24sXFxuICAgICAgICAgICAgYm9keUEsXFxuICAgICAgICAgICAgYm9keUIsXFxuICAgICAgICAgICAgbm9ybWFsLFxcbiAgICAgICAgICAgIGNvbnRhY3RTaGFyZSxcXG4gICAgICAgICAgICBwb3NpdGlvbkltcHVsc2UsXFxuICAgICAgICAgICAgcG9zaXRpb25EYW1wZW4gPSBSZXNvbHZlci5fcG9zaXRpb25EYW1wZW4gKiAoZGFtcGluZyB8fCAxKSxcXG4gICAgICAgICAgICBzbG9wRGFtcGVuID0gQ29tbW9uLmNsYW1wKGRlbHRhIC8gQ29tbW9uLl9iYXNlRGVsdGEsIDAsIDEpLFxcbiAgICAgICAgICAgIHBhaXJzTGVuZ3RoID0gcGFpcnMubGVuZ3RoO1xcblxcbiAgICAgICAgLy8gZmluZCBpbXB1bHNlcyByZXF1aXJlZCB0byByZXNvbHZlIHBlbmV0cmF0aW9uXFxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgcGFpcnNMZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHBhaXIgPSBwYWlyc1tpXTtcXG4gICAgICAgICAgICBcXG4gICAgICAgICAgICBpZiAoIXBhaXIuaXNBY3RpdmUgfHwgcGFpci5pc1NlbnNvcilcXG4gICAgICAgICAgICAgICAgY29udGludWU7XFxuXFxuICAgICAgICAgICAgY29sbGlzaW9uID0gcGFpci5jb2xsaXNpb247XFxuICAgICAgICAgICAgYm9keUEgPSBjb2xsaXNpb24ucGFyZW50QTtcXG4gICAgICAgICAgICBib2R5QiA9IGNvbGxpc2lvbi5wYXJlbnRCO1xcbiAgICAgICAgICAgIG5vcm1hbCA9IGNvbGxpc2lvbi5ub3JtYWw7XFxuXFxuICAgICAgICAgICAgLy8gZ2V0IGN1cnJlbnQgc2VwYXJhdGlvbiBiZXR3ZWVuIGJvZHkgZWRnZXMgaW52b2x2ZWQgaW4gY29sbGlzaW9uXFxuICAgICAgICAgICAgcGFpci5zZXBhcmF0aW9uID0gXFxuICAgICAgICAgICAgICAgIG5vcm1hbC54ICogKGJvZHlCLnBvc2l0aW9uSW1wdWxzZS54ICsgY29sbGlzaW9uLnBlbmV0cmF0aW9uLnggLSBib2R5QS5wb3NpdGlvbkltcHVsc2UueClcXG4gICAgICAgICAgICAgICAgKyBub3JtYWwueSAqIChib2R5Qi5wb3NpdGlvbkltcHVsc2UueSArIGNvbGxpc2lvbi5wZW5ldHJhdGlvbi55IC0gYm9keUEucG9zaXRpb25JbXB1bHNlLnkpO1xcbiAgICAgICAgfVxcbiAgICAgICAgXFxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgcGFpcnNMZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHBhaXIgPSBwYWlyc1tpXTtcXG5cXG4gICAgICAgICAgICBpZiAoIXBhaXIuaXNBY3RpdmUgfHwgcGFpci5pc1NlbnNvcilcXG4gICAgICAgICAgICAgICAgY29udGludWU7XFxuICAgICAgICAgICAgXFxuICAgICAgICAgICAgY29sbGlzaW9uID0gcGFpci5jb2xsaXNpb247XFxuICAgICAgICAgICAgYm9keUEgPSBjb2xsaXNpb24ucGFyZW50QTtcXG4gICAgICAgICAgICBib2R5QiA9IGNvbGxpc2lvbi5wYXJlbnRCO1xcbiAgICAgICAgICAgIG5vcm1hbCA9IGNvbGxpc2lvbi5ub3JtYWw7XFxuICAgICAgICAgICAgcG9zaXRpb25JbXB1bHNlID0gcGFpci5zZXBhcmF0aW9uIC0gcGFpci5zbG9wICogc2xvcERhbXBlbjtcXG5cXG4gICAgICAgICAgICBpZiAoYm9keUEuaXNTdGF0aWMgfHwgYm9keUIuaXNTdGF0aWMpXFxuICAgICAgICAgICAgICAgIHBvc2l0aW9uSW1wdWxzZSAqPSAyO1xcbiAgICAgICAgICAgIFxcbiAgICAgICAgICAgIGlmICghKGJvZHlBLmlzU3RhdGljIHx8IGJvZHlBLmlzU2xlZXBpbmcpKSB7XFxuICAgICAgICAgICAgICAgIGNvbnRhY3RTaGFyZSA9IHBvc2l0aW9uRGFtcGVuIC8gYm9keUEudG90YWxDb250YWN0cztcXG4gICAgICAgICAgICAgICAgYm9keUEucG9zaXRpb25JbXB1bHNlLnggKz0gbm9ybWFsLnggKiBwb3NpdGlvbkltcHVsc2UgKiBjb250YWN0U2hhcmU7XFxuICAgICAgICAgICAgICAgIGJvZHlBLnBvc2l0aW9uSW1wdWxzZS55ICs9IG5vcm1hbC55ICogcG9zaXRpb25JbXB1bHNlICogY29udGFjdFNoYXJlO1xcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICBpZiAoIShib2R5Qi5pc1N0YXRpYyB8fCBib2R5Qi5pc1NsZWVwaW5nKSkge1xcbiAgICAgICAgICAgICAgICBjb250YWN0U2hhcmUgPSBwb3NpdGlvbkRhbXBlbiAvIGJvZHlCLnRvdGFsQ29udGFjdHM7XFxuICAgICAgICAgICAgICAgIGJvZHlCLnBvc2l0aW9uSW1wdWxzZS54IC09IG5vcm1hbC54ICogcG9zaXRpb25JbXB1bHNlICogY29udGFjdFNoYXJlO1xcbiAgICAgICAgICAgICAgICBib2R5Qi5wb3NpdGlvbkltcHVsc2UueSAtPSBub3JtYWwueSAqIHBvc2l0aW9uSW1wdWxzZSAqIGNvbnRhY3RTaGFyZTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBBcHBseSBwb3NpdGlvbiByZXNvbHV0aW9uLlxcbiAgICAgKiBAbWV0aG9kIHBvc3RTb2x2ZVBvc2l0aW9uXFxuICAgICAqIEBwYXJhbSB7Ym9keVtdfSBib2RpZXNcXG4gICAgICovXFxuICAgIFJlc29sdmVyLnBvc3RTb2x2ZVBvc2l0aW9uID0gZnVuY3Rpb24oYm9kaWVzKSB7XFxuICAgICAgICB2Y
2XIgcG9zaXRpb25XYXJtaW5nID0gUmVzb2x2ZXIuX3Bvc2l0aW9uV2FybWluZyxcXG4gICAgICAgICAgICBib2RpZXNMZW5ndGggPSBib2RpZXMubGVuZ3RoLFxcbiAgICAgICAgICAgIHZlcnRpY2VzVHJhbnNsYXRlID0gVmVydGljZXMudHJhbnNsYXRlLFxcbiAgICAgICAgICAgIGJvdW5kc1VwZGF0ZSA9IEJvdW5kcy51cGRhdGU7XFxuXFxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJvZGllc0xlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgdmFyIGJvZHkgPSBib2RpZXNbaV0sXFxuICAgICAgICAgICAgICAgIHBvc2l0aW9uSW1wdWxzZSA9IGJvZHkucG9zaXRpb25JbXB1bHNlLFxcbiAgICAgICAgICAgICAgICBwb3NpdGlvbkltcHVsc2VYID0gcG9zaXRpb25JbXB1bHNlLngsXFxuICAgICAgICAgICAgICAgIHBvc2l0aW9uSW1wdWxzZVkgPSBwb3NpdGlvbkltcHVsc2UueSxcXG4gICAgICAgICAgICAgICAgdmVsb2NpdHkgPSBib2R5LnZlbG9jaXR5O1xcblxcbiAgICAgICAgICAgIC8vIHJlc2V0IGNvbnRhY3QgY291bnRcXG4gICAgICAgICAgICBib2R5LnRvdGFsQ29udGFjdHMgPSAwO1xcblxcbiAgICAgICAgICAgIGlmIChwb3NpdGlvbkltcHVsc2VYICE9PSAwIHx8IHBvc2l0aW9uSW1wdWxzZVkgIT09IDApIHtcXG4gICAgICAgICAgICAgICAgLy8gdXBkYXRlIGJvZHkgZ2VvbWV0cnlcXG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBib2R5LnBhcnRzLmxlbmd0aDsgaisrKSB7XFxuICAgICAgICAgICAgICAgICAgICB2YXIgcGFydCA9IGJvZHkucGFydHNbal07XFxuICAgICAgICAgICAgICAgICAgICB2ZXJ0aWNlc1RyYW5zbGF0ZShwYXJ0LnZlcnRpY2VzLCBwb3NpdGlvbkltcHVsc2UpO1xcbiAgICAgICAgICAgICAgICAgICAgYm91bmRzVXBkYXRlKHBhcnQuYm91bmRzLCBwYXJ0LnZlcnRpY2VzLCB2ZWxvY2l0eSk7XFxuICAgICAgICAgICAgICAgICAgICBwYXJ0LnBvc2l0aW9uLnggKz0gcG9zaXRpb25JbXB1bHNlWDtcXG4gICAgICAgICAgICAgICAgICAgIHBhcnQucG9zaXRpb24ueSArPSBwb3NpdGlvbkltcHVsc2VZO1xcbiAgICAgICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgICAgIC8vIG1vdmUgdGhlIGJvZHkgd2l0aG91dCBjaGFuZ2luZyB2ZWxvY2l0eVxcbiAgICAgICAgICAgICAgICBib2R5LnBvc2l0aW9uUHJldi54ICs9IHBvc2l0aW9uSW1wdWxzZVg7XFxuICAgICAgICAgICAgICAgIGJvZHkucG9zaXRpb25QcmV2LnkgKz0gcG9zaXRpb25JbXB1bHNlWTtcXG5cXG4gICAgICAgICAgICAgICAgaWYgKHBvc2l0aW9uSW1wdWxzZVggKiB2ZWxvY2l0eS54ICsgcG9zaXRpb25JbXB1bHNlWSAqIHZlbG9jaXR5LnkgPCAwKSB7XFxuICAgICAgICAgICAgICAgICAgICAvLyByZXNldCBjYWNoZWQgaW1wdWxzZSBpZiB0aGUgYm9keSBoYXMgdmVsb2NpdHkgYWxvbmcgaXRcXG4gICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uSW1wdWxzZS54ID0gMDtcXG4gICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uSW1wdWxzZS55ID0gMDtcXG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICAgICAgICAgIC8vIHdhcm0gdGhlIG5leHQgaXRlcmF0aW9uXFxuICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbkltcHVsc2UueCAqPSBwb3NpdGlvbldhcm1pbmc7XFxuICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbkltcHVsc2UueSAqPSBwb3NpdGlvbldhcm1pbmc7XFxuICAgICAgICAgICAgICAgIH1cXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBQcmVwYXJlIHBhaXJzIGZvciB2ZWxvY2l0eSBzb2x2aW5nLlxcbiAgICAgKiBAbWV0aG9kIHByZVNvbHZlVmVsb2NpdHlcXG4gICAgICogQHBhcmFtIHtwYWlyW119IHBhaXJzXFxuICAgICAqL1xcbiAgICBSZXNvbHZlci5wcmVTb2x2ZVZlbG9jaXR5ID0gZnVuY3Rpb24ocGFpcnMpIHtcXG4gICAgICAgIHZhciBwYWlyc0xlbmd0aCA9IHBhaXJzLmxlbmd0aCxcXG4gICAgICAgICAgICBpLFxcbiAgICAgICAgICAgIGo7XFxuICAgICAgICBcXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBwYWlyc0xlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgdmFyIHBhaXIgPSBwYWlyc1tpXTtcXG4gICAgICAgICAgICBcXG4gICAgICAgICAgICBpZiAoIXBhaXIuaXNBY3RpdmUgfHwgcGFpci5pc1NlbnNvcilcXG4gICAgICAgICAgICAgICAgY29udGludWU7XFxuICAgICAgICAgICAgXFxuICAgICAgICAgICAgdmFyIGNvbnRhY3RzID0gcGFpci5hY3RpdmVDb250YWN0cyxcXG4gICAgICAgICAgICAgICAgY29udGFjdHNMZW5ndGggPSBjb250YWN0cy5sZW5ndGgsXFxuICAgICAgICAgICAgICAgIGNvbGxpc2lvbiA9IHBhaXIuY29sbGlzaW9uLFxcbiAgICAgICAgICAgICAgICBib2R5QSA9IGNvbGxpc2lvbi5wYXJlbnRBLFxcbiAgICAgICAgICAgICAgICBib2R5QiA9IGNvbGxpc2lvbi5wYXJlbnRCLFxcbiAgICAgICAgICAgICAgICBub3JtYWwgPSBjb2xsaXNpb24ubm9ybWFsLFxcbiAgICAgICAgICAgICAgICB0YW5nZW50ID0gY29sbGlzaW9uLnRhbmdlbnQ7XFxuICAgIFxcbiAgICAgICAgICAgIC8vIHJlc29sdmUgZWFjaCBjb250YWN0XFxuICAgICAgICAgICAgZm9yIChqID0gMDsgaiA8IGNvbnRhY3RzTGVuZ3RoOyBqKyspIHtcXG4gICAgICAgICAgICAgICAgdmFyIGNvbnRhY3QgPSBjb250YWN0c1tqXSxcXG4gICAgICAgICAgICAgICAgICAgIGNvbnRhY3RWZXJ0ZXggPSBjb250YWN0LnZlcnRleCxcXG4gICAgICAgICAgICAgICAgICAgIG5vcm1hbEltcHVsc2UgPSBjb250YWN0Lm5vcm1hbEltcHVsc2UsXFxuICAgICAgICAgICAgICAgICAgICB0YW5nZW50SW1wdWxzZSA9IGNvbnRhY3QudGFuZ2VudEltcHVsc2U7XFxuICAgIFxcbiAgICAgICAgICAgICAgICBpZiAobm9ybWFsSW1wdWxzZSAhPT0gMCB8fCB0YW5nZW50SW1wdWxzZSAhPT0gMCkge1xcbiAgICAgICAgICAgICAgICAgICAgLy8gdG90YWwgaW1wdWxzZSBmcm9tIGNvbnRhY3RcXG4gICAgICAgICAgICAgICAgICAgIHZhciBpbXB1bHNlWCA9IG5vcm1hbC54ICogbm9ybWFsSW1wdWxzZSArIHRhbmdlbnQueCAqIHRhbmdlbnRJbXB1bHNlLFxcbiAgICAgICAgICAgICAgICAgICAgICAgIGltcHVsc2VZID0gbm9ybWFsLnkgKiBub3JtYWxJbX
2B1bHNlICsgdGFuZ2VudC55ICogdGFuZ2VudEltcHVsc2U7XFxuICAgICAgICAgICAgICAgICAgICBcXG4gICAgICAgICAgICAgICAgICAgIC8vIGFwcGx5IGltcHVsc2UgZnJvbSBjb250YWN0XFxuICAgICAgICAgICAgICAgICAgICBpZiAoIShib2R5QS5pc1N0YXRpYyB8fCBib2R5QS5pc1NsZWVwaW5nKSkge1xcbiAgICAgICAgICAgICAgICAgICAgICAgIGJvZHlBLnBvc2l0aW9uUHJldi54ICs9IGltcHVsc2VYICogYm9keUEuaW52ZXJzZU1hc3M7XFxuICAgICAgICAgICAgICAgICAgICAgICAgYm9keUEucG9zaXRpb25QcmV2LnkgKz0gaW1wdWxzZVkgKiBib2R5QS5pbnZlcnNlTWFzcztcXG4gICAgICAgICAgICAgICAgICAgICAgICBib2R5QS5hbmdsZVByZXYgKz0gYm9keUEuaW52ZXJzZUluZXJ0aWEgKiAoXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChjb250YWN0VmVydGV4LnggLSBib2R5QS5wb3NpdGlvbi54KSAqIGltcHVsc2VZXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0gKGNvbnRhY3RWZXJ0ZXgueSAtIGJvZHlBLnBvc2l0aW9uLnkpICogaW1wdWxzZVhcXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xcbiAgICAgICAgICAgICAgICAgICAgfVxcbiAgICBcXG4gICAgICAgICAgICAgICAgICAgIGlmICghKGJvZHlCLmlzU3RhdGljIHx8IGJvZHlCLmlzU2xlZXBpbmcpKSB7XFxuICAgICAgICAgICAgICAgICAgICAgICAgYm9keUIucG9zaXRpb25QcmV2LnggLT0gaW1wdWxzZVggKiBib2R5Qi5pbnZlcnNlTWFzcztcXG4gICAgICAgICAgICAgICAgICAgICAgICBib2R5Qi5wb3NpdGlvblByZXYueSAtPSBpbXB1bHNlWSAqIGJvZHlCLmludmVyc2VNYXNzO1xcbiAgICAgICAgICAgICAgICAgICAgICAgIGJvZHlCLmFuZ2xlUHJldiAtPSBib2R5Qi5pbnZlcnNlSW5lcnRpYSAqIChcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKGNvbnRhY3RWZXJ0ZXgueCAtIGJvZHlCLnBvc2l0aW9uLngpICogaW1wdWxzZVkgXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC0gKGNvbnRhY3RWZXJ0ZXgueSAtIGJvZHlCLnBvc2l0aW9uLnkpICogaW1wdWxzZVhcXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xcbiAgICAgICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgICAgICB9XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogRmluZCBhIHNvbHV0aW9uIGZvciBwYWlyIHZlbG9jaXRpZXMuXFxuICAgICAqIEBtZXRob2Qgc29sdmVWZWxvY2l0eVxcbiAgICAgKiBAcGFyYW0ge3BhaXJbXX0gcGFpcnNcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGRlbHRhXFxuICAgICAqL1xcbiAgICBSZXNvbHZlci5zb2x2ZVZlbG9jaXR5ID0gZnVuY3Rpb24ocGFpcnMsIGRlbHRhKSB7XFxuICAgICAgICB2Y
2XIgdGltZVNjYWxlID0gZGVsdGEgLyBDb21tb24uX2Jhc2VEZWx0YSxcXG4gICAgICAgICAgICB0aW1lU2NhbGVTcXVhcmVkID0gdGltZVNjYWxlICogdGltZVNjYWxlLFxcbiAgICAgICAgICAgIHRpbWVTY2FsZUN1YmVkID0gdGltZVNjYWxlU3F1YXJlZCAqIHRpbWVTY2FsZSxcXG4gICAgICAgICAgICByZXN0aW5nVGhyZXNoID0gLVJlc29sdmVyLl9yZXN0aW5nVGhyZXNoICogdGltZVNjYWxlLFxcbiAgICAgICAgICAgIHJlc3RpbmdUaHJlc2hUYW5nZW50ID0gUmVzb2x2ZXIuX3Jlc3RpbmdUaHJlc2hUYW5nZW50LFxcbiAgICAgICAgICAgIGZyaWN0aW9uTm9ybWFsTXVsdGlwbGllciA9IFJlc29sdmVyLl9mcmljdGlvbk5vcm1hbE11bHRpcGxpZXIgKiB0aW1lU2NhbGUsXFxuICAgICAgICAgICAgZnJpY3Rpb25NYXhTdGF0aWMgPSBSZXNvbHZlci5fZnJpY3Rpb25NYXhTdGF0aWMsXFxuICAgICAgICAgICAgcGFpcnNMZW5ndGggPSBwYWlycy5sZW5ndGgsXFxuICAgICAgICAgICAgdGFuZ2VudEltcHVsc2UsXFxuICAgICAgICAgICAgbWF4RnJpY3Rpb24sXFxuICAgICAgICAgICAgaSxcXG4gICAgICAgICAgICBqO1xcblxcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IHBhaXJzTGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICB2YXIgcGFpciA9IHBhaXJzW2ldO1xcbiAgICAgICAgICAgIFxcbiAgICAgICAgICAgIGlmICghcGFpci5pc0FjdGl2ZSB8fCBwYWlyLmlzU2Vuc29yKVxcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcXG4gICAgICAgICAgICBcXG4gICAgICAgICAgICB2Y
2XIgY29sbGlzaW9uID0gcGFpci5jb2xsaXNpb24sXFxuICAgICAgICAgICAgICAgIGJvZHlBID0gY29sbGlzaW9uLnBhcmVudEEsXFxuICAgICAgICAgICAgICAgIGJvZHlCID0gY29sbGlzaW9uLnBhcmVudEIsXFxuICAgICAgICAgICAgICAgIGJvZHlBVmVsb2NpdHkgPSBib2R5QS52ZWxvY2l0eSxcXG4gICAgICAgICAgICAgICAgYm9keUJWZWxvY2l0eSA9IGJvZHlCLnZlbG9jaXR5LFxcbiAgICAgICAgICAgICAgICBub3JtYWxYID0gY29sbGlzaW9uLm5vcm1hbC54LFxcbiAgICAgICAgICAgICAgICBub3JtYWxZID0gY29sbGlzaW9uLm5vcm1hbC55LFxcbiAgICAgICAgICAgICAgICB0YW5nZW50WCA9IGNvbGxpc2lvbi50YW5nZW50LngsXFxuICAgICAgICAgICAgICAgIHRhbmdlbnRZID0gY29sbGlzaW9uLnRhbmdlbnQueSxcXG4gICAgICAgICAgICAgICAgY29udGFjdHMgPSBwYWlyLmFjdGl2ZUNvbnRhY3RzLFxcbiAgICAgICAgICAgICAgICBjb250YWN0c0xlbmd0aCA9IGNvbnRhY3RzLmxlbmd0aCxcXG4gICAgICAgICAgICAgICAgY29udGFjdFNoYXJlID0gMSAvIGNvbnRhY3RzTGVuZ3RoLFxcbiAgICAgICAgICAgICAgICBpbnZlcnNlTWFzc1RvdGFsID0gYm9keUEuaW52ZXJzZU1hc3MgKyBib2R5Qi5pbnZlcnNlTWFzcyxcXG4gICAgICAgICAgICAgICAgZnJpY3Rpb24gPSBwYWlyLmZyaWN0aW9uICogcGFpci5mcmljdGlvblN0YXRpYyAqIGZyaWN0aW9uTm9ybWFsTXVsdGlwbGllcjtcXG5cXG4gICAgICAgICAgICAvLyB1cGRhdGUgYm9keSB2ZWxvY2l0aWVzXFxuICAgICAgICAgICAgYm9keUFWZWxvY2l0eS54ID0gYm9keUEucG9zaXRpb24ueCAtIGJvZHlBLnBvc2l0aW9uUHJldi54O1xcbiAgICAgICAgICAgIGJvZHlBVmVsb2NpdHkueSA9IGJvZHlBLnBvc2l0aW9uLnkgLSBib2R5QS5wb3NpdGlvblByZXYueTtcXG4gICAgICAgICAgICBib2R5QlZlbG9jaXR5LnggPSBib2R5Qi5wb3NpdGlvbi54IC0gYm9keUIucG9zaXRpb25QcmV2Lng7XFxuICAgICAgICAgICAgYm9keUJWZWxvY2l0eS55ID0gYm9keUIucG9zaXRpb24ueSAtIGJvZHlCLnBvc2l0aW9uUHJldi55O1xcbiAgICAgICAgICAgIGJvZHlBLmFuZ3VsYXJWZWxvY2l0eSA9IGJvZHlBLmFuZ2xlIC0gYm9keUEuYW5nbGVQcmV2O1xcbiAgICAgICAgICAgIGJvZHlCLmFuZ3VsYXJWZWxvY2l0eSA9IGJvZHlCLmFuZ2xlIC0gYm9keUIuYW5nbGVQcmV2O1xcblxcbiAgICAgICAgICAgIC8vIHJlc29sdmUgZWFjaCBjb250YWN0XFxuICAgICAgICAgICAgZm9yIChqID0gMDsgaiA8IGNvbnRhY3RzTGVuZ3RoOyBqKyspIHtcXG4gICAgICAgICAgICAgICAgdmFyIGNvbnRhY3QgPSBjb250YWN0c1tqXSxcXG4gICAgICAgICAgICAgICAgICAgIGNvbnRhY3RWZXJ0ZXggPSBjb250YWN0LnZlcnRleDtcXG5cXG4gICAgICAgICAgICAgICAgdmFyIG9mZnNldEFYID0gY29udGFjdFZlcnRleC54IC0gYm9keUEucG9zaXRpb24ueCxcXG4gICAgICAgICAgICAgICAgICAgIG9mZnNldEFZID0gY29udGFjdFZlcnRleC55IC0gYm9keUEucG9zaXRpb24ueSxcXG4gICAgICAgICAgICAgICAgICAgIG9mZnNldEJYID0gY29udGFjdFZlcnRleC54IC0gYm9keUIucG9zaXRpb24ueCxcXG4gICAgICAgICAgICAgICAgICAgIG9mZnNldEJZID0gY29udGFjdFZlcnRleC55IC0gYm9keUIucG9zaXRpb24ueTtcXG4gXFxuICAgICAgICAgICAgICAgIHZhciB2ZWxvY2l0eVBvaW50QVggPSBib2R5QVZlbG9jaXR5LnggLSBvZmZzZXRBWSAqIGJvZHlBLmFuZ3VsYXJWZWxvY2l0eSxcXG4gICAgICAgICAgICAgICAgICAgIHZlbG9jaXR5UG9pbnRBWSA9IGJvZHlBVmVsb2NpdHkueSArIG9mZnNldEFYICogYm9keUEuYW5ndWxhclZlbG9jaXR5LFxcbiAgICAgICAgICAgICAgICAgICAgdmVsb2NpdHlQb2ludEJYID0gYm9keUJWZWxvY2l0eS54IC0gb2Zmc2V0QlkgKiBib2R5Qi5hbmd1bGFyVmVsb2NpdHksXFxuICAgICAgICAgICAgICAgICAgICB2ZWxvY2l0eVBvaW50QlkgPSBib2R5QlZlbG9jaXR5LnkgKyBvZmZzZXRCWCAqIGJvZHlCLmFuZ3VsYXJWZWxvY2l0eTtcXG5cXG4gICAgICAgICAgICAgICAgdmFyIHJlbGF0aXZlVmVsb2NpdHlYID0gdmVsb2NpdHlQb2ludEFYIC0gdmVsb2NpdHlQb2ludEJYLFxcbiAgICAgICAgICAgICAgICAgICAgcmVsYXRpdmVWZWxvY2l0eVkgPSB2ZWxvY2l0eVBvaW50QVkgLSB2ZWxvY2l0eVBvaW50Qlk7XFxuXFxuICAgICAgICAgICAgICAgIHZhciBub3JtYWxWZWxvY2l0eSA9IG5vcm1hbFggKiByZWxhdGl2ZVZlbG9jaXR5WCArIG5vcm1hbFkgKiByZWxhdGl2ZVZlbG9jaXR5WSxcXG4gICAgICAgICAgICAgICAgICAgIHRhbmdlbnRWZWxvY2l0eSA9IHRhbmdlbnRYICogcmVsYXRpdmVWZWxvY2l0eVggKyB0YW5nZW50WSAqIHJlbGF0aXZlVmVsb2NpdHlZO1xcblxcbiAgICAgICAgICAgICAgICAvLyBjb3Vsb21iIGZyaWN0aW9uXFxuICAgICAgICAgICAgICAgIHZhciBub3JtYWxPdmVybGFwID0gcGFpci5zZXBhcmF0aW9uICsgbm9ybWFsVmVsb2NpdHk7XFxuICAgICAgICAgICAgICAgIHZhciBub3JtYWxGb3JjZSA9IE1hdGgubWluKG5vcm1hbE92ZXJsYXAsIDEpO1xcbiAgICAgICAgICAgICAgICBub3JtYWxGb3JjZSA9IG5vcm1hbE92ZXJsYXAgPCAwID8gMCA6IG5vcm1hbEZvcmNlO1xcblxcbiAgICAgICAgICAgICAgICB2Y
2XIgZnJpY3Rpb25MaW1pdCA9IG5vcm1hbEZvcmNlICogZnJpY3Rpb247XFxuXFxuICAgICAgICAgICAgICAgIGlmICh0YW5nZW50VmVsb2NpdHkgPCAtZnJpY3Rpb25MaW1pdCB8fCB0YW5nZW50VmVsb2NpdHkgPiBmcmljdGlvbkxpbWl0KSB7XFxuICAgICAgICAgICAgICAgICAgICBtYXhGcmljdGlvbiA9ICh0YW5nZW50VmVsb2NpdHkgPiAwID8gdGFuZ2VudFZlbG9jaXR5IDogLXRhbmdlbnRWZWxvY2l0eSk7XFxuICAgICAgICAgICAgICAgICAgICB0YW5nZW50SW1wdWxzZSA9IHBhaXIuZnJpY3Rpb24gKiAodGFuZ2VudFZlbG9jaXR5ID4gMCA/IDEgOiAtMSkgKiB0aW1lU2NhbGVDdWJlZDtcXG4gICAgICAgICAgICAgICAgICAgIFxcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRhbmdlbnRJbXB1bHNlIDwgLW1heEZyaWN0aW9uKSB7XFxuICAgICAgICAgICAgICAgICAgICAgICAgdGFuZ2VudEltcHVsc2UgPSAtbWF4RnJpY3Rpb247XFxuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRhbmdlbnRJbXB1bHNlID4gbWF4RnJpY3Rpb24pIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICB0YW5nZW50SW1wdWxzZSA9IG1heEZyaWN0aW9uO1xcbiAgICAgICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgICAgICAgICAgdGFuZ2VudEltcHVsc2UgPSB0YW5nZW50VmVsb2NpdHk7XFxuICAgICAgICAgICAgICAgICAgICBtYXhGcmljdGlvbiA9IGZyaWN0aW9uTWF4U3RhdGljO1xcbiAgICAgICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgICAgIC8vIGFjY291bnQgZm9yIG1hc3MsIGluZXJ0aWEgYW5kIGNvbnRhY3Qgb2Zmc2V0XFxuICAgICAgICAgICAgICAgIHZhciBvQWNOID0gb2Zmc2V0QVggKiBub3JtYWxZIC0gb2Zmc2V0QVkgKiBub3JtYWxYLFxcbiAgICAgICAgICAgICAgICAgICAgb0JjTiA9IG9mZnNldEJYICogbm9ybWFsWSAtIG9mZnNldEJZICogbm9ybWFsWCxcXG4gICAgICAgICAgICAgICAgICAgIHNoYXJlID0gY29udGFjdFNoYXJlIC8gKGludmVyc2VNYXNzVG90YWwgKyBib2R5QS5pbnZlcnNlSW5lcnRpYSAqIG9BY04gKiBvQWNOICsgYm9keUIuaW52ZXJzZUluZXJ0aWEgKiBvQmNOICogb0JjTik7XFxuXFxuICAgICAgICAgICAgICAgIC8vIHJhdyBpbXB1bHNlc1xcbiAgICAgICAgICAgICAgICB2Y
2XIgbm9ybWFsSW1wdWxzZSA9ICgxICsgcGFpci5yZXN0aXR1dGlvbikgKiBub3JtYWxWZWxvY2l0eSAqIHNoYXJlO1xcbiAgICAgICAgICAgICAgICB0YW5nZW50SW1wdWxzZSAqPSBzaGFyZTtcXG5cXG4gICAgICAgICAgICAgICAgLy8gaGFuZGxlIGhpZ2ggdmVsb2NpdHkgYW5kIHJlc3RpbmcgY29sbGlzaW9ucyBzZXBhcmF0ZWx5XFxuICAgICAgICAgICAgICAgIGlmIChub3JtYWxWZWxvY2l0eSA8IHJlc3RpbmdUaHJlc2gpIHtcXG4gICAgICAgICAgICAgICAgICAgIC8vIGhpZ2ggbm9ybWFsIHZlbG9jaXR5IHNvIGNsZWFyIGNhY2hlZCBjb250YWN0IG5vcm1hbCBpbXB1bHNlXFxuICAgICAgICAgICAgICAgICAgICBjb250YWN0Lm5vcm1hbEltcHVsc2UgPSAwO1xcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgICAgICAgICAgLy8gc29sdmUgcmVzdGluZyBjb2xsaXNpb24gY29uc3RyYWludHMgdXNpbmcgRXJpbiBDYXR0bydzIG1ldGhvZCAoR0RDMDgpXFxuICAgICAgICAgICAgICAgICAgICAvLyBpbXB1bHNlIGNvbnN0cmFpbnQgdGVuZHMgdG8gMFxcbiAgICAgICAgICAgICAgICAgICAgdmFyIGNvbnRhY3ROb3JtYWxJbXB1bHNlID0gY29udGFjdC5ub3JtYWxJbXB1bHNlO1xcbiAgICAgICAgICAgICAgICAgICAgY29udGFjdC5ub3JtYWxJbXB1bHNlICs9IG5vcm1hbEltcHVsc2U7XFxuICAgICAgICAgICAgICAgICAgICBpZiAoY29udGFjdC5ub3JtYWxJbXB1bHNlID4gMCkgY29udGFjdC5ub3JtYWxJbXB1bHNlID0gMDtcXG4gICAgICAgICAgICAgICAgICAgIG5vcm1hbEltcHVsc2UgPSBjb250YWN0Lm5vcm1hbEltcHVsc2UgLSBjb250YWN0Tm9ybWFsSW1wdWxzZTtcXG4gICAgICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgICAgICAvLyBoYW5kbGUgaGlnaCB2ZWxvY2l0eSBhbmQgcmVzdGluZyBjb2xsaXNpb25zIHNlcGFyYXRlbHlcXG4gICAgICAgICAgICAgICAgaWYgKHRhbmdlbnRWZWxvY2l0eSA8IC1yZXN0aW5nVGhyZXNoVGFuZ2VudCB8fCB0YW5nZW50VmVsb2NpdHkgPiByZXN0aW5nVGhyZXNoVGFuZ2VudCkge1xcbiAgICAgICAgICAgICAgICAgICAgLy8gaGlnaCB0YW5nZW50IHZlbG9jaXR5IHNvIGNsZWFyIGNhY2hlZCBjb250YWN0IHRhbmdlbnQgaW1wdWxzZVxcbiAgICAgICAgICAgICAgICAgICAgY29udGFjdC50YW5nZW50SW1wdWxzZSA9IDA7XFxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgICAgICAgICAvLyBzb2x2ZSByZXN0aW5nIGNvbGxpc2lvbiBjb25zdHJhaW50cyB1c2luZyBFcmluIENhdHRvJ3MgbWV0aG9kIChHREMwOClcXG4gICAgICAgICAgICAgICAgICAgIC8vIHRhbmdlbnQgaW1wdWxzZSB0ZW5kcyB0byAtdGFuZ2VudFNwZWVkIG9yICt0YW5nZW50U3BlZWRcXG4gICAgICAgICAgICAgICAgICAgIHZhciBjb250YWN0VGFuZ2VudEltcHVsc2UgPSBjb250YWN0LnRhbmdlbnRJbXB1bHNlO1xcbiAgICAgICAgICAgICAgICAgICAgY29udGFjdC50YW5nZW50SW1wdWxzZSArPSB0YW5nZW50SW1wdWxzZTtcXG4gICAgICAgICAgICAgICAgICAgIGlmIChjb250YWN0LnRhbmdlbnRJbXB1bHNlIDwgLW1heEZyaWN0aW9uKSBjb250YWN0LnRhbmdlbnRJbXB1bHNlID0gLW1heEZyaWN0aW9uO1xcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNvbnRhY3QudGFuZ2VudEltcHVsc2UgPiBtYXhGcmljdGlvbikgY29udGFjdC50YW5nZW50SW1wdWxzZSA9IG1heEZyaWN0aW9uO1xcbiAgICAgICAgICAgICAgICAgICAgdGFuZ2VudEltcHVsc2UgPSBjb250YWN0LnRhbmdlbnRJbXB1bHNlIC0gY29udGFjdFRhbmdlbnRJbXB1bHNlO1xcbiAgICAgICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgICAgIC8vIHRvdGFsIGltcHVsc2UgZnJvbSBjb250YWN0XFxuICAgICAgICAgICAgICAgIHZhciBpbXB1bHNlWCA9IG5vcm1hbFggKiBub3JtYWxJbXB1bHNlICsgdGFuZ2VudFggKiB0YW5nZW50SW1wdWxzZSxcXG4gICAgICAgICAgICAgICAgICAgIGltcHVsc2VZID0gbm9ybWFsWSAqIG5vcm1hbEltcHVsc2UgKyB0YW5nZW50WSAqIHRhbmdlbnRJbXB1bHNlO1xcbiAgICAgICAgICAgICAgICBcXG4gICAgICAgICAgICAgICAgLy8gYXBwbHkgaW1wdWxzZSBmcm9tIGNvbnRhY3RcXG4gICAgICAgICAgICAgICAgaWYgKCEoYm9keUEuaXNTdGF0aWMgfHwgYm9keUEuaXNTbGVlcGluZykpIHtcXG4gICAgICAgICAgICAgICAgICAgIGJvZHlBLnBvc2l0aW9uUHJldi54ICs9IGltcHVsc2VYICogYm9keUEuaW52ZXJzZU1hc3M7XFxuICAgICAgICAgICAgICAgICAgICBib2R5QS5wb3NpdGlvblByZXYueSArPSBpbXB1bHNlWSAqIGJvZHlBLmludmVyc2VNYXNzO1xcbiAgICAgICAgICAgICAgICAgICAgYm9keUEuYW5nbGVQcmV2ICs9IChvZmZzZXRBWCAqIGltcHVsc2VZIC0gb2Zmc2V0QVkgKiBpbXB1bHNlWCkgKiBib2R5QS5pbnZlcnNlSW5lcnRpYTtcXG4gICAgICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgICAgICBpZiAoIShib2R5Qi5pc1N0YXRpYyB8fCBib2R5Qi5pc1NsZWVwaW5nKSkge1xcbiAgICAgICAgICAgICAgICAgICAgYm9keUIucG9zaXRpb25QcmV2LnggLT0gaW1wdWxzZVggKiBib2R5Qi5pbnZlcnNlTWFzcztcXG4gICAgICAgICAgICAgICAgICAgIGJvZHlCLnBvc2l0aW9uUHJldi55IC09IGltcHVsc2VZICogYm9keUIuaW52ZXJzZU1hc3M7XFxuICAgICAgICAgICAgICAgICAgICBib2R5Qi5hbmdsZVByZXYgLT0gKG9mZnNldEJYICogaW1wdWxzZVkgLSBvZmZzZXRCWSAqIGltcHVsc2VYKSAqIGJvZHlCLmludmVyc2VJbmVydGlhO1xcbiAgICAgICAgICAgICAgICB9XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcbiAgICB9O1xcblxcbn0pKCk7XFxuXFxuXFxuLyoqKi8gfSksXFxuLyogMTkgKi9cXG4vKioqLyAoZnVuY3Rpb24obW9kdWxlLCBleHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XFxuXFxuLyoqXFxuKiBUaGUgYE1hdHRlci5QYWlyc2AgbW9kdWxlIGNvbnRhaW5zIG1ldGhvZHMgZm9yIGNyZWF0aW5nIGFuZCBtYW5pcHVsYXRpbmcgY29sbGlzaW9uIHBhaXIgc2V0cy5cXG4qXFxuKiBAY2xhc3MgUGFpcnNcXG4qL1xcblxcbnZhciBQYWlycyA9IHt9O1xcblxcbm1vZHVsZS5leHBvcnRzID0gUGFpcnM7XFxuXFxudmFyIFBhaXIgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDkpO1xcbnZhciBDb21tb24gPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDApO1xcblxcbihmdW5jdGlvbigpIHtcXG5cXG4gICAgLyoqXFxuICAgICAqIENyZWF0ZXMgYSBuZXcgcGFpcnMgc3RydWN0dXJlLlxcbiAgICAgKiBAbWV0aG9kIGNyZWF0ZVxcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9uc1xcbiAgICAgKiBAcmV0dXJuIHtwYWlyc30gQSBuZXcgcGFpcnMgc3RydWN0dXJlXFxuICAgICAqL1xcbiAgICBQYWlycy5jcmVhdGUgPSBmdW5jdGlvbihvcHRpb25zKSB7XFxuICAgICAgICByZXR1cm4gQ29tbW9uLmV4dGVuZCh7IFxcbiAgICAgICAgICAgI
2HRhYmxlOiB7fSxcXG4gICAgICAgICAgICBsaXN0OiBbXSxcXG4gICAgICAgICAgICBjb2xsaXNpb25TdGFydDogW10sXFxuICAgICAgICAgICAgY29sbGlzaW9uQWN0aXZlOiBbXSxcXG4gICAgICAgICAgICBjb2xsaXNpb25FbmQ6IFtdXFxuICAgICAgICB9LCBvcHRpb25zKTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFVwZGF0ZXMgcGFpcnMgZ2l2ZW4gYSBsaXN0IG9mIGNvbGxpc2lvbnMuXFxuICAgICAqIEBtZXRob2QgdXBkYXRlXFxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBwYWlyc1xcbiAgICAgKiBAcGFyYW0ge2NvbGxpc2lvbltdfSBjb2xsaXNpb25zXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB0aW1lc3RhbXBcXG4gICAgICovXFxuICAgIFBhaXJzLnVwZGF0ZSA9IGZ1bmN0aW9uKHBhaXJzLCBjb2xsaXNpb25zLCB0aW1lc3RhbXApIHtcXG4gICAgICAgIHZhciBwYWlyc0xpc3QgPSBwYWlycy5saXN0LFxcbiAgICAgICAgICAgIHBhaXJzTGlzdExlbmd0aCA9IHBhaXJzTGlzdC5sZW5ndGgsXFxuICAgICAgICAgICAgcGFpcnNUYWJsZSA9IHBhaXJzLnRhYmxlLFxcbiAgICAgICAgICAgIGNvbGxpc2lvbnNMZW5ndGggPSBjb2xsaXNpb25zLmxlbmd0aCxcXG4gICAgICAgICAgICBjb2xsaXNpb25TdGFydCA9IHBhaXJzLmNvbGxpc2lvblN0YXJ0LFxcbiAgICAgICAgICAgIGNvbGxpc2lvbkVuZCA9IHBhaXJzLmNvbGxpc2lvbkVuZCxcXG4gICAgICAgICAgICBjb2xsaXNpb25BY3RpdmUgPSBwYWlycy5jb2xsaXNpb25BY3RpdmUsXFxuICAgICAgICAgICAgY29sbGlzaW9uLFxcbiAgICAgICAgICAgIHBhaXJJbmRleCxcXG4gICAgICAgICAgICBwYWlyLFxcbiAgICAgICAgICAgIGk7XFxuXFxuICAgICAgICAvLyBjbGVhciBjb2xsaXNpb24gc3RhdGUgYXJyYXlzLCBidXQgbWFpbnRhaW4gb2xkIHJlZmVyZW5jZVxcbiAgICAgICAgY29sbGlzaW9uU3RhcnQubGVuZ3RoID0gMDtcXG4gICAgICAgIGNvbGxpc2lvbkVuZC5sZW5ndGggPSAwO1xcbiAgICAgICAgY29sbGlzaW9uQWN0aXZlLmxlbmd0aCA9IDA7XFxuXFxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgcGFpcnNMaXN0TGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICBwYWlyc0xpc3RbaV0uY29uZmlybWVkQWN0aXZlID0gZmFsc2U7XFxuICAgICAgICB9XFxuXFxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgY29sbGlzaW9uc0xlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgY29sbGlzaW9uID0gY29sbGlzaW9uc1tpXTtcXG4gICAgICAgICAgICBwYWlyID0gY29sbGlzaW9uLnBhaXI7XFxuXFxuICAgICAgICAgICAgaWYgKHBhaXIpIHtcXG4gICAgICAgICAgICAgICAgLy8gcGFpciBhbHJlYWR5IGV4aXN0cyAoYnV0IG1heSBvciBtYXkgbm90IGJlIGFjdGl2ZSlcXG4gICAgICAgICAgICAgICAgaWYgKHBhaXIuaXNBY3RpdmUpIHtcXG4gICAgICAgICAgICAgICAgICAgIC8vIHBhaXIgZXhpc3RzIGFuZCBpcyBhY3RpdmVcXG4gICAgICAgICAgICAgICAgICAgIGNvbGxpc2lvbkFjdGl2ZS5wdXNoKHBhaXIpO1xcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgICAgICAgICAgLy8gcGFpciBleGlzdHMgYnV0IHdhcyBpbmFjdGl2ZSwgc28gYSBjb2xsaXNpb24gaGFzIGp1c3Qgc3RhcnRlZCBhZ2FpblxcbiAgICAgICAgICAgICAgICAgICAgY29sbGlzaW9uU3RhcnQucHVzaChwYWlyKTtcXG4gICAgICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgICAgICAvLyB1cGRhdGUgdGhlIHBhaXJcXG4gICAgICAgICAgICAgICAgUGFpci51cGRhdGUocGFpciwgY29sbGlzaW9uLCB0aW1lc3RhbXApO1xcbiAgICAgICAgICAgICAgICBwYWlyLmNvbmZpcm1lZEFjdGl2ZSA9IHRydWU7XFxuICAgICAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICAgICAgLy8gcGFpciBkaWQgbm90IGV4aXN0LCBjcmVhdGUgYSBuZXcgcGFpclxcbiAgICAgICAgICAgICAgICBwYWlyID0gUGFpci5jcmVhdGUoY29sbGlzaW9uLCB0aW1lc3RhbXApO1xcbiAgICAgICAgICAgICAgICBwYWlyc1RhYmxlW3BhaXIuaWRdID0gcGFpcjtcXG5cXG4gICAgICAgICAgICAgICAgLy8gcHVzaCB0aGUgbmV3IHBhaXJcXG4gICAgICAgICAgICAgICAgY29sbGlzaW9uU3RhcnQucHVzaChwYWlyKTtcXG4gICAgICAgICAgICAgICAgcGFpcnNMaXN0LnB1c2gocGFpcik7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcblxcbiAgICAgICAgLy8gZmluZCBwYWlycyB0aGF0IGFyZSBubyBsb25nZXIgYWN0aXZlXFxuICAgICAgICB2Y
2XIgcmVtb3ZlUGFpckluZGV4ID0gW107XFxuICAgICAgICBwYWlyc0xpc3RMZW5ndGggPSBwYWlyc0xpc3QubGVuZ3RoO1xcblxcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IHBhaXJzTGlzdExlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgcGFpciA9IHBhaXJzTGlzdFtpXTtcXG4gICAgICAgICAgICBcXG4gICAgICAgICAgICBpZiAoIXBhaXIuY29uZmlybWVkQWN0aXZlKSB7XFxuICAgICAgICAgICAgICAgIFBhaXIuc2V0QWN0aXZlKHBhaXIsIGZhbHNlLCB0aW1lc3RhbXApO1xcbiAgICAgICAgICAgICAgICBjb2xsaXNpb25FbmQucHVzaChwYWlyKTtcXG5cXG4gICAgICAgICAgICAgICAgaWYgKCFwYWlyLmNvbGxpc2lvbi5ib2R5QS5pc1NsZWVwaW5nICYmICFwYWlyLmNvbGxpc2lvbi5ib2R5Qi5pc1NsZWVwaW5nKSB7XFxuICAgICAgICAgICAgICAgICAgICByZW1vdmVQYWlySW5kZXgucHVzaChpKTtcXG4gICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG5cXG4gICAgICAgIC8vIHJlbW92ZSBpbmFjdGl2ZSBwYWlyc1xcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IHJlbW92ZVBhaXJJbmRleC5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHBhaXJJbmRleCA9IHJlbW92ZVBhaXJJbmRleFtpXSAtIGk7XFxuICAgICAgICAgICAgcGFpciA9IHBhaXJzTGlzdFtwYWlySW5kZXhdO1xcbiAgICAgICAgICAgIHBhaXJzTGlzdC5zcGxpY2UocGFpckluZGV4LCAxKTtcXG4gICAgICAgICAgICBkZWxldGUgcGFpcnNUYWJsZVtwYWlyLmlkXTtcXG4gICAgICAgIH1cXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIENsZWFycyB0aGUgZ2l2ZW4gcGFpcnMgc3RydWN0dXJlLlxcbiAgICAgKiBAbWV0aG9kIGNsZWFyXFxuICAgICAqIEBwYXJhbSB7cGFpcnN9IHBhaXJzXFxuICAgICAqIEByZXR1cm4ge3BhaXJzfSBwYWlyc1xcbiAgICAgKi9cXG4gICAgUGFpcnMuY2xlYXIgPSBmdW5jdGlvbihwYWlycykge1xcbiAgICAgICAgcGFpcnMudGFibGUgPSB7fTtcXG4gICAgICAgIHBhaXJzLmxpc3QubGVuZ3RoID0gMDtcXG4gICAgICAgIHBhaXJzLmNvbGxpc2lvblN0YXJ0Lmxlbmd0aCA9IDA7XFxuICAgICAgICBwYWlycy5jb2xsaXNpb25BY3RpdmUubGVuZ3RoID0gMDtcXG4gICAgICAgIHBhaXJzLmNvbGxpc2lvbkVuZC5sZW5ndGggPSAwO1xcbiAgICAgICAgcmV0dXJuIHBhaXJzO1xcbiAgICB9O1xcblxcbn0pKCk7XFxuXFxuXFxuLyoqKi8gfSksXFxuLyogMjAgKi9cXG4vKioqLyAoZnVuY3Rpb24obW9kdWxlLCBleHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XFxuXFxudmFyIE1hdHRlciA9IG1vZHVsZS5leHBvcnRzID0gX193ZWJwYWNrX3JlcXVpcmVfXygyMSk7XFxyXFxuXFxyXFxuTWF0dGVyLkF4ZXMgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDExKTtcXHJcXG5NYXR0ZXIuQm9kaWVzID0gX193ZWJwYWNrX3JlcXVpcmVfXygxMik7XFxyXFxuTWF0dGVyLkJvZHkgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDQpO1xcclxcbk1hdHRlci5Cb3VuZHMgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDEpO1xcclxcbk1hdHRlci5Db2xsaXNpb24gPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDgpO1xcclxcbk1hdHRlci5Db21tb24gPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDApO1xcclxcbk1hdHRlci5Db21wb3NpdGUgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDYpO1xcclxcbk1hdHRlci5Db21wb3NpdGVzID0gX193ZWJwYWNrX3JlcXVpcmVfXygyMik7XFxyXFxuTWF0dGVyLkNvbnN0cmFpbnQgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDEwKTtcXHJcXG5NYXR0ZXIuQ29udGFjdCA9IF9fd2VicGFja19yZXF1aXJlX18oMTYpO1xcclxcbk1hdHRlci5EZXRlY3RvciA9IF9fd2VicGFja19yZXF1aXJlX18oMTMpO1xcclxcbk1hdHRlci5FbmdpbmUgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDE3KTtcXHJcXG5NYXR0ZXIuRXZlbnRzID0gX193ZWJwYWNrX3JlcXVpcmVfXyg1KTtcXHJcXG5NYXR0ZXIuR3JpZCA9IF9fd2VicGFja19yZXF1aXJlX18oMjMpO1xcclxcbk1hdHRlci5Nb3VzZSA9IF9fd2VicGFja19yZXF1aXJlX18oMTQpO1xcclxcbk1hdHRlci5Nb3VzZUNvbnN0cmFpbnQgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDI0KTtcXHJcXG5NYXR0ZXIuUGFpciA9IF9fd2VicGFja19yZXF1aXJlX18oOSk7XFxyXFxuTWF0dGVyLlBhaXJzID0gX193ZWJwYWNrX3JlcXVpcmVfXygxOSk7XFxyXFxuTWF0dGVyLlBsdWdpbiA9IF9fd2VicGFja19yZXF1aXJlX18oMTUpO1xcclxcbk1hdHRlci5RdWVyeSA9IF9fd2VicGFja19yZXF1aXJlX18oMjUpO1xcclxcbk1hdHRlci5SZW5kZXIgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDI2KTtcXHJcXG5NYXR0ZXIuUmVzb2x2ZXIgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDE4KTtcXHJcXG5NYXR0ZXIuUnVubmVyID0gX193ZWJwYWNrX3JlcXVpcmVfXygyNyk7XFxyXFxuTWF0dGVyLlNBVCA9IF9fd2VicGFja19yZXF1aXJlX18oMjgpO1xcclxcbk1hdHRlci5TbGVlcGluZyA9IF9fd2VicGFja19yZXF1aXJlX18oNyk7XFxyXFxuTWF0dGVyLlN2ZyA9IF9fd2VicGFja19yZXF1aXJlX18oMjkpO1xcclxcbk1hdHRlci5WZWN0b3IgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDIpO1xcclxcbk1hdHRlci5WZXJ0aWNlcyA9IF9fd2VicGFja19yZXF1aXJlX18oMyk7XFxyXFxuTWF0dGVyLldvcmxkID0gX193ZWJwYWNrX3JlcXVpcmVfXygzMCk7XFxyXFxuXFxyXFxuLy8gdGVtcG9yYXJ5IGJhY2sgY29tcGF0aWJpbGl0eVxcclxcbk1hdHRlci5FbmdpbmUucnVuID0gTWF0dGVyLlJ1bm5lci5ydW47XFxyXFxuTWF0dGVyLkNvbW1vbi5kZXByZWNhdGVkKE1hdHRlci5FbmdpbmUsICdydW4nLCAnRW5naW5lLnJ1biDinqQgdXNlIE1hdHRlci5SdW5uZXIucnVuKGVuZ2luZSkgaW5zdGVhZCcpO1xcclxcblxcblxcbi8qKiovIH0pLFxcbi8qIDIxICovXFxuLyoqKi8gKGZ1bmN0aW9uKG1vZHVsZSwgZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xcblxcbi8qKlxcclxcbiogVGhlIGBNYXR0ZXJgIG1vZHVsZSBpcyB0aGUgdG9wIGxldmVsIG5hbWVzcGFjZS4gSXQgYWxzbyBpbmNsdWRlcyBhIGZ1bmN0aW9uIGZvciBpbnN0YWxsaW5nIHBsdWdpbnMgb24gdG9wIG9mIHRoZSBsaWJyYXJ5LlxcclxcbipcXHJcXG4qIEBjbGFzcyBNYXR0ZXJcXHJcXG4qL1xcclxcblxcclxcbnZhciBNYXR0ZXIgPSB7fTtcXHJcXG5cXHJcXG5tb2R1bGUuZXhwb3J0cyA9IE1hdHRlcjtcXHJcXG5cXHJcXG52YXIgUGx1Z2luID0gX193ZWJwYWNrX3JlcXVpcmVfXygxNSk7XFxyXFxudmFyIENvbW1vbiA9IF9fd2VicGFja19yZXF1aXJlX18oMCk7XFxyXFxuXFxyXFxuKGZ1bmN0aW9uKCkge1xcclxcblxcclxcbiAgICAvKipcXHJcXG4gICAgICogVGhlIGxpYnJhcnkgbmFtZS5cXHJcXG4gICAgICogQHByb3BlcnR5IG5hbWVcXHJcXG4gICAgICogQHJlYWRPbmx5XFxyXFxuICAgICAqIEB0eXBlIHtTdHJpbmd9XFxyXFxuICAgICAqL1xcclxcbiAgICBNYXR0ZXIubmFtZSA9ICdtY
2XR0ZXItanMnO1xcclxcblxcclxcbiAgICAvKipcXHJcXG4gICAgICogVGhlIGxpYnJhcnkgdmVyc2lvbi5cXHJcXG4gICAgICogQHByb3BlcnR5IHZlcnNpb25cXHJcXG4gICAgICogQHJlYWRPbmx5XFxyXFxuICAgICAqIEB0eXBlIHtTdHJpbmd9XFxyXFxuICAgICAqL1xcclxcbiAgICBNYXR0ZXIudmVyc2lvbiA9ICB0cnVlID8gXFxcIjAuMTkuMFxcXCIgOiB1bmRlZmluZWQ7XFxyXFxuXFxyXFxuICAgIC8qKlxcclxcbiAgICAgKiBBIGxpc3Qgb2YgcGx1Z2luIGRlcGVuZGVuY2llcyB0byBiZSBpbnN0YWxsZWQuIFRoZXNlIGFyZSBub3JtYWxseSBzZXQgYW5kIGluc3RhbGxlZCB0aHJvdWdoIGBNYXR0ZXIudXNlYC5cXHJcXG4gICAgICogQWx0ZXJuYXRpdmVseSB5b3UgbWF5IHNldCBgTWF0dGVyLnVzZXNgIG1hbnVhbGx5IGFuZCBpbnN0YWxsIHRoZW0gYnkgY2FsbGluZyBgUGx1Z2luLnVzZShNYXR0ZXIpYC5cXHJcXG4gICAgICogQHByb3BlcnR5IHVzZXNcXHJcXG4gICAgICogQHR5cGUge0FycmF5fVxcclxcbiAgICAgKi9cXHJcXG4gICAgTWF0dGVyLnVzZXMgPSBbXTtcXHJcXG5cXHJcXG4gICAgLyoqXFxyXFxuICAgICAqIFRoZSBwbHVnaW5zIHRoYXQgaGF2ZSBiZWVuIGluc3RhbGxlZCB0aHJvdWdoIGBNYXR0ZXIuUGx1Z2luLmluc3RhbGxgLiBSZWFkIG9ubHkuXFxyXFxuICAgICAqIEBwcm9wZXJ0eSB1c2VkXFxyXFxuICAgICAqIEByZWFkT25seVxcclxcbiAgICAgKiBAdHlwZSB7QXJyYXl9XFxyXFxuICAgICAqL1xcclxcbiAgICBNYXR0ZXIudXNlZCA9IFtdO1xcclxcblxcclxcbiAgICAvKipcXHJcXG4gICAgICogSW5zdGFsbHMgdGhlIGdpdmVuIHBsdWdpbnMgb24gdGhlIGBNYXR0ZXJgIG5hbWVzcGFjZS5cXHJcXG4gICAgICogVGhpcyBpcyBhIHNob3J0LWhhbmQgZm9yIGBQbHVnaW4udXNlYCwgc2VlIGl0IGZvciBtb3JlIGluZm9ybWF0aW9uLlxcclxcbiAgICAgKiBDYWxsIHRoaXMgZnVuY3Rpb24gb25jZSBhdCB0aGUgc3RhcnQgb2YgeW91ciBjb2RlLCB3aXRoIGFsbCBvZiB0aGUgcGx1Z2lucyB5b3Ugd2lzaCB0byBpbnN0YWxsIGFzIGFyZ3VtZW50cy5cXHJcXG4gICAgICogQXZvaWQgY2FsbGluZyB0aGlzIGZ1bmN0aW9uIG11bHRpcGxlIHRpbWVzIHVubGVzcyB5b3UgaW50ZW5kIHRvIG1hbnVhbGx5IGNvbnRyb2wgaW5zdGFsbGF0aW9uIG9yZGVyLlxcclxcbiAgICAgKiBAbWV0aG9kIHVzZVxcclxcbiAgICAgKiBAcGFyYW0gLi4ucGx1Z2luIHtGdW5jdGlvbn0gVGhlIHBsdWdpbihzKSB0byBpbnN0YWxsIG9uIGBiYXNlYCAobXVsdGktYXJndW1lbnQpLlxcclxcbiAgICAgKi9cXHJcXG4gICAgTWF0dGVyLnVzZSA9IGZ1bmN0aW9uKCkge1xcclxcbiAgICAgICAgUGx1Z2luLnVzZShNYXR0ZXIsIEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cykpO1xcclxcbiAgICB9O1xcclxcblxcclxcbiAgICAvKipcXHJcXG4gICAgICogQ2hhaW5zIGEgZnVuY3Rpb24gdG8gZXhjdXRlIGJlZm9yZSB0aGUgb3JpZ2luYWwgZnVuY3Rpb24gb24gdGhlIGdpdmVuIGBwYXRoYCByZWxhdGl2ZSB0byBgTWF0dGVyYC5cXHJcXG4gICAgICogU2VlIGFsc28gZG9jcyBmb3IgYENvbW1vbi5jaGFpbmAuXFxyXFxuICAgICAqIEBtZXRob2QgYmVmb3JlXFxyXFxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIFRoZSBwYXRoIHJlbGF0aXZlIHRvIGBNYXR0ZXJgXFxyXFxuICAgICAqIEBwYXJhbSB7ZnVuY3Rpb259IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIGNoYWluIGJlZm9yZSB0aGUgb3JpZ2luYWxcXHJcXG4gICAgICogQHJldHVybiB7ZnVuY3Rpb259IFRoZSBjaGFpbmVkIGZ1bmN0aW9uIHRoYXQgcmVwbGFjZWQgdGhlIG9yaWdpbmFsXFxyXFxuICAgICAqL1xcclxcbiAgICBNYXR0ZXIuYmVmb3JlID0gZnVuY3Rpb24ocGF0aCwgZnVuYykge1xcclxcbiAgICAgICAgcGF0aCA9IHBhdGgucmVwbGFjZSgvXk1hdHRlci4vLCAnJyk7XFxyXFxuICAgICAgICByZXR1cm4gQ29tbW9uLmNoYWluUGF0aEJlZm9yZShNYXR0ZXIsIHBhdGgsIGZ1bmMpO1xcclxcbiAgICB9O1xcclxcblxcclxcbiAgICAvKipcXHJcXG4gICAgICogQ2hhaW5zIGEgZnVuY3Rpb24gdG8gZXhjdXRlIGFmdGVyIHRoZSBvcmlnaW5hbCBmdW5jdGlvbiBvbiB0aGUgZ2l2ZW4gYHBhdGhgIHJlbGF0aXZlIHRvIGBNYXR0ZXJgLlxcclxcbiAgICAgKiBTZWUgYWxzbyBkb2NzIGZvciBgQ29tbW9uLmNoYWluYC5cXHJcXG4gICAgICogQG1ldGhvZCBhZnRlclxcclxcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gcGF0aCBUaGUgcGF0aCByZWxhdGl2ZSB0byBgTWF0dGVyYFxcclxcbiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBmdW5jIFRoZSBmdW5jdGlvbiB0byBjaGFpbiBhZnRlciB0aGUgb3JpZ2luYWxcXHJcXG4gICAgICogQHJldHVybiB7ZnVuY3Rpb259IFRoZSBjaGFpbmVkIGZ1bmN0aW9uIHRoYXQgcmVwbGFjZWQgdGhlIG9yaWdpbmFsXFxyXFxuICAgICAqL1xcclxcbiAgICBNYXR0ZXIuYWZ0ZXIgPSBmdW5jdGlvbihwYXRoLCBmdW5jKSB7XFxyXFxuICAgICAgICBwYXRoID0gcGF0aC5yZXBsYWNlKC9eTWF0dGVyLi8sICcnKTtcXHJcXG4gICAgICAgIHJldHVybiBDb21tb24uY2hhaW5QYXRoQWZ0ZXIoTWF0dGVyLCBwYXRoLCBmdW5jKTtcXHJcXG4gICAgfTtcXHJcXG5cXHJcXG59KSgpO1xcclxcblxcblxcbi8qKiovIH0pLFxcbi8qIDIyICovXFxuLyoqKi8gKGZ1bmN0aW9uKG1vZHVsZSwgZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xcblxcbi8qKlxcbiogVGhlIGBNYXR0ZXIuQ29tcG9zaXRlc2AgbW9kdWxlIGNvbnRhaW5zIGZhY3RvcnkgbWV0aG9kcyBmb3IgY3JlYXRpbmcgY29tcG9zaXRlIGJvZGllc1xcbiogd2l0aCBjb21tb25seSB1c2VkIGNvbmZpZ3VyYXRpb25zIChzdWNoIGFzIHN0YWNrcyBhbmQgY2hhaW5zKS5cXG4qXFxuKiBTZWUgdGhlIGluY2x1ZGVkIHVzYWdlIFtleGFtcGxlc10oaHR0cHM6Ly9naXRodWIuY29tL2xpYWJydS9tYXR0ZXItanMvdHJlZS9tYXN0ZXIvZXhhbXBsZXMpLlxcbipcXG4qIEBjbGFzcyBDb21wb3NpdGVzXFxuKi9cXG5cXG52YXIgQ29tcG9zaXRlcyA9IHt9O1xcblxcbm1vZHVsZS5leHBvcnRzID0gQ29tcG9zaXRlcztcXG5cXG52YXIgQ29tcG9zaXRlID0gX193ZWJwYWNrX3JlcXVpcmVfXyg2KTtcXG52YXIgQ29uc3RyYWludCA9IF9fd2VicGFja19yZXF1aXJlX18oMTApO1xcbnZhciBDb21tb24gPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDApO1xcbnZhciBCb2R5ID0gX193ZWJwYWNrX3JlcXVpcmVfXyg0KTtcXG52YXIgQm9kaWVzID0gX193ZWJwYWNrX3JlcXVpcmVfXygxMik7XFxudmFyIGRlcHJlY2F0ZWQgPSBDb21tb24uZGVwcmVjYXRlZDtcXG5cXG4oZnVuY3Rpb24oKSB7XFxuXFxuICAgIC8qKlxcbiAgICAgKiBDcmVhdGUgYSBuZXcgY29tcG9zaXRlIGNvbnRhaW5pbmcgYm9k
2aWVzIGNyZWF0ZWQgaW4gdGhlIGNhbGxiYWNrIGluIGEgZ3JpZCBhcnJhbmdlbWVudC5cXG4gICAgICogVGhpcyBmdW5jdGlvbiB1c2VzIHRoZSBib2R5J3MgYm91bmRzIHRvIHByZXZlbnQgb3ZlcmxhcHMuXFxuICAgICAqIEBtZXRob2Qgc3RhY2tcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHh4XFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB5eVxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gY29sdW1uc1xcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gcm93c1xcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gY29sdW1uR2FwXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSByb3dHYXBcXG4gICAgICogQHBhcmFtIHtmdW5jdGlvbn0gY2FsbGJhY2tcXG4gICAgICogQHJldHVybiB7Y29tcG9zaXRlfSBBIG5ldyBjb21wb3NpdGUgY29udGFpbmluZyBvYmplY3RzIGNyZWF0ZWQgaW4gdGhlIGNhbGxiYWNrXFxuICAgICAqL1xcbiAgICBDb21wb3NpdGVzLnN0YWNrID0gZnVuY3Rpb24oeHgsIHl5LCBjb2x1bW5zLCByb3dzLCBjb2x1bW5HYXAsIHJvd0dhcCwgY2FsbGJhY2spIHtcXG4gICAgICAgIHZhciBzdGFjayA9IENvbXBvc2l0ZS5jcmVhdGUoeyBsYWJlbDogJ1N0YWNrJyB9KSxcXG4gICAgICAgICAgICB4ID0geHgsXFxuICAgICAgICAgICAgeSA9IHl5LFxcbiAgICAgICAgICAgIGxhc3RCb2R5LFxcbiAgICAgICAgICAgIGkgPSAwO1xcblxcbiAgICAgICAgZm9yICh2YXIgcm93ID0gMDsgcm93IDwgcm93czsgcm93KyspIHtcXG4gICAgICAgICAgICB2YXIgbWF4SGVpZ2h0ID0gMDtcXG4gICAgICAgICAgICBcXG4gICAgICAgICAgICBmb3IgKHZhciBjb2x1bW4gPSAwOyBjb2x1bW4gPCBjb2x1bW5zOyBjb2x1bW4rKykge1xcbiAgICAgICAgICAgICAgICB2Y
2XIgYm9keSA9IGNhbGxiYWNrKHgsIHksIGNvbHVtbiwgcm93LCBsYXN0Qm9keSwgaSk7XFxuICAgICAgICAgICAgICAgICAgICBcXG4gICAgICAgICAgICAgICAgaWYgKGJvZHkpIHtcXG4gICAgICAgICAgICAgICAgICAgIHZhciBib2R5SGVpZ2h0ID0gYm9keS5ib3VuZHMubWF4LnkgLSBib2R5LmJvdW5kcy5taW4ueSxcXG4gICAgICAgICAgICAgICAgICAgICAgICBib2R5V2lkdGggPSBib2R5LmJvdW5kcy5tYXgueCAtIGJvZHkuYm91bmRzLm1pbi54OyBcXG5cXG4gICAgICAgICAgICAgICAgICAgIGlmIChib2R5SGVpZ2h0ID4gbWF4SGVpZ2h0KVxcbiAgICAgICAgICAgICAgICAgICAgICAgIG1heEhlaWdodCA9IGJvZHlIZWlnaHQ7XFxuICAgICAgICAgICAgICAgICAgICBcXG4gICAgICAgICAgICAgICAgICAgIEJvZHkudHJhbnNsYXRlKGJvZHksIHsgeDogYm9keVdpZHRoICogMC41LCB5OiBib2R5SGVpZ2h0ICogMC41IH0pO1xcblxcbiAgICAgICAgICAgICAgICAgICAgeCA9IGJvZHkuYm91bmRzLm1heC54ICsgY29sdW1uR2FwO1xcblxcbiAgICAgICAgICAgICAgICAgICAgQ29tcG9zaXRlLmFkZEJvZHkoc3RhY2ssIGJvZHkpO1xcbiAgICAgICAgICAgICAgICAgICAgXFxuICAgICAgICAgICAgICAgICAgICBsYXN0Qm9keSA9IGJvZHk7XFxuICAgICAgICAgICAgICAgICAgICBpICs9IDE7XFxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgICAgICAgICB4ICs9IGNvbHVtbkdhcDtcXG4gICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgIH1cXG4gICAgICAgICAgICBcXG4gICAgICAgICAgICB5ICs9IG1heEhlaWdodCArIHJvd0dhcDtcXG4gICAgICAgICAgICB4ID0geHg7XFxuICAgICAgICB9XFxuXFxuICAgICAgICByZXR1cm4gc3RhY2s7XFxuICAgIH07XFxuICAgIFxcbiAgICAvKipcXG4gICAgICogQ2hhaW5zIGFsbCBib2RpZXMgaW4gdGhlIGdpdmVuIGNvbXBvc2l0ZSB0b2dldGhlciB1c2luZyBjb25zdHJhaW50cy5cXG4gICAgICogQG1ldGhvZCBjaGFpblxcbiAgICAgKiBAcGFyYW0ge2NvbXBvc2l0ZX0gY29tcG9zaXRlXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB4T2Zmc2V0QVxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0geU9mZnNldEFcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHhPZmZzZXRCXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB5T2Zmc2V0QlxcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9uc1xcbiAgICAgKiBAcmV0dXJuIHtjb21wb3NpdGV9IEEgbmV3IGNvbXBvc2l0ZSBjb250YWluaW5nIG9iamVjdHMgY2hhaW5lZCB0b2dldGhlciB3aXRoIGNvbnN0cmFpbnRzXFxuICAgICAqL1xcbiAgICBDb21wb3NpdGVzLmNoYWluID0gZnVuY3Rpb24oY29tcG9zaXRlLCB4T2Zmc2V0QSwgeU9mZnNldEEsIHhPZmZzZXRCLCB5T2Zmc2V0Qiwgb3B0aW9ucykge1xcbiAgICAgICAgdmFyIGJvZGllcyA9IGNvbXBvc2l0ZS5ib2RpZXM7XFxuICAgICAgICBcXG4gICAgICAgIGZvciAodmFyIGkgPSAxOyBpIDwgYm9kaWVzLmxlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgdmFyIGJvZHlBID0gYm9kaWVzW2kgLSAxXSxcXG4gICAgICAgICAgICAgICAgYm9keUIgPSBib2RpZXNbaV0sXFxuICAgICAgICAgICAgICAgIGJvZHlBSGVpZ2h0ID0gYm9keUEuYm91bmRzLm1heC55IC0gYm9keUEuYm91bmRzLm1pbi55LFxcbiAgICAgICAgICAgICAgICBib2R5QVdpZHRoID0gYm9keUEuYm91bmRzLm1heC54IC0gYm9keUEuYm91bmRzLm1pbi54LCBcXG4gICAgICAgICAgICAgICAgYm9keUJIZWlnaHQgPSBib2R5Qi5ib3VuZHMubWF4LnkgLSBib2R5Qi5ib3VuZHMubWluLnksXFxuICAgICAgICAgICAgICAgIGJvZHlCV2lkdGggPSBib2R5Qi5ib3VuZHMubWF4LnggLSBib2R5Qi5ib3VuZHMubWluLng7XFxuICAgICAgICBcXG4gICAgICAgICAgICB2Y
2XIgZGVmYXVsdHMgPSB7XFxuICAgICAgICAgICAgICAgIGJvZHlBOiBib2R5QSxcXG4gICAgICAgICAgICAgICAgcG9pbnRBOiB7IHg6IGJvZHlBV2lkdGggKiB4T2Zmc2V0QSwgeTogYm9keUFIZWlnaHQgKiB5T2Zmc2V0QSB9LFxcbiAgICAgICAgICAgICAgICBib2R5QjogYm9keUIsXFxuICAgICAgICAgICAgICAgIHBvaW50QjogeyB4OiBib2R5QldpZHRoICogeE9mZnNldEIsIHk6IGJvZHlCSGVpZ2h0ICogeU9mZnNldEIgfVxcbiAgICAgICAgICAgIH07XFxuICAgICAgICAgICAgXFxuICAgICAgICAgICAgdmFyIGNvbnN0cmFpbnQgPSBDb21tb24uZXh0ZW5kKGRlZmF1bHRzLCBvcHRpb25zKTtcXG4gICAgICAgIFxcbiAgICAgICAgICAgIENvbXBvc2l0ZS5hZGRDb25zdHJhaW50KGNvbXBvc2l0ZSwgQ29uc3RyYWludC5jcmVhdGUoY29uc3RyYWludCkpO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgY29tcG9zaXRlLmxhYmVsICs9ICcgQ2hhaW4nO1xcbiAgICAgICAgXFxuICAgICAgICByZXR1cm4gY29tcG9zaXRlO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogQ29ubmVjdHMgYm9kaWVzIGluIHRoZSBjb21wb3NpdGUgd2l0aCBjb25zdHJhaW50cyBpbiBhIGdyaWQgcGF0dGVybiwgd2l0aCBvcHRpb25hbCBjcm9zcyBicmFjZXMuXFxuICAgICAqIEBtZXRob2QgbWVzaFxcbiAgICAgKiBAcGFyYW0ge2NvbXBvc2l0ZX0gY29tcG9zaXRlXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBjb2x1bW5zXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSByb3dzXFxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gY3Jvc3NCcmFjZVxcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9uc1xcbiAgICAgKiBAcmV0dXJuIHtjb21wb3NpdGV9IFRoZSBjb21wb3NpdGUgY29udGFpbmluZyBvYmplY3RzIG1lc2hlZCB0b2dldGhlciB3aXRoIGNvbnN0cmFpbnRzXFxuICAgICAqL1xcbiAgICBDb21wb3NpdGVzLm1lc2ggPSBmdW5jdGlvbihjb21wb3NpdGUsIGNvbHVtbnMsIHJvd3MsIGNyb3NzQnJhY2UsIG9wdGlvbnMpIHtcXG4gICAgICAgIHZhciBib2RpZXMgPSBjb21wb3NpdGUuYm9kaWVzLFxcbiAgICAgICAgICAgIHJvdyxcXG4gICAgICAgICAgICBjb2wsXFxuICAgICAgICAgICAgYm9keUEsXFxuICAgICAgICAgICAgYm9keUIsXFxuICAgICAgICAgICAgYm9keUM7XFxuICAgICAgICBcXG4gICAgICAgIGZvciAocm93ID0gMDsgcm93IDwgcm93czsgcm93KyspIHtcXG4gICAgICAgICAgICBmb3IgKGNvbCA9IDE7IGNvbCA8IGNvbHVtbnM7IGNvbCsrKSB7XFxuICAgICAgICAgICAgICAgIGJvZHlBID0gYm9kaWVzWyhjb2wgLSAxKSArIChyb3cgKiBjb2x1bW5zKV07XFxuICAgICAgICAgICAgICAgIGJvZHlCID0gYm9kaWVzW2NvbCArIChyb3cgKiBjb2x1bW5zKV07XFxuICAgICAgICAgICAgICAgIENvbXBvc2l0ZS5hZGRDb25zdHJhaW50KGNvbXBvc2l0ZSwgQ29uc3RyYWludC5jcmVhdGUoQ29tbW9uLmV4dGVuZCh7IGJvZHlBOiBib2R5QSwgYm9keUI6IGJvZHlCIH0sIG9wdGlvbnMpKSk7XFxuICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgIGlmIChyb3cgPiAwKSB7XFxuICAgICAgICAgICAgICAgIGZvciAoY29sID0gMDsgY29sIDwgY29sdW1uczsgY29sKyspIHtcXG4gICAgICAgICAgICAgICAgICAgIGJvZHlBID0gYm9kaWVzW2NvbCArICgocm93IC0gMSkgKiBjb2x1bW5zKV07XFxuICAgICAgICAgICAgICAgICAgICBib2R5QiA9IGJvZGllc1tjb2wgKyAocm93ICogY29sdW1ucyldO1xcbiAgICAgICAgICAgICAgICAgICAgQ29tcG9zaXRlLmFkZENvbnN0cmFpbnQoY29tcG9zaXRlLCBDb25zdHJhaW50LmNyZWF0ZShDb21tb24uZXh0ZW5kKHsgYm9keUE6IGJvZHlBLCBib2R5QjogYm9keUIgfSwgb3B0aW9ucykpKTtcXG5cXG4gICAgICAgICAgICAgICAgICAgIGlmIChjcm9zc0JyYWNlICYmIGNvbCA+IDApIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICBib2R5QyA9IGJvZGllc1soY29sIC0gMSkgKyAoKHJvdyAtIDEpICogY29sdW1ucyldO1xcbiAgICAgICAgICAgICAgICAgICAgICAgIENvbXBvc2l0ZS5hZGRDb25zdHJhaW50KGNvbXBvc2l0ZSwgQ29uc3RyYWludC5jcmVhdGUoQ29tbW9uLmV4dGVuZCh7IGJvZHlBOiBib2R5QywgYm9keUI6IGJvZHlCIH0sIG9wdGlvbnMpKSk7XFxuICAgICAgICAgICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgICAgICAgICBpZiAoY3Jvc3NCcmFjZSAmJiBjb2wgPCBjb2x1bW5zIC0gMSkge1xcbiAgICAgICAgICAgICAgICAgICAgICAgIGJvZHlDID0gYm9kaWVzWyhjb2wgKyAxKSArICgocm93IC0gMSkgKiBjb2x1bW5zKV07XFxuICAgICAgICAgICAgICAgICAgICAgICAgQ29tcG9zaXRlLmFkZENvbnN0cmFpbnQoY29tcG9zaXRlLCBDb25zdHJhaW50LmNyZWF0ZShDb21tb24uZXh0ZW5kKHsgYm9keUE6IGJvZHlDLCBib2R5QjogYm9keUIgfSwgb3B0aW9ucykpKTtcXG4gICAgICAgICAgICAgICAgICAgIH1cXG4gICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG5cXG4gICAgICAgIGNvbXBvc2l0ZS5sYWJlbCArPSAnIE1lc2gnO1xcbiAgICAgICAgXFxuICAgICAgICByZXR1cm4gY29tcG9zaXRlO1xcbiAgICB9O1xcbiAgICBcXG4gICAgLyoqXFxuICAgICAqIENyZWF0ZSBhIG5ldyBjb21wb3NpdGUgY29udGFpbmluZyBib2RpZXMgY3JlYXRlZCBpbiB0aGUgY2FsbGJhY2sgaW4gYSBweXJhbWlkIGFycmFuZ2VtZW50LlxcbiAgICAgKiBUaGlzIGZ1bmN0aW9uIHVzZXMgdGhlIGJvZHkncyBib3VuZHMgdG8gcHJldmVudCBvdmVybGFwcy5cXG4gICAgICogQG1ldGhvZCBweXJhbWlkXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB4eFxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0geXlcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGNvbHVtbnNcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHJvd3NcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGNvbHVtbkdhcFxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gcm93R2FwXFxuICAgICAqIEBwYXJhbSB7ZnVuY3Rpb259IGNhbGxiYWNrXFxuICAgICAqIEByZXR1cm4ge2NvbXBvc2l0ZX0gQSBuZXcgY29tcG9zaXRlIGNvbnRhaW5pbmcgb2JqZWN0cyBjcmVhdGVkIGluIHRoZSBjYWxsYmFja1xcbiAgICAgKi9cXG4gICAgQ29tcG9zaXRlcy5weXJhbWlkID0gZnVuY3Rpb24oeHgsIHl5LCBjb2x1bW5zLCByb3dzLCBjb2x1bW5HYXAsIHJvd0dhcCwgY2FsbGJhY2spIHtcXG4gICAgICAgI
2HJldHVybiBDb21wb3NpdGVzLnN0YWNrKHh4LCB5eSwgY29sdW1ucywgcm93cywgY29sdW1uR2FwLCByb3dHYXAsIGZ1bmN0aW9uKHgsIHksIGNvbHVtbiwgcm93LCBsYXN0Qm9keSwgaSkge1xcbiAgICAgICAgICAgIHZhciBhY3R1YWxSb3dzID0gTWF0aC5taW4ocm93cywgTWF0aC5jZWlsKGNvbHVtbnMgLyAyKSksXFxuICAgICAgICAgICAgICAgIGxhc3RCb2R5V2lkdGggPSBsYXN0Qm9keSA/IGxhc3RCb2R5LmJvdW5kcy5tYXgueCAtIGxhc3RCb2R5LmJvdW5kcy5taW4ueCA6IDA7XFxuICAgICAgICAgICAgXFxuICAgICAgICAgICAgaWYgKHJvdyA+IGFjdHVhbFJvd3MpXFxuICAgICAgICAgICAgICAgIHJldHVybjtcXG4gICAgICAgICAgICBcXG4gICAgICAgICAgICAvLyByZXZlcnNlIHJvdyBvcmRlclxcbiAgICAgICAgICAgIHJvdyA9IGFjdHVhbFJvd3MgLSByb3c7XFxuICAgICAgICAgICAgXFxuICAgICAgICAgICAgdmFyIHN0YXJ0ID0gcm93LFxcbiAgICAgICAgICAgICAgICBlbmQgPSBjb2x1bW5zIC0gMSAtIHJvdztcXG5cXG4gICAgICAgICAgICBpZiAoY29sdW1uIDwgc3RhcnQgfHwgY29sdW1uID4gZW5kKVxcbiAgICAgICAgICAgICAgICByZXR1cm47XFxuICAgICAgICAgICAgXFxuICAgICAgICAgICAgLy8gcmV0cm9hY3RpdmVseSBmaXggdGhlIGZpcnN0IGJvZHkncyBwb3NpdGlvbiwgc2luY2Ugd2lkdGggd2FzIHVua25vd25cXG4gICAgICAgICAgICBpZiAoaSA9PT0gMSkge1xcbiAgICAgICAgICAgICAgICBCb2R5LnRyYW5zbGF0ZShsYXN0Qm9keSwgeyB4OiAoY29sdW1uICsgKGNvbHVtbnMgJSAyID09PSAxID8gMSA6IC0xKSkgKiBsYXN0Qm9keVdpZHRoLCB5OiAwIH0pO1xcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICB2Y
2XIgeE9mZnNldCA9IGxhc3RCb2R5ID8gY29sdW1uICogbGFzdEJvZHlXaWR0aCA6IDA7XFxuICAgICAgICAgICAgXFxuICAgICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKHh4ICsgeE9mZnNldCArIGNvbHVtbiAqIGNvbHVtbkdhcCwgeSwgY29sdW1uLCByb3csIGxhc3RCb2R5LCBpKTtcXG4gICAgICAgIH0pO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogVGhpcyBoYXMgbm93IG1vdmVkIHRvIHRoZSBbbmV3dG9uc0NyYWRsZSBleGFtcGxlXShodHRwczovL2dpdGh1Yi5jb20vbGlhYnJ1L21hdHRlci1qcy9ibG9iL21hc3Rlci9leGFtcGxlcy9uZXd0b25zQ3JhZGxlLmpzKSwgZm9sbG93IHRoYXQgaW5zdGVhZCBhcyB0aGlzIGZ1bmN0aW9uIGlzIGRlcHJlY2F0ZWQgaGVyZS5cXG4gICAgICogQGRlcHJlY2F0ZWQgbW92ZWQgdG8gbmV3dG9uc0NyYWRsZSBleGFtcGxlXFxuICAgICAqIEBtZXRob2QgbmV3dG9uc0NyYWRsZVxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0geHhcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHl5XFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBudW1iZXJcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHNpemVcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGxlbmd0aFxcbiAgICAgKiBAcmV0dXJuIHtjb21wb3NpdGV9IEEgbmV3IGNvbXBvc2l0ZSBuZXd0b25zQ3JhZGxlIGJvZHlcXG4gICAgICovXFxuICAgIENvbXBvc2l0ZXMubmV3dG9uc0NyYWRsZSA9IGZ1bmN0aW9uKHh4LCB5eSwgbnVtYmVyLCBzaXplLCBsZW5ndGgpIHtcXG4gICAgICAgIHZhciBuZXd0b25zQ3JhZGxlID0gQ29tcG9zaXRlLmNyZWF0ZSh7IGxhYmVsOiAnTmV3dG9ucyBDcmFkbGUnIH0pO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBudW1iZXI7IGkrKykge1xcbiAgICAgICAgICAgIHZhciBzZXBhcmF0aW9uID0gMS45LFxcbiAgICAgICAgICAgICAgICBjaXJjbGUgPSBCb2RpZXMuY2lyY2xlKHh4ICsgaSAqIChzaXplICogc2VwYXJhdGlvbiksIHl5ICsgbGVuZ3RoLCBzaXplLCBcXG4gICAgICAgICAgICAgICAgICAgIHsgaW5lcnRpYTogSW5maW5pdHksIHJlc3RpdHV0aW9uOiAxLCBmcmljdGlvbjogMCwgZnJpY3Rpb25BaXI6IDAuMDAwMSwgc2xvcDogMSB9KSxcXG4gICAgICAgICAgICAgICAgY29uc3RyYWludCA9IENvbnN0cmFpbnQuY3JlYXRlKHsgcG9pbnRBOiB7IHg6IHh4ICsgaSAqIChzaXplICogc2VwYXJhdGlvbiksIHk6IHl5IH0sIGJvZHlCOiBjaXJjbGUgfSk7XFxuXFxuICAgICAgICAgICAgQ29tcG9zaXRlLmFkZEJvZHkobmV3dG9uc0NyYWRsZSwgY2lyY2xlKTtcXG4gICAgICAgICAgICBDb21wb3NpdGUuYWRkQ29uc3RyYWludChuZXd0b25zQ3JhZGxlLCBjb25zdHJhaW50KTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHJldHVybiBuZXd0b25zQ3JhZGxlO1xcbiAgICB9O1xcblxcbiAgICBkZXByZWNhdGVkKENvbXBvc2l0ZXMsICduZXd0b25zQ3JhZGxlJywgJ0NvbXBvc2l0ZXMubmV3dG9uc0NyYWRsZSDinqQgbW92ZWQgdG8gbmV3dG9uc0NyYWRsZSBleGFtcGxlJyk7XFxuICAgIFxcbiAgICAvKipcXG4gICAgICogVGhpcyBoYXMgbm93IG1vdmVkIHRvIHRoZSBbY2FyIGV4YW1wbGVdKGh0dHBzOi8vZ2l0aHViLmNvbS9saWFicnUvbWF0dGVyLWpzL2Jsb2IvbWFzdGVyL2V4YW1wbGVzL2Nhci5qcyksIGZvbGxvdyB0aGF0IGluc3RlYWQgYXMgdGhpcyBmdW5jdGlvbiBpcyBkZXByZWNhdGVkIGhlcmUuXFxuICAgICAqIEBkZXByZWNhdGVkIG1vdmVkIHRvIGNhciBleGFtcGxlXFxuICAgICAqIEBtZXRob2QgY2FyXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB4eFxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0geXlcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoXFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHRcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHdoZWVsU2l6ZVxcbiAgICAgKiBAcmV0dXJuIHtjb21wb3NpdGV9IEEgbmV3IGNvbXBvc2l0ZSBjYXIgYm9keVxcbiAgICAgKi9cXG4gICAgQ29tcG9zaXRlcy5jYXIgPSBmdW5jdGlvbih4eCwgeXksIHdpZHRoLCBoZWlnaHQsIHdoZWVsU2l6ZSkge1xcbiAgICAgICAgdmFyIGdyb3VwID0gQm9keS5uZXh0R3JvdXAodHJ1ZSksXFxuICAgICAgICAgICAgd2hlZWxCYXNlID0gMjAsXFxuICAgICAgICAgICAgd2hlZWxBT2Zmc2V0ID0gLXdpZHRoICogMC41ICsgd2hlZWxCYXNlLFxcbiAgICAgICAgICAgIHdoZWVsQk9mZnNldCA9IHdpZHRoICogMC41IC0gd2hlZWxCYXNlLFxcbiAgICAgICAgICAgIHdoZWVsWU9mZnNldCA9IDA7XFxuICAgIFxcbiAgICAgICAgdmFyIGNhciA9IENvbXBvc2l0ZS5jcmVhdGUoeyBsYWJlbDogJ0NhcicgfSksXFxuICAgICAgICAgICAgYm9keSA9IEJvZGllcy5yZWN0YW5nbGUoeHgsIHl5LCB3aWR0aCwgaGVpZ2h0LCB7IFxcbiAgICAgICAgICAgICAgICBjb2xsaXNpb25GaWx0ZXI6IHtcXG4gICAgICAgICAgICAgICAgICAgIGdyb3VwOiBncm91cFxcbiAgICAgICAgICAgICAgICB9LFxcbiAgICAgICAgICAgICAgICBjaGFtZmVyOiB7XFxuICAgICAgICAgICAgICAgICAgICByYWRpdXM6IGhlaWdodCAqIDAuNVxcbiAgICAgICAgICAgICAgICB9LFxcbiAgICAgICAgICAgICAgICBkZW5zaXR5OiAwLjAwMDJcXG4gICAgICAgICAgICB9KTtcXG4gICAgXFxuICAgICAgICB2Y
2XIgd2hlZWxBID0gQm9kaWVzLmNpcmNsZSh4eCArIHdoZWVsQU9mZnNldCwgeXkgKyB3aGVlbFlPZmZzZXQsIHdoZWVsU2l6ZSwgeyBcXG4gICAgICAgICAgICBjb2xsaXNpb25GaWx0ZXI6IHtcXG4gICAgICAgICAgICAgICAgZ3JvdXA6IGdyb3VwXFxuICAgICAgICAgICAgfSxcXG4gICAgICAgICAgICBmcmljdGlvbjogMC44XFxuICAgICAgICB9KTtcXG4gICAgICAgICAgICAgICAgICAgIFxcbiAgICAgICAgdmFyIHdoZWVsQiA9IEJvZGllcy5jaXJjbGUoeHggKyB3aGVlbEJPZmZzZXQsIHl5ICsgd2hlZWxZT2Zmc2V0LCB3aGVlbFNpemUsIHsgXFxuICAgICAgICAgICAgY29sbGlzaW9uRmlsdGVyOiB7XFxuICAgICAgICAgICAgICAgIGdyb3VwOiBncm91cFxcbiAgICAgICAgICAgIH0sXFxuICAgICAgICAgICAgZnJpY3Rpb246IDAuOFxcbiAgICAgICAgfSk7XFxuICAgICAgICAgICAgICAgICAgICBcXG4gICAgICAgIHZhciBheGVsQSA9IENvbnN0cmFpbnQuY3JlYXRlKHtcXG4gICAgICAgICAgICBib2R5QjogYm9keSxcXG4gICAgICAgICAgICBwb2ludEI6IHsgeDogd2hlZWxBT2Zmc2V0LCB5OiB3aGVlbFlPZmZzZXQgfSxcXG4gICAgICAgICAgICBib2R5QTogd2hlZWxBLFxcbiAgICAgICAgICAgIHN0aWZmbmVzczogMSxcXG4gICAgICAgICAgICBsZW5ndGg6IDBcXG4gICAgICAgIH0pO1xcbiAgICAgICAgICAgICAgICAgICAgICAgIFxcbiAgICAgICAgdmFyIGF4ZWxCID0gQ29uc3RyYWludC5jcmVhdGUoe1xcbiAgICAgICAgICAgIGJvZHlCOiBib2R5LFxcbiAgICAgICAgICAgIHBvaW50QjogeyB4OiB3aGVlbEJPZmZzZXQsIHk6IHdoZWVsWU9mZnNldCB9LFxcbiAgICAgICAgICAgIGJvZHlBOiB3aGVlbEIsXFxuICAgICAgICAgICAgc3RpZmZuZXNzOiAxLFxcbiAgICAgICAgICAgIGxlbmd0aDogMFxcbiAgICAgICAgfSk7XFxuICAgICAgICBcXG4gICAgICAgIENvbXBvc2l0ZS5hZGRCb2R5KGNhciwgYm9keSk7XFxuICAgICAgICBDb21wb3NpdGUuYWRkQm9keShjYXIsIHdoZWVsQSk7XFxuICAgICAgICBDb21wb3NpdGUuYWRkQm9keShjYXIsIHdoZWVsQik7XFxuICAgICAgICBDb21wb3NpdGUuYWRkQ29uc3RyYWludChjYXIsIGF4ZWxBKTtcXG4gICAgICAgIENvbXBvc2l0ZS5hZGRDb25zdHJhaW50KGNhciwgYXhlbEIpO1xcblxcbiAgICAgICAgcmV0dXJuIGNhcjtcXG4gICAgfTtcXG5cXG4gICAgZGVwcmVjYXRlZChDb21wb3NpdGVzLCAnY2FyJywgJ0NvbXBvc2l0ZXMuY2FyIOKepCBtb3ZlZCB0byBjYXIgZXhhbXBsZScpO1xcblxcbiAgICAvKipcXG4gICAgICogVGhpcyBoYXMgbm93IG1vdmVkIHRvIHRoZSBbc29mdEJvZHkgZXhhbXBsZV0oaHR0cHM6Ly9naXRodWIuY29tL2xpYWJydS9tYXR0ZXItanMvYmxvYi9tYXN0ZXIvZXhhbXBsZXMvc29mdEJvZHkuanMpXFxuICAgICAqIGFuZCB0aGUgW2Nsb3RoIGV4YW1wbGVdKGh0dHBzOi8vZ2l0aHViLmNvbS9saWFicnUvbWF0dGVyLWpzL2Jsb2IvbWFzdGVyL2V4YW1wbGVzL2Nsb3RoLmpzKSwgZm9sbG93IHRob3NlIGluc3RlYWQgYXMgdGhpcyBmdW5jdGlvbiBpcyBkZXByZWNhdGVkIGhlcmUuXFxuICAgICAqIEBkZXByZWNhdGVkIG1vdmVkIHRvIHNvZnRCb2R5IGFuZCBjbG90aCBleGFtcGxlc1xcbiAgICAgKiBAbWV0aG9kIHNvZnRCb2R5XFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB4eFxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0geXlcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGNvbHVtbnNcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHJvd3NcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGNvbHVtbkdhcFxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gcm93R2FwXFxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gY3Jvc3NCcmFjZVxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gcGFydGljbGVSYWRpdXNcXG4gICAgICogQHBhcmFtIHt9IHBhcnRpY2xlT3B0aW9uc1xcbiAgICAgKiBAcGFyYW0ge30gY29uc3RyYWludE9wdGlvbnNcXG4gICAgICogQHJldHVybiB7Y29tcG9zaXRlfSBBIG5ldyBjb21wb3NpdGUgc29mdEJvZHlcXG4gICAgICovXFxuICAgIENvbXBvc2l0ZXMuc29mdEJvZHkgPSBmdW5jdGlvbih4eCwgeXksIGNvbHVtbnMsIHJvd3MsIGNvbHVtbkdhcCwgcm93R2FwLCBjcm9zc0JyYWNlLCBwYXJ0aWNsZVJhZGl1cywgcGFydGljbGVPcHRpb25zLCBjb25zdHJhaW50T3B0aW9ucykge1xcbiAgICAgICAgcGFydGljbGVPcHRpb25zID0gQ29tbW9uLmV4dGVuZCh7IGluZXJ0aWE6IEluZmluaXR5IH0sIHBhcnRpY2xlT3B0aW9ucyk7XFxuICAgICAgICBjb25zdHJhaW50T3B0aW9ucyA9IENvbW1vbi5leHRlbmQoeyBzdGlmZm5lc3M6IDAuMiwgcmVuZGVyOiB7IHR5cGU6ICdsaW5lJywgYW5jaG9yczogZmFsc2UgfSB9LCBjb25zdHJhaW50T3B0aW9ucyk7XFxuXFxuICAgICAgICB2Y
2XIgc29mdEJvZHkgPSBDb21wb3NpdGVzLnN0YWNrKHh4LCB5eSwgY29sdW1ucywgcm93cywgY29sdW1uR2FwLCByb3dHYXAsIGZ1bmN0aW9uKHgsIHkpIHtcXG4gICAgICAgICAgICByZXR1cm4gQm9kaWVzLmNpcmNsZSh4LCB5LCBwYXJ0aWNsZVJhZGl1cywgcGFydGljbGVPcHRpb25zKTtcXG4gICAgICAgIH0pO1xcblxcbiAgICAgICAgQ29tcG9zaXRlcy5tZXNoKHNvZnRCb2R5LCBjb2x1bW5zLCByb3dzLCBjcm9zc0JyYWNlLCBjb25zdHJhaW50T3B0aW9ucyk7XFxuXFxuICAgICAgICBzb2Z0Qm9keS5sYWJlbCA9ICdTb2Z0IEJvZHknO1xcblxcbiAgICAgICAgcmV0dXJuIHNvZnRCb2R5O1xcbiAgICB9O1xcblxcbiAgICBkZXByZWNhdGVkKENvbXBvc2l0ZXMsICdzb2Z0Qm9keScsICdDb21wb3NpdGVzLnNvZnRCb2R5IOKepCBtb3ZlZCB0byBzb2Z0Qm9keSBhbmQgY2xvdGggZXhhbXBsZXMnKTtcXG59KSgpO1xcblxcblxcbi8qKiovIH0pLFxcbi8qIDIzICovXFxuLyoqKi8gKGZ1bmN0aW9uKG1vZHVsZSwgZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xcblxcbi8qKlxcbiogVGhpcyBtb2R1bGUgaGFzIG5vdyBiZWVuIHJlcGxhY2VkIGJ5IGBNYXR0ZXIuRGV0ZWN0b3JgLlxcbipcXG4qIEFsbCB1c2FnZSBzaG91bGQgYmUgbWlncmF0ZWQgdG8gYE1hdHRlci5EZXRlY3RvcmAgb3IgYW5vdGhlciBhbHRlcm5hdGl2ZS5cXG4qIEZvciBiYWNrLWNvbXBhdGliaWxpdHkgcHVycG9zZXMgdGhpcyBtb2R1bGUgd2lsbCByZW1haW4gZm9yIGEgc2hvcnQgdGVybSBhbmQgdGhlbiBsYXRlciByZW1vdmVkIGluIGEgZnV0dXJlIHJlbGVhc2UuXFxuKlxcbiogVGhlIGBNYXR0ZXIuR3JpZGAgbW9kdWxlIGNvbnRhaW5zIG1ldGhvZHMgZm9yIGNyZWF0aW5nIGFuZCBtYW5pcHVsYXRpbmcgY29sbGlzaW9uIGJyb2FkcGhhc2UgZ3JpZCBzdHJ1Y3R1cmVzLlxcbipcXG4qIEBjbGFzcyBHcmlkXFxuKiBAZGVwcmVjYXRlZFxcbiovXFxuXFxudmFyIEdyaWQgPSB7fTtcXG5cXG5tb2R1bGUuZXhwb3J0cyA9IEdyaWQ7XFxuXFxudmFyIFBhaXIgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDkpO1xcbnZhciBDb21tb24gPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDApO1xcbnZhciBkZXByZWNhdGVkID0gQ29tbW9uLmRlcHJlY2F0ZWQ7XFxuXFxuKGZ1bmN0aW9uKCkge1xcblxcbiAgICAvKipcXG4gICAgICogQ3JlYXRlcyBhIG5ldyBncmlkLlxcbiAgICAgKiBAZGVwcmVjYXRlZCByZXBsYWNlZCBieSBNYXR0ZXIuRGV0ZWN0b3JcXG4gICAgICogQG1ldGhvZCBjcmVhdGVcXG4gICAgICogQHBhcmFtIHt9IG9wdGlvbnNcXG4gICAgICogQHJldHVybiB7Z3JpZH0gQSBuZXcgZ3JpZFxcbiAgICAgKi9cXG4gICAgR3JpZC5jcmVhdGUgPSBmdW5jdGlvbihvcHRpb25zKSB7XFxuICAgICAgICB2Y
2XIgZGVmYXVsdHMgPSB7XFxuICAgICAgICAgICAgYnVja2V0czoge30sXFxuICAgICAgICAgICAgcGFpcnM6IHt9LFxcbiAgICAgICAgICAgIHBhaXJzTGlzdDogW10sXFxuICAgICAgICAgICAgYnVja2V0V2lkdGg6IDQ4LFxcbiAgICAgICAgICAgIGJ1Y2tldEhlaWdodDogNDhcXG4gICAgICAgIH07XFxuXFxuICAgICAgICByZXR1cm4gQ29tbW9uLmV4dGVuZChkZWZhdWx0cywgb3B0aW9ucyk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBUaGUgd2lkdGggb2YgYSBzaW5nbGUgZ3JpZCBidWNrZXQuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBidWNrZXRXaWR0aFxcbiAgICAgKiBAdHlwZSBudW1iZXJcXG4gICAgICogQGRlZmF1bHQgNDhcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBUaGUgaGVpZ2h0IG9mIGEgc2luZ2xlIGdyaWQgYnVja2V0LlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgYnVja2V0SGVpZ2h0XFxuICAgICAqIEB0eXBlIG51bWJlclxcbiAgICAgKiBAZGVmYXVsdCA0OFxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIFVwZGF0ZXMgdGhlIGdyaWQuXFxuICAgICAqIEBkZXByZWNhdGVkIHJlcGxhY2VkIGJ5IE1hdHRlci5EZXRlY3RvclxcbiAgICAgKiBAbWV0aG9kIHVwZGF0ZVxcbiAgICAgKiBAcGFyYW0ge2dyaWR9IGdyaWRcXG4gICAgICogQHBhcmFtIHtib2R5W119IGJvZGllc1xcbiAgICAgKiBAcGFyYW0ge2VuZ2luZX0gZW5naW5lXFxuICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gZm9yY2VVcGRhdGVcXG4gICAgICovXFxuICAgIEdyaWQudXBkYXRlID0gZnVuY3Rpb24oZ3JpZCwgYm9kaWVzLCBlbmdpbmUsIGZvcmNlVXBkYXRlKSB7XFxuICAgICAgICB2Y
2XIgaSwgY29sLCByb3csXFxuICAgICAgICAgICAgd29ybGQgPSBlbmdpbmUud29ybGQsXFxuICAgICAgICAgICAgYnVja2V0cyA9IGdyaWQuYnVja2V0cyxcXG4gICAgICAgICAgICBidWNrZXQsXFxuICAgICAgICAgICAgYnVja2V0SWQsXFxuICAgICAgICAgICAgZ3JpZENoYW5nZWQgPSBmYWxzZTtcXG5cXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBib2RpZXMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICB2YXIgYm9keSA9IGJvZGllc1tpXTtcXG5cXG4gICAgICAgICAgICBpZiAoYm9keS5pc1NsZWVwaW5nICYmICFmb3JjZVVwZGF0ZSlcXG4gICAgICAgICAgICAgICAgY29udGludWU7XFxuXFxuICAgICAgICAgICAgLy8gdGVtcG9yYXJ5IGJhY2sgY29tcGF0aWJpbGl0eSBib3VuZHMgY2hlY2tcXG4gICAgICAgICAgICBpZiAod29ybGQuYm91bmRzICYmIChib2R5LmJvdW5kcy5tYXgueCA8IHdvcmxkLmJvdW5kcy5taW4ueCB8fCBib2R5LmJvdW5kcy5taW4ueCA+IHdvcmxkLmJvdW5kcy5tYXgueFxcbiAgICAgICAgICAgICAgICB8fCBib2R5LmJvdW5kcy5tYXgueSA8IHdvcmxkLmJvdW5kcy5taW4ueSB8fCBib2R5LmJvdW5kcy5taW4ueSA+IHdvcmxkLmJvdW5kcy5tYXgueSkpXFxuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xcblxcbiAgICAgICAgICAgIHZhciBuZXdSZWdpb24gPSBHcmlkLl9nZXRSZWdpb24oZ3JpZCwgYm9keSk7XFxuXFxuICAgICAgICAgICAgLy8gaWYgdGhlIGJvZHkgaGFzIGNoYW5nZWQgZ3JpZCByZWdpb25cXG4gICAgICAgICAgICBpZiAoIWJvZHkucmVnaW9uIHx8IG5ld1JlZ2lvbi5pZCAhPT0gYm9keS5yZWdpb24uaWQgfHwgZm9yY2VVcGRhdGUpIHtcXG5cXG4gICAgICAgICAgICAgICAgaWYgKCFib2R5LnJlZ2lvbiB8fCBmb3JjZVVwZGF0ZSlcXG4gICAgICAgICAgICAgICAgICAgIGJvZHkucmVnaW9uID0gbmV3UmVnaW9uO1xcblxcbiAgICAgICAgICAgICAgICB2Y
2XIgdW5pb24gPSBHcmlkLl9yZWdpb25VbmlvbihuZXdSZWdpb24sIGJvZHkucmVnaW9uKTtcXG5cXG4gICAgICAgICAgICAgICAgLy8gdXBkYXRlIGdyaWQgYnVja2V0cyBhZmZlY3RlZCBieSByZWdpb24gY2hhbmdlXFxuICAgICAgICAgICAgICAgIC8vIGl0ZXJhdGUgb3ZlciB0aGUgdW5pb24gb2YgYm90aCByZWdpb25zXFxuICAgICAgICAgICAgICAgIGZvciAoY29sID0gdW5pb24uc3RhcnRDb2w7IGNvbCA8PSB1bmlvbi5lbmRDb2w7IGNvbCsrKSB7XFxuICAgICAgICAgICAgICAgICAgICBmb3IgKHJvdyA9IHVuaW9uLnN0YXJ0Um93OyByb3cgPD0gdW5pb24uZW5kUm93OyByb3crKykge1xcbiAgICAgICAgICAgICAgICAgICAgICAgIGJ1Y2tldElkID0gR3JpZC5fZ2V0QnVja2V0SWQoY29sLCByb3cpO1xcbiAgICAgICAgICAgICAgICAgICAgICAgIGJ1Y2tldCA9IGJ1Y2tldHNbYnVja2V0SWRdO1xcblxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBpc0luc2lkZU5ld1JlZ2lvbiA9IChjb2wgPj0gbmV3UmVnaW9uLnN0YXJ0Q29sICYmIGNvbCA8PSBuZXdSZWdpb24uZW5kQ29sXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJiYgcm93ID49IG5ld1JlZ2lvbi5zdGFydFJvdyAmJiByb3cgPD0gbmV3UmVnaW9uLmVuZFJvdyk7XFxuXFxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGlzSW5zaWRlT2xkUmVnaW9uID0gKGNvbCA+PSBib2R5LnJlZ2lvbi5zdGFydENvbCAmJiBjb2wgPD0gYm9keS5yZWdpb24uZW5kQ29sXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJiYgcm93ID49IGJvZHkucmVnaW9uLnN0YXJ0Um93ICYmIHJvdyA8PSBib2R5LnJlZ2lvbi5lbmRSb3cpO1xcblxcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJlbW92ZSBmcm9tIG9sZCByZWdpb24gYnVja2V0c1xcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghaXNJbnNpZGVOZXdSZWdpb24gJiYgaXNJbnNpZGVPbGRSZWdpb24pIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzSW5zaWRlT2xkUmVnaW9uKSB7XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoYnVja2V0KVxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEdyaWQuX2J1Y2tldFJlbW92ZUJvZHkoZ3JpZCwgYnVja2V0LCBib2R5KTtcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBhZGQgdG8gbmV3IHJlZ2lvbiBidWNrZXRzXFxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGJvZHkucmVnaW9uID09PSBuZXdSZWdpb24gfHwgKGlzSW5zaWRlTmV3UmVnaW9uICYmICFpc0luc2lkZU9sZFJlZ2lvbikgfHwgZm9yY2VVcGRhdGUpIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFidWNrZXQpXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBidWNrZXQgPSBHcmlkLl9jcmVhdGVCdWNrZXQoYnVja2V0cywgYnVja2V0SWQpO1xcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBHcmlkLl9idWNrZXRBZGRCb2R5KGdyaWQsIGJ1Y2tldCwgYm9keSk7XFxuICAgICAgICAgICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgICAgIC8vIHNldCB0aGUgbmV3IHJlZ2lvblxcbiAgICAgICAgICAgICAgICBib2R5LnJlZ2lvbiA9IG5ld1JlZ2lvbjtcXG5cXG4gICAgICAgICAgICAgICAgLy8gZmxhZyBjaGFuZ2VzIHNvIHdlIGNhbiB1cGRhdGUgcGFpcnNcXG4gICAgICAgICAgICAgICAgZ3JpZENoYW5nZWQgPSB0cnVlO1xcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG5cXG4gICAgICAgIC8vIHVwZGF0ZSBwYWlycyBsaXN0IG9ubHkgaWYgcGFpcnMgY2hhbmdlZCAoaS5lLiBhIGJvZHkgY2hhbmdlZCByZWdpb24pXFxuICAgICAgICBpZiAoZ3JpZENoYW5nZWQpXFxuICAgICAgICAgICAgZ3JpZC5wYWlyc0xpc3QgPSBHcmlkLl9jcmVhdGVBY3RpdmVQYWlyc0xpc3QoZ3JpZCk7XFxuICAgIH07XFxuXFxuICAgIGRlcHJlY2F0ZWQoR3JpZCwgJ3VwZGF0ZScsICdHcmlkLnVwZGF0ZSDinqQgcmVwbGFjZWQgYnkgTWF0dGVyLkRldGVjdG9yJyk7XFxuXFxuICAgIC8qKlxcbiAgICAgKiBDbGVhcnMgdGhlIGdyaWQuXFxuICAgICAqIEBkZXByZWNhdGVkIHJlcGxhY2VkIGJ5IE1hdHRlci5EZXRlY3RvclxcbiAgICAgKiBAbWV0aG9kIGNsZWFyXFxuICAgICAqIEBwYXJhbSB7Z3JpZH0gZ3JpZFxcbiAgICAgKi9cXG4gICAgR3JpZC5jbGVhciA9IGZ1bmN0aW9uKGdyaWQpIHtcXG4gICAgICAgIGdyaWQuYnVja2V0cyA9IHt9O1xcbiAgICAgICAgZ3JpZC5wYWlycyA9IHt9O1xcbiAgICAgICAgZ3JpZC5wYWlyc0xpc3QgPSBbXTtcXG4gICAgfTtcXG5cXG4gICAgZGVwcmVjYXRlZChHcmlkLCAnY2xlYXInLCAnR3JpZC5jbGVhciDinqQgcmVwbGFjZWQgYnkgTWF0dGVyLkRldGVjdG9yJyk7XFxuXFxuICAgIC8qKlxcbiAgICAgKiBGaW5kcyB0aGUgdW5pb24gb2YgdHdvIHJlZ2lvbnMuXFxuICAgICAqIEBtZXRob2QgX3JlZ2lvblVuaW9uXFxuICAgICAqIEBkZXByZWNhdGVkIHJlcGxhY2VkIGJ5IE1hdHRlci5EZXRlY3RvclxcbiAgICAgKiBAcHJpdmF0ZVxcbiAgICAgKiBAcGFyYW0ge30gcmVnaW9uQVxcbiAgICAgKiBAcGFyYW0ge30gcmVnaW9uQlxcbiAgICAgKiBAcmV0dXJuIHt9IHJlZ2lvblxcbiAgICAgKi9cXG4gICAgR3JpZC5fcmVnaW9uVW5pb24gPSBmdW5jdGlvbihyZWdpb25BLCByZWdpb25CKSB7XFxuICAgICAgICB2Y
2XIgc3RhcnRDb2wgPSBNYXRoLm1pbihyZWdpb25BLnN0YXJ0Q29sLCByZWdpb25CLnN0YXJ0Q29sKSxcXG4gICAgICAgICAgICBlbmRDb2wgPSBNYXRoLm1heChyZWdpb25BLmVuZENvbCwgcmVnaW9uQi5lbmRDb2wpLFxcbiAgICAgICAgICAgIHN0YXJ0Um93ID0gTWF0aC5taW4ocmVnaW9uQS5zdGFydFJvdywgcmVnaW9uQi5zdGFydFJvdyksXFxuICAgICAgICAgICAgZW5kUm93ID0gTWF0aC5tYXgocmVnaW9uQS5lbmRSb3csIHJlZ2lvbkIuZW5kUm93KTtcXG5cXG4gICAgICAgIHJldHVybiBHcmlkLl9jcmVhdGVSZWdpb24oc3RhcnRDb2wsIGVuZENvbCwgc3RhcnRSb3csIGVuZFJvdyk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBHZXRzIHRoZSByZWdpb24gYSBnaXZlbiBib2R5IGZhbGxzIGluIGZvciBhIGdpdmVuIGdyaWQuXFxuICAgICAqIEBtZXRob2QgX2dldFJlZ2lvblxcbiAgICAgKiBAZGVwcmVjYXRlZCByZXBsYWNlZCBieSBNYXR0ZXIuRGV0ZWN0b3JcXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQHBhcmFtIHt9IGdyaWRcXG4gICAgICogQHBhcmFtIHt9IGJvZHlcXG4gICAgICogQHJldHVybiB7fSByZWdpb25cXG4gICAgICovXFxuICAgIEdyaWQuX2dldFJlZ2lvbiA9IGZ1bmN0aW9uKGdyaWQsIGJvZHkpIHtcXG4gICAgICAgIHZhciBib3VuZHMgPSBib2R5LmJvdW5kcyxcXG4gICAgICAgICAgICBzdGFydENvbCA9IE1hdGguZmxvb3IoYm91bmRzLm1pbi54IC8gZ3JpZC5idWNrZXRXaWR0aCksXFxuICAgICAgICAgICAgZW5kQ29sID0gTWF0aC5mbG9vcihib3VuZHMubWF4LnggLyBncmlkLmJ1Y2tldFdpZHRoKSxcXG4gICAgICAgICAgICBzdGFydFJvdyA9IE1hdGguZmxvb3IoYm91bmRzLm1pbi55IC8gZ3JpZC5idWNrZXRIZWlnaHQpLFxcbiAgICAgICAgICAgIGVuZFJvdyA9IE1hdGguZmxvb3IoYm91bmRzLm1heC55IC8gZ3JpZC5idWNrZXRIZWlnaHQpO1xcblxcbiAgICAgICAgcmV0dXJuIEdyaWQuX2NyZWF0ZVJlZ2lvbihzdGFydENvbCwgZW5kQ29sLCBzdGFydFJvdywgZW5kUm93KTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIENyZWF0ZXMgYSByZWdpb24uXFxuICAgICAqIEBtZXRob2QgX2NyZWF0ZVJlZ2lvblxcbiAgICAgKiBAZGVwcmVjYXRlZCByZXBsYWNlZCBieSBNYXR0ZXIuRGV0ZWN0b3JcXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQHBhcmFtIHt9IHN0YXJ0Q29sXFxuICAgICAqIEBwYXJhbSB7fSBlbmRDb2xcXG4gICAgICogQHBhcmFtIHt9IHN0YXJ0Um93XFxuICAgICAqIEBwYXJhbSB7fSBlbmRSb3dcXG4gICAgICogQHJldHVybiB7fSByZWdpb25cXG4gICAgICovXFxuICAgIEdyaWQuX2NyZWF0ZVJlZ2lvbiA9IGZ1bmN0aW9uKHN0YXJ0Q29sLCBlbmRDb2wsIHN0YXJ0Um93LCBlbmRSb3cpIHtcXG4gICAgICAgIHJldHVybiB7IFxcbiAgICAgICAgICAgIGlkOiBzdGFydENvbCArICcsJyArIGVuZENvbCArICcsJyArIHN0YXJ0Um93ICsgJywnICsgZW5kUm93LFxcbiAgICAgICAgICAgIHN0YXJ0Q29sOiBzdGFydENvbCwgXFxuICAgICAgICAgICAgZW5kQ29sOiBlbmRDb2wsIFxcbiAgICAgICAgICAgIHN0YXJ0Um93OiBzdGFydFJvdywgXFxuICAgICAgICAgICAgZW5kUm93OiBlbmRSb3cgXFxuICAgICAgICB9O1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogR2V0cyB0aGUgYnVja2V0IGlkIGF0IHRoZSBnaXZlbiBwb3NpdGlvbi5cXG4gICAgICogQG1ldGhvZCBfZ2V0QnVja2V0SWRcXG4gICAgICogQGRlcHJlY2F0ZWQgcmVwbGFjZWQgYnkgTWF0dGVyLkRldGVjdG9yXFxuICAgICAqIEBwcml2YXRlXFxuICAgICAqIEBwYXJhbSB7fSBjb2x1bW5cXG4gICAgICogQHBhcmFtIHt9IHJvd1xcbiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9IGJ1Y2tldCBpZFxcbiAgICAgKi9cXG4gICAgR3JpZC5fZ2V0QnVja2V0SWQgPSBmdW5jdGlvbihjb2x1bW4sIHJvdykge1xcbiAgICAgICAgcmV0dXJuICdDJyArIGNvbHVtbiArICdSJyArIHJvdztcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIENyZWF0ZXMgYSBidWNrZXQuXFxuICAgICAqIEBtZXRob2QgX2NyZWF0ZUJ1Y2tldFxcbiAgICAgKiBAZGVwcmVjYXRlZCByZXBsYWNlZCBieSBNYXR0ZXIuRGV0ZWN0b3JcXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQHBhcmFtIHt9IGJ1Y2tldHNcXG4gICAgICogQHBhcmFtIHt9IGJ1Y2tldElkXFxuICAgICAqIEByZXR1cm4ge30gYnVja2V0XFxuICAgICAqL1xcbiAgICBHcmlkLl9jcmVhdGVCdWNrZXQgPSBmdW5jdGlvbihidWNrZXRzLCBidWNrZXRJZCkge1xcbiAgICAgICAgdmFyIGJ1Y2tldCA9IGJ1Y2tldHNbYnVja2V0SWRdID0gW107XFxuICAgICAgICByZXR1cm4gYnVja2V0O1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogQWRkcyBhIGJvZHkgdG8gYSBidWNrZXQuXFxuICAgICAqIEBtZXRob2QgX2J1Y2tldEFkZEJvZHlcXG4gICAgICogQGRlcHJlY2F0ZWQgcmVwbGFjZWQgYnkgTWF0dGVyLkRldGVjdG9yXFxuICAgICAqIEBwcml2YXRlXFxuICAgICAqIEBwYXJhbSB7fSBncmlkXFxuICAgICAqIEBwYXJhbSB7fSBidWNrZXRcXG4gICAgICogQHBhcmFtIHt9IGJvZHlcXG4gICAgICovXFxuICAgIEdyaWQuX2J1Y2tldEFkZEJvZHkgPSBmdW5jdGlvbihncmlkLCBidWNrZXQsIGJvZHkpIHtcXG4gICAgICAgIHZhciBncmlkUGFpcnMgPSBncmlkLnBhaXJzLFxcbiAgICAgICAgICAgIHBhaXJJZCA9IFBhaXIuaWQsXFxuICAgICAgICAgICAgYnVja2V0TGVuZ3RoID0gYnVja2V0Lmxlbmd0aCxcXG4gICAgICAgICAgICBpO1xcblxcbiAgICAgICAgLy8gYWRkIG5ldyBwYWlyc1xcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGJ1Y2tldExlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgdmFyIGJvZHlCID0gYnVja2V0W2ldO1xcblxcbiAgICAgICAgICAgIGlmIChib2R5LmlkID09PSBib2R5Qi5pZCB8fCAoYm9keS5pc1N0YXRpYyAmJiBib2R5Qi5pc1N0YXRpYykpXFxuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xcblxcbiAgICAgICAgICAgIC8vIGtlZXAgdHJhY2sgb2YgdGhlIG51bWJlciBvZiBidWNrZXRzIHRoZSBwYWlyIGV4aXN0cyBpblxcbiAgICAgICAgICAgIC8vIGltcG9ydGFudCBmb3IgR3JpZC51cGRhdGUgdG8gd29ya1xcbiAgICAgICAgICAgI
2HZhciBpZCA9IHBhaXJJZChib2R5LCBib2R5QiksXFxuICAgICAgICAgICAgICAgIHBhaXIgPSBncmlkUGFpcnNbaWRdO1xcblxcbiAgICAgICAgICAgIGlmIChwYWlyKSB7XFxuICAgICAgICAgICAgICAgIHBhaXJbMl0gKz0gMTtcXG4gICAgICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgICAgICBncmlkUGFpcnNbaWRdID0gW2JvZHksIGJvZHlCLCAxXTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuXFxuICAgICAgICAvLyBhZGQgdG8gYm9kaWVzIChhZnRlciBwYWlycywgb3RoZXJ3aXNlIHBhaXJzIHdpdGggc2VsZilcXG4gICAgICAgIGJ1Y2tldC5wdXNoKGJvZHkpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmVtb3ZlcyBhIGJvZHkgZnJvbSBhIGJ1Y2tldC5cXG4gICAgICogQG1ldGhvZCBfYnVja2V0UmVtb3ZlQm9keVxcbiAgICAgKiBAZGVwcmVjYXRlZCByZXBsYWNlZCBieSBNYXR0ZXIuRGV0ZWN0b3JcXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQHBhcmFtIHt9IGdyaWRcXG4gICAgICogQHBhcmFtIHt9IGJ1Y2tldFxcbiAgICAgKiBAcGFyYW0ge30gYm9keVxcbiAgICAgKi9cXG4gICAgR3JpZC5fYnVja2V0UmVtb3ZlQm9keSA9IGZ1bmN0aW9uKGdyaWQsIGJ1Y2tldCwgYm9keSkge1xcbiAgICAgICAgdmFyIGdyaWRQYWlycyA9IGdyaWQucGFpcnMsXFxuICAgICAgICAgICAgcGFpcklkID0gUGFpci5pZCxcXG4gICAgICAgICAgICBpO1xcblxcbiAgICAgICAgLy8gcmVtb3ZlIGZyb20gYnVja2V0XFxuICAgICAgICBidWNrZXQuc3BsaWNlKENvbW1vbi5pbmRleE9mKGJ1Y2tldCwgYm9keSksIDEpO1xcblxcbiAgICAgICAgdmFyIGJ1Y2tldExlbmd0aCA9IGJ1Y2tldC5sZW5ndGg7XFxuXFxuICAgICAgICAvLyB1cGRhdGUgcGFpciBjb3VudHNcXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBidWNrZXRMZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIC8vIGtlZXAgdHJhY2sgb2YgdGhlIG51bWJlciBvZiBidWNrZXRzIHRoZSBwYWlyIGV4aXN0cyBpblxcbiAgICAgICAgICAgIC8vIGltcG9ydGFudCBmb3IgX2NyZWF0ZUFjdGl2ZVBhaXJzTGlzdCB0byB3b3JrXFxuICAgICAgICAgICAgdmFyIHBhaXIgPSBncmlkUGFpcnNbcGFpcklkKGJvZHksIGJ1Y2tldFtpXSldO1xcblxcbiAgICAgICAgICAgIGlmIChwYWlyKVxcbiAgICAgICAgICAgICAgICBwYWlyWzJdIC09IDE7XFxuICAgICAgICB9XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBHZW5lcmF0ZXMgYSBsaXN0IG9mIHRoZSBhY3RpdmUgcGFpcnMgaW4gdGhlIGdyaWQuXFxuICAgICAqIEBtZXRob2QgX2NyZWF0ZUFjdGl2ZVBhaXJzTGlzdFxcbiAgICAgKiBAZGVwcmVjYXRlZCByZXBsYWNlZCBieSBNYXR0ZXIuRGV0ZWN0b3JcXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQHBhcmFtIHt9IGdyaWRcXG4gICAgICogQHJldHVybiBbXSBwYWlyc1xcbiAgICAgKi9cXG4gICAgR3JpZC5fY3JlYXRlQWN0aXZlUGFpcnNMaXN0ID0gZnVuY3Rpb24oZ3JpZCkge1xcbiAgICAgICAgdmFyIHBhaXIsXFxuICAgICAgICAgICAgZ3JpZFBhaXJzID0gZ3JpZC5wYWlycyxcXG4gICAgICAgICAgICBwYWlyS2V5cyA9IENvbW1vbi5rZXlzKGdyaWRQYWlycyksXFxuICAgICAgICAgICAgcGFpcktleXNMZW5ndGggPSBwYWlyS2V5cy5sZW5ndGgsXFxuICAgICAgICAgICAgcGFpcnMgPSBbXSxcXG4gICAgICAgICAgICBrO1xcblxcbiAgICAgICAgLy8gaXRlcmF0ZSBvdmVyIGdyaWQucGFpcnNcXG4gICAgICAgIGZvciAoayA9IDA7IGsgPCBwYWlyS2V5c0xlbmd0aDsgaysrKSB7XFxuICAgICAgICAgICAgcGFpciA9IGdyaWRQYWlyc1twYWlyS2V5c1trXV07XFxuXFxuICAgICAgICAgICAgLy8gaWYgcGFpciBleGlzdHMgaW4gYXQgbGVhc3Qgb25lIGJ1Y2tldFxcbiAgICAgICAgICAgIC8vIGl0IGlzIGEgcGFpciB0aGF0IG5lZWRzIGZ1cnRoZXIgY29sbGlzaW9uIHRlc3Rpbmcgc28gcHVzaCBpdFxcbiAgICAgICAgICAgIGlmIChwYWlyWzJdID4gMCkge1xcbiAgICAgICAgICAgICAgICBwYWlycy5wdXNoKHBhaXIpO1xcbiAgICAgICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgICAgIGRlbGV0ZSBncmlkUGFpcnNbcGFpcktleXNba11dO1xcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHJldHVybiBwYWlycztcXG4gICAgfTtcXG4gICAgXFxufSkoKTtcXG5cXG5cXG4vKioqLyB9KSxcXG4vKiAyNCAqL1xcbi8qKiovIChmdW5jdGlvbihtb2R1bGUsIGV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pIHtcXG5cXG4vKipcXG4qIFRoZSBgTWF0dGVyLk1vdXNlQ29uc3RyYWludGAgbW9kdWxlIGNvbnRhaW5zIG1ldGhvZHMgZm9yIGNyZWF0aW5nIG1vdXNlIGNvbnN0cmFpbnRzLlxcbiogTW91c2UgY29uc3RyYWludHMgYXJlIHVzZWQgZm9yIGFsbG93aW5nIHVzZXIgaW50ZXJhY3Rpb24sIHByb3ZpZGluZyB0aGUgYWJpbGl0eSB0byBtb3ZlIGJvZGllcyB2aWEgdGhlIG1vdXNlIG9yIHRvdWNoLlxcbipcXG4qIFNlZSB0aGUgaW5jbHVkZWQgdXNhZ2UgW2V4YW1wbGVzXShodHRwczovL2dpdGh1Yi5jb20vbGlhYnJ1L21hdHRlci1qcy90cmVlL21hc3Rlci9leGFtcGxlcykuXFxuKlxcbiogQGNsYXNzIE1vdXNlQ29uc3RyYWludFxcbiovXFxuXFxudmFyIE1vdXNlQ29uc3RyYWludCA9IHt9O1xcblxcbm1vZHVsZS5leHBvcnRzID0gTW91c2VDb25zdHJhaW50O1xcblxcbnZhciBWZXJ0aWNlcyA9IF9fd2VicGFja19yZXF1aXJlX18oMyk7XFxudmFyIFNsZWVwaW5nID0gX193ZWJwYWNrX3JlcXVpcmVfXyg3KTtcXG52YXIgTW91c2UgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDE0KTtcXG52YXIgRXZlbnRzID0gX193ZWJwYWNrX3JlcXVpcmVfXyg1KTtcXG52YXIgRGV0ZWN0b3IgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDEzKTtcXG52YXIgQ29uc3RyYWludCA9IF9fd2VicGFja19yZXF1aXJlX18oMTApO1xcbnZhciBDb21wb3NpdGUgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDYpO1xcbnZhciBDb21tb24gPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDApO1xcbnZhciBCb3VuZHMgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDEpO1xcblxcbihmdW5jdGlvbigpIHtcXG5cXG4gICAgLyoqXFxuICAgICAqIENyZWF0ZXMgYSBuZXcgbW91c2UgY29uc3RyYWludC5cXG4gICAgICogQWxsIHByb3BlcnRpZXMgaGF2ZSBkZWZhdWx0IHZhbHVlcywgYW5kIG1hbnkgYXJlIHByZS1jYWxjdWxhdGVkIGF1dG9tYXRpY2FsbHkgYmFzZWQgb24gb3RoZXIgcHJvcGVydGllcy5cXG4gICAgICogU2VlIH
2RoZSBwcm9wZXJ0aWVzIHNlY3Rpb24gYmVsb3cgZm9yIGRldGFpbGVkIGluZm9ybWF0aW9uIG9uIHdoYXQgeW91IGNhbiBwYXNzIHZpYSB0aGUgYG9wdGlvbnNgIG9iamVjdC5cXG4gICAgICogQG1ldGhvZCBjcmVhdGVcXG4gICAgICogQHBhcmFtIHtlbmdpbmV9IGVuZ2luZVxcbiAgICAgKiBAcGFyYW0ge30gb3B0aW9uc1xcbiAgICAgKiBAcmV0dXJuIHtNb3VzZUNvbnN0cmFpbnR9IEEgbmV3IE1vdXNlQ29uc3RyYWludFxcbiAgICAgKi9cXG4gICAgTW91c2VDb25zdHJhaW50LmNyZWF0ZSA9IGZ1bmN0aW9uKGVuZ2luZSwgb3B0aW9ucykge1xcbiAgICAgICAgdmFyIG1vdXNlID0gKGVuZ2luZSA/IGVuZ2luZS5tb3VzZSA6IG51bGwpIHx8IChvcHRpb25zID8gb3B0aW9ucy5tb3VzZSA6IG51bGwpO1xcblxcbiAgICAgICAgaWYgKCFtb3VzZSkge1xcbiAgICAgICAgICAgIGlmIChlbmdpbmUgJiYgZW5naW5lLnJlbmRlciAmJiBlbmdpbmUucmVuZGVyLmNhbnZhcykge1xcbiAgICAgICAgICAgICAgICBtb3VzZSA9IE1vdXNlLmNyZWF0ZShlbmdpbmUucmVuZGVyLmNhbnZhcyk7XFxuICAgICAgICAgICAgfSBlbHNlIGlmIChvcHRpb25zICYmIG9wdGlvbnMuZWxlbWVudCkge1xcbiAgICAgICAgICAgICAgICBtb3VzZSA9IE1vdXNlLmNyZWF0ZShvcHRpb25zLmVsZW1lbnQpO1xcbiAgICAgICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgICAgIG1vdXNlID0gTW91c2UuY3JlYXRlKCk7XFxuICAgICAgICAgICAgICAgIENvbW1vbi53YXJuKCdNb3VzZUNvbnN0cmFpbnQuY3JlYXRlOiBvcHRpb25zLm1vdXNlIHdhcyB1bmRlZmluZWQsIG9wdGlvbnMuZWxlbWVudCB3YXMgdW5kZWZpbmVkLCBtYXkgbm90IGZ1bmN0aW9uIGFzIGV4cGVjdGVkJyk7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcblxcbiAgICAgICAgdmFyIGNvbnN0cmFpbnQgPSBDb25zdHJhaW50LmNyZWF0ZSh7IFxcbiAgICAgICAgICAgIGxhYmVsOiAnTW91c2UgQ29uc3RyYWludCcsXFxuICAgICAgICAgICAgcG9pbnRBOiBtb3VzZS5wb3NpdGlvbixcXG4gICAgICAgICAgICBwb2ludEI6IHsgeDogMCwgeTogMCB9LFxcbiAgICAgICAgICAgIGxlbmd0aDogMC4wMSwgXFxuICAgICAgICAgICAgc3RpZmZuZXNzOiAwLjEsXFxuICAgICAgICAgICAgYW5ndWxhclN0aWZmbmVzczogMSxcXG4gICAgICAgICAgICByZW5kZXI6IHtcXG4gICAgICAgICAgICAgICAgc3Ryb2tlU3R5bGU6ICcjOTBFRTkwJyxcXG4gICAgICAgICAgICAgICAgbGluZVdpZHRoOiAzXFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfSk7XFxuXFxuICAgICAgICB2Y
2XIgZGVmYXVsdHMgPSB7XFxuICAgICAgICAgICAgdHlwZTogJ21vdXNlQ29uc3RyYWludCcsXFxuICAgICAgICAgICAgbW91c2U6IG1vdXNlLFxcbiAgICAgICAgICAgIGVsZW1lbnQ6IG51bGwsXFxuICAgICAgICAgICAgYm9keTogbnVsbCxcXG4gICAgICAgICAgICBjb25zdHJhaW50OiBjb25zdHJhaW50LFxcbiAgICAgICAgICAgIGNvbGxpc2lvbkZpbHRlcjoge1xcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogMHgwMDAxLFxcbiAgICAgICAgICAgICAgICBtYXNrOiAweEZGRkZGRkZGLFxcbiAgICAgICAgICAgICAgICBncm91cDogMFxcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH07XFxuXFxuICAgICAgICB2YXIgbW91c2VDb25zdHJhaW50ID0gQ29tbW9uLmV4dGVuZChkZWZhdWx0cywgb3B0aW9ucyk7XFxuXFxuICAgICAgICBFdmVudHMub24oZW5naW5lLCAnYmVmb3JlVXBkYXRlJywgZnVuY3Rpb24oKSB7XFxuICAgICAgICAgICAgdmFyIGFsbEJvZGllcyA9IENvbXBvc2l0ZS5hbGxCb2RpZXMoZW5naW5lLndvcmxkKTtcXG4gICAgICAgICAgICBNb3VzZUNvbnN0cmFpbnQudXBkYXRlKG1vdXNlQ29uc3RyYWludCwgYWxsQm9kaWVzKTtcXG4gICAgICAgICAgICBNb3VzZUNvbnN0cmFpbnQuX3RyaWdnZXJFdmVudHMobW91c2VDb25zdHJhaW50KTtcXG4gICAgICAgIH0pO1xcblxcbiAgICAgICAgcmV0dXJuIG1vdXNlQ29uc3RyYWludDtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFVwZGF0ZXMgdGhlIGdpdmVuIG1vdXNlIGNvbnN0cmFpbnQuXFxuICAgICAqIEBwcml2YXRlXFxuICAgICAqIEBtZXRob2QgdXBkYXRlXFxuICAgICAqIEBwYXJhbSB7TW91c2VDb25zdHJhaW50fSBtb3VzZUNvbnN0cmFpbnRcXG4gICAgICogQHBhcmFtIHtib2R5W119IGJvZGllc1xcbiAgICAgKi9cXG4gICAgTW91c2VDb25zdHJhaW50LnVwZGF0ZSA9IGZ1bmN0aW9uKG1vdXNlQ29uc3RyYWludCwgYm9kaWVzKSB7XFxuICAgICAgICB2Y
2XIgbW91c2UgPSBtb3VzZUNvbnN0cmFpbnQubW91c2UsXFxuICAgICAgICAgICAgY29uc3RyYWludCA9IG1vdXNlQ29uc3RyYWludC5jb25zdHJhaW50LFxcbiAgICAgICAgICAgIGJvZHkgPSBtb3VzZUNvbnN0cmFpbnQuYm9keTtcXG5cXG4gICAgICAgIGlmIChtb3VzZS5idXR0b24gPT09IDApIHtcXG4gICAgICAgICAgICBpZiAoIWNvbnN0cmFpbnQuYm9keUIpIHtcXG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBib2RpZXMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICAgICAgICAgIGJvZHkgPSBib2RpZXNbaV07XFxuICAgICAgICAgICAgICAgICAgICBpZiAoQm91bmRzLmNvbnRhaW5zKGJvZHkuYm91bmRzLCBtb3VzZS5wb3NpdGlvbikgXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICYmIERldGVjdG9yLmNhbkNvbGxpZGUoYm9keS5jb2xsaXNpb25GaWx0ZXIsIG1vdXNlQ29uc3RyYWludC5jb2xsaXNpb25GaWx0ZXIpKSB7XFxuICAgICAgICAgICAgICAgICAgICAgICAgZm9yICh2YXIgaiA9IGJvZHkucGFydHMubGVuZ3RoID4gMSA/IDEgOiAwOyBqIDwgYm9keS5wYXJ0cy5sZW5ndGg7IGorKykge1xcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcGFydCA9IGJvZHkucGFydHNbal07XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChWZXJ0aWNlcy5jb250YWlucyhwYXJ0LnZlcnRpY2VzLCBtb3VzZS5wb3NpdGlvbikpIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0cmFpbnQucG9pbnRBID0gbW91c2UucG9zaXRpb247XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdHJhaW50LmJvZHlCID0gbW91c2VDb25zdHJhaW50LmJvZHkgPSBib2R5O1xcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3RyYWludC5wb2ludEIgPSB7IHg6IG1vdXNlLnBvc2l0aW9uLnggLSBib2R5LnBvc2l0aW9uLngsIHk6IG1vdXNlLnBvc2l0aW9uLnkgLSBib2R5LnBvc2l0aW9uLnkgfTtcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0cmFpbnQuYW5nbGVCID0gYm9keS5hbmdsZTtcXG5cXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNsZWVwaW5nLnNldChib2R5LCBmYWxzZSk7XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBFdmVudHMudHJpZ2dlcihtb3VzZUNvbnN0cmFpbnQsICdzdGFydGRyYWcnLCB7IG1vdXNlOiBtb3VzZSwgYm9keTogYm9keSB9KTtcXG5cXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XFxuICAgICAgICAgICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgICAgICB9XFxuICAgICAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICAgICAgU2xlZXBpbmcuc2V0KGNvbnN0cmFpbnQuYm9keUIsIGZhbHNlKTtcXG4gICAgICAgICAgICAgICAgY29uc3RyYWludC5wb2ludEEgPSBtb3VzZS5wb3NpdGlvbjtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgIGNvbnN0cmFpbnQuYm9keUIgPSBtb3VzZUNvbnN0cmFpbnQuYm9keSA9IG51bGw7XFxuICAgICAgICAgICAgY29uc3RyYWludC5wb2ludEIgPSBudWxsO1xcblxcbiAgICAgICAgICAgIGlmIChib2R5KVxcbiAgICAgICAgICAgICAgICBFdmVudHMudHJpZ2dlcihtb3VzZUNvbnN0cmFpbnQsICdlbmRkcmFnJywgeyBtb3VzZTogbW91c2UsIGJvZHk6IGJvZHkgfSk7XFxuICAgICAgICB9XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBUcmlnZ2VycyBtb3VzZSBjb25zdHJhaW50IGV2ZW50cy5cXG4gICAgICogQG1ldGhvZCBfdHJpZ2dlckV2ZW50c1xcbiAgICAgKiBAcHJpdmF0ZVxcbiAgICAgKiBAcGFyYW0ge21vdXNlfSBtb3VzZUNvbnN0cmFpbnRcXG4gICAgICovXFxuICAgIE1vdXNlQ29uc3RyYWludC5fdHJpZ2dlckV2ZW50cyA9IGZ1bmN0aW9uKG1vdXNlQ29uc3RyYWludCkge1xcbiAgICAgICAgdmFyIG1vdXNlID0gbW91c2VDb25zdHJhaW50Lm1vdXNlLFxcbiAgICAgICAgICAgIG1vdXNlRXZlbnRzID0gbW91c2Uuc291cmNlRXZlbnRzO1xcblxcbiAgICAgICAgaWYgKG1vdXNlRXZlbnRzLm1vdXNlbW92ZSlcXG4gICAgICAgICAgICBFdmVudHMudHJpZ2dlcihtb3VzZUNvbnN0cmFpbnQsICdtb3VzZW1vdmUnLCB7IG1vdXNlOiBtb3VzZSB9KTtcXG5cXG4gICAgICAgIGlmIChtb3VzZUV2ZW50cy5tb3VzZWRvd24pXFxuICAgICAgICAgICAgRXZlbnRzLnRyaWdnZXIobW91c2VDb25zdHJhaW50LCAnbW91c2Vkb3duJywgeyBtb3VzZTogbW91c2UgfSk7XFxuXFxuICAgICAgICBpZiAobW91c2VFdmVudHMubW91c2V1cClcXG4gICAgICAgICAgICBFdmVudHMudHJpZ2dlcihtb3VzZUNvbnN0cmFpbnQsICdtb3VzZXVwJywgeyBtb3VzZTogbW91c2UgfSk7XFxuXFxuICAgICAgICAvLyByZXNldCB0aGUgbW91c2Ugc3RhdGUgcmVhZHkgZm9yIHRoZSBuZXh0IHN0ZXBcXG4gICAgICAgIE1vdXNlLmNsZWFyU291cmNlRXZlbnRzKG1vdXNlKTtcXG4gICAgfTtcXG5cXG4gICAgLypcXG4gICAgKlxcbiAgICAqICBFdmVudHMgRG9jdW1lbnRhdGlvblxcbiAgICAqXFxuICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAqIEZpcmVkIHdoZW4gdGhlIG1vdXNlIGhhcyBtb3ZlZCAob3IgYSB0b3VjaCBtb3ZlcykgZHVyaW5nIHRoZSBsYXN0IHN0ZXBcXG4gICAgKlxcbiAgICAqIEBldmVudCBtb3VzZW1vdmVcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQgQW4gZXZlbnQgb2JqZWN0XFxuICAgICogQHBhcmFtIHttb3VzZX0gZXZlbnQubW91c2UgVGhlIGVuZ2luZSdzIG1vdXNlIGluc3RhbmNlXFxuICAgICogQHBhcmFtIHt9IGV2ZW50LnNvdXJjZSBUaGUgc291cmNlIG9iamVjdCBvZiB0aGUgZXZlbnRcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQubmFtZSBUaGUgbmFtZSBvZiB0aGUgZXZlbnRcXG4gICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICogRmlyZWQgd2hlbiB0aGUgbW91c2UgaXMgZG93biAob3IgYSB0b3VjaCBoYXMgc3RhcnRlZCkgZHVyaW5nIHRoZSBsYXN0IHN0ZXBcXG4gICAgKlxcbiAgICAqIEBldmVudCBtb3VzZWRvd25cXG4gICAgKiBAcGFyYW0ge30gZXZlbnQgQW4gZXZlbnQgb2JqZWN0XFxuICAgICogQHBhcmFtIHttb3VzZX0gZXZlbnQubW91c2UgVGhlIGVuZ2luZSdzIG1vdXNlIGluc3RhbmNlXFxuICAgICogQHBhcmFtIHt9IGV2ZW50LnNvdXJjZSBUaGUgc291cmNlIG9iamVjdCBvZiB0aGUgZXZlbnRcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQubmFtZSBUaGUgbmFtZSBvZiB0aGUgZXZlbnRcXG4gICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICogRmlyZWQgd2hlbiB0aGUgbW91c2UgaXMgdXAgKG9yIGEgdG91Y2ggaGFzIGVuZGVkKSBkdXJpbmcgdGhlIGxhc3Qgc3RlcFxcbiAgICAqXFxuICAgICogQGV2ZW50IG1vdXNldXBcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQgQW4gZXZlbnQgb2JqZWN0XFxuICAgICogQHBhcmFtIHttb3VzZX0gZXZlbnQubW91c2UgVGhlIGVuZ2luZSdzIG1vdXNlIGluc3RhbmNlXFxuICAgICogQHBhcmFtIHt9IGV2ZW50LnNvdXJjZSBUaGUgc291cmNlIG9iamVjdCBvZiB0aGUgZXZlbnRcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQubmFtZSBUaGUgbmFtZSBvZiB0aGUgZXZlbnRcXG4gICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICogRmlyZWQgd2hlbiB0aGUgdXNlciBzdGFydHMgZHJhZ2dpbmcgYSBib2R5XFxuICAgICpcXG4gICAgKiBAZXZlbnQgc3RhcnRkcmFnXFxuICAgICogQHBhcmFtIHt9IGV2ZW50IEFuIGV2ZW50IG9iamVjdFxcbiAgICAqIEBwYXJhbSB7bW91c2V9IGV2ZW50Lm1vdXNlIFRoZSBlbmdpbmUncyBtb3VzZSBpbnN0YW5jZVxcbiAgICAqIEBwYXJhbSB7Ym9keX0gZXZlbnQuYm9keSBUaGUgYm9keSBiZWluZyBkcmFnZ2VkXFxuICAgICogQHBhcmFtIHt9IGV2ZW50LnNvdXJjZSBUaGUgc291cmNlIG9iamVjdCBvZiB0aGUgZXZlbnRcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQubmFtZSBUaGUgbmFtZSBvZiB0aGUgZXZlbnRcXG4gICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICogRmlyZWQgd2hlbiB0aGUgdXNlciBlbmRzIGRyYWdnaW5nIGEgYm9keVxcbiAgICAqXFxuICAgICogQGV2ZW50IGVuZGRyYWdcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQgQW4gZXZlbnQgb2JqZWN0XFxuICAgICogQHBhcmFtIHttb3VzZX0gZXZlbnQubW91c2UgVGhlIGVuZ2luZSdzIG1vdXNlIGluc3RhbmNlXFxuICAgICogQHBhcmFtIHtib2R5fSBldmVudC5ib2R5IFRoZSBib2R5IHRoYXQgaGFzIHN0b3BwZWQgYmVpbmcgZHJhZ2dlZFxcbiAgICAqIEBwYXJhbSB7fSBldmVudC5zb3VyY2UgVGhlIHNvdXJjZSBvYmplY3Qgb2YgdGhlIGV2ZW50XFxuICAgICogQHBhcmFtIHt9IGV2ZW50Lm5hbWUgVGhlIG5hbWUgb2YgdGhlIGV2ZW50XFxuICAgICovXFxuXFxuICAgIC8qXFxuICAgICpcXG4gICAgKiAgUHJvcGVydGllcyBEb2N1bWVudGF0aW9uXFxuICAgICpcXG4gICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEEgYFN0cmluZ2AgZGVub3RpbmcgdGhlIHR5cGUgb2Ygb2JqZWN0LlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgdHlwZVxcbiAgICAgKiBAdHlwZSBzdHJpbmdcXG4gICAgICogQGRlZmF1bHQgXFxcImNvbnN0cmFpbnRcXFwiXFxuICAgICAqIEByZWFkT25seVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIFRoZSBgTW91c2VgIGluc3RhbmNlIGluIHVzZS4gSWYgbm90IHN1cHBsaWVkIGluIGBNb3VzZUNvbnN0cmFpbnQuY3JlYXRlYCwgb25lIHdpbGwgYmUgY3JlYXRlZC5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IG1vdXNlXFxuICAgICAqIEB0eXBlIG1vdXNlXFxuICAgICAqIEBkZWZhdWx0IG1vdXNlXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogVGhlIGBCb2R5YCB0aGF0IGlzIGN1cnJlbnRseSBiZWluZyBtb3ZlZCBieSB0aGUgdXNlciwgb3IgYG51bGxgIGlmIG5vIGJvZHkuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBib2R5XFxuICAgICAqIEB0eXBlIGJvZHlcXG4gICAgICogQGRlZmF1bHQgbnVsbFxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIFRoZSBgQ29uc3RyYWludGAgb2JqZWN0IHRoYXQgaXMgdXNlZCB0byBtb3ZlIHRoZSBib2R5IGR1cmluZyBpbnRlcmFjdGlvbi5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IGNvbnN0cmFpbnRcXG4gICAgICogQHR5cGUgY29uc3RyYWludFxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEFuIGBPYmplY3RgIHRoYXQgc3BlY2lmaWVzIHRoZSBjb2xsaXNpb24gZmlsdGVyIHByb3BlcnRpZXMuXFxuICAgICAqIFRoZSBjb2xsaXNpb24gZmlsdGVyIGFsbG93cyB0aGUgdXNlciB0byBkZWZpbmUgd2h
2pY2ggdHlwZXMgb2YgYm9keSB0aGlzIG1vdXNlIGNvbnN0cmFpbnQgY2FuIGludGVyYWN0IHdpdGguXFxuICAgICAqIFNlZSBgYm9keS5jb2xsaXNpb25GaWx0ZXJgIGZvciBtb3JlIGluZm9ybWF0aW9uLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgY29sbGlzaW9uRmlsdGVyXFxuICAgICAqIEB0eXBlIG9iamVjdFxcbiAgICAgKi9cXG5cXG59KSgpO1xcblxcblxcbi8qKiovIH0pLFxcbi8qIDI1ICovXFxuLyoqKi8gKGZ1bmN0aW9uKG1vZHVsZSwgZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xcblxcbi8qKlxcbiogVGhlIGBNYXR0ZXIuUXVlcnlgIG1vZHVsZSBjb250YWlucyBtZXRob2RzIGZvciBwZXJmb3JtaW5nIGNvbGxpc2lvbiBxdWVyaWVzLlxcbipcXG4qIFNlZSB0aGUgaW5jbHVkZWQgdXNhZ2UgW2V4YW1wbGVzXShodHRwczovL2dpdGh1Yi5jb20vbGlhYnJ1L21hdHRlci1qcy90cmVlL21hc3Rlci9leGFtcGxlcykuXFxuKlxcbiogQGNsYXNzIFF1ZXJ5XFxuKi9cXG5cXG52YXIgUXVlcnkgPSB7fTtcXG5cXG5tb2R1bGUuZXhwb3J0cyA9IFF1ZXJ5O1xcblxcbnZhciBWZWN0b3IgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDIpO1xcbnZhciBDb2xsaXNpb24gPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDgpO1xcbnZhciBCb3VuZHMgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDEpO1xcbnZhciBCb2RpZXMgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDEyKTtcXG52YXIgVmVydGljZXMgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDMpO1xcblxcbihmdW5jdGlvbigpIHtcXG5cXG4gICAgLyoqXFxuICAgICAqIFJldHVybnMgYSBsaXN0IG9mIGNvbGxpc2lvbnMgYmV0d2VlbiBgYm9keWAgYW5kIGBib2RpZXNgLlxcbiAgICAgKiBAbWV0aG9kIGNvbGxpZGVzXFxuICAgICAqIEBwYXJhbSB7Ym9keX0gYm9keVxcbiAgICAgKiBAcGFyYW0ge2JvZHlbXX0gYm9kaWVzXFxuICAgICAqIEByZXR1cm4ge2NvbGxpc2lvbltdfSBDb2xsaXNpb25zXFxuICAgICAqL1xcbiAgICBRdWVyeS5jb2xsaWRlcyA9IGZ1bmN0aW9uKGJvZHksIGJvZGllcykge1xcbiAgICAgICAgdmFyIGNvbGxpc2lvbnMgPSBbXSxcXG4gICAgICAgICAgICBib2RpZXNMZW5ndGggPSBib2RpZXMubGVuZ3RoLFxcbiAgICAgICAgICAgIGJvdW5kcyA9IGJvZHkuYm91bmRzLFxcbiAgICAgICAgICAgIGNvbGxpZGVzID0gQ29sbGlzaW9uLmNvbGxpZGVzLFxcbiAgICAgICAgICAgIG92ZXJsYXBzID0gQm91bmRzLm92ZXJsYXBzO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBib2RpZXNMZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHZhciBib2R5QSA9IGJvZGllc1tpXSxcXG4gICAgICAgICAgICAgICAgcGFydHNBTGVuZ3RoID0gYm9keUEucGFydHMubGVuZ3RoLFxcbiAgICAgICAgICAgICAgICBwYXJ0c0FTdGFydCA9IHBhcnRzQUxlbmd0aCA9PT0gMSA/IDAgOiAxO1xcbiAgICAgICAgICAgIFxcbiAgICAgICAgICAgIGlmIChvdmVybGFwcyhib2R5QS5ib3VuZHMsIGJvdW5kcykpIHtcXG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaiA9IHBhcnRzQVN0YXJ0OyBqIDwgcGFydHNBTGVuZ3RoOyBqKyspIHtcXG4gICAgICAgICAgICAgICAgICAgIHZhciBwYXJ0ID0gYm9keUEucGFydHNbal07XFxuXFxuICAgICAgICAgICAgICAgICAgICBpZiAob3ZlcmxhcHMocGFydC5ib3VuZHMsIGJvdW5kcykpIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICB2Y
2XIgY29sbGlzaW9uID0gY29sbGlkZXMocGFydCwgYm9keSk7XFxuXFxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNvbGxpc2lvbikge1xcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xsaXNpb25zLnB1c2goY29sbGlzaW9uKTtcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XFxuICAgICAgICAgICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgICAgICB9XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcblxcbiAgICAgICAgcmV0dXJuIGNvbGxpc2lvbnM7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBDYXN0cyBhIHJheSBzZWdtZW50IGFnYWluc3QgYSBzZXQgb2YgYm9kaWVzIGFuZCByZXR1cm5zIGFsbCBjb2xsaXNpb25zLCByYXkgd2lkdGggaXMgb3B0aW9uYWwuIEludGVyc2VjdGlvbiBwb2ludHMgYXJlIG5vdCBwcm92aWRlZC5cXG4gICAgICogQG1ldGhvZCByYXlcXG4gICAgICogQHBhcmFtIHtib2R5W119IGJvZGllc1xcbiAgICAgKiBAcGFyYW0ge3ZlY3Rvcn0gc3RhcnRQb2ludFxcbiAgICAgKiBAcGFyYW0ge3ZlY3Rvcn0gZW5kUG9pbnRcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IFtyYXlXaWR0aF1cXG4gICAgICogQHJldHVybiB7Y29sbGlzaW9uW119IENvbGxpc2lvbnNcXG4gICAgICovXFxuICAgIFF1ZXJ5LnJheSA9IGZ1bmN0aW9uKGJvZGllcywgc3RhcnRQb2ludCwgZW5kUG9pbnQsIHJheVdpZHRoKSB7XFxuICAgICAgICByYXlXaWR0aCA9IHJheVdpZHRoIHx8IDFlLTEwMDtcXG5cXG4gICAgICAgIHZhciByYXlBbmdsZSA9IFZlY3Rvci5hbmdsZShzdGFydFBvaW50LCBlbmRQb2ludCksXFxuICAgICAgICAgICAgcmF5TGVuZ3RoID0gVmVjdG9yLm1hZ25pdHVkZShWZWN0b3Iuc3ViKHN0YXJ0UG9pbnQsIGVuZFBvaW50KSksXFxuICAgICAgICAgICAgcmF5WCA9IChlbmRQb2ludC54ICsgc3RhcnRQb2ludC54KSAqIDAuNSxcXG4gICAgICAgICAgICByYXlZID0gKGVuZFBvaW50LnkgKyBzdGFydFBvaW50LnkpICogMC41LFxcbiAgICAgICAgICAgIHJheSA9IEJvZGllcy5yZWN0YW5nbGUocmF5WCwgcmF5WSwgcmF5TGVuZ3RoLCByYXlXaWR0aCwgeyBhbmdsZTogcmF5QW5nbGUgfSksXFxuICAgICAgICAgICAgY29sbGlzaW9ucyA9IFF1ZXJ5LmNvbGxpZGVzKHJheSwgYm9kaWVzKTtcXG5cXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY29sbGlzaW9ucy5sZW5ndGg7IGkgKz0gMSkge1xcbiAgICAgICAgICAgIHZhciBjb2xsaXNpb24gPSBjb2xsaXNpb25zW2ldO1xcbiAgICAgICAgICAgIGNvbGxpc2lvbi5ib2R5ID0gY29sbGlzaW9uLmJvZHlCID0gY29sbGlzaW9uLmJvZHlBOyAgICAgICAgICAgIFxcbiAgICAgICAgfVxcblxcbiAgICAgICAgcmV0dXJuIGNvbGxpc2lvbnM7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIGFsbCBib2RpZXMgd2hvc2UgYm91bmRzIGFyZSBpbnNpZGUgKG9yIG91dHNpZGUgaWYgc2V0KSB0aGUgZ2l2ZW4gc2V0IG9mIGJvdW5kcywgZnJvbSB0aGUgZ2l2ZW4gc2V0IG9mIGJvZGllcy5cXG4gICAgICogQG1ldGhvZCByZWdpb25cXG4gICAgICogQHBhcmFtIHtib2R5W119IGJvZGllc1xcbiAgICAgKiBAcGFyYW0ge2JvdW5kc30gYm91bmRzXFxuICAgICAqIEBwYXJhbSB7Ym9vbH0gW291dHNpZGU9ZmFsc2VdXFxuICAgICAqIEByZXR1cm4ge2JvZHlbXX0gVGhlIGJvZGllcyBtYXRjaGluZyB0aGUgcXVlcnlcXG4gICAgICovXFxuICAgIFF1ZXJ5LnJlZ2lvbiA9IGZ1bmN0aW9uKGJvZGllcywgYm91bmRzLCBvdXRzaWRlKSB7XFxuICAgICAgICB2Y
2XIgcmVzdWx0ID0gW107XFxuXFxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJvZGllcy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHZhciBib2R5ID0gYm9kaWVzW2ldLFxcbiAgICAgICAgICAgICAgICBvdmVybGFwcyA9IEJvdW5kcy5vdmVybGFwcyhib2R5LmJvdW5kcywgYm91bmRzKTtcXG4gICAgICAgICAgICBpZiAoKG92ZXJsYXBzICYmICFvdXRzaWRlKSB8fCAoIW92ZXJsYXBzICYmIG91dHNpZGUpKVxcbiAgICAgICAgICAgICAgICByZXN1bHQucHVzaChib2R5KTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIHJldHVybiByZXN1bHQ7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZXR1cm5zIGFsbCBib2RpZXMgd2hvc2UgdmVydGljZXMgY29udGFpbiB0aGUgZ2l2ZW4gcG9pbnQsIGZyb20gdGhlIGdpdmVuIHNldCBvZiBib2RpZXMuXFxuICAgICAqIEBtZXRob2QgcG9pbnRcXG4gICAgICogQHBhcmFtIHtib2R5W119IGJvZGllc1xcbiAgICAgKiBAcGFyYW0ge3ZlY3Rvcn0gcG9pbnRcXG4gICAgICogQHJldHVybiB7Ym9keVtdfSBUaGUgYm9kaWVzIG1hdGNoaW5nIHRoZSBxdWVyeVxcbiAgICAgKi9cXG4gICAgUXVlcnkucG9pbnQgPSBmdW5jdGlvbihib2RpZXMsIHBvaW50KSB7XFxuICAgICAgICB2YXIgcmVzdWx0ID0gW107XFxuXFxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJvZGllcy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHZhciBib2R5ID0gYm9kaWVzW2ldO1xcbiAgICAgICAgICAgIFxcbiAgICAgICAgICAgIGlmIChCb3VuZHMuY29udGFpbnMoYm9keS5ib3VuZHMsIHBvaW50KSkge1xcbiAgICAgICAgICAgICAgICBmb3IgKHZhciBqID0gYm9keS5wYXJ0cy5sZW5ndGggPT09IDEgPyAwIDogMTsgaiA8IGJvZHkucGFydHMubGVuZ3RoOyBqKyspIHtcXG4gICAgICAgICAgICAgICAgICAgIHZhciBwYXJ0ID0gYm9keS5wYXJ0c1tqXTtcXG5cXG4gICAgICAgICAgICAgICAgICAgIGlmIChCb3VuZHMuY29udGFpbnMocGFydC5ib3VuZHMsIHBvaW50KVxcbiAgICAgICAgICAgICAgICAgICAgICAgICYmIFZlcnRpY2VzLmNvbnRhaW5zKHBhcnQudmVydGljZXMsIHBvaW50KSkge1xcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKGJvZHkpO1xcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xcbiAgICAgICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgICAgICB9XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcblxcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcXG4gICAgfTtcXG5cXG59KSgpO1xcblxcblxcbi8qKiovIH0pLFxcbi8qIDI2ICovXFxuLyoqKi8gKGZ1bmN0aW9uKG1vZHVsZSwgZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXykge1xcblxcbi8qKlxcbiogVGhlIGBNYXR0ZXIuUmVuZGVyYCBtb2R1bGUgaXMgYSBzaW1wbGUgY2FudmFzIGJhc2VkIHJlbmRlcmVyIGZvciB2aXN1YWxpc2luZyBpbnN0YW5jZXMgb2YgYE1hdHRlci5FbmdpbmVgLlxcbiogSXQgaXMgaW50ZW5kZWQgZm9yIGRldmVsb3BtZW50IGFuZCBkZWJ1Z2dpbmcgcHVycG9zZXMsIGJ1dCBtYXkgYWxzbyBiZSBzdWl0YWJsZSBmb3Igc2ltcGxlIGdhbWVzLlxcbiogSXQgaW5jbHVkZXMgYSBudW1iZXIgb2YgZHJhd2luZyBvcHRpb25zIGluY2x1ZGluZyB3aXJlZnJhbWUsIHZlY3RvciB3aXRoIHN1cHBvcnQgZm9yIHNwcml0ZXMgYW5kIHZpZXdwb3J0cy5cXG4qXFxuKiBAY2xhc3MgUmVuZGVyXFxuKi9cXG5cXG52YXIgUmVuZGVyID0ge307XFxuXFxubW9kdWxlLmV4cG9ydHMgPSBSZW5kZXI7XFxuXFxudmFyIEJvZHkgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDQpO1xcbnZhciBDb21tb24gPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDApO1xcbnZhciBDb21wb3NpdGUgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDYpO1xcbnZhciBCb3VuZHMgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDEpO1xcbnZhciBFdmVudHMgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDUpO1xcbnZhciBWZWN0b3IgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDIpO1xcbnZhciBNb3VzZSA9IF9fd2VicGFja19yZXF1aXJlX18oMTQpO1xcblxcbihmdW5jdGlvbigpIHtcXG5cXG4gICAgdmFyIF9yZXF1ZXN0QW5pbWF0aW9uRnJhbWUsXFxuICAgICAgICBfY2FuY2VsQW5pbWF0aW9uRnJhbWU7XFxuXFxuICAgIGlmICh0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJykge1xcbiAgICAgICAgX3JlcXVlc3RBbmltYXRpb25GcmFtZSA9IHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUgfHwgd2luZG93LndlYmtpdFJlcXVlc3RBbmltYXRpb25GcmFtZVxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfHwgd2luZG93Lm1velJlcXVlc3RBbmltYXRpb25GcmFtZSB8fCB3aW5kb3cubXNSZXF1ZXN0QW5pbWF0aW9uRnJhbWVcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHx8IGZ1bmN0aW9uKGNhbGxiYWNrKXsgd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24oKSB7IGNhbGxiYWNrKENvbW1vbi5ub3coKSk7IH0sIDEwMDAgLyA2MCk7IH07XFxuXFxuICAgICAgICBfY2FuY2VsQW5pbWF0aW9uRnJhbWUgPSB3aW5kb3cuY2FuY2VsQW5pbWF0aW9uRnJhbWUgfHwgd2luZG93Lm1vekNhbmNlbEFuaW1hdGlvbkZyYW1lXFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8fCB3aW5kb3cud2Via2l0Q2FuY2VsQW5pbWF0aW9uRnJhbWUgfHwgd2luZG93Lm1zQ2FuY2VsQW5pbWF0aW9uRnJhbWU7XFxuICAgIH1cXG5cXG4gICAgUmVuZGVyLl9nb29kRnBzID0gMzA7XFxuICAgIFJlbmRlci5fZ29vZERlbHRhID0gMTAwMCAvIDYwO1xcblxcbiAgICAvKipcXG4gICAgICogQ3JlYXRlcyBhIG5ldyByZW5kZXJlci4gVGhlIG9wdGlvbnMgcGFyYW1ldGVyIGlzIGFuIG9iamVjdCB0aGF0IHNwZWNpZmllcyBhbnkgcHJvcGVydGllcyB5b3Ugd2lzaCB0byBvdmVycmlkZSB0aGUgZGVmYXVsdHMuXFxuICAgICAqIEFsbCBwcm9wZXJ0aWVzIGhhdmUgZGVmYXVsdCB2YWx1ZXMsIGFuZCBtYW55IGFyZSBwcmUtY2FsY3VsYXRlZCBhdXRvbWF0aWNhbGx5IGJhc2VkIG9uIG90aGVyIHByb3BlcnRpZXMuXFxuICAgICAqIFNlZSB0aGUgcHJv
2cGVydGllcyBzZWN0aW9uIGJlbG93IGZvciBkZXRhaWxlZCBpbmZvcm1hdGlvbiBvbiB3aGF0IHlvdSBjYW4gcGFzcyB2aWEgdGhlIGBvcHRpb25zYCBvYmplY3QuXFxuICAgICAqIEBtZXRob2QgY3JlYXRlXFxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSBbb3B0aW9uc11cXG4gICAgICogQHJldHVybiB7cmVuZGVyfSBBIG5ldyByZW5kZXJlclxcbiAgICAgKi9cXG4gICAgUmVuZGVyLmNyZWF0ZSA9IGZ1bmN0aW9uKG9wdGlvbnMpIHtcXG4gICAgICAgIHZhciBkZWZhdWx0cyA9IHtcXG4gICAgICAgICAgICBlbmdpbmU6IG51bGwsXFxuICAgICAgICAgICAgZWxlbWVudDogbnVsbCxcXG4gICAgICAgICAgICBjYW52YXM6IG51bGwsXFxuICAgICAgICAgICAgbW91c2U6IG51bGwsXFxuICAgICAgICAgICAgZnJhbWVSZXF1ZXN0SWQ6IG51bGwsXFxuICAgICAgICAgICAgdGltaW5nOiB7XFxuICAgICAgICAgICAgICAgIGhpc3RvcnlTaXplOiA2MCxcXG4gICAgICAgICAgICAgICAgZGVsdGE6IDAsXFxuICAgICAgICAgICAgICAgIGRlbHRhSGlzdG9yeTogW10sXFxuICAgICAgICAgICAgICAgIGxhc3RUaW1lOiAwLFxcbiAgICAgICAgICAgICAgICBsYXN0VGltZXN0YW1wOiAwLFxcbiAgICAgICAgICAgICAgICBsYXN0RWxhcHNlZDogMCxcXG4gICAgICAgICAgICAgICAgdGltZXN0YW1wRWxhcHNlZDogMCxcXG4gICAgICAgICAgICAgICAgdGltZXN0YW1wRWxhcHNlZEhpc3Rvcnk6IFtdLFxcbiAgICAgICAgICAgICAgICBlbmdpbmVEZWx0YUhpc3Rvcnk6IFtdLFxcbiAgICAgICAgICAgICAgICBlbmdpbmVFbGFwc2VkSGlzdG9yeTogW10sXFxuICAgICAgICAgICAgICAgIGVsYXBzZWRIaXN0b3J5OiBbXVxcbiAgICAgICAgICAgIH0sXFxuICAgICAgICAgICAgb3B0aW9uczoge1xcbiAgICAgICAgICAgICAgICB3aWR0aDogODAwLFxcbiAgICAgICAgICAgICAgICBoZWlnaHQ6IDYwMCxcXG4gICAgICAgICAgICAgICAgcGl4ZWxSYXRpbzogMSxcXG4gICAgICAgICAgICAgICAgYmFja2dyb3VuZDogJyMxNDE1MWYnLFxcbiAgICAgICAgICAgICAgICB3aXJlZnJhbWVCYWNrZ3JvdW5kOiAnIzE0MTUxZicsXFxuICAgICAgICAgICAgICAgIGhhc0JvdW5kczogISFvcHRpb25zLmJvdW5kcyxcXG4gICAgICAgICAgICAgICAgZW5hYmxlZDogdHJ1ZSxcXG4gICAgICAgICAgICAgICAgd2lyZWZyYW1lczogdHJ1ZSxcXG4gICAgICAgICAgICAgICAgc2hvd1NsZWVwaW5nOiB0cnVlLFxcbiAgICAgICAgICAgICAgICBzaG93RGVidWc6IGZhbHNlLFxcbiAgICAgICAgICAgICAgICBzaG93U3RhdHM6IGZhbHNlLFxcbiAgICAgICAgICAgICAgICBzaG93UGVyZm9ybWFuY2U6IGZhbHNlLFxcbiAgICAgICAgICAgICAgICBzaG93Qm91bmRzOiBmYWxzZSxcXG4gICAgICAgICAgICAgICAgc2hvd1ZlbG9jaXR5OiBmYWxzZSxcXG4gICAgICAgICAgICAgICAgc2hvd0NvbGxpc2lvbnM6IGZhbHNlLFxcbiAgICAgICAgICAgICAgICBzaG93U2VwYXJhdGlvbnM6IGZhbHNlLFxcbiAgICAgICAgICAgICAgICBzaG93QXhlczogZmFsc2UsXFxuICAgICAgICAgICAgICAgIHNob3dQb3NpdGlvbnM6IGZhbHNlLFxcbiAgICAgICAgICAgICAgICBzaG93QW5nbGVJbmRpY2F0b3I6IGZhbHNlLFxcbiAgICAgICAgICAgICAgICBzaG93SWRzOiBmYWxzZSxcXG4gICAgICAgICAgICAgICAgc2hvd1ZlcnRleE51bWJlcnM6IGZhbHNlLFxcbiAgICAgICAgICAgICAgICBzaG93Q29udmV4SHVsbHM6IGZhbHNlLFxcbiAgICAgICAgICAgICAgICBzaG93SW50ZXJuYWxFZGdlczogZmFsc2UsXFxuICAgICAgICAgICAgICAgIHNob3dNb3VzZVBvc2l0aW9uOiBmYWxzZVxcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH07XFxuXFxuICAgICAgICB2Y
2XIgcmVuZGVyID0gQ29tbW9uLmV4dGVuZChkZWZhdWx0cywgb3B0aW9ucyk7XFxuXFxuICAgICAgICBpZiAocmVuZGVyLmNhbnZhcykge1xcbiAgICAgICAgICAgIHJlbmRlci5jYW52YXMud2lkdGggPSByZW5kZXIub3B0aW9ucy53aWR0aCB8fCByZW5kZXIuY2FudmFzLndpZHRoO1xcbiAgICAgICAgICAgIHJlbmRlci5jYW52YXMuaGVpZ2h0ID0gcmVuZGVyLm9wdGlvbnMuaGVpZ2h0IHx8IHJlbmRlci5jYW52YXMuaGVpZ2h0O1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgcmVuZGVyLm1vdXNlID0gb3B0aW9ucy5tb3VzZTtcXG4gICAgICAgIHJlbmRlci5lbmdpbmUgPSBvcHRpb25zLmVuZ2luZTtcXG4gICAgICAgIHJlbmRlci5jYW52YXMgPSByZW5kZXIuY2FudmFzIHx8IF9jcmVhdGVDYW52YXMocmVuZGVyLm9wdGlvbnMud2lkdGgsIHJlbmRlci5vcHRpb25zLmhlaWdodCk7XFxuICAgICAgICByZW5kZXIuY29udGV4dCA9IHJlbmRlci5jYW52YXMuZ2V0Q29udGV4dCgnMmQnKTtcXG4gICAgICAgIHJlbmRlci50ZXh0dXJlcyA9IHt9O1xcblxcbiAgICAgICAgcmVuZGVyLmJvdW5kcyA9IHJlbmRlci5ib3VuZHMgfHwge1xcbiAgICAgICAgICAgIG1pbjoge1xcbiAgICAgICAgICAgICAgICB4OiAwLFxcbiAgICAgICAgICAgICAgICB5OiAwXFxuICAgICAgICAgICAgfSxcXG4gICAgICAgICAgICBtYXg6IHtcXG4gICAgICAgICAgICAgICAgeDogcmVuZGVyLmNhbnZhcy53aWR0aCxcXG4gICAgICAgICAgICAgICAgeTogcmVuZGVyLmNhbnZhcy5oZWlnaHRcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9O1xcblxcbiAgICAgICAgLy8gZm9yIHRlbXBvcmFyeSBiYWNrIGNvbXBhdGliaWxpdHkgb25seVxcbiAgICAgICAgcmVuZGVyLmNvbnRyb2xsZXIgPSBSZW5kZXI7XFxuICAgICAgICByZW5kZXIub3B0aW9ucy5zaG93QnJvYWRwaGFzZSA9IGZhbHNlO1xcblxcbiAgICAgICAgaWYgKHJlbmRlci5vcHRpb25zLnBpeGVsUmF0aW8gIT09IDEpIHtcXG4gICAgICAgICAgICBSZW5kZXIuc2V0UGl4ZWxSYXRpbyhyZW5kZXIsIHJlbmRlci5vcHRpb25zLnBpeGVsUmF0aW8pO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgaWYgKENvbW1vbi5pc0VsZW1lbnQocmVuZGVyLmVsZW1lbnQpKSB7XFxuICAgICAgICAgICAgcmVuZGVyLmVsZW1lbnQuYXBwZW5kQ2hpbGQocmVuZGVyLmNhbnZhcyk7XFxuICAgICAgICB9XFxuXFxuICAgICAgICByZXR1cm4gcmVuZGVyO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogQ29udGludW91c2x5IHVwZGF0ZXMgdGhlIHJlbmRlciBjYW52YXMgb24gdGhlIGByZXF1ZXN0QW5pbWF0aW9uRnJhbWVgIGV2ZW50LlxcbiAgICAgKiBAbWV0aG9kIHJ1blxcbiAgICAgKiBAcGFyYW0ge3JlbmRlcn0gcmVuZGVyXFxuICAgICAqL1xcbiAgICBSZW5kZXIucnVuID0gZnVuY3Rpb24ocmVuZGVyKSB7XFxuICAgICAgICAoZnVuY3Rpb24gbG9vcCh0aW1lKXtcXG4gICAgICAgICAgICByZW5kZXIuZnJhbWVSZXF1ZXN0SWQgPSBfcmVxdWVzdEFuaW1hdGlvbkZyYW1lKGxvb3ApO1xcbiAgICAgICAgICAgIFxcbiAgICAgICAgICAgIF91cGRhdGVUaW1pbmcocmVuZGVyLCB0aW1lKTtcXG5cXG4gICAgICAgICAgICBSZW5kZXIud29ybGQocmVuZGVyLCB0aW1lKTtcXG5cXG4gICAgICAgICAgICBpZiAocmVuZGVyLm9wdGlvbnMuc2hvd1N0YXRzIHx8IHJlbmRlci5vcHRpb25zLnNob3dEZWJ1Zykge1xcbiAgICAgICAgICAgICAgICBSZW5kZXIuc3RhdHMocmVuZGVyLCByZW5kZXIuY29udGV4dCwgdGltZSk7XFxuICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgIGlmIChyZW5kZXIub3B0aW9ucy5zaG93UGVyZm9ybWFuY2UgfHwgcmVuZGVyLm9wdGlvbnMuc2hvd0RlYnVnKSB7XFxuICAgICAgICAgICAgICAgIFJlbmRlci5wZXJmb3JtYW5jZShyZW5kZXIsIHJlbmRlci5jb250ZXh0LCB0aW1lKTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9KSgpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogRW5kcyBleGVjdXRpb24gb2YgYFJlbmRlci5ydW5gIG9uIHRoZSBnaXZlbiBgcmVuZGVyYCwgYnkgY2FuY2VsaW5nIHRoZSBhbmltYXRpb24gZnJhbWUgcmVxdWVzdCBldmVudCBsb29wLlxcbiAgICAgKiBAbWV0aG9kIHN0b3BcXG4gICAgICogQHBhcmFtIHtyZW5kZXJ9IHJlbmRlclxcbiAgICAgKi9cXG4gICAgUmVuZGVyLnN0b3AgPSBmdW5jdGlvbihyZW5kZXIpIHtcXG4gICAgICAgIF9jYW5jZWxBbmltYXRpb25GcmFtZShyZW5kZXIuZnJhbWVSZXF1ZXN0SWQpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogU2V0cyB0aGUgcGl4ZWwgcmF0aW8gb2YgdGhlIHJlbmRlcmVyIGFuZCB1cGRhdGVzIHRoZSBjYW52YXMuXFxuICAgICAqIFRvIGF1dG9tYXRpY2FsbHkgZGV0ZWN0IHRoZSBjb3JyZWN0IHJhdGlvLCBwYXNzIHRoZSBzdHJpbmcgYCdhdXRvJ2AgZm9yIGBwaXhlbFJhdGlvYC5cXG4gICAgICogQG1ldGhvZCBzZXRQaXhlbFJhdGlvXFxuICAgICAqIEBwYXJhbSB7cmVuZGVyfSByZW5kZXJcXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHBpeGVsUmF0aW9cXG4gICAgICovXFxuICAgIFJlbmRlci5zZXRQaXhlbFJhdGlvID0gZnVuY3Rpb24ocmVuZGVyLCBwaXhlbFJhdGlvKSB7XFxuICAgICAgICB2Y
2XIgb3B0aW9ucyA9IHJlbmRlci5vcHRpb25zLFxcbiAgICAgICAgICAgIGNhbnZhcyA9IHJlbmRlci5jYW52YXM7XFxuXFxuICAgICAgICBpZiAocGl4ZWxSYXRpbyA9PT0gJ2F1dG8nKSB7XFxuICAgICAgICAgICAgcGl4ZWxSYXRpbyA9IF9nZXRQaXhlbFJhdGlvKGNhbnZhcyk7XFxuICAgICAgICB9XFxuXFxuICAgICAgICBvcHRpb25zLnBpeGVsUmF0aW8gPSBwaXhlbFJhdGlvO1xcbiAgICAgICAgY2FudmFzLnNldEF0dHJpYnV0ZSgnZGF0YS1waXhlbC1yYXRpbycsIHBpeGVsUmF0aW8pO1xcbiAgICAgICAgY2FudmFzLndpZHRoID0gb3B0aW9ucy53aWR0aCAqIHBpeGVsUmF0aW87XFxuICAgICAgICBjYW52YXMuaGVpZ2h0ID0gb3B0aW9ucy5oZWlnaHQgKiBwaXhlbFJhdGlvO1xcbiAgICAgICAgY2FudmFzLnN0eWxlLndpZHRoID0gb3B0aW9ucy53aWR0aCArICdweCc7XFxuICAgICAgICBjYW52YXMuc3R5bGUuaGVpZ2h0ID0gb3B0aW9ucy5oZWlnaHQgKyAncHgnO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUG9zaXRpb25zIGFuZCBzaXplcyB0aGUgdmlld3BvcnQgYXJvdW5kIHRoZSBnaXZlbiBvYmplY3QgYm91bmRzLlxcbiAgICAgKiBPYmplY3RzIG11c3QgaGF2ZSBhdCBsZWFzdCBvbmUgb2YgdGhlIGZvbGxvd2luZyBwcm9wZXJ0aWVzOlxcbiAgICAgKiAtIGBvYmplY3QuYm91bmRzYFxcbiAgICAgKiAtIGBvYmplY3QucG9zaXRpb25gXFxuICAgICAqIC0gYG9iamVjdC5taW5gIGFuZCBgb2JqZWN0Lm1heGBcXG4gICAgICogLSBgb2JqZWN0LnhgIGFuZCBgb2JqZWN0LnlgXFxuICAgICAqIEBtZXRob2QgbG9va0F0XFxuICAgICAqIEBwYXJhbSB7cmVuZGVyfSByZW5kZXJcXG4gICAgICogQHBhcmFtIHtvYmplY3RbXX0gb2JqZWN0c1xcbiAgICAgKiBAcGFyYW0ge3ZlY3Rvcn0gW3BhZGRpbmddXFxuICAgICAqIEBwYXJhbSB7Ym9vbH0gW2NlbnRlcj10cnVlXVxcbiAgICAgKi9cXG4gICAgUmVuZGVyLmxvb2tBdCA9IGZ1bmN0aW9uKHJlbmRlciwgb2JqZWN0cywgcGFkZGluZywgY2VudGVyKSB7XFxuICAgICAgICBjZW50ZXIgPSB0eXBlb2YgY2VudGVyICE9PSAndW5kZWZpbmVkJyA/IGNlbnRlciA6IHRydWU7XFxuICAgICAgICBvYmplY3RzID0gQ29tbW9uLmlzQXJyYXkob2JqZWN0cykgPyBvYmplY3RzIDogW29iamVjdHNdO1xcbiAgICAgICAgcGFkZGluZyA9IHBhZGRpbmcgfHwge1xcbiAgICAgICAgICAgIHg6IDAsXFxuICAgICAgICAgICAgeTogMFxcbiAgICAgICAgfTtcXG5cXG4gICAgICAgIC8vIGZpbmQgYm91bmRzIG9mIGFsbCBvYmplY3RzXFxuICAgICAgICB2Y
2XIgYm91bmRzID0ge1xcbiAgICAgICAgICAgIG1pbjogeyB4OiBJbmZpbml0eSwgeTogSW5maW5pdHkgfSxcXG4gICAgICAgICAgICBtYXg6IHsgeDogLUluZmluaXR5LCB5OiAtSW5maW5pdHkgfVxcbiAgICAgICAgfTtcXG5cXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgb2JqZWN0cy5sZW5ndGg7IGkgKz0gMSkge1xcbiAgICAgICAgICAgIHZhciBvYmplY3QgPSBvYmplY3RzW2ldLFxcbiAgICAgICAgICAgICAgICBtaW4gPSBvYmplY3QuYm91bmRzID8gb2JqZWN0LmJvdW5kcy5taW4gOiAob2JqZWN0Lm1pbiB8fCBvYmplY3QucG9zaXRpb24gfHwgb2JqZWN0KSxcXG4gICAgICAgICAgICAgICAgbWF4ID0gb2JqZWN0LmJvdW5kcyA/IG9iamVjdC5ib3VuZHMubWF4IDogKG9iamVjdC5tYXggfHwgb2JqZWN0LnBvc2l0aW9uIHx8IG9iamVjdCk7XFxuXFxuICAgICAgICAgICAgaWYgKG1pbiAmJiBtYXgpIHtcXG4gICAgICAgICAgICAgICAgaWYgKG1pbi54IDwgYm91bmRzLm1pbi54KVxcbiAgICAgICAgICAgICAgICAgICAgYm91bmRzLm1pbi54ID0gbWluLng7XFxuXFxuICAgICAgICAgICAgICAgIGlmIChtYXgueCA+IGJvdW5kcy5tYXgueClcXG4gICAgICAgICAgICAgICAgICAgIGJvdW5kcy5tYXgueCA9IG1heC54O1xcblxcbiAgICAgICAgICAgICAgICBpZiAobWluLnkgPCBib3VuZHMubWluLnkpXFxuICAgICAgICAgICAgICAgICAgICBib3VuZHMubWluLnkgPSBtaW4ueTtcXG5cXG4gICAgICAgICAgICAgICAgaWYgKG1heC55ID4gYm91bmRzLm1heC55KVxcbiAgICAgICAgICAgICAgICAgICAgYm91bmRzLm1heC55ID0gbWF4Lnk7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcblxcbiAgICAgICAgLy8gZmluZCByYXRpb3NcXG4gICAgICAgIHZhciB3aWR0aCA9IChib3VuZHMubWF4LnggLSBib3VuZHMubWluLngpICsgMiAqIHBhZGRpbmcueCxcXG4gICAgICAgICAgICBoZWlnaHQgPSAoYm91bmRzLm1heC55IC0gYm91bmRzLm1pbi55KSArIDIgKiBwYWRkaW5nLnksXFxuICAgICAgICAgICAgdmlld0hlaWdodCA9IHJlbmRlci5jYW52YXMuaGVpZ2h0LFxcbiAgICAgICAgICAgIHZpZXdXaWR0aCA9IHJlbmRlci5jYW52YXMud2lkdGgsXFxuICAgICAgICAgICAgb3V0ZXJSYXRpbyA9IHZpZXdXaWR0aCAvIHZpZXdIZWlnaHQsXFxuICAgICAgICAgICAgaW5uZXJSYXRpbyA9IHdpZHRoIC8gaGVpZ2h0LFxcbiAgICAgICAgICAgIHNjYWxlWCA9IDEsXFxuICAgICAgICAgICAgc2NhbGVZID0gMTtcXG5cXG4gICAgICAgIC8vIGZpbmQgc2NhbGUgZmFjdG9yXFxuICAgICAgICBpZiAoaW5uZXJSYXRpbyA+IG91dGVyUmF0aW8pIHtcXG4gICAgICAgICAgICBzY2FsZVkgPSBpbm5lclJhdGlvIC8gb3V0ZXJSYXRpbztcXG4gICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgc2NhbGVYID0gb3V0ZXJSYXRpbyAvIGlubmVyUmF0aW87XFxuICAgICAgICB9XFxuXFxuICAgICAgICAvLyBlbmFibGUgYm91bmRzXFxuICAgICAgICByZW5kZXIub3B0aW9ucy5oYXNCb3VuZHMgPSB0cnVlO1xcblxcbiAgICAgICAgLy8gcG9zaXRpb24gYW5kIHNpemVcXG4gICAgICAgIHJlbmRlci5ib3VuZHMubWluLnggPSBib3VuZHMubWluLng7XFxuICAgICAgICByZW5kZXIuYm91bmRzLm1heC54ID0gYm91bmRzLm1pbi54ICsgd2lkdGggKiBzY2FsZVg7XFxuICAgICAgICByZW5kZXIuYm91bmRzLm1pbi55ID0gYm91bmRzLm1pbi55O1xcbiAgICAgICAgcmVuZGVyLmJvdW5kcy5tYXgueSA9IGJvdW5kcy5taW4ueSArIGhlaWdodCAqIHNjYWxlWTtcXG5cXG4gICAgICAgIC8vIGNlbnRlclxcbiAgICAgICAgaWYgKGNlbnRlcikge1xcbiAgICAgICAgICAgIHJlbmRlci5ib3VuZHMubWluLnggKz0gd2lkdGggKiAwLjUgLSAod2lkdGggKiBzY2FsZVgpICogMC41O1xcbiAgICAgICAgICAgIHJlbmRlci5ib3VuZHMubWF4LnggKz0gd2lkdGggKiAwLjUgLSAod2lkdGggKiBzY2FsZVgpICogMC41O1xcbiAgICAgICAgICAgIHJlbmRlci5ib3VuZHMubWluLnkgKz0gaGVpZ2h0ICogMC41IC0gKGhlaWdodCAqIHNjYWxlWSkgKiAwLjU7XFxuICAgICAgICAgICAgcmVuZGVyLmJvdW5kcy5tYXgueSArPSBoZWlnaHQgKiAwLjUgLSAoaGVpZ2h0ICogc2NhbGVZKSAqIDAuNTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIC8vIHBhZGRpbmdcXG4gICAgICAgIHJlbmRlci5ib3VuZHMubWluLnggLT0gcGFkZGluZy54O1xcbiAgICAgICAgcmVuZGVyLmJvdW5kcy5tYXgueCAtPSBwYWRkaW5nLng7XFxuICAgICAgICByZW5kZXIuYm91bmRzLm1pbi55IC09IHBhZGRpbmcueTtcXG4gICAgICAgIHJlbmRlci5ib3VuZHMubWF4LnkgLT0gcGFkZGluZy55O1xcblxcbiAgICAgICAgLy8gdXBkYXRlIG1vdXNlXFxuICAgICAgICBpZiAocmVuZGVyLm1vdXNlKSB7XFxuICAgICAgICAgICAgTW91c2Uuc2V0U2NhbGUocmVuZGVyLm1vdXNlLCB7XFxuICAgICAgICAgICAgICAgIHg6IChyZW5kZXIuYm91bmRzLm1heC54IC0gcmVuZGVyLmJvdW5kcy5taW4ueCkgLyByZW5kZXIuY2FudmFzLndpZHRoLFxcbiAgICAgICAgICAgICAgICB5OiAocmVuZGVyLmJvdW5kcy5tYXgueSAtIHJlbmRlci5ib3VuZHMubWluLnkpIC8gcmVuZGVyLmNhbnZhcy5oZWlnaHRcXG4gICAgICAgICAgICB9KTtcXG5cXG4gICAgICAgICAgICBNb3VzZS5zZXRPZmZzZXQocmVuZGVyLm1vdXNlLCByZW5kZXIuYm91bmRzLm1pbik7XFxuICAgICAgICB9XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBBcHBsaWVzIHZpZXdwb3J0IHRyYW5zZm9ybXMgYmFzZWQgb24gYHJlbmRlci5ib3VuZHNgIHRvIGEgcmVuZGVyIGNvbnRleHQuXFxuICAgICAqIEBtZXRob2Qgc3RhcnRWaWV3VHJhbnNmb3JtXFxuICAgICAqIEBwYXJhbSB7cmVuZGVyfSByZW5kZXJcXG4gICAgICovXFxuICAgIFJlbmRlci5zdGFydFZpZXdUcmFuc2Zvcm0gPSBmdW5jdGlvbihyZW5kZXIpIHtcXG4gICAgICAgIHZhciBib3VuZHNXaWR0aCA9IHJlbmRlci5ib3VuZHMubWF4LnggLSByZW5kZXIuYm91bmRzLm1pbi54LFxcbiAgICAgICAgICAgIGJvdW5kc0hlaWdodCA9IHJlbmRlci5ib3VuZHMubWF4LnkgLSByZW5kZXIuYm91bmRzLm1pbi55LFxcbiAgICAgICAgICAgIGJvdW5kc1NjYWxlWCA9IGJvdW5kc1dpZHRoIC8gcmVuZGVyLm9wdGlvbnMud2lkdGgsXFxuICAgICAgICAgICAgYm91bmRzU2NhbGVZID0gYm91bmRzSGVpZ2h0IC8gcmVuZGVyLm9wdGlvbnMuaGVpZ2h0O1xcblxcbiAgICAgICAgcmVuZGVyLmNvbnRleHQuc2V0VHJhbnNmb3JtKFxcbiAgICAgICAgICAgI
2HJlbmRlci5vcHRpb25zLnBpeGVsUmF0aW8gLyBib3VuZHNTY2FsZVgsIDAsIDAsIFxcbiAgICAgICAgICAgIHJlbmRlci5vcHRpb25zLnBpeGVsUmF0aW8gLyBib3VuZHNTY2FsZVksIDAsIDBcXG4gICAgICAgICk7XFxuICAgICAgICBcXG4gICAgICAgIHJlbmRlci5jb250ZXh0LnRyYW5zbGF0ZSgtcmVuZGVyLmJvdW5kcy5taW4ueCwgLXJlbmRlci5ib3VuZHMubWluLnkpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmVzZXRzIGFsbCB0cmFuc2Zvcm1zIG9uIHRoZSByZW5kZXIgY29udGV4dC5cXG4gICAgICogQG1ldGhvZCBlbmRWaWV3VHJhbnNmb3JtXFxuICAgICAqIEBwYXJhbSB7cmVuZGVyfSByZW5kZXJcXG4gICAgICovXFxuICAgIFJlbmRlci5lbmRWaWV3VHJhbnNmb3JtID0gZnVuY3Rpb24ocmVuZGVyKSB7XFxuICAgICAgICByZW5kZXIuY29udGV4dC5zZXRUcmFuc2Zvcm0ocmVuZGVyLm9wdGlvbnMucGl4ZWxSYXRpbywgMCwgMCwgcmVuZGVyLm9wdGlvbnMucGl4ZWxSYXRpbywgMCwgMCk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZW5kZXJzIHRoZSBnaXZlbiBgZW5naW5lYCdzIGBNYXR0ZXIuV29ybGRgIG9iamVjdC5cXG4gICAgICogVGhpcyBpcyB0aGUgZW50cnkgcG9pbnQgZm9yIGFsbCByZW5kZXJpbmcgYW5kIHNob3VsZCBiZSBjYWxsZWQgZXZlcnkgdGltZSB0aGUgc2NlbmUgY2hhbmdlcy5cXG4gICAgICogQG1ldGhvZCB3b3JsZFxcbiAgICAgKiBAcGFyYW0ge3JlbmRlcn0gcmVuZGVyXFxuICAgICAqL1xcbiAgICBSZW5kZXIud29ybGQgPSBmdW5jdGlvbihyZW5kZXIsIHRpbWUpIHtcXG4gICAgICAgIHZhciBzdGFydFRpbWUgPSBDb21tb24ubm93KCksXFxuICAgICAgICAgICAgZW5naW5lID0gcmVuZGVyLmVuZ2luZSxcXG4gICAgICAgICAgICB3b3JsZCA9IGVuZ2luZS53b3JsZCxcXG4gICAgICAgICAgICBjYW52YXMgPSByZW5kZXIuY2FudmFzLFxcbiAgICAgICAgICAgIGNvbnRleHQgPSByZW5kZXIuY29udGV4dCxcXG4gICAgICAgICAgICBvcHRpb25zID0gcmVuZGVyLm9wdGlvbnMsXFxuICAgICAgICAgICAgdGltaW5nID0gcmVuZGVyLnRpbWluZztcXG5cXG4gICAgICAgIHZhciBhbGxCb2RpZXMgPSBDb21wb3NpdGUuYWxsQm9kaWVzKHdvcmxkKSxcXG4gICAgICAgICAgICBhbGxDb25zdHJhaW50cyA9IENvbXBvc2l0ZS5hbGxDb25zdHJhaW50cyh3b3JsZCksXFxuICAgICAgICAgICAgYmFja2dyb3VuZCA9IG9wdGlvbnMud2lyZWZyYW1lcyA/IG9wdGlvbnMud2lyZWZyYW1lQmFja2dyb3VuZCA6IG9wdGlvbnMuYmFja2dyb3VuZCxcXG4gICAgICAgICAgICBib2RpZXMgPSBbXSxcXG4gICAgICAgICAgICBjb25zdHJhaW50cyA9IFtdLFxcbiAgICAgICAgICAgIGk7XFxuXFxuICAgICAgICB2Y
2XIgZXZlbnQgPSB7XFxuICAgICAgICAgICAgdGltZXN0YW1wOiBlbmdpbmUudGltaW5nLnRpbWVzdGFtcFxcbiAgICAgICAgfTtcXG5cXG4gICAgICAgIEV2ZW50cy50cmlnZ2VyKHJlbmRlciwgJ2JlZm9yZVJlbmRlcicsIGV2ZW50KTtcXG5cXG4gICAgICAgIC8vIGFwcGx5IGJhY2tncm91bmQgaWYgaXQgaGFzIGNoYW5nZWRcXG4gICAgICAgIGlmIChyZW5kZXIuY3VycmVudEJhY2tncm91bmQgIT09IGJhY2tncm91bmQpXFxuICAgICAgICAgICAgX2FwcGx5QmFja2dyb3VuZChyZW5kZXIsIGJhY2tncm91bmQpO1xcblxcbiAgICAgICAgLy8gY2xlYXIgdGhlIGNhbnZhcyB3aXRoIGEgdHJhbnNwYXJlbnQgZmlsbCwgdG8gYWxsb3cgdGhlIGNhbnZhcyBiYWNrZ3JvdW5kIHRvIHNob3dcXG4gICAgICAgIGNvbnRleHQuZ2xvYmFsQ29tcG9zaXRlT3BlcmF0aW9uID0gJ3NvdXJjZS1pbic7XFxuICAgICAgICBjb250ZXh0LmZpbGxTdHlsZSA9IFxcXCJ0cmFuc3BhcmVudFxcXCI7XFxuICAgICAgICBjb250ZXh0LmZpbGxSZWN0KDAsIDAsIGNhbnZhcy53aWR0aCwgY2FudmFzLmhlaWdodCk7XFxuICAgICAgICBjb250ZXh0Lmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbiA9ICdzb3VyY2Utb3Zlcic7XFxuXFxuICAgICAgICAvLyBoYW5kbGUgYm91bmRzXFxuICAgICAgICBpZiAob3B0aW9ucy5oYXNCb3VuZHMpIHtcXG4gICAgICAgICAgICAvLyBmaWx0ZXIgb3V0IGJvZGllcyB0aGF0IGFyZSBub3QgaW4gdmlld1xcbiAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBhbGxCb2RpZXMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICAgICAgdmFyIGJvZHkgPSBhbGxCb2RpZXNbaV07XFxuICAgICAgICAgICAgICAgIGlmIChCb3VuZHMub3ZlcmxhcHMoYm9keS5ib3VuZHMsIHJlbmRlci5ib3VuZHMpKVxcbiAgICAgICAgICAgICAgICAgICAgYm9kaWVzLnB1c2goYm9keSk7XFxuICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgIC8vIGZpbHRlciBvdXQgY29uc3RyYWludHMgdGhhdCBhcmUgbm90IGluIHZpZXdcXG4gICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgYWxsQ29uc3RyYWludHMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICAgICAgdmFyIGNvbnN0cmFpbnQgPSBhbGxDb25zdHJhaW50c1tpXSxcXG4gICAgICAgICAgICAgICAgICAgIGJvZHlBID0gY29uc3RyYWludC5ib2R5QSxcXG4gICAgICAgICAgICAgICAgICAgIGJvZHlCID0gY29uc3RyYWludC5ib2R5QixcXG4gICAgICAgICAgICAgICAgICAgIHBvaW50QVdvcmxkID0gY29uc3RyYWludC5wb2ludEEsXFxuICAgICAgICAgICAgICAgICAgICBwb2ludEJXb3JsZCA9IGNvbnN0cmFpbnQucG9pbnRCO1xcblxcbiAgICAgICAgICAgICAgICBpZiAoYm9keUEpIHBvaW50QVdvcmxkID0gVmVjdG9yLmFkZChib2R5QS5wb3NpdGlvbiwgY29uc3RyYWludC5wb2ludEEpO1xcbiAgICAgICAgICAgICAgICBpZiAoYm9keUIpIHBvaW50QldvcmxkID0gVmVjdG9yLmFkZChib2R5Qi5wb3NpdGlvbiwgY29uc3RyYWludC5wb2ludEIpO1xcblxcbiAgICAgICAgICAgICAgICBpZiAoIXBvaW50QVdvcmxkIHx8ICFwb2ludEJXb3JsZClcXG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xcblxcbiAgICAgICAgICAgICAgICBpZiAoQm91bmRzLmNvbnRhaW5zKHJlbmRlci5ib3VuZHMsIHBvaW50QVdvcmxkKSB8fCBCb3VuZHMuY29udGFpbnMocmVuZGVyLmJvdW5kcywgcG9pbnRCV29ybGQpKVxcbiAgICAgICAgICAgICAgICAgICAgY29uc3RyYWludHMucHVzaChjb25zdHJhaW50KTtcXG4gICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgLy8gdHJhbnNmb3JtIHRoZSB2aWV3XFxuICAgICAgICAgICAgUmVuZGVyLnN0YXJ0Vmlld1RyYW5zZm9ybShyZW5kZXIpO1xcblxcbiAgICAgICAgICAgIC8vIHVwZGF0ZSBtb3VzZVxcbiAgICAgICAgICAgIGlmIChyZW5kZXIubW91c2UpIHtcXG4gICAgICAgICAgICAgICAgTW91c2Uuc2V0U2NhbGUocmVuZGVyLm1vdXNlLCB7XFxuICAgICAgICAgICAgICAgICAgICB4OiAocmVuZGVyLmJvdW5kcy5tYXgueCAtIHJlbmRlci5ib3VuZHMubWluLngpIC8gcmVuZGVyLm9wdGlvbnMud2lkdGgsXFxuICAgICAgICAgICAgICAgICAgICB5OiAocmVuZGVyLmJvdW5kcy5tYXgueSAtIHJlbmRlci5ib3VuZHMubWluLnkpIC8gcmVuZGVyLm9wdGlvbnMuaGVpZ2h0XFxuICAgICAgICAgICAgICAgIH0pO1xcblxcbiAgICAgICAgICAgICAgICBNb3VzZS5zZXRPZmZzZXQocmVuZGVyLm1vdXNlLCByZW5kZXIuYm91bmRzLm1pbik7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICBjb25zdHJhaW50cyA9IGFsbENvbnN0cmFpbnRzO1xcbiAgICAgICAgICAgIGJvZGllcyA9IGFsbEJvZGllcztcXG5cXG4gICAgICAgICAgICBpZiAocmVuZGVyLm9wdGlvbnMucGl4ZWxSYXRpbyAhPT0gMSkge1xcbiAgICAgICAgICAgICAgICByZW5kZXIuY29udGV4dC5zZXRUcmFuc2Zvcm0ocmVuZGVyLm9wdGlvbnMucGl4ZWxSYXRpbywgMCwgMCwgcmVuZGVyLm9wdGlvbnMucGl4ZWxSYXRpbywgMCwgMCk7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcblxcbiAgICAgICAgaWYgKCFvcHRpb25zLndpcmVmcmFtZXMgfHwgKGVuZ2luZS5lbmFibGVTbGVlcGluZyAmJiBvcHRpb25zLnNob3dTbGVlcGluZykpIHtcXG4gICAgICAgICAgICAvLyBmdWxseSBmZWF0dXJlZCByZW5kZXJpbmcgb2YgYm9kaWVzXFxuICAgICAgICAgICAgUmVuZGVyLmJvZGllcyhyZW5kZXIsIGJvZGllcywgY29udGV4dCk7XFxuICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgIGlmIChvcHRpb25zLnNob3dDb252ZXhIdWxscylcXG4gICAgICAgICAgICAgICAgUmVuZGVyLmJvZHlDb252ZXhIdWxscyhyZW5kZXIsIGJvZGllcywgY29udGV4dCk7XFxuXFxuICAgICAgICAgICAgLy8gb3B0aW1pc2VkIG1ldGhvZCBmb3Igd2lyZWZyYW1lcyBvbmx5XFxuICAgICAgICAgICAgUmVuZGVyLmJvZHlXaXJlZnJhbWVzKHJlbmRlciwgYm9kaWVzLCBjb250ZXh0KTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIGlmIChvcHRpb25zLnNob3dCb3VuZHMpXFxuICAgICAgICAgICAgUmVuZGVyLmJvZHlCb3VuZHMocmVuZGVyLCBib2RpZXMsIGNvbnRleHQpO1xcblxcbiAgICAgICAgaWYgKG9wdGlvbnMuc2hvd0F4ZXMgfHwgb3B0aW9ucy5zaG93QW5nbGVJbmRpY2F0b3IpXFxuICAgICAgICAgICAgUmVuZGVyLmJvZHlBeGVzKHJlbmRlciwgYm9kaWVzLCBjb250ZXh0KTtcXG5cXG4gICAgICAgIGlmIChvcHRpb25zLnNob3dQb3NpdGlvbnMpXFxuICAgICAgICAgICAgUmVuZGVyLmJvZHlQb3NpdGlvbnMocmVuZGVyLCBib2RpZXMsIGNvbnRleHQpO1xcblxcbiAgICAgICAgaWYgKG9wdGlvbnMuc2hvd1ZlbG9jaXR5KVxcbiAgICAgICAgICAgIFJlbmRlci5ib2R5VmVsb2NpdHkocmVuZGVyLCBib2RpZXMsIGNvbnRleHQpO1xcblxcbiAgICAgICAgaWYgKG9wdGlvbnMuc2hvd0lkcylcXG4gICAgICAgICAgICBSZW5kZXIuYm9keUlkcyhyZW5kZXIsIGJvZGllcywgY29udGV4dCk7XFxuXFxuICAgICAgICBpZiAob3B0aW9ucy5zaG93U2VwYXJhdGlvbnMpXFxuICAgICAgICAgICAgUmVuZGVyLnNlcGFyYXRpb25zKHJlbmRlciwgZW5naW5lLnBhaXJzLmx
2pc3QsIGNvbnRleHQpO1xcblxcbiAgICAgICAgaWYgKG9wdGlvbnMuc2hvd0NvbGxpc2lvbnMpXFxuICAgICAgICAgICAgUmVuZGVyLmNvbGxpc2lvbnMocmVuZGVyLCBlbmdpbmUucGFpcnMubGlzdCwgY29udGV4dCk7XFxuXFxuICAgICAgICBpZiAob3B0aW9ucy5zaG93VmVydGV4TnVtYmVycylcXG4gICAgICAgICAgICBSZW5kZXIudmVydGV4TnVtYmVycyhyZW5kZXIsIGJvZGllcywgY29udGV4dCk7XFxuXFxuICAgICAgICBpZiAob3B0aW9ucy5zaG93TW91c2VQb3NpdGlvbilcXG4gICAgICAgICAgICBSZW5kZXIubW91c2VQb3NpdGlvbihyZW5kZXIsIHJlbmRlci5tb3VzZSwgY29udGV4dCk7XFxuXFxuICAgICAgICBSZW5kZXIuY29uc3RyYWludHMoY29uc3RyYWludHMsIGNvbnRleHQpO1xcblxcbiAgICAgICAgaWYgKG9wdGlvbnMuaGFzQm91bmRzKSB7XFxuICAgICAgICAgICAgLy8gcmV2ZXJ0IHZpZXcgdHJhbnNmb3Jtc1xcbiAgICAgICAgICAgIFJlbmRlci5lbmRWaWV3VHJhbnNmb3JtKHJlbmRlcik7XFxuICAgICAgICB9XFxuXFxuICAgICAgICBFdmVudHMudHJpZ2dlcihyZW5kZXIsICdhZnRlclJlbmRlcicsIGV2ZW50KTtcXG5cXG4gICAgICAgIC8vIGxvZyB0aGUgdGltZSBlbGFwc2VkIGNvbXB1dGluZyB0aGlzIHVwZGF0ZVxcbiAgICAgICAgdGltaW5nLmxhc3RFbGFwc2VkID0gQ29tbW9uLm5vdygpIC0gc3RhcnRUaW1lO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmVuZGVycyBzdGF0aXN0aWNzIGFib3V0IHRoZSBlbmdpbmUgYW5kIHdvcmxkIHVzZWZ1bCBmb3IgZGVidWdnaW5nLlxcbiAgICAgKiBAcHJpdmF0ZVxcbiAgICAgKiBAbWV0aG9kIHN0YXRzXFxuICAgICAqIEBwYXJhbSB7cmVuZGVyfSByZW5kZXJcXG4gICAgICogQHBhcmFtIHtSZW5kZXJpbmdDb250ZXh0fSBjb250ZXh0XFxuICAgICAqIEBwYXJhbSB7TnVtYmVyfSB0aW1lXFxuICAgICAqL1xcbiAgICBSZW5kZXIuc3RhdHMgPSBmdW5jdGlvbihyZW5kZXIsIGNvbnRleHQsIHRpbWUpIHtcXG4gICAgICAgIHZhciBlbmdpbmUgPSByZW5kZXIuZW5naW5lLFxcbiAgICAgICAgICAgIHdvcmxkID0gZW5naW5lLndvcmxkLFxcbiAgICAgICAgICAgIGJvZGllcyA9IENvbXBvc2l0ZS5hbGxCb2RpZXMod29ybGQpLFxcbiAgICAgICAgICAgIHBhcnRzID0gMCxcXG4gICAgICAgICAgICB3aWR0aCA9IDU1LFxcbiAgICAgICAgICAgIGhlaWdodCA9IDQ0LFxcbiAgICAgICAgICAgIHggPSAwLFxcbiAgICAgICAgICAgIHkgPSAwO1xcbiAgICAgICAgXFxuICAgICAgICAvLyBjb3VudCBwYXJ0c1xcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBib2RpZXMubGVuZ3RoOyBpICs9IDEpIHtcXG4gICAgICAgICAgICBwYXJ0cyArPSBib2RpZXNbaV0ucGFydHMubGVuZ3RoO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgLy8gc2VjdGlvbnNcXG4gICAgICAgIHZhciBzZWN0aW9ucyA9IHtcXG4gICAgICAgICAgICAnUGFydCc6IHBhcnRzLFxcbiAgICAgICAgICAgICdCb2R5JzogYm9kaWVzLmxlbmd0aCxcXG4gICAgICAgICAgICAnQ29ucyc6IENvbXBvc2l0ZS5hbGxDb25zdHJhaW50cyh3b3JsZCkubGVuZ3RoLFxcbiAgICAgICAgICAgICdDb21wJzogQ29tcG9zaXRlLmFsbENvbXBvc2l0ZXMod29ybGQpLmxlbmd0aCxcXG4gICAgICAgICAgICAnUGFpcic6IGVuZ2luZS5wYWlycy5saXN0Lmxlbmd0aFxcbiAgICAgICAgfTtcXG5cXG4gICAgICAgIC8vIGJhY2tncm91bmRcXG4gICAgICAgIGNvbnRleHQuZmlsbFN0eWxlID0gJyMwZTBmMTknO1xcbiAgICAgICAgY29udGV4dC5maWxsUmVjdCh4LCB5LCB3aWR0aCAqIDUuNSwgaGVpZ2h0KTtcXG5cXG4gICAgICAgIGNvbnRleHQuZm9udCA9ICcxMnB4IEFyaWFsJztcXG4gICAgICAgIGNvbnRleHQudGV4dEJhc2VsaW5lID0gJ3RvcCc7XFxuICAgICAgICBjb250ZXh0LnRleHRBbGlnbiA9ICdyaWdodCc7XFxuXFxuICAgICAgICAvLyBzZWN0aW9uc1xcbiAgICAgICAgZm9yICh2YXIga2V5IGluIHNlY3Rpb25zKSB7XFxuICAgICAgICAgICAgdmFyIHNlY3Rpb24gPSBzZWN0aW9uc1trZXldO1xcbiAgICAgICAgICAgIC8vIGxhYmVsXFxuICAgICAgICAgICAgY29udGV4dC5maWxsU3R5bGUgPSAnI2FhYSc7XFxuICAgICAgICAgICAgY29udGV4dC5maWxsVGV4dChrZXksIHggKyB3aWR0aCwgeSArIDgpO1xcblxcbiAgICAgICAgICAgIC8vIHZhbHVlXFxuICAgICAgICAgICAgY29udGV4dC5maWxsU3R5bGUgPSAnI2VlZSc7XFxuICAgICAgICAgICAgY29udGV4dC5maWxsVGV4dChzZWN0aW9uLCB4ICsgd2lkdGgsIHkgKyAyNik7XFxuXFxuICAgICAgICAgICAgeCArPSB3aWR0aDtcXG4gICAgICAgIH1cXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFJlbmRlcnMgZW5naW5lIGFuZCByZW5kZXIgcGVyZm9ybWFuY2UgaW5mb3JtYXRpb24uXFxuICAgICAqIEBwcml2YXRlXFxuICAgICAqIEBtZXRob2QgcGVyZm9ybWFuY2VcXG4gICAgICogQHBhcmFtIHtyZW5kZXJ9IHJlbmRlclxcbiAgICAgKiBAcGFyYW0ge1JlbmRlcmluZ0NvbnRleHR9IGNvbnRleHRcXG4gICAgICovXFxuICAgIFJlbmRlci5wZXJmb3JtYW5jZSA9IGZ1bmN0aW9uKHJlbmRlciwgY29udGV4dCkge1xcbiAgICAgICAgdmFyIGVuZ2luZSA9IHJlbmRlci5lbmdpbmUsXFxuICAgICAgICAgICAgdGltaW5nID0gcmVuZGVyLnRpbWluZyxcXG4gICAgICAgICAgICBkZWx0YUhpc3RvcnkgPSB0aW1pbmcuZGVsdGFIaXN0b3J5LFxcbiAgICAgICAgICAgIGVsYXBzZWRIaXN0b3J5ID0gdGltaW5nLmVsYXBzZWRIaXN0b3J5LFxcbiAgICAgICAgICAgIHRpbWVzdGFtcEVsYXBzZWRIaXN0b3J5ID0gdGltaW5nLnRpbWVzdGFtcEVsYXBzZWRIaXN0b3J5LFxcbiAgICAgICAgICAgIGVuZ2luZURlbHRhSGlzdG9yeSA9IHRpbWluZy5lbmdpbmVEZWx0YUhpc3RvcnksXFxuICAgICAgICAgICAgZW5naW5lRWxhcHNlZEhpc3RvcnkgPSB0aW1pbmcuZW5naW5lRWxhcHNlZEhpc3RvcnksXFxuICAgICAgICAgICAgbGFzdEVuZ2luZURlbHRhID0gZW5naW5lLnRpbWluZy5sYXN0RGVsdGE7XFxuICAgICAgICBcXG4gICAgICAgI
2HZhciBkZWx0YU1lYW4gPSBfbWVhbihkZWx0YUhpc3RvcnkpLFxcbiAgICAgICAgICAgIGVsYXBzZWRNZWFuID0gX21lYW4oZWxhcHNlZEhpc3RvcnkpLFxcbiAgICAgICAgICAgIGVuZ2luZURlbHRhTWVhbiA9IF9tZWFuKGVuZ2luZURlbHRhSGlzdG9yeSksXFxuICAgICAgICAgICAgZW5naW5lRWxhcHNlZE1lYW4gPSBfbWVhbihlbmdpbmVFbGFwc2VkSGlzdG9yeSksXFxuICAgICAgICAgICAgdGltZXN0YW1wRWxhcHNlZE1lYW4gPSBfbWVhbih0aW1lc3RhbXBFbGFwc2VkSGlzdG9yeSksXFxuICAgICAgICAgICAgcmF0ZU1lYW4gPSAodGltZXN0YW1wRWxhcHNlZE1lYW4gLyBkZWx0YU1lYW4pIHx8IDAsXFxuICAgICAgICAgICAgZnBzID0gKDEwMDAgLyBkZWx0YU1lYW4pIHx8IDA7XFxuXFxuICAgICAgICB2YXIgZ3JhcGhIZWlnaHQgPSA0LFxcbiAgICAgICAgICAgIGdhcCA9IDEyLFxcbiAgICAgICAgICAgIHdpZHRoID0gNjAsXFxuICAgICAgICAgICAgaGVpZ2h0ID0gMzQsXFxuICAgICAgICAgICAgeCA9IDEwLFxcbiAgICAgICAgICAgIHkgPSA2OTtcXG5cXG4gICAgICAgIC8vIGJhY2tncm91bmRcXG4gICAgICAgIGNvbnRleHQuZmlsbFN0eWxlID0gJyMwZTBmMTknO1xcbiAgICAgICAgY29udGV4dC5maWxsUmVjdCgwLCA1MCwgZ2FwICogNCArIHdpZHRoICogNSArIDIyLCBoZWlnaHQpO1xcblxcbiAgICAgICAgLy8gc2hvdyBGUFNcXG4gICAgICAgIFJlbmRlci5zdGF0dXMoXFxuICAgICAgICAgICAgY29udGV4dCwgeCwgeSwgd2lkdGgsIGdyYXBoSGVpZ2h0LCBkZWx0YUhpc3RvcnkubGVuZ3RoLCBcXG4gICAgICAgICAgICBNYXRoLnJvdW5kKGZwcykgKyAnIGZwcycsIFxcbiAgICAgICAgICAgIGZwcyAvIFJlbmRlci5fZ29vZEZwcyxcXG4gICAgICAgICAgICBmdW5jdGlvbihpKSB7IHJldHVybiAoZGVsdGFIaXN0b3J5W2ldIC8gZGVsdGFNZWFuKSAtIDE7IH1cXG4gICAgICAgICk7XFxuXFxuICAgICAgICAvLyBzaG93IGVuZ2luZSBkZWx0YVxcbiAgICAgICAgUmVuZGVyLnN0YXR1cyhcXG4gICAgICAgICAgICBjb250ZXh0LCB4ICsgZ2FwICsgd2lkdGgsIHksIHdpZHRoLCBncmFwaEhlaWdodCwgZW5naW5lRGVsdGFIaXN0b3J5Lmxlbmd0aCxcXG4gICAgICAgICAgICBsYXN0RW5naW5lRGVsdGEudG9GaXhlZCgyKSArICcgZHQnLCBcXG4gICAgICAgICAgICBSZW5kZXIuX2dvb2REZWx0YSAvIGxhc3RFbmdpbmVEZWx0YSxcXG4gICAgICAgICAgICBmdW5jdGlvbihpKSB7IHJldHVybiAoZW5naW5lRGVsdGFIaXN0b3J5W2ldIC8gZW5naW5lRGVsdGFNZWFuKSAtIDE7IH1cXG4gICAgICAgICk7XFxuXFxuICAgICAgICAvLyBzaG93IGVuZ2luZSB1cGRhdGUgdGltZVxcbiAgICAgICAgUmVuZGVyLnN0YXR1cyhcXG4gICAgICAgICAgICBjb250ZXh0LCB4ICsgKGdhcCArIHdpZHRoKSAqIDIsIHksIHdpZHRoLCBncmFwaEhlaWdodCwgZW5naW5lRWxhcHNlZEhpc3RvcnkubGVuZ3RoLFxcbiAgICAgICAgICAgIGVuZ2luZUVsYXBzZWRNZWFuLnRvRml4ZWQoMikgKyAnIHV0JywgXFxuICAgICAgICAgICAgMSAtIChlbmdpbmVFbGFwc2VkTWVhbiAvIFJlbmRlci5fZ29vZEZwcyksXFxuICAgICAgICAgICAgZnVuY3Rpb24oaSkgeyByZXR1cm4gKGVuZ2luZUVsYXBzZWRIaXN0b3J5W2ldIC8gZW5naW5lRWxhcHNlZE1lYW4pIC0gMTsgfVxcbiAgICAgICAgKTtcXG5cXG4gICAgICAgIC8vIHNob3cgcmVuZGVyIHRpbWVcXG4gICAgICAgIFJlbmRlci5zdGF0dXMoXFxuICAgICAgICAgICAgY29udGV4dCwgeCArIChnYXAgKyB3aWR0aCkgKiAzLCB5LCB3aWR0aCwgZ3JhcGhIZWlnaHQsIGVsYXBzZWRIaXN0b3J5Lmxlbmd0aCxcXG4gICAgICAgICAgICBlbGFwc2VkTWVhbi50b0ZpeGVkKDIpICsgJyBydCcsIFxcbiAgICAgICAgICAgIDEgLSAoZWxhcHNlZE1lYW4gLyBSZW5kZXIuX2dvb2RGcHMpLFxcbiAgICAgICAgICAgIGZ1bmN0aW9uKGkpIHsgcmV0dXJuIChlbGFwc2VkSGlzdG9yeVtpXSAvIGVsYXBzZWRNZWFuKSAtIDE7IH1cXG4gICAgICAgICk7XFxuXFxuICAgICAgICAvLyBzaG93IGVmZmVjdGl2ZSBzcGVlZFxcbiAgICAgICAgUmVuZGVyLnN0YXR1cyhcXG4gICAgICAgICAgICBjb250ZXh0LCB4ICsgKGdhcCArIHdpZHRoKSAqIDQsIHksIHdpZHRoLCBncmFwaEhlaWdodCwgdGltZXN0YW1wRWxhcHNlZEhpc3RvcnkubGVuZ3RoLCBcXG4gICAgICAgICAgICByYXRlTWVhbi50b0ZpeGVkKDIpICsgJyB4JywgXFxuICAgICAgICAgICAgcmF0ZU1lYW4gKiByYXRlTWVhbiAqIHJhdGVNZWFuLFxcbiAgICAgICAgICAgIGZ1bmN0aW9uKGkpIHsgcmV0dXJuICgoKHRpbWVzdGFtcEVsYXBzZWRIaXN0b3J5W2ldIC8gZGVsdGFIaXN0b3J5W2ldKSAvIHJhdGVNZWFuKSB8fCAwKSAtIDE7IH1cXG4gICAgICAgICk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBSZW5kZXJzIGEgbGFiZWwsIGluZGljYXRvciBhbmQgYSBjaGFydC5cXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQG1ldGhvZCBzdGF0dXNcXG4gICAgICogQHBhcmFtIHtSZW5kZXJpbmdDb250ZXh0fSBjb250ZXh0XFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB4XFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB5XFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aFxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0XFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBjb3VudFxcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gbGFiZWxcXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGluZGljYXRvclxcbiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBwbG90WVxcbiAgICAgKi9cXG4gICAgUmVuZGVyLnN0YXR1cyA9IGZ1bmN0aW9uKGNvbnRleHQsIHgsIHksIHdpZHRoLCBoZWlnaHQsIGNvdW50LCBsYWJlbCwgaW5kaWNhdG9yLCBwbG90WSkge1xcbiAgICAgICAgLy8gYmFja2dyb3VuZFxcbiAgICAgICAgY29udGV4dC5zdHJva2VTdHlsZSA9ICcjODg4JztcXG4gICAgICAgIGNvbnRleHQuZmlsbFN0eWxlID0gJyM0NDQnO1xcbiAgICAgICAgY29udGV4dC5saW5lV2lkdGggPSAxO1xcbiAgICAgICAgY29udGV4dC5maWxsUmVjdCh4LCB5ICsgNywgd2lkdGgsIDEpO1xcblxcbiAgICAgICAgLy8gY2hhcnRcXG4gICAgICAgIGNvbnRleHQuYmVnaW5QYXRoKCk7XFxuICAgICAgICBjb250ZXh0Lm1vdmVUbyh4LCB5ICsgNyAtIGhlaWdodCAqIENvbW1vbi5jbGFtcCgwLjQgKiBwbG90WSgwKSwgLTIsIDIpKTtcXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgd2lkdGg7IGkgKz0gMSkge1xcbiAgICAgICAgICAgIGNvbnRleHQubGluZVRvKHggKyBpLCB5ICsgNyAtIChpIDwgY291bnQgPyBoZWlnaHQgKiBDb21tb24uY2xhbXAoMC40ICogcGxvdFkoaSksIC0yLCAyKSA6IDApKTtcXG4gICAgICAgI
2H1cXG4gICAgICAgIGNvbnRleHQuc3Ryb2tlKCk7XFxuXFxuICAgICAgICAvLyBpbmRpY2F0b3JcXG4gICAgICAgIGNvbnRleHQuZmlsbFN0eWxlID0gJ2hzbCgnICsgQ29tbW9uLmNsYW1wKDI1ICsgOTUgKiBpbmRpY2F0b3IsIDAsIDEyMCkgKyAnLDEwMCUsNjAlKSc7XFxuICAgICAgICBjb250ZXh0LmZpbGxSZWN0KHgsIHkgLSA3LCA0LCA0KTtcXG5cXG4gICAgICAgIC8vIGxhYmVsXFxuICAgICAgICBjb250ZXh0LmZvbnQgPSAnMTJweCBBcmlhbCc7XFxuICAgICAgICBjb250ZXh0LnRleHRCYXNlbGluZSA9ICdtaWRkbGUnO1xcbiAgICAgICAgY29udGV4dC50ZXh0QWxpZ24gPSAncmlnaHQnO1xcbiAgICAgICAgY29udGV4dC5maWxsU3R5bGUgPSAnI2VlZSc7XFxuICAgICAgICBjb250ZXh0LmZpbGxUZXh0KGxhYmVsLCB4ICsgd2lkdGgsIHkgLSA1KTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIERlc2NyaXB0aW9uXFxuICAgICAqIEBwcml2YXRlXFxuICAgICAqIEBtZXRob2QgY29uc3RyYWludHNcXG4gICAgICogQHBhcmFtIHtjb25zdHJhaW50W119IGNvbnN0cmFpbnRzXFxuICAgICAqIEBwYXJhbSB7UmVuZGVyaW5nQ29udGV4dH0gY29udGV4dFxcbiAgICAgKi9cXG4gICAgUmVuZGVyLmNvbnN0cmFpbnRzID0gZnVuY3Rpb24oY29uc3RyYWludHMsIGNvbnRleHQpIHtcXG4gICAgICAgIHZhciBjID0gY29udGV4dDtcXG5cXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY29uc3RyYWludHMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICB2Y
2XIgY29uc3RyYWludCA9IGNvbnN0cmFpbnRzW2ldO1xcblxcbiAgICAgICAgICAgIGlmICghY29uc3RyYWludC5yZW5kZXIudmlzaWJsZSB8fCAhY29uc3RyYWludC5wb2ludEEgfHwgIWNvbnN0cmFpbnQucG9pbnRCKVxcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcXG5cXG4gICAgICAgICAgICB2YXIgYm9keUEgPSBjb25zdHJhaW50LmJvZHlBLFxcbiAgICAgICAgICAgICAgICBib2R5QiA9IGNvbnN0cmFpbnQuYm9keUIsXFxuICAgICAgICAgICAgICAgIHN0YXJ0LFxcbiAgICAgICAgICAgICAgICBlbmQ7XFxuXFxuICAgICAgICAgICAgaWYgKGJvZHlBKSB7XFxuICAgICAgICAgICAgICAgIHN0YXJ0ID0gVmVjdG9yLmFkZChib2R5QS5wb3NpdGlvbiwgY29uc3RyYWludC5wb2ludEEpO1xcbiAgICAgICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgICAgIHN0YXJ0ID0gY29uc3RyYWludC5wb2ludEE7XFxuICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgIGlmIChjb25zdHJhaW50LnJlbmRlci50eXBlID09PSAncGluJykge1xcbiAgICAgICAgICAgICAgICBjLmJlZ2luUGF0aCgpO1xcbiAgICAgICAgICAgICAgICBjLmFyYyhzdGFydC54LCBzdGFydC55LCAzLCAwLCAyICogTWF0aC5QSSk7XFxuICAgICAgICAgICAgICAgIGMuY2xvc2VQYXRoKCk7XFxuICAgICAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICAgICAgaWYgKGJvZHlCKSB7XFxuICAgICAgICAgICAgICAgICAgICBlbmQgPSBWZWN0b3IuYWRkKGJvZHlCLnBvc2l0aW9uLCBjb25zdHJhaW50LnBvaW50Qik7XFxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgICAgICAgICBlbmQgPSBjb25zdHJhaW50LnBvaW50QjtcXG4gICAgICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgICAgICBjLmJlZ2luUGF0aCgpO1xcbiAgICAgICAgICAgICAgICBjLm1vdmVUbyhzdGFydC54LCBzdGFydC55KTtcXG5cXG4gICAgICAgICAgICAgICAgaWYgKGNvbnN0cmFpbnQucmVuZGVyLnR5cGUgPT09ICdzcHJpbmcnKSB7XFxuICAgICAgICAgICAgICAgICAgICB2Y
2XIgZGVsdGEgPSBWZWN0b3Iuc3ViKGVuZCwgc3RhcnQpLFxcbiAgICAgICAgICAgICAgICAgICAgICAgIG5vcm1hbCA9IFZlY3Rvci5wZXJwKFZlY3Rvci5ub3JtYWxpc2UoZGVsdGEpKSxcXG4gICAgICAgICAgICAgICAgICAgICAgICBjb2lscyA9IE1hdGguY2VpbChDb21tb24uY2xhbXAoY29uc3RyYWludC5sZW5ndGggLyA1LCAxMiwgMjApKSxcXG4gICAgICAgICAgICAgICAgICAgICAgICBvZmZzZXQ7XFxuXFxuICAgICAgICAgICAgICAgICAgICBmb3IgKHZhciBqID0gMTsgaiA8IGNvaWxzOyBqICs9IDEpIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICBvZmZzZXQgPSBqICUgMiA9PT0gMCA/IDEgOiAtMTtcXG5cXG4gICAgICAgICAgICAgICAgICAgICAgICBjLmxpbmVUbyhcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQueCArIGRlbHRhLnggKiAoaiAvIGNvaWxzKSArIG5vcm1hbC54ICogb2Zmc2V0ICogNCxcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnQueSArIGRlbHRhLnkgKiAoaiAvIGNvaWxzKSArIG5vcm1hbC55ICogb2Zmc2V0ICogNFxcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XFxuICAgICAgICAgICAgICAgICAgICB9XFxuICAgICAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICAgICAgYy5saW5lVG8oZW5kLngsIGVuZC55KTtcXG4gICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgaWYgKGNvbnN0cmFpbnQucmVuZGVyLmxpbmVXaWR0aCkge1xcbiAgICAgICAgICAgICAgICBjLmxpbmVXaWR0aCA9IGNvbnN0cmFpbnQucmVuZGVyLmxpbmVXaWR0aDtcXG4gICAgICAgICAgICAgICAgYy5zdHJva2VTdHlsZSA9IGNvbnN0cmFpbnQucmVuZGVyLnN0cm9rZVN0eWxlO1xcbiAgICAgICAgICAgICAgICBjLnN0cm9rZSgpO1xcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICBpZiAoY29uc3RyYWludC5yZW5kZXIuYW5jaG9ycykge1xcbiAgICAgICAgICAgICAgICBjLmZpbGxTdHlsZSA9IGNvbnN0cmFpbnQucmVuZGVyLnN0cm9rZVN0eWxlO1xcbiAgICAgICAgICAgICAgICBjLmJlZ2luUGF0aCgpO1xcbiAgICAgICAgICAgICAgICBjLmFyYyhzdGFydC54LCBzdGFydC55LCAzLCAwLCAyICogTWF0aC5QSSk7XFxuICAgICAgICAgICAgICAgIGMuYXJjKGVuZC54LCBlbmQueSwgMywgMCwgMiAqIE1hdGguUEkpO1xcbiAgICAgICAgICAgICAgICBjLmNsb3NlUGF0aCgpO1xcbiAgICAgICAgICAgICAgICBjLmZpbGwoKTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBEZXNjcmlwdGlvblxcbiAgICAgKiBAcHJpdmF0ZVxcbiAgICAgKiBAbWV0aG9kIGJvZGllc1xcbiAgICAgKiBAcGFyYW0ge3JlbmRlcn0gcmVuZGVyXFxuICAgICAqIEBwYXJhbSB7Ym9keVtdfSBib2RpZXNcXG4gICAgICogQHBhcmFtIHtSZW5kZXJpbmdDb250ZXh0fSBjb250ZXh0XFxuICAgICAqL1xcbiAgICBSZW5kZXIuYm9kaWVzID0gZnVuY3Rpb24ocmVuZGVyLCBib2RpZXMsIGNvbnRleHQpIHtcXG4gICAgICAgIHZhciBjID0gY29udGV4dCxcXG4gICAgICAgICAgICBlbmdpbmUgPSByZW5kZXIuZW5naW5lLFxcbiAgICAgICAgICAgIG9wdGlvbnMgPSByZW5kZXIub3B0aW9ucyxcXG4gICAgICAgICAgICBzaG93SW50ZXJuYWxFZGdlcyA9IG9wdGlvbnMuc2hvd0ludGVybmFsRWRnZXMgfHwgIW9wdGlvbnMud2lyZWZyYW1lcyxcXG4gICAgICAgICAgICBib2R5LFxcbiAgICAgICAgICAgIHBhcnQsXFxuICAgICAgICAgICAgaSxcXG4gICAgICAgICAgICBrO1xcblxcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGJvZGllcy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIGJvZHkgPSBib2RpZXNbaV07XFxuXFxuICAgICAgICAgICAgaWYgKCFib2R5LnJlbmRlci52aXNpYmxlKVxcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcXG5cXG4gICAgICAgICAgICAvLyBoYW5kbGUgY29tcG91bmQgcGFydHNcXG4gICAgICAgICAgICBmb3IgKGsgPSBib2R5LnBhcnRzLmxlbmd0aCA+IDEgPyAxIDogMDsgayA8IGJvZHkucGFydHMubGVuZ3RoOyBrKyspIHtcXG4gICAgICAgICAgICAgICAgcGFydCA9IGJvZHkucGFydHNba107XFxuXFxuICAgICAgICAgICAgICAgIGlmICghcGFydC5yZW5kZXIudmlzaWJsZSlcXG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xcblxcbiAgICAgICAgICAgICAgICBpZiAob3B0aW9ucy5zaG93U2xlZXBpbmcgJiYgYm9keS5pc1NsZWVwaW5nKSB7XFxuICAgICAgICAgICAgICAgICAgICBjLmdsb2JhbEFscGhhID0gMC41ICogcGFydC5yZW5kZXIub3BhY2l0eTtcXG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChwYXJ0LnJlbmRlci5vcGFjaXR5ICE9PSAxKSB7XFxuICAgICAgICAgICAgICAgICAgICBjLmdsb2JhbEFscGhhID0gcGFydC5yZW5kZXIub3BhY2l0eTtcXG4gICAgICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgICAgICBpZiAocGFydC5yZW5kZXIuc3ByaXRlICYmIHBhcnQucmVuZGVyLnNwcml0ZS50ZXh0dXJlICYmICFvcHRpb25zLndpcmVmcmFtZXMpIHtcXG4gICAgICAgICAgICAgICAgICAgIC8vIHBhcnQgc3ByaXRlXFxuICAgICAgICAgICAgICAgICAgICB2Y
2XIgc3ByaXRlID0gcGFydC5yZW5kZXIuc3ByaXRlLFxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRleHR1cmUgPSBfZ2V0VGV4dHVyZShyZW5kZXIsIHNwcml0ZS50ZXh0dXJlKTtcXG5cXG4gICAgICAgICAgICAgICAgICAgIGMudHJhbnNsYXRlKHBhcnQucG9zaXRpb24ueCwgcGFydC5wb3NpdGlvbi55KTtcXG4gICAgICAgICAgICAgICAgICAgIGMucm90YXRlKHBhcnQuYW5nbGUpO1xcblxcbiAgICAgICAgICAgICAgICAgICAgYy5kcmF3SW1hZ2UoXFxuICAgICAgICAgICAgICAgICAgICAgICAgdGV4dHVyZSxcXG4gICAgICAgICAgICAgICAgICAgICAgICB0ZXh0dXJlLndpZHRoICogLXNwcml0ZS54T2Zmc2V0ICogc3ByaXRlLnhTY2FsZSxcXG4gICAgICAgICAgICAgICAgICAgICAgICB0ZXh0dXJlLmhlaWdodCAqIC1zcHJpdGUueU9mZnNldCAqIHNwcml0ZS55U2NhbGUsXFxuICAgICAgICAgICAgICAgICAgICAgICAgdGV4dHVyZS53aWR0aCAqIHNwcml0ZS54U2NhbGUsXFxuICAgICAgICAgICAgICAgICAgICAgICAgdGV4dHVyZS5oZWlnaHQgKiBzcHJpdGUueVNjYWxlXFxuICAgICAgICAgICAgICAgICAgICApO1xcblxcbiAgICAgICAgICAgICAgICAgICAgLy8gcmV2ZXJ0IHRyYW5zbGF0aW9uLCBob3BlZnVsbHkgZmFzdGVyIHRoYW4gc2F2ZSAvIHJlc3RvcmVcXG4gICAgICAgICAgICAgICAgICAgIGMucm90YXRlKC1wYXJ0LmFuZ2xlKTtcXG4gICAgICAgICAgICAgICAgICAgIGMudHJhbnNsYXRlKC1wYXJ0LnBvc2l0aW9uLngsIC1wYXJ0LnBvc2l0aW9uLnkpO1xcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgICAgICAgICAgLy8gcGFydCBwb2x5Z29uXFxuICAgICAgICAgICAgICAgICAgICBpZiAocGFydC5jaXJjbGVSYWRpdXMpIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICBjLmJlZ2luUGF0aCgpO1xcbiAgICAgICAgICAgICAgICAgICAgICAgIGMuYXJjKHBhcnQucG9zaXRpb24ueCwgcGFydC5wb3NpdGlvbi55LCBwYXJ0LmNpcmNsZVJhZGl1cywgMCwgMiAqIE1hdGguUEkpO1xcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICBjLmJlZ2luUGF0aCgpO1xcbiAgICAgICAgICAgICAgICAgICAgICAgIGMubW92ZVRvKHBhcnQudmVydGljZXNbMF0ueCwgcGFydC52ZXJ0aWNlc1swXS55KTtcXG5cXG4gICAgICAgICAgICAgICAgICAgICAgICBmb3IgKHZhciBqID0gMTsgaiA8IHBhcnQudmVydGljZXMubGVuZ3RoOyBqKyspIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFwYXJ0LnZlcnRpY2VzW2ogLSAxXS5pc0ludGVybmFsIHx8IHNob3dJbnRlcm5hbEVkZ2VzKSB7XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjLmxpbmVUbyhwYXJ0LnZlcnRpY2VzW2pdLngsIHBhcnQudmVydGljZXNbal0ueSk7XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjLm1vdmVUbyhwYXJ0LnZlcnRpY2VzW2pdLngsIHBhcnQudmVydGljZXNbal0ueSk7XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBhcnQudmVydGljZXNbal0uaXNJbnRlcm5hbCAmJiAhc2hvd0ludGVybmFsRWRnZXMpIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMubW92ZVRvKHBhcnQudmVydGljZXNbKGogKyAxKSAlIHBhcnQudmVydGljZXMubGVuZ3RoXS54LCBwYXJ0LnZlcnRpY2VzWyhqICsgMSkgJSBwYXJ0LnZlcnRpY2VzLmxlbmd0aF0ueSk7XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cXG4gICAgICAgICAgICAgICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgICAgICAgICAgICAgYy5saW5lVG8ocGFydC52ZXJ0aWNlc1swXS54LCBwYXJ0LnZlcnRpY2VzWzBdLnkpO1xcbiAgICAgICAgICAgICAgICAgICAgICAgIGMuY2xvc2VQYXRoKCk7XFxuICAgICAgICAgICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgICAgICAgICBpZiAoIW9wdGlvbnMud2lyZWZyYW1lcykge1xcbiAgICAgICAgICAgICAgICAgICAgICAgIGMuZmlsbFN0eWxlID0gcGFydC5yZW5kZXIuZmlsbFN0eWxlO1xcblxcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChwYXJ0LnJlbmRlci5saW5lV2lkdGgpIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYy5saW5lV2lkdGggPSBwYXJ0LnJlbmRlci5saW5lV2lkdGg7XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMuc3Ryb2tlU3R5bGUgPSBwYXJ0LnJlbmRlci5zdHJva2VTdHlsZTtcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYy5zdHJva2UoKTtcXG4gICAgICAgICAgICAgICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgICAgICAgICAgICAgYy5maWxsKCk7XFxuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgICAgICAgICAgICAgIGMubGluZVdpZHRoID0gMTtcXG4gICAgICAgICAgICAgICAgICAgICAgICBjLnN0cm9rZVN0eWxlID0gJyNiYmInO1xcbiAgICAgICAgICAgICAgICAgICAgICAgIGMuc3Ryb2tlKCk7XFxuICAgICAgICAgICAgICAgICAgICB9XFxuICAgICAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICAgICAgYy5nbG9iYWxBbHBoYSA9IDE7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogT3B0aW1pc2VkIG1ldGhvZCBmb3IgZHJhd2luZyBib2R5IHdpcmVmcmFtZXMgaW4gb25lIHBhc3NcXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQG1ldGhvZCBib2R5V2lyZWZyYW1lc1xcbiAgICAgKiBAcGFyYW0ge3JlbmRlcn0gcmVuZGVyXFxuICAgICAqIEBwYXJhbSB7Ym9keVtdfSBib2RpZXNcXG4gICAgICogQHBhcmFtIHtSZW5kZXJpbmdDb250ZXh0fSBjb250ZXh0XFxuICAgICAqL1xcbiAgICBSZW5kZXIuYm9keVdpcmVmcmFtZXMgPSBmdW5jdGlvbihyZW5kZXIsIGJvZGllcywgY29udGV4dCkge1xcbiAgICAgICAgdmFyIGMgPSBjb250ZXh0LFxcbiAgICAgICAgICAgI
2HNob3dJbnRlcm5hbEVkZ2VzID0gcmVuZGVyLm9wdGlvbnMuc2hvd0ludGVybmFsRWRnZXMsXFxuICAgICAgICAgICAgYm9keSxcXG4gICAgICAgICAgICBwYXJ0LFxcbiAgICAgICAgICAgIGksXFxuICAgICAgICAgICAgaixcXG4gICAgICAgICAgICBrO1xcblxcbiAgICAgICAgYy5iZWdpblBhdGgoKTtcXG5cXG4gICAgICAgIC8vIHJlbmRlciBhbGwgYm9kaWVzXFxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgYm9kaWVzLmxlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgYm9keSA9IGJvZGllc1tpXTtcXG5cXG4gICAgICAgICAgICBpZiAoIWJvZHkucmVuZGVyLnZpc2libGUpXFxuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xcblxcbiAgICAgICAgICAgIC8vIGhhbmRsZSBjb21wb3VuZCBwYXJ0c1xcbiAgICAgICAgICAgIGZvciAoayA9IGJvZHkucGFydHMubGVuZ3RoID4gMSA/IDEgOiAwOyBrIDwgYm9keS5wYXJ0cy5sZW5ndGg7IGsrKykge1xcbiAgICAgICAgICAgICAgICBwYXJ0ID0gYm9keS5wYXJ0c1trXTtcXG5cXG4gICAgICAgICAgICAgICAgYy5tb3ZlVG8ocGFydC52ZXJ0aWNlc1swXS54LCBwYXJ0LnZlcnRpY2VzWzBdLnkpO1xcblxcbiAgICAgICAgICAgICAgICBmb3IgKGogPSAxOyBqIDwgcGFydC52ZXJ0aWNlcy5sZW5ndGg7IGorKykge1xcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFwYXJ0LnZlcnRpY2VzW2ogLSAxXS5pc0ludGVybmFsIHx8IHNob3dJbnRlcm5hbEVkZ2VzKSB7XFxuICAgICAgICAgICAgICAgICAgICAgICAgYy5saW5lVG8ocGFydC52ZXJ0aWNlc1tqXS54LCBwYXJ0LnZlcnRpY2VzW2pdLnkpO1xcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICBjLm1vdmVUbyhwYXJ0LnZlcnRpY2VzW2pdLngsIHBhcnQudmVydGljZXNbal0ueSk7XFxuICAgICAgICAgICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgICAgICAgICBpZiAocGFydC52ZXJ0aWNlc1tqXS5pc0ludGVybmFsICYmICFzaG93SW50ZXJuYWxFZGdlcykge1xcbiAgICAgICAgICAgICAgICAgICAgICAgIGMubW92ZVRvKHBhcnQudmVydGljZXNbKGogKyAxKSAlIHBhcnQudmVydGljZXMubGVuZ3RoXS54LCBwYXJ0LnZlcnRpY2VzWyhqICsgMSkgJSBwYXJ0LnZlcnRpY2VzLmxlbmd0aF0ueSk7XFxuICAgICAgICAgICAgICAgICAgICB9XFxuICAgICAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICAgICAgYy5saW5lVG8ocGFydC52ZXJ0aWNlc1swXS54LCBwYXJ0LnZlcnRpY2VzWzBdLnkpO1xcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG5cXG4gICAgICAgIGMubGluZVdpZHRoID0gMTtcXG4gICAgICAgIGMuc3Ryb2tlU3R5bGUgPSAnI2JiYic7XFxuICAgICAgICBjLnN0cm9rZSgpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogT3B0aW1pc2VkIG1ldGhvZCBmb3IgZHJhd2luZyBib2R5IGNvbnZleCBodWxsIHdpcmVmcmFtZXMgaW4gb25lIHBhc3NcXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQG1ldGhvZCBib2R5Q29udmV4SHVsbHNcXG4gICAgICogQHBhcmFtIHtyZW5kZXJ9IHJlbmRlclxcbiAgICAgKiBAcGFyYW0ge2JvZHlbXX0gYm9kaWVzXFxuICAgICAqIEBwYXJhbSB7UmVuZGVyaW5nQ29udGV4dH0gY29udGV4dFxcbiAgICAgKi9cXG4gICAgUmVuZGVyLmJvZHlDb252ZXhIdWxscyA9IGZ1bmN0aW9uKHJlbmRlciwgYm9kaWVzLCBjb250ZXh0KSB7XFxuICAgICAgICB2Y
2XIgYyA9IGNvbnRleHQsXFxuICAgICAgICAgICAgYm9keSxcXG4gICAgICAgICAgICBwYXJ0LFxcbiAgICAgICAgICAgIGksXFxuICAgICAgICAgICAgaixcXG4gICAgICAgICAgICBrO1xcblxcbiAgICAgICAgYy5iZWdpblBhdGgoKTtcXG5cXG4gICAgICAgIC8vIHJlbmRlciBjb252ZXggaHVsbHNcXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBib2RpZXMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICBib2R5ID0gYm9kaWVzW2ldO1xcblxcbiAgICAgICAgICAgIGlmICghYm9keS5yZW5kZXIudmlzaWJsZSB8fCBib2R5LnBhcnRzLmxlbmd0aCA9PT0gMSlcXG4gICAgICAgICAgICAgICAgY29udGludWU7XFxuXFxuICAgICAgICAgICAgYy5tb3ZlVG8oYm9keS52ZXJ0aWNlc1swXS54LCBib2R5LnZlcnRpY2VzWzBdLnkpO1xcblxcbiAgICAgICAgICAgIGZvciAoaiA9IDE7IGogPCBib2R5LnZlcnRpY2VzLmxlbmd0aDsgaisrKSB7XFxuICAgICAgICAgICAgICAgIGMubGluZVRvKGJvZHkudmVydGljZXNbal0ueCwgYm9keS52ZXJ0aWNlc1tqXS55KTtcXG4gICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgYy5saW5lVG8oYm9keS52ZXJ0aWNlc1swXS54LCBib2R5LnZlcnRpY2VzWzBdLnkpO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgYy5saW5lV2lkdGggPSAxO1xcbiAgICAgICAgYy5zdHJva2VTdHlsZSA9ICdyZ2JhKDI1NSwyNTUsMjU1LDAuMiknO1xcbiAgICAgICAgYy5zdHJva2UoKTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIFJlbmRlcnMgYm9keSB2ZXJ0ZXggbnVtYmVycy5cXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQG1ldGhvZCB2ZXJ0ZXhOdW1iZXJzXFxuICAgICAqIEBwYXJhbSB7cmVuZGVyfSByZW5kZXJcXG4gICAgICogQHBhcmFtIHtib2R5W119IGJvZGllc1xcbiAgICAgKiBAcGFyYW0ge1JlbmRlcmluZ0NvbnRleHR9IGNvbnRleHRcXG4gICAgICovXFxuICAgIFJlbmRlci52ZXJ0ZXhOdW1iZXJzID0gZnVuY3Rpb24ocmVuZGVyLCBib2RpZXMsIGNvbnRleHQpIHtcXG4gICAgICAgIHZhciBjID0gY29udGV4dCxcXG4gICAgICAgICAgICBpLFxcbiAgICAgICAgICAgIGosXFxuICAgICAgICAgICAgaztcXG5cXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBib2RpZXMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICB2Y
2XIgcGFydHMgPSBib2RpZXNbaV0ucGFydHM7XFxuICAgICAgICAgICAgZm9yIChrID0gcGFydHMubGVuZ3RoID4gMSA/IDEgOiAwOyBrIDwgcGFydHMubGVuZ3RoOyBrKyspIHtcXG4gICAgICAgICAgICAgICAgdmFyIHBhcnQgPSBwYXJ0c1trXTtcXG4gICAgICAgICAgICAgICAgZm9yIChqID0gMDsgaiA8IHBhcnQudmVydGljZXMubGVuZ3RoOyBqKyspIHtcXG4gICAgICAgICAgICAgICAgICAgIGMuZmlsbFN0eWxlID0gJ3JnYmEoMjU1LDI1NSwyNTUsMC4yKSc7XFxuICAgICAgICAgICAgICAgICAgICBjLmZpbGxUZXh0KGkgKyAnXycgKyBqLCBwYXJ0LnBvc2l0aW9uLnggKyAocGFydC52ZXJ0aWNlc1tqXS54IC0gcGFydC5wb3NpdGlvbi54KSAqIDAuOCwgcGFydC5wb3NpdGlvbi55ICsgKHBhcnQudmVydGljZXNbal0ueSAtIHBhcnQucG9zaXRpb24ueSkgKiAwLjgpO1xcbiAgICAgICAgICAgICAgICB9XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmVuZGVycyBtb3VzZSBwb3NpdGlvbi5cXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQG1ldGhvZCBtb3VzZVBvc2l0aW9uXFxuICAgICAqIEBwYXJhbSB7cmVuZGVyfSByZW5kZXJcXG4gICAgICogQHBhcmFtIHttb3VzZX0gbW91c2VcXG4gICAgICogQHBhcmFtIHtSZW5kZXJpbmdDb250ZXh0fSBjb250ZXh0XFxuICAgICAqL1xcbiAgICBSZW5kZXIubW91c2VQb3NpdGlvbiA9IGZ1bmN0aW9uKHJlbmRlciwgbW91c2UsIGNvbnRleHQpIHtcXG4gICAgICAgIHZhciBjID0gY29udGV4dDtcXG4gICAgICAgIGMuZmlsbFN0eWxlID0gJ3JnYmEoMjU1LDI1NSwyNTUsMC44KSc7XFxuICAgICAgICBjLmZpbGxUZXh0KG1vdXNlLnBvc2l0aW9uLnggKyAnICAnICsgbW91c2UucG9zaXRpb24ueSwgbW91c2UucG9zaXRpb24ueCArIDUsIG1vdXNlLnBvc2l0aW9uLnkgLSA1KTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIERyYXdzIGJvZHkgYm91bmRzXFxuICAgICAqIEBwcml2YXRlXFxuICAgICAqIEBtZXRob2QgYm9keUJvdW5kc1xcbiAgICAgKiBAcGFyYW0ge3JlbmRlcn0gcmVuZGVyXFxuICAgICAqIEBwYXJhbSB7Ym9keVtdfSBib2RpZXNcXG4gICAgICogQHBhcmFtIHtSZW5kZXJpbmdDb250ZXh0fSBjb250ZXh0XFxuICAgICAqL1xcbiAgICBSZW5kZXIuYm9keUJvdW5kcyA9IGZ1bmN0aW9uKHJlbmRlciwgYm9kaWVzLCBjb250ZXh0KSB7XFxuICAgICAgICB2Y
2XIgYyA9IGNvbnRleHQsXFxuICAgICAgICAgICAgZW5naW5lID0gcmVuZGVyLmVuZ2luZSxcXG4gICAgICAgICAgICBvcHRpb25zID0gcmVuZGVyLm9wdGlvbnM7XFxuXFxuICAgICAgICBjLmJlZ2luUGF0aCgpO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBib2RpZXMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICB2YXIgYm9keSA9IGJvZGllc1tpXTtcXG5cXG4gICAgICAgICAgICBpZiAoYm9keS5yZW5kZXIudmlzaWJsZSkge1xcbiAgICAgICAgICAgICAgICB2YXIgcGFydHMgPSBib2RpZXNbaV0ucGFydHM7XFxuICAgICAgICAgICAgICAgIGZvciAodmFyIGogPSBwYXJ0cy5sZW5ndGggPiAxID8gMSA6IDA7IGogPCBwYXJ0cy5sZW5ndGg7IGorKykge1xcbiAgICAgICAgICAgICAgICAgICAgdmFyIHBhcnQgPSBwYXJ0c1tqXTtcXG4gICAgICAgICAgICAgICAgICAgIGMucmVjdChwYXJ0LmJvdW5kcy5taW4ueCwgcGFydC5ib3VuZHMubWluLnksIHBhcnQuYm91bmRzLm1heC54IC0gcGFydC5ib3VuZHMubWluLngsIHBhcnQuYm91bmRzLm1heC55IC0gcGFydC5ib3VuZHMubWluLnkpO1xcbiAgICAgICAgICAgICAgICB9XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcblxcbiAgICAgICAgaWYgKG9wdGlvbnMud2lyZWZyYW1lcykge1xcbiAgICAgICAgICAgIGMuc3Ryb2tlU3R5bGUgPSAncmdiYSgyNTUsMjU1LDI1NSwwLjA4KSc7XFxuICAgICAgICB9IGVsc2Uge1xcbiAgICAgICAgICAgIGMuc3Ryb2tlU3R5bGUgPSAncmdiYSgwLDAsMCwwLjEpJztcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIGMubGluZVdpZHRoID0gMTtcXG4gICAgICAgIGMuc3Ryb2tlKCk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBEcmF3cyBib2R5IGFuZ2xlIGluZGljYXRvcnMgYW5kIGF4ZXNcXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQG1ldGhvZCBib2R5QXhlc1xcbiAgICAgKiBAcGFyYW0ge3JlbmRlcn0gcmVuZGVyXFxuICAgICAqIEBwYXJhbSB7Ym9keVtdfSBib2RpZXNcXG4gICAgICogQHBhcmFtIHtSZW5kZXJpbmdDb250ZXh0fSBjb250ZXh0XFxuICAgICAqL1xcbiAgICBSZW5kZXIuYm9keUF4ZXMgPSBmdW5jdGlvbihyZW5kZXIsIGJvZGllcywgY29udGV4dCkge1xcbiAgICAgICAgdmFyIGMgPSBjb250ZXh0LFxcbiAgICAgICAgICAgIGVuZ2luZSA9IHJlbmRlci5lbmdpbmUsXFxuICAgICAgICAgICAgb3B0aW9ucyA9IHJlbmRlci5vcHRpb25zLFxcbiAgICAgICAgICAgIHBhcnQsXFxuICAgICAgICAgICAgaSxcXG4gICAgICAgICAgICBqLFxcbiAgICAgICAgICAgIGs7XFxuXFxuICAgICAgICBjLmJlZ2luUGF0aCgpO1xcblxcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGJvZGllcy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHZhciBib2R5ID0gYm9kaWVzW2ldLFxcbiAgICAgICAgICAgICAgICBwYXJ0cyA9IGJvZHkucGFydHM7XFxuXFxuICAgICAgICAgICAgaWYgKCFib2R5LnJlbmRlci52aXNpYmxlKVxcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcXG5cXG4gICAgICAgICAgICBpZiAob3B0aW9ucy5zaG93QXhlcykge1xcbiAgICAgICAgICAgICAgICAvLyByZW5kZXIgYWxsIGF4ZXNcXG4gICAgICAgICAgICAgICAgZm9yIChqID0gcGFydHMubGVuZ3RoID4gMSA/IDEgOiAwOyBqIDwgcGFydHMubGVuZ3RoOyBqKyspIHtcXG4gICAgICAgICAgICAgICAgICAgIHBhcnQgPSBwYXJ0c1tqXTtcXG4gICAgICAgICAgICAgICAgICAgIGZvciAoayA9IDA7IGsgPCBwYXJ0LmF4ZXMubGVuZ3RoOyBrKyspIHtcXG4gICAgICAgICAgICAgICAgICAgICAgICB2Y
2XIgYXhpcyA9IHBhcnQuYXhlc1trXTtcXG4gICAgICAgICAgICAgICAgICAgICAgICBjLm1vdmVUbyhwYXJ0LnBvc2l0aW9uLngsIHBhcnQucG9zaXRpb24ueSk7XFxuICAgICAgICAgICAgICAgICAgICAgICAgYy5saW5lVG8ocGFydC5wb3NpdGlvbi54ICsgYXhpcy54ICogMjAsIHBhcnQucG9zaXRpb24ueSArIGF4aXMueSAqIDIwKTtcXG4gICAgICAgICAgICAgICAgICAgIH1cXG4gICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgICAgIGZvciAoaiA9IHBhcnRzLmxlbmd0aCA+IDEgPyAxIDogMDsgaiA8IHBhcnRzLmxlbmd0aDsgaisrKSB7XFxuICAgICAgICAgICAgICAgICAgICBwYXJ0ID0gcGFydHNbal07XFxuICAgICAgICAgICAgICAgICAgICBmb3IgKGsgPSAwOyBrIDwgcGFydC5heGVzLmxlbmd0aDsgaysrKSB7XFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmVuZGVyIGEgc2luZ2xlIGF4aXMgaW5kaWNhdG9yXFxuICAgICAgICAgICAgICAgICAgICAgICAgYy5tb3ZlVG8ocGFydC5wb3NpdGlvbi54LCBwYXJ0LnBvc2l0aW9uLnkpO1xcbiAgICAgICAgICAgICAgICAgICAgICAgIGMubGluZVRvKChwYXJ0LnZlcnRpY2VzWzBdLnggKyBwYXJ0LnZlcnRpY2VzW3BhcnQudmVydGljZXMubGVuZ3RoLTFdLngpIC8gMixcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKHBhcnQudmVydGljZXNbMF0ueSArIHBhcnQudmVydGljZXNbcGFydC52ZXJ0aWNlcy5sZW5ndGgtMV0ueSkgLyAyKTtcXG4gICAgICAgICAgICAgICAgICAgIH1cXG4gICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG5cXG4gICAgICAgIGlmIChvcHRpb25zLndpcmVmcmFtZXMpIHtcXG4gICAgICAgICAgICBjLnN0cm9rZVN0eWxlID0gJ2luZGlhbnJlZCc7XFxuICAgICAgICAgICAgYy5saW5lV2lkdGggPSAxO1xcbiAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICBjLnN0cm9rZVN0eWxlID0gJ3JnYmEoMjU1LCAyNTUsIDI1NSwgMC40KSc7XFxuICAgICAgICAgICAgYy5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb24gPSAnb3ZlcmxheSc7XFxuICAgICAgICAgICAgYy5saW5lV2lkdGggPSAyO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgYy5zdHJva2UoKTtcXG4gICAgICAgIGMuZ2xvYmFsQ29tcG9zaXRlT3BlcmF0aW9uID0gJ3NvdXJjZS1vdmVyJztcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIERyYXdzIGJvZHkgcG9zaXRpb25zXFxuICAgICAqIEBwcml2YXRlXFxuICAgICAqIEBtZXRob2QgYm9keVBvc2l0aW9uc1xcbiAgICAgKiBAcGFyYW0ge3JlbmRlcn0gcmVuZGVyXFxuICAgICAqIEBwYXJhbSB7Ym9keVtdfSBib2RpZXNcXG4gICAgICogQHBhcmFtIHtSZW5kZXJpbmdDb250ZXh0fSBjb250ZXh0XFxuICAgICAqL1xcbiAgICBSZW5kZXIuYm9keVBvc2l0aW9ucyA9IGZ1bmN0aW9uKHJlbmRlciwgYm9kaWVzLCBjb250ZXh0KSB7XFxuICAgICAgICB2Y
2XIgYyA9IGNvbnRleHQsXFxuICAgICAgICAgICAgZW5naW5lID0gcmVuZGVyLmVuZ2luZSxcXG4gICAgICAgICAgICBvcHRpb25zID0gcmVuZGVyLm9wdGlvbnMsXFxuICAgICAgICAgICAgYm9keSxcXG4gICAgICAgICAgICBwYXJ0LFxcbiAgICAgICAgICAgIGksXFxuICAgICAgICAgICAgaztcXG5cXG4gICAgICAgIGMuYmVnaW5QYXRoKCk7XFxuXFxuICAgICAgICAvLyByZW5kZXIgY3VycmVudCBwb3NpdGlvbnNcXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBib2RpZXMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICBib2R5ID0gYm9kaWVzW2ldO1xcblxcbiAgICAgICAgICAgIGlmICghYm9keS5yZW5kZXIudmlzaWJsZSlcXG4gICAgICAgICAgICAgICAgY29udGludWU7XFxuXFxuICAgICAgICAgICAgLy8gaGFuZGxlIGNvbXBvdW5kIHBhcnRzXFxuICAgICAgICAgICAgZm9yIChrID0gMDsgayA8IGJvZHkucGFydHMubGVuZ3RoOyBrKyspIHtcXG4gICAgICAgICAgICAgICAgcGFydCA9IGJvZHkucGFydHNba107XFxuICAgICAgICAgICAgICAgIGMuYXJjKHBhcnQucG9zaXRpb24ueCwgcGFydC5wb3NpdGlvbi55LCAzLCAwLCAyICogTWF0aC5QSSwgZmFsc2UpO1xcbiAgICAgICAgICAgICAgICBjLmNsb3NlUGF0aCgpO1xcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG5cXG4gICAgICAgIGlmIChvcHRpb25zLndpcmVmcmFtZXMpIHtcXG4gICAgICAgICAgICBjLmZpbGxTdHlsZSA9ICdpbmRpYW5yZWQnO1xcbiAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICBjLmZpbGxTdHlsZSA9ICdyZ2JhKDAsMCwwLDAuNSknO1xcbiAgICAgICAgfVxcbiAgICAgICAgYy5maWxsKCk7XFxuXFxuICAgICAgICBjLmJlZ2luUGF0aCgpO1xcblxcbiAgICAgICAgLy8gcmVuZGVyIHByZXZpb3VzIHBvc2l0aW9uc1xcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGJvZGllcy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIGJvZHkgPSBib2RpZXNbaV07XFxuICAgICAgICAgICAgaWYgKGJvZHkucmVuZGVyLnZpc2libGUpIHtcXG4gICAgICAgICAgICAgICAgYy5hcmMoYm9keS5wb3NpdGlvblByZXYueCwgYm9keS5wb3NpdGlvblByZXYueSwgMiwgMCwgMiAqIE1hdGguUEksIGZhbHNlKTtcXG4gICAgICAgICAgICAgICAgYy5jbG9zZVBhdGgoKTtcXG4gICAgICAgICAgICB9XFxuICAgICAgICB9XFxuXFxuICAgICAgICBjLmZpbGxTdHlsZSA9ICdyZ2JhKDI1NSwxNjUsMCwwLjgpJztcXG4gICAgICAgIGMuZmlsbCgpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogRHJhd3MgYm9keSB2ZWxvY2l0eVxcbiAgICAgKiBAcHJpdmF0ZVxcbiAgICAgKiBAbWV0aG9kIGJvZHlWZWxvY2l0eVxcbiAgICAgKiBAcGFyYW0ge3JlbmRlcn0gcmVuZGVyXFxuICAgICAqIEBwYXJhbSB7Ym9keVtdfSBib2RpZXNcXG4gICAgICogQHBhcmFtIHtSZW5kZXJpbmdDb250ZXh0fSBjb250ZXh0XFxuICAgICAqL1xcbiAgICBSZW5kZXIuYm9keVZlbG9jaXR5ID0gZnVuY3Rpb24ocmVuZGVyLCBib2RpZXMsIGNvbnRleHQpIHtcXG4gICAgICAgIHZhciBjID0gY29udGV4dDtcXG5cXG4gICAgICAgIGMuYmVnaW5QYXRoKCk7XFxuXFxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJvZGllcy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHZhciBib2R5ID0gYm9kaWVzW2ldO1xcblxcbiAgICAgICAgICAgIGlmICghYm9keS5yZW5kZXIudmlzaWJsZSlcXG4gICAgICAgICAgICAgICAgY29udGludWU7XFxuXFxuICAgICAgICAgICAgdmFyIHZlbG9jaXR5ID0gQm9keS5nZXRWZWxvY2l0eShib2R5KTtcXG5cXG4gICAgICAgICAgICBjLm1vdmVUbyhib2R5LnBvc2l0aW9uLngsIGJvZHkucG9zaXRpb24ueSk7XFxuICAgICAgICAgICAgYy5saW5lVG8oYm9keS5wb3NpdGlvbi54ICsgdmVsb2NpdHkueCwgYm9keS5wb3NpdGlvbi55ICsgdmVsb2NpdHkueSk7XFxuICAgICAgICB9XFxuXFxuICAgICAgICBjLmxpbmVXaWR0aCA9IDM7XFxuICAgICAgICBjLnN0cm9rZVN0eWxlID0gJ2Nvcm5mbG93ZXJibHVlJztcXG4gICAgICAgIGMuc3Ryb2tlKCk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBEcmF3cyBib2R5IGlkc1xcbiAgICAgKiBAcHJpdmF0ZVxcbiAgICAgKiBAbWV0aG9kIGJvZHlJZHNcXG4gICAgICogQHBhcmFtIHtyZW5kZXJ9IHJlbmRlclxcbiAgICAgKiBAcGFyYW0ge2JvZHlbXX0gYm9kaWVzXFxuICAgICAqIEBwYXJhbSB7UmVuZGVyaW5nQ29udGV4dH0gY29udGV4dFxcbiAgICAgKi9cXG4gICAgUmVuZGVyLmJvZHlJZHMgPSBmdW5jdGlvbihyZW5kZXIsIGJvZGllcywgY29udGV4dCkge1xcbiAgICAgICAgdmFyIGMgPSBjb250ZXh0LFxcbiAgICAgICAgICAgIGksXFxuICAgICAgICAgICAgajtcXG5cXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBib2RpZXMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICBpZiAoIWJvZGllc1tpXS5yZW5kZXIudmlzaWJsZSlcXG4gICAgICAgICAgICAgICAgY29udGludWU7XFxuXFxuICAgICAgICAgICAgdmFyIHBhcnRzID0gYm9kaWVzW2ldLnBhcnRzO1xcbiAgICAgICAgICAgIGZvciAoaiA9IHBhcnRzLmxlbmd0aCA+IDEgPyAxIDogMDsgaiA8IHBhcnRzLmxlbmd0aDsgaisrKSB7XFxuICAgICAgICAgICAgICAgIHZhciBwYXJ0ID0gcGFydHNbal07XFxuICAgICAgICAgICAgICAgIGMuZm9udCA9IFxcXCIxMnB4IEFyaWFsXFxcIjtcXG4gICAgICAgICAgICAgICAgYy5maWxsU3R5bGUgPSAncmdiYSgyNTUsMjU1LDI1NSwwLjUpJztcXG4gICAgICAgICAgICAgICAgYy5maWxsVGV4dChwYXJ0LmlkLCBwYXJ0LnBvc2l0aW9uLnggKyAxMCwgcGFydC5wb3NpdGlvbi55IC0gMTApO1xcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIERlc2NyaXB0aW9uXFxuICAgICAqIEBwcml2YXRlXFxuICAgICAqIEBtZXRob2QgY29sbGlzaW9uc1xcbiAgICAgKiBAcGFyYW0ge3JlbmRlcn0gcmVuZGVyXFxuICAgICAqIEBwYXJhbSB7cGFpcltdfSBwYWlyc1xcbiAgICAgKiBAcGFyYW0ge1JlbmRlcmluZ0NvbnRleHR9IGNvbnRleHRcXG4gICAgICovXFxuICAgIFJlbmRlci5jb2xsaXNpb25zID0gZnVuY3Rpb24ocmVuZGVyLCBwYWlycywgY29udGV4dCkge1xcbiAgICAgICAgdmFyIGMgPSBjb250ZXh0LFxcbiAgICAgICAgICAgIG9wdGlvbnMgPSByZW5kZXIub3B0aW9ucyxcXG4gICAgICAgICAgICBwYWlyLFxcbiAgICAgICAgICAgIGNvbGxpc2lvbixcXG4gICAgICAgICAgICBjb3JyZWN0ZWQsXFxuICAgICAgICAgICAgYm9keUEsXFxuICAgICAgICAgICAgYm9keUIsXFxuICAgICAgICAgICAgaSxcXG4gICAgICAgICAgICBqO1xcblxcbiAgICAgICAgYy5iZWdpblBhdGgoKTtcXG5cXG4gICAgICAgIC8vIHJlbmRlciBjb2xsaXNpb24gcG9zaXRpb25zXFxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgcGFpcnMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICBwYWlyID0gcGFpcnNbaV07XFxuXFxuICAgICAgICAgICAgaWYgKCFwYWlyLmlzQWN0aXZlKVxcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcXG5cXG4gICAgICAgICAgICBjb2xsaXNpb24gPSBwYWlyLmNvbGxpc2lvbjtcXG4gICAgICAgICAgICBmb3IgKGogPSAwOyBqIDwgcGFpci5hY3RpdmVDb250YWN0cy5sZW5ndGg7IGorKykge1xcbiAgICAgICAgICAgICAgICB2Y
2XIgY29udGFjdCA9IHBhaXIuYWN0aXZlQ29udGFjdHNbal0sXFxuICAgICAgICAgICAgICAgICAgICB2ZXJ0ZXggPSBjb250YWN0LnZlcnRleDtcXG4gICAgICAgICAgICAgICAgYy5yZWN0KHZlcnRleC54IC0gMS41LCB2ZXJ0ZXgueSAtIDEuNSwgMy41LCAzLjUpO1xcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG5cXG4gICAgICAgIGlmIChvcHRpb25zLndpcmVmcmFtZXMpIHtcXG4gICAgICAgICAgICBjLmZpbGxTdHlsZSA9ICdyZ2JhKDI1NSwyNTUsMjU1LDAuNyknO1xcbiAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICBjLmZpbGxTdHlsZSA9ICdvcmFuZ2UnO1xcbiAgICAgICAgfVxcbiAgICAgICAgYy5maWxsKCk7XFxuXFxuICAgICAgICBjLmJlZ2luUGF0aCgpO1xcblxcbiAgICAgICAgLy8gcmVuZGVyIGNvbGxpc2lvbiBub3JtYWxzXFxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgcGFpcnMubGVuZ3RoOyBpKyspIHtcXG4gICAgICAgICAgICBwYWlyID0gcGFpcnNbaV07XFxuXFxuICAgICAgICAgICAgaWYgKCFwYWlyLmlzQWN0aXZlKVxcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcXG5cXG4gICAgICAgICAgICBjb2xsaXNpb24gPSBwYWlyLmNvbGxpc2lvbjtcXG5cXG4gICAgICAgICAgICBpZiAocGFpci5hY3RpdmVDb250YWN0cy5sZW5ndGggPiAwKSB7XFxuICAgICAgICAgICAgICAgIHZhciBub3JtYWxQb3NYID0gcGFpci5hY3RpdmVDb250YWN0c1swXS52ZXJ0ZXgueCxcXG4gICAgICAgICAgICAgICAgICAgIG5vcm1hbFBvc1kgPSBwYWlyLmFjdGl2ZUNvbnRhY3RzWzBdLnZlcnRleC55O1xcblxcbiAgICAgICAgICAgICAgICBpZiAocGFpci5hY3RpdmVDb250YWN0cy5sZW5ndGggPT09IDIpIHtcXG4gICAgICAgICAgICAgICAgICAgIG5vcm1hbFBvc1ggPSAocGFpci5hY3RpdmVDb250YWN0c1swXS52ZXJ0ZXgueCArIHBhaXIuYWN0aXZlQ29udGFjdHNbMV0udmVydGV4LngpIC8gMjtcXG4gICAgICAgICAgICAgICAgICAgIG5vcm1hbFBvc1kgPSAocGFpci5hY3RpdmVDb250YWN0c1swXS52ZXJ0ZXgueSArIHBhaXIuYWN0aXZlQ29udGFjdHNbMV0udmVydGV4LnkpIC8gMjtcXG4gICAgICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgICAgICBpZiAoY29sbGlzaW9uLmJvZHlCID09PSBjb2xsaXNpb24uc3VwcG9ydHNbMF0uYm9keSB8fCBjb2xsaXNpb24uYm9keUEuaXNTdGF0aWMgPT09IHRydWUpIHtcXG4gICAgICAgICAgICAgICAgICAgIGMubW92ZVRvKG5vcm1hbFBvc1ggLSBjb2xsaXNpb24ubm9ybWFsLnggKiA4LCBub3JtYWxQb3NZIC0gY29sbGlzaW9uLm5vcm1hbC55ICogOCk7XFxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgICAgICAgICBjLm1vdmVUbyhub3JtYWxQb3NYICsgY29sbGlzaW9uLm5vcm1hbC54ICogOCwgbm9ybWFsUG9zWSArIGNvbGxpc2lvbi5ub3JtYWwueSAqIDgpO1xcbiAgICAgICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgICAgIGMubGluZVRvKG5vcm1hbFBvc1gsIG5vcm1hbFBvc1kpO1xcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH1cXG5cXG4gICAgICAgIGlmIChvcHRpb25zLndpcmVmcmFtZXMpIHtcXG4gICAgICAgICAgICBjLnN0cm9rZVN0eWxlID0gJ3JnYmEoMjU1LDE2NSwwLDAuNyknO1xcbiAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICBjLnN0cm9rZVN0eWxlID0gJ29yYW5nZSc7XFxuICAgICAgICB9XFxuXFxuICAgICAgICBjLmxpbmVXaWR0aCA9IDE7XFxuICAgICAgICBjLnN0cm9rZSgpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogRGVzY3JpcHRpb25cXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQG1ldGhvZCBzZXBhcmF0aW9uc1xcbiAgICAgKiBAcGFyYW0ge3JlbmRlcn0gcmVuZGVyXFxuICAgICAqIEBwYXJhbSB7cGFpcltdfSBwYWlyc1xcbiAgICAgKiBAcGFyYW0ge1JlbmRlcmluZ0NvbnRleHR9IGNvbnRleHRcXG4gICAgICovXFxuICAgIFJlbmRlci5zZXBhcmF0aW9ucyA9IGZ1bmN0aW9uKHJlbmRlciwgcGFpcnMsIGNvbnRleHQpIHtcXG4gICAgICAgIHZhciBjID0gY29udGV4dCxcXG4gICAgICAgICAgICBvcHRpb25zID0gcmVuZGVyLm9wdGlvbnMsXFxuICAgICAgICAgICAgcGFpcixcXG4gICAgICAgICAgICBjb2xsaXNpb24sXFxuICAgICAgICAgICAgY29ycmVjdGVkLFxcbiAgICAgICAgICAgIGJvZHlBLFxcbiAgICAgICAgICAgIGJvZHlCLFxcbiAgICAgICAgICAgIGksXFxuICAgICAgICAgICAgajtcXG5cXG4gICAgICAgIGMuYmVnaW5QYXRoKCk7XFxuXFxuICAgICAgICAvLyByZW5kZXIgc2VwYXJhdGlvbnNcXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBwYWlycy5sZW5ndGg7IGkrKykge1xcbiAgICAgICAgICAgIHBhaXIgPSBwYWlyc1tpXTtcXG5cXG4gICAgICAgICAgICBpZiAoIXBhaXIuaXNBY3RpdmUpXFxuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xcblxcbiAgICAgICAgICAgIGNvbGxpc2lvbiA9IHBhaXIuY29sbGlzaW9uO1xcbiAgICAgICAgICAgIGJvZHlBID0gY29sbGlzaW9uLmJvZHlBO1xcbiAgICAgICAgICAgIGJvZHlCID0gY29sbGlzaW9uLmJvZHlCO1xcblxcbiAgICAgICAgICAgIHZhciBrID0gMTtcXG5cXG4gICAgICAgICAgICBpZiAoIWJvZHlCLmlzU3RhdGljICYmICFib2R5QS5pc1N0YXRpYykgayA9IDAuNTtcXG4gICAgICAgICAgICBpZiAoYm9keUIuaXNTdGF0aWMpIGsgPSAwO1xcblxcbiAgICAgICAgICAgIGMubW92ZVRvKGJvZHlCLnBvc2l0aW9uLngsIGJvZHlCLnBvc2l0aW9uLnkpO1xcbiAgICAgICAgICAgIGMubGluZVRvKGJvZHlCLnBvc2l0aW9uLnggLSBjb2xsaXNpb24ucGVuZXRyYXRpb24ueCAqIGssIGJvZHlCLnBvc2l0aW9uLnkgLSBjb2xsaXNpb24ucGVuZXRyYXRpb24ueSAqIGspO1xcblxcbiAgICAgICAgICAgIGsgPSAxO1xcblxcbiAgICAgICAgICAgIGlmICghYm9keUIuaXNTdGF0aWMgJiYgIWJvZHlBLmlzU3RhdGljKSBrID0gMC41O1xcbiAgICAgICAgICAgIGlmIChib2R5QS5pc1N0YXRpYykgayA9IDA7XFxuXFxuICAgICAgICAgICAgYy5tb3ZlVG8oYm9keUEucG9zaXRpb24ueCwgYm9keUEucG9zaXRpb24ueSk7XFxuICAgICAgICAgICAgYy5saW5lVG8oYm9keUEucG9zaXRpb24ueCArIGNvbGxpc2lvbi5wZW5ldHJhdGlvbi54ICogaywgYm9keUEucG9zaXRpb24ueSArIGNvbGxpc2lvbi5wZW5ldHJhdGlvbi55ICogayk7XFxuICAgICAgICB9XFxuXFxuICAgICAgICBpZiAob3B0aW9ucy53aXJlZnJhbWVzKSB7XFxuICAgICAgICAgICAgYy5zdHJva2VTdHlsZSA9ICdyZ2JhKDI1NSwxNjUsMCwwLjUpJztcXG4gICAgICAgI
2H0gZWxzZSB7XFxuICAgICAgICAgICAgYy5zdHJva2VTdHlsZSA9ICdvcmFuZ2UnO1xcbiAgICAgICAgfVxcbiAgICAgICAgYy5zdHJva2UoKTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIERlc2NyaXB0aW9uXFxuICAgICAqIEBwcml2YXRlXFxuICAgICAqIEBtZXRob2QgaW5zcGVjdG9yXFxuICAgICAqIEBwYXJhbSB7aW5zcGVjdG9yfSBpbnNwZWN0b3JcXG4gICAgICogQHBhcmFtIHtSZW5kZXJpbmdDb250ZXh0fSBjb250ZXh0XFxuICAgICAqL1xcbiAgICBSZW5kZXIuaW5zcGVjdG9yID0gZnVuY3Rpb24oaW5zcGVjdG9yLCBjb250ZXh0KSB7XFxuICAgICAgICB2YXIgZW5naW5lID0gaW5zcGVjdG9yLmVuZ2luZSxcXG4gICAgICAgICAgICBzZWxlY3RlZCA9IGluc3BlY3Rvci5zZWxlY3RlZCxcXG4gICAgICAgICAgICByZW5kZXIgPSBpbnNwZWN0b3IucmVuZGVyLFxcbiAgICAgICAgICAgIG9wdGlvbnMgPSByZW5kZXIub3B0aW9ucyxcXG4gICAgICAgICAgICBib3VuZHM7XFxuXFxuICAgICAgICBpZiAob3B0aW9ucy5oYXNCb3VuZHMpIHtcXG4gICAgICAgICAgICB2YXIgYm91bmRzV2lkdGggPSByZW5kZXIuYm91bmRzLm1heC54IC0gcmVuZGVyLmJvdW5kcy5taW4ueCxcXG4gICAgICAgICAgICAgICAgYm91bmRzSGVpZ2h0ID0gcmVuZGVyLmJvdW5kcy5tYXgueSAtIHJlbmRlci5ib3VuZHMubWluLnksXFxuICAgICAgICAgICAgICAgIGJvdW5kc1NjYWxlWCA9IGJvdW5kc1dpZHRoIC8gcmVuZGVyLm9wdGlvbnMud2lkdGgsXFxuICAgICAgICAgICAgICAgIGJvdW5kc1NjYWxlWSA9IGJvdW5kc0hlaWdodCAvIHJlbmRlci5vcHRpb25zLmhlaWdodDtcXG5cXG4gICAgICAgICAgICBjb250ZXh0LnNjYWxlKDEgLyBib3VuZHNTY2FsZVgsIDEgLyBib3VuZHNTY2FsZVkpO1xcbiAgICAgICAgICAgIGNvbnRleHQudHJhbnNsYXRlKC1yZW5kZXIuYm91bmRzLm1pbi54LCAtcmVuZGVyLmJvdW5kcy5taW4ueSk7XFxuICAgICAgICB9XFxuXFxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNlbGVjdGVkLmxlbmd0aDsgaSsrKSB7XFxuICAgICAgICAgICAgdmFyIGl0ZW0gPSBzZWxlY3RlZFtpXS5kYXRhO1xcblxcbiAgICAgICAgICAgIGNvbnRleHQudHJhbnNsYXRlKDAuNSwgMC41KTtcXG4gICAgICAgICAgICBjb250ZXh0LmxpbmVXaWR0aCA9IDE7XFxuICAgICAgICAgICAgY29udGV4dC5zdHJva2VTdHlsZSA9ICdyZ2JhKDI1NSwxNjUsMCwwLjkpJztcXG4gICAgICAgICAgICBjb250ZXh0LnNldExpbmVEYXNoKFsxLDJdKTtcXG5cXG4gICAgICAgICAgICBzd2l0Y2ggKGl0ZW0udHlwZSkge1xcblxcbiAgICAgICAgICAgIGNhc2UgJ2JvZHknOlxcblxcbiAgICAgICAgICAgICAgICAvLyByZW5kZXIgYm9keSBzZWxlY3Rpb25zXFxuICAgICAgICAgICAgICAgIGJvdW5kcyA9IGl0ZW0uYm91bmRzO1xcbiAgICAgICAgICAgICAgICBjb250ZXh0LmJlZ2luUGF0aCgpO1xcbiAgICAgICAgICAgICAgICBjb250ZXh0LnJlY3QoTWF0aC5mbG9vcihib3VuZHMubWluLnggLSAzKSwgTWF0aC5mbG9vcihib3VuZHMubWluLnkgLSAzKSxcXG4gICAgICAgICAgICAgICAgICAgIE1hdGguZmxvb3IoYm91bmRzLm1heC54IC0gYm91bmRzLm1pbi54ICsgNiksIE1hdGguZmxvb3IoYm91bmRzLm1heC55IC0gYm91bmRzLm1pbi55ICsgNikpO1xcbiAgICAgICAgICAgICAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN0cm9rZSgpO1xcblxcbiAgICAgICAgICAgICAgICBicmVhaztcXG5cXG4gICAgICAgICAgICBjYXNlICdjb25zdHJhaW50JzpcXG5cXG4gICAgICAgICAgICAgICAgLy8gcmVuZGVyIGNvbnN0cmFpbnQgc2VsZWN0aW9uc1xcbiAgICAgICAgICAgICAgICB2Y
2XIgcG9pbnQgPSBpdGVtLnBvaW50QTtcXG4gICAgICAgICAgICAgICAgaWYgKGl0ZW0uYm9keUEpXFxuICAgICAgICAgICAgICAgICAgICBwb2ludCA9IGl0ZW0ucG9pbnRCO1xcbiAgICAgICAgICAgICAgICBjb250ZXh0LmJlZ2luUGF0aCgpO1xcbiAgICAgICAgICAgICAgICBjb250ZXh0LmFyYyhwb2ludC54LCBwb2ludC55LCAxMCwgMCwgMiAqIE1hdGguUEkpO1xcbiAgICAgICAgICAgICAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN0cm9rZSgpO1xcblxcbiAgICAgICAgICAgICAgICBicmVhaztcXG5cXG4gICAgICAgICAgICB9XFxuXFxuICAgICAgICAgICAgY29udGV4dC5zZXRMaW5lRGFzaChbXSk7XFxuICAgICAgICAgICAgY29udGV4dC50cmFuc2xhdGUoLTAuNSwgLTAuNSk7XFxuICAgICAgICB9XFxuXFxuICAgICAgICAvLyByZW5kZXIgc2VsZWN0aW9uIHJlZ2lvblxcbiAgICAgICAgaWYgKGluc3BlY3Rvci5zZWxlY3RTdGFydCAhPT0gbnVsbCkge1xcbiAgICAgICAgICAgIGNvbnRleHQudHJhbnNsYXRlKDAuNSwgMC41KTtcXG4gICAgICAgICAgICBjb250ZXh0LmxpbmVXaWR0aCA9IDE7XFxuICAgICAgICAgICAgY29udGV4dC5zdHJva2VTdHlsZSA9ICdyZ2JhKDI1NSwxNjUsMCwwLjYpJztcXG4gICAgICAgICAgICBjb250ZXh0LmZpbGxTdHlsZSA9ICdyZ2JhKDI1NSwxNjUsMCwwLjEpJztcXG4gICAgICAgICAgICBib3VuZHMgPSBpbnNwZWN0b3Iuc2VsZWN0Qm91bmRzO1xcbiAgICAgICAgICAgIGNvbnRleHQuYmVnaW5QYXRoKCk7XFxuICAgICAgICAgICAgY29udGV4dC5yZWN0KE1hdGguZmxvb3IoYm91bmRzLm1pbi54KSwgTWF0aC5mbG9vcihib3VuZHMubWluLnkpLFxcbiAgICAgICAgICAgICAgICBNYXRoLmZsb29yKGJvdW5kcy5tYXgueCAtIGJvdW5kcy5taW4ueCksIE1hdGguZmxvb3IoYm91bmRzLm1heC55IC0gYm91bmRzLm1pbi55KSk7XFxuICAgICAgICAgICAgY29udGV4dC5jbG9zZVBhdGgoKTtcXG4gICAgICAgICAgICBjb250ZXh0LnN0cm9rZSgpO1xcbiAgICAgICAgICAgIGNvbnRleHQuZmlsbCgpO1xcbiAgICAgICAgICAgIGNvbnRleHQudHJhbnNsYXRlKC0wLjUsIC0wLjUpO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgaWYgKG9wdGlvbnMuaGFzQm91bmRzKVxcbiAgICAgICAgICAgIGNvbnRleHQuc2V0VHJhbnNmb3JtKDEsIDAsIDAsIDEsIDAsIDApO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogVXBkYXRlcyByZW5kZXIgdGltaW5nLlxcbiAgICAgKiBAbWV0aG9kIF91cGRhdGVUaW1pbmdcXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQHBhcmFtIHtyZW5kZXJ9IHJlbmRlclxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gdGltZVxcbiAgICAgKi9cXG4gICAgdmFyIF91cGRhdGVUaW1pbmcgPSBmdW5jdGlvbihyZW5kZXIsIHRpbWUpIHtcXG4gICAgICAgIHZhciBlbmdpbmUgPSByZW5kZXIuZW5naW5lLFxcbiAgICAgICAgICAgIHRpbWluZyA9IHJlbmRlci50aW1pbmcsXFxuICAgICAgICAgICAgaGlzdG9yeVNpemUgPSB0aW1pbmcuaGlzdG9yeVNpemUsXFxuICAgICAgICAgICAgdGltZXN0YW1wID0gZW5naW5lLnRpbWluZy50aW1lc3RhbXA7XFxuXFxuICAgICAgICB0aW1pbmcuZGVsdGEgPSB0aW1lIC0gdGltaW5nLmxhc3RUaW1lIHx8IFJlbmRlci5fZ29vZERlbHRhO1xcbiAgICAgICAgdGltaW5nLmxhc3RUaW1lID0gdGltZTtcXG5cXG4gICAgICAgIHRpbWluZy50aW1lc3RhbXBFbGFwc2VkID0gdGltZXN0YW1wIC0gdGltaW5nLmxhc3RUaW1lc3RhbXAgfHwgMDtcXG4gICAgICAgIHRpbWluZy5sYXN0VGltZXN0YW1wID0gdGltZXN0YW1wO1xcblxcbiAgICAgICAgdGltaW5nLmRlbHRhSGlzdG9yeS51bnNoaWZ0KHRpbWluZy5kZWx0YSk7XFxuICAgICAgICB0aW1pbmcuZGVsdGFIaXN0b3J5Lmxlbmd0aCA9IE1hdGgubWluKHRpbWluZy5kZWx0YUhpc3RvcnkubGVuZ3RoLCBoaXN0b3J5U2l6ZSk7XFxuXFxuICAgICAgICB0aW1pbmcuZW5naW5lRGVsdGFIaXN0b3J5LnVuc2hpZnQoZW5naW5lLnRpbWluZy5sYXN0RGVsdGEpO1xcbiAgICAgICAgdGltaW5nLmVuZ2luZURlbHRhSGlzdG9yeS5sZW5ndGggPSBNYXRoLm1pbih0aW1pbmcuZW5naW5lRGVsdGFIaXN0b3J5Lmxlbmd0aCwgaGlzdG9yeVNpemUpO1xcblxcbiAgICAgICAgdGltaW5nLnRpbWVzdGFtcEVsYXBzZWRIaXN0b3J5LnVuc2hpZnQodGltaW5nLnRpbWVzdGFtcEVsYXBzZWQpO1xcbiAgICAgICAgdGltaW5nLnRpbWVzdGFtcEVsYXBzZWRIaXN0b3J5Lmxlbmd0aCA9IE1hdGgubWluKHRpbWluZy50aW1lc3RhbXBFbGFwc2VkSGlzdG9yeS5sZW5ndGgsIGhpc3RvcnlTaXplKTtcXG5cXG4gICAgICAgIHRpbWluZy5lbmdpbmVFbGFwc2VkSGlzdG9yeS51bnNoaWZ0KGVuZ2luZS50aW1pbmcubGFzdEVsYXBzZWQpO1xcbiAgICAgICAgdGltaW5nLmVuZ2luZUVsYXBzZWRIaXN0b3J5Lmxlbmd0aCA9IE1hdGgubWluKHRpbWluZy5lbmdpbmVFbGFwc2VkSGlzdG9yeS5sZW5ndGgsIGhpc3RvcnlTaXplKTtcXG5cXG4gICAgICAgIHRpbWluZy5lbGFwc2VkSGlzdG9yeS51bnNoaWZ0KHRpbWluZy5sYXN0RWxhcHNlZCk7XFxuICAgICAgICB0aW1pbmcuZWxhcHNlZEhpc3RvcnkubGVuZ3RoID0gTWF0aC5taW4odGltaW5nLmVsYXBzZWRIaXN0b3J5Lmxlbmd0aCwgaGlzdG9yeVNpemUpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogUmV0dXJucyB0aGUgbWVhbiB2YWx1ZSBvZiB0aGUgZ2l2ZW4gbnVtYmVycy5cXG4gICAgICogQG1ldGhvZCBfbWVhblxcbiAgICAgKiBAcHJpdmF0ZVxcbiAgICAgKiBAcGFyYW0ge051bWJlcltdfSB2YWx1ZXNcXG4gICAgICogQHJldHVybiB7TnVtYmVyfSB0aGUgbWVhbiBvZiBnaXZlbiB2YWx1ZXNcXG4gICAgICovXFxuICAgIHZhciBfbWVhbiA9IGZ1bmN0aW9uKHZhbHVlcykge1xcbiAgICAgICAgdmFyIHJlc3VsdCA9IDA7XFxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHZhbHVlcy5sZW5ndGg7IGkgKz0gMSkge1xcbiAgICAgICAgICAgIHJlc3VsdCArPSB2YWx1ZXNbaV07XFxuICAgICAgICB9XFxuICAgICAgICByZXR1cm4gKHJlc3VsdCAvIHZhbHVlcy5sZW5ndGgpIHx8IDA7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBAbWV0aG9kIF9jcmVhdGVDYW52YXNcXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQHBhcmFtIHt9IHdpZHRoXFxuICAgICAqIEBwYXJhbSB7fSBoZWlnaHRcXG4gICAgICogQHJldHVybi
2BjYW52YXNcXG4gICAgICovXFxuICAgIHZhciBfY3JlYXRlQ2FudmFzID0gZnVuY3Rpb24od2lkdGgsIGhlaWdodCkge1xcbiAgICAgICAgdmFyIGNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpO1xcbiAgICAgICAgY2FudmFzLndpZHRoID0gd2lkdGg7XFxuICAgICAgICBjYW52YXMuaGVpZ2h0ID0gaGVpZ2h0O1xcbiAgICAgICAgY2FudmFzLm9uY29udGV4dG1lbnUgPSBmdW5jdGlvbigpIHsgcmV0dXJuIGZhbHNlOyB9O1xcbiAgICAgICAgY2FudmFzLm9uc2VsZWN0c3RhcnQgPSBmdW5jdGlvbigpIHsgcmV0dXJuIGZhbHNlOyB9O1xcbiAgICAgICAgcmV0dXJuIGNhbnZhcztcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIEdldHMgdGhlIHBpeGVsIHJhdGlvIG9mIHRoZSBjYW52YXMuXFxuICAgICAqIEBtZXRob2QgX2dldFBpeGVsUmF0aW9cXG4gICAgICogQHByaXZhdGVcXG4gICAgICogQHBhcmFtIHtIVE1MRWxlbWVudH0gY2FudmFzXFxuICAgICAqIEByZXR1cm4ge051bWJlcn0gcGl4ZWwgcmF0aW9cXG4gICAgICovXFxuICAgIHZhciBfZ2V0UGl4ZWxSYXRpbyA9IGZ1bmN0aW9uKGNhbnZhcykge1xcbiAgICAgICAgdmFyIGNvbnRleHQgPSBjYW52YXMuZ2V0Q29udGV4dCgnMmQnKSxcXG4gICAgICAgICAgICBkZXZpY2VQaXhlbFJhdGlvID0gd2luZG93LmRldmljZVBpeGVsUmF0aW8gfHwgMSxcXG4gICAgICAgICAgICBiYWNraW5nU3RvcmVQaXhlbFJhdGlvID0gY29udGV4dC53ZWJraXRCYWNraW5nU3RvcmVQaXhlbFJhdGlvIHx8IGNvbnRleHQubW96QmFja2luZ1N0b3JlUGl4ZWxSYXRpb1xcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfHwgY29udGV4dC5tc0JhY2tpbmdTdG9yZVBpeGVsUmF0aW8gfHwgY29udGV4dC5vQmFja2luZ1N0b3JlUGl4ZWxSYXRpb1xcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfHwgY29udGV4dC5iYWNraW5nU3RvcmVQaXhlbFJhdGlvIHx8IDE7XFxuXFxuICAgICAgICByZXR1cm4gZGV2aWNlUGl4ZWxSYXRpbyAvIGJhY2tpbmdTdG9yZVBpeGVsUmF0aW87XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBHZXRzIHRoZSByZXF1ZXN0ZWQgdGV4dHVyZSAoYW4gSW1hZ2UpIHZpYSBpdHMgcGF0aFxcbiAgICAgKiBAbWV0aG9kIF9nZXRUZXh0dXJlXFxuICAgICAqIEBwcml2YXRlXFxuICAgICAqIEBwYXJhbSB7cmVuZGVyfSByZW5kZXJcXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGltYWdlUGF0aFxcbiAgICAgKiBAcmV0dXJuIHtJbWFnZX0gdGV4dHVyZVxcbiAgICAgKi9cXG4gICAgdmFyIF9nZXRUZXh0dXJlID0gZnVuY3Rpb24ocmVuZGVyLCBpbWFnZVBhdGgpIHtcXG4gICAgICAgIHZhciBpbWFnZSA9IHJlbmRlci50ZXh0dXJlc1tpbWFnZVBhdGhdO1xcblxcbiAgICAgICAgaWYgKGltYWdlKVxcbiAgICAgICAgICAgIHJldHVybiBpbWFnZTtcXG5cXG4gICAgICAgIGltYWdlID0gcmVuZGVyLnRleHR1cmVzW2ltYWdlUGF0aF0gPSBuZXcgSW1hZ2UoKTtcXG4gICAgICAgIGltYWdlLnNyYyA9IGltYWdlUGF0aDtcXG5cXG4gICAgICAgIHJldHVybiBpbWFnZTtcXG4gICAgfTtcXG5cXG4gICAgLyoqXFxuICAgICAqIEFwcGxpZXMgdGhlIGJhY2tncm91bmQgdG8gdGhlIGNhbnZhcyB1c2luZyBDU1MuXFxuICAgICAqIEBtZXRob2QgYXBwbHlCYWNrZ3JvdW5kXFxuICAgICAqIEBwcml2YXRlXFxuICAgICAqIEBwYXJhbSB7cmVuZGVyfSByZW5kZXJcXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGJhY2tncm91bmRcXG4gICAgICovXFxuICAgIHZhciBfYXBwbHlCYWNrZ3JvdW5kID0gZnVuY3Rpb24ocmVuZGVyLCBiYWNrZ3JvdW5kKSB7XFxuICAgICAgICB2Y
2XIgY3NzQmFja2dyb3VuZCA9IGJhY2tncm91bmQ7XFxuXFxuICAgICAgICBpZiAoLyhqcGd8Z2lmfHBuZykkLy50ZXN0KGJhY2tncm91bmQpKVxcbiAgICAgICAgICAgIGNzc0JhY2tncm91bmQgPSAndXJsKCcgKyBiYWNrZ3JvdW5kICsgJyknO1xcblxcbiAgICAgICAgcmVuZGVyLmNhbnZhcy5zdHlsZS5iYWNrZ3JvdW5kID0gY3NzQmFja2dyb3VuZDtcXG4gICAgICAgIHJlbmRlci5jYW52YXMuc3R5bGUuYmFja2dyb3VuZFNpemUgPSBcXFwiY29udGFpblxcXCI7XFxuICAgICAgICByZW5kZXIuY3VycmVudEJhY2tncm91bmQgPSBiYWNrZ3JvdW5kO1xcbiAgICB9O1xcblxcbiAgICAvKlxcbiAgICAqXFxuICAgICogIEV2ZW50cyBEb2N1bWVudGF0aW9uXFxuICAgICpcXG4gICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICogRmlyZWQgYmVmb3JlIHJlbmRlcmluZ1xcbiAgICAqXFxuICAgICogQGV2ZW50IGJlZm9yZVJlbmRlclxcbiAgICAqIEBwYXJhbSB7fSBldmVudCBBbiBldmVudCBvYmplY3RcXG4gICAgKiBAcGFyYW0ge251bWJlcn0gZXZlbnQudGltZXN0YW1wIFRoZSBlbmdpbmUudGltaW5nLnRpbWVzdGFtcCBvZiB0aGUgZXZlbnRcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQuc291cmNlIFRoZSBzb3VyY2Ugb2JqZWN0IG9mIHRoZSBldmVudFxcbiAgICAqIEBwYXJhbSB7fSBldmVudC5uYW1lIFRoZSBuYW1lIG9mIHRoZSBldmVudFxcbiAgICAqL1xcblxcbiAgICAvKipcXG4gICAgKiBGaXJlZCBhZnRlciByZW5kZXJpbmdcXG4gICAgKlxcbiAgICAqIEBldmVudCBhZnRlclJlbmRlclxcbiAgICAqIEBwYXJhbSB7fSBldmVudCBBbiBldmVudCBvYmplY3RcXG4gICAgKiBAcGFyYW0ge251bWJlcn0gZXZlbnQudGltZXN0YW1wIFRoZSBlbmdpbmUudGltaW5nLnRpbWVzdGFtcCBvZiB0aGUgZXZlbnRcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQuc291cmNlIFRoZSBzb3VyY2Ugb2JqZWN0IG9mIHRoZSBldmVudFxcbiAgICAqIEBwYXJhbSB7fSBldmVudC5uYW1lIFRoZSBuYW1lIG9mIHRoZSBldmVudFxcbiAgICAqL1xcblxcbiAgICAvKlxcbiAgICAqXFxuICAgICogIFByb3BlcnRpZXMgRG9jdW1lbnRhdGlvblxcbiAgICAqXFxuICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGJhY2stcmVmZXJlbmNlIHRvIHRoZSBgTWF0dGVyLlJlbmRlcmAgbW9kdWxlLlxcbiAgICAgKlxcbiAgICAgKiBAZGVwcmVjYXRlZFxcbiAgICAgKiBAcHJvcGVydHkgY29udHJvbGxlclxcbiAgICAgKiBAdHlwZSByZW5kZXJcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIHJlZmVyZW5jZSB0byB0aGUgYE1hdHRlci5FbmdpbmVgIGluc3RhbmNlIHRvIGJlIHVzZWQuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBlbmdpbmVcXG4gICAgICogQHR5cGUgZW5naW5lXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSByZWZlcmVuY2UgdG8gdGhlIGVsZW1lbnQgd2hlcmUgdGhlIGNhbnZhcyBpcyB0byBiZSBpbnNlcnRlZCAoaWYgYHJlbmRlci5jYW52YXNgIGhhcyBub3QgYmVlbiBzcGVjaWZpZWQpXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBlbGVtZW50XFxuICAgICAqIEB0eXBlIEhUTUxFbGVtZW50XFxuICAgICAqIEBkZWZhdWx0IG51bGxcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBUaGUgY2FudmFzIGVsZW1lbnQgdG8gcmVuZGVyIHRvLiBJZiBub3Qgc3BlY2lmaWVkLCBvbmUgd2lsbCBiZSBjcmVhdGVkIGlmIGByZW5kZXIuZWxlbWVudGAgaGFzIGJlZW4gc3BlY2lmaWVkLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgY2FudmFzXFxuICAgICAqIEB0eXBlIEhUTUxDYW52YXNFbGVtZW50XFxuICAgICAqIEBkZWZhdWx0IG51bGxcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGBCb3VuZHNgIG9iamVjdCB0aGF0IHNwZWNpZmllcyB0aGUgZHJhd2luZyB2aWV3IHJlZ2lvbi5cXG4gICAgICogUmVuZGVyaW5nIHdpbGwgYmUgYXV0b21hdGljYWxseSB0cmFuc2Zvcm1lZCBhbmQgc2NhbGVkIHRvIGZpdCB3aXRoaW4gdGhlIGNhbnZhcyBzaXplIChgcmVuZGVyLm9wdGlvbnMud2lkdGhgIGFuZCBgcmVuZGVyLm9wdGlvbnMuaGVpZ2h0YCkuXFxuICAgICAqIFRoaXMgYWxsb3dzIGZvciBjcmVhdGluZyB2aWV3cyB0aGF0IGNhbiBwYW4gb3Igem9vbSBhcm91bmQgdGhlIHNjZW5lLlxcbiAgICAgKiBZb3UgbXVzdCBhbHNvIHNldCBgcmVuZGVyLm9wdGlvbnMuaGFzQm91bmRzYCB0byBgdHJ1ZWAgdG8gZW5hYmxlIGJvdW5kZWQgcmVuZGVyaW5nLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgYm91bmRzXFxuICAgICAqIEB0eXBlIGJvdW5kc1xcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIFRoZSAyZCByZW5kZXJpbmcgY29udGV4dCBmcm9tIHRoZSBgcmVuZGVyLmNhbnZhc2AgZWxlbWVudC5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IGNvbnRleHRcXG4gICAgICogQHR5cGUgQ2FudmFzUmVuZGVyaW5nQ29udGV4dDJEXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogVGhlIHNwcml0ZSB0ZXh0dXJlIGNhY2hlLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgdGV4dHVyZXNcXG4gICAgICogQHR5cGUge31cXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBUaGUgbW91c2UgdG8gcmVuZGVyIGlmIGByZW5kZXIub3B0aW9ucy5zaG93TW91c2VQb3NpdGlvbmAgaXMgZW5hYmxlZC5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IG1vdXNlXFxuICAgICAqIEB0eXBlIG1vdXNlXFxuICAgICAqIEBkZWZhdWx0IG51bGxcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIG9mIHRoZSByZW5kZXJlci5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IG9wdGlvbnNcXG4gICAgICogQHR5cGUge31cXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBUaGUgdGFyZ2V0IHdpZHRoIGluIHBpeGVscyBvZiB0aGUgYHJlbmRlci5jYW52YXNgIHRvIGJlIGNyZWF0ZWQuXFxuICAgICAqIFNlZSBhbHNvIHRoZSBgb3B0aW9ucy5waXhlbFJhdGlvYCBwcm9wZXJ0eSB0byBjaGFuZ2UgcmVuZGVyIHF1YWxpdHkuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBvcHRpb25zLndpZHRoXFxuICAgICAqIEB0eXBlIG51bWJlclxcbiAgICAgKiBAZGVmYXVsdCA4MDBcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBUaGUgdGFyZ2V0IGhlaWdodCBpbiBwaXhlbHMgb2YgdGhlIGByZW5kZXIuY2FudmFzYCB0byBiZSBjcmVhdGVkLlxcbiAgICAgKiBTZWUgYWxzbyB0aGUgYG9wdGlvbnMucGl4ZWxSYXRpb2AgcHJvcGVydHkgdG8gY2hhbmdlIHJlbmRlciBxdWFsaXR5LlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgb3B0aW9ucy5oZWlnaHRcXG4gICAgICogQHR5cGUgbnVtYmVyXFxuICAgICAqIEBkZWZhdWx0IDYwMFxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIFRoZSBbcGl4ZWwgcmF0aW9dKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0FQSS9XaW5kb3cvZGV2aWNlUGl4ZWxSYXRpbykgdG8gdXNlIHdoZW4gcmVuZGVyaW5nLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgb3B0aW9ucy5waXhlbFJhdGlvXFxuICAgICAqIEB0eXBlIG51bWJlclxcbiAgICAgKiBAZGVmYXVsdCAxXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBDU1MgYmFja2dyb3VuZCBjb2xvciBzdHJpbmcgdG8gdXNlIHdoZW4gYHJlbmRlci5vcHRpb25zLndpcmVmcmFtZXNgIGlzIGRpc2FibGVkLlxcbiAgICAgKiBUaGlzIG1heSBiZSBhbHNvIHNldCB0byBgJ3RyYW5zcGFyZW50J2Agb3IgZXF1aXZhbGVudC5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IG9wdGlvbnMuYmFja2dyb3VuZFxcbiAgICAgKiBAdHlwZSBzdHJpbmdcXG4gICAgICogQGRlZmF1bHQgJyMxNDE1MWYnXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBDU1MgYmFja2dyb3VuZCBjb2xvciBzdHJpbmcgdG8gdXNlIHdoZW4gYHJlbmRlci5vcHRpb25zLndpcmVmcmFtZXNgIGlzIGVuYWJsZWQuXFxuICAgICAqIFRoaXMgbWF5IGJlIGFsc28gc2V0IHRvIGAndHJhbnNwYXJlbnQnYCBvciBlcXVpdmFsZW50LlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgb3B0aW9ucy53aXJlZnJhbWVCYWNrZ3JvdW5kXFxuICAgICAqIEB0eXBlIHN0cmluZ1xcbiAgICAgKiBAZGVmYXVsdCAnIzE0MTUxZidcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGZsYWcgdGhhdCBzcGVjaWZpZXMgaWYgYHJlbmRlci5ib3VuZHNgIHNob3VsZCBiZSB1c2VkIHdoZW4gcmVuZGVyaW5nLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgb3B0aW9ucy5oYXNCb3VuZHNcXG4gICAgICogQHR5cGUgYm9vbGVhblxcbiAgICAgKiBAZGVmYXVsdCBmYWxzZVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEEgZmxhZyB0byBlbmFibGUgb3IgZGlzYWJsZSBhbGwgZGVidWcgaW5mb3JtYXRpb24gb3ZlcmxheXMgdG9nZXRoZXIuICBcXG4gICAgICogVGhpcyBpbmNsdWRlcyBhbmQgaGFzIHByaW9yaXR5IG92ZXIgdGhlIHZhbHVlcyBvZjpcXG4gICAgICpcXG4gICAgICogLSBgcmVuZGVyLm9wdGlvbnMuc2hvd1N0YXRzYFxcbiAgICAgKiAtIGByZW5kZXIub3B0aW9ucy5zaG93UGVyZm9ybWFuY2VgXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBvcHRpb25zLnNob3dEZWJ1Z1xcbiAgICAgKiBAdHlwZSBib29sZWFuXFxuICAgICAqIEBkZWZhdWx0IGZhbHNlXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBmbGFnIHRvIGVuYWJsZSBvciBkaXNhYmxlIHRoZSBlbmdpbmUgc3RhdHMgaW5mbyBvdmVybGF5LiAgXFxuICAgICAqIEZyb20gbGVmdCB0byByaWdodCwgdGhlI
2HZhbHVlcyBzaG93biBhcmU6XFxuICAgICAqXFxuICAgICAqIC0gYm9keSBwYXJ0cyB0b3RhbFxcbiAgICAgKiAtIGJvZHkgdG90YWxcXG4gICAgICogLSBjb25zdHJhaW50cyB0b3RhbFxcbiAgICAgKiAtIGNvbXBvc2l0ZXMgdG90YWxcXG4gICAgICogLSBjb2xsaXNpb24gcGFpcnMgdG90YWxcXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IG9wdGlvbnMuc2hvd1N0YXRzXFxuICAgICAqIEB0eXBlIGJvb2xlYW5cXG4gICAgICogQGRlZmF1bHQgZmFsc2VcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGZsYWcgdG8gZW5hYmxlIG9yIGRpc2FibGUgcGVyZm9ybWFuY2UgY2hhcnRzLiAgXFxuICAgICAqIEZyb20gbGVmdCB0byByaWdodCwgdGhlIHZhbHVlcyBzaG93biBhcmU6XFxuICAgICAqXFxuICAgICAqIC0gYXZlcmFnZSByZW5kZXIgZnJlcXVlbmN5IChlLmcuIDYwIGZwcylcXG4gICAgICogLSBleGFjdCBlbmdpbmUgZGVsdGEgdGltZSB1c2VkIGZvciBsYXN0IHVwZGF0ZSAoZS5nLiAxNi42Nm1zKVxcbiAgICAgKiAtIGF2ZXJhZ2UgZW5naW5lIGV4ZWN1dGlvbiBkdXJhdGlvbiAoZS5nLiA1LjAwbXMpXFxuICAgICAqIC0gYXZlcmFnZSByZW5kZXIgZXhlY3V0aW9uIGR1cmF0aW9uIChlLmcuIDAuNDBtcylcXG4gICAgICogLSBhdmVyYWdlIGVmZmVjdGl2ZSBwbGF5IHNwZWVkIChlLmcuICcxLjAweCcgaXMgJ3JlYWwtdGltZScpXFxuICAgICAqXFxuICAgICAqIEVhY2ggdmFsdWUgaXMgcmVjb3JkZWQgb3ZlciBhIGZpeGVkIHNhbXBsZSBvZiBwYXN0IGZyYW1lcyAoNjAgZnJhbWVzKS5cXG4gICAgICpcXG4gICAgICogQSBjaGFydCBzaG93biBiZWxvdyBlYWNoIHZhbHVlIGluZGljYXRlcyB0aGUgdmFyaWFuY2UgZnJvbSB0aGUgYXZlcmFnZSBvdmVyIHRoZSBzYW1wbGUuXFxuICAgICAqIFRoZSBtb3JlIHN0YWJsZSBvciBmaXhlZCB0aGUgdmFsdWUgaXMgdGhlIGZsYXR0ZXIgdGhlIGNoYXJ0IHdpbGwgYXBwZWFyLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgb3B0aW9ucy5zaG93UGVyZm9ybWFuY2VcXG4gICAgICogQHR5cGUgYm9vbGVhblxcbiAgICAgKiBAZGVmYXVsdCBmYWxzZVxcbiAgICAgKi9cXG4gICAgXFxuICAgIC8qKlxcbiAgICAgKiBBIGZsYWcgdG8gZW5hYmxlIG9y
2IGRpc2FibGUgcmVuZGVyaW5nIGVudGlyZWx5LlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgb3B0aW9ucy5lbmFibGVkXFxuICAgICAqIEB0eXBlIGJvb2xlYW5cXG4gICAgICogQGRlZmF1bHQgZmFsc2VcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGZsYWcgdG8gdG9nZ2xlIHdpcmVmcmFtZSByZW5kZXJpbmcgb3RoZXJ3aXNlIHNvbGlkIGZpbGwgcmVuZGVyaW5nIGlzIHVzZWQuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBvcHRpb25zLndpcmVmcmFtZXNcXG4gICAgICogQHR5cGUgYm9vbGVhblxcbiAgICAgKiBAZGVmYXVsdCB0cnVlXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBmbGFnIHRvIGVuYWJsZSBvciBkaXNhYmxlIHNsZWVwaW5nIGJvZGllcyBpbmRpY2F0b3JzLlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgb3B0aW9ucy5zaG93U2xlZXBpbmdcXG4gICAgICogQHR5cGUgYm9vbGVhblxcbiAgICAgKiBAZGVmYXVsdCB0cnVlXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBmbGFnIHRvIGVuYWJsZSBvciBkaXNhYmxlIHRoZSBkZWJ1ZyBpbmZvcm1hdGlvbiBvdmVybGF5LlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgb3B0aW9ucy5zaG93RGVidWdcXG4gICAgICogQHR5cGUgYm9vbGVhblxcbiAgICAgKiBAZGVmYXVsdCBmYWxzZVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEEgZmxhZyB0byBlbmFibGUgb3IgZGlzYWJsZSB0aGUgY29sbGlzaW9uIGJyb2FkcGhhc2UgZGVidWcgb3ZlcmxheS5cXG4gICAgICpcXG4gICAgICogQGRlcHJlY2F0ZWQgbm8gbG9uZ2VyIGltcGxlbWVudGVkXFxuICAgICAqIEBwcm9wZXJ0eSBvcHRpb25zLnNob3dCcm9hZHBoYXNlXFxuICAgICAqIEB0eXBlIGJvb2xlYW5cXG4gICAgICogQGRlZmF1bHQgZmFsc2VcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGZsYWcgdG8gZW5hYmxlIG9y
2IGRpc2FibGUgdGhlIGJvZHkgYm91bmRzIGRlYnVnIG92ZXJsYXkuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBvcHRpb25zLnNob3dCb3VuZHNcXG4gICAgICogQHR5cGUgYm9vbGVhblxcbiAgICAgKiBAZGVmYXVsdCBmYWxzZVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEEgZmxhZyB0byBlbmFibGUgb3IgZGlzYWJsZSB0aGUgYm9keSB2ZWxvY2l0eSBkZWJ1ZyBvdmVybGF5LlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgb3B0aW9ucy5zaG93VmVsb2NpdHlcXG4gICAgICogQHR5cGUgYm9vbGVhblxcbiAgICAgKiBAZGVmYXVsdCBmYWxzZVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEEgZmxhZyB0byBlbmFibGUgb3IgZGlzYWJsZSB0aGUgYm9keSBjb2xsaXNpb25zIGRlYnVnIG92ZXJsYXkuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBvcHRpb25zLnNob3dDb2xsaXNpb25zXFxuICAgICAqIEB0eXBlIGJvb2xlYW5cXG4gICAgICogQGRlZmF1bHQgZmFsc2VcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGZsYWcgdG8gZW5hYmxlIG9yIGRpc2FibGUgdGhlIGNvbGxpc2lvbiByZXNvbHZlciBzZXBhcmF0aW9ucyBkZWJ1ZyBvdmVybGF5LlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgb3B0aW9ucy5zaG93U2VwYXJhdGlvbnNcXG4gICAgICogQHR5cGUgYm9vbGVhblxcbiAgICAgKiBAZGVmYXVsdCBmYWxzZVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEEgZmxhZyB0byBlbmFibGUgb3IgZGlzYWJsZSB0aGUgYm9keSBheGVzIGRlYnVnIG92ZXJsYXkuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBvcHRpb25zLnNob3dBeGVzXFxuICAgICAqIEB0eXBlIGJvb2xlYW5cXG4gICAgICogQGRlZmF1bHQgZmFsc2VcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGZsYWcgdG8gZW5hYmxlIG9y
2IGRpc2FibGUgdGhlIGJvZHkgcG9zaXRpb25zIGRlYnVnIG92ZXJsYXkuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBvcHRpb25zLnNob3dQb3NpdGlvbnNcXG4gICAgICogQHR5cGUgYm9vbGVhblxcbiAgICAgKiBAZGVmYXVsdCBmYWxzZVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEEgZmxhZyB0byBlbmFibGUgb3IgZGlzYWJsZSB0aGUgYm9keSBhbmdsZSBkZWJ1ZyBvdmVybGF5LlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgb3B0aW9ucy5zaG93QW5nbGVJbmRpY2F0b3JcXG4gICAgICogQHR5cGUgYm9vbGVhblxcbiAgICAgKiBAZGVmYXVsdCBmYWxzZVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEEgZmxhZyB0byBlbmFibGUgb3IgZGlzYWJsZSB0aGUgYm9keSBhbmQgcGFydCBpZHMgZGVidWcgb3ZlcmxheS5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IG9wdGlvbnMuc2hvd0lkc1xcbiAgICAgKiBAdHlwZSBib29sZWFuXFxuICAgICAqIEBkZWZhdWx0IGZhbHNlXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBmbGFnIHRvIGVuYWJsZSBvciBkaXNhYmxlIHRoZSBib2R5IHZlcnRleCBudW1iZXJzIGRlYnVnIG92ZXJsYXkuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBvcHRpb25zLnNob3dWZXJ0ZXhOdW1iZXJzXFxuICAgICAqIEB0eXBlIGJvb2xlYW5cXG4gICAgICogQGRlZmF1bHQgZmFsc2VcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGZsYWcgdG8gZW5hYmxlIG9yIGRpc2FibGUgdGhlIGJvZHkgY29udmV4IGh1bGxzIGRlYnVnIG92ZXJsYXkuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBvcHRpb25zLnNob3dDb252ZXhIdWxsc1xcbiAgICAgKiBAdHlwZSBib29sZWFuXFxuICAgICAqIEBkZWZhdWx0IGZhbHNlXFxuICAgICAqL1xcblxcbiAgICAvKipcXG4gICAgICogQSBmbGFnIHRvIGVuYWJsZSBvciBkaXNhYmxlIHRoZSBib2R5IGludGVybmFsIGVkZ2VzIGRlYnVnIG92ZXJsYXkuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBvcHRpb25zLnNob3dJbnRlcm5hbEVkZ2VzXFxuICAgICAqIEB0eXBlIGJvb2xlYW5cXG4gICAgICogQGRlZmF1bHQgZmFsc2VcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGZsYWcgdG8gZW5hYmxlIG9y
2IGRpc2FibGUgdGhlIG1vdXNlIHBvc2l0aW9uIGRlYnVnIG92ZXJsYXkuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBvcHRpb25zLnNob3dNb3VzZVBvc2l0aW9uXFxuICAgICAqIEB0eXBlIGJvb2xlYW5cXG4gICAgICogQGRlZmF1bHQgZmFsc2VcXG4gICAgICovXFxuXFxufSkoKTtcXG5cXG5cXG4vKioqLyB9KSxcXG4vKiAyNyAqL1xcbi8qKiovIChmdW5jdGlvbihtb2R1bGUsIGV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pIHtcXG5cXG4vKipcXG4qIFRoZSBgTWF0dGVyLlJ1bm5lcmAgbW9kdWxlIGlzIGFuIG9wdGlvbmFsIHV0aWxpdHkgd2hpY2ggcHJvdmlkZXMgYSBnYW1lIGxvb3AsIFxcbiogdGhhdCBoYW5kbGVzIGNvbnRpbnVvdXNseSB1cGRhdGluZyBhIGBNYXR0ZXIuRW5naW5lYCBmb3IgeW91IHdpdGhpbiBhIGJyb3dzZXIuXFxuKiBJdCBpcyBpbnRlbmRlZCBmb3IgZGV2ZWxvcG1lbnQgYW5kIGRlYnVnZ2luZyBwdXJwb3NlcywgYnV0IG1heSBhbHNvIGJlIHN1aXRhYmxlIGZvciBzaW1wbGUgZ2FtZXMuXFxuKiBJZiB5b3UgYXJlIHVzaW5nIHlvdXIgb3duIGdhbWUgbG9vcCBpbnN0ZWFkLCB0aGVuIHlvdSBkbyBub3QgbmVlZCB0aGUgYE1hdHRlci5SdW5uZXJgIG1vZHVsZS5cXG4qIEluc3RlYWQganVzdCBjYWxsIGBFbmdpbmUudXBkYXRlKGVuZ2luZSwgZGVsdGEpYCBpbiB5b3VyIG93biBsb29wLlxcbipcXG4qIFNlZSB0aGUgaW5jbHVkZWQgdXNhZ2UgW2V4YW1wbGVzXShodHRwczovL2dpdGh1Yi5jb20vbGlhYnJ1L21hdHRlci1qcy90cmVlL21hc3Rlci9leGFtcGxlcykuXFxuKlxcbiogQGNsYXNzIFJ1bm5lclxcbiovXFxuXFxudmFyIFJ1bm5lciA9IHt9O1xcblxcbm1vZHVsZS5leHBvcnRzID0gUnVubmVyO1xcblxcbnZhciBFdmVudHMgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDUpO1xcbnZhciBFbmdpbmUgPSBfX3dlYnBhY2tfcmVxdWlyZV9fKDE3KTtcXG52YXIgQ29tbW9uID0gX193ZWJwYWNrX3JlcXVpcmVfXygwKTtcXG5cXG4oZnVuY3Rpb24oKSB7XFxuXFxuICAgIHZhciBfcmVxdWVzdEFuaW1hdGlvbkZyYW1lLFxcbiAgICAgICAgX2NhbmNlbEFuaW1hdGlvbkZyYW1lO1xcblxcbiAgICBpZiAodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcpIHtcXG4gICAgICAgIF9yZXF1ZXN0QW5pbWF0aW9uRnJhbWUgPSB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lIHx8IHdpbmRvdy53ZWJraXRSZXF1ZXN0QW5pbWF0aW9uRnJhbWVcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHx8IHdpbmRvdy5tb3pSZXF1ZXN0QW5pbWF0aW9uRnJhbWUgfHwgd2luZG93Lm1zUmVxdWVzdEFuaW1hdGlvbkZyYW1lO1xcbiAgIFxcbiAgICAgICAgX2NhbmNlbEFuaW1hdGlvbkZyYW1lID0gd2luZG93LmNhbmNlbEFuaW1hdGlvbkZyYW1lIHx8IHdpbmRvdy5tb3pDYW5jZWxBbmltYXRpb25GcmFtZSBcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHx8IHdpbmRvdy53ZWJraXRDYW5jZWxBbmltYXRpb25GcmFtZSB8fCB3aW5kb3cubXNDYW5jZWxBbmltYXRpb25GcmFtZTtcXG4gICAgfVxcblxcbiAgICBpZiAoIV9yZXF1ZXN0QW5pbWF0aW9uRnJhbWUpIHtcXG4gICAgICAgIHZhciBfZnJhbWVUaW1lb3V0O1xcblxcbiAgICAgICAgX3JlcXVlc3RBbmltYXRpb25GcmFtZSA9IGZ1bmN0aW9uKGNhbGxiYWNrKXsgXFxuICAgICAgICAgICAgX2ZyYW1lVGltZW91dCA9IHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7IFxcbiAgICAgICAgICAgICAgICBjYWxsYmFjayhDb21tb24ubm93KCkpOyBcXG4gICAgICAgICAgICB9LCAxMDAwIC8gNjApO1xcbiAgICAgICAgfTtcXG5cXG4gICAgICAgIF9jYW5jZWxBbmltYXRpb25GcmFtZSA9IGZ1bmN0aW9uKCkge1xcbiAgICAgICAgICAgIGNsZWFyVGltZW91dChfZnJhbWVUaW1lb3V0KTtcXG4gICAgICAgIH07XFxuICAgIH1cXG5cXG4gICAgLyoqXFxuICAgICAqIENyZWF0ZXMgYSBuZXcgUnVubmVyLiBUaGUgb3B0aW9ucyBwYXJhbWV0ZXIgaXMgYW4gb2JqZWN0IHRoYXQgc3BlY2lmaWVzIGFueSBwcm9wZXJ0aWVzIHlvdSB3aXNoIHRvIG92ZXJyaWRlIHRoZSBkZWZhdWx0cy5cXG4gICAgICogQG1ldGhvZCBjcmVhdGVcXG4gICAgICogQHBhcmFtIHt9IG9wdGlvbnNcXG4gICAgICovXFxuICAgIFJ1bm5lci5jcmVhdGUgPSBmdW5jdGlvbihvcHRpb25zKSB7XFxuICAgICAgICB2Y
2XIgZGVmYXVsdHMgPSB7XFxuICAgICAgICAgICAgZnBzOiA2MCxcXG4gICAgICAgICAgICBkZWx0YVNhbXBsZVNpemU6IDYwLFxcbiAgICAgICAgICAgIGNvdW50ZXJUaW1lc3RhbXA6IDAsXFxuICAgICAgICAgICAgZnJhbWVDb3VudGVyOiAwLFxcbiAgICAgICAgICAgIGRlbHRhSGlzdG9yeTogW10sXFxuICAgICAgICAgICAgdGltZVByZXY6IG51bGwsXFxuICAgICAgICAgICAgZnJhbWVSZXF1ZXN0SWQ6IG51bGwsXFxuICAgICAgICAgICAgaXNGaXhlZDogZmFsc2UsXFxuICAgICAgICAgICAgZW5hYmxlZDogdHJ1ZVxcbiAgICAgICAgfTtcXG5cXG4gICAgICAgIHZhciBydW5uZXIgPSBDb21tb24uZXh0ZW5kKGRlZmF1bHRzLCBvcHRpb25zKTtcXG5cXG4gICAgICAgIHJ1bm5lci5kZWx0YSA9IHJ1bm5lci5kZWx0YSB8fCAxMDAwIC8gcnVubmVyLmZwcztcXG4gICAgICAgIHJ1bm5lci5kZWx0YU1pbiA9IHJ1bm5lci5kZWx0YU1pbiB8fCAxMDAwIC8gcnVubmVyLmZwcztcXG4gICAgICAgIHJ1bm5lci5kZWx0YU1heCA9IHJ1bm5lci5kZWx0YU1heCB8fCAxMDAwIC8gKHJ1bm5lci5mcHMgKiAwLjUpO1xcbiAgICAgICAgcnVubmVyLmZwcyA9IDEwMDAgLyBydW5uZXIuZGVsdGE7XFxuXFxuICAgICAgICByZXR1cm4gcnVubmVyO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogQ29udGludW91c2x5IHRpY2tzIGEgYE1hdHRlci5FbmdpbmVgIGJ5IGNhbGxpbmcgYFJ1bm5lci50aWNrYCBvbiB0aGUgYHJlcXVlc3RBbmltYXRpb25GcmFtZWAgZXZlbnQuXFxuICAgICAqIEBtZXRob2QgcnVuXFxuICAgICAqIEBwYXJhbSB7ZW5naW5lfSBlbmdpbmVcXG4gICAgICovXFxuICAgIFJ1bm5lci5ydW4gPSBmdW5jdGlvbihydW5uZXIsIGVuZ2luZSkge1xcbiAgICAgICAgLy8gY3JlYXRlIHJ1bm5lciBpZiBlbmdpbmUgaXMgZmlyc3QgYXJndW1lbnRcXG4gICAgICAgIGlmICh0eXBlb2YgcnVubmVyLnBvc2l0aW9uSXRlcmF0aW9ucyAhPT0gJ3VuZGVmaW5lZCcpIHtcXG4gICAgICAgICAgICBlbmdpbmUgPSBydW5uZXI7XFxuICAgICAgICAgICAgcnVubmVyID0gUnVubmVyLmNyZWF0ZSgpO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgKGZ1bmN0aW9uIHJ1bih0aW1lKXtcXG4gICAgICAgICAgICBydW5uZXIuZnJhbWVSZXF1ZXN0SWQgPSBfcmVxdWVzdEFuaW1hdGlvbkZyYW1lKHJ1bik7XFxuXFxuICAgICAgICAgICAgaWYgKHRpbWUgJiYgcnVubmVyLmVuYWJsZWQpIHtcXG4gICAgICAgICAgICAgICAgUnVubmVyLnRpY2socnVubmVyLCBlbmdpbmUsIHRpbWUpO1xcbiAgICAgICAgICAgIH1cXG4gICAgICAgIH0pKCk7XFxuXFxuICAgICAgICByZXR1cm4gcnVubmVyO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogQSBnYW1lIGxvb3AgdXRpbGl0eSB0aGF0IHVwZGF0ZXMgdGhlIGVuZ2luZSBhbmQgcmVuZGVyZXIgYnkgb25lIHN0ZXAgKGEgJ3RpY2snKS5cXG4gICAgICogRmVhdHVyZXMgZGVsdGEgc21vb3RoaW5nLCB0aW1lIGNvcnJlY3Rpb24gYW5kIGZpeGVkIG9yIGR5bmFtaWMgdGltaW5nLlxcbiAgICAgKiBDb25zaWRlciBqdXN0IGBFbmdpbmUudXBkYXRlKGVuZ2luZSwgZGVsdGEpYCBpZiB5b3UncmUgdXNpbmcgeW91ciBvd24gbG9vcC5cXG4gICAgICogQG1ldGhvZCB0aWNrXFxuICAgICAqIEBwYXJhbSB7cnVubmVyfSBydW5uZXJcXG4gICAgICogQHBhcmFtIHtlbmdpbmV9IGVuZ2luZVxcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gdGltZVxcbiAgICAgKi9cXG4gICAgUnVubmVyLnRpY2sgPSBmdW5jdGlvbihydW5uZXIsIGVuZ2luZSwgdGltZSkge1xcbiAgICAgICAgdmFyIHRpbWluZyA9IGVuZ2luZS50aW1pbmcsXFxuICAgICAgICAgICAgZGVsdGE7XFxuXFxuICAgICAgICBpZiAocnVubmVyLmlzRml4ZWQpIHtcXG4gICAgICAgICAgICAvLyBmaXhlZCB0aW1lc3RlcFxcbiAgICAgICAgICAgIGRlbHRhID0gcnVubmVyLmRlbHRhO1xcbiAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICAvLyBkeW5hbWljIHRpbWVzdGVwIGJhc2VkIG9uIHdhbGwgY2xvY2sgYmV0d2VlbiBjYWxsc1xcbiAgICAgICAgICAgIGRlbHRhID0gKHRpbWUgLSBydW5uZXIudGltZVByZXYpIHx8IHJ1bm5lci5kZWx0YTtcXG4gICAgICAgICAgICBydW5uZXIudGltZVByZXYgPSB0aW1lO1xcblxcbiAgICAgICAgICAgIC8vIG9wdGltaXN0aWNhbGx5IGZpbHRlciBkZWx0YSBvdmVyIGEgZmV3IGZyYW1lcywgdG8gaW1wcm92ZSBzdGFiaWxpdHlcXG4gICAgICAgICAgICBydW5uZXIuZGVsdGFIaXN0b3J5LnB1c2goZGVsdGEpO1xcbiAgICAgICAgICAgIHJ1bm5lci5kZWx0YUhpc3RvcnkgPSBydW5uZXIuZGVsdGFIaXN0b3J5LnNsaWNlKC1ydW5uZXIuZGVsdGFTYW1wbGVTaXplKTtcXG4gICAgICAgICAgICBkZWx0YSA9IE1hdGgubWluLmFwcGx5KG51bGwsIHJ1bm5lci5kZWx0YUhpc3RvcnkpO1xcblxcbiAgICAgICAgICAgIC8vIGxpbWl0IGRlbHRhXFxuICAgICAgICAgICAgZGVsdGEgPSBkZWx0YSA8IHJ1bm5lci5kZWx0YU1pbiA/IHJ1bm5lci5kZWx0YU1pbiA6IGRlbHRhO1xcbiAgICAgICAgICAgIGRlbHRhID0gZGVsdGEgPiBydW5uZXIuZGVsdGFNYXggPyBydW5uZXIuZGVsdGFNYXggOiBkZWx0YTtcXG5cXG4gICAgICAgICAgICAvLyB1cGRhdGUgZW5naW5lIHRpbWluZyBvYmplY3RcXG4gICAgICAgICAgICBydW5uZXIuZGVsdGEgPSBkZWx0YTtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIC8vIGNyZWF0ZSBhbiBldmVudCBvYmplY3RcXG4gICAgICAgIHZhciBldmVudCA9IHtcXG4gICAgICAgICAgICB0aW1lc3RhbXA6IHRpbWluZy50aW1lc3RhbXBcXG4gICAgICAgIH07XFxuXFxuICAgICAgICBFdmVudHMudHJpZ2dlcihydW5uZXIsICdiZWZvcmVUaWNrJywgZXZlbnQpO1xcblxcbiAgICAgICAgLy8gZnBzIGNvdW50ZXJcXG4gICAgICAgIHJ1bm5lci5mcmFtZUNvdW50ZXIgKz0gMTtcXG4gICAgICAgIGlmICh0aW1lIC0gcnVubmVyLmNvdW50ZXJUaW1lc3RhbXAgPj0gMTAwMCkge1xcbiAgICAgICAgICAgIHJ1bm5lci5mcHMgPSBydW5uZXIuZnJhbWVDb3VudGVyICogKCh0aW1lIC0gcnVubmVyLmNvdW50ZXJUaW1lc3RhbXApIC8gMTAwMCk7XFxuICAgICAgICAgICAgcnVubmVyLmNvdW50ZXJUaW1lc3RhbXAgPSB0aW1lO1xcbiAgICAgICAgICAgI
2HJ1bm5lci5mcmFtZUNvdW50ZXIgPSAwO1xcbiAgICAgICAgfVxcblxcbiAgICAgICAgRXZlbnRzLnRyaWdnZXIocnVubmVyLCAndGljaycsIGV2ZW50KTtcXG5cXG4gICAgICAgIC8vIHVwZGF0ZVxcbiAgICAgICAgRXZlbnRzLnRyaWdnZXIocnVubmVyLCAnYmVmb3JlVXBkYXRlJywgZXZlbnQpO1xcblxcbiAgICAgICAgRW5naW5lLnVwZGF0ZShlbmdpbmUsIGRlbHRhKTtcXG5cXG4gICAgICAgIEV2ZW50cy50cmlnZ2VyKHJ1bm5lciwgJ2FmdGVyVXBkYXRlJywgZXZlbnQpO1xcblxcbiAgICAgICAgRXZlbnRzLnRyaWdnZXIocnVubmVyLCAnYWZ0ZXJUaWNrJywgZXZlbnQpO1xcbiAgICB9O1xcblxcbiAgICAvKipcXG4gICAgICogRW5kcyBleGVjdXRpb24gb2YgYFJ1bm5lci5ydW5gIG9uIHRoZSBnaXZlbiBgcnVubmVyYCwgYnkgY2FuY2VsaW5nIHRoZSBhbmltYXRpb24gZnJhbWUgcmVxdWVzdCBldmVudCBsb29wLlxcbiAgICAgKiBJZiB5b3Ugd2lzaCB0byBvbmx5IHRlbXBvcmFyaWx5IHBhdXNlIHRoZSBlbmdpbmUsIHNlZSBgZW5naW5lLmVuYWJsZWRgIGluc3RlYWQuXFxuICAgICAqIEBtZXRob2Qgc3RvcFxcbiAgICAgKiBAcGFyYW0ge3J1bm5lcn0gcnVubmVyXFxuICAgICAqL1xcbiAgICBSdW5uZXIuc3RvcCA9IGZ1bmN0aW9uKHJ1bm5lcikge1xcbiAgICAgICAgX2NhbmNlbEFuaW1hdGlvbkZyYW1lKHJ1bm5lci5mcmFtZVJlcXVlc3RJZCk7XFxuICAgIH07XFxuXFxuICAgIC8qKlxcbiAgICAgKiBBbGlhcyBmb3IgYFJ1bm5lci5ydW5gLlxcbiAgICAgKiBAbWV0aG9kIHN0YXJ0XFxuICAgICAqIEBwYXJhbSB7cnVubmVyfSBydW5uZXJcXG4gICAgICogQHBhcmFtIHtlbmdpbmV9IGVuZ2luZVxcbiAgICAgKi9cXG4gICAgUnVubmVyLnN0YXJ0ID0gZnVuY3Rpb24ocnVubmVyLCBlbmdpbmUpIHtcXG4gICAgICAgIFJ1bm5lci5ydW4ocnVubmVyLCBlbmdpbmUpO1xcbiAgICB9O1xcblxcbiAgICAvKlxcbiAgICAqXFxuICAgICogIEV2ZW50cyBEb2N1bWVudGF0aW9uXFxuICAgICpcXG4gICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICogRmlyZWQgYXQgdGhlIHN0YXJ0IG9mIGEgdGljaywgYmVmb3JlIGFueSB1cGRhdGVzIHRvIHRoZSBlbmdpbmUgb3IgdGltaW5nXFxuICAgICpcXG4gICAgKiBAZXZlbnQgYmVmb3JlVGlja1xcbiAgICAqIEBwYXJhbSB7fSBldmVudCBBbiBldmVudCBvYmplY3RcXG4gICAgKiBAcGFyYW0ge251bWJlcn0gZXZlbnQudGltZXN0YW1wIFRoZSBlbmdpbmUudGltaW5nLnRpbWVzdGFtcCBvZiB0aGUgZXZlbnRcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQuc291cmNlIFRoZSBzb3VyY2Ugb2JqZWN0IG9mIHRoZSBldmVudFxcbiAgICAqIEBwYXJhbSB7fSBldmVudC5uYW1lIFRoZSBuYW1lIG9mIHRoZSBldmVudFxcbiAgICAqL1xcblxcbiAgICAvKipcXG4gICAgKiBGaXJlZCBhZnRlciBlbmdpbmUgdGltaW5nIHVwZGF0ZWQsIGJ1dCBqdXN0IGJlZm9yZSB1cGRhdGVcXG4gICAgKlxcbiAgICAqIEBldmVudCB0aWNrXFxuICAgICogQHBhcmFtIHt9IGV2ZW50IEFuIGV2ZW50IG9iamVjdFxcbiAgICAqIEBwYXJhbSB7bnVtYmVyfSBldmVudC50aW1lc3RhbXAgVGhlIGVuZ2luZS50aW1pbmcudGltZXN0YW1wIG9mIHRoZSBldmVudFxcbiAgICAqIEBwYXJhbSB7fSBldmVudC5zb3VyY2UgVGhlIHNvdXJjZSBvYmplY3Qgb2YgdGhlIGV2ZW50XFxuICAgICogQHBhcmFtIHt9IGV2ZW50Lm5hbWUgVGhlIG5hbWUgb2YgdGhlIGV2ZW50XFxuICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAqIEZpcmVkIGF0IHRoZSBlbmQgb2YgYSB0aWNrLCBhZnRlciBlbmdpbmUgdXBkYXRlIGFuZCBhZnRlciByZW5kZXJpbmdcXG4gICAgKlxcbiAgICAqIEBldmVudCBhZnRlclRpY2tcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQgQW4gZXZlbnQgb2JqZWN0XFxuICAgICogQHBhcmFtIHtudW1iZXJ9IGV2ZW50LnRpbWVzdGFtcCBUaGUgZW5naW5lLnRpbWluZy50aW1lc3RhbXAgb2YgdGhlIGV2ZW50XFxuICAgICogQHBhcmFtIHt9IGV2ZW50LnNvdXJjZSBUaGUgc291cmNlIG9iamVjdCBvZiB0aGUgZXZlbnRcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQubmFtZSBUaGUgbmFtZSBvZiB0aGUgZXZlbnRcXG4gICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICogRmlyZWQgYmVmb3JlIHVwZGF0ZVxcbiAgICAqXFxuICAgICogQGV2ZW50IGJlZm9yZVVwZGF0ZVxcbiAgICAqIEBwYXJhbSB7fSBldmVudCBBbiBldmVudCBvYmplY3RcXG4gICAgKiBAcGFyYW0ge251bWJlcn0gZXZlbnQudGltZXN0YW1wIFRoZSBlbmdpbmUudGltaW5nLnRpbWVzdGFtcCBvZiB0aGUgZXZlbnRcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQuc291cmNlIFRoZSBzb3VyY2Ugb2JqZWN0IG9mIHRoZSBldmVudFxcbiAgICAqIEBwYXJhbSB7fSBldmVudC5uYW1lIFRoZSBuYW1lIG9mIHRoZSBldmVudFxcbiAgICAqL1xcblxcbiAgICAvKipcXG4gICAgKiBGaXJlZCBhZnRlciB1cGRhdGVcXG4gICAgKlxcbiAgICAqIEBldmVudCBhZnRlclVwZGF0ZVxcbiAgICAqIEBwYXJhbSB7fSBldmVudCBBbiBldmVudCBvYmplY3RcXG4gICAgKiBAcGFyYW0ge251bWJlcn0gZXZlbnQudGltZXN0YW1wIFRoZSBlbmdpbmUudGltaW5nLnRpbWVzdGFtcCBvZiB0aGUgZXZlbnRcXG4gICAgKiBAcGFyYW0ge30gZXZlbnQuc291cmNlIFRoZSBzb3VyY2Ugb2JqZWN0IG9mIHRoZSBldmVudFxcbiAgICAqIEBwYXJhbSB7fSBldmVudC5uYW1lIFRoZSBuYW1lIG9mIHRoZSBldmVudFxcbiAgICAqL1xcblxcbiAgICAvKlxcbiAgICAqXFxuICAgICogIFByb3BlcnRpZXMgRG9jdW1lbnRhdGlvblxcbiAgICAqXFxuICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGZsYWcgdGhhdCBzcGVjaWZpZXMgd2hldGhlciB0aGUgcnVubmVyIGlzIHJ1bm5pbmcgb3Igbm90LlxcbiAgICAgKlxcbiAgICAgKiBAcHJvcGVydHkgZW5hYmxlZFxcbiAgICAgKiBAdHlwZSBib29sZWFuXFxuICAgICAqIEBkZWZhdWx0IHRydWVcXG4gICAgICovXFxuXFxuICAgIC8qKlxcbiAgICAgKiBBIGBCb29sZWFuYCB0aGF0IHNwZWNpZmllcyBpZiB0aGUgcnVubmVyIHNob3VsZCB1c2UgYSBmaXhlZCB0aW1lc3RlcCAob3RoZXJ3aXNlIGl0IGlzIHZhcmlhYmxlKS5cXG4gICAgICogSWYgdGltaW5nIGlzIGZpeGVkLCB0aGVuIHRoZSBhcHBhcmVudCBzaW11bGF0aW9uIHNwZWVkIHdpbGwgY2hhbmdlIGRlcGVuZGluZyBvbiB0aGUgZnJhbWUgcmF0ZSAoYnV0IGJlaGF2aW91ciB3aWxsIGJlIGRldGVybWluaXN0aWMpLlxcbiAgICAgKiBJZiB0aGUgdGltaW5nIGlzIHZhcmlhYmxlLCB0aGVuIHRoZSBhcHBhcmVudCBzaW11bGF0aW9uIHNwZWVkIHdpbGwgYmUgY29uc3RhbnQgKGFwcHJveGltYXRlbHksIGJ1dCBhdCB0aGUgY29zdCBvZiBkZXRlcm1pbmluaXNtKS5cXG4gICAgICpcXG4gICAgICogQHByb3BlcnR5IGlzRml4ZWRcXG4gICAgICogQHR5cGUgYm9vbGVhblxcbiAgICAgKiBAZGVmYXVsdCBmYWxzZVxcbiAgICAgKi9cXG5cXG4gICAgLyoqXFxuICAgICAqIEEgYE51bWJlcmAgdGhhdCBzcGVjaWZpZXMgdGhlIHRpbWUgc3RlcCBiZXR3ZWVuIHVwZGF0ZXMgaW4gbWlsbGlzZWNvbmRzLlxcbiAgICAgKiBJZiBgZW5naW5lLnRpbWluZy5pc0ZpeGVkYCBpcyBzZXQgdG8gYHRydWVgLCB0aGVuIGBkZWx0YWAgaXMgZml4ZWQuXFxuICAgICAqIElmIGl0IGlzIGBmYWxzZWAsIHRoZW4gYGRlbHRhYCBjYW4gZHluYW1pY2FsbHkgY2hhbmdlIHRvIG1haW50YWluIHRoZSBjb3JyZWN0IGFwcGFyZW50IHNpbXVsYXRpb24gc3BlZWQuXFxuICAgICAqXFxuICAgICAqIEBwcm9wZXJ0eSBkZWx0YVxcbiAgICAgKiBAdHlwZSBudW1iZXJcXG4gICAgICogQGRlZmF1bHQgMTAwMCAvIDYwXFxuICAgICAqL1xcblxcbn0pKCk7XFxuXFxuXFxuLyoqKi8gfSksXFxuLyogMjggKi9cXG4vKioqLyAoZnVuY3Rpb24obW9kdWxlLCBleHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XFxuXFxuLyoqXFxuKiBUaGlzIG1vZHVsZSBoYXMgbm93IGJlZW4gcmVwbGFjZWQgYnkgYE1hdHRlci5Db2xsaXNpb25gLlxcbipcXG4qIEFsbCB1c2FnZSBzaG91bGQgYmUgbWlncmF0ZWQgdG8gYE1hdHRlci5Db2xsaXNpb25gLlxcbiogRm9yIGJhY2stY29tcGF0aWJpbGl0eSBwdXJwb3NlcyB0aGlzIG1vZHVsZSB3aWxsIHJlbWFpbiBmb3IgYSBzaG9ydCB0ZXJtIGFuZCB0aGVuIGxhdGVyIHJlbW92ZWQgaW4gYSBmdXR1cmUgcmVsZWFzZS5cXG4qXFxuKiBUaGUgYE1hdHRlci5TQVRgIG1vZHVsZSBjb250YWlucyBtZXRob2RzIGZvciBk
2ZXRlY3RpbmcgY29sbGlzaW9ucyB1c2luZyB0aGUgU2VwYXJhdGluZyBBeGlzIFRoZW9yZW0uXFxuKlxcbiogQGNsYXNzIFNBVFxcbiogQGRlcHJlY2F0ZWRcXG4qL1xcblxcbnZhciBTQVQgPSB7fTtcXG5cXG5tb2R1bGUuZXhwb3J0cyA9IFNBVDtcXG5cXG52YXIgQ29sbGlzaW9uID0gX193ZWJwYWNrX3JlcXVpcmVfXyg4KTtcXG52YXIgQ29tbW9uID0gX193ZWJwYWNrX3JlcXVpcmVfXygwKTtcXG52YXIgZGVwcmVjYXRlZCA9IENvbW1vbi5kZXByZWNhdGVkO1xcblxcbihmdW5jdGlvbigpIHtcXG5cXG4gICAgLyoqXFxuICAgICAqIERldGVjdCBjb2xsaXNpb24gYmV0d2VlbiB0d28gYm9kaWVzIHVzaW5nIHRoZSBTZXBhcmF0aW5nIEF4aXMgVGhlb3JlbS5cXG4gICAgICogQGRlcHJlY2F0ZWQgcmVwbGFjZWQgYnkgQ29sbGlzaW9uLmNvbGxpZGVzXFxuICAgICAqIEBtZXRob2QgY29sbGlkZXNcXG4gICAgICogQHBhcmFtIHtib2R5fSBib2R5QVxcbiAgICAgKiBAcGFyYW0ge2JvZHl9IGJvZHlCXFxuICAgICAqIEByZXR1cm4ge2NvbGxpc2lvbn0gY29sbGlzaW9uXFxuICAgICAqL1xcbiAgICBTQVQuY29sbGlkZXMgPSBmdW5jdGlvbihib2R5QSwgYm9keUIpIHtcXG4gICAgICAgIHJldHVybiBDb2xsaXNpb24uY29sbGlkZXMoYm9keUEsIGJvZHlCKTtcXG4gICAgfTtcXG5cXG4gICAgZGVwcmVjYXRlZChTQVQsICdjb2xsaWRlcycsICdTQVQuY29sbGlkZXMg4p6kIHJlcGxhY2VkIGJ5IENvbGxpc2lvbi5jb2xsaWRlcycpO1xcblxcbn0pKCk7XFxuXFxuXFxuLyoqKi8gfSksXFxuLyogMjkgKi9cXG4vKioqLyAoZnVuY3Rpb24obW9kdWxlLCBleHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XFxuXFxuLyoqXFxuKiBUaGUgYE1hdHRlci5TdmdgIG1vZHVsZSBjb250YWlucyBtZXRob2RzIGZvciBjb252ZXJ0aW5nIFNWRyBpbWFnZXMgaW50byBhbiBhcnJheSBvZiB2ZWN0b3IgcG9pbnRzLlxcbipcXG4qIFRvIHVzZSB0aGlzIG1vZHVsZSB5b3UgYWxzbyBuZWVkIHRoZSBTVkdQYXRoU2VnIHBvbHlmaWxsOiBodHRwczovL2dpdGh1Yi5jb20vcHJvZ2Vycy9wYXRoc2VnXFxuKlxcbiogU2VlIHRoZSBpbmNsdWRlZCB1c2FnZSBbZXhhbXBsZXNdKGh0dHBzOi8vZ2l0aHViLmNvbS9saWFicnUvbWF0dGVyLWpzL3RyZWUvbWFzdGVyL2V4YW1wbGVzKS5cXG4qXFxuKiBAY2xhc3MgU3ZnXFxuKi9cXG5cXG52YXIgU3ZnID0ge307XFxuXFxubW9kdWxlLmV4cG9ydHMgPSBTdmc7XFxuXFxudmFyIEJvdW5kcyA9IF9fd2VicGFja19yZXF1aXJlX18oMSk7XFxudmFyIENvbW1vbiA9IF9fd2VicGFja19yZXF1aXJlX18oMCk7XFxuXFxuKGZ1bmN0aW9uKCkge1xcblxcbiAgICAvKipcXG4gICAgICogQ29udmVydHMgYW4gU1ZHIHBhdGggaW50byBhbiBhcnJheSBvZiB2ZWN0b3IgcG9pbnRzLlxcbiAgICAgKiBJZiB0aGUgaW5wdXQgcGF0aCBmb3JtcyBhIGNvbmNhdmUgc2hhcGUsIHlvdSBtdXN0IGRlY29tcG9zZSB0aGUgcmVzdWx0IGludG8gY29udmV4IHBhcnRzIGJlZm9yZSB1c2UuXFxuICAgICAqIFNlZSBgQm9kaWVzLmZyb21WZXJ0aWNlc2Agd2hpY2ggcHJvdmlkZXMgc3VwcG9ydCBmb3IgdGhpcy5cXG4gICAgICogTm90ZSB0aGF0IHRoaXMgZnVuY3Rpb24gaXMgbm90IGd1YXJhbnRlZWQgdG8gc3VwcG9ydCBjb21wbGV4IHBhdGhzIChzdWNoIGFzIHRob3NlIHdpdGggaG9sZXMpLlxcbiAgICAgKiBZb3UgbXVzdCBsb2FkIHRoZSBgcGF0aHNlZy5qc2AgcG9seWZpbGwgb24gbmV3ZXIgYnJvd3NlcnMuXFxuICAgICAqIEBtZXRob2QgcGF0aFRvVmVydGljZXNcXG4gICAgICogQHBhcmFtIHtTVkdQYXRoRWxlbWVudH0gcGF0aFxcbiAgICAgKiBAcGFyYW0ge051bWJlcn0gW3NhbXBsZUxlbmd0aD0xNV1cXG4gICAgICogQHJldHVybiB7VmVjdG9yW119IHBvaW50c1xcbiAgICAgKi9cXG4gICAgU3ZnLnBhdGhUb1ZlcnRpY2VzID0gZnVuY3Rpb24ocGF0aCwgc2FtcGxlTGVuZ3RoKSB7XFxuICAgICAgICBpZiAodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgJiYgISgnU1ZHUGF0aFNlZycgaW4gd2luZG93KSkge1xcbiAgICAgICAgICAgIENvbW1vbi53YXJuKCdTdmcucGF0aFRvVmVydGljZXM6IFNWR1BhdGhTZWcgbm90IGRlZmluZWQsIGEgcG9seWZpbGwgaXMgcmVxdWlyZWQuJyk7XFxuICAgICAgICB9XFxuXFxuICAgICAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vd291dC9zdmcudG9wb2x5LmpzL2Jsb2IvbWFzdGVyL3N2Zy50b3BvbHkuanNcXG4gICAgICAgIHZhciBpLCBpbCwgdG90YWwsIHBvaW50LCBzZWdtZW50LCBzZWdtZW50cywgXFxuICAgICAgICAgICAgc2VnbWVudHNRdWV1ZSwgbGFzdFNlZ21lbnQsIFxcbiAgICAgICAgICAgIGxhc3RQb2ludCwgc2VnbWVudEluZGV4LCBwb2ludHMgPSBbXSxcXG4gICAgICAgICAgICBseCwgbHksIGxlbmd0aCA9IDAsIHggPSAwLCB5ID0gMDtcXG5cXG4gICAgICAgIHNhbXBsZUxlbmd0aCA9IHNhbXBsZUxlbmd0aCB8fCAxNTtcXG5cXG4gICAgICAgIHZhciBhZGRQb2ludCA9IGZ1bmN0aW9uKHB4LCBweSwgcGF0aFNlZ1R5cGUpIHtcXG4gICAgICAgICAgICAvLyBhbGwgb2RkLW51bWJlcmVkIHBhdGggdHlwZXMgYXJlIHJlbGF0aXZlIGV4Y2VwdCBQQVRIU0VHX0NMT1NFUEFUSCAoMSlcXG4gICAgICAgICAgICB2Y
2XIgaXNSZWxhdGl2ZSA9IHBhdGhTZWdUeXBlICUgMiA9PT0gMSAmJiBwYXRoU2VnVHlwZSA+IDE7XFxuXFxuICAgICAgICAgICAgLy8gd2hlbiB0aGUgbGFzdCBwb2ludCBkb2Vzbid0IGVxdWFsIHRoZSBjdXJyZW50IHBvaW50IGFkZCB0aGUgY3VycmVudCBwb2ludFxcbiAgICAgICAgICAgIGlmICghbGFzdFBvaW50IHx8IHB4ICE9IGxhc3RQb2ludC54IHx8IHB5ICE9IGxhc3RQb2ludC55KSB7XFxuICAgICAgICAgICAgICAgIGlmIChsYXN0UG9pbnQgJiYgaXNSZWxhdGl2ZSkge1xcbiAgICAgICAgICAgICAgICAgICAgbHggPSBsYXN0UG9pbnQueDtcXG4gICAgICAgICAgICAgICAgICAgIGx5ID0gbGFzdFBvaW50Lnk7XFxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XFxuICAgICAgICAgICAgICAgICAgICBseCA9IDA7XFxuICAgICAgICAgICAgICAgICAgICBseSA9IDA7XFxuICAgICAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICAgICAgdmFyIHBvaW50ID0ge1xcbiAgICAgICAgICAgICAgICAgICAgeDogbHggKyBweCxcXG4gICAgICAgICAgICAgICAgICAgIHk6IGx5ICsgcHlcXG4gICAgICAgICAgICAgICAgfTtcXG5cXG4gICAgICAgICAgICAgICAgLy8gc2V0IGxhc3QgcG9pbnRcXG4gICAgICAgICAgICAgICAgaWYgKGlzUmVsYXRpdmUgfHwgIWxhc3RQb2ludCkge1xcbiAgICAgICAgICAgICAgICAgICAgbGFzdFBvaW50ID0gcG9pbnQ7XFxuICAgICAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICAgICAgcG9pbnRzLnB1c2gocG9pbnQpO1xcblxcbiAgICAgICAgICAgICAgICB4ID0gbHggKyBweDtcXG4gICAgICAgICAgICAgICAgeSA9IGx5ICsgcHk7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfTtcXG5cXG4gICAgICAgIHZhciBhZGRTZWdtZW50UG9pbnQgPSBmdW5jdGlvbihzZWdtZW50KSB7XFxuICAgICAgICAgICAgdmFyIHNlZ1R5cGUgPSBzZWdtZW50LnBhdGhTZWdUeXBlQXNMZXR0ZXIudG9VcHBlckNhc2UoKTtcXG5cXG4gICAgICAgICAgICAvLyBza2lwIHBhdGggZW5kc1xcbiAgICAgICAgICAgIGlmIChzZWdUeXBlID09PSAnWicpIFxcbiAgICAgICAgICAgICAgICByZXR1cm47XFxuXFxuICAgICAgICAgICAgLy8gbWFwIHNlZ21lbnQgdG8geCBhbmQgeVxcbiAgICAgICAgICAgIHN3aXRjaCAoc2VnVHlwZSkge1xcblxcbiAgICAgICAgICAgIGNhc2UgJ00nOlxcbiAgICAgICAgICAgIGNhc2UgJ0wnOlxcbiAgICAgICAgICAgIGNhc2UgJ1QnOlxcbiAgICAgICAgICAgIGNhc2UgJ0MnOlxcbiAgICAgICAgICAgIGNhc2UgJ1MnOlxcbiAgICAgICAgICAgIGNhc2UgJ1EnOlxcbiAgICAgICAgICAgICAgICB4ID0gc2VnbWVudC54O1xcbiAgICAgICAgICAgICAgICB5ID0gc2VnbWVudC55O1xcbiAgICAgICAgICAgICAgICBicmVhaztcXG4gICAgICAgICAgICBjYXNlICdIJzpcXG4gICAgICAgICAgICAgICAgeCA9IHNlZ21lbnQueDtcXG4gICAgICAgICAgICAgICAgYnJlYWs7XFxuICAgICAgICAgICAgY2FzZSAnVic6XFxuICAgICAgICAgICAgICAgIHkgPSBzZWdtZW50Lnk7XFxuICAgICAgICAgICAgICAgIGJyZWFrO1xcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICBhZGRQb2ludCh4LCB5LCBzZWdtZW50LnBhdGhTZWdUeXBlKTtcXG4gICAgICAgIH07XFxuXFxuICAgICAgICAvLyBlbnN1cmUgcGF0aCBpcyBhYnNvbHV0ZVxcbiAgICAgICAgU3ZnLl9zdmdQYXRoVG9BYnNvbHV0ZShwYXRoKTtcXG5cXG4gICAgICAgIC8vIGdldCB0b3RhbCBsZW5ndGhcXG4gICAgICAgIHRvdGFsID0gcGF0aC5nZXRUb3RhbExlbmd0aCgpO1xcblxcbiAgICAgICAgLy8gcXVldWUgc2VnbWVudHNcXG4gICAgICAgIHNlZ21lbnRzID0gW107XFxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgcGF0aC5wYXRoU2VnTGlzdC5udW1iZXJPZkl0ZW1zOyBpICs9IDEpXFxuICAgICAgICAgICAgc2VnbWVudHMucHVzaChwYXRoLnBhdGhTZWdMaXN0LmdldEl0ZW0oaSkpO1xcblxcbiAgICAgICAgc2VnbWVudHNRdWV1ZSA9IHNlZ21lbnRzLmNvbmNhdCgpO1xcblxcbiAgICAgICAgLy8gc2FtcGxlIHRocm91Z2ggcGF0aFxcbiAgICAgICAgd2hpbGUgKGxlbmd0aCA8IHRvdGFsKSB7XFxuICAgICAgICAgICAgLy8gZ2V0IHNlZ21lbnQgYXQgcG9zaXRpb25cXG4gICAgICAgICAgICBzZWdtZW50SW5kZXggPSBwYXRoLmdldFBhdGhTZWdBdExlbmd0aChsZW5ndGgpO1xcbiAgICAgICAgICAgIHNlZ21lbnQgPSBzZWdtZW50c1tzZWdtZW50SW5kZXhdO1xcblxcbiAgICAgICAgICAgIC8vIG5ldyBzZWdtZW50XFxuICAgICAgICAgICAgaWYgKHNlZ21lbnQgIT0gbGFzdFNlZ21lbnQpIHtcXG4gICAgICAgICAgICAgICAgd2hpbGUgKHNlZ21lbnRzUXVldWUubGVuZ3RoICYmIHNlZ21lbnRzUXVldWVbMF0gIT0gc2VnbWVudClcXG4gICAgICAgICAgICAgICAgICAgIGFkZFNlZ21lbnRQb2ludChzZWdtZW50c1F1ZXVlLnNoaWZ0KCkpO1xcblxcbiAgICAgICAgICAgICAgICBsYXN0U2VnbWVudCA9IHNlZ21lbnQ7XFxuICAgICAgICAgICAgfVxcblxcbiAgICAgICAgICAgIC8vIGFkZCBwb2ludHMgaW4gYmV0d2VlbiB3aGVuIGN1cnZpbmdcXG4gICAgICAgICAgICAvLyBUT0RPOiBhZGFwdGl2ZSBzYW1wbGluZ1xcbiAgICAgICAgICAgIHN3aXRjaCAoc2VnbWVudC5wYXRoU2VnVHlwZUFzTGV0dGVyLnRvVXBwZXJDYXNlKCkpIHtcXG5cXG4gICAgICAgICAgICBjYXNlICdDJzpcXG4gICAgICAgICAgICBjYXNlICdUJzpcXG4gICAgICAgICAgICBjYXNlICdTJzpcXG4gICAgICAgICAgICBjYXNlICdRJzpcXG4gICAgICAgICAgICBjYXNlICdBJzpcXG4gICAgICAgICAgICAgICAgcG9pbnQgPSBwYXRoLmdldFBvaW50QXRMZW5ndGgobGVuZ3RoKTtcXG4gICAgICAgICAgICAgICAgYWRkUG9pbnQocG9pbnQueCwgcG9pbnQueSwgMCk7XFxuICAgICAgICAgICAgICAgIGJyZWFrO1xcblxcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICAvLyBpbmNyZW1lbnQgYnkgc2FtcGxlIHZhbHVlXFxuICAgICAgICAgICAgbGVuZ3RoICs9IHNhbXBsZUxlbmd0aDtcXG4gICAgICAgIH1cXG5cXG4gICAgICAgIC8vIGFkZCByZW1haW5pbmcgc2VnbWVudHMgbm90IHBhc3NlZCBieSBzYW1wbGluZ1xcbiAgICAgICAgZm9yIChpID0gMCwgaWwgPSBzZWdtZW50c1F1ZXVlLmxlbmd0aDsgaSA8IGlsOyArK2kpXFxuICAgICAgICAgICAgYWRkU2VnbWVudFBvaW50KHNlZ21lbnRzUXVldWVbaV0pO1xcblxcbiAgICAgICAgcmV0dXJuIHBvaW50cztcXG4gICAgfTtcXG5cXG4gICAgU3ZnLl9zdmdQYXRoVG9BYnNvbHV0ZSA9IGZ1bmN0aW9uKHBhdGgpIHtcXG4gICAgICAgIC8vIGh0dHA6Ly9waHJvZ3oubmV0L2NvbnZlcnQtc3ZnLXBhdGgtdG8tYWxsLWFic29sdXRlLWNvbW1hbmRzXFxuICAgICAgICAvLyBDb3B5cmlnaHQgKGMpIEdhdmluIEtpc3RuZXJcXG4gICAgICAgIC8vIGh0dHA6Ly9waHJvZ3oubmV0L2pzL19SZXVzZUxpY2Vuc2UudHh0XFxuICAgICAgICAvLyBNb2RpZmljYXRpb25zOiB0aWR5IGZvcm1hdHRpbmcgYW5kIG5hbWluZ1xcbiAgICAgICAgdmFyIHgwLCB5MCwgeDEsIHkxLCB4MiwgeTIsIHNlZ3MgPSBwYXRoLnBhdGhTZWdMaXN0LFxcbiAgICAgICAgICAgI
2HggPSAwLCB5ID0gMCwgbGVuID0gc2Vncy5udW1iZXJPZkl0ZW1zO1xcblxcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW47ICsraSkge1xcbiAgICAgICAgICAgIHZhciBzZWcgPSBzZWdzLmdldEl0ZW0oaSksXFxuICAgICAgICAgICAgICAgIHNlZ1R5cGUgPSBzZWcucGF0aFNlZ1R5cGVBc0xldHRlcjtcXG5cXG4gICAgICAgICAgICBpZiAoL1tNTEhWQ1NRVEFdLy50ZXN0KHNlZ1R5cGUpKSB7XFxuICAgICAgICAgICAgICAgIGlmICgneCcgaW4gc2VnKSB4ID0gc2VnLng7XFxuICAgICAgICAgICAgICAgIGlmICgneScgaW4gc2VnKSB5ID0gc2VnLnk7XFxuICAgICAgICAgICAgfSBlbHNlIHtcXG4gICAgICAgICAgICAgICAgaWYgKCd4MScgaW4gc2VnKSB4MSA9IHggKyBzZWcueDE7XFxuICAgICAgICAgICAgICAgIGlmICgneDInIGluIHNlZykgeDIgPSB4ICsgc2VnLngyO1xcbiAgICAgICAgICAgICAgICBpZiAoJ3kxJyBpbiBzZWcpIHkxID0geSArIHNlZy55MTtcXG4gICAgICAgICAgICAgICAgaWYgKCd5MicgaW4gc2VnKSB5MiA9IHkgKyBzZWcueTI7XFxuICAgICAgICAgICAgICAgIGlmICgneCcgaW4gc2VnKSB4ICs9IHNlZy54O1xcbiAgICAgICAgICAgICAgICBpZiAoJ3knIGluIHNlZykgeSArPSBzZWcueTtcXG5cXG4gICAgICAgICAgICAgICAgc3dpdGNoIChzZWdUeXBlKSB7XFxuXFxuICAgICAgICAgICAgICAgIGNhc2UgJ20nOlxcbiAgICAgICAgICAgICAgICAgICAgc2Vncy5yZXBsYWNlSXRlbShwYXRoLmNyZWF0ZVNWR1BhdGhTZWdNb3ZldG9BYnMoeCwgeSksIGkpO1xcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XFxuICAgICAgICAgICAgICAgIGNhc2UgJ2wnOlxcbiAgICAgICAgICAgICAgICAgICAgc2Vncy5yZXBsYWNlSXRlbShwYXRoLmNyZWF0ZVNWR1BhdGhTZWdMaW5ldG9BYnMoeCwgeSksIGkpO1xcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XFxuICAgICAgICAgICAgICAgIGNhc2UgJ2gnOlxcbiAgICAgICAgICAgICAgICAgICAgc2Vncy5yZXBsYWNlSXRlbShwYXRoLmNyZWF0ZVNWR1BhdGhTZWdMaW5ldG9Ib3Jpem9udGFsQWJzKHgpLCBpKTtcXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xcbiAgICAgICAgICAgICAgICBjYXNlICd2JzpcXG4gICAgICAgICAgICAgICAgICAgIHNlZ3MucmVwbGFjZUl0ZW0ocGF0aC5jcmVhdGVTVkdQYXRoU2VnTGluZXRvVmVydGljYWxBYnMoeSksIGkpO1xcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XFxuICAgICAgICAgICAgICAgIGNhc2UgJ2MnOlxcbiAgICAgICAgICAgICAgICAgICAgc2Vncy5yZXBsYWNlSXRlbShwYXRoLmNyZWF0ZVNWR1BhdGhTZWdDdXJ2ZXRvQ3ViaWNBYnMoeCwgeSwgeDEsIHkxLCB4MiwgeTIpLCBpKTtcXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xcbiAgICAgICAgICAgICAgICBjYXNlICdzJzpcXG4gICAgICAgICAgICAgICAgICAgIHNlZ3MucmVwbGFjZUl0ZW0ocGF0aC5jcmVhdGVTVkdQYXRoU2VnQ3VydmV0b0N1YmljU21vb3RoQWJzKHgsIHksIHgyLCB5MiksIGkpO1xcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XFxuICAgICAgICAgICAgICAgIGNhc2UgJ3EnOlxcbiAgICAgICAgICAgICAgICAgICAgc2Vncy5yZXBsYWNlSXRlbShwYXRoLmNyZWF0ZVNWR1BhdGhTZWdDdXJ2ZXRvUXVhZHJhdGljQWJzKHgsIHksIHgxLCB5MSksIGkpO1xcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XFxuICAgICAgICAgICAgICAgIGNhc2UgJ3QnOlxcbiAgICAgICAgICAgICAgICAgICAgc2Vncy5yZXBsYWNlSXRlbShwYXRoLmNyZWF0ZVNWR1BhdGhTZWdDdXJ2ZXRvUXVhZHJhdGljU21vb3RoQWJzKHgsIHkpLCBpKTtcXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xcbiAgICAgICAgICAgICAgICBjYXNlICdhJzpcXG4gICAgICAgICAgICAgICAgICAgIHNlZ3MucmVwbGFjZUl0ZW0ocGF0aC5jcmVhdGVTVkdQYXRoU2VnQXJjQWJzKHgsIHksIHNlZy5yMSwgc2VnLnIyLCBzZWcuYW5nbGUsIHNlZy5sYXJnZUFyY0ZsYWcsIHNlZy5zd2VlcEZsYWcpLCBpKTtcXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xcbiAgICAgICAgICAgICAgICBjYXNlICd6JzpcXG4gICAgICAgICAgICAgICAgY2FzZSAnWic6XFxuICAgICAgICAgICAgICAgICAgICB4ID0geDA7XFxuICAgICAgICAgICAgICAgICAgICB5ID0geTA7XFxuICAgICAgICAgICAgICAgICAgICBicmVhaztcXG5cXG4gICAgICAgICAgICAgICAgfVxcbiAgICAgICAgICAgIH1cXG5cXG4gICAgICAgICAgICBpZiAoc2VnVHlwZSA9PSAnTScgfHwgc2VnVHlwZSA9PSAnbScpIHtcXG4gICAgICAgICAgICAgICAgeDAgPSB4O1xcbiAgICAgICAgICAgICAgICB5MCA9IHk7XFxuICAgICAgICAgICAgfVxcbiAgICAgICAgfVxcbiAgICB9O1xcblxcbn0pKCk7XFxuXFxuLyoqKi8gfSksXFxuLyogMzAgKi9cXG4vKioqLyAoZnVuY3Rpb24obW9kdWxlLCBleHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKSB7XFxuXFxuLyoqXFxuKiBUaGlzIG1vZHVsZSBoYXMgbm93IGJlZW4gcmVwbGFjZWQgYnkgYE1hdHRlci5Db21wb3NpdGVgLlxcbipcXG4qIEFsbCB1c2FnZSBzaG91bGQgYmUgbWlncmF0ZWQgdG8gdGhlIGVxdWl2YWxlbnQgZnVuY3Rpb25zIGZvdW5kIG9uIGBNYXR0ZXIuQ29tcG9zaXRlYC5cXG4qIEZvciBleGFtcGxlIGBXb3JsZC5hZGQod29ybGQsIGJvZHkpYCBub3cgYmVjb21lcyBgQ29tcG9zaXRlLmFkZCh3b3JsZCwgYm9keSlgLlxcbipcXG4qIFRoZSBwcm9wZXJ0eSBgd29ybGQuZ3Jhdml0eWAgaGFzIGJlZW4gbW92ZWQgdG8gYGVuZ2luZS5ncmF2aXR5YC5cXG4qXFxuKiBGb3IgYmFjay1jb21wYXRpYmlsaXR5IHB1cnBvc2VzIHRoaXMgbW9kdWxlIHdpbGwgcmVtYWluIGFzIGEgZGlyZWN0IGFsaWFzIHRvIGBNYXR0ZXIuQ29tcG9zaXRlYCBpbiB0aGUgc2hvcnQgdGVybSBkdXJpbmcgbWlncmF0aW9uLlxcbiogRXZlbnR1YWxseSB0aGlzIGFsaWFzIG1vZHVsZSB3aWxsIGJlIG1hcmtlZCBhcyBkZXByZWNhdGVkIGFuZCB0aGVuIGxhdGVyIHJlbW92ZWQgaW4gYSBmdXR1cmUgcmVsZWFzZS5cXG4qXFxuKiBAY2xhc3MgV29ybGRcXG4qL1xcblxcbnZhciBXb3JsZCA9IHt9O1xcblxcbm1vZHVsZS5leHBvcnRzID0gV29ybGQ7XFxuXFxudmFyIENvbXBvc2l0ZSA9IF9fd2VicGFja19yZXF1aXJlX18oNik7XFxudmFyIENvbW1vbiA9IF9fd2VicGFja19yZXF1aXJlX18oMCk7XFxuXFxuKGZ1bmN0aW9uKCkge1xcblxcbiAgICAvKipcXG4gICAgICogU2VlIGFib3ZlLCBhbGlhc2VzIGZvciBiYWNrIGNvbXBhdGliaWxpdHkgb25seVxcbiAgICAgKi9cXG4gICAgV29ybGQuY3JlYXRlID0gQ29tcG9zaXRlLmNyZWF0ZTtcXG4gICAgV29ybGQuYWRkID0gQ29tcG9zaXRlLmFkZDtcXG4gICAgV29ybGQucmVtb3ZlID0gQ29tcG9zaXRlLnJlbW92ZTtcXG4gICAgV29ybGQuY2xlYXIgPSBDb21wb3NpdGUuY2xlYXI7XFxuICAgIFdvcmxkLmFkZENvbXBvc2l0ZSA9IENvbXBvc2l0ZS5hZGRDb21wb3NpdGU7XFxuICAgIFdvcmxkLmFkZEJvZHkgPSBDb21wb3NpdGUuYWRkQm9keTtcXG4gICAgV29ybGQuYWRk
2Q29uc3RyYWludCA9IENvbXBvc2l0ZS5hZGRDb25zdHJhaW50O1xcblxcbn0pKCk7XFxuXFxuXFxuLyoqKi8gfSlcXG4vKioqKioqLyBdKTtcXG59KTtcXG4vKiBXRUJQQUNLIFZBUiBJTkpFQ1RJT04gKi99LmNhbGwodGhpcywgX193ZWJwYWNrX3JlcXVpcmVfXygvKiEgLi8uLi8uLi93ZWJwYWNrL2J1aWxkaW4vZ2xvYmFsLmpzICovIFxcXCIuL25vZGVfbW9kdWxlcy93ZWJwYWNrL2J1aWxkaW4vZ2xvYmFsLmpzXFxcIikpKVxcblxcbi8vIyBzb3VyY2VVUkw9d2VicGFjazovLy8uL25vZGVfbW9kdWxlcy9tYXR0ZXItanMvYnVpbGQvbWF0dGVyLmpzP1wiKTtcbiAgICAvKioqL1xuICB9LFxuXG4gIC8qKiovXG4gIFwiLi9ub2RlX21vZHVsZXMvd2VicGFjay9idWlsZGluL2dsb2JhbC5qc1wiOlxuICAvKiEqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiEqXFxcbiAgICAhKioqICh3ZWJwYWNrKS9idWlsZGluL2dsb2JhbC5qcyAqKiohXG4gICAgXFwqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuICAvKiEgbm8gc3RhdGljIGV4cG9ydHMgZm91bmQgKi9cblxuICAvKioqL1xuICBmdW5jdGlvbiBub2RlX21vZHVsZXNXZWJwYWNrQnVpbGRpbkdsb2JhbEpzKG1vZHVsZSwgZXhwb3J0cykge1xuICAgIGV2YWwoXCJ2YXIgZztcXG5cXG4vLyBUaGlzIHdvcmtzIGluIG5vbi1zdHJpY3QgbW9kZVxcbmcgPSAoZnVuY3Rpb24oKSB7XFxuXFx0cmV0dXJuIHRoaXM7XFxufSkoKTtcXG5cXG50cnkge1xcblxcdC8vIFRoaXMgd29ya3MgaWYgZXZhbCBpcyBhbGxvd2VkIChzZWUgQ1NQKVxcblxcdGcgPSBnIHx8IG5ldyBGdW5jdGlvbihcXFwicmV0dXJuIHRoaXNcXFwiKSgpO1xcbn0gY2F0Y2ggKGUpIHtcXG5cXHQvLyBUaGlzIHdvcmtzIGlmIHRoZSB3aW5kb3cgcmVmZXJlbmNlIGlzIGF2YWlsYWJsZVxcblxcdGlmICh0eXBlb2Ygd2luZG93ID09PSBcXFwib2JqZWN0XFxcIikgZyA9IHdpbmRvdztcXG59XFxuXFxuLy8gZyBjYW4gc3RpbGwgYmUgdW5kZWZpbmVkLCBidXQgbm90aGluZyB0byBkbyBhYm91dCBpdC4uLlxcbi8vIFdlIHJldHVybiB1bmRlZmluZWQsIGluc3RlYWQgb2Ygbm90aGluZyBoZXJlLCBzbyBpdCdzXFxuLy8gZWFzaWVyIHRvIGhhbmRsZSB0aGlzIGNhc2UuIGlmKCFnbG9iYWwpIHsgLi4ufVxcblxcbm1vZHVsZS5leHBvcnRzID0gZztcXG5cXG5cXG4vLyMgc291cmNlVVJMPXdlYnBhY2s6Ly8vKHdlYnBhY2spL2J1aWxkaW4vZ2xvYmFsLmpzP1wiKTtcbiAgICAvKioqL1xuICB9XG4gIC8qKioqKiovXG5cbn0pOyJdLCJuYW1lcyI6WyJfdHlwZW9mIiwib2JqIiwiU3ltYm9sIiwiaXRlcmF0b3IiLCJjb25zdHJ1Y3RvciIsInByb3RvdHlwZSIsIm1vZHVsZXMiLCJpbnN0YWxsZWRNb2R1bGVzIiwiX193ZWJwYWNrX3JlcXVpcmVfXyIsIm1vZHVsZUlkIiwiZXhwb3J0cyIsIm1vZHVsZSIsImkiLCJsIiwiY2FsbCIsIm0iLCJjIiwiZCIsIm5hbWUiLCJnZXR0ZXIiLCJvIiwiT2JqZWN0IiwiZGVmaW5lUHJvcGVydHkiLCJlbnVtZXJhYmxlIiwiZ2V0IiwiciIsInRvU3RyaW5nVGFnIiwidmFsdWUiLCJ0IiwibW9kZSIsIl9fZXNNb2R1bGUiLCJucyIsImNyZWF0ZSIsImtleSIsImJpbmQiLCJuIiwib2JqZWN0IiwicHJvcGVydHkiLCJoYXNPd25Qcm9wZXJ0eSIsInAiLCJzIiwiLi9hc3NldHMvc3JjL2pzL21haW4uanMiLCJhc3NldHNTcmNKc01haW5KcyIsIl9fd2VicGFja19leHBvcnRzX18iLCJldmFsIiwiLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvYWNjb3JkaW9uLmpzIiwiYXNzZXRzU3JjSnNNb2R1bGVzQWNjb3JkaW9uSnMiLCIuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9hc2lkZS5qcyIsImFzc2V0c1NyY0pzTW9kdWxlc0FzaWRlSnMiLCIuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9ibG9nRmlsdGVycy5qcyIsImFzc2V0c1NyY0pzTW9kdWxlc0Jsb2dGaWx0ZXJzSnMiLCIuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9jYXJvdXNlbC5qcyIsImFzc2V0c1NyY0pzTW9kdWxlc0Nhcm91c2VsSnMiLCIuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9jZjcuanMiLCJhc3NldHNTcmNKc01vZHVsZXNDZjdKcyIsIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2N1cnNvci5qcyIsImFzc2V0c1NyY0pzTW9kdWxlc0N1cnNvckpzIiwiLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvZmlsZS5qcyIsImFzc2V0c1NyY0pzTW9kdWxlc0ZpbGVKcyIsIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2Zvb3Rlci5qcyIsImFzc2V0c1NyY0pzTW9kdWxlc0Zvb3RlckpzIiwiLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvZ3NhcC9jdXJ0YWluLmpzIiwiYXNzZXRzU3JjSnNNb2R1bGVzR3NhcEN1cnRhaW5KcyIsIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2dzYXAvZWFzZXMuanMiLCJhc3NldHNTcmNKc01vZHVsZXNHc2FwRWFzZXNKcyIsIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2dzYXAvZmVhdHVyZXMuanMiLCJhc3NldHNTcmNKc01vZHVsZXNHc2FwRmVhdHVyZXNKcyIsIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2dzYXAvaW50cm8uanMiLCJhc3NldHNTcmNKc01vZHVsZXNHc2FwSW50cm9KcyIsIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2dzYXAvc2Nyb2xsVHJpZ2dlci5qcyIsImFzc2V0c1NyY0pzTW9kdWxlc0dzYXBTY3JvbGxUcmlnZ2VySnMiLCIuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9oZWxwZXIuanMiLCJhc3NldHNTcmNKc01vZHVsZXNIZWxwZXJKcyIsIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL2luY2x1c2lvbi5qcyIsImFzc2V0c1NyY0pzTW9kdWxlc0luY2x1c2lvbkpzIiwiLi9hc3NldHMvc3JjL2pzL21vZHVsZXMvam9iLmpzIiwiYXNzZXRzU3JjSnNNb2R1bGVzSm9iSnMiLCIuL2Fzc2V0cy9zcmMvanMvbW9kdWxlcy9tYXR0ZXIuanMiLCJhc3NldHNTcmNKc01vZHVsZXNNYXR0ZXJKcyIsIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL21lZGlhLmpzIiwiYXNzZXRzU3JjSnNNb2R1bGVzTWVkaWFKcyIsIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL21lbnVzLmpzIiwiYXNzZXRzU3JjSnNNb2R1bGVzTWVudXNKcyIsIi4vYXNzZXRzL3NyYy9qcy9tb2R1bGVzL3NlY3Rpb24uanMiLCJhc3NldHNTcmNKc01vZHVsZXNTZWN0aW9uSnMiLCIuL2xpYnJhcmllcy9wcngtZmlsdGVycy9wcngtZmlsdGVycy5qcyIsImxpYnJhcmllc1ByeEZpbHRlcnNQcnhGaWx0ZXJzSnMiLCIuL2xpYnJhcmllcy9wcngtaGVscGVycy9wcngtaGVscGVycy5qcyIsImxpYnJhcmllc1ByeEhlbHBlcnNQcnhIZWxwZXJzSnMiLCIuL2xpYnJhcmllcy9wcngtbWFycXVlZS9wcngtbWFycXVlZS5qcyIsImxpYnJhcmllc1ByeE1hcnF1ZW
2VQcnhNYXJxdWVlSnMiLCIuL2xpYnJhcmllcy9wcngtc2Nyb2xsL3ByeC1zY3JvbGwuanMiLCJsaWJyYXJpZXNQcnhTY3JvbGxQcnhTY3JvbGxKcyIsIi4vbm9kZV9tb2R1bGVzL2Z1enp5c29ydC9mdXp6eXNvcnQuanMiLCJub2RlX21vZHVsZXNGdXp6eXNvcnRGdXp6eXNvcnRKcyIsIi4vbm9kZV9tb2R1bGVzL21hdHRlci1qcy9idWlsZC9tYXR0ZXIuanMiLCJub2RlX21vZHVsZXNNYXR0ZXJKc0J1aWxkTWF0dGVySnMiLCIuL25vZGVfbW9kdWxlcy93ZWJwYWNrL2J1aWxkaW4vZ2xvYmFsLmpzIiwibm9kZV9tb2R1bGVzV2VicGFja0J1aWxkaW5HbG9iYWxKcyJdLCJtYXBwaW5ncyI6ImFBRUEsU0FBU0EsUUFBUUMsR0FBbVYsT0FBdE9ELFFBQXJELG1CQUFYRSxRQUFvRCxpQkFBcEJBLE9BQU9DLFNBQW1DLFNBQWlCRixHQUFPLGNBQWNBLEdBQTJCLFNBQWlCQSxHQUFPLE9BQU9BLEdBQXlCLG1CQUFYQyxRQUF5QkQsRUFBSUcsY0FBZ0JGLFFBQVVELElBQVFDLE9BQU9HLFVBQVksZ0JBQWtCSixJQUF5QkEsSUFHblgsU0FBV0ssR0FPVCxJQUFJQyxFQUFtQixHQVF2QixTQUFTQyxFQUFvQkMsR0FPM0IsR0FBSUYsRUFBaUJFLEdBRW5CLE9BQU9GLEVBQWlCRSxHQUFVQyxRQVNwQyxJQUFJQyxFQUFTSixFQUFpQkUsR0FBWSxDQUV4Q0csRUFBR0gsRUFHSEksR0FBRyxFQUdISCxRQUFTLElBMkJYLE9BaEJBSixFQUFRRyxHQUFVSyxLQUFLSCxFQUFPRCxRQUFTQyxFQUFRQSxFQUFPRCxRQUFTRixHQVEvREcsRUFBT0UsR0FBSSxFQVFKRixFQUFPRCxRQWFoQkYsRUFBb0JPLEVBQUlULEVBUXhCRSxFQUFvQlEsRUFBSVQsRUFReEJDLEVBQW9CUyxFQUFJLFNBQVVQLEVBQVNRLEVBQU1DLEdBRTFDWCxFQUFvQlksRUFBRVYsRUFBU1EsSUFFbENHLE9BQU9DLGVBQWVaLEVBQVNRLEVBQU0sQ0FDbkNLLFlBQVksRUFDWkMsSUFBS0wsS0FlWFgsRUFBb0JpQixFQUFJLFNBQVVmLEdBRVYsb0JBQVhSLFFBQTBCQSxPQUFPd0IsYUFFMUNMLE9BQU9DLGVBQWVaLEVBQVNSLE9BQU93QixZQUFhLENBQ2pEQyxNQUFPLFdBT1hOLE9BQU9DLGVBQWVaLEVBQVMsYUFBYyxDQUMzQ2lCLE9BQU8sS0F3QlhuQixFQUFvQm9CLEVBQUksU0FBVUQsRUFBT0UsR0FLdkMsR0FIVyxFQUFQQSxJQUFVRixFQUFRbkIsRUFBb0JtQixJQUcvQixFQUFQRSxFQUFVLE9BQU9GLEVBR3JCLEdBQVcsRUFBUEUsR0FBK0IsV0FBbkI3QixRQUFRMkIsSUFBdUJBLEdBQVNBLEVBQU1HLFdBQVksT0FBT0gsRUFHakYsSUFBSUksRUFBS1YsT0FBT1csT0FBTyxNQWF2QixHQVZBeEIsRUFBb0JpQixFQUFFTSxHQUl0QlYsT0FBT0MsZUFBZVMsRUFBSSxVQUFXLENBQ25DUixZQUFZLEVBQ1pJLE1BQU9BLElBSUUsRUFBUEUsR0FBNEIsaUJBQVRGLEVBQW1CLElBQUssSUFBSU0sS0FBT04sRUFDeERuQixFQUFvQlMsRUFBRWMsRUFBSUUsRUFBSyxTQUFVQSxHQUN2QyxPQUFPTixFQUFNTSxJQUNiQyxLQUFLLEtBQU1ELElBSWYsT0FBT0YsR0FXVHZCLEVBQW9CMkIsRUFBSSxTQUFVeEIsR0FFaEMsSUFBSVEsRUFBU1IsR0FBVUEsRUFBT21CLFdBRTlCLFdBQ0UsT0FBT25CLEVBQWdCLFNBR3pCLFdBQ0UsT0FBT0EsR0FRVCxPQUpBSCxFQUFvQlMsRUFBRUUsRUFBUSxJQUFLQSxHQUk1QkEsR0FXVFgsRUFBb0JZLEVBQUksU0FBVWdCLEVBQVFDLEdBQ3hDLE9BQU9oQixPQUFPaEIsVUFBVWlDLGVBQWV4QixLQUFLc0IsRUFBUUMsSUFVdEQ3QixFQUFvQitCLEVBQUksR0FVakIvQixFQUFvQkEsRUFBb0JnQyxFQUFJLDJCQXRQckQsQ0E0UEUsQ0FFQUMsMEJBUUEsU0FBU0Msa0JBQWtCL0IsT0FBUWdDLG9CQUFxQm5DLHFCQUd0RG9DLEtBQUssNHZOQUtQQyx1Q0FRQSxTQUFTQyw4QkFBOEJuQyxPQUFRZ0Msb0JBQXFCbkMscUJBR2xFb0MsS0FBSywrNUNBS1BHLG1DQVFBLFNBQVNDLDBCQUEwQnJDLE9BQVFnQyxvQkFBcUJuQyxxQkFHOURvQyxLQUFLLDRqREFLUEsseUNBUUEsU0FBU0MsZ0NBQWdDdkMsT0FBUWdDLG9CQUFxQm5DLHFCQUdwRW9DLEtBQUsseVZBS1BPLHNDQVFBLFNBQVNDLDZCQUE2QnpDLE9BQVFnQyxvQkFBcUJuQyxxQkFHakVvQyxLQUFLLDAvSEFLUFMsaUNBUUEsU0FBU0Msd0JBQXdCM0MsT0FBUWdDLG9CQUFxQm5DLHFCQUc1RG9DLEtBQUsscTZDQUtQVyxvQ0FRQSxTQUFTQywyQkFBMkI3QyxPQUFRZ0Msb0JBQXFCbkMscUJBRy9Eb0MsS0FBSyxnbkVBS1BhLGtDQVFBLFNBQVNDLHlCQUF5Qi9DLE9BQVFnQyxvQkFBcUJuQyxxQkFHN0RvQyxLQUFLLDIzREFLUGUsb0NBUUEsU0FBU0MsMkJBQTJCakQsT0FBUWdDLG9CQUFxQm5DLHFCQUcvRG9DLEtBQUssc3JDQUtQaUIsMENBUUEsU0FBU0MsZ0NBQWdDbkQsT0FBUWdDLG9CQUFxQm5DLHFCQUdwRW9DLEtBQUssZ3pGQUtQbUIsd0NBUUEsU0FBU0MsOEJBQThCckQsT0FBUWdDLG9CQUFxQm5DLHFCQUdsRW9DLEtBQUssNnZEQUtQcUIsMkNBUUEsU0FBU0MsaUNBQWlDdkQsT0FBUWdDLG9CQUFxQm5DLHFCQUdyRW9DLEtBQUssMm1JQUtQdUIsd0NBUUEsU0FBU0MsOEJBQThCekQsT0FBUWdDLG9CQUFxQm5DLHFCQUdsRW9DLEtBQUssa29DQUtQeUIsZ0RBUUEsU0FBU0Msc0NBQXNDM0QsT0FBUWdDLG9CQUFxQm5DLHFCQUcxRW9DLEtBQUssaWtCQUtQMkIsb0NBUUEsU0FBU0MsMkJBQTJCN0QsT0FBUWdDLG9CQUFxQm5DLHFCQUcvRG9DLEtBQUssczBCQUtQNkIsdUNBUUEsU0FBU0MsOEJBQThCL0QsT0FBUWdDLG9CQUFxQm5DLHFCQUdsRW9DLEtBQUssZ1ZBS1ArQixpQ0FRQSxTQUFTQyx3QkFBd0JqRSxPQUFRZ0Msb0JBQXFCbkMscUJBRzVEb0MsS0FBSyxpOENBS1BpQyxvQ0FRQSxTQUFTQywyQkFBMkJuRSxPQUFRZ0Msb0JBQXFCbkMscUJBRy9Eb0MsS0FBSyxxdUtBS1BtQyxtQ0FRQSxTQUFTQywwQkFBMEJyRSxPQUFRZ0Msb0JBQXFCbkMscUJBRzlEb0MsS0FBSywyZEFLUHFDLG1DQVFBLFNBQVNDLDBCQUEwQnZFLE9BQVFnQyxvQkFBcUJuQyxxQkFHOURvQyxLQUFLLDhzRkFLUHVDLHFDQVFBLFNBQVNDLDRCQUE0QnpFLE9BQVFnQyxvQkFBcUJuQyxxQkFHaEVvQyxLQUFLLGtrQkFLUHlDLHlDQVFBLFNBQVNDLGdDQUFnQzNFLE9BQVFnQyxvQkFBcUJuQyxxQkFHcEVvQyxLQUFLLDY0UUFLUDJDLHlDQVFBLFNBQVNDLGdDQUFnQzd
2FLE9BQVFnQyxvQkFBcUJuQyxxQkFHcEVvQyxLQUFLLHc1REFLUDZDLHlDQVFBLFNBQVNDLGdDQUFnQy9FLE9BQVFnQyxvQkFBcUJuQyxxQkFHcEVvQyxLQUFLLCs5S0FLUCtDLHVDQVFBLFNBQVNDLDhCQUE4QmpGLE9BQVFnQyxvQkFBcUJuQyxxQkFHbEVvQyxLQUFLLDI1cEJBS1BpRCx3Q0FRQSxTQUFTQyxpQ0FBaUNuRixPQUFRRCxRQUFTRixxQkFDekRvQyxLQUFLLDg4dUJBS1BtRCwyQ0FRQSxTQUFTQyxrQ0FBa0NyRixPQUFRRCxRQUFTRixxQkFDMURvQyxLQUFLLGc0d1dBS1BxRCwyQ0FRQSxTQUFTQyxtQ0FBbUN2RixPQUFRRCxTQUNsRGtDLEtBQUsifQ==

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.