diff --git a/README.md b/README.md index 86a4df4..40fb4a7 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ has loaded. # Getting started -Checkout the Demo +Checkout the Demo and Blueprint or `npm i -S search-collector` diff --git a/demo/index.html b/demo/index.html index 374bc22..544ef20 100644 --- a/demo/index.html +++ b/demo/index.html @@ -73,6 +73,10 @@

Usage

  1. Search for any search phrase
  2. +
  3. + (Optional) search for a "redirect" to be redirected to a special campaign landing page to test redirect + tracking +
  4. Click a product
  5. Put it into the basket
  6. Repeat as many times you wish
  7. diff --git a/demo/js/collector-integration.js b/demo/js/collector-integration.js index bbfeff5..f6104e9 100644 --- a/demo/js/collector-integration.js +++ b/demo/js/collector-integration.js @@ -24,7 +24,8 @@ const { CheckoutClickCollector, ConsoleTransport, SuggestSearchCollector, - AssociatedProductCollector + AssociatedProductCollector, + ListenerType, } = window.SearchCollector; @@ -88,13 +89,44 @@ collectorModule.add(new SuggestSearchCollector((writer, type, context) => { }); })); -collectorModule.add(new RedirectCollector(firedSearchCallback, isSearchPage, context)); +const redirectProductClickCollector = new ProductClickCollector('[data-track-id="product"]', { + idResolver: element => element.getAttribute('data-product-id'), + positionResolver: element => positionResolver('[data-track-id="product"]', element), + priceResolver: element => extractPrice(element.querySelector('[data-track-id="priceContainer"]')?.textContent), + metadataResolver: element => void 0, // metadata can be anything + trail +}); + +const redirectImpressionCollector = new ImpressionCollector('[data-track-id="product"]', + element => element.getAttribute('data-product-id'), + element => positionResolver('[data-track-id="product"]', element)); + +redirectProductClickCollector.setContext(context); +redirectImpressionCollector.setContext(context); + +collectorModule.add(new RedirectCollector(firedSearchCallback, isSearchPage, { + resultCountResolver: searchResultCountResolver, + collectors: [redirectProductClickCollector, redirectImpressionCollector], + nestedRedirects: { + depth: 2, + subSelectors: ['[data-track-id="redirectSubSelector"]'] + } +}, ListenerType.Sentinel, context)); + +// basket PDP collectorModule.add( new BasketClickCollector('[data-track-id="addToCartPDP"]', element => element.getAttribute('data-product-id'), element => extractPrice(document.querySelector('[data-track-id="priceContainer"]').textContent)) ); +// basket PLP +collectorModule.add( + new BasketClickCollector('[data-track-id="addToCartPLP"]', + element => element.getAttribute('data-product-id'), + element => extractPrice(document.querySelector('[data-track-id="priceContainer"]').textContent)) +); + collectorModule.add( new CheckoutClickCollector('[data-track-id="checkoutButton"]', '[data-track-id="checkoutProduct"]', element => element.getAttribute("data-product-id"), diff --git a/demo/js/index.window.bundle.js b/demo/js/index.window.bundle.js index c28914a..607ceb2 100644 --- a/demo/js/index.window.bundle.js +++ b/demo/js/index.window.bundle.js @@ -1,14 +1,548 @@ /******/ (() => { // webpackBootstrap +/******/ "use strict"; /******/ var __webpack_modules__ = ({ -/***/ "./node_modules/scrollmonitor/scrollMonitor.js": -/*!*****************************************************!*\ - !*** ./node_modules/scrollmonitor/scrollMonitor.js ***! - \*****************************************************/ -/***/ (function(module) { +/***/ "./node_modules/scrollmonitor/dist/module/index.js": +/*!*********************************************************!*\ + !*** ./node_modules/scrollmonitor/dist/module/index.js ***! + \*********************************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -!function(t,e){ true?module.exports=e():0}(this,function(){return function(t){function e(o){if(i[o])return i[o].exports;var s=i[o]={exports:{},id:o,loaded:!1};return t[o].call(s.exports,s,s.exports,e),s.loaded=!0,s.exports}var i={};return e.m=t,e.c=i,e.p="",e(0)}([function(t,e,i){"use strict";var o=i(1),s=o.isInBrowser,n=i(2),r=new n(s?document.body:null);r.setStateFromDOM(null),r.listenToDOM(),s&&(window.scrollMonitor=r),t.exports=r},function(t,e){"use strict";e.VISIBILITYCHANGE="visibilityChange",e.ENTERVIEWPORT="enterViewport",e.FULLYENTERVIEWPORT="fullyEnterViewport",e.EXITVIEWPORT="exitViewport",e.PARTIALLYEXITVIEWPORT="partiallyExitViewport",e.LOCATIONCHANGE="locationChange",e.STATECHANGE="stateChange",e.eventTypes=[e.VISIBILITYCHANGE,e.ENTERVIEWPORT,e.FULLYENTERVIEWPORT,e.EXITVIEWPORT,e.PARTIALLYEXITVIEWPORT,e.LOCATIONCHANGE,e.STATECHANGE],e.isOnServer="undefined"==typeof window,e.isInBrowser=!e.isOnServer,e.defaultOffsets={top:0,bottom:0}},function(t,e,i){"use strict";function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function s(t){return c?0:t===document.body?window.innerHeight||document.documentElement.clientHeight:t.clientHeight}function n(t){return c?0:t===document.body?Math.max(document.body.scrollHeight,document.documentElement.scrollHeight,document.body.offsetHeight,document.documentElement.offsetHeight,document.documentElement.clientHeight):t.scrollHeight}function r(t){return c?0:t===document.body?window.pageYOffset||document.documentElement&&document.documentElement.scrollTop||document.body.scrollTop:t.scrollTop}var h=i(1),c=h.isOnServer,a=h.isInBrowser,l=h.eventTypes,p=i(3),u=!1;if(a)try{var w=Object.defineProperty({},"passive",{get:function(){u=!0}});window.addEventListener("test",null,w)}catch(t){}var d=!!u&&{capture:!1,passive:!0},f=function(){function t(e,i){function h(){if(a.viewportTop=r(e),a.viewportBottom=a.viewportTop+a.viewportHeight,a.documentHeight=n(e),a.documentHeight!==p){for(u=a.watchers.length;u--;)a.watchers[u].recalculateLocation();p=a.documentHeight}}function c(){for(w=a.watchers.length;w--;)a.watchers[w].update();for(w=a.watchers.length;w--;)a.watchers[w].triggerCallbacks()}o(this,t);var a=this;this.item=e,this.watchers=[],this.viewportTop=null,this.viewportBottom=null,this.documentHeight=n(e),this.viewportHeight=s(e),this.DOMListener=function(){t.prototype.DOMListener.apply(a,arguments)},this.eventTypes=l,i&&(this.containerWatcher=i.create(e));var p,u,w;this.update=function(){h(),c()},this.recalculateLocations=function(){this.documentHeight=0,this.update()}}return t.prototype.listenToDOM=function(){a&&(window.addEventListener?(this.item===document.body?window.addEventListener("scroll",this.DOMListener,d):this.item.addEventListener("scroll",this.DOMListener,d),window.addEventListener("resize",this.DOMListener)):(this.item===document.body?window.attachEvent("onscroll",this.DOMListener):this.item.attachEvent("onscroll",this.DOMListener),window.attachEvent("onresize",this.DOMListener)),this.destroy=function(){window.addEventListener?(this.item===document.body?(window.removeEventListener("scroll",this.DOMListener,d),this.containerWatcher.destroy()):this.item.removeEventListener("scroll",this.DOMListener,d),window.removeEventListener("resize",this.DOMListener)):(this.item===document.body?(window.detachEvent("onscroll",this.DOMListener),this.containerWatcher.destroy()):this.item.detachEvent("onscroll",this.DOMListener),window.detachEvent("onresize",this.DOMListener))})},t.prototype.destroy=function(){},t.prototype.DOMListener=function(t){this.setStateFromDOM(t)},t.prototype.setStateFromDOM=function(t){var e=r(this.item),i=s(this.item),o=n(this.item);this.setState(e,i,o,t)},t.prototype.setState=function(t,e,i,o){var s=e!==this.viewportHeight||i!==this.contentHeight;if(this.latestEvent=o,this.viewportTop=t,this.viewportHeight=e,this.viewportBottom=t+e,this.contentHeight=i,s)for(var n=this.watchers.length;n--;)this.watchers[n].recalculateLocation();this.updateAndTriggerWatchers(o)},t.prototype.updateAndTriggerWatchers=function(t){for(var e=this.watchers.length;e--;)this.watchers[e].update();for(e=this.watchers.length;e--;)this.watchers[e].triggerCallbacks(t)},t.prototype.createCustomContainer=function(){return new t},t.prototype.createContainer=function(e){"string"==typeof e?e=document.querySelector(e):e&&e.length>0&&(e=e[0]);var i=new t(e,this);return i.setStateFromDOM(),i.listenToDOM(),i},t.prototype.create=function(t,e){"string"==typeof t?t=document.querySelector(t):t&&t.length>0&&(t=t[0]);var i=new p(this,t,e);return this.watchers.push(i),i},t.prototype.beget=function(t,e){return this.create(t,e)},t}();t.exports=f},function(t,e,i){"use strict";function o(t,e,i){function o(t,e){if(0!==t.length)for(E=t.length;E--;)y=t[E],y.callback.call(s,e,s),y.isOne&&t.splice(E,1)}var s=this;this.watchItem=e,this.container=t,i?i===+i?this.offsets={top:i,bottom:i}:this.offsets={top:i.top||w.top,bottom:i.bottom||w.bottom}:this.offsets=w,this.callbacks={};for(var d=0,f=u.length;d0?this.top=this.bottom=this.watchItem:this.top=this.bottom=this.container.documentHeight-this.watchItem:(this.top=this.watchItem.top,this.bottom=this.watchItem.bottom);this.top-=this.offsets.top,this.bottom+=this.offsets.bottom,this.height=this.bottom-this.top,void 0===t&&void 0===e||this.top===t&&this.bottom===e||o(this.callbacks[l],null)}},this.recalculateLocation(),this.update(),m=this.isInViewport,v=this.isFullyInViewport,b=this.isAboveViewport,I=this.isBelowViewport}var s=i(1),n=s.VISIBILITYCHANGE,r=s.ENTERVIEWPORT,h=s.FULLYENTERVIEWPORT,c=s.EXITVIEWPORT,a=s.PARTIALLYEXITVIEWPORT,l=s.LOCATIONCHANGE,p=s.STATECHANGE,u=s.eventTypes,w=s.defaultOffsets;o.prototype={on:function(t,e,i){switch(!0){case t===n&&!this.isInViewport&&this.isAboveViewport:case t===r&&this.isInViewport:case t===h&&this.isFullyInViewport:case t===c&&this.isAboveViewport&&!this.isInViewport:case t===a&&this.isInViewport&&this.isAboveViewport:if(e.call(this,this.container.latestEvent,this),i)return}if(!this.callbacks[t])throw new Error("Tried to add a scroll monitor listener of type "+t+". Your options are: "+u.join(", "));this.callbacks[t].push({callback:e,isOne:i||!1})},off:function(t,e){if(!this.callbacks[t])throw new Error("Tried to remove a scroll monitor listener of type "+t+". Your options are: "+u.join(", "));for(var i,o=0;i=this.callbacks[t][o];o++)if(i.callback===e){this.callbacks[t].splice(o,1);break}},one:function(t,e){this.on(t,e,!0)},recalculateSize:function(){this.height=this.watchItem.offsetHeight+this.offsets.top+this.offsets.bottom,this.bottom=this.top+this.height},update:function(){this.isAboveViewport=this.topthis.container.viewportBottom,this.isInViewport=this.topthis.container.viewportTop,this.isFullyInViewport=this.top>=this.container.viewportTop&&this.bottom<=this.container.viewportBottom||this.isAboveViewport&&this.isBelowViewport},destroy:function(){var t=this.container.watchers.indexOf(this),e=this;this.container.watchers.splice(t,1);for(var i=0,o=u.length;i (/* reexport safe */ _src_container_js__WEBPACK_IMPORTED_MODULE_0__.ScrollMonitorContainer), +/* harmony export */ "Watcher": () => (/* reexport safe */ _src_watcher_js__WEBPACK_IMPORTED_MODULE_1__.Watcher), +/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _src_container_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./src/container.js */ "./node_modules/scrollmonitor/dist/module/src/container.js"); +/* harmony import */ var _src_watcher_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./src/watcher.js */ "./node_modules/scrollmonitor/dist/module/src/watcher.js"); +/* harmony import */ var _src_types__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./src/types */ "./node_modules/scrollmonitor/dist/module/src/types.js"); +/* harmony import */ var _src_constants_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./src/constants.js */ "./node_modules/scrollmonitor/dist/module/src/constants.js"); + + + + + +// this is needed for the type, but if we're not in a browser the only +// way listenToDOM will be called is if you call scrollmonitor.createContainer +// and you can't do that until you have a DOM element. +var scrollMonitor = new _src_container_js__WEBPACK_IMPORTED_MODULE_0__.ScrollMonitorContainer(_src_constants_js__WEBPACK_IMPORTED_MODULE_3__.isInBrowser ? document.body : undefined); +if (_src_constants_js__WEBPACK_IMPORTED_MODULE_3__.isInBrowser) { + scrollMonitor.updateState(); + scrollMonitor.listenToDOM(); +} +//@ts-ignore +window.scrollMonitor = scrollMonitor; +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (scrollMonitor); +//# sourceMappingURL=index.js.map + +/***/ }), + +/***/ "./node_modules/scrollmonitor/dist/module/src/constants.js": +/*!*****************************************************************!*\ + !*** ./node_modules/scrollmonitor/dist/module/src/constants.js ***! + \*****************************************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "ENTERVIEWPORT": () => (/* binding */ ENTERVIEWPORT), +/* harmony export */ "EXITVIEWPORT": () => (/* binding */ EXITVIEWPORT), +/* harmony export */ "FULLYENTERVIEWPORT": () => (/* binding */ FULLYENTERVIEWPORT), +/* harmony export */ "LOCATIONCHANGE": () => (/* binding */ LOCATIONCHANGE), +/* harmony export */ "PARTIALLYEXITVIEWPORT": () => (/* binding */ PARTIALLYEXITVIEWPORT), +/* harmony export */ "STATECHANGE": () => (/* binding */ STATECHANGE), +/* harmony export */ "VISIBILITYCHANGE": () => (/* binding */ VISIBILITYCHANGE), +/* harmony export */ "defaultOffsets": () => (/* binding */ defaultOffsets), +/* harmony export */ "eventTypes": () => (/* binding */ eventTypes), +/* harmony export */ "isInBrowser": () => (/* binding */ isInBrowser), +/* harmony export */ "isOnServer": () => (/* binding */ isOnServer) +/* harmony export */ }); +var VISIBILITYCHANGE = 'visibilityChange'; +var ENTERVIEWPORT = 'enterViewport'; +var FULLYENTERVIEWPORT = 'fullyEnterViewport'; +var EXITVIEWPORT = 'exitViewport'; +var PARTIALLYEXITVIEWPORT = 'partiallyExitViewport'; +var LOCATIONCHANGE = 'locationChange'; +var STATECHANGE = 'stateChange'; +var eventTypes = [ + VISIBILITYCHANGE, + ENTERVIEWPORT, + FULLYENTERVIEWPORT, + EXITVIEWPORT, + PARTIALLYEXITVIEWPORT, + LOCATIONCHANGE, + STATECHANGE, +]; +var isOnServer = typeof window === 'undefined'; +var isInBrowser = !isOnServer; +var defaultOffsets = { top: 0, bottom: 0 }; +//# sourceMappingURL=constants.js.map + +/***/ }), + +/***/ "./node_modules/scrollmonitor/dist/module/src/container.js": +/*!*****************************************************************!*\ + !*** ./node_modules/scrollmonitor/dist/module/src/container.js ***! + \*****************************************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "ScrollMonitorContainer": () => (/* binding */ ScrollMonitorContainer) +/* harmony export */ }); +/* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./constants.js */ "./node_modules/scrollmonitor/dist/module/src/constants.js"); +/* harmony import */ var _watcher_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./watcher.js */ "./node_modules/scrollmonitor/dist/module/src/watcher.js"); + + +function getViewportHeight(element) { + if (_constants_js__WEBPACK_IMPORTED_MODULE_0__.isOnServer) { + return 0; + } + if (element === document.body) { + return window.innerHeight || document.documentElement.clientHeight; + } + else { + return element.clientHeight; + } +} +function getContentHeight(element) { + if (_constants_js__WEBPACK_IMPORTED_MODULE_0__.isOnServer) { + return 0; + } + if (element === document.body) { + // jQuery approach + // whichever is greatest + return Math.max(document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.documentElement.clientHeight); + } + else { + return element.scrollHeight; + } +} +function scrollTop(element) { + if (_constants_js__WEBPACK_IMPORTED_MODULE_0__.isOnServer) { + return 0; + } + if (element === document.body) { + return (window.pageYOffset || + (document.documentElement && document.documentElement.scrollTop) || + document.body.scrollTop); + } + else { + return element.scrollTop; + } +} +var browserSupportsPassive = false; +if (_constants_js__WEBPACK_IMPORTED_MODULE_0__.isInBrowser) { + try { + var opts = Object.defineProperty({}, 'passive', { + get: function () { + browserSupportsPassive = true; + }, + }); + window.addEventListener('test', null, opts); + } + catch (e) { } +} +var useCapture = browserSupportsPassive ? { capture: false, passive: true } : false; +var ScrollMonitorContainer = /** @class */ (function () { + function ScrollMonitorContainer(item, parentWatcher) { + this.eventTypes = _constants_js__WEBPACK_IMPORTED_MODULE_0__.eventTypes; + var self = this; + this.item = item; + this.watchers = []; + this.viewportTop = null; + this.viewportBottom = null; + this.documentHeight = getContentHeight(item); + this.viewportHeight = getViewportHeight(item); + this.DOMListener = function () { + ScrollMonitorContainer.prototype.DOMListener.apply(self, arguments); + }; + if (parentWatcher) { + this.containerWatcher = parentWatcher.create(item); + } + var previousDocumentHeight; + var calculateViewportI; + function calculateViewport() { + self.viewportTop = scrollTop(item); + self.viewportBottom = self.viewportTop + self.viewportHeight; + self.documentHeight = getContentHeight(item); + if (self.documentHeight !== previousDocumentHeight) { + calculateViewportI = self.watchers.length; + while (calculateViewportI--) { + self.watchers[calculateViewportI].recalculateLocation(); + } + previousDocumentHeight = self.documentHeight; + } + } + var updateAndTriggerWatchersI; + function updateAndTriggerWatchers() { + // update all watchers then trigger the events so one can rely on another being up to date. + updateAndTriggerWatchersI = self.watchers.length; + while (updateAndTriggerWatchersI--) { + self.watchers[updateAndTriggerWatchersI].update(); + } + updateAndTriggerWatchersI = self.watchers.length; + while (updateAndTriggerWatchersI--) { + self.watchers[updateAndTriggerWatchersI].triggerCallbacks(undefined); + } + } + this.update = function () { + calculateViewport(); + updateAndTriggerWatchers(); + }; + this.recalculateLocations = function () { + this.documentHeight = 0; + this.update(); + }; + } + ScrollMonitorContainer.prototype.listenToDOM = function () { + if (_constants_js__WEBPACK_IMPORTED_MODULE_0__.isInBrowser) { + if (this.item === document.body) { + window.addEventListener('scroll', this.DOMListener, useCapture); + } + else { + this.item.addEventListener('scroll', this.DOMListener, useCapture); + } + window.addEventListener('resize', this.DOMListener); + this.destroy = function () { + if (this.item === document.body) { + window.removeEventListener('scroll', this.DOMListener, useCapture); + this.containerWatcher.destroy(); + } + else { + this.item.removeEventListener('scroll', this.DOMListener, useCapture); + } + window.removeEventListener('resize', this.DOMListener); + }; + } + }; + ScrollMonitorContainer.prototype.destroy = function () { + // noop, override for your own purposes. + // in listenToDOM, for example. + }; + ScrollMonitorContainer.prototype.DOMListener = function (event) { + //alert('got scroll'); + this.updateState(); + this.updateAndTriggerWatchers(event); + }; + ScrollMonitorContainer.prototype.updateState = function () { + var viewportTop = scrollTop(this.item); + var viewportHeight = getViewportHeight(this.item); + var contentHeight = getContentHeight(this.item); + var needsRecalcuate = viewportHeight !== this.viewportHeight || contentHeight !== this.contentHeight; + this.viewportTop = viewportTop; + this.viewportHeight = viewportHeight; + this.viewportBottom = viewportTop + viewportHeight; + this.contentHeight = contentHeight; + if (needsRecalcuate) { + var i = this.watchers.length; + while (i--) { + this.watchers[i].recalculateLocation(); + } + } + }; + ScrollMonitorContainer.prototype.updateAndTriggerWatchers = function (event) { + var i = this.watchers.length; + while (i--) { + this.watchers[i].update(); + } + i = this.watchers.length; + while (i--) { + this.watchers[i].triggerCallbacks(event); + } + }; + ScrollMonitorContainer.prototype.createContainer = function (input) { + var item; + if (typeof input === 'string') { + item = document.querySelector(input); + } + else if (Array.isArray(input) || input instanceof NodeList) { + item = input[0]; + } + else { + item = input; + } + var container = new ScrollMonitorContainer(item, this); + this.updateState(); + container.listenToDOM(); + return container; + }; + ScrollMonitorContainer.prototype.create = function (input, offsets) { + var item; + if (typeof item === 'string') { + item = document.querySelector(item); + } + else if (Array.isArray(input) || input instanceof NodeList) { + item = input[0]; + } + else { + item = input; + } + var watcher = new _watcher_js__WEBPACK_IMPORTED_MODULE_1__.Watcher(this, item, offsets); + this.watchers.push(watcher); + return watcher; + }; + /** + * @deprecated since version 1.1 + */ + ScrollMonitorContainer.prototype.beget = function (input, offsets) { + return this.create(input, offsets); + }; + return ScrollMonitorContainer; +}()); + +//# sourceMappingURL=container.js.map + +/***/ }), + +/***/ "./node_modules/scrollmonitor/dist/module/src/types.js": +/*!*************************************************************!*\ + !*** ./node_modules/scrollmonitor/dist/module/src/types.js ***! + \*************************************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); + +//# sourceMappingURL=types.js.map + +/***/ }), + +/***/ "./node_modules/scrollmonitor/dist/module/src/watcher.js": +/*!***************************************************************!*\ + !*** ./node_modules/scrollmonitor/dist/module/src/watcher.js ***! + \***************************************************************/ +/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "Watcher": () => (/* binding */ Watcher) +/* harmony export */ }); +/* harmony import */ var _constants_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./constants.js */ "./node_modules/scrollmonitor/dist/module/src/constants.js"); + +var Watcher = /** @class */ (function () { + function Watcher(container, watchItem, offsets) { + this.container = container; + this.watchItem = watchItem; + this.locked = false; + this.callbacks = {}; + var self = this; + if (!offsets) { + this.offsets = _constants_js__WEBPACK_IMPORTED_MODULE_0__.defaultOffsets; + } + else if (typeof offsets === 'number') { + this.offsets = { top: offsets, bottom: offsets }; + } + else { + this.offsets = { + top: 'top' in offsets ? offsets.top : _constants_js__WEBPACK_IMPORTED_MODULE_0__.defaultOffsets.top, + bottom: 'bottom' in offsets ? offsets.bottom : _constants_js__WEBPACK_IMPORTED_MODULE_0__.defaultOffsets.bottom, + }; + } + for (var i = 0, j = _constants_js__WEBPACK_IMPORTED_MODULE_0__.eventTypes.length; i < j; i++) { + self.callbacks[_constants_js__WEBPACK_IMPORTED_MODULE_0__.eventTypes[i]] = []; + } + this.locked = false; + var wasInViewport; + var wasFullyInViewport; + var wasAboveViewport; + var wasBelowViewport; + var listenerToTriggerListI; + var listener; + var needToTriggerStateChange = false; + function triggerCallbackArray(listeners, event) { + needToTriggerStateChange = true; + if (listeners.length === 0) { + return; + } + listenerToTriggerListI = listeners.length; + while (listenerToTriggerListI--) { + listener = listeners[listenerToTriggerListI]; + listener.callback.call(self, event, self); + if (listener.isOne) { + listeners.splice(listenerToTriggerListI, 1); + } + } + } + this.triggerCallbacks = function triggerCallbacks(event) { + if (this.isInViewport && !wasInViewport) { + triggerCallbackArray(this.callbacks[_constants_js__WEBPACK_IMPORTED_MODULE_0__.ENTERVIEWPORT], event); + } + if (this.isFullyInViewport && !wasFullyInViewport) { + triggerCallbackArray(this.callbacks[_constants_js__WEBPACK_IMPORTED_MODULE_0__.FULLYENTERVIEWPORT], event); + } + if (this.isAboveViewport !== wasAboveViewport && + this.isBelowViewport !== wasBelowViewport) { + triggerCallbackArray(this.callbacks[_constants_js__WEBPACK_IMPORTED_MODULE_0__.VISIBILITYCHANGE], event); + // if you skip completely past this element + if (!wasFullyInViewport && !this.isFullyInViewport) { + triggerCallbackArray(this.callbacks[_constants_js__WEBPACK_IMPORTED_MODULE_0__.FULLYENTERVIEWPORT], event); + triggerCallbackArray(this.callbacks[_constants_js__WEBPACK_IMPORTED_MODULE_0__.PARTIALLYEXITVIEWPORT], event); + } + if (!wasInViewport && !this.isInViewport) { + triggerCallbackArray(this.callbacks[_constants_js__WEBPACK_IMPORTED_MODULE_0__.ENTERVIEWPORT], event); + triggerCallbackArray(this.callbacks[_constants_js__WEBPACK_IMPORTED_MODULE_0__.EXITVIEWPORT], event); + } + } + if (!this.isFullyInViewport && wasFullyInViewport) { + triggerCallbackArray(this.callbacks[_constants_js__WEBPACK_IMPORTED_MODULE_0__.PARTIALLYEXITVIEWPORT], event); + } + if (!this.isInViewport && wasInViewport) { + triggerCallbackArray(this.callbacks[_constants_js__WEBPACK_IMPORTED_MODULE_0__.EXITVIEWPORT], event); + } + if (this.isInViewport !== wasInViewport) { + triggerCallbackArray(this.callbacks[_constants_js__WEBPACK_IMPORTED_MODULE_0__.VISIBILITYCHANGE], event); + } + if (needToTriggerStateChange) { + needToTriggerStateChange = false; + triggerCallbackArray(this.callbacks[_constants_js__WEBPACK_IMPORTED_MODULE_0__.STATECHANGE], event); + } + wasInViewport = this.isInViewport; + wasFullyInViewport = this.isFullyInViewport; + wasAboveViewport = this.isAboveViewport; + wasBelowViewport = this.isBelowViewport; + }; + this.recalculateLocation = function () { + if (this.locked) { + return; + } + var previousTop = this.top; + var previousBottom = this.bottom; + if (this.watchItem.nodeName) { + // a dom element + var cachedDisplay = this.watchItem.style.display; + if (cachedDisplay === 'none') { + this.watchItem.style.display = ''; + } + var containerOffset = 0; + var container = this.container; + while (container.containerWatcher) { + containerOffset += + container.containerWatcher.top - + container.containerWatcher.container.viewportTop; + container = container.containerWatcher.container; + } + var boundingRect = this.watchItem.getBoundingClientRect(); + this.top = boundingRect.top + this.container.viewportTop - containerOffset; + this.bottom = boundingRect.bottom + this.container.viewportTop - containerOffset; + if (cachedDisplay === 'none') { + this.watchItem.style.display = cachedDisplay; + } + } + else if (this.watchItem === +this.watchItem) { + // number + if (this.watchItem > 0) { + this.top = this.bottom = this.watchItem; + } + else { + this.top = this.bottom = this.container.documentHeight - this.watchItem; + } + } + else { + // an object with a top and bottom property + this.top = this.watchItem.top; + this.bottom = this.watchItem.bottom; + } + this.top -= this.offsets.top; + this.bottom += this.offsets.bottom; + this.height = this.bottom - this.top; + if ((previousTop !== undefined || previousBottom !== undefined) && + (this.top !== previousTop || this.bottom !== previousBottom)) { + triggerCallbackArray(this.callbacks[_constants_js__WEBPACK_IMPORTED_MODULE_0__.LOCATIONCHANGE], undefined); + } + }; + this.recalculateLocation(); + this.update(); + wasInViewport = this.isInViewport; + wasFullyInViewport = this.isFullyInViewport; + wasAboveViewport = this.isAboveViewport; + wasBelowViewport = this.isBelowViewport; + } + Watcher.prototype.on = function (event, callback, isOne) { + if (isOne === void 0) { isOne = false; } + // trigger the event if it applies to the element right now. + switch (true) { + case event === _constants_js__WEBPACK_IMPORTED_MODULE_0__.VISIBILITYCHANGE && !this.isInViewport && this.isAboveViewport: + case event === _constants_js__WEBPACK_IMPORTED_MODULE_0__.ENTERVIEWPORT && this.isInViewport: + case event === _constants_js__WEBPACK_IMPORTED_MODULE_0__.FULLYENTERVIEWPORT && this.isFullyInViewport: + case event === _constants_js__WEBPACK_IMPORTED_MODULE_0__.EXITVIEWPORT && this.isAboveViewport && !this.isInViewport: + case event === _constants_js__WEBPACK_IMPORTED_MODULE_0__.PARTIALLYEXITVIEWPORT && this.isInViewport && this.isAboveViewport: + callback.call(this, this); + if (isOne) { + return; + } + } + if (this.callbacks[event]) { + this.callbacks[event].push({ callback: callback, isOne: isOne }); + } + else { + throw new Error('Tried to add a scroll monitor listener of type ' + + event + + '. Your options are: ' + + _constants_js__WEBPACK_IMPORTED_MODULE_0__.eventTypes.join(', ')); + } + }; + Watcher.prototype.off = function (event, callback) { + if (this.callbacks[event]) { + for (var i = 0, item; (item = this.callbacks[event][i]); i++) { + if (item.callback === callback) { + this.callbacks[event].splice(i, 1); + break; + } + } + } + else { + throw new Error('Tried to remove a scroll monitor listener of type ' + + event + + '. Your options are: ' + + _constants_js__WEBPACK_IMPORTED_MODULE_0__.eventTypes.join(', ')); + } + }; + Watcher.prototype.one = function (event, callback) { + this.on(event, callback, true); + }; + Watcher.prototype.recalculateSize = function () { + if (this.watchItem instanceof HTMLElement) { + this.height = this.watchItem.offsetHeight + this.offsets.top + this.offsets.bottom; + this.bottom = this.top + this.height; + } + }; + Watcher.prototype.update = function () { + this.isAboveViewport = this.top < this.container.viewportTop; + this.isBelowViewport = this.bottom > this.container.viewportBottom; + this.isInViewport = + this.top < this.container.viewportBottom && this.bottom > this.container.viewportTop; + this.isFullyInViewport = + (this.top >= this.container.viewportTop && + this.bottom <= this.container.viewportBottom) || + (this.isAboveViewport && this.isBelowViewport); + }; + Watcher.prototype.destroy = function () { + var index = this.container.watchers.indexOf(this), self = this; + this.container.watchers.splice(index, 1); + self.callbacks = {}; + }; + // prevent recalculating the element location + Watcher.prototype.lock = function () { + this.locked = true; + }; + Watcher.prototype.unlock = function () { + this.locked = false; + }; + return Watcher; +}()); + +var eventHandlerFactory = function (type) { + return function (callback, isOne) { + if (isOne === void 0) { isOne = false; } + this.on.call(this, type, callback, isOne); + }; +}; +for (var i = 0, j = _constants_js__WEBPACK_IMPORTED_MODULE_0__.eventTypes.length; i < j; i++) { + var type = _constants_js__WEBPACK_IMPORTED_MODULE_0__.eventTypes[i]; + Watcher.prototype[type] = eventHandlerFactory(type); +} +//# sourceMappingURL=watcher.js.map /***/ }), @@ -18,16 +552,13 @@ \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "CollectorModule": () => (/* binding */ CollectorModule) /* harmony export */ }); -/* harmony import */ var _writers_SplitStreamWriter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./writers/SplitStreamWriter */ "./src/main/writers/SplitStreamWriter.ts"); -/* harmony import */ var _logger_TransportLogger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./logger/TransportLogger */ "./src/main/logger/TransportLogger.ts"); -/* harmony import */ var _writers_ConsoleWriter__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./writers/ConsoleWriter */ "./src/main/writers/ConsoleWriter.ts"); -/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./logger */ "./src/main/logger/index.ts"); - +/* harmony import */ var _writers__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./writers */ "./src/main/writers/index.ts"); +/* harmony import */ var _logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./logger */ "./src/main/logger/index.ts"); +/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utils */ "./src/main/utils/index.ts"); @@ -43,8 +574,8 @@ class CollectorModule { this.options = options || {}; } add(collector) { - if (this.options.context && !collector.getContext()) - collector.setContext(this.options.context); + if (!collector.getContext()) + collector.setContext(this.options.context || new _utils__WEBPACK_IMPORTED_MODULE_2__.Context(window, document)); this.collectors.push(collector); if (this.hasStarted === true) this.invokedCollector(collector); @@ -83,17 +614,14 @@ class CollectorModule { if (hasLogger) return this.logger; if (!this.transports || this.transports.length === 0) { - console.warn("ATTENTION-SEARCH-COLLECTOR-WARNING"); - console.warn("search-collector: no LoggerTransport configured while using the default TransportLogger. Please add a transport CollectorModule#addLogTransport or CollectorModule#setTransports"); - console.warn("search-collector: will FALLBACK to ConsoleTransport"); - return new _logger_TransportLogger__WEBPACK_IMPORTED_MODULE_1__.TransportLogger([new _logger__WEBPACK_IMPORTED_MODULE_3__.ConsoleTransport()]); + return new _logger__WEBPACK_IMPORTED_MODULE_1__.TransportLogger([new _logger__WEBPACK_IMPORTED_MODULE_1__.ConsoleTransport()]); } - return new _logger_TransportLogger__WEBPACK_IMPORTED_MODULE_1__.TransportLogger(this.transports); + return new _logger__WEBPACK_IMPORTED_MODULE_1__.TransportLogger(this.transports); } getWriter() { return this.writers.length == 0 - ? this.options.writer || new _writers_ConsoleWriter__WEBPACK_IMPORTED_MODULE_2__.ConsoleWriter() - : new _writers_SplitStreamWriter__WEBPACK_IMPORTED_MODULE_0__.SplitStreamWriter(this.writers); + ? this.options.writer || new _writers__WEBPACK_IMPORTED_MODULE_0__.ConsoleWriter() + : new _writers__WEBPACK_IMPORTED_MODULE_0__.SplitStreamWriter(this.writers); } } @@ -106,15 +634,12 @@ class CollectorModule { \**************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "AbstractCollector": () => (/* binding */ AbstractCollector) /* harmony export */ }); -/* harmony import */ var _utils_Context__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../utils/Context */ "./src/main/utils/Context.ts"); - class AbstractCollector { - constructor(type, context = new _utils_Context__WEBPACK_IMPORTED_MODULE_0__.Context(window, document)) { + constructor(type, context) { this.type = type; this.context = context; } @@ -150,7 +675,8 @@ class AbstractCollector { return handler(...args, ...handlerArgs); } catch (e) { - log.error(`[${this.constructor.name}] Unexpected error during resolver execution: `, e); + if (log) + log.error(`[${this.constructor.name}] Unexpected error during resolver execution: `, e); } }; } @@ -172,7 +698,9 @@ class AbstractCollector { } } catch (e) { - log.error(`[${this.constructor.name}] Unexpected error during resolver execution: `, e); + if (log && log.error) { + log.error(`[${this.constructor.name}] Unexpected error during resolver execution: `, e); + } } } } @@ -186,7 +714,6 @@ class AbstractCollector { \***********************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "AssociatedProductCollector": () => (/* binding */ AssociatedProductCollector) @@ -273,7 +800,6 @@ class AssociatedProductCollector extends _AbstractCollector__WEBPACK_IMPORTED_MO \*****************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "BasketClickCollector": () => (/* binding */ BasketClickCollector) @@ -315,7 +841,6 @@ class BasketClickCollector extends _ClickCollector__WEBPACK_IMPORTED_MODULE_0__. \*************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "BrowserCollector": () => (/* binding */ BrowserCollector) @@ -327,11 +852,12 @@ __webpack_require__.r(__webpack_exports__); * need to consult the GDPR guidelines */ class BrowserCollector extends _AbstractCollector__WEBPACK_IMPORTED_MODULE_0__.AbstractCollector { - constructor(options = { recordUrl: true, recordReferrer: true, recordLanguage: false }) { + constructor(options = { recordUrl: true, recordReferrer: true, recordLanguage: false, recordUserAgent: false }) { super("browser"); this.recordUrl = options.recordUrl || false; this.recordReferrer = options.recordReferrer || false; this.recordLanguage = options.recordLanguage || false; + this.recordUserAgent = options.recordUserAgent || false; } /** * Attach a writer, note that this collector is not asynchronous and will write @@ -352,6 +878,8 @@ class BrowserCollector extends _AbstractCollector__WEBPACK_IMPORTED_MODULE_0__.A data.url = win.location.href; if (this.recordReferrer) data.ref = doc.referrer; + if (this.recordUserAgent) + data.agent = window.navigator.userAgent; writer.write(data); } } @@ -365,7 +893,6 @@ class BrowserCollector extends _AbstractCollector__WEBPACK_IMPORTED_MODULE_0__.A \*******************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "CheckoutClickCollector": () => (/* binding */ CheckoutClickCollector) @@ -427,11 +954,17 @@ class CheckoutClickCollector extends _AbstractCollector__WEBPACK_IMPORTED_MODULE // "sentinel (default)" - works on elements inserted in the DOM anytime, but interferes with CSS animations on these elements if (this.listenerType === _utils_ListenerType__WEBPACK_IMPORTED_MODULE_2__.ListenerType.Dom) { const nodeList = doc.querySelectorAll(this.clickSelector); - nodeList.forEach((el) => el.addEventListener("click", this.logWrapHandler(handler, log))); + nodeList.forEach((el) => el.addEventListener("click", this.logWrapHandler(handler, log), { + passive: true, + capture: true + })); } else { const sentinel = new _utils_Sentinel__WEBPACK_IMPORTED_MODULE_1__.Sentinel(this.getDocument()); - sentinel.on(this.clickSelector, el => el.addEventListener("click", this.logWrapHandler(handler, log))); + sentinel.on(this.clickSelector, el => el.addEventListener("click", this.logWrapHandler(handler, log), { + passive: true, + capture: true + })); } } } @@ -445,7 +978,6 @@ class CheckoutClickCollector extends _AbstractCollector__WEBPACK_IMPORTED_MODULE \***********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "ClickCollector": () => (/* binding */ ClickCollector) @@ -471,9 +1003,10 @@ class ClickCollector extends _AbstractCollector__WEBPACK_IMPORTED_MODULE_0__.Abs * @param {string} selectorExpression - Document query selector identifying the elements to attach to * @param {string} type - The type OF element click to report * @param {string} listenerType - Whether the listener should be a dom or sentinel listener + * @param context */ - constructor(selectorExpression, type = "click", listenerType = _utils_ListenerType__WEBPACK_IMPORTED_MODULE_2__.ListenerType.Sentinel) { - super(type); + constructor(selectorExpression, type = "click", listenerType = _utils_ListenerType__WEBPACK_IMPORTED_MODULE_2__.ListenerType.Sentinel, context) { + super(type, context); this.selectorExpression = selectorExpression; this.listenerType = listenerType; } @@ -508,11 +1041,17 @@ class ClickCollector extends _AbstractCollector__WEBPACK_IMPORTED_MODULE_0__.Abs // "sentinel (default)" - works on elements inserted in the DOM anytime, but interferes with CSS animations on these elements if (this.listenerType === _utils_ListenerType__WEBPACK_IMPORTED_MODULE_2__.ListenerType.Dom) { const nodeList = this.getDocument().querySelectorAll(this.selectorExpression); - nodeList.forEach((el) => el.addEventListener("click", this.logWrapHandler(handler, log, el))); + nodeList.forEach((el) => el.addEventListener("click", this.logWrapHandler(handler, log, el), { + passive: true, + capture: true + })); } else { const sentinel = new _utils_Sentinel__WEBPACK_IMPORTED_MODULE_1__.Sentinel(this.getDocument()); - sentinel.on(this.selectorExpression, el => el.addEventListener("click", this.logWrapHandler(handler, log, el))); + sentinel.on(this.selectorExpression, el => el.addEventListener("click", this.logWrapHandler(handler, log, el), { + passive: true, + capture: true + })); } } } @@ -526,7 +1065,6 @@ class ClickCollector extends _AbstractCollector__WEBPACK_IMPORTED_MODULE_0__.Abs \*************************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "ClickWriterResolverCollector": () => (/* binding */ ClickWriterResolverCollector) @@ -560,11 +1098,17 @@ class ClickWriterResolverCollector extends _WriterResolverCollector__WEBPACK_IMP }; if (this.listenerType === _utils_ListenerType__WEBPACK_IMPORTED_MODULE_0__.ListenerType.Dom) { const nodeList = this.getDocument().querySelectorAll(this.selectorExpression); - nodeList.forEach(el => el.addEventListener("click", ev => this.logWrapHandler(handler, log, el, ev)())); + nodeList.forEach(el => el.addEventListener("click", ev => this.logWrapHandler(handler, log, el, ev)(), { + passive: true, + capture: true + })); } else { const sentinel = new _utils_Sentinel__WEBPACK_IMPORTED_MODULE_1__.Sentinel(this.getDocument()); - sentinel.on(this.selectorExpression, el => el.addEventListener("click", ev => this.logWrapHandler(handler, log, el, ev)())); + sentinel.on(this.selectorExpression, el => el.addEventListener("click", ev => this.logWrapHandler(handler, log, el, ev)(), { + passive: true, + capture: true + })); } } } @@ -578,7 +1122,6 @@ class ClickWriterResolverCollector extends _WriterResolverCollector__WEBPACK_IMP \*****************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "FilterClickCollector": () => (/* binding */ FilterClickCollector) @@ -611,7 +1154,6 @@ class FilterClickCollector extends _ClickCollector__WEBPACK_IMPORTED_MODULE_0__. \*****************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "FiredSearchCollector": () => (/* binding */ FiredSearchCollector) @@ -642,7 +1184,6 @@ class FiredSearchCollector extends _WriterResolverCollector__WEBPACK_IMPORTED_MO \******************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "GenericEventCollector": () => (/* binding */ GenericEventCollector) @@ -693,15 +1234,13 @@ class GenericEventCollector extends _AbstractCollector__WEBPACK_IMPORTED_MODULE_ \****************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "ImpressionCollector": () => (/* binding */ ImpressionCollector) /* harmony export */ }); /* harmony import */ var _AbstractCollector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./AbstractCollector */ "./src/main/collectors/AbstractCollector.ts"); /* harmony import */ var _utils_Sentinel__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils/Sentinel */ "./src/main/utils/Sentinel.ts"); -/* harmony import */ var scrollmonitor__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! scrollmonitor */ "./node_modules/scrollmonitor/scrollMonitor.js"); -/* harmony import */ var scrollmonitor__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(scrollmonitor__WEBPACK_IMPORTED_MODULE_2__); +/* harmony import */ var scrollmonitor__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! scrollmonitor */ "./node_modules/scrollmonitor/dist/module/index.js"); /* harmony import */ var _utils_LocalStorageQueue__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../utils/LocalStorageQueue */ "./src/main/utils/LocalStorageQueue.ts"); /* harmony import */ var _utils_Util__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../utils/Util */ "./src/main/utils/Util.ts"); @@ -723,12 +1262,14 @@ class ImpressionCollector extends _AbstractCollector__WEBPACK_IMPORTED_MODULE_0_ * @param {string} selectorExpression - Document query selector identifying the elements to attach to * @param idResolver - Resolve the id of the element * @param positionResolver - Resolve the position of the element in dom + * @param expectedPageResolver - If supplied, impressions will only be tracked if this resolver returns true. Comes in handy for single page applications */ - constructor(selectorExpression, idResolver, positionResolver) { + constructor(selectorExpression, idResolver, positionResolver, expectedPageResolver) { super("impression"); this.selectorExpression = selectorExpression; this.idResolver = idResolver; this.positionResolver = positionResolver; + this.expectedPageResolver = expectedPageResolver; this.queue = new _utils_LocalStorageQueue__WEBPACK_IMPORTED_MODULE_3__.LocalStorageQueue("impressions"); } /** @@ -749,13 +1290,16 @@ class ImpressionCollector extends _AbstractCollector__WEBPACK_IMPORTED_MODULE_0_ .catch(err => log.error("Could not drain queue: ", err)); }, 250); const handler = element => { - scrollmonitor__WEBPACK_IMPORTED_MODULE_2___default().create(element).enterViewport(() => { + scrollmonitor__WEBPACK_IMPORTED_MODULE_2__["default"].create(element).enterViewport(() => { + if (this.expectedPageResolver && !this.expectedPageResolver()) { + return; + } this.queue.push({ id: this.resolve(this.idResolver, log, element), position: this.resolve(this.positionResolver, log, element) }); flush(); - }); + }, true); }; new _utils_Sentinel__WEBPACK_IMPORTED_MODULE_1__.Sentinel(this.getDocument()).on(this.selectorExpression, this.logWrapHandler(handler, log)); } @@ -770,7 +1314,6 @@ class ImpressionCollector extends _AbstractCollector__WEBPACK_IMPORTED_MODULE_0_ \************************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "InstantSearchQueryCollector": () => (/* binding */ InstantSearchQueryCollector) @@ -820,12 +1363,13 @@ class InstantSearchQueryCollector extends _AbstractCollector__WEBPACK_IMPORTED_M } // Delay the reaction of the event, clean the timeout if the event fires // again and start counting from 0 - delay(() => { + delay((timestamp) => { const keywords = searchBox.value; if (keywords && keywords.length >= this.minLength) { writer.write({ "type": type, - "keywords": keywords + "keywords": keywords, + timestamp }); } }, this.delayMs); @@ -848,9 +1392,15 @@ class InstantSearchQueryCollector extends _AbstractCollector__WEBPACK_IMPORTED_M } const delay = (function () { let timer; + let time; return function (callback, ms) { clearTimeout(timer); - timer = setTimeout(callback, ms); + if (!time) + time = new Date().getTime(); + timer = setTimeout(() => { + callback(time); + time = null; + }, ms); }; })(); @@ -863,13 +1413,16 @@ const delay = (function () { \******************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "ProductClickCollector": () => (/* binding */ ProductClickCollector) /* harmony export */ }); /* harmony import */ var _ClickCollector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./ClickCollector */ "./src/main/collectors/ClickCollector.ts"); /* harmony import */ var _utils_ListenerType__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils/ListenerType */ "./src/main/utils/ListenerType.ts"); +/* harmony import */ var _query__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../query */ "./src/main/query/index.ts"); +/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../utils */ "./src/main/utils/index.ts"); + + /** @@ -892,18 +1445,25 @@ class ProductClickCollector extends _ClickCollector__WEBPACK_IMPORTED_MODULE_0__ collect(element, event, log) { const id = this.resolve(this.idResolver, log, element, event); if (id) { - if (this.trail) { - // Register that this product journey into potential purchase started - // with this query - this.trail.register(id); - } - return { + const clickData = { id, position: this.resolve(this.positionResolver, log, element, event), price: this.resolve(this.priceResolver, log, element, event), image: this.resolve(this.imageResolver, log, element, event), metadata: this.resolve(this.metadataResolver, log, element, event) }; + if (this.trail) { + // After a redirect a trail with the pathname is registered containing the query which triggered the redirect. + // If we have such a query we use it to build the trail. + const trailData = this.trail.fetch((0,_utils__WEBPACK_IMPORTED_MODULE_3__.normalizePathname)(location.pathname)); + if (trailData) { + clickData.query = trailData.query; + } + // Register that this product journey into potential purchase started + // with this query + this.trail.register(id, _query__WEBPACK_IMPORTED_MODULE_2__.TrailType.Main, trailData === null || trailData === void 0 ? void 0 : trailData.query); + } + return clickData; } } } @@ -917,14 +1477,15 @@ class ProductClickCollector extends _ClickCollector__WEBPACK_IMPORTED_MODULE_0__ \**************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "RedirectCollector": () => (/* binding */ RedirectCollector) /* harmony export */ }); /* harmony import */ var _AbstractCollector__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./AbstractCollector */ "./src/main/collectors/AbstractCollector.ts"); -/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils */ "./src/main/utils/index.ts"); -/* harmony import */ var _query__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../query */ "./src/main/query/index.ts"); +/* harmony import */ var _resolvers_Resolver__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../resolvers/Resolver */ "./src/main/resolvers/Resolver.ts"); +/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../utils */ "./src/main/utils/index.ts"); +/* harmony import */ var _query__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../query */ "./src/main/query/index.ts"); + @@ -938,12 +1499,98 @@ class RedirectCollector extends _AbstractCollector__WEBPACK_IMPORTED_MODULE_0__. * @constructor * @param {function} triggerResolver - Function that fires when a search happens, should return the keyword * @param {function} expectedPageResolver - Function that should return whether the page we load is the expected one + * @param redirectKpiParams - Parameters for collecting KPI's after a redirect + * @param listenerType * @param context */ - constructor(triggerResolver, expectedPageResolver, context) { + constructor(triggerResolver, expectedPageResolver, redirectKpiParams = {}, listenerType = _utils__WEBPACK_IMPORTED_MODULE_2__.ListenerType.Sentinel, context) { + var _a, _b; super("redirect", context); this.triggerResolver = triggerResolver; this.expectedPageResolver = expectedPageResolver; + this.redirectKpiParams = redirectKpiParams; + this.listenerType = listenerType; + /** + * Used to track if the collectors have been attached already in case attached is called multiple times + * @private + */ + this.isCollectorsAttached = false; + /** + * Used to track if the trigger has been installed already in case attached is called multiple times + */ + this.isTriggerInstalled = false; + this.triggerResolver = triggerResolver; + this.expectedPageResolver = expectedPageResolver; + this.listenerType = listenerType; + this.collectors = redirectKpiParams.collectors || []; + this.resultCountResolver = redirectKpiParams.resultCountResolver || (_ => void 0); + this.redirectTTL = this.redirectKpiParams.redirectTTLMillis || 86400000; + this.maxPathSegments = this.redirectKpiParams.maxPathSegments || -1; + this.subSelectors = ((_a = this.redirectKpiParams.nestedRedirects) === null || _a === void 0 ? void 0 : _a.subSelectors) || []; + this.depth = ((_b = this.redirectKpiParams.nestedRedirects) === null || _b === void 0 ? void 0 : _b.depth) || 1; + this.queryResolver = (phrase) => { + if (phrase.indexOf("$s=") > -1) { + return new _query__WEBPACK_IMPORTED_MODULE_3__.Query(phrase); + } + const query = new _query__WEBPACK_IMPORTED_MODULE_3__.Query(); + query.setSearch(phrase); + return query; + }; + this.sessionResolver = () => (0,_resolvers_Resolver__WEBPACK_IMPORTED_MODULE_1__.cookieSessionResolver)(); + this.redirectTrail = new _query__WEBPACK_IMPORTED_MODULE_3__.Trail(() => { + const pathInfo = RedirectCollector.getRedirectPathInfo(this.getPathname()); + return new _query__WEBPACK_IMPORTED_MODULE_3__.Query(pathInfo === null || pathInfo === void 0 ? void 0 : pathInfo.query); + }, this.sessionResolver); + } + setContext(context) { + super.setContext(context); + this.collectors.forEach(collector => collector.setContext(context)); + } + /** + * Marks this path as a redirect landing page. + * @param path the pathname e.g. /some-path + * @param query the query which lead to this path + * @param key the key to store the redirect path in + * @private + */ + static setRedirectPath(path, query, key = RedirectCollector.PATH_STORAGE_KEY) { + const redirectPaths = this.getRedirectPaths(); + redirectPaths[path] = { + query, + timestamp: new Date().getTime() + }; + (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getSessionStorage)().setItem(key, JSON.stringify(redirectPaths)); + } + /** + * Get all marked paths + * @private + */ + static getRedirectPaths(key = RedirectCollector.PATH_STORAGE_KEY) { + return JSON.parse((0,_utils__WEBPACK_IMPORTED_MODULE_2__.getSessionStorage)().getItem(key) || "{}"); + } + /** + * Retrieve data for the given path + * @param path + * @param key + * @private + */ + static getRedirectPathInfo(path, key = RedirectCollector.PATH_STORAGE_KEY) { + return this.getRedirectPaths(key)[path]; + } + /** + * Delete all expired redirect paths + * @private + */ + expireRedirectPaths(key = RedirectCollector.PATH_STORAGE_KEY) { + const redirectPaths = RedirectCollector.getRedirectPaths(key); + const now = new Date().getTime(); + Object.keys(redirectPaths).forEach(path => { + const pathInfo = redirectPaths[path]; + if (now - Number(pathInfo.timestamp) > this.redirectTTL) { + delete redirectPaths[path]; + } + }); + (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getSessionStorage)().setItem(key, JSON.stringify(redirectPaths)); } /** * Check whether we should be recording a redirect event @@ -952,30 +1599,146 @@ class RedirectCollector extends _AbstractCollector__WEBPACK_IMPORTED_MODULE_0__. * @param log */ attach(writer, log) { - this.resolve(this.triggerResolver, log, keyword => { - (0,_utils__WEBPACK_IMPORTED_MODULE_1__.getSessionStorage)().setItem(RedirectCollector.STORAGE_KEY, keyword); - }); + if (this.isTriggerInstalled === false) { + this.resolve(this.triggerResolver, log, keyword => (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getSessionStorage)().setItem(RedirectCollector.LAST_SEARCH_STORAGE_KEY, keyword)); + this.isTriggerInstalled = true; + } + this.expireRedirectPaths(); // Fetch the latest search if any - const lastSearch = (0,_utils__WEBPACK_IMPORTED_MODULE_1__.getSessionStorage)().getItem(RedirectCollector.STORAGE_KEY); + const lastSearch = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getSessionStorage)().getItem(RedirectCollector.LAST_SEARCH_STORAGE_KEY); + const pathname = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.normalizePathname)(this.getWindow().location.pathname); if (lastSearch) { - // Remove the search action, as we're either on a search result page or we've redirected - (0,_utils__WEBPACK_IMPORTED_MODULE_1__.getSessionStorage)().removeItem(RedirectCollector.STORAGE_KEY); - // If we have not landed on the expected search page, it must have been (looove) a redirect - if (!this.resolve(this.expectedPageResolver, log)) { - // Thus record the redirect - const query = new _query__WEBPACK_IMPORTED_MODULE_2__.Query(); - query.setSearch(lastSearch); + (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getSessionStorage)().removeItem(RedirectCollector.LAST_SEARCH_STORAGE_KEY); + // If we have not landed on the expected search page, it must have been a redirect + if (shouldTrackRedirect(document.referrer) && !this.resolve(this.expectedPageResolver, log)) { + const query = this.queryResolver(lastSearch).toString(); writer.write({ type: "redirect", keywords: lastSearch, - query: query.toString(), - url: window.location.href + query, + url: window.location.href, + resultCount: this.resolve(this.resultCountResolver, log) }); + // mark as redirect landing page + RedirectCollector.setRedirectPath(this.getPathname(), query); + // register trail on the current pathname because the ProductClick collector doesn't know about the maxPathSegments property + this.redirectTrail.register(pathname, _query__WEBPACK_IMPORTED_MODULE_3__.TrailType.Main); + } + } + // this is only triggered when a subSelector item was clicked i.e. a nested redirect + const lastSearchNestedRedirect = this.getNestedRedirect(); + if (lastSearchNestedRedirect) { + const query = this.queryResolver(lastSearchNestedRedirect.query).toString(); + RedirectCollector.setRedirectPath(this.getPathname(), query); + // register trail on the current pathname because the ProductClick collector doesn't know about the maxPathSegments property + this.redirectTrail.register(pathname, _query__WEBPACK_IMPORTED_MODULE_3__.TrailType.Main); + (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getSessionStorage)().removeItem(RedirectCollector.NESTED_REDIRECT_KEYWORDS_STORAGE_KEY); + } + /** + * Check if we have tracked this path before and if it is still valid. + * If valid, we have to attach the KPI collectors to gather KPIs for this landing page. + * We have to do this because people can navigate away from the landing page and back again and we don't want to lose all subsequent clicks etc. + */ + const pathInfo = this.redirectTrail.fetch(this.getPathname()); + if (pathInfo && this.isCollectorsAttached !== true) { + this.attachCollectors(writer, log, pathInfo.query); + this.isCollectorsAttached = true; + // register trail on the current pathname because the ProductClick collector doesn't know about the maxPathSegments property + this.redirectTrail.register(pathname, _query__WEBPACK_IMPORTED_MODULE_3__.TrailType.Main); + // if we have nested redirects, we have to carry the query parameters over to the next page + this.attachSubSelectors(pathInfo, (lastSearchNestedRedirect === null || lastSearchNestedRedirect === void 0 ? void 0 : lastSearchNestedRedirect.depth) || 0); + } + } + getNestedRedirect() { + const payload = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getSessionStorage)().getItem(RedirectCollector.NESTED_REDIRECT_KEYWORDS_STORAGE_KEY); + if (payload) { + return JSON.parse(payload); + } + return undefined; + } + isMaxDepthExceeded(currentDepth = 0) { + return currentDepth >= this.depth; + } + registerNestedRedirect(query, currentDepth = 0) { + if (this.isMaxDepthExceeded(currentDepth)) + return; + const payload = { + query: query, + depth: currentDepth + 1 + }; + (0,_utils__WEBPACK_IMPORTED_MODULE_2__.getSessionStorage)().setItem(RedirectCollector.NESTED_REDIRECT_KEYWORDS_STORAGE_KEY, JSON.stringify(payload)); + } + attachSubSelectors(pathInfo, currentDepth) { + if (this.isMaxDepthExceeded(currentDepth)) + return; + this.subSelectors.forEach(selector => { + const handleClick = () => { + this.registerNestedRedirect(pathInfo.query, currentDepth); + }; + if (this.listenerType === _utils__WEBPACK_IMPORTED_MODULE_2__.ListenerType.Sentinel) { + const sentinel = new _utils__WEBPACK_IMPORTED_MODULE_2__.Sentinel(this.getDocument()); + sentinel.on(selector, element => { + const info = this.redirectTrail.fetch(this.getPathname()); + if (info) { // the sentinel can trigger on any page, we need to make sure we attach subSelectors only on valid redirect paths + element.addEventListener("click", handleClick); + } + }); + } + else { + document.querySelectorAll(selector).forEach(element => { + element.addEventListener("click", handleClick); + }); + } + }); + } + getPathname() { + const pathname = (0,_utils__WEBPACK_IMPORTED_MODULE_2__.normalizePathname)(this.getWindow().location.pathname); + if (this.maxPathSegments > 0) { + const pathSegments = pathname.split("/"); + return (0,_utils__WEBPACK_IMPORTED_MODULE_2__.normalizePathname)(pathSegments.filter(s => !!s).slice(0, this.maxPathSegments).join("/")); + } + return pathname; + } + attachCollectors(writer, log, query) { + // attach all collectors which are responsible to gather kpi's after the redirect + this.collectors.forEach(collector => { + try { + collector.attach({ + write(data) { + writer.write({ ...data, query: data.query || query }); + } + }, log); } + catch (e) { + if (log) + log.error(e); + } + }); + } +} +/** + * Key used to store the keywords of the last executed search + */ +RedirectCollector.LAST_SEARCH_STORAGE_KEY = "__lastSearch"; +/** + * Key used to store query information for a given redirect landing page (path of the url) + */ +RedirectCollector.PATH_STORAGE_KEY = "___pathStorage"; +RedirectCollector.NESTED_REDIRECT_KEYWORDS_STORAGE_KEY = "___nestedRedirectKeywordsStorage"; +function shouldTrackRedirect(referer) { + if (referer) { + try { + const refUrl = new URL(referer); + const currentUrl = new URL(window.location.href); + if (currentUrl.origin && refUrl.origin) + return refUrl.origin === currentUrl.origin; + } + catch (e) { + console.error(e); } } + return true; } -RedirectCollector.STORAGE_KEY = "__lastSearch"; /***/ }), @@ -986,7 +1749,6 @@ RedirectCollector.STORAGE_KEY = "__lastSearch"; \******************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "SearchResultCollector": () => (/* binding */ SearchResultCollector) @@ -1040,7 +1802,6 @@ class SearchResultCollector extends _AbstractCollector__WEBPACK_IMPORTED_MODULE_ \*******************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "SuggestSearchCollector": () => (/* binding */ SuggestSearchCollector) @@ -1071,7 +1832,6 @@ class SuggestSearchCollector extends _WriterResolverCollector__WEBPACK_IMPORTED_ \********************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "WriterResolverCollector": () => (/* binding */ WriterResolverCollector) @@ -1100,7 +1860,6 @@ class WriterResolverCollector extends _AbstractCollector__WEBPACK_IMPORTED_MODUL \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "AbstractCollector": () => (/* reexport safe */ _AbstractCollector__WEBPACK_IMPORTED_MODULE_0__.AbstractCollector), @@ -1165,7 +1924,6 @@ __webpack_require__.r(__webpack_exports__); \***********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); @@ -1178,7 +1936,6 @@ __webpack_require__.r(__webpack_exports__); \********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); @@ -1191,7 +1948,6 @@ __webpack_require__.r(__webpack_exports__); \********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "TransportLogger": () => (/* binding */ TransportLogger) @@ -1237,13 +1993,12 @@ class TransportLogger { \**********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "TransportLogger": () => (/* reexport safe */ _TransportLogger__WEBPACK_IMPORTED_MODULE_2__.TransportLogger), /* harmony export */ "ConsoleTransport": () => (/* reexport safe */ _transport__WEBPACK_IMPORTED_MODULE_3__.ConsoleTransport), /* harmony export */ "SQSErrorTransport": () => (/* reexport safe */ _transport__WEBPACK_IMPORTED_MODULE_3__.SQSErrorTransport), -/* harmony export */ "SQSTransport": () => (/* reexport safe */ _transport__WEBPACK_IMPORTED_MODULE_3__.SQSTransport) +/* harmony export */ "SQSTransport": () => (/* reexport safe */ _transport__WEBPACK_IMPORTED_MODULE_3__.SQSTransport), +/* harmony export */ "TransportLogger": () => (/* reexport safe */ _TransportLogger__WEBPACK_IMPORTED_MODULE_2__.TransportLogger) /* harmony export */ }); /* harmony import */ var _Logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Logger */ "./src/main/logger/Logger.ts"); /* harmony import */ var _LoggerTransport__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./LoggerTransport */ "./src/main/logger/LoggerTransport.ts"); @@ -1263,7 +2018,6 @@ __webpack_require__.r(__webpack_exports__); \*******************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "ConsoleTransport": () => (/* binding */ ConsoleTransport) @@ -1296,7 +2050,6 @@ class ConsoleTransport { \********************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "SQSErrorTransport": () => (/* binding */ SQSErrorTransport) @@ -1353,7 +2106,6 @@ class SQSErrorTransport { \***************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "SQSTransport": () => (/* binding */ SQSTransport) @@ -1399,7 +2151,6 @@ class SQSTransport extends _SQSErrorTransport__WEBPACK_IMPORTED_MODULE_0__.SQSEr \********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "ConsoleTransport": () => (/* reexport safe */ _ConsoleTransport__WEBPACK_IMPORTED_MODULE_0__.ConsoleTransport), @@ -1422,7 +2173,6 @@ __webpack_require__.r(__webpack_exports__); \*********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Query": () => (/* binding */ Query) @@ -1671,7 +2421,6 @@ function arrayRemove(array, from, to) { \*********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Trail": () => (/* binding */ Trail) @@ -1754,7 +2503,6 @@ class Trail { \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "TrailType": () => (/* binding */ TrailType) @@ -1774,7 +2522,6 @@ var TrailType; \*********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Query": () => (/* reexport safe */ _Query__WEBPACK_IMPORTED_MODULE_0__.Query), @@ -1797,23 +2544,25 @@ __webpack_require__.r(__webpack_exports__); \****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "cookieResolver": () => (/* binding */ cookieResolver), /* harmony export */ "cookieSessionResolver": () => (/* binding */ cookieSessionResolver), -/* harmony export */ "positionResolver": () => (/* binding */ positionResolver), -/* harmony export */ "debugResolver": () => (/* binding */ debugResolver) +/* harmony export */ "debugResolver": () => (/* binding */ debugResolver), +/* harmony export */ "positionResolver": () => (/* binding */ positionResolver) /* harmony export */ }); -/* harmony import */ var _utils_Util__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../utils/Util */ "./src/main/utils/Util.ts"); +/* harmony import */ var _utils_Context__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../utils/Context */ "./src/main/utils/Context.ts"); +/* harmony import */ var _utils_Util__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utils/Util */ "./src/main/utils/Util.ts"); + const MINUTES_ONE_DAY = 60 * 24; +const MINUTES_TWO_DAYS = 60 * 24 * 2; const MINUTES_HALF_HOUR = 30; /** * Read the cookie with the provided name * @param name the name of the cookie */ -const cookieResolver = (name = "") => (0,_utils_Util__WEBPACK_IMPORTED_MODULE_0__.getCookie)(name); +const cookieResolver = (name = "") => (0,_utils_Util__WEBPACK_IMPORTED_MODULE_1__.getCookie)(name); /** * Resolve the id of the current search session. A search session is defined as * limited time slice of search activity across multiple tabs. By default a session @@ -1825,16 +2574,17 @@ const cookieResolver = (name = "") => (0,_utils_Util__WEBPACK_IMPORTED_MODULE_0_ * * @param name the name of the session cookie */ -const cookieSessionResolver = (name = "SearchCollectorSession") => (0,_utils_Util__WEBPACK_IMPORTED_MODULE_0__.setCookie)(name, cookieResolver(name) || (0,_utils_Util__WEBPACK_IMPORTED_MODULE_0__.generateId)(), MINUTES_HALF_HOUR); +const cookieSessionResolver = (name = "SearchCollectorSession") => (0,_utils_Util__WEBPACK_IMPORTED_MODULE_1__.setCookie)(name, cookieResolver(name) || (0,_utils_Util__WEBPACK_IMPORTED_MODULE_1__.generateId)(), MINUTES_TWO_DAYS); /** * Find the position of a DOM element relative to other DOM elements of the same type. * To be used to find the position of an item in a search result. * * @param selectorExpression the css expression to query for other elements * @param element the element for which we want to know the position relative to the elements selected by selectorExpression + * @param ctx the context to use. defaults to new Context(window, document) */ -const positionResolver = (selectorExpression, element) => { - return Array.from(document.querySelectorAll(selectorExpression)) +const positionResolver = (selectorExpression, element, ctx = new _utils_Context__WEBPACK_IMPORTED_MODULE_0__.Context(window, document)) => { + return Array.from(ctx.getDocument().querySelectorAll(selectorExpression)) .reduce((acc, node, index) => node === element ? index : acc, undefined); }; /** @@ -1846,9 +2596,9 @@ const debugResolver = () => { const isDebugParamExists = debugParam != null; if (isDebugParamExists) { const debug = debugParam === "true"; - (0,_utils_Util__WEBPACK_IMPORTED_MODULE_0__.getLocalStorage)().setItem(DEBUG_KEY, String(debug)); + (0,_utils_Util__WEBPACK_IMPORTED_MODULE_1__.getLocalStorage)().setItem(DEBUG_KEY, String(debug)); } - return (0,_utils_Util__WEBPACK_IMPORTED_MODULE_0__.getLocalStorage)().getItem(DEBUG_KEY) === "true"; + return (0,_utils_Util__WEBPACK_IMPORTED_MODULE_1__.getLocalStorage)().getItem(DEBUG_KEY) === "true"; }; @@ -1860,7 +2610,6 @@ const debugResolver = () => { \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "cookieResolver": () => (/* reexport safe */ _Resolver__WEBPACK_IMPORTED_MODULE_0__.cookieResolver), @@ -1880,7 +2629,6 @@ __webpack_require__.r(__webpack_exports__); \***********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Context": () => (/* binding */ Context) @@ -1907,7 +2655,6 @@ class Context { \****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "ListenerType": () => (/* binding */ ListenerType) @@ -1927,7 +2674,6 @@ var ListenerType; \*********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "LocalStorageQueue": () => (/* binding */ LocalStorageQueue) @@ -1984,7 +2730,6 @@ class LocalStorageQueue { \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Sentinel": () => (/* binding */ Sentinel) @@ -2119,17 +2864,17 @@ class Sentinel { \********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "parseQueryString": () => (/* binding */ parseQueryString), -/* harmony export */ "getLocalStorage": () => (/* binding */ getLocalStorage), /* harmony export */ "base64Encode": () => (/* binding */ base64Encode), +/* harmony export */ "debounce": () => (/* binding */ debounce), /* harmony export */ "generateId": () => (/* binding */ generateId), -/* harmony export */ "getSessionStorage": () => (/* binding */ getSessionStorage), -/* harmony export */ "setCookie": () => (/* binding */ setCookie), /* harmony export */ "getCookie": () => (/* binding */ getCookie), -/* harmony export */ "debounce": () => (/* binding */ debounce) +/* harmony export */ "getLocalStorage": () => (/* binding */ getLocalStorage), +/* harmony export */ "getSessionStorage": () => (/* binding */ getSessionStorage), +/* harmony export */ "normalizePathname": () => (/* binding */ normalizePathname), +/* harmony export */ "parseQueryString": () => (/* binding */ parseQueryString), +/* harmony export */ "setCookie": () => (/* binding */ setCookie) /* harmony export */ }); /** * Parse the browser query string or the passed string into a javascript object @@ -2141,6 +2886,13 @@ __webpack_require__.r(__webpack_exports__); const parseQueryString = (queryString = window.location.search) => { return new URLSearchParams(queryString); }; +const normalizePathname = (path) => { + if (!path.startsWith("/")) + path = "/" + path; + if (path.endsWith("/")) + path = path.substring(0, path.length - 1); + return path; +}; /** * Some browser like Safari prevent accessing localStorage in private mode by throwing exceptions. * Use this method to retrieve a mock impl which will at least prevent errors. @@ -2351,7 +3103,6 @@ const debounce = (func, wait = 100, immediate = false) => { \*********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Context": () => (/* reexport safe */ _Context__WEBPACK_IMPORTED_MODULE_0__.Context), @@ -2364,6 +3115,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony export */ "getCookie": () => (/* reexport safe */ _Util__WEBPACK_IMPORTED_MODULE_4__.getCookie), /* harmony export */ "getLocalStorage": () => (/* reexport safe */ _Util__WEBPACK_IMPORTED_MODULE_4__.getLocalStorage), /* harmony export */ "getSessionStorage": () => (/* reexport safe */ _Util__WEBPACK_IMPORTED_MODULE_4__.getSessionStorage), +/* harmony export */ "normalizePathname": () => (/* reexport safe */ _Util__WEBPACK_IMPORTED_MODULE_4__.normalizePathname), /* harmony export */ "parseQueryString": () => (/* reexport safe */ _Util__WEBPACK_IMPORTED_MODULE_4__.parseQueryString), /* harmony export */ "setCookie": () => (/* reexport safe */ _Util__WEBPACK_IMPORTED_MODULE_4__.setCookie) /* harmony export */ }); @@ -2387,7 +3139,6 @@ __webpack_require__.r(__webpack_exports__); \************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Base64EncodeWriter": () => (/* binding */ Base64EncodeWriter) @@ -2413,7 +3164,6 @@ class Base64EncodeWriter { \***************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "BrowserTrackingWriter": () => (/* binding */ BrowserTrackingWriter) @@ -2452,7 +3202,6 @@ class BrowserTrackingWriter { \*********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "BufferingWriter": () => (/* binding */ BufferingWriter) @@ -2499,7 +3248,6 @@ class BufferingWriter { \*******************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "ConsoleWriter": () => (/* binding */ ConsoleWriter) @@ -2520,7 +3268,6 @@ class ConsoleWriter { \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "DebugWriter": () => (/* binding */ DebugWriter) @@ -2549,7 +3296,6 @@ class DebugWriter { \*******************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "DefaultWriter": () => (/* binding */ DefaultWriter) @@ -2610,7 +3356,6 @@ function isSQS(endpoint, forceSQS) { \************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "JSONEnvelopeWriter": () => (/* binding */ JSONEnvelopeWriter) @@ -2625,7 +3370,8 @@ class JSONEnvelopeWriter { this.channel = channel; } write(data) { - data.timestamp = new Date().getTime(); + if (!data.timestamp) + data.timestamp = new Date().getTime(); data.session = this.sessionResolver(); data.channel = this.channel; this.delegate.write(data); @@ -2641,7 +3387,6 @@ class JSONEnvelopeWriter { \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "QueryWriter": () => (/* binding */ QueryWriter) @@ -2670,7 +3415,6 @@ class QueryWriter { \*********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "RestEventWriter": () => (/* binding */ RestEventWriter) @@ -2697,7 +3441,6 @@ class RestEventWriter { \********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "SQSEventWriter": () => (/* binding */ SQSEventWriter) @@ -2733,7 +3476,6 @@ class SQSEventWriter { \***********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "SplitStreamWriter": () => (/* binding */ SplitStreamWriter) @@ -2766,7 +3508,6 @@ class SplitStreamWriter { \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "TrailWriter": () => (/* binding */ TrailWriter) @@ -2835,7 +3576,6 @@ class TrailWriter { \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Base64EncodeWriter": () => (/* reexport safe */ _Base64EncodeWriter__WEBPACK_IMPORTED_MODULE_0__.Base64EncodeWriter), @@ -2843,8 +3583,8 @@ __webpack_require__.r(__webpack_exports__); /* harmony export */ "DefaultWriter": () => (/* reexport safe */ _DefaultWriter__WEBPACK_IMPORTED_MODULE_2__.DefaultWriter), /* harmony export */ "JSONEnvelopeWriter": () => (/* reexport safe */ _JSONEnvelopeWriter__WEBPACK_IMPORTED_MODULE_3__.JSONEnvelopeWriter), /* harmony export */ "RestEventWriter": () => (/* reexport safe */ _RestEventWriter__WEBPACK_IMPORTED_MODULE_4__.RestEventWriter), -/* harmony export */ "SplitStreamWriter": () => (/* reexport safe */ _SplitStreamWriter__WEBPACK_IMPORTED_MODULE_5__.SplitStreamWriter), -/* harmony export */ "SQSEventWriter": () => (/* reexport safe */ _SQSEventWriter__WEBPACK_IMPORTED_MODULE_6__.SQSEventWriter) +/* harmony export */ "SQSEventWriter": () => (/* reexport safe */ _SQSEventWriter__WEBPACK_IMPORTED_MODULE_6__.SQSEventWriter), +/* harmony export */ "SplitStreamWriter": () => (/* reexport safe */ _SplitStreamWriter__WEBPACK_IMPORTED_MODULE_5__.SplitStreamWriter) /* harmony export */ }); /* harmony import */ var _Base64EncodeWriter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Base64EncodeWriter */ "./src/main/writers/Base64EncodeWriter.ts"); /* harmony import */ var _BufferingWriter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./BufferingWriter */ "./src/main/writers/BufferingWriter.ts"); @@ -2870,7 +3610,6 @@ __webpack_require__.r(__webpack_exports__); \***********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { -"use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Base64EncodeWriter": () => (/* reexport safe */ _Base64EncodeWriter__WEBPACK_IMPORTED_MODULE_0__.Base64EncodeWriter), @@ -2882,8 +3621,8 @@ __webpack_require__.r(__webpack_exports__); /* harmony export */ "JSONEnvelopeWriter": () => (/* reexport safe */ _JSONEnvelopeWriter__WEBPACK_IMPORTED_MODULE_6__.JSONEnvelopeWriter), /* harmony export */ "QueryWriter": () => (/* reexport safe */ _QueryWriter__WEBPACK_IMPORTED_MODULE_7__.QueryWriter), /* harmony export */ "RestEventWriter": () => (/* reexport safe */ _RestEventWriter__WEBPACK_IMPORTED_MODULE_8__.RestEventWriter), -/* harmony export */ "SplitStreamWriter": () => (/* reexport safe */ _SplitStreamWriter__WEBPACK_IMPORTED_MODULE_9__.SplitStreamWriter), /* harmony export */ "SQSEventWriter": () => (/* reexport safe */ _SQSEventWriter__WEBPACK_IMPORTED_MODULE_10__.SQSEventWriter), +/* harmony export */ "SplitStreamWriter": () => (/* reexport safe */ _SplitStreamWriter__WEBPACK_IMPORTED_MODULE_9__.SplitStreamWriter), /* harmony export */ "TrailWriter": () => (/* reexport safe */ _TrailWriter__WEBPACK_IMPORTED_MODULE_11__.TrailWriter) /* harmony export */ }); /* harmony import */ var _Base64EncodeWriter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Base64EncodeWriter */ "./src/main/writers/Base64EncodeWriter.ts"); @@ -2936,25 +3675,13 @@ __webpack_require__.r(__webpack_exports__); /******/ }; /******/ /******/ // Execute the module function -/******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /************************************************************************/ -/******/ /* webpack/runtime/compat get default export */ -/******/ (() => { -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = (module) => { -/******/ var getter = module && module.__esModule ? -/******/ () => (module['default']) : -/******/ () => (module); -/******/ __webpack_require__.d(getter, { a: getter }); -/******/ return getter; -/******/ }; -/******/ })(); -/******/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports @@ -2985,66 +3712,66 @@ __webpack_require__.r(__webpack_exports__); /******/ /************************************************************************/ var __webpack_exports__ = {}; -// This entry need to be wrapped in an IIFE because it need to be in strict mode. +// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. (() => { -"use strict"; /*!***************************!*\ !*** ./src/main/index.ts ***! \***************************/ __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "CollectorModule": () => (/* reexport safe */ _CollectorModule__WEBPACK_IMPORTED_MODULE_0__.CollectorModule), /* harmony export */ "AbstractCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.AbstractCollector), /* harmony export */ "AssociatedProductCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.AssociatedProductCollector), +/* harmony export */ "Base64EncodeWriter": () => (/* reexport safe */ _writers__WEBPACK_IMPORTED_MODULE_2__.Base64EncodeWriter), /* harmony export */ "BasketClickCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.BasketClickCollector), /* harmony export */ "BrowserCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.BrowserCollector), +/* harmony export */ "BrowserTrackingWriter": () => (/* reexport safe */ _writers__WEBPACK_IMPORTED_MODULE_2__.BrowserTrackingWriter), +/* harmony export */ "BufferingWriter": () => (/* reexport safe */ _writers__WEBPACK_IMPORTED_MODULE_2__.BufferingWriter), /* harmony export */ "CheckoutClickCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.CheckoutClickCollector), /* harmony export */ "ClickCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.ClickCollector), /* harmony export */ "ClickWriterResolverCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.ClickWriterResolverCollector), +/* harmony export */ "CollectorModule": () => (/* reexport safe */ _CollectorModule__WEBPACK_IMPORTED_MODULE_0__.CollectorModule), +/* harmony export */ "ConsoleTransport": () => (/* reexport safe */ _logger__WEBPACK_IMPORTED_MODULE_4__.ConsoleTransport), +/* harmony export */ "ConsoleWriter": () => (/* reexport safe */ _writers__WEBPACK_IMPORTED_MODULE_2__.ConsoleWriter), +/* harmony export */ "Context": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_6__.Context), +/* harmony export */ "DebugWriter": () => (/* reexport safe */ _writers__WEBPACK_IMPORTED_MODULE_2__.DebugWriter), +/* harmony export */ "DefaultWriter": () => (/* reexport safe */ _writers__WEBPACK_IMPORTED_MODULE_2__.DefaultWriter), /* harmony export */ "FilterClickCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.FilterClickCollector), /* harmony export */ "FiredSearchCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.FiredSearchCollector), /* harmony export */ "GenericEventCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.GenericEventCollector), /* harmony export */ "ImpressionCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.ImpressionCollector), /* harmony export */ "InstantSearchQueryCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.InstantSearchQueryCollector), -/* harmony export */ "ProductClickCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.ProductClickCollector), -/* harmony export */ "RedirectCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.RedirectCollector), -/* harmony export */ "SearchResultCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.SearchResultCollector), -/* harmony export */ "SuggestSearchCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.SuggestSearchCollector), -/* harmony export */ "WriterResolverCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.WriterResolverCollector), -/* harmony export */ "Base64EncodeWriter": () => (/* reexport safe */ _writers__WEBPACK_IMPORTED_MODULE_2__.Base64EncodeWriter), -/* harmony export */ "BrowserTrackingWriter": () => (/* reexport safe */ _writers__WEBPACK_IMPORTED_MODULE_2__.BrowserTrackingWriter), -/* harmony export */ "BufferingWriter": () => (/* reexport safe */ _writers__WEBPACK_IMPORTED_MODULE_2__.BufferingWriter), -/* harmony export */ "ConsoleWriter": () => (/* reexport safe */ _writers__WEBPACK_IMPORTED_MODULE_2__.ConsoleWriter), -/* harmony export */ "DebugWriter": () => (/* reexport safe */ _writers__WEBPACK_IMPORTED_MODULE_2__.DebugWriter), -/* harmony export */ "DefaultWriter": () => (/* reexport safe */ _writers__WEBPACK_IMPORTED_MODULE_2__.DefaultWriter), /* harmony export */ "JSONEnvelopeWriter": () => (/* reexport safe */ _writers__WEBPACK_IMPORTED_MODULE_2__.JSONEnvelopeWriter), +/* harmony export */ "ListenerType": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_6__.ListenerType), +/* harmony export */ "LocalStorageQueue": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_6__.LocalStorageQueue), +/* harmony export */ "ProductClickCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.ProductClickCollector), +/* harmony export */ "Query": () => (/* reexport safe */ _query__WEBPACK_IMPORTED_MODULE_3__.Query), /* harmony export */ "QueryWriter": () => (/* reexport safe */ _writers__WEBPACK_IMPORTED_MODULE_2__.QueryWriter), +/* harmony export */ "RedirectCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.RedirectCollector), /* harmony export */ "RestEventWriter": () => (/* reexport safe */ _writers__WEBPACK_IMPORTED_MODULE_2__.RestEventWriter), +/* harmony export */ "SQSErrorTransport": () => (/* reexport safe */ _logger__WEBPACK_IMPORTED_MODULE_4__.SQSErrorTransport), /* harmony export */ "SQSEventWriter": () => (/* reexport safe */ _writers__WEBPACK_IMPORTED_MODULE_2__.SQSEventWriter), +/* harmony export */ "SQSTransport": () => (/* reexport safe */ _logger__WEBPACK_IMPORTED_MODULE_4__.SQSTransport), +/* harmony export */ "SearchResultCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.SearchResultCollector), +/* harmony export */ "Sentinel": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_6__.Sentinel), /* harmony export */ "SplitStreamWriter": () => (/* reexport safe */ _writers__WEBPACK_IMPORTED_MODULE_2__.SplitStreamWriter), -/* harmony export */ "TrailWriter": () => (/* reexport safe */ _writers__WEBPACK_IMPORTED_MODULE_2__.TrailWriter), -/* harmony export */ "Query": () => (/* reexport safe */ _query__WEBPACK_IMPORTED_MODULE_3__.Query), +/* harmony export */ "SuggestSearchCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.SuggestSearchCollector), /* harmony export */ "Trail": () => (/* reexport safe */ _query__WEBPACK_IMPORTED_MODULE_3__.Trail), /* harmony export */ "TrailType": () => (/* reexport safe */ _query__WEBPACK_IMPORTED_MODULE_3__.TrailType), -/* harmony export */ "ConsoleTransport": () => (/* reexport safe */ _logger__WEBPACK_IMPORTED_MODULE_4__.ConsoleTransport), -/* harmony export */ "SQSErrorTransport": () => (/* reexport safe */ _logger__WEBPACK_IMPORTED_MODULE_4__.SQSErrorTransport), -/* harmony export */ "SQSTransport": () => (/* reexport safe */ _logger__WEBPACK_IMPORTED_MODULE_4__.SQSTransport), +/* harmony export */ "TrailWriter": () => (/* reexport safe */ _writers__WEBPACK_IMPORTED_MODULE_2__.TrailWriter), /* harmony export */ "TransportLogger": () => (/* reexport safe */ _logger__WEBPACK_IMPORTED_MODULE_4__.TransportLogger), +/* harmony export */ "WriterResolverCollector": () => (/* reexport safe */ _collectors___WEBPACK_IMPORTED_MODULE_1__.WriterResolverCollector), +/* harmony export */ "base64Encode": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_6__.base64Encode), /* harmony export */ "cookieResolver": () => (/* reexport safe */ _resolvers__WEBPACK_IMPORTED_MODULE_5__.cookieResolver), /* harmony export */ "cookieSessionResolver": () => (/* reexport safe */ _resolvers__WEBPACK_IMPORTED_MODULE_5__.cookieSessionResolver), -/* harmony export */ "debugResolver": () => (/* reexport safe */ _resolvers__WEBPACK_IMPORTED_MODULE_5__.debugResolver), -/* harmony export */ "positionResolver": () => (/* reexport safe */ _resolvers__WEBPACK_IMPORTED_MODULE_5__.positionResolver), -/* harmony export */ "Context": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_6__.Context), -/* harmony export */ "ListenerType": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_6__.ListenerType), -/* harmony export */ "LocalStorageQueue": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_6__.LocalStorageQueue), -/* harmony export */ "Sentinel": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_6__.Sentinel), -/* harmony export */ "base64Encode": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_6__.base64Encode), /* harmony export */ "debounce": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_6__.debounce), +/* harmony export */ "debugResolver": () => (/* reexport safe */ _resolvers__WEBPACK_IMPORTED_MODULE_5__.debugResolver), /* harmony export */ "generateId": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_6__.generateId), /* harmony export */ "getCookie": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_6__.getCookie), /* harmony export */ "getLocalStorage": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_6__.getLocalStorage), /* harmony export */ "getSessionStorage": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_6__.getSessionStorage), +/* harmony export */ "normalizePathname": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_6__.normalizePathname), /* harmony export */ "parseQueryString": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_6__.parseQueryString), +/* harmony export */ "positionResolver": () => (/* reexport safe */ _resolvers__WEBPACK_IMPORTED_MODULE_5__.positionResolver), /* harmony export */ "setCookie": () => (/* reexport safe */ _utils__WEBPACK_IMPORTED_MODULE_6__.setCookie) /* harmony export */ }); /* harmony import */ var _CollectorModule__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./CollectorModule */ "./src/main/CollectorModule.ts"); @@ -3067,4 +3794,4 @@ __webpack_require__.r(__webpack_exports__); window.SearchCollector = __webpack_exports__; /******/ })() ; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,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O0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCLDBCQUEwQjtBQUNsRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCLDBCQUEwQjtBQUNsRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0IsMEJBQTBCO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7QUN6T21FO0FBQzNCO0FBQ3hDO0FBQ087QUFD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O0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7Ozs7QUNYTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7Ozs7Ozs7Ozs7Ozs7QUNwQkE7QUFDQTtBQUNBO0FBQ087QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7Ozs7Ozs7Ozs7Ozs7O0FDakJPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUNyRHFDO0FBQ0g7QUFDRjtBQUNLO0FBQ0g7QUFDRTtBQUNIOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FDTkk7QUFDRztBQUNOO0FBQ0Y7QUFDRjtBQUNFO0FBQ0s7QUFDUDtBQUNJO0FBQ0U7QUFDSDtBQUNIO0FBQ0w7Ozs7Ozs7VUNaekI7VUFDQTs7VUFFQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTs7VUFFQTtVQUNBOztVQUVBO1VBQ0E7VUFDQTs7Ozs7V0N0QkE7V0FDQTtXQUNBO1dBQ0E7V0FDQTtXQUNBLGlDQUFpQyxXQUFXO1dBQzVDO1dBQ0E7Ozs7O1dDUEE7V0FDQTtXQUNBO1dBQ0E7V0FDQSx5Q0FBeUMsd0NBQXdDO1dBQ2pGO1dBQ0E7V0FDQTs7Ozs7V0NQQTs7Ozs7V0NBQTtXQUNBO1dBQ0E7V0FDQSx1REFBdUQsaUJBQWlCO1dBQ3hFO1dBQ0EsZ0RBQWdELGFBQWE7V0FDN0Q7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FDTmtDO0FBQ0o7QUFDSjtBQUNGO0FBQ0M7QUFDRztBQUNKIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vbm9kZV9tb2R1bGVzL3Njcm9sbG1vbml0b3Ivc2Nyb2xsTW9uaXRvci5qcyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9Db2xsZWN0b3JNb2R1bGUudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vY29sbGVjdG9ycy9BYnN0cmFjdENvbGxlY3Rvci50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9jb2xsZWN0b3JzL0Fzc29jaWF0ZWRQcm9kdWN0Q29sbGVjdG9yLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL2NvbGxlY3RvcnMvQmFza2V0Q2xpY2tDb2xsZWN0b3IudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vY29sbGVjdG9ycy9Ccm93c2VyQ29sbGVjdG9yLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL2NvbGxlY3RvcnMvQ2hlY2tvdXRDbGlja0NvbGxlY3Rvci50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9jb2xsZWN0b3JzL0NsaWNrQ29sbGVjdG9yLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL2NvbGxlY3RvcnMvQ2xpY2tXcml0ZXJSZXNvbHZlckNvbGxlY3Rvci50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9jb2xsZWN0b3JzL0ZpbHRlckNsaWNrQ29sbGVjdG9yLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL2NvbGxlY3RvcnMvRmlyZWRTZWFyY2hDb2xsZWN0b3IudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vY29sbGVjdG9ycy9HZW5lcmljRXZlbnRDb2xsZWN0b3IudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vY29sbGVjdG9ycy9JbXByZXNzaW9uQ29sbGVjdG9yLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL2NvbGxlY3RvcnMvSW5zdGFudFNlYXJjaFF1ZXJ5Q29sbGVjdG9yLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL2NvbGxlY3RvcnMvUHJvZHVjdENsaWNrQ29sbGVjdG9yLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL2NvbGxlY3RvcnMvUmVkaXJlY3RDb2xsZWN0b3IudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vY29sbGVjdG9ycy9TZWFyY2hSZXN1bHRDb2xsZWN0b3IudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vY29sbGVjdG9ycy9TdWdnZXN0U2VhcmNoQ29sbGVjdG9yLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL2NvbGxlY3RvcnMvV3JpdGVyUmVzb2x2ZXJDb2xsZWN0b3IudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vY29sbGVjdG9ycy9pbmRleC50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9sb2dnZXIvTG9nZ2VyLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL2xvZ2dlci9Mb2dnZXJUcmFuc3BvcnQudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vbG9nZ2VyL1RyYW5zcG9ydExvZ2dlci50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9sb2dnZXIvaW5kZXgudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vbG9nZ2VyL3RyYW5zcG9ydC9Db25zb2xlVHJhbnNwb3J0LnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL2xvZ2dlci90cmFuc3BvcnQvU1FTRXJyb3JUcmFuc3BvcnQudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vbG9nZ2VyL3RyYW5zcG9ydC9TUVNUcmFuc3BvcnQudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vbG9nZ2VyL3RyYW5zcG9ydC9pbmRleC50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9xdWVyeS9RdWVyeS50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9xdWVyeS9UcmFpbC50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9xdWVyeS9UcmFpbFR5cGUudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vcXVlcnkvaW5kZXgudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vcmVzb2x2ZXJzL1Jlc29sdmVyLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3Jlc29sdmVycy9pbmRleC50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi91dGlscy9Db250ZXh0LnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3V0aWxzL0xpc3RlbmVyVHlwZS50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi91dGlscy9Mb2NhbFN0b3JhZ2VRdWV1ZS50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi91dGlscy9TZW50aW5lbC50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi91dGlscy9VdGlsLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3V0aWxzL2luZGV4LnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3dyaXRlcnMvQmFzZTY0RW5jb2RlV3JpdGVyLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3dyaXRlcnMvQnJvd3NlclRyYWNraW5nV3JpdGVyLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3dyaXRlcnMvQnVmZmVyaW5nV3JpdGVyLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3dyaXRlcnMvQ29uc29sZVdyaXRlci50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi93cml0ZXJzL0RlYnVnV3JpdGVyLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3dyaXRlcnMvRGVmYXVsdFdyaXRlci50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi93cml0ZXJzL0pTT05FbnZlbG9wZVdyaXRlci50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi93cml0ZXJzL1F1ZXJ5V3JpdGVyLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3dyaXRlcnMvUmVzdEV2ZW50V3JpdGVyLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3dyaXRlcnMvU1FTRXZlbnRXcml0ZXIudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vd3JpdGVycy9TcGxpdFN0cmVhbVdyaXRlci50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi93cml0ZXJzL1RyYWlsV3JpdGVyLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3dyaXRlcnMvV3JpdGVyLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3dyaXRlcnMvaW5kZXgudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yL3dlYnBhY2svYm9vdHN0cmFwIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci93ZWJwYWNrL3J1bnRpbWUvY29tcGF0IGdldCBkZWZhdWx0IGV4cG9ydCIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3Ivd2VicGFjay9ydW50aW1lL2RlZmluZSBwcm9wZXJ0eSBnZXR0ZXJzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci93ZWJwYWNrL3J1bnRpbWUvaGFzT3duUHJvcGVydHkgc2hvcnRoYW5kIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci93ZWJwYWNrL3J1bnRpbWUvbWFrZSBuYW1lc3BhY2Ugb2JqZWN0Iiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL2luZGV4LnRzIl0sInNvdXJjZXNDb250ZW50IjpbIiFmdW5jdGlvbih0LGUpe1wib2JqZWN0XCI9PXR5cGVvZiBleHBvcnRzJiZcIm9iamVjdFwiPT10eXBlb2YgbW9kdWxlP21vZHVsZS5leHBvcnRzPWUoKTpcImZ1bmN0aW9uXCI9PXR5cGVvZiBkZWZpbmUmJmRlZmluZS5hbWQ/ZGVmaW5lKFwic2Nyb2xsTW9uaXRvclwiLFtdLGUpOlwib2JqZWN0XCI9PXR5cGVvZiBleHBvcnRzP2V4cG9ydHMuc2Nyb2xsTW9uaXRvcj1lKCk6dC5zY3JvbGxNb25pdG9yPWUoKX0odGhpcyxmdW5jdGlvbigpe3JldHVybiBmdW5jdGlvbih0KXtmdW5jdGlvbiBlKG8pe2lmKGlbb10pcmV0dXJuIGlbb10uZXhwb3J0czt2YXIgcz1pW29dPXtleHBvcnRzOnt9LGlkOm8sbG9hZGVkOiExfTtyZXR1cm4gdFtvXS5jYWxsKHMuZXhwb3J0cyxzLHMuZXhwb3J0cyxlKSxzLmxvYWRlZD0hMCxzLmV4cG9ydHN9dmFyIGk9e307cmV0dXJuIGUubT10LGUuYz1pLGUucD1cIlwiLGUoMCl9KFtmdW5jdGlvbih0LGUsaSl7XCJ1c2Ugc3RyaWN0XCI7dmFyIG89aSgxKSxzPW8uaXNJbkJyb3dzZXIsbj1pKDIpLHI9bmV3IG4ocz9kb2N1bWVudC5ib2R5Om51bGwpO3Iuc2V0U3RhdGVGcm9tRE9NKG51bGwpLHIubGlzdGVuVG9ET00oKSxzJiYod2luZG93LnNjcm9sbE1vbml0b3I9ciksdC5leHBvcnRzPXJ9LGZ1bmN0aW9uKHQsZSl7XCJ1c2Ugc3RyaWN0XCI7ZS5WSVNJQklMSVRZQ0hBTkdFPVwidmlzaWJpbGl0eUNoYW5nZVwiLGUuRU5URVJWSUVXUE9SVD1cImVudGVyVmlld3BvcnRcIixlLkZVTExZRU5URVJWSUVXUE9SVD1cImZ1bGx5RW50ZXJWaWV3cG9ydFwiLGUuRVhJVFZJRVdQT1JUPVwiZXhpdFZpZXdwb3J0XCIsZS5QQVJUSUFMTFlFWElUVklFV1BPUlQ9XCJwYXJ0aWFsbHlFeGl0Vmlld3BvcnRcIixlLkxPQ0FUSU9OQ0hBTkdFPVwibG9jYXRpb25DaGFuZ2VcIixlLlNUQVRFQ0hBTkdFPVwic3RhdGVDaGFuZ2VcIixlLmV2ZW50VHlwZXM9W2UuVklTSUJJTElUWUNIQU5HRSxlLkVOVEVSVklFV1BPUlQsZS5GVUxMWUVOVEVSVklFV1BPUlQsZS5FWElUVklFV1BPUlQsZS5QQVJUSUFMTFlFWElUVklFV1BPUlQsZS5MT0NBVElPTkNIQU5HRSxlLlNUQVRFQ0hBTkdFXSxlLmlzT25TZXJ2ZXI9XCJ1bmRlZmluZWRcIj09dHlwZW9mIHdpbmRvdyxlLmlzSW5Ccm93c2VyPSFlLmlzT25TZXJ2ZXIsZS5kZWZhdWx0T2Zmc2V0cz17dG9wOjAsYm90dG9tOjB9fSxmdW5jdGlvbih0LGUsaSl7XCJ1c2Ugc3RyaWN0XCI7ZnVuY3Rpb24gbyh0LGUpe2lmKCEodCBpbnN0YW5jZW9mIGUpKXRocm93IG5ldyBUeXBlRXJyb3IoXCJDYW5ub3QgY2FsbCBhIGNsYXNzIGFzIGEgZnVuY3Rpb25cIil9ZnVuY3Rpb24gcyh0KXtyZXR1cm4gYz8wOnQ9PT1kb2N1bWVudC5ib2R5P3dpbmRvdy5pbm5lckhlaWdodHx8ZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudEhlaWdodDp0LmNsaWVudEhlaWdodH1mdW5jdGlvbiBuKHQpe3JldHVybiBjPzA6dD09PWRvY3VtZW50LmJvZHk/TWF0aC5tYXgoZG9jdW1lbnQuYm9keS5zY3JvbGxIZWlnaHQsZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnNjcm9sbEhlaWdodCxkb2N1bWVudC5ib2R5Lm9mZnNldEhlaWdodCxkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQub2Zmc2V0SGVpZ2h0LGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRIZWlnaHQpOnQuc2Nyb2xsSGVpZ2h0fWZ1bmN0aW9uIHIodCl7cmV0dXJuIGM/MDp0PT09ZG9jdW1lbnQuYm9keT93aW5kb3cucGFnZVlPZmZzZXR8fGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCYmZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnNjcm9sbFRvcHx8ZG9jdW1lbnQuYm9keS5zY3JvbGxUb3A6dC5zY3JvbGxUb3B9dmFyIGg9aSgxKSxjPWguaXNPblNlcnZlcixhPWguaXNJbkJyb3dzZXIsbD1oLmV2ZW50VHlwZXMscD1pKDMpLHU9ITE7aWYoYSl0cnl7dmFyIHc9T2JqZWN0LmRlZmluZVByb3BlcnR5KHt9LFwicGFzc2l2ZVwiLHtnZXQ6ZnVuY3Rpb24oKXt1PSEwfX0pO3dpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwidGVzdFwiLG51bGwsdyl9Y2F0Y2godCl7fXZhciBkPSEhdSYme2NhcHR1cmU6ITEscGFzc2l2ZTohMH0sZj1mdW5jdGlvbigpe2Z1bmN0aW9uIHQoZSxpKXtmdW5jdGlvbiBoKCl7aWYoYS52aWV3cG9ydFRvcD1yKGUpLGEudmlld3BvcnRCb3R0b209YS52aWV3cG9ydFRvcCthLnZpZXdwb3J0SGVpZ2h0LGEuZG9jdW1lbnRIZWlnaHQ9bihlKSxhLmRvY3VtZW50SGVpZ2h0IT09cCl7Zm9yKHU9YS53YXRjaGVycy5sZW5ndGg7dS0tOylhLndhdGNoZXJzW3VdLnJlY2FsY3VsYXRlTG9jYXRpb24oKTtwPWEuZG9jdW1lbnRIZWlnaHR9fWZ1bmN0aW9uIGMoKXtmb3Iodz1hLndhdGNoZXJzLmxlbmd0aDt3LS07KWEud2F0Y2hlcnNbd10udXBkYXRlKCk7Zm9yKHc9YS53YXRjaGVycy5sZW5ndGg7dy0tOylhLndhdGNoZXJzW3ddLnRyaWdnZXJDYWxsYmFja3MoKX1vKHRoaXMsdCk7dmFyIGE9dGhpczt0aGlzLml0ZW09ZSx0aGlzLndhdGNoZXJzPVtdLHRoaXMudmlld3BvcnRUb3A9bnVsbCx0aGlzLnZpZXdwb3J0Qm90dG9tPW51bGwsdGhpcy5kb2N1bWVudEhlaWdodD1uKGUpLHRoaXMudmlld3BvcnRIZWlnaHQ9cyhlKSx0aGlzLkRPTUxpc3RlbmVyPWZ1bmN0aW9uKCl7dC5wcm90b3R5cGUuRE9NTGlzdGVuZXIuYXBwbHkoYSxhcmd1bWVudHMpfSx0aGlzLmV2ZW50VHlwZXM9bCxpJiYodGhpcy5jb250YWluZXJXYXRjaGVyPWkuY3JlYXRlKGUpKTt2YXIgcCx1LHc7dGhpcy51cGRhdGU9ZnVuY3Rpb24oKXtoKCksYygpfSx0aGlzLnJlY2FsY3VsYXRlTG9jYXRpb25zPWZ1bmN0aW9uKCl7dGhpcy5kb2N1bWVudEhlaWdodD0wLHRoaXMudXBkYXRlKCl9fXJldHVybiB0LnByb3RvdHlwZS5saXN0ZW5Ub0RPTT1mdW5jdGlvbigpe2EmJih3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcj8odGhpcy5pdGVtPT09ZG9jdW1lbnQuYm9keT93aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcihcInNjcm9sbFwiLHRoaXMuRE9NTGlzdGVuZXIsZCk6dGhpcy5pdGVtLmFkZEV2ZW50TGlzdGVuZXIoXCJzY3JvbGxcIix0aGlzLkRPTUxpc3RlbmVyLGQpLHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwicmVzaXplXCIsdGhpcy5ET01MaXN0ZW5lcikpOih0aGlzLml0ZW09PT1kb2N1bWVudC5ib2R5P3dpbmRvdy5hdHRhY2hFdmVudChcIm9uc2Nyb2xsXCIsdGhpcy5ET01MaXN0ZW5lcik6dGhpcy5pdGVtLmF0dGFjaEV2ZW50KFwib25zY3JvbGxcIix0aGlzLkRPTUxpc3RlbmVyKSx3aW5kb3cuYXR0YWNoRXZlbnQoXCJvbnJlc2l6ZVwiLHRoaXMuRE9NTGlzdGVuZXIpKSx0aGlzLmRlc3Ryb3k9ZnVuY3Rpb24oKXt3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcj8odGhpcy5pdGVtPT09ZG9jdW1lbnQuYm9keT8od2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJzY3JvbGxcIix0aGlzLkRPTUxpc3RlbmVyLGQpLHRoaXMuY29udGFpbmVyV2F0Y2hlci5kZXN0cm95KCkpOnRoaXMuaXRlbS5yZW1vdmVFdmVudExpc3RlbmVyKFwic2Nyb2xsXCIsdGhpcy5ET01MaXN0ZW5lcixkKSx3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcihcInJlc2l6ZVwiLHRoaXMuRE9NTGlzdGVuZXIpKToodGhpcy5pdGVtPT09ZG9jdW1lbnQuYm9keT8od2luZG93LmRldGFjaEV2ZW50KFwib25zY3JvbGxcIix0aGlzLkRPTUxpc3RlbmVyKSx0aGlzLmNvbnRhaW5lcldhdGNoZXIuZGVzdHJveSgpKTp0aGlzLml0ZW0uZGV0YWNoRXZlbnQoXCJvbnNjcm9sbFwiLHRoaXMuRE9NTGlzdGVuZXIpLHdpbmRvdy5kZXRhY2hFdmVudChcIm9ucmVzaXplXCIsdGhpcy5ET01MaXN0ZW5lcikpfSl9LHQucHJvdG90eXBlLmRlc3Ryb3k9ZnVuY3Rpb24oKXt9LHQucHJvdG90eXBlLkRPTUxpc3RlbmVyPWZ1bmN0aW9uKHQpe3RoaXMuc2V0U3RhdGVGcm9tRE9NKHQpfSx0LnByb3RvdHlwZS5zZXRTdGF0ZUZyb21ET009ZnVuY3Rpb24odCl7dmFyIGU9cih0aGlzLml0ZW0pLGk9cyh0aGlzLml0ZW0pLG89bih0aGlzLml0ZW0pO3RoaXMuc2V0U3RhdGUoZSxpLG8sdCl9LHQucHJvdG90eXBlLnNldFN0YXRlPWZ1bmN0aW9uKHQsZSxpLG8pe3ZhciBzPWUhPT10aGlzLnZpZXdwb3J0SGVpZ2h0fHxpIT09dGhpcy5jb250ZW50SGVpZ2h0O2lmKHRoaXMubGF0ZXN0RXZlbnQ9byx0aGlzLnZpZXdwb3J0VG9wPXQsdGhpcy52aWV3cG9ydEhlaWdodD1lLHRoaXMudmlld3BvcnRCb3R0b209dCtlLHRoaXMuY29udGVudEhlaWdodD1pLHMpZm9yKHZhciBuPXRoaXMud2F0Y2hlcnMubGVuZ3RoO24tLTspdGhpcy53YXRjaGVyc1tuXS5yZWNhbGN1bGF0ZUxvY2F0aW9uKCk7dGhpcy51cGRhdGVBbmRUcmlnZ2VyV2F0Y2hlcnMobyl9LHQucHJvdG90eXBlLnVwZGF0ZUFuZFRyaWdnZXJXYXRjaGVycz1mdW5jdGlvbih0KXtmb3IodmFyIGU9dGhpcy53YXRjaGVycy5sZW5ndGg7ZS0tOyl0aGlzLndhdGNoZXJzW2VdLnVwZGF0ZSgpO2ZvcihlPXRoaXMud2F0Y2hlcnMubGVuZ3RoO2UtLTspdGhpcy53YXRjaGVyc1tlXS50cmlnZ2VyQ2FsbGJhY2tzKHQpfSx0LnByb3RvdHlwZS5jcmVhdGVDdXN0b21Db250YWluZXI9ZnVuY3Rpb24oKXtyZXR1cm4gbmV3IHR9LHQucHJvdG90eXBlLmNyZWF0ZUNvbnRhaW5lcj1mdW5jdGlvbihlKXtcInN0cmluZ1wiPT10eXBlb2YgZT9lPWRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoZSk6ZSYmZS5sZW5ndGg+MCYmKGU9ZVswXSk7dmFyIGk9bmV3IHQoZSx0aGlzKTtyZXR1cm4gaS5zZXRTdGF0ZUZyb21ET00oKSxpLmxpc3RlblRvRE9NKCksaX0sdC5wcm90b3R5cGUuY3JlYXRlPWZ1bmN0aW9uKHQsZSl7XCJzdHJpbmdcIj09dHlwZW9mIHQ/dD1kb2N1bWVudC5xdWVyeVNlbGVjdG9yKHQpOnQmJnQubGVuZ3RoPjAmJih0PXRbMF0pO3ZhciBpPW5ldyBwKHRoaXMsdCxlKTtyZXR1cm4gdGhpcy53YXRjaGVycy5wdXNoKGkpLGl9LHQucHJvdG90eXBlLmJlZ2V0PWZ1bmN0aW9uKHQsZSl7cmV0dXJuIHRoaXMuY3JlYXRlKHQsZSl9LHR9KCk7dC5leHBvcnRzPWZ9LGZ1bmN0aW9uKHQsZSxpKXtcInVzZSBzdHJpY3RcIjtmdW5jdGlvbiBvKHQsZSxpKXtmdW5jdGlvbiBvKHQsZSl7aWYoMCE9PXQubGVuZ3RoKWZvcihFPXQubGVuZ3RoO0UtLTspeT10W0VdLHkuY2FsbGJhY2suY2FsbChzLGUscykseS5pc09uZSYmdC5zcGxpY2UoRSwxKX12YXIgcz10aGlzO3RoaXMud2F0Y2hJdGVtPWUsdGhpcy5jb250YWluZXI9dCxpP2k9PT0raT90aGlzLm9mZnNldHM9e3RvcDppLGJvdHRvbTppfTp0aGlzLm9mZnNldHM9e3RvcDppLnRvcHx8dy50b3AsYm90dG9tOmkuYm90dG9tfHx3LmJvdHRvbX06dGhpcy5vZmZzZXRzPXcsdGhpcy5jYWxsYmFja3M9e307Zm9yKHZhciBkPTAsZj11Lmxlbmd0aDtkPGY7ZCsrKXMuY2FsbGJhY2tzW3VbZF1dPVtdO3RoaXMubG9ja2VkPSExO3ZhciBtLHYsYixJLEUseTt0aGlzLnRyaWdnZXJDYWxsYmFja3M9ZnVuY3Rpb24odCl7c3dpdGNoKHRoaXMuaXNJblZpZXdwb3J0JiYhbSYmbyh0aGlzLmNhbGxiYWNrc1tyXSx0KSx0aGlzLmlzRnVsbHlJblZpZXdwb3J0JiYhdiYmbyh0aGlzLmNhbGxiYWNrc1toXSx0KSx0aGlzLmlzQWJvdmVWaWV3cG9ydCE9PWImJnRoaXMuaXNCZWxvd1ZpZXdwb3J0IT09SSYmKG8odGhpcy5jYWxsYmFja3Nbbl0sdCksdnx8dGhpcy5pc0Z1bGx5SW5WaWV3cG9ydHx8KG8odGhpcy5jYWxsYmFja3NbaF0sdCksbyh0aGlzLmNhbGxiYWNrc1thXSx0KSksbXx8dGhpcy5pc0luVmlld3BvcnR8fChvKHRoaXMuY2FsbGJhY2tzW3JdLHQpLG8odGhpcy5jYWxsYmFja3NbY10sdCkpKSwhdGhpcy5pc0Z1bGx5SW5WaWV3cG9ydCYmdiYmbyh0aGlzLmNhbGxiYWNrc1thXSx0KSwhdGhpcy5pc0luVmlld3BvcnQmJm0mJm8odGhpcy5jYWxsYmFja3NbY10sdCksdGhpcy5pc0luVmlld3BvcnQhPT1tJiZvKHRoaXMuY2FsbGJhY2tzW25dLHQpLCEwKXtjYXNlIG0hPT10aGlzLmlzSW5WaWV3cG9ydDpjYXNlIHYhPT10aGlzLmlzRnVsbHlJblZpZXdwb3J0OmNhc2UgYiE9PXRoaXMuaXNBYm92ZVZpZXdwb3J0OmNhc2UgSSE9PXRoaXMuaXNCZWxvd1ZpZXdwb3J0Om8odGhpcy5jYWxsYmFja3NbcF0sdCl9bT10aGlzLmlzSW5WaWV3cG9ydCx2PXRoaXMuaXNGdWxseUluVmlld3BvcnQsYj10aGlzLmlzQWJvdmVWaWV3cG9ydCxJPXRoaXMuaXNCZWxvd1ZpZXdwb3J0fSx0aGlzLnJlY2FsY3VsYXRlTG9jYXRpb249ZnVuY3Rpb24oKXtpZighdGhpcy5sb2NrZWQpe3ZhciB0PXRoaXMudG9wLGU9dGhpcy5ib3R0b207aWYodGhpcy53YXRjaEl0ZW0ubm9kZU5hbWUpe3ZhciBpPXRoaXMud2F0Y2hJdGVtLnN0eWxlLmRpc3BsYXk7XCJub25lXCI9PT1pJiYodGhpcy53YXRjaEl0ZW0uc3R5bGUuZGlzcGxheT1cIlwiKTtmb3IodmFyIHM9MCxuPXRoaXMuY29udGFpbmVyO24uY29udGFpbmVyV2F0Y2hlcjspcys9bi5jb250YWluZXJXYXRjaGVyLnRvcC1uLmNvbnRhaW5lcldhdGNoZXIuY29udGFpbmVyLnZpZXdwb3J0VG9wLG49bi5jb250YWluZXJXYXRjaGVyLmNvbnRhaW5lcjt2YXIgcj10aGlzLndhdGNoSXRlbS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTt0aGlzLnRvcD1yLnRvcCt0aGlzLmNvbnRhaW5lci52aWV3cG9ydFRvcC1zLHRoaXMuYm90dG9tPXIuYm90dG9tK3RoaXMuY29udGFpbmVyLnZpZXdwb3J0VG9wLXMsXCJub25lXCI9PT1pJiYodGhpcy53YXRjaEl0ZW0uc3R5bGUuZGlzcGxheT1pKX1lbHNlIHRoaXMud2F0Y2hJdGVtPT09K3RoaXMud2F0Y2hJdGVtP3RoaXMud2F0Y2hJdGVtPjA/dGhpcy50b3A9dGhpcy5ib3R0b209dGhpcy53YXRjaEl0ZW06dGhpcy50b3A9dGhpcy5ib3R0b209dGhpcy5jb250YWluZXIuZG9jdW1lbnRIZWlnaHQtdGhpcy53YXRjaEl0ZW06KHRoaXMudG9wPXRoaXMud2F0Y2hJdGVtLnRvcCx0aGlzLmJvdHRvbT10aGlzLndhdGNoSXRlbS5ib3R0b20pO3RoaXMudG9wLT10aGlzLm9mZnNldHMudG9wLHRoaXMuYm90dG9tKz10aGlzLm9mZnNldHMuYm90dG9tLHRoaXMuaGVpZ2h0PXRoaXMuYm90dG9tLXRoaXMudG9wLHZvaWQgMD09PXQmJnZvaWQgMD09PWV8fHRoaXMudG9wPT09dCYmdGhpcy5ib3R0b209PT1lfHxvKHRoaXMuY2FsbGJhY2tzW2xdLG51bGwpfX0sdGhpcy5yZWNhbGN1bGF0ZUxvY2F0aW9uKCksdGhpcy51cGRhdGUoKSxtPXRoaXMuaXNJblZpZXdwb3J0LHY9dGhpcy5pc0Z1bGx5SW5WaWV3cG9ydCxiPXRoaXMuaXNBYm92ZVZpZXdwb3J0LEk9dGhpcy5pc0JlbG93Vmlld3BvcnR9dmFyIHM9aSgxKSxuPXMuVklTSUJJTElUWUNIQU5HRSxyPXMuRU5URVJWSUVXUE9SVCxoPXMuRlVMTFlFTlRFUlZJRVdQT1JULGM9cy5FWElUVklFV1BPUlQsYT1zLlBBUlRJQUxMWUVYSVRWSUVXUE9SVCxsPXMuTE9DQVRJT05DSEFOR0UscD1zLlNUQVRFQ0hBTkdFLHU9cy5ldmVudFR5cGVzLHc9cy5kZWZhdWx0T2Zmc2V0cztvLnByb3RvdHlwZT17b246ZnVuY3Rpb24odCxlLGkpe3N3aXRjaCghMCl7Y2FzZSB0PT09biYmIXRoaXMuaXNJblZpZXdwb3J0JiZ0aGlzLmlzQWJvdmVWaWV3cG9ydDpjYXNlIHQ9PT1yJiZ0aGlzLmlzSW5WaWV3cG9ydDpjYXNlIHQ9PT1oJiZ0aGlzLmlzRnVsbHlJblZpZXdwb3J0OmNhc2UgdD09PWMmJnRoaXMuaXNBYm92ZVZpZXdwb3J0JiYhdGhpcy5pc0luVmlld3BvcnQ6Y2FzZSB0PT09YSYmdGhpcy5pc0luVmlld3BvcnQmJnRoaXMuaXNBYm92ZVZpZXdwb3J0OmlmKGUuY2FsbCh0aGlzLHRoaXMuY29udGFpbmVyLmxhdGVzdEV2ZW50LHRoaXMpLGkpcmV0dXJufWlmKCF0aGlzLmNhbGxiYWNrc1t0XSl0aHJvdyBuZXcgRXJyb3IoXCJUcmllZCB0byBhZGQgYSBzY3JvbGwgbW9uaXRvciBsaXN0ZW5lciBvZiB0eXBlIFwiK3QrXCIuIFlvdXIgb3B0aW9ucyBhcmU6IFwiK3Uuam9pbihcIiwgXCIpKTt0aGlzLmNhbGxiYWNrc1t0XS5wdXNoKHtjYWxsYmFjazplLGlzT25lOml8fCExfSl9LG9mZjpmdW5jdGlvbih0LGUpe2lmKCF0aGlzLmNhbGxiYWNrc1t0XSl0aHJvdyBuZXcgRXJyb3IoXCJUcmllZCB0byByZW1vdmUgYSBzY3JvbGwgbW9uaXRvciBsaXN0ZW5lciBvZiB0eXBlIFwiK3QrXCIuIFlvdXIgb3B0aW9ucyBhcmU6IFwiK3Uuam9pbihcIiwgXCIpKTtmb3IodmFyIGksbz0wO2k9dGhpcy5jYWxsYmFja3NbdF1bb107bysrKWlmKGkuY2FsbGJhY2s9PT1lKXt0aGlzLmNhbGxiYWNrc1t0XS5zcGxpY2UobywxKTticmVha319LG9uZTpmdW5jdGlvbih0LGUpe3RoaXMub24odCxlLCEwKX0scmVjYWxjdWxhdGVTaXplOmZ1bmN0aW9uKCl7dGhpcy5oZWlnaHQ9dGhpcy53YXRjaEl0ZW0ub2Zmc2V0SGVpZ2h0K3RoaXMub2Zmc2V0cy50b3ArdGhpcy5vZmZzZXRzLmJvdHRvbSx0aGlzLmJvdHRvbT10aGlzLnRvcCt0aGlzLmhlaWdodH0sdXBkYXRlOmZ1bmN0aW9uKCl7dGhpcy5pc0Fib3ZlVmlld3BvcnQ9dGhpcy50b3A8dGhpcy5jb250YWluZXIudmlld3BvcnRUb3AsdGhpcy5pc0JlbG93Vmlld3BvcnQ9dGhpcy5ib3R0b20+dGhpcy5jb250YWluZXIudmlld3BvcnRCb3R0b20sdGhpcy5pc0luVmlld3BvcnQ9dGhpcy50b3A8dGhpcy5jb250YWluZXIudmlld3BvcnRCb3R0b20mJnRoaXMuYm90dG9tPnRoaXMuY29udGFpbmVyLnZpZXdwb3J0VG9wLHRoaXMuaXNGdWxseUluVmlld3BvcnQ9dGhpcy50b3A+PXRoaXMuY29udGFpbmVyLnZpZXdwb3J0VG9wJiZ0aGlzLmJvdHRvbTw9dGhpcy5jb250YWluZXIudmlld3BvcnRCb3R0b218fHRoaXMuaXNBYm92ZVZpZXdwb3J0JiZ0aGlzLmlzQmVsb3dWaWV3cG9ydH0sZGVzdHJveTpmdW5jdGlvbigpe3ZhciB0PXRoaXMuY29udGFpbmVyLndhdGNoZXJzLmluZGV4T2YodGhpcyksZT10aGlzO3RoaXMuY29udGFpbmVyLndhdGNoZXJzLnNwbGljZSh0LDEpO2Zvcih2YXIgaT0wLG89dS5sZW5ndGg7aTxvO2krKyllLmNhbGxiYWNrc1t1W2ldXS5sZW5ndGg9MH0sbG9jazpmdW5jdGlvbigpe3RoaXMubG9ja2VkPSEwfSx1bmxvY2s6ZnVuY3Rpb24oKXt0aGlzLmxvY2tlZD0hMX19O2Zvcih2YXIgZD1mdW5jdGlvbih0KXtyZXR1cm4gZnVuY3Rpb24oZSxpKXt0aGlzLm9uLmNhbGwodGhpcyx0LGUsaSl9fSxmPTAsbT11Lmxlbmd0aDtmPG07ZisrKXt2YXIgdj11W2ZdO28ucHJvdG90eXBlW3ZdPWQodil9dC5leHBvcnRzPW99XSl9KTtcbi8vIyBzb3VyY2VNYXBwaW5nVVJMPXNjcm9sbE1vbml0b3IuanMubWFwIiwiaW1wb3J0IHsgU3BsaXRTdHJlYW1Xcml0ZXIgfSBmcm9tIFwiLi93cml0ZXJzL1NwbGl0U3RyZWFtV3JpdGVyXCI7XG5pbXBvcnQgeyBUcmFuc3BvcnRMb2dnZXIgfSBmcm9tIFwiLi9sb2dnZXIvVHJhbnNwb3J0TG9nZ2VyXCI7XG5pbXBvcnQgeyBDb25zb2xlV3JpdGVyIH0gZnJvbSBcIi4vd3JpdGVycy9Db25zb2xlV3JpdGVyXCI7XG5pbXBvcnQgeyBDb25zb2xlVHJhbnNwb3J0IH0gZnJvbSBcIi4vbG9nZ2VyXCI7XG4vKipcbiAqIERlZmF1bHQgYXNzZW1ibHkgcG9pbnQgb2YgY29sbGVjdG9ycyBhbmQgd3JpdGVycy5cbiAqL1xuZXhwb3J0IGNsYXNzIENvbGxlY3Rvck1vZHVsZSB7XG4gICAgY29uc3RydWN0b3Iob3B0aW9ucykge1xuICAgICAgICB0aGlzLmNvbGxlY3RvcnMgPSBbXTtcbiAgICAgICAgdGhpcy53cml0ZXJzID0gW107XG4gICAgICAgIHRoaXMudHJhbnNwb3J0cyA9IFtdO1xuICAgICAgICB0aGlzLmhhc1N0YXJ0ZWQgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICB9XG4gICAgYWRkKGNvbGxlY3Rvcikge1xuICAgICAgICBpZiAodGhpcy5vcHRpb25zLmNvbnRleHQgJiYgIWNvbGxlY3Rvci5nZXRDb250ZXh0KCkpXG4gICAgICAgICAgICBjb2xsZWN0b3Iuc2V0Q29udGV4dCh0aGlzLm9wdGlvbnMuY29udGV4dCk7XG4gICAgICAgIHRoaXMuY29sbGVjdG9ycy5wdXNoKGNvbGxlY3Rvcik7XG4gICAgICAgIGlmICh0aGlzLmhhc1N0YXJ0ZWQgPT09IHRydWUpXG4gICAgICAgICAgICB0aGlzLmludm9rZWRDb2xsZWN0b3IoY29sbGVjdG9yKTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogU3RhcnQgY29sbGVjdGluZyBkYXRhIGJ5IGF0dGFjaGluZyBhbGwgY29sbGVjdG9yc1xuICAgICAqL1xuICAgIHN0YXJ0KCkge1xuICAgICAgICB0aGlzLmNvbGxlY3RvcnMuZm9yRWFjaChjb2xsZWN0b3IgPT4gdGhpcy5pbnZva2VkQ29sbGVjdG9yKGNvbGxlY3RvcikpO1xuICAgICAgICB0aGlzLmhhc1N0YXJ0ZWQgPSB0cnVlO1xuICAgIH1cbiAgICBhZGRMb2dUcmFuc3BvcnQodHJhbnNwb3J0KSB7XG4gICAgICAgIHRoaXMudHJhbnNwb3J0cy5wdXNoKHRyYW5zcG9ydCk7XG4gICAgfVxuICAgIHNldFRyYW5zcG9ydHModHJhbnNwb3J0cykge1xuICAgICAgICB0aGlzLnRyYW5zcG9ydHMgPSB0cmFuc3BvcnRzIHx8IFtdO1xuICAgIH1cbiAgICBzZXRXcml0ZXJzKHJlcGxhY2VtZW50V3JpdGVycykge1xuICAgICAgICB0aGlzLndyaXRlcnMgPSBBcnJheS5pc0FycmF5KHJlcGxhY2VtZW50V3JpdGVycykgPyBbLi4ucmVwbGFjZW1lbnRXcml0ZXJzXSA6IFtyZXBsYWNlbWVudFdyaXRlcnNdO1xuICAgIH1cbiAgICBzZXRMb2dnZXIobG9nZ2VyKSB7XG4gICAgICAgIHRoaXMubG9nZ2VyID0gbG9nZ2VyO1xuICAgIH1cbiAgICBpbnZva2VkQ29sbGVjdG9yKGNvbGxlY3Rvcikge1xuICAgICAgICBjb25zdCB3cml0ZXIgPSB0aGlzLmdldFdyaXRlcigpO1xuICAgICAgICBjb25zdCBsb2cgPSB0aGlzLmdldExvZ2dlcigpO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29sbGVjdG9yLmF0dGFjaCh3cml0ZXIsIGxvZyk7XG4gICAgICAgIH1cbiAgICAgICAgY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGxvZy5lcnJvcihgWyR7Y29sbGVjdG9yLmNvbnN0cnVjdG9yLm5hbWV9XSBVbmV4cGVjdGVkIEV4Y2VwdGlvbiBkdXJpbmcgY29sbGVjdG9yIGF0dGFjaDogYCwgZSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZ2V0TG9nZ2VyKCkge1xuICAgICAgICBjb25zdCBoYXNMb2dnZXIgPSAhIXRoaXMubG9nZ2VyO1xuICAgICAgICBpZiAoaGFzTG9nZ2VyKVxuICAgICAgICAgICAgcmV0dXJuIHRoaXMubG9nZ2VyO1xuICAgICAgICBpZiAoIXRoaXMudHJhbnNwb3J0cyB8fCB0aGlzLnRyYW5zcG9ydHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXCJBVFRFTlRJT04tU0VBUkNILUNPTExFQ1RPUi1XQVJOSU5HXCIpO1xuICAgICAgICAgICAgY29uc29sZS53YXJuKFwic2VhcmNoLWNvbGxlY3Rvcjogbm8gTG9nZ2VyVHJhbnNwb3J0IGNvbmZpZ3VyZWQgd2hpbGUgdXNpbmcgdGhlIGRlZmF1bHQgVHJhbnNwb3J0TG9nZ2VyLiBQbGVhc2UgYWRkIGEgdHJhbnNwb3J0IENvbGxlY3Rvck1vZHVsZSNhZGRMb2dUcmFuc3BvcnQgb3IgQ29sbGVjdG9yTW9kdWxlI3NldFRyYW5zcG9ydHNcIik7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXCJzZWFyY2gtY29sbGVjdG9yOiB3aWxsIEZBTExCQUNLIHRvIENvbnNvbGVUcmFuc3BvcnRcIik7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFRyYW5zcG9ydExvZ2dlcihbbmV3IENvbnNvbGVUcmFuc3BvcnQoKV0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBuZXcgVHJhbnNwb3J0TG9nZ2VyKHRoaXMudHJhbnNwb3J0cyk7XG4gICAgfVxuICAgIGdldFdyaXRlcigpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMud3JpdGVycy5sZW5ndGggPT0gMFxuICAgICAgICAgICAgPyB0aGlzLm9wdGlvbnMud3JpdGVyIHx8IG5ldyBDb25zb2xlV3JpdGVyKClcbiAgICAgICAgICAgIDogbmV3IFNwbGl0U3RyZWFtV3JpdGVyKHRoaXMud3JpdGVycyk7XG4gICAgfVxufVxuIiwiaW1wb3J0IHsgQ29udGV4dCB9IGZyb20gXCIuLi91dGlscy9Db250ZXh0XCI7XG5leHBvcnQgY2xhc3MgQWJzdHJhY3RDb2xsZWN0b3Ige1xuICAgIGNvbnN0cnVjdG9yKHR5cGUsIGNvbnRleHQgPSBuZXcgQ29udGV4dCh3aW5kb3csIGRvY3VtZW50KSkge1xuICAgICAgICB0aGlzLnR5cGUgPSB0eXBlO1xuICAgICAgICB0aGlzLmNvbnRleHQgPSBjb250ZXh0O1xuICAgIH1cbiAgICBnZXRUeXBlKCkge1xuICAgICAgICByZXR1cm4gdGhpcy50eXBlO1xuICAgIH1cbiAgICBzZXRDb250ZXh0KGNvbnRleHQpIHtcbiAgICAgICAgdGhpcy5jb250ZXh0ID0gY29udGV4dDtcbiAgICB9XG4gICAgZ2V0Q29udGV4dCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY29udGV4dDtcbiAgICB9XG4gICAgZ2V0V2luZG93KCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jb250ZXh0LmdldFdpbmRvdygpO1xuICAgIH1cbiAgICBnZXREb2N1bWVudCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY29udGV4dC5nZXREb2N1bWVudCgpO1xuICAgIH1cbiAgICBhdHRhY2god3JpdGVyLCBsb2cpIHtcbiAgICAgICAgLy8gb3ZlcnJpZGUgaW4gc3ViY2xhc3NcbiAgICB9XG4gICAgLyoqXG4gICAgICogVXNlZCB0byBsb2cgaWYgYSBoYW5kbGVyIGZhaWxzIGl0cyBleGVjdXRpb25cbiAgICAgKiBVc2FnZTogZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsIHRoaXMubG9nV3JhcEhhbmRsZXIoeW91cmhhbmRsZXIsIGxvZ2dlcikpXG4gICAgICogQHBhcmFtIGhhbmRsZXJcbiAgICAgKiBAcGFyYW0gbG9nXG4gICAgICogQHBhcmFtIGhhbmRsZXJBcmdzXG4gICAgICogQHByb3RlY3RlZFxuICAgICAqL1xuICAgIGxvZ1dyYXBIYW5kbGVyKGhhbmRsZXIsIGxvZywgLi4uaGFuZGxlckFyZ3MpIHtcbiAgICAgICAgcmV0dXJuICguLi5hcmdzKSA9PiB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIHJldHVybiBoYW5kbGVyKC4uLmFyZ3MsIC4uLmhhbmRsZXJBcmdzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgbG9nLmVycm9yKGBbJHt0aGlzLmNvbnN0cnVjdG9yLm5hbWV9XSBVbmV4cGVjdGVkIGVycm9yIGR1cmluZyByZXNvbHZlciBleGVjdXRpb246IGAsIGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBVc2VkIHRvIGV4ZWN1dGUgcmVzb2x2ZXIgZnVuY3Rpb25zLlxuICAgICAqIExvZ3MgYSBkZWJ1ZyBtZXNzYWdlIGlmIHRoZSB2YWx1ZSBpcyB1bmRlZmluZWQgb3IgbG9ncyBhbiBlcnJvciBpZiBhbiBleGNlcHRpb24gaXMgdGhyb3duIGJ5IHRoZSByZXNvbHZlclxuICAgICAqIEBwYXJhbSByZXNvbHZlciBBIHJlc29sdmVyIGZ1bmN0aW9uXG4gICAgICogQHBhcmFtIGxvZyB0aGUgbG9nZ2VyXG4gICAgICogQHBhcmFtIHJlc29sdmVyQXJncyBhcmd1bWVudHMgdG8gYmUgcGFzc2VkIHRvIHRoZSByZXNvbHZlciBmdW5jdGlvblxuICAgICAqIEBwcm90ZWN0ZWRcbiAgICAgKi9cbiAgICByZXNvbHZlKHJlc29sdmVyLCBsb2csIC4uLnJlc29sdmVyQXJncykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgaWYgKHJlc29sdmVyKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgdmFsID0gcmVzb2x2ZXIoLi4ucmVzb2x2ZXJBcmdzKTtcbiAgICAgICAgICAgICAgICBpZiAodmFsID09IHZvaWQgMClcbiAgICAgICAgICAgICAgICAgICAgbG9nLmRlYnVnKFwiUmVzb2x2ZXIgcmV0dXJuZWQgbm8gdmFsdWUuXCIsIHJlc29sdmVyKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdmFsO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGNhdGNoIChlKSB7XG4gICAgICAgICAgICBsb2cuZXJyb3IoYFske3RoaXMuY29uc3RydWN0b3IubmFtZX1dIFVuZXhwZWN0ZWQgZXJyb3IgZHVyaW5nIHJlc29sdmVyIGV4ZWN1dGlvbjogYCwgZSk7XG4gICAgICAgIH1cbiAgICB9XG59XG4iLCJpbXBvcnQgeyBTZW50aW5lbCB9IGZyb20gXCIuLi91dGlscy9TZW50aW5lbFwiO1xuaW1wb3J0IHsgQWJzdHJhY3RDb2xsZWN0b3IgfSBmcm9tIFwiLi9BYnN0cmFjdENvbGxlY3RvclwiO1xuaW1wb3J0IHsgVHJhaWxUeXBlIH0gZnJvbSBcIi4uL3F1ZXJ5L1RyYWlsVHlwZVwiO1xuLyoqXG4gKiBDb2xsZWN0IGNsaWNrcyBvbiBlbGVtZW50cyBtYXRjaGluZyBhIHF1ZXJ5IHNlbGVjdG9yLiBIYW5kbGVzIGJvdGggRE9NIGVsZW1lbnRzXG4gKiBwcmVzZW50IGluIHRoZSBET00gYW5kIGVsZW1lbnRzIGluc2VydGVkIGFmdGVyIHRoZSBwYWdlIGxvYWQgLyBjb2xsZWN0b3IgY29uc3RydWN0aW9uLlxuICpcbiAqIFdoZW4gYSBjbGljayBvY2N1cnMsIGEgZnVuY3Rpb24gcHJvdmlkZWQgYXQgY29uc3RydWN0aW9uIHRpbWUgZ2V0IGludm9rZWQgdG8gY29sbGVjdCBkYXRhIHBvaW50c1xuICogZnJvbSB0aGUgZWxlbWVudC5cbiAqL1xuZXhwb3J0IGNsYXNzIEFzc29jaWF0ZWRQcm9kdWN0Q29sbGVjdG9yIGV4dGVuZHMgQWJzdHJhY3RDb2xsZWN0b3Ige1xuICAgIC8qKlxuICAgICAqIENvbnN0cnVjdCBhIGNsaWNrIGNvbGxlY3RvclxuICAgICAqXG4gICAgICogQGNvbnN0cnVjdG9yXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHNlbGVjdG9yRXhwcmVzc2lvbiAtIERvY3VtZW50IHF1ZXJ5IHNlbGVjdG9yIGlkZW50aWZ5aW5nIHRoZSBlbGVtZW50cyB0byBhdHRhY2ggdG9cbiAgICAgKiBAcGFyYW0gbWFpblByb2R1Y3RJZFxuICAgICAqIEBwYXJhbSByZXNvbHZlcnNcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihzZWxlY3RvckV4cHJlc3Npb24sIG1haW5Qcm9kdWN0SWQsIHJlc29sdmVycykge1xuICAgICAgICBzdXBlcihcImFzc29jaWF0ZWQtcHJvZHVjdFwiKTtcbiAgICAgICAgdGhpcy5tYWluUHJvZHVjdElkID0gbWFpblByb2R1Y3RJZDtcbiAgICAgICAgdGhpcy5zZWxlY3RvckV4cHJlc3Npb24gPSBzZWxlY3RvckV4cHJlc3Npb247XG4gICAgICAgIHRoaXMuaWRSZXNvbHZlciA9IHJlc29sdmVycy5pZFJlc29sdmVyO1xuICAgICAgICB0aGlzLnBvc2l0aW9uUmVzb2x2ZXIgPSByZXNvbHZlcnMucG9zaXRpb25SZXNvbHZlcjtcbiAgICAgICAgdGhpcy5wcmljZVJlc29sdmVyID0gcmVzb2x2ZXJzLnByaWNlUmVzb2x2ZXI7XG4gICAgICAgIHRoaXMudHJhaWwgPSByZXNvbHZlcnMudHJhaWw7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEFkZCBjbGljayBldmVudCBsaXN0ZW5lcnMgdG8gdGhlIGlkZW50aWZpZWQgZWxlbWVudHMsIHdyaXRlIHRoZSBkYXRhXG4gICAgICogd2hlbiB0aGUgZXZlbnQgb2NjdXJzXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gd3JpdGVyIC0gVGhlIHdyaXRlciB0byBzZW5kIHRoZSBkYXRhIHRvXG4gICAgICogQHBhcmFtIGxvZ1xuICAgICAqL1xuICAgIGF0dGFjaCh3cml0ZXIsIGxvZykge1xuICAgICAgICBjb25zdCBjb2xsZWN0ID0gZWxlbWVudCA9PiB7XG4gICAgICAgICAgICBjb25zdCBpZCA9IHRoaXMucmVzb2x2ZSh0aGlzLmlkUmVzb2x2ZXIsIGxvZywgZWxlbWVudCk7XG4gICAgICAgICAgICBpZiAoaWQpIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy50cmFpbCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBGaW5kIG91dCB0aGUgcXVlcnkgc291cmNlIG9mIHRoZSBtYWluIHByb2R1Y3QuIE5vdGUgdGhhdCBkZXNwaXRlIGJlaW5nIGFcbiAgICAgICAgICAgICAgICAgICAgLy8gXCJtYWluXCIgcHJvZHVjdCwgaXQgY291bGQgYmUgYSAybmQgb3IgM3JkLCA0dGggbGV2ZWwgb2YgYXNzb2NpYXRlZCBwcm9kdWN0IGJyb3dzaW5nXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHByZXZpb3VzVHJhaWwgPSB0aGlzLnRyYWlsLmZldGNoKHRoaXMubWFpblByb2R1Y3RJZCk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChwcmV2aW91c1RyYWlsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVcG9uIGEgZm9sbG93LXVwIGV2ZW50IGZvciB0aGlzIHByb2R1Y3QgKGV4LiBiYXNrZXQpLCB3ZSB3b3VsZCBwaWNrIHRoaXMgdHJhaWxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMudHJhaWwucmVnaXN0ZXIoaWQsIFRyYWlsVHlwZS5Bc3NvY2lhdGVkLCBwcmV2aW91c1RyYWlsLnF1ZXJ5KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICBpZCxcbiAgICAgICAgICAgICAgICAgICAgcG9zaXRpb246IHRoaXMucmVzb2x2ZSh0aGlzLnBvc2l0aW9uUmVzb2x2ZXIsIGxvZywgZWxlbWVudCksXG4gICAgICAgICAgICAgICAgICAgIHByaWNlOiB0aGlzLnJlc29sdmUodGhpcy5wcmljZVJlc29sdmVyLCBsb2csIGVsZW1lbnQpXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgaGFuZGxlciA9IGVsID0+IHtcbiAgICAgICAgICAgIGVsLmFkZEV2ZW50TGlzdGVuZXIoXCJjbGlja1wiLCB0aGlzLmxvZ1dyYXBIYW5kbGVyKGV2ID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBwYXlsb2FkID0gY29sbGVjdChlbCk7XG4gICAgICAgICAgICAgICAgaWYgKHBheWxvYWQpIHtcbiAgICAgICAgICAgICAgICAgICAgd3JpdGVyLndyaXRlKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIFwidHlwZVwiOiB0aGlzLmdldFR5cGUoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIC4uLnBheWxvYWRcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSwgbG9nKSk7XG4gICAgICAgIH07XG4gICAgICAgIG5ldyBTZW50aW5lbCh0aGlzLmdldERvY3VtZW50KCkpLm9uKHRoaXMuc2VsZWN0b3JFeHByZXNzaW9uLCBoYW5kbGVyKTtcbiAgICB9XG59XG4iLCJpbXBvcnQgeyBDbGlja0NvbGxlY3RvciB9IGZyb20gXCIuL0NsaWNrQ29sbGVjdG9yXCI7XG5pbXBvcnQgeyBMaXN0ZW5lclR5cGUgfSBmcm9tIFwiLi4vdXRpbHMvTGlzdGVuZXJUeXBlXCI7XG4vKipcbiAqIENvbGxlY3QgaWQgYW5kIHByaWNlIGlmIGFuIGl0ZW0gd2FzIGFkZCBpbnRvIHRoZSBiYXNrZXRcbiAqL1xuZXhwb3J0IGNsYXNzIEJhc2tldENsaWNrQ29sbGVjdG9yIGV4dGVuZHMgQ2xpY2tDb2xsZWN0b3Ige1xuICAgIGNvbnN0cnVjdG9yKHNlbGVjdG9yLCBpZFJlc29sdmVyLCBwcmljZVJlc29sdmVyLCBsaXN0ZW5lclR5cGUgPSBMaXN0ZW5lclR5cGUuU2VudGluZWwpIHtcbiAgICAgICAgc3VwZXIoc2VsZWN0b3IsIFwiYmFza2V0XCIsIGxpc3RlbmVyVHlwZSk7XG4gICAgICAgIHRoaXMuaWRSZXNvbHZlciA9IGlkUmVzb2x2ZXI7XG4gICAgICAgIHRoaXMucHJpY2VSZXNvbHZlciA9IHByaWNlUmVzb2x2ZXI7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIENvbGxlY3QgdGhlIHByb2R1Y3QgY2xpY2sgaW5mb3JtYXRpb24gZnJvbSB0aGUgZWxlbWVudFxuICAgICAqIEBvdmVycmlkZVxuICAgICAqL1xuICAgIGNvbGxlY3QoZWxlbWVudCwgZXZlbnQsIGxvZykge1xuICAgICAgICBjb25zdCBpZCA9IHRoaXMucmVzb2x2ZSh0aGlzLmlkUmVzb2x2ZXIsIGxvZywgZWxlbWVudCwgZXZlbnQpO1xuICAgICAgICBpZiAoaWQpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgaWQsXG4gICAgICAgICAgICAgICAgcHJpY2U6IHRoaXMucmVzb2x2ZSh0aGlzLnByaWNlUmVzb2x2ZXIsIGxvZywgZWxlbWVudCwgZXZlbnQpXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgfVxufVxuIiwiaW1wb3J0IHsgQWJzdHJhY3RDb2xsZWN0b3IgfSBmcm9tIFwiLi9BYnN0cmFjdENvbGxlY3RvclwiO1xuLyoqXG4gKiBDb2xsZWN0IGJhc2ljIGJyb3dzZXIgaW5mb3JtYXRpb24uIE5vdGUgdGhhdCBkZXBlbmRpbmcgb24gaG93IHlvdSB1c2UgdGhpcyB5b3UgbWF5XG4gKiBuZWVkIHRvIGNvbnN1bHQgdGhlIEdEUFIgZ3VpZGVsaW5lc1xuICovXG5leHBvcnQgY2xhc3MgQnJvd3NlckNvbGxlY3RvciBleHRlbmRzIEFic3RyYWN0Q29sbGVjdG9yIHtcbiAgICBjb25zdHJ1Y3RvcihvcHRpb25zID0geyByZWNvcmRVcmw6IHRydWUsIHJlY29yZFJlZmVycmVyOiB0cnVlLCByZWNvcmRMYW5ndWFnZTogZmFsc2UgfSkge1xuICAgICAgICBzdXBlcihcImJyb3dzZXJcIik7XG4gICAgICAgIHRoaXMucmVjb3JkVXJsID0gb3B0aW9ucy5yZWNvcmRVcmwgfHwgZmFsc2U7XG4gICAgICAgIHRoaXMucmVjb3JkUmVmZXJyZXIgPSBvcHRpb25zLnJlY29yZFJlZmVycmVyIHx8IGZhbHNlO1xuICAgICAgICB0aGlzLnJlY29yZExhbmd1YWdlID0gb3B0aW9ucy5yZWNvcmRMYW5ndWFnZSB8fCBmYWxzZTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogQXR0YWNoIGEgd3JpdGVyLCBub3RlIHRoYXQgdGhpcyBjb2xsZWN0b3IgaXMgbm90IGFzeW5jaHJvbm91cyBhbmQgd2lsbCB3cml0ZVxuICAgICAqIHRoZSBkYXRhIGltbWVkaWF0ZWxseVxuICAgICAqXG4gICAgICogQHBhcmFtIHtvYmplY3R9IHdyaXRlciAtIFRoZSB3cml0ZXIgdG8gc2VuZCB0aGUgZGF0YSB0b1xuICAgICAqL1xuICAgIGF0dGFjaCh3cml0ZXIpIHtcbiAgICAgICAgY29uc3Qgd2luID0gdGhpcy5nZXRXaW5kb3coKTtcbiAgICAgICAgY29uc3QgZG9jID0gdGhpcy5nZXREb2N1bWVudCgpO1xuICAgICAgICBjb25zdCBkYXRhID0ge1xuICAgICAgICAgICAgdHlwZTogdGhpcy5nZXRUeXBlKCksXG4gICAgICAgICAgICB0b3VjaDogKCdvbnRvdWNoc3RhcnQnIGluIHdpbmRvdykgfHwgKG5hdmlnYXRvci5tYXhUb3VjaFBvaW50cyA+IDApXG4gICAgICAgIH07XG4gICAgICAgIGlmICh0aGlzLnJlY29yZExhbmd1YWdlKVxuICAgICAgICAgICAgZGF0YS5sYW5nID0gd2luLm5hdmlnYXRvci5sYW5ndWFnZTtcbiAgICAgICAgaWYgKHRoaXMucmVjb3JkVXJsKVxuICAgICAgICAgICAgZGF0YS51cmwgPSB3aW4ubG9jYXRpb24uaHJlZjtcbiAgICAgICAgaWYgKHRoaXMucmVjb3JkUmVmZXJyZXIpXG4gICAgICAgICAgICBkYXRhLnJlZiA9IGRvYy5yZWZlcnJlcjtcbiAgICAgICAgd3JpdGVyLndyaXRlKGRhdGEpO1xuICAgIH1cbn1cbiIsImltcG9ydCB7IEFic3RyYWN0Q29sbGVjdG9yIH0gZnJvbSBcIi4vQWJzdHJhY3RDb2xsZWN0b3JcIjtcbmltcG9ydCB7IFNlbnRpbmVsIH0gZnJvbSBcIi4uL3V0aWxzL1NlbnRpbmVsXCI7XG5pbXBvcnQgeyBMaXN0ZW5lclR5cGUgfSBmcm9tIFwiLi4vdXRpbHMvTGlzdGVuZXJUeXBlXCI7XG4vKipcbiAqIFRyaWdnZXJlZCBieSBhIGNsaWNrU2VsZWN0b3IsIHRoZSBjb2xsZWN0b3Igd2lsbCBmaXJlIHRoZSBjb250ZW50U2VsZWN0b3IgdG8gc2VsZWN0IGVsZW1lbnRzIHRvIGNvbGxlY3RcbiAqIGluZm9ybWF0aW9uIGZyb20gYW5kIHdyaXRlIHRvIHRoZSBjb2xsZWN0b3Igd3JpdGVyXG4gKi9cbmV4cG9ydCBjbGFzcyBDaGVja291dENsaWNrQ29sbGVjdG9yIGV4dGVuZHMgQWJzdHJhY3RDb2xsZWN0b3Ige1xuICAgIGNvbnN0cnVjdG9yKGNsaWNrU2VsZWN0b3IsIGNvbnRlbnRTZWxlY3RvciwgaWRSZXNvbHZlciwgcHJpY2VSZXNvbHZlciwgYW1vdW50UmVzb2x2ZXIsIGxpc3RlbmVyVHlwZSA9IExpc3RlbmVyVHlwZS5TZW50aW5lbCkge1xuICAgICAgICBzdXBlcihcImNoZWNrb3V0XCIpO1xuICAgICAgICB0aGlzLmNsaWNrU2VsZWN0b3IgPSBjbGlja1NlbGVjdG9yO1xuICAgICAgICB0aGlzLmNvbnRlbnRTZWxlY3RvciA9IGNvbnRlbnRTZWxlY3RvcjtcbiAgICAgICAgdGhpcy5pZFJlc29sdmVyID0gaWRSZXNvbHZlcjtcbiAgICAgICAgdGhpcy5wcmljZVJlc29sdmVyID0gcHJpY2VSZXNvbHZlcjtcbiAgICAgICAgdGhpcy5hbW91bnRSZXNvbHZlciA9IGFtb3VudFJlc29sdmVyO1xuICAgICAgICB0aGlzLmxpc3RlbmVyVHlwZSA9IGxpc3RlbmVyVHlwZTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogQWRkIGNsaWNrIGV2ZW50IGxpc3RlbmVycyB0byB0aGUgaWRlbnRpZmllZCBlbGVtZW50cywgd3JpdGUgdGhlIGRhdGFcbiAgICAgKiB3aGVuIHRoZSBldmVudCBvY2N1cnNcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSB3cml0ZXIgLSBUaGUgd3JpdGVyIHRvIHNlbmQgdGhlIGRhdGEgdG9cbiAgICAgKiBAcGFyYW0gbG9nXG4gICAgICovXG4gICAgYXR0YWNoKHdyaXRlciwgbG9nKSB7XG4gICAgICAgIGNvbnN0IGRvYyA9IHRoaXMuZ2V0RG9jdW1lbnQoKTtcbiAgICAgICAgLy8gQWN0aXZhdGVzIG9uIGNsaWNrIG9mIHRoZSBlbGVtZW50IHNlbGVjdGVkIHVzaW5nIHRoZSBjbGlja1NlbGVjdG9yXG4gICAgICAgIGNvbnN0IGhhbmRsZXIgPSAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGVsZW1lbnRzID0gZG9jLnF1ZXJ5U2VsZWN0b3JBbGwodGhpcy5jb250ZW50U2VsZWN0b3IpO1xuICAgICAgICAgICAgZWxlbWVudHMuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBpZCA9IHRoaXMucmVzb2x2ZSh0aGlzLmlkUmVzb2x2ZXIsIGxvZywgZWxlbWVudCwgZXZlbnQpO1xuICAgICAgICAgICAgICAgIGlmIChpZCkge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBkYXRhID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWQsXG4gICAgICAgICAgICAgICAgICAgICAgICBwcmljZTogdGhpcy5yZXNvbHZlKHRoaXMucHJpY2VSZXNvbHZlciwgbG9nLCBlbGVtZW50LCBldmVudCksXG4gICAgICAgICAgICAgICAgICAgICAgICBhbW91bnQ6IHRoaXMucmVzb2x2ZSh0aGlzLmFtb3VudFJlc29sdmVyLCBsb2csIGVsZW1lbnQsIGV2ZW50KVxuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICAvLyBXZSB3cml0ZSBlYWNoIGl0ZW0gc2VwYXJhdGVseSAtIHRoZXkgbWF5IGJlIGNvbWluZyBmcm9tIGRpZmZlcmVudCBxdWVyaWVzXG4gICAgICAgICAgICAgICAgICAgIC8vIHRodXMgd2hlbiB3ZSB0cnkgdG8gcmVzb2x2ZSB0aGUgdHJhaWwgZm9yIGVhY2ggb2YgdGhlbSB3ZSBuZWVkIHRvIGhhdmUgdGhlbVxuICAgICAgICAgICAgICAgICAgICAvLyBhcyBzZXBhcmF0ZSByZWNvcmRzXG4gICAgICAgICAgICAgICAgICAgIHdyaXRlci53cml0ZSh7XG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlOiB0aGlzLmdldFR5cGUoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIC4uLmRhdGFcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG4gICAgICAgIC8vIFRoZSBTZW50aWVsIGxpYnJhcnkgdXNlcyBhbmltYXRpb25zdGFydCBldmVudCBsaXN0ZW5lcnMgd2hpY2ggbWF5IGludGVyZmVyZSB3aXRoXG4gICAgICAgIC8vIGFuaW1hdGlvbnMgYXR0YWNoZWQgb24gZWxlbWVuZXRzLiBUaGUgaW4tbGlicmFyeSBwcm92aWRlZCB3b3JrYXJvdW5kIG1lY2hhbmlzbSBkb2VzIG5vdCB3b3JrXG4gICAgICAgIC8vIDEwMCUsIHRodXMgd2UgcHJvdmlkZSB0aGUgbGlzdGVuZXJUeXBlIGNob2ljZSBiZWxvdy4gVGhlIHRyYWRlb2Zmc1xuICAgICAgICAvLyBcImRvbVwiIC0gbm8gYW5pbWF0aW9uIGludGVyZmVyZW5jZSwgb25seSBvbmNsaWNrIGF0dGFjaGVkLCBidXQgZG9lcyBub3QgaGFuZGxlIGVsZW1lbnRzIGluc2VydGVkIGluIHRoZSBET00gbGF0ZXJcbiAgICAgICAgLy8gXCJzZW50aW5lbCAoZGVmYXVsdClcIiAtIHdvcmtzIG9uIGVsZW1lbnRzIGluc2VydGVkIGluIHRoZSBET00gYW55dGltZSwgYnV0IGludGVyZmVyZXMgd2l0aCBDU1MgYW5pbWF0aW9ucyBvbiB0aGVzZSBlbGVtZW50c1xuICAgICAgICBpZiAodGhpcy5saXN0ZW5lclR5cGUgPT09IExpc3RlbmVyVHlwZS5Eb20pIHtcbiAgICAgICAgICAgIGNvbnN0IG5vZGVMaXN0ID0gZG9jLnF1ZXJ5U2VsZWN0b3JBbGwodGhpcy5jbGlja1NlbGVjdG9yKTtcbiAgICAgICAgICAgIG5vZGVMaXN0LmZvckVhY2goKGVsKSA9PiBlbC5hZGRFdmVudExpc3RlbmVyKFwiY2xpY2tcIiwgdGhpcy5sb2dXcmFwSGFuZGxlcihoYW5kbGVyLCBsb2cpKSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBzZW50aW5lbCA9IG5ldyBTZW50aW5lbCh0aGlzLmdldERvY3VtZW50KCkpO1xuICAgICAgICAgICAgc2VudGluZWwub24odGhpcy5jbGlja1NlbGVjdG9yLCBlbCA9PiBlbC5hZGRFdmVudExpc3RlbmVyKFwiY2xpY2tcIiwgdGhpcy5sb2dXcmFwSGFuZGxlcihoYW5kbGVyLCBsb2cpKSk7XG4gICAgICAgIH1cbiAgICB9XG59XG4iLCJpbXBvcnQgeyBBYnN0cmFjdENvbGxlY3RvciB9IGZyb20gXCIuL0Fic3RyYWN0Q29sbGVjdG9yXCI7XG5pbXBvcnQgeyBTZW50aW5lbCB9IGZyb20gXCIuLi91dGlscy9TZW50aW5lbFwiO1xuaW1wb3J0IHsgTGlzdGVuZXJUeXBlIH0gZnJvbSBcIi4uL3V0aWxzL0xpc3RlbmVyVHlwZVwiO1xuLyoqXG4gKiBDb2xsZWN0IGNsaWNrcyBvbiBlbGVtZW50cyBtYXRjaGluZyBhIHF1ZXJ5IHNlbGVjdG9yLiBIYW5kbGVzIGJvdGggRE9NIGVsZW1lbnRzXG4gKiBwcmVzZW50IGluIHRoZSBET00gYW5kIGVsZW1lbnRzIGluc2VydGVkIGFmdGVyIHRoZSBwYWdlIGxvYWQgLyBjb2xsZWN0b3IgY29uc3RydWN0aW9uLlxuICpcbiAqIFdoZW4gYSBjbGljayBvY2N1cnMsIGEgZnVuY3Rpb24gcHJvdmlkZWQgYXQgY29uc3RydWN0aW9uIHRpbWUgZ2V0IGludm9rZWQgdG8gY29sbGVjdCBkYXRhIHBvaW50c1xuICogZnJvbSB0aGUgZWxlbWVudC5cbiAqL1xuZXhwb3J0IGNsYXNzIENsaWNrQ29sbGVjdG9yIGV4dGVuZHMgQWJzdHJhY3RDb2xsZWN0b3Ige1xuICAgIC8qKlxuICAgICAqIENvbnN0cnVjdCBhIGNsaWNrIGNvbGxlY3RvclxuICAgICAqXG4gICAgICogQGNvbnN0cnVjdG9yXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHNlbGVjdG9yRXhwcmVzc2lvbiAtIERvY3VtZW50IHF1ZXJ5IHNlbGVjdG9yIGlkZW50aWZ5aW5nIHRoZSBlbGVtZW50cyB0byBhdHRhY2ggdG9cbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSB0eXBlIE9GIGVsZW1lbnQgY2xpY2sgdG8gcmVwb3J0XG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGxpc3RlbmVyVHlwZSAtIFdoZXRoZXIgdGhlIGxpc3RlbmVyIHNob3VsZCBiZSBhIGRvbSBvciBzZW50aW5lbCBsaXN0ZW5lclxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKHNlbGVjdG9yRXhwcmVzc2lvbiwgdHlwZSA9IFwiY2xpY2tcIiwgbGlzdGVuZXJUeXBlID0gTGlzdGVuZXJUeXBlLlNlbnRpbmVsKSB7XG4gICAgICAgIHN1cGVyKHR5cGUpO1xuICAgICAgICB0aGlzLnNlbGVjdG9yRXhwcmVzc2lvbiA9IHNlbGVjdG9yRXhwcmVzc2lvbjtcbiAgICAgICAgdGhpcy5saXN0ZW5lclR5cGUgPSBsaXN0ZW5lclR5cGU7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEFic3RyYWN0IGNvbGxlY3Rpb24gbWV0aG9kLCBtdXN0IGJlIG92ZXJyaWRkZW4gaW4gdGhlIHN1YmNsYXNzZXNcbiAgICAgKiBAYWJzdHJhY3RcbiAgICAgKi9cbiAgICBjb2xsZWN0KGVsZW1lbnQsIGV2ZW50LCBsb2cpIHtcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgLyoqXG4gICAgICogQWRkIGNsaWNrIGV2ZW50IGxpc3RlbmVycyB0byB0aGUgaWRlbnRpZmllZCBlbGVtZW50cywgd3JpdGUgdGhlIGRhdGFcbiAgICAgKiB3aGVuIHRoZSBldmVudCBvY2N1cnNcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSB3cml0ZXIgLSBUaGUgd3JpdGVyIHRvIHNlbmQgdGhlIGRhdGEgdG9cbiAgICAgKiBAcGFyYW0gbG9nXG4gICAgICovXG4gICAgYXR0YWNoKHdyaXRlciwgbG9nKSB7XG4gICAgICAgIGNvbnN0IGhhbmRsZXIgPSAoZXZlbnQsIGVsZW1lbnQpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHBheWxvYWQgPSB0aGlzLmNvbGxlY3QoZWxlbWVudCwgZXZlbnQsIGxvZyk7XG4gICAgICAgICAgICBpZiAocGF5bG9hZCkge1xuICAgICAgICAgICAgICAgIHdyaXRlci53cml0ZSh7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6IHRoaXMudHlwZSxcbiAgICAgICAgICAgICAgICAgICAgLi4ucGF5bG9hZFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICAvLyBUaGUgU2VudGllbCBsaWJyYXJ5IHVzZXMgYW5pbWF0aW9uc3RhcnQgZXZlbnQgbGlzdGVuZXJzIHdoaWNoIG1heSBpbnRlcmZlcmUgd2l0aFxuICAgICAgICAvLyBhbmltYXRpb25zIGF0dGFjaGVkIG9uIGVsZW1lbmV0cy4gVGhlIGluLWxpYnJhcnkgcHJvdmlkZWQgd29ya2Fyb3VuZCBtZWNoYW5pc20gZG9lcyBub3Qgd29ya1xuICAgICAgICAvLyAxMDAlLCB0aHVzIHdlIHByb3ZpZGUgdGhlIGxpc3RlbmVyVHlwZSBjaG9pY2UgYmVsb3cuIFRoZSB0cmFkZW9mZnNcbiAgICAgICAgLy8gXCJkb21cIiAtIG5vIGFuaW1hdGlvbiBpbnRlcmZlcmVuY2UsIG9ubHkgb25jbGljayBhdHRhY2hlZCwgYnV0IGRvZXMgbm90IGhhbmRsZSBlbGVtZW50cyBpbnNlcnRlZCBpbiB0aGUgRE9NIGxhdGVyXG4gICAgICAgIC8vIFwic2VudGluZWwgKGRlZmF1bHQpXCIgLSB3b3JrcyBvbiBlbGVtZW50cyBpbnNlcnRlZCBpbiB0aGUgRE9NIGFueXRpbWUsIGJ1dCBpbnRlcmZlcmVzIHdpdGggQ1NTIGFuaW1hdGlvbnMgb24gdGhlc2UgZWxlbWVudHNcbiAgICAgICAgaWYgKHRoaXMubGlzdGVuZXJUeXBlID09PSBMaXN0ZW5lclR5cGUuRG9tKSB7XG4gICAgICAgICAgICBjb25zdCBub2RlTGlzdCA9IHRoaXMuZ2V0RG9jdW1lbnQoKS5xdWVyeVNlbGVjdG9yQWxsKHRoaXMuc2VsZWN0b3JFeHByZXNzaW9uKTtcbiAgICAgICAgICAgIG5vZGVMaXN0LmZvckVhY2goKGVsKSA9PiBlbC5hZGRFdmVudExpc3RlbmVyKFwiY2xpY2tcIiwgdGhpcy5sb2dXcmFwSGFuZGxlcihoYW5kbGVyLCBsb2csIGVsKSkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgY29uc3Qgc2VudGluZWwgPSBuZXcgU2VudGluZWwodGhpcy5nZXREb2N1bWVudCgpKTtcbiAgICAgICAgICAgIHNlbnRpbmVsLm9uKHRoaXMuc2VsZWN0b3JFeHByZXNzaW9uLCBlbCA9PiBlbC5hZGRFdmVudExpc3RlbmVyKFwiY2xpY2tcIiwgdGhpcy5sb2dXcmFwSGFuZGxlcihoYW5kbGVyLCBsb2csIGVsKSkpO1xuICAgICAgICB9XG4gICAgfVxufVxuIiwiaW1wb3J0IHsgTGlzdGVuZXJUeXBlIH0gZnJvbSBcIi4uL3V0aWxzL0xpc3RlbmVyVHlwZVwiO1xuaW1wb3J0IHsgU2VudGluZWwgfSBmcm9tIFwiLi4vdXRpbHMvU2VudGluZWxcIjtcbmltcG9ydCB7IFdyaXRlclJlc29sdmVyQ29sbGVjdG9yIH0gZnJvbSBcIi4vV3JpdGVyUmVzb2x2ZXJDb2xsZWN0b3JcIjtcbi8qKlxuICogRXh0ZW5kcyBXcml0ZXJSZXNvbHZlckNvbGxlY3RvciBhbmQgaW52b2tlcyB0aGUgV3JpdGVyUmVzb2x2ZXJDb2xsZWN0b3IjYXR0YWNoKHdyaXRlciwgbG9nKVxuICogd2hlbiBhIGNsaWNrIG9uIGFuIGVsZW1lbnQgZm9yIHRoZSBwcm92aWRlZCBcInNlbGVjdG9yRXhwcmVzc2lvblwiIG9jY3Vyc1xuICovXG5leHBvcnQgY2xhc3MgQ2xpY2tXcml0ZXJSZXNvbHZlckNvbGxlY3RvciBleHRlbmRzIFdyaXRlclJlc29sdmVyQ29sbGVjdG9yIHtcbiAgICAvKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSBzZWxlY3RvckV4cHJlc3Npb24gdGhlIGNzcyBleHByZXNzaW9uIHRvIHF1ZXJ5IGZvciBvdGhlciBlbGVtZW50c1xuICAgICAqIEBwYXJhbSB0eXBlIHRoZSB0eXBlIG9mIHRoZSBldmVudFxuICAgICAqIEBwYXJhbSByZXNvbHZlciBhIHtXcml0ZXJSZXNvbHZlcn0gd2hpY2ggd2lsbCBiZSBleGVjdXRlZCBhcyBzb29uIGFzIGFuIGVsZW1lbnQgbWF0Y2hpbmcgdGhlIHNlbGVjdG9yRXhwcmVzc2lvbiBpcyBjbGlja2VkXG4gICAgICogQHBhcmFtIGxpc3RlbmVyVHlwZSB7TGlzdGVuZXJUeXBlfVxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKHNlbGVjdG9yRXhwcmVzc2lvbiwgdHlwZSwgcmVzb2x2ZXIsIGxpc3RlbmVyVHlwZSA9IExpc3RlbmVyVHlwZS5TZW50aW5lbCkge1xuICAgICAgICBzdXBlcih0eXBlLCByZXNvbHZlcik7XG4gICAgICAgIHRoaXMuc2VsZWN0b3JFeHByZXNzaW9uID0gc2VsZWN0b3JFeHByZXNzaW9uO1xuICAgICAgICB0aGlzLmxpc3RlbmVyVHlwZSA9IGxpc3RlbmVyVHlwZTtcbiAgICB9XG4gICAgYXR0YWNoKHdyaXRlciwgbG9nKSB7XG4gICAgICAgIGNvbnN0IGhhbmRsZXIgPSAoZWwsIGV2ZW50KSA9PiB7XG4gICAgICAgICAgICBzdXBlci5hdHRhY2god3JpdGVyLCBsb2cpO1xuICAgICAgICB9O1xuICAgICAgICBpZiAodGhpcy5saXN0ZW5lclR5cGUgPT09IExpc3RlbmVyVHlwZS5Eb20pIHtcbiAgICAgICAgICAgIGNvbnN0IG5vZGVMaXN0ID0gdGhpcy5nZXREb2N1bWVudCgpLnF1ZXJ5U2VsZWN0b3JBbGwodGhpcy5zZWxlY3RvckV4cHJlc3Npb24pO1xuICAgICAgICAgICAgbm9kZUxpc3QuZm9yRWFjaChlbCA9PiBlbC5hZGRFdmVudExpc3RlbmVyKFwiY2xpY2tcIiwgZXYgPT4gdGhpcy5sb2dXcmFwSGFuZGxlcihoYW5kbGVyLCBsb2csIGVsLCBldikoKSkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgY29uc3Qgc2VudGluZWwgPSBuZXcgU2VudGluZWwodGhpcy5nZXREb2N1bWVudCgpKTtcbiAgICAgICAgICAgIHNlbnRpbmVsLm9uKHRoaXMuc2VsZWN0b3JFeHByZXNzaW9uLCBlbCA9PiBlbC5hZGRFdmVudExpc3RlbmVyKFwiY2xpY2tcIiwgZXYgPT4gdGhpcy5sb2dXcmFwSGFuZGxlcihoYW5kbGVyLCBsb2csIGVsLCBldikoKSkpO1xuICAgICAgICB9XG4gICAgfVxufVxuIiwiaW1wb3J0IHsgQ2xpY2tDb2xsZWN0b3IgfSBmcm9tIFwiLi9DbGlja0NvbGxlY3RvclwiO1xuLyoqXG4gKiBDbGlja0NvbGxlY3RvciBlbWl0dGluZyBcImZpbHRlclwiIGV2ZW50cywgYXR0YWNoIHRvIGZhY2V0IGxpbmtzXG4gKi9cbmV4cG9ydCBjbGFzcyBGaWx0ZXJDbGlja0NvbGxlY3RvciBleHRlbmRzIENsaWNrQ29sbGVjdG9yIHtcbiAgICBjb25zdHJ1Y3RvcihzZWxlY3RvciwgY29sbGVjdG9yKSB7XG4gICAgICAgIHN1cGVyKHNlbGVjdG9yLCBcImZpbHRlclwiKTtcbiAgICAgICAgdGhpcy5yZXNvbHZlciA9IGNvbGxlY3RvcjtcbiAgICB9XG4gICAgLyoqXG4gICAgICogQ29sbGVjdCB0aGUgcHJvZHVjdCBjbGljayBpbmZvcm1hdGlvbiBmcm9tIHRoZSBlbGVtZW50XG4gICAgICogQG92ZXJyaWRlXG4gICAgICovXG4gICAgY29sbGVjdChlbGVtZW50LCBldmVudCwgbG9nKSB7XG4gICAgICAgIHJldHVybiB7IHF1ZXJ5OiB0aGlzLnJlc29sdmUodGhpcy5yZXNvbHZlciwgbG9nLCBlbGVtZW50LCBldmVudCkgfTtcbiAgICB9XG59XG4iLCJpbXBvcnQgeyBXcml0ZXJSZXNvbHZlckNvbGxlY3RvciB9IGZyb20gXCIuL1dyaXRlclJlc29sdmVyQ29sbGVjdG9yXCI7XG4vKipcbiAqIFRyaWdnZXJlZCB3aGVuIHRoZSBjbGllbnQgaGFzIHRyaWdnZXJlZC9maXJlZCBhIHNlYXJjaFxuICovXG5leHBvcnQgY2xhc3MgRmlyZWRTZWFyY2hDb2xsZWN0b3IgZXh0ZW5kcyBXcml0ZXJSZXNvbHZlckNvbGxlY3RvciB7XG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0IGZpcmVkIHNlYXJjaCBjb2xsZWN0b3JcbiAgICAgKlxuICAgICAqIEBjb25zdHJ1Y3RvclxuICAgICAqIEBwYXJhbSB7ZnVuY3Rpb259IHJlc29sdmVyIC0gRnVuY3Rpb24gdGhhdCB0cmlnZ2VycyB0aGUgd3JpdGluZy4gV2UgY2FuJ3QgYWx3YXlzIGRldGVybWluZSB3aGVuIHNlYXJjaCB0cmlnZ2VycywgbGVhdmUgdG8gdGhlIGltcGxlbWVudGF0aW9uIHRvIGRldGVybWluZSB3aGVuL2hvd1xuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKHJlc29sdmVyKSB7XG4gICAgICAgIHN1cGVyKFwiZmlyZWQtc2VhcmNoXCIsIHJlc29sdmVyKTtcbiAgICB9XG59XG4iLCJpbXBvcnQgeyBBYnN0cmFjdENvbGxlY3RvciB9IGZyb20gXCIuL0Fic3RyYWN0Q29sbGVjdG9yXCI7XG4vKipcbiAqIENvbGxlY3QgZGlmZmVyZW50IHR5cGUgb2YgZXZlbnRzIHZpYSBhIGN1c3RvbSBldmVudC4gVGhlIGN1c3RvbSBldmVudCBzaG91bGQgaG9sZCB0aGUgcHJvcGVydGllc1xuICogXCJ0eXBlXCIgYW5kIFwiZGF0YVwiIGluIHRoZSBjdXN0b20gcGF5bG9hZC5cbiAqXG4gKiBTZWUgaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvR3VpZGUvRXZlbnRzL0NyZWF0aW5nX2FuZF90cmlnZ2VyaW5nX2V2ZW50cyBmb3IgZ3VpZGFuY2VcbiAqL1xuZXhwb3J0IGNsYXNzIEdlbmVyaWNFdmVudENvbGxlY3RvciBleHRlbmRzIEFic3RyYWN0Q29sbGVjdG9yIHtcbiAgICAvKipcbiAgICAgKiBDb25zdHJ1Y3QgZXZlbnQgYmFzZWQgY29sbGVjdG9yXG4gICAgICpcbiAgICAgKiBAY29uc3RydWN0b3JcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gZXZlbnROYW1lIC0gdGhlIG5hbWUgb2YgdGhlIGV2ZW50IHRvIHJlYWN0IG9uXG4gICAgICogQHBhcmFtIHR5cGVcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihldmVudE5hbWUsIHR5cGUgPSBcIkdlbmVyaWNFdmVudFwiKSB7XG4gICAgICAgIHN1cGVyKHR5cGUpO1xuICAgICAgICB0aGlzLmV2ZW50TmFtZSA9IGV2ZW50TmFtZTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogQXR0YWNoIGEgd3JpdGVyLCBub3RlIHRoYXQgdGhpcyBjb2xsZWN0b3IgaXMgYXN5bmNocm9ub3VzIGFuZCB3aWxsIHdyaXRlXG4gICAgICogdGhlIGRhdGEgd2hlbiB0aGUgZXZlbnQgdHJpZ2dlcnNcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSB3cml0ZXIgLSBUaGUgd3JpdGVyIHRvIHNlbmQgdGhlIGRhdGEgdG9cbiAgICAgKiBAcGFyYW0gbG9nXG4gICAgICovXG4gICAgYXR0YWNoKHdyaXRlciwgbG9nKSB7XG4gICAgICAgIHRoaXMuZ2V0V2luZG93KCkuYWRkRXZlbnRMaXN0ZW5lcih0aGlzLmV2ZW50TmFtZSwgdGhpcy5sb2dXcmFwSGFuZGxlcigoZSkgPT4ge1xuICAgICAgICAgICAgd3JpdGVyLndyaXRlKHtcbiAgICAgICAgICAgICAgICBcInR5cGVcIjogZS5kZXRhaWwudHlwZSxcbiAgICAgICAgICAgICAgICAuLi5lLmRldGFpbC5kYXRhXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSwgbG9nKSk7XG4gICAgfVxufVxuIiwiaW1wb3J0IHsgQWJzdHJhY3RDb2xsZWN0b3IgfSBmcm9tIFwiLi9BYnN0cmFjdENvbGxlY3RvclwiO1xuaW1wb3J0IHsgU2VudGluZWwgfSBmcm9tIFwiLi4vdXRpbHMvU2VudGluZWxcIjtcbmltcG9ydCBTY3JvbGxNb25pdG9yIGZyb20gXCJzY3JvbGxtb25pdG9yXCI7XG5pbXBvcnQgeyBMb2NhbFN0b3JhZ2VRdWV1ZSB9IGZyb20gXCIuLi91dGlscy9Mb2NhbFN0b3JhZ2VRdWV1ZVwiO1xuaW1wb3J0IHsgZGVib3VuY2UgfSBmcm9tIFwiLi4vdXRpbHMvVXRpbFwiO1xuLyoqXG4gKiBDb2xsZWN0IGltcHJlc3Npb25zIC0gYSBkaXNwbGF5IG9mIGEgcHJvZHVjdCBpbiB0aGUgYnJvd3NlciB2aWV3cG9ydC4gSWYgdGhlIHByb2R1Y3QgaXMgc2hvd24gbXVsdGlwbGVcbiAqIHRpbWVzLCB0aGUgY29sbGVjdG9yIHdpbGwgcmVjb3JkIG11bHRpcGxlIGV2ZW50cyBpLmUuIHdlIGRvbid0IGFwcGx5IGZpbHRlciBsb2dpYyBoZXJlLlxuICpcbiAqIEhhbmRsZXMgYm90aCBET00gZWxlbWVudHMgcHJlc2VudCBpbiB0aGUgRE9NIGFuZCBlbGVtZW50cyBpbnNlcnRlZCBhZnRlciB0aGUgcGFnZSBsb2FkIC8gY29sbGVjdG9yIGNvbnN0cnVjdGlvbi5cbiAqL1xuZXhwb3J0IGNsYXNzIEltcHJlc3Npb25Db2xsZWN0b3IgZXh0ZW5kcyBBYnN0cmFjdENvbGxlY3RvciB7XG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0IGltcHJlc3Npb24gY29sbGVjdG9yXG4gICAgICpcbiAgICAgKiBAY29uc3RydWN0b3JcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gc2VsZWN0b3JFeHByZXNzaW9uIC0gRG9jdW1lbnQgcXVlcnkgc2VsZWN0b3IgaWRlbnRpZnlpbmcgdGhlIGVsZW1lbnRzIHRvIGF0dGFjaCB0b1xuICAgICAqIEBwYXJhbSBpZFJlc29sdmVyIC0gUmVzb2x2ZSB0aGUgaWQgb2YgdGhlIGVsZW1lbnRcbiAgICAgKiBAcGFyYW0gcG9zaXRpb25SZXNvbHZlciAtIFJlc29sdmUgdGhlIHBvc2l0aW9uIG9mIHRoZSBlbGVtZW50IGluIGRvbVxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKHNlbGVjdG9yRXhwcmVzc2lvbiwgaWRSZXNvbHZlciwgcG9zaXRpb25SZXNvbHZlcikge1xuICAgICAgICBzdXBlcihcImltcHJlc3Npb25cIik7XG4gICAgICAgIHRoaXMuc2VsZWN0b3JFeHByZXNzaW9uID0gc2VsZWN0b3JFeHByZXNzaW9uO1xuICAgICAgICB0aGlzLmlkUmVzb2x2ZXIgPSBpZFJlc29sdmVyO1xuICAgICAgICB0aGlzLnBvc2l0aW9uUmVzb2x2ZXIgPSBwb3NpdGlvblJlc29sdmVyO1xuICAgICAgICB0aGlzLnF1ZXVlID0gbmV3IExvY2FsU3RvcmFnZVF1ZXVlKFwiaW1wcmVzc2lvbnNcIik7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEFkZCBpbXByZXNzaW9uIGV2ZW50IGxpc3RlbmVycyB0byB0aGUgaWRlbnRpZmllZCBlbGVtZW50cywgd3JpdGUgdGhlIGRhdGFcbiAgICAgKiB3aGVuIHRoZSBldmVudCBvY2N1cnMsIHdpdGggYSBkZWxheSBvZiAxcyAtIHdlIGNvdWxkIGdhdGhlciBtYW55IGV2ZW50cyB3aXRoaW4gdGhpcyB0aW1lZnJhbWVcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSB3cml0ZXIgLSBUaGUgd3JpdGVyIHRvIHNlbmQgdGhlIGRhdGEgdG9cbiAgICAgKiBAcGFyYW0ge0xvZ2dlcn0gbG9nIC0gVGhlIGxvZ2dlclxuICAgICAqL1xuICAgIGF0dGFjaCh3cml0ZXIsIGxvZykge1xuICAgICAgICBjb25zdCBmbHVzaCA9IGRlYm91bmNlKCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMucXVldWUudHJhbnNhY3Rpb25hbERyYWluKHF1ZXVlID0+IG5ldyBQcm9taXNlKHJlcyA9PiB7XG4gICAgICAgICAgICAgICAgcmVzKHdyaXRlci53cml0ZSh7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6IHRoaXMudHlwZSxcbiAgICAgICAgICAgICAgICAgICAgZGF0YTogcXVldWVcbiAgICAgICAgICAgICAgICB9KSk7XG4gICAgICAgICAgICB9KSlcbiAgICAgICAgICAgICAgICAuY2F0Y2goZXJyID0+IGxvZy5lcnJvcihcIkNvdWxkIG5vdCBkcmFpbiBxdWV1ZTogXCIsIGVycikpO1xuICAgICAgICB9LCAyNTApO1xuICAgICAgICBjb25zdCBoYW5kbGVyID0gZWxlbWVudCA9PiB7XG4gICAgICAgICAgICBTY3JvbGxNb25pdG9yLmNyZWF0ZShlbGVtZW50KS5lbnRlclZpZXdwb3J0KCgpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLnF1ZXVlLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICBpZDogdGhpcy5yZXNvbHZlKHRoaXMuaWRSZXNvbHZlciwgbG9nLCBlbGVtZW50KSxcbiAgICAgICAgICAgICAgICAgICAgcG9zaXRpb246IHRoaXMucmVzb2x2ZSh0aGlzLnBvc2l0aW9uUmVzb2x2ZXIsIGxvZywgZWxlbWVudClcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBmbHVzaCgpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG4gICAgICAgIG5ldyBTZW50aW5lbCh0aGlzLmdldERvY3VtZW50KCkpLm9uKHRoaXMuc2VsZWN0b3JFeHByZXNzaW9uLCB0aGlzLmxvZ1dyYXBIYW5kbGVyKGhhbmRsZXIsIGxvZykpO1xuICAgIH1cbn1cbiIsImltcG9ydCB7IEFic3RyYWN0Q29sbGVjdG9yIH0gZnJvbSBcIi4vQWJzdHJhY3RDb2xsZWN0b3JcIjtcbmltcG9ydCB7IFNlbnRpbmVsIH0gZnJvbSBcIi4uL3V0aWxzL1NlbnRpbmVsXCI7XG5pbXBvcnQgeyBMaXN0ZW5lclR5cGUgfSBmcm9tIFwiLi4vdXRpbHMvTGlzdGVuZXJUeXBlXCI7XG4vKipcbiAqIENvbGxlY3Qgc2VhcmNoIGluZm9ybWF0aW9uIGZyb20gYSBmaWVsZCB0aGF0IGhhcyBhIFwiYXMteW91LXR5cGVcIiB0cmlnZ2VyIGFuZFxuICogcmVuZGVycyBzZWFyY2ggcmVzdWx0cyBpbW1lZGlhdGVseS4gTWF5IHRyaWdnZXIgbXVsdGlwbGUgdGltZXMgZGVwZW5kaW5nIG9uXG4gKiB0eXBlIHNwZWVkIHBhdHRlcm5zIC0gd2UgZXhwZWN0IHRoYXQgdGhlIGludGVydmFsIGJldHdlZW4ga2V5IHN0cm9rZXMgd291bGQgYmVcbiAqIGxlc3MgdGhhbiA1MDBtc1xuICovXG5leHBvcnQgY2xhc3MgSW5zdGFudFNlYXJjaFF1ZXJ5Q29sbGVjdG9yIGV4dGVuZHMgQWJzdHJhY3RDb2xsZWN0b3Ige1xuICAgIC8qKlxuICAgICAqIENvbnN0cnVjdCBpbnN0YW50IHNlYXJjaCBjb2xsZWN0b3JcbiAgICAgKlxuICAgICAqIEBjb25zdHJ1Y3RvclxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBzZWxlY3RvckV4cHJlc3Npb24gLSBEb2N1bWVudCBxdWVyeSBzZWxlY3RvciBpZGVudGlmeWluZyB0aGUgZWxlbWVudHMgdG8gYXR0YWNoIHRvXG4gICAgICogQHBhcmFtIGRlbGF5TXNcbiAgICAgKiBAcGFyYW0gbWluTGVuZ3RoXG4gICAgICogQHBhcmFtIGxpc3RlbmVyVHlwZVxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKHNlbGVjdG9yRXhwcmVzc2lvbiwgZGVsYXlNcyA9IDUwMCwgbWluTGVuZ3RoID0gMiwgbGlzdGVuZXJUeXBlID0gTGlzdGVuZXJUeXBlLlNlbnRpbmVsKSB7XG4gICAgICAgIHN1cGVyKFwiaW5zdGFudC1zZWFyY2hcIik7XG4gICAgICAgIHRoaXMuc2VsZWN0b3JFeHByZXNzaW9uID0gc2VsZWN0b3JFeHByZXNzaW9uO1xuICAgICAgICB0aGlzLmRlbGF5TXMgPSBkZWxheU1zO1xuICAgICAgICB0aGlzLm1pbkxlbmd0aCA9IG1pbkxlbmd0aDtcbiAgICAgICAgdGhpcy5saXN0ZW5lclR5cGUgPSBsaXN0ZW5lclR5cGU7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEFkZCBpbXByZXNzaW9uIGV2ZW50IGxpc3RlbmVycyB0byB0aGUgaWRlbnRpZmllZCBlbGVtZW50cywgd3JpdGUgdGhlIGRhdGFcbiAgICAgKiB3aGVuIHRoZSBldmVudCBvY2N1cnNcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSB3cml0ZXIgLSBUaGUgd3JpdGVyIHRvIHNlbmQgdGhlIGRhdGEgdG9cbiAgICAgKiBAcGFyYW0gbG9nXG4gICAgICovXG4gICAgYXR0YWNoKHdyaXRlciwgbG9nKSB7XG4gICAgICAgIGNvbnN0IHR5cGUgPSB0aGlzLmdldFR5cGUoKTtcbiAgICAgICAgY29uc3QgaGFuZGxlciA9IChlLCBzZWFyY2hCb3gpID0+IHtcbiAgICAgICAgICAgIC8vIElnbm9yZSBzaGlmdCwgY3RybCwgZXRjLiBwcmVzc2VzLCByZWFjdCBvbmx5IG9uIGNoYXJhY3RlcnNcbiAgICAgICAgICAgIGlmIChlLndoaWNoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gRGVsYXkgdGhlIHJlYWN0aW9uIG9mIHRoZSBldmVudCwgY2xlYW4gdGhlIHRpbWVvdXQgaWYgdGhlIGV2ZW50IGZpcmVzXG4gICAgICAgICAgICAvLyBhZ2FpbiBhbmQgc3RhcnQgY291bnRpbmcgZnJvbSAwXG4gICAgICAgICAgICBkZWxheSgoKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3Qga2V5d29yZHMgPSBzZWFyY2hCb3gudmFsdWU7XG4gICAgICAgICAgICAgICAgaWYgKGtleXdvcmRzICYmIGtleXdvcmRzLmxlbmd0aCA+PSB0aGlzLm1pbkxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICB3cml0ZXIud3JpdGUoe1xuICAgICAgICAgICAgICAgICAgICAgICAgXCJ0eXBlXCI6IHR5cGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBcImtleXdvcmRzXCI6IGtleXdvcmRzXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sIHRoaXMuZGVsYXlNcyk7XG4gICAgICAgIH07XG4gICAgICAgIC8vIFRoZSBTZW50aWVsIGxpYnJhcnkgdXNlcyBhbmltYXRpb25zdGFydCBldmVudCBsaXN0ZW5lcnMgd2hpY2ggbWF5IGludGVyZmVyZSB3aXRoXG4gICAgICAgIC8vIGFuaW1hdGlvbnMgYXR0YWNoZWQgb24gZWxlbWVuZXRzLiBUaGUgaW4tbGlicmFyeSBwcm92aWRlZCB3b3JrYXJvdW5kIG1lY2hhbmlzbSBkb2VzIG5vdCB3b3JrXG4gICAgICAgIC8vIDEwMCUsIHRodXMgd2UgcHJvdmlkZSB0aGUgbGlzdGVuZXJUeXBlIGNob2ljZSBiZWxvdy4gVGhlIHRyYWRlb2Zmc1xuICAgICAgICAvLyBcImRvbVwiIC0gbm8gYW5pbWF0aW9uIGludGVyZmVyZW5jZSwgb25seSBvbmNsaWNrIGF0dGFjaGVkLCBidXQgZG9lcyBub3QgaGFuZGxlIGVsZW1lbnRzIGluc2VydGVkIGluIHRoZSBET00gbGF0ZXJcbiAgICAgICAgLy8gXCJzZW50aW5lbCAoZGVmYXVsdClcIiAtIHdvcmtzIG9uIGVsZW1lbnRzIGluc2VydGVkIGluIHRoZSBET00gYW55dGltZSwgYnV0IGludGVyZmVyZXMgd2l0aCBDU1MgYW5pbWF0aW9ucyBvbiB0aGVzZSBlbGVtZW50c1xuICAgICAgICBpZiAodGhpcy5saXN0ZW5lclR5cGUgPT09IExpc3RlbmVyVHlwZS5Eb20pIHtcbiAgICAgICAgICAgIGNvbnN0IG5vZGVMaXN0ID0gdGhpcy5nZXREb2N1bWVudCgpLnF1ZXJ5U2VsZWN0b3JBbGwodGhpcy5zZWxlY3RvckV4cHJlc3Npb24pO1xuICAgICAgICAgICAgbm9kZUxpc3QuZm9yRWFjaChlbCA9PiBlbC5hZGRFdmVudExpc3RlbmVyKFwia2V5dXBcIiwgdGhpcy5sb2dXcmFwSGFuZGxlcihoYW5kbGVyLCBsb2csIGVsKSkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgbmV3IFNlbnRpbmVsKHRoaXMuZ2V0RG9jdW1lbnQoKSkub24odGhpcy5zZWxlY3RvckV4cHJlc3Npb24sIChlbCkgPT4ge1xuICAgICAgICAgICAgICAgIGVsLmFkZEV2ZW50TGlzdGVuZXIoXCJrZXl1cFwiLCB0aGlzLmxvZ1dyYXBIYW5kbGVyKGhhbmRsZXIsIGxvZywgZWwpKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxufVxuY29uc3QgZGVsYXkgPSAoZnVuY3Rpb24gKCkge1xuICAgIGxldCB0aW1lcjtcbiAgICByZXR1cm4gZnVuY3Rpb24gKGNhbGxiYWNrLCBtcykge1xuICAgICAgICBjbGVhclRpbWVvdXQodGltZXIpO1xuICAgICAgICB0aW1lciA9IHNldFRpbWVvdXQoY2FsbGJhY2ssIG1zKTtcbiAgICB9O1xufSkoKTtcbiIsImltcG9ydCB7IENsaWNrQ29sbGVjdG9yIH0gZnJvbSBcIi4vQ2xpY2tDb2xsZWN0b3JcIjtcbmltcG9ydCB7IExpc3RlbmVyVHlwZSB9IGZyb20gXCIuLi91dGlscy9MaXN0ZW5lclR5cGVcIjtcbi8qKlxuICogQ2xpY2tDb2xsZWN0b3IgZW1pdHRpbmcgXCJwcm9kdWN0XCIgZXZlbnRzLCBhdHRhY2ggdG8gcHJvZHVjdCBsaW5rc1xuICovXG5leHBvcnQgY2xhc3MgUHJvZHVjdENsaWNrQ29sbGVjdG9yIGV4dGVuZHMgQ2xpY2tDb2xsZWN0b3Ige1xuICAgIGNvbnN0cnVjdG9yKHNlbGVjdG9yLCByZXNvbHZlcnMsIGxpc3RlbmVyVHlwZSA9IExpc3RlbmVyVHlwZS5TZW50aW5lbCkge1xuICAgICAgICBzdXBlcihzZWxlY3RvciwgXCJwcm9kdWN0XCIsIGxpc3RlbmVyVHlwZSk7XG4gICAgICAgIHRoaXMuaWRSZXNvbHZlciA9IHJlc29sdmVycy5pZFJlc29sdmVyO1xuICAgICAgICB0aGlzLnBvc2l0aW9uUmVzb2x2ZXIgPSByZXNvbHZlcnMucG9zaXRpb25SZXNvbHZlcjtcbiAgICAgICAgdGhpcy5wcmljZVJlc29sdmVyID0gcmVzb2x2ZXJzLnByaWNlUmVzb2x2ZXI7XG4gICAgICAgIHRoaXMuaW1hZ2VSZXNvbHZlciA9IHJlc29sdmVycy5pbWFnZVJlc29sdmVyO1xuICAgICAgICB0aGlzLm1ldGFkYXRhUmVzb2x2ZXIgPSByZXNvbHZlcnMubWV0YWRhdGFSZXNvbHZlcjtcbiAgICAgICAgdGhpcy50cmFpbCA9IHJlc29sdmVycy50cmFpbDtcbiAgICB9XG4gICAgLyoqXG4gICAgICogQ29sbGVjdCB0aGUgcHJvZHVjdCBjbGljayBpbmZvcm1hdGlvbiBmcm9tIHRoZSBlbGVtZW50XG4gICAgICogQG92ZXJyaWRlXG4gICAgICovXG4gICAgY29sbGVjdChlbGVtZW50LCBldmVudCwgbG9nKSB7XG4gICAgICAgIGNvbnN0IGlkID0gdGhpcy5yZXNvbHZlKHRoaXMuaWRSZXNvbHZlciwgbG9nLCBlbGVtZW50LCBldmVudCk7XG4gICAgICAgIGlmIChpZCkge1xuICAgICAgICAgICAgaWYgKHRoaXMudHJhaWwpIHtcbiAgICAgICAgICAgICAgICAvLyBSZWdpc3RlciB0aGF0IHRoaXMgcHJvZHVjdCBqb3VybmV5IGludG8gcG90ZW50aWFsIHB1cmNoYXNlIHN0YXJ0ZWRcbiAgICAgICAgICAgICAgICAvLyB3aXRoIHRoaXMgcXVlcnlcbiAgICAgICAgICAgICAgICB0aGlzLnRyYWlsLnJlZ2lzdGVyKGlkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgaWQsXG4gICAgICAgICAgICAgICAgcG9zaXRpb246IHRoaXMucmVzb2x2ZSh0aGlzLnBvc2l0aW9uUmVzb2x2ZXIsIGxvZywgZWxlbWVudCwgZXZlbnQpLFxuICAgICAgICAgICAgICAgIHByaWNlOiB0aGlzLnJlc29sdmUodGhpcy5wcmljZVJlc29sdmVyLCBsb2csIGVsZW1lbnQsIGV2ZW50KSxcbiAgICAgICAgICAgICAgICBpbWFnZTogdGhpcy5yZXNvbHZlKHRoaXMuaW1hZ2VSZXNvbHZlciwgbG9nLCBlbGVtZW50LCBldmVudCksXG4gICAgICAgICAgICAgICAgbWV0YWRhdGE6IHRoaXMucmVzb2x2ZSh0aGlzLm1ldGFkYXRhUmVzb2x2ZXIsIGxvZywgZWxlbWVudCwgZXZlbnQpXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgfVxufVxuIiwiaW1wb3J0IHsgQWJzdHJhY3RDb2xsZWN0b3IgfSBmcm9tIFwiLi9BYnN0cmFjdENvbGxlY3RvclwiO1xuaW1wb3J0IHsgZ2V0U2Vzc2lvblN0b3JhZ2UgfSBmcm9tIFwiLi4vdXRpbHNcIjtcbmltcG9ydCB7IFF1ZXJ5IH0gZnJvbSBcIi4uL3F1ZXJ5XCI7XG4vKipcbiAqIEtlZXAgdHJhY2sgb2YgaHVtYW4gdHJpZ2dlcmVkIHNlYXJjaGVzIGZvbGxvd2VkIGJ5IGEgcmVkaXJlY3QgdG8gYSBwYWdlIGRpZmZlcmVudCB0aGFuIHRoZSBzZWFyY2ggcmVzdWx0IHBhZ2VcbiAqL1xuZXhwb3J0IGNsYXNzIFJlZGlyZWN0Q29sbGVjdG9yIGV4dGVuZHMgQWJzdHJhY3RDb2xsZWN0b3Ige1xuICAgIC8qKlxuICAgICAqIENvbnN0cnVjdCByZWRpcmVjdCBjb2xsZWN0b3JcbiAgICAgKlxuICAgICAqIEBjb25zdHJ1Y3RvclxuICAgICAqIEBwYXJhbSB7ZnVuY3Rpb259IHRyaWdnZXJSZXNvbHZlciAtIEZ1bmN0aW9uIHRoYXQgZmlyZXMgd2hlbiBhIHNlYXJjaCBoYXBwZW5zLCBzaG91bGQgcmV0dXJuIHRoZSBrZXl3b3JkXG4gICAgICogQHBhcmFtIHtmdW5jdGlvbn0gZXhwZWN0ZWRQYWdlUmVzb2x2ZXIgLSBGdW5jdGlvbiB0aGF0IHNob3VsZCByZXR1cm4gd2hldGhlciB0aGUgcGFnZSB3ZSBsb2FkIGlzIHRoZSBleHBlY3RlZCBvbmVcbiAgICAgKiBAcGFyYW0gY29udGV4dFxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKHRyaWdnZXJSZXNvbHZlciwgZXhwZWN0ZWRQYWdlUmVzb2x2ZXIsIGNvbnRleHQpIHtcbiAgICAgICAgc3VwZXIoXCJyZWRpcmVjdFwiLCBjb250ZXh0KTtcbiAgICAgICAgdGhpcy50cmlnZ2VyUmVzb2x2ZXIgPSB0cmlnZ2VyUmVzb2x2ZXI7XG4gICAgICAgIHRoaXMuZXhwZWN0ZWRQYWdlUmVzb2x2ZXIgPSBleHBlY3RlZFBhZ2VSZXNvbHZlcjtcbiAgICB9XG4gICAgLyoqXG4gICAgICogQ2hlY2sgd2hldGhlciB3ZSBzaG91bGQgYmUgcmVjb3JkaW5nIGEgcmVkaXJlY3QgZXZlbnRcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSB3cml0ZXIgLSBUaGUgd3JpdGVyIHRvIHNlbmQgdGhlIGRhdGEgdG9cbiAgICAgKiBAcGFyYW0gbG9nXG4gICAgICovXG4gICAgYXR0YWNoKHdyaXRlciwgbG9nKSB7XG4gICAgICAgIHRoaXMucmVzb2x2ZSh0aGlzLnRyaWdnZXJSZXNvbHZlciwgbG9nLCBrZXl3b3JkID0+IHtcbiAgICAgICAgICAgIGdldFNlc3Npb25TdG9yYWdlKCkuc2V0SXRlbShSZWRpcmVjdENvbGxlY3Rvci5TVE9SQUdFX0tFWSwga2V5d29yZCk7XG4gICAgICAgIH0pO1xuICAgICAgICAvLyBGZXRjaCB0aGUgbGF0ZXN0IHNlYXJjaCBpZiBhbnlcbiAgICAgICAgY29uc3QgbGFzdFNlYXJjaCA9IGdldFNlc3Npb25TdG9yYWdlKCkuZ2V0SXRlbShSZWRpcmVjdENvbGxlY3Rvci5TVE9SQUdFX0tFWSk7XG4gICAgICAgIGlmIChsYXN0U2VhcmNoKSB7XG4gICAgICAgICAgICAvLyBSZW1vdmUgdGhlIHNlYXJjaCBhY3Rpb24sIGFzIHdlJ3JlIGVpdGhlciBvbiBhIHNlYXJjaCByZXN1bHQgcGFnZSBvciB3ZSd2ZSByZWRpcmVjdGVkXG4gICAgICAgICAgICBnZXRTZXNzaW9uU3RvcmFnZSgpLnJlbW92ZUl0ZW0oUmVkaXJlY3RDb2xsZWN0b3IuU1RPUkFHRV9LRVkpO1xuICAgICAgICAgICAgLy8gSWYgd2UgaGF2ZSBub3QgbGFuZGVkIG9uIHRoZSBleHBlY3RlZCBzZWFyY2ggcGFnZSwgaXQgbXVzdCBoYXZlIGJlZW4gKGxvb292ZSkgYSByZWRpcmVjdFxuICAgICAgICAgICAgaWYgKCF0aGlzLnJlc29sdmUodGhpcy5leHBlY3RlZFBhZ2VSZXNvbHZlciwgbG9nKSkge1xuICAgICAgICAgICAgICAgIC8vIFRodXMgcmVjb3JkIHRoZSByZWRpcmVjdFxuICAgICAgICAgICAgICAgIGNvbnN0IHF1ZXJ5ID0gbmV3IFF1ZXJ5KCk7XG4gICAgICAgICAgICAgICAgcXVlcnkuc2V0U2VhcmNoKGxhc3RTZWFyY2gpO1xuICAgICAgICAgICAgICAgIHdyaXRlci53cml0ZSh7XG4gICAgICAgICAgICAgICAgICAgIHR5cGU6IFwicmVkaXJlY3RcIixcbiAgICAgICAgICAgICAgICAgICAga2V5d29yZHM6IGxhc3RTZWFyY2gsXG4gICAgICAgICAgICAgICAgICAgIHF1ZXJ5OiBxdWVyeS50b1N0cmluZygpLFxuICAgICAgICAgICAgICAgICAgICB1cmw6IHdpbmRvdy5sb2NhdGlvbi5ocmVmXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59XG5SZWRpcmVjdENvbGxlY3Rvci5TVE9SQUdFX0tFWSA9IFwiX19sYXN0U2VhcmNoXCI7XG4iLCJpbXBvcnQgeyBBYnN0cmFjdENvbGxlY3RvciB9IGZyb20gXCIuL0Fic3RyYWN0Q29sbGVjdG9yXCI7XG4vKipcbiAqIENvbGxlY3QgdGhlIGJhc2ljIHNlYXJjaCBpbmZvcm1hdGlvbiAtIHRoZSBrZXl3b3JkcyB1c2VkIGZvciB0aGUgc2VhcmNoIGFuZFxuICogdGhlIG51bWJlciBvZiByZXN1bHRzLiBTeW5jaHJvbm91cyBpLmUuIHRoZSB3cml0aW5nIGhhcHBlbnMgZGlyZWN0bHkgd2hlbiBhIHdyaXRlciBpcyBhdHRhY2hlZC5cbiAqIFNlZSB0aGUgb3RoZXIgc2VhcmNoIGNvbGxlY3RvcnMgZm9yIGR5bmFtaWMgb25lcy5cbiAqL1xuZXhwb3J0IGNsYXNzIFNlYXJjaFJlc3VsdENvbGxlY3RvciBleHRlbmRzIEFic3RyYWN0Q29sbGVjdG9yIHtcbiAgICAvKipcbiAgICAgKiBDb25zdHJ1Y3Qgc2VhcmNoIHJlc3VsdCBjb2xsZWN0b3JcbiAgICAgKlxuICAgICAqIEBjb25zdHJ1Y3RvclxuICAgICAqIEBwYXJhbSB7ZnVuY3Rpb259IHBocmFzZVJlc29sdmVyIC0gRnVuY3Rpb24gdGhhdCBzaG91bGQgcmV0dXJuIHRoZSBzZWFyY2ggcGhyYXNlIHVzZWQgZm9yIHRoZSBzZWFyY2hcbiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBjb3VudFJlc29sdmVyIC0gRnVuY3Rpb24gdGhhdCBzaG91bGQgcmV0dXJuIHRoZSBudW1uYmVyIG9mIHJlc3VsdHMgaW4gdGhlIHNlYXJjaFxuICAgICAqIEBwYXJhbSB7ZnVuY3Rpb259IGFjdGlvblJlc29sdmVyIC0gQSBzZWFyY2ggcmVzdWx0IG1heSBiZSByZWZpbmVkIG9yIGEgY2xpZW50IG1heSBicm93c2UgMiwzLDQgcGFnZS5cbiAgICAgKiBUaGlzIGZ1bmN0aW9uIHNob3VsZCBwcm92aWRlIGEgdGV4dCByZXByZXNhbnRpb24gb2YgdGhlIGFjdGlvblxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKHBocmFzZVJlc29sdmVyLCBjb3VudFJlc29sdmVyLCBhY3Rpb25SZXNvbHZlcikge1xuICAgICAgICBzdXBlcihcInNlYXJjaFwiKTtcbiAgICAgICAgdGhpcy5waHJhc2VSZXNvbHZlciA9IHBocmFzZVJlc29sdmVyO1xuICAgICAgICB0aGlzLmNvdW50UmVzb2x2ZXIgPSBjb3VudFJlc29sdmVyO1xuICAgICAgICB0aGlzLmFjdGlvblJlc29sdmVyID0gYWN0aW9uUmVzb2x2ZXI7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEF0dGFjaCBhIHdyaXRlciwgbm90ZSB0aGF0IHRoaXMgY29sbGVjdG9yIGlzIG5vdCBhc3luY2hyb25vdXMgYW5kIHdpbGwgd3JpdGVcbiAgICAgKiB0aGUgZGF0YSBpbW1lZGlhdGVsbHlcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7b2JqZWN0fSB3cml0ZXIgLSBUaGUgd3JpdGVyIHRvIHNlbmQgdGhlIGRhdGEgdG9cbiAgICAgKiBAcGFyYW0ge29iamVjdH0gbG9nIC0gVGhlIGxvZ2dlclxuICAgICAqL1xuICAgIGF0dGFjaCh3cml0ZXIsIGxvZykge1xuICAgICAgICB3cml0ZXIud3JpdGUoe1xuICAgICAgICAgICAgdHlwZTogXCJzZWFyY2hcIixcbiAgICAgICAgICAgIGtleXdvcmRzOiB0aGlzLnJlc29sdmUodGhpcy5waHJhc2VSZXNvbHZlciwgbG9nLCB7fSksXG4gICAgICAgICAgICBjb3VudDogdGhpcy5yZXNvbHZlKHRoaXMuY291bnRSZXNvbHZlciwgbG9nLCB7fSksXG4gICAgICAgICAgICBhY3Rpb246IHRoaXMucmVzb2x2ZSh0aGlzLmFjdGlvblJlc29sdmVyLCBsb2csIHt9KSB8fCBcInNlYXJjaFwiXG4gICAgICAgIH0pO1xuICAgIH1cbn1cbiIsImltcG9ydCB7IFdyaXRlclJlc29sdmVyQ29sbGVjdG9yIH0gZnJvbSBcIi4vV3JpdGVyUmVzb2x2ZXJDb2xsZWN0b3JcIjtcbi8qKlxuICogQ29sbGVjdCBzdWdnZXN0IHNlYXJjaCBpbmZvcm1hdGlvbiAtIGtleXdvcmQgc2VhcmNoZXMgY29taW5nIGZyb20gYSBzdWdnZXN0aW9uIHdpZGdldC9mdW5jdGlvbmFsaXR5XG4gKi9cbmV4cG9ydCBjbGFzcyBTdWdnZXN0U2VhcmNoQ29sbGVjdG9yIGV4dGVuZHMgV3JpdGVyUmVzb2x2ZXJDb2xsZWN0b3Ige1xuICAgIC8qKlxuICAgICAqIENvbnN0cnVjdCBzdWdnZXN0IHNlYXJjaCBjb2xsZWN0b3JcbiAgICAgKlxuICAgICAqIEBjb25zdHJ1Y3RvclxuICAgICAqIEBwYXJhbSB7ZnVuY3Rpb259IHJlc29sdmVyIC0gRnVuY3Rpb24gdGhhdCB0cmlnZ2VycyB0aGUgd3JpdGluZy4gU3VnZ2VzdCBtaWdodCBiZSBjb21wbGV4LCBsZWF2ZSB0byB0aGUgaW1wbGVtZW50YXRpb24gdG8gZGV0ZXJtaW5lIHdoZW4vaG93XG4gICAgICovXG4gICAgY29uc3RydWN0b3IocmVzb2x2ZXIpIHtcbiAgICAgICAgc3VwZXIoXCJzdWdnZXN0LXNlYXJjaFwiLCByZXNvbHZlcik7XG4gICAgfVxufVxuIiwiaW1wb3J0IHsgQWJzdHJhY3RDb2xsZWN0b3IgfSBmcm9tIFwiLi9BYnN0cmFjdENvbGxlY3RvclwiO1xuLyoqXG4gKiBSZXNvbHZlcyBpbW1lZGlhdGVseSBhbmQgcGFzc2luZyB0aGUgd3JpdGVyLCB0aGUgdHlwZSBvZiB0aGUgZXZlbnQgKyBjb250ZXh0IHRvIHRoZSBwcm92aWRlZCByZXNvbHZlciBmdW5jdGlvbi5cbiAqL1xuZXhwb3J0IGNsYXNzIFdyaXRlclJlc29sdmVyQ29sbGVjdG9yIGV4dGVuZHMgQWJzdHJhY3RDb2xsZWN0b3Ige1xuICAgIGNvbnN0cnVjdG9yKHR5cGUsIHJlc29sdmVyKSB7XG4gICAgICAgIHN1cGVyKHR5cGUpO1xuICAgICAgICB0aGlzLnJlc29sdmVyID0gcmVzb2x2ZXI7XG4gICAgfVxuICAgIGF0dGFjaCh3cml0ZXIsIGxvZykge1xuICAgICAgICB0aGlzLnJlc29sdmUodGhpcy5yZXNvbHZlciwgbG9nLCB3cml0ZXIsIHRoaXMuZ2V0VHlwZSgpLCB0aGlzLmdldENvbnRleHQoKSk7XG4gICAgfVxufVxuIiwiZXhwb3J0ICogZnJvbSBcIi4vQWJzdHJhY3RDb2xsZWN0b3JcIjtcbmV4cG9ydCAqIGZyb20gXCIuL0Fzc29jaWF0ZWRQcm9kdWN0Q29sbGVjdG9yXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9CYXNrZXRDbGlja0NvbGxlY3RvclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vQnJvd3NlckNvbGxlY3RvclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vQ2hlY2tvdXRDbGlja0NvbGxlY3RvclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vQ2xpY2tDb2xsZWN0b3JcIjtcbmV4cG9ydCAqIGZyb20gXCIuL0NsaWNrV3JpdGVyUmVzb2x2ZXJDb2xsZWN0b3JcIjtcbmV4cG9ydCAqIGZyb20gXCIuL0ZpbHRlckNsaWNrQ29sbGVjdG9yXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9GaXJlZFNlYXJjaENvbGxlY3RvclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vR2VuZXJpY0V2ZW50Q29sbGVjdG9yXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9JbXByZXNzaW9uQ29sbGVjdG9yXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9JbnN0YW50U2VhcmNoUXVlcnlDb2xsZWN0b3JcIjtcbmV4cG9ydCAqIGZyb20gXCIuL1Byb2R1Y3RDbGlja0NvbGxlY3RvclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vUmVkaXJlY3RDb2xsZWN0b3JcIjtcbmV4cG9ydCAqIGZyb20gXCIuL1NlYXJjaFJlc3VsdENvbGxlY3RvclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vU3VnZ2VzdFNlYXJjaENvbGxlY3RvclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vV3JpdGVyUmVzb2x2ZXJDb2xsZWN0b3JcIjtcbiIsImV4cG9ydCB7fTtcbiIsImV4cG9ydCB7fTtcbiIsIi8qKlxuICogUGFzc2VzIGFsbCBsb2cgbWVzc2FnZXMgdG8gdGhlIHByb3ZpZGVkIHRyYW5zcG9ydHNcbiAqL1xuZXhwb3J0IGNsYXNzIFRyYW5zcG9ydExvZ2dlciB7XG4gICAgY29uc3RydWN0b3IodHJhbnNwb3J0cywgaXNEZWJ1Z0VuYWJsZWQgPSBmYWxzZSkge1xuICAgICAgICB0aGlzLnRyYW5zcG9ydHMgPSB0cmFuc3BvcnRzO1xuICAgICAgICB0aGlzLmlzRGVidWdFbmFibGVkID0gaXNEZWJ1Z0VuYWJsZWQ7XG4gICAgfVxuICAgIGRlYnVnKG1zZywgLi4uZGF0YUFyZ3MpIHtcbiAgICAgICAgdGhpcy50cmFuc3BvcnRzLmZvckVhY2godHJhbnNwb3J0ID0+IHRoaXMuY2FsbFRyYW5zcG9ydCh0cmFuc3BvcnQsIFwiZGVidWdcIiwgbXNnLCAuLi5kYXRhQXJncykpO1xuICAgIH1cbiAgICBlcnJvcihtc2csIC4uLmRhdGFBcmdzKSB7XG4gICAgICAgIHRoaXMudHJhbnNwb3J0cy5mb3JFYWNoKHRyYW5zcG9ydCA9PiB0aGlzLmNhbGxUcmFuc3BvcnQodHJhbnNwb3J0LCBcImVycm9yXCIsIG1zZywgLi4uZGF0YUFyZ3MpKTtcbiAgICB9XG4gICAgaW5mbyhtc2csIC4uLmRhdGFBcmdzKSB7XG4gICAgICAgIHRoaXMudHJhbnNwb3J0cy5mb3JFYWNoKHRyYW5zcG9ydCA9PiB0aGlzLmNhbGxUcmFuc3BvcnQodHJhbnNwb3J0LCBcImluZm9cIiwgbXNnLCAuLi5kYXRhQXJncykpO1xuICAgIH1cbiAgICB3YXJuKG1zZywgLi4uZGF0YUFyZ3MpIHtcbiAgICAgICAgdGhpcy50cmFuc3BvcnRzLmZvckVhY2godHJhbnNwb3J0ID0+IHRoaXMuY2FsbFRyYW5zcG9ydCh0cmFuc3BvcnQsIFwid2FyblwiLCBtc2csIC4uLmRhdGFBcmdzKSk7XG4gICAgfVxuICAgIGNhbGxUcmFuc3BvcnQodHJhbnNwb3J0LCBsZXZlbCwgbXNnLCAuLi5kYXRhQXJncykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgaWYgKHRyYW5zcG9ydFtsZXZlbF0gJiYgdHlwZW9mIHRyYW5zcG9ydFtsZXZlbF0gPT09IFwiZnVuY3Rpb25cIilcbiAgICAgICAgICAgICAgICB0cmFuc3BvcnRbbGV2ZWxdKG1zZywgLi4uZGF0YUFyZ3MpO1xuICAgICAgICB9XG4gICAgICAgIGNhdGNoIChlKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5pc0RlYnVnRW5hYmxlZClcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiQ291bGQgbm90IGNhbGwgdHJhbnNwb3J0OiBcIiwgZSk7XG4gICAgICAgIH1cbiAgICB9XG59XG4iLCJleHBvcnQgKiBmcm9tIFwiLi9Mb2dnZXJcIjtcbmV4cG9ydCAqIGZyb20gXCIuL0xvZ2dlclRyYW5zcG9ydFwiO1xuZXhwb3J0ICogZnJvbSBcIi4vVHJhbnNwb3J0TG9nZ2VyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi90cmFuc3BvcnRcIjtcbiIsImV4cG9ydCBjbGFzcyBDb25zb2xlVHJhbnNwb3J0IHtcbiAgICBkZWJ1Zyhtc2csIC4uLmRhdGFBcmdzKSB7XG4gICAgICAgIGNvbnNvbGUuZGVidWcobXNnLCAuLi5kYXRhQXJncyk7XG4gICAgfVxuICAgIDtcbiAgICBpbmZvKG1zZywgLi4uZGF0YUFyZ3MpIHtcbiAgICAgICAgY29uc29sZS5pbmZvKG1zZywgLi4uZGF0YUFyZ3MpO1xuICAgIH1cbiAgICA7XG4gICAgd2Fybihtc2csIC4uLmRhdGFBcmdzKSB7XG4gICAgICAgIGNvbnNvbGUud2Fybihtc2csIC4uLmRhdGFBcmdzKTtcbiAgICB9XG4gICAgO1xuICAgIGVycm9yKG1zZywgLi4uZGF0YUFyZ3MpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihtc2csIC4uLmRhdGFBcmdzKTtcbiAgICB9XG4gICAgO1xufVxuIiwiaW1wb3J0IHsgYmFzZTY0RW5jb2RlIH0gZnJvbSBcIi4uLy4uL3V0aWxzXCI7XG4vKipcbiAqIE9ubHkgYWRkcyBlcnJvciBtZXNzYWdlcyB0byBhbiBzcXMgcXVldWVcbiAqL1xuZXhwb3J0IGNsYXNzIFNRU0Vycm9yVHJhbnNwb3J0IHtcbiAgICBjb25zdHJ1Y3RvcihxdWV1ZSwgY2hhbm5lbCwgc2Vzc2lvblJlc29sdmVyLCBmaWZvID0gZmFsc2UpIHtcbiAgICAgICAgdGhpcy5xdWV1ZSA9IHF1ZXVlO1xuICAgICAgICB0aGlzLmNoYW5uZWwgPSBjaGFubmVsO1xuICAgICAgICB0aGlzLnNlc3Npb25SZXNvbHZlciA9IHNlc3Npb25SZXNvbHZlcjtcbiAgICAgICAgdGhpcy5maWZvID0gZmlmbztcbiAgICB9XG4gICAgc2VuZChkYXRhKSB7XG4gICAgICAgIGNvbnN0IGltZyA9IG5ldyBJbWFnZSgpO1xuICAgICAgICBsZXQgc3JjID0gdGhpcy5xdWV1ZSArIFwiP1ZlcnNpb249MjAxMi0xMS0wNSZBY3Rpb249U2VuZE1lc3NhZ2VcIjtcbiAgICAgICAgLy8gU1FTIHN1cHBvcnRzIEZJRk8gcXVldWVzIGluIHNvbWUgcmVnaW9ucyB0aGF0IGNhbiBhbHNvIGd1YXJhbnRlZSB0aGUgb3JkZXJcbiAgICAgICAgLy8gb2YgdGhlIG1lc3NhZ2VzLlxuICAgICAgICBpZiAodGhpcy5maWZvKSB7XG4gICAgICAgICAgICAvLyBUT0RPIHdoZW4gZW5vdWdoIGluZm9ybWF0aW9uIGlzIHByZXNlbnQgdG8gdW5pcXVlbHkgaWRlbnRpZnkgYSBtZXNzYWdlLCBzd2l0Y2ggdGhlIGRlZHVwbGljYXRpb24gaWQgdG8gYSBtZXNzYWdlIGhhc2hcbiAgICAgICAgICAgIHNyYyArPSBcIiZNZXNzYWdlR3JvdXBJZD0xJk1lc3NhZ2VEZWR1cGxpY2F0aW9uSWQ9XCIgKyBNYXRoLnJhbmRvbSgpO1xuICAgICAgICB9XG4gICAgICAgIGlmICghQXJyYXkuaXNBcnJheShkYXRhKSAmJiB0eXBlb2YgZGF0YSAhPT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgZGF0YSA9IFtkYXRhXTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodHlwZW9mIGRhdGEgIT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgIGRhdGEgPSBKU09OLnN0cmluZ2lmeShkYXRhKTtcbiAgICAgICAgfVxuICAgICAgICBzcmMgKz0gXCImTWVzc2FnZUJvZHk9XCIgKyBiYXNlNjRFbmNvZGUoZW5jb2RlVVJJQ29tcG9uZW50KGRhdGEpKTtcbiAgICAgICAgaW1nLnNyYyA9IHNyYztcbiAgICB9XG4gICAgZXJyb3IobXNnLCAuLi5kYXRhQXJncykge1xuICAgICAgICB0aGlzLnNlbmQoe1xuICAgICAgICAgICAgdHlwZTogXCJlcnJvclwiLFxuICAgICAgICAgICAgbXNnLFxuICAgICAgICAgICAgY2hhbm5lbDogdGhpcy5jaGFubmVsLFxuICAgICAgICAgICAgc2Vzc2lvbjogdGhpcy5zZXNzaW9uUmVzb2x2ZXIoKSxcbiAgICAgICAgICAgIHRpbWVzdGFtcDogbmV3IERhdGUoKS5nZXRUaW1lKCksXG4gICAgICAgICAgICAuLi5kYXRhQXJnc1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgO1xufVxuIiwiaW1wb3J0IHsgU1FTRXJyb3JUcmFuc3BvcnQgfSBmcm9tIFwiLi9TUVNFcnJvclRyYW5zcG9ydFwiO1xuLyoqXG4gKiBBZGRzIGFsbCBsb2cgbGV2ZWxzIHRvIGFuIFNRUyBxdWV1ZVxuICovXG5leHBvcnQgY2xhc3MgU1FTVHJhbnNwb3J0IGV4dGVuZHMgU1FTRXJyb3JUcmFuc3BvcnQge1xuICAgIGRlYnVnKG1zZywgLi4uZGF0YUFyZ3MpIHtcbiAgICAgICAgdGhpcy5zZW5kKHtcbiAgICAgICAgICAgIHR5cGU6IFwiZGVidWdcIixcbiAgICAgICAgICAgIG1zZyxcbiAgICAgICAgICAgIC4uLmRhdGFBcmdzXG4gICAgICAgIH0pO1xuICAgIH1cbiAgICA7XG4gICAgaW5mbyhtc2csIC4uLmRhdGFBcmdzKSB7XG4gICAgICAgIHRoaXMuc2VuZCh7XG4gICAgICAgICAgICB0eXBlOiBcImluZm9cIixcbiAgICAgICAgICAgIG1zZyxcbiAgICAgICAgICAgIC4uLmRhdGFBcmdzXG4gICAgICAgIH0pO1xuICAgIH1cbiAgICA7XG4gICAgd2Fybihtc2csIC4uLmRhdGFBcmdzKSB7XG4gICAgICAgIHRoaXMuc2VuZCh7XG4gICAgICAgICAgICB0eXBlOiBcIndhcm5pbmdcIixcbiAgICAgICAgICAgIG1zZyxcbiAgICAgICAgICAgIC4uLmRhdGFBcmdzXG4gICAgICAgIH0pO1xuICAgIH1cbiAgICA7XG59XG4iLCJleHBvcnQgKiBmcm9tIFwiLi9Db25zb2xlVHJhbnNwb3J0XCI7XG5leHBvcnQgKiBmcm9tIFwiLi9TUVNFcnJvclRyYW5zcG9ydFwiO1xuZXhwb3J0ICogZnJvbSBcIi4vU1FTVHJhbnNwb3J0XCI7XG4iLCJleHBvcnQgY2xhc3MgUXVlcnkge1xuICAgIGNvbnN0cnVjdG9yKHF1ZXJ5U3RyaW5nKSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBSZW1vdmUgYWxsIHNlbGVjdGlvbnMgb24gdGhpcyBmaWVsZFxuICAgICAgICAgKi9cbiAgICAgICAgdGhpcy5yZW1vdmVTZWxlY3Rpb25BdCA9IGZ1bmN0aW9uIChwb3MpIHtcbiAgICAgICAgICAgIGFycmF5UmVtb3ZlKHRoaXMuY3JpdGVyaWEsIHBvcywgcG9zKTtcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5jcml0ZXJpYSA9IFtdO1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgIGlmIChxdWVyeVN0cmluZykge1xuICAgICAgICAgICAgdmFyIGNyaXRlcmlhID0gW107XG4gICAgICAgICAgICB2YXIgYW5kcyA9IHF1ZXJ5U3RyaW5nLnNwbGl0KFwiL1wiKTtcbiAgICAgICAgICAgIGFuZHMuZm9yRWFjaChmdW5jdGlvbiAoYW5kKSB7XG4gICAgICAgICAgICAgICAgaWYgKGFuZC5pbmRleE9mKFwifFwiKSAhPSAtMSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgb3JzID0gYW5kLnNwbGl0KFwifFwiKTtcbiAgICAgICAgICAgICAgICAgICAgb3JzLmZvckVhY2goZnVuY3Rpb24gKG9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjcml0ZXJpYS5wdXNoKHsgXCJzZWxlY3Rpb25cIjogb3IsIFwidHlwZVwiOiBcIm9yXCIgfSk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgY3JpdGVyaWEucHVzaCh7IFwic2VsZWN0aW9uXCI6IGFuZCwgXCJ0eXBlXCI6IFwiYW5kXCIgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBjcml0ZXJpYS5mb3JFYWNoKGZ1bmN0aW9uIChjcml0ZXJpb24pIHtcbiAgICAgICAgICAgICAgICB2YXIgYyA9IHVuZXNjYXBlKGNyaXRlcmlvbi5zZWxlY3Rpb24pO1xuICAgICAgICAgICAgICAgIGlmIChjLmluZGV4T2YoXCI9XCIpICE9IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciB2YWx1ZVNwbGl0ID0gYy5zcGxpdChcIj1cIik7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYuY3JpdGVyaWEucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgICAgICBcImZpZWxkXCI6IHZhbHVlU3BsaXRbMF0sXG4gICAgICAgICAgICAgICAgICAgICAgICBcIm9wZXJhdGlvblwiOiBcIj1cIixcbiAgICAgICAgICAgICAgICAgICAgICAgIFwidmFsdWVcIjogdmFsdWVTcGxpdFsxXSxcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiYWdncmVnYXRpb25cIjogY3JpdGVyaW9uLnR5cGVcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKGMuaW5kZXhPZihcIjxcIikgIT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZhbHVlU3BsaXQgPSBjLnNwbGl0KFwiPFwiKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKDIgPT0gdmFsdWVTcGxpdC5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuY3JpdGVyaWEucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJmaWVsZFwiOiB2YWx1ZVNwbGl0WzBdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwib3BlcmF0aW9uXCI6IFwiPFwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwidmFsdWVcIjogdmFsdWVTcGxpdFsxXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcImFnZ3JlZ2F0aW9uXCI6IGNyaXRlcmlvbi50eXBlXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIGlmICgzID09IHZhbHVlU3BsaXQubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmNyaXRlcmlhLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiZmllbGRcIjogdmFsdWVTcGxpdFsxXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIm9wZXJhdGlvblwiOiBcIj48XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJsb3dlclZhbHVlXCI6IHZhbHVlU3BsaXRbMF0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJ1cHBlclZhbHVlXCI6IHZhbHVlU3BsaXRbMl0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJhZ2dyZWdhdGlvblwiOiBjcml0ZXJpb24udHlwZVxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoYy5pbmRleE9mKFwiPlwiKSAhPSAtMSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgdmFsdWVTcGxpdCA9IGMuc3BsaXQoXCI+XCIpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoMiA9PSB2YWx1ZVNwbGl0Lmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5jcml0ZXJpYS5wdXNoKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcImZpZWxkXCI6IHZhbHVlU3BsaXRbMF0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJvcGVyYXRpb25cIjogXCI+XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJ2YWx1ZVwiOiB2YWx1ZVNwbGl0WzFdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiYWdncmVnYXRpb25cIjogY3JpdGVyaW9uLnR5cGVcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKDMgPT0gdmFsdWVTcGxpdC5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuY3JpdGVyaWEucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJmaWVsZFwiOiB2YWx1ZVNwbGl0WzFdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwib3BlcmF0aW9uXCI6IFwiPjxcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcImxvd2VyVmFsdWVcIjogdmFsdWVTcGxpdFsyXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcInVwcGVyVmFsdWVcIjogdmFsdWVTcGxpdFsxXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcImFnZ3JlZ2F0aW9uXCI6IGNyaXRlcmlvbi50eXBlXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8qKlxuICAgICAqIFB1dCBiYWNrIHRvIHN0cmluZyB0aGUgcXVlcnkgb2JqZWN0XG4gICAgICpcbiAgICAgKiBAcmV0dXJucyBhIHN0cmluZyBpbiB0aGUgZm9ybSBvZiAvYnJhbmQ9ZGVidXQvcHJpY2U+MTAwL1xuICAgICAqL1xuICAgIHRvU3RyaW5nKCkge1xuICAgICAgICB2YXIgcmVzdWx0ID0gXCJcIjtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmNyaXRlcmlhLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICB2YXIgY3JpdGVyaW9uID0gdGhpcy5jcml0ZXJpYVtpXTtcbiAgICAgICAgICAgIHZhciBzZXBhcmF0b3IgPSBcIi9cIjtcbiAgICAgICAgICAgIGlmIChcIm9yXCIgPT0gY3JpdGVyaW9uLmFnZ3JlZ2F0aW9uKSB7XG4gICAgICAgICAgICAgICAgdmFyIG5leHQgPSB0aGlzLmNyaXRlcmlhW2kgKyAxXTtcbiAgICAgICAgICAgICAgICBpZiAobmV4dCAmJiBcIm9yXCIgPT0gbmV4dC5hZ2dyZWdhdGlvbikge1xuICAgICAgICAgICAgICAgICAgICBzZXBhcmF0b3IgPSBcInxcIjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoY3JpdGVyaW9uLm9wZXJhdGlvbiA9PSBcIj48XCIpIHtcbiAgICAgICAgICAgICAgICByZXN1bHQgKz0gY3JpdGVyaW9uLmxvd2VyVmFsdWUgKyBcIjxcIiArIGNyaXRlcmlvbi5maWVsZCArIFwiPFwiICsgY3JpdGVyaW9uLnVwcGVyVmFsdWUgKyBzZXBhcmF0b3I7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXN1bHQgKz0gY3JpdGVyaW9uLmZpZWxkICsgY3JpdGVyaW9uLm9wZXJhdGlvbiArIGNyaXRlcmlvbi52YWx1ZSArIHNlcGFyYXRvcjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBBZGQgYSBzZWxlY3Rpb24gdG8gdGhpcyBxdWVyeS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBmaWVsZCB0aGUgbmFtZSBvZiB0aGUgZmllbGQgd2UncmUgZHJpbGxpbmcgZG93biB3aXRoXG4gICAgICogQHBhcmFtIG9wZXJhdGlvbiB0aGUgb3BlcmF0aW9uLCBleCA9LD4sPFxuICAgICAqIEBwYXJhbSB2YWx1ZSB0aGUgdmFsdWUgZm9yIHRoZSBvcGVyYXRpb25cbiAgICAgKiBAcGFyYW0gdmFsdWUxIG9wdGlvbmFsIHNlY29uZCB2YWx1ZSBmb3IgY29uc3RydWN0aW5nIHJhbmdlcyBsaWtlIDEwMDxwcmljZTwyMDBcbiAgICAgKi9cbiAgICBhZGRTZWxlY3Rpb24oZmllbGQsIG9wZXJhdGlvbiwgdmFsdWUsIHZhbHVlMSwgYWdncmVnYXRpb24pIHtcbiAgICAgICAgY29uc3QgYWdnID0gYWdncmVnYXRpb24gPyBhZ2dyZWdhdGlvbiA6IFwiYW5kXCI7XG4gICAgICAgIGlmICh2YWx1ZTEgJiYgXCI+PFwiID09IG9wZXJhdGlvbikge1xuICAgICAgICAgICAgdGhpcy5jcml0ZXJpYS5wdXNoKHtcbiAgICAgICAgICAgICAgICBcImZpZWxkXCI6IGZpZWxkLFxuICAgICAgICAgICAgICAgIFwib3BlcmF0aW9uXCI6IFwiPjxcIixcbiAgICAgICAgICAgICAgICBcImxvd2VyVmFsdWVcIjogdmFsdWUsXG4gICAgICAgICAgICAgICAgXCJ1cHBlclZhbHVlXCI6IHZhbHVlMSxcbiAgICAgICAgICAgICAgICBcImFnZ3JlZ2F0aW9uXCI6IGFnZ1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmNyaXRlcmlhLnB1c2goe1xuICAgICAgICAgICAgICAgIFwiZmllbGRcIjogZmllbGQsXG4gICAgICAgICAgICAgICAgXCJvcGVyYXRpb25cIjogb3BlcmF0aW9uLFxuICAgICAgICAgICAgICAgIFwidmFsdWVcIjogdmFsdWUsXG4gICAgICAgICAgICAgICAgXCJhZ2dyZWdhdGlvblwiOiBhZ2dcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8qKlxuICAgICAqIFBhcnNlIGFuZCBjb25zdHJ1Y3QgYSBuZXcgb2JqZWN0IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBxdWVyeSBzdHJpbmcgZm9ybVxuICAgICAqXG4gICAgICogQHBhcmFtIHF1ZXJ5U3RyaW5nIHRoZSBxdWVyeSBzdHJpbmcgaW4gdGhlIGZvcm0gb2YgXCIvXCIgam9pbmVkIGNyaXRlcmlhLiBleC4gL2JyYW5kPWRlYnV0L3ByaWNlPjEwMC9cbiAgICAgKiBAcmV0dXJuc1xuICAgICAqL1xuICAgIGdldFNlbGVjdGlvbnMoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmNyaXRlcmlhO1xuICAgIH1cbiAgICBnZXRTZWxlY3Rpb24oZmllbGQpIHtcbiAgICAgICAgZm9yICh2YXIgYyBpbiB0aGlzLmNyaXRlcmlhKSB7XG4gICAgICAgICAgICB2YXIgY3JpdCA9IHRoaXMuY3JpdGVyaWFbY107XG4gICAgICAgICAgICBpZiAoY3JpdC5maWVsZCA9PSBmaWVsZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBjcml0O1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIENoZWNrIGlmIHRoaXMgcXVlcnkgYWxyZWFkeSBoYXMgYSBzZWxlY3Rpb24gZm9yIHRoZSBnaXZlbiBmaWVsZFxuICAgICAqXG4gICAgICogQHJldHVybnMgdHJ1ZSBpZiB3ZSBoYXZlIGEgc2VsZWN0aW9uIG9mIHRoaXMgZmllbGQsIGZhbHNlIG90aGVyd2lzZVxuICAgICAqL1xuICAgIGhhc1NlbGVjdGlvbihmaWVsZCkge1xuICAgICAgICBmb3IgKHZhciBjIGluIHRoaXMuY3JpdGVyaWEpIHtcbiAgICAgICAgICAgIHZhciBjcml0ID0gdGhpcy5jcml0ZXJpYVtjXTtcbiAgICAgICAgICAgIGlmIChjcml0LmZpZWxkID09IGZpZWxkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBDaGVjayBpZiB0aGlzIHF1ZXJ5IGFscmVhZHkgaGFzIGEgc2VsZWN0aW9uIGZvciB0aGUgZ2l2ZW4gZmllbGRcbiAgICAgKlxuICAgICAqIEByZXR1cm5zIHRydWUgaWYgd2UgaGF2ZSBhIHNlbGVjdGlvbiBvZiB0aGlzIGZpZWxkLCBmYWxzZSBvdGhlcndpc2VcbiAgICAgKi9cbiAgICBoYXNFeGFjdFNlbGVjdGlvbihmaWVsZCkge1xuICAgICAgICBmb3IgKHZhciBjIGluIHRoaXMuY3JpdGVyaWEpIHtcbiAgICAgICAgICAgIHZhciBjcml0ID0gdGhpcy5jcml0ZXJpYVtjXTtcbiAgICAgICAgICAgIGlmIChjcml0LmZpZWxkID09IGZpZWxkICYmIGNyaXQub3BlcmF0aW9uID09IFwiPVwiKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBSZW1vdmUgYWxsIHNlbGVjdGlvbnMgb24gdGhpcyBmaWVsZFxuICAgICAqL1xuICAgIHJlbW92ZVNlbGVjdGlvbihmaWVsZCkge1xuICAgICAgICB2YXIgY3JpdGVyaWEgPSBbXTtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmNyaXRlcmlhLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICB2YXIgY3JpdCA9IHRoaXMuY3JpdGVyaWFbaV07XG4gICAgICAgICAgICBpZiAoY3JpdC5maWVsZCA9PSBmaWVsZCkge1xuICAgICAgICAgICAgICAgIGNyaXRlcmlhLnB1c2goaSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgd2hpbGUgKGNyaXRlcmlhLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHZhciBjID0gY3JpdGVyaWEucG9wKCk7XG4gICAgICAgICAgICBhcnJheVJlbW92ZSh0aGlzLmNyaXRlcmlhLCBjLCBjKTtcbiAgICAgICAgfVxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuY3JpdGVyaWEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIHZhciBjdXJyZW50ID0gdGhpcy5jcml0ZXJpYVtpXTtcbiAgICAgICAgICAgIHZhciBwcmV2aW91cyA9IHRoaXMuY3JpdGVyaWFbaSAtIDFdO1xuICAgICAgICAgICAgdmFyIG5leHQgPSB0aGlzLmNyaXRlcmlhW2kgKyAxXTtcbiAgICAgICAgICAgIGlmIChcIm9yXCIgPT0gY3VycmVudC5hZ2dyZWdhdGlvbikge1xuICAgICAgICAgICAgICAgIGlmICgoIW5leHQgfHwgXCJhbmRcIiA9PSBuZXh0LmFnZ3JlZ2F0aW9uKSAmJiAoIXByZXZpb3VzIHx8IFwiYW5kXCIgPT0gcHJldmlvdXMuYWdncmVnYXRpb24pKSB7XG4gICAgICAgICAgICAgICAgICAgIGN1cnJlbnQuYWdncmVnYXRpb24gPSBcImFuZFwiO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICBzZXRTZWFyY2godGVybSkge1xuICAgICAgICBpZiAodGVybSkge1xuICAgICAgICAgICAgdGhpcy5yZW1vdmVTZWxlY3Rpb24oXCIkc1wiKTtcbiAgICAgICAgICAgIHRoaXMuY3JpdGVyaWEudW5zaGlmdCh7XG4gICAgICAgICAgICAgICAgXCJmaWVsZFwiOiBcIiRzXCIsXG4gICAgICAgICAgICAgICAgXCJvcGVyYXRpb25cIjogXCI9XCIsXG4gICAgICAgICAgICAgICAgXCJ2YWx1ZVwiOiB0ZXJtXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBnZXRTZWFyY2goKSB7XG4gICAgICAgIGNvbnN0IHMgPSB0aGlzLmdldFNlbGVjdGlvbihcIiRzXCIpO1xuICAgICAgICByZXR1cm4gcyA/IHMudmFsdWUgOiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIGlzVmFsaWQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmNyaXRlcmlhLmxlbmd0aCA+IDA7XG4gICAgfVxufVxuLyoqXG4gKiBXZSBoYXZlIHRoZSBzYW1lIGZ1bmN0aW9uIGluIHV0aWwgYnV0IHdlIHdhbnQgdG8gaGF2ZSBxdWVyeS5qcyB3aXRob3V0IGFueSBkZXBlbmRlbmNpZXNcbiAqXG4gKiBAcGFyYW0gYXJyYXlcbiAqIEBwYXJhbSBmcm9tXG4gKiBAcGFyYW0gdG9cbiAqIEByZXR1cm5zIHtOdW1iZXJ8Kn1cbiAqL1xuZnVuY3Rpb24gYXJyYXlSZW1vdmUoYXJyYXksIGZyb20sIHRvKSB7XG4gICAgdmFyIHJlc3QgPSBhcnJheS5zbGljZSgodG8gfHwgZnJvbSkgKyAxIHx8IGFycmF5Lmxlbmd0aCk7XG4gICAgYXJyYXkubGVuZ3RoID0gZnJvbSA8IDAgPyBhcnJheS5sZW5ndGggKyBmcm9tIDogZnJvbTtcbiAgICByZXR1cm4gYXJyYXkucHVzaC5hcHBseShhcnJheSwgcmVzdCk7XG59XG4iLCJpbXBvcnQgeyBnZXRMb2NhbFN0b3JhZ2UsIGdldFNlc3Npb25TdG9yYWdlIH0gZnJvbSBcIi4uL3V0aWxzL1V0aWxcIjtcbmltcG9ydCB7IFRyYWlsVHlwZSB9IGZyb20gXCIuL1RyYWlsVHlwZVwiO1xuY29uc3QgVFRMID0gMTAwMCAqIDYwICogNjAgKiAyNCAqIDI7XG5leHBvcnQgY2xhc3MgVHJhaWwge1xuICAgIC8qKlxuICAgICAqXG4gICAgICogQHBhcmFtIHF1ZXJ5UmVzb2x2ZXJcbiAgICAgKiBAcGFyYW0gc2Vzc2lvblJlc29sdmVyXG4gICAgICogQHBhcmFtIHVpZCB0aGUgdW5pcXVlIGlkIG9mIHRoaXMgdHJhaWwuIFVzZWQgYXMgcGFydCBvZiB0aGUga2V5IHRvIHNhdmUgYWxsIFRyYWlsIHN0ZXBzL3BhcnRzXG4gICAgICovXG4gICAgY29uc3RydWN0b3IocXVlcnlSZXNvbHZlciwgc2Vzc2lvblJlc29sdmVyLCB1aWQpIHtcbiAgICAgICAgdGhpcy5xdWVyeVJlc29sdmVyID0gcXVlcnlSZXNvbHZlcjtcbiAgICAgICAgdGhpcy5zZXNzaW9uUmVzb2x2ZXIgPSBzZXNzaW9uUmVzb2x2ZXI7XG4gICAgICAgIHRoaXMua2V5ID0gXCJzZWFyY2gtY29sbGVjdG9yLXRyYWlsXCIgKyAodWlkID8gXCItXCIgKyB1aWQgOiBcIlwiKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IGxvY2FsVHJhaWxzID0gdGhpcy5fbG9hZChnZXRMb2NhbFN0b3JhZ2UoKSk7XG4gICAgICAgICAgICBjb25zdCBub3cgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcbiAgICAgICAgICAgIC8vIERyb3AgYWxsIGV4cGlyZWQgdHJhaWxzLCBUVEwgaW4gc3luYyB3aXRoIHNlc3Npb24gZHVyYXRpb24gb2YgMzAgbWluXG4gICAgICAgICAgICBmb3IgKGxldCBpZCBvZiBPYmplY3Qua2V5cyhsb2NhbFRyYWlscykpIHtcbiAgICAgICAgICAgICAgICBpZiAobm93ID4gbG9jYWxUcmFpbHNbaWRdLnRpbWVzdGFtcCArIFRUTCkge1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgbG9jYWxUcmFpbHNbaWRdO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuX3NhdmUoZ2V0TG9jYWxTdG9yYWdlKCksIGxvY2FsVHJhaWxzKTtcbiAgICAgICAgICAgIC8vIExvYWQgZXhpc3Rpbmcgc2Vzc2lvbiB0cmFpbHMgYW5kIG1lcmdlIGl0IHdpdGggdGhlIGxvY2FsIHN0b3JhZ2UgdHJhaWxzLlxuICAgICAgICAgICAgLy8gVGhpcyBzaG91bGQgZ3VhcmFudGVlIHRoYXQgcmVnYXJkbGVzcyBvZiB3aGV0aGVyIHRoZSBwYWdlcyBmdXJ0aGVyIGRvd24gdGhlIHRyYWlsXG4gICAgICAgICAgICAvLyAoYmFza2V0LCBjaGVja291dCkgd2VyZSBvcGVuIGluIGEgbmV3IHRhYiBvciBub3QsIHdlIGhhdmUgYSBmdWxsIHJlcHJlc2VudGF0aW9uXG4gICAgICAgICAgICAvLyBvZiBhbGwgcHJvZHVjdCBjbGlja3Mgd2l0aGluIHRoZSBzZXNzaW9uLiBSZW1pbmRlciwgc2Vzc2lvblN0b3JhZ2UgaXMgbWFpbnRhaW5lZFxuICAgICAgICAgICAgLy8gcGVyIHRhYi93aW5kb3cgYW5kIGlzIGRlbGV0ZWQgdXBvbiBjbG9zaW5nLCBsb2NhbFN0b3JhZ2UgaXMgcGVyIHdlYnNpdGUgd2l0aCBub1xuICAgICAgICAgICAgLy8gZGVmYXVsdCBleHBpcnkuXG4gICAgICAgICAgICBjb25zdCBzZXNzaW9uVHJhaWxzID0gdGhpcy5fbG9hZChnZXRTZXNzaW9uU3RvcmFnZSgpKTtcbiAgICAgICAgICAgIGNvbnN0IHRyYWlscyA9IE9iamVjdC5hc3NpZ24obG9jYWxUcmFpbHMsIHNlc3Npb25UcmFpbHMpO1xuICAgICAgICAgICAgdGhpcy5fc2F2ZShnZXRTZXNzaW9uU3RvcmFnZSgpLCB0cmFpbHMpO1xuICAgICAgICB9XG4gICAgICAgIGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcIkVycm9yIHBhcnNpbmcgc3RvcmVkIGV2ZW50IHF1ZXVlIFwiICsgZSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLyoqXG4gICAgICogUmVnaXN0ZXIgdGhpcyBwcm9kdWN0IGlkIGFzIHN0YXJ0aW5nIGEgcHVyY2hhc2Ugam91cm5leSBhdCB0aGlzIHNlc3Npb24vcXVlcnlcbiAgICAgKiBQb3NzaWJsZSB0cmFpbCB0eXBlcyBhcmUgXCJtYWluXCIgYW5kIFwiYXNzb2NpYXRlZFwiXG4gICAgICovXG4gICAgcmVnaXN0ZXIoaWQsIHRyYWlsVHlwZSA9IFRyYWlsVHlwZS5NYWluLCBxdWVyeVN0cmluZykge1xuICAgICAgICBjb25zdCB0cmFpbCA9IHtcbiAgICAgICAgICAgIHRpbWVzdGFtcDogbmV3IERhdGUoKS5nZXRUaW1lKCksXG4gICAgICAgICAgICBxdWVyeTogcXVlcnlTdHJpbmcgfHwgdGhpcy5xdWVyeVJlc29sdmVyKCkudG9TdHJpbmcoKSxcbiAgICAgICAgICAgIHR5cGU6IHRyYWlsVHlwZVxuICAgICAgICB9O1xuICAgICAgICBmb3IgKGxldCBzdG9yYWdlIG9mIFtnZXRMb2NhbFN0b3JhZ2UoKSwgZ2V0U2Vzc2lvblN0b3JhZ2UoKV0pIHtcbiAgICAgICAgICAgIGNvbnN0IHRyYWlscyA9IHRoaXMuX2xvYWQoc3RvcmFnZSk7XG4gICAgICAgICAgICB0cmFpbHNbaWRdID0gdHJhaWw7XG4gICAgICAgICAgICB0aGlzLl9zYXZlKHN0b3JhZ2UsIHRyYWlscyk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZmV0Y2goaWQpIHtcbiAgICAgICAgY29uc3QgdHJhaWxzID0gdGhpcy5fbG9hZChnZXRTZXNzaW9uU3RvcmFnZSgpKTtcbiAgICAgICAgcmV0dXJuIHRyYWlsc1tpZF07XG4gICAgfVxuICAgIF9sb2FkKHN0b3JhZ2UpIHtcbiAgICAgICAgY29uc3QgZGF0YSA9IHN0b3JhZ2UuZ2V0SXRlbSh0aGlzLmtleSk7XG4gICAgICAgIHJldHVybiBkYXRhID8gSlNPTi5wYXJzZShkYXRhKSA6IHt9O1xuICAgIH1cbiAgICBfc2F2ZShzdG9yYWdlLCBkYXRhKSB7XG4gICAgICAgIHN0b3JhZ2Uuc2V0SXRlbSh0aGlzLmtleSwgSlNPTi5zdHJpbmdpZnkoZGF0YSkpO1xuICAgIH1cbn1cbiIsImV4cG9ydCB2YXIgVHJhaWxUeXBlO1xuKGZ1bmN0aW9uIChUcmFpbFR5cGUpIHtcbiAgICBUcmFpbFR5cGVbXCJNYWluXCJdID0gXCJtYWluXCI7XG4gICAgVHJhaWxUeXBlW1wiQXNzb2NpYXRlZFwiXSA9IFwiYXNzb2NpYXRlZFwiO1xufSkoVHJhaWxUeXBlIHx8IChUcmFpbFR5cGUgPSB7fSkpO1xuIiwiZXhwb3J0ICogZnJvbSBcIi4vUXVlcnlcIjtcbmV4cG9ydCAqIGZyb20gXCIuL1RyYWlsXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9UcmFpbFR5cGVcIjtcbiIsImltcG9ydCB7IGdlbmVyYXRlSWQsIGdldENvb2tpZSwgZ2V0TG9jYWxTdG9yYWdlLCBzZXRDb29raWUgfSBmcm9tIFwiLi4vdXRpbHMvVXRpbFwiO1xuY29uc3QgTUlOVVRFU19PTkVfREFZID0gNjAgKiAyNDtcbmNvbnN0IE1JTlVURVNfSEFMRl9IT1VSID0gMzA7XG4vKipcbiAqIFJlYWQgdGhlIGNvb2tpZSB3aXRoIHRoZSBwcm92aWRlZCBuYW1lXG4gKiBAcGFyYW0gbmFtZSB0aGUgbmFtZSBvZiB0aGUgY29va2llXG4gKi9cbmV4cG9ydCBjb25zdCBjb29raWVSZXNvbHZlciA9IChuYW1lID0gXCJcIikgPT4gZ2V0Q29va2llKG5hbWUpO1xuLyoqXG4gKiBSZXNvbHZlIHRoZSBpZCBvZiB0aGUgY3VycmVudCBzZWFyY2ggc2Vzc2lvbi4gQSBzZWFyY2ggc2Vzc2lvbiBpcyBkZWZpbmVkIGFzXG4gKiBsaW1pdGVkIHRpbWUgc2xpY2Ugb2Ygc2VhcmNoIGFjdGl2aXR5IGFjcm9zcyBtdWx0aXBsZSB0YWJzLiBCeSBkZWZhdWx0IGEgc2Vzc2lvblxuICogd291bGQgYmUgY29uc2lkZXJlZCBleHBpcmVkIGFmdGVyIDMwIG1pbiBvZiBpbmFjdGl2aXR5LlxuICpcbiAqIEluIGNhc2UgdGhlIHJlc29sdmVyIGlzIGNvbnN0cnVjdGVkIHdpdGggYSBjb29raWUgbmFtZSwgdGhlIHNlc3Npb24gbGlmZWN5Y2xlXG4gKiB3aWxsIGJlIGdvdmVybmVkIGJ5IHRoZSBsaWZlY3ljbGUgb2YgdGhhdCBjb29raWUuIE90aGVyd2lzZSB0aGUgcmVzb2x2ZXIgd2lsbFxuICogc2V0IGl0cyBvd24gY29va2llLlxuICpcbiAqIEBwYXJhbSBuYW1lIHRoZSBuYW1lIG9mIHRoZSBzZXNzaW9uIGNvb2tpZVxuICovXG5leHBvcnQgY29uc3QgY29va2llU2Vzc2lvblJlc29sdmVyID0gKG5hbWUgPSBcIlNlYXJjaENvbGxlY3RvclNlc3Npb25cIikgPT4gc2V0Q29va2llKG5hbWUsIGNvb2tpZVJlc29sdmVyKG5hbWUpIHx8IGdlbmVyYXRlSWQoKSwgTUlOVVRFU19IQUxGX0hPVVIpO1xuLyoqXG4gKiBGaW5kIHRoZSBwb3NpdGlvbiBvZiBhIERPTSBlbGVtZW50IHJlbGF0aXZlIHRvIG90aGVyIERPTSBlbGVtZW50cyBvZiB0aGUgc2FtZSB0eXBlLlxuICogVG8gYmUgdXNlZCB0byBmaW5kIHRoZSBwb3NpdGlvbiBvZiBhbiBpdGVtIGluIGEgc2VhcmNoIHJlc3VsdC5cbiAqXG4gKiBAcGFyYW0gc2VsZWN0b3JFeHByZXNzaW9uIHRoZSBjc3MgZXhwcmVzc2lvbiB0byBxdWVyeSBmb3Igb3RoZXIgZWxlbWVudHNcbiAqIEBwYXJhbSBlbGVtZW50IHRoZSBlbGVtZW50IGZvciB3aGljaCB3ZSB3YW50IHRvIGtub3cgdGhlIHBvc2l0aW9uIHJlbGF0aXZlIHRvIHRoZSBlbGVtZW50cyBzZWxlY3RlZCBieSBzZWxlY3RvckV4cHJlc3Npb25cbiAqL1xuZXhwb3J0IGNvbnN0IHBvc2l0aW9uUmVzb2x2ZXIgPSAoc2VsZWN0b3JFeHByZXNzaW9uLCBlbGVtZW50KSA9PiB7XG4gICAgcmV0dXJuIEFycmF5LmZyb20oZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbChzZWxlY3RvckV4cHJlc3Npb24pKVxuICAgICAgICAucmVkdWNlKChhY2MsIG5vZGUsIGluZGV4KSA9PiBub2RlID09PSBlbGVtZW50ID8gaW5kZXggOiBhY2MsIHVuZGVmaW5lZCk7XG59O1xuLyoqXG4gKiBUaGlzIGlzIGEgcGVyc2lzdGVudCBkZWJ1ZyByZXNvbHZlciB3aGljaCBzdG9yZXMgdGhlIGRlYnVnIHF1ZXJ5IHBhcmFtZXRlciBhY3Jvc3MgcmVxdWVzdHMuXG4gKi9cbmV4cG9ydCBjb25zdCBkZWJ1Z1Jlc29sdmVyID0gKCkgPT4ge1xuICAgIGNvbnN0IERFQlVHX0tFWSA9IFwiX19jb2xsZWN0b3JEZWJ1Z1wiO1xuICAgIGNvbnN0IGRlYnVnUGFyYW0gPSBuZXcgVVJMU2VhcmNoUGFyYW1zKHdpbmRvdy5sb2NhdGlvbi5zZWFyY2gpLmdldChcImRlYnVnXCIpO1xuICAgIGNvbnN0IGlzRGVidWdQYXJhbUV4aXN0cyA9IGRlYnVnUGFyYW0gIT0gbnVsbDtcbiAgICBpZiAoaXNEZWJ1Z1BhcmFtRXhpc3RzKSB7XG4gICAgICAgIGNvbnN0IGRlYnVnID0gZGVidWdQYXJhbSA9PT0gXCJ0cnVlXCI7XG4gICAgICAgIGdldExvY2FsU3RvcmFnZSgpLnNldEl0ZW0oREVCVUdfS0VZLCBTdHJpbmcoZGVidWcpKTtcbiAgICB9XG4gICAgcmV0dXJuIGdldExvY2FsU3RvcmFnZSgpLmdldEl0ZW0oREVCVUdfS0VZKSA9PT0gXCJ0cnVlXCI7XG59O1xuIiwiZXhwb3J0ICogZnJvbSBcIi4vUmVzb2x2ZXJcIjtcbiIsImV4cG9ydCBjbGFzcyBDb250ZXh0IHtcbiAgICBjb25zdHJ1Y3Rvcih3aW5kb3csIGRvY3VtZW50KSB7XG4gICAgICAgIHRoaXMud2luZG93ID0gd2luZG93O1xuICAgICAgICB0aGlzLmRvY3VtZW50ID0gZG9jdW1lbnQ7XG4gICAgfVxuICAgIGdldFdpbmRvdygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMud2luZG93O1xuICAgIH1cbiAgICBnZXREb2N1bWVudCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZG9jdW1lbnQ7XG4gICAgfVxufVxuIiwiZXhwb3J0IHZhciBMaXN0ZW5lclR5cGU7XG4oZnVuY3Rpb24gKExpc3RlbmVyVHlwZSkge1xuICAgIExpc3RlbmVyVHlwZVtcIkRvbVwiXSA9IFwiZG9tXCI7XG4gICAgTGlzdGVuZXJUeXBlW1wiU2VudGluZWxcIl0gPSBcInNlbnRpbmVsXCI7XG59KShMaXN0ZW5lclR5cGUgfHwgKExpc3RlbmVyVHlwZSA9IHt9KSk7XG4iLCJpbXBvcnQgeyBnZXRMb2NhbFN0b3JhZ2UgfSBmcm9tIFwiLi9VdGlsXCI7XG5leHBvcnQgY2xhc3MgTG9jYWxTdG9yYWdlUXVldWUge1xuICAgIGNvbnN0cnVjdG9yKGlkKSB7XG4gICAgICAgIHRoaXMubmFtZSA9IFwic2VhcmNoLWNvbGxlY3Rvci1xdWV1ZVwiICsgKGlkID8gXCItXCIgKyBpZCA6IFwiXCIpO1xuICAgICAgICB0aGlzLnF1ZXVlID0gW107XG4gICAgICAgIGNvbnN0IHN0b3JlZFF1ZXVlID0gZ2V0TG9jYWxTdG9yYWdlKCkuZ2V0SXRlbSh0aGlzLm5hbWUpO1xuICAgICAgICBpZiAoc3RvcmVkUXVldWUpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgdGhpcy5xdWV1ZSA9IEpTT04ucGFyc2Uoc3RvcmVkUXVldWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRXJyb3IgcGFyc2luZyBzdG9yZWQgZXZlbnQgcXVldWUgXCIgKyBlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICBwdXNoKGRhdGEpIHtcbiAgICAgICAgdGhpcy5xdWV1ZS5wdXNoKGRhdGEpO1xuICAgICAgICB0aGlzLl9zYXZlKCk7XG4gICAgfVxuICAgIGRyYWluKCkge1xuICAgICAgICBjb25zdCBidWZmZXIgPSB0aGlzLnF1ZXVlO1xuICAgICAgICB0aGlzLnF1ZXVlID0gW107XG4gICAgICAgIHRoaXMuX3NhdmUoKTtcbiAgICAgICAgcmV0dXJuIGJ1ZmZlcjtcbiAgICB9XG4gICAgdHJhbnNhY3Rpb25hbERyYWluKGFzeW5jQ2FsbGJhY2spIHtcbiAgICAgICAgY29uc3QgYnVmZmVyID0gdGhpcy5xdWV1ZTtcbiAgICAgICAgcmV0dXJuIGFzeW5jQ2FsbGJhY2sodGhpcy5xdWV1ZSlcbiAgICAgICAgICAgIC50aGVuKHJlcyA9PiB7XG4gICAgICAgICAgICB0aGlzLnF1ZXVlID0gW107XG4gICAgICAgICAgICB0aGlzLl9zYXZlKCk7XG4gICAgICAgICAgICByZXR1cm4gYnVmZmVyO1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgc2l6ZSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucXVldWUubGVuZ3RoO1xuICAgIH1cbiAgICBfc2F2ZSgpIHtcbiAgICAgICAgZ2V0TG9jYWxTdG9yYWdlKCkuc2V0SXRlbSh0aGlzLm5hbWUsIEpTT04uc3RyaW5naWZ5KHRoaXMucXVldWUpKTtcbiAgICB9XG59XG4iLCIvKipcbiAqIENsb25lZCBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9tdWljc3Mvc2VudGluZWxqcyB1bnRpbCBhIHBhdGNoZWQgdmVyc2lvblxuICogc3VwcG9yaW5nIGlmcmFtZXMgZ2V0cyBhdmFpbGFibGVcbiAqIExpY2Vuc2UgdW5kZXIgTUlUXG4gKi9cbnZhciBpc0FycmF5ID0gQXJyYXkuaXNBcnJheSwgc2VsZWN0b3JUb0FuaW1hdGlvbk1hcCA9IHt9LCBhbmltYXRpb25DYWxsYmFja3MgPSB7fSwgc3R5bGVFbCwgc3R5bGVTaGVldCwgY3NzUnVsZXM7XG5leHBvcnQgY2xhc3MgU2VudGluZWwge1xuICAgIGNvbnN0cnVjdG9yKGRvYyA9IGRvY3VtZW50KSB7XG4gICAgICAgIHRoaXMuZG9jdW1lbnQgPSBkb2M7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEFkZCB3YXRjaGVyLlxuICAgICAqIEBwYXJhbSB7YXJyYXl9IGNzc1NlbGVjdG9ycyAtIExpc3Qgb2YgQ1NTIHNlbGVjdG9yIHN0cmluZ3NcbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvblxuICAgICAqL1xuICAgIG9uKGNzc1NlbGVjdG9ycywgY2FsbGJhY2spIHtcbiAgICAgICAgaWYgKCFjYWxsYmFjaylcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgLy8gaW5pdGlhbGl6ZSBhbmltYXRpb25zdGFydCBldmVudCBsaXN0ZW5lclxuICAgICAgICBpZiAoIXN0eWxlRWwpIHtcbiAgICAgICAgICAgIHZhciBkb2MgPSB0aGlzLmRvY3VtZW50LCBoZWFkID0gZG9jLmhlYWQ7XG4gICAgICAgICAgICAvLyBhZGQgYW5pbWF0aW9uc3RhcnQgZXZlbnQgbGlzdGVuZXJcbiAgICAgICAgICAgIC8vQHRzLWlnbm9yZVxuICAgICAgICAgICAgZG9jLmFkZEV2ZW50TGlzdGVuZXIoJ2FuaW1hdGlvbnN0YXJ0JywgZnVuY3Rpb24gKGV2LCBjYWxsYmFja3MsIGwsIGkpIHtcbiAgICAgICAgICAgICAgICBjYWxsYmFja3MgPSBhbmltYXRpb25DYWxsYmFja3NbZXYuYW5pbWF0aW9uTmFtZV07XG4gICAgICAgICAgICAgICAgLy8gZXhpdCBpZiBjYWxsYmFja3MgaGF2ZW4ndCBiZWVuIHJlZ2lzdGVyZWRcbiAgICAgICAgICAgICAgICBpZiAoIWNhbGxiYWNrcylcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIC8vIHN0b3Agb3RoZXIgY2FsbGJhY2tzIGZyb20gZmlyaW5nXG4gICAgICAgICAgICAgICAgZXYuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCk7XG4gICAgICAgICAgICAgICAgLy8gaXRlcmF0ZSB0aHJvdWdoIGNhbGxiYWNrc1xuICAgICAgICAgICAgICAgIGwgPSBjYWxsYmFja3MubGVuZ3RoO1xuICAgICAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBsOyBpKyspXG4gICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrc1tpXShldi50YXJnZXQpO1xuICAgICAgICAgICAgfSwgdHJ1ZSk7XG4gICAgICAgICAgICAvLyBhZGQgc3R5bGVzaGVldCB0byBkb2N1bWVudFxuICAgICAgICAgICAgc3R5bGVFbCA9IGRvYy5jcmVhdGVFbGVtZW50KCdzdHlsZScpO1xuICAgICAgICAgICAgaGVhZC5pbnNlcnRCZWZvcmUoc3R5bGVFbCwgaGVhZC5maXJzdENoaWxkKTtcbiAgICAgICAgICAgIHN0eWxlU2hlZXQgPSBzdHlsZUVsLnNoZWV0O1xuICAgICAgICAgICAgY3NzUnVsZXMgPSBzdHlsZVNoZWV0LmNzc1J1bGVzO1xuICAgICAgICB9XG4gICAgICAgIC8vIGxpc3RpZnkgYXJndW1lbnQgYW5kIGFkZCBjc3MgcnVsZXMvIGNhY2hlIGNhbGxiYWNrc1xuICAgICAgICAoaXNBcnJheShjc3NTZWxlY3RvcnMpID8gY3NzU2VsZWN0b3JzIDogW2Nzc1NlbGVjdG9yc10pXG4gICAgICAgICAgICAubWFwKGZ1bmN0aW9uIChzZWxlY3RvciwgYW5pbUlkLCBpc0N1c3RvbU5hbWUpIHtcbiAgICAgICAgICAgIGFuaW1JZCA9IHNlbGVjdG9yVG9BbmltYXRpb25NYXBbc2VsZWN0b3JdO1xuICAgICAgICAgICAgaWYgKCFhbmltSWQpIHtcbiAgICAgICAgICAgICAgICAvL0B0cy1pZ25vcmVcbiAgICAgICAgICAgICAgICBpc0N1c3RvbU5hbWUgPSBzZWxlY3RvclswXSA9PSAnISc7XG4gICAgICAgICAgICAgICAgLy8gZGVmaW5lIGFuaW1hdGlvbiBuYW1lIGFuZCBhZGQgdG8gbWFwXG4gICAgICAgICAgICAgICAgc2VsZWN0b3JUb0FuaW1hdGlvbk1hcFtzZWxlY3Rvcl0gPSBhbmltSWQgPVxuICAgICAgICAgICAgICAgICAgICBpc0N1c3RvbU5hbWUgPyBzZWxlY3Rvci5zbGljZSgxKSA6ICdzZW50aW5lbC0nICtcbiAgICAgICAgICAgICAgICAgICAgICAgIE1hdGgucmFuZG9tKCkudG9TdHJpbmcoMTYpLnNsaWNlKDIpO1xuICAgICAgICAgICAgICAgIC8vIGFkZCBrZXlmcmFtZSBydWxlXG4gICAgICAgICAgICAgICAgY3NzUnVsZXNbc3R5bGVTaGVldC5pbnNlcnRSdWxlKCdAa2V5ZnJhbWVzICcgKyBhbmltSWQgK1xuICAgICAgICAgICAgICAgICAgICAne2Zyb217dHJhbnNmb3JtOm5vbmU7fXRve3RyYW5zZm9ybTpub25lO319JywgY3NzUnVsZXMubGVuZ3RoKV1cbiAgICAgICAgICAgICAgICAgICAgLl9pZCA9IHNlbGVjdG9yO1xuICAgICAgICAgICAgICAgIC8vIGFkZCBzZWxlY3RvciBhbmltYXRpb24gcnVsZVxuICAgICAgICAgICAgICAgIGlmICghaXNDdXN0b21OYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIGNzc1J1bGVzW3N0eWxlU2hlZXQuaW5zZXJ0UnVsZShzZWxlY3RvciArICd7YW5pbWF0aW9uLWR1cmF0aW9uOjAuMDAwMXM7YW5pbWF0aW9uLW5hbWU6JyArXG4gICAgICAgICAgICAgICAgICAgICAgICBhbmltSWQgKyAnO30nLCBjc3NSdWxlcy5sZW5ndGgpXVxuICAgICAgICAgICAgICAgICAgICAgICAgLl9pZCA9IHNlbGVjdG9yO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBhZGQgdG8gbWFwXG4gICAgICAgICAgICAgICAgc2VsZWN0b3JUb0FuaW1hdGlvbk1hcFtzZWxlY3Rvcl0gPSBhbmltSWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBhZGQgdG8gY2FsbGJhY2tzXG4gICAgICAgICAgICAoYW5pbWF0aW9uQ2FsbGJhY2tzW2FuaW1JZF0gPSBhbmltYXRpb25DYWxsYmFja3NbYW5pbUlkXSB8fCBbXSlcbiAgICAgICAgICAgICAgICAucHVzaChjYWxsYmFjayk7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBSZW1vdmUgd2F0Y2hlci5cbiAgICAgKiBAcGFyYW0ge2FycmF5fSBjc3NTZWxlY3RvcnMgLSBMaXN0IG9mIENTUyBzZWxlY3RvciBzdHJpbmdzXG4gICAgICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gKG9wdGlvbmFsKVxuICAgICAqL1xuICAgIG9mZihjc3NTZWxlY3RvcnMsIGNhbGxiYWNrKSB7XG4gICAgICAgIC8vIGxpc3RpZnkgYXJndW1lbnQgYW5kIGl0ZXJhdGUgdGhyb3VnaCBydWxlc1xuICAgICAgICAoaXNBcnJheShjc3NTZWxlY3RvcnMpID8gY3NzU2VsZWN0b3JzIDogW2Nzc1NlbGVjdG9yc10pXG4gICAgICAgICAgICAvL0B0cy1pZ25vcmVcbiAgICAgICAgICAgIC5tYXAoZnVuY3Rpb24gKHNlbGVjdG9yLCBhbmltSWQsIGNhbGxiYWNrTGlzdCwgaSkge1xuICAgICAgICAgICAgLy8gZ2V0IGFuaW1JZFxuICAgICAgICAgICAgaWYgKCEoYW5pbUlkID0gc2VsZWN0b3JUb0FuaW1hdGlvbk1hcFtzZWxlY3Rvcl0pKVxuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIC8vIGdldCBjYWxsYmFja3NcbiAgICAgICAgICAgIGNhbGxiYWNrTGlzdCA9IGFuaW1hdGlvbkNhbGxiYWNrc1thbmltSWRdO1xuICAgICAgICAgICAgLy8gcmVtb3ZlIGNhbGxiYWNrIGZyb20gbGlzdFxuICAgICAgICAgICAgaWYgKGNhbGxiYWNrKSB7XG4gICAgICAgICAgICAgICAgaSA9IGNhbGxiYWNrTGlzdC5sZW5ndGg7XG4gICAgICAgICAgICAgICAgd2hpbGUgKGktLSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoY2FsbGJhY2tMaXN0W2ldID09PSBjYWxsYmFjaylcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrTGlzdC5zcGxpY2UoaSwgMSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2tMaXN0ID0gW107XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBleGl0IGlmIGNhbGxiYWNrcyBzdGlsbCBleGlzdFxuICAgICAgICAgICAgaWYgKGNhbGxiYWNrTGlzdC5sZW5ndGgpXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgLy8gY2xlYXIgY2FjaGUgYW5kIHJlbW92ZSBjc3MgcnVsZXNcbiAgICAgICAgICAgIGkgPSBjc3NSdWxlcy5sZW5ndGg7XG4gICAgICAgICAgICB3aGlsZSAoaS0tKSB7XG4gICAgICAgICAgICAgICAgaWYgKGNzc1J1bGVzW2ldLl9pZCA9PSBzZWxlY3RvcilcbiAgICAgICAgICAgICAgICAgICAgc3R5bGVTaGVldC5kZWxldGVSdWxlKGkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZGVsZXRlIHNlbGVjdG9yVG9BbmltYXRpb25NYXBbc2VsZWN0b3JdO1xuICAgICAgICAgICAgZGVsZXRlIGFuaW1hdGlvbkNhbGxiYWNrc1thbmltSWRdO1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogUmVzZXQgd2F0Y2hlcnMgYW5kIGNhY2hlXG4gICAgICovXG4gICAgcmVzZXQoKSB7XG4gICAgICAgIHNlbGVjdG9yVG9BbmltYXRpb25NYXAgPSB7fTtcbiAgICAgICAgYW5pbWF0aW9uQ2FsbGJhY2tzID0ge307XG4gICAgICAgIGlmIChzdHlsZUVsKVxuICAgICAgICAgICAgc3R5bGVFbC5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKHN0eWxlRWwpO1xuICAgICAgICBzdHlsZUVsID0gMDtcbiAgICB9XG59XG4iLCIvKipcbiAqIFBhcnNlIHRoZSBicm93c2VyIHF1ZXJ5IHN0cmluZyBvciB0aGUgcGFzc2VkIHN0cmluZyBpbnRvIGEgamF2YXNjcmlwdCBvYmplY3RcbiAqIHdpdGgga2V5cyB0aGUgcXVlcnkgcGFyYW1ldGVyIG5hbWVzIGFuZCB2YWx1ZXMgdGhlIGNvcnJlc3BvbmRpbmcgdmFsdWVzLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBxdWVyeVN0cmluZyAtIHRoZSBxdWVyeSBzdHJpbmcgdG8gcGFyc2UsIHdpbmRvdy5sb2NhdGlvbi5zZWFyY2ggaWYgbm90IGF2YWlsYWJsZVxuICogQHJldHVybiB7b2JqZWN0fVxuICovXG5leHBvcnQgY29uc3QgcGFyc2VRdWVyeVN0cmluZyA9IChxdWVyeVN0cmluZyA9IHdpbmRvdy5sb2NhdGlvbi5zZWFyY2gpID0+IHtcbiAgICByZXR1cm4gbmV3IFVSTFNlYXJjaFBhcmFtcyhxdWVyeVN0cmluZyk7XG59O1xuLyoqXG4gKiBTb21lIGJyb3dzZXIgbGlrZSBTYWZhcmkgcHJldmVudCBhY2Nlc3NpbmcgbG9jYWxTdG9yYWdlIGluIHByaXZhdGUgbW9kZSBieSB0aHJvd2luZyBleGNlcHRpb25zLlxuICogVXNlIHRoaXMgbWV0aG9kIHRvIHJldHJpZXZlIGEgbW9jayBpbXBsIHdoaWNoIHdpbGwgYXQgbGVhc3QgcHJldmVudCBlcnJvcnMuXG4gKi9cbmV4cG9ydCBjb25zdCBnZXRMb2NhbFN0b3JhZ2UgPSAoKSA9PiB7XG4gICAgaWYgKFwibG9jYWxTdG9yYWdlXCIgaW4gd2luZG93KSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBsb2NhbFN0b3JhZ2UuZ2V0SXRlbShcImFiY1wiKTsgLy8gYWNjZXNzIGxvY2FsU3RvcmFnZSB0byB0cmlnZ2VyIGluY29nbml0byBtb2RlIGV4Y2VwdGlvbnNcbiAgICAgICAgICAgIHJldHVybiBsb2NhbFN0b3JhZ2U7XG4gICAgICAgIH1cbiAgICAgICAgY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoZSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGNvb2tpZVN0b3JhZ2UoNTI1NjAwLCBcIl9fbG9jYWxTdG9yYWdlTW9ja19fX1wiKTtcbn07XG4vKipcbiAqIFVSTCBzYWZlIGJhc2U2NCBlbmNvZGluZ1xuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHIgLSBUaGUgc3RyaW5nIHRvIGJlIGVuY29kZWQsIG9ubHkgQVNDSUkvSVNPLTg4NTktMSBzdXBwb3J0ZWRcbiAqL1xuZXhwb3J0IGNvbnN0IGJhc2U2NEVuY29kZSA9IChzdHIpID0+IHtcbiAgICAvLyBOb3RlLCArIHJlcGxhY2VkIHdpdGggLSwgLyByZXBsYWNlZCB3aXRoIF9cbiAgICBjb25zdCBiNjQgPSBcIkFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5LV89XCI7XG4gICAgbGV0IG8xLCBvMiwgbzMsIGJpdHMsIGgxLCBoMiwgaDMsIGg0LCBlID0gW10sIHBhZCA9ICcnLCBjO1xuICAgIGMgPSBzdHIubGVuZ3RoICUgMzsgLy8gcGFkIHN0cmluZyB0byBsZW5ndGggb2YgbXVsdGlwbGUgb2YgM1xuICAgIGlmIChjID4gMCkge1xuICAgICAgICB3aGlsZSAoYysrIDwgMykge1xuICAgICAgICAgICAgcGFkICs9ICc9JztcbiAgICAgICAgICAgIHN0ciArPSAnXFwwJztcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBub3RlOiBkb2luZyBwYWRkaW5nIGhlcmUgc2F2ZXMgdXMgZG9pbmcgc3BlY2lhbC1jYXNlIHBhY2tpbmcgZm9yIHRyYWlsaW5nIDEgb3IgMiBjaGFyc1xuICAgIGZvciAoYyA9IDA7IGMgPCBzdHIubGVuZ3RoOyBjICs9IDMpIHsgLy8gcGFjayB0aHJlZSBvY3RldHMgaW50byBmb3VyIGhleGV0c1xuICAgICAgICBvMSA9IHN0ci5jaGFyQ29kZUF0KGMpO1xuICAgICAgICBvMiA9IHN0ci5jaGFyQ29kZUF0KGMgKyAxKTtcbiAgICAgICAgbzMgPSBzdHIuY2hhckNvZGVBdChjICsgMik7XG4gICAgICAgIGJpdHMgPSBvMSA8PCAxNiB8IG8yIDw8IDggfCBvMztcbiAgICAgICAgaDEgPSBiaXRzID4+IDE4ICYgMHgzZjtcbiAgICAgICAgaDIgPSBiaXRzID4+IDEyICYgMHgzZjtcbiAgICAgICAgaDMgPSBiaXRzID4+IDYgJiAweDNmO1xuICAgICAgICBoNCA9IGJpdHMgJiAweDNmO1xuICAgICAgICAvLyB1c2UgaGV4dGV0cyB0byBpbmRleCBpbnRvIGNvZGUgc3RyaW5nXG4gICAgICAgIGVbYyAvIDNdID0gYjY0LmNoYXJBdChoMSkgKyBiNjQuY2hhckF0KGgyKSArIGI2NC5jaGFyQXQoaDMpICsgYjY0LmNoYXJBdChoNCk7XG4gICAgfVxuICAgIHN0ciA9IGUuam9pbignJyk7IC8vIHVzZSBBcnJheS5qb2luKCkgZm9yIGJldHRlciBwZXJmb3JtYW5jZSB0aGFuIHJlcGVhdGVkIHN0cmluZyBhcHBlbmRzXG4gICAgLy8gcmVwbGFjZSAnQSdzIGZyb20gcGFkZGVkIG51bGxzIHdpdGggJz0nc1xuICAgIHN0ciA9IHN0ci5zbGljZSgwLCBzdHIubGVuZ3RoIC0gcGFkLmxlbmd0aCkgKyBwYWQ7XG4gICAgcmV0dXJuIHN0cjtcbn07XG5leHBvcnQgY29uc3QgZ2VuZXJhdGVJZCA9ICgpID0+IHtcbiAgICBjb25zdCBwb3NzaWJsZSA9IFwiQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODlcIjtcbiAgICBsZXQgdGV4dCA9IFwiXCI7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCA3OyBpKyspIHtcbiAgICAgICAgdGV4dCArPSBwb3NzaWJsZS5jaGFyQXQoTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogcG9zc2libGUubGVuZ3RoKSk7XG4gICAgfVxuICAgIHJldHVybiB0ZXh0O1xufTtcbmV4cG9ydCBjb25zdCBnZXRTZXNzaW9uU3RvcmFnZSA9ICgpID0+IHtcbiAgICBpZiAoXCJzZXNzaW9uU3RvcmFnZVwiIGluIHdpbmRvdykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgc2Vzc2lvblN0b3JhZ2UuZ2V0SXRlbShcImFiY1wiKTsgLy8gYWNjZXNzIHNlc3Npb25TdG9yYWdlIHRvIHRyaWdnZXIgaW5jb2duaXRvIG1vZGUgZXhjZXB0aW9uc1xuICAgICAgICAgICAgcmV0dXJuIHNlc3Npb25TdG9yYWdlO1xuICAgICAgICB9XG4gICAgICAgIGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGUpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBjb29raWVTdG9yYWdlKHZvaWQgMCwgXCJfX3Nlc3Npb25TdG9yYWdlTW9ja19fX1wiKTtcbn07XG5mdW5jdGlvbiBjb29raWVTdG9yYWdlKHR0bE1pbnV0ZXMsIHN0b3JhZ2VOYW1lKSB7XG4gICAgY29uc3QgTE9DQUxfU1RPUkFHRV9DT09LSUVfTkFNRSA9IHN0b3JhZ2VOYW1lO1xuICAgIGZ1bmN0aW9uIGdldFN0b3JhZ2VGcm9tQ29va2llKCkge1xuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShnZXRDb29raWUoTE9DQUxfU1RPUkFHRV9DT09LSUVfTkFNRSkgfHwgXCJ7fVwiKTtcbiAgICB9XG4gICAgZnVuY3Rpb24gc2F2ZVN0b3JhZ2VUb0Nvb2tpZShkYXRhKSB7XG4gICAgICAgIHNldENvb2tpZShMT0NBTF9TVE9SQUdFX0NPT0tJRV9OQU1FLCBkYXRhLCB0dGxNaW51dGVzKTsgLy8gb25lIHllYXJcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgICAgZ2V0SXRlbShrZXkpIHtcbiAgICAgICAgICAgIHJldHVybiBnZXRTdG9yYWdlRnJvbUNvb2tpZSgpW2tleV0gfHwgbnVsbDtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0SXRlbShrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICBjb25zdCBsb2NhbFN0b3JhZ2VTdGF0ZSA9IGdldFN0b3JhZ2VGcm9tQ29va2llKCk7XG4gICAgICAgICAgICBsb2NhbFN0b3JhZ2VTdGF0ZVtrZXldID0gdmFsdWU7XG4gICAgICAgICAgICBzYXZlU3RvcmFnZVRvQ29va2llKEpTT04uc3RyaW5naWZ5KGxvY2FsU3RvcmFnZVN0YXRlKSk7XG4gICAgICAgIH0sXG4gICAgICAgIHJlbW92ZUl0ZW0oa2V5KSB7XG4gICAgICAgICAgICBjb25zdCBsb2NhbFN0b3JhZ2VTdGF0ZSA9IGdldFN0b3JhZ2VGcm9tQ29va2llKCk7XG4gICAgICAgICAgICBkZWxldGUgbG9jYWxTdG9yYWdlU3RhdGVba2V5XTtcbiAgICAgICAgICAgIHNhdmVTdG9yYWdlVG9Db29raWUoSlNPTi5zdHJpbmdpZnkobG9jYWxTdG9yYWdlU3RhdGUpKTtcbiAgICAgICAgfSxcbiAgICAgICAgY2xlYXIoKSB7XG4gICAgICAgICAgICBjb25zdCBsb2NhbFN0b3JhZ2VTdGF0ZSA9IHt9O1xuICAgICAgICAgICAgc2F2ZVN0b3JhZ2VUb0Nvb2tpZShKU09OLnN0cmluZ2lmeShsb2NhbFN0b3JhZ2VTdGF0ZSkpO1xuICAgICAgICB9LFxuICAgICAgICBrZXkobikge1xuICAgICAgICAgICAgY29uc3QgbG9jYWxTdG9yYWdlU3RhdGUgPSBnZXRTdG9yYWdlRnJvbUNvb2tpZSgpO1xuICAgICAgICAgICAgY29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKGxvY2FsU3RvcmFnZVN0YXRlKTtcbiAgICAgICAgICAgIGlmIChuID4ga2V5cy5sZW5ndGggLSAxKVxuICAgICAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICAgICAgcmV0dXJuIGtleXNbbl07XG4gICAgICAgIH0sXG4gICAgICAgIGdldCBsZW5ndGgoKSB7XG4gICAgICAgICAgICBjb25zdCBsb2NhbFN0b3JhZ2VTdGF0ZSA9IGdldFN0b3JhZ2VGcm9tQ29va2llKCk7XG4gICAgICAgICAgICByZXR1cm4gT2JqZWN0LmtleXMobG9jYWxTdG9yYWdlU3RhdGUpLmxlbmd0aDtcbiAgICAgICAgfVxuICAgIH07XG59XG5leHBvcnQgY29uc3Qgc2V0Q29va2llID0gKG5hbWUsIHZhbHVlLCB0dGxNaW51dGVzKSA9PiB7XG4gICAgbGV0IGV4cGlyZXMgPSBcIlwiO1xuICAgIGlmICh0dGxNaW51dGVzKSB7XG4gICAgICAgIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZSgpO1xuICAgICAgICBkYXRlLnNldFRpbWUoZGF0ZS5nZXRUaW1lKCkgKyAodHRsTWludXRlcyAqIDYwICogMTAwMCkpO1xuICAgICAgICBleHBpcmVzID0gXCI7IGV4cGlyZXM9XCIgKyBkYXRlLnRvVVRDU3RyaW5nKCk7XG4gICAgfVxuICAgIC8vIEhhbmRsZSB0aGUgdXBjb21pbmcgZm9yY2VkIHN3aXRjaCB0byBTYW1lU2l0ZSAmIFNlY3VyZSBwYXJhbXMgaHR0cHM6Ly93d3cuY2hyb21lc3RhdHVzLmNvbS9mZWF0dXJlLzU2MzM1MjE2MjIxODgwMzJcbiAgICAvLyBTaW5jZSB0aGlzIGlzIGEgZ2VuZXJpYyBsaWJyYXJ5LCB3ZSBjYW4ndCByZXN0cmljdCB0aGUgZG9tYWluIHVuZGVyIHdoaWNoIGl0J3MgYmVlaW5nIHNlcnZlZCwgdGh1cyBub3Qgc2V0dGluZyBkb21haW5cbiAgICAvLyBmb3IgdGhlIGNvb2tpZS4gSXQncyB1c3VhbGx5IGxvYWRlZCBhbmQgc3Vic2VxdWVudGx5IHJlcXVlc3RlZCBmcm9tIGEgdGhpcmQtcGFydHkgZG9tYWluLCB0aHVzIHdlIG5lZWQgdG8gc3BlY2lmeSBTYW1lU2l0ZT1Ob25lIHdoaWNoXG4gICAgLy8gcGVyIHRoZSBsYXRlc3Qgc3BlY2lmaWNhdGlvbnMgcmVxdWlyZXMgdGhlIFNlY3VyZSBhdHRyaWJ1dGUuXG4gICAgLy9cbiAgICAvLyBUbyBhbGxvdyBsb2NhbCBkZWJ1Z2dpbmcsIHdlIHdvbid0IHNldCB0aGVzZSB3aGVuIGxvYWRlZCBvbiBsb2NhbGhvc3QuIE5vdGUsIGFmdGVyIHRoaXMgY2hhbmdlLCB5b3Ugd29uJ3QgYmUgYWJsZSB0byBzZXJ2ZVxuICAgIC8vIHRoZSBjb2xsZWN0b3IgdG8gcmVhbCBjbGllbnRzIG92ZXIgbm9uLWh0dHBzIGNvbm5lY3Rpb25zIC0gdGhlIHNlc3Npb24gY29va2llcyB3b24ndCBtYXRjaFxuICAgIGNvbnN0IHNhbWVTaXRlID0gd2luZG93LmxvY2F0aW9uLmhvc3RuYW1lID09PSBcImxvY2FsaG9zdFwiID8gXCJcIiA6IFwiOyBTYW1lU2l0ZT1Ob25lOyBTZWN1cmVcIjtcbiAgICBkb2N1bWVudC5jb29raWUgPSBuYW1lICsgXCI9XCIgKyAodmFsdWUgfHwgXCJcIikgKyBleHBpcmVzICsgXCI7IHBhdGg9L1wiICsgc2FtZVNpdGU7XG4gICAgcmV0dXJuIHZhbHVlO1xufTtcbmV4cG9ydCBjb25zdCBnZXRDb29raWUgPSAoY25hbWUpID0+IHtcbiAgICBjb25zdCBuYW1lID0gY25hbWUgKyBcIj1cIjtcbiAgICBjb25zdCBkZWNvZGVkQ29va2llID0gZGVjb2RlVVJJQ29tcG9uZW50KGRvY3VtZW50LmNvb2tpZSk7XG4gICAgY29uc3QgY2EgPSBkZWNvZGVkQ29va2llLnNwbGl0KCc7Jyk7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjYS5sZW5ndGg7IGkrKykge1xuICAgICAgICBsZXQgYyA9IGNhW2ldO1xuICAgICAgICB3aGlsZSAoYy5jaGFyQXQoMCkgPT0gJyAnKSB7XG4gICAgICAgICAgICBjID0gYy5zdWJzdHJpbmcoMSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGMuaW5kZXhPZihuYW1lKSA9PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4gYy5zdWJzdHJpbmcobmFtZS5sZW5ndGgsIGMubGVuZ3RoKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gXCJcIjtcbn07XG4vKipcbiAqIFJldHVybnMgYSBmdW5jdGlvbiwgdGhhdCwgYXMgbG9uZyBhcyBpdCBjb250aW51ZXMgdG8gYmUgaW52b2tlZCwgd2lsbCBub3RcbiAqIGJlIHRyaWdnZXJlZC4gVGhlIGZ1bmN0aW9uIHdpbGwgYmUgY2FsbGVkIGFmdGVyIGl0IHN0b3BzIGJlaW5nIGNhbGxlZCBmb3JcbiAqIE4gbWlsbGlzZWNvbmRzLiBJZiBgaW1tZWRpYXRlYCBpcyBwYXNzZWQsIHRyaWdnZXIgdGhlIGZ1bmN0aW9uIG9uIHRoZVxuICogbGVhZGluZyBlZGdlLCBpbnN0ZWFkIG9mIHRoZSB0cmFpbGluZy4gVGhlIGZ1bmN0aW9uIGFsc28gaGFzIGEgcHJvcGVydHkgJ2NsZWFyJ1xuICogdGhhdCBpcyBhIGZ1bmN0aW9uIHdoaWNoIHdpbGwgY2xlYXIgdGhlIHRpbWVyIHRvIHByZXZlbnQgcHJldmlvdXNseSBzY2hlZHVsZWQgZXhlY3V0aW9ucy5cbiAqXG4gKiBAc291cmNlIHVuZGVyc2NvcmUuanNcbiAqIEBzZWUgaHR0cDovL3Vuc2NyaXB0YWJsZS5jb20vMjAwOS8wMy8yMC9kZWJvdW5jaW5nLWphdmFzY3JpcHQtbWV0aG9kcy9cbiAqIEBwYXJhbSBmdW5jIHtGdW5jdGlvbn0gZnVuY3Rpb24gdG8gd3JhcFxuICogQHBhcmFtIHdhaXQge051bWJlcn0gdGltZW91dCBpbiBtcyAoYDEwMGApXG4gKiBAcGFyYW0gaW1tZWRpYXRlIHtCb29sZWFufSB3aGV0aGVyIHRvIGV4ZWN1dGUgYXQgdGhlIGJlZ2lubmluZyAoYGZhbHNlYClcbiAqIEBhcGkgcHVibGljXG4gKi9cbmV4cG9ydCBjb25zdCBkZWJvdW5jZSA9IChmdW5jLCB3YWl0ID0gMTAwLCBpbW1lZGlhdGUgPSBmYWxzZSkgPT4ge1xuICAgIHZhciB0aW1lb3V0LCBhcmdzLCBjb250ZXh0LCB0aW1lc3RhbXAsIHJlc3VsdDtcbiAgICBmdW5jdGlvbiBsYXRlcigpIHtcbiAgICAgICAgdmFyIGxhc3QgPSBEYXRlLm5vdygpIC0gdGltZXN0YW1wO1xuICAgICAgICBpZiAobGFzdCA8IHdhaXQgJiYgbGFzdCA+PSAwKSB7XG4gICAgICAgICAgICB0aW1lb3V0ID0gc2V0VGltZW91dChsYXRlciwgd2FpdCAtIGxhc3QpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGltZW91dCA9IG51bGw7XG4gICAgICAgICAgICBpZiAoIWltbWVkaWF0ZSkge1xuICAgICAgICAgICAgICAgIHJlc3VsdCA9IGZ1bmMuYXBwbHkoY29udGV4dCwgYXJncyk7XG4gICAgICAgICAgICAgICAgY29udGV4dCA9IGFyZ3MgPSBudWxsO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIGNvbnN0IGRlYm91bmNlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29udGV4dCA9IHRoaXM7XG4gICAgICAgIGFyZ3MgPSBhcmd1bWVudHM7XG4gICAgICAgIHRpbWVzdGFtcCA9IERhdGUubm93KCk7XG4gICAgICAgIHZhciBjYWxsTm93ID0gaW1tZWRpYXRlICYmICF0aW1lb3V0O1xuICAgICAgICBpZiAoIXRpbWVvdXQpXG4gICAgICAgICAgICB0aW1lb3V0ID0gc2V0VGltZW91dChsYXRlciwgd2FpdCk7XG4gICAgICAgIGlmIChjYWxsTm93KSB7XG4gICAgICAgICAgICByZXN1bHQgPSBmdW5jLmFwcGx5KGNvbnRleHQsIGFyZ3MpO1xuICAgICAgICAgICAgY29udGV4dCA9IGFyZ3MgPSBudWxsO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfTtcbiAgICBkZWJvdW5jZWQuY2xlYXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICh0aW1lb3V0KSB7XG4gICAgICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dCk7XG4gICAgICAgICAgICB0aW1lb3V0ID0gbnVsbDtcbiAgICAgICAgfVxuICAgIH07XG4gICAgZGVib3VuY2VkLmZsdXNoID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodGltZW91dCkge1xuICAgICAgICAgICAgcmVzdWx0ID0gZnVuYy5hcHBseShjb250ZXh0LCBhcmdzKTtcbiAgICAgICAgICAgIGNvbnRleHQgPSBhcmdzID0gbnVsbDtcbiAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcbiAgICAgICAgICAgIHRpbWVvdXQgPSBudWxsO1xuICAgICAgICB9XG4gICAgfTtcbiAgICByZXR1cm4gZGVib3VuY2VkO1xufTtcbiIsImV4cG9ydCAqIGZyb20gXCIuL0NvbnRleHRcIjtcbmV4cG9ydCAqIGZyb20gXCIuL0xpc3RlbmVyVHlwZVwiO1xuZXhwb3J0ICogZnJvbSBcIi4vTG9jYWxTdG9yYWdlUXVldWVcIjtcbmV4cG9ydCAqIGZyb20gXCIuL1NlbnRpbmVsXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9VdGlsXCI7XG4iLCJpbXBvcnQgeyBiYXNlNjRFbmNvZGUgfSBmcm9tIFwiLi4vdXRpbHNcIjtcbmV4cG9ydCBjbGFzcyBCYXNlNjRFbmNvZGVXcml0ZXIge1xuICAgIGNvbnN0cnVjdG9yKGRlbGVnYXRlKSB7XG4gICAgICAgIHRoaXMuZGVsZWdhdGUgPSBkZWxlZ2F0ZTtcbiAgICB9XG4gICAgd3JpdGUoZGF0YSkge1xuICAgICAgICBjb25zdCBkID0gSlNPTi5zdHJpbmdpZnkoZGF0YSk7XG4gICAgICAgIHRoaXMuZGVsZWdhdGUud3JpdGUoYmFzZTY0RW5jb2RlKGVuY29kZVVSSUNvbXBvbmVudChkKSkpO1xuICAgIH1cbn1cbiIsImV4cG9ydCBjbGFzcyBCcm93c2VyVHJhY2tpbmdXcml0ZXIge1xuICAgIGNvbnN0cnVjdG9yKGRlbGVnYXRlLCBvcHRpb25zKSB7XG4gICAgICAgIHRoaXMuZGVsZWdhdGUgPSBkZWxlZ2F0ZTtcbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcbiAgICB9XG4gICAgd3JpdGUoZGF0YSkge1xuICAgICAgICBjb25zdCB7IHJlY29yZFVybCwgcmVjb3JkUmVmZXJyZXIsIHJlY29yZExhbmd1YWdlIH0gPSB0aGlzLm9wdGlvbnM7XG4gICAgICAgIGlmIChyZWNvcmRVcmwgJiYgIWRhdGEudXJsKVxuICAgICAgICAgICAgZGF0YS51cmwgPSB0aGlzLmdldFdpbmRvdygpLmxvY2F0aW9uLmhyZWY7XG4gICAgICAgIGlmIChyZWNvcmRSZWZlcnJlciAmJiAhZGF0YS5yZWYpXG4gICAgICAgICAgICBkYXRhLnJlZiA9IHRoaXMuZ2V0RG9jdW1lbnQoKS5yZWZlcnJlcjtcbiAgICAgICAgaWYgKHJlY29yZExhbmd1YWdlICYmICFkYXRhLmxhbmcpXG4gICAgICAgICAgICBkYXRhLmxhbmcgPSB0aGlzLmdldFdpbmRvdygpLm5hdmlnYXRvci5sYW5ndWFnZTtcbiAgICAgICAgdGhpcy5kZWxlZ2F0ZS53cml0ZShkYXRhKTtcbiAgICB9XG4gICAgZ2V0RG9jdW1lbnQoKSB7XG4gICAgICAgIGNvbnN0IHsgY29udGV4dCB9ID0gdGhpcy5vcHRpb25zO1xuICAgICAgICByZXR1cm4gY29udGV4dCA/IGNvbnRleHQuZ2V0RG9jdW1lbnQoKSA6IGRvY3VtZW50O1xuICAgIH1cbiAgICBnZXRXaW5kb3coKSB7XG4gICAgICAgIGNvbnN0IHsgY29udGV4dCB9ID0gdGhpcy5vcHRpb25zO1xuICAgICAgICByZXR1cm4gY29udGV4dCA/IGNvbnRleHQuZ2V0V2luZG93KCkgOiB3aW5kb3c7XG4gICAgfVxufVxuIiwiaW1wb3J0IHsgTG9jYWxTdG9yYWdlUXVldWUgfSBmcm9tIFwiLi4vdXRpbHMvTG9jYWxTdG9yYWdlUXVldWVcIjtcbi8qKlxuICogQSB3cml0ZXIgdGhhdCBidWZmZXJzIHRoZSBpbmNvbWluZyBldmVudHMgaW4gYSBsb2NhbCBzdG9yYWdlIHF1ZXVlIGFuZCB3cml0ZXNcbiAqIHRoZW0gb3V0IGluIGJhdGNoZXMgZXZlcnkgc2Vjb25kLiBJZiB0aGUgcXVldWUgaXMgbm90IGVtcHR5LCB3aGVuIHRoZSB0aW1lciB0aWNrc1xuICogdGhlIHdyaXRlciB3aWxsIHNlbmQgdGhlIGF2YWlsYWJsZSBkYXRhIHJlZ2FyZGxlc3Mgb2Ygd2hldGhlciB0aGVyZSBhcmUgY29sbGVjdG9yIGV2ZW50cyBpLmUuXG4gKiBldmVuIGluIHRpbWVzIG9mIGluYWN0aXZpdHkgb3Igd2hlbiBsb2FkaW5nIHRoZSBwYWdlIGFuZCBwcmV2aW91cyBzdGF0ZSBpcyBhdmFpbGFibGUuXG4gKlxuICogVGhlIHdyaXRlciB3aWxsIGFsc28gdHJ5IHRvIHNlbmQgdGhlIGF2YWlsYWJsZSBkYXRhIG9uIGJyb3dzZXIgdW5sb2FkIGV2ZW50LlxuICovXG5leHBvcnQgY2xhc3MgQnVmZmVyaW5nV3JpdGVyIHtcbiAgICBjb25zdHJ1Y3RvcihkZWxlZ2F0ZSwgaWQsIHRpbWVyTXMgPSAxMDAwKSB7XG4gICAgICAgIHRoaXMuZGVsZWdhdGUgPSBkZWxlZ2F0ZTtcbiAgICAgICAgdGhpcy5xdWV1ZSA9IG5ldyBMb2NhbFN0b3JhZ2VRdWV1ZShpZCk7XG4gICAgICAgIHRoaXMudGltZXJNcyA9IHRpbWVyTXM7XG4gICAgICAgIHRoaXMudGltZXIgPSBzZXRUaW1lb3V0KHRoaXMuZmx1c2guYmluZCh0aGlzKSwgdGltZXJNcyk7XG4gICAgICAgIHRoaXMuaWQgPSBpZDtcbiAgICB9XG4gICAgd3JpdGUoZGF0YSkge1xuICAgICAgICB0aGlzLnF1ZXVlLnB1c2goZGF0YSk7XG4gICAgfVxuICAgIGZsdXNoKGNhbmNlbFRpbWVyKSB7XG4gICAgICAgIGlmICh0aGlzLnF1ZXVlLnNpemUoKSA+IDApIHtcbiAgICAgICAgICAgIC8vIGlmIHRoZSBicm93c2VyIHNodXRzZG93biBiZWZvcmUgdGhlIHdyaXRlIGlzIGNvbXBsZXRlXG4gICAgICAgICAgICB0aGlzLnF1ZXVlLnRyYW5zYWN0aW9uYWxEcmFpbihxdWV1ZSA9PiBuZXcgUHJvbWlzZShyZXMgPT4gcmVzKHRoaXMuZGVsZWdhdGUud3JpdGUocXVldWUpKSkpXG4gICAgICAgICAgICAgICAgLmNhdGNoKGVyciA9PiBjb25zb2xlLmVycm9yKFwiY291bGQgbm90IGRyYWluIHF1ZXVlOiBcIiwgZXJyKSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFjYW5jZWxUaW1lcikge1xuICAgICAgICAgICAgdGhpcy50aW1lciA9IHNldFRpbWVvdXQodGhpcy5mbHVzaC5iaW5kKHRoaXMpLCB0aGlzLnRpbWVyTXMpO1xuICAgICAgICB9XG4gICAgfVxufVxuIiwiZXhwb3J0IGNsYXNzIENvbnNvbGVXcml0ZXIge1xuICAgIHdyaXRlKGRhdGEpIHtcbiAgICAgICAgY29uc29sZS5kZWJ1ZyhcIkNvbnNvbGVXcml0ZXIgcmVjZWl2aW5nIG5ldyBkYXRhOiBcIik7XG4gICAgICAgIGNvbnNvbGUubG9nKGRhdGEpO1xuICAgIH1cbn1cbiIsIi8qKlxuICogTG9ncyB0aGUgZGF0YSB0byB0aGUgYnJvd3NlciBjb25zb2xlIHVzaW5nIGNvbnNvbGUuZGVidWdcbiAqL1xuZXhwb3J0IGNsYXNzIERlYnVnV3JpdGVyIHtcbiAgICBjb25zdHJ1Y3RvcihkZWxlZ2F0ZSwgZGVidWcpIHtcbiAgICAgICAgdGhpcy5kZWxlZ2F0ZSA9IGRlbGVnYXRlO1xuICAgICAgICB0aGlzLmRlYnVnID0gZGVidWc7XG4gICAgfVxuICAgIHdyaXRlKGRhdGEpIHtcbiAgICAgICAgaWYgKHRoaXMuZGVidWcpXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgICAgdGhpcy5kZWxlZ2F0ZS53cml0ZShkYXRhKTtcbiAgICB9XG59XG4iLCJpbXBvcnQgeyBTUVNFdmVudFdyaXRlciB9IGZyb20gXCIuL1NRU0V2ZW50V3JpdGVyXCI7XG5pbXBvcnQgeyBSZXN0RXZlbnRXcml0ZXIgfSBmcm9tIFwiLi9SZXN0RXZlbnRXcml0ZXJcIjtcbmltcG9ydCB7IEJ1ZmZlcmluZ1dyaXRlciB9IGZyb20gXCIuL0J1ZmZlcmluZ1dyaXRlclwiO1xuaW1wb3J0IHsgQmFzZTY0RW5jb2RlV3JpdGVyIH0gZnJvbSBcIi4vQmFzZTY0RW5jb2RlV3JpdGVyXCI7XG5pbXBvcnQgeyBKU09ORW52ZWxvcGVXcml0ZXIgfSBmcm9tIFwiLi9KU09ORW52ZWxvcGVXcml0ZXJcIjtcbmltcG9ydCB7IFRyYWlsV3JpdGVyIH0gZnJvbSBcIi4vVHJhaWxXcml0ZXJcIjtcbmltcG9ydCB7IEJyb3dzZXJUcmFja2luZ1dyaXRlciB9IGZyb20gXCIuL0Jyb3dzZXJUcmFja2luZ1dyaXRlclwiO1xuaW1wb3J0IHsgRGVidWdXcml0ZXIgfSBmcm9tIFwiLi9EZWJ1Z1dyaXRlclwiO1xuaW1wb3J0IHsgUXVlcnlXcml0ZXIgfSBmcm9tIFwiLi9RdWVyeVdyaXRlclwiO1xuaW1wb3J0IHsgVHJhaWwgfSBmcm9tIFwiLi4vcXVlcnkvVHJhaWxcIjtcbmV4cG9ydCBjbGFzcyBEZWZhdWx0V3JpdGVyIHtcbiAgICBjb25zdHJ1Y3RvcihvcHRpb25zKSB7XG4gICAgICAgIGNvbnN0IHsgZW5kcG9pbnQsIHNxcyB9ID0gb3B0aW9ucztcbiAgICAgICAgLy8gV3JpdGVyIHBpcGVsaW5lLCBhZGQvcmVtb3ZlIHBpZWNlcyBhY2NvcmRpbmcgdG8gdXNlIGNhc2VcbiAgICAgICAgLy8gVGhpcyB3cml0ZXIgcGlwZWxpbmUgd2lsbCBzZW5kIEJhc2U2NCBlbmNvZGVkIGFycmF5IG9mIGpzb24gZXZlbnRzXG4gICAgICAgIGxldCB3cml0ZXIgPSBpc1NRUyhlbmRwb2ludCwgc3FzKSA/IG5ldyBTUVNFdmVudFdyaXRlcihlbmRwb2ludCkgOiBuZXcgUmVzdEV2ZW50V3JpdGVyKGVuZHBvaW50KTtcbiAgICAgICAgd3JpdGVyID0gbmV3IEJhc2U2NEVuY29kZVdyaXRlcih3cml0ZXIpO1xuICAgICAgICB3cml0ZXIgPSBuZXcgQnVmZmVyaW5nV3JpdGVyKHdyaXRlciwgXCJidWZmZXI6XCIgKyBvcHRpb25zLmVuZHBvaW50KTtcbiAgICAgICAgd3JpdGVyID0gbmV3IERlYnVnV3JpdGVyKHdyaXRlciwgb3B0aW9ucy5kZWJ1Zyk7XG4gICAgICAgIHdyaXRlciA9IG5ldyBRdWVyeVdyaXRlcih3cml0ZXIsIG9wdGlvbnMucmVzb2x2ZXIucXVlcnlSZXNvbHZlcik7XG4gICAgICAgIHdyaXRlciA9IG5ldyBUcmFpbFdyaXRlcih3cml0ZXIsIG9wdGlvbnMudHJhaWwgfHwgbmV3IFRyYWlsKG9wdGlvbnMucmVzb2x2ZXIucXVlcnlSZXNvbHZlciwgb3B0aW9ucy5yZXNvbHZlci5zZXNzaW9uUmVzb2x2ZXIpLCBvcHRpb25zLnJlc29sdmVyLnF1ZXJ5UmVzb2x2ZXIpO1xuICAgICAgICB3cml0ZXIgPSBuZXcgSlNPTkVudmVsb3BlV3JpdGVyKHdyaXRlciwgb3B0aW9ucy5yZXNvbHZlci5zZXNzaW9uUmVzb2x2ZXIsIG9wdGlvbnMuY2hhbm5lbCk7XG4gICAgICAgIHdyaXRlciA9IG5ldyBCcm93c2VyVHJhY2tpbmdXcml0ZXIod3JpdGVyLCB7XG4gICAgICAgICAgICByZWNvcmRSZWZlcnJlcjogb3B0aW9ucy5yZWNvcmRSZWZlcnJlcixcbiAgICAgICAgICAgIHJlY29yZFVybDogb3B0aW9ucy5yZWNvcmRVcmwsXG4gICAgICAgICAgICByZWNvcmRMYW5ndWFnZTogb3B0aW9ucy5yZWNvcmRMYW5ndWFnZVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy53cml0ZXIgPSB3cml0ZXI7XG4gICAgfVxuICAgIHdyaXRlKGRhdGEpIHtcbiAgICAgICAgdGhpcy53cml0ZXIud3JpdGUoZGF0YSk7XG4gICAgfVxufVxuZnVuY3Rpb24gaXNTUVMoZW5kcG9pbnQsIGZvcmNlU1FTKSB7XG4gICAgcmV0dXJuIGZvcmNlU1FTIHx8IChlbmRwb2ludC5pbmRleE9mKFwic3FzXCIpICE9IC0xICYmIGVuZHBvaW50LmluZGV4T2YoXCJhbWF6b25hd3MuY29tXCIpICE9IC0xKTtcbn1cbiIsIi8qKlxuICogV3JhcCB0aGUgZXZlbnRzIGluIGEgSlNPTiBlbnZlbG9wZSwgZW5yaWNoIGVhY2ggcmVjb3JkIHdpdGggdGltZXN0YW1wLCBzZXNzaW9uIGFuZCBjaGFubmVsIGluZm9ybWF0aW9uLlxuICovXG5leHBvcnQgY2xhc3MgSlNPTkVudmVsb3BlV3JpdGVyIHtcbiAgICBjb25zdHJ1Y3RvcihkZWxlZ2F0ZSwgc2Vzc2lvblJlc29sdmVyLCBjaGFubmVsKSB7XG4gICAgICAgIHRoaXMuZGVsZWdhdGUgPSBkZWxlZ2F0ZTtcbiAgICAgICAgdGhpcy5zZXNzaW9uUmVzb2x2ZXIgPSBzZXNzaW9uUmVzb2x2ZXI7XG4gICAgICAgIHRoaXMuY2hhbm5lbCA9IGNoYW5uZWw7XG4gICAgfVxuICAgIHdyaXRlKGRhdGEpIHtcbiAgICAgICAgZGF0YS50aW1lc3RhbXAgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcbiAgICAgICAgZGF0YS5zZXNzaW9uID0gdGhpcy5zZXNzaW9uUmVzb2x2ZXIoKTtcbiAgICAgICAgZGF0YS5jaGFubmVsID0gdGhpcy5jaGFubmVsO1xuICAgICAgICB0aGlzLmRlbGVnYXRlLndyaXRlKGRhdGEpO1xuICAgIH1cbn1cbiIsIi8qKlxuICogQXBwZW5kcyB0aGUgcXVlcnkgdG8gdGhlIGRhdGEgaWYgbm8gcXVlcnkgcHJvcGVydHkgZXhpc3RzXG4gKi9cbmV4cG9ydCBjbGFzcyBRdWVyeVdyaXRlciB7XG4gICAgY29uc3RydWN0b3IoZGVsZWdhdGUsIHF1ZXJ5UmVzb2x2ZXIpIHtcbiAgICAgICAgdGhpcy5kZWxlZ2F0ZSA9IGRlbGVnYXRlO1xuICAgICAgICB0aGlzLnF1ZXJ5UmVzb2x2ZXIgPSBxdWVyeVJlc29sdmVyO1xuICAgIH1cbiAgICB3cml0ZShkYXRhKSB7XG4gICAgICAgIGlmICghZGF0YS5xdWVyeSlcbiAgICAgICAgICAgIGRhdGEucXVlcnkgPSB0aGlzLnF1ZXJ5UmVzb2x2ZXIoKS50b1N0cmluZygpO1xuICAgICAgICB0aGlzLmRlbGVnYXRlLndyaXRlKGRhdGEpO1xuICAgIH1cbn1cbiIsIi8qKlxuICogU3RyYWlnaHQtZm9yd2FyZCBSRVNUIHdyaXRlIHZpYSBHRVQgcmVxdWVzdFxuICovXG5leHBvcnQgY2xhc3MgUmVzdEV2ZW50V3JpdGVyIHtcbiAgICBjb25zdHJ1Y3RvcihlbmRwb2ludCkge1xuICAgICAgICB0aGlzLmVuZHBvaW50ID0gZW5kcG9pbnQ7XG4gICAgfVxuICAgIHdyaXRlKGRhdGEpIHtcbiAgICAgICAgY29uc3QgaW1nID0gbmV3IEltYWdlKCk7XG4gICAgICAgIGltZy5zcmMgPSB0aGlzLmVuZHBvaW50ICsgXCI/ZGF0YT1cIiArIEpTT04uc3RyaW5naWZ5KGRhdGEpO1xuICAgIH1cbn1cbiIsImV4cG9ydCBjbGFzcyBTUVNFdmVudFdyaXRlciB7XG4gICAgY29uc3RydWN0b3IocXVldWUsIGZpZm8gPSBmYWxzZSkge1xuICAgICAgICB0aGlzLnF1ZXVlID0gcXVldWU7XG4gICAgICAgIHRoaXMuZmlmbyA9IGZpZm87XG4gICAgfVxuICAgIHdyaXRlKGRhdGEpIHtcbiAgICAgICAgY29uc3QgaW1nID0gbmV3IEltYWdlKCk7XG4gICAgICAgIGxldCBzcmMgPSB0aGlzLnF1ZXVlICsgXCI/VmVyc2lvbj0yMDEyLTExLTA1JkFjdGlvbj1TZW5kTWVzc2FnZVwiO1xuICAgICAgICAvLyBTUVMgc3VwcG9ydHMgRklGTyBxdWV1ZXMgaW4gc29tZSByZWdpb25zIHRoYXQgY2FuIGFsc28gZ3VhcmFudGVlIHRoZSBvcmRlclxuICAgICAgICAvLyBvZiB0aGUgbWVzc2FnZXMuXG4gICAgICAgIGlmICh0aGlzLmZpZm8pIHtcbiAgICAgICAgICAgIC8vIFRPRE8gd2hlbiBlbm91Z2ggaW5mb3JtYXRpb24gaXMgcHJlc2VudCB0byB1bmlxdWVseSBpZGVudGlmeSBhIG1lc3NhZ2UsIHN3aXRjaCB0aGUgZGVkdXBsaWNhdGlvbiBpZCB0byBhIG1lc3NhZ2UgaGFzaFxuICAgICAgICAgICAgc3JjICs9IFwiJk1lc3NhZ2VHcm91cElkPTEmTWVzc2FnZURlZHVwbGljYXRpb25JZD1cIiArIE1hdGgucmFuZG9tKCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHR5cGVvZiBkYXRhICE9PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICBkYXRhID0gSlNPTi5zdHJpbmdpZnkoZGF0YSk7XG4gICAgICAgIH1cbiAgICAgICAgc3JjICs9IFwiJk1lc3NhZ2VCb2R5PVwiICsgZGF0YTtcbiAgICAgICAgaW1nLnNyYyA9IHNyYztcbiAgICB9XG59XG4iLCIvKipcbiAqIENhbGxzIGFsbCB3cml0ZXJzIHBhc3NlZCB0byB0aGUgY29uc3RydWN0b3IgZXJyb3Igc2FmZVxuICovXG5leHBvcnQgY2xhc3MgU3BsaXRTdHJlYW1Xcml0ZXIge1xuICAgIGNvbnN0cnVjdG9yKHdyaXRlcnMpIHtcbiAgICAgICAgdGhpcy53cml0ZXJzID0gd3JpdGVycztcbiAgICB9XG4gICAgd3JpdGUoZGF0YSkge1xuICAgICAgICBmb3IgKGxldCB3cml0ZXIgb2YgdGhpcy53cml0ZXJzKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIHdyaXRlci53cml0ZShkYXRhKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkNvdWxkIG5vdCB3cml0ZSBkYXRhOiBcIiwgZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59XG4iLCJleHBvcnQgY2xhc3MgVHJhaWxXcml0ZXIge1xuICAgIGNvbnN0cnVjdG9yKGRlbGVnYXRlLCB0cmFpbCwgcXVlcnlSZXNvbHZlcikge1xuICAgICAgICB0aGlzLmRlbGVnYXRlID0gZGVsZWdhdGU7XG4gICAgICAgIHRoaXMudHJhaWwgPSB0cmFpbDtcbiAgICAgICAgdGhpcy5xdWVyeVJlc29sdmVyID0gcXVlcnlSZXNvbHZlcjtcbiAgICB9XG4gICAgd3JpdGUoZGF0YSkge1xuICAgICAgICBjb25zdCBxID0gdGhpcy5xdWVyeVJlc29sdmVyKCk7XG4gICAgICAgIGlmICgoIXEgfHwgIXEuaXNWYWxpZCgpKSAmJiAhZGF0YS5xdWVyeSAmJiB0aGlzLmlzQXBwZW5kVHJhaWwoZGF0YSkpIHtcbiAgICAgICAgICAgIC8vIFNlZSBpZiB3ZSBoYXZlIGEgcGF5bG9hZCBpZCBhbmQgYSB0cmFpbCBmb3IgaXQuIFRoaXMgbWVhbnMgd2VcbiAgICAgICAgICAgIC8vIGFyZSBjb2xsZWN0aW5nIGRhdGEgZm9yIGFuIGV2ZW50IHRoYXQgZG9lcyBub3QgaGF2ZSBhIHF1ZXJ5IGNvbnRleHRcbiAgICAgICAgICAgIC8vIG9uIHRoZSBwYWdlIGFueW1vcmUgYnV0IHdlIHdhbnQgdG8gYXNzb2NpYXRlIHRoZSBldmVudCB3aXRoIHRoZSBxdWVyeVxuICAgICAgICAgICAgLy8gY29udGV4dCBvZiB0aGUgb3JpZ2luYWwgc2VhcmNoIHJlc3VsdFxuICAgICAgICAgICAgdGhpcy5hcHBlbmRUcmFpbChkYXRhKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmRlbGVnYXRlLndyaXRlKGRhdGEpO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBBcHBlbmQgdGhlIFRyYWlsIGlmIGFueVxuICAgICAqIEBwYXJhbSBkYXRhXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBhcHBlbmRUcmFpbChkYXRhKSB7XG4gICAgICAgIGNvbnN0IHRyYWlsID0gdGhpcy50cmFpbC5mZXRjaCh0aGlzLmdldElkKGRhdGEpKTtcbiAgICAgICAgaWYgKHRyYWlsICYmIHRyYWlsLnF1ZXJ5KSB7XG4gICAgICAgICAgICBkYXRhLnF1ZXJ5ID0gdHJhaWwucXVlcnk7XG4gICAgICAgICAgICBkYXRhLnF1ZXJ5VGltZSA9IHRyYWlsLnRpbWVzdGFtcDtcbiAgICAgICAgICAgIGRhdGEudHJhaWxUeXBlID0gdHJhaWwudHlwZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvKipcbiAgICAgKiBmb3IgbGVnYWN5IHN1cHBvcnQ6IHNvbWV0aW1lcyBkYXRhIHdhcyB3cmFwcGVkIGluIHByb3BlcnR5IGNhbGxlZCBcImRhdGFcIlxuICAgICAqIEBwYXJhbSBkYXRhXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBnZXRJZChkYXRhKSB7XG4gICAgICAgIHZhciBfYTtcbiAgICAgICAgaWYgKGRhdGEpXG4gICAgICAgICAgICByZXR1cm4gZGF0YS5pZCB8fCAoKF9hID0gZGF0YS5kYXRhKSA9PT0gbnVsbCB8fCBfYSA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2EuaWQpO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBFdmFsdWF0ZXMgaWYgdGhlIFRyYWlsIHNob3VsZCBiZSBhcHBlbmRlZCB0byB0aGlzIGV2ZW50XG4gICAgICogQHBhcmFtIGRhdGFcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIGlzQXBwZW5kVHJhaWwoZGF0YSkge1xuICAgICAgICByZXR1cm4gZGF0YSAmJiBbXCJjaGVja291dFwiLCBcImJhc2tldFwiLCBcImZpbHRlclwiXS5pbmRleE9mKGRhdGEudHlwZSkgPiAtMTtcbiAgICAgICAgLy8gVEE6IFRoaXMgd2FzIHByZXZpb3VzbHkgXCJkYXRhLmRhdGEgJiYgZGF0YS5kYXRhLmlkICYmIHRoaXMudHJhaWxcIlxuICAgICAgICAvLyB0aGUgb25seSBDb2xsZWN0b3JzIGFwcGVuZGluZyBhIHByb3BlcnR5IGNhbGxlZCBcImRhdGFcIiB0byBpdHMgZXZlbnQgYXJlIENsaWNrQ29sbGVjdG9yIGkuZS5cbiAgICAgICAgLy8gQ2hlY2tvdXRDbGlja0NvbGxlY3RvciwgQmFza2V0Q2xpY2tDb2xsZWN0b3IsIEZpbHRlckNsaWNrQ29sbGVjdG9yXG4gICAgICAgIC8vIEkndmUgcmVmYWN0b3JlZCB0aGlzIGltcGxpY2l0IGNvbmRpdGlvbiB0byB0aGlzIGZ1bmN0aW9uXG4gICAgICAgIC8vIFRPRE8gdmFsaWRhdGUgaWYgdGhpbmdzIHdpbGwgYnJlYWsgd2l0aCBuZXcgaW1wbFxuICAgIH1cbn1cbiIsImV4cG9ydCAqIGZyb20gXCIuL0Jhc2U2NEVuY29kZVdyaXRlclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vQnVmZmVyaW5nV3JpdGVyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9EZWZhdWx0V3JpdGVyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9KU09ORW52ZWxvcGVXcml0ZXJcIjtcbmV4cG9ydCAqIGZyb20gXCIuL1Jlc3RFdmVudFdyaXRlclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vU3BsaXRTdHJlYW1Xcml0ZXJcIjtcbmV4cG9ydCAqIGZyb20gXCIuL1NRU0V2ZW50V3JpdGVyXCI7XG4iLCJleHBvcnQgKiBmcm9tIFwiLi9CYXNlNjRFbmNvZGVXcml0ZXJcIjtcbmV4cG9ydCAqIGZyb20gXCIuL0Jyb3dzZXJUcmFja2luZ1dyaXRlclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vQnVmZmVyaW5nV3JpdGVyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9Db25zb2xlV3JpdGVyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9EZWJ1Z1dyaXRlclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vRGVmYXVsdFdyaXRlclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vSlNPTkVudmVsb3BlV3JpdGVyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9RdWVyeVdyaXRlclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vUmVzdEV2ZW50V3JpdGVyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9TcGxpdFN0cmVhbVdyaXRlclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vU1FTRXZlbnRXcml0ZXJcIjtcbmV4cG9ydCAqIGZyb20gXCIuL1RyYWlsV3JpdGVyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9Xcml0ZXJcIjtcbiIsIi8vIFRoZSBtb2R1bGUgY2FjaGVcbnZhciBfX3dlYnBhY2tfbW9kdWxlX2NhY2hlX18gPSB7fTtcblxuLy8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cbmZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcblx0Ly8gQ2hlY2sgaWYgbW9kdWxlIGlzIGluIGNhY2hlXG5cdHZhciBjYWNoZWRNb2R1bGUgPSBfX3dlYnBhY2tfbW9kdWxlX2NhY2hlX19bbW9kdWxlSWRdO1xuXHRpZiAoY2FjaGVkTW9kdWxlICE9PSB1bmRlZmluZWQpIHtcblx0XHRyZXR1cm4gY2FjaGVkTW9kdWxlLmV4cG9ydHM7XG5cdH1cblx0Ly8gQ3JlYXRlIGEgbmV3IG1vZHVsZSAoYW5kIHB1dCBpdCBpbnRvIHRoZSBjYWNoZSlcblx0dmFyIG1vZHVsZSA9IF9fd2VicGFja19tb2R1bGVfY2FjaGVfX1ttb2R1bGVJZF0gPSB7XG5cdFx0Ly8gbm8gbW9kdWxlLmlkIG5lZWRlZFxuXHRcdC8vIG5vIG1vZHVsZS5sb2FkZWQgbmVlZGVkXG5cdFx0ZXhwb3J0czoge31cblx0fTtcblxuXHQvLyBFeGVjdXRlIHRoZSBtb2R1bGUgZnVuY3Rpb25cblx0X193ZWJwYWNrX21vZHVsZXNfX1ttb2R1bGVJZF0uY2FsbChtb2R1bGUuZXhwb3J0cywgbW9kdWxlLCBtb2R1bGUuZXhwb3J0cywgX193ZWJwYWNrX3JlcXVpcmVfXyk7XG5cblx0Ly8gUmV0dXJuIHRoZSBleHBvcnRzIG9mIHRoZSBtb2R1bGVcblx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xufVxuXG4iLCIvLyBnZXREZWZhdWx0RXhwb3J0IGZ1bmN0aW9uIGZvciBjb21wYXRpYmlsaXR5IHdpdGggbm9uLWhhcm1vbnkgbW9kdWxlc1xuX193ZWJwYWNrX3JlcXVpcmVfXy5uID0gKG1vZHVsZSkgPT4ge1xuXHR2YXIgZ2V0dGVyID0gbW9kdWxlICYmIG1vZHVsZS5fX2VzTW9kdWxlID9cblx0XHQoKSA9PiAobW9kdWxlWydkZWZhdWx0J10pIDpcblx0XHQoKSA9PiAobW9kdWxlKTtcblx0X193ZWJwYWNrX3JlcXVpcmVfXy5kKGdldHRlciwgeyBhOiBnZXR0ZXIgfSk7XG5cdHJldHVybiBnZXR0ZXI7XG59OyIsIi8vIGRlZmluZSBnZXR0ZXIgZnVuY3Rpb25zIGZvciBoYXJtb255IGV4cG9ydHNcbl9fd2VicGFja19yZXF1aXJlX18uZCA9IChleHBvcnRzLCBkZWZpbml0aW9uKSA9PiB7XG5cdGZvcih2YXIga2V5IGluIGRlZmluaXRpb24pIHtcblx0XHRpZihfX3dlYnBhY2tfcmVxdWlyZV9fLm8oZGVmaW5pdGlvbiwga2V5KSAmJiAhX193ZWJwYWNrX3JlcXVpcmVfXy5vKGV4cG9ydHMsIGtleSkpIHtcblx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBrZXksIHsgZW51bWVyYWJsZTogdHJ1ZSwgZ2V0OiBkZWZpbml0aW9uW2tleV0gfSk7XG5cdFx0fVxuXHR9XG59OyIsIl9fd2VicGFja19yZXF1aXJlX18ubyA9IChvYmosIHByb3ApID0+IChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqLCBwcm9wKSkiLCIvLyBkZWZpbmUgX19lc01vZHVsZSBvbiBleHBvcnRzXG5fX3dlYnBhY2tfcmVxdWlyZV9fLnIgPSAoZXhwb3J0cykgPT4ge1xuXHRpZih0eXBlb2YgU3ltYm9sICE9PSAndW5kZWZpbmVkJyAmJiBTeW1ib2wudG9TdHJpbmdUYWcpIHtcblx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgU3ltYm9sLnRvU3RyaW5nVGFnLCB7IHZhbHVlOiAnTW9kdWxlJyB9KTtcblx0fVxuXHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgJ19fZXNNb2R1bGUnLCB7IHZhbHVlOiB0cnVlIH0pO1xufTsiLCJleHBvcnQgKiBmcm9tIFwiLi9Db2xsZWN0b3JNb2R1bGVcIjtcbmV4cG9ydCAqIGZyb20gXCIuL2NvbGxlY3RvcnMvXCI7XG5leHBvcnQgKiBmcm9tIFwiLi93cml0ZXJzXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9xdWVyeVwiO1xuZXhwb3J0ICogZnJvbSBcIi4vbG9nZ2VyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9yZXNvbHZlcnNcIjtcbmV4cG9ydCAqIGZyb20gXCIuL3V0aWxzXCI7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0= \ No newline at end of file +//# sourceMappingURL=data:application/json;charset=utf-8;base64,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Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUNOa0M7QUFDSjtBQUNKO0FBQ0Y7QUFDQztBQUNHO0FBQ0oiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9ub2RlX21vZHVsZXMvc2Nyb2xsbW9uaXRvci9kaXN0L21vZHVsZS9pbmRleC5qcyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9ub2RlX21vZHVsZXMvc2Nyb2xsbW9uaXRvci9kaXN0L21vZHVsZS9zcmMvY29uc3RhbnRzLmpzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL25vZGVfbW9kdWxlcy9zY3JvbGxtb25pdG9yL2Rpc3QvbW9kdWxlL3NyYy9jb250YWluZXIuanMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vbm9kZV9tb2R1bGVzL3Njcm9sbG1vbml0b3IvZGlzdC9tb2R1bGUvc3JjL3R5cGVzLmpzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL25vZGVfbW9kdWxlcy9zY3JvbGxtb25pdG9yL2Rpc3QvbW9kdWxlL3NyYy93YXRjaGVyLmpzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL0NvbGxlY3Rvck1vZHVsZS50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9jb2xsZWN0b3JzL0Fic3RyYWN0Q29sbGVjdG9yLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL2NvbGxlY3RvcnMvQXNzb2NpYXRlZFByb2R1Y3RDb2xsZWN0b3IudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vY29sbGVjdG9ycy9CYXNrZXRDbGlja0NvbGxlY3Rvci50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9jb2xsZWN0b3JzL0Jyb3dzZXJDb2xsZWN0b3IudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vY29sbGVjdG9ycy9DaGVja291dENsaWNrQ29sbGVjdG9yLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL2NvbGxlY3RvcnMvQ2xpY2tDb2xsZWN0b3IudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vY29sbGVjdG9ycy9DbGlja1dyaXRlclJlc29sdmVyQ29sbGVjdG9yLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL2NvbGxlY3RvcnMvRmlsdGVyQ2xpY2tDb2xsZWN0b3IudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vY29sbGVjdG9ycy9GaXJlZFNlYXJjaENvbGxlY3Rvci50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9jb2xsZWN0b3JzL0dlbmVyaWNFdmVudENvbGxlY3Rvci50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9jb2xsZWN0b3JzL0ltcHJlc3Npb25Db2xsZWN0b3IudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vY29sbGVjdG9ycy9JbnN0YW50U2VhcmNoUXVlcnlDb2xsZWN0b3IudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vY29sbGVjdG9ycy9Qcm9kdWN0Q2xpY2tDb2xsZWN0b3IudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vY29sbGVjdG9ycy9SZWRpcmVjdENvbGxlY3Rvci50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9jb2xsZWN0b3JzL1NlYXJjaFJlc3VsdENvbGxlY3Rvci50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9jb2xsZWN0b3JzL1N1Z2dlc3RTZWFyY2hDb2xsZWN0b3IudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vY29sbGVjdG9ycy9Xcml0ZXJSZXNvbHZlckNvbGxlY3Rvci50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9jb2xsZWN0b3JzL2luZGV4LnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL2xvZ2dlci9Mb2dnZXIudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vbG9nZ2VyL0xvZ2dlclRyYW5zcG9ydC50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9sb2dnZXIvVHJhbnNwb3J0TG9nZ2VyLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL2xvZ2dlci9pbmRleC50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9sb2dnZXIvdHJhbnNwb3J0L0NvbnNvbGVUcmFuc3BvcnQudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vbG9nZ2VyL3RyYW5zcG9ydC9TUVNFcnJvclRyYW5zcG9ydC50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9sb2dnZXIvdHJhbnNwb3J0L1NRU1RyYW5zcG9ydC50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9sb2dnZXIvdHJhbnNwb3J0L2luZGV4LnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3F1ZXJ5L1F1ZXJ5LnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3F1ZXJ5L1RyYWlsLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3F1ZXJ5L1RyYWlsVHlwZS50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9xdWVyeS9pbmRleC50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9yZXNvbHZlcnMvUmVzb2x2ZXIudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vcmVzb2x2ZXJzL2luZGV4LnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3V0aWxzL0NvbnRleHQudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vdXRpbHMvTGlzdGVuZXJUeXBlLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3V0aWxzL0xvY2FsU3RvcmFnZVF1ZXVlLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3V0aWxzL1NlbnRpbmVsLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3V0aWxzL1V0aWwudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vdXRpbHMvaW5kZXgudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vd3JpdGVycy9CYXNlNjRFbmNvZGVXcml0ZXIudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vd3JpdGVycy9Ccm93c2VyVHJhY2tpbmdXcml0ZXIudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vd3JpdGVycy9CdWZmZXJpbmdXcml0ZXIudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vd3JpdGVycy9Db25zb2xlV3JpdGVyLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3dyaXRlcnMvRGVidWdXcml0ZXIudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vd3JpdGVycy9EZWZhdWx0V3JpdGVyLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3dyaXRlcnMvSlNPTkVudmVsb3BlV3JpdGVyLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3dyaXRlcnMvUXVlcnlXcml0ZXIudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vd3JpdGVycy9SZXN0RXZlbnRXcml0ZXIudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vd3JpdGVycy9TUVNFdmVudFdyaXRlci50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi93cml0ZXJzL1NwbGl0U3RyZWFtV3JpdGVyLnRzIiwid2VicGFjazovL1NlYXJjaENvbGxlY3Rvci8uL3NyYy9tYWluL3dyaXRlcnMvVHJhaWxXcml0ZXIudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vd3JpdGVycy9Xcml0ZXIudHMiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yLy4vc3JjL21haW4vd3JpdGVycy9pbmRleC50cyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3Ivd2VicGFjay9ib290c3RyYXAiLCJ3ZWJwYWNrOi8vU2VhcmNoQ29sbGVjdG9yL3dlYnBhY2svcnVudGltZS9kZWZpbmUgcHJvcGVydHkgZ2V0dGVycyIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3Ivd2VicGFjay9ydW50aW1lL2hhc093blByb3BlcnR5IHNob3J0aGFuZCIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3Ivd2VicGFjay9ydW50aW1lL21ha2UgbmFtZXNwYWNlIG9iamVjdCIsIndlYnBhY2s6Ly9TZWFyY2hDb2xsZWN0b3IvLi9zcmMvbWFpbi9pbmRleC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgeyBTY3JvbGxNb25pdG9yQ29udGFpbmVyIH0gZnJvbSAnLi9zcmMvY29udGFpbmVyLmpzJztcbmV4cG9ydCB7IFdhdGNoZXIgfSBmcm9tICcuL3NyYy93YXRjaGVyLmpzJztcbmV4cG9ydCAqIGZyb20gJy4vc3JjL3R5cGVzJztcbmltcG9ydCB7IGlzSW5Ccm93c2VyIH0gZnJvbSAnLi9zcmMvY29uc3RhbnRzLmpzJztcbmltcG9ydCB7IFNjcm9sbE1vbml0b3JDb250YWluZXIgfSBmcm9tICcuL3NyYy9jb250YWluZXIuanMnO1xuLy8gdGhpcyBpcyBuZWVkZWQgZm9yIHRoZSB0eXBlLCBidXQgaWYgd2UncmUgbm90IGluIGEgYnJvd3NlciB0aGUgb25seVxuLy8gd2F5IGxpc3RlblRvRE9NIHdpbGwgYmUgY2FsbGVkIGlzIGlmIHlvdSBjYWxsIHNjcm9sbG1vbml0b3IuY3JlYXRlQ29udGFpbmVyXG4vLyBhbmQgeW91IGNhbid0IGRvIHRoYXQgdW50aWwgeW91IGhhdmUgYSBET00gZWxlbWVudC5cbnZhciBzY3JvbGxNb25pdG9yID0gbmV3IFNjcm9sbE1vbml0b3JDb250YWluZXIoaXNJbkJyb3dzZXIgPyBkb2N1bWVudC5ib2R5IDogdW5kZWZpbmVkKTtcbmlmIChpc0luQnJvd3Nlcikge1xuICAgIHNjcm9sbE1vbml0b3IudXBkYXRlU3RhdGUoKTtcbiAgICBzY3JvbGxNb25pdG9yLmxpc3RlblRvRE9NKCk7XG59XG4vL0B0cy1pZ25vcmVcbndpbmRvdy5zY3JvbGxNb25pdG9yID0gc2Nyb2xsTW9uaXRvcjtcbmV4cG9ydCBkZWZhdWx0IHNjcm9sbE1vbml0b3I7XG4vLyMgc291cmNlTWFwcGluZ1VSTD1pbmRleC5qcy5tYXAiLCJleHBvcnQgdmFyIFZJU0lCSUxJVFlDSEFOR0UgPSAndmlzaWJpbGl0eUNoYW5nZSc7XG5leHBvcnQgdmFyIEVOVEVSVklFV1BPUlQgPSAnZW50ZXJWaWV3cG9ydCc7XG5leHBvcnQgdmFyIEZVTExZRU5URVJWSUVXUE9SVCA9ICdmdWxseUVudGVyVmlld3BvcnQnO1xuZXhwb3J0IHZhciBFWElUVklFV1BPUlQgPSAnZXhpdFZpZXdwb3J0JztcbmV4cG9ydCB2YXIgUEFSVElBTExZRVhJVFZJRVdQT1JUID0gJ3BhcnRpYWxseUV4aXRWaWV3cG9ydCc7XG5leHBvcnQgdmFyIExPQ0FUSU9OQ0hBTkdFID0gJ2xvY2F0aW9uQ2hhbmdlJztcbmV4cG9ydCB2YXIgU1RBVEVDSEFOR0UgPSAnc3RhdGVDaGFuZ2UnO1xuZXhwb3J0IHZhciBldmVudFR5cGVzID0gW1xuICAgIFZJU0lCSUxJVFlDSEFOR0UsXG4gICAgRU5URVJWSUVXUE9SVCxcbiAgICBGVUxMWUVOVEVSVklFV1BPUlQsXG4gICAgRVhJVFZJRVdQT1JULFxuICAgIFBBUlRJQUxMWUVYSVRWSUVXUE9SVCxcbiAgICBMT0NBVElPTkNIQU5HRSxcbiAgICBTVEFURUNIQU5HRSxcbl07XG5leHBvcnQgdmFyIGlzT25TZXJ2ZXIgPSB0eXBlb2Ygd2luZG93ID09PSAndW5kZWZpbmVkJztcbmV4cG9ydCB2YXIgaXNJbkJyb3dzZXIgPSAhaXNPblNlcnZlcjtcbmV4cG9ydCB2YXIgZGVmYXVsdE9mZnNldHMgPSB7IHRvcDogMCwgYm90dG9tOiAwIH07XG4vLyMgc291cmNlTWFwcGluZ1VSTD1jb25zdGFudHMuanMubWFwIiwiaW1wb3J0IHsgaXNPblNlcnZlciwgaXNJbkJyb3dzZXIsIGV2ZW50VHlwZXMgfSBmcm9tICcuL2NvbnN0YW50cy5qcyc7XG5pbXBvcnQgeyBXYXRjaGVyIH0gZnJvbSAnLi93YXRjaGVyLmpzJztcbmZ1bmN0aW9uIGdldFZpZXdwb3J0SGVpZ2h0KGVsZW1lbnQpIHtcbiAgICBpZiAoaXNPblNlcnZlcikge1xuICAgICAgICByZXR1cm4gMDtcbiAgICB9XG4gICAgaWYgKGVsZW1lbnQgPT09IGRvY3VtZW50LmJvZHkpIHtcbiAgICAgICAgcmV0dXJuIHdpbmRvdy5pbm5lckhlaWdodCB8fCBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xpZW50SGVpZ2h0O1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgcmV0dXJuIGVsZW1lbnQuY2xpZW50SGVpZ2h0O1xuICAgIH1cbn1cbmZ1bmN0aW9uIGdldENvbnRlbnRIZWlnaHQoZWxlbWVudCkge1xuICAgIGlmIChpc09uU2VydmVyKSB7XG4gICAgICAgIHJldHVybiAwO1xuICAgIH1cbiAgICBpZiAoZWxlbWVudCA9PT0gZG9jdW1lbnQuYm9keSkge1xuICAgICAgICAvLyBqUXVlcnkgYXBwcm9hY2hcbiAgICAgICAgLy8gd2hpY2hldmVyIGlzIGdyZWF0ZXN0XG4gICAgICAgIHJldHVybiBNYXRoLm1heChkb2N1bWVudC5ib2R5LnNjcm9sbEhlaWdodCwgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnNjcm9sbEhlaWdodCwgZG9jdW1lbnQuYm9keS5vZmZzZXRIZWlnaHQsIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5vZmZzZXRIZWlnaHQsIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRIZWlnaHQpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgcmV0dXJuIGVsZW1lbnQuc2Nyb2xsSGVpZ2h0O1xuICAgIH1cbn1cbmZ1bmN0aW9uIHNjcm9sbFRvcChlbGVtZW50KSB7XG4gICAgaWYgKGlzT25TZXJ2ZXIpIHtcbiAgICAgICAgcmV0dXJuIDA7XG4gICAgfVxuICAgIGlmIChlbGVtZW50ID09PSBkb2N1bWVudC5ib2R5KSB7XG4gICAgICAgIHJldHVybiAod2luZG93LnBhZ2VZT2Zmc2V0IHx8XG4gICAgICAgICAgICAoZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50ICYmIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zY3JvbGxUb3ApIHx8XG4gICAgICAgICAgICBkb2N1bWVudC5ib2R5LnNjcm9sbFRvcCk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICByZXR1cm4gZWxlbWVudC5zY3JvbGxUb3A7XG4gICAgfVxufVxudmFyIGJyb3dzZXJTdXBwb3J0c1Bhc3NpdmUgPSBmYWxzZTtcbmlmIChpc0luQnJvd3Nlcikge1xuICAgIHRyeSB7XG4gICAgICAgIHZhciBvcHRzID0gT2JqZWN0LmRlZmluZVByb3BlcnR5KHt9LCAncGFzc2l2ZScsIHtcbiAgICAgICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIGJyb3dzZXJTdXBwb3J0c1Bhc3NpdmUgPSB0cnVlO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCd0ZXN0JywgbnVsbCwgb3B0cyk7XG4gICAgfVxuICAgIGNhdGNoIChlKSB7IH1cbn1cbnZhciB1c2VDYXB0dXJlID0gYnJvd3NlclN1cHBvcnRzUGFzc2l2ZSA/IHsgY2FwdHVyZTogZmFsc2UsIHBhc3NpdmU6IHRydWUgfSA6IGZhbHNlO1xudmFyIFNjcm9sbE1vbml0b3JDb250YWluZXIgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gU2Nyb2xsTW9uaXRvckNvbnRhaW5lcihpdGVtLCBwYXJlbnRXYXRjaGVyKSB7XG4gICAgICAgIHRoaXMuZXZlbnRUeXBlcyA9IGV2ZW50VHlwZXM7XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgdGhpcy5pdGVtID0gaXRlbTtcbiAgICAgICAgdGhpcy53YXRjaGVycyA9IFtdO1xuICAgICAgICB0aGlzLnZpZXdwb3J0VG9wID0gbnVsbDtcbiAgICAgICAgdGhpcy52aWV3cG9ydEJvdHRvbSA9IG51bGw7XG4gICAgICAgIHRoaXMuZG9jdW1lbnRIZWlnaHQgPSBnZXRDb250ZW50SGVpZ2h0KGl0ZW0pO1xuICAgICAgICB0aGlzLnZpZXdwb3J0SGVpZ2h0ID0gZ2V0Vmlld3BvcnRIZWlnaHQoaXRlbSk7XG4gICAgICAgIHRoaXMuRE9NTGlzdGVuZXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBTY3JvbGxNb25pdG9yQ29udGFpbmVyLnByb3RvdHlwZS5ET01MaXN0ZW5lci5hcHBseShzZWxmLCBhcmd1bWVudHMpO1xuICAgICAgICB9O1xuICAgICAgICBpZiAocGFyZW50V2F0Y2hlcikge1xuICAgICAgICAgICAgdGhpcy5jb250YWluZXJXYXRjaGVyID0gcGFyZW50V2F0Y2hlci5jcmVhdGUoaXRlbSk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHByZXZpb3VzRG9jdW1lbnRIZWlnaHQ7XG4gICAgICAgIHZhciBjYWxjdWxhdGVWaWV3cG9ydEk7XG4gICAgICAgIGZ1bmN0aW9uIGNhbGN1bGF0ZVZpZXdwb3J0KCkge1xuICAgICAgICAgICAgc2VsZi52aWV3cG9ydFRvcCA9IHNjcm9sbFRvcChpdGVtKTtcbiAgICAgICAgICAgIHNlbGYudmlld3BvcnRCb3R0b20gPSBzZWxmLnZpZXdwb3J0VG9wICsgc2VsZi52aWV3cG9ydEhlaWdodDtcbiAgICAgICAgICAgIHNlbGYuZG9jdW1lbnRIZWlnaHQgPSBnZXRDb250ZW50SGVpZ2h0KGl0ZW0pO1xuICAgICAgICAgICAgaWYgKHNlbGYuZG9jdW1lbnRIZWlnaHQgIT09IHByZXZpb3VzRG9jdW1lbnRIZWlnaHQpIHtcbiAgICAgICAgICAgICAgICBjYWxjdWxhdGVWaWV3cG9ydEkgPSBzZWxmLndhdGNoZXJzLmxlbmd0aDtcbiAgICAgICAgICAgICAgICB3aGlsZSAoY2FsY3VsYXRlVmlld3BvcnRJLS0pIHtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi53YXRjaGVyc1tjYWxjdWxhdGVWaWV3cG9ydEldLnJlY2FsY3VsYXRlTG9jYXRpb24oKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcHJldmlvdXNEb2N1bWVudEhlaWdodCA9IHNlbGYuZG9jdW1lbnRIZWlnaHQ7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHVwZGF0ZUFuZFRyaWdnZXJXYXRjaGVyc0k7XG4gICAgICAgIGZ1bmN0aW9uIHVwZGF0ZUFuZFRyaWdnZXJXYXRjaGVycygpIHtcbiAgICAgICAgICAgIC8vIHVwZGF0ZSBhbGwgd2F0Y2hlcnMgdGhlbiB0cmlnZ2VyIHRoZSBldmVudHMgc28gb25lIGNhbiByZWx5IG9uIGFub3RoZXIgYmVpbmcgdXAgdG8gZGF0ZS5cbiAgICAgICAgICAgIHVwZGF0ZUFuZFRyaWdnZXJXYXRjaGVyc0kgPSBzZWxmLndhdGNoZXJzLmxlbmd0aDtcbiAgICAgICAgICAgIHdoaWxlICh1cGRhdGVBbmRUcmlnZ2VyV2F0Y2hlcnNJLS0pIHtcbiAgICAgICAgICAgICAgICBzZWxmLndhdGNoZXJzW3VwZGF0ZUFuZFRyaWdnZXJXYXRjaGVyc0ldLnVwZGF0ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdXBkYXRlQW5kVHJpZ2dlcldhdGNoZXJzSSA9IHNlbGYud2F0Y2hlcnMubGVuZ3RoO1xuICAgICAgICAgICAgd2hpbGUgKHVwZGF0ZUFuZFRyaWdnZXJXYXRjaGVyc0ktLSkge1xuICAgICAgICAgICAgICAgIHNlbGYud2F0Y2hlcnNbdXBkYXRlQW5kVHJpZ2dlcldhdGNoZXJzSV0udHJpZ2dlckNhbGxiYWNrcyh1bmRlZmluZWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHRoaXMudXBkYXRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgY2FsY3VsYXRlVmlld3BvcnQoKTtcbiAgICAgICAgICAgIHVwZGF0ZUFuZFRyaWdnZXJXYXRjaGVycygpO1xuICAgICAgICB9O1xuICAgICAgICB0aGlzLnJlY2FsY3VsYXRlTG9jYXRpb25zID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdGhpcy5kb2N1bWVudEhlaWdodCA9IDA7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZSgpO1xuICAgICAgICB9O1xuICAgIH1cbiAgICBTY3JvbGxNb25pdG9yQ29udGFpbmVyLnByb3RvdHlwZS5saXN0ZW5Ub0RPTSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKGlzSW5Ccm93c2VyKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5pdGVtID09PSBkb2N1bWVudC5ib2R5KSB7XG4gICAgICAgICAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Njcm9sbCcsIHRoaXMuRE9NTGlzdGVuZXIsIHVzZUNhcHR1cmUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5pdGVtLmFkZEV2ZW50TGlzdGVuZXIoJ3Njcm9sbCcsIHRoaXMuRE9NTGlzdGVuZXIsIHVzZUNhcHR1cmUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsIHRoaXMuRE9NTGlzdGVuZXIpO1xuICAgICAgICAgICAgdGhpcy5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLml0ZW0gPT09IGRvY3VtZW50LmJvZHkpIHtcbiAgICAgICAgICAgICAgICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3Njcm9sbCcsIHRoaXMuRE9NTGlzdGVuZXIsIHVzZUNhcHR1cmUpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbnRhaW5lcldhdGNoZXIuZGVzdHJveSgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5pdGVtLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3Njcm9sbCcsIHRoaXMuRE9NTGlzdGVuZXIsIHVzZUNhcHR1cmUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcigncmVzaXplJywgdGhpcy5ET01MaXN0ZW5lcik7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgfTtcbiAgICBTY3JvbGxNb25pdG9yQ29udGFpbmVyLnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyBub29wLCBvdmVycmlkZSBmb3IgeW91ciBvd24gcHVycG9zZXMuXG4gICAgICAgIC8vIGluIGxpc3RlblRvRE9NLCBmb3IgZXhhbXBsZS5cbiAgICB9O1xuICAgIFNjcm9sbE1vbml0b3JDb250YWluZXIucHJvdG90eXBlLkRPTUxpc3RlbmVyID0gZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIC8vYWxlcnQoJ2dvdCBzY3JvbGwnKTtcbiAgICAgICAgdGhpcy51cGRhdGVTdGF0ZSgpO1xuICAgICAgICB0aGlzLnVwZGF0ZUFuZFRyaWdnZXJXYXRjaGVycyhldmVudCk7XG4gICAgfTtcbiAgICBTY3JvbGxNb25pdG9yQ29udGFpbmVyLnByb3RvdHlwZS51cGRhdGVTdGF0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHZpZXdwb3J0VG9wID0gc2Nyb2xsVG9wKHRoaXMuaXRlbSk7XG4gICAgICAgIHZhciB2aWV3cG9ydEhlaWdodCA9IGdldFZpZXdwb3J0SGVpZ2h0KHRoaXMuaXRlbSk7XG4gICAgICAgIHZhciBjb250ZW50SGVpZ2h0ID0gZ2V0Q29udGVudEhlaWdodCh0aGlzLml0ZW0pO1xuICAgICAgICB2YXIgbmVlZHNSZWNhbGN1YXRlID0gdmlld3BvcnRIZWlnaHQgIT09IHRoaXMudmlld3BvcnRIZWlnaHQgfHwgY29udGVudEhlaWdodCAhPT0gdGhpcy5jb250ZW50SGVpZ2h0O1xuICAgICAgICB0aGlzLnZpZXdwb3J0VG9wID0gdmlld3BvcnRUb3A7XG4gICAgICAgIHRoaXMudmlld3BvcnRIZWlnaHQgPSB2aWV3cG9ydEhlaWdodDtcbiAgICAgICAgdGhpcy52aWV3cG9ydEJvdHRvbSA9IHZpZXdwb3J0VG9wICsgdmlld3BvcnRIZWlnaHQ7XG4gICAgICAgIHRoaXMuY29udGVudEhlaWdodCA9IGNvbnRlbnRIZWlnaHQ7XG4gICAgICAgIGlmIChuZWVkc1JlY2FsY3VhdGUpIHtcbiAgICAgICAgICAgIHZhciBpID0gdGhpcy53YXRjaGVycy5sZW5ndGg7XG4gICAgICAgICAgICB3aGlsZSAoaS0tKSB7XG4gICAgICAgICAgICAgICAgdGhpcy53YXRjaGVyc1tpXS5yZWNhbGN1bGF0ZUxvY2F0aW9uKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuICAgIFNjcm9sbE1vbml0b3JDb250YWluZXIucHJvdG90eXBlLnVwZGF0ZUFuZFRyaWdnZXJXYXRjaGVycyA9IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICB2YXIgaSA9IHRoaXMud2F0Y2hlcnMubGVuZ3RoO1xuICAgICAgICB3aGlsZSAoaS0tKSB7XG4gICAgICAgICAgICB0aGlzLndhdGNoZXJzW2ldLnVwZGF0ZSgpO1xuICAgICAgICB9XG4gICAgICAgIGkgPSB0aGlzLndhdGNoZXJzLmxlbmd0aDtcbiAgICAgICAgd2hpbGUgKGktLSkge1xuICAgICAgICAgICAgdGhpcy53YXRjaGVyc1tpXS50cmlnZ2VyQ2FsbGJhY2tzKGV2ZW50KTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgU2Nyb2xsTW9uaXRvckNvbnRhaW5lci5wcm90b3R5cGUuY3JlYXRlQ29udGFpbmVyID0gZnVuY3Rpb24gKGlucHV0KSB7XG4gICAgICAgIHZhciBpdGVtO1xuICAgICAgICBpZiAodHlwZW9mIGlucHV0ID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgaXRlbSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoaW5wdXQpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKEFycmF5LmlzQXJyYXkoaW5wdXQpIHx8IGlucHV0IGluc3RhbmNlb2YgTm9kZUxpc3QpIHtcbiAgICAgICAgICAgIGl0ZW0gPSBpbnB1dFswXTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGl0ZW0gPSBpbnB1dDtcbiAgICAgICAgfVxuICAgICAgICB2YXIgY29udGFpbmVyID0gbmV3IFNjcm9sbE1vbml0b3JDb250YWluZXIoaXRlbSwgdGhpcyk7XG4gICAgICAgIHRoaXMudXBkYXRlU3RhdGUoKTtcbiAgICAgICAgY29udGFpbmVyLmxpc3RlblRvRE9NKCk7XG4gICAgICAgIHJldHVybiBjb250YWluZXI7XG4gICAgfTtcbiAgICBTY3JvbGxNb25pdG9yQ29udGFpbmVyLnByb3RvdHlwZS5jcmVhdGUgPSBmdW5jdGlvbiAoaW5wdXQsIG9mZnNldHMpIHtcbiAgICAgICAgdmFyIGl0ZW07XG4gICAgICAgIGlmICh0eXBlb2YgaXRlbSA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIGl0ZW0gPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKGl0ZW0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKEFycmF5LmlzQXJyYXkoaW5wdXQpIHx8IGlucHV0IGluc3RhbmNlb2YgTm9kZUxpc3QpIHtcbiAgICAgICAgICAgIGl0ZW0gPSBpbnB1dFswXTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGl0ZW0gPSBpbnB1dDtcbiAgICAgICAgfVxuICAgICAgICB2YXIgd2F0Y2hlciA9IG5ldyBXYXRjaGVyKHRoaXMsIGl0ZW0sIG9mZnNldHMpO1xuICAgICAgICB0aGlzLndhdGNoZXJzLnB1c2god2F0Y2hlcik7XG4gICAgICAgIHJldHVybiB3YXRjaGVyO1xuICAgIH07XG4gICAgLyoqXG4gICAgICogQGRlcHJlY2F0ZWQgc2luY2UgdmVyc2lvbiAxLjFcbiAgICAgKi9cbiAgICBTY3JvbGxNb25pdG9yQ29udGFpbmVyLnByb3RvdHlwZS5iZWdldCA9IGZ1bmN0aW9uIChpbnB1dCwgb2Zmc2V0cykge1xuICAgICAgICByZXR1cm4gdGhpcy5jcmVhdGUoaW5wdXQsIG9mZnNldHMpO1xuICAgIH07XG4gICAgcmV0dXJuIFNjcm9sbE1vbml0b3JDb250YWluZXI7XG59KCkpO1xuZXhwb3J0IHsgU2Nyb2xsTW9uaXRvckNvbnRhaW5lciB9O1xuLy8jIHNvdXJjZU1hcHBpbmdVUkw9Y29udGFpbmVyLmpzLm1hcCIsImV4cG9ydCB7fTtcbi8vIyBzb3VyY2VNYXBwaW5nVVJMPXR5cGVzLmpzLm1hcCIsImltcG9ydCB7IFZJU0lCSUxJVFlDSEFOR0UsIEVOVEVSVklFV1BPUlQsIEZVTExZRU5URVJWSUVXUE9SVCwgRVhJVFZJRVdQT1JULCBQQVJUSUFMTFlFWElUVklFV1BPUlQsIExPQ0FUSU9OQ0hBTkdFLCBTVEFURUNIQU5HRSwgZXZlbnRUeXBlcywgZGVmYXVsdE9mZnNldHMsIH0gZnJvbSAnLi9jb25zdGFudHMuanMnO1xudmFyIFdhdGNoZXIgPSAvKiogQGNsYXNzICovIChmdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gV2F0Y2hlcihjb250YWluZXIsIHdhdGNoSXRlbSwgb2Zmc2V0cykge1xuICAgICAgICB0aGlzLmNvbnRhaW5lciA9IGNvbnRhaW5lcjtcbiAgICAgICAgdGhpcy53YXRjaEl0ZW0gPSB3YXRjaEl0ZW07XG4gICAgICAgIHRoaXMubG9ja2VkID0gZmFsc2U7XG4gICAgICAgIHRoaXMuY2FsbGJhY2tzID0ge307XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgaWYgKCFvZmZzZXRzKSB7XG4gICAgICAgICAgICB0aGlzLm9mZnNldHMgPSBkZWZhdWx0T2Zmc2V0cztcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh0eXBlb2Ygb2Zmc2V0cyA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgICAgIHRoaXMub2Zmc2V0cyA9IHsgdG9wOiBvZmZzZXRzLCBib3R0b206IG9mZnNldHMgfTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMub2Zmc2V0cyA9IHtcbiAgICAgICAgICAgICAgICB0b3A6ICd0b3AnIGluIG9mZnNldHMgPyBvZmZzZXRzLnRvcCA6IGRlZmF1bHRPZmZzZXRzLnRvcCxcbiAgICAgICAgICAgICAgICBib3R0b206ICdib3R0b20nIGluIG9mZnNldHMgPyBvZmZzZXRzLmJvdHRvbSA6IGRlZmF1bHRPZmZzZXRzLmJvdHRvbSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgZm9yICh2YXIgaSA9IDAsIGogPSBldmVudFR5cGVzLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuICAgICAgICAgICAgc2VsZi5jYWxsYmFja3NbZXZlbnRUeXBlc1tpXV0gPSBbXTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmxvY2tlZCA9IGZhbHNlO1xuICAgICAgICB2YXIgd2FzSW5WaWV3cG9ydDtcbiAgICAgICAgdmFyIHdhc0Z1bGx5SW5WaWV3cG9ydDtcbiAgICAgICAgdmFyIHdhc0Fib3ZlVmlld3BvcnQ7XG4gICAgICAgIHZhciB3YXNCZWxvd1ZpZXdwb3J0O1xuICAgICAgICB2YXIgbGlzdGVuZXJUb1RyaWdnZXJMaXN0STtcbiAgICAgICAgdmFyIGxpc3RlbmVyO1xuICAgICAgICB2YXIgbmVlZFRvVHJpZ2dlclN0YXRlQ2hhbmdlID0gZmFsc2U7XG4gICAgICAgIGZ1bmN0aW9uIHRyaWdnZXJDYWxsYmFja0FycmF5KGxpc3RlbmVycywgZXZlbnQpIHtcbiAgICAgICAgICAgIG5lZWRUb1RyaWdnZXJTdGF0ZUNoYW5nZSA9IHRydWU7XG4gICAgICAgICAgICBpZiAobGlzdGVuZXJzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxpc3RlbmVyVG9UcmlnZ2VyTGlzdEkgPSBsaXN0ZW5lcnMubGVuZ3RoO1xuICAgICAgICAgICAgd2hpbGUgKGxpc3RlbmVyVG9UcmlnZ2VyTGlzdEktLSkge1xuICAgICAgICAgICAgICAgIGxpc3RlbmVyID0gbGlzdGVuZXJzW2xpc3RlbmVyVG9UcmlnZ2VyTGlzdEldO1xuICAgICAgICAgICAgICAgIGxpc3RlbmVyLmNhbGxiYWNrLmNhbGwoc2VsZiwgZXZlbnQsIHNlbGYpO1xuICAgICAgICAgICAgICAgIGlmIChsaXN0ZW5lci5pc09uZSkge1xuICAgICAgICAgICAgICAgICAgICBsaXN0ZW5lcnMuc3BsaWNlKGxpc3RlbmVyVG9UcmlnZ2VyTGlzdEksIDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLnRyaWdnZXJDYWxsYmFja3MgPSBmdW5jdGlvbiB0cmlnZ2VyQ2FsbGJhY2tzKGV2ZW50KSB7XG4gICAgICAgICAgICBpZiAodGhpcy5pc0luVmlld3BvcnQgJiYgIXdhc0luVmlld3BvcnQpIHtcbiAgICAgICAgICAgICAgICB0cmlnZ2VyQ2FsbGJhY2tBcnJheSh0aGlzLmNhbGxiYWNrc1tFTlRFUlZJRVdQT1JUXSwgZXZlbnQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHRoaXMuaXNGdWxseUluVmlld3BvcnQgJiYgIXdhc0Z1bGx5SW5WaWV3cG9ydCkge1xuICAgICAgICAgICAgICAgIHRyaWdnZXJDYWxsYmFja0FycmF5KHRoaXMuY2FsbGJhY2tzW0ZVTExZRU5URVJWSUVXUE9SVF0sIGV2ZW50KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh0aGlzLmlzQWJvdmVWaWV3cG9ydCAhPT0gd2FzQWJvdmVWaWV3cG9ydCAmJlxuICAgICAgICAgICAgICAgIHRoaXMuaXNCZWxvd1ZpZXdwb3J0ICE9PSB3YXNCZWxvd1ZpZXdwb3J0KSB7XG4gICAgICAgICAgICAgICAgdHJpZ2dlckNhbGxiYWNrQXJyYXkodGhpcy5jYWxsYmFja3NbVklTSUJJTElUWUNIQU5HRV0sIGV2ZW50KTtcbiAgICAgICAgICAgICAgICAvLyBpZiB5b3Ugc2tpcCBjb21wbGV0ZWx5IHBhc3QgdGhpcyBlbGVtZW50XG4gICAgICAgICAgICAgICAgaWYgKCF3YXNGdWxseUluVmlld3BvcnQgJiYgIXRoaXMuaXNGdWxseUluVmlld3BvcnQpIHtcbiAgICAgICAgICAgICAgICAgICAgdHJpZ2dlckNhbGxiYWNrQXJyYXkodGhpcy5jYWxsYmFja3NbRlVMTFlFTlRFUlZJRVdQT1JUXSwgZXZlbnQpO1xuICAgICAgICAgICAgICAgICAgICB0cmlnZ2VyQ2FsbGJhY2tBcnJheSh0aGlzLmNhbGxiYWNrc1tQQVJUSUFMTFlFWElUVklFV1BPUlRdLCBldmVudCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICghd2FzSW5WaWV3cG9ydCAmJiAhdGhpcy5pc0luVmlld3BvcnQpIHtcbiAgICAgICAgICAgICAgICAgICAgdHJpZ2dlckNhbGxiYWNrQXJyYXkodGhpcy5jYWxsYmFja3NbRU5URVJWSUVXUE9SVF0sIGV2ZW50KTtcbiAgICAgICAgICAgICAgICAgICAgdHJpZ2dlckNhbGxiYWNrQXJyYXkodGhpcy5jYWxsYmFja3NbRVhJVFZJRVdQT1JUXSwgZXZlbnQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghdGhpcy5pc0Z1bGx5SW5WaWV3cG9ydCAmJiB3YXNGdWxseUluVmlld3BvcnQpIHtcbiAgICAgICAgICAgICAgICB0cmlnZ2VyQ2FsbGJhY2tBcnJheSh0aGlzLmNhbGxiYWNrc1tQQVJUSUFMTFlFWElUVklFV1BPUlRdLCBldmVudCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIXRoaXMuaXNJblZpZXdwb3J0ICYmIHdhc0luVmlld3BvcnQpIHtcbiAgICAgICAgICAgICAgICB0cmlnZ2VyQ2FsbGJhY2tBcnJheSh0aGlzLmNhbGxiYWNrc1tFWElUVklFV1BPUlRdLCBldmVudCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodGhpcy5pc0luVmlld3BvcnQgIT09IHdhc0luVmlld3BvcnQpIHtcbiAgICAgICAgICAgICAgICB0cmlnZ2VyQ2FsbGJhY2tBcnJheSh0aGlzLmNhbGxiYWNrc1tWSVNJQklMSVRZQ0hBTkdFXSwgZXZlbnQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG5lZWRUb1RyaWdnZXJTdGF0ZUNoYW5nZSkge1xuICAgICAgICAgICAgICAgIG5lZWRUb1RyaWdnZXJTdGF0ZUNoYW5nZSA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIHRyaWdnZXJDYWxsYmFja0FycmF5KHRoaXMuY2FsbGJhY2tzW1NUQVRFQ0hBTkdFXSwgZXZlbnQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgd2FzSW5WaWV3cG9ydCA9IHRoaXMuaXNJblZpZXdwb3J0O1xuICAgICAgICAgICAgd2FzRnVsbHlJblZpZXdwb3J0ID0gdGhpcy5pc0Z1bGx5SW5WaWV3cG9ydDtcbiAgICAgICAgICAgIHdhc0Fib3ZlVmlld3BvcnQgPSB0aGlzLmlzQWJvdmVWaWV3cG9ydDtcbiAgICAgICAgICAgIHdhc0JlbG93Vmlld3BvcnQgPSB0aGlzLmlzQmVsb3dWaWV3cG9ydDtcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5yZWNhbGN1bGF0ZUxvY2F0aW9uID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKHRoaXMubG9ja2VkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHByZXZpb3VzVG9wID0gdGhpcy50b3A7XG4gICAgICAgICAgICB2YXIgcHJldmlvdXNCb3R0b20gPSB0aGlzLmJvdHRvbTtcbiAgICAgICAgICAgIGlmICh0aGlzLndhdGNoSXRlbS5ub2RlTmFtZSkge1xuICAgICAgICAgICAgICAgIC8vIGEgZG9tIGVsZW1lbnRcbiAgICAgICAgICAgICAgICB2YXIgY2FjaGVkRGlzcGxheSA9IHRoaXMud2F0Y2hJdGVtLnN0eWxlLmRpc3BsYXk7XG4gICAgICAgICAgICAgICAgaWYgKGNhY2hlZERpc3BsYXkgPT09ICdub25lJykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLndhdGNoSXRlbS5zdHlsZS5kaXNwbGF5ID0gJyc7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHZhciBjb250YWluZXJPZmZzZXQgPSAwO1xuICAgICAgICAgICAgICAgIHZhciBjb250YWluZXIgPSB0aGlzLmNvbnRhaW5lcjtcbiAgICAgICAgICAgICAgICB3aGlsZSAoY29udGFpbmVyLmNvbnRhaW5lcldhdGNoZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgY29udGFpbmVyT2Zmc2V0ICs9XG4gICAgICAgICAgICAgICAgICAgICAgICBjb250YWluZXIuY29udGFpbmVyV2F0Y2hlci50b3AgLVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRhaW5lci5jb250YWluZXJXYXRjaGVyLmNvbnRhaW5lci52aWV3cG9ydFRvcDtcbiAgICAgICAgICAgICAgICAgICAgY29udGFpbmVyID0gY29udGFpbmVyLmNvbnRhaW5lcldhdGNoZXIuY29udGFpbmVyO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB2YXIgYm91bmRpbmdSZWN0ID0gdGhpcy53YXRjaEl0ZW0uZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgICAgICAgICAgdGhpcy50b3AgPSBib3VuZGluZ1JlY3QudG9wICsgdGhpcy5jb250YWluZXIudmlld3BvcnRUb3AgLSBjb250YWluZXJPZmZzZXQ7XG4gICAgICAgICAgICAgICAgdGhpcy5ib3R0b20gPSBib3VuZGluZ1JlY3QuYm90dG9tICsgdGhpcy5jb250YWluZXIudmlld3BvcnRUb3AgLSBjb250YWluZXJPZmZzZXQ7XG4gICAgICAgICAgICAgICAgaWYgKGNhY2hlZERpc3BsYXkgPT09ICdub25lJykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLndhdGNoSXRlbS5zdHlsZS5kaXNwbGF5ID0gY2FjaGVkRGlzcGxheTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICh0aGlzLndhdGNoSXRlbSA9PT0gK3RoaXMud2F0Y2hJdGVtKSB7XG4gICAgICAgICAgICAgICAgLy8gbnVtYmVyXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMud2F0Y2hJdGVtID4gMCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnRvcCA9IHRoaXMuYm90dG9tID0gdGhpcy53YXRjaEl0ZW07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnRvcCA9IHRoaXMuYm90dG9tID0gdGhpcy5jb250YWluZXIuZG9jdW1lbnRIZWlnaHQgLSB0aGlzLndhdGNoSXRlbTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBhbiBvYmplY3Qgd2l0aCBhIHRvcCBhbmQgYm90dG9tIHByb3BlcnR5XG4gICAgICAgICAgICAgICAgdGhpcy50b3AgPSB0aGlzLndhdGNoSXRlbS50b3A7XG4gICAgICAgICAgICAgICAgdGhpcy5ib3R0b20gPSB0aGlzLndhdGNoSXRlbS5ib3R0b207XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnRvcCAtPSB0aGlzLm9mZnNldHMudG9wO1xuICAgICAgICAgICAgdGhpcy5ib3R0b20gKz0gdGhpcy5vZmZzZXRzLmJvdHRvbTtcbiAgICAgICAgICAgIHRoaXMuaGVpZ2h0ID0gdGhpcy5ib3R0b20gLSB0aGlzLnRvcDtcbiAgICAgICAgICAgIGlmICgocHJldmlvdXNUb3AgIT09IHVuZGVmaW5lZCB8fCBwcmV2aW91c0JvdHRvbSAhPT0gdW5kZWZpbmVkKSAmJlxuICAgICAgICAgICAgICAgICh0aGlzLnRvcCAhPT0gcHJldmlvdXNUb3AgfHwgdGhpcy5ib3R0b20gIT09IHByZXZpb3VzQm90dG9tKSkge1xuICAgICAgICAgICAgICAgIHRyaWdnZXJDYWxsYmFja0FycmF5KHRoaXMuY2FsbGJhY2tzW0xPQ0FUSU9OQ0hBTkdFXSwgdW5kZWZpbmVkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5yZWNhbGN1bGF0ZUxvY2F0aW9uKCk7XG4gICAgICAgIHRoaXMudXBkYXRlKCk7XG4gICAgICAgIHdhc0luVmlld3BvcnQgPSB0aGlzLmlzSW5WaWV3cG9ydDtcbiAgICAgICAgd2FzRnVsbHlJblZpZXdwb3J0ID0gdGhpcy5pc0Z1bGx5SW5WaWV3cG9ydDtcbiAgICAgICAgd2FzQWJvdmVWaWV3cG9ydCA9IHRoaXMuaXNBYm92ZVZpZXdwb3J0O1xuICAgICAgICB3YXNCZWxvd1ZpZXdwb3J0ID0gdGhpcy5pc0JlbG93Vmlld3BvcnQ7XG4gICAgfVxuICAgIFdhdGNoZXIucHJvdG90eXBlLm9uID0gZnVuY3Rpb24gKGV2ZW50LCBjYWxsYmFjaywgaXNPbmUpIHtcbiAgICAgICAgaWYgKGlzT25lID09PSB2b2lkIDApIHsgaXNPbmUgPSBmYWxzZTsgfVxuICAgICAgICAvLyB0cmlnZ2VyIHRoZSBldmVudCBpZiBpdCBhcHBsaWVzIHRvIHRoZSBlbGVtZW50IHJpZ2h0IG5vdy5cbiAgICAgICAgc3dpdGNoICh0cnVlKSB7XG4gICAgICAgICAgICBjYXNlIGV2ZW50ID09PSBWSVNJQklMSVRZQ0hBTkdFICYmICF0aGlzLmlzSW5WaWV3cG9ydCAmJiB0aGlzLmlzQWJvdmVWaWV3cG9ydDpcbiAgICAgICAgICAgIGNhc2UgZXZlbnQgPT09IEVOVEVSVklFV1BPUlQgJiYgdGhpcy5pc0luVmlld3BvcnQ6XG4gICAgICAgICAgICBjYXNlIGV2ZW50ID09PSBGVUxMWUVOVEVSVklFV1BPUlQgJiYgdGhpcy5pc0Z1bGx5SW5WaWV3cG9ydDpcbiAgICAgICAgICAgIGNhc2UgZXZlbnQgPT09IEVYSVRWSUVXUE9SVCAmJiB0aGlzLmlzQWJvdmVWaWV3cG9ydCAmJiAhdGhpcy5pc0luVmlld3BvcnQ6XG4gICAgICAgICAgICBjYXNlIGV2ZW50ID09PSBQQVJUSUFMTFlFWElUVklFV1BPUlQgJiYgdGhpcy5pc0luVmlld3BvcnQgJiYgdGhpcy5pc0Fib3ZlVmlld3BvcnQ6XG4gICAgICAgICAgICAgICAgY2FsbGJhY2suY2FsbCh0aGlzLCB0aGlzKTtcbiAgICAgICAgICAgICAgICBpZiAoaXNPbmUpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5jYWxsYmFja3NbZXZlbnRdKSB7XG4gICAgICAgICAgICB0aGlzLmNhbGxiYWNrc1tldmVudF0ucHVzaCh7IGNhbGxiYWNrOiBjYWxsYmFjaywgaXNPbmU6IGlzT25lIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdUcmllZCB0byBhZGQgYSBzY3JvbGwgbW9uaXRvciBsaXN0ZW5lciBvZiB0eXBlICcgK1xuICAgICAgICAgICAgICAgIGV2ZW50ICtcbiAgICAgICAgICAgICAgICAnLiBZb3VyIG9wdGlvbnMgYXJlOiAnICtcbiAgICAgICAgICAgICAgICBldmVudFR5cGVzLmpvaW4oJywgJykpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICBXYXRjaGVyLnByb3RvdHlwZS5vZmYgPSBmdW5jdGlvbiAoZXZlbnQsIGNhbGxiYWNrKSB7XG4gICAgICAgIGlmICh0aGlzLmNhbGxiYWNrc1tldmVudF0pIHtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwLCBpdGVtOyAoaXRlbSA9IHRoaXMuY2FsbGJhY2tzW2V2ZW50XVtpXSk7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmIChpdGVtLmNhbGxiYWNrID09PSBjYWxsYmFjaykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNhbGxiYWNrc1tldmVudF0uc3BsaWNlKGksIDEpO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1RyaWVkIHRvIHJlbW92ZSBhIHNjcm9sbCBtb25pdG9yIGxpc3RlbmVyIG9mIHR5cGUgJyArXG4gICAgICAgICAgICAgICAgZXZlbnQgK1xuICAgICAgICAgICAgICAgICcuIFlvdXIgb3B0aW9ucyBhcmU6ICcgK1xuICAgICAgICAgICAgICAgIGV2ZW50VHlwZXMuam9pbignLCAnKSk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIFdhdGNoZXIucHJvdG90eXBlLm9uZSA9IGZ1bmN0aW9uIChldmVudCwgY2FsbGJhY2spIHtcbiAgICAgICAgdGhpcy5vbihldmVudCwgY2FsbGJhY2ssIHRydWUpO1xuICAgIH07XG4gICAgV2F0Y2hlci5wcm90b3R5cGUucmVjYWxjdWxhdGVTaXplID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodGhpcy53YXRjaEl0ZW0gaW5zdGFuY2VvZiBIVE1MRWxlbWVudCkge1xuICAgICAgICAgICAgdGhpcy5oZWlnaHQgPSB0aGlzLndhdGNoSXRlbS5vZmZzZXRIZWlnaHQgKyB0aGlzLm9mZnNldHMudG9wICsgdGhpcy5vZmZzZXRzLmJvdHRvbTtcbiAgICAgICAgICAgIHRoaXMuYm90dG9tID0gdGhpcy50b3AgKyB0aGlzLmhlaWdodDtcbiAgICAgICAgfVxuICAgIH07XG4gICAgV2F0Y2hlci5wcm90b3R5cGUudXBkYXRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLmlzQWJvdmVWaWV3cG9ydCA9IHRoaXMudG9wIDwgdGhpcy5jb250YWluZXIudmlld3BvcnRUb3A7XG4gICAgICAgIHRoaXMuaXNCZWxvd1ZpZXdwb3J0ID0gdGhpcy5ib3R0b20gPiB0aGlzLmNvbnRhaW5lci52aWV3cG9ydEJvdHRvbTtcbiAgICAgICAgdGhpcy5pc0luVmlld3BvcnQgPVxuICAgICAgICAgICAgdGhpcy50b3AgPCB0aGlzLmNvbnRhaW5lci52aWV3cG9ydEJvdHRvbSAmJiB0aGlzLmJvdHRvbSA+IHRoaXMuY29udGFpbmVyLnZpZXdwb3J0VG9wO1xuICAgICAgICB0aGlzLmlzRnVsbHlJblZpZXdwb3J0ID1cbiAgICAgICAgICAgICh0aGlzLnRvcCA+PSB0aGlzLmNvbnRhaW5lci52aWV3cG9ydFRvcCAmJlxuICAgICAgICAgICAgICAgIHRoaXMuYm90dG9tIDw9IHRoaXMuY29udGFpbmVyLnZpZXdwb3J0Qm90dG9tKSB8fFxuICAgICAgICAgICAgICAgICh0aGlzLmlzQWJvdmVWaWV3cG9ydCAmJiB0aGlzLmlzQmVsb3dWaWV3cG9ydCk7XG4gICAgfTtcbiAgICBXYXRjaGVyLnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgaW5kZXggPSB0aGlzLmNvbnRhaW5lci53YXRjaGVycy5pbmRleE9mKHRoaXMpLCBzZWxmID0gdGhpcztcbiAgICAgICAgdGhpcy5jb250YWluZXIud2F0Y2hlcnMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICAgICAgc2VsZi5jYWxsYmFja3MgPSB7fTtcbiAgICB9O1xuICAgIC8vIHByZXZlbnQgcmVjYWxjdWxhdGluZyB0aGUgZWxlbWVudCBsb2NhdGlvblxuICAgIFdhdGNoZXIucHJvdG90eXBlLmxvY2sgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMubG9ja2VkID0gdHJ1ZTtcbiAgICB9O1xuICAgIFdhdGNoZXIucHJvdG90eXBlLnVubG9jayA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5sb2NrZWQgPSBmYWxzZTtcbiAgICB9O1xuICAgIHJldHVybiBXYXRjaGVyO1xufSgpKTtcbmV4cG9ydCB7IFdhdGNoZXIgfTtcbnZhciBldmVudEhhbmRsZXJGYWN0b3J5ID0gZnVuY3Rpb24gKHR5cGUpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKGNhbGxiYWNrLCBpc09uZSkge1xuICAgICAgICBpZiAoaXNPbmUgPT09IHZvaWQgMCkgeyBpc09uZSA9IGZhbHNlOyB9XG4gICAgICAgIHRoaXMub24uY2FsbCh0aGlzLCB0eXBlLCBjYWxsYmFjaywgaXNPbmUpO1xuICAgIH07XG59O1xuZm9yICh2YXIgaSA9IDAsIGogPSBldmVudFR5cGVzLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuICAgIHZhciB0eXBlID0gZXZlbnRUeXBlc1tpXTtcbiAgICBXYXRjaGVyLnByb3RvdHlwZVt0eXBlXSA9IGV2ZW50SGFuZGxlckZhY3RvcnkodHlwZSk7XG59XG4vLyMgc291cmNlTWFwcGluZ1VSTD13YXRjaGVyLmpzLm1hcCIsImltcG9ydCB7IENvbnNvbGVXcml0ZXIsIFNwbGl0U3RyZWFtV3JpdGVyIH0gZnJvbSBcIi4vd3JpdGVyc1wiO1xuaW1wb3J0IHsgQ29uc29sZVRyYW5zcG9ydCwgVHJhbnNwb3J0TG9nZ2VyIH0gZnJvbSBcIi4vbG9nZ2VyXCI7XG5pbXBvcnQgeyBDb250ZXh0IH0gZnJvbSBcIi4vdXRpbHNcIjtcbi8qKlxuICogRGVmYXVsdCBhc3NlbWJseSBwb2ludCBvZiBjb2xsZWN0b3JzIGFuZCB3cml0ZXJzLlxuICovXG5leHBvcnQgY2xhc3MgQ29sbGVjdG9yTW9kdWxlIHtcbiAgICBjb25zdHJ1Y3RvcihvcHRpb25zKSB7XG4gICAgICAgIHRoaXMuY29sbGVjdG9ycyA9IFtdO1xuICAgICAgICB0aGlzLndyaXRlcnMgPSBbXTtcbiAgICAgICAgdGhpcy50cmFuc3BvcnRzID0gW107XG4gICAgICAgIHRoaXMuaGFzU3RhcnRlZCA9IGZhbHNlO1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgIH1cbiAgICBhZGQoY29sbGVjdG9yKSB7XG4gICAgICAgIGlmICghY29sbGVjdG9yLmdldENvbnRleHQoKSlcbiAgICAgICAgICAgIGNvbGxlY3Rvci5zZXRDb250ZXh0KHRoaXMub3B0aW9ucy5jb250ZXh0IHx8IG5ldyBDb250ZXh0KHdpbmRvdywgZG9jdW1lbnQpKTtcbiAgICAgICAgdGhpcy5jb2xsZWN0b3JzLnB1c2goY29sbGVjdG9yKTtcbiAgICAgICAgaWYgKHRoaXMuaGFzU3RhcnRlZCA9PT0gdHJ1ZSlcbiAgICAgICAgICAgIHRoaXMuaW52b2tlZENvbGxlY3Rvcihjb2xsZWN0b3IpO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBTdGFydCBjb2xsZWN0aW5nIGRhdGEgYnkgYXR0YWNoaW5nIGFsbCBjb2xsZWN0b3JzXG4gICAgICovXG4gICAgc3RhcnQoKSB7XG4gICAgICAgIHRoaXMuY29sbGVjdG9ycy5mb3JFYWNoKGNvbGxlY3RvciA9PiB0aGlzLmludm9rZWRDb2xsZWN0b3IoY29sbGVjdG9yKSk7XG4gICAgICAgIHRoaXMuaGFzU3RhcnRlZCA9IHRydWU7XG4gICAgfVxuICAgIGFkZExvZ1RyYW5zcG9ydCh0cmFuc3BvcnQpIHtcbiAgICAgICAgdGhpcy50cmFuc3BvcnRzLnB1c2godHJhbnNwb3J0KTtcbiAgICB9XG4gICAgc2V0VHJhbnNwb3J0cyh0cmFuc3BvcnRzKSB7XG4gICAgICAgIHRoaXMudHJhbnNwb3J0cyA9IHRyYW5zcG9ydHMgfHwgW107XG4gICAgfVxuICAgIHNldFdyaXRlcnMocmVwbGFjZW1lbnRXcml0ZXJzKSB7XG4gICAgICAgIHRoaXMud3JpdGVycyA9IEFycmF5LmlzQXJyYXkocmVwbGFjZW1lbnRXcml0ZXJzKSA/IFsuLi5yZXBsYWNlbWVudFdyaXRlcnNdIDogW3JlcGxhY2VtZW50V3JpdGVyc107XG4gICAgfVxuICAgIHNldExvZ2dlcihsb2dnZXIpIHtcbiAgICAgICAgdGhpcy5sb2dnZXIgPSBsb2dnZXI7XG4gICAgfVxuICAgIGludm9rZWRDb2xsZWN0b3IoY29sbGVjdG9yKSB7XG4gICAgICAgIGNvbnN0IHdyaXRlciA9IHRoaXMuZ2V0V3JpdGVyKCk7XG4gICAgICAgIGNvbnN0IGxvZyA9IHRoaXMuZ2V0TG9nZ2VyKCk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb2xsZWN0b3IuYXR0YWNoKHdyaXRlciwgbG9nKTtcbiAgICAgICAgfVxuICAgICAgICBjYXRjaCAoZSkge1xuICAgICAgICAgICAgbG9nLmVycm9yKGBbJHtjb2xsZWN0b3IuY29uc3RydWN0b3IubmFtZX1dIFVuZXhwZWN0ZWQgRXhjZXB0aW9uIGR1cmluZyBjb2xsZWN0b3IgYXR0YWNoOiBgLCBlKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBnZXRMb2dnZXIoKSB7XG4gICAgICAgIGNvbnN0IGhhc0xvZ2dlciA9ICEhdGhpcy5sb2dnZXI7XG4gICAgICAgIGlmIChoYXNMb2dnZXIpXG4gICAgICAgICAgICByZXR1cm4gdGhpcy5sb2dnZXI7XG4gICAgICAgIGlmICghdGhpcy50cmFuc3BvcnRzIHx8IHRoaXMudHJhbnNwb3J0cy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgVHJhbnNwb3J0TG9nZ2VyKFtuZXcgQ29uc29sZVRyYW5zcG9ydCgpXSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG5ldyBUcmFuc3BvcnRMb2dnZXIodGhpcy50cmFuc3BvcnRzKTtcbiAgICB9XG4gICAgZ2V0V3JpdGVyKCkge1xuICAgICAgICByZXR1cm4gdGhpcy53cml0ZXJzLmxlbmd0aCA9PSAwXG4gICAgICAgICAgICA/IHRoaXMub3B0aW9ucy53cml0ZXIgfHwgbmV3IENvbnNvbGVXcml0ZXIoKVxuICAgICAgICAgICAgOiBuZXcgU3BsaXRTdHJlYW1Xcml0ZXIodGhpcy53cml0ZXJzKTtcbiAgICB9XG59XG4iLCJleHBvcnQgY2xhc3MgQWJzdHJhY3RDb2xsZWN0b3Ige1xuICAgIGNvbnN0cnVjdG9yKHR5cGUsIGNvbnRleHQpIHtcbiAgICAgICAgdGhpcy50eXBlID0gdHlwZTtcbiAgICAgICAgdGhpcy5jb250ZXh0ID0gY29udGV4dDtcbiAgICB9XG4gICAgZ2V0VHlwZSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudHlwZTtcbiAgICB9XG4gICAgc2V0Q29udGV4dChjb250ZXh0KSB7XG4gICAgICAgIHRoaXMuY29udGV4dCA9IGNvbnRleHQ7XG4gICAgfVxuICAgIGdldENvbnRleHQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmNvbnRleHQ7XG4gICAgfVxuICAgIGdldFdpbmRvdygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY29udGV4dC5nZXRXaW5kb3coKTtcbiAgICB9XG4gICAgZ2V0RG9jdW1lbnQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmNvbnRleHQuZ2V0RG9jdW1lbnQoKTtcbiAgICB9XG4gICAgYXR0YWNoKHdyaXRlciwgbG9nKSB7XG4gICAgICAgIC8vIG92ZXJyaWRlIGluIHN1YmNsYXNzXG4gICAgfVxuICAgIC8qKlxuICAgICAqIFVzZWQgdG8gbG9nIGlmIGEgaGFuZGxlciBmYWlscyBpdHMgZXhlY3V0aW9uXG4gICAgICogVXNhZ2U6IGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoXCJjbGlja1wiLCB0aGlzLmxvZ1dyYXBIYW5kbGVyKHlvdXJoYW5kbGVyLCBsb2dnZXIpKVxuICAgICAqIEBwYXJhbSBoYW5kbGVyXG4gICAgICogQHBhcmFtIGxvZ1xuICAgICAqIEBwYXJhbSBoYW5kbGVyQXJnc1xuICAgICAqIEBwcm90ZWN0ZWRcbiAgICAgKi9cbiAgICBsb2dXcmFwSGFuZGxlcihoYW5kbGVyLCBsb2csIC4uLmhhbmRsZXJBcmdzKSB7XG4gICAgICAgIHJldHVybiAoLi4uYXJncykgPT4ge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gaGFuZGxlciguLi5hcmdzLCAuLi5oYW5kbGVyQXJncyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIGlmIChsb2cpXG4gICAgICAgICAgICAgICAgICAgIGxvZy5lcnJvcihgWyR7dGhpcy5jb25zdHJ1Y3Rvci5uYW1lfV0gVW5leHBlY3RlZCBlcnJvciBkdXJpbmcgcmVzb2x2ZXIgZXhlY3V0aW9uOiBgLCBlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogVXNlZCB0byBleGVjdXRlIHJlc29sdmVyIGZ1bmN0aW9ucy5cbiAgICAgKiBMb2dzIGEgZGVidWcgbWVzc2FnZSBpZiB0aGUgdmFsdWUgaXMgdW5kZWZpbmVkIG9yIGxvZ3MgYW4gZXJyb3IgaWYgYW4gZXhjZXB0aW9uIGlzIHRocm93biBieSB0aGUgcmVzb2x2ZXJcbiAgICAgKiBAcGFyYW0gcmVzb2x2ZXIgQSByZXNvbHZlciBmdW5jdGlvblxuICAgICAqIEBwYXJhbSBsb2cgdGhlIGxvZ2dlclxuICAgICAqIEBwYXJhbSByZXNvbHZlckFyZ3MgYXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byB0aGUgcmVzb2x2ZXIgZnVuY3Rpb25cbiAgICAgKiBAcHJvdGVjdGVkXG4gICAgICovXG4gICAgcmVzb2x2ZShyZXNvbHZlciwgbG9nLCAuLi5yZXNvbHZlckFyZ3MpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGlmIChyZXNvbHZlcikge1xuICAgICAgICAgICAgICAgIGNvbnN0IHZhbCA9IHJlc29sdmVyKC4uLnJlc29sdmVyQXJncyk7XG4gICAgICAgICAgICAgICAgaWYgKHZhbCA9PSB2b2lkIDApXG4gICAgICAgICAgICAgICAgICAgIGxvZy5kZWJ1ZyhcIlJlc29sdmVyIHJldHVybmVkIG5vIHZhbHVlLlwiLCByZXNvbHZlcik7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHZhbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBjYXRjaCAoZSkge1xuICAgICAgICAgICAgaWYgKGxvZyAmJiBsb2cuZXJyb3IpIHtcbiAgICAgICAgICAgICAgICBsb2cuZXJyb3IoYFske3RoaXMuY29uc3RydWN0b3IubmFtZX1dIFVuZXhwZWN0ZWQgZXJyb3IgZHVyaW5nIHJlc29sdmVyIGV4ZWN1dGlvbjogYCwgZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59XG4iLCJpbXBvcnQgeyBTZW50aW5lbCB9IGZyb20gXCIuLi91dGlscy9TZW50aW5lbFwiO1xuaW1wb3J0IHsgQWJzdHJhY3RDb2xsZWN0b3IgfSBmcm9tIFwiLi9BYnN0cmFjdENvbGxlY3RvclwiO1xuaW1wb3J0IHsgVHJhaWxUeXBlIH0gZnJvbSBcIi4uL3F1ZXJ5L1RyYWlsVHlwZVwiO1xuLyoqXG4gKiBDb2xsZWN0IGNsaWNrcyBvbiBlbGVtZW50cyBtYXRjaGluZyBhIHF1ZXJ5IHNlbGVjdG9yLiBIYW5kbGVzIGJvdGggRE9NIGVsZW1lbnRzXG4gKiBwcmVzZW50IGluIHRoZSBET00gYW5kIGVsZW1lbnRzIGluc2VydGVkIGFmdGVyIHRoZSBwYWdlIGxvYWQgLyBjb2xsZWN0b3IgY29uc3RydWN0aW9uLlxuICpcbiAqIFdoZW4gYSBjbGljayBvY2N1cnMsIGEgZnVuY3Rpb24gcHJvdmlkZWQgYXQgY29uc3RydWN0aW9uIHRpbWUgZ2V0IGludm9rZWQgdG8gY29sbGVjdCBkYXRhIHBvaW50c1xuICogZnJvbSB0aGUgZWxlbWVudC5cbiAqL1xuZXhwb3J0IGNsYXNzIEFzc29jaWF0ZWRQcm9kdWN0Q29sbGVjdG9yIGV4dGVuZHMgQWJzdHJhY3RDb2xsZWN0b3Ige1xuICAgIC8qKlxuICAgICAqIENvbnN0cnVjdCBhIGNsaWNrIGNvbGxlY3RvclxuICAgICAqXG4gICAgICogQGNvbnN0cnVjdG9yXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHNlbGVjdG9yRXhwcmVzc2lvbiAtIERvY3VtZW50IHF1ZXJ5IHNlbGVjdG9yIGlkZW50aWZ5aW5nIHRoZSBlbGVtZW50cyB0byBhdHRhY2ggdG9cbiAgICAgKiBAcGFyYW0gbWFpblByb2R1Y3RJZFxuICAgICAqIEBwYXJhbSByZXNvbHZlcnNcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihzZWxlY3RvckV4cHJlc3Npb24sIG1haW5Qcm9kdWN0SWQsIHJlc29sdmVycykge1xuICAgICAgICBzdXBlcihcImFzc29jaWF0ZWQtcHJvZHVjdFwiKTtcbiAgICAgICAgdGhpcy5tYWluUHJvZHVjdElkID0gbWFpblByb2R1Y3RJZDtcbiAgICAgICAgdGhpcy5zZWxlY3RvckV4cHJlc3Npb24gPSBzZWxlY3RvckV4cHJlc3Npb247XG4gICAgICAgIHRoaXMuaWRSZXNvbHZlciA9IHJlc29sdmVycy5pZFJlc29sdmVyO1xuICAgICAgICB0aGlzLnBvc2l0aW9uUmVzb2x2ZXIgPSByZXNvbHZlcnMucG9zaXRpb25SZXNvbHZlcjtcbiAgICAgICAgdGhpcy5wcmljZVJlc29sdmVyID0gcmVzb2x2ZXJzLnByaWNlUmVzb2x2ZXI7XG4gICAgICAgIHRoaXMudHJhaWwgPSByZXNvbHZlcnMudHJhaWw7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEFkZCBjbGljayBldmVudCBsaXN0ZW5lcnMgdG8gdGhlIGlkZW50aWZpZWQgZWxlbWVudHMsIHdyaXRlIHRoZSBkYXRhXG4gICAgICogd2hlbiB0aGUgZXZlbnQgb2NjdXJzXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gd3JpdGVyIC0gVGhlIHdyaXRlciB0byBzZW5kIHRoZSBkYXRhIHRvXG4gICAgICogQHBhcmFtIGxvZ1xuICAgICAqL1xuICAgIGF0dGFjaCh3cml0ZXIsIGxvZykge1xuICAgICAgICBjb25zdCBjb2xsZWN0ID0gZWxlbWVudCA9PiB7XG4gICAgICAgICAgICBjb25zdCBpZCA9IHRoaXMucmVzb2x2ZSh0aGlzLmlkUmVzb2x2ZXIsIGxvZywgZWxlbWVudCk7XG4gICAgICAgICAgICBpZiAoaWQpIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy50cmFpbCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBGaW5kIG91dCB0aGUgcXVlcnkgc291cmNlIG9mIHRoZSBtYWluIHByb2R1Y3QuIE5vdGUgdGhhdCBkZXNwaXRlIGJlaW5nIGFcbiAgICAgICAgICAgICAgICAgICAgLy8gXCJtYWluXCIgcHJvZHVjdCwgaXQgY291bGQgYmUgYSAybmQgb3IgM3JkLCA0dGggbGV2ZWwgb2YgYXNzb2NpYXRlZCBwcm9kdWN0IGJyb3dzaW5nXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHByZXZpb3VzVHJhaWwgPSB0aGlzLnRyYWlsLmZldGNoKHRoaXMubWFpblByb2R1Y3RJZCk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChwcmV2aW91c1RyYWlsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBVcG9uIGEgZm9sbG93LXVwIGV2ZW50IGZvciB0aGlzIHByb2R1Y3QgKGV4LiBiYXNrZXQpLCB3ZSB3b3VsZCBwaWNrIHRoaXMgdHJhaWxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMudHJhaWwucmVnaXN0ZXIoaWQsIFRyYWlsVHlwZS5Bc3NvY2lhdGVkLCBwcmV2aW91c1RyYWlsLnF1ZXJ5KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgICAgICBpZCxcbiAgICAgICAgICAgICAgICAgICAgcG9zaXRpb246IHRoaXMucmVzb2x2ZSh0aGlzLnBvc2l0aW9uUmVzb2x2ZXIsIGxvZywgZWxlbWVudCksXG4gICAgICAgICAgICAgICAgICAgIHByaWNlOiB0aGlzLnJlc29sdmUodGhpcy5wcmljZVJlc29sdmVyLCBsb2csIGVsZW1lbnQpXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgaGFuZGxlciA9IGVsID0+IHtcbiAgICAgICAgICAgIGVsLmFkZEV2ZW50TGlzdGVuZXIoXCJjbGlja1wiLCB0aGlzLmxvZ1dyYXBIYW5kbGVyKGV2ID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBwYXlsb2FkID0gY29sbGVjdChlbCk7XG4gICAgICAgICAgICAgICAgaWYgKHBheWxvYWQpIHtcbiAgICAgICAgICAgICAgICAgICAgd3JpdGVyLndyaXRlKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIFwidHlwZVwiOiB0aGlzLmdldFR5cGUoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIC4uLnBheWxvYWRcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSwgbG9nKSk7XG4gICAgICAgIH07XG4gICAgICAgIG5ldyBTZW50aW5lbCh0aGlzLmdldERvY3VtZW50KCkpLm9uKHRoaXMuc2VsZWN0b3JFeHByZXNzaW9uLCBoYW5kbGVyKTtcbiAgICB9XG59XG4iLCJpbXBvcnQgeyBDbGlja0NvbGxlY3RvciB9IGZyb20gXCIuL0NsaWNrQ29sbGVjdG9yXCI7XG5pbXBvcnQgeyBMaXN0ZW5lclR5cGUgfSBmcm9tIFwiLi4vdXRpbHMvTGlzdGVuZXJUeXBlXCI7XG4vKipcbiAqIENvbGxlY3QgaWQgYW5kIHByaWNlIGlmIGFuIGl0ZW0gd2FzIGFkZCBpbnRvIHRoZSBiYXNrZXRcbiAqL1xuZXhwb3J0IGNsYXNzIEJhc2tldENsaWNrQ29sbGVjdG9yIGV4dGVuZHMgQ2xpY2tDb2xsZWN0b3Ige1xuICAgIGNvbnN0cnVjdG9yKHNlbGVjdG9yLCBpZFJlc29sdmVyLCBwcmljZVJlc29sdmVyLCBsaXN0ZW5lclR5cGUgPSBMaXN0ZW5lclR5cGUuU2VudGluZWwpIHtcbiAgICAgICAgc3VwZXIoc2VsZWN0b3IsIFwiYmFza2V0XCIsIGxpc3RlbmVyVHlwZSk7XG4gICAgICAgIHRoaXMuaWRSZXNvbHZlciA9IGlkUmVzb2x2ZXI7XG4gICAgICAgIHRoaXMucHJpY2VSZXNvbHZlciA9IHByaWNlUmVzb2x2ZXI7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIENvbGxlY3QgdGhlIHByb2R1Y3QgY2xpY2sgaW5mb3JtYXRpb24gZnJvbSB0aGUgZWxlbWVudFxuICAgICAqIEBvdmVycmlkZVxuICAgICAqL1xuICAgIGNvbGxlY3QoZWxlbWVudCwgZXZlbnQsIGxvZykge1xuICAgICAgICBjb25zdCBpZCA9IHRoaXMucmVzb2x2ZSh0aGlzLmlkUmVzb2x2ZXIsIGxvZywgZWxlbWVudCwgZXZlbnQpO1xuICAgICAgICBpZiAoaWQpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgaWQsXG4gICAgICAgICAgICAgICAgcHJpY2U6IHRoaXMucmVzb2x2ZSh0aGlzLnByaWNlUmVzb2x2ZXIsIGxvZywgZWxlbWVudCwgZXZlbnQpXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgfVxufVxuIiwiaW1wb3J0IHsgQWJzdHJhY3RDb2xsZWN0b3IgfSBmcm9tIFwiLi9BYnN0cmFjdENvbGxlY3RvclwiO1xuLyoqXG4gKiBDb2xsZWN0IGJhc2ljIGJyb3dzZXIgaW5mb3JtYXRpb24uIE5vdGUgdGhhdCBkZXBlbmRpbmcgb24gaG93IHlvdSB1c2UgdGhpcyB5b3UgbWF5XG4gKiBuZWVkIHRvIGNvbnN1bHQgdGhlIEdEUFIgZ3VpZGVsaW5lc1xuICovXG5leHBvcnQgY2xhc3MgQnJvd3NlckNvbGxlY3RvciBleHRlbmRzIEFic3RyYWN0Q29sbGVjdG9yIHtcbiAgICBjb25zdHJ1Y3RvcihvcHRpb25zID0geyByZWNvcmRVcmw6IHRydWUsIHJlY29yZFJlZmVycmVyOiB0cnVlLCByZWNvcmRMYW5ndWFnZTogZmFsc2UsIHJlY29yZFVzZXJBZ2VudDogZmFsc2UgfSkge1xuICAgICAgICBzdXBlcihcImJyb3dzZXJcIik7XG4gICAgICAgIHRoaXMucmVjb3JkVXJsID0gb3B0aW9ucy5yZWNvcmRVcmwgfHwgZmFsc2U7XG4gICAgICAgIHRoaXMucmVjb3JkUmVmZXJyZXIgPSBvcHRpb25zLnJlY29yZFJlZmVycmVyIHx8IGZhbHNlO1xuICAgICAgICB0aGlzLnJlY29yZExhbmd1YWdlID0gb3B0aW9ucy5yZWNvcmRMYW5ndWFnZSB8fCBmYWxzZTtcbiAgICAgICAgdGhpcy5yZWNvcmRVc2VyQWdlbnQgPSBvcHRpb25zLnJlY29yZFVzZXJBZ2VudCB8fCBmYWxzZTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogQXR0YWNoIGEgd3JpdGVyLCBub3RlIHRoYXQgdGhpcyBjb2xsZWN0b3IgaXMgbm90IGFzeW5jaHJvbm91cyBhbmQgd2lsbCB3cml0ZVxuICAgICAqIHRoZSBkYXRhIGltbWVkaWF0ZWxseVxuICAgICAqXG4gICAgICogQHBhcmFtIHtvYmplY3R9IHdyaXRlciAtIFRoZSB3cml0ZXIgdG8gc2VuZCB0aGUgZGF0YSB0b1xuICAgICAqL1xuICAgIGF0dGFjaCh3cml0ZXIpIHtcbiAgICAgICAgY29uc3Qgd2luID0gdGhpcy5nZXRXaW5kb3coKTtcbiAgICAgICAgY29uc3QgZG9jID0gdGhpcy5nZXREb2N1bWVudCgpO1xuICAgICAgICBjb25zdCBkYXRhID0ge1xuICAgICAgICAgICAgdHlwZTogdGhpcy5nZXRUeXBlKCksXG4gICAgICAgICAgICB0b3VjaDogKCdvbnRvdWNoc3RhcnQnIGluIHdpbmRvdykgfHwgKG5hdmlnYXRvci5tYXhUb3VjaFBvaW50cyA+IDApXG4gICAgICAgIH07XG4gICAgICAgIGlmICh0aGlzLnJlY29yZExhbmd1YWdlKVxuICAgICAgICAgICAgZGF0YS5sYW5nID0gd2luLm5hdmlnYXRvci5sYW5ndWFnZTtcbiAgICAgICAgaWYgKHRoaXMucmVjb3JkVXJsKVxuICAgICAgICAgICAgZGF0YS51cmwgPSB3aW4ubG9jYXRpb24uaHJlZjtcbiAgICAgICAgaWYgKHRoaXMucmVjb3JkUmVmZXJyZXIpXG4gICAgICAgICAgICBkYXRhLnJlZiA9IGRvYy5yZWZlcnJlcjtcbiAgICAgICAgaWYgKHRoaXMucmVjb3JkVXNlckFnZW50KVxuICAgICAgICAgICAgZGF0YS5hZ2VudCA9IHdpbmRvdy5uYXZpZ2F0b3IudXNlckFnZW50O1xuICAgICAgICB3cml0ZXIud3JpdGUoZGF0YSk7XG4gICAgfVxufVxuIiwiaW1wb3J0IHsgQWJzdHJhY3RDb2xsZWN0b3IgfSBmcm9tIFwiLi9BYnN0cmFjdENvbGxlY3RvclwiO1xuaW1wb3J0IHsgU2VudGluZWwgfSBmcm9tIFwiLi4vdXRpbHMvU2VudGluZWxcIjtcbmltcG9ydCB7IExpc3RlbmVyVHlwZSB9IGZyb20gXCIuLi91dGlscy9MaXN0ZW5lclR5cGVcIjtcbi8qKlxuICogVHJpZ2dlcmVkIGJ5IGEgY2xpY2tTZWxlY3RvciwgdGhlIGNvbGxlY3RvciB3aWxsIGZpcmUgdGhlIGNvbnRlbnRTZWxlY3RvciB0byBzZWxlY3QgZWxlbWVudHMgdG8gY29sbGVjdFxuICogaW5mb3JtYXRpb24gZnJvbSBhbmQgd3JpdGUgdG8gdGhlIGNvbGxlY3RvciB3cml0ZXJcbiAqL1xuZXhwb3J0IGNsYXNzIENoZWNrb3V0Q2xpY2tDb2xsZWN0b3IgZXh0ZW5kcyBBYnN0cmFjdENvbGxlY3RvciB7XG4gICAgY29uc3RydWN0b3IoY2xpY2tTZWxlY3RvciwgY29udGVudFNlbGVjdG9yLCBpZFJlc29sdmVyLCBwcmljZVJlc29sdmVyLCBhbW91bnRSZXNvbHZlciwgbGlzdGVuZXJUeXBlID0gTGlzdGVuZXJUeXBlLlNlbnRpbmVsKSB7XG4gICAgICAgIHN1cGVyKFwiY2hlY2tvdXRcIik7XG4gICAgICAgIHRoaXMuY2xpY2tTZWxlY3RvciA9IGNsaWNrU2VsZWN0b3I7XG4gICAgICAgIHRoaXMuY29udGVudFNlbGVjdG9yID0gY29udGVudFNlbGVjdG9yO1xuICAgICAgICB0aGlzLmlkUmVzb2x2ZXIgPSBpZFJlc29sdmVyO1xuICAgICAgICB0aGlzLnByaWNlUmVzb2x2ZXIgPSBwcmljZVJlc29sdmVyO1xuICAgICAgICB0aGlzLmFtb3VudFJlc29sdmVyID0gYW1vdW50UmVzb2x2ZXI7XG4gICAgICAgIHRoaXMubGlzdGVuZXJUeXBlID0gbGlzdGVuZXJUeXBlO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBBZGQgY2xpY2sgZXZlbnQgbGlzdGVuZXJzIHRvIHRoZSBpZGVudGlmaWVkIGVsZW1lbnRzLCB3cml0ZSB0aGUgZGF0YVxuICAgICAqIHdoZW4gdGhlIGV2ZW50IG9jY3Vyc1xuICAgICAqXG4gICAgICogQHBhcmFtIHtvYmplY3R9IHdyaXRlciAtIFRoZSB3cml0ZXIgdG8gc2VuZCB0aGUgZGF0YSB0b1xuICAgICAqIEBwYXJhbSBsb2dcbiAgICAgKi9cbiAgICBhdHRhY2god3JpdGVyLCBsb2cpIHtcbiAgICAgICAgY29uc3QgZG9jID0gdGhpcy5nZXREb2N1bWVudCgpO1xuICAgICAgICAvLyBBY3RpdmF0ZXMgb24gY2xpY2sgb2YgdGhlIGVsZW1lbnQgc2VsZWN0ZWQgdXNpbmcgdGhlIGNsaWNrU2VsZWN0b3JcbiAgICAgICAgY29uc3QgaGFuZGxlciA9IChldmVudCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgZWxlbWVudHMgPSBkb2MucXVlcnlTZWxlY3RvckFsbCh0aGlzLmNvbnRlbnRTZWxlY3Rvcik7XG4gICAgICAgICAgICBlbGVtZW50cy5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IGlkID0gdGhpcy5yZXNvbHZlKHRoaXMuaWRSZXNvbHZlciwgbG9nLCBlbGVtZW50LCBldmVudCk7XG4gICAgICAgICAgICAgICAgaWYgKGlkKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGRhdGEgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHByaWNlOiB0aGlzLnJlc29sdmUodGhpcy5wcmljZVJlc29sdmVyLCBsb2csIGVsZW1lbnQsIGV2ZW50KSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGFtb3VudDogdGhpcy5yZXNvbHZlKHRoaXMuYW1vdW50UmVzb2x2ZXIsIGxvZywgZWxlbWVudCwgZXZlbnQpXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIC8vIFdlIHdyaXRlIGVhY2ggaXRlbSBzZXBhcmF0ZWx5IC0gdGhleSBtYXkgYmUgY29taW5nIGZyb20gZGlmZmVyZW50IHF1ZXJpZXNcbiAgICAgICAgICAgICAgICAgICAgLy8gdGh1cyB3aGVuIHdlIHRyeSB0byByZXNvbHZlIHRoZSB0cmFpbCBmb3IgZWFjaCBvZiB0aGVtIHdlIG5lZWQgdG8gaGF2ZSB0aGVtXG4gICAgICAgICAgICAgICAgICAgIC8vIGFzIHNlcGFyYXRlIHJlY29yZHNcbiAgICAgICAgICAgICAgICAgICAgd3JpdGVyLndyaXRlKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6IHRoaXMuZ2V0VHlwZSgpLFxuICAgICAgICAgICAgICAgICAgICAgICAgLi4uZGF0YVxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfTtcbiAgICAgICAgLy8gVGhlIFNlbnRpZWwgbGlicmFyeSB1c2VzIGFuaW1hdGlvbnN0YXJ0IGV2ZW50IGxpc3RlbmVycyB3aGljaCBtYXkgaW50ZXJmZXJlIHdpdGhcbiAgICAgICAgLy8gYW5pbWF0aW9ucyBhdHRhY2hlZCBvbiBlbGVtZW5ldHMuIFRoZSBpbi1saWJyYXJ5IHByb3ZpZGVkIHdvcmthcm91bmQgbWVjaGFuaXNtIGRvZXMgbm90IHdvcmtcbiAgICAgICAgLy8gMTAwJSwgdGh1cyB3ZSBwcm92aWRlIHRoZSBsaXN0ZW5lclR5cGUgY2hvaWNlIGJlbG93LiBUaGUgdHJhZGVvZmZzXG4gICAgICAgIC8vIFwiZG9tXCIgLSBubyBhbmltYXRpb24gaW50ZXJmZXJlbmNlLCBvbmx5IG9uY2xpY2sgYXR0YWNoZWQsIGJ1dCBkb2VzIG5vdCBoYW5kbGUgZWxlbWVudHMgaW5zZXJ0ZWQgaW4gdGhlIERPTSBsYXRlclxuICAgICAgICAvLyBcInNlbnRpbmVsIChkZWZhdWx0KVwiIC0gd29ya3Mgb24gZWxlbWVudHMgaW5zZXJ0ZWQgaW4gdGhlIERPTSBhbnl0aW1lLCBidXQgaW50ZXJmZXJlcyB3aXRoIENTUyBhbmltYXRpb25zIG9uIHRoZXNlIGVsZW1lbnRzXG4gICAgICAgIGlmICh0aGlzLmxpc3RlbmVyVHlwZSA9PT0gTGlzdGVuZXJUeXBlLkRvbSkge1xuICAgICAgICAgICAgY29uc3Qgbm9kZUxpc3QgPSBkb2MucXVlcnlTZWxlY3RvckFsbCh0aGlzLmNsaWNrU2VsZWN0b3IpO1xuICAgICAgICAgICAgbm9kZUxpc3QuZm9yRWFjaCgoZWwpID0+IGVsLmFkZEV2ZW50TGlzdGVuZXIoXCJjbGlja1wiLCB0aGlzLmxvZ1dyYXBIYW5kbGVyKGhhbmRsZXIsIGxvZyksIHtcbiAgICAgICAgICAgICAgICBwYXNzaXZlOiB0cnVlLFxuICAgICAgICAgICAgICAgIGNhcHR1cmU6IHRydWVcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IHNlbnRpbmVsID0gbmV3IFNlbnRpbmVsKHRoaXMuZ2V0RG9jdW1lbnQoKSk7XG4gICAgICAgICAgICBzZW50aW5lbC5vbih0aGlzLmNsaWNrU2VsZWN0b3IsIGVsID0+IGVsLmFkZEV2ZW50TGlzdGVuZXIoXCJjbGlja1wiLCB0aGlzLmxvZ1dyYXBIYW5kbGVyKGhhbmRsZXIsIGxvZyksIHtcbiAgICAgICAgICAgICAgICBwYXNzaXZlOiB0cnVlLFxuICAgICAgICAgICAgICAgIGNhcHR1cmU6IHRydWVcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuICAgIH1cbn1cbiIsImltcG9ydCB7IEFic3RyYWN0Q29sbGVjdG9yIH0gZnJvbSBcIi4vQWJzdHJhY3RDb2xsZWN0b3JcIjtcbmltcG9ydCB7IFNlbnRpbmVsIH0gZnJvbSBcIi4uL3V0aWxzL1NlbnRpbmVsXCI7XG5pbXBvcnQgeyBMaXN0ZW5lclR5cGUgfSBmcm9tIFwiLi4vdXRpbHMvTGlzdGVuZXJUeXBlXCI7XG4vKipcbiAqIENvbGxlY3QgY2xpY2tzIG9uIGVsZW1lbnRzIG1hdGNoaW5nIGEgcXVlcnkgc2VsZWN0b3IuIEhhbmRsZXMgYm90aCBET00gZWxlbWVudHNcbiAqIHByZXNlbnQgaW4gdGhlIERPTSBhbmQgZWxlbWVudHMgaW5zZXJ0ZWQgYWZ0ZXIgdGhlIHBhZ2UgbG9hZCAvIGNvbGxlY3RvciBjb25zdHJ1Y3Rpb24uXG4gKlxuICogV2hlbiBhIGNsaWNrIG9jY3VycywgYSBmdW5jdGlvbiBwcm92aWRlZCBhdCBjb25zdHJ1Y3Rpb24gdGltZSBnZXQgaW52b2tlZCB0byBjb2xsZWN0IGRhdGEgcG9pbnRzXG4gKiBmcm9tIHRoZSBlbGVtZW50LlxuICovXG5leHBvcnQgY2xhc3MgQ2xpY2tDb2xsZWN0b3IgZXh0ZW5kcyBBYnN0cmFjdENvbGxlY3RvciB7XG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0IGEgY2xpY2sgY29sbGVjdG9yXG4gICAgICpcbiAgICAgKiBAY29uc3RydWN0b3JcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gc2VsZWN0b3JFeHByZXNzaW9uIC0gRG9jdW1lbnQgcXVlcnkgc2VsZWN0b3IgaWRlbnRpZnlpbmcgdGhlIGVsZW1lbnRzIHRvIGF0dGFjaCB0b1xuICAgICAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIHR5cGUgT0YgZWxlbWVudCBjbGljayB0byByZXBvcnRcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gbGlzdGVuZXJUeXBlIC0gV2hldGhlciB0aGUgbGlzdGVuZXIgc2hvdWxkIGJlIGEgZG9tIG9yIHNlbnRpbmVsIGxpc3RlbmVyXG4gICAgICogQHBhcmFtIGNvbnRleHRcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihzZWxlY3RvckV4cHJlc3Npb24sIHR5cGUgPSBcImNsaWNrXCIsIGxpc3RlbmVyVHlwZSA9IExpc3RlbmVyVHlwZS5TZW50aW5lbCwgY29udGV4dCkge1xuICAgICAgICBzdXBlcih0eXBlLCBjb250ZXh0KTtcbiAgICAgICAgdGhpcy5zZWxlY3RvckV4cHJlc3Npb24gPSBzZWxlY3RvckV4cHJlc3Npb247XG4gICAgICAgIHRoaXMubGlzdGVuZXJUeXBlID0gbGlzdGVuZXJUeXBlO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBBYnN0cmFjdCBjb2xsZWN0aW9uIG1ldGhvZCwgbXVzdCBiZSBvdmVycmlkZGVuIGluIHRoZSBzdWJjbGFzc2VzXG4gICAgICogQGFic3RyYWN0XG4gICAgICovXG4gICAgY29sbGVjdChlbGVtZW50LCBldmVudCwgbG9nKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEFkZCBjbGljayBldmVudCBsaXN0ZW5lcnMgdG8gdGhlIGlkZW50aWZpZWQgZWxlbWVudHMsIHdyaXRlIHRoZSBkYXRhXG4gICAgICogd2hlbiB0aGUgZXZlbnQgb2NjdXJzXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gd3JpdGVyIC0gVGhlIHdyaXRlciB0byBzZW5kIHRoZSBkYXRhIHRvXG4gICAgICogQHBhcmFtIGxvZ1xuICAgICAqL1xuICAgIGF0dGFjaCh3cml0ZXIsIGxvZykge1xuICAgICAgICBjb25zdCBoYW5kbGVyID0gKGV2ZW50LCBlbGVtZW50KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBwYXlsb2FkID0gdGhpcy5jb2xsZWN0KGVsZW1lbnQsIGV2ZW50LCBsb2cpO1xuICAgICAgICAgICAgaWYgKHBheWxvYWQpIHtcbiAgICAgICAgICAgICAgICB3cml0ZXIud3JpdGUoe1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiB0aGlzLnR5cGUsXG4gICAgICAgICAgICAgICAgICAgIC4uLnBheWxvYWRcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgLy8gVGhlIFNlbnRpZWwgbGlicmFyeSB1c2VzIGFuaW1hdGlvbnN0YXJ0IGV2ZW50IGxpc3RlbmVycyB3aGljaCBtYXkgaW50ZXJmZXJlIHdpdGhcbiAgICAgICAgLy8gYW5pbWF0aW9ucyBhdHRhY2hlZCBvbiBlbGVtZW5ldHMuIFRoZSBpbi1saWJyYXJ5IHByb3ZpZGVkIHdvcmthcm91bmQgbWVjaGFuaXNtIGRvZXMgbm90IHdvcmtcbiAgICAgICAgLy8gMTAwJSwgdGh1cyB3ZSBwcm92aWRlIHRoZSBsaXN0ZW5lclR5cGUgY2hvaWNlIGJlbG93LiBUaGUgdHJhZGVvZmZzXG4gICAgICAgIC8vIFwiZG9tXCIgLSBubyBhbmltYXRpb24gaW50ZXJmZXJlbmNlLCBvbmx5IG9uY2xpY2sgYXR0YWNoZWQsIGJ1dCBkb2VzIG5vdCBoYW5kbGUgZWxlbWVudHMgaW5zZXJ0ZWQgaW4gdGhlIERPTSBsYXRlclxuICAgICAgICAvLyBcInNlbnRpbmVsIChkZWZhdWx0KVwiIC0gd29ya3Mgb24gZWxlbWVudHMgaW5zZXJ0ZWQgaW4gdGhlIERPTSBhbnl0aW1lLCBidXQgaW50ZXJmZXJlcyB3aXRoIENTUyBhbmltYXRpb25zIG9uIHRoZXNlIGVsZW1lbnRzXG4gICAgICAgIGlmICh0aGlzLmxpc3RlbmVyVHlwZSA9PT0gTGlzdGVuZXJUeXBlLkRvbSkge1xuICAgICAgICAgICAgY29uc3Qgbm9kZUxpc3QgPSB0aGlzLmdldERvY3VtZW50KCkucXVlcnlTZWxlY3RvckFsbCh0aGlzLnNlbGVjdG9yRXhwcmVzc2lvbik7XG4gICAgICAgICAgICBub2RlTGlzdC5mb3JFYWNoKChlbCkgPT4gZWwuYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsIHRoaXMubG9nV3JhcEhhbmRsZXIoaGFuZGxlciwgbG9nLCBlbCksIHtcbiAgICAgICAgICAgICAgICBwYXNzaXZlOiB0cnVlLFxuICAgICAgICAgICAgICAgIGNhcHR1cmU6IHRydWVcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IHNlbnRpbmVsID0gbmV3IFNlbnRpbmVsKHRoaXMuZ2V0RG9jdW1lbnQoKSk7XG4gICAgICAgICAgICBzZW50aW5lbC5vbih0aGlzLnNlbGVjdG9yRXhwcmVzc2lvbiwgZWwgPT4gZWwuYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsIHRoaXMubG9nV3JhcEhhbmRsZXIoaGFuZGxlciwgbG9nLCBlbCksIHtcbiAgICAgICAgICAgICAgICBwYXNzaXZlOiB0cnVlLFxuICAgICAgICAgICAgICAgIGNhcHR1cmU6IHRydWVcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuICAgIH1cbn1cbiIsImltcG9ydCB7IExpc3RlbmVyVHlwZSB9IGZyb20gXCIuLi91dGlscy9MaXN0ZW5lclR5cGVcIjtcbmltcG9ydCB7IFNlbnRpbmVsIH0gZnJvbSBcIi4uL3V0aWxzL1NlbnRpbmVsXCI7XG5pbXBvcnQgeyBXcml0ZXJSZXNvbHZlckNvbGxlY3RvciB9IGZyb20gXCIuL1dyaXRlclJlc29sdmVyQ29sbGVjdG9yXCI7XG4vKipcbiAqIEV4dGVuZHMgV3JpdGVyUmVzb2x2ZXJDb2xsZWN0b3IgYW5kIGludm9rZXMgdGhlIFdyaXRlclJlc29sdmVyQ29sbGVjdG9yI2F0dGFjaCh3cml0ZXIsIGxvZylcbiAqIHdoZW4gYSBjbGljayBvbiBhbiBlbGVtZW50IGZvciB0aGUgcHJvdmlkZWQgXCJzZWxlY3RvckV4cHJlc3Npb25cIiBvY2N1cnNcbiAqL1xuZXhwb3J0IGNsYXNzIENsaWNrV3JpdGVyUmVzb2x2ZXJDb2xsZWN0b3IgZXh0ZW5kcyBXcml0ZXJSZXNvbHZlckNvbGxlY3RvciB7XG4gICAgLyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gc2VsZWN0b3JFeHByZXNzaW9uIHRoZSBjc3MgZXhwcmVzc2lvbiB0byBxdWVyeSBmb3Igb3RoZXIgZWxlbWVudHNcbiAgICAgKiBAcGFyYW0gdHlwZSB0aGUgdHlwZSBvZiB0aGUgZXZlbnRcbiAgICAgKiBAcGFyYW0gcmVzb2x2ZXIgYSB7V3JpdGVyUmVzb2x2ZXJ9IHdoaWNoIHdpbGwgYmUgZXhlY3V0ZWQgYXMgc29vbiBhcyBhbiBlbGVtZW50IG1hdGNoaW5nIHRoZSBzZWxlY3RvckV4cHJlc3Npb24gaXMgY2xpY2tlZFxuICAgICAqIEBwYXJhbSBsaXN0ZW5lclR5cGUge0xpc3RlbmVyVHlwZX1cbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihzZWxlY3RvckV4cHJlc3Npb24sIHR5cGUsIHJlc29sdmVyLCBsaXN0ZW5lclR5cGUgPSBMaXN0ZW5lclR5cGUuU2VudGluZWwpIHtcbiAgICAgICAgc3VwZXIodHlwZSwgcmVzb2x2ZXIpO1xuICAgICAgICB0aGlzLnNlbGVjdG9yRXhwcmVzc2lvbiA9IHNlbGVjdG9yRXhwcmVzc2lvbjtcbiAgICAgICAgdGhpcy5saXN0ZW5lclR5cGUgPSBsaXN0ZW5lclR5cGU7XG4gICAgfVxuICAgIGF0dGFjaCh3cml0ZXIsIGxvZykge1xuICAgICAgICBjb25zdCBoYW5kbGVyID0gKGVsLCBldmVudCkgPT4ge1xuICAgICAgICAgICAgc3VwZXIuYXR0YWNoKHdyaXRlciwgbG9nKTtcbiAgICAgICAgfTtcbiAgICAgICAgaWYgKHRoaXMubGlzdGVuZXJUeXBlID09PSBMaXN0ZW5lclR5cGUuRG9tKSB7XG4gICAgICAgICAgICBjb25zdCBub2RlTGlzdCA9IHRoaXMuZ2V0RG9jdW1lbnQoKS5xdWVyeVNlbGVjdG9yQWxsKHRoaXMuc2VsZWN0b3JFeHByZXNzaW9uKTtcbiAgICAgICAgICAgIG5vZGVMaXN0LmZvckVhY2goZWwgPT4gZWwuYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsIGV2ID0+IHRoaXMubG9nV3JhcEhhbmRsZXIoaGFuZGxlciwgbG9nLCBlbCwgZXYpKCksIHtcbiAgICAgICAgICAgICAgICBwYXNzaXZlOiB0cnVlLFxuICAgICAgICAgICAgICAgIGNhcHR1cmU6IHRydWVcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IHNlbnRpbmVsID0gbmV3IFNlbnRpbmVsKHRoaXMuZ2V0RG9jdW1lbnQoKSk7XG4gICAgICAgICAgICBzZW50aW5lbC5vbih0aGlzLnNlbGVjdG9yRXhwcmVzc2lvbiwgZWwgPT4gZWwuYWRkRXZlbnRMaXN0ZW5lcihcImNsaWNrXCIsIGV2ID0+IHRoaXMubG9nV3JhcEhhbmRsZXIoaGFuZGxlciwgbG9nLCBlbCwgZXYpKCksIHtcbiAgICAgICAgICAgICAgICBwYXNzaXZlOiB0cnVlLFxuICAgICAgICAgICAgICAgIGNhcHR1cmU6IHRydWVcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuICAgIH1cbn1cbiIsImltcG9ydCB7IENsaWNrQ29sbGVjdG9yIH0gZnJvbSBcIi4vQ2xpY2tDb2xsZWN0b3JcIjtcbi8qKlxuICogQ2xpY2tDb2xsZWN0b3IgZW1pdHRpbmcgXCJmaWx0ZXJcIiBldmVudHMsIGF0dGFjaCB0byBmYWNldCBsaW5rc1xuICovXG5leHBvcnQgY2xhc3MgRmlsdGVyQ2xpY2tDb2xsZWN0b3IgZXh0ZW5kcyBDbGlja0NvbGxlY3RvciB7XG4gICAgY29uc3RydWN0b3Ioc2VsZWN0b3IsIGNvbGxlY3Rvcikge1xuICAgICAgICBzdXBlcihzZWxlY3RvciwgXCJmaWx0ZXJcIik7XG4gICAgICAgIHRoaXMucmVzb2x2ZXIgPSBjb2xsZWN0b3I7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIENvbGxlY3QgdGhlIHByb2R1Y3QgY2xpY2sgaW5mb3JtYXRpb24gZnJvbSB0aGUgZWxlbWVudFxuICAgICAqIEBvdmVycmlkZVxuICAgICAqL1xuICAgIGNvbGxlY3QoZWxlbWVudCwgZXZlbnQsIGxvZykge1xuICAgICAgICByZXR1cm4geyBxdWVyeTogdGhpcy5yZXNvbHZlKHRoaXMucmVzb2x2ZXIsIGxvZywgZWxlbWVudCwgZXZlbnQpIH07XG4gICAgfVxufVxuIiwiaW1wb3J0IHsgV3JpdGVyUmVzb2x2ZXJDb2xsZWN0b3IgfSBmcm9tIFwiLi9Xcml0ZXJSZXNvbHZlckNvbGxlY3RvclwiO1xuLyoqXG4gKiBUcmlnZ2VyZWQgd2hlbiB0aGUgY2xpZW50IGhhcyB0cmlnZ2VyZWQvZmlyZWQgYSBzZWFyY2hcbiAqL1xuZXhwb3J0IGNsYXNzIEZpcmVkU2VhcmNoQ29sbGVjdG9yIGV4dGVuZHMgV3JpdGVyUmVzb2x2ZXJDb2xsZWN0b3Ige1xuICAgIC8qKlxuICAgICAqIENvbnN0cnVjdCBmaXJlZCBzZWFyY2ggY29sbGVjdG9yXG4gICAgICpcbiAgICAgKiBAY29uc3RydWN0b3JcbiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSByZXNvbHZlciAtIEZ1bmN0aW9uIHRoYXQgdHJpZ2dlcnMgdGhlIHdyaXRpbmcuIFdlIGNhbid0IGFsd2F5cyBkZXRlcm1pbmUgd2hlbiBzZWFyY2ggdHJpZ2dlcnMsIGxlYXZlIHRvIHRoZSBpbXBsZW1lbnRhdGlvbiB0byBkZXRlcm1pbmUgd2hlbi9ob3dcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihyZXNvbHZlcikge1xuICAgICAgICBzdXBlcihcImZpcmVkLXNlYXJjaFwiLCByZXNvbHZlcik7XG4gICAgfVxufVxuIiwiaW1wb3J0IHsgQWJzdHJhY3RDb2xsZWN0b3IgfSBmcm9tIFwiLi9BYnN0cmFjdENvbGxlY3RvclwiO1xuLyoqXG4gKiBDb2xsZWN0IGRpZmZlcmVudCB0eXBlIG9mIGV2ZW50cyB2aWEgYSBjdXN0b20gZXZlbnQuIFRoZSBjdXN0b20gZXZlbnQgc2hvdWxkIGhvbGQgdGhlIHByb3BlcnRpZXNcbiAqIFwidHlwZVwiIGFuZCBcImRhdGFcIiBpbiB0aGUgY3VzdG9tIHBheWxvYWQuXG4gKlxuICogU2VlIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0d1aWRlL0V2ZW50cy9DcmVhdGluZ19hbmRfdHJpZ2dlcmluZ19ldmVudHMgZm9yIGd1aWRhbmNlXG4gKi9cbmV4cG9ydCBjbGFzcyBHZW5lcmljRXZlbnRDb2xsZWN0b3IgZXh0ZW5kcyBBYnN0cmFjdENvbGxlY3RvciB7XG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0IGV2ZW50IGJhc2VkIGNvbGxlY3RvclxuICAgICAqXG4gICAgICogQGNvbnN0cnVjdG9yXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZSAtIHRoZSBuYW1lIG9mIHRoZSBldmVudCB0byByZWFjdCBvblxuICAgICAqIEBwYXJhbSB0eXBlXG4gICAgICovXG4gICAgY29uc3RydWN0b3IoZXZlbnROYW1lLCB0eXBlID0gXCJHZW5lcmljRXZlbnRcIikge1xuICAgICAgICBzdXBlcih0eXBlKTtcbiAgICAgICAgdGhpcy5ldmVudE5hbWUgPSBldmVudE5hbWU7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEF0dGFjaCBhIHdyaXRlciwgbm90ZSB0aGF0IHRoaXMgY29sbGVjdG9yIGlzIGFzeW5jaHJvbm91cyBhbmQgd2lsbCB3cml0ZVxuICAgICAqIHRoZSBkYXRhIHdoZW4gdGhlIGV2ZW50IHRyaWdnZXJzXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gd3JpdGVyIC0gVGhlIHdyaXRlciB0byBzZW5kIHRoZSBkYXRhIHRvXG4gICAgICogQHBhcmFtIGxvZ1xuICAgICAqL1xuICAgIGF0dGFjaCh3cml0ZXIsIGxvZykge1xuICAgICAgICB0aGlzLmdldFdpbmRvdygpLmFkZEV2ZW50TGlzdGVuZXIodGhpcy5ldmVudE5hbWUsIHRoaXMubG9nV3JhcEhhbmRsZXIoKGUpID0+IHtcbiAgICAgICAgICAgIHdyaXRlci53cml0ZSh7XG4gICAgICAgICAgICAgICAgXCJ0eXBlXCI6IGUuZGV0YWlsLnR5cGUsXG4gICAgICAgICAgICAgICAgLi4uZS5kZXRhaWwuZGF0YVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sIGxvZykpO1xuICAgIH1cbn1cbiIsImltcG9ydCB7IEFic3RyYWN0Q29sbGVjdG9yIH0gZnJvbSBcIi4vQWJzdHJhY3RDb2xsZWN0b3JcIjtcbmltcG9ydCB7IFNlbnRpbmVsIH0gZnJvbSBcIi4uL3V0aWxzL1NlbnRpbmVsXCI7XG5pbXBvcnQgU2Nyb2xsTW9uaXRvciBmcm9tIFwic2Nyb2xsbW9uaXRvclwiO1xuaW1wb3J0IHsgTG9jYWxTdG9yYWdlUXVldWUgfSBmcm9tIFwiLi4vdXRpbHMvTG9jYWxTdG9yYWdlUXVldWVcIjtcbmltcG9ydCB7IGRlYm91bmNlIH0gZnJvbSBcIi4uL3V0aWxzL1V0aWxcIjtcbi8qKlxuICogQ29sbGVjdCBpbXByZXNzaW9ucyAtIGEgZGlzcGxheSBvZiBhIHByb2R1Y3QgaW4gdGhlIGJyb3dzZXIgdmlld3BvcnQuIElmIHRoZSBwcm9kdWN0IGlzIHNob3duIG11bHRpcGxlXG4gKiB0aW1lcywgdGhlIGNvbGxlY3RvciB3aWxsIHJlY29yZCBtdWx0aXBsZSBldmVudHMgaS5lLiB3ZSBkb24ndCBhcHBseSBmaWx0ZXIgbG9naWMgaGVyZS5cbiAqXG4gKiBIYW5kbGVzIGJvdGggRE9NIGVsZW1lbnRzIHByZXNlbnQgaW4gdGhlIERPTSBhbmQgZWxlbWVudHMgaW5zZXJ0ZWQgYWZ0ZXIgdGhlIHBhZ2UgbG9hZCAvIGNvbGxlY3RvciBjb25zdHJ1Y3Rpb24uXG4gKi9cbmV4cG9ydCBjbGFzcyBJbXByZXNzaW9uQ29sbGVjdG9yIGV4dGVuZHMgQWJzdHJhY3RDb2xsZWN0b3Ige1xuICAgIC8qKlxuICAgICAqIENvbnN0cnVjdCBpbXByZXNzaW9uIGNvbGxlY3RvclxuICAgICAqXG4gICAgICogQGNvbnN0cnVjdG9yXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHNlbGVjdG9yRXhwcmVzc2lvbiAtIERvY3VtZW50IHF1ZXJ5IHNlbGVjdG9yIGlkZW50aWZ5aW5nIHRoZSBlbGVtZW50cyB0byBhdHRhY2ggdG9cbiAgICAgKiBAcGFyYW0gaWRSZXNvbHZlciAtIFJlc29sdmUgdGhlIGlkIG9mIHRoZSBlbGVtZW50XG4gICAgICogQHBhcmFtIHBvc2l0aW9uUmVzb2x2ZXIgLSBSZXNvbHZlIHRoZSBwb3NpdGlvbiBvZiB0aGUgZWxlbWVudCBpbiBkb21cbiAgICAgKiBAcGFyYW0gZXhwZWN0ZWRQYWdlUmVzb2x2ZXIgLSBJZiBzdXBwbGllZCwgaW1wcmVzc2lvbnMgd2lsbCBvbmx5IGJlIHRyYWNrZWQgaWYgdGhpcyByZXNvbHZlciByZXR1cm5zIHRydWUuIENvbWVzIGluIGhhbmR5IGZvciBzaW5nbGUgcGFnZSBhcHBsaWNhdGlvbnNcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihzZWxlY3RvckV4cHJlc3Npb24sIGlkUmVzb2x2ZXIsIHBvc2l0aW9uUmVzb2x2ZXIsIGV4cGVjdGVkUGFnZVJlc29sdmVyKSB7XG4gICAgICAgIHN1cGVyKFwiaW1wcmVzc2lvblwiKTtcbiAgICAgICAgdGhpcy5zZWxlY3RvckV4cHJlc3Npb24gPSBzZWxlY3RvckV4cHJlc3Npb247XG4gICAgICAgIHRoaXMuaWRSZXNvbHZlciA9IGlkUmVzb2x2ZXI7XG4gICAgICAgIHRoaXMucG9zaXRpb25SZXNvbHZlciA9IHBvc2l0aW9uUmVzb2x2ZXI7XG4gICAgICAgIHRoaXMuZXhwZWN0ZWRQYWdlUmVzb2x2ZXIgPSBleHBlY3RlZFBhZ2VSZXNvbHZlcjtcbiAgICAgICAgdGhpcy5xdWV1ZSA9IG5ldyBMb2NhbFN0b3JhZ2VRdWV1ZShcImltcHJlc3Npb25zXCIpO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBBZGQgaW1wcmVzc2lvbiBldmVudCBsaXN0ZW5lcnMgdG8gdGhlIGlkZW50aWZpZWQgZWxlbWVudHMsIHdyaXRlIHRoZSBkYXRhXG4gICAgICogd2hlbiB0aGUgZXZlbnQgb2NjdXJzLCB3aXRoIGEgZGVsYXkgb2YgMXMgLSB3ZSBjb3VsZCBnYXRoZXIgbWFueSBldmVudHMgd2l0aGluIHRoaXMgdGltZWZyYW1lXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gd3JpdGVyIC0gVGhlIHdyaXRlciB0byBzZW5kIHRoZSBkYXRhIHRvXG4gICAgICogQHBhcmFtIHtMb2dnZXJ9IGxvZyAtIFRoZSBsb2dnZXJcbiAgICAgKi9cbiAgICBhdHRhY2god3JpdGVyLCBsb2cpIHtcbiAgICAgICAgY29uc3QgZmx1c2ggPSBkZWJvdW5jZSgoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnF1ZXVlLnRyYW5zYWN0aW9uYWxEcmFpbihxdWV1ZSA9PiBuZXcgUHJvbWlzZShyZXMgPT4ge1xuICAgICAgICAgICAgICAgIHJlcyh3cml0ZXIud3JpdGUoe1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiB0aGlzLnR5cGUsXG4gICAgICAgICAgICAgICAgICAgIGRhdGE6IHF1ZXVlXG4gICAgICAgICAgICAgICAgfSkpO1xuICAgICAgICAgICAgfSkpXG4gICAgICAgICAgICAgICAgLmNhdGNoKGVyciA9PiBsb2cuZXJyb3IoXCJDb3VsZCBub3QgZHJhaW4gcXVldWU6IFwiLCBlcnIpKTtcbiAgICAgICAgfSwgMjUwKTtcbiAgICAgICAgY29uc3QgaGFuZGxlciA9IGVsZW1lbnQgPT4ge1xuICAgICAgICAgICAgU2Nyb2xsTW9uaXRvci5jcmVhdGUoZWxlbWVudCkuZW50ZXJWaWV3cG9ydCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuZXhwZWN0ZWRQYWdlUmVzb2x2ZXIgJiYgIXRoaXMuZXhwZWN0ZWRQYWdlUmVzb2x2ZXIoKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMucXVldWUucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgIGlkOiB0aGlzLnJlc29sdmUodGhpcy5pZFJlc29sdmVyLCBsb2csIGVsZW1lbnQpLFxuICAgICAgICAgICAgICAgICAgICBwb3NpdGlvbjogdGhpcy5yZXNvbHZlKHRoaXMucG9zaXRpb25SZXNvbHZlciwgbG9nLCBlbGVtZW50KVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGZsdXNoKCk7XG4gICAgICAgICAgICB9LCB0cnVlKTtcbiAgICAgICAgfTtcbiAgICAgICAgbmV3IFNlbnRpbmVsKHRoaXMuZ2V0RG9jdW1lbnQoKSkub24odGhpcy5zZWxlY3RvckV4cHJlc3Npb24sIHRoaXMubG9nV3JhcEhhbmRsZXIoaGFuZGxlciwgbG9nKSk7XG4gICAgfVxufVxuIiwiaW1wb3J0IHsgQWJzdHJhY3RDb2xsZWN0b3IgfSBmcm9tIFwiLi9BYnN0cmFjdENvbGxlY3RvclwiO1xuaW1wb3J0IHsgU2VudGluZWwgfSBmcm9tIFwiLi4vdXRpbHMvU2VudGluZWxcIjtcbmltcG9ydCB7IExpc3RlbmVyVHlwZSB9IGZyb20gXCIuLi91dGlscy9MaXN0ZW5lclR5cGVcIjtcbi8qKlxuICogQ29sbGVjdCBzZWFyY2ggaW5mb3JtYXRpb24gZnJvbSBhIGZpZWxkIHRoYXQgaGFzIGEgXCJhcy15b3UtdHlwZVwiIHRyaWdnZXIgYW5kXG4gKiByZW5kZXJzIHNlYXJjaCByZXN1bHRzIGltbWVkaWF0ZWx5LiBNYXkgdHJpZ2dlciBtdWx0aXBsZSB0aW1lcyBkZXBlbmRpbmcgb25cbiAqIHR5cGUgc3BlZWQgcGF0dGVybnMgLSB3ZSBleHBlY3QgdGhhdCB0aGUgaW50ZXJ2YWwgYmV0d2VlbiBrZXkgc3Ryb2tlcyB3b3VsZCBiZVxuICogbGVzcyB0aGFuIDUwMG1zXG4gKi9cbmV4cG9ydCBjbGFzcyBJbnN0YW50U2VhcmNoUXVlcnlDb2xsZWN0b3IgZXh0ZW5kcyBBYnN0cmFjdENvbGxlY3RvciB7XG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0IGluc3RhbnQgc2VhcmNoIGNvbGxlY3RvclxuICAgICAqXG4gICAgICogQGNvbnN0cnVjdG9yXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHNlbGVjdG9yRXhwcmVzc2lvbiAtIERvY3VtZW50IHF1ZXJ5IHNlbGVjdG9yIGlkZW50aWZ5aW5nIHRoZSBlbGVtZW50cyB0byBhdHRhY2ggdG9cbiAgICAgKiBAcGFyYW0gZGVsYXlNc1xuICAgICAqIEBwYXJhbSBtaW5MZW5ndGhcbiAgICAgKiBAcGFyYW0gbGlzdGVuZXJUeXBlXG4gICAgICovXG4gICAgY29uc3RydWN0b3Ioc2VsZWN0b3JFeHByZXNzaW9uLCBkZWxheU1zID0gNTAwLCBtaW5MZW5ndGggPSAyLCBsaXN0ZW5lclR5cGUgPSBMaXN0ZW5lclR5cGUuU2VudGluZWwpIHtcbiAgICAgICAgc3VwZXIoXCJpbnN0YW50LXNlYXJjaFwiKTtcbiAgICAgICAgdGhpcy5zZWxlY3RvckV4cHJlc3Npb24gPSBzZWxlY3RvckV4cHJlc3Npb247XG4gICAgICAgIHRoaXMuZGVsYXlNcyA9IGRlbGF5TXM7XG4gICAgICAgIHRoaXMubWluTGVuZ3RoID0gbWluTGVuZ3RoO1xuICAgICAgICB0aGlzLmxpc3RlbmVyVHlwZSA9IGxpc3RlbmVyVHlwZTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogQWRkIGltcHJlc3Npb24gZXZlbnQgbGlzdGVuZXJzIHRvIHRoZSBpZGVudGlmaWVkIGVsZW1lbnRzLCB3cml0ZSB0aGUgZGF0YVxuICAgICAqIHdoZW4gdGhlIGV2ZW50IG9jY3Vyc1xuICAgICAqXG4gICAgICogQHBhcmFtIHtvYmplY3R9IHdyaXRlciAtIFRoZSB3cml0ZXIgdG8gc2VuZCB0aGUgZGF0YSB0b1xuICAgICAqIEBwYXJhbSBsb2dcbiAgICAgKi9cbiAgICBhdHRhY2god3JpdGVyLCBsb2cpIHtcbiAgICAgICAgY29uc3QgdHlwZSA9IHRoaXMuZ2V0VHlwZSgpO1xuICAgICAgICBjb25zdCBoYW5kbGVyID0gKGUsIHNlYXJjaEJveCkgPT4ge1xuICAgICAgICAgICAgLy8gSWdub3JlIHNoaWZ0LCBjdHJsLCBldGMuIHByZXNzZXMsIHJlYWN0IG9ubHkgb24gY2hhcmFjdGVyc1xuICAgICAgICAgICAgaWYgKGUud2hpY2ggPT09IDApIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBEZWxheSB0aGUgcmVhY3Rpb24gb2YgdGhlIGV2ZW50LCBjbGVhbiB0aGUgdGltZW91dCBpZiB0aGUgZXZlbnQgZmlyZXNcbiAgICAgICAgICAgIC8vIGFnYWluIGFuZCBzdGFydCBjb3VudGluZyBmcm9tIDBcbiAgICAgICAgICAgIGRlbGF5KCh0aW1lc3RhbXApID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBrZXl3b3JkcyA9IHNlYXJjaEJveC52YWx1ZTtcbiAgICAgICAgICAgICAgICBpZiAoa2V5d29yZHMgJiYga2V5d29yZHMubGVuZ3RoID49IHRoaXMubWluTGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgIHdyaXRlci53cml0ZSh7XG4gICAgICAgICAgICAgICAgICAgICAgICBcInR5cGVcIjogdHlwZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIFwia2V5d29yZHNcIjoga2V5d29yZHMsXG4gICAgICAgICAgICAgICAgICAgICAgICB0aW1lc3RhbXBcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSwgdGhpcy5kZWxheU1zKTtcbiAgICAgICAgfTtcbiAgICAgICAgLy8gVGhlIFNlbnRpZWwgbGlicmFyeSB1c2VzIGFuaW1hdGlvbnN0YXJ0IGV2ZW50IGxpc3RlbmVycyB3aGljaCBtYXkgaW50ZXJmZXJlIHdpdGhcbiAgICAgICAgLy8gYW5pbWF0aW9ucyBhdHRhY2hlZCBvbiBlbGVtZW5ldHMuIFRoZSBpbi1saWJyYXJ5IHByb3ZpZGVkIHdvcmthcm91bmQgbWVjaGFuaXNtIGRvZXMgbm90IHdvcmtcbiAgICAgICAgLy8gMTAwJSwgdGh1cyB3ZSBwcm92aWRlIHRoZSBsaXN0ZW5lclR5cGUgY2hvaWNlIGJlbG93LiBUaGUgdHJhZGVvZmZzXG4gICAgICAgIC8vIFwiZG9tXCIgLSBubyBhbmltYXRpb24gaW50ZXJmZXJlbmNlLCBvbmx5IG9uY2xpY2sgYXR0YWNoZWQsIGJ1dCBkb2VzIG5vdCBoYW5kbGUgZWxlbWVudHMgaW5zZXJ0ZWQgaW4gdGhlIERPTSBsYXRlclxuICAgICAgICAvLyBcInNlbnRpbmVsIChkZWZhdWx0KVwiIC0gd29ya3Mgb24gZWxlbWVudHMgaW5zZXJ0ZWQgaW4gdGhlIERPTSBhbnl0aW1lLCBidXQgaW50ZXJmZXJlcyB3aXRoIENTUyBhbmltYXRpb25zIG9uIHRoZXNlIGVsZW1lbnRzXG4gICAgICAgIGlmICh0aGlzLmxpc3RlbmVyVHlwZSA9PT0gTGlzdGVuZXJUeXBlLkRvbSkge1xuICAgICAgICAgICAgY29uc3Qgbm9kZUxpc3QgPSB0aGlzLmdldERvY3VtZW50KCkucXVlcnlTZWxlY3RvckFsbCh0aGlzLnNlbGVjdG9yRXhwcmVzc2lvbik7XG4gICAgICAgICAgICBub2RlTGlzdC5mb3JFYWNoKGVsID0+IGVsLmFkZEV2ZW50TGlzdGVuZXIoXCJrZXl1cFwiLCB0aGlzLmxvZ1dyYXBIYW5kbGVyKGhhbmRsZXIsIGxvZywgZWwpKSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBuZXcgU2VudGluZWwodGhpcy5nZXREb2N1bWVudCgpKS5vbih0aGlzLnNlbGVjdG9yRXhwcmVzc2lvbiwgKGVsKSA9PiB7XG4gICAgICAgICAgICAgICAgZWwuYWRkRXZlbnRMaXN0ZW5lcihcImtleXVwXCIsIHRoaXMubG9nV3JhcEhhbmRsZXIoaGFuZGxlciwgbG9nLCBlbCkpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG59XG5jb25zdCBkZWxheSA9IChmdW5jdGlvbiAoKSB7XG4gICAgbGV0IHRpbWVyO1xuICAgIGxldCB0aW1lO1xuICAgIHJldHVybiBmdW5jdGlvbiAoY2FsbGJhY2ssIG1zKSB7XG4gICAgICAgIGNsZWFyVGltZW91dCh0aW1lcik7XG4gICAgICAgIGlmICghdGltZSlcbiAgICAgICAgICAgIHRpbWUgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcbiAgICAgICAgdGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIGNhbGxiYWNrKHRpbWUpO1xuICAgICAgICAgICAgdGltZSA9IG51bGw7XG4gICAgICAgIH0sIG1zKTtcbiAgICB9O1xufSkoKTtcbiIsImltcG9ydCB7IENsaWNrQ29sbGVjdG9yIH0gZnJvbSBcIi4vQ2xpY2tDb2xsZWN0b3JcIjtcbmltcG9ydCB7IExpc3RlbmVyVHlwZSB9IGZyb20gXCIuLi91dGlscy9MaXN0ZW5lclR5cGVcIjtcbmltcG9ydCB7IFRyYWlsVHlwZSB9IGZyb20gXCIuLi9xdWVyeVwiO1xuaW1wb3J0IHsgbm9ybWFsaXplUGF0aG5hbWUgfSBmcm9tIFwiLi4vdXRpbHNcIjtcbi8qKlxuICogQ2xpY2tDb2xsZWN0b3IgZW1pdHRpbmcgXCJwcm9kdWN0XCIgZXZlbnRzLCBhdHRhY2ggdG8gcHJvZHVjdCBsaW5rc1xuICovXG5leHBvcnQgY2xhc3MgUHJvZHVjdENsaWNrQ29sbGVjdG9yIGV4dGVuZHMgQ2xpY2tDb2xsZWN0b3Ige1xuICAgIGNvbnN0cnVjdG9yKHNlbGVjdG9yLCByZXNvbHZlcnMsIGxpc3RlbmVyVHlwZSA9IExpc3RlbmVyVHlwZS5TZW50aW5lbCkge1xuICAgICAgICBzdXBlcihzZWxlY3RvciwgXCJwcm9kdWN0XCIsIGxpc3RlbmVyVHlwZSk7XG4gICAgICAgIHRoaXMuaWRSZXNvbHZlciA9IHJlc29sdmVycy5pZFJlc29sdmVyO1xuICAgICAgICB0aGlzLnBvc2l0aW9uUmVzb2x2ZXIgPSByZXNvbHZlcnMucG9zaXRpb25SZXNvbHZlcjtcbiAgICAgICAgdGhpcy5wcmljZVJlc29sdmVyID0gcmVzb2x2ZXJzLnByaWNlUmVzb2x2ZXI7XG4gICAgICAgIHRoaXMuaW1hZ2VSZXNvbHZlciA9IHJlc29sdmVycy5pbWFnZVJlc29sdmVyO1xuICAgICAgICB0aGlzLm1ldGFkYXRhUmVzb2x2ZXIgPSByZXNvbHZlcnMubWV0YWRhdGFSZXNvbHZlcjtcbiAgICAgICAgdGhpcy50cmFpbCA9IHJlc29sdmVycy50cmFpbDtcbiAgICB9XG4gICAgLyoqXG4gICAgICogQ29sbGVjdCB0aGUgcHJvZHVjdCBjbGljayBpbmZvcm1hdGlvbiBmcm9tIHRoZSBlbGVtZW50XG4gICAgICogQG92ZXJyaWRlXG4gICAgICovXG4gICAgY29sbGVjdChlbGVtZW50LCBldmVudCwgbG9nKSB7XG4gICAgICAgIGNvbnN0IGlkID0gdGhpcy5yZXNvbHZlKHRoaXMuaWRSZXNvbHZlciwgbG9nLCBlbGVtZW50LCBldmVudCk7XG4gICAgICAgIGlmIChpZCkge1xuICAgICAgICAgICAgY29uc3QgY2xpY2tEYXRhID0ge1xuICAgICAgICAgICAgICAgIGlkLFxuICAgICAgICAgICAgICAgIHBvc2l0aW9uOiB0aGlzLnJlc29sdmUodGhpcy5wb3NpdGlvblJlc29sdmVyLCBsb2csIGVsZW1lbnQsIGV2ZW50KSxcbiAgICAgICAgICAgICAgICBwcmljZTogdGhpcy5yZXNvbHZlKHRoaXMucHJpY2VSZXNvbHZlciwgbG9nLCBlbGVtZW50LCBldmVudCksXG4gICAgICAgICAgICAgICAgaW1hZ2U6IHRoaXMucmVzb2x2ZSh0aGlzLmltYWdlUmVzb2x2ZXIsIGxvZywgZWxlbWVudCwgZXZlbnQpLFxuICAgICAgICAgICAgICAgIG1ldGFkYXRhOiB0aGlzLnJlc29sdmUodGhpcy5tZXRhZGF0YVJlc29sdmVyLCBsb2csIGVsZW1lbnQsIGV2ZW50KVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGlmICh0aGlzLnRyYWlsKSB7XG4gICAgICAgICAgICAgICAgLy8gQWZ0ZXIgYSByZWRpcmVjdCBhIHRyYWlsIHdpdGggdGhlIHBhdGhuYW1lIGlzIHJlZ2lzdGVyZWQgY29udGFpbmluZyB0aGUgcXVlcnkgd2hpY2ggdHJpZ2dlcmVkIHRoZSByZWRpcmVjdC5cbiAgICAgICAgICAgICAgICAvLyBJZiB3ZSBoYXZlIHN1Y2ggYSBxdWVyeSB3ZSB1c2UgaXQgdG8gYnVpbGQgdGhlIHRyYWlsLlxuICAgICAgICAgICAgICAgIGNvbnN0IHRyYWlsRGF0YSA9IHRoaXMudHJhaWwuZmV0Y2gobm9ybWFsaXplUGF0aG5hbWUobG9jYXRpb24ucGF0aG5hbWUpKTtcbiAgICAgICAgICAgICAgICBpZiAodHJhaWxEYXRhKSB7XG4gICAgICAgICAgICAgICAgICAgIGNsaWNrRGF0YS5xdWVyeSA9IHRyYWlsRGF0YS5xdWVyeTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gUmVnaXN0ZXIgdGhhdCB0aGlzIHByb2R1Y3Qgam91cm5leSBpbnRvIHBvdGVudGlhbCBwdXJjaGFzZSBzdGFydGVkXG4gICAgICAgICAgICAgICAgLy8gd2l0aCB0aGlzIHF1ZXJ5XG4gICAgICAgICAgICAgICAgdGhpcy50cmFpbC5yZWdpc3RlcihpZCwgVHJhaWxUeXBlLk1haW4sIHRyYWlsRGF0YSA9PT0gbnVsbCB8fCB0cmFpbERhdGEgPT09IHZvaWQgMCA/IHZvaWQgMCA6IHRyYWlsRGF0YS5xdWVyeSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gY2xpY2tEYXRhO1xuICAgICAgICB9XG4gICAgfVxufVxuIiwiaW1wb3J0IHsgQWJzdHJhY3RDb2xsZWN0b3IgfSBmcm9tIFwiLi9BYnN0cmFjdENvbGxlY3RvclwiO1xuaW1wb3J0IHsgY29va2llU2Vzc2lvblJlc29sdmVyIH0gZnJvbSBcIi4uL3Jlc29sdmVycy9SZXNvbHZlclwiO1xuaW1wb3J0IHsgZ2V0U2Vzc2lvblN0b3JhZ2UsIExpc3RlbmVyVHlwZSwgbm9ybWFsaXplUGF0aG5hbWUsIFNlbnRpbmVsIH0gZnJvbSBcIi4uL3V0aWxzXCI7XG5pbXBvcnQgeyBRdWVyeSwgVHJhaWwsIFRyYWlsVHlwZSB9IGZyb20gXCIuLi9xdWVyeVwiO1xuLyoqXG4gKiBLZWVwIHRyYWNrIG9mIGh1bWFuIHRyaWdnZXJlZCBzZWFyY2hlcyBmb2xsb3dlZCBieSBhIHJlZGlyZWN0IHRvIGEgcGFnZSBkaWZmZXJlbnQgdGhhbiB0aGUgc2VhcmNoIHJlc3VsdCBwYWdlXG4gKi9cbmV4cG9ydCBjbGFzcyBSZWRpcmVjdENvbGxlY3RvciBleHRlbmRzIEFic3RyYWN0Q29sbGVjdG9yIHtcbiAgICAvKipcbiAgICAgKiBDb25zdHJ1Y3QgcmVkaXJlY3QgY29sbGVjdG9yXG4gICAgICpcbiAgICAgKiBAY29uc3RydWN0b3JcbiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSB0cmlnZ2VyUmVzb2x2ZXIgLSBGdW5jdGlvbiB0aGF0IGZpcmVzIHdoZW4gYSBzZWFyY2ggaGFwcGVucywgc2hvdWxkIHJldHVybiB0aGUga2V5d29yZFxuICAgICAqIEBwYXJhbSB7ZnVuY3Rpb259IGV4cGVjdGVkUGFnZVJlc29sdmVyIC0gRnVuY3Rpb24gdGhhdCBzaG91bGQgcmV0dXJuIHdoZXRoZXIgdGhlIHBhZ2Ugd2UgbG9hZCBpcyB0aGUgZXhwZWN0ZWQgb25lXG4gICAgICogQHBhcmFtIHJlZGlyZWN0S3BpUGFyYW1zIC0gUGFyYW1ldGVycyBmb3IgY29sbGVjdGluZyBLUEkncyBhZnRlciBhIHJlZGlyZWN0XG4gICAgICogQHBhcmFtIGxpc3RlbmVyVHlwZVxuICAgICAqIEBwYXJhbSBjb250ZXh0XG4gICAgICovXG4gICAgY29uc3RydWN0b3IodHJpZ2dlclJlc29sdmVyLCBleHBlY3RlZFBhZ2VSZXNvbHZlciwgcmVkaXJlY3RLcGlQYXJhbXMgPSB7fSwgbGlzdGVuZXJUeXBlID0gTGlzdGVuZXJUeXBlLlNlbnRpbmVsLCBjb250ZXh0KSB7XG4gICAgICAgIHZhciBfYSwgX2I7XG4gICAgICAgIHN1cGVyKFwicmVkaXJlY3RcIiwgY29udGV4dCk7XG4gICAgICAgIHRoaXMudHJpZ2dlclJlc29sdmVyID0gdHJpZ2dlclJlc29sdmVyO1xuICAgICAgICB0aGlzLmV4cGVjdGVkUGFnZVJlc29sdmVyID0gZXhwZWN0ZWRQYWdlUmVzb2x2ZXI7XG4gICAgICAgIHRoaXMucmVkaXJlY3RLcGlQYXJhbXMgPSByZWRpcmVjdEtwaVBhcmFtcztcbiAgICAgICAgdGhpcy5saXN0ZW5lclR5cGUgPSBsaXN0ZW5lclR5cGU7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBVc2VkIHRvIHRyYWNrIGlmIHRoZSBjb2xsZWN0b3JzIGhhdmUgYmVlbiBhdHRhY2hlZCBhbHJlYWR5IGluIGNhc2UgYXR0YWNoZWQgaXMgY2FsbGVkIG11bHRpcGxlIHRpbWVzXG4gICAgICAgICAqIEBwcml2YXRlXG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLmlzQ29sbGVjdG9yc0F0dGFjaGVkID0gZmFsc2U7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBVc2VkIHRvIHRyYWNrIGlmIHRoZSB0cmlnZ2VyIGhhcyBiZWVuIGluc3RhbGxlZCBhbHJlYWR5IGluIGNhc2UgYXR0YWNoZWQgaXMgY2FsbGVkIG11bHRpcGxlIHRpbWVzXG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLmlzVHJpZ2dlckluc3RhbGxlZCA9IGZhbHNlO1xuICAgICAgICB0aGlzLnRyaWdnZXJSZXNvbHZlciA9IHRyaWdnZXJSZXNvbHZlcjtcbiAgICAgICAgdGhpcy5leHBlY3RlZFBhZ2VSZXNvbHZlciA9IGV4cGVjdGVkUGFnZVJlc29sdmVyO1xuICAgICAgICB0aGlzLmxpc3RlbmVyVHlwZSA9IGxpc3RlbmVyVHlwZTtcbiAgICAgICAgdGhpcy5jb2xsZWN0b3JzID0gcmVkaXJlY3RLcGlQYXJhbXMuY29sbGVjdG9ycyB8fCBbXTtcbiAgICAgICAgdGhpcy5yZXN1bHRDb3VudFJlc29sdmVyID0gcmVkaXJlY3RLcGlQYXJhbXMucmVzdWx0Q291bnRSZXNvbHZlciB8fCAoXyA9PiB2b2lkIDApO1xuICAgICAgICB0aGlzLnJlZGlyZWN0VFRMID0gdGhpcy5yZWRpcmVjdEtwaVBhcmFtcy5yZWRpcmVjdFRUTE1pbGxpcyB8fCA4NjQwMDAwMDtcbiAgICAgICAgdGhpcy5tYXhQYXRoU2VnbWVudHMgPSB0aGlzLnJlZGlyZWN0S3BpUGFyYW1zLm1heFBhdGhTZWdtZW50cyB8fCAtMTtcbiAgICAgICAgdGhpcy5zdWJTZWxlY3RvcnMgPSAoKF9hID0gdGhpcy5yZWRpcmVjdEtwaVBhcmFtcy5uZXN0ZWRSZWRpcmVjdHMpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5zdWJTZWxlY3RvcnMpIHx8IFtdO1xuICAgICAgICB0aGlzLmRlcHRoID0gKChfYiA9IHRoaXMucmVkaXJlY3RLcGlQYXJhbXMubmVzdGVkUmVkaXJlY3RzKSA9PT0gbnVsbCB8fCBfYiA9PT0gdm9pZCAwID8gdm9pZCAwIDogX2IuZGVwdGgpIHx8IDE7XG4gICAgICAgIHRoaXMucXVlcnlSZXNvbHZlciA9IChwaHJhc2UpID0+IHtcbiAgICAgICAgICAgIGlmIChwaHJhc2UuaW5kZXhPZihcIiRzPVwiKSA+IC0xKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBRdWVyeShwaHJhc2UpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgcXVlcnkgPSBuZXcgUXVlcnkoKTtcbiAgICAgICAgICAgIHF1ZXJ5LnNldFNlYXJjaChwaHJhc2UpO1xuICAgICAgICAgICAgcmV0dXJuIHF1ZXJ5O1xuICAgICAgICB9O1xuICAgICAgICB0aGlzLnNlc3Npb25SZXNvbHZlciA9ICgpID0+IGNvb2tpZVNlc3Npb25SZXNvbHZlcigpO1xuICAgICAgICB0aGlzLnJlZGlyZWN0VHJhaWwgPSBuZXcgVHJhaWwoKCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgcGF0aEluZm8gPSBSZWRpcmVjdENvbGxlY3Rvci5nZXRSZWRpcmVjdFBhdGhJbmZvKHRoaXMuZ2V0UGF0aG5hbWUoKSk7XG4gICAgICAgICAgICByZXR1cm4gbmV3IFF1ZXJ5KHBhdGhJbmZvID09PSBudWxsIHx8IHBhdGhJbmZvID09PSB2b2lkIDAgPyB2b2lkIDAgOiBwYXRoSW5mby5xdWVyeSk7XG4gICAgICAgIH0sIHRoaXMuc2Vzc2lvblJlc29sdmVyKTtcbiAgICB9XG4gICAgc2V0Q29udGV4dChjb250ZXh0KSB7XG4gICAgICAgIHN1cGVyLnNldENvbnRleHQoY29udGV4dCk7XG4gICAgICAgIHRoaXMuY29sbGVjdG9ycy5mb3JFYWNoKGNvbGxlY3RvciA9PiBjb2xsZWN0b3Iuc2V0Q29udGV4dChjb250ZXh0KSk7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIE1hcmtzIHRoaXMgcGF0aCBhcyBhIHJlZGlyZWN0IGxhbmRpbmcgcGFnZS5cbiAgICAgKiBAcGFyYW0gcGF0aCB0aGUgcGF0aG5hbWUgZS5nLiAvc29tZS1wYXRoXG4gICAgICogQHBhcmFtIHF1ZXJ5IHRoZSBxdWVyeSB3aGljaCBsZWFkIHRvIHRoaXMgcGF0aFxuICAgICAqIEBwYXJhbSBrZXkgdGhlIGtleSB0byBzdG9yZSB0aGUgcmVkaXJlY3QgcGF0aCBpblxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgc3RhdGljIHNldFJlZGlyZWN0UGF0aChwYXRoLCBxdWVyeSwga2V5ID0gUmVkaXJlY3RDb2xsZWN0b3IuUEFUSF9TVE9SQUdFX0tFWSkge1xuICAgICAgICBjb25zdCByZWRpcmVjdFBhdGhzID0gdGhpcy5nZXRSZWRpcmVjdFBhdGhzKCk7XG4gICAgICAgIHJlZGlyZWN0UGF0aHNbcGF0aF0gPSB7XG4gICAgICAgICAgICBxdWVyeSxcbiAgICAgICAgICAgIHRpbWVzdGFtcDogbmV3IERhdGUoKS5nZXRUaW1lKClcbiAgICAgICAgfTtcbiAgICAgICAgZ2V0U2Vzc2lvblN0b3JhZ2UoKS5zZXRJdGVtKGtleSwgSlNPTi5zdHJpbmdpZnkocmVkaXJlY3RQYXRocykpO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBHZXQgYWxsIG1hcmtlZCBwYXRoc1xuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgc3RhdGljIGdldFJlZGlyZWN0UGF0aHMoa2V5ID0gUmVkaXJlY3RDb2xsZWN0b3IuUEFUSF9TVE9SQUdFX0tFWSkge1xuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShnZXRTZXNzaW9uU3RvcmFnZSgpLmdldEl0ZW0oa2V5KSB8fCBcInt9XCIpO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBSZXRyaWV2ZSBkYXRhIGZvciB0aGUgZ2l2ZW4gcGF0aFxuICAgICAqIEBwYXJhbSBwYXRoXG4gICAgICogQHBhcmFtIGtleVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgc3RhdGljIGdldFJlZGlyZWN0UGF0aEluZm8ocGF0aCwga2V5ID0gUmVkaXJlY3RDb2xsZWN0b3IuUEFUSF9TVE9SQUdFX0tFWSkge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRSZWRpcmVjdFBhdGhzKGtleSlbcGF0aF07XG4gICAgfVxuICAgIC8qKlxuICAgICAqIERlbGV0ZSBhbGwgZXhwaXJlZCByZWRpcmVjdCBwYXRoc1xuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgZXhwaXJlUmVkaXJlY3RQYXRocyhrZXkgPSBSZWRpcmVjdENvbGxlY3Rvci5QQVRIX1NUT1JBR0VfS0VZKSB7XG4gICAgICAgIGNvbnN0IHJlZGlyZWN0UGF0aHMgPSBSZWRpcmVjdENvbGxlY3Rvci5nZXRSZWRpcmVjdFBhdGhzKGtleSk7XG4gICAgICAgIGNvbnN0IG5vdyA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuICAgICAgICBPYmplY3Qua2V5cyhyZWRpcmVjdFBhdGhzKS5mb3JFYWNoKHBhdGggPT4ge1xuICAgICAgICAgICAgY29uc3QgcGF0aEluZm8gPSByZWRpcmVjdFBhdGhzW3BhdGhdO1xuICAgICAgICAgICAgaWYgKG5vdyAtIE51bWJlcihwYXRoSW5mby50aW1lc3RhbXApID4gdGhpcy5yZWRpcmVjdFRUTCkge1xuICAgICAgICAgICAgICAgIGRlbGV0ZSByZWRpcmVjdFBhdGhzW3BhdGhdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgZ2V0U2Vzc2lvblN0b3JhZ2UoKS5zZXRJdGVtKGtleSwgSlNPTi5zdHJpbmdpZnkocmVkaXJlY3RQYXRocykpO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBDaGVjayB3aGV0aGVyIHdlIHNob3VsZCBiZSByZWNvcmRpbmcgYSByZWRpcmVjdCBldmVudFxuICAgICAqXG4gICAgICogQHBhcmFtIHtvYmplY3R9IHdyaXRlciAtIFRoZSB3cml0ZXIgdG8gc2VuZCB0aGUgZGF0YSB0b1xuICAgICAqIEBwYXJhbSBsb2dcbiAgICAgKi9cbiAgICBhdHRhY2god3JpdGVyLCBsb2cpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNUcmlnZ2VySW5zdGFsbGVkID09PSBmYWxzZSkge1xuICAgICAgICAgICAgdGhpcy5yZXNvbHZlKHRoaXMudHJpZ2dlclJlc29sdmVyLCBsb2csIGtleXdvcmQgPT4gZ2V0U2Vzc2lvblN0b3JhZ2UoKS5zZXRJdGVtKFJlZGlyZWN0Q29sbGVjdG9yLkxBU1RfU0VBUkNIX1NUT1JBR0VfS0VZLCBrZXl3b3JkKSk7XG4gICAgICAgICAgICB0aGlzLmlzVHJpZ2dlckluc3RhbGxlZCA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5leHBpcmVSZWRpcmVjdFBhdGhzKCk7XG4gICAgICAgIC8vIEZldGNoIHRoZSBsYXRlc3Qgc2VhcmNoIGlmIGFueVxuICAgICAgICBjb25zdCBsYXN0U2VhcmNoID0gZ2V0U2Vzc2lvblN0b3JhZ2UoKS5nZXRJdGVtKFJlZGlyZWN0Q29sbGVjdG9yLkxBU1RfU0VBUkNIX1NUT1JBR0VfS0VZKTtcbiAgICAgICAgY29uc3QgcGF0aG5hbWUgPSBub3JtYWxpemVQYXRobmFtZSh0aGlzLmdldFdpbmRvdygpLmxvY2F0aW9uLnBhdGhuYW1lKTtcbiAgICAgICAgaWYgKGxhc3RTZWFyY2gpIHtcbiAgICAgICAgICAgIGdldFNlc3Npb25TdG9yYWdlKCkucmVtb3ZlSXRlbShSZWRpcmVjdENvbGxlY3Rvci5MQVNUX1NFQVJDSF9TVE9SQUdFX0tFWSk7XG4gICAgICAgICAgICAvLyBJZiB3ZSBoYXZlIG5vdCBsYW5kZWQgb24gdGhlIGV4cGVjdGVkIHNlYXJjaCBwYWdlLCBpdCBtdXN0IGhhdmUgYmVlbiBhIHJlZGlyZWN0XG4gICAgICAgICAgICBpZiAoc2hvdWxkVHJhY2tSZWRpcmVjdChkb2N1bWVudC5yZWZlcnJlcikgJiYgIXRoaXMucmVzb2x2ZSh0aGlzLmV4cGVjdGVkUGFnZVJlc29sdmVyLCBsb2cpKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgcXVlcnkgPSB0aGlzLnF1ZXJ5UmVzb2x2ZXIobGFzdFNlYXJjaCkudG9TdHJpbmcoKTtcbiAgICAgICAgICAgICAgICB3cml0ZXIud3JpdGUoe1xuICAgICAgICAgICAgICAgICAgICB0eXBlOiBcInJlZGlyZWN0XCIsXG4gICAgICAgICAgICAgICAgICAgIGtleXdvcmRzOiBsYXN0U2VhcmNoLFxuICAgICAgICAgICAgICAgICAgICBxdWVyeSxcbiAgICAgICAgICAgICAgICAgICAgdXJsOiB3aW5kb3cubG9jYXRpb24uaHJlZixcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0Q291bnQ6IHRoaXMucmVzb2x2ZSh0aGlzLnJlc3VsdENvdW50UmVzb2x2ZXIsIGxvZylcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAvLyBtYXJrIGFzIHJlZGlyZWN0IGxhbmRpbmcgcGFnZVxuICAgICAgICAgICAgICAgIFJlZGlyZWN0Q29sbGVjdG9yLnNldFJlZGlyZWN0UGF0aCh0aGlzLmdldFBhdGhuYW1lKCksIHF1ZXJ5KTtcbiAgICAgICAgICAgICAgICAvLyByZWdpc3RlciB0cmFpbCBvbiB0aGUgY3VycmVudCBwYXRobmFtZSBiZWNhdXNlIHRoZSBQcm9kdWN0Q2xpY2sgY29sbGVjdG9yIGRvZXNuJ3Qga25vdyBhYm91dCB0aGUgbWF4UGF0aFNlZ21lbnRzIHByb3BlcnR5XG4gICAgICAgICAgICAgICAgdGhpcy5yZWRpcmVjdFRyYWlsLnJlZ2lzdGVyKHBhdGhuYW1lLCBUcmFpbFR5cGUuTWFpbik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy8gdGhpcyBpcyBvbmx5ICB0cmlnZ2VyZWQgd2hlbiBhIHN1YlNlbGVjdG9yIGl0ZW0gd2FzIGNsaWNrZWQgaS5lLiBhIG5lc3RlZCByZWRpcmVjdFxuICAgICAgICBjb25zdCBsYXN0U2VhcmNoTmVzdGVkUmVkaXJlY3QgPSB0aGlzLmdldE5lc3RlZFJlZGlyZWN0KCk7XG4gICAgICAgIGlmIChsYXN0U2VhcmNoTmVzdGVkUmVkaXJlY3QpIHtcbiAgICAgICAgICAgIGNvbnN0IHF1ZXJ5ID0gdGhpcy5xdWVyeVJlc29sdmVyKGxhc3RTZWFyY2hOZXN0ZWRSZWRpcmVjdC5xdWVyeSkudG9TdHJpbmcoKTtcbiAgICAgICAgICAgIFJlZGlyZWN0Q29sbGVjdG9yLnNldFJlZGlyZWN0UGF0aCh0aGlzLmdldFBhdGhuYW1lKCksIHF1ZXJ5KTtcbiAgICAgICAgICAgIC8vIHJlZ2lzdGVyIHRyYWlsIG9uIHRoZSBjdXJyZW50IHBhdGhuYW1lIGJlY2F1c2UgdGhlIFByb2R1Y3RDbGljayBjb2xsZWN0b3IgZG9lc24ndCBrbm93IGFib3V0IHRoZSBtYXhQYXRoU2VnbWVudHMgcHJvcGVydHlcbiAgICAgICAgICAgIHRoaXMucmVkaXJlY3RUcmFpbC5yZWdpc3RlcihwYXRobmFtZSwgVHJhaWxUeXBlLk1haW4pO1xuICAgICAgICAgICAgZ2V0U2Vzc2lvblN0b3JhZ2UoKS5yZW1vdmVJdGVtKFJlZGlyZWN0Q29sbGVjdG9yLk5FU1RFRF9SRURJUkVDVF9LRVlXT1JEU19TVE9SQUdFX0tFWSk7XG4gICAgICAgIH1cbiAgICAgICAgLyoqXG4gICAgICAgICAqIENoZWNrIGlmIHdlIGhhdmUgdHJhY2tlZCB0aGlzIHBhdGggYmVmb3JlIGFuZCBpZiBpdCBpcyBzdGlsbCB2YWxpZC5cbiAgICAgICAgICogSWYgdmFsaWQsIHdlIGhhdmUgdG8gYXR0YWNoIHRoZSBLUEkgY29sbGVjdG9ycyB0byBnYXRoZXIgS1BJcyBmb3IgdGhpcyBsYW5kaW5nIHBhZ2UuXG4gICAgICAgICAqIFdlIGhhdmUgdG8gZG8gdGhpcyBiZWNhdXNlIHBlb3BsZSBjYW4gbmF2aWdhdGUgYXdheSBmcm9tIHRoZSBsYW5kaW5nIHBhZ2UgYW5kIGJhY2sgYWdhaW4gYW5kIHdlIGRvbid0IHdhbnQgdG8gbG9zZSBhbGwgc3Vic2VxdWVudCBjbGlja3MgZXRjLlxuICAgICAgICAgKi9cbiAgICAgICAgY29uc3QgcGF0aEluZm8gPSB0aGlzLnJlZGlyZWN0VHJhaWwuZmV0Y2godGhpcy5nZXRQYXRobmFtZSgpKTtcbiAgICAgICAgaWYgKHBhdGhJbmZvICYmIHRoaXMuaXNDb2xsZWN0b3JzQXR0YWNoZWQgIT09IHRydWUpIHtcbiAgICAgICAgICAgIHRoaXMuYXR0YWNoQ29sbGVjdG9ycyh3cml0ZXIsIGxvZywgcGF0aEluZm8ucXVlcnkpO1xuICAgICAgICAgICAgdGhpcy5pc0NvbGxlY3RvcnNBdHRhY2hlZCA9IHRydWU7XG4gICAgICAgICAgICAvLyByZWdpc3RlciB0cmFpbCBvbiB0aGUgY3VycmVudCBwYXRobmFtZSBiZWNhdXNlIHRoZSBQcm9kdWN0Q2xpY2sgY29sbGVjdG9yIGRvZXNuJ3Qga25vdyBhYm91dCB0aGUgbWF4UGF0aFNlZ21lbnRzIHByb3BlcnR5XG4gICAgICAgICAgICB0aGlzLnJlZGlyZWN0VHJhaWwucmVnaXN0ZXIocGF0aG5hbWUsIFRyYWlsVHlwZS5NYWluKTtcbiAgICAgICAgICAgIC8vIGlmIHdlIGhhdmUgbmVzdGVkIHJlZGlyZWN0cywgd2UgaGF2ZSB0byBjYXJyeSB0aGUgcXVlcnkgcGFyYW1ldGVycyBvdmVyIHRvIHRoZSBuZXh0IHBhZ2VcbiAgICAgICAgICAgIHRoaXMuYXR0YWNoU3ViU2VsZWN0b3JzKHBhdGhJbmZvLCAobGFzdFNlYXJjaE5lc3RlZFJlZGlyZWN0ID09PSBudWxsIHx8IGxhc3RTZWFyY2hOZXN0ZWRSZWRpcmVjdCA9PT0gdm9pZCAwID8gdm9pZCAwIDogbGFzdFNlYXJjaE5lc3RlZFJlZGlyZWN0LmRlcHRoKSB8fCAwKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBnZXROZXN0ZWRSZWRpcmVjdCgpIHtcbiAgICAgICAgY29uc3QgcGF5bG9hZCA9IGdldFNlc3Npb25TdG9yYWdlKCkuZ2V0SXRlbShSZWRpcmVjdENvbGxlY3Rvci5ORVNURURfUkVESVJFQ1RfS0VZV09SRFNfU1RPUkFHRV9LRVkpO1xuICAgICAgICBpZiAocGF5bG9hZCkge1xuICAgICAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UocGF5bG9hZCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgaXNNYXhEZXB0aEV4Y2VlZGVkKGN1cnJlbnREZXB0aCA9IDApIHtcbiAgICAgICAgcmV0dXJuIGN1cnJlbnREZXB0aCA+PSB0aGlzLmRlcHRoO1xuICAgIH1cbiAgICByZWdpc3Rlck5lc3RlZFJlZGlyZWN0KHF1ZXJ5LCBjdXJyZW50RGVwdGggPSAwKSB7XG4gICAgICAgIGlmICh0aGlzLmlzTWF4RGVwdGhFeGNlZWRlZChjdXJyZW50RGVwdGgpKVxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICBjb25zdCBwYXlsb2FkID0ge1xuICAgICAgICAgICAgcXVlcnk6IHF1ZXJ5LFxuICAgICAgICAgICAgZGVwdGg6IGN1cnJlbnREZXB0aCArIDFcbiAgICAgICAgfTtcbiAgICAgICAgZ2V0U2Vzc2lvblN0b3JhZ2UoKS5zZXRJdGVtKFJlZGlyZWN0Q29sbGVjdG9yLk5FU1RFRF9SRURJUkVDVF9LRVlXT1JEU19TVE9SQUdFX0tFWSwgSlNPTi5zdHJpbmdpZnkocGF5bG9hZCkpO1xuICAgIH1cbiAgICBhdHRhY2hTdWJTZWxlY3RvcnMocGF0aEluZm8sIGN1cnJlbnREZXB0aCkge1xuICAgICAgICBpZiAodGhpcy5pc01heERlcHRoRXhjZWVkZWQoY3VycmVudERlcHRoKSlcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgdGhpcy5zdWJTZWxlY3RvcnMuZm9yRWFjaChzZWxlY3RvciA9PiB7XG4gICAgICAgICAgICBjb25zdCBoYW5kbGVDbGljayA9ICgpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlZ2lzdGVyTmVzdGVkUmVkaXJlY3QocGF0aEluZm8ucXVlcnksIGN1cnJlbnREZXB0aCk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgaWYgKHRoaXMubGlzdGVuZXJUeXBlID09PSBMaXN0ZW5lclR5cGUuU2VudGluZWwpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBzZW50aW5lbCA9IG5ldyBTZW50aW5lbCh0aGlzLmdldERvY3VtZW50KCkpO1xuICAgICAgICAgICAgICAgIHNlbnRpbmVsLm9uKHNlbGVjdG9yLCBlbGVtZW50ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgaW5mbyA9IHRoaXMucmVkaXJlY3RUcmFpbC5mZXRjaCh0aGlzLmdldFBhdGhuYW1lKCkpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoaW5mbykgeyAvLyB0aGUgc2VudGluZWwgY2FuIHRyaWdnZXIgb24gYW55IHBhZ2UsIHdlIG5lZWQgdG8gbWFrZSBzdXJlIHdlIGF0dGFjaCBzdWJTZWxlY3RvcnMgb25seSBvbiB2YWxpZCByZWRpcmVjdCBwYXRoc1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5hZGRFdmVudExpc3RlbmVyKFwiY2xpY2tcIiwgaGFuZGxlQ2xpY2spO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKHNlbGVjdG9yKS5mb3JFYWNoKGVsZW1lbnQgPT4ge1xuICAgICAgICAgICAgICAgICAgICBlbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoXCJjbGlja1wiLCBoYW5kbGVDbGljayk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBnZXRQYXRobmFtZSgpIHtcbiAgICAgICAgY29uc3QgcGF0aG5hbWUgPSBub3JtYWxpemVQYXRobmFtZSh0aGlzLmdldFdpbmRvdygpLmxvY2F0aW9uLnBhdGhuYW1lKTtcbiAgICAgICAgaWYgKHRoaXMubWF4UGF0aFNlZ21lbnRzID4gMCkge1xuICAgICAgICAgICAgY29uc3QgcGF0aFNlZ21lbnRzID0gcGF0aG5hbWUuc3BsaXQoXCIvXCIpO1xuICAgICAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZVBhdGhuYW1lKHBhdGhTZWdtZW50cy5maWx0ZXIocyA9PiAhIXMpLnNsaWNlKDAsIHRoaXMubWF4UGF0aFNlZ21lbnRzKS5qb2luKFwiL1wiKSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHBhdGhuYW1lO1xuICAgIH1cbiAgICBhdHRhY2hDb2xsZWN0b3JzKHdyaXRlciwgbG9nLCBxdWVyeSkge1xuICAgICAgICAvLyBhdHRhY2ggYWxsIGNvbGxlY3RvcnMgd2hpY2ggYXJlIHJlc3BvbnNpYmxlIHRvIGdhdGhlciBrcGkncyBhZnRlciB0aGUgcmVkaXJlY3RcbiAgICAgICAgdGhpcy5jb2xsZWN0b3JzLmZvckVhY2goY29sbGVjdG9yID0+IHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgY29sbGVjdG9yLmF0dGFjaCh7XG4gICAgICAgICAgICAgICAgICAgIHdyaXRlKGRhdGEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdyaXRlci53cml0ZSh7IC4uLmRhdGEsIHF1ZXJ5OiBkYXRhLnF1ZXJ5IHx8IHF1ZXJ5IH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSwgbG9nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgaWYgKGxvZylcbiAgICAgICAgICAgICAgICAgICAgbG9nLmVycm9yKGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG59XG4vKipcbiAqIEtleSB1c2VkIHRvIHN0b3JlIHRoZSBrZXl3b3JkcyBvZiB0aGUgbGFzdCBleGVjdXRlZCBzZWFyY2hcbiAqL1xuUmVkaXJlY3RDb2xsZWN0b3IuTEFTVF9TRUFSQ0hfU1RPUkFHRV9LRVkgPSBcIl9fbGFzdFNlYXJjaFwiO1xuLyoqXG4gKiBLZXkgdXNlZCB0byBzdG9yZSBxdWVyeSBpbmZvcm1hdGlvbiBmb3IgYSBnaXZlbiByZWRpcmVjdCBsYW5kaW5nIHBhZ2UgKHBhdGggb2YgdGhlIHVybClcbiAqL1xuUmVkaXJlY3RDb2xsZWN0b3IuUEFUSF9TVE9SQUdFX0tFWSA9IFwiX19fcGF0aFN0b3JhZ2VcIjtcblJlZGlyZWN0Q29sbGVjdG9yLk5FU1RFRF9SRURJUkVDVF9LRVlXT1JEU19TVE9SQUdFX0tFWSA9IFwiX19fbmVzdGVkUmVkaXJlY3RLZXl3b3Jkc1N0b3JhZ2VcIjtcbmZ1bmN0aW9uIHNob3VsZFRyYWNrUmVkaXJlY3QocmVmZXJlcikge1xuICAgIGlmIChyZWZlcmVyKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCByZWZVcmwgPSBuZXcgVVJMKHJlZmVyZXIpO1xuICAgICAgICAgICAgY29uc3QgY3VycmVudFVybCA9IG5ldyBVUkwod2luZG93LmxvY2F0aW9uLmhyZWYpO1xuICAgICAgICAgICAgaWYgKGN1cnJlbnRVcmwub3JpZ2luICYmIHJlZlVybC5vcmlnaW4pXG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlZlVybC5vcmlnaW4gPT09IGN1cnJlbnRVcmwub3JpZ2luO1xuICAgICAgICB9XG4gICAgICAgIGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGUpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xufVxuIiwiaW1wb3J0IHsgQWJzdHJhY3RDb2xsZWN0b3IgfSBmcm9tIFwiLi9BYnN0cmFjdENvbGxlY3RvclwiO1xuLyoqXG4gKiBDb2xsZWN0IHRoZSBiYXNpYyBzZWFyY2ggaW5mb3JtYXRpb24gLSB0aGUga2V5d29yZHMgdXNlZCBmb3IgdGhlIHNlYXJjaCBhbmRcbiAqIHRoZSBudW1iZXIgb2YgcmVzdWx0cy4gU3luY2hyb25vdXMgaS5lLiB0aGUgd3JpdGluZyBoYXBwZW5zIGRpcmVjdGx5IHdoZW4gYSB3cml0ZXIgaXMgYXR0YWNoZWQuXG4gKiBTZWUgdGhlIG90aGVyIHNlYXJjaCBjb2xsZWN0b3JzIGZvciBkeW5hbWljIG9uZXMuXG4gKi9cbmV4cG9ydCBjbGFzcyBTZWFyY2hSZXN1bHRDb2xsZWN0b3IgZXh0ZW5kcyBBYnN0cmFjdENvbGxlY3RvciB7XG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0IHNlYXJjaCByZXN1bHQgY29sbGVjdG9yXG4gICAgICpcbiAgICAgKiBAY29uc3RydWN0b3JcbiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBwaHJhc2VSZXNvbHZlciAtIEZ1bmN0aW9uIHRoYXQgc2hvdWxkIHJldHVybiB0aGUgc2VhcmNoIHBocmFzZSB1c2VkIGZvciB0aGUgc2VhcmNoXG4gICAgICogQHBhcmFtIHtmdW5jdGlvbn0gY291bnRSZXNvbHZlciAtIEZ1bmN0aW9uIHRoYXQgc2hvdWxkIHJldHVybiB0aGUgbnVtbmJlciBvZiByZXN1bHRzIGluIHRoZSBzZWFyY2hcbiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBhY3Rpb25SZXNvbHZlciAtIEEgc2VhcmNoIHJlc3VsdCBtYXkgYmUgcmVmaW5lZCBvciBhIGNsaWVudCBtYXkgYnJvd3NlIDIsMyw0IHBhZ2UuXG4gICAgICogVGhpcyBmdW5jdGlvbiBzaG91bGQgcHJvdmlkZSBhIHRleHQgcmVwcmVzYW50aW9uIG9mIHRoZSBhY3Rpb25cbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihwaHJhc2VSZXNvbHZlciwgY291bnRSZXNvbHZlciwgYWN0aW9uUmVzb2x2ZXIpIHtcbiAgICAgICAgc3VwZXIoXCJzZWFyY2hcIik7XG4gICAgICAgIHRoaXMucGhyYXNlUmVzb2x2ZXIgPSBwaHJhc2VSZXNvbHZlcjtcbiAgICAgICAgdGhpcy5jb3VudFJlc29sdmVyID0gY291bnRSZXNvbHZlcjtcbiAgICAgICAgdGhpcy5hY3Rpb25SZXNvbHZlciA9IGFjdGlvblJlc29sdmVyO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBBdHRhY2ggYSB3cml0ZXIsIG5vdGUgdGhhdCB0aGlzIGNvbGxlY3RvciBpcyBub3QgYXN5bmNocm9ub3VzIGFuZCB3aWxsIHdyaXRlXG4gICAgICogdGhlIGRhdGEgaW1tZWRpYXRlbGx5XG4gICAgICpcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gd3JpdGVyIC0gVGhlIHdyaXRlciB0byBzZW5kIHRoZSBkYXRhIHRvXG4gICAgICogQHBhcmFtIHtvYmplY3R9IGxvZyAtIFRoZSBsb2dnZXJcbiAgICAgKi9cbiAgICBhdHRhY2god3JpdGVyLCBsb2cpIHtcbiAgICAgICAgd3JpdGVyLndyaXRlKHtcbiAgICAgICAgICAgIHR5cGU6IFwic2VhcmNoXCIsXG4gICAgICAgICAgICBrZXl3b3JkczogdGhpcy5yZXNvbHZlKHRoaXMucGhyYXNlUmVzb2x2ZXIsIGxvZywge30pLFxuICAgICAgICAgICAgY291bnQ6IHRoaXMucmVzb2x2ZSh0aGlzLmNvdW50UmVzb2x2ZXIsIGxvZywge30pLFxuICAgICAgICAgICAgYWN0aW9uOiB0aGlzLnJlc29sdmUodGhpcy5hY3Rpb25SZXNvbHZlciwgbG9nLCB7fSkgfHwgXCJzZWFyY2hcIlxuICAgICAgICB9KTtcbiAgICB9XG59XG4iLCJpbXBvcnQgeyBXcml0ZXJSZXNvbHZlckNvbGxlY3RvciB9IGZyb20gXCIuL1dyaXRlclJlc29sdmVyQ29sbGVjdG9yXCI7XG4vKipcbiAqIENvbGxlY3Qgc3VnZ2VzdCBzZWFyY2ggaW5mb3JtYXRpb24gLSBrZXl3b3JkIHNlYXJjaGVzIGNvbWluZyBmcm9tIGEgc3VnZ2VzdGlvbiB3aWRnZXQvZnVuY3Rpb25hbGl0eVxuICovXG5leHBvcnQgY2xhc3MgU3VnZ2VzdFNlYXJjaENvbGxlY3RvciBleHRlbmRzIFdyaXRlclJlc29sdmVyQ29sbGVjdG9yIHtcbiAgICAvKipcbiAgICAgKiBDb25zdHJ1Y3Qgc3VnZ2VzdCBzZWFyY2ggY29sbGVjdG9yXG4gICAgICpcbiAgICAgKiBAY29uc3RydWN0b3JcbiAgICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSByZXNvbHZlciAtIEZ1bmN0aW9uIHRoYXQgdHJpZ2dlcnMgdGhlIHdyaXRpbmcuIFN1Z2dlc3QgbWlnaHQgYmUgY29tcGxleCwgbGVhdmUgdG8gdGhlIGltcGxlbWVudGF0aW9uIHRvIGRldGVybWluZSB3aGVuL2hvd1xuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKHJlc29sdmVyKSB7XG4gICAgICAgIHN1cGVyKFwic3VnZ2VzdC1zZWFyY2hcIiwgcmVzb2x2ZXIpO1xuICAgIH1cbn1cbiIsImltcG9ydCB7IEFic3RyYWN0Q29sbGVjdG9yIH0gZnJvbSBcIi4vQWJzdHJhY3RDb2xsZWN0b3JcIjtcbi8qKlxuICogUmVzb2x2ZXMgaW1tZWRpYXRlbHkgYW5kIHBhc3NpbmcgdGhlIHdyaXRlciwgdGhlIHR5cGUgb2YgdGhlIGV2ZW50ICsgY29udGV4dCB0byB0aGUgcHJvdmlkZWQgcmVzb2x2ZXIgZnVuY3Rpb24uXG4gKi9cbmV4cG9ydCBjbGFzcyBXcml0ZXJSZXNvbHZlckNvbGxlY3RvciBleHRlbmRzIEFic3RyYWN0Q29sbGVjdG9yIHtcbiAgICBjb25zdHJ1Y3Rvcih0eXBlLCByZXNvbHZlcikge1xuICAgICAgICBzdXBlcih0eXBlKTtcbiAgICAgICAgdGhpcy5yZXNvbHZlciA9IHJlc29sdmVyO1xuICAgIH1cbiAgICBhdHRhY2god3JpdGVyLCBsb2cpIHtcbiAgICAgICAgdGhpcy5yZXNvbHZlKHRoaXMucmVzb2x2ZXIsIGxvZywgd3JpdGVyLCB0aGlzLmdldFR5cGUoKSwgdGhpcy5nZXRDb250ZXh0KCkpO1xuICAgIH1cbn1cbiIsImV4cG9ydCAqIGZyb20gXCIuL0Fic3RyYWN0Q29sbGVjdG9yXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9Bc3NvY2lhdGVkUHJvZHVjdENvbGxlY3RvclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vQmFza2V0Q2xpY2tDb2xsZWN0b3JcIjtcbmV4cG9ydCAqIGZyb20gXCIuL0Jyb3dzZXJDb2xsZWN0b3JcIjtcbmV4cG9ydCAqIGZyb20gXCIuL0NoZWNrb3V0Q2xpY2tDb2xsZWN0b3JcIjtcbmV4cG9ydCAqIGZyb20gXCIuL0NsaWNrQ29sbGVjdG9yXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9DbGlja1dyaXRlclJlc29sdmVyQ29sbGVjdG9yXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9GaWx0ZXJDbGlja0NvbGxlY3RvclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vRmlyZWRTZWFyY2hDb2xsZWN0b3JcIjtcbmV4cG9ydCAqIGZyb20gXCIuL0dlbmVyaWNFdmVudENvbGxlY3RvclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vSW1wcmVzc2lvbkNvbGxlY3RvclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vSW5zdGFudFNlYXJjaFF1ZXJ5Q29sbGVjdG9yXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9Qcm9kdWN0Q2xpY2tDb2xsZWN0b3JcIjtcbmV4cG9ydCAqIGZyb20gXCIuL1JlZGlyZWN0Q29sbGVjdG9yXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9TZWFyY2hSZXN1bHRDb2xsZWN0b3JcIjtcbmV4cG9ydCAqIGZyb20gXCIuL1N1Z2dlc3RTZWFyY2hDb2xsZWN0b3JcIjtcbmV4cG9ydCAqIGZyb20gXCIuL1dyaXRlclJlc29sdmVyQ29sbGVjdG9yXCI7XG4iLCJleHBvcnQge307XG4iLCJleHBvcnQge307XG4iLCIvKipcbiAqIFBhc3NlcyBhbGwgbG9nIG1lc3NhZ2VzIHRvIHRoZSBwcm92aWRlZCB0cmFuc3BvcnRzXG4gKi9cbmV4cG9ydCBjbGFzcyBUcmFuc3BvcnRMb2dnZXIge1xuICAgIGNvbnN0cnVjdG9yKHRyYW5zcG9ydHMsIGlzRGVidWdFbmFibGVkID0gZmFsc2UpIHtcbiAgICAgICAgdGhpcy50cmFuc3BvcnRzID0gdHJhbnNwb3J0cztcbiAgICAgICAgdGhpcy5pc0RlYnVnRW5hYmxlZCA9IGlzRGVidWdFbmFibGVkO1xuICAgIH1cbiAgICBkZWJ1Zyhtc2csIC4uLmRhdGFBcmdzKSB7XG4gICAgICAgIHRoaXMudHJhbnNwb3J0cy5mb3JFYWNoKHRyYW5zcG9ydCA9PiB0aGlzLmNhbGxUcmFuc3BvcnQodHJhbnNwb3J0LCBcImRlYnVnXCIsIG1zZywgLi4uZGF0YUFyZ3MpKTtcbiAgICB9XG4gICAgZXJyb3IobXNnLCAuLi5kYXRhQXJncykge1xuICAgICAgICB0aGlzLnRyYW5zcG9ydHMuZm9yRWFjaCh0cmFuc3BvcnQgPT4gdGhpcy5jYWxsVHJhbnNwb3J0KHRyYW5zcG9ydCwgXCJlcnJvclwiLCBtc2csIC4uLmRhdGFBcmdzKSk7XG4gICAgfVxuICAgIGluZm8obXNnLCAuLi5kYXRhQXJncykge1xuICAgICAgICB0aGlzLnRyYW5zcG9ydHMuZm9yRWFjaCh0cmFuc3BvcnQgPT4gdGhpcy5jYWxsVHJhbnNwb3J0KHRyYW5zcG9ydCwgXCJpbmZvXCIsIG1zZywgLi4uZGF0YUFyZ3MpKTtcbiAgICB9XG4gICAgd2Fybihtc2csIC4uLmRhdGFBcmdzKSB7XG4gICAgICAgIHRoaXMudHJhbnNwb3J0cy5mb3JFYWNoKHRyYW5zcG9ydCA9PiB0aGlzLmNhbGxUcmFuc3BvcnQodHJhbnNwb3J0LCBcIndhcm5cIiwgbXNnLCAuLi5kYXRhQXJncykpO1xuICAgIH1cbiAgICBjYWxsVHJhbnNwb3J0KHRyYW5zcG9ydCwgbGV2ZWwsIG1zZywgLi4uZGF0YUFyZ3MpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGlmICh0cmFuc3BvcnRbbGV2ZWxdICYmIHR5cGVvZiB0cmFuc3BvcnRbbGV2ZWxdID09PSBcImZ1bmN0aW9uXCIpXG4gICAgICAgICAgICAgICAgdHJhbnNwb3J0W2xldmVsXShtc2csIC4uLmRhdGFBcmdzKTtcbiAgICAgICAgfVxuICAgICAgICBjYXRjaCAoZSkge1xuICAgICAgICAgICAgaWYgKHRoaXMuaXNEZWJ1Z0VuYWJsZWQpXG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkNvdWxkIG5vdCBjYWxsIHRyYW5zcG9ydDogXCIsIGUpO1xuICAgICAgICB9XG4gICAgfVxufVxuIiwiZXhwb3J0ICogZnJvbSBcIi4vTG9nZ2VyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9Mb2dnZXJUcmFuc3BvcnRcIjtcbmV4cG9ydCAqIGZyb20gXCIuL1RyYW5zcG9ydExvZ2dlclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vdHJhbnNwb3J0XCI7XG4iLCJleHBvcnQgY2xhc3MgQ29uc29sZVRyYW5zcG9ydCB7XG4gICAgZGVidWcobXNnLCAuLi5kYXRhQXJncykge1xuICAgICAgICBjb25zb2xlLmRlYnVnKG1zZywgLi4uZGF0YUFyZ3MpO1xuICAgIH1cbiAgICA7XG4gICAgaW5mbyhtc2csIC4uLmRhdGFBcmdzKSB7XG4gICAgICAgIGNvbnNvbGUuaW5mbyhtc2csIC4uLmRhdGFBcmdzKTtcbiAgICB9XG4gICAgO1xuICAgIHdhcm4obXNnLCAuLi5kYXRhQXJncykge1xuICAgICAgICBjb25zb2xlLndhcm4obXNnLCAuLi5kYXRhQXJncyk7XG4gICAgfVxuICAgIDtcbiAgICBlcnJvcihtc2csIC4uLmRhdGFBcmdzKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IobXNnLCAuLi5kYXRhQXJncyk7XG4gICAgfVxuICAgIDtcbn1cbiIsImltcG9ydCB7IGJhc2U2NEVuY29kZSB9IGZyb20gXCIuLi8uLi91dGlsc1wiO1xuLyoqXG4gKiBPbmx5IGFkZHMgZXJyb3IgbWVzc2FnZXMgdG8gYW4gc3FzIHF1ZXVlXG4gKi9cbmV4cG9ydCBjbGFzcyBTUVNFcnJvclRyYW5zcG9ydCB7XG4gICAgY29uc3RydWN0b3IocXVldWUsIGNoYW5uZWwsIHNlc3Npb25SZXNvbHZlciwgZmlmbyA9IGZhbHNlKSB7XG4gICAgICAgIHRoaXMucXVldWUgPSBxdWV1ZTtcbiAgICAgICAgdGhpcy5jaGFubmVsID0gY2hhbm5lbDtcbiAgICAgICAgdGhpcy5zZXNzaW9uUmVzb2x2ZXIgPSBzZXNzaW9uUmVzb2x2ZXI7XG4gICAgICAgIHRoaXMuZmlmbyA9IGZpZm87XG4gICAgfVxuICAgIHNlbmQoZGF0YSkge1xuICAgICAgICBjb25zdCBpbWcgPSBuZXcgSW1hZ2UoKTtcbiAgICAgICAgbGV0IHNyYyA9IHRoaXMucXVldWUgKyBcIj9WZXJzaW9uPTIwMTItMTEtMDUmQWN0aW9uPVNlbmRNZXNzYWdlXCI7XG4gICAgICAgIC8vIFNRUyBzdXBwb3J0cyBGSUZPIHF1ZXVlcyBpbiBzb21lIHJlZ2lvbnMgdGhhdCBjYW4gYWxzbyBndWFyYW50ZWUgdGhlIG9yZGVyXG4gICAgICAgIC8vIG9mIHRoZSBtZXNzYWdlcy5cbiAgICAgICAgaWYgKHRoaXMuZmlmbykge1xuICAgICAgICAgICAgLy8gVE9ETyB3aGVuIGVub3VnaCBpbmZvcm1hdGlvbiBpcyBwcmVzZW50IHRvIHVuaXF1ZWx5IGlkZW50aWZ5IGEgbWVzc2FnZSwgc3dpdGNoIHRoZSBkZWR1cGxpY2F0aW9uIGlkIHRvIGEgbWVzc2FnZSBoYXNoXG4gICAgICAgICAgICBzcmMgKz0gXCImTWVzc2FnZUdyb3VwSWQ9MSZNZXNzYWdlRGVkdXBsaWNhdGlvbklkPVwiICsgTWF0aC5yYW5kb20oKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIUFycmF5LmlzQXJyYXkoZGF0YSkgJiYgdHlwZW9mIGRhdGEgIT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgIGRhdGEgPSBbZGF0YV07XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHR5cGVvZiBkYXRhICE9PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICBkYXRhID0gSlNPTi5zdHJpbmdpZnkoZGF0YSk7XG4gICAgICAgIH1cbiAgICAgICAgc3JjICs9IFwiJk1lc3NhZ2VCb2R5PVwiICsgYmFzZTY0RW5jb2RlKGVuY29kZVVSSUNvbXBvbmVudChkYXRhKSk7XG4gICAgICAgIGltZy5zcmMgPSBzcmM7XG4gICAgfVxuICAgIGVycm9yKG1zZywgLi4uZGF0YUFyZ3MpIHtcbiAgICAgICAgdGhpcy5zZW5kKHtcbiAgICAgICAgICAgIHR5cGU6IFwiZXJyb3JcIixcbiAgICAgICAgICAgIG1zZyxcbiAgICAgICAgICAgIGNoYW5uZWw6IHRoaXMuY2hhbm5lbCxcbiAgICAgICAgICAgIHNlc3Npb246IHRoaXMuc2Vzc2lvblJlc29sdmVyKCksXG4gICAgICAgICAgICB0aW1lc3RhbXA6IG5ldyBEYXRlKCkuZ2V0VGltZSgpLFxuICAgICAgICAgICAgLi4uZGF0YUFyZ3NcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIDtcbn1cbiIsImltcG9ydCB7IFNRU0Vycm9yVHJhbnNwb3J0IH0gZnJvbSBcIi4vU1FTRXJyb3JUcmFuc3BvcnRcIjtcbi8qKlxuICogQWRkcyBhbGwgbG9nIGxldmVscyB0byBhbiBTUVMgcXVldWVcbiAqL1xuZXhwb3J0IGNsYXNzIFNRU1RyYW5zcG9ydCBleHRlbmRzIFNRU0Vycm9yVHJhbnNwb3J0IHtcbiAgICBkZWJ1Zyhtc2csIC4uLmRhdGFBcmdzKSB7XG4gICAgICAgIHRoaXMuc2VuZCh7XG4gICAgICAgICAgICB0eXBlOiBcImRlYnVnXCIsXG4gICAgICAgICAgICBtc2csXG4gICAgICAgICAgICAuLi5kYXRhQXJnc1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgO1xuICAgIGluZm8obXNnLCAuLi5kYXRhQXJncykge1xuICAgICAgICB0aGlzLnNlbmQoe1xuICAgICAgICAgICAgdHlwZTogXCJpbmZvXCIsXG4gICAgICAgICAgICBtc2csXG4gICAgICAgICAgICAuLi5kYXRhQXJnc1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgO1xuICAgIHdhcm4obXNnLCAuLi5kYXRhQXJncykge1xuICAgICAgICB0aGlzLnNlbmQoe1xuICAgICAgICAgICAgdHlwZTogXCJ3YXJuaW5nXCIsXG4gICAgICAgICAgICBtc2csXG4gICAgICAgICAgICAuLi5kYXRhQXJnc1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgO1xufVxuIiwiZXhwb3J0ICogZnJvbSBcIi4vQ29uc29sZVRyYW5zcG9ydFwiO1xuZXhwb3J0ICogZnJvbSBcIi4vU1FTRXJyb3JUcmFuc3BvcnRcIjtcbmV4cG9ydCAqIGZyb20gXCIuL1NRU1RyYW5zcG9ydFwiO1xuIiwiZXhwb3J0IGNsYXNzIFF1ZXJ5IHtcbiAgICBjb25zdHJ1Y3RvcihxdWVyeVN0cmluZykge1xuICAgICAgICAvKipcbiAgICAgICAgICogUmVtb3ZlIGFsbCBzZWxlY3Rpb25zIG9uIHRoaXMgZmllbGRcbiAgICAgICAgICovXG4gICAgICAgIHRoaXMucmVtb3ZlU2VsZWN0aW9uQXQgPSBmdW5jdGlvbiAocG9zKSB7XG4gICAgICAgICAgICBhcnJheVJlbW92ZSh0aGlzLmNyaXRlcmlhLCBwb3MsIHBvcyk7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuY3JpdGVyaWEgPSBbXTtcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICBpZiAocXVlcnlTdHJpbmcpIHtcbiAgICAgICAgICAgIHZhciBjcml0ZXJpYSA9IFtdO1xuICAgICAgICAgICAgdmFyIGFuZHMgPSBxdWVyeVN0cmluZy5zcGxpdChcIi9cIik7XG4gICAgICAgICAgICBhbmRzLmZvckVhY2goZnVuY3Rpb24gKGFuZCkge1xuICAgICAgICAgICAgICAgIGlmIChhbmQuaW5kZXhPZihcInxcIikgIT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9ycyA9IGFuZC5zcGxpdChcInxcIik7XG4gICAgICAgICAgICAgICAgICAgIG9ycy5mb3JFYWNoKGZ1bmN0aW9uIChvcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgY3JpdGVyaWEucHVzaCh7IFwic2VsZWN0aW9uXCI6IG9yLCBcInR5cGVcIjogXCJvclwiIH0pO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGNyaXRlcmlhLnB1c2goeyBcInNlbGVjdGlvblwiOiBhbmQsIFwidHlwZVwiOiBcImFuZFwiIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgY3JpdGVyaWEuZm9yRWFjaChmdW5jdGlvbiAoY3JpdGVyaW9uKSB7XG4gICAgICAgICAgICAgICAgdmFyIGMgPSB1bmVzY2FwZShjcml0ZXJpb24uc2VsZWN0aW9uKTtcbiAgICAgICAgICAgICAgICBpZiAoYy5pbmRleE9mKFwiPVwiKSAhPSAtMSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgdmFsdWVTcGxpdCA9IGMuc3BsaXQoXCI9XCIpO1xuICAgICAgICAgICAgICAgICAgICBzZWxmLmNyaXRlcmlhLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgXCJmaWVsZFwiOiB2YWx1ZVNwbGl0WzBdLFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJvcGVyYXRpb25cIjogXCI9XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBcInZhbHVlXCI6IHZhbHVlU3BsaXRbMV0sXG4gICAgICAgICAgICAgICAgICAgICAgICBcImFnZ3JlZ2F0aW9uXCI6IGNyaXRlcmlvbi50eXBlXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmIChjLmluZGV4T2YoXCI8XCIpICE9IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciB2YWx1ZVNwbGl0ID0gYy5zcGxpdChcIjxcIik7XG4gICAgICAgICAgICAgICAgICAgIGlmICgyID09IHZhbHVlU3BsaXQubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmNyaXRlcmlhLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiZmllbGRcIjogdmFsdWVTcGxpdFswXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIm9wZXJhdGlvblwiOiBcIjxcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcInZhbHVlXCI6IHZhbHVlU3BsaXRbMV0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJhZ2dyZWdhdGlvblwiOiBjcml0ZXJpb24udHlwZVxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoMyA9PSB2YWx1ZVNwbGl0Lmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5jcml0ZXJpYS5wdXNoKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcImZpZWxkXCI6IHZhbHVlU3BsaXRbMV0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJvcGVyYXRpb25cIjogXCI+PFwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwibG93ZXJWYWx1ZVwiOiB2YWx1ZVNwbGl0WzBdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwidXBwZXJWYWx1ZVwiOiB2YWx1ZVNwbGl0WzJdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiYWdncmVnYXRpb25cIjogY3JpdGVyaW9uLnR5cGVcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKGMuaW5kZXhPZihcIj5cIikgIT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZhbHVlU3BsaXQgPSBjLnNwbGl0KFwiPlwiKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKDIgPT0gdmFsdWVTcGxpdC5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuY3JpdGVyaWEucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJmaWVsZFwiOiB2YWx1ZVNwbGl0WzBdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwib3BlcmF0aW9uXCI6IFwiPlwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwidmFsdWVcIjogdmFsdWVTcGxpdFsxXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcImFnZ3JlZ2F0aW9uXCI6IGNyaXRlcmlvbi50eXBlXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIGlmICgzID09IHZhbHVlU3BsaXQubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmNyaXRlcmlhLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiZmllbGRcIjogdmFsdWVTcGxpdFsxXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIm9wZXJhdGlvblwiOiBcIj48XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJsb3dlclZhbHVlXCI6IHZhbHVlU3BsaXRbMl0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJ1cHBlclZhbHVlXCI6IHZhbHVlU3BsaXRbMV0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJhZ2dyZWdhdGlvblwiOiBjcml0ZXJpb24udHlwZVxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvKipcbiAgICAgKiBQdXQgYmFjayB0byBzdHJpbmcgdGhlIHF1ZXJ5IG9iamVjdFxuICAgICAqXG4gICAgICogQHJldHVybnMgYSBzdHJpbmcgaW4gdGhlIGZvcm0gb2YgL2JyYW5kPWRlYnV0L3ByaWNlPjEwMC9cbiAgICAgKi9cbiAgICB0b1N0cmluZygpIHtcbiAgICAgICAgdmFyIHJlc3VsdCA9IFwiXCI7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5jcml0ZXJpYS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmFyIGNyaXRlcmlvbiA9IHRoaXMuY3JpdGVyaWFbaV07XG4gICAgICAgICAgICB2YXIgc2VwYXJhdG9yID0gXCIvXCI7XG4gICAgICAgICAgICBpZiAoXCJvclwiID09IGNyaXRlcmlvbi5hZ2dyZWdhdGlvbikge1xuICAgICAgICAgICAgICAgIHZhciBuZXh0ID0gdGhpcy5jcml0ZXJpYVtpICsgMV07XG4gICAgICAgICAgICAgICAgaWYgKG5leHQgJiYgXCJvclwiID09IG5leHQuYWdncmVnYXRpb24pIHtcbiAgICAgICAgICAgICAgICAgICAgc2VwYXJhdG9yID0gXCJ8XCI7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGNyaXRlcmlvbi5vcGVyYXRpb24gPT0gXCI+PFwiKSB7XG4gICAgICAgICAgICAgICAgcmVzdWx0ICs9IGNyaXRlcmlvbi5sb3dlclZhbHVlICsgXCI8XCIgKyBjcml0ZXJpb24uZmllbGQgKyBcIjxcIiArIGNyaXRlcmlvbi51cHBlclZhbHVlICsgc2VwYXJhdG9yO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgcmVzdWx0ICs9IGNyaXRlcmlvbi5maWVsZCArIGNyaXRlcmlvbi5vcGVyYXRpb24gKyBjcml0ZXJpb24udmFsdWUgKyBzZXBhcmF0b3I7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG4gICAgLyoqXG4gICAgICogQWRkIGEgc2VsZWN0aW9uIHRvIHRoaXMgcXVlcnkuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gZmllbGQgdGhlIG5hbWUgb2YgdGhlIGZpZWxkIHdlJ3JlIGRyaWxsaW5nIGRvd24gd2l0aFxuICAgICAqIEBwYXJhbSBvcGVyYXRpb24gdGhlIG9wZXJhdGlvbiwgZXggPSw+LDxcbiAgICAgKiBAcGFyYW0gdmFsdWUgdGhlIHZhbHVlIGZvciB0aGUgb3BlcmF0aW9uXG4gICAgICogQHBhcmFtIHZhbHVlMSBvcHRpb25hbCBzZWNvbmQgdmFsdWUgZm9yIGNvbnN0cnVjdGluZyByYW5nZXMgbGlrZSAxMDA8cHJpY2U8MjAwXG4gICAgICovXG4gICAgYWRkU2VsZWN0aW9uKGZpZWxkLCBvcGVyYXRpb24sIHZhbHVlLCB2YWx1ZTEsIGFnZ3JlZ2F0aW9uKSB7XG4gICAgICAgIGNvbnN0IGFnZyA9IGFnZ3JlZ2F0aW9uID8gYWdncmVnYXRpb24gOiBcImFuZFwiO1xuICAgICAgICBpZiAodmFsdWUxICYmIFwiPjxcIiA9PSBvcGVyYXRpb24pIHtcbiAgICAgICAgICAgIHRoaXMuY3JpdGVyaWEucHVzaCh7XG4gICAgICAgICAgICAgICAgXCJmaWVsZFwiOiBmaWVsZCxcbiAgICAgICAgICAgICAgICBcIm9wZXJhdGlvblwiOiBcIj48XCIsXG4gICAgICAgICAgICAgICAgXCJsb3dlclZhbHVlXCI6IHZhbHVlLFxuICAgICAgICAgICAgICAgIFwidXBwZXJWYWx1ZVwiOiB2YWx1ZTEsXG4gICAgICAgICAgICAgICAgXCJhZ2dyZWdhdGlvblwiOiBhZ2dcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5jcml0ZXJpYS5wdXNoKHtcbiAgICAgICAgICAgICAgICBcImZpZWxkXCI6IGZpZWxkLFxuICAgICAgICAgICAgICAgIFwib3BlcmF0aW9uXCI6IG9wZXJhdGlvbixcbiAgICAgICAgICAgICAgICBcInZhbHVlXCI6IHZhbHVlLFxuICAgICAgICAgICAgICAgIFwiYWdncmVnYXRpb25cIjogYWdnXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvKipcbiAgICAgKiBQYXJzZSBhbmQgY29uc3RydWN0IGEgbmV3IG9iamVjdCByZXByZXNlbnRhdGlvbiBvZiB0aGUgcXVlcnkgc3RyaW5nIGZvcm1cbiAgICAgKlxuICAgICAqIEBwYXJhbSBxdWVyeVN0cmluZyB0aGUgcXVlcnkgc3RyaW5nIGluIHRoZSBmb3JtIG9mIFwiL1wiIGpvaW5lZCBjcml0ZXJpYS4gZXguIC9icmFuZD1kZWJ1dC9wcmljZT4xMDAvXG4gICAgICogQHJldHVybnNcbiAgICAgKi9cbiAgICBnZXRTZWxlY3Rpb25zKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jcml0ZXJpYTtcbiAgICB9XG4gICAgZ2V0U2VsZWN0aW9uKGZpZWxkKSB7XG4gICAgICAgIGZvciAodmFyIGMgaW4gdGhpcy5jcml0ZXJpYSkge1xuICAgICAgICAgICAgdmFyIGNyaXQgPSB0aGlzLmNyaXRlcmlhW2NdO1xuICAgICAgICAgICAgaWYgKGNyaXQuZmllbGQgPT0gZmllbGQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gY3JpdDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBDaGVjayBpZiB0aGlzIHF1ZXJ5IGFscmVhZHkgaGFzIGEgc2VsZWN0aW9uIGZvciB0aGUgZ2l2ZW4gZmllbGRcbiAgICAgKlxuICAgICAqIEByZXR1cm5zIHRydWUgaWYgd2UgaGF2ZSBhIHNlbGVjdGlvbiBvZiB0aGlzIGZpZWxkLCBmYWxzZSBvdGhlcndpc2VcbiAgICAgKi9cbiAgICBoYXNTZWxlY3Rpb24oZmllbGQpIHtcbiAgICAgICAgZm9yICh2YXIgYyBpbiB0aGlzLmNyaXRlcmlhKSB7XG4gICAgICAgICAgICB2YXIgY3JpdCA9IHRoaXMuY3JpdGVyaWFbY107XG4gICAgICAgICAgICBpZiAoY3JpdC5maWVsZCA9PSBmaWVsZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogQ2hlY2sgaWYgdGhpcyBxdWVyeSBhbHJlYWR5IGhhcyBhIHNlbGVjdGlvbiBmb3IgdGhlIGdpdmVuIGZpZWxkXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyB0cnVlIGlmIHdlIGhhdmUgYSBzZWxlY3Rpb24gb2YgdGhpcyBmaWVsZCwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAgICovXG4gICAgaGFzRXhhY3RTZWxlY3Rpb24oZmllbGQpIHtcbiAgICAgICAgZm9yICh2YXIgYyBpbiB0aGlzLmNyaXRlcmlhKSB7XG4gICAgICAgICAgICB2YXIgY3JpdCA9IHRoaXMuY3JpdGVyaWFbY107XG4gICAgICAgICAgICBpZiAoY3JpdC5maWVsZCA9PSBmaWVsZCAmJiBjcml0Lm9wZXJhdGlvbiA9PSBcIj1cIikge1xuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogUmVtb3ZlIGFsbCBzZWxlY3Rpb25zIG9uIHRoaXMgZmllbGRcbiAgICAgKi9cbiAgICByZW1vdmVTZWxlY3Rpb24oZmllbGQpIHtcbiAgICAgICAgdmFyIGNyaXRlcmlhID0gW107XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5jcml0ZXJpYS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmFyIGNyaXQgPSB0aGlzLmNyaXRlcmlhW2ldO1xuICAgICAgICAgICAgaWYgKGNyaXQuZmllbGQgPT0gZmllbGQpIHtcbiAgICAgICAgICAgICAgICBjcml0ZXJpYS5wdXNoKGkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHdoaWxlIChjcml0ZXJpYS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICB2YXIgYyA9IGNyaXRlcmlhLnBvcCgpO1xuICAgICAgICAgICAgYXJyYXlSZW1vdmUodGhpcy5jcml0ZXJpYSwgYywgYyk7XG4gICAgICAgIH1cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmNyaXRlcmlhLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICB2YXIgY3VycmVudCA9IHRoaXMuY3JpdGVyaWFbaV07XG4gICAgICAgICAgICB2YXIgcHJldmlvdXMgPSB0aGlzLmNyaXRlcmlhW2kgLSAxXTtcbiAgICAgICAgICAgIHZhciBuZXh0ID0gdGhpcy5jcml0ZXJpYVtpICsgMV07XG4gICAgICAgICAgICBpZiAoXCJvclwiID09IGN1cnJlbnQuYWdncmVnYXRpb24pIHtcbiAgICAgICAgICAgICAgICBpZiAoKCFuZXh0IHx8IFwiYW5kXCIgPT0gbmV4dC5hZ2dyZWdhdGlvbikgJiYgKCFwcmV2aW91cyB8fCBcImFuZFwiID09IHByZXZpb3VzLmFnZ3JlZ2F0aW9uKSkge1xuICAgICAgICAgICAgICAgICAgICBjdXJyZW50LmFnZ3JlZ2F0aW9uID0gXCJhbmRcIjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgc2V0U2VhcmNoKHRlcm0pIHtcbiAgICAgICAgaWYgKHRlcm0pIHtcbiAgICAgICAgICAgIHRoaXMucmVtb3ZlU2VsZWN0aW9uKFwiJHNcIik7XG4gICAgICAgICAgICB0aGlzLmNyaXRlcmlhLnVuc2hpZnQoe1xuICAgICAgICAgICAgICAgIFwiZmllbGRcIjogXCIkc1wiLFxuICAgICAgICAgICAgICAgIFwib3BlcmF0aW9uXCI6IFwiPVwiLFxuICAgICAgICAgICAgICAgIFwidmFsdWVcIjogdGVybVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZ2V0U2VhcmNoKCkge1xuICAgICAgICBjb25zdCBzID0gdGhpcy5nZXRTZWxlY3Rpb24oXCIkc1wiKTtcbiAgICAgICAgcmV0dXJuIHMgPyBzLnZhbHVlIDogdW5kZWZpbmVkO1xuICAgIH1cbiAgICBpc1ZhbGlkKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jcml0ZXJpYS5sZW5ndGggPiAwO1xuICAgIH1cbn1cbi8qKlxuICogV2UgaGF2ZSB0aGUgc2FtZSBmdW5jdGlvbiBpbiB1dGlsIGJ1dCB3ZSB3YW50IHRvIGhhdmUgcXVlcnkuanMgd2l0aG91dCBhbnkgZGVwZW5kZW5jaWVzXG4gKlxuICogQHBhcmFtIGFycmF5XG4gKiBAcGFyYW0gZnJvbVxuICogQHBhcmFtIHRvXG4gKiBAcmV0dXJucyB7TnVtYmVyfCp9XG4gKi9cbmZ1bmN0aW9uIGFycmF5UmVtb3ZlKGFycmF5LCBmcm9tLCB0bykge1xuICAgIHZhciByZXN0ID0gYXJyYXkuc2xpY2UoKHRvIHx8IGZyb20pICsgMSB8fCBhcnJheS5sZW5ndGgpO1xuICAgIGFycmF5Lmxlbmd0aCA9IGZyb20gPCAwID8gYXJyYXkubGVuZ3RoICsgZnJvbSA6IGZyb207XG4gICAgcmV0dXJuIGFycmF5LnB1c2guYXBwbHkoYXJyYXksIHJlc3QpO1xufVxuIiwiaW1wb3J0IHsgZ2V0TG9jYWxTdG9yYWdlLCBnZXRTZXNzaW9uU3RvcmFnZSB9IGZyb20gXCIuLi91dGlscy9VdGlsXCI7XG5pbXBvcnQgeyBUcmFpbFR5cGUgfSBmcm9tIFwiLi9UcmFpbFR5cGVcIjtcbmNvbnN0IFRUTCA9IDEwMDAgKiA2MCAqIDYwICogMjQgKiAyO1xuZXhwb3J0IGNsYXNzIFRyYWlsIHtcbiAgICAvKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSBxdWVyeVJlc29sdmVyXG4gICAgICogQHBhcmFtIHNlc3Npb25SZXNvbHZlclxuICAgICAqIEBwYXJhbSB1aWQgdGhlIHVuaXF1ZSBpZCBvZiB0aGlzIHRyYWlsLiBVc2VkIGFzIHBhcnQgb2YgdGhlIGtleSB0byBzYXZlIGFsbCBUcmFpbCBzdGVwcy9wYXJ0c1xuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKHF1ZXJ5UmVzb2x2ZXIsIHNlc3Npb25SZXNvbHZlciwgdWlkKSB7XG4gICAgICAgIHRoaXMucXVlcnlSZXNvbHZlciA9IHF1ZXJ5UmVzb2x2ZXI7XG4gICAgICAgIHRoaXMuc2Vzc2lvblJlc29sdmVyID0gc2Vzc2lvblJlc29sdmVyO1xuICAgICAgICB0aGlzLmtleSA9IFwic2VhcmNoLWNvbGxlY3Rvci10cmFpbFwiICsgKHVpZCA/IFwiLVwiICsgdWlkIDogXCJcIik7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBsb2NhbFRyYWlscyA9IHRoaXMuX2xvYWQoZ2V0TG9jYWxTdG9yYWdlKCkpO1xuICAgICAgICAgICAgY29uc3Qgbm93ID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG4gICAgICAgICAgICAvLyBEcm9wIGFsbCBleHBpcmVkIHRyYWlscywgVFRMIGluIHN5bmMgd2l0aCBzZXNzaW9uIGR1cmF0aW9uIG9mIDMwIG1pblxuICAgICAgICAgICAgZm9yIChsZXQgaWQgb2YgT2JqZWN0LmtleXMobG9jYWxUcmFpbHMpKSB7XG4gICAgICAgICAgICAgICAgaWYgKG5vdyA+IGxvY2FsVHJhaWxzW2lkXS50aW1lc3RhbXAgKyBUVEwpIHtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIGxvY2FsVHJhaWxzW2lkXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLl9zYXZlKGdldExvY2FsU3RvcmFnZSgpLCBsb2NhbFRyYWlscyk7XG4gICAgICAgICAgICAvLyBMb2FkIGV4aXN0aW5nIHNlc3Npb24gdHJhaWxzIGFuZCBtZXJnZSBpdCB3aXRoIHRoZSBsb2NhbCBzdG9yYWdlIHRyYWlscy5cbiAgICAgICAgICAgIC8vIFRoaXMgc2hvdWxkIGd1YXJhbnRlZSB0aGF0IHJlZ2FyZGxlc3Mgb2Ygd2hldGhlciB0aGUgcGFnZXMgZnVydGhlciBkb3duIHRoZSB0cmFpbFxuICAgICAgICAgICAgLy8gKGJhc2tldCwgY2hlY2tvdXQpIHdlcmUgb3BlbiBpbiBhIG5ldyB0YWIgb3Igbm90LCB3ZSBoYXZlIGEgZnVsbCByZXByZXNlbnRhdGlvblxuICAgICAgICAgICAgLy8gb2YgYWxsIHByb2R1Y3QgY2xpY2tzIHdpdGhpbiB0aGUgc2Vzc2lvbi4gUmVtaW5kZXIsIHNlc3Npb25TdG9yYWdlIGlzIG1haW50YWluZWRcbiAgICAgICAgICAgIC8vIHBlciB0YWIvd2luZG93IGFuZCBpcyBkZWxldGVkIHVwb24gY2xvc2luZywgbG9jYWxTdG9yYWdlIGlzIHBlciB3ZWJzaXRlIHdpdGggbm9cbiAgICAgICAgICAgIC8vIGRlZmF1bHQgZXhwaXJ5LlxuICAgICAgICAgICAgY29uc3Qgc2Vzc2lvblRyYWlscyA9IHRoaXMuX2xvYWQoZ2V0U2Vzc2lvblN0b3JhZ2UoKSk7XG4gICAgICAgICAgICBjb25zdCB0cmFpbHMgPSBPYmplY3QuYXNzaWduKGxvY2FsVHJhaWxzLCBzZXNzaW9uVHJhaWxzKTtcbiAgICAgICAgICAgIHRoaXMuX3NhdmUoZ2V0U2Vzc2lvblN0b3JhZ2UoKSwgdHJhaWxzKTtcbiAgICAgICAgfVxuICAgICAgICBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5sb2coXCJFcnJvciBwYXJzaW5nIHN0b3JlZCBldmVudCBxdWV1ZSBcIiArIGUpO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8qKlxuICAgICAqIFJlZ2lzdGVyIHRoaXMgcHJvZHVjdCBpZCBhcyBzdGFydGluZyBhIHB1cmNoYXNlIGpvdXJuZXkgYXQgdGhpcyBzZXNzaW9uL3F1ZXJ5XG4gICAgICogUG9zc2libGUgdHJhaWwgdHlwZXMgYXJlIFwibWFpblwiIGFuZCBcImFzc29jaWF0ZWRcIlxuICAgICAqL1xuICAgIHJlZ2lzdGVyKGlkLCB0cmFpbFR5cGUgPSBUcmFpbFR5cGUuTWFpbiwgcXVlcnlTdHJpbmcpIHtcbiAgICAgICAgY29uc3QgdHJhaWwgPSB7XG4gICAgICAgICAgICB0aW1lc3RhbXA6IG5ldyBEYXRlKCkuZ2V0VGltZSgpLFxuICAgICAgICAgICAgcXVlcnk6IHF1ZXJ5U3RyaW5nIHx8IHRoaXMucXVlcnlSZXNvbHZlcigpLnRvU3RyaW5nKCksXG4gICAgICAgICAgICB0eXBlOiB0cmFpbFR5cGVcbiAgICAgICAgfTtcbiAgICAgICAgZm9yIChsZXQgc3RvcmFnZSBvZiBbZ2V0TG9jYWxTdG9yYWdlKCksIGdldFNlc3Npb25TdG9yYWdlKCldKSB7XG4gICAgICAgICAgICBjb25zdCB0cmFpbHMgPSB0aGlzLl9sb2FkKHN0b3JhZ2UpO1xuICAgICAgICAgICAgdHJhaWxzW2lkXSA9IHRyYWlsO1xuICAgICAgICAgICAgdGhpcy5fc2F2ZShzdG9yYWdlLCB0cmFpbHMpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGZldGNoKGlkKSB7XG4gICAgICAgIGNvbnN0IHRyYWlscyA9IHRoaXMuX2xvYWQoZ2V0U2Vzc2lvblN0b3JhZ2UoKSk7XG4gICAgICAgIHJldHVybiB0cmFpbHNbaWRdO1xuICAgIH1cbiAgICBfbG9hZChzdG9yYWdlKSB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSBzdG9yYWdlLmdldEl0ZW0odGhpcy5rZXkpO1xuICAgICAgICByZXR1cm4gZGF0YSA/IEpTT04ucGFyc2UoZGF0YSkgOiB7fTtcbiAgICB9XG4gICAgX3NhdmUoc3RvcmFnZSwgZGF0YSkge1xuICAgICAgICBzdG9yYWdlLnNldEl0ZW0odGhpcy5rZXksIEpTT04uc3RyaW5naWZ5KGRhdGEpKTtcbiAgICB9XG59XG4iLCJleHBvcnQgdmFyIFRyYWlsVHlwZTtcbihmdW5jdGlvbiAoVHJhaWxUeXBlKSB7XG4gICAgVHJhaWxUeXBlW1wiTWFpblwiXSA9IFwibWFpblwiO1xuICAgIFRyYWlsVHlwZVtcIkFzc29jaWF0ZWRcIl0gPSBcImFzc29jaWF0ZWRcIjtcbn0pKFRyYWlsVHlwZSB8fCAoVHJhaWxUeXBlID0ge30pKTtcbiIsImV4cG9ydCAqIGZyb20gXCIuL1F1ZXJ5XCI7XG5leHBvcnQgKiBmcm9tIFwiLi9UcmFpbFwiO1xuZXhwb3J0ICogZnJvbSBcIi4vVHJhaWxUeXBlXCI7XG4iLCJpbXBvcnQgeyBDb250ZXh0IH0gZnJvbSBcIi4uL3V0aWxzL0NvbnRleHRcIjtcbmltcG9ydCB7IGdlbmVyYXRlSWQsIGdldENvb2tpZSwgZ2V0TG9jYWxTdG9yYWdlLCBzZXRDb29raWUgfSBmcm9tIFwiLi4vdXRpbHMvVXRpbFwiO1xuY29uc3QgTUlOVVRFU19PTkVfREFZID0gNjAgKiAyNDtcbmNvbnN0IE1JTlVURVNfVFdPX0RBWVMgPSA2MCAqIDI0ICogMjtcbmNvbnN0IE1JTlVURVNfSEFMRl9IT1VSID0gMzA7XG4vKipcbiAqIFJlYWQgdGhlIGNvb2tpZSB3aXRoIHRoZSBwcm92aWRlZCBuYW1lXG4gKiBAcGFyYW0gbmFtZSB0aGUgbmFtZSBvZiB0aGUgY29va2llXG4gKi9cbmV4cG9ydCBjb25zdCBjb29raWVSZXNvbHZlciA9IChuYW1lID0gXCJcIikgPT4gZ2V0Q29va2llKG5hbWUpO1xuLyoqXG4gKiBSZXNvbHZlIHRoZSBpZCBvZiB0aGUgY3VycmVudCBzZWFyY2ggc2Vzc2lvbi4gQSBzZWFyY2ggc2Vzc2lvbiBpcyBkZWZpbmVkIGFzXG4gKiBsaW1pdGVkIHRpbWUgc2xpY2Ugb2Ygc2VhcmNoIGFjdGl2aXR5IGFjcm9zcyBtdWx0aXBsZSB0YWJzLiBCeSBkZWZhdWx0IGEgc2Vzc2lvblxuICogd291bGQgYmUgY29uc2lkZXJlZCBleHBpcmVkIGFmdGVyIDMwIG1pbiBvZiBpbmFjdGl2aXR5LlxuICpcbiAqIEluIGNhc2UgdGhlIHJlc29sdmVyIGlzIGNvbnN0cnVjdGVkIHdpdGggYSBjb29raWUgbmFtZSwgdGhlIHNlc3Npb24gbGlmZWN5Y2xlXG4gKiB3aWxsIGJlIGdvdmVybmVkIGJ5IHRoZSBsaWZlY3ljbGUgb2YgdGhhdCBjb29raWUuIE90aGVyd2lzZSB0aGUgcmVzb2x2ZXIgd2lsbFxuICogc2V0IGl0cyBvd24gY29va2llLlxuICpcbiAqIEBwYXJhbSBuYW1lIHRoZSBuYW1lIG9mIHRoZSBzZXNzaW9uIGNvb2tpZVxuICovXG5leHBvcnQgY29uc3QgY29va2llU2Vzc2lvblJlc29sdmVyID0gKG5hbWUgPSBcIlNlYXJjaENvbGxlY3RvclNlc3Npb25cIikgPT4gc2V0Q29va2llKG5hbWUsIGNvb2tpZVJlc29sdmVyKG5hbWUpIHx8IGdlbmVyYXRlSWQoKSwgTUlOVVRFU19UV09fREFZUyk7XG4vKipcbiAqIEZpbmQgdGhlIHBvc2l0aW9uIG9mIGEgRE9NIGVsZW1lbnQgcmVsYXRpdmUgdG8gb3RoZXIgRE9NIGVsZW1lbnRzIG9mIHRoZSBzYW1lIHR5cGUuXG4gKiBUbyBiZSB1c2VkIHRvIGZpbmQgdGhlIHBvc2l0aW9uIG9mIGFuIGl0ZW0gaW4gYSBzZWFyY2ggcmVzdWx0LlxuICpcbiAqIEBwYXJhbSBzZWxlY3RvckV4cHJlc3Npb24gdGhlIGNzcyBleHByZXNzaW9uIHRvIHF1ZXJ5IGZvciBvdGhlciBlbGVtZW50c1xuICogQHBhcmFtIGVsZW1lbnQgdGhlIGVsZW1lbnQgZm9yIHdoaWNoIHdlIHdhbnQgdG8ga25vdyB0aGUgcG9zaXRpb24gcmVsYXRpdmUgdG8gdGhlIGVsZW1lbnRzIHNlbGVjdGVkIGJ5IHNlbGVjdG9yRXhwcmVzc2lvblxuICogQHBhcmFtIGN0eCB0aGUgY29udGV4dCB0byB1c2UuIGRlZmF1bHRzIHRvIG5ldyBDb250ZXh0KHdpbmRvdywgZG9jdW1lbnQpXG4gKi9cbmV4cG9ydCBjb25zdCBwb3NpdGlvblJlc29sdmVyID0gKHNlbGVjdG9yRXhwcmVzc2lvbiwgZWxlbWVudCwgY3R4ID0gbmV3IENvbnRleHQod2luZG93LCBkb2N1bWVudCkpID0+IHtcbiAgICByZXR1cm4gQXJyYXkuZnJvbShjdHguZ2V0RG9jdW1lbnQoKS5xdWVyeVNlbGVjdG9yQWxsKHNlbGVjdG9yRXhwcmVzc2lvbikpXG4gICAgICAgIC5yZWR1Y2UoKGFjYywgbm9kZSwgaW5kZXgpID0+IG5vZGUgPT09IGVsZW1lbnQgPyBpbmRleCA6IGFjYywgdW5kZWZpbmVkKTtcbn07XG4vKipcbiAqIFRoaXMgaXMgYSBwZXJzaXN0ZW50IGRlYnVnIHJlc29sdmVyIHdoaWNoIHN0b3JlcyB0aGUgZGVidWcgcXVlcnkgcGFyYW1ldGVyIGFjcm9zcyByZXF1ZXN0cy5cbiAqL1xuZXhwb3J0IGNvbnN0IGRlYnVnUmVzb2x2ZXIgPSAoKSA9PiB7XG4gICAgY29uc3QgREVCVUdfS0VZID0gXCJfX2NvbGxlY3RvckRlYnVnXCI7XG4gICAgY29uc3QgZGVidWdQYXJhbSA9IG5ldyBVUkxTZWFyY2hQYXJhbXMod2luZG93LmxvY2F0aW9uLnNlYXJjaCkuZ2V0KFwiZGVidWdcIik7XG4gICAgY29uc3QgaXNEZWJ1Z1BhcmFtRXhpc3RzID0gZGVidWdQYXJhbSAhPSBudWxsO1xuICAgIGlmIChpc0RlYnVnUGFyYW1FeGlzdHMpIHtcbiAgICAgICAgY29uc3QgZGVidWcgPSBkZWJ1Z1BhcmFtID09PSBcInRydWVcIjtcbiAgICAgICAgZ2V0TG9jYWxTdG9yYWdlKCkuc2V0SXRlbShERUJVR19LRVksIFN0cmluZyhkZWJ1ZykpO1xuICAgIH1cbiAgICByZXR1cm4gZ2V0TG9jYWxTdG9yYWdlKCkuZ2V0SXRlbShERUJVR19LRVkpID09PSBcInRydWVcIjtcbn07XG4iLCJleHBvcnQgKiBmcm9tIFwiLi9SZXNvbHZlclwiO1xuIiwiZXhwb3J0IGNsYXNzIENvbnRleHQge1xuICAgIGNvbnN0cnVjdG9yKHdpbmRvdywgZG9jdW1lbnQpIHtcbiAgICAgICAgdGhpcy53aW5kb3cgPSB3aW5kb3c7XG4gICAgICAgIHRoaXMuZG9jdW1lbnQgPSBkb2N1bWVudDtcbiAgICB9XG4gICAgZ2V0V2luZG93KCkge1xuICAgICAgICByZXR1cm4gdGhpcy53aW5kb3c7XG4gICAgfVxuICAgIGdldERvY3VtZW50KCkge1xuICAgICAgICByZXR1cm4gdGhpcy5kb2N1bWVudDtcbiAgICB9XG59XG4iLCJleHBvcnQgdmFyIExpc3RlbmVyVHlwZTtcbihmdW5jdGlvbiAoTGlzdGVuZXJUeXBlKSB7XG4gICAgTGlzdGVuZXJUeXBlW1wiRG9tXCJdID0gXCJkb21cIjtcbiAgICBMaXN0ZW5lclR5cGVbXCJTZW50aW5lbFwiXSA9IFwic2VudGluZWxcIjtcbn0pKExpc3RlbmVyVHlwZSB8fCAoTGlzdGVuZXJUeXBlID0ge30pKTtcbiIsImltcG9ydCB7IGdldExvY2FsU3RvcmFnZSB9IGZyb20gXCIuL1V0aWxcIjtcbmV4cG9ydCBjbGFzcyBMb2NhbFN0b3JhZ2VRdWV1ZSB7XG4gICAgY29uc3RydWN0b3IoaWQpIHtcbiAgICAgICAgdGhpcy5uYW1lID0gXCJzZWFyY2gtY29sbGVjdG9yLXF1ZXVlXCIgKyAoaWQgPyBcIi1cIiArIGlkIDogXCJcIik7XG4gICAgICAgIHRoaXMucXVldWUgPSBbXTtcbiAgICAgICAgY29uc3Qgc3RvcmVkUXVldWUgPSBnZXRMb2NhbFN0b3JhZ2UoKS5nZXRJdGVtKHRoaXMubmFtZSk7XG4gICAgICAgIGlmIChzdG9yZWRRdWV1ZSkge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICB0aGlzLnF1ZXVlID0gSlNPTi5wYXJzZShzdG9yZWRRdWV1ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciBwYXJzaW5nIHN0b3JlZCBldmVudCBxdWV1ZSBcIiArIGUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIHB1c2goZGF0YSkge1xuICAgICAgICB0aGlzLnF1ZXVlLnB1c2goZGF0YSk7XG4gICAgICAgIHRoaXMuX3NhdmUoKTtcbiAgICB9XG4gICAgZHJhaW4oKSB7XG4gICAgICAgIGNvbnN0IGJ1ZmZlciA9IHRoaXMucXVldWU7XG4gICAgICAgIHRoaXMucXVldWUgPSBbXTtcbiAgICAgICAgdGhpcy5fc2F2ZSgpO1xuICAgICAgICByZXR1cm4gYnVmZmVyO1xuICAgIH1cbiAgICB0cmFuc2FjdGlvbmFsRHJhaW4oYXN5bmNDYWxsYmFjaykge1xuICAgICAgICBjb25zdCBidWZmZXIgPSB0aGlzLnF1ZXVlO1xuICAgICAgICByZXR1cm4gYXN5bmNDYWxsYmFjayh0aGlzLnF1ZXVlKVxuICAgICAgICAgICAgLnRoZW4ocmVzID0+IHtcbiAgICAgICAgICAgIHRoaXMucXVldWUgPSBbXTtcbiAgICAgICAgICAgIHRoaXMuX3NhdmUoKTtcbiAgICAgICAgICAgIHJldHVybiBidWZmZXI7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBzaXplKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5xdWV1ZS5sZW5ndGg7XG4gICAgfVxuICAgIF9zYXZlKCkge1xuICAgICAgICBnZXRMb2NhbFN0b3JhZ2UoKS5zZXRJdGVtKHRoaXMubmFtZSwgSlNPTi5zdHJpbmdpZnkodGhpcy5xdWV1ZSkpO1xuICAgIH1cbn1cbiIsIi8qKlxuICogQ2xvbmVkIGZyb20gaHR0cHM6Ly9naXRodWIuY29tL211aWNzcy9zZW50aW5lbGpzIHVudGlsIGEgcGF0Y2hlZCB2ZXJzaW9uXG4gKiBzdXBwb3JpbmcgaWZyYW1lcyBnZXRzIGF2YWlsYWJsZVxuICogTGljZW5zZSB1bmRlciBNSVRcbiAqL1xudmFyIGlzQXJyYXkgPSBBcnJheS5pc0FycmF5LCBzZWxlY3RvclRvQW5pbWF0aW9uTWFwID0ge30sIGFuaW1hdGlvbkNhbGxiYWNrcyA9IHt9LCBzdHlsZUVsLCBzdHlsZVNoZWV0LCBjc3NSdWxlcztcbmV4cG9ydCBjbGFzcyBTZW50aW5lbCB7XG4gICAgY29uc3RydWN0b3IoZG9jID0gZG9jdW1lbnQpIHtcbiAgICAgICAgdGhpcy5kb2N1bWVudCA9IGRvYztcbiAgICB9XG4gICAgLyoqXG4gICAgICogQWRkIHdhdGNoZXIuXG4gICAgICogQHBhcmFtIHthcnJheX0gY3NzU2VsZWN0b3JzIC0gTGlzdCBvZiBDU1Mgc2VsZWN0b3Igc3RyaW5nc1xuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uXG4gICAgICovXG4gICAgb24oY3NzU2VsZWN0b3JzLCBjYWxsYmFjaykge1xuICAgICAgICBpZiAoIWNhbGxiYWNrKVxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAvLyBpbml0aWFsaXplIGFuaW1hdGlvbnN0YXJ0IGV2ZW50IGxpc3RlbmVyXG4gICAgICAgIGlmICghc3R5bGVFbCkge1xuICAgICAgICAgICAgdmFyIGRvYyA9IHRoaXMuZG9jdW1lbnQsIGhlYWQgPSBkb2MuaGVhZDtcbiAgICAgICAgICAgIC8vIGFkZCBhbmltYXRpb25zdGFydCBldmVudCBsaXN0ZW5lclxuICAgICAgICAgICAgLy9AdHMtaWdub3JlXG4gICAgICAgICAgICBkb2MuYWRkRXZlbnRMaXN0ZW5lcignYW5pbWF0aW9uc3RhcnQnLCBmdW5jdGlvbiAoZXYsIGNhbGxiYWNrcywgbCwgaSkge1xuICAgICAgICAgICAgICAgIGNhbGxiYWNrcyA9IGFuaW1hdGlvbkNhbGxiYWNrc1tldi5hbmltYXRpb25OYW1lXTtcbiAgICAgICAgICAgICAgICAvLyBleGl0IGlmIGNhbGxiYWNrcyBoYXZlbid0IGJlZW4gcmVnaXN0ZXJlZFxuICAgICAgICAgICAgICAgIGlmICghY2FsbGJhY2tzKVxuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgLy8gc3RvcCBvdGhlciBjYWxsYmFja3MgZnJvbSBmaXJpbmdcbiAgICAgICAgICAgICAgICBldi5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTtcbiAgICAgICAgICAgICAgICAvLyBpdGVyYXRlIHRocm91Z2ggY2FsbGJhY2tzXG4gICAgICAgICAgICAgICAgbCA9IGNhbGxiYWNrcy5sZW5ndGg7XG4gICAgICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IGw7IGkrKylcbiAgICAgICAgICAgICAgICAgICAgY2FsbGJhY2tzW2ldKGV2LnRhcmdldCk7XG4gICAgICAgICAgICB9LCB0cnVlKTtcbiAgICAgICAgICAgIC8vIGFkZCBzdHlsZXNoZWV0IHRvIGRvY3VtZW50XG4gICAgICAgICAgICBzdHlsZUVsID0gZG9jLmNyZWF0ZUVsZW1lbnQoJ3N0eWxlJyk7XG4gICAgICAgICAgICBoZWFkLmluc2VydEJlZm9yZShzdHlsZUVsLCBoZWFkLmZpcnN0Q2hpbGQpO1xuICAgICAgICAgICAgc3R5bGVTaGVldCA9IHN0eWxlRWwuc2hlZXQ7XG4gICAgICAgICAgICBjc3NSdWxlcyA9IHN0eWxlU2hlZXQuY3NzUnVsZXM7XG4gICAgICAgIH1cbiAgICAgICAgLy8gbGlzdGlmeSBhcmd1bWVudCBhbmQgYWRkIGNzcyBydWxlcy8gY2FjaGUgY2FsbGJhY2tzXG4gICAgICAgIChpc0FycmF5KGNzc1NlbGVjdG9ycykgPyBjc3NTZWxlY3RvcnMgOiBbY3NzU2VsZWN0b3JzXSlcbiAgICAgICAgICAgIC5tYXAoZnVuY3Rpb24gKHNlbGVjdG9yLCBhbmltSWQsIGlzQ3VzdG9tTmFtZSkge1xuICAgICAgICAgICAgYW5pbUlkID0gc2VsZWN0b3JUb0FuaW1hdGlvbk1hcFtzZWxlY3Rvcl07XG4gICAgICAgICAgICBpZiAoIWFuaW1JZCkge1xuICAgICAgICAgICAgICAgIC8vQHRzLWlnbm9yZVxuICAgICAgICAgICAgICAgIGlzQ3VzdG9tTmFtZSA9IHNlbGVjdG9yWzBdID09ICchJztcbiAgICAgICAgICAgICAgICAvLyBkZWZpbmUgYW5pbWF0aW9uIG5hbWUgYW5kIGFkZCB0byBtYXBcbiAgICAgICAgICAgICAgICBzZWxlY3RvclRvQW5pbWF0aW9uTWFwW3NlbGVjdG9yXSA9IGFuaW1JZCA9XG4gICAgICAgICAgICAgICAgICAgIGlzQ3VzdG9tTmFtZSA/IHNlbGVjdG9yLnNsaWNlKDEpIDogJ3NlbnRpbmVsLScgK1xuICAgICAgICAgICAgICAgICAgICAgICAgTWF0aC5yYW5kb20oKS50b1N0cmluZygxNikuc2xpY2UoMik7XG4gICAgICAgICAgICAgICAgLy8gYWRkIGtleWZyYW1lIHJ1bGVcbiAgICAgICAgICAgICAgICBjc3NSdWxlc1tzdHlsZVNoZWV0Lmluc2VydFJ1bGUoJ0BrZXlmcmFtZXMgJyArIGFuaW1JZCArXG4gICAgICAgICAgICAgICAgICAgICd7ZnJvbXt0cmFuc2Zvcm06bm9uZTt9dG97dHJhbnNmb3JtOm5vbmU7fX0nLCBjc3NSdWxlcy5sZW5ndGgpXVxuICAgICAgICAgICAgICAgICAgICAuX2lkID0gc2VsZWN0b3I7XG4gICAgICAgICAgICAgICAgLy8gYWRkIHNlbGVjdG9yIGFuaW1hdGlvbiBydWxlXG4gICAgICAgICAgICAgICAgaWYgKCFpc0N1c3RvbU5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgY3NzUnVsZXNbc3R5bGVTaGVldC5pbnNlcnRSdWxlKHNlbGVjdG9yICsgJ3thbmltYXRpb24tZHVyYXRpb246MC4wMDAxczthbmltYXRpb24tbmFtZTonICtcbiAgICAgICAgICAgICAgICAgICAgICAgIGFuaW1JZCArICc7fScsIGNzc1J1bGVzLmxlbmd0aCldXG4gICAgICAgICAgICAgICAgICAgICAgICAuX2lkID0gc2VsZWN0b3I7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIGFkZCB0byBtYXBcbiAgICAgICAgICAgICAgICBzZWxlY3RvclRvQW5pbWF0aW9uTWFwW3NlbGVjdG9yXSA9IGFuaW1JZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIGFkZCB0byBjYWxsYmFja3NcbiAgICAgICAgICAgIChhbmltYXRpb25DYWxsYmFja3NbYW5pbUlkXSA9IGFuaW1hdGlvbkNhbGxiYWNrc1thbmltSWRdIHx8IFtdKVxuICAgICAgICAgICAgICAgIC5wdXNoKGNhbGxiYWNrKTtcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIFJlbW92ZSB3YXRjaGVyLlxuICAgICAqIEBwYXJhbSB7YXJyYXl9IGNzc1NlbGVjdG9ycyAtIExpc3Qgb2YgQ1NTIHNlbGVjdG9yIHN0cmluZ3NcbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiAob3B0aW9uYWwpXG4gICAgICovXG4gICAgb2ZmKGNzc1NlbGVjdG9ycywgY2FsbGJhY2spIHtcbiAgICAgICAgLy8gbGlzdGlmeSBhcmd1bWVudCBhbmQgaXRlcmF0ZSB0aHJvdWdoIHJ1bGVzXG4gICAgICAgIChpc0FycmF5KGNzc1NlbGVjdG9ycykgPyBjc3NTZWxlY3RvcnMgOiBbY3NzU2VsZWN0b3JzXSlcbiAgICAgICAgICAgIC8vQHRzLWlnbm9yZVxuICAgICAgICAgICAgLm1hcChmdW5jdGlvbiAoc2VsZWN0b3IsIGFuaW1JZCwgY2FsbGJhY2tMaXN0LCBpKSB7XG4gICAgICAgICAgICAvLyBnZXQgYW5pbUlkXG4gICAgICAgICAgICBpZiAoIShhbmltSWQgPSBzZWxlY3RvclRvQW5pbWF0aW9uTWFwW3NlbGVjdG9yXSkpXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgLy8gZ2V0IGNhbGxiYWNrc1xuICAgICAgICAgICAgY2FsbGJhY2tMaXN0ID0gYW5pbWF0aW9uQ2FsbGJhY2tzW2FuaW1JZF07XG4gICAgICAgICAgICAvLyByZW1vdmUgY2FsbGJhY2sgZnJvbSBsaXN0XG4gICAgICAgICAgICBpZiAoY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICBpID0gY2FsbGJhY2tMaXN0Lmxlbmd0aDtcbiAgICAgICAgICAgICAgICB3aGlsZSAoaS0tKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChjYWxsYmFja0xpc3RbaV0gPT09IGNhbGxiYWNrKVxuICAgICAgICAgICAgICAgICAgICAgICAgY2FsbGJhY2tMaXN0LnNwbGljZShpLCAxKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBjYWxsYmFja0xpc3QgPSBbXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIGV4aXQgaWYgY2FsbGJhY2tzIHN0aWxsIGV4aXN0XG4gICAgICAgICAgICBpZiAoY2FsbGJhY2tMaXN0Lmxlbmd0aClcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAvLyBjbGVhciBjYWNoZSBhbmQgcmVtb3ZlIGNzcyBydWxlc1xuICAgICAgICAgICAgaSA9IGNzc1J1bGVzLmxlbmd0aDtcbiAgICAgICAgICAgIHdoaWxlIChpLS0pIHtcbiAgICAgICAgICAgICAgICBpZiAoY3NzUnVsZXNbaV0uX2lkID09IHNlbGVjdG9yKVxuICAgICAgICAgICAgICAgICAgICBzdHlsZVNoZWV0LmRlbGV0ZVJ1bGUoaSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBkZWxldGUgc2VsZWN0b3JUb0FuaW1hdGlvbk1hcFtzZWxlY3Rvcl07XG4gICAgICAgICAgICBkZWxldGUgYW5pbWF0aW9uQ2FsbGJhY2tzW2FuaW1JZF07XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBSZXNldCB3YXRjaGVycyBhbmQgY2FjaGVcbiAgICAgKi9cbiAgICByZXNldCgpIHtcbiAgICAgICAgc2VsZWN0b3JUb0FuaW1hdGlvbk1hcCA9IHt9O1xuICAgICAgICBhbmltYXRpb25DYWxsYmFja3MgPSB7fTtcbiAgICAgICAgaWYgKHN0eWxlRWwpXG4gICAgICAgICAgICBzdHlsZUVsLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoc3R5bGVFbCk7XG4gICAgICAgIHN0eWxlRWwgPSAwO1xuICAgIH1cbn1cbiIsIi8qKlxuICogUGFyc2UgdGhlIGJyb3dzZXIgcXVlcnkgc3RyaW5nIG9yIHRoZSBwYXNzZWQgc3RyaW5nIGludG8gYSBqYXZhc2NyaXB0IG9iamVjdFxuICogd2l0aCBrZXlzIHRoZSBxdWVyeSBwYXJhbWV0ZXIgbmFtZXMgYW5kIHZhbHVlcyB0aGUgY29ycmVzcG9uZGluZyB2YWx1ZXMuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHF1ZXJ5U3RyaW5nIC0gdGhlIHF1ZXJ5IHN0cmluZyB0byBwYXJzZSwgd2luZG93LmxvY2F0aW9uLnNlYXJjaCBpZiBub3QgYXZhaWxhYmxlXG4gKiBAcmV0dXJuIHtvYmplY3R9XG4gKi9cbmV4cG9ydCBjb25zdCBwYXJzZVF1ZXJ5U3RyaW5nID0gKHF1ZXJ5U3RyaW5nID0gd2luZG93LmxvY2F0aW9uLnNlYXJjaCkgPT4ge1xuICAgIHJldHVybiBuZXcgVVJMU2VhcmNoUGFyYW1zKHF1ZXJ5U3RyaW5nKTtcbn07XG5leHBvcnQgY29uc3Qgbm9ybWFsaXplUGF0aG5hbWUgPSAocGF0aCkgPT4ge1xuICAgIGlmICghcGF0aC5zdGFydHNXaXRoKFwiL1wiKSlcbiAgICAgICAgcGF0aCA9IFwiL1wiICsgcGF0aDtcbiAgICBpZiAocGF0aC5lbmRzV2l0aChcIi9cIikpXG4gICAgICAgIHBhdGggPSBwYXRoLnN1YnN0cmluZygwLCBwYXRoLmxlbmd0aCAtIDEpO1xuICAgIHJldHVybiBwYXRoO1xufTtcbi8qKlxuICogU29tZSBicm93c2VyIGxpa2UgU2FmYXJpIHByZXZlbnQgYWNjZXNzaW5nIGxvY2FsU3RvcmFnZSBpbiBwcml2YXRlIG1vZGUgYnkgdGhyb3dpbmcgZXhjZXB0aW9ucy5cbiAqIFVzZSB0aGlzIG1ldGhvZCB0byByZXRyaWV2ZSBhIG1vY2sgaW1wbCB3aGljaCB3aWxsIGF0IGxlYXN0IHByZXZlbnQgZXJyb3JzLlxuICovXG5leHBvcnQgY29uc3QgZ2V0TG9jYWxTdG9yYWdlID0gKCkgPT4ge1xuICAgIGlmIChcImxvY2FsU3RvcmFnZVwiIGluIHdpbmRvdykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgbG9jYWxTdG9yYWdlLmdldEl0ZW0oXCJhYmNcIik7IC8vIGFjY2VzcyBsb2NhbFN0b3JhZ2UgdG8gdHJpZ2dlciBpbmNvZ25pdG8gbW9kZSBleGNlcHRpb25zXG4gICAgICAgICAgICByZXR1cm4gbG9jYWxTdG9yYWdlO1xuICAgICAgICB9XG4gICAgICAgIGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGUpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBjb29raWVTdG9yYWdlKDUyNTYwMCwgXCJfX2xvY2FsU3RvcmFnZU1vY2tfX19cIik7XG59O1xuLyoqXG4gKiBVUkwgc2FmZSBiYXNlNjQgZW5jb2RpbmdcbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyIC0gVGhlIHN0cmluZyB0byBiZSBlbmNvZGVkLCBvbmx5IEFTQ0lJL0lTTy04ODU5LTEgc3VwcG9ydGVkXG4gKi9cbmV4cG9ydCBjb25zdCBiYXNlNjRFbmNvZGUgPSAoc3RyKSA9PiB7XG4gICAgLy8gTm90ZSwgKyByZXBsYWNlZCB3aXRoIC0sIC8gcmVwbGFjZWQgd2l0aCBfXG4gICAgY29uc3QgYjY0ID0gXCJBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWmFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6MDEyMzQ1Njc4OS1fPVwiO1xuICAgIGxldCBvMSwgbzIsIG8zLCBiaXRzLCBoMSwgaDIsIGgzLCBoNCwgZSA9IFtdLCBwYWQgPSAnJywgYztcbiAgICBjID0gc3RyLmxlbmd0aCAlIDM7IC8vIHBhZCBzdHJpbmcgdG8gbGVuZ3RoIG9mIG11bHRpcGxlIG9mIDNcbiAgICBpZiAoYyA+IDApIHtcbiAgICAgICAgd2hpbGUgKGMrKyA8IDMpIHtcbiAgICAgICAgICAgIHBhZCArPSAnPSc7XG4gICAgICAgICAgICBzdHIgKz0gJ1xcMCc7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gbm90ZTogZG9pbmcgcGFkZGluZyBoZXJlIHNhdmVzIHVzIGRvaW5nIHNwZWNpYWwtY2FzZSBwYWNraW5nIGZvciB0cmFpbGluZyAxIG9yIDIgY2hhcnNcbiAgICBmb3IgKGMgPSAwOyBjIDwgc3RyLmxlbmd0aDsgYyArPSAzKSB7IC8vIHBhY2sgdGhyZWUgb2N0ZXRzIGludG8gZm91ciBoZXhldHNcbiAgICAgICAgbzEgPSBzdHIuY2hhckNvZGVBdChjKTtcbiAgICAgICAgbzIgPSBzdHIuY2hhckNvZGVBdChjICsgMSk7XG4gICAgICAgIG8zID0gc3RyLmNoYXJDb2RlQXQoYyArIDIpO1xuICAgICAgICBiaXRzID0gbzEgPDwgMTYgfCBvMiA8PCA4IHwgbzM7XG4gICAgICAgIGgxID0gYml0cyA+PiAxOCAmIDB4M2Y7XG4gICAgICAgIGgyID0gYml0cyA+PiAxMiAmIDB4M2Y7XG4gICAgICAgIGgzID0gYml0cyA+PiA2ICYgMHgzZjtcbiAgICAgICAgaDQgPSBiaXRzICYgMHgzZjtcbiAgICAgICAgLy8gdXNlIGhleHRldHMgdG8gaW5kZXggaW50byBjb2RlIHN0cmluZ1xuICAgICAgICBlW2MgLyAzXSA9IGI2NC5jaGFyQXQoaDEpICsgYjY0LmNoYXJBdChoMikgKyBiNjQuY2hhckF0KGgzKSArIGI2NC5jaGFyQXQoaDQpO1xuICAgIH1cbiAgICBzdHIgPSBlLmpvaW4oJycpOyAvLyB1c2UgQXJyYXkuam9pbigpIGZvciBiZXR0ZXIgcGVyZm9ybWFuY2UgdGhhbiByZXBlYXRlZCBzdHJpbmcgYXBwZW5kc1xuICAgIC8vIHJlcGxhY2UgJ0EncyBmcm9tIHBhZGRlZCBudWxscyB3aXRoICc9J3NcbiAgICBzdHIgPSBzdHIuc2xpY2UoMCwgc3RyLmxlbmd0aCAtIHBhZC5sZW5ndGgpICsgcGFkO1xuICAgIHJldHVybiBzdHI7XG59O1xuZXhwb3J0IGNvbnN0IGdlbmVyYXRlSWQgPSAoKSA9PiB7XG4gICAgY29uc3QgcG9zc2libGUgPSBcIkFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5XCI7XG4gICAgbGV0IHRleHQgPSBcIlwiO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgNzsgaSsrKSB7XG4gICAgICAgIHRleHQgKz0gcG9zc2libGUuY2hhckF0KE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIHBvc3NpYmxlLmxlbmd0aCkpO1xuICAgIH1cbiAgICByZXR1cm4gdGV4dDtcbn07XG5leHBvcnQgY29uc3QgZ2V0U2Vzc2lvblN0b3JhZ2UgPSAoKSA9PiB7XG4gICAgaWYgKFwic2Vzc2lvblN0b3JhZ2VcIiBpbiB3aW5kb3cpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHNlc3Npb25TdG9yYWdlLmdldEl0ZW0oXCJhYmNcIik7IC8vIGFjY2VzcyBzZXNzaW9uU3RvcmFnZSB0byB0cmlnZ2VyIGluY29nbml0byBtb2RlIGV4Y2VwdGlvbnNcbiAgICAgICAgICAgIHJldHVybiBzZXNzaW9uU3RvcmFnZTtcbiAgICAgICAgfVxuICAgICAgICBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcihlKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gY29va2llU3RvcmFnZSh2b2lkIDAsIFwiX19zZXNzaW9uU3RvcmFnZU1vY2tfX19cIik7XG59O1xuZnVuY3Rpb24gY29va2llU3RvcmFnZSh0dGxNaW51dGVzLCBzdG9yYWdlTmFtZSkge1xuICAgIGNvbnN0IExPQ0FMX1NUT1JBR0VfQ09PS0lFX05BTUUgPSBzdG9yYWdlTmFtZTtcbiAgICBmdW5jdGlvbiBnZXRTdG9yYWdlRnJvbUNvb2tpZSgpIHtcbiAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UoZ2V0Q29va2llKExPQ0FMX1NUT1JBR0VfQ09PS0lFX05BTUUpIHx8IFwie31cIik7XG4gICAgfVxuICAgIGZ1bmN0aW9uIHNhdmVTdG9yYWdlVG9Db29raWUoZGF0YSkge1xuICAgICAgICBzZXRDb29raWUoTE9DQUxfU1RPUkFHRV9DT09LSUVfTkFNRSwgZGF0YSwgdHRsTWludXRlcyk7IC8vIG9uZSB5ZWFyXG4gICAgfVxuICAgIHJldHVybiB7XG4gICAgICAgIGdldEl0ZW0oa2V5KSB7XG4gICAgICAgICAgICByZXR1cm4gZ2V0U3RvcmFnZUZyb21Db29raWUoKVtrZXldIHx8IG51bGw7XG4gICAgICAgIH0sXG4gICAgICAgIHNldEl0ZW0oa2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgY29uc3QgbG9jYWxTdG9yYWdlU3RhdGUgPSBnZXRTdG9yYWdlRnJvbUNvb2tpZSgpO1xuICAgICAgICAgICAgbG9jYWxTdG9yYWdlU3RhdGVba2V5XSA9IHZhbHVlO1xuICAgICAgICAgICAgc2F2ZVN0b3JhZ2VUb0Nvb2tpZShKU09OLnN0cmluZ2lmeShsb2NhbFN0b3JhZ2VTdGF0ZSkpO1xuICAgICAgICB9LFxuICAgICAgICByZW1vdmVJdGVtKGtleSkge1xuICAgICAgICAgICAgY29uc3QgbG9jYWxTdG9yYWdlU3RhdGUgPSBnZXRTdG9yYWdlRnJvbUNvb2tpZSgpO1xuICAgICAgICAgICAgZGVsZXRlIGxvY2FsU3RvcmFnZVN0YXRlW2tleV07XG4gICAgICAgICAgICBzYXZlU3RvcmFnZVRvQ29va2llKEpTT04uc3RyaW5naWZ5KGxvY2FsU3RvcmFnZVN0YXRlKSk7XG4gICAgICAgIH0sXG4gICAgICAgIGNsZWFyKCkge1xuICAgICAgICAgICAgY29uc3QgbG9jYWxTdG9yYWdlU3RhdGUgPSB7fTtcbiAgICAgICAgICAgIHNhdmVTdG9yYWdlVG9Db29raWUoSlNPTi5zdHJpbmdpZnkobG9jYWxTdG9yYWdlU3RhdGUpKTtcbiAgICAgICAgfSxcbiAgICAgICAga2V5KG4pIHtcbiAgICAgICAgICAgIGNvbnN0IGxvY2FsU3RvcmFnZVN0YXRlID0gZ2V0U3RvcmFnZUZyb21Db29raWUoKTtcbiAgICAgICAgICAgIGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyhsb2NhbFN0b3JhZ2VTdGF0ZSk7XG4gICAgICAgICAgICBpZiAobiA+IGtleXMubGVuZ3RoIC0gMSlcbiAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgICAgIHJldHVybiBrZXlzW25dO1xuICAgICAgICB9LFxuICAgICAgICBnZXQgbGVuZ3RoKCkge1xuICAgICAgICAgICAgY29uc3QgbG9jYWxTdG9yYWdlU3RhdGUgPSBnZXRTdG9yYWdlRnJvbUNvb2tpZSgpO1xuICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5rZXlzKGxvY2FsU3RvcmFnZVN0YXRlKS5sZW5ndGg7XG4gICAgICAgIH1cbiAgICB9O1xufVxuZXhwb3J0IGNvbnN0IHNldENvb2tpZSA9IChuYW1lLCB2YWx1ZSwgdHRsTWludXRlcykgPT4ge1xuICAgIGxldCBleHBpcmVzID0gXCJcIjtcbiAgICBpZiAodHRsTWludXRlcykge1xuICAgICAgICBjb25zdCBkYXRlID0gbmV3IERhdGUoKTtcbiAgICAgICAgZGF0ZS5zZXRUaW1lKGRhdGUuZ2V0VGltZSgpICsgKHR0bE1pbnV0ZXMgKiA2MCAqIDEwMDApKTtcbiAgICAgICAgZXhwaXJlcyA9IFwiOyBleHBpcmVzPVwiICsgZGF0ZS50b1VUQ1N0cmluZygpO1xuICAgIH1cbiAgICAvLyBIYW5kbGUgdGhlIHVwY29taW5nIGZvcmNlZCBzd2l0Y2ggdG8gU2FtZVNpdGUgJiBTZWN1cmUgcGFyYW1zIGh0dHBzOi8vd3d3LmNocm9tZXN0YXR1cy5jb20vZmVhdHVyZS81NjMzNTIxNjIyMTg4MDMyXG4gICAgLy8gU2luY2UgdGhpcyBpcyBhIGdlbmVyaWMgbGlicmFyeSwgd2UgY2FuJ3QgcmVzdHJpY3QgdGhlIGRvbWFpbiB1bmRlciB3aGljaCBpdCdzIGJlZWluZyBzZXJ2ZWQsIHRodXMgbm90IHNldHRpbmcgZG9tYWluXG4gICAgLy8gZm9yIHRoZSBjb29raWUuIEl0J3MgdXN1YWxseSBsb2FkZWQgYW5kIHN1YnNlcXVlbnRseSByZXF1ZXN0ZWQgZnJvbSBhIHRoaXJkLXBhcnR5IGRvbWFpbiwgdGh1cyB3ZSBuZWVkIHRvIHNwZWNpZnkgU2FtZVNpdGU9Tm9uZSB3aGljaFxuICAgIC8vIHBlciB0aGUgbGF0ZXN0IHNwZWNpZmljYXRpb25zIHJlcXVpcmVzIHRoZSBTZWN1cmUgYXR0cmlidXRlLlxuICAgIC8vXG4gICAgLy8gVG8gYWxsb3cgbG9jYWwgZGVidWdnaW5nLCB3ZSB3b24ndCBzZXQgdGhlc2Ugd2hlbiBsb2FkZWQgb24gbG9jYWxob3N0LiBOb3RlLCBhZnRlciB0aGlzIGNoYW5nZSwgeW91IHdvbid0IGJlIGFibGUgdG8gc2VydmVcbiAgICAvLyB0aGUgY29sbGVjdG9yIHRvIHJlYWwgY2xpZW50cyBvdmVyIG5vbi1odHRwcyBjb25uZWN0aW9ucyAtIHRoZSBzZXNzaW9uIGNvb2tpZXMgd29uJ3QgbWF0Y2hcbiAgICBjb25zdCBzYW1lU2l0ZSA9IHdpbmRvdy5sb2NhdGlvbi5ob3N0bmFtZSA9PT0gXCJsb2NhbGhvc3RcIiA/IFwiXCIgOiBcIjsgU2FtZVNpdGU9Tm9uZTsgU2VjdXJlXCI7XG4gICAgZG9jdW1lbnQuY29va2llID0gbmFtZSArIFwiPVwiICsgKHZhbHVlIHx8IFwiXCIpICsgZXhwaXJlcyArIFwiOyBwYXRoPS9cIiArIHNhbWVTaXRlO1xuICAgIHJldHVybiB2YWx1ZTtcbn07XG5leHBvcnQgY29uc3QgZ2V0Q29va2llID0gKGNuYW1lKSA9PiB7XG4gICAgY29uc3QgbmFtZSA9IGNuYW1lICsgXCI9XCI7XG4gICAgY29uc3QgZGVjb2RlZENvb2tpZSA9IGRlY29kZVVSSUNvbXBvbmVudChkb2N1bWVudC5jb29raWUpO1xuICAgIGNvbnN0IGNhID0gZGVjb2RlZENvb2tpZS5zcGxpdCgnOycpO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY2EubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgbGV0IGMgPSBjYVtpXTtcbiAgICAgICAgd2hpbGUgKGMuY2hhckF0KDApID09ICcgJykge1xuICAgICAgICAgICAgYyA9IGMuc3Vic3RyaW5nKDEpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChjLmluZGV4T2YobmFtZSkgPT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIGMuc3Vic3RyaW5nKG5hbWUubGVuZ3RoLCBjLmxlbmd0aCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIFwiXCI7XG59O1xuLyoqXG4gKiBSZXR1cm5zIGEgZnVuY3Rpb24sIHRoYXQsIGFzIGxvbmcgYXMgaXQgY29udGludWVzIHRvIGJlIGludm9rZWQsIHdpbGwgbm90XG4gKiBiZSB0cmlnZ2VyZWQuIFRoZSBmdW5jdGlvbiB3aWxsIGJlIGNhbGxlZCBhZnRlciBpdCBzdG9wcyBiZWluZyBjYWxsZWQgZm9yXG4gKiBOIG1pbGxpc2Vjb25kcy4gSWYgYGltbWVkaWF0ZWAgaXMgcGFzc2VkLCB0cmlnZ2VyIHRoZSBmdW5jdGlvbiBvbiB0aGVcbiAqIGxlYWRpbmcgZWRnZSwgaW5zdGVhZCBvZiB0aGUgdHJhaWxpbmcuIFRoZSBmdW5jdGlvbiBhbHNvIGhhcyBhIHByb3BlcnR5ICdjbGVhcidcbiAqIHRoYXQgaXMgYSBmdW5jdGlvbiB3aGljaCB3aWxsIGNsZWFyIHRoZSB0aW1lciB0byBwcmV2ZW50IHByZXZpb3VzbHkgc2NoZWR1bGVkIGV4ZWN1dGlvbnMuXG4gKlxuICogQHNvdXJjZSB1bmRlcnNjb3JlLmpzXG4gKiBAc2VlIGh0dHA6Ly91bnNjcmlwdGFibGUuY29tLzIwMDkvMDMvMjAvZGVib3VuY2luZy1qYXZhc2NyaXB0LW1ldGhvZHMvXG4gKiBAcGFyYW0gZnVuYyB7RnVuY3Rpb259IGZ1bmN0aW9uIHRvIHdyYXBcbiAqIEBwYXJhbSB3YWl0IHtOdW1iZXJ9IHRpbWVvdXQgaW4gbXMgKGAxMDBgKVxuICogQHBhcmFtIGltbWVkaWF0ZSB7Qm9vbGVhbn0gd2hldGhlciB0byBleGVjdXRlIGF0IHRoZSBiZWdpbm5pbmcgKGBmYWxzZWApXG4gKiBAYXBpIHB1YmxpY1xuICovXG5leHBvcnQgY29uc3QgZGVib3VuY2UgPSAoZnVuYywgd2FpdCA9IDEwMCwgaW1tZWRpYXRlID0gZmFsc2UpID0+IHtcbiAgICB2YXIgdGltZW91dCwgYXJncywgY29udGV4dCwgdGltZXN0YW1wLCByZXN1bHQ7XG4gICAgZnVuY3Rpb24gbGF0ZXIoKSB7XG4gICAgICAgIHZhciBsYXN0ID0gRGF0ZS5ub3coKSAtIHRpbWVzdGFtcDtcbiAgICAgICAgaWYgKGxhc3QgPCB3YWl0ICYmIGxhc3QgPj0gMCkge1xuICAgICAgICAgICAgdGltZW91dCA9IHNldFRpbWVvdXQobGF0ZXIsIHdhaXQgLSBsYXN0KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRpbWVvdXQgPSBudWxsO1xuICAgICAgICAgICAgaWYgKCFpbW1lZGlhdGUpIHtcbiAgICAgICAgICAgICAgICByZXN1bHQgPSBmdW5jLmFwcGx5KGNvbnRleHQsIGFyZ3MpO1xuICAgICAgICAgICAgICAgIGNvbnRleHQgPSBhcmdzID0gbnVsbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICBjb25zdCBkZWJvdW5jZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnRleHQgPSB0aGlzO1xuICAgICAgICBhcmdzID0gYXJndW1lbnRzO1xuICAgICAgICB0aW1lc3RhbXAgPSBEYXRlLm5vdygpO1xuICAgICAgICB2YXIgY2FsbE5vdyA9IGltbWVkaWF0ZSAmJiAhdGltZW91dDtcbiAgICAgICAgaWYgKCF0aW1lb3V0KVxuICAgICAgICAgICAgdGltZW91dCA9IHNldFRpbWVvdXQobGF0ZXIsIHdhaXQpO1xuICAgICAgICBpZiAoY2FsbE5vdykge1xuICAgICAgICAgICAgcmVzdWx0ID0gZnVuYy5hcHBseShjb250ZXh0LCBhcmdzKTtcbiAgICAgICAgICAgIGNvbnRleHQgPSBhcmdzID0gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH07XG4gICAgZGVib3VuY2VkLmNsZWFyID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodGltZW91dCkge1xuICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgICAgICAgICAgdGltZW91dCA9IG51bGw7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIGRlYm91bmNlZC5mbHVzaCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHRpbWVvdXQpIHtcbiAgICAgICAgICAgIHJlc3VsdCA9IGZ1bmMuYXBwbHkoY29udGV4dCwgYXJncyk7XG4gICAgICAgICAgICBjb250ZXh0ID0gYXJncyA9IG51bGw7XG4gICAgICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dCk7XG4gICAgICAgICAgICB0aW1lb3V0ID0gbnVsbDtcbiAgICAgICAgfVxuICAgIH07XG4gICAgcmV0dXJuIGRlYm91bmNlZDtcbn07XG4iLCJleHBvcnQgKiBmcm9tIFwiLi9Db250ZXh0XCI7XG5leHBvcnQgKiBmcm9tIFwiLi9MaXN0ZW5lclR5cGVcIjtcbmV4cG9ydCAqIGZyb20gXCIuL0xvY2FsU3RvcmFnZVF1ZXVlXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9TZW50aW5lbFwiO1xuZXhwb3J0ICogZnJvbSBcIi4vVXRpbFwiO1xuIiwiaW1wb3J0IHsgYmFzZTY0RW5jb2RlIH0gZnJvbSBcIi4uL3V0aWxzXCI7XG5leHBvcnQgY2xhc3MgQmFzZTY0RW5jb2RlV3JpdGVyIHtcbiAgICBjb25zdHJ1Y3RvcihkZWxlZ2F0ZSkge1xuICAgICAgICB0aGlzLmRlbGVnYXRlID0gZGVsZWdhdGU7XG4gICAgfVxuICAgIHdyaXRlKGRhdGEpIHtcbiAgICAgICAgY29uc3QgZCA9IEpTT04uc3RyaW5naWZ5KGRhdGEpO1xuICAgICAgICB0aGlzLmRlbGVnYXRlLndyaXRlKGJhc2U2NEVuY29kZShlbmNvZGVVUklDb21wb25lbnQoZCkpKTtcbiAgICB9XG59XG4iLCJleHBvcnQgY2xhc3MgQnJvd3NlclRyYWNraW5nV3JpdGVyIHtcbiAgICBjb25zdHJ1Y3RvcihkZWxlZ2F0ZSwgb3B0aW9ucykge1xuICAgICAgICB0aGlzLmRlbGVnYXRlID0gZGVsZWdhdGU7XG4gICAgICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgfVxuICAgIHdyaXRlKGRhdGEpIHtcbiAgICAgICAgY29uc3QgeyByZWNvcmRVcmwsIHJlY29yZFJlZmVycmVyLCByZWNvcmRMYW5ndWFnZSB9ID0gdGhpcy5vcHRpb25zO1xuICAgICAgICBpZiAocmVjb3JkVXJsICYmICFkYXRhLnVybClcbiAgICAgICAgICAgIGRhdGEudXJsID0gdGhpcy5nZXRXaW5kb3coKS5sb2NhdGlvbi5ocmVmO1xuICAgICAgICBpZiAocmVjb3JkUmVmZXJyZXIgJiYgIWRhdGEucmVmKVxuICAgICAgICAgICAgZGF0YS5yZWYgPSB0aGlzLmdldERvY3VtZW50KCkucmVmZXJyZXI7XG4gICAgICAgIGlmIChyZWNvcmRMYW5ndWFnZSAmJiAhZGF0YS5sYW5nKVxuICAgICAgICAgICAgZGF0YS5sYW5nID0gdGhpcy5nZXRXaW5kb3coKS5uYXZpZ2F0b3IubGFuZ3VhZ2U7XG4gICAgICAgIHRoaXMuZGVsZWdhdGUud3JpdGUoZGF0YSk7XG4gICAgfVxuICAgIGdldERvY3VtZW50KCkge1xuICAgICAgICBjb25zdCB7IGNvbnRleHQgfSA9IHRoaXMub3B0aW9ucztcbiAgICAgICAgcmV0dXJuIGNvbnRleHQgPyBjb250ZXh0LmdldERvY3VtZW50KCkgOiBkb2N1bWVudDtcbiAgICB9XG4gICAgZ2V0V2luZG93KCkge1xuICAgICAgICBjb25zdCB7IGNvbnRleHQgfSA9IHRoaXMub3B0aW9ucztcbiAgICAgICAgcmV0dXJuIGNvbnRleHQgPyBjb250ZXh0LmdldFdpbmRvdygpIDogd2luZG93O1xuICAgIH1cbn1cbiIsImltcG9ydCB7IExvY2FsU3RvcmFnZVF1ZXVlIH0gZnJvbSBcIi4uL3V0aWxzL0xvY2FsU3RvcmFnZVF1ZXVlXCI7XG4vKipcbiAqIEEgd3JpdGVyIHRoYXQgYnVmZmVycyB0aGUgaW5jb21pbmcgZXZlbnRzIGluIGEgbG9jYWwgc3RvcmFnZSBxdWV1ZSBhbmQgd3JpdGVzXG4gKiB0aGVtIG91dCBpbiBiYXRjaGVzIGV2ZXJ5IHNlY29uZC4gSWYgdGhlIHF1ZXVlIGlzIG5vdCBlbXB0eSwgd2hlbiB0aGUgdGltZXIgdGlja3NcbiAqIHRoZSB3cml0ZXIgd2lsbCBzZW5kIHRoZSBhdmFpbGFibGUgZGF0YSByZWdhcmRsZXNzIG9mIHdoZXRoZXIgdGhlcmUgYXJlIGNvbGxlY3RvciBldmVudHMgaS5lLlxuICogZXZlbiBpbiB0aW1lcyBvZiBpbmFjdGl2aXR5IG9yIHdoZW4gbG9hZGluZyB0aGUgcGFnZSBhbmQgcHJldmlvdXMgc3RhdGUgaXMgYXZhaWxhYmxlLlxuICpcbiAqIFRoZSB3cml0ZXIgd2lsbCBhbHNvIHRyeSB0byBzZW5kIHRoZSBhdmFpbGFibGUgZGF0YSBvbiBicm93c2VyIHVubG9hZCBldmVudC5cbiAqL1xuZXhwb3J0IGNsYXNzIEJ1ZmZlcmluZ1dyaXRlciB7XG4gICAgY29uc3RydWN0b3IoZGVsZWdhdGUsIGlkLCB0aW1lck1zID0gMTAwMCkge1xuICAgICAgICB0aGlzLmRlbGVnYXRlID0gZGVsZWdhdGU7XG4gICAgICAgIHRoaXMucXVldWUgPSBuZXcgTG9jYWxTdG9yYWdlUXVldWUoaWQpO1xuICAgICAgICB0aGlzLnRpbWVyTXMgPSB0aW1lck1zO1xuICAgICAgICB0aGlzLnRpbWVyID0gc2V0VGltZW91dCh0aGlzLmZsdXNoLmJpbmQodGhpcyksIHRpbWVyTXMpO1xuICAgICAgICB0aGlzLmlkID0gaWQ7XG4gICAgfVxuICAgIHdyaXRlKGRhdGEpIHtcbiAgICAgICAgdGhpcy5xdWV1ZS5wdXNoKGRhdGEpO1xuICAgIH1cbiAgICBmbHVzaChjYW5jZWxUaW1lcikge1xuICAgICAgICBpZiAodGhpcy5xdWV1ZS5zaXplKCkgPiAwKSB7XG4gICAgICAgICAgICAvLyBpZiB0aGUgYnJvd3NlciBzaHV0c2Rvd24gYmVmb3JlIHRoZSB3cml0ZSBpcyBjb21wbGV0ZVxuICAgICAgICAgICAgdGhpcy5xdWV1ZS50cmFuc2FjdGlvbmFsRHJhaW4ocXVldWUgPT4gbmV3IFByb21pc2UocmVzID0+IHJlcyh0aGlzLmRlbGVnYXRlLndyaXRlKHF1ZXVlKSkpKVxuICAgICAgICAgICAgICAgIC5jYXRjaChlcnIgPT4gY29uc29sZS5lcnJvcihcImNvdWxkIG5vdCBkcmFpbiBxdWV1ZTogXCIsIGVycikpO1xuICAgICAgICB9XG4gICAgICAgIGlmICghY2FuY2VsVGltZXIpIHtcbiAgICAgICAgICAgIHRoaXMudGltZXIgPSBzZXRUaW1lb3V0KHRoaXMuZmx1c2guYmluZCh0aGlzKSwgdGhpcy50aW1lck1zKTtcbiAgICAgICAgfVxuICAgIH1cbn1cbiIsImV4cG9ydCBjbGFzcyBDb25zb2xlV3JpdGVyIHtcbiAgICB3cml0ZShkYXRhKSB7XG4gICAgICAgIGNvbnNvbGUuZGVidWcoXCJDb25zb2xlV3JpdGVyIHJlY2VpdmluZyBuZXcgZGF0YTogXCIpO1xuICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICB9XG59XG4iLCIvKipcbiAqIExvZ3MgdGhlIGRhdGEgdG8gdGhlIGJyb3dzZXIgY29uc29sZSB1c2luZyBjb25zb2xlLmRlYnVnXG4gKi9cbmV4cG9ydCBjbGFzcyBEZWJ1Z1dyaXRlciB7XG4gICAgY29uc3RydWN0b3IoZGVsZWdhdGUsIGRlYnVnKSB7XG4gICAgICAgIHRoaXMuZGVsZWdhdGUgPSBkZWxlZ2F0ZTtcbiAgICAgICAgdGhpcy5kZWJ1ZyA9IGRlYnVnO1xuICAgIH1cbiAgICB3cml0ZShkYXRhKSB7XG4gICAgICAgIGlmICh0aGlzLmRlYnVnKVxuICAgICAgICAgICAgY29uc29sZS5sb2coZGF0YSk7XG4gICAgICAgIHRoaXMuZGVsZWdhdGUud3JpdGUoZGF0YSk7XG4gICAgfVxufVxuIiwiaW1wb3J0IHsgU1FTRXZlbnRXcml0ZXIgfSBmcm9tIFwiLi9TUVNFdmVudFdyaXRlclwiO1xuaW1wb3J0IHsgUmVzdEV2ZW50V3JpdGVyIH0gZnJvbSBcIi4vUmVzdEV2ZW50V3JpdGVyXCI7XG5pbXBvcnQgeyBCdWZmZXJpbmdXcml0ZXIgfSBmcm9tIFwiLi9CdWZmZXJpbmdXcml0ZXJcIjtcbmltcG9ydCB7IEJhc2U2NEVuY29kZVdyaXRlciB9IGZyb20gXCIuL0Jhc2U2NEVuY29kZVdyaXRlclwiO1xuaW1wb3J0IHsgSlNPTkVudmVsb3BlV3JpdGVyIH0gZnJvbSBcIi4vSlNPTkVudmVsb3BlV3JpdGVyXCI7XG5pbXBvcnQgeyBUcmFpbFdyaXRlciB9IGZyb20gXCIuL1RyYWlsV3JpdGVyXCI7XG5pbXBvcnQgeyBCcm93c2VyVHJhY2tpbmdXcml0ZXIgfSBmcm9tIFwiLi9Ccm93c2VyVHJhY2tpbmdXcml0ZXJcIjtcbmltcG9ydCB7IERlYnVnV3JpdGVyIH0gZnJvbSBcIi4vRGVidWdXcml0ZXJcIjtcbmltcG9ydCB7IFF1ZXJ5V3JpdGVyIH0gZnJvbSBcIi4vUXVlcnlXcml0ZXJcIjtcbmltcG9ydCB7IFRyYWlsIH0gZnJvbSBcIi4uL3F1ZXJ5L1RyYWlsXCI7XG5leHBvcnQgY2xhc3MgRGVmYXVsdFdyaXRlciB7XG4gICAgY29uc3RydWN0b3Iob3B0aW9ucykge1xuICAgICAgICBjb25zdCB7IGVuZHBvaW50LCBzcXMgfSA9IG9wdGlvbnM7XG4gICAgICAgIC8vIFdyaXRlciBwaXBlbGluZSwgYWRkL3JlbW92ZSBwaWVjZXMgYWNjb3JkaW5nIHRvIHVzZSBjYXNlXG4gICAgICAgIC8vIFRoaXMgd3JpdGVyIHBpcGVsaW5lIHdpbGwgc2VuZCBCYXNlNjQgZW5jb2RlZCBhcnJheSBvZiBqc29uIGV2ZW50c1xuICAgICAgICBsZXQgd3JpdGVyID0gaXNTUVMoZW5kcG9pbnQsIHNxcykgPyBuZXcgU1FTRXZlbnRXcml0ZXIoZW5kcG9pbnQpIDogbmV3IFJlc3RFdmVudFdyaXRlcihlbmRwb2ludCk7XG4gICAgICAgIHdyaXRlciA9IG5ldyBCYXNlNjRFbmNvZGVXcml0ZXIod3JpdGVyKTtcbiAgICAgICAgd3JpdGVyID0gbmV3IEJ1ZmZlcmluZ1dyaXRlcih3cml0ZXIsIFwiYnVmZmVyOlwiICsgb3B0aW9ucy5lbmRwb2ludCk7XG4gICAgICAgIHdyaXRlciA9IG5ldyBEZWJ1Z1dyaXRlcih3cml0ZXIsIG9wdGlvbnMuZGVidWcpO1xuICAgICAgICB3cml0ZXIgPSBuZXcgUXVlcnlXcml0ZXIod3JpdGVyLCBvcHRpb25zLnJlc29sdmVyLnF1ZXJ5UmVzb2x2ZXIpO1xuICAgICAgICB3cml0ZXIgPSBuZXcgVHJhaWxXcml0ZXIod3JpdGVyLCBvcHRpb25zLnRyYWlsIHx8IG5ldyBUcmFpbChvcHRpb25zLnJlc29sdmVyLnF1ZXJ5UmVzb2x2ZXIsIG9wdGlvbnMucmVzb2x2ZXIuc2Vzc2lvblJlc29sdmVyKSwgb3B0aW9ucy5yZXNvbHZlci5xdWVyeVJlc29sdmVyKTtcbiAgICAgICAgd3JpdGVyID0gbmV3IEpTT05FbnZlbG9wZVdyaXRlcih3cml0ZXIsIG9wdGlvbnMucmVzb2x2ZXIuc2Vzc2lvblJlc29sdmVyLCBvcHRpb25zLmNoYW5uZWwpO1xuICAgICAgICB3cml0ZXIgPSBuZXcgQnJvd3NlclRyYWNraW5nV3JpdGVyKHdyaXRlciwge1xuICAgICAgICAgICAgcmVjb3JkUmVmZXJyZXI6IG9wdGlvbnMucmVjb3JkUmVmZXJyZXIsXG4gICAgICAgICAgICByZWNvcmRVcmw6IG9wdGlvbnMucmVjb3JkVXJsLFxuICAgICAgICAgICAgcmVjb3JkTGFuZ3VhZ2U6IG9wdGlvbnMucmVjb3JkTGFuZ3VhZ2VcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMud3JpdGVyID0gd3JpdGVyO1xuICAgIH1cbiAgICB3cml0ZShkYXRhKSB7XG4gICAgICAgIHRoaXMud3JpdGVyLndyaXRlKGRhdGEpO1xuICAgIH1cbn1cbmZ1bmN0aW9uIGlzU1FTKGVuZHBvaW50LCBmb3JjZVNRUykge1xuICAgIHJldHVybiBmb3JjZVNRUyB8fCAoZW5kcG9pbnQuaW5kZXhPZihcInNxc1wiKSAhPSAtMSAmJiBlbmRwb2ludC5pbmRleE9mKFwiYW1hem9uYXdzLmNvbVwiKSAhPSAtMSk7XG59XG4iLCIvKipcbiAqIFdyYXAgdGhlIGV2ZW50cyBpbiBhIEpTT04gZW52ZWxvcGUsIGVucmljaCBlYWNoIHJlY29yZCB3aXRoIHRpbWVzdGFtcCwgc2Vzc2lvbiBhbmQgY2hhbm5lbCBpbmZvcm1hdGlvbi5cbiAqL1xuZXhwb3J0IGNsYXNzIEpTT05FbnZlbG9wZVdyaXRlciB7XG4gICAgY29uc3RydWN0b3IoZGVsZWdhdGUsIHNlc3Npb25SZXNvbHZlciwgY2hhbm5lbCkge1xuICAgICAgICB0aGlzLmRlbGVnYXRlID0gZGVsZWdhdGU7XG4gICAgICAgIHRoaXMuc2Vzc2lvblJlc29sdmVyID0gc2Vzc2lvblJlc29sdmVyO1xuICAgICAgICB0aGlzLmNoYW5uZWwgPSBjaGFubmVsO1xuICAgIH1cbiAgICB3cml0ZShkYXRhKSB7XG4gICAgICAgIGlmICghZGF0YS50aW1lc3RhbXApXG4gICAgICAgICAgICBkYXRhLnRpbWVzdGFtcCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuICAgICAgICBkYXRhLnNlc3Npb24gPSB0aGlzLnNlc3Npb25SZXNvbHZlcigpO1xuICAgICAgICBkYXRhLmNoYW5uZWwgPSB0aGlzLmNoYW5uZWw7XG4gICAgICAgIHRoaXMuZGVsZWdhdGUud3JpdGUoZGF0YSk7XG4gICAgfVxufVxuIiwiLyoqXG4gKiBBcHBlbmRzIHRoZSBxdWVyeSB0byB0aGUgZGF0YSBpZiBubyBxdWVyeSBwcm9wZXJ0eSBleGlzdHNcbiAqL1xuZXhwb3J0IGNsYXNzIFF1ZXJ5V3JpdGVyIHtcbiAgICBjb25zdHJ1Y3RvcihkZWxlZ2F0ZSwgcXVlcnlSZXNvbHZlcikge1xuICAgICAgICB0aGlzLmRlbGVnYXRlID0gZGVsZWdhdGU7XG4gICAgICAgIHRoaXMucXVlcnlSZXNvbHZlciA9IHF1ZXJ5UmVzb2x2ZXI7XG4gICAgfVxuICAgIHdyaXRlKGRhdGEpIHtcbiAgICAgICAgaWYgKCFkYXRhLnF1ZXJ5KVxuICAgICAgICAgICAgZGF0YS5xdWVyeSA9IHRoaXMucXVlcnlSZXNvbHZlcigpLnRvU3RyaW5nKCk7XG4gICAgICAgIHRoaXMuZGVsZWdhdGUud3JpdGUoZGF0YSk7XG4gICAgfVxufVxuIiwiLyoqXG4gKiBTdHJhaWdodC1mb3J3YXJkIFJFU1Qgd3JpdGUgdmlhIEdFVCByZXF1ZXN0XG4gKi9cbmV4cG9ydCBjbGFzcyBSZXN0RXZlbnRXcml0ZXIge1xuICAgIGNvbnN0cnVjdG9yKGVuZHBvaW50KSB7XG4gICAgICAgIHRoaXMuZW5kcG9pbnQgPSBlbmRwb2ludDtcbiAgICB9XG4gICAgd3JpdGUoZGF0YSkge1xuICAgICAgICBjb25zdCBpbWcgPSBuZXcgSW1hZ2UoKTtcbiAgICAgICAgaW1nLnNyYyA9IHRoaXMuZW5kcG9pbnQgKyBcIj9kYXRhPVwiICsgSlNPTi5zdHJpbmdpZnkoZGF0YSk7XG4gICAgfVxufVxuIiwiZXhwb3J0IGNsYXNzIFNRU0V2ZW50V3JpdGVyIHtcbiAgICBjb25zdHJ1Y3RvcihxdWV1ZSwgZmlmbyA9IGZhbHNlKSB7XG4gICAgICAgIHRoaXMucXVldWUgPSBxdWV1ZTtcbiAgICAgICAgdGhpcy5maWZvID0gZmlmbztcbiAgICB9XG4gICAgd3JpdGUoZGF0YSkge1xuICAgICAgICBjb25zdCBpbWcgPSBuZXcgSW1hZ2UoKTtcbiAgICAgICAgbGV0IHNyYyA9IHRoaXMucXVldWUgKyBcIj9WZXJzaW9uPTIwMTItMTEtMDUmQWN0aW9uPVNlbmRNZXNzYWdlXCI7XG4gICAgICAgIC8vIFNRUyBzdXBwb3J0cyBGSUZPIHF1ZXVlcyBpbiBzb21lIHJlZ2lvbnMgdGhhdCBjYW4gYWxzbyBndWFyYW50ZWUgdGhlIG9yZGVyXG4gICAgICAgIC8vIG9mIHRoZSBtZXNzYWdlcy5cbiAgICAgICAgaWYgKHRoaXMuZmlmbykge1xuICAgICAgICAgICAgLy8gVE9ETyB3aGVuIGVub3VnaCBpbmZvcm1hdGlvbiBpcyBwcmVzZW50IHRvIHVuaXF1ZWx5IGlkZW50aWZ5IGEgbWVzc2FnZSwgc3dpdGNoIHRoZSBkZWR1cGxpY2F0aW9uIGlkIHRvIGEgbWVzc2FnZSBoYXNoXG4gICAgICAgICAgICBzcmMgKz0gXCImTWVzc2FnZUdyb3VwSWQ9MSZNZXNzYWdlRGVkdXBsaWNhdGlvbklkPVwiICsgTWF0aC5yYW5kb20oKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodHlwZW9mIGRhdGEgIT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgIGRhdGEgPSBKU09OLnN0cmluZ2lmeShkYXRhKTtcbiAgICAgICAgfVxuICAgICAgICBzcmMgKz0gXCImTWVzc2FnZUJvZHk9XCIgKyBkYXRhO1xuICAgICAgICBpbWcuc3JjID0gc3JjO1xuICAgIH1cbn1cbiIsIi8qKlxuICogQ2FsbHMgYWxsIHdyaXRlcnMgcGFzc2VkIHRvIHRoZSBjb25zdHJ1Y3RvciBlcnJvciBzYWZlXG4gKi9cbmV4cG9ydCBjbGFzcyBTcGxpdFN0cmVhbVdyaXRlciB7XG4gICAgY29uc3RydWN0b3Iod3JpdGVycykge1xuICAgICAgICB0aGlzLndyaXRlcnMgPSB3cml0ZXJzO1xuICAgIH1cbiAgICB3cml0ZShkYXRhKSB7XG4gICAgICAgIGZvciAobGV0IHdyaXRlciBvZiB0aGlzLndyaXRlcnMpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgd3JpdGVyLndyaXRlKGRhdGEpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiQ291bGQgbm90IHdyaXRlIGRhdGE6IFwiLCBlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbn1cbiIsImV4cG9ydCBjbGFzcyBUcmFpbFdyaXRlciB7XG4gICAgY29uc3RydWN0b3IoZGVsZWdhdGUsIHRyYWlsLCBxdWVyeVJlc29sdmVyKSB7XG4gICAgICAgIHRoaXMuZGVsZWdhdGUgPSBkZWxlZ2F0ZTtcbiAgICAgICAgdGhpcy50cmFpbCA9IHRyYWlsO1xuICAgICAgICB0aGlzLnF1ZXJ5UmVzb2x2ZXIgPSBxdWVyeVJlc29sdmVyO1xuICAgIH1cbiAgICB3cml0ZShkYXRhKSB7XG4gICAgICAgIGNvbnN0IHEgPSB0aGlzLnF1ZXJ5UmVzb2x2ZXIoKTtcbiAgICAgICAgaWYgKCghcSB8fCAhcS5pc1ZhbGlkKCkpICYmICFkYXRhLnF1ZXJ5ICYmIHRoaXMuaXNBcHBlbmRUcmFpbChkYXRhKSkge1xuICAgICAgICAgICAgLy8gU2VlIGlmIHdlIGhhdmUgYSBwYXlsb2FkIGlkIGFuZCBhIHRyYWlsIGZvciBpdC4gVGhpcyBtZWFucyB3ZVxuICAgICAgICAgICAgLy8gYXJlIGNvbGxlY3RpbmcgZGF0YSBmb3IgYW4gZXZlbnQgdGhhdCBkb2VzIG5vdCBoYXZlIGEgcXVlcnkgY29udGV4dFxuICAgICAgICAgICAgLy8gb24gdGhlIHBhZ2UgYW55bW9yZSBidXQgd2Ugd2FudCB0byBhc3NvY2lhdGUgdGhlIGV2ZW50IHdpdGggdGhlIHF1ZXJ5XG4gICAgICAgICAgICAvLyBjb250ZXh0IG9mIHRoZSBvcmlnaW5hbCBzZWFyY2ggcmVzdWx0XG4gICAgICAgICAgICB0aGlzLmFwcGVuZFRyYWlsKGRhdGEpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuZGVsZWdhdGUud3JpdGUoZGF0YSk7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEFwcGVuZCB0aGUgVHJhaWwgaWYgYW55XG4gICAgICogQHBhcmFtIGRhdGFcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIGFwcGVuZFRyYWlsKGRhdGEpIHtcbiAgICAgICAgY29uc3QgdHJhaWwgPSB0aGlzLnRyYWlsLmZldGNoKHRoaXMuZ2V0SWQoZGF0YSkpO1xuICAgICAgICBpZiAodHJhaWwgJiYgdHJhaWwucXVlcnkpIHtcbiAgICAgICAgICAgIGRhdGEucXVlcnkgPSB0cmFpbC5xdWVyeTtcbiAgICAgICAgICAgIGRhdGEucXVlcnlUaW1lID0gdHJhaWwudGltZXN0YW1wO1xuICAgICAgICAgICAgZGF0YS50cmFpbFR5cGUgPSB0cmFpbC50eXBlO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8qKlxuICAgICAqIGZvciBsZWdhY3kgc3VwcG9ydDogc29tZXRpbWVzIGRhdGEgd2FzIHdyYXBwZWQgaW4gcHJvcGVydHkgY2FsbGVkIFwiZGF0YVwiXG4gICAgICogQHBhcmFtIGRhdGFcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIGdldElkKGRhdGEpIHtcbiAgICAgICAgdmFyIF9hO1xuICAgICAgICBpZiAoZGF0YSlcbiAgICAgICAgICAgIHJldHVybiBkYXRhLmlkIHx8ICgoX2EgPSBkYXRhLmRhdGEpID09PSBudWxsIHx8IF9hID09PSB2b2lkIDAgPyB2b2lkIDAgOiBfYS5pZCk7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEV2YWx1YXRlcyBpZiB0aGUgVHJhaWwgc2hvdWxkIGJlIGFwcGVuZGVkIHRvIHRoaXMgZXZlbnRcbiAgICAgKiBAcGFyYW0gZGF0YVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgaXNBcHBlbmRUcmFpbChkYXRhKSB7XG4gICAgICAgIHJldHVybiBkYXRhICYmIFtcImNoZWNrb3V0XCIsIFwiYmFza2V0XCIsIFwiZmlsdGVyXCJdLmluZGV4T2YoZGF0YS50eXBlKSA+IC0xO1xuICAgICAgICAvLyBUQTogVGhpcyB3YXMgcHJldmlvdXNseSBcImRhdGEuZGF0YSAmJiBkYXRhLmRhdGEuaWQgJiYgdGhpcy50cmFpbFwiXG4gICAgICAgIC8vIHRoZSBvbmx5IENvbGxlY3RvcnMgYXBwZW5kaW5nIGEgcHJvcGVydHkgY2FsbGVkIFwiZGF0YVwiIHRvIGl0cyBldmVudCBhcmUgQ2xpY2tDb2xsZWN0b3IgaS5lLlxuICAgICAgICAvLyBDaGVja291dENsaWNrQ29sbGVjdG9yLCBCYXNrZXRDbGlja0NvbGxlY3RvciwgRmlsdGVyQ2xpY2tDb2xsZWN0b3JcbiAgICAgICAgLy8gSSd2ZSByZWZhY3RvcmVkIHRoaXMgaW1wbGljaXQgY29uZGl0aW9uIHRvIHRoaXMgZnVuY3Rpb25cbiAgICAgICAgLy8gVE9ETyB2YWxpZGF0ZSBpZiB0aGluZ3Mgd2lsbCBicmVhayB3aXRoIG5ldyBpbXBsXG4gICAgfVxufVxuIiwiZXhwb3J0ICogZnJvbSBcIi4vQmFzZTY0RW5jb2RlV3JpdGVyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9CdWZmZXJpbmdXcml0ZXJcIjtcbmV4cG9ydCAqIGZyb20gXCIuL0RlZmF1bHRXcml0ZXJcIjtcbmV4cG9ydCAqIGZyb20gXCIuL0pTT05FbnZlbG9wZVdyaXRlclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vUmVzdEV2ZW50V3JpdGVyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9TcGxpdFN0cmVhbVdyaXRlclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vU1FTRXZlbnRXcml0ZXJcIjtcbiIsImV4cG9ydCAqIGZyb20gXCIuL0Jhc2U2NEVuY29kZVdyaXRlclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vQnJvd3NlclRyYWNraW5nV3JpdGVyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9CdWZmZXJpbmdXcml0ZXJcIjtcbmV4cG9ydCAqIGZyb20gXCIuL0NvbnNvbGVXcml0ZXJcIjtcbmV4cG9ydCAqIGZyb20gXCIuL0RlYnVnV3JpdGVyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9EZWZhdWx0V3JpdGVyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9KU09ORW52ZWxvcGVXcml0ZXJcIjtcbmV4cG9ydCAqIGZyb20gXCIuL1F1ZXJ5V3JpdGVyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9SZXN0RXZlbnRXcml0ZXJcIjtcbmV4cG9ydCAqIGZyb20gXCIuL1NwbGl0U3RyZWFtV3JpdGVyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9TUVNFdmVudFdyaXRlclwiO1xuZXhwb3J0ICogZnJvbSBcIi4vVHJhaWxXcml0ZXJcIjtcbmV4cG9ydCAqIGZyb20gXCIuL1dyaXRlclwiO1xuIiwiLy8gVGhlIG1vZHVsZSBjYWNoZVxudmFyIF9fd2VicGFja19tb2R1bGVfY2FjaGVfXyA9IHt9O1xuXG4vLyBUaGUgcmVxdWlyZSBmdW5jdGlvblxuZnVuY3Rpb24gX193ZWJwYWNrX3JlcXVpcmVfXyhtb2R1bGVJZCkge1xuXHQvLyBDaGVjayBpZiBtb2R1bGUgaXMgaW4gY2FjaGVcblx0dmFyIGNhY2hlZE1vZHVsZSA9IF9fd2VicGFja19tb2R1bGVfY2FjaGVfX1ttb2R1bGVJZF07XG5cdGlmIChjYWNoZWRNb2R1bGUgIT09IHVuZGVmaW5lZCkge1xuXHRcdHJldHVybiBjYWNoZWRNb2R1bGUuZXhwb3J0cztcblx0fVxuXHQvLyBDcmVhdGUgYSBuZXcgbW9kdWxlIChhbmQgcHV0IGl0IGludG8gdGhlIGNhY2hlKVxuXHR2YXIgbW9kdWxlID0gX193ZWJwYWNrX21vZHVsZV9jYWNoZV9fW21vZHVsZUlkXSA9IHtcblx0XHQvLyBubyBtb2R1bGUuaWQgbmVlZGVkXG5cdFx0Ly8gbm8gbW9kdWxlLmxvYWRlZCBuZWVkZWRcblx0XHRleHBvcnRzOiB7fVxuXHR9O1xuXG5cdC8vIEV4ZWN1dGUgdGhlIG1vZHVsZSBmdW5jdGlvblxuXHRfX3dlYnBhY2tfbW9kdWxlc19fW21vZHVsZUlkXShtb2R1bGUsIG1vZHVsZS5leHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKTtcblxuXHQvLyBSZXR1cm4gdGhlIGV4cG9ydHMgb2YgdGhlIG1vZHVsZVxuXHRyZXR1cm4gbW9kdWxlLmV4cG9ydHM7XG59XG5cbiIsIi8vIGRlZmluZSBnZXR0ZXIgZnVuY3Rpb25zIGZvciBoYXJtb255IGV4cG9ydHNcbl9fd2VicGFja19yZXF1aXJlX18uZCA9IChleHBvcnRzLCBkZWZpbml0aW9uKSA9PiB7XG5cdGZvcih2YXIga2V5IGluIGRlZmluaXRpb24pIHtcblx0XHRpZihfX3dlYnBhY2tfcmVxdWlyZV9fLm8oZGVmaW5pdGlvbiwga2V5KSAmJiAhX193ZWJwYWNrX3JlcXVpcmVfXy5vKGV4cG9ydHMsIGtleSkpIHtcblx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBrZXksIHsgZW51bWVyYWJsZTogdHJ1ZSwgZ2V0OiBkZWZpbml0aW9uW2tleV0gfSk7XG5cdFx0fVxuXHR9XG59OyIsIl9fd2VicGFja19yZXF1aXJlX18ubyA9IChvYmosIHByb3ApID0+IChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqLCBwcm9wKSkiLCIvLyBkZWZpbmUgX19lc01vZHVsZSBvbiBleHBvcnRzXG5fX3dlYnBhY2tfcmVxdWlyZV9fLnIgPSAoZXhwb3J0cykgPT4ge1xuXHRpZih0eXBlb2YgU3ltYm9sICE9PSAndW5kZWZpbmVkJyAmJiBTeW1ib2wudG9TdHJpbmdUYWcpIHtcblx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgU3ltYm9sLnRvU3RyaW5nVGFnLCB7IHZhbHVlOiAnTW9kdWxlJyB9KTtcblx0fVxuXHRPYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgJ19fZXNNb2R1bGUnLCB7IHZhbHVlOiB0cnVlIH0pO1xufTsiLCJleHBvcnQgKiBmcm9tIFwiLi9Db2xsZWN0b3JNb2R1bGVcIjtcbmV4cG9ydCAqIGZyb20gXCIuL2NvbGxlY3RvcnMvXCI7XG5leHBvcnQgKiBmcm9tIFwiLi93cml0ZXJzXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9xdWVyeVwiO1xuZXhwb3J0ICogZnJvbSBcIi4vbG9nZ2VyXCI7XG5leHBvcnQgKiBmcm9tIFwiLi9yZXNvbHZlcnNcIjtcbmV4cG9ydCAqIGZyb20gXCIuL3V0aWxzXCI7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0= \ No newline at end of file diff --git a/demo/js/util.js b/demo/js/util.js index 5035e7b..f16d965 100644 --- a/demo/js/util.js +++ b/demo/js/util.js @@ -43,8 +43,12 @@ document.addEventListener("DOMContentLoaded", () => { event.preventDefault(); const query = document.querySelector("input").value; - if (query) + if (query === "redirect" || query === '"redirect"') { + redirect(`/redirect-landing-page.html?query=${query}`); + + } else if (query) { redirect(`/product-listing.html?query=${query}`); + } }); document.querySelector('[data-track-id="searchButton"]').addEventListener("click", event => { const query = document.querySelector("input").value; @@ -67,7 +71,7 @@ document.addEventListener("DOMContentLoaded", () => { Array.from(document.querySelectorAll("main.products a")).forEach(anchor => { anchor.addEventListener("click", (e) => { e.preventDefault(); - redirect(`/product-detail.html?id=${e.currentTarget.getAttribute("data-product-id")}`) + redirect(`/product-detail.html?id=${e.currentTarget.parentElement.getAttribute("data-product-id")}`) }); }); @@ -85,10 +89,14 @@ document.addEventListener("DOMContentLoaded", () => { /** * AddToBasket Click */ - Array.from(document.querySelectorAll("main.pdp button")).forEach(anchor => { + Array.from(document.querySelectorAll("main.pdp button, main.products button")).forEach(anchor => { anchor.addEventListener("click", (e) => { e.preventDefault(); - basket.add(e.currentTarget.getAttribute("data-product-id")); + if (e.currentTarget.hasAttribute("data-product-id")) { + basket.add(e.currentTarget.getAttribute("data-product-id")); + } else { + basket.add(e.currentTarget.parentElement.getAttribute("data-product-id")); + } redirect(`/basket.html`) }); }); diff --git a/demo/product-listing.html b/demo/product-listing.html index ed0d778..6ed8a1b 100644 --- a/demo/product-listing.html +++ b/demo/product-listing.html @@ -64,77 +64,95 @@

    Search Terms

    document.querySelector("#searchPhrase").textContent = new URLSearchParams(window.location.search).get("query");
    -
    diff --git a/demo/redirect-landing-page.html b/demo/redirect-landing-page.html new file mode 100644 index 0000000..ad0b67e --- /dev/null +++ b/demo/redirect-landing-page.html @@ -0,0 +1,159 @@ + + + + + Product Listing Page + + + + + + + + + + + + + + + + +
    +
    + + + +
    + + +
    +
    + basket svg +
    0
    +
    +
    + +
    +
    +
    +
    +

    Search Terms

    +
    +
    Jeans
    +
    Shoes
    +
    Shirts
    +
    Boots
    +
    Trousers
    +
    +
    +
    +
    +
    + +
    +
    + + + +
    +
    + Your search for  produced 9 results +
    + +
    + + + + + + + + + +
    +
    + + diff --git a/demo/sub-landing-page-one.html b/demo/sub-landing-page-one.html new file mode 100644 index 0000000..69c8409 --- /dev/null +++ b/demo/sub-landing-page-one.html @@ -0,0 +1,145 @@ + + + + + Product Listing Page + + + + + + + + + + + + + + + + +
    +
    + + + +
    + + +
    +
    + basket svg +
    0
    +
    +
    + +
    +
    +
    +
    +

    Search Terms

    +
    +
    Jeans
    +
    Shoes
    +
    Shirts
    +
    Boots
    +
    Trousers
    +
    +
    +
    +
    +
    + +
    +
    +

    Special Campaign Category Page 1

    +
    +
    + Your search for  produced 9 results +
    + +
    + + + + + + + + + +
    +
    + + diff --git a/demo/sub-landing-page-three.html b/demo/sub-landing-page-three.html new file mode 100644 index 0000000..cb8168b --- /dev/null +++ b/demo/sub-landing-page-three.html @@ -0,0 +1,145 @@ + + + + + Product Listing Page + + + + + + + + + + + + + + + + +
    +
    + + + +
    + + +
    +
    + basket svg +
    0
    +
    +
    + +
    +
    +
    +
    +

    Search Terms

    +
    +
    Jeans
    +
    Shoes
    +
    Shirts
    +
    Boots
    +
    Trousers
    +
    +
    +
    +
    +
    + +
    +
    +

    Special Campaign Category Page 3

    +
    +
    + Your search for  produced 9 results +
    + +
    + + + + + + + + + +
    +
    + + diff --git a/demo/sub-landing-page-two.html b/demo/sub-landing-page-two.html new file mode 100644 index 0000000..0da9837 --- /dev/null +++ b/demo/sub-landing-page-two.html @@ -0,0 +1,145 @@ + + + + + Product Listing Page + + + + + + + + + + + + + + + + +
    +
    + + + +
    + + +
    +
    + basket svg +
    0
    +
    +
    + +
    +
    +
    +
    +

    Search Terms

    +
    +
    Jeans
    +
    Shoes
    +
    Shirts
    +
    Boots
    +
    Trousers
    +
    +
    +
    +
    +
    + +
    +
    +

    Special Campaign Category Page 2

    +
    +
    + Your search for  produced 9 results +
    + +
    + + + + + + + + + +
    +
    + + diff --git a/src/main/collectors/ProductClickCollector.ts b/src/main/collectors/ProductClickCollector.ts index 7361b63..34f953e 100644 --- a/src/main/collectors/ProductClickCollector.ts +++ b/src/main/collectors/ProductClickCollector.ts @@ -3,6 +3,7 @@ import {ListenerType} from "../utils/ListenerType"; import {AnyResolver, NumberResolver, StringResolver} from "../resolvers/Resolver"; import {Trail} from "../query/Trail"; import {TrailType} from "../query"; +import {normalizePathname} from "../utils"; export type ProductClickCollectorResolver = { idResolver: StringResolver, @@ -52,7 +53,7 @@ export class ProductClickCollector extends ClickCollector { if (this.trail) { // After a redirect a trail with the pathname is registered containing the query which triggered the redirect. // If we have such a query we use it to build the trail. - const trailData = this.trail.fetch(location.pathname); + const trailData = this.trail.fetch(normalizePathname(location.pathname)); if (trailData) { clickData.query = trailData.query; } diff --git a/src/main/collectors/RedirectCollector.ts b/src/main/collectors/RedirectCollector.ts index f2cb6e0..b4a41fd 100644 --- a/src/main/collectors/RedirectCollector.ts +++ b/src/main/collectors/RedirectCollector.ts @@ -7,29 +7,73 @@ import { NumberResolver, StringResolver } from "../resolvers/Resolver"; -import {getSessionStorage} from "../utils"; +import {getSessionStorage, ListenerType, normalizePathname, Sentinel} from "../utils"; import {Query, Trail, TrailType} from "../query"; export type RedirectKpiCollectorParams = { resultCountResolver?: NumberResolver collectors?: Array, + maxPathSegments?: number, + nestedRedirects?: { + subSelectors?: string[], + depth?: number + }, redirectTTLMillis?: number } +interface NestedRedirect { + query: string, + depth: number +} + /** * Keep track of human triggered searches followed by a redirect to a page different than the search result page */ export class RedirectCollector extends AbstractCollector { - private static STORAGE_KEY = "__lastSearch"; + /** + * Key used to store the keywords of the last executed search + */ + private static LAST_SEARCH_STORAGE_KEY = "__lastSearch"; + + /** + * Key used to store query information for a given redirect landing page (path of the url) + */ private static PATH_STORAGE_KEY = "___pathStorage"; + private static NESTED_REDIRECT_KEYWORDS_STORAGE_KEY = "___nestedRedirectKeywordsStorage"; + private readonly resultCountResolver: NumberResolver; private readonly collectors: Array; private readonly queryResolver: (phrase) => Query; private readonly sessionResolver: StringResolver; private readonly redirectTTL: number; private readonly redirectTrail: Trail; + + /** + * Sub selectors to use when searching for elements which trigger redirects that are associated to the initial search query + * @private + */ + private readonly subSelectors: string[]; + + /** + * Maximum number of path segments to store in the path storage + * @default -1 (unlimited) + * @private + */ + private readonly maxPathSegments: number; + + /** + * Maximum depth of nested redirects to track + * @default 1 + * @private + */ + private readonly depth: number; + + /** + * Used to track if the collectors have been attached already in case attached is called multiple times + * @private + */ private isCollectorsAttached = false; /** @@ -37,6 +81,12 @@ export class RedirectCollector extends AbstractCollector { */ private isTriggerInstalled = false; + /** + * Used to skip the referer test for single page applications. + * @private + */ + private initialHistoryLength = window.history.length; + /** * Construct redirect collector * @@ -44,21 +94,31 @@ export class RedirectCollector extends AbstractCollector { * @param {function} triggerResolver - Function that fires when a search happens, should return the keyword * @param {function} expectedPageResolver - Function that should return whether the page we load is the expected one * @param redirectKpiParams - Parameters for collecting KPI's after a redirect + * @param listenerType * @param context */ constructor(private readonly triggerResolver: CallbackResolver, private readonly expectedPageResolver: BooleanResolver, private readonly redirectKpiParams: RedirectKpiCollectorParams = {}, + private readonly listenerType = ListenerType.Sentinel, context?: Context) { super("redirect", context); this.triggerResolver = triggerResolver; this.expectedPageResolver = expectedPageResolver; + this.listenerType = listenerType; this.collectors = redirectKpiParams.collectors || []; this.resultCountResolver = redirectKpiParams.resultCountResolver || (_ => void 0); this.redirectTTL = this.redirectKpiParams.redirectTTLMillis || 86400000; + this.maxPathSegments = this.redirectKpiParams.maxPathSegments || -1; + + this.subSelectors = this.redirectKpiParams.nestedRedirects?.subSelectors || []; + this.depth = this.redirectKpiParams.nestedRedirects?.depth || 1; - this.queryResolver = (phrase) => { + this.queryResolver = (phrase: string) => { + if (phrase.indexOf("$s=") > -1) { + return new Query(phrase); + } const query = new Query(); query.setSearch(phrase); return query; @@ -67,7 +127,7 @@ export class RedirectCollector extends AbstractCollector { this.sessionResolver = () => cookieSessionResolver(); this.redirectTrail = new Trail(() => { - const pathInfo = RedirectCollector.getRedirectPathInfo(window.location.pathname); + const pathInfo = RedirectCollector.getRedirectPathInfo(this.getPathname()); return new Query(pathInfo?.query); }, this.sessionResolver); } @@ -81,41 +141,43 @@ export class RedirectCollector extends AbstractCollector { * Marks this path as a redirect landing page. * @param path the pathname e.g. /some-path * @param query the query which lead to this path + * @param key the key to store the redirect path in * @private */ - private static setRedirectPath(path: string, query: string) { + private static setRedirectPath(path: string, query: string, key: string = RedirectCollector.PATH_STORAGE_KEY) { const redirectPaths = this.getRedirectPaths(); redirectPaths[path] = { query, timestamp: new Date().getTime() }; - getSessionStorage().setItem(RedirectCollector.PATH_STORAGE_KEY, JSON.stringify(redirectPaths)); + getSessionStorage().setItem(key, JSON.stringify(redirectPaths)); } /** * Get all marked paths * @private */ - private static getRedirectPaths() { - return JSON.parse(getSessionStorage().getItem(RedirectCollector.PATH_STORAGE_KEY) || "{}"); + private static getRedirectPaths(key: string = RedirectCollector.PATH_STORAGE_KEY) { + return JSON.parse(getSessionStorage().getItem(key) || "{}"); } /** * Retrieve data for the given path * @param path + * @param key * @private */ - private static getRedirectPathInfo(path: string) { - return this.getRedirectPaths()[path]; + private static getRedirectPathInfo(path: string, key: string = RedirectCollector.PATH_STORAGE_KEY) { + return this.getRedirectPaths(key)[path]; } /** * Delete all expired redirect paths * @private */ - private expireRedirectPaths() { - const redirectPaths = RedirectCollector.getRedirectPaths(); + private expireRedirectPaths(key: string = RedirectCollector.PATH_STORAGE_KEY) { + const redirectPaths = RedirectCollector.getRedirectPaths(key); const now = new Date().getTime(); Object.keys(redirectPaths).forEach(path => { const pathInfo = redirectPaths[path]; @@ -123,7 +185,7 @@ export class RedirectCollector extends AbstractCollector { delete redirectPaths[path]; } }); - getSessionStorage().setItem(RedirectCollector.PATH_STORAGE_KEY, JSON.stringify(redirectPaths)); + getSessionStorage().setItem(key, JSON.stringify(redirectPaths)); } /** @@ -134,20 +196,21 @@ export class RedirectCollector extends AbstractCollector { */ attach(writer, log) { if (this.isTriggerInstalled === false) { - this.resolve(this.triggerResolver, log, keyword => getSessionStorage().setItem(RedirectCollector.STORAGE_KEY, keyword)); + this.resolve(this.triggerResolver, log, keyword => getSessionStorage().setItem(RedirectCollector.LAST_SEARCH_STORAGE_KEY, keyword)); this.isTriggerInstalled = true; } this.expireRedirectPaths(); // Fetch the latest search if any - const lastSearch = getSessionStorage().getItem(RedirectCollector.STORAGE_KEY); + const lastSearch = getSessionStorage().getItem(RedirectCollector.LAST_SEARCH_STORAGE_KEY); + const pathname = normalizePathname(this.getWindow().location.pathname); if (lastSearch) { - getSessionStorage().removeItem(RedirectCollector.STORAGE_KEY); + getSessionStorage().removeItem(RedirectCollector.LAST_SEARCH_STORAGE_KEY); // If we have not landed on the expected search page, it must have been a redirect - if (shouldTrackRedirect(document.referrer) && !this.resolve(this.expectedPageResolver, log)) { + if (shouldTrackRedirect(document.referrer, this.initialHistoryLength) && !this.resolve(this.expectedPageResolver, log)) { const query = this.queryResolver(lastSearch).toString() writer.write({ type: "redirect", @@ -158,31 +221,111 @@ export class RedirectCollector extends AbstractCollector { }); // mark as redirect landing page - RedirectCollector.setRedirectPath(window.location.pathname, query); - // register a trail with the pathname for subsequent click events. See ProductClickCollector.ts - this.redirectTrail.register(window.location.pathname, TrailType.Main, query); + RedirectCollector.setRedirectPath(this.getPathname(), query); + + // register trail on the current pathname because the ProductClick collector doesn't know about the maxPathSegments property + this.redirectTrail.register(pathname, TrailType.Main); } } + // this is only triggered when a subSelector item was clicked i.e. a nested redirect + const lastSearchNestedRedirect = this.getNestedRedirect(); + if (lastSearchNestedRedirect) { + const query = this.queryResolver(lastSearchNestedRedirect.query).toString(); + RedirectCollector.setRedirectPath(this.getPathname(), query); + // register trail on the current pathname because the ProductClick collector doesn't know about the maxPathSegments property + this.redirectTrail.register(pathname, TrailType.Main); + + getSessionStorage().removeItem(RedirectCollector.NESTED_REDIRECT_KEYWORDS_STORAGE_KEY); + } + /** * Check if we have tracked this path before and if it is still valid. * If valid, we have to attach the KPI collectors to gather KPIs for this landing page. * We have to do this because people can navigate away from the landing page and back again and we don't want to lose all subsequent clicks etc. */ - const pathInfo = RedirectCollector.getRedirectPathInfo(this.getWindow().location.pathname); + const pathInfo = this.redirectTrail.fetch(this.getPathname()); if (pathInfo && this.isCollectorsAttached !== true) { this.attachCollectors(writer, log, pathInfo.query); this.isCollectorsAttached = true; + + // register trail on the current pathname because the ProductClick collector doesn't know about the maxPathSegments property + this.redirectTrail.register(pathname, TrailType.Main); + + // if we have nested redirects, we have to carry the query parameters over to the next page + this.attachSubSelectors(pathInfo, lastSearchNestedRedirect?.depth || 0); + } + } + + private getNestedRedirect(): NestedRedirect | undefined { + const payload = getSessionStorage().getItem(RedirectCollector.NESTED_REDIRECT_KEYWORDS_STORAGE_KEY); + if (payload) { + return JSON.parse(payload) as NestedRedirect; + } + return undefined; + } + + private isMaxDepthExceeded(currentDepth: number = 0) { + return currentDepth >= this.depth; + } + + private registerNestedRedirect(query: string, currentDepth: number = 0) { + if (this.isMaxDepthExceeded(currentDepth)) + return; + + const payload = { + query: query, + depth: currentDepth + 1 + }; + + getSessionStorage().setItem(RedirectCollector.NESTED_REDIRECT_KEYWORDS_STORAGE_KEY, JSON.stringify(payload)); + } + + private attachSubSelectors(pathInfo, currentDepth: number) { + if (this.isMaxDepthExceeded(currentDepth)) + return; + + this.subSelectors.forEach(selector => { + const handleClick = () => { + this.registerNestedRedirect(pathInfo.query, currentDepth); + } + + if (this.listenerType === ListenerType.Sentinel) { + const sentinel = new Sentinel(this.getDocument()); + sentinel.on(selector, element => { + const info = this.redirectTrail.fetch(this.getPathname()); + if (info) { // the sentinel can trigger on any page, we need to make sure we attach subSelectors only on valid redirect paths + element.addEventListener("click", handleClick); + } + }) + } else { + document.querySelectorAll(selector).forEach(element => { + element.addEventListener("click", handleClick); + }); + } + }); + } + + private getPathname(): string { + const pathname = normalizePathname(this.getWindow().location.pathname); + if (this.maxPathSegments > 0) { + const pathSegments = pathname.split("/"); + return normalizePathname(pathSegments.filter(s => !!s).slice(0, this.maxPathSegments).join("/")); } + return pathname; } private attachCollectors(writer, log, query) { + const instance = this; // attach all collectors which are responsible to gather kpi's after the redirect this.collectors.forEach(collector => { try { collector.attach({ write(data) { - writer.write({...data, query: data.query || query}); + const pathInfo = instance.redirectTrail.fetch(instance.getPathname()); + if (pathInfo) { // check if this url path is marked as a redirect page to prevent wrongly tracked events + writer.write({...data, query: data.query || query}); + } } }, log) } catch (e) { @@ -194,12 +337,13 @@ export class RedirectCollector extends AbstractCollector { } -function shouldTrackRedirect(referer: string) { +function shouldTrackRedirect(referer: string, initialHistoryLength: number) { if (referer) { try { const refUrl = new URL(referer); const currentUrl = new URL(window.location.href); - if (currentUrl.origin && refUrl.origin) + // compare the history length, if it does not equal we are on a an SPA and cant compare the referer + if (initialHistoryLength === history.length && currentUrl.origin && refUrl.origin) return refUrl.origin === currentUrl.origin; } catch (e) { console.error(e); diff --git a/src/main/utils/Util.ts b/src/main/utils/Util.ts index 0f47c76..7589693 100644 --- a/src/main/utils/Util.ts +++ b/src/main/utils/Util.ts @@ -9,6 +9,15 @@ export const parseQueryString = (queryString = window.location.search) => { return new URLSearchParams(queryString); } +export const normalizePathname = (path: string) => { + if (!path.startsWith("/")) + path = "/" + path; + if (path.endsWith("/")) + path = path.substring(0, path.length - 1); + + return path; +} + /** * Some browser like Safari prevent accessing localStorage in private mode by throwing exceptions. * Use this method to retrieve a mock impl which will at least prevent errors. diff --git a/src/test/collectors/RedirectCollector.test.ts b/src/test/collectors/RedirectCollector.test.ts index ffcbafe..ed209f9 100644 --- a/src/test/collectors/RedirectCollector.test.ts +++ b/src/test/collectors/RedirectCollector.test.ts @@ -26,6 +26,38 @@ describe('RedirectCollector Suite', () => { await verifyNoUnmatchedRequests(); }) + test('track redirect data maxPathSegments', async () => { + const redirectStubAsserter = await createStubAsserter("RedirectCollectorTracking.json"); + const clickStubAsserter = await createStubAsserter("RedirectProductClickCollectorTracking.json"); + + await page.goto(getHost() + "/nested/path/RedirectCollector.page.html?isSearchPage=true", {waitUntil: 'networkidle0'}); + + await Promise.all([page.waitForNavigation({waitUntil: "networkidle0"}), page.click("#searchButton")]); + + await wait(100); + + await redirectStubAsserter.verifyCallCount(1) + .verifyQueryParams(params => { + const trackingData = JSON.parse(params.data.values[0]); + expect(trackingData.type).toBe("redirect"); + expect(trackingData.keywords).toBe("THE REDIRECT QUERY"); + expect(trackingData.query).toBe("$s=THE REDIRECT QUERY/"); + expect(trackingData.url).toBe(getHost() + "/nested/path/RedirectCollector.page.html?isSearchPage=false"); + }) + .verify(); + + await clickStubAsserter.verifyCallCount(0) + .verify(); + + const trail = await page.evaluate(() => { + return sessionStorage.getItem("___pathStorage"); + }); + + const redirectPaths = JSON.parse(trail); + expect(redirectPaths["/nested"]).toBeDefined(); + expect(redirectPaths["/nested"].query).toBe("$s=THE REDIRECT QUERY/"); + }); + test('track redirect data', async () => { const redirectStubAsserter = await createStubAsserter("RedirectCollectorTracking.json"); const clickStubAsserter = await createStubAsserter("RedirectProductClickCollectorTracking.json"); @@ -96,6 +128,66 @@ describe('RedirectCollector Suite', () => { .verify(); }); + test('track redirect product clicks after a subSelector click', async () => { + const redirectStubAsserter = await createStubAsserter("RedirectCollectorTracking.json"); + const clickStubAsserter = await createStubAsserter("RedirectProductClickCollectorTracking.json"); + + await page.goto(getHost() + "/RedirectCollectorWithProductClicks.page.html?isSearchPage=true", {waitUntil: 'networkidle0'}); + + await Promise.all([page.waitForNavigation({waitUntil: "networkidle0"}), page.click("#searchButton")]); + + await wait(100); + + await page.click("#clickMe"); + + await wait(100); + + // make sure a trail for that path exists + const trail = await page.evaluate(() => { + return localStorage.getItem("search-collector-trail"); + }); + const pathInfo = JSON.parse(trail)["/RedirectCollectorWithProductClicks.page.html"]; + expect(pathInfo.query).toBe("$s=THE REDIRECT QUERY/"); + + await redirectStubAsserter.verifyCallCount(1) + .verifyQueryParams(params => { + const trackingData = JSON.parse(params.data.values[0]); + expect(trackingData.type).toBe("redirect"); + expect(trackingData.keywords).toBe("THE REDIRECT QUERY"); + expect(trackingData.query).toBe("$s=THE REDIRECT QUERY/"); + expect(trackingData.url).toBe(getHost() + "/RedirectCollectorWithProductClicks.page.html?isSearchPage=false"); + expect(trackingData.resultCount).toBe(5); + }) + .verify(); + + await Promise.all([page.waitForNavigation({waitUntil: "networkidle0"}), page.click("#subSelector")]); + + await wait(100); + + await page.click("#clickMe"); + + await wait(100); + + + await clickStubAsserter.verifyCallCount(2) + .verifyQueryParams((params, i) => { + const trackingData = JSON.parse(params.data.values[0]); + expect(trackingData.type).toBe("product"); + expect(trackingData.id).toBe("5"); + expect(trackingData.position).toBe(4); + expect(trackingData.price).toBe(5.99); + expect(trackingData.query).toBe("$s=THE REDIRECT QUERY/"); + expect(trackingData.image).toBe("image.jpg"); + expect(trackingData.metadata).toBe("DIV"); + if (i === 0) + expect(trackingData.url).toBe(getHost() + "/RedirectCollectorSubSelectorPage.page.html?isSearchPage=false"); + + if (i === 1) + expect(trackingData.url).toBe(getHost() + "/RedirectCollectorWithProductClicks.page.html?isSearchPage=false"); + }) + .verify(); + }); + test('track redirect data different origin', async () => { const stubAsserter = await createStubAsserter("RedirectCollectorTracking.json"); diff --git a/src/test/mock/__files/RedirectCollectorSubSelectorPage.page.html b/src/test/mock/__files/RedirectCollectorSubSelectorPage.page.html new file mode 100644 index 0000000..fec856e --- /dev/null +++ b/src/test/mock/__files/RedirectCollectorSubSelectorPage.page.html @@ -0,0 +1,90 @@ + + + + + E2E Testing + + + + + + + + + + + + +
    Product
    +
    Product
    +
    Product
    +
    Product
    +
    +
    Click Me Product
    +
    +
    Product
    +
    Product
    +
    Product
    +
    Product
    +
    Product
    + + + diff --git a/src/test/mock/__files/RedirectCollectorWithProductClicks.page.html b/src/test/mock/__files/RedirectCollectorWithProductClicks.page.html index 43d0089..2431094 100644 --- a/src/test/mock/__files/RedirectCollectorWithProductClicks.page.html +++ b/src/test/mock/__files/RedirectCollectorWithProductClicks.page.html @@ -11,11 +11,16 @@ RedirectCollector, RestEventWriter, positionResolver, - ProductClickCollector + ProductClickCollector, + BrowserTrackingWriter } = window.SearchCollector; const collector = new CollectorModule({ - writer: new RestEventWriter(location.origin + "/redirect-collector-channel") + writer: new BrowserTrackingWriter(new RestEventWriter(location.origin + "/redirect-collector-channel"), { + recordUrl: true, + recordReferrer: true, + recordLanguage: true + }) }); const firedSearchCallback = (callback) => { @@ -34,6 +39,9 @@ }, { resultCountResolver: () => 5, + nestedRedirects: { + subSelectors: ["#subSelector"], + }, collectors: [new ProductClickCollector(".product", { idResolver: element => element.getAttribute("data-id"), positionResolver: element => positionResolver(".product", element), @@ -50,10 +58,15 @@ document.location.href = document.location.origin + window.location.pathname + "?" + params.toString(); }); + document.querySelector("#subSelector").addEventListener("click", () => { + const params = new URLSearchParams(document.location.search); + params.delete("isSearchPage"); + params.append("isSearchPage", "false"); + document.location.href = document.location.origin + window.location.pathname.replace("RedirectCollectorWithProductClicks.page.html", "RedirectCollectorSubSelectorPage.page.html") + "?" + params.toString(); + }); + collector.start(); }); - - @@ -62,7 +75,7 @@ - +
    Product
    diff --git a/src/test/mock/__files/nested/path/RedirectCollector.page.html b/src/test/mock/__files/nested/path/RedirectCollector.page.html new file mode 100644 index 0000000..b9308c0 --- /dev/null +++ b/src/test/mock/__files/nested/path/RedirectCollector.page.html @@ -0,0 +1,72 @@ + + + + + E2E Testing + + + + + + + + + + + + +
    Product
    +
    Product
    +
    Product
    +
    Product
    +
    +
    Click Me Product
    +
    +
    Product
    +
    Product
    +
    Product
    +
    Product
    +
    Product
    + + + diff --git a/src/test/wiremock.ts b/src/test/wiremock.ts index 7382a52..d76f6d3 100644 --- a/src/test/wiremock.ts +++ b/src/test/wiremock.ts @@ -3,7 +3,6 @@ import fetch from "node-fetch"; import {join} from "path"; import {getRandomInt, wait} from "./util"; - export class StubAsserter { private disposed: boolean; @@ -44,9 +43,11 @@ export class StubAsserter { return this; } - private async _verifyBody(assertFn: (body: any) => void) { - const entry = await this.fetchJournalEntry(); - await assertFn(entry.request.body); + private async _verifyBody(assertFn: (body: any, i: number) => void) { + const entries = await this.fetchJournalEntry(); + for (let i = 0; i < entries.length; i++) { + await assertFn(entries[i].request.body, i); + } } verifyHeaders(assertFn: (headers: { [key: string]: string }) => void) { @@ -56,9 +57,11 @@ export class StubAsserter { return this; } - private async _verifyHeaders(assertFn: (headers: { [key: string]: string }) => void) { - const entry = await this.fetchJournalEntry(); - await assertFn(entry.request.headers); + private async _verifyHeaders(assertFn: (headers: { [key: string]: string }, i: number) => void) { + const entries = await this.fetchJournalEntry(); + for (let i = 0; i < entries.length; i++) { + await assertFn(entries[i].request.headers, i); + } } verifyCookies(assertFn: (cookies: { [key: string]: string }) => void) { @@ -68,9 +71,11 @@ export class StubAsserter { return this; } - private async _verifyCookies(assertFn: (cookies: { [key: string]: string }) => void) { - const entry = await this.fetchJournalEntry(); - await assertFn(entry.request.cookies); + private async _verifyCookies(assertFn: (cookies: { [key: string]: string }, i: number) => void) { + const entries = await this.fetchJournalEntry(); + for (let i = 0; i < entries.length; i++) { + await assertFn(entries[i].request.cookies, i); + } } verifyRequest(assertFn: (request: any) => void) { @@ -80,32 +85,39 @@ export class StubAsserter { return this; } - private async _verifyRequest(assertFn: (request: any) => void) { - const entry = await this.fetchJournalEntry(); - await assertFn(entry.request); + private async _verifyRequest(assertFn: (request: any, i: number) => void) { + const entries = await this.fetchJournalEntry(); + for (let i = 0; i < entries.length; i++) { + await assertFn(entries[i].request, i); + } } - verifyQueryParams(assertFn: (queryParams: { [key: string]: { key: string, values: Array } }) => void) { + verifyQueryParams(assertFn: (queryParams: { [key: string]: { key: string, values: Array } }, i:number) => void) { this.testFunctions.push(async () => { await this._verifyQueryParams(assertFn); }); return this; } - private async _verifyQueryParams(assertFn: (queryParams: { [key: string]: { key: string, values: Array } }) => void) { - const entry = await this.fetchJournalEntry(); - await assertFn(entry.request.queryParams); + private async _verifyQueryParams(assertFn: (queryParams: { + [key: string]: { key: string, values: Array } + }, i: number) => void) { + const entries = await this.fetchJournalEntry(); + for (let i = 0; i < entries.length; i++) { + await assertFn(entries[i].request.queryParams, i); + } } private async fetchJournalEntry() { - const entry = (await this.getJournal()).requests.find(entry => entry.stubMapping.id === this.stub.id); - if (!entry) + const requests = (await this.getJournal()).requests; + const entries = requests.filter(entry => entry.stubMapping.id === this.stub.id); + if (entries?.length == 0) throw Error(`Could not find stub for id ${this.stub.id} with filename ${this.stub.__filename}, probably (1) your api-stub did not match your request or \n (2) there were no request at all or \n (3) another stub matched your request.`); - return entry; + return entries; } private async dispose() { @@ -233,6 +245,8 @@ export const createMockServer = (port = getRandomInt(49152, 65535)) => { throw Error("mock server already started"); process = exec(`npx wiremock --port ${port} --verbose --root-dir ${__dirname + "/mock"}`); + process.stderr.on("data", data => console.error(data)); + process.stdout.on("data", data => console.debug(data)); const readyTime = await waitForReadiness(); // console.debug(`wiremock ready after ${readyTime}ms`); },