/******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = "/"; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 0); /******/ }) /************************************************************************/ /******/ ({ /***/ "./node_modules/@fancyapps/fancybox/dist/jquery.fancybox.js": /*!******************************************************************!*\ !*** ./node_modules/@fancyapps/fancybox/dist/jquery.fancybox.js ***! \******************************************************************/ /*! no static exports found */ /***/ (function(module, exports) { eval("// ==================================================\n// fancyBox v3.5.7\n//\n// Licensed GPLv3 for open source use\n// or fancyBox Commercial License for commercial use\n//\n// http://fancyapps.com/fancybox/\n// Copyright 2019 fancyApps\n//\n// ==================================================\n(function (window, document, $, undefined) {\r\n \"use strict\";\r\n\r\n window.console = window.console || {\r\n info: function (stuff) {}\r\n };\r\n\r\n // If there's no jQuery, fancyBox can't work\r\n // =========================================\r\n\r\n if (!$) {\r\n return;\r\n }\r\n\r\n // Check if fancyBox is already initialized\r\n // ========================================\r\n\r\n if ($.fn.fancybox) {\r\n console.info(\"fancyBox already initialized\");\r\n\r\n return;\r\n }\r\n\r\n // Private default settings\r\n // ========================\r\n\r\n var defaults = {\r\n // Close existing modals\r\n // Set this to false if you do not need to stack multiple instances\r\n closeExisting: false,\r\n\r\n // Enable infinite gallery navigation\r\n loop: false,\r\n\r\n // Horizontal space between slides\r\n gutter: 50,\r\n\r\n // Enable keyboard navigation\r\n keyboard: true,\r\n\r\n // Should allow caption to overlap the content\r\n preventCaptionOverlap: true,\r\n\r\n // Should display navigation arrows at the screen edges\r\n arrows: true,\r\n\r\n // Should display counter at the top left corner\r\n infobar: true,\r\n\r\n // Should display close button (using `btnTpl.smallBtn` template) over the content\r\n // Can be true, false, \"auto\"\r\n // If \"auto\" - will be automatically enabled for \"html\", \"inline\" or \"ajax\" items\r\n smallBtn: \"auto\",\r\n\r\n // Should display toolbar (buttons at the top)\r\n // Can be true, false, \"auto\"\r\n // If \"auto\" - will be automatically hidden if \"smallBtn\" is enabled\r\n toolbar: \"auto\",\r\n\r\n // What buttons should appear in the top right corner.\r\n // Buttons will be created using templates from `btnTpl` option\r\n // and they will be placed into toolbar (class=\"fancybox-toolbar\"` element)\r\n buttons: [\r\n \"zoom\",\r\n //\"share\",\r\n \"slideShow\",\r\n //\"fullScreen\",\r\n //\"download\",\r\n \"thumbs\",\r\n \"close\"\r\n ],\r\n\r\n // Detect \"idle\" time in seconds\r\n idleTime: 3,\r\n\r\n // Disable right-click and use simple image protection for images\r\n protect: false,\r\n\r\n // Shortcut to make content \"modal\" - disable keyboard navigtion, hide buttons, etc\r\n modal: false,\r\n\r\n image: {\r\n // Wait for images to load before displaying\r\n // true - wait for image to load and then display;\r\n // false - display thumbnail and load the full-sized image over top,\r\n // requires predefined image dimensions (`data-width` and `data-height` attributes)\r\n preload: false\r\n },\r\n\r\n ajax: {\r\n // Object containing settings for ajax request\r\n settings: {\r\n // This helps to indicate that request comes from the modal\r\n // Feel free to change naming\r\n data: {\r\n fancybox: true\r\n }\r\n }\r\n },\r\n\r\n iframe: {\r\n // Iframe template\r\n tpl: '',\r\n\r\n // Preload iframe before displaying it\r\n // This allows to calculate iframe content width and height\r\n // (note: Due to \"Same Origin Policy\", you can't get cross domain data).\r\n preload: true,\r\n\r\n // Custom CSS styling for iframe wrapping element\r\n // You can use this to set custom iframe dimensions\r\n css: {},\r\n\r\n // Iframe tag attributes\r\n attr: {\r\n scrolling: \"auto\"\r\n }\r\n },\r\n\r\n // For HTML5 video only\r\n video: {\r\n tpl: '\",\r\n format: \"\", // custom video format\r\n autoStart: true\r\n },\r\n\r\n // Default content type if cannot be detected automatically\r\n defaultType: \"image\",\r\n\r\n // Open/close animation type\r\n // Possible values:\r\n // false - disable\r\n // \"zoom\" - zoom images from/to thumbnail\r\n // \"fade\"\r\n // \"zoom-in-out\"\r\n //\r\n animationEffect: \"zoom\",\r\n\r\n // Duration in ms for open/close animation\r\n animationDuration: 366,\r\n\r\n // Should image change opacity while zooming\r\n // If opacity is \"auto\", then opacity will be changed if image and thumbnail have different aspect ratios\r\n zoomOpacity: \"auto\",\r\n\r\n // Transition effect between slides\r\n //\r\n // Possible values:\r\n // false - disable\r\n // \"fade'\r\n // \"slide'\r\n // \"circular'\r\n // \"tube'\r\n // \"zoom-in-out'\r\n // \"rotate'\r\n //\r\n transitionEffect: \"fade\",\r\n\r\n // Duration in ms for transition animation\r\n transitionDuration: 366,\r\n\r\n // Custom CSS class for slide element\r\n slideClass: \"\",\r\n\r\n // Custom CSS class for layout\r\n baseClass: \"\",\r\n\r\n // Base template for layout\r\n baseTpl: '
' +\r\n '
' +\r\n '
' +\r\n '
 / 
' +\r\n '
{{buttons}}
' +\r\n '
{{arrows}}
' +\r\n '
' +\r\n '
' +\r\n \"
\" +\r\n \"
\",\r\n\r\n // Loading indicator template\r\n spinnerTpl: '
',\r\n\r\n // Error message template\r\n errorTpl: '

{{ERROR}}

',\r\n\r\n btnTpl: {\r\n download: '' +\r\n '' +\r\n \"\",\r\n\r\n zoom: '\",\r\n\r\n close: '\",\r\n\r\n // Arrows\r\n arrowLeft: '\",\r\n\r\n arrowRight: '\",\r\n\r\n // This small close button will be appended to your html/inline/ajax content by default,\r\n // if \"smallBtn\" option is not set to false\r\n smallBtn: '\"\r\n },\r\n\r\n // Container is injected into this element\r\n parentEl: \"body\",\r\n\r\n // Hide browser vertical scrollbars; use at your own risk\r\n hideScrollbar: true,\r\n\r\n // Focus handling\r\n // ==============\r\n\r\n // Try to focus on the first focusable element after opening\r\n autoFocus: true,\r\n\r\n // Put focus back to active element after closing\r\n backFocus: true,\r\n\r\n // Do not let user to focus on element outside modal content\r\n trapFocus: true,\r\n\r\n // Module specific options\r\n // =======================\r\n\r\n fullScreen: {\r\n autoStart: false\r\n },\r\n\r\n // Set `touch: false` to disable panning/swiping\r\n touch: {\r\n vertical: true, // Allow to drag content vertically\r\n momentum: true // Continue movement after releasing mouse/touch when panning\r\n },\r\n\r\n // Hash value when initializing manually,\r\n // set `false` to disable hash change\r\n hash: null,\r\n\r\n // Customize or add new media types\r\n // Example:\r\n /*\r\n media : {\r\n youtube : {\r\n params : {\r\n autoplay : 0\r\n }\r\n }\r\n }\r\n */\r\n media: {},\r\n\r\n slideShow: {\r\n autoStart: false,\r\n speed: 3000\r\n },\r\n\r\n thumbs: {\r\n autoStart: false, // Display thumbnails on opening\r\n hideOnClose: true, // Hide thumbnail grid when closing animation starts\r\n parentEl: \".fancybox-container\", // Container is injected into this element\r\n axis: \"y\" // Vertical (y) or horizontal (x) scrolling\r\n },\r\n\r\n // Use mousewheel to navigate gallery\r\n // If 'auto' - enabled for images only\r\n wheel: \"auto\",\r\n\r\n // Callbacks\r\n //==========\r\n\r\n // See Documentation/API/Events for more information\r\n // Example:\r\n /*\r\n afterShow: function( instance, current ) {\r\n console.info( 'Clicked element:' );\r\n console.info( current.opts.$orig );\r\n }\r\n */\r\n\r\n onInit: $.noop, // When instance has been initialized\r\n\r\n beforeLoad: $.noop, // Before the content of a slide is being loaded\r\n afterLoad: $.noop, // When the content of a slide is done loading\r\n\r\n beforeShow: $.noop, // Before open animation starts\r\n afterShow: $.noop, // When content is done loading and animating\r\n\r\n beforeClose: $.noop, // Before the instance attempts to close. Return false to cancel the close.\r\n afterClose: $.noop, // After instance has been closed\r\n\r\n onActivate: $.noop, // When instance is brought to front\r\n onDeactivate: $.noop, // When other instance has been activated\r\n\r\n // Interaction\r\n // ===========\r\n\r\n // Use options below to customize taken action when user clicks or double clicks on the fancyBox area,\r\n // each option can be string or method that returns value.\r\n //\r\n // Possible values:\r\n // \"close\" - close instance\r\n // \"next\" - move to next gallery item\r\n // \"nextOrClose\" - move to next gallery item or close if gallery has only one item\r\n // \"toggleControls\" - show/hide controls\r\n // \"zoom\" - zoom image (if loaded)\r\n // false - do nothing\r\n\r\n // Clicked on the content\r\n clickContent: function (current, event) {\r\n return current.type === \"image\" ? \"zoom\" : false;\r\n },\r\n\r\n // Clicked on the slide\r\n clickSlide: \"close\",\r\n\r\n // Clicked on the background (backdrop) element;\r\n // if you have not changed the layout, then most likely you need to use `clickSlide` option\r\n clickOutside: \"close\",\r\n\r\n // Same as previous two, but for double click\r\n dblclickContent: false,\r\n dblclickSlide: false,\r\n dblclickOutside: false,\r\n\r\n // Custom options when mobile device is detected\r\n // =============================================\r\n\r\n mobile: {\r\n preventCaptionOverlap: false,\r\n idleTime: false,\r\n clickContent: function (current, event) {\r\n return current.type === \"image\" ? \"toggleControls\" : false;\r\n },\r\n clickSlide: function (current, event) {\r\n return current.type === \"image\" ? \"toggleControls\" : \"close\";\r\n },\r\n dblclickContent: function (current, event) {\r\n return current.type === \"image\" ? \"zoom\" : false;\r\n },\r\n dblclickSlide: function (current, event) {\r\n return current.type === \"image\" ? \"zoom\" : false;\r\n }\r\n },\r\n\r\n // Internationalization\r\n // ====================\r\n\r\n lang: \"en\",\r\n i18n: {\r\n en: {\r\n CLOSE: \"Close\",\r\n NEXT: \"Next\",\r\n PREV: \"Previous\",\r\n ERROR: \"The requested content cannot be loaded.
Please try again later.\",\r\n PLAY_START: \"Start slideshow\",\r\n PLAY_STOP: \"Pause slideshow\",\r\n FULL_SCREEN: \"Full screen\",\r\n THUMBS: \"Thumbnails\",\r\n DOWNLOAD: \"Download\",\r\n SHARE: \"Share\",\r\n ZOOM: \"Zoom\"\r\n },\r\n de: {\r\n CLOSE: \"Schließen\",\r\n NEXT: \"Weiter\",\r\n PREV: \"Zurück\",\r\n ERROR: \"Die angeforderten Daten konnten nicht geladen werden.
Bitte versuchen Sie es später nochmal.\",\r\n PLAY_START: \"Diaschau starten\",\r\n PLAY_STOP: \"Diaschau beenden\",\r\n FULL_SCREEN: \"Vollbild\",\r\n THUMBS: \"Vorschaubilder\",\r\n DOWNLOAD: \"Herunterladen\",\r\n SHARE: \"Teilen\",\r\n ZOOM: \"Vergrößern\"\r\n }\r\n }\r\n };\r\n\r\n // Few useful variables and methods\r\n // ================================\r\n\r\n var $W = $(window);\r\n var $D = $(document);\r\n\r\n var called = 0;\r\n\r\n // Check if an object is a jQuery object and not a native JavaScript object\r\n // ========================================================================\r\n var isQuery = function (obj) {\r\n return obj && obj.hasOwnProperty && obj instanceof $;\r\n };\r\n\r\n // Handle multiple browsers for \"requestAnimationFrame\" and \"cancelAnimationFrame\"\r\n // ===============================================================================\r\n var requestAFrame = (function () {\r\n return (\r\n window.requestAnimationFrame ||\r\n window.webkitRequestAnimationFrame ||\r\n window.mozRequestAnimationFrame ||\r\n window.oRequestAnimationFrame ||\r\n // if all else fails, use setTimeout\r\n function (callback) {\r\n return window.setTimeout(callback, 1000 / 60);\r\n }\r\n );\r\n })();\r\n\r\n var cancelAFrame = (function () {\r\n return (\r\n window.cancelAnimationFrame ||\r\n window.webkitCancelAnimationFrame ||\r\n window.mozCancelAnimationFrame ||\r\n window.oCancelAnimationFrame ||\r\n function (id) {\r\n window.clearTimeout(id);\r\n }\r\n );\r\n })();\r\n\r\n // Detect the supported transition-end event property name\r\n // =======================================================\r\n var transitionEnd = (function () {\r\n var el = document.createElement(\"fakeelement\"),\r\n t;\r\n\r\n var transitions = {\r\n transition: \"transitionend\",\r\n OTransition: \"oTransitionEnd\",\r\n MozTransition: \"transitionend\",\r\n WebkitTransition: \"webkitTransitionEnd\"\r\n };\r\n\r\n for (t in transitions) {\r\n if (el.style[t] !== undefined) {\r\n return transitions[t];\r\n }\r\n }\r\n\r\n return \"transitionend\";\r\n })();\r\n\r\n // Force redraw on an element.\r\n // This helps in cases where the browser doesn't redraw an updated element properly\r\n // ================================================================================\r\n var forceRedraw = function ($el) {\r\n return $el && $el.length && $el[0].offsetHeight;\r\n };\r\n\r\n // Exclude array (`buttons`) options from deep merging\r\n // ===================================================\r\n var mergeOpts = function (opts1, opts2) {\r\n var rez = $.extend(true, {}, opts1, opts2);\r\n\r\n $.each(opts2, function (key, value) {\r\n if ($.isArray(value)) {\r\n rez[key] = value;\r\n }\r\n });\r\n\r\n return rez;\r\n };\r\n\r\n // How much of an element is visible in viewport\r\n // =============================================\r\n\r\n var inViewport = function (elem) {\r\n var elemCenter, rez;\r\n\r\n if (!elem || elem.ownerDocument !== document) {\r\n return false;\r\n }\r\n\r\n $(\".fancybox-container\").css(\"pointer-events\", \"none\");\r\n\r\n elemCenter = {\r\n x: elem.getBoundingClientRect().left + elem.offsetWidth / 2,\r\n y: elem.getBoundingClientRect().top + elem.offsetHeight / 2\r\n };\r\n\r\n rez = document.elementFromPoint(elemCenter.x, elemCenter.y) === elem;\r\n\r\n $(\".fancybox-container\").css(\"pointer-events\", \"\");\r\n\r\n return rez;\r\n };\r\n\r\n // Class definition\r\n // ================\r\n\r\n var FancyBox = function (content, opts, index) {\r\n var self = this;\r\n\r\n self.opts = mergeOpts({\r\n index: index\r\n }, $.fancybox.defaults);\r\n\r\n if ($.isPlainObject(opts)) {\r\n self.opts = mergeOpts(self.opts, opts);\r\n }\r\n\r\n if ($.fancybox.isMobile) {\r\n self.opts = mergeOpts(self.opts, self.opts.mobile);\r\n }\r\n\r\n self.id = self.opts.id || ++called;\r\n\r\n self.currIndex = parseInt(self.opts.index, 10) || 0;\r\n self.prevIndex = null;\r\n\r\n self.prevPos = null;\r\n self.currPos = 0;\r\n\r\n self.firstRun = true;\r\n\r\n // All group items\r\n self.group = [];\r\n\r\n // Existing slides (for current, next and previous gallery items)\r\n self.slides = {};\r\n\r\n // Create group elements\r\n self.addContent(content);\r\n\r\n if (!self.group.length) {\r\n return;\r\n }\r\n\r\n self.init();\r\n };\r\n\r\n $.extend(FancyBox.prototype, {\r\n // Create DOM structure\r\n // ====================\r\n\r\n init: function () {\r\n var self = this,\r\n firstItem = self.group[self.currIndex],\r\n firstItemOpts = firstItem.opts,\r\n $container,\r\n buttonStr;\r\n\r\n if (firstItemOpts.closeExisting) {\r\n $.fancybox.close(true);\r\n }\r\n\r\n // Hide scrollbars\r\n // ===============\r\n\r\n $(\"body\").addClass(\"fancybox-active\");\r\n\r\n if (\r\n !$.fancybox.getInstance() &&\r\n firstItemOpts.hideScrollbar !== false &&\r\n !$.fancybox.isMobile &&\r\n document.body.scrollHeight > window.innerHeight\r\n ) {\r\n $(\"head\").append(\r\n '\"\r\n );\r\n\r\n $(\"body\").addClass(\"compensate-for-scrollbar\");\r\n }\r\n\r\n // Build html markup and set references\r\n // ====================================\r\n\r\n // Build html code for buttons and insert into main template\r\n buttonStr = \"\";\r\n\r\n $.each(firstItemOpts.buttons, function (index, value) {\r\n buttonStr += firstItemOpts.btnTpl[value] || \"\";\r\n });\r\n\r\n // Create markup from base template, it will be initially hidden to\r\n // avoid unnecessary work like painting while initializing is not complete\r\n $container = $(\r\n self.translate(\r\n self,\r\n firstItemOpts.baseTpl\r\n .replace(\"{{buttons}}\", buttonStr)\r\n .replace(\"{{arrows}}\", firstItemOpts.btnTpl.arrowLeft + firstItemOpts.btnTpl.arrowRight)\r\n )\r\n )\r\n .attr(\"id\", \"fancybox-container-\" + self.id)\r\n .addClass(firstItemOpts.baseClass)\r\n .data(\"FancyBox\", self)\r\n .appendTo(firstItemOpts.parentEl);\r\n\r\n // Create object holding references to jQuery wrapped nodes\r\n self.$refs = {\r\n container: $container\r\n };\r\n\r\n [\"bg\", \"inner\", \"infobar\", \"toolbar\", \"stage\", \"caption\", \"navigation\"].forEach(function (item) {\r\n self.$refs[item] = $container.find(\".fancybox-\" + item);\r\n });\r\n\r\n self.trigger(\"onInit\");\r\n\r\n // Enable events, deactive previous instances\r\n self.activate();\r\n\r\n // Build slides, load and reveal content\r\n self.jumpTo(self.currIndex);\r\n },\r\n\r\n // Simple i18n support - replaces object keys found in template\r\n // with corresponding values\r\n // ============================================================\r\n\r\n translate: function (obj, str) {\r\n var arr = obj.opts.i18n[obj.opts.lang] || obj.opts.i18n.en;\r\n\r\n return str.replace(/\\{\\{(\\w+)\\}\\}/g, function (match, n) {\r\n return arr[n] === undefined ? match : arr[n];\r\n });\r\n },\r\n\r\n // Populate current group with fresh content\r\n // Check if each object has valid type and content\r\n // ===============================================\r\n\r\n addContent: function (content) {\r\n var self = this,\r\n items = $.makeArray(content),\r\n thumbs;\r\n\r\n $.each(items, function (i, item) {\r\n var obj = {},\r\n opts = {},\r\n $item,\r\n type,\r\n found,\r\n src,\r\n srcParts;\r\n\r\n // Step 1 - Make sure we have an object\r\n // ====================================\r\n\r\n if ($.isPlainObject(item)) {\r\n // We probably have manual usage here, something like\r\n // $.fancybox.open( [ { src : \"image.jpg\", type : \"image\" } ] )\r\n\r\n obj = item;\r\n opts = item.opts || item;\r\n } else if ($.type(item) === \"object\" && $(item).length) {\r\n // Here we probably have jQuery collection returned by some selector\r\n $item = $(item);\r\n\r\n // Support attributes like `data-options='{\"touch\" : false}'` and `data-touch='false'`\r\n opts = $item.data() || {};\r\n opts = $.extend(true, {}, opts, opts.options);\r\n\r\n // Here we store clicked element\r\n opts.$orig = $item;\r\n\r\n obj.src = self.opts.src || opts.src || $item.attr(\"href\");\r\n\r\n // Assume that simple syntax is used, for example:\r\n // `$.fancybox.open( $(\"#test\"), {} );`\r\n if (!obj.type && !obj.src) {\r\n obj.type = \"inline\";\r\n obj.src = item;\r\n }\r\n } else {\r\n // Assume we have a simple html code, for example:\r\n // $.fancybox.open( '

Hi!

' );\r\n obj = {\r\n type: \"html\",\r\n src: item + \"\"\r\n };\r\n }\r\n\r\n // Each gallery object has full collection of options\r\n obj.opts = $.extend(true, {}, self.opts, opts);\r\n\r\n // Do not merge buttons array\r\n if ($.isArray(opts.buttons)) {\r\n obj.opts.buttons = opts.buttons;\r\n }\r\n\r\n if ($.fancybox.isMobile && obj.opts.mobile) {\r\n obj.opts = mergeOpts(obj.opts, obj.opts.mobile);\r\n }\r\n\r\n // Step 2 - Make sure we have content type, if not - try to guess\r\n // ==============================================================\r\n\r\n type = obj.type || obj.opts.type;\r\n src = obj.src || \"\";\r\n\r\n if (!type && src) {\r\n if ((found = src.match(/\\.(mp4|mov|ogv|webm)((\\?|#).*)?$/i))) {\r\n type = \"video\";\r\n\r\n if (!obj.opts.video.format) {\r\n obj.opts.video.format = \"video/\" + (found[1] === \"ogv\" ? \"ogg\" : found[1]);\r\n }\r\n } else if (src.match(/(^data:image\\/[a-z0-9+\\/=]*,)|(\\.(jp(e|g|eg)|gif|png|bmp|webp|svg|ico)((\\?|#).*)?$)/i)) {\r\n type = \"image\";\r\n } else if (src.match(/\\.(pdf)((\\?|#).*)?$/i)) {\r\n type = \"iframe\";\r\n obj = $.extend(true, obj, {\r\n contentType: \"pdf\",\r\n opts: {\r\n iframe: {\r\n preload: false\r\n }\r\n }\r\n });\r\n } else if (src.charAt(0) === \"#\") {\r\n type = \"inline\";\r\n }\r\n }\r\n\r\n if (type) {\r\n obj.type = type;\r\n } else {\r\n self.trigger(\"objectNeedsType\", obj);\r\n }\r\n\r\n if (!obj.contentType) {\r\n obj.contentType = $.inArray(obj.type, [\"html\", \"inline\", \"ajax\"]) > -1 ? \"html\" : obj.type;\r\n }\r\n\r\n // Step 3 - Some adjustments\r\n // =========================\r\n\r\n obj.index = self.group.length;\r\n\r\n if (obj.opts.smallBtn == \"auto\") {\r\n obj.opts.smallBtn = $.inArray(obj.type, [\"html\", \"inline\", \"ajax\"]) > -1;\r\n }\r\n\r\n if (obj.opts.toolbar === \"auto\") {\r\n obj.opts.toolbar = !obj.opts.smallBtn;\r\n }\r\n\r\n // Find thumbnail image, check if exists and if is in the viewport\r\n obj.$thumb = obj.opts.$thumb || null;\r\n\r\n if (obj.opts.$trigger && obj.index === self.opts.index) {\r\n obj.$thumb = obj.opts.$trigger.find(\"img:first\");\r\n\r\n if (obj.$thumb.length) {\r\n obj.opts.$orig = obj.opts.$trigger;\r\n }\r\n }\r\n\r\n if (!(obj.$thumb && obj.$thumb.length) && obj.opts.$orig) {\r\n obj.$thumb = obj.opts.$orig.find(\"img:first\");\r\n }\r\n\r\n if (obj.$thumb && !obj.$thumb.length) {\r\n obj.$thumb = null;\r\n }\r\n\r\n obj.thumb = obj.opts.thumb || (obj.$thumb ? obj.$thumb[0].src : null);\r\n\r\n // \"caption\" is a \"special\" option, it can be used to customize caption per gallery item\r\n if ($.type(obj.opts.caption) === \"function\") {\r\n obj.opts.caption = obj.opts.caption.apply(item, [self, obj]);\r\n }\r\n\r\n if ($.type(self.opts.caption) === \"function\") {\r\n obj.opts.caption = self.opts.caption.apply(item, [self, obj]);\r\n }\r\n\r\n // Make sure we have caption as a string or jQuery object\r\n if (!(obj.opts.caption instanceof $)) {\r\n obj.opts.caption = obj.opts.caption === undefined ? \"\" : obj.opts.caption + \"\";\r\n }\r\n\r\n // Check if url contains \"filter\" used to filter the content\r\n // Example: \"ajax.html #something\"\r\n if (obj.type === \"ajax\") {\r\n srcParts = src.split(/\\s+/, 2);\r\n\r\n if (srcParts.length > 1) {\r\n obj.src = srcParts.shift();\r\n\r\n obj.opts.filter = srcParts.shift();\r\n }\r\n }\r\n\r\n // Hide all buttons and disable interactivity for modal items\r\n if (obj.opts.modal) {\r\n obj.opts = $.extend(true, obj.opts, {\r\n trapFocus: true,\r\n // Remove buttons\r\n infobar: 0,\r\n toolbar: 0,\r\n\r\n smallBtn: 0,\r\n\r\n // Disable keyboard navigation\r\n keyboard: 0,\r\n\r\n // Disable some modules\r\n slideShow: 0,\r\n fullScreen: 0,\r\n thumbs: 0,\r\n touch: 0,\r\n\r\n // Disable click event handlers\r\n clickContent: false,\r\n clickSlide: false,\r\n clickOutside: false,\r\n dblclickContent: false,\r\n dblclickSlide: false,\r\n dblclickOutside: false\r\n });\r\n }\r\n\r\n // Step 4 - Add processed object to group\r\n // ======================================\r\n\r\n self.group.push(obj);\r\n });\r\n\r\n // Update controls if gallery is already opened\r\n if (Object.keys(self.slides).length) {\r\n self.updateControls();\r\n\r\n // Update thumbnails, if needed\r\n thumbs = self.Thumbs;\r\n\r\n if (thumbs && thumbs.isActive) {\r\n thumbs.create();\r\n\r\n thumbs.focus();\r\n }\r\n }\r\n },\r\n\r\n // Attach an event handler functions for:\r\n // - navigation buttons\r\n // - browser scrolling, resizing;\r\n // - focusing\r\n // - keyboard\r\n // - detecting inactivity\r\n // ======================================\r\n\r\n addEvents: function () {\r\n var self = this;\r\n\r\n self.removeEvents();\r\n\r\n // Make navigation elements clickable\r\n // ==================================\r\n\r\n self.$refs.container\r\n .on(\"click.fb-close\", \"[data-fancybox-close]\", function (e) {\r\n e.stopPropagation();\r\n e.preventDefault();\r\n\r\n self.close(e);\r\n })\r\n .on(\"touchstart.fb-prev click.fb-prev\", \"[data-fancybox-prev]\", function (e) {\r\n e.stopPropagation();\r\n e.preventDefault();\r\n\r\n self.previous();\r\n })\r\n .on(\"touchstart.fb-next click.fb-next\", \"[data-fancybox-next]\", function (e) {\r\n e.stopPropagation();\r\n e.preventDefault();\r\n\r\n self.next();\r\n })\r\n .on(\"click.fb\", \"[data-fancybox-zoom]\", function (e) {\r\n // Click handler for zoom button\r\n self[self.isScaledDown() ? \"scaleToActual\" : \"scaleToFit\"]();\r\n });\r\n\r\n // Handle page scrolling and browser resizing\r\n // ==========================================\r\n\r\n $W.on(\"orientationchange.fb resize.fb\", function (e) {\r\n if (e && e.originalEvent && e.originalEvent.type === \"resize\") {\r\n if (self.requestId) {\r\n cancelAFrame(self.requestId);\r\n }\r\n\r\n self.requestId = requestAFrame(function () {\r\n self.update(e);\r\n });\r\n } else {\r\n if (self.current && self.current.type === \"iframe\") {\r\n self.$refs.stage.hide();\r\n }\r\n\r\n setTimeout(\r\n function () {\r\n self.$refs.stage.show();\r\n\r\n self.update(e);\r\n },\r\n $.fancybox.isMobile ? 600 : 250\r\n );\r\n }\r\n });\r\n\r\n $D.on(\"keydown.fb\", function (e) {\r\n var instance = $.fancybox ? $.fancybox.getInstance() : null,\r\n current = instance.current,\r\n keycode = e.keyCode || e.which;\r\n\r\n // Trap keyboard focus inside of the modal\r\n // =======================================\r\n\r\n if (keycode == 9) {\r\n if (current.opts.trapFocus) {\r\n self.focus(e);\r\n }\r\n\r\n return;\r\n }\r\n\r\n // Enable keyboard navigation\r\n // ==========================\r\n\r\n if (!current.opts.keyboard || e.ctrlKey || e.altKey || e.shiftKey || $(e.target).is(\"input,textarea,video,audio,select\")) {\r\n return;\r\n }\r\n\r\n // Backspace and Esc keys\r\n if (keycode === 8 || keycode === 27) {\r\n e.preventDefault();\r\n\r\n self.close(e);\r\n\r\n return;\r\n }\r\n\r\n // Left arrow and Up arrow\r\n if (keycode === 37 || keycode === 38) {\r\n e.preventDefault();\r\n\r\n self.previous();\r\n\r\n return;\r\n }\r\n\r\n // Righ arrow and Down arrow\r\n if (keycode === 39 || keycode === 40) {\r\n e.preventDefault();\r\n\r\n self.next();\r\n\r\n return;\r\n }\r\n\r\n self.trigger(\"afterKeydown\", e, keycode);\r\n });\r\n\r\n // Hide controls after some inactivity period\r\n if (self.group[self.currIndex].opts.idleTime) {\r\n self.idleSecondsCounter = 0;\r\n\r\n $D.on(\r\n \"mousemove.fb-idle mouseleave.fb-idle mousedown.fb-idle touchstart.fb-idle touchmove.fb-idle scroll.fb-idle keydown.fb-idle\",\r\n function (e) {\r\n self.idleSecondsCounter = 0;\r\n\r\n if (self.isIdle) {\r\n self.showControls();\r\n }\r\n\r\n self.isIdle = false;\r\n }\r\n );\r\n\r\n self.idleInterval = window.setInterval(function () {\r\n self.idleSecondsCounter++;\r\n\r\n if (self.idleSecondsCounter >= self.group[self.currIndex].opts.idleTime && !self.isDragging) {\r\n self.isIdle = true;\r\n self.idleSecondsCounter = 0;\r\n\r\n self.hideControls();\r\n }\r\n }, 1000);\r\n }\r\n },\r\n\r\n // Remove events added by the core\r\n // ===============================\r\n\r\n removeEvents: function () {\r\n var self = this;\r\n\r\n $W.off(\"orientationchange.fb resize.fb\");\r\n $D.off(\"keydown.fb .fb-idle\");\r\n\r\n this.$refs.container.off(\".fb-close .fb-prev .fb-next\");\r\n\r\n if (self.idleInterval) {\r\n window.clearInterval(self.idleInterval);\r\n\r\n self.idleInterval = null;\r\n }\r\n },\r\n\r\n // Change to previous gallery item\r\n // ===============================\r\n\r\n previous: function (duration) {\r\n return this.jumpTo(this.currPos - 1, duration);\r\n },\r\n\r\n // Change to next gallery item\r\n // ===========================\r\n\r\n next: function (duration) {\r\n return this.jumpTo(this.currPos + 1, duration);\r\n },\r\n\r\n // Switch to selected gallery item\r\n // ===============================\r\n\r\n jumpTo: function (pos, duration) {\r\n var self = this,\r\n groupLen = self.group.length,\r\n firstRun,\r\n isMoved,\r\n loop,\r\n current,\r\n previous,\r\n slidePos,\r\n stagePos,\r\n prop,\r\n diff;\r\n\r\n if (self.isDragging || self.isClosing || (self.isAnimating && self.firstRun)) {\r\n return;\r\n }\r\n\r\n // Should loop?\r\n pos = parseInt(pos, 10);\r\n loop = self.current ? self.current.opts.loop : self.opts.loop;\r\n\r\n if (!loop && (pos < 0 || pos >= groupLen)) {\r\n return false;\r\n }\r\n\r\n // Check if opening for the first time; this helps to speed things up\r\n firstRun = self.firstRun = !Object.keys(self.slides).length;\r\n\r\n // Create slides\r\n previous = self.current;\r\n\r\n self.prevIndex = self.currIndex;\r\n self.prevPos = self.currPos;\r\n\r\n current = self.createSlide(pos);\r\n\r\n if (groupLen > 1) {\r\n if (loop || current.index < groupLen - 1) {\r\n self.createSlide(pos + 1);\r\n }\r\n\r\n if (loop || current.index > 0) {\r\n self.createSlide(pos - 1);\r\n }\r\n }\r\n\r\n self.current = current;\r\n self.currIndex = current.index;\r\n self.currPos = current.pos;\r\n\r\n self.trigger(\"beforeShow\", firstRun);\r\n\r\n self.updateControls();\r\n\r\n // Validate duration length\r\n current.forcedDuration = undefined;\r\n\r\n if ($.isNumeric(duration)) {\r\n current.forcedDuration = duration;\r\n } else {\r\n duration = current.opts[firstRun ? \"animationDuration\" : \"transitionDuration\"];\r\n }\r\n\r\n duration = parseInt(duration, 10);\r\n\r\n // Check if user has swiped the slides or if still animating\r\n isMoved = self.isMoved(current);\r\n\r\n // Make sure current slide is visible\r\n current.$slide.addClass(\"fancybox-slide--current\");\r\n\r\n // Fresh start - reveal container, current slide and start loading content\r\n if (firstRun) {\r\n if (current.opts.animationEffect && duration) {\r\n self.$refs.container.css(\"transition-duration\", duration + \"ms\");\r\n }\r\n\r\n self.$refs.container.addClass(\"fancybox-is-open\").trigger(\"focus\");\r\n\r\n // Attempt to load content into slide\r\n // This will later call `afterLoad` -> `revealContent`\r\n self.loadSlide(current);\r\n\r\n self.preload(\"image\");\r\n\r\n return;\r\n }\r\n\r\n // Get actual slide/stage positions (before cleaning up)\r\n slidePos = $.fancybox.getTranslate(previous.$slide);\r\n stagePos = $.fancybox.getTranslate(self.$refs.stage);\r\n\r\n // Clean up all slides\r\n $.each(self.slides, function (index, slide) {\r\n $.fancybox.stop(slide.$slide, true);\r\n });\r\n\r\n if (previous.pos !== current.pos) {\r\n previous.isComplete = false;\r\n }\r\n\r\n previous.$slide.removeClass(\"fancybox-slide--complete fancybox-slide--current\");\r\n\r\n // If slides are out of place, then animate them to correct position\r\n if (isMoved) {\r\n // Calculate horizontal swipe distance\r\n diff = slidePos.left - (previous.pos * slidePos.width + previous.pos * previous.opts.gutter);\r\n\r\n $.each(self.slides, function (index, slide) {\r\n slide.$slide.removeClass(\"fancybox-animated\").removeClass(function (index, className) {\r\n return (className.match(/(^|\\s)fancybox-fx-\\S+/g) || []).join(\" \");\r\n });\r\n\r\n // Make sure that each slide is in equal distance\r\n // This is mostly needed for freshly added slides, because they are not yet positioned\r\n var leftPos = slide.pos * slidePos.width + slide.pos * slide.opts.gutter;\r\n\r\n $.fancybox.setTranslate(slide.$slide, {\r\n top: 0,\r\n left: leftPos - stagePos.left + diff\r\n });\r\n\r\n if (slide.pos !== current.pos) {\r\n slide.$slide.addClass(\"fancybox-slide--\" + (slide.pos > current.pos ? \"next\" : \"previous\"));\r\n }\r\n\r\n // Redraw to make sure that transition will start\r\n forceRedraw(slide.$slide);\r\n\r\n // Animate the slide\r\n $.fancybox.animate(\r\n slide.$slide, {\r\n top: 0,\r\n left: (slide.pos - current.pos) * slidePos.width + (slide.pos - current.pos) * slide.opts.gutter\r\n },\r\n duration,\r\n function () {\r\n slide.$slide\r\n .css({\r\n transform: \"\",\r\n opacity: \"\"\r\n })\r\n .removeClass(\"fancybox-slide--next fancybox-slide--previous\");\r\n\r\n if (slide.pos === self.currPos) {\r\n self.complete();\r\n }\r\n }\r\n );\r\n });\r\n } else if (duration && current.opts.transitionEffect) {\r\n // Set transition effect for previously active slide\r\n prop = \"fancybox-animated fancybox-fx-\" + current.opts.transitionEffect;\r\n\r\n previous.$slide.addClass(\"fancybox-slide--\" + (previous.pos > current.pos ? \"next\" : \"previous\"));\r\n\r\n $.fancybox.animate(\r\n previous.$slide,\r\n prop,\r\n duration,\r\n function () {\r\n previous.$slide.removeClass(prop).removeClass(\"fancybox-slide--next fancybox-slide--previous\");\r\n },\r\n false\r\n );\r\n }\r\n\r\n if (current.isLoaded) {\r\n self.revealContent(current);\r\n } else {\r\n self.loadSlide(current);\r\n }\r\n\r\n self.preload(\"image\");\r\n },\r\n\r\n // Create new \"slide\" element\r\n // These are gallery items that are actually added to DOM\r\n // =======================================================\r\n\r\n createSlide: function (pos) {\r\n var self = this,\r\n $slide,\r\n index;\r\n\r\n index = pos % self.group.length;\r\n index = index < 0 ? self.group.length + index : index;\r\n\r\n if (!self.slides[pos] && self.group[index]) {\r\n $slide = $('
').appendTo(self.$refs.stage);\r\n\r\n self.slides[pos] = $.extend(true, {}, self.group[index], {\r\n pos: pos,\r\n $slide: $slide,\r\n isLoaded: false\r\n });\r\n\r\n self.updateSlide(self.slides[pos]);\r\n }\r\n\r\n return self.slides[pos];\r\n },\r\n\r\n // Scale image to the actual size of the image;\r\n // x and y values should be relative to the slide\r\n // ==============================================\r\n\r\n scaleToActual: function (x, y, duration) {\r\n var self = this,\r\n current = self.current,\r\n $content = current.$content,\r\n canvasWidth = $.fancybox.getTranslate(current.$slide).width,\r\n canvasHeight = $.fancybox.getTranslate(current.$slide).height,\r\n newImgWidth = current.width,\r\n newImgHeight = current.height,\r\n imgPos,\r\n posX,\r\n posY,\r\n scaleX,\r\n scaleY;\r\n\r\n if (self.isAnimating || self.isMoved() || !$content || !(current.type == \"image\" && current.isLoaded && !current.hasError)) {\r\n return;\r\n }\r\n\r\n self.isAnimating = true;\r\n\r\n $.fancybox.stop($content);\r\n\r\n x = x === undefined ? canvasWidth * 0.5 : x;\r\n y = y === undefined ? canvasHeight * 0.5 : y;\r\n\r\n imgPos = $.fancybox.getTranslate($content);\r\n\r\n imgPos.top -= $.fancybox.getTranslate(current.$slide).top;\r\n imgPos.left -= $.fancybox.getTranslate(current.$slide).left;\r\n\r\n scaleX = newImgWidth / imgPos.width;\r\n scaleY = newImgHeight / imgPos.height;\r\n\r\n // Get center position for original image\r\n posX = canvasWidth * 0.5 - newImgWidth * 0.5;\r\n posY = canvasHeight * 0.5 - newImgHeight * 0.5;\r\n\r\n // Make sure image does not move away from edges\r\n if (newImgWidth > canvasWidth) {\r\n posX = imgPos.left * scaleX - (x * scaleX - x);\r\n\r\n if (posX > 0) {\r\n posX = 0;\r\n }\r\n\r\n if (posX < canvasWidth - newImgWidth) {\r\n posX = canvasWidth - newImgWidth;\r\n }\r\n }\r\n\r\n if (newImgHeight > canvasHeight) {\r\n posY = imgPos.top * scaleY - (y * scaleY - y);\r\n\r\n if (posY > 0) {\r\n posY = 0;\r\n }\r\n\r\n if (posY < canvasHeight - newImgHeight) {\r\n posY = canvasHeight - newImgHeight;\r\n }\r\n }\r\n\r\n self.updateCursor(newImgWidth, newImgHeight);\r\n\r\n $.fancybox.animate(\r\n $content, {\r\n top: posY,\r\n left: posX,\r\n scaleX: scaleX,\r\n scaleY: scaleY\r\n },\r\n duration || 366,\r\n function () {\r\n self.isAnimating = false;\r\n }\r\n );\r\n\r\n // Stop slideshow\r\n if (self.SlideShow && self.SlideShow.isActive) {\r\n self.SlideShow.stop();\r\n }\r\n },\r\n\r\n // Scale image to fit inside parent element\r\n // ========================================\r\n\r\n scaleToFit: function (duration) {\r\n var self = this,\r\n current = self.current,\r\n $content = current.$content,\r\n end;\r\n\r\n if (self.isAnimating || self.isMoved() || !$content || !(current.type == \"image\" && current.isLoaded && !current.hasError)) {\r\n return;\r\n }\r\n\r\n self.isAnimating = true;\r\n\r\n $.fancybox.stop($content);\r\n\r\n end = self.getFitPos(current);\r\n\r\n self.updateCursor(end.width, end.height);\r\n\r\n $.fancybox.animate(\r\n $content, {\r\n top: end.top,\r\n left: end.left,\r\n scaleX: end.width / $content.width(),\r\n scaleY: end.height / $content.height()\r\n },\r\n duration || 366,\r\n function () {\r\n self.isAnimating = false;\r\n }\r\n );\r\n },\r\n\r\n // Calculate image size to fit inside viewport\r\n // ===========================================\r\n\r\n getFitPos: function (slide) {\r\n var self = this,\r\n $content = slide.$content,\r\n $slide = slide.$slide,\r\n width = slide.width || slide.opts.width,\r\n height = slide.height || slide.opts.height,\r\n maxWidth,\r\n maxHeight,\r\n minRatio,\r\n aspectRatio,\r\n rez = {};\r\n\r\n if (!slide.isLoaded || !$content || !$content.length) {\r\n return false;\r\n }\r\n\r\n maxWidth = $.fancybox.getTranslate(self.$refs.stage).width;\r\n maxHeight = $.fancybox.getTranslate(self.$refs.stage).height;\r\n\r\n maxWidth -=\r\n parseFloat($slide.css(\"paddingLeft\")) +\r\n parseFloat($slide.css(\"paddingRight\")) +\r\n parseFloat($content.css(\"marginLeft\")) +\r\n parseFloat($content.css(\"marginRight\"));\r\n\r\n maxHeight -=\r\n parseFloat($slide.css(\"paddingTop\")) +\r\n parseFloat($slide.css(\"paddingBottom\")) +\r\n parseFloat($content.css(\"marginTop\")) +\r\n parseFloat($content.css(\"marginBottom\"));\r\n\r\n if (!width || !height) {\r\n width = maxWidth;\r\n height = maxHeight;\r\n }\r\n\r\n minRatio = Math.min(1, maxWidth / width, maxHeight / height);\r\n\r\n width = minRatio * width;\r\n height = minRatio * height;\r\n\r\n // Adjust width/height to precisely fit into container\r\n if (width > maxWidth - 0.5) {\r\n width = maxWidth;\r\n }\r\n\r\n if (height > maxHeight - 0.5) {\r\n height = maxHeight;\r\n }\r\n\r\n if (slide.type === \"image\") {\r\n rez.top = Math.floor((maxHeight - height) * 0.5) + parseFloat($slide.css(\"paddingTop\"));\r\n rez.left = Math.floor((maxWidth - width) * 0.5) + parseFloat($slide.css(\"paddingLeft\"));\r\n } else if (slide.contentType === \"video\") {\r\n // Force aspect ratio for the video\r\n // \"I say the whole world must learn of our peaceful ways… by force!\"\r\n aspectRatio = slide.opts.width && slide.opts.height ? width / height : slide.opts.ratio || 16 / 9;\r\n\r\n if (height > width / aspectRatio) {\r\n height = width / aspectRatio;\r\n } else if (width > height * aspectRatio) {\r\n width = height * aspectRatio;\r\n }\r\n }\r\n\r\n rez.width = width;\r\n rez.height = height;\r\n\r\n return rez;\r\n },\r\n\r\n // Update content size and position for all slides\r\n // ==============================================\r\n\r\n update: function (e) {\r\n var self = this;\r\n\r\n $.each(self.slides, function (key, slide) {\r\n self.updateSlide(slide, e);\r\n });\r\n },\r\n\r\n // Update slide content position and size\r\n // ======================================\r\n\r\n updateSlide: function (slide, e) {\r\n var self = this,\r\n $content = slide && slide.$content,\r\n width = slide.width || slide.opts.width,\r\n height = slide.height || slide.opts.height,\r\n $slide = slide.$slide;\r\n\r\n // First, prevent caption overlap, if needed\r\n self.adjustCaption(slide);\r\n\r\n // Then resize content to fit inside the slide\r\n if ($content && (width || height || slide.contentType === \"video\") && !slide.hasError) {\r\n $.fancybox.stop($content);\r\n\r\n $.fancybox.setTranslate($content, self.getFitPos(slide));\r\n\r\n if (slide.pos === self.currPos) {\r\n self.isAnimating = false;\r\n\r\n self.updateCursor();\r\n }\r\n }\r\n\r\n // Then some adjustments\r\n self.adjustLayout(slide);\r\n\r\n if ($slide.length) {\r\n $slide.trigger(\"refresh\");\r\n\r\n if (slide.pos === self.currPos) {\r\n self.$refs.toolbar\r\n .add(self.$refs.navigation.find(\".fancybox-button--arrow_right\"))\r\n .toggleClass(\"compensate-for-scrollbar\", $slide.get(0).scrollHeight > $slide.get(0).clientHeight);\r\n }\r\n }\r\n\r\n self.trigger(\"onUpdate\", slide, e);\r\n },\r\n\r\n // Horizontally center slide\r\n // =========================\r\n\r\n centerSlide: function (duration) {\r\n var self = this,\r\n current = self.current,\r\n $slide = current.$slide;\r\n\r\n if (self.isClosing || !current) {\r\n return;\r\n }\r\n\r\n $slide.siblings().css({\r\n transform: \"\",\r\n opacity: \"\"\r\n });\r\n\r\n $slide\r\n .parent()\r\n .children()\r\n .removeClass(\"fancybox-slide--previous fancybox-slide--next\");\r\n\r\n $.fancybox.animate(\r\n $slide, {\r\n top: 0,\r\n left: 0,\r\n opacity: 1\r\n },\r\n duration === undefined ? 0 : duration,\r\n function () {\r\n // Clean up\r\n $slide.css({\r\n transform: \"\",\r\n opacity: \"\"\r\n });\r\n\r\n if (!current.isComplete) {\r\n self.complete();\r\n }\r\n },\r\n false\r\n );\r\n },\r\n\r\n // Check if current slide is moved (swiped)\r\n // ========================================\r\n\r\n isMoved: function (slide) {\r\n var current = slide || this.current,\r\n slidePos,\r\n stagePos;\r\n\r\n if (!current) {\r\n return false;\r\n }\r\n\r\n stagePos = $.fancybox.getTranslate(this.$refs.stage);\r\n slidePos = $.fancybox.getTranslate(current.$slide);\r\n\r\n return (\r\n !current.$slide.hasClass(\"fancybox-animated\") &&\r\n (Math.abs(slidePos.top - stagePos.top) > 0.5 || Math.abs(slidePos.left - stagePos.left) > 0.5)\r\n );\r\n },\r\n\r\n // Update cursor style depending if content can be zoomed\r\n // ======================================================\r\n\r\n updateCursor: function (nextWidth, nextHeight) {\r\n var self = this,\r\n current = self.current,\r\n $container = self.$refs.container,\r\n canPan,\r\n isZoomable;\r\n\r\n if (!current || self.isClosing || !self.Guestures) {\r\n return;\r\n }\r\n\r\n $container.removeClass(\"fancybox-is-zoomable fancybox-can-zoomIn fancybox-can-zoomOut fancybox-can-swipe fancybox-can-pan\");\r\n\r\n canPan = self.canPan(nextWidth, nextHeight);\r\n\r\n isZoomable = canPan ? true : self.isZoomable();\r\n\r\n $container.toggleClass(\"fancybox-is-zoomable\", isZoomable);\r\n\r\n $(\"[data-fancybox-zoom]\").prop(\"disabled\", !isZoomable);\r\n\r\n if (canPan) {\r\n $container.addClass(\"fancybox-can-pan\");\r\n } else if (\r\n isZoomable &&\r\n (current.opts.clickContent === \"zoom\" || ($.isFunction(current.opts.clickContent) && current.opts.clickContent(current) == \"zoom\"))\r\n ) {\r\n $container.addClass(\"fancybox-can-zoomIn\");\r\n } else if (current.opts.touch && (current.opts.touch.vertical || self.group.length > 1) && current.contentType !== \"video\") {\r\n $container.addClass(\"fancybox-can-swipe\");\r\n }\r\n },\r\n\r\n // Check if current slide is zoomable\r\n // ==================================\r\n\r\n isZoomable: function () {\r\n var self = this,\r\n current = self.current,\r\n fitPos;\r\n\r\n // Assume that slide is zoomable if:\r\n // - image is still loading\r\n // - actual size of the image is smaller than available area\r\n if (current && !self.isClosing && current.type === \"image\" && !current.hasError) {\r\n if (!current.isLoaded) {\r\n return true;\r\n }\r\n\r\n fitPos = self.getFitPos(current);\r\n\r\n if (fitPos && (current.width > fitPos.width || current.height > fitPos.height)) {\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n },\r\n\r\n // Check if current image dimensions are smaller than actual\r\n // =========================================================\r\n\r\n isScaledDown: function (nextWidth, nextHeight) {\r\n var self = this,\r\n rez = false,\r\n current = self.current,\r\n $content = current.$content;\r\n\r\n if (nextWidth !== undefined && nextHeight !== undefined) {\r\n rez = nextWidth < current.width && nextHeight < current.height;\r\n } else if ($content) {\r\n rez = $.fancybox.getTranslate($content);\r\n rez = rez.width < current.width && rez.height < current.height;\r\n }\r\n\r\n return rez;\r\n },\r\n\r\n // Check if image dimensions exceed parent element\r\n // ===============================================\r\n\r\n canPan: function (nextWidth, nextHeight) {\r\n var self = this,\r\n current = self.current,\r\n pos = null,\r\n rez = false;\r\n\r\n if (current.type === \"image\" && (current.isComplete || (nextWidth && nextHeight)) && !current.hasError) {\r\n rez = self.getFitPos(current);\r\n\r\n if (nextWidth !== undefined && nextHeight !== undefined) {\r\n pos = {\r\n width: nextWidth,\r\n height: nextHeight\r\n };\r\n } else if (current.isComplete) {\r\n pos = $.fancybox.getTranslate(current.$content);\r\n }\r\n\r\n if (pos && rez) {\r\n rez = Math.abs(pos.width - rez.width) > 1.5 || Math.abs(pos.height - rez.height) > 1.5;\r\n }\r\n }\r\n\r\n return rez;\r\n },\r\n\r\n // Load content into the slide\r\n // ===========================\r\n\r\n loadSlide: function (slide) {\r\n var self = this,\r\n type,\r\n $slide,\r\n ajaxLoad;\r\n\r\n if (slide.isLoading || slide.isLoaded) {\r\n return;\r\n }\r\n\r\n slide.isLoading = true;\r\n\r\n if (self.trigger(\"beforeLoad\", slide) === false) {\r\n slide.isLoading = false;\r\n\r\n return false;\r\n }\r\n\r\n type = slide.type;\r\n $slide = slide.$slide;\r\n\r\n $slide\r\n .off(\"refresh\")\r\n .trigger(\"onReset\")\r\n .addClass(slide.opts.slideClass);\r\n\r\n // Create content depending on the type\r\n switch (type) {\r\n case \"image\":\r\n self.setImage(slide);\r\n\r\n break;\r\n\r\n case \"iframe\":\r\n self.setIframe(slide);\r\n\r\n break;\r\n\r\n case \"html\":\r\n self.setContent(slide, slide.src || slide.content);\r\n\r\n break;\r\n\r\n case \"video\":\r\n self.setContent(\r\n slide,\r\n slide.opts.video.tpl\r\n .replace(/\\{\\{src\\}\\}/gi, slide.src)\r\n .replace(\"{{format}}\", slide.opts.videoFormat || slide.opts.video.format || \"\")\r\n .replace(\"{{poster}}\", slide.thumb || \"\")\r\n );\r\n\r\n break;\r\n\r\n case \"inline\":\r\n if ($(slide.src).length) {\r\n self.setContent(slide, $(slide.src));\r\n } else {\r\n self.setError(slide);\r\n }\r\n\r\n break;\r\n\r\n case \"ajax\":\r\n self.showLoading(slide);\r\n\r\n ajaxLoad = $.ajax(\r\n $.extend({}, slide.opts.ajax.settings, {\r\n url: slide.src,\r\n success: function (data, textStatus) {\r\n if (textStatus === \"success\") {\r\n self.setContent(slide, data);\r\n }\r\n },\r\n error: function (jqXHR, textStatus) {\r\n if (jqXHR && textStatus !== \"abort\") {\r\n self.setError(slide);\r\n }\r\n }\r\n })\r\n );\r\n\r\n $slide.one(\"onReset\", function () {\r\n ajaxLoad.abort();\r\n });\r\n\r\n break;\r\n\r\n default:\r\n self.setError(slide);\r\n\r\n break;\r\n }\r\n\r\n return true;\r\n },\r\n\r\n // Use thumbnail image, if possible\r\n // ================================\r\n\r\n setImage: function (slide) {\r\n var self = this,\r\n ghost;\r\n\r\n // Check if need to show loading icon\r\n setTimeout(function () {\r\n var $img = slide.$image;\r\n\r\n if (!self.isClosing && slide.isLoading && (!$img || !$img.length || !$img[0].complete) && !slide.hasError) {\r\n self.showLoading(slide);\r\n }\r\n }, 50);\r\n\r\n //Check if image has srcset\r\n self.checkSrcset(slide);\r\n\r\n // This will be wrapper containing both ghost and actual image\r\n slide.$content = $('
')\r\n .addClass(\"fancybox-is-hidden\")\r\n .appendTo(slide.$slide.addClass(\"fancybox-slide--image\"));\r\n\r\n // If we have a thumbnail, we can display it while actual image is loading\r\n // Users will not stare at black screen and actual image will appear gradually\r\n if (slide.opts.preload !== false && slide.opts.width && slide.opts.height && slide.thumb) {\r\n slide.width = slide.opts.width;\r\n slide.height = slide.opts.height;\r\n\r\n ghost = document.createElement(\"img\");\r\n\r\n ghost.onerror = function () {\r\n $(this).remove();\r\n\r\n slide.$ghost = null;\r\n };\r\n\r\n ghost.onload = function () {\r\n self.afterLoad(slide);\r\n };\r\n\r\n slide.$ghost = $(ghost)\r\n .addClass(\"fancybox-image\")\r\n .appendTo(slide.$content)\r\n .attr(\"src\", slide.thumb);\r\n }\r\n\r\n // Start loading actual image\r\n self.setBigImage(slide);\r\n },\r\n\r\n // Check if image has srcset and get the source\r\n // ============================================\r\n checkSrcset: function (slide) {\r\n var srcset = slide.opts.srcset || slide.opts.image.srcset,\r\n found,\r\n temp,\r\n pxRatio,\r\n windowWidth;\r\n\r\n // If we have \"srcset\", then we need to find first matching \"src\" value.\r\n // This is necessary, because when you set an src attribute, the browser will preload the image\r\n // before any javascript or even CSS is applied.\r\n if (srcset) {\r\n pxRatio = window.devicePixelRatio || 1;\r\n windowWidth = window.innerWidth * pxRatio;\r\n\r\n temp = srcset.split(\",\").map(function (el) {\r\n var ret = {};\r\n\r\n el.trim()\r\n .split(/\\s+/)\r\n .forEach(function (el, i) {\r\n var value = parseInt(el.substring(0, el.length - 1), 10);\r\n\r\n if (i === 0) {\r\n return (ret.url = el);\r\n }\r\n\r\n if (value) {\r\n ret.value = value;\r\n ret.postfix = el[el.length - 1];\r\n }\r\n });\r\n\r\n return ret;\r\n });\r\n\r\n // Sort by value\r\n temp.sort(function (a, b) {\r\n return a.value - b.value;\r\n });\r\n\r\n // Ok, now we have an array of all srcset values\r\n for (var j = 0; j < temp.length; j++) {\r\n var el = temp[j];\r\n\r\n if ((el.postfix === \"w\" && el.value >= windowWidth) || (el.postfix === \"x\" && el.value >= pxRatio)) {\r\n found = el;\r\n break;\r\n }\r\n }\r\n\r\n // If not found, take the last one\r\n if (!found && temp.length) {\r\n found = temp[temp.length - 1];\r\n }\r\n\r\n if (found) {\r\n slide.src = found.url;\r\n\r\n // If we have default width/height values, we can calculate height for matching source\r\n if (slide.width && slide.height && found.postfix == \"w\") {\r\n slide.height = (slide.width / slide.height) * found.value;\r\n slide.width = found.value;\r\n }\r\n\r\n slide.opts.srcset = srcset;\r\n }\r\n }\r\n },\r\n\r\n // Create full-size image\r\n // ======================\r\n\r\n setBigImage: function (slide) {\r\n var self = this,\r\n img = document.createElement(\"img\"),\r\n $img = $(img);\r\n\r\n slide.$image = $img\r\n .one(\"error\", function () {\r\n self.setError(slide);\r\n })\r\n .one(\"load\", function () {\r\n var sizes;\r\n\r\n if (!slide.$ghost) {\r\n self.resolveImageSlideSize(slide, this.naturalWidth, this.naturalHeight);\r\n\r\n self.afterLoad(slide);\r\n }\r\n\r\n if (self.isClosing) {\r\n return;\r\n }\r\n\r\n if (slide.opts.srcset) {\r\n sizes = slide.opts.sizes;\r\n\r\n if (!sizes || sizes === \"auto\") {\r\n sizes =\r\n (slide.width / slide.height > 1 && $W.width() / $W.height() > 1 ? \"100\" : Math.round((slide.width / slide.height) * 100)) +\r\n \"vw\";\r\n }\r\n\r\n $img.attr(\"sizes\", sizes).attr(\"srcset\", slide.opts.srcset);\r\n }\r\n\r\n // Hide temporary image after some delay\r\n if (slide.$ghost) {\r\n setTimeout(function () {\r\n if (slide.$ghost && !self.isClosing) {\r\n slide.$ghost.hide();\r\n }\r\n }, Math.min(300, Math.max(1000, slide.height / 1600)));\r\n }\r\n\r\n self.hideLoading(slide);\r\n })\r\n .addClass(\"fancybox-image\")\r\n .attr(\"src\", slide.src)\r\n .appendTo(slide.$content);\r\n\r\n if ((img.complete || img.readyState == \"complete\") && $img.naturalWidth && $img.naturalHeight) {\r\n $img.trigger(\"load\");\r\n } else if (img.error) {\r\n $img.trigger(\"error\");\r\n }\r\n },\r\n\r\n // Computes the slide size from image size and maxWidth/maxHeight\r\n // ==============================================================\r\n\r\n resolveImageSlideSize: function (slide, imgWidth, imgHeight) {\r\n var maxWidth = parseInt(slide.opts.width, 10),\r\n maxHeight = parseInt(slide.opts.height, 10);\r\n\r\n // Sets the default values from the image\r\n slide.width = imgWidth;\r\n slide.height = imgHeight;\r\n\r\n if (maxWidth > 0) {\r\n slide.width = maxWidth;\r\n slide.height = Math.floor((maxWidth * imgHeight) / imgWidth);\r\n }\r\n\r\n if (maxHeight > 0) {\r\n slide.width = Math.floor((maxHeight * imgWidth) / imgHeight);\r\n slide.height = maxHeight;\r\n }\r\n },\r\n\r\n // Create iframe wrapper, iframe and bindings\r\n // ==========================================\r\n\r\n setIframe: function (slide) {\r\n var self = this,\r\n opts = slide.opts.iframe,\r\n $slide = slide.$slide,\r\n $iframe;\r\n\r\n slide.$content = $('
')\r\n .css(opts.css)\r\n .appendTo($slide);\r\n\r\n $slide.addClass(\"fancybox-slide--\" + slide.contentType);\r\n\r\n slide.$iframe = $iframe = $(opts.tpl.replace(/\\{rnd\\}/g, new Date().getTime()))\r\n .attr(opts.attr)\r\n .appendTo(slide.$content);\r\n\r\n if (opts.preload) {\r\n self.showLoading(slide);\r\n\r\n // Unfortunately, it is not always possible to determine if iframe is successfully loaded\r\n // (due to browser security policy)\r\n\r\n $iframe.on(\"load.fb error.fb\", function (e) {\r\n this.isReady = 1;\r\n\r\n slide.$slide.trigger(\"refresh\");\r\n\r\n self.afterLoad(slide);\r\n });\r\n\r\n // Recalculate iframe content size\r\n // ===============================\r\n\r\n $slide.on(\"refresh.fb\", function () {\r\n var $content = slide.$content,\r\n frameWidth = opts.css.width,\r\n frameHeight = opts.css.height,\r\n $contents,\r\n $body;\r\n\r\n if ($iframe[0].isReady !== 1) {\r\n return;\r\n }\r\n\r\n try {\r\n $contents = $iframe.contents();\r\n $body = $contents.find(\"body\");\r\n } catch (ignore) {}\r\n\r\n // Calculate content dimensions, if it is accessible\r\n if ($body && $body.length && $body.children().length) {\r\n // Avoid scrolling to top (if multiple instances)\r\n $slide.css(\"overflow\", \"visible\");\r\n\r\n $content.css({\r\n width: \"100%\",\r\n \"max-width\": \"100%\",\r\n height: \"9999px\"\r\n });\r\n\r\n if (frameWidth === undefined) {\r\n frameWidth = Math.ceil(Math.max($body[0].clientWidth, $body.outerWidth(true)));\r\n }\r\n\r\n $content.css(\"width\", frameWidth ? frameWidth : \"\").css(\"max-width\", \"\");\r\n\r\n if (frameHeight === undefined) {\r\n frameHeight = Math.ceil(Math.max($body[0].clientHeight, $body.outerHeight(true)));\r\n }\r\n\r\n $content.css(\"height\", frameHeight ? frameHeight : \"\");\r\n\r\n $slide.css(\"overflow\", \"auto\");\r\n }\r\n\r\n $content.removeClass(\"fancybox-is-hidden\");\r\n });\r\n } else {\r\n self.afterLoad(slide);\r\n }\r\n\r\n $iframe.attr(\"src\", slide.src);\r\n\r\n // Remove iframe if closing or changing gallery item\r\n $slide.one(\"onReset\", function () {\r\n // This helps IE not to throw errors when closing\r\n try {\r\n $(this)\r\n .find(\"iframe\")\r\n .hide()\r\n .unbind()\r\n .attr(\"src\", \"//about:blank\");\r\n } catch (ignore) {}\r\n\r\n $(this)\r\n .off(\"refresh.fb\")\r\n .empty();\r\n\r\n slide.isLoaded = false;\r\n slide.isRevealed = false;\r\n });\r\n },\r\n\r\n // Wrap and append content to the slide\r\n // ======================================\r\n\r\n setContent: function (slide, content) {\r\n var self = this;\r\n\r\n if (self.isClosing) {\r\n return;\r\n }\r\n\r\n self.hideLoading(slide);\r\n\r\n if (slide.$content) {\r\n $.fancybox.stop(slide.$content);\r\n }\r\n\r\n slide.$slide.empty();\r\n\r\n // If content is a jQuery object, then it will be moved to the slide.\r\n // The placeholder is created so we will know where to put it back.\r\n if (isQuery(content) && content.parent().length) {\r\n // Make sure content is not already moved to fancyBox\r\n if (content.hasClass(\"fancybox-content\") || content.parent().hasClass(\"fancybox-content\")) {\r\n content.parents(\".fancybox-slide\").trigger(\"onReset\");\r\n }\r\n\r\n // Create temporary element marking original place of the content\r\n slide.$placeholder = $(\"
\")\r\n .hide()\r\n .insertAfter(content);\r\n\r\n // Make sure content is visible\r\n content.css(\"display\", \"inline-block\");\r\n } else if (!slide.hasError) {\r\n // If content is just a plain text, try to convert it to html\r\n if ($.type(content) === \"string\") {\r\n content = $(\"
\")\r\n .append($.trim(content))\r\n .contents();\r\n }\r\n\r\n // If \"filter\" option is provided, then filter content\r\n if (slide.opts.filter) {\r\n content = $(\"
\")\r\n .html(content)\r\n .find(slide.opts.filter);\r\n }\r\n }\r\n\r\n slide.$slide.one(\"onReset\", function () {\r\n // Pause all html5 video/audio\r\n $(this)\r\n .find(\"video,audio\")\r\n .trigger(\"pause\");\r\n\r\n // Put content back\r\n if (slide.$placeholder) {\r\n slide.$placeholder.after(content.removeClass(\"fancybox-content\").hide()).remove();\r\n\r\n slide.$placeholder = null;\r\n }\r\n\r\n // Remove custom close button\r\n if (slide.$smallBtn) {\r\n slide.$smallBtn.remove();\r\n\r\n slide.$smallBtn = null;\r\n }\r\n\r\n // Remove content and mark slide as not loaded\r\n if (!slide.hasError) {\r\n $(this).empty();\r\n\r\n slide.isLoaded = false;\r\n slide.isRevealed = false;\r\n }\r\n });\r\n\r\n $(content).appendTo(slide.$slide);\r\n\r\n if ($(content).is(\"video,audio\")) {\r\n $(content).addClass(\"fancybox-video\");\r\n\r\n $(content).wrap(\"
\");\r\n\r\n slide.contentType = \"video\";\r\n\r\n slide.opts.width = slide.opts.width || $(content).attr(\"width\");\r\n slide.opts.height = slide.opts.height || $(content).attr(\"height\");\r\n }\r\n\r\n slide.$content = slide.$slide\r\n .children()\r\n .filter(\"div,form,main,video,audio,article,.fancybox-content\")\r\n .first();\r\n\r\n slide.$content.siblings().hide();\r\n\r\n // Re-check if there is a valid content\r\n // (in some cases, ajax response can contain various elements or plain text)\r\n if (!slide.$content.length) {\r\n slide.$content = slide.$slide\r\n .wrapInner(\"
\")\r\n .children()\r\n .first();\r\n }\r\n\r\n slide.$content.addClass(\"fancybox-content\");\r\n\r\n slide.$slide.addClass(\"fancybox-slide--\" + slide.contentType);\r\n\r\n self.afterLoad(slide);\r\n },\r\n\r\n // Display error message\r\n // =====================\r\n\r\n setError: function (slide) {\r\n slide.hasError = true;\r\n\r\n slide.$slide\r\n .trigger(\"onReset\")\r\n .removeClass(\"fancybox-slide--\" + slide.contentType)\r\n .addClass(\"fancybox-slide--error\");\r\n\r\n slide.contentType = \"html\";\r\n\r\n this.setContent(slide, this.translate(slide, slide.opts.errorTpl));\r\n\r\n if (slide.pos === this.currPos) {\r\n this.isAnimating = false;\r\n }\r\n },\r\n\r\n // Show loading icon inside the slide\r\n // ==================================\r\n\r\n showLoading: function (slide) {\r\n var self = this;\r\n\r\n slide = slide || self.current;\r\n\r\n if (slide && !slide.$spinner) {\r\n slide.$spinner = $(self.translate(self, self.opts.spinnerTpl))\r\n .appendTo(slide.$slide)\r\n .hide()\r\n .fadeIn(\"fast\");\r\n }\r\n },\r\n\r\n // Remove loading icon from the slide\r\n // ==================================\r\n\r\n hideLoading: function (slide) {\r\n var self = this;\r\n\r\n slide = slide || self.current;\r\n\r\n if (slide && slide.$spinner) {\r\n slide.$spinner.stop().remove();\r\n\r\n delete slide.$spinner;\r\n }\r\n },\r\n\r\n // Adjustments after slide content has been loaded\r\n // ===============================================\r\n\r\n afterLoad: function (slide) {\r\n var self = this;\r\n\r\n if (self.isClosing) {\r\n return;\r\n }\r\n\r\n slide.isLoading = false;\r\n slide.isLoaded = true;\r\n\r\n self.trigger(\"afterLoad\", slide);\r\n\r\n self.hideLoading(slide);\r\n\r\n // Add small close button\r\n if (slide.opts.smallBtn && (!slide.$smallBtn || !slide.$smallBtn.length)) {\r\n slide.$smallBtn = $(self.translate(slide, slide.opts.btnTpl.smallBtn)).appendTo(slide.$content);\r\n }\r\n\r\n // Disable right click\r\n if (slide.opts.protect && slide.$content && !slide.hasError) {\r\n slide.$content.on(\"contextmenu.fb\", function (e) {\r\n if (e.button == 2) {\r\n e.preventDefault();\r\n }\r\n\r\n return true;\r\n });\r\n\r\n // Add fake element on top of the image\r\n // This makes a bit harder for user to select image\r\n if (slide.type === \"image\") {\r\n $('
').appendTo(slide.$content);\r\n }\r\n }\r\n\r\n self.adjustCaption(slide);\r\n\r\n self.adjustLayout(slide);\r\n\r\n if (slide.pos === self.currPos) {\r\n self.updateCursor();\r\n }\r\n\r\n self.revealContent(slide);\r\n },\r\n\r\n // Prevent caption overlap,\r\n // fix css inconsistency across browsers\r\n // =====================================\r\n\r\n adjustCaption: function (slide) {\r\n var self = this,\r\n current = slide || self.current,\r\n caption = current.opts.caption,\r\n preventOverlap = current.opts.preventCaptionOverlap,\r\n $caption = self.$refs.caption,\r\n $clone,\r\n captionH = false;\r\n\r\n $caption.toggleClass(\"fancybox-caption--separate\", preventOverlap);\r\n\r\n if (preventOverlap && caption && caption.length) {\r\n if (current.pos !== self.currPos) {\r\n $clone = $caption.clone().appendTo($caption.parent());\r\n\r\n $clone\r\n .children()\r\n .eq(0)\r\n .empty()\r\n .html(caption);\r\n\r\n captionH = $clone.outerHeight(true);\r\n\r\n $clone.empty().remove();\r\n } else if (self.$caption) {\r\n captionH = self.$caption.outerHeight(true);\r\n }\r\n\r\n current.$slide.css(\"padding-bottom\", captionH || \"\");\r\n }\r\n },\r\n\r\n // Simple hack to fix inconsistency across browsers, described here (affects Edge, too):\r\n // https://bugzilla.mozilla.org/show_bug.cgi?id=748518\r\n // ====================================================================================\r\n\r\n adjustLayout: function (slide) {\r\n var self = this,\r\n current = slide || self.current,\r\n scrollHeight,\r\n marginBottom,\r\n inlinePadding,\r\n actualPadding;\r\n\r\n if (current.isLoaded && current.opts.disableLayoutFix !== true) {\r\n current.$content.css(\"margin-bottom\", \"\");\r\n\r\n // If we would always set margin-bottom for the content,\r\n // then it would potentially break vertical align\r\n if (current.$content.outerHeight() > current.$slide.height() + 0.5) {\r\n inlinePadding = current.$slide[0].style[\"padding-bottom\"];\r\n actualPadding = current.$slide.css(\"padding-bottom\");\r\n\r\n if (parseFloat(actualPadding) > 0) {\r\n scrollHeight = current.$slide[0].scrollHeight;\r\n\r\n current.$slide.css(\"padding-bottom\", 0);\r\n\r\n if (Math.abs(scrollHeight - current.$slide[0].scrollHeight) < 1) {\r\n marginBottom = actualPadding;\r\n }\r\n\r\n current.$slide.css(\"padding-bottom\", inlinePadding);\r\n }\r\n }\r\n\r\n current.$content.css(\"margin-bottom\", marginBottom);\r\n }\r\n },\r\n\r\n // Make content visible\r\n // This method is called right after content has been loaded or\r\n // user navigates gallery and transition should start\r\n // ============================================================\r\n\r\n revealContent: function (slide) {\r\n var self = this,\r\n $slide = slide.$slide,\r\n end = false,\r\n start = false,\r\n isMoved = self.isMoved(slide),\r\n isRevealed = slide.isRevealed,\r\n effect,\r\n effectClassName,\r\n duration,\r\n opacity;\r\n\r\n slide.isRevealed = true;\r\n\r\n effect = slide.opts[self.firstRun ? \"animationEffect\" : \"transitionEffect\"];\r\n duration = slide.opts[self.firstRun ? \"animationDuration\" : \"transitionDuration\"];\r\n\r\n duration = parseInt(slide.forcedDuration === undefined ? duration : slide.forcedDuration, 10);\r\n\r\n if (isMoved || slide.pos !== self.currPos || !duration) {\r\n effect = false;\r\n }\r\n\r\n // Check if can zoom\r\n if (effect === \"zoom\") {\r\n if (slide.pos === self.currPos && duration && slide.type === \"image\" && !slide.hasError && (start = self.getThumbPos(slide))) {\r\n end = self.getFitPos(slide);\r\n } else {\r\n effect = \"fade\";\r\n }\r\n }\r\n\r\n // Zoom animation\r\n // ==============\r\n if (effect === \"zoom\") {\r\n self.isAnimating = true;\r\n\r\n end.scaleX = end.width / start.width;\r\n end.scaleY = end.height / start.height;\r\n\r\n // Check if we need to animate opacity\r\n opacity = slide.opts.zoomOpacity;\r\n\r\n if (opacity == \"auto\") {\r\n opacity = Math.abs(slide.width / slide.height - start.width / start.height) > 0.1;\r\n }\r\n\r\n if (opacity) {\r\n start.opacity = 0.1;\r\n end.opacity = 1;\r\n }\r\n\r\n // Draw image at start position\r\n $.fancybox.setTranslate(slide.$content.removeClass(\"fancybox-is-hidden\"), start);\r\n\r\n forceRedraw(slide.$content);\r\n\r\n // Start animation\r\n $.fancybox.animate(slide.$content, end, duration, function () {\r\n self.isAnimating = false;\r\n\r\n self.complete();\r\n });\r\n\r\n return;\r\n }\r\n\r\n self.updateSlide(slide);\r\n\r\n // Simply show content if no effect\r\n // ================================\r\n if (!effect) {\r\n slide.$content.removeClass(\"fancybox-is-hidden\");\r\n\r\n if (!isRevealed && isMoved && slide.type === \"image\" && !slide.hasError) {\r\n slide.$content.hide().fadeIn(\"fast\");\r\n }\r\n\r\n if (slide.pos === self.currPos) {\r\n self.complete();\r\n }\r\n\r\n return;\r\n }\r\n\r\n // Prepare for CSS transiton\r\n // =========================\r\n $.fancybox.stop($slide);\r\n\r\n //effectClassName = \"fancybox-animated fancybox-slide--\" + (slide.pos >= self.prevPos ? \"next\" : \"previous\") + \" fancybox-fx-\" + effect;\r\n effectClassName = \"fancybox-slide--\" + (slide.pos >= self.prevPos ? \"next\" : \"previous\") + \" fancybox-animated fancybox-fx-\" + effect;\r\n\r\n $slide.addClass(effectClassName).removeClass(\"fancybox-slide--current\"); //.addClass(effectClassName);\r\n\r\n slide.$content.removeClass(\"fancybox-is-hidden\");\r\n\r\n // Force reflow\r\n forceRedraw($slide);\r\n\r\n if (slide.type !== \"image\") {\r\n slide.$content.hide().show(0);\r\n }\r\n\r\n $.fancybox.animate(\r\n $slide,\r\n \"fancybox-slide--current\",\r\n duration,\r\n function () {\r\n $slide.removeClass(effectClassName).css({\r\n transform: \"\",\r\n opacity: \"\"\r\n });\r\n\r\n if (slide.pos === self.currPos) {\r\n self.complete();\r\n }\r\n },\r\n true\r\n );\r\n },\r\n\r\n // Check if we can and have to zoom from thumbnail\r\n //================================================\r\n\r\n getThumbPos: function (slide) {\r\n var rez = false,\r\n $thumb = slide.$thumb,\r\n thumbPos,\r\n btw,\r\n brw,\r\n bbw,\r\n blw;\r\n\r\n if (!$thumb || !inViewport($thumb[0])) {\r\n return false;\r\n }\r\n\r\n thumbPos = $.fancybox.getTranslate($thumb);\r\n\r\n btw = parseFloat($thumb.css(\"border-top-width\") || 0);\r\n brw = parseFloat($thumb.css(\"border-right-width\") || 0);\r\n bbw = parseFloat($thumb.css(\"border-bottom-width\") || 0);\r\n blw = parseFloat($thumb.css(\"border-left-width\") || 0);\r\n\r\n rez = {\r\n top: thumbPos.top + btw,\r\n left: thumbPos.left + blw,\r\n width: thumbPos.width - brw - blw,\r\n height: thumbPos.height - btw - bbw,\r\n scaleX: 1,\r\n scaleY: 1\r\n };\r\n\r\n return thumbPos.width > 0 && thumbPos.height > 0 ? rez : false;\r\n },\r\n\r\n // Final adjustments after current gallery item is moved to position\r\n // and it`s content is loaded\r\n // ==================================================================\r\n\r\n complete: function () {\r\n var self = this,\r\n current = self.current,\r\n slides = {},\r\n $el;\r\n\r\n if (self.isMoved() || !current.isLoaded) {\r\n return;\r\n }\r\n\r\n if (!current.isComplete) {\r\n current.isComplete = true;\r\n\r\n current.$slide.siblings().trigger(\"onReset\");\r\n\r\n self.preload(\"inline\");\r\n\r\n // Trigger any CSS transiton inside the slide\r\n forceRedraw(current.$slide);\r\n\r\n current.$slide.addClass(\"fancybox-slide--complete\");\r\n\r\n // Remove unnecessary slides\r\n $.each(self.slides, function (key, slide) {\r\n if (slide.pos >= self.currPos - 1 && slide.pos <= self.currPos + 1) {\r\n slides[slide.pos] = slide;\r\n } else if (slide) {\r\n $.fancybox.stop(slide.$slide);\r\n\r\n slide.$slide.off().remove();\r\n }\r\n });\r\n\r\n self.slides = slides;\r\n }\r\n\r\n self.isAnimating = false;\r\n\r\n self.updateCursor();\r\n\r\n self.trigger(\"afterShow\");\r\n\r\n // Autoplay first html5 video/audio\r\n if (!!current.opts.video.autoStart) {\r\n current.$slide\r\n .find(\"video,audio\")\r\n .filter(\":visible:first\")\r\n .trigger(\"play\")\r\n .one(\"ended\", function () {\r\n if (Document.exitFullscreen) {\r\n Document.exitFullscreen();\r\n } else if (this.webkitExitFullscreen) {\r\n this.webkitExitFullscreen();\r\n }\r\n\r\n self.next();\r\n });\r\n }\r\n\r\n // Try to focus on the first focusable element\r\n if (current.opts.autoFocus && current.contentType === \"html\") {\r\n // Look for the first input with autofocus attribute\r\n $el = current.$content.find(\"input[autofocus]:enabled:visible:first\");\r\n\r\n if ($el.length) {\r\n $el.trigger(\"focus\");\r\n } else {\r\n self.focus(null, true);\r\n }\r\n }\r\n\r\n // Avoid jumping\r\n current.$slide.scrollTop(0).scrollLeft(0);\r\n },\r\n\r\n // Preload next and previous slides\r\n // ================================\r\n\r\n preload: function (type) {\r\n var self = this,\r\n prev,\r\n next;\r\n\r\n if (self.group.length < 2) {\r\n return;\r\n }\r\n\r\n next = self.slides[self.currPos + 1];\r\n prev = self.slides[self.currPos - 1];\r\n\r\n if (prev && prev.type === type) {\r\n self.loadSlide(prev);\r\n }\r\n\r\n if (next && next.type === type) {\r\n self.loadSlide(next);\r\n }\r\n },\r\n\r\n // Try to find and focus on the first focusable element\r\n // ====================================================\r\n\r\n focus: function (e, firstRun) {\r\n var self = this,\r\n focusableStr = [\r\n \"a[href]\",\r\n \"area[href]\",\r\n 'input:not([disabled]):not([type=\"hidden\"]):not([aria-hidden])',\r\n \"select:not([disabled]):not([aria-hidden])\",\r\n \"textarea:not([disabled]):not([aria-hidden])\",\r\n \"button:not([disabled]):not([aria-hidden])\",\r\n \"iframe\",\r\n \"object\",\r\n \"embed\",\r\n \"video\",\r\n \"audio\",\r\n \"[contenteditable]\",\r\n '[tabindex]:not([tabindex^=\"-\"])'\r\n ].join(\",\"),\r\n focusableItems,\r\n focusedItemIndex;\r\n\r\n if (self.isClosing) {\r\n return;\r\n }\r\n\r\n if (e || !self.current || !self.current.isComplete) {\r\n // Focus on any element inside fancybox\r\n focusableItems = self.$refs.container.find(\"*:visible\");\r\n } else {\r\n // Focus inside current slide\r\n focusableItems = self.current.$slide.find(\"*:visible\" + (firstRun ? \":not(.fancybox-close-small)\" : \"\"));\r\n }\r\n\r\n focusableItems = focusableItems.filter(focusableStr).filter(function () {\r\n return $(this).css(\"visibility\") !== \"hidden\" && !$(this).hasClass(\"disabled\");\r\n });\r\n\r\n if (focusableItems.length) {\r\n focusedItemIndex = focusableItems.index(document.activeElement);\r\n\r\n if (e && e.shiftKey) {\r\n // Back tab\r\n if (focusedItemIndex < 0 || focusedItemIndex == 0) {\r\n e.preventDefault();\r\n\r\n focusableItems.eq(focusableItems.length - 1).trigger(\"focus\");\r\n }\r\n } else {\r\n // Outside or Forward tab\r\n if (focusedItemIndex < 0 || focusedItemIndex == focusableItems.length - 1) {\r\n if (e) {\r\n e.preventDefault();\r\n }\r\n\r\n focusableItems.eq(0).trigger(\"focus\");\r\n }\r\n }\r\n } else {\r\n self.$refs.container.trigger(\"focus\");\r\n }\r\n },\r\n\r\n // Activates current instance - brings container to the front and enables keyboard,\r\n // notifies other instances about deactivating\r\n // =================================================================================\r\n\r\n activate: function () {\r\n var self = this;\r\n\r\n // Deactivate all instances\r\n $(\".fancybox-container\").each(function () {\r\n var instance = $(this).data(\"FancyBox\");\r\n\r\n // Skip self and closing instances\r\n if (instance && instance.id !== self.id && !instance.isClosing) {\r\n instance.trigger(\"onDeactivate\");\r\n\r\n instance.removeEvents();\r\n\r\n instance.isVisible = false;\r\n }\r\n });\r\n\r\n self.isVisible = true;\r\n\r\n if (self.current || self.isIdle) {\r\n self.update();\r\n\r\n self.updateControls();\r\n }\r\n\r\n self.trigger(\"onActivate\");\r\n\r\n self.addEvents();\r\n },\r\n\r\n // Start closing procedure\r\n // This will start \"zoom-out\" animation if needed and clean everything up afterwards\r\n // =================================================================================\r\n\r\n close: function (e, d) {\r\n var self = this,\r\n current = self.current,\r\n effect,\r\n duration,\r\n $content,\r\n domRect,\r\n opacity,\r\n start,\r\n end;\r\n\r\n var done = function () {\r\n self.cleanUp(e);\r\n };\r\n\r\n if (self.isClosing) {\r\n return false;\r\n }\r\n\r\n self.isClosing = true;\r\n\r\n // If beforeClose callback prevents closing, make sure content is centered\r\n if (self.trigger(\"beforeClose\", e) === false) {\r\n self.isClosing = false;\r\n\r\n requestAFrame(function () {\r\n self.update();\r\n });\r\n\r\n return false;\r\n }\r\n\r\n // Remove all events\r\n // If there are multiple instances, they will be set again by \"activate\" method\r\n self.removeEvents();\r\n\r\n $content = current.$content;\r\n effect = current.opts.animationEffect;\r\n duration = $.isNumeric(d) ? d : effect ? current.opts.animationDuration : 0;\r\n\r\n current.$slide.removeClass(\"fancybox-slide--complete fancybox-slide--next fancybox-slide--previous fancybox-animated\");\r\n\r\n if (e !== true) {\r\n $.fancybox.stop(current.$slide);\r\n } else {\r\n effect = false;\r\n }\r\n\r\n // Remove other slides\r\n current.$slide\r\n .siblings()\r\n .trigger(\"onReset\")\r\n .remove();\r\n\r\n // Trigger animations\r\n if (duration) {\r\n self.$refs.container\r\n .removeClass(\"fancybox-is-open\")\r\n .addClass(\"fancybox-is-closing\")\r\n .css(\"transition-duration\", duration + \"ms\");\r\n }\r\n\r\n // Clean up\r\n self.hideLoading(current);\r\n\r\n self.hideControls(true);\r\n\r\n self.updateCursor();\r\n\r\n // Check if possible to zoom-out\r\n if (\r\n effect === \"zoom\" &&\r\n !($content && duration && current.type === \"image\" && !self.isMoved() && !current.hasError && (end = self.getThumbPos(current)))\r\n ) {\r\n effect = \"fade\";\r\n }\r\n\r\n if (effect === \"zoom\") {\r\n $.fancybox.stop($content);\r\n\r\n domRect = $.fancybox.getTranslate($content);\r\n\r\n start = {\r\n top: domRect.top,\r\n left: domRect.left,\r\n scaleX: domRect.width / end.width,\r\n scaleY: domRect.height / end.height,\r\n width: end.width,\r\n height: end.height\r\n };\r\n\r\n // Check if we need to animate opacity\r\n opacity = current.opts.zoomOpacity;\r\n\r\n if (opacity == \"auto\") {\r\n opacity = Math.abs(current.width / current.height - end.width / end.height) > 0.1;\r\n }\r\n\r\n if (opacity) {\r\n end.opacity = 0;\r\n }\r\n\r\n $.fancybox.setTranslate($content, start);\r\n\r\n forceRedraw($content);\r\n\r\n $.fancybox.animate($content, end, duration, done);\r\n\r\n return true;\r\n }\r\n\r\n if (effect && duration) {\r\n $.fancybox.animate(\r\n current.$slide.addClass(\"fancybox-slide--previous\").removeClass(\"fancybox-slide--current\"),\r\n \"fancybox-animated fancybox-fx-\" + effect,\r\n duration,\r\n done\r\n );\r\n } else {\r\n // If skip animation\r\n if (e === true) {\r\n setTimeout(done, duration);\r\n } else {\r\n done();\r\n }\r\n }\r\n\r\n return true;\r\n },\r\n\r\n // Final adjustments after removing the instance\r\n // =============================================\r\n\r\n cleanUp: function (e) {\r\n var self = this,\r\n instance,\r\n $focus = self.current.opts.$orig,\r\n x,\r\n y;\r\n\r\n self.current.$slide.trigger(\"onReset\");\r\n\r\n self.$refs.container.empty().remove();\r\n\r\n self.trigger(\"afterClose\", e);\r\n\r\n // Place back focus\r\n if (!!self.current.opts.backFocus) {\r\n if (!$focus || !$focus.length || !$focus.is(\":visible\")) {\r\n $focus = self.$trigger;\r\n }\r\n\r\n if ($focus && $focus.length) {\r\n x = window.scrollX;\r\n y = window.scrollY;\r\n\r\n $focus.trigger(\"focus\");\r\n\r\n $(\"html, body\")\r\n .scrollTop(y)\r\n .scrollLeft(x);\r\n }\r\n }\r\n\r\n self.current = null;\r\n\r\n // Check if there are other instances\r\n instance = $.fancybox.getInstance();\r\n\r\n if (instance) {\r\n instance.activate();\r\n } else {\r\n $(\"body\").removeClass(\"fancybox-active compensate-for-scrollbar\");\r\n\r\n $(\"#fancybox-style-noscroll\").remove();\r\n }\r\n },\r\n\r\n // Call callback and trigger an event\r\n // ==================================\r\n\r\n trigger: function (name, slide) {\r\n var args = Array.prototype.slice.call(arguments, 1),\r\n self = this,\r\n obj = slide && slide.opts ? slide : self.current,\r\n rez;\r\n\r\n if (obj) {\r\n args.unshift(obj);\r\n } else {\r\n obj = self;\r\n }\r\n\r\n args.unshift(self);\r\n\r\n if ($.isFunction(obj.opts[name])) {\r\n rez = obj.opts[name].apply(obj, args);\r\n }\r\n\r\n if (rez === false) {\r\n return rez;\r\n }\r\n\r\n if (name === \"afterClose\" || !self.$refs) {\r\n $D.trigger(name + \".fb\", args);\r\n } else {\r\n self.$refs.container.trigger(name + \".fb\", args);\r\n }\r\n },\r\n\r\n // Update infobar values, navigation button states and reveal caption\r\n // ==================================================================\r\n\r\n updateControls: function () {\r\n var self = this,\r\n current = self.current,\r\n index = current.index,\r\n $container = self.$refs.container,\r\n $caption = self.$refs.caption,\r\n caption = current.opts.caption;\r\n\r\n // Recalculate content dimensions\r\n current.$slide.trigger(\"refresh\");\r\n\r\n // Set caption\r\n if (caption && caption.length) {\r\n self.$caption = $caption;\r\n\r\n $caption\r\n .children()\r\n .eq(0)\r\n .html(caption);\r\n } else {\r\n self.$caption = null;\r\n }\r\n\r\n if (!self.hasHiddenControls && !self.isIdle) {\r\n self.showControls();\r\n }\r\n\r\n // Update info and navigation elements\r\n $container.find(\"[data-fancybox-count]\").html(self.group.length);\r\n $container.find(\"[data-fancybox-index]\").html(index + 1);\r\n\r\n $container.find(\"[data-fancybox-prev]\").prop(\"disabled\", !current.opts.loop && index <= 0);\r\n $container.find(\"[data-fancybox-next]\").prop(\"disabled\", !current.opts.loop && index >= self.group.length - 1);\r\n\r\n if (current.type === \"image\") {\r\n // Re-enable buttons; update download button source\r\n $container\r\n .find(\"[data-fancybox-zoom]\")\r\n .show()\r\n .end()\r\n .find(\"[data-fancybox-download]\")\r\n .attr(\"href\", current.opts.image.src || current.src)\r\n .show();\r\n } else if (current.opts.toolbar) {\r\n $container.find(\"[data-fancybox-download],[data-fancybox-zoom]\").hide();\r\n }\r\n\r\n // Make sure focus is not on disabled button/element\r\n if ($(document.activeElement).is(\":hidden,[disabled]\")) {\r\n self.$refs.container.trigger(\"focus\");\r\n }\r\n },\r\n\r\n // Hide toolbar and caption\r\n // ========================\r\n\r\n hideControls: function (andCaption) {\r\n var self = this,\r\n arr = [\"infobar\", \"toolbar\", \"nav\"];\r\n\r\n if (andCaption || !self.current.opts.preventCaptionOverlap) {\r\n arr.push(\"caption\");\r\n }\r\n\r\n this.$refs.container.removeClass(\r\n arr\r\n .map(function (i) {\r\n return \"fancybox-show-\" + i;\r\n })\r\n .join(\" \")\r\n );\r\n\r\n this.hasHiddenControls = true;\r\n },\r\n\r\n showControls: function () {\r\n var self = this,\r\n opts = self.current ? self.current.opts : self.opts,\r\n $container = self.$refs.container;\r\n\r\n self.hasHiddenControls = false;\r\n self.idleSecondsCounter = 0;\r\n\r\n $container\r\n .toggleClass(\"fancybox-show-toolbar\", !!(opts.toolbar && opts.buttons))\r\n .toggleClass(\"fancybox-show-infobar\", !!(opts.infobar && self.group.length > 1))\r\n .toggleClass(\"fancybox-show-caption\", !!self.$caption)\r\n .toggleClass(\"fancybox-show-nav\", !!(opts.arrows && self.group.length > 1))\r\n .toggleClass(\"fancybox-is-modal\", !!opts.modal);\r\n },\r\n\r\n // Toggle toolbar and caption\r\n // ==========================\r\n\r\n toggleControls: function () {\r\n if (this.hasHiddenControls) {\r\n this.showControls();\r\n } else {\r\n this.hideControls();\r\n }\r\n }\r\n });\r\n\r\n $.fancybox = {\r\n version: \"3.5.7\",\r\n defaults: defaults,\r\n\r\n // Get current instance and execute a command.\r\n //\r\n // Examples of usage:\r\n //\r\n // $instance = $.fancybox.getInstance();\r\n // $.fancybox.getInstance().jumpTo( 1 );\r\n // $.fancybox.getInstance( 'jumpTo', 1 );\r\n // $.fancybox.getInstance( function() {\r\n // console.info( this.currIndex );\r\n // });\r\n // ======================================================\r\n\r\n getInstance: function (command) {\r\n var instance = $('.fancybox-container:not(\".fancybox-is-closing\"):last').data(\"FancyBox\"),\r\n args = Array.prototype.slice.call(arguments, 1);\r\n\r\n if (instance instanceof FancyBox) {\r\n if ($.type(command) === \"string\") {\r\n instance[command].apply(instance, args);\r\n } else if ($.type(command) === \"function\") {\r\n command.apply(instance, args);\r\n }\r\n\r\n return instance;\r\n }\r\n\r\n return false;\r\n },\r\n\r\n // Create new instance\r\n // ===================\r\n\r\n open: function (items, opts, index) {\r\n return new FancyBox(items, opts, index);\r\n },\r\n\r\n // Close current or all instances\r\n // ==============================\r\n\r\n close: function (all) {\r\n var instance = this.getInstance();\r\n\r\n if (instance) {\r\n instance.close();\r\n\r\n // Try to find and close next instance\r\n if (all === true) {\r\n this.close(all);\r\n }\r\n }\r\n },\r\n\r\n // Close all instances and unbind all events\r\n // =========================================\r\n\r\n destroy: function () {\r\n this.close(true);\r\n\r\n $D.add(\"body\").off(\"click.fb-start\", \"**\");\r\n },\r\n\r\n // Try to detect mobile devices\r\n // ============================\r\n\r\n isMobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent),\r\n\r\n // Detect if 'translate3d' support is available\r\n // ============================================\r\n\r\n use3d: (function () {\r\n var div = document.createElement(\"div\");\r\n\r\n return (\r\n window.getComputedStyle &&\r\n window.getComputedStyle(div) &&\r\n window.getComputedStyle(div).getPropertyValue(\"transform\") &&\r\n !(document.documentMode && document.documentMode < 11)\r\n );\r\n })(),\r\n\r\n // Helper function to get current visual state of an element\r\n // returns array[ top, left, horizontal-scale, vertical-scale, opacity ]\r\n // =====================================================================\r\n\r\n getTranslate: function ($el) {\r\n var domRect;\r\n\r\n if (!$el || !$el.length) {\r\n return false;\r\n }\r\n\r\n domRect = $el[0].getBoundingClientRect();\r\n\r\n return {\r\n top: domRect.top || 0,\r\n left: domRect.left || 0,\r\n width: domRect.width,\r\n height: domRect.height,\r\n opacity: parseFloat($el.css(\"opacity\"))\r\n };\r\n },\r\n\r\n // Shortcut for setting \"translate3d\" properties for element\r\n // Can set be used to set opacity, too\r\n // ========================================================\r\n\r\n setTranslate: function ($el, props) {\r\n var str = \"\",\r\n css = {};\r\n\r\n if (!$el || !props) {\r\n return;\r\n }\r\n\r\n if (props.left !== undefined || props.top !== undefined) {\r\n str =\r\n (props.left === undefined ? $el.position().left : props.left) +\r\n \"px, \" +\r\n (props.top === undefined ? $el.position().top : props.top) +\r\n \"px\";\r\n\r\n if (this.use3d) {\r\n str = \"translate3d(\" + str + \", 0px)\";\r\n } else {\r\n str = \"translate(\" + str + \")\";\r\n }\r\n }\r\n\r\n if (props.scaleX !== undefined && props.scaleY !== undefined) {\r\n str += \" scale(\" + props.scaleX + \", \" + props.scaleY + \")\";\r\n } else if (props.scaleX !== undefined) {\r\n str += \" scaleX(\" + props.scaleX + \")\";\r\n }\r\n\r\n if (str.length) {\r\n css.transform = str;\r\n }\r\n\r\n if (props.opacity !== undefined) {\r\n css.opacity = props.opacity;\r\n }\r\n\r\n if (props.width !== undefined) {\r\n css.width = props.width;\r\n }\r\n\r\n if (props.height !== undefined) {\r\n css.height = props.height;\r\n }\r\n\r\n return $el.css(css);\r\n },\r\n\r\n // Simple CSS transition handler\r\n // =============================\r\n\r\n animate: function ($el, to, duration, callback, leaveAnimationName) {\r\n var self = this,\r\n from;\r\n\r\n if ($.isFunction(duration)) {\r\n callback = duration;\r\n duration = null;\r\n }\r\n\r\n self.stop($el);\r\n\r\n from = self.getTranslate($el);\r\n\r\n $el.on(transitionEnd, function (e) {\r\n // Skip events from child elements and z-index change\r\n if (e && e.originalEvent && (!$el.is(e.originalEvent.target) || e.originalEvent.propertyName == \"z-index\")) {\r\n return;\r\n }\r\n\r\n self.stop($el);\r\n\r\n if ($.isNumeric(duration)) {\r\n $el.css(\"transition-duration\", \"\");\r\n }\r\n\r\n if ($.isPlainObject(to)) {\r\n if (to.scaleX !== undefined && to.scaleY !== undefined) {\r\n self.setTranslate($el, {\r\n top: to.top,\r\n left: to.left,\r\n width: from.width * to.scaleX,\r\n height: from.height * to.scaleY,\r\n scaleX: 1,\r\n scaleY: 1\r\n });\r\n }\r\n } else if (leaveAnimationName !== true) {\r\n $el.removeClass(to);\r\n }\r\n\r\n if ($.isFunction(callback)) {\r\n callback(e);\r\n }\r\n });\r\n\r\n if ($.isNumeric(duration)) {\r\n $el.css(\"transition-duration\", duration + \"ms\");\r\n }\r\n\r\n // Start animation by changing CSS properties or class name\r\n if ($.isPlainObject(to)) {\r\n if (to.scaleX !== undefined && to.scaleY !== undefined) {\r\n delete to.width;\r\n delete to.height;\r\n\r\n if ($el.parent().hasClass(\"fancybox-slide--image\")) {\r\n $el.parent().addClass(\"fancybox-is-scaling\");\r\n }\r\n }\r\n\r\n $.fancybox.setTranslate($el, to);\r\n } else {\r\n $el.addClass(to);\r\n }\r\n\r\n // Make sure that `transitionend` callback gets fired\r\n $el.data(\r\n \"timer\",\r\n setTimeout(function () {\r\n $el.trigger(transitionEnd);\r\n }, duration + 33)\r\n );\r\n },\r\n\r\n stop: function ($el, callCallback) {\r\n if ($el && $el.length) {\r\n clearTimeout($el.data(\"timer\"));\r\n\r\n if (callCallback) {\r\n $el.trigger(transitionEnd);\r\n }\r\n\r\n $el.off(transitionEnd).css(\"transition-duration\", \"\");\r\n\r\n $el.parent().removeClass(\"fancybox-is-scaling\");\r\n }\r\n }\r\n };\r\n\r\n // Default click handler for \"fancyboxed\" links\r\n // ============================================\r\n\r\n function _run(e, opts) {\r\n var items = [],\r\n index = 0,\r\n $target,\r\n value,\r\n instance;\r\n\r\n // Avoid opening multiple times\r\n if (e && e.isDefaultPrevented()) {\r\n return;\r\n }\r\n\r\n e.preventDefault();\r\n\r\n opts = opts || {};\r\n\r\n if (e && e.data) {\r\n opts = mergeOpts(e.data.options, opts);\r\n }\r\n\r\n $target = opts.$target || $(e.currentTarget).trigger(\"blur\");\r\n instance = $.fancybox.getInstance();\r\n\r\n if (instance && instance.$trigger && instance.$trigger.is($target)) {\r\n return;\r\n }\r\n\r\n if (opts.selector) {\r\n items = $(opts.selector);\r\n } else {\r\n // Get all related items and find index for clicked one\r\n value = $target.attr(\"data-fancybox\") || \"\";\r\n\r\n if (value) {\r\n items = e.data ? e.data.items : [];\r\n items = items.length ? items.filter('[data-fancybox=\"' + value + '\"]') : $('[data-fancybox=\"' + value + '\"]');\r\n } else {\r\n items = [$target];\r\n }\r\n }\r\n\r\n index = $(items).index($target);\r\n\r\n // Sometimes current item can not be found\r\n if (index < 0) {\r\n index = 0;\r\n }\r\n\r\n instance = $.fancybox.open(items, opts, index);\r\n\r\n // Save last active element\r\n instance.$trigger = $target;\r\n }\r\n\r\n // Create a jQuery plugin\r\n // ======================\r\n\r\n $.fn.fancybox = function (options) {\r\n var selector;\r\n\r\n options = options || {};\r\n selector = options.selector || false;\r\n\r\n if (selector) {\r\n // Use body element instead of document so it executes first\r\n $(\"body\")\r\n .off(\"click.fb-start\", selector)\r\n .on(\"click.fb-start\", selector, {\r\n options: options\r\n }, _run);\r\n } else {\r\n this.off(\"click.fb-start\").on(\r\n \"click.fb-start\", {\r\n items: this,\r\n options: options\r\n },\r\n _run\r\n );\r\n }\r\n\r\n return this;\r\n };\r\n\r\n // Self initializing plugin for all elements having `data-fancybox` attribute\r\n // ==========================================================================\r\n\r\n $D.on(\"click.fb-start\", \"[data-fancybox]\", _run);\r\n\r\n // Enable \"trigger elements\"\r\n // =========================\r\n\r\n $D.on(\"click.fb-start\", \"[data-fancybox-trigger]\", function (e) {\r\n $('[data-fancybox=\"' + $(this).attr(\"data-fancybox-trigger\") + '\"]')\r\n .eq($(this).attr(\"data-fancybox-index\") || 0)\r\n .trigger(\"click.fb-start\", {\r\n $trigger: $(this)\r\n });\r\n });\r\n\r\n // Track focus event for better accessibility styling\r\n // ==================================================\r\n (function () {\r\n var buttonStr = \".fancybox-button\",\r\n focusStr = \"fancybox-focus\",\r\n $pressed = null;\r\n\r\n $D.on(\"mousedown mouseup focus blur\", buttonStr, function (e) {\r\n switch (e.type) {\r\n case \"mousedown\":\r\n $pressed = $(this);\r\n break;\r\n case \"mouseup\":\r\n $pressed = null;\r\n break;\r\n case \"focusin\":\r\n $(buttonStr).removeClass(focusStr);\r\n\r\n if (!$(this).is($pressed) && !$(this).is(\"[disabled]\")) {\r\n $(this).addClass(focusStr);\r\n }\r\n break;\r\n case \"focusout\":\r\n $(buttonStr).removeClass(focusStr);\r\n break;\r\n }\r\n });\r\n })();\r\n})(window, document, jQuery);\n// ==========================================================================\r\n//\r\n// Media\r\n// Adds additional media type support\r\n//\r\n// ==========================================================================\r\n(function ($) {\r\n \"use strict\";\r\n\r\n // Object containing properties for each media type\r\n var defaults = {\r\n youtube: {\r\n matcher: /(youtube\\.com|youtu\\.be|youtube\\-nocookie\\.com)\\/(watch\\?(.*&)?v=|v\\/|u\\/|embed\\/?)?(videoseries\\?list=(.*)|[\\w-]{11}|\\?listType=(.*)&list=(.*))(.*)/i,\r\n params: {\r\n autoplay: 1,\r\n autohide: 1,\r\n fs: 1,\r\n rel: 0,\r\n hd: 1,\r\n wmode: \"transparent\",\r\n enablejsapi: 1,\r\n html5: 1\r\n },\r\n paramPlace: 8,\r\n type: \"iframe\",\r\n url: \"https://www.youtube-nocookie.com/embed/$4\",\r\n thumb: \"https://img.youtube.com/vi/$4/hqdefault.jpg\"\r\n },\r\n\r\n vimeo: {\r\n matcher: /^.+vimeo.com\\/(.*\\/)?([\\d]+)(.*)?/,\r\n params: {\r\n autoplay: 1,\r\n hd: 1,\r\n show_title: 1,\r\n show_byline: 1,\r\n show_portrait: 0,\r\n fullscreen: 1\r\n },\r\n paramPlace: 3,\r\n type: \"iframe\",\r\n url: \"//player.vimeo.com/video/$2\"\r\n },\r\n\r\n instagram: {\r\n matcher: /(instagr\\.am|instagram\\.com)\\/p\\/([a-zA-Z0-9_\\-]+)\\/?/i,\r\n type: \"image\",\r\n url: \"//$1/p/$2/media/?size=l\"\r\n },\r\n\r\n // Examples:\r\n // http://maps.google.com/?ll=48.857995,2.294297&spn=0.007666,0.021136&t=m&z=16\r\n // https://www.google.com/maps/@37.7852006,-122.4146355,14.65z\r\n // https://www.google.com/maps/@52.2111123,2.9237542,6.61z?hl=en\r\n // https://www.google.com/maps/place/Googleplex/@37.4220041,-122.0833494,17z/data=!4m5!3m4!1s0x0:0x6c296c66619367e0!8m2!3d37.4219998!4d-122.0840572\r\n gmap_place: {\r\n matcher: /(maps\\.)?google\\.([a-z]{2,3}(\\.[a-z]{2})?)\\/(((maps\\/(place\\/(.*)\\/)?\\@(.*),(\\d+.?\\d+?)z))|(\\?ll=))(.*)?/i,\r\n type: \"iframe\",\r\n url: function (rez) {\r\n return (\r\n \"//maps.google.\" +\r\n rez[2] +\r\n \"/?ll=\" +\r\n (rez[9] ? rez[9] + \"&z=\" + Math.floor(rez[10]) + (rez[12] ? rez[12].replace(/^\\//, \"&\") : \"\") : rez[12] + \"\").replace(/\\?/, \"&\") +\r\n \"&output=\" +\r\n (rez[12] && rez[12].indexOf(\"layer=c\") > 0 ? \"svembed\" : \"embed\")\r\n );\r\n }\r\n },\r\n\r\n // Examples:\r\n // https://www.google.com/maps/search/Empire+State+Building/\r\n // https://www.google.com/maps/search/?api=1&query=centurylink+field\r\n // https://www.google.com/maps/search/?api=1&query=47.5951518,-122.3316393\r\n gmap_search: {\r\n matcher: /(maps\\.)?google\\.([a-z]{2,3}(\\.[a-z]{2})?)\\/(maps\\/search\\/)(.*)/i,\r\n type: \"iframe\",\r\n url: function (rez) {\r\n return \"//maps.google.\" + rez[2] + \"/maps?q=\" + rez[5].replace(\"query=\", \"q=\").replace(\"api=1\", \"\") + \"&output=embed\";\r\n }\r\n }\r\n };\r\n\r\n // Formats matching url to final form\r\n var format = function (url, rez, params) {\r\n if (!url) {\r\n return;\r\n }\r\n\r\n params = params || \"\";\r\n\r\n if ($.type(params) === \"object\") {\r\n params = $.param(params, true);\r\n }\r\n\r\n $.each(rez, function (key, value) {\r\n url = url.replace(\"$\" + key, value || \"\");\r\n });\r\n\r\n if (params.length) {\r\n url += (url.indexOf(\"?\") > 0 ? \"&\" : \"?\") + params;\r\n }\r\n\r\n return url;\r\n };\r\n\r\n $(document).on(\"objectNeedsType.fb\", function (e, instance, item) {\r\n var url = item.src || \"\",\r\n type = false,\r\n media,\r\n thumb,\r\n rez,\r\n params,\r\n urlParams,\r\n paramObj,\r\n provider;\r\n\r\n media = $.extend(true, {}, defaults, item.opts.media);\r\n\r\n // Look for any matching media type\r\n $.each(media, function (providerName, providerOpts) {\r\n rez = url.match(providerOpts.matcher);\r\n\r\n if (!rez) {\r\n return;\r\n }\r\n\r\n type = providerOpts.type;\r\n provider = providerName;\r\n paramObj = {};\r\n\r\n if (providerOpts.paramPlace && rez[providerOpts.paramPlace]) {\r\n urlParams = rez[providerOpts.paramPlace];\r\n\r\n if (urlParams[0] == \"?\") {\r\n urlParams = urlParams.substring(1);\r\n }\r\n\r\n urlParams = urlParams.split(\"&\");\r\n\r\n for (var m = 0; m < urlParams.length; ++m) {\r\n var p = urlParams[m].split(\"=\", 2);\r\n\r\n if (p.length == 2) {\r\n paramObj[p[0]] = decodeURIComponent(p[1].replace(/\\+/g, \" \"));\r\n }\r\n }\r\n }\r\n\r\n params = $.extend(true, {}, providerOpts.params, item.opts[providerName], paramObj);\r\n\r\n url =\r\n $.type(providerOpts.url) === \"function\" ? providerOpts.url.call(this, rez, params, item) : format(providerOpts.url, rez, params);\r\n\r\n thumb =\r\n $.type(providerOpts.thumb) === \"function\" ? providerOpts.thumb.call(this, rez, params, item) : format(providerOpts.thumb, rez);\r\n\r\n if (providerName === \"youtube\") {\r\n url = url.replace(/&t=((\\d+)m)?(\\d+)s/, function (match, p1, m, s) {\r\n return \"&start=\" + ((m ? parseInt(m, 10) * 60 : 0) + parseInt(s, 10));\r\n });\r\n } else if (providerName === \"vimeo\") {\r\n url = url.replace(\"&%23\", \"#\");\r\n }\r\n\r\n return false;\r\n });\r\n\r\n // If it is found, then change content type and update the url\r\n\r\n if (type) {\r\n if (!item.opts.thumb && !(item.opts.$thumb && item.opts.$thumb.length)) {\r\n item.opts.thumb = thumb;\r\n }\r\n\r\n if (type === \"iframe\") {\r\n item.opts = $.extend(true, item.opts, {\r\n iframe: {\r\n preload: false,\r\n attr: {\r\n scrolling: \"no\"\r\n }\r\n }\r\n });\r\n }\r\n\r\n $.extend(item, {\r\n type: type,\r\n src: url,\r\n origSrc: item.src,\r\n contentSource: provider,\r\n contentType: type === \"image\" ? \"image\" : provider == \"gmap_place\" || provider == \"gmap_search\" ? \"map\" : \"video\"\r\n });\r\n } else if (url) {\r\n item.type = item.opts.defaultType;\r\n }\r\n });\r\n\r\n // Load YouTube/Video API on request to detect when video finished playing\r\n var VideoAPILoader = {\r\n youtube: {\r\n src: \"https://www.youtube.com/iframe_api\",\r\n class: \"YT\",\r\n loading: false,\r\n loaded: false\r\n },\r\n\r\n vimeo: {\r\n src: \"https://player.vimeo.com/api/player.js\",\r\n class: \"Vimeo\",\r\n loading: false,\r\n loaded: false\r\n },\r\n\r\n load: function (vendor) {\r\n var _this = this,\r\n script;\r\n\r\n if (this[vendor].loaded) {\r\n setTimeout(function () {\r\n _this.done(vendor);\r\n });\r\n return;\r\n }\r\n\r\n if (this[vendor].loading) {\r\n return;\r\n }\r\n\r\n this[vendor].loading = true;\r\n\r\n script = document.createElement(\"script\");\r\n script.type = \"text/javascript\";\r\n script.src = this[vendor].src;\r\n\r\n if (vendor === \"youtube\") {\r\n window.onYouTubeIframeAPIReady = function () {\r\n _this[vendor].loaded = true;\r\n _this.done(vendor);\r\n };\r\n } else {\r\n script.onload = function () {\r\n _this[vendor].loaded = true;\r\n _this.done(vendor);\r\n };\r\n }\r\n\r\n document.body.appendChild(script);\r\n },\r\n done: function (vendor) {\r\n var instance, $el, player;\r\n\r\n if (vendor === \"youtube\") {\r\n delete window.onYouTubeIframeAPIReady;\r\n }\r\n\r\n instance = $.fancybox.getInstance();\r\n\r\n if (instance) {\r\n $el = instance.current.$content.find(\"iframe\");\r\n\r\n if (vendor === \"youtube\" && YT !== undefined && YT) {\r\n player = new YT.Player($el.attr(\"id\"), {\r\n events: {\r\n onStateChange: function (e) {\r\n if (e.data == 0) {\r\n instance.next();\r\n }\r\n }\r\n }\r\n });\r\n } else if (vendor === \"vimeo\" && Vimeo !== undefined && Vimeo) {\r\n player = new Vimeo.Player($el);\r\n\r\n player.on(\"ended\", function () {\r\n instance.next();\r\n });\r\n }\r\n }\r\n }\r\n };\r\n\r\n $(document).on({\r\n \"afterShow.fb\": function (e, instance, current) {\r\n if (instance.group.length > 1 && (current.contentSource === \"youtube\" || current.contentSource === \"vimeo\")) {\r\n VideoAPILoader.load(current.contentSource);\r\n }\r\n }\r\n });\r\n})(jQuery);\n// ==========================================================================\r\n//\r\n// Guestures\r\n// Adds touch guestures, handles click and tap events\r\n//\r\n// ==========================================================================\r\n(function (window, document, $) {\r\n \"use strict\";\r\n\r\n var requestAFrame = (function () {\r\n return (\r\n window.requestAnimationFrame ||\r\n window.webkitRequestAnimationFrame ||\r\n window.mozRequestAnimationFrame ||\r\n window.oRequestAnimationFrame ||\r\n // if all else fails, use setTimeout\r\n function (callback) {\r\n return window.setTimeout(callback, 1000 / 60);\r\n }\r\n );\r\n })();\r\n\r\n var cancelAFrame = (function () {\r\n return (\r\n window.cancelAnimationFrame ||\r\n window.webkitCancelAnimationFrame ||\r\n window.mozCancelAnimationFrame ||\r\n window.oCancelAnimationFrame ||\r\n function (id) {\r\n window.clearTimeout(id);\r\n }\r\n );\r\n })();\r\n\r\n var getPointerXY = function (e) {\r\n var result = [];\r\n\r\n e = e.originalEvent || e || window.e;\r\n e = e.touches && e.touches.length ? e.touches : e.changedTouches && e.changedTouches.length ? e.changedTouches : [e];\r\n\r\n for (var key in e) {\r\n if (e[key].pageX) {\r\n result.push({\r\n x: e[key].pageX,\r\n y: e[key].pageY\r\n });\r\n } else if (e[key].clientX) {\r\n result.push({\r\n x: e[key].clientX,\r\n y: e[key].clientY\r\n });\r\n }\r\n }\r\n\r\n return result;\r\n };\r\n\r\n var distance = function (point2, point1, what) {\r\n if (!point1 || !point2) {\r\n return 0;\r\n }\r\n\r\n if (what === \"x\") {\r\n return point2.x - point1.x;\r\n } else if (what === \"y\") {\r\n return point2.y - point1.y;\r\n }\r\n\r\n return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2));\r\n };\r\n\r\n var isClickable = function ($el) {\r\n if (\r\n $el.is('a,area,button,[role=\"button\"],input,label,select,summary,textarea,video,audio,iframe') ||\r\n $.isFunction($el.get(0).onclick) ||\r\n $el.data(\"selectable\")\r\n ) {\r\n return true;\r\n }\r\n\r\n // Check for attributes like data-fancybox-next or data-fancybox-close\r\n for (var i = 0, atts = $el[0].attributes, n = atts.length; i < n; i++) {\r\n if (atts[i].nodeName.substr(0, 14) === \"data-fancybox-\") {\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n };\r\n\r\n var hasScrollbars = function (el) {\r\n var overflowY = window.getComputedStyle(el)[\"overflow-y\"],\r\n overflowX = window.getComputedStyle(el)[\"overflow-x\"],\r\n vertical = (overflowY === \"scroll\" || overflowY === \"auto\") && el.scrollHeight > el.clientHeight,\r\n horizontal = (overflowX === \"scroll\" || overflowX === \"auto\") && el.scrollWidth > el.clientWidth;\r\n\r\n return vertical || horizontal;\r\n };\r\n\r\n var isScrollable = function ($el) {\r\n var rez = false;\r\n\r\n while (true) {\r\n rez = hasScrollbars($el.get(0));\r\n\r\n if (rez) {\r\n break;\r\n }\r\n\r\n $el = $el.parent();\r\n\r\n if (!$el.length || $el.hasClass(\"fancybox-stage\") || $el.is(\"body\")) {\r\n break;\r\n }\r\n }\r\n\r\n return rez;\r\n };\r\n\r\n var Guestures = function (instance) {\r\n var self = this;\r\n\r\n self.instance = instance;\r\n\r\n self.$bg = instance.$refs.bg;\r\n self.$stage = instance.$refs.stage;\r\n self.$container = instance.$refs.container;\r\n\r\n self.destroy();\r\n\r\n self.$container.on(\"touchstart.fb.touch mousedown.fb.touch\", $.proxy(self, \"ontouchstart\"));\r\n };\r\n\r\n Guestures.prototype.destroy = function () {\r\n var self = this;\r\n\r\n self.$container.off(\".fb.touch\");\r\n\r\n $(document).off(\".fb.touch\");\r\n\r\n if (self.requestId) {\r\n cancelAFrame(self.requestId);\r\n self.requestId = null;\r\n }\r\n\r\n if (self.tapped) {\r\n clearTimeout(self.tapped);\r\n self.tapped = null;\r\n }\r\n };\r\n\r\n Guestures.prototype.ontouchstart = function (e) {\r\n var self = this,\r\n $target = $(e.target),\r\n instance = self.instance,\r\n current = instance.current,\r\n $slide = current.$slide,\r\n $content = current.$content,\r\n isTouchDevice = e.type == \"touchstart\";\r\n\r\n // Do not respond to both (touch and mouse) events\r\n if (isTouchDevice) {\r\n self.$container.off(\"mousedown.fb.touch\");\r\n }\r\n\r\n // Ignore right click\r\n if (e.originalEvent && e.originalEvent.button == 2) {\r\n return;\r\n }\r\n\r\n // Ignore taping on links, buttons, input elements\r\n if (!$slide.length || !$target.length || isClickable($target) || isClickable($target.parent())) {\r\n return;\r\n }\r\n // Ignore clicks on the scrollbar\r\n if (!$target.is(\"img\") && e.originalEvent.clientX > $target[0].clientWidth + $target.offset().left) {\r\n return;\r\n }\r\n\r\n // Ignore clicks while zooming or closing\r\n if (!current || instance.isAnimating || current.$slide.hasClass(\"fancybox-animated\")) {\r\n e.stopPropagation();\r\n e.preventDefault();\r\n\r\n return;\r\n }\r\n\r\n self.realPoints = self.startPoints = getPointerXY(e);\r\n\r\n if (!self.startPoints.length) {\r\n return;\r\n }\r\n\r\n // Allow other scripts to catch touch event if \"touch\" is set to false\r\n if (current.touch) {\r\n e.stopPropagation();\r\n }\r\n\r\n self.startEvent = e;\r\n\r\n self.canTap = true;\r\n self.$target = $target;\r\n self.$content = $content;\r\n self.opts = current.opts.touch;\r\n\r\n self.isPanning = false;\r\n self.isSwiping = false;\r\n self.isZooming = false;\r\n self.isScrolling = false;\r\n self.canPan = instance.canPan();\r\n\r\n self.startTime = new Date().getTime();\r\n self.distanceX = self.distanceY = self.distance = 0;\r\n\r\n self.canvasWidth = Math.round($slide[0].clientWidth);\r\n self.canvasHeight = Math.round($slide[0].clientHeight);\r\n\r\n self.contentLastPos = null;\r\n self.contentStartPos = $.fancybox.getTranslate(self.$content) || {\r\n top: 0,\r\n left: 0\r\n };\r\n self.sliderStartPos = $.fancybox.getTranslate($slide);\r\n\r\n // Since position will be absolute, but we need to make it relative to the stage\r\n self.stagePos = $.fancybox.getTranslate(instance.$refs.stage);\r\n\r\n self.sliderStartPos.top -= self.stagePos.top;\r\n self.sliderStartPos.left -= self.stagePos.left;\r\n\r\n self.contentStartPos.top -= self.stagePos.top;\r\n self.contentStartPos.left -= self.stagePos.left;\r\n\r\n $(document)\r\n .off(\".fb.touch\")\r\n .on(isTouchDevice ? \"touchend.fb.touch touchcancel.fb.touch\" : \"mouseup.fb.touch mouseleave.fb.touch\", $.proxy(self, \"ontouchend\"))\r\n .on(isTouchDevice ? \"touchmove.fb.touch\" : \"mousemove.fb.touch\", $.proxy(self, \"ontouchmove\"));\r\n\r\n if ($.fancybox.isMobile) {\r\n document.addEventListener(\"scroll\", self.onscroll, true);\r\n }\r\n\r\n // Skip if clicked outside the sliding area\r\n if (!(self.opts || self.canPan) || !($target.is(self.$stage) || self.$stage.find($target).length)) {\r\n if ($target.is(\".fancybox-image\")) {\r\n e.preventDefault();\r\n }\r\n\r\n if (!($.fancybox.isMobile && $target.parents(\".fancybox-caption\").length)) {\r\n return;\r\n }\r\n }\r\n\r\n self.isScrollable = isScrollable($target) || isScrollable($target.parent());\r\n\r\n // Check if element is scrollable and try to prevent default behavior (scrolling)\r\n if (!($.fancybox.isMobile && self.isScrollable)) {\r\n e.preventDefault();\r\n }\r\n\r\n // One finger or mouse click - swipe or pan an image\r\n if (self.startPoints.length === 1 || current.hasError) {\r\n if (self.canPan) {\r\n $.fancybox.stop(self.$content);\r\n\r\n self.isPanning = true;\r\n } else {\r\n self.isSwiping = true;\r\n }\r\n\r\n self.$container.addClass(\"fancybox-is-grabbing\");\r\n }\r\n\r\n // Two fingers - zoom image\r\n if (self.startPoints.length === 2 && current.type === \"image\" && (current.isLoaded || current.$ghost)) {\r\n self.canTap = false;\r\n self.isSwiping = false;\r\n self.isPanning = false;\r\n\r\n self.isZooming = true;\r\n\r\n $.fancybox.stop(self.$content);\r\n\r\n self.centerPointStartX = (self.startPoints[0].x + self.startPoints[1].x) * 0.5 - $(window).scrollLeft();\r\n self.centerPointStartY = (self.startPoints[0].y + self.startPoints[1].y) * 0.5 - $(window).scrollTop();\r\n\r\n self.percentageOfImageAtPinchPointX = (self.centerPointStartX - self.contentStartPos.left) / self.contentStartPos.width;\r\n self.percentageOfImageAtPinchPointY = (self.centerPointStartY - self.contentStartPos.top) / self.contentStartPos.height;\r\n\r\n self.startDistanceBetweenFingers = distance(self.startPoints[0], self.startPoints[1]);\r\n }\r\n };\r\n\r\n Guestures.prototype.onscroll = function (e) {\r\n var self = this;\r\n\r\n self.isScrolling = true;\r\n\r\n document.removeEventListener(\"scroll\", self.onscroll, true);\r\n };\r\n\r\n Guestures.prototype.ontouchmove = function (e) {\r\n var self = this;\r\n\r\n // Make sure user has not released over iframe or disabled element\r\n if (e.originalEvent.buttons !== undefined && e.originalEvent.buttons === 0) {\r\n self.ontouchend(e);\r\n return;\r\n }\r\n\r\n if (self.isScrolling) {\r\n self.canTap = false;\r\n return;\r\n }\r\n\r\n self.newPoints = getPointerXY(e);\r\n\r\n if (!(self.opts || self.canPan) || !self.newPoints.length || !self.newPoints.length) {\r\n return;\r\n }\r\n\r\n if (!(self.isSwiping && self.isSwiping === true)) {\r\n e.preventDefault();\r\n }\r\n\r\n self.distanceX = distance(self.newPoints[0], self.startPoints[0], \"x\");\r\n self.distanceY = distance(self.newPoints[0], self.startPoints[0], \"y\");\r\n\r\n self.distance = distance(self.newPoints[0], self.startPoints[0]);\r\n\r\n // Skip false ontouchmove events (Chrome)\r\n if (self.distance > 0) {\r\n if (self.isSwiping) {\r\n self.onSwipe(e);\r\n } else if (self.isPanning) {\r\n self.onPan();\r\n } else if (self.isZooming) {\r\n self.onZoom();\r\n }\r\n }\r\n };\r\n\r\n Guestures.prototype.onSwipe = function (e) {\r\n var self = this,\r\n instance = self.instance,\r\n swiping = self.isSwiping,\r\n left = self.sliderStartPos.left || 0,\r\n angle;\r\n\r\n // If direction is not yet determined\r\n if (swiping === true) {\r\n // We need at least 10px distance to correctly calculate an angle\r\n if (Math.abs(self.distance) > 10) {\r\n self.canTap = false;\r\n\r\n if (instance.group.length < 2 && self.opts.vertical) {\r\n self.isSwiping = \"y\";\r\n } else if (instance.isDragging || self.opts.vertical === false || (self.opts.vertical === \"auto\" && $(window).width() > 800)) {\r\n self.isSwiping = \"x\";\r\n } else {\r\n angle = Math.abs((Math.atan2(self.distanceY, self.distanceX) * 180) / Math.PI);\r\n\r\n self.isSwiping = angle > 45 && angle < 135 ? \"y\" : \"x\";\r\n }\r\n\r\n if (self.isSwiping === \"y\" && $.fancybox.isMobile && self.isScrollable) {\r\n self.isScrolling = true;\r\n\r\n return;\r\n }\r\n\r\n instance.isDragging = self.isSwiping;\r\n\r\n // Reset points to avoid jumping, because we dropped first swipes to calculate the angle\r\n self.startPoints = self.newPoints;\r\n\r\n $.each(instance.slides, function (index, slide) {\r\n var slidePos, stagePos;\r\n\r\n $.fancybox.stop(slide.$slide);\r\n\r\n slidePos = $.fancybox.getTranslate(slide.$slide);\r\n stagePos = $.fancybox.getTranslate(instance.$refs.stage);\r\n\r\n slide.$slide\r\n .css({\r\n transform: \"\",\r\n opacity: \"\",\r\n \"transition-duration\": \"\"\r\n })\r\n .removeClass(\"fancybox-animated\")\r\n .removeClass(function (index, className) {\r\n return (className.match(/(^|\\s)fancybox-fx-\\S+/g) || []).join(\" \");\r\n });\r\n\r\n if (slide.pos === instance.current.pos) {\r\n self.sliderStartPos.top = slidePos.top - stagePos.top;\r\n self.sliderStartPos.left = slidePos.left - stagePos.left;\r\n }\r\n\r\n $.fancybox.setTranslate(slide.$slide, {\r\n top: slidePos.top - stagePos.top,\r\n left: slidePos.left - stagePos.left\r\n });\r\n });\r\n\r\n // Stop slideshow\r\n if (instance.SlideShow && instance.SlideShow.isActive) {\r\n instance.SlideShow.stop();\r\n }\r\n }\r\n\r\n return;\r\n }\r\n\r\n // Sticky edges\r\n if (swiping == \"x\") {\r\n if (\r\n self.distanceX > 0 &&\r\n (self.instance.group.length < 2 || (self.instance.current.index === 0 && !self.instance.current.opts.loop))\r\n ) {\r\n left = left + Math.pow(self.distanceX, 0.8);\r\n } else if (\r\n self.distanceX < 0 &&\r\n (self.instance.group.length < 2 ||\r\n (self.instance.current.index === self.instance.group.length - 1 && !self.instance.current.opts.loop))\r\n ) {\r\n left = left - Math.pow(-self.distanceX, 0.8);\r\n } else {\r\n left = left + self.distanceX;\r\n }\r\n }\r\n\r\n self.sliderLastPos = {\r\n top: swiping == \"x\" ? 0 : self.sliderStartPos.top + self.distanceY,\r\n left: left\r\n };\r\n\r\n if (self.requestId) {\r\n cancelAFrame(self.requestId);\r\n\r\n self.requestId = null;\r\n }\r\n\r\n self.requestId = requestAFrame(function () {\r\n if (self.sliderLastPos) {\r\n $.each(self.instance.slides, function (index, slide) {\r\n var pos = slide.pos - self.instance.currPos;\r\n\r\n $.fancybox.setTranslate(slide.$slide, {\r\n top: self.sliderLastPos.top,\r\n left: self.sliderLastPos.left + pos * self.canvasWidth + pos * slide.opts.gutter\r\n });\r\n });\r\n\r\n self.$container.addClass(\"fancybox-is-sliding\");\r\n }\r\n });\r\n };\r\n\r\n Guestures.prototype.onPan = function () {\r\n var self = this;\r\n\r\n // Prevent accidental movement (sometimes, when tapping casually, finger can move a bit)\r\n if (distance(self.newPoints[0], self.realPoints[0]) < ($.fancybox.isMobile ? 10 : 5)) {\r\n self.startPoints = self.newPoints;\r\n return;\r\n }\r\n\r\n self.canTap = false;\r\n\r\n self.contentLastPos = self.limitMovement();\r\n\r\n if (self.requestId) {\r\n cancelAFrame(self.requestId);\r\n }\r\n\r\n self.requestId = requestAFrame(function () {\r\n $.fancybox.setTranslate(self.$content, self.contentLastPos);\r\n });\r\n };\r\n\r\n // Make panning sticky to the edges\r\n Guestures.prototype.limitMovement = function () {\r\n var self = this;\r\n\r\n var canvasWidth = self.canvasWidth;\r\n var canvasHeight = self.canvasHeight;\r\n\r\n var distanceX = self.distanceX;\r\n var distanceY = self.distanceY;\r\n\r\n var contentStartPos = self.contentStartPos;\r\n\r\n var currentOffsetX = contentStartPos.left;\r\n var currentOffsetY = contentStartPos.top;\r\n\r\n var currentWidth = contentStartPos.width;\r\n var currentHeight = contentStartPos.height;\r\n\r\n var minTranslateX, minTranslateY, maxTranslateX, maxTranslateY, newOffsetX, newOffsetY;\r\n\r\n if (currentWidth > canvasWidth) {\r\n newOffsetX = currentOffsetX + distanceX;\r\n } else {\r\n newOffsetX = currentOffsetX;\r\n }\r\n\r\n newOffsetY = currentOffsetY + distanceY;\r\n\r\n // Slow down proportionally to traveled distance\r\n minTranslateX = Math.max(0, canvasWidth * 0.5 - currentWidth * 0.5);\r\n minTranslateY = Math.max(0, canvasHeight * 0.5 - currentHeight * 0.5);\r\n\r\n maxTranslateX = Math.min(canvasWidth - currentWidth, canvasWidth * 0.5 - currentWidth * 0.5);\r\n maxTranslateY = Math.min(canvasHeight - currentHeight, canvasHeight * 0.5 - currentHeight * 0.5);\r\n\r\n // ->\r\n if (distanceX > 0 && newOffsetX > minTranslateX) {\r\n newOffsetX = minTranslateX - 1 + Math.pow(-minTranslateX + currentOffsetX + distanceX, 0.8) || 0;\r\n }\r\n\r\n // <-\r\n if (distanceX < 0 && newOffsetX < maxTranslateX) {\r\n newOffsetX = maxTranslateX + 1 - Math.pow(maxTranslateX - currentOffsetX - distanceX, 0.8) || 0;\r\n }\r\n\r\n // \\/\r\n if (distanceY > 0 && newOffsetY > minTranslateY) {\r\n newOffsetY = minTranslateY - 1 + Math.pow(-minTranslateY + currentOffsetY + distanceY, 0.8) || 0;\r\n }\r\n\r\n // /\\\r\n if (distanceY < 0 && newOffsetY < maxTranslateY) {\r\n newOffsetY = maxTranslateY + 1 - Math.pow(maxTranslateY - currentOffsetY - distanceY, 0.8) || 0;\r\n }\r\n\r\n return {\r\n top: newOffsetY,\r\n left: newOffsetX\r\n };\r\n };\r\n\r\n Guestures.prototype.limitPosition = function (newOffsetX, newOffsetY, newWidth, newHeight) {\r\n var self = this;\r\n\r\n var canvasWidth = self.canvasWidth;\r\n var canvasHeight = self.canvasHeight;\r\n\r\n if (newWidth > canvasWidth) {\r\n newOffsetX = newOffsetX > 0 ? 0 : newOffsetX;\r\n newOffsetX = newOffsetX < canvasWidth - newWidth ? canvasWidth - newWidth : newOffsetX;\r\n } else {\r\n // Center horizontally\r\n newOffsetX = Math.max(0, canvasWidth / 2 - newWidth / 2);\r\n }\r\n\r\n if (newHeight > canvasHeight) {\r\n newOffsetY = newOffsetY > 0 ? 0 : newOffsetY;\r\n newOffsetY = newOffsetY < canvasHeight - newHeight ? canvasHeight - newHeight : newOffsetY;\r\n } else {\r\n // Center vertically\r\n newOffsetY = Math.max(0, canvasHeight / 2 - newHeight / 2);\r\n }\r\n\r\n return {\r\n top: newOffsetY,\r\n left: newOffsetX\r\n };\r\n };\r\n\r\n Guestures.prototype.onZoom = function () {\r\n var self = this;\r\n\r\n // Calculate current distance between points to get pinch ratio and new width and height\r\n var contentStartPos = self.contentStartPos;\r\n\r\n var currentWidth = contentStartPos.width;\r\n var currentHeight = contentStartPos.height;\r\n\r\n var currentOffsetX = contentStartPos.left;\r\n var currentOffsetY = contentStartPos.top;\r\n\r\n var endDistanceBetweenFingers = distance(self.newPoints[0], self.newPoints[1]);\r\n\r\n var pinchRatio = endDistanceBetweenFingers / self.startDistanceBetweenFingers;\r\n\r\n var newWidth = Math.floor(currentWidth * pinchRatio);\r\n var newHeight = Math.floor(currentHeight * pinchRatio);\r\n\r\n // This is the translation due to pinch-zooming\r\n var translateFromZoomingX = (currentWidth - newWidth) * self.percentageOfImageAtPinchPointX;\r\n var translateFromZoomingY = (currentHeight - newHeight) * self.percentageOfImageAtPinchPointY;\r\n\r\n // Point between the two touches\r\n var centerPointEndX = (self.newPoints[0].x + self.newPoints[1].x) / 2 - $(window).scrollLeft();\r\n var centerPointEndY = (self.newPoints[0].y + self.newPoints[1].y) / 2 - $(window).scrollTop();\r\n\r\n // And this is the translation due to translation of the centerpoint\r\n // between the two fingers\r\n var translateFromTranslatingX = centerPointEndX - self.centerPointStartX;\r\n var translateFromTranslatingY = centerPointEndY - self.centerPointStartY;\r\n\r\n // The new offset is the old/current one plus the total translation\r\n var newOffsetX = currentOffsetX + (translateFromZoomingX + translateFromTranslatingX);\r\n var newOffsetY = currentOffsetY + (translateFromZoomingY + translateFromTranslatingY);\r\n\r\n var newPos = {\r\n top: newOffsetY,\r\n left: newOffsetX,\r\n scaleX: pinchRatio,\r\n scaleY: pinchRatio\r\n };\r\n\r\n self.canTap = false;\r\n\r\n self.newWidth = newWidth;\r\n self.newHeight = newHeight;\r\n\r\n self.contentLastPos = newPos;\r\n\r\n if (self.requestId) {\r\n cancelAFrame(self.requestId);\r\n }\r\n\r\n self.requestId = requestAFrame(function () {\r\n $.fancybox.setTranslate(self.$content, self.contentLastPos);\r\n });\r\n };\r\n\r\n Guestures.prototype.ontouchend = function (e) {\r\n var self = this;\r\n\r\n var swiping = self.isSwiping;\r\n var panning = self.isPanning;\r\n var zooming = self.isZooming;\r\n var scrolling = self.isScrolling;\r\n\r\n self.endPoints = getPointerXY(e);\r\n self.dMs = Math.max(new Date().getTime() - self.startTime, 1);\r\n\r\n self.$container.removeClass(\"fancybox-is-grabbing\");\r\n\r\n $(document).off(\".fb.touch\");\r\n\r\n document.removeEventListener(\"scroll\", self.onscroll, true);\r\n\r\n if (self.requestId) {\r\n cancelAFrame(self.requestId);\r\n\r\n self.requestId = null;\r\n }\r\n\r\n self.isSwiping = false;\r\n self.isPanning = false;\r\n self.isZooming = false;\r\n self.isScrolling = false;\r\n\r\n self.instance.isDragging = false;\r\n\r\n if (self.canTap) {\r\n return self.onTap(e);\r\n }\r\n\r\n self.speed = 100;\r\n\r\n // Speed in px/ms\r\n self.velocityX = (self.distanceX / self.dMs) * 0.5;\r\n self.velocityY = (self.distanceY / self.dMs) * 0.5;\r\n\r\n if (panning) {\r\n self.endPanning();\r\n } else if (zooming) {\r\n self.endZooming();\r\n } else {\r\n self.endSwiping(swiping, scrolling);\r\n }\r\n\r\n return;\r\n };\r\n\r\n Guestures.prototype.endSwiping = function (swiping, scrolling) {\r\n var self = this,\r\n ret = false,\r\n len = self.instance.group.length,\r\n distanceX = Math.abs(self.distanceX),\r\n canAdvance = swiping == \"x\" && len > 1 && ((self.dMs > 130 && distanceX > 10) || distanceX > 50),\r\n speedX = 300;\r\n\r\n self.sliderLastPos = null;\r\n\r\n // Close if swiped vertically / navigate if horizontally\r\n if (swiping == \"y\" && !scrolling && Math.abs(self.distanceY) > 50) {\r\n // Continue vertical movement\r\n $.fancybox.animate(\r\n self.instance.current.$slide, {\r\n top: self.sliderStartPos.top + self.distanceY + self.velocityY * 150,\r\n opacity: 0\r\n },\r\n 200\r\n );\r\n ret = self.instance.close(true, 250);\r\n } else if (canAdvance && self.distanceX > 0) {\r\n ret = self.instance.previous(speedX);\r\n } else if (canAdvance && self.distanceX < 0) {\r\n ret = self.instance.next(speedX);\r\n }\r\n\r\n if (ret === false && (swiping == \"x\" || swiping == \"y\")) {\r\n self.instance.centerSlide(200);\r\n }\r\n\r\n self.$container.removeClass(\"fancybox-is-sliding\");\r\n };\r\n\r\n // Limit panning from edges\r\n // ========================\r\n Guestures.prototype.endPanning = function () {\r\n var self = this,\r\n newOffsetX,\r\n newOffsetY,\r\n newPos;\r\n\r\n if (!self.contentLastPos) {\r\n return;\r\n }\r\n\r\n if (self.opts.momentum === false || self.dMs > 350) {\r\n newOffsetX = self.contentLastPos.left;\r\n newOffsetY = self.contentLastPos.top;\r\n } else {\r\n // Continue movement\r\n newOffsetX = self.contentLastPos.left + self.velocityX * 500;\r\n newOffsetY = self.contentLastPos.top + self.velocityY * 500;\r\n }\r\n\r\n newPos = self.limitPosition(newOffsetX, newOffsetY, self.contentStartPos.width, self.contentStartPos.height);\r\n\r\n newPos.width = self.contentStartPos.width;\r\n newPos.height = self.contentStartPos.height;\r\n\r\n $.fancybox.animate(self.$content, newPos, 366);\r\n };\r\n\r\n Guestures.prototype.endZooming = function () {\r\n var self = this;\r\n\r\n var current = self.instance.current;\r\n\r\n var newOffsetX, newOffsetY, newPos, reset;\r\n\r\n var newWidth = self.newWidth;\r\n var newHeight = self.newHeight;\r\n\r\n if (!self.contentLastPos) {\r\n return;\r\n }\r\n\r\n newOffsetX = self.contentLastPos.left;\r\n newOffsetY = self.contentLastPos.top;\r\n\r\n reset = {\r\n top: newOffsetY,\r\n left: newOffsetX,\r\n width: newWidth,\r\n height: newHeight,\r\n scaleX: 1,\r\n scaleY: 1\r\n };\r\n\r\n // Reset scalex/scaleY values; this helps for perfomance and does not break animation\r\n $.fancybox.setTranslate(self.$content, reset);\r\n\r\n if (newWidth < self.canvasWidth && newHeight < self.canvasHeight) {\r\n self.instance.scaleToFit(150);\r\n } else if (newWidth > current.width || newHeight > current.height) {\r\n self.instance.scaleToActual(self.centerPointStartX, self.centerPointStartY, 150);\r\n } else {\r\n newPos = self.limitPosition(newOffsetX, newOffsetY, newWidth, newHeight);\r\n\r\n $.fancybox.animate(self.$content, newPos, 150);\r\n }\r\n };\r\n\r\n Guestures.prototype.onTap = function (e) {\r\n var self = this;\r\n var $target = $(e.target);\r\n\r\n var instance = self.instance;\r\n var current = instance.current;\r\n\r\n var endPoints = (e && getPointerXY(e)) || self.startPoints;\r\n\r\n var tapX = endPoints[0] ? endPoints[0].x - $(window).scrollLeft() - self.stagePos.left : 0;\r\n var tapY = endPoints[0] ? endPoints[0].y - $(window).scrollTop() - self.stagePos.top : 0;\r\n\r\n var where;\r\n\r\n var process = function (prefix) {\r\n var action = current.opts[prefix];\r\n\r\n if ($.isFunction(action)) {\r\n action = action.apply(instance, [current, e]);\r\n }\r\n\r\n if (!action) {\r\n return;\r\n }\r\n\r\n switch (action) {\r\n case \"close\":\r\n instance.close(self.startEvent);\r\n\r\n break;\r\n\r\n case \"toggleControls\":\r\n instance.toggleControls();\r\n\r\n break;\r\n\r\n case \"next\":\r\n instance.next();\r\n\r\n break;\r\n\r\n case \"nextOrClose\":\r\n if (instance.group.length > 1) {\r\n instance.next();\r\n } else {\r\n instance.close(self.startEvent);\r\n }\r\n\r\n break;\r\n\r\n case \"zoom\":\r\n if (current.type == \"image\" && (current.isLoaded || current.$ghost)) {\r\n if (instance.canPan()) {\r\n instance.scaleToFit();\r\n } else if (instance.isScaledDown()) {\r\n instance.scaleToActual(tapX, tapY);\r\n } else if (instance.group.length < 2) {\r\n instance.close(self.startEvent);\r\n }\r\n }\r\n\r\n break;\r\n }\r\n };\r\n\r\n // Ignore right click\r\n if (e.originalEvent && e.originalEvent.button == 2) {\r\n return;\r\n }\r\n\r\n // Skip if clicked on the scrollbar\r\n if (!$target.is(\"img\") && tapX > $target[0].clientWidth + $target.offset().left) {\r\n return;\r\n }\r\n\r\n // Check where is clicked\r\n if ($target.is(\".fancybox-bg,.fancybox-inner,.fancybox-outer,.fancybox-container\")) {\r\n where = \"Outside\";\r\n } else if ($target.is(\".fancybox-slide\")) {\r\n where = \"Slide\";\r\n } else if (\r\n instance.current.$content &&\r\n instance.current.$content\r\n .find($target)\r\n .addBack()\r\n .filter($target).length\r\n ) {\r\n where = \"Content\";\r\n } else {\r\n return;\r\n }\r\n\r\n // Check if this is a double tap\r\n if (self.tapped) {\r\n // Stop previously created single tap\r\n clearTimeout(self.tapped);\r\n self.tapped = null;\r\n\r\n // Skip if distance between taps is too big\r\n if (Math.abs(tapX - self.tapX) > 50 || Math.abs(tapY - self.tapY) > 50) {\r\n return this;\r\n }\r\n\r\n // OK, now we assume that this is a double-tap\r\n process(\"dblclick\" + where);\r\n } else {\r\n // Single tap will be processed if user has not clicked second time within 300ms\r\n // or there is no need to wait for double-tap\r\n self.tapX = tapX;\r\n self.tapY = tapY;\r\n\r\n if (current.opts[\"dblclick\" + where] && current.opts[\"dblclick\" + where] !== current.opts[\"click\" + where]) {\r\n self.tapped = setTimeout(function () {\r\n self.tapped = null;\r\n\r\n if (!instance.isAnimating) {\r\n process(\"click\" + where);\r\n }\r\n }, 500);\r\n } else {\r\n process(\"click\" + where);\r\n }\r\n }\r\n\r\n return this;\r\n };\r\n\r\n $(document)\r\n .on(\"onActivate.fb\", function (e, instance) {\r\n if (instance && !instance.Guestures) {\r\n instance.Guestures = new Guestures(instance);\r\n }\r\n })\r\n .on(\"beforeClose.fb\", function (e, instance) {\r\n if (instance && instance.Guestures) {\r\n instance.Guestures.destroy();\r\n }\r\n });\r\n})(window, document, jQuery);\n// ==========================================================================\r\n//\r\n// SlideShow\r\n// Enables slideshow functionality\r\n//\r\n// Example of usage:\r\n// $.fancybox.getInstance().SlideShow.start()\r\n//\r\n// ==========================================================================\r\n(function (document, $) {\r\n \"use strict\";\r\n\r\n $.extend(true, $.fancybox.defaults, {\r\n btnTpl: {\r\n slideShow: '\"\r\n },\r\n slideShow: {\r\n autoStart: false,\r\n speed: 3000,\r\n progress: true\r\n }\r\n });\r\n\r\n var SlideShow = function (instance) {\r\n this.instance = instance;\r\n this.init();\r\n };\r\n\r\n $.extend(SlideShow.prototype, {\r\n timer: null,\r\n isActive: false,\r\n $button: null,\r\n\r\n init: function () {\r\n var self = this,\r\n instance = self.instance,\r\n opts = instance.group[instance.currIndex].opts.slideShow;\r\n\r\n self.$button = instance.$refs.toolbar.find(\"[data-fancybox-play]\").on(\"click\", function () {\r\n self.toggle();\r\n });\r\n\r\n if (instance.group.length < 2 || !opts) {\r\n self.$button.hide();\r\n } else if (opts.progress) {\r\n self.$progress = $('
').appendTo(instance.$refs.inner);\r\n }\r\n },\r\n\r\n set: function (force) {\r\n var self = this,\r\n instance = self.instance,\r\n current = instance.current;\r\n\r\n // Check if reached last element\r\n if (current && (force === true || current.opts.loop || instance.currIndex < instance.group.length - 1)) {\r\n if (self.isActive && current.contentType !== \"video\") {\r\n if (self.$progress) {\r\n $.fancybox.animate(self.$progress.show(), {\r\n scaleX: 1\r\n }, current.opts.slideShow.speed);\r\n }\r\n\r\n self.timer = setTimeout(function () {\r\n if (!instance.current.opts.loop && instance.current.index == instance.group.length - 1) {\r\n instance.jumpTo(0);\r\n } else {\r\n instance.next();\r\n }\r\n }, current.opts.slideShow.speed);\r\n }\r\n } else {\r\n self.stop();\r\n instance.idleSecondsCounter = 0;\r\n instance.showControls();\r\n }\r\n },\r\n\r\n clear: function () {\r\n var self = this;\r\n\r\n clearTimeout(self.timer);\r\n\r\n self.timer = null;\r\n\r\n if (self.$progress) {\r\n self.$progress.removeAttr(\"style\").hide();\r\n }\r\n },\r\n\r\n start: function () {\r\n var self = this,\r\n current = self.instance.current;\r\n\r\n if (current) {\r\n self.$button\r\n .attr(\"title\", (current.opts.i18n[current.opts.lang] || current.opts.i18n.en).PLAY_STOP)\r\n .removeClass(\"fancybox-button--play\")\r\n .addClass(\"fancybox-button--pause\");\r\n\r\n self.isActive = true;\r\n\r\n if (current.isComplete) {\r\n self.set(true);\r\n }\r\n\r\n self.instance.trigger(\"onSlideShowChange\", true);\r\n }\r\n },\r\n\r\n stop: function () {\r\n var self = this,\r\n current = self.instance.current;\r\n\r\n self.clear();\r\n\r\n self.$button\r\n .attr(\"title\", (current.opts.i18n[current.opts.lang] || current.opts.i18n.en).PLAY_START)\r\n .removeClass(\"fancybox-button--pause\")\r\n .addClass(\"fancybox-button--play\");\r\n\r\n self.isActive = false;\r\n\r\n self.instance.trigger(\"onSlideShowChange\", false);\r\n\r\n if (self.$progress) {\r\n self.$progress.removeAttr(\"style\").hide();\r\n }\r\n },\r\n\r\n toggle: function () {\r\n var self = this;\r\n\r\n if (self.isActive) {\r\n self.stop();\r\n } else {\r\n self.start();\r\n }\r\n }\r\n });\r\n\r\n $(document).on({\r\n \"onInit.fb\": function (e, instance) {\r\n if (instance && !instance.SlideShow) {\r\n instance.SlideShow = new SlideShow(instance);\r\n }\r\n },\r\n\r\n \"beforeShow.fb\": function (e, instance, current, firstRun) {\r\n var SlideShow = instance && instance.SlideShow;\r\n\r\n if (firstRun) {\r\n if (SlideShow && current.opts.slideShow.autoStart) {\r\n SlideShow.start();\r\n }\r\n } else if (SlideShow && SlideShow.isActive) {\r\n SlideShow.clear();\r\n }\r\n },\r\n\r\n \"afterShow.fb\": function (e, instance, current) {\r\n var SlideShow = instance && instance.SlideShow;\r\n\r\n if (SlideShow && SlideShow.isActive) {\r\n SlideShow.set();\r\n }\r\n },\r\n\r\n \"afterKeydown.fb\": function (e, instance, current, keypress, keycode) {\r\n var SlideShow = instance && instance.SlideShow;\r\n\r\n // \"P\" or Spacebar\r\n if (SlideShow && current.opts.slideShow && (keycode === 80 || keycode === 32) && !$(document.activeElement).is(\"button,a,input\")) {\r\n keypress.preventDefault();\r\n\r\n SlideShow.toggle();\r\n }\r\n },\r\n\r\n \"beforeClose.fb onDeactivate.fb\": function (e, instance) {\r\n var SlideShow = instance && instance.SlideShow;\r\n\r\n if (SlideShow) {\r\n SlideShow.stop();\r\n }\r\n }\r\n });\r\n\r\n // Page Visibility API to pause slideshow when window is not active\r\n $(document).on(\"visibilitychange\", function () {\r\n var instance = $.fancybox.getInstance(),\r\n SlideShow = instance && instance.SlideShow;\r\n\r\n if (SlideShow && SlideShow.isActive) {\r\n if (document.hidden) {\r\n SlideShow.clear();\r\n } else {\r\n SlideShow.set();\r\n }\r\n }\r\n });\r\n})(document, jQuery);\n// ==========================================================================\r\n//\r\n// FullScreen\r\n// Adds fullscreen functionality\r\n//\r\n// ==========================================================================\r\n(function (document, $) {\r\n \"use strict\";\r\n\r\n // Collection of methods supported by user browser\r\n var fn = (function () {\r\n var fnMap = [\r\n [\"requestFullscreen\", \"exitFullscreen\", \"fullscreenElement\", \"fullscreenEnabled\", \"fullscreenchange\", \"fullscreenerror\"],\r\n // new WebKit\r\n [\r\n \"webkitRequestFullscreen\",\r\n \"webkitExitFullscreen\",\r\n \"webkitFullscreenElement\",\r\n \"webkitFullscreenEnabled\",\r\n \"webkitfullscreenchange\",\r\n \"webkitfullscreenerror\"\r\n ],\r\n // old WebKit (Safari 5.1)\r\n [\r\n \"webkitRequestFullScreen\",\r\n \"webkitCancelFullScreen\",\r\n \"webkitCurrentFullScreenElement\",\r\n \"webkitCancelFullScreen\",\r\n \"webkitfullscreenchange\",\r\n \"webkitfullscreenerror\"\r\n ],\r\n [\r\n \"mozRequestFullScreen\",\r\n \"mozCancelFullScreen\",\r\n \"mozFullScreenElement\",\r\n \"mozFullScreenEnabled\",\r\n \"mozfullscreenchange\",\r\n \"mozfullscreenerror\"\r\n ],\r\n [\"msRequestFullscreen\", \"msExitFullscreen\", \"msFullscreenElement\", \"msFullscreenEnabled\", \"MSFullscreenChange\", \"MSFullscreenError\"]\r\n ];\r\n\r\n var ret = {};\r\n\r\n for (var i = 0; i < fnMap.length; i++) {\r\n var val = fnMap[i];\r\n\r\n if (val && val[1] in document) {\r\n for (var j = 0; j < val.length; j++) {\r\n ret[fnMap[0][j]] = val[j];\r\n }\r\n\r\n return ret;\r\n }\r\n }\r\n\r\n return false;\r\n })();\r\n\r\n if (fn) {\r\n var FullScreen = {\r\n request: function (elem) {\r\n elem = elem || document.documentElement;\r\n\r\n elem[fn.requestFullscreen](elem.ALLOW_KEYBOARD_INPUT);\r\n },\r\n exit: function () {\r\n document[fn.exitFullscreen]();\r\n },\r\n toggle: function (elem) {\r\n elem = elem || document.documentElement;\r\n\r\n if (this.isFullscreen()) {\r\n this.exit();\r\n } else {\r\n this.request(elem);\r\n }\r\n },\r\n isFullscreen: function () {\r\n return Boolean(document[fn.fullscreenElement]);\r\n },\r\n enabled: function () {\r\n return Boolean(document[fn.fullscreenEnabled]);\r\n }\r\n };\r\n\r\n $.extend(true, $.fancybox.defaults, {\r\n btnTpl: {\r\n fullScreen: '\"\r\n },\r\n fullScreen: {\r\n autoStart: false\r\n }\r\n });\r\n\r\n $(document).on(fn.fullscreenchange, function () {\r\n var isFullscreen = FullScreen.isFullscreen(),\r\n instance = $.fancybox.getInstance();\r\n\r\n if (instance) {\r\n // If image is zooming, then force to stop and reposition properly\r\n if (instance.current && instance.current.type === \"image\" && instance.isAnimating) {\r\n instance.isAnimating = false;\r\n\r\n instance.update(true, true, 0);\r\n\r\n if (!instance.isComplete) {\r\n instance.complete();\r\n }\r\n }\r\n\r\n instance.trigger(\"onFullscreenChange\", isFullscreen);\r\n\r\n instance.$refs.container.toggleClass(\"fancybox-is-fullscreen\", isFullscreen);\r\n\r\n instance.$refs.toolbar\r\n .find(\"[data-fancybox-fullscreen]\")\r\n .toggleClass(\"fancybox-button--fsenter\", !isFullscreen)\r\n .toggleClass(\"fancybox-button--fsexit\", isFullscreen);\r\n }\r\n });\r\n }\r\n\r\n $(document).on({\r\n \"onInit.fb\": function (e, instance) {\r\n var $container;\r\n\r\n if (!fn) {\r\n instance.$refs.toolbar.find(\"[data-fancybox-fullscreen]\").remove();\r\n\r\n return;\r\n }\r\n\r\n if (instance && instance.group[instance.currIndex].opts.fullScreen) {\r\n $container = instance.$refs.container;\r\n\r\n $container.on(\"click.fb-fullscreen\", \"[data-fancybox-fullscreen]\", function (e) {\r\n e.stopPropagation();\r\n e.preventDefault();\r\n\r\n FullScreen.toggle();\r\n });\r\n\r\n if (instance.opts.fullScreen && instance.opts.fullScreen.autoStart === true) {\r\n FullScreen.request();\r\n }\r\n\r\n // Expose API\r\n instance.FullScreen = FullScreen;\r\n } else if (instance) {\r\n instance.$refs.toolbar.find(\"[data-fancybox-fullscreen]\").hide();\r\n }\r\n },\r\n\r\n \"afterKeydown.fb\": function (e, instance, current, keypress, keycode) {\r\n // \"F\"\r\n if (instance && instance.FullScreen && keycode === 70) {\r\n keypress.preventDefault();\r\n\r\n instance.FullScreen.toggle();\r\n }\r\n },\r\n\r\n \"beforeClose.fb\": function (e, instance) {\r\n if (instance && instance.FullScreen && instance.$refs.container.hasClass(\"fancybox-is-fullscreen\")) {\r\n FullScreen.exit();\r\n }\r\n }\r\n });\r\n})(document, jQuery);\n// ==========================================================================\r\n//\r\n// Thumbs\r\n// Displays thumbnails in a grid\r\n//\r\n// ==========================================================================\r\n(function (document, $) {\r\n \"use strict\";\r\n\r\n var CLASS = \"fancybox-thumbs\",\r\n CLASS_ACTIVE = CLASS + \"-active\";\r\n\r\n // Make sure there are default values\r\n $.fancybox.defaults = $.extend(\r\n true, {\r\n btnTpl: {\r\n thumbs: '\"\r\n },\r\n thumbs: {\r\n autoStart: false, // Display thumbnails on opening\r\n hideOnClose: true, // Hide thumbnail grid when closing animation starts\r\n parentEl: \".fancybox-container\", // Container is injected into this element\r\n axis: \"y\" // Vertical (y) or horizontal (x) scrolling\r\n }\r\n },\r\n $.fancybox.defaults\r\n );\r\n\r\n var FancyThumbs = function (instance) {\r\n this.init(instance);\r\n };\r\n\r\n $.extend(FancyThumbs.prototype, {\r\n $button: null,\r\n $grid: null,\r\n $list: null,\r\n isVisible: false,\r\n isActive: false,\r\n\r\n init: function (instance) {\r\n var self = this,\r\n group = instance.group,\r\n enabled = 0;\r\n\r\n self.instance = instance;\r\n self.opts = group[instance.currIndex].opts.thumbs;\r\n\r\n instance.Thumbs = self;\r\n\r\n self.$button = instance.$refs.toolbar.find(\"[data-fancybox-thumbs]\");\r\n\r\n // Enable thumbs if at least two group items have thumbnails\r\n for (var i = 0, len = group.length; i < len; i++) {\r\n if (group[i].thumb) {\r\n enabled++;\r\n }\r\n\r\n if (enabled > 1) {\r\n break;\r\n }\r\n }\r\n\r\n if (enabled > 1 && !!self.opts) {\r\n self.$button.removeAttr(\"style\").on(\"click\", function () {\r\n self.toggle();\r\n });\r\n\r\n self.isActive = true;\r\n } else {\r\n self.$button.hide();\r\n }\r\n },\r\n\r\n create: function () {\r\n var self = this,\r\n instance = self.instance,\r\n parentEl = self.opts.parentEl,\r\n list = [],\r\n src;\r\n\r\n if (!self.$grid) {\r\n // Create main element\r\n self.$grid = $('
').appendTo(\r\n instance.$refs.container\r\n .find(parentEl)\r\n .addBack()\r\n .filter(parentEl)\r\n );\r\n\r\n // Add \"click\" event that performs gallery navigation\r\n self.$grid.on(\"click\", \"a\", function () {\r\n instance.jumpTo($(this).attr(\"data-index\"));\r\n });\r\n }\r\n\r\n // Build the list\r\n if (!self.$list) {\r\n self.$list = $('
').appendTo(self.$grid);\r\n }\r\n\r\n $.each(instance.group, function (i, item) {\r\n src = item.thumb;\r\n\r\n if (!src && item.type === \"image\") {\r\n src = item.src;\r\n }\r\n\r\n list.push(\r\n '\"\r\n );\r\n });\r\n\r\n self.$list[0].innerHTML = list.join(\"\");\r\n\r\n if (self.opts.axis === \"x\") {\r\n // Set fixed width for list element to enable horizontal scrolling\r\n self.$list.width(\r\n parseInt(self.$grid.css(\"padding-right\"), 10) +\r\n instance.group.length *\r\n self.$list\r\n .children()\r\n .eq(0)\r\n .outerWidth(true)\r\n );\r\n }\r\n },\r\n\r\n focus: function (duration) {\r\n var self = this,\r\n $list = self.$list,\r\n $grid = self.$grid,\r\n thumb,\r\n thumbPos;\r\n\r\n if (!self.instance.current) {\r\n return;\r\n }\r\n\r\n thumb = $list\r\n .children()\r\n .removeClass(CLASS_ACTIVE)\r\n .filter('[data-index=\"' + self.instance.current.index + '\"]')\r\n .addClass(CLASS_ACTIVE);\r\n\r\n thumbPos = thumb.position();\r\n\r\n // Check if need to scroll to make current thumb visible\r\n if (self.opts.axis === \"y\" && (thumbPos.top < 0 || thumbPos.top > $list.height() - thumb.outerHeight())) {\r\n $list.stop().animate({\r\n scrollTop: $list.scrollTop() + thumbPos.top\r\n },\r\n duration\r\n );\r\n } else if (\r\n self.opts.axis === \"x\" &&\r\n (thumbPos.left < $grid.scrollLeft() || thumbPos.left > $grid.scrollLeft() + ($grid.width() - thumb.outerWidth()))\r\n ) {\r\n $list\r\n .parent()\r\n .stop()\r\n .animate({\r\n scrollLeft: thumbPos.left\r\n },\r\n duration\r\n );\r\n }\r\n },\r\n\r\n update: function () {\r\n var that = this;\r\n that.instance.$refs.container.toggleClass(\"fancybox-show-thumbs\", this.isVisible);\r\n\r\n if (that.isVisible) {\r\n if (!that.$grid) {\r\n that.create();\r\n }\r\n\r\n that.instance.trigger(\"onThumbsShow\");\r\n\r\n that.focus(0);\r\n } else if (that.$grid) {\r\n that.instance.trigger(\"onThumbsHide\");\r\n }\r\n\r\n // Update content position\r\n that.instance.update();\r\n },\r\n\r\n hide: function () {\r\n this.isVisible = false;\r\n this.update();\r\n },\r\n\r\n show: function () {\r\n this.isVisible = true;\r\n this.update();\r\n },\r\n\r\n toggle: function () {\r\n this.isVisible = !this.isVisible;\r\n this.update();\r\n }\r\n });\r\n\r\n $(document).on({\r\n \"onInit.fb\": function (e, instance) {\r\n var Thumbs;\r\n\r\n if (instance && !instance.Thumbs) {\r\n Thumbs = new FancyThumbs(instance);\r\n\r\n if (Thumbs.isActive && Thumbs.opts.autoStart === true) {\r\n Thumbs.show();\r\n }\r\n }\r\n },\r\n\r\n \"beforeShow.fb\": function (e, instance, item, firstRun) {\r\n var Thumbs = instance && instance.Thumbs;\r\n\r\n if (Thumbs && Thumbs.isVisible) {\r\n Thumbs.focus(firstRun ? 0 : 250);\r\n }\r\n },\r\n\r\n \"afterKeydown.fb\": function (e, instance, current, keypress, keycode) {\r\n var Thumbs = instance && instance.Thumbs;\r\n\r\n // \"G\"\r\n if (Thumbs && Thumbs.isActive && keycode === 71) {\r\n keypress.preventDefault();\r\n\r\n Thumbs.toggle();\r\n }\r\n },\r\n\r\n \"beforeClose.fb\": function (e, instance) {\r\n var Thumbs = instance && instance.Thumbs;\r\n\r\n if (Thumbs && Thumbs.isVisible && Thumbs.opts.hideOnClose !== false) {\r\n Thumbs.$grid.hide();\r\n }\r\n }\r\n });\r\n})(document, jQuery);\n//// ==========================================================================\r\n//\r\n// Share\r\n// Displays simple form for sharing current url\r\n//\r\n// ==========================================================================\r\n(function (document, $) {\r\n \"use strict\";\r\n\r\n $.extend(true, $.fancybox.defaults, {\r\n btnTpl: {\r\n share: '\"\r\n },\r\n share: {\r\n url: function (instance, item) {\r\n return (\r\n (!instance.currentHash && !(item.type === \"inline\" || item.type === \"html\") ? item.origSrc || item.src : false) || window.location\r\n );\r\n },\r\n tpl: '
' +\r\n \"

{{SHARE}}

\" +\r\n \"

\" +\r\n '' +\r\n '' +\r\n \"Facebook\" +\r\n \"\" +\r\n '' +\r\n '' +\r\n \"Twitter\" +\r\n \"\" +\r\n '' +\r\n '' +\r\n \"Pinterest\" +\r\n \"\" +\r\n \"

\" +\r\n '

' +\r\n \"
\"\r\n }\r\n });\r\n\r\n function escapeHtml(string) {\r\n var entityMap = {\r\n \"&\": \"&\",\r\n \"<\": \"<\",\r\n \">\": \">\",\r\n '\"': \""\",\r\n \"'\": \"'\",\r\n \"/\": \"/\",\r\n \"`\": \"`\",\r\n \"=\": \"=\"\r\n };\r\n\r\n return String(string).replace(/[&<>\"'`=\\/]/g, function (s) {\r\n return entityMap[s];\r\n });\r\n }\r\n\r\n $(document).on(\"click\", \"[data-fancybox-share]\", function () {\r\n var instance = $.fancybox.getInstance(),\r\n current = instance.current || null,\r\n url,\r\n tpl;\r\n\r\n if (!current) {\r\n return;\r\n }\r\n\r\n if ($.type(current.opts.share.url) === \"function\") {\r\n url = current.opts.share.url.apply(current, [instance, current]);\r\n }\r\n\r\n tpl = current.opts.share.tpl\r\n .replace(/\\{\\{media\\}\\}/g, current.type === \"image\" ? encodeURIComponent(current.src) : \"\")\r\n .replace(/\\{\\{url\\}\\}/g, encodeURIComponent(url))\r\n .replace(/\\{\\{url_raw\\}\\}/g, escapeHtml(url))\r\n .replace(/\\{\\{descr\\}\\}/g, instance.$caption ? encodeURIComponent(instance.$caption.text()) : \"\");\r\n\r\n $.fancybox.open({\r\n src: instance.translate(instance, tpl),\r\n type: \"html\",\r\n opts: {\r\n touch: false,\r\n animationEffect: false,\r\n afterLoad: function (shareInstance, shareCurrent) {\r\n // Close self if parent instance is closing\r\n instance.$refs.container.one(\"beforeClose.fb\", function () {\r\n shareInstance.close(null, 0);\r\n });\r\n\r\n // Opening links in a popup window\r\n shareCurrent.$content.find(\".fancybox-share__button\").click(function () {\r\n window.open(this.href, \"Share\", \"width=550, height=450\");\r\n return false;\r\n });\r\n },\r\n mobile: {\r\n autoFocus: false\r\n }\r\n }\r\n });\r\n });\r\n})(document, jQuery);\n// ==========================================================================\r\n//\r\n// Hash\r\n// Enables linking to each modal\r\n//\r\n// ==========================================================================\r\n(function (window, document, $) {\r\n \"use strict\";\r\n\r\n // Simple $.escapeSelector polyfill (for jQuery prior v3)\r\n if (!$.escapeSelector) {\r\n $.escapeSelector = function (sel) {\r\n var rcssescape = /([\\0-\\x1f\\x7f]|^-?\\d)|^-$|[^\\x80-\\uFFFF\\w-]/g;\r\n var fcssescape = function (ch, asCodePoint) {\r\n if (asCodePoint) {\r\n // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER\r\n if (ch === \"\\0\") {\r\n return \"\\uFFFD\";\r\n }\r\n\r\n // Control characters and (dependent upon position) numbers get escaped as code points\r\n return ch.slice(0, -1) + \"\\\\\" + ch.charCodeAt(ch.length - 1).toString(16) + \" \";\r\n }\r\n\r\n // Other potentially-special ASCII characters get backslash-escaped\r\n return \"\\\\\" + ch;\r\n };\r\n\r\n return (sel + \"\").replace(rcssescape, fcssescape);\r\n };\r\n }\r\n\r\n // Get info about gallery name and current index from url\r\n function parseUrl() {\r\n var hash = window.location.hash.substr(1),\r\n rez = hash.split(\"-\"),\r\n index = rez.length > 1 && /^\\+?\\d+$/.test(rez[rez.length - 1]) ? parseInt(rez.pop(-1), 10) || 1 : 1,\r\n gallery = rez.join(\"-\");\r\n\r\n return {\r\n hash: hash,\r\n /* Index is starting from 1 */\r\n index: index < 1 ? 1 : index,\r\n gallery: gallery\r\n };\r\n }\r\n\r\n // Trigger click evnt on links to open new fancyBox instance\r\n function triggerFromUrl(url) {\r\n if (url.gallery !== \"\") {\r\n // If we can find element matching 'data-fancybox' atribute,\r\n // then triggering click event should start fancyBox\r\n $(\"[data-fancybox='\" + $.escapeSelector(url.gallery) + \"']\")\r\n .eq(url.index - 1)\r\n .focus()\r\n .trigger(\"click.fb-start\");\r\n }\r\n }\r\n\r\n // Get gallery name from current instance\r\n function getGalleryID(instance) {\r\n var opts, ret;\r\n\r\n if (!instance) {\r\n return false;\r\n }\r\n\r\n opts = instance.current ? instance.current.opts : instance.opts;\r\n ret = opts.hash || (opts.$orig ? opts.$orig.data(\"fancybox\") || opts.$orig.data(\"fancybox-trigger\") : \"\");\r\n\r\n return ret === \"\" ? false : ret;\r\n }\r\n\r\n // Start when DOM becomes ready\r\n $(function () {\r\n // Check if user has disabled this module\r\n if ($.fancybox.defaults.hash === false) {\r\n return;\r\n }\r\n\r\n // Update hash when opening/closing fancyBox\r\n $(document).on({\r\n \"onInit.fb\": function (e, instance) {\r\n var url, gallery;\r\n\r\n if (instance.group[instance.currIndex].opts.hash === false) {\r\n return;\r\n }\r\n\r\n url = parseUrl();\r\n gallery = getGalleryID(instance);\r\n\r\n // Make sure gallery start index matches index from hash\r\n if (gallery && url.gallery && gallery == url.gallery) {\r\n instance.currIndex = url.index - 1;\r\n }\r\n },\r\n\r\n \"beforeShow.fb\": function (e, instance, current, firstRun) {\r\n var gallery;\r\n\r\n if (!current || current.opts.hash === false) {\r\n return;\r\n }\r\n\r\n // Check if need to update window hash\r\n gallery = getGalleryID(instance);\r\n\r\n if (!gallery) {\r\n return;\r\n }\r\n\r\n // Variable containing last hash value set by fancyBox\r\n // It will be used to determine if fancyBox needs to close after hash change is detected\r\n instance.currentHash = gallery + (instance.group.length > 1 ? \"-\" + (current.index + 1) : \"\");\r\n\r\n // If current hash is the same (this instance most likely is opened by hashchange), then do nothing\r\n if (window.location.hash === \"#\" + instance.currentHash) {\r\n return;\r\n }\r\n\r\n if (firstRun && !instance.origHash) {\r\n instance.origHash = window.location.hash;\r\n }\r\n\r\n if (instance.hashTimer) {\r\n clearTimeout(instance.hashTimer);\r\n }\r\n\r\n // Update hash\r\n instance.hashTimer = setTimeout(function () {\r\n if (\"replaceState\" in window.history) {\r\n window.history[firstRun ? \"pushState\" : \"replaceState\"]({},\r\n document.title,\r\n window.location.pathname + window.location.search + \"#\" + instance.currentHash\r\n );\r\n\r\n if (firstRun) {\r\n instance.hasCreatedHistory = true;\r\n }\r\n } else {\r\n window.location.hash = instance.currentHash;\r\n }\r\n\r\n instance.hashTimer = null;\r\n }, 300);\r\n },\r\n\r\n \"beforeClose.fb\": function (e, instance, current) {\r\n if (!current || current.opts.hash === false) {\r\n return;\r\n }\r\n\r\n clearTimeout(instance.hashTimer);\r\n\r\n // Goto previous history entry\r\n if (instance.currentHash && instance.hasCreatedHistory) {\r\n window.history.back();\r\n } else if (instance.currentHash) {\r\n if (\"replaceState\" in window.history) {\r\n window.history.replaceState({}, document.title, window.location.pathname + window.location.search + (instance.origHash || \"\"));\r\n } else {\r\n window.location.hash = instance.origHash;\r\n }\r\n }\r\n\r\n instance.currentHash = null;\r\n }\r\n });\r\n\r\n // Check if need to start/close after url has changed\r\n $(window).on(\"hashchange.fb\", function () {\r\n var url = parseUrl(),\r\n fb = null;\r\n\r\n // Find last fancyBox instance that has \"hash\"\r\n $.each(\r\n $(\".fancybox-container\")\r\n .get()\r\n .reverse(),\r\n function (index, value) {\r\n var tmp = $(value).data(\"FancyBox\");\r\n\r\n if (tmp && tmp.currentHash) {\r\n fb = tmp;\r\n return false;\r\n }\r\n }\r\n );\r\n\r\n if (fb) {\r\n // Now, compare hash values\r\n if (fb.currentHash !== url.gallery + \"-\" + url.index && !(url.index === 1 && fb.currentHash == url.gallery)) {\r\n fb.currentHash = null;\r\n\r\n fb.close();\r\n }\r\n } else if (url.gallery !== \"\") {\r\n triggerFromUrl(url);\r\n }\r\n });\r\n\r\n // Check current hash and trigger click event on matching element to start fancyBox, if needed\r\n setTimeout(function () {\r\n if (!$.fancybox.getInstance()) {\r\n triggerFromUrl(parseUrl());\r\n }\r\n }, 50);\r\n });\r\n})(window, document, jQuery);\n// ==========================================================================\r\n//\r\n// Wheel\r\n// Basic mouse weheel support for gallery navigation\r\n//\r\n// ==========================================================================\r\n(function (document, $) {\r\n \"use strict\";\r\n\r\n var prevTime = new Date().getTime();\r\n\r\n $(document).on({\r\n \"onInit.fb\": function (e, instance, current) {\r\n instance.$refs.stage.on(\"mousewheel DOMMouseScroll wheel MozMousePixelScroll\", function (e) {\r\n var current = instance.current,\r\n currTime = new Date().getTime();\r\n\r\n if (instance.group.length < 2 || current.opts.wheel === false || (current.opts.wheel === \"auto\" && current.type !== \"image\")) {\r\n return;\r\n }\r\n\r\n e.preventDefault();\r\n e.stopPropagation();\r\n\r\n if (current.$slide.hasClass(\"fancybox-animated\")) {\r\n return;\r\n }\r\n\r\n e = e.originalEvent || e;\r\n\r\n if (currTime - prevTime < 250) {\r\n return;\r\n }\r\n\r\n prevTime = currTime;\r\n\r\n instance[(-e.deltaY || -e.deltaX || e.wheelDelta || -e.detail) < 0 ? \"next\" : \"previous\"]();\r\n });\r\n }\r\n });\r\n})(document, jQuery);//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvQGZhbmN5YXBwcy9mYW5jeWJveC9kaXN0L2pxdWVyeS5mYW5jeWJveC5qcz8zOTY0Il0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQSx1Q0FBdUMsSUFBSSx1QkFBdUIsSUFBSSw0RUFBNEU7O0FBRWxKO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxhQUFhOztBQUViO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0EsdUZBQXVGLFFBQVE7QUFDL0Ysd0JBQXdCLEtBQUssVUFBVSxRQUFRO0FBQy9DLDBFQUEwRSxLQUFLO0FBQy9FO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDRFQUE0RSxPQUFPO0FBQ25GLHVDQUF1QyxTQUFTO0FBQ2hELDBDQUEwQyxRQUFRO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxnREFBZ0QsT0FBTzs7QUFFdkQ7QUFDQSwrR0FBK0csVUFBVSxvQkFBb0I7QUFDN0k7QUFDQTs7QUFFQSwrRkFBK0YsTUFBTTtBQUNyRztBQUNBOztBQUVBLGtHQUFrRyxPQUFPO0FBQ3pHO0FBQ0E7O0FBRUE7QUFDQSwwR0FBMEcsTUFBTTtBQUNoSDtBQUNBOztBQUVBLDRHQUE0RyxNQUFNO0FBQ2xIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGlIQUFpSCxPQUFPO0FBQ3hIO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUEsd0NBQXdDO0FBQ3hDOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhOztBQUViO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0EsNkJBQTZCO0FBQzdCO0FBQ0Esd0JBQXdCO0FBQ3hCLDJHQUEyRztBQUMzRztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQkFBMEIsT0FBTztBQUNqQztBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsK0JBQStCOztBQUUvQjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5RkFBeUY7QUFDekY7QUFDQSxlQUFlO0FBQ2Y7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCLFNBQVM7QUFDakMsd0JBQXdCLFFBQVE7QUFDaEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxPQUFPOztBQUVQOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsNEJBQTRCLEVBQUUsT0FBTyxFQUFFO0FBQ3ZDO0FBQ0EsT0FBTztBQUNQLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0Esb0JBQW9CO0FBQ3BCLG1CQUFtQjtBQUNuQjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGlDQUFpQyxvQ0FBb0M7O0FBRXJFO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQSxxREFBcUQsZ0JBQWdCO0FBQ3JFO0FBQ0Esa0NBQWtDOztBQUVsQztBQUNBOztBQUVBOztBQUVBO0FBQ0EsK0NBQStDLEdBQUc7QUFDbEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxvQ0FBb0M7O0FBRXBDO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiLFdBQVc7QUFDWDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0EsU0FBUzs7QUFFVDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFdBQVc7QUFDWCxTQUFTO0FBQ1Q7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsNkNBQTZDO0FBQzdDOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7O0FBRVg7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7O0FBRVg7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakI7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVCxPQUFPO0FBQ1A7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTs7QUFFQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSw0Q0FBNEM7QUFDNUM7QUFDQTtBQUNBO0FBQ0EsU0FBUzs7QUFFVDtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxPQUFPO0FBQ1AsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVzs7QUFFWDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCLEVBQUUsS0FBSyxFQUFFO0FBQ2pDLHdCQUF3QixRQUFRO0FBQ2hDLHdCQUF3QixRQUFRO0FBQ2hDOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSx1QkFBdUI7QUFDdkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGVBQWU7QUFDZjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiOztBQUVBO0FBQ0E7QUFDQSxXQUFXOztBQUVYOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7O0FBRWI7QUFDQSxTQUFTOztBQUVUO0FBQ0E7QUFDQTtBQUNBLFNBQVM7O0FBRVQ7QUFDQSx1QkFBdUIsaUJBQWlCO0FBQ3hDOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjs7QUFFQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsc0RBQXNELEtBQUs7QUFDM0Q7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLFNBQVM7O0FBRVQ7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7O0FBRVg7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhOztBQUViO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLFNBQVM7QUFDVCxPQUFPO0FBQ1A7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTOztBQUVUO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsT0FBTztBQUNQLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsT0FBTzs7QUFFUDs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsU0FBUzs7QUFFVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLFNBQVM7QUFDVDtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxTQUFTOztBQUVUO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLDhFQUE4RTs7QUFFOUU7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7O0FBRVg7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQjtBQUNuQjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYOztBQUVBO0FBQ0E7QUFDQSxTQUFTOztBQUVUO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7O0FBRUE7QUFDQSxXQUFXO0FBQ1g7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxPQUFPOztBQUVQOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxTQUFTOztBQUVUO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87QUFDUDs7QUFFQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsNkJBQTZCO0FBQzdCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQSxTQUFTO0FBQ1Q7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVCxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1AsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxHQUFHO0FBQ0gsQ0FBQztBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0Esa0lBQWtJLEdBQUc7QUFDckk7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0NBQXdDLElBQUksU0FBUyxFQUFFO0FBQ3ZEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3Q0FBd0MsSUFBSSxTQUFTLEVBQUU7QUFDdkQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLDZCQUE2Qjs7QUFFN0I7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsdUJBQXVCLHNCQUFzQjtBQUM3Qzs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGdDQUFnQzs7QUFFaEM7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVCxPQUFPO0FBQ1A7QUFDQTs7QUFFQTtBQUNBLEtBQUs7O0FBRUw7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1AsS0FBSztBQUNMO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxLQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsU0FBUztBQUNUOztBQUVBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVCxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsOERBQThELE9BQU87QUFDckU7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxPQUFPO0FBQ1A7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0EsU0FBUztBQUNUOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0EsYUFBYTs7QUFFYjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsU0FBUzs7QUFFVDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWCxTQUFTOztBQUVUO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQSxLQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBLEtBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGtDQUFrQztBQUNsQzs7QUFFQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsT0FBTztBQUNQO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsQ0FBQztBQUNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLG9HQUFvRyxZQUFZO0FBQ2hIO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsT0FBTzs7QUFFUDtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsbUJBQW1CLGtCQUFrQjtBQUNyQzs7QUFFQTtBQUNBLHVCQUF1QixnQkFBZ0I7QUFDdkM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsZ0hBQWdILGFBQWE7QUFDN0g7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLFNBQVM7O0FBRVQ7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUdBQXVHLFFBQVE7QUFDL0c7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSx5Q0FBeUMsU0FBUztBQUNsRDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsU0FBUzs7QUFFVDtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxnQ0FBZ0M7QUFDaEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87O0FBRVA7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLE9BQU87QUFDUDtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxrR0FBa0csT0FBTztBQUN6RztBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQSxlQUFlLE9BQU87QUFDdEI7QUFDQSwySEFBMkgsS0FBSztBQUNoSTtBQUNBO0FBQ0E7QUFDQSxtSEFBbUgsS0FBSyxRQUFRLE9BQU87QUFDdkk7QUFDQTtBQUNBO0FBQ0EsK0hBQStILEtBQUssZUFBZSxPQUFPLFNBQVMsT0FBTztBQUMxSztBQUNBO0FBQ0E7QUFDQTtBQUNBLHNFQUFzRSxTQUFTO0FBQy9FO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakIsZ0JBQWdCO0FBQ2hCLGdCQUFnQjtBQUNoQixrQkFBa0I7QUFDbEIsaUJBQWlCO0FBQ2pCLGtCQUFrQjtBQUNsQixrQkFBa0I7QUFDbEIsa0JBQWtCO0FBQ2xCOztBQUVBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0Esa0JBQWtCLEVBQUUsT0FBTyxFQUFFO0FBQzdCLGtCQUFrQixFQUFFLEtBQUssRUFBRTtBQUMzQixrQkFBa0IsRUFBRSxTQUFTLEVBQUU7QUFDL0Isa0JBQWtCLEVBQUUsT0FBTyxFQUFFOztBQUU3QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7O0FBRVg7QUFDQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1gsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMLEdBQUc7QUFDSCxDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLHNFQUFzRTtBQUN0RTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7O0FBRUE7QUFDQSxTQUFTO0FBQ1QsT0FBTzs7QUFFUDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSwwQ0FBMEM7QUFDMUMsV0FBVztBQUNYO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMLEdBQUc7QUFDSCxDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSxPQUFPO0FBQ1A7QUFDQSxHQUFHO0FBQ0gsQ0FBQyIsImZpbGUiOiIuL25vZGVfbW9kdWxlcy9AZmFuY3lhcHBzL2ZhbmN5Ym94L2Rpc3QvanF1ZXJ5LmZhbmN5Ym94LmpzLmpzIiwic291cmNlc0NvbnRlbnQiOlsiLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIGZhbmN5Qm94IHYzLjUuN1xuLy9cbi8vIExpY2Vuc2VkIEdQTHYzIGZvciBvcGVuIHNvdXJjZSB1c2Vcbi8vIG9yIGZhbmN5Qm94IENvbW1lcmNpYWwgTGljZW5zZSBmb3IgY29tbWVyY2lhbCB1c2Vcbi8vXG4vLyBodHRwOi8vZmFuY3lhcHBzLmNvbS9mYW5jeWJveC9cbi8vIENvcHlyaWdodCAyMDE5IGZhbmN5QXBwc1xuLy9cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4oZnVuY3Rpb24gKHdpbmRvdywgZG9jdW1lbnQsICQsIHVuZGVmaW5lZCkge1xyXG4gIFwidXNlIHN0cmljdFwiO1xyXG5cclxuICB3aW5kb3cuY29uc29sZSA9IHdpbmRvdy5jb25zb2xlIHx8IHtcclxuICAgIGluZm86IGZ1bmN0aW9uIChzdHVmZikge31cclxuICB9O1xyXG5cclxuICAvLyBJZiB0aGVyZSdzIG5vIGpRdWVyeSwgZmFuY3lCb3ggY2FuJ3Qgd29ya1xyXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gIGlmICghJCkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgZmFuY3lCb3ggaXMgYWxyZWFkeSBpbml0aWFsaXplZFxyXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgaWYgKCQuZm4uZmFuY3lib3gpIHtcclxuICAgIGNvbnNvbGUuaW5mbyhcImZhbmN5Qm94IGFscmVhZHkgaW5pdGlhbGl6ZWRcIik7XHJcblxyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gUHJpdmF0ZSBkZWZhdWx0IHNldHRpbmdzXHJcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gIHZhciBkZWZhdWx0cyA9IHtcclxuICAgIC8vIENsb3NlIGV4aXN0aW5nIG1vZGFsc1xyXG4gICAgLy8gU2V0IHRoaXMgdG8gZmFsc2UgaWYgeW91IGRvIG5vdCBuZWVkIHRvIHN0YWNrIG11bHRpcGxlIGluc3RhbmNlc1xyXG4gICAgY2xvc2VFeGlzdGluZzogZmFsc2UsXHJcblxyXG4gICAgLy8gRW5hYmxlIGluZmluaXRlIGdhbGxlcnkgbmF2aWdhdGlvblxyXG4gICAgbG9vcDogZmFsc2UsXHJcblxyXG4gICAgLy8gSG9yaXpvbnRhbCBzcGFjZSBiZXR3ZWVuIHNsaWRlc1xyXG4gICAgZ3V0dGVyOiA1MCxcclxuXHJcbiAgICAvLyBFbmFibGUga2V5Ym9hcmQgbmF2aWdhdGlvblxyXG4gICAga2V5Ym9hcmQ6IHRydWUsXHJcblxyXG4gICAgLy8gU2hvdWxkIGFsbG93IGNhcHRpb24gdG8gb3ZlcmxhcCB0aGUgY29udGVudFxyXG4gICAgcHJldmVudENhcHRpb25PdmVybGFwOiB0cnVlLFxyXG5cclxuICAgIC8vIFNob3VsZCBkaXNwbGF5IG5hdmlnYXRpb24gYXJyb3dzIGF0IHRoZSBzY3JlZW4gZWRnZXNcclxuICAgIGFycm93czogdHJ1ZSxcclxuXHJcbiAgICAvLyBTaG91bGQgZGlzcGxheSBjb3VudGVyIGF0IHRoZSB0b3AgbGVmdCBjb3JuZXJcclxuICAgIGluZm9iYXI6IHRydWUsXHJcblxyXG4gICAgLy8gU2hvdWxkIGRpc3BsYXkgY2xvc2UgYnV0dG9uICh1c2luZyBgYnRuVHBsLnNtYWxsQnRuYCB0ZW1wbGF0ZSkgb3ZlciB0aGUgY29udGVudFxyXG4gICAgLy8gQ2FuIGJlIHRydWUsIGZhbHNlLCBcImF1dG9cIlxyXG4gICAgLy8gSWYgXCJhdXRvXCIgLSB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgZW5hYmxlZCBmb3IgXCJodG1sXCIsIFwiaW5saW5lXCIgb3IgXCJhamF4XCIgaXRlbXNcclxuICAgIHNtYWxsQnRuOiBcImF1dG9cIixcclxuXHJcbiAgICAvLyBTaG91bGQgZGlzcGxheSB0b29sYmFyIChidXR0b25zIGF0IHRoZSB0b3ApXHJcbiAgICAvLyBDYW4gYmUgdHJ1ZSwgZmFsc2UsIFwiYXV0b1wiXHJcbiAgICAvLyBJZiBcImF1dG9cIiAtIHdpbGwgYmUgYXV0b21hdGljYWxseSBoaWRkZW4gaWYgXCJzbWFsbEJ0blwiIGlzIGVuYWJsZWRcclxuICAgIHRvb2xiYXI6IFwiYXV0b1wiLFxyXG5cclxuICAgIC8vIFdoYXQgYnV0dG9ucyBzaG91bGQgYXBwZWFyIGluIHRoZSB0b3AgcmlnaHQgY29ybmVyLlxyXG4gICAgLy8gQnV0dG9ucyB3aWxsIGJlIGNyZWF0ZWQgdXNpbmcgdGVtcGxhdGVzIGZyb20gYGJ0blRwbGAgb3B0aW9uXHJcbiAgICAvLyBhbmQgdGhleSB3aWxsIGJlIHBsYWNlZCBpbnRvIHRvb2xiYXIgKGNsYXNzPVwiZmFuY3lib3gtdG9vbGJhclwiYCBlbGVtZW50KVxyXG4gICAgYnV0dG9uczogW1xyXG4gICAgICBcInpvb21cIixcclxuICAgICAgLy9cInNoYXJlXCIsXHJcbiAgICAgIFwic2xpZGVTaG93XCIsXHJcbiAgICAgIC8vXCJmdWxsU2NyZWVuXCIsXHJcbiAgICAgIC8vXCJkb3dubG9hZFwiLFxyXG4gICAgICBcInRodW1ic1wiLFxyXG4gICAgICBcImNsb3NlXCJcclxuICAgIF0sXHJcblxyXG4gICAgLy8gRGV0ZWN0IFwiaWRsZVwiIHRpbWUgaW4gc2Vjb25kc1xyXG4gICAgaWRsZVRpbWU6IDMsXHJcblxyXG4gICAgLy8gRGlzYWJsZSByaWdodC1jbGljayBhbmQgdXNlIHNpbXBsZSBpbWFnZSBwcm90ZWN0aW9uIGZvciBpbWFnZXNcclxuICAgIHByb3RlY3Q6IGZhbHNlLFxyXG5cclxuICAgIC8vIFNob3J0Y3V0IHRvIG1ha2UgY29udGVudCBcIm1vZGFsXCIgLSBkaXNhYmxlIGtleWJvYXJkIG5hdmlndGlvbiwgaGlkZSBidXR0b25zLCBldGNcclxuICAgIG1vZGFsOiBmYWxzZSxcclxuXHJcbiAgICBpbWFnZToge1xyXG4gICAgICAvLyBXYWl0IGZvciBpbWFnZXMgdG8gbG9hZCBiZWZvcmUgZGlzcGxheWluZ1xyXG4gICAgICAvLyAgIHRydWUgIC0gd2FpdCBmb3IgaW1hZ2UgdG8gbG9hZCBhbmQgdGhlbiBkaXNwbGF5O1xyXG4gICAgICAvLyAgIGZhbHNlIC0gZGlzcGxheSB0aHVtYm5haWwgYW5kIGxvYWQgdGhlIGZ1bGwtc2l6ZWQgaW1hZ2Ugb3ZlciB0b3AsXHJcbiAgICAgIC8vICAgICAgICAgICByZXF1aXJlcyBwcmVkZWZpbmVkIGltYWdlIGRpbWVuc2lvbnMgKGBkYXRhLXdpZHRoYCBhbmQgYGRhdGEtaGVpZ2h0YCBhdHRyaWJ1dGVzKVxyXG4gICAgICBwcmVsb2FkOiBmYWxzZVxyXG4gICAgfSxcclxuXHJcbiAgICBhamF4OiB7XHJcbiAgICAgIC8vIE9iamVjdCBjb250YWluaW5nIHNldHRpbmdzIGZvciBhamF4IHJlcXVlc3RcclxuICAgICAgc2V0dGluZ3M6IHtcclxuICAgICAgICAvLyBUaGlzIGhlbHBzIHRvIGluZGljYXRlIHRoYXQgcmVxdWVzdCBjb21lcyBmcm9tIHRoZSBtb2RhbFxyXG4gICAgICAgIC8vIEZlZWwgZnJlZSB0byBjaGFuZ2UgbmFtaW5nXHJcbiAgICAgICAgZGF0YToge1xyXG4gICAgICAgICAgZmFuY3lib3g6IHRydWVcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgaWZyYW1lOiB7XHJcbiAgICAgIC8vIElmcmFtZSB0ZW1wbGF0ZVxyXG4gICAgICB0cGw6ICc8aWZyYW1lIGlkPVwiZmFuY3lib3gtZnJhbWV7cm5kfVwiIG5hbWU9XCJmYW5jeWJveC1mcmFtZXtybmR9XCIgY2xhc3M9XCJmYW5jeWJveC1pZnJhbWVcIiBhbGxvd2Z1bGxzY3JlZW49XCJhbGxvd2Z1bGxzY3JlZW5cIiBhbGxvdz1cImF1dG9wbGF5OyBmdWxsc2NyZWVuXCIgc3JjPVwiXCI+PC9pZnJhbWU+JyxcclxuXHJcbiAgICAgIC8vIFByZWxvYWQgaWZyYW1lIGJlZm9yZSBkaXNwbGF5aW5nIGl0XHJcbiAgICAgIC8vIFRoaXMgYWxsb3dzIHRvIGNhbGN1bGF0ZSBpZnJhbWUgY29udGVudCB3aWR0aCBhbmQgaGVpZ2h0XHJcbiAgICAgIC8vIChub3RlOiBEdWUgdG8gXCJTYW1lIE9yaWdpbiBQb2xpY3lcIiwgeW91IGNhbid0IGdldCBjcm9zcyBkb21haW4gZGF0YSkuXHJcbiAgICAgIHByZWxvYWQ6IHRydWUsXHJcblxyXG4gICAgICAvLyBDdXN0b20gQ1NTIHN0eWxpbmcgZm9yIGlmcmFtZSB3cmFwcGluZyBlbGVtZW50XHJcbiAgICAgIC8vIFlvdSBjYW4gdXNlIHRoaXMgdG8gc2V0IGN1c3RvbSBpZnJhbWUgZGltZW5zaW9uc1xyXG4gICAgICBjc3M6IHt9LFxyXG5cclxuICAgICAgLy8gSWZyYW1lIHRhZyBhdHRyaWJ1dGVzXHJcbiAgICAgIGF0dHI6IHtcclxuICAgICAgICBzY3JvbGxpbmc6IFwiYXV0b1wiXHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgLy8gRm9yIEhUTUw1IHZpZGVvIG9ubHlcclxuICAgIHZpZGVvOiB7XHJcbiAgICAgIHRwbDogJzx2aWRlbyBjbGFzcz1cImZhbmN5Ym94LXZpZGVvXCIgY29udHJvbHMgY29udHJvbHNMaXN0PVwibm9kb3dubG9hZFwiIHBvc3Rlcj1cInt7cG9zdGVyfX1cIj4nICtcclxuICAgICAgICAnPHNvdXJjZSBzcmM9XCJ7e3NyY319XCIgdHlwZT1cInt7Zm9ybWF0fX1cIiAvPicgK1xyXG4gICAgICAgICdTb3JyeSwgeW91ciBicm93c2VyIGRvZXNuXFwndCBzdXBwb3J0IGVtYmVkZGVkIHZpZGVvcywgPGEgaHJlZj1cInt7c3JjfX1cIj5kb3dubG9hZDwvYT4gYW5kIHdhdGNoIHdpdGggeW91ciBmYXZvcml0ZSB2aWRlbyBwbGF5ZXIhJyArXHJcbiAgICAgICAgXCI8L3ZpZGVvPlwiLFxyXG4gICAgICBmb3JtYXQ6IFwiXCIsIC8vIGN1c3RvbSB2aWRlbyBmb3JtYXRcclxuICAgICAgYXV0b1N0YXJ0OiB0cnVlXHJcbiAgICB9LFxyXG5cclxuICAgIC8vIERlZmF1bHQgY29udGVudCB0eXBlIGlmIGNhbm5vdCBiZSBkZXRlY3RlZCBhdXRvbWF0aWNhbGx5XHJcbiAgICBkZWZhdWx0VHlwZTogXCJpbWFnZVwiLFxyXG5cclxuICAgIC8vIE9wZW4vY2xvc2UgYW5pbWF0aW9uIHR5cGVcclxuICAgIC8vIFBvc3NpYmxlIHZhbHVlczpcclxuICAgIC8vICAgZmFsc2UgICAgICAgICAgICAtIGRpc2FibGVcclxuICAgIC8vICAgXCJ6b29tXCIgICAgICAgICAgIC0gem9vbSBpbWFnZXMgZnJvbS90byB0aHVtYm5haWxcclxuICAgIC8vICAgXCJmYWRlXCJcclxuICAgIC8vICAgXCJ6b29tLWluLW91dFwiXHJcbiAgICAvL1xyXG4gICAgYW5pbWF0aW9uRWZmZWN0OiBcInpvb21cIixcclxuXHJcbiAgICAvLyBEdXJhdGlvbiBpbiBtcyBmb3Igb3Blbi9jbG9zZSBhbmltYXRpb25cclxuICAgIGFuaW1hdGlvbkR1cmF0aW9uOiAzNjYsXHJcblxyXG4gICAgLy8gU2hvdWxkIGltYWdlIGNoYW5nZSBvcGFjaXR5IHdoaWxlIHpvb21pbmdcclxuICAgIC8vIElmIG9wYWNpdHkgaXMgXCJhdXRvXCIsIHRoZW4gb3BhY2l0eSB3aWxsIGJlIGNoYW5nZWQgaWYgaW1hZ2UgYW5kIHRodW1ibmFpbCBoYXZlIGRpZmZlcmVudCBhc3BlY3QgcmF0aW9zXHJcbiAgICB6b29tT3BhY2l0eTogXCJhdXRvXCIsXHJcblxyXG4gICAgLy8gVHJhbnNpdGlvbiBlZmZlY3QgYmV0d2VlbiBzbGlkZXNcclxuICAgIC8vXHJcbiAgICAvLyBQb3NzaWJsZSB2YWx1ZXM6XHJcbiAgICAvLyAgIGZhbHNlICAgICAgICAgICAgLSBkaXNhYmxlXHJcbiAgICAvLyAgIFwiZmFkZSdcclxuICAgIC8vICAgXCJzbGlkZSdcclxuICAgIC8vICAgXCJjaXJjdWxhcidcclxuICAgIC8vICAgXCJ0dWJlJ1xyXG4gICAgLy8gICBcInpvb20taW4tb3V0J1xyXG4gICAgLy8gICBcInJvdGF0ZSdcclxuICAgIC8vXHJcbiAgICB0cmFuc2l0aW9uRWZmZWN0OiBcImZhZGVcIixcclxuXHJcbiAgICAvLyBEdXJhdGlvbiBpbiBtcyBmb3IgdHJhbnNpdGlvbiBhbmltYXRpb25cclxuICAgIHRyYW5zaXRpb25EdXJhdGlvbjogMzY2LFxyXG5cclxuICAgIC8vIEN1c3RvbSBDU1MgY2xhc3MgZm9yIHNsaWRlIGVsZW1lbnRcclxuICAgIHNsaWRlQ2xhc3M6IFwiXCIsXHJcblxyXG4gICAgLy8gQ3VzdG9tIENTUyBjbGFzcyBmb3IgbGF5b3V0XHJcbiAgICBiYXNlQ2xhc3M6IFwiXCIsXHJcblxyXG4gICAgLy8gQmFzZSB0ZW1wbGF0ZSBmb3IgbGF5b3V0XHJcbiAgICBiYXNlVHBsOiAnPGRpdiBjbGFzcz1cImZhbmN5Ym94LWNvbnRhaW5lclwiIHJvbGU9XCJkaWFsb2dcIiB0YWJpbmRleD1cIi0xXCI+JyArXHJcbiAgICAgICc8ZGl2IGNsYXNzPVwiZmFuY3lib3gtYmdcIj48L2Rpdj4nICtcclxuICAgICAgJzxkaXYgY2xhc3M9XCJmYW5jeWJveC1pbm5lclwiPicgK1xyXG4gICAgICAnPGRpdiBjbGFzcz1cImZhbmN5Ym94LWluZm9iYXJcIj48c3BhbiBkYXRhLWZhbmN5Ym94LWluZGV4Pjwvc3Bhbj4mbmJzcDsvJm5ic3A7PHNwYW4gZGF0YS1mYW5jeWJveC1jb3VudD48L3NwYW4+PC9kaXY+JyArXHJcbiAgICAgICc8ZGl2IGNsYXNzPVwiZmFuY3lib3gtdG9vbGJhclwiPnt7YnV0dG9uc319PC9kaXY+JyArXHJcbiAgICAgICc8ZGl2IGNsYXNzPVwiZmFuY3lib3gtbmF2aWdhdGlvblwiPnt7YXJyb3dzfX08L2Rpdj4nICtcclxuICAgICAgJzxkaXYgY2xhc3M9XCJmYW5jeWJveC1zdGFnZVwiPjwvZGl2PicgK1xyXG4gICAgICAnPGRpdiBjbGFzcz1cImZhbmN5Ym94LWNhcHRpb25cIj48ZGl2IGNsYXNzPVwiZmFuY3lib3gtY2FwdGlvbl9fYm9keVwiPjwvZGl2PjwvZGl2PicgK1xyXG4gICAgICBcIjwvZGl2PlwiICtcclxuICAgICAgXCI8L2Rpdj5cIixcclxuXHJcbiAgICAvLyBMb2FkaW5nIGluZGljYXRvciB0ZW1wbGF0ZVxyXG4gICAgc3Bpbm5lclRwbDogJzxkaXYgY2xhc3M9XCJmYW5jeWJveC1sb2FkaW5nXCI+PC9kaXY+JyxcclxuXHJcbiAgICAvLyBFcnJvciBtZXNzYWdlIHRlbXBsYXRlXHJcbiAgICBlcnJvclRwbDogJzxkaXYgY2xhc3M9XCJmYW5jeWJveC1lcnJvclwiPjxwPnt7RVJST1J9fTwvcD48L2Rpdj4nLFxyXG5cclxuICAgIGJ0blRwbDoge1xyXG4gICAgICBkb3dubG9hZDogJzxhIGRvd25sb2FkIGRhdGEtZmFuY3lib3gtZG93bmxvYWQgY2xhc3M9XCJmYW5jeWJveC1idXR0b24gZmFuY3lib3gtYnV0dG9uLS1kb3dubG9hZFwiIHRpdGxlPVwie3tET1dOTE9BRH19XCIgaHJlZj1cImphdmFzY3JpcHQ6O1wiPicgK1xyXG4gICAgICAgICc8c3ZnIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIiB2aWV3Qm94PVwiMCAwIDI0IDI0XCI+PHBhdGggZD1cIk0xOC42MiAxNy4wOVYxOUg1LjM4di0xLjkxem0tMi45Ny02Ljk2TDE3IDExLjQ1bC01IDQuODctNS00Ljg3IDEuMzYtMS4zMiAyLjY4IDIuNjRWNWgxLjkydjcuNzd6XCIvPjwvc3ZnPicgK1xyXG4gICAgICAgIFwiPC9hPlwiLFxyXG5cclxuICAgICAgem9vbTogJzxidXR0b24gZGF0YS1mYW5jeWJveC16b29tIGNsYXNzPVwiZmFuY3lib3gtYnV0dG9uIGZhbmN5Ym94LWJ1dHRvbi0tem9vbVwiIHRpdGxlPVwie3taT09NfX1cIj4nICtcclxuICAgICAgICAnPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgdmlld0JveD1cIjAgMCAyNCAyNFwiPjxwYXRoIGQ9XCJNMTguNyAxNy4zbC0zLTNhNS45IDUuOSAwIDAgMC0uNi03LjYgNS45IDUuOSAwIDAgMC04LjQgMCA1LjkgNS45IDAgMCAwIDAgOC40IDUuOSA1LjkgMCAwIDAgNy43LjdsMyAzYTEgMSAwIDAgMCAxLjMgMGMuNC0uNS40LTEgMC0xLjV6TTguMSAxMy44YTQgNCAwIDAgMSAwLTUuNyA0IDQgMCAwIDEgNS43IDAgNCA0IDAgMCAxIDAgNS43IDQgNCAwIDAgMS01LjcgMHpcIi8+PC9zdmc+JyArXHJcbiAgICAgICAgXCI8L2J1dHRvbj5cIixcclxuXHJcbiAgICAgIGNsb3NlOiAnPGJ1dHRvbiBkYXRhLWZhbmN5Ym94LWNsb3NlIGNsYXNzPVwiZmFuY3lib3gtYnV0dG9uIGZhbmN5Ym94LWJ1dHRvbi0tY2xvc2VcIiB0aXRsZT1cInt7Q0xPU0V9fVwiPicgK1xyXG4gICAgICAgICc8c3ZnIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIiB2aWV3Qm94PVwiMCAwIDI0IDI0XCI+PHBhdGggZD1cIk0xMiAxMC42TDYuNiA1LjIgNS4yIDYuNmw1LjQgNS40LTUuNCA1LjQgMS40IDEuNCA1LjQtNS40IDUuNCA1LjQgMS40LTEuNC01LjQtNS40IDUuNC01LjQtMS40LTEuNC01LjQgNS40elwiLz48L3N2Zz4nICtcclxuICAgICAgICBcIjwvYnV0dG9uPlwiLFxyXG5cclxuICAgICAgLy8gQXJyb3dzXHJcbiAgICAgIGFycm93TGVmdDogJzxidXR0b24gZGF0YS1mYW5jeWJveC1wcmV2IGNsYXNzPVwiZmFuY3lib3gtYnV0dG9uIGZhbmN5Ym94LWJ1dHRvbi0tYXJyb3dfbGVmdFwiIHRpdGxlPVwie3tQUkVWfX1cIj4nICtcclxuICAgICAgICAnPGRpdj48c3ZnIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIiB2aWV3Qm94PVwiMCAwIDI0IDI0XCI+PHBhdGggZD1cIk0xMS4yOCAxNS43bC0xLjM0IDEuMzdMNSAxMmw0Ljk0LTUuMDcgMS4zNCAxLjM4LTIuNjggMi43MkgxOXYxLjk0SDguNnpcIi8+PC9zdmc+PC9kaXY+JyArXHJcbiAgICAgICAgXCI8L2J1dHRvbj5cIixcclxuXHJcbiAgICAgIGFycm93UmlnaHQ6ICc8YnV0dG9uIGRhdGEtZmFuY3lib3gtbmV4dCBjbGFzcz1cImZhbmN5Ym94LWJ1dHRvbiBmYW5jeWJveC1idXR0b24tLWFycm93X3JpZ2h0XCIgdGl0bGU9XCJ7e05FWFR9fVwiPicgK1xyXG4gICAgICAgICc8ZGl2PjxzdmcgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIj48cGF0aCBkPVwiTTE1LjQgMTIuOTdsLTIuNjggMi43MiAxLjM0IDEuMzhMMTkgMTJsLTQuOTQtNS4wNy0xLjM0IDEuMzggMi42OCAyLjcySDV2MS45NHpcIi8+PC9zdmc+PC9kaXY+JyArXHJcbiAgICAgICAgXCI8L2J1dHRvbj5cIixcclxuXHJcbiAgICAgIC8vIFRoaXMgc21hbGwgY2xvc2UgYnV0dG9uIHdpbGwgYmUgYXBwZW5kZWQgdG8geW91ciBodG1sL2lubGluZS9hamF4IGNvbnRlbnQgYnkgZGVmYXVsdCxcclxuICAgICAgLy8gaWYgXCJzbWFsbEJ0blwiIG9wdGlvbiBpcyBub3Qgc2V0IHRvIGZhbHNlXHJcbiAgICAgIHNtYWxsQnRuOiAnPGJ1dHRvbiB0eXBlPVwiYnV0dG9uXCIgZGF0YS1mYW5jeWJveC1jbG9zZSBjbGFzcz1cImZhbmN5Ym94LWJ1dHRvbiBmYW5jeWJveC1jbG9zZS1zbWFsbFwiIHRpdGxlPVwie3tDTE9TRX19XCI+JyArXHJcbiAgICAgICAgJzxzdmcgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiIHZlcnNpb249XCIxXCIgdmlld0JveD1cIjAgMCAyNCAyNFwiPjxwYXRoIGQ9XCJNMTMgMTJsNS01LTEtMS01IDUtNS01LTEgMSA1IDUtNSA1IDEgMSA1LTUgNSA1IDEtMXpcIi8+PC9zdmc+JyArXHJcbiAgICAgICAgXCI8L2J1dHRvbj5cIlxyXG4gICAgfSxcclxuXHJcbiAgICAvLyBDb250YWluZXIgaXMgaW5qZWN0ZWQgaW50byB0aGlzIGVsZW1lbnRcclxuICAgIHBhcmVudEVsOiBcImJvZHlcIixcclxuXHJcbiAgICAvLyBIaWRlIGJyb3dzZXIgdmVydGljYWwgc2Nyb2xsYmFyczsgdXNlIGF0IHlvdXIgb3duIHJpc2tcclxuICAgIGhpZGVTY3JvbGxiYXI6IHRydWUsXHJcblxyXG4gICAgLy8gRm9jdXMgaGFuZGxpbmdcclxuICAgIC8vID09PT09PT09PT09PT09XHJcblxyXG4gICAgLy8gVHJ5IHRvIGZvY3VzIG9uIHRoZSBmaXJzdCBmb2N1c2FibGUgZWxlbWVudCBhZnRlciBvcGVuaW5nXHJcbiAgICBhdXRvRm9jdXM6IHRydWUsXHJcblxyXG4gICAgLy8gUHV0IGZvY3VzIGJhY2sgdG8gYWN0aXZlIGVsZW1lbnQgYWZ0ZXIgY2xvc2luZ1xyXG4gICAgYmFja0ZvY3VzOiB0cnVlLFxyXG5cclxuICAgIC8vIERvIG5vdCBsZXQgdXNlciB0byBmb2N1cyBvbiBlbGVtZW50IG91dHNpZGUgbW9kYWwgY29udGVudFxyXG4gICAgdHJhcEZvY3VzOiB0cnVlLFxyXG5cclxuICAgIC8vIE1vZHVsZSBzcGVjaWZpYyBvcHRpb25zXHJcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIGZ1bGxTY3JlZW46IHtcclxuICAgICAgYXV0b1N0YXJ0OiBmYWxzZVxyXG4gICAgfSxcclxuXHJcbiAgICAvLyBTZXQgYHRvdWNoOiBmYWxzZWAgdG8gZGlzYWJsZSBwYW5uaW5nL3N3aXBpbmdcclxuICAgIHRvdWNoOiB7XHJcbiAgICAgIHZlcnRpY2FsOiB0cnVlLCAvLyBBbGxvdyB0byBkcmFnIGNvbnRlbnQgdmVydGljYWxseVxyXG4gICAgICBtb21lbnR1bTogdHJ1ZSAvLyBDb250aW51ZSBtb3ZlbWVudCBhZnRlciByZWxlYXNpbmcgbW91c2UvdG91Y2ggd2hlbiBwYW5uaW5nXHJcbiAgICB9LFxyXG5cclxuICAgIC8vIEhhc2ggdmFsdWUgd2hlbiBpbml0aWFsaXppbmcgbWFudWFsbHksXHJcbiAgICAvLyBzZXQgYGZhbHNlYCB0byBkaXNhYmxlIGhhc2ggY2hhbmdlXHJcbiAgICBoYXNoOiBudWxsLFxyXG5cclxuICAgIC8vIEN1c3RvbWl6ZSBvciBhZGQgbmV3IG1lZGlhIHR5cGVzXHJcbiAgICAvLyBFeGFtcGxlOlxyXG4gICAgLypcclxuICAgICAgbWVkaWEgOiB7XHJcbiAgICAgICAgeW91dHViZSA6IHtcclxuICAgICAgICAgIHBhcmFtcyA6IHtcclxuICAgICAgICAgICAgYXV0b3BsYXkgOiAwXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAqL1xyXG4gICAgbWVkaWE6IHt9LFxyXG5cclxuICAgIHNsaWRlU2hvdzoge1xyXG4gICAgICBhdXRvU3RhcnQ6IGZhbHNlLFxyXG4gICAgICBzcGVlZDogMzAwMFxyXG4gICAgfSxcclxuXHJcbiAgICB0aHVtYnM6IHtcclxuICAgICAgYXV0b1N0YXJ0OiBmYWxzZSwgLy8gRGlzcGxheSB0aHVtYm5haWxzIG9uIG9wZW5pbmdcclxuICAgICAgaGlkZU9uQ2xvc2U6IHRydWUsIC8vIEhpZGUgdGh1bWJuYWlsIGdyaWQgd2hlbiBjbG9zaW5nIGFuaW1hdGlvbiBzdGFydHNcclxuICAgICAgcGFyZW50RWw6IFwiLmZhbmN5Ym94LWNvbnRhaW5lclwiLCAvLyBDb250YWluZXIgaXMgaW5qZWN0ZWQgaW50byB0aGlzIGVsZW1lbnRcclxuICAgICAgYXhpczogXCJ5XCIgLy8gVmVydGljYWwgKHkpIG9yIGhvcml6b250YWwgKHgpIHNjcm9sbGluZ1xyXG4gICAgfSxcclxuXHJcbiAgICAvLyBVc2UgbW91c2V3aGVlbCB0byBuYXZpZ2F0ZSBnYWxsZXJ5XHJcbiAgICAvLyBJZiAnYXV0bycgLSBlbmFibGVkIGZvciBpbWFnZXMgb25seVxyXG4gICAgd2hlZWw6IFwiYXV0b1wiLFxyXG5cclxuICAgIC8vIENhbGxiYWNrc1xyXG4gICAgLy89PT09PT09PT09XHJcblxyXG4gICAgLy8gU2VlIERvY3VtZW50YXRpb24vQVBJL0V2ZW50cyBmb3IgbW9yZSBpbmZvcm1hdGlvblxyXG4gICAgLy8gRXhhbXBsZTpcclxuICAgIC8qXHJcbiAgICAgIGFmdGVyU2hvdzogZnVuY3Rpb24oIGluc3RhbmNlLCBjdXJyZW50ICkge1xyXG4gICAgICAgIGNvbnNvbGUuaW5mbyggJ0NsaWNrZWQgZWxlbWVudDonICk7XHJcbiAgICAgICAgY29uc29sZS5pbmZvKCBjdXJyZW50Lm9wdHMuJG9yaWcgKTtcclxuICAgICAgfVxyXG4gICAgKi9cclxuXHJcbiAgICBvbkluaXQ6ICQubm9vcCwgLy8gV2hlbiBpbnN0YW5jZSBoYXMgYmVlbiBpbml0aWFsaXplZFxyXG5cclxuICAgIGJlZm9yZUxvYWQ6ICQubm9vcCwgLy8gQmVmb3JlIHRoZSBjb250ZW50IG9mIGEgc2xpZGUgaXMgYmVpbmcgbG9hZGVkXHJcbiAgICBhZnRlckxvYWQ6ICQubm9vcCwgLy8gV2hlbiB0aGUgY29udGVudCBvZiBhIHNsaWRlIGlzIGRvbmUgbG9hZGluZ1xyXG5cclxuICAgIGJlZm9yZVNob3c6ICQubm9vcCwgLy8gQmVmb3JlIG9wZW4gYW5pbWF0aW9uIHN0YXJ0c1xyXG4gICAgYWZ0ZXJTaG93OiAkLm5vb3AsIC8vIFdoZW4gY29udGVudCBpcyBkb25lIGxvYWRpbmcgYW5kIGFuaW1hdGluZ1xyXG5cclxuICAgIGJlZm9yZUNsb3NlOiAkLm5vb3AsIC8vIEJlZm9yZSB0aGUgaW5zdGFuY2UgYXR0ZW1wdHMgdG8gY2xvc2UuIFJldHVybiBmYWxzZSB0byBjYW5jZWwgdGhlIGNsb3NlLlxyXG4gICAgYWZ0ZXJDbG9zZTogJC5ub29wLCAvLyBBZnRlciBpbnN0YW5jZSBoYXMgYmVlbiBjbG9zZWRcclxuXHJcbiAgICBvbkFjdGl2YXRlOiAkLm5vb3AsIC8vIFdoZW4gaW5zdGFuY2UgaXMgYnJvdWdodCB0byBmcm9udFxyXG4gICAgb25EZWFjdGl2YXRlOiAkLm5vb3AsIC8vIFdoZW4gb3RoZXIgaW5zdGFuY2UgaGFzIGJlZW4gYWN0aXZhdGVkXHJcblxyXG4gICAgLy8gSW50ZXJhY3Rpb25cclxuICAgIC8vID09PT09PT09PT09XHJcblxyXG4gICAgLy8gVXNlIG9wdGlvbnMgYmVsb3cgdG8gY3VzdG9taXplIHRha2VuIGFjdGlvbiB3aGVuIHVzZXIgY2xpY2tzIG9yIGRvdWJsZSBjbGlja3Mgb24gdGhlIGZhbmN5Qm94IGFyZWEsXHJcbiAgICAvLyBlYWNoIG9wdGlvbiBjYW4gYmUgc3RyaW5nIG9yIG1ldGhvZCB0aGF0IHJldHVybnMgdmFsdWUuXHJcbiAgICAvL1xyXG4gICAgLy8gUG9zc2libGUgdmFsdWVzOlxyXG4gICAgLy8gICBcImNsb3NlXCIgICAgICAgICAgIC0gY2xvc2UgaW5zdGFuY2VcclxuICAgIC8vICAgXCJuZXh0XCIgICAgICAgICAgICAtIG1vdmUgdG8gbmV4dCBnYWxsZXJ5IGl0ZW1cclxuICAgIC8vICAgXCJuZXh0T3JDbG9zZVwiICAgICAtIG1vdmUgdG8gbmV4dCBnYWxsZXJ5IGl0ZW0gb3IgY2xvc2UgaWYgZ2FsbGVyeSBoYXMgb25seSBvbmUgaXRlbVxyXG4gICAgLy8gICBcInRvZ2dsZUNvbnRyb2xzXCIgIC0gc2hvdy9oaWRlIGNvbnRyb2xzXHJcbiAgICAvLyAgIFwiem9vbVwiICAgICAgICAgICAgLSB6b29tIGltYWdlIChpZiBsb2FkZWQpXHJcbiAgICAvLyAgIGZhbHNlICAgICAgICAgICAgIC0gZG8gbm90aGluZ1xyXG5cclxuICAgIC8vIENsaWNrZWQgb24gdGhlIGNvbnRlbnRcclxuICAgIGNsaWNrQ29udGVudDogZnVuY3Rpb24gKGN1cnJlbnQsIGV2ZW50KSB7XHJcbiAgICAgIHJldHVybiBjdXJyZW50LnR5cGUgPT09IFwiaW1hZ2VcIiA/IFwiem9vbVwiIDogZmFsc2U7XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIENsaWNrZWQgb24gdGhlIHNsaWRlXHJcbiAgICBjbGlja1NsaWRlOiBcImNsb3NlXCIsXHJcblxyXG4gICAgLy8gQ2xpY2tlZCBvbiB0aGUgYmFja2dyb3VuZCAoYmFja2Ryb3ApIGVsZW1lbnQ7XHJcbiAgICAvLyBpZiB5b3UgaGF2ZSBub3QgY2hhbmdlZCB0aGUgbGF5b3V0LCB0aGVuIG1vc3QgbGlrZWx5IHlvdSBuZWVkIHRvIHVzZSBgY2xpY2tTbGlkZWAgb3B0aW9uXHJcbiAgICBjbGlja091dHNpZGU6IFwiY2xvc2VcIixcclxuXHJcbiAgICAvLyBTYW1lIGFzIHByZXZpb3VzIHR3bywgYnV0IGZvciBkb3VibGUgY2xpY2tcclxuICAgIGRibGNsaWNrQ29udGVudDogZmFsc2UsXHJcbiAgICBkYmxjbGlja1NsaWRlOiBmYWxzZSxcclxuICAgIGRibGNsaWNrT3V0c2lkZTogZmFsc2UsXHJcblxyXG4gICAgLy8gQ3VzdG9tIG9wdGlvbnMgd2hlbiBtb2JpbGUgZGV2aWNlIGlzIGRldGVjdGVkXHJcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICBtb2JpbGU6IHtcclxuICAgICAgcHJldmVudENhcHRpb25PdmVybGFwOiBmYWxzZSxcclxuICAgICAgaWRsZVRpbWU6IGZhbHNlLFxyXG4gICAgICBjbGlja0NvbnRlbnQ6IGZ1bmN0aW9uIChjdXJyZW50LCBldmVudCkge1xyXG4gICAgICAgIHJldHVybiBjdXJyZW50LnR5cGUgPT09IFwiaW1hZ2VcIiA/IFwidG9nZ2xlQ29udHJvbHNcIiA6IGZhbHNlO1xyXG4gICAgICB9LFxyXG4gICAgICBjbGlja1NsaWRlOiBmdW5jdGlvbiAoY3VycmVudCwgZXZlbnQpIHtcclxuICAgICAgICByZXR1cm4gY3VycmVudC50eXBlID09PSBcImltYWdlXCIgPyBcInRvZ2dsZUNvbnRyb2xzXCIgOiBcImNsb3NlXCI7XHJcbiAgICAgIH0sXHJcbiAgICAgIGRibGNsaWNrQ29udGVudDogZnVuY3Rpb24gKGN1cnJlbnQsIGV2ZW50KSB7XHJcbiAgICAgICAgcmV0dXJuIGN1cnJlbnQudHlwZSA9PT0gXCJpbWFnZVwiID8gXCJ6b29tXCIgOiBmYWxzZTtcclxuICAgICAgfSxcclxuICAgICAgZGJsY2xpY2tTbGlkZTogZnVuY3Rpb24gKGN1cnJlbnQsIGV2ZW50KSB7XHJcbiAgICAgICAgcmV0dXJuIGN1cnJlbnQudHlwZSA9PT0gXCJpbWFnZVwiID8gXCJ6b29tXCIgOiBmYWxzZTtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICAvLyBJbnRlcm5hdGlvbmFsaXphdGlvblxyXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICBsYW5nOiBcImVuXCIsXHJcbiAgICBpMThuOiB7XHJcbiAgICAgIGVuOiB7XHJcbiAgICAgICAgQ0xPU0U6IFwiQ2xvc2VcIixcclxuICAgICAgICBORVhUOiBcIk5leHRcIixcclxuICAgICAgICBQUkVWOiBcIlByZXZpb3VzXCIsXHJcbiAgICAgICAgRVJST1I6IFwiVGhlIHJlcXVlc3RlZCBjb250ZW50IGNhbm5vdCBiZSBsb2FkZWQuIDxici8+IFBsZWFzZSB0cnkgYWdhaW4gbGF0ZXIuXCIsXHJcbiAgICAgICAgUExBWV9TVEFSVDogXCJTdGFydCBzbGlkZXNob3dcIixcclxuICAgICAgICBQTEFZX1NUT1A6IFwiUGF1c2Ugc2xpZGVzaG93XCIsXHJcbiAgICAgICAgRlVMTF9TQ1JFRU46IFwiRnVsbCBzY3JlZW5cIixcclxuICAgICAgICBUSFVNQlM6IFwiVGh1bWJuYWlsc1wiLFxyXG4gICAgICAgIERPV05MT0FEOiBcIkRvd25sb2FkXCIsXHJcbiAgICAgICAgU0hBUkU6IFwiU2hhcmVcIixcclxuICAgICAgICBaT09NOiBcIlpvb21cIlxyXG4gICAgICB9LFxyXG4gICAgICBkZToge1xyXG4gICAgICAgIENMT1NFOiBcIlNjaGxpZSZzemxpZztlblwiLFxyXG4gICAgICAgIE5FWFQ6IFwiV2VpdGVyXCIsXHJcbiAgICAgICAgUFJFVjogXCJadXImdXVtbDtja1wiLFxyXG4gICAgICAgIEVSUk9SOiBcIkRpZSBhbmdlZm9yZGVydGVuIERhdGVuIGtvbm50ZW4gbmljaHQgZ2VsYWRlbiB3ZXJkZW4uIDxici8+IEJpdHRlIHZlcnN1Y2hlbiBTaWUgZXMgc3AmYXVtbDt0ZXIgbm9jaG1hbC5cIixcclxuICAgICAgICBQTEFZX1NUQVJUOiBcIkRpYXNjaGF1IHN0YXJ0ZW5cIixcclxuICAgICAgICBQTEFZX1NUT1A6IFwiRGlhc2NoYXUgYmVlbmRlblwiLFxyXG4gICAgICAgIEZVTExfU0NSRUVOOiBcIlZvbGxiaWxkXCIsXHJcbiAgICAgICAgVEhVTUJTOiBcIlZvcnNjaGF1YmlsZGVyXCIsXHJcbiAgICAgICAgRE9XTkxPQUQ6IFwiSGVydW50ZXJsYWRlblwiLFxyXG4gICAgICAgIFNIQVJFOiBcIlRlaWxlblwiLFxyXG4gICAgICAgIFpPT006IFwiVmVyZ3Imb3VtbDsmc3psaWc7ZXJuXCJcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIC8vIEZldyB1c2VmdWwgdmFyaWFibGVzIGFuZCBtZXRob2RzXHJcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgdmFyICRXID0gJCh3aW5kb3cpO1xyXG4gIHZhciAkRCA9ICQoZG9jdW1lbnQpO1xyXG5cclxuICB2YXIgY2FsbGVkID0gMDtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgYW4gb2JqZWN0IGlzIGEgalF1ZXJ5IG9iamVjdCBhbmQgbm90IGEgbmF0aXZlIEphdmFTY3JpcHQgb2JqZWN0XHJcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbiAgdmFyIGlzUXVlcnkgPSBmdW5jdGlvbiAob2JqKSB7XHJcbiAgICByZXR1cm4gb2JqICYmIG9iai5oYXNPd25Qcm9wZXJ0eSAmJiBvYmogaW5zdGFuY2VvZiAkO1xyXG4gIH07XHJcblxyXG4gIC8vIEhhbmRsZSBtdWx0aXBsZSBicm93c2VycyBmb3IgXCJyZXF1ZXN0QW5pbWF0aW9uRnJhbWVcIiBhbmQgXCJjYW5jZWxBbmltYXRpb25GcmFtZVwiXHJcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4gIHZhciByZXF1ZXN0QUZyYW1lID0gKGZ1bmN0aW9uICgpIHtcclxuICAgIHJldHVybiAoXHJcbiAgICAgIHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUgfHxcclxuICAgICAgd2luZG93LndlYmtpdFJlcXVlc3RBbmltYXRpb25GcmFtZSB8fFxyXG4gICAgICB3aW5kb3cubW96UmVxdWVzdEFuaW1hdGlvbkZyYW1lIHx8XHJcbiAgICAgIHdpbmRvdy5vUmVxdWVzdEFuaW1hdGlvbkZyYW1lIHx8XHJcbiAgICAgIC8vIGlmIGFsbCBlbHNlIGZhaWxzLCB1c2Ugc2V0VGltZW91dFxyXG4gICAgICBmdW5jdGlvbiAoY2FsbGJhY2spIHtcclxuICAgICAgICByZXR1cm4gd2luZG93LnNldFRpbWVvdXQoY2FsbGJhY2ssIDEwMDAgLyA2MCk7XHJcbiAgICAgIH1cclxuICAgICk7XHJcbiAgfSkoKTtcclxuXHJcbiAgdmFyIGNhbmNlbEFGcmFtZSA9IChmdW5jdGlvbiAoKSB7XHJcbiAgICByZXR1cm4gKFxyXG4gICAgICB3aW5kb3cuY2FuY2VsQW5pbWF0aW9uRnJhbWUgfHxcclxuICAgICAgd2luZG93LndlYmtpdENhbmNlbEFuaW1hdGlvbkZyYW1lIHx8XHJcbiAgICAgIHdpbmRvdy5tb3pDYW5jZWxBbmltYXRpb25GcmFtZSB8fFxyXG4gICAgICB3aW5kb3cub0NhbmNlbEFuaW1hdGlvbkZyYW1lIHx8XHJcbiAgICAgIGZ1bmN0aW9uIChpZCkge1xyXG4gICAgICAgIHdpbmRvdy5jbGVhclRpbWVvdXQoaWQpO1xyXG4gICAgICB9XHJcbiAgICApO1xyXG4gIH0pKCk7XHJcblxyXG4gIC8vIERldGVjdCB0aGUgc3VwcG9ydGVkIHRyYW5zaXRpb24tZW5kIGV2ZW50IHByb3BlcnR5IG5hbWVcclxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbiAgdmFyIHRyYW5zaXRpb25FbmQgPSAoZnVuY3Rpb24gKCkge1xyXG4gICAgdmFyIGVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImZha2VlbGVtZW50XCIpLFxyXG4gICAgICB0O1xyXG5cclxuICAgIHZhciB0cmFuc2l0aW9ucyA9IHtcclxuICAgICAgdHJhbnNpdGlvbjogXCJ0cmFuc2l0aW9uZW5kXCIsXHJcbiAgICAgIE9UcmFuc2l0aW9uOiBcIm9UcmFuc2l0aW9uRW5kXCIsXHJcbiAgICAgIE1velRyYW5zaXRpb246IFwidHJhbnNpdGlvbmVuZFwiLFxyXG4gICAgICBXZWJraXRUcmFuc2l0aW9uOiBcIndlYmtpdFRyYW5zaXRpb25FbmRcIlxyXG4gICAgfTtcclxuXHJcbiAgICBmb3IgKHQgaW4gdHJhbnNpdGlvbnMpIHtcclxuICAgICAgaWYgKGVsLnN0eWxlW3RdICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICByZXR1cm4gdHJhbnNpdGlvbnNbdF07XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gXCJ0cmFuc2l0aW9uZW5kXCI7XHJcbiAgfSkoKTtcclxuXHJcbiAgLy8gRm9yY2UgcmVkcmF3IG9uIGFuIGVsZW1lbnQuXHJcbiAgLy8gVGhpcyBoZWxwcyBpbiBjYXNlcyB3aGVyZSB0aGUgYnJvd3NlciBkb2Vzbid0IHJlZHJhdyBhbiB1cGRhdGVkIGVsZW1lbnQgcHJvcGVybHlcclxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4gIHZhciBmb3JjZVJlZHJhdyA9IGZ1bmN0aW9uICgkZWwpIHtcclxuICAgIHJldHVybiAkZWwgJiYgJGVsLmxlbmd0aCAmJiAkZWxbMF0ub2Zmc2V0SGVpZ2h0O1xyXG4gIH07XHJcblxyXG4gIC8vIEV4Y2x1ZGUgYXJyYXkgKGBidXR0b25zYCkgb3B0aW9ucyBmcm9tIGRlZXAgbWVyZ2luZ1xyXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4gIHZhciBtZXJnZU9wdHMgPSBmdW5jdGlvbiAob3B0czEsIG9wdHMyKSB7XHJcbiAgICB2YXIgcmV6ID0gJC5leHRlbmQodHJ1ZSwge30sIG9wdHMxLCBvcHRzMik7XHJcblxyXG4gICAgJC5lYWNoKG9wdHMyLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xyXG4gICAgICBpZiAoJC5pc0FycmF5KHZhbHVlKSkge1xyXG4gICAgICAgIHJleltrZXldID0gdmFsdWU7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiByZXo7XHJcbiAgfTtcclxuXHJcbiAgLy8gSG93IG11Y2ggb2YgYW4gZWxlbWVudCBpcyB2aXNpYmxlIGluIHZpZXdwb3J0XHJcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gIHZhciBpblZpZXdwb3J0ID0gZnVuY3Rpb24gKGVsZW0pIHtcclxuICAgIHZhciBlbGVtQ2VudGVyLCByZXo7XHJcblxyXG4gICAgaWYgKCFlbGVtIHx8IGVsZW0ub3duZXJEb2N1bWVudCAhPT0gZG9jdW1lbnQpIHtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgICQoXCIuZmFuY3lib3gtY29udGFpbmVyXCIpLmNzcyhcInBvaW50ZXItZXZlbnRzXCIsIFwibm9uZVwiKTtcclxuXHJcbiAgICBlbGVtQ2VudGVyID0ge1xyXG4gICAgICB4OiBlbGVtLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmxlZnQgKyBlbGVtLm9mZnNldFdpZHRoIC8gMixcclxuICAgICAgeTogZWxlbS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS50b3AgKyBlbGVtLm9mZnNldEhlaWdodCAvIDJcclxuICAgIH07XHJcblxyXG4gICAgcmV6ID0gZG9jdW1lbnQuZWxlbWVudEZyb21Qb2ludChlbGVtQ2VudGVyLngsIGVsZW1DZW50ZXIueSkgPT09IGVsZW07XHJcblxyXG4gICAgJChcIi5mYW5jeWJveC1jb250YWluZXJcIikuY3NzKFwicG9pbnRlci1ldmVudHNcIiwgXCJcIik7XHJcblxyXG4gICAgcmV0dXJuIHJlejtcclxuICB9O1xyXG5cclxuICAvLyBDbGFzcyBkZWZpbml0aW9uXHJcbiAgLy8gPT09PT09PT09PT09PT09PVxyXG5cclxuICB2YXIgRmFuY3lCb3ggPSBmdW5jdGlvbiAoY29udGVudCwgb3B0cywgaW5kZXgpIHtcclxuICAgIHZhciBzZWxmID0gdGhpcztcclxuXHJcbiAgICBzZWxmLm9wdHMgPSBtZXJnZU9wdHMoe1xyXG4gICAgICBpbmRleDogaW5kZXhcclxuICAgIH0sICQuZmFuY3lib3guZGVmYXVsdHMpO1xyXG5cclxuICAgIGlmICgkLmlzUGxhaW5PYmplY3Qob3B0cykpIHtcclxuICAgICAgc2VsZi5vcHRzID0gbWVyZ2VPcHRzKHNlbGYub3B0cywgb3B0cyk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCQuZmFuY3lib3guaXNNb2JpbGUpIHtcclxuICAgICAgc2VsZi5vcHRzID0gbWVyZ2VPcHRzKHNlbGYub3B0cywgc2VsZi5vcHRzLm1vYmlsZSk7XHJcbiAgICB9XHJcblxyXG4gICAgc2VsZi5pZCA9IHNlbGYub3B0cy5pZCB8fCArK2NhbGxlZDtcclxuXHJcbiAgICBzZWxmLmN1cnJJbmRleCA9IHBhcnNlSW50KHNlbGYub3B0cy5pbmRleCwgMTApIHx8IDA7XHJcbiAgICBzZWxmLnByZXZJbmRleCA9IG51bGw7XHJcblxyXG4gICAgc2VsZi5wcmV2UG9zID0gbnVsbDtcclxuICAgIHNlbGYuY3VyclBvcyA9IDA7XHJcblxyXG4gICAgc2VsZi5maXJzdFJ1biA9IHRydWU7XHJcblxyXG4gICAgLy8gQWxsIGdyb3VwIGl0ZW1zXHJcbiAgICBzZWxmLmdyb3VwID0gW107XHJcblxyXG4gICAgLy8gRXhpc3Rpbmcgc2xpZGVzIChmb3IgY3VycmVudCwgbmV4dCBhbmQgcHJldmlvdXMgZ2FsbGVyeSBpdGVtcylcclxuICAgIHNlbGYuc2xpZGVzID0ge307XHJcblxyXG4gICAgLy8gQ3JlYXRlIGdyb3VwIGVsZW1lbnRzXHJcbiAgICBzZWxmLmFkZENvbnRlbnQoY29udGVudCk7XHJcblxyXG4gICAgaWYgKCFzZWxmLmdyb3VwLmxlbmd0aCkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgc2VsZi5pbml0KCk7XHJcbiAgfTtcclxuXHJcbiAgJC5leHRlbmQoRmFuY3lCb3gucHJvdG90eXBlLCB7XHJcbiAgICAvLyBDcmVhdGUgRE9NIHN0cnVjdHVyZVxyXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICBpbml0OiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHZhciBzZWxmID0gdGhpcyxcclxuICAgICAgICBmaXJzdEl0ZW0gPSBzZWxmLmdyb3VwW3NlbGYuY3VyckluZGV4XSxcclxuICAgICAgICBmaXJzdEl0ZW1PcHRzID0gZmlyc3RJdGVtLm9wdHMsXHJcbiAgICAgICAgJGNvbnRhaW5lcixcclxuICAgICAgICBidXR0b25TdHI7XHJcblxyXG4gICAgICBpZiAoZmlyc3RJdGVtT3B0cy5jbG9zZUV4aXN0aW5nKSB7XHJcbiAgICAgICAgJC5mYW5jeWJveC5jbG9zZSh0cnVlKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSGlkZSBzY3JvbGxiYXJzXHJcbiAgICAgIC8vID09PT09PT09PT09PT09PVxyXG5cclxuICAgICAgJChcImJvZHlcIikuYWRkQ2xhc3MoXCJmYW5jeWJveC1hY3RpdmVcIik7XHJcblxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgISQuZmFuY3lib3guZ2V0SW5zdGFuY2UoKSAmJlxyXG4gICAgICAgIGZpcnN0SXRlbU9wdHMuaGlkZVNjcm9sbGJhciAhPT0gZmFsc2UgJiZcclxuICAgICAgICAhJC5mYW5jeWJveC5pc01vYmlsZSAmJlxyXG4gICAgICAgIGRvY3VtZW50LmJvZHkuc2Nyb2xsSGVpZ2h0ID4gd2luZG93LmlubmVySGVpZ2h0XHJcbiAgICAgICkge1xyXG4gICAgICAgICQoXCJoZWFkXCIpLmFwcGVuZChcclxuICAgICAgICAgICc8c3R5bGUgaWQ9XCJmYW5jeWJveC1zdHlsZS1ub3Njcm9sbFwiIHR5cGU9XCJ0ZXh0L2Nzc1wiPi5jb21wZW5zYXRlLWZvci1zY3JvbGxiYXJ7bWFyZ2luLXJpZ2h0OicgK1xyXG4gICAgICAgICAgKHdpbmRvdy5pbm5lcldpZHRoIC0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudFdpZHRoKSArXHJcbiAgICAgICAgICBcInB4O308L3N0eWxlPlwiXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgJChcImJvZHlcIikuYWRkQ2xhc3MoXCJjb21wZW5zYXRlLWZvci1zY3JvbGxiYXJcIik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEJ1aWxkIGh0bWwgbWFya3VwIGFuZCBzZXQgcmVmZXJlbmNlc1xyXG4gICAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICAgIC8vIEJ1aWxkIGh0bWwgY29kZSBmb3IgYnV0dG9ucyBhbmQgaW5zZXJ0IGludG8gbWFpbiB0ZW1wbGF0ZVxyXG4gICAgICBidXR0b25TdHIgPSBcIlwiO1xyXG5cclxuICAgICAgJC5lYWNoKGZpcnN0SXRlbU9wdHMuYnV0dG9ucywgZnVuY3Rpb24gKGluZGV4LCB2YWx1ZSkge1xyXG4gICAgICAgIGJ1dHRvblN0ciArPSBmaXJzdEl0ZW1PcHRzLmJ0blRwbFt2YWx1ZV0gfHwgXCJcIjtcclxuICAgICAgfSk7XHJcblxyXG4gICAgICAvLyBDcmVhdGUgbWFya3VwIGZyb20gYmFzZSB0ZW1wbGF0ZSwgaXQgd2lsbCBiZSBpbml0aWFsbHkgaGlkZGVuIHRvXHJcbiAgICAgIC8vIGF2b2lkIHVubmVjZXNzYXJ5IHdvcmsgbGlrZSBwYWludGluZyB3aGlsZSBpbml0aWFsaXppbmcgaXMgbm90IGNvbXBsZXRlXHJcbiAgICAgICRjb250YWluZXIgPSAkKFxyXG4gICAgICAgICAgc2VsZi50cmFuc2xhdGUoXHJcbiAgICAgICAgICAgIHNlbGYsXHJcbiAgICAgICAgICAgIGZpcnN0SXRlbU9wdHMuYmFzZVRwbFxyXG4gICAgICAgICAgICAucmVwbGFjZShcInt7YnV0dG9uc319XCIsIGJ1dHRvblN0cilcclxuICAgICAgICAgICAgLnJlcGxhY2UoXCJ7e2Fycm93c319XCIsIGZpcnN0SXRlbU9wdHMuYnRuVHBsLmFycm93TGVmdCArIGZpcnN0SXRlbU9wdHMuYnRuVHBsLmFycm93UmlnaHQpXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgKVxyXG4gICAgICAgIC5hdHRyKFwiaWRcIiwgXCJmYW5jeWJveC1jb250YWluZXItXCIgKyBzZWxmLmlkKVxyXG4gICAgICAgIC5hZGRDbGFzcyhmaXJzdEl0ZW1PcHRzLmJhc2VDbGFzcylcclxuICAgICAgICAuZGF0YShcIkZhbmN5Qm94XCIsIHNlbGYpXHJcbiAgICAgICAgLmFwcGVuZFRvKGZpcnN0SXRlbU9wdHMucGFyZW50RWwpO1xyXG5cclxuICAgICAgLy8gQ3JlYXRlIG9iamVjdCBob2xkaW5nIHJlZmVyZW5jZXMgdG8galF1ZXJ5IHdyYXBwZWQgbm9kZXNcclxuICAgICAgc2VsZi4kcmVmcyA9IHtcclxuICAgICAgICBjb250YWluZXI6ICRjb250YWluZXJcclxuICAgICAgfTtcclxuXHJcbiAgICAgIFtcImJnXCIsIFwiaW5uZXJcIiwgXCJpbmZvYmFyXCIsIFwidG9vbGJhclwiLCBcInN0YWdlXCIsIFwiY2FwdGlvblwiLCBcIm5hdmlnYXRpb25cIl0uZm9yRWFjaChmdW5jdGlvbiAoaXRlbSkge1xyXG4gICAgICAgIHNlbGYuJHJlZnNbaXRlbV0gPSAkY29udGFpbmVyLmZpbmQoXCIuZmFuY3lib3gtXCIgKyBpdGVtKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgICBzZWxmLnRyaWdnZXIoXCJvbkluaXRcIik7XHJcblxyXG4gICAgICAvLyBFbmFibGUgZXZlbnRzLCBkZWFjdGl2ZSBwcmV2aW91cyBpbnN0YW5jZXNcclxuICAgICAgc2VsZi5hY3RpdmF0ZSgpO1xyXG5cclxuICAgICAgLy8gQnVpbGQgc2xpZGVzLCBsb2FkIGFuZCByZXZlYWwgY29udGVudFxyXG4gICAgICBzZWxmLmp1bXBUbyhzZWxmLmN1cnJJbmRleCk7XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIFNpbXBsZSBpMThuIHN1cHBvcnQgLSByZXBsYWNlcyBvYmplY3Qga2V5cyBmb3VuZCBpbiB0ZW1wbGF0ZVxyXG4gICAgLy8gd2l0aCBjb3JyZXNwb25kaW5nIHZhbHVlc1xyXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgdHJhbnNsYXRlOiBmdW5jdGlvbiAob2JqLCBzdHIpIHtcclxuICAgICAgdmFyIGFyciA9IG9iai5vcHRzLmkxOG5bb2JqLm9wdHMubGFuZ10gfHwgb2JqLm9wdHMuaTE4bi5lbjtcclxuXHJcbiAgICAgIHJldHVybiBzdHIucmVwbGFjZSgvXFx7XFx7KFxcdyspXFx9XFx9L2csIGZ1bmN0aW9uIChtYXRjaCwgbikge1xyXG4gICAgICAgIHJldHVybiBhcnJbbl0gPT09IHVuZGVmaW5lZCA/IG1hdGNoIDogYXJyW25dO1xyXG4gICAgICB9KTtcclxuICAgIH0sXHJcblxyXG4gICAgLy8gUG9wdWxhdGUgY3VycmVudCBncm91cCB3aXRoIGZyZXNoIGNvbnRlbnRcclxuICAgIC8vIENoZWNrIGlmIGVhY2ggb2JqZWN0IGhhcyB2YWxpZCB0eXBlIGFuZCBjb250ZW50XHJcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIGFkZENvbnRlbnQ6IGZ1bmN0aW9uIChjb250ZW50KSB7XHJcbiAgICAgIHZhciBzZWxmID0gdGhpcyxcclxuICAgICAgICBpdGVtcyA9ICQubWFrZUFycmF5KGNvbnRlbnQpLFxyXG4gICAgICAgIHRodW1icztcclxuXHJcbiAgICAgICQuZWFjaChpdGVtcywgZnVuY3Rpb24gKGksIGl0ZW0pIHtcclxuICAgICAgICB2YXIgb2JqID0ge30sXHJcbiAgICAgICAgICBvcHRzID0ge30sXHJcbiAgICAgICAgICAkaXRlbSxcclxuICAgICAgICAgIHR5cGUsXHJcbiAgICAgICAgICBmb3VuZCxcclxuICAgICAgICAgIHNyYyxcclxuICAgICAgICAgIHNyY1BhcnRzO1xyXG5cclxuICAgICAgICAvLyBTdGVwIDEgLSBNYWtlIHN1cmUgd2UgaGF2ZSBhbiBvYmplY3RcclxuICAgICAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICAgICAgaWYgKCQuaXNQbGFpbk9iamVjdChpdGVtKSkge1xyXG4gICAgICAgICAgLy8gV2UgcHJvYmFibHkgaGF2ZSBtYW51YWwgdXNhZ2UgaGVyZSwgc29tZXRoaW5nIGxpa2VcclxuICAgICAgICAgIC8vICQuZmFuY3lib3gub3BlbiggWyB7IHNyYyA6IFwiaW1hZ2UuanBnXCIsIHR5cGUgOiBcImltYWdlXCIgfSBdIClcclxuXHJcbiAgICAgICAgICBvYmogPSBpdGVtO1xyXG4gICAgICAgICAgb3B0cyA9IGl0ZW0ub3B0cyB8fCBpdGVtO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoJC50eXBlKGl0ZW0pID09PSBcIm9iamVjdFwiICYmICQoaXRlbSkubGVuZ3RoKSB7XHJcbiAgICAgICAgICAvLyBIZXJlIHdlIHByb2JhYmx5IGhhdmUgalF1ZXJ5IGNvbGxlY3Rpb24gcmV0dXJuZWQgYnkgc29tZSBzZWxlY3RvclxyXG4gICAgICAgICAgJGl0ZW0gPSAkKGl0ZW0pO1xyXG5cclxuICAgICAgICAgIC8vIFN1cHBvcnQgYXR0cmlidXRlcyBsaWtlIGBkYXRhLW9wdGlvbnM9J3tcInRvdWNoXCIgOiBmYWxzZX0nYCBhbmQgYGRhdGEtdG91Y2g9J2ZhbHNlJ2BcclxuICAgICAgICAgIG9wdHMgPSAkaXRlbS5kYXRhKCkgfHwge307XHJcbiAgICAgICAgICBvcHRzID0gJC5leHRlbmQodHJ1ZSwge30sIG9wdHMsIG9wdHMub3B0aW9ucyk7XHJcblxyXG4gICAgICAgICAgLy8gSGVyZSB3ZSBzdG9yZSBjbGlja2VkIGVsZW1lbnRcclxuICAgICAgICAgIG9wdHMuJG9yaWcgPSAkaXRlbTtcclxuXHJcbiAgICAgICAgICBvYmouc3JjID0gc2VsZi5vcHRzLnNyYyB8fCBvcHRzLnNyYyB8fCAkaXRlbS5hdHRyKFwiaHJlZlwiKTtcclxuXHJcbiAgICAgICAgICAvLyBBc3N1bWUgdGhhdCBzaW1wbGUgc3ludGF4IGlzIHVzZWQsIGZvciBleGFtcGxlOlxyXG4gICAgICAgICAgLy8gICBgJC5mYW5jeWJveC5vcGVuKCAkKFwiI3Rlc3RcIiksIHt9ICk7YFxyXG4gICAgICAgICAgaWYgKCFvYmoudHlwZSAmJiAhb2JqLnNyYykge1xyXG4gICAgICAgICAgICBvYmoudHlwZSA9IFwiaW5saW5lXCI7XHJcbiAgICAgICAgICAgIG9iai5zcmMgPSBpdGVtO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAvLyBBc3N1bWUgd2UgaGF2ZSBhIHNpbXBsZSBodG1sIGNvZGUsIGZvciBleGFtcGxlOlxyXG4gICAgICAgICAgLy8gICAkLmZhbmN5Ym94Lm9wZW4oICc8ZGl2PjxoMT5IaSE8L2gxPjwvZGl2PicgKTtcclxuICAgICAgICAgIG9iaiA9IHtcclxuICAgICAgICAgICAgdHlwZTogXCJodG1sXCIsXHJcbiAgICAgICAgICAgIHNyYzogaXRlbSArIFwiXCJcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBFYWNoIGdhbGxlcnkgb2JqZWN0IGhhcyBmdWxsIGNvbGxlY3Rpb24gb2Ygb3B0aW9uc1xyXG4gICAgICAgIG9iai5vcHRzID0gJC5leHRlbmQodHJ1ZSwge30sIHNlbGYub3B0cywgb3B0cyk7XHJcblxyXG4gICAgICAgIC8vIERvIG5vdCBtZXJnZSBidXR0b25zIGFycmF5XHJcbiAgICAgICAgaWYgKCQuaXNBcnJheShvcHRzLmJ1dHRvbnMpKSB7XHJcbiAgICAgICAgICBvYmoub3B0cy5idXR0b25zID0gb3B0cy5idXR0b25zO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKCQuZmFuY3lib3guaXNNb2JpbGUgJiYgb2JqLm9wdHMubW9iaWxlKSB7XHJcbiAgICAgICAgICBvYmoub3B0cyA9IG1lcmdlT3B0cyhvYmoub3B0cywgb2JqLm9wdHMubW9iaWxlKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFN0ZXAgMiAtIE1ha2Ugc3VyZSB3ZSBoYXZlIGNvbnRlbnQgdHlwZSwgaWYgbm90IC0gdHJ5IHRvIGd1ZXNzXHJcbiAgICAgICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICAgICAgdHlwZSA9IG9iai50eXBlIHx8IG9iai5vcHRzLnR5cGU7XHJcbiAgICAgICAgc3JjID0gb2JqLnNyYyB8fCBcIlwiO1xyXG5cclxuICAgICAgICBpZiAoIXR5cGUgJiYgc3JjKSB7XHJcbiAgICAgICAgICBpZiAoKGZvdW5kID0gc3JjLm1hdGNoKC9cXC4obXA0fG1vdnxvZ3Z8d2VibSkoKFxcP3wjKS4qKT8kL2kpKSkge1xyXG4gICAgICAgICAgICB0eXBlID0gXCJ2aWRlb1wiO1xyXG5cclxuICAgICAgICAgICAgaWYgKCFvYmoub3B0cy52aWRlby5mb3JtYXQpIHtcclxuICAgICAgICAgICAgICBvYmoub3B0cy52aWRlby5mb3JtYXQgPSBcInZpZGVvL1wiICsgKGZvdW5kWzFdID09PSBcIm9ndlwiID8gXCJvZ2dcIiA6IGZvdW5kWzFdKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIGlmIChzcmMubWF0Y2goLyheZGF0YTppbWFnZVxcL1thLXowLTkrXFwvPV0qLCl8KFxcLihqcChlfGd8ZWcpfGdpZnxwbmd8Ym1wfHdlYnB8c3ZnfGljbykoKFxcP3wjKS4qKT8kKS9pKSkge1xyXG4gICAgICAgICAgICB0eXBlID0gXCJpbWFnZVwiO1xyXG4gICAgICAgICAgfSBlbHNlIGlmIChzcmMubWF0Y2goL1xcLihwZGYpKChcXD98IykuKik/JC9pKSkge1xyXG4gICAgICAgICAgICB0eXBlID0gXCJpZnJhbWVcIjtcclxuICAgICAgICAgICAgb2JqID0gJC5leHRlbmQodHJ1ZSwgb2JqLCB7XHJcbiAgICAgICAgICAgICAgY29udGVudFR5cGU6IFwicGRmXCIsXHJcbiAgICAgICAgICAgICAgb3B0czoge1xyXG4gICAgICAgICAgICAgICAgaWZyYW1lOiB7XHJcbiAgICAgICAgICAgICAgICAgIHByZWxvYWQ6IGZhbHNlXHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICAgIH0gZWxzZSBpZiAoc3JjLmNoYXJBdCgwKSA9PT0gXCIjXCIpIHtcclxuICAgICAgICAgICAgdHlwZSA9IFwiaW5saW5lXCI7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAodHlwZSkge1xyXG4gICAgICAgICAgb2JqLnR5cGUgPSB0eXBlO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBzZWxmLnRyaWdnZXIoXCJvYmplY3ROZWVkc1R5cGVcIiwgb2JqKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmICghb2JqLmNvbnRlbnRUeXBlKSB7XHJcbiAgICAgICAgICBvYmouY29udGVudFR5cGUgPSAkLmluQXJyYXkob2JqLnR5cGUsIFtcImh0bWxcIiwgXCJpbmxpbmVcIiwgXCJhamF4XCJdKSA+IC0xID8gXCJodG1sXCIgOiBvYmoudHlwZTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFN0ZXAgMyAtIFNvbWUgYWRqdXN0bWVudHNcclxuICAgICAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgICAgIG9iai5pbmRleCA9IHNlbGYuZ3JvdXAubGVuZ3RoO1xyXG5cclxuICAgICAgICBpZiAob2JqLm9wdHMuc21hbGxCdG4gPT0gXCJhdXRvXCIpIHtcclxuICAgICAgICAgIG9iai5vcHRzLnNtYWxsQnRuID0gJC5pbkFycmF5KG9iai50eXBlLCBbXCJodG1sXCIsIFwiaW5saW5lXCIsIFwiYWpheFwiXSkgPiAtMTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmIChvYmoub3B0cy50b29sYmFyID09PSBcImF1dG9cIikge1xyXG4gICAgICAgICAgb2JqLm9wdHMudG9vbGJhciA9ICFvYmoub3B0cy5zbWFsbEJ0bjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIEZpbmQgdGh1bWJuYWlsIGltYWdlLCBjaGVjayBpZiBleGlzdHMgYW5kIGlmIGlzIGluIHRoZSB2aWV3cG9ydFxyXG4gICAgICAgIG9iai4kdGh1bWIgPSBvYmoub3B0cy4kdGh1bWIgfHwgbnVsbDtcclxuXHJcbiAgICAgICAgaWYgKG9iai5vcHRzLiR0cmlnZ2VyICYmIG9iai5pbmRleCA9PT0gc2VsZi5vcHRzLmluZGV4KSB7XHJcbiAgICAgICAgICBvYmouJHRodW1iID0gb2JqLm9wdHMuJHRyaWdnZXIuZmluZChcImltZzpmaXJzdFwiKTtcclxuXHJcbiAgICAgICAgICBpZiAob2JqLiR0aHVtYi5sZW5ndGgpIHtcclxuICAgICAgICAgICAgb2JqLm9wdHMuJG9yaWcgPSBvYmoub3B0cy4kdHJpZ2dlcjtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmICghKG9iai4kdGh1bWIgJiYgb2JqLiR0aHVtYi5sZW5ndGgpICYmIG9iai5vcHRzLiRvcmlnKSB7XHJcbiAgICAgICAgICBvYmouJHRodW1iID0gb2JqLm9wdHMuJG9yaWcuZmluZChcImltZzpmaXJzdFwiKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmIChvYmouJHRodW1iICYmICFvYmouJHRodW1iLmxlbmd0aCkge1xyXG4gICAgICAgICAgb2JqLiR0aHVtYiA9IG51bGw7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBvYmoudGh1bWIgPSBvYmoub3B0cy50aHVtYiB8fCAob2JqLiR0aHVtYiA/IG9iai4kdGh1bWJbMF0uc3JjIDogbnVsbCk7XHJcblxyXG4gICAgICAgIC8vIFwiY2FwdGlvblwiIGlzIGEgXCJzcGVjaWFsXCIgb3B0aW9uLCBpdCBjYW4gYmUgdXNlZCB0byBjdXN0b21pemUgY2FwdGlvbiBwZXIgZ2FsbGVyeSBpdGVtXHJcbiAgICAgICAgaWYgKCQudHlwZShvYmoub3B0cy5jYXB0aW9uKSA9PT0gXCJmdW5jdGlvblwiKSB7XHJcbiAgICAgICAgICBvYmoub3B0cy5jYXB0aW9uID0gb2JqLm9wdHMuY2FwdGlvbi5hcHBseShpdGVtLCBbc2VsZiwgb2JqXSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoJC50eXBlKHNlbGYub3B0cy5jYXB0aW9uKSA9PT0gXCJmdW5jdGlvblwiKSB7XHJcbiAgICAgICAgICBvYmoub3B0cy5jYXB0aW9uID0gc2VsZi5vcHRzLmNhcHRpb24uYXBwbHkoaXRlbSwgW3NlbGYsIG9ial0pO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gTWFrZSBzdXJlIHdlIGhhdmUgY2FwdGlvbiBhcyBhIHN0cmluZyBvciBqUXVlcnkgb2JqZWN0XHJcbiAgICAgICAgaWYgKCEob2JqLm9wdHMuY2FwdGlvbiBpbnN0YW5jZW9mICQpKSB7XHJcbiAgICAgICAgICBvYmoub3B0cy5jYXB0aW9uID0gb2JqLm9wdHMuY2FwdGlvbiA9PT0gdW5kZWZpbmVkID8gXCJcIiA6IG9iai5vcHRzLmNhcHRpb24gKyBcIlwiO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaWYgdXJsIGNvbnRhaW5zIFwiZmlsdGVyXCIgdXNlZCB0byBmaWx0ZXIgdGhlIGNvbnRlbnRcclxuICAgICAgICAvLyBFeGFtcGxlOiBcImFqYXguaHRtbCAjc29tZXRoaW5nXCJcclxuICAgICAgICBpZiAob2JqLnR5cGUgPT09IFwiYWpheFwiKSB7XHJcbiAgICAgICAgICBzcmNQYXJ0cyA9IHNyYy5zcGxpdCgvXFxzKy8sIDIpO1xyXG5cclxuICAgICAgICAgIGlmIChzcmNQYXJ0cy5sZW5ndGggPiAxKSB7XHJcbiAgICAgICAgICAgIG9iai5zcmMgPSBzcmNQYXJ0cy5zaGlmdCgpO1xyXG5cclxuICAgICAgICAgICAgb2JqLm9wdHMuZmlsdGVyID0gc3JjUGFydHMuc2hpZnQoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIEhpZGUgYWxsIGJ1dHRvbnMgYW5kIGRpc2FibGUgaW50ZXJhY3Rpdml0eSBmb3IgbW9kYWwgaXRlbXNcclxuICAgICAgICBpZiAob2JqLm9wdHMubW9kYWwpIHtcclxuICAgICAgICAgIG9iai5vcHRzID0gJC5leHRlbmQodHJ1ZSwgb2JqLm9wdHMsIHtcclxuICAgICAgICAgICAgdHJhcEZvY3VzOiB0cnVlLFxyXG4gICAgICAgICAgICAvLyBSZW1vdmUgYnV0dG9uc1xyXG4gICAgICAgICAgICBpbmZvYmFyOiAwLFxyXG4gICAgICAgICAgICB0b29sYmFyOiAwLFxyXG5cclxuICAgICAgICAgICAgc21hbGxCdG46IDAsXHJcblxyXG4gICAgICAgICAgICAvLyBEaXNhYmxlIGtleWJvYXJkIG5hdmlnYXRpb25cclxuICAgICAgICAgICAga2V5Ym9hcmQ6IDAsXHJcblxyXG4gICAgICAgICAgICAvLyBEaXNhYmxlIHNvbWUgbW9kdWxlc1xyXG4gICAgICAgICAgICBzbGlkZVNob3c6IDAsXHJcbiAgICAgICAgICAgIGZ1bGxTY3JlZW46IDAsXHJcbiAgICAgICAgICAgIHRodW1iczogMCxcclxuICAgICAgICAgICAgdG91Y2g6IDAsXHJcblxyXG4gICAgICAgICAgICAvLyBEaXNhYmxlIGNsaWNrIGV2ZW50IGhhbmRsZXJzXHJcbiAgICAgICAgICAgIGNsaWNrQ29udGVudDogZmFsc2UsXHJcbiAgICAgICAgICAgIGNsaWNrU2xpZGU6IGZhbHNlLFxyXG4gICAgICAgICAgICBjbGlja091dHNpZGU6IGZhbHNlLFxyXG4gICAgICAgICAgICBkYmxjbGlja0NvbnRlbnQ6IGZhbHNlLFxyXG4gICAgICAgICAgICBkYmxjbGlja1NsaWRlOiBmYWxzZSxcclxuICAgICAgICAgICAgZGJsY2xpY2tPdXRzaWRlOiBmYWxzZVxyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBTdGVwIDQgLSBBZGQgcHJvY2Vzc2VkIG9iamVjdCB0byBncm91cFxyXG4gICAgICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgICAgIHNlbGYuZ3JvdXAucHVzaChvYmopO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIC8vIFVwZGF0ZSBjb250cm9scyBpZiBnYWxsZXJ5IGlzIGFscmVhZHkgb3BlbmVkXHJcbiAgICAgIGlmIChPYmplY3Qua2V5cyhzZWxmLnNsaWRlcykubGVuZ3RoKSB7XHJcbiAgICAgICAgc2VsZi51cGRhdGVDb250cm9scygpO1xyXG5cclxuICAgICAgICAvLyBVcGRhdGUgdGh1bWJuYWlscywgaWYgbmVlZGVkXHJcbiAgICAgICAgdGh1bWJzID0gc2VsZi5UaHVtYnM7XHJcblxyXG4gICAgICAgIGlmICh0aHVtYnMgJiYgdGh1bWJzLmlzQWN0aXZlKSB7XHJcbiAgICAgICAgICB0aHVtYnMuY3JlYXRlKCk7XHJcblxyXG4gICAgICAgICAgdGh1bWJzLmZvY3VzKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIEF0dGFjaCBhbiBldmVudCBoYW5kbGVyIGZ1bmN0aW9ucyBmb3I6XHJcbiAgICAvLyAgIC0gbmF2aWdhdGlvbiBidXR0b25zXHJcbiAgICAvLyAgIC0gYnJvd3NlciBzY3JvbGxpbmcsIHJlc2l6aW5nO1xyXG4gICAgLy8gICAtIGZvY3VzaW5nXHJcbiAgICAvLyAgIC0ga2V5Ym9hcmRcclxuICAgIC8vICAgLSBkZXRlY3RpbmcgaW5hY3Rpdml0eVxyXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICBhZGRFdmVudHM6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgdmFyIHNlbGYgPSB0aGlzO1xyXG5cclxuICAgICAgc2VsZi5yZW1vdmVFdmVudHMoKTtcclxuXHJcbiAgICAgIC8vIE1ha2UgbmF2aWdhdGlvbiBlbGVtZW50cyBjbGlja2FibGVcclxuICAgICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgICAgc2VsZi4kcmVmcy5jb250YWluZXJcclxuICAgICAgICAub24oXCJjbGljay5mYi1jbG9zZVwiLCBcIltkYXRhLWZhbmN5Ym94LWNsb3NlXVwiLCBmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcclxuXHJcbiAgICAgICAgICBzZWxmLmNsb3NlKGUpO1xyXG4gICAgICAgIH0pXHJcbiAgICAgICAgLm9uKFwidG91Y2hzdGFydC5mYi1wcmV2IGNsaWNrLmZiLXByZXZcIiwgXCJbZGF0YS1mYW5jeWJveC1wcmV2XVwiLCBmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcclxuXHJcbiAgICAgICAgICBzZWxmLnByZXZpb3VzKCk7XHJcbiAgICAgICAgfSlcclxuICAgICAgICAub24oXCJ0b3VjaHN0YXJ0LmZiLW5leHQgY2xpY2suZmItbmV4dFwiLCBcIltkYXRhLWZhbmN5Ym94LW5leHRdXCIsIGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xyXG5cclxuICAgICAgICAgIHNlbGYubmV4dCgpO1xyXG4gICAgICAgIH0pXHJcbiAgICAgICAgLm9uKFwiY2xpY2suZmJcIiwgXCJbZGF0YS1mYW5jeWJveC16b29tXVwiLCBmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgICAgLy8gQ2xpY2sgaGFuZGxlciBmb3Igem9vbSBidXR0b25cclxuICAgICAgICAgIHNlbGZbc2VsZi5pc1NjYWxlZERvd24oKSA/IFwic2NhbGVUb0FjdHVhbFwiIDogXCJzY2FsZVRvRml0XCJdKCk7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAvLyBIYW5kbGUgcGFnZSBzY3JvbGxpbmcgYW5kIGJyb3dzZXIgcmVzaXppbmdcclxuICAgICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgICAkVy5vbihcIm9yaWVudGF0aW9uY2hhbmdlLmZiIHJlc2l6ZS5mYlwiLCBmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgIGlmIChlICYmIGUub3JpZ2luYWxFdmVudCAmJiBlLm9yaWdpbmFsRXZlbnQudHlwZSA9PT0gXCJyZXNpemVcIikge1xyXG4gICAgICAgICAgaWYgKHNlbGYucmVxdWVzdElkKSB7XHJcbiAgICAgICAgICAgIGNhbmNlbEFGcmFtZShzZWxmLnJlcXVlc3RJZCk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgc2VsZi5yZXF1ZXN0SWQgPSByZXF1ZXN0QUZyYW1lKGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgc2VsZi51cGRhdGUoZSk7XHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgaWYgKHNlbGYuY3VycmVudCAmJiBzZWxmLmN1cnJlbnQudHlwZSA9PT0gXCJpZnJhbWVcIikge1xyXG4gICAgICAgICAgICBzZWxmLiRyZWZzLnN0YWdlLmhpZGUoKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICBzZXRUaW1lb3V0KFxyXG4gICAgICAgICAgICBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgc2VsZi4kcmVmcy5zdGFnZS5zaG93KCk7XHJcblxyXG4gICAgICAgICAgICAgIHNlbGYudXBkYXRlKGUpO1xyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAkLmZhbmN5Ym94LmlzTW9iaWxlID8gNjAwIDogMjUwXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICAkRC5vbihcImtleWRvd24uZmJcIiwgZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICB2YXIgaW5zdGFuY2UgPSAkLmZhbmN5Ym94ID8gJC5mYW5jeWJveC5nZXRJbnN0YW5jZSgpIDogbnVsbCxcclxuICAgICAgICAgIGN1cnJlbnQgPSBpbnN0YW5jZS5jdXJyZW50LFxyXG4gICAgICAgICAga2V5Y29kZSA9IGUua2V5Q29kZSB8fCBlLndoaWNoO1xyXG5cclxuICAgICAgICAvLyBUcmFwIGtleWJvYXJkIGZvY3VzIGluc2lkZSBvZiB0aGUgbW9kYWxcclxuICAgICAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICAgICAgaWYgKGtleWNvZGUgPT0gOSkge1xyXG4gICAgICAgICAgaWYgKGN1cnJlbnQub3B0cy50cmFwRm9jdXMpIHtcclxuICAgICAgICAgICAgc2VsZi5mb2N1cyhlKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBFbmFibGUga2V5Ym9hcmQgbmF2aWdhdGlvblxyXG4gICAgICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgICAgIGlmICghY3VycmVudC5vcHRzLmtleWJvYXJkIHx8IGUuY3RybEtleSB8fCBlLmFsdEtleSB8fCBlLnNoaWZ0S2V5IHx8ICQoZS50YXJnZXQpLmlzKFwiaW5wdXQsdGV4dGFyZWEsdmlkZW8sYXVkaW8sc2VsZWN0XCIpKSB7XHJcbiAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBCYWNrc3BhY2UgYW5kIEVzYyBrZXlzXHJcbiAgICAgICAgaWYgKGtleWNvZGUgPT09IDggfHwga2V5Y29kZSA9PT0gMjcpIHtcclxuICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcclxuXHJcbiAgICAgICAgICBzZWxmLmNsb3NlKGUpO1xyXG5cclxuICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIExlZnQgYXJyb3cgYW5kIFVwIGFycm93XHJcbiAgICAgICAgaWYgKGtleWNvZGUgPT09IDM3IHx8IGtleWNvZGUgPT09IDM4KSB7XHJcbiAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcblxyXG4gICAgICAgICAgc2VsZi5wcmV2aW91cygpO1xyXG5cclxuICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFJpZ2ggYXJyb3cgYW5kIERvd24gYXJyb3dcclxuICAgICAgICBpZiAoa2V5Y29kZSA9PT0gMzkgfHwga2V5Y29kZSA9PT0gNDApIHtcclxuICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcclxuXHJcbiAgICAgICAgICBzZWxmLm5leHQoKTtcclxuXHJcbiAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBzZWxmLnRyaWdnZXIoXCJhZnRlcktleWRvd25cIiwgZSwga2V5Y29kZSk7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgLy8gSGlkZSBjb250cm9scyBhZnRlciBzb21lIGluYWN0aXZpdHkgcGVyaW9kXHJcbiAgICAgIGlmIChzZWxmLmdyb3VwW3NlbGYuY3VyckluZGV4XS5vcHRzLmlkbGVUaW1lKSB7XHJcbiAgICAgICAgc2VsZi5pZGxlU2Vjb25kc0NvdW50ZXIgPSAwO1xyXG5cclxuICAgICAgICAkRC5vbihcclxuICAgICAgICAgIFwibW91c2Vtb3ZlLmZiLWlkbGUgbW91c2VsZWF2ZS5mYi1pZGxlIG1vdXNlZG93bi5mYi1pZGxlIHRvdWNoc3RhcnQuZmItaWRsZSB0b3VjaG1vdmUuZmItaWRsZSBzY3JvbGwuZmItaWRsZSBrZXlkb3duLmZiLWlkbGVcIixcclxuICAgICAgICAgIGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgICAgIHNlbGYuaWRsZVNlY29uZHNDb3VudGVyID0gMDtcclxuXHJcbiAgICAgICAgICAgIGlmIChzZWxmLmlzSWRsZSkge1xyXG4gICAgICAgICAgICAgIHNlbGYuc2hvd0NvbnRyb2xzKCk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIHNlbGYuaXNJZGxlID0gZmFsc2U7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgc2VsZi5pZGxlSW50ZXJ2YWwgPSB3aW5kb3cuc2V0SW50ZXJ2YWwoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgc2VsZi5pZGxlU2Vjb25kc0NvdW50ZXIrKztcclxuXHJcbiAgICAgICAgICBpZiAoc2VsZi5pZGxlU2Vjb25kc0NvdW50ZXIgPj0gc2VsZi5ncm91cFtzZWxmLmN1cnJJbmRleF0ub3B0cy5pZGxlVGltZSAmJiAhc2VsZi5pc0RyYWdnaW5nKSB7XHJcbiAgICAgICAgICAgIHNlbGYuaXNJZGxlID0gdHJ1ZTtcclxuICAgICAgICAgICAgc2VsZi5pZGxlU2Vjb25kc0NvdW50ZXIgPSAwO1xyXG5cclxuICAgICAgICAgICAgc2VsZi5oaWRlQ29udHJvbHMoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9LCAxMDAwKTtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICAvLyBSZW1vdmUgZXZlbnRzIGFkZGVkIGJ5IHRoZSBjb3JlXHJcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgcmVtb3ZlRXZlbnRzOiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHZhciBzZWxmID0gdGhpcztcclxuXHJcbiAgICAgICRXLm9mZihcIm9yaWVudGF0aW9uY2hhbmdlLmZiIHJlc2l6ZS5mYlwiKTtcclxuICAgICAgJEQub2ZmKFwia2V5ZG93bi5mYiAuZmItaWRsZVwiKTtcclxuXHJcbiAgICAgIHRoaXMuJHJlZnMuY29udGFpbmVyLm9mZihcIi5mYi1jbG9zZSAuZmItcHJldiAuZmItbmV4dFwiKTtcclxuXHJcbiAgICAgIGlmIChzZWxmLmlkbGVJbnRlcnZhbCkge1xyXG4gICAgICAgIHdpbmRvdy5jbGVhckludGVydmFsKHNlbGYuaWRsZUludGVydmFsKTtcclxuXHJcbiAgICAgICAgc2VsZi5pZGxlSW50ZXJ2YWwgPSBudWxsO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIENoYW5nZSB0byBwcmV2aW91cyBnYWxsZXJ5IGl0ZW1cclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICBwcmV2aW91czogZnVuY3Rpb24gKGR1cmF0aW9uKSB7XHJcbiAgICAgIHJldHVybiB0aGlzLmp1bXBUbyh0aGlzLmN1cnJQb3MgLSAxLCBkdXJhdGlvbik7XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIENoYW5nZSB0byBuZXh0IGdhbGxlcnkgaXRlbVxyXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgbmV4dDogZnVuY3Rpb24gKGR1cmF0aW9uKSB7XHJcbiAgICAgIHJldHVybiB0aGlzLmp1bXBUbyh0aGlzLmN1cnJQb3MgKyAxLCBkdXJhdGlvbik7XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIFN3aXRjaCB0byBzZWxlY3RlZCBnYWxsZXJ5IGl0ZW1cclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICBqdW1wVG86IGZ1bmN0aW9uIChwb3MsIGR1cmF0aW9uKSB7XHJcbiAgICAgIHZhciBzZWxmID0gdGhpcyxcclxuICAgICAgICBncm91cExlbiA9IHNlbGYuZ3JvdXAubGVuZ3RoLFxyXG4gICAgICAgIGZpcnN0UnVuLFxyXG4gICAgICAgIGlzTW92ZWQsXHJcbiAgICAgICAgbG9vcCxcclxuICAgICAgICBjdXJyZW50LFxyXG4gICAgICAgIHByZXZpb3VzLFxyXG4gICAgICAgIHNsaWRlUG9zLFxyXG4gICAgICAgIHN0YWdlUG9zLFxyXG4gICAgICAgIHByb3AsXHJcbiAgICAgICAgZGlmZjtcclxuXHJcbiAgICAgIGlmIChzZWxmLmlzRHJhZ2dpbmcgfHwgc2VsZi5pc0Nsb3NpbmcgfHwgKHNlbGYuaXNBbmltYXRpbmcgJiYgc2VsZi5maXJzdFJ1bikpIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFNob3VsZCBsb29wP1xyXG4gICAgICBwb3MgPSBwYXJzZUludChwb3MsIDEwKTtcclxuICAgICAgbG9vcCA9IHNlbGYuY3VycmVudCA/IHNlbGYuY3VycmVudC5vcHRzLmxvb3AgOiBzZWxmLm9wdHMubG9vcDtcclxuXHJcbiAgICAgIGlmICghbG9vcCAmJiAocG9zIDwgMCB8fCBwb3MgPj0gZ3JvdXBMZW4pKSB7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiBvcGVuaW5nIGZvciB0aGUgZmlyc3QgdGltZTsgdGhpcyBoZWxwcyB0byBzcGVlZCB0aGluZ3MgdXBcclxuICAgICAgZmlyc3RSdW4gPSBzZWxmLmZpcnN0UnVuID0gIU9iamVjdC5rZXlzKHNlbGYuc2xpZGVzKS5sZW5ndGg7XHJcblxyXG4gICAgICAvLyBDcmVhdGUgc2xpZGVzXHJcbiAgICAgIHByZXZpb3VzID0gc2VsZi5jdXJyZW50O1xyXG5cclxuICAgICAgc2VsZi5wcmV2SW5kZXggPSBzZWxmLmN1cnJJbmRleDtcclxuICAgICAgc2VsZi5wcmV2UG9zID0gc2VsZi5jdXJyUG9zO1xyXG5cclxuICAgICAgY3VycmVudCA9IHNlbGYuY3JlYXRlU2xpZGUocG9zKTtcclxuXHJcbiAgICAgIGlmIChncm91cExlbiA+IDEpIHtcclxuICAgICAgICBpZiAobG9vcCB8fCBjdXJyZW50LmluZGV4IDwgZ3JvdXBMZW4gLSAxKSB7XHJcbiAgICAgICAgICBzZWxmLmNyZWF0ZVNsaWRlKHBvcyArIDEpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKGxvb3AgfHwgY3VycmVudC5pbmRleCA+IDApIHtcclxuICAgICAgICAgIHNlbGYuY3JlYXRlU2xpZGUocG9zIC0gMSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBzZWxmLmN1cnJlbnQgPSBjdXJyZW50O1xyXG4gICAgICBzZWxmLmN1cnJJbmRleCA9IGN1cnJlbnQuaW5kZXg7XHJcbiAgICAgIHNlbGYuY3VyclBvcyA9IGN1cnJlbnQucG9zO1xyXG5cclxuICAgICAgc2VsZi50cmlnZ2VyKFwiYmVmb3JlU2hvd1wiLCBmaXJzdFJ1bik7XHJcblxyXG4gICAgICBzZWxmLnVwZGF0ZUNvbnRyb2xzKCk7XHJcblxyXG4gICAgICAvLyBWYWxpZGF0ZSBkdXJhdGlvbiBsZW5ndGhcclxuICAgICAgY3VycmVudC5mb3JjZWREdXJhdGlvbiA9IHVuZGVmaW5lZDtcclxuXHJcbiAgICAgIGlmICgkLmlzTnVtZXJpYyhkdXJhdGlvbikpIHtcclxuICAgICAgICBjdXJyZW50LmZvcmNlZER1cmF0aW9uID0gZHVyYXRpb247XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgZHVyYXRpb24gPSBjdXJyZW50Lm9wdHNbZmlyc3RSdW4gPyBcImFuaW1hdGlvbkR1cmF0aW9uXCIgOiBcInRyYW5zaXRpb25EdXJhdGlvblwiXTtcclxuICAgICAgfVxyXG5cclxuICAgICAgZHVyYXRpb24gPSBwYXJzZUludChkdXJhdGlvbiwgMTApO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdXNlciBoYXMgc3dpcGVkIHRoZSBzbGlkZXMgb3IgaWYgc3RpbGwgYW5pbWF0aW5nXHJcbiAgICAgIGlzTW92ZWQgPSBzZWxmLmlzTW92ZWQoY3VycmVudCk7XHJcblxyXG4gICAgICAvLyBNYWtlIHN1cmUgY3VycmVudCBzbGlkZSBpcyB2aXNpYmxlXHJcbiAgICAgIGN1cnJlbnQuJHNsaWRlLmFkZENsYXNzKFwiZmFuY3lib3gtc2xpZGUtLWN1cnJlbnRcIik7XHJcblxyXG4gICAgICAvLyBGcmVzaCBzdGFydCAtIHJldmVhbCBjb250YWluZXIsIGN1cnJlbnQgc2xpZGUgYW5kIHN0YXJ0IGxvYWRpbmcgY29udGVudFxyXG4gICAgICBpZiAoZmlyc3RSdW4pIHtcclxuICAgICAgICBpZiAoY3VycmVudC5vcHRzLmFuaW1hdGlvbkVmZmVjdCAmJiBkdXJhdGlvbikge1xyXG4gICAgICAgICAgc2VsZi4kcmVmcy5jb250YWluZXIuY3NzKFwidHJhbnNpdGlvbi1kdXJhdGlvblwiLCBkdXJhdGlvbiArIFwibXNcIik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBzZWxmLiRyZWZzLmNvbnRhaW5lci5hZGRDbGFzcyhcImZhbmN5Ym94LWlzLW9wZW5cIikudHJpZ2dlcihcImZvY3VzXCIpO1xyXG5cclxuICAgICAgICAvLyBBdHRlbXB0IHRvIGxvYWQgY29udGVudCBpbnRvIHNsaWRlXHJcbiAgICAgICAgLy8gVGhpcyB3aWxsIGxhdGVyIGNhbGwgYGFmdGVyTG9hZGAgLT4gYHJldmVhbENvbnRlbnRgXHJcbiAgICAgICAgc2VsZi5sb2FkU2xpZGUoY3VycmVudCk7XHJcblxyXG4gICAgICAgIHNlbGYucHJlbG9hZChcImltYWdlXCIpO1xyXG5cclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCBhY3R1YWwgc2xpZGUvc3RhZ2UgcG9zaXRpb25zIChiZWZvcmUgY2xlYW5pbmcgdXApXHJcbiAgICAgIHNsaWRlUG9zID0gJC5mYW5jeWJveC5nZXRUcmFuc2xhdGUocHJldmlvdXMuJHNsaWRlKTtcclxuICAgICAgc3RhZ2VQb3MgPSAkLmZhbmN5Ym94LmdldFRyYW5zbGF0ZShzZWxmLiRyZWZzLnN0YWdlKTtcclxuXHJcbiAgICAgIC8vIENsZWFuIHVwIGFsbCBzbGlkZXNcclxuICAgICAgJC5lYWNoKHNlbGYuc2xpZGVzLCBmdW5jdGlvbiAoaW5kZXgsIHNsaWRlKSB7XHJcbiAgICAgICAgJC5mYW5jeWJveC5zdG9wKHNsaWRlLiRzbGlkZSwgdHJ1ZSk7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgaWYgKHByZXZpb3VzLnBvcyAhPT0gY3VycmVudC5wb3MpIHtcclxuICAgICAgICBwcmV2aW91cy5pc0NvbXBsZXRlID0gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHByZXZpb3VzLiRzbGlkZS5yZW1vdmVDbGFzcyhcImZhbmN5Ym94LXNsaWRlLS1jb21wbGV0ZSBmYW5jeWJveC1zbGlkZS0tY3VycmVudFwiKTtcclxuXHJcbiAgICAgIC8vIElmIHNsaWRlcyBhcmUgb3V0IG9mIHBsYWNlLCB0aGVuIGFuaW1hdGUgdGhlbSB0byBjb3JyZWN0IHBvc2l0aW9uXHJcbiAgICAgIGlmIChpc01vdmVkKSB7XHJcbiAgICAgICAgLy8gQ2FsY3VsYXRlIGhvcml6b250YWwgc3dpcGUgZGlzdGFuY2VcclxuICAgICAgICBkaWZmID0gc2xpZGVQb3MubGVmdCAtIChwcmV2aW91cy5wb3MgKiBzbGlkZVBvcy53aWR0aCArIHByZXZpb3VzLnBvcyAqIHByZXZpb3VzLm9wdHMuZ3V0dGVyKTtcclxuXHJcbiAgICAgICAgJC5lYWNoKHNlbGYuc2xpZGVzLCBmdW5jdGlvbiAoaW5kZXgsIHNsaWRlKSB7XHJcbiAgICAgICAgICBzbGlkZS4kc2xpZGUucmVtb3ZlQ2xhc3MoXCJmYW5jeWJveC1hbmltYXRlZFwiKS5yZW1vdmVDbGFzcyhmdW5jdGlvbiAoaW5kZXgsIGNsYXNzTmFtZSkge1xyXG4gICAgICAgICAgICByZXR1cm4gKGNsYXNzTmFtZS5tYXRjaCgvKF58XFxzKWZhbmN5Ym94LWZ4LVxcUysvZykgfHwgW10pLmpvaW4oXCIgXCIpO1xyXG4gICAgICAgICAgfSk7XHJcblxyXG4gICAgICAgICAgLy8gTWFrZSBzdXJlIHRoYXQgZWFjaCBzbGlkZSBpcyBpbiBlcXVhbCBkaXN0YW5jZVxyXG4gICAgICAgICAgLy8gVGhpcyBpcyBtb3N0bHkgbmVlZGVkIGZvciBmcmVzaGx5IGFkZGVkIHNsaWRlcywgYmVjYXVzZSB0aGV5IGFyZSBub3QgeWV0IHBvc2l0aW9uZWRcclxuICAgICAgICAgIHZhciBsZWZ0UG9zID0gc2xpZGUucG9zICogc2xpZGVQb3Mud2lkdGggKyBzbGlkZS5wb3MgKiBzbGlkZS5vcHRzLmd1dHRlcjtcclxuXHJcbiAgICAgICAgICAkLmZhbmN5Ym94LnNldFRyYW5zbGF0ZShzbGlkZS4kc2xpZGUsIHtcclxuICAgICAgICAgICAgdG9wOiAwLFxyXG4gICAgICAgICAgICBsZWZ0OiBsZWZ0UG9zIC0gc3RhZ2VQb3MubGVmdCArIGRpZmZcclxuICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgIGlmIChzbGlkZS5wb3MgIT09IGN1cnJlbnQucG9zKSB7XHJcbiAgICAgICAgICAgIHNsaWRlLiRzbGlkZS5hZGRDbGFzcyhcImZhbmN5Ym94LXNsaWRlLS1cIiArIChzbGlkZS5wb3MgPiBjdXJyZW50LnBvcyA/IFwibmV4dFwiIDogXCJwcmV2aW91c1wiKSk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgLy8gUmVkcmF3IHRvIG1ha2Ugc3VyZSB0aGF0IHRyYW5zaXRpb24gd2lsbCBzdGFydFxyXG4gICAgICAgICAgZm9yY2VSZWRyYXcoc2xpZGUuJHNsaWRlKTtcclxuXHJcbiAgICAgICAgICAvLyBBbmltYXRlIHRoZSBzbGlkZVxyXG4gICAgICAgICAgJC5mYW5jeWJveC5hbmltYXRlKFxyXG4gICAgICAgICAgICBzbGlkZS4kc2xpZGUsIHtcclxuICAgICAgICAgICAgICB0b3A6IDAsXHJcbiAgICAgICAgICAgICAgbGVmdDogKHNsaWRlLnBvcyAtIGN1cnJlbnQucG9zKSAqIHNsaWRlUG9zLndpZHRoICsgKHNsaWRlLnBvcyAtIGN1cnJlbnQucG9zKSAqIHNsaWRlLm9wdHMuZ3V0dGVyXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIGR1cmF0aW9uLFxyXG4gICAgICAgICAgICBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgc2xpZGUuJHNsaWRlXHJcbiAgICAgICAgICAgICAgICAuY3NzKHtcclxuICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtOiBcIlwiLFxyXG4gICAgICAgICAgICAgICAgICBvcGFjaXR5OiBcIlwiXHJcbiAgICAgICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICAgICAgLnJlbW92ZUNsYXNzKFwiZmFuY3lib3gtc2xpZGUtLW5leHQgZmFuY3lib3gtc2xpZGUtLXByZXZpb3VzXCIpO1xyXG5cclxuICAgICAgICAgICAgICBpZiAoc2xpZGUucG9zID09PSBzZWxmLmN1cnJQb3MpIHtcclxuICAgICAgICAgICAgICAgIHNlbGYuY29tcGxldGUoKTtcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0gZWxzZSBpZiAoZHVyYXRpb24gJiYgY3VycmVudC5vcHRzLnRyYW5zaXRpb25FZmZlY3QpIHtcclxuICAgICAgICAvLyBTZXQgdHJhbnNpdGlvbiBlZmZlY3QgZm9yIHByZXZpb3VzbHkgYWN0aXZlIHNsaWRlXHJcbiAgICAgICAgcHJvcCA9IFwiZmFuY3lib3gtYW5pbWF0ZWQgZmFuY3lib3gtZngtXCIgKyBjdXJyZW50Lm9wdHMudHJhbnNpdGlvbkVmZmVjdDtcclxuXHJcbiAgICAgICAgcHJldmlvdXMuJHNsaWRlLmFkZENsYXNzKFwiZmFuY3lib3gtc2xpZGUtLVwiICsgKHByZXZpb3VzLnBvcyA+IGN1cnJlbnQucG9zID8gXCJuZXh0XCIgOiBcInByZXZpb3VzXCIpKTtcclxuXHJcbiAgICAgICAgJC5mYW5jeWJveC5hbmltYXRlKFxyXG4gICAgICAgICAgcHJldmlvdXMuJHNsaWRlLFxyXG4gICAgICAgICAgcHJvcCxcclxuICAgICAgICAgIGR1cmF0aW9uLFxyXG4gICAgICAgICAgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICBwcmV2aW91cy4kc2xpZGUucmVtb3ZlQ2xhc3MocHJvcCkucmVtb3ZlQ2xhc3MoXCJmYW5jeWJveC1zbGlkZS0tbmV4dCBmYW5jeWJveC1zbGlkZS0tcHJldmlvdXNcIik7XHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAgZmFsc2VcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoY3VycmVudC5pc0xvYWRlZCkge1xyXG4gICAgICAgIHNlbGYucmV2ZWFsQ29udGVudChjdXJyZW50KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBzZWxmLmxvYWRTbGlkZShjdXJyZW50KTtcclxuICAgICAgfVxyXG5cclxuICAgICAgc2VsZi5wcmVsb2FkKFwiaW1hZ2VcIik7XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIENyZWF0ZSBuZXcgXCJzbGlkZVwiIGVsZW1lbnRcclxuICAgIC8vIFRoZXNlIGFyZSBnYWxsZXJ5IGl0ZW1zICB0aGF0IGFyZSBhY3R1YWxseSBhZGRlZCB0byBET01cclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICBjcmVhdGVTbGlkZTogZnVuY3Rpb24gKHBvcykge1xyXG4gICAgICB2YXIgc2VsZiA9IHRoaXMsXHJcbiAgICAgICAgJHNsaWRlLFxyXG4gICAgICAgIGluZGV4O1xyXG5cclxuICAgICAgaW5kZXggPSBwb3MgJSBzZWxmLmdyb3VwLmxlbmd0aDtcclxuICAgICAgaW5kZXggPSBpbmRleCA8IDAgPyBzZWxmLmdyb3VwLmxlbmd0aCArIGluZGV4IDogaW5kZXg7XHJcblxyXG4gICAgICBpZiAoIXNlbGYuc2xpZGVzW3Bvc10gJiYgc2VsZi5ncm91cFtpbmRleF0pIHtcclxuICAgICAgICAkc2xpZGUgPSAkKCc8ZGl2IGNsYXNzPVwiZmFuY3lib3gtc2xpZGVcIj48L2Rpdj4nKS5hcHBlbmRUbyhzZWxmLiRyZWZzLnN0YWdlKTtcclxuXHJcbiAgICAgICAgc2VsZi5zbGlkZXNbcG9zXSA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzZWxmLmdyb3VwW2luZGV4XSwge1xyXG4gICAgICAgICAgcG9zOiBwb3MsXHJcbiAgICAgICAgICAkc2xpZGU6ICRzbGlkZSxcclxuICAgICAgICAgIGlzTG9hZGVkOiBmYWxzZVxyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICBzZWxmLnVwZGF0ZVNsaWRlKHNlbGYuc2xpZGVzW3Bvc10pO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gc2VsZi5zbGlkZXNbcG9zXTtcclxuICAgIH0sXHJcblxyXG4gICAgLy8gU2NhbGUgaW1hZ2UgdG8gdGhlIGFjdHVhbCBzaXplIG9mIHRoZSBpbWFnZTtcclxuICAgIC8vIHggYW5kIHkgdmFsdWVzIHNob3VsZCBiZSByZWxhdGl2ZSB0byB0aGUgc2xpZGVcclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICBzY2FsZVRvQWN0dWFsOiBmdW5jdGlvbiAoeCwgeSwgZHVyYXRpb24pIHtcclxuICAgICAgdmFyIHNlbGYgPSB0aGlzLFxyXG4gICAgICAgIGN1cnJlbnQgPSBzZWxmLmN1cnJlbnQsXHJcbiAgICAgICAgJGNvbnRlbnQgPSBjdXJyZW50LiRjb250ZW50LFxyXG4gICAgICAgIGNhbnZhc1dpZHRoID0gJC5mYW5jeWJveC5nZXRUcmFuc2xhdGUoY3VycmVudC4kc2xpZGUpLndpZHRoLFxyXG4gICAgICAgIGNhbnZhc0hlaWdodCA9ICQuZmFuY3lib3guZ2V0VHJhbnNsYXRlKGN1cnJlbnQuJHNsaWRlKS5oZWlnaHQsXHJcbiAgICAgICAgbmV3SW1nV2lkdGggPSBjdXJyZW50LndpZHRoLFxyXG4gICAgICAgIG5ld0ltZ0hlaWdodCA9IGN1cnJlbnQuaGVpZ2h0LFxyXG4gICAgICAgIGltZ1BvcyxcclxuICAgICAgICBwb3NYLFxyXG4gICAgICAgIHBvc1ksXHJcbiAgICAgICAgc2NhbGVYLFxyXG4gICAgICAgIHNjYWxlWTtcclxuXHJcbiAgICAgIGlmIChzZWxmLmlzQW5pbWF0aW5nIHx8IHNlbGYuaXNNb3ZlZCgpIHx8ICEkY29udGVudCB8fCAhKGN1cnJlbnQudHlwZSA9PSBcImltYWdlXCIgJiYgY3VycmVudC5pc0xvYWRlZCAmJiAhY3VycmVudC5oYXNFcnJvcikpIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHNlbGYuaXNBbmltYXRpbmcgPSB0cnVlO1xyXG5cclxuICAgICAgJC5mYW5jeWJveC5zdG9wKCRjb250ZW50KTtcclxuXHJcbiAgICAgIHggPSB4ID09PSB1bmRlZmluZWQgPyBjYW52YXNXaWR0aCAqIDAuNSA6IHg7XHJcbiAgICAgIHkgPSB5ID09PSB1bmRlZmluZWQgPyBjYW52YXNIZWlnaHQgKiAwLjUgOiB5O1xyXG5cclxuICAgICAgaW1nUG9zID0gJC5mYW5jeWJveC5nZXRUcmFuc2xhdGUoJGNvbnRlbnQpO1xyXG5cclxuICAgICAgaW1nUG9zLnRvcCAtPSAkLmZhbmN5Ym94LmdldFRyYW5zbGF0ZShjdXJyZW50LiRzbGlkZSkudG9wO1xyXG4gICAgICBpbWdQb3MubGVmdCAtPSAkLmZhbmN5Ym94LmdldFRyYW5zbGF0ZShjdXJyZW50LiRzbGlkZSkubGVmdDtcclxuXHJcbiAgICAgIHNjYWxlWCA9IG5ld0ltZ1dpZHRoIC8gaW1nUG9zLndpZHRoO1xyXG4gICAgICBzY2FsZVkgPSBuZXdJbWdIZWlnaHQgLyBpbWdQb3MuaGVpZ2h0O1xyXG5cclxuICAgICAgLy8gR2V0IGNlbnRlciBwb3NpdGlvbiBmb3Igb3JpZ2luYWwgaW1hZ2VcclxuICAgICAgcG9zWCA9IGNhbnZhc1dpZHRoICogMC41IC0gbmV3SW1nV2lkdGggKiAwLjU7XHJcbiAgICAgIHBvc1kgPSBjYW52YXNIZWlnaHQgKiAwLjUgLSBuZXdJbWdIZWlnaHQgKiAwLjU7XHJcblxyXG4gICAgICAvLyBNYWtlIHN1cmUgaW1hZ2UgZG9lcyBub3QgbW92ZSBhd2F5IGZyb20gZWRnZXNcclxuICAgICAgaWYgKG5ld0ltZ1dpZHRoID4gY2FudmFzV2lkdGgpIHtcclxuICAgICAgICBwb3NYID0gaW1nUG9zLmxlZnQgKiBzY2FsZVggLSAoeCAqIHNjYWxlWCAtIHgpO1xyXG5cclxuICAgICAgICBpZiAocG9zWCA+IDApIHtcclxuICAgICAgICAgIHBvc1ggPSAwO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKHBvc1ggPCBjYW52YXNXaWR0aCAtIG5ld0ltZ1dpZHRoKSB7XHJcbiAgICAgICAgICBwb3NYID0gY2FudmFzV2lkdGggLSBuZXdJbWdXaWR0aDtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChuZXdJbWdIZWlnaHQgPiBjYW52YXNIZWlnaHQpIHtcclxuICAgICAgICBwb3NZID0gaW1nUG9zLnRvcCAqIHNjYWxlWSAtICh5ICogc2NhbGVZIC0geSk7XHJcblxyXG4gICAgICAgIGlmIChwb3NZID4gMCkge1xyXG4gICAgICAgICAgcG9zWSA9IDA7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAocG9zWSA8IGNhbnZhc0hlaWdodCAtIG5ld0ltZ0hlaWdodCkge1xyXG4gICAgICAgICAgcG9zWSA9IGNhbnZhc0hlaWdodCAtIG5ld0ltZ0hlaWdodDtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHNlbGYudXBkYXRlQ3Vyc29yKG5ld0ltZ1dpZHRoLCBuZXdJbWdIZWlnaHQpO1xyXG5cclxuICAgICAgJC5mYW5jeWJveC5hbmltYXRlKFxyXG4gICAgICAgICRjb250ZW50LCB7XHJcbiAgICAgICAgICB0b3A6IHBvc1ksXHJcbiAgICAgICAgICBsZWZ0OiBwb3NYLFxyXG4gICAgICAgICAgc2NhbGVYOiBzY2FsZVgsXHJcbiAgICAgICAgICBzY2FsZVk6IHNjYWxlWVxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgZHVyYXRpb24gfHwgMzY2LFxyXG4gICAgICAgIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgIHNlbGYuaXNBbmltYXRpbmcgPSBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBTdG9wIHNsaWRlc2hvd1xyXG4gICAgICBpZiAoc2VsZi5TbGlkZVNob3cgJiYgc2VsZi5TbGlkZVNob3cuaXNBY3RpdmUpIHtcclxuICAgICAgICBzZWxmLlNsaWRlU2hvdy5zdG9wKCk7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgLy8gU2NhbGUgaW1hZ2UgdG8gZml0IGluc2lkZSBwYXJlbnQgZWxlbWVudFxyXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIHNjYWxlVG9GaXQ6IGZ1bmN0aW9uIChkdXJhdGlvbikge1xyXG4gICAgICB2YXIgc2VsZiA9IHRoaXMsXHJcbiAgICAgICAgY3VycmVudCA9IHNlbGYuY3VycmVudCxcclxuICAgICAgICAkY29udGVudCA9IGN1cnJlbnQuJGNvbnRlbnQsXHJcbiAgICAgICAgZW5kO1xyXG5cclxuICAgICAgaWYgKHNlbGYuaXNBbmltYXRpbmcgfHwgc2VsZi5pc01vdmVkKCkgfHwgISRjb250ZW50IHx8ICEoY3VycmVudC50eXBlID09IFwiaW1hZ2VcIiAmJiBjdXJyZW50LmlzTG9hZGVkICYmICFjdXJyZW50Lmhhc0Vycm9yKSkge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgc2VsZi5pc0FuaW1hdGluZyA9IHRydWU7XHJcblxyXG4gICAgICAkLmZhbmN5Ym94LnN0b3AoJGNvbnRlbnQpO1xyXG5cclxuICAgICAgZW5kID0gc2VsZi5nZXRGaXRQb3MoY3VycmVudCk7XHJcblxyXG4gICAgICBzZWxmLnVwZGF0ZUN1cnNvcihlbmQud2lkdGgsIGVuZC5oZWlnaHQpO1xyXG5cclxuICAgICAgJC5mYW5jeWJveC5hbmltYXRlKFxyXG4gICAgICAgICRjb250ZW50LCB7XHJcbiAgICAgICAgICB0b3A6IGVuZC50b3AsXHJcbiAgICAgICAgICBsZWZ0OiBlbmQubGVmdCxcclxuICAgICAgICAgIHNjYWxlWDogZW5kLndpZHRoIC8gJGNvbnRlbnQud2lkdGgoKSxcclxuICAgICAgICAgIHNjYWxlWTogZW5kLmhlaWdodCAvICRjb250ZW50LmhlaWdodCgpXHJcbiAgICAgICAgfSxcclxuICAgICAgICBkdXJhdGlvbiB8fCAzNjYsXHJcbiAgICAgICAgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgc2VsZi5pc0FuaW1hdGluZyA9IGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuICAgIH0sXHJcblxyXG4gICAgLy8gQ2FsY3VsYXRlIGltYWdlIHNpemUgdG8gZml0IGluc2lkZSB2aWV3cG9ydFxyXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIGdldEZpdFBvczogZnVuY3Rpb24gKHNsaWRlKSB7XHJcbiAgICAgIHZhciBzZWxmID0gdGhpcyxcclxuICAgICAgICAkY29udGVudCA9IHNsaWRlLiRjb250ZW50LFxyXG4gICAgICAgICRzbGlkZSA9IHNsaWRlLiRzbGlkZSxcclxuICAgICAgICB3aWR0aCA9IHNsaWRlLndpZHRoIHx8IHNsaWRlLm9wdHMud2lkdGgsXHJcbiAgICAgICAgaGVpZ2h0ID0gc2xpZGUuaGVpZ2h0IHx8IHNsaWRlLm9wdHMuaGVpZ2h0LFxyXG4gICAgICAgIG1heFdpZHRoLFxyXG4gICAgICAgIG1heEhlaWdodCxcclxuICAgICAgICBtaW5SYXRpbyxcclxuICAgICAgICBhc3BlY3RSYXRpbyxcclxuICAgICAgICByZXogPSB7fTtcclxuXHJcbiAgICAgIGlmICghc2xpZGUuaXNMb2FkZWQgfHwgISRjb250ZW50IHx8ICEkY29udGVudC5sZW5ndGgpIHtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIG1heFdpZHRoID0gJC5mYW5jeWJveC5nZXRUcmFuc2xhdGUoc2VsZi4kcmVmcy5zdGFnZSkud2lkdGg7XHJcbiAgICAgIG1heEhlaWdodCA9ICQuZmFuY3lib3guZ2V0VHJhbnNsYXRlKHNlbGYuJHJlZnMuc3RhZ2UpLmhlaWdodDtcclxuXHJcbiAgICAgIG1heFdpZHRoIC09XHJcbiAgICAgICAgcGFyc2VGbG9hdCgkc2xpZGUuY3NzKFwicGFkZGluZ0xlZnRcIikpICtcclxuICAgICAgICBwYXJzZUZsb2F0KCRzbGlkZS5jc3MoXCJwYWRkaW5nUmlnaHRcIikpICtcclxuICAgICAgICBwYXJzZUZsb2F0KCRjb250ZW50LmNzcyhcIm1hcmdpbkxlZnRcIikpICtcclxuICAgICAgICBwYXJzZUZsb2F0KCRjb250ZW50LmNzcyhcIm1hcmdpblJpZ2h0XCIpKTtcclxuXHJcbiAgICAgIG1heEhlaWdodCAtPVxyXG4gICAgICAgIHBhcnNlRmxvYXQoJHNsaWRlLmNzcyhcInBhZGRpbmdUb3BcIikpICtcclxuICAgICAgICBwYXJzZUZsb2F0KCRzbGlkZS5jc3MoXCJwYWRkaW5nQm90dG9tXCIpKSArXHJcbiAgICAgICAgcGFyc2VGbG9hdCgkY29udGVudC5jc3MoXCJtYXJnaW5Ub3BcIikpICtcclxuICAgICAgICBwYXJzZUZsb2F0KCRjb250ZW50LmNzcyhcIm1hcmdpbkJvdHRvbVwiKSk7XHJcblxyXG4gICAgICBpZiAoIXdpZHRoIHx8ICFoZWlnaHQpIHtcclxuICAgICAgICB3aWR0aCA9IG1heFdpZHRoO1xyXG4gICAgICAgIGhlaWdodCA9IG1heEhlaWdodDtcclxuICAgICAgfVxyXG5cclxuICAgICAgbWluUmF0aW8gPSBNYXRoLm1pbigxLCBtYXhXaWR0aCAvIHdpZHRoLCBtYXhIZWlnaHQgLyBoZWlnaHQpO1xyXG5cclxuICAgICAgd2lkdGggPSBtaW5SYXRpbyAqIHdpZHRoO1xyXG4gICAgICBoZWlnaHQgPSBtaW5SYXRpbyAqIGhlaWdodDtcclxuXHJcbiAgICAgIC8vIEFkanVzdCB3aWR0aC9oZWlnaHQgdG8gcHJlY2lzZWx5IGZpdCBpbnRvIGNvbnRhaW5lclxyXG4gICAgICBpZiAod2lkdGggPiBtYXhXaWR0aCAtIDAuNSkge1xyXG4gICAgICAgIHdpZHRoID0gbWF4V2lkdGg7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChoZWlnaHQgPiBtYXhIZWlnaHQgLSAwLjUpIHtcclxuICAgICAgICBoZWlnaHQgPSBtYXhIZWlnaHQ7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChzbGlkZS50eXBlID09PSBcImltYWdlXCIpIHtcclxuICAgICAgICByZXoudG9wID0gTWF0aC5mbG9vcigobWF4SGVpZ2h0IC0gaGVpZ2h0KSAqIDAuNSkgKyBwYXJzZUZsb2F0KCRzbGlkZS5jc3MoXCJwYWRkaW5nVG9wXCIpKTtcclxuICAgICAgICByZXoubGVmdCA9IE1hdGguZmxvb3IoKG1heFdpZHRoIC0gd2lkdGgpICogMC41KSArIHBhcnNlRmxvYXQoJHNsaWRlLmNzcyhcInBhZGRpbmdMZWZ0XCIpKTtcclxuICAgICAgfSBlbHNlIGlmIChzbGlkZS5jb250ZW50VHlwZSA9PT0gXCJ2aWRlb1wiKSB7XHJcbiAgICAgICAgLy8gRm9yY2UgYXNwZWN0IHJhdGlvIGZvciB0aGUgdmlkZW9cclxuICAgICAgICAvLyBcIkkgc2F5IHRoZSB3aG9sZSB3b3JsZCBtdXN0IGxlYXJuIG9mIG91ciBwZWFjZWZ1bCB3YXlz4oCmIGJ5IGZvcmNlIVwiXHJcbiAgICAgICAgYXNwZWN0UmF0aW8gPSBzbGlkZS5vcHRzLndpZHRoICYmIHNsaWRlLm9wdHMuaGVpZ2h0ID8gd2lkdGggLyBoZWlnaHQgOiBzbGlkZS5vcHRzLnJhdGlvIHx8IDE2IC8gOTtcclxuXHJcbiAgICAgICAgaWYgKGhlaWdodCA+IHdpZHRoIC8gYXNwZWN0UmF0aW8pIHtcclxuICAgICAgICAgIGhlaWdodCA9IHdpZHRoIC8gYXNwZWN0UmF0aW87XHJcbiAgICAgICAgfSBlbHNlIGlmICh3aWR0aCA+IGhlaWdodCAqIGFzcGVjdFJhdGlvKSB7XHJcbiAgICAgICAgICB3aWR0aCA9IGhlaWdodCAqIGFzcGVjdFJhdGlvO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgcmV6LndpZHRoID0gd2lkdGg7XHJcbiAgICAgIHJlei5oZWlnaHQgPSBoZWlnaHQ7XHJcblxyXG4gICAgICByZXR1cm4gcmV6O1xyXG4gICAgfSxcclxuXHJcbiAgICAvLyBVcGRhdGUgY29udGVudCBzaXplIGFuZCBwb3NpdGlvbiBmb3IgYWxsIHNsaWRlc1xyXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIHVwZGF0ZTogZnVuY3Rpb24gKGUpIHtcclxuICAgICAgdmFyIHNlbGYgPSB0aGlzO1xyXG5cclxuICAgICAgJC5lYWNoKHNlbGYuc2xpZGVzLCBmdW5jdGlvbiAoa2V5LCBzbGlkZSkge1xyXG4gICAgICAgIHNlbGYudXBkYXRlU2xpZGUoc2xpZGUsIGUpO1xyXG4gICAgICB9KTtcclxuICAgIH0sXHJcblxyXG4gICAgLy8gVXBkYXRlIHNsaWRlIGNvbnRlbnQgcG9zaXRpb24gYW5kIHNpemVcclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgdXBkYXRlU2xpZGU6IGZ1bmN0aW9uIChzbGlkZSwgZSkge1xyXG4gICAgICB2YXIgc2VsZiA9IHRoaXMsXHJcbiAgICAgICAgJGNvbnRlbnQgPSBzbGlkZSAmJiBzbGlkZS4kY29udGVudCxcclxuICAgICAgICB3aWR0aCA9IHNsaWRlLndpZHRoIHx8IHNsaWRlLm9wdHMud2lkdGgsXHJcbiAgICAgICAgaGVpZ2h0ID0gc2xpZGUuaGVpZ2h0IHx8IHNsaWRlLm9wdHMuaGVpZ2h0LFxyXG4gICAgICAgICRzbGlkZSA9IHNsaWRlLiRzbGlkZTtcclxuXHJcbiAgICAgIC8vIEZpcnN0LCBwcmV2ZW50IGNhcHRpb24gb3ZlcmxhcCwgaWYgbmVlZGVkXHJcbiAgICAgIHNlbGYuYWRqdXN0Q2FwdGlvbihzbGlkZSk7XHJcblxyXG4gICAgICAvLyBUaGVuIHJlc2l6ZSBjb250ZW50IHRvIGZpdCBpbnNpZGUgdGhlIHNsaWRlXHJcbiAgICAgIGlmICgkY29udGVudCAmJiAod2lkdGggfHwgaGVpZ2h0IHx8IHNsaWRlLmNvbnRlbnRUeXBlID09PSBcInZpZGVvXCIpICYmICFzbGlkZS5oYXNFcnJvcikge1xyXG4gICAgICAgICQuZmFuY3lib3guc3RvcCgkY29udGVudCk7XHJcblxyXG4gICAgICAgICQuZmFuY3lib3guc2V0VHJhbnNsYXRlKCRjb250ZW50LCBzZWxmLmdldEZpdFBvcyhzbGlkZSkpO1xyXG5cclxuICAgICAgICBpZiAoc2xpZGUucG9zID09PSBzZWxmLmN1cnJQb3MpIHtcclxuICAgICAgICAgIHNlbGYuaXNBbmltYXRpbmcgPSBmYWxzZTtcclxuXHJcbiAgICAgICAgICBzZWxmLnVwZGF0ZUN1cnNvcigpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gVGhlbiBzb21lIGFkanVzdG1lbnRzXHJcbiAgICAgIHNlbGYuYWRqdXN0TGF5b3V0KHNsaWRlKTtcclxuXHJcbiAgICAgIGlmICgkc2xpZGUubGVuZ3RoKSB7XHJcbiAgICAgICAgJHNsaWRlLnRyaWdnZXIoXCJyZWZyZXNoXCIpO1xyXG5cclxuICAgICAgICBpZiAoc2xpZGUucG9zID09PSBzZWxmLmN1cnJQb3MpIHtcclxuICAgICAgICAgIHNlbGYuJHJlZnMudG9vbGJhclxyXG4gICAgICAgICAgICAuYWRkKHNlbGYuJHJlZnMubmF2aWdhdGlvbi5maW5kKFwiLmZhbmN5Ym94LWJ1dHRvbi0tYXJyb3dfcmlnaHRcIikpXHJcbiAgICAgICAgICAgIC50b2dnbGVDbGFzcyhcImNvbXBlbnNhdGUtZm9yLXNjcm9sbGJhclwiLCAkc2xpZGUuZ2V0KDApLnNjcm9sbEhlaWdodCA+ICRzbGlkZS5nZXQoMCkuY2xpZW50SGVpZ2h0KTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHNlbGYudHJpZ2dlcihcIm9uVXBkYXRlXCIsIHNsaWRlLCBlKTtcclxuICAgIH0sXHJcblxyXG4gICAgLy8gSG9yaXpvbnRhbGx5IGNlbnRlciBzbGlkZVxyXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIGNlbnRlclNsaWRlOiBmdW5jdGlvbiAoZHVyYXRpb24pIHtcclxuICAgICAgdmFyIHNlbGYgPSB0aGlzLFxyXG4gICAgICAgIGN1cnJlbnQgPSBzZWxmLmN1cnJlbnQsXHJcbiAgICAgICAgJHNsaWRlID0gY3VycmVudC4kc2xpZGU7XHJcblxyXG4gICAgICBpZiAoc2VsZi5pc0Nsb3NpbmcgfHwgIWN1cnJlbnQpIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICRzbGlkZS5zaWJsaW5ncygpLmNzcyh7XHJcbiAgICAgICAgdHJhbnNmb3JtOiBcIlwiLFxyXG4gICAgICAgIG9wYWNpdHk6IFwiXCJcclxuICAgICAgfSk7XHJcblxyXG4gICAgICAkc2xpZGVcclxuICAgICAgICAucGFyZW50KClcclxuICAgICAgICAuY2hpbGRyZW4oKVxyXG4gICAgICAgIC5yZW1vdmVDbGFzcyhcImZhbmN5Ym94LXNsaWRlLS1wcmV2aW91cyBmYW5jeWJveC1zbGlkZS0tbmV4dFwiKTtcclxuXHJcbiAgICAgICQuZmFuY3lib3guYW5pbWF0ZShcclxuICAgICAgICAkc2xpZGUsIHtcclxuICAgICAgICAgIHRvcDogMCxcclxuICAgICAgICAgIGxlZnQ6IDAsXHJcbiAgICAgICAgICBvcGFjaXR5OiAxXHJcbiAgICAgICAgfSxcclxuICAgICAgICBkdXJhdGlvbiA9PT0gdW5kZWZpbmVkID8gMCA6IGR1cmF0aW9uLFxyXG4gICAgICAgIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgIC8vIENsZWFuIHVwXHJcbiAgICAgICAgICAkc2xpZGUuY3NzKHtcclxuICAgICAgICAgICAgdHJhbnNmb3JtOiBcIlwiLFxyXG4gICAgICAgICAgICBvcGFjaXR5OiBcIlwiXHJcbiAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgICBpZiAoIWN1cnJlbnQuaXNDb21wbGV0ZSkge1xyXG4gICAgICAgICAgICBzZWxmLmNvbXBsZXRlKCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSxcclxuICAgICAgICBmYWxzZVxyXG4gICAgICApO1xyXG4gICAgfSxcclxuXHJcbiAgICAvLyBDaGVjayBpZiBjdXJyZW50IHNsaWRlIGlzIG1vdmVkIChzd2lwZWQpXHJcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgaXNNb3ZlZDogZnVuY3Rpb24gKHNsaWRlKSB7XHJcbiAgICAgIHZhciBjdXJyZW50ID0gc2xpZGUgfHwgdGhpcy5jdXJyZW50LFxyXG4gICAgICAgIHNsaWRlUG9zLFxyXG4gICAgICAgIHN0YWdlUG9zO1xyXG5cclxuICAgICAgaWYgKCFjdXJyZW50KSB7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBzdGFnZVBvcyA9ICQuZmFuY3lib3guZ2V0VHJhbnNsYXRlKHRoaXMuJHJlZnMuc3RhZ2UpO1xyXG4gICAgICBzbGlkZVBvcyA9ICQuZmFuY3lib3guZ2V0VHJhbnNsYXRlKGN1cnJlbnQuJHNsaWRlKTtcclxuXHJcbiAgICAgIHJldHVybiAoXHJcbiAgICAgICAgIWN1cnJlbnQuJHNsaWRlLmhhc0NsYXNzKFwiZmFuY3lib3gtYW5pbWF0ZWRcIikgJiZcclxuICAgICAgICAoTWF0aC5hYnMoc2xpZGVQb3MudG9wIC0gc3RhZ2VQb3MudG9wKSA+IDAuNSB8fCBNYXRoLmFicyhzbGlkZVBvcy5sZWZ0IC0gc3RhZ2VQb3MubGVmdCkgPiAwLjUpXHJcbiAgICAgICk7XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIFVwZGF0ZSBjdXJzb3Igc3R5bGUgZGVwZW5kaW5nIGlmIGNvbnRlbnQgY2FuIGJlIHpvb21lZFxyXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgdXBkYXRlQ3Vyc29yOiBmdW5jdGlvbiAobmV4dFdpZHRoLCBuZXh0SGVpZ2h0KSB7XHJcbiAgICAgIHZhciBzZWxmID0gdGhpcyxcclxuICAgICAgICBjdXJyZW50ID0gc2VsZi5jdXJyZW50LFxyXG4gICAgICAgICRjb250YWluZXIgPSBzZWxmLiRyZWZzLmNvbnRhaW5lcixcclxuICAgICAgICBjYW5QYW4sXHJcbiAgICAgICAgaXNab29tYWJsZTtcclxuXHJcbiAgICAgIGlmICghY3VycmVudCB8fCBzZWxmLmlzQ2xvc2luZyB8fCAhc2VsZi5HdWVzdHVyZXMpIHtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICRjb250YWluZXIucmVtb3ZlQ2xhc3MoXCJmYW5jeWJveC1pcy16b29tYWJsZSBmYW5jeWJveC1jYW4tem9vbUluIGZhbmN5Ym94LWNhbi16b29tT3V0IGZhbmN5Ym94LWNhbi1zd2lwZSBmYW5jeWJveC1jYW4tcGFuXCIpO1xyXG5cclxuICAgICAgY2FuUGFuID0gc2VsZi5jYW5QYW4obmV4dFdpZHRoLCBuZXh0SGVpZ2h0KTtcclxuXHJcbiAgICAgIGlzWm9vbWFibGUgPSBjYW5QYW4gPyB0cnVlIDogc2VsZi5pc1pvb21hYmxlKCk7XHJcblxyXG4gICAgICAkY29udGFpbmVyLnRvZ2dsZUNsYXNzKFwiZmFuY3lib3gtaXMtem9vbWFibGVcIiwgaXNab29tYWJsZSk7XHJcblxyXG4gICAgICAkKFwiW2RhdGEtZmFuY3lib3gtem9vbV1cIikucHJvcChcImRpc2FibGVkXCIsICFpc1pvb21hYmxlKTtcclxuXHJcbiAgICAgIGlmIChjYW5QYW4pIHtcclxuICAgICAgICAkY29udGFpbmVyLmFkZENsYXNzKFwiZmFuY3lib3gtY2FuLXBhblwiKTtcclxuICAgICAgfSBlbHNlIGlmIChcclxuICAgICAgICBpc1pvb21hYmxlICYmXHJcbiAgICAgICAgKGN1cnJlbnQub3B0cy5jbGlja0NvbnRlbnQgPT09IFwiem9vbVwiIHx8ICgkLmlzRnVuY3Rpb24oY3VycmVudC5vcHRzLmNsaWNrQ29udGVudCkgJiYgY3VycmVudC5vcHRzLmNsaWNrQ29udGVudChjdXJyZW50KSA9PSBcInpvb21cIikpXHJcbiAgICAgICkge1xyXG4gICAgICAgICRjb250YWluZXIuYWRkQ2xhc3MoXCJmYW5jeWJveC1jYW4tem9vbUluXCIpO1xyXG4gICAgICB9IGVsc2UgaWYgKGN1cnJlbnQub3B0cy50b3VjaCAmJiAoY3VycmVudC5vcHRzLnRvdWNoLnZlcnRpY2FsIHx8IHNlbGYuZ3JvdXAubGVuZ3RoID4gMSkgJiYgY3VycmVudC5jb250ZW50VHlwZSAhPT0gXCJ2aWRlb1wiKSB7XHJcbiAgICAgICAgJGNvbnRhaW5lci5hZGRDbGFzcyhcImZhbmN5Ym94LWNhbi1zd2lwZVwiKTtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICAvLyBDaGVjayBpZiBjdXJyZW50IHNsaWRlIGlzIHpvb21hYmxlXHJcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgaXNab29tYWJsZTogZnVuY3Rpb24gKCkge1xyXG4gICAgICB2YXIgc2VsZiA9IHRoaXMsXHJcbiAgICAgICAgY3VycmVudCA9IHNlbGYuY3VycmVudCxcclxuICAgICAgICBmaXRQb3M7XHJcblxyXG4gICAgICAvLyBBc3N1bWUgdGhhdCBzbGlkZSBpcyB6b29tYWJsZSBpZjpcclxuICAgICAgLy8gICAtIGltYWdlIGlzIHN0aWxsIGxvYWRpbmdcclxuICAgICAgLy8gICAtIGFjdHVhbCBzaXplIG9mIHRoZSBpbWFnZSBpcyBzbWFsbGVyIHRoYW4gYXZhaWxhYmxlIGFyZWFcclxuICAgICAgaWYgKGN1cnJlbnQgJiYgIXNlbGYuaXNDbG9zaW5nICYmIGN1cnJlbnQudHlwZSA9PT0gXCJpbWFnZVwiICYmICFjdXJyZW50Lmhhc0Vycm9yKSB7XHJcbiAgICAgICAgaWYgKCFjdXJyZW50LmlzTG9hZGVkKSB7XHJcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGZpdFBvcyA9IHNlbGYuZ2V0Rml0UG9zKGN1cnJlbnQpO1xyXG5cclxuICAgICAgICBpZiAoZml0UG9zICYmIChjdXJyZW50LndpZHRoID4gZml0UG9zLndpZHRoIHx8IGN1cnJlbnQuaGVpZ2h0ID4gZml0UG9zLmhlaWdodCkpIHtcclxuICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfSxcclxuXHJcbiAgICAvLyBDaGVjayBpZiBjdXJyZW50IGltYWdlIGRpbWVuc2lvbnMgYXJlIHNtYWxsZXIgdGhhbiBhY3R1YWxcclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIGlzU2NhbGVkRG93bjogZnVuY3Rpb24gKG5leHRXaWR0aCwgbmV4dEhlaWdodCkge1xyXG4gICAgICB2YXIgc2VsZiA9IHRoaXMsXHJcbiAgICAgICAgcmV6ID0gZmFsc2UsXHJcbiAgICAgICAgY3VycmVudCA9IHNlbGYuY3VycmVudCxcclxuICAgICAgICAkY29udGVudCA9IGN1cnJlbnQuJGNvbnRlbnQ7XHJcblxyXG4gICAgICBpZiAobmV4dFdpZHRoICE9PSB1bmRlZmluZWQgJiYgbmV4dEhlaWdodCAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgcmV6ID0gbmV4dFdpZHRoIDwgY3VycmVudC53aWR0aCAmJiBuZXh0SGVpZ2h0IDwgY3VycmVudC5oZWlnaHQ7XHJcbiAgICAgIH0gZWxzZSBpZiAoJGNvbnRlbnQpIHtcclxuICAgICAgICByZXogPSAkLmZhbmN5Ym94LmdldFRyYW5zbGF0ZSgkY29udGVudCk7XHJcbiAgICAgICAgcmV6ID0gcmV6LndpZHRoIDwgY3VycmVudC53aWR0aCAmJiByZXouaGVpZ2h0IDwgY3VycmVudC5oZWlnaHQ7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHJldHVybiByZXo7XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIENoZWNrIGlmIGltYWdlIGRpbWVuc2lvbnMgZXhjZWVkIHBhcmVudCBlbGVtZW50XHJcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIGNhblBhbjogZnVuY3Rpb24gKG5leHRXaWR0aCwgbmV4dEhlaWdodCkge1xyXG4gICAgICB2YXIgc2VsZiA9IHRoaXMsXHJcbiAgICAgICAgY3VycmVudCA9IHNlbGYuY3VycmVudCxcclxuICAgICAgICBwb3MgPSBudWxsLFxyXG4gICAgICAgIHJleiA9IGZhbHNlO1xyXG5cclxuICAgICAgaWYgKGN1cnJlbnQudHlwZSA9PT0gXCJpbWFnZVwiICYmIChjdXJyZW50LmlzQ29tcGxldGUgfHwgKG5leHRXaWR0aCAmJiBuZXh0SGVpZ2h0KSkgJiYgIWN1cnJlbnQuaGFzRXJyb3IpIHtcclxuICAgICAgICByZXogPSBzZWxmLmdldEZpdFBvcyhjdXJyZW50KTtcclxuXHJcbiAgICAgICAgaWYgKG5leHRXaWR0aCAhPT0gdW5kZWZpbmVkICYmIG5leHRIZWlnaHQgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgcG9zID0ge1xyXG4gICAgICAgICAgICB3aWR0aDogbmV4dFdpZHRoLFxyXG4gICAgICAgICAgICBoZWlnaHQ6IG5leHRIZWlnaHRcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSBlbHNlIGlmIChjdXJyZW50LmlzQ29tcGxldGUpIHtcclxuICAgICAgICAgIHBvcyA9ICQuZmFuY3lib3guZ2V0VHJhbnNsYXRlKGN1cnJlbnQuJGNvbnRlbnQpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKHBvcyAmJiByZXopIHtcclxuICAgICAgICAgIHJleiA9IE1hdGguYWJzKHBvcy53aWR0aCAtIHJlei53aWR0aCkgPiAxLjUgfHwgTWF0aC5hYnMocG9zLmhlaWdodCAtIHJlei5oZWlnaHQpID4gMS41O1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIHJlejtcclxuICAgIH0sXHJcblxyXG4gICAgLy8gTG9hZCBjb250ZW50IGludG8gdGhlIHNsaWRlXHJcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICBsb2FkU2xpZGU6IGZ1bmN0aW9uIChzbGlkZSkge1xyXG4gICAgICB2YXIgc2VsZiA9IHRoaXMsXHJcbiAgICAgICAgdHlwZSxcclxuICAgICAgICAkc2xpZGUsXHJcbiAgICAgICAgYWpheExvYWQ7XHJcblxyXG4gICAgICBpZiAoc2xpZGUuaXNMb2FkaW5nIHx8IHNsaWRlLmlzTG9hZGVkKSB7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBzbGlkZS5pc0xvYWRpbmcgPSB0cnVlO1xyXG5cclxuICAgICAgaWYgKHNlbGYudHJpZ2dlcihcImJlZm9yZUxvYWRcIiwgc2xpZGUpID09PSBmYWxzZSkge1xyXG4gICAgICAgIHNsaWRlLmlzTG9hZGluZyA9IGZhbHNlO1xyXG5cclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHR5cGUgPSBzbGlkZS50eXBlO1xyXG4gICAgICAkc2xpZGUgPSBzbGlkZS4kc2xpZGU7XHJcblxyXG4gICAgICAkc2xpZGVcclxuICAgICAgICAub2ZmKFwicmVmcmVzaFwiKVxyXG4gICAgICAgIC50cmlnZ2VyKFwib25SZXNldFwiKVxyXG4gICAgICAgIC5hZGRDbGFzcyhzbGlkZS5vcHRzLnNsaWRlQ2xhc3MpO1xyXG5cclxuICAgICAgLy8gQ3JlYXRlIGNvbnRlbnQgZGVwZW5kaW5nIG9uIHRoZSB0eXBlXHJcbiAgICAgIHN3aXRjaCAodHlwZSkge1xyXG4gICAgICAgIGNhc2UgXCJpbWFnZVwiOlxyXG4gICAgICAgICAgc2VsZi5zZXRJbWFnZShzbGlkZSk7XHJcblxyXG4gICAgICAgICAgYnJlYWs7XHJcblxyXG4gICAgICAgIGNhc2UgXCJpZnJhbWVcIjpcclxuICAgICAgICAgIHNlbGYuc2V0SWZyYW1lKHNsaWRlKTtcclxuXHJcbiAgICAgICAgICBicmVhaztcclxuXHJcbiAgICAgICAgY2FzZSBcImh0bWxcIjpcclxuICAgICAgICAgIHNlbGYuc2V0Q29udGVudChzbGlkZSwgc2xpZGUuc3JjIHx8IHNsaWRlLmNvbnRlbnQpO1xyXG5cclxuICAgICAgICAgIGJyZWFrO1xyXG5cclxuICAgICAgICBjYXNlIFwidmlkZW9cIjpcclxuICAgICAgICAgIHNlbGYuc2V0Q29udGVudChcclxuICAgICAgICAgICAgc2xpZGUsXHJcbiAgICAgICAgICAgIHNsaWRlLm9wdHMudmlkZW8udHBsXHJcbiAgICAgICAgICAgIC5yZXBsYWNlKC9cXHtcXHtzcmNcXH1cXH0vZ2ksIHNsaWRlLnNyYylcclxuICAgICAgICAgICAgLnJlcGxhY2UoXCJ7e2Zvcm1hdH19XCIsIHNsaWRlLm9wdHMudmlkZW9Gb3JtYXQgfHwgc2xpZGUub3B0cy52aWRlby5mb3JtYXQgfHwgXCJcIilcclxuICAgICAgICAgICAgLnJlcGxhY2UoXCJ7e3Bvc3Rlcn19XCIsIHNsaWRlLnRodW1iIHx8IFwiXCIpXHJcbiAgICAgICAgICApO1xyXG5cclxuICAgICAgICAgIGJyZWFrO1xyXG5cclxuICAgICAgICBjYXNlIFwiaW5saW5lXCI6XHJcbiAgICAgICAgICBpZiAoJChzbGlkZS5zcmMpLmxlbmd0aCkge1xyXG4gICAgICAgICAgICBzZWxmLnNldENvbnRlbnQoc2xpZGUsICQoc2xpZGUuc3JjKSk7XHJcbiAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICBzZWxmLnNldEVycm9yKHNsaWRlKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICBicmVhaztcclxuXHJcbiAgICAgICAgY2FzZSBcImFqYXhcIjpcclxuICAgICAgICAgIHNlbGYuc2hvd0xvYWRpbmcoc2xpZGUpO1xyXG5cclxuICAgICAgICAgIGFqYXhMb2FkID0gJC5hamF4KFxyXG4gICAgICAgICAgICAkLmV4dGVuZCh7fSwgc2xpZGUub3B0cy5hamF4LnNldHRpbmdzLCB7XHJcbiAgICAgICAgICAgICAgdXJsOiBzbGlkZS5zcmMsXHJcbiAgICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24gKGRhdGEsIHRleHRTdGF0dXMpIHtcclxuICAgICAgICAgICAgICAgIGlmICh0ZXh0U3RhdHVzID09PSBcInN1Y2Nlc3NcIikge1xyXG4gICAgICAgICAgICAgICAgICBzZWxmLnNldENvbnRlbnQoc2xpZGUsIGRhdGEpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgICAgZXJyb3I6IGZ1bmN0aW9uIChqcVhIUiwgdGV4dFN0YXR1cykge1xyXG4gICAgICAgICAgICAgICAgaWYgKGpxWEhSICYmIHRleHRTdGF0dXMgIT09IFwiYWJvcnRcIikge1xyXG4gICAgICAgICAgICAgICAgICBzZWxmLnNldEVycm9yKHNsaWRlKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH0pXHJcbiAgICAgICAgICApO1xyXG5cclxuICAgICAgICAgICRzbGlkZS5vbmUoXCJvblJlc2V0XCIsIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgYWpheExvYWQuYWJvcnQoKTtcclxuICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgIGJyZWFrO1xyXG5cclxuICAgICAgICBkZWZhdWx0OlxyXG4gICAgICAgICAgc2VsZi5zZXRFcnJvcihzbGlkZSk7XHJcblxyXG4gICAgICAgICAgYnJlYWs7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfSxcclxuXHJcbiAgICAvLyBVc2UgdGh1bWJuYWlsIGltYWdlLCBpZiBwb3NzaWJsZVxyXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICBzZXRJbWFnZTogZnVuY3Rpb24gKHNsaWRlKSB7XHJcbiAgICAgIHZhciBzZWxmID0gdGhpcyxcclxuICAgICAgICBnaG9zdDtcclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIG5lZWQgdG8gc2hvdyBsb2FkaW5nIGljb25cclxuICAgICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgdmFyICRpbWcgPSBzbGlkZS4kaW1hZ2U7XHJcblxyXG4gICAgICAgIGlmICghc2VsZi5pc0Nsb3NpbmcgJiYgc2xpZGUuaXNMb2FkaW5nICYmICghJGltZyB8fCAhJGltZy5sZW5ndGggfHwgISRpbWdbMF0uY29tcGxldGUpICYmICFzbGlkZS5oYXNFcnJvcikge1xyXG4gICAgICAgICAgc2VsZi5zaG93TG9hZGluZyhzbGlkZSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9LCA1MCk7XHJcblxyXG4gICAgICAvL0NoZWNrIGlmIGltYWdlIGhhcyBzcmNzZXRcclxuICAgICAgc2VsZi5jaGVja1NyY3NldChzbGlkZSk7XHJcblxyXG4gICAgICAvLyBUaGlzIHdpbGwgYmUgd3JhcHBlciBjb250YWluaW5nIGJvdGggZ2hvc3QgYW5kIGFjdHVhbCBpbWFnZVxyXG4gICAgICBzbGlkZS4kY29udGVudCA9ICQoJzxkaXYgY2xhc3M9XCJmYW5jeWJveC1jb250ZW50XCI+PC9kaXY+JylcclxuICAgICAgICAuYWRkQ2xhc3MoXCJmYW5jeWJveC1pcy1oaWRkZW5cIilcclxuICAgICAgICAuYXBwZW5kVG8oc2xpZGUuJHNsaWRlLmFkZENsYXNzKFwiZmFuY3lib3gtc2xpZGUtLWltYWdlXCIpKTtcclxuXHJcbiAgICAgIC8vIElmIHdlIGhhdmUgYSB0aHVtYm5haWwsIHdlIGNhbiBkaXNwbGF5IGl0IHdoaWxlIGFjdHVhbCBpbWFnZSBpcyBsb2FkaW5nXHJcbiAgICAgIC8vIFVzZXJzIHdpbGwgbm90IHN0YXJlIGF0IGJsYWNrIHNjcmVlbiBhbmQgYWN0dWFsIGltYWdlIHdpbGwgYXBwZWFyIGdyYWR1YWxseVxyXG4gICAgICBpZiAoc2xpZGUub3B0cy5wcmVsb2FkICE9PSBmYWxzZSAmJiBzbGlkZS5vcHRzLndpZHRoICYmIHNsaWRlLm9wdHMuaGVpZ2h0ICYmIHNsaWRlLnRodW1iKSB7XHJcbiAgICAgICAgc2xpZGUud2lkdGggPSBzbGlkZS5vcHRzLndpZHRoO1xyXG4gICAgICAgIHNsaWRlLmhlaWdodCA9IHNsaWRlLm9wdHMuaGVpZ2h0O1xyXG5cclxuICAgICAgICBnaG9zdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJpbWdcIik7XHJcblxyXG4gICAgICAgIGdob3N0Lm9uZXJyb3IgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAkKHRoaXMpLnJlbW92ZSgpO1xyXG5cclxuICAgICAgICAgIHNsaWRlLiRnaG9zdCA9IG51bGw7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgZ2hvc3Qub25sb2FkID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgc2VsZi5hZnRlckxvYWQoc2xpZGUpO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHNsaWRlLiRnaG9zdCA9ICQoZ2hvc3QpXHJcbiAgICAgICAgICAuYWRkQ2xhc3MoXCJmYW5jeWJveC1pbWFnZVwiKVxyXG4gICAgICAgICAgLmFwcGVuZFRvKHNsaWRlLiRjb250ZW50KVxyXG4gICAgICAgICAgLmF0dHIoXCJzcmNcIiwgc2xpZGUudGh1bWIpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBTdGFydCBsb2FkaW5nIGFjdHVhbCBpbWFnZVxyXG4gICAgICBzZWxmLnNldEJpZ0ltYWdlKHNsaWRlKTtcclxuICAgIH0sXHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgaW1hZ2UgaGFzIHNyY3NldCBhbmQgZ2V0IHRoZSBzb3VyY2VcclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbiAgICBjaGVja1NyY3NldDogZnVuY3Rpb24gKHNsaWRlKSB7XHJcbiAgICAgIHZhciBzcmNzZXQgPSBzbGlkZS5vcHRzLnNyY3NldCB8fCBzbGlkZS5vcHRzLmltYWdlLnNyY3NldCxcclxuICAgICAgICBmb3VuZCxcclxuICAgICAgICB0ZW1wLFxyXG4gICAgICAgIHB4UmF0aW8sXHJcbiAgICAgICAgd2luZG93V2lkdGg7XHJcblxyXG4gICAgICAvLyBJZiB3ZSBoYXZlIFwic3Jjc2V0XCIsIHRoZW4gd2UgbmVlZCB0byBmaW5kIGZpcnN0IG1hdGNoaW5nIFwic3JjXCIgdmFsdWUuXHJcbiAgICAgIC8vIFRoaXMgaXMgbmVjZXNzYXJ5LCBiZWNhdXNlIHdoZW4geW91IHNldCBhbiBzcmMgYXR0cmlidXRlLCB0aGUgYnJvd3NlciB3aWxsIHByZWxvYWQgdGhlIGltYWdlXHJcbiAgICAgIC8vIGJlZm9yZSBhbnkgamF2YXNjcmlwdCBvciBldmVuIENTUyBpcyBhcHBsaWVkLlxyXG4gICAgICBpZiAoc3Jjc2V0KSB7XHJcbiAgICAgICAgcHhSYXRpbyA9IHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvIHx8IDE7XHJcbiAgICAgICAgd2luZG93V2lkdGggPSB3aW5kb3cuaW5uZXJXaWR0aCAqIHB4UmF0aW87XHJcblxyXG4gICAgICAgIHRlbXAgPSBzcmNzZXQuc3BsaXQoXCIsXCIpLm1hcChmdW5jdGlvbiAoZWwpIHtcclxuICAgICAgICAgIHZhciByZXQgPSB7fTtcclxuXHJcbiAgICAgICAgICBlbC50cmltKClcclxuICAgICAgICAgICAgLnNwbGl0KC9cXHMrLylcclxuICAgICAgICAgICAgLmZvckVhY2goZnVuY3Rpb24gKGVsLCBpKSB7XHJcbiAgICAgICAgICAgICAgdmFyIHZhbHVlID0gcGFyc2VJbnQoZWwuc3Vic3RyaW5nKDAsIGVsLmxlbmd0aCAtIDEpLCAxMCk7XHJcblxyXG4gICAgICAgICAgICAgIGlmIChpID09PSAwKSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gKHJldC51cmwgPSBlbCk7XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICBpZiAodmFsdWUpIHtcclxuICAgICAgICAgICAgICAgIHJldC52YWx1ZSA9IHZhbHVlO1xyXG4gICAgICAgICAgICAgICAgcmV0LnBvc3RmaXggPSBlbFtlbC5sZW5ndGggLSAxXTtcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgIHJldHVybiByZXQ7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFNvcnQgYnkgdmFsdWVcclxuICAgICAgICB0ZW1wLnNvcnQoZnVuY3Rpb24gKGEsIGIpIHtcclxuICAgICAgICAgIHJldHVybiBhLnZhbHVlIC0gYi52YWx1ZTtcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gT2ssIG5vdyB3ZSBoYXZlIGFuIGFycmF5IG9mIGFsbCBzcmNzZXQgdmFsdWVzXHJcbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCB0ZW1wLmxlbmd0aDsgaisrKSB7XHJcbiAgICAgICAgICB2YXIgZWwgPSB0ZW1wW2pdO1xyXG5cclxuICAgICAgICAgIGlmICgoZWwucG9zdGZpeCA9PT0gXCJ3XCIgJiYgZWwudmFsdWUgPj0gd2luZG93V2lkdGgpIHx8IChlbC5wb3N0Zml4ID09PSBcInhcIiAmJiBlbC52YWx1ZSA+PSBweFJhdGlvKSkge1xyXG4gICAgICAgICAgICBmb3VuZCA9IGVsO1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIElmIG5vdCBmb3VuZCwgdGFrZSB0aGUgbGFzdCBvbmVcclxuICAgICAgICBpZiAoIWZvdW5kICYmIHRlbXAubGVuZ3RoKSB7XHJcbiAgICAgICAgICBmb3VuZCA9IHRlbXBbdGVtcC5sZW5ndGggLSAxXTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmIChmb3VuZCkge1xyXG4gICAgICAgICAgc2xpZGUuc3JjID0gZm91bmQudXJsO1xyXG5cclxuICAgICAgICAgIC8vIElmIHdlIGhhdmUgZGVmYXVsdCB3aWR0aC9oZWlnaHQgdmFsdWVzLCB3ZSBjYW4gY2FsY3VsYXRlIGhlaWdodCBmb3IgbWF0Y2hpbmcgc291cmNlXHJcbiAgICAgICAgICBpZiAoc2xpZGUud2lkdGggJiYgc2xpZGUuaGVpZ2h0ICYmIGZvdW5kLnBvc3RmaXggPT0gXCJ3XCIpIHtcclxuICAgICAgICAgICAgc2xpZGUuaGVpZ2h0ID0gKHNsaWRlLndpZHRoIC8gc2xpZGUuaGVpZ2h0KSAqIGZvdW5kLnZhbHVlO1xyXG4gICAgICAgICAgICBzbGlkZS53aWR0aCA9IGZvdW5kLnZhbHVlO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHNsaWRlLm9wdHMuc3Jjc2V0ID0gc3Jjc2V0O1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICAvLyBDcmVhdGUgZnVsbC1zaXplIGltYWdlXHJcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgc2V0QmlnSW1hZ2U6IGZ1bmN0aW9uIChzbGlkZSkge1xyXG4gICAgICB2YXIgc2VsZiA9IHRoaXMsXHJcbiAgICAgICAgaW1nID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImltZ1wiKSxcclxuICAgICAgICAkaW1nID0gJChpbWcpO1xyXG5cclxuICAgICAgc2xpZGUuJGltYWdlID0gJGltZ1xyXG4gICAgICAgIC5vbmUoXCJlcnJvclwiLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICBzZWxmLnNldEVycm9yKHNsaWRlKTtcclxuICAgICAgICB9KVxyXG4gICAgICAgIC5vbmUoXCJsb2FkXCIsIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgIHZhciBzaXplcztcclxuXHJcbiAgICAgICAgICBpZiAoIXNsaWRlLiRnaG9zdCkge1xyXG4gICAgICAgICAgICBzZWxmLnJlc29sdmVJbWFnZVNsaWRlU2l6ZShzbGlkZSwgdGhpcy5uYXR1cmFsV2lkdGgsIHRoaXMubmF0dXJhbEhlaWdodCk7XHJcblxyXG4gICAgICAgICAgICBzZWxmLmFmdGVyTG9hZChzbGlkZSk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgaWYgKHNlbGYuaXNDbG9zaW5nKSB7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICBpZiAoc2xpZGUub3B0cy5zcmNzZXQpIHtcclxuICAgICAgICAgICAgc2l6ZXMgPSBzbGlkZS5vcHRzLnNpemVzO1xyXG5cclxuICAgICAgICAgICAgaWYgKCFzaXplcyB8fCBzaXplcyA9PT0gXCJhdXRvXCIpIHtcclxuICAgICAgICAgICAgICBzaXplcyA9XHJcbiAgICAgICAgICAgICAgICAoc2xpZGUud2lkdGggLyBzbGlkZS5oZWlnaHQgPiAxICYmICRXLndpZHRoKCkgLyAkVy5oZWlnaHQoKSA+IDEgPyBcIjEwMFwiIDogTWF0aC5yb3VuZCgoc2xpZGUud2lkdGggLyBzbGlkZS5oZWlnaHQpICogMTAwKSkgK1xyXG4gICAgICAgICAgICAgICAgXCJ2d1wiO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAkaW1nLmF0dHIoXCJzaXplc1wiLCBzaXplcykuYXR0cihcInNyY3NldFwiLCBzbGlkZS5vcHRzLnNyY3NldCk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgLy8gSGlkZSB0ZW1wb3JhcnkgaW1hZ2UgYWZ0ZXIgc29tZSBkZWxheVxyXG4gICAgICAgICAgaWYgKHNsaWRlLiRnaG9zdCkge1xyXG4gICAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgICBpZiAoc2xpZGUuJGdob3N0ICYmICFzZWxmLmlzQ2xvc2luZykge1xyXG4gICAgICAgICAgICAgICAgc2xpZGUuJGdob3N0LmhpZGUoKTtcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH0sIE1hdGgubWluKDMwMCwgTWF0aC5tYXgoMTAwMCwgc2xpZGUuaGVpZ2h0IC8gMTYwMCkpKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICBzZWxmLmhpZGVMb2FkaW5nKHNsaWRlKTtcclxuICAgICAgICB9KVxyXG4gICAgICAgIC5hZGRDbGFzcyhcImZhbmN5Ym94LWltYWdlXCIpXHJcbiAgICAgICAgLmF0dHIoXCJzcmNcIiwgc2xpZGUuc3JjKVxyXG4gICAgICAgIC5hcHBlbmRUbyhzbGlkZS4kY29udGVudCk7XHJcblxyXG4gICAgICBpZiAoKGltZy5jb21wbGV0ZSB8fCBpbWcucmVhZHlTdGF0ZSA9PSBcImNvbXBsZXRlXCIpICYmICRpbWcubmF0dXJhbFdpZHRoICYmICRpbWcubmF0dXJhbEhlaWdodCkge1xyXG4gICAgICAgICRpbWcudHJpZ2dlcihcImxvYWRcIik7XHJcbiAgICAgIH0gZWxzZSBpZiAoaW1nLmVycm9yKSB7XHJcbiAgICAgICAgJGltZy50cmlnZ2VyKFwiZXJyb3JcIik7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgLy8gQ29tcHV0ZXMgdGhlIHNsaWRlIHNpemUgZnJvbSBpbWFnZSBzaXplIGFuZCBtYXhXaWR0aC9tYXhIZWlnaHRcclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgcmVzb2x2ZUltYWdlU2xpZGVTaXplOiBmdW5jdGlvbiAoc2xpZGUsIGltZ1dpZHRoLCBpbWdIZWlnaHQpIHtcclxuICAgICAgdmFyIG1heFdpZHRoID0gcGFyc2VJbnQoc2xpZGUub3B0cy53aWR0aCwgMTApLFxyXG4gICAgICAgIG1heEhlaWdodCA9IHBhcnNlSW50KHNsaWRlLm9wdHMuaGVpZ2h0LCAxMCk7XHJcblxyXG4gICAgICAvLyBTZXRzIHRoZSBkZWZhdWx0IHZhbHVlcyBmcm9tIHRoZSBpbWFnZVxyXG4gICAgICBzbGlkZS53aWR0aCA9IGltZ1dpZHRoO1xyXG4gICAgICBzbGlkZS5oZWlnaHQgPSBpbWdIZWlnaHQ7XHJcblxyXG4gICAgICBpZiAobWF4V2lkdGggPiAwKSB7XHJcbiAgICAgICAgc2xpZGUud2lkdGggPSBtYXhXaWR0aDtcclxuICAgICAgICBzbGlkZS5oZWlnaHQgPSBNYXRoLmZsb29yKChtYXhXaWR0aCAqIGltZ0hlaWdodCkgLyBpbWdXaWR0aCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChtYXhIZWlnaHQgPiAwKSB7XHJcbiAgICAgICAgc2xpZGUud2lkdGggPSBNYXRoLmZsb29yKChtYXhIZWlnaHQgKiBpbWdXaWR0aCkgLyBpbWdIZWlnaHQpO1xyXG4gICAgICAgIHNsaWRlLmhlaWdodCA9IG1heEhlaWdodDtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICAvLyBDcmVhdGUgaWZyYW1lIHdyYXBwZXIsIGlmcmFtZSBhbmQgYmluZGluZ3NcclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIHNldElmcmFtZTogZnVuY3Rpb24gKHNsaWRlKSB7XHJcbiAgICAgIHZhciBzZWxmID0gdGhpcyxcclxuICAgICAgICBvcHRzID0gc2xpZGUub3B0cy5pZnJhbWUsXHJcbiAgICAgICAgJHNsaWRlID0gc2xpZGUuJHNsaWRlLFxyXG4gICAgICAgICRpZnJhbWU7XHJcblxyXG4gICAgICBzbGlkZS4kY29udGVudCA9ICQoJzxkaXYgY2xhc3M9XCJmYW5jeWJveC1jb250ZW50JyArIChvcHRzLnByZWxvYWQgPyBcIiBmYW5jeWJveC1pcy1oaWRkZW5cIiA6IFwiXCIpICsgJ1wiPjwvZGl2PicpXHJcbiAgICAgICAgLmNzcyhvcHRzLmNzcylcclxuICAgICAgICAuYXBwZW5kVG8oJHNsaWRlKTtcclxuXHJcbiAgICAgICRzbGlkZS5hZGRDbGFzcyhcImZhbmN5Ym94LXNsaWRlLS1cIiArIHNsaWRlLmNvbnRlbnRUeXBlKTtcclxuXHJcbiAgICAgIHNsaWRlLiRpZnJhbWUgPSAkaWZyYW1lID0gJChvcHRzLnRwbC5yZXBsYWNlKC9cXHtybmRcXH0vZywgbmV3IERhdGUoKS5nZXRUaW1lKCkpKVxyXG4gICAgICAgIC5hdHRyKG9wdHMuYXR0cilcclxuICAgICAgICAuYXBwZW5kVG8oc2xpZGUuJGNvbnRlbnQpO1xyXG5cclxuICAgICAgaWYgKG9wdHMucHJlbG9hZCkge1xyXG4gICAgICAgIHNlbGYuc2hvd0xvYWRpbmcoc2xpZGUpO1xyXG5cclxuICAgICAgICAvLyBVbmZvcnR1bmF0ZWx5LCBpdCBpcyBub3QgYWx3YXlzIHBvc3NpYmxlIHRvIGRldGVybWluZSBpZiBpZnJhbWUgaXMgc3VjY2Vzc2Z1bGx5IGxvYWRlZFxyXG4gICAgICAgIC8vIChkdWUgdG8gYnJvd3NlciBzZWN1cml0eSBwb2xpY3kpXHJcblxyXG4gICAgICAgICRpZnJhbWUub24oXCJsb2FkLmZiIGVycm9yLmZiXCIsIGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgICB0aGlzLmlzUmVhZHkgPSAxO1xyXG5cclxuICAgICAgICAgIHNsaWRlLiRzbGlkZS50cmlnZ2VyKFwicmVmcmVzaFwiKTtcclxuXHJcbiAgICAgICAgICBzZWxmLmFmdGVyTG9hZChzbGlkZSk7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFJlY2FsY3VsYXRlIGlmcmFtZSBjb250ZW50IHNpemVcclxuICAgICAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgICAgICRzbGlkZS5vbihcInJlZnJlc2guZmJcIiwgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgdmFyICRjb250ZW50ID0gc2xpZGUuJGNvbnRlbnQsXHJcbiAgICAgICAgICAgIGZyYW1lV2lkdGggPSBvcHRzLmNzcy53aWR0aCxcclxuICAgICAgICAgICAgZnJhbWVIZWlnaHQgPSBvcHRzLmNzcy5oZWlnaHQsXHJcbiAgICAgICAgICAgICRjb250ZW50cyxcclxuICAgICAgICAgICAgJGJvZHk7XHJcblxyXG4gICAgICAgICAgaWYgKCRpZnJhbWVbMF0uaXNSZWFkeSAhPT0gMSkge1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgJGNvbnRlbnRzID0gJGlmcmFtZS5jb250ZW50cygpO1xyXG4gICAgICAgICAgICAkYm9keSA9ICRjb250ZW50cy5maW5kKFwiYm9keVwiKTtcclxuICAgICAgICAgIH0gY2F0Y2ggKGlnbm9yZSkge31cclxuXHJcbiAgICAgICAgICAvLyBDYWxjdWxhdGUgY29udGVudCBkaW1lbnNpb25zLCBpZiBpdCBpcyBhY2Nlc3NpYmxlXHJcbiAgICAgICAgICBpZiAoJGJvZHkgJiYgJGJvZHkubGVuZ3RoICYmICRib2R5LmNoaWxkcmVuKCkubGVuZ3RoKSB7XHJcbiAgICAgICAgICAgIC8vIEF2b2lkIHNjcm9sbGluZyB0byB0b3AgKGlmIG11bHRpcGxlIGluc3RhbmNlcylcclxuICAgICAgICAgICAgJHNsaWRlLmNzcyhcIm92ZXJmbG93XCIsIFwidmlzaWJsZVwiKTtcclxuXHJcbiAgICAgICAgICAgICRjb250ZW50LmNzcyh7XHJcbiAgICAgICAgICAgICAgd2lkdGg6IFwiMTAwJVwiLFxyXG4gICAgICAgICAgICAgIFwibWF4LXdpZHRoXCI6IFwiMTAwJVwiLFxyXG4gICAgICAgICAgICAgIGhlaWdodDogXCI5OTk5cHhcIlxyXG4gICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgICAgIGlmIChmcmFtZVdpZHRoID09PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgICAgICBmcmFtZVdpZHRoID0gTWF0aC5jZWlsKE1hdGgubWF4KCRib2R5WzBdLmNsaWVudFdpZHRoLCAkYm9keS5vdXRlcldpZHRoKHRydWUpKSk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICRjb250ZW50LmNzcyhcIndpZHRoXCIsIGZyYW1lV2lkdGggPyBmcmFtZVdpZHRoIDogXCJcIikuY3NzKFwibWF4LXdpZHRoXCIsIFwiXCIpO1xyXG5cclxuICAgICAgICAgICAgaWYgKGZyYW1lSGVpZ2h0ID09PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgICAgICBmcmFtZUhlaWdodCA9IE1hdGguY2VpbChNYXRoLm1heCgkYm9keVswXS5jbGllbnRIZWlnaHQsICRib2R5Lm91dGVySGVpZ2h0KHRydWUpKSk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICRjb250ZW50LmNzcyhcImhlaWdodFwiLCBmcmFtZUhlaWdodCA/IGZyYW1lSGVpZ2h0IDogXCJcIik7XHJcblxyXG4gICAgICAgICAgICAkc2xpZGUuY3NzKFwib3ZlcmZsb3dcIiwgXCJhdXRvXCIpO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICRjb250ZW50LnJlbW92ZUNsYXNzKFwiZmFuY3lib3gtaXMtaGlkZGVuXCIpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHNlbGYuYWZ0ZXJMb2FkKHNsaWRlKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgJGlmcmFtZS5hdHRyKFwic3JjXCIsIHNsaWRlLnNyYyk7XHJcblxyXG4gICAgICAvLyBSZW1vdmUgaWZyYW1lIGlmIGNsb3Npbmcgb3IgY2hhbmdpbmcgZ2FsbGVyeSBpdGVtXHJcbiAgICAgICRzbGlkZS5vbmUoXCJvblJlc2V0XCIsIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAvLyBUaGlzIGhlbHBzIElFIG5vdCB0byB0aHJvdyBlcnJvcnMgd2hlbiBjbG9zaW5nXHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICQodGhpcylcclxuICAgICAgICAgICAgLmZpbmQoXCJpZnJhbWVcIilcclxuICAgICAgICAgICAgLmhpZGUoKVxyXG4gICAgICAgICAgICAudW5iaW5kKClcclxuICAgICAgICAgICAgLmF0dHIoXCJzcmNcIiwgXCIvL2Fib3V0OmJsYW5rXCIpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGlnbm9yZSkge31cclxuXHJcbiAgICAgICAgJCh0aGlzKVxyXG4gICAgICAgICAgLm9mZihcInJlZnJlc2guZmJcIilcclxuICAgICAgICAgIC5lbXB0eSgpO1xyXG5cclxuICAgICAgICBzbGlkZS5pc0xvYWRlZCA9IGZhbHNlO1xyXG4gICAgICAgIHNsaWRlLmlzUmV2ZWFsZWQgPSBmYWxzZTtcclxuICAgICAgfSk7XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIFdyYXAgYW5kIGFwcGVuZCBjb250ZW50IHRvIHRoZSBzbGlkZVxyXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICBzZXRDb250ZW50OiBmdW5jdGlvbiAoc2xpZGUsIGNvbnRlbnQpIHtcclxuICAgICAgdmFyIHNlbGYgPSB0aGlzO1xyXG5cclxuICAgICAgaWYgKHNlbGYuaXNDbG9zaW5nKSB7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBzZWxmLmhpZGVMb2FkaW5nKHNsaWRlKTtcclxuXHJcbiAgICAgIGlmIChzbGlkZS4kY29udGVudCkge1xyXG4gICAgICAgICQuZmFuY3lib3guc3RvcChzbGlkZS4kY29udGVudCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHNsaWRlLiRzbGlkZS5lbXB0eSgpO1xyXG5cclxuICAgICAgLy8gSWYgY29udGVudCBpcyBhIGpRdWVyeSBvYmplY3QsIHRoZW4gaXQgd2lsbCBiZSBtb3ZlZCB0byB0aGUgc2xpZGUuXHJcbiAgICAgIC8vIFRoZSBwbGFjZWhvbGRlciBpcyBjcmVhdGVkIHNvIHdlIHdpbGwga25vdyB3aGVyZSB0byBwdXQgaXQgYmFjay5cclxuICAgICAgaWYgKGlzUXVlcnkoY29udGVudCkgJiYgY29udGVudC5wYXJlbnQoKS5sZW5ndGgpIHtcclxuICAgICAgICAvLyBNYWtlIHN1cmUgY29udGVudCBpcyBub3QgYWxyZWFkeSBtb3ZlZCB0byBmYW5jeUJveFxyXG4gICAgICAgIGlmIChjb250ZW50Lmhhc0NsYXNzKFwiZmFuY3lib3gtY29udGVudFwiKSB8fCBjb250ZW50LnBhcmVudCgpLmhhc0NsYXNzKFwiZmFuY3lib3gtY29udGVudFwiKSkge1xyXG4gICAgICAgICAgY29udGVudC5wYXJlbnRzKFwiLmZhbmN5Ym94LXNsaWRlXCIpLnRyaWdnZXIoXCJvblJlc2V0XCIpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gQ3JlYXRlIHRlbXBvcmFyeSBlbGVtZW50IG1hcmtpbmcgb3JpZ2luYWwgcGxhY2Ugb2YgdGhlIGNvbnRlbnRcclxuICAgICAgICBzbGlkZS4kcGxhY2Vob2xkZXIgPSAkKFwiPGRpdj5cIilcclxuICAgICAgICAgIC5oaWRlKClcclxuICAgICAgICAgIC5pbnNlcnRBZnRlcihjb250ZW50KTtcclxuXHJcbiAgICAgICAgLy8gTWFrZSBzdXJlIGNvbnRlbnQgaXMgdmlzaWJsZVxyXG4gICAgICAgIGNvbnRlbnQuY3NzKFwiZGlzcGxheVwiLCBcImlubGluZS1ibG9ja1wiKTtcclxuICAgICAgfSBlbHNlIGlmICghc2xpZGUuaGFzRXJyb3IpIHtcclxuICAgICAgICAvLyBJZiBjb250ZW50IGlzIGp1c3QgYSBwbGFpbiB0ZXh0LCB0cnkgdG8gY29udmVydCBpdCB0byBodG1sXHJcbiAgICAgICAgaWYgKCQudHlwZShjb250ZW50KSA9PT0gXCJzdHJpbmdcIikge1xyXG4gICAgICAgICAgY29udGVudCA9ICQoXCI8ZGl2PlwiKVxyXG4gICAgICAgICAgICAuYXBwZW5kKCQudHJpbShjb250ZW50KSlcclxuICAgICAgICAgICAgLmNvbnRlbnRzKCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBJZiBcImZpbHRlclwiIG9wdGlvbiBpcyBwcm92aWRlZCwgdGhlbiBmaWx0ZXIgY29udGVudFxyXG4gICAgICAgIGlmIChzbGlkZS5vcHRzLmZpbHRlcikge1xyXG4gICAgICAgICAgY29udGVudCA9ICQoXCI8ZGl2PlwiKVxyXG4gICAgICAgICAgICAuaHRtbChjb250ZW50KVxyXG4gICAgICAgICAgICAuZmluZChzbGlkZS5vcHRzLmZpbHRlcik7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBzbGlkZS4kc2xpZGUub25lKFwib25SZXNldFwiLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgLy8gUGF1c2UgYWxsIGh0bWw1IHZpZGVvL2F1ZGlvXHJcbiAgICAgICAgJCh0aGlzKVxyXG4gICAgICAgICAgLmZpbmQoXCJ2aWRlbyxhdWRpb1wiKVxyXG4gICAgICAgICAgLnRyaWdnZXIoXCJwYXVzZVwiKTtcclxuXHJcbiAgICAgICAgLy8gUHV0IGNvbnRlbnQgYmFja1xyXG4gICAgICAgIGlmIChzbGlkZS4kcGxhY2Vob2xkZXIpIHtcclxuICAgICAgICAgIHNsaWRlLiRwbGFjZWhvbGRlci5hZnRlcihjb250ZW50LnJlbW92ZUNsYXNzKFwiZmFuY3lib3gtY29udGVudFwiKS5oaWRlKCkpLnJlbW92ZSgpO1xyXG5cclxuICAgICAgICAgIHNsaWRlLiRwbGFjZWhvbGRlciA9IG51bGw7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBSZW1vdmUgY3VzdG9tIGNsb3NlIGJ1dHRvblxyXG4gICAgICAgIGlmIChzbGlkZS4kc21hbGxCdG4pIHtcclxuICAgICAgICAgIHNsaWRlLiRzbWFsbEJ0bi5yZW1vdmUoKTtcclxuXHJcbiAgICAgICAgICBzbGlkZS4kc21hbGxCdG4gPSBudWxsO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gUmVtb3ZlIGNvbnRlbnQgYW5kIG1hcmsgc2xpZGUgYXMgbm90IGxvYWRlZFxyXG4gICAgICAgIGlmICghc2xpZGUuaGFzRXJyb3IpIHtcclxuICAgICAgICAgICQodGhpcykuZW1wdHkoKTtcclxuXHJcbiAgICAgICAgICBzbGlkZS5pc0xvYWRlZCA9IGZhbHNlO1xyXG4gICAgICAgICAgc2xpZGUuaXNSZXZlYWxlZCA9IGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICAkKGNvbnRlbnQpLmFwcGVuZFRvKHNsaWRlLiRzbGlkZSk7XHJcblxyXG4gICAgICBpZiAoJChjb250ZW50KS5pcyhcInZpZGVvLGF1ZGlvXCIpKSB7XHJcbiAgICAgICAgJChjb250ZW50KS5hZGRDbGFzcyhcImZhbmN5Ym94LXZpZGVvXCIpO1xyXG5cclxuICAgICAgICAkKGNvbnRlbnQpLndyYXAoXCI8ZGl2PjwvZGl2PlwiKTtcclxuXHJcbiAgICAgICAgc2xpZGUuY29udGVudFR5cGUgPSBcInZpZGVvXCI7XHJcblxyXG4gICAgICAgIHNsaWRlLm9wdHMud2lkdGggPSBzbGlkZS5vcHRzLndpZHRoIHx8ICQoY29udGVudCkuYXR0cihcIndpZHRoXCIpO1xyXG4gICAgICAgIHNsaWRlLm9wdHMuaGVpZ2h0ID0gc2xpZGUub3B0cy5oZWlnaHQgfHwgJChjb250ZW50KS5hdHRyKFwiaGVpZ2h0XCIpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBzbGlkZS4kY29udGVudCA9IHNsaWRlLiRzbGlkZVxyXG4gICAgICAgIC5jaGlsZHJlbigpXHJcbiAgICAgICAgLmZpbHRlcihcImRpdixmb3JtLG1haW4sdmlkZW8sYXVkaW8sYXJ0aWNsZSwuZmFuY3lib3gtY29udGVudFwiKVxyXG4gICAgICAgIC5maXJzdCgpO1xyXG5cclxuICAgICAgc2xpZGUuJGNvbnRlbnQuc2libGluZ3MoKS5oaWRlKCk7XHJcblxyXG4gICAgICAvLyBSZS1jaGVjayBpZiB0aGVyZSBpcyBhIHZhbGlkIGNvbnRlbnRcclxuICAgICAgLy8gKGluIHNvbWUgY2FzZXMsIGFqYXggcmVzcG9uc2UgY2FuIGNvbnRhaW4gdmFyaW91cyBlbGVtZW50cyBvciBwbGFpbiB0ZXh0KVxyXG4gICAgICBpZiAoIXNsaWRlLiRjb250ZW50Lmxlbmd0aCkge1xyXG4gICAgICAgIHNsaWRlLiRjb250ZW50ID0gc2xpZGUuJHNsaWRlXHJcbiAgICAgICAgICAud3JhcElubmVyKFwiPGRpdj48L2Rpdj5cIilcclxuICAgICAgICAgIC5jaGlsZHJlbigpXHJcbiAgICAgICAgICAuZmlyc3QoKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgc2xpZGUuJGNvbnRlbnQuYWRkQ2xhc3MoXCJmYW5jeWJveC1jb250ZW50XCIpO1xyXG5cclxuICAgICAgc2xpZGUuJHNsaWRlLmFkZENsYXNzKFwiZmFuY3lib3gtc2xpZGUtLVwiICsgc2xpZGUuY29udGVudFR5cGUpO1xyXG5cclxuICAgICAgc2VsZi5hZnRlckxvYWQoc2xpZGUpO1xyXG4gICAgfSxcclxuXHJcbiAgICAvLyBEaXNwbGF5IGVycm9yIG1lc3NhZ2VcclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIHNldEVycm9yOiBmdW5jdGlvbiAoc2xpZGUpIHtcclxuICAgICAgc2xpZGUuaGFzRXJyb3IgPSB0cnVlO1xyXG5cclxuICAgICAgc2xpZGUuJHNsaWRlXHJcbiAgICAgICAgLnRyaWdnZXIoXCJvblJlc2V0XCIpXHJcbiAgICAgICAgLnJlbW92ZUNsYXNzKFwiZmFuY3lib3gtc2xpZGUtLVwiICsgc2xpZGUuY29udGVudFR5cGUpXHJcbiAgICAgICAgLmFkZENsYXNzKFwiZmFuY3lib3gtc2xpZGUtLWVycm9yXCIpO1xyXG5cclxuICAgICAgc2xpZGUuY29udGVudFR5cGUgPSBcImh0bWxcIjtcclxuXHJcbiAgICAgIHRoaXMuc2V0Q29udGVudChzbGlkZSwgdGhpcy50cmFuc2xhdGUoc2xpZGUsIHNsaWRlLm9wdHMuZXJyb3JUcGwpKTtcclxuXHJcbiAgICAgIGlmIChzbGlkZS5wb3MgPT09IHRoaXMuY3VyclBvcykge1xyXG4gICAgICAgIHRoaXMuaXNBbmltYXRpbmcgPSBmYWxzZTtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICAvLyBTaG93IGxvYWRpbmcgaWNvbiBpbnNpZGUgdGhlIHNsaWRlXHJcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgc2hvd0xvYWRpbmc6IGZ1bmN0aW9uIChzbGlkZSkge1xyXG4gICAgICB2YXIgc2VsZiA9IHRoaXM7XHJcblxyXG4gICAgICBzbGlkZSA9IHNsaWRlIHx8IHNlbGYuY3VycmVudDtcclxuXHJcbiAgICAgIGlmIChzbGlkZSAmJiAhc2xpZGUuJHNwaW5uZXIpIHtcclxuICAgICAgICBzbGlkZS4kc3Bpbm5lciA9ICQoc2VsZi50cmFuc2xhdGUoc2VsZiwgc2VsZi5vcHRzLnNwaW5uZXJUcGwpKVxyXG4gICAgICAgICAgLmFwcGVuZFRvKHNsaWRlLiRzbGlkZSlcclxuICAgICAgICAgIC5oaWRlKClcclxuICAgICAgICAgIC5mYWRlSW4oXCJmYXN0XCIpO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIFJlbW92ZSBsb2FkaW5nIGljb24gZnJvbSB0aGUgc2xpZGVcclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICBoaWRlTG9hZGluZzogZnVuY3Rpb24gKHNsaWRlKSB7XHJcbiAgICAgIHZhciBzZWxmID0gdGhpcztcclxuXHJcbiAgICAgIHNsaWRlID0gc2xpZGUgfHwgc2VsZi5jdXJyZW50O1xyXG5cclxuICAgICAgaWYgKHNsaWRlICYmIHNsaWRlLiRzcGlubmVyKSB7XHJcbiAgICAgICAgc2xpZGUuJHNwaW5uZXIuc3RvcCgpLnJlbW92ZSgpO1xyXG5cclxuICAgICAgICBkZWxldGUgc2xpZGUuJHNwaW5uZXI7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgLy8gQWRqdXN0bWVudHMgYWZ0ZXIgc2xpZGUgY29udGVudCBoYXMgYmVlbiBsb2FkZWRcclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgYWZ0ZXJMb2FkOiBmdW5jdGlvbiAoc2xpZGUpIHtcclxuICAgICAgdmFyIHNlbGYgPSB0aGlzO1xyXG5cclxuICAgICAgaWYgKHNlbGYuaXNDbG9zaW5nKSB7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBzbGlkZS5pc0xvYWRpbmcgPSBmYWxzZTtcclxuICAgICAgc2xpZGUuaXNMb2FkZWQgPSB0cnVlO1xyXG5cclxuICAgICAgc2VsZi50cmlnZ2VyKFwiYWZ0ZXJMb2FkXCIsIHNsaWRlKTtcclxuXHJcbiAgICAgIHNlbGYuaGlkZUxvYWRpbmcoc2xpZGUpO1xyXG5cclxuICAgICAgLy8gQWRkIHNtYWxsIGNsb3NlIGJ1dHRvblxyXG4gICAgICBpZiAoc2xpZGUub3B0cy5zbWFsbEJ0biAmJiAoIXNsaWRlLiRzbWFsbEJ0biB8fCAhc2xpZGUuJHNtYWxsQnRuLmxlbmd0aCkpIHtcclxuICAgICAgICBzbGlkZS4kc21hbGxCdG4gPSAkKHNlbGYudHJhbnNsYXRlKHNsaWRlLCBzbGlkZS5vcHRzLmJ0blRwbC5zbWFsbEJ0bikpLmFwcGVuZFRvKHNsaWRlLiRjb250ZW50KTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRGlzYWJsZSByaWdodCBjbGlja1xyXG4gICAgICBpZiAoc2xpZGUub3B0cy5wcm90ZWN0ICYmIHNsaWRlLiRjb250ZW50ICYmICFzbGlkZS5oYXNFcnJvcikge1xyXG4gICAgICAgIHNsaWRlLiRjb250ZW50Lm9uKFwiY29udGV4dG1lbnUuZmJcIiwgZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICAgIGlmIChlLmJ1dHRvbiA9PSAyKSB7XHJcbiAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gQWRkIGZha2UgZWxlbWVudCBvbiB0b3Agb2YgdGhlIGltYWdlXHJcbiAgICAgICAgLy8gVGhpcyBtYWtlcyBhIGJpdCBoYXJkZXIgZm9yIHVzZXIgdG8gc2VsZWN0IGltYWdlXHJcbiAgICAgICAgaWYgKHNsaWRlLnR5cGUgPT09IFwiaW1hZ2VcIikge1xyXG4gICAgICAgICAgJCgnPGRpdiBjbGFzcz1cImZhbmN5Ym94LXNwYWNlYmFsbFwiPjwvZGl2PicpLmFwcGVuZFRvKHNsaWRlLiRjb250ZW50KTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHNlbGYuYWRqdXN0Q2FwdGlvbihzbGlkZSk7XHJcblxyXG4gICAgICBzZWxmLmFkanVzdExheW91dChzbGlkZSk7XHJcblxyXG4gICAgICBpZiAoc2xpZGUucG9zID09PSBzZWxmLmN1cnJQb3MpIHtcclxuICAgICAgICBzZWxmLnVwZGF0ZUN1cnNvcigpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBzZWxmLnJldmVhbENvbnRlbnQoc2xpZGUpO1xyXG4gICAgfSxcclxuXHJcbiAgICAvLyBQcmV2ZW50IGNhcHRpb24gb3ZlcmxhcCxcclxuICAgIC8vIGZpeCBjc3MgaW5jb25zaXN0ZW5jeSBhY3Jvc3MgYnJvd3NlcnNcclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICBhZGp1c3RDYXB0aW9uOiBmdW5jdGlvbiAoc2xpZGUpIHtcclxuICAgICAgdmFyIHNlbGYgPSB0aGlzLFxyXG4gICAgICAgIGN1cnJlbnQgPSBzbGlkZSB8fCBzZWxmLmN1cnJlbnQsXHJcbiAgICAgICAgY2FwdGlvbiA9IGN1cnJlbnQub3B0cy5jYXB0aW9uLFxyXG4gICAgICAgIHByZXZlbnRPdmVybGFwID0gY3VycmVudC5vcHRzLnByZXZlbnRDYXB0aW9uT3ZlcmxhcCxcclxuICAgICAgICAkY2FwdGlvbiA9IHNlbGYuJHJlZnMuY2FwdGlvbixcclxuICAgICAgICAkY2xvbmUsXHJcbiAgICAgICAgY2FwdGlvbkggPSBmYWxzZTtcclxuXHJcbiAgICAgICRjYXB0aW9uLnRvZ2dsZUNsYXNzKFwiZmFuY3lib3gtY2FwdGlvbi0tc2VwYXJhdGVcIiwgcHJldmVudE92ZXJsYXApO1xyXG5cclxuICAgICAgaWYgKHByZXZlbnRPdmVybGFwICYmIGNhcHRpb24gJiYgY2FwdGlvbi5sZW5ndGgpIHtcclxuICAgICAgICBpZiAoY3VycmVudC5wb3MgIT09IHNlbGYuY3VyclBvcykge1xyXG4gICAgICAgICAgJGNsb25lID0gJGNhcHRpb24uY2xvbmUoKS5hcHBlbmRUbygkY2FwdGlvbi5wYXJlbnQoKSk7XHJcblxyXG4gICAgICAgICAgJGNsb25lXHJcbiAgICAgICAgICAgIC5jaGlsZHJlbigpXHJcbiAgICAgICAgICAgIC5lcSgwKVxyXG4gICAgICAgICAgICAuZW1wdHkoKVxyXG4gICAgICAgICAgICAuaHRtbChjYXB0aW9uKTtcclxuXHJcbiAgICAgICAgICBjYXB0aW9uSCA9ICRjbG9uZS5vdXRlckhlaWdodCh0cnVlKTtcclxuXHJcbiAgICAgICAgICAkY2xvbmUuZW1wdHkoKS5yZW1vdmUoKTtcclxuICAgICAgICB9IGVsc2UgaWYgKHNlbGYuJGNhcHRpb24pIHtcclxuICAgICAgICAgIGNhcHRpb25IID0gc2VsZi4kY2FwdGlvbi5vdXRlckhlaWdodCh0cnVlKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGN1cnJlbnQuJHNsaWRlLmNzcyhcInBhZGRpbmctYm90dG9tXCIsIGNhcHRpb25IIHx8IFwiXCIpO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIFNpbXBsZSBoYWNrIHRvIGZpeCBpbmNvbnNpc3RlbmN5IGFjcm9zcyBicm93c2VycywgZGVzY3JpYmVkIGhlcmUgKGFmZmVjdHMgRWRnZSwgdG9vKTpcclxuICAgIC8vIGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTc0ODUxOFxyXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgYWRqdXN0TGF5b3V0OiBmdW5jdGlvbiAoc2xpZGUpIHtcclxuICAgICAgdmFyIHNlbGYgPSB0aGlzLFxyXG4gICAgICAgIGN1cnJlbnQgPSBzbGlkZSB8fCBzZWxmLmN1cnJlbnQsXHJcbiAgICAgICAgc2Nyb2xsSGVpZ2h0LFxyXG4gICAgICAgIG1hcmdpbkJvdHRvbSxcclxuICAgICAgICBpbmxpbmVQYWRkaW5nLFxyXG4gICAgICAgIGFjdHVhbFBhZGRpbmc7XHJcblxyXG4gICAgICBpZiAoY3VycmVudC5pc0xvYWRlZCAmJiBjdXJyZW50Lm9wdHMuZGlzYWJsZUxheW91dEZpeCAhPT0gdHJ1ZSkge1xyXG4gICAgICAgIGN1cnJlbnQuJGNvbnRlbnQuY3NzKFwibWFyZ2luLWJvdHRvbVwiLCBcIlwiKTtcclxuXHJcbiAgICAgICAgLy8gSWYgd2Ugd291bGQgYWx3YXlzIHNldCBtYXJnaW4tYm90dG9tIGZvciB0aGUgY29udGVudCxcclxuICAgICAgICAvLyB0aGVuIGl0IHdvdWxkIHBvdGVudGlhbGx5IGJyZWFrIHZlcnRpY2FsIGFsaWduXHJcbiAgICAgICAgaWYgKGN1cnJlbnQuJGNvbnRlbnQub3V0ZXJIZWlnaHQoKSA+IGN1cnJlbnQuJHNsaWRlLmhlaWdodCgpICsgMC41KSB7XHJcbiAgICAgICAgICBpbmxpbmVQYWRkaW5nID0gY3VycmVudC4kc2xpZGVbMF0uc3R5bGVbXCJwYWRkaW5nLWJvdHRvbVwiXTtcclxuICAgICAgICAgIGFjdHVhbFBhZGRpbmcgPSBjdXJyZW50LiRzbGlkZS5jc3MoXCJwYWRkaW5nLWJvdHRvbVwiKTtcclxuXHJcbiAgICAgICAgICBpZiAocGFyc2VGbG9hdChhY3R1YWxQYWRkaW5nKSA+IDApIHtcclxuICAgICAgICAgICAgc2Nyb2xsSGVpZ2h0ID0gY3VycmVudC4kc2xpZGVbMF0uc2Nyb2xsSGVpZ2h0O1xyXG5cclxuICAgICAgICAgICAgY3VycmVudC4kc2xpZGUuY3NzKFwicGFkZGluZy1ib3R0b21cIiwgMCk7XHJcblxyXG4gICAgICAgICAgICBpZiAoTWF0aC5hYnMoc2Nyb2xsSGVpZ2h0IC0gY3VycmVudC4kc2xpZGVbMF0uc2Nyb2xsSGVpZ2h0KSA8IDEpIHtcclxuICAgICAgICAgICAgICBtYXJnaW5Cb3R0b20gPSBhY3R1YWxQYWRkaW5nO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICBjdXJyZW50LiRzbGlkZS5jc3MoXCJwYWRkaW5nLWJvdHRvbVwiLCBpbmxpbmVQYWRkaW5nKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGN1cnJlbnQuJGNvbnRlbnQuY3NzKFwibWFyZ2luLWJvdHRvbVwiLCBtYXJnaW5Cb3R0b20pO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIE1ha2UgY29udGVudCB2aXNpYmxlXHJcbiAgICAvLyBUaGlzIG1ldGhvZCBpcyBjYWxsZWQgcmlnaHQgYWZ0ZXIgY29udGVudCBoYXMgYmVlbiBsb2FkZWQgb3JcclxuICAgIC8vIHVzZXIgbmF2aWdhdGVzIGdhbGxlcnkgYW5kIHRyYW5zaXRpb24gc2hvdWxkIHN0YXJ0XHJcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICByZXZlYWxDb250ZW50OiBmdW5jdGlvbiAoc2xpZGUpIHtcclxuICAgICAgdmFyIHNlbGYgPSB0aGlzLFxyXG4gICAgICAgICRzbGlkZSA9IHNsaWRlLiRzbGlkZSxcclxuICAgICAgICBlbmQgPSBmYWxzZSxcclxuICAgICAgICBzdGFydCA9IGZhbHNlLFxyXG4gICAgICAgIGlzTW92ZWQgPSBzZWxmLmlzTW92ZWQoc2xpZGUpLFxyXG4gICAgICAgIGlzUmV2ZWFsZWQgPSBzbGlkZS5pc1JldmVhbGVkLFxyXG4gICAgICAgIGVmZmVjdCxcclxuICAgICAgICBlZmZlY3RDbGFzc05hbWUsXHJcbiAgICAgICAgZHVyYXRpb24sXHJcbiAgICAgICAgb3BhY2l0eTtcclxuXHJcbiAgICAgIHNsaWRlLmlzUmV2ZWFsZWQgPSB0cnVlO1xyXG5cclxuICAgICAgZWZmZWN0ID0gc2xpZGUub3B0c1tzZWxmLmZpcnN0UnVuID8gXCJhbmltYXRpb25FZmZlY3RcIiA6IFwidHJhbnNpdGlvbkVmZmVjdFwiXTtcclxuICAgICAgZHVyYXRpb24gPSBzbGlkZS5vcHRzW3NlbGYuZmlyc3RSdW4gPyBcImFuaW1hdGlvbkR1cmF0aW9uXCIgOiBcInRyYW5zaXRpb25EdXJhdGlvblwiXTtcclxuXHJcbiAgICAgIGR1cmF0aW9uID0gcGFyc2VJbnQoc2xpZGUuZm9yY2VkRHVyYXRpb24gPT09IHVuZGVmaW5lZCA/IGR1cmF0aW9uIDogc2xpZGUuZm9yY2VkRHVyYXRpb24sIDEwKTtcclxuXHJcbiAgICAgIGlmIChpc01vdmVkIHx8IHNsaWRlLnBvcyAhPT0gc2VsZi5jdXJyUG9zIHx8ICFkdXJhdGlvbikge1xyXG4gICAgICAgIGVmZmVjdCA9IGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiBjYW4gem9vbVxyXG4gICAgICBpZiAoZWZmZWN0ID09PSBcInpvb21cIikge1xyXG4gICAgICAgIGlmIChzbGlkZS5wb3MgPT09IHNlbGYuY3VyclBvcyAmJiBkdXJhdGlvbiAmJiBzbGlkZS50eXBlID09PSBcImltYWdlXCIgJiYgIXNsaWRlLmhhc0Vycm9yICYmIChzdGFydCA9IHNlbGYuZ2V0VGh1bWJQb3Moc2xpZGUpKSkge1xyXG4gICAgICAgICAgZW5kID0gc2VsZi5nZXRGaXRQb3Moc2xpZGUpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBlZmZlY3QgPSBcImZhZGVcIjtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFpvb20gYW5pbWF0aW9uXHJcbiAgICAgIC8vID09PT09PT09PT09PT09XHJcbiAgICAgIGlmIChlZmZlY3QgPT09IFwiem9vbVwiKSB7XHJcbiAgICAgICAgc2VsZi5pc0FuaW1hdGluZyA9IHRydWU7XHJcblxyXG4gICAgICAgIGVuZC5zY2FsZVggPSBlbmQud2lkdGggLyBzdGFydC53aWR0aDtcclxuICAgICAgICBlbmQuc2NhbGVZID0gZW5kLmhlaWdodCAvIHN0YXJ0LmhlaWdodDtcclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaWYgd2UgbmVlZCB0byBhbmltYXRlIG9wYWNpdHlcclxuICAgICAgICBvcGFjaXR5ID0gc2xpZGUub3B0cy56b29tT3BhY2l0eTtcclxuXHJcbiAgICAgICAgaWYgKG9wYWNpdHkgPT0gXCJhdXRvXCIpIHtcclxuICAgICAgICAgIG9wYWNpdHkgPSBNYXRoLmFicyhzbGlkZS53aWR0aCAvIHNsaWRlLmhlaWdodCAtIHN0YXJ0LndpZHRoIC8gc3RhcnQuaGVpZ2h0KSA+IDAuMTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmIChvcGFjaXR5KSB7XHJcbiAgICAgICAgICBzdGFydC5vcGFjaXR5ID0gMC4xO1xyXG4gICAgICAgICAgZW5kLm9wYWNpdHkgPSAxO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gRHJhdyBpbWFnZSBhdCBzdGFydCBwb3NpdGlvblxyXG4gICAgICAgICQuZmFuY3lib3guc2V0VHJhbnNsYXRlKHNsaWRlLiRjb250ZW50LnJlbW92ZUNsYXNzKFwiZmFuY3lib3gtaXMtaGlkZGVuXCIpLCBzdGFydCk7XHJcblxyXG4gICAgICAgIGZvcmNlUmVkcmF3KHNsaWRlLiRjb250ZW50KTtcclxuXHJcbiAgICAgICAgLy8gU3RhcnQgYW5pbWF0aW9uXHJcbiAgICAgICAgJC5mYW5jeWJveC5hbmltYXRlKHNsaWRlLiRjb250ZW50LCBlbmQsIGR1cmF0aW9uLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICBzZWxmLmlzQW5pbWF0aW5nID0gZmFsc2U7XHJcblxyXG4gICAgICAgICAgc2VsZi5jb21wbGV0ZSgpO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHNlbGYudXBkYXRlU2xpZGUoc2xpZGUpO1xyXG5cclxuICAgICAgLy8gU2ltcGx5IHNob3cgY29udGVudCBpZiBubyBlZmZlY3RcclxuICAgICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuICAgICAgaWYgKCFlZmZlY3QpIHtcclxuICAgICAgICBzbGlkZS4kY29udGVudC5yZW1vdmVDbGFzcyhcImZhbmN5Ym94LWlzLWhpZGRlblwiKTtcclxuXHJcbiAgICAgICAgaWYgKCFpc1JldmVhbGVkICYmIGlzTW92ZWQgJiYgc2xpZGUudHlwZSA9PT0gXCJpbWFnZVwiICYmICFzbGlkZS5oYXNFcnJvcikge1xyXG4gICAgICAgICAgc2xpZGUuJGNvbnRlbnQuaGlkZSgpLmZhZGVJbihcImZhc3RcIik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoc2xpZGUucG9zID09PSBzZWxmLmN1cnJQb3MpIHtcclxuICAgICAgICAgIHNlbGYuY29tcGxldGUoKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gUHJlcGFyZSBmb3IgQ1NTIHRyYW5zaXRvblxyXG4gICAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09XHJcbiAgICAgICQuZmFuY3lib3guc3RvcCgkc2xpZGUpO1xyXG5cclxuICAgICAgLy9lZmZlY3RDbGFzc05hbWUgPSBcImZhbmN5Ym94LWFuaW1hdGVkIGZhbmN5Ym94LXNsaWRlLS1cIiArIChzbGlkZS5wb3MgPj0gc2VsZi5wcmV2UG9zID8gXCJuZXh0XCIgOiBcInByZXZpb3VzXCIpICsgXCIgZmFuY3lib3gtZngtXCIgKyBlZmZlY3Q7XHJcbiAgICAgIGVmZmVjdENsYXNzTmFtZSA9IFwiZmFuY3lib3gtc2xpZGUtLVwiICsgKHNsaWRlLnBvcyA+PSBzZWxmLnByZXZQb3MgPyBcIm5leHRcIiA6IFwicHJldmlvdXNcIikgKyBcIiBmYW5jeWJveC1hbmltYXRlZCBmYW5jeWJveC1meC1cIiArIGVmZmVjdDtcclxuXHJcbiAgICAgICRzbGlkZS5hZGRDbGFzcyhlZmZlY3RDbGFzc05hbWUpLnJlbW92ZUNsYXNzKFwiZmFuY3lib3gtc2xpZGUtLWN1cnJlbnRcIik7IC8vLmFkZENsYXNzKGVmZmVjdENsYXNzTmFtZSk7XHJcblxyXG4gICAgICBzbGlkZS4kY29udGVudC5yZW1vdmVDbGFzcyhcImZhbmN5Ym94LWlzLWhpZGRlblwiKTtcclxuXHJcbiAgICAgIC8vIEZvcmNlIHJlZmxvd1xyXG4gICAgICBmb3JjZVJlZHJhdygkc2xpZGUpO1xyXG5cclxuICAgICAgaWYgKHNsaWRlLnR5cGUgIT09IFwiaW1hZ2VcIikge1xyXG4gICAgICAgIHNsaWRlLiRjb250ZW50LmhpZGUoKS5zaG93KDApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAkLmZhbmN5Ym94LmFuaW1hdGUoXHJcbiAgICAgICAgJHNsaWRlLFxyXG4gICAgICAgIFwiZmFuY3lib3gtc2xpZGUtLWN1cnJlbnRcIixcclxuICAgICAgICBkdXJhdGlvbixcclxuICAgICAgICBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAkc2xpZGUucmVtb3ZlQ2xhc3MoZWZmZWN0Q2xhc3NOYW1lKS5jc3Moe1xyXG4gICAgICAgICAgICB0cmFuc2Zvcm06IFwiXCIsXHJcbiAgICAgICAgICAgIG9wYWNpdHk6IFwiXCJcclxuICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgIGlmIChzbGlkZS5wb3MgPT09IHNlbGYuY3VyclBvcykge1xyXG4gICAgICAgICAgICBzZWxmLmNvbXBsZXRlKCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSxcclxuICAgICAgICB0cnVlXHJcbiAgICAgICk7XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIENoZWNrIGlmIHdlIGNhbiBhbmQgaGF2ZSB0byB6b29tIGZyb20gdGh1bWJuYWlsXHJcbiAgICAvLz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIGdldFRodW1iUG9zOiBmdW5jdGlvbiAoc2xpZGUpIHtcclxuICAgICAgdmFyIHJleiA9IGZhbHNlLFxyXG4gICAgICAgICR0aHVtYiA9IHNsaWRlLiR0aHVtYixcclxuICAgICAgICB0aHVtYlBvcyxcclxuICAgICAgICBidHcsXHJcbiAgICAgICAgYnJ3LFxyXG4gICAgICAgIGJidyxcclxuICAgICAgICBibHc7XHJcblxyXG4gICAgICBpZiAoISR0aHVtYiB8fCAhaW5WaWV3cG9ydCgkdGh1bWJbMF0pKSB7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICB0aHVtYlBvcyA9ICQuZmFuY3lib3guZ2V0VHJhbnNsYXRlKCR0aHVtYik7XHJcblxyXG4gICAgICBidHcgPSBwYXJzZUZsb2F0KCR0aHVtYi5jc3MoXCJib3JkZXItdG9wLXdpZHRoXCIpIHx8IDApO1xyXG4gICAgICBicncgPSBwYXJzZUZsb2F0KCR0aHVtYi5jc3MoXCJib3JkZXItcmlnaHQtd2lkdGhcIikgfHwgMCk7XHJcbiAgICAgIGJidyA9IHBhcnNlRmxvYXQoJHRodW1iLmNzcyhcImJvcmRlci1ib3R0b20td2lkdGhcIikgfHwgMCk7XHJcbiAgICAgIGJsdyA9IHBhcnNlRmxvYXQoJHRodW1iLmNzcyhcImJvcmRlci1sZWZ0LXdpZHRoXCIpIHx8IDApO1xyXG5cclxuICAgICAgcmV6ID0ge1xyXG4gICAgICAgIHRvcDogdGh1bWJQb3MudG9wICsgYnR3LFxyXG4gICAgICAgIGxlZnQ6IHRodW1iUG9zLmxlZnQgKyBibHcsXHJcbiAgICAgICAgd2lkdGg6IHRodW1iUG9zLndpZHRoIC0gYnJ3IC0gYmx3LFxyXG4gICAgICAgIGhlaWdodDogdGh1bWJQb3MuaGVpZ2h0IC0gYnR3IC0gYmJ3LFxyXG4gICAgICAgIHNjYWxlWDogMSxcclxuICAgICAgICBzY2FsZVk6IDFcclxuICAgICAgfTtcclxuXHJcbiAgICAgIHJldHVybiB0aHVtYlBvcy53aWR0aCA+IDAgJiYgdGh1bWJQb3MuaGVpZ2h0ID4gMCA/IHJleiA6IGZhbHNlO1xyXG4gICAgfSxcclxuXHJcbiAgICAvLyBGaW5hbCBhZGp1c3RtZW50cyBhZnRlciBjdXJyZW50IGdhbGxlcnkgaXRlbSBpcyBtb3ZlZCB0byBwb3NpdGlvblxyXG4gICAgLy8gYW5kIGl0YHMgY29udGVudCBpcyBsb2FkZWRcclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIGNvbXBsZXRlOiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHZhciBzZWxmID0gdGhpcyxcclxuICAgICAgICBjdXJyZW50ID0gc2VsZi5jdXJyZW50LFxyXG4gICAgICAgIHNsaWRlcyA9IHt9LFxyXG4gICAgICAgICRlbDtcclxuXHJcbiAgICAgIGlmIChzZWxmLmlzTW92ZWQoKSB8fCAhY3VycmVudC5pc0xvYWRlZCkge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKCFjdXJyZW50LmlzQ29tcGxldGUpIHtcclxuICAgICAgICBjdXJyZW50LmlzQ29tcGxldGUgPSB0cnVlO1xyXG5cclxuICAgICAgICBjdXJyZW50LiRzbGlkZS5zaWJsaW5ncygpLnRyaWdnZXIoXCJvblJlc2V0XCIpO1xyXG5cclxuICAgICAgICBzZWxmLnByZWxvYWQoXCJpbmxpbmVcIik7XHJcblxyXG4gICAgICAgIC8vIFRyaWdnZXIgYW55IENTUyB0cmFuc2l0b24gaW5zaWRlIHRoZSBzbGlkZVxyXG4gICAgICAgIGZvcmNlUmVkcmF3KGN1cnJlbnQuJHNsaWRlKTtcclxuXHJcbiAgICAgICAgY3VycmVudC4kc2xpZGUuYWRkQ2xhc3MoXCJmYW5jeWJveC1zbGlkZS0tY29tcGxldGVcIik7XHJcblxyXG4gICAgICAgIC8vIFJlbW92ZSB1bm5lY2Vzc2FyeSBzbGlkZXNcclxuICAgICAgICAkLmVhY2goc2VsZi5zbGlkZXMsIGZ1bmN0aW9uIChrZXksIHNsaWRlKSB7XHJcbiAgICAgICAgICBpZiAoc2xpZGUucG9zID49IHNlbGYuY3VyclBvcyAtIDEgJiYgc2xpZGUucG9zIDw9IHNlbGYuY3VyclBvcyArIDEpIHtcclxuICAgICAgICAgICAgc2xpZGVzW3NsaWRlLnBvc10gPSBzbGlkZTtcclxuICAgICAgICAgIH0gZWxzZSBpZiAoc2xpZGUpIHtcclxuICAgICAgICAgICAgJC5mYW5jeWJveC5zdG9wKHNsaWRlLiRzbGlkZSk7XHJcblxyXG4gICAgICAgICAgICBzbGlkZS4kc2xpZGUub2ZmKCkucmVtb3ZlKCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIHNlbGYuc2xpZGVzID0gc2xpZGVzO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBzZWxmLmlzQW5pbWF0aW5nID0gZmFsc2U7XHJcblxyXG4gICAgICBzZWxmLnVwZGF0ZUN1cnNvcigpO1xyXG5cclxuICAgICAgc2VsZi50cmlnZ2VyKFwiYWZ0ZXJTaG93XCIpO1xyXG5cclxuICAgICAgLy8gQXV0b3BsYXkgZmlyc3QgaHRtbDUgdmlkZW8vYXVkaW9cclxuICAgICAgaWYgKCEhY3VycmVudC5vcHRzLnZpZGVvLmF1dG9TdGFydCkge1xyXG4gICAgICAgIGN1cnJlbnQuJHNsaWRlXHJcbiAgICAgICAgICAuZmluZChcInZpZGVvLGF1ZGlvXCIpXHJcbiAgICAgICAgICAuZmlsdGVyKFwiOnZpc2libGU6Zmlyc3RcIilcclxuICAgICAgICAgIC50cmlnZ2VyKFwicGxheVwiKVxyXG4gICAgICAgICAgLm9uZShcImVuZGVkXCIsIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgaWYgKERvY3VtZW50LmV4aXRGdWxsc2NyZWVuKSB7XHJcbiAgICAgICAgICAgICAgRG9jdW1lbnQuZXhpdEZ1bGxzY3JlZW4oKTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmICh0aGlzLndlYmtpdEV4aXRGdWxsc2NyZWVuKSB7XHJcbiAgICAgICAgICAgICAgdGhpcy53ZWJraXRFeGl0RnVsbHNjcmVlbigpO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICBzZWxmLm5leHQoKTtcclxuICAgICAgICAgIH0pO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBUcnkgdG8gZm9jdXMgb24gdGhlIGZpcnN0IGZvY3VzYWJsZSBlbGVtZW50XHJcbiAgICAgIGlmIChjdXJyZW50Lm9wdHMuYXV0b0ZvY3VzICYmIGN1cnJlbnQuY29udGVudFR5cGUgPT09IFwiaHRtbFwiKSB7XHJcbiAgICAgICAgLy8gTG9vayBmb3IgdGhlIGZpcnN0IGlucHV0IHdpdGggYXV0b2ZvY3VzIGF0dHJpYnV0ZVxyXG4gICAgICAgICRlbCA9IGN1cnJlbnQuJGNvbnRlbnQuZmluZChcImlucHV0W2F1dG9mb2N1c106ZW5hYmxlZDp2aXNpYmxlOmZpcnN0XCIpO1xyXG5cclxuICAgICAgICBpZiAoJGVsLmxlbmd0aCkge1xyXG4gICAgICAgICAgJGVsLnRyaWdnZXIoXCJmb2N1c1wiKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgc2VsZi5mb2N1cyhudWxsLCB0cnVlKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEF2b2lkIGp1bXBpbmdcclxuICAgICAgY3VycmVudC4kc2xpZGUuc2Nyb2xsVG9wKDApLnNjcm9sbExlZnQoMCk7XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIFByZWxvYWQgbmV4dCBhbmQgcHJldmlvdXMgc2xpZGVzXHJcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIHByZWxvYWQ6IGZ1bmN0aW9uICh0eXBlKSB7XHJcbiAgICAgIHZhciBzZWxmID0gdGhpcyxcclxuICAgICAgICBwcmV2LFxyXG4gICAgICAgIG5leHQ7XHJcblxyXG4gICAgICBpZiAoc2VsZi5ncm91cC5sZW5ndGggPCAyKSB7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBuZXh0ID0gc2VsZi5zbGlkZXNbc2VsZi5jdXJyUG9zICsgMV07XHJcbiAgICAgIHByZXYgPSBzZWxmLnNsaWRlc1tzZWxmLmN1cnJQb3MgLSAxXTtcclxuXHJcbiAgICAgIGlmIChwcmV2ICYmIHByZXYudHlwZSA9PT0gdHlwZSkge1xyXG4gICAgICAgIHNlbGYubG9hZFNsaWRlKHByZXYpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAobmV4dCAmJiBuZXh0LnR5cGUgPT09IHR5cGUpIHtcclxuICAgICAgICBzZWxmLmxvYWRTbGlkZShuZXh0KTtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICAvLyBUcnkgdG8gZmluZCBhbmQgZm9jdXMgb24gdGhlIGZpcnN0IGZvY3VzYWJsZSBlbGVtZW50XHJcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgZm9jdXM6IGZ1bmN0aW9uIChlLCBmaXJzdFJ1bikge1xyXG4gICAgICB2YXIgc2VsZiA9IHRoaXMsXHJcbiAgICAgICAgZm9jdXNhYmxlU3RyID0gW1xyXG4gICAgICAgICAgXCJhW2hyZWZdXCIsXHJcbiAgICAgICAgICBcImFyZWFbaHJlZl1cIixcclxuICAgICAgICAgICdpbnB1dDpub3QoW2Rpc2FibGVkXSk6bm90KFt0eXBlPVwiaGlkZGVuXCJdKTpub3QoW2FyaWEtaGlkZGVuXSknLFxyXG4gICAgICAgICAgXCJzZWxlY3Q6bm90KFtkaXNhYmxlZF0pOm5vdChbYXJpYS1oaWRkZW5dKVwiLFxyXG4gICAgICAgICAgXCJ0ZXh0YXJlYTpub3QoW2Rpc2FibGVkXSk6bm90KFthcmlhLWhpZGRlbl0pXCIsXHJcbiAgICAgICAgICBcImJ1dHRvbjpub3QoW2Rpc2FibGVkXSk6bm90KFthcmlhLWhpZGRlbl0pXCIsXHJcbiAgICAgICAgICBcImlmcmFtZVwiLFxyXG4gICAgICAgICAgXCJvYmplY3RcIixcclxuICAgICAgICAgIFwiZW1iZWRcIixcclxuICAgICAgICAgIFwidmlkZW9cIixcclxuICAgICAgICAgIFwiYXVkaW9cIixcclxuICAgICAgICAgIFwiW2NvbnRlbnRlZGl0YWJsZV1cIixcclxuICAgICAgICAgICdbdGFiaW5kZXhdOm5vdChbdGFiaW5kZXhePVwiLVwiXSknXHJcbiAgICAgICAgXS5qb2luKFwiLFwiKSxcclxuICAgICAgICBmb2N1c2FibGVJdGVtcyxcclxuICAgICAgICBmb2N1c2VkSXRlbUluZGV4O1xyXG5cclxuICAgICAgaWYgKHNlbGYuaXNDbG9zaW5nKSB7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoZSB8fCAhc2VsZi5jdXJyZW50IHx8ICFzZWxmLmN1cnJlbnQuaXNDb21wbGV0ZSkge1xyXG4gICAgICAgIC8vIEZvY3VzIG9uIGFueSBlbGVtZW50IGluc2lkZSBmYW5jeWJveFxyXG4gICAgICAgIGZvY3VzYWJsZUl0ZW1zID0gc2VsZi4kcmVmcy5jb250YWluZXIuZmluZChcIio6dmlzaWJsZVwiKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBGb2N1cyBpbnNpZGUgY3VycmVudCBzbGlkZVxyXG4gICAgICAgIGZvY3VzYWJsZUl0ZW1zID0gc2VsZi5jdXJyZW50LiRzbGlkZS5maW5kKFwiKjp2aXNpYmxlXCIgKyAoZmlyc3RSdW4gPyBcIjpub3QoLmZhbmN5Ym94LWNsb3NlLXNtYWxsKVwiIDogXCJcIikpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBmb2N1c2FibGVJdGVtcyA9IGZvY3VzYWJsZUl0ZW1zLmZpbHRlcihmb2N1c2FibGVTdHIpLmZpbHRlcihmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgcmV0dXJuICQodGhpcykuY3NzKFwidmlzaWJpbGl0eVwiKSAhPT0gXCJoaWRkZW5cIiAmJiAhJCh0aGlzKS5oYXNDbGFzcyhcImRpc2FibGVkXCIpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIGlmIChmb2N1c2FibGVJdGVtcy5sZW5ndGgpIHtcclxuICAgICAgICBmb2N1c2VkSXRlbUluZGV4ID0gZm9jdXNhYmxlSXRlbXMuaW5kZXgoZG9jdW1lbnQuYWN0aXZlRWxlbWVudCk7XHJcblxyXG4gICAgICAgIGlmIChlICYmIGUuc2hpZnRLZXkpIHtcclxuICAgICAgICAgIC8vIEJhY2sgdGFiXHJcbiAgICAgICAgICBpZiAoZm9jdXNlZEl0ZW1JbmRleCA8IDAgfHwgZm9jdXNlZEl0ZW1JbmRleCA9PSAwKSB7XHJcbiAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcclxuXHJcbiAgICAgICAgICAgIGZvY3VzYWJsZUl0ZW1zLmVxKGZvY3VzYWJsZUl0ZW1zLmxlbmd0aCAtIDEpLnRyaWdnZXIoXCJmb2N1c1wiKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgLy8gT3V0c2lkZSBvciBGb3J3YXJkIHRhYlxyXG4gICAgICAgICAgaWYgKGZvY3VzZWRJdGVtSW5kZXggPCAwIHx8IGZvY3VzZWRJdGVtSW5kZXggPT0gZm9jdXNhYmxlSXRlbXMubGVuZ3RoIC0gMSkge1xyXG4gICAgICAgICAgICBpZiAoZSkge1xyXG4gICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgZm9jdXNhYmxlSXRlbXMuZXEoMCkudHJpZ2dlcihcImZvY3VzXCIpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBzZWxmLiRyZWZzLmNvbnRhaW5lci50cmlnZ2VyKFwiZm9jdXNcIik7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgLy8gQWN0aXZhdGVzIGN1cnJlbnQgaW5zdGFuY2UgLSBicmluZ3MgY29udGFpbmVyIHRvIHRoZSBmcm9udCBhbmQgZW5hYmxlcyBrZXlib2FyZCxcclxuICAgIC8vIG5vdGlmaWVzIG90aGVyIGluc3RhbmNlcyBhYm91dCBkZWFjdGl2YXRpbmdcclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIGFjdGl2YXRlOiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHZhciBzZWxmID0gdGhpcztcclxuXHJcbiAgICAgIC8vIERlYWN0aXZhdGUgYWxsIGluc3RhbmNlc1xyXG4gICAgICAkKFwiLmZhbmN5Ym94LWNvbnRhaW5lclwiKS5lYWNoKGZ1bmN0aW9uICgpIHtcclxuICAgICAgICB2YXIgaW5zdGFuY2UgPSAkKHRoaXMpLmRhdGEoXCJGYW5jeUJveFwiKTtcclxuXHJcbiAgICAgICAgLy8gU2tpcCBzZWxmIGFuZCBjbG9zaW5nIGluc3RhbmNlc1xyXG4gICAgICAgIGlmIChpbnN0YW5jZSAmJiBpbnN0YW5jZS5pZCAhPT0gc2VsZi5pZCAmJiAhaW5zdGFuY2UuaXNDbG9zaW5nKSB7XHJcbiAgICAgICAgICBpbnN0YW5jZS50cmlnZ2VyKFwib25EZWFjdGl2YXRlXCIpO1xyXG5cclxuICAgICAgICAgIGluc3RhbmNlLnJlbW92ZUV2ZW50cygpO1xyXG5cclxuICAgICAgICAgIGluc3RhbmNlLmlzVmlzaWJsZSA9IGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICBzZWxmLmlzVmlzaWJsZSA9IHRydWU7XHJcblxyXG4gICAgICBpZiAoc2VsZi5jdXJyZW50IHx8IHNlbGYuaXNJZGxlKSB7XHJcbiAgICAgICAgc2VsZi51cGRhdGUoKTtcclxuXHJcbiAgICAgICAgc2VsZi51cGRhdGVDb250cm9scygpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBzZWxmLnRyaWdnZXIoXCJvbkFjdGl2YXRlXCIpO1xyXG5cclxuICAgICAgc2VsZi5hZGRFdmVudHMoKTtcclxuICAgIH0sXHJcblxyXG4gICAgLy8gU3RhcnQgY2xvc2luZyBwcm9jZWR1cmVcclxuICAgIC8vIFRoaXMgd2lsbCBzdGFydCBcInpvb20tb3V0XCIgYW5pbWF0aW9uIGlmIG5lZWRlZCBhbmQgY2xlYW4gZXZlcnl0aGluZyB1cCBhZnRlcndhcmRzXHJcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICBjbG9zZTogZnVuY3Rpb24gKGUsIGQpIHtcclxuICAgICAgdmFyIHNlbGYgPSB0aGlzLFxyXG4gICAgICAgIGN1cnJlbnQgPSBzZWxmLmN1cnJlbnQsXHJcbiAgICAgICAgZWZmZWN0LFxyXG4gICAgICAgIGR1cmF0aW9uLFxyXG4gICAgICAgICRjb250ZW50LFxyXG4gICAgICAgIGRvbVJlY3QsXHJcbiAgICAgICAgb3BhY2l0eSxcclxuICAgICAgICBzdGFydCxcclxuICAgICAgICBlbmQ7XHJcblxyXG4gICAgICB2YXIgZG9uZSA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICBzZWxmLmNsZWFuVXAoZSk7XHJcbiAgICAgIH07XHJcblxyXG4gICAgICBpZiAoc2VsZi5pc0Nsb3NpbmcpIHtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHNlbGYuaXNDbG9zaW5nID0gdHJ1ZTtcclxuXHJcbiAgICAgIC8vIElmIGJlZm9yZUNsb3NlIGNhbGxiYWNrIHByZXZlbnRzIGNsb3NpbmcsIG1ha2Ugc3VyZSBjb250ZW50IGlzIGNlbnRlcmVkXHJcbiAgICAgIGlmIChzZWxmLnRyaWdnZXIoXCJiZWZvcmVDbG9zZVwiLCBlKSA9PT0gZmFsc2UpIHtcclxuICAgICAgICBzZWxmLmlzQ2xvc2luZyA9IGZhbHNlO1xyXG5cclxuICAgICAgICByZXF1ZXN0QUZyYW1lKGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgIHNlbGYudXBkYXRlKCk7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gUmVtb3ZlIGFsbCBldmVudHNcclxuICAgICAgLy8gSWYgdGhlcmUgYXJlIG11bHRpcGxlIGluc3RhbmNlcywgdGhleSB3aWxsIGJlIHNldCBhZ2FpbiBieSBcImFjdGl2YXRlXCIgbWV0aG9kXHJcbiAgICAgIHNlbGYucmVtb3ZlRXZlbnRzKCk7XHJcblxyXG4gICAgICAkY29udGVudCA9IGN1cnJlbnQuJGNvbnRlbnQ7XHJcbiAgICAgIGVmZmVjdCA9IGN1cnJlbnQub3B0cy5hbmltYXRpb25FZmZlY3Q7XHJcbiAgICAgIGR1cmF0aW9uID0gJC5pc051bWVyaWMoZCkgPyBkIDogZWZmZWN0ID8gY3VycmVudC5vcHRzLmFuaW1hdGlvbkR1cmF0aW9uIDogMDtcclxuXHJcbiAgICAgIGN1cnJlbnQuJHNsaWRlLnJlbW92ZUNsYXNzKFwiZmFuY3lib3gtc2xpZGUtLWNvbXBsZXRlIGZhbmN5Ym94LXNsaWRlLS1uZXh0IGZhbmN5Ym94LXNsaWRlLS1wcmV2aW91cyBmYW5jeWJveC1hbmltYXRlZFwiKTtcclxuXHJcbiAgICAgIGlmIChlICE9PSB0cnVlKSB7XHJcbiAgICAgICAgJC5mYW5jeWJveC5zdG9wKGN1cnJlbnQuJHNsaWRlKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBlZmZlY3QgPSBmYWxzZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gUmVtb3ZlIG90aGVyIHNsaWRlc1xyXG4gICAgICBjdXJyZW50LiRzbGlkZVxyXG4gICAgICAgIC5zaWJsaW5ncygpXHJcbiAgICAgICAgLnRyaWdnZXIoXCJvblJlc2V0XCIpXHJcbiAgICAgICAgLnJlbW92ZSgpO1xyXG5cclxuICAgICAgLy8gVHJpZ2dlciBhbmltYXRpb25zXHJcbiAgICAgIGlmIChkdXJhdGlvbikge1xyXG4gICAgICAgIHNlbGYuJHJlZnMuY29udGFpbmVyXHJcbiAgICAgICAgICAucmVtb3ZlQ2xhc3MoXCJmYW5jeWJveC1pcy1vcGVuXCIpXHJcbiAgICAgICAgICAuYWRkQ2xhc3MoXCJmYW5jeWJveC1pcy1jbG9zaW5nXCIpXHJcbiAgICAgICAgICAuY3NzKFwidHJhbnNpdGlvbi1kdXJhdGlvblwiLCBkdXJhdGlvbiArIFwibXNcIik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENsZWFuIHVwXHJcbiAgICAgIHNlbGYuaGlkZUxvYWRpbmcoY3VycmVudCk7XHJcblxyXG4gICAgICBzZWxmLmhpZGVDb250cm9scyh0cnVlKTtcclxuXHJcbiAgICAgIHNlbGYudXBkYXRlQ3Vyc29yKCk7XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiBwb3NzaWJsZSB0byB6b29tLW91dFxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgZWZmZWN0ID09PSBcInpvb21cIiAmJlxyXG4gICAgICAgICEoJGNvbnRlbnQgJiYgZHVyYXRpb24gJiYgY3VycmVudC50eXBlID09PSBcImltYWdlXCIgJiYgIXNlbGYuaXNNb3ZlZCgpICYmICFjdXJyZW50Lmhhc0Vycm9yICYmIChlbmQgPSBzZWxmLmdldFRodW1iUG9zKGN1cnJlbnQpKSlcclxuICAgICAgKSB7XHJcbiAgICAgICAgZWZmZWN0ID0gXCJmYWRlXCI7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChlZmZlY3QgPT09IFwiem9vbVwiKSB7XHJcbiAgICAgICAgJC5mYW5jeWJveC5zdG9wKCRjb250ZW50KTtcclxuXHJcbiAgICAgICAgZG9tUmVjdCA9ICQuZmFuY3lib3guZ2V0VHJhbnNsYXRlKCRjb250ZW50KTtcclxuXHJcbiAgICAgICAgc3RhcnQgPSB7XHJcbiAgICAgICAgICB0b3A6IGRvbVJlY3QudG9wLFxyXG4gICAgICAgICAgbGVmdDogZG9tUmVjdC5sZWZ0LFxyXG4gICAgICAgICAgc2NhbGVYOiBkb21SZWN0LndpZHRoIC8gZW5kLndpZHRoLFxyXG4gICAgICAgICAgc2NhbGVZOiBkb21SZWN0LmhlaWdodCAvIGVuZC5oZWlnaHQsXHJcbiAgICAgICAgICB3aWR0aDogZW5kLndpZHRoLFxyXG4gICAgICAgICAgaGVpZ2h0OiBlbmQuaGVpZ2h0XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaWYgd2UgbmVlZCB0byBhbmltYXRlIG9wYWNpdHlcclxuICAgICAgICBvcGFjaXR5ID0gY3VycmVudC5vcHRzLnpvb21PcGFjaXR5O1xyXG5cclxuICAgICAgICBpZiAob3BhY2l0eSA9PSBcImF1dG9cIikge1xyXG4gICAgICAgICAgb3BhY2l0eSA9IE1hdGguYWJzKGN1cnJlbnQud2lkdGggLyBjdXJyZW50LmhlaWdodCAtIGVuZC53aWR0aCAvIGVuZC5oZWlnaHQpID4gMC4xO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKG9wYWNpdHkpIHtcclxuICAgICAgICAgIGVuZC5vcGFjaXR5ID0gMDtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgICQuZmFuY3lib3guc2V0VHJhbnNsYXRlKCRjb250ZW50LCBzdGFydCk7XHJcblxyXG4gICAgICAgIGZvcmNlUmVkcmF3KCRjb250ZW50KTtcclxuXHJcbiAgICAgICAgJC5mYW5jeWJveC5hbmltYXRlKCRjb250ZW50LCBlbmQsIGR1cmF0aW9uLCBkb25lKTtcclxuXHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChlZmZlY3QgJiYgZHVyYXRpb24pIHtcclxuICAgICAgICAkLmZhbmN5Ym94LmFuaW1hdGUoXHJcbiAgICAgICAgICBjdXJyZW50LiRzbGlkZS5hZGRDbGFzcyhcImZhbmN5Ym94LXNsaWRlLS1wcmV2aW91c1wiKS5yZW1vdmVDbGFzcyhcImZhbmN5Ym94LXNsaWRlLS1jdXJyZW50XCIpLFxyXG4gICAgICAgICAgXCJmYW5jeWJveC1hbmltYXRlZCBmYW5jeWJveC1meC1cIiArIGVmZmVjdCxcclxuICAgICAgICAgIGR1cmF0aW9uLFxyXG4gICAgICAgICAgZG9uZVxyXG4gICAgICAgICk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gSWYgc2tpcCBhbmltYXRpb25cclxuICAgICAgICBpZiAoZSA9PT0gdHJ1ZSkge1xyXG4gICAgICAgICAgc2V0VGltZW91dChkb25lLCBkdXJhdGlvbik7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGRvbmUoKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfSxcclxuXHJcbiAgICAvLyBGaW5hbCBhZGp1c3RtZW50cyBhZnRlciByZW1vdmluZyB0aGUgaW5zdGFuY2VcclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIGNsZWFuVXA6IGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgIHZhciBzZWxmID0gdGhpcyxcclxuICAgICAgICBpbnN0YW5jZSxcclxuICAgICAgICAkZm9jdXMgPSBzZWxmLmN1cnJlbnQub3B0cy4kb3JpZyxcclxuICAgICAgICB4LFxyXG4gICAgICAgIHk7XHJcblxyXG4gICAgICBzZWxmLmN1cnJlbnQuJHNsaWRlLnRyaWdnZXIoXCJvblJlc2V0XCIpO1xyXG5cclxuICAgICAgc2VsZi4kcmVmcy5jb250YWluZXIuZW1wdHkoKS5yZW1vdmUoKTtcclxuXHJcbiAgICAgIHNlbGYudHJpZ2dlcihcImFmdGVyQ2xvc2VcIiwgZSk7XHJcblxyXG4gICAgICAvLyBQbGFjZSBiYWNrIGZvY3VzXHJcbiAgICAgIGlmICghIXNlbGYuY3VycmVudC5vcHRzLmJhY2tGb2N1cykge1xyXG4gICAgICAgIGlmICghJGZvY3VzIHx8ICEkZm9jdXMubGVuZ3RoIHx8ICEkZm9jdXMuaXMoXCI6dmlzaWJsZVwiKSkge1xyXG4gICAgICAgICAgJGZvY3VzID0gc2VsZi4kdHJpZ2dlcjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmICgkZm9jdXMgJiYgJGZvY3VzLmxlbmd0aCkge1xyXG4gICAgICAgICAgeCA9IHdpbmRvdy5zY3JvbGxYO1xyXG4gICAgICAgICAgeSA9IHdpbmRvdy5zY3JvbGxZO1xyXG5cclxuICAgICAgICAgICRmb2N1cy50cmlnZ2VyKFwiZm9jdXNcIik7XHJcblxyXG4gICAgICAgICAgJChcImh0bWwsIGJvZHlcIilcclxuICAgICAgICAgICAgLnNjcm9sbFRvcCh5KVxyXG4gICAgICAgICAgICAuc2Nyb2xsTGVmdCh4KTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHNlbGYuY3VycmVudCA9IG51bGw7XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGVyZSBhcmUgb3RoZXIgaW5zdGFuY2VzXHJcbiAgICAgIGluc3RhbmNlID0gJC5mYW5jeWJveC5nZXRJbnN0YW5jZSgpO1xyXG5cclxuICAgICAgaWYgKGluc3RhbmNlKSB7XHJcbiAgICAgICAgaW5zdGFuY2UuYWN0aXZhdGUoKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAkKFwiYm9keVwiKS5yZW1vdmVDbGFzcyhcImZhbmN5Ym94LWFjdGl2ZSBjb21wZW5zYXRlLWZvci1zY3JvbGxiYXJcIik7XHJcblxyXG4gICAgICAgICQoXCIjZmFuY3lib3gtc3R5bGUtbm9zY3JvbGxcIikucmVtb3ZlKCk7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgLy8gQ2FsbCBjYWxsYmFjayBhbmQgdHJpZ2dlciBhbiBldmVudFxyXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIHRyaWdnZXI6IGZ1bmN0aW9uIChuYW1lLCBzbGlkZSkge1xyXG4gICAgICB2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSksXHJcbiAgICAgICAgc2VsZiA9IHRoaXMsXHJcbiAgICAgICAgb2JqID0gc2xpZGUgJiYgc2xpZGUub3B0cyA/IHNsaWRlIDogc2VsZi5jdXJyZW50LFxyXG4gICAgICAgIHJlejtcclxuXHJcbiAgICAgIGlmIChvYmopIHtcclxuICAgICAgICBhcmdzLnVuc2hpZnQob2JqKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBvYmogPSBzZWxmO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBhcmdzLnVuc2hpZnQoc2VsZik7XHJcblxyXG4gICAgICBpZiAoJC5pc0Z1bmN0aW9uKG9iai5vcHRzW25hbWVdKSkge1xyXG4gICAgICAgIHJleiA9IG9iai5vcHRzW25hbWVdLmFwcGx5KG9iaiwgYXJncyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChyZXogPT09IGZhbHNlKSB7XHJcbiAgICAgICAgcmV0dXJuIHJlejtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKG5hbWUgPT09IFwiYWZ0ZXJDbG9zZVwiIHx8ICFzZWxmLiRyZWZzKSB7XHJcbiAgICAgICAgJEQudHJpZ2dlcihuYW1lICsgXCIuZmJcIiwgYXJncyk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgc2VsZi4kcmVmcy5jb250YWluZXIudHJpZ2dlcihuYW1lICsgXCIuZmJcIiwgYXJncyk7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgLy8gVXBkYXRlIGluZm9iYXIgdmFsdWVzLCBuYXZpZ2F0aW9uIGJ1dHRvbiBzdGF0ZXMgYW5kIHJldmVhbCBjYXB0aW9uXHJcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICB1cGRhdGVDb250cm9sczogZnVuY3Rpb24gKCkge1xyXG4gICAgICB2YXIgc2VsZiA9IHRoaXMsXHJcbiAgICAgICAgY3VycmVudCA9IHNlbGYuY3VycmVudCxcclxuICAgICAgICBpbmRleCA9IGN1cnJlbnQuaW5kZXgsXHJcbiAgICAgICAgJGNvbnRhaW5lciA9IHNlbGYuJHJlZnMuY29udGFpbmVyLFxyXG4gICAgICAgICRjYXB0aW9uID0gc2VsZi4kcmVmcy5jYXB0aW9uLFxyXG4gICAgICAgIGNhcHRpb24gPSBjdXJyZW50Lm9wdHMuY2FwdGlvbjtcclxuXHJcbiAgICAgIC8vIFJlY2FsY3VsYXRlIGNvbnRlbnQgZGltZW5zaW9uc1xyXG4gICAgICBjdXJyZW50LiRzbGlkZS50cmlnZ2VyKFwicmVmcmVzaFwiKTtcclxuXHJcbiAgICAgIC8vIFNldCBjYXB0aW9uXHJcbiAgICAgIGlmIChjYXB0aW9uICYmIGNhcHRpb24ubGVuZ3RoKSB7XHJcbiAgICAgICAgc2VsZi4kY2FwdGlvbiA9ICRjYXB0aW9uO1xyXG5cclxuICAgICAgICAkY2FwdGlvblxyXG4gICAgICAgICAgLmNoaWxkcmVuKClcclxuICAgICAgICAgIC5lcSgwKVxyXG4gICAgICAgICAgLmh0bWwoY2FwdGlvbik7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgc2VsZi4kY2FwdGlvbiA9IG51bGw7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICghc2VsZi5oYXNIaWRkZW5Db250cm9scyAmJiAhc2VsZi5pc0lkbGUpIHtcclxuICAgICAgICBzZWxmLnNob3dDb250cm9scygpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBVcGRhdGUgaW5mbyBhbmQgbmF2aWdhdGlvbiBlbGVtZW50c1xyXG4gICAgICAkY29udGFpbmVyLmZpbmQoXCJbZGF0YS1mYW5jeWJveC1jb3VudF1cIikuaHRtbChzZWxmLmdyb3VwLmxlbmd0aCk7XHJcbiAgICAgICRjb250YWluZXIuZmluZChcIltkYXRhLWZhbmN5Ym94LWluZGV4XVwiKS5odG1sKGluZGV4ICsgMSk7XHJcblxyXG4gICAgICAkY29udGFpbmVyLmZpbmQoXCJbZGF0YS1mYW5jeWJveC1wcmV2XVwiKS5wcm9wKFwiZGlzYWJsZWRcIiwgIWN1cnJlbnQub3B0cy5sb29wICYmIGluZGV4IDw9IDApO1xyXG4gICAgICAkY29udGFpbmVyLmZpbmQoXCJbZGF0YS1mYW5jeWJveC1uZXh0XVwiKS5wcm9wKFwiZGlzYWJsZWRcIiwgIWN1cnJlbnQub3B0cy5sb29wICYmIGluZGV4ID49IHNlbGYuZ3JvdXAubGVuZ3RoIC0gMSk7XHJcblxyXG4gICAgICBpZiAoY3VycmVudC50eXBlID09PSBcImltYWdlXCIpIHtcclxuICAgICAgICAvLyBSZS1lbmFibGUgYnV0dG9uczsgdXBkYXRlIGRvd25sb2FkIGJ1dHRvbiBzb3VyY2VcclxuICAgICAgICAkY29udGFpbmVyXHJcbiAgICAgICAgICAuZmluZChcIltkYXRhLWZhbmN5Ym94LXpvb21dXCIpXHJcbiAgICAgICAgICAuc2hvdygpXHJcbiAgICAgICAgICAuZW5kKClcclxuICAgICAgICAgIC5maW5kKFwiW2RhdGEtZmFuY3lib3gtZG93bmxvYWRdXCIpXHJcbiAgICAgICAgICAuYXR0cihcImhyZWZcIiwgY3VycmVudC5vcHRzLmltYWdlLnNyYyB8fCBjdXJyZW50LnNyYylcclxuICAgICAgICAgIC5zaG93KCk7XHJcbiAgICAgIH0gZWxzZSBpZiAoY3VycmVudC5vcHRzLnRvb2xiYXIpIHtcclxuICAgICAgICAkY29udGFpbmVyLmZpbmQoXCJbZGF0YS1mYW5jeWJveC1kb3dubG9hZF0sW2RhdGEtZmFuY3lib3gtem9vbV1cIikuaGlkZSgpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBNYWtlIHN1cmUgZm9jdXMgaXMgbm90IG9uIGRpc2FibGVkIGJ1dHRvbi9lbGVtZW50XHJcbiAgICAgIGlmICgkKGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpLmlzKFwiOmhpZGRlbixbZGlzYWJsZWRdXCIpKSB7XHJcbiAgICAgICAgc2VsZi4kcmVmcy5jb250YWluZXIudHJpZ2dlcihcImZvY3VzXCIpO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIEhpZGUgdG9vbGJhciBhbmQgY2FwdGlvblxyXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgaGlkZUNvbnRyb2xzOiBmdW5jdGlvbiAoYW5kQ2FwdGlvbikge1xyXG4gICAgICB2YXIgc2VsZiA9IHRoaXMsXHJcbiAgICAgICAgYXJyID0gW1wiaW5mb2JhclwiLCBcInRvb2xiYXJcIiwgXCJuYXZcIl07XHJcblxyXG4gICAgICBpZiAoYW5kQ2FwdGlvbiB8fCAhc2VsZi5jdXJyZW50Lm9wdHMucHJldmVudENhcHRpb25PdmVybGFwKSB7XHJcbiAgICAgICAgYXJyLnB1c2goXCJjYXB0aW9uXCIpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICB0aGlzLiRyZWZzLmNvbnRhaW5lci5yZW1vdmVDbGFzcyhcclxuICAgICAgICBhcnJcclxuICAgICAgICAubWFwKGZ1bmN0aW9uIChpKSB7XHJcbiAgICAgICAgICByZXR1cm4gXCJmYW5jeWJveC1zaG93LVwiICsgaTtcclxuICAgICAgICB9KVxyXG4gICAgICAgIC5qb2luKFwiIFwiKVxyXG4gICAgICApO1xyXG5cclxuICAgICAgdGhpcy5oYXNIaWRkZW5Db250cm9scyA9IHRydWU7XHJcbiAgICB9LFxyXG5cclxuICAgIHNob3dDb250cm9sczogZnVuY3Rpb24gKCkge1xyXG4gICAgICB2YXIgc2VsZiA9IHRoaXMsXHJcbiAgICAgICAgb3B0cyA9IHNlbGYuY3VycmVudCA/IHNlbGYuY3VycmVudC5vcHRzIDogc2VsZi5vcHRzLFxyXG4gICAgICAgICRjb250YWluZXIgPSBzZWxmLiRyZWZzLmNvbnRhaW5lcjtcclxuXHJcbiAgICAgIHNlbGYuaGFzSGlkZGVuQ29udHJvbHMgPSBmYWxzZTtcclxuICAgICAgc2VsZi5pZGxlU2Vjb25kc0NvdW50ZXIgPSAwO1xyXG5cclxuICAgICAgJGNvbnRhaW5lclxyXG4gICAgICAgIC50b2dnbGVDbGFzcyhcImZhbmN5Ym94LXNob3ctdG9vbGJhclwiLCAhIShvcHRzLnRvb2xiYXIgJiYgb3B0cy5idXR0b25zKSlcclxuICAgICAgICAudG9nZ2xlQ2xhc3MoXCJmYW5jeWJveC1zaG93LWluZm9iYXJcIiwgISEob3B0cy5pbmZvYmFyICYmIHNlbGYuZ3JvdXAubGVuZ3RoID4gMSkpXHJcbiAgICAgICAgLnRvZ2dsZUNsYXNzKFwiZmFuY3lib3gtc2hvdy1jYXB0aW9uXCIsICEhc2VsZi4kY2FwdGlvbilcclxuICAgICAgICAudG9nZ2xlQ2xhc3MoXCJmYW5jeWJveC1zaG93LW5hdlwiLCAhIShvcHRzLmFycm93cyAmJiBzZWxmLmdyb3VwLmxlbmd0aCA+IDEpKVxyXG4gICAgICAgIC50b2dnbGVDbGFzcyhcImZhbmN5Ym94LWlzLW1vZGFsXCIsICEhb3B0cy5tb2RhbCk7XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIFRvZ2dsZSB0b29sYmFyIGFuZCBjYXB0aW9uXHJcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIHRvZ2dsZUNvbnRyb2xzOiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIGlmICh0aGlzLmhhc0hpZGRlbkNvbnRyb2xzKSB7XHJcbiAgICAgICAgdGhpcy5zaG93Q29udHJvbHMoKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLmhpZGVDb250cm9scygpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gICQuZmFuY3lib3ggPSB7XHJcbiAgICB2ZXJzaW9uOiBcIjMuNS43XCIsXHJcbiAgICBkZWZhdWx0czogZGVmYXVsdHMsXHJcblxyXG4gICAgLy8gR2V0IGN1cnJlbnQgaW5zdGFuY2UgYW5kIGV4ZWN1dGUgYSBjb21tYW5kLlxyXG4gICAgLy9cclxuICAgIC8vIEV4YW1wbGVzIG9mIHVzYWdlOlxyXG4gICAgLy9cclxuICAgIC8vICAgJGluc3RhbmNlID0gJC5mYW5jeWJveC5nZXRJbnN0YW5jZSgpO1xyXG4gICAgLy8gICAkLmZhbmN5Ym94LmdldEluc3RhbmNlKCkuanVtcFRvKCAxICk7XHJcbiAgICAvLyAgICQuZmFuY3lib3guZ2V0SW5zdGFuY2UoICdqdW1wVG8nLCAxICk7XHJcbiAgICAvLyAgICQuZmFuY3lib3guZ2V0SW5zdGFuY2UoIGZ1bmN0aW9uKCkge1xyXG4gICAgLy8gICAgICAgY29uc29sZS5pbmZvKCB0aGlzLmN1cnJJbmRleCApO1xyXG4gICAgLy8gICB9KTtcclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIGdldEluc3RhbmNlOiBmdW5jdGlvbiAoY29tbWFuZCkge1xyXG4gICAgICB2YXIgaW5zdGFuY2UgPSAkKCcuZmFuY3lib3gtY29udGFpbmVyOm5vdChcIi5mYW5jeWJveC1pcy1jbG9zaW5nXCIpOmxhc3QnKS5kYXRhKFwiRmFuY3lCb3hcIiksXHJcbiAgICAgICAgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XHJcblxyXG4gICAgICBpZiAoaW5zdGFuY2UgaW5zdGFuY2VvZiBGYW5jeUJveCkge1xyXG4gICAgICAgIGlmICgkLnR5cGUoY29tbWFuZCkgPT09IFwic3RyaW5nXCIpIHtcclxuICAgICAgICAgIGluc3RhbmNlW2NvbW1hbmRdLmFwcGx5KGluc3RhbmNlLCBhcmdzKTtcclxuICAgICAgICB9IGVsc2UgaWYgKCQudHlwZShjb21tYW5kKSA9PT0gXCJmdW5jdGlvblwiKSB7XHJcbiAgICAgICAgICBjb21tYW5kLmFwcGx5KGluc3RhbmNlLCBhcmdzKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiBpbnN0YW5jZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfSxcclxuXHJcbiAgICAvLyBDcmVhdGUgbmV3IGluc3RhbmNlXHJcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgb3BlbjogZnVuY3Rpb24gKGl0ZW1zLCBvcHRzLCBpbmRleCkge1xyXG4gICAgICByZXR1cm4gbmV3IEZhbmN5Qm94KGl0ZW1zLCBvcHRzLCBpbmRleCk7XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIENsb3NlIGN1cnJlbnQgb3IgYWxsIGluc3RhbmNlc1xyXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgY2xvc2U6IGZ1bmN0aW9uIChhbGwpIHtcclxuICAgICAgdmFyIGluc3RhbmNlID0gdGhpcy5nZXRJbnN0YW5jZSgpO1xyXG5cclxuICAgICAgaWYgKGluc3RhbmNlKSB7XHJcbiAgICAgICAgaW5zdGFuY2UuY2xvc2UoKTtcclxuXHJcbiAgICAgICAgLy8gVHJ5IHRvIGZpbmQgYW5kIGNsb3NlIG5leHQgaW5zdGFuY2VcclxuICAgICAgICBpZiAoYWxsID09PSB0cnVlKSB7XHJcbiAgICAgICAgICB0aGlzLmNsb3NlKGFsbCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIENsb3NlIGFsbCBpbnN0YW5jZXMgYW5kIHVuYmluZCBhbGwgZXZlbnRzXHJcbiAgICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIGRlc3Ryb3k6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgdGhpcy5jbG9zZSh0cnVlKTtcclxuXHJcbiAgICAgICRELmFkZChcImJvZHlcIikub2ZmKFwiY2xpY2suZmItc3RhcnRcIiwgXCIqKlwiKTtcclxuICAgIH0sXHJcblxyXG4gICAgLy8gVHJ5IHRvIGRldGVjdCBtb2JpbGUgZGV2aWNlc1xyXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIGlzTW9iaWxlOiAvQW5kcm9pZHx3ZWJPU3xpUGhvbmV8aVBhZHxpUG9kfEJsYWNrQmVycnl8SUVNb2JpbGV8T3BlcmEgTWluaS9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCksXHJcblxyXG4gICAgLy8gRGV0ZWN0IGlmICd0cmFuc2xhdGUzZCcgc3VwcG9ydCBpcyBhdmFpbGFibGVcclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgdXNlM2Q6IChmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHZhciBkaXYgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiZGl2XCIpO1xyXG5cclxuICAgICAgcmV0dXJuIChcclxuICAgICAgICB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZSAmJlxyXG4gICAgICAgIHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGRpdikgJiZcclxuICAgICAgICB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShkaXYpLmdldFByb3BlcnR5VmFsdWUoXCJ0cmFuc2Zvcm1cIikgJiZcclxuICAgICAgICAhKGRvY3VtZW50LmRvY3VtZW50TW9kZSAmJiBkb2N1bWVudC5kb2N1bWVudE1vZGUgPCAxMSlcclxuICAgICAgKTtcclxuICAgIH0pKCksXHJcblxyXG4gICAgLy8gSGVscGVyIGZ1bmN0aW9uIHRvIGdldCBjdXJyZW50IHZpc3VhbCBzdGF0ZSBvZiBhbiBlbGVtZW50XHJcbiAgICAvLyByZXR1cm5zIGFycmF5WyB0b3AsIGxlZnQsIGhvcml6b250YWwtc2NhbGUsIHZlcnRpY2FsLXNjYWxlLCBvcGFjaXR5IF1cclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAgIGdldFRyYW5zbGF0ZTogZnVuY3Rpb24gKCRlbCkge1xyXG4gICAgICB2YXIgZG9tUmVjdDtcclxuXHJcbiAgICAgIGlmICghJGVsIHx8ICEkZWwubGVuZ3RoKSB7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBkb21SZWN0ID0gJGVsWzBdLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG5cclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICB0b3A6IGRvbVJlY3QudG9wIHx8IDAsXHJcbiAgICAgICAgbGVmdDogZG9tUmVjdC5sZWZ0IHx8IDAsXHJcbiAgICAgICAgd2lkdGg6IGRvbVJlY3Qud2lkdGgsXHJcbiAgICAgICAgaGVpZ2h0OiBkb21SZWN0LmhlaWdodCxcclxuICAgICAgICBvcGFjaXR5OiBwYXJzZUZsb2F0KCRlbC5jc3MoXCJvcGFjaXR5XCIpKVxyXG4gICAgICB9O1xyXG4gICAgfSxcclxuXHJcbiAgICAvLyBTaG9ydGN1dCBmb3Igc2V0dGluZyBcInRyYW5zbGF0ZTNkXCIgcHJvcGVydGllcyBmb3IgZWxlbWVudFxyXG4gICAgLy8gQ2FuIHNldCBiZSB1c2VkIHRvIHNldCBvcGFjaXR5LCB0b29cclxuICAgIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICAgc2V0VHJhbnNsYXRlOiBmdW5jdGlvbiAoJGVsLCBwcm9wcykge1xyXG4gICAgICB2YXIgc3RyID0gXCJcIixcclxuICAgICAgICBjc3MgPSB7fTtcclxuXHJcbiAgICAgIGlmICghJGVsIHx8ICFwcm9wcykge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKHByb3BzLmxlZnQgIT09IHVuZGVmaW5lZCB8fCBwcm9wcy50b3AgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIHN0ciA9XHJcbiAgICAgICAgICAocHJvcHMubGVmdCA9PT0gdW5kZWZpbmVkID8gJGVsLnBvc2l0aW9uKCkubGVmdCA6IHByb3BzLmxlZnQpICtcclxuICAgICAgICAgIFwicHgsIFwiICtcclxuICAgICAgICAgIChwcm9wcy50b3AgPT09IHVuZGVmaW5lZCA/ICRlbC5wb3NpdGlvbigpLnRvcCA6IHByb3BzLnRvcCkgK1xyXG4gICAgICAgICAgXCJweFwiO1xyXG5cclxuICAgICAgICBpZiAodGhpcy51c2UzZCkge1xyXG4gICAgICAgICAgc3RyID0gXCJ0cmFuc2xhdGUzZChcIiArIHN0ciArIFwiLCAwcHgpXCI7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHN0ciA9IFwidHJhbnNsYXRlKFwiICsgc3RyICsgXCIpXCI7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAocHJvcHMuc2NhbGVYICE9PSB1bmRlZmluZWQgJiYgcHJvcHMuc2NhbGVZICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBzdHIgKz0gXCIgc2NhbGUoXCIgKyBwcm9wcy5zY2FsZVggKyBcIiwgXCIgKyBwcm9wcy5zY2FsZVkgKyBcIilcIjtcclxuICAgICAgfSBlbHNlIGlmIChwcm9wcy5zY2FsZVggIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIHN0ciArPSBcIiBzY2FsZVgoXCIgKyBwcm9wcy5zY2FsZVggKyBcIilcIjtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKHN0ci5sZW5ndGgpIHtcclxuICAgICAgICBjc3MudHJhbnNmb3JtID0gc3RyO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAocHJvcHMub3BhY2l0eSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgY3NzLm9wYWNpdHkgPSBwcm9wcy5vcGFjaXR5O1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAocHJvcHMud2lkdGggIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIGNzcy53aWR0aCA9IHByb3BzLndpZHRoO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAocHJvcHMuaGVpZ2h0ICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBjc3MuaGVpZ2h0ID0gcHJvcHMuaGVpZ2h0O1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gJGVsLmNzcyhjc3MpO1xyXG4gICAgfSxcclxuXHJcbiAgICAvLyBTaW1wbGUgQ1NTIHRyYW5zaXRpb24gaGFuZGxlclxyXG4gICAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuXHJcbiAgICBhbmltYXRlOiBmdW5jdGlvbiAoJGVsLCB0bywgZHVyYXRpb24sIGNhbGxiYWNrLCBsZWF2ZUFuaW1hdGlvbk5hbWUpIHtcclxuICAgICAgdmFyIHNlbGYgPSB0aGlzLFxyXG4gICAgICAgIGZyb207XHJcblxyXG4gICAgICBpZiAoJC5pc0Z1bmN0aW9uKGR1cmF0aW9uKSkge1xyXG4gICAgICAgIGNhbGxiYWNrID0gZHVyYXRpb247XHJcbiAgICAgICAgZHVyYXRpb24gPSBudWxsO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBzZWxmLnN0b3AoJGVsKTtcclxuXHJcbiAgICAgIGZyb20gPSBzZWxmLmdldFRyYW5zbGF0ZSgkZWwpO1xyXG5cclxuICAgICAgJGVsLm9uKHRyYW5zaXRpb25FbmQsIGZ1bmN0aW9uIChlKSB7XHJcbiAgICAgICAgLy8gU2tpcCBldmVudHMgZnJvbSBjaGlsZCBlbGVtZW50cyBhbmQgei1pbmRleCBjaGFuZ2VcclxuICAgICAgICBpZiAoZSAmJiBlLm9yaWdpbmFsRXZlbnQgJiYgKCEkZWwuaXMoZS5vcmlnaW5hbEV2ZW50LnRhcmdldCkgfHwgZS5vcmlnaW5hbEV2ZW50LnByb3BlcnR5TmFtZSA9PSBcInotaW5kZXhcIikpIHtcclxuICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHNlbGYuc3RvcCgkZWwpO1xyXG5cclxuICAgICAgICBpZiAoJC5pc051bWVyaWMoZHVyYXRpb24pKSB7XHJcbiAgICAgICAgICAkZWwuY3NzKFwidHJhbnNpdGlvbi1kdXJhdGlvblwiLCBcIlwiKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmICgkLmlzUGxhaW5PYmplY3QodG8pKSB7XHJcbiAgICAgICAgICBpZiAodG8uc2NhbGVYICE9PSB1bmRlZmluZWQgJiYgdG8uc2NhbGVZICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgICAgc2VsZi5zZXRUcmFuc2xhdGUoJGVsLCB7XHJcbiAgICAgICAgICAgICAgdG9wOiB0by50b3AsXHJcbiAgICAgICAgICAgICAgbGVmdDogdG8ubGVmdCxcclxuICAgICAgICAgICAgICB3aWR0aDogZnJvbS53aWR0aCAqIHRvLnNjYWxlWCxcclxuICAgICAgICAgICAgICBoZWlnaHQ6IGZyb20uaGVpZ2h0ICogdG8uc2NhbGVZLFxyXG4gICAgICAgICAgICAgIHNjYWxlWDogMSxcclxuICAgICAgICAgICAgICBzY2FsZVk6IDFcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSBlbHNlIGlmIChsZWF2ZUFuaW1hdGlvbk5hbWUgIT09IHRydWUpIHtcclxuICAgICAgICAgICRlbC5yZW1vdmVDbGFzcyh0byk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoJC5pc0Z1bmN0aW9uKGNhbGxiYWNrKSkge1xyXG4gICAgICAgICAgY2FsbGJhY2soZSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIGlmICgkLmlzTnVtZXJpYyhkdXJhdGlvbikpIHtcclxuICAgICAgICAkZWwuY3NzKFwidHJhbnNpdGlvbi1kdXJhdGlvblwiLCBkdXJhdGlvbiArIFwibXNcIik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFN0YXJ0IGFuaW1hdGlvbiBieSBjaGFuZ2luZyBDU1MgcHJvcGVydGllcyBvciBjbGFzcyBuYW1lXHJcbiAgICAgIGlmICgkLmlzUGxhaW5PYmplY3QodG8pKSB7XHJcbiAgICAgICAgaWYgKHRvLnNjYWxlWCAhPT0gdW5kZWZpbmVkICYmIHRvLnNjYWxlWSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgICBkZWxldGUgdG8ud2lkdGg7XHJcbiAgICAgICAgICBkZWxldGUgdG8uaGVpZ2h0O1xyXG5cclxuICAgICAgICAgIGlmICgkZWwucGFyZW50KCkuaGFzQ2xhc3MoXCJmYW5jeWJveC1zbGlkZS0taW1hZ2VcIikpIHtcclxuICAgICAgICAgICAgJGVsLnBhcmVudCgpLmFkZENsYXNzKFwiZmFuY3lib3gtaXMtc2NhbGluZ1wiKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgICQuZmFuY3lib3guc2V0VHJhbnNsYXRlKCRlbCwgdG8pO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgICRlbC5hZGRDbGFzcyh0byk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIE1ha2Ugc3VyZSB0aGF0IGB0cmFuc2l0aW9uZW5kYCBjYWxsYmFjayBnZXRzIGZpcmVkXHJcbiAgICAgICRlbC5kYXRhKFxyXG4gICAgICAgIFwidGltZXJcIixcclxuICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICRlbC50cmlnZ2VyKHRyYW5zaXRpb25FbmQpO1xyXG4gICAgICAgIH0sIGR1cmF0aW9uICsgMzMpXHJcbiAgICAgICk7XHJcbiAgICB9LFxyXG5cclxuICAgIHN0b3A6IGZ1bmN0aW9uICgkZWwsIGNhbGxDYWxsYmFjaykge1xyXG4gICAgICBpZiAoJGVsICYmICRlbC5sZW5ndGgpIHtcclxuICAgICAgICBjbGVhclRpbWVvdXQoJGVsLmRhdGEoXCJ0aW1lclwiKSk7XHJcblxyXG4gICAgICAgIGlmIChjYWxsQ2FsbGJhY2spIHtcclxuICAgICAgICAgICRlbC50cmlnZ2VyKHRyYW5zaXRpb25FbmQpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgJGVsLm9mZih0cmFuc2l0aW9uRW5kKS5jc3MoXCJ0cmFuc2l0aW9uLWR1cmF0aW9uXCIsIFwiXCIpO1xyXG5cclxuICAgICAgICAkZWwucGFyZW50KCkucmVtb3ZlQ2xhc3MoXCJmYW5jeWJveC1pcy1zY2FsaW5nXCIpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfTtcclxuXHJcbiAgLy8gRGVmYXVsdCBjbGljayBoYW5kbGVyIGZvciBcImZhbmN5Ym94ZWRcIiBsaW5rc1xyXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gIGZ1bmN0aW9uIF9ydW4oZSwgb3B0cykge1xyXG4gICAgdmFyIGl0ZW1zID0gW10sXHJcbiAgICAgIGluZGV4ID0gMCxcclxuICAgICAgJHRhcmdldCxcclxuICAgICAgdmFsdWUsXHJcbiAgICAgIGluc3RhbmNlO1xyXG5cclxuICAgIC8vIEF2b2lkIG9wZW5pbmcgbXVsdGlwbGUgdGltZXNcclxuICAgIGlmIChlICYmIGUuaXNEZWZhdWx0UHJldmVudGVkKCkpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGUucHJldmVudERlZmF1bHQoKTtcclxuXHJcbiAgICBvcHRzID0gb3B0cyB8fCB7fTtcclxuXHJcbiAgICBpZiAoZSAmJiBlLmRhdGEpIHtcclxuICAgICAgb3B0cyA9IG1lcmdlT3B0cyhlLmRhdGEub3B0aW9ucywgb3B0cyk7XHJcbiAgICB9XHJcblxyXG4gICAgJHRhcmdldCA9IG9wdHMuJHRhcmdldCB8fCAkKGUuY3VycmVudFRhcmdldCkudHJpZ2dlcihcImJsdXJcIik7XHJcbiAgICBpbnN0YW5jZSA9ICQuZmFuY3lib3guZ2V0SW5zdGFuY2UoKTtcclxuXHJcbiAgICBpZiAoaW5zdGFuY2UgJiYgaW5zdGFuY2UuJHRyaWdnZXIgJiYgaW5zdGFuY2UuJHRyaWdnZXIuaXMoJHRhcmdldCkpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChvcHRzLnNlbGVjdG9yKSB7XHJcbiAgICAgIGl0ZW1zID0gJChvcHRzLnNlbGVjdG9yKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIEdldCBhbGwgcmVsYXRlZCBpdGVtcyBhbmQgZmluZCBpbmRleCBmb3IgY2xpY2tlZCBvbmVcclxuICAgICAgdmFsdWUgPSAkdGFyZ2V0LmF0dHIoXCJkYXRhLWZhbmN5Ym94XCIpIHx8IFwiXCI7XHJcblxyXG4gICAgICBpZiAodmFsdWUpIHtcclxuICAgICAgICBpdGVtcyA9IGUuZGF0YSA/IGUuZGF0YS5pdGVtcyA6IFtdO1xyXG4gICAgICAgIGl0ZW1zID0gaXRlbXMubGVuZ3RoID8gaXRlbXMuZmlsdGVyKCdbZGF0YS1mYW5jeWJveD1cIicgKyB2YWx1ZSArICdcIl0nKSA6ICQoJ1tkYXRhLWZhbmN5Ym94PVwiJyArIHZhbHVlICsgJ1wiXScpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGl0ZW1zID0gWyR0YXJnZXRdO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgaW5kZXggPSAkKGl0ZW1zKS5pbmRleCgkdGFyZ2V0KTtcclxuXHJcbiAgICAvLyBTb21ldGltZXMgY3VycmVudCBpdGVtIGNhbiBub3QgYmUgZm91bmRcclxuICAgIGlmIChpbmRleCA8IDApIHtcclxuICAgICAgaW5kZXggPSAwO1xyXG4gICAgfVxyXG5cclxuICAgIGluc3RhbmNlID0gJC5mYW5jeWJveC5vcGVuKGl0ZW1zLCBvcHRzLCBpbmRleCk7XHJcblxyXG4gICAgLy8gU2F2ZSBsYXN0IGFjdGl2ZSBlbGVtZW50XHJcbiAgICBpbnN0YW5jZS4kdHJpZ2dlciA9ICR0YXJnZXQ7XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBqUXVlcnkgcGx1Z2luXHJcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAkLmZuLmZhbmN5Ym94ID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcclxuICAgIHZhciBzZWxlY3RvcjtcclxuXHJcbiAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcclxuICAgIHNlbGVjdG9yID0gb3B0aW9ucy5zZWxlY3RvciB8fCBmYWxzZTtcclxuXHJcbiAgICBpZiAoc2VsZWN0b3IpIHtcclxuICAgICAgLy8gVXNlIGJvZHkgZWxlbWVudCBpbnN0ZWFkIG9mIGRvY3VtZW50IHNvIGl0IGV4ZWN1dGVzIGZpcnN0XHJcbiAgICAgICQoXCJib2R5XCIpXHJcbiAgICAgICAgLm9mZihcImNsaWNrLmZiLXN0YXJ0XCIsIHNlbGVjdG9yKVxyXG4gICAgICAgIC5vbihcImNsaWNrLmZiLXN0YXJ0XCIsIHNlbGVjdG9yLCB7XHJcbiAgICAgICAgICBvcHRpb25zOiBvcHRpb25zXHJcbiAgICAgICAgfSwgX3J1bik7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aGlzLm9mZihcImNsaWNrLmZiLXN0YXJ0XCIpLm9uKFxyXG4gICAgICAgIFwiY2xpY2suZmItc3RhcnRcIiwge1xyXG4gICAgICAgICAgaXRlbXM6IHRoaXMsXHJcbiAgICAgICAgICBvcHRpb25zOiBvcHRpb25zXHJcbiAgICAgICAgfSxcclxuICAgICAgICBfcnVuXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfTtcclxuXHJcbiAgLy8gU2VsZiBpbml0aWFsaXppbmcgcGx1Z2luIGZvciBhbGwgZWxlbWVudHMgaGF2aW5nIGBkYXRhLWZhbmN5Ym94YCBhdHRyaWJ1dGVcclxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG5cclxuICAkRC5vbihcImNsaWNrLmZiLXN0YXJ0XCIsIFwiW2RhdGEtZmFuY3lib3hdXCIsIF9ydW4pO1xyXG5cclxuICAvLyBFbmFibGUgXCJ0cmlnZ2VyIGVsZW1lbnRzXCJcclxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09XHJcblxyXG4gICRELm9uKFwiY2xpY2suZmItc3RhcnRcIiwgXCJbZGF0YS1mYW5jeWJveC10cmlnZ2VyXVwiLCBmdW5jdGlvbiAoZSkge1xyXG4gICAgJCgnW2RhdGEtZmFuY3lib3g9XCInICsgJCh0aGlzKS5hdHRyKFwiZGF0YS1mYW5jeWJveC10cmlnZ2VyXCIpICsgJ1wiXScpXHJcbiAgICAgIC5lcSgkKHRoaXMpLmF0dHIoXCJkYXRhLWZhbmN5Ym94LWluZGV4XCIpIHx8IDApXHJcbiAgICAgIC50cmlnZ2VyKFwiY2xpY2suZmItc3RhcnRcIiwge1xyXG4gICAgICAgICR0cmlnZ2VyOiAkKHRoaXMpXHJcbiAgICAgIH0pO1xyXG4gIH0pO1xyXG5cclxuICAvLyBUcmFjayBmb2N1cyBldmVudCBmb3IgYmV0dGVyIGFjY2Vzc2liaWxpdHkgc3R5bGluZ1xyXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbiAgKGZ1bmN0aW9uICgpIHtcclxuICAgIHZhciBidXR0b25TdHIgPSBcIi5mYW5jeWJveC1idXR0b25cIixcclxuICAgICAgZm9jdXNTdHIgPSBcImZhbmN5Ym94LWZvY3VzXCIsXHJcbiAgICAgICRwcmVzc2VkID0gbnVsbDtcclxuXHJcbiAgICAkRC5vbihcIm1vdXNlZG93biBtb3VzZXVwIGZvY3VzIGJsdXJcIiwgYnV0dG9uU3RyLCBmdW5jdGlvbiAoZSkge1xyXG4gICAgICBzd2l0Y2ggKGUudHlwZSkge1xyXG4gICAgICAgIGNhc2UgXCJtb3VzZWRvd25cIjpcclxuICAgICAgICAgICRwcmVzc2VkID0gJCh0aGlzKTtcclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIGNhc2UgXCJtb3VzZXVwXCI6XHJcbiAgICAgICAgICAkcHJlc3NlZCA9IG51bGw7XHJcbiAgICAgICAgICBicmVhaztcclxuICAgICAgICBjYXNlIFwiZm9jdXNpblwiOlxyXG4gICAgICAgICAgJChidXR0b25TdHIpLnJlbW92ZUNsYXNzKGZvY3VzU3RyKTtcclxuXHJcbiAgICAgICAgICBpZiAoISQodGhpcykuaXMoJHByZXNzZWQpICYmICEkKHRoaXMpLmlzKFwiW2Rpc2FibGVkXVwiKSkge1xyXG4gICAgICAgICAgICAkKHRoaXMpLmFkZENsYXNzKGZvY3VzU3RyKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIGNhc2UgXCJmb2N1c291dFwiOlxyXG4gICAgICAgICAgJChidXR0b25TdHIpLnJlbW92ZUNsYXNzKGZvY3VzU3RyKTtcclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9KSgpO1xyXG59KSh3aW5kb3csIGRvY3VtZW50LCBqUXVlcnkpO1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuLy9cclxuLy8gTWVkaWFcclxuLy8gQWRkcyBhZGRpdGlvbmFsIG1lZGlhIHR5cGUgc3VwcG9ydFxyXG4vL1xyXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4oZnVuY3Rpb24gKCQpIHtcclxuICBcInVzZSBzdHJpY3RcIjtcclxuXHJcbiAgLy8gT2JqZWN0IGNvbnRhaW5pbmcgcHJvcGVydGllcyBmb3IgZWFjaCBtZWRpYSB0eXBlXHJcbiAgdmFyIGRlZmF1bHRzID0ge1xyXG4gICAgeW91dHViZToge1xyXG4gICAgICBtYXRjaGVyOiAvKHlvdXR1YmVcXC5jb218eW91dHVcXC5iZXx5b3V0dWJlXFwtbm9jb29raWVcXC5jb20pXFwvKHdhdGNoXFw/KC4qJik/dj18dlxcL3x1XFwvfGVtYmVkXFwvPyk/KHZpZGVvc2VyaWVzXFw/bGlzdD0oLiopfFtcXHctXXsxMX18XFw/bGlzdFR5cGU9KC4qKSZsaXN0PSguKikpKC4qKS9pLFxyXG4gICAgICBwYXJhbXM6IHtcclxuICAgICAgICBhdXRvcGxheTogMSxcclxuICAgICAgICBhdXRvaGlkZTogMSxcclxuICAgICAgICBmczogMSxcclxuICAgICAgICByZWw6IDAsXHJcbiAgICAgICAgaGQ6IDEsXHJcbiAgICAgICAgd21vZGU6IFwidHJhbnNwYXJlbnRcIixcclxuICAgICAgICBlbmFibGVqc2FwaTogMSxcclxuICAgICAgICBodG1sNTogMVxyXG4gICAgICB9LFxyXG4gICAgICBwYXJhbVBsYWNlOiA4LFxyXG4gICAgICB0eXBlOiBcImlmcmFtZVwiLFxyXG4gICAgICB1cmw6IFwiaHR0cHM6Ly93d3cueW91dHViZS1ub2Nvb2tpZS5jb20vZW1iZWQvJDRcIixcclxuICAgICAgdGh1bWI6IFwiaHR0cHM6Ly9pbWcueW91dHViZS5jb20vdmkvJDQvaHFkZWZhdWx0LmpwZ1wiXHJcbiAgICB9LFxyXG5cclxuICAgIHZpbWVvOiB7XHJcbiAgICAgIG1hdGNoZXI6IC9eLit2aW1lby5jb21cXC8oLipcXC8pPyhbXFxkXSspKC4qKT8vLFxyXG4gICAgICBwYXJhbXM6IHtcclxuICAgICAgICBhdXRvcGxheTogMSxcclxuICAgICAgICBoZDogMSxcclxuICAgICAgICBzaG93X3RpdGxlOiAxLFxyXG4gICAgICAgIHNob3dfYnlsaW5lOiAxLFxyXG4gICAgICAgIHNob3dfcG9ydHJhaXQ6IDAsXHJcbiAgICAgICAgZnVsbHNjcmVlbjogMVxyXG4gICAgICB9LFxyXG4gICAgICBwYXJhbVBsYWNlOiAzLFxyXG4gICAgICB0eXBlOiBcImlmcmFtZVwiLFxyXG4gICAgICB1cmw6IFwiLy9wbGF5ZXIudmltZW8uY29tL3ZpZGVvLyQyXCJcclxuICAgIH0sXHJcblxyXG4gICAgaW5zdGFncmFtOiB7XHJcbiAgICAgIG1hdGNoZXI6IC8oaW5zdGFnclxcLmFtfGluc3RhZ3JhbVxcLmNvbSlcXC9wXFwvKFthLXpBLVowLTlfXFwtXSspXFwvPy9pLFxyXG4gICAgICB0eXBlOiBcImltYWdlXCIsXHJcbiAgICAgIHVybDogXCIvLyQxL3AvJDIvbWVkaWEvP3NpemU9bFwiXHJcbiAgICB9LFxyXG5cclxuICAgIC8vIEV4YW1wbGVzOlxyXG4gICAgLy8gaHR0cDovL21hcHMuZ29vZ2xlLmNvbS8/bGw9NDguODU3OTk1LDIuMjk0Mjk3JnNwbj0wLjAwNzY2NiwwLjAyMTEzNiZ0PW0mej0xNlxyXG4gICAgLy8gaHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS9tYXBzL0AzNy43ODUyMDA2LC0xMjIuNDE0NjM1NSwxNC42NXpcclxuICAgIC8vIGh0dHBzOi8vd3d3Lmdvb2dsZS5jb20vbWFwcy9ANTIuMjExMTEyMywyLjkyMzc1NDIsNi42MXo/aGw9ZW5cclxuICAgIC8vIGh0dHBzOi8vd3d3Lmdvb2dsZS5jb20vbWFwcy9wbGFjZS9Hb29nbGVwbGV4L0AzNy40MjIwMDQxLC0xMjIuMDgzMzQ5NCwxN3ovZGF0YT0hNG01ITNtNCExczB4MDoweDZjMjk2YzY2NjE5MzY3ZTAhOG0yITNkMzcuNDIxOTk5OCE0ZC0xMjIuMDg0MDU3MlxyXG4gICAgZ21hcF9wbGFjZToge1xyXG4gICAgICBtYXRjaGVyOiAvKG1hcHNcXC4pP2dvb2dsZVxcLihbYS16XXsyLDN9KFxcLlthLXpdezJ9KT8pXFwvKCgobWFwc1xcLyhwbGFjZVxcLyguKilcXC8pP1xcQCguKiksKFxcZCsuP1xcZCs/KXopKXwoXFw/bGw9KSkoLiopPy9pLFxyXG4gICAgICB0eXBlOiBcImlmcmFtZVwiLFxyXG4gICAgICB1cmw6IGZ1bmN0aW9uIChyZXopIHtcclxuICAgICAgICByZXR1cm4gKFxyXG4gICAgICAgICAgXCIvL21hcHMuZ29vZ2xlLlwiICtcclxuICAgICAgICAgIHJlelsyXSArXHJcbiAgICAgICAgICBcIi8/bGw9XCIgK1xyXG4gICAgICAgICAgKHJlels5XSA/IHJlels5XSArIFwiJno9XCIgKyBNYXRoLmZsb29yKHJlelsxMF0pICsgKHJlelsxMl0gPyByZXpbMTJdLnJlcGxhY2UoL15cXC8vLCBcIiZcIikgOiBcIlwiKSA6IHJlelsxMl0gKyBcIlwiKS5yZXBsYWNlKC9cXD8vLCBcIiZcIikgK1xyXG4gICAgICAgICAgXCImb3V0cHV0PVwiICtcclxuICAgICAgICAgIChyZXpbMTJdICYmIHJlelsxMl0uaW5kZXhPZihcImxheWVyPWNcIikgPiAwID8gXCJzdmVtYmVkXCIgOiBcImVtYmVkXCIpXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICAvLyBFeGFtcGxlczpcclxuICAgIC8vIGh0dHBzOi8vd3d3Lmdvb2dsZS5jb20vbWFwcy9zZWFyY2gvRW1waXJlK1N0YXRlK0J1aWxkaW5nL1xyXG4gICAgLy8gaHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS9tYXBzL3NlYXJjaC8/YXBpPTEmcXVlcnk9Y2VudHVyeWxpbmsrZmllbGRcclxuICAgIC8vIGh0dHBzOi8vd3d3Lmdvb2dsZS5jb20vbWFwcy9zZWFyY2gvP2FwaT0xJnF1ZXJ5PTQ3LjU5NTE1MTgsLTEyMi4zMzE2MzkzXHJcbiAgICBnbWFwX3NlYXJjaDoge1xyXG4gICAgICBtYXRjaGVyOiAvKG1hcHNcXC4pP2dvb2dsZVxcLihbYS16XXsyLDN9KFxcLlthLXpdezJ9KT8pXFwvKG1hcHNcXC9zZWFyY2hcXC8pKC4qKS9pLFxyXG4gICAgICB0eXBlOiBcImlmcmFtZVwiLFxyXG4gICAgICB1cmw6IGZ1bmN0aW9uIChyZXopIHtcclxuICAgICAgICByZXR1cm4gXCIvL21hcHMuZ29vZ2xlLlwiICsgcmV6WzJdICsgXCIvbWFwcz9xPVwiICsgcmV6WzVdLnJlcGxhY2UoXCJxdWVyeT1cIiwgXCJxPVwiKS5yZXBsYWNlKFwiYXBpPTFcIiwgXCJcIikgKyBcIiZvdXRwdXQ9ZW1iZWRcIjtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIC8vIEZvcm1hdHMgbWF0Y2hpbmcgdXJsIHRvIGZpbmFsIGZvcm1cclxuICB2YXIgZm9ybWF0ID0gZnVuY3Rpb24gKHVybCwgcmV6LCBwYXJhbXMpIHtcclxuICAgIGlmICghdXJsKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICBwYXJhbXMgPSBwYXJhbXMgfHwgXCJcIjtcclxuXHJcbiAgICBpZiAoJC50eXBlKHBhcmFtcykgPT09IFwib2JqZWN0XCIpIHtcclxuICAgICAgcGFyYW1zID0gJC5wYXJhbShwYXJhbXMsIHRydWUpO1xyXG4gICAgfVxyXG5cclxuICAgICQuZWFjaChyZXosIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XHJcbiAgICAgIHVybCA9IHVybC5yZXBsYWNlKFwiJFwiICsga2V5LCB2YWx1ZSB8fCBcIlwiKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGlmIChwYXJhbXMubGVuZ3RoKSB7XHJcbiAgICAgIHVybCArPSAodXJsLmluZGV4T2YoXCI/XCIpID4gMCA/IFwiJlwiIDogXCI/XCIpICsgcGFyYW1zO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB1cmw7XHJcbiAgfTtcclxuXHJcbiAgJChkb2N1bWVudCkub24oXCJvYmplY3ROZWVkc1R5cGUuZmJcIiwgZnVuY3Rpb24gKGUsIGluc3RhbmNlLCBpdGVtKSB7XHJcbiAgICB2YXIgdXJsID0gaXRlbS5zcmMgfHwgXCJcIixcclxuICAgICAgdHlwZSA9IGZhbHNlLFxyXG4gICAgICBtZWRpYSxcclxuICAgICAgdGh1bWIsXHJcbiAgICAgIHJleixcclxuICAgICAgcGFyYW1zLFxyXG4gICAgICB1cmxQYXJhbXMsXHJcbiAgICAgIHBhcmFtT2JqLFxyXG4gICAgICBwcm92aWRlcjtcclxuXHJcbiAgICBtZWRpYSA9ICQuZXh0ZW5kKHRydWUsIHt9LCBkZWZhdWx0cywgaXRlbS5vcHRzLm1lZGlhKTtcclxuXHJcbiAgICAvLyBMb29rIGZvciBhbnkgbWF0Y2hpbmcgbWVkaWEgdHlwZVxyXG4gICAgJC5lYWNoKG1lZGlhLCBmdW5jdGlvbiAocHJvdmlkZXJOYW1lLCBwcm92aWRlck9wdHMpIHtcclxuICAgICAgcmV6ID0gdXJsLm1hdGNoKHByb3ZpZGVyT3B0cy5tYXRjaGVyKTtcclxuXHJcbiAgICAgIGlmICghcmV6KSB7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcblxyXG4gICAgICB0eXBlID0gcHJvdmlkZXJPcHRzLnR5cGU7XHJcbiAgICAgIHByb3ZpZGVyID0gcHJvdmlkZXJOYW1lO1xyXG4gICAgICBwYXJhbU9iaiA9IHt9O1xyXG5cclxuICAgICAgaWYgKHByb3ZpZGVyT3B0cy5wYXJhbVBsYWNlICYmIHJleltwcm92aWRlck9wdHMucGFyYW1QbGFjZV0pIHtcclxuICAgICAgICB1cmxQYXJhbXMgPSByZXpbcHJvdmlkZXJPcHRzLnBhcmFtUGxhY2VdO1xyXG5cclxuICAgICAgICBpZiAodXJsUGFyYW1zWzBdID09IFwiP1wiKSB7XHJcbiAgICAgICAgICB1cmxQYXJhbXMgPSB1cmxQYXJhbXMuc3Vic3RyaW5nKDEpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdXJsUGFyYW1zID0gdXJsUGFyYW1zLnNwbGl0KFwiJlwiKTtcclxuXHJcbiAgICAgICAgZm9yICh2YXIgbSA9IDA7IG0gPCB1cmxQYXJhbXMubGVuZ3RoOyArK20pIHtcclxuICAgICAgICAgIHZhciBwID0gdXJsUGFyYW1zW21dLnNwbGl0KFwiPVwiLCAyKTtcclxuXHJcbiAgICAgICAgICBpZiAocC5sZW5ndGggPT0gMikge1xyXG4gICAgICAgICAgICBwYXJhbU9ialtwWzBdXSA9IGRlY29kZVVSSUNvbXBvbmVudChwWzFdLnJlcGxhY2UoL1xcKy9nLCBcIiBcIikpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgcGFyYW1zID0gJC5leHRlbmQodHJ1ZSwge30sIHByb3ZpZGVyT3B0cy5wYXJhbXMsIGl0ZW0ub3B0c1twcm92aWRlck5hbWVdLCBwYXJhbU9iaik7XHJcblxyXG4gICAgICB1cmwgPVxyXG4gICAgICAgICQudHlwZShwcm92aWRlck9wdHMudXJsKSA9PT0gXCJmdW5jdGlvblwiID8gcHJvdmlkZXJPcHRzLnVybC5jYWxsKHRoaXMsIHJleiwgcGFyYW1zLCBpdGVtKSA6IGZvcm1hdChwcm92aWRlck9wdHMudXJsLCByZXosIHBhcmFtcyk7XHJcblxyXG4gICAgICB0aHVtYiA9XHJcbiAgICAgICAgJC50eXBlKHByb3ZpZGVyT3B0cy50aHVtYikgPT09IFwiZnVuY3Rpb25cIiA/IHByb3ZpZGVyT3B0cy50aHVtYi5jYWxsKHRoaXMsIHJleiwgcGFyYW1zLCBpdGVtKSA6IGZvcm1hdChwcm92aWRlck9wdHMudGh1bWIsIHJleik7XHJcblxyXG4gICAgICBpZiAocHJvdmlkZXJOYW1lID09PSBcInlvdXR1YmVcIikge1xyXG4gICAgICAgIHVybCA9IHVybC5yZXBsYWNlKC8mdD0oKFxcZCspbSk/KFxcZCspcy8sIGZ1bmN0aW9uIChtYXRjaCwgcDEsIG0sIHMpIHtcclxuICAgICAgICAgIHJldHVybiBcIiZzdGFydD1cIiArICgobSA/IHBhcnNlSW50KG0sIDEwKSAqIDYwIDogMCkgKyBwYXJzZUludChzLCAxMCkpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGVsc2UgaWYgKHByb3ZpZGVyTmFtZSA9PT0gXCJ2aW1lb1wiKSB7XHJcbiAgICAgICAgdXJsID0gdXJsLnJlcGxhY2UoXCImJTIzXCIsIFwiI1wiKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gSWYgaXQgaXMgZm91bmQsIHRoZW4gY2hhbmdlIGNvbnRlbnQgdHlwZSBhbmQgdXBkYXRlIHRoZSB1cmxcclxuXHJcbiAgICBpZiAodHlwZSkge1xyXG4gICAgICBpZiAoIWl0ZW0ub3B0cy50aHVtYiAmJiAhKGl0ZW0ub3B0cy4kdGh1bWIgJiYgaXRlbS5vcHRzLiR0aHVtYi5sZW5ndGgpKSB7XHJcbiAgICAgICAgaXRlbS5vcHRzLnRodW1iID0gdGh1bWI7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICh0eXBlID09PSBcImlmcmFtZVwiKSB7XHJcbiAgICAgICAgaXRlbS5vcHRzID0gJC5leHRlbmQodHJ1ZSwgaXRlbS5vcHRzLCB7XHJcbiAgICAgICAgICBpZnJhbWU6IHtcclxuICAgICAgICAgICAgcHJlbG9hZDogZmFsc2UsXHJcbiAgICAgICAgICAgIGF0dHI6IHtcclxuICAgICAgICAgICAgICBzY3JvbGxpbmc6IFwibm9cIlxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgICQuZXh0ZW5kKGl0ZW0sIHtcclxuICAgICAgICB0eXBlOiB0eXBlLFxyXG4gICAgICAgIHNyYzogdXJsLFxyXG4gICAgICAgIG9yaWdTcmM6IGl0ZW0uc3JjLFxyXG4gICAgICAgIGNvbnRlbnRTb3VyY2U6IHByb3ZpZGVyLFxyXG4gICAgICAgIGNvbnRlbnRUeXBlOiB0eXBlID09PSBcImltYWdlXCIgPyBcImltYWdlXCIgOiBwcm92aWRlciA9PSBcImdtYXBfcGxhY2VcIiB8fCBwcm92aWRlciA9PSBcImdtYXBfc2VhcmNoXCIgPyBcIm1hcFwiIDogXCJ2aWRlb1wiXHJcbiAgICAgIH0pO1xyXG4gICAgfSBlbHNlIGlmICh1cmwpIHtcclxuICAgICAgaXRlbS50eXBlID0gaXRlbS5vcHRzLmRlZmF1bHRUeXBlO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBMb2FkIFlvdVR1YmUvVmlkZW8gQVBJIG9uIHJlcXVlc3QgdG8gZGV0ZWN0IHdoZW4gdmlkZW8gZmluaXNoZWQgcGxheWluZ1xyXG4gIHZhciBWaWRlb0FQSUxvYWRlciA9IHtcclxuICAgIHlvdXR1YmU6IHtcclxuICAgICAgc3JjOiBcImh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL2lmcmFtZV9hcGlcIixcclxuICAgICAgY2xhc3M6IFwiWVRcIixcclxuICAgICAgbG9hZGluZzogZmFsc2UsXHJcbiAgICAgIGxvYWRlZDogZmFsc2VcclxuICAgIH0sXHJcblxyXG4gICAgdmltZW86IHtcclxuICAgICAgc3JjOiBcImh0dHBzOi8vcGxheWVyLnZpbWVvLmNvbS9hcGkvcGxheWVyLmpzXCIsXHJcbiAgICAgIGNsYXNzOiBcIlZpbWVvXCIsXHJcbiAgICAgIGxvYWRpbmc6IGZhbHNlLFxyXG4gICAgICBsb2FkZWQ6IGZhbHNlXHJcbiAgICB9LFxyXG5cclxuICAgIGxvYWQ6IGZ1bmN0aW9uICh2ZW5kb3IpIHtcclxuICAgICAgdmFyIF90aGlzID0gdGhpcyxcclxuICAgICAgICBzY3JpcHQ7XHJcblxyXG4gICAgICBpZiAodGhpc1t2ZW5kb3JdLmxvYWRlZCkge1xyXG4gICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgX3RoaXMuZG9uZSh2ZW5kb3IpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKHRoaXNbdmVuZG9yXS5sb2FkaW5nKSB7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcblxyXG4gICAgICB0aGlzW3ZlbmRvcl0ubG9hZGluZyA9IHRydWU7XHJcblxyXG4gICAgICBzY3JpcHQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwic2NyaXB0XCIpO1xyXG4gICAgICBzY3JpcHQudHlwZSA9IFwidGV4dC9qYXZhc2NyaXB0XCI7XHJcbiAgICAgIHNjcmlwdC5zcmMgPSB0aGlzW3ZlbmRvcl0uc3JjO1xyXG5cclxuICAgICAgaWYgKHZlbmRvciA9PT0gXCJ5b3V0dWJlXCIpIHtcclxuICAgICAgICB3aW5kb3cub25Zb3VUdWJlSWZyYW1lQVBJUmVhZHkgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICBfdGhpc1t2ZW5kb3JdLmxvYWRlZCA9IHRydWU7XHJcbiAgICAgICAgICBfdGhpcy5kb25lKHZlbmRvcik7XHJcbiAgICAgICAgfTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBzY3JpcHQub25sb2FkID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgX3RoaXNbdmVuZG9yXS5sb2FkZWQgPSB0cnVlO1xyXG4gICAgICAgICAgX3RoaXMuZG9uZSh2ZW5kb3IpO1xyXG4gICAgICAgIH07XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoc2NyaXB0KTtcclxuICAgIH0sXHJcbiAgICBkb25lOiBmdW5jdGlvbiAodmVuZG9yKSB7XHJcbiAgICAgIHZhciBpbnN0YW5jZSwgJGVsLCBwbGF5ZXI7XHJcblxyXG4gICAgICBpZiAodmVuZG9yID09PSBcInlvdXR1YmVcIikge1xyXG4gICAgICAgIGRlbGV0ZSB3aW5kb3cub25Zb3VUdWJlSWZyYW1lQVBJUmVhZHk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGluc3RhbmNlID0gJC5mYW5jeWJveC5nZXRJbnN0YW5jZSgpO1xyXG5cclxuICAgICAgaWYgKGluc3RhbmNlKSB7XHJcbiAgICAgICAgJGVsID0gaW5zdGFuY2UuY3VycmVudC4kY29udGVudC5maW5kKFwiaWZyYW1lXCIpO1xyXG5cclxuICAgICAgICBpZiAodmVuZG9yID09PSBcInlvdXR1YmVcIiAmJiBZVCAhPT0gdW5kZWZpbmVkICYmIFlUKSB7XHJcbiAgICAgICAgICBwbGF5ZXIgPSBuZXcgWVQuUGxheWVyKCRlbC5hdHRyKFwiaWRcIiksIHtcclxuICAgICAgICAgICAgZXZlbnRzOiB7XHJcbiAgICAgICAgICAgICAgb25TdGF0ZUNoYW5nZTogZnVuY3Rpb24gKGUpIHtcclxuICAgICAgICAgICAgICAgIGlmIChlLmRhdGEgPT0gMCkge1xyXG4gICAgICAgICAgICAgICAgICBpbnN0YW5jZS5uZXh0KCk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9IGVsc2UgaWYgKHZlbmRvciA9PT0gXCJ2aW1lb1wiICYmIFZpbWVvICE9PSB1bmRlZmluZWQgJiYgVmltZW8pIHtcclxuICAgICAgICAgIHBsYXllciA9IG5ldyBWaW1lby5QbGF5ZXIoJGVsKTtcclxuXHJcbiAgICAgICAgICBwbGF5ZXIub24oXCJlbmRlZFwiLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgIGluc3RhbmNlLm5leHQoKTtcclxuICAgICAgICAgIH0pO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gICQoZG9jdW1lbnQpLm9uKHtcclxuICAgIFwiYWZ0ZXJTaG93LmZiXCI6IGZ1bmN0aW9uIChlLCBpbnN0YW5jZSwgY3VycmVudCkge1xyXG4gICAgICBpZiAoaW5zdGFuY2UuZ3JvdXAubGVuZ3RoID4gMSAmJiAoY3VycmVudC5jb250ZW50U291cmNlID09PSBcInlvdXR1YmVcIiB8fCBjdXJyZW50LmNvbnRlbnRTb3VyY2UgPT09IFwidmltZW9cIikpIHtcclxuICAgICAgICBWaWRlb0FQSUxvYWRlci5sb2FkKGN1cnJlbnQuY29udGVudFNvdXJjZSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxufSkoalF1ZXJ5KTtcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbi8vXHJcbi8vIEd1ZXN0dXJlc1xyXG4vLyBBZGRzIHRvdWNoIGd1ZXN0dXJlcywgaGFuZGxlcyBjbGljayBhbmQgdGFwIGV2ZW50c1xyXG4vL1xyXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4oZnVuY3Rpb24gKHdpbmRvdywgZG9jdW1lbnQsICQpIHtcclxuICBcInVzZSBzdHJpY3RcIjtcclxuXHJcbiAgdmFyIHJlcXVlc3RBRnJhbWUgPSAoZnVuY3Rpb24gKCkge1xyXG4gICAgcmV0dXJuIChcclxuICAgICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSB8fFxyXG4gICAgICB3aW5kb3cud2Via2l0UmVxdWVzdEFuaW1hdGlvbkZyYW1lIHx8XHJcbiAgICAgIHdpbmRvdy5tb3pSZXF1ZXN0QW5pbWF0aW9uRnJhbWUgfHxcclxuICAgICAgd2luZG93Lm9SZXF1ZXN0QW5pbWF0aW9uRnJhbWUgfHxcclxuICAgICAgLy8gaWYgYWxsIGVsc2UgZmFpbHMsIHVzZSBzZXRUaW1lb3V0XHJcbiAgICAgIGZ1bmN0aW9uIChjYWxsYmFjaykge1xyXG4gICAgICAgIHJldHVybiB3aW5kb3cuc2V0VGltZW91dChjYWxsYmFjaywgMTAwMCAvIDYwKTtcclxuICAgICAgfVxyXG4gICAgKTtcclxuICB9KSgpO1xyXG5cclxuICB2YXIgY2FuY2VsQUZyYW1lID0gKGZ1bmN0aW9uICgpIHtcclxuICAgIHJldHVybiAoXHJcbiAgICAgIHdpbmRvdy5jYW5jZWxBbmltYXRpb25GcmFtZSB8fFxyXG4gICAgICB3aW5kb3cud2Via2l0Q2FuY2VsQW5pbWF0aW9uRnJhbWUgfHxcclxuICAgICAgd2luZG93Lm1vekNhbmNlbEFuaW1hdGlvbkZyYW1lIHx8XHJcbiAgICAgIHdpbmRvdy5vQ2FuY2VsQW5pbWF0aW9uRnJhbWUgfHxcclxuICAgICAgZnVuY3Rpb24gKGlkKSB7XHJcbiAgICAgICAgd2luZG93LmNsZWFyVGltZW91dChpZCk7XHJcbiAgICAgIH1cclxuICAgICk7XHJcbiAgfSkoKTtcclxuXHJcbiAgdmFyIGdldFBvaW50ZXJYWSA9IGZ1bmN0aW9uIChlKSB7XHJcbiAgICB2YXIgcmVzdWx0ID0gW107XHJcblxyXG4gICAgZSA9IGUub3JpZ2luYWxFdmVudCB8fCBlIHx8IHdpbmRvdy5lO1xyXG4gICAgZSA9IGUudG91Y2hlcyAmJiBlLnRvdWNoZXMubGVuZ3RoID8gZS50b3VjaGVzIDogZS5jaGFuZ2VkVG91Y2hlcyAmJiBlLmNoYW5nZWRUb3VjaGVzLmxlbmd0aCA/IGUuY2hhbmdlZFRvdWNoZXMgOiBbZV07XHJcblxyXG4gICAgZm9yICh2YXIga2V5IGluIGUpIHtcclxuICAgICAgaWYgKGVba2V5XS5wYWdlWCkge1xyXG4gICAgICAgIHJlc3VsdC5wdXNoKHtcclxuICAgICAgICAgIHg6IGVba2V5XS5wYWdlWCxcclxuICAgICAgICAgIHk6IGVba2V5XS5wYWdlWVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGVsc2UgaWYgKGVba2V5XS5jbGllbnRYKSB7XHJcbiAgICAgICAgcmVzdWx0LnB1c2goe1xyXG4gICAgICAgICAgeDogZVtrZXldLmNsaWVudFgsXHJcbiAgICAgICAgICB5OiBlW2tleV0uY2xpZW50WVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHJlc3VsdDtcclxuICB9O1xyXG5cclxuICB2YXIgZGlzdGFuY2UgPSBmdW5jdGlvbiAocG9pbnQyLCBwb2ludDEsIHdoYXQpIHtcclxuICAgIGlmICghcG9pbnQxIHx8ICFwb2ludDIpIHtcclxuICAgICAgcmV0dXJuIDA7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHdoYXQgPT09IFwieFwiKSB7XHJcbiAgICAgIHJldHVybiBwb2ludDIueCAtIHBvaW50MS54O1xyXG4gICAgfSBlbHNlIGlmICh3aGF0ID09PSBcInlcIikge1xyXG4gICAgICByZXR1cm4gcG9pbnQyLnkgLSBwb2ludDEueTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gTWF0aC5zcXJ0KE1hdGgucG93KHBvaW50Mi54IC0gcG9pbnQxLngsIDIpICsgTWF0aC5wb3cocG9pbnQyLnkgLSBwb2ludDEueSwgMikpO1xyXG4gIH07XHJcblxyXG4gIHZhciBpc0NsaWNrYWJsZSA9IGZ1bmN0aW9uICgkZWwpIHtcclxuICAgIGlmIChcclxuICAgICAgJGVsLmlzKCdhLGFyZWEsYnV0dG9uLFtyb2xlPVwiYnV0dG9uXCJdLGlucHV0LGxhYmVsLHNlbGVjdCxzdW1tYXJ5LHRleHRhcmVhLHZpZGVvLGF1ZGlvLGlmcmFtZScpIHx8XHJcbiAgICAgICQuaXNGdW5jdGlvbigkZWwuZ2V0KDApLm9uY2xpY2spIHx8XHJcbiAgICAgICRlbC5kYXRhKFwic2VsZWN0YWJsZVwiKVxyXG4gICAgKSB7XHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIGZvciBhdHRyaWJ1dGVzIGxpa2UgZGF0YS1mYW5jeWJveC1uZXh0IG9yIGRhdGEtZmFuY3lib3gtY2xvc2VcclxuICAgIGZvciAodmFyIGkgPSAwLCBhdHRzID0gJGVsWzBdLmF0dHJpYnV0ZXMsIG4gPSBhdHRzLmxlbmd0aDsgaSA8IG47IGkrKykge1xyXG4gICAgICBpZiAoYXR0c1tpXS5ub2RlTmFtZS5zdWJzdHIoMCwgMTQpID09PSBcImRhdGEtZmFuY3lib3gtXCIpIHtcclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBmYWxzZTtcclxuICB9O1xyXG5cclxuICB2YXIgaGFzU2Nyb2xsYmFycyA9IGZ1bmN0aW9uIChlbCkge1xyXG4gICAgdmFyIG92ZXJmbG93WSA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGVsKVtcIm92ZXJmbG93LXlcIl0sXHJcbiAgICAgIG92ZXJmbG93WCA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGVsKVtcIm92ZXJmbG93LXhcIl0sXHJcbiAgICAgIHZlcnRpY2FsID0gKG92ZXJmbG93WSA9PT0gXCJzY3JvbGxcIiB8fCBvdmVyZmxvd1kgPT09IFwiYXV0b1wiKSAmJiBlbC5zY3JvbGxIZWlnaHQgPiBlbC5jbGllbnRIZWlnaHQsXHJcbiAgICAgIGhvcml6b250YWwgPSAob3ZlcmZsb3dYID09PSBcInNjcm9sbFwiIHx8IG92ZXJmbG93WCA9PT0gXCJhdXRvXCIpICYmIGVsLnNjcm9sbFdpZHRoID4gZWwuY2xpZW50V2lkdGg7XHJcblxyXG4gICAgcmV0dXJuIHZlcnRpY2FsIHx8IGhvcml6b250YWw7XHJcbiAgfTtcclxuXHJcbiAgdmFyIGlzU2Nyb2xsYWJsZSA9IGZ1bmN0aW9uICgkZWwpIHtcclxuICAgIHZhciByZXogPSBmYWxzZTtcclxuXHJcbiAgICB3aGlsZSAodHJ1ZSkge1xyXG4gICAgICByZXogPSBoYXNTY3JvbGxiYXJzKCRlbC5nZXQoMCkpO1xyXG5cclxuICAgICAgaWYgKHJleikge1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAkZWwgPSAkZWwucGFyZW50KCk7XHJcblxyXG4gICAgICBpZiAoISRlbC5sZW5ndGggfHwgJGVsLmhhc0NsYXNzKFwiZmFuY3lib3gtc3RhZ2VcIikgfHwgJGVsLmlzKFwiYm9keVwiKSkge1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHJlejtcclxuICB9O1xyXG5cclxuICB2YXIgR3Vlc3R1cmVzID0gZnVuY3Rpb24gKGluc3RhbmNlKSB7XHJcbiAgICB2YXIgc2VsZiA9IHRoaXM7XHJcblxyXG4gICAgc2VsZi5pbnN0YW5jZSA9IGluc3RhbmNlO1xyXG5cclxuICAgIHNlbGYuJGJnID0gaW5zdGFuY2UuJHJlZnMuYmc7XHJcbiAgICBzZWxmLiRzdGFnZSA9IGluc3RhbmNlLiRyZWZzLnN0YWdlO1xyXG4gICAgc2VsZi4kY29udGFpbmVyID0gaW5zdGFuY2UuJHJlZnMuY29udGFpbmVyO1xyXG5cclxuICAgIHNlbGYuZGVzdHJveSgpO1xyXG5cclxuICAgIHNlbGYuJGNvbnRhaW5lci5vbihcInRvdWNoc3RhcnQuZmIudG91Y2ggbW91c2Vkb3duLmZiLnRvdWNoXCIsICQucHJveHkoc2VsZiwgXCJvbnRvdWNoc3RhcnRcIikpO1xyXG4gIH07XHJcblxyXG4gIEd1ZXN0dXJlcy5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcclxuICAgIHZhciBzZWxmID0gdGhpcztcclxuXHJcbiAgICBzZWxmLiRjb250YWluZXIub2ZmKFwiLmZiLnRvdWNoXCIpO1xyXG5cclxuICAgICQoZG9jdW1lbnQpLm9mZihcIi5mYi50b3VjaFwiKTtcclxuXHJcbiAgICBpZiAoc2VsZi5yZXF1ZXN0SWQpIHtcclxuICAgICAgY2FuY2VsQUZyYW1lKHNlbGYucmVxdWVzdElkKTtcclxuICAgICAgc2VsZi5yZXF1ZXN0SWQgPSBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChzZWxmLnRhcHBlZCkge1xyXG4gICAgICBjbGVhclRpbWVvdXQoc2VsZi50YXBwZWQpO1xyXG4gICAgICBzZWxmLnRhcHBlZCA9IG51bGw7XHJcbiAgICB9XHJcbiAgfTtcclxuXHJcbiAgR3Vlc3R1cmVzLnByb3RvdHlwZS5vbnRvdWNoc3RhcnQgPSBmdW5jdGlvbiAoZSkge1xyXG4gICAgdmFyIHNlbGYgPSB0aGlzLFxyXG4gICAgICAkdGFyZ2V0ID0gJChlLnRhcmdldCksXHJcbiAgICAgIGluc3RhbmNlID0gc2VsZi5pbnN0YW5jZSxcclxuICAgICAgY3VycmVudCA9IGluc3RhbmNlLmN1cnJlbnQsXHJcbiAgICAgICRzbGlkZSA9IGN1cnJlbnQuJHNsaWRlLFxyXG4gICAgICAkY29udGVudCA9IGN1cnJlbnQuJGNvbnRlbnQsXHJcbiAgICAgIGlzVG91Y2hEZXZpY2UgPSBlLnR5cGUgPT0gXCJ0b3VjaHN0YXJ0XCI7XHJcblxyXG4gICAgLy8gRG8gbm90IHJlc3BvbmQgdG8gYm90aCAodG91Y2ggYW5kIG1vdXNlKSBldmVudHNcclxuICAgIGlmIChpc1RvdWNoRGV2aWNlKSB7XHJcbiAgICAgIHNlbGYuJGNvbnRhaW5lci5vZmYoXCJtb3VzZWRvd24uZmIudG91Y2hcIik7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSWdub3JlIHJpZ2h0IGNsaWNrXHJcbiAgICBpZiAoZS5vcmlnaW5hbEV2ZW50ICYmIGUub3JpZ2luYWxFdmVudC5idXR0b24gPT0gMikge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSWdub3JlIHRhcGluZyBvbiBsaW5rcywgYnV0dG9ucywgaW5wdXQgZWxlbWVudHNcclxuICAgIGlmICghJHNsaWRlLmxlbmd0aCB8fCAhJHRhcmdldC5sZW5ndGggfHwgaXNDbGlja2FibGUoJHRhcmdldCkgfHwgaXNDbGlja2FibGUoJHRhcmdldC5wYXJlbnQoKSkpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgLy8gSWdub3JlIGNsaWNrcyBvbiB0aGUgc2Nyb2xsYmFyXHJcbiAgICBpZiAoISR0YXJnZXQuaXMoXCJpbWdcIikgJiYgZS5vcmlnaW5hbEV2ZW50LmNsaWVudFggPiAkdGFyZ2V0WzBdLmNsaWVudFdpZHRoICsgJHRhcmdldC5vZmZzZXQoKS5sZWZ0KSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBJZ25vcmUgY2xpY2tzIHdoaWxlIHpvb21pbmcgb3IgY2xvc2luZ1xyXG4gICAgaWYgKCFjdXJyZW50IHx8IGluc3RhbmNlLmlzQW5pbWF0aW5nIHx8IGN1cnJlbnQuJHNsaWRlLmhhc0NsYXNzKFwiZmFuY3lib3gtYW5pbWF0ZWRcIikpIHtcclxuICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xyXG5cclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIHNlbGYucmVhbFBvaW50cyA9IHNlbGYuc3RhcnRQb2ludHMgPSBnZXRQb2ludGVyWFkoZSk7XHJcblxyXG4gICAgaWYgKCFzZWxmLnN0YXJ0UG9pbnRzLmxlbmd0aCkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWxsb3cgb3RoZXIgc2NyaXB0cyB0byBjYXRjaCB0b3VjaCBldmVudCBpZiBcInRvdWNoXCIgaXMgc2V0IHRvIGZhbHNlXHJcbiAgICBpZiAoY3VycmVudC50b3VjaCkge1xyXG4gICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgfVxyXG5cclxuICAgIHNlbGYuc3RhcnRFdmVudCA9IGU7XHJcblxyXG4gICAgc2VsZi5jYW5UYXAgPSB0cnVlO1xyXG4gICAgc2VsZi4kdGFyZ2V0ID0gJHRhcmdldDtcclxuICAgIHNlbGYuJGNvbnRlbnQgPSAkY29udGVudDtcclxuICAgIHNlbGYub3B0cyA9IGN1cnJlbnQub3B0cy50b3VjaDtcclxuXHJcbiAgICBzZWxmLmlzUGFubmluZyA9IGZhbHNlO1xyXG4gICAgc2VsZi5pc1N3aXBpbmcgPSBmYWxzZTtcclxuICAgIHNlbGYuaXNab29taW5nID0gZmFsc2U7XHJcbiAgICBzZWxmLmlzU2Nyb2xsaW5nID0gZmFsc2U7XHJcbiAgICBzZWxmLmNhblBhbiA9IGluc3RhbmNlLmNhblBhbigpO1xyXG5cclxuICAgIHNlbGYuc3RhcnRUaW1lID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcbiAgICBzZWxmLmRpc3RhbmNlWCA9IHNlbGYuZGlzdGFuY2VZID0gc2VsZi5kaXN0YW5jZSA9IDA7XHJcblxyXG4gICAgc2VsZi5jYW52YXNXaWR0aCA9IE1hdGgucm91bmQoJHNsaWRlWzBdLmNsaWVudFdpZHRoKTtcclxuICAgIHNlbGYuY2FudmFzSGVpZ2h0ID0gTWF0aC5yb3VuZCgkc2xpZGVbMF0uY2xpZW50SGVpZ2h0KTtcclxuXHJcbiAgICBzZWxmLmNvbnRlbnRMYXN0UG9zID0gbnVsbDtcclxuICAgIHNlbGYuY29udGVudFN0YXJ0UG9zID0gJC5mYW5jeWJveC5nZXRUcmFuc2xhdGUoc2VsZi4kY29udGVudCkgfHwge1xyXG4gICAgICB0b3A6IDAsXHJcbiAgICAgIGxlZnQ6IDBcclxuICAgIH07XHJcbiAgICBzZWxmLnNsaWRlclN0YXJ0UG9zID0gJC5mYW5jeWJveC5nZXRUcmFuc2xhdGUoJHNsaWRlKTtcclxuXHJcbiAgICAvLyBTaW5jZSBwb3NpdGlvbiB3aWxsIGJlIGFic29sdXRlLCBidXQgd2UgbmVlZCB0byBtYWtlIGl0IHJlbGF0aXZlIHRvIHRoZSBzdGFnZVxyXG4gICAgc2VsZi5zdGFnZVBvcyA9ICQuZmFuY3lib3guZ2V0VHJhbnNsYXRlKGluc3RhbmNlLiRyZWZzLnN0YWdlKTtcclxuXHJcbiAgICBzZWxmLnNsaWRlclN0YXJ0UG9zLnRvcCAtPSBzZWxmLnN0YWdlUG9zLnRvcDtcclxuICAgIHNlbGYuc2xpZGVyU3RhcnRQb3MubGVmdCAtPSBzZWxmLnN0YWdlUG9zLmxlZnQ7XHJcblxyXG4gICAgc2VsZi5jb250ZW50U3RhcnRQb3MudG9wIC09IHNlbGYuc3RhZ2VQb3MudG9wO1xyXG4gICAgc2VsZi5jb250ZW50U3RhcnRQb3MubGVmdCAtPSBzZWxmLnN0YWdlUG9zLmxlZnQ7XHJcblxyXG4gICAgJChkb2N1bWVudClcclxuICAgICAgLm9mZihcIi5mYi50b3VjaFwiKVxyXG4gICAgICAub24oaXNUb3VjaERldmljZSA/IFwidG91Y2hlbmQuZmIudG91Y2ggdG91Y2hjYW5jZWwuZmIudG91Y2hcIiA6IFwibW91c2V1cC5mYi50b3VjaCBtb3VzZWxlYXZlLmZiLnRvdWNoXCIsICQucHJveHkoc2VsZiwgXCJvbnRvdWNoZW5kXCIpKVxyXG4gICAgICAub24oaXNUb3VjaERldmljZSA/IFwidG91Y2htb3ZlLmZiLnRvdWNoXCIgOiBcIm1vdXNlbW92ZS5mYi50b3VjaFwiLCAkLnByb3h5KHNlbGYsIFwib250b3VjaG1vdmVcIikpO1xyXG5cclxuICAgIGlmICgkLmZhbmN5Ym94LmlzTW9iaWxlKSB7XHJcbiAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoXCJzY3JvbGxcIiwgc2VsZi5vbnNjcm9sbCwgdHJ1ZSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2tpcCBpZiBjbGlja2VkIG91dHNpZGUgdGhlIHNsaWRpbmcgYXJlYVxyXG4gICAgaWYgKCEoc2VsZi5vcHRzIHx8IHNlbGYuY2FuUGFuKSB8fCAhKCR0YXJnZXQuaXMoc2VsZi4kc3RhZ2UpIHx8IHNlbGYuJHN0YWdlLmZpbmQoJHRhcmdldCkubGVuZ3RoKSkge1xyXG4gICAgICBpZiAoJHRhcmdldC5pcyhcIi5mYW5jeWJveC1pbWFnZVwiKSkge1xyXG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKCEoJC5mYW5jeWJveC5pc01vYmlsZSAmJiAkdGFyZ2V0LnBhcmVudHMoXCIuZmFuY3lib3gtY2FwdGlvblwiKS5sZW5ndGgpKSB7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgc2VsZi5pc1Njcm9sbGFibGUgPSBpc1Njcm9sbGFibGUoJHRhcmdldCkgfHwgaXNTY3JvbGxhYmxlKCR0YXJnZXQucGFyZW50KCkpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIGVsZW1lbnQgaXMgc2Nyb2xsYWJsZSBhbmQgdHJ5IHRvIHByZXZlbnQgZGVmYXVsdCBiZWhhdmlvciAoc2Nyb2xsaW5nKVxyXG4gICAgaWYgKCEoJC5mYW5jeWJveC5pc01vYmlsZSAmJiBzZWxmLmlzU2Nyb2xsYWJsZSkpIHtcclxuICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE9uZSBmaW5nZXIgb3IgbW91c2UgY2xpY2sgLSBzd2lwZSBvciBwYW4gYW4gaW1hZ2VcclxuICAgIGlmIChzZWxmLnN0YXJ0UG9pbnRzLmxlbmd0aCA9PT0gMSB8fCBjdXJyZW50Lmhhc0Vycm9yKSB7XHJcbiAgICAgIGlmIChzZWxmLmNhblBhbikge1xyXG4gICAgICAgICQuZmFuY3lib3guc3RvcChzZWxmLiRjb250ZW50KTtcclxuXHJcbiAgICAgICAgc2VsZi5pc1Bhbm5pbmcgPSB0cnVlO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHNlbGYuaXNTd2lwaW5nID0gdHJ1ZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgc2VsZi4kY29udGFpbmVyLmFkZENsYXNzKFwiZmFuY3lib3gtaXMtZ3JhYmJpbmdcIik7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVHdvIGZpbmdlcnMgLSB6b29tIGltYWdlXHJcbiAgICBpZiAoc2VsZi5zdGFydFBvaW50cy5sZW5ndGggPT09IDIgJiYgY3VycmVudC50eXBlID09PSBcImltYWdlXCIgJiYgKGN1cnJlbnQuaXNMb2FkZWQgfHwgY3VycmVudC4kZ2hvc3QpKSB7XHJcbiAgICAgIHNlbGYuY2FuVGFwID0gZmFsc2U7XHJcbiAgICAgIHNlbGYuaXNTd2lwaW5nID0gZmFsc2U7XHJcbiAgICAgIHNlbGYuaXNQYW5uaW5nID0gZmFsc2U7XHJcblxyXG4gICAgICBzZWxmLmlzWm9vbWluZyA9IHRydWU7XHJcblxyXG4gICAgICAkLmZhbmN5Ym94LnN0b3Aoc2VsZi4kY29udGVudCk7XHJcblxyXG4gICAgICBzZWxmLmNlbnRlclBvaW50U3RhcnRYID0gKHNlbGYuc3RhcnRQb2ludHNbMF0ueCArIHNlbGYuc3RhcnRQb2ludHNbMV0ueCkgKiAwLjUgLSAkKHdpbmRvdykuc2Nyb2xsTGVmdCgpO1xyXG4gICAgICBzZWxmLmNlbnRlclBvaW50U3RhcnRZID0gKHNlbGYuc3RhcnRQb2ludHNbMF0ueSArIHNlbGYuc3RhcnRQb2ludHNbMV0ueSkgKiAwLjUgLSAkKHdpbmRvdykuc2Nyb2xsVG9wKCk7XHJcblxyXG4gICAgICBzZWxmLnBlcmNlbnRhZ2VPZkltYWdlQXRQaW5jaFBvaW50WCA9IChzZWxmLmNlbnRlclBvaW50U3RhcnRYIC0gc2VsZi5jb250ZW50U3RhcnRQb3MubGVmdCkgLyBzZWxmLmNvbnRlbnRTdGFydFBvcy53aWR0aDtcclxuICAgICAgc2VsZi5wZXJjZW50YWdlT2ZJbWFnZUF0UGluY2hQb2ludFkgPSAoc2VsZi5jZW50ZXJQb2ludFN0YXJ0WSAtIHNlbGYuY29udGVudFN0YXJ0UG9zLnRvcCkgLyBzZWxmLmNvbnRlbnRTdGFydFBvcy5oZWlnaHQ7XHJcblxyXG4gICAgICBzZWxmLnN0YXJ0RGlzdGFuY2VCZXR3ZWVuRmluZ2VycyA9IGRpc3RhbmNlKHNlbGYuc3RhcnRQb2ludHNbMF0sIHNlbGYuc3RhcnRQb2ludHNbMV0pO1xyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIEd1ZXN0dXJlcy5wcm90b3R5cGUub25zY3JvbGwgPSBmdW5jdGlvbiAoZSkge1xyXG4gICAgdmFyIHNlbGYgPSB0aGlzO1xyXG5cclxuICAgIHNlbGYuaXNTY3JvbGxpbmcgPSB0cnVlO1xyXG5cclxuICAgIGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJzY3JvbGxcIiwgc2VsZi5vbnNjcm9sbCwgdHJ1ZSk7XHJcbiAgfTtcclxuXHJcbiAgR3Vlc3R1cmVzLnByb3RvdHlwZS5vbnRvdWNobW92ZSA9IGZ1bmN0aW9uIChlKSB7XHJcbiAgICB2YXIgc2VsZiA9IHRoaXM7XHJcblxyXG4gICAgLy8gTWFrZSBzdXJlIHVzZXIgaGFzIG5vdCByZWxlYXNlZCBvdmVyIGlmcmFtZSBvciBkaXNhYmxlZCBlbGVtZW50XHJcbiAgICBpZiAoZS5vcmlnaW5hbEV2ZW50LmJ1dHRvbnMgIT09IHVuZGVmaW5lZCAmJiBlLm9yaWdpbmFsRXZlbnQuYnV0dG9ucyA9PT0gMCkge1xyXG4gICAgICBzZWxmLm9udG91Y2hlbmQoZSk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoc2VsZi5pc1Njcm9sbGluZykge1xyXG4gICAgICBzZWxmLmNhblRhcCA9IGZhbHNlO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgc2VsZi5uZXdQb2ludHMgPSBnZXRQb2ludGVyWFkoZSk7XHJcblxyXG4gICAgaWYgKCEoc2VsZi5vcHRzIHx8IHNlbGYuY2FuUGFuKSB8fCAhc2VsZi5uZXdQb2ludHMubGVuZ3RoIHx8ICFzZWxmLm5ld1BvaW50cy5sZW5ndGgpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICghKHNlbGYuaXNTd2lwaW5nICYmIHNlbGYuaXNTd2lwaW5nID09PSB0cnVlKSkge1xyXG4gICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICB9XHJcblxyXG4gICAgc2VsZi5kaXN0YW5jZVggPSBkaXN0YW5jZShzZWxmLm5ld1BvaW50c1swXSwgc2VsZi5zdGFydFBvaW50c1swXSwgXCJ4XCIpO1xyXG4gICAgc2VsZi5kaXN0YW5jZVkgPSBkaXN0YW5jZShzZWxmLm5ld1BvaW50c1swXSwgc2VsZi5zdGFydFBvaW50c1swXSwgXCJ5XCIpO1xyXG5cclxuICAgIHNlbGYuZGlzdGFuY2UgPSBkaXN0YW5jZShzZWxmLm5ld1BvaW50c1swXSwgc2VsZi5zdGFydFBvaW50c1swXSk7XHJcblxyXG4gICAgLy8gU2tpcCBmYWxzZSBvbnRvdWNobW92ZSBldmVudHMgKENocm9tZSlcclxuICAgIGlmIChzZWxmLmRpc3RhbmNlID4gMCkge1xyXG4gICAgICBpZiAoc2VsZi5pc1N3aXBpbmcpIHtcclxuICAgICAgICBzZWxmLm9uU3dpcGUoZSk7XHJcbiAgICAgIH0gZWxzZSBpZiAoc2VsZi5pc1Bhbm5pbmcpIHtcclxuICAgICAgICBzZWxmLm9uUGFuKCk7XHJcbiAgICAgIH0gZWxzZSBpZiAoc2VsZi5pc1pvb21pbmcpIHtcclxuICAgICAgICBzZWxmLm9uWm9vbSgpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfTtcclxuXHJcbiAgR3Vlc3R1cmVzLnByb3RvdHlwZS5vblN3aXBlID0gZnVuY3Rpb24gKGUpIHtcclxuICAgIHZhciBzZWxmID0gdGhpcyxcclxuICAgICAgaW5zdGFuY2UgPSBzZWxmLmluc3RhbmNlLFxyXG4gICAgICBzd2lwaW5nID0gc2VsZi5pc1N3aXBpbmcsXHJcbiAgICAgIGxlZnQgPSBzZWxmLnNsaWRlclN0YXJ0UG9zLmxlZnQgfHwgMCxcclxuICAgICAgYW5nbGU7XHJcblxyXG4gICAgLy8gSWYgZGlyZWN0aW9uIGlzIG5vdCB5ZXQgZGV0ZXJtaW5lZFxyXG4gICAgaWYgKHN3aXBpbmcgPT09IHRydWUpIHtcclxuICAgICAgLy8gV2UgbmVlZCBhdCBsZWFzdCAxMHB4IGRpc3RhbmNlIHRvIGNvcnJlY3RseSBjYWxjdWxhdGUgYW4gYW5nbGVcclxuICAgICAgaWYgKE1hdGguYWJzKHNlbGYuZGlzdGFuY2UpID4gMTApIHtcclxuICAgICAgICBzZWxmLmNhblRhcCA9IGZhbHNlO1xyXG5cclxuICAgICAgICBpZiAoaW5zdGFuY2UuZ3JvdXAubGVuZ3RoIDwgMiAmJiBzZWxmLm9wdHMudmVydGljYWwpIHtcclxuICAgICAgICAgIHNlbGYuaXNTd2lwaW5nID0gXCJ5XCI7XHJcbiAgICAgICAgfSBlbHNlIGlmIChpbnN0YW5jZS5pc0RyYWdnaW5nIHx8IHNlbGYub3B0cy52ZXJ0aWNhbCA9PT0gZmFsc2UgfHwgKHNlbGYub3B0cy52ZXJ0aWNhbCA9PT0gXCJhdXRvXCIgJiYgJCh3aW5kb3cpLndpZHRoKCkgPiA4MDApKSB7XHJcbiAgICAgICAgICBzZWxmLmlzU3dpcGluZyA9IFwieFwiO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBhbmdsZSA9IE1hdGguYWJzKChNYXRoLmF0YW4yKHNlbGYuZGlzdGFuY2VZLCBzZWxmLmRpc3RhbmNlWCkgKiAxODApIC8gTWF0aC5QSSk7XHJcblxyXG4gICAgICAgICAgc2VsZi5pc1N3aXBpbmcgPSBhbmdsZSA+IDQ1ICYmIGFuZ2xlIDwgMTM1ID8gXCJ5XCIgOiBcInhcIjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmIChzZWxmLmlzU3dpcGluZyA9PT0gXCJ5XCIgJiYgJC5mYW5jeWJveC5pc01vYmlsZSAmJiBzZWxmLmlzU2Nyb2xsYWJsZSkge1xyXG4gICAgICAgICAgc2VsZi5pc1Njcm9sbGluZyA9IHRydWU7XHJcblxyXG4gICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaW5zdGFuY2UuaXNEcmFnZ2luZyA9IHNlbGYuaXNTd2lwaW5nO1xyXG5cclxuICAgICAgICAvLyBSZXNldCBwb2ludHMgdG8gYXZvaWQganVtcGluZywgYmVjYXVzZSB3ZSBkcm9wcGVkIGZpcnN0IHN3aXBlcyB0byBjYWxjdWxhdGUgdGhlIGFuZ2xlXHJcbiAgICAgICAgc2VsZi5zdGFydFBvaW50cyA9IHNlbGYubmV3UG9pbnRzO1xyXG5cclxuICAgICAgICAkLmVhY2goaW5zdGFuY2Uuc2xpZGVzLCBmdW5jdGlvbiAoaW5kZXgsIHNsaWRlKSB7XHJcbiAgICAgICAgICB2YXIgc2xpZGVQb3MsIHN0YWdlUG9zO1xyXG5cclxuICAgICAgICAgICQuZmFuY3lib3guc3RvcChzbGlkZS4kc2xpZGUpO1xyXG5cclxuICAgICAgICAgIHNsaWRlUG9zID0gJC5mYW5jeWJveC5nZXRUcmFuc2xhdGUoc2xpZGUuJHNsaWRlKTtcclxuICAgICAgICAgIHN0YWdlUG9zID0gJC5mYW5jeWJveC5nZXRUcmFuc2xhdGUoaW5zdGFuY2UuJHJlZnMuc3RhZ2UpO1xyXG5cclxuICAgICAgICAgIHNsaWRlLiRzbGlkZVxyXG4gICAgICAgICAgICAuY3NzKHtcclxuICAgICAgICAgICAgICB0cmFuc2Zvcm06IFwiXCIsXHJcbiAgICAgICAgICAgICAgb3BhY2l0eTogXCJcIixcclxuICAgICAgICAgICAgICBcInRyYW5zaXRpb24tZHVyYXRpb25cIjogXCJcIlxyXG4gICAgICAgICAgICB9KVxyXG4gICAgICAgICAgICAucmVtb3ZlQ2xhc3MoXCJmYW5jeWJveC1hbmltYXRlZFwiKVxyXG4gICAgICAgICAgICAucmVtb3ZlQ2xhc3MoZnVuY3Rpb24gKGluZGV4LCBjbGFzc05hbWUpIHtcclxuICAgICAgICAgICAgICByZXR1cm4gKGNsYXNzTmFtZS5tYXRjaCgvKF58XFxzKWZhbmN5Ym94LWZ4LVxcUysvZykgfHwgW10pLmpvaW4oXCIgXCIpO1xyXG4gICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgICBpZiAoc2xpZGUucG9zID09PSBpbnN0YW5jZS5jdXJyZW50LnBvcykge1xyXG4gICAgICAgICAgICBzZWxmLnNsaWRlclN0YXJ0UG9zLnRvcCA9IHNsaWRlUG9zLnRvcCAtIHN0YWdlUG9zLnRvcDtcclxuICAgICAgICAgICAgc2VsZi5zbGlkZXJTdGFydFBvcy5sZWZ0ID0gc2xpZGVQb3MubGVmdCAtIHN0YWdlUG9zLmxlZnQ7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgJC5mYW5jeWJveC5zZXRUcmFuc2xhdGUoc2xpZGUuJHNsaWRlLCB7XHJcbiAgICAgICAgICAgIHRvcDogc2xpZGVQb3MudG9wIC0gc3RhZ2VQb3MudG9wLFxyXG4gICAgICAgICAgICBsZWZ0OiBzbGlkZVBvcy5sZWZ0IC0gc3RhZ2VQb3MubGVmdFxyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFN0b3Agc2xpZGVzaG93XHJcbiAgICAgICAgaWYgKGluc3RhbmNlLlNsaWRlU2hvdyAmJiBpbnN0YW5jZS5TbGlkZVNob3cuaXNBY3RpdmUpIHtcclxuICAgICAgICAgIGluc3RhbmNlLlNsaWRlU2hvdy5zdG9wKCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU3RpY2t5IGVkZ2VzXHJcbiAgICBpZiAoc3dpcGluZyA9PSBcInhcIikge1xyXG4gICAgICBpZiAoXHJcbiAgICAgICAgc2VsZi5kaXN0YW5jZVggPiAwICYmXHJcbiAgICAgICAgKHNlbGYuaW5zdGFuY2UuZ3JvdXAubGVuZ3RoIDwgMiB8fCAoc2VsZi5pbnN0YW5jZS5jdXJyZW50LmluZGV4ID09PSAwICYmICFzZWxmLmluc3RhbmNlLmN1cnJlbnQub3B0cy5sb29wKSlcclxuICAgICAgKSB7XHJcbiAgICAgICAgbGVmdCA9IGxlZnQgKyBNYXRoLnBvdyhzZWxmLmRpc3RhbmNlWCwgMC44KTtcclxuICAgICAgfSBlbHNlIGlmIChcclxuICAgICAgICBzZWxmLmRpc3RhbmNlWCA8IDAgJiZcclxuICAgICAgICAoc2VsZi5pbnN0YW5jZS5ncm91cC5sZW5ndGggPCAyIHx8XHJcbiAgICAgICAgICAoc2VsZi5pbnN0YW5jZS5jdXJyZW50LmluZGV4ID09PSBzZWxmLmluc3RhbmNlLmdyb3VwLmxlbmd0aCAtIDEgJiYgIXNlbGYuaW5zdGFuY2UuY3VycmVudC5vcHRzLmxvb3ApKVxyXG4gICAgICApIHtcclxuICAgICAgICBsZWZ0ID0gbGVmdCAtIE1hdGgucG93KC1zZWxmLmRpc3RhbmNlWCwgMC44KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBsZWZ0ID0gbGVmdCArIHNlbGYuZGlzdGFuY2VYO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgc2VsZi5zbGlkZXJMYXN0UG9zID0ge1xyXG4gICAgICB0b3A6IHN3aXBpbmcgPT0gXCJ4XCIgPyAwIDogc2VsZi5zbGlkZXJTdGFydFBvcy50b3AgKyBzZWxmLmRpc3RhbmNlWSxcclxuICAgICAgbGVmdDogbGVmdFxyXG4gICAgfTtcclxuXHJcbiAgICBpZiAoc2VsZi5yZXF1ZXN0SWQpIHtcclxuICAgICAgY2FuY2VsQUZyYW1lKHNlbGYucmVxdWVzdElkKTtcclxuXHJcbiAgICAgIHNlbGYucmVxdWVzdElkID0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICBzZWxmLnJlcXVlc3RJZCA9IHJlcXVlc3RBRnJhbWUoZnVuY3Rpb24gKCkge1xyXG4gICAgICBpZiAoc2VsZi5zbGlkZXJMYXN0UG9zKSB7XHJcbiAgICAgICAgJC5lYWNoKHNlbGYuaW5zdGFuY2Uuc2xpZGVzLCBmdW5jdGlvbiAoaW5kZXgsIHNsaWRlKSB7XHJcbiAgICAgICAgICB2YXIgcG9zID0gc2xpZGUucG9zIC0gc2VsZi5pbnN0YW5jZS5jdXJyUG9zO1xyXG5cclxuICAgICAgICAgICQuZmFuY3lib3guc2V0VHJhbnNsYXRlKHNsaWRlLiRzbGlkZSwge1xyXG4gICAgICAgICAgICB0b3A6IHNlbGYuc2xpZGVyTGFzdFBvcy50b3AsXHJcbiAgICAgICAgICAgIGxlZnQ6IHNlbGYuc2xpZGVyTGFzdFBvcy5sZWZ0ICsgcG9zICogc2VsZi5jYW52YXNXaWR0aCArIHBvcyAqIHNsaWRlLm9wdHMuZ3V0dGVyXHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgc2VsZi4kY29udGFpbmVyLmFkZENsYXNzKFwiZmFuY3lib3gtaXMtc2xpZGluZ1wiKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfTtcclxuXHJcbiAgR3Vlc3R1cmVzLnByb3RvdHlwZS5vblBhbiA9IGZ1bmN0aW9uICgpIHtcclxuICAgIHZhciBzZWxmID0gdGhpcztcclxuXHJcbiAgICAvLyBQcmV2ZW50IGFjY2lkZW50YWwgbW92ZW1lbnQgKHNvbWV0aW1lcywgd2hlbiB0YXBwaW5nIGNhc3VhbGx5LCBmaW5nZXIgY2FuIG1vdmUgYSBiaXQpXHJcbiAgICBpZiAoZGlzdGFuY2Uoc2VsZi5uZXdQb2ludHNbMF0sIHNlbGYucmVhbFBvaW50c1swXSkgPCAoJC5mYW5jeWJveC5pc01vYmlsZSA/IDEwIDogNSkpIHtcclxuICAgICAgc2VsZi5zdGFydFBvaW50cyA9IHNlbGYubmV3UG9pbnRzO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgc2VsZi5jYW5UYXAgPSBmYWxzZTtcclxuXHJcbiAgICBzZWxmLmNvbnRlbnRMYXN0UG9zID0gc2VsZi5saW1pdE1vdmVtZW50KCk7XHJcblxyXG4gICAgaWYgKHNlbGYucmVxdWVzdElkKSB7XHJcbiAgICAgIGNhbmNlbEFGcmFtZShzZWxmLnJlcXVlc3RJZCk7XHJcbiAgICB9XHJcblxyXG4gICAgc2VsZi5yZXF1ZXN0SWQgPSByZXF1ZXN0QUZyYW1lKGZ1bmN0aW9uICgpIHtcclxuICAgICAgJC5mYW5jeWJveC5zZXRUcmFuc2xhdGUoc2VsZi4kY29udGVudCwgc2VsZi5jb250ZW50TGFzdFBvcyk7XHJcbiAgICB9KTtcclxuICB9O1xyXG5cclxuICAvLyBNYWtlIHBhbm5pbmcgc3RpY2t5IHRvIHRoZSBlZGdlc1xyXG4gIEd1ZXN0dXJlcy5wcm90b3R5cGUubGltaXRNb3ZlbWVudCA9IGZ1bmN0aW9uICgpIHtcclxuICAgIHZhciBzZWxmID0gdGhpcztcclxuXHJcbiAgICB2YXIgY2FudmFzV2lkdGggPSBzZWxmLmNhbnZhc1dpZHRoO1xyXG4gICAgdmFyIGNhbnZhc0hlaWdodCA9IHNlbGYuY2FudmFzSGVpZ2h0O1xyXG5cclxuICAgIHZhciBkaXN0YW5jZVggPSBzZWxmLmRpc3RhbmNlWDtcclxuICAgIHZhciBkaXN0YW5jZVkgPSBzZWxmLmRpc3RhbmNlWTtcclxuXHJcbiAgICB2YXIgY29udGVudFN0YXJ0UG9zID0gc2VsZi5jb250ZW50U3RhcnRQb3M7XHJcblxyXG4gICAgdmFyIGN1cnJlbnRPZmZzZXRYID0gY29udGVudFN0YXJ0UG9zLmxlZnQ7XHJcbiAgICB2YXIgY3VycmVudE9mZnNldFkgPSBjb250ZW50U3RhcnRQb3MudG9wO1xyXG5cclxuICAgIHZhciBjdXJyZW50V2lkdGggPSBjb250ZW50U3RhcnRQb3Mud2lkdGg7XHJcbiAgICB2YXIgY3VycmVudEhlaWdodCA9IGNvbnRlbnRTdGFydFBvcy5oZWlnaHQ7XHJcblxyXG4gICAgdmFyIG1pblRyYW5zbGF0ZVgsIG1pblRyYW5zbGF0ZVksIG1heFRyYW5zbGF0ZVgsIG1heFRyYW5zbGF0ZVksIG5ld09mZnNldFgsIG5ld09mZnNldFk7XHJcblxyXG4gICAgaWYgKGN1cnJlbnRXaWR0aCA+IGNhbnZhc1dpZHRoKSB7XHJcbiAgICAgIG5ld09mZnNldFggPSBjdXJyZW50T2Zmc2V0WCArIGRpc3RhbmNlWDtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIG5ld09mZnNldFggPSBjdXJyZW50T2Zmc2V0WDtcclxuICAgIH1cclxuXHJcbiAgICBuZXdPZmZzZXRZID0gY3VycmVudE9mZnNldFkgKyBkaXN0YW5jZVk7XHJcblxyXG4gICAgLy8gU2xvdyBkb3duIHByb3BvcnRpb25hbGx5IHRvIHRyYXZlbGVkIGRpc3RhbmNlXHJcbiAgICBtaW5UcmFuc2xhdGVYID0gTWF0aC5tYXgoMCwgY2FudmFzV2lkdGggKiAwLjUgLSBjdXJyZW50V2lkdGggKiAwLjUpO1xyXG4gICAgbWluVHJhbnNsYXRlWSA9IE1hdGgubWF4KDAsIGNhbnZhc0hlaWdodCAqIDAuNSAtIGN1cnJlbnRIZWlnaHQgKiAwLjUpO1xyXG5cclxuICAgIG1heFRyYW5zbGF0ZVggPSBNYXRoLm1pbihjYW52YXNXaWR0aCAtIGN1cnJlbnRXaWR0aCwgY2FudmFzV2lkdGggKiAwLjUgLSBjdXJyZW50V2lkdGggKiAwLjUpO1xyXG4gICAgbWF4VHJhbnNsYXRlWSA9IE1hdGgubWluKGNhbnZhc0hlaWdodCAtIGN1cnJlbnRIZWlnaHQsIGNhbnZhc0hlaWdodCAqIDAuNSAtIGN1cnJlbnRIZWlnaHQgKiAwLjUpO1xyXG5cclxuICAgIC8vICAgLT5cclxuICAgIGlmIChkaXN0YW5jZVggPiAwICYmIG5ld09mZnNldFggPiBtaW5UcmFuc2xhdGVYKSB7XHJcbiAgICAgIG5ld09mZnNldFggPSBtaW5UcmFuc2xhdGVYIC0gMSArIE1hdGgucG93KC1taW5UcmFuc2xhdGVYICsgY3VycmVudE9mZnNldFggKyBkaXN0YW5jZVgsIDAuOCkgfHwgMDtcclxuICAgIH1cclxuXHJcbiAgICAvLyAgICA8LVxyXG4gICAgaWYgKGRpc3RhbmNlWCA8IDAgJiYgbmV3T2Zmc2V0WCA8IG1heFRyYW5zbGF0ZVgpIHtcclxuICAgICAgbmV3T2Zmc2V0WCA9IG1heFRyYW5zbGF0ZVggKyAxIC0gTWF0aC5wb3cobWF4VHJhbnNsYXRlWCAtIGN1cnJlbnRPZmZzZXRYIC0gZGlzdGFuY2VYLCAwLjgpIHx8IDA7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gICBcXC9cclxuICAgIGlmIChkaXN0YW5jZVkgPiAwICYmIG5ld09mZnNldFkgPiBtaW5UcmFuc2xhdGVZKSB7XHJcbiAgICAgIG5ld09mZnNldFkgPSBtaW5UcmFuc2xhdGVZIC0gMSArIE1hdGgucG93KC1taW5UcmFuc2xhdGVZICsgY3VycmVudE9mZnNldFkgKyBkaXN0YW5jZVksIDAuOCkgfHwgMDtcclxuICAgIH1cclxuXHJcbiAgICAvLyAgIC9cXFxyXG4gICAgaWYgKGRpc3RhbmNlWSA8IDAgJiYgbmV3T2Zmc2V0WSA8IG1heFRyYW5zbGF0ZVkpIHtcclxuICAgICAgbmV3T2Zmc2V0WSA9IG1heFRyYW5zbGF0ZVkgKyAxIC0gTWF0aC5wb3cobWF4VHJhbnNsYXRlWSAtIGN1cnJlbnRPZmZzZXRZIC0gZGlzdGFuY2VZLCAwLjgpIHx8IDA7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgdG9wOiBuZXdPZmZzZXRZLFxyXG4gICAgICBsZWZ0OiBuZXdPZmZzZXRYXHJcbiAgICB9O1xyXG4gIH07XHJcblxyXG4gIEd1ZXN0dXJlcy5wcm90b3R5cGUubGltaXRQb3NpdGlvbiA9IGZ1bmN0aW9uIChuZXdPZmZzZXRYLCBuZXdPZmZzZXRZLCBuZXdXaWR0aCwgbmV3SGVpZ2h0KSB7XHJcbiAgICB2YXIgc2VsZiA9IHRoaXM7XHJcblxyXG4gICAgdmFyIGNhbnZhc1dpZHRoID0gc2VsZi5jYW52YXNXaWR0aDtcclxuICAgIHZhciBjYW52YXNIZWlnaHQgPSBzZWxmLmNhbnZhc0hlaWdodDtcclxuXHJcbiAgICBpZiAobmV3V2lkdGggPiBjYW52YXNXaWR0aCkge1xyXG4gICAgICBuZXdPZmZzZXRYID0gbmV3T2Zmc2V0WCA+IDAgPyAwIDogbmV3T2Zmc2V0WDtcclxuICAgICAgbmV3T2Zmc2V0WCA9IG5ld09mZnNldFggPCBjYW52YXNXaWR0aCAtIG5ld1dpZHRoID8gY2FudmFzV2lkdGggLSBuZXdXaWR0aCA6IG5ld09mZnNldFg7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBDZW50ZXIgaG9yaXpvbnRhbGx5XHJcbiAgICAgIG5ld09mZnNldFggPSBNYXRoLm1heCgwLCBjYW52YXNXaWR0aCAvIDIgLSBuZXdXaWR0aCAvIDIpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChuZXdIZWlnaHQgPiBjYW52YXNIZWlnaHQpIHtcclxuICAgICAgbmV3T2Zmc2V0WSA9IG5ld09mZnNldFkgPiAwID8gMCA6IG5ld09mZnNldFk7XHJcbiAgICAgIG5ld09mZnNldFkgPSBuZXdPZmZzZXRZIDwgY2FudmFzSGVpZ2h0IC0gbmV3SGVpZ2h0ID8gY2FudmFzSGVpZ2h0IC0gbmV3SGVpZ2h0IDogbmV3T2Zmc2V0WTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENlbnRlciB2ZXJ0aWNhbGx5XHJcbiAgICAgIG5ld09mZnNldFkgPSBNYXRoLm1heCgwLCBjYW52YXNIZWlnaHQgLyAyIC0gbmV3SGVpZ2h0IC8gMik7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgdG9wOiBuZXdPZmZzZXRZLFxyXG4gICAgICBsZWZ0OiBuZXdPZmZzZXRYXHJcbiAgICB9O1xyXG4gIH07XHJcblxyXG4gIEd1ZXN0dXJlcy5wcm90b3R5cGUub25ab29tID0gZnVuY3Rpb24gKCkge1xyXG4gICAgdmFyIHNlbGYgPSB0aGlzO1xyXG5cclxuICAgIC8vIENhbGN1bGF0ZSBjdXJyZW50IGRpc3RhbmNlIGJldHdlZW4gcG9pbnRzIHRvIGdldCBwaW5jaCByYXRpbyBhbmQgbmV3IHdpZHRoIGFuZCBoZWlnaHRcclxuICAgIHZhciBjb250ZW50U3RhcnRQb3MgPSBzZWxmLmNvbnRlbnRTdGFydFBvcztcclxuXHJcbiAgICB2YXIgY3VycmVudFdpZHRoID0gY29udGVudFN0YXJ0UG9zLndpZHRoO1xyXG4gICAgdmFyIGN1cnJlbnRIZWlnaHQgPSBjb250ZW50U3RhcnRQb3MuaGVpZ2h0O1xyXG5cclxuICAgIHZhciBjdXJyZW50T2Zmc2V0WCA9IGNvbnRlbnRTdGFydFBvcy5sZWZ0O1xyXG4gICAgdmFyIGN1cnJlbnRPZmZzZXRZID0gY29udGVudFN0YXJ0UG9zLnRvcDtcclxuXHJcbiAgICB2YXIgZW5kRGlzdGFuY2VCZXR3ZWVuRmluZ2VycyA9IGRpc3RhbmNlKHNlbGYubmV3UG9pbnRzWzBdLCBzZWxmLm5ld1BvaW50c1sxXSk7XHJcblxyXG4gICAgdmFyIHBpbmNoUmF0aW8gPSBlbmREaXN0YW5jZUJldHdlZW5GaW5nZXJzIC8gc2VsZi5zdGFydERpc3RhbmNlQmV0d2VlbkZpbmdlcnM7XHJcblxyXG4gICAgdmFyIG5ld1dpZHRoID0gTWF0aC5mbG9vcihjdXJyZW50V2lkdGggKiBwaW5jaFJhdGlvKTtcclxuICAgIHZhciBuZXdIZWlnaHQgPSBNYXRoLmZsb29yKGN1cnJlbnRIZWlnaHQgKiBwaW5jaFJhdGlvKTtcclxuXHJcbiAgICAvLyBUaGlzIGlzIHRoZSB0cmFuc2xhdGlvbiBkdWUgdG8gcGluY2gtem9vbWluZ1xyXG4gICAgdmFyIHRyYW5zbGF0ZUZyb21ab29taW5nWCA9IChjdXJyZW50V2lkdGggLSBuZXdXaWR0aCkgKiBzZWxmLnBlcmNlbnRhZ2VPZkltYWdlQXRQaW5jaFBvaW50WDtcclxuICAgIHZhciB0cmFuc2xhdGVGcm9tWm9vbWluZ1kgPSAoY3VycmVudEhlaWdodCAtIG5ld0hlaWdodCkgKiBzZWxmLnBlcmNlbnRhZ2VPZkltYWdlQXRQaW5jaFBvaW50WTtcclxuXHJcbiAgICAvLyBQb2ludCBiZXR3ZWVuIHRoZSB0d28gdG91Y2hlc1xyXG4gICAgdmFyIGNlbnRlclBvaW50RW5kWCA9IChzZWxmLm5ld1BvaW50c1swXS54ICsgc2VsZi5uZXdQb2ludHNbMV0ueCkgLyAyIC0gJCh3aW5kb3cpLnNjcm9sbExlZnQoKTtcclxuICAgIHZhciBjZW50ZXJQb2ludEVuZFkgPSAoc2VsZi5uZXdQb2ludHNbMF0ueSArIHNlbGYubmV3UG9pbnRzWzFdLnkpIC8gMiAtICQod2luZG93KS5zY3JvbGxUb3AoKTtcclxuXHJcbiAgICAvLyBBbmQgdGhpcyBpcyB0aGUgdHJhbnNsYXRpb24gZHVlIHRvIHRyYW5zbGF0aW9uIG9mIHRoZSBjZW50ZXJwb2ludFxyXG4gICAgLy8gYmV0d2VlbiB0aGUgdHdvIGZpbmdlcnNcclxuICAgIHZhciB0cmFuc2xhdGVGcm9tVHJhbnNsYXRpbmdYID0gY2VudGVyUG9pbnRFbmRYIC0gc2VsZi5jZW50ZXJQb2ludFN0YXJ0WDtcclxuICAgIHZhciB0cmFuc2xhdGVGcm9tVHJhbnNsYXRpbmdZID0gY2VudGVyUG9pbnRFbmRZIC0gc2VsZi5jZW50ZXJQb2ludFN0YXJ0WTtcclxuXHJcbiAgICAvLyBUaGUgbmV3IG9mZnNldCBpcyB0aGUgb2xkL2N1cnJlbnQgb25lIHBsdXMgdGhlIHRvdGFsIHRyYW5zbGF0aW9uXHJcbiAgICB2YXIgbmV3T2Zmc2V0WCA9IGN1cnJlbnRPZmZzZXRYICsgKHRyYW5zbGF0ZUZyb21ab29taW5nWCArIHRyYW5zbGF0ZUZyb21UcmFuc2xhdGluZ1gpO1xyXG4gICAgdmFyIG5ld09mZnNldFkgPSBjdXJyZW50T2Zmc2V0WSArICh0cmFuc2xhdGVGcm9tWm9vbWluZ1kgKyB0cmFuc2xhdGVGcm9tVHJhbnNsYXRpbmdZKTtcclxuXHJcbiAgICB2YXIgbmV3UG9zID0ge1xyXG4gICAgICB0b3A6IG5ld09mZnNldFksXHJcbiAgICAgIGxlZnQ6IG5ld09mZnNldFgsXHJcbiAgICAgIHNjYWxlWDogcGluY2hSYXRpbyxcclxuICAgICAgc2NhbGVZOiBwaW5jaFJhdGlvXHJcbiAgICB9O1xyXG5cclxuICAgIHNlbGYuY2FuVGFwID0gZmFsc2U7XHJcblxyXG4gICAgc2VsZi5uZXdXaWR0aCA9IG5ld1dpZHRoO1xyXG4gICAgc2VsZi5uZXdIZWlnaHQgPSBuZXdIZWlnaHQ7XHJcblxyXG4gICAgc2VsZi5jb250ZW50TGFzdFBvcyA9IG5ld1BvcztcclxuXHJcbiAgICBpZiAoc2VsZi5yZXF1ZXN0SWQpIHtcclxuICAgICAgY2FuY2VsQUZyYW1lKHNlbGYucmVxdWVzdElkKTtcclxuICAgIH1cclxuXHJcbiAgICBzZWxmLnJlcXVlc3RJZCA9IHJlcXVlc3RBRnJhbWUoZnVuY3Rpb24gKCkge1xyXG4gICAgICAkLmZhbmN5Ym94LnNldFRyYW5zbGF0ZShzZWxmLiRjb250ZW50LCBzZWxmLmNvbnRlbnRMYXN0UG9zKTtcclxuICAgIH0pO1xyXG4gIH07XHJcblxyXG4gIEd1ZXN0dXJlcy5wcm90b3R5cGUub250b3VjaGVuZCA9IGZ1bmN0aW9uIChlKSB7XHJcbiAgICB2YXIgc2VsZiA9IHRoaXM7XHJcblxyXG4gICAgdmFyIHN3aXBpbmcgPSBzZWxmLmlzU3dpcGluZztcclxuICAgIHZhciBwYW5uaW5nID0gc2VsZi5pc1Bhbm5pbmc7XHJcbiAgICB2YXIgem9vbWluZyA9IHNlbGYuaXNab29taW5nO1xyXG4gICAgdmFyIHNjcm9sbGluZyA9IHNlbGYuaXNTY3JvbGxpbmc7XHJcblxyXG4gICAgc2VsZi5lbmRQb2ludHMgPSBnZXRQb2ludGVyWFkoZSk7XHJcbiAgICBzZWxmLmRNcyA9IE1hdGgubWF4KG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gc2VsZi5zdGFydFRpbWUsIDEpO1xyXG5cclxuICAgIHNlbGYuJGNvbnRhaW5lci5yZW1vdmVDbGFzcyhcImZhbmN5Ym94LWlzLWdyYWJiaW5nXCIpO1xyXG5cclxuICAgICQoZG9jdW1lbnQpLm9mZihcIi5mYi50b3VjaFwiKTtcclxuXHJcbiAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKFwic2Nyb2xsXCIsIHNlbGYub25zY3JvbGwsIHRydWUpO1xyXG5cclxuICAgIGlmIChzZWxmLnJlcXVlc3RJZCkge1xyXG4gICAgICBjYW5jZWxBRnJhbWUoc2VsZi5yZXF1ZXN0SWQpO1xyXG5cclxuICAgICAgc2VsZi5yZXF1ZXN0SWQgPSBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIHNlbGYuaXNTd2lwaW5nID0gZmFsc2U7XHJcbiAgICBzZWxmLmlzUGFubmluZyA9IGZhbHNlO1xyXG4gICAgc2VsZi5pc1pvb21pbmcgPSBmYWxzZTtcclxuICAgIHNlbGYuaXNTY3JvbGxpbmcgPSBmYWxzZTtcclxuXHJcbiAgICBzZWxmLmluc3RhbmNlLmlzRHJhZ2dpbmcgPSBmYWxzZTtcclxuXHJcbiAgICBpZiAoc2VsZi5jYW5UYXApIHtcclxuICAgICAgcmV0dXJuIHNlbGYub25UYXAoZSk7XHJcbiAgICB9XHJcblxyXG4gICAgc2VsZi5zcGVlZCA9IDEwMDtcclxuXHJcbiAgICAvLyBTcGVlZCBpbiBweC9tc1xyXG4gICAgc2VsZi52ZWxvY2l0eVggPSAoc2VsZi5kaXN0YW5jZVggLyBzZWxmLmRNcykgKiAwLjU7XHJcbiAgICBzZWxmLnZlbG9jaXR5WSA9IChzZWxmLmRpc3RhbmNlWSAvIHNlbGYuZE1zKSAqIDAuNTtcclxuXHJcbiAgICBpZiAocGFubmluZykge1xyXG4gICAgICBzZWxmLmVuZFBhbm5pbmcoKTtcclxuICAgIH0gZWxzZSBpZiAoem9vbWluZykge1xyXG4gICAgICBzZWxmLmVuZFpvb21pbmcoKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHNlbGYuZW5kU3dpcGluZyhzd2lwaW5nLCBzY3JvbGxpbmcpO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybjtcclxuICB9O1xyXG5cclxuICBHdWVzdHVyZXMucHJvdG90eXBlLmVuZFN3aXBpbmcgPSBmdW5jdGlvbiAoc3dpcGluZywgc2Nyb2xsaW5nKSB7XHJcbiAgICB2YXIgc2VsZiA9IHRoaXMsXHJcbiAgICAgIHJldCA9IGZhbHNlLFxyXG4gICAgICBsZW4gPSBzZWxmLmluc3RhbmNlLmdyb3VwLmxlbmd0aCxcclxuICAgICAgZGlzdGFuY2VYID0gTWF0aC5hYnMoc2VsZi5kaXN0YW5jZVgpLFxyXG4gICAgICBjYW5BZHZhbmNlID0gc3dpcGluZyA9PSBcInhcIiAmJiBsZW4gPiAxICYmICgoc2VsZi5kTXMgPiAxMzAgJiYgZGlzdGFuY2VYID4gMTApIHx8IGRpc3RhbmNlWCA+IDUwKSxcclxuICAgICAgc3BlZWRYID0gMzAwO1xyXG5cclxuICAgIHNlbGYuc2xpZGVyTGFzdFBvcyA9IG51bGw7XHJcblxyXG4gICAgLy8gQ2xvc2UgaWYgc3dpcGVkIHZlcnRpY2FsbHkgLyBuYXZpZ2F0ZSBpZiBob3Jpem9udGFsbHlcclxuICAgIGlmIChzd2lwaW5nID09IFwieVwiICYmICFzY3JvbGxpbmcgJiYgTWF0aC5hYnMoc2VsZi5kaXN0YW5jZVkpID4gNTApIHtcclxuICAgICAgLy8gQ29udGludWUgdmVydGljYWwgbW92ZW1lbnRcclxuICAgICAgJC5mYW5jeWJveC5hbmltYXRlKFxyXG4gICAgICAgIHNlbGYuaW5zdGFuY2UuY3VycmVudC4kc2xpZGUsIHtcclxuICAgICAgICAgIHRvcDogc2VsZi5zbGlkZXJTdGFydFBvcy50b3AgKyBzZWxmLmRpc3RhbmNlWSArIHNlbGYudmVsb2NpdHlZICogMTUwLFxyXG4gICAgICAgICAgb3BhY2l0eTogMFxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgMjAwXHJcbiAgICAgICk7XHJcbiAgICAgIHJldCA9IHNlbGYuaW5zdGFuY2UuY2xvc2UodHJ1ZSwgMjUwKTtcclxuICAgIH0gZWxzZSBpZiAoY2FuQWR2YW5jZSAmJiBzZWxmLmRpc3RhbmNlWCA+IDApIHtcclxuICAgICAgcmV0ID0gc2VsZi5pbnN0YW5jZS5wcmV2aW91cyhzcGVlZFgpO1xyXG4gICAgfSBlbHNlIGlmIChjYW5BZHZhbmNlICYmIHNlbGYuZGlzdGFuY2VYIDwgMCkge1xyXG4gICAgICByZXQgPSBzZWxmLmluc3RhbmNlLm5leHQoc3BlZWRYKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAocmV0ID09PSBmYWxzZSAmJiAoc3dpcGluZyA9PSBcInhcIiB8fCBzd2lwaW5nID09IFwieVwiKSkge1xyXG4gICAgICBzZWxmLmluc3RhbmNlLmNlbnRlclNsaWRlKDIwMCk7XHJcbiAgICB9XHJcblxyXG4gICAgc2VsZi4kY29udGFpbmVyLnJlbW92ZUNsYXNzKFwiZmFuY3lib3gtaXMtc2xpZGluZ1wiKTtcclxuICB9O1xyXG5cclxuICAvLyBMaW1pdCBwYW5uaW5nIGZyb20gZWRnZXNcclxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT1cclxuICBHdWVzdHVyZXMucHJvdG90eXBlLmVuZFBhbm5pbmcgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICB2YXIgc2VsZiA9IHRoaXMsXHJcbiAgICAgIG5ld09mZnNldFgsXHJcbiAgICAgIG5ld09mZnNldFksXHJcbiAgICAgIG5ld1BvcztcclxuXHJcbiAgICBpZiAoIXNlbGYuY29udGVudExhc3RQb3MpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChzZWxmLm9wdHMubW9tZW50dW0gPT09IGZhbHNlIHx8IHNlbGYuZE1zID4gMzUwKSB7XHJcbiAgICAgIG5ld09mZnNldFggPSBzZWxmLmNvbnRlbnRMYXN0UG9zLmxlZnQ7XHJcbiAgICAgIG5ld09mZnNldFkgPSBzZWxmLmNvbnRlbnRMYXN0UG9zLnRvcDtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENvbnRpbnVlIG1vdmVtZW50XHJcbiAgICAgIG5ld09mZnNldFggPSBzZWxmLmNvbnRlbnRMYXN0UG9zLmxlZnQgKyBzZWxmLnZlbG9jaXR5WCAqIDUwMDtcclxuICAgICAgbmV3T2Zmc2V0WSA9IHNlbGYuY29udGVudExhc3RQb3MudG9wICsgc2VsZi52ZWxvY2l0eVkgKiA1MDA7XHJcbiAgICB9XHJcblxyXG4gICAgbmV3UG9zID0gc2VsZi5saW1pdFBvc2l0aW9uKG5ld09mZnNldFgsIG5ld09mZnNldFksIHNlbGYuY29udGVudFN0YXJ0UG9zLndpZHRoLCBzZWxmLmNvbnRlbnRTdGFydFBvcy5oZWlnaHQpO1xyXG5cclxuICAgIG5ld1Bvcy53aWR0aCA9IHNlbGYuY29udGVudFN0YXJ0UG9zLndpZHRoO1xyXG4gICAgbmV3UG9zLmhlaWdodCA9IHNlbGYuY29udGVudFN0YXJ0UG9zLmhlaWdodDtcclxuXHJcbiAgICAkLmZhbmN5Ym94LmFuaW1hdGUoc2VsZi4kY29udGVudCwgbmV3UG9zLCAzNjYpO1xyXG4gIH07XHJcblxyXG4gIEd1ZXN0dXJlcy5wcm90b3R5cGUuZW5kWm9vbWluZyA9IGZ1bmN0aW9uICgpIHtcclxuICAgIHZhciBzZWxmID0gdGhpcztcclxuXHJcbiAgICB2YXIgY3VycmVudCA9IHNlbGYuaW5zdGFuY2UuY3VycmVudDtcclxuXHJcbiAgICB2YXIgbmV3T2Zmc2V0WCwgbmV3T2Zmc2V0WSwgbmV3UG9zLCByZXNldDtcclxuXHJcbiAgICB2YXIgbmV3V2lkdGggPSBzZWxmLm5ld1dpZHRoO1xyXG4gICAgdmFyIG5ld0hlaWdodCA9IHNlbGYubmV3SGVpZ2h0O1xyXG5cclxuICAgIGlmICghc2VsZi5jb250ZW50TGFzdFBvcykge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgbmV3T2Zmc2V0WCA9IHNlbGYuY29udGVudExhc3RQb3MubGVmdDtcclxuICAgIG5ld09mZnNldFkgPSBzZWxmLmNvbnRlbnRMYXN0UG9zLnRvcDtcclxuXHJcbiAgICByZXNldCA9IHtcclxuICAgICAgdG9wOiBuZXdPZmZzZXRZLFxyXG4gICAgICBsZWZ0OiBuZXdPZmZzZXRYLFxyXG4gICAgICB3aWR0aDogbmV3V2lkdGgsXHJcbiAgICAgIGhlaWdodDogbmV3SGVpZ2h0LFxyXG4gICAgICBzY2FsZVg6IDEsXHJcbiAgICAgIHNjYWxlWTogMVxyXG4gICAgfTtcclxuXHJcbiAgICAvLyBSZXNldCBzY2FsZXgvc2NhbGVZIHZhbHVlczsgdGhpcyBoZWxwcyBmb3IgcGVyZm9tYW5jZSBhbmQgZG9lcyBub3QgYnJlYWsgYW5pbWF0aW9uXHJcbiAgICAkLmZhbmN5Ym94LnNldFRyYW5zbGF0ZShzZWxmLiRjb250ZW50LCByZXNldCk7XHJcblxyXG4gICAgaWYgKG5ld1dpZHRoIDwgc2VsZi5jYW52YXNXaWR0aCAmJiBuZXdIZWlnaHQgPCBzZWxmLmNhbnZhc0hlaWdodCkge1xyXG4gICAgICBzZWxmLmluc3RhbmNlLnNjYWxlVG9GaXQoMTUwKTtcclxuICAgIH0gZWxzZSBpZiAobmV3V2lkdGggPiBjdXJyZW50LndpZHRoIHx8IG5ld0hlaWdodCA+IGN1cnJlbnQuaGVpZ2h0KSB7XHJcbiAgICAgIHNlbGYuaW5zdGFuY2Uuc2NhbGVUb0FjdHVhbChzZWxmLmNlbnRlclBvaW50U3RhcnRYLCBzZWxmLmNlbnRlclBvaW50U3RhcnRZLCAxNTApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbmV3UG9zID0gc2VsZi5saW1pdFBvc2l0aW9uKG5ld09mZnNldFgsIG5ld09mZnNldFksIG5ld1dpZHRoLCBuZXdIZWlnaHQpO1xyXG5cclxuICAgICAgJC5mYW5jeWJveC5hbmltYXRlKHNlbGYuJGNvbnRlbnQsIG5ld1BvcywgMTUwKTtcclxuICAgIH1cclxuICB9O1xyXG5cclxuICBHdWVzdHVyZXMucHJvdG90eXBlLm9uVGFwID0gZnVuY3Rpb24gKGUpIHtcclxuICAgIHZhciBzZWxmID0gdGhpcztcclxuICAgIHZhciAkdGFyZ2V0ID0gJChlLnRhcmdldCk7XHJcblxyXG4gICAgdmFyIGluc3RhbmNlID0gc2VsZi5pbnN0YW5jZTtcclxuICAgIHZhciBjdXJyZW50ID0gaW5zdGFuY2UuY3VycmVudDtcclxuXHJcbiAgICB2YXIgZW5kUG9pbnRzID0gKGUgJiYgZ2V0UG9pbnRlclhZKGUpKSB8fCBzZWxmLnN0YXJ0UG9pbnRzO1xyXG5cclxuICAgIHZhciB0YXBYID0gZW5kUG9pbnRzWzBdID8gZW5kUG9pbnRzWzBdLnggLSAkKHdpbmRvdykuc2Nyb2xsTGVmdCgpIC0gc2VsZi5zdGFnZVBvcy5sZWZ0IDogMDtcclxuICAgIHZhciB0YXBZID0gZW5kUG9pbnRzWzBdID8gZW5kUG9pbnRzWzBdLnkgLSAkKHdpbmRvdykuc2Nyb2xsVG9wKCkgLSBzZWxmLnN0YWdlUG9zLnRvcCA6IDA7XHJcblxyXG4gICAgdmFyIHdoZXJlO1xyXG5cclxuICAgIHZhciBwcm9jZXNzID0gZnVuY3Rpb24gKHByZWZpeCkge1xyXG4gICAgICB2YXIgYWN0aW9uID0gY3VycmVudC5vcHRzW3ByZWZpeF07XHJcblxyXG4gICAgICBpZiAoJC5pc0Z1bmN0aW9uKGFjdGlvbikpIHtcclxuICAgICAgICBhY3Rpb24gPSBhY3Rpb24uYXBwbHkoaW5zdGFuY2UsIFtjdXJyZW50LCBlXSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICghYWN0aW9uKSB7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBzd2l0Y2ggKGFjdGlvbikge1xyXG4gICAgICAgIGNhc2UgXCJjbG9zZVwiOlxyXG4gICAgICAgICAgaW5zdGFuY2UuY2xvc2Uoc2VsZi5zdGFydEV2ZW50KTtcclxuXHJcbiAgICAgICAgICBicmVhaztcclxuXHJcbiAgICAgICAgY2FzZSBcInRvZ2dsZUNvbnRyb2xzXCI6XHJcbiAgICAgICAgICBpbnN0YW5jZS50b2dnbGVDb250cm9scygpO1xyXG5cclxuICAgICAgICAgIGJyZWFrO1xyXG5cclxuICAgICAgICBjYXNlIFwibmV4dFwiOlxyXG4gICAgICAgICAgaW5zdGFuY2UubmV4dCgpO1xyXG5cclxuICAgICAgICAgIGJyZWFrO1xyXG5cclxuICAgICAgICBjYXNlIFwibmV4dE9yQ2xvc2VcIjpcclxuICAgICAgICAgIGlmIChpbnN0YW5jZS5ncm91cC5sZW5ndGggPiAxKSB7XHJcbiAgICAgICAgICAgIGluc3RhbmNlLm5leHQoKTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGluc3RhbmNlLmNsb3NlKHNlbGYuc3RhcnRFdmVudCk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgYnJlYWs7XHJcblxyXG4gICAgICAgIGNhc2UgXCJ6b29tXCI6XHJcbiAgICAgICAgICBpZiAoY3VycmVudC50eXBlID09IFwiaW1hZ2VcIiAmJiAoY3VycmVudC5pc0xvYWRlZCB8fCBjdXJyZW50LiRnaG9zdCkpIHtcclxuICAgICAgICAgICAgaWYgKGluc3RhbmNlLmNhblBhbigpKSB7XHJcbiAgICAgICAgICAgICAgaW5zdGFuY2Uuc2NhbGVUb0ZpdCgpO1xyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGluc3RhbmNlLmlzU2NhbGVkRG93bigpKSB7XHJcbiAgICAgICAgICAgICAgaW5zdGFuY2Uuc2NhbGVUb0FjdHVhbCh0YXBYLCB0YXBZKTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChpbnN0YW5jZS5ncm91cC5sZW5ndGggPCAyKSB7XHJcbiAgICAgICAgICAgICAgaW5zdGFuY2UuY2xvc2Uoc2VsZi5zdGFydEV2ZW50KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIC8vIElnbm9yZSByaWdodCBjbGlja1xyXG4gICAgaWYgKGUub3JpZ2luYWxFdmVudCAmJiBlLm9yaWdpbmFsRXZlbnQuYnV0dG9uID09IDIpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNraXAgaWYgY2xpY2tlZCBvbiB0aGUgc2Nyb2xsYmFyXHJcbiAgICBpZiAoISR0YXJnZXQuaXMoXCJpbWdcIikgJiYgdGFwWCA+ICR0YXJnZXRbMF0uY2xpZW50V2lkdGggKyAkdGFyZ2V0Lm9mZnNldCgpLmxlZnQpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIHdoZXJlIGlzIGNsaWNrZWRcclxuICAgIGlmICgkdGFyZ2V0LmlzKFwiLmZhbmN5Ym94LWJnLC5mYW5jeWJveC1pbm5lciwuZmFuY3lib3gtb3V0ZXIsLmZhbmN5Ym94LWNvbnRhaW5lclwiKSkge1xyXG4gICAgICB3aGVyZSA9IFwiT3V0c2lkZVwiO1xyXG4gICAgfSBlbHNlIGlmICgkdGFyZ2V0LmlzKFwiLmZhbmN5Ym94LXNsaWRlXCIpKSB7XHJcbiAgICAgIHdoZXJlID0gXCJTbGlkZVwiO1xyXG4gICAgfSBlbHNlIGlmIChcclxuICAgICAgaW5zdGFuY2UuY3VycmVudC4kY29udGVudCAmJlxyXG4gICAgICBpbnN0YW5jZS5jdXJyZW50LiRjb250ZW50XHJcbiAgICAgIC5maW5kKCR0YXJnZXQpXHJcbiAgICAgIC5hZGRCYWNrKClcclxuICAgICAgLmZpbHRlcigkdGFyZ2V0KS5sZW5ndGhcclxuICAgICkge1xyXG4gICAgICB3aGVyZSA9IFwiQ29udGVudFwiO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoaXMgaXMgYSBkb3VibGUgdGFwXHJcbiAgICBpZiAoc2VsZi50YXBwZWQpIHtcclxuICAgICAgLy8gU3RvcCBwcmV2aW91c2x5IGNyZWF0ZWQgc2luZ2xlIHRhcFxyXG4gICAgICBjbGVhclRpbWVvdXQoc2VsZi50YXBwZWQpO1xyXG4gICAgICBzZWxmLnRhcHBlZCA9IG51bGw7XHJcblxyXG4gICAgICAvLyBTa2lwIGlmIGRpc3RhbmNlIGJldHdlZW4gdGFwcyBpcyB0b28gYmlnXHJcbiAgICAgIGlmIChNYXRoLmFicyh0YXBYIC0gc2VsZi50YXBYKSA+IDUwIHx8IE1hdGguYWJzKHRhcFkgLSBzZWxmLnRhcFkpID4gNTApIHtcclxuICAgICAgICByZXR1cm4gdGhpcztcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gT0ssIG5vdyB3ZSBhc3N1bWUgdGhhdCB0aGlzIGlzIGEgZG91YmxlLXRhcFxyXG4gICAgICBwcm9jZXNzKFwiZGJsY2xpY2tcIiArIHdoZXJlKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIFNpbmdsZSB0YXAgd2lsbCBiZSBwcm9jZXNzZWQgaWYgdXNlciBoYXMgbm90IGNsaWNrZWQgc2Vjb25kIHRpbWUgd2l0aGluIDMwMG1zXHJcbiAgICAgIC8vIG9yIHRoZXJlIGlzIG5vIG5lZWQgdG8gd2FpdCBmb3IgZG91YmxlLXRhcFxyXG4gICAgICBzZWxmLnRhcFggPSB0YXBYO1xyXG4gICAgICBzZWxmLnRhcFkgPSB0YXBZO1xyXG5cclxuICAgICAgaWYgKGN1cnJlbnQub3B0c1tcImRibGNsaWNrXCIgKyB3aGVyZV0gJiYgY3VycmVudC5vcHRzW1wiZGJsY2xpY2tcIiArIHdoZXJlXSAhPT0gY3VycmVudC5vcHRzW1wiY2xpY2tcIiArIHdoZXJlXSkge1xyXG4gICAgICAgIHNlbGYudGFwcGVkID0gc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICBzZWxmLnRhcHBlZCA9IG51bGw7XHJcblxyXG4gICAgICAgICAgaWYgKCFpbnN0YW5jZS5pc0FuaW1hdGluZykge1xyXG4gICAgICAgICAgICBwcm9jZXNzKFwiY2xpY2tcIiArIHdoZXJlKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9LCA1MDApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHByb2Nlc3MoXCJjbGlja1wiICsgd2hlcmUpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfTtcclxuXHJcbiAgJChkb2N1bWVudClcclxuICAgIC5vbihcIm9uQWN0aXZhdGUuZmJcIiwgZnVuY3Rpb24gKGUsIGluc3RhbmNlKSB7XHJcbiAgICAgIGlmIChpbnN0YW5jZSAmJiAhaW5zdGFuY2UuR3Vlc3R1cmVzKSB7XHJcbiAgICAgICAgaW5zdGFuY2UuR3Vlc3R1cmVzID0gbmV3IEd1ZXN0dXJlcyhpbnN0YW5jZSk7XHJcbiAgICAgIH1cclxuICAgIH0pXHJcbiAgICAub24oXCJiZWZvcmVDbG9zZS5mYlwiLCBmdW5jdGlvbiAoZSwgaW5zdGFuY2UpIHtcclxuICAgICAgaWYgKGluc3RhbmNlICYmIGluc3RhbmNlLkd1ZXN0dXJlcykge1xyXG4gICAgICAgIGluc3RhbmNlLkd1ZXN0dXJlcy5kZXN0cm95KCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG59KSh3aW5kb3csIGRvY3VtZW50LCBqUXVlcnkpO1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuLy9cclxuLy8gU2xpZGVTaG93XHJcbi8vIEVuYWJsZXMgc2xpZGVzaG93IGZ1bmN0aW9uYWxpdHlcclxuLy9cclxuLy8gRXhhbXBsZSBvZiB1c2FnZTpcclxuLy8gJC5mYW5jeWJveC5nZXRJbnN0YW5jZSgpLlNsaWRlU2hvdy5zdGFydCgpXHJcbi8vXHJcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbihmdW5jdGlvbiAoZG9jdW1lbnQsICQpIHtcclxuICBcInVzZSBzdHJpY3RcIjtcclxuXHJcbiAgJC5leHRlbmQodHJ1ZSwgJC5mYW5jeWJveC5kZWZhdWx0cywge1xyXG4gICAgYnRuVHBsOiB7XHJcbiAgICAgIHNsaWRlU2hvdzogJzxidXR0b24gZGF0YS1mYW5jeWJveC1wbGF5IGNsYXNzPVwiZmFuY3lib3gtYnV0dG9uIGZhbmN5Ym94LWJ1dHRvbi0tcGxheVwiIHRpdGxlPVwie3tQTEFZX1NUQVJUfX1cIj4nICtcclxuICAgICAgICAnPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgdmlld0JveD1cIjAgMCAyNCAyNFwiPjxwYXRoIGQ9XCJNNi41IDUuNHYxMy4ybDExLTYuNnpcIi8+PC9zdmc+JyArXHJcbiAgICAgICAgJzxzdmcgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIj48cGF0aCBkPVwiTTguMzMgNS43NWgyLjJ2MTIuNWgtMi4yVjUuNzV6bTUuMTUgMGgyLjJ2MTIuNWgtMi4yVjUuNzV6XCIvPjwvc3ZnPicgK1xyXG4gICAgICAgIFwiPC9idXR0b24+XCJcclxuICAgIH0sXHJcbiAgICBzbGlkZVNob3c6IHtcclxuICAgICAgYXV0b1N0YXJ0OiBmYWxzZSxcclxuICAgICAgc3BlZWQ6IDMwMDAsXHJcbiAgICAgIHByb2dyZXNzOiB0cnVlXHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIHZhciBTbGlkZVNob3cgPSBmdW5jdGlvbiAoaW5zdGFuY2UpIHtcclxuICAgIHRoaXMuaW5zdGFuY2UgPSBpbnN0YW5jZTtcclxuICAgIHRoaXMuaW5pdCgpO1xyXG4gIH07XHJcblxyXG4gICQuZXh0ZW5kKFNsaWRlU2hvdy5wcm90b3R5cGUsIHtcclxuICAgIHRpbWVyOiBudWxsLFxyXG4gICAgaXNBY3RpdmU6IGZhbHNlLFxyXG4gICAgJGJ1dHRvbjogbnVsbCxcclxuXHJcbiAgICBpbml0OiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHZhciBzZWxmID0gdGhpcyxcclxuICAgICAgICBpbnN0YW5jZSA9IHNlbGYuaW5zdGFuY2UsXHJcbiAgICAgICAgb3B0cyA9IGluc3RhbmNlLmdyb3VwW2luc3RhbmNlLmN1cnJJbmRleF0ub3B0cy5zbGlkZVNob3c7XHJcblxyXG4gICAgICBzZWxmLiRidXR0b24gPSBpbnN0YW5jZS4kcmVmcy50b29sYmFyLmZpbmQoXCJbZGF0YS1mYW5jeWJveC1wbGF5XVwiKS5vbihcImNsaWNrXCIsIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICBzZWxmLnRvZ2dsZSgpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIGlmIChpbnN0YW5jZS5ncm91cC5sZW5ndGggPCAyIHx8ICFvcHRzKSB7XHJcbiAgICAgICAgc2VsZi4kYnV0dG9uLmhpZGUoKTtcclxuICAgICAgfSBlbHNlIGlmIChvcHRzLnByb2dyZXNzKSB7XHJcbiAgICAgICAgc2VsZi4kcHJvZ3Jlc3MgPSAkKCc8ZGl2IGNsYXNzPVwiZmFuY3lib3gtcHJvZ3Jlc3NcIj48L2Rpdj4nKS5hcHBlbmRUbyhpbnN0YW5jZS4kcmVmcy5pbm5lcik7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgc2V0OiBmdW5jdGlvbiAoZm9yY2UpIHtcclxuICAgICAgdmFyIHNlbGYgPSB0aGlzLFxyXG4gICAgICAgIGluc3RhbmNlID0gc2VsZi5pbnN0YW5jZSxcclxuICAgICAgICBjdXJyZW50ID0gaW5zdGFuY2UuY3VycmVudDtcclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHJlYWNoZWQgbGFzdCBlbGVtZW50XHJcbiAgICAgIGlmIChjdXJyZW50ICYmIChmb3JjZSA9PT0gdHJ1ZSB8fCBjdXJyZW50Lm9wdHMubG9vcCB8fCBpbnN0YW5jZS5jdXJySW5kZXggPCBpbnN0YW5jZS5ncm91cC5sZW5ndGggLSAxKSkge1xyXG4gICAgICAgIGlmIChzZWxmLmlzQWN0aXZlICYmIGN1cnJlbnQuY29udGVudFR5cGUgIT09IFwidmlkZW9cIikge1xyXG4gICAgICAgICAgaWYgKHNlbGYuJHByb2dyZXNzKSB7XHJcbiAgICAgICAgICAgICQuZmFuY3lib3guYW5pbWF0ZShzZWxmLiRwcm9ncmVzcy5zaG93KCksIHtcclxuICAgICAgICAgICAgICBzY2FsZVg6IDFcclxuICAgICAgICAgICAgfSwgY3VycmVudC5vcHRzLnNsaWRlU2hvdy5zcGVlZCk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgc2VsZi50aW1lciA9IHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICBpZiAoIWluc3RhbmNlLmN1cnJlbnQub3B0cy5sb29wICYmIGluc3RhbmNlLmN1cnJlbnQuaW5kZXggPT0gaW5zdGFuY2UuZ3JvdXAubGVuZ3RoIC0gMSkge1xyXG4gICAgICAgICAgICAgIGluc3RhbmNlLmp1bXBUbygwKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICBpbnN0YW5jZS5uZXh0KCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0sIGN1cnJlbnQub3B0cy5zbGlkZVNob3cuc3BlZWQpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBzZWxmLnN0b3AoKTtcclxuICAgICAgICBpbnN0YW5jZS5pZGxlU2Vjb25kc0NvdW50ZXIgPSAwO1xyXG4gICAgICAgIGluc3RhbmNlLnNob3dDb250cm9scygpO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIGNsZWFyOiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHZhciBzZWxmID0gdGhpcztcclxuXHJcbiAgICAgIGNsZWFyVGltZW91dChzZWxmLnRpbWVyKTtcclxuXHJcbiAgICAgIHNlbGYudGltZXIgPSBudWxsO1xyXG5cclxuICAgICAgaWYgKHNlbGYuJHByb2dyZXNzKSB7XHJcbiAgICAgICAgc2VsZi4kcHJvZ3Jlc3MucmVtb3ZlQXR0cihcInN0eWxlXCIpLmhpZGUoKTtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICBzdGFydDogZnVuY3Rpb24gKCkge1xyXG4gICAgICB2YXIgc2VsZiA9IHRoaXMsXHJcbiAgICAgICAgY3VycmVudCA9IHNlbGYuaW5zdGFuY2UuY3VycmVudDtcclxuXHJcbiAgICAgIGlmIChjdXJyZW50KSB7XHJcbiAgICAgICAgc2VsZi4kYnV0dG9uXHJcbiAgICAgICAgICAuYXR0cihcInRpdGxlXCIsIChjdXJyZW50Lm9wdHMuaTE4bltjdXJyZW50Lm9wdHMubGFuZ10gfHwgY3VycmVudC5vcHRzLmkxOG4uZW4pLlBMQVlfU1RPUClcclxuICAgICAgICAgIC5yZW1vdmVDbGFzcyhcImZhbmN5Ym94LWJ1dHRvbi0tcGxheVwiKVxyXG4gICAgICAgICAgLmFkZENsYXNzKFwiZmFuY3lib3gtYnV0dG9uLS1wYXVzZVwiKTtcclxuXHJcbiAgICAgICAgc2VsZi5pc0FjdGl2ZSA9IHRydWU7XHJcblxyXG4gICAgICAgIGlmIChjdXJyZW50LmlzQ29tcGxldGUpIHtcclxuICAgICAgICAgIHNlbGYuc2V0KHRydWUpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgc2VsZi5pbnN0YW5jZS50cmlnZ2VyKFwib25TbGlkZVNob3dDaGFuZ2VcIiwgdHJ1ZSk7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgc3RvcDogZnVuY3Rpb24gKCkge1xyXG4gICAgICB2YXIgc2VsZiA9IHRoaXMsXHJcbiAgICAgICAgY3VycmVudCA9IHNlbGYuaW5zdGFuY2UuY3VycmVudDtcclxuXHJcbiAgICAgIHNlbGYuY2xlYXIoKTtcclxuXHJcbiAgICAgIHNlbGYuJGJ1dHRvblxyXG4gICAgICAgIC5hdHRyKFwidGl0bGVcIiwgKGN1cnJlbnQub3B0cy5pMThuW2N1cnJlbnQub3B0cy5sYW5nXSB8fCBjdXJyZW50Lm9wdHMuaTE4bi5lbikuUExBWV9TVEFSVClcclxuICAgICAgICAucmVtb3ZlQ2xhc3MoXCJmYW5jeWJveC1idXR0b24tLXBhdXNlXCIpXHJcbiAgICAgICAgLmFkZENsYXNzKFwiZmFuY3lib3gtYnV0dG9uLS1wbGF5XCIpO1xyXG5cclxuICAgICAgc2VsZi5pc0FjdGl2ZSA9IGZhbHNlO1xyXG5cclxuICAgICAgc2VsZi5pbnN0YW5jZS50cmlnZ2VyKFwib25TbGlkZVNob3dDaGFuZ2VcIiwgZmFsc2UpO1xyXG5cclxuICAgICAgaWYgKHNlbGYuJHByb2dyZXNzKSB7XHJcbiAgICAgICAgc2VsZi4kcHJvZ3Jlc3MucmVtb3ZlQXR0cihcInN0eWxlXCIpLmhpZGUoKTtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICB0b2dnbGU6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgdmFyIHNlbGYgPSB0aGlzO1xyXG5cclxuICAgICAgaWYgKHNlbGYuaXNBY3RpdmUpIHtcclxuICAgICAgICBzZWxmLnN0b3AoKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBzZWxmLnN0YXJ0KCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgJChkb2N1bWVudCkub24oe1xyXG4gICAgXCJvbkluaXQuZmJcIjogZnVuY3Rpb24gKGUsIGluc3RhbmNlKSB7XHJcbiAgICAgIGlmIChpbnN0YW5jZSAmJiAhaW5zdGFuY2UuU2xpZGVTaG93KSB7XHJcbiAgICAgICAgaW5zdGFuY2UuU2xpZGVTaG93ID0gbmV3IFNsaWRlU2hvdyhpbnN0YW5jZSk7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgXCJiZWZvcmVTaG93LmZiXCI6IGZ1bmN0aW9uIChlLCBpbnN0YW5jZSwgY3VycmVudCwgZmlyc3RSdW4pIHtcclxuICAgICAgdmFyIFNsaWRlU2hvdyA9IGluc3RhbmNlICYmIGluc3RhbmNlLlNsaWRlU2hvdztcclxuXHJcbiAgICAgIGlmIChmaXJzdFJ1bikge1xyXG4gICAgICAgIGlmIChTbGlkZVNob3cgJiYgY3VycmVudC5vcHRzLnNsaWRlU2hvdy5hdXRvU3RhcnQpIHtcclxuICAgICAgICAgIFNsaWRlU2hvdy5zdGFydCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSBlbHNlIGlmIChTbGlkZVNob3cgJiYgU2xpZGVTaG93LmlzQWN0aXZlKSB7XHJcbiAgICAgICAgU2xpZGVTaG93LmNsZWFyKCk7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgXCJhZnRlclNob3cuZmJcIjogZnVuY3Rpb24gKGUsIGluc3RhbmNlLCBjdXJyZW50KSB7XHJcbiAgICAgIHZhciBTbGlkZVNob3cgPSBpbnN0YW5jZSAmJiBpbnN0YW5jZS5TbGlkZVNob3c7XHJcblxyXG4gICAgICBpZiAoU2xpZGVTaG93ICYmIFNsaWRlU2hvdy5pc0FjdGl2ZSkge1xyXG4gICAgICAgIFNsaWRlU2hvdy5zZXQoKTtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICBcImFmdGVyS2V5ZG93bi5mYlwiOiBmdW5jdGlvbiAoZSwgaW5zdGFuY2UsIGN1cnJlbnQsIGtleXByZXNzLCBrZXljb2RlKSB7XHJcbiAgICAgIHZhciBTbGlkZVNob3cgPSBpbnN0YW5jZSAmJiBpbnN0YW5jZS5TbGlkZVNob3c7XHJcblxyXG4gICAgICAvLyBcIlBcIiBvciBTcGFjZWJhclxyXG4gICAgICBpZiAoU2xpZGVTaG93ICYmIGN1cnJlbnQub3B0cy5zbGlkZVNob3cgJiYgKGtleWNvZGUgPT09IDgwIHx8IGtleWNvZGUgPT09IDMyKSAmJiAhJChkb2N1bWVudC5hY3RpdmVFbGVtZW50KS5pcyhcImJ1dHRvbixhLGlucHV0XCIpKSB7XHJcbiAgICAgICAga2V5cHJlc3MucHJldmVudERlZmF1bHQoKTtcclxuXHJcbiAgICAgICAgU2xpZGVTaG93LnRvZ2dsZSgpO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIFwiYmVmb3JlQ2xvc2UuZmIgb25EZWFjdGl2YXRlLmZiXCI6IGZ1bmN0aW9uIChlLCBpbnN0YW5jZSkge1xyXG4gICAgICB2YXIgU2xpZGVTaG93ID0gaW5zdGFuY2UgJiYgaW5zdGFuY2UuU2xpZGVTaG93O1xyXG5cclxuICAgICAgaWYgKFNsaWRlU2hvdykge1xyXG4gICAgICAgIFNsaWRlU2hvdy5zdG9wKCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gUGFnZSBWaXNpYmlsaXR5IEFQSSB0byBwYXVzZSBzbGlkZXNob3cgd2hlbiB3aW5kb3cgaXMgbm90IGFjdGl2ZVxyXG4gICQoZG9jdW1lbnQpLm9uKFwidmlzaWJpbGl0eWNoYW5nZVwiLCBmdW5jdGlvbiAoKSB7XHJcbiAgICB2YXIgaW5zdGFuY2UgPSAkLmZhbmN5Ym94LmdldEluc3RhbmNlKCksXHJcbiAgICAgIFNsaWRlU2hvdyA9IGluc3RhbmNlICYmIGluc3RhbmNlLlNsaWRlU2hvdztcclxuXHJcbiAgICBpZiAoU2xpZGVTaG93ICYmIFNsaWRlU2hvdy5pc0FjdGl2ZSkge1xyXG4gICAgICBpZiAoZG9jdW1lbnQuaGlkZGVuKSB7XHJcbiAgICAgICAgU2xpZGVTaG93LmNsZWFyKCk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgU2xpZGVTaG93LnNldCgpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcbn0pKGRvY3VtZW50LCBqUXVlcnkpO1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuLy9cclxuLy8gRnVsbFNjcmVlblxyXG4vLyBBZGRzIGZ1bGxzY3JlZW4gZnVuY3Rpb25hbGl0eVxyXG4vL1xyXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4oZnVuY3Rpb24gKGRvY3VtZW50LCAkKSB7XHJcbiAgXCJ1c2Ugc3RyaWN0XCI7XHJcblxyXG4gIC8vIENvbGxlY3Rpb24gb2YgbWV0aG9kcyBzdXBwb3J0ZWQgYnkgdXNlciBicm93c2VyXHJcbiAgdmFyIGZuID0gKGZ1bmN0aW9uICgpIHtcclxuICAgIHZhciBmbk1hcCA9IFtcclxuICAgICAgW1wicmVxdWVzdEZ1bGxzY3JlZW5cIiwgXCJleGl0RnVsbHNjcmVlblwiLCBcImZ1bGxzY3JlZW5FbGVtZW50XCIsIFwiZnVsbHNjcmVlbkVuYWJsZWRcIiwgXCJmdWxsc2NyZWVuY2hhbmdlXCIsIFwiZnVsbHNjcmVlbmVycm9yXCJdLFxyXG4gICAgICAvLyBuZXcgV2ViS2l0XHJcbiAgICAgIFtcclxuICAgICAgICBcIndlYmtpdFJlcXVlc3RGdWxsc2NyZWVuXCIsXHJcbiAgICAgICAgXCJ3ZWJraXRFeGl0RnVsbHNjcmVlblwiLFxyXG4gICAgICAgIFwid2Via2l0RnVsbHNjcmVlbkVsZW1lbnRcIixcclxuICAgICAgICBcIndlYmtpdEZ1bGxzY3JlZW5FbmFibGVkXCIsXHJcbiAgICAgICAgXCJ3ZWJraXRmdWxsc2NyZWVuY2hhbmdlXCIsXHJcbiAgICAgICAgXCJ3ZWJraXRmdWxsc2NyZWVuZXJyb3JcIlxyXG4gICAgICBdLFxyXG4gICAgICAvLyBvbGQgV2ViS2l0IChTYWZhcmkgNS4xKVxyXG4gICAgICBbXHJcbiAgICAgICAgXCJ3ZWJraXRSZXF1ZXN0RnVsbFNjcmVlblwiLFxyXG4gICAgICAgIFwid2Via2l0Q2FuY2VsRnVsbFNjcmVlblwiLFxyXG4gICAgICAgIFwid2Via2l0Q3VycmVudEZ1bGxTY3JlZW5FbGVtZW50XCIsXHJcbiAgICAgICAgXCJ3ZWJraXRDYW5jZWxGdWxsU2NyZWVuXCIsXHJcbiAgICAgICAgXCJ3ZWJraXRmdWxsc2NyZWVuY2hhbmdlXCIsXHJcbiAgICAgICAgXCJ3ZWJraXRmdWxsc2NyZWVuZXJyb3JcIlxyXG4gICAgICBdLFxyXG4gICAgICBbXHJcbiAgICAgICAgXCJtb3pSZXF1ZXN0RnVsbFNjcmVlblwiLFxyXG4gICAgICAgIFwibW96Q2FuY2VsRnVsbFNjcmVlblwiLFxyXG4gICAgICAgIFwibW96RnVsbFNjcmVlbkVsZW1lbnRcIixcclxuICAgICAgICBcIm1vekZ1bGxTY3JlZW5FbmFibGVkXCIsXHJcbiAgICAgICAgXCJtb3pmdWxsc2NyZWVuY2hhbmdlXCIsXHJcbiAgICAgICAgXCJtb3pmdWxsc2NyZWVuZXJyb3JcIlxyXG4gICAgICBdLFxyXG4gICAgICBbXCJtc1JlcXVlc3RGdWxsc2NyZWVuXCIsIFwibXNFeGl0RnVsbHNjcmVlblwiLCBcIm1zRnVsbHNjcmVlbkVsZW1lbnRcIiwgXCJtc0Z1bGxzY3JlZW5FbmFibGVkXCIsIFwiTVNGdWxsc2NyZWVuQ2hhbmdlXCIsIFwiTVNGdWxsc2NyZWVuRXJyb3JcIl1cclxuICAgIF07XHJcblxyXG4gICAgdmFyIHJldCA9IHt9O1xyXG5cclxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZm5NYXAubGVuZ3RoOyBpKyspIHtcclxuICAgICAgdmFyIHZhbCA9IGZuTWFwW2ldO1xyXG5cclxuICAgICAgaWYgKHZhbCAmJiB2YWxbMV0gaW4gZG9jdW1lbnQpIHtcclxuICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IHZhbC5sZW5ndGg7IGorKykge1xyXG4gICAgICAgICAgcmV0W2ZuTWFwWzBdW2pdXSA9IHZhbFtqXTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiByZXQ7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfSkoKTtcclxuXHJcbiAgaWYgKGZuKSB7XHJcbiAgICB2YXIgRnVsbFNjcmVlbiA9IHtcclxuICAgICAgcmVxdWVzdDogZnVuY3Rpb24gKGVsZW0pIHtcclxuICAgICAgICBlbGVtID0gZWxlbSB8fCBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQ7XHJcblxyXG4gICAgICAgIGVsZW1bZm4ucmVxdWVzdEZ1bGxzY3JlZW5dKGVsZW0uQUxMT1dfS0VZQk9BUkRfSU5QVVQpO1xyXG4gICAgICB9LFxyXG4gICAgICBleGl0OiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgZG9jdW1lbnRbZm4uZXhpdEZ1bGxzY3JlZW5dKCk7XHJcbiAgICAgIH0sXHJcbiAgICAgIHRvZ2dsZTogZnVuY3Rpb24gKGVsZW0pIHtcclxuICAgICAgICBlbGVtID0gZWxlbSB8fCBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQ7XHJcblxyXG4gICAgICAgIGlmICh0aGlzLmlzRnVsbHNjcmVlbigpKSB7XHJcbiAgICAgICAgICB0aGlzLmV4aXQoKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhpcy5yZXF1ZXN0KGVsZW0pO1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgaXNGdWxsc2NyZWVuOiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgcmV0dXJuIEJvb2xlYW4oZG9jdW1lbnRbZm4uZnVsbHNjcmVlbkVsZW1lbnRdKTtcclxuICAgICAgfSxcclxuICAgICAgZW5hYmxlZDogZnVuY3Rpb24gKCkge1xyXG4gICAgICAgIHJldHVybiBCb29sZWFuKGRvY3VtZW50W2ZuLmZ1bGxzY3JlZW5FbmFibGVkXSk7XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgJC5leHRlbmQodHJ1ZSwgJC5mYW5jeWJveC5kZWZhdWx0cywge1xyXG4gICAgICBidG5UcGw6IHtcclxuICAgICAgICBmdWxsU2NyZWVuOiAnPGJ1dHRvbiBkYXRhLWZhbmN5Ym94LWZ1bGxzY3JlZW4gY2xhc3M9XCJmYW5jeWJveC1idXR0b24gZmFuY3lib3gtYnV0dG9uLS1mc2VudGVyXCIgdGl0bGU9XCJ7e0ZVTExfU0NSRUVOfX1cIj4nICtcclxuICAgICAgICAgICc8c3ZnIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIiB2aWV3Qm94PVwiMCAwIDI0IDI0XCI+PHBhdGggZD1cIk03IDE0SDV2NWg1di0ySDd2LTN6bS0yLTRoMlY3aDNWNUg1djV6bTEyIDdoLTN2Mmg1di01aC0ydjN6TTE0IDV2MmgzdjNoMlY1aC01elwiLz48L3N2Zz4nICtcclxuICAgICAgICAgICc8c3ZnIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIiB2aWV3Qm94PVwiMCAwIDI0IDI0XCI+PHBhdGggZD1cIk01IDE2aDN2M2gydi01SDV6bTMtOEg1djJoNVY1SDh6bTYgMTFoMnYtM2gzdi0yaC01em0yLTExVjVoLTJ2NWg1Vjh6XCIvPjwvc3ZnPicgK1xyXG4gICAgICAgICAgXCI8L2J1dHRvbj5cIlxyXG4gICAgICB9LFxyXG4gICAgICBmdWxsU2NyZWVuOiB7XHJcbiAgICAgICAgYXV0b1N0YXJ0OiBmYWxzZVxyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICAkKGRvY3VtZW50KS5vbihmbi5mdWxsc2NyZWVuY2hhbmdlLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHZhciBpc0Z1bGxzY3JlZW4gPSBGdWxsU2NyZWVuLmlzRnVsbHNjcmVlbigpLFxyXG4gICAgICAgIGluc3RhbmNlID0gJC5mYW5jeWJveC5nZXRJbnN0YW5jZSgpO1xyXG5cclxuICAgICAgaWYgKGluc3RhbmNlKSB7XHJcbiAgICAgICAgLy8gSWYgaW1hZ2UgaXMgem9vbWluZywgdGhlbiBmb3JjZSB0byBzdG9wIGFuZCByZXBvc2l0aW9uIHByb3Blcmx5XHJcbiAgICAgICAgaWYgKGluc3RhbmNlLmN1cnJlbnQgJiYgaW5zdGFuY2UuY3VycmVudC50eXBlID09PSBcImltYWdlXCIgJiYgaW5zdGFuY2UuaXNBbmltYXRpbmcpIHtcclxuICAgICAgICAgIGluc3RhbmNlLmlzQW5pbWF0aW5nID0gZmFsc2U7XHJcblxyXG4gICAgICAgICAgaW5zdGFuY2UudXBkYXRlKHRydWUsIHRydWUsIDApO1xyXG5cclxuICAgICAgICAgIGlmICghaW5zdGFuY2UuaXNDb21wbGV0ZSkge1xyXG4gICAgICAgICAgICBpbnN0YW5jZS5jb21wbGV0ZSgpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaW5zdGFuY2UudHJpZ2dlcihcIm9uRnVsbHNjcmVlbkNoYW5nZVwiLCBpc0Z1bGxzY3JlZW4pO1xyXG5cclxuICAgICAgICBpbnN0YW5jZS4kcmVmcy5jb250YWluZXIudG9nZ2xlQ2xhc3MoXCJmYW5jeWJveC1pcy1mdWxsc2NyZWVuXCIsIGlzRnVsbHNjcmVlbik7XHJcblxyXG4gICAgICAgIGluc3RhbmNlLiRyZWZzLnRvb2xiYXJcclxuICAgICAgICAgIC5maW5kKFwiW2RhdGEtZmFuY3lib3gtZnVsbHNjcmVlbl1cIilcclxuICAgICAgICAgIC50b2dnbGVDbGFzcyhcImZhbmN5Ym94LWJ1dHRvbi0tZnNlbnRlclwiLCAhaXNGdWxsc2NyZWVuKVxyXG4gICAgICAgICAgLnRvZ2dsZUNsYXNzKFwiZmFuY3lib3gtYnV0dG9uLS1mc2V4aXRcIiwgaXNGdWxsc2NyZWVuKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAkKGRvY3VtZW50KS5vbih7XHJcbiAgICBcIm9uSW5pdC5mYlwiOiBmdW5jdGlvbiAoZSwgaW5zdGFuY2UpIHtcclxuICAgICAgdmFyICRjb250YWluZXI7XHJcblxyXG4gICAgICBpZiAoIWZuKSB7XHJcbiAgICAgICAgaW5zdGFuY2UuJHJlZnMudG9vbGJhci5maW5kKFwiW2RhdGEtZmFuY3lib3gtZnVsbHNjcmVlbl1cIikucmVtb3ZlKCk7XHJcblxyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGluc3RhbmNlICYmIGluc3RhbmNlLmdyb3VwW2luc3RhbmNlLmN1cnJJbmRleF0ub3B0cy5mdWxsU2NyZWVuKSB7XHJcbiAgICAgICAgJGNvbnRhaW5lciA9IGluc3RhbmNlLiRyZWZzLmNvbnRhaW5lcjtcclxuXHJcbiAgICAgICAgJGNvbnRhaW5lci5vbihcImNsaWNrLmZiLWZ1bGxzY3JlZW5cIiwgXCJbZGF0YS1mYW5jeWJveC1mdWxsc2NyZWVuXVwiLCBmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcclxuXHJcbiAgICAgICAgICBGdWxsU2NyZWVuLnRvZ2dsZSgpO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICBpZiAoaW5zdGFuY2Uub3B0cy5mdWxsU2NyZWVuICYmIGluc3RhbmNlLm9wdHMuZnVsbFNjcmVlbi5hdXRvU3RhcnQgPT09IHRydWUpIHtcclxuICAgICAgICAgIEZ1bGxTY3JlZW4ucmVxdWVzdCgpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gRXhwb3NlIEFQSVxyXG4gICAgICAgIGluc3RhbmNlLkZ1bGxTY3JlZW4gPSBGdWxsU2NyZWVuO1xyXG4gICAgICB9IGVsc2UgaWYgKGluc3RhbmNlKSB7XHJcbiAgICAgICAgaW5zdGFuY2UuJHJlZnMudG9vbGJhci5maW5kKFwiW2RhdGEtZmFuY3lib3gtZnVsbHNjcmVlbl1cIikuaGlkZSgpO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIFwiYWZ0ZXJLZXlkb3duLmZiXCI6IGZ1bmN0aW9uIChlLCBpbnN0YW5jZSwgY3VycmVudCwga2V5cHJlc3MsIGtleWNvZGUpIHtcclxuICAgICAgLy8gXCJGXCJcclxuICAgICAgaWYgKGluc3RhbmNlICYmIGluc3RhbmNlLkZ1bGxTY3JlZW4gJiYga2V5Y29kZSA9PT0gNzApIHtcclxuICAgICAgICBrZXlwcmVzcy5wcmV2ZW50RGVmYXVsdCgpO1xyXG5cclxuICAgICAgICBpbnN0YW5jZS5GdWxsU2NyZWVuLnRvZ2dsZSgpO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIFwiYmVmb3JlQ2xvc2UuZmJcIjogZnVuY3Rpb24gKGUsIGluc3RhbmNlKSB7XHJcbiAgICAgIGlmIChpbnN0YW5jZSAmJiBpbnN0YW5jZS5GdWxsU2NyZWVuICYmIGluc3RhbmNlLiRyZWZzLmNvbnRhaW5lci5oYXNDbGFzcyhcImZhbmN5Ym94LWlzLWZ1bGxzY3JlZW5cIikpIHtcclxuICAgICAgICBGdWxsU2NyZWVuLmV4aXQoKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59KShkb2N1bWVudCwgalF1ZXJ5KTtcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbi8vXHJcbi8vIFRodW1ic1xyXG4vLyBEaXNwbGF5cyB0aHVtYm5haWxzIGluIGEgZ3JpZFxyXG4vL1xyXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4oZnVuY3Rpb24gKGRvY3VtZW50LCAkKSB7XHJcbiAgXCJ1c2Ugc3RyaWN0XCI7XHJcblxyXG4gIHZhciBDTEFTUyA9IFwiZmFuY3lib3gtdGh1bWJzXCIsXHJcbiAgICBDTEFTU19BQ1RJVkUgPSBDTEFTUyArIFwiLWFjdGl2ZVwiO1xyXG5cclxuICAvLyBNYWtlIHN1cmUgdGhlcmUgYXJlIGRlZmF1bHQgdmFsdWVzXHJcbiAgJC5mYW5jeWJveC5kZWZhdWx0cyA9ICQuZXh0ZW5kKFxyXG4gICAgdHJ1ZSwge1xyXG4gICAgICBidG5UcGw6IHtcclxuICAgICAgICB0aHVtYnM6ICc8YnV0dG9uIGRhdGEtZmFuY3lib3gtdGh1bWJzIGNsYXNzPVwiZmFuY3lib3gtYnV0dG9uIGZhbmN5Ym94LWJ1dHRvbi0tdGh1bWJzXCIgdGl0bGU9XCJ7e1RIVU1CU319XCI+JyArXHJcbiAgICAgICAgICAnPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgdmlld0JveD1cIjAgMCAyNCAyNFwiPjxwYXRoIGQ9XCJNMTQuNTkgMTQuNTloMy43NnYzLjc2aC0zLjc2di0zLjc2em0tNC40NyAwaDMuNzZ2My43NmgtMy43NnYtMy43NnptLTQuNDcgMGgzLjc2djMuNzZINS42NXYtMy43NnptOC45NC00LjQ3aDMuNzZ2My43NmgtMy43NnYtMy43NnptLTQuNDcgMGgzLjc2djMuNzZoLTMuNzZ2LTMuNzZ6bS00LjQ3IDBoMy43NnYzLjc2SDUuNjV2LTMuNzZ6bTguOTQtNC40N2gzLjc2djMuNzZoLTMuNzZWNS42NXptLTQuNDcgMGgzLjc2djMuNzZoLTMuNzZWNS42NXptLTQuNDcgMGgzLjc2djMuNzZINS42NVY1LjY1elwiLz48L3N2Zz4nICtcclxuICAgICAgICAgIFwiPC9idXR0b24+XCJcclxuICAgICAgfSxcclxuICAgICAgdGh1bWJzOiB7XHJcbiAgICAgICAgYXV0b1N0YXJ0OiBmYWxzZSwgLy8gRGlzcGxheSB0aHVtYm5haWxzIG9uIG9wZW5pbmdcclxuICAgICAgICBoaWRlT25DbG9zZTogdHJ1ZSwgLy8gSGlkZSB0aHVtYm5haWwgZ3JpZCB3aGVuIGNsb3NpbmcgYW5pbWF0aW9uIHN0YXJ0c1xyXG4gICAgICAgIHBhcmVudEVsOiBcIi5mYW5jeWJveC1jb250YWluZXJcIiwgLy8gQ29udGFpbmVyIGlzIGluamVjdGVkIGludG8gdGhpcyBlbGVtZW50XHJcbiAgICAgICAgYXhpczogXCJ5XCIgLy8gVmVydGljYWwgKHkpIG9yIGhvcml6b250YWwgKHgpIHNjcm9sbGluZ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgJC5mYW5jeWJveC5kZWZhdWx0c1xyXG4gICk7XHJcblxyXG4gIHZhciBGYW5jeVRodW1icyA9IGZ1bmN0aW9uIChpbnN0YW5jZSkge1xyXG4gICAgdGhpcy5pbml0KGluc3RhbmNlKTtcclxuICB9O1xyXG5cclxuICAkLmV4dGVuZChGYW5jeVRodW1icy5wcm90b3R5cGUsIHtcclxuICAgICRidXR0b246IG51bGwsXHJcbiAgICAkZ3JpZDogbnVsbCxcclxuICAgICRsaXN0OiBudWxsLFxyXG4gICAgaXNWaXNpYmxlOiBmYWxzZSxcclxuICAgIGlzQWN0aXZlOiBmYWxzZSxcclxuXHJcbiAgICBpbml0OiBmdW5jdGlvbiAoaW5zdGFuY2UpIHtcclxuICAgICAgdmFyIHNlbGYgPSB0aGlzLFxyXG4gICAgICAgIGdyb3VwID0gaW5zdGFuY2UuZ3JvdXAsXHJcbiAgICAgICAgZW5hYmxlZCA9IDA7XHJcblxyXG4gICAgICBzZWxmLmluc3RhbmNlID0gaW5zdGFuY2U7XHJcbiAgICAgIHNlbGYub3B0cyA9IGdyb3VwW2luc3RhbmNlLmN1cnJJbmRleF0ub3B0cy50aHVtYnM7XHJcblxyXG4gICAgICBpbnN0YW5jZS5UaHVtYnMgPSBzZWxmO1xyXG5cclxuICAgICAgc2VsZi4kYnV0dG9uID0gaW5zdGFuY2UuJHJlZnMudG9vbGJhci5maW5kKFwiW2RhdGEtZmFuY3lib3gtdGh1bWJzXVwiKTtcclxuXHJcbiAgICAgIC8vIEVuYWJsZSB0aHVtYnMgaWYgYXQgbGVhc3QgdHdvIGdyb3VwIGl0ZW1zIGhhdmUgdGh1bWJuYWlsc1xyXG4gICAgICBmb3IgKHZhciBpID0gMCwgbGVuID0gZ3JvdXAubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcclxuICAgICAgICBpZiAoZ3JvdXBbaV0udGh1bWIpIHtcclxuICAgICAgICAgIGVuYWJsZWQrKztcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmIChlbmFibGVkID4gMSkge1xyXG4gICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoZW5hYmxlZCA+IDEgJiYgISFzZWxmLm9wdHMpIHtcclxuICAgICAgICBzZWxmLiRidXR0b24ucmVtb3ZlQXR0cihcInN0eWxlXCIpLm9uKFwiY2xpY2tcIiwgZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgc2VsZi50b2dnbGUoKTtcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgc2VsZi5pc0FjdGl2ZSA9IHRydWU7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgc2VsZi4kYnV0dG9uLmhpZGUoKTtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICBjcmVhdGU6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgdmFyIHNlbGYgPSB0aGlzLFxyXG4gICAgICAgIGluc3RhbmNlID0gc2VsZi5pbnN0YW5jZSxcclxuICAgICAgICBwYXJlbnRFbCA9IHNlbGYub3B0cy5wYXJlbnRFbCxcclxuICAgICAgICBsaXN0ID0gW10sXHJcbiAgICAgICAgc3JjO1xyXG5cclxuICAgICAgaWYgKCFzZWxmLiRncmlkKSB7XHJcbiAgICAgICAgLy8gQ3JlYXRlIG1haW4gZWxlbWVudFxyXG4gICAgICAgIHNlbGYuJGdyaWQgPSAkKCc8ZGl2IGNsYXNzPVwiJyArIENMQVNTICsgXCIgXCIgKyBDTEFTUyArIFwiLVwiICsgc2VsZi5vcHRzLmF4aXMgKyAnXCI+PC9kaXY+JykuYXBwZW5kVG8oXHJcbiAgICAgICAgICBpbnN0YW5jZS4kcmVmcy5jb250YWluZXJcclxuICAgICAgICAgIC5maW5kKHBhcmVudEVsKVxyXG4gICAgICAgICAgLmFkZEJhY2soKVxyXG4gICAgICAgICAgLmZpbHRlcihwYXJlbnRFbClcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBBZGQgXCJjbGlja1wiIGV2ZW50IHRoYXQgcGVyZm9ybXMgZ2FsbGVyeSBuYXZpZ2F0aW9uXHJcbiAgICAgICAgc2VsZi4kZ3JpZC5vbihcImNsaWNrXCIsIFwiYVwiLCBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICBpbnN0YW5jZS5qdW1wVG8oJCh0aGlzKS5hdHRyKFwiZGF0YS1pbmRleFwiKSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEJ1aWxkIHRoZSBsaXN0XHJcbiAgICAgIGlmICghc2VsZi4kbGlzdCkge1xyXG4gICAgICAgIHNlbGYuJGxpc3QgPSAkKCc8ZGl2IGNsYXNzPVwiJyArIENMQVNTICsgJ19fbGlzdFwiPicpLmFwcGVuZFRvKHNlbGYuJGdyaWQpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAkLmVhY2goaW5zdGFuY2UuZ3JvdXAsIGZ1bmN0aW9uIChpLCBpdGVtKSB7XHJcbiAgICAgICAgc3JjID0gaXRlbS50aHVtYjtcclxuXHJcbiAgICAgICAgaWYgKCFzcmMgJiYgaXRlbS50eXBlID09PSBcImltYWdlXCIpIHtcclxuICAgICAgICAgIHNyYyA9IGl0ZW0uc3JjO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgbGlzdC5wdXNoKFxyXG4gICAgICAgICAgJzxhIGhyZWY9XCJqYXZhc2NyaXB0OjtcIiB0YWJpbmRleD1cIjBcIiBkYXRhLWluZGV4PVwiJyArXHJcbiAgICAgICAgICBpICtcclxuICAgICAgICAgICdcIicgK1xyXG4gICAgICAgICAgKHNyYyAmJiBzcmMubGVuZ3RoID8gJyBzdHlsZT1cImJhY2tncm91bmQtaW1hZ2U6dXJsKCcgKyBzcmMgKyAnKVwiJyA6ICdjbGFzcz1cImZhbmN5Ym94LXRodW1icy1taXNzaW5nXCInKSArXHJcbiAgICAgICAgICBcIj48L2E+XCJcclxuICAgICAgICApO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIHNlbGYuJGxpc3RbMF0uaW5uZXJIVE1MID0gbGlzdC5qb2luKFwiXCIpO1xyXG5cclxuICAgICAgaWYgKHNlbGYub3B0cy5heGlzID09PSBcInhcIikge1xyXG4gICAgICAgIC8vIFNldCBmaXhlZCB3aWR0aCBmb3IgbGlzdCBlbGVtZW50IHRvIGVuYWJsZSBob3Jpem9udGFsIHNjcm9sbGluZ1xyXG4gICAgICAgIHNlbGYuJGxpc3Qud2lkdGgoXHJcbiAgICAgICAgICBwYXJzZUludChzZWxmLiRncmlkLmNzcyhcInBhZGRpbmctcmlnaHRcIiksIDEwKSArXHJcbiAgICAgICAgICBpbnN0YW5jZS5ncm91cC5sZW5ndGggKlxyXG4gICAgICAgICAgc2VsZi4kbGlzdFxyXG4gICAgICAgICAgLmNoaWxkcmVuKClcclxuICAgICAgICAgIC5lcSgwKVxyXG4gICAgICAgICAgLm91dGVyV2lkdGgodHJ1ZSlcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIGZvY3VzOiBmdW5jdGlvbiAoZHVyYXRpb24pIHtcclxuICAgICAgdmFyIHNlbGYgPSB0aGlzLFxyXG4gICAgICAgICRsaXN0ID0gc2VsZi4kbGlzdCxcclxuICAgICAgICAkZ3JpZCA9IHNlbGYuJGdyaWQsXHJcbiAgICAgICAgdGh1bWIsXHJcbiAgICAgICAgdGh1bWJQb3M7XHJcblxyXG4gICAgICBpZiAoIXNlbGYuaW5zdGFuY2UuY3VycmVudCkge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgdGh1bWIgPSAkbGlzdFxyXG4gICAgICAgIC5jaGlsZHJlbigpXHJcbiAgICAgICAgLnJlbW92ZUNsYXNzKENMQVNTX0FDVElWRSlcclxuICAgICAgICAuZmlsdGVyKCdbZGF0YS1pbmRleD1cIicgKyBzZWxmLmluc3RhbmNlLmN1cnJlbnQuaW5kZXggKyAnXCJdJylcclxuICAgICAgICAuYWRkQ2xhc3MoQ0xBU1NfQUNUSVZFKTtcclxuXHJcbiAgICAgIHRodW1iUG9zID0gdGh1bWIucG9zaXRpb24oKTtcclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIG5lZWQgdG8gc2Nyb2xsIHRvIG1ha2UgY3VycmVudCB0aHVtYiB2aXNpYmxlXHJcbiAgICAgIGlmIChzZWxmLm9wdHMuYXhpcyA9PT0gXCJ5XCIgJiYgKHRodW1iUG9zLnRvcCA8IDAgfHwgdGh1bWJQb3MudG9wID4gJGxpc3QuaGVpZ2h0KCkgLSB0aHVtYi5vdXRlckhlaWdodCgpKSkge1xyXG4gICAgICAgICRsaXN0LnN0b3AoKS5hbmltYXRlKHtcclxuICAgICAgICAgICAgc2Nyb2xsVG9wOiAkbGlzdC5zY3JvbGxUb3AoKSArIHRodW1iUG9zLnRvcFxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIGR1cmF0aW9uXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBlbHNlIGlmIChcclxuICAgICAgICBzZWxmLm9wdHMuYXhpcyA9PT0gXCJ4XCIgJiZcclxuICAgICAgICAodGh1bWJQb3MubGVmdCA8ICRncmlkLnNjcm9sbExlZnQoKSB8fCB0aHVtYlBvcy5sZWZ0ID4gJGdyaWQuc2Nyb2xsTGVmdCgpICsgKCRncmlkLndpZHRoKCkgLSB0aHVtYi5vdXRlcldpZHRoKCkpKVxyXG4gICAgICApIHtcclxuICAgICAgICAkbGlzdFxyXG4gICAgICAgICAgLnBhcmVudCgpXHJcbiAgICAgICAgICAuc3RvcCgpXHJcbiAgICAgICAgICAuYW5pbWF0ZSh7XHJcbiAgICAgICAgICAgICAgc2Nyb2xsTGVmdDogdGh1bWJQb3MubGVmdFxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICBkdXJhdGlvblxyXG4gICAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICB1cGRhdGU6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgdmFyIHRoYXQgPSB0aGlzO1xyXG4gICAgICB0aGF0Lmluc3RhbmNlLiRyZWZzLmNvbnRhaW5lci50b2dnbGVDbGFzcyhcImZhbmN5Ym94LXNob3ctdGh1bWJzXCIsIHRoaXMuaXNWaXNpYmxlKTtcclxuXHJcbiAgICAgIGlmICh0aGF0LmlzVmlzaWJsZSkge1xyXG4gICAgICAgIGlmICghdGhhdC4kZ3JpZCkge1xyXG4gICAgICAgICAgdGhhdC5jcmVhdGUoKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHRoYXQuaW5zdGFuY2UudHJpZ2dlcihcIm9uVGh1bWJzU2hvd1wiKTtcclxuXHJcbiAgICAgICAgdGhhdC5mb2N1cygwKTtcclxuICAgICAgfSBlbHNlIGlmICh0aGF0LiRncmlkKSB7XHJcbiAgICAgICAgdGhhdC5pbnN0YW5jZS50cmlnZ2VyKFwib25UaHVtYnNIaWRlXCIpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBVcGRhdGUgY29udGVudCBwb3NpdGlvblxyXG4gICAgICB0aGF0Lmluc3RhbmNlLnVwZGF0ZSgpO1xyXG4gICAgfSxcclxuXHJcbiAgICBoaWRlOiBmdW5jdGlvbiAoKSB7XHJcbiAgICAgIHRoaXMuaXNWaXNpYmxlID0gZmFsc2U7XHJcbiAgICAgIHRoaXMudXBkYXRlKCk7XHJcbiAgICB9LFxyXG5cclxuICAgIHNob3c6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgdGhpcy5pc1Zpc2libGUgPSB0cnVlO1xyXG4gICAgICB0aGlzLnVwZGF0ZSgpO1xyXG4gICAgfSxcclxuXHJcbiAgICB0b2dnbGU6IGZ1bmN0aW9uICgpIHtcclxuICAgICAgdGhpcy5pc1Zpc2libGUgPSAhdGhpcy5pc1Zpc2libGU7XHJcbiAgICAgIHRoaXMudXBkYXRlKCk7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gICQoZG9jdW1lbnQpLm9uKHtcclxuICAgIFwib25Jbml0LmZiXCI6IGZ1bmN0aW9uIChlLCBpbnN0YW5jZSkge1xyXG4gICAgICB2YXIgVGh1bWJzO1xyXG5cclxuICAgICAgaWYgKGluc3RhbmNlICYmICFpbnN0YW5jZS5UaHVtYnMpIHtcclxuICAgICAgICBUaHVtYnMgPSBuZXcgRmFuY3lUaHVtYnMoaW5zdGFuY2UpO1xyXG5cclxuICAgICAgICBpZiAoVGh1bWJzLmlzQWN0aXZlICYmIFRodW1icy5vcHRzLmF1dG9TdGFydCA9PT0gdHJ1ZSkge1xyXG4gICAgICAgICAgVGh1bWJzLnNob3coKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgXCJiZWZvcmVTaG93LmZiXCI6IGZ1bmN0aW9uIChlLCBpbnN0YW5jZSwgaXRlbSwgZmlyc3RSdW4pIHtcclxuICAgICAgdmFyIFRodW1icyA9IGluc3RhbmNlICYmIGluc3RhbmNlLlRodW1icztcclxuXHJcbiAgICAgIGlmIChUaHVtYnMgJiYgVGh1bWJzLmlzVmlzaWJsZSkge1xyXG4gICAgICAgIFRodW1icy5mb2N1cyhmaXJzdFJ1biA/IDAgOiAyNTApO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIFwiYWZ0ZXJLZXlkb3duLmZiXCI6IGZ1bmN0aW9uIChlLCBpbnN0YW5jZSwgY3VycmVudCwga2V5cHJlc3MsIGtleWNvZGUpIHtcclxuICAgICAgdmFyIFRodW1icyA9IGluc3RhbmNlICYmIGluc3RhbmNlLlRodW1icztcclxuXHJcbiAgICAgIC8vIFwiR1wiXHJcbiAgICAgIGlmIChUaHVtYnMgJiYgVGh1bWJzLmlzQWN0aXZlICYmIGtleWNvZGUgPT09IDcxKSB7XHJcbiAgICAgICAga2V5cHJlc3MucHJldmVudERlZmF1bHQoKTtcclxuXHJcbiAgICAgICAgVGh1bWJzLnRvZ2dsZSgpO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIFwiYmVmb3JlQ2xvc2UuZmJcIjogZnVuY3Rpb24gKGUsIGluc3RhbmNlKSB7XHJcbiAgICAgIHZhciBUaHVtYnMgPSBpbnN0YW5jZSAmJiBpbnN0YW5jZS5UaHVtYnM7XHJcblxyXG4gICAgICBpZiAoVGh1bWJzICYmIFRodW1icy5pc1Zpc2libGUgJiYgVGh1bWJzLm9wdHMuaGlkZU9uQ2xvc2UgIT09IGZhbHNlKSB7XHJcbiAgICAgICAgVGh1bWJzLiRncmlkLmhpZGUoKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59KShkb2N1bWVudCwgalF1ZXJ5KTtcbi8vLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuLy9cclxuLy8gU2hhcmVcclxuLy8gRGlzcGxheXMgc2ltcGxlIGZvcm0gZm9yIHNoYXJpbmcgY3VycmVudCB1cmxcclxuLy9cclxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cclxuKGZ1bmN0aW9uIChkb2N1bWVudCwgJCkge1xyXG4gIFwidXNlIHN0cmljdFwiO1xyXG5cclxuICAkLmV4dGVuZCh0cnVlLCAkLmZhbmN5Ym94LmRlZmF1bHRzLCB7XHJcbiAgICBidG5UcGw6IHtcclxuICAgICAgc2hhcmU6ICc8YnV0dG9uIGRhdGEtZmFuY3lib3gtc2hhcmUgY2xhc3M9XCJmYW5jeWJveC1idXR0b24gZmFuY3lib3gtYnV0dG9uLS1zaGFyZVwiIHRpdGxlPVwie3tTSEFSRX19XCI+JyArXHJcbiAgICAgICAgJzxzdmcgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIj48cGF0aCBkPVwiTTIuNTUgMTljMS40LTguNCA5LjEtOS44IDExLjktOS44VjVsNyA3LTcgNi4zdi0zLjVjLTIuOCAwLTEwLjUgMi4xLTExLjkgNC4yelwiLz48L3N2Zz4nICtcclxuICAgICAgICBcIjwvYnV0dG9uPlwiXHJcbiAgICB9LFxyXG4gICAgc2hhcmU6IHtcclxuICAgICAgdXJsOiBmdW5jdGlvbiAoaW5zdGFuY2UsIGl0ZW0pIHtcclxuICAgICAgICByZXR1cm4gKFxyXG4gICAgICAgICAgKCFpbnN0YW5jZS5jdXJyZW50SGFzaCAmJiAhKGl0ZW0udHlwZSA9PT0gXCJpbmxpbmVcIiB8fCBpdGVtLnR5cGUgPT09IFwiaHRtbFwiKSA/IGl0ZW0ub3JpZ1NyYyB8fCBpdGVtLnNyYyA6IGZhbHNlKSB8fCB3aW5kb3cubG9jYXRpb25cclxuICAgICAgICApO1xyXG4gICAgICB9LFxyXG4gICAgICB0cGw6ICc8ZGl2IGNsYXNzPVwiZmFuY3lib3gtc2hhcmVcIj4nICtcclxuICAgICAgICBcIjxoMT57e1NIQVJFfX08L2gxPlwiICtcclxuICAgICAgICBcIjxwPlwiICtcclxuICAgICAgICAnPGEgY2xhc3M9XCJmYW5jeWJveC1zaGFyZV9fYnV0dG9uIGZhbmN5Ym94LXNoYXJlX19idXR0b24tLWZiXCIgaHJlZj1cImh0dHBzOi8vd3d3LmZhY2Vib29rLmNvbS9zaGFyZXIvc2hhcmVyLnBocD91PXt7dXJsfX1cIj4nICtcclxuICAgICAgICAnPHN2ZyB2aWV3Qm94PVwiMCAwIDUxMiA1MTJcIiB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCI+PHBhdGggZD1cIm0yODcgNDU2di0yOTljMC0yMSA2LTM1IDM1LTM1aDM4di02M2MtNy0xLTI5LTMtNTUtMy01NCAwLTkxIDMzLTkxIDk0djMwNm0xNDMtMjU0aC0yMDV2NzJoMTk2XCIgLz48L3N2Zz4nICtcclxuICAgICAgICBcIjxzcGFuPkZhY2Vib29rPC9zcGFuPlwiICtcclxuICAgICAgICBcIjwvYT5cIiArXHJcbiAgICAgICAgJzxhIGNsYXNzPVwiZmFuY3lib3gtc2hhcmVfX2J1dHRvbiBmYW5jeWJveC1zaGFyZV9fYnV0dG9uLS10d1wiIGhyZWY9XCJodHRwczovL3R3aXR0ZXIuY29tL2ludGVudC90d2VldD91cmw9e3t1cmx9fSZ0ZXh0PXt7ZGVzY3J9fVwiPicgK1xyXG4gICAgICAgICc8c3ZnIHZpZXdCb3g9XCIwIDAgNTEyIDUxMlwiIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIj48cGF0aCBkPVwibTQ1NiAxMzNjLTE0IDctMzEgMTEtNDcgMTMgMTctMTAgMzAtMjcgMzctNDYtMTUgMTAtMzQgMTYtNTIgMjAtNjEtNjItMTU3LTctMTQxIDc1LTY4LTMtMTI5LTM1LTE2OS04NS0yMiAzNy0xMSA4NiAyNiAxMDktMTMgMC0yNi00LTM3LTkgMCAzOSAyOCA3MiA2NSA4MC0xMiAzLTI1IDQtMzcgMiAxMCAzMyA0MSA1NyA3NyA1Ny00MiAzMC03NyAzOC0xMjIgMzQgMTcwIDExMSAzNzgtMzIgMzU5LTIwOCAxNi0xMSAzMC0yNSA0MS00MnpcIiAvPjwvc3ZnPicgK1xyXG4gICAgICAgIFwiPHNwYW4+VHdpdHRlcjwvc3Bhbj5cIiArXHJcbiAgICAgICAgXCI8L2E+XCIgK1xyXG4gICAgICAgICc8YSBjbGFzcz1cImZhbmN5Ym94LXNoYXJlX19idXR0b24gZmFuY3lib3gtc2hhcmVfX2J1dHRvbi0tcHRcIiBocmVmPVwiaHR0cHM6Ly93d3cucGludGVyZXN0LmNvbS9waW4vY3JlYXRlL2J1dHRvbi8/dXJsPXt7dXJsfX0mZGVzY3JpcHRpb249e3tkZXNjcn19Jm1lZGlhPXt7bWVkaWF9fVwiPicgK1xyXG4gICAgICAgICc8c3ZnIHZpZXdCb3g9XCIwIDAgNTEyIDUxMlwiIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIj48cGF0aCBkPVwibTI2NSA1NmMtMTA5IDAtMTY0IDc4LTE2NCAxNDQgMCAzOSAxNSA3NCA0NyA4NyA1IDIgMTAgMCAxMi01bDQtMTljMi02IDEtOC0zLTEzLTktMTEtMTUtMjUtMTUtNDUgMC01OCA0My0xMTAgMTEzLTExMCA2MiAwIDk2IDM4IDk2IDg4IDAgNjctMzAgMTIyLTczIDEyMi0yNCAwLTQyLTE5LTM2LTQ0IDYtMjkgMjAtNjAgMjAtODEgMC0xOS0xMC0zNS0zMS0zNS0yNSAwLTQ0IDI2LTQ0IDYwIDAgMjEgNyAzNiA3IDM2bC0zMCAxMjVjLTggMzctMSA4MyAwIDg3IDAgMyA0IDQgNSAyIDItMyAzMi0zOSA0Mi03NWwxNi02NGM4IDE2IDMxIDI5IDU2IDI5IDc0IDAgMTI0LTY3IDEyNC0xNTcgMC02OS01OC0xMzItMTQ2LTEzMnpcIiBmaWxsPVwiI2ZmZlwiLz48L3N2Zz4nICtcclxuICAgICAgICBcIjxzcGFuPlBpbnRlcmVzdDwvc3Bhbj5cIiArXHJcbiAgICAgICAgXCI8L2E+XCIgK1xyXG4gICAgICAgIFwiPC9wPlwiICtcclxuICAgICAgICAnPHA+PGlucHV0IGNsYXNzPVwiZmFuY3lib3gtc2hhcmVfX2lucHV0XCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cInt7dXJsX3Jhd319XCIgb25jbGljaz1cInNlbGVjdCgpXCIgLz48L3A+JyArXHJcbiAgICAgICAgXCI8L2Rpdj5cIlxyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICBmdW5jdGlvbiBlc2NhcGVIdG1sKHN0cmluZykge1xyXG4gICAgdmFyIGVudGl0eU1hcCA9IHtcclxuICAgICAgXCImXCI6IFwiJmFtcDtcIixcclxuICAgICAgXCI8XCI6IFwiJmx0O1wiLFxyXG4gICAgICBcIj5cIjogXCImZ3Q7XCIsXHJcbiAgICAgICdcIic6IFwiJnF1b3Q7XCIsXHJcbiAgICAgIFwiJ1wiOiBcIiYjMzk7XCIsXHJcbiAgICAgIFwiL1wiOiBcIiYjeDJGO1wiLFxyXG4gICAgICBcImBcIjogXCImI3g2MDtcIixcclxuICAgICAgXCI9XCI6IFwiJiN4M0Q7XCJcclxuICAgIH07XHJcblxyXG4gICAgcmV0dXJuIFN0cmluZyhzdHJpbmcpLnJlcGxhY2UoL1smPD5cIidgPVxcL10vZywgZnVuY3Rpb24gKHMpIHtcclxuICAgICAgcmV0dXJuIGVudGl0eU1hcFtzXTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgJChkb2N1bWVudCkub24oXCJjbGlja1wiLCBcIltkYXRhLWZhbmN5Ym94LXNoYXJlXVwiLCBmdW5jdGlvbiAoKSB7XHJcbiAgICB2YXIgaW5zdGFuY2UgPSAkLmZhbmN5Ym94LmdldEluc3RhbmNlKCksXHJcbiAgICAgIGN1cnJlbnQgPSBpbnN0YW5jZS5jdXJyZW50IHx8IG51bGwsXHJcbiAgICAgIHVybCxcclxuICAgICAgdHBsO1xyXG5cclxuICAgIGlmICghY3VycmVudCkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCQudHlwZShjdXJyZW50Lm9wdHMuc2hhcmUudXJsKSA9PT0gXCJmdW5jdGlvblwiKSB7XHJcbiAgICAgIHVybCA9IGN1cnJlbnQub3B0cy5zaGFyZS51cmwuYXBwbHkoY3VycmVudCwgW2luc3RhbmNlLCBjdXJyZW50XSk7XHJcbiAgICB9XHJcblxyXG4gICAgdHBsID0gY3VycmVudC5vcHRzLnNoYXJlLnRwbFxyXG4gICAgICAucmVwbGFjZSgvXFx7XFx7bWVkaWFcXH1cXH0vZywgY3VycmVudC50eXBlID09PSBcImltYWdlXCIgPyBlbmNvZGVVUklDb21wb25lbnQoY3VycmVudC5zcmMpIDogXCJcIilcclxuICAgICAgLnJlcGxhY2UoL1xce1xce3VybFxcfVxcfS9nLCBlbmNvZGVVUklDb21wb25lbnQodXJsKSlcclxuICAgICAgLnJlcGxhY2UoL1xce1xce3VybF9yYXdcXH1cXH0vZywgZXNjYXBlSHRtbCh1cmwpKVxyXG4gICAgICAucmVwbGFjZSgvXFx7XFx7ZGVzY3JcXH1cXH0vZywgaW5zdGFuY2UuJGNhcHRpb24gPyBlbmNvZGVVUklDb21wb25lbnQoaW5zdGFuY2UuJGNhcHRpb24udGV4dCgpKSA6IFwiXCIpO1xyXG5cclxuICAgICQuZmFuY3lib3gub3Blbih7XHJcbiAgICAgIHNyYzogaW5zdGFuY2UudHJhbnNsYXRlKGluc3RhbmNlLCB0cGwpLFxyXG4gICAgICB0eXBlOiBcImh0bWxcIixcclxuICAgICAgb3B0czoge1xyXG4gICAgICAgIHRvdWNoOiBmYWxzZSxcclxuICAgICAgICBhbmltYXRpb25FZmZlY3Q6IGZhbHNlLFxyXG4gICAgICAgIGFmdGVyTG9hZDogZnVuY3Rpb24gKHNoYXJlSW5zdGFuY2UsIHNoYXJlQ3VycmVudCkge1xyXG4gICAgICAgICAgLy8gQ2xvc2Ugc2VsZiBpZiBwYXJlbnQgaW5zdGFuY2UgaXMgY2xvc2luZ1xyXG4gICAgICAgICAgaW5zdGFuY2UuJHJlZnMuY29udGFpbmVyLm9uZShcImJlZm9yZUNsb3NlLmZiXCIsIGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAgICAgc2hhcmVJbnN0YW5jZS5jbG9zZShudWxsLCAwKTtcclxuICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgIC8vIE9wZW5pbmcgbGlua3MgaW4gYSBwb3B1cCB3aW5kb3dcclxuICAgICAgICAgIHNoYXJlQ3VycmVudC4kY29udGVudC5maW5kKFwiLmZhbmN5Ym94LXNoYXJlX19idXR0b25cIikuY2xpY2soZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICB3aW5kb3cub3Blbih0aGlzLmhyZWYsIFwiU2hhcmVcIiwgXCJ3aWR0aD01NTAsIGhlaWdodD00NTBcIik7XHJcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICAgIH0pO1xyXG4gICAgICAgIH0sXHJcbiAgICAgICAgbW9iaWxlOiB7XHJcbiAgICAgICAgICBhdXRvRm9jdXM6IGZhbHNlXHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9KTtcclxufSkoZG9jdW1lbnQsIGpRdWVyeSk7XG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4vL1xyXG4vLyBIYXNoXHJcbi8vIEVuYWJsZXMgbGlua2luZyB0byBlYWNoIG1vZGFsXHJcbi8vXHJcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbihmdW5jdGlvbiAod2luZG93LCBkb2N1bWVudCwgJCkge1xyXG4gIFwidXNlIHN0cmljdFwiO1xyXG5cclxuICAvLyBTaW1wbGUgJC5lc2NhcGVTZWxlY3RvciBwb2x5ZmlsbCAoZm9yIGpRdWVyeSBwcmlvciB2MylcclxuICBpZiAoISQuZXNjYXBlU2VsZWN0b3IpIHtcclxuICAgICQuZXNjYXBlU2VsZWN0b3IgPSBmdW5jdGlvbiAoc2VsKSB7XHJcbiAgICAgIHZhciByY3NzZXNjYXBlID0gLyhbXFwwLVxceDFmXFx4N2ZdfF4tP1xcZCl8Xi0kfFteXFx4ODAtXFx1RkZGRlxcdy1dL2c7XHJcbiAgICAgIHZhciBmY3NzZXNjYXBlID0gZnVuY3Rpb24gKGNoLCBhc0NvZGVQb2ludCkge1xyXG4gICAgICAgIGlmIChhc0NvZGVQb2ludCkge1xyXG4gICAgICAgICAgLy8gVSswMDAwIE5VTEwgYmVjb21lcyBVK0ZGRkQgUkVQTEFDRU1FTlQgQ0hBUkFDVEVSXHJcbiAgICAgICAgICBpZiAoY2ggPT09IFwiXFwwXCIpIHtcclxuICAgICAgICAgICAgcmV0dXJuIFwiXFx1RkZGRFwiO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIC8vIENvbnRyb2wgY2hhcmFjdGVycyBhbmQgKGRlcGVuZGVudCB1cG9uIHBvc2l0aW9uKSBudW1iZXJzIGdldCBlc2NhcGVkIGFzIGNvZGUgcG9pbnRzXHJcbiAgICAgICAgICByZXR1cm4gY2guc2xpY2UoMCwgLTEpICsgXCJcXFxcXCIgKyBjaC5jaGFyQ29kZUF0KGNoLmxlbmd0aCAtIDEpLnRvU3RyaW5nKDE2KSArIFwiIFwiO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gT3RoZXIgcG90ZW50aWFsbHktc3BlY2lhbCBBU0NJSSBjaGFyYWN0ZXJzIGdldCBiYWNrc2xhc2gtZXNjYXBlZFxyXG4gICAgICAgIHJldHVybiBcIlxcXFxcIiArIGNoO1xyXG4gICAgICB9O1xyXG5cclxuICAgICAgcmV0dXJuIChzZWwgKyBcIlwiKS5yZXBsYWNlKHJjc3Nlc2NhcGUsIGZjc3Nlc2NhcGUpO1xyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIC8vIEdldCBpbmZvIGFib3V0IGdhbGxlcnkgbmFtZSBhbmQgY3VycmVudCBpbmRleCBmcm9tIHVybFxyXG4gIGZ1bmN0aW9uIHBhcnNlVXJsKCkge1xyXG4gICAgdmFyIGhhc2ggPSB3aW5kb3cubG9jYXRpb24uaGFzaC5zdWJzdHIoMSksXHJcbiAgICAgIHJleiA9IGhhc2guc3BsaXQoXCItXCIpLFxyXG4gICAgICBpbmRleCA9IHJlei5sZW5ndGggPiAxICYmIC9eXFwrP1xcZCskLy50ZXN0KHJleltyZXoubGVuZ3RoIC0gMV0pID8gcGFyc2VJbnQocmV6LnBvcCgtMSksIDEwKSB8fCAxIDogMSxcclxuICAgICAgZ2FsbGVyeSA9IHJlei5qb2luKFwiLVwiKTtcclxuXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBoYXNoOiBoYXNoLFxyXG4gICAgICAvKiBJbmRleCBpcyBzdGFydGluZyBmcm9tIDEgKi9cclxuICAgICAgaW5kZXg6IGluZGV4IDwgMSA/IDEgOiBpbmRleCxcclxuICAgICAgZ2FsbGVyeTogZ2FsbGVyeVxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIC8vIFRyaWdnZXIgY2xpY2sgZXZudCBvbiBsaW5rcyB0byBvcGVuIG5ldyBmYW5jeUJveCBpbnN0YW5jZVxyXG4gIGZ1bmN0aW9uIHRyaWdnZXJGcm9tVXJsKHVybCkge1xyXG4gICAgaWYgKHVybC5nYWxsZXJ5ICE9PSBcIlwiKSB7XHJcbiAgICAgIC8vIElmIHdlIGNhbiBmaW5kIGVsZW1lbnQgbWF0Y2hpbmcgJ2RhdGEtZmFuY3lib3gnIGF0cmlidXRlLFxyXG4gICAgICAvLyB0aGVuIHRyaWdnZXJpbmcgY2xpY2sgZXZlbnQgc2hvdWxkIHN0YXJ0IGZhbmN5Qm94XHJcbiAgICAgICQoXCJbZGF0YS1mYW5jeWJveD0nXCIgKyAkLmVzY2FwZVNlbGVjdG9yKHVybC5nYWxsZXJ5KSArIFwiJ11cIilcclxuICAgICAgICAuZXEodXJsLmluZGV4IC0gMSlcclxuICAgICAgICAuZm9jdXMoKVxyXG4gICAgICAgIC50cmlnZ2VyKFwiY2xpY2suZmItc3RhcnRcIik7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgZ2FsbGVyeSBuYW1lIGZyb20gY3VycmVudCBpbnN0YW5jZVxyXG4gIGZ1bmN0aW9uIGdldEdhbGxlcnlJRChpbnN0YW5jZSkge1xyXG4gICAgdmFyIG9wdHMsIHJldDtcclxuXHJcbiAgICBpZiAoIWluc3RhbmNlKSB7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICBvcHRzID0gaW5zdGFuY2UuY3VycmVudCA/IGluc3RhbmNlLmN1cnJlbnQub3B0cyA6IGluc3RhbmNlLm9wdHM7XHJcbiAgICByZXQgPSBvcHRzLmhhc2ggfHwgKG9wdHMuJG9yaWcgPyBvcHRzLiRvcmlnLmRhdGEoXCJmYW5jeWJveFwiKSB8fCBvcHRzLiRvcmlnLmRhdGEoXCJmYW5jeWJveC10cmlnZ2VyXCIpIDogXCJcIik7XHJcblxyXG4gICAgcmV0dXJuIHJldCA9PT0gXCJcIiA/IGZhbHNlIDogcmV0O1xyXG4gIH1cclxuXHJcbiAgLy8gU3RhcnQgd2hlbiBET00gYmVjb21lcyByZWFkeVxyXG4gICQoZnVuY3Rpb24gKCkge1xyXG4gICAgLy8gQ2hlY2sgaWYgdXNlciBoYXMgZGlzYWJsZWQgdGhpcyBtb2R1bGVcclxuICAgIGlmICgkLmZhbmN5Ym94LmRlZmF1bHRzLmhhc2ggPT09IGZhbHNlKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBVcGRhdGUgaGFzaCB3aGVuIG9wZW5pbmcvY2xvc2luZyBmYW5jeUJveFxyXG4gICAgJChkb2N1bWVudCkub24oe1xyXG4gICAgICBcIm9uSW5pdC5mYlwiOiBmdW5jdGlvbiAoZSwgaW5zdGFuY2UpIHtcclxuICAgICAgICB2YXIgdXJsLCBnYWxsZXJ5O1xyXG5cclxuICAgICAgICBpZiAoaW5zdGFuY2UuZ3JvdXBbaW5zdGFuY2UuY3VyckluZGV4XS5vcHRzLmhhc2ggPT09IGZhbHNlKSB7XHJcbiAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB1cmwgPSBwYXJzZVVybCgpO1xyXG4gICAgICAgIGdhbGxlcnkgPSBnZXRHYWxsZXJ5SUQoaW5zdGFuY2UpO1xyXG5cclxuICAgICAgICAvLyBNYWtlIHN1cmUgZ2FsbGVyeSBzdGFydCBpbmRleCBtYXRjaGVzIGluZGV4IGZyb20gaGFzaFxyXG4gICAgICAgIGlmIChnYWxsZXJ5ICYmIHVybC5nYWxsZXJ5ICYmIGdhbGxlcnkgPT0gdXJsLmdhbGxlcnkpIHtcclxuICAgICAgICAgIGluc3RhbmNlLmN1cnJJbmRleCA9IHVybC5pbmRleCAtIDE7XHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG5cclxuICAgICAgXCJiZWZvcmVTaG93LmZiXCI6IGZ1bmN0aW9uIChlLCBpbnN0YW5jZSwgY3VycmVudCwgZmlyc3RSdW4pIHtcclxuICAgICAgICB2YXIgZ2FsbGVyeTtcclxuXHJcbiAgICAgICAgaWYgKCFjdXJyZW50IHx8IGN1cnJlbnQub3B0cy5oYXNoID09PSBmYWxzZSkge1xyXG4gICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaWYgbmVlZCB0byB1cGRhdGUgd2luZG93IGhhc2hcclxuICAgICAgICBnYWxsZXJ5ID0gZ2V0R2FsbGVyeUlEKGluc3RhbmNlKTtcclxuXHJcbiAgICAgICAgaWYgKCFnYWxsZXJ5KSB7XHJcbiAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBWYXJpYWJsZSBjb250YWluaW5nIGxhc3QgaGFzaCB2YWx1ZSBzZXQgYnkgZmFuY3lCb3hcclxuICAgICAgICAvLyBJdCB3aWxsIGJlIHVzZWQgdG8gZGV0ZXJtaW5lIGlmIGZhbmN5Qm94IG5lZWRzIHRvIGNsb3NlIGFmdGVyIGhhc2ggY2hhbmdlIGlzIGRldGVjdGVkXHJcbiAgICAgICAgaW5zdGFuY2UuY3VycmVudEhhc2ggPSBnYWxsZXJ5ICsgKGluc3RhbmNlLmdyb3VwLmxlbmd0aCA+IDEgPyBcIi1cIiArIChjdXJyZW50LmluZGV4ICsgMSkgOiBcIlwiKTtcclxuXHJcbiAgICAgICAgLy8gSWYgY3VycmVudCBoYXNoIGlzIHRoZSBzYW1lICh0aGlzIGluc3RhbmNlIG1vc3QgbGlrZWx5IGlzIG9wZW5lZCBieSBoYXNoY2hhbmdlKSwgdGhlbiBkbyBub3RoaW5nXHJcbiAgICAgICAgaWYgKHdpbmRvdy5sb2NhdGlvbi5oYXNoID09PSBcIiNcIiArIGluc3RhbmNlLmN1cnJlbnRIYXNoKSB7XHJcbiAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoZmlyc3RSdW4gJiYgIWluc3RhbmNlLm9yaWdIYXNoKSB7XHJcbiAgICAgICAgICBpbnN0YW5jZS5vcmlnSGFzaCA9IHdpbmRvdy5sb2NhdGlvbi5oYXNoO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKGluc3RhbmNlLmhhc2hUaW1lcikge1xyXG4gICAgICAgICAgY2xlYXJUaW1lb3V0KGluc3RhbmNlLmhhc2hUaW1lcik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBVcGRhdGUgaGFzaFxyXG4gICAgICAgIGluc3RhbmNlLmhhc2hUaW1lciA9IHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgaWYgKFwicmVwbGFjZVN0YXRlXCIgaW4gd2luZG93Lmhpc3RvcnkpIHtcclxuICAgICAgICAgICAgd2luZG93Lmhpc3RvcnlbZmlyc3RSdW4gPyBcInB1c2hTdGF0ZVwiIDogXCJyZXBsYWNlU3RhdGVcIl0oe30sXHJcbiAgICAgICAgICAgICAgZG9jdW1lbnQudGl0bGUsXHJcbiAgICAgICAgICAgICAgd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lICsgd2luZG93LmxvY2F0aW9uLnNlYXJjaCArIFwiI1wiICsgaW5zdGFuY2UuY3VycmVudEhhc2hcclxuICAgICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICAgIGlmIChmaXJzdFJ1bikge1xyXG4gICAgICAgICAgICAgIGluc3RhbmNlLmhhc0NyZWF0ZWRIaXN0b3J5ID0gdHJ1ZTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgd2luZG93LmxvY2F0aW9uLmhhc2ggPSBpbnN0YW5jZS5jdXJyZW50SGFzaDtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICBpbnN0YW5jZS5oYXNoVGltZXIgPSBudWxsO1xyXG4gICAgICAgIH0sIDMwMCk7XHJcbiAgICAgIH0sXHJcblxyXG4gICAgICBcImJlZm9yZUNsb3NlLmZiXCI6IGZ1bmN0aW9uIChlLCBpbnN0YW5jZSwgY3VycmVudCkge1xyXG4gICAgICAgIGlmICghY3VycmVudCB8fCBjdXJyZW50Lm9wdHMuaGFzaCA9PT0gZmFsc2UpIHtcclxuICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGNsZWFyVGltZW91dChpbnN0YW5jZS5oYXNoVGltZXIpO1xyXG5cclxuICAgICAgICAvLyBHb3RvIHByZXZpb3VzIGhpc3RvcnkgZW50cnlcclxuICAgICAgICBpZiAoaW5zdGFuY2UuY3VycmVudEhhc2ggJiYgaW5zdGFuY2UuaGFzQ3JlYXRlZEhpc3RvcnkpIHtcclxuICAgICAgICAgIHdpbmRvdy5oaXN0b3J5LmJhY2soKTtcclxuICAgICAgICB9IGVsc2UgaWYgKGluc3RhbmNlLmN1cnJlbnRIYXNoKSB7XHJcbiAgICAgICAgICBpZiAoXCJyZXBsYWNlU3RhdGVcIiBpbiB3aW5kb3cuaGlzdG9yeSkge1xyXG4gICAgICAgICAgICB3aW5kb3cuaGlzdG9yeS5yZXBsYWNlU3RhdGUoe30sIGRvY3VtZW50LnRpdGxlLCB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUgKyB3aW5kb3cubG9jYXRpb24uc2VhcmNoICsgKGluc3RhbmNlLm9yaWdIYXNoIHx8IFwiXCIpKTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHdpbmRvdy5sb2NhdGlvbi5oYXNoID0gaW5zdGFuY2Uub3JpZ0hhc2g7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpbnN0YW5jZS5jdXJyZW50SGFzaCA9IG51bGw7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIG5lZWQgdG8gc3RhcnQvY2xvc2UgYWZ0ZXIgdXJsIGhhcyBjaGFuZ2VkXHJcbiAgICAkKHdpbmRvdykub24oXCJoYXNoY2hhbmdlLmZiXCIsIGZ1bmN0aW9uICgpIHtcclxuICAgICAgdmFyIHVybCA9IHBhcnNlVXJsKCksXHJcbiAgICAgICAgZmIgPSBudWxsO1xyXG5cclxuICAgICAgLy8gRmluZCBsYXN0IGZhbmN5Qm94IGluc3RhbmNlIHRoYXQgaGFzIFwiaGFzaFwiXHJcbiAgICAgICQuZWFjaChcclxuICAgICAgICAkKFwiLmZhbmN5Ym94LWNvbnRhaW5lclwiKVxyXG4gICAgICAgIC5nZXQoKVxyXG4gICAgICAgIC5yZXZlcnNlKCksXHJcbiAgICAgICAgZnVuY3Rpb24gKGluZGV4LCB2YWx1ZSkge1xyXG4gICAgICAgICAgdmFyIHRtcCA9ICQodmFsdWUpLmRhdGEoXCJGYW5jeUJveFwiKTtcclxuXHJcbiAgICAgICAgICBpZiAodG1wICYmIHRtcC5jdXJyZW50SGFzaCkge1xyXG4gICAgICAgICAgICBmYiA9IHRtcDtcclxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuXHJcbiAgICAgIGlmIChmYikge1xyXG4gICAgICAgIC8vIE5vdywgY29tcGFyZSBoYXNoIHZhbHVlc1xyXG4gICAgICAgIGlmIChmYi5jdXJyZW50SGFzaCAhPT0gdXJsLmdhbGxlcnkgKyBcIi1cIiArIHVybC5pbmRleCAmJiAhKHVybC5pbmRleCA9PT0gMSAmJiBmYi5jdXJyZW50SGFzaCA9PSB1cmwuZ2FsbGVyeSkpIHtcclxuICAgICAgICAgIGZiLmN1cnJlbnRIYXNoID0gbnVsbDtcclxuXHJcbiAgICAgICAgICBmYi5jbG9zZSgpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSBlbHNlIGlmICh1cmwuZ2FsbGVyeSAhPT0gXCJcIikge1xyXG4gICAgICAgIHRyaWdnZXJGcm9tVXJsKHVybCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIC8vIENoZWNrIGN1cnJlbnQgaGFzaCBhbmQgdHJpZ2dlciBjbGljayBldmVudCBvbiBtYXRjaGluZyBlbGVtZW50IHRvIHN0YXJ0IGZhbmN5Qm94LCBpZiBuZWVkZWRcclxuICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xyXG4gICAgICBpZiAoISQuZmFuY3lib3guZ2V0SW5zdGFuY2UoKSkge1xyXG4gICAgICAgIHRyaWdnZXJGcm9tVXJsKHBhcnNlVXJsKCkpO1xyXG4gICAgICB9XHJcbiAgICB9LCA1MCk7XHJcbiAgfSk7XHJcbn0pKHdpbmRvdywgZG9jdW1lbnQsIGpRdWVyeSk7XG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxyXG4vL1xyXG4vLyBXaGVlbFxyXG4vLyBCYXNpYyBtb3VzZSB3ZWhlZWwgc3VwcG9ydCBmb3IgZ2FsbGVyeSBuYXZpZ2F0aW9uXHJcbi8vXHJcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbihmdW5jdGlvbiAoZG9jdW1lbnQsICQpIHtcclxuICBcInVzZSBzdHJpY3RcIjtcclxuXHJcbiAgdmFyIHByZXZUaW1lID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcblxyXG4gICQoZG9jdW1lbnQpLm9uKHtcclxuICAgIFwib25Jbml0LmZiXCI6IGZ1bmN0aW9uIChlLCBpbnN0YW5jZSwgY3VycmVudCkge1xyXG4gICAgICBpbnN0YW5jZS4kcmVmcy5zdGFnZS5vbihcIm1vdXNld2hlZWwgRE9NTW91c2VTY3JvbGwgd2hlZWwgTW96TW91c2VQaXhlbFNjcm9sbFwiLCBmdW5jdGlvbiAoZSkge1xyXG4gICAgICAgIHZhciBjdXJyZW50ID0gaW5zdGFuY2UuY3VycmVudCxcclxuICAgICAgICAgIGN1cnJUaW1lID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcblxyXG4gICAgICAgIGlmIChpbnN0YW5jZS5ncm91cC5sZW5ndGggPCAyIHx8IGN1cnJlbnQub3B0cy53aGVlbCA9PT0gZmFsc2UgfHwgKGN1cnJlbnQub3B0cy53aGVlbCA9PT0gXCJhdXRvXCIgJiYgY3VycmVudC50eXBlICE9PSBcImltYWdlXCIpKSB7XHJcbiAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuXHJcbiAgICAgICAgaWYgKGN1cnJlbnQuJHNsaWRlLmhhc0NsYXNzKFwiZmFuY3lib3gtYW5pbWF0ZWRcIikpIHtcclxuICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGUgPSBlLm9yaWdpbmFsRXZlbnQgfHwgZTtcclxuXHJcbiAgICAgICAgaWYgKGN1cnJUaW1lIC0gcHJldlRpbWUgPCAyNTApIHtcclxuICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHByZXZUaW1lID0gY3VyclRpbWU7XHJcblxyXG4gICAgICAgIGluc3RhbmNlWygtZS5kZWx0YVkgfHwgLWUuZGVsdGFYIHx8IGUud2hlZWxEZWx0YSB8fCAtZS5kZXRhaWwpIDwgMCA/IFwibmV4dFwiIDogXCJwcmV2aW91c1wiXSgpO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuICB9KTtcclxufSkoZG9jdW1lbnQsIGpRdWVyeSk7Il0sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./node_modules/@fancyapps/fancybox/dist/jquery.fancybox.js\n"); /***/ }), /***/ "./node_modules/bootstrap/dist/js/bootstrap.js": /*!*****************************************************!*\ !*** ./node_modules/bootstrap/dist/js/bootstrap.js ***! \*****************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) { eval("/*!\n * Bootstrap v4.5.2 (https://getbootstrap.com/)\n * Copyright 2011-2020 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n(function (global, factory) {\n true ? factory(exports, __webpack_require__(/*! jquery */ \"./node_modules/jquery/dist/jquery.js\"), __webpack_require__(/*! popper.js */ \"./node_modules/popper.js/dist/esm/popper.js\")) :\n undefined;\n}(this, (function (exports, $, Popper) { 'use strict';\n\n $ = $ && Object.prototype.hasOwnProperty.call($, 'default') ? $['default'] : $;\n Popper = Popper && Object.prototype.hasOwnProperty.call(Popper, 'default') ? Popper['default'] : Popper;\n\n function _defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n }\n\n function _createClass(Constructor, protoProps, staticProps) {\n if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n if (staticProps) _defineProperties(Constructor, staticProps);\n return Constructor;\n }\n\n function _extends() {\n _extends = Object.assign || function (target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = arguments[i];\n\n for (var key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n target[key] = source[key];\n }\n }\n }\n\n return target;\n };\n\n return _extends.apply(this, arguments);\n }\n\n function _inheritsLoose(subClass, superClass) {\n subClass.prototype = Object.create(superClass.prototype);\n subClass.prototype.constructor = subClass;\n subClass.__proto__ = superClass;\n }\n\n /**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.5.2): util.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n /**\n * ------------------------------------------------------------------------\n * Private TransitionEnd Helpers\n * ------------------------------------------------------------------------\n */\n\n var TRANSITION_END = 'transitionend';\n var MAX_UID = 1000000;\n var MILLISECONDS_MULTIPLIER = 1000; // Shoutout AngusCroll (https://goo.gl/pxwQGp)\n\n function toType(obj) {\n if (obj === null || typeof obj === 'undefined') {\n return \"\" + obj;\n }\n\n return {}.toString.call(obj).match(/\\s([a-z]+)/i)[1].toLowerCase();\n }\n\n function getSpecialTransitionEndEvent() {\n return {\n bindType: TRANSITION_END,\n delegateType: TRANSITION_END,\n handle: function handle(event) {\n if ($(event.target).is(this)) {\n return event.handleObj.handler.apply(this, arguments); // eslint-disable-line prefer-rest-params\n }\n\n return undefined;\n }\n };\n }\n\n function transitionEndEmulator(duration) {\n var _this = this;\n\n var called = false;\n $(this).one(Util.TRANSITION_END, function () {\n called = true;\n });\n setTimeout(function () {\n if (!called) {\n Util.triggerTransitionEnd(_this);\n }\n }, duration);\n return this;\n }\n\n function setTransitionEndSupport() {\n $.fn.emulateTransitionEnd = transitionEndEmulator;\n $.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent();\n }\n /**\n * --------------------------------------------------------------------------\n * Public Util Api\n * --------------------------------------------------------------------------\n */\n\n\n var Util = {\n TRANSITION_END: 'bsTransitionEnd',\n getUID: function getUID(prefix) {\n do {\n // eslint-disable-next-line no-bitwise\n prefix += ~~(Math.random() * MAX_UID); // \"~~\" acts like a faster Math.floor() here\n } while (document.getElementById(prefix));\n\n return prefix;\n },\n getSelectorFromElement: function getSelectorFromElement(element) {\n var selector = element.getAttribute('data-target');\n\n if (!selector || selector === '#') {\n var hrefAttr = element.getAttribute('href');\n selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : '';\n }\n\n try {\n return document.querySelector(selector) ? selector : null;\n } catch (err) {\n return null;\n }\n },\n getTransitionDurationFromElement: function getTransitionDurationFromElement(element) {\n if (!element) {\n return 0;\n } // Get transition-duration of the element\n\n\n var transitionDuration = $(element).css('transition-duration');\n var transitionDelay = $(element).css('transition-delay');\n var floatTransitionDuration = parseFloat(transitionDuration);\n var floatTransitionDelay = parseFloat(transitionDelay); // Return 0 if element or transition duration is not found\n\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0;\n } // If multiple durations are defined, take the first\n\n\n transitionDuration = transitionDuration.split(',')[0];\n transitionDelay = transitionDelay.split(',')[0];\n return (parseFloat(transitionDuration) + parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER;\n },\n reflow: function reflow(element) {\n return element.offsetHeight;\n },\n triggerTransitionEnd: function triggerTransitionEnd(element) {\n $(element).trigger(TRANSITION_END);\n },\n // TODO: Remove in v5\n supportsTransitionEnd: function supportsTransitionEnd() {\n return Boolean(TRANSITION_END);\n },\n isElement: function isElement(obj) {\n return (obj[0] || obj).nodeType;\n },\n typeCheckConfig: function typeCheckConfig(componentName, config, configTypes) {\n for (var property in configTypes) {\n if (Object.prototype.hasOwnProperty.call(configTypes, property)) {\n var expectedTypes = configTypes[property];\n var value = config[property];\n var valueType = value && Util.isElement(value) ? 'element' : toType(value);\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new Error(componentName.toUpperCase() + \": \" + (\"Option \\\"\" + property + \"\\\" provided type \\\"\" + valueType + \"\\\" \") + (\"but expected type \\\"\" + expectedTypes + \"\\\".\"));\n }\n }\n }\n },\n findShadowRoot: function findShadowRoot(element) {\n if (!document.documentElement.attachShadow) {\n return null;\n } // Can find the shadow root otherwise it'll return the document\n\n\n if (typeof element.getRootNode === 'function') {\n var root = element.getRootNode();\n return root instanceof ShadowRoot ? root : null;\n }\n\n if (element instanceof ShadowRoot) {\n return element;\n } // when we don't find a shadow root\n\n\n if (!element.parentNode) {\n return null;\n }\n\n return Util.findShadowRoot(element.parentNode);\n },\n jQueryDetection: function jQueryDetection() {\n if (typeof $ === 'undefined') {\n throw new TypeError('Bootstrap\\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\\'s JavaScript.');\n }\n\n var version = $.fn.jquery.split(' ')[0].split('.');\n var minMajor = 1;\n var ltMajor = 2;\n var minMinor = 9;\n var minPatch = 1;\n var maxMajor = 4;\n\n if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) {\n throw new Error('Bootstrap\\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0');\n }\n }\n };\n Util.jQueryDetection();\n setTransitionEndSupport();\n\n /**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\n var NAME = 'alert';\n var VERSION = '4.5.2';\n var DATA_KEY = 'bs.alert';\n var EVENT_KEY = \".\" + DATA_KEY;\n var DATA_API_KEY = '.data-api';\n var JQUERY_NO_CONFLICT = $.fn[NAME];\n var SELECTOR_DISMISS = '[data-dismiss=\"alert\"]';\n var EVENT_CLOSE = \"close\" + EVENT_KEY;\n var EVENT_CLOSED = \"closed\" + EVENT_KEY;\n var EVENT_CLICK_DATA_API = \"click\" + EVENT_KEY + DATA_API_KEY;\n var CLASS_NAME_ALERT = 'alert';\n var CLASS_NAME_FADE = 'fade';\n var CLASS_NAME_SHOW = 'show';\n /**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\n var Alert = /*#__PURE__*/function () {\n function Alert(element) {\n this._element = element;\n } // Getters\n\n\n var _proto = Alert.prototype;\n\n // Public\n _proto.close = function close(element) {\n var rootElement = this._element;\n\n if (element) {\n rootElement = this._getRootElement(element);\n }\n\n var customEvent = this._triggerCloseEvent(rootElement);\n\n if (customEvent.isDefaultPrevented()) {\n return;\n }\n\n this._removeElement(rootElement);\n };\n\n _proto.dispose = function dispose() {\n $.removeData(this._element, DATA_KEY);\n this._element = null;\n } // Private\n ;\n\n _proto._getRootElement = function _getRootElement(element) {\n var selector = Util.getSelectorFromElement(element);\n var parent = false;\n\n if (selector) {\n parent = document.querySelector(selector);\n }\n\n if (!parent) {\n parent = $(element).closest(\".\" + CLASS_NAME_ALERT)[0];\n }\n\n return parent;\n };\n\n _proto._triggerCloseEvent = function _triggerCloseEvent(element) {\n var closeEvent = $.Event(EVENT_CLOSE);\n $(element).trigger(closeEvent);\n return closeEvent;\n };\n\n _proto._removeElement = function _removeElement(element) {\n var _this = this;\n\n $(element).removeClass(CLASS_NAME_SHOW);\n\n if (!$(element).hasClass(CLASS_NAME_FADE)) {\n this._destroyElement(element);\n\n return;\n }\n\n var transitionDuration = Util.getTransitionDurationFromElement(element);\n $(element).one(Util.TRANSITION_END, function (event) {\n return _this._destroyElement(element, event);\n }).emulateTransitionEnd(transitionDuration);\n };\n\n _proto._destroyElement = function _destroyElement(element) {\n $(element).detach().trigger(EVENT_CLOSED).remove();\n } // Static\n ;\n\n Alert._jQueryInterface = function _jQueryInterface(config) {\n return this.each(function () {\n var $element = $(this);\n var data = $element.data(DATA_KEY);\n\n if (!data) {\n data = new Alert(this);\n $element.data(DATA_KEY, data);\n }\n\n if (config === 'close') {\n data[config](this);\n }\n });\n };\n\n Alert._handleDismiss = function _handleDismiss(alertInstance) {\n return function (event) {\n if (event) {\n event.preventDefault();\n }\n\n alertInstance.close(this);\n };\n };\n\n _createClass(Alert, null, [{\n key: \"VERSION\",\n get: function get() {\n return VERSION;\n }\n }]);\n\n return Alert;\n }();\n /**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\n\n $(document).on(EVENT_CLICK_DATA_API, SELECTOR_DISMISS, Alert._handleDismiss(new Alert()));\n /**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\n $.fn[NAME] = Alert._jQueryInterface;\n $.fn[NAME].Constructor = Alert;\n\n $.fn[NAME].noConflict = function () {\n $.fn[NAME] = JQUERY_NO_CONFLICT;\n return Alert._jQueryInterface;\n };\n\n /**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\n var NAME$1 = 'button';\n var VERSION$1 = '4.5.2';\n var DATA_KEY$1 = 'bs.button';\n var EVENT_KEY$1 = \".\" + DATA_KEY$1;\n var DATA_API_KEY$1 = '.data-api';\n var JQUERY_NO_CONFLICT$1 = $.fn[NAME$1];\n var CLASS_NAME_ACTIVE = 'active';\n var CLASS_NAME_BUTTON = 'btn';\n var CLASS_NAME_FOCUS = 'focus';\n var SELECTOR_DATA_TOGGLE_CARROT = '[data-toggle^=\"button\"]';\n var SELECTOR_DATA_TOGGLES = '[data-toggle=\"buttons\"]';\n var SELECTOR_DATA_TOGGLE = '[data-toggle=\"button\"]';\n var SELECTOR_DATA_TOGGLES_BUTTONS = '[data-toggle=\"buttons\"] .btn';\n var SELECTOR_INPUT = 'input:not([type=\"hidden\"])';\n var SELECTOR_ACTIVE = '.active';\n var SELECTOR_BUTTON = '.btn';\n var EVENT_CLICK_DATA_API$1 = \"click\" + EVENT_KEY$1 + DATA_API_KEY$1;\n var EVENT_FOCUS_BLUR_DATA_API = \"focus\" + EVENT_KEY$1 + DATA_API_KEY$1 + \" \" + (\"blur\" + EVENT_KEY$1 + DATA_API_KEY$1);\n var EVENT_LOAD_DATA_API = \"load\" + EVENT_KEY$1 + DATA_API_KEY$1;\n /**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\n var Button = /*#__PURE__*/function () {\n function Button(element) {\n this._element = element;\n } // Getters\n\n\n var _proto = Button.prototype;\n\n // Public\n _proto.toggle = function toggle() {\n var triggerChangeEvent = true;\n var addAriaPressed = true;\n var rootElement = $(this._element).closest(SELECTOR_DATA_TOGGLES)[0];\n\n if (rootElement) {\n var input = this._element.querySelector(SELECTOR_INPUT);\n\n if (input) {\n if (input.type === 'radio') {\n if (input.checked && this._element.classList.contains(CLASS_NAME_ACTIVE)) {\n triggerChangeEvent = false;\n } else {\n var activeElement = rootElement.querySelector(SELECTOR_ACTIVE);\n\n if (activeElement) {\n $(activeElement).removeClass(CLASS_NAME_ACTIVE);\n }\n }\n }\n\n if (triggerChangeEvent) {\n // if it's not a radio button or checkbox don't add a pointless/invalid checked property to the input\n if (input.type === 'checkbox' || input.type === 'radio') {\n input.checked = !this._element.classList.contains(CLASS_NAME_ACTIVE);\n }\n\n $(input).trigger('change');\n }\n\n input.focus();\n addAriaPressed = false;\n }\n }\n\n if (!(this._element.hasAttribute('disabled') || this._element.classList.contains('disabled'))) {\n if (addAriaPressed) {\n this._element.setAttribute('aria-pressed', !this._element.classList.contains(CLASS_NAME_ACTIVE));\n }\n\n if (triggerChangeEvent) {\n $(this._element).toggleClass(CLASS_NAME_ACTIVE);\n }\n }\n };\n\n _proto.dispose = function dispose() {\n $.removeData(this._element, DATA_KEY$1);\n this._element = null;\n } // Static\n ;\n\n Button._jQueryInterface = function _jQueryInterface(config) {\n return this.each(function () {\n var data = $(this).data(DATA_KEY$1);\n\n if (!data) {\n data = new Button(this);\n $(this).data(DATA_KEY$1, data);\n }\n\n if (config === 'toggle') {\n data[config]();\n }\n });\n };\n\n _createClass(Button, null, [{\n key: \"VERSION\",\n get: function get() {\n return VERSION$1;\n }\n }]);\n\n return Button;\n }();\n /**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\n\n $(document).on(EVENT_CLICK_DATA_API$1, SELECTOR_DATA_TOGGLE_CARROT, function (event) {\n var button = event.target;\n var initialButton = button;\n\n if (!$(button).hasClass(CLASS_NAME_BUTTON)) {\n button = $(button).closest(SELECTOR_BUTTON)[0];\n }\n\n if (!button || button.hasAttribute('disabled') || button.classList.contains('disabled')) {\n event.preventDefault(); // work around Firefox bug #1540995\n } else {\n var inputBtn = button.querySelector(SELECTOR_INPUT);\n\n if (inputBtn && (inputBtn.hasAttribute('disabled') || inputBtn.classList.contains('disabled'))) {\n event.preventDefault(); // work around Firefox bug #1540995\n\n return;\n }\n\n if (initialButton.tagName !== 'LABEL' || inputBtn && inputBtn.type !== 'checkbox') {\n Button._jQueryInterface.call($(button), 'toggle');\n }\n }\n }).on(EVENT_FOCUS_BLUR_DATA_API, SELECTOR_DATA_TOGGLE_CARROT, function (event) {\n var button = $(event.target).closest(SELECTOR_BUTTON)[0];\n $(button).toggleClass(CLASS_NAME_FOCUS, /^focus(in)?$/.test(event.type));\n });\n $(window).on(EVENT_LOAD_DATA_API, function () {\n // ensure correct active class is set to match the controls' actual values/states\n // find all checkboxes/readio buttons inside data-toggle groups\n var buttons = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLES_BUTTONS));\n\n for (var i = 0, len = buttons.length; i < len; i++) {\n var button = buttons[i];\n var input = button.querySelector(SELECTOR_INPUT);\n\n if (input.checked || input.hasAttribute('checked')) {\n button.classList.add(CLASS_NAME_ACTIVE);\n } else {\n button.classList.remove(CLASS_NAME_ACTIVE);\n }\n } // find all button toggles\n\n\n buttons = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE));\n\n for (var _i = 0, _len = buttons.length; _i < _len; _i++) {\n var _button = buttons[_i];\n\n if (_button.getAttribute('aria-pressed') === 'true') {\n _button.classList.add(CLASS_NAME_ACTIVE);\n } else {\n _button.classList.remove(CLASS_NAME_ACTIVE);\n }\n }\n });\n /**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\n $.fn[NAME$1] = Button._jQueryInterface;\n $.fn[NAME$1].Constructor = Button;\n\n $.fn[NAME$1].noConflict = function () {\n $.fn[NAME$1] = JQUERY_NO_CONFLICT$1;\n return Button._jQueryInterface;\n };\n\n /**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\n var NAME$2 = 'carousel';\n var VERSION$2 = '4.5.2';\n var DATA_KEY$2 = 'bs.carousel';\n var EVENT_KEY$2 = \".\" + DATA_KEY$2;\n var DATA_API_KEY$2 = '.data-api';\n var JQUERY_NO_CONFLICT$2 = $.fn[NAME$2];\n var ARROW_LEFT_KEYCODE = 37; // KeyboardEvent.which value for left arrow key\n\n var ARROW_RIGHT_KEYCODE = 39; // KeyboardEvent.which value for right arrow key\n\n var TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch\n\n var SWIPE_THRESHOLD = 40;\n var Default = {\n interval: 5000,\n keyboard: true,\n slide: false,\n pause: 'hover',\n wrap: true,\n touch: true\n };\n var DefaultType = {\n interval: '(number|boolean)',\n keyboard: 'boolean',\n slide: '(boolean|string)',\n pause: '(string|boolean)',\n wrap: 'boolean',\n touch: 'boolean'\n };\n var DIRECTION_NEXT = 'next';\n var DIRECTION_PREV = 'prev';\n var DIRECTION_LEFT = 'left';\n var DIRECTION_RIGHT = 'right';\n var EVENT_SLIDE = \"slide\" + EVENT_KEY$2;\n var EVENT_SLID = \"slid\" + EVENT_KEY$2;\n var EVENT_KEYDOWN = \"keydown\" + EVENT_KEY$2;\n var EVENT_MOUSEENTER = \"mouseenter\" + EVENT_KEY$2;\n var EVENT_MOUSELEAVE = \"mouseleave\" + EVENT_KEY$2;\n var EVENT_TOUCHSTART = \"touchstart\" + EVENT_KEY$2;\n var EVENT_TOUCHMOVE = \"touchmove\" + EVENT_KEY$2;\n var EVENT_TOUCHEND = \"touchend\" + EVENT_KEY$2;\n var EVENT_POINTERDOWN = \"pointerdown\" + EVENT_KEY$2;\n var EVENT_POINTERUP = \"pointerup\" + EVENT_KEY$2;\n var EVENT_DRAG_START = \"dragstart\" + EVENT_KEY$2;\n var EVENT_LOAD_DATA_API$1 = \"load\" + EVENT_KEY$2 + DATA_API_KEY$2;\n var EVENT_CLICK_DATA_API$2 = \"click\" + EVENT_KEY$2 + DATA_API_KEY$2;\n var CLASS_NAME_CAROUSEL = 'carousel';\n var CLASS_NAME_ACTIVE$1 = 'active';\n var CLASS_NAME_SLIDE = 'slide';\n var CLASS_NAME_RIGHT = 'carousel-item-right';\n var CLASS_NAME_LEFT = 'carousel-item-left';\n var CLASS_NAME_NEXT = 'carousel-item-next';\n var CLASS_NAME_PREV = 'carousel-item-prev';\n var CLASS_NAME_POINTER_EVENT = 'pointer-event';\n var SELECTOR_ACTIVE$1 = '.active';\n var SELECTOR_ACTIVE_ITEM = '.active.carousel-item';\n var SELECTOR_ITEM = '.carousel-item';\n var SELECTOR_ITEM_IMG = '.carousel-item img';\n var SELECTOR_NEXT_PREV = '.carousel-item-next, .carousel-item-prev';\n var SELECTOR_INDICATORS = '.carousel-indicators';\n var SELECTOR_DATA_SLIDE = '[data-slide], [data-slide-to]';\n var SELECTOR_DATA_RIDE = '[data-ride=\"carousel\"]';\n var PointerType = {\n TOUCH: 'touch',\n PEN: 'pen'\n };\n /**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\n var Carousel = /*#__PURE__*/function () {\n function Carousel(element, config) {\n this._items = null;\n this._interval = null;\n this._activeElement = null;\n this._isPaused = false;\n this._isSliding = false;\n this.touchTimeout = null;\n this.touchStartX = 0;\n this.touchDeltaX = 0;\n this._config = this._getConfig(config);\n this._element = element;\n this._indicatorsElement = this._element.querySelector(SELECTOR_INDICATORS);\n this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0;\n this._pointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent);\n\n this._addEventListeners();\n } // Getters\n\n\n var _proto = Carousel.prototype;\n\n // Public\n _proto.next = function next() {\n if (!this._isSliding) {\n this._slide(DIRECTION_NEXT);\n }\n };\n\n _proto.nextWhenVisible = function nextWhenVisible() {\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden && $(this._element).is(':visible') && $(this._element).css('visibility') !== 'hidden') {\n this.next();\n }\n };\n\n _proto.prev = function prev() {\n if (!this._isSliding) {\n this._slide(DIRECTION_PREV);\n }\n };\n\n _proto.pause = function pause(event) {\n if (!event) {\n this._isPaused = true;\n }\n\n if (this._element.querySelector(SELECTOR_NEXT_PREV)) {\n Util.triggerTransitionEnd(this._element);\n this.cycle(true);\n }\n\n clearInterval(this._interval);\n this._interval = null;\n };\n\n _proto.cycle = function cycle(event) {\n if (!event) {\n this._isPaused = false;\n }\n\n if (this._interval) {\n clearInterval(this._interval);\n this._interval = null;\n }\n\n if (this._config.interval && !this._isPaused) {\n this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval);\n }\n };\n\n _proto.to = function to(index) {\n var _this = this;\n\n this._activeElement = this._element.querySelector(SELECTOR_ACTIVE_ITEM);\n\n var activeIndex = this._getItemIndex(this._activeElement);\n\n if (index > this._items.length - 1 || index < 0) {\n return;\n }\n\n if (this._isSliding) {\n $(this._element).one(EVENT_SLID, function () {\n return _this.to(index);\n });\n return;\n }\n\n if (activeIndex === index) {\n this.pause();\n this.cycle();\n return;\n }\n\n var direction = index > activeIndex ? DIRECTION_NEXT : DIRECTION_PREV;\n\n this._slide(direction, this._items[index]);\n };\n\n _proto.dispose = function dispose() {\n $(this._element).off(EVENT_KEY$2);\n $.removeData(this._element, DATA_KEY$2);\n this._items = null;\n this._config = null;\n this._element = null;\n this._interval = null;\n this._isPaused = null;\n this._isSliding = null;\n this._activeElement = null;\n this._indicatorsElement = null;\n } // Private\n ;\n\n _proto._getConfig = function _getConfig(config) {\n config = _extends({}, Default, config);\n Util.typeCheckConfig(NAME$2, config, DefaultType);\n return config;\n };\n\n _proto._handleSwipe = function _handleSwipe() {\n var absDeltax = Math.abs(this.touchDeltaX);\n\n if (absDeltax <= SWIPE_THRESHOLD) {\n return;\n }\n\n var direction = absDeltax / this.touchDeltaX;\n this.touchDeltaX = 0; // swipe left\n\n if (direction > 0) {\n this.prev();\n } // swipe right\n\n\n if (direction < 0) {\n this.next();\n }\n };\n\n _proto._addEventListeners = function _addEventListeners() {\n var _this2 = this;\n\n if (this._config.keyboard) {\n $(this._element).on(EVENT_KEYDOWN, function (event) {\n return _this2._keydown(event);\n });\n }\n\n if (this._config.pause === 'hover') {\n $(this._element).on(EVENT_MOUSEENTER, function (event) {\n return _this2.pause(event);\n }).on(EVENT_MOUSELEAVE, function (event) {\n return _this2.cycle(event);\n });\n }\n\n if (this._config.touch) {\n this._addTouchEventListeners();\n }\n };\n\n _proto._addTouchEventListeners = function _addTouchEventListeners() {\n var _this3 = this;\n\n if (!this._touchSupported) {\n return;\n }\n\n var start = function start(event) {\n if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {\n _this3.touchStartX = event.originalEvent.clientX;\n } else if (!_this3._pointerEvent) {\n _this3.touchStartX = event.originalEvent.touches[0].clientX;\n }\n };\n\n var move = function move(event) {\n // ensure swiping with one touch and not pinching\n if (event.originalEvent.touches && event.originalEvent.touches.length > 1) {\n _this3.touchDeltaX = 0;\n } else {\n _this3.touchDeltaX = event.originalEvent.touches[0].clientX - _this3.touchStartX;\n }\n };\n\n var end = function end(event) {\n if (_this3._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {\n _this3.touchDeltaX = event.originalEvent.clientX - _this3.touchStartX;\n }\n\n _this3._handleSwipe();\n\n if (_this3._config.pause === 'hover') {\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n _this3.pause();\n\n if (_this3.touchTimeout) {\n clearTimeout(_this3.touchTimeout);\n }\n\n _this3.touchTimeout = setTimeout(function (event) {\n return _this3.cycle(event);\n }, TOUCHEVENT_COMPAT_WAIT + _this3._config.interval);\n }\n };\n\n $(this._element.querySelectorAll(SELECTOR_ITEM_IMG)).on(EVENT_DRAG_START, function (e) {\n return e.preventDefault();\n });\n\n if (this._pointerEvent) {\n $(this._element).on(EVENT_POINTERDOWN, function (event) {\n return start(event);\n });\n $(this._element).on(EVENT_POINTERUP, function (event) {\n return end(event);\n });\n\n this._element.classList.add(CLASS_NAME_POINTER_EVENT);\n } else {\n $(this._element).on(EVENT_TOUCHSTART, function (event) {\n return start(event);\n });\n $(this._element).on(EVENT_TOUCHMOVE, function (event) {\n return move(event);\n });\n $(this._element).on(EVENT_TOUCHEND, function (event) {\n return end(event);\n });\n }\n };\n\n _proto._keydown = function _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return;\n }\n\n switch (event.which) {\n case ARROW_LEFT_KEYCODE:\n event.preventDefault();\n this.prev();\n break;\n\n case ARROW_RIGHT_KEYCODE:\n event.preventDefault();\n this.next();\n break;\n }\n };\n\n _proto._getItemIndex = function _getItemIndex(element) {\n this._items = element && element.parentNode ? [].slice.call(element.parentNode.querySelectorAll(SELECTOR_ITEM)) : [];\n return this._items.indexOf(element);\n };\n\n _proto._getItemByDirection = function _getItemByDirection(direction, activeElement) {\n var isNextDirection = direction === DIRECTION_NEXT;\n var isPrevDirection = direction === DIRECTION_PREV;\n\n var activeIndex = this._getItemIndex(activeElement);\n\n var lastItemIndex = this._items.length - 1;\n var isGoingToWrap = isPrevDirection && activeIndex === 0 || isNextDirection && activeIndex === lastItemIndex;\n\n if (isGoingToWrap && !this._config.wrap) {\n return activeElement;\n }\n\n var delta = direction === DIRECTION_PREV ? -1 : 1;\n var itemIndex = (activeIndex + delta) % this._items.length;\n return itemIndex === -1 ? this._items[this._items.length - 1] : this._items[itemIndex];\n };\n\n _proto._triggerSlideEvent = function _triggerSlideEvent(relatedTarget, eventDirectionName) {\n var targetIndex = this._getItemIndex(relatedTarget);\n\n var fromIndex = this._getItemIndex(this._element.querySelector(SELECTOR_ACTIVE_ITEM));\n\n var slideEvent = $.Event(EVENT_SLIDE, {\n relatedTarget: relatedTarget,\n direction: eventDirectionName,\n from: fromIndex,\n to: targetIndex\n });\n $(this._element).trigger(slideEvent);\n return slideEvent;\n };\n\n _proto._setActiveIndicatorElement = function _setActiveIndicatorElement(element) {\n if (this._indicatorsElement) {\n var indicators = [].slice.call(this._indicatorsElement.querySelectorAll(SELECTOR_ACTIVE$1));\n $(indicators).removeClass(CLASS_NAME_ACTIVE$1);\n\n var nextIndicator = this._indicatorsElement.children[this._getItemIndex(element)];\n\n if (nextIndicator) {\n $(nextIndicator).addClass(CLASS_NAME_ACTIVE$1);\n }\n }\n };\n\n _proto._slide = function _slide(direction, element) {\n var _this4 = this;\n\n var activeElement = this._element.querySelector(SELECTOR_ACTIVE_ITEM);\n\n var activeElementIndex = this._getItemIndex(activeElement);\n\n var nextElement = element || activeElement && this._getItemByDirection(direction, activeElement);\n\n var nextElementIndex = this._getItemIndex(nextElement);\n\n var isCycling = Boolean(this._interval);\n var directionalClassName;\n var orderClassName;\n var eventDirectionName;\n\n if (direction === DIRECTION_NEXT) {\n directionalClassName = CLASS_NAME_LEFT;\n orderClassName = CLASS_NAME_NEXT;\n eventDirectionName = DIRECTION_LEFT;\n } else {\n directionalClassName = CLASS_NAME_RIGHT;\n orderClassName = CLASS_NAME_PREV;\n eventDirectionName = DIRECTION_RIGHT;\n }\n\n if (nextElement && $(nextElement).hasClass(CLASS_NAME_ACTIVE$1)) {\n this._isSliding = false;\n return;\n }\n\n var slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName);\n\n if (slideEvent.isDefaultPrevented()) {\n return;\n }\n\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n return;\n }\n\n this._isSliding = true;\n\n if (isCycling) {\n this.pause();\n }\n\n this._setActiveIndicatorElement(nextElement);\n\n var slidEvent = $.Event(EVENT_SLID, {\n relatedTarget: nextElement,\n direction: eventDirectionName,\n from: activeElementIndex,\n to: nextElementIndex\n });\n\n if ($(this._element).hasClass(CLASS_NAME_SLIDE)) {\n $(nextElement).addClass(orderClassName);\n Util.reflow(nextElement);\n $(activeElement).addClass(directionalClassName);\n $(nextElement).addClass(directionalClassName);\n var nextElementInterval = parseInt(nextElement.getAttribute('data-interval'), 10);\n\n if (nextElementInterval) {\n this._config.defaultInterval = this._config.defaultInterval || this._config.interval;\n this._config.interval = nextElementInterval;\n } else {\n this._config.interval = this._config.defaultInterval || this._config.interval;\n }\n\n var transitionDuration = Util.getTransitionDurationFromElement(activeElement);\n $(activeElement).one(Util.TRANSITION_END, function () {\n $(nextElement).removeClass(directionalClassName + \" \" + orderClassName).addClass(CLASS_NAME_ACTIVE$1);\n $(activeElement).removeClass(CLASS_NAME_ACTIVE$1 + \" \" + orderClassName + \" \" + directionalClassName);\n _this4._isSliding = false;\n setTimeout(function () {\n return $(_this4._element).trigger(slidEvent);\n }, 0);\n }).emulateTransitionEnd(transitionDuration);\n } else {\n $(activeElement).removeClass(CLASS_NAME_ACTIVE$1);\n $(nextElement).addClass(CLASS_NAME_ACTIVE$1);\n this._isSliding = false;\n $(this._element).trigger(slidEvent);\n }\n\n if (isCycling) {\n this.cycle();\n }\n } // Static\n ;\n\n Carousel._jQueryInterface = function _jQueryInterface(config) {\n return this.each(function () {\n var data = $(this).data(DATA_KEY$2);\n\n var _config = _extends({}, Default, $(this).data());\n\n if (typeof config === 'object') {\n _config = _extends({}, _config, config);\n }\n\n var action = typeof config === 'string' ? config : _config.slide;\n\n if (!data) {\n data = new Carousel(this, _config);\n $(this).data(DATA_KEY$2, data);\n }\n\n if (typeof config === 'number') {\n data.to(config);\n } else if (typeof action === 'string') {\n if (typeof data[action] === 'undefined') {\n throw new TypeError(\"No method named \\\"\" + action + \"\\\"\");\n }\n\n data[action]();\n } else if (_config.interval && _config.ride) {\n data.pause();\n data.cycle();\n }\n });\n };\n\n Carousel._dataApiClickHandler = function _dataApiClickHandler(event) {\n var selector = Util.getSelectorFromElement(this);\n\n if (!selector) {\n return;\n }\n\n var target = $(selector)[0];\n\n if (!target || !$(target).hasClass(CLASS_NAME_CAROUSEL)) {\n return;\n }\n\n var config = _extends({}, $(target).data(), $(this).data());\n\n var slideIndex = this.getAttribute('data-slide-to');\n\n if (slideIndex) {\n config.interval = false;\n }\n\n Carousel._jQueryInterface.call($(target), config);\n\n if (slideIndex) {\n $(target).data(DATA_KEY$2).to(slideIndex);\n }\n\n event.preventDefault();\n };\n\n _createClass(Carousel, null, [{\n key: \"VERSION\",\n get: function get() {\n return VERSION$2;\n }\n }, {\n key: \"Default\",\n get: function get() {\n return Default;\n }\n }]);\n\n return Carousel;\n }();\n /**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\n\n $(document).on(EVENT_CLICK_DATA_API$2, SELECTOR_DATA_SLIDE, Carousel._dataApiClickHandler);\n $(window).on(EVENT_LOAD_DATA_API$1, function () {\n var carousels = [].slice.call(document.querySelectorAll(SELECTOR_DATA_RIDE));\n\n for (var i = 0, len = carousels.length; i < len; i++) {\n var $carousel = $(carousels[i]);\n\n Carousel._jQueryInterface.call($carousel, $carousel.data());\n }\n });\n /**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\n $.fn[NAME$2] = Carousel._jQueryInterface;\n $.fn[NAME$2].Constructor = Carousel;\n\n $.fn[NAME$2].noConflict = function () {\n $.fn[NAME$2] = JQUERY_NO_CONFLICT$2;\n return Carousel._jQueryInterface;\n };\n\n /**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\n var NAME$3 = 'collapse';\n var VERSION$3 = '4.5.2';\n var DATA_KEY$3 = 'bs.collapse';\n var EVENT_KEY$3 = \".\" + DATA_KEY$3;\n var DATA_API_KEY$3 = '.data-api';\n var JQUERY_NO_CONFLICT$3 = $.fn[NAME$3];\n var Default$1 = {\n toggle: true,\n parent: ''\n };\n var DefaultType$1 = {\n toggle: 'boolean',\n parent: '(string|element)'\n };\n var EVENT_SHOW = \"show\" + EVENT_KEY$3;\n var EVENT_SHOWN = \"shown\" + EVENT_KEY$3;\n var EVENT_HIDE = \"hide\" + EVENT_KEY$3;\n var EVENT_HIDDEN = \"hidden\" + EVENT_KEY$3;\n var EVENT_CLICK_DATA_API$3 = \"click\" + EVENT_KEY$3 + DATA_API_KEY$3;\n var CLASS_NAME_SHOW$1 = 'show';\n var CLASS_NAME_COLLAPSE = 'collapse';\n var CLASS_NAME_COLLAPSING = 'collapsing';\n var CLASS_NAME_COLLAPSED = 'collapsed';\n var DIMENSION_WIDTH = 'width';\n var DIMENSION_HEIGHT = 'height';\n var SELECTOR_ACTIVES = '.show, .collapsing';\n var SELECTOR_DATA_TOGGLE$1 = '[data-toggle=\"collapse\"]';\n /**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\n var Collapse = /*#__PURE__*/function () {\n function Collapse(element, config) {\n this._isTransitioning = false;\n this._element = element;\n this._config = this._getConfig(config);\n this._triggerArray = [].slice.call(document.querySelectorAll(\"[data-toggle=\\\"collapse\\\"][href=\\\"#\" + element.id + \"\\\"],\" + (\"[data-toggle=\\\"collapse\\\"][data-target=\\\"#\" + element.id + \"\\\"]\")));\n var toggleList = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE$1));\n\n for (var i = 0, len = toggleList.length; i < len; i++) {\n var elem = toggleList[i];\n var selector = Util.getSelectorFromElement(elem);\n var filterElement = [].slice.call(document.querySelectorAll(selector)).filter(function (foundElem) {\n return foundElem === element;\n });\n\n if (selector !== null && filterElement.length > 0) {\n this._selector = selector;\n\n this._triggerArray.push(elem);\n }\n }\n\n this._parent = this._config.parent ? this._getParent() : null;\n\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._element, this._triggerArray);\n }\n\n if (this._config.toggle) {\n this.toggle();\n }\n } // Getters\n\n\n var _proto = Collapse.prototype;\n\n // Public\n _proto.toggle = function toggle() {\n if ($(this._element).hasClass(CLASS_NAME_SHOW$1)) {\n this.hide();\n } else {\n this.show();\n }\n };\n\n _proto.show = function show() {\n var _this = this;\n\n if (this._isTransitioning || $(this._element).hasClass(CLASS_NAME_SHOW$1)) {\n return;\n }\n\n var actives;\n var activesData;\n\n if (this._parent) {\n actives = [].slice.call(this._parent.querySelectorAll(SELECTOR_ACTIVES)).filter(function (elem) {\n if (typeof _this._config.parent === 'string') {\n return elem.getAttribute('data-parent') === _this._config.parent;\n }\n\n return elem.classList.contains(CLASS_NAME_COLLAPSE);\n });\n\n if (actives.length === 0) {\n actives = null;\n }\n }\n\n if (actives) {\n activesData = $(actives).not(this._selector).data(DATA_KEY$3);\n\n if (activesData && activesData._isTransitioning) {\n return;\n }\n }\n\n var startEvent = $.Event(EVENT_SHOW);\n $(this._element).trigger(startEvent);\n\n if (startEvent.isDefaultPrevented()) {\n return;\n }\n\n if (actives) {\n Collapse._jQueryInterface.call($(actives).not(this._selector), 'hide');\n\n if (!activesData) {\n $(actives).data(DATA_KEY$3, null);\n }\n }\n\n var dimension = this._getDimension();\n\n $(this._element).removeClass(CLASS_NAME_COLLAPSE).addClass(CLASS_NAME_COLLAPSING);\n this._element.style[dimension] = 0;\n\n if (this._triggerArray.length) {\n $(this._triggerArray).removeClass(CLASS_NAME_COLLAPSED).attr('aria-expanded', true);\n }\n\n this.setTransitioning(true);\n\n var complete = function complete() {\n $(_this._element).removeClass(CLASS_NAME_COLLAPSING).addClass(CLASS_NAME_COLLAPSE + \" \" + CLASS_NAME_SHOW$1);\n _this._element.style[dimension] = '';\n\n _this.setTransitioning(false);\n\n $(_this._element).trigger(EVENT_SHOWN);\n };\n\n var capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1);\n var scrollSize = \"scroll\" + capitalizedDimension;\n var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n this._element.style[dimension] = this._element[scrollSize] + \"px\";\n };\n\n _proto.hide = function hide() {\n var _this2 = this;\n\n if (this._isTransitioning || !$(this._element).hasClass(CLASS_NAME_SHOW$1)) {\n return;\n }\n\n var startEvent = $.Event(EVENT_HIDE);\n $(this._element).trigger(startEvent);\n\n if (startEvent.isDefaultPrevented()) {\n return;\n }\n\n var dimension = this._getDimension();\n\n this._element.style[dimension] = this._element.getBoundingClientRect()[dimension] + \"px\";\n Util.reflow(this._element);\n $(this._element).addClass(CLASS_NAME_COLLAPSING).removeClass(CLASS_NAME_COLLAPSE + \" \" + CLASS_NAME_SHOW$1);\n var triggerArrayLength = this._triggerArray.length;\n\n if (triggerArrayLength > 0) {\n for (var i = 0; i < triggerArrayLength; i++) {\n var trigger = this._triggerArray[i];\n var selector = Util.getSelectorFromElement(trigger);\n\n if (selector !== null) {\n var $elem = $([].slice.call(document.querySelectorAll(selector)));\n\n if (!$elem.hasClass(CLASS_NAME_SHOW$1)) {\n $(trigger).addClass(CLASS_NAME_COLLAPSED).attr('aria-expanded', false);\n }\n }\n }\n }\n\n this.setTransitioning(true);\n\n var complete = function complete() {\n _this2.setTransitioning(false);\n\n $(_this2._element).removeClass(CLASS_NAME_COLLAPSING).addClass(CLASS_NAME_COLLAPSE).trigger(EVENT_HIDDEN);\n };\n\n this._element.style[dimension] = '';\n var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n $(this._element).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n };\n\n _proto.setTransitioning = function setTransitioning(isTransitioning) {\n this._isTransitioning = isTransitioning;\n };\n\n _proto.dispose = function dispose() {\n $.removeData(this._element, DATA_KEY$3);\n this._config = null;\n this._parent = null;\n this._element = null;\n this._triggerArray = null;\n this._isTransitioning = null;\n } // Private\n ;\n\n _proto._getConfig = function _getConfig(config) {\n config = _extends({}, Default$1, config);\n config.toggle = Boolean(config.toggle); // Coerce string values\n\n Util.typeCheckConfig(NAME$3, config, DefaultType$1);\n return config;\n };\n\n _proto._getDimension = function _getDimension() {\n var hasWidth = $(this._element).hasClass(DIMENSION_WIDTH);\n return hasWidth ? DIMENSION_WIDTH : DIMENSION_HEIGHT;\n };\n\n _proto._getParent = function _getParent() {\n var _this3 = this;\n\n var parent;\n\n if (Util.isElement(this._config.parent)) {\n parent = this._config.parent; // It's a jQuery object\n\n if (typeof this._config.parent.jquery !== 'undefined') {\n parent = this._config.parent[0];\n }\n } else {\n parent = document.querySelector(this._config.parent);\n }\n\n var selector = \"[data-toggle=\\\"collapse\\\"][data-parent=\\\"\" + this._config.parent + \"\\\"]\";\n var children = [].slice.call(parent.querySelectorAll(selector));\n $(children).each(function (i, element) {\n _this3._addAriaAndCollapsedClass(Collapse._getTargetFromElement(element), [element]);\n });\n return parent;\n };\n\n _proto._addAriaAndCollapsedClass = function _addAriaAndCollapsedClass(element, triggerArray) {\n var isOpen = $(element).hasClass(CLASS_NAME_SHOW$1);\n\n if (triggerArray.length) {\n $(triggerArray).toggleClass(CLASS_NAME_COLLAPSED, !isOpen).attr('aria-expanded', isOpen);\n }\n } // Static\n ;\n\n Collapse._getTargetFromElement = function _getTargetFromElement(element) {\n var selector = Util.getSelectorFromElement(element);\n return selector ? document.querySelector(selector) : null;\n };\n\n Collapse._jQueryInterface = function _jQueryInterface(config) {\n return this.each(function () {\n var $this = $(this);\n var data = $this.data(DATA_KEY$3);\n\n var _config = _extends({}, Default$1, $this.data(), typeof config === 'object' && config ? config : {});\n\n if (!data && _config.toggle && typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false;\n }\n\n if (!data) {\n data = new Collapse(this, _config);\n $this.data(DATA_KEY$3, data);\n }\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n }\n\n data[config]();\n }\n });\n };\n\n _createClass(Collapse, null, [{\n key: \"VERSION\",\n get: function get() {\n return VERSION$3;\n }\n }, {\n key: \"Default\",\n get: function get() {\n return Default$1;\n }\n }]);\n\n return Collapse;\n }();\n /**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\n\n $(document).on(EVENT_CLICK_DATA_API$3, SELECTOR_DATA_TOGGLE$1, function (event) {\n // preventDefault only for elements (which change the URL) not inside the collapsible element\n if (event.currentTarget.tagName === 'A') {\n event.preventDefault();\n }\n\n var $trigger = $(this);\n var selector = Util.getSelectorFromElement(this);\n var selectors = [].slice.call(document.querySelectorAll(selector));\n $(selectors).each(function () {\n var $target = $(this);\n var data = $target.data(DATA_KEY$3);\n var config = data ? 'toggle' : $trigger.data();\n\n Collapse._jQueryInterface.call($target, config);\n });\n });\n /**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\n $.fn[NAME$3] = Collapse._jQueryInterface;\n $.fn[NAME$3].Constructor = Collapse;\n\n $.fn[NAME$3].noConflict = function () {\n $.fn[NAME$3] = JQUERY_NO_CONFLICT$3;\n return Collapse._jQueryInterface;\n };\n\n /**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\n var NAME$4 = 'dropdown';\n var VERSION$4 = '4.5.2';\n var DATA_KEY$4 = 'bs.dropdown';\n var EVENT_KEY$4 = \".\" + DATA_KEY$4;\n var DATA_API_KEY$4 = '.data-api';\n var JQUERY_NO_CONFLICT$4 = $.fn[NAME$4];\n var ESCAPE_KEYCODE = 27; // KeyboardEvent.which value for Escape (Esc) key\n\n var SPACE_KEYCODE = 32; // KeyboardEvent.which value for space key\n\n var TAB_KEYCODE = 9; // KeyboardEvent.which value for tab key\n\n var ARROW_UP_KEYCODE = 38; // KeyboardEvent.which value for up arrow key\n\n var ARROW_DOWN_KEYCODE = 40; // KeyboardEvent.which value for down arrow key\n\n var RIGHT_MOUSE_BUTTON_WHICH = 3; // MouseEvent.which value for the right button (assuming a right-handed mouse)\n\n var REGEXP_KEYDOWN = new RegExp(ARROW_UP_KEYCODE + \"|\" + ARROW_DOWN_KEYCODE + \"|\" + ESCAPE_KEYCODE);\n var EVENT_HIDE$1 = \"hide\" + EVENT_KEY$4;\n var EVENT_HIDDEN$1 = \"hidden\" + EVENT_KEY$4;\n var EVENT_SHOW$1 = \"show\" + EVENT_KEY$4;\n var EVENT_SHOWN$1 = \"shown\" + EVENT_KEY$4;\n var EVENT_CLICK = \"click\" + EVENT_KEY$4;\n var EVENT_CLICK_DATA_API$4 = \"click\" + EVENT_KEY$4 + DATA_API_KEY$4;\n var EVENT_KEYDOWN_DATA_API = \"keydown\" + EVENT_KEY$4 + DATA_API_KEY$4;\n var EVENT_KEYUP_DATA_API = \"keyup\" + EVENT_KEY$4 + DATA_API_KEY$4;\n var CLASS_NAME_DISABLED = 'disabled';\n var CLASS_NAME_SHOW$2 = 'show';\n var CLASS_NAME_DROPUP = 'dropup';\n var CLASS_NAME_DROPRIGHT = 'dropright';\n var CLASS_NAME_DROPLEFT = 'dropleft';\n var CLASS_NAME_MENURIGHT = 'dropdown-menu-right';\n var CLASS_NAME_POSITION_STATIC = 'position-static';\n var SELECTOR_DATA_TOGGLE$2 = '[data-toggle=\"dropdown\"]';\n var SELECTOR_FORM_CHILD = '.dropdown form';\n var SELECTOR_MENU = '.dropdown-menu';\n var SELECTOR_NAVBAR_NAV = '.navbar-nav';\n var SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)';\n var PLACEMENT_TOP = 'top-start';\n var PLACEMENT_TOPEND = 'top-end';\n var PLACEMENT_BOTTOM = 'bottom-start';\n var PLACEMENT_BOTTOMEND = 'bottom-end';\n var PLACEMENT_RIGHT = 'right-start';\n var PLACEMENT_LEFT = 'left-start';\n var Default$2 = {\n offset: 0,\n flip: true,\n boundary: 'scrollParent',\n reference: 'toggle',\n display: 'dynamic',\n popperConfig: null\n };\n var DefaultType$2 = {\n offset: '(number|string|function)',\n flip: 'boolean',\n boundary: '(string|element)',\n reference: '(string|element)',\n display: 'string',\n popperConfig: '(null|object)'\n };\n /**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\n var Dropdown = /*#__PURE__*/function () {\n function Dropdown(element, config) {\n this._element = element;\n this._popper = null;\n this._config = this._getConfig(config);\n this._menu = this._getMenuElement();\n this._inNavbar = this._detectNavbar();\n\n this._addEventListeners();\n } // Getters\n\n\n var _proto = Dropdown.prototype;\n\n // Public\n _proto.toggle = function toggle() {\n if (this._element.disabled || $(this._element).hasClass(CLASS_NAME_DISABLED)) {\n return;\n }\n\n var isActive = $(this._menu).hasClass(CLASS_NAME_SHOW$2);\n\n Dropdown._clearMenus();\n\n if (isActive) {\n return;\n }\n\n this.show(true);\n };\n\n _proto.show = function show(usePopper) {\n if (usePopper === void 0) {\n usePopper = false;\n }\n\n if (this._element.disabled || $(this._element).hasClass(CLASS_NAME_DISABLED) || $(this._menu).hasClass(CLASS_NAME_SHOW$2)) {\n return;\n }\n\n var relatedTarget = {\n relatedTarget: this._element\n };\n var showEvent = $.Event(EVENT_SHOW$1, relatedTarget);\n\n var parent = Dropdown._getParentFromElement(this._element);\n\n $(parent).trigger(showEvent);\n\n if (showEvent.isDefaultPrevented()) {\n return;\n } // Disable totally Popper.js for Dropdown in Navbar\n\n\n if (!this._inNavbar && usePopper) {\n /**\n * Check for Popper dependency\n * Popper - https://popper.js.org\n */\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper.js (https://popper.js.org/)');\n }\n\n var referenceElement = this._element;\n\n if (this._config.reference === 'parent') {\n referenceElement = parent;\n } else if (Util.isElement(this._config.reference)) {\n referenceElement = this._config.reference; // Check if it's jQuery element\n\n if (typeof this._config.reference.jquery !== 'undefined') {\n referenceElement = this._config.reference[0];\n }\n } // If boundary is not `scrollParent`, then set position to `static`\n // to allow the menu to \"escape\" the scroll parent's boundaries\n // https://github.com/twbs/bootstrap/issues/24251\n\n\n if (this._config.boundary !== 'scrollParent') {\n $(parent).addClass(CLASS_NAME_POSITION_STATIC);\n }\n\n this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig());\n } // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n\n\n if ('ontouchstart' in document.documentElement && $(parent).closest(SELECTOR_NAVBAR_NAV).length === 0) {\n $(document.body).children().on('mouseover', null, $.noop);\n }\n\n this._element.focus();\n\n this._element.setAttribute('aria-expanded', true);\n\n $(this._menu).toggleClass(CLASS_NAME_SHOW$2);\n $(parent).toggleClass(CLASS_NAME_SHOW$2).trigger($.Event(EVENT_SHOWN$1, relatedTarget));\n };\n\n _proto.hide = function hide() {\n if (this._element.disabled || $(this._element).hasClass(CLASS_NAME_DISABLED) || !$(this._menu).hasClass(CLASS_NAME_SHOW$2)) {\n return;\n }\n\n var relatedTarget = {\n relatedTarget: this._element\n };\n var hideEvent = $.Event(EVENT_HIDE$1, relatedTarget);\n\n var parent = Dropdown._getParentFromElement(this._element);\n\n $(parent).trigger(hideEvent);\n\n if (hideEvent.isDefaultPrevented()) {\n return;\n }\n\n if (this._popper) {\n this._popper.destroy();\n }\n\n $(this._menu).toggleClass(CLASS_NAME_SHOW$2);\n $(parent).toggleClass(CLASS_NAME_SHOW$2).trigger($.Event(EVENT_HIDDEN$1, relatedTarget));\n };\n\n _proto.dispose = function dispose() {\n $.removeData(this._element, DATA_KEY$4);\n $(this._element).off(EVENT_KEY$4);\n this._element = null;\n this._menu = null;\n\n if (this._popper !== null) {\n this._popper.destroy();\n\n this._popper = null;\n }\n };\n\n _proto.update = function update() {\n this._inNavbar = this._detectNavbar();\n\n if (this._popper !== null) {\n this._popper.scheduleUpdate();\n }\n } // Private\n ;\n\n _proto._addEventListeners = function _addEventListeners() {\n var _this = this;\n\n $(this._element).on(EVENT_CLICK, function (event) {\n event.preventDefault();\n event.stopPropagation();\n\n _this.toggle();\n });\n };\n\n _proto._getConfig = function _getConfig(config) {\n config = _extends({}, this.constructor.Default, $(this._element).data(), config);\n Util.typeCheckConfig(NAME$4, config, this.constructor.DefaultType);\n return config;\n };\n\n _proto._getMenuElement = function _getMenuElement() {\n if (!this._menu) {\n var parent = Dropdown._getParentFromElement(this._element);\n\n if (parent) {\n this._menu = parent.querySelector(SELECTOR_MENU);\n }\n }\n\n return this._menu;\n };\n\n _proto._getPlacement = function _getPlacement() {\n var $parentDropdown = $(this._element.parentNode);\n var placement = PLACEMENT_BOTTOM; // Handle dropup\n\n if ($parentDropdown.hasClass(CLASS_NAME_DROPUP)) {\n placement = $(this._menu).hasClass(CLASS_NAME_MENURIGHT) ? PLACEMENT_TOPEND : PLACEMENT_TOP;\n } else if ($parentDropdown.hasClass(CLASS_NAME_DROPRIGHT)) {\n placement = PLACEMENT_RIGHT;\n } else if ($parentDropdown.hasClass(CLASS_NAME_DROPLEFT)) {\n placement = PLACEMENT_LEFT;\n } else if ($(this._menu).hasClass(CLASS_NAME_MENURIGHT)) {\n placement = PLACEMENT_BOTTOMEND;\n }\n\n return placement;\n };\n\n _proto._detectNavbar = function _detectNavbar() {\n return $(this._element).closest('.navbar').length > 0;\n };\n\n _proto._getOffset = function _getOffset() {\n var _this2 = this;\n\n var offset = {};\n\n if (typeof this._config.offset === 'function') {\n offset.fn = function (data) {\n data.offsets = _extends({}, data.offsets, _this2._config.offset(data.offsets, _this2._element) || {});\n return data;\n };\n } else {\n offset.offset = this._config.offset;\n }\n\n return offset;\n };\n\n _proto._getPopperConfig = function _getPopperConfig() {\n var popperConfig = {\n placement: this._getPlacement(),\n modifiers: {\n offset: this._getOffset(),\n flip: {\n enabled: this._config.flip\n },\n preventOverflow: {\n boundariesElement: this._config.boundary\n }\n }\n }; // Disable Popper.js if we have a static display\n\n if (this._config.display === 'static') {\n popperConfig.modifiers.applyStyle = {\n enabled: false\n };\n }\n\n return _extends({}, popperConfig, this._config.popperConfig);\n } // Static\n ;\n\n Dropdown._jQueryInterface = function _jQueryInterface(config) {\n return this.each(function () {\n var data = $(this).data(DATA_KEY$4);\n\n var _config = typeof config === 'object' ? config : null;\n\n if (!data) {\n data = new Dropdown(this, _config);\n $(this).data(DATA_KEY$4, data);\n }\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n }\n\n data[config]();\n }\n });\n };\n\n Dropdown._clearMenus = function _clearMenus(event) {\n if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH || event.type === 'keyup' && event.which !== TAB_KEYCODE)) {\n return;\n }\n\n var toggles = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE$2));\n\n for (var i = 0, len = toggles.length; i < len; i++) {\n var parent = Dropdown._getParentFromElement(toggles[i]);\n\n var context = $(toggles[i]).data(DATA_KEY$4);\n var relatedTarget = {\n relatedTarget: toggles[i]\n };\n\n if (event && event.type === 'click') {\n relatedTarget.clickEvent = event;\n }\n\n if (!context) {\n continue;\n }\n\n var dropdownMenu = context._menu;\n\n if (!$(parent).hasClass(CLASS_NAME_SHOW$2)) {\n continue;\n }\n\n if (event && (event.type === 'click' && /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) && $.contains(parent, event.target)) {\n continue;\n }\n\n var hideEvent = $.Event(EVENT_HIDE$1, relatedTarget);\n $(parent).trigger(hideEvent);\n\n if (hideEvent.isDefaultPrevented()) {\n continue;\n } // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n\n\n if ('ontouchstart' in document.documentElement) {\n $(document.body).children().off('mouseover', null, $.noop);\n }\n\n toggles[i].setAttribute('aria-expanded', 'false');\n\n if (context._popper) {\n context._popper.destroy();\n }\n\n $(dropdownMenu).removeClass(CLASS_NAME_SHOW$2);\n $(parent).removeClass(CLASS_NAME_SHOW$2).trigger($.Event(EVENT_HIDDEN$1, relatedTarget));\n }\n };\n\n Dropdown._getParentFromElement = function _getParentFromElement(element) {\n var parent;\n var selector = Util.getSelectorFromElement(element);\n\n if (selector) {\n parent = document.querySelector(selector);\n }\n\n return parent || element.parentNode;\n } // eslint-disable-next-line complexity\n ;\n\n Dropdown._dataApiKeydownHandler = function _dataApiKeydownHandler(event) {\n // If not input/textarea:\n // - And not a key in REGEXP_KEYDOWN => not a dropdown command\n // If input/textarea:\n // - If space key => not a dropdown command\n // - If key is other than escape\n // - If key is not up or down => not a dropdown command\n // - If trigger inside the menu => not a dropdown command\n if (/input|textarea/i.test(event.target.tagName) ? event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE && (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE || $(event.target).closest(SELECTOR_MENU).length) : !REGEXP_KEYDOWN.test(event.which)) {\n return;\n }\n\n if (this.disabled || $(this).hasClass(CLASS_NAME_DISABLED)) {\n return;\n }\n\n var parent = Dropdown._getParentFromElement(this);\n\n var isActive = $(parent).hasClass(CLASS_NAME_SHOW$2);\n\n if (!isActive && event.which === ESCAPE_KEYCODE) {\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n\n if (!isActive || isActive && (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) {\n if (event.which === ESCAPE_KEYCODE) {\n $(parent.querySelector(SELECTOR_DATA_TOGGLE$2)).trigger('focus');\n }\n\n $(this).trigger('click');\n return;\n }\n\n var items = [].slice.call(parent.querySelectorAll(SELECTOR_VISIBLE_ITEMS)).filter(function (item) {\n return $(item).is(':visible');\n });\n\n if (items.length === 0) {\n return;\n }\n\n var index = items.indexOf(event.target);\n\n if (event.which === ARROW_UP_KEYCODE && index > 0) {\n // Up\n index--;\n }\n\n if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) {\n // Down\n index++;\n }\n\n if (index < 0) {\n index = 0;\n }\n\n items[index].focus();\n };\n\n _createClass(Dropdown, null, [{\n key: \"VERSION\",\n get: function get() {\n return VERSION$4;\n }\n }, {\n key: \"Default\",\n get: function get() {\n return Default$2;\n }\n }, {\n key: \"DefaultType\",\n get: function get() {\n return DefaultType$2;\n }\n }]);\n\n return Dropdown;\n }();\n /**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\n\n $(document).on(EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE$2, Dropdown._dataApiKeydownHandler).on(EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown._dataApiKeydownHandler).on(EVENT_CLICK_DATA_API$4 + \" \" + EVENT_KEYUP_DATA_API, Dropdown._clearMenus).on(EVENT_CLICK_DATA_API$4, SELECTOR_DATA_TOGGLE$2, function (event) {\n event.preventDefault();\n event.stopPropagation();\n\n Dropdown._jQueryInterface.call($(this), 'toggle');\n }).on(EVENT_CLICK_DATA_API$4, SELECTOR_FORM_CHILD, function (e) {\n e.stopPropagation();\n });\n /**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\n $.fn[NAME$4] = Dropdown._jQueryInterface;\n $.fn[NAME$4].Constructor = Dropdown;\n\n $.fn[NAME$4].noConflict = function () {\n $.fn[NAME$4] = JQUERY_NO_CONFLICT$4;\n return Dropdown._jQueryInterface;\n };\n\n /**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\n var NAME$5 = 'modal';\n var VERSION$5 = '4.5.2';\n var DATA_KEY$5 = 'bs.modal';\n var EVENT_KEY$5 = \".\" + DATA_KEY$5;\n var DATA_API_KEY$5 = '.data-api';\n var JQUERY_NO_CONFLICT$5 = $.fn[NAME$5];\n var ESCAPE_KEYCODE$1 = 27; // KeyboardEvent.which value for Escape (Esc) key\n\n var Default$3 = {\n backdrop: true,\n keyboard: true,\n focus: true,\n show: true\n };\n var DefaultType$3 = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n focus: 'boolean',\n show: 'boolean'\n };\n var EVENT_HIDE$2 = \"hide\" + EVENT_KEY$5;\n var EVENT_HIDE_PREVENTED = \"hidePrevented\" + EVENT_KEY$5;\n var EVENT_HIDDEN$2 = \"hidden\" + EVENT_KEY$5;\n var EVENT_SHOW$2 = \"show\" + EVENT_KEY$5;\n var EVENT_SHOWN$2 = \"shown\" + EVENT_KEY$5;\n var EVENT_FOCUSIN = \"focusin\" + EVENT_KEY$5;\n var EVENT_RESIZE = \"resize\" + EVENT_KEY$5;\n var EVENT_CLICK_DISMISS = \"click.dismiss\" + EVENT_KEY$5;\n var EVENT_KEYDOWN_DISMISS = \"keydown.dismiss\" + EVENT_KEY$5;\n var EVENT_MOUSEUP_DISMISS = \"mouseup.dismiss\" + EVENT_KEY$5;\n var EVENT_MOUSEDOWN_DISMISS = \"mousedown.dismiss\" + EVENT_KEY$5;\n var EVENT_CLICK_DATA_API$5 = \"click\" + EVENT_KEY$5 + DATA_API_KEY$5;\n var CLASS_NAME_SCROLLABLE = 'modal-dialog-scrollable';\n var CLASS_NAME_SCROLLBAR_MEASURER = 'modal-scrollbar-measure';\n var CLASS_NAME_BACKDROP = 'modal-backdrop';\n var CLASS_NAME_OPEN = 'modal-open';\n var CLASS_NAME_FADE$1 = 'fade';\n var CLASS_NAME_SHOW$3 = 'show';\n var CLASS_NAME_STATIC = 'modal-static';\n var SELECTOR_DIALOG = '.modal-dialog';\n var SELECTOR_MODAL_BODY = '.modal-body';\n var SELECTOR_DATA_TOGGLE$3 = '[data-toggle=\"modal\"]';\n var SELECTOR_DATA_DISMISS = '[data-dismiss=\"modal\"]';\n var SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top';\n var SELECTOR_STICKY_CONTENT = '.sticky-top';\n /**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\n var Modal = /*#__PURE__*/function () {\n function Modal(element, config) {\n this._config = this._getConfig(config);\n this._element = element;\n this._dialog = element.querySelector(SELECTOR_DIALOG);\n this._backdrop = null;\n this._isShown = false;\n this._isBodyOverflowing = false;\n this._ignoreBackdropClick = false;\n this._isTransitioning = false;\n this._scrollbarWidth = 0;\n } // Getters\n\n\n var _proto = Modal.prototype;\n\n // Public\n _proto.toggle = function toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget);\n };\n\n _proto.show = function show(relatedTarget) {\n var _this = this;\n\n if (this._isShown || this._isTransitioning) {\n return;\n }\n\n if ($(this._element).hasClass(CLASS_NAME_FADE$1)) {\n this._isTransitioning = true;\n }\n\n var showEvent = $.Event(EVENT_SHOW$2, {\n relatedTarget: relatedTarget\n });\n $(this._element).trigger(showEvent);\n\n if (this._isShown || showEvent.isDefaultPrevented()) {\n return;\n }\n\n this._isShown = true;\n\n this._checkScrollbar();\n\n this._setScrollbar();\n\n this._adjustDialog();\n\n this._setEscapeEvent();\n\n this._setResizeEvent();\n\n $(this._element).on(EVENT_CLICK_DISMISS, SELECTOR_DATA_DISMISS, function (event) {\n return _this.hide(event);\n });\n $(this._dialog).on(EVENT_MOUSEDOWN_DISMISS, function () {\n $(_this._element).one(EVENT_MOUSEUP_DISMISS, function (event) {\n if ($(event.target).is(_this._element)) {\n _this._ignoreBackdropClick = true;\n }\n });\n });\n\n this._showBackdrop(function () {\n return _this._showElement(relatedTarget);\n });\n };\n\n _proto.hide = function hide(event) {\n var _this2 = this;\n\n if (event) {\n event.preventDefault();\n }\n\n if (!this._isShown || this._isTransitioning) {\n return;\n }\n\n var hideEvent = $.Event(EVENT_HIDE$2);\n $(this._element).trigger(hideEvent);\n\n if (!this._isShown || hideEvent.isDefaultPrevented()) {\n return;\n }\n\n this._isShown = false;\n var transition = $(this._element).hasClass(CLASS_NAME_FADE$1);\n\n if (transition) {\n this._isTransitioning = true;\n }\n\n this._setEscapeEvent();\n\n this._setResizeEvent();\n\n $(document).off(EVENT_FOCUSIN);\n $(this._element).removeClass(CLASS_NAME_SHOW$3);\n $(this._element).off(EVENT_CLICK_DISMISS);\n $(this._dialog).off(EVENT_MOUSEDOWN_DISMISS);\n\n if (transition) {\n var transitionDuration = Util.getTransitionDurationFromElement(this._element);\n $(this._element).one(Util.TRANSITION_END, function (event) {\n return _this2._hideModal(event);\n }).emulateTransitionEnd(transitionDuration);\n } else {\n this._hideModal();\n }\n };\n\n _proto.dispose = function dispose() {\n [window, this._element, this._dialog].forEach(function (htmlElement) {\n return $(htmlElement).off(EVENT_KEY$5);\n });\n /**\n * `document` has 2 events `EVENT_FOCUSIN` and `EVENT_CLICK_DATA_API`\n * Do not move `document` in `htmlElements` array\n * It will remove `EVENT_CLICK_DATA_API` event that should remain\n */\n\n $(document).off(EVENT_FOCUSIN);\n $.removeData(this._element, DATA_KEY$5);\n this._config = null;\n this._element = null;\n this._dialog = null;\n this._backdrop = null;\n this._isShown = null;\n this._isBodyOverflowing = null;\n this._ignoreBackdropClick = null;\n this._isTransitioning = null;\n this._scrollbarWidth = null;\n };\n\n _proto.handleUpdate = function handleUpdate() {\n this._adjustDialog();\n } // Private\n ;\n\n _proto._getConfig = function _getConfig(config) {\n config = _extends({}, Default$3, config);\n Util.typeCheckConfig(NAME$5, config, DefaultType$3);\n return config;\n };\n\n _proto._triggerBackdropTransition = function _triggerBackdropTransition() {\n var _this3 = this;\n\n if (this._config.backdrop === 'static') {\n var hideEventPrevented = $.Event(EVENT_HIDE_PREVENTED);\n $(this._element).trigger(hideEventPrevented);\n\n if (hideEventPrevented.defaultPrevented) {\n return;\n }\n\n var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;\n\n if (!isModalOverflowing) {\n this._element.style.overflowY = 'hidden';\n }\n\n this._element.classList.add(CLASS_NAME_STATIC);\n\n var modalTransitionDuration = Util.getTransitionDurationFromElement(this._dialog);\n $(this._element).off(Util.TRANSITION_END);\n $(this._element).one(Util.TRANSITION_END, function () {\n _this3._element.classList.remove(CLASS_NAME_STATIC);\n\n if (!isModalOverflowing) {\n $(_this3._element).one(Util.TRANSITION_END, function () {\n _this3._element.style.overflowY = '';\n }).emulateTransitionEnd(_this3._element, modalTransitionDuration);\n }\n }).emulateTransitionEnd(modalTransitionDuration);\n\n this._element.focus();\n } else {\n this.hide();\n }\n };\n\n _proto._showElement = function _showElement(relatedTarget) {\n var _this4 = this;\n\n var transition = $(this._element).hasClass(CLASS_NAME_FADE$1);\n var modalBody = this._dialog ? this._dialog.querySelector(SELECTOR_MODAL_BODY) : null;\n\n if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {\n // Don't move modal's DOM position\n document.body.appendChild(this._element);\n }\n\n this._element.style.display = 'block';\n\n this._element.removeAttribute('aria-hidden');\n\n this._element.setAttribute('aria-modal', true);\n\n this._element.setAttribute('role', 'dialog');\n\n if ($(this._dialog).hasClass(CLASS_NAME_SCROLLABLE) && modalBody) {\n modalBody.scrollTop = 0;\n } else {\n this._element.scrollTop = 0;\n }\n\n if (transition) {\n Util.reflow(this._element);\n }\n\n $(this._element).addClass(CLASS_NAME_SHOW$3);\n\n if (this._config.focus) {\n this._enforceFocus();\n }\n\n var shownEvent = $.Event(EVENT_SHOWN$2, {\n relatedTarget: relatedTarget\n });\n\n var transitionComplete = function transitionComplete() {\n if (_this4._config.focus) {\n _this4._element.focus();\n }\n\n _this4._isTransitioning = false;\n $(_this4._element).trigger(shownEvent);\n };\n\n if (transition) {\n var transitionDuration = Util.getTransitionDurationFromElement(this._dialog);\n $(this._dialog).one(Util.TRANSITION_END, transitionComplete).emulateTransitionEnd(transitionDuration);\n } else {\n transitionComplete();\n }\n };\n\n _proto._enforceFocus = function _enforceFocus() {\n var _this5 = this;\n\n $(document).off(EVENT_FOCUSIN) // Guard against infinite focus loop\n .on(EVENT_FOCUSIN, function (event) {\n if (document !== event.target && _this5._element !== event.target && $(_this5._element).has(event.target).length === 0) {\n _this5._element.focus();\n }\n });\n };\n\n _proto._setEscapeEvent = function _setEscapeEvent() {\n var _this6 = this;\n\n if (this._isShown) {\n $(this._element).on(EVENT_KEYDOWN_DISMISS, function (event) {\n if (_this6._config.keyboard && event.which === ESCAPE_KEYCODE$1) {\n event.preventDefault();\n\n _this6.hide();\n } else if (!_this6._config.keyboard && event.which === ESCAPE_KEYCODE$1) {\n _this6._triggerBackdropTransition();\n }\n });\n } else if (!this._isShown) {\n $(this._element).off(EVENT_KEYDOWN_DISMISS);\n }\n };\n\n _proto._setResizeEvent = function _setResizeEvent() {\n var _this7 = this;\n\n if (this._isShown) {\n $(window).on(EVENT_RESIZE, function (event) {\n return _this7.handleUpdate(event);\n });\n } else {\n $(window).off(EVENT_RESIZE);\n }\n };\n\n _proto._hideModal = function _hideModal() {\n var _this8 = this;\n\n this._element.style.display = 'none';\n\n this._element.setAttribute('aria-hidden', true);\n\n this._element.removeAttribute('aria-modal');\n\n this._element.removeAttribute('role');\n\n this._isTransitioning = false;\n\n this._showBackdrop(function () {\n $(document.body).removeClass(CLASS_NAME_OPEN);\n\n _this8._resetAdjustments();\n\n _this8._resetScrollbar();\n\n $(_this8._element).trigger(EVENT_HIDDEN$2);\n });\n };\n\n _proto._removeBackdrop = function _removeBackdrop() {\n if (this._backdrop) {\n $(this._backdrop).remove();\n this._backdrop = null;\n }\n };\n\n _proto._showBackdrop = function _showBackdrop(callback) {\n var _this9 = this;\n\n var animate = $(this._element).hasClass(CLASS_NAME_FADE$1) ? CLASS_NAME_FADE$1 : '';\n\n if (this._isShown && this._config.backdrop) {\n this._backdrop = document.createElement('div');\n this._backdrop.className = CLASS_NAME_BACKDROP;\n\n if (animate) {\n this._backdrop.classList.add(animate);\n }\n\n $(this._backdrop).appendTo(document.body);\n $(this._element).on(EVENT_CLICK_DISMISS, function (event) {\n if (_this9._ignoreBackdropClick) {\n _this9._ignoreBackdropClick = false;\n return;\n }\n\n if (event.target !== event.currentTarget) {\n return;\n }\n\n _this9._triggerBackdropTransition();\n });\n\n if (animate) {\n Util.reflow(this._backdrop);\n }\n\n $(this._backdrop).addClass(CLASS_NAME_SHOW$3);\n\n if (!callback) {\n return;\n }\n\n if (!animate) {\n callback();\n return;\n }\n\n var backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop);\n $(this._backdrop).one(Util.TRANSITION_END, callback).emulateTransitionEnd(backdropTransitionDuration);\n } else if (!this._isShown && this._backdrop) {\n $(this._backdrop).removeClass(CLASS_NAME_SHOW$3);\n\n var callbackRemove = function callbackRemove() {\n _this9._removeBackdrop();\n\n if (callback) {\n callback();\n }\n };\n\n if ($(this._element).hasClass(CLASS_NAME_FADE$1)) {\n var _backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop);\n\n $(this._backdrop).one(Util.TRANSITION_END, callbackRemove).emulateTransitionEnd(_backdropTransitionDuration);\n } else {\n callbackRemove();\n }\n } else if (callback) {\n callback();\n }\n } // ----------------------------------------------------------------------\n // the following methods are used to handle overflowing modals\n // todo (fat): these should probably be refactored out of modal.js\n // ----------------------------------------------------------------------\n ;\n\n _proto._adjustDialog = function _adjustDialog() {\n var isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight;\n\n if (!this._isBodyOverflowing && isModalOverflowing) {\n this._element.style.paddingLeft = this._scrollbarWidth + \"px\";\n }\n\n if (this._isBodyOverflowing && !isModalOverflowing) {\n this._element.style.paddingRight = this._scrollbarWidth + \"px\";\n }\n };\n\n _proto._resetAdjustments = function _resetAdjustments() {\n this._element.style.paddingLeft = '';\n this._element.style.paddingRight = '';\n };\n\n _proto._checkScrollbar = function _checkScrollbar() {\n var rect = document.body.getBoundingClientRect();\n this._isBodyOverflowing = Math.round(rect.left + rect.right) < window.innerWidth;\n this._scrollbarWidth = this._getScrollbarWidth();\n };\n\n _proto._setScrollbar = function _setScrollbar() {\n var _this10 = this;\n\n if (this._isBodyOverflowing) {\n // Note: DOMNode.style.paddingRight returns the actual value or '' if not set\n // while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set\n var fixedContent = [].slice.call(document.querySelectorAll(SELECTOR_FIXED_CONTENT));\n var stickyContent = [].slice.call(document.querySelectorAll(SELECTOR_STICKY_CONTENT)); // Adjust fixed content padding\n\n $(fixedContent).each(function (index, element) {\n var actualPadding = element.style.paddingRight;\n var calculatedPadding = $(element).css('padding-right');\n $(element).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + _this10._scrollbarWidth + \"px\");\n }); // Adjust sticky content margin\n\n $(stickyContent).each(function (index, element) {\n var actualMargin = element.style.marginRight;\n var calculatedMargin = $(element).css('margin-right');\n $(element).data('margin-right', actualMargin).css('margin-right', parseFloat(calculatedMargin) - _this10._scrollbarWidth + \"px\");\n }); // Adjust body padding\n\n var actualPadding = document.body.style.paddingRight;\n var calculatedPadding = $(document.body).css('padding-right');\n $(document.body).data('padding-right', actualPadding).css('padding-right', parseFloat(calculatedPadding) + this._scrollbarWidth + \"px\");\n }\n\n $(document.body).addClass(CLASS_NAME_OPEN);\n };\n\n _proto._resetScrollbar = function _resetScrollbar() {\n // Restore fixed content padding\n var fixedContent = [].slice.call(document.querySelectorAll(SELECTOR_FIXED_CONTENT));\n $(fixedContent).each(function (index, element) {\n var padding = $(element).data('padding-right');\n $(element).removeData('padding-right');\n element.style.paddingRight = padding ? padding : '';\n }); // Restore sticky content\n\n var elements = [].slice.call(document.querySelectorAll(\"\" + SELECTOR_STICKY_CONTENT));\n $(elements).each(function (index, element) {\n var margin = $(element).data('margin-right');\n\n if (typeof margin !== 'undefined') {\n $(element).css('margin-right', margin).removeData('margin-right');\n }\n }); // Restore body padding\n\n var padding = $(document.body).data('padding-right');\n $(document.body).removeData('padding-right');\n document.body.style.paddingRight = padding ? padding : '';\n };\n\n _proto._getScrollbarWidth = function _getScrollbarWidth() {\n // thx d.walsh\n var scrollDiv = document.createElement('div');\n scrollDiv.className = CLASS_NAME_SCROLLBAR_MEASURER;\n document.body.appendChild(scrollDiv);\n var scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth;\n document.body.removeChild(scrollDiv);\n return scrollbarWidth;\n } // Static\n ;\n\n Modal._jQueryInterface = function _jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n var data = $(this).data(DATA_KEY$5);\n\n var _config = _extends({}, Default$3, $(this).data(), typeof config === 'object' && config ? config : {});\n\n if (!data) {\n data = new Modal(this, _config);\n $(this).data(DATA_KEY$5, data);\n }\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n }\n\n data[config](relatedTarget);\n } else if (_config.show) {\n data.show(relatedTarget);\n }\n });\n };\n\n _createClass(Modal, null, [{\n key: \"VERSION\",\n get: function get() {\n return VERSION$5;\n }\n }, {\n key: \"Default\",\n get: function get() {\n return Default$3;\n }\n }]);\n\n return Modal;\n }();\n /**\n * ------------------------------------------------------------------------\n * Data Api implementation\n * ------------------------------------------------------------------------\n */\n\n\n $(document).on(EVENT_CLICK_DATA_API$5, SELECTOR_DATA_TOGGLE$3, function (event) {\n var _this11 = this;\n\n var target;\n var selector = Util.getSelectorFromElement(this);\n\n if (selector) {\n target = document.querySelector(selector);\n }\n\n var config = $(target).data(DATA_KEY$5) ? 'toggle' : _extends({}, $(target).data(), $(this).data());\n\n if (this.tagName === 'A' || this.tagName === 'AREA') {\n event.preventDefault();\n }\n\n var $target = $(target).one(EVENT_SHOW$2, function (showEvent) {\n if (showEvent.isDefaultPrevented()) {\n // Only register focus restorer if modal will actually get shown\n return;\n }\n\n $target.one(EVENT_HIDDEN$2, function () {\n if ($(_this11).is(':visible')) {\n _this11.focus();\n }\n });\n });\n\n Modal._jQueryInterface.call($(target), config, this);\n });\n /**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\n $.fn[NAME$5] = Modal._jQueryInterface;\n $.fn[NAME$5].Constructor = Modal;\n\n $.fn[NAME$5].noConflict = function () {\n $.fn[NAME$5] = JQUERY_NO_CONFLICT$5;\n return Modal._jQueryInterface;\n };\n\n /**\n * --------------------------------------------------------------------------\n * Bootstrap (v4.5.2): tools/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n var uriAttrs = ['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href'];\n var ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i;\n var DefaultWhitelist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n div: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n };\n /**\n * A pattern that recognizes a commonly useful subset of URLs that are safe.\n *\n * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts\n */\n\n var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^#&/:?]*(?:[#/?]|$))/gi;\n /**\n * A pattern that matches safe data URLs. Only matches image, video and audio types.\n *\n * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts\n */\n\n var DATA_URL_PATTERN = /^data:(?:image\\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\\/(?:mpeg|mp4|ogg|webm)|audio\\/(?:mp3|oga|ogg|opus));base64,[\\d+/a-z]+=*$/i;\n\n function allowedAttribute(attr, allowedAttributeList) {\n var attrName = attr.nodeName.toLowerCase();\n\n if (allowedAttributeList.indexOf(attrName) !== -1) {\n if (uriAttrs.indexOf(attrName) !== -1) {\n return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN));\n }\n\n return true;\n }\n\n var regExp = allowedAttributeList.filter(function (attrRegex) {\n return attrRegex instanceof RegExp;\n }); // Check if a regular expression validates the attribute.\n\n for (var i = 0, len = regExp.length; i < len; i++) {\n if (attrName.match(regExp[i])) {\n return true;\n }\n }\n\n return false;\n }\n\n function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {\n if (unsafeHtml.length === 0) {\n return unsafeHtml;\n }\n\n if (sanitizeFn && typeof sanitizeFn === 'function') {\n return sanitizeFn(unsafeHtml);\n }\n\n var domParser = new window.DOMParser();\n var createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');\n var whitelistKeys = Object.keys(whiteList);\n var elements = [].slice.call(createdDocument.body.querySelectorAll('*'));\n\n var _loop = function _loop(i, len) {\n var el = elements[i];\n var elName = el.nodeName.toLowerCase();\n\n if (whitelistKeys.indexOf(el.nodeName.toLowerCase()) === -1) {\n el.parentNode.removeChild(el);\n return \"continue\";\n }\n\n var attributeList = [].slice.call(el.attributes);\n var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || []);\n attributeList.forEach(function (attr) {\n if (!allowedAttribute(attr, whitelistedAttributes)) {\n el.removeAttribute(attr.nodeName);\n }\n });\n };\n\n for (var i = 0, len = elements.length; i < len; i++) {\n var _ret = _loop(i);\n\n if (_ret === \"continue\") continue;\n }\n\n return createdDocument.body.innerHTML;\n }\n\n /**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\n var NAME$6 = 'tooltip';\n var VERSION$6 = '4.5.2';\n var DATA_KEY$6 = 'bs.tooltip';\n var EVENT_KEY$6 = \".\" + DATA_KEY$6;\n var JQUERY_NO_CONFLICT$6 = $.fn[NAME$6];\n var CLASS_PREFIX = 'bs-tooltip';\n var BSCLS_PREFIX_REGEX = new RegExp(\"(^|\\\\s)\" + CLASS_PREFIX + \"\\\\S+\", 'g');\n var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn'];\n var DefaultType$4 = {\n animation: 'boolean',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string',\n delay: '(number|object)',\n html: 'boolean',\n selector: '(string|boolean)',\n placement: '(string|function)',\n offset: '(number|string|function)',\n container: '(string|element|boolean)',\n fallbackPlacement: '(string|array)',\n boundary: '(string|element)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n whiteList: 'object',\n popperConfig: '(null|object)'\n };\n var AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: 'right',\n BOTTOM: 'bottom',\n LEFT: 'left'\n };\n var Default$4 = {\n animation: true,\n template: '
' + '
' + '
',\n trigger: 'hover focus',\n title: '',\n delay: 0,\n html: false,\n selector: false,\n placement: 'top',\n offset: 0,\n container: false,\n fallbackPlacement: 'flip',\n boundary: 'scrollParent',\n sanitize: true,\n sanitizeFn: null,\n whiteList: DefaultWhitelist,\n popperConfig: null\n };\n var HOVER_STATE_SHOW = 'show';\n var HOVER_STATE_OUT = 'out';\n var Event = {\n HIDE: \"hide\" + EVENT_KEY$6,\n HIDDEN: \"hidden\" + EVENT_KEY$6,\n SHOW: \"show\" + EVENT_KEY$6,\n SHOWN: \"shown\" + EVENT_KEY$6,\n INSERTED: \"inserted\" + EVENT_KEY$6,\n CLICK: \"click\" + EVENT_KEY$6,\n FOCUSIN: \"focusin\" + EVENT_KEY$6,\n FOCUSOUT: \"focusout\" + EVENT_KEY$6,\n MOUSEENTER: \"mouseenter\" + EVENT_KEY$6,\n MOUSELEAVE: \"mouseleave\" + EVENT_KEY$6\n };\n var CLASS_NAME_FADE$2 = 'fade';\n var CLASS_NAME_SHOW$4 = 'show';\n var SELECTOR_TOOLTIP_INNER = '.tooltip-inner';\n var SELECTOR_ARROW = '.arrow';\n var TRIGGER_HOVER = 'hover';\n var TRIGGER_FOCUS = 'focus';\n var TRIGGER_CLICK = 'click';\n var TRIGGER_MANUAL = 'manual';\n /**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\n var Tooltip = /*#__PURE__*/function () {\n function Tooltip(element, config) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper.js (https://popper.js.org/)');\n } // private\n\n\n this._isEnabled = true;\n this._timeout = 0;\n this._hoverState = '';\n this._activeTrigger = {};\n this._popper = null; // Protected\n\n this.element = element;\n this.config = this._getConfig(config);\n this.tip = null;\n\n this._setListeners();\n } // Getters\n\n\n var _proto = Tooltip.prototype;\n\n // Public\n _proto.enable = function enable() {\n this._isEnabled = true;\n };\n\n _proto.disable = function disable() {\n this._isEnabled = false;\n };\n\n _proto.toggleEnabled = function toggleEnabled() {\n this._isEnabled = !this._isEnabled;\n };\n\n _proto.toggle = function toggle(event) {\n if (!this._isEnabled) {\n return;\n }\n\n if (event) {\n var dataKey = this.constructor.DATA_KEY;\n var context = $(event.currentTarget).data(dataKey);\n\n if (!context) {\n context = new this.constructor(event.currentTarget, this._getDelegateConfig());\n $(event.currentTarget).data(dataKey, context);\n }\n\n context._activeTrigger.click = !context._activeTrigger.click;\n\n if (context._isWithActiveTrigger()) {\n context._enter(null, context);\n } else {\n context._leave(null, context);\n }\n } else {\n if ($(this.getTipElement()).hasClass(CLASS_NAME_SHOW$4)) {\n this._leave(null, this);\n\n return;\n }\n\n this._enter(null, this);\n }\n };\n\n _proto.dispose = function dispose() {\n clearTimeout(this._timeout);\n $.removeData(this.element, this.constructor.DATA_KEY);\n $(this.element).off(this.constructor.EVENT_KEY);\n $(this.element).closest('.modal').off('hide.bs.modal', this._hideModalHandler);\n\n if (this.tip) {\n $(this.tip).remove();\n }\n\n this._isEnabled = null;\n this._timeout = null;\n this._hoverState = null;\n this._activeTrigger = null;\n\n if (this._popper) {\n this._popper.destroy();\n }\n\n this._popper = null;\n this.element = null;\n this.config = null;\n this.tip = null;\n };\n\n _proto.show = function show() {\n var _this = this;\n\n if ($(this.element).css('display') === 'none') {\n throw new Error('Please use show on visible elements');\n }\n\n var showEvent = $.Event(this.constructor.Event.SHOW);\n\n if (this.isWithContent() && this._isEnabled) {\n $(this.element).trigger(showEvent);\n var shadowRoot = Util.findShadowRoot(this.element);\n var isInTheDom = $.contains(shadowRoot !== null ? shadowRoot : this.element.ownerDocument.documentElement, this.element);\n\n if (showEvent.isDefaultPrevented() || !isInTheDom) {\n return;\n }\n\n var tip = this.getTipElement();\n var tipId = Util.getUID(this.constructor.NAME);\n tip.setAttribute('id', tipId);\n this.element.setAttribute('aria-describedby', tipId);\n this.setContent();\n\n if (this.config.animation) {\n $(tip).addClass(CLASS_NAME_FADE$2);\n }\n\n var placement = typeof this.config.placement === 'function' ? this.config.placement.call(this, tip, this.element) : this.config.placement;\n\n var attachment = this._getAttachment(placement);\n\n this.addAttachmentClass(attachment);\n\n var container = this._getContainer();\n\n $(tip).data(this.constructor.DATA_KEY, this);\n\n if (!$.contains(this.element.ownerDocument.documentElement, this.tip)) {\n $(tip).appendTo(container);\n }\n\n $(this.element).trigger(this.constructor.Event.INSERTED);\n this._popper = new Popper(this.element, tip, this._getPopperConfig(attachment));\n $(tip).addClass(CLASS_NAME_SHOW$4); // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n\n if ('ontouchstart' in document.documentElement) {\n $(document.body).children().on('mouseover', null, $.noop);\n }\n\n var complete = function complete() {\n if (_this.config.animation) {\n _this._fixTransition();\n }\n\n var prevHoverState = _this._hoverState;\n _this._hoverState = null;\n $(_this.element).trigger(_this.constructor.Event.SHOWN);\n\n if (prevHoverState === HOVER_STATE_OUT) {\n _this._leave(null, _this);\n }\n };\n\n if ($(this.tip).hasClass(CLASS_NAME_FADE$2)) {\n var transitionDuration = Util.getTransitionDurationFromElement(this.tip);\n $(this.tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n } else {\n complete();\n }\n }\n };\n\n _proto.hide = function hide(callback) {\n var _this2 = this;\n\n var tip = this.getTipElement();\n var hideEvent = $.Event(this.constructor.Event.HIDE);\n\n var complete = function complete() {\n if (_this2._hoverState !== HOVER_STATE_SHOW && tip.parentNode) {\n tip.parentNode.removeChild(tip);\n }\n\n _this2._cleanTipClass();\n\n _this2.element.removeAttribute('aria-describedby');\n\n $(_this2.element).trigger(_this2.constructor.Event.HIDDEN);\n\n if (_this2._popper !== null) {\n _this2._popper.destroy();\n }\n\n if (callback) {\n callback();\n }\n };\n\n $(this.element).trigger(hideEvent);\n\n if (hideEvent.isDefaultPrevented()) {\n return;\n }\n\n $(tip).removeClass(CLASS_NAME_SHOW$4); // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n\n if ('ontouchstart' in document.documentElement) {\n $(document.body).children().off('mouseover', null, $.noop);\n }\n\n this._activeTrigger[TRIGGER_CLICK] = false;\n this._activeTrigger[TRIGGER_FOCUS] = false;\n this._activeTrigger[TRIGGER_HOVER] = false;\n\n if ($(this.tip).hasClass(CLASS_NAME_FADE$2)) {\n var transitionDuration = Util.getTransitionDurationFromElement(tip);\n $(tip).one(Util.TRANSITION_END, complete).emulateTransitionEnd(transitionDuration);\n } else {\n complete();\n }\n\n this._hoverState = '';\n };\n\n _proto.update = function update() {\n if (this._popper !== null) {\n this._popper.scheduleUpdate();\n }\n } // Protected\n ;\n\n _proto.isWithContent = function isWithContent() {\n return Boolean(this.getTitle());\n };\n\n _proto.addAttachmentClass = function addAttachmentClass(attachment) {\n $(this.getTipElement()).addClass(CLASS_PREFIX + \"-\" + attachment);\n };\n\n _proto.getTipElement = function getTipElement() {\n this.tip = this.tip || $(this.config.template)[0];\n return this.tip;\n };\n\n _proto.setContent = function setContent() {\n var tip = this.getTipElement();\n this.setElementContent($(tip.querySelectorAll(SELECTOR_TOOLTIP_INNER)), this.getTitle());\n $(tip).removeClass(CLASS_NAME_FADE$2 + \" \" + CLASS_NAME_SHOW$4);\n };\n\n _proto.setElementContent = function setElementContent($element, content) {\n if (typeof content === 'object' && (content.nodeType || content.jquery)) {\n // Content is a DOM node or a jQuery\n if (this.config.html) {\n if (!$(content).parent().is($element)) {\n $element.empty().append(content);\n }\n } else {\n $element.text($(content).text());\n }\n\n return;\n }\n\n if (this.config.html) {\n if (this.config.sanitize) {\n content = sanitizeHtml(content, this.config.whiteList, this.config.sanitizeFn);\n }\n\n $element.html(content);\n } else {\n $element.text(content);\n }\n };\n\n _proto.getTitle = function getTitle() {\n var title = this.element.getAttribute('data-original-title');\n\n if (!title) {\n title = typeof this.config.title === 'function' ? this.config.title.call(this.element) : this.config.title;\n }\n\n return title;\n } // Private\n ;\n\n _proto._getPopperConfig = function _getPopperConfig(attachment) {\n var _this3 = this;\n\n var defaultBsConfig = {\n placement: attachment,\n modifiers: {\n offset: this._getOffset(),\n flip: {\n behavior: this.config.fallbackPlacement\n },\n arrow: {\n element: SELECTOR_ARROW\n },\n preventOverflow: {\n boundariesElement: this.config.boundary\n }\n },\n onCreate: function onCreate(data) {\n if (data.originalPlacement !== data.placement) {\n _this3._handlePopperPlacementChange(data);\n }\n },\n onUpdate: function onUpdate(data) {\n return _this3._handlePopperPlacementChange(data);\n }\n };\n return _extends({}, defaultBsConfig, this.config.popperConfig);\n };\n\n _proto._getOffset = function _getOffset() {\n var _this4 = this;\n\n var offset = {};\n\n if (typeof this.config.offset === 'function') {\n offset.fn = function (data) {\n data.offsets = _extends({}, data.offsets, _this4.config.offset(data.offsets, _this4.element) || {});\n return data;\n };\n } else {\n offset.offset = this.config.offset;\n }\n\n return offset;\n };\n\n _proto._getContainer = function _getContainer() {\n if (this.config.container === false) {\n return document.body;\n }\n\n if (Util.isElement(this.config.container)) {\n return $(this.config.container);\n }\n\n return $(document).find(this.config.container);\n };\n\n _proto._getAttachment = function _getAttachment(placement) {\n return AttachmentMap[placement.toUpperCase()];\n };\n\n _proto._setListeners = function _setListeners() {\n var _this5 = this;\n\n var triggers = this.config.trigger.split(' ');\n triggers.forEach(function (trigger) {\n if (trigger === 'click') {\n $(_this5.element).on(_this5.constructor.Event.CLICK, _this5.config.selector, function (event) {\n return _this5.toggle(event);\n });\n } else if (trigger !== TRIGGER_MANUAL) {\n var eventIn = trigger === TRIGGER_HOVER ? _this5.constructor.Event.MOUSEENTER : _this5.constructor.Event.FOCUSIN;\n var eventOut = trigger === TRIGGER_HOVER ? _this5.constructor.Event.MOUSELEAVE : _this5.constructor.Event.FOCUSOUT;\n $(_this5.element).on(eventIn, _this5.config.selector, function (event) {\n return _this5._enter(event);\n }).on(eventOut, _this5.config.selector, function (event) {\n return _this5._leave(event);\n });\n }\n });\n\n this._hideModalHandler = function () {\n if (_this5.element) {\n _this5.hide();\n }\n };\n\n $(this.element).closest('.modal').on('hide.bs.modal', this._hideModalHandler);\n\n if (this.config.selector) {\n this.config = _extends({}, this.config, {\n trigger: 'manual',\n selector: ''\n });\n } else {\n this._fixTitle();\n }\n };\n\n _proto._fixTitle = function _fixTitle() {\n var titleType = typeof this.element.getAttribute('data-original-title');\n\n if (this.element.getAttribute('title') || titleType !== 'string') {\n this.element.setAttribute('data-original-title', this.element.getAttribute('title') || '');\n this.element.setAttribute('title', '');\n }\n };\n\n _proto._enter = function _enter(event, context) {\n var dataKey = this.constructor.DATA_KEY;\n context = context || $(event.currentTarget).data(dataKey);\n\n if (!context) {\n context = new this.constructor(event.currentTarget, this._getDelegateConfig());\n $(event.currentTarget).data(dataKey, context);\n }\n\n if (event) {\n context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true;\n }\n\n if ($(context.getTipElement()).hasClass(CLASS_NAME_SHOW$4) || context._hoverState === HOVER_STATE_SHOW) {\n context._hoverState = HOVER_STATE_SHOW;\n return;\n }\n\n clearTimeout(context._timeout);\n context._hoverState = HOVER_STATE_SHOW;\n\n if (!context.config.delay || !context.config.delay.show) {\n context.show();\n return;\n }\n\n context._timeout = setTimeout(function () {\n if (context._hoverState === HOVER_STATE_SHOW) {\n context.show();\n }\n }, context.config.delay.show);\n };\n\n _proto._leave = function _leave(event, context) {\n var dataKey = this.constructor.DATA_KEY;\n context = context || $(event.currentTarget).data(dataKey);\n\n if (!context) {\n context = new this.constructor(event.currentTarget, this._getDelegateConfig());\n $(event.currentTarget).data(dataKey, context);\n }\n\n if (event) {\n context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] = false;\n }\n\n if (context._isWithActiveTrigger()) {\n return;\n }\n\n clearTimeout(context._timeout);\n context._hoverState = HOVER_STATE_OUT;\n\n if (!context.config.delay || !context.config.delay.hide) {\n context.hide();\n return;\n }\n\n context._timeout = setTimeout(function () {\n if (context._hoverState === HOVER_STATE_OUT) {\n context.hide();\n }\n }, context.config.delay.hide);\n };\n\n _proto._isWithActiveTrigger = function _isWithActiveTrigger() {\n for (var trigger in this._activeTrigger) {\n if (this._activeTrigger[trigger]) {\n return true;\n }\n }\n\n return false;\n };\n\n _proto._getConfig = function _getConfig(config) {\n var dataAttributes = $(this.element).data();\n Object.keys(dataAttributes).forEach(function (dataAttr) {\n if (DISALLOWED_ATTRIBUTES.indexOf(dataAttr) !== -1) {\n delete dataAttributes[dataAttr];\n }\n });\n config = _extends({}, this.constructor.Default, dataAttributes, typeof config === 'object' && config ? config : {});\n\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n };\n }\n\n if (typeof config.title === 'number') {\n config.title = config.title.toString();\n }\n\n if (typeof config.content === 'number') {\n config.content = config.content.toString();\n }\n\n Util.typeCheckConfig(NAME$6, config, this.constructor.DefaultType);\n\n if (config.sanitize) {\n config.template = sanitizeHtml(config.template, config.whiteList, config.sanitizeFn);\n }\n\n return config;\n };\n\n _proto._getDelegateConfig = function _getDelegateConfig() {\n var config = {};\n\n if (this.config) {\n for (var key in this.config) {\n if (this.constructor.Default[key] !== this.config[key]) {\n config[key] = this.config[key];\n }\n }\n }\n\n return config;\n };\n\n _proto._cleanTipClass = function _cleanTipClass() {\n var $tip = $(this.getTipElement());\n var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX);\n\n if (tabClass !== null && tabClass.length) {\n $tip.removeClass(tabClass.join(''));\n }\n };\n\n _proto._handlePopperPlacementChange = function _handlePopperPlacementChange(popperData) {\n this.tip = popperData.instance.popper;\n\n this._cleanTipClass();\n\n this.addAttachmentClass(this._getAttachment(popperData.placement));\n };\n\n _proto._fixTransition = function _fixTransition() {\n var tip = this.getTipElement();\n var initConfigAnimation = this.config.animation;\n\n if (tip.getAttribute('x-placement') !== null) {\n return;\n }\n\n $(tip).removeClass(CLASS_NAME_FADE$2);\n this.config.animation = false;\n this.hide();\n this.show();\n this.config.animation = initConfigAnimation;\n } // Static\n ;\n\n Tooltip._jQueryInterface = function _jQueryInterface(config) {\n return this.each(function () {\n var data = $(this).data(DATA_KEY$6);\n\n var _config = typeof config === 'object' && config;\n\n if (!data && /dispose|hide/.test(config)) {\n return;\n }\n\n if (!data) {\n data = new Tooltip(this, _config);\n $(this).data(DATA_KEY$6, data);\n }\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n }\n\n data[config]();\n }\n });\n };\n\n _createClass(Tooltip, null, [{\n key: \"VERSION\",\n get: function get() {\n return VERSION$6;\n }\n }, {\n key: \"Default\",\n get: function get() {\n return Default$4;\n }\n }, {\n key: \"NAME\",\n get: function get() {\n return NAME$6;\n }\n }, {\n key: \"DATA_KEY\",\n get: function get() {\n return DATA_KEY$6;\n }\n }, {\n key: \"Event\",\n get: function get() {\n return Event;\n }\n }, {\n key: \"EVENT_KEY\",\n get: function get() {\n return EVENT_KEY$6;\n }\n }, {\n key: \"DefaultType\",\n get: function get() {\n return DefaultType$4;\n }\n }]);\n\n return Tooltip;\n }();\n /**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\n\n $.fn[NAME$6] = Tooltip._jQueryInterface;\n $.fn[NAME$6].Constructor = Tooltip;\n\n $.fn[NAME$6].noConflict = function () {\n $.fn[NAME$6] = JQUERY_NO_CONFLICT$6;\n return Tooltip._jQueryInterface;\n };\n\n /**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\n var NAME$7 = 'popover';\n var VERSION$7 = '4.5.2';\n var DATA_KEY$7 = 'bs.popover';\n var EVENT_KEY$7 = \".\" + DATA_KEY$7;\n var JQUERY_NO_CONFLICT$7 = $.fn[NAME$7];\n var CLASS_PREFIX$1 = 'bs-popover';\n var BSCLS_PREFIX_REGEX$1 = new RegExp(\"(^|\\\\s)\" + CLASS_PREFIX$1 + \"\\\\S+\", 'g');\n\n var Default$5 = _extends({}, Tooltip.Default, {\n placement: 'right',\n trigger: 'click',\n content: '',\n template: '
' + '
' + '

' + '
'\n });\n\n var DefaultType$5 = _extends({}, Tooltip.DefaultType, {\n content: '(string|element|function)'\n });\n\n var CLASS_NAME_FADE$3 = 'fade';\n var CLASS_NAME_SHOW$5 = 'show';\n var SELECTOR_TITLE = '.popover-header';\n var SELECTOR_CONTENT = '.popover-body';\n var Event$1 = {\n HIDE: \"hide\" + EVENT_KEY$7,\n HIDDEN: \"hidden\" + EVENT_KEY$7,\n SHOW: \"show\" + EVENT_KEY$7,\n SHOWN: \"shown\" + EVENT_KEY$7,\n INSERTED: \"inserted\" + EVENT_KEY$7,\n CLICK: \"click\" + EVENT_KEY$7,\n FOCUSIN: \"focusin\" + EVENT_KEY$7,\n FOCUSOUT: \"focusout\" + EVENT_KEY$7,\n MOUSEENTER: \"mouseenter\" + EVENT_KEY$7,\n MOUSELEAVE: \"mouseleave\" + EVENT_KEY$7\n };\n /**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\n var Popover = /*#__PURE__*/function (_Tooltip) {\n _inheritsLoose(Popover, _Tooltip);\n\n function Popover() {\n return _Tooltip.apply(this, arguments) || this;\n }\n\n var _proto = Popover.prototype;\n\n // Overrides\n _proto.isWithContent = function isWithContent() {\n return this.getTitle() || this._getContent();\n };\n\n _proto.addAttachmentClass = function addAttachmentClass(attachment) {\n $(this.getTipElement()).addClass(CLASS_PREFIX$1 + \"-\" + attachment);\n };\n\n _proto.getTipElement = function getTipElement() {\n this.tip = this.tip || $(this.config.template)[0];\n return this.tip;\n };\n\n _proto.setContent = function setContent() {\n var $tip = $(this.getTipElement()); // We use append for html objects to maintain js events\n\n this.setElementContent($tip.find(SELECTOR_TITLE), this.getTitle());\n\n var content = this._getContent();\n\n if (typeof content === 'function') {\n content = content.call(this.element);\n }\n\n this.setElementContent($tip.find(SELECTOR_CONTENT), content);\n $tip.removeClass(CLASS_NAME_FADE$3 + \" \" + CLASS_NAME_SHOW$5);\n } // Private\n ;\n\n _proto._getContent = function _getContent() {\n return this.element.getAttribute('data-content') || this.config.content;\n };\n\n _proto._cleanTipClass = function _cleanTipClass() {\n var $tip = $(this.getTipElement());\n var tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX$1);\n\n if (tabClass !== null && tabClass.length > 0) {\n $tip.removeClass(tabClass.join(''));\n }\n } // Static\n ;\n\n Popover._jQueryInterface = function _jQueryInterface(config) {\n return this.each(function () {\n var data = $(this).data(DATA_KEY$7);\n\n var _config = typeof config === 'object' ? config : null;\n\n if (!data && /dispose|hide/.test(config)) {\n return;\n }\n\n if (!data) {\n data = new Popover(this, _config);\n $(this).data(DATA_KEY$7, data);\n }\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(\"No method named \\\"\" + config + \"\\\"\");\n }\n\n data[config]();\n }\n });\n };\n\n _createClass(Popover, null, [{\n key: \"VERSION\",\n // Getters\n get: function get() {\n return VERSION$7;\n }\n }, {\n key: \"Default\",\n get: function get() {\n return Default$5;\n }\n }, {\n key: \"NAME\",\n get: function get() {\n return NAME$7;\n }\n }, {\n key: \"DATA_KEY\",\n get: function get() {\n return DATA_KEY$7;\n }\n }, {\n key: \"Event\",\n get: function get() {\n return Event$1;\n }\n }, {\n key: \"EVENT_KEY\",\n get: function get() {\n return EVENT_KEY$7;\n }\n }, {\n key: \"DefaultType\",\n get: function get() {\n return DefaultType$5;\n }\n }]);\n\n return Popover;\n }(Tooltip);\n /**\n * ------------------------------------------------------------------------\n * jQuery\n * ------------------------------------------------------------------------\n */\n\n\n $.fn[NAME$7] = Popover._jQueryInterface;\n $.fn[NAME$7].Constructor = Popover;\n\n $.fn[NAME$7].noConflict = function () {\n $.fn[NAME$7] = JQUERY_NO_CONFLICT$7;\n return Popover._jQueryInterface;\n };\n\n /**\n * ------------------------------------------------------------------------\n * Constants\n * ------------------------------------------------------------------------\n */\n\n var NAME$8 = 'scrollspy';\n var VERSION$8 = '4.5.2';\n var DATA_KEY$8 = 'bs.scrollspy';\n var EVENT_KEY$8 = \".\" + DATA_KEY$8;\n var DATA_API_KEY$6 = '.data-api';\n var JQUERY_NO_CONFLICT$8 = $.fn[NAME$8];\n var Default$6 = {\n offset: 10,\n method: 'auto',\n target: ''\n };\n var DefaultType$6 = {\n offset: 'number',\n method: 'string',\n target: '(string|element)'\n };\n var EVENT_ACTIVATE = \"activate\" + EVENT_KEY$8;\n var EVENT_SCROLL = \"scroll\" + EVENT_KEY$8;\n var EVENT_LOAD_DATA_API$2 = \"load\" + EVENT_KEY$8 + DATA_API_KEY$6;\n var CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item';\n var CLASS_NAME_ACTIVE$2 = 'active';\n var SELECTOR_DATA_SPY = '[data-spy=\"scroll\"]';\n var SELECTOR_NAV_LIST_GROUP = '.nav, .list-group';\n var SELECTOR_NAV_LINKS = '.nav-link';\n var SELECTOR_NAV_ITEMS = '.nav-item';\n var SELECTOR_LIST_ITEMS = '.list-group-item';\n var SELECTOR_DROPDOWN = '.dropdown';\n var SELECTOR_DROPDOWN_ITEMS = '.dropdown-item';\n var SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle';\n var METHOD_OFFSET = 'offset';\n var METHOD_POSITION = 'position';\n /**\n * ------------------------------------------------------------------------\n * Class Definition\n * ------------------------------------------------------------------------\n */\n\n var ScrollSpy = /*#__PURE__*/function () {\n function ScrollSpy(element, config) {\n var _this = this;\n\n this._element = element;\n this._scrollElement = element.tagName === 'BODY' ? window : element;\n this._config = this._getConfig(config);\n this._selector = this._config.target + \" \" + SELECTOR_NAV_LINKS + \",\" + (this._config.target + \" \" + SELECTOR_LIST_ITEMS + \",\") + (this._config.target + \" \" + SELECTOR_DROPDOWN_ITEMS);\n this._offsets = [];\n this._targets = [];\n this._activeTarget = null;\n this._scrollHeight = 0;\n $(this._scrollElement).on(EVENT_SCROLL, function (event) {\n return _this._process(event);\n });\n this.refresh();\n\n this._process();\n } // Getters\n\n\n var _proto = ScrollSpy.prototype;\n\n // Public\n _proto.refresh = function refresh() {\n var _this2 = this;\n\n var autoMethod = this._scrollElement === this._scrollElement.window ? METHOD_OFFSET : METHOD_POSITION;\n var offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method;\n var offsetBase = offsetMethod === METHOD_POSITION ? this._getScrollTop() : 0;\n this._offsets = [];\n this._targets = [];\n this._scrollHeight = this._getScrollHeight();\n var targets = [].slice.call(document.querySelectorAll(this._selector));\n targets.map(function (element) {\n var target;\n var targetSelector = Util.getSelectorFromElement(element);\n\n if (targetSelector) {\n target = document.querySelector(targetSelector);\n }\n\n if (target) {\n var targetBCR = target.getBoundingClientRect();\n\n if (targetBCR.width || targetBCR.height) {\n // TODO (fat): remove sketch reliance on jQuery position/offset\n return [$(target)[offsetMethod]().top + offsetBase, targetSelector];\n }\n }\n\n return null;\n }).filter(function (item) {\n return item;\n }).sort(function (a, b) {\n return a[0] - b[0];\n }).forEach(function (item) {\n _this2._offsets.push(item[0]);\n\n _this2._targets.push(item[1]);\n });\n };\n\n _proto.dispose = function dispose() {\n $.removeData(this._element, DATA_KEY$8);\n $(this._scrollElement).off(EVENT_KEY$8);\n this._element = null;\n this._scrollElement = null;\n this._config = null;\n this._selector = null;\n this._offsets = null;\n this._targets = null;\n this._activeTarget = null;\n this._scrollHeight = null;\n } // Private\n ;\n\n _proto._getConfig = function _getConfig(config) {\n config = _extends({}, Default$6, typeof config === 'object' && config ? config : {});\n\n if (typeof config.target !== 'string' && Util.isElement(config.target)) {\n var id = $(config.target).attr('id');\n\n if (!id) {\n id = Util.getUID(NAME$8);\n $(config.target).attr('id', id);\n }\n\n config.target = \"#\" + id;\n }\n\n Util.typeCheckConfig(NAME$8, config, DefaultType$6);\n return config;\n };\n\n _proto._getScrollTop = function _getScrollTop() {\n return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop;\n };\n\n _proto._getScrollHeight = function _getScrollHeight() {\n return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight);\n };\n\n _proto._getOffsetHeight = function _getOffsetHeight() {\n return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height;\n };\n\n _proto._process = function _process() {\n var scrollTop = this._getScrollTop() + this._config.offset;\n\n var scrollHeight = this._getScrollHeight();\n\n var maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight();\n\n if (this._scrollHeight !== scrollHeight) {\n this.refresh();\n }\n\n if (scrollTop >= maxScroll) {\n var target = this._targets[this._targets.length - 1];\n\n if (this._activeTarget !== target) {\n this._activate(target);\n }\n\n return;\n }\n\n if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {\n this._activeTarget = null;\n\n this._clear();\n\n return;\n }\n\n for (var i = this._offsets.length; i--;) {\n var isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]);\n\n if (isActiveTarget) {\n this._activate(this._targets[i]);\n }\n }\n };\n\n _proto._activate = function _activate(target) {\n this._activeTarget = target;\n\n this._clear();\n\n var queries = this._selector.split(',').map(function (selector) {\n return selector + \"[data-target=\\\"\" + target + \"\\\"],\" + selector + \"[href=\\\"\" + target + \"\\\"]\";\n });\n\n var $link = $([].slice.call(document.querySelectorAll(queries.join(','))));\n\n if ($link.hasClass(CLASS_NAME_DROPDOWN_ITEM)) {\n $link.closest(SELECTOR_DROPDOWN).find(SELECTOR_DROPDOWN_TOGGLE).addClass(CLASS_NAME_ACTIVE$2);\n $link.addClass(CLASS_NAME_ACTIVE$2);\n } else {\n // Set triggered link as active\n $link.addClass(CLASS_NAME_ACTIVE$2); // Set triggered links parents as active\n // With both
    and