(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(require("sdp")); else if(typeof define === 'function' && define.amd) define(["sdp"], factory); else if(typeof exports === 'object') exports["lib-pixelstreamingfrontend"] = factory(require("sdp")); else root["lib-pixelstreamingfrontend"] = factory(root["sdp"]); })(this, (__WEBPACK_EXTERNAL_MODULE_sdp__) => { return /******/ (() => { // webpackBootstrap /******/ "use strict"; /******/ var __webpack_modules__ = ({ /***/ "./src/AFK/AFKController.ts": /*!**********************************!*\ !*** ./src/AFK/AFKController.ts ***! \**********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "AFKController": () => (/* binding */ AFKController) /* harmony export */ }); /* harmony import */ var _Config_Config__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Config/Config */ "./src/Config/Config.ts"); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); /* harmony import */ var _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Util/EventEmitter */ "./src/Util/EventEmitter.ts"); // Copyright Epic Games, Inc. All Rights Reserved. class AFKController { constructor(config, pixelStreaming, onDismissAfk) { // time out logic details this.closeTimeout = 10; this.active = false; this.countdownActive = false; this.warnTimer = undefined; this.countDown = 0; this.countDownTimer = undefined; this.config = config; this.pixelStreaming = pixelStreaming; this.onDismissAfk = onDismissAfk; this.onAFKTimedOutCallback = () => { console.log('AFK timed out, did you want to override this callback?'); }; } /** * The methods that occur when an afk event listener is clicked */ onAfkClick() { clearInterval(this.countDownTimer); if (this.active || this.countdownActive) { this.startAfkWarningTimer(); this.pixelStreaming.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.AfkWarningDeactivateEvent()); } } /** * Start the warning timer if a timeout is set greater that 0 seconds */ startAfkWarningTimer() { if (this.config.getNumericSettingValue(_Config_Config__WEBPACK_IMPORTED_MODULE_1__.NumericParameters.AFKTimeoutSecs) > 0 && this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_1__.Flags.AFKDetection)) { this.active = true; } else { this.active = false; } this.resetAfkWarningTimer(); } /** * Stop the afk warning timer */ stopAfkWarningTimer() { this.active = false; this.countdownActive = false; clearTimeout(this.warnTimer); clearInterval(this.countDownTimer); } /** * Pause the timer which when elapsed will warn the user they are inactive. */ pauseAfkWarningTimer() { this.active = false; } /** * If the user interacts then reset the warning timer. */ resetAfkWarningTimer() { if (this.active && this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_1__.Flags.AFKDetection)) { clearTimeout(this.warnTimer); this.warnTimer = setTimeout(() => this.activateAfkEvent(), this.config.getNumericSettingValue(_Config_Config__WEBPACK_IMPORTED_MODULE_1__.NumericParameters.AFKTimeoutSecs) * 1000); } } /** * Show the AFK overlay and begin the countDown */ activateAfkEvent() { // Pause the timer while the user is looking at the inactivity warning overlay this.pauseAfkWarningTimer(); // instantiate a new overlay this.pixelStreaming.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.AfkWarningActivateEvent({ countDown: this.countDown, dismissAfk: this.onDismissAfk })); // update our countDown timer and overlay contents this.countDown = this.closeTimeout; this.countdownActive = true; this.pixelStreaming.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.AfkWarningUpdateEvent({ countDown: this.countDown })); // if we are in locked mouse exit pointerlock if (!this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_1__.Flags.HoveringMouseMode)) { // minor hack to alleviate ios not supporting pointerlock if (document.exitPointerLock) { document.exitPointerLock(); } } // reset our countDown interval accordingly this.countDownTimer = setInterval(() => { this.countDown--; if (this.countDown == 0) { // The user failed to click so hide the overlay and disconnect them. this.pixelStreaming.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.AfkTimedOutEvent()); this.onAFKTimedOutCallback(); _Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.GetStackTrace(), 'You have been disconnected due to inactivity'); // switch off the afk feature as stream has closed this.stopAfkWarningTimer(); } else { this.pixelStreaming.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.AfkWarningUpdateEvent({ countDown: this.countDown })); } }, 1000); } } /***/ }), /***/ "./src/Config/Config.ts": /*!******************************!*\ !*** ./src/Config/Config.ts ***! \******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Config": () => (/* binding */ Config), /* harmony export */ "ControlSchemeType": () => (/* binding */ ControlSchemeType), /* harmony export */ "Flags": () => (/* binding */ Flags), /* harmony export */ "NumericParameters": () => (/* binding */ NumericParameters), /* harmony export */ "OptionParameters": () => (/* binding */ OptionParameters), /* harmony export */ "TextParameters": () => (/* binding */ TextParameters) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); /* harmony import */ var _SettingFlag__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./SettingFlag */ "./src/Config/SettingFlag.ts"); /* harmony import */ var _SettingNumber__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./SettingNumber */ "./src/Config/SettingNumber.ts"); /* harmony import */ var _SettingText__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./SettingText */ "./src/Config/SettingText.ts"); /* harmony import */ var _SettingOption__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./SettingOption */ "./src/Config/SettingOption.ts"); /* harmony import */ var _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../Util/EventEmitter */ "./src/Util/EventEmitter.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * A collection of flags that can be toggled and are core to all Pixel Streaming experiences. * These are used in the `Config.Flags` map. */ class Flags { } Flags.AutoConnect = 'AutoConnect'; Flags.AutoPlayVideo = 'AutoPlayVideo'; Flags.AFKDetection = 'TimeoutIfIdle'; Flags.BrowserSendOffer = 'OfferToReceive'; Flags.HoveringMouseMode = 'HoveringMouse'; Flags.ForceMonoAudio = 'ForceMonoAudio'; Flags.ForceTURN = 'ForceTURN'; Flags.FakeMouseWithTouches = 'FakeMouseWithTouches'; Flags.IsQualityController = 'ControlsQuality'; Flags.MatchViewportResolution = 'MatchViewportRes'; Flags.StartVideoMuted = 'StartVideoMuted'; Flags.SuppressBrowserKeys = 'SuppressBrowserKeys'; Flags.UseMic = 'UseMic'; Flags.KeyboardInput = 'KeyboardInput'; Flags.MouseInput = 'MouseInput'; Flags.TouchInput = 'TouchInput'; Flags.GamepadInput = 'GamepadInput'; Flags.XRControllerInput = 'XRControllerInput'; Flags.WaitForStreamer = "WaitForStreamer"; const isFlagId = (id) => Object.getOwnPropertyNames(Flags).some((name) => Flags[name] === id); /** * A collection of numeric parameters that are core to all Pixel Streaming experiences. * */ class NumericParameters { } NumericParameters.AFKTimeoutSecs = 'AFKTimeout'; NumericParameters.MinQP = 'MinQP'; NumericParameters.MaxQP = 'MaxQP'; NumericParameters.WebRTCFPS = 'WebRTCFPS'; NumericParameters.WebRTCMinBitrate = 'WebRTCMinBitrate'; NumericParameters.WebRTCMaxBitrate = 'WebRTCMaxBitrate'; NumericParameters.MaxReconnectAttempts = 'MaxReconnectAttempts'; NumericParameters.StreamerAutoJoinInterval = 'StreamerAutoJoinInterval'; const isNumericId = (id) => Object.getOwnPropertyNames(NumericParameters).some((name) => NumericParameters[name] === id); /** * A collection of textual parameters that are core to all Pixel Streaming experiences. * */ class TextParameters { } TextParameters.SignallingServerUrl = 'ss'; const isTextId = (id) => Object.getOwnPropertyNames(TextParameters).some((name) => TextParameters[name] === id); /** * A collection of enum based parameters that are core to all Pixel Streaming experiences. * */ class OptionParameters { } OptionParameters.PreferredCodec = 'PreferredCodec'; OptionParameters.StreamerId = 'StreamerId'; const isOptionId = (id) => Object.getOwnPropertyNames(OptionParameters).some((name) => OptionParameters[name] === id); class Config { // ------------ Settings ----------------- constructor(config = {}) { /* A map of flags that can be toggled - options that can be set in the application - e.g. Use Mic? */ this.flags = new Map(); /* A map of numerical settings - options that can be in the application - e.g. MinBitrate */ this.numericParameters = new Map(); /* A map of text settings - e.g. signalling server url */ this.textParameters = new Map(); /* A map of enum based settings - e.g. preferred codec */ this.optionParameters = new Map(); const { initialSettings, useUrlParams } = config; this._useUrlParams = !!useUrlParams; this.populateDefaultSettings(this._useUrlParams); if (initialSettings) { this.setSettings(initialSettings); } } /** * True if reading configuration initial values from URL parameters, and * persisting changes in URL when changed. */ get useUrlParams() { return this._useUrlParams; } /** * Populate the default settings for a Pixel Streaming application */ populateDefaultSettings(useUrlParams) { /** * Text Parameters */ this.textParameters.set(TextParameters.SignallingServerUrl, new _SettingText__WEBPACK_IMPORTED_MODULE_0__.SettingText(TextParameters.SignallingServerUrl, 'Signalling url', 'Url of the signalling server', (location.protocol === 'https:' ? 'wss://' : 'ws://') + window.location.hostname + // for readability, we omit the port if it's 80 (window.location.port === '80' || window.location.port === '' ? '' : `:${window.location.port}`), useUrlParams)); this.optionParameters.set(OptionParameters.StreamerId, new _SettingOption__WEBPACK_IMPORTED_MODULE_1__.SettingOption(OptionParameters.StreamerId, 'Streamer ID', 'The ID of the streamer to stream.', '', [], useUrlParams)); /** * Enum Parameters */ this.optionParameters.set(OptionParameters.PreferredCodec, new _SettingOption__WEBPACK_IMPORTED_MODULE_1__.SettingOption(OptionParameters.PreferredCodec, 'Preferred Codec', 'The preferred codec to be used during codec negotiation', 'H264 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f', (function () { const browserSupportedCodecs = []; // Try get the info needed from the RTCRtpReceiver. This is only available on chrome if (!RTCRtpReceiver.getCapabilities) { browserSupportedCodecs.push('Only available on Chrome'); return browserSupportedCodecs; } const matcher = /(VP\d|H26\d|AV1).*/; const codecs = RTCRtpReceiver.getCapabilities('video').codecs; codecs.forEach((codec) => { const str = codec.mimeType.split('/')[1] + ' ' + (codec.sdpFmtpLine || ''); const match = matcher.exec(str); if (match !== null) { browserSupportedCodecs.push(str); } }); return browserSupportedCodecs; })(), useUrlParams)); /** * Boolean parameters */ this.flags.set(Flags.AutoConnect, new _SettingFlag__WEBPACK_IMPORTED_MODULE_2__.SettingFlag(Flags.AutoConnect, 'Auto connect to stream', 'Whether we should attempt to auto connect to the signalling server or show a click to start prompt.', false, useUrlParams)); this.flags.set(Flags.AutoPlayVideo, new _SettingFlag__WEBPACK_IMPORTED_MODULE_2__.SettingFlag(Flags.AutoPlayVideo, 'Auto play video', 'When video is ready automatically start playing it as opposed to showing a play button.', true, useUrlParams)); this.flags.set(Flags.BrowserSendOffer, new _SettingFlag__WEBPACK_IMPORTED_MODULE_2__.SettingFlag(Flags.BrowserSendOffer, 'Browser send offer', 'Browser will initiate the WebRTC handshake by sending the offer to the streamer', false, useUrlParams)); this.flags.set(Flags.UseMic, new _SettingFlag__WEBPACK_IMPORTED_MODULE_2__.SettingFlag(Flags.UseMic, 'Use microphone', 'Make browser request microphone access and open an input audio track.', false, useUrlParams)); this.flags.set(Flags.StartVideoMuted, new _SettingFlag__WEBPACK_IMPORTED_MODULE_2__.SettingFlag(Flags.StartVideoMuted, 'Start video muted', 'Video will start muted if true.', false, useUrlParams)); this.flags.set(Flags.SuppressBrowserKeys, new _SettingFlag__WEBPACK_IMPORTED_MODULE_2__.SettingFlag(Flags.SuppressBrowserKeys, 'Suppress browser keys', 'Suppress certain browser keys that we use in UE, for example F5 to show shader complexity instead of refresh the page.', true, useUrlParams)); this.flags.set(Flags.IsQualityController, new _SettingFlag__WEBPACK_IMPORTED_MODULE_2__.SettingFlag(Flags.IsQualityController, 'Is quality controller?', 'True if this peer controls stream quality', true, useUrlParams)); this.flags.set(Flags.ForceMonoAudio, new _SettingFlag__WEBPACK_IMPORTED_MODULE_2__.SettingFlag(Flags.ForceMonoAudio, 'Force mono audio', 'Force browser to request mono audio in the SDP', false, useUrlParams)); this.flags.set(Flags.ForceTURN, new _SettingFlag__WEBPACK_IMPORTED_MODULE_2__.SettingFlag(Flags.ForceTURN, 'Force TURN', 'Only generate TURN/Relayed ICE candidates.', false, useUrlParams)); this.flags.set(Flags.AFKDetection, new _SettingFlag__WEBPACK_IMPORTED_MODULE_2__.SettingFlag(Flags.AFKDetection, 'AFK if idle', 'Timeout the experience if user is AFK for a period.', false, useUrlParams)); this.flags.set(Flags.MatchViewportResolution, new _SettingFlag__WEBPACK_IMPORTED_MODULE_2__.SettingFlag(Flags.MatchViewportResolution, 'Match viewport resolution', 'Pixel Streaming will be instructed to dynamically resize the video stream to match the size of the video element.', false, useUrlParams)); this.flags.set(Flags.HoveringMouseMode, new _SettingFlag__WEBPACK_IMPORTED_MODULE_2__.SettingFlag(Flags.HoveringMouseMode, 'Control Scheme: Locked Mouse', 'Either locked mouse, where the pointer is consumed by the video and locked to it, or hovering mouse, where the mouse is not consumed.', false, useUrlParams, (isHoveringMouse, setting) => { setting.label = `Control Scheme: ${isHoveringMouse ? 'Hovering' : 'Locked'} Mouse`; })); this.flags.set(Flags.FakeMouseWithTouches, new _SettingFlag__WEBPACK_IMPORTED_MODULE_2__.SettingFlag(Flags.FakeMouseWithTouches, 'Fake mouse with touches', 'A single finger touch is converted into a mouse event. This allows a non-touch application to be controlled partially via a touch device.', false, useUrlParams)); this.flags.set(Flags.KeyboardInput, new _SettingFlag__WEBPACK_IMPORTED_MODULE_2__.SettingFlag(Flags.KeyboardInput, 'Keyboard input', 'If enabled, send keyboard events to streamer', true, useUrlParams)); this.flags.set(Flags.MouseInput, new _SettingFlag__WEBPACK_IMPORTED_MODULE_2__.SettingFlag(Flags.MouseInput, 'Mouse input', 'If enabled, send mouse events to streamer', true, useUrlParams)); this.flags.set(Flags.TouchInput, new _SettingFlag__WEBPACK_IMPORTED_MODULE_2__.SettingFlag(Flags.TouchInput, 'Touch input', 'If enabled, send touch events to streamer', true, useUrlParams)); this.flags.set(Flags.GamepadInput, new _SettingFlag__WEBPACK_IMPORTED_MODULE_2__.SettingFlag(Flags.GamepadInput, 'Gamepad input', 'If enabled, send gamepad events to streamer', true, useUrlParams)); this.flags.set(Flags.XRControllerInput, new _SettingFlag__WEBPACK_IMPORTED_MODULE_2__.SettingFlag(Flags.XRControllerInput, 'XR controller input', 'If enabled, send XR controller events to streamer', true, useUrlParams)); this.flags.set(Flags.WaitForStreamer, new _SettingFlag__WEBPACK_IMPORTED_MODULE_2__.SettingFlag(Flags.WaitForStreamer, 'Wait for streamer', 'Will continue trying to connect to the first streamer available.', true, useUrlParams)); /** * Numeric parameters */ this.numericParameters.set(NumericParameters.AFKTimeoutSecs, new _SettingNumber__WEBPACK_IMPORTED_MODULE_3__.SettingNumber(NumericParameters.AFKTimeoutSecs, 'AFK timeout', 'The time (in seconds) it takes for the application to time out if AFK timeout is enabled.', 0 /*min*/, 600 /*max*/, 120 /*value*/, useUrlParams)); this.numericParameters.set(NumericParameters.MaxReconnectAttempts, new _SettingNumber__WEBPACK_IMPORTED_MODULE_3__.SettingNumber(NumericParameters.MaxReconnectAttempts, 'Max Reconnects', 'Maximum number of reconnects the application will attempt when a streamer disconnects.', 0 /*min*/, 999 /*max*/, 3 /*value*/, useUrlParams)); this.numericParameters.set(NumericParameters.MinQP, new _SettingNumber__WEBPACK_IMPORTED_MODULE_3__.SettingNumber(NumericParameters.MinQP, 'Min QP', 'The lower bound for the quantization parameter (QP) of the encoder. 0 = Best quality, 51 = worst quality.', 0 /*min*/, 51 /*max*/, 0 /*value*/, useUrlParams)); this.numericParameters.set(NumericParameters.MaxQP, new _SettingNumber__WEBPACK_IMPORTED_MODULE_3__.SettingNumber(NumericParameters.MaxQP, 'Max QP', 'The upper bound for the quantization parameter (QP) of the encoder. 0 = Best quality, 51 = worst quality.', 0 /*min*/, 51 /*max*/, 51 /*value*/, useUrlParams)); this.numericParameters.set(NumericParameters.WebRTCFPS, new _SettingNumber__WEBPACK_IMPORTED_MODULE_3__.SettingNumber(NumericParameters.WebRTCFPS, 'Max FPS', 'The maximum FPS that WebRTC will try to transmit frames at.', 1 /*min*/, 999 /*max*/, 60 /*value*/, useUrlParams)); this.numericParameters.set(NumericParameters.WebRTCMinBitrate, new _SettingNumber__WEBPACK_IMPORTED_MODULE_3__.SettingNumber(NumericParameters.WebRTCMinBitrate, 'Min Bitrate (kbps)', 'The minimum bitrate that WebRTC should use.', 0 /*min*/, 500000 /*max*/, 0 /*value*/, useUrlParams)); this.numericParameters.set(NumericParameters.WebRTCMaxBitrate, new _SettingNumber__WEBPACK_IMPORTED_MODULE_3__.SettingNumber(NumericParameters.WebRTCMaxBitrate, 'Max Bitrate (kbps)', 'The maximum bitrate that WebRTC should use.', 0 /*min*/, 500000 /*max*/, 0 /*value*/, useUrlParams)); this.numericParameters.set(NumericParameters.StreamerAutoJoinInterval, new _SettingNumber__WEBPACK_IMPORTED_MODULE_3__.SettingNumber(NumericParameters.StreamerAutoJoinInterval, 'Streamer Auto Join Interval (ms)', 'Delay between retries when waiting for an available streamer.', 500 /*min*/, 900000 /*max*/, 3000 /*value*/, useUrlParams)); } /** * Add a callback to fire when the numeric setting is toggled. * @param id The id of the flag. * @param onChangedListener The callback to fire when the numeric value changes. */ _addOnNumericSettingChangedListener(id, onChangedListener) { if (this.numericParameters.has(id)) { this.numericParameters .get(id) .addOnChangedListener(onChangedListener); } } _addOnOptionSettingChangedListener(id, onChangedListener) { if (this.optionParameters.has(id)) { this.optionParameters .get(id) .addOnChangedListener(onChangedListener); } } /** * @param id The id of the numeric setting we are interested in getting a value for. * @returns The numeric value stored in the parameter with the passed id. */ getNumericSettingValue(id) { if (this.numericParameters.has(id)) { return this.numericParameters.get(id).number; } else { throw new Error(`There is no numeric setting with the id of ${id}`); } } /** * @param id The id of the text setting we are interested in getting a value for. * @returns The text value stored in the parameter with the passed id. */ getTextSettingValue(id) { if (this.textParameters.has(id)) { return this.textParameters.get(id).value; } else { throw new Error(`There is no numeric setting with the id of ${id}`); } } /** * Set number in the setting. * @param id The id of the numeric setting we are interested in. * @param value The numeric value to set. */ setNumericSetting(id, value) { if (this.numericParameters.has(id)) { this.numericParameters.get(id).number = value; } else { throw new Error(`There is no numeric setting with the id of ${id}`); } } /** * Add a callback to fire when the flag is toggled. * @param id The id of the flag. * @param onChangeListener The callback to fire when the value changes. */ _addOnSettingChangedListener(id, onChangeListener) { if (this.flags.has(id)) { this.flags.get(id).onChange = onChangeListener; } } /** * Add a callback to fire when the text is changed. * @param id The id of the flag. * @param onChangeListener The callback to fire when the value changes. */ _addOnTextSettingChangedListener(id, onChangeListener) { if (this.textParameters.has(id)) { this.textParameters.get(id).onChange = onChangeListener; } } /** * Get the option which has the given id. * @param id The id of the option. * @returns The SettingOption object matching id */ getSettingOption(id) { return this.optionParameters.get(id); } /** * Get the value of the configuration flag which has the given id. * @param id The unique id for the flag. * @returns True if the flag is enabled. */ isFlagEnabled(id) { return this.flags.get(id).flag; } /** * Set flag to be enabled/disabled. * @param id The id of the flag to toggle. * @param flagEnabled True if the flag should be enabled. */ setFlagEnabled(id, flagEnabled) { if (!this.flags.has(id)) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_4__.Logger.Warning(_Logger_Logger__WEBPACK_IMPORTED_MODULE_4__.Logger.GetStackTrace(), `Cannot toggle flag called ${id} - it does not exist in the Config.flags map.`); } else { this.flags.get(id).flag = flagEnabled; } } /** * Set the text setting. * @param id The id of the setting * @param settingValue The value to set in the setting. */ setTextSetting(id, settingValue) { if (!this.textParameters.has(id)) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_4__.Logger.Warning(_Logger_Logger__WEBPACK_IMPORTED_MODULE_4__.Logger.GetStackTrace(), `Cannot set text setting called ${id} - it does not exist in the Config.textParameters map.`); } else { this.textParameters.get(id).text = settingValue; } } /** * Set the option setting list of options. * @param id The id of the setting * @param settingOptions The values the setting could take */ setOptionSettingOptions(id, settingOptions) { if (!this.optionParameters.has(id)) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_4__.Logger.Warning(_Logger_Logger__WEBPACK_IMPORTED_MODULE_4__.Logger.GetStackTrace(), `Cannot set text setting called ${id} - it does not exist in the Config.optionParameters map.`); } else { this.optionParameters.get(id).options = settingOptions; } } /** * Set option enum settings selected option. * @param id The id of the setting * @param settingOptions The value to select out of all the options */ setOptionSettingValue(id, settingValue) { if (!this.optionParameters.has(id)) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_4__.Logger.Warning(_Logger_Logger__WEBPACK_IMPORTED_MODULE_4__.Logger.GetStackTrace(), `Cannot set text setting called ${id} - it does not exist in the Config.enumParameters map.`); } else { this.optionParameters.get(id).selected = settingValue; } } /** * Set the label for the flag. * @param id The id of the flag. * @param label The new label to use for the flag. */ setFlagLabel(id, label) { if (!this.flags.has(id)) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_4__.Logger.Warning(_Logger_Logger__WEBPACK_IMPORTED_MODULE_4__.Logger.GetStackTrace(), `Cannot set label for flag called ${id} - it does not exist in the Config.flags map.`); } else { this.flags.get(id).label = label; } } /** * Set a subset of all settings in one function call. * * @param settings A (partial) list of settings to set */ setSettings(settings) { for (const key of Object.keys(settings)) { if (isFlagId(key)) { this.setFlagEnabled(key, settings[key]); } else if (isNumericId(key)) { this.setNumericSetting(key, settings[key]); } else if (isTextId(key)) { this.setTextSetting(key, settings[key]); } else if (isOptionId(key)) { this.setOptionSettingValue(key, settings[key]); } } } /** * Get all settings * @returns All setting values as an object with setting ids as keys */ getSettings() { const settings = {}; for (const [key, value] of this.flags.entries()) { settings[key] = value.flag; } for (const [key, value] of this.numericParameters.entries()) { settings[key] = value.number; } for (const [key, value] of this.textParameters.entries()) { settings[key] = value.text; } for (const [key, value] of this.optionParameters.entries()) { settings[key] = value.selected; } return settings; } /** * Get all Flag settings as an array. * @returns All SettingFlag objects */ getFlags() { return Array.from(this.flags.values()); } /** * Get all Text settings as an array. * @returns All SettingText objects */ getTextSettings() { return Array.from(this.textParameters.values()); } /** * Get all Number settings as an array. * @returns All SettingNumber objects */ getNumericSettings() { return Array.from(this.numericParameters.values()); } /** * Get all Option settings as an array. * @returns All SettingOption objects */ getOptionSettings() { return Array.from(this.optionParameters.values()); } /** * Emit events when settings change. * @param eventEmitter */ _registerOnChangeEvents(eventEmitter) { for (const key of this.flags.keys()) { const flag = this.flags.get(key); if (flag) { flag.onChangeEmit = (newValue) => eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_5__.SettingsChangedEvent({ id: flag.id, type: 'flag', value: newValue, target: flag })); } } for (const key of this.numericParameters.keys()) { const number = this.numericParameters.get(key); if (number) { number.onChangeEmit = (newValue) => eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_5__.SettingsChangedEvent({ id: number.id, type: 'number', value: newValue, target: number })); } } for (const key of this.textParameters.keys()) { const text = this.textParameters.get(key); if (text) { text.onChangeEmit = (newValue) => eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_5__.SettingsChangedEvent({ id: text.id, type: 'text', value: newValue, target: text })); } } for (const key of this.optionParameters.keys()) { const option = this.optionParameters.get(key); if (option) { option.onChangeEmit = (newValue) => eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_5__.SettingsChangedEvent({ id: option.id, type: 'option', value: newValue, target: option })); } } } } /** * The enum associated with the mouse being locked or hovering */ var ControlSchemeType; (function (ControlSchemeType) { ControlSchemeType[ControlSchemeType["LockedMouse"] = 0] = "LockedMouse"; ControlSchemeType[ControlSchemeType["HoveringMouse"] = 1] = "HoveringMouse"; })(ControlSchemeType || (ControlSchemeType = {})); /***/ }), /***/ "./src/Config/SettingBase.ts": /*!***********************************!*\ !*** ./src/Config/SettingBase.ts ***! \***********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "SettingBase": () => (/* binding */ SettingBase) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. /** * Base class for a setting that has a text label and an arbitrary setting value it stores. */ class SettingBase { constructor(id, label, description, defaultSettingValue, // eslint-disable-next-line @typescript-eslint/no-empty-function defaultOnChangeListener = () => { }) { this.onChange = defaultOnChangeListener; this.onChangeEmit = () => { /* Do nothing, to be overridden. */ }; this.id = id; this.description = description; this.label = label; this.value = defaultSettingValue; } /** * Set the label text for the setting. * @param label setting label. */ set label(inLabel) { this._label = inLabel; this.onChangeEmit(this._value); } /** * @returns The label text for the setting. */ get label() { return this._label; } /** * @return The setting's value. */ get value() { return this._value; } /** * Update the setting's stored value. * @param inValue The new value for the setting. */ set value(inValue) { this._value = inValue; this.onChange(this._value, this); this.onChangeEmit(this._value); } } /***/ }), /***/ "./src/Config/SettingFlag.ts": /*!***********************************!*\ !*** ./src/Config/SettingFlag.ts ***! \***********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "SettingFlag": () => (/* binding */ SettingFlag) /* harmony export */ }); /* harmony import */ var _SettingBase__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./SettingBase */ "./src/Config/SettingBase.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * A boolean flag setting object with a text label. */ class SettingFlag extends _SettingBase__WEBPACK_IMPORTED_MODULE_0__.SettingBase { constructor(id, label, description, defaultFlagValue, useUrlParams, // eslint-disable-next-line @typescript-eslint/no-empty-function defaultOnChangeListener = () => { }) { super(id, label, description, defaultFlagValue, defaultOnChangeListener); const urlParams = new URLSearchParams(window.location.search); if (!useUrlParams || !urlParams.has(this.id)) { this.flag = defaultFlagValue; } else { // parse flag from url parameters const urlParamFlag = this.getUrlParamFlag(); this.flag = urlParamFlag; } this.useUrlParams = useUrlParams; } /** * Parse the flag value from the url parameters. * @returns True if the url parameters contains /?id, but False if /?id=false */ getUrlParamFlag() { const urlParams = new URLSearchParams(window.location.search); if (urlParams.has(this.id)) { if (urlParams.get(this.id) === 'false' || urlParams.get(this.id) === 'False') { return false; } return true; } return false; } /** * Persist the setting value in URL. */ updateURLParams() { if (this.useUrlParams) { // set url params const urlParams = new URLSearchParams(window.location.search); if (this.flag === true) { urlParams.set(this.id, 'true'); } else { urlParams.set(this.id, 'false'); } window.history.replaceState({}, '', urlParams.toString() !== '' ? `${location.pathname}?${urlParams}` : `${location.pathname}`); } } /** * Enables this flag. */ enable() { this.flag = true; } /** * @return The setting's value. */ get flag() { return !!this.value; } /** * Update the setting's stored value. * @param inValue The new value for the setting. */ set flag(inValue) { this.value = inValue; } } /***/ }), /***/ "./src/Config/SettingNumber.ts": /*!*************************************!*\ !*** ./src/Config/SettingNumber.ts ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "SettingNumber": () => (/* binding */ SettingNumber) /* harmony export */ }); /* harmony import */ var _SettingBase__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./SettingBase */ "./src/Config/SettingBase.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * A number setting object with a text label. Min and max limit the range of allowed values. */ class SettingNumber extends _SettingBase__WEBPACK_IMPORTED_MODULE_0__.SettingBase { constructor(id, label, description, min, max, defaultNumber, useUrlParams, // eslint-disable-next-line @typescript-eslint/no-empty-function defaultOnChangeListener = () => { }) { super(id, label, description, defaultNumber, defaultOnChangeListener); this._min = min; this._max = max; // attempt to read the number from the url params const urlParams = new URLSearchParams(window.location.search); if (!useUrlParams || !urlParams.has(this.id)) { this.number = defaultNumber; } else { const parsedValue = Number.parseInt(urlParams.get(this.id)); this.number = Number.isNaN(parsedValue) ? defaultNumber : parsedValue; } this.useUrlParams = useUrlParams; } /** * Persist the setting value in URL. */ updateURLParams() { if (this.useUrlParams) { // set url params like ?id=number const urlParams = new URLSearchParams(window.location.search); urlParams.set(this.id, this.number.toString()); window.history.replaceState({}, '', urlParams.toString() !== '' ? `${location.pathname}?${urlParams}` : `${location.pathname}`); } } /** * Set the number value (will be clamped within range). */ set number(newNumber) { this.value = this.clamp(newNumber); } /** * @returns The number stored. */ get number() { return this.value; } /** * Clamps a number between the min and max values (inclusive). * @param inNumber The number to clamp. * @returns The clamped number. */ clamp(inNumber) { return Math.max(Math.min(this._max, inNumber), this._min); } /** * Returns the minimum value * @returns The minimum value */ get min() { return this._min; } /** * Returns the maximum value * @returns The maximum value */ get max() { return this._max; } /** * Add a change listener to the number object. */ addOnChangedListener(onChangedFunc) { this.onChange = onChangedFunc; } } /***/ }), /***/ "./src/Config/SettingOption.ts": /*!*************************************!*\ !*** ./src/Config/SettingOption.ts ***! \*************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "SettingOption": () => (/* binding */ SettingOption) /* harmony export */ }); /* harmony import */ var _SettingBase__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./SettingBase */ "./src/Config/SettingBase.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * An Option setting object with a text label. Allows you to specify an array of options and select one of them. */ class SettingOption extends _SettingBase__WEBPACK_IMPORTED_MODULE_0__.SettingBase { constructor(id, label, description, defaultTextValue, options, useUrlParams, // eslint-disable-next-line @typescript-eslint/no-empty-function defaultOnChangeListener = () => { }) { super(id, label, description, [defaultTextValue, defaultTextValue], defaultOnChangeListener); this.options = options; const urlParams = new URLSearchParams(window.location.search); const stringToMatch = useUrlParams && urlParams.has(this.id) ? this.getUrlParamText() : defaultTextValue; this.selected = stringToMatch; this.useUrlParams = useUrlParams; } /** * Parse the text value from the url parameters. * @returns The text value parsed from the url if the url parameters contains /?id=value, but empty string if just /?id or no url param found. */ getUrlParamText() { var _a; const urlParams = new URLSearchParams(window.location.search); if (urlParams.has(this.id)) { return (_a = urlParams.get(this.id)) !== null && _a !== void 0 ? _a : ''; } return ''; } /** * Persist the setting value in URL. */ updateURLParams() { if (this.useUrlParams) { // set url params const urlParams = new URLSearchParams(window.location.search); urlParams.set(this.id, this.selected); window.history.replaceState({}, '', urlParams.toString() !== '' ? `${location.pathname}?${urlParams}` : `${location.pathname}`); } } /** * Add a change listener to the select element. */ addOnChangedListener(onChangedFunc) { this.onChange = onChangedFunc; } /** * @returns All available options as an array */ get options() { return this._options; } /** * Set options * @param values Array of options */ set options(values) { this._options = values; this.onChangeEmit(this.selected); } /** * @returns Selected option as a string */ get selected() { return this.value; } /** * Set selected option if it matches one of the available options * @param value Selected option */ set selected(value) { // A user may not specify the full possible value so we instead use the closest match. // eg ?xxx=H264 would select 'H264 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f' let filteredList = this.options.filter((option) => option.indexOf(value) !== -1); if (filteredList.length) { this.value = filteredList[0]; return; } // A user has specified a codec with a fmtp string but this codec + fmtp line isn't available. // in that case, just use the codec filteredList = this.options.filter((option) => option.indexOf(value.split(' ')[0]) !== -1); if (filteredList.length) { this.value = filteredList[0]; return; } } } /***/ }), /***/ "./src/Config/SettingText.ts": /*!***********************************!*\ !*** ./src/Config/SettingText.ts ***! \***********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "SettingText": () => (/* binding */ SettingText) /* harmony export */ }); /* harmony import */ var _SettingBase__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./SettingBase */ "./src/Config/SettingBase.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * A text setting object with a text label. */ class SettingText extends _SettingBase__WEBPACK_IMPORTED_MODULE_0__.SettingBase { constructor(id, label, description, defaultTextValue, useUrlParams, // eslint-disable-next-line @typescript-eslint/no-empty-function defaultOnChangeListener = () => { }) { super(id, label, description, defaultTextValue, defaultOnChangeListener); const urlParams = new URLSearchParams(window.location.search); if (!useUrlParams || !urlParams.has(this.id)) { this.text = defaultTextValue; } else { // parse flag from url parameters const urlParamFlag = this.getUrlParamText(); this.text = urlParamFlag; } this.useUrlParams = useUrlParams; } /** * Parse the text value from the url parameters. * @returns The text value parsed from the url if the url parameters contains /?id=value, but empty string if just /?id or no url param found. */ getUrlParamText() { var _a; const urlParams = new URLSearchParams(window.location.search); if (urlParams.has(this.id)) { return (_a = urlParams.get(this.id)) !== null && _a !== void 0 ? _a : ''; } return ''; } /** * Persist the setting value in URL. */ updateURLParams() { if (this.useUrlParams) { // set url params const urlParams = new URLSearchParams(window.location.search); urlParams.set(this.id, this.text); window.history.replaceState({}, '', urlParams.toString() !== '' ? `${location.pathname}?${urlParams}` : `${location.pathname}`); } } /** * @return The setting's value. */ get text() { return this.value; } /** * Update the setting's stored value. * @param inValue The new value for the setting. */ set text(inValue) { this.value = inValue; } } /***/ }), /***/ "./src/DataChannel/DataChannelController.ts": /*!**************************************************!*\ !*** ./src/DataChannel/DataChannelController.ts ***! \**************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "DataChannelController": () => (/* binding */ DataChannelController) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * Handles the Sending and Receiving of messages to the UE Instance via the Data Channel */ class DataChannelController { constructor() { this.isReceivingFreezeFrame = false; } /** * return the current state of a datachannel controller instance * @returns the current DataChannelController instance */ getDataChannelInstance() { return this; } /** * To Create and Set up a Data Channel * @param peerConnection - The RTC Peer Connection * @param label - Label of the Data Channel * @param datachannelOptions - Optional RTC DataChannel options */ createDataChannel(peerConnection, label, datachannelOptions) { this.peerConnection = peerConnection; this.label = label; this.datachannelOptions = datachannelOptions; if (datachannelOptions == null) { this.datachannelOptions = {}; this.datachannelOptions.ordered = true; } this.dataChannel = this.peerConnection.createDataChannel(this.label, this.datachannelOptions); this.setupDataChannel(); } setupDataChannel() { //We Want an Array Buffer not a blob this.dataChannel.binaryType = 'arraybuffer'; this.dataChannel.onopen = (ev) => this.handleOnOpen(ev); this.dataChannel.onclose = (ev) => this.handleOnClose(ev); this.dataChannel.onmessage = (ev) => this.handleOnMessage(ev); this.dataChannel.onerror = (ev) => this.handleOnError(ev); } /** * Handles when the Data Channel is opened */ handleOnOpen(ev) { var _a; _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), `Data Channel (${this.label}) opened.`, 7); this.onOpen((_a = this.dataChannel) === null || _a === void 0 ? void 0 : _a.label, ev); } /** * Handles when the Data Channel is closed */ handleOnClose(ev) { var _a; _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), `Data Channel (${this.label}) closed.`, 7); this.onClose((_a = this.dataChannel) === null || _a === void 0 ? void 0 : _a.label, ev); } /** * Handles when a message is received * @param event - Message Event */ handleOnMessage(event) { // Higher log level to prevent log spam with messages received _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), `Data Channel (${this.label}) message: ${event}`, 8); } /** * Handles when an error is thrown * @param event - Error Event */ handleOnError(event) { var _a; _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), `Data Channel (${this.label}) error: ${event}`, 7); this.onError((_a = this.dataChannel) === null || _a === void 0 ? void 0 : _a.label, event); } /** * Override to register onOpen handler * @param label Data channel label ("datachannel", "send-datachannel", "recv-datachannel") * @param ev event */ // eslint-disable-next-line @typescript-eslint/no-unused-vars onOpen(label, ev) { // empty default implementation } /** * Override to register onClose handler * @param label Data channel label ("datachannel", "send-datachannel", "recv-datachannel") * @param ev event */ // eslint-disable-next-line @typescript-eslint/no-unused-vars onClose(label, ev) { // empty default implementation } /** * Override to register onError handler * @param label Data channel label ("datachannel", "send-datachannel", "recv-datachannel") * @param ev event */ // eslint-disable-next-line @typescript-eslint/no-unused-vars onError(label, ev) { // empty default implementation } } /***/ }), /***/ "./src/DataChannel/DataChannelLatencyTestController.ts": /*!*************************************************************!*\ !*** ./src/DataChannel/DataChannelLatencyTestController.ts ***! \*************************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "DataChannelLatencyTestController": () => (/* binding */ DataChannelLatencyTestController) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); /* harmony import */ var _DataChannelLatencyTestResults__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./DataChannelLatencyTestResults */ "./src/DataChannel/DataChannelLatencyTestResults.ts"); // Copyright Epic Games, Inc. All Rights Reserved. class DataChannelLatencyTestController { constructor(sink, callback) { this.sink = sink; this.callback = callback; this.records = new Map(); this.seq = 0; } start(config) { if (this.isRunning()) { return false; } this.startTime = Date.now(); this.records.clear(); this.interval = setInterval((() => { if (Date.now() - this.startTime >= config.duration) { this.stop(); } else { this.sendRequest(config.requestSize, config.responseSize); } }).bind(this), Math.floor(1000 / config.rps)); return true; } stop() { if (this.interval) { clearInterval(this.interval); this.interval = undefined; this.callback(this.produceResult()); } } produceResult() { const resultRecords = new Map(this.records); return { records: resultRecords, dataChannelRtt: Math.ceil(Array.from(this.records.values()).reduce((acc, next) => { return acc + (next.playerReceivedTimestamp - next.playerSentTimestamp); }, 0) / this.records.size), playerToStreamerTime: Math.ceil(Array.from(this.records.values()).reduce((acc, next) => { return acc + (next.streamerReceivedTimestamp - next.playerSentTimestamp); }, 0) / this.records.size), streamerToPlayerTime: Math.ceil(Array.from(this.records.values()).reduce((acc, next) => { return acc + (next.playerReceivedTimestamp - next.streamerSentTimestamp); }, 0) / this.records.size), exportLatencyAsCSV: () => { let csv = "Timestamp;RTT;PlayerToStreamer;StreamerToPlayer;\n"; resultRecords.forEach((record) => { csv += record.playerSentTimestamp + ";"; csv += (record.playerReceivedTimestamp - record.playerSentTimestamp) + ";"; csv += (record.streamerReceivedTimestamp - record.playerSentTimestamp) + ";"; csv += (record.playerReceivedTimestamp - record.streamerSentTimestamp) + ";"; csv += "\n"; }); return csv; } }; } isRunning() { return !!this.interval; } receive(response) { if (!this.isRunning()) { return; } if (!response) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), "Undefined response from server"); return; } let record = this.records.get(response.Seq); if (record) { record.update(response); } } sendRequest(requestSize, responseSize) { let request = this.createRequest(requestSize, responseSize); let record = new _DataChannelLatencyTestResults__WEBPACK_IMPORTED_MODULE_1__.DataChannelLatencyTestRecord(request); this.records.set(record.seq, record); this.sink(request); } createRequest(requestSize, responseSize) { return { Seq: this.seq++, FillResponseSize: responseSize, Filler: requestSize ? "A".repeat(requestSize) : "" }; } } /***/ }), /***/ "./src/DataChannel/DataChannelLatencyTestResults.ts": /*!**********************************************************!*\ !*** ./src/DataChannel/DataChannelLatencyTestResults.ts ***! \**********************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "DataChannelLatencyTestRecord": () => (/* binding */ DataChannelLatencyTestRecord) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. class DataChannelLatencyTestRecord { constructor(request) { this.seq = request.Seq; this.playerSentTimestamp = Date.now(); this.requestFillerSize = request.Filler ? request.Filler.length : 0; } update(response) { this.playerReceivedTimestamp = Date.now(); this.streamerReceivedTimestamp = response.ReceivedTimestamp; this.streamerSentTimestamp = response.SentTimestamp; this.responseFillerSize = response.Filler ? response.Filler.length : 0; } } /***/ }), /***/ "./src/DataChannel/DataChannelSender.ts": /*!**********************************************!*\ !*** ./src/DataChannel/DataChannelSender.ts ***! \**********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "DataChannelSender": () => (/* binding */ DataChannelSender) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * A class for sending data channel messages */ class DataChannelSender { /** * @param dataChannelProvider - Data channel object type */ constructor(dataChannelProvider) { this.dataChannelProvider = dataChannelProvider; } canSend() { return (this.dataChannelProvider.getDataChannelInstance().dataChannel !== undefined && this.dataChannelProvider.getDataChannelInstance().dataChannel .readyState == 'open'); } /** * Send Data over the Data channel to the UE Instance * @param data - Message Data Array Buffer */ sendData(data) { // reset the afk inactivity const dataChannelInstance = this.dataChannelProvider.getDataChannelInstance(); if (dataChannelInstance.dataChannel.readyState == 'open') { dataChannelInstance.dataChannel.send(data); _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), `Message Sent: ${new Uint8Array(data)}`, 6); this.resetAfkWarningTimerOnDataSend(); } else { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), `Message Failed: ${new Uint8Array(data)}`); } } /** * An override method for resetting the Afk warning timer when data is sent over the data channel */ resetAfkWarningTimerOnDataSend() { // Base Functionality: Do Nothing } } /***/ }), /***/ "./src/DataChannel/InitialSettings.ts": /*!********************************************!*\ !*** ./src/DataChannel/InitialSettings.ts ***! \********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "EncoderSettings": () => (/* binding */ EncoderSettings), /* harmony export */ "InitialSettings": () => (/* binding */ InitialSettings), /* harmony export */ "PixelStreamingSettings": () => (/* binding */ PixelStreamingSettings), /* harmony export */ "WebRTCSettings": () => (/* binding */ WebRTCSettings) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. /** * Latency Test Results Data */ class InitialSettings { constructor() { this.PixelStreamingSettings = new PixelStreamingSettings(); this.EncoderSettings = new EncoderSettings(); this.WebRTCSettings = new WebRTCSettings(); } /** * Checks for compatibility with the FPS and MaxFPS stats between 4.27 and 5 */ ueCompatible() { if (this.WebRTCSettings.MaxFPS != null) { this.WebRTCSettings.FPS = this.WebRTCSettings.MaxFPS; } } } /** * A class for handling Pixel Streaming details */ class PixelStreamingSettings { } /** * A class for handling encoder stats */ class EncoderSettings { } /** * A class for handling web rtc stats */ class WebRTCSettings { } /***/ }), /***/ "./src/DataChannel/LatencyTestResults.ts": /*!***********************************************!*\ !*** ./src/DataChannel/LatencyTestResults.ts ***! \***********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "LatencyTestResults": () => (/* binding */ LatencyTestResults) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * Latency Test Results Data */ class LatencyTestResults { constructor() { //Fields Set from the latency payload regardless of version this.ReceiptTimeMs = null; this.TransmissionTimeMs = null; //Fields Set from the latency payload from 4.27.2 this.PreCaptureTimeMs = null; this.PostCaptureTimeMs = null; this.PreEncodeTimeMs = null; this.PostEncodeTimeMs = null; //Fields Set from the latency payload from 5.0 this.EncodeMs = null; this.CaptureToSendMs = null; //Fields Set when processed this.testStartTimeMs = 0; this.browserReceiptTimeMs = 0; //Fields set from calculations this.latencyExcludingDecode = 0; this.testDuration = 0; //ueLatency: number = 0; this.networkLatency = 0; this.browserSendLatency = 0; this.frameDisplayDeltaTimeMs = 0; this.endToEndLatency = 0; //uePixelStreamLatency: number = 0; this.encodeLatency = 0; } /** * Sets the Delta Time Milliseconds * @param DeltaTimeMs - Delta Time Milliseconds */ setFrameDisplayDeltaTime(DeltaTimeMs) { if (this.frameDisplayDeltaTimeMs == 0) { this.frameDisplayDeltaTimeMs = Math.round(DeltaTimeMs); } } /** * Process the encoder times and set them */ processFields() { if (this.EncodeMs == null && (this.PreEncodeTimeMs != null || this.PostEncodeTimeMs != null)) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), `Setting Encode Ms \n ${this.PostEncodeTimeMs} \n ${this.PreEncodeTimeMs}`, 6); this.EncodeMs = this.PostEncodeTimeMs - this.PreEncodeTimeMs; } if (this.CaptureToSendMs == null && (this.PreCaptureTimeMs != null || this.PostCaptureTimeMs != null)) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), `Setting CaptureToSendMs Ms \n ${this.PostCaptureTimeMs} \n ${this.PreCaptureTimeMs}`, 6); this.CaptureToSendMs = this.PostCaptureTimeMs - this.PreCaptureTimeMs; } } } /***/ }), /***/ "./src/FreezeFrame/FreezeFrame.ts": /*!****************************************!*\ !*** ./src/FreezeFrame/FreezeFrame.ts ***! \****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "FreezeFrame": () => (/* binding */ FreezeFrame) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. /** * A class for managing the freeze frame object */ class FreezeFrame { /** * Construct a freeze frame * @param rootDiv the div that a freeze frame element will be injected into */ constructor(rootDiv) { this.freezeFrameHeight = 0; this.freezeFrameWidth = 0; this.rootDiv = rootDiv; // create the overlay this.rootElement = document.createElement('div'); this.rootElement.id = 'freezeFrame'; this.rootElement.style.display = 'none'; this.rootElement.style.pointerEvents = 'none'; this.rootElement.style.position = 'absolute'; this.rootElement.style.zIndex = '20'; // create the image place holder this.imageElement = document.createElement('img'); this.imageElement.style.position = 'absolute'; // append the image into the root element and append the element to the root div this.rootElement.appendChild(this.imageElement); this.rootDiv.appendChild(this.rootElement); } /** * Set the freeze frame element for showing */ setElementForShow() { this.rootElement.style.display = 'block'; } /** * Set the freeze frame element for hiding */ setElementForHide() { this.rootElement.style.display = 'none'; } /** * Update the freeze frames image source * @param jpeg - the freeze frame image as a byte array data */ updateImageElementSource(jpeg) { const base64 = btoa(jpeg.reduce((data, byte) => data + String.fromCharCode(byte), '')); this.imageElement.src = 'data:image/jpeg;base64,' + base64; } /** * Set the dimensions for the freeze frame from the element and resize it */ setDimensionsFromElementAndResize() { this.freezeFrameHeight = this.imageElement.naturalHeight; this.freezeFrameWidth = this.imageElement.naturalWidth; this.resize(); } /** * Resize a freeze frame element */ resize() { if (this.freezeFrameWidth !== 0 && this.freezeFrameHeight !== 0) { let displayWidth = 0; let displayHeight = 0; let displayTop = 0; let displayLeft = 0; const parentAspectRatio = this.rootDiv.clientWidth / this.rootDiv.clientHeight; const videoAspectRatio = this.freezeFrameWidth / this.freezeFrameHeight; if (parentAspectRatio < videoAspectRatio) { displayWidth = this.rootDiv.clientWidth; displayHeight = Math.floor(this.rootDiv.clientWidth / videoAspectRatio); displayTop = Math.floor((this.rootDiv.clientHeight - displayHeight) * 0.5); displayLeft = 0; } else { displayWidth = Math.floor(this.rootDiv.clientHeight * videoAspectRatio); displayHeight = this.rootDiv.clientHeight; displayTop = 0; displayLeft = Math.floor((this.rootDiv.clientWidth - displayWidth) * 0.5); } this.rootElement.style.width = this.rootDiv.offsetWidth + 'px'; this.rootElement.style.height = this.rootDiv.offsetHeight + 'px'; this.rootElement.style.left = 0 + 'px'; this.rootElement.style.top = 0 + 'px'; this.imageElement.style.width = displayWidth + 'px'; this.imageElement.style.height = displayHeight + 'px'; this.imageElement.style.left = displayLeft + 'px'; this.imageElement.style.top = displayTop + 'px'; } } } /***/ }), /***/ "./src/FreezeFrame/FreezeFrameController.ts": /*!**************************************************!*\ !*** ./src/FreezeFrame/FreezeFrameController.ts ***! \**************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "FreezeFrameController": () => (/* binding */ FreezeFrameController) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); /* harmony import */ var _FreezeFrame__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./FreezeFrame */ "./src/FreezeFrame/FreezeFrame.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * A class for controlling freeze frame functionality */ class FreezeFrameController { /** * Construct a freeze frame controller * @param rootDiv - the div that a freeze frame element will be injected into */ constructor(rootDiv) { this.receiving = false; this.size = 0; this.jpeg = undefined; this.valid = false; this.freezeFrameDelay = 50; this.freezeFrame = new _FreezeFrame__WEBPACK_IMPORTED_MODULE_0__.FreezeFrame(rootDiv); } /** * Show the freeze frame if it is valid */ showFreezeFrame() { if (this.valid) { this.freezeFrame.setElementForShow(); } } /** * Hide the freeze frame and set the validity to false */ hideFreezeFrame() { this.valid = false; this.freezeFrame.setElementForHide(); } /** * Update the freeze frames image source and load it * @param jpeg - the freeze frame image as a byte array data * @param onLoadCallBack - a call back for managing if the play overlay needs to be shown or not */ updateFreezeFrameAndShow(jpeg, onLoadCallBack) { this.freezeFrame.updateImageElementSource(jpeg); this.freezeFrame.imageElement.onload = () => { this.freezeFrame.setDimensionsFromElementAndResize(); onLoadCallBack(); }; } /** * Process the new freeze frame image and update it * @param view - the freeze frame image as a byte array data * @param onLoadCallBack - a call back for managing if the play overlay needs to be shown or not */ processFreezeFrameMessage(view, onLoadCallBack) { // Reset freeze frame if we got a freeze frame message and we are not "receiving" yet. if (!this.receiving) { this.receiving = true; this.valid = false; this.size = 0; this.jpeg = undefined; } // Extract total size of freeze frame (across all chunks) this.size = new DataView(view.slice(1, 5).buffer).getInt32(0, true); // Get the jpeg part of the payload const jpegBytes = view.slice(1 + 4); // Append to existing jpeg that holds the freeze frame if (this.jpeg) { const jpeg = new Uint8Array(this.jpeg.length + jpegBytes.length); jpeg.set(this.jpeg, 0); jpeg.set(jpegBytes, this.jpeg.length); this.jpeg = jpeg; } // No existing freeze frame jpeg, make one else { this.jpeg = jpegBytes; this.receiving = true; _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), `received first chunk of freeze frame: ${this.jpeg.length}/${this.size}`, 6); } // Finished receiving freeze frame, we can show it now if (this.jpeg.length === this.size) { this.receiving = false; this.valid = true; _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), `received complete freeze frame ${this.size}`, 6); this.updateFreezeFrameAndShow(this.jpeg, onLoadCallBack); } // We received more data than the freeze frame payload message indicate (this is an error) else if (this.jpeg.length > this.size) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), `received bigger freeze frame than advertised: ${this.jpeg.length}/${this.size}`); this.jpeg = undefined; this.receiving = false; } } } /***/ }), /***/ "./src/Inputs/FakeTouchController.ts": /*!*******************************************!*\ !*** ./src/Inputs/FakeTouchController.ts ***! \*******************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "FakeTouchController": () => (/* binding */ FakeTouchController), /* harmony export */ "FakeTouchFinger": () => (/* binding */ FakeTouchFinger) /* harmony export */ }); /* harmony import */ var _MouseButtons__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./MouseButtons */ "./src/Inputs/MouseButtons.ts"); /* harmony import */ var _Util_EventListenerTracker__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Util/EventListenerTracker */ "./src/Util/EventListenerTracker.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * Allows for the usage of fake touch events and implements ITouchController * @param dataChannelController - The controller for the Data channel * @param videoElementParent - The video player DOM element */ class FakeTouchController { /** * @param toStreamerMessagesProvider - Stream message instance * @param videoElementProvider - Video element instance * @param coordinateConverter - A coordinate converter instance */ constructor(toStreamerMessagesProvider, videoElementProvider, coordinateConverter) { // Utility for keeping track of event handlers and unregistering them this.touchEventListenerTracker = new _Util_EventListenerTracker__WEBPACK_IMPORTED_MODULE_0__.EventListenerTracker(); this.toStreamerMessagesProvider = toStreamerMessagesProvider; this.videoElementProvider = videoElementProvider; this.coordinateConverter = coordinateConverter; const ontouchstart = (ev) => this.onTouchStart(ev); const ontouchend = (ev) => this.onTouchEnd(ev); const ontouchmove = (ev) => this.onTouchMove(ev); document.addEventListener('touchstart', ontouchstart, { passive: false }); document.addEventListener('touchend', ontouchend, { passive: false }); document.addEventListener('touchmove', ontouchmove, { passive: false }); this.touchEventListenerTracker.addUnregisterCallback(() => document.removeEventListener('touchstart', ontouchstart)); this.touchEventListenerTracker.addUnregisterCallback(() => document.removeEventListener('touchend', ontouchend)); this.touchEventListenerTracker.addUnregisterCallback(() => document.removeEventListener('touchmove', ontouchmove)); } /** * Unregister all touch events */ unregisterTouchEvents() { this.touchEventListenerTracker.unregisterAll(); } /** * Sets the video Element Parent Client Rect numbers for this class * @param videoElementParentClientRect - a html ElementParentClientRect object */ setVideoElementParentClientRect(videoElementParentClientRect) { this.videoElementParentClientRect = videoElementParentClientRect; } /** * When a touch event begins * @param touch - the activating touch event */ onTouchStart(touch) { if (!this.videoElementProvider.isVideoReady()) { return; } if (this.fakeTouchFinger == null) { const first_touch = touch.changedTouches[0]; this.fakeTouchFinger = new FakeTouchFinger(first_touch.identifier, first_touch.clientX - this.videoElementParentClientRect.left, first_touch.clientY - this.videoElementParentClientRect.top); const videoElementParent = this.videoElementProvider.getVideoParentElement(); const mouseEvent = new MouseEvent('mouseenter', first_touch); videoElementParent.dispatchEvent(mouseEvent); const coord = this.coordinateConverter.normalizeAndQuantizeUnsigned(this.fakeTouchFinger.x, this.fakeTouchFinger.y); const toStreamerHandlers = this.toStreamerMessagesProvider.toStreamerHandlers; toStreamerHandlers.get('MouseDown')([ _MouseButtons__WEBPACK_IMPORTED_MODULE_1__.MouseButton.mainButton, coord.x, coord.y ]); } touch.preventDefault(); } /** * When a touch event ends * @param touchEvent - the activating touch event */ onTouchEnd(touchEvent) { if (!this.videoElementProvider.isVideoReady()) { return; } const videoElementParent = this.videoElementProvider.getVideoParentElement(); const toStreamerHandlers = this.toStreamerMessagesProvider.toStreamerHandlers; for (let t = 0; t < touchEvent.changedTouches.length; t++) { const touch = touchEvent.changedTouches[t]; if (touch.identifier === this.fakeTouchFinger.id) { const x = touch.clientX - this.videoElementParentClientRect.left; const y = touch.clientY - this.videoElementParentClientRect.top; const coord = this.coordinateConverter.normalizeAndQuantizeUnsigned(x, y); toStreamerHandlers.get('MouseUp')([ _MouseButtons__WEBPACK_IMPORTED_MODULE_1__.MouseButton.mainButton, coord.x, coord.y ]); const mouseEvent = new MouseEvent('mouseleave', touch); videoElementParent.dispatchEvent(mouseEvent); this.fakeTouchFinger = null; break; } } touchEvent.preventDefault(); } /** * On a Move touch event * @param touchEvent - the activating touch event */ onTouchMove(touchEvent) { if (!this.videoElementProvider.isVideoReady()) { return; } const toStreamerHandlers = this.toStreamerMessagesProvider.toStreamerHandlers; for (let t = 0; t < touchEvent.touches.length; t++) { const touch = touchEvent.touches[t]; if (touch.identifier === this.fakeTouchFinger.id) { const x = touch.clientX - this.videoElementParentClientRect.left; const y = touch.clientY - this.videoElementParentClientRect.top; const coord = this.coordinateConverter.normalizeAndQuantizeUnsigned(x, y); const delta = this.coordinateConverter.normalizeAndQuantizeSigned(x - this.fakeTouchFinger.x, y - this.fakeTouchFinger.y); toStreamerHandlers.get('MouseMove')([ coord.x, coord.y, delta.x, delta.y ]); this.fakeTouchFinger.x = x; this.fakeTouchFinger.y = y; break; } } touchEvent.preventDefault(); } } /** * The interface for finger position mapping */ class FakeTouchFinger { /** * @param id - the button id * @param x - the x axis value * @param y - the y axis value */ constructor(id, x, y) { this.id = id; this.x = x; this.y = y; } } /***/ }), /***/ "./src/Inputs/GamepadController.ts": /*!*****************************************!*\ !*** ./src/Inputs/GamepadController.ts ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "GamePadController": () => (/* binding */ GamePadController), /* harmony export */ "gamepadLayout": () => (/* binding */ gamepadLayout) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); /* harmony import */ var _Util_EventListenerTracker__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Util/EventListenerTracker */ "./src/Util/EventListenerTracker.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * The class that handles the functionality of gamepads and controllers */ class GamePadController { /** * @param toStreamerMessagesProvider - Stream message instance */ constructor(toStreamerMessagesProvider) { // Utility for keeping track of event handlers and unregistering them this.gamePadEventListenerTracker = new _Util_EventListenerTracker__WEBPACK_IMPORTED_MODULE_0__.EventListenerTracker(); this.toStreamerMessagesProvider = toStreamerMessagesProvider; this.requestAnimationFrame = (window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.requestAnimationFrame).bind(window); const browserWindow = window; if ('GamepadEvent' in browserWindow) { const onGamePadConnected = (ev) => this.gamePadConnectHandler(ev); const onGamePadDisconnected = (ev) => this.gamePadDisconnectHandler(ev); window.addEventListener('gamepadconnected', onGamePadConnected); window.addEventListener('gamepaddisconnected', onGamePadDisconnected); this.gamePadEventListenerTracker.addUnregisterCallback(() => window.removeEventListener('gamepadconnected', onGamePadConnected)); this.gamePadEventListenerTracker.addUnregisterCallback(() => window.removeEventListener('gamepaddisconnected', onGamePadDisconnected)); } else if ('WebKitGamepadEvent' in browserWindow) { const onWebkitGamePadConnected = (ev) => this.gamePadConnectHandler(ev); const onWebkitGamePadDisconnected = (ev) => this.gamePadDisconnectHandler(ev); window.addEventListener('webkitgamepadconnected', onWebkitGamePadConnected); window.addEventListener('webkitgamepaddisconnected', onWebkitGamePadDisconnected); this.gamePadEventListenerTracker.addUnregisterCallback(() => window.removeEventListener('webkitgamepadconnected', onWebkitGamePadConnected)); this.gamePadEventListenerTracker.addUnregisterCallback(() => window.removeEventListener('webkitgamepaddisconnected', onWebkitGamePadDisconnected)); } this.controllers = []; if (navigator.getGamepads) { for (const gamepad of navigator.getGamepads()) { if (gamepad) { this.gamePadConnectHandler(new GamepadEvent('gamepadconnected', { gamepad })); } } } } /** * Unregisters all event handlers */ unregisterGamePadEvents() { this.gamePadEventListenerTracker.unregisterAll(); for (const controller of this.controllers) { if (controller.id !== undefined) { this.onGamepadDisconnected(controller.id); } } this.controllers = []; this.onGamepadConnected = () => { }; this.onGamepadDisconnected = () => { }; } /** * Connects the gamepad handler * @param gamePadEvent - the activating gamepad event */ gamePadConnectHandler(gamePadEvent) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'Gamepad connect handler', 6); const gamepad = gamePadEvent.gamepad; const temp = { currentState: gamepad, prevState: gamepad, id: undefined }; this.controllers.push(temp); this.controllers[gamepad.index].currentState = gamepad; this.controllers[gamepad.index].prevState = gamepad; _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'gamepad: ' + gamepad.id + ' connected', 6); window.requestAnimationFrame(() => this.updateStatus()); this.onGamepadConnected(); } /** * Disconnects the gamepad handler * @param gamePadEvent - the activating gamepad event */ gamePadDisconnectHandler(gamePadEvent) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'Gamepad disconnect handler', 6); _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'gamepad: ' + gamePadEvent.gamepad.id + ' disconnected', 6); const deletedController = this.controllers[gamePadEvent.gamepad.index]; delete this.controllers[gamePadEvent.gamepad.index]; this.controllers = this.controllers.filter((controller) => controller !== undefined); this.onGamepadDisconnected(deletedController.id); } /** * Scan for connected gamepads */ scanGamePads() { const gamepads = navigator.getGamepads ? navigator.getGamepads() : navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : []; for (let i = 0; i < gamepads.length; i++) { if (gamepads[i] && gamepads[i].index in this.controllers) { this.controllers[gamepads[i].index].currentState = gamepads[i]; } } } /** * Updates the status of the gamepad and sends the inputs */ updateStatus() { this.scanGamePads(); const toStreamerHandlers = this.toStreamerMessagesProvider.toStreamerHandlers; // Iterate over multiple controllers in the case the multiple gamepads are connected for (const controller of this.controllers) { // If we haven't received an id (possible if using an older version of UE), return to original functionality const controllerIndex = (controller.id === undefined) ? this.controllers.indexOf(controller) : controller.id; const currentState = controller.currentState; for (let i = 0; i < controller.currentState.buttons.length; i++) { const currentButton = controller.currentState.buttons[i]; const previousButton = controller.prevState.buttons[i]; if (currentButton.pressed) { // press if (i == gamepadLayout.LeftTrigger) { // UEs left analog has a button index of 5 toStreamerHandlers.get('GamepadAnalog')([ controllerIndex, 5, currentButton.value ]); } else if (i == gamepadLayout.RightTrigger) { // UEs right analog has a button index of 6 toStreamerHandlers.get('GamepadAnalog')([ controllerIndex, 6, currentButton.value ]); } else { toStreamerHandlers.get('GamepadButtonPressed')([ controllerIndex, i, previousButton.pressed ? 1 : 0 ]); } } else if (!currentButton.pressed && previousButton.pressed) { // release if (i == gamepadLayout.LeftTrigger) { // UEs left analog has a button index of 5 toStreamerHandlers.get('GamepadAnalog')([ controllerIndex, 5, 0 ]); } else if (i == gamepadLayout.RightTrigger) { // UEs right analog has a button index of 6 toStreamerHandlers.get('GamepadAnalog')([ controllerIndex, 6, 0 ]); } else { toStreamerHandlers.get('GamepadButtonReleased')([ controllerIndex, i ]); } } } // Iterate over gamepad axes (we will increment in lots of 2 as there is 2 axes per stick) for (let i = 0; i < currentState.axes.length; i += 2) { // Horizontal axes are even numbered const x = parseFloat(currentState.axes[i].toFixed(4)); // Vertical axes are odd numbered // https://w3c.github.io/gamepad/#remapping Gamepad browser side standard mapping has positive down, negative up. This is downright disgusting. So we fix it. const y = -parseFloat(currentState.axes[i + 1].toFixed(4)); // UE's analog axes follow the same order as the browsers, but start at index 1 so we will offset as such toStreamerHandlers.get('GamepadAnalog')([ controllerIndex, i + 1, x ]); // Horizontal axes, only offset by 1 toStreamerHandlers.get('GamepadAnalog')([ controllerIndex, i + 2, y ]); // Vertical axes, offset by two (1 to match UEs axes convention and then another 1 for the vertical axes) } this.controllers[controllerIndex].prevState = currentState; } if (this.controllers.length > 0) { this.requestAnimationFrame(() => this.updateStatus()); } } onGamepadResponseReceived(gamepadId) { for (const controller of this.controllers) { if (controller.id === undefined) { controller.id = gamepadId; break; } } } /** * Event to send the gamepadconnected message to the application */ onGamepadConnected() { // Default Functionality: Do Nothing } /** * Event to send the gamepaddisconnected message to the application */ // eslint-disable-next-line @typescript-eslint/no-unused-vars onGamepadDisconnected(controllerIdx) { // Default Functionality: Do Nothing } } /** * Gamepad layout codes enum */ var gamepadLayout; (function (gamepadLayout) { gamepadLayout[gamepadLayout["RightClusterBottomButton"] = 0] = "RightClusterBottomButton"; gamepadLayout[gamepadLayout["RightClusterRightButton"] = 1] = "RightClusterRightButton"; gamepadLayout[gamepadLayout["RightClusterLeftButton"] = 2] = "RightClusterLeftButton"; gamepadLayout[gamepadLayout["RightClusterTopButton"] = 3] = "RightClusterTopButton"; gamepadLayout[gamepadLayout["LeftShoulder"] = 4] = "LeftShoulder"; gamepadLayout[gamepadLayout["RightShoulder"] = 5] = "RightShoulder"; gamepadLayout[gamepadLayout["LeftTrigger"] = 6] = "LeftTrigger"; gamepadLayout[gamepadLayout["RightTrigger"] = 7] = "RightTrigger"; gamepadLayout[gamepadLayout["SelectOrBack"] = 8] = "SelectOrBack"; gamepadLayout[gamepadLayout["StartOrForward"] = 9] = "StartOrForward"; gamepadLayout[gamepadLayout["LeftAnalogPress"] = 10] = "LeftAnalogPress"; gamepadLayout[gamepadLayout["RightAnalogPress"] = 11] = "RightAnalogPress"; gamepadLayout[gamepadLayout["LeftClusterTopButton"] = 12] = "LeftClusterTopButton"; gamepadLayout[gamepadLayout["LeftClusterBottomButton"] = 13] = "LeftClusterBottomButton"; gamepadLayout[gamepadLayout["LeftClusterLeftButton"] = 14] = "LeftClusterLeftButton"; gamepadLayout[gamepadLayout["LeftClusterRightButton"] = 15] = "LeftClusterRightButton"; gamepadLayout[gamepadLayout["CentreButton"] = 16] = "CentreButton"; // Axes gamepadLayout[gamepadLayout["LeftStickHorizontal"] = 0] = "LeftStickHorizontal"; gamepadLayout[gamepadLayout["LeftStickVertical"] = 1] = "LeftStickVertical"; gamepadLayout[gamepadLayout["RightStickHorizontal"] = 2] = "RightStickHorizontal"; gamepadLayout[gamepadLayout["RightStickVertical"] = 3] = "RightStickVertical"; })(gamepadLayout || (gamepadLayout = {})); /***/ }), /***/ "./src/Inputs/HoveringMouseEvents.ts": /*!*******************************************!*\ !*** ./src/Inputs/HoveringMouseEvents.ts ***! \*******************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "HoveringMouseEvents": () => (/* binding */ HoveringMouseEvents) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * Video Player mouse Hover handler */ class HoveringMouseEvents { /** * @param mouseController - Mouse Controller instance */ constructor(mouseController) { this.mouseController = mouseController; } /** * Unregister event handlers */ unregisterMouseEvents() { // empty for HoveringMouseEvents implementation } /** * Handle the mouse move event, sends the mouse data to the UE Instance * @param mouseEvent - Mouse Event */ updateMouseMovePosition(mouseEvent) { if (!this.mouseController.videoElementProvider.isVideoReady()) { return; } _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'MouseMove', 6); const coord = this.mouseController.coordinateConverter.normalizeAndQuantizeUnsigned(mouseEvent.offsetX, mouseEvent.offsetY); const delta = this.mouseController.coordinateConverter.normalizeAndQuantizeSigned(mouseEvent.movementX, mouseEvent.movementY); const toStreamerHandlers = this.mouseController.toStreamerMessagesProvider.toStreamerHandlers; toStreamerHandlers.get('MouseMove')([ coord.x, coord.y, delta.x, delta.y ]); mouseEvent.preventDefault(); } /** * Handle the mouse Down event, sends the mouse data to the UE Instance * @param mouseEvent - Mouse Event */ handleMouseDown(mouseEvent) { if (!this.mouseController.videoElementProvider.isVideoReady()) { return; } _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'onMouse Down', 6); const coord = this.mouseController.coordinateConverter.normalizeAndQuantizeUnsigned(mouseEvent.offsetX, mouseEvent.offsetY); const toStreamerHandlers = this.mouseController.toStreamerMessagesProvider.toStreamerHandlers; toStreamerHandlers.get('MouseDown')([ mouseEvent.button, coord.x, coord.y ]); mouseEvent.preventDefault(); } /** * Handle the mouse Up event, sends the mouse data to the UE Instance * @param mouseEvent - Mouse Event */ handleMouseUp(mouseEvent) { if (!this.mouseController.videoElementProvider.isVideoReady()) { return; } _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'onMouse Up', 6); const coord = this.mouseController.coordinateConverter.normalizeAndQuantizeUnsigned(mouseEvent.offsetX, mouseEvent.offsetY); const toStreamerHandlers = this.mouseController.toStreamerMessagesProvider.toStreamerHandlers; toStreamerHandlers.get('MouseUp')([ mouseEvent.button, coord.x, coord.y ]); mouseEvent.preventDefault(); } /** * Consumes the mouse context event. The UE instance has no equivalent and doesn't need to be informed. * @param mouseEvent - Mouse Event */ handleContextMenu(mouseEvent) { if (!this.mouseController.videoElementProvider.isVideoReady()) { return; } mouseEvent.preventDefault(); } /** * Handle the mouse wheel event, sends the mouse wheel data to the UE Instance * @param wheelEvent - Mouse Event */ handleMouseWheel(wheelEvent) { if (!this.mouseController.videoElementProvider.isVideoReady()) { return; } const coord = this.mouseController.coordinateConverter.normalizeAndQuantizeUnsigned(wheelEvent.offsetX, wheelEvent.offsetY); const toStreamerHandlers = this.mouseController.toStreamerMessagesProvider.toStreamerHandlers; toStreamerHandlers.get('MouseWheel')([ wheelEvent.wheelDelta, coord.x, coord.y ]); wheelEvent.preventDefault(); } /** * Handle the mouse double click event, sends the mouse data to the UE Instance * @param mouseEvent - Mouse Event */ handleMouseDouble(mouseEvent) { if (!this.mouseController.videoElementProvider.isVideoReady()) { return; } const coord = this.mouseController.coordinateConverter.normalizeAndQuantizeUnsigned(mouseEvent.offsetX, mouseEvent.offsetY); const toStreamerHandlers = this.mouseController.toStreamerMessagesProvider.toStreamerHandlers; toStreamerHandlers.get('MouseDouble')([ mouseEvent.button, coord.x, coord.y ]); } /** * Handle the press mouse buttons event, sends the mouse data to the UE Instance * @param mouseEvent - Mouse Event */ handlePressMouseButtons(mouseEvent) { if (!this.mouseController.videoElementProvider.isVideoReady()) { return; } _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'onMouse press', 6); this.mouseController.pressMouseButtons(mouseEvent.buttons, mouseEvent.offsetX, mouseEvent.offsetY); } /** * Handle the release mouse buttons event, sends the mouse data to the UE Instance * @param mouseEvent - Mouse Event */ handleReleaseMouseButtons(mouseEvent) { if (!this.mouseController.videoElementProvider.isVideoReady()) { return; } _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'onMouse release', 6); this.mouseController.releaseMouseButtons(mouseEvent.buttons, mouseEvent.offsetX, mouseEvent.offsetY); } } /***/ }), /***/ "./src/Inputs/InputClassesFactory.ts": /*!*******************************************!*\ !*** ./src/Inputs/InputClassesFactory.ts ***! \*******************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "ActiveKeys": () => (/* binding */ ActiveKeys), /* harmony export */ "InputClassesFactory": () => (/* binding */ InputClassesFactory) /* harmony export */ }); /* harmony import */ var _FakeTouchController__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./FakeTouchController */ "./src/Inputs/FakeTouchController.ts"); /* harmony import */ var _KeyboardController__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./KeyboardController */ "./src/Inputs/KeyboardController.ts"); /* harmony import */ var _MouseController__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./MouseController */ "./src/Inputs/MouseController.ts"); /* harmony import */ var _TouchController__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./TouchController */ "./src/Inputs/TouchController.ts"); /* harmony import */ var _GamepadController__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./GamepadController */ "./src/Inputs/GamepadController.ts"); /* harmony import */ var _Config_Config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../Config/Config */ "./src/Config/Config.ts"); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * Class for making and setting up input class types */ class InputClassesFactory { /** * @param toStreamerMessagesProvider - Stream message instance * @param videoElementProvider - Video Player instance * @param coordinateConverter - A coordinateConverter instance */ constructor(toStreamerMessagesProvider, videoElementProvider, coordinateConverter) { this.activeKeys = new ActiveKeys(); this.toStreamerMessagesProvider = toStreamerMessagesProvider; this.videoElementProvider = videoElementProvider; this.coordinateConverter = coordinateConverter; } /** * Registers browser key events. */ registerKeyBoard(config) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'Register Keyboard Events', 7); const keyboardController = new _KeyboardController__WEBPACK_IMPORTED_MODULE_1__.KeyboardController(this.toStreamerMessagesProvider, config, this.activeKeys); keyboardController.registerKeyBoardEvents(); return keyboardController; } /** * register mouse events based on a control type * @param controlScheme - if the mouse is either hovering or locked */ registerMouse(controlScheme) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'Register Mouse Events', 7); const mouseController = new _MouseController__WEBPACK_IMPORTED_MODULE_2__.MouseController(this.toStreamerMessagesProvider, this.videoElementProvider, this.coordinateConverter, this.activeKeys); switch (controlScheme) { case _Config_Config__WEBPACK_IMPORTED_MODULE_3__.ControlSchemeType.LockedMouse: mouseController.registerLockedMouseEvents(mouseController); break; case _Config_Config__WEBPACK_IMPORTED_MODULE_3__.ControlSchemeType.HoveringMouse: mouseController.registerHoveringMouseEvents(mouseController); break; default: _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Info(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'unknown Control Scheme Type Defaulting to Locked Mouse Events'); mouseController.registerLockedMouseEvents(mouseController); break; } return mouseController; } /** * register touch events * @param fakeMouseTouch - the faked mouse touch event */ registerTouch(fakeMouseTouch, videoElementParentClientRect) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'Registering Touch', 6); if (fakeMouseTouch) { const fakeTouchController = new _FakeTouchController__WEBPACK_IMPORTED_MODULE_4__.FakeTouchController(this.toStreamerMessagesProvider, this.videoElementProvider, this.coordinateConverter); fakeTouchController.setVideoElementParentClientRect(videoElementParentClientRect); return fakeTouchController; } else { return new _TouchController__WEBPACK_IMPORTED_MODULE_5__.TouchController(this.toStreamerMessagesProvider, this.videoElementProvider, this.coordinateConverter); } } /** * registers a gamepad */ registerGamePad() { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'Register Game Pad', 7); const gamePadController = new _GamepadController__WEBPACK_IMPORTED_MODULE_6__.GamePadController(this.toStreamerMessagesProvider); return gamePadController; } } /** * A class that keeps track of current active keys */ class ActiveKeys { constructor() { this.activeKeys = []; this.activeKeys = []; } /** * Get the current array of active keys * @returns - an array of active keys */ getActiveKeys() { return this.activeKeys; } } /***/ }), /***/ "./src/Inputs/KeyboardController.ts": /*!******************************************!*\ !*** ./src/Inputs/KeyboardController.ts ***! \******************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "KeyboardController": () => (/* binding */ KeyboardController) /* harmony export */ }); /* harmony import */ var _SpecialKeyCodes__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./SpecialKeyCodes */ "./src/Inputs/SpecialKeyCodes.ts"); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); /* harmony import */ var _Config_Config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../Config/Config */ "./src/Config/Config.ts"); /* harmony import */ var _Util_EventListenerTracker__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Util/EventListenerTracker */ "./src/Util/EventListenerTracker.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * Handles the Keyboard Inputs for the document */ class KeyboardController { /** * @param toStreamerMessagesProvider Stream message provider class object * @param config The applications configuration. We're interested in the suppress browser keys option * @param activeKeysProvider Active keys provider class object */ constructor(toStreamerMessagesProvider, config, activeKeysProvider) { // Utility for keeping track of event handlers and unregistering them this.keyboardEventListenerTracker = new _Util_EventListenerTracker__WEBPACK_IMPORTED_MODULE_0__.EventListenerTracker(); /* * New browser APIs have moved away from KeyboardEvent.keyCode to KeyboardEvent.Code. * For details see: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode#constants_for_keycode_value * We still use old KeyboardEvent.keyCode integers in the UE C++ side, so we need a way to map the new * string-based KeyboardEvent.Code to the old integers. */ this.CodeToKeyCode = { Escape: 27, Digit0: 48, Digit1: 49, Digit2: 50, Digit3: 51, Digit4: 52, Digit5: 53, Digit6: 54, Digit7: 55, Digit8: 56, Digit9: 57, Minus: 173, Equal: 187, Backspace: 8, Tab: 9, KeyQ: 81, KeyW: 87, KeyE: 69, KeyR: 82, KeyT: 84, KeyY: 89, KeyU: 85, KeyI: 73, KeyO: 79, KeyP: 80, BracketLeft: 219, BracketRight: 221, Enter: 13, ControlLeft: 17, KeyA: 65, KeyS: 83, KeyD: 68, KeyF: 70, KeyG: 71, KeyH: 72, KeyJ: 74, KeyK: 75, KeyL: 76, Semicolon: 186, Quote: 222, Backquote: 192, ShiftLeft: 16, Backslash: 220, KeyZ: 90, KeyX: 88, KeyC: 67, KeyV: 86, KeyB: 66, KeyN: 78, KeyM: 77, Comma: 188, Period: 190, Slash: 191, ShiftRight: 253, AltLeft: 18, Space: 32, CapsLock: 20, F1: 112, F2: 113, F3: 114, F4: 115, F5: 116, F6: 117, F7: 118, F8: 119, F9: 120, F10: 121, F11: 122, F12: 123, Pause: 19, ScrollLock: 145, NumpadDivide: 111, NumpadMultiply: 106, NumpadSubtract: 109, NumpadAdd: 107, NumpadDecimal: 110, Numpad9: 105, Numpad8: 104, Numpad7: 103, Numpad6: 102, Numpad5: 101, Numpad4: 100, Numpad3: 99, Numpad2: 98, Numpad1: 97, Numpad0: 96, NumLock: 144, ControlRight: 254, AltRight: 255, Home: 36, End: 35, ArrowUp: 38, ArrowLeft: 37, ArrowRight: 39, ArrowDown: 40, PageUp: 33, PageDown: 34, Insert: 45, Delete: 46, ContextMenu: 93 }; this.toStreamerMessagesProvider = toStreamerMessagesProvider; this.config = config; this.activeKeysProvider = activeKeysProvider; } /** * Registers document keyboard events with the controller */ registerKeyBoardEvents() { const keyDownHandler = (ev) => this.handleOnKeyDown(ev); const keyUpHandler = (ev) => this.handleOnKeyUp(ev); const keyPressHandler = (ev) => this.handleOnKeyPress(ev); document.addEventListener("keydown", keyDownHandler); document.addEventListener("keyup", keyUpHandler); //This has been deprecated as at Jun 13 2021 document.addEventListener("keypress", keyPressHandler); this.keyboardEventListenerTracker.addUnregisterCallback(() => document.removeEventListener("keydown", keyDownHandler)); this.keyboardEventListenerTracker.addUnregisterCallback(() => document.removeEventListener("keyup", keyUpHandler)); this.keyboardEventListenerTracker.addUnregisterCallback(() => document.removeEventListener("keypress", keyPressHandler)); } /** * Unregisters document keyboard events */ unregisterKeyBoardEvents() { this.keyboardEventListenerTracker.unregisterAll(); } /** * Handles When a key is down * @param keyboardEvent - Keyboard event */ handleOnKeyDown(keyboardEvent) { const keyCode = this.getKeycode(keyboardEvent); if (!keyCode) { return; } _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), `key down ${keyCode}, repeat = ${keyboardEvent.repeat}`, 6); const toStreamerHandlers = this.toStreamerMessagesProvider.toStreamerHandlers; toStreamerHandlers.get('KeyDown')([ this.getKeycode(keyboardEvent), keyboardEvent.repeat ? 1 : 0 ]); const activeKeys = this.activeKeysProvider.getActiveKeys(); activeKeys.push(keyCode); // Backspace is not considered a keypress in JavaScript but we need it // to be so characters may be deleted in a UE text entry field. if (keyCode === _SpecialKeyCodes__WEBPACK_IMPORTED_MODULE_2__.SpecialKeyCodes.backSpace) { document.dispatchEvent(new KeyboardEvent('keypress', { charCode: _SpecialKeyCodes__WEBPACK_IMPORTED_MODULE_2__.SpecialKeyCodes.backSpace })); } if (this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_3__.Flags.SuppressBrowserKeys) && this.isKeyCodeBrowserKey(keyCode)) { keyboardEvent.preventDefault(); } } /** * handles when a key is up * @param keyboardEvent - Keyboard event */ handleOnKeyUp(keyboardEvent) { const keyCode = this.getKeycode(keyboardEvent); if (!keyCode) { return; } _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), `key up ${keyCode}`, 6); const toStreamerHandlers = this.toStreamerMessagesProvider.toStreamerHandlers; toStreamerHandlers.get('KeyUp')([keyCode]); if (this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_3__.Flags.SuppressBrowserKeys) && this.isKeyCodeBrowserKey(keyCode)) { keyboardEvent.preventDefault(); } } /** * Handles when a key is press * @param keyboard - Keyboard Event */ handleOnKeyPress(keyboard) { if (!('charCode' in keyboard)) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Warning(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'KeyboardEvent.charCode is deprecated in this browser, cannot send key press.'); return; } const charCode = keyboard.charCode; _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), `key press ${charCode}`, 6); const toStreamerHandlers = this.toStreamerMessagesProvider.toStreamerHandlers; toStreamerHandlers.get('KeyPress')([charCode]); } /** * Gets the Keycode of the Key pressed * @param keyboardEvent - Key board Event * @returns - the key code of the Key */ getKeycode(keyboardEvent) { // If we don't have keyCode property because browser API is deprecated then use KeyboardEvent.code instead. // See: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode#constants_for_keycode_value if (!('keyCode' in keyboardEvent)) { // Convert KeyboardEvent.code string into integer-based key code for backwards compatibility reasons. const event = keyboardEvent; if (event.code in this.CodeToKeyCode) { return this.CodeToKeyCode[event.code]; } else { _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Warning(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), `Keyboard code of ${event.code} is not supported in our mapping, ignoring this key.`); return null; } } // If we made it here KeyboardEvent.keyCode is still supported so we can safely use it. if (keyboardEvent.keyCode === _SpecialKeyCodes__WEBPACK_IMPORTED_MODULE_2__.SpecialKeyCodes.shift && keyboardEvent.code === 'ShiftRight') { return _SpecialKeyCodes__WEBPACK_IMPORTED_MODULE_2__.SpecialKeyCodes.rightShift; } else if (keyboardEvent.keyCode === _SpecialKeyCodes__WEBPACK_IMPORTED_MODULE_2__.SpecialKeyCodes.control && keyboardEvent.code === 'ControlRight') { return _SpecialKeyCodes__WEBPACK_IMPORTED_MODULE_2__.SpecialKeyCodes.rightControl; } else if (keyboardEvent.keyCode === _SpecialKeyCodes__WEBPACK_IMPORTED_MODULE_2__.SpecialKeyCodes.alt && keyboardEvent.code === 'AltRight') { return _SpecialKeyCodes__WEBPACK_IMPORTED_MODULE_2__.SpecialKeyCodes.rightAlt; } else { return keyboardEvent.keyCode; } } /** * Browser keys do not have a charCode so we only need to test keyCode. * @param keyCode - the browser keycode number */ isKeyCodeBrowserKey(keyCode) { // Function keys or tab key are considered "browser keys" that we may wish to suppress by preventing them being process by browser. return (keyCode >= 112 && keyCode <= 123) || keyCode === 9; } } /***/ }), /***/ "./src/Inputs/LockedMouseEvents.ts": /*!*****************************************!*\ !*** ./src/Inputs/LockedMouseEvents.ts ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "LockedMouseEvents": () => (/* binding */ LockedMouseEvents) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); /* harmony import */ var _Util_EventListenerTracker__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Util/EventListenerTracker */ "./src/Util/EventListenerTracker.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * Handle the mouse locked events */ class LockedMouseEvents { /** * @param videoElementProvider - Video Player instance * @param mouseController - Mouse controller instance * @param activeKeysProvider - Active keys provider instance * @param playerStyleAttributesProvider - Player style attributes instance */ constructor(videoElementProvider, mouseController, activeKeysProvider) { this.x = 0; this.y = 0; this.updateMouseMovePositionEvent = (mouseEvent) => { this.updateMouseMovePosition(mouseEvent); }; // Utility for keeping track of event handlers and unregistering them this.mouseEventListenerTracker = new _Util_EventListenerTracker__WEBPACK_IMPORTED_MODULE_0__.EventListenerTracker(); this.videoElementProvider = videoElementProvider; this.mouseController = mouseController; this.activeKeysProvider = activeKeysProvider; const videoElementParent = this.videoElementProvider.getVideoParentElement(); this.x = videoElementParent.getBoundingClientRect().width / 2; this.y = videoElementParent.getBoundingClientRect().height / 2; this.coord = this.mouseController.coordinateConverter.normalizeAndQuantizeUnsigned(this.x, this.y); } /** * Unregisters all event handlers */ unregisterMouseEvents() { this.mouseEventListenerTracker.unregisterAll(); } /** * Handle when the locked state Changed */ lockStateChange() { const videoElementParent = this.videoElementProvider.getVideoParentElement(); const toStreamerHandlers = this.mouseController.toStreamerMessagesProvider.toStreamerHandlers; if (document.pointerLockElement === videoElementParent || document.mozPointerLockElement === videoElementParent) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'Pointer locked', 6); document.addEventListener('mousemove', this.updateMouseMovePositionEvent, false); this.mouseEventListenerTracker.addUnregisterCallback(() => document.removeEventListener('mousemove', this.updateMouseMovePositionEvent, false)); } else { _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'The pointer lock status is now unlocked', 6); // !a new arrow function must not be used here as it will be counted as a new function that cannot be removed document.removeEventListener('mousemove', this.updateMouseMovePositionEvent, false); // If mouse loses focus, send a key up for all of the currently held-down keys // This is necessary as when the mouse loses focus, the windows stops listening for events and as such // the keyup listener won't get fired let activeKeys = this.activeKeysProvider.getActiveKeys(); const setKeys = new Set(activeKeys); const newKeysIterable = []; setKeys.forEach((setKey) => { newKeysIterable[setKey]; }); newKeysIterable.forEach((uniqueKeycode) => { toStreamerHandlers.get('KeyUp')([uniqueKeycode]); }); // Reset the active keys back to nothing activeKeys = []; } } /** * Handle the mouse move event, sends the mouse data to the UE Instance * @param mouseEvent - Mouse Event */ updateMouseMovePosition(mouseEvent) { if (!this.videoElementProvider.isVideoReady()) { return; } const toStreamerHandlers = this.mouseController.toStreamerMessagesProvider.toStreamerHandlers; const styleWidth = this.videoElementProvider.getVideoParentElement().clientWidth; const styleHeight = this.videoElementProvider.getVideoParentElement().clientHeight; this.x += mouseEvent.movementX; this.y += mouseEvent.movementY; if (this.x > styleWidth) { this.x -= styleWidth; } if (this.y > styleHeight) { this.y -= styleHeight; } if (this.x < 0) { this.x = styleWidth + this.x; } if (this.y < 0) { this.y = styleHeight - this.y; } this.coord = this.mouseController.coordinateConverter.normalizeAndQuantizeUnsigned(this.x, this.y); const delta = this.mouseController.coordinateConverter.normalizeAndQuantizeSigned(mouseEvent.movementX, mouseEvent.movementY); toStreamerHandlers.get('MouseMove')([ this.coord.x, this.coord.y, delta.x, delta.y ]); } /** * Handle the mouse Down event, sends the mouse data to the UE Instance * @param mouseEvent - Mouse Event */ handleMouseDown(mouseEvent) { if (!this.videoElementProvider.isVideoReady()) { return; } const toStreamerHandlers = this.mouseController.toStreamerMessagesProvider.toStreamerHandlers; toStreamerHandlers.get('MouseDown')([ mouseEvent.button, // We use the store value of this.coord as opposed to the mouseEvent.x/y as the mouseEvent location // uses the system cursor location which hasn't moved this.coord.x, this.coord.y ]); } /** * Handle the mouse Up event, sends the mouse data to the UE Instance * @param mouseEvent - Mouse Event */ handleMouseUp(mouseEvent) { if (!this.videoElementProvider.isVideoReady()) { return; } const toStreamerHandlers = this.mouseController.toStreamerMessagesProvider.toStreamerHandlers; toStreamerHandlers.get('MouseUp')([ mouseEvent.button, // We use the store value of this.coord as opposed to the mouseEvent.x/y as the mouseEvent location // uses the system cursor location which hasn't moved this.coord.x, this.coord.y ]); } /** * Handle the mouse wheel event, sends the mouse wheel data to the UE Instance * @param wheelEvent - Mouse Event */ handleMouseWheel(wheelEvent) { if (!this.videoElementProvider.isVideoReady()) { return; } const toStreamerHandlers = this.mouseController.toStreamerMessagesProvider.toStreamerHandlers; toStreamerHandlers.get('MouseWheel')([ wheelEvent.wheelDelta, // We use the store value of this.coord as opposed to the mouseEvent.x/y as the mouseEvent location // uses the system cursor location which hasn't moved this.coord.x, this.coord.y ]); } /** * Handle the mouse double click event, sends the mouse data to the UE Instance * @param mouseEvent - Mouse Event */ handleMouseDouble(mouseEvent) { if (!this.videoElementProvider.isVideoReady()) { return; } const toStreamerHandlers = this.mouseController.toStreamerMessagesProvider.toStreamerHandlers; toStreamerHandlers.get('MouseDouble')([ mouseEvent.button, // We use the store value of this.coord as opposed to the mouseEvent.x/y as the mouseEvent location // uses the system cursor location which hasn't moved this.coord.x, this.coord.y ]); } /** * Handle the press mouse buttons event, sends the mouse data to the UE Instance * @param mouseEvent - Mouse Event */ handlePressMouseButtons(mouseEvent) { if (!this.videoElementProvider.isVideoReady()) { return; } this.mouseController.pressMouseButtons(mouseEvent.buttons, this.x, this.y); } /** * Handle the release mouse buttons event, sends the mouse data to the UE Instance * @param mouseEvent - Mouse Event */ handleReleaseMouseButtons(mouseEvent) { if (!this.videoElementProvider.isVideoReady()) { return; } this.mouseController.releaseMouseButtons(mouseEvent.buttons, this.x, this.y); } } /***/ }), /***/ "./src/Inputs/MouseButtons.ts": /*!************************************!*\ !*** ./src/Inputs/MouseButtons.ts ***! \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "MouseButton": () => (/* binding */ MouseButton), /* harmony export */ "MouseButtonsMask": () => (/* binding */ MouseButtonsMask) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. /** * Mouse Button Data * {@link https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button} */ class MouseButton { } MouseButton.mainButton = 0; // Left button. MouseButton.auxiliaryButton = 1; // Wheel button. MouseButton.secondaryButton = 2; // Right button. MouseButton.fourthButton = 3; // Browser Back button. MouseButton.fifthButton = 4; // Browser Forward button. /** * Mouse Button Mask Data * {@link https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons} */ class MouseButtonsMask { } MouseButtonsMask.primaryButton = 1; // Left button. MouseButtonsMask.secondaryButton = 2; // Right button. MouseButtonsMask.auxiliaryButton = 4; // Wheel button. MouseButtonsMask.fourthButton = 8; // Browser Back button. MouseButtonsMask.fifthButton = 16; // Browser Forward button. /***/ }), /***/ "./src/Inputs/MouseController.ts": /*!***************************************!*\ !*** ./src/Inputs/MouseController.ts ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "MouseController": () => (/* binding */ MouseController) /* harmony export */ }); /* harmony import */ var _MouseButtons__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./MouseButtons */ "./src/Inputs/MouseButtons.ts"); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); /* harmony import */ var _LockedMouseEvents__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./LockedMouseEvents */ "./src/Inputs/LockedMouseEvents.ts"); /* harmony import */ var _HoveringMouseEvents__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./HoveringMouseEvents */ "./src/Inputs/HoveringMouseEvents.ts"); /* harmony import */ var _Util_EventListenerTracker__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Util/EventListenerTracker */ "./src/Util/EventListenerTracker.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * Handles the Mouse Inputs for the document */ class MouseController { /** * @param toStreamerMessagesProvider - Stream message instance * @param videoElementProvider - Video Player instance * @param normalizeAndQuantize - A normalize and quantize instance */ constructor(toStreamerMessagesProvider, videoElementProvider, coordinateConverter, activeKeysProvider) { // Utility for keeping track of event handlers and unregistering them this.mouseEventListenerTracker = new _Util_EventListenerTracker__WEBPACK_IMPORTED_MODULE_0__.EventListenerTracker(); this.toStreamerMessagesProvider = toStreamerMessagesProvider; this.coordinateConverter = coordinateConverter; this.videoElementProvider = videoElementProvider; this.activeKeysProvider = activeKeysProvider; this.registerMouseEnterAndLeaveEvents(); } /** * Clears all the click events on the current video element parent div */ unregisterMouseEvents() { this.mouseEventListenerTracker.unregisterAll(); } /** * Register a locked mouse class * @param mouseController - a mouse controller instance * @param playerStyleAttributesProvider - a player style attributes instance */ registerLockedMouseEvents(mouseController) { const videoElementParent = this.videoElementProvider.getVideoParentElement(); const lockedMouseEvents = new _LockedMouseEvents__WEBPACK_IMPORTED_MODULE_1__.LockedMouseEvents(this.videoElementProvider, mouseController, this.activeKeysProvider); videoElementParent.requestPointerLock = videoElementParent.requestPointerLock || videoElementParent.mozRequestPointerLock; document.exitPointerLock = document.exitPointerLock || document.mozExitPointerLock; // minor hack to alleviate ios not supporting pointerlock if (videoElementParent.requestPointerLock) { const onclick = () => { videoElementParent.requestPointerLock(); }; videoElementParent.addEventListener('click', onclick); this.mouseEventListenerTracker.addUnregisterCallback(() => videoElementParent.removeEventListener('click', onclick)); } const lockStateChangeListener = () => lockedMouseEvents.lockStateChange(); document.addEventListener('pointerlockchange', lockStateChangeListener, false); document.addEventListener('mozpointerlockchange', lockStateChangeListener, false); this.mouseEventListenerTracker.addUnregisterCallback(() => document.removeEventListener('pointerlockchange', lockStateChangeListener, false)); this.mouseEventListenerTracker.addUnregisterCallback(() => document.removeEventListener('mozpointerlockchange', lockStateChangeListener, false)); const onmousedown = (mouseEvent) => lockedMouseEvents.handleMouseDown(mouseEvent); const onmouseup = (mouseEvent) => lockedMouseEvents.handleMouseUp(mouseEvent); const onwheel = (wheelEvent) => lockedMouseEvents.handleMouseWheel(wheelEvent); const ondblclick = (mouseEvent) => lockedMouseEvents.handleMouseDouble(mouseEvent); videoElementParent.addEventListener('mousedown', onmousedown); videoElementParent.addEventListener('mouseup', onmouseup); videoElementParent.addEventListener('wheel', onwheel); videoElementParent.addEventListener('dblclick', ondblclick); this.mouseEventListenerTracker.addUnregisterCallback(() => videoElementParent.removeEventListener('mousedown', onmousedown)); this.mouseEventListenerTracker.addUnregisterCallback(() => videoElementParent.removeEventListener('mouseup', onmouseup)); this.mouseEventListenerTracker.addUnregisterCallback(() => videoElementParent.removeEventListener('wheel', onwheel)); this.mouseEventListenerTracker.addUnregisterCallback(() => videoElementParent.removeEventListener('dblclick', ondblclick)); this.mouseEventListenerTracker.addUnregisterCallback(() => lockedMouseEvents.unregisterMouseEvents()); this.mouseEventListenerTracker.addUnregisterCallback(() => { if (document.exitPointerLock && (document.pointerLockElement === videoElementParent || document.mozPointerLockElement === videoElementParent)) { document.exitPointerLock(); } }); } /** * Register a hovering mouse class * @param mouseController - A mouse controller object */ registerHoveringMouseEvents(mouseController) { const videoElementParent = this.videoElementProvider.getVideoParentElement(); const hoveringMouseEvents = new _HoveringMouseEvents__WEBPACK_IMPORTED_MODULE_2__.HoveringMouseEvents(mouseController); const onmousemove = (mouseEvent) => hoveringMouseEvents.updateMouseMovePosition(mouseEvent); const onmousedown = (mouseEvent) => hoveringMouseEvents.handleMouseDown(mouseEvent); const onmouseup = (mouseEvent) => hoveringMouseEvents.handleMouseUp(mouseEvent); const oncontextmenu = (mouseEvent) => hoveringMouseEvents.handleContextMenu(mouseEvent); const onwheel = (wheelEvent) => hoveringMouseEvents.handleMouseWheel(wheelEvent); const ondblclick = (mouseEvent) => hoveringMouseEvents.handleMouseDouble(mouseEvent); videoElementParent.addEventListener('mousemove', onmousemove); videoElementParent.addEventListener('mousedown', onmousedown); videoElementParent.addEventListener('mouseup', onmouseup); videoElementParent.addEventListener('contextmenu', oncontextmenu); videoElementParent.addEventListener('wheel', onwheel); videoElementParent.addEventListener('dblclick', ondblclick); this.mouseEventListenerTracker.addUnregisterCallback(() => videoElementParent.removeEventListener('mousemove', onmousemove)); this.mouseEventListenerTracker.addUnregisterCallback(() => videoElementParent.removeEventListener('mousedown', onmousedown)); this.mouseEventListenerTracker.addUnregisterCallback(() => videoElementParent.removeEventListener('mouseup', onmouseup)); this.mouseEventListenerTracker.addUnregisterCallback(() => videoElementParent.removeEventListener('contextmenu', oncontextmenu)); this.mouseEventListenerTracker.addUnregisterCallback(() => videoElementParent.removeEventListener('wheel', onwheel)); this.mouseEventListenerTracker.addUnregisterCallback(() => videoElementParent.removeEventListener('dblclick', ondblclick)); this.mouseEventListenerTracker.addUnregisterCallback(() => hoveringMouseEvents.unregisterMouseEvents()); } /** * Set the mouse enter and mouse leave events */ registerMouseEnterAndLeaveEvents() { const videoElementParent = this.videoElementProvider.getVideoParentElement(); // Handle when the Mouse has entered the element const onmouseenter = (event) => { if (!this.videoElementProvider.isVideoReady()) { return; } _Logger_Logger__WEBPACK_IMPORTED_MODULE_3__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_3__.Logger.GetStackTrace(), 'Mouse Entered', 6); this.sendMouseEnter(); this.pressMouseButtons(event.buttons, event.x, event.y); }; // Handles when the mouse has left the element const onmouseleave = (event) => { if (!this.videoElementProvider.isVideoReady()) { return; } _Logger_Logger__WEBPACK_IMPORTED_MODULE_3__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_3__.Logger.GetStackTrace(), 'Mouse Left', 6); this.sendMouseLeave(); this.releaseMouseButtons(event.buttons, event.x, event.y); }; videoElementParent.addEventListener('mouseenter', onmouseenter); videoElementParent.addEventListener('mouseleave', onmouseleave); this.mouseEventListenerTracker.addUnregisterCallback(() => videoElementParent.removeEventListener('mouseenter', onmouseenter)); this.mouseEventListenerTracker.addUnregisterCallback(() => videoElementParent.removeEventListener('mouseleave', onmouseleave)); } /** * Handle when a mouse button is released * @param buttons - Mouse Button * @param X - Mouse pointer X coordinate * @param Y - Mouse pointer Y coordinate */ releaseMouseButtons(buttons, X, Y) { const coord = this.coordinateConverter.normalizeAndQuantizeUnsigned(X, Y); if (buttons & _MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButtonsMask.primaryButton) { this.sendMouseUp(_MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButton.mainButton, coord.x, coord.y); } if (buttons & _MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButtonsMask.secondaryButton) { this.sendMouseUp(_MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButton.secondaryButton, coord.x, coord.y); } if (buttons & _MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButtonsMask.auxiliaryButton) { this.sendMouseUp(_MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButton.auxiliaryButton, coord.x, coord.y); } if (buttons & _MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButtonsMask.fourthButton) { this.sendMouseUp(_MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButton.fourthButton, coord.x, coord.y); } if (buttons & _MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButtonsMask.fifthButton) { this.sendMouseUp(_MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButton.fifthButton, coord.x, coord.y); } } /** * Handle when a mouse button is pressed * @param buttons - Mouse Button * @param X - Mouse pointer X coordinate * @param Y - Mouse pointer Y coordinate */ pressMouseButtons(buttons, X, Y) { if (!this.videoElementProvider.isVideoReady()) { return; } const coord = this.coordinateConverter.normalizeAndQuantizeUnsigned(X, Y); if (buttons & _MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButtonsMask.primaryButton) { this.sendMouseDown(_MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButton.mainButton, coord.x, coord.y); } if (buttons & _MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButtonsMask.secondaryButton) { this.sendMouseDown(_MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButton.secondaryButton, coord.x, coord.y); } if (buttons & _MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButtonsMask.auxiliaryButton) { this.sendMouseDown(_MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButton.auxiliaryButton, coord.x, coord.y); } if (buttons & _MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButtonsMask.fourthButton) { this.sendMouseDown(_MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButton.fourthButton, coord.x, coord.y); } if (buttons & _MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButtonsMask.fifthButton) { this.sendMouseDown(_MouseButtons__WEBPACK_IMPORTED_MODULE_4__.MouseButton.fifthButton, coord.x, coord.y); } } /** * Handles mouse enter */ sendMouseEnter() { if (!this.videoElementProvider.isVideoReady()) { return; } const toStreamerHandlers = this.toStreamerMessagesProvider.toStreamerHandlers; toStreamerHandlers.get('MouseEnter')(); } /** * Handles mouse Leave */ sendMouseLeave() { if (!this.videoElementProvider.isVideoReady()) { return; } const toStreamerHandlers = this.toStreamerMessagesProvider.toStreamerHandlers; toStreamerHandlers.get('MouseLeave')(); } /** * Handles when a mouse button is pressed down * @param button - Mouse Button Pressed * @param X - Mouse X Coordinate * @param Y - Mouse Y Coordinate */ sendMouseDown(button, X, Y) { if (!this.videoElementProvider.isVideoReady()) { return; } _Logger_Logger__WEBPACK_IMPORTED_MODULE_3__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_3__.Logger.GetStackTrace(), `mouse button ${button} down at (${X}, ${Y})`, 6); const toStreamerHandlers = this.toStreamerMessagesProvider.toStreamerHandlers; toStreamerHandlers.get('MouseDown')([button, X, Y]); } /** * Handles when a mouse button is pressed up * @param button - Mouse Button Pressed * @param X - Mouse X Coordinate * @param Y - Mouse Y Coordinate */ sendMouseUp(button, X, Y) { if (!this.videoElementProvider.isVideoReady()) { return; } _Logger_Logger__WEBPACK_IMPORTED_MODULE_3__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_3__.Logger.GetStackTrace(), `mouse button ${button} up at (${X}, ${Y})`, 6); const coord = this.coordinateConverter.normalizeAndQuantizeUnsigned(X, Y); const toStreamerHandlers = this.toStreamerMessagesProvider.toStreamerHandlers; toStreamerHandlers.get('MouseUp')([button, coord.x, coord.y]); } } /***/ }), /***/ "./src/Inputs/SpecialKeyCodes.ts": /*!***************************************!*\ !*** ./src/Inputs/SpecialKeyCodes.ts ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "SpecialKeyCodes": () => (/* binding */ SpecialKeyCodes) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. /** * Registers the Special Key codes * Must be kept in sync with JavaScriptKeyCodeToFKey C++ array. * The index of the entry in the array is the special key code given below. */ class SpecialKeyCodes { } SpecialKeyCodes.backSpace = 8; SpecialKeyCodes.shift = 16; SpecialKeyCodes.control = 17; SpecialKeyCodes.alt = 18; SpecialKeyCodes.rightShift = 253; SpecialKeyCodes.rightControl = 254; SpecialKeyCodes.rightAlt = 255; /***/ }), /***/ "./src/Inputs/TouchController.ts": /*!***************************************!*\ !*** ./src/Inputs/TouchController.ts ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "TouchController": () => (/* binding */ TouchController) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); /* harmony import */ var _Util_EventListenerTracker__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Util/EventListenerTracker */ "./src/Util/EventListenerTracker.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * Handles the Touch input Events */ class TouchController { /** * @param toStreamerMessagesProvider - Stream message instance * @param videoElementProvider - Video Player instance * @param coordinateConverter - A coordinate converter instance */ constructor(toStreamerMessagesProvider, videoElementProvider, coordinateConverter) { this.fingers = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]; this.fingerIds = new Map(); this.maxByteValue = 255; // Utility for keeping track of event handlers and unregistering them this.touchEventListenerTracker = new _Util_EventListenerTracker__WEBPACK_IMPORTED_MODULE_0__.EventListenerTracker(); this.toStreamerMessagesProvider = toStreamerMessagesProvider; this.videoElementProvider = videoElementProvider; this.coordinateConverter = coordinateConverter; this.videoElementParent = videoElementProvider.getVideoElement(); const ontouchstart = (ev) => this.onTouchStart(ev); const ontouchend = (ev) => this.onTouchEnd(ev); const ontouchmove = (ev) => this.onTouchMove(ev); this.videoElementParent.addEventListener('touchstart', ontouchstart); this.videoElementParent.addEventListener('touchend', ontouchend); this.videoElementParent.addEventListener('touchmove', ontouchmove); this.touchEventListenerTracker.addUnregisterCallback(() => this.videoElementParent.removeEventListener('touchstart', ontouchstart)); this.touchEventListenerTracker.addUnregisterCallback(() => this.videoElementParent.removeEventListener('touchend', ontouchend)); this.touchEventListenerTracker.addUnregisterCallback(() => this.videoElementParent.removeEventListener('touchmove', ontouchmove)); _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'Touch Events Registered', 6); // is this strictly necessary? const preventOnTouchMove = (event) => { event.preventDefault(); }; document.addEventListener('touchmove', preventOnTouchMove); this.touchEventListenerTracker.addUnregisterCallback(() => document.removeEventListener('touchmove', preventOnTouchMove)); } /** * Unregister all touch events */ unregisterTouchEvents() { this.touchEventListenerTracker.unregisterAll(); } /** * Remember a touch command * @param touch - the touch command */ rememberTouch(touch) { const finger = this.fingers.pop(); if (finger === undefined) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'exhausted touch identifiers', 6); } this.fingerIds.set(touch.identifier, finger); } /** * Forgets a touch command * @param touch - the touch command */ forgetTouch(touch) { this.fingers.push(this.fingerIds.get(touch.identifier)); // Sort array back into descending order. This means if finger '1' were to lift after finger '0', we would ensure that 0 will be the first index to pop this.fingers.sort(function (a, b) { return b - a; }); this.fingerIds.delete(touch.identifier); } /** * When a touch event starts * @param touchEvent - the touch event being intercepted */ onTouchStart(touchEvent) { if (!this.videoElementProvider.isVideoReady()) { return; } for (let t = 0; t < touchEvent.changedTouches.length; t++) { this.rememberTouch(touchEvent.changedTouches[t]); } _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'touch start', 6); this.emitTouchData('TouchStart', touchEvent.changedTouches); touchEvent.preventDefault(); } /** * When a touch event ends * @param touchEvent - the touch event being intercepted */ onTouchEnd(touchEvent) { if (!this.videoElementProvider.isVideoReady()) { return; } _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'touch end', 6); this.emitTouchData('TouchEnd', touchEvent.changedTouches); // Re-cycle unique identifiers previously assigned to each touch. for (let t = 0; t < touchEvent.changedTouches.length; t++) { this.forgetTouch(touchEvent.changedTouches[t]); } touchEvent.preventDefault(); } /** * when a moving touch event occurs * @param touchEvent - the touch event being intercepted */ onTouchMove(touchEvent) { if (!this.videoElementProvider.isVideoReady()) { return; } _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'touch move', 6); this.emitTouchData('TouchMove', touchEvent.touches); touchEvent.preventDefault(); } emitTouchData(type, touches) { if (!this.videoElementProvider.isVideoReady()) { return; } const offset = this.videoElementProvider.getVideoParentElement().getBoundingClientRect(); const toStreamerHandlers = this.toStreamerMessagesProvider.toStreamerHandlers; for (let t = 0; t < touches.length; t++) { const numTouches = 1; // the number of touches to be sent this message const touch = touches[t]; const x = touch.clientX - offset.left; const y = touch.clientY - offset.top; _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), `F${this.fingerIds.get(touch.identifier)}=(${x}, ${y})`, 6); const coord = this.coordinateConverter.normalizeAndQuantizeUnsigned(x, y); switch (type) { case 'TouchStart': toStreamerHandlers.get('TouchStart')([ numTouches, coord.x, coord.y, this.fingerIds.get(touch.identifier), this.maxByteValue * touch.force, coord.inRange ? 1 : 0 ]); break; case 'TouchEnd': toStreamerHandlers.get('TouchEnd')([ numTouches, coord.x, coord.y, this.fingerIds.get(touch.identifier), this.maxByteValue * touch.force, coord.inRange ? 1 : 0 ]); break; case 'TouchMove': toStreamerHandlers.get('TouchMove')([ numTouches, coord.x, coord.y, this.fingerIds.get(touch.identifier), this.maxByteValue * touch.force, coord.inRange ? 1 : 0 ]); break; } } } } /***/ }), /***/ "./src/Inputs/XRGamepadController.ts": /*!*******************************************!*\ !*** ./src/Inputs/XRGamepadController.ts ***! \*******************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "XRGamepadController": () => (/* binding */ XRGamepadController) /* harmony export */ }); /* harmony import */ var _Util_WebXRUtils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Util/WebXRUtils */ "./src/Util/WebXRUtils.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * The class that handles the functionality of xrgamepads and controllers */ class XRGamepadController { /** * @param toStreamerMessagesProvider - Stream message instance */ constructor(toStreamerMessagesProvider) { this.toStreamerMessagesProvider = toStreamerMessagesProvider; this.controllers = []; } updateStatus(source, frame, refSpace) { if (source.gamepad) { const gamepadPose = frame.getPose(source.gripSpace, refSpace); if (!gamepadPose) { return; } let system = 0; if (source.profiles.includes('htc-vive')) { system = 1; } else if (source.profiles.includes('oculus-touch')) { system = 2; } // TODO (william.belcher): Add other profiles (Quest, Microsoft Mixed Reality, etc) this.toStreamerMessagesProvider.toStreamerHandlers.get('XRSystem')([ system ]); // Default: AnyHand (2) let handedness = 2; switch (source.handedness) { case 'left': handedness = 0; break; case 'right': handedness = 1; break; } // Send controller transform const matrix = gamepadPose.transform.matrix; const mat = []; for (let i = 0; i < 16; i++) { mat[i] = new Float32Array([matrix[i]])[0]; } // prettier-ignore this.toStreamerMessagesProvider.toStreamerHandlers.get('XRControllerTransform')([ mat[0], mat[4], mat[8], mat[12], mat[1], mat[5], mat[9], mat[13], mat[2], mat[6], mat[10], mat[14], mat[3], mat[7], mat[11], mat[15], handedness ]); // Handle controller buttons and axes if (this.controllers[handedness] === undefined) { this.controllers[handedness] = { prevState: undefined, currentState: undefined, id: undefined }; this.controllers[handedness].prevState = _Util_WebXRUtils__WEBPACK_IMPORTED_MODULE_0__.WebXRUtils.deepCopyGamepad(source.gamepad); } this.controllers[handedness].currentState = _Util_WebXRUtils__WEBPACK_IMPORTED_MODULE_0__.WebXRUtils.deepCopyGamepad(source.gamepad); const controller = this.controllers[handedness]; const currState = controller.currentState; const prevState = controller.prevState; // Iterate over buttons for (let i = 0; i < currState.buttons.length; i++) { const currButton = currState.buttons[i]; const prevButton = prevState.buttons[i]; if (currButton.pressed) { // press this.toStreamerMessagesProvider.toStreamerHandlers.get('XRButtonPressed')([handedness, i, prevButton.pressed ? 1 : 0]); } else if (!currButton.pressed && prevButton.pressed) { this.toStreamerMessagesProvider.toStreamerHandlers.get('XRButtonReleased')([handedness, i, 0]); } if (currButton.touched && !currButton.pressed) { // press this.toStreamerMessagesProvider.toStreamerHandlers.get('XRButtonPressed')([handedness, 3, prevButton.touched ? 1 : 0]); } else if (!currButton.touched && prevButton.touched) { this.toStreamerMessagesProvider.toStreamerHandlers.get('XRButtonReleased')([handedness, 3, 0]); } } // Iterate over gamepad axes for (let i = 0; i < currState.axes.length; i++) { this.toStreamerMessagesProvider.toStreamerHandlers.get('XRAnalog')([handedness, i, currState.axes[i]]); } this.controllers[handedness].prevState = currState; } } } /***/ }), /***/ "./src/Logger/Logger.ts": /*!******************************!*\ !*** ./src/Logger/Logger.ts ***! \******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "Logger": () => (/* binding */ Logger) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. class Logger { /** * Captures the stack and returns it * @returns the current stack */ static GetStackTrace() { const error = new Error(); let formattedStack = 'No Stack Available for this browser'; // format the error if (error.stack) { formattedStack = error.stack.toString().replace(/Error/g, ''); } return formattedStack; } /** * Set the log verbosity level */ static SetLoggerVerbosity(verboseLogLevel) { if (this.verboseLogLevel != null) { this.verboseLogLevel = verboseLogLevel; } } /** * The standard logging output * @param stack - the stack trace * @param message - the message to be logged * @param verbosity - the verbosity level */ static Log(stack, message, verbosity) { if (verbosity > this.verboseLogLevel) { return; } const returnString = `Level: Log\nMsg: ${message}\nCaller: ${stack}`; console.log(returnString); } /** * The standard logging output * @param stack - the stack trace * @param message - the message to be logged * @param verbosity - the verbosity level */ static Info(stack, message, verbosity) { if (verbosity > this.verboseLogLevel) { return; } const returnString = `Level: Info\nMsg: ${message}`; console.info(returnString); } /** * The standard logging output * @param stack - the stack trace * @param message - the message to be logged */ static Error(stack, message) { const returnString = `Level: Error\nMsg: ${message}\nCaller: ${stack}`; console.error(returnString); } /** * The standard logging output * @param stack - the stack trace * @param message - the message to be logged */ static Warning(stack, message) { const returnString = `Level: Warning\nCaller: ${stack}\nMsg: ${message}`; console.warn(returnString); } } Logger.verboseLogLevel = 5; /***/ }), /***/ "./src/PeerConnectionController/AggregatedStats.ts": /*!*********************************************************!*\ !*** ./src/PeerConnectionController/AggregatedStats.ts ***! \*********************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "AggregatedStats": () => (/* binding */ AggregatedStats) /* harmony export */ }); /* harmony import */ var _InboundRTPStats__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./InboundRTPStats */ "./src/PeerConnectionController/InboundRTPStats.ts"); /* harmony import */ var _DataChannelStats__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./DataChannelStats */ "./src/PeerConnectionController/DataChannelStats.ts"); /* harmony import */ var _CandidateStat__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./CandidateStat */ "./src/PeerConnectionController/CandidateStat.ts"); /* harmony import */ var _CandidatePairStats__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./CandidatePairStats */ "./src/PeerConnectionController/CandidatePairStats.ts"); /* harmony import */ var _OutBoundRTPStats__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./OutBoundRTPStats */ "./src/PeerConnectionController/OutBoundRTPStats.ts"); /* harmony import */ var _SessionStats__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./SessionStats */ "./src/PeerConnectionController/SessionStats.ts"); /* harmony import */ var _StreamStats__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./StreamStats */ "./src/PeerConnectionController/StreamStats.ts"); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); // Copyright Epic Games, Inc. All Rights Reserved. class AggregatedStats { constructor() { this.inboundVideoStats = new _InboundRTPStats__WEBPACK_IMPORTED_MODULE_0__.InboundVideoStats(); this.inboundAudioStats = new _InboundRTPStats__WEBPACK_IMPORTED_MODULE_0__.InboundAudioStats(); this.candidatePair = new _CandidatePairStats__WEBPACK_IMPORTED_MODULE_1__.CandidatePairStats(); this.DataChannelStats = new _DataChannelStats__WEBPACK_IMPORTED_MODULE_2__.DataChannelStats(); this.outBoundVideoStats = new _OutBoundRTPStats__WEBPACK_IMPORTED_MODULE_3__.OutBoundVideoStats(); this.sessionStats = new _SessionStats__WEBPACK_IMPORTED_MODULE_4__.SessionStats(); this.streamStats = new _StreamStats__WEBPACK_IMPORTED_MODULE_5__.StreamStats(); this.codecs = new Map(); } /** * Gather all the information from the RTC Peer Connection Report * @param rtcStatsReport - RTC Stats Report */ processStats(rtcStatsReport) { this.localCandidates = new Array(); this.remoteCandidates = new Array(); rtcStatsReport.forEach((stat) => { const type = stat.type; switch (type) { case 'candidate-pair': this.handleCandidatePair(stat); break; case 'certificate': break; case 'codec': this.handleCodec(stat); break; case 'data-channel': this.handleDataChannel(stat); break; case 'inbound-rtp': this.handleInBoundRTP(stat); break; case 'local-candidate': this.handleLocalCandidate(stat); break; case 'media-source': break; case 'media-playout': break; case 'outbound-rtp': break; case 'peer-connection': break; case 'remote-candidate': this.handleRemoteCandidate(stat); break; case 'remote-inbound-rtp': break; case 'remote-outbound-rtp': this.handleRemoteOutBound(stat); break; case 'track': this.handleTrack(stat); break; case 'transport': break; case 'stream': this.handleStream(stat); break; default: _Logger_Logger__WEBPACK_IMPORTED_MODULE_6__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_6__.Logger.GetStackTrace(), 'unhandled Stat Type'); _Logger_Logger__WEBPACK_IMPORTED_MODULE_6__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_6__.Logger.GetStackTrace(), stat); break; } }); } /** * Process stream stats data from webrtc * * @param stat - the stats coming in from webrtc */ handleStream(stat) { this.streamStats = stat; } /** * Process the Ice Candidate Pair Data * @param stat - the stats coming in from ice candidates */ handleCandidatePair(stat) { this.candidatePair.bytesReceived = stat.bytesReceived; this.candidatePair.bytesSent = stat.bytesSent; this.candidatePair.localCandidateId = stat.localCandidateId; this.candidatePair.remoteCandidateId = stat.remoteCandidateId; this.candidatePair.nominated = stat.nominated; this.candidatePair.readable = stat.readable; this.candidatePair.selected = stat.selected; this.candidatePair.writable = stat.writable; this.candidatePair.state = stat.state; this.candidatePair.currentRoundTripTime = stat.currentRoundTripTime; } /** * Process the Data Channel Data * @param stat - the stats coming in from the data channel */ handleDataChannel(stat) { this.DataChannelStats.bytesReceived = stat.bytesReceived; this.DataChannelStats.bytesSent = stat.bytesSent; this.DataChannelStats.dataChannelIdentifier = stat.dataChannelIdentifier; this.DataChannelStats.id = stat.id; this.DataChannelStats.label = stat.label; this.DataChannelStats.messagesReceived = stat.messagesReceived; this.DataChannelStats.messagesSent = stat.messagesSent; this.DataChannelStats.protocol = stat.protocol; this.DataChannelStats.state = stat.state; this.DataChannelStats.timestamp = stat.timestamp; } /** * Process the Local Ice Candidate Data * @param stat - local stats */ handleLocalCandidate(stat) { const localCandidate = new _CandidateStat__WEBPACK_IMPORTED_MODULE_7__.CandidateStat(); localCandidate.label = 'local-candidate'; localCandidate.address = stat.address; localCandidate.port = stat.port; localCandidate.protocol = stat.protocol; localCandidate.candidateType = stat.candidateType; localCandidate.id = stat.id; this.localCandidates.push(localCandidate); } /** * Process the Remote Ice Candidate Data * @param stat - ice candidate stats */ handleRemoteCandidate(stat) { const RemoteCandidate = new _CandidateStat__WEBPACK_IMPORTED_MODULE_7__.CandidateStat(); RemoteCandidate.label = 'local-candidate'; RemoteCandidate.address = stat.address; RemoteCandidate.port = stat.port; RemoteCandidate.protocol = stat.protocol; RemoteCandidate.id = stat.id; RemoteCandidate.candidateType = stat.candidateType; this.remoteCandidates.push(RemoteCandidate); } /** * Process the Inbound RTP Audio and Video Data * @param stat - inbound rtp stats */ handleInBoundRTP(stat) { switch (stat.kind) { case 'video': // Need to convert to unknown first to remove an error around // InboundVideoStats having the bitrate member which isn't found on // the InboundRTPStats this.inboundVideoStats = stat; if (this.lastVideoStats != undefined) { this.inboundVideoStats.bitrate = (8 * (this.inboundVideoStats.bytesReceived - this.lastVideoStats.bytesReceived)) / (this.inboundVideoStats.timestamp - this.lastVideoStats.timestamp); this.inboundVideoStats.bitrate = Math.floor(this.inboundVideoStats.bitrate); } this.lastVideoStats = Object.assign({}, this.inboundVideoStats); break; case 'audio': // Need to convert to unknown first to remove an error around // InboundAudioStats having the bitrate member which isn't found on // the InboundRTPStats this.inboundAudioStats = stat; if (this.lastAudioStats != undefined) { this.inboundAudioStats.bitrate = (8 * (this.inboundAudioStats.bytesReceived - this.lastAudioStats.bytesReceived)) / (this.inboundAudioStats.timestamp - this.lastAudioStats.timestamp); this.inboundAudioStats.bitrate = Math.floor(this.inboundAudioStats.bitrate); } this.lastAudioStats = Object.assign({}, this.inboundAudioStats); break; default: _Logger_Logger__WEBPACK_IMPORTED_MODULE_6__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_6__.Logger.GetStackTrace(), 'Kind is not handled'); break; } } /** * Process the outbound RTP Audio and Video Data * @param stat - remote outbound stats */ handleRemoteOutBound(stat) { switch (stat.kind) { case 'video': this.outBoundVideoStats.bytesSent = stat.bytesSent; this.outBoundVideoStats.id = stat.id; this.outBoundVideoStats.localId = stat.localId; this.outBoundVideoStats.packetsSent = stat.packetsSent; this.outBoundVideoStats.remoteTimestamp = stat.remoteTimestamp; this.outBoundVideoStats.timestamp = stat.timestamp; break; case 'audio': break; default: break; } } /** * Process the Inbound Video Track Data * @param stat - video track stats */ handleTrack(stat) { // we only want to extract stats from the video track if (stat.type === 'track' && (stat.trackIdentifier === 'video_label' || stat.kind === 'video')) { this.inboundVideoStats.framesDropped = stat.framesDropped; this.inboundVideoStats.framesReceived = stat.framesReceived; this.inboundVideoStats.frameHeight = stat.frameHeight; this.inboundVideoStats.frameWidth = stat.frameWidth; } } handleCodec(stat) { const codecId = stat.id; const codecType = `${stat.mimeType .replace('video/', '') .replace('audio/', '')}${stat.sdpFmtpLine ? ` ${stat.sdpFmtpLine}` : ''}`; this.codecs.set(codecId, codecType); } handleSessionStatistics(videoStartTime, inputController, videoEncoderAvgQP) { const deltaTime = Date.now() - videoStartTime; this.sessionStats.runTime = new Date(deltaTime) .toISOString() .substr(11, 8) .toString(); const controlsStreamInput = inputController === null ? 'Not sent yet' : inputController ? 'true' : 'false'; this.sessionStats.controlsStreamInput = controlsStreamInput; this.sessionStats.videoEncoderAvgQP = videoEncoderAvgQP; } /** * Check if a value coming in from our stats is actually a number * @param value - the number to be checked */ isNumber(value) { return typeof value === 'number' && isFinite(value); } } /***/ }), /***/ "./src/PeerConnectionController/CandidatePairStats.ts": /*!************************************************************!*\ !*** ./src/PeerConnectionController/CandidatePairStats.ts ***! \************************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "CandidatePairStats": () => (/* binding */ CandidatePairStats) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. /** * ICE Candidate Pair Stats collected from the RTC Stats Report */ class CandidatePairStats { } /***/ }), /***/ "./src/PeerConnectionController/CandidateStat.ts": /*!*******************************************************!*\ !*** ./src/PeerConnectionController/CandidateStat.ts ***! \*******************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "CandidateStat": () => (/* binding */ CandidateStat) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. /** * ICE Candidate Stat collected from the RTC Stats Report */ class CandidateStat { } /***/ }), /***/ "./src/PeerConnectionController/DataChannelStats.ts": /*!**********************************************************!*\ !*** ./src/PeerConnectionController/DataChannelStats.ts ***! \**********************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "DataChannelStats": () => (/* binding */ DataChannelStats) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. /** * Data Channel Stats collected from the RTC Stats Report */ class DataChannelStats { } /***/ }), /***/ "./src/PeerConnectionController/InboundRTPStats.ts": /*!*********************************************************!*\ !*** ./src/PeerConnectionController/InboundRTPStats.ts ***! \*********************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "InboundAudioStats": () => (/* binding */ InboundAudioStats), /* harmony export */ "InboundRTPStats": () => (/* binding */ InboundRTPStats), /* harmony export */ "InboundVideoStats": () => (/* binding */ InboundVideoStats) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. /** * Inbound Audio Stats collected from the RTC Stats Report */ class InboundAudioStats { } /** * Inbound Video Stats collected from the RTC Stats Report */ class InboundVideoStats { } /** * Inbound Stats collected from the RTC Stats Report */ class InboundRTPStats { } /***/ }), /***/ "./src/PeerConnectionController/OutBoundRTPStats.ts": /*!**********************************************************!*\ !*** ./src/PeerConnectionController/OutBoundRTPStats.ts ***! \**********************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "OutBoundRTPStats": () => (/* binding */ OutBoundRTPStats), /* harmony export */ "OutBoundVideoStats": () => (/* binding */ OutBoundVideoStats) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. /** * Outbound Video Stats collected from the RTC Stats Report */ class OutBoundVideoStats { } /** * Outbound Stats collected from the RTC Stats Report */ class OutBoundRTPStats { } /***/ }), /***/ "./src/PeerConnectionController/PeerConnectionController.ts": /*!******************************************************************!*\ !*** ./src/PeerConnectionController/PeerConnectionController.ts ***! \******************************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "PeerConnectionController": () => (/* binding */ PeerConnectionController) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); /* harmony import */ var _Config_Config__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Config/Config */ "./src/Config/Config.ts"); /* harmony import */ var _AggregatedStats__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./AggregatedStats */ "./src/PeerConnectionController/AggregatedStats.ts"); /* harmony import */ var sdp__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! sdp */ "sdp"); /* harmony import */ var sdp__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(sdp__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _Util_RTCUtils__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../Util/RTCUtils */ "./src/Util/RTCUtils.ts"); // Copyright Epic Games, Inc. All Rights Reserved. var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; /** * Handles the Peer Connection */ class PeerConnectionController { /** * Create a new RTC Peer Connection client * @param options - Peer connection Options * @param config - The config for our PS experience. */ constructor(options, config, preferredCodec) { this.config = config; this.createPeerConnection(options, preferredCodec); } createPeerConnection(options, preferredCodec) { // Set the ICE transport to relay if TURN enabled if (this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_1__.Flags.ForceTURN)) { options.iceTransportPolicy = 'relay'; _Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.GetStackTrace(), 'Forcing TURN usage by setting ICE Transport Policy in peer connection config.'); } // build a new peer connection with the options this.peerConnection = new RTCPeerConnection(options); this.peerConnection.onsignalingstatechange = (ev) => this.handleSignalStateChange(ev); this.peerConnection.oniceconnectionstatechange = (ev) => this.handleIceConnectionStateChange(ev); this.peerConnection.onicegatheringstatechange = (ev) => this.handleIceGatheringStateChange(ev); this.peerConnection.ontrack = (ev) => this.handleOnTrack(ev); this.peerConnection.onicecandidate = (ev) => this.handleIceCandidate(ev); this.peerConnection.ondatachannel = (ev) => this.handleDataChannel(ev); this.aggregatedStats = new _AggregatedStats__WEBPACK_IMPORTED_MODULE_3__.AggregatedStats(); this.preferredCodec = preferredCodec; this.updateCodecSelection = true; } /** * Create an offer for the Web RTC handshake and send the offer to the signaling server via websocket * @param offerOptions - RTC Offer Options */ createOffer(offerOptions, config) { return __awaiter(this, void 0, void 0, function* () { _Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.GetStackTrace(), 'Create Offer', 6); const isLocalhostConnection = location.hostname === 'localhost' || location.hostname === '127.0.0.1'; const isHttpsConnection = location.protocol === 'https:'; let useMic = config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_1__.Flags.UseMic); if (useMic && !(isLocalhostConnection || isHttpsConnection)) { useMic = false; _Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.GetStackTrace(), 'Microphone access in the browser will not work if you are not on HTTPS or localhost. Disabling mic access.'); _Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.GetStackTrace(), "For testing you can enable HTTP microphone access Chrome by visiting chrome://flags/ and enabling 'unsafely-treat-insecure-origin-as-secure'"); } this.setupTransceiversAsync(useMic).finally(() => { var _a; (_a = this.peerConnection) === null || _a === void 0 ? void 0 : _a.createOffer(offerOptions).then((offer) => { var _a; this.showTextOverlayConnecting(); offer.sdp = this.mungeSDP(offer.sdp, useMic); (_a = this.peerConnection) === null || _a === void 0 ? void 0 : _a.setLocalDescription(offer); this.onSendWebRTCOffer(offer); }).catch(() => { this.showTextOverlaySetupFailure(); }); }); }); } /** * */ receiveOffer(offer, config) { var _a; return __awaiter(this, void 0, void 0, function* () { _Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.GetStackTrace(), 'Receive Offer', 6); (_a = this.peerConnection) === null || _a === void 0 ? void 0 : _a.setRemoteDescription(offer).then(() => { const isLocalhostConnection = location.hostname === 'localhost' || location.hostname === '127.0.0.1'; const isHttpsConnection = location.protocol === 'https:'; let useMic = config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_1__.Flags.UseMic); if (useMic && !(isLocalhostConnection || isHttpsConnection)) { useMic = false; _Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.GetStackTrace(), 'Microphone access in the browser will not work if you are not on HTTPS or localhost. Disabling mic access.'); _Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.GetStackTrace(), "For testing you can enable HTTP microphone access Chrome by visiting chrome://flags/ and enabling 'unsafely-treat-insecure-origin-as-secure'"); } this.setupTransceiversAsync(useMic).finally(() => { var _a; (_a = this.peerConnection) === null || _a === void 0 ? void 0 : _a.createAnswer().then((Answer) => { var _a; Answer.sdp = this.mungeSDP(Answer.sdp, useMic); return (_a = this.peerConnection) === null || _a === void 0 ? void 0 : _a.setLocalDescription(Answer); }).then(() => { var _a; this.onSendWebRTCAnswer((_a = this.peerConnection) === null || _a === void 0 ? void 0 : _a.currentLocalDescription); }).catch(() => { _Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.GetStackTrace(), 'createAnswer() failed'); }); }); }); // Ugly syntax, but this achieves the intersection of the browser supported list and the UE supported list this.config.setOptionSettingOptions(_Config_Config__WEBPACK_IMPORTED_MODULE_1__.OptionParameters.PreferredCodec, this.parseAvailableCodecs(offer).filter((value) => this.config .getSettingOption(_Config_Config__WEBPACK_IMPORTED_MODULE_1__.OptionParameters.PreferredCodec) .options.includes(value))); }); } /** * Set the Remote Descriptor from the signaling server to the RTC Peer Connection * @param answer - RTC Session Descriptor from the Signaling Server */ receiveAnswer(answer) { var _a; (_a = this.peerConnection) === null || _a === void 0 ? void 0 : _a.setRemoteDescription(answer); // Ugly syntax, but this achieves the intersection of the browser supported list and the UE supported list this.config.setOptionSettingOptions(_Config_Config__WEBPACK_IMPORTED_MODULE_1__.OptionParameters.PreferredCodec, this.parseAvailableCodecs(answer).filter((value) => this.config .getSettingOption(_Config_Config__WEBPACK_IMPORTED_MODULE_1__.OptionParameters.PreferredCodec) .options.includes(value))); } /** * Generate Aggregated Stats and then fire a onVideo Stats event */ generateStats() { var _a; (_a = this.peerConnection) === null || _a === void 0 ? void 0 : _a.getStats(null).then((StatsData) => { this.aggregatedStats.processStats(StatsData); this.onVideoStats(this.aggregatedStats); // Update the preferred codec selection based on what was actually negotiated if (this.updateCodecSelection) { this.config.setOptionSettingValue(_Config_Config__WEBPACK_IMPORTED_MODULE_1__.OptionParameters.PreferredCodec, this.aggregatedStats.codecs.get(this.aggregatedStats.inboundVideoStats.codecId)); } }); } /** * Close The Peer Connection */ close() { if (this.peerConnection) { this.peerConnection.close(); this.peerConnection = null; } } /** * Modify the Session Descriptor * @param sdp - Session Descriptor as a string * @param useMic - Is the microphone in use * @returns A modified Session Descriptor */ mungeSDP(sdp, useMic) { let mungedSDP = sdp.replace(/(a=fmtp:\d+ .*level-asymmetry-allowed=.*)\r\n/gm, '$1;x-google-start-bitrate=10000;x-google-max-bitrate=100000\r\n'); // set max bitrate to highest bitrate Opus supports let audioSDP = 'maxaveragebitrate=510000;'; if (useMic) { // set the max capture rate to 48khz (so we can send high quality audio from mic) audioSDP += 'sprop-maxcapturerate=48000;'; } // Force mono or stereo based on whether ?forceMono was passed or not audioSDP += this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_1__.Flags.ForceMonoAudio) ? 'stereo=0;' : 'stereo=1;'; // enable in-band forward error correction for opus audio audioSDP += 'useinbandfec=1'; // We use the line 'useinbandfec=1' (which Opus uses) to set our Opus specific audio parameters. mungedSDP = mungedSDP.replace('useinbandfec=1', audioSDP); return mungedSDP; } /** * When a Ice Candidate is received add to the RTC Peer Connection * @param iceCandidate - RTC Ice Candidate from the Signaling Server */ handleOnIce(iceCandidate) { var _a; _Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.GetStackTrace(), 'peerconnection handleOnIce', 6); // // if forcing TURN, reject any candidates not relay if (this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_1__.Flags.ForceTURN)) { // check if no relay address is found, if so, we are assuming it means no TURN server if (iceCandidate.candidate.indexOf('relay') < 0) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.Info(_Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.GetStackTrace(), `Dropping candidate because it was not TURN relay. | Type= ${iceCandidate.type} | Protocol= ${iceCandidate.protocol} | Address=${iceCandidate.address} | Port=${iceCandidate.port} |`, 6); return; } } (_a = this.peerConnection) === null || _a === void 0 ? void 0 : _a.addIceCandidate(iceCandidate); } /** * When the RTC Peer Connection Signaling server state Changes * @param state - Signaling Server State Change Event */ handleSignalStateChange(state) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.GetStackTrace(), 'signaling state change: ' + state, 6); } /** * Handle when the Ice Connection State Changes * @param state - Ice Connection State */ handleIceConnectionStateChange(state) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.GetStackTrace(), 'ice connection state change: ' + state, 6); this.onIceConnectionStateChange(state); } /** * Handle when the Ice Gathering State Changes * @param state - Ice Gathering State Change */ handleIceGatheringStateChange(state) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_2__.Logger.GetStackTrace(), 'ice gathering state change: ' + JSON.stringify(state), 6); } /** * Activates the onTrack method * @param event - The webRtc track event */ handleOnTrack(event) { this.onTrack(event); } /** * Activates the onPeerIceCandidate * @param event - The peer ice candidate */ handleIceCandidate(event) { this.onPeerIceCandidate(event); } /** * Activates the onDataChannel * @param event - The peer's data channel */ handleDataChannel(event) { this.onDataChannel(event); } /** * An override method for onTrack for use outside of the PeerConnectionController * @param trackEvent - The webRtc track event */ // eslint-disable-next-line @typescript-eslint/no-unused-vars onTrack(trackEvent) { // Default Functionality: Do Nothing } /** * An override method for onIceConnectionStateChange for use outside of the PeerConnectionController * @param event - The webRtc iceconnectionstatechange event */ // eslint-disable-next-line @typescript-eslint/no-unused-vars onIceConnectionStateChange(event) { // Default Functionality: Do Nothing } /** * An override method for onPeerIceCandidate for use outside of the PeerConnectionController * @param peerConnectionIceEvent - The peer ice candidate */ // eslint-disable-next-line @typescript-eslint/no-unused-vars onPeerIceCandidate(peerConnectionIceEvent) { // Default Functionality: Do Nothing } /** * An override method for onDataChannel for use outside of the PeerConnectionController * @param datachannelEvent - The peer's data channel */ // eslint-disable-next-line @typescript-eslint/no-unused-vars onDataChannel(datachannelEvent) { // Default Functionality: Do Nothing } /** * Setup tracks on the RTC Peer Connection * @param useMic - is mic in use */ setupTransceiversAsync(useMic) { var _a, _b, _c, _d, _e, _f, _g, _h, _j; return __awaiter(this, void 0, void 0, function* () { const hasTransceivers = ((_a = this.peerConnection) === null || _a === void 0 ? void 0 : _a.getTransceivers().length) > 0; // Setup a transceiver for getting UE video (_b = this.peerConnection) === null || _b === void 0 ? void 0 : _b.addTransceiver('video', { direction: 'recvonly' }); // We can only set preferrec codec on Chrome if (RTCRtpReceiver.getCapabilities && this.preferredCodec != '') { for (const transceiver of (_d = (_c = this.peerConnection) === null || _c === void 0 ? void 0 : _c.getTransceivers()) !== null && _d !== void 0 ? _d : []) { if (transceiver && transceiver.receiver && transceiver.receiver.track && transceiver.receiver.track.kind === 'video' && // As of 06/2023, FireFox has added RTCRtpReceiver.getCapabilities, but hasn't added the ability to set codec preferences transceiver.setCodecPreferences) { const preferredRTPCodec = this.preferredCodec.split(' '); const codecs = [ { mimeType: 'video/' + preferredRTPCodec[0] /* Name */, clockRate: 90000, sdpFmtpLine: preferredRTPCodec[1] /* sdpFmtpLine */ ? preferredRTPCodec[1] : '' } ]; this.config .getSettingOption(_Config_Config__WEBPACK_IMPORTED_MODULE_1__.OptionParameters.PreferredCodec) .options.filter((option) => { // Remove the preferred codec from the list of possible codecs as we've set it already return option != this.preferredCodec; }) .forEach((option) => { // Ammend the rest of the browsers supported codecs const altCodec = option.split(' '); codecs.push({ mimeType: 'video/' + altCodec[0] /* Name */, clockRate: 90000, sdpFmtpLine: altCodec[1] /* sdpFmtpLine */ ? altCodec[1] : '' }); }); for (const codec of codecs) { if (codec.sdpFmtpLine === '') { // We can't dynamically add members to the codec, so instead remove the field if it's empty delete codec.sdpFmtpLine; } } transceiver.setCodecPreferences(codecs); } } } // Setup a transceiver for sending mic audio to UE and receiving audio from UE if (!useMic) { (_e = this.peerConnection) === null || _e === void 0 ? void 0 : _e.addTransceiver('audio', { direction: 'recvonly' }); } else { // set the audio options based on mic usage const audioOptions = { autoGainControl: false, channelCount: 1, echoCancellation: false, latency: 0, noiseSuppression: false, sampleRate: 48000, sampleSize: 16, volume: 1.0 }; // set the media send options const mediaSendOptions = { video: false, audio: audioOptions }; // Note using mic on android chrome requires SSL or chrome://flags/ "unsafely-treat-insecure-origin-as-secure" const stream = yield navigator.mediaDevices.getUserMedia(mediaSendOptions); if (stream) { if (hasTransceivers) { for (const transceiver of (_g = (_f = this.peerConnection) === null || _f === void 0 ? void 0 : _f.getTransceivers()) !== null && _g !== void 0 ? _g : []) { if (_Util_RTCUtils__WEBPACK_IMPORTED_MODULE_4__.RTCUtils.canTransceiverReceiveAudio(transceiver)) { for (const track of stream.getTracks()) { if (track.kind && track.kind == 'audio') { transceiver.sender.replaceTrack(track); transceiver.direction = 'sendrecv'; } } } } } else { for (const track of stream.getTracks()) { if (track.kind && track.kind == 'audio') { (_h = this.peerConnection) === null || _h === void 0 ? void 0 : _h.addTransceiver(track, { direction: 'sendrecv' }); } } } } else { (_j = this.peerConnection) === null || _j === void 0 ? void 0 : _j.addTransceiver('audio', { direction: 'recvonly' }); } } }); } /** * And override event for when the video stats are fired * @param event - Aggregated Stats */ // eslint-disable-next-line @typescript-eslint/no-unused-vars onVideoStats(event) { // Default Functionality: Do Nothing } /** * Event to send the RTC offer to the Signaling server * @param offer - RTC Offer */ // eslint-disable-next-line @typescript-eslint/no-unused-vars onSendWebRTCOffer(offer) { // Default Functionality: Do Nothing } /** * Event to send the RTC Answer to the Signaling server * @param answer - RTC Answer */ // eslint-disable-next-line @typescript-eslint/no-unused-vars onSendWebRTCAnswer(answer) { // Default Functionality: Do Nothing } /** * An override for showing the Peer connection connecting Overlay */ showTextOverlayConnecting() { // Default Functionality: Do Nothing } /** * An override for showing the Peer connection Failed overlay */ showTextOverlaySetupFailure() { // Default Functionality: Do Nothing } parseAvailableCodecs(rtcSessionDescription) { // No point in updating the available codecs if on FF if (!RTCRtpReceiver.getCapabilities) return ['Only available on Chrome']; const ueSupportedCodecs = []; const sections = (0,sdp__WEBPACK_IMPORTED_MODULE_0__.splitSections)(rtcSessionDescription.sdp); // discard the session information as we only want media related info sections.shift(); sections.forEach((mediaSection) => { const { codecs } = (0,sdp__WEBPACK_IMPORTED_MODULE_0__.parseRtpParameters)(mediaSection); // Filter only for VPX / H26X / AV1 const matcher = /(VP\d|H26\d|AV1).*/; codecs.forEach((c) => { const str = c.name + ' ' + Object.keys(c.parameters || {}) .map((p) => p + '=' + c.parameters[p]) .join(';'); const match = matcher.exec(str); if (match !== null) { if (c.name == 'VP9') { // UE answers don't specify profile but we know we want profile 0 c.parameters = { 'profile-id': '0' }; } const codecStr = c.name + ' ' + Object.keys(c.parameters || {}) .map((p) => p + '=' + c.parameters[p]) .join(';'); ueSupportedCodecs.push(codecStr); } }); }); return ueSupportedCodecs; } } /***/ }), /***/ "./src/PeerConnectionController/SessionStats.ts": /*!******************************************************!*\ !*** ./src/PeerConnectionController/SessionStats.ts ***! \******************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "SessionStats": () => (/* binding */ SessionStats) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. /** * Session statistics */ class SessionStats { } /***/ }), /***/ "./src/PeerConnectionController/StreamStats.ts": /*!*****************************************************!*\ !*** ./src/PeerConnectionController/StreamStats.ts ***! \*****************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "StreamStats": () => (/* binding */ StreamStats) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. /** * Class to hold the stream stats data coming in from webRtc */ class StreamStats { } /***/ }), /***/ "./src/PixelStreaming/PixelStreaming.ts": /*!**********************************************!*\ !*** ./src/PixelStreaming/PixelStreaming.ts ***! \**********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "PixelStreaming": () => (/* binding */ PixelStreaming) /* harmony export */ }); /* harmony import */ var _Config_Config__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../Config/Config */ "./src/Config/Config.ts"); /* harmony import */ var _WebRtcPlayer_WebRtcPlayerController__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../WebRtcPlayer/WebRtcPlayerController */ "./src/WebRtcPlayer/WebRtcPlayerController.ts"); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); /* harmony import */ var _UI_OnScreenKeyboard__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../UI/OnScreenKeyboard */ "./src/UI/OnScreenKeyboard.ts"); /* harmony import */ var _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Util/EventEmitter */ "./src/Util/EventEmitter.ts"); /* harmony import */ var _WebXR_WebXRController__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../WebXR/WebXRController */ "./src/WebXR/WebXRController.ts"); /* harmony import */ var _UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../UeInstanceMessage/StreamMessageController */ "./src/UeInstanceMessage/StreamMessageController.ts"); /* harmony import */ var _DataChannel_DataChannelLatencyTestController__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../DataChannel/DataChannelLatencyTestController */ "./src/DataChannel/DataChannelLatencyTestController.ts"); /* harmony import */ var _Util_RTCUtils__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../Util/RTCUtils */ "./src/Util/RTCUtils.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * The key class for the browser side of a Pixel Streaming application, it includes: * WebRTC handling, XR support, input handling, and emitters for lifetime and state change events. * Users are encouraged to use this class as is, through composition, or extend it. In any case, * this will likely be the core of your Pixel Streaming experience in terms of functionality. */ class PixelStreaming { /** * @param config - A newly instantiated config object * @param overrides - Parameters to override default behaviour * returns the base Pixel streaming object */ constructor(config, overrides) { this.allowConsoleCommands = false; this.config = config; if (overrides === null || overrides === void 0 ? void 0 : overrides.videoElementParent) { this._videoElementParent = overrides.videoElementParent; } this._eventEmitter = new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.EventEmitter(); this.configureSettings(); // setup WebRTC this.setWebRtcPlayerController(new _WebRtcPlayer_WebRtcPlayerController__WEBPACK_IMPORTED_MODULE_1__.WebRtcPlayerController(this.config, this)); // Onscreen keyboard this.onScreenKeyboardHelper = new _UI_OnScreenKeyboard__WEBPACK_IMPORTED_MODULE_2__.OnScreenKeyboard(this.videoElementParent); this.onScreenKeyboardHelper.unquantizeAndDenormalizeUnsigned = (x, y) => this._webRtcController.requestUnquantizedAndDenormalizeUnsigned(x, y); this._activateOnScreenKeyboard = (command) => this.onScreenKeyboardHelper.showOnScreenKeyboard(command); this._webXrController = new _WebXR_WebXRController__WEBPACK_IMPORTED_MODULE_3__.WebXRController(this._webRtcController); } /** * Gets the element that contains the video stream element. */ get videoElementParent() { if (!this._videoElementParent) { this._videoElementParent = document.createElement('div'); this._videoElementParent.id = 'videoElementParent'; } return this._videoElementParent; } /** * Configure the settings with on change listeners and any additional per experience settings. */ configureSettings() { this.config._addOnSettingChangedListener(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.Flags.IsQualityController, (wantsQualityController) => { // If the setting has been set to true (either programatically or the user has flicked the toggle) // and we aren't currently quality controller, send the request if (wantsQualityController === true && !this._webRtcController.isQualityController) { this._webRtcController.sendRequestQualityControlOwnership(); } }); this.config._addOnSettingChangedListener(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.Flags.AFKDetection, (isAFKEnabled) => { this._webRtcController.setAfkEnabled(isAFKEnabled); }); this.config._addOnSettingChangedListener(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.Flags.MatchViewportResolution, () => { this._webRtcController.videoPlayer.updateVideoStreamSize(); }); this.config._addOnSettingChangedListener(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.Flags.HoveringMouseMode, (isHoveringMouse) => { this.config.setFlagLabel(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.Flags.HoveringMouseMode, `Control Scheme: ${isHoveringMouse ? 'Hovering' : 'Locked'} Mouse`); this._webRtcController.setMouseInputEnabled(this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.Flags.MouseInput)); }); // user input this.config._addOnSettingChangedListener(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.Flags.KeyboardInput, (isEnabled) => { this._webRtcController.setKeyboardInputEnabled(isEnabled); }); this.config._addOnSettingChangedListener(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.Flags.MouseInput, (isEnabled) => { this._webRtcController.setMouseInputEnabled(isEnabled); }); this.config._addOnSettingChangedListener(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.Flags.TouchInput, (isEnabled) => { this._webRtcController.setTouchInputEnabled(isEnabled); }); this.config._addOnSettingChangedListener(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.Flags.GamepadInput, (isEnabled) => { this._webRtcController.setGamePadInputEnabled(isEnabled); }); // encoder settings this.config._addOnNumericSettingChangedListener(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.MinQP, (newValue) => { _Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.GetStackTrace(), '-------- Sending MinQP --------', 7); this._webRtcController.sendEncoderMinQP(newValue); _Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.GetStackTrace(), '-------------------------------------------', 7); }); this.config._addOnNumericSettingChangedListener(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.MaxQP, (newValue) => { _Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.GetStackTrace(), '-------- Sending encoder settings --------', 7); this._webRtcController.sendEncoderMaxQP(newValue); _Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.GetStackTrace(), '-------------------------------------------', 7); }); // WebRTC settings this.config._addOnNumericSettingChangedListener(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.WebRTCMinBitrate, (newValue) => { _Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.GetStackTrace(), '-------- Sending web rtc settings --------', 7); this._webRtcController.sendWebRTCMinBitrate(newValue * 1000 /* kbps to bps */); _Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.GetStackTrace(), '-------------------------------------------', 7); }); this.config._addOnNumericSettingChangedListener(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.WebRTCMaxBitrate, (newValue) => { _Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.GetStackTrace(), '-------- Sending web rtc settings --------', 7); this._webRtcController.sendWebRTCMaxBitrate(newValue * 1000 /* kbps to bps */); _Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.GetStackTrace(), '-------------------------------------------', 7); }); this.config._addOnNumericSettingChangedListener(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.WebRTCFPS, (newValue) => { _Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.GetStackTrace(), '-------- Sending web rtc settings --------', 7); this._webRtcController.sendWebRTCFps(newValue); _Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.GetStackTrace(), '-------------------------------------------', 7); }); this.config._addOnOptionSettingChangedListener(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.OptionParameters.PreferredCodec, (newValue) => { if (this._webRtcController) { this._webRtcController.setPreferredCodec(newValue); } }); this.config._registerOnChangeEvents(this._eventEmitter); } /** * Activate the on screen keyboard when receiving the command from the streamer * @param command - the keyboard command */ // eslint-disable-next-line @typescript-eslint/no-unused-vars _activateOnScreenKeyboard(command) { throw new Error('Method not implemented.'); } /** * Set the input control ownership * @param inputControlOwnership - does the user have input control ownership */ _onInputControlOwnership(inputControlOwnership) { this._inputController = inputControlOwnership; } /** * Instantiate the WebRTCPlayerController interface to provide WebRTCPlayerController functionality within this class and set up anything that requires it * @param webRtcPlayerController - a WebRtcPlayerController controller instance */ setWebRtcPlayerController(webRtcPlayerController) { this._webRtcController = webRtcPlayerController; this._webRtcController.setPreferredCodec(this.config.getSettingOption(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.OptionParameters.PreferredCodec) .selected); this._webRtcController.resizePlayerStyle(); // connect if auto connect flag is enabled this.checkForAutoConnect(); } /** * Connect to signaling server. */ connect() { this._eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.StreamPreConnectEvent()); this._webRtcController.connectToSignallingServer(); } /** * Reconnects to the signaling server. If connection is up, disconnects first * before establishing a new connection */ reconnect() { this._eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.StreamReconnectEvent()); this._webRtcController.tryReconnect("Reconnecting..."); } /** * Disconnect from the signaling server and close open peer connections. */ disconnect() { this._eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.StreamPreDisconnectEvent()); this._webRtcController.close(); } /** * Play the stream. Can be called only after a peer connection has been established. */ play() { this._onStreamLoading(); this._webRtcController.playStream(); } /** * Auto connect if AutoConnect flag is enabled */ checkForAutoConnect() { // set up if the auto play will be used or regular click to start if (this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.Flags.AutoConnect)) { // if autoplaying show an info overlay while while waiting for the connection to begin this._onWebRtcAutoConnect(); this._webRtcController.connectToSignallingServer(); } } /** * Will unmute the microphone track which is sent to Unreal Engine. * By default, will only unmute an existing mic track. * * @param forceEnable Can be used for cases when this object wasn't initialized with a mic track. * If this parameter is true, the connection will be restarted with a microphone. * Warning: this takes some time, as a full renegotiation and reconnection will happen. */ unmuteMicrophone(forceEnable = false) { // If there's an existing mic track, we just set muted state if (this.config.isFlagEnabled('UseMic')) { this.setMicrophoneMuted(false); return; } // If there's no pre-existing mic track, and caller is ok with full reset, we enable and reset if (forceEnable) { this.config.setFlagEnabled("UseMic", true); this.reconnect(); return; } // If we prefer not to force a reconnection, just warn the user that this operation didn't happen _Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.Warning(_Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.GetStackTrace(), 'Trying to unmute mic, but PixelStreaming was initialized with no microphone track. Call with forceEnable == true to re-connect with a mic track.'); } muteMicrophone() { if (this.config.isFlagEnabled('UseMic')) { this.setMicrophoneMuted(true); return; } // If there wasn't a mic track, just let user know there's nothing to mute _Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.Info(_Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.GetStackTrace(), 'Trying to mute mic, but PixelStreaming has no microphone track, so sending sound is already disabled.'); } setMicrophoneMuted(mute) { var _a, _b, _c, _d; for (const transceiver of (_d = (_c = (_b = (_a = this._webRtcController) === null || _a === void 0 ? void 0 : _a.peerConnectionController) === null || _b === void 0 ? void 0 : _b.peerConnection) === null || _c === void 0 ? void 0 : _c.getTransceivers()) !== null && _d !== void 0 ? _d : []) { if (_Util_RTCUtils__WEBPACK_IMPORTED_MODULE_6__.RTCUtils.canTransceiverSendAudio(transceiver)) { transceiver.sender.track.enabled = !mute; } } } /** * Emit an event on auto connecting */ _onWebRtcAutoConnect() { this._eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.WebRtcAutoConnectEvent()); } /** * Set up functionality to happen when receiving a webRTC answer */ _onWebRtcSdp() { this._eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.WebRtcSdpEvent()); } /** * Emits a StreamLoading event */ _onStreamLoading() { this._eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.StreamLoadingEvent()); } /** * Event fired when the video is disconnected - emits given eventString or an override * message from webRtcController if one has been set * @param eventString - a string describing why the connection closed * @param allowClickToReconnect - true if we want to allow the user to retry the connection with a click */ _onDisconnect(eventString, allowClickToReconnect) { this._eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.WebRtcDisconnectedEvent({ eventString: eventString, allowClickToReconnect: allowClickToReconnect })); } /** * Handles when Web Rtc is connecting */ _onWebRtcConnecting() { this._eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.WebRtcConnectingEvent()); } /** * Handles when Web Rtc has connected */ _onWebRtcConnected() { this._eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.WebRtcConnectedEvent()); } /** * Handles when Web Rtc fails to connect */ _onWebRtcFailed() { this._eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.WebRtcFailedEvent()); } /** * Handle when the Video has been Initialized */ _onVideoInitialized() { this._eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.VideoInitializedEvent()); this._videoStartTime = Date.now(); } /** * Set up functionality to happen when receiving latency test results * @param latency - latency test results object */ _onLatencyTestResult(latencyTimings) { this._eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.LatencyTestResultEvent({ latencyTimings })); } _onDataChannelLatencyTestResponse(response) { this._eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.DataChannelLatencyTestResponseEvent({ response })); } /** * Set up functionality to happen when receiving video statistics * @param videoStats - video statistics as a aggregate stats object */ _onVideoStats(videoStats) { // Duration if (!this._videoStartTime || this._videoStartTime === undefined) { this._videoStartTime = Date.now(); } videoStats.handleSessionStatistics(this._videoStartTime, this._inputController, this._webRtcController.videoAvgQp); this._eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.StatsReceivedEvent({ aggregatedStats: videoStats })); } /** * Set up functionality to happen when calculating the average video encoder qp * @param QP - the quality number of the stream */ _onVideoEncoderAvgQP(QP) { this._eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.VideoEncoderAvgQPEvent({ avgQP: QP })); } /** * Set up functionality to happen when receiving and handling initial settings for the UE app * @param settings - initial UE app settings */ _onInitialSettings(settings) { var _a; this._eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.InitialSettingsEvent({ settings })); if (settings.PixelStreamingSettings) { this.allowConsoleCommands = (_a = settings.PixelStreamingSettings.AllowPixelStreamingCommands) !== null && _a !== void 0 ? _a : false; if (this.allowConsoleCommands === false) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.Info(_Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.GetStackTrace(), '-AllowPixelStreamingCommands=false, sending arbitrary console commands from browser to UE is disabled.'); } } const useUrlParams = this.config.useUrlParams; const urlParams = new URLSearchParams(window.location.search); if (settings.EncoderSettings) { this.config.setNumericSetting(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.MinQP, // If a setting is set in the URL, make sure we respect that value as opposed to what the application sends us (useUrlParams && urlParams.has(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.MinQP)) ? Number.parseInt(urlParams.get(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.MinQP)) : settings.EncoderSettings.MinQP); this.config.setNumericSetting(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.MaxQP, (useUrlParams && urlParams.has(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.MaxQP)) ? Number.parseInt(urlParams.get(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.MaxQP)) : settings.EncoderSettings.MaxQP); } if (settings.WebRTCSettings) { this.config.setNumericSetting(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.WebRTCMinBitrate, (useUrlParams && urlParams.has(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.WebRTCMinBitrate)) ? Number.parseInt(urlParams.get(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.WebRTCMinBitrate)) : settings.WebRTCSettings.MinBitrate / 1000 /* bps to kbps */); this.config.setNumericSetting(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.WebRTCMaxBitrate, (useUrlParams && urlParams.has(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.WebRTCMaxBitrate)) ? Number.parseInt(urlParams.get(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.WebRTCMaxBitrate)) : settings.WebRTCSettings.MaxBitrate / 1000 /* bps to kbps */); this.config.setNumericSetting(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.WebRTCFPS, (useUrlParams && urlParams.has(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.WebRTCFPS)) ? Number.parseInt(urlParams.get(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.NumericParameters.WebRTCFPS)) : settings.WebRTCSettings.FPS); } } /** * Set up functionality to happen when setting quality control ownership of a stream * @param hasQualityOwnership - does this user have quality ownership of the stream true / false */ _onQualityControlOwnership(hasQualityOwnership) { this.config.setFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_4__.Flags.IsQualityController, hasQualityOwnership); } _onPlayerCount(playerCount) { this._eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.PlayerCountEvent({ count: playerCount })); } /** * Request a connection latency test. * NOTE: There are plans to refactor all request* functions. Expect changes if you use this! * @returns */ requestLatencyTest() { if (!this._webRtcController.videoPlayer.isVideoReady()) { return false; } this._webRtcController.sendLatencyTest(); return true; } /** * Request a data channel latency test. * NOTE: There are plans to refactor all request* functions. Expect changes if you use this! */ requestDataChannelLatencyTest(config) { if (!this._webRtcController.videoPlayer.isVideoReady()) { return false; } if (!this._dataChannelLatencyTestController) { this._dataChannelLatencyTestController = new _DataChannel_DataChannelLatencyTestController__WEBPACK_IMPORTED_MODULE_7__.DataChannelLatencyTestController(this._webRtcController.sendDataChannelLatencyTest.bind(this._webRtcController), (result) => { this._eventEmitter.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_0__.DataChannelLatencyTestResultEvent({ result })); }); this.addEventListener("dataChannelLatencyTestResponse", ({ data: { response } }) => { this._dataChannelLatencyTestController.receive(response); }); } return this._dataChannelLatencyTestController.start(config); } /** * Request for the UE application to show FPS counter. * NOTE: There are plans to refactor all request* functions. Expect changes if you use this! * @returns */ requestShowFps() { if (!this._webRtcController.videoPlayer.isVideoReady()) { return false; } this._webRtcController.sendShowFps(); return true; } /** * Request for a new IFrame from the UE application. * NOTE: There are plans to refactor all request* functions. Expect changes if you use this! * @returns */ requestIframe() { if (!this._webRtcController.videoPlayer.isVideoReady()) { return false; } this._webRtcController.sendIframeRequest(); return true; } /** * Send data to UE application. The data will be run through JSON.stringify() so e.g. strings * and any serializable plain JSON objects with no recurrence can be sent. * @returns true if succeeded, false if rejected */ emitUIInteraction(descriptor) { if (!this._webRtcController.videoPlayer.isVideoReady()) { return false; } this._webRtcController.emitUIInteraction(descriptor); return true; } /** * Send a command to UE application. Blocks ConsoleCommand descriptors unless UE * has signaled that it allows console commands. * @returns true if succeeded, false if rejected */ emitCommand(descriptor) { if (!this._webRtcController.videoPlayer.isVideoReady()) { return false; } if (!this.allowConsoleCommands && 'ConsoleCommand' in descriptor) { return false; } this._webRtcController.emitCommand(descriptor); return true; } /** * Send a console command to UE application. Only allowed if UE has signaled that it allows * console commands. * @returns true if succeeded, false if rejected */ emitConsoleCommand(command) { if (!this.allowConsoleCommands || !this._webRtcController.videoPlayer.isVideoReady()) { return false; } this._webRtcController.emitConsoleCommand(command); return true; } /** * Add a UE -> browser response event listener * @param name - The name of the response handler * @param listener - The method to be activated when a message is received */ addResponseEventListener(name, listener) { this._webRtcController.responseController.addResponseEventListener(name, listener); } /** * Remove a UE -> browser response event listener * @param name - The name of the response handler */ removeResponseEventListener(name) { this._webRtcController.responseController.removeResponseEventListener(name); } /** * Dispatch a new event. * @param e event * @returns */ dispatchEvent(e) { return this._eventEmitter.dispatchEvent(e); } /** * Register an event handler. * @param type event name * @param listener event handler function */ addEventListener(type, listener) { this._eventEmitter.addEventListener(type, listener); } /** * Remove an event handler. * @param type event name * @param listener event handler function */ removeEventListener(type, listener) { this._eventEmitter.removeEventListener(type, listener); } /** * Enable/disable XR mode. */ toggleXR() { this.webXrController.xrClicked(); } /** * Pass in a function to generate a signalling server URL. * This function is useful if you need to programmatically construct your signalling server URL. * @param signallingUrlBuilderFunc A function that generates a signalling server url. */ setSignallingUrlBuilder(signallingUrlBuilderFunc) { this._webRtcController.signallingUrlBuilder = signallingUrlBuilderFunc; } /** * Public getter for the websocket controller. Access to this property allows you to send * custom websocket messages. */ get webSocketController() { return this._webRtcController.webSocketController; } /** * Public getter for the webXrController controller. Used for all XR features. */ get webXrController() { return this._webXrController; } registerMessageHandler(name, direction, handler) { if (direction === _UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_8__.MessageDirection.FromStreamer && typeof handler === 'undefined') { _Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.Warning(_Logger_Logger__WEBPACK_IMPORTED_MODULE_5__.Logger.GetStackTrace(), `Unable to register an undefined handler for ${name}`); return; } if (direction === _UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_8__.MessageDirection.ToStreamer && typeof handler === 'undefined') { this._webRtcController.streamMessageController.registerMessageHandler(direction, name, (data) => this._webRtcController.sendMessageController.sendMessageToStreamer(name, data)); } else { this._webRtcController.streamMessageController.registerMessageHandler(direction, name, (data) => handler(data)); } } get toStreamerHandlers() { return this._webRtcController.streamMessageController.toStreamerHandlers; } isReconnecting() { return this._webRtcController.isReconnecting; } } /***/ }), /***/ "./src/UI/OnScreenKeyboard.ts": /*!************************************!*\ !*** ./src/UI/OnScreenKeyboard.ts ***! \************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "OnScreenKeyboard": () => (/* binding */ OnScreenKeyboard) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. /** * Class for handling on screen keyboard usage */ class OnScreenKeyboard { /** * * @param videoElementParent The div element the video player is injected into */ constructor(videoElementParent) { this.editTextButton = null; this.hiddenInput = null; if ('ontouchstart' in document.documentElement) { this.createOnScreenKeyboardHelpers(videoElementParent); } } /** * An override for unquantizeAndDenormalizeUnsigned * @param x the x axis point * @param y the y axis point * @returns unquantizeAndDenormalizeUnsigned object */ // eslint-disable-next-line @typescript-eslint/no-unused-vars unquantizeAndDenormalizeUnsigned(x, y) { return null; } /** * Creates on screen keyboard helpers * @param videoElementParent The div element the video player i injected into */ createOnScreenKeyboardHelpers(videoElementParent) { if (!this.hiddenInput) { this.hiddenInput = document.createElement('input'); this.hiddenInput.id = 'hiddenInput'; this.hiddenInput.maxLength = 0; videoElementParent.appendChild(this.hiddenInput); } if (!this.editTextButton) { this.editTextButton = document.createElement('button'); this.editTextButton.id = 'editTextButton'; this.editTextButton.innerHTML = 'edit text'; videoElementParent.appendChild(this.editTextButton); // Hide the 'edit text' button. this.editTextButton.classList.add('hiddenState'); this.editTextButton.addEventListener('touchend', (event) => { // Show the on-screen keyboard. this.hiddenInput.focus(); event.preventDefault(); }); } } /** * Shows the on screen keyboard * @param command the command received via the data channel containing keyboard positions */ showOnScreenKeyboard(command) { if (command.showOnScreenKeyboard) { // Show the 'edit text' button. this.editTextButton.classList.remove('hiddenState'); // Place the 'edit text' button near the UE input widget. const pos = this.unquantizeAndDenormalizeUnsigned(command.x, command.y); this.editTextButton.style.top = pos.y.toString() + 'px'; this.editTextButton.style.left = (pos.x - 40).toString() + 'px'; } else { // Hide the 'edit text' button. this.editTextButton.classList.add('hiddenState'); // Hide the on-screen keyboard. this.hiddenInput.blur(); } } } /***/ }), /***/ "./src/UeInstanceMessage/ResponseController.ts": /*!*****************************************************!*\ !*** ./src/UeInstanceMessage/ResponseController.ts ***! \*****************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "ResponseController": () => (/* binding */ ResponseController) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); // Copyright Epic Games, Inc. All Rights Reserved. class ResponseController { constructor() { this.responseEventListeners = new Map(); } /** * Add a response event listener to the response map * @param name - The name of the response * @param listener - The method to be activated when the response is selected */ addResponseEventListener(name, listener) { this.responseEventListeners.set(name, listener); } /** * Remove a response event listener to the response map * @param name - The name of the response */ removeResponseEventListener(name) { this.responseEventListeners.delete(name); } /** * Handle a response when receiving one form the streamer * @param message - Data received from the data channel with the command in question */ onResponse(message) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'DataChannelReceiveMessageType.Response', 6); const responses = new TextDecoder('utf-16').decode(message.slice(1)); _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), responses, 6); this.responseEventListeners.forEach((listener) => { listener(responses); }); } } /***/ }), /***/ "./src/UeInstanceMessage/SendMessageController.ts": /*!********************************************************!*\ !*** ./src/UeInstanceMessage/SendMessageController.ts ***! \********************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "SendMessageController": () => (/* binding */ SendMessageController) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); // Copyright Epic Games, Inc. All Rights Reserved. class SendMessageController { /** * @param dataChannelSender - Data channel instance * @param toStreamerMessagesMapProvider - Stream Messages instance */ constructor(dataChannelSender, toStreamerMessagesMapProvider) { this.dataChannelSender = dataChannelSender; this.toStreamerMessagesMapProvider = toStreamerMessagesMapProvider; } /** * Send a message to the streamer through the data channel * @param messageType - the type of message we are sending * @param messageData - the message data we are sending over the data channel * @returns - nil */ sendMessageToStreamer(messageType, messageData) { if (messageData === undefined) { messageData = []; } const toStreamerMessages = this.toStreamerMessagesMapProvider.toStreamerMessages; const messageFormat = toStreamerMessages.get(messageType); if (messageFormat === undefined) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), `Attempted to send a message to the streamer with message type: ${messageType}, but the frontend hasn't been configured to send such a message. Check you've added the message type in your cpp`); return; } if (messageFormat.structure && messageData && messageFormat.structure.length !== messageData.length) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), `Provided message data doesn't match expected layout. Expected [ ${messageFormat.structure.map((element) => { switch (element) { case 'uint8': case 'uint16': case 'int16': case 'float': case 'double': return 'number'; case 'string': return 'string'; } }).toString()} ] but received [ ${messageData.map((element) => typeof element).toString()} ]`); return; } let byteLength = 0; const textEncoder = new TextEncoder(); // One loop to calculate the length in bytes of all of the provided data messageData.forEach((element, idx) => { const type = messageFormat.structure[idx]; switch (type) { case 'uint8': byteLength += 1; break; case 'uint16': byteLength += 2; break; case 'int16': byteLength += 2; break; case 'float': byteLength += 4; break; case 'double': byteLength += 8; break; case 'string': // 2 bytes for string length byteLength += 2; // 2 bytes per characters byteLength += 2 * textEncoder.encode(element).length; break; } }); const data = new DataView(new ArrayBuffer(byteLength + 1)); data.setUint8(0, messageFormat.id); let byteOffset = 1; messageData.forEach((element, idx) => { const type = messageFormat.structure[idx]; switch (type) { case 'uint8': data.setUint8(byteOffset, element); byteOffset += 1; break; case 'uint16': data.setUint16(byteOffset, element, true); byteOffset += 2; break; case 'int16': data.setInt16(byteOffset, element, true); byteOffset += 2; break; case 'float': data.setFloat32(byteOffset, element, true); byteOffset += 4; break; case 'double': data.setFloat64(byteOffset, element, true); byteOffset += 8; break; case 'string': data.setUint16(byteOffset, element.length, true); byteOffset += 2; for (let i = 0; i < element.length; i++) { data.setUint16(byteOffset, element.charCodeAt(i), true); byteOffset += 2; } break; } }); if (!this.dataChannelSender.canSend()) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Info(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), `Data channel cannot send yet, skipping sending message: ${messageType} - ${new Uint8Array(data.buffer)}`); return; } this.dataChannelSender.sendData(data.buffer); } } /***/ }), /***/ "./src/UeInstanceMessage/StreamMessageController.ts": /*!**********************************************************!*\ !*** ./src/UeInstanceMessage/StreamMessageController.ts ***! \**********************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "MessageDirection": () => (/* binding */ MessageDirection), /* harmony export */ "StreamMessageController": () => (/* binding */ StreamMessageController), /* harmony export */ "ToStreamerMessage": () => (/* binding */ ToStreamerMessage) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); // Copyright Epic Games, Inc. All Rights Reserved. class ToStreamerMessage { } class StreamMessageController { constructor() { this.toStreamerHandlers = new Map(); this.fromStreamerHandlers = new Map(); this.toStreamerMessages = new Map(); this.fromStreamerMessages = new Map(); } /** * Populate the Default message protocol */ populateDefaultProtocol() { /* * Control Messages. Range = 0..49. */ this.toStreamerMessages.set('IFrameRequest', { id: 0, structure: [] }); this.toStreamerMessages.set('RequestQualityControl', { id: 1, structure: [] }); this.toStreamerMessages.set('FpsRequest', { id: 2, structure: [] }); this.toStreamerMessages.set('AverageBitrateRequest', { id: 3, structure: [] }); this.toStreamerMessages.set('StartStreaming', { id: 4, structure: [] }); this.toStreamerMessages.set('StopStreaming', { id: 5, structure: [] }); this.toStreamerMessages.set('LatencyTest', { id: 6, structure: ['string'] }); this.toStreamerMessages.set('RequestInitialSettings', { id: 7, structure: [] }); this.toStreamerMessages.set('TestEcho', { id: 8, structure: [] }); this.toStreamerMessages.set('DataChannelLatencyTest', { id: 9, structure: [] }); /* * Input Messages. Range = 50..89. */ // Generic Input Messages. Range = 50..59. this.toStreamerMessages.set('UIInteraction', { id: 50, structure: ['string'] }); this.toStreamerMessages.set('Command', { id: 51, structure: ['string'] }); // Keyboard Input Message. Range = 60..69. this.toStreamerMessages.set('KeyDown', { id: 60, // keyCode isRepeat structure: ['uint8', 'uint8'] }); this.toStreamerMessages.set('KeyUp', { id: 61, // keyCode structure: ['uint8'] }); this.toStreamerMessages.set('KeyPress', { id: 62, // charcode structure: ['uint16'] }); // Mouse Input Messages. Range = 70..79. this.toStreamerMessages.set('MouseEnter', { id: 70, structure: [] }); this.toStreamerMessages.set('MouseLeave', { id: 71, structure: [] }); this.toStreamerMessages.set('MouseDown', { id: 72, // button x y structure: ['uint8', 'uint16', 'uint16'] }); this.toStreamerMessages.set('MouseUp', { id: 73, // button x y structure: ['uint8', 'uint16', 'uint16'] }); this.toStreamerMessages.set('MouseMove', { id: 74, // x y deltaX deltaY structure: ['uint16', 'uint16', 'int16', 'int16'] }); this.toStreamerMessages.set('MouseWheel', { id: 75, // delta x y structure: ['int16', 'uint16', 'uint16'] }); this.toStreamerMessages.set('MouseDouble', { id: 76, // button x y structure: ['uint8', 'uint16', 'uint16'] }); // Touch Input Messages. Range = 80..89. this.toStreamerMessages.set('TouchStart', { id: 80, // numtouches(1) x y idx force valid structure: ['uint8', 'uint16', 'uint16', 'uint8', 'uint8', 'uint8'] }); this.toStreamerMessages.set('TouchEnd', { id: 81, // numtouches(1) x y idx force valid structure: ['uint8', 'uint16', 'uint16', 'uint8', 'uint8', 'uint8'] }); this.toStreamerMessages.set('TouchMove', { id: 82, // numtouches(1) x y idx force valid structure: ['uint8', 'uint16', 'uint16', 'uint8', 'uint8', 'uint8'] }); // Gamepad Input Messages. Range = 90..99 this.toStreamerMessages.set('GamepadConnected', { id: 93, structure: [] }); this.toStreamerMessages.set('GamepadButtonPressed', { id: 90, // ctrlerId button isRepeat structure: ['uint8', 'uint8', 'uint8'] }); this.toStreamerMessages.set('GamepadButtonReleased', { id: 91, // ctrlerId button isRepeat(0) structure: ['uint8', 'uint8', 'uint8'] }); this.toStreamerMessages.set('GamepadAnalog', { id: 92, // ctrlerId button analogValue structure: ['uint8', 'uint8', 'double'] }); this.toStreamerMessages.set('GamepadDisconnected', { id: 94, // ctrlerId structure: ['uint8'] }); this.fromStreamerMessages.set(0, 'QualityControlOwnership'); this.fromStreamerMessages.set(1, 'Response'); this.fromStreamerMessages.set(2, 'Command'); this.fromStreamerMessages.set(3, 'FreezeFrame'); this.fromStreamerMessages.set(4, 'UnfreezeFrame'); this.fromStreamerMessages.set(5, 'VideoEncoderAvgQP'); this.fromStreamerMessages.set(6, 'LatencyTest'); this.fromStreamerMessages.set(7, 'InitialSettings'); this.fromStreamerMessages.set(8, 'FileExtension'); this.fromStreamerMessages.set(9, 'FileMimeType'); this.fromStreamerMessages.set(10, 'FileContents'); this.fromStreamerMessages.set(11, 'TestEcho'); this.fromStreamerMessages.set(12, 'InputControlOwnership'); this.fromStreamerMessages.set(13, 'GamepadResponse'); this.fromStreamerMessages.set(14, 'DataChannelLatencyTest'); this.fromStreamerMessages.set(255, 'Protocol'); } /** * Register a message handler * @param messageDirection - the direction of the message; toStreamer or fromStreamer * @param messageType - the type of the message * @param messageHandler - the function or method to be executed when this handler is called */ registerMessageHandler(messageDirection, messageType, messageHandler) { switch (messageDirection) { case MessageDirection.ToStreamer: this.toStreamerHandlers.set(messageType, messageHandler); break; case MessageDirection.FromStreamer: this.fromStreamerHandlers.set(messageType, messageHandler); break; default: _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), `Unknown message direction ${messageDirection}`); } } } /** * The enum for message directions */ var MessageDirection; (function (MessageDirection) { MessageDirection[MessageDirection["ToStreamer"] = 0] = "ToStreamer"; MessageDirection[MessageDirection["FromStreamer"] = 1] = "FromStreamer"; })(MessageDirection || (MessageDirection = {})); /***/ }), /***/ "./src/UeInstanceMessage/ToStreamerMessagesController.ts": /*!***************************************************************!*\ !*** ./src/UeInstanceMessage/ToStreamerMessagesController.ts ***! \***************************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "ToStreamerMessagesController": () => (/* binding */ ToStreamerMessagesController) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. class ToStreamerMessagesController { /** * @param sendMessageController - Stream message controller instance */ constructor(sendMessageController) { this.sendMessageController = sendMessageController; } /** * Send Request to Take Quality Control to the UE Instance */ SendRequestQualityControl() { this.sendMessageController.sendMessageToStreamer('RequestQualityControl'); } /** * Send Max FPS Request to the UE Instance */ SendMaxFpsRequest() { this.sendMessageController.sendMessageToStreamer('FpsRequest'); } /** * Send Average Bitrate Request to the UE Instance */ SendAverageBitrateRequest() { this.sendMessageController.sendMessageToStreamer('AverageBitrateRequest'); } /** * Send a Start Streaming Message to the UE Instance */ SendStartStreaming() { this.sendMessageController.sendMessageToStreamer('StartStreaming'); } /** * Send a Stop Streaming Message to the UE Instance */ SendStopStreaming() { this.sendMessageController.sendMessageToStreamer('StopStreaming'); } /** * Send a Request Initial Settings to the UE Instance */ SendRequestInitialSettings() { this.sendMessageController.sendMessageToStreamer('RequestInitialSettings'); } } /***/ }), /***/ "./src/Util/CoordinateConverter.ts": /*!*****************************************!*\ !*** ./src/Util/CoordinateConverter.ts ***! \*****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "CoordinateConverter": () => (/* binding */ CoordinateConverter), /* harmony export */ "NormalizedQuantizedSignedCoord": () => (/* binding */ NormalizedQuantizedSignedCoord), /* harmony export */ "NormalizedQuantizedUnsignedCoord": () => (/* binding */ NormalizedQuantizedUnsignedCoord), /* harmony export */ "UnquantizedDenormalizedUnsignedCoord": () => (/* binding */ UnquantizedDenormalizedUnsignedCoord) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * Converts coordinates from element relative coordinates to values normalized within the value range of a short (and back again) */ class CoordinateConverter { /** * @param videoElementProvider - the div element that the video player will be injected into */ constructor(videoElementProvider) { this.videoElementProvider = videoElementProvider; this.normalizeAndQuantizeUnsignedFunc = () => { throw new Error('Normalize and quantize unsigned, method not implemented.'); }; this.normalizeAndQuantizeSignedFunc = () => { throw new Error('Normalize and unquantize signed, method not implemented.'); }; this.denormalizeAndUnquantizeUnsignedFunc = () => { throw new Error('Denormalize and unquantize unsigned, method not implemented.'); }; } /** * The surface method for setterNormalizeAndQuantizeUnsigned * @param x - x axis point * @param y - y axis point */ normalizeAndQuantizeUnsigned(x, y) { return this.normalizeAndQuantizeUnsignedFunc(x, y); } /** * The surface method for setterUnquantizeAndDenormalizeUnsigned * @param x - x axis point * @param y - y axis point */ unquantizeAndDenormalizeUnsigned(x, y) { return this.denormalizeAndUnquantizeUnsignedFunc(x, y); } /** * The surface method for setterNormalizeAndQuantizeSigned * @param x - x axis point * @param y - y axis point */ normalizeAndQuantizeSigned(x, y) { return this.normalizeAndQuantizeSignedFunc(x, y); } /** * set up the Normalize And Quantize methods based on the aspect ratio and the video player ratio */ setupNormalizeAndQuantize() { this.videoElementParent = this.videoElementProvider.getVideoParentElement(); this.videoElement = this.videoElementProvider.getVideoElement(); if (this.videoElementParent && this.videoElement) { const playerAspectRatio = this.videoElementParent.clientHeight / this.videoElementParent.clientWidth; const videoAspectRatio = this.videoElement.videoHeight / this.videoElement.videoWidth; if (playerAspectRatio > videoAspectRatio) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'Setup Normalize and Quantize for playerAspectRatio > videoAspectRatio', 6); this.ratio = playerAspectRatio / videoAspectRatio; this.normalizeAndQuantizeUnsignedFunc = (x, y) => this.normalizeAndQuantizeUnsignedPlayerBigger(x, y); this.normalizeAndQuantizeSignedFunc = (x, y) => this.normalizeAndQuantizeSignedPlayerBigger(x, y); this.denormalizeAndUnquantizeUnsignedFunc = (x, y) => this.denormalizeAndUnquantizeUnsignedPlayerBigger(x, y); } else { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'Setup Normalize and Quantize for playerAspectRatio <= videoAspectRatio', 6); this.ratio = videoAspectRatio / playerAspectRatio; this.normalizeAndQuantizeUnsignedFunc = (x, y) => this.normalizeAndQuantizeUnsignedPlayerSmaller(x, y); this.normalizeAndQuantizeSignedFunc = (x, y) => this.normalizeAndQuantizeSignedPlayerSmaller(x, y); this.denormalizeAndUnquantizeUnsignedFunc = (x, y) => this.denormalizeAndUnquantizeUnsignedPlayerSmaller(x, y); } } } /** * normalizeAndQuantizeUnsigned for playerAspectRatio > videoAspectRatio * @param x - x axis point * @param y - y axis point */ normalizeAndQuantizeUnsignedPlayerBigger(x, y) { const normalizedX = x / this.videoElementParent.clientWidth; const normalizedY = this.ratio * (y / this.videoElementParent.clientHeight - 0.5) + 0.5; if (normalizedX < 0.0 || normalizedX > 1.0 || normalizedY < 0.0 || normalizedY > 1.0) { return new NormalizedQuantizedUnsignedCoord(false, 65535, 65535); } else { return new NormalizedQuantizedUnsignedCoord(true, normalizedX * 65536, normalizedY * 65536); } } /** * unquantizeAndDenormalizeUnsigned for playerAspectRatio > videoAspectRatio * @param x - x axis point * @param y - y axis point */ denormalizeAndUnquantizeUnsignedPlayerBigger(x, y) { const normalizedX = x / 65536; const normalizedY = (y / 65536 - 0.5) / this.ratio + 0.5; return new UnquantizedDenormalizedUnsignedCoord(normalizedX * this.videoElementParent.clientWidth, normalizedY * this.videoElementParent.clientHeight); } /** * normalizeAndQuantizeSigned for playerAspectRatio > videoAspectRatio * @param x - x axis point * @param y - y axis point */ normalizeAndQuantizeSignedPlayerBigger(x, y) { const normalizedX = x / (0.5 * this.videoElementParent.clientWidth); const normalizedY = (this.ratio * y) / (0.5 * this.videoElementParent.clientHeight); return new NormalizedQuantizedSignedCoord(normalizedX * 32767, normalizedY * 32767); } /** * normalizeAndQuantizeUnsigned for playerAspectRatio <= videoAspectRatio * @param x - x axis point * @param y - y axis point */ normalizeAndQuantizeUnsignedPlayerSmaller(x, y) { const normalizedX = this.ratio * (x / this.videoElementParent.clientWidth - 0.5) + 0.5; const normalizedY = y / this.videoElementParent.clientHeight; if (normalizedX < 0.0 || normalizedX > 1.0 || normalizedY < 0.0 || normalizedY > 1.0) { return new NormalizedQuantizedUnsignedCoord(false, 65535, 65535); } else { return new NormalizedQuantizedUnsignedCoord(true, normalizedX * 65536, normalizedY * 65536); } } /** * unquantizeAndDenormalizeUnsigned for playerAspectRatio <= videoAspectRatio * @param x - x axis point * @param y - y axis point */ denormalizeAndUnquantizeUnsignedPlayerSmaller(x, y) { const normalizedX = (x / 65536 - 0.5) / this.ratio + 0.5; const normalizedY = y / 65536; return new UnquantizedDenormalizedUnsignedCoord(normalizedX * this.videoElementParent.clientWidth, normalizedY * this.videoElementParent.clientHeight); } /** * normalizeAndQuantizeSigned for playerAspectRatio <= videoAspectRatio * @param x - x axis point * @param y - y axis point */ normalizeAndQuantizeSignedPlayerSmaller(x, y) { const normalizedX = (this.ratio * x) / (0.5 * this.videoElementParent.clientWidth); const normalizedY = y / (0.5 * this.videoElementParent.clientHeight); return new NormalizedQuantizedSignedCoord(normalizedX * 32767, normalizedY * 32767); } } /** * A class for NormalizeAndQuantizeUnsigned objects */ class NormalizedQuantizedUnsignedCoord { constructor(inRange, x, y) { this.inRange = inRange; this.x = x; this.y = y; } } /** * A class for UnquantizedAndDenormalizeUnsigned objects */ class UnquantizedDenormalizedUnsignedCoord { constructor(x, y) { this.x = x; this.y = y; } } /** * A class for NormalizedQuantizedSignedCoord objects */ class NormalizedQuantizedSignedCoord { constructor(x, y) { this.x = x; this.y = y; } } /***/ }), /***/ "./src/Util/EventEmitter.ts": /*!**********************************!*\ !*** ./src/Util/EventEmitter.ts ***! \**********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "AfkTimedOutEvent": () => (/* binding */ AfkTimedOutEvent), /* harmony export */ "AfkWarningActivateEvent": () => (/* binding */ AfkWarningActivateEvent), /* harmony export */ "AfkWarningDeactivateEvent": () => (/* binding */ AfkWarningDeactivateEvent), /* harmony export */ "AfkWarningUpdateEvent": () => (/* binding */ AfkWarningUpdateEvent), /* harmony export */ "DataChannelCloseEvent": () => (/* binding */ DataChannelCloseEvent), /* harmony export */ "DataChannelErrorEvent": () => (/* binding */ DataChannelErrorEvent), /* harmony export */ "DataChannelLatencyTestResponseEvent": () => (/* binding */ DataChannelLatencyTestResponseEvent), /* harmony export */ "DataChannelLatencyTestResultEvent": () => (/* binding */ DataChannelLatencyTestResultEvent), /* harmony export */ "DataChannelOpenEvent": () => (/* binding */ DataChannelOpenEvent), /* harmony export */ "EventEmitter": () => (/* binding */ EventEmitter), /* harmony export */ "HideFreezeFrameEvent": () => (/* binding */ HideFreezeFrameEvent), /* harmony export */ "InitialSettingsEvent": () => (/* binding */ InitialSettingsEvent), /* harmony export */ "LatencyTestResultEvent": () => (/* binding */ LatencyTestResultEvent), /* harmony export */ "LoadFreezeFrameEvent": () => (/* binding */ LoadFreezeFrameEvent), /* harmony export */ "PlayStreamErrorEvent": () => (/* binding */ PlayStreamErrorEvent), /* harmony export */ "PlayStreamEvent": () => (/* binding */ PlayStreamEvent), /* harmony export */ "PlayStreamRejectedEvent": () => (/* binding */ PlayStreamRejectedEvent), /* harmony export */ "PlayerCountEvent": () => (/* binding */ PlayerCountEvent), /* harmony export */ "SettingsChangedEvent": () => (/* binding */ SettingsChangedEvent), /* harmony export */ "StatsReceivedEvent": () => (/* binding */ StatsReceivedEvent), /* harmony export */ "StreamLoadingEvent": () => (/* binding */ StreamLoadingEvent), /* harmony export */ "StreamPreConnectEvent": () => (/* binding */ StreamPreConnectEvent), /* harmony export */ "StreamPreDisconnectEvent": () => (/* binding */ StreamPreDisconnectEvent), /* harmony export */ "StreamReconnectEvent": () => (/* binding */ StreamReconnectEvent), /* harmony export */ "StreamerListMessageEvent": () => (/* binding */ StreamerListMessageEvent), /* harmony export */ "VideoEncoderAvgQPEvent": () => (/* binding */ VideoEncoderAvgQPEvent), /* harmony export */ "VideoInitializedEvent": () => (/* binding */ VideoInitializedEvent), /* harmony export */ "WebRtcAutoConnectEvent": () => (/* binding */ WebRtcAutoConnectEvent), /* harmony export */ "WebRtcConnectedEvent": () => (/* binding */ WebRtcConnectedEvent), /* harmony export */ "WebRtcConnectingEvent": () => (/* binding */ WebRtcConnectingEvent), /* harmony export */ "WebRtcDisconnectedEvent": () => (/* binding */ WebRtcDisconnectedEvent), /* harmony export */ "WebRtcFailedEvent": () => (/* binding */ WebRtcFailedEvent), /* harmony export */ "WebRtcSdpEvent": () => (/* binding */ WebRtcSdpEvent), /* harmony export */ "XrFrameEvent": () => (/* binding */ XrFrameEvent), /* harmony export */ "XrSessionEndedEvent": () => (/* binding */ XrSessionEndedEvent), /* harmony export */ "XrSessionStartedEvent": () => (/* binding */ XrSessionStartedEvent) /* harmony export */ }); /** * An event that is emitted when AFK disconnect is about to happen. * Can be cancelled by calling the callback function provided as part of the event. */ class AfkWarningActivateEvent extends Event { constructor(data) { super('afkWarningActivate'); this.data = data; } } /** * An event that is emitted when the AFK disconnect countdown is updated. */ class AfkWarningUpdateEvent extends Event { constructor(data) { super('afkWarningUpdate'); this.data = data; } } /** * An event that is emitted when AFK warning is deactivated. */ class AfkWarningDeactivateEvent extends Event { constructor() { super('afkWarningDeactivate'); } } /** * An event that is emitted when AFK countdown reaches 0 and the user is disconnected. */ class AfkTimedOutEvent extends Event { constructor() { super('afkTimedOut'); } } /** * An event that is emitted when we receive new video quality value. */ class VideoEncoderAvgQPEvent extends Event { constructor(data) { super('videoEncoderAvgQP'); this.data = data; } } /** * An event that is emitted after a WebRtc connection has been negotiated. */ class WebRtcSdpEvent extends Event { constructor() { super('webRtcSdp'); } } /** * An event that is emitted when auto connecting. */ class WebRtcAutoConnectEvent extends Event { constructor() { super('webRtcAutoConnect'); } } /** * An event that is emitted when sending a WebRtc offer. */ class WebRtcConnectingEvent extends Event { constructor() { super('webRtcConnecting'); } } /** * An event that is emitted when WebRtc connection has been established. */ class WebRtcConnectedEvent extends Event { constructor() { super('webRtcConnected'); } } /** * An event that is emitted if WebRtc connection has failed. */ class WebRtcFailedEvent extends Event { constructor() { super('webRtcFailed'); } } /** * An event that is emitted if WebRtc connection is disconnected. */ class WebRtcDisconnectedEvent extends Event { constructor(data) { super('webRtcDisconnected'); this.data = data; } } /** * An event that is emitted when RTCDataChannel is opened. */ class DataChannelOpenEvent extends Event { constructor(data) { super('dataChannelOpen'); this.data = data; } } /** * An event that is emitted when RTCDataChannel is closed. */ class DataChannelCloseEvent extends Event { constructor(data) { super('dataChannelClose'); this.data = data; } } /** * An event that is emitted on RTCDataChannel errors. */ class DataChannelErrorEvent extends Event { constructor(data) { super('dataChannelError'); this.data = data; } } /** * An event that is emitted when the video stream has been initialized. */ class VideoInitializedEvent extends Event { constructor() { super('videoInitialized'); } } /** * An event that is emitted when video stream loading starts. */ class StreamLoadingEvent extends Event { constructor() { super('streamLoading'); } } /** * An event that is emitted when video stream loading has finished. */ class StreamPreConnectEvent extends Event { constructor() { super('streamConnect'); } } /** * An event that is emitted when video stream has stopped. */ class StreamPreDisconnectEvent extends Event { constructor() { super('streamDisconnect'); } } /** * An event that is emitted when video stream is reconnecting. */ class StreamReconnectEvent extends Event { constructor() { super('streamReconnect'); } } /** * An event that is emitted if there are errors loading the video stream. */ class PlayStreamErrorEvent extends Event { constructor(data) { super('playStreamError'); this.data = data; } } /** * An event that is emitted before trying to start video playback. */ class PlayStreamEvent extends Event { constructor() { super('playStream'); } } /** * An event that is emitted if the browser rejects video playback. Can happen for example if * video auto-play without user interaction is refused by the browser. */ class PlayStreamRejectedEvent extends Event { constructor(data) { super('playStreamRejected'); this.data = data; } } /** * An event that is emitted when receiving a full FreezeFrame image from UE. */ class LoadFreezeFrameEvent extends Event { constructor(data) { super('loadFreezeFrame'); this.data = data; } } /** * An event that is emitted when receiving UnfreezeFrame message from UE and video playback is about to be resumed. */ class HideFreezeFrameEvent extends Event { constructor() { super('hideFreezeFrame'); } } /** * An event that is emitted when receiving WebRTC statistics. */ class StatsReceivedEvent extends Event { constructor(data) { super('statsReceived'); this.data = data; } } /** * An event that is emitted when streamer list changes. */ class StreamerListMessageEvent extends Event { constructor(data) { super('streamerListMessage'); this.data = data; } } /** * An event that is emitted when receiving latency test results. */ class LatencyTestResultEvent extends Event { constructor(data) { super('latencyTestResult'); this.data = data; } } /** * An event that is emitted when receiving data channel latency test response from server. * This event is handled by DataChannelLatencyTestController */ class DataChannelLatencyTestResponseEvent extends Event { constructor(data) { super('dataChannelLatencyTestResponse'); this.data = data; } } /** * An event that is emitted when data channel latency test results are ready. */ class DataChannelLatencyTestResultEvent extends Event { constructor(data) { super('dataChannelLatencyTestResult'); this.data = data; } } /** * An event that is emitted when receiving initial settings from UE. */ class InitialSettingsEvent extends Event { constructor(data) { super('initialSettings'); this.data = data; } } /** * An event that is emitted when PixelStreaming settings change. */ class SettingsChangedEvent extends Event { constructor(data) { super('settingsChanged'); this.data = data; } } /** * Event emitted when an XR Session starts */ class XrSessionStartedEvent extends Event { constructor() { super('xrSessionStarted'); } } /** * Event emitted when an XR Session ends */ class XrSessionEndedEvent extends Event { constructor() { super('xrSessionEnded'); } } /** * Event emitted when an XR Frame is complete */ class XrFrameEvent extends Event { constructor(data) { super('xrFrame'); this.data = data; } } /** * An event that is emitted when receiving a player count from the signalling server */ class PlayerCountEvent extends Event { constructor(data) { super('playerCount'); this.data = data; } } class EventEmitter extends EventTarget { /** * Dispatch a new event. * @param e event * @returns */ dispatchEvent(e) { return super.dispatchEvent(e); } /** * Register an event handler. * @param type event name * @param listener event handler function */ addEventListener(type, listener) { super.addEventListener(type, listener); } /** * Remove an event handler. * @param type event name * @param listener event handler function */ removeEventListener(type, listener) { super.removeEventListener(type, listener); } } /***/ }), /***/ "./src/Util/EventListenerTracker.ts": /*!******************************************!*\ !*** ./src/Util/EventListenerTracker.ts ***! \******************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "EventListenerTracker": () => (/* binding */ EventListenerTracker) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. class EventListenerTracker { constructor() { this.unregisterCallbacks = []; } /** * Add a new callback that is executed when unregisterAll is called. * @param callback */ addUnregisterCallback(callback) { this.unregisterCallbacks.push(callback); } /** * Execute all callbacks and clear the list. */ unregisterAll() { for (const callback of this.unregisterCallbacks) { callback(); } this.unregisterCallbacks = []; } } /***/ }), /***/ "./src/Util/FileUtil.ts": /*!******************************!*\ !*** ./src/Util/FileUtil.ts ***! \******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "FileTemplate": () => (/* binding */ FileTemplate), /* harmony export */ "FileUtil": () => (/* binding */ FileUtil) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * Utility function for populate file information from byte buffers. */ class FileUtil { /** * Processes a files extension when received over data channel * @param view - the file extension data */ static setExtensionFromBytes(view, file) { // Reset file if we got a file message and we are not "receiving" it yet if (!file.receiving) { file.mimetype = ''; file.extension = ''; file.receiving = true; file.valid = false; file.size = 0; file.data = []; file.timestampStart = new Date().getTime(); _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'Received first chunk of file', 6); } const extensionAsString = new TextDecoder('utf-16').decode(view.slice(1)); _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), extensionAsString, 6); file.extension = extensionAsString; } /** * Processes a files mime type when received over data channel * @param view - the file mime type data */ static setMimeTypeFromBytes(view, file) { // Reset file if we got a file message and we are not "receiving" it yet if (!file.receiving) { file.mimetype = ''; file.extension = ''; file.receiving = true; file.valid = false; file.size = 0; file.data = []; file.timestampStart = new Date().getTime(); _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'Received first chunk of file', 6); } const mimeAsString = new TextDecoder('utf-16').decode(view.slice(1)); _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), mimeAsString, 6); file.mimetype = mimeAsString; } /** * Processes a files contents when received over data channel * @param view - the file contents data */ static setContentsFromBytes(view, file) { // If we haven't received the initial setup instructions, return if (!file.receiving) return; // Extract the total size of the file (across all chunks) file.size = Math.ceil(new DataView(view.slice(1, 5).buffer).getInt32(0, true) / 16379 /* The maximum number of payload bits per message*/); // Get the file part of the payload const fileBytes = view.slice(1 + 4); // Append to existing data that holds the file file.data.push(fileBytes); // Uncomment for debug _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), `Received file chunk: ${file.data.length}/${file.size}`, 6); if (file.data.length === file.size) { file.receiving = false; file.valid = true; _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'Received complete file', 6); const transferDuration = new Date().getTime() - file.timestampStart; const transferBitrate = Math.round((file.size * 16 * 1024) / transferDuration); _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), `Average transfer bitrate: ${transferBitrate}kb/s over ${transferDuration / 1000} seconds`, 6); // File reconstruction /** * Example code to reconstruct the file * * This code reconstructs the received data into the original file based on the mime type and extension provided and then downloads the reconstructed file */ const received = new Blob(file.data, { type: file.mimetype }); const a = document.createElement('a'); a.setAttribute('href', URL.createObjectURL(received)); a.setAttribute('download', `transfer.${file.extension}`); document.body.append(a); // if you are so inclined to make it auto-download, do something like: a.click(); a.remove(); } else if (file.data.length > file.size) { file.receiving = false; _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), `Received bigger file than advertised: ${file.data.length}/${file.size}`); } } } /** * A class that represents a template for a downloaded file */ class FileTemplate { constructor() { this.mimetype = ''; this.extension = ''; this.receiving = false; this.size = 0; this.data = []; this.valid = false; } } /***/ }), /***/ "./src/Util/RTCUtils.ts": /*!******************************!*\ !*** ./src/Util/RTCUtils.ts ***! \******************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "RTCUtils": () => (/* binding */ RTCUtils) /* harmony export */ }); class RTCUtils { static isVideoTransciever(transceiver) { return this.canTransceiverReceiveVideo(transceiver) || this.canTransceiverSendVideo(transceiver); } static canTransceiverReceiveVideo(transceiver) { return !!transceiver && (transceiver.direction === 'sendrecv' || transceiver.direction === 'recvonly') && transceiver.receiver && transceiver.receiver.track && transceiver.receiver.track.kind === 'video'; } static canTransceiverSendVideo(transceiver) { return !!transceiver && (transceiver.direction === 'sendrecv' || transceiver.direction === 'sendonly') && transceiver.sender && transceiver.sender.track && transceiver.sender.track.kind === 'video'; } static isAudioTransciever(transceiver) { return this.canTransceiverReceiveAudio(transceiver) || this.canTransceiverSendAudio(transceiver); } static canTransceiverReceiveAudio(transceiver) { return !!transceiver && (transceiver.direction === 'sendrecv' || transceiver.direction === 'recvonly') && transceiver.receiver && transceiver.receiver.track && transceiver.receiver.track.kind === 'audio'; } static canTransceiverSendAudio(transceiver) { return !!transceiver && (transceiver.direction === 'sendrecv' || transceiver.direction === 'sendonly') && transceiver.sender && transceiver.sender.track && transceiver.sender.track.kind === 'audio'; } } /***/ }), /***/ "./src/Util/WebGLUtils.ts": /*!********************************!*\ !*** ./src/Util/WebGLUtils.ts ***! \********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "WebGLUtils": () => (/* binding */ WebGLUtils) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. class WebGLUtils { static vertexShader() { return ` attribute vec2 a_position; attribute vec2 a_texCoord; // input uniform vec2 u_resolution; uniform vec4 u_offset; // varying vec2 v_texCoord; void main() { // convert the rectangle from pixels to 0.0 to 1.0 vec2 zeroToOne = a_position / u_resolution; // convert from 0->1 to 0->2 vec2 zeroToTwo = zeroToOne * 2.0; // convert from 0->2 to -1->+1 (clipspace) vec2 clipSpace = zeroToTwo - 1.0; gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); // pass the texCoord to the fragment shader // The GPU will interpolate this value between points. v_texCoord = (a_texCoord * u_offset.xy) + u_offset.zw; } `; } static fragmentShader() { return ` precision mediump float; // our texture uniform sampler2D u_image; // the texCoords passed in from the vertex shader. varying vec2 v_texCoord; void main() { gl_FragColor = texture2D(u_image, v_texCoord); } `; } } /***/ }), /***/ "./src/Util/WebXRUtils.ts": /*!********************************!*\ !*** ./src/Util/WebXRUtils.ts ***! \********************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "WebXRUtils": () => (/* binding */ WebXRUtils) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. class WebXRUtils { /** * Deep copies a gamepad's values by first converting it to a JSON object and then back to a gamepad * * @param gamepad the original gamepad * @returns a new gamepad object, populated with the original gamepads values */ static deepCopyGamepad(gamepad) { return JSON.parse(JSON.stringify({ buttons: gamepad.buttons.map((b) => JSON.parse(JSON.stringify({ pressed: b.pressed, touched: b.touched }))), axes: gamepad.axes })); } } /***/ }), /***/ "./src/VideoPlayer/StreamController.ts": /*!*********************************************!*\ !*** ./src/VideoPlayer/StreamController.ts ***! \*********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "StreamController": () => (/* binding */ StreamController) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * Video Player Controller handles the creation of the video HTML element and all handlers */ class StreamController { /** * @param videoElementProvider Video Player instance */ constructor(videoElementProvider) { this.videoElementProvider = videoElementProvider; this.audioElement = document.createElement('Audio'); this.videoElementProvider.setAudioElement(this.audioElement); } /** * Handles when the Peer connection has a track event * @param rtcTrackEvent - RTC Track Event */ handleOnTrack(rtcTrackEvent) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'handleOnTrack ' + JSON.stringify(rtcTrackEvent.streams), 6); const videoElement = this.videoElementProvider.getVideoElement(); if (rtcTrackEvent.track) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'Got track - ' + rtcTrackEvent.track.kind + ' id=' + rtcTrackEvent.track.id + ' readyState=' + rtcTrackEvent.track.readyState, 6); } if (rtcTrackEvent.track.kind == 'audio') { this.CreateAudioTrack(rtcTrackEvent.streams[0]); return; } else if (rtcTrackEvent.track.kind == 'video' && videoElement.srcObject !== rtcTrackEvent.streams[0]) { videoElement.srcObject = rtcTrackEvent.streams[0]; _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'Set video source from video track ontrack.'); return; } } /** * Creates the audio device when receiving an RTCTrackEvent with the kind of "audio" * @param audioMediaStream - Audio Media stream track */ CreateAudioTrack(audioMediaStream) { const videoElement = this.videoElementProvider.getVideoElement(); // do nothing the video has the same media stream as the audio track we have here (they are linked) if (videoElement.srcObject == audioMediaStream) { return; } // video element has some other media stream that is not associated with this audio track else if (videoElement.srcObject && videoElement.srcObject !== audioMediaStream) { // create a new audio element this.audioElement.srcObject = audioMediaStream; _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'Created new audio element to play separate audio stream.'); } } } /***/ }), /***/ "./src/VideoPlayer/VideoPlayer.ts": /*!****************************************!*\ !*** ./src/VideoPlayer/VideoPlayer.ts ***! \****************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "VideoPlayer": () => (/* binding */ VideoPlayer) /* harmony export */ }); /* harmony import */ var _Config_Config__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Config/Config */ "./src/Config/Config.ts"); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * The video player html element */ class VideoPlayer { /** * @param videoElementParent the html div the the video player will be injected into * @param config the applications configuration. We're interested in the startVideoMuted flag */ constructor(videoElementParent, config) { this.lastTimeResized = new Date().getTime(); this.videoElement = document.createElement('video'); this.config = config; this.videoElement.id = 'streamingVideo'; this.videoElement.disablePictureInPicture = true; this.videoElement.playsInline = true; this.videoElement.style.width = '100%'; this.videoElement.style.height = '100%'; this.videoElement.style.position = 'absolute'; this.videoElement.style.pointerEvents = 'all'; videoElementParent.appendChild(this.videoElement); this.onResizePlayerCallback = () => { console.log('Resolution changed, restyling player, did you forget to override this function?'); }; this.onMatchViewportResolutionCallback = () => { console.log('Resolution changed and match viewport resolution is turned on, did you forget to override this function?'); }; // set play for video (and audio) this.videoElement.onclick = () => { if (this.audioElement != undefined && this.audioElement.paused) { this.audioElement.play(); } if (this.videoElement.paused) { this.videoElement.play(); } }; this.videoElement.onloadedmetadata = () => { this.onVideoInitialized(); }; // set resize events to the windows if it is resized or its orientation is changed window.addEventListener('resize', () => this.resizePlayerStyle(), true); window.addEventListener('orientationchange', () => this.onOrientationChange()); } setAudioElement(audioElement) { this.audioElement = audioElement; } /** * Sets up the video element with any application config and plays the video element. * @returns A promise for if playing the video was successful or not. */ play() { this.videoElement.muted = this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_0__.Flags.StartVideoMuted); this.videoElement.autoplay = this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_0__.Flags.AutoPlayVideo); return this.videoElement.play(); } /** * @returns True if the video element is paused. */ isPaused() { return this.videoElement.paused; } /** * @returns - whether the video element is playing. */ isVideoReady() { return (this.videoElement.readyState !== undefined && this.videoElement.readyState > 0); } /** * @returns True if the video element has a valid video source (srcObject). */ hasVideoSource() { return (this.videoElement.srcObject !== undefined && this.videoElement.srcObject !== null); } /** * Get the current context of the html video element * @returns - the current context of the video element */ getVideoElement() { return this.videoElement; } /** * Get the current context of the html video elements parent * @returns - the current context of the video elements parent */ getVideoParentElement() { return this.videoElement.parentElement; } /** * Set the Video Elements src object tracks to enable * @param enabled - Enable Tracks on the Src Object */ setVideoEnabled(enabled) { // this is a temporary hack until type scripts video element is updated to reflect the need for tracks on a html video element const videoElement = this.videoElement; videoElement.srcObject .getTracks() .forEach((track) => (track.enabled = enabled)); } /** * An override for when the video has been initialized with a srcObject */ onVideoInitialized() { // Default Functionality: Do Nothing } /** * On the orientation change of a window clear the timeout */ onOrientationChange() { clearTimeout(this.orientationChangeTimeout); this.orientationChangeTimeout = window.setTimeout(() => { this.resizePlayerStyle(); }, 500); } /** * Resizes the player style based on the window height and width * @returns - nil if requirements are satisfied */ resizePlayerStyle() { const videoElementParent = this.getVideoParentElement(); if (!videoElementParent) { return; } this.updateVideoStreamSize(); if (videoElementParent.classList.contains('fixed-size')) { this.onResizePlayerCallback(); return; } // controls for resizing the player this.resizePlayerStyleToFillParentElement(); this.onResizePlayerCallback(); } /** * Resizes the player element to fill the parent element */ resizePlayerStyleToFillParentElement() { const videoElementParent = this.getVideoParentElement(); //Video is not initialized yet so set videoElementParent to size of parent element const styleWidth = '100%'; const styleHeight = '100%'; const styleTop = 0; const styleLeft = 0; videoElementParent.setAttribute('style', 'top: ' + styleTop + 'px; left: ' + styleLeft + 'px; width: ' + styleWidth + '; height: ' + styleHeight + '; cursor: default;'); } updateVideoStreamSize() { if (!this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_0__.Flags.MatchViewportResolution)) { return; } const now = new Date().getTime(); if (now - this.lastTimeResized > 300) { const videoElementParent = this.getVideoParentElement(); if (!videoElementParent) { return; } this.onMatchViewportResolutionCallback(videoElementParent.clientWidth, videoElementParent.clientHeight); this.lastTimeResized = new Date().getTime(); } else { _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'Resizing too often - skipping', 6); clearTimeout(this.resizeTimeoutHandle); this.resizeTimeoutHandle = window.setTimeout(() => this.updateVideoStreamSize(), 100); } } } /***/ }), /***/ "./src/WebRtcPlayer/WebRtcPlayerController.ts": /*!****************************************************!*\ !*** ./src/WebRtcPlayer/WebRtcPlayerController.ts ***! \****************************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "WebRtcPlayerController": () => (/* binding */ WebRtcPlayerController) /* harmony export */ }); /* harmony import */ var _WebSockets_WebSocketController__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../WebSockets/WebSocketController */ "./src/WebSockets/WebSocketController.ts"); /* harmony import */ var _VideoPlayer_StreamController__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../VideoPlayer/StreamController */ "./src/VideoPlayer/StreamController.ts"); /* harmony import */ var _FreezeFrame_FreezeFrameController__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../FreezeFrame/FreezeFrameController */ "./src/FreezeFrame/FreezeFrameController.ts"); /* harmony import */ var _AFK_AFKController__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../AFK/AFKController */ "./src/AFK/AFKController.ts"); /* harmony import */ var _DataChannel_DataChannelController__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../DataChannel/DataChannelController */ "./src/DataChannel/DataChannelController.ts"); /* harmony import */ var _PeerConnectionController_PeerConnectionController__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ../PeerConnectionController/PeerConnectionController */ "./src/PeerConnectionController/PeerConnectionController.ts"); /* harmony import */ var _Config_Config__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../Config/Config */ "./src/Config/Config.ts"); /* harmony import */ var _DataChannel_InitialSettings__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ../DataChannel/InitialSettings */ "./src/DataChannel/InitialSettings.ts"); /* harmony import */ var _DataChannel_LatencyTestResults__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ../DataChannel/LatencyTestResults */ "./src/DataChannel/LatencyTestResults.ts"); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); /* harmony import */ var _Util_FileUtil__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Util/FileUtil */ "./src/Util/FileUtil.ts"); /* harmony import */ var _Inputs_InputClassesFactory__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ../Inputs/InputClassesFactory */ "./src/Inputs/InputClassesFactory.ts"); /* harmony import */ var _VideoPlayer_VideoPlayer__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../VideoPlayer/VideoPlayer */ "./src/VideoPlayer/VideoPlayer.ts"); /* harmony import */ var _UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../UeInstanceMessage/StreamMessageController */ "./src/UeInstanceMessage/StreamMessageController.ts"); /* harmony import */ var _UeInstanceMessage_ResponseController__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../UeInstanceMessage/ResponseController */ "./src/UeInstanceMessage/ResponseController.ts"); /* harmony import */ var _UeInstanceMessage_SendMessageController__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ../UeInstanceMessage/SendMessageController */ "./src/UeInstanceMessage/SendMessageController.ts"); /* harmony import */ var _UeInstanceMessage_ToStreamerMessagesController__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../UeInstanceMessage/ToStreamerMessagesController */ "./src/UeInstanceMessage/ToStreamerMessagesController.ts"); /* harmony import */ var _DataChannel_DataChannelSender__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../DataChannel/DataChannelSender */ "./src/DataChannel/DataChannelSender.ts"); /* harmony import */ var _Util_CoordinateConverter__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../Util/CoordinateConverter */ "./src/Util/CoordinateConverter.ts"); /* harmony import */ var _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ../Util/EventEmitter */ "./src/Util/EventEmitter.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * Entry point for the WebRTC Player */ class WebRtcPlayerController { /** * * @param config - the frontend config object * @param pixelStreaming - the PixelStreaming object */ constructor(config, pixelStreaming) { this.shouldShowPlayOverlay = true; this.autoJoinTimer = undefined; this.config = config; this.pixelStreaming = pixelStreaming; this.responseController = new _UeInstanceMessage_ResponseController__WEBPACK_IMPORTED_MODULE_0__.ResponseController(); this.file = new _Util_FileUtil__WEBPACK_IMPORTED_MODULE_1__.FileTemplate(); this.sdpConstraints = { offerToReceiveAudio: true, offerToReceiveVideo: true }; // set up the afk logic class and connect up its method for closing the signaling server this.afkController = new _AFK_AFKController__WEBPACK_IMPORTED_MODULE_2__.AFKController(this.config, this.pixelStreaming, this.onAfkTriggered.bind(this)); this.afkController.onAFKTimedOutCallback = () => { this.closeSignalingServer('You have been disconnected due to inactivity'); }; this.freezeFrameController = new _FreezeFrame_FreezeFrameController__WEBPACK_IMPORTED_MODULE_3__.FreezeFrameController(this.pixelStreaming.videoElementParent); this.videoPlayer = new _VideoPlayer_VideoPlayer__WEBPACK_IMPORTED_MODULE_4__.VideoPlayer(this.pixelStreaming.videoElementParent, this.config); this.videoPlayer.onVideoInitialized = () => this.handleVideoInitialized(); // When in match viewport resolution mode, when the browser viewport is resized we send a resize command back to UE. this.videoPlayer.onMatchViewportResolutionCallback = (width, height) => { const descriptor = { 'Resolution.Width': width, 'Resolution.Height': height }; this.streamMessageController.toStreamerHandlers.get('Command')([JSON.stringify(descriptor)]); }; // Every time video player is resized in browser we need to reinitialize the mouse coordinate conversion and freeze frame sizing logic. this.videoPlayer.onResizePlayerCallback = () => { this.setUpMouseAndFreezeFrame(); }; this.streamController = new _VideoPlayer_StreamController__WEBPACK_IMPORTED_MODULE_5__.StreamController(this.videoPlayer); this.coordinateConverter = new _Util_CoordinateConverter__WEBPACK_IMPORTED_MODULE_6__.CoordinateConverter(this.videoPlayer); this.sendrecvDataChannelController = new _DataChannel_DataChannelController__WEBPACK_IMPORTED_MODULE_7__.DataChannelController(); this.recvDataChannelController = new _DataChannel_DataChannelController__WEBPACK_IMPORTED_MODULE_7__.DataChannelController(); this.registerDataChannelEventEmitters(this.sendrecvDataChannelController); this.registerDataChannelEventEmitters(this.recvDataChannelController); this.dataChannelSender = new _DataChannel_DataChannelSender__WEBPACK_IMPORTED_MODULE_8__.DataChannelSender(this.sendrecvDataChannelController); this.dataChannelSender.resetAfkWarningTimerOnDataSend = () => this.afkController.resetAfkWarningTimer(); this.streamMessageController = new _UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.StreamMessageController(); // set up websocket methods this.webSocketController = new _WebSockets_WebSocketController__WEBPACK_IMPORTED_MODULE_10__.WebSocketController(); this.webSocketController.onConfig = (messageConfig) => this.handleOnConfigMessage(messageConfig); this.webSocketController.onStreamerList = (messageList) => this.handleStreamerListMessage(messageList); this.webSocketController.onPlayerCount = (playerCount) => { this.pixelStreaming._onPlayerCount(playerCount.count); }; this.webSocketController.onOpen.addEventListener('open', () => { const BrowserSendsOffer = this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.Flags.BrowserSendOffer); if (!BrowserSendsOffer) { this.webSocketController.requestStreamerList(); } }); this.webSocketController.onClose.addEventListener('close', (event) => { // when we refresh the page during a stream we get the going away code. // in that case we don't want to reconnect since we're navigating away. // https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/code // lists all the codes. const CODE_GOING_AWAY = 1001; const willTryReconnect = this.shouldReconnect && event.detail.code != CODE_GOING_AWAY && this.config.getNumericSettingValue(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.NumericParameters.MaxReconnectAttempts) > 0; const disconnectMessage = this.disconnectMessage ? this.disconnectMessage : event.detail.reason; this.pixelStreaming._onDisconnect(disconnectMessage, !willTryReconnect && !this.isReconnecting); this.afkController.stopAfkWarningTimer(); // stop sending stats on interval if we have closed our connection if (this.statsTimerHandle && this.statsTimerHandle !== undefined) { window.clearInterval(this.statsTimerHandle); } // reset the stream quality icon. this.setVideoEncoderAvgQP(0); // unregister all input device event handlers on disconnect this.setTouchInputEnabled(false); this.setMouseInputEnabled(false); this.setKeyboardInputEnabled(false); this.setGamePadInputEnabled(false); if (willTryReconnect) { // need a small delay here to prevent reconnect spamming setTimeout(() => { this.isReconnecting = true; this.reconnectAttempt++; this.tryReconnect(event.detail.reason); }, 2000); } }); // set up the final webRtc player controller methods from within our application so a connection can be activated this.sendMessageController = new _UeInstanceMessage_SendMessageController__WEBPACK_IMPORTED_MODULE_12__.SendMessageController(this.dataChannelSender, this.streamMessageController); this.toStreamerMessagesController = new _UeInstanceMessage_ToStreamerMessagesController__WEBPACK_IMPORTED_MODULE_13__.ToStreamerMessagesController(this.sendMessageController); this.registerMessageHandlers(); this.streamMessageController.populateDefaultProtocol(); this.inputClassesFactory = new _Inputs_InputClassesFactory__WEBPACK_IMPORTED_MODULE_14__.InputClassesFactory(this.streamMessageController, this.videoPlayer, this.coordinateConverter); this.isUsingSFU = false; this.isQualityController = false; this.preferredCodec = ''; this.shouldReconnect = true; this.isReconnecting = false; this.reconnectAttempt = 0; this.config._addOnOptionSettingChangedListener(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.OptionParameters.StreamerId, (streamerid) => { if (streamerid === "") { return; } // close the current peer connection and create a new one this.peerConnectionController.peerConnection.close(); this.peerConnectionController.createPeerConnection(this.peerConfig, this.preferredCodec); this.subscribedStream = streamerid; this.webSocketController.sendSubscribe(streamerid); }); this.setVideoEncoderAvgQP(-1); this.signallingUrlBuilder = () => { let signallingServerUrl = this.config.getTextSettingValue(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.TextParameters.SignallingServerUrl); // If we are connecting to the SFU add a special url parameter to the url if (this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.Flags.BrowserSendOffer)) { signallingServerUrl += '?' + _Config_Config__WEBPACK_IMPORTED_MODULE_11__.Flags.BrowserSendOffer + '=true'; } // This code is no longer needed, but is a good example for how subsequent config flags can be appended // if (this.config.isFlagEnabled(Flags.BrowserSendOffer)) { // signallingServerUrl += (signallingServerUrl.includes('?') ? '&' : '?') + Flags.BrowserSendOffer + '=true'; // } return signallingServerUrl; }; } /** * Make a request to UnquantizedAndDenormalizeUnsigned coordinates * @param x x axis coordinate * @param y y axis coordinate */ requestUnquantizedAndDenormalizeUnsigned(x, y) { return this.coordinateConverter.unquantizeAndDenormalizeUnsigned(x, y); } /** * Handles when a message is received * @param event - Message Event */ handleOnMessage(event) { const message = new Uint8Array(event.data); _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'Message incoming:' + message, 6); //try { const messageType = this.streamMessageController.fromStreamerMessages.get(message[0]); this.streamMessageController.fromStreamerHandlers.get(messageType)(event.data); //} catch (e) { //Logger.Error(Logger.GetStackTrace(), `Custom data channel message with message type that is unknown to the Pixel Streaming protocol. Does your PixelStreamingProtocol need updating? The message type was: ${message[0]}`); //} } /** * Register message all handlers */ registerMessageHandlers() { // From Streamer // Message events from the streamer have a data type of ArrayBuffer as we force this type in the DatachannelController this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.FromStreamer, 'QualityControlOwnership', (data) => this.onQualityControlOwnership(data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.FromStreamer, 'Response', (data) => this.responseController.onResponse(data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.FromStreamer, 'Command', (data) => { this.onCommand(data); }); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.FromStreamer, 'FreezeFrame', (data) => this.onFreezeFrameMessage(data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.FromStreamer, 'UnfreezeFrame', () => this.invalidateFreezeFrameAndEnableVideo()); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.FromStreamer, 'VideoEncoderAvgQP', (data) => this.handleVideoEncoderAvgQP(data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.FromStreamer, 'LatencyTest', (data) => this.handleLatencyTestResult(data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.FromStreamer, 'DataChannelLatencyTest', (data) => this.handleDataChannelLatencyTestResponse(data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.FromStreamer, 'InitialSettings', (data) => this.handleInitialSettings(data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.FromStreamer, 'FileExtension', (data) => this.onFileExtension(data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.FromStreamer, 'FileMimeType', (data) => this.onFileMimeType(data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.FromStreamer, 'FileContents', (data) => this.onFileContents(data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.FromStreamer, 'TestEcho', () => { /* Do nothing */ }); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.FromStreamer, 'InputControlOwnership', (data) => this.onInputControlOwnership(data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.FromStreamer, 'GamepadResponse', (data) => this.onGamepadResponse(data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.FromStreamer, 'Protocol', (data) => this.onProtocolMessage(data)); // To Streamer this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'IFrameRequest', () => this.sendMessageController.sendMessageToStreamer('IFrameRequest')); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'RequestQualityControl', () => this.sendMessageController.sendMessageToStreamer('RequestQualityControl')); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'FpsRequest', () => this.sendMessageController.sendMessageToStreamer('FpsRequest')); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'AverageBitrateRequest', () => this.sendMessageController.sendMessageToStreamer('AverageBitrateRequest')); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'StartStreaming', () => this.sendMessageController.sendMessageToStreamer('StartStreaming')); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'StopStreaming', () => this.sendMessageController.sendMessageToStreamer('StopStreaming')); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'LatencyTest', (data) => this.sendMessageController.sendMessageToStreamer('LatencyTest', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'RequestInitialSettings', () => this.sendMessageController.sendMessageToStreamer('RequestInitialSettings')); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'TestEcho', () => { /* Do nothing */ }); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'UIInteraction', (data) => this.sendMessageController.sendMessageToStreamer('UIInteraction', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'Command', (data) => this.sendMessageController.sendMessageToStreamer('Command', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'TextboxEntry', (data) => this.sendMessageController.sendMessageToStreamer('TextboxEntry', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'KeyDown', (data) => this.sendMessageController.sendMessageToStreamer('KeyDown', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'KeyUp', (data) => this.sendMessageController.sendMessageToStreamer('KeyUp', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'KeyPress', (data) => this.sendMessageController.sendMessageToStreamer('KeyPress', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'MouseEnter', (data) => this.sendMessageController.sendMessageToStreamer('MouseEnter', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'MouseLeave', (data) => this.sendMessageController.sendMessageToStreamer('MouseLeave', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'MouseDown', (data) => this.sendMessageController.sendMessageToStreamer('MouseDown', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'MouseUp', (data) => this.sendMessageController.sendMessageToStreamer('MouseUp', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'MouseMove', (data) => this.sendMessageController.sendMessageToStreamer('MouseMove', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'MouseWheel', (data) => this.sendMessageController.sendMessageToStreamer('MouseWheel', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'MouseDouble', (data) => this.sendMessageController.sendMessageToStreamer('MouseDouble', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'TouchStart', (data) => this.sendMessageController.sendMessageToStreamer('TouchStart', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'TouchEnd', (data) => this.sendMessageController.sendMessageToStreamer('TouchEnd', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'TouchMove', (data) => this.sendMessageController.sendMessageToStreamer('TouchMove', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'GamepadConnected', () => this.sendMessageController.sendMessageToStreamer('GamepadConnected')); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'GamepadButtonPressed', (data) => this.sendMessageController.sendMessageToStreamer('GamepadButtonPressed', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'GamepadButtonReleased', (data) => this.sendMessageController.sendMessageToStreamer('GamepadButtonReleased', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'GamepadAnalog', (data) => this.sendMessageController.sendMessageToStreamer('GamepadAnalog', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'GamepadDisconnected', (data) => this.sendMessageController.sendMessageToStreamer('GamepadDisconnected', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'XRHMDTransform', (data) => this.sendMessageController.sendMessageToStreamer('XRHMDTransform', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'XRControllerTransform', (data) => this.sendMessageController.sendMessageToStreamer('XRControllerTransform', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'XRSystem', (data) => this.sendMessageController.sendMessageToStreamer('XRSystem', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'XRButtonTouched', (data) => this.sendMessageController.sendMessageToStreamer('XRButtonTouched', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'XRButtonPressed', (data) => this.sendMessageController.sendMessageToStreamer('XRButtonPressed', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'XRButtonReleased', (data) => this.sendMessageController.sendMessageToStreamer('XRButtonReleased', data)); this.streamMessageController.registerMessageHandler(_UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer, 'XRAnalog', (data) => this.sendMessageController.sendMessageToStreamer('XRAnalog', data)); } /** * Activate the logic associated with a command from UE * @param message */ onCommand(message) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'DataChannelReceiveMessageType.Command', 6); const commandAsString = new TextDecoder('utf-16').decode(message.slice(1)); _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'Data Channel Command: ' + commandAsString, 6); const command = JSON.parse(commandAsString); if (command.command === 'onScreenKeyboard') { this.pixelStreaming._activateOnScreenKeyboard(command); } } /** * Handles a protocol message received from the streamer * @param message the message data from the streamer */ onProtocolMessage(message) { try { const protocolString = new TextDecoder('utf-16').decode(message.slice(1)); const protocolJSON = JSON.parse(protocolString); if (!Object.prototype.hasOwnProperty.call(protocolJSON, 'Direction')) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'Malformed protocol received. Ensure the protocol message contains a direction'); } const direction = protocolJSON.Direction; delete protocolJSON.Direction; _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), `Received new ${direction == _UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.FromStreamer ? 'FromStreamer' : 'ToStreamer'} protocol. Updating existing protocol...`); Object.keys(protocolJSON).forEach((messageType) => { const message = protocolJSON[messageType]; switch (direction) { case _UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer: // Check that the message contains all the relevant params if (!Object.prototype.hasOwnProperty.call(message, 'id')) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), `ToStreamer->${messageType} protocol definition was malformed as it didn't contain at least an id\n Definition was: ${JSON.stringify(message, null, 2)}`); // return in a forEach is equivalent to a continue in a normal for loop return; } // UE5.1 and UE5.2 don't send a structure for these message types, but they actually do have a structure so ignore updating them if ((messageType === "UIInteraction" || messageType === "Command" || messageType === "LatencyTest")) { return; } if (this.streamMessageController.toStreamerHandlers.get(messageType)) { // If we've registered a handler for this message type we can add it to our supported messages. ie registerMessageHandler(...) this.streamMessageController.toStreamerMessages.set(messageType, message); } else { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), `There was no registered handler for "${messageType}" - try adding one using registerMessageHandler(MessageDirection.ToStreamer, "${messageType}", myHandler)`); } break; case _UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.FromStreamer: // Check that the message contains all the relevant params if (!Object.prototype.hasOwnProperty.call(message, 'id')) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), `FromStreamer->${messageType} protocol definition was malformed as it didn't contain at least an id\n Definition was: ${JSON.stringify(message, null, 2)}`); // return in a forEach is equivalent to a continue in a normal for loop return; } if (this.streamMessageController.fromStreamerHandlers.get(messageType)) { // If we've registered a handler for this message type. ie registerMessageHandler(...) this.streamMessageController.fromStreamerMessages.set(message.id, messageType); } else { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), `There was no registered handler for "${message}" - try adding one using registerMessageHandler(MessageDirection.FromStreamer, "${messageType}", myHandler)`); } break; default: _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), `Unknown direction: ${direction}`); } }); // Once the protocol has been received, we can send our control messages this.toStreamerMessagesController.SendRequestInitialSettings(); this.toStreamerMessagesController.SendRequestQualityControl(); } catch (e) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), e); } } /** * Handles an input control message when it is received from the streamer * @param message The input control message */ onInputControlOwnership(message) { const view = new Uint8Array(message); _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'DataChannelReceiveMessageType.InputControlOwnership', 6); const inputControlOwnership = new Boolean(view[1]).valueOf(); _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), `Received input controller message - will your input control the stream: ${inputControlOwnership}`); this.pixelStreaming._onInputControlOwnership(inputControlOwnership); } /** * * @param message */ onGamepadResponse(message) { const responseString = new TextDecoder('utf-16').decode(message.slice(1)); const responseJSON = JSON.parse(responseString); this.gamePadController.onGamepadResponseReceived(responseJSON.controllerId); } onAfkTriggered() { this.afkController.onAfkClick(); // if the stream is paused play it, if we can if (this.videoPlayer.isPaused() && this.videoPlayer.hasVideoSource()) { this.playStream(); } } /** * Set whether we should timeout when afk. * @param afkEnabled If true we timeout when idle for some given amount of time. */ setAfkEnabled(afkEnabled) { if (afkEnabled) { this.onAfkTriggered(); } else { this.afkController.stopAfkWarningTimer(); } } /** * Attempt a reconnection to the signalling server */ tryReconnect(message) { // if there is no webSocketController return immediately or this will not work if (!this.webSocketController) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'The Web Socket Controller does not exist so this will not work right now.'); return; } // if the connection is open, first close it. wait some time and try again. this.isReconnecting = true; if (this.webSocketController.webSocket && this.webSocketController.webSocket.readyState != WebSocket.CLOSED) { this.closeSignalingServer(`${message} Restarting stream...`); setTimeout(() => { this.tryReconnect(message); }, 3000); } else { this.pixelStreaming._onWebRtcAutoConnect(); this.connectToSignallingServer(); } } /** * Loads a freeze frame if it is required otherwise shows the play overlay */ loadFreezeFrameOrShowPlayOverlay() { this.pixelStreaming.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_16__.LoadFreezeFrameEvent({ shouldShowPlayOverlay: this.shouldShowPlayOverlay, isValid: this.freezeFrameController.valid, jpegData: this.freezeFrameController.jpeg })); if (this.shouldShowPlayOverlay === true) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'showing play overlay'); this.resizePlayerStyle(); } else { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'showing freeze frame'); this.freezeFrameController.showFreezeFrame(); } setTimeout(() => { this.videoPlayer.setVideoEnabled(false); }, this.freezeFrameController.freezeFrameDelay); } /** * Process the freeze frame and load it * @param message The freeze frame data in bytes */ onFreezeFrameMessage(message) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'DataChannelReceiveMessageType.FreezeFrame', 6); const view = new Uint8Array(message); this.freezeFrameController.processFreezeFrameMessage(view, () => this.loadFreezeFrameOrShowPlayOverlay()); } /** * Enable the video after hiding a freeze frame */ invalidateFreezeFrameAndEnableVideo() { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'DataChannelReceiveMessageType.FreezeFrame', 6); setTimeout(() => { this.pixelStreaming.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_16__.HideFreezeFrameEvent()); this.freezeFrameController.hideFreezeFrame(); }, this.freezeFrameController.freezeFrameDelay); if (this.videoPlayer.getVideoElement()) { this.videoPlayer.setVideoEnabled(true); } } /** * Prep datachannel data for processing file extension * @param data the file extension data */ onFileExtension(data) { const view = new Uint8Array(data); _Util_FileUtil__WEBPACK_IMPORTED_MODULE_1__.FileUtil.setExtensionFromBytes(view, this.file); } /** * Prep datachannel data for processing the file mime type * @param data the file mime type data */ onFileMimeType(data) { const view = new Uint8Array(data); _Util_FileUtil__WEBPACK_IMPORTED_MODULE_1__.FileUtil.setMimeTypeFromBytes(view, this.file); } /** * Prep datachannel data for processing the file contents * @param data the file contents data */ onFileContents(data) { const view = new Uint8Array(data); _Util_FileUtil__WEBPACK_IMPORTED_MODULE_1__.FileUtil.setContentsFromBytes(view, this.file); } /** * Plays the stream audio and video source and sets up other pieces while the stream starts */ playStream() { if (!this.videoPlayer.getVideoElement()) { const message = 'Could not play video stream because the video player was not initialized correctly.'; this.pixelStreaming.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_16__.PlayStreamErrorEvent({ message })); _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), message); // close the connection this.closeSignalingServer('Stream not initialized correctly'); return; } if (!this.videoPlayer.hasVideoSource()) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Warning(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'Cannot play stream, the video element has no srcObject to play.'); return; } this.setTouchInputEnabled(this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.Flags.TouchInput)); this.pixelStreaming.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_16__.PlayStreamEvent()); if (this.streamController.audioElement.srcObject) { const startMuted = this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.Flags.StartVideoMuted); this.streamController.audioElement.muted = startMuted; if (startMuted) { this.playVideo(); } else { this.streamController.audioElement .play() .then(() => { this.playVideo(); }) .catch((onRejectedReason) => { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), onRejectedReason); _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'Browser does not support autoplaying video without interaction - to resolve this we are going to show the play button overlay.'); this.pixelStreaming.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_16__.PlayStreamRejectedEvent({ reason: onRejectedReason })); }); } } else { this.playVideo(); } this.shouldShowPlayOverlay = false; this.freezeFrameController.showFreezeFrame(); } /** * Plays the video stream */ playVideo() { // handle play() with promise as it is an asynchronous call this.videoPlayer.play().catch((onRejectedReason) => { if (this.streamController.audioElement.srcObject) { this.streamController.audioElement.pause(); } _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), onRejectedReason); _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'Browser does not support autoplaying video without interaction - to resolve this we are going to show the play button overlay.'); this.pixelStreaming.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_16__.PlayStreamRejectedEvent({ reason: onRejectedReason })); }); } /** * Enable the video to play automatically if enableAutoplay is true */ autoPlayVideoOrSetUpPlayOverlay() { if (this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.Flags.AutoPlayVideo)) { // attempt to play the video this.playStream(); } this.resizePlayerStyle(); } /** * Connect to the Signaling server */ connectToSignallingServer() { this.locallyClosed = false; this.shouldReconnect = true; this.disconnectMessage = null; const signallingUrl = this.signallingUrlBuilder(); this.webSocketController.connect(signallingUrl); } /** * This will start the handshake to the signalling server * @param peerConfig - RTC Configuration Options from the Signaling server * @remark RTC Peer Connection on Ice Candidate event have it handled by handle Send Ice Candidate */ startSession(peerConfig) { this.peerConfig = peerConfig; // check for forcing turn if (this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.Flags.ForceTURN)) { // check for a turn server const hasTurnServer = this.checkTurnServerAvailability(peerConfig); // close and error if turn is forced and there is no turn server if (!hasTurnServer) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Info(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'No turn server was found in the Peer Connection Options. TURN cannot be forced, closing connection. Please use STUN instead'); this.closeSignalingServer('TURN cannot be forced, closing connection. Please use STUN instead.'); return; } } // set up the peer connection controller this.peerConnectionController = new _PeerConnectionController_PeerConnectionController__WEBPACK_IMPORTED_MODULE_17__.PeerConnectionController(this.peerConfig, this.config, this.preferredCodec); // set up peer connection controller video stats this.peerConnectionController.onVideoStats = (event) => this.handleVideoStats(event); /* When the Peer Connection wants to send an offer have it handled */ this.peerConnectionController.onSendWebRTCOffer = (offer) => this.handleSendWebRTCOffer(offer); /* When the Peer Connection wants to send an answer have it handled */ this.peerConnectionController.onSendWebRTCAnswer = (offer) => this.handleSendWebRTCAnswer(offer); /* When the Peer Connection ice candidate is added have it handled */ this.peerConnectionController.onPeerIceCandidate = (peerConnectionIceEvent) => this.handleSendIceCandidate(peerConnectionIceEvent); /* When the Peer Connection has a data channel created for it by the browser, handle it */ this.peerConnectionController.onDataChannel = (datachannelEvent) => this.handleDataChannel(datachannelEvent); // set up webRtc text overlays this.peerConnectionController.showTextOverlayConnecting = () => this.pixelStreaming._onWebRtcConnecting(); this.peerConnectionController.showTextOverlaySetupFailure = () => this.pixelStreaming._onWebRtcFailed(); let webRtcConnectedSent = false; this.peerConnectionController.onIceConnectionStateChange = () => { // Browsers emit "connected" when getting first connection and "completed" when finishing // candidate checking. However, sometimes browsers can skip "connected" and only emit "completed". // Therefore need to check both cases and emit onWebRtcConnected only once on the first hit. if (!webRtcConnectedSent && ["connected", "completed"].includes(this.peerConnectionController.peerConnection.iceConnectionState)) { this.pixelStreaming._onWebRtcConnected(); webRtcConnectedSent = true; } }; /* RTC Peer Connection on Track event -> handle on track */ this.peerConnectionController.onTrack = (trackEvent) => this.streamController.handleOnTrack(trackEvent); /* Start the Hand shake process by creating an Offer */ const BrowserSendsOffer = this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.Flags.BrowserSendOffer); if (BrowserSendsOffer) { // If browser is sending the offer, create an offer and send it to the streamer this.sendrecvDataChannelController.createDataChannel(this.peerConnectionController.peerConnection, 'cirrus', this.datachannelOptions); this.sendrecvDataChannelController.handleOnMessage = (ev) => this.handleOnMessage(ev); this.peerConnectionController.createOffer(this.sdpConstraints, this.config); } } /** * Checks the peer connection options for a turn server and returns true or false */ checkTurnServerAvailability(options) { // if iceServers is empty return false this should not be the general use case but is here incase if (!options.iceServers) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Info(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'A turn sever was not found'); return false; } // loop through the ice servers to check for a turn url for (const iceServer of options.iceServers) { for (const url of iceServer.urls) { if (url.includes('turn')) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), `A turn sever was found at ${url}`); return true; } } } _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Info(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'A turn sever was not found'); return false; } /** * Handles when a Config Message is received contains the Peer Connection Options required (STUN and TURN Server Info) * @param messageConfig - Config Message received from the signaling server */ handleOnConfigMessage(messageConfig) { this.resizePlayerStyle(); // Tell the WebRtcController to start a session with the peer options sent from the signaling server this.startSession(messageConfig.peerConnectionOptions); // When the signaling server sends a WebRTC Answer over the websocket connection have the WebRtcController handle the message this.webSocketController.onWebRtcAnswer = (messageAnswer) => this.handleWebRtcAnswer(messageAnswer); this.webSocketController.onWebRtcOffer = (messageOffer) => this.handleWebRtcOffer(messageOffer); this.webSocketController.onWebRtcPeerDataChannels = (messageDataChannels) => this.handleWebRtcSFUPeerDatachannels(messageDataChannels); // When the signaling server sends a IceCandidate over the websocket connection have the WebRtcController handle the message this.webSocketController.onIceCandidate = (iceCandidate) => this.handleIceCandidate(iceCandidate); } /** * Handles when the signalling server gives us the list of streamer ids. */ handleStreamerListMessage(messageStreamerList) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), `Got streamer list ${messageStreamerList.ids}`, 6); // add the streamers to the UI const settingOptions = [...messageStreamerList.ids]; // copy the original messageStreamerList.ids settingOptions.unshift(''); // add an empty option at the top this.config.setOptionSettingOptions(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.OptionParameters.StreamerId, settingOptions); let wantedStreamerId = null; let autoSelectedStreamerId = null; const waitForStreamer = this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.Flags.WaitForStreamer); const reconnectLimit = this.config.getNumericSettingValue(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.NumericParameters.MaxReconnectAttempts); const reconnectDelay = this.config.getNumericSettingValue(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.NumericParameters.StreamerAutoJoinInterval); // first we figure out a wanted streamer id through various means const urlParams = new URLSearchParams(window.location.search); if (urlParams.has(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.OptionParameters.StreamerId)) { // if we've set the streamer id on the url we only want that streamer id wantedStreamerId = urlParams.get(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.OptionParameters.StreamerId); } else if (this.subscribedStream) { // we were previously subscribed to a streamer, we want that wantedStreamerId = this.subscribedStream; } // now lets see if we can pick it. if (wantedStreamerId && messageStreamerList.ids.includes(wantedStreamerId)) { // if the wanted stream is in the list. we pick that autoSelectedStreamerId = wantedStreamerId; } else if ((!wantedStreamerId || !waitForStreamer) && messageStreamerList.ids.length == 1) { // otherwise, if we're not waiting for the wanted streamer and there's only one streamer, connect to it autoSelectedStreamerId = messageStreamerList.ids[0]; } // if we found a streamer id to auto select, select it if (autoSelectedStreamerId) { this.isReconnecting = false; this.reconnectAttempt = 0; this.config.setOptionSettingValue(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.OptionParameters.StreamerId, autoSelectedStreamerId); } else { // no auto selected streamer. // if we're waiting for a streamer then try reconnecting if (waitForStreamer) { if (this.reconnectAttempt < reconnectLimit) { // still reconnects available this.isReconnecting = true; this.reconnectAttempt++; setTimeout(() => { this.webSocketController.requestStreamerList(); }, reconnectDelay); } else { // We've exhausted our reconnect attempts, return to main screen this.reconnectAttempt = 0; this.isReconnecting = false; this.shouldReconnect = false; } } } // dispatch this event finally this.pixelStreaming.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_16__.StreamerListMessageEvent({ messageStreamerList, autoSelectedStreamerId, wantedStreamerId })); } /** * Handle the RTC Answer from the signaling server * @param Answer - Answer SDP from the peer. */ handleWebRtcAnswer(Answer) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), `Got answer sdp ${Answer.sdp}`, 6); const sdpAnswer = { sdp: Answer.sdp, type: 'answer' }; this.peerConnectionController.receiveAnswer(sdpAnswer); this.handlePostWebrtcNegotiation(); } /** * Handle the RTC offer from a WebRTC peer (received through the signalling server). * @param Offer - Offer SDP from the peer. */ handleWebRtcOffer(Offer) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), `Got offer sdp ${Offer.sdp}`, 6); this.isUsingSFU = Offer.sfu ? Offer.sfu : false; if (this.isUsingSFU) { // Disable negotiating with the sfu as the sfu only supports one codec at a time this.peerConnectionController.preferredCodec = ''; } const sdpOffer = { sdp: Offer.sdp, type: 'offer' }; this.peerConnectionController.receiveOffer(sdpOffer, this.config); this.handlePostWebrtcNegotiation(); } /** * Handle when the SFU provides the peer with its data channels * @param DataChannels - The message from the SFU containing the data channels ids */ handleWebRtcSFUPeerDatachannels(DataChannels) { const SendOptions = { ordered: true, negotiated: true, id: DataChannels.sendStreamId }; const unidirectional = DataChannels.sendStreamId != DataChannels.recvStreamId; this.sendrecvDataChannelController.createDataChannel(this.peerConnectionController.peerConnection, unidirectional ? 'send-datachannel' : 'datachannel', SendOptions); if (unidirectional) { const RecvOptions = { ordered: true, negotiated: true, id: DataChannels.recvStreamId }; this.recvDataChannelController.createDataChannel(this.peerConnectionController.peerConnection, 'recv-datachannel', RecvOptions); this.recvDataChannelController.handleOnOpen = () => this.webSocketController.sendSFURecvDataChannelReady(); // If we're uni-directional, only the recv data channel should handle incoming messages this.recvDataChannelController.handleOnMessage = (ev) => this.handleOnMessage(ev); } else { // else our primary datachannel is send/recv so it can handle incoming messages this.sendrecvDataChannelController.handleOnMessage = (ev) => this.handleOnMessage(ev); } } handlePostWebrtcNegotiation() { // start the afk warning timer as PS is now running this.afkController.startAfkWarningTimer(); // show the overlay that we have negotiated a connection this.pixelStreaming._onWebRtcSdp(); if (this.statsTimerHandle && this.statsTimerHandle !== undefined) { window.clearInterval(this.statsTimerHandle); } this.statsTimerHandle = window.setInterval(() => this.getStats(), 1000); /* */ this.setMouseInputEnabled(this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.Flags.MouseInput)); this.setKeyboardInputEnabled(this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.Flags.KeyboardInput)); this.setGamePadInputEnabled(this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.Flags.GamepadInput)); } /** * When an ice Candidate is received from the Signaling server add it to the Peer Connection Client * @param iceCandidate - Ice Candidate from Server */ handleIceCandidate(iceCandidate) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'Web RTC Controller: onWebRtcIce', 6); const candidate = new RTCIceCandidate(iceCandidate); this.peerConnectionController.handleOnIce(candidate); } /** * Send the ice Candidate to the signaling server via websocket * @param iceEvent - RTC Peer ConnectionIceEvent) { */ handleSendIceCandidate(iceEvent) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'OnIceCandidate', 6); if (iceEvent.candidate && iceEvent.candidate.candidate) { this.webSocketController.sendIceCandidate(iceEvent.candidate); } } /** * Send the ice Candidate to the signaling server via websocket * @param iceEvent - RTC Peer ConnectionIceEvent) { */ handleDataChannel(datachannelEvent) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'Data channel created for us by browser as we are a receiving peer.', 6); this.sendrecvDataChannelController.dataChannel = datachannelEvent.channel; // Data channel was created for us, so we just need to setup its callbacks and array type this.sendrecvDataChannelController.setupDataChannel(); this.sendrecvDataChannelController.handleOnMessage = (ev) => this.handleOnMessage(ev); } /** * Send the RTC Offer Session to the Signaling server via websocket * @param offer - RTC Session Description */ handleSendWebRTCOffer(offer) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'Sending the offer to the Server', 6); this.webSocketController.sendWebRtcOffer(offer); } /** * Send the RTC Offer Session to the Signaling server via websocket * @param answer - RTC Session Description */ handleSendWebRTCAnswer(answer) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'Sending the answer to the Server', 6); this.webSocketController.sendWebRtcAnswer(answer); if (this.isUsingSFU) { this.webSocketController.sendWebRtcDatachannelRequest(); } } /** * Set the freeze frame overlay to the player div */ setUpMouseAndFreezeFrame() { // Calculating and normalizing positions depends on the width and height of the player. this.videoElementParentClientRect = this.videoPlayer .getVideoParentElement() .getBoundingClientRect(); this.coordinateConverter.setupNormalizeAndQuantize(); this.freezeFrameController.freezeFrame.resize(); } /** * Close the Connection to the signaling server */ closeSignalingServer(message) { var _a; // We explicitly called close, therefore we don't want to trigger auto reconnect this.locallyClosed = true; this.shouldReconnect = false; this.disconnectMessage = message; (_a = this.webSocketController) === null || _a === void 0 ? void 0 : _a.close(); } /** * Close the peer connection */ closePeerConnection() { var _a; (_a = this.peerConnectionController) === null || _a === void 0 ? void 0 : _a.close(); } /** * Close all connections */ close() { this.closeSignalingServer(''); this.closePeerConnection(); } /** * Fires a Video Stats Event in the RTC Peer Connection */ getStats() { this.peerConnectionController.generateStats(); } /** * Send a Latency Test Request to the UE Instance */ sendLatencyTest() { this.latencyStartTime = Date.now(); this.streamMessageController.toStreamerHandlers.get('LatencyTest')([JSON.stringify({ StartTime: this.latencyStartTime })]); } /** * Send a Data Channel Latency Test Request to the UE Instance */ sendDataChannelLatencyTest(descriptor) { this.streamMessageController.toStreamerHandlers.get('DataChannelLatencyTest')([JSON.stringify(descriptor)]); } /** * Send the MinQP encoder setting to the UE Instance. * @param minQP - The lower bound for QP when encoding * valid values are (1-51) where: * 1 = Best quality but highest bitrate. * 51 = Worst quality but lowest bitrate. * By default the minQP is 1 meaning the encoder is free * to aim for the best quality it can on the given network link. */ sendEncoderMinQP(minQP) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), `MinQP=${minQP}\n`, 6); if (minQP != null) { this.streamMessageController.toStreamerHandlers.get('Command')([JSON.stringify({ 'Encoder.MinQP': minQP })]); } } /** * Send the MaxQP encoder setting to the UE Instance. * @param maxQP - The upper bound for QP when encoding * valid values are (1-51) where: * 1 = Best quality but highest bitrate. * 51 = Worst quality but lowest bitrate. * By default the maxQP is 51 meaning the encoder is free * to drop quality as low as needed on the given network link. */ sendEncoderMaxQP(maxQP) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), `MaxQP=${maxQP}\n`, 6); if (maxQP != null) { this.streamMessageController.toStreamerHandlers.get('Command')([JSON.stringify({ 'Encoder.MaxQP': maxQP })]); } } /** * Send the { WebRTC.MinBitrate: SomeNumber }} command to UE to set * the minimum bitrate that we allow WebRTC to use * (note setting this too high in poor networks can be problematic). * @param minBitrate - The minimum bitrate we would like WebRTC to not fall below. */ sendWebRTCMinBitrate(minBitrate) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), `WebRTC Min Bitrate=${minBitrate}`, 6); if (minBitrate != null) { this.streamMessageController.toStreamerHandlers.get('Command')([JSON.stringify({ 'WebRTC.MinBitrate': minBitrate })]); } } /** * Send the { WebRTC.MaxBitrate: SomeNumber }} command to UE to set * the minimum bitrate that we allow WebRTC to use * (note setting this too low could result in blocky video). * @param minBitrate - The minimum bitrate we would like WebRTC to not fall below. */ sendWebRTCMaxBitrate(maxBitrate) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), `WebRTC Max Bitrate=${maxBitrate}`, 6); if (maxBitrate != null) { this.streamMessageController.toStreamerHandlers.get('Command')([JSON.stringify({ 'WebRTC.MaxBitrate': maxBitrate })]); } } /** * Send the { WebRTC.Fps: SomeNumber }} UE 5.0+ * and { WebRTC.MaxFps } UE 4.27 command to set * the maximum fps we would like WebRTC to stream at. * @param fps - The maximum stream fps. */ sendWebRTCFps(fps) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), `WebRTC FPS=${fps}`, 6); if (fps != null) { this.streamMessageController.toStreamerHandlers.get('Command')([JSON.stringify({ 'WebRTC.Fps': fps })]); /* TODO: Remove when UE 4.27 unsupported. */ this.streamMessageController.toStreamerHandlers.get('Command')([JSON.stringify({ 'WebRTC.MaxFps': fps })]); } } /** * Sends the UI Descriptor `stat fps` to the UE Instance */ sendShowFps() { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), '---- Sending show stat to UE ----', 6); this.streamMessageController.toStreamerHandlers.get('Command')([JSON.stringify({ 'stat.fps': '' })]); } /** * Send an Iframe request to the streamer */ sendIframeRequest() { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), '---- Sending Request for an IFrame ----', 6); this.streamMessageController.toStreamerHandlers.get('IFrameRequest')(); } /** * Send a UIInteraction message */ emitUIInteraction(descriptor) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), '---- Sending custom UIInteraction message ----', 6); this.streamMessageController.toStreamerHandlers.get('UIInteraction')([JSON.stringify(descriptor)]); } /** * Send a Command message */ emitCommand(descriptor) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), '---- Sending custom Command message ----', 6); this.streamMessageController.toStreamerHandlers.get('Command')([JSON.stringify(descriptor)]); } /** * Send a console command message */ emitConsoleCommand(command) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), '---- Sending custom Command:ConsoleCommand message ----', 6); this.streamMessageController.toStreamerHandlers.get('Command')([JSON.stringify({ ConsoleCommand: command, })]); } /** * Sends a request to the UE Instance to have ownership of Quality */ sendRequestQualityControlOwnership() { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), '---- Sending Request to Control Quality ----', 6); this.toStreamerMessagesController.SendRequestQualityControl(); } /** * Handles when a Latency Test Result are received from the UE Instance * @param message - Latency Test Timings */ handleLatencyTestResult(message) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'DataChannelReceiveMessageType.latencyTest', 6); const latencyAsString = new TextDecoder('utf-16').decode(message.slice(1)); const latencyTestResults = new _DataChannel_LatencyTestResults__WEBPACK_IMPORTED_MODULE_18__.LatencyTestResults(); Object.assign(latencyTestResults, JSON.parse(latencyAsString)); latencyTestResults.processFields(); latencyTestResults.testStartTimeMs = this.latencyStartTime; latencyTestResults.browserReceiptTimeMs = Date.now(); latencyTestResults.latencyExcludingDecode = ~~(latencyTestResults.browserReceiptTimeMs - latencyTestResults.testStartTimeMs); latencyTestResults.testDuration = ~~(latencyTestResults.TransmissionTimeMs - latencyTestResults.ReceiptTimeMs); latencyTestResults.networkLatency = ~~(latencyTestResults.latencyExcludingDecode - latencyTestResults.testDuration); if (latencyTestResults.frameDisplayDeltaTimeMs && latencyTestResults.browserReceiptTimeMs) { latencyTestResults.endToEndLatency = ~~(latencyTestResults.frameDisplayDeltaTimeMs + latencyTestResults.networkLatency, +latencyTestResults.CaptureToSendMs); } this.pixelStreaming._onLatencyTestResult(latencyTestResults); } /** * Handles when a Data Channel Latency Test Response is received from the UE Instance * @param message - Data Channel Latency Test Response */ handleDataChannelLatencyTestResponse(message) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'DataChannelReceiveMessageType.dataChannelLatencyResponse', 6); const responseAsString = new TextDecoder('utf-16').decode(message.slice(1)); const latencyTestResponse = JSON.parse(responseAsString); this.pixelStreaming._onDataChannelLatencyTestResponse(latencyTestResponse); } /** * Handles when the Encoder and Web RTC Settings are received from the UE Instance * @param message - Initial Encoder and Web RTC Settings */ handleInitialSettings(message) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'DataChannelReceiveMessageType.InitialSettings', 6); const payloadAsString = new TextDecoder('utf-16').decode(message.slice(1)); const parsedInitialSettings = JSON.parse(payloadAsString); const initialSettings = new _DataChannel_InitialSettings__WEBPACK_IMPORTED_MODULE_19__.InitialSettings(); if (parsedInitialSettings.Encoder) { initialSettings.EncoderSettings = parsedInitialSettings.Encoder; } if (parsedInitialSettings.WebRTC) { initialSettings.WebRTCSettings = parsedInitialSettings.WebRTC; } if (parsedInitialSettings.PixelStreaming) { initialSettings.PixelStreamingSettings = parsedInitialSettings.PixelStreaming; } if (parsedInitialSettings.ConfigOptions && parsedInitialSettings.ConfigOptions.DefaultToHover !== undefined) { this.config.setFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.Flags.HoveringMouseMode, !!parsedInitialSettings.ConfigOptions.DefaultToHover); } initialSettings.ueCompatible(); _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), payloadAsString, 6); this.pixelStreaming._onInitialSettings(initialSettings); } /** * Handles when the Quantization Parameter are received from the UE Instance * @param message - Encoders Quantization Parameter */ handleVideoEncoderAvgQP(message) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'DataChannelReceiveMessageType.VideoEncoderAvgQP', 6); const AvgQP = Number(new TextDecoder('utf-16').decode(message.slice(1))); this.setVideoEncoderAvgQP(AvgQP); } /** * Handles when the video element has been loaded with a srcObject */ handleVideoInitialized() { this.pixelStreaming._onVideoInitialized(); // either autoplay the video or set up the play overlay this.autoPlayVideoOrSetUpPlayOverlay(); this.resizePlayerStyle(); this.videoPlayer.updateVideoStreamSize(); } /** * Flag set if the user has Quality Ownership * @param message - Does the current client have Quality Ownership */ onQualityControlOwnership(message) { const view = new Uint8Array(message); _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), 'DataChannelReceiveMessageType.QualityControlOwnership', 6); this.isQualityController = new Boolean(view[1]).valueOf(); _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), `Received quality controller message, will control quality: ${this.isQualityController}`); this.pixelStreaming._onQualityControlOwnership(this.isQualityController); } /** * Handles when the Aggregated stats are Collected * @param stats - Aggregated Stats */ handleVideoStats(stats) { this.pixelStreaming._onVideoStats(stats); } /** * To Resize the Video Player element */ resizePlayerStyle() { this.videoPlayer.resizePlayerStyle(); } setPreferredCodec(codec) { this.preferredCodec = codec; if (this.peerConnectionController) { this.peerConnectionController.preferredCodec = codec; this.peerConnectionController.updateCodecSelection = false; } } setVideoEncoderAvgQP(avgQP) { this.videoAvgQp = avgQP; this.pixelStreaming._onVideoEncoderAvgQP(this.videoAvgQp); } /** * enables/disables keyboard event listeners */ setKeyboardInputEnabled(isEnabled) { var _a; (_a = this.keyboardController) === null || _a === void 0 ? void 0 : _a.unregisterKeyBoardEvents(); if (isEnabled) { this.keyboardController = this.inputClassesFactory.registerKeyBoard(this.config); } } /** * enables/disables mouse event listeners */ setMouseInputEnabled(isEnabled) { var _a; (_a = this.mouseController) === null || _a === void 0 ? void 0 : _a.unregisterMouseEvents(); if (isEnabled) { const mouseMode = this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.Flags.HoveringMouseMode) ? _Config_Config__WEBPACK_IMPORTED_MODULE_11__.ControlSchemeType.HoveringMouse : _Config_Config__WEBPACK_IMPORTED_MODULE_11__.ControlSchemeType.LockedMouse; this.mouseController = this.inputClassesFactory.registerMouse(mouseMode); } } /** * enables/disables touch event listeners */ setTouchInputEnabled(isEnabled) { var _a; (_a = this.touchController) === null || _a === void 0 ? void 0 : _a.unregisterTouchEvents(); if (isEnabled) { this.touchController = this.inputClassesFactory.registerTouch(this.config.isFlagEnabled(_Config_Config__WEBPACK_IMPORTED_MODULE_11__.Flags.FakeMouseWithTouches), this.videoElementParentClientRect); } } /** * enables/disables game pad event listeners */ setGamePadInputEnabled(isEnabled) { var _a; (_a = this.gamePadController) === null || _a === void 0 ? void 0 : _a.unregisterGamePadEvents(); if (isEnabled) { this.gamePadController = this.inputClassesFactory.registerGamePad(); this.gamePadController.onGamepadConnected = () => { this.streamMessageController.toStreamerHandlers.get('GamepadConnected')(); }; this.gamePadController.onGamepadDisconnected = (controllerIdx) => { this.streamMessageController.toStreamerHandlers.get('GamepadDisconnected')([controllerIdx]); }; } } registerDataChannelEventEmitters(dataChannel) { dataChannel.onOpen = (label, event) => this.pixelStreaming.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_16__.DataChannelOpenEvent({ label, event })); dataChannel.onClose = (label, event) => this.pixelStreaming.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_16__.DataChannelCloseEvent({ label, event })); dataChannel.onError = (label, event) => this.pixelStreaming.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_16__.DataChannelErrorEvent({ label, event })); } registerMessageHandler(name, direction, handler) { if (direction === _UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.FromStreamer && typeof handler === 'undefined') { _Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.Warning(_Logger_Logger__WEBPACK_IMPORTED_MODULE_15__.Logger.GetStackTrace(), `Unable to register handler for ${name} as no handler was passed`); } this.streamMessageController.registerMessageHandler(direction, name, (data) => (typeof handler === 'undefined' && direction === _UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_9__.MessageDirection.ToStreamer) ? this.sendMessageController.sendMessageToStreamer(name, data) : handler(data)); } } /***/ }), /***/ "./src/WebSockets/MessageReceive.ts": /*!******************************************!*\ !*** ./src/WebSockets/MessageReceive.ts ***! \******************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "MessageAnswer": () => (/* binding */ MessageAnswer), /* harmony export */ "MessageAuthRequired": () => (/* binding */ MessageAuthRequired), /* harmony export */ "MessageConfig": () => (/* binding */ MessageConfig), /* harmony export */ "MessageIceCandidate": () => (/* binding */ MessageIceCandidate), /* harmony export */ "MessageOffer": () => (/* binding */ MessageOffer), /* harmony export */ "MessageOnScreenKeyboard": () => (/* binding */ MessageOnScreenKeyboard), /* harmony export */ "MessagePeerDataChannels": () => (/* binding */ MessagePeerDataChannels), /* harmony export */ "MessagePlayerCount": () => (/* binding */ MessagePlayerCount), /* harmony export */ "MessageRecv": () => (/* binding */ MessageRecv), /* harmony export */ "MessageRecvTypes": () => (/* binding */ MessageRecvTypes), /* harmony export */ "MessageStreamerList": () => (/* binding */ MessageStreamerList) /* harmony export */ }); // Copyright Epic Games, Inc. All Rights Reserved. /** * The Types of Messages that will be received */ var MessageRecvTypes; (function (MessageRecvTypes) { MessageRecvTypes["CONFIG"] = "config"; MessageRecvTypes["STREAMER_LIST"] = "streamerList"; MessageRecvTypes["PLAYER_COUNT"] = "playerCount"; MessageRecvTypes["OFFER"] = "offer"; MessageRecvTypes["ANSWER"] = "answer"; MessageRecvTypes["ICE_CANDIDATE"] = "iceCandidate"; MessageRecvTypes["PEER_DATA_CHANNELS"] = "peerDataChannels"; MessageRecvTypes["PING"] = "ping"; MessageRecvTypes["WARNING"] = "warning"; })(MessageRecvTypes || (MessageRecvTypes = {})); /** * Concrete Received Message wrapper */ class MessageRecv { } /** * Authentication Required Message wrapper */ class MessageAuthRequired extends MessageRecv { } /** * Config Message Wrapper */ class MessageConfig extends MessageRecv { } /** * Streamer List Message Wrapper */ class MessageStreamerList extends MessageRecv { } /** * Player Count Message wrapper */ class MessagePlayerCount extends MessageRecv { } /** * Web RTC offer Answer Message wrapper */ class MessageAnswer extends MessageRecv { } /** * WebRTC sdp offer Message wrapper. */ class MessageOffer extends MessageRecv { } /** * Ice Candidate Message wrapper */ class MessageIceCandidate extends MessageRecv { } /** * Peer Data Channels Message wrapper */ class MessagePeerDataChannels extends MessageRecv { } class MessageOnScreenKeyboard { } /***/ }), /***/ "./src/WebSockets/MessageSend.ts": /*!***************************************!*\ !*** ./src/WebSockets/MessageSend.ts ***! \***************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "MessageIceCandidate": () => (/* binding */ MessageIceCandidate), /* harmony export */ "MessageListStreamers": () => (/* binding */ MessageListStreamers), /* harmony export */ "MessagePong": () => (/* binding */ MessagePong), /* harmony export */ "MessageSFURecvDataChannelReady": () => (/* binding */ MessageSFURecvDataChannelReady), /* harmony export */ "MessageSend": () => (/* binding */ MessageSend), /* harmony export */ "MessageSendTypes": () => (/* binding */ MessageSendTypes), /* harmony export */ "MessageSubscribe": () => (/* binding */ MessageSubscribe), /* harmony export */ "MessageUnsubscribe": () => (/* binding */ MessageUnsubscribe), /* harmony export */ "MessageWebRTCAnswer": () => (/* binding */ MessageWebRTCAnswer), /* harmony export */ "MessageWebRTCDatachannelRequest": () => (/* binding */ MessageWebRTCDatachannelRequest), /* harmony export */ "MessageWebRTCOffer": () => (/* binding */ MessageWebRTCOffer) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * The Send Types that are pushed from the signaling server */ var MessageSendTypes; (function (MessageSendTypes) { MessageSendTypes["LIST_STREAMERS"] = "listStreamers"; MessageSendTypes["SUBSCRIBE"] = "subscribe"; MessageSendTypes["UNSUBSCRIBE"] = "unsubscribe"; MessageSendTypes["ICE_CANDIDATE"] = "iceCandidate"; MessageSendTypes["OFFER"] = "offer"; MessageSendTypes["ANSWER"] = "answer"; MessageSendTypes["DATACHANNELREQUEST"] = "dataChannelRequest"; MessageSendTypes["SFURECVDATACHANNELREADY"] = "peerDataChannelsReady"; MessageSendTypes["PONG"] = "pong"; })(MessageSendTypes || (MessageSendTypes = {})); /** * A Wrapper for the message to send to the signaling server */ class MessageSend { /** * Turns the wrapper into a JSON String * @returns - JSON String of the Message to send */ payload() { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'Sending => \n' + JSON.stringify(this, undefined, 4), 6); return JSON.stringify(this); } } class MessageListStreamers extends MessageSend { constructor() { super(); this.type = MessageSendTypes.LIST_STREAMERS; } } class MessageSubscribe extends MessageSend { constructor(streamerid) { super(); this.type = MessageSendTypes.SUBSCRIBE; this.streamerId = streamerid; } } class MessageUnsubscribe extends MessageSend { constructor() { super(); this.type = MessageSendTypes.UNSUBSCRIBE; } } /** * Instance Request Message Wrapper */ class MessagePong extends MessageSend { constructor(time) { super(); this.type = MessageSendTypes.PONG; this.time = time; } } /** * Web RTC Offer message wrapper */ class MessageWebRTCOffer extends MessageSend { /** * @param offer - Generated Web RTC Offer */ constructor(offer) { super(); this.type = MessageSendTypes.OFFER; if (offer) { this.type = offer.type; this.sdp = offer.sdp; } } } /** * Web RTC Answer message wrapper */ class MessageWebRTCAnswer extends MessageSend { /** * @param answer - Generated Web RTC Offer */ constructor(answer) { super(); this.type = MessageSendTypes.ANSWER; if (answer) { this.type = answer.type; this.sdp = answer.sdp; } } } /** * Web RTC Data channel request message wrapper */ class MessageWebRTCDatachannelRequest extends MessageSend { constructor() { super(); this.type = MessageSendTypes.DATACHANNELREQUEST; } } /** * Web RTC SFU Data channel ready message wrapper */ class MessageSFURecvDataChannelReady extends MessageSend { constructor() { super(); this.type = MessageSendTypes.SFURECVDATACHANNELREADY; } } /** * RTC Ice Candidate Wrapper */ class MessageIceCandidate { /** * @param candidate - RTC Ice Candidate */ constructor(candidate) { this.type = MessageSendTypes.ICE_CANDIDATE; this.candidate = candidate; } /** * Turns the wrapper into a JSON String * @returns - JSON String of the Message to send */ payload() { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'Sending => \n' + JSON.stringify(this, undefined, 4), 6); return JSON.stringify(this); } } /***/ }), /***/ "./src/WebSockets/SignallingProtocol.ts": /*!**********************************************!*\ !*** ./src/WebSockets/SignallingProtocol.ts ***! \**********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "SignallingProtocol": () => (/* binding */ SignallingProtocol) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); /* harmony import */ var _MessageReceive__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./MessageReceive */ "./src/WebSockets/MessageReceive.ts"); /* harmony import */ var _MessageSend__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./MessageSend */ "./src/WebSockets/MessageSend.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * Signalling protocol for handling messages from the signalling server. */ class SignallingProtocol { constructor() { this.FromUEMessageHandlers = new Map(); } addMessageHandler(messageId, messageHandler) { this.FromUEMessageHandlers.set(messageId, messageHandler); } handleMessage(messageId, messageData) { if (this.FromUEMessageHandlers.has(messageId)) { this.FromUEMessageHandlers.get(messageId)(messageData); } else { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), `Message type of ${messageId} does not have a message handler registered on the frontend - ignoring message.`); } } /** * Setup any default signalling message handling, these can be overridden or additional handlers added with `addMessageHandler`. * @param websocketController The controller to setup these handlers on. */ static setupDefaultHandlers(websocketController) { // PING websocketController.signallingProtocol.addMessageHandler(_MessageReceive__WEBPACK_IMPORTED_MODULE_1__.MessageRecvTypes.PING, (pingPayload) => { // send our pong payload back to the signalling server const pongPayload = new _MessageSend__WEBPACK_IMPORTED_MODULE_2__.MessagePong(new Date().getTime()).payload(); _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), _MessageReceive__WEBPACK_IMPORTED_MODULE_1__.MessageRecvTypes.PING + ': ' + pingPayload, 6); websocketController.webSocket.send(pongPayload); }); // CONFIG websocketController.signallingProtocol.addMessageHandler(_MessageReceive__WEBPACK_IMPORTED_MODULE_1__.MessageRecvTypes.CONFIG, (configPayload) => { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), _MessageReceive__WEBPACK_IMPORTED_MODULE_1__.MessageRecvTypes.CONFIG, 6); const config = JSON.parse(configPayload); websocketController.onConfig(config); }); // STREAMER_LIST websocketController.signallingProtocol.addMessageHandler(_MessageReceive__WEBPACK_IMPORTED_MODULE_1__.MessageRecvTypes.STREAMER_LIST, (listPayload) => { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), _MessageReceive__WEBPACK_IMPORTED_MODULE_1__.MessageRecvTypes.STREAMER_LIST, 6); const streamerList = JSON.parse(listPayload); websocketController.onStreamerList(streamerList); }); // PLAYER_COUNT websocketController.signallingProtocol.addMessageHandler(_MessageReceive__WEBPACK_IMPORTED_MODULE_1__.MessageRecvTypes.PLAYER_COUNT, (playerCountPayload) => { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), _MessageReceive__WEBPACK_IMPORTED_MODULE_1__.MessageRecvTypes.PLAYER_COUNT, 6); const playerCount = JSON.parse(playerCountPayload); _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), 'Player Count: ' + playerCount.count, 6); websocketController.onPlayerCount(playerCount); }); // ANSWER websocketController.signallingProtocol.addMessageHandler(_MessageReceive__WEBPACK_IMPORTED_MODULE_1__.MessageRecvTypes.ANSWER, (answerPayload) => { // send our pong payload back to the signalling server _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), _MessageReceive__WEBPACK_IMPORTED_MODULE_1__.MessageRecvTypes.ANSWER, 6); const answer = JSON.parse(answerPayload); websocketController.onWebRtcAnswer(answer); }); // OFFER websocketController.signallingProtocol.addMessageHandler(_MessageReceive__WEBPACK_IMPORTED_MODULE_1__.MessageRecvTypes.OFFER, (offerPayload) => { // send our pong payload back to the signalling server _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), _MessageReceive__WEBPACK_IMPORTED_MODULE_1__.MessageRecvTypes.OFFER, 6); const offer = JSON.parse(offerPayload); websocketController.onWebRtcOffer(offer); }); // ICE CANDIDATE websocketController.signallingProtocol.addMessageHandler(_MessageReceive__WEBPACK_IMPORTED_MODULE_1__.MessageRecvTypes.ICE_CANDIDATE, (iceCandidatePayload) => { // send our pong payload back to the signalling server _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), _MessageReceive__WEBPACK_IMPORTED_MODULE_1__.MessageRecvTypes.ICE_CANDIDATE, 6); const iceCandidate = JSON.parse(iceCandidatePayload); websocketController.onIceCandidate(iceCandidate.candidate); }); // WARNING websocketController.signallingProtocol.addMessageHandler(_MessageReceive__WEBPACK_IMPORTED_MODULE_1__.MessageRecvTypes.WARNING, (warningPayload) => { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Warning(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), `Warning received: ${warningPayload}`); }); // PEER DATA CHANNELS websocketController.signallingProtocol.addMessageHandler(_MessageReceive__WEBPACK_IMPORTED_MODULE_1__.MessageRecvTypes.PEER_DATA_CHANNELS, (peerDataChannelsPayload) => { _Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_0__.Logger.GetStackTrace(), _MessageReceive__WEBPACK_IMPORTED_MODULE_1__.MessageRecvTypes.PEER_DATA_CHANNELS, 6); const peerDataChannels = JSON.parse(peerDataChannelsPayload); websocketController.onWebRtcPeerDataChannels(peerDataChannels); }); } } /***/ }), /***/ "./src/WebSockets/WebSocketController.ts": /*!***********************************************!*\ !*** ./src/WebSockets/WebSocketController.ts ***! \***********************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "WebSocketController": () => (/* binding */ WebSocketController) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); /* harmony import */ var _MessageSend__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./MessageSend */ "./src/WebSockets/MessageSend.ts"); /* harmony import */ var _SignallingProtocol__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./SignallingProtocol */ "./src/WebSockets/SignallingProtocol.ts"); // Copyright Epic Games, Inc. All Rights Reserved. /** * The controller for the WebSocket and all associated methods */ class WebSocketController { constructor() { this.WS_OPEN_STATE = 1; this.onOpen = new EventTarget(); this.onClose = new EventTarget(); this.signallingProtocol = new _SignallingProtocol__WEBPACK_IMPORTED_MODULE_0__.SignallingProtocol(); _SignallingProtocol__WEBPACK_IMPORTED_MODULE_0__.SignallingProtocol.setupDefaultHandlers(this); } /** * Connect to the signaling server * @param connectionURL - The Address of the signaling server * @returns - If there is a connection */ connect(connectionURL) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), connectionURL, 6); try { this.webSocket = new WebSocket(connectionURL); this.webSocket.onopen = (event) => this.handleOnOpen(event); this.webSocket.onerror = () => this.handleOnError(); this.webSocket.onclose = (event) => this.handleOnClose(event); this.webSocket.onmessage = (event) => this.handleOnMessage(event); this.webSocket.onmessagebinary = (event) => this.handleOnMessageBinary(event); return true; } catch (error) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Error(error, error); return false; } } /** * Handles what happens when a message is received in binary form * @param event - Message Received */ handleOnMessageBinary(event) { // if the event is empty return if (!event || !event.data) { return; } // handle the binary and then handle the message event.data .text() .then((messageString) => { // build a new message const constructedMessage = new MessageEvent('messageFromBinary', { data: messageString }); // send the new stringified event back into `onmessage` this.handleOnMessage(constructedMessage); }) .catch((error) => { _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), `Failed to parse binary blob from websocket, reason: ${error}`); }); } /** * Handles what happens when a message is received * @param event - Message Received */ handleOnMessage(event) { // Check if websocket message is binary, if so, stringify it. if (event.data && event.data instanceof Blob) { this.handleOnMessageBinary(event); return; } const message = JSON.parse(event.data); _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'received => \n' + JSON.stringify(JSON.parse(event.data), undefined, 4), 6); // Send to our signalling protocol to handle the incoming message this.signallingProtocol.handleMessage(message.type, event.data); } /** * Handles when the Websocket is opened * @param event - Not Used */ // eslint-disable-next-line @typescript-eslint/no-unused-vars handleOnOpen(event) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'Connected to the signalling server via WebSocket', 6); this.onOpen.dispatchEvent(new Event('open')); } /** * Handles when there is an error on the websocket * @param event - Error Payload */ handleOnError() { _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Error(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'WebSocket error'); } /** * Handles when the Websocket is closed * @param event - Close Event */ handleOnClose(event) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'Disconnected to the signalling server via WebSocket: ' + JSON.stringify(event.code) + ' - ' + event.reason); this.onClose.dispatchEvent(new CustomEvent('close', { 'detail': event })); } requestStreamerList() { const payload = new _MessageSend__WEBPACK_IMPORTED_MODULE_2__.MessageListStreamers(); this.webSocket.send(payload.payload()); } sendSubscribe(streamerid) { const payload = new _MessageSend__WEBPACK_IMPORTED_MODULE_2__.MessageSubscribe(streamerid); this.webSocket.send(payload.payload()); } sendUnsubscribe() { const payload = new _MessageSend__WEBPACK_IMPORTED_MODULE_2__.MessageUnsubscribe(); this.webSocket.send(payload.payload()); } sendWebRtcOffer(offer) { const payload = new _MessageSend__WEBPACK_IMPORTED_MODULE_2__.MessageWebRTCOffer(offer); this.webSocket.send(payload.payload()); } sendWebRtcAnswer(answer) { const payload = new _MessageSend__WEBPACK_IMPORTED_MODULE_2__.MessageWebRTCAnswer(answer); this.webSocket.send(payload.payload()); } sendWebRtcDatachannelRequest() { const payload = new _MessageSend__WEBPACK_IMPORTED_MODULE_2__.MessageWebRTCDatachannelRequest(); this.webSocket.send(payload.payload()); } sendSFURecvDataChannelReady() { const payload = new _MessageSend__WEBPACK_IMPORTED_MODULE_2__.MessageSFURecvDataChannelReady(); this.webSocket.send(payload.payload()); } /** * Sends an RTC Ice Candidate to the Server * @param candidate - RTC Ice Candidate */ sendIceCandidate(candidate) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'Sending Ice Candidate'); if (this.webSocket && this.webSocket.readyState === this.WS_OPEN_STATE) { //ws.send(JSON.stringify({ type: 'iceCandidate', candidate: candidate })); const IceCandidate = new _MessageSend__WEBPACK_IMPORTED_MODULE_2__.MessageIceCandidate(candidate); this.webSocket.send(IceCandidate.payload()); } } /** * Closes the Websocket connection */ close() { var _a; (_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.close(); } /** * The Message Contains the payload of the peer connection options used for the RTC Peer hand shake * @param messageConfig - Config Message received from he signaling server */ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function onConfig(messageConfig) { } /** * The Message Contains the payload of the peer connection options used for the RTC Peer hand shake * @param messageConfig - Config Message received from he signaling server */ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function onStreamerList(messageStreamerList) { } /** * @param iceCandidate - Ice Candidate sent from the Signaling server server's RTC hand shake */ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function onIceCandidate(iceCandidate) { } /** * Event is fired when the websocket receives the answer for the RTC peer Connection * @param messageAnswer - The RTC Answer payload from the signaling server */ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function onWebRtcAnswer(messageAnswer) { } /** * Event is fired when the websocket receives the offer for the RTC peer Connection * @param messageOffer - The sdp offer */ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function onWebRtcOffer(messageOffer) { } /** * Event is fired when the websocket receives the data channels for the RTC peer Connection from the SFU * @param messageDataChannels - The data channels details */ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function onWebRtcPeerDataChannels(messageDataChannels) { } /** * Event is fired when the websocket receives the an updated player count from cirrus * @param MessagePlayerCount - The new player count */ // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function onPlayerCount(playerCount) { } } /***/ }), /***/ "./src/WebXR/WebXRController.ts": /*!**************************************!*\ !*** ./src/WebXR/WebXRController.ts ***! \**************************************/ /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "WebXRController": () => (/* binding */ WebXRController) /* harmony export */ }); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../Logger/Logger */ "./src/Logger/Logger.ts"); /* harmony import */ var _Util_WebGLUtils__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../Util/WebGLUtils */ "./src/Util/WebGLUtils.ts"); /* harmony import */ var _Inputs_XRGamepadController__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../Inputs/XRGamepadController */ "./src/Inputs/XRGamepadController.ts"); /* harmony import */ var _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../Util/EventEmitter */ "./src/Util/EventEmitter.ts"); /* harmony import */ var _pixelstreamingfrontend__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../pixelstreamingfrontend */ "./src/Config/Config.ts"); // Copyright Epic Games, Inc. All Rights Reserved. class WebXRController { constructor(webRtcPlayerController) { this.xrSession = null; this.webRtcController = webRtcPlayerController; this.xrControllers = []; this.xrGamepadController = new _Inputs_XRGamepadController__WEBPACK_IMPORTED_MODULE_0__.XRGamepadController(this.webRtcController.streamMessageController); this.onSessionEnded = new EventTarget(); this.onSessionStarted = new EventTarget(); this.onFrame = new EventTarget(); } xrClicked() { if (!this.xrSession) { navigator.xr .requestSession('immersive-vr') .then((session) => { this.onXrSessionStarted(session); }); } else { this.xrSession.end(); } } onXrSessionEnded() { _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'XR Session ended'); this.xrSession = null; this.onSessionEnded.dispatchEvent(new Event('xrSessionEnded')); } onXrSessionStarted(session) { _Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.Log(_Logger_Logger__WEBPACK_IMPORTED_MODULE_1__.Logger.GetStackTrace(), 'XR Session started'); this.xrSession = session; this.xrSession.addEventListener('end', () => { this.onXrSessionEnded(); }); const canvas = document.createElement('canvas'); this.gl = canvas.getContext('webgl2', { xrCompatible: true }); this.xrSession.updateRenderState({ baseLayer: new XRWebGLLayer(this.xrSession, this.gl) }); // setup vertex shader const vertexShader = this.gl.createShader(this.gl.VERTEX_SHADER); this.gl.shaderSource(vertexShader, _Util_WebGLUtils__WEBPACK_IMPORTED_MODULE_2__.WebGLUtils.vertexShader()); this.gl.compileShader(vertexShader); // setup fragment shader const fragmentShader = this.gl.createShader(this.gl.FRAGMENT_SHADER); this.gl.shaderSource(fragmentShader, _Util_WebGLUtils__WEBPACK_IMPORTED_MODULE_2__.WebGLUtils.fragmentShader()); this.gl.compileShader(fragmentShader); // setup GLSL program const shaderProgram = this.gl.createProgram(); this.gl.attachShader(shaderProgram, vertexShader); this.gl.attachShader(shaderProgram, fragmentShader); this.gl.linkProgram(shaderProgram); this.gl.useProgram(shaderProgram); // look up where vertex data needs to go this.positionLocation = this.gl.getAttribLocation(shaderProgram, 'a_position'); this.texcoordLocation = this.gl.getAttribLocation(shaderProgram, 'a_texCoord'); // Create a buffer to put three 2d clip space points in this.positionBuffer = this.gl.createBuffer(); // Bind it to ARRAY_BUFFER (think of it as ARRAY_BUFFER = positionBuffer) this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer); // Turn on the position attribute this.gl.enableVertexAttribArray(this.positionLocation); // Create a texture. const texture = this.gl.createTexture(); this.gl.bindTexture(this.gl.TEXTURE_2D, texture); // Set the parameters so we can render any size image. this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE); this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE); this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST); this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST); this.texcoordBuffer = this.gl.createBuffer(); // lookup uniforms this.resolutionLocation = this.gl.getUniformLocation(shaderProgram, 'u_resolution'); this.offsetLocation = this.gl.getUniformLocation(shaderProgram, 'u_offset'); session.requestReferenceSpace('local').then((refSpace) => { this.xrRefSpace = refSpace; this.xrSession.requestAnimationFrame((time, frame) => this.onXrFrame(time, frame)); }); this.onSessionStarted.dispatchEvent(new Event('xrSessionStarted')); } onXrFrame(time, frame) { const pose = frame.getViewerPose(this.xrRefSpace); if (pose) { const matrix = pose.transform.matrix; const mat = []; for (let i = 0; i < 16; i++) { mat[i] = new Float32Array([matrix[i]])[0]; } // prettier-ignore this.webRtcController.streamMessageController.toStreamerHandlers.get('XRHMDTransform')([ mat[0], mat[4], mat[8], mat[12], mat[1], mat[5], mat[9], mat[13], mat[2], mat[6], mat[10], mat[14], mat[3], mat[7], mat[11], mat[15] ]); const glLayer = this.xrSession.renderState.baseLayer; // If we do have a valid pose, bind the WebGL layer's framebuffer, // which is where any content to be displayed on the XRDevice must be // rendered. this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, glLayer.framebuffer); // Upload the image into the texture. WebGL knows how to extract the current frame from the video element this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, this.webRtcController.videoPlayer.getVideoElement()); this.render(this.webRtcController.videoPlayer.getVideoElement()); } if (this.webRtcController.config.isFlagEnabled(_pixelstreamingfrontend__WEBPACK_IMPORTED_MODULE_3__.Flags.XRControllerInput)) { this.xrSession.inputSources.forEach((source, index, array) => { this.xrGamepadController.updateStatus(source, frame, this.xrRefSpace); }, this); } this.xrSession.requestAnimationFrame((time, frame) => this.onXrFrame(time, frame)); this.onFrame.dispatchEvent(new _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_4__.XrFrameEvent({ time, frame })); } render(videoElement) { if (!this.gl) { return; } const glLayer = this.xrSession.renderState.baseLayer; this.gl.viewport(0, 0, glLayer.framebufferWidth, glLayer.framebufferHeight); this.gl.uniform4f(this.offsetLocation, 1.0, 1.0, 0.0, 0.0); // Set rectangle // prettier-ignore this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array([ 0, 0, videoElement.videoWidth, 0, 0, videoElement.videoHeight, 0, videoElement.videoHeight, videoElement.videoWidth, 0, videoElement.videoWidth, videoElement.videoHeight ]), this.gl.STATIC_DRAW); // Provide texture coordinates for the rectangle this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texcoordBuffer); this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array([ 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0 ]), this.gl.STATIC_DRAW); let size; // components per iteration let type; // the data type let normalize; // normalize the data let stride; // 0 = move forward size * sizeof(type) each iteration to get the next position let offset; // start position of the buffer // Bind the position buffer. this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer); // Tell the position attribute how to get data out of positionBuffer (ARRAY_BUFFER) size = 2; // 2 components per iteration type = this.gl.FLOAT; // the data is 32bit floats normalize = false; // don't normalize the data stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position offset = 0; // start at the beginning of the buffer this.gl.vertexAttribPointer(this.positionLocation, size, type, normalize, stride, offset); // Turn on the texcoord attribute this.gl.enableVertexAttribArray(this.texcoordLocation); // bind the texcoord buffer. this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texcoordBuffer); // Tell the texcoord attribute how to get data out of texcoordBuffer (ARRAY_BUFFER) size = 2; // 2 components per iteration type = this.gl.FLOAT; // the data is 32bit floats normalize = false; // don't normalize the data stride = 0; // 0 = move forward size * sizeof(type) each iteration to get the next position offset = 0; // start at the beginning of the buffer this.gl.vertexAttribPointer(this.texcoordLocation, size, type, normalize, stride, offset); // set the resolution this.gl.uniform2f(this.resolutionLocation, videoElement.videoWidth, videoElement.videoHeight); // draw the rectangle. const primitiveType = this.gl.TRIANGLES; const count = 6; offset = 0; this.gl.drawArrays(primitiveType, offset, count); } static isSessionSupported(mode) { if (navigator.xr) { return navigator.xr.isSessionSupported(mode); } else { return new Promise(() => { return false; }); } } } /***/ }), /***/ "sdp": /*!**********************!*\ !*** external "sdp" ***! \**********************/ /***/ ((module) => { module.exports = __WEBPACK_EXTERNAL_MODULE_sdp__; /***/ }) /******/ }); /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ var cachedModule = __webpack_module_cache__[moduleId]; /******/ if (cachedModule !== undefined) { /******/ return cachedModule.exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = __webpack_module_cache__[moduleId] = { /******/ // no module.id needed /******/ // no module.loaded needed /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ __webpack_modules__[moduleId](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 /******/ __webpack_require__.d = (exports, definition) => { /******/ for(var key in definition) { /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ (() => { /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) /******/ })(); /******/ /******/ /* webpack/runtime/make namespace object */ /******/ (() => { /******/ // define __esModule on exports /******/ __webpack_require__.r = (exports) => { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ })(); /******/ /************************************************************************/ var __webpack_exports__ = {}; // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. (() => { /*!***************************************!*\ !*** ./src/pixelstreamingfrontend.ts ***! \***************************************/ __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ "AfkLogic": () => (/* reexport safe */ _AFK_AFKController__WEBPACK_IMPORTED_MODULE_9__.AFKController), /* harmony export */ "AfkTimedOutEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.AfkTimedOutEvent), /* harmony export */ "AfkWarningActivateEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.AfkWarningActivateEvent), /* harmony export */ "AfkWarningDeactivateEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.AfkWarningDeactivateEvent), /* harmony export */ "AfkWarningUpdateEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.AfkWarningUpdateEvent), /* harmony export */ "AggregatedStats": () => (/* reexport safe */ _PeerConnectionController_AggregatedStats__WEBPACK_IMPORTED_MODULE_12__.AggregatedStats), /* harmony export */ "CandidatePairStats": () => (/* reexport safe */ _PeerConnectionController_CandidatePairStats__WEBPACK_IMPORTED_MODULE_20__.CandidatePairStats), /* harmony export */ "CandidateStat": () => (/* reexport safe */ _PeerConnectionController_CandidateStat__WEBPACK_IMPORTED_MODULE_21__.CandidateStat), /* harmony export */ "Config": () => (/* reexport safe */ _Config_Config__WEBPACK_IMPORTED_MODULE_2__.Config), /* harmony export */ "ControlSchemeType": () => (/* reexport safe */ _Config_Config__WEBPACK_IMPORTED_MODULE_2__.ControlSchemeType), /* harmony export */ "DataChannelCloseEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.DataChannelCloseEvent), /* harmony export */ "DataChannelErrorEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.DataChannelErrorEvent), /* harmony export */ "DataChannelLatencyTestResponseEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.DataChannelLatencyTestResponseEvent), /* harmony export */ "DataChannelLatencyTestResultEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.DataChannelLatencyTestResultEvent), /* harmony export */ "DataChannelOpenEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.DataChannelOpenEvent), /* harmony export */ "DataChannelStats": () => (/* reexport safe */ _PeerConnectionController_DataChannelStats__WEBPACK_IMPORTED_MODULE_22__.DataChannelStats), /* harmony export */ "EncoderSettings": () => (/* reexport safe */ _DataChannel_InitialSettings__WEBPACK_IMPORTED_MODULE_11__.EncoderSettings), /* harmony export */ "EventEmitter": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.EventEmitter), /* harmony export */ "Flags": () => (/* reexport safe */ _Config_Config__WEBPACK_IMPORTED_MODULE_2__.Flags), /* harmony export */ "HideFreezeFrameEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.HideFreezeFrameEvent), /* harmony export */ "InboundAudioStats": () => (/* reexport safe */ _PeerConnectionController_InboundRTPStats__WEBPACK_IMPORTED_MODULE_23__.InboundAudioStats), /* harmony export */ "InboundVideoStats": () => (/* reexport safe */ _PeerConnectionController_InboundRTPStats__WEBPACK_IMPORTED_MODULE_23__.InboundVideoStats), /* harmony export */ "InitialSettings": () => (/* reexport safe */ _DataChannel_InitialSettings__WEBPACK_IMPORTED_MODULE_11__.InitialSettings), /* harmony export */ "InitialSettingsEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.InitialSettingsEvent), /* harmony export */ "LatencyTestResultEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.LatencyTestResultEvent), /* harmony export */ "LatencyTestResults": () => (/* reexport safe */ _DataChannel_LatencyTestResults__WEBPACK_IMPORTED_MODULE_10__.LatencyTestResults), /* harmony export */ "LoadFreezeFrameEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.LoadFreezeFrameEvent), /* harmony export */ "Logger": () => (/* reexport safe */ _Logger_Logger__WEBPACK_IMPORTED_MODULE_13__.Logger), /* harmony export */ "MessageDirection": () => (/* reexport safe */ _UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_15__.MessageDirection), /* harmony export */ "MessageRecv": () => (/* reexport safe */ _WebSockets_MessageReceive__WEBPACK_IMPORTED_MODULE_17__.MessageRecv), /* harmony export */ "MessageSend": () => (/* reexport safe */ _WebSockets_MessageSend__WEBPACK_IMPORTED_MODULE_16__.MessageSend), /* harmony export */ "MessageStreamerList": () => (/* reexport safe */ _WebSockets_MessageReceive__WEBPACK_IMPORTED_MODULE_17__.MessageStreamerList), /* harmony export */ "NumericParameters": () => (/* reexport safe */ _Config_Config__WEBPACK_IMPORTED_MODULE_2__.NumericParameters), /* harmony export */ "OptionParameters": () => (/* reexport safe */ _Config_Config__WEBPACK_IMPORTED_MODULE_2__.OptionParameters), /* harmony export */ "OutBoundVideoStats": () => (/* reexport safe */ _PeerConnectionController_OutBoundRTPStats__WEBPACK_IMPORTED_MODULE_24__.OutBoundVideoStats), /* harmony export */ "PixelStreaming": () => (/* reexport safe */ _PixelStreaming_PixelStreaming__WEBPACK_IMPORTED_MODULE_8__.PixelStreaming), /* harmony export */ "PlayStreamErrorEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.PlayStreamErrorEvent), /* harmony export */ "PlayStreamEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.PlayStreamEvent), /* harmony export */ "PlayStreamRejectedEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.PlayStreamRejectedEvent), /* harmony export */ "PlayerCountEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.PlayerCountEvent), /* harmony export */ "SettingBase": () => (/* reexport safe */ _Config_SettingBase__WEBPACK_IMPORTED_MODULE_3__.SettingBase), /* harmony export */ "SettingFlag": () => (/* reexport safe */ _Config_SettingFlag__WEBPACK_IMPORTED_MODULE_4__.SettingFlag), /* harmony export */ "SettingNumber": () => (/* reexport safe */ _Config_SettingNumber__WEBPACK_IMPORTED_MODULE_5__.SettingNumber), /* harmony export */ "SettingOption": () => (/* reexport safe */ _Config_SettingOption__WEBPACK_IMPORTED_MODULE_6__.SettingOption), /* harmony export */ "SettingText": () => (/* reexport safe */ _Config_SettingText__WEBPACK_IMPORTED_MODULE_7__.SettingText), /* harmony export */ "SettingsChangedEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.SettingsChangedEvent), /* harmony export */ "SignallingProtocol": () => (/* reexport safe */ _WebSockets_SignallingProtocol__WEBPACK_IMPORTED_MODULE_19__.SignallingProtocol), /* harmony export */ "StatsReceivedEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.StatsReceivedEvent), /* harmony export */ "StreamLoadingEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.StreamLoadingEvent), /* harmony export */ "StreamPreConnectEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.StreamPreConnectEvent), /* harmony export */ "StreamPreDisconnectEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.StreamPreDisconnectEvent), /* harmony export */ "StreamReconnectEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.StreamReconnectEvent), /* harmony export */ "StreamerListMessageEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.StreamerListMessageEvent), /* harmony export */ "TextParameters": () => (/* reexport safe */ _Config_Config__WEBPACK_IMPORTED_MODULE_2__.TextParameters), /* harmony export */ "UnquantizedAndDenormalizeUnsigned": () => (/* reexport safe */ _Util_CoordinateConverter__WEBPACK_IMPORTED_MODULE_14__.UnquantizedDenormalizedUnsignedCoord), /* harmony export */ "VideoEncoderAvgQPEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.VideoEncoderAvgQPEvent), /* harmony export */ "VideoInitializedEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.VideoInitializedEvent), /* harmony export */ "WebRTCSettings": () => (/* reexport safe */ _DataChannel_InitialSettings__WEBPACK_IMPORTED_MODULE_11__.WebRTCSettings), /* harmony export */ "WebRtcAutoConnectEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.WebRtcAutoConnectEvent), /* harmony export */ "WebRtcConnectedEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.WebRtcConnectedEvent), /* harmony export */ "WebRtcConnectingEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.WebRtcConnectingEvent), /* harmony export */ "WebRtcDisconnectedEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.WebRtcDisconnectedEvent), /* harmony export */ "WebRtcFailedEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.WebRtcFailedEvent), /* harmony export */ "WebRtcPlayerController": () => (/* reexport safe */ _WebRtcPlayer_WebRtcPlayerController__WEBPACK_IMPORTED_MODULE_0__.WebRtcPlayerController), /* harmony export */ "WebRtcSdpEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.WebRtcSdpEvent), /* harmony export */ "WebSocketController": () => (/* reexport safe */ _WebSockets_WebSocketController__WEBPACK_IMPORTED_MODULE_18__.WebSocketController), /* harmony export */ "WebXRController": () => (/* reexport safe */ _WebXR_WebXRController__WEBPACK_IMPORTED_MODULE_1__.WebXRController), /* harmony export */ "XrFrameEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.XrFrameEvent), /* harmony export */ "XrSessionEndedEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.XrSessionEndedEvent), /* harmony export */ "XrSessionStartedEvent": () => (/* reexport safe */ _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__.XrSessionStartedEvent) /* harmony export */ }); /* harmony import */ var _WebRtcPlayer_WebRtcPlayerController__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./WebRtcPlayer/WebRtcPlayerController */ "./src/WebRtcPlayer/WebRtcPlayerController.ts"); /* harmony import */ var _WebXR_WebXRController__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./WebXR/WebXRController */ "./src/WebXR/WebXRController.ts"); /* harmony import */ var _Config_Config__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Config/Config */ "./src/Config/Config.ts"); /* harmony import */ var _Config_SettingBase__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Config/SettingBase */ "./src/Config/SettingBase.ts"); /* harmony import */ var _Config_SettingFlag__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./Config/SettingFlag */ "./src/Config/SettingFlag.ts"); /* harmony import */ var _Config_SettingNumber__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./Config/SettingNumber */ "./src/Config/SettingNumber.ts"); /* harmony import */ var _Config_SettingOption__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./Config/SettingOption */ "./src/Config/SettingOption.ts"); /* harmony import */ var _Config_SettingText__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./Config/SettingText */ "./src/Config/SettingText.ts"); /* harmony import */ var _PixelStreaming_PixelStreaming__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./PixelStreaming/PixelStreaming */ "./src/PixelStreaming/PixelStreaming.ts"); /* harmony import */ var _AFK_AFKController__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./AFK/AFKController */ "./src/AFK/AFKController.ts"); /* harmony import */ var _DataChannel_LatencyTestResults__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./DataChannel/LatencyTestResults */ "./src/DataChannel/LatencyTestResults.ts"); /* harmony import */ var _DataChannel_InitialSettings__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./DataChannel/InitialSettings */ "./src/DataChannel/InitialSettings.ts"); /* harmony import */ var _PeerConnectionController_AggregatedStats__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./PeerConnectionController/AggregatedStats */ "./src/PeerConnectionController/AggregatedStats.ts"); /* harmony import */ var _Logger_Logger__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./Logger/Logger */ "./src/Logger/Logger.ts"); /* harmony import */ var _Util_CoordinateConverter__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./Util/CoordinateConverter */ "./src/Util/CoordinateConverter.ts"); /* harmony import */ var _UeInstanceMessage_StreamMessageController__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./UeInstanceMessage/StreamMessageController */ "./src/UeInstanceMessage/StreamMessageController.ts"); /* harmony import */ var _WebSockets_MessageSend__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./WebSockets/MessageSend */ "./src/WebSockets/MessageSend.ts"); /* harmony import */ var _WebSockets_MessageReceive__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./WebSockets/MessageReceive */ "./src/WebSockets/MessageReceive.ts"); /* harmony import */ var _WebSockets_WebSocketController__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./WebSockets/WebSocketController */ "./src/WebSockets/WebSocketController.ts"); /* harmony import */ var _WebSockets_SignallingProtocol__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./WebSockets/SignallingProtocol */ "./src/WebSockets/SignallingProtocol.ts"); /* harmony import */ var _PeerConnectionController_CandidatePairStats__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./PeerConnectionController/CandidatePairStats */ "./src/PeerConnectionController/CandidatePairStats.ts"); /* harmony import */ var _PeerConnectionController_CandidateStat__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ./PeerConnectionController/CandidateStat */ "./src/PeerConnectionController/CandidateStat.ts"); /* harmony import */ var _PeerConnectionController_DataChannelStats__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ./PeerConnectionController/DataChannelStats */ "./src/PeerConnectionController/DataChannelStats.ts"); /* harmony import */ var _PeerConnectionController_InboundRTPStats__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ./PeerConnectionController/InboundRTPStats */ "./src/PeerConnectionController/InboundRTPStats.ts"); /* harmony import */ var _PeerConnectionController_OutBoundRTPStats__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! ./PeerConnectionController/OutBoundRTPStats */ "./src/PeerConnectionController/OutBoundRTPStats.ts"); /* harmony import */ var _Util_EventEmitter__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! ./Util/EventEmitter */ "./src/Util/EventEmitter.ts"); // Copyright Epic Games, Inc. All Rights Reserved. })(); /******/ return __webpack_exports__; /******/ })() ; }); //# sourceMappingURL=data:application/json;charset=utf-8;base64,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QUssVUFBVSxDQUFDO1lBQzlFLFdBQVcsQ0FBQyxRQUFRO1lBQ3BCLFdBQVcsQ0FBQyxRQUFRLENBQUMsS0FBSztZQUMxQixXQUFXLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssT0FBTyxDQUFDO0lBQ3BELENBQUM7SUFFRCxNQUFNLENBQUMsdUJBQXVCLENBQUMsV0FBMkM7UUFDdEUsT0FBTyxDQUFDLENBQUMsV0FBVztZQUNoQixDQUFDLFdBQVcsQ0FBQyxTQUFTLEtBQUssVUFBVSxJQUFJLFdBQVcsQ0FBQyxTQUFTLEtBQUssVUFBVSxDQUFDO1lBQzlFLFdBQVcsQ0FBQyxNQUFNO1lBQ2xCLFdBQVcsQ0FBQyxNQUFNLENBQUMsS0FBSztZQUN4QixXQUFXLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssT0FBTyxDQUFDO0lBQ2xELENBQUM7SUFFRCxNQUFNLENBQUMsa0JBQWtCLENBQUMsV0FBMkM7UUFDakUsT0FBTyxJQUFJLENBQUMsMEJBQTBCLENBQUMsV0FBVyxDQUFDLElBQUksSUFBSSxDQUFDLHVCQUF1QixDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ3JHLENBQUM7SUFFRCxNQUFNLENBQUMsMEJBQTBCLENBQUMsV0FBMkM7UUFDekUsT0FBTyxDQUFDLENBQUMsV0FBVztZQUNoQixDQUFDLFdBQVcsQ0FBQyxTQUFTLEtBQUssVUFBVSxJQUFJLFdBQVcsQ0FBQyxTQUFTLEtBQUssVUFBVSxDQUFDO1lBQzlFLFdBQVcsQ0FBQyxRQUFRO1lBQ3BCLFdBQVcsQ0FBQyxRQUFRLENBQUMsS0FBSztZQUMxQixXQUFXLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssT0FBTyxDQUFDO0lBQ3BELENBQUM7SUFFRCxNQUFNLENBQUMsdUJBQXVCLENBQUMsV0FBMkM7UUFDdEUsT0FBTyxDQUFDLENBQUMsV0FBVztZQUNoQixDQUFDLFdBQVcsQ0FBQyxTQUFTLEtBQUssVUFBVSxJQUFJLFdBQVcsQ0FBQyxTQUFTLEtBQUssVUFBVSxDQUFDO1lBQzlFLFdBQVcs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T0FBTyxLQUFLLENBQUM7WUFDakIsQ0FBQyxDQUFDLENBQUM7U0FDTjtJQUNMLENBQUM7Q0FDSjs7Ozs7Ozs7Ozs7QUM5VEQ7Ozs7OztVQ0FBO1VBQ0E7O1VBRUE7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7VUFDQTtVQUNBO1VBQ0E7O1VBRUE7VUFDQTs7VUFFQTtVQUNBO1VBQ0E7Ozs7O1dDdEJBO1dBQ0E7V0FDQTtXQUNBO1dBQ0E7V0FDQSxpQ0FBaUMsV0FBVztXQUM1QztXQUNBOzs7OztXQ1BBO1dBQ0E7V0FDQTtXQUNBO1dBQ0EseUNBQXlDLHdDQUF3QztXQUNqRjtXQUNBO1dBQ0E7Ozs7O1dDUEE7Ozs7O1dDQUE7V0FDQTtXQUNBO1dBQ0EsdURBQXVELGlCQUFpQjtXQUN4RTtXQUNBLGdEQUFnRCxhQUFhO1dBQzdEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FDTkEsa0RBQWtEO0FBRTZCO0FBQ3JCO0FBYWpDO0FBQzBCO0FBQ0E7QUFDSTtBQUNBO0FBQ0o7QUFDYztBQUVEO0FBRU07QUFLL0I7QUFDc0M7QUFDcEM7QUFDOEU7QUFDeEM7QUFDeEI7QUFDd0I7QUFDUjtBQUNGO0FBRWM7QUFDVjtBQUNNO0FBSTNCO0FBQzZCO0FBQzdDIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vbGliLXBpeGVsc3RyZWFtaW5nZnJvbnRlbmQvd2VicGFjay91bml2ZXJzYWxNb2R1bGVEZWZpbml0aW9uIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL0FGSy9BRktDb250cm9sbGVyLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL0NvbmZpZy9Db25maWcudHMiLCJ3ZWJwYWNrOi8vbGliLXBpeGVsc3RyZWFtaW5nZnJvbnRlbmQvLi9zcmMvQ29uZmlnL1NldHRpbmdCYXNlLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL0NvbmZpZy9TZXR0aW5nRmxhZy50cyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC8uL3NyYy9Db25maWcvU2V0dGluZ051bWJlci50cyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC8uL3NyYy9Db25maWcvU2V0dGluZ09wdGlvbi50cyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC8uL3NyYy9Db25maWcvU2V0dGluZ1RleHQudHMiLCJ3ZWJwYWNrOi8vbGliLXBpeGVsc3RyZWFtaW5nZnJvbnRlbmQvLi9zcmMvRGF0YUNoYW5uZWwvRGF0YUNoYW5uZWxDb250cm9sbGVyLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL0RhdGFDaGFubmVsL0RhdGFDaGFubmVsTGF0ZW5jeVRlc3RDb250cm9sbGVyLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL0RhdGFDaGFubmVsL0RhdGFDaGFubmVsTGF0ZW5jeVRlc3RSZXN1bHRzLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL0RhdGFDaGFubmVsL0RhdGFDaGFubmVsU2VuZGVyLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL0RhdGFDaGFubmVsL0luaXRpYWxTZXR0aW5ncy50cyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC8uL3NyYy9EYXRhQ2hhbm5lbC9MYXRlbmN5VGVzdFJlc3VsdHMudHMiLCJ3ZWJwYWNrOi8vbGliLXBpeGVsc3RyZWFtaW5nZnJvbnRlbmQvLi9zcmMvRnJlZXplRnJhbWUvRnJlZXplRnJhbWUudHMiLCJ3ZWJwYWNrOi8vbGliLXBpeGVsc3RyZWFtaW5nZnJvbnRlbmQvLi9zcmMvRnJlZXplRnJhbWUvRnJlZXplRnJhbWVDb250cm9sbGVyLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL0lucHV0cy9GYWtlVG91Y2hDb250cm9sbGVyLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL0lucHV0cy9HYW1lcGFkQ29udHJvbGxlci50cyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC8uL3NyYy9JbnB1dHMvSG92ZXJpbmdNb3VzZUV2ZW50cy50cyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC8uL3NyYy9JbnB1dHMvSW5wdXRDbGFzc2VzRmFjdG9yeS50cyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC8uL3NyYy9JbnB1dHMvS2V5Ym9hcmRDb250cm9sbGVyLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL0lucHV0cy9Mb2NrZWRNb3VzZUV2ZW50cy50cyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC8uL3NyYy9JbnB1dHMvTW91c2VCdXR0b25zLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL0lucHV0cy9Nb3VzZUNvbnRyb2xsZXIudHMiLCJ3ZWJwYWNrOi8vbGliLXBpeGVsc3RyZWFtaW5nZnJvbnRlbmQvLi9zcmMvSW5wdXRzL1NwZWNpYWxLZXlDb2Rlcy50cyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC8uL3NyYy9JbnB1dHMvVG91Y2hDb250cm9sbGVyLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL0lucHV0cy9YUkdhbWVwYWRDb250cm9sbGVyLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL0xvZ2dlci9Mb2dnZXIudHMiLCJ3ZWJwYWNrOi8vbGliLXBpeGVsc3RyZWFtaW5nZnJvbnRlbmQvLi9zcmMvUGVlckNvbm5lY3Rpb25Db250cm9sbGVyL0FnZ3JlZ2F0ZWRTdGF0cy50cyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC8uL3NyYy9QZWVyQ29ubmVjdGlvbkNvbnRyb2xsZXIvQ2FuZGlkYXRlUGFpclN0YXRzLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL1BlZXJDb25uZWN0aW9uQ29udHJvbGxlci9DYW5kaWRhdGVTdGF0LnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL1BlZXJDb25uZWN0aW9uQ29udHJvbGxlci9EYXRhQ2hhbm5lbFN0YXRzLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL1BlZXJDb25uZWN0aW9uQ29udHJvbGxlci9JbmJvdW5kUlRQU3RhdHMudHMiLCJ3ZWJwYWNrOi8vbGliLXBpeGVsc3RyZWFtaW5nZnJvbnRlbmQvLi9zcmMvUGVlckNvbm5lY3Rpb25Db250cm9sbGVyL091dEJvdW5kUlRQU3RhdHMudHMiLCJ3ZWJwYWNrOi8vbGliLXBpeGVsc3RyZWFtaW5nZnJvbnRlbmQvLi9zcmMvUGVlckNvbm5lY3Rpb25Db250cm9sbGVyL1BlZXJDb25uZWN0aW9uQ29udHJvbGxlci50cyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC8uL3NyYy9QZWVyQ29ubmVjdGlvbkNvbnRyb2xsZXIvU2Vzc2lvblN0YXRzLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL1BlZXJDb25uZWN0aW9uQ29udHJvbGxlci9TdHJlYW1TdGF0cy50cyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC8uL3NyYy9QaXhlbFN0cmVhbWluZy9QaXhlbFN0cmVhbWluZy50cyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC8uL3NyYy9VSS9PblNjcmVlbktleWJvYXJkLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL1VlSW5zdGFuY2VNZXNzYWdlL1Jlc3BvbnNlQ29udHJvbGxlci50cyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC8uL3NyYy9VZUluc3RhbmNlTWVzc2FnZS9TZW5kTWVzc2FnZUNvbnRyb2xsZXIudHMiLCJ3ZWJwYWNrOi8vbGliLXBpeGVsc3RyZWFtaW5nZnJvbnRlbmQvLi9zcmMvVWVJbnN0YW5jZU1lc3NhZ2UvU3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIudHMiLCJ3ZWJwYWNrOi8vbGliLXBpeGVsc3RyZWFtaW5nZnJvbnRlbmQvLi9zcmMvVWVJbnN0YW5jZU1lc3NhZ2UvVG9TdHJlYW1lck1lc3NhZ2VzQ29udHJvbGxlci50cyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC8uL3NyYy9VdGlsL0Nvb3JkaW5hdGVDb252ZXJ0ZXIudHMiLCJ3ZWJwYWNrOi8vbGliLXBpeGVsc3RyZWFtaW5nZnJvbnRlbmQvLi9zcmMvVXRpbC9FdmVudEVtaXR0ZXIudHMiLCJ3ZWJwYWNrOi8vbGliLXBpeGVsc3RyZWFtaW5nZnJvbnRlbmQvLi9zcmMvVXRpbC9FdmVudExpc3RlbmVyVHJhY2tlci50cyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC8uL3NyYy9VdGlsL0ZpbGVVdGlsLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL1V0aWwvUlRDVXRpbHMudHMiLCJ3ZWJwYWNrOi8vbGliLXBpeGVsc3RyZWFtaW5nZnJvbnRlbmQvLi9zcmMvVXRpbC9XZWJHTFV0aWxzLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL1V0aWwvV2ViWFJVdGlscy50cyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC8uL3NyYy9WaWRlb1BsYXllci9TdHJlYW1Db250cm9sbGVyLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL1ZpZGVvUGxheWVyL1ZpZGVvUGxheWVyLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL1dlYlJ0Y1BsYXllci9XZWJSdGNQbGF5ZXJDb250cm9sbGVyLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kLy4vc3JjL1dlYlNvY2tldHMvTWVzc2FnZVJlY2VpdmUudHMiLCJ3ZWJwYWNrOi8vbGliLXBpeGVsc3RyZWFtaW5nZnJvbnRlbmQvLi9zcmMvV2ViU29ja2V0cy9NZXNzYWdlU2VuZC50cyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC8uL3NyYy9XZWJTb2NrZXRzL1NpZ25hbGxpbmdQcm90b2NvbC50cyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC8uL3NyYy9XZWJTb2NrZXRzL1dlYlNvY2tldENvbnRyb2xsZXIudHMiLCJ3ZWJwYWNrOi8vbGliLXBpeGVsc3RyZWFtaW5nZnJvbnRlbmQvLi9zcmMvV2ViWFIvV2ViWFJDb250cm9sbGVyLnRzIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kL2V4dGVybmFsIHVtZCBcInNkcFwiIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kL3dlYnBhY2svYm9vdHN0cmFwIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kL3dlYnBhY2svcnVudGltZS9jb21wYXQgZ2V0IGRlZmF1bHQgZXhwb3J0Iiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kL3dlYnBhY2svcnVudGltZS9kZWZpbmUgcHJvcGVydHkgZ2V0dGVycyIsIndlYnBhY2s6Ly9saWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC93ZWJwYWNrL3J1bnRpbWUvaGFzT3duUHJvcGVydHkgc2hvcnRoYW5kIiwid2VicGFjazovL2xpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kL3dlYnBhY2svcnVudGltZS9tYWtlIG5hbWVzcGFjZSBvYmplY3QiLCJ3ZWJwYWNrOi8vbGliLXBpeGVsc3RyZWFtaW5nZnJvbnRlbmQvLi9zcmMvcGl4ZWxzdHJlYW1pbmdmcm9udGVuZC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gd2VicGFja1VuaXZlcnNhbE1vZHVsZURlZmluaXRpb24ocm9vdCwgZmFjdG9yeSkge1xuXHRpZih0eXBlb2YgZXhwb3J0cyA9PT0gJ29iamVjdCcgJiYgdHlwZW9mIG1vZHVsZSA9PT0gJ29iamVjdCcpXG5cdFx0bW9kdWxlLmV4cG9ydHMgPSBmYWN0b3J5KHJlcXVpcmUoXCJzZHBcIikpO1xuXHRlbHNlIGlmKHR5cGVvZiBkZWZpbmUgPT09ICdmdW5jdGlvbicgJiYgZGVmaW5lLmFtZClcblx0XHRkZWZpbmUoW1wic2RwXCJdLCBmYWN0b3J5KTtcblx0ZWxzZSBpZih0eXBlb2YgZXhwb3J0cyA9PT0gJ29iamVjdCcpXG5cdFx0ZXhwb3J0c1tcImxpYi1waXhlbHN0cmVhbWluZ2Zyb250ZW5kXCJdID0gZmFjdG9yeShyZXF1aXJlKFwic2RwXCIpKTtcblx0ZWxzZVxuXHRcdHJvb3RbXCJsaWItcGl4ZWxzdHJlYW1pbmdmcm9udGVuZFwiXSA9IGZhY3Rvcnkocm9vdFtcInNkcFwiXSk7XG59KSh0aGlzLCAoX19XRUJQQUNLX0VYVEVSTkFMX01PRFVMRV9zZHBfXykgPT4ge1xucmV0dXJuICIsIi8vIENvcHlyaWdodCBFcGljIEdhbWVzLCBJbmMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG5cbmltcG9ydCB7IENvbmZpZywgRmxhZ3MsIE51bWVyaWNQYXJhbWV0ZXJzIH0gZnJvbSAnLi4vQ29uZmlnL0NvbmZpZyc7XG5pbXBvcnQgeyBMb2dnZXIgfSBmcm9tICcuLi9Mb2dnZXIvTG9nZ2VyJztcbmltcG9ydCB7IFBpeGVsU3RyZWFtaW5nIH0gZnJvbSAnLi4vUGl4ZWxTdHJlYW1pbmcvUGl4ZWxTdHJlYW1pbmcnO1xuaW1wb3J0IHtcbiAgICBBZmtUaW1lZE91dEV2ZW50LFxuICAgIEFma1dhcm5pbmdBY3RpdmF0ZUV2ZW50LFxuICAgIEFma1dhcm5pbmdEZWFjdGl2YXRlRXZlbnQsXG4gICAgQWZrV2FybmluZ1VwZGF0ZUV2ZW50XG59IGZyb20gJy4uL1V0aWwvRXZlbnRFbWl0dGVyJztcblxuZXhwb3J0IGNsYXNzIEFGS0NvbnRyb2xsZXIge1xuICAgIC8vIHRpbWUgb3V0IGxvZ2ljIGRldGFpbHNcbiAgICBjbG9zZVRpbWVvdXQgPSAxMDtcbiAgICBhY3RpdmUgPSBmYWxzZTtcbiAgICBjb3VudGRvd25BY3RpdmUgPSBmYWxzZTtcbiAgICB3YXJuVGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+ID0gdW5kZWZpbmVkO1xuICAgIGNvdW50RG93biA9IDA7XG4gICAgY291bnREb3duVGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldEludGVydmFsPiA9IHVuZGVmaW5lZDtcbiAgICBjb25maWc6IENvbmZpZztcbiAgICBwaXhlbFN0cmVhbWluZzogUGl4ZWxTdHJlYW1pbmc7XG4gICAgb25EaXNtaXNzQWZrOiAoKSA9PiB2b2lkO1xuXG4gICAgb25BRktUaW1lZE91dENhbGxiYWNrOiAoKSA9PiB2b2lkO1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIGNvbmZpZzogQ29uZmlnLFxuICAgICAgICBwaXhlbFN0cmVhbWluZzogUGl4ZWxTdHJlYW1pbmcsXG4gICAgICAgIG9uRGlzbWlzc0FmazogKCkgPT4gdm9pZFxuICAgICkge1xuICAgICAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcbiAgICAgICAgdGhpcy5waXhlbFN0cmVhbWluZyA9IHBpeGVsU3RyZWFtaW5nO1xuICAgICAgICB0aGlzLm9uRGlzbWlzc0FmayA9IG9uRGlzbWlzc0FmaztcbiAgICAgICAgdGhpcy5vbkFGS1RpbWVkT3V0Q2FsbGJhY2sgPSAoKSA9PiB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICAgICAgICAnQUZLIHRpbWVkIG91dCwgZGlkIHlvdSB3YW50IHRvIG92ZXJyaWRlIHRoaXMgY2FsbGJhY2s/J1xuICAgICAgICAgICAgKTtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgbWV0aG9kcyB0aGF0IG9jY3VyIHdoZW4gYW4gYWZrIGV2ZW50IGxpc3RlbmVyIGlzIGNsaWNrZWRcbiAgICAgKi9cbiAgICBvbkFma0NsaWNrKCkge1xuICAgICAgICBjbGVhckludGVydmFsKHRoaXMuY291bnREb3duVGltZXIpO1xuXG4gICAgICAgIGlmICh0aGlzLmFjdGl2ZSB8fCB0aGlzLmNvdW50ZG93bkFjdGl2ZSkge1xuICAgICAgICAgICAgdGhpcy5zdGFydEFma1dhcm5pbmdUaW1lcigpO1xuICAgICAgICAgICAgdGhpcy5waXhlbFN0cmVhbWluZy5kaXNwYXRjaEV2ZW50KFxuICAgICAgICAgICAgICAgIG5ldyBBZmtXYXJuaW5nRGVhY3RpdmF0ZUV2ZW50KClcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTdGFydCB0aGUgd2FybmluZyB0aW1lciBpZiBhIHRpbWVvdXQgaXMgc2V0IGdyZWF0ZXIgdGhhdCAwIHNlY29uZHNcbiAgICAgKi9cbiAgICBzdGFydEFma1dhcm5pbmdUaW1lcigpIHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgdGhpcy5jb25maWcuZ2V0TnVtZXJpY1NldHRpbmdWYWx1ZShcbiAgICAgICAgICAgICAgICBOdW1lcmljUGFyYW1ldGVycy5BRktUaW1lb3V0U2Vjc1xuICAgICAgICAgICAgKSA+IDAgJiZcbiAgICAgICAgICAgIHRoaXMuY29uZmlnLmlzRmxhZ0VuYWJsZWQoRmxhZ3MuQUZLRGV0ZWN0aW9uKVxuICAgICAgICApIHtcbiAgICAgICAgICAgIHRoaXMuYWN0aXZlID0gdHJ1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuYWN0aXZlID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5yZXNldEFma1dhcm5pbmdUaW1lcigpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFN0b3AgdGhlIGFmayB3YXJuaW5nIHRpbWVyXG4gICAgICovXG4gICAgc3RvcEFma1dhcm5pbmdUaW1lcigpIHtcbiAgICAgICAgdGhpcy5hY3RpdmUgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5jb3VudGRvd25BY3RpdmUgPSBmYWxzZTtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRoaXMud2FyblRpbWVyKTtcbiAgICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLmNvdW50RG93blRpbWVyKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQYXVzZSB0aGUgdGltZXIgd2hpY2ggd2hlbiBlbGFwc2VkIHdpbGwgd2FybiB0aGUgdXNlciB0aGV5IGFyZSBpbmFjdGl2ZS5cbiAgICAgKi9cbiAgICBwYXVzZUFma1dhcm5pbmdUaW1lcigpIHtcbiAgICAgICAgdGhpcy5hY3RpdmUgPSBmYWxzZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBJZiB0aGUgdXNlciBpbnRlcmFjdHMgdGhlbiByZXNldCB0aGUgd2FybmluZyB0aW1lci5cbiAgICAgKi9cbiAgICByZXNldEFma1dhcm5pbmdUaW1lcigpIHtcbiAgICAgICAgaWYgKHRoaXMuYWN0aXZlICYmIHRoaXMuY29uZmlnLmlzRmxhZ0VuYWJsZWQoRmxhZ3MuQUZLRGV0ZWN0aW9uKSkge1xuICAgICAgICAgICAgY2xlYXJUaW1lb3V0KHRoaXMud2FyblRpbWVyKTtcbiAgICAgICAgICAgIHRoaXMud2FyblRpbWVyID0gc2V0VGltZW91dChcbiAgICAgICAgICAgICAgICAoKSA9PiB0aGlzLmFjdGl2YXRlQWZrRXZlbnQoKSxcbiAgICAgICAgICAgICAgICB0aGlzLmNvbmZpZy5nZXROdW1lcmljU2V0dGluZ1ZhbHVlKFxuICAgICAgICAgICAgICAgICAgICBOdW1lcmljUGFyYW1ldGVycy5BRktUaW1lb3V0U2Vjc1xuICAgICAgICAgICAgICAgICkgKiAxMDAwXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2hvdyB0aGUgQUZLIG92ZXJsYXkgYW5kIGJlZ2luIHRoZSBjb3VudERvd25cbiAgICAgKi9cbiAgICBhY3RpdmF0ZUFma0V2ZW50KCkge1xuICAgICAgICAvLyBQYXVzZSB0aGUgdGltZXIgd2hpbGUgdGhlIHVzZXIgaXMgbG9va2luZyBhdCB0aGUgaW5hY3Rpdml0eSB3YXJuaW5nIG92ZXJsYXlcbiAgICAgICAgdGhpcy5wYXVzZUFma1dhcm5pbmdUaW1lcigpO1xuXG4gICAgICAgIC8vIGluc3RhbnRpYXRlIGEgbmV3IG92ZXJsYXlcbiAgICAgICAgdGhpcy5waXhlbFN0cmVhbWluZy5kaXNwYXRjaEV2ZW50KFxuICAgICAgICAgICAgbmV3IEFma1dhcm5pbmdBY3RpdmF0ZUV2ZW50KHtcbiAgICAgICAgICAgICAgICBjb3VudERvd246IHRoaXMuY291bnREb3duLFxuICAgICAgICAgICAgICAgIGRpc21pc3NBZms6IHRoaXMub25EaXNtaXNzQWZrXG4gICAgICAgICAgICB9KVxuICAgICAgICApO1xuXG4gICAgICAgIC8vIHVwZGF0ZSBvdXIgY291bnREb3duIHRpbWVyIGFuZCBvdmVybGF5IGNvbnRlbnRzXG4gICAgICAgIHRoaXMuY291bnREb3duID0gdGhpcy5jbG9zZVRpbWVvdXQ7XG4gICAgICAgIHRoaXMuY291bnRkb3duQWN0aXZlID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5waXhlbFN0cmVhbWluZy5kaXNwYXRjaEV2ZW50KFxuICAgICAgICAgICAgbmV3IEFma1dhcm5pbmdVcGRhdGVFdmVudCh7IGNvdW50RG93bjogdGhpcy5jb3VudERvd24gfSlcbiAgICAgICAgKTtcblxuICAgICAgICAvLyBpZiB3ZSBhcmUgaW4gbG9ja2VkIG1vdXNlIGV4aXQgcG9pbnRlcmxvY2tcbiAgICAgICAgaWYgKCF0aGlzLmNvbmZpZy5pc0ZsYWdFbmFibGVkKEZsYWdzLkhvdmVyaW5nTW91c2VNb2RlKSkge1xuICAgICAgICAgICAgLy8gbWlub3IgaGFjayB0byBhbGxldmlhdGUgaW9zIG5vdCBzdXBwb3J0aW5nIHBvaW50ZXJsb2NrXG4gICAgICAgICAgICBpZiAoZG9jdW1lbnQuZXhpdFBvaW50ZXJMb2NrKSB7XG4gICAgICAgICAgICAgICAgZG9jdW1lbnQuZXhpdFBvaW50ZXJMb2NrKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyByZXNldCBvdXIgY291bnREb3duIGludGVydmFsIGFjY29yZGluZ2x5XG4gICAgICAgIHRoaXMuY291bnREb3duVGltZXIgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmNvdW50RG93bi0tO1xuICAgICAgICAgICAgaWYgKHRoaXMuY291bnREb3duID09IDApIHtcbiAgICAgICAgICAgICAgICAvLyBUaGUgdXNlciBmYWlsZWQgdG8gY2xpY2sgc28gaGlkZSB0aGUgb3ZlcmxheSBhbmQgZGlzY29ubmVjdCB0aGVtLlxuICAgICAgICAgICAgICAgIHRoaXMucGl4ZWxTdHJlYW1pbmcuZGlzcGF0Y2hFdmVudChcbiAgICAgICAgICAgICAgICAgICAgbmV3IEFma1RpbWVkT3V0RXZlbnQoKVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgdGhpcy5vbkFGS1RpbWVkT3V0Q2FsbGJhY2soKTtcbiAgICAgICAgICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgICAgICAnWW91IGhhdmUgYmVlbiBkaXNjb25uZWN0ZWQgZHVlIHRvIGluYWN0aXZpdHknXG4gICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgIC8vIHN3aXRjaCBvZmYgdGhlIGFmayBmZWF0dXJlIGFzIHN0cmVhbSBoYXMgY2xvc2VkXG4gICAgICAgICAgICAgICAgdGhpcy5zdG9wQWZrV2FybmluZ1RpbWVyKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMucGl4ZWxTdHJlYW1pbmcuZGlzcGF0Y2hFdmVudChcbiAgICAgICAgICAgICAgICAgICAgbmV3IEFma1dhcm5pbmdVcGRhdGVFdmVudCh7IGNvdW50RG93bjogdGhpcy5jb3VudERvd24gfSlcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LCAxMDAwKTtcbiAgICB9XG59XG4iLCIvLyBDb3B5cmlnaHQgRXBpYyBHYW1lcywgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuXG5pbXBvcnQgeyBMb2dnZXIgfSBmcm9tICcuLi9Mb2dnZXIvTG9nZ2VyJztcbmltcG9ydCB7IFNldHRpbmdGbGFnIH0gZnJvbSAnLi9TZXR0aW5nRmxhZyc7XG5pbXBvcnQgeyBTZXR0aW5nTnVtYmVyIH0gZnJvbSAnLi9TZXR0aW5nTnVtYmVyJztcbmltcG9ydCB7IFNldHRpbmdUZXh0IH0gZnJvbSAnLi9TZXR0aW5nVGV4dCc7XG5pbXBvcnQgeyBTZXR0aW5nT3B0aW9uIH0gZnJvbSAnLi9TZXR0aW5nT3B0aW9uJztcbmltcG9ydCB7IEV2ZW50RW1pdHRlciwgU2V0dGluZ3NDaGFuZ2VkRXZlbnQgfSBmcm9tICcuLi9VdGlsL0V2ZW50RW1pdHRlcic7XG5pbXBvcnQgeyBTZXR0aW5nQmFzZSB9IGZyb20gJy4vU2V0dGluZ0Jhc2UnO1xuXG4vKipcbiAqIEEgY29sbGVjdGlvbiBvZiBmbGFncyB0aGF0IGNhbiBiZSB0b2dnbGVkIGFuZCBhcmUgY29yZSB0byBhbGwgUGl4ZWwgU3RyZWFtaW5nIGV4cGVyaWVuY2VzLlxuICogVGhlc2UgYXJlIHVzZWQgaW4gdGhlIGBDb25maWcuRmxhZ3NgIG1hcC5cbiAqL1xuZXhwb3J0IGNsYXNzIEZsYWdzIHtcbiAgICBzdGF0aWMgQXV0b0Nvbm5lY3QgPSAnQXV0b0Nvbm5lY3QnIGFzIGNvbnN0O1xuICAgIHN0YXRpYyBBdXRvUGxheVZpZGVvID0gJ0F1dG9QbGF5VmlkZW8nIGFzIGNvbnN0O1xuICAgIHN0YXRpYyBBRktEZXRlY3Rpb24gPSAnVGltZW91dElmSWRsZScgYXMgY29uc3Q7XG4gICAgc3RhdGljIEJyb3dzZXJTZW5kT2ZmZXIgPSAnT2ZmZXJUb1JlY2VpdmUnIGFzIGNvbnN0O1xuICAgIHN0YXRpYyBIb3ZlcmluZ01vdXNlTW9kZSA9ICdIb3ZlcmluZ01vdXNlJyBhcyBjb25zdDtcbiAgICBzdGF0aWMgRm9yY2VNb25vQXVkaW8gPSAnRm9yY2VNb25vQXVkaW8nIGFzIGNvbnN0O1xuICAgIHN0YXRpYyBGb3JjZVRVUk4gPSAnRm9yY2VUVVJOJyBhcyBjb25zdDtcbiAgICBzdGF0aWMgRmFrZU1vdXNlV2l0aFRvdWNoZXMgPSAnRmFrZU1vdXNlV2l0aFRvdWNoZXMnIGFzIGNvbnN0O1xuICAgIHN0YXRpYyBJc1F1YWxpdHlDb250cm9sbGVyID0gJ0NvbnRyb2xzUXVhbGl0eScgYXMgY29uc3Q7XG4gICAgc3RhdGljIE1hdGNoVmlld3BvcnRSZXNvbHV0aW9uID0gJ01hdGNoVmlld3BvcnRSZXMnIGFzIGNvbnN0O1xuICAgIHN0YXRpYyBTdGFydFZpZGVvTXV0ZWQgPSAnU3RhcnRWaWRlb011dGVkJyBhcyBjb25zdDtcbiAgICBzdGF0aWMgU3VwcHJlc3NCcm93c2VyS2V5cyA9ICdTdXBwcmVzc0Jyb3dzZXJLZXlzJyBhcyBjb25zdDtcbiAgICBzdGF0aWMgVXNlTWljID0gJ1VzZU1pYycgYXMgY29uc3Q7XG4gICAgc3RhdGljIEtleWJvYXJkSW5wdXQgPSAnS2V5Ym9hcmRJbnB1dCcgYXMgY29uc3Q7XG4gICAgc3RhdGljIE1vdXNlSW5wdXQgPSAnTW91c2VJbnB1dCcgYXMgY29uc3Q7XG4gICAgc3RhdGljIFRvdWNoSW5wdXQgPSAnVG91Y2hJbnB1dCcgYXMgY29uc3Q7XG4gICAgc3RhdGljIEdhbWVwYWRJbnB1dCA9ICdHYW1lcGFkSW5wdXQnIGFzIGNvbnN0O1xuICAgIHN0YXRpYyBYUkNvbnRyb2xsZXJJbnB1dCA9ICdYUkNvbnRyb2xsZXJJbnB1dCcgYXMgY29uc3Q7XG4gICAgc3RhdGljIFdhaXRGb3JTdHJlYW1lciA9IFwiV2FpdEZvclN0cmVhbWVyXCIgYXMgY29uc3Q7XG59XG5cbmV4cG9ydCB0eXBlIEZsYWdzS2V5cyA9IEV4Y2x1ZGU8a2V5b2YgdHlwZW9mIEZsYWdzLCAncHJvdG90eXBlJz47XG5leHBvcnQgdHlwZSBGbGFnc0lkcyA9IHR5cGVvZiBGbGFnc1tGbGFnc0tleXNdO1xuXG5jb25zdCBpc0ZsYWdJZCA9IChpZDogc3RyaW5nKTogaWQgaXMgRmxhZ3NJZHMgPT5cbiAgICBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhGbGFncykuc29tZShcbiAgICAgICAgKG5hbWU6IEZsYWdzS2V5cykgPT4gRmxhZ3NbbmFtZV0gPT09IGlkXG4gICAgKTtcblxuLyoqXG4gKiBBIGNvbGxlY3Rpb24gb2YgbnVtZXJpYyBwYXJhbWV0ZXJzIHRoYXQgYXJlIGNvcmUgdG8gYWxsIFBpeGVsIFN0cmVhbWluZyBleHBlcmllbmNlcy5cbiAqXG4gKi9cbmV4cG9ydCBjbGFzcyBOdW1lcmljUGFyYW1ldGVycyB7XG4gICAgc3RhdGljIEFGS1RpbWVvdXRTZWNzID0gJ0FGS1RpbWVvdXQnIGFzIGNvbnN0O1xuICAgIHN0YXRpYyBNaW5RUCA9ICdNaW5RUCcgYXMgY29uc3Q7XG4gICAgc3RhdGljIE1heFFQID0gJ01heFFQJyBhcyBjb25zdDtcbiAgICBzdGF0aWMgV2ViUlRDRlBTID0gJ1dlYlJUQ0ZQUycgYXMgY29uc3Q7XG4gICAgc3RhdGljIFdlYlJUQ01pbkJpdHJhdGUgPSAnV2ViUlRDTWluQml0cmF0ZScgYXMgY29uc3Q7XG4gICAgc3RhdGljIFdlYlJUQ01heEJpdHJhdGUgPSAnV2ViUlRDTWF4Qml0cmF0ZScgYXMgY29uc3Q7XG4gICAgc3RhdGljIE1heFJlY29ubmVjdEF0dGVtcHRzID0gJ01heFJlY29ubmVjdEF0dGVtcHRzJyBhcyBjb25zdDtcbiAgICBzdGF0aWMgU3RyZWFtZXJBdXRvSm9pbkludGVydmFsID0gJ1N0cmVhbWVyQXV0b0pvaW5JbnRlcnZhbCcgYXMgY29uc3Q7XG59XG5cbmV4cG9ydCB0eXBlIE51bWVyaWNQYXJhbWV0ZXJzS2V5cyA9IEV4Y2x1ZGU8XG4gICAga2V5b2YgdHlwZW9mIE51bWVyaWNQYXJhbWV0ZXJzLFxuICAgICdwcm90b3R5cGUnXG4+O1xuZXhwb3J0IHR5cGUgTnVtZXJpY1BhcmFtZXRlcnNJZHMgPVxuICAgIHR5cGVvZiBOdW1lcmljUGFyYW1ldGVyc1tOdW1lcmljUGFyYW1ldGVyc0tleXNdO1xuXG5jb25zdCBpc051bWVyaWNJZCA9IChpZDogc3RyaW5nKTogaWQgaXMgTnVtZXJpY1BhcmFtZXRlcnNJZHMgPT5cbiAgICBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhOdW1lcmljUGFyYW1ldGVycykuc29tZShcbiAgICAgICAgKG5hbWU6IE51bWVyaWNQYXJhbWV0ZXJzS2V5cykgPT4gTnVtZXJpY1BhcmFtZXRlcnNbbmFtZV0gPT09IGlkXG4gICAgKTtcblxuLyoqXG4gKiBBIGNvbGxlY3Rpb24gb2YgdGV4dHVhbCBwYXJhbWV0ZXJzIHRoYXQgYXJlIGNvcmUgdG8gYWxsIFBpeGVsIFN0cmVhbWluZyBleHBlcmllbmNlcy5cbiAqXG4gKi9cbmV4cG9ydCBjbGFzcyBUZXh0UGFyYW1ldGVycyB7XG4gICAgc3RhdGljIFNpZ25hbGxpbmdTZXJ2ZXJVcmwgPSAnc3MnIGFzIGNvbnN0O1xufVxuXG5leHBvcnQgdHlwZSBUZXh0UGFyYW1ldGVyc0tleXMgPSBFeGNsdWRlPFxuICAgIGtleW9mIHR5cGVvZiBUZXh0UGFyYW1ldGVycyxcbiAgICAncHJvdG90eXBlJ1xuPjtcbmV4cG9ydCB0eXBlIFRleHRQYXJhbWV0ZXJzSWRzID0gdHlwZW9mIFRleHRQYXJhbWV0ZXJzW1RleHRQYXJhbWV0ZXJzS2V5c107XG5cbmNvbnN0IGlzVGV4dElkID0gKGlkOiBzdHJpbmcpOiBpZCBpcyBUZXh0UGFyYW1ldGVyc0lkcyA9PlxuICAgIE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKFRleHRQYXJhbWV0ZXJzKS5zb21lKFxuICAgICAgICAobmFtZTogVGV4dFBhcmFtZXRlcnNLZXlzKSA9PiBUZXh0UGFyYW1ldGVyc1tuYW1lXSA9PT0gaWRcbiAgICApO1xuXG4vKipcbiAqIEEgY29sbGVjdGlvbiBvZiBlbnVtIGJhc2VkIHBhcmFtZXRlcnMgdGhhdCBhcmUgY29yZSB0byBhbGwgUGl4ZWwgU3RyZWFtaW5nIGV4cGVyaWVuY2VzLlxuICpcbiAqL1xuZXhwb3J0IGNsYXNzIE9wdGlvblBhcmFtZXRlcnMge1xuICAgIHN0YXRpYyBQcmVmZXJyZWRDb2RlYyA9ICdQcmVmZXJyZWRDb2RlYycgYXMgY29uc3Q7XG4gICAgc3RhdGljIFN0cmVhbWVySWQgPSAnU3RyZWFtZXJJZCcgYXMgY29uc3Q7XG59XG5cbmV4cG9ydCB0eXBlIE9wdGlvblBhcmFtZXRlcnNLZXlzID0gRXhjbHVkZTxcbiAgICBrZXlvZiB0eXBlb2YgT3B0aW9uUGFyYW1ldGVycyxcbiAgICAncHJvdG90eXBlJ1xuPjtcbmV4cG9ydCB0eXBlIE9wdGlvblBhcmFtZXRlcnNJZHMgPSB0eXBlb2YgT3B0aW9uUGFyYW1ldGVyc1tPcHRpb25QYXJhbWV0ZXJzS2V5c107XG5cbmNvbnN0IGlzT3B0aW9uSWQgPSAoaWQ6IHN0cmluZyk6IGlkIGlzIE9wdGlvblBhcmFtZXRlcnNJZHMgPT5cbiAgICBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhPcHRpb25QYXJhbWV0ZXJzKS5zb21lKFxuICAgICAgICAobmFtZTogT3B0aW9uUGFyYW1ldGVyc0tleXMpID0+IE9wdGlvblBhcmFtZXRlcnNbbmFtZV0gPT09IGlkXG4gICAgKTtcblxuLyoqXG4gKiBVdGlsaXR5IHR5cGVzIGZvciBpbmZlcnJpbmcgZGF0YSB0eXBlIGJhc2VkIG9uIHNldHRpbmcgSURcbiAqL1xuZXhwb3J0IHR5cGUgT3B0aW9uSWRzID1cbiAgICB8IEZsYWdzSWRzXG4gICAgfCBOdW1lcmljUGFyYW1ldGVyc0lkc1xuICAgIHwgVGV4dFBhcmFtZXRlcnNJZHNcbiAgICB8IE9wdGlvblBhcmFtZXRlcnNJZHM7XG5leHBvcnQgdHlwZSBPcHRpb25LZXlzPFQ+ID0gVCBleHRlbmRzIEZsYWdzSWRzXG4gICAgPyBib29sZWFuXG4gICAgOiBUIGV4dGVuZHMgTnVtZXJpY1BhcmFtZXRlcnNJZHNcbiAgICA/IG51bWJlclxuICAgIDogVCBleHRlbmRzIFRleHRQYXJhbWV0ZXJzSWRzXG4gICAgPyBzdHJpbmdcbiAgICA6IFQgZXh0ZW5kcyBPcHRpb25QYXJhbWV0ZXJzSWRzXG4gICAgPyBzdHJpbmdcbiAgICA6IG5ldmVyO1xuXG5leHBvcnQgdHlwZSBBbGxTZXR0aW5ncyA9IHtcbiAgICBbSyBpbiBPcHRpb25JZHNdOiBPcHRpb25LZXlzPEs+O1xufTtcblxuZXhwb3J0IGludGVyZmFjZSBDb25maWdQYXJhbXMge1xuICAgIC8qKiBJbml0aWFsIFBpeGVsIFN0cmVhbWluZyBzZXR0aW5ncyAqL1xuICAgIGluaXRpYWxTZXR0aW5ncz86IFBhcnRpYWw8QWxsU2V0dGluZ3M+O1xuICAgIC8qKiBJZiB1c2VVcmxQYXJhbXMgaXMgc2V0IHRydWUsIHdpbGwgcmVhZCBpbml0aWFsIHZhbHVlcyBmcm9tIFVSTCBwYXJhbWV0ZXJzIGFuZCBwZXJzaXN0IGNoYW5nZWQgc2V0dGluZ3MgaW50byBVUkwgKi9cbiAgICB1c2VVcmxQYXJhbXM/OiBib29sZWFuO1xufVxuZXhwb3J0IGNsYXNzIENvbmZpZyB7XG4gICAgLyogQSBtYXAgb2YgZmxhZ3MgdGhhdCBjYW4gYmUgdG9nZ2xlZCAtIG9wdGlvbnMgdGhhdCBjYW4gYmUgc2V0IGluIHRoZSBhcHBsaWNhdGlvbiAtIGUuZy4gVXNlIE1pYz8gKi9cbiAgICBwcml2YXRlIGZsYWdzID0gbmV3IE1hcDxGbGFnc0lkcywgU2V0dGluZ0ZsYWc+KCk7XG5cbiAgICAvKiBBIG1hcCBvZiBudW1lcmljYWwgc2V0dGluZ3MgLSBvcHRpb25zIHRoYXQgY2FuIGJlIGluIHRoZSBhcHBsaWNhdGlvbiAtIGUuZy4gTWluQml0cmF0ZSAqL1xuICAgIHByaXZhdGUgbnVtZXJpY1BhcmFtZXRlcnMgPSBuZXcgTWFwPE51bWVyaWNQYXJhbWV0ZXJzSWRzLCBTZXR0aW5nTnVtYmVyPigpO1xuXG4gICAgLyogQSBtYXAgb2YgdGV4dCBzZXR0aW5ncyAtIGUuZy4gc2lnbmFsbGluZyBzZXJ2ZXIgdXJsICovXG4gICAgcHJpdmF0ZSB0ZXh0UGFyYW1ldGVycyA9IG5ldyBNYXA8VGV4dFBhcmFtZXRlcnNJZHMsIFNldHRpbmdUZXh0PigpO1xuXG4gICAgLyogQSBtYXAgb2YgZW51bSBiYXNlZCBzZXR0aW5ncyAtIGUuZy4gcHJlZmVycmVkIGNvZGVjICovXG4gICAgcHJpdmF0ZSBvcHRpb25QYXJhbWV0ZXJzID0gbmV3IE1hcDxPcHRpb25QYXJhbWV0ZXJzSWRzLCBTZXR0aW5nT3B0aW9uPigpO1xuXG4gICAgcHJpdmF0ZSBfdXNlVXJsUGFyYW1zOiBib29sZWFuO1xuXG4gICAgLy8gLS0tLS0tLS0tLS0tIFNldHRpbmdzIC0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgICBjb25zdHJ1Y3Rvcihjb25maWc6IENvbmZpZ1BhcmFtcyA9IHt9KSB7XG4gICAgICAgIGNvbnN0IHsgaW5pdGlhbFNldHRpbmdzLCB1c2VVcmxQYXJhbXMgfSA9IGNvbmZpZztcbiAgICAgICAgdGhpcy5fdXNlVXJsUGFyYW1zID0gISF1c2VVcmxQYXJhbXM7XG4gICAgICAgIHRoaXMucG9wdWxhdGVEZWZhdWx0U2V0dGluZ3ModGhpcy5fdXNlVXJsUGFyYW1zKTtcbiAgICAgICAgaWYgKGluaXRpYWxTZXR0aW5ncykge1xuICAgICAgICAgICAgdGhpcy5zZXRTZXR0aW5ncyhpbml0aWFsU2V0dGluZ3MpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVHJ1ZSBpZiByZWFkaW5nIGNvbmZpZ3VyYXRpb24gaW5pdGlhbCB2YWx1ZXMgZnJvbSBVUkwgcGFyYW1ldGVycywgYW5kXG4gICAgICogcGVyc2lzdGluZyBjaGFuZ2VzIGluIFVSTCB3aGVuIGNoYW5nZWQuXG4gICAgICovXG4gICAgcHVibGljIGdldCB1c2VVcmxQYXJhbXMoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl91c2VVcmxQYXJhbXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUG9wdWxhdGUgdGhlIGRlZmF1bHQgc2V0dGluZ3MgZm9yIGEgUGl4ZWwgU3RyZWFtaW5nIGFwcGxpY2F0aW9uXG4gICAgICovXG4gICAgcHJpdmF0ZSBwb3B1bGF0ZURlZmF1bHRTZXR0aW5ncyh1c2VVcmxQYXJhbXM6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRleHQgUGFyYW1ldGVyc1xuICAgICAgICAgKi9cblxuICAgICAgICB0aGlzLnRleHRQYXJhbWV0ZXJzLnNldChcbiAgICAgICAgICAgIFRleHRQYXJhbWV0ZXJzLlNpZ25hbGxpbmdTZXJ2ZXJVcmwsXG4gICAgICAgICAgICBuZXcgU2V0dGluZ1RleHQoXG4gICAgICAgICAgICAgICAgVGV4dFBhcmFtZXRlcnMuU2lnbmFsbGluZ1NlcnZlclVybCxcbiAgICAgICAgICAgICAgICAnU2lnbmFsbGluZyB1cmwnLFxuICAgICAgICAgICAgICAgICdVcmwgb2YgdGhlIHNpZ25hbGxpbmcgc2VydmVyJyxcbiAgICAgICAgICAgICAgICAobG9jYXRpb24ucHJvdG9jb2wgPT09ICdodHRwczonID8gJ3dzczovLycgOiAnd3M6Ly8nKSArXG4gICAgICAgICAgICAgICAgICAgIHdpbmRvdy5sb2NhdGlvbi5ob3N0bmFtZSArXG4gICAgICAgICAgICAgICAgICAgIC8vIGZvciByZWFkYWJpbGl0eSwgd2Ugb21pdCB0aGUgcG9ydCBpZiBpdCdzIDgwXG4gICAgICAgICAgICAgICAgICAgICh3aW5kb3cubG9jYXRpb24ucG9ydCA9PT0gJzgwJyB8fFxuICAgICAgICAgICAgICAgICAgICB3aW5kb3cubG9jYXRpb24ucG9ydCA9PT0gJydcbiAgICAgICAgICAgICAgICAgICAgICAgID8gJydcbiAgICAgICAgICAgICAgICAgICAgICAgIDogYDoke3dpbmRvdy5sb2NhdGlvbi5wb3J0fWApLFxuICAgICAgICAgICAgICAgIHVzZVVybFBhcmFtc1xuICAgICAgICAgICAgKVxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMub3B0aW9uUGFyYW1ldGVycy5zZXQoXG4gICAgICAgICAgICBPcHRpb25QYXJhbWV0ZXJzLlN0cmVhbWVySWQsXG4gICAgICAgICAgICBuZXcgU2V0dGluZ09wdGlvbihcbiAgICAgICAgICAgICAgICBPcHRpb25QYXJhbWV0ZXJzLlN0cmVhbWVySWQsXG4gICAgICAgICAgICAgICAgJ1N0cmVhbWVyIElEJyxcbiAgICAgICAgICAgICAgICAnVGhlIElEIG9mIHRoZSBzdHJlYW1lciB0byBzdHJlYW0uJyxcbiAgICAgICAgICAgICAgICAnJyxcbiAgICAgICAgICAgICAgICBbXSxcbiAgICAgICAgICAgICAgICB1c2VVcmxQYXJhbXNcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogRW51bSBQYXJhbWV0ZXJzXG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLm9wdGlvblBhcmFtZXRlcnMuc2V0KFxuICAgICAgICAgICAgT3B0aW9uUGFyYW1ldGVycy5QcmVmZXJyZWRDb2RlYyxcbiAgICAgICAgICAgIG5ldyBTZXR0aW5nT3B0aW9uKFxuICAgICAgICAgICAgICAgIE9wdGlvblBhcmFtZXRlcnMuUHJlZmVycmVkQ29kZWMsXG4gICAgICAgICAgICAgICAgJ1ByZWZlcnJlZCBDb2RlYycsXG4gICAgICAgICAgICAgICAgJ1RoZSBwcmVmZXJyZWQgY29kZWMgdG8gYmUgdXNlZCBkdXJpbmcgY29kZWMgbmVnb3RpYXRpb24nLFxuICAgICAgICAgICAgICAgICdIMjY0IGxldmVsLWFzeW1tZXRyeS1hbGxvd2VkPTE7cGFja2V0aXphdGlvbi1tb2RlPTE7cHJvZmlsZS1sZXZlbC1pZD00MmUwMWYnLFxuICAgICAgICAgICAgICAgIChmdW5jdGlvbiAoKTogQXJyYXk8c3RyaW5nPiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGJyb3dzZXJTdXBwb3J0ZWRDb2RlY3M6IEFycmF5PHN0cmluZz4gPSBbXTtcbiAgICAgICAgICAgICAgICAgICAgLy8gVHJ5IGdldCB0aGUgaW5mbyBuZWVkZWQgZnJvbSB0aGUgUlRDUnRwUmVjZWl2ZXIuIFRoaXMgaXMgb25seSBhdmFpbGFibGUgb24gY2hyb21lXG4gICAgICAgICAgICAgICAgICAgIGlmICghUlRDUnRwUmVjZWl2ZXIuZ2V0Q2FwYWJpbGl0aWVzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBicm93c2VyU3VwcG9ydGVkQ29kZWNzLnB1c2goJ09ubHkgYXZhaWxhYmxlIG9uIENocm9tZScpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGJyb3dzZXJTdXBwb3J0ZWRDb2RlY3M7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBjb25zdCBtYXRjaGVyID0gLyhWUFxcZHxIMjZcXGR8QVYxKS4qLztcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgY29kZWNzID1cbiAgICAgICAgICAgICAgICAgICAgICAgIFJUQ1J0cFJlY2VpdmVyLmdldENhcGFiaWxpdGllcygndmlkZW8nKS5jb2RlY3M7XG4gICAgICAgICAgICAgICAgICAgIGNvZGVjcy5mb3JFYWNoKChjb2RlYykgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3Qgc3RyID1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2RlYy5taW1lVHlwZS5zcGxpdCgnLycpWzFdICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChjb2RlYy5zZHBGbXRwTGluZSB8fCAnJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBtYXRjaCA9IG1hdGNoZXIuZXhlYyhzdHIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1hdGNoICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJvd3NlclN1cHBvcnRlZENvZGVjcy5wdXNoKHN0cik7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYnJvd3NlclN1cHBvcnRlZENvZGVjcztcbiAgICAgICAgICAgICAgICB9KSgpLFxuICAgICAgICAgICAgICAgIHVzZVVybFBhcmFtc1xuICAgICAgICAgICAgKVxuICAgICAgICApO1x0XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIEJvb2xlYW4gcGFyYW1ldGVyc1xuICAgICAgICAgKi9cblxuICAgICAgICB0aGlzLmZsYWdzLnNldChcbiAgICAgICAgICAgIEZsYWdzLkF1dG9Db25uZWN0LFxuICAgICAgICAgICAgbmV3IFNldHRpbmdGbGFnKFxuICAgICAgICAgICAgICAgIEZsYWdzLkF1dG9Db25uZWN0LFxuICAgICAgICAgICAgICAgICdBdXRvIGNvbm5lY3QgdG8gc3RyZWFtJyxcbiAgICAgICAgICAgICAgICAnV2hldGhlciB3ZSBzaG91bGQgYXR0ZW1wdCB0byBhdXRvIGNvbm5lY3QgdG8gdGhlIHNpZ25hbGxpbmcgc2VydmVyIG9yIHNob3cgYSBjbGljayB0byBzdGFydCBwcm9tcHQuJyxcbiAgICAgICAgICAgICAgICBmYWxzZSxcbiAgICAgICAgICAgICAgICB1c2VVcmxQYXJhbXNcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLmZsYWdzLnNldChcbiAgICAgICAgICAgIEZsYWdzLkF1dG9QbGF5VmlkZW8sXG4gICAgICAgICAgICBuZXcgU2V0dGluZ0ZsYWcoXG4gICAgICAgICAgICAgICAgRmxhZ3MuQXV0b1BsYXlWaWRlbyxcbiAgICAgICAgICAgICAgICAnQXV0byBwbGF5IHZpZGVvJyxcbiAgICAgICAgICAgICAgICAnV2hlbiB2aWRlbyBpcyByZWFkeSBhdXRvbWF0aWNhbGx5IHN0YXJ0IHBsYXlpbmcgaXQgYXMgb3Bwb3NlZCB0byBzaG93aW5nIGEgcGxheSBidXR0b24uJyxcbiAgICAgICAgICAgICAgICB0cnVlLFxuICAgICAgICAgICAgICAgIHVzZVVybFBhcmFtc1xuICAgICAgICAgICAgKVxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMuZmxhZ3Muc2V0KFxuICAgICAgICAgICAgRmxhZ3MuQnJvd3NlclNlbmRPZmZlcixcbiAgICAgICAgICAgIG5ldyBTZXR0aW5nRmxhZyhcbiAgICAgICAgICAgICAgICBGbGFncy5Ccm93c2VyU2VuZE9mZmVyLFxuICAgICAgICAgICAgICAgICdCcm93c2VyIHNlbmQgb2ZmZXInLFxuICAgICAgICAgICAgICAgICdCcm93c2VyIHdpbGwgaW5pdGlhdGUgdGhlIFdlYlJUQyBoYW5kc2hha2UgYnkgc2VuZGluZyB0aGUgb2ZmZXIgdG8gdGhlIHN0cmVhbWVyJyxcbiAgICAgICAgICAgICAgICBmYWxzZSxcbiAgICAgICAgICAgICAgICB1c2VVcmxQYXJhbXNcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLmZsYWdzLnNldChcbiAgICAgICAgICAgIEZsYWdzLlVzZU1pYyxcbiAgICAgICAgICAgIG5ldyBTZXR0aW5nRmxhZyhcbiAgICAgICAgICAgICAgICBGbGFncy5Vc2VNaWMsXG4gICAgICAgICAgICAgICAgJ1VzZSBtaWNyb3Bob25lJyxcbiAgICAgICAgICAgICAgICAnTWFrZSBicm93c2VyIHJlcXVlc3QgbWljcm9waG9uZSBhY2Nlc3MgYW5kIG9wZW4gYW4gaW5wdXQgYXVkaW8gdHJhY2suJyxcbiAgICAgICAgICAgICAgICBmYWxzZSxcbiAgICAgICAgICAgICAgICB1c2VVcmxQYXJhbXNcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLmZsYWdzLnNldChcbiAgICAgICAgICAgIEZsYWdzLlN0YXJ0VmlkZW9NdXRlZCxcbiAgICAgICAgICAgIG5ldyBTZXR0aW5nRmxhZyhcbiAgICAgICAgICAgICAgICBGbGFncy5TdGFydFZpZGVvTXV0ZWQsXG4gICAgICAgICAgICAgICAgJ1N0YXJ0IHZpZGVvIG11dGVkJyxcbiAgICAgICAgICAgICAgICAnVmlkZW8gd2lsbCBzdGFydCBtdXRlZCBpZiB0cnVlLicsXG4gICAgICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAgICAgdXNlVXJsUGFyYW1zXG4gICAgICAgICAgICApXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5mbGFncy5zZXQoXG4gICAgICAgICAgICBGbGFncy5TdXBwcmVzc0Jyb3dzZXJLZXlzLFxuICAgICAgICAgICAgbmV3IFNldHRpbmdGbGFnKFxuICAgICAgICAgICAgICAgIEZsYWdzLlN1cHByZXNzQnJvd3NlcktleXMsXG4gICAgICAgICAgICAgICAgJ1N1cHByZXNzIGJyb3dzZXIga2V5cycsXG4gICAgICAgICAgICAgICAgJ1N1cHByZXNzIGNlcnRhaW4gYnJvd3NlciBrZXlzIHRoYXQgd2UgdXNlIGluIFVFLCBmb3IgZXhhbXBsZSBGNSB0byBzaG93IHNoYWRlciBjb21wbGV4aXR5IGluc3RlYWQgb2YgcmVmcmVzaCB0aGUgcGFnZS4nLFxuICAgICAgICAgICAgICAgIHRydWUsXG4gICAgICAgICAgICAgICAgdXNlVXJsUGFyYW1zXG4gICAgICAgICAgICApXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5mbGFncy5zZXQoXG4gICAgICAgICAgICBGbGFncy5Jc1F1YWxpdHlDb250cm9sbGVyLFxuICAgICAgICAgICAgbmV3IFNldHRpbmdGbGFnKFxuICAgICAgICAgICAgICAgIEZsYWdzLklzUXVhbGl0eUNvbnRyb2xsZXIsXG4gICAgICAgICAgICAgICAgJ0lzIHF1YWxpdHkgY29udHJvbGxlcj8nLFxuICAgICAgICAgICAgICAgICdUcnVlIGlmIHRoaXMgcGVlciBjb250cm9scyBzdHJlYW0gcXVhbGl0eScsXG4gICAgICAgICAgICAgICAgdHJ1ZSxcbiAgICAgICAgICAgICAgICB1c2VVcmxQYXJhbXNcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLmZsYWdzLnNldChcbiAgICAgICAgICAgIEZsYWdzLkZvcmNlTW9ub0F1ZGlvLFxuICAgICAgICAgICAgbmV3IFNldHRpbmdGbGFnKFxuICAgICAgICAgICAgICAgIEZsYWdzLkZvcmNlTW9ub0F1ZGlvLFxuICAgICAgICAgICAgICAgICdGb3JjZSBtb25vIGF1ZGlvJyxcbiAgICAgICAgICAgICAgICAnRm9yY2UgYnJvd3NlciB0byByZXF1ZXN0IG1vbm8gYXVkaW8gaW4gdGhlIFNEUCcsXG4gICAgICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAgICAgdXNlVXJsUGFyYW1zXG4gICAgICAgICAgICApXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5mbGFncy5zZXQoXG4gICAgICAgICAgICBGbGFncy5Gb3JjZVRVUk4sXG4gICAgICAgICAgICBuZXcgU2V0dGluZ0ZsYWcoXG4gICAgICAgICAgICAgICAgRmxhZ3MuRm9yY2VUVVJOLFxuICAgICAgICAgICAgICAgICdGb3JjZSBUVVJOJyxcbiAgICAgICAgICAgICAgICAnT25seSBnZW5lcmF0ZSBUVVJOL1JlbGF5ZWQgSUNFIGNhbmRpZGF0ZXMuJyxcbiAgICAgICAgICAgICAgICBmYWxzZSxcbiAgICAgICAgICAgICAgICB1c2VVcmxQYXJhbXNcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLmZsYWdzLnNldChcbiAgICAgICAgICAgIEZsYWdzLkFGS0RldGVjdGlvbixcbiAgICAgICAgICAgIG5ldyBTZXR0aW5nRmxhZyhcbiAgICAgICAgICAgICAgICBGbGFncy5BRktEZXRlY3Rpb24sXG4gICAgICAgICAgICAgICAgJ0FGSyBpZiBpZGxlJyxcbiAgICAgICAgICAgICAgICAnVGltZW91dCB0aGUgZXhwZXJpZW5jZSBpZiB1c2VyIGlzIEFGSyBmb3IgYSBwZXJpb2QuJyxcbiAgICAgICAgICAgICAgICBmYWxzZSxcbiAgICAgICAgICAgICAgICB1c2VVcmxQYXJhbXNcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLmZsYWdzLnNldChcbiAgICAgICAgICAgIEZsYWdzLk1hdGNoVmlld3BvcnRSZXNvbHV0aW9uLFxuICAgICAgICAgICAgbmV3IFNldHRpbmdGbGFnKFxuICAgICAgICAgICAgICAgIEZsYWdzLk1hdGNoVmlld3BvcnRSZXNvbHV0aW9uLFxuICAgICAgICAgICAgICAgICdNYXRjaCB2aWV3cG9ydCByZXNvbHV0aW9uJyxcbiAgICAgICAgICAgICAgICAnUGl4ZWwgU3RyZWFtaW5nIHdpbGwgYmUgaW5zdHJ1Y3RlZCB0byBkeW5hbWljYWxseSByZXNpemUgdGhlIHZpZGVvIHN0cmVhbSB0byBtYXRjaCB0aGUgc2l6ZSBvZiB0aGUgdmlkZW8gZWxlbWVudC4nLFxuICAgICAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgICAgIHVzZVVybFBhcmFtc1xuICAgICAgICAgICAgKVxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMuZmxhZ3Muc2V0KFxuICAgICAgICAgICAgRmxhZ3MuSG92ZXJpbmdNb3VzZU1vZGUsXG4gICAgICAgICAgICBuZXcgU2V0dGluZ0ZsYWcoXG4gICAgICAgICAgICAgICAgRmxhZ3MuSG92ZXJpbmdNb3VzZU1vZGUsXG4gICAgICAgICAgICAgICAgJ0NvbnRyb2wgU2NoZW1lOiBMb2NrZWQgTW91c2UnLFxuICAgICAgICAgICAgICAgICdFaXRoZXIgbG9ja2VkIG1vdXNlLCB3aGVyZSB0aGUgcG9pbnRlciBpcyBjb25zdW1lZCBieSB0aGUgdmlkZW8gYW5kIGxvY2tlZCB0byBpdCwgb3IgaG92ZXJpbmcgbW91c2UsIHdoZXJlIHRoZSBtb3VzZSBpcyBub3QgY29uc3VtZWQuJyxcbiAgICAgICAgICAgICAgICBmYWxzZSxcbiAgICAgICAgICAgICAgICB1c2VVcmxQYXJhbXMsXG4gICAgICAgICAgICAgICAgKGlzSG92ZXJpbmdNb3VzZTogYm9vbGVhbiwgc2V0dGluZzogU2V0dGluZ0Jhc2UpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgc2V0dGluZy5sYWJlbCA9IGBDb250cm9sIFNjaGVtZTogJHtpc0hvdmVyaW5nTW91c2UgPyAnSG92ZXJpbmcnIDogJ0xvY2tlZCd9IE1vdXNlYDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5mbGFncy5zZXQoXG4gICAgICAgICAgICBGbGFncy5GYWtlTW91c2VXaXRoVG91Y2hlcyxcbiAgICAgICAgICAgIG5ldyBTZXR0aW5nRmxhZyhcbiAgICAgICAgICAgICAgICBGbGFncy5GYWtlTW91c2VXaXRoVG91Y2hlcyxcbiAgICAgICAgICAgICAgICAnRmFrZSBtb3VzZSB3aXRoIHRvdWNoZXMnLFxuICAgICAgICAgICAgICAgICdBIHNpbmdsZSBmaW5nZXIgdG91Y2ggaXMgY29udmVydGVkIGludG8gYSBtb3VzZSBldmVudC4gVGhpcyBhbGxvd3MgYSBub24tdG91Y2ggYXBwbGljYXRpb24gdG8gYmUgY29udHJvbGxlZCBwYXJ0aWFsbHkgdmlhIGEgdG91Y2ggZGV2aWNlLicsXG4gICAgICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAgICAgdXNlVXJsUGFyYW1zXG4gICAgICAgICAgICApXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5mbGFncy5zZXQoXG4gICAgICAgICAgICBGbGFncy5LZXlib2FyZElucHV0LFxuICAgICAgICAgICAgbmV3IFNldHRpbmdGbGFnKFxuICAgICAgICAgICAgICAgIEZsYWdzLktleWJvYXJkSW5wdXQsXG4gICAgICAgICAgICAgICAgJ0tleWJvYXJkIGlucHV0JyxcbiAgICAgICAgICAgICAgICAnSWYgZW5hYmxlZCwgc2VuZCBrZXlib2FyZCBldmVudHMgdG8gc3RyZWFtZXInLFxuICAgICAgICAgICAgICAgIHRydWUsXG4gICAgICAgICAgICAgICAgdXNlVXJsUGFyYW1zXG4gICAgICAgICAgICApXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5mbGFncy5zZXQoXG4gICAgICAgICAgICBGbGFncy5Nb3VzZUlucHV0LFxuICAgICAgICAgICAgbmV3IFNldHRpbmdGbGFnKFxuICAgICAgICAgICAgICAgIEZsYWdzLk1vdXNlSW5wdXQsXG4gICAgICAgICAgICAgICAgJ01vdXNlIGlucHV0JyxcbiAgICAgICAgICAgICAgICAnSWYgZW5hYmxlZCwgc2VuZCBtb3VzZSBldmVudHMgdG8gc3RyZWFtZXInLFxuICAgICAgICAgICAgICAgIHRydWUsXG4gICAgICAgICAgICAgICAgdXNlVXJsUGFyYW1zXG4gICAgICAgICAgICApXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5mbGFncy5zZXQoXG4gICAgICAgICAgICBGbGFncy5Ub3VjaElucHV0LFxuICAgICAgICAgICAgbmV3IFNldHRpbmdGbGFnKFxuICAgICAgICAgICAgICAgIEZsYWdzLlRvdWNoSW5wdXQsXG4gICAgICAgICAgICAgICAgJ1RvdWNoIGlucHV0JyxcbiAgICAgICAgICAgICAgICAnSWYgZW5hYmxlZCwgc2VuZCB0b3VjaCBldmVudHMgdG8gc3RyZWFtZXInLFxuICAgICAgICAgICAgICAgIHRydWUsXG4gICAgICAgICAgICAgICAgdXNlVXJsUGFyYW1zXG4gICAgICAgICAgICApXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5mbGFncy5zZXQoXG4gICAgICAgICAgICBGbGFncy5HYW1lcGFkSW5wdXQsXG4gICAgICAgICAgICBuZXcgU2V0dGluZ0ZsYWcoXG4gICAgICAgICAgICAgICAgRmxhZ3MuR2FtZXBhZElucHV0LFxuICAgICAgICAgICAgICAgICdHYW1lcGFkIGlucHV0JyxcbiAgICAgICAgICAgICAgICAnSWYgZW5hYmxlZCwgc2VuZCBnYW1lcGFkIGV2ZW50cyB0byBzdHJlYW1lcicsXG4gICAgICAgICAgICAgICAgdHJ1ZSxcbiAgICAgICAgICAgICAgICB1c2VVcmxQYXJhbXNcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLmZsYWdzLnNldChcbiAgICAgICAgICAgIEZsYWdzLlhSQ29udHJvbGxlcklucHV0LFxuICAgICAgICAgICAgbmV3IFNldHRpbmdGbGFnKFxuICAgICAgICAgICAgICAgIEZsYWdzLlhSQ29udHJvbGxlcklucHV0LFxuICAgICAgICAgICAgICAgICdYUiBjb250cm9sbGVyIGlucHV0JyxcbiAgICAgICAgICAgICAgICAnSWYgZW5hYmxlZCwgc2VuZCBYUiBjb250cm9sbGVyIGV2ZW50cyB0byBzdHJlYW1lcicsXG4gICAgICAgICAgICAgICAgdHJ1ZSxcbiAgICAgICAgICAgICAgICB1c2VVcmxQYXJhbXNcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLmZsYWdzLnNldChcbiAgICAgICAgICAgIEZsYWdzLldhaXRGb3JTdHJlYW1lcixcbiAgICAgICAgICAgIG5ldyBTZXR0aW5nRmxhZyhcbiAgICAgICAgICAgICAgICBGbGFncy5XYWl0Rm9yU3RyZWFtZXIsXG4gICAgICAgICAgICAgICAgJ1dhaXQgZm9yIHN0cmVhbWVyJyxcbiAgICAgICAgICAgICAgICAnV2lsbCBjb250aW51ZSB0cnlpbmcgdG8gY29ubmVjdCB0byB0aGUgZmlyc3Qgc3RyZWFtZXIgYXZhaWxhYmxlLicsXG4gICAgICAgICAgICAgICAgdHJ1ZSxcbiAgICAgICAgICAgICAgICB1c2VVcmxQYXJhbXNcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogTnVtZXJpYyBwYXJhbWV0ZXJzXG4gICAgICAgICAqL1xuXG4gICAgICAgIHRoaXMubnVtZXJpY1BhcmFtZXRlcnMuc2V0KFxuICAgICAgICAgICAgTnVtZXJpY1BhcmFtZXRlcnMuQUZLVGltZW91dFNlY3MsXG4gICAgICAgICAgICBuZXcgU2V0dGluZ051bWJlcihcbiAgICAgICAgICAgICAgICBOdW1lcmljUGFyYW1ldGVycy5BRktUaW1lb3V0U2VjcyxcbiAgICAgICAgICAgICAgICAnQUZLIHRpbWVvdXQnLFxuICAgICAgICAgICAgICAgICdUaGUgdGltZSAoaW4gc2Vjb25kcykgaXQgdGFrZXMgZm9yIHRoZSBhcHBsaWNhdGlvbiB0byB0aW1lIG91dCBpZiBBRksgdGltZW91dCBpcyBlbmFibGVkLicsXG4gICAgICAgICAgICAgICAgMCAvKm1pbiovLFxuICAgICAgICAgICAgICAgIDYwMCAvKm1heCovLFxuICAgICAgICAgICAgICAgIDEyMCAvKnZhbHVlKi8sXG4gICAgICAgICAgICAgICAgdXNlVXJsUGFyYW1zXG4gICAgICAgICAgICApXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5udW1lcmljUGFyYW1ldGVycy5zZXQoXG4gICAgICAgICAgICBOdW1lcmljUGFyYW1ldGVycy5NYXhSZWNvbm5lY3RBdHRlbXB0cyxcbiAgICAgICAgICAgIG5ldyBTZXR0aW5nTnVtYmVyKFxuICAgICAgICAgICAgICAgIE51bWVyaWNQYXJhbWV0ZXJzLk1heFJlY29ubmVjdEF0dGVtcHRzLFxuICAgICAgICAgICAgICAgICdNYXggUmVjb25uZWN0cycsXG4gICAgICAgICAgICAgICAgJ01heGltdW0gbnVtYmVyIG9mIHJlY29ubmVjdHMgdGhlIGFwcGxpY2F0aW9uIHdpbGwgYXR0ZW1wdCB3aGVuIGEgc3RyZWFtZXIgZGlzY29ubmVjdHMuJyxcbiAgICAgICAgICAgICAgICAwIC8qbWluKi8sXG4gICAgICAgICAgICAgICAgOTk5IC8qbWF4Ki8sXG4gICAgICAgICAgICAgICAgMyAvKnZhbHVlKi8sXG4gICAgICAgICAgICAgICAgdXNlVXJsUGFyYW1zXG4gICAgICAgICAgICApXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5udW1lcmljUGFyYW1ldGVycy5zZXQoXG4gICAgICAgICAgICBOdW1lcmljUGFyYW1ldGVycy5NaW5RUCxcbiAgICAgICAgICAgIG5ldyBTZXR0aW5nTnVtYmVyKFxuICAgICAgICAgICAgICAgIE51bWVyaWNQYXJhbWV0ZXJzLk1pblFQLFxuICAgICAgICAgICAgICAgICdNaW4gUVAnLFxuICAgICAgICAgICAgICAgICdUaGUgbG93ZXIgYm91bmQgZm9yIHRoZSBxdWFudGl6YXRpb24gcGFyYW1ldGVyIChRUCkgb2YgdGhlIGVuY29kZXIuIDAgPSBCZXN0IHF1YWxpdHksIDUxID0gd29yc3QgcXVhbGl0eS4nLFxuICAgICAgICAgICAgICAgIDAgLyptaW4qLyxcbiAgICAgICAgICAgICAgICA1MSAvKm1heCovLFxuICAgICAgICAgICAgICAgIDAgLyp2YWx1ZSovLFxuICAgICAgICAgICAgICAgIHVzZVVybFBhcmFtc1xuICAgICAgICAgICAgKVxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMubnVtZXJpY1BhcmFtZXRlcnMuc2V0KFxuICAgICAgICAgICAgTnVtZXJpY1BhcmFtZXRlcnMuTWF4UVAsXG4gICAgICAgICAgICBuZXcgU2V0dGluZ051bWJlcihcbiAgICAgICAgICAgICAgICBOdW1lcmljUGFyYW1ldGVycy5NYXhRUCxcbiAgICAgICAgICAgICAgICAnTWF4IFFQJyxcbiAgICAgICAgICAgICAgICAnVGhlIHVwcGVyIGJvdW5kIGZvciB0aGUgcXVhbnRpemF0aW9uIHBhcmFtZXRlciAoUVApIG9mIHRoZSBlbmNvZGVyLiAwID0gQmVzdCBxdWFsaXR5LCA1MSA9IHdvcnN0IHF1YWxpdHkuJyxcbiAgICAgICAgICAgICAgICAwIC8qbWluKi8sXG4gICAgICAgICAgICAgICAgNTEgLyptYXgqLyxcbiAgICAgICAgICAgICAgICA1MSAvKnZhbHVlKi8sXG4gICAgICAgICAgICAgICAgdXNlVXJsUGFyYW1zXG4gICAgICAgICAgICApXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5udW1lcmljUGFyYW1ldGVycy5zZXQoXG4gICAgICAgICAgICBOdW1lcmljUGFyYW1ldGVycy5XZWJSVENGUFMsXG4gICAgICAgICAgICBuZXcgU2V0dGluZ051bWJlcihcbiAgICAgICAgICAgICAgICBOdW1lcmljUGFyYW1ldGVycy5XZWJSVENGUFMsXG4gICAgICAgICAgICAgICAgJ01heCBGUFMnLFxuICAgICAgICAgICAgICAgICdUaGUgbWF4aW11bSBGUFMgdGhhdCBXZWJSVEMgd2lsbCB0cnkgdG8gdHJhbnNtaXQgZnJhbWVzIGF0LicsXG4gICAgICAgICAgICAgICAgMSAvKm1pbiovLFxuICAgICAgICAgICAgICAgIDk5OSAvKm1heCovLFxuICAgICAgICAgICAgICAgIDYwIC8qdmFsdWUqLyxcbiAgICAgICAgICAgICAgICB1c2VVcmxQYXJhbXNcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLm51bWVyaWNQYXJhbWV0ZXJzLnNldChcbiAgICAgICAgICAgIE51bWVyaWNQYXJhbWV0ZXJzLldlYlJUQ01pbkJpdHJhdGUsXG4gICAgICAgICAgICBuZXcgU2V0dGluZ051bWJlcihcbiAgICAgICAgICAgICAgICBOdW1lcmljUGFyYW1ldGVycy5XZWJSVENNaW5CaXRyYXRlLFxuICAgICAgICAgICAgICAgICdNaW4gQml0cmF0ZSAoa2JwcyknLFxuICAgICAgICAgICAgICAgICdUaGUgbWluaW11bSBiaXRyYXRlIHRoYXQgV2ViUlRDIHNob3VsZCB1c2UuJyxcbiAgICAgICAgICAgICAgICAwIC8qbWluKi8sXG4gICAgICAgICAgICAgICAgNTAwMDAwIC8qbWF4Ki8sXG4gICAgICAgICAgICAgICAgMCAvKnZhbHVlKi8sXG4gICAgICAgICAgICAgICAgdXNlVXJsUGFyYW1zXG4gICAgICAgICAgICApXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5udW1lcmljUGFyYW1ldGVycy5zZXQoXG4gICAgICAgICAgICBOdW1lcmljUGFyYW1ldGVycy5XZWJSVENNYXhCaXRyYXRlLFxuICAgICAgICAgICAgbmV3IFNldHRpbmdOdW1iZXIoXG4gICAgICAgICAgICAgICAgTnVtZXJpY1BhcmFtZXRlcnMuV2ViUlRDTWF4Qml0cmF0ZSxcbiAgICAgICAgICAgICAgICAnTWF4IEJpdHJhdGUgKGticHMpJyxcbiAgICAgICAgICAgICAgICAnVGhlIG1heGltdW0gYml0cmF0ZSB0aGF0IFdlYlJUQyBzaG91bGQgdXNlLicsXG4gICAgICAgICAgICAgICAgMCAvKm1pbiovLFxuICAgICAgICAgICAgICAgIDUwMDAwMCAvKm1heCovLFxuICAgICAgICAgICAgICAgIDAgLyp2YWx1ZSovLFxuICAgICAgICAgICAgICAgIHVzZVVybFBhcmFtc1xuICAgICAgICAgICAgKVxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMubnVtZXJpY1BhcmFtZXRlcnMuc2V0KFxuICAgICAgICAgICAgTnVtZXJpY1BhcmFtZXRlcnMuU3RyZWFtZXJBdXRvSm9pbkludGVydmFsLFxuICAgICAgICAgICAgbmV3IFNldHRpbmdOdW1iZXIoXG4gICAgICAgICAgICAgICAgTnVtZXJpY1BhcmFtZXRlcnMuU3RyZWFtZXJBdXRvSm9pbkludGVydmFsLFxuICAgICAgICAgICAgICAgICdTdHJlYW1lciBBdXRvIEpvaW4gSW50ZXJ2YWwgKG1zKScsXG4gICAgICAgICAgICAgICAgJ0RlbGF5IGJldHdlZW4gcmV0cmllcyB3aGVuIHdhaXRpbmcgZm9yIGFuIGF2YWlsYWJsZSBzdHJlYW1lci4nLFxuICAgICAgICAgICAgICAgIDUwMCAvKm1pbiovLFxuICAgICAgICAgICAgICAgIDkwMDAwMCAvKm1heCovLFxuICAgICAgICAgICAgICAgIDMwMDAgLyp2YWx1ZSovLFxuICAgICAgICAgICAgICAgIHVzZVVybFBhcmFtc1xuICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFkZCBhIGNhbGxiYWNrIHRvIGZpcmUgd2hlbiB0aGUgbnVtZXJpYyBzZXR0aW5nIGlzIHRvZ2dsZWQuXG4gICAgICogQHBhcmFtIGlkIFRoZSBpZCBvZiB0aGUgZmxhZy5cbiAgICAgKiBAcGFyYW0gb25DaGFuZ2VkTGlzdGVuZXIgVGhlIGNhbGxiYWNrIHRvIGZpcmUgd2hlbiB0aGUgbnVtZXJpYyB2YWx1ZSBjaGFuZ2VzLlxuICAgICAqL1xuICAgIF9hZGRPbk51bWVyaWNTZXR0aW5nQ2hhbmdlZExpc3RlbmVyKFxuICAgICAgICBpZDogTnVtZXJpY1BhcmFtZXRlcnNJZHMsXG4gICAgICAgIG9uQ2hhbmdlZExpc3RlbmVyOiAobmV3VmFsdWU6IG51bWJlcikgPT4gdm9pZFxuICAgICk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5udW1lcmljUGFyYW1ldGVycy5oYXMoaWQpKSB7XG4gICAgICAgICAgICB0aGlzLm51bWVyaWNQYXJhbWV0ZXJzXG4gICAgICAgICAgICAgICAgLmdldChpZClcbiAgICAgICAgICAgICAgICAuYWRkT25DaGFuZ2VkTGlzdGVuZXIob25DaGFuZ2VkTGlzdGVuZXIpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgX2FkZE9uT3B0aW9uU2V0dGluZ0NoYW5nZWRMaXN0ZW5lcihcbiAgICAgICAgaWQ6IE9wdGlvblBhcmFtZXRlcnNJZHMsXG4gICAgICAgIG9uQ2hhbmdlZExpc3RlbmVyOiAobmV3VmFsdWU6IHN0cmluZykgPT4gdm9pZFxuICAgICk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5vcHRpb25QYXJhbWV0ZXJzLmhhcyhpZCkpIHtcbiAgICAgICAgICAgIHRoaXMub3B0aW9uUGFyYW1ldGVyc1xuICAgICAgICAgICAgICAgIC5nZXQoaWQpXG4gICAgICAgICAgICAgICAgLmFkZE9uQ2hhbmdlZExpc3RlbmVyKG9uQ2hhbmdlZExpc3RlbmVyKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSBpZCBUaGUgaWQgb2YgdGhlIG51bWVyaWMgc2V0dGluZyB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBnZXR0aW5nIGEgdmFsdWUgZm9yLlxuICAgICAqIEByZXR1cm5zIFRoZSBudW1lcmljIHZhbHVlIHN0b3JlZCBpbiB0aGUgcGFyYW1ldGVyIHdpdGggdGhlIHBhc3NlZCBpZC5cbiAgICAgKi9cbiAgICBnZXROdW1lcmljU2V0dGluZ1ZhbHVlKGlkOiBOdW1lcmljUGFyYW1ldGVyc0lkcyk6IG51bWJlciB7XG4gICAgICAgIGlmICh0aGlzLm51bWVyaWNQYXJhbWV0ZXJzLmhhcyhpZCkpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLm51bWVyaWNQYXJhbWV0ZXJzLmdldChpZCkubnVtYmVyO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBUaGVyZSBpcyBubyBudW1lcmljIHNldHRpbmcgd2l0aCB0aGUgaWQgb2YgJHtpZH1gKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSBpZCBUaGUgaWQgb2YgdGhlIHRleHQgc2V0dGluZyB3ZSBhcmUgaW50ZXJlc3RlZCBpbiBnZXR0aW5nIGEgdmFsdWUgZm9yLlxuICAgICAqIEByZXR1cm5zIFRoZSB0ZXh0IHZhbHVlIHN0b3JlZCBpbiB0aGUgcGFyYW1ldGVyIHdpdGggdGhlIHBhc3NlZCBpZC5cbiAgICAgKi9cbiAgICBnZXRUZXh0U2V0dGluZ1ZhbHVlKGlkOiBUZXh0UGFyYW1ldGVyc0lkcyk6IHN0cmluZyB7XG4gICAgICAgIGlmICh0aGlzLnRleHRQYXJhbWV0ZXJzLmhhcyhpZCkpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnRleHRQYXJhbWV0ZXJzLmdldChpZCkudmFsdWUgYXMgc3RyaW5nO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBUaGVyZSBpcyBubyBudW1lcmljIHNldHRpbmcgd2l0aCB0aGUgaWQgb2YgJHtpZH1gKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCBudW1iZXIgaW4gdGhlIHNldHRpbmcuXG4gICAgICogQHBhcmFtIGlkIFRoZSBpZCBvZiB0aGUgbnVtZXJpYyBzZXR0aW5nIHdlIGFyZSBpbnRlcmVzdGVkIGluLlxuICAgICAqIEBwYXJhbSB2YWx1ZSBUaGUgbnVtZXJpYyB2YWx1ZSB0byBzZXQuXG4gICAgICovXG4gICAgc2V0TnVtZXJpY1NldHRpbmcoaWQ6IE51bWVyaWNQYXJhbWV0ZXJzSWRzLCB2YWx1ZTogbnVtYmVyKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLm51bWVyaWNQYXJhbWV0ZXJzLmhhcyhpZCkpIHtcbiAgICAgICAgICAgIHRoaXMubnVtZXJpY1BhcmFtZXRlcnMuZ2V0KGlkKS5udW1iZXIgPSB2YWx1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVGhlcmUgaXMgbm8gbnVtZXJpYyBzZXR0aW5nIHdpdGggdGhlIGlkIG9mICR7aWR9YCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBZGQgYSBjYWxsYmFjayB0byBmaXJlIHdoZW4gdGhlIGZsYWcgaXMgdG9nZ2xlZC5cbiAgICAgKiBAcGFyYW0gaWQgVGhlIGlkIG9mIHRoZSBmbGFnLlxuICAgICAqIEBwYXJhbSBvbkNoYW5nZUxpc3RlbmVyIFRoZSBjYWxsYmFjayB0byBmaXJlIHdoZW4gdGhlIHZhbHVlIGNoYW5nZXMuXG4gICAgICovXG4gICAgX2FkZE9uU2V0dGluZ0NoYW5nZWRMaXN0ZW5lcihcbiAgICAgICAgaWQ6IEZsYWdzSWRzLFxuICAgICAgICBvbkNoYW5nZUxpc3RlbmVyOiAobmV3RmxhZ1ZhbHVlOiBib29sZWFuKSA9PiB2b2lkXG4gICAgKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmZsYWdzLmhhcyhpZCkpIHtcbiAgICAgICAgICAgIHRoaXMuZmxhZ3MuZ2V0KGlkKS5vbkNoYW5nZSA9IG9uQ2hhbmdlTGlzdGVuZXI7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBZGQgYSBjYWxsYmFjayB0byBmaXJlIHdoZW4gdGhlIHRleHQgaXMgY2hhbmdlZC5cbiAgICAgKiBAcGFyYW0gaWQgVGhlIGlkIG9mIHRoZSBmbGFnLlxuICAgICAqIEBwYXJhbSBvbkNoYW5nZUxpc3RlbmVyIFRoZSBjYWxsYmFjayB0byBmaXJlIHdoZW4gdGhlIHZhbHVlIGNoYW5nZXMuXG4gICAgICovXG4gICAgX2FkZE9uVGV4dFNldHRpbmdDaGFuZ2VkTGlzdGVuZXIoXG4gICAgICAgIGlkOiBUZXh0UGFyYW1ldGVyc0lkcyxcbiAgICAgICAgb25DaGFuZ2VMaXN0ZW5lcjogKG5ld1RleHRWYWx1ZTogc3RyaW5nKSA9PiB2b2lkXG4gICAgKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLnRleHRQYXJhbWV0ZXJzLmhhcyhpZCkpIHtcbiAgICAgICAgICAgIHRoaXMudGV4dFBhcmFtZXRlcnMuZ2V0KGlkKS5vbkNoYW5nZSA9IG9uQ2hhbmdlTGlzdGVuZXI7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgdGhlIG9wdGlvbiB3aGljaCBoYXMgdGhlIGdpdmVuIGlkLlxuICAgICAqIEBwYXJhbSBpZCBUaGUgaWQgb2YgdGhlIG9wdGlvbi5cbiAgICAgKiBAcmV0dXJucyBUaGUgU2V0dGluZ09wdGlvbiBvYmplY3QgbWF0Y2hpbmcgaWRcbiAgICAgKi9cbiAgICBnZXRTZXR0aW5nT3B0aW9uKGlkOiBPcHRpb25QYXJhbWV0ZXJzSWRzKTogU2V0dGluZ09wdGlvbiB7XG4gICAgICAgIHJldHVybiB0aGlzLm9wdGlvblBhcmFtZXRlcnMuZ2V0KGlkKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgdGhlIHZhbHVlIG9mIHRoZSBjb25maWd1cmF0aW9uIGZsYWcgd2hpY2ggaGFzIHRoZSBnaXZlbiBpZC5cbiAgICAgKiBAcGFyYW0gaWQgVGhlIHVuaXF1ZSBpZCBmb3IgdGhlIGZsYWcuXG4gICAgICogQHJldHVybnMgVHJ1ZSBpZiB0aGUgZmxhZyBpcyBlbmFibGVkLlxuICAgICAqL1xuICAgIGlzRmxhZ0VuYWJsZWQoaWQ6IEZsYWdzSWRzKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLmZsYWdzLmdldChpZCkuZmxhZyBhcyBib29sZWFuO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCBmbGFnIHRvIGJlIGVuYWJsZWQvZGlzYWJsZWQuXG4gICAgICogQHBhcmFtIGlkIFRoZSBpZCBvZiB0aGUgZmxhZyB0byB0b2dnbGUuXG4gICAgICogQHBhcmFtIGZsYWdFbmFibGVkIFRydWUgaWYgdGhlIGZsYWcgc2hvdWxkIGJlIGVuYWJsZWQuXG4gICAgICovXG4gICAgc2V0RmxhZ0VuYWJsZWQoaWQ6IEZsYWdzSWRzLCBmbGFnRW5hYmxlZDogYm9vbGVhbikge1xuICAgICAgICBpZiAoIXRoaXMuZmxhZ3MuaGFzKGlkKSkge1xuICAgICAgICAgICAgTG9nZ2VyLldhcm5pbmcoXG4gICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICBgQ2Fubm90IHRvZ2dsZSBmbGFnIGNhbGxlZCAke2lkfSAtIGl0IGRvZXMgbm90IGV4aXN0IGluIHRoZSBDb25maWcuZmxhZ3MgbWFwLmBcbiAgICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmZsYWdzLmdldChpZCkuZmxhZyA9IGZsYWdFbmFibGVkO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0IHRoZSB0ZXh0IHNldHRpbmcuXG4gICAgICogQHBhcmFtIGlkIFRoZSBpZCBvZiB0aGUgc2V0dGluZ1xuICAgICAqIEBwYXJhbSBzZXR0aW5nVmFsdWUgVGhlIHZhbHVlIHRvIHNldCBpbiB0aGUgc2V0dGluZy5cbiAgICAgKi9cbiAgICBzZXRUZXh0U2V0dGluZyhpZDogVGV4dFBhcmFtZXRlcnNJZHMsIHNldHRpbmdWYWx1ZTogc3RyaW5nKSB7XG4gICAgICAgIGlmICghdGhpcy50ZXh0UGFyYW1ldGVycy5oYXMoaWQpKSB7XG4gICAgICAgICAgICBMb2dnZXIuV2FybmluZyhcbiAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgIGBDYW5ub3Qgc2V0IHRleHQgc2V0dGluZyBjYWxsZWQgJHtpZH0gLSBpdCBkb2VzIG5vdCBleGlzdCBpbiB0aGUgQ29uZmlnLnRleHRQYXJhbWV0ZXJzIG1hcC5gXG4gICAgICAgICAgICApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy50ZXh0UGFyYW1ldGVycy5nZXQoaWQpLnRleHQgPSBzZXR0aW5nVmFsdWU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXQgdGhlIG9wdGlvbiBzZXR0aW5nIGxpc3Qgb2Ygb3B0aW9ucy5cbiAgICAgKiBAcGFyYW0gaWQgVGhlIGlkIG9mIHRoZSBzZXR0aW5nXG4gICAgICogQHBhcmFtIHNldHRpbmdPcHRpb25zIFRoZSB2YWx1ZXMgdGhlIHNldHRpbmcgY291bGQgdGFrZVxuICAgICAqL1xuICAgIHNldE9wdGlvblNldHRpbmdPcHRpb25zKFxuICAgICAgICBpZDogT3B0aW9uUGFyYW1ldGVyc0lkcyxcbiAgICAgICAgc2V0dGluZ09wdGlvbnM6IEFycmF5PHN0cmluZz5cbiAgICApIHtcbiAgICAgICAgaWYgKCF0aGlzLm9wdGlvblBhcmFtZXRlcnMuaGFzKGlkKSkge1xuICAgICAgICAgICAgTG9nZ2VyLldhcm5pbmcoXG4gICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICBgQ2Fubm90IHNldCB0ZXh0IHNldHRpbmcgY2FsbGVkICR7aWR9IC0gaXQgZG9lcyBub3QgZXhpc3QgaW4gdGhlIENvbmZpZy5vcHRpb25QYXJhbWV0ZXJzIG1hcC5gXG4gICAgICAgICAgICApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5vcHRpb25QYXJhbWV0ZXJzLmdldChpZCkub3B0aW9ucyA9IHNldHRpbmdPcHRpb25zO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0IG9wdGlvbiBlbnVtIHNldHRpbmdzIHNlbGVjdGVkIG9wdGlvbi5cbiAgICAgKiBAcGFyYW0gaWQgVGhlIGlkIG9mIHRoZSBzZXR0aW5nXG4gICAgICogQHBhcmFtIHNldHRpbmdPcHRpb25zIFRoZSB2YWx1ZSB0byBzZWxlY3Qgb3V0IG9mIGFsbCB0aGUgb3B0aW9uc1xuICAgICAqL1xuICAgIHNldE9wdGlvblNldHRpbmdWYWx1ZShpZDogT3B0aW9uUGFyYW1ldGVyc0lkcywgc2V0dGluZ1ZhbHVlOiBzdHJpbmcpIHtcbiAgICAgICAgaWYgKCF0aGlzLm9wdGlvblBhcmFtZXRlcnMuaGFzKGlkKSkge1xuICAgICAgICAgICAgTG9nZ2VyLldhcm5pbmcoXG4gICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICBgQ2Fubm90IHNldCB0ZXh0IHNldHRpbmcgY2FsbGVkICR7aWR9IC0gaXQgZG9lcyBub3QgZXhpc3QgaW4gdGhlIENvbmZpZy5lbnVtUGFyYW1ldGVycyBtYXAuYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMub3B0aW9uUGFyYW1ldGVycy5nZXQoaWQpLnNlbGVjdGVkID0gc2V0dGluZ1ZhbHVlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0IHRoZSBsYWJlbCBmb3IgdGhlIGZsYWcuXG4gICAgICogQHBhcmFtIGlkIFRoZSBpZCBvZiB0aGUgZmxhZy5cbiAgICAgKiBAcGFyYW0gbGFiZWwgVGhlIG5ldyBsYWJlbCB0byB1c2UgZm9yIHRoZSBmbGFnLlxuICAgICAqL1xuICAgIHNldEZsYWdMYWJlbChpZDogRmxhZ3NJZHMsIGxhYmVsOiBzdHJpbmcpIHtcbiAgICAgICAgaWYgKCF0aGlzLmZsYWdzLmhhcyhpZCkpIHtcbiAgICAgICAgICAgIExvZ2dlci5XYXJuaW5nKFxuICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgYENhbm5vdCBzZXQgbGFiZWwgZm9yIGZsYWcgY2FsbGVkICR7aWR9IC0gaXQgZG9lcyBub3QgZXhpc3QgaW4gdGhlIENvbmZpZy5mbGFncyBtYXAuYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuZmxhZ3MuZ2V0KGlkKS5sYWJlbCA9IGxhYmVsO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0IGEgc3Vic2V0IG9mIGFsbCBzZXR0aW5ncyBpbiBvbmUgZnVuY3Rpb24gY2FsbC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBzZXR0aW5ncyBBIChwYXJ0aWFsKSBsaXN0IG9mIHNldHRpbmdzIHRvIHNldFxuICAgICAqL1xuICAgIHNldFNldHRpbmdzKHNldHRpbmdzOiBQYXJ0aWFsPEFsbFNldHRpbmdzPikge1xuICAgICAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhzZXR0aW5ncykpIHtcbiAgICAgICAgICAgIGlmIChpc0ZsYWdJZChrZXkpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRGbGFnRW5hYmxlZChrZXksIHNldHRpbmdzW2tleV0pO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChpc051bWVyaWNJZChrZXkpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXROdW1lcmljU2V0dGluZyhrZXksIHNldHRpbmdzW2tleV0pO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChpc1RleHRJZChrZXkpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRUZXh0U2V0dGluZyhrZXksIHNldHRpbmdzW2tleV0pO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChpc09wdGlvbklkKGtleSkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNldE9wdGlvblNldHRpbmdWYWx1ZShrZXksIHNldHRpbmdzW2tleV0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGFsbCBzZXR0aW5nc1xuICAgICAqIEByZXR1cm5zIEFsbCBzZXR0aW5nIHZhbHVlcyBhcyBhbiBvYmplY3Qgd2l0aCBzZXR0aW5nIGlkcyBhcyBrZXlzXG4gICAgICovXG4gICAgZ2V0U2V0dGluZ3MoKTogUGFydGlhbDxBbGxTZXR0aW5ncz4ge1xuICAgICAgICBjb25zdCBzZXR0aW5nczogUGFydGlhbDxBbGxTZXR0aW5ncz4gPSB7fTtcbiAgICAgICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgdGhpcy5mbGFncy5lbnRyaWVzKCkpIHtcbiAgICAgICAgICAgIHNldHRpbmdzW2tleV0gPSB2YWx1ZS5mbGFnO1xuICAgICAgICB9XG4gICAgICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIHRoaXMubnVtZXJpY1BhcmFtZXRlcnMuZW50cmllcygpKSB7XG4gICAgICAgICAgICBzZXR0aW5nc1trZXldID0gdmFsdWUubnVtYmVyO1xuICAgICAgICB9XG4gICAgICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIHRoaXMudGV4dFBhcmFtZXRlcnMuZW50cmllcygpKSB7XG4gICAgICAgICAgICBzZXR0aW5nc1trZXldID0gdmFsdWUudGV4dDtcbiAgICAgICAgfVxuICAgICAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiB0aGlzLm9wdGlvblBhcmFtZXRlcnMuZW50cmllcygpKSB7XG4gICAgICAgICAgICBzZXR0aW5nc1trZXldID0gdmFsdWUuc2VsZWN0ZWQ7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNldHRpbmdzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCBhbGwgRmxhZyBzZXR0aW5ncyBhcyBhbiBhcnJheS5cbiAgICAgKiBAcmV0dXJucyBBbGwgU2V0dGluZ0ZsYWcgb2JqZWN0c1xuICAgICAqL1xuICAgIGdldEZsYWdzKCk6IEFycmF5PFNldHRpbmdGbGFnPiB7XG4gICAgICAgIHJldHVybiBBcnJheS5mcm9tKHRoaXMuZmxhZ3MudmFsdWVzKCkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCBhbGwgVGV4dCBzZXR0aW5ncyBhcyBhbiBhcnJheS5cbiAgICAgKiBAcmV0dXJucyBBbGwgU2V0dGluZ1RleHQgb2JqZWN0c1xuICAgICAqL1xuICAgIGdldFRleHRTZXR0aW5ncygpOiBBcnJheTxTZXR0aW5nVGV4dD4ge1xuICAgICAgICByZXR1cm4gQXJyYXkuZnJvbSh0aGlzLnRleHRQYXJhbWV0ZXJzLnZhbHVlcygpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgYWxsIE51bWJlciBzZXR0aW5ncyBhcyBhbiBhcnJheS5cbiAgICAgKiBAcmV0dXJucyBBbGwgU2V0dGluZ051bWJlciBvYmplY3RzXG4gICAgICovXG4gICAgZ2V0TnVtZXJpY1NldHRpbmdzKCk6IEFycmF5PFNldHRpbmdOdW1iZXI+IHtcbiAgICAgICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy5udW1lcmljUGFyYW1ldGVycy52YWx1ZXMoKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IGFsbCBPcHRpb24gc2V0dGluZ3MgYXMgYW4gYXJyYXkuXG4gICAgICogQHJldHVybnMgQWxsIFNldHRpbmdPcHRpb24gb2JqZWN0c1xuICAgICAqL1xuICAgIGdldE9wdGlvblNldHRpbmdzKCk6IEFycmF5PFNldHRpbmdPcHRpb24+IHtcbiAgICAgICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy5vcHRpb25QYXJhbWV0ZXJzLnZhbHVlcygpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBFbWl0IGV2ZW50cyB3aGVuIHNldHRpbmdzIGNoYW5nZS5cbiAgICAgKiBAcGFyYW0gZXZlbnRFbWl0dGVyXG4gICAgICovXG4gICAgX3JlZ2lzdGVyT25DaGFuZ2VFdmVudHMoZXZlbnRFbWl0dGVyOiBFdmVudEVtaXR0ZXIpIHtcbiAgICAgICAgZm9yIChjb25zdCBrZXkgb2YgdGhpcy5mbGFncy5rZXlzKCkpIHtcbiAgICAgICAgICAgIGNvbnN0IGZsYWcgPSB0aGlzLmZsYWdzLmdldChrZXkpO1xuICAgICAgICAgICAgaWYgKGZsYWcpIHtcbiAgICAgICAgICAgICAgICBmbGFnLm9uQ2hhbmdlRW1pdCA9IChuZXdWYWx1ZTogYm9vbGVhbikgPT5cbiAgICAgICAgICAgICAgICAgICAgZXZlbnRFbWl0dGVyLmRpc3BhdGNoRXZlbnQoXG4gICAgICAgICAgICAgICAgICAgICAgICBuZXcgU2V0dGluZ3NDaGFuZ2VkRXZlbnQoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkOiBmbGFnLmlkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICdmbGFnJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZTogbmV3VmFsdWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0OiBmbGFnXG4gICAgICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGZvciAoY29uc3Qga2V5IG9mIHRoaXMubnVtZXJpY1BhcmFtZXRlcnMua2V5cygpKSB7XG4gICAgICAgICAgICBjb25zdCBudW1iZXIgPSB0aGlzLm51bWVyaWNQYXJhbWV0ZXJzLmdldChrZXkpO1xuICAgICAgICAgICAgaWYgKG51bWJlcikge1xuICAgICAgICAgICAgICAgIG51bWJlci5vbkNoYW5nZUVtaXQgPSAobmV3VmFsdWU6IG51bWJlcikgPT5cbiAgICAgICAgICAgICAgICAgICAgZXZlbnRFbWl0dGVyLmRpc3BhdGNoRXZlbnQoXG4gICAgICAgICAgICAgICAgICAgICAgICBuZXcgU2V0dGluZ3NDaGFuZ2VkRXZlbnQoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkOiBudW1iZXIuaWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU6IG5ld1ZhbHVlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldDogbnVtYmVyXG4gICAgICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGZvciAoY29uc3Qga2V5IG9mIHRoaXMudGV4dFBhcmFtZXRlcnMua2V5cygpKSB7XG4gICAgICAgICAgICBjb25zdCB0ZXh0ID0gdGhpcy50ZXh0UGFyYW1ldGVycy5nZXQoa2V5KTtcbiAgICAgICAgICAgIGlmICh0ZXh0KSB7XG4gICAgICAgICAgICAgICAgdGV4dC5vbkNoYW5nZUVtaXQgPSAobmV3VmFsdWU6IHN0cmluZykgPT5cbiAgICAgICAgICAgICAgICAgICAgZXZlbnRFbWl0dGVyLmRpc3BhdGNoRXZlbnQoXG4gICAgICAgICAgICAgICAgICAgICAgICBuZXcgU2V0dGluZ3NDaGFuZ2VkRXZlbnQoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlkOiB0ZXh0LmlkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZTogbmV3VmFsdWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0OiB0ZXh0XG4gICAgICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGZvciAoY29uc3Qga2V5IG9mIHRoaXMub3B0aW9uUGFyYW1ldGVycy5rZXlzKCkpIHtcbiAgICAgICAgICAgIGNvbnN0IG9wdGlvbiA9IHRoaXMub3B0aW9uUGFyYW1ldGVycy5nZXQoa2V5KTtcbiAgICAgICAgICAgIGlmIChvcHRpb24pIHtcbiAgICAgICAgICAgICAgICBvcHRpb24ub25DaGFuZ2VFbWl0ID0gKG5ld1ZhbHVlOiBzdHJpbmcpID0+XG4gICAgICAgICAgICAgICAgICAgIGV2ZW50RW1pdHRlci5kaXNwYXRjaEV2ZW50KFxuICAgICAgICAgICAgICAgICAgICAgICAgbmV3IFNldHRpbmdzQ2hhbmdlZEV2ZW50KHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZDogb3B0aW9uLmlkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICdvcHRpb24nLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlOiBuZXdWYWx1ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXQ6IG9wdGlvblxuICAgICAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbn1cblxuLyoqXG4gKiBUaGUgZW51bSBhc3NvY2lhdGVkIHdpdGggdGhlIG1vdXNlIGJlaW5nIGxvY2tlZCBvciBob3ZlcmluZ1xuICovXG5leHBvcnQgZW51bSBDb250cm9sU2NoZW1lVHlwZSB7XG4gICAgTG9ja2VkTW91c2UgPSAwLFxuICAgIEhvdmVyaW5nTW91c2UgPSAxXG59XG4iLCIvLyBDb3B5cmlnaHQgRXBpYyBHYW1lcywgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuXG4vKipcbiAqIEJhc2UgY2xhc3MgZm9yIGEgc2V0dGluZyB0aGF0IGhhcyBhIHRleHQgbGFiZWwgYW5kIGFuIGFyYml0cmFyeSBzZXR0aW5nIHZhbHVlIGl0IHN0b3Jlcy5cbiAqL1xuZXhwb3J0IGNsYXNzIFNldHRpbmdCYXNlIHtcbiAgICBpZDogc3RyaW5nO1xuICAgIGRlc2NyaXB0aW9uOiBzdHJpbmc7XG4gICAgX2xhYmVsOiBzdHJpbmc7XG4gICAgX3ZhbHVlOiB1bmtub3duO1xuICAgIG9uQ2hhbmdlOiAoY2hhbmdlZFZhbHVlOiB1bmtub3duLCBzZXR0aW5nOiBTZXR0aW5nQmFzZSkgPT4gdm9pZDtcbiAgICBvbkNoYW5nZUVtaXQ6IChjaGFuZ2VkVmFsdWU6IHVua25vd24pID0+IHZvaWQ7XG5cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgaWQ6IHN0cmluZyxcbiAgICAgICAgbGFiZWw6IHN0cmluZyxcbiAgICAgICAgZGVzY3JpcHRpb246IHN0cmluZyxcbiAgICAgICAgZGVmYXVsdFNldHRpbmdWYWx1ZTogdW5rbm93bixcblx0XHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWVtcHR5LWZ1bmN0aW9uXG5cdFx0ZGVmYXVsdE9uQ2hhbmdlTGlzdGVuZXI6IChjaGFuZ2VkVmFsdWU6IHVua25vd24sIHNldHRpbmc6IFNldHRpbmdCYXNlKSA9PiB2b2lkID0gKCkgPT4geyAvKiBEbyBub3RoaW5nLCB0byBiZSBvdmVycmlkZGVuLiAqLyB9XG4gICAgKSB7XG4gICAgICAgIHRoaXMub25DaGFuZ2UgPSBkZWZhdWx0T25DaGFuZ2VMaXN0ZW5lcjtcblxuICAgICAgICB0aGlzLm9uQ2hhbmdlRW1pdCA9ICgpID0+IHtcbiAgICAgICAgICAgIC8qIERvIG5vdGhpbmcsIHRvIGJlIG92ZXJyaWRkZW4uICovXG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuaWQgPSBpZDtcbiAgICAgICAgdGhpcy5kZXNjcmlwdGlvbiA9IGRlc2NyaXB0aW9uO1xuICAgICAgICB0aGlzLmxhYmVsID0gbGFiZWw7XG4gICAgICAgIHRoaXMudmFsdWUgPSBkZWZhdWx0U2V0dGluZ1ZhbHVlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCB0aGUgbGFiZWwgdGV4dCBmb3IgdGhlIHNldHRpbmcuXG4gICAgICogQHBhcmFtIGxhYmVsIHNldHRpbmcgbGFiZWwuXG4gICAgICovXG4gICAgcHVibGljIHNldCBsYWJlbChpbkxhYmVsOiBzdHJpbmcpIHtcbiAgICAgICAgdGhpcy5fbGFiZWwgPSBpbkxhYmVsO1xuICAgICAgICB0aGlzLm9uQ2hhbmdlRW1pdCh0aGlzLl92YWx1ZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHJldHVybnMgVGhlIGxhYmVsIHRleHQgZm9yIHRoZSBzZXR0aW5nLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgbGFiZWwoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2xhYmVsO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEByZXR1cm4gVGhlIHNldHRpbmcncyB2YWx1ZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IHZhbHVlKCk6IHVua25vd24ge1xuICAgICAgICByZXR1cm4gdGhpcy5fdmFsdWU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVXBkYXRlIHRoZSBzZXR0aW5nJ3Mgc3RvcmVkIHZhbHVlLlxuICAgICAqIEBwYXJhbSBpblZhbHVlIFRoZSBuZXcgdmFsdWUgZm9yIHRoZSBzZXR0aW5nLlxuICAgICAqL1xuICAgIHB1YmxpYyBzZXQgdmFsdWUoaW5WYWx1ZTogdW5rbm93bikge1xuICAgICAgICB0aGlzLl92YWx1ZSA9IGluVmFsdWU7XG4gICAgICAgIHRoaXMub25DaGFuZ2UodGhpcy5fdmFsdWUsIHRoaXMpO1xuICAgICAgICB0aGlzLm9uQ2hhbmdlRW1pdCh0aGlzLl92YWx1ZSk7XG4gICAgfVxufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuaW1wb3J0IHR5cGUgeyBGbGFnc0lkcyB9IGZyb20gJy4vQ29uZmlnJztcbmltcG9ydCB7IFNldHRpbmdCYXNlIH0gZnJvbSAnLi9TZXR0aW5nQmFzZSc7XG5cbi8qKlxuICogQSBib29sZWFuIGZsYWcgc2V0dGluZyBvYmplY3Qgd2l0aCBhIHRleHQgbGFiZWwuXG4gKi9cbmV4cG9ydCBjbGFzcyBTZXR0aW5nRmxhZzxcbiAgICBDdXN0b21JZHMgZXh0ZW5kcyBzdHJpbmcgPSBGbGFnc0lkc1xuPiBleHRlbmRzIFNldHRpbmdCYXNlIHtcbiAgICBpZDogRmxhZ3NJZHMgfCBDdXN0b21JZHM7XG4gICAgb25DaGFuZ2VFbWl0OiAoY2hhbmdlZFZhbHVlOiBib29sZWFuKSA9PiB2b2lkO1xuICAgIHVzZVVybFBhcmFtczogYm9vbGVhbjtcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBpZDogRmxhZ3NJZHMgfCBDdXN0b21JZHMsXG4gICAgICAgIGxhYmVsOiBzdHJpbmcsXG4gICAgICAgIGRlc2NyaXB0aW9uOiBzdHJpbmcsXG4gICAgICAgIGRlZmF1bHRGbGFnVmFsdWU6IGJvb2xlYW4sXG4gICAgICAgIHVzZVVybFBhcmFtczogYm9vbGVhbixcblx0XHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWVtcHR5LWZ1bmN0aW9uXG5cdFx0ZGVmYXVsdE9uQ2hhbmdlTGlzdGVuZXI6IChjaGFuZ2VkVmFsdWU6IHVua25vd24sIHNldHRpbmc6IFNldHRpbmdCYXNlKSA9PiB2b2lkID0gKCkgPT4geyAvKiBEbyBub3RoaW5nLCB0byBiZSBvdmVycmlkZGVuLiAqLyB9XG4gICAgKSB7XG4gICAgICAgIHN1cGVyKGlkLCBsYWJlbCwgZGVzY3JpcHRpb24sIGRlZmF1bHRGbGFnVmFsdWUsIGRlZmF1bHRPbkNoYW5nZUxpc3RlbmVyKTtcblxuICAgICAgICBjb25zdCB1cmxQYXJhbXMgPSBuZXcgVVJMU2VhcmNoUGFyYW1zKHdpbmRvdy5sb2NhdGlvbi5zZWFyY2gpO1xuICAgICAgICBpZiAoIXVzZVVybFBhcmFtcyB8fCAhdXJsUGFyYW1zLmhhcyh0aGlzLmlkKSkge1xuICAgICAgICAgICAgdGhpcy5mbGFnID0gZGVmYXVsdEZsYWdWYWx1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIHBhcnNlIGZsYWcgZnJvbSB1cmwgcGFyYW1ldGVyc1xuICAgICAgICAgICAgY29uc3QgdXJsUGFyYW1GbGFnID0gdGhpcy5nZXRVcmxQYXJhbUZsYWcoKTtcbiAgICAgICAgICAgIHRoaXMuZmxhZyA9IHVybFBhcmFtRmxhZztcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnVzZVVybFBhcmFtcyA9IHVzZVVybFBhcmFtcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQYXJzZSB0aGUgZmxhZyB2YWx1ZSBmcm9tIHRoZSB1cmwgcGFyYW1ldGVycy5cbiAgICAgKiBAcmV0dXJucyBUcnVlIGlmIHRoZSB1cmwgcGFyYW1ldGVycyBjb250YWlucyAvP2lkLCBidXQgRmFsc2UgaWYgLz9pZD1mYWxzZVxuICAgICAqL1xuICAgIGdldFVybFBhcmFtRmxhZygpOiBib29sZWFuIHtcbiAgICAgICAgY29uc3QgdXJsUGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh3aW5kb3cubG9jYXRpb24uc2VhcmNoKTtcbiAgICAgICAgaWYgKHVybFBhcmFtcy5oYXModGhpcy5pZCkpIHtcbiAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICB1cmxQYXJhbXMuZ2V0KHRoaXMuaWQpID09PSAnZmFsc2UnIHx8XG4gICAgICAgICAgICAgICAgdXJsUGFyYW1zLmdldCh0aGlzLmlkKSA9PT0gJ0ZhbHNlJ1xuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFBlcnNpc3QgdGhlIHNldHRpbmcgdmFsdWUgaW4gVVJMLlxuICAgICAqL1xuICAgIHB1YmxpYyB1cGRhdGVVUkxQYXJhbXMoKSB7XG4gICAgICAgIGlmICh0aGlzLnVzZVVybFBhcmFtcykge1xuICAgICAgICAgICAgLy8gc2V0IHVybCBwYXJhbXNcbiAgICAgICAgICAgIGNvbnN0IHVybFBhcmFtcyA9IG5ldyBVUkxTZWFyY2hQYXJhbXMod2luZG93LmxvY2F0aW9uLnNlYXJjaCk7XG4gICAgICAgICAgICBpZiAodGhpcy5mbGFnID09PSB0cnVlKSB7XG4gICAgICAgICAgICAgICAgdXJsUGFyYW1zLnNldCh0aGlzLmlkLCAndHJ1ZScpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB1cmxQYXJhbXMuc2V0KHRoaXMuaWQsICdmYWxzZScpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgd2luZG93Lmhpc3RvcnkucmVwbGFjZVN0YXRlKFxuICAgICAgICAgICAgICAgIHt9LFxuICAgICAgICAgICAgICAgICcnLFxuICAgICAgICAgICAgICAgIHVybFBhcmFtcy50b1N0cmluZygpICE9PSAnJ1xuICAgICAgICAgICAgICAgICAgICA/IGAke2xvY2F0aW9uLnBhdGhuYW1lfT8ke3VybFBhcmFtc31gXG4gICAgICAgICAgICAgICAgICAgIDogYCR7bG9jYXRpb24ucGF0aG5hbWV9YFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEVuYWJsZXMgdGhpcyBmbGFnLlxuICAgICAqL1xuICAgIHB1YmxpYyBlbmFibGUoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuZmxhZyA9IHRydWU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHJldHVybiBUaGUgc2V0dGluZydzIHZhbHVlLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgZmxhZygpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuICEhdGhpcy52YWx1ZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBVcGRhdGUgdGhlIHNldHRpbmcncyBzdG9yZWQgdmFsdWUuXG4gICAgICogQHBhcmFtIGluVmFsdWUgVGhlIG5ldyB2YWx1ZSBmb3IgdGhlIHNldHRpbmcuXG4gICAgICovXG4gICAgcHVibGljIHNldCBmbGFnKGluVmFsdWU6IGJvb2xlYW4pIHtcbiAgICAgICAgdGhpcy52YWx1ZSA9IGluVmFsdWU7XG4gICAgfVxufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuaW1wb3J0IHR5cGUgeyBOdW1lcmljUGFyYW1ldGVyc0lkcyB9IGZyb20gJy4vQ29uZmlnJztcbmltcG9ydCB7IFNldHRpbmdCYXNlIH0gZnJvbSAnLi9TZXR0aW5nQmFzZSc7XG5cbi8qKlxuICogQSBudW1iZXIgc2V0dGluZyBvYmplY3Qgd2l0aCBhIHRleHQgbGFiZWwuIE1pbiBhbmQgbWF4IGxpbWl0IHRoZSByYW5nZSBvZiBhbGxvd2VkIHZhbHVlcy5cbiAqL1xuZXhwb3J0IGNsYXNzIFNldHRpbmdOdW1iZXI8XG4gICAgQ3VzdG9tSWRzIGV4dGVuZHMgc3RyaW5nID0gTnVtZXJpY1BhcmFtZXRlcnNJZHNcbj4gZXh0ZW5kcyBTZXR0aW5nQmFzZSB7XG4gICAgX21pbjogbnVtYmVyO1xuICAgIF9tYXg6IG51bWJlcjtcblxuICAgIGlkOiBOdW1lcmljUGFyYW1ldGVyc0lkcyB8IEN1c3RvbUlkcztcbiAgICBvbkNoYW5nZUVtaXQ6IChjaGFuZ2VkVmFsdWU6IG51bWJlcikgPT4gdm9pZDtcbiAgICB1c2VVcmxQYXJhbXM6IGJvb2xlYW47XG5cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgaWQ6IE51bWVyaWNQYXJhbWV0ZXJzSWRzIHwgQ3VzdG9tSWRzLFxuICAgICAgICBsYWJlbDogc3RyaW5nLFxuICAgICAgICBkZXNjcmlwdGlvbjogc3RyaW5nLFxuICAgICAgICBtaW46IG51bWJlcixcbiAgICAgICAgbWF4OiBudW1iZXIsXG4gICAgICAgIGRlZmF1bHROdW1iZXI6IG51bWJlcixcbiAgICAgICAgdXNlVXJsUGFyYW1zOiBib29sZWFuLFxuXHRcdC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZW1wdHktZnVuY3Rpb25cblx0XHRkZWZhdWx0T25DaGFuZ2VMaXN0ZW5lcjogKGNoYW5nZWRWYWx1ZTogdW5rbm93biwgc2V0dGluZzogU2V0dGluZ0Jhc2UpID0+IHZvaWQgPSAoKSA9PiB7IC8qIERvIG5vdGhpbmcsIHRvIGJlIG92ZXJyaWRkZW4uICovIH1cbiAgICApIHtcbiAgICAgICAgc3VwZXIoaWQsIGxhYmVsLCBkZXNjcmlwdGlvbiwgZGVmYXVsdE51bWJlciwgZGVmYXVsdE9uQ2hhbmdlTGlzdGVuZXIpO1xuXG4gICAgICAgIHRoaXMuX21pbiA9IG1pbjtcbiAgICAgICAgdGhpcy5fbWF4ID0gbWF4O1xuXG4gICAgICAgIC8vIGF0dGVtcHQgdG8gcmVhZCB0aGUgbnVtYmVyIGZyb20gdGhlIHVybCBwYXJhbXNcbiAgICAgICAgY29uc3QgdXJsUGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh3aW5kb3cubG9jYXRpb24uc2VhcmNoKTtcbiAgICAgICAgaWYgKCF1c2VVcmxQYXJhbXMgfHwgIXVybFBhcmFtcy5oYXModGhpcy5pZCkpIHtcbiAgICAgICAgICAgIHRoaXMubnVtYmVyID0gZGVmYXVsdE51bWJlcjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IHBhcnNlZFZhbHVlID0gTnVtYmVyLnBhcnNlSW50KHVybFBhcmFtcy5nZXQodGhpcy5pZCkpO1xuICAgICAgICAgICAgdGhpcy5udW1iZXIgPSBOdW1iZXIuaXNOYU4ocGFyc2VkVmFsdWUpXG4gICAgICAgICAgICAgICAgPyBkZWZhdWx0TnVtYmVyXG4gICAgICAgICAgICAgICAgOiBwYXJzZWRWYWx1ZTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnVzZVVybFBhcmFtcyA9IHVzZVVybFBhcmFtcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQZXJzaXN0IHRoZSBzZXR0aW5nIHZhbHVlIGluIFVSTC5cbiAgICAgKi9cbiAgICBwdWJsaWMgdXBkYXRlVVJMUGFyYW1zKCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy51c2VVcmxQYXJhbXMpIHtcbiAgICAgICAgICAgIC8vIHNldCB1cmwgcGFyYW1zIGxpa2UgP2lkPW51bWJlclxuICAgICAgICAgICAgY29uc3QgdXJsUGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh3aW5kb3cubG9jYXRpb24uc2VhcmNoKTtcbiAgICAgICAgICAgIHVybFBhcmFtcy5zZXQodGhpcy5pZCwgdGhpcy5udW1iZXIudG9TdHJpbmcoKSk7XG4gICAgICAgICAgICB3aW5kb3cuaGlzdG9yeS5yZXBsYWNlU3RhdGUoXG4gICAgICAgICAgICAgICAge30sXG4gICAgICAgICAgICAgICAgJycsXG4gICAgICAgICAgICAgICAgdXJsUGFyYW1zLnRvU3RyaW5nKCkgIT09ICcnXG4gICAgICAgICAgICAgICAgICAgID8gYCR7bG9jYXRpb24ucGF0aG5hbWV9PyR7dXJsUGFyYW1zfWBcbiAgICAgICAgICAgICAgICAgICAgOiBgJHtsb2NhdGlvbi5wYXRobmFtZX1gXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0IHRoZSBudW1iZXIgdmFsdWUgKHdpbGwgYmUgY2xhbXBlZCB3aXRoaW4gcmFuZ2UpLlxuICAgICAqL1xuICAgIHB1YmxpYyBzZXQgbnVtYmVyKG5ld051bWJlcjogbnVtYmVyKSB7XG4gICAgICAgIHRoaXMudmFsdWUgPSB0aGlzLmNsYW1wKG5ld051bWJlcik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHJldHVybnMgVGhlIG51bWJlciBzdG9yZWQuXG4gICAgICovXG4gICAgcHVibGljIGdldCBudW1iZXIoKTogbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWUgYXMgbnVtYmVyO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENsYW1wcyBhIG51bWJlciBiZXR3ZWVuIHRoZSBtaW4gYW5kIG1heCB2YWx1ZXMgKGluY2x1c2l2ZSkuXG4gICAgICogQHBhcmFtIGluTnVtYmVyIFRoZSBudW1iZXIgdG8gY2xhbXAuXG4gICAgICogQHJldHVybnMgVGhlIGNsYW1wZWQgbnVtYmVyLlxuICAgICAqL1xuICAgIHB1YmxpYyBjbGFtcChpbk51bWJlcjogbnVtYmVyKTogbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIE1hdGgubWF4KE1hdGgubWluKHRoaXMuX21heCwgaW5OdW1iZXIpLCB0aGlzLl9taW4pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIG1pbmltdW0gdmFsdWVcbiAgICAgKiBAcmV0dXJucyBUaGUgbWluaW11bSB2YWx1ZVxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgbWluKCk6IG51bWJlciB7XG4gICAgICAgIHJldHVybiB0aGlzLl9taW47XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgbWF4aW11bSB2YWx1ZVxuICAgICAqIEByZXR1cm5zIFRoZSBtYXhpbXVtIHZhbHVlXG4gICAgICovXG4gICAgcHVibGljIGdldCBtYXgoKTogbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX21heDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBZGQgYSBjaGFuZ2UgbGlzdGVuZXIgdG8gdGhlIG51bWJlciBvYmplY3QuXG4gICAgICovXG4gICAgcHVibGljIGFkZE9uQ2hhbmdlZExpc3RlbmVyKG9uQ2hhbmdlZEZ1bmM6IChuZXdOdW1iZXI6IG51bWJlcikgPT4gdm9pZCkge1xuICAgICAgICB0aGlzLm9uQ2hhbmdlID0gb25DaGFuZ2VkRnVuYztcbiAgICB9XG59XG4iLCIvLyBDb3B5cmlnaHQgRXBpYyBHYW1lcywgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuXG5pbXBvcnQgdHlwZSB7IE9wdGlvblBhcmFtZXRlcnNJZHMgfSBmcm9tICcuL0NvbmZpZyc7XG5pbXBvcnQgeyBTZXR0aW5nQmFzZSB9IGZyb20gJy4vU2V0dGluZ0Jhc2UnO1xuXG4vKipcbiAqIEFuIE9wdGlvbiBzZXR0aW5nIG9iamVjdCB3aXRoIGEgdGV4dCBsYWJlbC4gQWxsb3dzIHlvdSB0byBzcGVjaWZ5IGFuIGFycmF5IG9mIG9wdGlvbnMgYW5kIHNlbGVjdCBvbmUgb2YgdGhlbS5cbiAqL1xuZXhwb3J0IGNsYXNzIFNldHRpbmdPcHRpb248XG4gICAgQ3VzdG9tSWRzIGV4dGVuZHMgc3RyaW5nID0gT3B0aW9uUGFyYW1ldGVyc0lkc1xuPiBleHRlbmRzIFNldHRpbmdCYXNlIHtcbiAgICBpZDogT3B0aW9uUGFyYW1ldGVyc0lkcyB8IEN1c3RvbUlkcztcbiAgICBvbkNoYW5nZUVtaXQ6IChjaGFuZ2VkVmFsdWU6IHN0cmluZykgPT4gdm9pZDtcbiAgICBfb3B0aW9uczogQXJyYXk8c3RyaW5nPjtcbiAgICB1c2VVcmxQYXJhbXM6IGJvb2xlYW47XG5cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgaWQ6IE9wdGlvblBhcmFtZXRlcnNJZHMgfCBDdXN0b21JZHMsXG4gICAgICAgIGxhYmVsOiBzdHJpbmcsXG4gICAgICAgIGRlc2NyaXB0aW9uOiBzdHJpbmcsXG4gICAgICAgIGRlZmF1bHRUZXh0VmFsdWU6IHN0cmluZyxcbiAgICAgICAgb3B0aW9uczogQXJyYXk8c3RyaW5nPixcbiAgICAgICAgdXNlVXJsUGFyYW1zOiBib29sZWFuLFxuXHRcdC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZW1wdHktZnVuY3Rpb25cblx0XHRkZWZhdWx0T25DaGFuZ2VMaXN0ZW5lcjogKGNoYW5nZWRWYWx1ZTogdW5rbm93biwgc2V0dGluZzogU2V0dGluZ0Jhc2UpID0+IHZvaWQgPSAoKSA9PiB7IC8qIERvIG5vdGhpbmcsIHRvIGJlIG92ZXJyaWRkZW4uICovIH1cbiAgICApIHtcbiAgICAgICAgc3VwZXIoaWQsIGxhYmVsLCBkZXNjcmlwdGlvbiwgW2RlZmF1bHRUZXh0VmFsdWUsIGRlZmF1bHRUZXh0VmFsdWVdLCBkZWZhdWx0T25DaGFuZ2VMaXN0ZW5lcik7XG5cbiAgICAgICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcbiAgICAgICAgY29uc3QgdXJsUGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh3aW5kb3cubG9jYXRpb24uc2VhcmNoKTtcbiAgICAgICAgY29uc3Qgc3RyaW5nVG9NYXRjaDogc3RyaW5nID1cbiAgICAgICAgICAgIHVzZVVybFBhcmFtcyAmJiB1cmxQYXJhbXMuaGFzKHRoaXMuaWQpXG4gICAgICAgICAgICAgICAgPyB0aGlzLmdldFVybFBhcmFtVGV4dCgpXG4gICAgICAgICAgICAgICAgOiBkZWZhdWx0VGV4dFZhbHVlO1xuICAgICAgICB0aGlzLnNlbGVjdGVkID0gc3RyaW5nVG9NYXRjaDtcbiAgICAgICAgdGhpcy51c2VVcmxQYXJhbXMgPSB1c2VVcmxQYXJhbXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUGFyc2UgdGhlIHRleHQgdmFsdWUgZnJvbSB0aGUgdXJsIHBhcmFtZXRlcnMuXG4gICAgICogQHJldHVybnMgVGhlIHRleHQgdmFsdWUgcGFyc2VkIGZyb20gdGhlIHVybCBpZiB0aGUgdXJsIHBhcmFtZXRlcnMgY29udGFpbnMgLz9pZD12YWx1ZSwgYnV0IGVtcHR5IHN0cmluZyBpZiBqdXN0IC8/aWQgb3Igbm8gdXJsIHBhcmFtIGZvdW5kLlxuICAgICAqL1xuICAgIGdldFVybFBhcmFtVGV4dCgpOiBzdHJpbmcge1xuICAgICAgICBjb25zdCB1cmxQYXJhbXMgPSBuZXcgVVJMU2VhcmNoUGFyYW1zKHdpbmRvdy5sb2NhdGlvbi5zZWFyY2gpO1xuICAgICAgICBpZiAodXJsUGFyYW1zLmhhcyh0aGlzLmlkKSkge1xuICAgICAgICAgICAgcmV0dXJuIHVybFBhcmFtcy5nZXQodGhpcy5pZCkgPz8gJyc7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICcnO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFBlcnNpc3QgdGhlIHNldHRpbmcgdmFsdWUgaW4gVVJMLlxuICAgICAqL1xuICAgIHB1YmxpYyB1cGRhdGVVUkxQYXJhbXMoKSB7XG4gICAgICAgIGlmICh0aGlzLnVzZVVybFBhcmFtcykge1xuICAgICAgICAgICAgLy8gc2V0IHVybCBwYXJhbXNcbiAgICAgICAgICAgIGNvbnN0IHVybFBhcmFtcyA9IG5ldyBVUkxTZWFyY2hQYXJhbXMod2luZG93LmxvY2F0aW9uLnNlYXJjaCk7XG4gICAgICAgICAgICB1cmxQYXJhbXMuc2V0KHRoaXMuaWQsIHRoaXMuc2VsZWN0ZWQpO1xuICAgICAgICAgICAgd2luZG93Lmhpc3RvcnkucmVwbGFjZVN0YXRlKFxuICAgICAgICAgICAgICAgIHt9LFxuICAgICAgICAgICAgICAgICcnLFxuICAgICAgICAgICAgICAgIHVybFBhcmFtcy50b1N0cmluZygpICE9PSAnJ1xuICAgICAgICAgICAgICAgICAgICA/IGAke2xvY2F0aW9uLnBhdGhuYW1lfT8ke3VybFBhcmFtc31gXG4gICAgICAgICAgICAgICAgICAgIDogYCR7bG9jYXRpb24ucGF0aG5hbWV9YFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFkZCBhIGNoYW5nZSBsaXN0ZW5lciB0byB0aGUgc2VsZWN0IGVsZW1lbnQuXG4gICAgICovXG4gICAgcHVibGljIGFkZE9uQ2hhbmdlZExpc3RlbmVyKG9uQ2hhbmdlZEZ1bmM6IChuZXdWYWx1ZTogc3RyaW5nKSA9PiB2b2lkKSB7XG4gICAgICAgIHRoaXMub25DaGFuZ2UgPSBvbkNoYW5nZWRGdW5jO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEByZXR1cm5zIEFsbCBhdmFpbGFibGUgb3B0aW9ucyBhcyBhbiBhcnJheVxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgb3B0aW9ucygpOiBBcnJheTxzdHJpbmc+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX29wdGlvbnM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0IG9wdGlvbnNcbiAgICAgKiBAcGFyYW0gdmFsdWVzIEFycmF5IG9mIG9wdGlvbnNcbiAgICAgKi9cbiAgICBwdWJsaWMgc2V0IG9wdGlvbnModmFsdWVzOiBBcnJheTxzdHJpbmc+KSB7XG4gICAgICAgIHRoaXMuX29wdGlvbnMgPSB2YWx1ZXM7XG4gICAgICAgIHRoaXMub25DaGFuZ2VFbWl0KHRoaXMuc2VsZWN0ZWQpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEByZXR1cm5zIFNlbGVjdGVkIG9wdGlvbiBhcyBhIHN0cmluZ1xuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgc2VsZWN0ZWQoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWUgYXMgc3RyaW5nO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCBzZWxlY3RlZCBvcHRpb24gaWYgaXQgbWF0Y2hlcyBvbmUgb2YgdGhlIGF2YWlsYWJsZSBvcHRpb25zXG4gICAgICogQHBhcmFtIHZhbHVlIFNlbGVjdGVkIG9wdGlvblxuICAgICAqL1xuICAgIHB1YmxpYyBzZXQgc2VsZWN0ZWQodmFsdWU6IHN0cmluZykge1xuICAgICAgICAvLyBBIHVzZXIgbWF5IG5vdCBzcGVjaWZ5IHRoZSBmdWxsIHBvc3NpYmxlIHZhbHVlIHNvIHdlIGluc3RlYWQgdXNlIHRoZSBjbG9zZXN0IG1hdGNoLlxuICAgICAgICAvLyBlZyA/eHh4PUgyNjQgd291bGQgc2VsZWN0ICdIMjY0IGxldmVsLWFzeW1tZXRyeS1hbGxvd2VkPTE7cGFja2V0aXphdGlvbi1tb2RlPTE7cHJvZmlsZS1sZXZlbC1pZD00MjAwMWYnXG4gICAgICAgIGxldCBmaWx0ZXJlZExpc3QgPSB0aGlzLm9wdGlvbnMuZmlsdGVyKFxuICAgICAgICAgICAgKG9wdGlvbjogc3RyaW5nKSA9PiBvcHRpb24uaW5kZXhPZih2YWx1ZSkgIT09IC0xXG4gICAgICAgICk7XG4gICAgICAgIGlmIChmaWx0ZXJlZExpc3QubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGlzLnZhbHVlID0gZmlsdGVyZWRMaXN0WzBdO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9IFxuXG4gICAgICAgIC8vIEEgdXNlciBoYXMgc3BlY2lmaWVkIGEgY29kZWMgd2l0aCBhIGZtdHAgc3RyaW5nIGJ1dCB0aGlzIGNvZGVjICsgZm10cCBsaW5lIGlzbid0IGF2YWlsYWJsZS5cbiAgICAgICAgLy8gaW4gdGhhdCBjYXNlLCBqdXN0IHVzZSB0aGUgY29kZWNcbiAgICAgICAgZmlsdGVyZWRMaXN0ID0gdGhpcy5vcHRpb25zLmZpbHRlcihcbiAgICAgICAgICAgIChvcHRpb246IHN0cmluZykgPT4gb3B0aW9uLmluZGV4T2YodmFsdWUuc3BsaXQoJyAnKVswXSkgIT09IC0xXG4gICAgICAgICk7XG4gICAgICAgIGlmIChmaWx0ZXJlZExpc3QubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGlzLnZhbHVlID0gZmlsdGVyZWRMaXN0WzBdO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgfVxufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuaW1wb3J0IHR5cGUgeyBUZXh0UGFyYW1ldGVyc0lkcyB9IGZyb20gJy4vQ29uZmlnJztcbmltcG9ydCB7IFNldHRpbmdCYXNlIH0gZnJvbSAnLi9TZXR0aW5nQmFzZSc7XG5cbi8qKlxuICogQSB0ZXh0IHNldHRpbmcgb2JqZWN0IHdpdGggYSB0ZXh0IGxhYmVsLlxuICovXG5leHBvcnQgY2xhc3MgU2V0dGluZ1RleHQ8XG4gICAgQ3VzdG9tSWRzIGV4dGVuZHMgc3RyaW5nID0gVGV4dFBhcmFtZXRlcnNJZHNcbj4gZXh0ZW5kcyBTZXR0aW5nQmFzZSB7XG4gICAgaWQ6IFRleHRQYXJhbWV0ZXJzSWRzIHwgQ3VzdG9tSWRzO1xuICAgIG9uQ2hhbmdlRW1pdDogKGNoYW5nZWRWYWx1ZTogc3RyaW5nKSA9PiB2b2lkO1xuICAgIHVzZVVybFBhcmFtczogYm9vbGVhbjtcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBpZDogVGV4dFBhcmFtZXRlcnNJZHMgfCBDdXN0b21JZHMsXG4gICAgICAgIGxhYmVsOiBzdHJpbmcsXG4gICAgICAgIGRlc2NyaXB0aW9uOiBzdHJpbmcsXG4gICAgICAgIGRlZmF1bHRUZXh0VmFsdWU6IHN0cmluZyxcbiAgICAgICAgdXNlVXJsUGFyYW1zOiBib29sZWFuLFxuXHRcdC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZW1wdHktZnVuY3Rpb25cblx0XHRkZWZhdWx0T25DaGFuZ2VMaXN0ZW5lcjogKGNoYW5nZWRWYWx1ZTogdW5rbm93biwgc2V0dGluZzogU2V0dGluZ0Jhc2UpID0+IHZvaWQgPSAoKSA9PiB7IC8qIERvIG5vdGhpbmcsIHRvIGJlIG92ZXJyaWRkZW4uICovIH1cbiAgICApIHtcbiAgICAgICAgc3VwZXIoaWQsIGxhYmVsLCBkZXNjcmlwdGlvbiwgZGVmYXVsdFRleHRWYWx1ZSwgZGVmYXVsdE9uQ2hhbmdlTGlzdGVuZXIpO1xuXG4gICAgICAgIGNvbnN0IHVybFBhcmFtcyA9IG5ldyBVUkxTZWFyY2hQYXJhbXMod2luZG93LmxvY2F0aW9uLnNlYXJjaCk7XG4gICAgICAgIGlmICghdXNlVXJsUGFyYW1zIHx8ICF1cmxQYXJhbXMuaGFzKHRoaXMuaWQpKSB7XG4gICAgICAgICAgICB0aGlzLnRleHQgPSBkZWZhdWx0VGV4dFZhbHVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gcGFyc2UgZmxhZyBmcm9tIHVybCBwYXJhbWV0ZXJzXG4gICAgICAgICAgICBjb25zdCB1cmxQYXJhbUZsYWcgPSB0aGlzLmdldFVybFBhcmFtVGV4dCgpO1xuICAgICAgICAgICAgdGhpcy50ZXh0ID0gdXJsUGFyYW1GbGFnO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMudXNlVXJsUGFyYW1zID0gdXNlVXJsUGFyYW1zO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFBhcnNlIHRoZSB0ZXh0IHZhbHVlIGZyb20gdGhlIHVybCBwYXJhbWV0ZXJzLlxuICAgICAqIEByZXR1cm5zIFRoZSB0ZXh0IHZhbHVlIHBhcnNlZCBmcm9tIHRoZSB1cmwgaWYgdGhlIHVybCBwYXJhbWV0ZXJzIGNvbnRhaW5zIC8/aWQ9dmFsdWUsIGJ1dCBlbXB0eSBzdHJpbmcgaWYganVzdCAvP2lkIG9yIG5vIHVybCBwYXJhbSBmb3VuZC5cbiAgICAgKi9cbiAgICBnZXRVcmxQYXJhbVRleHQoKTogc3RyaW5nIHtcbiAgICAgICAgY29uc3QgdXJsUGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh3aW5kb3cubG9jYXRpb24uc2VhcmNoKTtcbiAgICAgICAgaWYgKHVybFBhcmFtcy5oYXModGhpcy5pZCkpIHtcbiAgICAgICAgICAgIHJldHVybiB1cmxQYXJhbXMuZ2V0KHRoaXMuaWQpID8/ICcnO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiAnJztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQZXJzaXN0IHRoZSBzZXR0aW5nIHZhbHVlIGluIFVSTC5cbiAgICAgKi9cbiAgICBwdWJsaWMgdXBkYXRlVVJMUGFyYW1zKCkge1xuICAgICAgICBpZiAodGhpcy51c2VVcmxQYXJhbXMpIHtcbiAgICAgICAgICAgIC8vIHNldCB1cmwgcGFyYW1zXG4gICAgICAgICAgICBjb25zdCB1cmxQYXJhbXMgPSBuZXcgVVJMU2VhcmNoUGFyYW1zKHdpbmRvdy5sb2NhdGlvbi5zZWFyY2gpO1xuICAgICAgICAgICAgdXJsUGFyYW1zLnNldCh0aGlzLmlkLCB0aGlzLnRleHQpO1xuICAgICAgICAgICAgd2luZG93Lmhpc3RvcnkucmVwbGFjZVN0YXRlKFxuICAgICAgICAgICAgICAgIHt9LFxuICAgICAgICAgICAgICAgICcnLFxuICAgICAgICAgICAgICAgIHVybFBhcmFtcy50b1N0cmluZygpICE9PSAnJ1xuICAgICAgICAgICAgICAgICAgICA/IGAke2xvY2F0aW9uLnBhdGhuYW1lfT8ke3VybFBhcmFtc31gXG4gICAgICAgICAgICAgICAgICAgIDogYCR7bG9jYXRpb24ucGF0aG5hbWV9YFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEByZXR1cm4gVGhlIHNldHRpbmcncyB2YWx1ZS5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IHRleHQoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudmFsdWUgYXMgc3RyaW5nO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFVwZGF0ZSB0aGUgc2V0dGluZydzIHN0b3JlZCB2YWx1ZS5cbiAgICAgKiBAcGFyYW0gaW5WYWx1ZSBUaGUgbmV3IHZhbHVlIGZvciB0aGUgc2V0dGluZy5cbiAgICAgKi9cbiAgICBwdWJsaWMgc2V0IHRleHQoaW5WYWx1ZTogc3RyaW5nKSB7XG4gICAgICAgIHRoaXMudmFsdWUgPSBpblZhbHVlO1xuICAgIH1cbn1cbiIsIi8vIENvcHlyaWdodCBFcGljIEdhbWVzLCBJbmMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG5cbmltcG9ydCB7IExvZ2dlciB9IGZyb20gJy4uL0xvZ2dlci9Mb2dnZXInO1xuXG4vKipcbiAqIEhhbmRsZXMgdGhlIFNlbmRpbmcgYW5kIFJlY2VpdmluZyBvZiBtZXNzYWdlcyB0byB0aGUgVUUgSW5zdGFuY2UgdmlhIHRoZSBEYXRhIENoYW5uZWxcbiAqL1xuZXhwb3J0IGNsYXNzIERhdGFDaGFubmVsQ29udHJvbGxlciB7XG4gICAgZGF0YUNoYW5uZWw6IFJUQ0RhdGFDaGFubmVsO1xuICAgIHBlZXJDb25uZWN0aW9uOiBSVENQZWVyQ29ubmVjdGlvbjtcbiAgICBkYXRhY2hhbm5lbE9wdGlvbnM6IFJUQ0RhdGFDaGFubmVsSW5pdDtcbiAgICBsYWJlbDogc3RyaW5nO1xuICAgIGlzUmVjZWl2aW5nRnJlZXplRnJhbWUgPSBmYWxzZTtcblxuICAgIC8qKlxuICAgICAqIHJldHVybiB0aGUgY3VycmVudCBzdGF0ZSBvZiBhIGRhdGFjaGFubmVsIGNvbnRyb2xsZXIgaW5zdGFuY2VcbiAgICAgKiBAcmV0dXJucyB0aGUgY3VycmVudCBEYXRhQ2hhbm5lbENvbnRyb2xsZXIgaW5zdGFuY2VcbiAgICAgKi9cbiAgICBnZXREYXRhQ2hhbm5lbEluc3RhbmNlKCk6IERhdGFDaGFubmVsQ29udHJvbGxlciB7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRvIENyZWF0ZSBhbmQgU2V0IHVwIGEgRGF0YSBDaGFubmVsXG4gICAgICogQHBhcmFtIHBlZXJDb25uZWN0aW9uIC0gVGhlIFJUQyBQZWVyIENvbm5lY3Rpb25cbiAgICAgKiBAcGFyYW0gbGFiZWwgLSBMYWJlbCBvZiB0aGUgRGF0YSBDaGFubmVsXG4gICAgICogQHBhcmFtIGRhdGFjaGFubmVsT3B0aW9ucyAtIE9wdGlvbmFsIFJUQyBEYXRhQ2hhbm5lbCBvcHRpb25zXG4gICAgICovXG4gICAgY3JlYXRlRGF0YUNoYW5uZWwoXG4gICAgICAgIHBlZXJDb25uZWN0aW9uOiBSVENQZWVyQ29ubmVjdGlvbixcbiAgICAgICAgbGFiZWw6IHN0cmluZyxcbiAgICAgICAgZGF0YWNoYW5uZWxPcHRpb25zPzogUlRDRGF0YUNoYW5uZWxJbml0XG4gICAgKSB7XG4gICAgICAgIHRoaXMucGVlckNvbm5lY3Rpb24gPSBwZWVyQ29ubmVjdGlvbjtcbiAgICAgICAgdGhpcy5sYWJlbCA9IGxhYmVsO1xuICAgICAgICB0aGlzLmRhdGFjaGFubmVsT3B0aW9ucyA9IGRhdGFjaGFubmVsT3B0aW9ucztcbiAgICAgICAgaWYgKGRhdGFjaGFubmVsT3B0aW9ucyA9PSBudWxsKSB7XG4gICAgICAgICAgICB0aGlzLmRhdGFjaGFubmVsT3B0aW9ucyA9IHt9IGFzIFJUQ0RhdGFDaGFubmVsSW5pdDtcbiAgICAgICAgICAgIHRoaXMuZGF0YWNoYW5uZWxPcHRpb25zLm9yZGVyZWQgPSB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5kYXRhQ2hhbm5lbCA9IHRoaXMucGVlckNvbm5lY3Rpb24uY3JlYXRlRGF0YUNoYW5uZWwoXG4gICAgICAgICAgICB0aGlzLmxhYmVsLFxuICAgICAgICAgICAgdGhpcy5kYXRhY2hhbm5lbE9wdGlvbnNcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5zZXR1cERhdGFDaGFubmVsKCk7XG4gICAgfVxuXG4gICAgc2V0dXBEYXRhQ2hhbm5lbCgpIHtcbiAgICAgICAgLy9XZSBXYW50IGFuIEFycmF5IEJ1ZmZlciBub3QgYSBibG9iXG4gICAgICAgIHRoaXMuZGF0YUNoYW5uZWwuYmluYXJ5VHlwZSA9ICdhcnJheWJ1ZmZlcic7XG4gICAgICAgIHRoaXMuZGF0YUNoYW5uZWwub25vcGVuID0gKGV2OiBFdmVudCkgPT4gdGhpcy5oYW5kbGVPbk9wZW4oZXYpO1xuICAgICAgICB0aGlzLmRhdGFDaGFubmVsLm9uY2xvc2UgPSAoZXY6IEV2ZW50KSA9PiB0aGlzLmhhbmRsZU9uQ2xvc2UoZXYpO1xuICAgICAgICB0aGlzLmRhdGFDaGFubmVsLm9ubWVzc2FnZSA9IChldjogTWVzc2FnZUV2ZW50KSA9PlxuICAgICAgICAgICAgdGhpcy5oYW5kbGVPbk1lc3NhZ2UoZXYpO1xuICAgICAgICB0aGlzLmRhdGFDaGFubmVsLm9uZXJyb3IgPSAoZXY6IE1lc3NhZ2VFdmVudCkgPT4gdGhpcy5oYW5kbGVPbkVycm9yKGV2KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGVzIHdoZW4gdGhlIERhdGEgQ2hhbm5lbCBpcyBvcGVuZWRcbiAgICAgKi9cbiAgICBoYW5kbGVPbk9wZW4oZXY6IEV2ZW50KSB7XG4gICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgYERhdGEgQ2hhbm5lbCAoJHt0aGlzLmxhYmVsfSkgb3BlbmVkLmAsXG4gICAgICAgICAgICA3XG4gICAgICAgICk7XG4gICAgICAgIHRoaXMub25PcGVuKHRoaXMuZGF0YUNoYW5uZWw/LmxhYmVsLCBldik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSGFuZGxlcyB3aGVuIHRoZSBEYXRhIENoYW5uZWwgaXMgY2xvc2VkXG4gICAgICovXG4gICAgaGFuZGxlT25DbG9zZShldjogRXZlbnQpIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICBgRGF0YSBDaGFubmVsICgke3RoaXMubGFiZWx9KSBjbG9zZWQuYCxcbiAgICAgICAgICAgIDdcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5vbkNsb3NlKHRoaXMuZGF0YUNoYW5uZWw/LmxhYmVsLCBldik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSGFuZGxlcyB3aGVuIGEgbWVzc2FnZSBpcyByZWNlaXZlZFxuICAgICAqIEBwYXJhbSBldmVudCAtIE1lc3NhZ2UgRXZlbnRcbiAgICAgKi9cbiAgICBoYW5kbGVPbk1lc3NhZ2UoZXZlbnQ6IE1lc3NhZ2VFdmVudCkge1xuICAgICAgICAvLyBIaWdoZXIgbG9nIGxldmVsIHRvIHByZXZlbnQgbG9nIHNwYW0gd2l0aCBtZXNzYWdlcyByZWNlaXZlZFxuICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgIGBEYXRhIENoYW5uZWwgKCR7dGhpcy5sYWJlbH0pIG1lc3NhZ2U6ICR7ZXZlbnR9YCxcbiAgICAgICAgICAgIDhcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGVzIHdoZW4gYW4gZXJyb3IgaXMgdGhyb3duXG4gICAgICogQHBhcmFtIGV2ZW50IC0gRXJyb3IgRXZlbnRcbiAgICAgKi9cbiAgICBoYW5kbGVPbkVycm9yKGV2ZW50OiBNZXNzYWdlRXZlbnQpIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICBgRGF0YSBDaGFubmVsICgke3RoaXMubGFiZWx9KSBlcnJvcjogJHtldmVudH1gLFxuICAgICAgICAgICAgN1xuICAgICAgICApO1xuICAgICAgICB0aGlzLm9uRXJyb3IodGhpcy5kYXRhQ2hhbm5lbD8ubGFiZWwsIGV2ZW50KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBPdmVycmlkZSB0byByZWdpc3RlciBvbk9wZW4gaGFuZGxlclxuICAgICAqIEBwYXJhbSBsYWJlbCBEYXRhIGNoYW5uZWwgbGFiZWwgKFwiZGF0YWNoYW5uZWxcIiwgXCJzZW5kLWRhdGFjaGFubmVsXCIsIFwicmVjdi1kYXRhY2hhbm5lbFwiKVxuICAgICAqIEBwYXJhbSBldiBldmVudFxuICAgICAqL1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICBvbk9wZW4obGFiZWw6IHN0cmluZywgZXY6IEV2ZW50KSB7XG4gICAgICAgIC8vIGVtcHR5IGRlZmF1bHQgaW1wbGVtZW50YXRpb25cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBPdmVycmlkZSB0byByZWdpc3RlciBvbkNsb3NlIGhhbmRsZXJcbiAgICAgKiBAcGFyYW0gbGFiZWwgRGF0YSBjaGFubmVsIGxhYmVsIChcImRhdGFjaGFubmVsXCIsIFwic2VuZC1kYXRhY2hhbm5lbFwiLCBcInJlY3YtZGF0YWNoYW5uZWxcIilcbiAgICAgKiBAcGFyYW0gZXYgZXZlbnRcbiAgICAgKi9cbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICAgb25DbG9zZShsYWJlbDogc3RyaW5nLCBldjogRXZlbnQpIHtcbiAgICAgICAgLy8gZW1wdHkgZGVmYXVsdCBpbXBsZW1lbnRhdGlvblxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIE92ZXJyaWRlIHRvIHJlZ2lzdGVyIG9uRXJyb3IgaGFuZGxlclxuICAgICAqIEBwYXJhbSBsYWJlbCBEYXRhIGNoYW5uZWwgbGFiZWwgKFwiZGF0YWNoYW5uZWxcIiwgXCJzZW5kLWRhdGFjaGFubmVsXCIsIFwicmVjdi1kYXRhY2hhbm5lbFwiKVxuICAgICAqIEBwYXJhbSBldiBldmVudFxuICAgICAqL1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICBvbkVycm9yKGxhYmVsOiBzdHJpbmcsIGV2OiBFdmVudCkge1xuICAgICAgICAvLyBlbXB0eSBkZWZhdWx0IGltcGxlbWVudGF0aW9uXG4gICAgfVxufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuaW1wb3J0IHsgTG9nZ2VyIH0gZnJvbSAnLi4vTG9nZ2VyL0xvZ2dlcic7XG5pbXBvcnQge1xuICAgIERhdGFDaGFubmVsTGF0ZW5jeVRlc3RSZWNvcmQsXG4gICAgRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFJlcXVlc3QsXG4gICAgRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFJlc3BvbnNlLFxuICAgIERhdGFDaGFubmVsTGF0ZW5jeVRlc3RSZXN1bHQsXG4gICAgRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFNlcSxcbiAgICBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0VGltZXN0YW1wXG59IGZyb20gXCIuL0RhdGFDaGFubmVsTGF0ZW5jeVRlc3RSZXN1bHRzXCI7XG5cbmV4cG9ydCB0eXBlIERhdGFDaGFubmVsTGF0ZW5jeVRlc3RDb25maWcgPSB7XG4gICAgLy8gdGVzdCBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHNcbiAgICBkdXJhdGlvbjogbnVtYmVyO1xuICAgIC8vcmVxdWVzdHMgcGVyIHNlY29uZFxuICAgIHJwczogbnVtYmVyO1xuICAgIC8vcmVxdWVzdCBmaWxsZXIgc2l6ZVxuICAgIHJlcXVlc3RTaXplOiBudW1iZXI7XG4gICAgLy9yZXNwb25zZSBmaWxsZXIgc2l6ZVxuICAgIHJlc3BvbnNlU2l6ZTogbnVtYmVyO1xufVxuXG5leHBvcnQgdHlwZSBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0U2luayA9IChyZXF1ZXN0OiBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVxdWVzdCkgPT4gdm9pZDtcbmV4cG9ydCB0eXBlIERhdGFDaGFubmVsTGF0ZW5jeVRlc3RSZXN1bHRDYWxsYmFjayA9IChyZXN1bHQ6IERhdGFDaGFubmVsTGF0ZW5jeVRlc3RSZXN1bHQpID0+IHZvaWQ7XG5cbmV4cG9ydCBjbGFzcyBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0Q29udHJvbGxlciB7XG4gICAgc3RhcnRUaW1lOiBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0VGltZXN0YW1wO1xuICAgIHNpbms6IERhdGFDaGFubmVsTGF0ZW5jeVRlc3RTaW5rO1xuICAgIGNhbGxiYWNrOiBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVzdWx0Q2FsbGJhY2s7XG4gICAgcmVjb3JkczogTWFwPERhdGFDaGFubmVsTGF0ZW5jeVRlc3RTZXEsIERhdGFDaGFubmVsTGF0ZW5jeVRlc3RSZWNvcmQ+O1xuICAgIHNlcTogRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFNlcTtcbiAgICBpbnRlcnZhbDogTm9kZUpTLlRpbWVyO1xuXG4gICAgY29uc3RydWN0b3Ioc2luazogRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFNpbmssIGNhbGxiYWNrOiBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVzdWx0Q2FsbGJhY2spIHtcbiAgICAgICAgdGhpcy5zaW5rID0gc2luaztcbiAgICAgICAgdGhpcy5jYWxsYmFjayA9IGNhbGxiYWNrO1xuICAgICAgICB0aGlzLnJlY29yZHMgPSBuZXcgTWFwKCk7XG4gICAgICAgIHRoaXMuc2VxID0gMDtcbiAgICB9XG5cbiAgICBzdGFydChjb25maWc6IERhdGFDaGFubmVsTGF0ZW5jeVRlc3RDb25maWcpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNSdW5uaW5nKCkpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgICAgIHRoaXMucmVjb3Jkcy5jbGVhcigpO1xuICAgICAgICB0aGlzLmludGVydmFsID0gc2V0SW50ZXJ2YWwoKCgpID0+IHtcbiAgICAgICAgICAgIGlmIChEYXRlLm5vdygpIC0gdGhpcy5zdGFydFRpbWUgPj0gY29uZmlnLmR1cmF0aW9uKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zdG9wKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuc2VuZFJlcXVlc3QoY29uZmlnLnJlcXVlc3RTaXplLCBjb25maWcucmVzcG9uc2VTaXplKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSkuYmluZCh0aGlzKSwgTWF0aC5mbG9vcigxMDAwL2NvbmZpZy5ycHMpKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgc3RvcCgpIHtcbiAgICAgICAgaWYgKHRoaXMuaW50ZXJ2YWwpIHtcbiAgICAgICAgICAgIGNsZWFySW50ZXJ2YWwodGhpcy5pbnRlcnZhbCk7XG4gICAgICAgICAgICB0aGlzLmludGVydmFsID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgdGhpcy5jYWxsYmFjayh0aGlzLnByb2R1Y2VSZXN1bHQoKSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcm9kdWNlUmVzdWx0KCk6IERhdGFDaGFubmVsTGF0ZW5jeVRlc3RSZXN1bHQge1xuICAgICAgICBjb25zdCByZXN1bHRSZWNvcmRzID0gbmV3IE1hcCh0aGlzLnJlY29yZHMpO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgcmVjb3JkczogcmVzdWx0UmVjb3JkcyxcbiAgICAgICAgICAgIGRhdGFDaGFubmVsUnR0OiBNYXRoLmNlaWwoQXJyYXkuZnJvbSh0aGlzLnJlY29yZHMudmFsdWVzKCkpLnJlZHVjZSgoYWNjLCBuZXh0KSA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFjYyArIChuZXh0LnBsYXllclJlY2VpdmVkVGltZXN0YW1wIC0gbmV4dC5wbGF5ZXJTZW50VGltZXN0YW1wKTtcbiAgICAgICAgICAgIH0sIDApIC8gdGhpcy5yZWNvcmRzLnNpemUpLFxuICAgICAgICAgICAgcGxheWVyVG9TdHJlYW1lclRpbWU6IE1hdGguY2VpbChBcnJheS5mcm9tKHRoaXMucmVjb3Jkcy52YWx1ZXMoKSkucmVkdWNlKChhY2MsIG5leHQpID0+IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gYWNjICsgKG5leHQuc3RyZWFtZXJSZWNlaXZlZFRpbWVzdGFtcCAtIG5leHQucGxheWVyU2VudFRpbWVzdGFtcCk7XG4gICAgICAgICAgICB9LCAwKSAvIHRoaXMucmVjb3Jkcy5zaXplKSxcbiAgICAgICAgICAgIHN0cmVhbWVyVG9QbGF5ZXJUaW1lOiBNYXRoLmNlaWwoQXJyYXkuZnJvbSh0aGlzLnJlY29yZHMudmFsdWVzKCkpLnJlZHVjZSgoYWNjLCBuZXh0KSA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFjYyArIChuZXh0LnBsYXllclJlY2VpdmVkVGltZXN0YW1wIC0gbmV4dC5zdHJlYW1lclNlbnRUaW1lc3RhbXApO1xuICAgICAgICAgICAgfSwgMCkgLyB0aGlzLnJlY29yZHMuc2l6ZSksXG4gICAgICAgICAgICBleHBvcnRMYXRlbmN5QXNDU1Y6ICgpID0+IHtcbiAgICAgICAgICAgICAgICBsZXQgY3N2ID0gXCJUaW1lc3RhbXA7UlRUO1BsYXllclRvU3RyZWFtZXI7U3RyZWFtZXJUb1BsYXllcjtcXG5cIjtcbiAgICAgICAgICAgICAgICByZXN1bHRSZWNvcmRzLmZvckVhY2goKHJlY29yZCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjc3YgKz0gcmVjb3JkLnBsYXllclNlbnRUaW1lc3RhbXAgKyBcIjtcIjtcbiAgICAgICAgICAgICAgICAgICAgY3N2ICs9IChyZWNvcmQucGxheWVyUmVjZWl2ZWRUaW1lc3RhbXAgLSByZWNvcmQucGxheWVyU2VudFRpbWVzdGFtcCkgKyBcIjtcIjtcbiAgICAgICAgICAgICAgICAgICAgY3N2ICs9IChyZWNvcmQuc3RyZWFtZXJSZWNlaXZlZFRpbWVzdGFtcCAtIHJlY29yZC5wbGF5ZXJTZW50VGltZXN0YW1wKSArIFwiO1wiO1xuICAgICAgICAgICAgICAgICAgICBjc3YgKz0gKHJlY29yZC5wbGF5ZXJSZWNlaXZlZFRpbWVzdGFtcCAtIHJlY29yZC5zdHJlYW1lclNlbnRUaW1lc3RhbXApICsgXCI7XCI7XG4gICAgICAgICAgICAgICAgICAgIGNzdiArPSBcIlxcblwiO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgcmV0dXJuIGNzdjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIGlzUnVubmluZygpIHtcbiAgICAgICAgcmV0dXJuICEhdGhpcy5pbnRlcnZhbDtcbiAgICB9XG5cbiAgICByZWNlaXZlKHJlc3BvbnNlOiBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVzcG9uc2UpIHtcbiAgICAgICAgaWYgKCF0aGlzLmlzUnVubmluZygpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFyZXNwb25zZSkge1xuICAgICAgICAgICAgTG9nZ2VyLkVycm9yKFxuICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgXCJVbmRlZmluZWQgcmVzcG9uc2UgZnJvbSBzZXJ2ZXJcIlxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBsZXQgcmVjb3JkID0gdGhpcy5yZWNvcmRzLmdldChyZXNwb25zZS5TZXEpO1xuICAgICAgICBpZiAocmVjb3JkKSB7XG4gICAgICAgICAgICByZWNvcmQudXBkYXRlKHJlc3BvbnNlKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHNlbmRSZXF1ZXN0KHJlcXVlc3RTaXplOiBudW1iZXIsIHJlc3BvbnNlU2l6ZTogbnVtYmVyKSB7XG4gICAgICAgIGxldCByZXF1ZXN0ID0gdGhpcy5jcmVhdGVSZXF1ZXN0KHJlcXVlc3RTaXplLCByZXNwb25zZVNpemUpO1xuICAgICAgICBsZXQgcmVjb3JkID0gbmV3IERhdGFDaGFubmVsTGF0ZW5jeVRlc3RSZWNvcmQocmVxdWVzdCk7XG4gICAgICAgIHRoaXMucmVjb3Jkcy5zZXQocmVjb3JkLnNlcSwgcmVjb3JkKTtcbiAgICAgICAgdGhpcy5zaW5rKHJlcXVlc3QpO1xuICAgIH1cblxuICAgIGNyZWF0ZVJlcXVlc3QocmVxdWVzdFNpemU6IG51bWJlciwgcmVzcG9uc2VTaXplOiBudW1iZXIpOiBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVxdWVzdCB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBTZXE6IHRoaXMuc2VxKyssXG4gICAgICAgICAgICBGaWxsUmVzcG9uc2VTaXplOiByZXNwb25zZVNpemUsXG4gICAgICAgICAgICBGaWxsZXI6IHJlcXVlc3RTaXplID8gXCJBXCIucmVwZWF0KHJlcXVlc3RTaXplKSA6IFwiXCJcbiAgICAgICAgfVxuICAgIH1cblxufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuLyoqXG4gKiBEYXRhIENoYW5uZWwgTGF0ZW5jeSBUZXN0IHR5cGVzXG4gKi9cblxuXG4vKipcbiAqIFVuaXggZXBvY2hcbiAqL1xuZXhwb3J0IHR5cGUgRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFRpbWVzdGFtcCA9IG51bWJlcjtcblxuLyoqXG4gKiBTZXF1ZW5jZSBudW1iZXIgcmVwcmVzZW50ZWQgYnkgdW5zaWduZWQgaW50XG4gKi9cbmV4cG9ydCB0eXBlIERhdGFDaGFubmVsTGF0ZW5jeVRlc3RTZXEgPSBudW1iZXI7XG5cbi8qKlxuICogUmVxdWVzdCBzZW50IHRvIFN0cmVhbWVyXG4gKi9cbmV4cG9ydCB0eXBlIERhdGFDaGFubmVsTGF0ZW5jeVRlc3RSZXF1ZXN0ID0ge1xuICAgIFNlcTogRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFNlcTtcbiAgICBGaWxsUmVzcG9uc2VTaXplOiBudW1iZXI7XG4gICAgRmlsbGVyOiBzdHJpbmc7XG59XG5cbi8qKlxuICogUmVzcG9uc2UgZnJvbSB0aGUgU3RyZWFtZXJcbiAqL1xuZXhwb3J0IHR5cGUgRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFJlc3BvbnNlID0ge1xuICAgIFNlcTogRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFNlcTtcbiAgICBGaWxsZXI6IHN0cmluZztcbiAgICBSZWNlaXZlZFRpbWVzdGFtcDogRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFRpbWVzdGFtcDtcbiAgICBTZW50VGltZXN0YW1wOiBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0VGltZXN0YW1wO1xufVxuXG5leHBvcnQgdHlwZSBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVzdWx0ID0ge1xuICAgIHJlY29yZHM6IE1hcDxEYXRhQ2hhbm5lbExhdGVuY3lUZXN0U2VxLCBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVjb3JkPlxuICAgIGRhdGFDaGFubmVsUnR0OiBudW1iZXIsXG4gICAgcGxheWVyVG9TdHJlYW1lclRpbWU6IG51bWJlcixcbiAgICBzdHJlYW1lclRvUGxheWVyVGltZTogbnVtYmVyLFxuICAgIGV4cG9ydExhdGVuY3lBc0NTVjogKCkgPT4gc3RyaW5nXG59XG5cbmV4cG9ydCBjbGFzcyBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVjb3JkIHtcbiAgICBzZXE6IERhdGFDaGFubmVsTGF0ZW5jeVRlc3RTZXE7XG4gICAgcGxheWVyU2VudFRpbWVzdGFtcDogRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFRpbWVzdGFtcDtcbiAgICBwbGF5ZXJSZWNlaXZlZFRpbWVzdGFtcDogRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFRpbWVzdGFtcDtcbiAgICBzdHJlYW1lclJlY2VpdmVkVGltZXN0YW1wOiBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0VGltZXN0YW1wO1xuICAgIHN0cmVhbWVyU2VudFRpbWVzdGFtcDogRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFRpbWVzdGFtcDtcbiAgICByZXF1ZXN0RmlsbGVyU2l6ZTogbnVtYmVyO1xuICAgIHJlc3BvbnNlRmlsbGVyU2l6ZTogbnVtYmVyO1xuXG4gICAgY29uc3RydWN0b3IocmVxdWVzdDogRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFJlcXVlc3QpIHtcbiAgICAgICAgdGhpcy5zZXEgPSByZXF1ZXN0LlNlcTtcbiAgICAgICAgdGhpcy5wbGF5ZXJTZW50VGltZXN0YW1wID0gRGF0ZS5ub3coKTtcbiAgICAgICAgdGhpcy5yZXF1ZXN0RmlsbGVyU2l6ZSA9IHJlcXVlc3QuRmlsbGVyID8gcmVxdWVzdC5GaWxsZXIubGVuZ3RoIDogMDtcbiAgICB9XG5cbiAgICB1cGRhdGUocmVzcG9uc2U6IERhdGFDaGFubmVsTGF0ZW5jeVRlc3RSZXNwb25zZSkge1xuICAgICAgICB0aGlzLnBsYXllclJlY2VpdmVkVGltZXN0YW1wID0gRGF0ZS5ub3coKTtcbiAgICAgICAgdGhpcy5zdHJlYW1lclJlY2VpdmVkVGltZXN0YW1wID0gcmVzcG9uc2UuUmVjZWl2ZWRUaW1lc3RhbXA7XG4gICAgICAgIHRoaXMuc3RyZWFtZXJTZW50VGltZXN0YW1wID0gcmVzcG9uc2UuU2VudFRpbWVzdGFtcDtcbiAgICAgICAgdGhpcy5yZXNwb25zZUZpbGxlclNpemUgPSByZXNwb25zZS5GaWxsZXIgPyByZXNwb25zZS5GaWxsZXIubGVuZ3RoIDogMDtcbiAgICB9XG5cbn1cbiIsIi8vIENvcHlyaWdodCBFcGljIEdhbWVzLCBJbmMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG5cbmltcG9ydCB7IExvZ2dlciB9IGZyb20gJy4uL0xvZ2dlci9Mb2dnZXInO1xuaW1wb3J0IHsgRGF0YUNoYW5uZWxDb250cm9sbGVyIH0gZnJvbSAnLi9EYXRhQ2hhbm5lbENvbnRyb2xsZXInO1xuXG4vKipcbiAqIEEgY2xhc3MgZm9yIHNlbmRpbmcgZGF0YSBjaGFubmVsIG1lc3NhZ2VzXG4gKi9cbmV4cG9ydCBjbGFzcyBEYXRhQ2hhbm5lbFNlbmRlciB7XG4gICAgZGF0YUNoYW5uZWxQcm92aWRlcjogRGF0YUNoYW5uZWxDb250cm9sbGVyO1xuXG4gICAgLyoqXG4gICAgICogQHBhcmFtIGRhdGFDaGFubmVsUHJvdmlkZXIgLSBEYXRhIGNoYW5uZWwgb2JqZWN0IHR5cGVcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihkYXRhQ2hhbm5lbFByb3ZpZGVyOiBEYXRhQ2hhbm5lbENvbnRyb2xsZXIpIHtcbiAgICAgICAgdGhpcy5kYXRhQ2hhbm5lbFByb3ZpZGVyID0gZGF0YUNoYW5uZWxQcm92aWRlcjtcbiAgICB9XG5cbiAgICBjYW5TZW5kKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgdGhpcy5kYXRhQ2hhbm5lbFByb3ZpZGVyLmdldERhdGFDaGFubmVsSW5zdGFuY2UoKS5kYXRhQ2hhbm5lbCAhPT1cbiAgICAgICAgICAgICAgICB1bmRlZmluZWQgJiZcbiAgICAgICAgICAgIHRoaXMuZGF0YUNoYW5uZWxQcm92aWRlci5nZXREYXRhQ2hhbm5lbEluc3RhbmNlKCkuZGF0YUNoYW5uZWxcbiAgICAgICAgICAgICAgICAucmVhZHlTdGF0ZSA9PSAnb3BlbidcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZW5kIERhdGEgb3ZlciB0aGUgRGF0YSBjaGFubmVsIHRvIHRoZSBVRSBJbnN0YW5jZVxuICAgICAqIEBwYXJhbSBkYXRhIC0gTWVzc2FnZSBEYXRhIEFycmF5IEJ1ZmZlclxuICAgICAqL1xuICAgIHNlbmREYXRhKGRhdGE6IEFycmF5QnVmZmVyKSB7XG4gICAgICAgIC8vIHJlc2V0IHRoZSBhZmsgaW5hY3Rpdml0eVxuICAgICAgICBjb25zdCBkYXRhQ2hhbm5lbEluc3RhbmNlID1cbiAgICAgICAgICAgIHRoaXMuZGF0YUNoYW5uZWxQcm92aWRlci5nZXREYXRhQ2hhbm5lbEluc3RhbmNlKCk7XG5cbiAgICAgICAgaWYgKGRhdGFDaGFubmVsSW5zdGFuY2UuZGF0YUNoYW5uZWwucmVhZHlTdGF0ZSA9PSAnb3BlbicpIHtcbiAgICAgICAgICAgIGRhdGFDaGFubmVsSW5zdGFuY2UuZGF0YUNoYW5uZWwuc2VuZChkYXRhKTtcbiAgICAgICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICBgTWVzc2FnZSBTZW50OiAke25ldyBVaW50OEFycmF5KGRhdGEpfWAsXG4gICAgICAgICAgICAgICAgNlxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHRoaXMucmVzZXRBZmtXYXJuaW5nVGltZXJPbkRhdGFTZW5kKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBMb2dnZXIuRXJyb3IoXG4gICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICBgTWVzc2FnZSBGYWlsZWQ6ICR7bmV3IFVpbnQ4QXJyYXkoZGF0YSl9YFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFuIG92ZXJyaWRlIG1ldGhvZCBmb3IgcmVzZXR0aW5nIHRoZSBBZmsgd2FybmluZyB0aW1lciB3aGVuIGRhdGEgaXMgc2VudCBvdmVyIHRoZSBkYXRhIGNoYW5uZWxcbiAgICAgKi9cbiAgICByZXNldEFma1dhcm5pbmdUaW1lck9uRGF0YVNlbmQoKSB7XG4gICAgICAgIC8vIEJhc2UgRnVuY3Rpb25hbGl0eTogRG8gTm90aGluZ1xuICAgIH1cbn1cbiIsIi8vIENvcHlyaWdodCBFcGljIEdhbWVzLCBJbmMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG5cbi8qKlxuICogTGF0ZW5jeSBUZXN0IFJlc3VsdHMgRGF0YVxuICovXG5leHBvcnQgY2xhc3MgSW5pdGlhbFNldHRpbmdzIHtcbiAgICBQaXhlbFN0cmVhbWluZ1NldHRpbmdzOiBQaXhlbFN0cmVhbWluZ1NldHRpbmdzO1xuICAgIEVuY29kZXJTZXR0aW5nczogRW5jb2RlclNldHRpbmdzO1xuICAgIFdlYlJUQ1NldHRpbmdzOiBXZWJSVENTZXR0aW5ncztcblxuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLlBpeGVsU3RyZWFtaW5nU2V0dGluZ3MgPSBuZXcgUGl4ZWxTdHJlYW1pbmdTZXR0aW5ncygpO1xuICAgICAgICB0aGlzLkVuY29kZXJTZXR0aW5ncyA9IG5ldyBFbmNvZGVyU2V0dGluZ3MoKTtcbiAgICAgICAgdGhpcy5XZWJSVENTZXR0aW5ncyA9IG5ldyBXZWJSVENTZXR0aW5ncygpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENoZWNrcyBmb3IgY29tcGF0aWJpbGl0eSB3aXRoIHRoZSBGUFMgYW5kIE1heEZQUyBzdGF0cyBiZXR3ZWVuIDQuMjcgYW5kIDVcbiAgICAgKi9cbiAgICB1ZUNvbXBhdGlibGUoKSB7XG4gICAgICAgIGlmICh0aGlzLldlYlJUQ1NldHRpbmdzLk1heEZQUyAhPSBudWxsKSB7XG4gICAgICAgICAgICB0aGlzLldlYlJUQ1NldHRpbmdzLkZQUyA9IHRoaXMuV2ViUlRDU2V0dGluZ3MuTWF4RlBTO1xuICAgICAgICB9XG4gICAgfVxufVxuXG4vKipcbiAqIEEgY2xhc3MgZm9yIGhhbmRsaW5nIFBpeGVsIFN0cmVhbWluZyBkZXRhaWxzXG4gKi9cbmV4cG9ydCBjbGFzcyBQaXhlbFN0cmVhbWluZ1NldHRpbmdzIHtcbiAgICBBbGxvd1BpeGVsU3RyZWFtaW5nQ29tbWFuZHM/OiBib29sZWFuO1xuICAgIERpc2FibGVMYXRlbmN5VGVzdD86IGJvb2xlYW47XG59XG5cbi8qKlxuICogQSBjbGFzcyBmb3IgaGFuZGxpbmcgZW5jb2RlciBzdGF0c1xuICovXG5leHBvcnQgY2xhc3MgRW5jb2RlclNldHRpbmdzIHtcbiAgICBUYXJnZXRCaXRyYXRlPzogbnVtYmVyO1xuICAgIE1heEJpdHJhdGU/OiBudW1iZXI7XG4gICAgTWluUVA/OiBudW1iZXI7XG4gICAgTWF4UVA/OiBudW1iZXI7XG4gICAgUmF0ZUNvbnRyb2w/OiAnQ0JSJyB8ICdWQlInIHwgJ0NvbnN0UVAnO1xuICAgIEZpbGxlckRhdGE/OiBib29sZWFuO1xuICAgIE11bHRpUGFzcz86ICdESVNBQkxFRCcgfCAnUVVBUlRFUicgfCAnRlVMTCc7XG59XG5cbi8qKlxuICogQSBjbGFzcyBmb3IgaGFuZGxpbmcgd2ViIHJ0YyBzdGF0c1xuICovXG5leHBvcnQgY2xhc3MgV2ViUlRDU2V0dGluZ3Mge1xuICAgIERlZ3JhZGF0aW9uUHJlZj86ICdCQUxBTkNFRCcgfCAnTUFJTlRBSU5fRlJBTUVSQVRFJyB8ICdNQUlOVEFJTl9SRVNPTFVUSU9OJztcbiAgICBNaW5CaXRyYXRlPzogbnVtYmVyO1xuICAgIE1heEJpdHJhdGU/OiBudW1iZXI7XG4gICAgTG93UVA/OiBudW1iZXI7XG4gICAgSGlnaFFQPzogbnVtYmVyO1xuICAgIC8vIFVFNC4yNyBjb21wYXRpYmxlXG4gICAgTWF4RlBTPzogbnVtYmVyO1xuICAgIC8vIFVFNSBjb21wYXRpYmxlXG4gICAgRlBTPzogbnVtYmVyO1xufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuaW1wb3J0IHsgTG9nZ2VyIH0gZnJvbSAnLi4vTG9nZ2VyL0xvZ2dlcic7XG4vKipcbiAqIExhdGVuY3kgVGVzdCBSZXN1bHRzIERhdGFcbiAqL1xuZXhwb3J0IGNsYXNzIExhdGVuY3lUZXN0UmVzdWx0cyB7XG4gICAgLy9GaWVsZHMgU2V0IGZyb20gdGhlIGxhdGVuY3kgcGF5bG9hZCByZWdhcmRsZXNzIG9mIHZlcnNpb25cbiAgICBSZWNlaXB0VGltZU1zOiBudW1iZXIgPSBudWxsO1xuICAgIFRyYW5zbWlzc2lvblRpbWVNczogbnVtYmVyID0gbnVsbDtcblxuICAgIC8vRmllbGRzIFNldCBmcm9tIHRoZSBsYXRlbmN5IHBheWxvYWQgZnJvbSA0LjI3LjJcbiAgICBQcmVDYXB0dXJlVGltZU1zOiBudW1iZXIgPSBudWxsO1xuICAgIFBvc3RDYXB0dXJlVGltZU1zOiBudW1iZXIgPSBudWxsO1xuICAgIFByZUVuY29kZVRpbWVNczogbnVtYmVyID0gbnVsbDtcbiAgICBQb3N0RW5jb2RlVGltZU1zOiBudW1iZXIgPSBudWxsO1xuXG4gICAgLy9GaWVsZHMgU2V0IGZyb20gdGhlIGxhdGVuY3kgcGF5bG9hZCBmcm9tIDUuMFxuICAgIEVuY29kZU1zOiBudW1iZXIgPSBudWxsO1xuICAgIENhcHR1cmVUb1NlbmRNczogbnVtYmVyID0gbnVsbDtcblxuICAgIC8vRmllbGRzIFNldCB3aGVuIHByb2Nlc3NlZFxuICAgIHRlc3RTdGFydFRpbWVNcyA9IDA7XG4gICAgYnJvd3NlclJlY2VpcHRUaW1lTXMgPSAwO1xuXG4gICAgLy9GaWVsZHMgc2V0IGZyb20gY2FsY3VsYXRpb25zXG4gICAgbGF0ZW5jeUV4Y2x1ZGluZ0RlY29kZSA9IDA7XG4gICAgdGVzdER1cmF0aW9uID0gMDtcbiAgICAvL3VlTGF0ZW5jeTogbnVtYmVyID0gMDtcbiAgICBuZXR3b3JrTGF0ZW5jeSA9IDA7XG4gICAgYnJvd3NlclNlbmRMYXRlbmN5ID0gMDtcbiAgICBmcmFtZURpc3BsYXlEZWx0YVRpbWVNcyA9IDA7XG4gICAgZW5kVG9FbmRMYXRlbmN5ID0gMDtcbiAgICAvL3VlUGl4ZWxTdHJlYW1MYXRlbmN5OiBudW1iZXIgPSAwO1xuICAgIGVuY29kZUxhdGVuY3kgPSAwO1xuXG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgRGVsdGEgVGltZSBNaWxsaXNlY29uZHNcbiAgICAgKiBAcGFyYW0gRGVsdGFUaW1lTXMgLSBEZWx0YSBUaW1lIE1pbGxpc2Vjb25kc1xuICAgICAqL1xuICAgIHNldEZyYW1lRGlzcGxheURlbHRhVGltZShEZWx0YVRpbWVNczogbnVtYmVyKSB7XG4gICAgICAgIGlmICh0aGlzLmZyYW1lRGlzcGxheURlbHRhVGltZU1zID09IDApIHtcbiAgICAgICAgICAgIHRoaXMuZnJhbWVEaXNwbGF5RGVsdGFUaW1lTXMgPSBNYXRoLnJvdW5kKERlbHRhVGltZU1zKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFByb2Nlc3MgdGhlIGVuY29kZXIgdGltZXMgYW5kIHNldCB0aGVtXG4gICAgICovXG4gICAgcHJvY2Vzc0ZpZWxkcygpIHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgdGhpcy5FbmNvZGVNcyA9PSBudWxsICYmXG4gICAgICAgICAgICAodGhpcy5QcmVFbmNvZGVUaW1lTXMgIT0gbnVsbCB8fCB0aGlzLlBvc3RFbmNvZGVUaW1lTXMgIT0gbnVsbClcbiAgICAgICAgKSB7XG4gICAgICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgYFNldHRpbmcgRW5jb2RlIE1zIFxcbiAke3RoaXMuUG9zdEVuY29kZVRpbWVNc30gXFxuICR7dGhpcy5QcmVFbmNvZGVUaW1lTXN9YCxcbiAgICAgICAgICAgICAgICA2XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdGhpcy5FbmNvZGVNcyA9IHRoaXMuUG9zdEVuY29kZVRpbWVNcyAtIHRoaXMuUHJlRW5jb2RlVGltZU1zO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgdGhpcy5DYXB0dXJlVG9TZW5kTXMgPT0gbnVsbCAmJlxuICAgICAgICAgICAgKHRoaXMuUHJlQ2FwdHVyZVRpbWVNcyAhPSBudWxsIHx8IHRoaXMuUG9zdENhcHR1cmVUaW1lTXMgIT0gbnVsbClcbiAgICAgICAgKSB7XG4gICAgICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgYFNldHRpbmcgQ2FwdHVyZVRvU2VuZE1zIE1zIFxcbiAke3RoaXMuUG9zdENhcHR1cmVUaW1lTXN9IFxcbiAke3RoaXMuUHJlQ2FwdHVyZVRpbWVNc31gLFxuICAgICAgICAgICAgICAgIDZcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICB0aGlzLkNhcHR1cmVUb1NlbmRNcyA9XG4gICAgICAgICAgICAgICAgdGhpcy5Qb3N0Q2FwdHVyZVRpbWVNcyAtIHRoaXMuUHJlQ2FwdHVyZVRpbWVNcztcbiAgICAgICAgfVxuICAgIH1cbn1cbiIsIi8vIENvcHlyaWdodCBFcGljIEdhbWVzLCBJbmMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG5cbi8qKlxuICogQSBjbGFzcyBmb3IgbWFuYWdpbmcgdGhlIGZyZWV6ZSBmcmFtZSBvYmplY3RcbiAqL1xuZXhwb3J0IGNsYXNzIEZyZWV6ZUZyYW1lIHtcbiAgICBwcm90ZWN0ZWQgcm9vdERpdjogSFRNTEVsZW1lbnQ7XG4gICAgcHJvdGVjdGVkIHJvb3RFbGVtZW50OiBIVE1MRGl2RWxlbWVudDtcbiAgICBpbWFnZUVsZW1lbnQ6IEhUTUxJbWFnZUVsZW1lbnQ7XG4gICAgZnJlZXplRnJhbWVIZWlnaHQgPSAwO1xuICAgIGZyZWV6ZUZyYW1lV2lkdGggPSAwO1xuXG4gICAgLyoqXG4gICAgICogQ29uc3RydWN0IGEgZnJlZXplIGZyYW1lXG4gICAgICogQHBhcmFtIHJvb3REaXYgdGhlIGRpdiB0aGF0IGEgZnJlZXplIGZyYW1lIGVsZW1lbnQgd2lsbCBiZSBpbmplY3RlZCBpbnRvXG4gICAgICovXG4gICAgY29uc3RydWN0b3Iocm9vdERpdjogSFRNTEVsZW1lbnQpIHtcbiAgICAgICAgdGhpcy5yb290RGl2ID0gcm9vdERpdjtcblxuICAgICAgICAvLyBjcmVhdGUgdGhlIG92ZXJsYXlcbiAgICAgICAgdGhpcy5yb290RWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgICAgICB0aGlzLnJvb3RFbGVtZW50LmlkID0gJ2ZyZWV6ZUZyYW1lJztcbiAgICAgICAgdGhpcy5yb290RWxlbWVudC5zdHlsZS5kaXNwbGF5ID0gJ25vbmUnO1xuICAgICAgICB0aGlzLnJvb3RFbGVtZW50LnN0eWxlLnBvaW50ZXJFdmVudHMgPSAnbm9uZSc7XG4gICAgICAgIHRoaXMucm9vdEVsZW1lbnQuc3R5bGUucG9zaXRpb24gPSAnYWJzb2x1dGUnO1xuICAgICAgICB0aGlzLnJvb3RFbGVtZW50LnN0eWxlLnpJbmRleCA9ICcyMCc7XG5cbiAgICAgICAgLy8gY3JlYXRlIHRoZSBpbWFnZSBwbGFjZSBob2xkZXJcbiAgICAgICAgdGhpcy5pbWFnZUVsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdpbWcnKTtcbiAgICAgICAgdGhpcy5pbWFnZUVsZW1lbnQuc3R5bGUucG9zaXRpb24gPSAnYWJzb2x1dGUnO1xuXG4gICAgICAgIC8vIGFwcGVuZCB0aGUgaW1hZ2UgaW50byB0aGUgcm9vdCBlbGVtZW50IGFuZCBhcHBlbmQgdGhlIGVsZW1lbnQgdG8gdGhlIHJvb3QgZGl2XG4gICAgICAgIHRoaXMucm9vdEVsZW1lbnQuYXBwZW5kQ2hpbGQodGhpcy5pbWFnZUVsZW1lbnQpO1xuICAgICAgICB0aGlzLnJvb3REaXYuYXBwZW5kQ2hpbGQodGhpcy5yb290RWxlbWVudCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0IHRoZSBmcmVlemUgZnJhbWUgZWxlbWVudCBmb3Igc2hvd2luZ1xuICAgICAqL1xuICAgIHNldEVsZW1lbnRGb3JTaG93KCkge1xuICAgICAgICB0aGlzLnJvb3RFbGVtZW50LnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCB0aGUgZnJlZXplIGZyYW1lIGVsZW1lbnQgZm9yIGhpZGluZ1xuICAgICAqL1xuICAgIHNldEVsZW1lbnRGb3JIaWRlKCkge1xuICAgICAgICB0aGlzLnJvb3RFbGVtZW50LnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVXBkYXRlIHRoZSBmcmVlemUgZnJhbWVzIGltYWdlIHNvdXJjZVxuICAgICAqIEBwYXJhbSBqcGVnIC0gdGhlIGZyZWV6ZSBmcmFtZSBpbWFnZSBhcyBhIGJ5dGUgYXJyYXkgZGF0YVxuICAgICAqL1xuICAgIHVwZGF0ZUltYWdlRWxlbWVudFNvdXJjZShqcGVnOiBVaW50OEFycmF5KSB7XG4gICAgICAgIGNvbnN0IGJhc2U2NCA9IGJ0b2EoXG4gICAgICAgICAgICBqcGVnLnJlZHVjZSgoZGF0YSwgYnl0ZSkgPT4gZGF0YSArIFN0cmluZy5mcm9tQ2hhckNvZGUoYnl0ZSksICcnKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLmltYWdlRWxlbWVudC5zcmMgPSAnZGF0YTppbWFnZS9qcGVnO2Jhc2U2NCwnICsgYmFzZTY0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCB0aGUgZGltZW5zaW9ucyBmb3IgdGhlIGZyZWV6ZSBmcmFtZSBmcm9tIHRoZSBlbGVtZW50IGFuZCByZXNpemUgaXRcbiAgICAgKi9cbiAgICBzZXREaW1lbnNpb25zRnJvbUVsZW1lbnRBbmRSZXNpemUoKSB7XG4gICAgICAgIHRoaXMuZnJlZXplRnJhbWVIZWlnaHQgPSB0aGlzLmltYWdlRWxlbWVudC5uYXR1cmFsSGVpZ2h0O1xuICAgICAgICB0aGlzLmZyZWV6ZUZyYW1lV2lkdGggPSB0aGlzLmltYWdlRWxlbWVudC5uYXR1cmFsV2lkdGg7XG4gICAgICAgIHRoaXMucmVzaXplKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVzaXplIGEgZnJlZXplIGZyYW1lIGVsZW1lbnRcbiAgICAgKi9cbiAgICByZXNpemUoKSB7XG4gICAgICAgIGlmICh0aGlzLmZyZWV6ZUZyYW1lV2lkdGggIT09IDAgJiYgdGhpcy5mcmVlemVGcmFtZUhlaWdodCAhPT0gMCkge1xuICAgICAgICAgICAgbGV0IGRpc3BsYXlXaWR0aCA9IDA7XG4gICAgICAgICAgICBsZXQgZGlzcGxheUhlaWdodCA9IDA7XG4gICAgICAgICAgICBsZXQgZGlzcGxheVRvcCA9IDA7XG4gICAgICAgICAgICBsZXQgZGlzcGxheUxlZnQgPSAwO1xuICAgICAgICAgICAgY29uc3QgcGFyZW50QXNwZWN0UmF0aW8gPVxuICAgICAgICAgICAgICAgIHRoaXMucm9vdERpdi5jbGllbnRXaWR0aCAvIHRoaXMucm9vdERpdi5jbGllbnRIZWlnaHQ7XG4gICAgICAgICAgICBjb25zdCB2aWRlb0FzcGVjdFJhdGlvID1cbiAgICAgICAgICAgICAgICB0aGlzLmZyZWV6ZUZyYW1lV2lkdGggLyB0aGlzLmZyZWV6ZUZyYW1lSGVpZ2h0O1xuICAgICAgICAgICAgaWYgKHBhcmVudEFzcGVjdFJhdGlvIDwgdmlkZW9Bc3BlY3RSYXRpbykge1xuICAgICAgICAgICAgICAgIGRpc3BsYXlXaWR0aCA9IHRoaXMucm9vdERpdi5jbGllbnRXaWR0aDtcbiAgICAgICAgICAgICAgICBkaXNwbGF5SGVpZ2h0ID0gTWF0aC5mbG9vcihcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yb290RGl2LmNsaWVudFdpZHRoIC8gdmlkZW9Bc3BlY3RSYXRpb1xuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgZGlzcGxheVRvcCA9IE1hdGguZmxvb3IoXG4gICAgICAgICAgICAgICAgICAgICh0aGlzLnJvb3REaXYuY2xpZW50SGVpZ2h0IC0gZGlzcGxheUhlaWdodCkgKiAwLjVcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIGRpc3BsYXlMZWZ0ID0gMDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZGlzcGxheVdpZHRoID0gTWF0aC5mbG9vcihcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yb290RGl2LmNsaWVudEhlaWdodCAqIHZpZGVvQXNwZWN0UmF0aW9cbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIGRpc3BsYXlIZWlnaHQgPSB0aGlzLnJvb3REaXYuY2xpZW50SGVpZ2h0O1xuICAgICAgICAgICAgICAgIGRpc3BsYXlUb3AgPSAwO1xuICAgICAgICAgICAgICAgIGRpc3BsYXlMZWZ0ID0gTWF0aC5mbG9vcihcbiAgICAgICAgICAgICAgICAgICAgKHRoaXMucm9vdERpdi5jbGllbnRXaWR0aCAtIGRpc3BsYXlXaWR0aCkgKiAwLjVcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5yb290RWxlbWVudC5zdHlsZS53aWR0aCA9IHRoaXMucm9vdERpdi5vZmZzZXRXaWR0aCArICdweCc7XG4gICAgICAgICAgICB0aGlzLnJvb3RFbGVtZW50LnN0eWxlLmhlaWdodCA9IHRoaXMucm9vdERpdi5vZmZzZXRIZWlnaHQgKyAncHgnO1xuICAgICAgICAgICAgdGhpcy5yb290RWxlbWVudC5zdHlsZS5sZWZ0ID0gMCArICdweCc7XG4gICAgICAgICAgICB0aGlzLnJvb3RFbGVtZW50LnN0eWxlLnRvcCA9IDAgKyAncHgnO1xuXG4gICAgICAgICAgICB0aGlzLmltYWdlRWxlbWVudC5zdHlsZS53aWR0aCA9IGRpc3BsYXlXaWR0aCArICdweCc7XG4gICAgICAgICAgICB0aGlzLmltYWdlRWxlbWVudC5zdHlsZS5oZWlnaHQgPSBkaXNwbGF5SGVpZ2h0ICsgJ3B4JztcbiAgICAgICAgICAgIHRoaXMuaW1hZ2VFbGVtZW50LnN0eWxlLmxlZnQgPSBkaXNwbGF5TGVmdCArICdweCc7XG4gICAgICAgICAgICB0aGlzLmltYWdlRWxlbWVudC5zdHlsZS50b3AgPSBkaXNwbGF5VG9wICsgJ3B4JztcbiAgICAgICAgfVxuICAgIH1cbn1cbiIsIi8vIENvcHlyaWdodCBFcGljIEdhbWVzLCBJbmMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG5cbmltcG9ydCB7IExvZ2dlciB9IGZyb20gJy4uL0xvZ2dlci9Mb2dnZXInO1xuaW1wb3J0IHsgRnJlZXplRnJhbWUgfSBmcm9tICcuL0ZyZWV6ZUZyYW1lJztcblxuLyoqXG4gKiBBIGNsYXNzIGZvciBjb250cm9sbGluZyBmcmVlemUgZnJhbWUgZnVuY3Rpb25hbGl0eVxuICovXG5leHBvcnQgY2xhc3MgRnJlZXplRnJhbWVDb250cm9sbGVyIHtcbiAgICBmcmVlemVGcmFtZTogRnJlZXplRnJhbWU7XG4gICAgcmVjZWl2aW5nID0gZmFsc2U7XG4gICAgc2l6ZSA9IDA7XG4gICAganBlZzogVWludDhBcnJheSA9IHVuZGVmaW5lZDtcbiAgICB2YWxpZCA9IGZhbHNlO1xuICAgIGZyZWV6ZUZyYW1lRGVsYXkgPSA1MDtcblxuICAgIC8qKlxuICAgICAqIENvbnN0cnVjdCBhIGZyZWV6ZSBmcmFtZSBjb250cm9sbGVyXG4gICAgICogQHBhcmFtIHJvb3REaXYgLSB0aGUgZGl2IHRoYXQgYSBmcmVlemUgZnJhbWUgZWxlbWVudCB3aWxsIGJlIGluamVjdGVkIGludG9cbiAgICAgKi9cbiAgICBjb25zdHJ1Y3Rvcihyb290RGl2OiBIVE1MRWxlbWVudCkge1xuICAgICAgICB0aGlzLmZyZWV6ZUZyYW1lID0gbmV3IEZyZWV6ZUZyYW1lKHJvb3REaXYpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNob3cgdGhlIGZyZWV6ZSBmcmFtZSBpZiBpdCBpcyB2YWxpZFxuICAgICAqL1xuICAgIHNob3dGcmVlemVGcmFtZSgpIHtcbiAgICAgICAgaWYgKHRoaXMudmFsaWQpIHtcbiAgICAgICAgICAgIHRoaXMuZnJlZXplRnJhbWUuc2V0RWxlbWVudEZvclNob3coKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEhpZGUgdGhlIGZyZWV6ZSBmcmFtZSBhbmQgc2V0IHRoZSB2YWxpZGl0eSB0byBmYWxzZVxuICAgICAqL1xuICAgIGhpZGVGcmVlemVGcmFtZSgpIHtcbiAgICAgICAgdGhpcy52YWxpZCA9IGZhbHNlO1xuICAgICAgICB0aGlzLmZyZWV6ZUZyYW1lLnNldEVsZW1lbnRGb3JIaWRlKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVXBkYXRlIHRoZSBmcmVlemUgZnJhbWVzIGltYWdlIHNvdXJjZSBhbmQgbG9hZCBpdFxuICAgICAqIEBwYXJhbSBqcGVnIC0gdGhlIGZyZWV6ZSBmcmFtZSBpbWFnZSBhcyBhIGJ5dGUgYXJyYXkgZGF0YVxuICAgICAqIEBwYXJhbSBvbkxvYWRDYWxsQmFjayAtIGEgY2FsbCBiYWNrIGZvciBtYW5hZ2luZyBpZiB0aGUgcGxheSBvdmVybGF5IG5lZWRzIHRvIGJlIHNob3duIG9yIG5vdFxuICAgICAqL1xuICAgIHVwZGF0ZUZyZWV6ZUZyYW1lQW5kU2hvdyhqcGVnOiBVaW50OEFycmF5LCBvbkxvYWRDYWxsQmFjazogKCkgPT4gdm9pZCkge1xuICAgICAgICB0aGlzLmZyZWV6ZUZyYW1lLnVwZGF0ZUltYWdlRWxlbWVudFNvdXJjZShqcGVnKTtcbiAgICAgICAgdGhpcy5mcmVlemVGcmFtZS5pbWFnZUVsZW1lbnQub25sb2FkID0gKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5mcmVlemVGcmFtZS5zZXREaW1lbnNpb25zRnJvbUVsZW1lbnRBbmRSZXNpemUoKTtcbiAgICAgICAgICAgIG9uTG9hZENhbGxCYWNrKCk7XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUHJvY2VzcyB0aGUgbmV3IGZyZWV6ZSBmcmFtZSBpbWFnZSBhbmQgdXBkYXRlIGl0XG4gICAgICogQHBhcmFtIHZpZXcgLSB0aGUgZnJlZXplIGZyYW1lIGltYWdlIGFzIGEgYnl0ZSBhcnJheSBkYXRhXG4gICAgICogQHBhcmFtIG9uTG9hZENhbGxCYWNrIC0gYSBjYWxsIGJhY2sgZm9yIG1hbmFnaW5nIGlmIHRoZSBwbGF5IG92ZXJsYXkgbmVlZHMgdG8gYmUgc2hvd24gb3Igbm90XG4gICAgICovXG4gICAgcHJvY2Vzc0ZyZWV6ZUZyYW1lTWVzc2FnZSh2aWV3OiBVaW50OEFycmF5LCBvbkxvYWRDYWxsQmFjazogKCkgPT4gdm9pZCkge1xuICAgICAgICAvLyBSZXNldCBmcmVlemUgZnJhbWUgaWYgd2UgZ290IGEgZnJlZXplIGZyYW1lIG1lc3NhZ2UgYW5kIHdlIGFyZSBub3QgXCJyZWNlaXZpbmdcIiB5ZXQuXG4gICAgICAgIGlmICghdGhpcy5yZWNlaXZpbmcpIHtcbiAgICAgICAgICAgIHRoaXMucmVjZWl2aW5nID0gdHJ1ZTtcbiAgICAgICAgICAgIHRoaXMudmFsaWQgPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMuc2l6ZSA9IDA7XG4gICAgICAgICAgICB0aGlzLmpwZWcgPSB1bmRlZmluZWQ7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBFeHRyYWN0IHRvdGFsIHNpemUgb2YgZnJlZXplIGZyYW1lIChhY3Jvc3MgYWxsIGNodW5rcylcbiAgICAgICAgdGhpcy5zaXplID0gbmV3IERhdGFWaWV3KHZpZXcuc2xpY2UoMSwgNSkuYnVmZmVyKS5nZXRJbnQzMigwLCB0cnVlKTtcblxuICAgICAgICAvLyBHZXQgdGhlIGpwZWcgcGFydCBvZiB0aGUgcGF5bG9hZFxuICAgICAgICBjb25zdCBqcGVnQnl0ZXMgPSB2aWV3LnNsaWNlKDEgKyA0KTtcblxuICAgICAgICAvLyBBcHBlbmQgdG8gZXhpc3RpbmcganBlZyB0aGF0IGhvbGRzIHRoZSBmcmVlemUgZnJhbWVcbiAgICAgICAgaWYgKHRoaXMuanBlZykge1xuICAgICAgICAgICAgY29uc3QganBlZyA9IG5ldyBVaW50OEFycmF5KHRoaXMuanBlZy5sZW5ndGggKyBqcGVnQnl0ZXMubGVuZ3RoKTtcbiAgICAgICAgICAgIGpwZWcuc2V0KHRoaXMuanBlZywgMCk7XG4gICAgICAgICAgICBqcGVnLnNldChqcGVnQnl0ZXMsIHRoaXMuanBlZy5sZW5ndGgpO1xuICAgICAgICAgICAgdGhpcy5qcGVnID0ganBlZztcbiAgICAgICAgfVxuICAgICAgICAvLyBObyBleGlzdGluZyBmcmVlemUgZnJhbWUganBlZywgbWFrZSBvbmVcbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmpwZWcgPSBqcGVnQnl0ZXM7XG4gICAgICAgICAgICB0aGlzLnJlY2VpdmluZyA9IHRydWU7XG4gICAgICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgYHJlY2VpdmVkIGZpcnN0IGNodW5rIG9mIGZyZWV6ZSBmcmFtZTogJHt0aGlzLmpwZWcubGVuZ3RofS8ke3RoaXMuc2l6ZX1gLFxuICAgICAgICAgICAgICAgIDZcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBGaW5pc2hlZCByZWNlaXZpbmcgZnJlZXplIGZyYW1lLCB3ZSBjYW4gc2hvdyBpdCBub3dcbiAgICAgICAgaWYgKHRoaXMuanBlZy5sZW5ndGggPT09IHRoaXMuc2l6ZSkge1xuICAgICAgICAgICAgdGhpcy5yZWNlaXZpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMudmFsaWQgPSB0cnVlO1xuICAgICAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgIGByZWNlaXZlZCBjb21wbGV0ZSBmcmVlemUgZnJhbWUgJHt0aGlzLnNpemV9YCxcbiAgICAgICAgICAgICAgICA2XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdGhpcy51cGRhdGVGcmVlemVGcmFtZUFuZFNob3codGhpcy5qcGVnLCBvbkxvYWRDYWxsQmFjayk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gV2UgcmVjZWl2ZWQgbW9yZSBkYXRhIHRoYW4gdGhlIGZyZWV6ZSBmcmFtZSBwYXlsb2FkIG1lc3NhZ2UgaW5kaWNhdGUgKHRoaXMgaXMgYW4gZXJyb3IpXG4gICAgICAgIGVsc2UgaWYgKHRoaXMuanBlZy5sZW5ndGggPiB0aGlzLnNpemUpIHtcbiAgICAgICAgICAgIExvZ2dlci5FcnJvcihcbiAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgIGByZWNlaXZlZCBiaWdnZXIgZnJlZXplIGZyYW1lIHRoYW4gYWR2ZXJ0aXNlZDogJHt0aGlzLmpwZWcubGVuZ3RofS8ke3RoaXMuc2l6ZX1gXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdGhpcy5qcGVnID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgdGhpcy5yZWNlaXZpbmcgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgIH1cbn1cbiIsIi8vIENvcHlyaWdodCBFcGljIEdhbWVzLCBJbmMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG5cbmltcG9ydCB7IENvb3JkaW5hdGVDb252ZXJ0ZXIgfSBmcm9tICcuLi9VdGlsL0Nvb3JkaW5hdGVDb252ZXJ0ZXInO1xuaW1wb3J0IHsgU3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIgfSBmcm9tICcuLi9VZUluc3RhbmNlTWVzc2FnZS9TdHJlYW1NZXNzYWdlQ29udHJvbGxlcic7XG5pbXBvcnQgeyBWaWRlb1BsYXllciB9IGZyb20gJy4uL1ZpZGVvUGxheWVyL1ZpZGVvUGxheWVyJztcbmltcG9ydCB7IElUb3VjaENvbnRyb2xsZXIgfSBmcm9tICcuL0lUb3VjaENvbnRyb2xsZXInO1xuaW1wb3J0IHsgTW91c2VCdXR0b24gfSBmcm9tICcuL01vdXNlQnV0dG9ucyc7XG5pbXBvcnQgeyBFdmVudExpc3RlbmVyVHJhY2tlciB9IGZyb20gJy4uL1V0aWwvRXZlbnRMaXN0ZW5lclRyYWNrZXInO1xuXG4vKipcbiAqIEFsbG93cyBmb3IgdGhlIHVzYWdlIG9mIGZha2UgdG91Y2ggZXZlbnRzIGFuZCBpbXBsZW1lbnRzIElUb3VjaENvbnRyb2xsZXJcbiAqIEBwYXJhbSBkYXRhQ2hhbm5lbENvbnRyb2xsZXIgLSBUaGUgY29udHJvbGxlciBmb3IgdGhlIERhdGEgY2hhbm5lbFxuICogQHBhcmFtIHZpZGVvRWxlbWVudFBhcmVudCAtIFRoZSB2aWRlbyBwbGF5ZXIgRE9NIGVsZW1lbnRcbiAqL1xuZXhwb3J0IGNsYXNzIEZha2VUb3VjaENvbnRyb2xsZXIgaW1wbGVtZW50cyBJVG91Y2hDb250cm9sbGVyIHtcbiAgICBmYWtlVG91Y2hGaW5nZXI6IEZha2VUb3VjaEZpbmdlcjtcbiAgICB0b1N0cmVhbWVyTWVzc2FnZXNQcm92aWRlcjogU3RyZWFtTWVzc2FnZUNvbnRyb2xsZXI7XG4gICAgdmlkZW9FbGVtZW50UHJvdmlkZXI6IFZpZGVvUGxheWVyO1xuICAgIGNvb3JkaW5hdGVDb252ZXJ0ZXI6IENvb3JkaW5hdGVDb252ZXJ0ZXI7XG4gICAgdmlkZW9FbGVtZW50UGFyZW50Q2xpZW50UmVjdDogRE9NUmVjdDtcblxuICAgIC8vIFV0aWxpdHkgZm9yIGtlZXBpbmcgdHJhY2sgb2YgZXZlbnQgaGFuZGxlcnMgYW5kIHVucmVnaXN0ZXJpbmcgdGhlbVxuICAgIHByaXZhdGUgdG91Y2hFdmVudExpc3RlbmVyVHJhY2tlciA9IG5ldyBFdmVudExpc3RlbmVyVHJhY2tlcigpO1xuXG4gICAgLyoqXG4gICAgICogQHBhcmFtIHRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyIC0gU3RyZWFtIG1lc3NhZ2UgaW5zdGFuY2VcbiAgICAgKiBAcGFyYW0gdmlkZW9FbGVtZW50UHJvdmlkZXIgLSBWaWRlbyBlbGVtZW50IGluc3RhbmNlXG4gICAgICogQHBhcmFtIGNvb3JkaW5hdGVDb252ZXJ0ZXIgLSBBIGNvb3JkaW5hdGUgY29udmVydGVyIGluc3RhbmNlXG4gICAgICovXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIHRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyOiBTdHJlYW1NZXNzYWdlQ29udHJvbGxlcixcbiAgICAgICAgdmlkZW9FbGVtZW50UHJvdmlkZXI6IFZpZGVvUGxheWVyLFxuICAgICAgICBjb29yZGluYXRlQ29udmVydGVyOiBDb29yZGluYXRlQ29udmVydGVyXG4gICAgKSB7XG4gICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIgPSB0b1N0cmVhbWVyTWVzc2FnZXNQcm92aWRlcjtcbiAgICAgICAgdGhpcy52aWRlb0VsZW1lbnRQcm92aWRlciA9IHZpZGVvRWxlbWVudFByb3ZpZGVyO1xuICAgICAgICB0aGlzLmNvb3JkaW5hdGVDb252ZXJ0ZXIgPSBjb29yZGluYXRlQ29udmVydGVyO1xuICAgICAgICBjb25zdCBvbnRvdWNoc3RhcnQgPSAoZXY6IFRvdWNoRXZlbnQpID0+IHRoaXMub25Ub3VjaFN0YXJ0KGV2KTtcbiAgICAgICAgY29uc3Qgb250b3VjaGVuZCA9IChldjogVG91Y2hFdmVudCkgPT4gdGhpcy5vblRvdWNoRW5kKGV2KTtcbiAgICAgICAgY29uc3Qgb250b3VjaG1vdmUgPSAoZXY6IFRvdWNoRXZlbnQpID0+IHRoaXMub25Ub3VjaE1vdmUoZXYpO1xuICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCd0b3VjaHN0YXJ0Jywgb250b3VjaHN0YXJ0LCB7IHBhc3NpdmU6IGZhbHNlIH0pO1xuICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCd0b3VjaGVuZCcsIG9udG91Y2hlbmQsIHsgcGFzc2l2ZTogZmFsc2UgfSk7XG4gICAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3RvdWNobW92ZScsIG9udG91Y2htb3ZlLCB7IHBhc3NpdmU6IGZhbHNlIH0pO1xuICAgICAgICB0aGlzLnRvdWNoRXZlbnRMaXN0ZW5lclRyYWNrZXIuYWRkVW5yZWdpc3RlckNhbGxiYWNrKFxuICAgICAgICAgICAgKCkgPT4gZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigndG91Y2hzdGFydCcsIG9udG91Y2hzdGFydClcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy50b3VjaEV2ZW50TGlzdGVuZXJUcmFja2VyLmFkZFVucmVnaXN0ZXJDYWxsYmFjayhcbiAgICAgICAgICAgICgpID0+IGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RvdWNoZW5kJywgb250b3VjaGVuZClcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy50b3VjaEV2ZW50TGlzdGVuZXJUcmFja2VyLmFkZFVucmVnaXN0ZXJDYWxsYmFjayhcbiAgICAgICAgICAgICgpID0+IGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RvdWNobW92ZScsIG9udG91Y2htb3ZlKVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFVucmVnaXN0ZXIgYWxsIHRvdWNoIGV2ZW50c1xuICAgICAqL1xuICAgIHVucmVnaXN0ZXJUb3VjaEV2ZW50cygpIHtcbiAgICAgICAgdGhpcy50b3VjaEV2ZW50TGlzdGVuZXJUcmFja2VyLnVucmVnaXN0ZXJBbGwoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSB2aWRlbyBFbGVtZW50IFBhcmVudCBDbGllbnQgUmVjdCBudW1iZXJzIGZvciB0aGlzIGNsYXNzXG4gICAgICogQHBhcmFtIHZpZGVvRWxlbWVudFBhcmVudENsaWVudFJlY3QgLSBhIGh0bWwgRWxlbWVudFBhcmVudENsaWVudFJlY3Qgb2JqZWN0XG4gICAgICovXG4gICAgc2V0VmlkZW9FbGVtZW50UGFyZW50Q2xpZW50UmVjdCh2aWRlb0VsZW1lbnRQYXJlbnRDbGllbnRSZWN0OiBET01SZWN0KSB7XG4gICAgICAgIHRoaXMudmlkZW9FbGVtZW50UGFyZW50Q2xpZW50UmVjdCA9IHZpZGVvRWxlbWVudFBhcmVudENsaWVudFJlY3Q7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogV2hlbiBhIHRvdWNoIGV2ZW50IGJlZ2luc1xuICAgICAqIEBwYXJhbSB0b3VjaCAtIHRoZSBhY3RpdmF0aW5nIHRvdWNoIGV2ZW50XG4gICAgICovXG4gICAgb25Ub3VjaFN0YXJ0KHRvdWNoOiBUb3VjaEV2ZW50KTogdm9pZCB7XG4gICAgICAgIGlmICghdGhpcy52aWRlb0VsZW1lbnRQcm92aWRlci5pc1ZpZGVvUmVhZHkoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLmZha2VUb3VjaEZpbmdlciA9PSBudWxsKSB7XG4gICAgICAgICAgICBjb25zdCBmaXJzdF90b3VjaCA9IHRvdWNoLmNoYW5nZWRUb3VjaGVzWzBdO1xuICAgICAgICAgICAgdGhpcy5mYWtlVG91Y2hGaW5nZXIgPSBuZXcgRmFrZVRvdWNoRmluZ2VyKFxuICAgICAgICAgICAgICAgIGZpcnN0X3RvdWNoLmlkZW50aWZpZXIsXG4gICAgICAgICAgICAgICAgZmlyc3RfdG91Y2guY2xpZW50WCAtIHRoaXMudmlkZW9FbGVtZW50UGFyZW50Q2xpZW50UmVjdC5sZWZ0LFxuICAgICAgICAgICAgICAgIGZpcnN0X3RvdWNoLmNsaWVudFkgLSB0aGlzLnZpZGVvRWxlbWVudFBhcmVudENsaWVudFJlY3QudG9wXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBjb25zdCB2aWRlb0VsZW1lbnRQYXJlbnQgPVxuICAgICAgICAgICAgICAgIHRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIuZ2V0VmlkZW9QYXJlbnRFbGVtZW50KCkgYXMgSFRNTERpdkVsZW1lbnQ7XG4gICAgICAgICAgICBjb25zdCBtb3VzZUV2ZW50ID0gbmV3IE1vdXNlRXZlbnQoJ21vdXNlZW50ZXInLCBmaXJzdF90b3VjaCk7XG4gICAgICAgICAgICB2aWRlb0VsZW1lbnRQYXJlbnQuZGlzcGF0Y2hFdmVudChtb3VzZUV2ZW50KTtcblxuICAgICAgICAgICAgY29uc3QgY29vcmQgPSB0aGlzLmNvb3JkaW5hdGVDb252ZXJ0ZXIubm9ybWFsaXplQW5kUXVhbnRpemVVbnNpZ25lZChcbiAgICAgICAgICAgICAgICB0aGlzLmZha2VUb3VjaEZpbmdlci54LFxuICAgICAgICAgICAgICAgIHRoaXMuZmFrZVRvdWNoRmluZ2VyLnlcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBjb25zdCB0b1N0cmVhbWVySGFuZGxlcnMgPVxuICAgICAgICAgICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIudG9TdHJlYW1lckhhbmRsZXJzO1xuICAgICAgICAgICAgdG9TdHJlYW1lckhhbmRsZXJzLmdldCgnTW91c2VEb3duJykoW1xuICAgICAgICAgICAgICAgIE1vdXNlQnV0dG9uLm1haW5CdXR0b24sXG4gICAgICAgICAgICAgICAgY29vcmQueCxcbiAgICAgICAgICAgICAgICBjb29yZC55XG4gICAgICAgICAgICBdKTtcbiAgICAgICAgfVxuICAgICAgICB0b3VjaC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFdoZW4gYSB0b3VjaCBldmVudCBlbmRzXG4gICAgICogQHBhcmFtIHRvdWNoRXZlbnQgLSB0aGUgYWN0aXZhdGluZyB0b3VjaCBldmVudFxuICAgICAqL1xuICAgIG9uVG91Y2hFbmQodG91Y2hFdmVudDogVG91Y2hFdmVudCk6IHZvaWQge1xuICAgICAgICBpZiAoIXRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIuaXNWaWRlb1JlYWR5KCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCB2aWRlb0VsZW1lbnRQYXJlbnQgPVxuICAgICAgICAgICAgdGhpcy52aWRlb0VsZW1lbnRQcm92aWRlci5nZXRWaWRlb1BhcmVudEVsZW1lbnQoKTtcbiAgICAgICAgY29uc3QgdG9TdHJlYW1lckhhbmRsZXJzID1cbiAgICAgICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIudG9TdHJlYW1lckhhbmRsZXJzO1xuXG4gICAgICAgIGZvciAobGV0IHQgPSAwOyB0IDwgdG91Y2hFdmVudC5jaGFuZ2VkVG91Y2hlcy5sZW5ndGg7IHQrKykge1xuICAgICAgICAgICAgY29uc3QgdG91Y2ggPSB0b3VjaEV2ZW50LmNoYW5nZWRUb3VjaGVzW3RdO1xuICAgICAgICAgICAgaWYgKHRvdWNoLmlkZW50aWZpZXIgPT09IHRoaXMuZmFrZVRvdWNoRmluZ2VyLmlkKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgeCA9XG4gICAgICAgICAgICAgICAgICAgIHRvdWNoLmNsaWVudFggLSB0aGlzLnZpZGVvRWxlbWVudFBhcmVudENsaWVudFJlY3QubGVmdDtcbiAgICAgICAgICAgICAgICBjb25zdCB5ID0gdG91Y2guY2xpZW50WSAtIHRoaXMudmlkZW9FbGVtZW50UGFyZW50Q2xpZW50UmVjdC50b3A7XG4gICAgICAgICAgICAgICAgY29uc3QgY29vcmQgPVxuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvb3JkaW5hdGVDb252ZXJ0ZXIubm9ybWFsaXplQW5kUXVhbnRpemVVbnNpZ25lZCh4LCB5KTtcbiAgICAgICAgICAgICAgICB0b1N0cmVhbWVySGFuZGxlcnMuZ2V0KCdNb3VzZVVwJykoW1xuICAgICAgICAgICAgICAgICAgICBNb3VzZUJ1dHRvbi5tYWluQnV0dG9uLFxuICAgICAgICAgICAgICAgICAgICBjb29yZC54LFxuICAgICAgICAgICAgICAgICAgICBjb29yZC55XG4gICAgICAgICAgICAgICAgXSk7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBtb3VzZUV2ZW50ID0gbmV3IE1vdXNlRXZlbnQoJ21vdXNlbGVhdmUnLCB0b3VjaCk7XG4gICAgICAgICAgICAgICAgdmlkZW9FbGVtZW50UGFyZW50LmRpc3BhdGNoRXZlbnQobW91c2VFdmVudCk7XG4gICAgICAgICAgICAgICAgdGhpcy5mYWtlVG91Y2hGaW5nZXIgPSBudWxsO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHRvdWNoRXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBPbiBhIE1vdmUgdG91Y2ggZXZlbnRcbiAgICAgKiBAcGFyYW0gdG91Y2hFdmVudCAtIHRoZSBhY3RpdmF0aW5nIHRvdWNoIGV2ZW50XG4gICAgICovXG4gICAgb25Ub3VjaE1vdmUodG91Y2hFdmVudDogVG91Y2hFdmVudCk6IHZvaWQge1xuICAgICAgICBpZiAoIXRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIuaXNWaWRlb1JlYWR5KCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCB0b1N0cmVhbWVySGFuZGxlcnMgPVxuICAgICAgICAgICAgdGhpcy50b1N0cmVhbWVyTWVzc2FnZXNQcm92aWRlci50b1N0cmVhbWVySGFuZGxlcnM7XG5cbiAgICAgICAgZm9yIChsZXQgdCA9IDA7IHQgPCB0b3VjaEV2ZW50LnRvdWNoZXMubGVuZ3RoOyB0KyspIHtcbiAgICAgICAgICAgIGNvbnN0IHRvdWNoID0gdG91Y2hFdmVudC50b3VjaGVzW3RdO1xuICAgICAgICAgICAgaWYgKHRvdWNoLmlkZW50aWZpZXIgPT09IHRoaXMuZmFrZVRvdWNoRmluZ2VyLmlkKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgeCA9XG4gICAgICAgICAgICAgICAgICAgIHRvdWNoLmNsaWVudFggLSB0aGlzLnZpZGVvRWxlbWVudFBhcmVudENsaWVudFJlY3QubGVmdDtcbiAgICAgICAgICAgICAgICBjb25zdCB5ID0gdG91Y2guY2xpZW50WSAtIHRoaXMudmlkZW9FbGVtZW50UGFyZW50Q2xpZW50UmVjdC50b3A7XG4gICAgICAgICAgICAgICAgY29uc3QgY29vcmQgPVxuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvb3JkaW5hdGVDb252ZXJ0ZXIubm9ybWFsaXplQW5kUXVhbnRpemVVbnNpZ25lZCh4LCB5KTtcbiAgICAgICAgICAgICAgICBjb25zdCBkZWx0YSA9XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29vcmRpbmF0ZUNvbnZlcnRlci5ub3JtYWxpemVBbmRRdWFudGl6ZVNpZ25lZChcbiAgICAgICAgICAgICAgICAgICAgICAgIHggLSB0aGlzLmZha2VUb3VjaEZpbmdlci54LFxuICAgICAgICAgICAgICAgICAgICAgICAgeSAtIHRoaXMuZmFrZVRvdWNoRmluZ2VyLnlcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB0b1N0cmVhbWVySGFuZGxlcnMuZ2V0KCdNb3VzZU1vdmUnKShbXG4gICAgICAgICAgICAgICAgICAgIGNvb3JkLngsXG4gICAgICAgICAgICAgICAgICAgIGNvb3JkLnksXG4gICAgICAgICAgICAgICAgICAgIGRlbHRhLngsXG4gICAgICAgICAgICAgICAgICAgIGRlbHRhLnlcbiAgICAgICAgICAgICAgICBdKTtcbiAgICAgICAgICAgICAgICB0aGlzLmZha2VUb3VjaEZpbmdlci54ID0geDtcbiAgICAgICAgICAgICAgICB0aGlzLmZha2VUb3VjaEZpbmdlci55ID0geTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0b3VjaEV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxufVxuXG4vKipcbiAqIFRoZSBpbnRlcmZhY2UgZm9yIGZpbmdlciBwb3NpdGlvbiBtYXBwaW5nXG4gKi9cbmV4cG9ydCBjbGFzcyBGYWtlVG91Y2hGaW5nZXIge1xuICAgIGlkOiBudW1iZXI7XG4gICAgeDogbnVtYmVyO1xuICAgIHk6IG51bWJlcjtcblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSBpZCAtIHRoZSBidXR0b24gaWRcbiAgICAgKiBAcGFyYW0geCAtIHRoZSB4IGF4aXMgdmFsdWVcbiAgICAgKiBAcGFyYW0geSAtIHRoZSB5IGF4aXMgdmFsdWVcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihpZDogbnVtYmVyLCB4OiBudW1iZXIsIHk6IG51bWJlcikge1xuICAgICAgICB0aGlzLmlkID0gaWQ7XG4gICAgICAgIHRoaXMueCA9IHg7XG4gICAgICAgIHRoaXMueSA9IHk7XG4gICAgfVxufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuaW1wb3J0IHsgTG9nZ2VyIH0gZnJvbSAnLi4vTG9nZ2VyL0xvZ2dlcic7XG5pbXBvcnQgeyBTdHJlYW1NZXNzYWdlQ29udHJvbGxlciB9IGZyb20gJy4uL1VlSW5zdGFuY2VNZXNzYWdlL1N0cmVhbU1lc3NhZ2VDb250cm9sbGVyJztcbmltcG9ydCB7IEV2ZW50TGlzdGVuZXJUcmFja2VyIH0gZnJvbSAnLi4vVXRpbC9FdmVudExpc3RlbmVyVHJhY2tlcic7XG5pbXBvcnQgeyBDb250cm9sbGVyIH0gZnJvbSAnLi9HYW1lcGFkVHlwZXMnO1xuXG4vKipcbiAqIFRoZSBjbGFzcyB0aGF0IGhhbmRsZXMgdGhlIGZ1bmN0aW9uYWxpdHkgb2YgZ2FtZXBhZHMgYW5kIGNvbnRyb2xsZXJzXG4gKi9cbmV4cG9ydCBjbGFzcyBHYW1lUGFkQ29udHJvbGxlciB7XG4gICAgY29udHJvbGxlcnM6IEFycmF5PENvbnRyb2xsZXI+O1xuICAgIHJlcXVlc3RBbmltYXRpb25GcmFtZTogKGNhbGxiYWNrOiBGcmFtZVJlcXVlc3RDYWxsYmFjaykgPT4gbnVtYmVyO1xuICAgIHRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyOiBTdHJlYW1NZXNzYWdlQ29udHJvbGxlcjtcblxuICAgIC8vIFV0aWxpdHkgZm9yIGtlZXBpbmcgdHJhY2sgb2YgZXZlbnQgaGFuZGxlcnMgYW5kIHVucmVnaXN0ZXJpbmcgdGhlbVxuICAgIHByaXZhdGUgZ2FtZVBhZEV2ZW50TGlzdGVuZXJUcmFja2VyID0gbmV3IEV2ZW50TGlzdGVuZXJUcmFja2VyKCk7XG5cbiAgICAvKipcbiAgICAgKiBAcGFyYW0gdG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIgLSBTdHJlYW0gbWVzc2FnZSBpbnN0YW5jZVxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKHRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyOiBTdHJlYW1NZXNzYWdlQ29udHJvbGxlcikge1xuICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyID0gdG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXI7XG5cbiAgICAgICAgdGhpcy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUgPSAoXG4gICAgICAgICAgICB3aW5kb3cubW96UmVxdWVzdEFuaW1hdGlvbkZyYW1lIHx8XG4gICAgICAgICAgICB3aW5kb3cud2Via2l0UmVxdWVzdEFuaW1hdGlvbkZyYW1lIHx8XG4gICAgICAgICAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lXG4gICAgICAgICkuYmluZCh3aW5kb3cpO1xuICAgICAgICBjb25zdCBicm93c2VyV2luZG93ID0gd2luZG93IGFzIFdpbmRvdztcbiAgICAgICAgaWYgKCdHYW1lcGFkRXZlbnQnIGluIGJyb3dzZXJXaW5kb3cpIHtcbiAgICAgICAgICAgIGNvbnN0IG9uR2FtZVBhZENvbm5lY3RlZCA9IChldjogR2FtZXBhZEV2ZW50KSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuZ2FtZVBhZENvbm5lY3RIYW5kbGVyKGV2KTtcbiAgICAgICAgICAgIGNvbnN0IG9uR2FtZVBhZERpc2Nvbm5lY3RlZCA9IChldjogR2FtZXBhZEV2ZW50KSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuZ2FtZVBhZERpc2Nvbm5lY3RIYW5kbGVyKGV2KTtcbiAgICAgICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdnYW1lcGFkY29ubmVjdGVkJywgb25HYW1lUGFkQ29ubmVjdGVkKTtcbiAgICAgICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdnYW1lcGFkZGlzY29ubmVjdGVkJywgb25HYW1lUGFkRGlzY29ubmVjdGVkKTtcbiAgICAgICAgICAgIHRoaXMuZ2FtZVBhZEV2ZW50TGlzdGVuZXJUcmFja2VyLmFkZFVucmVnaXN0ZXJDYWxsYmFjayhcbiAgICAgICAgICAgICAgICAoKSA9PiB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcignZ2FtZXBhZGNvbm5lY3RlZCcsIG9uR2FtZVBhZENvbm5lY3RlZClcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICB0aGlzLmdhbWVQYWRFdmVudExpc3RlbmVyVHJhY2tlci5hZGRVbnJlZ2lzdGVyQ2FsbGJhY2soXG4gICAgICAgICAgICAgICAgKCkgPT4gd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2dhbWVwYWRkaXNjb25uZWN0ZWQnLCBvbkdhbWVQYWREaXNjb25uZWN0ZWQpXG4gICAgICAgICAgICApO1xuICAgICAgICB9IGVsc2UgaWYgKCdXZWJLaXRHYW1lcGFkRXZlbnQnIGluIGJyb3dzZXJXaW5kb3cpIHtcbiAgICAgICAgICAgIGNvbnN0IG9uV2Via2l0R2FtZVBhZENvbm5lY3RlZCA9IChldjogR2FtZXBhZEV2ZW50KSA9PiB0aGlzLmdhbWVQYWRDb25uZWN0SGFuZGxlcihldik7XG4gICAgICAgICAgICBjb25zdCBvbldlYmtpdEdhbWVQYWREaXNjb25uZWN0ZWQgPSAoZXY6IEdhbWVwYWRFdmVudCkgPT4gdGhpcy5nYW1lUGFkRGlzY29ubmVjdEhhbmRsZXIoZXYpO1xuICAgICAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3dlYmtpdGdhbWVwYWRjb25uZWN0ZWQnLCBvbldlYmtpdEdhbWVQYWRDb25uZWN0ZWQpO1xuICAgICAgICAgICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3dlYmtpdGdhbWVwYWRkaXNjb25uZWN0ZWQnLCBvbldlYmtpdEdhbWVQYWREaXNjb25uZWN0ZWQpO1xuICAgICAgICAgICAgdGhpcy5nYW1lUGFkRXZlbnRMaXN0ZW5lclRyYWNrZXIuYWRkVW5yZWdpc3RlckNhbGxiYWNrKFxuICAgICAgICAgICAgICAgICgpID0+IHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCd3ZWJraXRnYW1lcGFkY29ubmVjdGVkJywgb25XZWJraXRHYW1lUGFkQ29ubmVjdGVkKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHRoaXMuZ2FtZVBhZEV2ZW50TGlzdGVuZXJUcmFja2VyLmFkZFVucmVnaXN0ZXJDYWxsYmFjayhcbiAgICAgICAgICAgICAgICAoKSA9PiB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcignd2Via2l0Z2FtZXBhZGRpc2Nvbm5lY3RlZCcsIG9uV2Via2l0R2FtZVBhZERpc2Nvbm5lY3RlZClcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5jb250cm9sbGVycyA9IFtdO1xuICAgICAgICBpZiAobmF2aWdhdG9yLmdldEdhbWVwYWRzKSB7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGdhbWVwYWQgb2YgbmF2aWdhdG9yLmdldEdhbWVwYWRzKCkpIHtcbiAgICAgICAgICAgICAgICBpZiAoZ2FtZXBhZCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmdhbWVQYWRDb25uZWN0SGFuZGxlcihuZXcgR2FtZXBhZEV2ZW50KCdnYW1lcGFkY29ubmVjdGVkJywgeyBnYW1lcGFkIH0pKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBVbnJlZ2lzdGVycyBhbGwgZXZlbnQgaGFuZGxlcnNcbiAgICAgKi9cbiAgICB1bnJlZ2lzdGVyR2FtZVBhZEV2ZW50cygpIHtcbiAgICAgICAgdGhpcy5nYW1lUGFkRXZlbnRMaXN0ZW5lclRyYWNrZXIudW5yZWdpc3RlckFsbCgpO1xuICAgICAgICBmb3IoY29uc3QgY29udHJvbGxlciBvZiB0aGlzLmNvbnRyb2xsZXJzKSB7XG4gICAgICAgICAgICBpZihjb250cm9sbGVyLmlkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLm9uR2FtZXBhZERpc2Nvbm5lY3RlZChjb250cm9sbGVyLmlkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLmNvbnRyb2xsZXJzID0gW107XG4gICAgICAgIHRoaXMub25HYW1lcGFkQ29ubmVjdGVkID0gKCkgPT4geyAvKiAqLyB9O1xuICAgICAgICB0aGlzLm9uR2FtZXBhZERpc2Nvbm5lY3RlZCA9ICgpID0+IHsgLyogKi8gfTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDb25uZWN0cyB0aGUgZ2FtZXBhZCBoYW5kbGVyXG4gICAgICogQHBhcmFtIGdhbWVQYWRFdmVudCAtIHRoZSBhY3RpdmF0aW5nIGdhbWVwYWQgZXZlbnRcbiAgICAgKi9cbiAgICBnYW1lUGFkQ29ubmVjdEhhbmRsZXIoZ2FtZVBhZEV2ZW50OiBHYW1lcGFkRXZlbnQpIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCAnR2FtZXBhZCBjb25uZWN0IGhhbmRsZXInLCA2KTtcbiAgICAgICAgY29uc3QgZ2FtZXBhZCA9IGdhbWVQYWRFdmVudC5nYW1lcGFkO1xuXG4gICAgICAgIGNvbnN0IHRlbXA6IENvbnRyb2xsZXIgPSB7XG4gICAgICAgICAgICBjdXJyZW50U3RhdGU6IGdhbWVwYWQsXG4gICAgICAgICAgICBwcmV2U3RhdGU6IGdhbWVwYWQsXG4gICAgICAgICAgICBpZDogdW5kZWZpbmVkXG4gICAgICAgIH07XG5cbiAgICAgICAgdGhpcy5jb250cm9sbGVycy5wdXNoKHRlbXApO1xuICAgICAgICB0aGlzLmNvbnRyb2xsZXJzW2dhbWVwYWQuaW5kZXhdLmN1cnJlbnRTdGF0ZSA9IGdhbWVwYWQ7XG4gICAgICAgIHRoaXMuY29udHJvbGxlcnNbZ2FtZXBhZC5pbmRleF0ucHJldlN0YXRlID0gZ2FtZXBhZDtcbiAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAnZ2FtZXBhZDogJyArIGdhbWVwYWQuaWQgKyAnIGNvbm5lY3RlZCcsXG4gICAgICAgICAgICA2XG4gICAgICAgICk7XG4gICAgICAgIHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoKCkgPT4gdGhpcy51cGRhdGVTdGF0dXMoKSk7XG4gICAgICAgIHRoaXMub25HYW1lcGFkQ29ubmVjdGVkKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRGlzY29ubmVjdHMgdGhlIGdhbWVwYWQgaGFuZGxlclxuICAgICAqIEBwYXJhbSBnYW1lUGFkRXZlbnQgLSB0aGUgYWN0aXZhdGluZyBnYW1lcGFkIGV2ZW50XG4gICAgICovXG4gICAgZ2FtZVBhZERpc2Nvbm5lY3RIYW5kbGVyKGdhbWVQYWRFdmVudDogR2FtZXBhZEV2ZW50KSB7XG4gICAgICAgIExvZ2dlci5Mb2coTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSwgJ0dhbWVwYWQgZGlzY29ubmVjdCBoYW5kbGVyJywgNik7XG4gICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgJ2dhbWVwYWQ6ICcgKyBnYW1lUGFkRXZlbnQuZ2FtZXBhZC5pZCArICcgZGlzY29ubmVjdGVkJyxcbiAgICAgICAgICAgIDZcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgZGVsZXRlZENvbnRyb2xsZXIgPSB0aGlzLmNvbnRyb2xsZXJzW2dhbWVQYWRFdmVudC5nYW1lcGFkLmluZGV4XTtcbiAgICAgICAgZGVsZXRlIHRoaXMuY29udHJvbGxlcnNbZ2FtZVBhZEV2ZW50LmdhbWVwYWQuaW5kZXhdO1xuICAgICAgICB0aGlzLmNvbnRyb2xsZXJzID0gdGhpcy5jb250cm9sbGVycy5maWx0ZXIoXG4gICAgICAgICAgICAoY29udHJvbGxlcikgPT4gY29udHJvbGxlciAhPT0gdW5kZWZpbmVkXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMub25HYW1lcGFkRGlzY29ubmVjdGVkKGRlbGV0ZWRDb250cm9sbGVyLmlkKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTY2FuIGZvciBjb25uZWN0ZWQgZ2FtZXBhZHNcbiAgICAgKi9cbiAgICBzY2FuR2FtZVBhZHMoKSB7XG4gICAgICAgIGNvbnN0IGdhbWVwYWRzID0gbmF2aWdhdG9yLmdldEdhbWVwYWRzXG4gICAgICAgICAgICA/IG5hdmlnYXRvci5nZXRHYW1lcGFkcygpXG4gICAgICAgICAgICA6IG5hdmlnYXRvci53ZWJraXRHZXRHYW1lcGFkc1xuICAgICAgICAgICAgPyBuYXZpZ2F0b3Iud2Via2l0R2V0R2FtZXBhZHMoKVxuICAgICAgICAgICAgOiBbXTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBnYW1lcGFkcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKGdhbWVwYWRzW2ldICYmIGdhbWVwYWRzW2ldLmluZGV4IGluIHRoaXMuY29udHJvbGxlcnMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmNvbnRyb2xsZXJzW2dhbWVwYWRzW2ldLmluZGV4XS5jdXJyZW50U3RhdGUgPSBnYW1lcGFkc1tpXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFVwZGF0ZXMgdGhlIHN0YXR1cyBvZiB0aGUgZ2FtZXBhZCBhbmQgc2VuZHMgdGhlIGlucHV0c1xuICAgICAqL1xuICAgIHVwZGF0ZVN0YXR1cygpIHtcbiAgICAgICAgdGhpcy5zY2FuR2FtZVBhZHMoKTtcbiAgICAgICAgY29uc3QgdG9TdHJlYW1lckhhbmRsZXJzID1cbiAgICAgICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIudG9TdHJlYW1lckhhbmRsZXJzO1xuXG4gICAgICAgIC8vIEl0ZXJhdGUgb3ZlciBtdWx0aXBsZSBjb250cm9sbGVycyBpbiB0aGUgY2FzZSB0aGUgbXVsdGlwbGUgZ2FtZXBhZHMgYXJlIGNvbm5lY3RlZFxuICAgICAgICBmb3IgKGNvbnN0IGNvbnRyb2xsZXIgb2YgdGhpcy5jb250cm9sbGVycykge1xuICAgICAgICAgICAgLy8gSWYgd2UgaGF2ZW4ndCByZWNlaXZlZCBhbiBpZCAocG9zc2libGUgaWYgdXNpbmcgYW4gb2xkZXIgdmVyc2lvbiBvZiBVRSksIHJldHVybiB0byBvcmlnaW5hbCBmdW5jdGlvbmFsaXR5XG4gICAgICAgICAgICBjb25zdCBjb250cm9sbGVySW5kZXggPSAoY29udHJvbGxlci5pZCA9PT0gdW5kZWZpbmVkKSA/IHRoaXMuY29udHJvbGxlcnMuaW5kZXhPZihjb250cm9sbGVyKSA6IGNvbnRyb2xsZXIuaWQ7XG4gICAgICAgICAgICBjb25zdCBjdXJyZW50U3RhdGUgPSBjb250cm9sbGVyLmN1cnJlbnRTdGF0ZTtcbiAgICAgICAgICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY29udHJvbGxlci5jdXJyZW50U3RhdGUuYnV0dG9ucy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRCdXR0b24gPSBjb250cm9sbGVyLmN1cnJlbnRTdGF0ZS5idXR0b25zW2ldO1xuICAgICAgICAgICAgICAgIGNvbnN0IHByZXZpb3VzQnV0dG9uID0gY29udHJvbGxlci5wcmV2U3RhdGUuYnV0dG9uc1tpXTtcbiAgICAgICAgICAgICAgICBpZiAoY3VycmVudEJ1dHRvbi5wcmVzc2VkKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHByZXNzXG4gICAgICAgICAgICAgICAgICAgIGlmIChpID09IGdhbWVwYWRMYXlvdXQuTGVmdFRyaWdnZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgICAgICAgICAgICAgICAgICAgICBVRXMgbGVmdCBhbmFsb2cgaGFzIGEgYnV0dG9uIGluZGV4IG9mIDVcbiAgICAgICAgICAgICAgICAgICAgICAgIHRvU3RyZWFtZXJIYW5kbGVycy5nZXQoJ0dhbWVwYWRBbmFsb2cnKShbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJvbGxlckluZGV4LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VycmVudEJ1dHRvbi52YWx1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgXSk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoaSA9PSBnYW1lcGFkTGF5b3V0LlJpZ2h0VHJpZ2dlcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gICAgICAgICAgICAgICAgICAgICAgIFVFcyByaWdodCBhbmFsb2cgaGFzIGEgYnV0dG9uIGluZGV4IG9mIDZcbiAgICAgICAgICAgICAgICAgICAgICAgIHRvU3RyZWFtZXJIYW5kbGVycy5nZXQoJ0dhbWVwYWRBbmFsb2cnKShbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29udHJvbGxlckluZGV4LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDYsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VycmVudEJ1dHRvbi52YWx1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgXSk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0b1N0cmVhbWVySGFuZGxlcnMuZ2V0KCdHYW1lcGFkQnV0dG9uUHJlc3NlZCcpKFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sbGVySW5kZXgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmV2aW91c0J1dHRvbi5wcmVzc2VkID8gMSA6IDBcbiAgICAgICAgICAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmICghY3VycmVudEJ1dHRvbi5wcmVzc2VkICYmIHByZXZpb3VzQnV0dG9uLnByZXNzZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gcmVsZWFzZVxuICAgICAgICAgICAgICAgICAgICBpZiAoaSA9PSBnYW1lcGFkTGF5b3V0LkxlZnRUcmlnZ2VyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgICAgICAgICAgICAgICAgICAgICAgVUVzIGxlZnQgYW5hbG9nIGhhcyBhIGJ1dHRvbiBpbmRleCBvZiA1XG4gICAgICAgICAgICAgICAgICAgICAgICB0b1N0cmVhbWVySGFuZGxlcnMuZ2V0KCdHYW1lcGFkQW5hbG9nJykoW1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2xsZXJJbmRleCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA1LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDBcbiAgICAgICAgICAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGkgPT0gZ2FtZXBhZExheW91dC5SaWdodFRyaWdnZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgICAgICAgICAgICAgICAgICAgICBVRXMgcmlnaHQgYW5hbG9nIGhhcyBhIGJ1dHRvbiBpbmRleCBvZiA2XG4gICAgICAgICAgICAgICAgICAgICAgICB0b1N0cmVhbWVySGFuZGxlcnMuZ2V0KCdHYW1lcGFkQW5hbG9nJykoW1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2xsZXJJbmRleCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA2LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDBcbiAgICAgICAgICAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgdG9TdHJlYW1lckhhbmRsZXJzLmdldCgnR2FtZXBhZEJ1dHRvblJlbGVhc2VkJykoW1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRyb2xsZXJJbmRleCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpXG4gICAgICAgICAgICAgICAgICAgICAgICBdKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIEl0ZXJhdGUgb3ZlciBnYW1lcGFkIGF4ZXMgKHdlIHdpbGwgaW5jcmVtZW50IGluIGxvdHMgb2YgMiBhcyB0aGVyZSBpcyAyIGF4ZXMgcGVyIHN0aWNrKVxuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjdXJyZW50U3RhdGUuYXhlcy5sZW5ndGg7IGkgKz0gMikge1xuICAgICAgICAgICAgICAgIC8vIEhvcml6b250YWwgYXhlcyBhcmUgZXZlbiBudW1iZXJlZFxuICAgICAgICAgICAgICAgIGNvbnN0IHggPSBwYXJzZUZsb2F0KGN1cnJlbnRTdGF0ZS5heGVzW2ldLnRvRml4ZWQoNCkpO1xuXG4gICAgICAgICAgICAgICAgLy8gVmVydGljYWwgYXhlcyBhcmUgb2RkIG51bWJlcmVkXG4gICAgICAgICAgICAgICAgLy8gaHR0cHM6Ly93M2MuZ2l0aHViLmlvL2dhbWVwYWQvI3JlbWFwcGluZyBHYW1lcGFkIGJyb3dzZXIgc2lkZSBzdGFuZGFyZCBtYXBwaW5nIGhhcyBwb3NpdGl2ZSBkb3duLCBuZWdhdGl2ZSB1cC4gVGhpcyBpcyBkb3ducmlnaHQgZGlzZ3VzdGluZy4gU28gd2UgZml4IGl0LlxuICAgICAgICAgICAgICAgIGNvbnN0IHkgPSAtcGFyc2VGbG9hdChjdXJyZW50U3RhdGUuYXhlc1tpICsgMV0udG9GaXhlZCg0KSk7XG5cbiAgICAgICAgICAgICAgICAvLyBVRSdzIGFuYWxvZyBheGVzIGZvbGxvdyB0aGUgc2FtZSBvcmRlciBhcyB0aGUgYnJvd3NlcnMsIGJ1dCBzdGFydCBhdCBpbmRleCAxIHNvIHdlIHdpbGwgb2Zmc2V0IGFzIHN1Y2hcbiAgICAgICAgICAgICAgICB0b1N0cmVhbWVySGFuZGxlcnMuZ2V0KCdHYW1lcGFkQW5hbG9nJykoW1xuICAgICAgICAgICAgICAgICAgICBjb250cm9sbGVySW5kZXgsXG4gICAgICAgICAgICAgICAgICAgIGkgKyAxLFxuICAgICAgICAgICAgICAgICAgICB4XG4gICAgICAgICAgICAgICAgXSk7IC8vIEhvcml6b250YWwgYXhlcywgb25seSBvZmZzZXQgYnkgMVxuICAgICAgICAgICAgICAgIHRvU3RyZWFtZXJIYW5kbGVycy5nZXQoJ0dhbWVwYWRBbmFsb2cnKShbXG4gICAgICAgICAgICAgICAgICAgIGNvbnRyb2xsZXJJbmRleCxcbiAgICAgICAgICAgICAgICAgICAgaSArIDIsXG4gICAgICAgICAgICAgICAgICAgIHlcbiAgICAgICAgICAgICAgICBdKTsgLy8gVmVydGljYWwgYXhlcywgb2Zmc2V0IGJ5IHR3byAoMSB0byBtYXRjaCBVRXMgYXhlcyBjb252ZW50aW9uIGFuZCB0aGVuIGFub3RoZXIgMSBmb3IgdGhlIHZlcnRpY2FsIGF4ZXMpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmNvbnRyb2xsZXJzW2NvbnRyb2xsZXJJbmRleF0ucHJldlN0YXRlID0gY3VycmVudFN0YXRlO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLmNvbnRyb2xsZXJzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHRoaXMucmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHRoaXMudXBkYXRlU3RhdHVzKCkpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgb25HYW1lcGFkUmVzcG9uc2VSZWNlaXZlZChnYW1lcGFkSWQ6IG51bWJlcikge1xuICAgICAgICBmb3IoY29uc3QgY29udHJvbGxlciBvZiB0aGlzLmNvbnRyb2xsZXJzKSB7XG4gICAgICAgICAgICBpZihjb250cm9sbGVyLmlkID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICBjb250cm9sbGVyLmlkID0gZ2FtZXBhZElkO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRXZlbnQgdG8gc2VuZCB0aGUgZ2FtZXBhZGNvbm5lY3RlZCBtZXNzYWdlIHRvIHRoZSBhcHBsaWNhdGlvblxuICAgICAqL1xuICAgIG9uR2FtZXBhZENvbm5lY3RlZCgpIHtcbiAgICAgICAgLy8gRGVmYXVsdCBGdW5jdGlvbmFsaXR5OiBEbyBOb3RoaW5nXG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRXZlbnQgdG8gc2VuZCB0aGUgZ2FtZXBhZGRpc2Nvbm5lY3RlZCBtZXNzYWdlIHRvIHRoZSBhcHBsaWNhdGlvblxuICAgICAqL1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICBvbkdhbWVwYWREaXNjb25uZWN0ZWQoY29udHJvbGxlcklkeDogbnVtYmVyKSB7XG4gICAgICAgIC8vIERlZmF1bHQgRnVuY3Rpb25hbGl0eTogRG8gTm90aGluZ1xuICAgIH1cbn1cblxuXG5cbi8qKlxuICogQWRkaXRpb25hbCB0eXBlcyBmb3IgV2luZG93IGFuZCBOYXZpZ2F0b3JcbiAqL1xuZGVjbGFyZSBnbG9iYWwge1xuICAgIGludGVyZmFjZSBXaW5kb3cge1xuICAgICAgICBtb3pSZXF1ZXN0QW5pbWF0aW9uRnJhbWUoY2FsbGJhY2s6IEZyYW1lUmVxdWVzdENhbGxiYWNrKTogbnVtYmVyO1xuICAgICAgICB3ZWJraXRSZXF1ZXN0QW5pbWF0aW9uRnJhbWUoY2FsbGJhY2s6IEZyYW1lUmVxdWVzdENhbGxiYWNrKTogbnVtYmVyO1xuICAgIH1cblxuICAgIGludGVyZmFjZSBOYXZpZ2F0b3Ige1xuICAgICAgICB3ZWJraXRHZXRHYW1lcGFkcygpOiBHYW1lcGFkW107XG4gICAgfVxufVxuXG4vKipcbiAqIEdhbWVwYWQgbGF5b3V0IGNvZGVzIGVudW1cbiAqL1xuZXhwb3J0IGVudW0gZ2FtZXBhZExheW91dCB7XG4gICAgUmlnaHRDbHVzdGVyQm90dG9tQnV0dG9uID0gMCxcbiAgICBSaWdodENsdXN0ZXJSaWdodEJ1dHRvbiA9IDEsXG4gICAgUmlnaHRDbHVzdGVyTGVmdEJ1dHRvbiA9IDIsXG4gICAgUmlnaHRDbHVzdGVyVG9wQnV0dG9uID0gMyxcbiAgICBMZWZ0U2hvdWxkZXIgPSA0LFxuICAgIFJpZ2h0U2hvdWxkZXIgPSA1LFxuICAgIExlZnRUcmlnZ2VyID0gNixcbiAgICBSaWdodFRyaWdnZXIgPSA3LFxuICAgIFNlbGVjdE9yQmFjayA9IDgsXG4gICAgU3RhcnRPckZvcndhcmQgPSA5LFxuICAgIExlZnRBbmFsb2dQcmVzcyA9IDEwLFxuICAgIFJpZ2h0QW5hbG9nUHJlc3MgPSAxMSxcbiAgICBMZWZ0Q2x1c3RlclRvcEJ1dHRvbiA9IDEyLFxuICAgIExlZnRDbHVzdGVyQm90dG9tQnV0dG9uID0gMTMsXG4gICAgTGVmdENsdXN0ZXJMZWZ0QnV0dG9uID0gMTQsXG4gICAgTGVmdENsdXN0ZXJSaWdodEJ1dHRvbiA9IDE1LFxuICAgIENlbnRyZUJ1dHRvbiA9IDE2LFxuICAgIC8vIEF4ZXNcbiAgICBMZWZ0U3RpY2tIb3Jpem9udGFsID0gMCxcbiAgICBMZWZ0U3RpY2tWZXJ0aWNhbCA9IDEsXG4gICAgUmlnaHRTdGlja0hvcml6b250YWwgPSAyLFxuICAgIFJpZ2h0U3RpY2tWZXJ0aWNhbCA9IDNcbn1cbiIsIi8vIENvcHlyaWdodCBFcGljIEdhbWVzLCBJbmMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG5cbmltcG9ydCB7IE1vdXNlQ29udHJvbGxlciB9IGZyb20gJy4vTW91c2VDb250cm9sbGVyJztcbmltcG9ydCB7IExvZ2dlciB9IGZyb20gJy4uL0xvZ2dlci9Mb2dnZXInO1xuaW1wb3J0IHsgSU1vdXNlRXZlbnRzIH0gZnJvbSAnLi9JTW91c2VFdmVudHMnO1xuXG4vKipcbiAqIFZpZGVvIFBsYXllciBtb3VzZSBIb3ZlciBoYW5kbGVyXG4gKi9cbmV4cG9ydCBjbGFzcyBIb3ZlcmluZ01vdXNlRXZlbnRzIGltcGxlbWVudHMgSU1vdXNlRXZlbnRzIHtcbiAgICBtb3VzZUNvbnRyb2xsZXI6IE1vdXNlQ29udHJvbGxlcjtcblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSBtb3VzZUNvbnRyb2xsZXIgLSBNb3VzZSBDb250cm9sbGVyIGluc3RhbmNlXG4gICAgICovXG4gICAgY29uc3RydWN0b3IobW91c2VDb250cm9sbGVyOiBNb3VzZUNvbnRyb2xsZXIpIHtcbiAgICAgICAgdGhpcy5tb3VzZUNvbnRyb2xsZXIgPSBtb3VzZUNvbnRyb2xsZXI7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVW5yZWdpc3RlciBldmVudCBoYW5kbGVyc1xuICAgICAqL1xuICAgIHVucmVnaXN0ZXJNb3VzZUV2ZW50cygpOiB2b2lkIHtcbiAgICAgICAgLy8gZW1wdHkgZm9yIEhvdmVyaW5nTW91c2VFdmVudHMgaW1wbGVtZW50YXRpb25cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGUgdGhlIG1vdXNlIG1vdmUgZXZlbnQsIHNlbmRzIHRoZSBtb3VzZSBkYXRhIHRvIHRoZSBVRSBJbnN0YW5jZVxuICAgICAqIEBwYXJhbSBtb3VzZUV2ZW50IC0gTW91c2UgRXZlbnRcbiAgICAgKi9cbiAgICB1cGRhdGVNb3VzZU1vdmVQb3NpdGlvbihtb3VzZUV2ZW50OiBNb3VzZUV2ZW50KSB7XG4gICAgICAgIGlmICghdGhpcy5tb3VzZUNvbnRyb2xsZXIudmlkZW9FbGVtZW50UHJvdmlkZXIuaXNWaWRlb1JlYWR5KCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBMb2dnZXIuTG9nKExvZ2dlci5HZXRTdGFja1RyYWNlKCksICdNb3VzZU1vdmUnLCA2KTtcbiAgICAgICAgY29uc3QgY29vcmQgPVxuICAgICAgICAgICAgdGhpcy5tb3VzZUNvbnRyb2xsZXIuY29vcmRpbmF0ZUNvbnZlcnRlci5ub3JtYWxpemVBbmRRdWFudGl6ZVVuc2lnbmVkKFxuICAgICAgICAgICAgICAgIG1vdXNlRXZlbnQub2Zmc2V0WCxcbiAgICAgICAgICAgICAgICBtb3VzZUV2ZW50Lm9mZnNldFlcbiAgICAgICAgICAgICk7XG4gICAgICAgIGNvbnN0IGRlbHRhID1cbiAgICAgICAgICAgIHRoaXMubW91c2VDb250cm9sbGVyLmNvb3JkaW5hdGVDb252ZXJ0ZXIubm9ybWFsaXplQW5kUXVhbnRpemVTaWduZWQoXG4gICAgICAgICAgICAgICAgbW91c2VFdmVudC5tb3ZlbWVudFgsXG4gICAgICAgICAgICAgICAgbW91c2VFdmVudC5tb3ZlbWVudFlcbiAgICAgICAgICAgICk7XG4gICAgICAgIGNvbnN0IHRvU3RyZWFtZXJIYW5kbGVycyA9XG4gICAgICAgICAgICB0aGlzLm1vdXNlQ29udHJvbGxlci50b1N0cmVhbWVyTWVzc2FnZXNQcm92aWRlci50b1N0cmVhbWVySGFuZGxlcnM7XG4gICAgICAgIHRvU3RyZWFtZXJIYW5kbGVycy5nZXQoJ01vdXNlTW92ZScpKFtcbiAgICAgICAgICAgIGNvb3JkLngsXG4gICAgICAgICAgICBjb29yZC55LFxuICAgICAgICAgICAgZGVsdGEueCxcbiAgICAgICAgICAgIGRlbHRhLnlcbiAgICAgICAgXSk7XG4gICAgICAgIG1vdXNlRXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGUgdGhlIG1vdXNlIERvd24gZXZlbnQsIHNlbmRzIHRoZSBtb3VzZSBkYXRhIHRvIHRoZSBVRSBJbnN0YW5jZVxuICAgICAqIEBwYXJhbSBtb3VzZUV2ZW50IC0gTW91c2UgRXZlbnRcbiAgICAgKi9cbiAgICBoYW5kbGVNb3VzZURvd24obW91c2VFdmVudDogTW91c2VFdmVudCkge1xuICAgICAgICBpZiAoIXRoaXMubW91c2VDb250cm9sbGVyLnZpZGVvRWxlbWVudFByb3ZpZGVyLmlzVmlkZW9SZWFkeSgpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCAnb25Nb3VzZSBEb3duJywgNik7XG4gICAgICAgIGNvbnN0IGNvb3JkID1cbiAgICAgICAgICAgIHRoaXMubW91c2VDb250cm9sbGVyLmNvb3JkaW5hdGVDb252ZXJ0ZXIubm9ybWFsaXplQW5kUXVhbnRpemVVbnNpZ25lZChcbiAgICAgICAgICAgICAgICBtb3VzZUV2ZW50Lm9mZnNldFgsXG4gICAgICAgICAgICAgICAgbW91c2VFdmVudC5vZmZzZXRZXG4gICAgICAgICAgICApO1xuICAgICAgICBjb25zdCB0b1N0cmVhbWVySGFuZGxlcnMgPVxuICAgICAgICAgICAgdGhpcy5tb3VzZUNvbnRyb2xsZXIudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIudG9TdHJlYW1lckhhbmRsZXJzO1xuICAgICAgICB0b1N0cmVhbWVySGFuZGxlcnMuZ2V0KCdNb3VzZURvd24nKShbXG4gICAgICAgICAgICBtb3VzZUV2ZW50LmJ1dHRvbixcbiAgICAgICAgICAgIGNvb3JkLngsXG4gICAgICAgICAgICBjb29yZC55XG4gICAgICAgIF0pO1xuICAgICAgICBtb3VzZUV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSGFuZGxlIHRoZSBtb3VzZSBVcCBldmVudCwgc2VuZHMgdGhlIG1vdXNlIGRhdGEgdG8gdGhlIFVFIEluc3RhbmNlXG4gICAgICogQHBhcmFtIG1vdXNlRXZlbnQgLSBNb3VzZSBFdmVudFxuICAgICAqL1xuICAgIGhhbmRsZU1vdXNlVXAobW91c2VFdmVudDogTW91c2VFdmVudCkge1xuICAgICAgICBpZiAoIXRoaXMubW91c2VDb250cm9sbGVyLnZpZGVvRWxlbWVudFByb3ZpZGVyLmlzVmlkZW9SZWFkeSgpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCAnb25Nb3VzZSBVcCcsIDYpO1xuICAgICAgICBjb25zdCBjb29yZCA9XG4gICAgICAgICAgICB0aGlzLm1vdXNlQ29udHJvbGxlci5jb29yZGluYXRlQ29udmVydGVyLm5vcm1hbGl6ZUFuZFF1YW50aXplVW5zaWduZWQoXG4gICAgICAgICAgICAgICAgbW91c2VFdmVudC5vZmZzZXRYLFxuICAgICAgICAgICAgICAgIG1vdXNlRXZlbnQub2Zmc2V0WVxuICAgICAgICAgICAgKTtcbiAgICAgICAgY29uc3QgdG9TdHJlYW1lckhhbmRsZXJzID1cbiAgICAgICAgICAgIHRoaXMubW91c2VDb250cm9sbGVyLnRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyLnRvU3RyZWFtZXJIYW5kbGVycztcbiAgICAgICAgdG9TdHJlYW1lckhhbmRsZXJzLmdldCgnTW91c2VVcCcpKFtcbiAgICAgICAgICAgIG1vdXNlRXZlbnQuYnV0dG9uLFxuICAgICAgICAgICAgY29vcmQueCxcbiAgICAgICAgICAgIGNvb3JkLnlcbiAgICAgICAgXSk7XG4gICAgICAgIG1vdXNlRXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDb25zdW1lcyB0aGUgbW91c2UgY29udGV4dCBldmVudC4gVGhlIFVFIGluc3RhbmNlIGhhcyBubyBlcXVpdmFsZW50IGFuZCBkb2Vzbid0IG5lZWQgdG8gYmUgaW5mb3JtZWQuXG4gICAgICogQHBhcmFtIG1vdXNlRXZlbnQgLSBNb3VzZSBFdmVudFxuICAgICAqL1xuICAgIGhhbmRsZUNvbnRleHRNZW51KG1vdXNlRXZlbnQ6IE1vdXNlRXZlbnQpIHtcbiAgICAgICAgaWYgKCF0aGlzLm1vdXNlQ29udHJvbGxlci52aWRlb0VsZW1lbnRQcm92aWRlci5pc1ZpZGVvUmVhZHkoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIG1vdXNlRXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGUgdGhlIG1vdXNlIHdoZWVsIGV2ZW50LCBzZW5kcyB0aGUgbW91c2Ugd2hlZWwgZGF0YSB0byB0aGUgVUUgSW5zdGFuY2VcbiAgICAgKiBAcGFyYW0gd2hlZWxFdmVudCAtIE1vdXNlIEV2ZW50XG4gICAgICovXG4gICAgaGFuZGxlTW91c2VXaGVlbCh3aGVlbEV2ZW50OiBXaGVlbEV2ZW50KSB7XG4gICAgICAgIGlmICghdGhpcy5tb3VzZUNvbnRyb2xsZXIudmlkZW9FbGVtZW50UHJvdmlkZXIuaXNWaWRlb1JlYWR5KCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBjb29yZCA9XG4gICAgICAgICAgICB0aGlzLm1vdXNlQ29udHJvbGxlci5jb29yZGluYXRlQ29udmVydGVyLm5vcm1hbGl6ZUFuZFF1YW50aXplVW5zaWduZWQoXG4gICAgICAgICAgICAgICAgd2hlZWxFdmVudC5vZmZzZXRYLFxuICAgICAgICAgICAgICAgIHdoZWVsRXZlbnQub2Zmc2V0WVxuICAgICAgICAgICAgKTtcbiAgICAgICAgY29uc3QgdG9TdHJlYW1lckhhbmRsZXJzID1cbiAgICAgICAgICAgIHRoaXMubW91c2VDb250cm9sbGVyLnRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyLnRvU3RyZWFtZXJIYW5kbGVycztcbiAgICAgICAgdG9TdHJlYW1lckhhbmRsZXJzLmdldCgnTW91c2VXaGVlbCcpKFtcbiAgICAgICAgICAgIHdoZWVsRXZlbnQud2hlZWxEZWx0YSxcbiAgICAgICAgICAgIGNvb3JkLngsXG4gICAgICAgICAgICBjb29yZC55XG4gICAgICAgIF0pO1xuICAgICAgICB3aGVlbEV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSGFuZGxlIHRoZSBtb3VzZSBkb3VibGUgY2xpY2sgZXZlbnQsIHNlbmRzIHRoZSBtb3VzZSBkYXRhIHRvIHRoZSBVRSBJbnN0YW5jZVxuICAgICAqIEBwYXJhbSBtb3VzZUV2ZW50IC0gTW91c2UgRXZlbnRcbiAgICAgKi9cbiAgICBoYW5kbGVNb3VzZURvdWJsZShtb3VzZUV2ZW50OiBNb3VzZUV2ZW50KSB7XG4gICAgICAgIGlmICghdGhpcy5tb3VzZUNvbnRyb2xsZXIudmlkZW9FbGVtZW50UHJvdmlkZXIuaXNWaWRlb1JlYWR5KCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBjb29yZCA9XG4gICAgICAgICAgICB0aGlzLm1vdXNlQ29udHJvbGxlci5jb29yZGluYXRlQ29udmVydGVyLm5vcm1hbGl6ZUFuZFF1YW50aXplVW5zaWduZWQoXG4gICAgICAgICAgICAgICAgbW91c2VFdmVudC5vZmZzZXRYLFxuICAgICAgICAgICAgICAgIG1vdXNlRXZlbnQub2Zmc2V0WVxuICAgICAgICAgICAgKTtcbiAgICAgICAgY29uc3QgdG9TdHJlYW1lckhhbmRsZXJzID1cbiAgICAgICAgICAgIHRoaXMubW91c2VDb250cm9sbGVyLnRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyLnRvU3RyZWFtZXJIYW5kbGVycztcbiAgICAgICAgdG9TdHJlYW1lckhhbmRsZXJzLmdldCgnTW91c2VEb3VibGUnKShbXG4gICAgICAgICAgICBtb3VzZUV2ZW50LmJ1dHRvbixcbiAgICAgICAgICAgIGNvb3JkLngsXG4gICAgICAgICAgICBjb29yZC55XG4gICAgICAgIF0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEhhbmRsZSB0aGUgcHJlc3MgbW91c2UgYnV0dG9ucyBldmVudCwgc2VuZHMgdGhlIG1vdXNlIGRhdGEgdG8gdGhlIFVFIEluc3RhbmNlXG4gICAgICogQHBhcmFtIG1vdXNlRXZlbnQgLSBNb3VzZSBFdmVudFxuICAgICAqL1xuICAgIGhhbmRsZVByZXNzTW91c2VCdXR0b25zKG1vdXNlRXZlbnQ6IE1vdXNlRXZlbnQpIHtcbiAgICAgICAgaWYgKCF0aGlzLm1vdXNlQ29udHJvbGxlci52aWRlb0VsZW1lbnRQcm92aWRlci5pc1ZpZGVvUmVhZHkoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIExvZ2dlci5Mb2coTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSwgJ29uTW91c2UgcHJlc3MnLCA2KTtcbiAgICAgICAgdGhpcy5tb3VzZUNvbnRyb2xsZXIucHJlc3NNb3VzZUJ1dHRvbnMoXG4gICAgICAgICAgICBtb3VzZUV2ZW50LmJ1dHRvbnMsXG4gICAgICAgICAgICBtb3VzZUV2ZW50Lm9mZnNldFgsXG4gICAgICAgICAgICBtb3VzZUV2ZW50Lm9mZnNldFlcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGUgdGhlIHJlbGVhc2UgbW91c2UgYnV0dG9ucyBldmVudCwgc2VuZHMgdGhlIG1vdXNlIGRhdGEgdG8gdGhlIFVFIEluc3RhbmNlXG4gICAgICogQHBhcmFtIG1vdXNlRXZlbnQgLSBNb3VzZSBFdmVudFxuICAgICAqL1xuICAgIGhhbmRsZVJlbGVhc2VNb3VzZUJ1dHRvbnMobW91c2VFdmVudDogTW91c2VFdmVudCkge1xuICAgICAgICBpZiAoIXRoaXMubW91c2VDb250cm9sbGVyLnZpZGVvRWxlbWVudFByb3ZpZGVyLmlzVmlkZW9SZWFkeSgpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCAnb25Nb3VzZSByZWxlYXNlJywgNik7XG4gICAgICAgIHRoaXMubW91c2VDb250cm9sbGVyLnJlbGVhc2VNb3VzZUJ1dHRvbnMoXG4gICAgICAgICAgICBtb3VzZUV2ZW50LmJ1dHRvbnMsXG4gICAgICAgICAgICBtb3VzZUV2ZW50Lm9mZnNldFgsXG4gICAgICAgICAgICBtb3VzZUV2ZW50Lm9mZnNldFlcbiAgICAgICAgKTtcbiAgICB9XG59XG4iLCIvLyBDb3B5cmlnaHQgRXBpYyBHYW1lcywgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuXG5pbXBvcnQgeyBGYWtlVG91Y2hDb250cm9sbGVyIH0gZnJvbSAnLi9GYWtlVG91Y2hDb250cm9sbGVyJztcbmltcG9ydCB7IEtleWJvYXJkQ29udHJvbGxlciB9IGZyb20gJy4vS2V5Ym9hcmRDb250cm9sbGVyJztcbmltcG9ydCB7IE1vdXNlQ29udHJvbGxlciB9IGZyb20gJy4vTW91c2VDb250cm9sbGVyJztcbmltcG9ydCB7IFRvdWNoQ29udHJvbGxlciB9IGZyb20gJy4vVG91Y2hDb250cm9sbGVyJztcbmltcG9ydCB7IEdhbWVQYWRDb250cm9sbGVyIH0gZnJvbSAnLi9HYW1lcGFkQ29udHJvbGxlcic7XG5pbXBvcnQgeyBDb25maWcsIENvbnRyb2xTY2hlbWVUeXBlIH0gZnJvbSAnLi4vQ29uZmlnL0NvbmZpZyc7XG5pbXBvcnQgeyBMb2dnZXIgfSBmcm9tICcuLi9Mb2dnZXIvTG9nZ2VyJztcbmltcG9ydCB7IENvb3JkaW5hdGVDb252ZXJ0ZXIgfSBmcm9tICcuLi9VdGlsL0Nvb3JkaW5hdGVDb252ZXJ0ZXInO1xuaW1wb3J0IHsgU3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIgfSBmcm9tICcuLi9VZUluc3RhbmNlTWVzc2FnZS9TdHJlYW1NZXNzYWdlQ29udHJvbGxlcic7XG5pbXBvcnQgeyBWaWRlb1BsYXllciB9IGZyb20gJy4uL1ZpZGVvUGxheWVyL1ZpZGVvUGxheWVyJztcblxuLyoqXG4gKiBDbGFzcyBmb3IgbWFraW5nIGFuZCBzZXR0aW5nIHVwIGlucHV0IGNsYXNzIHR5cGVzXG4gKi9cbmV4cG9ydCBjbGFzcyBJbnB1dENsYXNzZXNGYWN0b3J5IHtcbiAgICB0b1N0cmVhbWVyTWVzc2FnZXNQcm92aWRlcjogU3RyZWFtTWVzc2FnZUNvbnRyb2xsZXI7XG4gICAgdmlkZW9FbGVtZW50UHJvdmlkZXI6IFZpZGVvUGxheWVyO1xuICAgIGNvb3JkaW5hdGVDb252ZXJ0ZXI6IENvb3JkaW5hdGVDb252ZXJ0ZXI7XG4gICAgYWN0aXZlS2V5czogQWN0aXZlS2V5cyA9IG5ldyBBY3RpdmVLZXlzKCk7XG5cbiAgICAvKipcbiAgICAgKiBAcGFyYW0gdG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIgLSBTdHJlYW0gbWVzc2FnZSBpbnN0YW5jZVxuICAgICAqIEBwYXJhbSB2aWRlb0VsZW1lbnRQcm92aWRlciAtIFZpZGVvIFBsYXllciBpbnN0YW5jZVxuICAgICAqIEBwYXJhbSBjb29yZGluYXRlQ29udmVydGVyIC0gQSBjb29yZGluYXRlQ29udmVydGVyIGluc3RhbmNlXG4gICAgICovXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIHRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyOiBTdHJlYW1NZXNzYWdlQ29udHJvbGxlcixcbiAgICAgICAgdmlkZW9FbGVtZW50UHJvdmlkZXI6IFZpZGVvUGxheWVyLFxuICAgICAgICBjb29yZGluYXRlQ29udmVydGVyOiBDb29yZGluYXRlQ29udmVydGVyXG4gICAgKSB7XG4gICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIgPSB0b1N0cmVhbWVyTWVzc2FnZXNQcm92aWRlcjtcbiAgICAgICAgdGhpcy52aWRlb0VsZW1lbnRQcm92aWRlciA9IHZpZGVvRWxlbWVudFByb3ZpZGVyO1xuICAgICAgICB0aGlzLmNvb3JkaW5hdGVDb252ZXJ0ZXIgPSBjb29yZGluYXRlQ29udmVydGVyO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlZ2lzdGVycyBicm93c2VyIGtleSBldmVudHMuXG4gICAgICovXG4gICAgcmVnaXN0ZXJLZXlCb2FyZChjb25maWc6IENvbmZpZykge1xuICAgICAgICBMb2dnZXIuTG9nKExvZ2dlci5HZXRTdGFja1RyYWNlKCksICdSZWdpc3RlciBLZXlib2FyZCBFdmVudHMnLCA3KTtcbiAgICAgICAgY29uc3Qga2V5Ym9hcmRDb250cm9sbGVyID0gbmV3IEtleWJvYXJkQ29udHJvbGxlcihcbiAgICAgICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIsXG4gICAgICAgICAgICBjb25maWcsXG4gICAgICAgICAgICB0aGlzLmFjdGl2ZUtleXNcbiAgICAgICAgKTtcbiAgICAgICAga2V5Ym9hcmRDb250cm9sbGVyLnJlZ2lzdGVyS2V5Qm9hcmRFdmVudHMoKTtcbiAgICAgICAgcmV0dXJuIGtleWJvYXJkQ29udHJvbGxlcjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiByZWdpc3RlciBtb3VzZSBldmVudHMgYmFzZWQgb24gYSBjb250cm9sIHR5cGVcbiAgICAgKiBAcGFyYW0gY29udHJvbFNjaGVtZSAtIGlmIHRoZSBtb3VzZSBpcyBlaXRoZXIgaG92ZXJpbmcgb3IgbG9ja2VkXG4gICAgICovXG4gICAgcmVnaXN0ZXJNb3VzZShjb250cm9sU2NoZW1lOiBDb250cm9sU2NoZW1lVHlwZSkge1xuICAgICAgICBMb2dnZXIuTG9nKExvZ2dlci5HZXRTdGFja1RyYWNlKCksICdSZWdpc3RlciBNb3VzZSBFdmVudHMnLCA3KTtcbiAgICAgICAgY29uc3QgbW91c2VDb250cm9sbGVyID0gbmV3IE1vdXNlQ29udHJvbGxlcihcbiAgICAgICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIsXG4gICAgICAgICAgICB0aGlzLnZpZGVvRWxlbWVudFByb3ZpZGVyLFxuICAgICAgICAgICAgdGhpcy5jb29yZGluYXRlQ29udmVydGVyLFxuICAgICAgICAgICAgdGhpcy5hY3RpdmVLZXlzXG4gICAgICAgICk7XG5cbiAgICAgICAgc3dpdGNoIChjb250cm9sU2NoZW1lKSB7XG4gICAgICAgICAgICBjYXNlIENvbnRyb2xTY2hlbWVUeXBlLkxvY2tlZE1vdXNlOlxuICAgICAgICAgICAgICAgIG1vdXNlQ29udHJvbGxlci5yZWdpc3RlckxvY2tlZE1vdXNlRXZlbnRzKG1vdXNlQ29udHJvbGxlcik7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIENvbnRyb2xTY2hlbWVUeXBlLkhvdmVyaW5nTW91c2U6XG4gICAgICAgICAgICAgICAgbW91c2VDb250cm9sbGVyLnJlZ2lzdGVySG92ZXJpbmdNb3VzZUV2ZW50cyhtb3VzZUNvbnRyb2xsZXIpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICBMb2dnZXIuSW5mbyhcbiAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICAgICAgJ3Vua25vd24gQ29udHJvbCBTY2hlbWUgVHlwZSBEZWZhdWx0aW5nIHRvIExvY2tlZCBNb3VzZSBFdmVudHMnXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBtb3VzZUNvbnRyb2xsZXIucmVnaXN0ZXJMb2NrZWRNb3VzZUV2ZW50cyhtb3VzZUNvbnRyb2xsZXIpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG1vdXNlQ29udHJvbGxlcjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiByZWdpc3RlciB0b3VjaCBldmVudHNcbiAgICAgKiBAcGFyYW0gZmFrZU1vdXNlVG91Y2ggLSB0aGUgZmFrZWQgbW91c2UgdG91Y2ggZXZlbnRcbiAgICAgKi9cbiAgICByZWdpc3RlclRvdWNoKFxuICAgICAgICBmYWtlTW91c2VUb3VjaDogYm9vbGVhbixcbiAgICAgICAgdmlkZW9FbGVtZW50UGFyZW50Q2xpZW50UmVjdDogRE9NUmVjdFxuICAgICkge1xuICAgICAgICBMb2dnZXIuTG9nKExvZ2dlci5HZXRTdGFja1RyYWNlKCksICdSZWdpc3RlcmluZyBUb3VjaCcsIDYpO1xuICAgICAgICBpZiAoZmFrZU1vdXNlVG91Y2gpIHtcbiAgICAgICAgICAgIGNvbnN0IGZha2VUb3VjaENvbnRyb2xsZXIgPSBuZXcgRmFrZVRvdWNoQ29udHJvbGxlcihcbiAgICAgICAgICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyLFxuICAgICAgICAgICAgICAgIHRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIsXG4gICAgICAgICAgICAgICAgdGhpcy5jb29yZGluYXRlQ29udmVydGVyXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgZmFrZVRvdWNoQ29udHJvbGxlci5zZXRWaWRlb0VsZW1lbnRQYXJlbnRDbGllbnRSZWN0KFxuICAgICAgICAgICAgICAgIHZpZGVvRWxlbWVudFBhcmVudENsaWVudFJlY3RcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICByZXR1cm4gZmFrZVRvdWNoQ29udHJvbGxlcjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgVG91Y2hDb250cm9sbGVyKFxuICAgICAgICAgICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIsXG4gICAgICAgICAgICAgICAgdGhpcy52aWRlb0VsZW1lbnRQcm92aWRlcixcbiAgICAgICAgICAgICAgICB0aGlzLmNvb3JkaW5hdGVDb252ZXJ0ZXJcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiByZWdpc3RlcnMgYSBnYW1lcGFkXG4gICAgICovXG4gICAgcmVnaXN0ZXJHYW1lUGFkKCkge1xuICAgICAgICBMb2dnZXIuTG9nKExvZ2dlci5HZXRTdGFja1RyYWNlKCksICdSZWdpc3RlciBHYW1lIFBhZCcsIDcpO1xuICAgICAgICBjb25zdCBnYW1lUGFkQ29udHJvbGxlciA9IG5ldyBHYW1lUGFkQ29udHJvbGxlcihcbiAgICAgICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXJcbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIGdhbWVQYWRDb250cm9sbGVyO1xuICAgIH1cbn1cblxuLyoqXG4gKiBBIGNsYXNzIHRoYXQga2VlcHMgdHJhY2sgb2YgY3VycmVudCBhY3RpdmUga2V5c1xuICovXG5leHBvcnQgY2xhc3MgQWN0aXZlS2V5cyB7XG4gICAgYWN0aXZlS2V5czogQXJyYXk8bnVtYmVyPiA9IFtdO1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLmFjdGl2ZUtleXMgPSBbXTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgdGhlIGN1cnJlbnQgYXJyYXkgb2YgYWN0aXZlIGtleXNcbiAgICAgKiBAcmV0dXJucyAtIGFuIGFycmF5IG9mIGFjdGl2ZSBrZXlzXG4gICAgICovXG4gICAgZ2V0QWN0aXZlS2V5cygpOiBudW1iZXJbXSB7XG4gICAgICAgIHJldHVybiB0aGlzLmFjdGl2ZUtleXM7XG4gICAgfVxufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuaW1wb3J0IHsgU3BlY2lhbEtleUNvZGVzIH0gZnJvbSAnLi9TcGVjaWFsS2V5Q29kZXMnO1xuaW1wb3J0IHsgTG9nZ2VyIH0gZnJvbSAnLi4vTG9nZ2VyL0xvZ2dlcic7XG5pbXBvcnQgeyBBY3RpdmVLZXlzIH0gZnJvbSAnLi9JbnB1dENsYXNzZXNGYWN0b3J5JztcbmltcG9ydCB7IFN0cmVhbU1lc3NhZ2VDb250cm9sbGVyIH0gZnJvbSAnLi4vVWVJbnN0YW5jZU1lc3NhZ2UvU3RyZWFtTWVzc2FnZUNvbnRyb2xsZXInO1xuaW1wb3J0IHsgQ29uZmlnLCBGbGFncyB9IGZyb20gJy4uL0NvbmZpZy9Db25maWcnO1xuaW1wb3J0IHsgRXZlbnRMaXN0ZW5lclRyYWNrZXIgfSBmcm9tICcuLi9VdGlsL0V2ZW50TGlzdGVuZXJUcmFja2VyJztcblxuaW50ZXJmYWNlIElDb2RlVG9LZXlDb2RlIHtcbiAgICBba2V5OiBzdHJpbmddOiBudW1iZXI7XG59XG5cbi8qKlxuICogSGFuZGxlcyB0aGUgS2V5Ym9hcmQgSW5wdXRzIGZvciB0aGUgZG9jdW1lbnRcbiAqL1xuZXhwb3J0IGNsYXNzIEtleWJvYXJkQ29udHJvbGxlciB7XG4gICAgdG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXI6IFN0cmVhbU1lc3NhZ2VDb250cm9sbGVyO1xuICAgIGFjdGl2ZUtleXNQcm92aWRlcjogQWN0aXZlS2V5cztcbiAgICBjb25maWc6IENvbmZpZztcblxuICAgIC8vIFV0aWxpdHkgZm9yIGtlZXBpbmcgdHJhY2sgb2YgZXZlbnQgaGFuZGxlcnMgYW5kIHVucmVnaXN0ZXJpbmcgdGhlbVxuICAgIHByaXZhdGUga2V5Ym9hcmRFdmVudExpc3RlbmVyVHJhY2tlciA9IG5ldyBFdmVudExpc3RlbmVyVHJhY2tlcigpO1xuXG4gICAgLypcbiAgICAgKiBOZXcgYnJvd3NlciBBUElzIGhhdmUgbW92ZWQgYXdheSBmcm9tIEtleWJvYXJkRXZlbnQua2V5Q29kZSB0byBLZXlib2FyZEV2ZW50LkNvZGUuXG4gICAgICogRm9yIGRldGFpbHMgc2VlOiBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9BUEkvS2V5Ym9hcmRFdmVudC9rZXlDb2RlI2NvbnN0YW50c19mb3Jfa2V5Y29kZV92YWx1ZVxuICAgICAqIFdlIHN0aWxsIHVzZSBvbGQgS2V5Ym9hcmRFdmVudC5rZXlDb2RlIGludGVnZXJzIGluIHRoZSBVRSBDKysgc2lkZSwgc28gd2UgbmVlZCBhIHdheSB0byBtYXAgdGhlIG5ld1xuICAgICAqIHN0cmluZy1iYXNlZCBLZXlib2FyZEV2ZW50LkNvZGUgdG8gdGhlIG9sZCBpbnRlZ2Vycy5cbiAgICAgKi9cbiAgICBDb2RlVG9LZXlDb2RlOiBJQ29kZVRvS2V5Q29kZSA9IHtcbiAgICAgICAgRXNjYXBlOiAyNyxcbiAgICAgICAgRGlnaXQwOiA0OCxcbiAgICAgICAgRGlnaXQxOiA0OSxcbiAgICAgICAgRGlnaXQyOiA1MCxcbiAgICAgICAgRGlnaXQzOiA1MSxcbiAgICAgICAgRGlnaXQ0OiA1MixcbiAgICAgICAgRGlnaXQ1OiA1MyxcbiAgICAgICAgRGlnaXQ2OiA1NCxcbiAgICAgICAgRGlnaXQ3OiA1NSxcbiAgICAgICAgRGlnaXQ4OiA1NixcbiAgICAgICAgRGlnaXQ5OiA1NyxcbiAgICAgICAgTWludXM6IDE3MyxcbiAgICAgICAgRXF1YWw6IDE4NyxcbiAgICAgICAgQmFja3NwYWNlOiA4LFxuICAgICAgICBUYWI6IDksXG4gICAgICAgIEtleVE6IDgxLFxuICAgICAgICBLZXlXOiA4NyxcbiAgICAgICAgS2V5RTogNjksXG4gICAgICAgIEtleVI6IDgyLFxuICAgICAgICBLZXlUOiA4NCxcbiAgICAgICAgS2V5WTogODksXG4gICAgICAgIEtleVU6IDg1LFxuICAgICAgICBLZXlJOiA3MyxcbiAgICAgICAgS2V5TzogNzksXG4gICAgICAgIEtleVA6IDgwLFxuICAgICAgICBCcmFja2V0TGVmdDogMjE5LFxuICAgICAgICBCcmFja2V0UmlnaHQ6IDIyMSxcbiAgICAgICAgRW50ZXI6IDEzLFxuICAgICAgICBDb250cm9sTGVmdDogMTcsXG4gICAgICAgIEtleUE6IDY1LFxuICAgICAgICBLZXlTOiA4MyxcbiAgICAgICAgS2V5RDogNjgsXG4gICAgICAgIEtleUY6IDcwLFxuICAgICAgICBLZXlHOiA3MSxcbiAgICAgICAgS2V5SDogNzIsXG4gICAgICAgIEtleUo6IDc0LFxuICAgICAgICBLZXlLOiA3NSxcbiAgICAgICAgS2V5TDogNzYsXG4gICAgICAgIFNlbWljb2xvbjogMTg2LFxuICAgICAgICBRdW90ZTogMjIyLFxuICAgICAgICBCYWNrcXVvdGU6IDE5MixcbiAgICAgICAgU2hpZnRMZWZ0OiAxNixcbiAgICAgICAgQmFja3NsYXNoOiAyMjAsXG4gICAgICAgIEtleVo6IDkwLFxuICAgICAgICBLZXlYOiA4OCxcbiAgICAgICAgS2V5QzogNjcsXG4gICAgICAgIEtleVY6IDg2LFxuICAgICAgICBLZXlCOiA2NixcbiAgICAgICAgS2V5TjogNzgsXG4gICAgICAgIEtleU06IDc3LFxuICAgICAgICBDb21tYTogMTg4LFxuICAgICAgICBQZXJpb2Q6IDE5MCxcbiAgICAgICAgU2xhc2g6IDE5MSxcbiAgICAgICAgU2hpZnRSaWdodDogMjUzLFxuICAgICAgICBBbHRMZWZ0OiAxOCxcbiAgICAgICAgU3BhY2U6IDMyLFxuICAgICAgICBDYXBzTG9jazogMjAsXG4gICAgICAgIEYxOiAxMTIsXG4gICAgICAgIEYyOiAxMTMsXG4gICAgICAgIEYzOiAxMTQsXG4gICAgICAgIEY0OiAxMTUsXG4gICAgICAgIEY1OiAxMTYsXG4gICAgICAgIEY2OiAxMTcsXG4gICAgICAgIEY3OiAxMTgsXG4gICAgICAgIEY4OiAxMTksXG4gICAgICAgIEY5OiAxMjAsXG4gICAgICAgIEYxMDogMTIxLFxuICAgICAgICBGMTE6IDEyMixcbiAgICAgICAgRjEyOiAxMjMsXG4gICAgICAgIFBhdXNlOiAxOSxcbiAgICAgICAgU2Nyb2xsTG9jazogMTQ1LFxuICAgICAgICBOdW1wYWREaXZpZGU6IDExMSxcbiAgICAgICAgTnVtcGFkTXVsdGlwbHk6IDEwNixcbiAgICAgICAgTnVtcGFkU3VidHJhY3Q6IDEwOSxcbiAgICAgICAgTnVtcGFkQWRkOiAxMDcsXG4gICAgICAgIE51bXBhZERlY2ltYWw6IDExMCxcbiAgICAgICAgTnVtcGFkOTogMTA1LFxuICAgICAgICBOdW1wYWQ4OiAxMDQsXG4gICAgICAgIE51bXBhZDc6IDEwMyxcbiAgICAgICAgTnVtcGFkNjogMTAyLFxuICAgICAgICBOdW1wYWQ1OiAxMDEsXG4gICAgICAgIE51bXBhZDQ6IDEwMCxcbiAgICAgICAgTnVtcGFkMzogOTksXG4gICAgICAgIE51bXBhZDI6IDk4LFxuICAgICAgICBOdW1wYWQxOiA5NyxcbiAgICAgICAgTnVtcGFkMDogOTYsXG4gICAgICAgIE51bUxvY2s6IDE0NCxcbiAgICAgICAgQ29udHJvbFJpZ2h0OiAyNTQsXG4gICAgICAgIEFsdFJpZ2h0OiAyNTUsXG4gICAgICAgIEhvbWU6IDM2LFxuICAgICAgICBFbmQ6IDM1LFxuICAgICAgICBBcnJvd1VwOiAzOCxcbiAgICAgICAgQXJyb3dMZWZ0OiAzNyxcbiAgICAgICAgQXJyb3dSaWdodDogMzksXG4gICAgICAgIEFycm93RG93bjogNDAsXG4gICAgICAgIFBhZ2VVcDogMzMsXG4gICAgICAgIFBhZ2VEb3duOiAzNCxcbiAgICAgICAgSW5zZXJ0OiA0NSxcbiAgICAgICAgRGVsZXRlOiA0NixcbiAgICAgICAgQ29udGV4dE1lbnU6IDkzXG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSB0b1N0cmVhbWVyTWVzc2FnZXNQcm92aWRlciBTdHJlYW0gbWVzc2FnZSBwcm92aWRlciBjbGFzcyBvYmplY3RcbiAgICAgKiBAcGFyYW0gY29uZmlnIFRoZSBhcHBsaWNhdGlvbnMgY29uZmlndXJhdGlvbi4gV2UncmUgaW50ZXJlc3RlZCBpbiB0aGUgc3VwcHJlc3MgYnJvd3NlciBrZXlzIG9wdGlvblxuICAgICAqIEBwYXJhbSBhY3RpdmVLZXlzUHJvdmlkZXIgQWN0aXZlIGtleXMgcHJvdmlkZXIgY2xhc3Mgb2JqZWN0XG4gICAgICovXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIHRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyOiBTdHJlYW1NZXNzYWdlQ29udHJvbGxlcixcbiAgICAgICAgY29uZmlnOiBDb25maWcsXG4gICAgICAgIGFjdGl2ZUtleXNQcm92aWRlcjogQWN0aXZlS2V5c1xuICAgICkge1xuICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyID0gdG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXI7XG4gICAgICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICAgICAgICB0aGlzLmFjdGl2ZUtleXNQcm92aWRlciA9IGFjdGl2ZUtleXNQcm92aWRlcjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZWdpc3RlcnMgZG9jdW1lbnQga2V5Ym9hcmQgZXZlbnRzIHdpdGggdGhlIGNvbnRyb2xsZXJcbiAgICAgKi9cbiAgICByZWdpc3RlcktleUJvYXJkRXZlbnRzKCkge1xuICAgICAgICBjb25zdCBrZXlEb3duSGFuZGxlciA9IChldjogS2V5Ym9hcmRFdmVudCkgPT4gdGhpcy5oYW5kbGVPbktleURvd24oZXYpO1xuICAgICAgICBjb25zdCBrZXlVcEhhbmRsZXIgPSAoZXY6IEtleWJvYXJkRXZlbnQpID0+IHRoaXMuaGFuZGxlT25LZXlVcChldik7XG4gICAgICAgIGNvbnN0IGtleVByZXNzSGFuZGxlciA9IChldjogS2V5Ym9hcmRFdmVudCkgPT4gdGhpcy5oYW5kbGVPbktleVByZXNzKGV2KTtcblxuICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKFwia2V5ZG93blwiLCBrZXlEb3duSGFuZGxlcik7XG4gICAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoXCJrZXl1cFwiLCBrZXlVcEhhbmRsZXIpO1xuXG4gICAgICAgIC8vVGhpcyBoYXMgYmVlbiBkZXByZWNhdGVkIGFzIGF0IEp1biAxMyAyMDIxXG4gICAgICAgIGRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIoXCJrZXlwcmVzc1wiLCBrZXlQcmVzc0hhbmRsZXIpO1xuXG4gICAgICAgIHRoaXMua2V5Ym9hcmRFdmVudExpc3RlbmVyVHJhY2tlci5hZGRVbnJlZ2lzdGVyQ2FsbGJhY2soXG4gICAgICAgICAgICAoKSA9PiBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKFwia2V5ZG93blwiLCBrZXlEb3duSGFuZGxlcilcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5rZXlib2FyZEV2ZW50TGlzdGVuZXJUcmFja2VyLmFkZFVucmVnaXN0ZXJDYWxsYmFjayhcbiAgICAgICAgICAgICgpID0+IGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJrZXl1cFwiLCBrZXlVcEhhbmRsZXIpXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMua2V5Ym9hcmRFdmVudExpc3RlbmVyVHJhY2tlci5hZGRVbnJlZ2lzdGVyQ2FsbGJhY2soXG4gICAgICAgICAgICAoKSA9PiBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKFwia2V5cHJlc3NcIiwga2V5UHJlc3NIYW5kbGVyKVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFVucmVnaXN0ZXJzIGRvY3VtZW50IGtleWJvYXJkIGV2ZW50c1xuICAgICAqL1xuICAgIHVucmVnaXN0ZXJLZXlCb2FyZEV2ZW50cygpIHtcbiAgICAgICAgdGhpcy5rZXlib2FyZEV2ZW50TGlzdGVuZXJUcmFja2VyLnVucmVnaXN0ZXJBbGwoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGVzIFdoZW4gYSBrZXkgaXMgZG93blxuICAgICAqIEBwYXJhbSBrZXlib2FyZEV2ZW50IC0gS2V5Ym9hcmQgZXZlbnRcbiAgICAgKi9cbiAgICBoYW5kbGVPbktleURvd24oa2V5Ym9hcmRFdmVudDogS2V5Ym9hcmRFdmVudCkge1xuICAgICAgICBjb25zdCBrZXlDb2RlID0gdGhpcy5nZXRLZXljb2RlKGtleWJvYXJkRXZlbnQpO1xuICAgICAgICBpZiAoIWtleUNvZGUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgYGtleSBkb3duICR7a2V5Q29kZX0sIHJlcGVhdCA9ICR7a2V5Ym9hcmRFdmVudC5yZXBlYXR9YCxcbiAgICAgICAgICAgIDZcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgdG9TdHJlYW1lckhhbmRsZXJzID1cbiAgICAgICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIudG9TdHJlYW1lckhhbmRsZXJzO1xuICAgICAgICB0b1N0cmVhbWVySGFuZGxlcnMuZ2V0KCdLZXlEb3duJykoW1xuICAgICAgICAgICAgdGhpcy5nZXRLZXljb2RlKGtleWJvYXJkRXZlbnQpLFxuICAgICAgICAgICAga2V5Ym9hcmRFdmVudC5yZXBlYXQgPyAxIDogMFxuICAgICAgICBdKTtcbiAgICAgICAgY29uc3QgYWN0aXZlS2V5cyA9IHRoaXMuYWN0aXZlS2V5c1Byb3ZpZGVyLmdldEFjdGl2ZUtleXMoKTtcbiAgICAgICAgYWN0aXZlS2V5cy5wdXNoKGtleUNvZGUpO1xuICAgICAgICAvLyBCYWNrc3BhY2UgaXMgbm90IGNvbnNpZGVyZWQgYSBrZXlwcmVzcyBpbiBKYXZhU2NyaXB0IGJ1dCB3ZSBuZWVkIGl0XG4gICAgICAgIC8vIHRvIGJlIHNvIGNoYXJhY3RlcnMgbWF5IGJlIGRlbGV0ZWQgaW4gYSBVRSB0ZXh0IGVudHJ5IGZpZWxkLlxuICAgICAgICBpZiAoa2V5Q29kZSA9PT0gU3BlY2lhbEtleUNvZGVzLmJhY2tTcGFjZSkge1xuICAgICAgICAgICAgZG9jdW1lbnQuZGlzcGF0Y2hFdmVudChcbiAgICAgICAgICAgICAgICBuZXcgS2V5Ym9hcmRFdmVudCgna2V5cHJlc3MnLCB7XG4gICAgICAgICAgICAgICAgICAgIGNoYXJDb2RlOiBTcGVjaWFsS2V5Q29kZXMuYmFja1NwYWNlXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoXG4gICAgICAgICAgICB0aGlzLmNvbmZpZy5pc0ZsYWdFbmFibGVkKEZsYWdzLlN1cHByZXNzQnJvd3NlcktleXMpICYmXG4gICAgICAgICAgICB0aGlzLmlzS2V5Q29kZUJyb3dzZXJLZXkoa2V5Q29kZSlcbiAgICAgICAgKSB7XG4gICAgICAgICAgICBrZXlib2FyZEV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBoYW5kbGVzIHdoZW4gYSBrZXkgaXMgdXBcbiAgICAgKiBAcGFyYW0ga2V5Ym9hcmRFdmVudCAtIEtleWJvYXJkIGV2ZW50XG4gICAgICovXG4gICAgaGFuZGxlT25LZXlVcChrZXlib2FyZEV2ZW50OiBLZXlib2FyZEV2ZW50KSB7XG4gICAgICAgIGNvbnN0IGtleUNvZGUgPSB0aGlzLmdldEtleWNvZGUoa2V5Ym9hcmRFdmVudCk7XG4gICAgICAgIGlmICgha2V5Q29kZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCBga2V5IHVwICR7a2V5Q29kZX1gLCA2KTtcbiAgICAgICAgY29uc3QgdG9TdHJlYW1lckhhbmRsZXJzID1cbiAgICAgICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIudG9TdHJlYW1lckhhbmRsZXJzO1xuICAgICAgICB0b1N0cmVhbWVySGFuZGxlcnMuZ2V0KCdLZXlVcCcpKFsga2V5Q29kZSBdKTtcblxuICAgICAgICBpZiAoXG4gICAgICAgICAgICB0aGlzLmNvbmZpZy5pc0ZsYWdFbmFibGVkKEZsYWdzLlN1cHByZXNzQnJvd3NlcktleXMpICYmXG4gICAgICAgICAgICB0aGlzLmlzS2V5Q29kZUJyb3dzZXJLZXkoa2V5Q29kZSlcbiAgICAgICAgKSB7XG4gICAgICAgICAgICBrZXlib2FyZEV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGVzIHdoZW4gYSBrZXkgaXMgcHJlc3NcbiAgICAgKiBAcGFyYW0ga2V5Ym9hcmQgLSBLZXlib2FyZCBFdmVudFxuICAgICAqL1xuICAgIGhhbmRsZU9uS2V5UHJlc3Moa2V5Ym9hcmQ6IEtleWJvYXJkRXZlbnQpIHtcbiAgICAgICAgaWYgKCEoJ2NoYXJDb2RlJyBpbiBrZXlib2FyZCkpIHtcbiAgICAgICAgICAgIExvZ2dlci5XYXJuaW5nKFxuICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgJ0tleWJvYXJkRXZlbnQuY2hhckNvZGUgaXMgZGVwcmVjYXRlZCBpbiB0aGlzIGJyb3dzZXIsIGNhbm5vdCBzZW5kIGtleSBwcmVzcy4nXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgY2hhckNvZGUgPSBrZXlib2FyZC5jaGFyQ29kZTtcbiAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCBga2V5IHByZXNzICR7Y2hhckNvZGV9YCwgNik7XG5cbiAgICAgICAgY29uc3QgdG9TdHJlYW1lckhhbmRsZXJzID1cbiAgICAgICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIudG9TdHJlYW1lckhhbmRsZXJzO1xuICAgICAgICB0b1N0cmVhbWVySGFuZGxlcnMuZ2V0KCdLZXlQcmVzcycpKFtjaGFyQ29kZV0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIEtleWNvZGUgb2YgdGhlIEtleSBwcmVzc2VkXG4gICAgICogQHBhcmFtIGtleWJvYXJkRXZlbnQgLSBLZXkgYm9hcmQgRXZlbnRcbiAgICAgKiBAcmV0dXJucyAtIHRoZSBrZXkgY29kZSBvZiB0aGUgS2V5XG4gICAgICovXG4gICAgZ2V0S2V5Y29kZShrZXlib2FyZEV2ZW50OiBLZXlib2FyZEV2ZW50KSB7XG4gICAgICAgIC8vIElmIHdlIGRvbid0IGhhdmUga2V5Q29kZSBwcm9wZXJ0eSBiZWNhdXNlIGJyb3dzZXIgQVBJIGlzIGRlcHJlY2F0ZWQgdGhlbiB1c2UgS2V5Ym9hcmRFdmVudC5jb2RlIGluc3RlYWQuXG4gICAgICAgIC8vIFNlZTogaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvQVBJL0tleWJvYXJkRXZlbnQva2V5Q29kZSNjb25zdGFudHNfZm9yX2tleWNvZGVfdmFsdWVcbiAgICAgICAgaWYgKCEoJ2tleUNvZGUnIGluIGtleWJvYXJkRXZlbnQpKSB7XG4gICAgICAgICAgICAvLyBDb252ZXJ0IEtleWJvYXJkRXZlbnQuY29kZSBzdHJpbmcgaW50byBpbnRlZ2VyLWJhc2VkIGtleSBjb2RlIGZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eSByZWFzb25zLlxuICAgICAgICAgICAgY29uc3QgZXZlbnQgPSBrZXlib2FyZEV2ZW50IGFzIEtleWJvYXJkRXZlbnQ7XG4gICAgICAgICAgICBpZiAoZXZlbnQuY29kZSBpbiB0aGlzLkNvZGVUb0tleUNvZGUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5Db2RlVG9LZXlDb2RlW2V2ZW50LmNvZGVdO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBMb2dnZXIuV2FybmluZyhcbiAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICAgICAgYEtleWJvYXJkIGNvZGUgb2YgJHtldmVudC5jb2RlfSBpcyBub3Qgc3VwcG9ydGVkIGluIG91ciBtYXBwaW5nLCBpZ25vcmluZyB0aGlzIGtleS5gXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIElmIHdlIG1hZGUgaXQgaGVyZSBLZXlib2FyZEV2ZW50LmtleUNvZGUgaXMgc3RpbGwgc3VwcG9ydGVkIHNvIHdlIGNhbiBzYWZlbHkgdXNlIGl0LlxuXG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIGtleWJvYXJkRXZlbnQua2V5Q29kZSA9PT0gU3BlY2lhbEtleUNvZGVzLnNoaWZ0ICYmXG4gICAgICAgICAgICBrZXlib2FyZEV2ZW50LmNvZGUgPT09ICdTaGlmdFJpZ2h0J1xuICAgICAgICApIHtcbiAgICAgICAgICAgIHJldHVybiBTcGVjaWFsS2V5Q29kZXMucmlnaHRTaGlmdDtcbiAgICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgICAgIGtleWJvYXJkRXZlbnQua2V5Q29kZSA9PT0gU3BlY2lhbEtleUNvZGVzLmNvbnRyb2wgJiZcbiAgICAgICAgICAgIGtleWJvYXJkRXZlbnQuY29kZSA9PT0gJ0NvbnRyb2xSaWdodCdcbiAgICAgICAgKSB7XG4gICAgICAgICAgICByZXR1cm4gU3BlY2lhbEtleUNvZGVzLnJpZ2h0Q29udHJvbDtcbiAgICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgICAgIGtleWJvYXJkRXZlbnQua2V5Q29kZSA9PT0gU3BlY2lhbEtleUNvZGVzLmFsdCAmJlxuICAgICAgICAgICAga2V5Ym9hcmRFdmVudC5jb2RlID09PSAnQWx0UmlnaHQnXG4gICAgICAgICkge1xuICAgICAgICAgICAgcmV0dXJuIFNwZWNpYWxLZXlDb2Rlcy5yaWdodEFsdDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBrZXlib2FyZEV2ZW50LmtleUNvZGU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBCcm93c2VyIGtleXMgZG8gbm90IGhhdmUgYSBjaGFyQ29kZSBzbyB3ZSBvbmx5IG5lZWQgdG8gdGVzdCBrZXlDb2RlLlxuICAgICAqIEBwYXJhbSBrZXlDb2RlIC0gdGhlIGJyb3dzZXIga2V5Y29kZSBudW1iZXJcbiAgICAgKi9cbiAgICBpc0tleUNvZGVCcm93c2VyS2V5KGtleUNvZGU6IG51bWJlcikge1xuICAgICAgICAvLyBGdW5jdGlvbiBrZXlzIG9yIHRhYiBrZXkgYXJlIGNvbnNpZGVyZWQgXCJicm93c2VyIGtleXNcIiB0aGF0IHdlIG1heSB3aXNoIHRvIHN1cHByZXNzIGJ5IHByZXZlbnRpbmcgdGhlbSBiZWluZyBwcm9jZXNzIGJ5IGJyb3dzZXIuXG4gICAgICAgIHJldHVybiAoa2V5Q29kZSA+PSAxMTIgJiYga2V5Q29kZSA8PSAxMjMpIHx8IGtleUNvZGUgPT09IDk7XG4gICAgfVxufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuaW1wb3J0IHsgTW91c2VDb250cm9sbGVyIH0gZnJvbSAnLi9Nb3VzZUNvbnRyb2xsZXInO1xuaW1wb3J0IHsgTG9nZ2VyIH0gZnJvbSAnLi4vTG9nZ2VyL0xvZ2dlcic7XG5pbXBvcnQgeyBJTW91c2VFdmVudHMgfSBmcm9tICcuL0lNb3VzZUV2ZW50cyc7XG5pbXBvcnQgeyBOb3JtYWxpemVkUXVhbnRpemVkVW5zaWduZWRDb29yZCB9IGZyb20gJy4uL1V0aWwvQ29vcmRpbmF0ZUNvbnZlcnRlcic7XG5pbXBvcnQgeyBBY3RpdmVLZXlzIH0gZnJvbSAnLi9JbnB1dENsYXNzZXNGYWN0b3J5JztcbmltcG9ydCB7IFZpZGVvUGxheWVyIH0gZnJvbSAnLi4vVmlkZW9QbGF5ZXIvVmlkZW9QbGF5ZXInO1xuaW1wb3J0IHsgRXZlbnRMaXN0ZW5lclRyYWNrZXIgfSBmcm9tICcuLi9VdGlsL0V2ZW50TGlzdGVuZXJUcmFja2VyJztcblxuLyoqXG4gKiBIYW5kbGUgdGhlIG1vdXNlIGxvY2tlZCBldmVudHNcbiAqL1xuZXhwb3J0IGNsYXNzIExvY2tlZE1vdXNlRXZlbnRzIGltcGxlbWVudHMgSU1vdXNlRXZlbnRzIHtcbiAgICB4ID0gMDtcbiAgICB5ID0gMDtcbiAgICBjb29yZDogTm9ybWFsaXplZFF1YW50aXplZFVuc2lnbmVkQ29vcmQ7XG4gICAgdmlkZW9FbGVtZW50UHJvdmlkZXI6IFZpZGVvUGxheWVyO1xuICAgIG1vdXNlQ29udHJvbGxlcjogTW91c2VDb250cm9sbGVyO1xuICAgIGFjdGl2ZUtleXNQcm92aWRlcjogQWN0aXZlS2V5cztcbiAgICB1cGRhdGVNb3VzZU1vdmVQb3NpdGlvbkV2ZW50ID0gKG1vdXNlRXZlbnQ6IE1vdXNlRXZlbnQpID0+IHtcbiAgICAgICAgdGhpcy51cGRhdGVNb3VzZU1vdmVQb3NpdGlvbihtb3VzZUV2ZW50KTtcbiAgICB9O1xuXG4gICAgLy8gVXRpbGl0eSBmb3Iga2VlcGluZyB0cmFjayBvZiBldmVudCBoYW5kbGVycyBhbmQgdW5yZWdpc3RlcmluZyB0aGVtXG4gICAgcHJpdmF0ZSBtb3VzZUV2ZW50TGlzdGVuZXJUcmFja2VyID0gbmV3IEV2ZW50TGlzdGVuZXJUcmFja2VyKCk7XG5cbiAgICAvKipcbiAgICAgKiBAcGFyYW0gdmlkZW9FbGVtZW50UHJvdmlkZXIgLSBWaWRlbyBQbGF5ZXIgaW5zdGFuY2VcbiAgICAgKiBAcGFyYW0gbW91c2VDb250cm9sbGVyIC0gTW91c2UgY29udHJvbGxlciBpbnN0YW5jZVxuICAgICAqIEBwYXJhbSBhY3RpdmVLZXlzUHJvdmlkZXIgLSBBY3RpdmUga2V5cyBwcm92aWRlciBpbnN0YW5jZVxuICAgICAqIEBwYXJhbSBwbGF5ZXJTdHlsZUF0dHJpYnV0ZXNQcm92aWRlciAtIFBsYXllciBzdHlsZSBhdHRyaWJ1dGVzIGluc3RhbmNlXG4gICAgICovXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIHZpZGVvRWxlbWVudFByb3ZpZGVyOiBWaWRlb1BsYXllcixcbiAgICAgICAgbW91c2VDb250cm9sbGVyOiBNb3VzZUNvbnRyb2xsZXIsXG4gICAgICAgIGFjdGl2ZUtleXNQcm92aWRlcjogQWN0aXZlS2V5c1xuICAgICkge1xuICAgICAgICB0aGlzLnZpZGVvRWxlbWVudFByb3ZpZGVyID0gdmlkZW9FbGVtZW50UHJvdmlkZXI7XG4gICAgICAgIHRoaXMubW91c2VDb250cm9sbGVyID0gbW91c2VDb250cm9sbGVyO1xuICAgICAgICB0aGlzLmFjdGl2ZUtleXNQcm92aWRlciA9IGFjdGl2ZUtleXNQcm92aWRlcjtcbiAgICAgICAgY29uc3QgdmlkZW9FbGVtZW50UGFyZW50ID1cbiAgICAgICAgICAgIHRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIuZ2V0VmlkZW9QYXJlbnRFbGVtZW50KCk7XG4gICAgICAgIHRoaXMueCA9IHZpZGVvRWxlbWVudFBhcmVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS53aWR0aCAvIDI7XG4gICAgICAgIHRoaXMueSA9IHZpZGVvRWxlbWVudFBhcmVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS5oZWlnaHQgLyAyO1xuICAgICAgICB0aGlzLmNvb3JkID1cbiAgICAgICAgICAgIHRoaXMubW91c2VDb250cm9sbGVyLmNvb3JkaW5hdGVDb252ZXJ0ZXIubm9ybWFsaXplQW5kUXVhbnRpemVVbnNpZ25lZChcbiAgICAgICAgICAgICAgICB0aGlzLngsXG4gICAgICAgICAgICAgICAgdGhpcy55XG4gICAgICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFVucmVnaXN0ZXJzIGFsbCBldmVudCBoYW5kbGVyc1xuICAgICAqL1xuICAgIHVucmVnaXN0ZXJNb3VzZUV2ZW50cygpIHtcbiAgICAgICAgdGhpcy5tb3VzZUV2ZW50TGlzdGVuZXJUcmFja2VyLnVucmVnaXN0ZXJBbGwoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGUgd2hlbiB0aGUgbG9ja2VkIHN0YXRlIENoYW5nZWRcbiAgICAgKi9cbiAgICBsb2NrU3RhdGVDaGFuZ2UoKSB7XG4gICAgICAgIGNvbnN0IHZpZGVvRWxlbWVudFBhcmVudCA9XG4gICAgICAgICAgICB0aGlzLnZpZGVvRWxlbWVudFByb3ZpZGVyLmdldFZpZGVvUGFyZW50RWxlbWVudCgpO1xuICAgICAgICBjb25zdCB0b1N0cmVhbWVySGFuZGxlcnMgPVxuICAgICAgICAgICAgdGhpcy5tb3VzZUNvbnRyb2xsZXIudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIudG9TdHJlYW1lckhhbmRsZXJzO1xuXG4gICAgICAgIGlmIChcbiAgICAgICAgICAgIGRvY3VtZW50LnBvaW50ZXJMb2NrRWxlbWVudCA9PT0gdmlkZW9FbGVtZW50UGFyZW50IHx8XG4gICAgICAgICAgICBkb2N1bWVudC5tb3pQb2ludGVyTG9ja0VsZW1lbnQgPT09IHZpZGVvRWxlbWVudFBhcmVudFxuICAgICAgICApIHtcbiAgICAgICAgICAgIExvZ2dlci5Mb2coTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSwgJ1BvaW50ZXIgbG9ja2VkJywgNik7XG4gICAgICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKFxuICAgICAgICAgICAgICAgICdtb3VzZW1vdmUnLFxuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlTW91c2VNb3ZlUG9zaXRpb25FdmVudCxcbiAgICAgICAgICAgICAgICBmYWxzZVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHRoaXMubW91c2VFdmVudExpc3RlbmVyVHJhY2tlci5hZGRVbnJlZ2lzdGVyQ2FsbGJhY2soXG4gICAgICAgICAgICAgICAgKCkgPT4gZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihcbiAgICAgICAgICAgICAgICAgICAgJ21vdXNlbW92ZScsXG4gICAgICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlTW91c2VNb3ZlUG9zaXRpb25FdmVudCxcbiAgICAgICAgICAgICAgICAgICAgZmFsc2VcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgICdUaGUgcG9pbnRlciBsb2NrIHN0YXR1cyBpcyBub3cgdW5sb2NrZWQnLFxuICAgICAgICAgICAgICAgIDZcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICAvLyAhYSBuZXcgYXJyb3cgZnVuY3Rpb24gbXVzdCBub3QgYmUgdXNlZCBoZXJlIGFzIGl0IHdpbGwgYmUgY291bnRlZCBhcyBhIG5ldyBmdW5jdGlvbiB0aGF0IGNhbm5vdCBiZSByZW1vdmVkXG4gICAgICAgICAgICBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKFxuICAgICAgICAgICAgICAgICdtb3VzZW1vdmUnLFxuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlTW91c2VNb3ZlUG9zaXRpb25FdmVudCxcbiAgICAgICAgICAgICAgICBmYWxzZVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgLy8gSWYgbW91c2UgbG9zZXMgZm9jdXMsIHNlbmQgYSBrZXkgdXAgZm9yIGFsbCBvZiB0aGUgY3VycmVudGx5IGhlbGQtZG93biBrZXlzXG4gICAgICAgICAgICAvLyBUaGlzIGlzIG5lY2Vzc2FyeSBhcyB3aGVuIHRoZSBtb3VzZSBsb3NlcyBmb2N1cywgdGhlIHdpbmRvd3Mgc3RvcHMgbGlzdGVuaW5nIGZvciBldmVudHMgYW5kIGFzIHN1Y2hcbiAgICAgICAgICAgIC8vIHRoZSBrZXl1cCBsaXN0ZW5lciB3b24ndCBnZXQgZmlyZWRcbiAgICAgICAgICAgIGxldCBhY3RpdmVLZXlzID0gdGhpcy5hY3RpdmVLZXlzUHJvdmlkZXIuZ2V0QWN0aXZlS2V5cygpO1xuICAgICAgICAgICAgY29uc3Qgc2V0S2V5cyA9IG5ldyBTZXQoYWN0aXZlS2V5cyk7XG4gICAgICAgICAgICBjb25zdCBuZXdLZXlzSXRlcmFibGU6IEFycmF5PG51bWJlcj4gPSBbXTtcblxuICAgICAgICAgICAgc2V0S2V5cy5mb3JFYWNoKChzZXRLZXk6IG51bWJlcikgPT4ge1xuICAgICAgICAgICAgICAgIG5ld0tleXNJdGVyYWJsZVtzZXRLZXldO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIG5ld0tleXNJdGVyYWJsZS5mb3JFYWNoKCh1bmlxdWVLZXljb2RlKSA9PiB7XG4gICAgICAgICAgICAgICAgdG9TdHJlYW1lckhhbmRsZXJzLmdldCgnS2V5VXAnKShbdW5pcXVlS2V5Y29kZV0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAvLyBSZXNldCB0aGUgYWN0aXZlIGtleXMgYmFjayB0byBub3RoaW5nXG4gICAgICAgICAgICBhY3RpdmVLZXlzID0gW107XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGUgdGhlIG1vdXNlIG1vdmUgZXZlbnQsIHNlbmRzIHRoZSBtb3VzZSBkYXRhIHRvIHRoZSBVRSBJbnN0YW5jZVxuICAgICAqIEBwYXJhbSBtb3VzZUV2ZW50IC0gTW91c2UgRXZlbnRcbiAgICAgKi9cbiAgICB1cGRhdGVNb3VzZU1vdmVQb3NpdGlvbihtb3VzZUV2ZW50OiBNb3VzZUV2ZW50KSB7XG4gICAgICAgIGlmICghdGhpcy52aWRlb0VsZW1lbnRQcm92aWRlci5pc1ZpZGVvUmVhZHkoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHRvU3RyZWFtZXJIYW5kbGVycyA9XG4gICAgICAgICAgICB0aGlzLm1vdXNlQ29udHJvbGxlci50b1N0cmVhbWVyTWVzc2FnZXNQcm92aWRlci50b1N0cmVhbWVySGFuZGxlcnM7XG4gICAgICAgIGNvbnN0IHN0eWxlV2lkdGggPVxuICAgICAgICAgICAgdGhpcy52aWRlb0VsZW1lbnRQcm92aWRlci5nZXRWaWRlb1BhcmVudEVsZW1lbnQoKS5jbGllbnRXaWR0aDtcbiAgICAgICAgY29uc3Qgc3R5bGVIZWlnaHQgPVxuICAgICAgICAgICAgdGhpcy52aWRlb0VsZW1lbnRQcm92aWRlci5nZXRWaWRlb1BhcmVudEVsZW1lbnQoKS5jbGllbnRIZWlnaHQ7XG5cbiAgICAgICAgdGhpcy54ICs9IG1vdXNlRXZlbnQubW92ZW1lbnRYO1xuICAgICAgICB0aGlzLnkgKz0gbW91c2VFdmVudC5tb3ZlbWVudFk7XG5cbiAgICAgICAgaWYgKHRoaXMueCA+IHN0eWxlV2lkdGgpIHtcbiAgICAgICAgICAgIHRoaXMueCAtPSBzdHlsZVdpZHRoO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLnkgPiBzdHlsZUhlaWdodCkge1xuICAgICAgICAgICAgdGhpcy55IC09IHN0eWxlSGVpZ2h0O1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLnggPCAwKSB7XG4gICAgICAgICAgICB0aGlzLnggPSBzdHlsZVdpZHRoICsgdGhpcy54O1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLnkgPCAwKSB7XG4gICAgICAgICAgICB0aGlzLnkgPSBzdHlsZUhlaWdodCAtIHRoaXMueTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuY29vcmQgPVxuICAgICAgICAgICAgdGhpcy5tb3VzZUNvbnRyb2xsZXIuY29vcmRpbmF0ZUNvbnZlcnRlci5ub3JtYWxpemVBbmRRdWFudGl6ZVVuc2lnbmVkKFxuICAgICAgICAgICAgICAgIHRoaXMueCxcbiAgICAgICAgICAgICAgICB0aGlzLnlcbiAgICAgICAgICAgICk7XG4gICAgICAgIGNvbnN0IGRlbHRhID1cbiAgICAgICAgICAgIHRoaXMubW91c2VDb250cm9sbGVyLmNvb3JkaW5hdGVDb252ZXJ0ZXIubm9ybWFsaXplQW5kUXVhbnRpemVTaWduZWQoXG4gICAgICAgICAgICAgICAgbW91c2VFdmVudC5tb3ZlbWVudFgsXG4gICAgICAgICAgICAgICAgbW91c2VFdmVudC5tb3ZlbWVudFlcbiAgICAgICAgICAgICk7XG4gICAgICAgIHRvU3RyZWFtZXJIYW5kbGVycy5nZXQoJ01vdXNlTW92ZScpKFtcbiAgICAgICAgICAgIHRoaXMuY29vcmQueCxcbiAgICAgICAgICAgIHRoaXMuY29vcmQueSxcbiAgICAgICAgICAgIGRlbHRhLngsXG4gICAgICAgICAgICBkZWx0YS55XG4gICAgICAgIF0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEhhbmRsZSB0aGUgbW91c2UgRG93biBldmVudCwgc2VuZHMgdGhlIG1vdXNlIGRhdGEgdG8gdGhlIFVFIEluc3RhbmNlXG4gICAgICogQHBhcmFtIG1vdXNlRXZlbnQgLSBNb3VzZSBFdmVudFxuICAgICAqL1xuICAgIGhhbmRsZU1vdXNlRG93bihtb3VzZUV2ZW50OiBNb3VzZUV2ZW50KSB7XG4gICAgICAgIGlmICghdGhpcy52aWRlb0VsZW1lbnRQcm92aWRlci5pc1ZpZGVvUmVhZHkoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgdG9TdHJlYW1lckhhbmRsZXJzID1cbiAgICAgICAgICAgIHRoaXMubW91c2VDb250cm9sbGVyLnRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyLnRvU3RyZWFtZXJIYW5kbGVycztcbiAgICAgICAgdG9TdHJlYW1lckhhbmRsZXJzLmdldCgnTW91c2VEb3duJykoW1xuICAgICAgICAgICAgbW91c2VFdmVudC5idXR0b24sXG4gICAgICAgICAgICAvLyBXZSB1c2UgdGhlIHN0b3JlIHZhbHVlIG9mIHRoaXMuY29vcmQgYXMgb3Bwb3NlZCB0byB0aGUgbW91c2VFdmVudC54L3kgYXMgdGhlIG1vdXNlRXZlbnQgbG9jYXRpb25cbiAgICAgICAgICAgIC8vIHVzZXMgdGhlIHN5c3RlbSBjdXJzb3IgbG9jYXRpb24gd2hpY2ggaGFzbid0IG1vdmVkXG4gICAgICAgICAgICB0aGlzLmNvb3JkLngsXG4gICAgICAgICAgICB0aGlzLmNvb3JkLnlcbiAgICAgICAgXSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSGFuZGxlIHRoZSBtb3VzZSBVcCBldmVudCwgc2VuZHMgdGhlIG1vdXNlIGRhdGEgdG8gdGhlIFVFIEluc3RhbmNlXG4gICAgICogQHBhcmFtIG1vdXNlRXZlbnQgLSBNb3VzZSBFdmVudFxuICAgICAqL1xuICAgIGhhbmRsZU1vdXNlVXAobW91c2VFdmVudDogTW91c2VFdmVudCkge1xuICAgICAgICBpZiAoIXRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIuaXNWaWRlb1JlYWR5KCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCB0b1N0cmVhbWVySGFuZGxlcnMgPVxuICAgICAgICAgICAgdGhpcy5tb3VzZUNvbnRyb2xsZXIudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIudG9TdHJlYW1lckhhbmRsZXJzO1xuICAgICAgICB0b1N0cmVhbWVySGFuZGxlcnMuZ2V0KCdNb3VzZVVwJykoW1xuICAgICAgICAgICAgbW91c2VFdmVudC5idXR0b24sXG4gICAgICAgICAgICAvLyBXZSB1c2UgdGhlIHN0b3JlIHZhbHVlIG9mIHRoaXMuY29vcmQgYXMgb3Bwb3NlZCB0byB0aGUgbW91c2VFdmVudC54L3kgYXMgdGhlIG1vdXNlRXZlbnQgbG9jYXRpb25cbiAgICAgICAgICAgIC8vIHVzZXMgdGhlIHN5c3RlbSBjdXJzb3IgbG9jYXRpb24gd2hpY2ggaGFzbid0IG1vdmVkXG4gICAgICAgICAgICB0aGlzLmNvb3JkLngsXG4gICAgICAgICAgICB0aGlzLmNvb3JkLnlcbiAgICAgICAgXSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSGFuZGxlIHRoZSBtb3VzZSB3aGVlbCBldmVudCwgc2VuZHMgdGhlIG1vdXNlIHdoZWVsIGRhdGEgdG8gdGhlIFVFIEluc3RhbmNlXG4gICAgICogQHBhcmFtIHdoZWVsRXZlbnQgLSBNb3VzZSBFdmVudFxuICAgICAqL1xuICAgIGhhbmRsZU1vdXNlV2hlZWwod2hlZWxFdmVudDogV2hlZWxFdmVudCkge1xuICAgICAgICBpZiAoIXRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIuaXNWaWRlb1JlYWR5KCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCB0b1N0cmVhbWVySGFuZGxlcnMgPVxuICAgICAgICAgICAgdGhpcy5tb3VzZUNvbnRyb2xsZXIudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIudG9TdHJlYW1lckhhbmRsZXJzO1xuICAgICAgICB0b1N0cmVhbWVySGFuZGxlcnMuZ2V0KCdNb3VzZVdoZWVsJykoW1xuICAgICAgICAgICAgd2hlZWxFdmVudC53aGVlbERlbHRhLFxuICAgICAgICAgICAgLy8gV2UgdXNlIHRoZSBzdG9yZSB2YWx1ZSBvZiB0aGlzLmNvb3JkIGFzIG9wcG9zZWQgdG8gdGhlIG1vdXNlRXZlbnQueC95IGFzIHRoZSBtb3VzZUV2ZW50IGxvY2F0aW9uXG4gICAgICAgICAgICAvLyB1c2VzIHRoZSBzeXN0ZW0gY3Vyc29yIGxvY2F0aW9uIHdoaWNoIGhhc24ndCBtb3ZlZFxuICAgICAgICAgICAgdGhpcy5jb29yZC54LFxuICAgICAgICAgICAgdGhpcy5jb29yZC55XG4gICAgICAgIF0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEhhbmRsZSB0aGUgbW91c2UgZG91YmxlIGNsaWNrIGV2ZW50LCBzZW5kcyB0aGUgbW91c2UgZGF0YSB0byB0aGUgVUUgSW5zdGFuY2VcbiAgICAgKiBAcGFyYW0gbW91c2VFdmVudCAtIE1vdXNlIEV2ZW50XG4gICAgICovXG4gICAgaGFuZGxlTW91c2VEb3VibGUobW91c2VFdmVudDogTW91c2VFdmVudCkge1xuICAgICAgICBpZiAoIXRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIuaXNWaWRlb1JlYWR5KCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCB0b1N0cmVhbWVySGFuZGxlcnMgPVxuICAgICAgICAgICAgdGhpcy5tb3VzZUNvbnRyb2xsZXIudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIudG9TdHJlYW1lckhhbmRsZXJzO1xuICAgICAgICB0b1N0cmVhbWVySGFuZGxlcnMuZ2V0KCdNb3VzZURvdWJsZScpKFtcbiAgICAgICAgICAgIG1vdXNlRXZlbnQuYnV0dG9uLFxuICAgICAgICAgICAgLy8gV2UgdXNlIHRoZSBzdG9yZSB2YWx1ZSBvZiB0aGlzLmNvb3JkIGFzIG9wcG9zZWQgdG8gdGhlIG1vdXNlRXZlbnQueC95IGFzIHRoZSBtb3VzZUV2ZW50IGxvY2F0aW9uXG4gICAgICAgICAgICAvLyB1c2VzIHRoZSBzeXN0ZW0gY3Vyc29yIGxvY2F0aW9uIHdoaWNoIGhhc24ndCBtb3ZlZFxuICAgICAgICAgICAgdGhpcy5jb29yZC54LFxuICAgICAgICAgICAgdGhpcy5jb29yZC55XG4gICAgICAgIF0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEhhbmRsZSB0aGUgcHJlc3MgbW91c2UgYnV0dG9ucyBldmVudCwgc2VuZHMgdGhlIG1vdXNlIGRhdGEgdG8gdGhlIFVFIEluc3RhbmNlXG4gICAgICogQHBhcmFtIG1vdXNlRXZlbnQgLSBNb3VzZSBFdmVudFxuICAgICAqL1xuICAgIGhhbmRsZVByZXNzTW91c2VCdXR0b25zKG1vdXNlRXZlbnQ6IE1vdXNlRXZlbnQpIHtcbiAgICAgICAgaWYgKCF0aGlzLnZpZGVvRWxlbWVudFByb3ZpZGVyLmlzVmlkZW9SZWFkeSgpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5tb3VzZUNvbnRyb2xsZXIucHJlc3NNb3VzZUJ1dHRvbnMoXG4gICAgICAgICAgICBtb3VzZUV2ZW50LmJ1dHRvbnMsXG4gICAgICAgICAgICB0aGlzLngsXG4gICAgICAgICAgICB0aGlzLnlcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGUgdGhlIHJlbGVhc2UgbW91c2UgYnV0dG9ucyBldmVudCwgc2VuZHMgdGhlIG1vdXNlIGRhdGEgdG8gdGhlIFVFIEluc3RhbmNlXG4gICAgICogQHBhcmFtIG1vdXNlRXZlbnQgLSBNb3VzZSBFdmVudFxuICAgICAqL1xuICAgIGhhbmRsZVJlbGVhc2VNb3VzZUJ1dHRvbnMobW91c2VFdmVudDogTW91c2VFdmVudCkge1xuICAgICAgICBpZiAoIXRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIuaXNWaWRlb1JlYWR5KCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLm1vdXNlQ29udHJvbGxlci5yZWxlYXNlTW91c2VCdXR0b25zKFxuICAgICAgICAgICAgbW91c2VFdmVudC5idXR0b25zLFxuICAgICAgICAgICAgdGhpcy54LFxuICAgICAgICAgICAgdGhpcy55XG4gICAgICAgICk7XG4gICAgfVxufVxuXG4vKipcbiAqIEV4dHJhIHR5cGVzIGZvciBEb2N1bWVudCBhbmQgV2hlZWxFdmVudFxuICovXG5kZWNsYXJlIGdsb2JhbCB7XG4gICAgaW50ZXJmYWNlIERvY3VtZW50IHtcbiAgICAgICAgbW96UG9pbnRlckxvY2tFbGVtZW50OiB1bmtub3duO1xuICAgICAgICBtb3pFeGl0UG9pbnRlckxvY2s/KCk6IHZvaWQ7XG4gICAgfVxuXG4gICAgaW50ZXJmYWNlIFdoZWVsRXZlbnQge1xuICAgICAgICB3aGVlbERlbHRhOiBudW1iZXI7XG4gICAgfVxufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuLyoqXG4gKiBNb3VzZSBCdXR0b24gRGF0YVxuICoge0BsaW5rIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0FQSS9Nb3VzZUV2ZW50L2J1dHRvbn1cbiAqL1xuZXhwb3J0IGNsYXNzIE1vdXNlQnV0dG9uIHtcbiAgICBzdGF0aWMgbWFpbkJ1dHRvbiA9IDA7IC8vIExlZnQgYnV0dG9uLlxuICAgIHN0YXRpYyBhdXhpbGlhcnlCdXR0b24gPSAxOyAvLyBXaGVlbCBidXR0b24uXG4gICAgc3RhdGljIHNlY29uZGFyeUJ1dHRvbiA9IDI7IC8vIFJpZ2h0IGJ1dHRvbi5cbiAgICBzdGF0aWMgZm91cnRoQnV0dG9uID0gMzsgLy8gQnJvd3NlciBCYWNrIGJ1dHRvbi5cbiAgICBzdGF0aWMgZmlmdGhCdXR0b24gPSA0OyAvLyBCcm93c2VyIEZvcndhcmQgYnV0dG9uLlxufVxuXG4vKipcbiAqIE1vdXNlIEJ1dHRvbiBNYXNrIERhdGFcbiAqIHtAbGluayBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9BUEkvTW91c2VFdmVudC9idXR0b25zfVxuICovXG5leHBvcnQgY2xhc3MgTW91c2VCdXR0b25zTWFzayB7XG4gICAgc3RhdGljIHByaW1hcnlCdXR0b24gPSAxOyAvLyBMZWZ0IGJ1dHRvbi5cbiAgICBzdGF0aWMgc2Vjb25kYXJ5QnV0dG9uID0gMjsgLy8gUmlnaHQgYnV0dG9uLlxuICAgIHN0YXRpYyBhdXhpbGlhcnlCdXR0b24gPSA0OyAvLyBXaGVlbCBidXR0b24uXG4gICAgc3RhdGljIGZvdXJ0aEJ1dHRvbiA9IDg7IC8vIEJyb3dzZXIgQmFjayBidXR0b24uXG4gICAgc3RhdGljIGZpZnRoQnV0dG9uID0gMTY7IC8vIEJyb3dzZXIgRm9yd2FyZCBidXR0b24uXG59XG4iLCIvLyBDb3B5cmlnaHQgRXBpYyBHYW1lcywgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuXG5pbXBvcnQgeyBNb3VzZUJ1dHRvbnNNYXNrLCBNb3VzZUJ1dHRvbiB9IGZyb20gJy4vTW91c2VCdXR0b25zJztcbmltcG9ydCB7IExvZ2dlciB9IGZyb20gJy4uL0xvZ2dlci9Mb2dnZXInO1xuaW1wb3J0IHsgU3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIgfSBmcm9tICcuLi9VZUluc3RhbmNlTWVzc2FnZS9TdHJlYW1NZXNzYWdlQ29udHJvbGxlcic7XG5pbXBvcnQgeyBDb29yZGluYXRlQ29udmVydGVyIH0gZnJvbSAnLi4vVXRpbC9Db29yZGluYXRlQ29udmVydGVyJztcbmltcG9ydCB7IFZpZGVvUGxheWVyIH0gZnJvbSAnLi4vVmlkZW9QbGF5ZXIvVmlkZW9QbGF5ZXInO1xuaW1wb3J0IHsgSU1vdXNlRXZlbnRzIH0gZnJvbSAnLi9JTW91c2VFdmVudHMnO1xuaW1wb3J0IHsgTG9ja2VkTW91c2VFdmVudHMgfSBmcm9tICcuL0xvY2tlZE1vdXNlRXZlbnRzJztcbmltcG9ydCB7IEhvdmVyaW5nTW91c2VFdmVudHMgfSBmcm9tICcuL0hvdmVyaW5nTW91c2VFdmVudHMnO1xuaW1wb3J0IHR5cGUgeyBBY3RpdmVLZXlzIH0gZnJvbSAnLi9JbnB1dENsYXNzZXNGYWN0b3J5JztcbmltcG9ydCB7IEV2ZW50TGlzdGVuZXJUcmFja2VyIH0gZnJvbSAnLi4vVXRpbC9FdmVudExpc3RlbmVyVHJhY2tlcic7XG5cbi8qKlxuICogSGFuZGxlcyB0aGUgTW91c2UgSW5wdXRzIGZvciB0aGUgZG9jdW1lbnRcbiAqL1xuZXhwb3J0IGNsYXNzIE1vdXNlQ29udHJvbGxlciB7XG4gICAgdmlkZW9FbGVtZW50UHJvdmlkZXI6IFZpZGVvUGxheWVyO1xuICAgIHRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyOiBTdHJlYW1NZXNzYWdlQ29udHJvbGxlcjtcbiAgICBjb29yZGluYXRlQ29udmVydGVyOiBDb29yZGluYXRlQ29udmVydGVyO1xuICAgIGFjdGl2ZUtleXNQcm92aWRlcjogQWN0aXZlS2V5cztcblxuICAgIC8vIFV0aWxpdHkgZm9yIGtlZXBpbmcgdHJhY2sgb2YgZXZlbnQgaGFuZGxlcnMgYW5kIHVucmVnaXN0ZXJpbmcgdGhlbVxuICAgIHByaXZhdGUgbW91c2VFdmVudExpc3RlbmVyVHJhY2tlciA9IG5ldyBFdmVudExpc3RlbmVyVHJhY2tlcigpO1xuXG4gICAgLyoqXG4gICAgICogQHBhcmFtIHRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyIC0gU3RyZWFtIG1lc3NhZ2UgaW5zdGFuY2VcbiAgICAgKiBAcGFyYW0gdmlkZW9FbGVtZW50UHJvdmlkZXIgLSBWaWRlbyBQbGF5ZXIgaW5zdGFuY2VcbiAgICAgKiBAcGFyYW0gbm9ybWFsaXplQW5kUXVhbnRpemUgLSBBIG5vcm1hbGl6ZSBhbmQgcXVhbnRpemUgaW5zdGFuY2VcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgdG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXI6IFN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLFxuICAgICAgICB2aWRlb0VsZW1lbnRQcm92aWRlcjogVmlkZW9QbGF5ZXIsXG4gICAgICAgIGNvb3JkaW5hdGVDb252ZXJ0ZXI6IENvb3JkaW5hdGVDb252ZXJ0ZXIsXG4gICAgICAgIGFjdGl2ZUtleXNQcm92aWRlcjogQWN0aXZlS2V5c1xuICAgICkge1xuICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyID0gdG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXI7XG4gICAgICAgIHRoaXMuY29vcmRpbmF0ZUNvbnZlcnRlciA9IGNvb3JkaW5hdGVDb252ZXJ0ZXI7XG4gICAgICAgIHRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIgPSB2aWRlb0VsZW1lbnRQcm92aWRlcjtcbiAgICAgICAgdGhpcy5hY3RpdmVLZXlzUHJvdmlkZXIgPSBhY3RpdmVLZXlzUHJvdmlkZXI7XG4gICAgICAgIHRoaXMucmVnaXN0ZXJNb3VzZUVudGVyQW5kTGVhdmVFdmVudHMoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDbGVhcnMgYWxsIHRoZSBjbGljayBldmVudHMgb24gdGhlIGN1cnJlbnQgdmlkZW8gZWxlbWVudCBwYXJlbnQgZGl2XG4gICAgICovXG4gICAgdW5yZWdpc3Rlck1vdXNlRXZlbnRzKCkge1xuICAgICAgICB0aGlzLm1vdXNlRXZlbnRMaXN0ZW5lclRyYWNrZXIudW5yZWdpc3RlckFsbCgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlZ2lzdGVyIGEgbG9ja2VkIG1vdXNlIGNsYXNzXG4gICAgICogQHBhcmFtIG1vdXNlQ29udHJvbGxlciAtIGEgbW91c2UgY29udHJvbGxlciBpbnN0YW5jZVxuICAgICAqIEBwYXJhbSBwbGF5ZXJTdHlsZUF0dHJpYnV0ZXNQcm92aWRlciAtIGEgcGxheWVyIHN0eWxlIGF0dHJpYnV0ZXMgaW5zdGFuY2VcbiAgICAgKi9cbiAgICByZWdpc3RlckxvY2tlZE1vdXNlRXZlbnRzKG1vdXNlQ29udHJvbGxlcjogTW91c2VDb250cm9sbGVyKSB7XG4gICAgICAgIGNvbnN0IHZpZGVvRWxlbWVudFBhcmVudCA9XG4gICAgICAgICAgICB0aGlzLnZpZGVvRWxlbWVudFByb3ZpZGVyLmdldFZpZGVvUGFyZW50RWxlbWVudCgpIGFzIEhUTUxEaXZFbGVtZW50O1xuICAgICAgICBjb25zdCBsb2NrZWRNb3VzZUV2ZW50czogSU1vdXNlRXZlbnRzID0gbmV3IExvY2tlZE1vdXNlRXZlbnRzKFxuICAgICAgICAgICAgdGhpcy52aWRlb0VsZW1lbnRQcm92aWRlcixcbiAgICAgICAgICAgIG1vdXNlQ29udHJvbGxlcixcbiAgICAgICAgICAgIHRoaXMuYWN0aXZlS2V5c1Byb3ZpZGVyXG4gICAgICAgICk7XG5cbiAgICAgICAgdmlkZW9FbGVtZW50UGFyZW50LnJlcXVlc3RQb2ludGVyTG9jayA9XG4gICAgICAgICAgICB2aWRlb0VsZW1lbnRQYXJlbnQucmVxdWVzdFBvaW50ZXJMb2NrIHx8XG4gICAgICAgICAgICB2aWRlb0VsZW1lbnRQYXJlbnQubW96UmVxdWVzdFBvaW50ZXJMb2NrO1xuICAgICAgICBkb2N1bWVudC5leGl0UG9pbnRlckxvY2sgPVxuICAgICAgICAgICAgZG9jdW1lbnQuZXhpdFBvaW50ZXJMb2NrIHx8IGRvY3VtZW50Lm1vekV4aXRQb2ludGVyTG9jaztcblxuICAgICAgICAvLyBtaW5vciBoYWNrIHRvIGFsbGV2aWF0ZSBpb3Mgbm90IHN1cHBvcnRpbmcgcG9pbnRlcmxvY2tcbiAgICAgICAgaWYgKHZpZGVvRWxlbWVudFBhcmVudC5yZXF1ZXN0UG9pbnRlckxvY2spIHtcbiAgICAgICAgICAgIGNvbnN0IG9uY2xpY2sgPSAoKSA9PiB7XG4gICAgICAgICAgICAgICAgdmlkZW9FbGVtZW50UGFyZW50LnJlcXVlc3RQb2ludGVyTG9jaygpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHZpZGVvRWxlbWVudFBhcmVudC5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIG9uY2xpY2spO1xuICAgICAgICAgICAgdGhpcy5tb3VzZUV2ZW50TGlzdGVuZXJUcmFja2VyLmFkZFVucmVnaXN0ZXJDYWxsYmFjayhcbiAgICAgICAgICAgICAgICAoKSA9PiB2aWRlb0VsZW1lbnRQYXJlbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignY2xpY2snLCBvbmNsaWNrKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGxvY2tTdGF0ZUNoYW5nZUxpc3RlbmVyID0gKCkgPT5cbiAgICAgICAgICAgIGxvY2tlZE1vdXNlRXZlbnRzLmxvY2tTdGF0ZUNoYW5nZSgpO1xuICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKFxuICAgICAgICAgICAgJ3BvaW50ZXJsb2NrY2hhbmdlJyxcbiAgICAgICAgICAgIGxvY2tTdGF0ZUNoYW5nZUxpc3RlbmVyLFxuICAgICAgICAgICAgZmFsc2VcbiAgICAgICAgKTtcbiAgICAgICAgZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcbiAgICAgICAgICAgICdtb3pwb2ludGVybG9ja2NoYW5nZScsXG4gICAgICAgICAgICBsb2NrU3RhdGVDaGFuZ2VMaXN0ZW5lcixcbiAgICAgICAgICAgIGZhbHNlXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMubW91c2VFdmVudExpc3RlbmVyVHJhY2tlci5hZGRVbnJlZ2lzdGVyQ2FsbGJhY2soXG4gICAgICAgICAgICAoKSA9PiBkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKFxuICAgICAgICAgICAgICAgICdwb2ludGVybG9ja2NoYW5nZScsXG4gICAgICAgICAgICAgICAgbG9ja1N0YXRlQ2hhbmdlTGlzdGVuZXIsXG4gICAgICAgICAgICAgICAgZmFsc2VcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5tb3VzZUV2ZW50TGlzdGVuZXJUcmFja2VyLmFkZFVucmVnaXN0ZXJDYWxsYmFjayhcbiAgICAgICAgICAgICgpID0+IGRvY3VtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoXG4gICAgICAgICAgICAgICAgJ21venBvaW50ZXJsb2NrY2hhbmdlJyxcbiAgICAgICAgICAgICAgICBsb2NrU3RhdGVDaGFuZ2VMaXN0ZW5lcixcbiAgICAgICAgICAgICAgICBmYWxzZVxuICAgICAgICAgICAgKVxuICAgICAgICApO1xuXG4gICAgICAgIGNvbnN0IG9ubW91c2Vkb3duID0gKG1vdXNlRXZlbnQ6IE1vdXNlRXZlbnQpID0+XG4gICAgICAgICAgICBsb2NrZWRNb3VzZUV2ZW50cy5oYW5kbGVNb3VzZURvd24obW91c2VFdmVudCk7XG4gICAgICAgIGNvbnN0IG9ubW91c2V1cCA9IChtb3VzZUV2ZW50OiBNb3VzZUV2ZW50KSA9PlxuICAgICAgICAgICAgbG9ja2VkTW91c2VFdmVudHMuaGFuZGxlTW91c2VVcChtb3VzZUV2ZW50KTtcbiAgICAgICAgY29uc3Qgb253aGVlbCA9ICh3aGVlbEV2ZW50OiBXaGVlbEV2ZW50KSA9PlxuICAgICAgICAgICAgbG9ja2VkTW91c2VFdmVudHMuaGFuZGxlTW91c2VXaGVlbCh3aGVlbEV2ZW50KTtcbiAgICAgICAgY29uc3Qgb25kYmxjbGljayA9IChtb3VzZUV2ZW50OiBNb3VzZUV2ZW50KSA9PlxuICAgICAgICAgICAgbG9ja2VkTW91c2VFdmVudHMuaGFuZGxlTW91c2VEb3VibGUobW91c2VFdmVudCk7XG4gICAgICAgIHZpZGVvRWxlbWVudFBhcmVudC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZWRvd24nLCBvbm1vdXNlZG93bik7XG4gICAgICAgIHZpZGVvRWxlbWVudFBhcmVudC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgb25tb3VzZXVwKTtcbiAgICAgICAgdmlkZW9FbGVtZW50UGFyZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3doZWVsJywgb253aGVlbCk7XG4gICAgICAgIHZpZGVvRWxlbWVudFBhcmVudC5hZGRFdmVudExpc3RlbmVyKCdkYmxjbGljaycsIG9uZGJsY2xpY2spO1xuXG4gICAgICAgIHRoaXMubW91c2VFdmVudExpc3RlbmVyVHJhY2tlci5hZGRVbnJlZ2lzdGVyQ2FsbGJhY2soXG4gICAgICAgICAgICAoKSA9PiB2aWRlb0VsZW1lbnRQYXJlbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgb25tb3VzZWRvd24pXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMubW91c2VFdmVudExpc3RlbmVyVHJhY2tlci5hZGRVbnJlZ2lzdGVyQ2FsbGJhY2soXG4gICAgICAgICAgICAoKSA9PiB2aWRlb0VsZW1lbnRQYXJlbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2V1cCcsIG9ubW91c2V1cClcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5tb3VzZUV2ZW50TGlzdGVuZXJUcmFja2VyLmFkZFVucmVnaXN0ZXJDYWxsYmFjayhcbiAgICAgICAgICAgICgpID0+IHZpZGVvRWxlbWVudFBhcmVudC5yZW1vdmVFdmVudExpc3RlbmVyKCd3aGVlbCcsIG9ud2hlZWwpXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMubW91c2VFdmVudExpc3RlbmVyVHJhY2tlci5hZGRVbnJlZ2lzdGVyQ2FsbGJhY2soXG4gICAgICAgICAgICAoKSA9PiB2aWRlb0VsZW1lbnRQYXJlbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignZGJsY2xpY2snLCBvbmRibGNsaWNrKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLm1vdXNlRXZlbnRMaXN0ZW5lclRyYWNrZXIuYWRkVW5yZWdpc3RlckNhbGxiYWNrKFxuICAgICAgICAgICAgKCkgPT4gbG9ja2VkTW91c2VFdmVudHMudW5yZWdpc3Rlck1vdXNlRXZlbnRzKClcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5tb3VzZUV2ZW50TGlzdGVuZXJUcmFja2VyLmFkZFVucmVnaXN0ZXJDYWxsYmFjaygoKSA9PiB7XG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgZG9jdW1lbnQuZXhpdFBvaW50ZXJMb2NrICYmXG4gICAgICAgICAgICAgICAgKGRvY3VtZW50LnBvaW50ZXJMb2NrRWxlbWVudCA9PT0gdmlkZW9FbGVtZW50UGFyZW50IHx8XG4gICAgICAgICAgICAgICAgICAgIGRvY3VtZW50Lm1velBvaW50ZXJMb2NrRWxlbWVudCA9PT0gdmlkZW9FbGVtZW50UGFyZW50KVxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgZG9jdW1lbnQuZXhpdFBvaW50ZXJMb2NrKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlZ2lzdGVyIGEgaG92ZXJpbmcgbW91c2UgY2xhc3NcbiAgICAgKiBAcGFyYW0gbW91c2VDb250cm9sbGVyIC0gQSBtb3VzZSBjb250cm9sbGVyIG9iamVjdFxuICAgICAqL1xuICAgIHJlZ2lzdGVySG92ZXJpbmdNb3VzZUV2ZW50cyhtb3VzZUNvbnRyb2xsZXI6IE1vdXNlQ29udHJvbGxlcikge1xuICAgICAgICBjb25zdCB2aWRlb0VsZW1lbnRQYXJlbnQgPVxuICAgICAgICAgICAgdGhpcy52aWRlb0VsZW1lbnRQcm92aWRlci5nZXRWaWRlb1BhcmVudEVsZW1lbnQoKSBhcyBIVE1MRGl2RWxlbWVudDtcbiAgICAgICAgY29uc3QgaG92ZXJpbmdNb3VzZUV2ZW50cyA9IG5ldyBIb3ZlcmluZ01vdXNlRXZlbnRzKG1vdXNlQ29udHJvbGxlcik7XG5cbiAgICAgICAgY29uc3Qgb25tb3VzZW1vdmUgPSAobW91c2VFdmVudDogTW91c2VFdmVudCkgPT5cbiAgICAgICAgICAgIGhvdmVyaW5nTW91c2VFdmVudHMudXBkYXRlTW91c2VNb3ZlUG9zaXRpb24obW91c2VFdmVudCk7XG4gICAgICAgIGNvbnN0IG9ubW91c2Vkb3duID0gKG1vdXNlRXZlbnQ6IE1vdXNlRXZlbnQpID0+XG4gICAgICAgICAgICBob3ZlcmluZ01vdXNlRXZlbnRzLmhhbmRsZU1vdXNlRG93bihtb3VzZUV2ZW50KTtcbiAgICAgICAgY29uc3Qgb25tb3VzZXVwID0gKG1vdXNlRXZlbnQ6IE1vdXNlRXZlbnQpID0+XG4gICAgICAgICAgICBob3ZlcmluZ01vdXNlRXZlbnRzLmhhbmRsZU1vdXNlVXAobW91c2VFdmVudCk7XG4gICAgICAgIGNvbnN0IG9uY29udGV4dG1lbnUgPSAobW91c2VFdmVudDogTW91c2VFdmVudCkgPT5cbiAgICAgICAgICAgIGhvdmVyaW5nTW91c2VFdmVudHMuaGFuZGxlQ29udGV4dE1lbnUobW91c2VFdmVudCk7XG4gICAgICAgIGNvbnN0IG9ud2hlZWwgPSAod2hlZWxFdmVudDogV2hlZWxFdmVudCkgPT5cbiAgICAgICAgICAgIGhvdmVyaW5nTW91c2VFdmVudHMuaGFuZGxlTW91c2VXaGVlbCh3aGVlbEV2ZW50KTtcbiAgICAgICAgY29uc3Qgb25kYmxjbGljayA9IChtb3VzZUV2ZW50OiBNb3VzZUV2ZW50KSA9PlxuICAgICAgICAgICAgaG92ZXJpbmdNb3VzZUV2ZW50cy5oYW5kbGVNb3VzZURvdWJsZShtb3VzZUV2ZW50KTtcbiAgICAgICAgdmlkZW9FbGVtZW50UGFyZW50LmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlbW92ZScsIG9ubW91c2Vtb3ZlKTtcbiAgICAgICAgdmlkZW9FbGVtZW50UGFyZW50LmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNlZG93bicsIG9ubW91c2Vkb3duKTtcbiAgICAgICAgdmlkZW9FbGVtZW50UGFyZW50LmFkZEV2ZW50TGlzdGVuZXIoJ21vdXNldXAnLCBvbm1vdXNldXApO1xuICAgICAgICB2aWRlb0VsZW1lbnRQYXJlbnQuYWRkRXZlbnRMaXN0ZW5lcignY29udGV4dG1lbnUnLCBvbmNvbnRleHRtZW51KTtcbiAgICAgICAgdmlkZW9FbGVtZW50UGFyZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3doZWVsJywgb253aGVlbCk7XG4gICAgICAgIHZpZGVvRWxlbWVudFBhcmVudC5hZGRFdmVudExpc3RlbmVyKCdkYmxjbGljaycsIG9uZGJsY2xpY2spO1xuXG4gICAgICAgIHRoaXMubW91c2VFdmVudExpc3RlbmVyVHJhY2tlci5hZGRVbnJlZ2lzdGVyQ2FsbGJhY2soXG4gICAgICAgICAgICAoKSA9PiB2aWRlb0VsZW1lbnRQYXJlbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgb25tb3VzZW1vdmUpXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMubW91c2VFdmVudExpc3RlbmVyVHJhY2tlci5hZGRVbnJlZ2lzdGVyQ2FsbGJhY2soXG4gICAgICAgICAgICAoKSA9PiB2aWRlb0VsZW1lbnRQYXJlbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgb25tb3VzZWRvd24pXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMubW91c2VFdmVudExpc3RlbmVyVHJhY2tlci5hZGRVbnJlZ2lzdGVyQ2FsbGJhY2soXG4gICAgICAgICAgICAoKSA9PiB2aWRlb0VsZW1lbnRQYXJlbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2V1cCcsIG9ubW91c2V1cClcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5tb3VzZUV2ZW50TGlzdGVuZXJUcmFja2VyLmFkZFVucmVnaXN0ZXJDYWxsYmFjayhcbiAgICAgICAgICAgICgpID0+IHZpZGVvRWxlbWVudFBhcmVudC5yZW1vdmVFdmVudExpc3RlbmVyKCdjb250ZXh0bWVudScsIG9uY29udGV4dG1lbnUpXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMubW91c2VFdmVudExpc3RlbmVyVHJhY2tlci5hZGRVbnJlZ2lzdGVyQ2FsbGJhY2soXG4gICAgICAgICAgICAoKSA9PiB2aWRlb0VsZW1lbnRQYXJlbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignd2hlZWwnLCBvbndoZWVsKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLm1vdXNlRXZlbnRMaXN0ZW5lclRyYWNrZXIuYWRkVW5yZWdpc3RlckNhbGxiYWNrKFxuICAgICAgICAgICAgKCkgPT4gdmlkZW9FbGVtZW50UGFyZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2RibGNsaWNrJywgb25kYmxjbGljaylcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5tb3VzZUV2ZW50TGlzdGVuZXJUcmFja2VyLmFkZFVucmVnaXN0ZXJDYWxsYmFjayhcbiAgICAgICAgICAgICgpID0+IGhvdmVyaW5nTW91c2VFdmVudHMudW5yZWdpc3Rlck1vdXNlRXZlbnRzKClcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXQgdGhlIG1vdXNlIGVudGVyIGFuZCBtb3VzZSBsZWF2ZSBldmVudHNcbiAgICAgKi9cbiAgICByZWdpc3Rlck1vdXNlRW50ZXJBbmRMZWF2ZUV2ZW50cygpIHtcbiAgICAgICAgY29uc3QgdmlkZW9FbGVtZW50UGFyZW50ID1cbiAgICAgICAgICAgIHRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIuZ2V0VmlkZW9QYXJlbnRFbGVtZW50KCkgYXMgSFRNTERpdkVsZW1lbnQ7XG5cbiAgICAgICAgLy8gSGFuZGxlIHdoZW4gdGhlIE1vdXNlIGhhcyBlbnRlcmVkIHRoZSBlbGVtZW50XG4gICAgICAgIGNvbnN0IG9ubW91c2VlbnRlciA9IChldmVudDogTW91c2VFdmVudCkgPT4ge1xuICAgICAgICAgICAgaWYgKCF0aGlzLnZpZGVvRWxlbWVudFByb3ZpZGVyLmlzVmlkZW9SZWFkeSgpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCAnTW91c2UgRW50ZXJlZCcsIDYpO1xuICAgICAgICAgICAgdGhpcy5zZW5kTW91c2VFbnRlcigpO1xuICAgICAgICAgICAgdGhpcy5wcmVzc01vdXNlQnV0dG9ucyhldmVudC5idXR0b25zLCBldmVudC54LCBldmVudC55KTtcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBIYW5kbGVzIHdoZW4gdGhlIG1vdXNlIGhhcyBsZWZ0IHRoZSBlbGVtZW50XG4gICAgICAgIGNvbnN0IG9ubW91c2VsZWF2ZSA9IChldmVudDogTW91c2VFdmVudCkgPT4ge1xuICAgICAgICAgICAgaWYgKCF0aGlzLnZpZGVvRWxlbWVudFByb3ZpZGVyLmlzVmlkZW9SZWFkeSgpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCAnTW91c2UgTGVmdCcsIDYpO1xuICAgICAgICAgICAgdGhpcy5zZW5kTW91c2VMZWF2ZSgpO1xuICAgICAgICAgICAgdGhpcy5yZWxlYXNlTW91c2VCdXR0b25zKGV2ZW50LmJ1dHRvbnMsIGV2ZW50LngsIGV2ZW50LnkpO1xuICAgICAgICB9O1xuICAgICAgICB2aWRlb0VsZW1lbnRQYXJlbnQuYWRkRXZlbnRMaXN0ZW5lcignbW91c2VlbnRlcicsIG9ubW91c2VlbnRlcik7XG4gICAgICAgIHZpZGVvRWxlbWVudFBhcmVudC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZWxlYXZlJywgb25tb3VzZWxlYXZlKTtcblxuICAgICAgICB0aGlzLm1vdXNlRXZlbnRMaXN0ZW5lclRyYWNrZXIuYWRkVW5yZWdpc3RlckNhbGxiYWNrKFxuICAgICAgICAgICAgKCkgPT4gdmlkZW9FbGVtZW50UGFyZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ21vdXNlZW50ZXInLCBvbm1vdXNlZW50ZXIpXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMubW91c2VFdmVudExpc3RlbmVyVHJhY2tlci5hZGRVbnJlZ2lzdGVyQ2FsbGJhY2soXG4gICAgICAgICAgICAoKSA9PiB2aWRlb0VsZW1lbnRQYXJlbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2VsZWF2ZScsIG9ubW91c2VsZWF2ZSlcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGUgd2hlbiBhIG1vdXNlIGJ1dHRvbiBpcyByZWxlYXNlZFxuICAgICAqIEBwYXJhbSBidXR0b25zIC0gTW91c2UgQnV0dG9uXG4gICAgICogQHBhcmFtIFggLSBNb3VzZSBwb2ludGVyIFggY29vcmRpbmF0ZVxuICAgICAqIEBwYXJhbSBZIC0gTW91c2UgcG9pbnRlciBZIGNvb3JkaW5hdGVcbiAgICAgKi9cbiAgICByZWxlYXNlTW91c2VCdXR0b25zKGJ1dHRvbnM6IG51bWJlciwgWDogbnVtYmVyLCBZOiBudW1iZXIpIHtcbiAgICAgICAgY29uc3QgY29vcmQgPSB0aGlzLmNvb3JkaW5hdGVDb252ZXJ0ZXIubm9ybWFsaXplQW5kUXVhbnRpemVVbnNpZ25lZChcbiAgICAgICAgICAgIFgsXG4gICAgICAgICAgICBZXG4gICAgICAgICk7XG4gICAgICAgIGlmIChidXR0b25zICYgTW91c2VCdXR0b25zTWFzay5wcmltYXJ5QnV0dG9uKSB7XG4gICAgICAgICAgICB0aGlzLnNlbmRNb3VzZVVwKE1vdXNlQnV0dG9uLm1haW5CdXR0b24sIGNvb3JkLngsIGNvb3JkLnkpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChidXR0b25zICYgTW91c2VCdXR0b25zTWFzay5zZWNvbmRhcnlCdXR0b24pIHtcbiAgICAgICAgICAgIHRoaXMuc2VuZE1vdXNlVXAoTW91c2VCdXR0b24uc2Vjb25kYXJ5QnV0dG9uLCBjb29yZC54LCBjb29yZC55KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoYnV0dG9ucyAmIE1vdXNlQnV0dG9uc01hc2suYXV4aWxpYXJ5QnV0dG9uKSB7XG4gICAgICAgICAgICB0aGlzLnNlbmRNb3VzZVVwKE1vdXNlQnV0dG9uLmF1eGlsaWFyeUJ1dHRvbiwgY29vcmQueCwgY29vcmQueSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGJ1dHRvbnMgJiBNb3VzZUJ1dHRvbnNNYXNrLmZvdXJ0aEJ1dHRvbikge1xuICAgICAgICAgICAgdGhpcy5zZW5kTW91c2VVcChNb3VzZUJ1dHRvbi5mb3VydGhCdXR0b24sIGNvb3JkLngsIGNvb3JkLnkpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChidXR0b25zICYgTW91c2VCdXR0b25zTWFzay5maWZ0aEJ1dHRvbikge1xuICAgICAgICAgICAgdGhpcy5zZW5kTW91c2VVcChNb3VzZUJ1dHRvbi5maWZ0aEJ1dHRvbiwgY29vcmQueCwgY29vcmQueSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGUgd2hlbiBhIG1vdXNlIGJ1dHRvbiBpcyBwcmVzc2VkXG4gICAgICogQHBhcmFtIGJ1dHRvbnMgLSBNb3VzZSBCdXR0b25cbiAgICAgKiBAcGFyYW0gWCAtIE1vdXNlIHBvaW50ZXIgWCBjb29yZGluYXRlXG4gICAgICogQHBhcmFtIFkgLSBNb3VzZSBwb2ludGVyIFkgY29vcmRpbmF0ZVxuICAgICAqL1xuICAgIHByZXNzTW91c2VCdXR0b25zKGJ1dHRvbnM6IG51bWJlciwgWDogbnVtYmVyLCBZOiBudW1iZXIpIHtcbiAgICAgICAgaWYgKCF0aGlzLnZpZGVvRWxlbWVudFByb3ZpZGVyLmlzVmlkZW9SZWFkeSgpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgY29vcmQgPSB0aGlzLmNvb3JkaW5hdGVDb252ZXJ0ZXIubm9ybWFsaXplQW5kUXVhbnRpemVVbnNpZ25lZChcbiAgICAgICAgICAgIFgsXG4gICAgICAgICAgICBZXG4gICAgICAgICk7XG4gICAgICAgIGlmIChidXR0b25zICYgTW91c2VCdXR0b25zTWFzay5wcmltYXJ5QnV0dG9uKSB7XG4gICAgICAgICAgICB0aGlzLnNlbmRNb3VzZURvd24oTW91c2VCdXR0b24ubWFpbkJ1dHRvbiwgY29vcmQueCwgY29vcmQueSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGJ1dHRvbnMgJiBNb3VzZUJ1dHRvbnNNYXNrLnNlY29uZGFyeUJ1dHRvbikge1xuICAgICAgICAgICAgdGhpcy5zZW5kTW91c2VEb3duKE1vdXNlQnV0dG9uLnNlY29uZGFyeUJ1dHRvbiwgY29vcmQueCwgY29vcmQueSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGJ1dHRvbnMgJiBNb3VzZUJ1dHRvbnNNYXNrLmF1eGlsaWFyeUJ1dHRvbikge1xuICAgICAgICAgICAgdGhpcy5zZW5kTW91c2VEb3duKE1vdXNlQnV0dG9uLmF1eGlsaWFyeUJ1dHRvbiwgY29vcmQueCwgY29vcmQueSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGJ1dHRvbnMgJiBNb3VzZUJ1dHRvbnNNYXNrLmZvdXJ0aEJ1dHRvbikge1xuICAgICAgICAgICAgdGhpcy5zZW5kTW91c2VEb3duKE1vdXNlQnV0dG9uLmZvdXJ0aEJ1dHRvbiwgY29vcmQueCwgY29vcmQueSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGJ1dHRvbnMgJiBNb3VzZUJ1dHRvbnNNYXNrLmZpZnRoQnV0dG9uKSB7XG4gICAgICAgICAgICB0aGlzLnNlbmRNb3VzZURvd24oTW91c2VCdXR0b24uZmlmdGhCdXR0b24sIGNvb3JkLngsIGNvb3JkLnkpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSGFuZGxlcyBtb3VzZSBlbnRlclxuICAgICAqL1xuICAgIHNlbmRNb3VzZUVudGVyKCkge1xuICAgICAgICBpZiAoIXRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIuaXNWaWRlb1JlYWR5KCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCB0b1N0cmVhbWVySGFuZGxlcnMgPVxuICAgICAgICAgICAgdGhpcy50b1N0cmVhbWVyTWVzc2FnZXNQcm92aWRlci50b1N0cmVhbWVySGFuZGxlcnM7XG4gICAgICAgIHRvU3RyZWFtZXJIYW5kbGVycy5nZXQoJ01vdXNlRW50ZXInKSgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEhhbmRsZXMgbW91c2UgTGVhdmVcbiAgICAgKi9cbiAgICBzZW5kTW91c2VMZWF2ZSgpIHtcbiAgICAgICAgaWYgKCF0aGlzLnZpZGVvRWxlbWVudFByb3ZpZGVyLmlzVmlkZW9SZWFkeSgpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgdG9TdHJlYW1lckhhbmRsZXJzID1cbiAgICAgICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIudG9TdHJlYW1lckhhbmRsZXJzO1xuICAgICAgICB0b1N0cmVhbWVySGFuZGxlcnMuZ2V0KCdNb3VzZUxlYXZlJykoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGVzIHdoZW4gYSBtb3VzZSBidXR0b24gaXMgcHJlc3NlZCBkb3duXG4gICAgICogQHBhcmFtIGJ1dHRvbiAtIE1vdXNlIEJ1dHRvbiBQcmVzc2VkXG4gICAgICogQHBhcmFtIFggIC0gTW91c2UgWCBDb29yZGluYXRlXG4gICAgICogQHBhcmFtIFkgIC0gTW91c2UgWSBDb29yZGluYXRlXG4gICAgICovXG4gICAgc2VuZE1vdXNlRG93bihidXR0b246IG51bWJlciwgWDogbnVtYmVyLCBZOiBudW1iZXIpIHtcbiAgICAgICAgaWYgKCF0aGlzLnZpZGVvRWxlbWVudFByb3ZpZGVyLmlzVmlkZW9SZWFkeSgpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICBgbW91c2UgYnV0dG9uICR7YnV0dG9ufSBkb3duIGF0ICgke1h9LCAke1l9KWAsXG4gICAgICAgICAgICA2XG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHRvU3RyZWFtZXJIYW5kbGVycyA9XG4gICAgICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyLnRvU3RyZWFtZXJIYW5kbGVycztcbiAgICAgICAgdG9TdHJlYW1lckhhbmRsZXJzLmdldCgnTW91c2VEb3duJykoW2J1dHRvbiwgWCwgWV0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEhhbmRsZXMgd2hlbiBhIG1vdXNlIGJ1dHRvbiBpcyBwcmVzc2VkIHVwXG4gICAgICogQHBhcmFtIGJ1dHRvbiAtIE1vdXNlIEJ1dHRvbiBQcmVzc2VkXG4gICAgICogQHBhcmFtIFggIC0gTW91c2UgWCBDb29yZGluYXRlXG4gICAgICogQHBhcmFtIFkgIC0gTW91c2UgWSBDb29yZGluYXRlXG4gICAgICovXG4gICAgc2VuZE1vdXNlVXAoYnV0dG9uOiBudW1iZXIsIFg6IG51bWJlciwgWTogbnVtYmVyKSB7XG4gICAgICAgIGlmICghdGhpcy52aWRlb0VsZW1lbnRQcm92aWRlci5pc1ZpZGVvUmVhZHkoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgYG1vdXNlIGJ1dHRvbiAke2J1dHRvbn0gdXAgYXQgKCR7WH0sICR7WX0pYCxcbiAgICAgICAgICAgIDZcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgY29vcmQgPSB0aGlzLmNvb3JkaW5hdGVDb252ZXJ0ZXIubm9ybWFsaXplQW5kUXVhbnRpemVVbnNpZ25lZChcbiAgICAgICAgICAgIFgsXG4gICAgICAgICAgICBZXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHRvU3RyZWFtZXJIYW5kbGVycyA9XG4gICAgICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyLnRvU3RyZWFtZXJIYW5kbGVycztcbiAgICAgICAgdG9TdHJlYW1lckhhbmRsZXJzLmdldCgnTW91c2VVcCcpKFtidXR0b24sIGNvb3JkLngsIGNvb3JkLnldKTtcbiAgICB9XG59XG4iLCIvLyBDb3B5cmlnaHQgRXBpYyBHYW1lcywgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuXG4vKipcbiAqIFJlZ2lzdGVycyB0aGUgU3BlY2lhbCBLZXkgY29kZXNcbiAqICBNdXN0IGJlIGtlcHQgaW4gc3luYyB3aXRoIEphdmFTY3JpcHRLZXlDb2RlVG9GS2V5IEMrKyBhcnJheS5cbiAqIFRoZSBpbmRleCBvZiB0aGUgZW50cnkgaW4gdGhlIGFycmF5IGlzIHRoZSBzcGVjaWFsIGtleSBjb2RlIGdpdmVuIGJlbG93LlxuICovXG5leHBvcnQgY2xhc3MgU3BlY2lhbEtleUNvZGVzIHtcbiAgICBzdGF0aWMgYmFja1NwYWNlID0gODtcbiAgICBzdGF0aWMgc2hpZnQgPSAxNjtcbiAgICBzdGF0aWMgY29udHJvbCA9IDE3O1xuICAgIHN0YXRpYyBhbHQgPSAxODtcbiAgICBzdGF0aWMgcmlnaHRTaGlmdCA9IDI1MztcbiAgICBzdGF0aWMgcmlnaHRDb250cm9sID0gMjU0O1xuICAgIHN0YXRpYyByaWdodEFsdCA9IDI1NTtcbn1cbiIsIi8vIENvcHlyaWdodCBFcGljIEdhbWVzLCBJbmMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG5cbmltcG9ydCB7IExvZ2dlciB9IGZyb20gJy4uL0xvZ2dlci9Mb2dnZXInO1xuaW1wb3J0IHsgQ29vcmRpbmF0ZUNvbnZlcnRlciB9IGZyb20gJy4uL1V0aWwvQ29vcmRpbmF0ZUNvbnZlcnRlcic7XG5pbXBvcnQgeyBTdHJlYW1NZXNzYWdlQ29udHJvbGxlciB9IGZyb20gJy4uL1VlSW5zdGFuY2VNZXNzYWdlL1N0cmVhbU1lc3NhZ2VDb250cm9sbGVyJztcbmltcG9ydCB7IFZpZGVvUGxheWVyIH0gZnJvbSAnLi4vVmlkZW9QbGF5ZXIvVmlkZW9QbGF5ZXInO1xuaW1wb3J0IHsgSVRvdWNoQ29udHJvbGxlciB9IGZyb20gJy4vSVRvdWNoQ29udHJvbGxlcic7XG5pbXBvcnQgeyBFdmVudExpc3RlbmVyVHJhY2tlciB9IGZyb20gJy4uL1V0aWwvRXZlbnRMaXN0ZW5lclRyYWNrZXInO1xuLyoqXG4gKiBIYW5kbGVzIHRoZSBUb3VjaCBpbnB1dCBFdmVudHNcbiAqL1xuZXhwb3J0IGNsYXNzIFRvdWNoQ29udHJvbGxlciBpbXBsZW1lbnRzIElUb3VjaENvbnRyb2xsZXIge1xuICAgIHRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyOiBTdHJlYW1NZXNzYWdlQ29udHJvbGxlcjtcbiAgICB2aWRlb0VsZW1lbnRQcm92aWRlcjogVmlkZW9QbGF5ZXI7XG4gICAgY29vcmRpbmF0ZUNvbnZlcnRlcjogQ29vcmRpbmF0ZUNvbnZlcnRlcjtcbiAgICB2aWRlb0VsZW1lbnRQYXJlbnQ6IEhUTUxWaWRlb0VsZW1lbnQ7XG4gICAgZmluZ2VycyA9IFs5LCA4LCA3LCA2LCA1LCA0LCAzLCAyLCAxLCAwXTtcbiAgICBmaW5nZXJJZHMgPSBuZXcgTWFwKCk7XG4gICAgbWF4Qnl0ZVZhbHVlID0gMjU1O1xuXG4gICAgLy8gVXRpbGl0eSBmb3Iga2VlcGluZyB0cmFjayBvZiBldmVudCBoYW5kbGVycyBhbmQgdW5yZWdpc3RlcmluZyB0aGVtXG4gICAgcHJpdmF0ZSB0b3VjaEV2ZW50TGlzdGVuZXJUcmFja2VyID0gbmV3IEV2ZW50TGlzdGVuZXJUcmFja2VyKCk7XG5cbiAgICAvKipcbiAgICAgKiBAcGFyYW0gdG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIgLSBTdHJlYW0gbWVzc2FnZSBpbnN0YW5jZVxuICAgICAqIEBwYXJhbSB2aWRlb0VsZW1lbnRQcm92aWRlciAtIFZpZGVvIFBsYXllciBpbnN0YW5jZVxuICAgICAqIEBwYXJhbSBjb29yZGluYXRlQ29udmVydGVyIC0gQSBjb29yZGluYXRlIGNvbnZlcnRlciBpbnN0YW5jZVxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICB0b1N0cmVhbWVyTWVzc2FnZXNQcm92aWRlcjogU3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIsXG4gICAgICAgIHZpZGVvRWxlbWVudFByb3ZpZGVyOiBWaWRlb1BsYXllcixcbiAgICAgICAgY29vcmRpbmF0ZUNvbnZlcnRlcjogQ29vcmRpbmF0ZUNvbnZlcnRlclxuICAgICkge1xuICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyID0gdG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXI7XG4gICAgICAgIHRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIgPSB2aWRlb0VsZW1lbnRQcm92aWRlcjtcbiAgICAgICAgdGhpcy5jb29yZGluYXRlQ29udmVydGVyID0gY29vcmRpbmF0ZUNvbnZlcnRlcjtcbiAgICAgICAgdGhpcy52aWRlb0VsZW1lbnRQYXJlbnQgPSB2aWRlb0VsZW1lbnRQcm92aWRlci5nZXRWaWRlb0VsZW1lbnQoKTtcbiAgICAgICAgY29uc3Qgb250b3VjaHN0YXJ0ID0gKGV2OiBUb3VjaEV2ZW50KSA9PlxuICAgICAgICAgICAgdGhpcy5vblRvdWNoU3RhcnQoZXYpO1xuICAgICAgICBjb25zdCBvbnRvdWNoZW5kID0gKGV2OiBUb3VjaEV2ZW50KSA9PlxuICAgICAgICAgICAgdGhpcy5vblRvdWNoRW5kKGV2KTtcbiAgICAgICAgY29uc3Qgb250b3VjaG1vdmUgPSAoZXY6IFRvdWNoRXZlbnQpID0+XG4gICAgICAgICAgICB0aGlzLm9uVG91Y2hNb3ZlKGV2KTtcbiAgICAgICAgdGhpcy52aWRlb0VsZW1lbnRQYXJlbnQuYWRkRXZlbnRMaXN0ZW5lcigndG91Y2hzdGFydCcsIG9udG91Y2hzdGFydCk7XG4gICAgICAgIHRoaXMudmlkZW9FbGVtZW50UGFyZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3RvdWNoZW5kJywgb250b3VjaGVuZCk7XG4gICAgICAgIHRoaXMudmlkZW9FbGVtZW50UGFyZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3RvdWNobW92ZScsIG9udG91Y2htb3ZlKTtcbiAgICAgICAgdGhpcy50b3VjaEV2ZW50TGlzdGVuZXJUcmFja2VyLmFkZFVucmVnaXN0ZXJDYWxsYmFjayhcbiAgICAgICAgICAgICgpID0+IHRoaXMudmlkZW9FbGVtZW50UGFyZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RvdWNoc3RhcnQnLCBvbnRvdWNoc3RhcnQpXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMudG91Y2hFdmVudExpc3RlbmVyVHJhY2tlci5hZGRVbnJlZ2lzdGVyQ2FsbGJhY2soXG4gICAgICAgICAgICAoKSA9PiB0aGlzLnZpZGVvRWxlbWVudFBhcmVudC5yZW1vdmVFdmVudExpc3RlbmVyKCd0b3VjaGVuZCcsIG9udG91Y2hlbmQpXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMudG91Y2hFdmVudExpc3RlbmVyVHJhY2tlci5hZGRVbnJlZ2lzdGVyQ2FsbGJhY2soXG4gICAgICAgICAgICAoKSA9PiB0aGlzLnZpZGVvRWxlbWVudFBhcmVudC5yZW1vdmVFdmVudExpc3RlbmVyKCd0b3VjaG1vdmUnLCBvbnRvdWNobW92ZSlcbiAgICAgICAgKTtcbiAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCAnVG91Y2ggRXZlbnRzIFJlZ2lzdGVyZWQnLCA2KTtcblxuICAgICAgICAvLyBpcyB0aGlzIHN0cmljdGx5IG5lY2Vzc2FyeT9cbiAgICAgICAgY29uc3QgcHJldmVudE9uVG91Y2hNb3ZlID0gKGV2ZW50OiBUb3VjaEV2ZW50KSA9PiB7XG4gICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB9O1xuICAgICAgICBkb2N1bWVudC5hZGRFdmVudExpc3RlbmVyKCd0b3VjaG1vdmUnLCBwcmV2ZW50T25Ub3VjaE1vdmUpO1xuICAgICAgICB0aGlzLnRvdWNoRXZlbnRMaXN0ZW5lclRyYWNrZXIuYWRkVW5yZWdpc3RlckNhbGxiYWNrKFxuICAgICAgICAgICAgKCkgPT4gZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigndG91Y2htb3ZlJywgcHJldmVudE9uVG91Y2hNb3ZlKVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFVucmVnaXN0ZXIgYWxsIHRvdWNoIGV2ZW50c1xuICAgICAqL1xuICAgIHVucmVnaXN0ZXJUb3VjaEV2ZW50cygpIHtcbiAgICAgICAgdGhpcy50b3VjaEV2ZW50TGlzdGVuZXJUcmFja2VyLnVucmVnaXN0ZXJBbGwoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZW1lbWJlciBhIHRvdWNoIGNvbW1hbmRcbiAgICAgKiBAcGFyYW0gdG91Y2ggLSB0aGUgdG91Y2ggY29tbWFuZFxuICAgICAqL1xuICAgIHJlbWVtYmVyVG91Y2godG91Y2g6IFRvdWNoKSB7XG4gICAgICAgIGNvbnN0IGZpbmdlciA9IHRoaXMuZmluZ2Vycy5wb3AoKTtcbiAgICAgICAgaWYgKGZpbmdlciA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgJ2V4aGF1c3RlZCB0b3VjaCBpZGVudGlmaWVycycsXG4gICAgICAgICAgICAgICAgNlxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmZpbmdlcklkcy5zZXQodG91Y2guaWRlbnRpZmllciwgZmluZ2VyKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBGb3JnZXRzIGEgdG91Y2ggY29tbWFuZFxuICAgICAqIEBwYXJhbSB0b3VjaCAtIHRoZSB0b3VjaCBjb21tYW5kXG4gICAgICovXG4gICAgZm9yZ2V0VG91Y2godG91Y2g6IFRvdWNoKSB7XG4gICAgICAgIHRoaXMuZmluZ2Vycy5wdXNoKHRoaXMuZmluZ2VySWRzLmdldCh0b3VjaC5pZGVudGlmaWVyKSk7XG4gICAgICAgIC8vIFNvcnQgYXJyYXkgYmFjayBpbnRvIGRlc2NlbmRpbmcgb3JkZXIuIFRoaXMgbWVhbnMgaWYgZmluZ2VyICcxJyB3ZXJlIHRvIGxpZnQgYWZ0ZXIgZmluZ2VyICcwJywgd2Ugd291bGQgZW5zdXJlIHRoYXQgMCB3aWxsIGJlIHRoZSBmaXJzdCBpbmRleCB0byBwb3BcbiAgICAgICAgdGhpcy5maW5nZXJzLnNvcnQoZnVuY3Rpb24gKGEsIGIpIHtcbiAgICAgICAgICAgIHJldHVybiBiIC0gYTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuZmluZ2VySWRzLmRlbGV0ZSh0b3VjaC5pZGVudGlmaWVyKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBXaGVuIGEgdG91Y2ggZXZlbnQgc3RhcnRzXG4gICAgICogQHBhcmFtIHRvdWNoRXZlbnQgLSB0aGUgdG91Y2ggZXZlbnQgYmVpbmcgaW50ZXJjZXB0ZWRcbiAgICAgKi9cbiAgICBvblRvdWNoU3RhcnQodG91Y2hFdmVudDogVG91Y2hFdmVudCkge1xuICAgICAgICBpZiAoIXRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIuaXNWaWRlb1JlYWR5KCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBmb3IgKGxldCB0ID0gMDsgdCA8IHRvdWNoRXZlbnQuY2hhbmdlZFRvdWNoZXMubGVuZ3RoOyB0KyspIHtcbiAgICAgICAgICAgIHRoaXMucmVtZW1iZXJUb3VjaCh0b3VjaEV2ZW50LmNoYW5nZWRUb3VjaGVzW3RdKTtcbiAgICAgICAgfVxuICAgICAgICBMb2dnZXIuTG9nKExvZ2dlci5HZXRTdGFja1RyYWNlKCksICd0b3VjaCBzdGFydCcsIDYpO1xuXG4gICAgICAgIHRoaXMuZW1pdFRvdWNoRGF0YSgnVG91Y2hTdGFydCcsIHRvdWNoRXZlbnQuY2hhbmdlZFRvdWNoZXMpO1xuICAgICAgICB0b3VjaEV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogV2hlbiBhIHRvdWNoIGV2ZW50IGVuZHNcbiAgICAgKiBAcGFyYW0gdG91Y2hFdmVudCAtIHRoZSB0b3VjaCBldmVudCBiZWluZyBpbnRlcmNlcHRlZFxuICAgICAqL1xuICAgIG9uVG91Y2hFbmQodG91Y2hFdmVudDogVG91Y2hFdmVudCkge1xuICAgICAgICBpZiAoIXRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIuaXNWaWRlb1JlYWR5KCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBMb2dnZXIuTG9nKExvZ2dlci5HZXRTdGFja1RyYWNlKCksICd0b3VjaCBlbmQnLCA2KTtcbiAgICAgICAgdGhpcy5lbWl0VG91Y2hEYXRhKCdUb3VjaEVuZCcsIHRvdWNoRXZlbnQuY2hhbmdlZFRvdWNoZXMpO1xuICAgICAgICAvLyBSZS1jeWNsZSB1bmlxdWUgaWRlbnRpZmllcnMgcHJldmlvdXNseSBhc3NpZ25lZCB0byBlYWNoIHRvdWNoLlxuICAgICAgICBmb3IgKGxldCB0ID0gMDsgdCA8IHRvdWNoRXZlbnQuY2hhbmdlZFRvdWNoZXMubGVuZ3RoOyB0KyspIHtcbiAgICAgICAgICAgIHRoaXMuZm9yZ2V0VG91Y2godG91Y2hFdmVudC5jaGFuZ2VkVG91Y2hlc1t0XSk7XG4gICAgICAgIH1cbiAgICAgICAgdG91Y2hFdmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIHdoZW4gYSBtb3ZpbmcgdG91Y2ggZXZlbnQgb2NjdXJzXG4gICAgICogQHBhcmFtIHRvdWNoRXZlbnQgLSB0aGUgdG91Y2ggZXZlbnQgYmVpbmcgaW50ZXJjZXB0ZWRcbiAgICAgKi9cbiAgICBvblRvdWNoTW92ZSh0b3VjaEV2ZW50OiBUb3VjaEV2ZW50KSB7XG4gICAgICAgIGlmICghdGhpcy52aWRlb0VsZW1lbnRQcm92aWRlci5pc1ZpZGVvUmVhZHkoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIExvZ2dlci5Mb2coTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSwgJ3RvdWNoIG1vdmUnLCA2KTtcbiAgICAgICAgdGhpcy5lbWl0VG91Y2hEYXRhKCdUb3VjaE1vdmUnLCB0b3VjaEV2ZW50LnRvdWNoZXMpO1xuICAgICAgICB0b3VjaEV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxuXG4gICAgZW1pdFRvdWNoRGF0YSh0eXBlOiBzdHJpbmcsIHRvdWNoZXM6IFRvdWNoTGlzdCkge1xuICAgICAgICBpZiAoIXRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIuaXNWaWRlb1JlYWR5KCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBvZmZzZXQgPSB0aGlzLnZpZGVvRWxlbWVudFByb3ZpZGVyLmdldFZpZGVvUGFyZW50RWxlbWVudCgpLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgICBjb25zdCB0b1N0cmVhbWVySGFuZGxlcnMgPVxuICAgICAgICAgICAgdGhpcy50b1N0cmVhbWVyTWVzc2FnZXNQcm92aWRlci50b1N0cmVhbWVySGFuZGxlcnM7XG5cbiAgICAgICAgZm9yIChsZXQgdCA9IDA7IHQgPCB0b3VjaGVzLmxlbmd0aDsgdCsrKSB7XG4gICAgICAgICAgICBjb25zdCBudW1Ub3VjaGVzID0gMTsgLy8gdGhlIG51bWJlciBvZiB0b3VjaGVzIHRvIGJlIHNlbnQgdGhpcyBtZXNzYWdlXG4gICAgICAgICAgICBjb25zdCB0b3VjaCA9IHRvdWNoZXNbdF07XG4gICAgICAgICAgICBjb25zdCB4ID0gdG91Y2guY2xpZW50WCAtIG9mZnNldC5sZWZ0O1xuICAgICAgICAgICAgY29uc3QgeSA9IHRvdWNoLmNsaWVudFkgLSBvZmZzZXQudG9wO1xuICAgICAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgIGBGJHt0aGlzLmZpbmdlcklkcy5nZXQodG91Y2guaWRlbnRpZmllcil9PSgke3h9LCAke3l9KWAsXG4gICAgICAgICAgICAgICAgNlxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgY29uc3QgY29vcmQgPSB0aGlzLmNvb3JkaW5hdGVDb252ZXJ0ZXIubm9ybWFsaXplQW5kUXVhbnRpemVVbnNpZ25lZChcbiAgICAgICAgICAgICAgICB4LFxuICAgICAgICAgICAgICAgIHlcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBzd2l0Y2ggKHR5cGUpIHtcbiAgICAgICAgICAgICAgICBjYXNlICdUb3VjaFN0YXJ0JzpcbiAgICAgICAgICAgICAgICAgICAgdG9TdHJlYW1lckhhbmRsZXJzLmdldCgnVG91Y2hTdGFydCcpKFtcbiAgICAgICAgICAgICAgICAgICAgICAgIG51bVRvdWNoZXMsXG4gICAgICAgICAgICAgICAgICAgICAgICBjb29yZC54LFxuICAgICAgICAgICAgICAgICAgICAgICAgY29vcmQueSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZmluZ2VySWRzLmdldCh0b3VjaC5pZGVudGlmaWVyKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubWF4Qnl0ZVZhbHVlICogdG91Y2guZm9yY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBjb29yZC5pblJhbmdlID8gMSA6IDBcbiAgICAgICAgICAgICAgICAgICAgXSk7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgJ1RvdWNoRW5kJzpcbiAgICAgICAgICAgICAgICAgICAgdG9TdHJlYW1lckhhbmRsZXJzLmdldCgnVG91Y2hFbmQnKShbXG4gICAgICAgICAgICAgICAgICAgICAgICBudW1Ub3VjaGVzLFxuICAgICAgICAgICAgICAgICAgICAgICAgY29vcmQueCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvb3JkLnksXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmZpbmdlcklkcy5nZXQodG91Y2guaWRlbnRpZmllciksXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLm1heEJ5dGVWYWx1ZSAqIHRvdWNoLmZvcmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgY29vcmQuaW5SYW5nZSA/IDEgOiAwXG4gICAgICAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlICdUb3VjaE1vdmUnOlxuICAgICAgICAgICAgICAgICAgICB0b1N0cmVhbWVySGFuZGxlcnMuZ2V0KCdUb3VjaE1vdmUnKShbXG4gICAgICAgICAgICAgICAgICAgICAgICBudW1Ub3VjaGVzLFxuICAgICAgICAgICAgICAgICAgICAgICAgY29vcmQueCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvb3JkLnksXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmZpbmdlcklkcy5nZXQodG91Y2guaWRlbnRpZmllciksXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLm1heEJ5dGVWYWx1ZSAqIHRvdWNoLmZvcmNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgY29vcmQuaW5SYW5nZSA/IDEgOiAwXG4gICAgICAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbn1cbiIsIi8vIENvcHlyaWdodCBFcGljIEdhbWVzLCBJbmMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG5cbmltcG9ydCB7IFN0cmVhbU1lc3NhZ2VDb250cm9sbGVyIH0gZnJvbSAnLi4vVWVJbnN0YW5jZU1lc3NhZ2UvU3RyZWFtTWVzc2FnZUNvbnRyb2xsZXInO1xuaW1wb3J0IHsgQ29udHJvbGxlciB9IGZyb20gJy4vR2FtZXBhZFR5cGVzJztcbmltcG9ydCB7IFdlYlhSVXRpbHMgfSBmcm9tICcuLi9VdGlsL1dlYlhSVXRpbHMnO1xuXG4vKipcbiAqIFRoZSBjbGFzcyB0aGF0IGhhbmRsZXMgdGhlIGZ1bmN0aW9uYWxpdHkgb2YgeHJnYW1lcGFkcyBhbmQgY29udHJvbGxlcnNcbiAqL1xuZXhwb3J0IGNsYXNzIFhSR2FtZXBhZENvbnRyb2xsZXIge1xuICAgIGNvbnRyb2xsZXJzOiBBcnJheTxDb250cm9sbGVyPjtcbiAgICB0b1N0cmVhbWVyTWVzc2FnZXNQcm92aWRlcjogU3RyZWFtTWVzc2FnZUNvbnRyb2xsZXI7XG5cbiAgICAvKipcbiAgICAgKiBAcGFyYW0gdG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIgLSBTdHJlYW0gbWVzc2FnZSBpbnN0YW5jZVxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKHRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyOiBTdHJlYW1NZXNzYWdlQ29udHJvbGxlcikge1xuICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyID0gdG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXI7XG4gICAgICAgIHRoaXMuY29udHJvbGxlcnMgPSBbXTtcbiAgICB9XG5cbiAgICB1cGRhdGVTdGF0dXMoXG4gICAgICAgIHNvdXJjZTogWFJJbnB1dFNvdXJjZSxcbiAgICAgICAgZnJhbWU6IFhSRnJhbWUsXG4gICAgICAgIHJlZlNwYWNlOiBYUlJlZmVyZW5jZVNwYWNlXG4gICAgKSB7XG4gICAgICAgIGlmIChzb3VyY2UuZ2FtZXBhZCkge1xuICAgICAgICAgICAgY29uc3QgZ2FtZXBhZFBvc2UgPSBmcmFtZS5nZXRQb3NlKHNvdXJjZS5ncmlwU3BhY2UsIHJlZlNwYWNlKTtcbiAgICAgICAgICAgIGlmICghZ2FtZXBhZFBvc2UpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGxldCBzeXN0ZW0gPSAwO1xuICAgICAgICAgICAgaWYgKHNvdXJjZS5wcm9maWxlcy5pbmNsdWRlcygnaHRjLXZpdmUnKSkge1xuICAgICAgICAgICAgICAgIHN5c3RlbSA9IDE7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHNvdXJjZS5wcm9maWxlcy5pbmNsdWRlcygnb2N1bHVzLXRvdWNoJykpIHtcbiAgICAgICAgICAgICAgICBzeXN0ZW0gPSAyO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gVE9ETyAod2lsbGlhbS5iZWxjaGVyKTogQWRkIG90aGVyIHByb2ZpbGVzIChRdWVzdCwgTWljcm9zb2Z0IE1peGVkIFJlYWxpdHksIGV0YylcbiAgICAgICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIudG9TdHJlYW1lckhhbmRsZXJzLmdldCgnWFJTeXN0ZW0nKShbXG4gICAgICAgICAgICAgICAgc3lzdGVtXG4gICAgICAgICAgICBdKTtcblxuICAgICAgICAgICAgLy8gRGVmYXVsdDogQW55SGFuZCAoMilcbiAgICAgICAgICAgIGxldCBoYW5kZWRuZXNzID0gMjtcbiAgICAgICAgICAgIHN3aXRjaCAoc291cmNlLmhhbmRlZG5lc3MpIHtcbiAgICAgICAgICAgICAgICBjYXNlICdsZWZ0JzpcbiAgICAgICAgICAgICAgICAgICAgaGFuZGVkbmVzcyA9IDA7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgJ3JpZ2h0JzpcbiAgICAgICAgICAgICAgICAgICAgaGFuZGVkbmVzcyA9IDE7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBTZW5kIGNvbnRyb2xsZXIgdHJhbnNmb3JtXG4gICAgICAgICAgICBjb25zdCBtYXRyaXggPSBnYW1lcGFkUG9zZS50cmFuc2Zvcm0ubWF0cml4O1xuICAgICAgICAgICAgY29uc3QgbWF0ID0gW107XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDE2OyBpKyspIHtcbiAgICAgICAgICAgICAgICBtYXRbaV0gPSBuZXcgRmxvYXQzMkFycmF5KFttYXRyaXhbaV1dKVswXTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gcHJldHRpZXItaWdub3JlXG4gICAgICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyLnRvU3RyZWFtZXJIYW5kbGVycy5nZXQoJ1hSQ29udHJvbGxlclRyYW5zZm9ybScpKFtcbiAgICAgICAgICAgICAgICBtYXRbMF0sIG1hdFs0XSwgbWF0WzhdLCBtYXRbMTJdLFxuICAgICAgICAgICAgICAgIG1hdFsxXSwgbWF0WzVdLCBtYXRbOV0sIG1hdFsxM10sXG4gICAgICAgICAgICAgICAgbWF0WzJdLCBtYXRbNl0sIG1hdFsxMF0sIG1hdFsxNF0sXG4gICAgICAgICAgICAgICAgbWF0WzNdLCBtYXRbN10sIG1hdFsxMV0sIG1hdFsxNV0sXG4gICAgICAgICAgICAgICAgaGFuZGVkbmVzc1xuICAgICAgICAgICAgXSk7XG5cbiAgICAgICAgICAgIC8vIEhhbmRsZSBjb250cm9sbGVyIGJ1dHRvbnMgYW5kIGF4ZXNcbiAgICAgICAgICAgIGlmICh0aGlzLmNvbnRyb2xsZXJzW2hhbmRlZG5lc3NdID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmNvbnRyb2xsZXJzW2hhbmRlZG5lc3NdID0ge1xuICAgICAgICAgICAgICAgICAgICBwcmV2U3RhdGU6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICAgICAgY3VycmVudFN0YXRlOiB1bmRlZmluZWQsXG5cdFx0XHRcdFx0aWQ6IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgdGhpcy5jb250cm9sbGVyc1toYW5kZWRuZXNzXS5wcmV2U3RhdGUgPVxuICAgICAgICAgICAgICAgICAgICBXZWJYUlV0aWxzLmRlZXBDb3B5R2FtZXBhZChzb3VyY2UuZ2FtZXBhZCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuY29udHJvbGxlcnNbaGFuZGVkbmVzc10uY3VycmVudFN0YXRlID1cbiAgICAgICAgICAgICAgICBXZWJYUlV0aWxzLmRlZXBDb3B5R2FtZXBhZChzb3VyY2UuZ2FtZXBhZCk7XG5cbiAgICAgICAgICAgIGNvbnN0IGNvbnRyb2xsZXIgPSB0aGlzLmNvbnRyb2xsZXJzW2hhbmRlZG5lc3NdO1xuICAgICAgICAgICAgY29uc3QgY3VyclN0YXRlID0gY29udHJvbGxlci5jdXJyZW50U3RhdGU7XG4gICAgICAgICAgICBjb25zdCBwcmV2U3RhdGUgPSBjb250cm9sbGVyLnByZXZTdGF0ZTtcbiAgICAgICAgICAgIC8vIEl0ZXJhdGUgb3ZlciBidXR0b25zXG4gICAgICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGN1cnJTdGF0ZS5idXR0b25zLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgY3VyckJ1dHRvbiA9IGN1cnJTdGF0ZS5idXR0b25zW2ldO1xuICAgICAgICAgICAgICAgIGNvbnN0IHByZXZCdXR0b24gPSBwcmV2U3RhdGUuYnV0dG9uc1tpXTtcblxuICAgICAgICAgICAgICAgIGlmIChjdXJyQnV0dG9uLnByZXNzZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gcHJlc3NcbiAgICAgICAgICAgICAgICAgICAgdGhpcy50b1N0cmVhbWVyTWVzc2FnZXNQcm92aWRlci50b1N0cmVhbWVySGFuZGxlcnMuZ2V0KFxuICAgICAgICAgICAgICAgICAgICAgICAgJ1hSQnV0dG9uUHJlc3NlZCdcbiAgICAgICAgICAgICAgICAgICAgKShbaGFuZGVkbmVzcywgaSwgcHJldkJ1dHRvbi5wcmVzc2VkID8gMSA6IDBdKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKCFjdXJyQnV0dG9uLnByZXNzZWQgJiYgcHJldkJ1dHRvbi5wcmVzc2VkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIudG9TdHJlYW1lckhhbmRsZXJzLmdldChcbiAgICAgICAgICAgICAgICAgICAgICAgICdYUkJ1dHRvblJlbGVhc2VkJ1xuICAgICAgICAgICAgICAgICAgICApKFtoYW5kZWRuZXNzLCBpLCAwXSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKGN1cnJCdXR0b24udG91Y2hlZCAmJiAhY3VyckJ1dHRvbi5wcmVzc2VkKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIHByZXNzXG4gICAgICAgICAgICAgICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIudG9TdHJlYW1lckhhbmRsZXJzLmdldChcbiAgICAgICAgICAgICAgICAgICAgICAgICdYUkJ1dHRvblByZXNzZWQnXG4gICAgICAgICAgICAgICAgICAgICkoW2hhbmRlZG5lc3MsIDMsIHByZXZCdXR0b24udG91Y2hlZCA/IDEgOiAwXSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmICghY3VyckJ1dHRvbi50b3VjaGVkICYmIHByZXZCdXR0b24udG91Y2hlZCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlc1Byb3ZpZGVyLnRvU3RyZWFtZXJIYW5kbGVycy5nZXQoXG4gICAgICAgICAgICAgICAgICAgICAgICAnWFJCdXR0b25SZWxlYXNlZCdcbiAgICAgICAgICAgICAgICAgICAgKShbaGFuZGVkbmVzcywgMywgMF0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gSXRlcmF0ZSBvdmVyIGdhbWVwYWQgYXhlc1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBjdXJyU3RhdGUuYXhlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzUHJvdmlkZXIudG9TdHJlYW1lckhhbmRsZXJzLmdldChcbiAgICAgICAgICAgICAgICAgICAgJ1hSQW5hbG9nJ1xuICAgICAgICAgICAgICAgICkoW2hhbmRlZG5lc3MsIGksIGN1cnJTdGF0ZS5heGVzW2ldXSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuY29udHJvbGxlcnNbaGFuZGVkbmVzc10ucHJldlN0YXRlID0gY3VyclN0YXRlO1xuICAgICAgICB9XG4gICAgfVxufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuZXhwb3J0IGNsYXNzIExvZ2dlciB7XG4gICAgc3RhdGljIHZlcmJvc2VMb2dMZXZlbCA9IDU7XG5cbiAgICAvKipcbiAgICAgKiBDYXB0dXJlcyB0aGUgc3RhY2sgYW5kIHJldHVybnMgaXRcbiAgICAgKiBAcmV0dXJucyB0aGUgY3VycmVudCBzdGFja1xuICAgICAqL1xuICAgIHN0YXRpYyBHZXRTdGFja1RyYWNlKCkge1xuICAgICAgICBjb25zdCBlcnJvciA9IG5ldyBFcnJvcigpO1xuICAgICAgICBsZXQgZm9ybWF0dGVkU3RhY2sgPSAnTm8gU3RhY2sgQXZhaWxhYmxlIGZvciB0aGlzIGJyb3dzZXInO1xuXG4gICAgICAgIC8vIGZvcm1hdCB0aGUgZXJyb3JcbiAgICAgICAgaWYgKGVycm9yLnN0YWNrKSB7XG4gICAgICAgICAgICBmb3JtYXR0ZWRTdGFjayA9IGVycm9yLnN0YWNrLnRvU3RyaW5nKCkucmVwbGFjZSgvRXJyb3IvZywgJycpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZvcm1hdHRlZFN0YWNrO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCB0aGUgbG9nIHZlcmJvc2l0eSBsZXZlbFxuICAgICAqL1xuICAgIHN0YXRpYyBTZXRMb2dnZXJWZXJib3NpdHkodmVyYm9zZUxvZ0xldmVsOiBudW1iZXIpIHtcbiAgICAgICAgaWYgKHRoaXMudmVyYm9zZUxvZ0xldmVsICE9IG51bGwpIHtcbiAgICAgICAgICAgIHRoaXMudmVyYm9zZUxvZ0xldmVsID0gdmVyYm9zZUxvZ0xldmVsO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhlIHN0YW5kYXJkIGxvZ2dpbmcgb3V0cHV0XG4gICAgICogQHBhcmFtIHN0YWNrIC0gdGhlIHN0YWNrIHRyYWNlXG4gICAgICogQHBhcmFtIG1lc3NhZ2UgLSB0aGUgbWVzc2FnZSB0byBiZSBsb2dnZWRcbiAgICAgKiBAcGFyYW0gdmVyYm9zaXR5IC0gdGhlIHZlcmJvc2l0eSBsZXZlbFxuICAgICAqL1xuICAgIHN0YXRpYyBMb2coc3RhY2s6IHN0cmluZywgbWVzc2FnZTogc3RyaW5nLCB2ZXJib3NpdHk/OiBudW1iZXIpIHtcbiAgICAgICAgaWYgKHZlcmJvc2l0eSA+IHRoaXMudmVyYm9zZUxvZ0xldmVsKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZXR1cm5TdHJpbmcgPSBgTGV2ZWw6IExvZ1xcbk1zZzogJHttZXNzYWdlfVxcbkNhbGxlcjogJHtzdGFja31gO1xuICAgICAgICBjb25zb2xlLmxvZyhyZXR1cm5TdHJpbmcpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBzdGFuZGFyZCBsb2dnaW5nIG91dHB1dFxuICAgICAqIEBwYXJhbSBzdGFjayAtIHRoZSBzdGFjayB0cmFjZVxuICAgICAqIEBwYXJhbSBtZXNzYWdlIC0gdGhlIG1lc3NhZ2UgdG8gYmUgbG9nZ2VkXG4gICAgICogQHBhcmFtIHZlcmJvc2l0eSAtIHRoZSB2ZXJib3NpdHkgbGV2ZWxcbiAgICAgKi9cbiAgICBzdGF0aWMgSW5mbyhzdGFjazogc3RyaW5nLCBtZXNzYWdlOiBzdHJpbmcsIHZlcmJvc2l0eT86IG51bWJlcikge1xuICAgICAgICBpZiAodmVyYm9zaXR5ID4gdGhpcy52ZXJib3NlTG9nTGV2ZWwpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHJldHVyblN0cmluZyA9IGBMZXZlbDogSW5mb1xcbk1zZzogJHttZXNzYWdlfWA7XG4gICAgICAgIGNvbnNvbGUuaW5mbyhyZXR1cm5TdHJpbmcpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBzdGFuZGFyZCBsb2dnaW5nIG91dHB1dFxuICAgICAqIEBwYXJhbSBzdGFjayAtIHRoZSBzdGFjayB0cmFjZVxuICAgICAqIEBwYXJhbSBtZXNzYWdlIC0gdGhlIG1lc3NhZ2UgdG8gYmUgbG9nZ2VkXG4gICAgICovXG4gICAgc3RhdGljIEVycm9yKHN0YWNrOiBzdHJpbmcsIG1lc3NhZ2U6IHN0cmluZykge1xuICAgICAgICBjb25zdCByZXR1cm5TdHJpbmcgPSBgTGV2ZWw6IEVycm9yXFxuTXNnOiAke21lc3NhZ2V9XFxuQ2FsbGVyOiAke3N0YWNrfWA7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IocmV0dXJuU3RyaW5nKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgc3RhbmRhcmQgbG9nZ2luZyBvdXRwdXRcbiAgICAgKiBAcGFyYW0gc3RhY2sgLSB0aGUgc3RhY2sgdHJhY2VcbiAgICAgKiBAcGFyYW0gbWVzc2FnZSAtIHRoZSBtZXNzYWdlIHRvIGJlIGxvZ2dlZFxuICAgICAqL1xuICAgIHN0YXRpYyBXYXJuaW5nKHN0YWNrOiBzdHJpbmcsIG1lc3NhZ2U6IHN0cmluZykge1xuICAgICAgICBjb25zdCByZXR1cm5TdHJpbmcgPSBgTGV2ZWw6IFdhcm5pbmdcXG5DYWxsZXI6ICR7c3RhY2t9XFxuTXNnOiAke21lc3NhZ2V9YDtcbiAgICAgICAgY29uc29sZS53YXJuKHJldHVyblN0cmluZyk7XG4gICAgfVxufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuaW1wb3J0IHtcbiAgICBJbmJvdW5kUlRQU3RhdHMsXG4gICAgSW5ib3VuZFZpZGVvU3RhdHMsXG4gICAgSW5ib3VuZEF1ZGlvU3RhdHNcbn0gZnJvbSAnLi9JbmJvdW5kUlRQU3RhdHMnO1xuaW1wb3J0IHsgSW5ib3VuZFRyYWNrU3RhdHMgfSBmcm9tICcuL0luYm91bmRUcmFja1N0YXRzJztcbmltcG9ydCB7IERhdGFDaGFubmVsU3RhdHMgfSBmcm9tICcuL0RhdGFDaGFubmVsU3RhdHMnO1xuaW1wb3J0IHsgQ2FuZGlkYXRlU3RhdCB9IGZyb20gJy4vQ2FuZGlkYXRlU3RhdCc7XG5pbXBvcnQgeyBDYW5kaWRhdGVQYWlyU3RhdHMgfSBmcm9tICcuL0NhbmRpZGF0ZVBhaXJTdGF0cyc7XG5pbXBvcnQgeyBPdXRCb3VuZFJUUFN0YXRzLCBPdXRCb3VuZFZpZGVvU3RhdHMgfSBmcm9tICcuL091dEJvdW5kUlRQU3RhdHMnO1xuaW1wb3J0IHsgU2Vzc2lvblN0YXRzIH0gZnJvbSAnLi9TZXNzaW9uU3RhdHMnO1xuaW1wb3J0IHsgU3RyZWFtU3RhdHMgfSBmcm9tICcuL1N0cmVhbVN0YXRzJztcbmltcG9ydCB7IENvZGVjU3RhdHMgfSBmcm9tICcuL0NvZGVjU3RhdHMnO1xuaW1wb3J0IHsgTG9nZ2VyIH0gZnJvbSAnLi4vTG9nZ2VyL0xvZ2dlcic7XG5cbi8qKlxuICogVGhlIEFnZ3JlZ2F0ZWQgU3RhdHMgdGhhdCBpcyBnZW5lcmF0ZWQgZnJvbSB0aGUgUlRDIFN0YXRzIFJlcG9ydFxuICovXG5cbnR5cGUgUlRDU3RhdHNUeXBlUFMgPSBSVENTdGF0c1R5cGUgfCAnc3RyZWFtJyB8ICdtZWRpYS1wbGF5b3V0JztcbmV4cG9ydCBjbGFzcyBBZ2dyZWdhdGVkU3RhdHMge1xuICAgIGluYm91bmRWaWRlb1N0YXRzOiBJbmJvdW5kVmlkZW9TdGF0cztcbiAgICBpbmJvdW5kQXVkaW9TdGF0czogSW5ib3VuZEF1ZGlvU3RhdHM7XG4gICAgbGFzdFZpZGVvU3RhdHM6IEluYm91bmRWaWRlb1N0YXRzO1xuICAgIGxhc3RBdWRpb1N0YXRzOiBJbmJvdW5kQXVkaW9TdGF0cztcbiAgICBjYW5kaWRhdGVQYWlyOiBDYW5kaWRhdGVQYWlyU3RhdHM7XG4gICAgRGF0YUNoYW5uZWxTdGF0czogRGF0YUNoYW5uZWxTdGF0cztcbiAgICBsb2NhbENhbmRpZGF0ZXM6IEFycmF5PENhbmRpZGF0ZVN0YXQ+O1xuICAgIHJlbW90ZUNhbmRpZGF0ZXM6IEFycmF5PENhbmRpZGF0ZVN0YXQ+O1xuICAgIG91dEJvdW5kVmlkZW9TdGF0czogT3V0Qm91bmRWaWRlb1N0YXRzO1xuICAgIHNlc3Npb25TdGF0czogU2Vzc2lvblN0YXRzO1xuICAgIHN0cmVhbVN0YXRzOiBTdHJlYW1TdGF0cztcbiAgICBjb2RlY3M6IE1hcDxzdHJpbmcsIHN0cmluZz47XG5cbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgdGhpcy5pbmJvdW5kVmlkZW9TdGF0cyA9IG5ldyBJbmJvdW5kVmlkZW9TdGF0cygpO1xuICAgICAgICB0aGlzLmluYm91bmRBdWRpb1N0YXRzID0gbmV3IEluYm91bmRBdWRpb1N0YXRzKCk7XG4gICAgICAgIHRoaXMuY2FuZGlkYXRlUGFpciA9IG5ldyBDYW5kaWRhdGVQYWlyU3RhdHMoKTtcbiAgICAgICAgdGhpcy5EYXRhQ2hhbm5lbFN0YXRzID0gbmV3IERhdGFDaGFubmVsU3RhdHMoKTtcbiAgICAgICAgdGhpcy5vdXRCb3VuZFZpZGVvU3RhdHMgPSBuZXcgT3V0Qm91bmRWaWRlb1N0YXRzKCk7XG4gICAgICAgIHRoaXMuc2Vzc2lvblN0YXRzID0gbmV3IFNlc3Npb25TdGF0cygpO1xuICAgICAgICB0aGlzLnN0cmVhbVN0YXRzID0gbmV3IFN0cmVhbVN0YXRzKCk7XG4gICAgICAgIHRoaXMuY29kZWNzID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZz4oKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHYXRoZXIgYWxsIHRoZSBpbmZvcm1hdGlvbiBmcm9tIHRoZSBSVEMgUGVlciBDb25uZWN0aW9uIFJlcG9ydFxuICAgICAqIEBwYXJhbSBydGNTdGF0c1JlcG9ydCAtIFJUQyBTdGF0cyBSZXBvcnRcbiAgICAgKi9cbiAgICBwcm9jZXNzU3RhdHMocnRjU3RhdHNSZXBvcnQ6IFJUQ1N0YXRzUmVwb3J0KSB7XG4gICAgICAgIHRoaXMubG9jYWxDYW5kaWRhdGVzID0gbmV3IEFycmF5PENhbmRpZGF0ZVN0YXQ+KCk7XG4gICAgICAgIHRoaXMucmVtb3RlQ2FuZGlkYXRlcyA9IG5ldyBBcnJheTxDYW5kaWRhdGVTdGF0PigpO1xuXG4gICAgICAgIHJ0Y1N0YXRzUmVwb3J0LmZvckVhY2goKHN0YXQpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHR5cGU6IFJUQ1N0YXRzVHlwZVBTID0gc3RhdC50eXBlO1xuXG4gICAgICAgICAgICBzd2l0Y2ggKHR5cGUpIHtcbiAgICAgICAgICAgICAgICBjYXNlICdjYW5kaWRhdGUtcGFpcic6XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaGFuZGxlQ2FuZGlkYXRlUGFpcihzdGF0KTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSAnY2VydGlmaWNhdGUnOlxuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlICdjb2RlYyc6XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaGFuZGxlQ29kZWMoc3RhdCk7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgJ2RhdGEtY2hhbm5lbCc6XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaGFuZGxlRGF0YUNoYW5uZWwoc3RhdCk7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgJ2luYm91bmQtcnRwJzpcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5oYW5kbGVJbkJvdW5kUlRQKHN0YXQpO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlICdsb2NhbC1jYW5kaWRhdGUnOlxuICAgICAgICAgICAgICAgICAgICB0aGlzLmhhbmRsZUxvY2FsQ2FuZGlkYXRlKHN0YXQpO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlICdtZWRpYS1zb3VyY2UnOlxuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlICdtZWRpYS1wbGF5b3V0JzpcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSAnb3V0Ym91bmQtcnRwJzpcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSAncGVlci1jb25uZWN0aW9uJzpcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSAncmVtb3RlLWNhbmRpZGF0ZSc6XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaGFuZGxlUmVtb3RlQ2FuZGlkYXRlKHN0YXQpO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlICdyZW1vdGUtaW5ib3VuZC1ydHAnOlxuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlICdyZW1vdGUtb3V0Ym91bmQtcnRwJzpcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5oYW5kbGVSZW1vdGVPdXRCb3VuZChzdGF0KTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSAndHJhY2snOlxuICAgICAgICAgICAgICAgICAgICB0aGlzLmhhbmRsZVRyYWNrKHN0YXQpO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlICd0cmFuc3BvcnQnOlxuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlICdzdHJlYW0nOlxuICAgICAgICAgICAgICAgICAgICB0aGlzLmhhbmRsZVN0cmVhbShzdGF0KTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLkVycm9yKExvZ2dlci5HZXRTdGFja1RyYWNlKCksICd1bmhhbmRsZWQgU3RhdCBUeXBlJyk7XG4gICAgICAgICAgICAgICAgICAgIExvZ2dlci5Mb2coTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSwgc3RhdCk7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQcm9jZXNzIHN0cmVhbSBzdGF0cyBkYXRhIGZyb20gd2VicnRjXG4gICAgICpcbiAgICAgKiBAcGFyYW0gc3RhdCAtIHRoZSBzdGF0cyBjb21pbmcgaW4gZnJvbSB3ZWJydGNcbiAgICAgKi9cbiAgICBoYW5kbGVTdHJlYW0oc3RhdDogU3RyZWFtU3RhdHMpIHtcbiAgICAgICAgdGhpcy5zdHJlYW1TdGF0cyA9IHN0YXQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUHJvY2VzcyB0aGUgSWNlIENhbmRpZGF0ZSBQYWlyIERhdGFcbiAgICAgKiBAcGFyYW0gc3RhdCAtIHRoZSBzdGF0cyBjb21pbmcgaW4gZnJvbSBpY2UgY2FuZGlkYXRlc1xuICAgICAqL1xuICAgIGhhbmRsZUNhbmRpZGF0ZVBhaXIoc3RhdDogQ2FuZGlkYXRlUGFpclN0YXRzKSB7XG4gICAgICAgIHRoaXMuY2FuZGlkYXRlUGFpci5ieXRlc1JlY2VpdmVkID0gc3RhdC5ieXRlc1JlY2VpdmVkO1xuICAgICAgICB0aGlzLmNhbmRpZGF0ZVBhaXIuYnl0ZXNTZW50ID0gc3RhdC5ieXRlc1NlbnQ7XG4gICAgICAgIHRoaXMuY2FuZGlkYXRlUGFpci5sb2NhbENhbmRpZGF0ZUlkID0gc3RhdC5sb2NhbENhbmRpZGF0ZUlkO1xuICAgICAgICB0aGlzLmNhbmRpZGF0ZVBhaXIucmVtb3RlQ2FuZGlkYXRlSWQgPSBzdGF0LnJlbW90ZUNhbmRpZGF0ZUlkO1xuICAgICAgICB0aGlzLmNhbmRpZGF0ZVBhaXIubm9taW5hdGVkID0gc3RhdC5ub21pbmF0ZWQ7XG4gICAgICAgIHRoaXMuY2FuZGlkYXRlUGFpci5yZWFkYWJsZSA9IHN0YXQucmVhZGFibGU7XG4gICAgICAgIHRoaXMuY2FuZGlkYXRlUGFpci5zZWxlY3RlZCA9IHN0YXQuc2VsZWN0ZWQ7XG4gICAgICAgIHRoaXMuY2FuZGlkYXRlUGFpci53cml0YWJsZSA9IHN0YXQud3JpdGFibGU7XG4gICAgICAgIHRoaXMuY2FuZGlkYXRlUGFpci5zdGF0ZSA9IHN0YXQuc3RhdGU7XG4gICAgICAgIHRoaXMuY2FuZGlkYXRlUGFpci5jdXJyZW50Um91bmRUcmlwVGltZSA9IHN0YXQuY3VycmVudFJvdW5kVHJpcFRpbWU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUHJvY2VzcyB0aGUgRGF0YSBDaGFubmVsIERhdGFcbiAgICAgKiBAcGFyYW0gc3RhdCAtIHRoZSBzdGF0cyBjb21pbmcgaW4gZnJvbSB0aGUgZGF0YSBjaGFubmVsXG4gICAgICovXG4gICAgaGFuZGxlRGF0YUNoYW5uZWwoc3RhdDogRGF0YUNoYW5uZWxTdGF0cykge1xuICAgICAgICB0aGlzLkRhdGFDaGFubmVsU3RhdHMuYnl0ZXNSZWNlaXZlZCA9IHN0YXQuYnl0ZXNSZWNlaXZlZDtcbiAgICAgICAgdGhpcy5EYXRhQ2hhbm5lbFN0YXRzLmJ5dGVzU2VudCA9IHN0YXQuYnl0ZXNTZW50O1xuICAgICAgICB0aGlzLkRhdGFDaGFubmVsU3RhdHMuZGF0YUNoYW5uZWxJZGVudGlmaWVyID1cbiAgICAgICAgICAgIHN0YXQuZGF0YUNoYW5uZWxJZGVudGlmaWVyO1xuICAgICAgICB0aGlzLkRhdGFDaGFubmVsU3RhdHMuaWQgPSBzdGF0LmlkO1xuICAgICAgICB0aGlzLkRhdGFDaGFubmVsU3RhdHMubGFiZWwgPSBzdGF0LmxhYmVsO1xuICAgICAgICB0aGlzLkRhdGFDaGFubmVsU3RhdHMubWVzc2FnZXNSZWNlaXZlZCA9IHN0YXQubWVzc2FnZXNSZWNlaXZlZDtcbiAgICAgICAgdGhpcy5EYXRhQ2hhbm5lbFN0YXRzLm1lc3NhZ2VzU2VudCA9IHN0YXQubWVzc2FnZXNTZW50O1xuICAgICAgICB0aGlzLkRhdGFDaGFubmVsU3RhdHMucHJvdG9jb2wgPSBzdGF0LnByb3RvY29sO1xuICAgICAgICB0aGlzLkRhdGFDaGFubmVsU3RhdHMuc3RhdGUgPSBzdGF0LnN0YXRlO1xuICAgICAgICB0aGlzLkRhdGFDaGFubmVsU3RhdHMudGltZXN0YW1wID0gc3RhdC50aW1lc3RhbXA7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUHJvY2VzcyB0aGUgTG9jYWwgSWNlIENhbmRpZGF0ZSBEYXRhXG4gICAgICogQHBhcmFtIHN0YXQgLSBsb2NhbCBzdGF0c1xuICAgICAqL1xuICAgIGhhbmRsZUxvY2FsQ2FuZGlkYXRlKHN0YXQ6IENhbmRpZGF0ZVN0YXQpIHtcbiAgICAgICAgY29uc3QgbG9jYWxDYW5kaWRhdGUgPSBuZXcgQ2FuZGlkYXRlU3RhdCgpO1xuICAgICAgICBsb2NhbENhbmRpZGF0ZS5sYWJlbCA9ICdsb2NhbC1jYW5kaWRhdGUnO1xuICAgICAgICBsb2NhbENhbmRpZGF0ZS5hZGRyZXNzID0gc3RhdC5hZGRyZXNzO1xuICAgICAgICBsb2NhbENhbmRpZGF0ZS5wb3J0ID0gc3RhdC5wb3J0O1xuICAgICAgICBsb2NhbENhbmRpZGF0ZS5wcm90b2NvbCA9IHN0YXQucHJvdG9jb2w7XG4gICAgICAgIGxvY2FsQ2FuZGlkYXRlLmNhbmRpZGF0ZVR5cGUgPSBzdGF0LmNhbmRpZGF0ZVR5cGU7XG4gICAgICAgIGxvY2FsQ2FuZGlkYXRlLmlkID0gc3RhdC5pZDtcbiAgICAgICAgdGhpcy5sb2NhbENhbmRpZGF0ZXMucHVzaChsb2NhbENhbmRpZGF0ZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUHJvY2VzcyB0aGUgUmVtb3RlIEljZSBDYW5kaWRhdGUgRGF0YVxuICAgICAqIEBwYXJhbSBzdGF0IC0gaWNlIGNhbmRpZGF0ZSBzdGF0c1xuICAgICAqL1xuICAgIGhhbmRsZVJlbW90ZUNhbmRpZGF0ZShzdGF0OiBDYW5kaWRhdGVTdGF0KSB7XG4gICAgICAgIGNvbnN0IFJlbW90ZUNhbmRpZGF0ZSA9IG5ldyBDYW5kaWRhdGVTdGF0KCk7XG4gICAgICAgIFJlbW90ZUNhbmRpZGF0ZS5sYWJlbCA9ICdsb2NhbC1jYW5kaWRhdGUnO1xuICAgICAgICBSZW1vdGVDYW5kaWRhdGUuYWRkcmVzcyA9IHN0YXQuYWRkcmVzcztcbiAgICAgICAgUmVtb3RlQ2FuZGlkYXRlLnBvcnQgPSBzdGF0LnBvcnQ7XG4gICAgICAgIFJlbW90ZUNhbmRpZGF0ZS5wcm90b2NvbCA9IHN0YXQucHJvdG9jb2w7XG4gICAgICAgIFJlbW90ZUNhbmRpZGF0ZS5pZCA9IHN0YXQuaWQ7XG4gICAgICAgIFJlbW90ZUNhbmRpZGF0ZS5jYW5kaWRhdGVUeXBlID0gc3RhdC5jYW5kaWRhdGVUeXBlO1xuICAgICAgICB0aGlzLnJlbW90ZUNhbmRpZGF0ZXMucHVzaChSZW1vdGVDYW5kaWRhdGUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFByb2Nlc3MgdGhlIEluYm91bmQgUlRQIEF1ZGlvIGFuZCBWaWRlbyBEYXRhXG4gICAgICogQHBhcmFtIHN0YXQgLSBpbmJvdW5kIHJ0cCBzdGF0c1xuICAgICAqL1xuICAgIGhhbmRsZUluQm91bmRSVFAoc3RhdDogSW5ib3VuZFJUUFN0YXRzKSB7XG4gICAgICAgIHN3aXRjaCAoc3RhdC5raW5kKSB7XG4gICAgICAgICAgICBjYXNlICd2aWRlbyc6XG4gICAgICAgICAgICAgICAgLy8gTmVlZCB0byBjb252ZXJ0IHRvIHVua25vd24gZmlyc3QgdG8gcmVtb3ZlIGFuIGVycm9yIGFyb3VuZFxuICAgICAgICAgICAgICAgIC8vIEluYm91bmRWaWRlb1N0YXRzIGhhdmluZyB0aGUgYml0cmF0ZSBtZW1iZXIgd2hpY2ggaXNuJ3QgZm91bmQgb25cbiAgICAgICAgICAgICAgICAvLyB0aGUgSW5ib3VuZFJUUFN0YXRzXG4gICAgICAgICAgICAgICAgdGhpcy5pbmJvdW5kVmlkZW9TdGF0cyA9IHN0YXQgYXMgdW5rbm93biBhcyBJbmJvdW5kVmlkZW9TdGF0cztcblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmxhc3RWaWRlb1N0YXRzICE9IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmluYm91bmRWaWRlb1N0YXRzLmJpdHJhdGUgPVxuICAgICAgICAgICAgICAgICAgICAgICAgKDggKlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICh0aGlzLmluYm91bmRWaWRlb1N0YXRzLmJ5dGVzUmVjZWl2ZWQgLVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmxhc3RWaWRlb1N0YXRzLmJ5dGVzUmVjZWl2ZWQpKSAvXG4gICAgICAgICAgICAgICAgICAgICAgICAodGhpcy5pbmJvdW5kVmlkZW9TdGF0cy50aW1lc3RhbXAgLVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubGFzdFZpZGVvU3RhdHMudGltZXN0YW1wKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5pbmJvdW5kVmlkZW9TdGF0cy5iaXRyYXRlID0gTWF0aC5mbG9vcihcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuaW5ib3VuZFZpZGVvU3RhdHMuYml0cmF0ZVxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLmxhc3RWaWRlb1N0YXRzID0geyAuLi50aGlzLmluYm91bmRWaWRlb1N0YXRzIH07XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlICdhdWRpbyc6XG4gICAgICAgICAgICAgICAgLy8gTmVlZCB0byBjb252ZXJ0IHRvIHVua25vd24gZmlyc3QgdG8gcmVtb3ZlIGFuIGVycm9yIGFyb3VuZFxuICAgICAgICAgICAgICAgIC8vIEluYm91bmRBdWRpb1N0YXRzIGhhdmluZyB0aGUgYml0cmF0ZSBtZW1iZXIgd2hpY2ggaXNuJ3QgZm91bmQgb25cbiAgICAgICAgICAgICAgICAvLyB0aGUgSW5ib3VuZFJUUFN0YXRzXG4gICAgICAgICAgICAgICAgdGhpcy5pbmJvdW5kQXVkaW9TdGF0cyA9IHN0YXQgYXMgdW5rbm93biBhcyBJbmJvdW5kQXVkaW9TdGF0cztcblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmxhc3RBdWRpb1N0YXRzICE9IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmluYm91bmRBdWRpb1N0YXRzLmJpdHJhdGUgPVxuICAgICAgICAgICAgICAgICAgICAgICAgKDggKlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICh0aGlzLmluYm91bmRBdWRpb1N0YXRzLmJ5dGVzUmVjZWl2ZWQgLVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmxhc3RBdWRpb1N0YXRzLmJ5dGVzUmVjZWl2ZWQpKSAvXG4gICAgICAgICAgICAgICAgICAgICAgICAodGhpcy5pbmJvdW5kQXVkaW9TdGF0cy50aW1lc3RhbXAgLVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubGFzdEF1ZGlvU3RhdHMudGltZXN0YW1wKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5pbmJvdW5kQXVkaW9TdGF0cy5iaXRyYXRlID0gTWF0aC5mbG9vcihcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuaW5ib3VuZEF1ZGlvU3RhdHMuYml0cmF0ZVxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLmxhc3RBdWRpb1N0YXRzID0geyAuLi50aGlzLmluYm91bmRBdWRpb1N0YXRzIH07XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIExvZ2dlci5Mb2coTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSwgJ0tpbmQgaXMgbm90IGhhbmRsZWQnKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFByb2Nlc3MgdGhlIG91dGJvdW5kIFJUUCBBdWRpbyBhbmQgVmlkZW8gRGF0YVxuICAgICAqIEBwYXJhbSBzdGF0IC0gcmVtb3RlIG91dGJvdW5kIHN0YXRzXG4gICAgICovXG4gICAgaGFuZGxlUmVtb3RlT3V0Qm91bmQoc3RhdDogT3V0Qm91bmRSVFBTdGF0cykge1xuICAgICAgICBzd2l0Y2ggKHN0YXQua2luZCkge1xuICAgICAgICAgICAgY2FzZSAndmlkZW8nOlxuICAgICAgICAgICAgICAgIHRoaXMub3V0Qm91bmRWaWRlb1N0YXRzLmJ5dGVzU2VudCA9IHN0YXQuYnl0ZXNTZW50O1xuICAgICAgICAgICAgICAgIHRoaXMub3V0Qm91bmRWaWRlb1N0YXRzLmlkID0gc3RhdC5pZDtcbiAgICAgICAgICAgICAgICB0aGlzLm91dEJvdW5kVmlkZW9TdGF0cy5sb2NhbElkID0gc3RhdC5sb2NhbElkO1xuICAgICAgICAgICAgICAgIHRoaXMub3V0Qm91bmRWaWRlb1N0YXRzLnBhY2tldHNTZW50ID0gc3RhdC5wYWNrZXRzU2VudDtcbiAgICAgICAgICAgICAgICB0aGlzLm91dEJvdW5kVmlkZW9TdGF0cy5yZW1vdGVUaW1lc3RhbXAgPSBzdGF0LnJlbW90ZVRpbWVzdGFtcDtcbiAgICAgICAgICAgICAgICB0aGlzLm91dEJvdW5kVmlkZW9TdGF0cy50aW1lc3RhbXAgPSBzdGF0LnRpbWVzdGFtcDtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ2F1ZGlvJzpcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFByb2Nlc3MgdGhlIEluYm91bmQgVmlkZW8gVHJhY2sgRGF0YVxuICAgICAqIEBwYXJhbSBzdGF0IC0gdmlkZW8gdHJhY2sgc3RhdHNcbiAgICAgKi9cbiAgICBoYW5kbGVUcmFjayhzdGF0OiBJbmJvdW5kVHJhY2tTdGF0cykge1xuICAgICAgICAvLyB3ZSBvbmx5IHdhbnQgdG8gZXh0cmFjdCBzdGF0cyBmcm9tIHRoZSB2aWRlbyB0cmFja1xuICAgICAgICBpZiAoXG4gICAgICAgICAgICBzdGF0LnR5cGUgPT09ICd0cmFjaycgJiZcbiAgICAgICAgICAgIChzdGF0LnRyYWNrSWRlbnRpZmllciA9PT0gJ3ZpZGVvX2xhYmVsJyB8fCBzdGF0LmtpbmQgPT09ICd2aWRlbycpXG4gICAgICAgICkge1xuICAgICAgICAgICAgdGhpcy5pbmJvdW5kVmlkZW9TdGF0cy5mcmFtZXNEcm9wcGVkID0gc3RhdC5mcmFtZXNEcm9wcGVkO1xuICAgICAgICAgICAgdGhpcy5pbmJvdW5kVmlkZW9TdGF0cy5mcmFtZXNSZWNlaXZlZCA9IHN0YXQuZnJhbWVzUmVjZWl2ZWQ7XG4gICAgICAgICAgICB0aGlzLmluYm91bmRWaWRlb1N0YXRzLmZyYW1lSGVpZ2h0ID0gc3RhdC5mcmFtZUhlaWdodDtcbiAgICAgICAgICAgIHRoaXMuaW5ib3VuZFZpZGVvU3RhdHMuZnJhbWVXaWR0aCA9IHN0YXQuZnJhbWVXaWR0aDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGhhbmRsZUNvZGVjKHN0YXQ6IENvZGVjU3RhdHMpIHtcbiAgICAgICAgY29uc3QgY29kZWNJZCA9IHN0YXQuaWQ7XG4gICAgICAgIGNvbnN0IGNvZGVjVHlwZSA9IGAke3N0YXQubWltZVR5cGVcbiAgICAgICAgICAgIC5yZXBsYWNlKCd2aWRlby8nLCAnJylcbiAgICAgICAgICAgIC5yZXBsYWNlKCdhdWRpby8nLCAnJyl9JHtcbiAgICAgICAgICAgIHN0YXQuc2RwRm10cExpbmUgPyBgICR7c3RhdC5zZHBGbXRwTGluZX1gIDogJydcbiAgICAgICAgfWA7XG4gICAgICAgIHRoaXMuY29kZWNzLnNldChjb2RlY0lkLCBjb2RlY1R5cGUpO1xuICAgIH1cblxuICAgIGhhbmRsZVNlc3Npb25TdGF0aXN0aWNzKFxuICAgICAgICB2aWRlb1N0YXJ0VGltZTogbnVtYmVyLFxuICAgICAgICBpbnB1dENvbnRyb2xsZXI6IGJvb2xlYW4gfCBudWxsLFxuICAgICAgICB2aWRlb0VuY29kZXJBdmdRUDogbnVtYmVyXG4gICAgKSB7XG4gICAgICAgIGNvbnN0IGRlbHRhVGltZSA9IERhdGUubm93KCkgLSB2aWRlb1N0YXJ0VGltZTtcbiAgICAgICAgdGhpcy5zZXNzaW9uU3RhdHMucnVuVGltZSA9IG5ldyBEYXRlKGRlbHRhVGltZSlcbiAgICAgICAgICAgIC50b0lTT1N0cmluZygpXG4gICAgICAgICAgICAuc3Vic3RyKDExLCA4KVxuICAgICAgICAgICAgLnRvU3RyaW5nKCk7XG5cbiAgICAgICAgY29uc3QgY29udHJvbHNTdHJlYW1JbnB1dCA9XG4gICAgICAgICAgICBpbnB1dENvbnRyb2xsZXIgPT09IG51bGxcbiAgICAgICAgICAgICAgICA/ICdOb3Qgc2VudCB5ZXQnXG4gICAgICAgICAgICAgICAgOiBpbnB1dENvbnRyb2xsZXJcbiAgICAgICAgICAgICAgICA/ICd0cnVlJ1xuICAgICAgICAgICAgICAgIDogJ2ZhbHNlJztcbiAgICAgICAgdGhpcy5zZXNzaW9uU3RhdHMuY29udHJvbHNTdHJlYW1JbnB1dCA9IGNvbnRyb2xzU3RyZWFtSW5wdXQ7XG5cbiAgICAgICAgdGhpcy5zZXNzaW9uU3RhdHMudmlkZW9FbmNvZGVyQXZnUVAgPSB2aWRlb0VuY29kZXJBdmdRUDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVjayBpZiBhIHZhbHVlIGNvbWluZyBpbiBmcm9tIG91ciBzdGF0cyBpcyBhY3R1YWxseSBhIG51bWJlclxuICAgICAqIEBwYXJhbSB2YWx1ZSAtIHRoZSBudW1iZXIgdG8gYmUgY2hlY2tlZFxuICAgICAqL1xuICAgIGlzTnVtYmVyKHZhbHVlOiB1bmtub3duKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInICYmIGlzRmluaXRlKHZhbHVlKTtcbiAgICB9XG59XG4iLCIvLyBDb3B5cmlnaHQgRXBpYyBHYW1lcywgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuXG4vKipcbiAqIElDRSBDYW5kaWRhdGUgUGFpciBTdGF0cyBjb2xsZWN0ZWQgZnJvbSB0aGUgUlRDIFN0YXRzIFJlcG9ydFxuICovXG5leHBvcnQgY2xhc3MgQ2FuZGlkYXRlUGFpclN0YXRzIHtcbiAgICBieXRlc1JlY2VpdmVkOiBudW1iZXI7XG4gICAgYnl0ZXNTZW50OiBudW1iZXI7XG4gICAgbG9jYWxDYW5kaWRhdGVJZDogc3RyaW5nO1xuICAgIHJlbW90ZUNhbmRpZGF0ZUlkOiBzdHJpbmc7XG4gICAgbm9taW5hdGVkOiBib29sZWFuO1xuICAgIHJlYWRhYmxlOiBib29sZWFuO1xuICAgIHdyaXRhYmxlOiBib29sZWFuO1xuICAgIHNlbGVjdGVkOiBib29sZWFuO1xuICAgIHN0YXRlOiBzdHJpbmc7XG4gICAgY3VycmVudFJvdW5kVHJpcFRpbWU6IG51bWJlcjtcbn1cbiIsIi8vIENvcHlyaWdodCBFcGljIEdhbWVzLCBJbmMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG5cbi8qKlxuICogSUNFIENhbmRpZGF0ZSBTdGF0IGNvbGxlY3RlZCBmcm9tIHRoZSBSVEMgU3RhdHMgUmVwb3J0XG4gKi9cbmV4cG9ydCBjbGFzcyBDYW5kaWRhdGVTdGF0IHtcbiAgICBsYWJlbDogc3RyaW5nO1xuICAgIGlkOiBzdHJpbmc7XG4gICAgYWRkcmVzczogc3RyaW5nO1xuICAgIGNhbmRpZGF0ZVR5cGU6IHN0cmluZztcbiAgICBwb3J0OiBudW1iZXI7XG4gICAgcHJvdG9jb2w6ICd0Y3AnIHwgJ3VkcCc7XG59XG4iLCIvLyBDb3B5cmlnaHQgRXBpYyBHYW1lcywgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuXG4vKipcbiAqIERhdGEgQ2hhbm5lbCBTdGF0cyBjb2xsZWN0ZWQgZnJvbSB0aGUgUlRDIFN0YXRzIFJlcG9ydFxuICovXG5leHBvcnQgY2xhc3MgRGF0YUNoYW5uZWxTdGF0cyB7XG4gICAgYnl0ZXNSZWNlaXZlZDogbnVtYmVyO1xuICAgIGJ5dGVzU2VudDogbnVtYmVyO1xuICAgIGRhdGFDaGFubmVsSWRlbnRpZmllcjogbnVtYmVyO1xuICAgIGlkOiBzdHJpbmc7XG4gICAgbGFiZWw6IHN0cmluZztcbiAgICBtZXNzYWdlc1JlY2VpdmVkOiBudW1iZXI7XG4gICAgbWVzc2FnZXNTZW50OiBudW1iZXI7XG4gICAgcHJvdG9jb2w6IHN0cmluZztcbiAgICBzdGF0ZTogc3RyaW5nO1xuICAgIHRpbWVzdGFtcDogbnVtYmVyO1xufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuLyoqXG4gKiBJbmJvdW5kIEF1ZGlvIFN0YXRzIGNvbGxlY3RlZCBmcm9tIHRoZSBSVEMgU3RhdHMgUmVwb3J0XG4gKi9cbmV4cG9ydCBjbGFzcyBJbmJvdW5kQXVkaW9TdGF0cyB7XG4gICAgYXVkaW9MZXZlbDogbnVtYmVyO1xuICAgIGJ5dGVzUmVjZWl2ZWQ6IG51bWJlcjtcbiAgICBjb2RlY0lkOiBzdHJpbmc7XG4gICAgY29uY2VhbGVkU2FtcGxlczogbnVtYmVyO1xuICAgIGNvbmNlYWxtZW50RXZlbnRzOiBudW1iZXI7XG4gICAgZmVjUGFja2V0c0Rpc2NhcmRlZDogbnVtYmVyO1xuICAgIGZlY1BhY2tldHNSZWNlaXZlZDogbnVtYmVyO1xuICAgIGhlYWRlckJ5dGVzUmVjZWl2ZWQ6IG51bWJlcjtcbiAgICBpZDogc3RyaW5nO1xuICAgIGluc2VydGVkU2FtcGxlc0ZvckRlY2VsZXJhdGlvbjogbnVtYmVyO1xuICAgIGppdHRlcjogbnVtYmVyO1xuICAgIGppdHRlckJ1ZmZlckRlbGF5OiBudW1iZXI7XG4gICAgaml0dGVyQnVmZmVyRW1pdHRlZENvdW50OiBudW1iZXI7XG4gICAgaml0dGVyQnVmZmVyTWluaW11bURlbGF5OiBudW1iZXI7XG4gICAgaml0dGVyQnVmZmVyVGFyZ2V0RGVsYXk6IG51bWJlcjtcbiAgICBraW5kOiBzdHJpbmc7XG4gICAgbGFzdFBhY2tldFJlY2VpdmVkVGltZXN0YW1wOiBudW1iZXI7XG4gICAgbWVkaWFUeXBlOiBzdHJpbmc7XG4gICAgbWlkOiBzdHJpbmc7XG4gICAgcGFja2V0c0Rpc2NhcmRlZDogbnVtYmVyO1xuICAgIHBhY2tldHNMb3N0OiBudW1iZXI7XG4gICAgcGFja2V0c1JlY2VpdmVkOiBudW1iZXI7XG4gICAgcmVtb3ZlZFNhbXBsZXNGb3JBY2NlbGVyYXRpb246IG51bWJlcjtcbiAgICBzaWxlbnRDb25jZWFsZWRTYW1wbGVzOiBudW1iZXI7XG4gICAgc3NyYzogbnVtYmVyO1xuICAgIHRpbWVzdGFtcDogbnVtYmVyO1xuICAgIHRvdGFsQXVkaW9FbmVyZ3k6IG51bWJlcjtcbiAgICB0b3RhbFNhbXBsZXNEdXJhdGlvbjogbnVtYmVyO1xuICAgIHRvdGFsU2FtcGxlc1JlY2VpdmVkOiBudW1iZXI7XG4gICAgdHJhY2tJZGVudGlmaWVyOiBzdHJpbmc7XG4gICAgdHJhbnNwb3J0SWQ6IHN0cmluZztcbiAgICB0eXBlOiBzdHJpbmc7XG5cbiAgICAvKiBhZGRpdGlvbmFsLCBjdXN0b20gc3RhdHMgKi9cbiAgICBiaXRyYXRlOiBudW1iZXI7XG59XG5cbi8qKlxuICogSW5ib3VuZCBWaWRlbyBTdGF0cyBjb2xsZWN0ZWQgZnJvbSB0aGUgUlRDIFN0YXRzIFJlcG9ydFxuICovXG5leHBvcnQgY2xhc3MgSW5ib3VuZFZpZGVvU3RhdHMge1xuICAgIGJ5dGVzUmVjZWl2ZWQ6IG51bWJlcjtcbiAgICBjb2RlY0lkOiBzdHJpbmc7XG4gICAgZmlyQ291bnQ6IG51bWJlcjtcbiAgICBmcmFtZUhlaWdodDogbnVtYmVyO1xuICAgIGZyYW1lV2lkdGg6IG51bWJlcjtcbiAgICBmcmFtZXNBc3NlbWJsZWRGcm9tTXVsdGlwbGVQYWNrZXRzOiBudW1iZXI7XG4gICAgZnJhbWVzRGVjb2RlZDogbnVtYmVyO1xuICAgIGZyYW1lc0Ryb3BwZWQ6IG51bWJlcjtcbiAgICBmcmFtZXNQZXJTZWNvbmQ6IG51bWJlcjtcbiAgICBmcmFtZXNSZWNlaXZlZDogbnVtYmVyO1xuICAgIGZyZWV6ZUNvdW50OiBudW1iZXI7XG4gICAgZ29vZ1RpbWluZ0ZyYW1lSW5mbzogc3RyaW5nO1xuICAgIGhlYWRlckJ5dGVzUmVjZWl2ZWQ6IG51bWJlcjtcbiAgICBpZDogc3RyaW5nO1xuICAgIGppdHRlcjogbnVtYmVyO1xuICAgIGppdHRlckJ1ZmZlckRlbGF5OiBudW1iZXI7XG4gICAgaml0dGVyQnVmZmVyRW1pdHRlZENvdW50OiBudW1iZXI7XG4gICAga2V5RnJhbWVzRGVjb2RlZDogbnVtYmVyO1xuICAgIGtpbmQ6IHN0cmluZztcbiAgICBsYXN0UGFja2V0UmVjZWl2ZWRUaW1lc3RhbXA6IG51bWJlcjtcbiAgICBtZWRpYVR5cGU6IHN0cmluZztcbiAgICBtaWQ6IHN0cmluZztcbiAgICBuYWNrQ291bnQ6IG51bWJlcjtcbiAgICBwYWNrZXRzTG9zdDogbnVtYmVyO1xuICAgIHBhY2tldHNSZWNlaXZlZDogbnVtYmVyO1xuICAgIHBhdXNlQ291bnQ6IG51bWJlcjtcbiAgICBwbGlDb3VudDogbnVtYmVyO1xuICAgIHNzcmM6IG51bWJlcjtcbiAgICB0aW1lc3RhbXA6IG51bWJlcjtcbiAgICB0b3RhbEFzc2VtYmx5VGltZTogbnVtYmVyO1xuICAgIHRvdGFsRGVjb2RlVGltZTogbnVtYmVyO1xuICAgIHRvdGFsRnJlZXplc0R1cmF0aW9uOiBudW1iZXI7XG4gICAgdG90YWxJbnRlckZyYW1lRGVsYXk6IG51bWJlcjtcbiAgICB0b3RhbFBhdXNlc0R1cmF0aW9uOiBudW1iZXI7XG4gICAgdG90YWxQcm9jZXNzaW5nRGVsYXk6IG51bWJlcjtcbiAgICB0b3RhbFNxdWFyZWRJbnRlckZyYW1lRGVsYXk6IG51bWJlcjtcbiAgICB0cmFja0lkZW50aWZpZXI6IHN0cmluZztcbiAgICB0cmFuc3BvcnRJZDogc3RyaW5nO1xuICAgIHR5cGU6IHN0cmluZztcblxuICAgIC8qIGFkZGl0aW9uYWwsIGN1c3RvbSBzdGF0cyAqL1xuICAgIGJpdHJhdGU6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBJbmJvdW5kIFN0YXRzIGNvbGxlY3RlZCBmcm9tIHRoZSBSVEMgU3RhdHMgUmVwb3J0XG4gKi9cbmV4cG9ydCBjbGFzcyBJbmJvdW5kUlRQU3RhdHMge1xuICAgIC8qIGNvbW1vbiBzdGF0cyAqL1xuICAgIGJ5dGVzUmVjZWl2ZWQ6IG51bWJlcjtcbiAgICBjb2RlY0lkOiBzdHJpbmc7XG4gICAgaGVhZGVyQnl0ZXNSZWNlaXZlZDogbnVtYmVyO1xuICAgIGlkOiBzdHJpbmc7XG4gICAgaml0dGVyOiBudW1iZXI7XG4gICAgaml0dGVyQnVmZmVyRGVsYXk6IG51bWJlcjtcbiAgICBqaXR0ZXJCdWZmZXJFbWl0dGVkQ291bnQ6IG51bWJlcjtcbiAgICBraW5kOiBzdHJpbmc7XG4gICAgbGFzdFBhY2tldFJlY2VpdmVkVGltZXN0YW1wOiBudW1iZXI7XG4gICAgbWVkaWFUeXBlOiBzdHJpbmc7XG4gICAgbWlkOiBzdHJpbmc7XG4gICAgcGFja2V0c0xvc3Q6IG51bWJlcjtcbiAgICBwYWNrZXRzUmVjZWl2ZWQ6IG51bWJlcjtcbiAgICBzc3JjOiBudW1iZXI7XG4gICAgdGltZXN0YW1wOiBudW1iZXI7XG4gICAgdHJhY2tJZGVudGlmaWVyOiBzdHJpbmc7XG4gICAgdHJhbnNwb3J0SWQ6IHN0cmluZztcbiAgICB0eXBlOiBzdHJpbmc7XG5cbiAgICAvKiBhdWRpbyBzcGVjaWZpYyBzdGF0cyAqL1xuICAgIGF1ZGlvTGV2ZWw6IG51bWJlcjtcbiAgICBjb25jZWFsZWRTYW1wbGVzOiBudW1iZXI7XG4gICAgY29uY2VhbG1lbnRFdmVudHM6IG51bWJlcjtcbiAgICBmZWNQYWNrZXRzRGlzY2FyZGVkOiBudW1iZXI7XG4gICAgZmVjUGFja2V0c1JlY2VpdmVkOiBudW1iZXI7XG4gICAgaW5zZXJ0ZWRTYW1wbGVzRm9yRGVjZWxlcmF0aW9uOiBudW1iZXI7XG4gICAgaml0dGVyQnVmZmVyTWluaW11bURlbGF5OiBudW1iZXI7XG4gICAgaml0dGVyQnVmZmVyVGFyZ2V0RGVsYXk6IG51bWJlcjtcbiAgICBwYWNrZXRzRGlzY2FyZGVkOiBudW1iZXI7XG4gICAgcmVtb3ZlZFNhbXBsZXNGb3JBY2NlbGVyYXRpb246IG51bWJlcjtcbiAgICBzaWxlbnRDb25jZWFsZWRTYW1wbGVzOiBudW1iZXI7XG4gICAgdG90YWxBdWRpb0VuZXJneTogbnVtYmVyO1xuICAgIHRvdGFsU2FtcGxlc0R1cmF0aW9uOiBudW1iZXI7XG4gICAgdG90YWxTYW1wbGVzUmVjZWl2ZWQ6IG51bWJlcjtcblxuICAgIC8qIHZpZGVvIHNwZWNpZmljIHN0YXRzICovXG4gICAgZmlyQ291bnQ6IG51bWJlcjtcbiAgICBmcmFtZUhlaWdodDogbnVtYmVyO1xuICAgIGZyYW1lV2lkdGg6IG51bWJlcjtcbiAgICBmcmFtZXNBc3NlbWJsZWRGcm9tTXVsdGlwbGVQYWNrZXRzOiBudW1iZXI7XG4gICAgZnJhbWVzRGVjb2RlZDogbnVtYmVyO1xuICAgIGZyYW1lc0Ryb3BwZWQ6IG51bWJlcjtcbiAgICBmcmFtZXNQZXJTZWNvbmQ6IG51bWJlcjtcbiAgICBmcmFtZXNSZWNlaXZlZDogbnVtYmVyO1xuICAgIGZyZWV6ZUNvdW50OiBudW1iZXI7XG4gICAgZ29vZ1RpbWluZ0ZyYW1lSW5mbzogc3RyaW5nO1xuICAgIGtleUZyYW1lc0RlY29kZWQ6IG51bWJlcjtcbiAgICBuYWNrQ291bnQ6IG51bWJlcjtcbiAgICBwYXVzZUNvdW50OiBudW1iZXI7XG4gICAgcGxpQ291bnQ6IG51bWJlcjtcbiAgICB0b3RhbEFzc2VtYmx5VGltZTogbnVtYmVyO1xuICAgIHRvdGFsRGVjb2RlVGltZTogbnVtYmVyO1xuICAgIHRvdGFsRnJlZXplc0R1cmF0aW9uOiBudW1iZXI7XG4gICAgdG90YWxJbnRlckZyYW1lRGVsYXk6IG51bWJlcjtcbiAgICB0b3RhbFBhdXNlc0R1cmF0aW9uOiBudW1iZXI7XG4gICAgdG90YWxQcm9jZXNzaW5nRGVsYXk6IG51bWJlcjtcbiAgICB0b3RhbFNxdWFyZWRJbnRlckZyYW1lRGVsYXk6IG51bWJlcjtcbn1cbiIsIi8vIENvcHlyaWdodCBFcGljIEdhbWVzLCBJbmMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG5cbi8qKlxuICogT3V0Ym91bmQgVmlkZW8gU3RhdHMgY29sbGVjdGVkIGZyb20gdGhlIFJUQyBTdGF0cyBSZXBvcnRcbiAqL1xuZXhwb3J0IGNsYXNzIE91dEJvdW5kVmlkZW9TdGF0cyB7XG4gICAgYnl0ZXNTZW50OiBudW1iZXI7XG4gICAgaWQ6IHN0cmluZztcbiAgICBsb2NhbElkOiBzdHJpbmc7XG4gICAgcGFja2V0c1NlbnQ6IG51bWJlcjtcbiAgICByZW1vdGVUaW1lc3RhbXA6IG51bWJlcjtcbiAgICB0aW1lc3RhbXA6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBPdXRib3VuZCBTdGF0cyBjb2xsZWN0ZWQgZnJvbSB0aGUgUlRDIFN0YXRzIFJlcG9ydFxuICovXG5leHBvcnQgY2xhc3MgT3V0Qm91bmRSVFBTdGF0cyB7XG4gICAga2luZDogc3RyaW5nO1xuICAgIGJ5dGVzU2VudDogbnVtYmVyO1xuICAgIGlkOiBzdHJpbmc7XG4gICAgbG9jYWxJZDogc3RyaW5nO1xuICAgIHBhY2tldHNTZW50OiBudW1iZXI7XG4gICAgcmVtb3RlVGltZXN0YW1wOiBudW1iZXI7XG4gICAgdGltZXN0YW1wOiBudW1iZXI7XG59XG4iLCIvLyBDb3B5cmlnaHQgRXBpYyBHYW1lcywgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuXG5pbXBvcnQgeyBMb2dnZXIgfSBmcm9tICcuLi9Mb2dnZXIvTG9nZ2VyJztcbmltcG9ydCB7IENvbmZpZywgT3B0aW9uUGFyYW1ldGVycywgRmxhZ3MgfSBmcm9tICcuLi9Db25maWcvQ29uZmlnJztcbmltcG9ydCB7IEFnZ3JlZ2F0ZWRTdGF0cyB9IGZyb20gJy4vQWdncmVnYXRlZFN0YXRzJztcbmltcG9ydCB7IHBhcnNlUnRwUGFyYW1ldGVycywgc3BsaXRTZWN0aW9ucyB9IGZyb20gJ3NkcCc7XG5pbXBvcnQgeyBSVENVdGlscyB9IGZyb20gJy4uL1V0aWwvUlRDVXRpbHMnO1xuXG4vKipcbiAqIEhhbmRsZXMgdGhlIFBlZXIgQ29ubmVjdGlvblxuICovXG5leHBvcnQgY2xhc3MgUGVlckNvbm5lY3Rpb25Db250cm9sbGVyIHtcbiAgICBwZWVyQ29ubmVjdGlvbjogUlRDUGVlckNvbm5lY3Rpb247XG4gICAgYWdncmVnYXRlZFN0YXRzOiBBZ2dyZWdhdGVkU3RhdHM7XG4gICAgY29uZmlnOiBDb25maWc7XG4gICAgcHJlZmVycmVkQ29kZWM6IHN0cmluZztcbiAgICB1cGRhdGVDb2RlY1NlbGVjdGlvbjogYm9vbGVhbjtcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZSBhIG5ldyBSVEMgUGVlciBDb25uZWN0aW9uIGNsaWVudFxuICAgICAqIEBwYXJhbSBvcHRpb25zIC0gUGVlciBjb25uZWN0aW9uIE9wdGlvbnNcbiAgICAgKiBAcGFyYW0gY29uZmlnIC0gVGhlIGNvbmZpZyBmb3Igb3VyIFBTIGV4cGVyaWVuY2UuXG4gICAgICovXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIG9wdGlvbnM6IFJUQ0NvbmZpZ3VyYXRpb24sXG4gICAgICAgIGNvbmZpZzogQ29uZmlnLFxuICAgICAgICBwcmVmZXJyZWRDb2RlYzogc3RyaW5nXG4gICAgKSB7XG4gICAgICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICAgICAgICB0aGlzLmNyZWF0ZVBlZXJDb25uZWN0aW9uKG9wdGlvbnMsIHByZWZlcnJlZENvZGVjKTtcbiAgICB9XG5cbiAgICBjcmVhdGVQZWVyQ29ubmVjdGlvbihvcHRpb25zOiBSVENDb25maWd1cmF0aW9uLCBwcmVmZXJyZWRDb2RlYzogc3RyaW5nKSB7XG4gICAgICAgIC8vIFNldCB0aGUgSUNFIHRyYW5zcG9ydCB0byByZWxheSBpZiBUVVJOIGVuYWJsZWRcbiAgICAgICAgaWYgKHRoaXMuY29uZmlnLmlzRmxhZ0VuYWJsZWQoRmxhZ3MuRm9yY2VUVVJOKSkge1xuICAgICAgICAgICAgb3B0aW9ucy5pY2VUcmFuc3BvcnRQb2xpY3kgPSAncmVsYXknO1xuICAgICAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgICdGb3JjaW5nIFRVUk4gdXNhZ2UgYnkgc2V0dGluZyBJQ0UgVHJhbnNwb3J0IFBvbGljeSBpbiBwZWVyIGNvbm5lY3Rpb24gY29uZmlnLidcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBidWlsZCBhIG5ldyBwZWVyIGNvbm5lY3Rpb24gd2l0aCB0aGUgb3B0aW9uc1xuICAgICAgICB0aGlzLnBlZXJDb25uZWN0aW9uID0gbmV3IFJUQ1BlZXJDb25uZWN0aW9uKG9wdGlvbnMpO1xuICAgICAgICB0aGlzLnBlZXJDb25uZWN0aW9uLm9uc2lnbmFsaW5nc3RhdGVjaGFuZ2UgPSAoZXY6IEV2ZW50KSA9PlxuICAgICAgICAgICAgdGhpcy5oYW5kbGVTaWduYWxTdGF0ZUNoYW5nZShldik7XG4gICAgICAgIHRoaXMucGVlckNvbm5lY3Rpb24ub25pY2Vjb25uZWN0aW9uc3RhdGVjaGFuZ2UgPSAoZXY6IEV2ZW50KSA9PlxuICAgICAgICAgICAgdGhpcy5oYW5kbGVJY2VDb25uZWN0aW9uU3RhdGVDaGFuZ2UoZXYpO1xuICAgICAgICB0aGlzLnBlZXJDb25uZWN0aW9uLm9uaWNlZ2F0aGVyaW5nc3RhdGVjaGFuZ2UgPSAoZXY6IEV2ZW50KSA9PlxuICAgICAgICAgICAgdGhpcy5oYW5kbGVJY2VHYXRoZXJpbmdTdGF0ZUNoYW5nZShldik7XG4gICAgICAgIHRoaXMucGVlckNvbm5lY3Rpb24ub250cmFjayA9IChldjogUlRDVHJhY2tFdmVudCkgPT5cbiAgICAgICAgICAgIHRoaXMuaGFuZGxlT25UcmFjayhldik7XG4gICAgICAgIHRoaXMucGVlckNvbm5lY3Rpb24ub25pY2VjYW5kaWRhdGUgPSAoZXY6IFJUQ1BlZXJDb25uZWN0aW9uSWNlRXZlbnQpID0+XG4gICAgICAgICAgICB0aGlzLmhhbmRsZUljZUNhbmRpZGF0ZShldik7XG4gICAgICAgIHRoaXMucGVlckNvbm5lY3Rpb24ub25kYXRhY2hhbm5lbCA9IChldjogUlRDRGF0YUNoYW5uZWxFdmVudCkgPT5cbiAgICAgICAgICAgIHRoaXMuaGFuZGxlRGF0YUNoYW5uZWwoZXYpO1xuICAgICAgICB0aGlzLmFnZ3JlZ2F0ZWRTdGF0cyA9IG5ldyBBZ2dyZWdhdGVkU3RhdHMoKTtcbiAgICAgICAgdGhpcy5wcmVmZXJyZWRDb2RlYyA9IHByZWZlcnJlZENvZGVjO1xuICAgICAgICB0aGlzLnVwZGF0ZUNvZGVjU2VsZWN0aW9uID0gdHJ1ZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDcmVhdGUgYW4gb2ZmZXIgZm9yIHRoZSBXZWIgUlRDIGhhbmRzaGFrZSBhbmQgc2VuZCB0aGUgb2ZmZXIgdG8gdGhlIHNpZ25hbGluZyBzZXJ2ZXIgdmlhIHdlYnNvY2tldFxuICAgICAqIEBwYXJhbSBvZmZlck9wdGlvbnMgLSBSVEMgT2ZmZXIgT3B0aW9uc1xuICAgICAqL1xuICAgIGFzeW5jIGNyZWF0ZU9mZmVyKG9mZmVyT3B0aW9uczogUlRDT2ZmZXJPcHRpb25zLCBjb25maWc6IENvbmZpZykge1xuICAgICAgICBMb2dnZXIuTG9nKExvZ2dlci5HZXRTdGFja1RyYWNlKCksICdDcmVhdGUgT2ZmZXInLCA2KTtcblxuICAgICAgICBjb25zdCBpc0xvY2FsaG9zdENvbm5lY3Rpb24gPVxuICAgICAgICAgICAgbG9jYXRpb24uaG9zdG5hbWUgPT09ICdsb2NhbGhvc3QnIHx8XG4gICAgICAgICAgICBsb2NhdGlvbi5ob3N0bmFtZSA9PT0gJzEyNy4wLjAuMSc7XG4gICAgICAgIGNvbnN0IGlzSHR0cHNDb25uZWN0aW9uID0gbG9jYXRpb24ucHJvdG9jb2wgPT09ICdodHRwczonO1xuICAgICAgICBsZXQgdXNlTWljID0gY29uZmlnLmlzRmxhZ0VuYWJsZWQoRmxhZ3MuVXNlTWljKTtcbiAgICAgICAgaWYgKHVzZU1pYyAmJiAhKGlzTG9jYWxob3N0Q29ubmVjdGlvbiB8fCBpc0h0dHBzQ29ubmVjdGlvbikpIHtcbiAgICAgICAgICAgIHVzZU1pYyA9IGZhbHNlO1xuICAgICAgICAgICAgTG9nZ2VyLkVycm9yKFxuICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgJ01pY3JvcGhvbmUgYWNjZXNzIGluIHRoZSBicm93c2VyIHdpbGwgbm90IHdvcmsgaWYgeW91IGFyZSBub3Qgb24gSFRUUFMgb3IgbG9jYWxob3N0LiBEaXNhYmxpbmcgbWljIGFjY2Vzcy4nXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgTG9nZ2VyLkVycm9yKFxuICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgXCJGb3IgdGVzdGluZyB5b3UgY2FuIGVuYWJsZSBIVFRQIG1pY3JvcGhvbmUgYWNjZXNzIENocm9tZSBieSB2aXNpdGluZyBjaHJvbWU6Ly9mbGFncy8gYW5kIGVuYWJsaW5nICd1bnNhZmVseS10cmVhdC1pbnNlY3VyZS1vcmlnaW4tYXMtc2VjdXJlJ1wiXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zZXR1cFRyYW5zY2VpdmVyc0FzeW5jKHVzZU1pYykuZmluYWxseSgoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnBlZXJDb25uZWN0aW9uXG4gICAgICAgICAgICAgICAgPy5jcmVhdGVPZmZlcihvZmZlck9wdGlvbnMpXG4gICAgICAgICAgICAgICAgLnRoZW4oKG9mZmVyOiBSVENTZXNzaW9uRGVzY3JpcHRpb25Jbml0KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2hvd1RleHRPdmVybGF5Q29ubmVjdGluZygpO1xuICAgICAgICAgICAgICAgICAgICBvZmZlci5zZHAgPSB0aGlzLm11bmdlU0RQKG9mZmVyLnNkcCwgdXNlTWljKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wZWVyQ29ubmVjdGlvbj8uc2V0TG9jYWxEZXNjcmlwdGlvbihvZmZlcik7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMub25TZW5kV2ViUlRDT2ZmZXIob2ZmZXIpO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmNhdGNoKCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zaG93VGV4dE92ZXJsYXlTZXR1cEZhaWx1cmUoKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICpcbiAgICAgKi9cbiAgICBhc3luYyByZWNlaXZlT2ZmZXIob2ZmZXI6IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbkluaXQsIGNvbmZpZzogQ29uZmlnKSB7XG4gICAgICAgIExvZ2dlci5Mb2coTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSwgJ1JlY2VpdmUgT2ZmZXInLCA2KTtcblxuICAgICAgICB0aGlzLnBlZXJDb25uZWN0aW9uPy5zZXRSZW1vdGVEZXNjcmlwdGlvbihvZmZlcikudGhlbigoKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBpc0xvY2FsaG9zdENvbm5lY3Rpb24gPVxuICAgICAgICAgICAgICAgIGxvY2F0aW9uLmhvc3RuYW1lID09PSAnbG9jYWxob3N0JyB8fFxuICAgICAgICAgICAgICAgIGxvY2F0aW9uLmhvc3RuYW1lID09PSAnMTI3LjAuMC4xJztcbiAgICAgICAgICAgIGNvbnN0IGlzSHR0cHNDb25uZWN0aW9uID0gbG9jYXRpb24ucHJvdG9jb2wgPT09ICdodHRwczonO1xuICAgICAgICAgICAgbGV0IHVzZU1pYyA9IGNvbmZpZy5pc0ZsYWdFbmFibGVkKEZsYWdzLlVzZU1pYyk7XG4gICAgICAgICAgICBpZiAodXNlTWljICYmICEoaXNMb2NhbGhvc3RDb25uZWN0aW9uIHx8IGlzSHR0cHNDb25uZWN0aW9uKSkge1xuICAgICAgICAgICAgICAgIHVzZU1pYyA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIExvZ2dlci5FcnJvcihcbiAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICAgICAgJ01pY3JvcGhvbmUgYWNjZXNzIGluIHRoZSBicm93c2VyIHdpbGwgbm90IHdvcmsgaWYgeW91IGFyZSBub3Qgb24gSFRUUFMgb3IgbG9jYWxob3N0LiBEaXNhYmxpbmcgbWljIGFjY2Vzcy4nXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBMb2dnZXIuRXJyb3IoXG4gICAgICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgICAgIFwiRm9yIHRlc3RpbmcgeW91IGNhbiBlbmFibGUgSFRUUCBtaWNyb3Bob25lIGFjY2VzcyBDaHJvbWUgYnkgdmlzaXRpbmcgY2hyb21lOi8vZmxhZ3MvIGFuZCBlbmFibGluZyAndW5zYWZlbHktdHJlYXQtaW5zZWN1cmUtb3JpZ2luLWFzLXNlY3VyZSdcIlxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuc2V0dXBUcmFuc2NlaXZlcnNBc3luYyh1c2VNaWMpLmZpbmFsbHkoKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMucGVlckNvbm5lY3Rpb25cbiAgICAgICAgICAgICAgICAgICAgPy5jcmVhdGVBbnN3ZXIoKVxuICAgICAgICAgICAgICAgICAgICAudGhlbigoQW5zd2VyOiBSVENTZXNzaW9uRGVzY3JpcHRpb25Jbml0KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBBbnN3ZXIuc2RwID0gdGhpcy5tdW5nZVNEUChBbnN3ZXIuc2RwLCB1c2VNaWMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMucGVlckNvbm5lY3Rpb24/LnNldExvY2FsRGVzY3JpcHRpb24oQW5zd2VyKTtcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5vblNlbmRXZWJSVENBbnN3ZXIoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5wZWVyQ29ubmVjdGlvbj8uY3VycmVudExvY2FsRGVzY3JpcHRpb25cbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgIC5jYXRjaCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBMb2dnZXIuRXJyb3IoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnY3JlYXRlQW5zd2VyKCkgZmFpbGVkJ1xuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gVWdseSBzeW50YXgsIGJ1dCB0aGlzIGFjaGlldmVzIHRoZSBpbnRlcnNlY3Rpb24gb2YgdGhlIGJyb3dzZXIgc3VwcG9ydGVkIGxpc3QgYW5kIHRoZSBVRSBzdXBwb3J0ZWQgbGlzdFxuICAgICAgICB0aGlzLmNvbmZpZy5zZXRPcHRpb25TZXR0aW5nT3B0aW9ucyhcbiAgICAgICAgICAgIE9wdGlvblBhcmFtZXRlcnMuUHJlZmVycmVkQ29kZWMsXG4gICAgICAgICAgICB0aGlzLnBhcnNlQXZhaWxhYmxlQ29kZWNzKG9mZmVyKS5maWx0ZXIoKHZhbHVlKSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuY29uZmlnXG4gICAgICAgICAgICAgICAgICAgIC5nZXRTZXR0aW5nT3B0aW9uKE9wdGlvblBhcmFtZXRlcnMuUHJlZmVycmVkQ29kZWMpXG4gICAgICAgICAgICAgICAgICAgIC5vcHRpb25zLmluY2x1ZGVzKHZhbHVlKVxuICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCB0aGUgUmVtb3RlIERlc2NyaXB0b3IgZnJvbSB0aGUgc2lnbmFsaW5nIHNlcnZlciB0byB0aGUgUlRDIFBlZXIgQ29ubmVjdGlvblxuICAgICAqIEBwYXJhbSBhbnN3ZXIgLSBSVEMgU2Vzc2lvbiBEZXNjcmlwdG9yIGZyb20gdGhlIFNpZ25hbGluZyBTZXJ2ZXJcbiAgICAgKi9cbiAgICByZWNlaXZlQW5zd2VyKGFuc3dlcjogUlRDU2Vzc2lvbkRlc2NyaXB0aW9uSW5pdCkge1xuICAgICAgICB0aGlzLnBlZXJDb25uZWN0aW9uPy5zZXRSZW1vdGVEZXNjcmlwdGlvbihhbnN3ZXIpO1xuICAgICAgICAvLyBVZ2x5IHN5bnRheCwgYnV0IHRoaXMgYWNoaWV2ZXMgdGhlIGludGVyc2VjdGlvbiBvZiB0aGUgYnJvd3NlciBzdXBwb3J0ZWQgbGlzdCBhbmQgdGhlIFVFIHN1cHBvcnRlZCBsaXN0XG4gICAgICAgIHRoaXMuY29uZmlnLnNldE9wdGlvblNldHRpbmdPcHRpb25zKFxuICAgICAgICAgICAgT3B0aW9uUGFyYW1ldGVycy5QcmVmZXJyZWRDb2RlYyxcbiAgICAgICAgICAgIHRoaXMucGFyc2VBdmFpbGFibGVDb2RlY3MoYW5zd2VyKS5maWx0ZXIoKHZhbHVlKSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuY29uZmlnXG4gICAgICAgICAgICAgICAgICAgIC5nZXRTZXR0aW5nT3B0aW9uKE9wdGlvblBhcmFtZXRlcnMuUHJlZmVycmVkQ29kZWMpXG4gICAgICAgICAgICAgICAgICAgIC5vcHRpb25zLmluY2x1ZGVzKHZhbHVlKVxuICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdlbmVyYXRlIEFnZ3JlZ2F0ZWQgU3RhdHMgYW5kIHRoZW4gZmlyZSBhIG9uVmlkZW8gU3RhdHMgZXZlbnRcbiAgICAgKi9cbiAgICBnZW5lcmF0ZVN0YXRzKCkge1xuICAgICAgICB0aGlzLnBlZXJDb25uZWN0aW9uPy5nZXRTdGF0cyhudWxsKS50aGVuKChTdGF0c0RhdGE6IFJUQ1N0YXRzUmVwb3J0KSA9PiB7XG4gICAgICAgICAgICB0aGlzLmFnZ3JlZ2F0ZWRTdGF0cy5wcm9jZXNzU3RhdHMoU3RhdHNEYXRhKTtcbiAgICAgICAgICAgIHRoaXMub25WaWRlb1N0YXRzKHRoaXMuYWdncmVnYXRlZFN0YXRzKTtcblxuICAgICAgICAgICAgLy8gVXBkYXRlIHRoZSBwcmVmZXJyZWQgY29kZWMgc2VsZWN0aW9uIGJhc2VkIG9uIHdoYXQgd2FzIGFjdHVhbGx5IG5lZ290aWF0ZWRcbiAgICAgICAgICAgIGlmICh0aGlzLnVwZGF0ZUNvZGVjU2VsZWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jb25maWcuc2V0T3B0aW9uU2V0dGluZ1ZhbHVlKFxuICAgICAgICAgICAgICAgICAgICBPcHRpb25QYXJhbWV0ZXJzLlByZWZlcnJlZENvZGVjLFxuICAgICAgICAgICAgICAgICAgICB0aGlzLmFnZ3JlZ2F0ZWRTdGF0cy5jb2RlY3MuZ2V0KFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5hZ2dyZWdhdGVkU3RhdHMuaW5ib3VuZFZpZGVvU3RhdHMuY29kZWNJZFxuICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2xvc2UgVGhlIFBlZXIgQ29ubmVjdGlvblxuICAgICAqL1xuICAgIGNsb3NlKCkge1xuICAgICAgICBpZiAodGhpcy5wZWVyQ29ubmVjdGlvbikge1xuICAgICAgICAgICAgdGhpcy5wZWVyQ29ubmVjdGlvbi5jbG9zZSgpO1xuICAgICAgICAgICAgdGhpcy5wZWVyQ29ubmVjdGlvbiA9IG51bGw7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBNb2RpZnkgdGhlIFNlc3Npb24gRGVzY3JpcHRvclxuICAgICAqIEBwYXJhbSBzZHAgLSBTZXNzaW9uIERlc2NyaXB0b3IgYXMgYSBzdHJpbmdcbiAgICAgKiBAcGFyYW0gdXNlTWljIC0gSXMgdGhlIG1pY3JvcGhvbmUgaW4gdXNlXG4gICAgICogQHJldHVybnMgQSBtb2RpZmllZCBTZXNzaW9uIERlc2NyaXB0b3JcbiAgICAgKi9cbiAgICBtdW5nZVNEUChzZHA6IHN0cmluZywgdXNlTWljOiBib29sZWFuKSB7XG4gICAgICAgIGxldCBtdW5nZWRTRFAgPSBzZHAucmVwbGFjZShcbiAgICAgICAgICAgIC8oYT1mbXRwOlxcZCsgLipsZXZlbC1hc3ltbWV0cnktYWxsb3dlZD0uKilcXHJcXG4vZ20sXG4gICAgICAgICAgICAnJDE7eC1nb29nbGUtc3RhcnQtYml0cmF0ZT0xMDAwMDt4LWdvb2dsZS1tYXgtYml0cmF0ZT0xMDAwMDBcXHJcXG4nXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gc2V0IG1heCBiaXRyYXRlIHRvIGhpZ2hlc3QgYml0cmF0ZSBPcHVzIHN1cHBvcnRzXG4gICAgICAgIGxldCBhdWRpb1NEUCA9ICdtYXhhdmVyYWdlYml0cmF0ZT01MTAwMDA7JztcblxuICAgICAgICBpZiAodXNlTWljKSB7XG4gICAgICAgICAgICAvLyBzZXQgdGhlIG1heCBjYXB0dXJlIHJhdGUgdG8gNDhraHogKHNvIHdlIGNhbiBzZW5kIGhpZ2ggcXVhbGl0eSBhdWRpbyBmcm9tIG1pYylcbiAgICAgICAgICAgIGF1ZGlvU0RQICs9ICdzcHJvcC1tYXhjYXB0dXJlcmF0ZT00ODAwMDsnO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gRm9yY2UgbW9ubyBvciBzdGVyZW8gYmFzZWQgb24gd2hldGhlciA/Zm9yY2VNb25vIHdhcyBwYXNzZWQgb3Igbm90XG4gICAgICAgIGF1ZGlvU0RQICs9IHRoaXMuY29uZmlnLmlzRmxhZ0VuYWJsZWQoRmxhZ3MuRm9yY2VNb25vQXVkaW8pXG4gICAgICAgICAgICA/ICdzdGVyZW89MDsnXG4gICAgICAgICAgICA6ICdzdGVyZW89MTsnO1xuXG4gICAgICAgIC8vIGVuYWJsZSBpbi1iYW5kIGZvcndhcmQgZXJyb3IgY29ycmVjdGlvbiBmb3Igb3B1cyBhdWRpb1xuICAgICAgICBhdWRpb1NEUCArPSAndXNlaW5iYW5kZmVjPTEnO1xuXG4gICAgICAgIC8vIFdlIHVzZSB0aGUgbGluZSAndXNlaW5iYW5kZmVjPTEnICh3aGljaCBPcHVzIHVzZXMpIHRvIHNldCBvdXIgT3B1cyBzcGVjaWZpYyBhdWRpbyBwYXJhbWV0ZXJzLlxuICAgICAgICBtdW5nZWRTRFAgPSBtdW5nZWRTRFAucmVwbGFjZSgndXNlaW5iYW5kZmVjPTEnLCBhdWRpb1NEUCk7XG5cbiAgICAgICAgcmV0dXJuIG11bmdlZFNEUDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBXaGVuIGEgSWNlIENhbmRpZGF0ZSBpcyByZWNlaXZlZCBhZGQgdG8gdGhlIFJUQyBQZWVyIENvbm5lY3Rpb25cbiAgICAgKiBAcGFyYW0gaWNlQ2FuZGlkYXRlIC0gUlRDIEljZSBDYW5kaWRhdGUgZnJvbSB0aGUgU2lnbmFsaW5nIFNlcnZlclxuICAgICAqL1xuICAgIGhhbmRsZU9uSWNlKGljZUNhbmRpZGF0ZTogUlRDSWNlQ2FuZGlkYXRlKSB7XG4gICAgICAgIExvZ2dlci5Mb2coTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSwgJ3BlZXJjb25uZWN0aW9uIGhhbmRsZU9uSWNlJywgNik7XG5cbiAgICAgICAgLy8gLy8gaWYgZm9yY2luZyBUVVJOLCByZWplY3QgYW55IGNhbmRpZGF0ZXMgbm90IHJlbGF5XG4gICAgICAgIGlmICh0aGlzLmNvbmZpZy5pc0ZsYWdFbmFibGVkKEZsYWdzLkZvcmNlVFVSTikpIHtcbiAgICAgICAgICAgIC8vIGNoZWNrIGlmIG5vIHJlbGF5IGFkZHJlc3MgaXMgZm91bmQsIGlmIHNvLCB3ZSBhcmUgYXNzdW1pbmcgaXQgbWVhbnMgbm8gVFVSTiBzZXJ2ZXJcbiAgICAgICAgICAgIGlmIChpY2VDYW5kaWRhdGUuY2FuZGlkYXRlLmluZGV4T2YoJ3JlbGF5JykgPCAwKSB7XG4gICAgICAgICAgICAgICAgTG9nZ2VyLkluZm8oXG4gICAgICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgICAgIGBEcm9wcGluZyBjYW5kaWRhdGUgYmVjYXVzZSBpdCB3YXMgbm90IFRVUk4gcmVsYXkuIHwgVHlwZT0gJHtpY2VDYW5kaWRhdGUudHlwZX0gfCBQcm90b2NvbD0gJHtpY2VDYW5kaWRhdGUucHJvdG9jb2x9IHwgQWRkcmVzcz0ke2ljZUNhbmRpZGF0ZS5hZGRyZXNzfSB8IFBvcnQ9JHtpY2VDYW5kaWRhdGUucG9ydH0gfGAsXG4gICAgICAgICAgICAgICAgICAgIDZcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMucGVlckNvbm5lY3Rpb24/LmFkZEljZUNhbmRpZGF0ZShpY2VDYW5kaWRhdGUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFdoZW4gdGhlIFJUQyBQZWVyIENvbm5lY3Rpb24gU2lnbmFsaW5nIHNlcnZlciBzdGF0ZSBDaGFuZ2VzXG4gICAgICogQHBhcmFtIHN0YXRlIC0gU2lnbmFsaW5nIFNlcnZlciBTdGF0ZSBDaGFuZ2UgRXZlbnRcbiAgICAgKi9cbiAgICBoYW5kbGVTaWduYWxTdGF0ZUNoYW5nZShzdGF0ZTogRXZlbnQpIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAnc2lnbmFsaW5nIHN0YXRlIGNoYW5nZTogJyArIHN0YXRlLFxuICAgICAgICAgICAgNlxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEhhbmRsZSB3aGVuIHRoZSBJY2UgQ29ubmVjdGlvbiBTdGF0ZSBDaGFuZ2VzXG4gICAgICogQHBhcmFtIHN0YXRlIC0gSWNlIENvbm5lY3Rpb24gU3RhdGVcbiAgICAgKi9cbiAgICBoYW5kbGVJY2VDb25uZWN0aW9uU3RhdGVDaGFuZ2Uoc3RhdGU6IEV2ZW50KSB7XG4gICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgJ2ljZSBjb25uZWN0aW9uIHN0YXRlIGNoYW5nZTogJyArIHN0YXRlLFxuICAgICAgICAgICAgNlxuICAgICAgICApO1xuICAgICAgICB0aGlzLm9uSWNlQ29ubmVjdGlvblN0YXRlQ2hhbmdlKHN0YXRlKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGUgd2hlbiB0aGUgSWNlIEdhdGhlcmluZyBTdGF0ZSBDaGFuZ2VzXG4gICAgICogQHBhcmFtIHN0YXRlIC0gSWNlIEdhdGhlcmluZyBTdGF0ZSBDaGFuZ2VcbiAgICAgKi9cbiAgICBoYW5kbGVJY2VHYXRoZXJpbmdTdGF0ZUNoYW5nZShzdGF0ZTogRXZlbnQpIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAnaWNlIGdhdGhlcmluZyBzdGF0ZSBjaGFuZ2U6ICcgKyBKU09OLnN0cmluZ2lmeShzdGF0ZSksXG4gICAgICAgICAgICA2XG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQWN0aXZhdGVzIHRoZSBvblRyYWNrIG1ldGhvZFxuICAgICAqIEBwYXJhbSBldmVudCAtIFRoZSB3ZWJSdGMgdHJhY2sgZXZlbnRcbiAgICAgKi9cbiAgICBoYW5kbGVPblRyYWNrKGV2ZW50OiBSVENUcmFja0V2ZW50KSB7XG4gICAgICAgIHRoaXMub25UcmFjayhldmVudCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQWN0aXZhdGVzIHRoZSBvblBlZXJJY2VDYW5kaWRhdGVcbiAgICAgKiBAcGFyYW0gZXZlbnQgLSBUaGUgcGVlciBpY2UgY2FuZGlkYXRlXG4gICAgICovXG4gICAgaGFuZGxlSWNlQ2FuZGlkYXRlKGV2ZW50OiBSVENQZWVyQ29ubmVjdGlvbkljZUV2ZW50KSB7XG4gICAgICAgIHRoaXMub25QZWVySWNlQ2FuZGlkYXRlKGV2ZW50KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBY3RpdmF0ZXMgdGhlIG9uRGF0YUNoYW5uZWxcbiAgICAgKiBAcGFyYW0gZXZlbnQgLSBUaGUgcGVlcidzIGRhdGEgY2hhbm5lbFxuICAgICAqL1xuICAgIGhhbmRsZURhdGFDaGFubmVsKGV2ZW50OiBSVENEYXRhQ2hhbm5lbEV2ZW50KSB7XG4gICAgICAgIHRoaXMub25EYXRhQ2hhbm5lbChldmVudCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQW4gb3ZlcnJpZGUgbWV0aG9kIGZvciBvblRyYWNrIGZvciB1c2Ugb3V0c2lkZSBvZiB0aGUgUGVlckNvbm5lY3Rpb25Db250cm9sbGVyXG4gICAgICogQHBhcmFtIHRyYWNrRXZlbnQgLSBUaGUgd2ViUnRjIHRyYWNrIGV2ZW50XG4gICAgICovXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgIG9uVHJhY2sodHJhY2tFdmVudDogUlRDVHJhY2tFdmVudCkge1xuICAgICAgICAvLyBEZWZhdWx0IEZ1bmN0aW9uYWxpdHk6IERvIE5vdGhpbmdcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBbiBvdmVycmlkZSBtZXRob2QgZm9yIG9uSWNlQ29ubmVjdGlvblN0YXRlQ2hhbmdlIGZvciB1c2Ugb3V0c2lkZSBvZiB0aGUgUGVlckNvbm5lY3Rpb25Db250cm9sbGVyXG4gICAgICogQHBhcmFtIGV2ZW50IC0gVGhlIHdlYlJ0YyBpY2Vjb25uZWN0aW9uc3RhdGVjaGFuZ2UgZXZlbnRcbiAgICAgKi9cbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICAgb25JY2VDb25uZWN0aW9uU3RhdGVDaGFuZ2UoZXZlbnQ6IEV2ZW50KSB7XG4gICAgICAgIC8vIERlZmF1bHQgRnVuY3Rpb25hbGl0eTogRG8gTm90aGluZ1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFuIG92ZXJyaWRlIG1ldGhvZCBmb3Igb25QZWVySWNlQ2FuZGlkYXRlIGZvciB1c2Ugb3V0c2lkZSBvZiB0aGUgUGVlckNvbm5lY3Rpb25Db250cm9sbGVyXG4gICAgICogQHBhcmFtIHBlZXJDb25uZWN0aW9uSWNlRXZlbnQgLSBUaGUgcGVlciBpY2UgY2FuZGlkYXRlXG4gICAgICovXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgIG9uUGVlckljZUNhbmRpZGF0ZShwZWVyQ29ubmVjdGlvbkljZUV2ZW50OiBSVENQZWVyQ29ubmVjdGlvbkljZUV2ZW50KSB7XG4gICAgICAgIC8vIERlZmF1bHQgRnVuY3Rpb25hbGl0eTogRG8gTm90aGluZ1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFuIG92ZXJyaWRlIG1ldGhvZCBmb3Igb25EYXRhQ2hhbm5lbCBmb3IgdXNlIG91dHNpZGUgb2YgdGhlIFBlZXJDb25uZWN0aW9uQ29udHJvbGxlclxuICAgICAqIEBwYXJhbSBkYXRhY2hhbm5lbEV2ZW50IC0gVGhlIHBlZXIncyBkYXRhIGNoYW5uZWxcbiAgICAgKi9cbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICAgb25EYXRhQ2hhbm5lbChkYXRhY2hhbm5lbEV2ZW50OiBSVENEYXRhQ2hhbm5lbEV2ZW50KSB7XG4gICAgICAgIC8vIERlZmF1bHQgRnVuY3Rpb25hbGl0eTogRG8gTm90aGluZ1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldHVwIHRyYWNrcyBvbiB0aGUgUlRDIFBlZXIgQ29ubmVjdGlvblxuICAgICAqIEBwYXJhbSB1c2VNaWMgLSBpcyBtaWMgaW4gdXNlXG4gICAgICovXG4gICAgYXN5bmMgc2V0dXBUcmFuc2NlaXZlcnNBc3luYyh1c2VNaWM6IGJvb2xlYW4pIHtcbiAgICAgICAgY29uc3QgaGFzVHJhbnNjZWl2ZXJzID1cbiAgICAgICAgICAgIHRoaXMucGVlckNvbm5lY3Rpb24/LmdldFRyYW5zY2VpdmVycygpLmxlbmd0aCA+IDA7XG5cbiAgICAgICAgLy8gU2V0dXAgYSB0cmFuc2NlaXZlciBmb3IgZ2V0dGluZyBVRSB2aWRlb1xuICAgICAgICB0aGlzLnBlZXJDb25uZWN0aW9uPy5hZGRUcmFuc2NlaXZlcigndmlkZW8nLCB7IGRpcmVjdGlvbjogJ3JlY3Zvbmx5JyB9KTtcblxuICAgICAgICAvLyBXZSBjYW4gb25seSBzZXQgcHJlZmVycmVjIGNvZGVjIG9uIENocm9tZVxuICAgICAgICBpZiAoUlRDUnRwUmVjZWl2ZXIuZ2V0Q2FwYWJpbGl0aWVzICYmIHRoaXMucHJlZmVycmVkQ29kZWMgIT0gJycpIHtcbiAgICAgICAgICAgIGZvciAoY29uc3QgdHJhbnNjZWl2ZXIgb2YgdGhpcy5wZWVyQ29ubmVjdGlvbj8uZ2V0VHJhbnNjZWl2ZXJzKCkgPz8gW10pIHtcbiAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgIHRyYW5zY2VpdmVyICYmICBcbiAgICAgICAgICAgICAgICAgICAgdHJhbnNjZWl2ZXIucmVjZWl2ZXIgJiZcbiAgICAgICAgICAgICAgICAgICAgdHJhbnNjZWl2ZXIucmVjZWl2ZXIudHJhY2sgJiZcbiAgICAgICAgICAgICAgICAgICAgdHJhbnNjZWl2ZXIucmVjZWl2ZXIudHJhY2sua2luZCA9PT0gJ3ZpZGVvJyAmJlxuICAgICAgICAgICAgICAgICAgICAvLyBBcyBvZiAwNi8yMDIzLCBGaXJlRm94IGhhcyBhZGRlZCBSVENSdHBSZWNlaXZlci5nZXRDYXBhYmlsaXRpZXMsIGJ1dCBoYXNuJ3QgYWRkZWQgdGhlIGFiaWxpdHkgdG8gc2V0IGNvZGVjIHByZWZlcmVuY2VzXG4gICAgICAgICAgICAgICAgICAgIHRyYW5zY2VpdmVyLnNldENvZGVjUHJlZmVyZW5jZXNcbiAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcHJlZmVycmVkUlRQQ29kZWMgPSB0aGlzLnByZWZlcnJlZENvZGVjLnNwbGl0KCcgJyk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGNvZGVjcyA9IFtcbiAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW1lVHlwZTpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3ZpZGVvLycgKyBwcmVmZXJyZWRSVFBDb2RlY1swXSAvKiBOYW1lICovLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsb2NrUmF0ZTogOTAwMDAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2RwRm10cExpbmU6IHByZWZlcnJlZFJUUENvZGVjWzFdIC8qIHNkcEZtdHBMaW5lICovXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gcHJlZmVycmVkUlRQQ29kZWNbMV1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgOiAnJ1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBdO1xuXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY29uZmlnXG4gICAgICAgICAgICAgICAgICAgICAgICAuZ2V0U2V0dGluZ09wdGlvbihPcHRpb25QYXJhbWV0ZXJzLlByZWZlcnJlZENvZGVjKVxuICAgICAgICAgICAgICAgICAgICAgICAgLm9wdGlvbnMuZmlsdGVyKChvcHRpb24pID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBSZW1vdmUgdGhlIHByZWZlcnJlZCBjb2RlYyBmcm9tIHRoZSBsaXN0IG9mIHBvc3NpYmxlIGNvZGVjcyBhcyB3ZSd2ZSBzZXQgaXQgYWxyZWFkeVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBvcHRpb24gIT0gdGhpcy5wcmVmZXJyZWRDb2RlYztcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgICAgICAuZm9yRWFjaCgob3B0aW9uKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gQW1tZW5kIHRoZSByZXN0IG9mIHRoZSBicm93c2VycyBzdXBwb3J0ZWQgY29kZWNzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgYWx0Q29kZWMgPSBvcHRpb24uc3BsaXQoJyAnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2RlY3MucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1pbWVUeXBlOiAndmlkZW8vJyArIGFsdENvZGVjWzBdIC8qIE5hbWUgKi8sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsb2NrUmF0ZTogOTAwMDAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNkcEZtdHBMaW5lOiBhbHRDb2RlY1sxXSAvKiBzZHBGbXRwTGluZSAqL1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPyBhbHRDb2RlY1sxXVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgOiAnJ1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgZm9yIChjb25zdCBjb2RlYyBvZiBjb2RlY3MpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChjb2RlYy5zZHBGbXRwTGluZSA9PT0gJycpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBXZSBjYW4ndCBkeW5hbWljYWxseSBhZGQgbWVtYmVycyB0byB0aGUgY29kZWMsIHNvIGluc3RlYWQgcmVtb3ZlIHRoZSBmaWVsZCBpZiBpdCdzIGVtcHR5XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIGNvZGVjLnNkcEZtdHBMaW5lO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgdHJhbnNjZWl2ZXIuc2V0Q29kZWNQcmVmZXJlbmNlcyhjb2RlY3MpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFNldHVwIGEgdHJhbnNjZWl2ZXIgZm9yIHNlbmRpbmcgbWljIGF1ZGlvIHRvIFVFIGFuZCByZWNlaXZpbmcgYXVkaW8gZnJvbSBVRVxuICAgICAgICBpZiAoIXVzZU1pYykge1xuICAgICAgICAgICAgdGhpcy5wZWVyQ29ubmVjdGlvbj8uYWRkVHJhbnNjZWl2ZXIoJ2F1ZGlvJywge1xuICAgICAgICAgICAgICAgIGRpcmVjdGlvbjogJ3JlY3Zvbmx5J1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBzZXQgdGhlIGF1ZGlvIG9wdGlvbnMgYmFzZWQgb24gbWljIHVzYWdlXG4gICAgICAgICAgICBjb25zdCBhdWRpb09wdGlvbnMgPSB7XG4gICAgICAgICAgICAgICAgYXV0b0dhaW5Db250cm9sOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBjaGFubmVsQ291bnQ6IDEsXG4gICAgICAgICAgICAgICAgZWNob0NhbmNlbGxhdGlvbjogZmFsc2UsXG4gICAgICAgICAgICAgICAgbGF0ZW5jeTogMCxcbiAgICAgICAgICAgICAgICBub2lzZVN1cHByZXNzaW9uOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBzYW1wbGVSYXRlOiA0ODAwMCxcbiAgICAgICAgICAgICAgICBzYW1wbGVTaXplOiAxNixcbiAgICAgICAgICAgICAgICB2b2x1bWU6IDEuMFxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBzZXQgdGhlIG1lZGlhIHNlbmQgb3B0aW9uc1xuICAgICAgICAgICAgY29uc3QgbWVkaWFTZW5kT3B0aW9uczogTWVkaWFTdHJlYW1Db25zdHJhaW50cyA9IHtcbiAgICAgICAgICAgICAgICB2aWRlbzogZmFsc2UsXG4gICAgICAgICAgICAgICAgYXVkaW86IGF1ZGlvT3B0aW9uc1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgLy8gTm90ZSB1c2luZyBtaWMgb24gYW5kcm9pZCBjaHJvbWUgcmVxdWlyZXMgU1NMIG9yIGNocm9tZTovL2ZsYWdzLyBcInVuc2FmZWx5LXRyZWF0LWluc2VjdXJlLW9yaWdpbi1hcy1zZWN1cmVcIlxuICAgICAgICAgICAgY29uc3Qgc3RyZWFtID0gYXdhaXQgbmF2aWdhdG9yLm1lZGlhRGV2aWNlcy5nZXRVc2VyTWVkaWEoXG4gICAgICAgICAgICAgICAgbWVkaWFTZW5kT3B0aW9uc1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGlmIChzdHJlYW0pIHtcbiAgICAgICAgICAgICAgICBpZiAoaGFzVHJhbnNjZWl2ZXJzKSB7XG4gICAgICAgICAgICAgICAgICAgIGZvciAoY29uc3QgdHJhbnNjZWl2ZXIgb2YgdGhpcy5wZWVyQ29ubmVjdGlvbj8uZ2V0VHJhbnNjZWl2ZXJzKCkgPz8gW10pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChSVENVdGlscy5jYW5UcmFuc2NlaXZlclJlY2VpdmVBdWRpbyh0cmFuc2NlaXZlcikpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IHRyYWNrIG9mIHN0cmVhbS5nZXRUcmFja3MoKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodHJhY2sua2luZCAmJiB0cmFjay5raW5kID09ICdhdWRpbycpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zY2VpdmVyLnNlbmRlci5yZXBsYWNlVHJhY2sodHJhY2spO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNjZWl2ZXIuZGlyZWN0aW9uID0gJ3NlbmRyZWN2JztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGZvciAoY29uc3QgdHJhY2sgb2Ygc3RyZWFtLmdldFRyYWNrcygpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodHJhY2sua2luZCAmJiB0cmFjay5raW5kID09ICdhdWRpbycpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBlZXJDb25uZWN0aW9uPy5hZGRUcmFuc2NlaXZlcih0cmFjaywge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb246ICdzZW5kcmVjdidcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5wZWVyQ29ubmVjdGlvbj8uYWRkVHJhbnNjZWl2ZXIoJ2F1ZGlvJywge1xuICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb246ICdyZWN2b25seSdcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFuZCBvdmVycmlkZSBldmVudCBmb3Igd2hlbiB0aGUgdmlkZW8gc3RhdHMgYXJlIGZpcmVkXG4gICAgICogQHBhcmFtIGV2ZW50IC0gQWdncmVnYXRlZCBTdGF0c1xuICAgICAqL1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICBvblZpZGVvU3RhdHMoZXZlbnQ6IEFnZ3JlZ2F0ZWRTdGF0cykge1xuICAgICAgICAvLyBEZWZhdWx0IEZ1bmN0aW9uYWxpdHk6IERvIE5vdGhpbmdcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBFdmVudCB0byBzZW5kIHRoZSBSVEMgb2ZmZXIgdG8gdGhlIFNpZ25hbGluZyBzZXJ2ZXJcbiAgICAgKiBAcGFyYW0gb2ZmZXIgLSBSVEMgT2ZmZXJcbiAgICAgKi9cbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICAgb25TZW5kV2ViUlRDT2ZmZXIob2ZmZXI6IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbkluaXQpIHtcbiAgICAgICAgLy8gRGVmYXVsdCBGdW5jdGlvbmFsaXR5OiBEbyBOb3RoaW5nXG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRXZlbnQgdG8gc2VuZCB0aGUgUlRDIEFuc3dlciB0byB0aGUgU2lnbmFsaW5nIHNlcnZlclxuICAgICAqIEBwYXJhbSBhbnN3ZXIgLSBSVEMgQW5zd2VyXG4gICAgICovXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgIG9uU2VuZFdlYlJUQ0Fuc3dlcihhbnN3ZXI6IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbkluaXQpIHtcbiAgICAgICAgLy8gRGVmYXVsdCBGdW5jdGlvbmFsaXR5OiBEbyBOb3RoaW5nXG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQW4gb3ZlcnJpZGUgZm9yIHNob3dpbmcgdGhlIFBlZXIgY29ubmVjdGlvbiBjb25uZWN0aW5nIE92ZXJsYXlcbiAgICAgKi9cbiAgICBzaG93VGV4dE92ZXJsYXlDb25uZWN0aW5nKCkge1xuICAgICAgICAvLyBEZWZhdWx0IEZ1bmN0aW9uYWxpdHk6IERvIE5vdGhpbmdcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBbiBvdmVycmlkZSBmb3Igc2hvd2luZyB0aGUgUGVlciBjb25uZWN0aW9uIEZhaWxlZCBvdmVybGF5XG4gICAgICovXG4gICAgc2hvd1RleHRPdmVybGF5U2V0dXBGYWlsdXJlKCkge1xuICAgICAgICAvLyBEZWZhdWx0IEZ1bmN0aW9uYWxpdHk6IERvIE5vdGhpbmdcbiAgICB9XG5cbiAgICBwYXJzZUF2YWlsYWJsZUNvZGVjcyhcbiAgICAgICAgcnRjU2Vzc2lvbkRlc2NyaXB0aW9uOiBSVENTZXNzaW9uRGVzY3JpcHRpb25Jbml0XG4gICAgKTogQXJyYXk8c3RyaW5nPiB7XG4gICAgICAgIC8vIE5vIHBvaW50IGluIHVwZGF0aW5nIHRoZSBhdmFpbGFibGUgY29kZWNzIGlmIG9uIEZGXG4gICAgICAgIGlmICghUlRDUnRwUmVjZWl2ZXIuZ2V0Q2FwYWJpbGl0aWVzKVxuICAgICAgICAgICAgcmV0dXJuIFsnT25seSBhdmFpbGFibGUgb24gQ2hyb21lJ107XG5cbiAgICAgICAgY29uc3QgdWVTdXBwb3J0ZWRDb2RlY3M6IEFycmF5PHN0cmluZz4gPSBbXTtcbiAgICAgICAgY29uc3Qgc2VjdGlvbnMgPSBzcGxpdFNlY3Rpb25zKHJ0Y1Nlc3Npb25EZXNjcmlwdGlvbi5zZHApO1xuICAgICAgICAvLyBkaXNjYXJkIHRoZSBzZXNzaW9uIGluZm9ybWF0aW9uIGFzIHdlIG9ubHkgd2FudCBtZWRpYSByZWxhdGVkIGluZm9cbiAgICAgICAgc2VjdGlvbnMuc2hpZnQoKTtcbiAgICAgICAgc2VjdGlvbnMuZm9yRWFjaCgobWVkaWFTZWN0aW9uKSA9PiB7XG4gICAgICAgICAgICBjb25zdCB7IGNvZGVjcyB9ID0gcGFyc2VSdHBQYXJhbWV0ZXJzKG1lZGlhU2VjdGlvbik7XG4gICAgICAgICAgICAvLyBGaWx0ZXIgb25seSBmb3IgVlBYIC8gSDI2WCAvIEFWMVxuICAgICAgICAgICAgY29uc3QgbWF0Y2hlciA9IC8oVlBcXGR8SDI2XFxkfEFWMSkuKi87XG4gICAgICAgICAgICBjb2RlY3MuZm9yRWFjaCgoYykgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IHN0ciA9XG4gICAgICAgICAgICAgICAgICAgIGMubmFtZSArXG4gICAgICAgICAgICAgICAgICAgICcgJyArXG4gICAgICAgICAgICAgICAgICAgIE9iamVjdC5rZXlzKGMucGFyYW1ldGVycyB8fCB7fSlcbiAgICAgICAgICAgICAgICAgICAgICAgIC5tYXAoKHApID0+IHAgKyAnPScgKyBjLnBhcmFtZXRlcnNbcF0pXG4gICAgICAgICAgICAgICAgICAgICAgICAuam9pbignOycpO1xuICAgICAgICAgICAgICAgIGNvbnN0IG1hdGNoID0gbWF0Y2hlci5leGVjKHN0cik7XG4gICAgICAgICAgICAgICAgaWYgKG1hdGNoICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChjLm5hbWUgPT0gJ1ZQOScpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFVFIGFuc3dlcnMgZG9uJ3Qgc3BlY2lmeSBwcm9maWxlIGJ1dCB3ZSBrbm93IHdlIHdhbnQgcHJvZmlsZSAwXG4gICAgICAgICAgICAgICAgICAgICAgICBjLnBhcmFtZXRlcnMgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3Byb2ZpbGUtaWQnOiAnMCdcbiAgICAgICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgY29uc3QgY29kZWNTdHI6IHN0cmluZyA9XG4gICAgICAgICAgICAgICAgICAgICAgICBjLm5hbWUgK1xuICAgICAgICAgICAgICAgICAgICAgICAgJyAnICtcbiAgICAgICAgICAgICAgICAgICAgICAgIE9iamVjdC5rZXlzKGMucGFyYW1ldGVycyB8fCB7fSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAubWFwKChwKSA9PiBwICsgJz0nICsgYy5wYXJhbWV0ZXJzW3BdKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5qb2luKCc7Jyk7XG4gICAgICAgICAgICAgICAgICAgIHVlU3VwcG9ydGVkQ29kZWNzLnB1c2goY29kZWNTdHIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gdWVTdXBwb3J0ZWRDb2RlY3M7XG4gICAgfVxufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuLyoqXG4gKiBTZXNzaW9uIHN0YXRpc3RpY3NcbiAqL1xuZXhwb3J0IGNsYXNzIFNlc3Npb25TdGF0cyB7XG4gICAgcnVuVGltZTogc3RyaW5nO1xuICAgIGNvbnRyb2xzU3RyZWFtSW5wdXQ6IHN0cmluZztcbiAgICB2aWRlb0VuY29kZXJBdmdRUDogbnVtYmVyO1xufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuLyoqXG4gKiBDbGFzcyB0byBob2xkIHRoZSBzdHJlYW0gc3RhdHMgZGF0YSBjb21pbmcgaW4gZnJvbSB3ZWJSdGNcbiAqL1xuZXhwb3J0IGNsYXNzIFN0cmVhbVN0YXRzIHtcbiAgICBpZDogc3RyaW5nO1xuICAgIHN0cmVhbUlkZW50aWZpZXI6IHN0cmluZztcbiAgICB0aW1lc3RhbXA6IG51bWJlcjtcbiAgICB0cmFja0lkczogc3RyaW5nW107XG59XG4iLCIvLyBDb3B5cmlnaHQgRXBpYyBHYW1lcywgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuXG5pbXBvcnQgeyBDb25maWcsIE9wdGlvblBhcmFtZXRlcnMgfSBmcm9tICcuLi9Db25maWcvQ29uZmlnJztcbmltcG9ydCB7IExhdGVuY3lUZXN0UmVzdWx0cyB9IGZyb20gJy4uL0RhdGFDaGFubmVsL0xhdGVuY3lUZXN0UmVzdWx0cyc7XG5pbXBvcnQgeyBBZ2dyZWdhdGVkU3RhdHMgfSBmcm9tICcuLi9QZWVyQ29ubmVjdGlvbkNvbnRyb2xsZXIvQWdncmVnYXRlZFN0YXRzJztcbmltcG9ydCB7IFdlYlJ0Y1BsYXllckNvbnRyb2xsZXIgfSBmcm9tICcuLi9XZWJSdGNQbGF5ZXIvV2ViUnRjUGxheWVyQ29udHJvbGxlcic7XG5pbXBvcnQgeyBGbGFncywgTnVtZXJpY1BhcmFtZXRlcnMgfSBmcm9tICcuLi9Db25maWcvQ29uZmlnJztcbmltcG9ydCB7IExvZ2dlciB9IGZyb20gJy4uL0xvZ2dlci9Mb2dnZXInO1xuaW1wb3J0IHsgSW5pdGlhbFNldHRpbmdzIH0gZnJvbSAnLi4vRGF0YUNoYW5uZWwvSW5pdGlhbFNldHRpbmdzJztcbmltcG9ydCB7IE9uU2NyZWVuS2V5Ym9hcmQgfSBmcm9tICcuLi9VSS9PblNjcmVlbktleWJvYXJkJztcbmltcG9ydCB7XG4gICAgRXZlbnRFbWl0dGVyLFxuICAgIEluaXRpYWxTZXR0aW5nc0V2ZW50LFxuICAgIExhdGVuY3lUZXN0UmVzdWx0RXZlbnQsXG4gICAgUGl4ZWxTdHJlYW1pbmdFdmVudCxcbiAgICBTdGF0c1JlY2VpdmVkRXZlbnQsXG4gICAgU3RyZWFtTG9hZGluZ0V2ZW50LFxuICAgIFN0cmVhbVByZUNvbm5lY3RFdmVudCxcbiAgICBTdHJlYW1SZWNvbm5lY3RFdmVudCxcbiAgICBTdHJlYW1QcmVEaXNjb25uZWN0RXZlbnQsXG4gICAgVmlkZW9FbmNvZGVyQXZnUVBFdmVudCxcbiAgICBWaWRlb0luaXRpYWxpemVkRXZlbnQsXG4gICAgV2ViUnRjQXV0b0Nvbm5lY3RFdmVudCxcbiAgICBXZWJSdGNDb25uZWN0ZWRFdmVudCxcbiAgICBXZWJSdGNDb25uZWN0aW5nRXZlbnQsXG4gICAgV2ViUnRjRGlzY29ubmVjdGVkRXZlbnQsXG4gICAgV2ViUnRjRmFpbGVkRXZlbnQsXG4gICAgV2ViUnRjU2RwRXZlbnQsXG4gICAgRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFJlc3BvbnNlRXZlbnQsXG4gICAgRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFJlc3VsdEV2ZW50LFxuICAgIFBsYXllckNvdW50RXZlbnRcbn0gZnJvbSAnLi4vVXRpbC9FdmVudEVtaXR0ZXInO1xuaW1wb3J0IHsgTWVzc2FnZU9uU2NyZWVuS2V5Ym9hcmQgfSBmcm9tICcuLi9XZWJTb2NrZXRzL01lc3NhZ2VSZWNlaXZlJztcbmltcG9ydCB7IFdlYlhSQ29udHJvbGxlciB9IGZyb20gJy4uL1dlYlhSL1dlYlhSQ29udHJvbGxlcic7XG5pbXBvcnQgeyBNZXNzYWdlRGlyZWN0aW9uIH0gZnJvbSAnLi4vVWVJbnN0YW5jZU1lc3NhZ2UvU3RyZWFtTWVzc2FnZUNvbnRyb2xsZXInO1xuaW1wb3J0IHtcbiAgICBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0Q29uZmlnLFxuICAgIERhdGFDaGFubmVsTGF0ZW5jeVRlc3RDb250cm9sbGVyXG59IGZyb20gXCIuLi9EYXRhQ2hhbm5lbC9EYXRhQ2hhbm5lbExhdGVuY3lUZXN0Q29udHJvbGxlclwiO1xuaW1wb3J0IHtcbiAgICBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVzcG9uc2UsXG4gICAgRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFJlc3VsdFxufSBmcm9tIFwiLi4vRGF0YUNoYW5uZWwvRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFJlc3VsdHNcIjtcbmltcG9ydCB7IFJUQ1V0aWxzIH0gZnJvbSAnLi4vVXRpbC9SVENVdGlscyc7XG5cblxuZXhwb3J0IGludGVyZmFjZSBQaXhlbFN0cmVhbWluZ092ZXJyaWRlcyB7XG4gICAgLyoqIFRoZSBET00gZWxtZW50IHdoZXJlIFBpeGVsIFN0cmVhbWluZyB2aWRlbyBhbmQgdXNlciBpbnB1dCBldmVudCBoYW5kbGVycyBhcmUgYXR0YWNoZWQgdG8uXG4gICAgICogWW91IGNhbiBnaXZlIGFuIGV4aXN0aW5nIERPTSBlbGVtZW50IGhlcmUuIElmIG5vdCBnaXZlbiwgdGhlIGxpYnJhcnkgd2lsbCBjcmVhdGUgYSBuZXcgZGl2IGVsZW1lbnRcbiAgICAgKiB0aGF0IGlzIG5vdCBhdHRhY2hlZCBhbnl3aGVyZS4gSW4gdGhpcyBjYXNlIHlvdSBjYW4gbGF0ZXIgZ2V0IGFjY2VzcyB0byB0aGlzIG5ldyBlbGVtZW50IGFuZFxuICAgICAqIGF0dGFjaCBpdCB0byB5b3VyIHdlYiBwYWdlLiAqL1xuICAgIHZpZGVvRWxlbWVudFBhcmVudD86IEhUTUxFbGVtZW50O1xufVxuXG4vKipcbiAqIFRoZSBrZXkgY2xhc3MgZm9yIHRoZSBicm93c2VyIHNpZGUgb2YgYSBQaXhlbCBTdHJlYW1pbmcgYXBwbGljYXRpb24sIGl0IGluY2x1ZGVzOlxuICogV2ViUlRDIGhhbmRsaW5nLCBYUiBzdXBwb3J0LCBpbnB1dCBoYW5kbGluZywgYW5kIGVtaXR0ZXJzIGZvciBsaWZldGltZSBhbmQgc3RhdGUgY2hhbmdlIGV2ZW50cy5cbiAqIFVzZXJzIGFyZSBlbmNvdXJhZ2VkIHRvIHVzZSB0aGlzIGNsYXNzIGFzIGlzLCB0aHJvdWdoIGNvbXBvc2l0aW9uLCBvciBleHRlbmQgaXQuIEluIGFueSBjYXNlLCBcbiAqIHRoaXMgd2lsbCBsaWtlbHkgYmUgdGhlIGNvcmUgb2YgeW91ciBQaXhlbCBTdHJlYW1pbmcgZXhwZXJpZW5jZSBpbiB0ZXJtcyBvZiBmdW5jdGlvbmFsaXR5LlxuICovXG5leHBvcnQgY2xhc3MgUGl4ZWxTdHJlYW1pbmcge1xuICAgIHByb3RlY3RlZCBfd2ViUnRjQ29udHJvbGxlcjogV2ViUnRjUGxheWVyQ29udHJvbGxlcjtcbiAgICBwcm90ZWN0ZWQgX3dlYlhyQ29udHJvbGxlcjogV2ViWFJDb250cm9sbGVyO1xuICAgIHByb3RlY3RlZCBfZGF0YUNoYW5uZWxMYXRlbmN5VGVzdENvbnRyb2xsZXI6IERhdGFDaGFubmVsTGF0ZW5jeVRlc3RDb250cm9sbGVyO1xuICAgIC8qKlxuICAgICAqIENvbmZpZ3VyYXRpb24gb2JqZWN0LiBZb3UgY2FuIHJlYWQgb3IgbW9kaWZ5IGNvbmZpZyB0aHJvdWdoIHRoaXMgb2JqZWN0LiBXaGVuZXZlclxuICAgICAqIHRoZSBjb25maWd1cmF0aW9uIGlzIGNoYW5nZWQsIHRoZSBsaWJyYXJ5IHdpbGwgZW1pdCBhIGBzZXR0aW5nc0NoYW5nZWRgIGV2ZW50LlxuICAgICAqL1xuICAgIHB1YmxpYyBjb25maWc6IENvbmZpZztcblxuICAgIHByaXZhdGUgX3ZpZGVvRWxlbWVudFBhcmVudDogSFRNTEVsZW1lbnQ7XG5cbiAgICBwcml2YXRlIGFsbG93Q29uc29sZUNvbW1hbmRzID0gZmFsc2U7XG5cbiAgICBwcml2YXRlIG9uU2NyZWVuS2V5Ym9hcmRIZWxwZXI6IE9uU2NyZWVuS2V5Ym9hcmQ7XG5cbiAgICBwcml2YXRlIF92aWRlb1N0YXJ0VGltZTogbnVtYmVyO1xuICAgIHByaXZhdGUgX2lucHV0Q29udHJvbGxlcjogYm9vbGVhbjtcblxuICAgIHByaXZhdGUgX2V2ZW50RW1pdHRlcjogRXZlbnRFbWl0dGVyO1xuXG4gICAgLyoqXG4gICAgICogQHBhcmFtIGNvbmZpZyAtIEEgbmV3bHkgaW5zdGFudGlhdGVkIGNvbmZpZyBvYmplY3RcbiAgICAgKiBAcGFyYW0gb3ZlcnJpZGVzIC0gUGFyYW1ldGVycyB0byBvdmVycmlkZSBkZWZhdWx0IGJlaGF2aW91clxuICAgICAqIHJldHVybnMgdGhlIGJhc2UgUGl4ZWwgc3RyZWFtaW5nIG9iamVjdFxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKGNvbmZpZzogQ29uZmlnLCBvdmVycmlkZXM/OiBQaXhlbFN0cmVhbWluZ092ZXJyaWRlcykge1xuICAgICAgICB0aGlzLmNvbmZpZyA9IGNvbmZpZztcblxuICAgICAgICBpZiAob3ZlcnJpZGVzPy52aWRlb0VsZW1lbnRQYXJlbnQpIHtcbiAgICAgICAgICAgIHRoaXMuX3ZpZGVvRWxlbWVudFBhcmVudCA9IG92ZXJyaWRlcy52aWRlb0VsZW1lbnRQYXJlbnQ7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLl9ldmVudEVtaXR0ZXIgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgICAgICAgdGhpcy5jb25maWd1cmVTZXR0aW5ncygpO1xuXG4gICAgICAgIC8vIHNldHVwIFdlYlJUQ1xuICAgICAgICB0aGlzLnNldFdlYlJ0Y1BsYXllckNvbnRyb2xsZXIoXG4gICAgICAgICAgICBuZXcgV2ViUnRjUGxheWVyQ29udHJvbGxlcih0aGlzLmNvbmZpZywgdGhpcylcbiAgICAgICAgKTtcblxuICAgICAgICAvLyBPbnNjcmVlbiBrZXlib2FyZFxuICAgICAgICB0aGlzLm9uU2NyZWVuS2V5Ym9hcmRIZWxwZXIgPSBuZXcgT25TY3JlZW5LZXlib2FyZChcbiAgICAgICAgICAgIHRoaXMudmlkZW9FbGVtZW50UGFyZW50XG4gICAgICAgICk7XG4gICAgICAgIHRoaXMub25TY3JlZW5LZXlib2FyZEhlbHBlci51bnF1YW50aXplQW5kRGVub3JtYWxpemVVbnNpZ25lZCA9IChcbiAgICAgICAgICAgIHg6IG51bWJlcixcbiAgICAgICAgICAgIHk6IG51bWJlclxuICAgICAgICApID0+XG4gICAgICAgICAgICB0aGlzLl93ZWJSdGNDb250cm9sbGVyLnJlcXVlc3RVbnF1YW50aXplZEFuZERlbm9ybWFsaXplVW5zaWduZWQoXG4gICAgICAgICAgICAgICAgeCxcbiAgICAgICAgICAgICAgICB5XG4gICAgICAgICAgICApO1xuICAgICAgICB0aGlzLl9hY3RpdmF0ZU9uU2NyZWVuS2V5Ym9hcmQgPSAoY29tbWFuZDogTWVzc2FnZU9uU2NyZWVuS2V5Ym9hcmQpID0+XG4gICAgICAgICAgICB0aGlzLm9uU2NyZWVuS2V5Ym9hcmRIZWxwZXIuc2hvd09uU2NyZWVuS2V5Ym9hcmQoY29tbWFuZCk7XG5cbiAgICAgICAgdGhpcy5fd2ViWHJDb250cm9sbGVyID0gbmV3IFdlYlhSQ29udHJvbGxlcih0aGlzLl93ZWJSdGNDb250cm9sbGVyKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXRzIHRoZSBlbGVtZW50IHRoYXQgY29udGFpbnMgdGhlIHZpZGVvIHN0cmVhbSBlbGVtZW50LlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgdmlkZW9FbGVtZW50UGFyZW50KCk6IEhUTUxFbGVtZW50IHtcbiAgICAgICAgaWYgKCF0aGlzLl92aWRlb0VsZW1lbnRQYXJlbnQpIHtcbiAgICAgICAgICAgIHRoaXMuX3ZpZGVvRWxlbWVudFBhcmVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgICAgICAgICAgdGhpcy5fdmlkZW9FbGVtZW50UGFyZW50LmlkID0gJ3ZpZGVvRWxlbWVudFBhcmVudCc7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuX3ZpZGVvRWxlbWVudFBhcmVudDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDb25maWd1cmUgdGhlIHNldHRpbmdzIHdpdGggb24gY2hhbmdlIGxpc3RlbmVycyBhbmQgYW55IGFkZGl0aW9uYWwgcGVyIGV4cGVyaWVuY2Ugc2V0dGluZ3MuXG4gICAgICovXG4gICAgcHJpdmF0ZSBjb25maWd1cmVTZXR0aW5ncygpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5jb25maWcuX2FkZE9uU2V0dGluZ0NoYW5nZWRMaXN0ZW5lcihcbiAgICAgICAgICAgIEZsYWdzLklzUXVhbGl0eUNvbnRyb2xsZXIsXG4gICAgICAgICAgICAod2FudHNRdWFsaXR5Q29udHJvbGxlcjogYm9vbGVhbikgPT4ge1xuICAgICAgICAgICAgICAgIC8vIElmIHRoZSBzZXR0aW5nIGhhcyBiZWVuIHNldCB0byB0cnVlIChlaXRoZXIgcHJvZ3JhbWF0aWNhbGx5IG9yIHRoZSB1c2VyIGhhcyBmbGlja2VkIHRoZSB0b2dnbGUpXG4gICAgICAgICAgICAgICAgLy8gYW5kIHdlIGFyZW4ndCBjdXJyZW50bHkgcXVhbGl0eSBjb250cm9sbGVyLCBzZW5kIHRoZSByZXF1ZXN0XG4gICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICB3YW50c1F1YWxpdHlDb250cm9sbGVyID09PSB0cnVlICYmXG4gICAgICAgICAgICAgICAgICAgICF0aGlzLl93ZWJSdGNDb250cm9sbGVyLmlzUXVhbGl0eUNvbnRyb2xsZXJcbiAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fd2ViUnRjQ29udHJvbGxlci5zZW5kUmVxdWVzdFF1YWxpdHlDb250cm9sT3duZXJzaGlwKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMuY29uZmlnLl9hZGRPblNldHRpbmdDaGFuZ2VkTGlzdGVuZXIoXG4gICAgICAgICAgICBGbGFncy5BRktEZXRlY3Rpb24sXG4gICAgICAgICAgICAoaXNBRktFbmFibGVkOiBib29sZWFuKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5fd2ViUnRjQ29udHJvbGxlci5zZXRBZmtFbmFibGVkKGlzQUZLRW5hYmxlZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5jb25maWcuX2FkZE9uU2V0dGluZ0NoYW5nZWRMaXN0ZW5lcihcbiAgICAgICAgICAgIEZsYWdzLk1hdGNoVmlld3BvcnRSZXNvbHV0aW9uLFxuICAgICAgICAgICAgKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuX3dlYlJ0Y0NvbnRyb2xsZXIudmlkZW9QbGF5ZXIudXBkYXRlVmlkZW9TdHJlYW1TaXplKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5jb25maWcuX2FkZE9uU2V0dGluZ0NoYW5nZWRMaXN0ZW5lcihcbiAgICAgICAgICAgIEZsYWdzLkhvdmVyaW5nTW91c2VNb2RlLFxuICAgICAgICAgICAgKGlzSG92ZXJpbmdNb3VzZTogYm9vbGVhbikgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuY29uZmlnLnNldEZsYWdMYWJlbChcbiAgICAgICAgICAgICAgICAgICAgRmxhZ3MuSG92ZXJpbmdNb3VzZU1vZGUsXG4gICAgICAgICAgICAgICAgICAgIGBDb250cm9sIFNjaGVtZTogJHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzSG92ZXJpbmdNb3VzZSA/ICdIb3ZlcmluZycgOiAnTG9ja2VkJ1xuICAgICAgICAgICAgICAgICAgICB9IE1vdXNlYFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgdGhpcy5fd2ViUnRjQ29udHJvbGxlci5zZXRNb3VzZUlucHV0RW5hYmxlZCh0aGlzLmNvbmZpZy5pc0ZsYWdFbmFibGVkKEZsYWdzLk1vdXNlSW5wdXQpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcblxuICAgICAgICAvLyB1c2VyIGlucHV0XG4gICAgICAgIHRoaXMuY29uZmlnLl9hZGRPblNldHRpbmdDaGFuZ2VkTGlzdGVuZXIoXG4gICAgICAgICAgICBGbGFncy5LZXlib2FyZElucHV0LFxuICAgICAgICAgICAgKGlzRW5hYmxlZDogYm9vbGVhbikgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuX3dlYlJ0Y0NvbnRyb2xsZXIuc2V0S2V5Ym9hcmRJbnB1dEVuYWJsZWQoaXNFbmFibGVkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLmNvbmZpZy5fYWRkT25TZXR0aW5nQ2hhbmdlZExpc3RlbmVyKFxuICAgICAgICAgICAgRmxhZ3MuTW91c2VJbnB1dCxcbiAgICAgICAgICAgIChpc0VuYWJsZWQ6IGJvb2xlYW4pID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLl93ZWJSdGNDb250cm9sbGVyLnNldE1vdXNlSW5wdXRFbmFibGVkKGlzRW5hYmxlZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5jb25maWcuX2FkZE9uU2V0dGluZ0NoYW5nZWRMaXN0ZW5lcihcbiAgICAgICAgICAgIEZsYWdzLlRvdWNoSW5wdXQsXG4gICAgICAgICAgICAoaXNFbmFibGVkOiBib29sZWFuKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5fd2ViUnRjQ29udHJvbGxlci5zZXRUb3VjaElucHV0RW5hYmxlZChpc0VuYWJsZWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMuY29uZmlnLl9hZGRPblNldHRpbmdDaGFuZ2VkTGlzdGVuZXIoXG4gICAgICAgICAgICBGbGFncy5HYW1lcGFkSW5wdXQsXG4gICAgICAgICAgICAoaXNFbmFibGVkOiBib29sZWFuKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5fd2ViUnRjQ29udHJvbGxlci5zZXRHYW1lUGFkSW5wdXRFbmFibGVkKGlzRW5hYmxlZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gZW5jb2RlciBzZXR0aW5nc1xuICAgICAgICB0aGlzLmNvbmZpZy5fYWRkT25OdW1lcmljU2V0dGluZ0NoYW5nZWRMaXN0ZW5lcihcbiAgICAgICAgICAgIE51bWVyaWNQYXJhbWV0ZXJzLk1pblFQLFxuICAgICAgICAgICAgKG5ld1ZhbHVlOiBudW1iZXIpID0+IHtcbiAgICAgICAgICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgICAgICAnLS0tLS0tLS0gIFNlbmRpbmcgTWluUVAgIC0tLS0tLS0tJyxcbiAgICAgICAgICAgICAgICAgICAgN1xuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgdGhpcy5fd2ViUnRjQ29udHJvbGxlci5zZW5kRW5jb2Rlck1pblFQKG5ld1ZhbHVlKTtcbiAgICAgICAgICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgICAgICAnLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLScsXG4gICAgICAgICAgICAgICAgICAgIDdcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMuY29uZmlnLl9hZGRPbk51bWVyaWNTZXR0aW5nQ2hhbmdlZExpc3RlbmVyKFxuICAgICAgICAgICAgTnVtZXJpY1BhcmFtZXRlcnMuTWF4UVAsXG4gICAgICAgICAgICAobmV3VmFsdWU6IG51bWJlcikgPT4ge1xuICAgICAgICAgICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgICAgICctLS0tLS0tLSAgU2VuZGluZyBlbmNvZGVyIHNldHRpbmdzICAtLS0tLS0tLScsXG4gICAgICAgICAgICAgICAgICAgIDdcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIHRoaXMuX3dlYlJ0Y0NvbnRyb2xsZXIuc2VuZEVuY29kZXJNYXhRUChuZXdWYWx1ZSk7XG4gICAgICAgICAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICAgICAgJy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0nLFxuICAgICAgICAgICAgICAgICAgICA3XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcblxuICAgICAgICAvLyBXZWJSVEMgc2V0dGluZ3NcbiAgICAgICAgdGhpcy5jb25maWcuX2FkZE9uTnVtZXJpY1NldHRpbmdDaGFuZ2VkTGlzdGVuZXIoXG4gICAgICAgICAgICBOdW1lcmljUGFyYW1ldGVycy5XZWJSVENNaW5CaXRyYXRlLFxuICAgICAgICAgICAgKG5ld1ZhbHVlOiBudW1iZXIpID0+IHtcbiAgICAgICAgICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgICAgICAnLS0tLS0tLS0gIFNlbmRpbmcgd2ViIHJ0YyBzZXR0aW5ncyAgLS0tLS0tLS0nLFxuICAgICAgICAgICAgICAgICAgICA3XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB0aGlzLl93ZWJSdGNDb250cm9sbGVyLnNlbmRXZWJSVENNaW5CaXRyYXRlKG5ld1ZhbHVlICogMTAwMCAvKiBrYnBzIHRvIGJwcyAqLyk7XG4gICAgICAgICAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICAgICAgJy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0nLFxuICAgICAgICAgICAgICAgICAgICA3XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLmNvbmZpZy5fYWRkT25OdW1lcmljU2V0dGluZ0NoYW5nZWRMaXN0ZW5lcihcbiAgICAgICAgICAgIE51bWVyaWNQYXJhbWV0ZXJzLldlYlJUQ01heEJpdHJhdGUsXG4gICAgICAgICAgICAobmV3VmFsdWU6IG51bWJlcikgPT4ge1xuICAgICAgICAgICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgICAgICctLS0tLS0tLSAgU2VuZGluZyB3ZWIgcnRjIHNldHRpbmdzICAtLS0tLS0tLScsXG4gICAgICAgICAgICAgICAgICAgIDdcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIHRoaXMuX3dlYlJ0Y0NvbnRyb2xsZXIuc2VuZFdlYlJUQ01heEJpdHJhdGUobmV3VmFsdWUgKiAxMDAwIC8qIGticHMgdG8gYnBzICovKTtcbiAgICAgICAgICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgICAgICAnLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLScsXG4gICAgICAgICAgICAgICAgICAgIDdcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMuY29uZmlnLl9hZGRPbk51bWVyaWNTZXR0aW5nQ2hhbmdlZExpc3RlbmVyKFxuICAgICAgICAgICAgTnVtZXJpY1BhcmFtZXRlcnMuV2ViUlRDRlBTLFxuICAgICAgICAgICAgKG5ld1ZhbHVlOiBudW1iZXIpID0+IHtcbiAgICAgICAgICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgICAgICAnLS0tLS0tLS0gIFNlbmRpbmcgd2ViIHJ0YyBzZXR0aW5ncyAgLS0tLS0tLS0nLFxuICAgICAgICAgICAgICAgICAgICA3XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB0aGlzLl93ZWJSdGNDb250cm9sbGVyLnNlbmRXZWJSVENGcHMobmV3VmFsdWUpO1xuICAgICAgICAgICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgICAgICctLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tJyxcbiAgICAgICAgICAgICAgICAgICAgN1xuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5jb25maWcuX2FkZE9uT3B0aW9uU2V0dGluZ0NoYW5nZWRMaXN0ZW5lcihcbiAgICAgICAgICAgIE9wdGlvblBhcmFtZXRlcnMuUHJlZmVycmVkQ29kZWMsXG4gICAgICAgICAgICAobmV3VmFsdWU6IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLl93ZWJSdGNDb250cm9sbGVyKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX3dlYlJ0Y0NvbnRyb2xsZXIuc2V0UHJlZmVycmVkQ29kZWMobmV3VmFsdWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLmNvbmZpZy5fcmVnaXN0ZXJPbkNoYW5nZUV2ZW50cyh0aGlzLl9ldmVudEVtaXR0ZXIpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFjdGl2YXRlIHRoZSBvbiBzY3JlZW4ga2V5Ym9hcmQgd2hlbiByZWNlaXZpbmcgdGhlIGNvbW1hbmQgZnJvbSB0aGUgc3RyZWFtZXJcbiAgICAgKiBAcGFyYW0gY29tbWFuZCAtIHRoZSBrZXlib2FyZCBjb21tYW5kXG4gICAgICovXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgIF9hY3RpdmF0ZU9uU2NyZWVuS2V5Ym9hcmQoY29tbWFuZDogTWVzc2FnZU9uU2NyZWVuS2V5Ym9hcmQpOiB2b2lkIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdNZXRob2Qgbm90IGltcGxlbWVudGVkLicpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCB0aGUgaW5wdXQgY29udHJvbCBvd25lcnNoaXBcbiAgICAgKiBAcGFyYW0gaW5wdXRDb250cm9sT3duZXJzaGlwIC0gZG9lcyB0aGUgdXNlciBoYXZlIGlucHV0IGNvbnRyb2wgb3duZXJzaGlwXG4gICAgICovXG4gICAgX29uSW5wdXRDb250cm9sT3duZXJzaGlwKGlucHV0Q29udHJvbE93bmVyc2hpcDogYm9vbGVhbik6IHZvaWQge1xuICAgICAgICB0aGlzLl9pbnB1dENvbnRyb2xsZXIgPSBpbnB1dENvbnRyb2xPd25lcnNoaXA7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSW5zdGFudGlhdGUgdGhlIFdlYlJUQ1BsYXllckNvbnRyb2xsZXIgaW50ZXJmYWNlIHRvIHByb3ZpZGUgV2ViUlRDUGxheWVyQ29udHJvbGxlciBmdW5jdGlvbmFsaXR5IHdpdGhpbiB0aGlzIGNsYXNzIGFuZCBzZXQgdXAgYW55dGhpbmcgdGhhdCByZXF1aXJlcyBpdFxuICAgICAqIEBwYXJhbSB3ZWJSdGNQbGF5ZXJDb250cm9sbGVyIC0gYSBXZWJSdGNQbGF5ZXJDb250cm9sbGVyIGNvbnRyb2xsZXIgaW5zdGFuY2VcbiAgICAgKi9cbiAgICBwcml2YXRlIHNldFdlYlJ0Y1BsYXllckNvbnRyb2xsZXIoXG4gICAgICAgIHdlYlJ0Y1BsYXllckNvbnRyb2xsZXI6IFdlYlJ0Y1BsYXllckNvbnRyb2xsZXJcbiAgICApIHtcbiAgICAgICAgdGhpcy5fd2ViUnRjQ29udHJvbGxlciA9IHdlYlJ0Y1BsYXllckNvbnRyb2xsZXI7XG5cbiAgICAgICAgdGhpcy5fd2ViUnRjQ29udHJvbGxlci5zZXRQcmVmZXJyZWRDb2RlYyhcbiAgICAgICAgICAgIHRoaXMuY29uZmlnLmdldFNldHRpbmdPcHRpb24oT3B0aW9uUGFyYW1ldGVycy5QcmVmZXJyZWRDb2RlYylcbiAgICAgICAgICAgICAgICAuc2VsZWN0ZWRcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5fd2ViUnRjQ29udHJvbGxlci5yZXNpemVQbGF5ZXJTdHlsZSgpO1xuXG4gICAgICAgIC8vIGNvbm5lY3QgaWYgYXV0byBjb25uZWN0IGZsYWcgaXMgZW5hYmxlZFxuICAgICAgICB0aGlzLmNoZWNrRm9yQXV0b0Nvbm5lY3QoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDb25uZWN0IHRvIHNpZ25hbGluZyBzZXJ2ZXIuXG4gICAgICovXG4gICAgcHVibGljIGNvbm5lY3QoKSB7XG4gICAgICAgIHRoaXMuX2V2ZW50RW1pdHRlci5kaXNwYXRjaEV2ZW50KG5ldyBTdHJlYW1QcmVDb25uZWN0RXZlbnQoKSk7XG4gICAgICAgIHRoaXMuX3dlYlJ0Y0NvbnRyb2xsZXIuY29ubmVjdFRvU2lnbmFsbGluZ1NlcnZlcigpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlY29ubmVjdHMgdG8gdGhlIHNpZ25hbGluZyBzZXJ2ZXIuIElmIGNvbm5lY3Rpb24gaXMgdXAsIGRpc2Nvbm5lY3RzIGZpcnN0XG4gICAgICogYmVmb3JlIGVzdGFibGlzaGluZyBhIG5ldyBjb25uZWN0aW9uXG4gICAgICovXG4gICAgcHVibGljIHJlY29ubmVjdCgpIHtcbiAgICAgICAgdGhpcy5fZXZlbnRFbWl0dGVyLmRpc3BhdGNoRXZlbnQobmV3IFN0cmVhbVJlY29ubmVjdEV2ZW50KCkpO1xuICAgICAgICB0aGlzLl93ZWJSdGNDb250cm9sbGVyLnRyeVJlY29ubmVjdChcIlJlY29ubmVjdGluZy4uLlwiKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBEaXNjb25uZWN0IGZyb20gdGhlIHNpZ25hbGluZyBzZXJ2ZXIgYW5kIGNsb3NlIG9wZW4gcGVlciBjb25uZWN0aW9ucy5cbiAgICAgKi9cbiAgICBwdWJsaWMgZGlzY29ubmVjdCgpIHtcbiAgICAgICAgdGhpcy5fZXZlbnRFbWl0dGVyLmRpc3BhdGNoRXZlbnQobmV3IFN0cmVhbVByZURpc2Nvbm5lY3RFdmVudCgpKTtcbiAgICAgICAgdGhpcy5fd2ViUnRjQ29udHJvbGxlci5jbG9zZSgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFBsYXkgdGhlIHN0cmVhbS4gQ2FuIGJlIGNhbGxlZCBvbmx5IGFmdGVyIGEgcGVlciBjb25uZWN0aW9uIGhhcyBiZWVuIGVzdGFibGlzaGVkLlxuICAgICAqL1xuICAgIHB1YmxpYyBwbGF5KCkge1xuICAgICAgICB0aGlzLl9vblN0cmVhbUxvYWRpbmcoKTtcbiAgICAgICAgdGhpcy5fd2ViUnRjQ29udHJvbGxlci5wbGF5U3RyZWFtKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQXV0byBjb25uZWN0IGlmIEF1dG9Db25uZWN0IGZsYWcgaXMgZW5hYmxlZFxuICAgICAqL1xuICAgIHByaXZhdGUgY2hlY2tGb3JBdXRvQ29ubmVjdCgpIHtcbiAgICAgICAgLy8gc2V0IHVwIGlmIHRoZSBhdXRvIHBsYXkgd2lsbCBiZSB1c2VkIG9yIHJlZ3VsYXIgY2xpY2sgdG8gc3RhcnRcbiAgICAgICAgaWYgKHRoaXMuY29uZmlnLmlzRmxhZ0VuYWJsZWQoRmxhZ3MuQXV0b0Nvbm5lY3QpKSB7XG4gICAgICAgICAgICAvLyBpZiBhdXRvcGxheWluZyBzaG93IGFuIGluZm8gb3ZlcmxheSB3aGlsZSB3aGlsZSB3YWl0aW5nIGZvciB0aGUgY29ubmVjdGlvbiB0byBiZWdpblxuICAgICAgICAgICAgdGhpcy5fb25XZWJSdGNBdXRvQ29ubmVjdCgpO1xuICAgICAgICAgICAgdGhpcy5fd2ViUnRjQ29udHJvbGxlci5jb25uZWN0VG9TaWduYWxsaW5nU2VydmVyKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogXG4gICAgICogV2lsbCB1bm11dGUgdGhlIG1pY3JvcGhvbmUgdHJhY2sgd2hpY2ggaXMgc2VudCB0byBVbnJlYWwgRW5naW5lLlxuICAgICAqIEJ5IGRlZmF1bHQsIHdpbGwgb25seSB1bm11dGUgYW4gZXhpc3RpbmcgbWljIHRyYWNrLlxuICAgICAqIFxuICAgICAqIEBwYXJhbSBmb3JjZUVuYWJsZSBDYW4gYmUgdXNlZCBmb3IgY2FzZXMgd2hlbiB0aGlzIG9iamVjdCB3YXNuJ3QgaW5pdGlhbGl6ZWQgd2l0aCBhIG1pYyB0cmFjay5cbiAgICAgKiBJZiB0aGlzIHBhcmFtZXRlciBpcyB0cnVlLCB0aGUgY29ubmVjdGlvbiB3aWxsIGJlIHJlc3RhcnRlZCB3aXRoIGEgbWljcm9waG9uZS5cbiAgICAgKiBXYXJuaW5nOiB0aGlzIHRha2VzIHNvbWUgdGltZSwgYXMgYSBmdWxsIHJlbmVnb3RpYXRpb24gYW5kIHJlY29ubmVjdGlvbiB3aWxsIGhhcHBlbi5cbiAgICAgKi9cbiAgICBwdWJsaWMgdW5tdXRlTWljcm9waG9uZShmb3JjZUVuYWJsZSA9IGZhbHNlKSA6IHZvaWQge1xuICAgICAgICAvLyBJZiB0aGVyZSdzIGFuIGV4aXN0aW5nIG1pYyB0cmFjaywgd2UganVzdCBzZXQgbXV0ZWQgc3RhdGVcbiAgICAgICAgaWYgKHRoaXMuY29uZmlnLmlzRmxhZ0VuYWJsZWQoJ1VzZU1pYycpKSB7XG4gICAgICAgICAgICB0aGlzLnNldE1pY3JvcGhvbmVNdXRlZChmYWxzZSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIC8vIElmIHRoZXJlJ3Mgbm8gcHJlLWV4aXN0aW5nIG1pYyB0cmFjaywgYW5kIGNhbGxlciBpcyBvayB3aXRoIGZ1bGwgcmVzZXQsIHdlIGVuYWJsZSBhbmQgcmVzZXRcbiAgICAgICAgaWYgKGZvcmNlRW5hYmxlKSB7XG4gICAgICAgICAgICB0aGlzLmNvbmZpZy5zZXRGbGFnRW5hYmxlZChcIlVzZU1pY1wiLCB0cnVlKTtcbiAgICAgICAgICAgIHRoaXMucmVjb25uZWN0KCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgICBcbiAgICAgICAgLy8gSWYgd2UgcHJlZmVyIG5vdCB0byBmb3JjZSBhIHJlY29ubmVjdGlvbiwganVzdCB3YXJuIHRoZSB1c2VyIHRoYXQgdGhpcyBvcGVyYXRpb24gZGlkbid0IGhhcHBlblxuICAgICAgICBMb2dnZXIuV2FybmluZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAnVHJ5aW5nIHRvIHVubXV0ZSBtaWMsIGJ1dCBQaXhlbFN0cmVhbWluZyB3YXMgaW5pdGlhbGl6ZWQgd2l0aCBubyBtaWNyb3Bob25lIHRyYWNrLiBDYWxsIHdpdGggZm9yY2VFbmFibGUgPT0gdHJ1ZSB0byByZS1jb25uZWN0IHdpdGggYSBtaWMgdHJhY2suJ1xuICAgICAgICApO1xuICAgIH1cblxuICAgIHB1YmxpYyBtdXRlTWljcm9waG9uZSgpIDogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmNvbmZpZy5pc0ZsYWdFbmFibGVkKCdVc2VNaWMnKSkge1xuICAgICAgICAgICAgdGhpcy5zZXRNaWNyb3Bob25lTXV0ZWQodHJ1ZSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBJZiB0aGVyZSB3YXNuJ3QgYSBtaWMgdHJhY2ssIGp1c3QgbGV0IHVzZXIga25vdyB0aGVyZSdzIG5vdGhpbmcgdG8gbXV0ZVxuICAgICAgICBMb2dnZXIuSW5mbyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAnVHJ5aW5nIHRvIG11dGUgbWljLCBidXQgUGl4ZWxTdHJlYW1pbmcgaGFzIG5vIG1pY3JvcGhvbmUgdHJhY2ssIHNvIHNlbmRpbmcgc291bmQgaXMgYWxyZWFkeSBkaXNhYmxlZC4nXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzZXRNaWNyb3Bob25lTXV0ZWQobXV0ZTogYm9vbGVhbikgOiB2b2lkXG4gICAge1xuICAgICAgICBmb3IgKGNvbnN0IHRyYW5zY2VpdmVyIG9mIHRoaXMuX3dlYlJ0Y0NvbnRyb2xsZXI/LnBlZXJDb25uZWN0aW9uQ29udHJvbGxlcj8ucGVlckNvbm5lY3Rpb24/LmdldFRyYW5zY2VpdmVycygpID8/IFtdKSB7XG4gICAgICAgICAgICBpZiAoUlRDVXRpbHMuY2FuVHJhbnNjZWl2ZXJTZW5kQXVkaW8odHJhbnNjZWl2ZXIpKSB7XG4gICAgICAgICAgICAgICAgdHJhbnNjZWl2ZXIuc2VuZGVyLnRyYWNrLmVuYWJsZWQgPSAhbXV0ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEVtaXQgYW4gZXZlbnQgb24gYXV0byBjb25uZWN0aW5nXG4gICAgICovXG4gICAgX29uV2ViUnRjQXV0b0Nvbm5lY3QoKSB7XG4gICAgICAgIHRoaXMuX2V2ZW50RW1pdHRlci5kaXNwYXRjaEV2ZW50KG5ldyBXZWJSdGNBdXRvQ29ubmVjdEV2ZW50KCkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCB1cCBmdW5jdGlvbmFsaXR5IHRvIGhhcHBlbiB3aGVuIHJlY2VpdmluZyBhIHdlYlJUQyBhbnN3ZXJcbiAgICAgKi9cbiAgICBfb25XZWJSdGNTZHAoKSB7XG4gICAgICAgIHRoaXMuX2V2ZW50RW1pdHRlci5kaXNwYXRjaEV2ZW50KG5ldyBXZWJSdGNTZHBFdmVudCgpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBFbWl0cyBhIFN0cmVhbUxvYWRpbmcgZXZlbnRcbiAgICAgKi9cbiAgICBfb25TdHJlYW1Mb2FkaW5nKCkge1xuICAgICAgICB0aGlzLl9ldmVudEVtaXR0ZXIuZGlzcGF0Y2hFdmVudChuZXcgU3RyZWFtTG9hZGluZ0V2ZW50KCkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEV2ZW50IGZpcmVkIHdoZW4gdGhlIHZpZGVvIGlzIGRpc2Nvbm5lY3RlZCAtIGVtaXRzIGdpdmVuIGV2ZW50U3RyaW5nIG9yIGFuIG92ZXJyaWRlXG4gICAgICogbWVzc2FnZSBmcm9tIHdlYlJ0Y0NvbnRyb2xsZXIgaWYgb25lIGhhcyBiZWVuIHNldFxuICAgICAqIEBwYXJhbSBldmVudFN0cmluZyAtIGEgc3RyaW5nIGRlc2NyaWJpbmcgd2h5IHRoZSBjb25uZWN0aW9uIGNsb3NlZFxuICAgICAqIEBwYXJhbSBhbGxvd0NsaWNrVG9SZWNvbm5lY3QgLSB0cnVlIGlmIHdlIHdhbnQgdG8gYWxsb3cgdGhlIHVzZXIgdG8gcmV0cnkgdGhlIGNvbm5lY3Rpb24gd2l0aCBhIGNsaWNrXG4gICAgICovXG4gICAgX29uRGlzY29ubmVjdChldmVudFN0cmluZzogc3RyaW5nLCBhbGxvd0NsaWNrVG9SZWNvbm5lY3Q6IGJvb2xlYW4pIHtcbiAgICAgICAgdGhpcy5fZXZlbnRFbWl0dGVyLmRpc3BhdGNoRXZlbnQoXG4gICAgICAgICAgICBuZXcgV2ViUnRjRGlzY29ubmVjdGVkRXZlbnQoe1xuICAgICAgICAgICAgICAgIGV2ZW50U3RyaW5nOiBldmVudFN0cmluZyxcbiAgICAgICAgICAgICAgICBhbGxvd0NsaWNrVG9SZWNvbm5lY3Q6IGFsbG93Q2xpY2tUb1JlY29ubmVjdFxuICAgICAgICAgICAgfSlcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGVzIHdoZW4gV2ViIFJ0YyBpcyBjb25uZWN0aW5nXG4gICAgICovXG4gICAgX29uV2ViUnRjQ29ubmVjdGluZygpIHtcbiAgICAgICAgdGhpcy5fZXZlbnRFbWl0dGVyLmRpc3BhdGNoRXZlbnQobmV3IFdlYlJ0Y0Nvbm5lY3RpbmdFdmVudCgpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGVzIHdoZW4gV2ViIFJ0YyBoYXMgY29ubmVjdGVkXG4gICAgICovXG4gICAgX29uV2ViUnRjQ29ubmVjdGVkKCkge1xuICAgICAgICB0aGlzLl9ldmVudEVtaXR0ZXIuZGlzcGF0Y2hFdmVudChuZXcgV2ViUnRjQ29ubmVjdGVkRXZlbnQoKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSGFuZGxlcyB3aGVuIFdlYiBSdGMgZmFpbHMgdG8gY29ubmVjdFxuICAgICAqL1xuICAgIF9vbldlYlJ0Y0ZhaWxlZCgpIHtcbiAgICAgICAgdGhpcy5fZXZlbnRFbWl0dGVyLmRpc3BhdGNoRXZlbnQobmV3IFdlYlJ0Y0ZhaWxlZEV2ZW50KCkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEhhbmRsZSB3aGVuIHRoZSBWaWRlbyBoYXMgYmVlbiBJbml0aWFsaXplZFxuICAgICAqL1xuICAgIF9vblZpZGVvSW5pdGlhbGl6ZWQoKSB7XG4gICAgICAgIHRoaXMuX2V2ZW50RW1pdHRlci5kaXNwYXRjaEV2ZW50KG5ldyBWaWRlb0luaXRpYWxpemVkRXZlbnQoKSk7XG4gICAgICAgIHRoaXMuX3ZpZGVvU3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXQgdXAgZnVuY3Rpb25hbGl0eSB0byBoYXBwZW4gd2hlbiByZWNlaXZpbmcgbGF0ZW5jeSB0ZXN0IHJlc3VsdHNcbiAgICAgKiBAcGFyYW0gbGF0ZW5jeSAtIGxhdGVuY3kgdGVzdCByZXN1bHRzIG9iamVjdFxuICAgICAqL1xuICAgIF9vbkxhdGVuY3lUZXN0UmVzdWx0KGxhdGVuY3lUaW1pbmdzOiBMYXRlbmN5VGVzdFJlc3VsdHMpIHtcbiAgICAgICAgdGhpcy5fZXZlbnRFbWl0dGVyLmRpc3BhdGNoRXZlbnQoXG4gICAgICAgICAgICBuZXcgTGF0ZW5jeVRlc3RSZXN1bHRFdmVudCh7IGxhdGVuY3lUaW1pbmdzIH0pXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgX29uRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFJlc3BvbnNlKHJlc3BvbnNlOiBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVzcG9uc2UpIHtcbiAgICAgICAgdGhpcy5fZXZlbnRFbWl0dGVyLmRpc3BhdGNoRXZlbnQoXG4gICAgICAgICAgICBuZXcgRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFJlc3BvbnNlRXZlbnQoeyByZXNwb25zZSB9KVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCB1cCBmdW5jdGlvbmFsaXR5IHRvIGhhcHBlbiB3aGVuIHJlY2VpdmluZyB2aWRlbyBzdGF0aXN0aWNzXG4gICAgICogQHBhcmFtIHZpZGVvU3RhdHMgLSB2aWRlbyBzdGF0aXN0aWNzIGFzIGEgYWdncmVnYXRlIHN0YXRzIG9iamVjdFxuICAgICAqL1xuICAgIF9vblZpZGVvU3RhdHModmlkZW9TdGF0czogQWdncmVnYXRlZFN0YXRzKSB7XG4gICAgICAgIC8vIER1cmF0aW9uXG4gICAgICAgIGlmICghdGhpcy5fdmlkZW9TdGFydFRpbWUgfHwgdGhpcy5fdmlkZW9TdGFydFRpbWUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGhpcy5fdmlkZW9TdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuICAgICAgICB9XG4gICAgICAgIHZpZGVvU3RhdHMuaGFuZGxlU2Vzc2lvblN0YXRpc3RpY3MoXG4gICAgICAgICAgICB0aGlzLl92aWRlb1N0YXJ0VGltZSxcbiAgICAgICAgICAgIHRoaXMuX2lucHV0Q29udHJvbGxlcixcbiAgICAgICAgICAgIHRoaXMuX3dlYlJ0Y0NvbnRyb2xsZXIudmlkZW9BdmdRcFxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMuX2V2ZW50RW1pdHRlci5kaXNwYXRjaEV2ZW50KFxuICAgICAgICAgICAgbmV3IFN0YXRzUmVjZWl2ZWRFdmVudCh7IGFnZ3JlZ2F0ZWRTdGF0czogdmlkZW9TdGF0cyB9KVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCB1cCBmdW5jdGlvbmFsaXR5IHRvIGhhcHBlbiB3aGVuIGNhbGN1bGF0aW5nIHRoZSBhdmVyYWdlIHZpZGVvIGVuY29kZXIgcXBcbiAgICAgKiBAcGFyYW0gUVAgLSB0aGUgcXVhbGl0eSBudW1iZXIgb2YgdGhlIHN0cmVhbVxuICAgICAqL1xuICAgIF9vblZpZGVvRW5jb2RlckF2Z1FQKFFQOiBudW1iZXIpIHtcbiAgICAgICAgdGhpcy5fZXZlbnRFbWl0dGVyLmRpc3BhdGNoRXZlbnQoXG4gICAgICAgICAgICBuZXcgVmlkZW9FbmNvZGVyQXZnUVBFdmVudCh7IGF2Z1FQOiBRUCB9KVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCB1cCBmdW5jdGlvbmFsaXR5IHRvIGhhcHBlbiB3aGVuIHJlY2VpdmluZyBhbmQgaGFuZGxpbmcgaW5pdGlhbCBzZXR0aW5ncyBmb3IgdGhlIFVFIGFwcFxuICAgICAqIEBwYXJhbSBzZXR0aW5ncyAtIGluaXRpYWwgVUUgYXBwIHNldHRpbmdzXG4gICAgICovXG4gICAgX29uSW5pdGlhbFNldHRpbmdzKHNldHRpbmdzOiBJbml0aWFsU2V0dGluZ3MpIHtcbiAgICAgICAgdGhpcy5fZXZlbnRFbWl0dGVyLmRpc3BhdGNoRXZlbnQoXG4gICAgICAgICAgICBuZXcgSW5pdGlhbFNldHRpbmdzRXZlbnQoeyBzZXR0aW5ncyB9KVxuICAgICAgICApO1xuICAgICAgICBpZiAoc2V0dGluZ3MuUGl4ZWxTdHJlYW1pbmdTZXR0aW5ncykge1xuICAgICAgICAgICAgdGhpcy5hbGxvd0NvbnNvbGVDb21tYW5kcyA9XG4gICAgICAgICAgICAgICAgc2V0dGluZ3MuUGl4ZWxTdHJlYW1pbmdTZXR0aW5ncy5BbGxvd1BpeGVsU3RyZWFtaW5nQ29tbWFuZHMgPz8gZmFsc2U7XG4gICAgICAgICAgICBpZiAodGhpcy5hbGxvd0NvbnNvbGVDb21tYW5kcyA9PT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgICBMb2dnZXIuSW5mbyhcbiAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICAgICAgJy1BbGxvd1BpeGVsU3RyZWFtaW5nQ29tbWFuZHM9ZmFsc2UsIHNlbmRpbmcgYXJiaXRyYXJ5IGNvbnNvbGUgY29tbWFuZHMgZnJvbSBicm93c2VyIHRvIFVFIGlzIGRpc2FibGVkLidcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgdXNlVXJsUGFyYW1zID0gdGhpcy5jb25maWcudXNlVXJsUGFyYW1zO1xuICAgICAgICBjb25zdCB1cmxQYXJhbXMgPSBuZXcgVVJMU2VhcmNoUGFyYW1zKHdpbmRvdy5sb2NhdGlvbi5zZWFyY2gpO1xuICAgICAgICBpZiAoc2V0dGluZ3MuRW5jb2RlclNldHRpbmdzKSB7XG4gICAgICAgICAgICB0aGlzLmNvbmZpZy5zZXROdW1lcmljU2V0dGluZyhcbiAgICAgICAgICAgICAgICBOdW1lcmljUGFyYW1ldGVycy5NaW5RUCxcbiAgICAgICAgICAgICAgICAvLyBJZiBhIHNldHRpbmcgaXMgc2V0IGluIHRoZSBVUkwsIG1ha2Ugc3VyZSB3ZSByZXNwZWN0IHRoYXQgdmFsdWUgYXMgb3Bwb3NlZCB0byB3aGF0IHRoZSBhcHBsaWNhdGlvbiBzZW5kcyB1c1xuICAgICAgICAgICAgICAgICh1c2VVcmxQYXJhbXMgJiYgdXJsUGFyYW1zLmhhcyhOdW1lcmljUGFyYW1ldGVycy5NaW5RUCkpIFxuICAgICAgICAgICAgICAgICAgICA/IE51bWJlci5wYXJzZUludCh1cmxQYXJhbXMuZ2V0KE51bWVyaWNQYXJhbWV0ZXJzLk1pblFQKSkgXG4gICAgICAgICAgICAgICAgICAgIDogc2V0dGluZ3MuRW5jb2RlclNldHRpbmdzLk1pblFQXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBcbiAgICAgICAgICAgIHRoaXMuY29uZmlnLnNldE51bWVyaWNTZXR0aW5nKFxuICAgICAgICAgICAgICAgIE51bWVyaWNQYXJhbWV0ZXJzLk1heFFQLFxuICAgICAgICAgICAgICAgICh1c2VVcmxQYXJhbXMgJiYgdXJsUGFyYW1zLmhhcyhOdW1lcmljUGFyYW1ldGVycy5NYXhRUCkpIFxuICAgICAgICAgICAgICAgICAgICA/IE51bWJlci5wYXJzZUludCh1cmxQYXJhbXMuZ2V0KE51bWVyaWNQYXJhbWV0ZXJzLk1heFFQKSkgXG4gICAgICAgICAgICAgICAgICAgIDogc2V0dGluZ3MuRW5jb2RlclNldHRpbmdzLk1heFFQXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGlmIChzZXR0aW5ncy5XZWJSVENTZXR0aW5ncykge1xuICAgICAgICAgICAgdGhpcy5jb25maWcuc2V0TnVtZXJpY1NldHRpbmcoXG4gICAgICAgICAgICAgICAgTnVtZXJpY1BhcmFtZXRlcnMuV2ViUlRDTWluQml0cmF0ZSxcbiAgICAgICAgICAgICAgICAodXNlVXJsUGFyYW1zICYmIHVybFBhcmFtcy5oYXMoTnVtZXJpY1BhcmFtZXRlcnMuV2ViUlRDTWluQml0cmF0ZSkpIFxuICAgICAgICAgICAgICAgICAgICA/IE51bWJlci5wYXJzZUludCh1cmxQYXJhbXMuZ2V0KE51bWVyaWNQYXJhbWV0ZXJzLldlYlJUQ01pbkJpdHJhdGUpKVxuICAgICAgICAgICAgICAgICAgICA6IHNldHRpbmdzLldlYlJUQ1NldHRpbmdzLk1pbkJpdHJhdGUgLyAxMDAwIC8qIGJwcyB0byBrYnBzICovXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdGhpcy5jb25maWcuc2V0TnVtZXJpY1NldHRpbmcoXG4gICAgICAgICAgICAgICAgTnVtZXJpY1BhcmFtZXRlcnMuV2ViUlRDTWF4Qml0cmF0ZSxcbiAgICAgICAgICAgICAgICAodXNlVXJsUGFyYW1zICYmIHVybFBhcmFtcy5oYXMoTnVtZXJpY1BhcmFtZXRlcnMuV2ViUlRDTWF4Qml0cmF0ZSkpIFxuICAgICAgICAgICAgICAgICAgICA/IE51bWJlci5wYXJzZUludCh1cmxQYXJhbXMuZ2V0KE51bWVyaWNQYXJhbWV0ZXJzLldlYlJUQ01heEJpdHJhdGUpKVxuICAgICAgICAgICAgICAgICAgICA6IHNldHRpbmdzLldlYlJUQ1NldHRpbmdzLk1heEJpdHJhdGUgLyAxMDAwIC8qIGJwcyB0byBrYnBzICovXG4gICAgICAgICAgICAgICAgXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdGhpcy5jb25maWcuc2V0TnVtZXJpY1NldHRpbmcoXG4gICAgICAgICAgICAgICAgTnVtZXJpY1BhcmFtZXRlcnMuV2ViUlRDRlBTLFxuICAgICAgICAgICAgICAgICh1c2VVcmxQYXJhbXMgJiYgdXJsUGFyYW1zLmhhcyhOdW1lcmljUGFyYW1ldGVycy5XZWJSVENGUFMpKSBcbiAgICAgICAgICAgICAgICAgICAgPyBOdW1iZXIucGFyc2VJbnQodXJsUGFyYW1zLmdldChOdW1lcmljUGFyYW1ldGVycy5XZWJSVENGUFMpKVxuICAgICAgICAgICAgICAgICAgICA6IHNldHRpbmdzLldlYlJUQ1NldHRpbmdzLkZQU1xuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCB1cCBmdW5jdGlvbmFsaXR5IHRvIGhhcHBlbiB3aGVuIHNldHRpbmcgcXVhbGl0eSBjb250cm9sIG93bmVyc2hpcCBvZiBhIHN0cmVhbVxuICAgICAqIEBwYXJhbSBoYXNRdWFsaXR5T3duZXJzaGlwIC0gZG9lcyB0aGlzIHVzZXIgaGF2ZSBxdWFsaXR5IG93bmVyc2hpcCBvZiB0aGUgc3RyZWFtIHRydWUgLyBmYWxzZVxuICAgICAqL1xuICAgIF9vblF1YWxpdHlDb250cm9sT3duZXJzaGlwKGhhc1F1YWxpdHlPd25lcnNoaXA6IGJvb2xlYW4pIHtcbiAgICAgICAgdGhpcy5jb25maWcuc2V0RmxhZ0VuYWJsZWQoXG4gICAgICAgICAgICBGbGFncy5Jc1F1YWxpdHlDb250cm9sbGVyLFxuICAgICAgICAgICAgaGFzUXVhbGl0eU93bmVyc2hpcFxuICAgICAgICApO1xuICAgIH1cblxuICAgIF9vblBsYXllckNvdW50KHBsYXllckNvdW50OiBudW1iZXIpIHtcbiAgICAgICAgdGhpcy5fZXZlbnRFbWl0dGVyLmRpc3BhdGNoRXZlbnQoXG4gICAgICAgICAgICBuZXcgUGxheWVyQ291bnRFdmVudCh7IGNvdW50OiBwbGF5ZXJDb3VudCB9KVxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlcXVlc3QgYSBjb25uZWN0aW9uIGxhdGVuY3kgdGVzdC5cbiAgICAgKiBOT1RFOiBUaGVyZSBhcmUgcGxhbnMgdG8gcmVmYWN0b3IgYWxsIHJlcXVlc3QqIGZ1bmN0aW9ucy4gRXhwZWN0IGNoYW5nZXMgaWYgeW91IHVzZSB0aGlzIVxuICAgICAqIEByZXR1cm5zXG4gICAgICovXG4gICAgcHVibGljIHJlcXVlc3RMYXRlbmN5VGVzdCgpIHtcbiAgICAgICAgaWYgKCF0aGlzLl93ZWJSdGNDb250cm9sbGVyLnZpZGVvUGxheWVyLmlzVmlkZW9SZWFkeSgpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fd2ViUnRjQ29udHJvbGxlci5zZW5kTGF0ZW5jeVRlc3QoKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVxdWVzdCBhIGRhdGEgY2hhbm5lbCBsYXRlbmN5IHRlc3QuXG4gICAgICogTk9URTogVGhlcmUgYXJlIHBsYW5zIHRvIHJlZmFjdG9yIGFsbCByZXF1ZXN0KiBmdW5jdGlvbnMuIEV4cGVjdCBjaGFuZ2VzIGlmIHlvdSB1c2UgdGhpcyFcbiAgICAgKi9cbiAgICBwdWJsaWMgcmVxdWVzdERhdGFDaGFubmVsTGF0ZW5jeVRlc3QoY29uZmlnOiBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0Q29uZmlnKSB7XG4gICAgICAgIGlmICghdGhpcy5fd2ViUnRjQ29udHJvbGxlci52aWRlb1BsYXllci5pc1ZpZGVvUmVhZHkoKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGlmICghdGhpcy5fZGF0YUNoYW5uZWxMYXRlbmN5VGVzdENvbnRyb2xsZXIpIHtcbiAgICAgICAgICAgIHRoaXMuX2RhdGFDaGFubmVsTGF0ZW5jeVRlc3RDb250cm9sbGVyID0gbmV3IERhdGFDaGFubmVsTGF0ZW5jeVRlc3RDb250cm9sbGVyKFxuICAgICAgICAgICAgICAgIHRoaXMuX3dlYlJ0Y0NvbnRyb2xsZXIuc2VuZERhdGFDaGFubmVsTGF0ZW5jeVRlc3QuYmluZCh0aGlzLl93ZWJSdGNDb250cm9sbGVyKSxcbiAgICAgICAgICAgICAgICAocmVzdWx0OiBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVzdWx0KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2V2ZW50RW1pdHRlci5kaXNwYXRjaEV2ZW50KG5ldyBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVzdWx0RXZlbnQoIHsgcmVzdWx0IH0pKVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgdGhpcy5hZGRFdmVudExpc3RlbmVyKFxuICAgICAgICAgICAgICAgIFwiZGF0YUNoYW5uZWxMYXRlbmN5VGVzdFJlc3BvbnNlXCIsXG4gICAgICAgICAgICAgICAgKHtkYXRhOiB7cmVzcG9uc2V9IH0pID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fZGF0YUNoYW5uZWxMYXRlbmN5VGVzdENvbnRyb2xsZXIucmVjZWl2ZShyZXNwb25zZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLl9kYXRhQ2hhbm5lbExhdGVuY3lUZXN0Q29udHJvbGxlci5zdGFydChjb25maWcpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlcXVlc3QgZm9yIHRoZSBVRSBhcHBsaWNhdGlvbiB0byBzaG93IEZQUyBjb3VudGVyLlxuICAgICAqIE5PVEU6IFRoZXJlIGFyZSBwbGFucyB0byByZWZhY3RvciBhbGwgcmVxdWVzdCogZnVuY3Rpb25zLiBFeHBlY3QgY2hhbmdlcyBpZiB5b3UgdXNlIHRoaXMhXG4gICAgICogQHJldHVybnNcbiAgICAgKi9cbiAgICBwdWJsaWMgcmVxdWVzdFNob3dGcHMoKSB7XG4gICAgICAgIGlmICghdGhpcy5fd2ViUnRjQ29udHJvbGxlci52aWRlb1BsYXllci5pc1ZpZGVvUmVhZHkoKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuX3dlYlJ0Y0NvbnRyb2xsZXIuc2VuZFNob3dGcHMoKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVxdWVzdCBmb3IgYSBuZXcgSUZyYW1lIGZyb20gdGhlIFVFIGFwcGxpY2F0aW9uLlxuICAgICAqIE5PVEU6IFRoZXJlIGFyZSBwbGFucyB0byByZWZhY3RvciBhbGwgcmVxdWVzdCogZnVuY3Rpb25zLiBFeHBlY3QgY2hhbmdlcyBpZiB5b3UgdXNlIHRoaXMhXG4gICAgICogQHJldHVybnNcbiAgICAgKi9cbiAgICBwdWJsaWMgcmVxdWVzdElmcmFtZSgpIHtcbiAgICAgICAgaWYgKCF0aGlzLl93ZWJSdGNDb250cm9sbGVyLnZpZGVvUGxheWVyLmlzVmlkZW9SZWFkeSgpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fd2ViUnRjQ29udHJvbGxlci5zZW5kSWZyYW1lUmVxdWVzdCgpO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZW5kIGRhdGEgdG8gVUUgYXBwbGljYXRpb24uIFRoZSBkYXRhIHdpbGwgYmUgcnVuIHRocm91Z2ggSlNPTi5zdHJpbmdpZnkoKSBzbyBlLmcuIHN0cmluZ3NcbiAgICAgKiBhbmQgYW55IHNlcmlhbGl6YWJsZSBwbGFpbiBKU09OIG9iamVjdHMgd2l0aCBubyByZWN1cnJlbmNlIGNhbiBiZSBzZW50LlxuICAgICAqIEByZXR1cm5zIHRydWUgaWYgc3VjY2VlZGVkLCBmYWxzZSBpZiByZWplY3RlZFxuICAgICAqL1xuICAgIHB1YmxpYyBlbWl0VUlJbnRlcmFjdGlvbihkZXNjcmlwdG9yOiBvYmplY3QgfCBzdHJpbmcpIHtcbiAgICAgICAgaWYgKCF0aGlzLl93ZWJSdGNDb250cm9sbGVyLnZpZGVvUGxheWVyLmlzVmlkZW9SZWFkeSgpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fd2ViUnRjQ29udHJvbGxlci5lbWl0VUlJbnRlcmFjdGlvbihkZXNjcmlwdG9yKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2VuZCBhIGNvbW1hbmQgdG8gVUUgYXBwbGljYXRpb24uIEJsb2NrcyBDb25zb2xlQ29tbWFuZCBkZXNjcmlwdG9ycyB1bmxlc3MgVUVcbiAgICAgKiBoYXMgc2lnbmFsZWQgdGhhdCBpdCBhbGxvd3MgY29uc29sZSBjb21tYW5kcy5cbiAgICAgKiBAcmV0dXJucyB0cnVlIGlmIHN1Y2NlZWRlZCwgZmFsc2UgaWYgcmVqZWN0ZWRcbiAgICAgKi9cbiAgICBwdWJsaWMgZW1pdENvbW1hbmQoZGVzY3JpcHRvcjogb2JqZWN0KSB7XG4gICAgICAgIGlmICghdGhpcy5fd2ViUnRjQ29udHJvbGxlci52aWRlb1BsYXllci5pc1ZpZGVvUmVhZHkoKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGlmICghdGhpcy5hbGxvd0NvbnNvbGVDb21tYW5kcyAmJiAnQ29uc29sZUNvbW1hbmQnIGluIGRlc2NyaXB0b3IpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLl93ZWJSdGNDb250cm9sbGVyLmVtaXRDb21tYW5kKGRlc2NyaXB0b3IpO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZW5kIGEgY29uc29sZSBjb21tYW5kIHRvIFVFIGFwcGxpY2F0aW9uLiBPbmx5IGFsbG93ZWQgaWYgVUUgaGFzIHNpZ25hbGVkIHRoYXQgaXQgYWxsb3dzXG4gICAgICogY29uc29sZSBjb21tYW5kcy5cbiAgICAgKiBAcmV0dXJucyB0cnVlIGlmIHN1Y2NlZWRlZCwgZmFsc2UgaWYgcmVqZWN0ZWRcbiAgICAgKi9cbiAgICBwdWJsaWMgZW1pdENvbnNvbGVDb21tYW5kKGNvbW1hbmQ6IHN0cmluZykge1xuICAgICAgICBpZiAoIXRoaXMuYWxsb3dDb25zb2xlQ29tbWFuZHMgfHwgIXRoaXMuX3dlYlJ0Y0NvbnRyb2xsZXIudmlkZW9QbGF5ZXIuaXNWaWRlb1JlYWR5KCkpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLl93ZWJSdGNDb250cm9sbGVyLmVtaXRDb25zb2xlQ29tbWFuZChjb21tYW5kKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQWRkIGEgVUUgLT4gYnJvd3NlciByZXNwb25zZSBldmVudCBsaXN0ZW5lclxuICAgICAqIEBwYXJhbSBuYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHJlc3BvbnNlIGhhbmRsZXJcbiAgICAgKiBAcGFyYW0gbGlzdGVuZXIgLSBUaGUgbWV0aG9kIHRvIGJlIGFjdGl2YXRlZCB3aGVuIGEgbWVzc2FnZSBpcyByZWNlaXZlZFxuICAgICAqL1xuICAgIHB1YmxpYyBhZGRSZXNwb25zZUV2ZW50TGlzdGVuZXIoXG4gICAgICAgIG5hbWU6IHN0cmluZyxcbiAgICAgICAgbGlzdGVuZXI6IChyZXNwb25zZTogc3RyaW5nKSA9PiB2b2lkXG4gICAgKSB7XG4gICAgICAgIHRoaXMuX3dlYlJ0Y0NvbnRyb2xsZXIucmVzcG9uc2VDb250cm9sbGVyLmFkZFJlc3BvbnNlRXZlbnRMaXN0ZW5lcihuYW1lLCBsaXN0ZW5lcik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlIGEgVUUgLT4gYnJvd3NlciByZXNwb25zZSBldmVudCBsaXN0ZW5lclxuICAgICAqIEBwYXJhbSBuYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHJlc3BvbnNlIGhhbmRsZXJcbiAgICAgKi9cbiAgICBwdWJsaWMgcmVtb3ZlUmVzcG9uc2VFdmVudExpc3RlbmVyKG5hbWU6IHN0cmluZykge1xuICAgICAgICB0aGlzLl93ZWJSdGNDb250cm9sbGVyLnJlc3BvbnNlQ29udHJvbGxlci5yZW1vdmVSZXNwb25zZUV2ZW50TGlzdGVuZXIobmFtZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRGlzcGF0Y2ggYSBuZXcgZXZlbnQuXG4gICAgICogQHBhcmFtIGUgZXZlbnRcbiAgICAgKiBAcmV0dXJuc1xuICAgICAqL1xuICAgIHB1YmxpYyBkaXNwYXRjaEV2ZW50KGU6IFBpeGVsU3RyZWFtaW5nRXZlbnQpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX2V2ZW50RW1pdHRlci5kaXNwYXRjaEV2ZW50KGUpO1xuICAgIH1cbiAgICBcbiAgICAvKipcbiAgICAgKiBSZWdpc3RlciBhbiBldmVudCBoYW5kbGVyLlxuICAgICAqIEBwYXJhbSB0eXBlIGV2ZW50IG5hbWVcbiAgICAgKiBAcGFyYW0gbGlzdGVuZXIgZXZlbnQgaGFuZGxlciBmdW5jdGlvblxuICAgICAqL1xuICAgIHB1YmxpYyBhZGRFdmVudExpc3RlbmVyPFxuICAgICAgICBUIGV4dGVuZHMgUGl4ZWxTdHJlYW1pbmdFdmVudFsndHlwZSddLFxuICAgICAgICBFIGV4dGVuZHMgUGl4ZWxTdHJlYW1pbmdFdmVudCAmIHsgdHlwZTogVCB9XG4gICAgPih0eXBlOiBULCBsaXN0ZW5lcjogKGU6IEV2ZW50ICYgRSkgPT4gdm9pZCkge1xuICAgICAgICB0aGlzLl9ldmVudEVtaXR0ZXIuYWRkRXZlbnRMaXN0ZW5lcih0eXBlLCBsaXN0ZW5lcik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlIGFuIGV2ZW50IGhhbmRsZXIuXG4gICAgICogQHBhcmFtIHR5cGUgZXZlbnQgbmFtZVxuICAgICAqIEBwYXJhbSBsaXN0ZW5lciBldmVudCBoYW5kbGVyIGZ1bmN0aW9uXG4gICAgICovXG4gICAgcHVibGljIHJlbW92ZUV2ZW50TGlzdGVuZXI8XG4gICAgICAgIFQgZXh0ZW5kcyBQaXhlbFN0cmVhbWluZ0V2ZW50Wyd0eXBlJ10sXG4gICAgICAgIEUgZXh0ZW5kcyBQaXhlbFN0cmVhbWluZ0V2ZW50ICYgeyB0eXBlOiBUIH1cbiAgICA+KHR5cGU6IFQsIGxpc3RlbmVyOiAoZTogRXZlbnQgJiBFKSA9PiB2b2lkKSB7XG4gICAgICAgIHRoaXMuX2V2ZW50RW1pdHRlci5yZW1vdmVFdmVudExpc3RlbmVyKHR5cGUsIGxpc3RlbmVyKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBFbmFibGUvZGlzYWJsZSBYUiBtb2RlLlxuICAgICAqL1xuICAgIHB1YmxpYyB0b2dnbGVYUigpIHtcbiAgICAgICAgdGhpcy53ZWJYckNvbnRyb2xsZXIueHJDbGlja2VkKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUGFzcyBpbiBhIGZ1bmN0aW9uIHRvIGdlbmVyYXRlIGEgc2lnbmFsbGluZyBzZXJ2ZXIgVVJMLlxuICAgICAqIFRoaXMgZnVuY3Rpb24gaXMgdXNlZnVsIGlmIHlvdSBuZWVkIHRvIHByb2dyYW1tYXRpY2FsbHkgY29uc3RydWN0IHlvdXIgc2lnbmFsbGluZyBzZXJ2ZXIgVVJMLlxuICAgICAqIEBwYXJhbSBzaWduYWxsaW5nVXJsQnVpbGRlckZ1bmMgQSBmdW5jdGlvbiB0aGF0IGdlbmVyYXRlcyBhIHNpZ25hbGxpbmcgc2VydmVyIHVybC5cbiAgICAgKi9cbiAgICBwdWJsaWMgc2V0U2lnbmFsbGluZ1VybEJ1aWxkZXIoc2lnbmFsbGluZ1VybEJ1aWxkZXJGdW5jOiAoKT0+c3RyaW5nKSB7XG4gICAgICAgIHRoaXMuX3dlYlJ0Y0NvbnRyb2xsZXIuc2lnbmFsbGluZ1VybEJ1aWxkZXIgPSBzaWduYWxsaW5nVXJsQnVpbGRlckZ1bmM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUHVibGljIGdldHRlciBmb3IgdGhlIHdlYnNvY2tldCBjb250cm9sbGVyLiBBY2Nlc3MgdG8gdGhpcyBwcm9wZXJ0eSBhbGxvd3MgeW91IHRvIHNlbmRcbiAgICAgKiBjdXN0b20gd2Vic29ja2V0IG1lc3NhZ2VzLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgd2ViU29ja2V0Q29udHJvbGxlcigpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3dlYlJ0Y0NvbnRyb2xsZXIud2ViU29ja2V0Q29udHJvbGxlcjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQdWJsaWMgZ2V0dGVyIGZvciB0aGUgd2ViWHJDb250cm9sbGVyIGNvbnRyb2xsZXIuIFVzZWQgZm9yIGFsbCBYUiBmZWF0dXJlcy5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0IHdlYlhyQ29udHJvbGxlcigpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3dlYlhyQ29udHJvbGxlcjtcbiAgICB9XG5cbiAgICBwdWJsaWMgcmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihuYW1lOiBzdHJpbmcsIGRpcmVjdGlvbjogTWVzc2FnZURpcmVjdGlvbiwgaGFuZGxlcj86IChkYXRhOiBBcnJheUJ1ZmZlciB8IEFycmF5PG51bWJlciB8IHN0cmluZz4pID0+IHZvaWQpIHtcbiAgICAgICAgaWYoZGlyZWN0aW9uID09PSBNZXNzYWdlRGlyZWN0aW9uLkZyb21TdHJlYW1lciAmJiB0eXBlb2YgaGFuZGxlciA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgIExvZ2dlci5XYXJuaW5nKExvZ2dlci5HZXRTdGFja1RyYWNlKCksIGBVbmFibGUgdG8gcmVnaXN0ZXIgYW4gdW5kZWZpbmVkIGhhbmRsZXIgZm9yICR7bmFtZX1gKVxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYoZGlyZWN0aW9uID09PSBNZXNzYWdlRGlyZWN0aW9uLlRvU3RyZWFtZXIgJiYgdHlwZW9mIGhhbmRsZXIgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICB0aGlzLl93ZWJSdGNDb250cm9sbGVyLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICAgICAgZGlyZWN0aW9uLFxuICAgICAgICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgICAgICAgKGRhdGE6IEFycmF5PG51bWJlciB8IHN0cmluZz4pID0+XG4gICAgICAgICAgICAgICAgdGhpcy5fd2ViUnRjQ29udHJvbGxlci5zZW5kTWVzc2FnZUNvbnRyb2xsZXIuc2VuZE1lc3NhZ2VUb1N0cmVhbWVyKFxuICAgICAgICAgICAgICAgICAgICBuYW1lLFxuICAgICAgICAgICAgICAgICAgICBkYXRhXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuX3dlYlJ0Y0NvbnRyb2xsZXIuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgICAgICBkaXJlY3Rpb24sXG4gICAgICAgICAgICAgICAgbmFtZSxcbiAgICAgICAgICAgICAgICAoZGF0YTogQXJyYXlCdWZmZXIpID0+IGhhbmRsZXIoZGF0YSlcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IHRvU3RyZWFtZXJIYW5kbGVycygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3dlYlJ0Y0NvbnRyb2xsZXIuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIudG9TdHJlYW1lckhhbmRsZXJzO1xuICAgIH1cblxuICAgIHB1YmxpYyBpc1JlY29ubmVjdGluZygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3dlYlJ0Y0NvbnRyb2xsZXIuaXNSZWNvbm5lY3Rpbmc7XG4gICAgfVxufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuaW1wb3J0IHsgVW5xdWFudGl6ZWREZW5vcm1hbGl6ZWRVbnNpZ25lZENvb3JkIH0gZnJvbSAnLi4vVXRpbC9Db29yZGluYXRlQ29udmVydGVyJztcbmltcG9ydCB7IE1lc3NhZ2VPblNjcmVlbktleWJvYXJkIH0gZnJvbSAnLi4vV2ViU29ja2V0cy9NZXNzYWdlUmVjZWl2ZSc7XG5cbi8qKlxuICogQ2xhc3MgZm9yIGhhbmRsaW5nIG9uIHNjcmVlbiBrZXlib2FyZCB1c2FnZVxuICovXG5leHBvcnQgY2xhc3MgT25TY3JlZW5LZXlib2FyZCB7XG4gICAgLy8gSWYgdGhlIHVzZXIgZm9jdXNlcyBvbiBhIFVFIGlucHV0IHdpZGdldCB0aGVuIHdlIHNob3cgdGhlbSBhIGJ1dHRvbiB0byBvcGVuXG4gICAgLy8gdGhlIG9uLXNjcmVlbiBrZXlib2FyZC4gSmF2YVNjcmlwdCBzZWN1cml0eSBtZWFucyB3ZSBjYW4gb25seSBzaG93IHRoZVxuICAgIC8vIG9uLXNjcmVlbiBrZXlib2FyZCBpbiByZXNwb25zZSB0byBhIHVzZXIgaW50ZXJhY3Rpb24uXG4gICAgZWRpdFRleHRCdXR0b246IEhUTUxCdXR0b25FbGVtZW50O1xuXG4gICAgLy8gQSBoaWRkZW4gaW5wdXQgdGV4dCBib3ggd2hpY2ggaXMgdXNlZCBvbmx5IGZvciBmb2N1c2luZyBhbmQgb3BlbmluZyB0aGVcbiAgICAvLyBvbi1zY3JlZW4ga2V5Ym9hcmQuXG4gICAgaGlkZGVuSW5wdXQ6IEhUTUxJbnB1dEVsZW1lbnQ7XG5cbiAgICAvKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB2aWRlb0VsZW1lbnRQYXJlbnQgVGhlIGRpdiBlbGVtZW50IHRoZSB2aWRlbyBwbGF5ZXIgaXMgaW5qZWN0ZWQgaW50b1xuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKHZpZGVvRWxlbWVudFBhcmVudDogSFRNTEVsZW1lbnQpIHtcbiAgICAgICAgdGhpcy5lZGl0VGV4dEJ1dHRvbiA9IG51bGw7XG4gICAgICAgIHRoaXMuaGlkZGVuSW5wdXQgPSBudWxsO1xuXG4gICAgICAgIGlmICgnb250b3VjaHN0YXJ0JyBpbiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQpIHtcbiAgICAgICAgICAgIHRoaXMuY3JlYXRlT25TY3JlZW5LZXlib2FyZEhlbHBlcnModmlkZW9FbGVtZW50UGFyZW50KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFuIG92ZXJyaWRlIGZvciB1bnF1YW50aXplQW5kRGVub3JtYWxpemVVbnNpZ25lZFxuICAgICAqIEBwYXJhbSB4IHRoZSB4IGF4aXMgcG9pbnRcbiAgICAgKiBAcGFyYW0geSB0aGUgeSBheGlzIHBvaW50XG4gICAgICogQHJldHVybnMgdW5xdWFudGl6ZUFuZERlbm9ybWFsaXplVW5zaWduZWQgb2JqZWN0XG4gICAgICovXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICAgIHVucXVhbnRpemVBbmREZW5vcm1hbGl6ZVVuc2lnbmVkKFxuICAgICAgICB4OiBudW1iZXIsXG4gICAgICAgIHk6IG51bWJlclxuICAgICk6IFVucXVhbnRpemVkRGVub3JtYWxpemVkVW5zaWduZWRDb29yZCB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgb24gc2NyZWVuIGtleWJvYXJkIGhlbHBlcnNcbiAgICAgKiBAcGFyYW0gdmlkZW9FbGVtZW50UGFyZW50IFRoZSBkaXYgZWxlbWVudCB0aGUgdmlkZW8gcGxheWVyIGkgaW5qZWN0ZWQgaW50b1xuICAgICAqL1xuICAgIGNyZWF0ZU9uU2NyZWVuS2V5Ym9hcmRIZWxwZXJzKHZpZGVvRWxlbWVudFBhcmVudDogSFRNTEVsZW1lbnQpIHtcbiAgICAgICAgaWYgKCF0aGlzLmhpZGRlbklucHV0KSB7XG4gICAgICAgICAgICB0aGlzLmhpZGRlbklucHV0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaW5wdXQnKTtcbiAgICAgICAgICAgIHRoaXMuaGlkZGVuSW5wdXQuaWQgPSAnaGlkZGVuSW5wdXQnO1xuICAgICAgICAgICAgdGhpcy5oaWRkZW5JbnB1dC5tYXhMZW5ndGggPSAwO1xuICAgICAgICAgICAgdmlkZW9FbGVtZW50UGFyZW50LmFwcGVuZENoaWxkKHRoaXMuaGlkZGVuSW5wdXQpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCF0aGlzLmVkaXRUZXh0QnV0dG9uKSB7XG4gICAgICAgICAgICB0aGlzLmVkaXRUZXh0QnV0dG9uID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYnV0dG9uJyk7XG4gICAgICAgICAgICB0aGlzLmVkaXRUZXh0QnV0dG9uLmlkID0gJ2VkaXRUZXh0QnV0dG9uJztcbiAgICAgICAgICAgIHRoaXMuZWRpdFRleHRCdXR0b24uaW5uZXJIVE1MID0gJ2VkaXQgdGV4dCc7XG4gICAgICAgICAgICB2aWRlb0VsZW1lbnRQYXJlbnQuYXBwZW5kQ2hpbGQodGhpcy5lZGl0VGV4dEJ1dHRvbik7XG5cbiAgICAgICAgICAgIC8vIEhpZGUgdGhlICdlZGl0IHRleHQnIGJ1dHRvbi5cbiAgICAgICAgICAgIHRoaXMuZWRpdFRleHRCdXR0b24uY2xhc3NMaXN0LmFkZCgnaGlkZGVuU3RhdGUnKTtcblxuICAgICAgICAgICAgdGhpcy5lZGl0VGV4dEJ1dHRvbi5hZGRFdmVudExpc3RlbmVyKCd0b3VjaGVuZCcsIChldmVudDogRXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICAvLyBTaG93IHRoZSBvbi1zY3JlZW4ga2V5Ym9hcmQuXG4gICAgICAgICAgICAgICAgdGhpcy5oaWRkZW5JbnB1dC5mb2N1cygpO1xuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNob3dzIHRoZSBvbiBzY3JlZW4ga2V5Ym9hcmRcbiAgICAgKiBAcGFyYW0gY29tbWFuZCB0aGUgY29tbWFuZCByZWNlaXZlZCB2aWEgdGhlIGRhdGEgY2hhbm5lbCBjb250YWluaW5nIGtleWJvYXJkIHBvc2l0aW9uc1xuICAgICAqL1xuICAgIHNob3dPblNjcmVlbktleWJvYXJkKGNvbW1hbmQ6IE1lc3NhZ2VPblNjcmVlbktleWJvYXJkKSB7XG4gICAgICAgIGlmIChjb21tYW5kLnNob3dPblNjcmVlbktleWJvYXJkKSB7XG4gICAgICAgICAgICAvLyBTaG93IHRoZSAnZWRpdCB0ZXh0JyBidXR0b24uXG4gICAgICAgICAgICB0aGlzLmVkaXRUZXh0QnV0dG9uLmNsYXNzTGlzdC5yZW1vdmUoJ2hpZGRlblN0YXRlJyk7XG4gICAgICAgICAgICAvLyBQbGFjZSB0aGUgJ2VkaXQgdGV4dCcgYnV0dG9uIG5lYXIgdGhlIFVFIGlucHV0IHdpZGdldC5cbiAgICAgICAgICAgIGNvbnN0IHBvcyA9IHRoaXMudW5xdWFudGl6ZUFuZERlbm9ybWFsaXplVW5zaWduZWQoXG4gICAgICAgICAgICAgICAgY29tbWFuZC54LFxuICAgICAgICAgICAgICAgIGNvbW1hbmQueVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHRoaXMuZWRpdFRleHRCdXR0b24uc3R5bGUudG9wID0gcG9zLnkudG9TdHJpbmcoKSArICdweCc7XG4gICAgICAgICAgICB0aGlzLmVkaXRUZXh0QnV0dG9uLnN0eWxlLmxlZnQgPSAocG9zLnggLSA0MCkudG9TdHJpbmcoKSArICdweCc7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBIaWRlIHRoZSAnZWRpdCB0ZXh0JyBidXR0b24uXG4gICAgICAgICAgICB0aGlzLmVkaXRUZXh0QnV0dG9uLmNsYXNzTGlzdC5hZGQoJ2hpZGRlblN0YXRlJyk7XG4gICAgICAgICAgICAvLyBIaWRlIHRoZSBvbi1zY3JlZW4ga2V5Ym9hcmQuXG4gICAgICAgICAgICB0aGlzLmhpZGRlbklucHV0LmJsdXIoKTtcbiAgICAgICAgfVxuICAgIH1cbn1cbiIsIi8vIENvcHlyaWdodCBFcGljIEdhbWVzLCBJbmMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG5cbmltcG9ydCB7IExvZ2dlciB9IGZyb20gJy4uL0xvZ2dlci9Mb2dnZXInO1xuXG5leHBvcnQgY2xhc3MgUmVzcG9uc2VDb250cm9sbGVyIHtcbiAgICByZXNwb25zZUV2ZW50TGlzdGVuZXJzOiBNYXA8c3RyaW5nLCAocmVzcG9uc2U6IHN0cmluZykgPT4gdm9pZD4gPSBuZXcgTWFwKCk7XG5cbiAgICAvKipcbiAgICAgKiBBZGQgYSByZXNwb25zZSBldmVudCBsaXN0ZW5lciB0byB0aGUgcmVzcG9uc2UgbWFwXG4gICAgICogQHBhcmFtIG5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgcmVzcG9uc2VcbiAgICAgKiBAcGFyYW0gbGlzdGVuZXIgLSBUaGUgbWV0aG9kIHRvIGJlIGFjdGl2YXRlZCB3aGVuIHRoZSByZXNwb25zZSBpcyBzZWxlY3RlZFxuICAgICAqL1xuICAgIGFkZFJlc3BvbnNlRXZlbnRMaXN0ZW5lcihcbiAgICAgICAgbmFtZTogc3RyaW5nLFxuICAgICAgICBsaXN0ZW5lcjogKHJlc3BvbnNlOiBzdHJpbmcpID0+IHZvaWRcbiAgICApIHtcbiAgICAgICAgdGhpcy5yZXNwb25zZUV2ZW50TGlzdGVuZXJzLnNldChuYW1lLCBsaXN0ZW5lcik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlIGEgcmVzcG9uc2UgZXZlbnQgbGlzdGVuZXIgdG8gdGhlIHJlc3BvbnNlIG1hcFxuICAgICAqIEBwYXJhbSBuYW1lIC0gVGhlIG5hbWUgb2YgdGhlIHJlc3BvbnNlXG4gICAgICovXG4gICAgcmVtb3ZlUmVzcG9uc2VFdmVudExpc3RlbmVyKG5hbWU6IHN0cmluZykge1xuICAgICAgICB0aGlzLnJlc3BvbnNlRXZlbnRMaXN0ZW5lcnMuZGVsZXRlKG5hbWUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEhhbmRsZSBhIHJlc3BvbnNlIHdoZW4gcmVjZWl2aW5nIG9uZSBmb3JtIHRoZSBzdHJlYW1lclxuICAgICAqIEBwYXJhbSBtZXNzYWdlIC0gRGF0YSByZWNlaXZlZCBmcm9tIHRoZSBkYXRhIGNoYW5uZWwgd2l0aCB0aGUgY29tbWFuZCBpbiBxdWVzdGlvblxuICAgICAqL1xuICAgIG9uUmVzcG9uc2UobWVzc2FnZTogQXJyYXlCdWZmZXIpIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAnRGF0YUNoYW5uZWxSZWNlaXZlTWVzc2FnZVR5cGUuUmVzcG9uc2UnLFxuICAgICAgICAgICAgNlxuICAgICAgICApO1xuICAgICAgICBjb25zdCByZXNwb25zZXMgPSBuZXcgVGV4dERlY29kZXIoJ3V0Zi0xNicpLmRlY29kZShtZXNzYWdlLnNsaWNlKDEpKTtcblxuICAgICAgICBMb2dnZXIuTG9nKExvZ2dlci5HZXRTdGFja1RyYWNlKCksIHJlc3BvbnNlcywgNik7XG4gICAgICAgIHRoaXMucmVzcG9uc2VFdmVudExpc3RlbmVycy5mb3JFYWNoKFxuICAgICAgICAgICAgKGxpc3RlbmVyOiAocmVzcG9uc2U6IHN0cmluZykgPT4gdm9pZCkgPT4ge1xuICAgICAgICAgICAgICAgIGxpc3RlbmVyKHJlc3BvbnNlcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgfVxufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuaW1wb3J0IHsgRGF0YUNoYW5uZWxTZW5kZXIgfSBmcm9tICcuLi9EYXRhQ2hhbm5lbC9EYXRhQ2hhbm5lbFNlbmRlcic7XG5pbXBvcnQgeyBMb2dnZXIgfSBmcm9tICcuLi9Mb2dnZXIvTG9nZ2VyJztcbmltcG9ydCB7IFN0cmVhbU1lc3NhZ2VDb250cm9sbGVyIH0gZnJvbSAnLi9TdHJlYW1NZXNzYWdlQ29udHJvbGxlcic7XG5cbmV4cG9ydCBjbGFzcyBTZW5kTWVzc2FnZUNvbnRyb2xsZXIge1xuICAgIHRvU3RyZWFtZXJNZXNzYWdlc01hcFByb3ZpZGVyOiBTdHJlYW1NZXNzYWdlQ29udHJvbGxlcjtcbiAgICBkYXRhQ2hhbm5lbFNlbmRlcjogRGF0YUNoYW5uZWxTZW5kZXI7XG5cbiAgICAvKipcbiAgICAgKiBAcGFyYW0gZGF0YUNoYW5uZWxTZW5kZXIgLSBEYXRhIGNoYW5uZWwgaW5zdGFuY2VcbiAgICAgKiBAcGFyYW0gdG9TdHJlYW1lck1lc3NhZ2VzTWFwUHJvdmlkZXIgLSBTdHJlYW0gTWVzc2FnZXMgaW5zdGFuY2VcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgZGF0YUNoYW5uZWxTZW5kZXI6IERhdGFDaGFubmVsU2VuZGVyLFxuICAgICAgICB0b1N0cmVhbWVyTWVzc2FnZXNNYXBQcm92aWRlcjogU3RyZWFtTWVzc2FnZUNvbnRyb2xsZXJcbiAgICApIHtcbiAgICAgICAgdGhpcy5kYXRhQ2hhbm5lbFNlbmRlciA9IGRhdGFDaGFubmVsU2VuZGVyO1xuICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlc01hcFByb3ZpZGVyID0gdG9TdHJlYW1lck1lc3NhZ2VzTWFwUHJvdmlkZXI7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2VuZCBhIG1lc3NhZ2UgdG8gdGhlIHN0cmVhbWVyIHRocm91Z2ggdGhlIGRhdGEgY2hhbm5lbFxuICAgICAqIEBwYXJhbSBtZXNzYWdlVHlwZSAtIHRoZSB0eXBlIG9mIG1lc3NhZ2Ugd2UgYXJlIHNlbmRpbmdcbiAgICAgKiBAcGFyYW0gbWVzc2FnZURhdGEgLSB0aGUgbWVzc2FnZSBkYXRhIHdlIGFyZSBzZW5kaW5nIG92ZXIgdGhlIGRhdGEgY2hhbm5lbFxuICAgICAqIEByZXR1cm5zIC0gbmlsXG4gICAgICovXG4gICAgc2VuZE1lc3NhZ2VUb1N0cmVhbWVyKG1lc3NhZ2VUeXBlOiBzdHJpbmcsIG1lc3NhZ2VEYXRhPzogQXJyYXk8bnVtYmVyIHwgc3RyaW5nPikge1xuICAgICAgICBpZiAobWVzc2FnZURhdGEgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgbWVzc2FnZURhdGEgPSBbXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHRvU3RyZWFtZXJNZXNzYWdlcyA9XG4gICAgICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlc01hcFByb3ZpZGVyLnRvU3RyZWFtZXJNZXNzYWdlcztcbiAgICAgICAgY29uc3QgbWVzc2FnZUZvcm1hdCA9IHRvU3RyZWFtZXJNZXNzYWdlcy5nZXQobWVzc2FnZVR5cGUpO1xuICAgICAgICBpZiAobWVzc2FnZUZvcm1hdCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBMb2dnZXIuRXJyb3IoXG4gICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICBgQXR0ZW1wdGVkIHRvIHNlbmQgYSBtZXNzYWdlIHRvIHRoZSBzdHJlYW1lciB3aXRoIG1lc3NhZ2UgdHlwZTogJHttZXNzYWdlVHlwZX0sIGJ1dCB0aGUgZnJvbnRlbmQgaGFzbid0IGJlZW4gY29uZmlndXJlZCB0byBzZW5kIHN1Y2ggYSBtZXNzYWdlLiBDaGVjayB5b3UndmUgYWRkZWQgdGhlIG1lc3NhZ2UgdHlwZSBpbiB5b3VyIGNwcGBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZihtZXNzYWdlRm9ybWF0LnN0cnVjdHVyZSAmJiBtZXNzYWdlRGF0YSAmJiBtZXNzYWdlRm9ybWF0LnN0cnVjdHVyZS5sZW5ndGggIT09IG1lc3NhZ2VEYXRhLmxlbmd0aCkge1xuICAgICAgICAgICAgTG9nZ2VyLkVycm9yKFxuICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgYFByb3ZpZGVkIG1lc3NhZ2UgZGF0YSBkb2Vzbid0IG1hdGNoIGV4cGVjdGVkIGxheW91dC4gRXhwZWN0ZWQgWyAke21lc3NhZ2VGb3JtYXQuc3RydWN0dXJlLm1hcCgoZWxlbWVudDogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHN3aXRjaCAoZWxlbWVudCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAndWludDgnOlxuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAndWludDE2JzpcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ2ludDE2JzpcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ2Zsb2F0JzpcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ2RvdWJsZSc6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuICdudW1iZXInO1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAnc3RyaW5nJzpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gJ3N0cmluZyc7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KS50b1N0cmluZygpIH0gXSBidXQgcmVjZWl2ZWQgWyAke21lc3NhZ2VEYXRhLm1hcCgoZWxlbWVudDogbnVtYmVyIHwgc3RyaW5nKSA9PiB0eXBlb2YgZWxlbWVudCkudG9TdHJpbmcoKX0gXWBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgYnl0ZUxlbmd0aCA9IDA7XG4gICAgICAgIGNvbnN0IHRleHRFbmNvZGVyID0gbmV3IFRleHRFbmNvZGVyKCk7XG4gICAgICAgIC8vIE9uZSBsb29wIHRvIGNhbGN1bGF0ZSB0aGUgbGVuZ3RoIGluIGJ5dGVzIG9mIGFsbCBvZiB0aGUgcHJvdmlkZWQgZGF0YVxuICAgICAgICBtZXNzYWdlRGF0YS5mb3JFYWNoKChlbGVtZW50OiBudW1iZXIgfCBzdHJpbmcsIGlkeDogbnVtYmVyKSA9PiB7XG4gICAgICAgICAgICBjb25zdCB0eXBlID0gbWVzc2FnZUZvcm1hdC5zdHJ1Y3R1cmVbaWR4XTtcbiAgICAgICAgICAgIHN3aXRjaCAodHlwZSkge1xuICAgICAgICAgICAgICAgIGNhc2UgJ3VpbnQ4JzpcbiAgICAgICAgICAgICAgICAgICAgYnl0ZUxlbmd0aCArPSAxO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgICAgIGNhc2UgJ3VpbnQxNic6XG4gICAgICAgICAgICAgICAgICAgIGJ5dGVMZW5ndGggKz0gMjtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgICAgICBjYXNlICdpbnQxNic6XG4gICAgICAgICAgICAgICAgICAgIGJ5dGVMZW5ndGggKz0gMjtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgICAgICBjYXNlICdmbG9hdCc6XG4gICAgICAgICAgICAgICAgICAgIGJ5dGVMZW5ndGggKz0gNDtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgICAgICBjYXNlICdkb3VibGUnOlxuICAgICAgICAgICAgICAgICAgICBieXRlTGVuZ3RoICs9IDg7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAgICAgY2FzZSAnc3RyaW5nJzpcbiAgICAgICAgICAgICAgICAgICAgLy8gMiBieXRlcyBmb3Igc3RyaW5nIGxlbmd0aFxuICAgICAgICAgICAgICAgICAgICBieXRlTGVuZ3RoICs9IDI7XG4gICAgICAgICAgICAgICAgICAgIC8vIDIgYnl0ZXMgcGVyIGNoYXJhY3RlcnNcbiAgICAgICAgICAgICAgICAgICAgYnl0ZUxlbmd0aCArPSAyICogdGV4dEVuY29kZXIuZW5jb2RlKGVsZW1lbnQgYXMgc3RyaW5nKS5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBjb25zdCBkYXRhID0gbmV3IERhdGFWaWV3KG5ldyBBcnJheUJ1ZmZlcihieXRlTGVuZ3RoICsgMSkpO1xuICAgICAgICBkYXRhLnNldFVpbnQ4KDAsIG1lc3NhZ2VGb3JtYXQuaWQpO1xuICAgICAgICBsZXQgYnl0ZU9mZnNldCA9IDE7XG5cbiAgICAgICAgbWVzc2FnZURhdGEuZm9yRWFjaCgoZWxlbWVudDogbnVtYmVyIHwgc3RyaW5nLCBpZHg6IG51bWJlcikgPT4ge1xuICAgICAgICAgICAgY29uc3QgdHlwZSA9IG1lc3NhZ2VGb3JtYXQuc3RydWN0dXJlW2lkeF07XG4gICAgICAgICAgICBzd2l0Y2ggKHR5cGUpIHtcbiAgICAgICAgICAgICAgICBjYXNlICd1aW50OCc6XG4gICAgICAgICAgICAgICAgICAgIGRhdGEuc2V0VWludDgoYnl0ZU9mZnNldCwgZWxlbWVudCBhcyBudW1iZXIpO1xuICAgICAgICAgICAgICAgICAgICBieXRlT2Zmc2V0ICs9IDE7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAgICAgY2FzZSAndWludDE2JzpcbiAgICAgICAgICAgICAgICAgICAgZGF0YS5zZXRVaW50MTYoYnl0ZU9mZnNldCwgZWxlbWVudCBhcyBudW1iZXIsIHRydWUpO1xuICAgICAgICAgICAgICAgICAgICBieXRlT2Zmc2V0ICs9IDI7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAgICAgY2FzZSAnaW50MTYnOlxuICAgICAgICAgICAgICAgICAgICBkYXRhLnNldEludDE2KGJ5dGVPZmZzZXQsIGVsZW1lbnQgYXMgbnVtYmVyLCB0cnVlKTtcbiAgICAgICAgICAgICAgICAgICAgYnl0ZU9mZnNldCArPSAyO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgICAgIGNhc2UgJ2Zsb2F0JzpcbiAgICAgICAgICAgICAgICAgICAgZGF0YS5zZXRGbG9hdDMyKGJ5dGVPZmZzZXQsIGVsZW1lbnQgYXMgbnVtYmVyLCB0cnVlKTtcbiAgICAgICAgICAgICAgICAgICAgYnl0ZU9mZnNldCArPSA0O1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgICAgIGNhc2UgJ2RvdWJsZSc6XG4gICAgICAgICAgICAgICAgICAgIGRhdGEuc2V0RmxvYXQ2NChieXRlT2Zmc2V0LCBlbGVtZW50IGFzIG51bWJlciwgdHJ1ZSk7XG4gICAgICAgICAgICAgICAgICAgIGJ5dGVPZmZzZXQgKz0gODtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgICAgICBjYXNlICdzdHJpbmcnOlxuICAgICAgICAgICAgICAgICAgICBkYXRhLnNldFVpbnQxNihieXRlT2Zmc2V0LCAoZWxlbWVudCBhcyBzdHJpbmcpLmxlbmd0aCwgdHJ1ZSk7XG4gICAgICAgICAgICAgICAgICAgIGJ5dGVPZmZzZXQgKz0gMjtcbiAgICAgICAgICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCAoZWxlbWVudCBhcyBzdHJpbmcpLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBkYXRhLnNldFVpbnQxNihieXRlT2Zmc2V0LCAoZWxlbWVudCBhcyBzdHJpbmcpLmNoYXJDb2RlQXQoaSksIHRydWUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYnl0ZU9mZnNldCArPSAyO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoIXRoaXMuZGF0YUNoYW5uZWxTZW5kZXIuY2FuU2VuZCgpKSB7XG4gICAgICAgICAgICBMb2dnZXIuSW5mbyhcbiAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgIGBEYXRhIGNoYW5uZWwgY2Fubm90IHNlbmQgeWV0LCBza2lwcGluZyBzZW5kaW5nIG1lc3NhZ2U6ICR7bWVzc2FnZVR5cGV9IC0gJHtuZXcgVWludDhBcnJheShcbiAgICAgICAgICAgICAgICAgICAgZGF0YS5idWZmZXJcbiAgICAgICAgICAgICAgICApfWBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmRhdGFDaGFubmVsU2VuZGVyLnNlbmREYXRhKGRhdGEuYnVmZmVyKTtcbiAgICB9XG59XG4iLCIvLyBDb3B5cmlnaHQgRXBpYyBHYW1lcywgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuXG5pbXBvcnQgeyBMb2dnZXIgfSBmcm9tICcuLi9Mb2dnZXIvTG9nZ2VyJztcblxuZXhwb3J0IGNsYXNzIFRvU3RyZWFtZXJNZXNzYWdlIHtcbiAgICBpZDogbnVtYmVyO1xuICAgIHN0cnVjdHVyZT86IEFycmF5PHN0cmluZz47XG59XG5cbmV4cG9ydCBjbGFzcyBTdHJlYW1NZXNzYWdlQ29udHJvbGxlciB7XG4gICAgdG9TdHJlYW1lckhhbmRsZXJzOiBNYXA8XG4gICAgICAgIHN0cmluZyxcbiAgICAgICAgKG1lc3NhZ2VEYXRhPzogQXJyYXk8bnVtYmVyIHwgc3RyaW5nPiB8IHVuZGVmaW5lZCkgPT4gdm9pZFxuICAgID47XG4gICAgZnJvbVN0cmVhbWVySGFuZGxlcnM6IE1hcDxcbiAgICAgICAgc3RyaW5nLFxuICAgICAgICAobWVzc2FnZVR5cGU6IHN0cmluZywgbWVzc2FnZURhdGE/OiBBcnJheUJ1ZmZlciB8IHVuZGVmaW5lZCkgPT4gdm9pZFxuICAgID47XG4gICAgLy8gICAgICAgICAgICAgICAgICAgICAgICBUeXBlICAgICAgRm9ybWF0XG4gICAgdG9TdHJlYW1lck1lc3NhZ2VzOiBNYXA8c3RyaW5nLCBUb1N0cmVhbWVyTWVzc2FnZT47XG4gICAgLy8gICAgICAgICAgICAgICAgICAgICAgICAgSUQgICAgICBUeXBlXG4gICAgZnJvbVN0cmVhbWVyTWVzc2FnZXM6IE1hcDxudW1iZXIsIHN0cmluZz47XG5cbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgdGhpcy50b1N0cmVhbWVySGFuZGxlcnMgPSBuZXcgTWFwKCk7XG4gICAgICAgIHRoaXMuZnJvbVN0cmVhbWVySGFuZGxlcnMgPSBuZXcgTWFwKCk7XG4gICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzID0gbmV3IE1hcCgpO1xuICAgICAgICB0aGlzLmZyb21TdHJlYW1lck1lc3NhZ2VzID0gbmV3IE1hcCgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFBvcHVsYXRlIHRoZSBEZWZhdWx0IG1lc3NhZ2UgcHJvdG9jb2xcbiAgICAgKi9cbiAgICBwb3B1bGF0ZURlZmF1bHRQcm90b2NvbCgpIHtcbiAgICAgICAgLypcbiAgICAgICAgICogQ29udHJvbCBNZXNzYWdlcy4gUmFuZ2UgPSAwLi40OS5cbiAgICAgICAgICovXG4gICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzLnNldCgnSUZyYW1lUmVxdWVzdCcsIHtcbiAgICAgICAgICAgIGlkOiAwLFxuICAgICAgICAgICAgc3RydWN0dXJlOiBbXVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy50b1N0cmVhbWVyTWVzc2FnZXMuc2V0KCdSZXF1ZXN0UXVhbGl0eUNvbnRyb2wnLCB7XG4gICAgICAgICAgICBpZDogMSxcbiAgICAgICAgICAgIHN0cnVjdHVyZTogW11cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzLnNldCgnRnBzUmVxdWVzdCcsIHtcbiAgICAgICAgICAgIGlkOiAyLFxuICAgICAgICAgICAgc3RydWN0dXJlOiBbXVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy50b1N0cmVhbWVyTWVzc2FnZXMuc2V0KCdBdmVyYWdlQml0cmF0ZVJlcXVlc3QnLCB7XG4gICAgICAgICAgICBpZDogMyxcbiAgICAgICAgICAgIHN0cnVjdHVyZTogW11cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzLnNldCgnU3RhcnRTdHJlYW1pbmcnLCB7XG4gICAgICAgICAgICBpZDogNCxcbiAgICAgICAgICAgIHN0cnVjdHVyZTogW11cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzLnNldCgnU3RvcFN0cmVhbWluZycsIHtcbiAgICAgICAgICAgIGlkOiA1LFxuICAgICAgICAgICAgc3RydWN0dXJlOiBbXVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy50b1N0cmVhbWVyTWVzc2FnZXMuc2V0KCdMYXRlbmN5VGVzdCcsIHtcbiAgICAgICAgICAgIGlkOiA2LFxuICAgICAgICAgICAgc3RydWN0dXJlOiBbJ3N0cmluZyddXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlcy5zZXQoJ1JlcXVlc3RJbml0aWFsU2V0dGluZ3MnLCB7XG4gICAgICAgICAgICBpZDogNyxcbiAgICAgICAgICAgIHN0cnVjdHVyZTogW11cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzLnNldCgnVGVzdEVjaG8nLCB7XG4gICAgICAgICAgICBpZDogOCxcbiAgICAgICAgICAgIHN0cnVjdHVyZTogW11cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzLnNldCgnRGF0YUNoYW5uZWxMYXRlbmN5VGVzdCcsIHtcbiAgICAgICAgICAgIGlkOiA5LFxuICAgICAgICAgICAgc3RydWN0dXJlOiBbXVxuICAgICAgICB9KTtcbiAgICAgICAgLypcbiAgICAgICAgICogSW5wdXQgTWVzc2FnZXMuIFJhbmdlID0gNTAuLjg5LlxuICAgICAgICAgKi9cbiAgICAgICAgLy8gR2VuZXJpYyBJbnB1dCBNZXNzYWdlcy4gUmFuZ2UgPSA1MC4uNTkuXG4gICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzLnNldCgnVUlJbnRlcmFjdGlvbicsIHtcbiAgICAgICAgICAgIGlkOiA1MCxcbiAgICAgICAgICAgIHN0cnVjdHVyZTogWydzdHJpbmcnXVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy50b1N0cmVhbWVyTWVzc2FnZXMuc2V0KCdDb21tYW5kJywge1xuICAgICAgICAgICAgaWQ6IDUxLFxuICAgICAgICAgICAgc3RydWN0dXJlOiBbJ3N0cmluZyddXG4gICAgICAgIH0pO1xuICAgICAgICAvLyBLZXlib2FyZCBJbnB1dCBNZXNzYWdlLiBSYW5nZSA9IDYwLi42OS5cbiAgICAgICAgdGhpcy50b1N0cmVhbWVyTWVzc2FnZXMuc2V0KCdLZXlEb3duJywge1xuICAgICAgICAgICAgaWQ6IDYwLFxuICAgICAgICAgICAgLy8gICAgICAgICAgICBrZXlDb2RlICBpc1JlcGVhdFxuICAgICAgICAgICAgc3RydWN0dXJlOiBbJ3VpbnQ4JywgJ3VpbnQ4J11cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzLnNldCgnS2V5VXAnLCB7XG4gICAgICAgICAgICBpZDogNjEsXG4gICAgICAgICAgICAvLyAgICAgICAgICAgIGtleUNvZGVcbiAgICAgICAgICAgIHN0cnVjdHVyZTogWyd1aW50OCddXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlcy5zZXQoJ0tleVByZXNzJywge1xuICAgICAgICAgICAgaWQ6IDYyLFxuICAgICAgICAgICAgLy8gICAgICAgICAgICBjaGFyY29kZVxuICAgICAgICAgICAgc3RydWN0dXJlOiBbJ3VpbnQxNiddXG4gICAgICAgIH0pO1xuICAgICAgICAvLyBNb3VzZSBJbnB1dCBNZXNzYWdlcy4gUmFuZ2UgPSA3MC4uNzkuXG4gICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzLnNldCgnTW91c2VFbnRlcicsIHtcbiAgICAgICAgICAgIGlkOiA3MCxcbiAgICAgICAgICAgIHN0cnVjdHVyZTogW11cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzLnNldCgnTW91c2VMZWF2ZScsIHtcbiAgICAgICAgICAgIGlkOiA3MSxcbiAgICAgICAgICAgIHN0cnVjdHVyZTogW11cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzLnNldCgnTW91c2VEb3duJywge1xuICAgICAgICAgICAgaWQ6IDcyLFxuICAgICAgICAgICAgLy8gICAgICAgICAgICAgIGJ1dHRvbiAgICAgeCAgICAgICAgIHlcbiAgICAgICAgICAgIHN0cnVjdHVyZTogWyd1aW50OCcsICd1aW50MTYnLCAndWludDE2J11cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzLnNldCgnTW91c2VVcCcsIHtcbiAgICAgICAgICAgIGlkOiA3MyxcbiAgICAgICAgICAgIC8vICAgICAgICAgICAgICBidXR0b24gICAgIHggICAgICAgICB5XG4gICAgICAgICAgICBzdHJ1Y3R1cmU6IFsndWludDgnLCAndWludDE2JywgJ3VpbnQxNiddXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlcy5zZXQoJ01vdXNlTW92ZScsIHtcbiAgICAgICAgICAgIGlkOiA3NCxcbiAgICAgICAgICAgIC8vICAgICAgICAgICAgICB4ICAgICAgICAgICB5ICAgICAgZGVsdGFYICAgIGRlbHRhWVxuICAgICAgICAgICAgc3RydWN0dXJlOiBbJ3VpbnQxNicsICd1aW50MTYnLCAnaW50MTYnLCAnaW50MTYnXVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy50b1N0cmVhbWVyTWVzc2FnZXMuc2V0KCdNb3VzZVdoZWVsJywge1xuICAgICAgICAgICAgaWQ6IDc1LFxuICAgICAgICAgICAgLy8gICAgICAgICAgICAgIGRlbHRhICAgICAgIHggICAgICAgIHlcbiAgICAgICAgICAgIHN0cnVjdHVyZTogWydpbnQxNicsICd1aW50MTYnLCAndWludDE2J11cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzLnNldCgnTW91c2VEb3VibGUnLCB7XG4gICAgICAgICAgICBpZDogNzYsXG4gICAgICAgICAgICAvLyAgICAgICAgICAgICAgYnV0dG9uICAgICB4ICAgICAgICAgeVxuICAgICAgICAgICAgc3RydWN0dXJlOiBbJ3VpbnQ4JywgJ3VpbnQxNicsICd1aW50MTYnXVxuICAgICAgICB9KTtcbiAgICAgICAgLy8gVG91Y2ggSW5wdXQgTWVzc2FnZXMuIFJhbmdlID0gODAuLjg5LlxuICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlcy5zZXQoJ1RvdWNoU3RhcnQnLCB7XG4gICAgICAgICAgICBpZDogODAsXG4gICAgICAgICAgICAvLyAgICAgICAgICBudW10b3VjaGVzKDEpICAgeCAgICAgICB5ICAgICAgICBpZHggICAgIGZvcmNlICAgICB2YWxpZFxuICAgICAgICAgICAgc3RydWN0dXJlOiBbJ3VpbnQ4JywgJ3VpbnQxNicsICd1aW50MTYnLCAndWludDgnLCAndWludDgnLCAndWludDgnXVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy50b1N0cmVhbWVyTWVzc2FnZXMuc2V0KCdUb3VjaEVuZCcsIHtcbiAgICAgICAgICAgIGlkOiA4MSxcbiAgICAgICAgICAgIC8vICAgICAgICAgIG51bXRvdWNoZXMoMSkgICB4ICAgICAgIHkgICAgICAgIGlkeCAgICAgZm9yY2UgICAgIHZhbGlkXG4gICAgICAgICAgICBzdHJ1Y3R1cmU6IFsndWludDgnLCAndWludDE2JywgJ3VpbnQxNicsICd1aW50OCcsICd1aW50OCcsICd1aW50OCddXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlcy5zZXQoJ1RvdWNoTW92ZScsIHtcbiAgICAgICAgICAgIGlkOiA4MixcbiAgICAgICAgICAgIC8vICAgICAgICAgIG51bXRvdWNoZXMoMSkgICB4ICAgICAgIHkgICAgICAgaWR4ICAgICAgZm9yY2UgICAgIHZhbGlkXG4gICAgICAgICAgICBzdHJ1Y3R1cmU6IFsndWludDgnLCAndWludDE2JywgJ3VpbnQxNicsICd1aW50OCcsICd1aW50OCcsICd1aW50OCddXG4gICAgICAgIH0pO1xuICAgICAgICAvLyBHYW1lcGFkIElucHV0IE1lc3NhZ2VzLiBSYW5nZSA9IDkwLi45OVxuICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlcy5zZXQoJ0dhbWVwYWRDb25uZWN0ZWQnLCB7XG4gICAgICAgICAgICBpZDogOTMsXG4gICAgICAgICAgICBzdHJ1Y3R1cmU6IFtdXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlcy5zZXQoJ0dhbWVwYWRCdXR0b25QcmVzc2VkJywge1xuICAgICAgICAgICAgaWQ6IDkwLFxuICAgICAgICAgICAgLy8gICAgICAgICBjdHJsZXJJZCAgIGJ1dHRvbiAgaXNSZXBlYXRcbiAgICAgICAgICAgIHN0cnVjdHVyZTogWyd1aW50OCcsICd1aW50OCcsICd1aW50OCddXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlcy5zZXQoJ0dhbWVwYWRCdXR0b25SZWxlYXNlZCcsIHtcbiAgICAgICAgICAgIGlkOiA5MSxcbiAgICAgICAgICAgIC8vICAgICAgICAgY3RybGVySWQgICBidXR0b24gIGlzUmVwZWF0KDApXG4gICAgICAgICAgICBzdHJ1Y3R1cmU6IFsndWludDgnLCAndWludDgnLCAndWludDgnXVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy50b1N0cmVhbWVyTWVzc2FnZXMuc2V0KCdHYW1lcGFkQW5hbG9nJywge1xuICAgICAgICAgICAgaWQ6IDkyLFxuICAgICAgICAgICAgLy8gICAgICAgICBjdHJsZXJJZCAgIGJ1dHRvbiAgYW5hbG9nVmFsdWVcbiAgICAgICAgICAgIHN0cnVjdHVyZTogWyd1aW50OCcsICd1aW50OCcsICdkb3VibGUnXVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy50b1N0cmVhbWVyTWVzc2FnZXMuc2V0KCdHYW1lcGFkRGlzY29ubmVjdGVkJywge1xuICAgICAgICAgICAgaWQ6IDk0LFxuICAgICAgICAgICAgLy8gICAgICAgICAgY3RybGVySWRcbiAgICAgICAgICAgIHN0cnVjdHVyZTogWyd1aW50OCddXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuZnJvbVN0cmVhbWVyTWVzc2FnZXMuc2V0KDAsICdRdWFsaXR5Q29udHJvbE93bmVyc2hpcCcpO1xuICAgICAgICB0aGlzLmZyb21TdHJlYW1lck1lc3NhZ2VzLnNldCgxLCAnUmVzcG9uc2UnKTtcbiAgICAgICAgdGhpcy5mcm9tU3RyZWFtZXJNZXNzYWdlcy5zZXQoMiwgJ0NvbW1hbmQnKTtcbiAgICAgICAgdGhpcy5mcm9tU3RyZWFtZXJNZXNzYWdlcy5zZXQoMywgJ0ZyZWV6ZUZyYW1lJyk7XG4gICAgICAgIHRoaXMuZnJvbVN0cmVhbWVyTWVzc2FnZXMuc2V0KDQsICdVbmZyZWV6ZUZyYW1lJyk7XG4gICAgICAgIHRoaXMuZnJvbVN0cmVhbWVyTWVzc2FnZXMuc2V0KDUsICdWaWRlb0VuY29kZXJBdmdRUCcpO1xuICAgICAgICB0aGlzLmZyb21TdHJlYW1lck1lc3NhZ2VzLnNldCg2LCAnTGF0ZW5jeVRlc3QnKTtcbiAgICAgICAgdGhpcy5mcm9tU3RyZWFtZXJNZXNzYWdlcy5zZXQoNywgJ0luaXRpYWxTZXR0aW5ncycpO1xuICAgICAgICB0aGlzLmZyb21TdHJlYW1lck1lc3NhZ2VzLnNldCg4LCAnRmlsZUV4dGVuc2lvbicpO1xuICAgICAgICB0aGlzLmZyb21TdHJlYW1lck1lc3NhZ2VzLnNldCg5LCAnRmlsZU1pbWVUeXBlJyk7XG4gICAgICAgIHRoaXMuZnJvbVN0cmVhbWVyTWVzc2FnZXMuc2V0KDEwLCAnRmlsZUNvbnRlbnRzJyk7XG4gICAgICAgIHRoaXMuZnJvbVN0cmVhbWVyTWVzc2FnZXMuc2V0KDExLCAnVGVzdEVjaG8nKTtcbiAgICAgICAgdGhpcy5mcm9tU3RyZWFtZXJNZXNzYWdlcy5zZXQoMTIsICdJbnB1dENvbnRyb2xPd25lcnNoaXAnKTtcbiAgICAgICAgdGhpcy5mcm9tU3RyZWFtZXJNZXNzYWdlcy5zZXQoMTMsICdHYW1lcGFkUmVzcG9uc2UnKTtcbiAgICAgICAgdGhpcy5mcm9tU3RyZWFtZXJNZXNzYWdlcy5zZXQoMTQsICdEYXRhQ2hhbm5lbExhdGVuY3lUZXN0Jyk7XG4gICAgICAgIHRoaXMuZnJvbVN0cmVhbWVyTWVzc2FnZXMuc2V0KDI1NSwgJ1Byb3RvY29sJyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVnaXN0ZXIgYSBtZXNzYWdlIGhhbmRsZXJcbiAgICAgKiBAcGFyYW0gbWVzc2FnZURpcmVjdGlvbiAtIHRoZSBkaXJlY3Rpb24gb2YgdGhlIG1lc3NhZ2U7IHRvU3RyZWFtZXIgb3IgZnJvbVN0cmVhbWVyXG4gICAgICogQHBhcmFtIG1lc3NhZ2VUeXBlIC0gdGhlIHR5cGUgb2YgdGhlIG1lc3NhZ2VcbiAgICAgKiBAcGFyYW0gbWVzc2FnZUhhbmRsZXIgLSB0aGUgZnVuY3Rpb24gb3IgbWV0aG9kIHRvIGJlIGV4ZWN1dGVkIHdoZW4gdGhpcyBoYW5kbGVyIGlzIGNhbGxlZFxuICAgICAqL1xuICAgIHJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgIG1lc3NhZ2VEaXJlY3Rpb246IE1lc3NhZ2VEaXJlY3Rpb24sXG4gICAgICAgIG1lc3NhZ2VUeXBlOiBzdHJpbmcsXG4gICAgICAgIG1lc3NhZ2VIYW5kbGVyOiAobWVzc2FnZURhdGE/OiB1bmtub3duIHwgdW5kZWZpbmVkKSA9PiB2b2lkXG4gICAgKSB7XG4gICAgICAgIHN3aXRjaCAobWVzc2FnZURpcmVjdGlvbikge1xuICAgICAgICAgICAgY2FzZSBNZXNzYWdlRGlyZWN0aW9uLlRvU3RyZWFtZXI6XG4gICAgICAgICAgICAgICAgdGhpcy50b1N0cmVhbWVySGFuZGxlcnMuc2V0KG1lc3NhZ2VUeXBlLCBtZXNzYWdlSGFuZGxlcik7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIE1lc3NhZ2VEaXJlY3Rpb24uRnJvbVN0cmVhbWVyOlxuICAgICAgICAgICAgICAgIHRoaXMuZnJvbVN0cmVhbWVySGFuZGxlcnMuc2V0KG1lc3NhZ2VUeXBlLCBtZXNzYWdlSGFuZGxlcik7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgICAgIGBVbmtub3duIG1lc3NhZ2UgZGlyZWN0aW9uICR7bWVzc2FnZURpcmVjdGlvbn1gXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuLyoqXG4gKiBUaGUgZW51bSBmb3IgbWVzc2FnZSBkaXJlY3Rpb25zXG4gKi9cbmV4cG9ydCBlbnVtIE1lc3NhZ2VEaXJlY3Rpb24ge1xuICAgIFRvU3RyZWFtZXIgPSAwLFxuICAgIEZyb21TdHJlYW1lciA9IDFcbn1cbiIsIi8vIENvcHlyaWdodCBFcGljIEdhbWVzLCBJbmMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG5cbmltcG9ydCB7IFNlbmRNZXNzYWdlQ29udHJvbGxlciB9IGZyb20gJy4vU2VuZE1lc3NhZ2VDb250cm9sbGVyJztcblxuZXhwb3J0IGNsYXNzIFRvU3RyZWFtZXJNZXNzYWdlc0NvbnRyb2xsZXIge1xuICAgIHNlbmRNZXNzYWdlQ29udHJvbGxlcjogU2VuZE1lc3NhZ2VDb250cm9sbGVyO1xuXG4gICAgLyoqXG4gICAgICogQHBhcmFtIHNlbmRNZXNzYWdlQ29udHJvbGxlciAtIFN0cmVhbSBtZXNzYWdlIGNvbnRyb2xsZXIgaW5zdGFuY2VcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihzZW5kTWVzc2FnZUNvbnRyb2xsZXI6IFNlbmRNZXNzYWdlQ29udHJvbGxlcikge1xuICAgICAgICB0aGlzLnNlbmRNZXNzYWdlQ29udHJvbGxlciA9IHNlbmRNZXNzYWdlQ29udHJvbGxlcjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZW5kIFJlcXVlc3QgdG8gVGFrZSBRdWFsaXR5IENvbnRyb2wgdG8gdGhlIFVFIEluc3RhbmNlXG4gICAgICovXG4gICAgU2VuZFJlcXVlc3RRdWFsaXR5Q29udHJvbCgpIHtcbiAgICAgICAgdGhpcy5zZW5kTWVzc2FnZUNvbnRyb2xsZXIuc2VuZE1lc3NhZ2VUb1N0cmVhbWVyKFxuICAgICAgICAgICAgJ1JlcXVlc3RRdWFsaXR5Q29udHJvbCdcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZW5kIE1heCBGUFMgUmVxdWVzdCB0byB0aGUgVUUgSW5zdGFuY2VcbiAgICAgKi9cbiAgICBTZW5kTWF4RnBzUmVxdWVzdCgpIHtcbiAgICAgICAgdGhpcy5zZW5kTWVzc2FnZUNvbnRyb2xsZXIuc2VuZE1lc3NhZ2VUb1N0cmVhbWVyKCdGcHNSZXF1ZXN0Jyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2VuZCBBdmVyYWdlIEJpdHJhdGUgUmVxdWVzdCB0byB0aGUgVUUgSW5zdGFuY2VcbiAgICAgKi9cbiAgICBTZW5kQXZlcmFnZUJpdHJhdGVSZXF1ZXN0KCkge1xuICAgICAgICB0aGlzLnNlbmRNZXNzYWdlQ29udHJvbGxlci5zZW5kTWVzc2FnZVRvU3RyZWFtZXIoXG4gICAgICAgICAgICAnQXZlcmFnZUJpdHJhdGVSZXF1ZXN0J1xuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNlbmQgYSBTdGFydCBTdHJlYW1pbmcgTWVzc2FnZSB0byB0aGUgVUUgSW5zdGFuY2VcbiAgICAgKi9cbiAgICBTZW5kU3RhcnRTdHJlYW1pbmcoKSB7XG4gICAgICAgIHRoaXMuc2VuZE1lc3NhZ2VDb250cm9sbGVyLnNlbmRNZXNzYWdlVG9TdHJlYW1lcignU3RhcnRTdHJlYW1pbmcnKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZW5kIGEgU3RvcCBTdHJlYW1pbmcgTWVzc2FnZSB0byB0aGUgVUUgSW5zdGFuY2VcbiAgICAgKi9cbiAgICBTZW5kU3RvcFN0cmVhbWluZygpIHtcbiAgICAgICAgdGhpcy5zZW5kTWVzc2FnZUNvbnRyb2xsZXIuc2VuZE1lc3NhZ2VUb1N0cmVhbWVyKCdTdG9wU3RyZWFtaW5nJyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2VuZCBhIFJlcXVlc3QgSW5pdGlhbCBTZXR0aW5ncyB0byB0aGUgVUUgSW5zdGFuY2VcbiAgICAgKi9cbiAgICBTZW5kUmVxdWVzdEluaXRpYWxTZXR0aW5ncygpIHtcbiAgICAgICAgdGhpcy5zZW5kTWVzc2FnZUNvbnRyb2xsZXIuc2VuZE1lc3NhZ2VUb1N0cmVhbWVyKFxuICAgICAgICAgICAgJ1JlcXVlc3RJbml0aWFsU2V0dGluZ3MnXG4gICAgICAgICk7XG4gICAgfVxufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuaW1wb3J0IHsgTG9nZ2VyIH0gZnJvbSAnLi4vTG9nZ2VyL0xvZ2dlcic7XG5pbXBvcnQgeyBWaWRlb1BsYXllciB9IGZyb20gJy4uL1ZpZGVvUGxheWVyL1ZpZGVvUGxheWVyJztcblxuLyoqXG4gKiBDb252ZXJ0cyBjb29yZGluYXRlcyBmcm9tIGVsZW1lbnQgcmVsYXRpdmUgY29vcmRpbmF0ZXMgdG8gdmFsdWVzIG5vcm1hbGl6ZWQgd2l0aGluIHRoZSB2YWx1ZSByYW5nZSBvZiBhIHNob3J0IChhbmQgYmFjayBhZ2FpbilcbiAqL1xuZXhwb3J0IGNsYXNzIENvb3JkaW5hdGVDb252ZXJ0ZXIge1xuICAgIHZpZGVvRWxlbWVudFByb3ZpZGVyOiBWaWRlb1BsYXllcjtcbiAgICB2aWRlb0VsZW1lbnRQYXJlbnQ6IEhUTUxFbGVtZW50O1xuICAgIHZpZGVvRWxlbWVudDogSFRNTFZpZGVvRWxlbWVudDtcbiAgICByYXRpbzogbnVtYmVyO1xuXG4gICAgbm9ybWFsaXplQW5kUXVhbnRpemVVbnNpZ25lZEZ1bmM6IChcbiAgICAgICAgeDogbnVtYmVyLFxuICAgICAgICB5OiBudW1iZXJcbiAgICApID0+IE5vcm1hbGl6ZWRRdWFudGl6ZWRVbnNpZ25lZENvb3JkO1xuICAgIG5vcm1hbGl6ZUFuZFF1YW50aXplU2lnbmVkRnVuYzogKFxuICAgICAgICB4OiBudW1iZXIsXG4gICAgICAgIHk6IG51bWJlclxuICAgICkgPT4gTm9ybWFsaXplZFF1YW50aXplZFNpZ25lZENvb3JkO1xuICAgIGRlbm9ybWFsaXplQW5kVW5xdWFudGl6ZVVuc2lnbmVkRnVuYzogKFxuICAgICAgICB4OiBudW1iZXIsXG4gICAgICAgIHk6IG51bWJlclxuICAgICkgPT4gVW5xdWFudGl6ZWREZW5vcm1hbGl6ZWRVbnNpZ25lZENvb3JkO1xuXG4gICAgLyoqXG4gICAgICogQHBhcmFtIHZpZGVvRWxlbWVudFByb3ZpZGVyIC0gdGhlIGRpdiBlbGVtZW50IHRoYXQgdGhlIHZpZGVvIHBsYXllciB3aWxsIGJlIGluamVjdGVkIGludG9cbiAgICAgKi9cbiAgICBjb25zdHJ1Y3Rvcih2aWRlb0VsZW1lbnRQcm92aWRlcjogVmlkZW9QbGF5ZXIpIHtcbiAgICAgICAgdGhpcy52aWRlb0VsZW1lbnRQcm92aWRlciA9IHZpZGVvRWxlbWVudFByb3ZpZGVyO1xuICAgICAgICB0aGlzLm5vcm1hbGl6ZUFuZFF1YW50aXplVW5zaWduZWRGdW5jID0gKCkgPT4ge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICAgICdOb3JtYWxpemUgYW5kIHF1YW50aXplIHVuc2lnbmVkLCBtZXRob2Qgbm90IGltcGxlbWVudGVkLidcbiAgICAgICAgICAgICk7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMubm9ybWFsaXplQW5kUXVhbnRpemVTaWduZWRGdW5jID0gKCkgPT4ge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICAgICdOb3JtYWxpemUgYW5kIHVucXVhbnRpemUgc2lnbmVkLCBtZXRob2Qgbm90IGltcGxlbWVudGVkLidcbiAgICAgICAgICAgICk7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuZGVub3JtYWxpemVBbmRVbnF1YW50aXplVW5zaWduZWRGdW5jID0gKCkgPT4ge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICAgICdEZW5vcm1hbGl6ZSBhbmQgdW5xdWFudGl6ZSB1bnNpZ25lZCwgbWV0aG9kIG5vdCBpbXBsZW1lbnRlZC4nXG4gICAgICAgICAgICApO1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBzdXJmYWNlIG1ldGhvZCBmb3Igc2V0dGVyTm9ybWFsaXplQW5kUXVhbnRpemVVbnNpZ25lZFxuICAgICAqIEBwYXJhbSB4IC0geCBheGlzIHBvaW50XG4gICAgICogQHBhcmFtIHkgLSB5IGF4aXMgcG9pbnRcbiAgICAgKi9cbiAgICBub3JtYWxpemVBbmRRdWFudGl6ZVVuc2lnbmVkKFxuICAgICAgICB4OiBudW1iZXIsXG4gICAgICAgIHk6IG51bWJlclxuICAgICk6IE5vcm1hbGl6ZWRRdWFudGl6ZWRVbnNpZ25lZENvb3JkIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubm9ybWFsaXplQW5kUXVhbnRpemVVbnNpZ25lZEZ1bmMoeCwgeSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhlIHN1cmZhY2UgbWV0aG9kIGZvciBzZXR0ZXJVbnF1YW50aXplQW5kRGVub3JtYWxpemVVbnNpZ25lZFxuICAgICAqIEBwYXJhbSB4IC0geCBheGlzIHBvaW50XG4gICAgICogQHBhcmFtIHkgLSB5IGF4aXMgcG9pbnRcbiAgICAgKi9cbiAgICB1bnF1YW50aXplQW5kRGVub3JtYWxpemVVbnNpZ25lZChcbiAgICAgICAgeDogbnVtYmVyLFxuICAgICAgICB5OiBudW1iZXJcbiAgICApOiBVbnF1YW50aXplZERlbm9ybWFsaXplZFVuc2lnbmVkQ29vcmQge1xuICAgICAgICByZXR1cm4gdGhpcy5kZW5vcm1hbGl6ZUFuZFVucXVhbnRpemVVbnNpZ25lZEZ1bmMoeCwgeSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhlIHN1cmZhY2UgbWV0aG9kIGZvciBzZXR0ZXJOb3JtYWxpemVBbmRRdWFudGl6ZVNpZ25lZFxuICAgICAqIEBwYXJhbSB4IC0geCBheGlzIHBvaW50XG4gICAgICogQHBhcmFtIHkgLSB5IGF4aXMgcG9pbnRcbiAgICAgKi9cbiAgICBub3JtYWxpemVBbmRRdWFudGl6ZVNpZ25lZChcbiAgICAgICAgeDogbnVtYmVyLFxuICAgICAgICB5OiBudW1iZXJcbiAgICApOiBOb3JtYWxpemVkUXVhbnRpemVkU2lnbmVkQ29vcmQge1xuICAgICAgICByZXR1cm4gdGhpcy5ub3JtYWxpemVBbmRRdWFudGl6ZVNpZ25lZEZ1bmMoeCwgeSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogc2V0IHVwIHRoZSBOb3JtYWxpemUgQW5kIFF1YW50aXplIG1ldGhvZHMgYmFzZWQgb24gdGhlIGFzcGVjdCByYXRpbyBhbmQgdGhlIHZpZGVvIHBsYXllciByYXRpb1xuICAgICAqL1xuICAgIHNldHVwTm9ybWFsaXplQW5kUXVhbnRpemUoKSB7XG4gICAgICAgIHRoaXMudmlkZW9FbGVtZW50UGFyZW50ID1cbiAgICAgICAgICAgIHRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIuZ2V0VmlkZW9QYXJlbnRFbGVtZW50KCk7XG4gICAgICAgIHRoaXMudmlkZW9FbGVtZW50ID0gdGhpcy52aWRlb0VsZW1lbnRQcm92aWRlci5nZXRWaWRlb0VsZW1lbnQoKTtcblxuICAgICAgICBpZiAodGhpcy52aWRlb0VsZW1lbnRQYXJlbnQgJiYgdGhpcy52aWRlb0VsZW1lbnQpIHtcbiAgICAgICAgICAgIGNvbnN0IHBsYXllckFzcGVjdFJhdGlvID1cbiAgICAgICAgICAgICAgICB0aGlzLnZpZGVvRWxlbWVudFBhcmVudC5jbGllbnRIZWlnaHQgL1xuICAgICAgICAgICAgICAgIHRoaXMudmlkZW9FbGVtZW50UGFyZW50LmNsaWVudFdpZHRoO1xuICAgICAgICAgICAgY29uc3QgdmlkZW9Bc3BlY3RSYXRpbyA9XG4gICAgICAgICAgICAgICAgdGhpcy52aWRlb0VsZW1lbnQudmlkZW9IZWlnaHQgLyB0aGlzLnZpZGVvRWxlbWVudC52aWRlb1dpZHRoO1xuICAgICAgICAgICAgaWYgKHBsYXllckFzcGVjdFJhdGlvID4gdmlkZW9Bc3BlY3RSYXRpbykge1xuICAgICAgICAgICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgICAgICdTZXR1cCBOb3JtYWxpemUgYW5kIFF1YW50aXplIGZvciBwbGF5ZXJBc3BlY3RSYXRpbyA+IHZpZGVvQXNwZWN0UmF0aW8nLFxuICAgICAgICAgICAgICAgICAgICA2XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJhdGlvID0gcGxheWVyQXNwZWN0UmF0aW8gLyB2aWRlb0FzcGVjdFJhdGlvO1xuICAgICAgICAgICAgICAgIHRoaXMubm9ybWFsaXplQW5kUXVhbnRpemVVbnNpZ25lZEZ1bmMgPSAoXG4gICAgICAgICAgICAgICAgICAgIHg6IG51bWJlcixcbiAgICAgICAgICAgICAgICAgICAgeTogbnVtYmVyXG4gICAgICAgICAgICAgICAgKSA9PiB0aGlzLm5vcm1hbGl6ZUFuZFF1YW50aXplVW5zaWduZWRQbGF5ZXJCaWdnZXIoeCwgeSk7XG4gICAgICAgICAgICAgICAgdGhpcy5ub3JtYWxpemVBbmRRdWFudGl6ZVNpZ25lZEZ1bmMgPSAoeDogbnVtYmVyLCB5OiBudW1iZXIpID0+XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubm9ybWFsaXplQW5kUXVhbnRpemVTaWduZWRQbGF5ZXJCaWdnZXIoeCwgeSk7XG4gICAgICAgICAgICAgICAgdGhpcy5kZW5vcm1hbGl6ZUFuZFVucXVhbnRpemVVbnNpZ25lZEZ1bmMgPSAoXG4gICAgICAgICAgICAgICAgICAgIHg6IG51bWJlcixcbiAgICAgICAgICAgICAgICAgICAgeTogbnVtYmVyXG4gICAgICAgICAgICAgICAgKSA9PiB0aGlzLmRlbm9ybWFsaXplQW5kVW5xdWFudGl6ZVVuc2lnbmVkUGxheWVyQmlnZ2VyKHgsIHkpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgICAgICAnU2V0dXAgTm9ybWFsaXplIGFuZCBRdWFudGl6ZSBmb3IgcGxheWVyQXNwZWN0UmF0aW8gPD0gdmlkZW9Bc3BlY3RSYXRpbycsXG4gICAgICAgICAgICAgICAgICAgIDZcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIHRoaXMucmF0aW8gPSB2aWRlb0FzcGVjdFJhdGlvIC8gcGxheWVyQXNwZWN0UmF0aW87XG4gICAgICAgICAgICAgICAgdGhpcy5ub3JtYWxpemVBbmRRdWFudGl6ZVVuc2lnbmVkRnVuYyA9IChcbiAgICAgICAgICAgICAgICAgICAgeDogbnVtYmVyLFxuICAgICAgICAgICAgICAgICAgICB5OiBudW1iZXJcbiAgICAgICAgICAgICAgICApID0+IHRoaXMubm9ybWFsaXplQW5kUXVhbnRpemVVbnNpZ25lZFBsYXllclNtYWxsZXIoeCwgeSk7XG4gICAgICAgICAgICAgICAgdGhpcy5ub3JtYWxpemVBbmRRdWFudGl6ZVNpZ25lZEZ1bmMgPSAoeDogbnVtYmVyLCB5OiBudW1iZXIpID0+XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubm9ybWFsaXplQW5kUXVhbnRpemVTaWduZWRQbGF5ZXJTbWFsbGVyKHgsIHkpO1xuICAgICAgICAgICAgICAgIHRoaXMuZGVub3JtYWxpemVBbmRVbnF1YW50aXplVW5zaWduZWRGdW5jID0gKFxuICAgICAgICAgICAgICAgICAgICB4OiBudW1iZXIsXG4gICAgICAgICAgICAgICAgICAgIHk6IG51bWJlclxuICAgICAgICAgICAgICAgICkgPT4gdGhpcy5kZW5vcm1hbGl6ZUFuZFVucXVhbnRpemVVbnNpZ25lZFBsYXllclNtYWxsZXIoeCwgeSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBub3JtYWxpemVBbmRRdWFudGl6ZVVuc2lnbmVkIGZvciBwbGF5ZXJBc3BlY3RSYXRpbyA+IHZpZGVvQXNwZWN0UmF0aW9cbiAgICAgKiBAcGFyYW0geCAtIHggYXhpcyBwb2ludFxuICAgICAqIEBwYXJhbSB5IC0geSBheGlzIHBvaW50XG4gICAgICovXG4gICAgbm9ybWFsaXplQW5kUXVhbnRpemVVbnNpZ25lZFBsYXllckJpZ2dlcihcbiAgICAgICAgeDogbnVtYmVyLFxuICAgICAgICB5OiBudW1iZXJcbiAgICApOiBOb3JtYWxpemVkUXVhbnRpemVkVW5zaWduZWRDb29yZCB7XG4gICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRYID0geCAvIHRoaXMudmlkZW9FbGVtZW50UGFyZW50LmNsaWVudFdpZHRoO1xuICAgICAgICBjb25zdCBub3JtYWxpemVkWSA9XG4gICAgICAgICAgICB0aGlzLnJhdGlvICogKHkgLyB0aGlzLnZpZGVvRWxlbWVudFBhcmVudC5jbGllbnRIZWlnaHQgLSAwLjUpICsgMC41O1xuICAgICAgICBpZiAoXG4gICAgICAgICAgICBub3JtYWxpemVkWCA8IDAuMCB8fFxuICAgICAgICAgICAgbm9ybWFsaXplZFggPiAxLjAgfHxcbiAgICAgICAgICAgIG5vcm1hbGl6ZWRZIDwgMC4wIHx8XG4gICAgICAgICAgICBub3JtYWxpemVkWSA+IDEuMFxuICAgICAgICApIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgTm9ybWFsaXplZFF1YW50aXplZFVuc2lnbmVkQ29vcmQoZmFsc2UsIDY1NTM1LCA2NTUzNSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IE5vcm1hbGl6ZWRRdWFudGl6ZWRVbnNpZ25lZENvb3JkKFxuICAgICAgICAgICAgICAgIHRydWUsXG4gICAgICAgICAgICAgICAgbm9ybWFsaXplZFggKiA2NTUzNixcbiAgICAgICAgICAgICAgICBub3JtYWxpemVkWSAqIDY1NTM2XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogdW5xdWFudGl6ZUFuZERlbm9ybWFsaXplVW5zaWduZWQgZm9yIHBsYXllckFzcGVjdFJhdGlvID4gdmlkZW9Bc3BlY3RSYXRpb1xuICAgICAqIEBwYXJhbSB4IC0geCBheGlzIHBvaW50XG4gICAgICogQHBhcmFtIHkgLSB5IGF4aXMgcG9pbnRcbiAgICAgKi9cbiAgICBkZW5vcm1hbGl6ZUFuZFVucXVhbnRpemVVbnNpZ25lZFBsYXllckJpZ2dlcih4OiBudW1iZXIsIHk6IG51bWJlcikge1xuICAgICAgICBjb25zdCBub3JtYWxpemVkWCA9IHggLyA2NTUzNjtcbiAgICAgICAgY29uc3Qgbm9ybWFsaXplZFkgPSAoeSAvIDY1NTM2IC0gMC41KSAvIHRoaXMucmF0aW8gKyAwLjU7XG4gICAgICAgIHJldHVybiBuZXcgVW5xdWFudGl6ZWREZW5vcm1hbGl6ZWRVbnNpZ25lZENvb3JkKFxuICAgICAgICAgICAgbm9ybWFsaXplZFggKiB0aGlzLnZpZGVvRWxlbWVudFBhcmVudC5jbGllbnRXaWR0aCxcbiAgICAgICAgICAgIG5vcm1hbGl6ZWRZICogdGhpcy52aWRlb0VsZW1lbnRQYXJlbnQuY2xpZW50SGVpZ2h0XG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogbm9ybWFsaXplQW5kUXVhbnRpemVTaWduZWQgZm9yIHBsYXllckFzcGVjdFJhdGlvID4gdmlkZW9Bc3BlY3RSYXRpb1xuICAgICAqIEBwYXJhbSB4IC0geCBheGlzIHBvaW50XG4gICAgICogQHBhcmFtIHkgLSB5IGF4aXMgcG9pbnRcbiAgICAgKi9cbiAgICBub3JtYWxpemVBbmRRdWFudGl6ZVNpZ25lZFBsYXllckJpZ2dlcih4OiBudW1iZXIsIHk6IG51bWJlcikge1xuICAgICAgICBjb25zdCBub3JtYWxpemVkWCA9IHggLyAoMC41ICogdGhpcy52aWRlb0VsZW1lbnRQYXJlbnQuY2xpZW50V2lkdGgpO1xuICAgICAgICBjb25zdCBub3JtYWxpemVkWSA9XG4gICAgICAgICAgICAodGhpcy5yYXRpbyAqIHkpIC8gKDAuNSAqIHRoaXMudmlkZW9FbGVtZW50UGFyZW50LmNsaWVudEhlaWdodCk7XG4gICAgICAgIHJldHVybiBuZXcgTm9ybWFsaXplZFF1YW50aXplZFNpZ25lZENvb3JkKFxuICAgICAgICAgICAgbm9ybWFsaXplZFggKiAzMjc2NyxcbiAgICAgICAgICAgIG5vcm1hbGl6ZWRZICogMzI3NjdcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBub3JtYWxpemVBbmRRdWFudGl6ZVVuc2lnbmVkIGZvciBwbGF5ZXJBc3BlY3RSYXRpbyA8PSB2aWRlb0FzcGVjdFJhdGlvXG4gICAgICogQHBhcmFtIHggLSB4IGF4aXMgcG9pbnRcbiAgICAgKiBAcGFyYW0geSAtIHkgYXhpcyBwb2ludFxuICAgICAqL1xuICAgIG5vcm1hbGl6ZUFuZFF1YW50aXplVW5zaWduZWRQbGF5ZXJTbWFsbGVyKHg6IG51bWJlciwgeTogbnVtYmVyKSB7XG4gICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRYID1cbiAgICAgICAgICAgIHRoaXMucmF0aW8gKiAoeCAvIHRoaXMudmlkZW9FbGVtZW50UGFyZW50LmNsaWVudFdpZHRoIC0gMC41KSArIDAuNTtcbiAgICAgICAgY29uc3Qgbm9ybWFsaXplZFkgPSB5IC8gdGhpcy52aWRlb0VsZW1lbnRQYXJlbnQuY2xpZW50SGVpZ2h0O1xuICAgICAgICBpZiAoXG4gICAgICAgICAgICBub3JtYWxpemVkWCA8IDAuMCB8fFxuICAgICAgICAgICAgbm9ybWFsaXplZFggPiAxLjAgfHxcbiAgICAgICAgICAgIG5vcm1hbGl6ZWRZIDwgMC4wIHx8XG4gICAgICAgICAgICBub3JtYWxpemVkWSA+IDEuMFxuICAgICAgICApIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgTm9ybWFsaXplZFF1YW50aXplZFVuc2lnbmVkQ29vcmQoZmFsc2UsIDY1NTM1LCA2NTUzNSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IE5vcm1hbGl6ZWRRdWFudGl6ZWRVbnNpZ25lZENvb3JkKFxuICAgICAgICAgICAgICAgIHRydWUsXG4gICAgICAgICAgICAgICAgbm9ybWFsaXplZFggKiA2NTUzNixcbiAgICAgICAgICAgICAgICBub3JtYWxpemVkWSAqIDY1NTM2XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogdW5xdWFudGl6ZUFuZERlbm9ybWFsaXplVW5zaWduZWQgZm9yIHBsYXllckFzcGVjdFJhdGlvIDw9IHZpZGVvQXNwZWN0UmF0aW9cbiAgICAgKiBAcGFyYW0geCAtIHggYXhpcyBwb2ludFxuICAgICAqIEBwYXJhbSB5IC0geSBheGlzIHBvaW50XG4gICAgICovXG4gICAgZGVub3JtYWxpemVBbmRVbnF1YW50aXplVW5zaWduZWRQbGF5ZXJTbWFsbGVyKHg6IG51bWJlciwgeTogbnVtYmVyKSB7XG4gICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRYID0gKHggLyA2NTUzNiAtIDAuNSkgLyB0aGlzLnJhdGlvICsgMC41O1xuICAgICAgICBjb25zdCBub3JtYWxpemVkWSA9IHkgLyA2NTUzNjtcbiAgICAgICAgcmV0dXJuIG5ldyBVbnF1YW50aXplZERlbm9ybWFsaXplZFVuc2lnbmVkQ29vcmQoXG4gICAgICAgICAgICBub3JtYWxpemVkWCAqIHRoaXMudmlkZW9FbGVtZW50UGFyZW50LmNsaWVudFdpZHRoLFxuICAgICAgICAgICAgbm9ybWFsaXplZFkgKiB0aGlzLnZpZGVvRWxlbWVudFBhcmVudC5jbGllbnRIZWlnaHRcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBub3JtYWxpemVBbmRRdWFudGl6ZVNpZ25lZCBmb3IgcGxheWVyQXNwZWN0UmF0aW8gPD0gdmlkZW9Bc3BlY3RSYXRpb1xuICAgICAqIEBwYXJhbSB4IC0geCBheGlzIHBvaW50XG4gICAgICogQHBhcmFtIHkgLSB5IGF4aXMgcG9pbnRcbiAgICAgKi9cbiAgICBub3JtYWxpemVBbmRRdWFudGl6ZVNpZ25lZFBsYXllclNtYWxsZXIoeDogbnVtYmVyLCB5OiBudW1iZXIpIHtcbiAgICAgICAgY29uc3Qgbm9ybWFsaXplZFggPVxuICAgICAgICAgICAgKHRoaXMucmF0aW8gKiB4KSAvICgwLjUgKiB0aGlzLnZpZGVvRWxlbWVudFBhcmVudC5jbGllbnRXaWR0aCk7XG4gICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRZID0geSAvICgwLjUgKiB0aGlzLnZpZGVvRWxlbWVudFBhcmVudC5jbGllbnRIZWlnaHQpO1xuICAgICAgICByZXR1cm4gbmV3IE5vcm1hbGl6ZWRRdWFudGl6ZWRTaWduZWRDb29yZChcbiAgICAgICAgICAgIG5vcm1hbGl6ZWRYICogMzI3NjcsXG4gICAgICAgICAgICBub3JtYWxpemVkWSAqIDMyNzY3XG4gICAgICAgICk7XG4gICAgfVxufVxuXG4vKipcbiAqIEEgY2xhc3MgZm9yIE5vcm1hbGl6ZUFuZFF1YW50aXplVW5zaWduZWQgb2JqZWN0c1xuICovXG5leHBvcnQgY2xhc3MgTm9ybWFsaXplZFF1YW50aXplZFVuc2lnbmVkQ29vcmQge1xuICAgIGluUmFuZ2U6IGJvb2xlYW47XG4gICAgeDogbnVtYmVyO1xuICAgIHk6IG51bWJlcjtcblxuICAgIGNvbnN0cnVjdG9yKGluUmFuZ2U6IGJvb2xlYW4sIHg6IG51bWJlciwgeTogbnVtYmVyKSB7XG4gICAgICAgIHRoaXMuaW5SYW5nZSA9IGluUmFuZ2U7XG4gICAgICAgIHRoaXMueCA9IHg7XG4gICAgICAgIHRoaXMueSA9IHk7XG4gICAgfVxufVxuXG4vKipcbiAqIEEgY2xhc3MgZm9yIFVucXVhbnRpemVkQW5kRGVub3JtYWxpemVVbnNpZ25lZCBvYmplY3RzXG4gKi9cbmV4cG9ydCBjbGFzcyBVbnF1YW50aXplZERlbm9ybWFsaXplZFVuc2lnbmVkQ29vcmQge1xuICAgIHg6IG51bWJlcjtcbiAgICB5OiBudW1iZXI7XG5cbiAgICBjb25zdHJ1Y3Rvcih4OiBudW1iZXIsIHk6IG51bWJlcikge1xuICAgICAgICB0aGlzLnggPSB4O1xuICAgICAgICB0aGlzLnkgPSB5O1xuICAgIH1cbn1cblxuLyoqXG4gKiBBIGNsYXNzIGZvciBOb3JtYWxpemVkUXVhbnRpemVkU2lnbmVkQ29vcmQgb2JqZWN0c1xuICovXG5leHBvcnQgY2xhc3MgTm9ybWFsaXplZFF1YW50aXplZFNpZ25lZENvb3JkIHtcbiAgICB4OiBudW1iZXI7XG4gICAgeTogbnVtYmVyO1xuXG4gICAgY29uc3RydWN0b3IoeDogbnVtYmVyLCB5OiBudW1iZXIpIHtcbiAgICAgICAgdGhpcy54ID0geDtcbiAgICAgICAgdGhpcy55ID0geTtcbiAgICB9XG59XG4iLCJpbXBvcnQge1xuICAgIEZsYWdzSWRzLFxuICAgIE51bWVyaWNQYXJhbWV0ZXJzSWRzLFxuICAgIE9wdGlvblBhcmFtZXRlcnNJZHMsXG4gICAgVGV4dFBhcmFtZXRlcnNJZHNcbn0gZnJvbSAnLi4vQ29uZmlnL0NvbmZpZyc7XG5pbXBvcnQgeyBMYXRlbmN5VGVzdFJlc3VsdHMgfSBmcm9tICcuLi9EYXRhQ2hhbm5lbC9MYXRlbmN5VGVzdFJlc3VsdHMnO1xuaW1wb3J0IHsgQWdncmVnYXRlZFN0YXRzIH0gZnJvbSAnLi4vUGVlckNvbm5lY3Rpb25Db250cm9sbGVyL0FnZ3JlZ2F0ZWRTdGF0cyc7XG5pbXBvcnQgeyBJbml0aWFsU2V0dGluZ3MgfSBmcm9tICcuLi9waXhlbHN0cmVhbWluZ2Zyb250ZW5kJztcbmltcG9ydCB7IE1lc3NhZ2VTdHJlYW1lckxpc3QgfSBmcm9tICcuLi9XZWJTb2NrZXRzL01lc3NhZ2VSZWNlaXZlJztcbmltcG9ydCB7IFNldHRpbmdGbGFnIH0gZnJvbSAnLi4vQ29uZmlnL1NldHRpbmdGbGFnJztcbmltcG9ydCB7IFNldHRpbmdOdW1iZXIgfSBmcm9tICcuLi9Db25maWcvU2V0dGluZ051bWJlcic7XG5pbXBvcnQgeyBTZXR0aW5nVGV4dCB9IGZyb20gJy4uL0NvbmZpZy9TZXR0aW5nVGV4dCc7XG5pbXBvcnQgeyBTZXR0aW5nT3B0aW9uIH0gZnJvbSAnLi4vQ29uZmlnL1NldHRpbmdPcHRpb24nO1xuaW1wb3J0IHtcbiAgICBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVzcG9uc2UsXG4gICAgRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFJlc3VsdFxufSBmcm9tIFwiLi4vRGF0YUNoYW5uZWwvRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFJlc3VsdHNcIjtcblxuLyoqXG4gKiBBbiBldmVudCB0aGF0IGlzIGVtaXR0ZWQgd2hlbiBBRksgZGlzY29ubmVjdCBpcyBhYm91dCB0byBoYXBwZW4uXG4gKiBDYW4gYmUgY2FuY2VsbGVkIGJ5IGNhbGxpbmcgdGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHByb3ZpZGVkIGFzIHBhcnQgb2YgdGhlIGV2ZW50LlxuICovXG5leHBvcnQgY2xhc3MgQWZrV2FybmluZ0FjdGl2YXRlRXZlbnQgZXh0ZW5kcyBFdmVudCB7XG4gICAgcmVhZG9ubHkgdHlwZTogJ2Fma1dhcm5pbmdBY3RpdmF0ZSc7XG4gICAgcmVhZG9ubHkgZGF0YToge1xuICAgICAgICAvKiogSG93IG1hbnkgc2Vjb25kcyB1bnRpbCB0aGUgc2Vzc2lvbiBpcyBkaXNjb25uZWN0ZWQgKi9cbiAgICAgICAgY291bnREb3duOiBudW1iZXI7XG4gICAgICAgIC8qKiBDYWxsYmFjayBmdW5jdGlvbiB0aGF0IG5lZWRzIHRvIGJlIGNhbGxlZCBpZiB5b3Ugd2lzaCB0byBjYW5jZWwgdGhlIEFGSyBkaXNjb25uZWN0IHRpbWVvdXQuICovXG4gICAgICAgIGRpc21pc3NBZms6ICgpID0+IHZvaWQ7XG4gICAgfTtcbiAgICBjb25zdHJ1Y3RvcihkYXRhOiBBZmtXYXJuaW5nQWN0aXZhdGVFdmVudFsnZGF0YSddKSB7XG4gICAgICAgIHN1cGVyKCdhZmtXYXJuaW5nQWN0aXZhdGUnKTtcbiAgICAgICAgdGhpcy5kYXRhID0gZGF0YTtcbiAgICB9XG59XG5cbi8qKlxuICogQW4gZXZlbnQgdGhhdCBpcyBlbWl0dGVkIHdoZW4gdGhlIEFGSyBkaXNjb25uZWN0IGNvdW50ZG93biBpcyB1cGRhdGVkLlxuICovXG5leHBvcnQgY2xhc3MgQWZrV2FybmluZ1VwZGF0ZUV2ZW50IGV4dGVuZHMgRXZlbnQge1xuICAgIHJlYWRvbmx5IHR5cGU6ICdhZmtXYXJuaW5nVXBkYXRlJztcbiAgICByZWFkb25seSBkYXRhOiB7XG4gICAgICAgIC8qKiBIb3cgbWFueSBzZWNvbmRzIHVudGlsIHRoZSBzZXNzaW9uIGlzIGRpc2Nvbm5lY3RlZCAqL1xuICAgICAgICBjb3VudERvd246IG51bWJlclxuICAgIH07XG4gICAgY29uc3RydWN0b3IoZGF0YTogQWZrV2FybmluZ1VwZGF0ZUV2ZW50WydkYXRhJ10pIHtcbiAgICAgICAgc3VwZXIoJ2Fma1dhcm5pbmdVcGRhdGUnKTtcbiAgICAgICAgdGhpcy5kYXRhID0gZGF0YTtcbiAgICB9XG59XG5cbi8qKlxuICogQW4gZXZlbnQgdGhhdCBpcyBlbWl0dGVkIHdoZW4gQUZLIHdhcm5pbmcgaXMgZGVhY3RpdmF0ZWQuXG4gKi9cbmV4cG9ydCBjbGFzcyBBZmtXYXJuaW5nRGVhY3RpdmF0ZUV2ZW50IGV4dGVuZHMgRXZlbnQge1xuICAgIHJlYWRvbmx5IHR5cGU6ICdhZmtXYXJuaW5nRGVhY3RpdmF0ZSc7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKCdhZmtXYXJuaW5nRGVhY3RpdmF0ZScpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBBbiBldmVudCB0aGF0IGlzIGVtaXR0ZWQgd2hlbiBBRksgY291bnRkb3duIHJlYWNoZXMgMCBhbmQgdGhlIHVzZXIgaXMgZGlzY29ubmVjdGVkLlxuICovXG5leHBvcnQgY2xhc3MgQWZrVGltZWRPdXRFdmVudCBleHRlbmRzIEV2ZW50IHtcbiAgICByZWFkb25seSB0eXBlOiAnYWZrVGltZWRPdXQnO1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlcignYWZrVGltZWRPdXQnKTtcbiAgICB9XG59XG5cbi8qKlxuICogQW4gZXZlbnQgdGhhdCBpcyBlbWl0dGVkIHdoZW4gd2UgcmVjZWl2ZSBuZXcgdmlkZW8gcXVhbGl0eSB2YWx1ZS5cbiAqL1xuZXhwb3J0IGNsYXNzIFZpZGVvRW5jb2RlckF2Z1FQRXZlbnQgZXh0ZW5kcyBFdmVudCB7XG4gICAgcmVhZG9ubHkgdHlwZTogJ3ZpZGVvRW5jb2RlckF2Z1FQJztcbiAgICByZWFkb25seSBkYXRhOiB7XG4gICAgICAgIC8qKiBBdmVyYWdlIHZpZGVvIHF1YWxpdHkgdmFsdWUgKi9cbiAgICAgICAgYXZnUVA6IG51bWJlclxuICAgIH07XG4gICAgY29uc3RydWN0b3IoZGF0YTogVmlkZW9FbmNvZGVyQXZnUVBFdmVudFsnZGF0YSddKSB7XG4gICAgICAgIHN1cGVyKCd2aWRlb0VuY29kZXJBdmdRUCcpO1xuICAgICAgICB0aGlzLmRhdGEgPSBkYXRhO1xuICAgIH1cbn1cblxuLyoqXG4gKiBBbiBldmVudCB0aGF0IGlzIGVtaXR0ZWQgYWZ0ZXIgYSBXZWJSdGMgY29ubmVjdGlvbiBoYXMgYmVlbiBuZWdvdGlhdGVkLiBcbiAqL1xuZXhwb3J0IGNsYXNzIFdlYlJ0Y1NkcEV2ZW50IGV4dGVuZHMgRXZlbnQge1xuICAgIHJlYWRvbmx5IHR5cGU6ICd3ZWJSdGNTZHAnO1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlcignd2ViUnRjU2RwJyk7XG4gICAgfVxufVxuXG4vKipcbiAqIEFuIGV2ZW50IHRoYXQgaXMgZW1pdHRlZCB3aGVuIGF1dG8gY29ubmVjdGluZy5cbiAqL1xuZXhwb3J0IGNsYXNzIFdlYlJ0Y0F1dG9Db25uZWN0RXZlbnQgZXh0ZW5kcyBFdmVudCB7XG4gICAgcmVhZG9ubHkgdHlwZTogJ3dlYlJ0Y0F1dG9Db25uZWN0JztcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgc3VwZXIoJ3dlYlJ0Y0F1dG9Db25uZWN0Jyk7XG4gICAgfVxufVxuXG4vKipcbiAqIEFuIGV2ZW50IHRoYXQgaXMgZW1pdHRlZCB3aGVuIHNlbmRpbmcgYSBXZWJSdGMgb2ZmZXIuXG4gKi9cbmV4cG9ydCBjbGFzcyBXZWJSdGNDb25uZWN0aW5nRXZlbnQgZXh0ZW5kcyBFdmVudCB7XG4gICAgcmVhZG9ubHkgdHlwZTogJ3dlYlJ0Y0Nvbm5lY3RpbmcnO1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlcignd2ViUnRjQ29ubmVjdGluZycpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBBbiBldmVudCB0aGF0IGlzIGVtaXR0ZWQgd2hlbiBXZWJSdGMgY29ubmVjdGlvbiBoYXMgYmVlbiBlc3RhYmxpc2hlZC5cbiAqL1xuZXhwb3J0IGNsYXNzIFdlYlJ0Y0Nvbm5lY3RlZEV2ZW50IGV4dGVuZHMgRXZlbnQge1xuICAgIHJlYWRvbmx5IHR5cGU6ICd3ZWJSdGNDb25uZWN0ZWQnO1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlcignd2ViUnRjQ29ubmVjdGVkJyk7XG4gICAgfVxufVxuXG4vKipcbiAqIEFuIGV2ZW50IHRoYXQgaXMgZW1pdHRlZCBpZiBXZWJSdGMgY29ubmVjdGlvbiBoYXMgZmFpbGVkLlxuICovXG5leHBvcnQgY2xhc3MgV2ViUnRjRmFpbGVkRXZlbnQgZXh0ZW5kcyBFdmVudCB7XG4gICAgcmVhZG9ubHkgdHlwZTogJ3dlYlJ0Y0ZhaWxlZCc7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKCd3ZWJSdGNGYWlsZWQnKTtcbiAgICB9XG59XG5cbi8qKlxuICogQW4gZXZlbnQgdGhhdCBpcyBlbWl0dGVkIGlmIFdlYlJ0YyBjb25uZWN0aW9uIGlzIGRpc2Nvbm5lY3RlZC5cbiAqL1xuZXhwb3J0IGNsYXNzIFdlYlJ0Y0Rpc2Nvbm5lY3RlZEV2ZW50IGV4dGVuZHMgRXZlbnQge1xuICAgIHJlYWRvbmx5IHR5cGU6ICd3ZWJSdGNEaXNjb25uZWN0ZWQnO1xuICAgIHJlYWRvbmx5IGRhdGE6IHtcbiAgICAgICAgLyoqIE1lc3NhZ2UgZGVzY3JpYmluZyB0aGUgZGlzY29ubmVjdCByZWFzb24gKi9cbiAgICAgICAgZXZlbnRTdHJpbmc6IHN0cmluZztcbiAgICAgICAgLyoqIHRydWUgaWYgdGhlIHVzZXIgaXMgYWJsZSB0byByZWNvbm5lY3QsIGZhbHNlIGlmIGRpc2Nvbm5lY3RlZCBiZWNhdXNlIG9mIHVucmVjb3ZlcmFibGUgcmVhc29ucyBsaWtlIG5vdCBhYmxlIHRvIGNvbm5lY3QgdG8gdGhlIHNpZ25hbGluZyBzZXJ2ZXIgKi9cbiAgICAgICAgYWxsb3dDbGlja1RvUmVjb25uZWN0OiBib29sZWFuO1xuICAgIH07XG4gICAgY29uc3RydWN0b3IoZGF0YTogV2ViUnRjRGlzY29ubmVjdGVkRXZlbnRbJ2RhdGEnXSkge1xuICAgICAgICBzdXBlcignd2ViUnRjRGlzY29ubmVjdGVkJyk7XG4gICAgICAgIHRoaXMuZGF0YSA9IGRhdGE7XG4gICAgfVxufVxuXG4vKipcbiAqIEFuIGV2ZW50IHRoYXQgaXMgZW1pdHRlZCB3aGVuIFJUQ0RhdGFDaGFubmVsIGlzIG9wZW5lZC5cbiAqL1xuZXhwb3J0IGNsYXNzIERhdGFDaGFubmVsT3BlbkV2ZW50IGV4dGVuZHMgRXZlbnQge1xuICAgIHJlYWRvbmx5IHR5cGU6ICdkYXRhQ2hhbm5lbE9wZW4nO1xuICAgIHJlYWRvbmx5IGRhdGE6IHtcbiAgICAgICAgLyoqIERhdGEgY2hhbm5lbCBsYWJlbC4gT25lIG9mICdkYXRhY2hhbm5lbCcsICdzZW5kLWRhdGFjaGFubmVsJywgJ3JlY3YtZGF0YWNoYW5uZWwnICovXG4gICAgICAgIGxhYmVsOiBzdHJpbmc7XG4gICAgICAgIC8qKiBSVENEYXRhQ2hhbm5lbCBvbk9wZW4gZXZlbnQgKi9cbiAgICAgICAgZXZlbnQ6IEV2ZW50XG4gICAgfTtcbiAgICBjb25zdHJ1Y3RvcihkYXRhOiBEYXRhQ2hhbm5lbE9wZW5FdmVudFsnZGF0YSddKSB7XG4gICAgICAgIHN1cGVyKCdkYXRhQ2hhbm5lbE9wZW4nKTtcbiAgICAgICAgdGhpcy5kYXRhID0gZGF0YTtcbiAgICB9XG59XG5cbi8qKlxuICogQW4gZXZlbnQgdGhhdCBpcyBlbWl0dGVkIHdoZW4gUlRDRGF0YUNoYW5uZWwgaXMgY2xvc2VkLlxuICovXG5leHBvcnQgY2xhc3MgRGF0YUNoYW5uZWxDbG9zZUV2ZW50IGV4dGVuZHMgRXZlbnQge1xuICAgIHJlYWRvbmx5IHR5cGU6ICdkYXRhQ2hhbm5lbENsb3NlJztcbiAgICByZWFkb25seSBkYXRhOiB7XG4gICAgICAgIC8qKiBEYXRhIGNoYW5uZWwgbGFiZWwuIE9uZSBvZiAnZGF0YWNoYW5uZWwnLCAnc2VuZC1kYXRhY2hhbm5lbCcsICdyZWN2LWRhdGFjaGFubmVsJyAqL1xuICAgICAgICBsYWJlbDogc3RyaW5nO1xuICAgICAgICAvKiogUlRDRGF0YUNoYW5uZWwgb25DbG9zZSBldmVudCAqL1xuICAgICAgICBldmVudDogRXZlbnRcbiAgICB9O1xuICAgIGNvbnN0cnVjdG9yKGRhdGE6IERhdGFDaGFubmVsQ2xvc2VFdmVudFsnZGF0YSddKSB7XG4gICAgICAgIHN1cGVyKCdkYXRhQ2hhbm5lbENsb3NlJyk7XG4gICAgICAgIHRoaXMuZGF0YSA9IGRhdGE7XG4gICAgfVxufVxuXG4vKipcbiAqIEFuIGV2ZW50IHRoYXQgaXMgZW1pdHRlZCBvbiBSVENEYXRhQ2hhbm5lbCBlcnJvcnMuXG4gKi9cbmV4cG9ydCBjbGFzcyBEYXRhQ2hhbm5lbEVycm9yRXZlbnQgZXh0ZW5kcyBFdmVudCB7XG4gICAgcmVhZG9ubHkgdHlwZTogJ2RhdGFDaGFubmVsRXJyb3InO1xuICAgIHJlYWRvbmx5IGRhdGE6IHtcbiAgICAgICAgLyoqIERhdGEgY2hhbm5lbCBsYWJlbC4gT25lIG9mICdkYXRhY2hhbm5lbCcsICdzZW5kLWRhdGFjaGFubmVsJywgJ3JlY3YtZGF0YWNoYW5uZWwnICovXG4gICAgICAgIGxhYmVsOiBzdHJpbmc7XG4gICAgICAgIC8qKiBSVENEYXRhQ2hhbm5lbCBvbkVycm9yIGV2ZW50ICovXG4gICAgICAgIGV2ZW50OiBFdmVudFxuICAgIH07XG4gICAgY29uc3RydWN0b3IoZGF0YTogRGF0YUNoYW5uZWxFcnJvckV2ZW50WydkYXRhJ10pIHtcbiAgICAgICAgc3VwZXIoJ2RhdGFDaGFubmVsRXJyb3InKTtcbiAgICAgICAgdGhpcy5kYXRhID0gZGF0YTtcbiAgICB9XG59XG5cbi8qKlxuICogQW4gZXZlbnQgdGhhdCBpcyBlbWl0dGVkIHdoZW4gdGhlIHZpZGVvIHN0cmVhbSBoYXMgYmVlbiBpbml0aWFsaXplZC5cbiAqL1xuZXhwb3J0IGNsYXNzIFZpZGVvSW5pdGlhbGl6ZWRFdmVudCBleHRlbmRzIEV2ZW50IHtcbiAgICByZWFkb25seSB0eXBlOiAndmlkZW9Jbml0aWFsaXplZCc7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKCd2aWRlb0luaXRpYWxpemVkJyk7XG4gICAgfVxufVxuXG4vKipcbiAqIEFuIGV2ZW50IHRoYXQgaXMgZW1pdHRlZCB3aGVuIHZpZGVvIHN0cmVhbSBsb2FkaW5nIHN0YXJ0cy5cbiAqL1xuZXhwb3J0IGNsYXNzIFN0cmVhbUxvYWRpbmdFdmVudCBleHRlbmRzIEV2ZW50IHtcbiAgICByZWFkb25seSB0eXBlOiAnc3RyZWFtTG9hZGluZyc7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKCdzdHJlYW1Mb2FkaW5nJyk7XG4gICAgfVxufVxuXG4vKipcbiAqIEFuIGV2ZW50IHRoYXQgaXMgZW1pdHRlZCB3aGVuIHZpZGVvIHN0cmVhbSBsb2FkaW5nIGhhcyBmaW5pc2hlZC5cbiAqL1xuZXhwb3J0IGNsYXNzIFN0cmVhbVByZUNvbm5lY3RFdmVudCBleHRlbmRzIEV2ZW50IHtcbiAgICByZWFkb25seSB0eXBlOiAnc3RyZWFtQ29ubmVjdCc7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKCdzdHJlYW1Db25uZWN0Jyk7XG4gICAgfVxufVxuXG4vKipcbiAqIEFuIGV2ZW50IHRoYXQgaXMgZW1pdHRlZCB3aGVuIHZpZGVvIHN0cmVhbSBoYXMgc3RvcHBlZC5cbiAqL1xuZXhwb3J0IGNsYXNzIFN0cmVhbVByZURpc2Nvbm5lY3RFdmVudCBleHRlbmRzIEV2ZW50IHtcbiAgICByZWFkb25seSB0eXBlOiAnc3RyZWFtRGlzY29ubmVjdCc7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKCdzdHJlYW1EaXNjb25uZWN0Jyk7XG4gICAgfVxufVxuXG4vKipcbiAqIEFuIGV2ZW50IHRoYXQgaXMgZW1pdHRlZCB3aGVuIHZpZGVvIHN0cmVhbSBpcyByZWNvbm5lY3RpbmcuXG4gKi9cbmV4cG9ydCBjbGFzcyBTdHJlYW1SZWNvbm5lY3RFdmVudCBleHRlbmRzIEV2ZW50IHtcbiAgICByZWFkb25seSB0eXBlOiAnc3RyZWFtUmVjb25uZWN0JztcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgc3VwZXIoJ3N0cmVhbVJlY29ubmVjdCcpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBBbiBldmVudCB0aGF0IGlzIGVtaXR0ZWQgaWYgdGhlcmUgYXJlIGVycm9ycyBsb2FkaW5nIHRoZSB2aWRlbyBzdHJlYW0uXG4gKi9cbmV4cG9ydCBjbGFzcyBQbGF5U3RyZWFtRXJyb3JFdmVudCBleHRlbmRzIEV2ZW50IHtcbiAgICByZWFkb25seSB0eXBlOiAncGxheVN0cmVhbUVycm9yJztcbiAgICByZWFkb25seSBkYXRhOiB7XG4gICAgICAgIC8qKiBFcnJvciBtZXNzYWdlICovXG4gICAgICAgIG1lc3NhZ2U6IHN0cmluZ1xuICAgIH07XG4gICAgY29uc3RydWN0b3IoZGF0YTogUGxheVN0cmVhbUVycm9yRXZlbnRbJ2RhdGEnXSkge1xuICAgICAgICBzdXBlcigncGxheVN0cmVhbUVycm9yJyk7XG4gICAgICAgIHRoaXMuZGF0YSA9IGRhdGE7XG4gICAgfVxufVxuXG4vKipcbiAqIEFuIGV2ZW50IHRoYXQgaXMgZW1pdHRlZCBiZWZvcmUgdHJ5aW5nIHRvIHN0YXJ0IHZpZGVvIHBsYXliYWNrLlxuICovXG5leHBvcnQgY2xhc3MgUGxheVN0cmVhbUV2ZW50IGV4dGVuZHMgRXZlbnQge1xuICAgIHJlYWRvbmx5IHR5cGU6ICdwbGF5U3RyZWFtJztcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgc3VwZXIoJ3BsYXlTdHJlYW0nKTtcbiAgICB9XG59XG5cbi8qKlxuICogQW4gZXZlbnQgdGhhdCBpcyBlbWl0dGVkIGlmIHRoZSBicm93c2VyIHJlamVjdHMgdmlkZW8gcGxheWJhY2suIENhbiBoYXBwZW4gZm9yIGV4YW1wbGUgaWZcbiAqIHZpZGVvIGF1dG8tcGxheSB3aXRob3V0IHVzZXIgaW50ZXJhY3Rpb24gaXMgcmVmdXNlZCBieSB0aGUgYnJvd3Nlci5cbiAqL1xuZXhwb3J0IGNsYXNzIFBsYXlTdHJlYW1SZWplY3RlZEV2ZW50IGV4dGVuZHMgRXZlbnQge1xuICAgIHJlYWRvbmx5IHR5cGU6ICdwbGF5U3RyZWFtUmVqZWN0ZWQnO1xuICAgIHJlYWRvbmx5IGRhdGE6IHtcbiAgICAgICAgLyoqIFJlamVjdGlvbiByZWFzb24gKi9cbiAgICAgICAgcmVhc29uOiB1bmtub3duXG4gICAgfTtcbiAgICBjb25zdHJ1Y3RvcihkYXRhOiBQbGF5U3RyZWFtUmVqZWN0ZWRFdmVudFsnZGF0YSddKSB7XG4gICAgICAgIHN1cGVyKCdwbGF5U3RyZWFtUmVqZWN0ZWQnKTtcbiAgICAgICAgdGhpcy5kYXRhID0gZGF0YTtcbiAgICB9XG59XG5cbi8qKlxuICogQW4gZXZlbnQgdGhhdCBpcyBlbWl0dGVkIHdoZW4gcmVjZWl2aW5nIGEgZnVsbCBGcmVlemVGcmFtZSBpbWFnZSBmcm9tIFVFLlxuICovXG5leHBvcnQgY2xhc3MgTG9hZEZyZWV6ZUZyYW1lRXZlbnQgZXh0ZW5kcyBFdmVudCB7XG4gICAgcmVhZG9ubHkgdHlwZTogJ2xvYWRGcmVlemVGcmFtZSc7XG4gICAgcmVhZG9ubHkgZGF0YToge1xuICAgICAgICAvKiogdHJ1ZSBpZiBzaG91bGQgc2hvdyBjbGljay10by1wbGF5IG92ZXJsYXksIG5vdCB0aGUgZnJlZXplIGZyYW1lIGNvbnRlbnRzICovXG4gICAgICAgIHNob3VsZFNob3dQbGF5T3ZlcmxheTogYm9vbGVhbjtcbiAgICAgICAgLyoqIHRydWUgaWYgdGhlIHJlY2VpdmVkIGltYWdlIGlzIHZhbGlkICovXG4gICAgICAgIGlzVmFsaWQ6IGJvb2xlYW47XG4gICAgICAgIC8qKiBJbWFnZSBkYXRhLiBDYW4gYmUgZS5nLiBkaXNwbGF5ZWQgYnkgZW5jb2RpbmcgYXMgYSBkYXRhIHVybC4gKi9cbiAgICAgICAganBlZ0RhdGE/OiBVaW50OEFycmF5O1xuICAgIH07XG4gICAgY29uc3RydWN0b3IoZGF0YTogTG9hZEZyZWV6ZUZyYW1lRXZlbnRbJ2RhdGEnXSkge1xuICAgICAgICBzdXBlcignbG9hZEZyZWV6ZUZyYW1lJyk7XG4gICAgICAgIHRoaXMuZGF0YSA9IGRhdGE7XG4gICAgfVxufVxuXG4vKipcbiAqIEFuIGV2ZW50IHRoYXQgaXMgZW1pdHRlZCB3aGVuIHJlY2VpdmluZyBVbmZyZWV6ZUZyYW1lIG1lc3NhZ2UgZnJvbSBVRSBhbmQgdmlkZW8gcGxheWJhY2sgaXMgYWJvdXQgdG8gYmUgcmVzdW1lZC5cbiAqL1xuZXhwb3J0IGNsYXNzIEhpZGVGcmVlemVGcmFtZUV2ZW50IGV4dGVuZHMgRXZlbnQge1xuICAgIHJlYWRvbmx5IHR5cGU6ICdoaWRlRnJlZXplRnJhbWUnO1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlcignaGlkZUZyZWV6ZUZyYW1lJyk7XG4gICAgfVxufVxuXG4vKipcbiAqIEFuIGV2ZW50IHRoYXQgaXMgZW1pdHRlZCB3aGVuIHJlY2VpdmluZyBXZWJSVEMgc3RhdGlzdGljcy5cbiAqL1xuZXhwb3J0IGNsYXNzIFN0YXRzUmVjZWl2ZWRFdmVudCBleHRlbmRzIEV2ZW50IHtcbiAgICByZWFkb25seSB0eXBlOiAnc3RhdHNSZWNlaXZlZCc7XG4gICAgcmVhZG9ubHkgZGF0YToge1xuICAgICAgICAvKiogU3RhdGlzdGljcyBvYmplY3QgKi9cbiAgICAgICAgYWdncmVnYXRlZFN0YXRzOiBBZ2dyZWdhdGVkU3RhdHNcbiAgICB9O1xuICAgIGNvbnN0cnVjdG9yKGRhdGE6IFN0YXRzUmVjZWl2ZWRFdmVudFsnZGF0YSddKSB7XG4gICAgICAgIHN1cGVyKCdzdGF0c1JlY2VpdmVkJyk7XG4gICAgICAgIHRoaXMuZGF0YSA9IGRhdGE7XG4gICAgfVxufVxuXG4vKipcbiAqIEFuIGV2ZW50IHRoYXQgaXMgZW1pdHRlZCB3aGVuIHN0cmVhbWVyIGxpc3QgY2hhbmdlcy5cbiAqL1xuZXhwb3J0IGNsYXNzIFN0cmVhbWVyTGlzdE1lc3NhZ2VFdmVudCBleHRlbmRzIEV2ZW50IHtcbiAgICByZWFkb25seSB0eXBlOiAnc3RyZWFtZXJMaXN0TWVzc2FnZSc7XG4gICAgcmVhZG9ubHkgZGF0YToge1xuICAgICAgICAvKiogU3RyZWFtZXIgbGlzdCBtZXNzYWdlIGNvbnRhaW5pbmcgYW4gYXJyYXkgb2Ygc3RyZWFtZXIgaWRzICovXG4gICAgICAgIG1lc3NhZ2VTdHJlYW1lckxpc3Q6IE1lc3NhZ2VTdHJlYW1lckxpc3Q7XG4gICAgICAgIC8qKiBBdXRvLXNlbGVjdGVkIHN0cmVhbWVyIGZyb20gdGhlIGxpc3QsIG9yIG51bGwgaWYgdW5hYmxlIHRvIGF1dG8tc2VsZWN0IGFuZCB1c2VyIHNob3VsZCBiZSBwcm9tcHRlZCB0byBzZWxlY3QgKi9cbiAgICAgICAgYXV0b1NlbGVjdGVkU3RyZWFtZXJJZDogc3RyaW5nO1xuICAgICAgICAvKiogV2FudGVkIHN0cmVhbWVyIGlkIGZyb20gdmFyaW91cyBjb25maWd1cmF0aW9ucy4gKi9cbiAgICAgICAgd2FudGVkU3RyZWFtZXJJZDogc3RyaW5nO1xuICAgIH07XG4gICAgY29uc3RydWN0b3IoZGF0YTogU3RyZWFtZXJMaXN0TWVzc2FnZUV2ZW50WydkYXRhJ10pIHtcbiAgICAgICAgc3VwZXIoJ3N0cmVhbWVyTGlzdE1lc3NhZ2UnKTtcbiAgICAgICAgdGhpcy5kYXRhID0gZGF0YTtcbiAgICB9XG59XG5cbi8qKlxuICogQW4gZXZlbnQgdGhhdCBpcyBlbWl0dGVkIHdoZW4gcmVjZWl2aW5nIGxhdGVuY3kgdGVzdCByZXN1bHRzLlxuICovXG5leHBvcnQgY2xhc3MgTGF0ZW5jeVRlc3RSZXN1bHRFdmVudCBleHRlbmRzIEV2ZW50IHtcbiAgICByZWFkb25seSB0eXBlOiAnbGF0ZW5jeVRlc3RSZXN1bHQnO1xuICAgIHJlYWRvbmx5IGRhdGE6IHtcbiAgICAgICAgLyoqIExhdGVuY3kgdGVzdCByZXN1bHQgb2JqZWN0ICovXG4gICAgICAgIGxhdGVuY3lUaW1pbmdzOiBMYXRlbmN5VGVzdFJlc3VsdHNcbiAgICB9O1xuICAgIGNvbnN0cnVjdG9yKGRhdGE6IExhdGVuY3lUZXN0UmVzdWx0RXZlbnRbJ2RhdGEnXSkge1xuICAgICAgICBzdXBlcignbGF0ZW5jeVRlc3RSZXN1bHQnKTtcbiAgICAgICAgdGhpcy5kYXRhID0gZGF0YTtcbiAgICB9XG59XG5cbi8qKlxuICogQW4gZXZlbnQgdGhhdCBpcyBlbWl0dGVkIHdoZW4gcmVjZWl2aW5nIGRhdGEgY2hhbm5lbCBsYXRlbmN5IHRlc3QgcmVzcG9uc2UgZnJvbSBzZXJ2ZXIuXG4gKiBUaGlzIGV2ZW50IGlzIGhhbmRsZWQgYnkgRGF0YUNoYW5uZWxMYXRlbmN5VGVzdENvbnRyb2xsZXJcbiAqL1xuZXhwb3J0IGNsYXNzIERhdGFDaGFubmVsTGF0ZW5jeVRlc3RSZXNwb25zZUV2ZW50IGV4dGVuZHMgRXZlbnQge1xuICAgIHJlYWRvbmx5IHR5cGU6ICdkYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVzcG9uc2UnO1xuICAgIHJlYWRvbmx5IGRhdGE6IHtcbiAgICAgICAgLyoqIExhdGVuY3kgdGVzdCByZXN1bHQgb2JqZWN0ICovXG4gICAgICAgIHJlc3BvbnNlOiBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVzcG9uc2VcbiAgICB9O1xuICAgIGNvbnN0cnVjdG9yKGRhdGE6IERhdGFDaGFubmVsTGF0ZW5jeVRlc3RSZXNwb25zZUV2ZW50WydkYXRhJ10pIHtcbiAgICAgICAgc3VwZXIoJ2RhdGFDaGFubmVsTGF0ZW5jeVRlc3RSZXNwb25zZScpO1xuICAgICAgICB0aGlzLmRhdGEgPSBkYXRhO1xuICAgIH1cbn1cblxuLyoqXG4gKiBBbiBldmVudCB0aGF0IGlzIGVtaXR0ZWQgd2hlbiBkYXRhIGNoYW5uZWwgbGF0ZW5jeSB0ZXN0IHJlc3VsdHMgYXJlIHJlYWR5LlxuICovXG5leHBvcnQgY2xhc3MgRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFJlc3VsdEV2ZW50IGV4dGVuZHMgRXZlbnQge1xuICAgIHJlYWRvbmx5IHR5cGU6ICdkYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVzdWx0JztcbiAgICByZWFkb25seSBkYXRhOiB7XG4gICAgICAgIC8qKiBMYXRlbmN5IHRlc3QgcmVzdWx0IG9iamVjdCAqL1xuICAgICAgICByZXN1bHQ6IERhdGFDaGFubmVsTGF0ZW5jeVRlc3RSZXN1bHRcbiAgICB9O1xuICAgIGNvbnN0cnVjdG9yKGRhdGE6IERhdGFDaGFubmVsTGF0ZW5jeVRlc3RSZXN1bHRFdmVudFsnZGF0YSddKSB7XG4gICAgICAgIHN1cGVyKCdkYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVzdWx0Jyk7XG4gICAgICAgIHRoaXMuZGF0YSA9IGRhdGE7XG4gICAgfVxufVxuXG4vKipcbiAqIEFuIGV2ZW50IHRoYXQgaXMgZW1pdHRlZCB3aGVuIHJlY2VpdmluZyBpbml0aWFsIHNldHRpbmdzIGZyb20gVUUuXG4gKi9cbmV4cG9ydCBjbGFzcyBJbml0aWFsU2V0dGluZ3NFdmVudCBleHRlbmRzIEV2ZW50IHtcbiAgICByZWFkb25seSB0eXBlOiAnaW5pdGlhbFNldHRpbmdzJztcbiAgICByZWFkb25seSBkYXRhOiB7XG4gICAgICAgIC8qKiBJbml0aWFsIHNldHRpbmdzIGZyb20gVUUgKi9cbiAgICAgICAgc2V0dGluZ3M6IEluaXRpYWxTZXR0aW5nc1xuICAgIH07XG4gICAgY29uc3RydWN0b3IoZGF0YTogSW5pdGlhbFNldHRpbmdzRXZlbnRbJ2RhdGEnXSkge1xuICAgICAgICBzdXBlcignaW5pdGlhbFNldHRpbmdzJyk7XG4gICAgICAgIHRoaXMuZGF0YSA9IGRhdGE7XG4gICAgfVxufVxuXG5leHBvcnQgdHlwZSBTZXR0aW5nc0RhdGEgPVxuICAgIHwge1xuICAgICAgICAgIC8qKiBGbGFnIGlkICovXG4gICAgICAgICAgaWQ6IEZsYWdzSWRzO1xuICAgICAgICAgIHR5cGU6ICdmbGFnJztcbiAgICAgICAgICAvKiogRmxhZyB2YWx1ZSAqL1xuICAgICAgICAgIHZhbHVlOiBib29sZWFuO1xuICAgICAgICAgIC8qKiBTZXR0aW5nRmxhZyBvYmplY3QgKi9cbiAgICAgICAgICB0YXJnZXQ6IFNldHRpbmdGbGFnO1xuICAgICAgfVxuICAgIHwge1xuICAgICAgICAgIC8qKiBOdW1lcmljIHNldHRpbmcgaWQgKi9cbiAgICAgICAgICBpZDogTnVtZXJpY1BhcmFtZXRlcnNJZHM7XG4gICAgICAgICAgdHlwZTogJ251bWJlcic7XG4gICAgICAgICAgLyoqIE51bWVyaWMgc2V0dGluZyB2YWx1ZSAqL1xuICAgICAgICAgIHZhbHVlOiBudW1iZXI7XG4gICAgICAgICAgLyoqIFNldHRpbmdOdW1iZXIgb2JqZWN0ICovXG4gICAgICAgICAgdGFyZ2V0OiBTZXR0aW5nTnVtYmVyO1xuICAgICAgfVxuICAgIHwge1xuICAgICAgICAgIC8qKiBUZXh0IHNldHRpbmcgaWQgKi9cbiAgICAgICAgICBpZDogVGV4dFBhcmFtZXRlcnNJZHM7XG4gICAgICAgICAgdHlwZTogJ3RleHQnO1xuICAgICAgICAgIC8qKiBUZXh0IHNldHRpbmcgdmFsdWUgKi9cbiAgICAgICAgICB2YWx1ZTogc3RyaW5nO1xuICAgICAgICAgIC8qKiBTZXR0aW5nVGV4dCBvYmplY3QgKi9cbiAgICAgICAgICB0YXJnZXQ6IFNldHRpbmdUZXh0O1xuICAgICAgfVxuICAgIHwge1xuICAgICAgICAgIC8qKiBPcHRpb24gc2V0dGluZyBpZCAqL1xuICAgICAgICAgIGlkOiBPcHRpb25QYXJhbWV0ZXJzSWRzO1xuICAgICAgICAgIHR5cGU6ICdvcHRpb24nO1xuICAgICAgICAgIC8qKiBPcHRpb24gc2V0dGluZyBzZWxlY3RlZCB2YWx1ZSAqL1xuICAgICAgICAgIHZhbHVlOiBzdHJpbmc7XG4gICAgICAgICAgLyoqIFNldHRpbmdPcHRpb24gb2JqZWN0ICovXG4gICAgICAgICAgdGFyZ2V0OiBTZXR0aW5nT3B0aW9uO1xuICAgICAgfTtcblxuLyoqXG4gKiBBbiBldmVudCB0aGF0IGlzIGVtaXR0ZWQgd2hlbiBQaXhlbFN0cmVhbWluZyBzZXR0aW5ncyBjaGFuZ2UuXG4gKi9cbmV4cG9ydCBjbGFzcyBTZXR0aW5nc0NoYW5nZWRFdmVudCBleHRlbmRzIEV2ZW50IHtcbiAgICByZWFkb25seSB0eXBlOiAnc2V0dGluZ3NDaGFuZ2VkJztcbiAgICByZWFkb25seSBkYXRhOiBTZXR0aW5nc0RhdGE7XG4gICAgY29uc3RydWN0b3IoZGF0YTogU2V0dGluZ3NDaGFuZ2VkRXZlbnRbJ2RhdGEnXSkge1xuICAgICAgICBzdXBlcignc2V0dGluZ3NDaGFuZ2VkJyk7XG4gICAgICAgIHRoaXMuZGF0YSA9IGRhdGE7XG4gICAgfVxufVxuXG4vKipcbiAqIEV2ZW50IGVtaXR0ZWQgd2hlbiBhbiBYUiBTZXNzaW9uIHN0YXJ0c1xuICovXG5leHBvcnQgY2xhc3MgWHJTZXNzaW9uU3RhcnRlZEV2ZW50IGV4dGVuZHMgRXZlbnQge1xuICAgIHJlYWRvbmx5IHR5cGU6ICd4clNlc3Npb25TdGFydGVkJztcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgc3VwZXIoJ3hyU2Vzc2lvblN0YXJ0ZWQnKTtcbiAgICB9XG59XG5cbi8qKlxuICogRXZlbnQgZW1pdHRlZCB3aGVuIGFuIFhSIFNlc3Npb24gZW5kc1xuICovXG5leHBvcnQgY2xhc3MgWHJTZXNzaW9uRW5kZWRFdmVudCBleHRlbmRzIEV2ZW50IHtcbiAgICByZWFkb25seSB0eXBlOiAneHJTZXNzaW9uRW5kZWQnO1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlcigneHJTZXNzaW9uRW5kZWQnKTtcbiAgICB9XG59XG5cbmV4cG9ydCB0eXBlIFhyRnJhbWVEYXRhID0ge1xuICAgIC8qKiBUaGUgZnJhbWUgdGltZXN0YW1wICAqL1xuICAgIHRpbWU6IERPTUhpZ2hSZXNUaW1lU3RhbXA7XG4gICAgLyoqIFRoZSBYUkZyYW1lICovXG4gICAgZnJhbWU6IFhSRnJhbWU7XG59O1xuXG4vKipcbiAqIEV2ZW50IGVtaXR0ZWQgd2hlbiBhbiBYUiBGcmFtZSBpcyBjb21wbGV0ZVxuICovXG5leHBvcnQgY2xhc3MgWHJGcmFtZUV2ZW50IGV4dGVuZHMgRXZlbnQge1xuICAgIHJlYWRvbmx5IHR5cGU6ICd4ckZyYW1lJztcbiAgICByZWFkb25seSBkYXRhOiBYckZyYW1lRGF0YVxuICAgIGNvbnN0cnVjdG9yKGRhdGE6IFhyRnJhbWVFdmVudFsnZGF0YSddKSB7XG4gICAgICAgIHN1cGVyKCd4ckZyYW1lJyk7XG4gICAgICAgIHRoaXMuZGF0YSA9IGRhdGE7XG4gICAgfVxufVxuXG4vKipcbiAqIEFuIGV2ZW50IHRoYXQgaXMgZW1pdHRlZCB3aGVuIHJlY2VpdmluZyBhIHBsYXllciBjb3VudCBmcm9tIHRoZSBzaWduYWxsaW5nIHNlcnZlclxuICovXG5leHBvcnQgY2xhc3MgUGxheWVyQ291bnRFdmVudCBleHRlbmRzIEV2ZW50IHtcbiAgICByZWFkb25seSB0eXBlOiAncGxheWVyQ291bnQnO1xuICAgIHJlYWRvbmx5IGRhdGE6IHtcbiAgICAgICAgLyoqIGNvdW50IG9iamVjdCAqL1xuICAgICAgICBjb3VudDogbnVtYmVyXG4gICAgfTtcbiAgICBjb25zdHJ1Y3RvcihkYXRhOiBQbGF5ZXJDb3VudEV2ZW50WydkYXRhJ10pIHtcbiAgICAgICAgc3VwZXIoJ3BsYXllckNvdW50Jyk7XG4gICAgICAgIHRoaXMuZGF0YSA9IGRhdGE7XG4gICAgfVxufVxuXG5leHBvcnQgdHlwZSBQaXhlbFN0cmVhbWluZ0V2ZW50ID1cbiAgICB8IEFma1dhcm5pbmdBY3RpdmF0ZUV2ZW50XG4gICAgfCBBZmtXYXJuaW5nVXBkYXRlRXZlbnRcbiAgICB8IEFma1dhcm5pbmdEZWFjdGl2YXRlRXZlbnRcbiAgICB8IEFma1RpbWVkT3V0RXZlbnRcbiAgICB8IFZpZGVvRW5jb2RlckF2Z1FQRXZlbnRcbiAgICB8IFdlYlJ0Y1NkcEV2ZW50XG4gICAgfCBXZWJSdGNBdXRvQ29ubmVjdEV2ZW50XG4gICAgfCBXZWJSdGNDb25uZWN0aW5nRXZlbnRcbiAgICB8IFdlYlJ0Y0Nvbm5lY3RlZEV2ZW50XG4gICAgfCBXZWJSdGNGYWlsZWRFdmVudFxuICAgIHwgV2ViUnRjRGlzY29ubmVjdGVkRXZlbnRcbiAgICB8IERhdGFDaGFubmVsT3BlbkV2ZW50XG4gICAgfCBEYXRhQ2hhbm5lbENsb3NlRXZlbnRcbiAgICB8IERhdGFDaGFubmVsRXJyb3JFdmVudFxuICAgIHwgVmlkZW9Jbml0aWFsaXplZEV2ZW50XG4gICAgfCBTdHJlYW1Mb2FkaW5nRXZlbnRcbiAgICB8IFN0cmVhbVByZUNvbm5lY3RFdmVudFxuICAgIHwgU3RyZWFtUmVjb25uZWN0RXZlbnRcbiAgICB8IFN0cmVhbVByZURpc2Nvbm5lY3RFdmVudFxuICAgIHwgUGxheVN0cmVhbUVycm9yRXZlbnRcbiAgICB8IFBsYXlTdHJlYW1FdmVudFxuICAgIHwgUGxheVN0cmVhbVJlamVjdGVkRXZlbnRcbiAgICB8IExvYWRGcmVlemVGcmFtZUV2ZW50XG4gICAgfCBIaWRlRnJlZXplRnJhbWVFdmVudFxuICAgIHwgU3RhdHNSZWNlaXZlZEV2ZW50XG4gICAgfCBTdHJlYW1lckxpc3RNZXNzYWdlRXZlbnRcbiAgICB8IExhdGVuY3lUZXN0UmVzdWx0RXZlbnRcbiAgICB8IERhdGFDaGFubmVsTGF0ZW5jeVRlc3RSZXNwb25zZUV2ZW50XG4gICAgfCBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVzdWx0RXZlbnRcbiAgICB8IEluaXRpYWxTZXR0aW5nc0V2ZW50XG4gICAgfCBTZXR0aW5nc0NoYW5nZWRFdmVudFxuICAgIHwgWHJTZXNzaW9uU3RhcnRlZEV2ZW50XG4gICAgfCBYclNlc3Npb25FbmRlZEV2ZW50XG4gICAgfCBYckZyYW1lRXZlbnRcbiAgICB8IFBsYXllckNvdW50RXZlbnQ7XG5cbmV4cG9ydCBjbGFzcyBFdmVudEVtaXR0ZXIgZXh0ZW5kcyBFdmVudFRhcmdldCB7XG4gICAgLyoqXG4gICAgICogRGlzcGF0Y2ggYSBuZXcgZXZlbnQuXG4gICAgICogQHBhcmFtIGUgZXZlbnRcbiAgICAgKiBAcmV0dXJuc1xuICAgICAqL1xuICAgIHB1YmxpYyBkaXNwYXRjaEV2ZW50KGU6IFBpeGVsU3RyZWFtaW5nRXZlbnQpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHN1cGVyLmRpc3BhdGNoRXZlbnQoZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVnaXN0ZXIgYW4gZXZlbnQgaGFuZGxlci5cbiAgICAgKiBAcGFyYW0gdHlwZSBldmVudCBuYW1lXG4gICAgICogQHBhcmFtIGxpc3RlbmVyIGV2ZW50IGhhbmRsZXIgZnVuY3Rpb25cbiAgICAgKi9cbiAgICBwdWJsaWMgYWRkRXZlbnRMaXN0ZW5lcjxcbiAgICAgICAgVCBleHRlbmRzIFBpeGVsU3RyZWFtaW5nRXZlbnRbJ3R5cGUnXSxcbiAgICAgICAgRSBleHRlbmRzIFBpeGVsU3RyZWFtaW5nRXZlbnQgJiB7IHR5cGU6IFQgfVxuICAgID4odHlwZTogVCwgbGlzdGVuZXI6IChlOiBFdmVudCAmIEUpID0+IHZvaWQpIHtcbiAgICAgICAgc3VwZXIuYWRkRXZlbnRMaXN0ZW5lcih0eXBlLCBsaXN0ZW5lcik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlIGFuIGV2ZW50IGhhbmRsZXIuXG4gICAgICogQHBhcmFtIHR5cGUgZXZlbnQgbmFtZVxuICAgICAqIEBwYXJhbSBsaXN0ZW5lciBldmVudCBoYW5kbGVyIGZ1bmN0aW9uXG4gICAgICovXG4gICAgcHVibGljIHJlbW92ZUV2ZW50TGlzdGVuZXI8XG4gICAgICAgIFQgZXh0ZW5kcyBQaXhlbFN0cmVhbWluZ0V2ZW50Wyd0eXBlJ10sXG4gICAgICAgIEUgZXh0ZW5kcyBQaXhlbFN0cmVhbWluZ0V2ZW50ICYgeyB0eXBlOiBUIH1cbiAgICA+KHR5cGU6IFQsIGxpc3RlbmVyOiAoZTogRXZlbnQgJiBFKSA9PiB2b2lkKSB7XG4gICAgICAgIHN1cGVyLnJlbW92ZUV2ZW50TGlzdGVuZXIodHlwZSwgbGlzdGVuZXIpO1xuICAgIH1cbn1cbiIsIi8vIENvcHlyaWdodCBFcGljIEdhbWVzLCBJbmMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG5cbmV4cG9ydCB0eXBlIFVucmVnaXN0ZXJGdW5jdGlvbiA9ICgpID0+IHZvaWQ7XG5cbmV4cG9ydCBjbGFzcyBFdmVudExpc3RlbmVyVHJhY2tlciB7XG4gICAgcHJpdmF0ZSB1bnJlZ2lzdGVyQ2FsbGJhY2tzOiBVbnJlZ2lzdGVyRnVuY3Rpb25bXTtcblxuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLnVucmVnaXN0ZXJDYWxsYmFja3MgPSBbXTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBZGQgYSBuZXcgY2FsbGJhY2sgdGhhdCBpcyBleGVjdXRlZCB3aGVuIHVucmVnaXN0ZXJBbGwgaXMgY2FsbGVkLlxuICAgICAqIEBwYXJhbSBjYWxsYmFjayBcbiAgICAgKi9cbiAgICBhZGRVbnJlZ2lzdGVyQ2FsbGJhY2soY2FsbGJhY2s6IFVucmVnaXN0ZXJGdW5jdGlvbikge1xuICAgICAgICB0aGlzLnVucmVnaXN0ZXJDYWxsYmFja3MucHVzaChjYWxsYmFjayk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRXhlY3V0ZSBhbGwgY2FsbGJhY2tzIGFuZCBjbGVhciB0aGUgbGlzdC5cbiAgICAgKi9cbiAgICB1bnJlZ2lzdGVyQWxsKCkge1xuICAgICAgICBmb3IgKGNvbnN0IGNhbGxiYWNrIG9mIHRoaXMudW5yZWdpc3RlckNhbGxiYWNrcykge1xuICAgICAgICAgICAgY2FsbGJhY2soKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnVucmVnaXN0ZXJDYWxsYmFja3MgPSBbXTtcbiAgICB9XG59XG4iLCIvLyBDb3B5cmlnaHQgRXBpYyBHYW1lcywgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuXG5pbXBvcnQgeyBMb2dnZXIgfSBmcm9tICcuLi9Mb2dnZXIvTG9nZ2VyJztcblxuLyoqXG4gKiBVdGlsaXR5IGZ1bmN0aW9uIGZvciBwb3B1bGF0ZSBmaWxlIGluZm9ybWF0aW9uIGZyb20gYnl0ZSBidWZmZXJzLlxuICovXG5leHBvcnQgY2xhc3MgRmlsZVV0aWwge1xuICAgIC8qKlxuICAgICAqIFByb2Nlc3NlcyBhIGZpbGVzIGV4dGVuc2lvbiB3aGVuIHJlY2VpdmVkIG92ZXIgZGF0YSBjaGFubmVsXG4gICAgICogQHBhcmFtIHZpZXcgLSB0aGUgZmlsZSBleHRlbnNpb24gZGF0YVxuICAgICAqL1xuICAgIHN0YXRpYyBzZXRFeHRlbnNpb25Gcm9tQnl0ZXModmlldzogVWludDhBcnJheSwgZmlsZTogRmlsZVRlbXBsYXRlKSB7XG4gICAgICAgIC8vIFJlc2V0IGZpbGUgaWYgd2UgZ290IGEgZmlsZSBtZXNzYWdlIGFuZCB3ZSBhcmUgbm90IFwicmVjZWl2aW5nXCIgaXQgeWV0XG4gICAgICAgIGlmICghZmlsZS5yZWNlaXZpbmcpIHtcbiAgICAgICAgICAgIGZpbGUubWltZXR5cGUgPSAnJztcbiAgICAgICAgICAgIGZpbGUuZXh0ZW5zaW9uID0gJyc7XG4gICAgICAgICAgICBmaWxlLnJlY2VpdmluZyA9IHRydWU7XG4gICAgICAgICAgICBmaWxlLnZhbGlkID0gZmFsc2U7XG4gICAgICAgICAgICBmaWxlLnNpemUgPSAwO1xuICAgICAgICAgICAgZmlsZS5kYXRhID0gW107XG4gICAgICAgICAgICBmaWxlLnRpbWVzdGFtcFN0YXJ0ID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG4gICAgICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgJ1JlY2VpdmVkIGZpcnN0IGNodW5rIG9mIGZpbGUnLFxuICAgICAgICAgICAgICAgIDZcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBleHRlbnNpb25Bc1N0cmluZyA9IG5ldyBUZXh0RGVjb2RlcigndXRmLTE2JykuZGVjb2RlKFxuICAgICAgICAgICAgdmlldy5zbGljZSgxKVxuICAgICAgICApO1xuICAgICAgICBMb2dnZXIuTG9nKExvZ2dlci5HZXRTdGFja1RyYWNlKCksIGV4dGVuc2lvbkFzU3RyaW5nLCA2KTtcbiAgICAgICAgZmlsZS5leHRlbnNpb24gPSBleHRlbnNpb25Bc1N0cmluZztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQcm9jZXNzZXMgYSBmaWxlcyBtaW1lIHR5cGUgd2hlbiByZWNlaXZlZCBvdmVyIGRhdGEgY2hhbm5lbFxuICAgICAqIEBwYXJhbSB2aWV3IC0gdGhlIGZpbGUgbWltZSB0eXBlIGRhdGFcbiAgICAgKi9cbiAgICBzdGF0aWMgc2V0TWltZVR5cGVGcm9tQnl0ZXModmlldzogVWludDhBcnJheSwgZmlsZTogRmlsZVRlbXBsYXRlKSB7XG4gICAgICAgIC8vIFJlc2V0IGZpbGUgaWYgd2UgZ290IGEgZmlsZSBtZXNzYWdlIGFuZCB3ZSBhcmUgbm90IFwicmVjZWl2aW5nXCIgaXQgeWV0XG4gICAgICAgIGlmICghZmlsZS5yZWNlaXZpbmcpIHtcbiAgICAgICAgICAgIGZpbGUubWltZXR5cGUgPSAnJztcbiAgICAgICAgICAgIGZpbGUuZXh0ZW5zaW9uID0gJyc7XG4gICAgICAgICAgICBmaWxlLnJlY2VpdmluZyA9IHRydWU7XG4gICAgICAgICAgICBmaWxlLnZhbGlkID0gZmFsc2U7XG4gICAgICAgICAgICBmaWxlLnNpemUgPSAwO1xuICAgICAgICAgICAgZmlsZS5kYXRhID0gW107XG4gICAgICAgICAgICBmaWxlLnRpbWVzdGFtcFN0YXJ0ID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG4gICAgICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgJ1JlY2VpdmVkIGZpcnN0IGNodW5rIG9mIGZpbGUnLFxuICAgICAgICAgICAgICAgIDZcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBtaW1lQXNTdHJpbmcgPSBuZXcgVGV4dERlY29kZXIoJ3V0Zi0xNicpLmRlY29kZSh2aWV3LnNsaWNlKDEpKTtcbiAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCBtaW1lQXNTdHJpbmcsIDYpO1xuICAgICAgICBmaWxlLm1pbWV0eXBlID0gbWltZUFzU3RyaW5nO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFByb2Nlc3NlcyBhIGZpbGVzIGNvbnRlbnRzIHdoZW4gcmVjZWl2ZWQgb3ZlciBkYXRhIGNoYW5uZWxcbiAgICAgKiBAcGFyYW0gdmlldyAtIHRoZSBmaWxlIGNvbnRlbnRzIGRhdGFcbiAgICAgKi9cbiAgICBzdGF0aWMgc2V0Q29udGVudHNGcm9tQnl0ZXModmlldzogVWludDhBcnJheSwgZmlsZTogRmlsZVRlbXBsYXRlKSB7XG4gICAgICAgIC8vIElmIHdlIGhhdmVuJ3QgcmVjZWl2ZWQgdGhlIGluaXRpYWwgc2V0dXAgaW5zdHJ1Y3Rpb25zLCByZXR1cm5cbiAgICAgICAgaWYgKCFmaWxlLnJlY2VpdmluZykgcmV0dXJuO1xuXG4gICAgICAgIC8vIEV4dHJhY3QgdGhlIHRvdGFsIHNpemUgb2YgdGhlIGZpbGUgKGFjcm9zcyBhbGwgY2h1bmtzKVxuICAgICAgICBmaWxlLnNpemUgPSBNYXRoLmNlaWwoXG4gICAgICAgICAgICBuZXcgRGF0YVZpZXcodmlldy5zbGljZSgxLCA1KS5idWZmZXIpLmdldEludDMyKDAsIHRydWUpIC9cbiAgICAgICAgICAgICAgICAxNjM3OSAvKiBUaGUgbWF4aW11bSBudW1iZXIgb2YgcGF5bG9hZCBiaXRzIHBlciBtZXNzYWdlKi9cbiAgICAgICAgKTtcblxuICAgICAgICAvLyBHZXQgdGhlIGZpbGUgcGFydCBvZiB0aGUgcGF5bG9hZFxuICAgICAgICBjb25zdCBmaWxlQnl0ZXMgPSB2aWV3LnNsaWNlKDEgKyA0KTtcblxuICAgICAgICAvLyBBcHBlbmQgdG8gZXhpc3RpbmcgZGF0YSB0aGF0IGhvbGRzIHRoZSBmaWxlXG4gICAgICAgIGZpbGUuZGF0YS5wdXNoKGZpbGVCeXRlcyk7XG5cbiAgICAgICAgLy8gVW5jb21tZW50IGZvciBkZWJ1Z1xuICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgIGBSZWNlaXZlZCBmaWxlIGNodW5rOiAke2ZpbGUuZGF0YS5sZW5ndGh9LyR7ZmlsZS5zaXplfWAsXG4gICAgICAgICAgICA2XG4gICAgICAgICk7XG5cbiAgICAgICAgaWYgKGZpbGUuZGF0YS5sZW5ndGggPT09IGZpbGUuc2l6ZSkge1xuICAgICAgICAgICAgZmlsZS5yZWNlaXZpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgIGZpbGUudmFsaWQgPSB0cnVlO1xuICAgICAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCAnUmVjZWl2ZWQgY29tcGxldGUgZmlsZScsIDYpO1xuICAgICAgICAgICAgY29uc3QgdHJhbnNmZXJEdXJhdGlvbiA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gZmlsZS50aW1lc3RhbXBTdGFydDtcbiAgICAgICAgICAgIGNvbnN0IHRyYW5zZmVyQml0cmF0ZSA9IE1hdGgucm91bmQoXG4gICAgICAgICAgICAgICAgKGZpbGUuc2l6ZSAqIDE2ICogMTAyNCkgLyB0cmFuc2ZlckR1cmF0aW9uXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgIGBBdmVyYWdlIHRyYW5zZmVyIGJpdHJhdGU6ICR7dHJhbnNmZXJCaXRyYXRlfWtiL3Mgb3ZlciAke1xuICAgICAgICAgICAgICAgICAgICB0cmFuc2ZlckR1cmF0aW9uIC8gMTAwMFxuICAgICAgICAgICAgICAgIH0gc2Vjb25kc2AsXG4gICAgICAgICAgICAgICAgNlxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgLy8gRmlsZSByZWNvbnN0cnVjdGlvblxuICAgICAgICAgICAgLyoqXG4gICAgICAgICAgICAgKiBFeGFtcGxlIGNvZGUgdG8gcmVjb25zdHJ1Y3QgdGhlIGZpbGVcbiAgICAgICAgICAgICAqXG4gICAgICAgICAgICAgKiBUaGlzIGNvZGUgcmVjb25zdHJ1Y3RzIHRoZSByZWNlaXZlZCBkYXRhIGludG8gdGhlIG9yaWdpbmFsIGZpbGUgYmFzZWQgb24gdGhlIG1pbWUgdHlwZSBhbmQgZXh0ZW5zaW9uIHByb3ZpZGVkIGFuZCB0aGVuIGRvd25sb2FkcyB0aGUgcmVjb25zdHJ1Y3RlZCBmaWxlXG4gICAgICAgICAgICAgKi9cbiAgICAgICAgICAgIGNvbnN0IHJlY2VpdmVkID0gbmV3IEJsb2IoZmlsZS5kYXRhLCB7IHR5cGU6IGZpbGUubWltZXR5cGUgfSk7XG4gICAgICAgICAgICBjb25zdCBhID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYScpO1xuICAgICAgICAgICAgYS5zZXRBdHRyaWJ1dGUoJ2hyZWYnLCBVUkwuY3JlYXRlT2JqZWN0VVJMKHJlY2VpdmVkKSk7XG4gICAgICAgICAgICBhLnNldEF0dHJpYnV0ZSgnZG93bmxvYWQnLCBgdHJhbnNmZXIuJHtmaWxlLmV4dGVuc2lvbn1gKTtcbiAgICAgICAgICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kKGEpO1xuICAgICAgICAgICAgLy8gaWYgeW91IGFyZSBzbyBpbmNsaW5lZCB0byBtYWtlIGl0IGF1dG8tZG93bmxvYWQsIGRvIHNvbWV0aGluZyBsaWtlOiBhLmNsaWNrKCk7XG4gICAgICAgICAgICBhLnJlbW92ZSgpO1xuICAgICAgICB9IGVsc2UgaWYgKGZpbGUuZGF0YS5sZW5ndGggPiBmaWxlLnNpemUpIHtcbiAgICAgICAgICAgIGZpbGUucmVjZWl2aW5nID0gZmFsc2U7XG4gICAgICAgICAgICBMb2dnZXIuRXJyb3IoXG4gICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICBgUmVjZWl2ZWQgYmlnZ2VyIGZpbGUgdGhhbiBhZHZlcnRpc2VkOiAke2ZpbGUuZGF0YS5sZW5ndGh9LyR7ZmlsZS5zaXplfWBcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbi8qKlxuICogQSBjbGFzcyB0aGF0IHJlcHJlc2VudHMgYSB0ZW1wbGF0ZSBmb3IgYSBkb3dubG9hZGVkIGZpbGVcbiAqL1xuZXhwb3J0IGNsYXNzIEZpbGVUZW1wbGF0ZSB7XG4gICAgbWltZXR5cGUgPSAnJztcbiAgICBleHRlbnNpb24gPSAnJztcbiAgICByZWNlaXZpbmcgPSBmYWxzZTtcbiAgICBzaXplID0gMDtcbiAgICBkYXRhOiBBcnJheTxVaW50OEFycmF5PiA9IFtdO1xuICAgIHZhbGlkID0gZmFsc2U7XG4gICAgdGltZXN0YW1wU3RhcnQ6IG51bWJlcjtcbn1cbiIsImV4cG9ydCBjbGFzcyBSVENVdGlscyB7XG4gICAgc3RhdGljIGlzVmlkZW9UcmFuc2NpZXZlcih0cmFuc2NlaXZlciA6IFJUQ1J0cFRyYW5zY2VpdmVyIHwgdW5kZWZpbmVkKSA6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5jYW5UcmFuc2NlaXZlclJlY2VpdmVWaWRlbyh0cmFuc2NlaXZlcikgfHwgdGhpcy5jYW5UcmFuc2NlaXZlclNlbmRWaWRlbyh0cmFuc2NlaXZlcik7XG4gICAgfVxuXG4gICAgc3RhdGljIGNhblRyYW5zY2VpdmVyUmVjZWl2ZVZpZGVvKHRyYW5zY2VpdmVyIDogUlRDUnRwVHJhbnNjZWl2ZXIgfCB1bmRlZmluZWQpIDogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiAhIXRyYW5zY2VpdmVyICYmXG4gICAgICAgICAgICAodHJhbnNjZWl2ZXIuZGlyZWN0aW9uID09PSAnc2VuZHJlY3YnIHx8IHRyYW5zY2VpdmVyLmRpcmVjdGlvbiA9PT0gJ3JlY3Zvbmx5JykgJiZcbiAgICAgICAgICAgIHRyYW5zY2VpdmVyLnJlY2VpdmVyICYmXG4gICAgICAgICAgICB0cmFuc2NlaXZlci5yZWNlaXZlci50cmFjayAmJlxuICAgICAgICAgICAgdHJhbnNjZWl2ZXIucmVjZWl2ZXIudHJhY2sua2luZCA9PT0gJ3ZpZGVvJzsgICAgXG4gICAgfVxuXG4gICAgc3RhdGljIGNhblRyYW5zY2VpdmVyU2VuZFZpZGVvKHRyYW5zY2VpdmVyIDogUlRDUnRwVHJhbnNjZWl2ZXIgfCB1bmRlZmluZWQpIDogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiAhIXRyYW5zY2VpdmVyICYmXG4gICAgICAgICAgICAodHJhbnNjZWl2ZXIuZGlyZWN0aW9uID09PSAnc2VuZHJlY3YnIHx8IHRyYW5zY2VpdmVyLmRpcmVjdGlvbiA9PT0gJ3NlbmRvbmx5JykgJiZcbiAgICAgICAgICAgIHRyYW5zY2VpdmVyLnNlbmRlciAmJlxuICAgICAgICAgICAgdHJhbnNjZWl2ZXIuc2VuZGVyLnRyYWNrICYmXG4gICAgICAgICAgICB0cmFuc2NlaXZlci5zZW5kZXIudHJhY2sua2luZCA9PT0gJ3ZpZGVvJzsgICAgXG4gICAgfVxuXG4gICAgc3RhdGljIGlzQXVkaW9UcmFuc2NpZXZlcih0cmFuc2NlaXZlciA6IFJUQ1J0cFRyYW5zY2VpdmVyIHwgdW5kZWZpbmVkKSA6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5jYW5UcmFuc2NlaXZlclJlY2VpdmVBdWRpbyh0cmFuc2NlaXZlcikgfHwgdGhpcy5jYW5UcmFuc2NlaXZlclNlbmRBdWRpbyh0cmFuc2NlaXZlcik7XG4gICAgfVxuXG4gICAgc3RhdGljIGNhblRyYW5zY2VpdmVyUmVjZWl2ZUF1ZGlvKHRyYW5zY2VpdmVyIDogUlRDUnRwVHJhbnNjZWl2ZXIgfCB1bmRlZmluZWQpIDogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiAhIXRyYW5zY2VpdmVyICYmXG4gICAgICAgICAgICAodHJhbnNjZWl2ZXIuZGlyZWN0aW9uID09PSAnc2VuZHJlY3YnIHx8IHRyYW5zY2VpdmVyLmRpcmVjdGlvbiA9PT0gJ3JlY3Zvbmx5JykgJiZcbiAgICAgICAgICAgIHRyYW5zY2VpdmVyLnJlY2VpdmVyICYmXG4gICAgICAgICAgICB0cmFuc2NlaXZlci5yZWNlaXZlci50cmFjayAmJlxuICAgICAgICAgICAgdHJhbnNjZWl2ZXIucmVjZWl2ZXIudHJhY2sua2luZCA9PT0gJ2F1ZGlvJzsgICAgXG4gICAgfVxuXG4gICAgc3RhdGljIGNhblRyYW5zY2VpdmVyU2VuZEF1ZGlvKHRyYW5zY2VpdmVyIDogUlRDUnRwVHJhbnNjZWl2ZXIgfCB1bmRlZmluZWQpIDogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiAhIXRyYW5zY2VpdmVyICYmXG4gICAgICAgICAgICAodHJhbnNjZWl2ZXIuZGlyZWN0aW9uID09PSAnc2VuZHJlY3YnIHx8IHRyYW5zY2VpdmVyLmRpcmVjdGlvbiA9PT0gJ3NlbmRvbmx5JykgJiZcbiAgICAgICAgICAgIHRyYW5zY2VpdmVyLnNlbmRlciAmJlxuICAgICAgICAgICAgdHJhbnNjZWl2ZXIuc2VuZGVyLnRyYWNrICYmXG4gICAgICAgICAgICB0cmFuc2NlaXZlci5zZW5kZXIudHJhY2sua2luZCA9PT0gJ2F1ZGlvJztcbiAgICB9XG59IiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuZXhwb3J0IGNsYXNzIFdlYkdMVXRpbHMge1xuICAgIHN0YXRpYyB2ZXJ0ZXhTaGFkZXIoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIGBcblx0XHRhdHRyaWJ1dGUgdmVjMiBhX3Bvc2l0aW9uO1xuXHRcdGF0dHJpYnV0ZSB2ZWMyIGFfdGV4Q29vcmQ7XG5cblx0XHQvLyBpbnB1dFxuXHRcdHVuaWZvcm0gdmVjMiB1X3Jlc29sdXRpb247XG5cdFx0dW5pZm9ybSB2ZWM0IHVfb2Zmc2V0O1xuXG5cdFx0Ly9cblx0XHR2YXJ5aW5nIHZlYzIgdl90ZXhDb29yZDtcblxuXHRcdHZvaWQgbWFpbigpIHtcblx0XHQgICAvLyBjb252ZXJ0IHRoZSByZWN0YW5nbGUgZnJvbSBwaXhlbHMgdG8gMC4wIHRvIDEuMFxuXHRcdCAgIHZlYzIgemVyb1RvT25lID0gYV9wb3NpdGlvbiAvIHVfcmVzb2x1dGlvbjtcblxuXHRcdCAgIC8vIGNvbnZlcnQgZnJvbSAwLT4xIHRvIDAtPjJcblx0XHQgICB2ZWMyIHplcm9Ub1R3byA9IHplcm9Ub09uZSAqIDIuMDtcblxuXHRcdCAgIC8vIGNvbnZlcnQgZnJvbSAwLT4yIHRvIC0xLT4rMSAoY2xpcHNwYWNlKVxuXHRcdCAgIHZlYzIgY2xpcFNwYWNlID0gemVyb1RvVHdvIC0gMS4wO1xuXG5cdFx0ICAgZ2xfUG9zaXRpb24gPSB2ZWM0KGNsaXBTcGFjZSAqIHZlYzIoMSwgLTEpLCAwLCAxKTtcblx0XHQgICAvLyBwYXNzIHRoZSB0ZXhDb29yZCB0byB0aGUgZnJhZ21lbnQgc2hhZGVyXG5cdFx0ICAgLy8gVGhlIEdQVSB3aWxsIGludGVycG9sYXRlIHRoaXMgdmFsdWUgYmV0d2VlbiBwb2ludHMuXG5cdFx0ICAgdl90ZXhDb29yZCA9IChhX3RleENvb3JkICogdV9vZmZzZXQueHkpICsgdV9vZmZzZXQuenc7XG5cdFx0fVxuXHRcdGA7XG4gICAgfVxuXG4gICAgc3RhdGljIGZyYWdtZW50U2hhZGVyKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiBgXG5cdFx0cHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7XG5cblx0XHQvLyBvdXIgdGV4dHVyZVxuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIHVfaW1hZ2U7XG5cblx0XHQvLyB0aGUgdGV4Q29vcmRzIHBhc3NlZCBpbiBmcm9tIHRoZSB2ZXJ0ZXggc2hhZGVyLlxuXHRcdHZhcnlpbmcgdmVjMiB2X3RleENvb3JkO1xuXG5cdFx0dm9pZCBtYWluKCkge1xuXHRcdCAgIGdsX0ZyYWdDb2xvciA9IHRleHR1cmUyRCh1X2ltYWdlLCB2X3RleENvb3JkKTtcblx0XHR9XG5cdFx0YDtcbiAgICB9XG59XG4iLCIvLyBDb3B5cmlnaHQgRXBpYyBHYW1lcywgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuXG5leHBvcnQgY2xhc3MgV2ViWFJVdGlscyB7XG4gICAgLyoqXG4gICAgICogRGVlcCBjb3BpZXMgYSBnYW1lcGFkJ3MgdmFsdWVzIGJ5IGZpcnN0IGNvbnZlcnRpbmcgaXQgdG8gYSBKU09OIG9iamVjdCBhbmQgdGhlbiBiYWNrIHRvIGEgZ2FtZXBhZFxuICAgICAqXG4gICAgICogQHBhcmFtIGdhbWVwYWQgdGhlIG9yaWdpbmFsIGdhbWVwYWRcbiAgICAgKiBAcmV0dXJucyBhIG5ldyBnYW1lcGFkIG9iamVjdCwgcG9wdWxhdGVkIHdpdGggdGhlIG9yaWdpbmFsIGdhbWVwYWRzIHZhbHVlc1xuICAgICAqL1xuICAgIHN0YXRpYyBkZWVwQ29weUdhbWVwYWQoZ2FtZXBhZDogR2FtZXBhZCk6IEdhbWVwYWQge1xuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShcbiAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICBidXR0b25zOiBnYW1lcGFkLmJ1dHRvbnMubWFwKChiKSA9PlxuICAgICAgICAgICAgICAgICAgICBKU09OLnBhcnNlKFxuICAgICAgICAgICAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByZXNzZWQ6IGIucHJlc3NlZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3VjaGVkOiBiLnRvdWNoZWRcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgIGF4ZXM6IGdhbWVwYWQuYXhlc1xuICAgICAgICAgICAgfSlcbiAgICAgICAgKTtcbiAgICB9XG59XG4iLCIvLyBDb3B5cmlnaHQgRXBpYyBHYW1lcywgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuXG5pbXBvcnQgeyBNb3VzZUNvbnRyb2xsZXIgfSBmcm9tICcuLi9JbnB1dHMvTW91c2VDb250cm9sbGVyJztcbmltcG9ydCB7IExvZ2dlciB9IGZyb20gJy4uL0xvZ2dlci9Mb2dnZXInO1xuaW1wb3J0IHsgVmlkZW9QbGF5ZXIgfSBmcm9tICcuL1ZpZGVvUGxheWVyJztcblxuLyoqXG4gKiBWaWRlbyBQbGF5ZXIgQ29udHJvbGxlciBoYW5kbGVzIHRoZSBjcmVhdGlvbiBvZiB0aGUgdmlkZW8gSFRNTCBlbGVtZW50IGFuZCBhbGwgaGFuZGxlcnNcbiAqL1xuZXhwb3J0IGNsYXNzIFN0cmVhbUNvbnRyb2xsZXIge1xuICAgIHZpZGVvRWxlbWVudFByb3ZpZGVyOiBWaWRlb1BsYXllcjtcbiAgICBhdWRpb0VsZW1lbnQ6IEhUTUxBdWRpb0VsZW1lbnQ7XG4gICAgbW91c2VDb250cm9sbGVyOiBNb3VzZUNvbnRyb2xsZXI7XG5cbiAgICAvKipcbiAgICAgKiBAcGFyYW0gdmlkZW9FbGVtZW50UHJvdmlkZXIgVmlkZW8gUGxheWVyIGluc3RhbmNlXG4gICAgICovXG4gICAgY29uc3RydWN0b3IodmlkZW9FbGVtZW50UHJvdmlkZXI6IFZpZGVvUGxheWVyKSB7XG4gICAgICAgIHRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIgPSB2aWRlb0VsZW1lbnRQcm92aWRlcjtcbiAgICAgICAgdGhpcy5hdWRpb0VsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdBdWRpbycpIGFzIEhUTUxBdWRpb0VsZW1lbnQ7XG4gICAgICAgIHRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIuc2V0QXVkaW9FbGVtZW50KHRoaXMuYXVkaW9FbGVtZW50KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGVzIHdoZW4gdGhlIFBlZXIgY29ubmVjdGlvbiBoYXMgYSB0cmFjayBldmVudFxuICAgICAqIEBwYXJhbSBydGNUcmFja0V2ZW50IC0gUlRDIFRyYWNrIEV2ZW50XG4gICAgICovXG4gICAgaGFuZGxlT25UcmFjayhydGNUcmFja0V2ZW50OiBSVENUcmFja0V2ZW50KSB7XG4gICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgJ2hhbmRsZU9uVHJhY2sgJyArIEpTT04uc3RyaW5naWZ5KHJ0Y1RyYWNrRXZlbnQuc3RyZWFtcyksXG4gICAgICAgICAgICA2XG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHZpZGVvRWxlbWVudCA9IHRoaXMudmlkZW9FbGVtZW50UHJvdmlkZXIuZ2V0VmlkZW9FbGVtZW50KCk7XG5cbiAgICAgICAgaWYgKHJ0Y1RyYWNrRXZlbnQudHJhY2spIHtcbiAgICAgICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICAnR290IHRyYWNrIC0gJyArXG4gICAgICAgICAgICAgICAgICAgIHJ0Y1RyYWNrRXZlbnQudHJhY2sua2luZCArXG4gICAgICAgICAgICAgICAgICAgICcgaWQ9JyArXG4gICAgICAgICAgICAgICAgICAgIHJ0Y1RyYWNrRXZlbnQudHJhY2suaWQgK1xuICAgICAgICAgICAgICAgICAgICAnIHJlYWR5U3RhdGU9JyArXG4gICAgICAgICAgICAgICAgICAgIHJ0Y1RyYWNrRXZlbnQudHJhY2sucmVhZHlTdGF0ZSxcbiAgICAgICAgICAgICAgICA2XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHJ0Y1RyYWNrRXZlbnQudHJhY2sua2luZCA9PSAnYXVkaW8nKSB7XG4gICAgICAgICAgICB0aGlzLkNyZWF0ZUF1ZGlvVHJhY2socnRjVHJhY2tFdmVudC5zdHJlYW1zWzBdKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgICAgIHJ0Y1RyYWNrRXZlbnQudHJhY2sua2luZCA9PSAndmlkZW8nICYmXG4gICAgICAgICAgICB2aWRlb0VsZW1lbnQuc3JjT2JqZWN0ICE9PSBydGNUcmFja0V2ZW50LnN0cmVhbXNbMF1cbiAgICAgICAgKSB7XG4gICAgICAgICAgICB2aWRlb0VsZW1lbnQuc3JjT2JqZWN0ID0gcnRjVHJhY2tFdmVudC5zdHJlYW1zWzBdO1xuICAgICAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgICdTZXQgdmlkZW8gc291cmNlIGZyb20gdmlkZW8gdHJhY2sgb250cmFjay4nXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyB0aGUgYXVkaW8gZGV2aWNlIHdoZW4gcmVjZWl2aW5nIGFuIFJUQ1RyYWNrRXZlbnQgd2l0aCB0aGUga2luZCBvZiBcImF1ZGlvXCJcbiAgICAgKiBAcGFyYW0gYXVkaW9NZWRpYVN0cmVhbSAtIEF1ZGlvIE1lZGlhIHN0cmVhbSB0cmFja1xuICAgICAqL1xuICAgIENyZWF0ZUF1ZGlvVHJhY2soYXVkaW9NZWRpYVN0cmVhbTogTWVkaWFTdHJlYW0pIHtcbiAgICAgICAgY29uc3QgdmlkZW9FbGVtZW50ID0gdGhpcy52aWRlb0VsZW1lbnRQcm92aWRlci5nZXRWaWRlb0VsZW1lbnQoKTtcblxuICAgICAgICAvLyBkbyBub3RoaW5nIHRoZSB2aWRlbyBoYXMgdGhlIHNhbWUgbWVkaWEgc3RyZWFtIGFzIHRoZSBhdWRpbyB0cmFjayB3ZSBoYXZlIGhlcmUgKHRoZXkgYXJlIGxpbmtlZClcbiAgICAgICAgaWYgKHZpZGVvRWxlbWVudC5zcmNPYmplY3QgPT0gYXVkaW9NZWRpYVN0cmVhbSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIC8vIHZpZGVvIGVsZW1lbnQgaGFzIHNvbWUgb3RoZXIgbWVkaWEgc3RyZWFtIHRoYXQgaXMgbm90IGFzc29jaWF0ZWQgd2l0aCB0aGlzIGF1ZGlvIHRyYWNrXG4gICAgICAgIGVsc2UgaWYgKFxuICAgICAgICAgICAgdmlkZW9FbGVtZW50LnNyY09iamVjdCAmJlxuICAgICAgICAgICAgdmlkZW9FbGVtZW50LnNyY09iamVjdCAhPT0gYXVkaW9NZWRpYVN0cmVhbVxuICAgICAgICApIHtcbiAgICAgICAgICAgIC8vIGNyZWF0ZSBhIG5ldyBhdWRpbyBlbGVtZW50XG4gICAgICAgICAgICB0aGlzLmF1ZGlvRWxlbWVudC5zcmNPYmplY3QgPSBhdWRpb01lZGlhU3RyZWFtO1xuICAgICAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgICdDcmVhdGVkIG5ldyBhdWRpbyBlbGVtZW50IHRvIHBsYXkgc2VwYXJhdGUgYXVkaW8gc3RyZWFtLidcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICB9XG59XG4iLCIvLyBDb3B5cmlnaHQgRXBpYyBHYW1lcywgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuXG5pbXBvcnQgeyBDb25maWcsIEZsYWdzIH0gZnJvbSAnLi4vQ29uZmlnL0NvbmZpZyc7XG5pbXBvcnQgeyBMb2dnZXIgfSBmcm9tICcuLi9Mb2dnZXIvTG9nZ2VyJztcblxuLyoqXG4gKiBFeHRyYSB0eXBlcyBmb3IgdGhlIEhUTUxFbGVtZW50XG4gKi9cbmRlY2xhcmUgZ2xvYmFsIHtcbiAgICBpbnRlcmZhY2UgSFRNTEVsZW1lbnQge1xuICAgICAgICBtb3pSZXF1ZXN0UG9pbnRlckxvY2s/KCk6IHZvaWQ7XG4gICAgfVxufVxuXG4vKipcbiAqIFRoZSB2aWRlbyBwbGF5ZXIgaHRtbCBlbGVtZW50XG4gKi9cbmV4cG9ydCBjbGFzcyBWaWRlb1BsYXllciB7XG4gICAgcHJpdmF0ZSBjb25maWc6IENvbmZpZztcbiAgICBwcml2YXRlIHZpZGVvRWxlbWVudDogSFRNTFZpZGVvRWxlbWVudDtcbiAgICBwcml2YXRlIGF1ZGlvRWxlbWVudD86IEhUTUxBdWRpb0VsZW1lbnQ7XG4gICAgcHJpdmF0ZSBvcmllbnRhdGlvbkNoYW5nZVRpbWVvdXQ6IG51bWJlcjtcbiAgICBwcml2YXRlIGxhc3RUaW1lUmVzaXplZCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuXG4gICAgb25NYXRjaFZpZXdwb3J0UmVzb2x1dGlvbkNhbGxiYWNrOiAod2lkdGg6IG51bWJlciwgaGVpZ2h0OiBudW1iZXIpID0+IHZvaWQ7XG4gICAgb25SZXNpemVQbGF5ZXJDYWxsYmFjazogKCkgPT4gdm9pZDtcbiAgICByZXNpemVUaW1lb3V0SGFuZGxlOiBudW1iZXI7XG5cbiAgICAvKipcbiAgICAgKiBAcGFyYW0gdmlkZW9FbGVtZW50UGFyZW50IHRoZSBodG1sIGRpdiB0aGUgdGhlIHZpZGVvIHBsYXllciB3aWxsIGJlIGluamVjdGVkIGludG9cbiAgICAgKiBAcGFyYW0gY29uZmlnIHRoZSBhcHBsaWNhdGlvbnMgY29uZmlndXJhdGlvbi4gV2UncmUgaW50ZXJlc3RlZCBpbiB0aGUgc3RhcnRWaWRlb011dGVkIGZsYWdcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3Rvcih2aWRlb0VsZW1lbnRQYXJlbnQ6IEhUTUxFbGVtZW50LCBjb25maWc6IENvbmZpZykge1xuICAgICAgICB0aGlzLnZpZGVvRWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3ZpZGVvJyk7XG4gICAgICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xuICAgICAgICB0aGlzLnZpZGVvRWxlbWVudC5pZCA9ICdzdHJlYW1pbmdWaWRlbyc7XG4gICAgICAgIHRoaXMudmlkZW9FbGVtZW50LmRpc2FibGVQaWN0dXJlSW5QaWN0dXJlID0gdHJ1ZTtcbiAgICAgICAgdGhpcy52aWRlb0VsZW1lbnQucGxheXNJbmxpbmUgPSB0cnVlO1xuICAgICAgICB0aGlzLnZpZGVvRWxlbWVudC5zdHlsZS53aWR0aCA9ICcxMDAlJztcbiAgICAgICAgdGhpcy52aWRlb0VsZW1lbnQuc3R5bGUuaGVpZ2h0ID0gJzEwMCUnO1xuICAgICAgICB0aGlzLnZpZGVvRWxlbWVudC5zdHlsZS5wb3NpdGlvbiA9ICdhYnNvbHV0ZSc7XG4gICAgICAgIHRoaXMudmlkZW9FbGVtZW50LnN0eWxlLnBvaW50ZXJFdmVudHMgPSAnYWxsJztcbiAgICAgICAgdmlkZW9FbGVtZW50UGFyZW50LmFwcGVuZENoaWxkKHRoaXMudmlkZW9FbGVtZW50KTtcblxuICAgICAgICB0aGlzLm9uUmVzaXplUGxheWVyQ2FsbGJhY2sgPSAoKSA9PiB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICAgICAgICAnUmVzb2x1dGlvbiBjaGFuZ2VkLCByZXN0eWxpbmcgcGxheWVyLCBkaWQgeW91IGZvcmdldCB0byBvdmVycmlkZSB0aGlzIGZ1bmN0aW9uPydcbiAgICAgICAgICAgICk7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMub25NYXRjaFZpZXdwb3J0UmVzb2x1dGlvbkNhbGxiYWNrID0gKCkgPT4ge1xuICAgICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICAgICAgJ1Jlc29sdXRpb24gY2hhbmdlZCBhbmQgbWF0Y2ggdmlld3BvcnQgcmVzb2x1dGlvbiBpcyB0dXJuZWQgb24sIGRpZCB5b3UgZm9yZ2V0IHRvIG92ZXJyaWRlIHRoaXMgZnVuY3Rpb24/J1xuICAgICAgICAgICAgKTtcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBzZXQgcGxheSBmb3IgdmlkZW8gKGFuZCBhdWRpbylcbiAgICAgICAgdGhpcy52aWRlb0VsZW1lbnQub25jbGljayA9ICgpID0+IHtcbiAgICAgICAgICAgIGlmICh0aGlzLmF1ZGlvRWxlbWVudCAhPSB1bmRlZmluZWQgJiYgdGhpcy5hdWRpb0VsZW1lbnQucGF1c2VkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5hdWRpb0VsZW1lbnQucGxheSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHRoaXMudmlkZW9FbGVtZW50LnBhdXNlZCkge1xuICAgICAgICAgICAgICAgIHRoaXMudmlkZW9FbGVtZW50LnBsYXkoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICB0aGlzLnZpZGVvRWxlbWVudC5vbmxvYWRlZG1ldGFkYXRhID0gKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5vblZpZGVvSW5pdGlhbGl6ZWQoKTtcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBzZXQgcmVzaXplIGV2ZW50cyB0byB0aGUgd2luZG93cyBpZiBpdCBpcyByZXNpemVkIG9yIGl0cyBvcmllbnRhdGlvbiBpcyBjaGFuZ2VkXG4gICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdyZXNpemUnLCAoKSA9PiB0aGlzLnJlc2l6ZVBsYXllclN0eWxlKCksIHRydWUpO1xuICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignb3JpZW50YXRpb25jaGFuZ2UnLCAoKSA9PlxuICAgICAgICAgICAgdGhpcy5vbk9yaWVudGF0aW9uQ2hhbmdlKClcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2V0QXVkaW9FbGVtZW50KGF1ZGlvRWxlbWVudDogSFRNTEF1ZGlvRWxlbWVudCkgOiB2b2lkIHtcbiAgICAgICAgdGhpcy5hdWRpb0VsZW1lbnQgPSBhdWRpb0VsZW1lbnQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0cyB1cCB0aGUgdmlkZW8gZWxlbWVudCB3aXRoIGFueSBhcHBsaWNhdGlvbiBjb25maWcgYW5kIHBsYXlzIHRoZSB2aWRlbyBlbGVtZW50LlxuICAgICAqIEByZXR1cm5zIEEgcHJvbWlzZSBmb3IgaWYgcGxheWluZyB0aGUgdmlkZW8gd2FzIHN1Y2Nlc3NmdWwgb3Igbm90LlxuICAgICAqL1xuICAgIHBsYXkoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMudmlkZW9FbGVtZW50Lm11dGVkID0gdGhpcy5jb25maWcuaXNGbGFnRW5hYmxlZChcbiAgICAgICAgICAgIEZsYWdzLlN0YXJ0VmlkZW9NdXRlZFxuICAgICAgICApO1xuICAgICAgICB0aGlzLnZpZGVvRWxlbWVudC5hdXRvcGxheSA9IHRoaXMuY29uZmlnLmlzRmxhZ0VuYWJsZWQoXG4gICAgICAgICAgICBGbGFncy5BdXRvUGxheVZpZGVvXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiB0aGlzLnZpZGVvRWxlbWVudC5wbGF5KCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHJldHVybnMgVHJ1ZSBpZiB0aGUgdmlkZW8gZWxlbWVudCBpcyBwYXVzZWQuXG4gICAgICovXG4gICAgaXNQYXVzZWQoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLnZpZGVvRWxlbWVudC5wYXVzZWQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHJldHVybnMgLSB3aGV0aGVyIHRoZSB2aWRlbyBlbGVtZW50IGlzIHBsYXlpbmcuXG4gICAgICovXG4gICAgaXNWaWRlb1JlYWR5KCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgdGhpcy52aWRlb0VsZW1lbnQucmVhZHlTdGF0ZSAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAgICAgICB0aGlzLnZpZGVvRWxlbWVudC5yZWFkeVN0YXRlID4gMFxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEByZXR1cm5zIFRydWUgaWYgdGhlIHZpZGVvIGVsZW1lbnQgaGFzIGEgdmFsaWQgdmlkZW8gc291cmNlIChzcmNPYmplY3QpLlxuICAgICAqL1xuICAgIGhhc1ZpZGVvU291cmNlKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgdGhpcy52aWRlb0VsZW1lbnQuc3JjT2JqZWN0ICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgICAgIHRoaXMudmlkZW9FbGVtZW50LnNyY09iamVjdCAhPT0gbnVsbFxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCB0aGUgY3VycmVudCBjb250ZXh0IG9mIHRoZSBodG1sIHZpZGVvIGVsZW1lbnRcbiAgICAgKiBAcmV0dXJucyAtIHRoZSBjdXJyZW50IGNvbnRleHQgb2YgdGhlIHZpZGVvIGVsZW1lbnRcbiAgICAgKi9cbiAgICBnZXRWaWRlb0VsZW1lbnQoKTogSFRNTFZpZGVvRWxlbWVudCB7XG4gICAgICAgIHJldHVybiB0aGlzLnZpZGVvRWxlbWVudDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBHZXQgdGhlIGN1cnJlbnQgY29udGV4dCBvZiB0aGUgaHRtbCB2aWRlbyBlbGVtZW50cyBwYXJlbnRcbiAgICAgKiBAcmV0dXJucyAtIHRoZSBjdXJyZW50IGNvbnRleHQgb2YgdGhlIHZpZGVvIGVsZW1lbnRzIHBhcmVudFxuICAgICAqL1xuICAgIGdldFZpZGVvUGFyZW50RWxlbWVudCgpOiBIVE1MRWxlbWVudCB7XG4gICAgICAgIHJldHVybiB0aGlzLnZpZGVvRWxlbWVudC5wYXJlbnRFbGVtZW50O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldCB0aGUgVmlkZW8gRWxlbWVudHMgc3JjIG9iamVjdCB0cmFja3MgdG8gZW5hYmxlXG4gICAgICogQHBhcmFtIGVuYWJsZWQgLSBFbmFibGUgVHJhY2tzIG9uIHRoZSBTcmMgT2JqZWN0XG4gICAgICovXG4gICAgc2V0VmlkZW9FbmFibGVkKGVuYWJsZWQ6IGJvb2xlYW4pIHtcbiAgICAgICAgLy8gdGhpcyBpcyBhIHRlbXBvcmFyeSBoYWNrIHVudGlsIHR5cGUgc2NyaXB0cyB2aWRlbyBlbGVtZW50IGlzIHVwZGF0ZWQgdG8gcmVmbGVjdCB0aGUgbmVlZCBmb3IgdHJhY2tzIG9uIGEgaHRtbCB2aWRlbyBlbGVtZW50XG4gICAgICAgIGNvbnN0IHZpZGVvRWxlbWVudCA9IHRoaXMudmlkZW9FbGVtZW50O1xuICAgICAgICAoPE1lZGlhU3RyZWFtPnZpZGVvRWxlbWVudC5zcmNPYmplY3QpXG4gICAgICAgICAgICAuZ2V0VHJhY2tzKClcbiAgICAgICAgICAgIC5mb3JFYWNoKCh0cmFjazogTWVkaWFTdHJlYW1UcmFjaykgPT4gKHRyYWNrLmVuYWJsZWQgPSBlbmFibGVkKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQW4gb3ZlcnJpZGUgZm9yIHdoZW4gdGhlIHZpZGVvIGhhcyBiZWVuIGluaXRpYWxpemVkIHdpdGggYSBzcmNPYmplY3RcbiAgICAgKi9cbiAgICBvblZpZGVvSW5pdGlhbGl6ZWQoKSB7XG4gICAgICAgIC8vIERlZmF1bHQgRnVuY3Rpb25hbGl0eTogRG8gTm90aGluZ1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIE9uIHRoZSBvcmllbnRhdGlvbiBjaGFuZ2Ugb2YgYSB3aW5kb3cgY2xlYXIgdGhlIHRpbWVvdXRcbiAgICAgKi9cbiAgICBvbk9yaWVudGF0aW9uQ2hhbmdlKCkge1xuICAgICAgICBjbGVhclRpbWVvdXQodGhpcy5vcmllbnRhdGlvbkNoYW5nZVRpbWVvdXQpO1xuICAgICAgICB0aGlzLm9yaWVudGF0aW9uQ2hhbmdlVGltZW91dCA9IHdpbmRvdy5zZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIHRoaXMucmVzaXplUGxheWVyU3R5bGUoKTtcbiAgICAgICAgfSwgNTAwKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXNpemVzIHRoZSBwbGF5ZXIgc3R5bGUgYmFzZWQgb24gdGhlIHdpbmRvdyBoZWlnaHQgYW5kIHdpZHRoXG4gICAgICogQHJldHVybnMgLSBuaWwgaWYgcmVxdWlyZW1lbnRzIGFyZSBzYXRpc2ZpZWRcbiAgICAgKi9cbiAgICByZXNpemVQbGF5ZXJTdHlsZSgpIHtcbiAgICAgICAgY29uc3QgdmlkZW9FbGVtZW50UGFyZW50ID0gdGhpcy5nZXRWaWRlb1BhcmVudEVsZW1lbnQoKTtcblxuICAgICAgICBpZiAoIXZpZGVvRWxlbWVudFBhcmVudCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy51cGRhdGVWaWRlb1N0cmVhbVNpemUoKTtcblxuICAgICAgICBpZiAodmlkZW9FbGVtZW50UGFyZW50LmNsYXNzTGlzdC5jb250YWlucygnZml4ZWQtc2l6ZScpKSB7XG4gICAgICAgICAgICB0aGlzLm9uUmVzaXplUGxheWVyQ2FsbGJhY2soKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGNvbnRyb2xzIGZvciByZXNpemluZyB0aGUgcGxheWVyXG4gICAgICAgIHRoaXMucmVzaXplUGxheWVyU3R5bGVUb0ZpbGxQYXJlbnRFbGVtZW50KCk7XG4gICAgICAgIHRoaXMub25SZXNpemVQbGF5ZXJDYWxsYmFjaygpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlc2l6ZXMgdGhlIHBsYXllciBlbGVtZW50IHRvIGZpbGwgdGhlIHBhcmVudCBlbGVtZW50XG4gICAgICovXG4gICAgcmVzaXplUGxheWVyU3R5bGVUb0ZpbGxQYXJlbnRFbGVtZW50KCkge1xuICAgICAgICBjb25zdCB2aWRlb0VsZW1lbnRQYXJlbnQgPSB0aGlzLmdldFZpZGVvUGFyZW50RWxlbWVudCgpO1xuXG4gICAgICAgIC8vVmlkZW8gaXMgbm90IGluaXRpYWxpemVkIHlldCBzbyBzZXQgdmlkZW9FbGVtZW50UGFyZW50IHRvIHNpemUgb2YgcGFyZW50IGVsZW1lbnRcbiAgICAgICAgY29uc3Qgc3R5bGVXaWR0aCA9ICcxMDAlJztcbiAgICAgICAgY29uc3Qgc3R5bGVIZWlnaHQgPSAnMTAwJSc7XG4gICAgICAgIGNvbnN0IHN0eWxlVG9wID0gMDtcbiAgICAgICAgY29uc3Qgc3R5bGVMZWZ0ID0gMDtcbiAgICAgICAgdmlkZW9FbGVtZW50UGFyZW50LnNldEF0dHJpYnV0ZShcbiAgICAgICAgICAgICdzdHlsZScsXG4gICAgICAgICAgICAndG9wOiAnICtcbiAgICAgICAgICAgICAgICBzdHlsZVRvcCArXG4gICAgICAgICAgICAgICAgJ3B4OyBsZWZ0OiAnICtcbiAgICAgICAgICAgICAgICBzdHlsZUxlZnQgK1xuICAgICAgICAgICAgICAgICdweDsgd2lkdGg6ICcgK1xuICAgICAgICAgICAgICAgIHN0eWxlV2lkdGggK1xuICAgICAgICAgICAgICAgICc7IGhlaWdodDogJyArXG4gICAgICAgICAgICAgICAgc3R5bGVIZWlnaHQgK1xuICAgICAgICAgICAgICAgICc7IGN1cnNvcjogZGVmYXVsdDsnXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgdXBkYXRlVmlkZW9TdHJlYW1TaXplKCkge1xuICAgICAgICBpZiAoIXRoaXMuY29uZmlnLmlzRmxhZ0VuYWJsZWQoRmxhZ3MuTWF0Y2hWaWV3cG9ydFJlc29sdXRpb24pKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBub3cgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcbiAgICAgICAgaWYgKG5vdyAtIHRoaXMubGFzdFRpbWVSZXNpemVkID4gMzAwKSB7XG4gICAgICAgICAgICBjb25zdCB2aWRlb0VsZW1lbnRQYXJlbnQgPSB0aGlzLmdldFZpZGVvUGFyZW50RWxlbWVudCgpO1xuICAgICAgICAgICAgaWYgKCF2aWRlb0VsZW1lbnRQYXJlbnQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMub25NYXRjaFZpZXdwb3J0UmVzb2x1dGlvbkNhbGxiYWNrKFxuICAgICAgICAgICAgICAgIHZpZGVvRWxlbWVudFBhcmVudC5jbGllbnRXaWR0aCxcbiAgICAgICAgICAgICAgICB2aWRlb0VsZW1lbnRQYXJlbnQuY2xpZW50SGVpZ2h0XG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB0aGlzLmxhc3RUaW1lUmVzaXplZCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgICdSZXNpemluZyB0b28gb2Z0ZW4gLSBza2lwcGluZycsXG4gICAgICAgICAgICAgICAgNlxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGNsZWFyVGltZW91dCh0aGlzLnJlc2l6ZVRpbWVvdXRIYW5kbGUpO1xuICAgICAgICAgICAgdGhpcy5yZXNpemVUaW1lb3V0SGFuZGxlID0gd2luZG93LnNldFRpbWVvdXQoXG4gICAgICAgICAgICAgICAgKCkgPT4gdGhpcy51cGRhdGVWaWRlb1N0cmVhbVNpemUoKSxcbiAgICAgICAgICAgICAgICAxMDBcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICB9XG59XG4iLCIvLyBDb3B5cmlnaHQgRXBpYyBHYW1lcywgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuXG5pbXBvcnQgeyBXZWJTb2NrZXRDb250cm9sbGVyIH0gZnJvbSAnLi4vV2ViU29ja2V0cy9XZWJTb2NrZXRDb250cm9sbGVyJztcbmltcG9ydCB7IFN0cmVhbUNvbnRyb2xsZXIgfSBmcm9tICcuLi9WaWRlb1BsYXllci9TdHJlYW1Db250cm9sbGVyJztcbmltcG9ydCB7XG4gICAgTWVzc2FnZUFuc3dlcixcbiAgICBNZXNzYWdlT2ZmZXIsXG4gICAgTWVzc2FnZUNvbmZpZyxcbiAgICBNZXNzYWdlU3RyZWFtZXJMaXN0XG59IGZyb20gJy4uL1dlYlNvY2tldHMvTWVzc2FnZVJlY2VpdmUnO1xuaW1wb3J0IHsgRnJlZXplRnJhbWVDb250cm9sbGVyIH0gZnJvbSAnLi4vRnJlZXplRnJhbWUvRnJlZXplRnJhbWVDb250cm9sbGVyJztcbmltcG9ydCB7IEFGS0NvbnRyb2xsZXIgfSBmcm9tICcuLi9BRksvQUZLQ29udHJvbGxlcic7XG5pbXBvcnQgeyBEYXRhQ2hhbm5lbENvbnRyb2xsZXIgfSBmcm9tICcuLi9EYXRhQ2hhbm5lbC9EYXRhQ2hhbm5lbENvbnRyb2xsZXInO1xuaW1wb3J0IHsgUGVlckNvbm5lY3Rpb25Db250cm9sbGVyIH0gZnJvbSAnLi4vUGVlckNvbm5lY3Rpb25Db250cm9sbGVyL1BlZXJDb25uZWN0aW9uQ29udHJvbGxlcic7XG5pbXBvcnQgeyBLZXlib2FyZENvbnRyb2xsZXIgfSBmcm9tICcuLi9JbnB1dHMvS2V5Ym9hcmRDb250cm9sbGVyJztcbmltcG9ydCB7IEFnZ3JlZ2F0ZWRTdGF0cyB9IGZyb20gJy4uL1BlZXJDb25uZWN0aW9uQ29udHJvbGxlci9BZ2dyZWdhdGVkU3RhdHMnO1xuaW1wb3J0IHtcbiAgICBDb25maWcsXG4gICAgRmxhZ3MsXG4gICAgQ29udHJvbFNjaGVtZVR5cGUsXG4gICAgVGV4dFBhcmFtZXRlcnMsXG4gICAgT3B0aW9uUGFyYW1ldGVycyxcbiAgICBOdW1lcmljUGFyYW1ldGVyc1xufSBmcm9tICcuLi9Db25maWcvQ29uZmlnJztcbmltcG9ydCB7XG4gICAgRW5jb2RlclNldHRpbmdzLFxuICAgIEluaXRpYWxTZXR0aW5ncyxcbiAgICBXZWJSVENTZXR0aW5nc1xufSBmcm9tICcuLi9EYXRhQ2hhbm5lbC9Jbml0aWFsU2V0dGluZ3MnO1xuaW1wb3J0IHsgTGF0ZW5jeVRlc3RSZXN1bHRzIH0gZnJvbSAnLi4vRGF0YUNoYW5uZWwvTGF0ZW5jeVRlc3RSZXN1bHRzJztcbmltcG9ydCB7IExvZ2dlciB9IGZyb20gJy4uL0xvZ2dlci9Mb2dnZXInO1xuaW1wb3J0IHsgRmlsZVRlbXBsYXRlLCBGaWxlVXRpbCB9IGZyb20gJy4uL1V0aWwvRmlsZVV0aWwnO1xuaW1wb3J0IHsgSW5wdXRDbGFzc2VzRmFjdG9yeSB9IGZyb20gJy4uL0lucHV0cy9JbnB1dENsYXNzZXNGYWN0b3J5JztcbmltcG9ydCB7IFZpZGVvUGxheWVyIH0gZnJvbSAnLi4vVmlkZW9QbGF5ZXIvVmlkZW9QbGF5ZXInO1xuaW1wb3J0IHtcbiAgICBTdHJlYW1NZXNzYWdlQ29udHJvbGxlcixcbiAgICBNZXNzYWdlRGlyZWN0aW9uXG59IGZyb20gJy4uL1VlSW5zdGFuY2VNZXNzYWdlL1N0cmVhbU1lc3NhZ2VDb250cm9sbGVyJztcbmltcG9ydCB7IFJlc3BvbnNlQ29udHJvbGxlciB9IGZyb20gJy4uL1VlSW5zdGFuY2VNZXNzYWdlL1Jlc3BvbnNlQ29udHJvbGxlcic7XG5pbXBvcnQgKiBhcyBNZXNzYWdlUmVjZWl2ZSBmcm9tICcuLi9XZWJTb2NrZXRzL01lc3NhZ2VSZWNlaXZlJztcbmltcG9ydCB7IE1lc3NhZ2VPblNjcmVlbktleWJvYXJkIH0gZnJvbSAnLi4vV2ViU29ja2V0cy9NZXNzYWdlUmVjZWl2ZSc7XG5pbXBvcnQgeyBTZW5kTWVzc2FnZUNvbnRyb2xsZXIgfSBmcm9tICcuLi9VZUluc3RhbmNlTWVzc2FnZS9TZW5kTWVzc2FnZUNvbnRyb2xsZXInO1xuaW1wb3J0IHsgVG9TdHJlYW1lck1lc3NhZ2VzQ29udHJvbGxlciB9IGZyb20gJy4uL1VlSW5zdGFuY2VNZXNzYWdlL1RvU3RyZWFtZXJNZXNzYWdlc0NvbnRyb2xsZXInO1xuaW1wb3J0IHsgTW91c2VDb250cm9sbGVyIH0gZnJvbSAnLi4vSW5wdXRzL01vdXNlQ29udHJvbGxlcic7XG5pbXBvcnQgeyBHYW1lUGFkQ29udHJvbGxlciB9IGZyb20gJy4uL0lucHV0cy9HYW1lcGFkQ29udHJvbGxlcic7XG5pbXBvcnQgeyBEYXRhQ2hhbm5lbFNlbmRlciB9IGZyb20gJy4uL0RhdGFDaGFubmVsL0RhdGFDaGFubmVsU2VuZGVyJztcbmltcG9ydCB7XG4gICAgQ29vcmRpbmF0ZUNvbnZlcnRlcixcbiAgICBVbnF1YW50aXplZERlbm9ybWFsaXplZFVuc2lnbmVkQ29vcmRcbn0gZnJvbSAnLi4vVXRpbC9Db29yZGluYXRlQ29udmVydGVyJztcbmltcG9ydCB7IFBpeGVsU3RyZWFtaW5nIH0gZnJvbSAnLi4vUGl4ZWxTdHJlYW1pbmcvUGl4ZWxTdHJlYW1pbmcnO1xuaW1wb3J0IHsgSVRvdWNoQ29udHJvbGxlciB9IGZyb20gJy4uL0lucHV0cy9JVG91Y2hDb250cm9sbGVyJztcbmltcG9ydCB7XG4gICAgRGF0YUNoYW5uZWxDbG9zZUV2ZW50LFxuICAgIERhdGFDaGFubmVsRXJyb3JFdmVudCxcbiAgICBEYXRhQ2hhbm5lbE9wZW5FdmVudCxcbiAgICBIaWRlRnJlZXplRnJhbWVFdmVudCxcbiAgICBMb2FkRnJlZXplRnJhbWVFdmVudCxcbiAgICBQbGF5U3RyZWFtRXJyb3JFdmVudCxcbiAgICBQbGF5U3RyZWFtRXZlbnQsXG4gICAgUGxheVN0cmVhbVJlamVjdGVkRXZlbnQsXG4gICAgU3RyZWFtZXJMaXN0TWVzc2FnZUV2ZW50XG59IGZyb20gJy4uL1V0aWwvRXZlbnRFbWl0dGVyJztcbmltcG9ydCB7XG4gICAgRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFJlcXVlc3QsXG4gICAgRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFJlc3BvbnNlXG59IGZyb20gXCIuLi9EYXRhQ2hhbm5lbC9EYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVzdWx0c1wiO1xuLyoqXG4gKiBFbnRyeSBwb2ludCBmb3IgdGhlIFdlYlJUQyBQbGF5ZXJcbiAqL1xuZXhwb3J0IGNsYXNzIFdlYlJ0Y1BsYXllckNvbnRyb2xsZXIge1xuICAgIGNvbmZpZzogQ29uZmlnO1xuICAgIHJlc3BvbnNlQ29udHJvbGxlcjogUmVzcG9uc2VDb250cm9sbGVyO1xuICAgIHNkcENvbnN0cmFpbnRzOiBSVENPZmZlck9wdGlvbnM7XG4gICAgd2ViU29ja2V0Q29udHJvbGxlcjogV2ViU29ja2V0Q29udHJvbGxlcjtcbiAgICAvLyBUaGUgcHJpbWFyeSBkYXRhIGNoYW5uZWwuIFRoaXMgaXMgYmlkaXJlY3Rpb25hbCB3aGVuIHAycCBhbmQgc2VuZCBvbmx5IHdoZW4gdXNpbmcgYW4gU0ZVXG4gICAgc2VuZHJlY3ZEYXRhQ2hhbm5lbENvbnRyb2xsZXI6IERhdGFDaGFubmVsQ29udHJvbGxlcjtcbiAgICAvLyBBIHJlY3Ygb25seSBkYXRhIGNoYW5uZWwgcmVxdWlyZWQgd2hlbiB1c2luZyBhbiBTRlVcbiAgICByZWN2RGF0YUNoYW5uZWxDb250cm9sbGVyOiBEYXRhQ2hhbm5lbENvbnRyb2xsZXI7XG4gICAgZGF0YUNoYW5uZWxTZW5kZXI6IERhdGFDaGFubmVsU2VuZGVyO1xuICAgIGRhdGFjaGFubmVsT3B0aW9uczogUlRDRGF0YUNoYW5uZWxJbml0O1xuICAgIHZpZGVvUGxheWVyOiBWaWRlb1BsYXllcjtcbiAgICBzdHJlYW1Db250cm9sbGVyOiBTdHJlYW1Db250cm9sbGVyO1xuICAgIHBlZXJDb25uZWN0aW9uQ29udHJvbGxlcjogUGVlckNvbm5lY3Rpb25Db250cm9sbGVyO1xuICAgIGlucHV0Q2xhc3Nlc0ZhY3Rvcnk6IElucHV0Q2xhc3Nlc0ZhY3Rvcnk7XG4gICAgZnJlZXplRnJhbWVDb250cm9sbGVyOiBGcmVlemVGcmFtZUNvbnRyb2xsZXI7XG4gICAgc2hvdWxkU2hvd1BsYXlPdmVybGF5ID0gdHJ1ZTtcbiAgICBhZmtDb250cm9sbGVyOiBBRktDb250cm9sbGVyO1xuICAgIHZpZGVvRWxlbWVudFBhcmVudENsaWVudFJlY3Q6IERPTVJlY3Q7XG4gICAgbGF0ZW5jeVN0YXJ0VGltZTogbnVtYmVyO1xuICAgIHBpeGVsU3RyZWFtaW5nOiBQaXhlbFN0cmVhbWluZztcbiAgICBzdHJlYW1NZXNzYWdlQ29udHJvbGxlcjogU3RyZWFtTWVzc2FnZUNvbnRyb2xsZXI7XG4gICAgc2VuZE1lc3NhZ2VDb250cm9sbGVyOiBTZW5kTWVzc2FnZUNvbnRyb2xsZXI7XG4gICAgdG9TdHJlYW1lck1lc3NhZ2VzQ29udHJvbGxlcjogVG9TdHJlYW1lck1lc3NhZ2VzQ29udHJvbGxlcjtcbiAgICBrZXlib2FyZENvbnRyb2xsZXI6IEtleWJvYXJkQ29udHJvbGxlcjtcbiAgICBtb3VzZUNvbnRyb2xsZXI6IE1vdXNlQ29udHJvbGxlcjtcbiAgICB0b3VjaENvbnRyb2xsZXI6IElUb3VjaENvbnRyb2xsZXI7XG4gICAgZ2FtZVBhZENvbnRyb2xsZXI6IEdhbWVQYWRDb250cm9sbGVyO1xuICAgIGNvb3JkaW5hdGVDb252ZXJ0ZXI6IENvb3JkaW5hdGVDb252ZXJ0ZXI7XG4gICAgaXNVc2luZ1NGVTogYm9vbGVhbjtcbiAgICBpc1F1YWxpdHlDb250cm9sbGVyOiBib29sZWFuO1xuICAgIHN0YXRzVGltZXJIYW5kbGU6IG51bWJlcjtcbiAgICBmaWxlOiBGaWxlVGVtcGxhdGU7XG4gICAgcHJlZmVycmVkQ29kZWM6IHN0cmluZztcbiAgICBwZWVyQ29uZmlnOiBSVENDb25maWd1cmF0aW9uO1xuICAgIHZpZGVvQXZnUXA6IG51bWJlcjtcbiAgICBsb2NhbGx5Q2xvc2VkOiBib29sZWFuO1xuICAgIHNob3VsZFJlY29ubmVjdDogYm9vbGVhbjtcbiAgICBpc1JlY29ubmVjdGluZzogYm9vbGVhbjtcbiAgICByZWNvbm5lY3RBdHRlbXB0OiBudW1iZXI7XG4gICAgZGlzY29ubmVjdE1lc3NhZ2U6IHN0cmluZztcbiAgICBzdWJzY3JpYmVkU3RyZWFtOiBzdHJpbmc7XG4gICAgc2lnbmFsbGluZ1VybEJ1aWxkZXI6ICgpID0+IHN0cmluZztcbiAgICBhdXRvSm9pblRpbWVyOiBSZXR1cm5UeXBlPHR5cGVvZiBzZXRUaW1lb3V0PiA9IHVuZGVmaW5lZDtcblxuICAgIC8qKlxuICAgICAqXG4gICAgICogQHBhcmFtIGNvbmZpZyAtIHRoZSBmcm9udGVuZCBjb25maWcgb2JqZWN0XG4gICAgICogQHBhcmFtIHBpeGVsU3RyZWFtaW5nIC0gdGhlIFBpeGVsU3RyZWFtaW5nIG9iamVjdFxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKGNvbmZpZzogQ29uZmlnLCBwaXhlbFN0cmVhbWluZzogUGl4ZWxTdHJlYW1pbmcpIHtcbiAgICAgICAgdGhpcy5jb25maWcgPSBjb25maWc7XG4gICAgICAgIHRoaXMucGl4ZWxTdHJlYW1pbmcgPSBwaXhlbFN0cmVhbWluZztcbiAgICAgICAgdGhpcy5yZXNwb25zZUNvbnRyb2xsZXIgPSBuZXcgUmVzcG9uc2VDb250cm9sbGVyKCk7XG4gICAgICAgIHRoaXMuZmlsZSA9IG5ldyBGaWxlVGVtcGxhdGUoKTtcblxuICAgICAgICB0aGlzLnNkcENvbnN0cmFpbnRzID0ge1xuICAgICAgICAgICAgb2ZmZXJUb1JlY2VpdmVBdWRpbzogdHJ1ZSxcbiAgICAgICAgICAgIG9mZmVyVG9SZWNlaXZlVmlkZW86IHRydWVcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBzZXQgdXAgdGhlIGFmayBsb2dpYyBjbGFzcyBhbmQgY29ubmVjdCB1cCBpdHMgbWV0aG9kIGZvciBjbG9zaW5nIHRoZSBzaWduYWxpbmcgc2VydmVyXG4gICAgICAgIHRoaXMuYWZrQ29udHJvbGxlciA9IG5ldyBBRktDb250cm9sbGVyKFxuICAgICAgICAgICAgdGhpcy5jb25maWcsXG4gICAgICAgICAgICB0aGlzLnBpeGVsU3RyZWFtaW5nLFxuICAgICAgICAgICAgdGhpcy5vbkFma1RyaWdnZXJlZC5iaW5kKHRoaXMpXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuYWZrQ29udHJvbGxlci5vbkFGS1RpbWVkT3V0Q2FsbGJhY2sgPSAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmNsb3NlU2lnbmFsaW5nU2VydmVyKCdZb3UgaGF2ZSBiZWVuIGRpc2Nvbm5lY3RlZCBkdWUgdG8gaW5hY3Rpdml0eScpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMuZnJlZXplRnJhbWVDb250cm9sbGVyID0gbmV3IEZyZWV6ZUZyYW1lQ29udHJvbGxlcihcbiAgICAgICAgICAgIHRoaXMucGl4ZWxTdHJlYW1pbmcudmlkZW9FbGVtZW50UGFyZW50XG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy52aWRlb1BsYXllciA9IG5ldyBWaWRlb1BsYXllcihcbiAgICAgICAgICAgIHRoaXMucGl4ZWxTdHJlYW1pbmcudmlkZW9FbGVtZW50UGFyZW50LFxuICAgICAgICAgICAgdGhpcy5jb25maWdcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy52aWRlb1BsYXllci5vblZpZGVvSW5pdGlhbGl6ZWQgPSAoKSA9PlxuICAgICAgICAgICAgdGhpcy5oYW5kbGVWaWRlb0luaXRpYWxpemVkKCk7XG5cbiAgICAgICAgLy8gV2hlbiBpbiBtYXRjaCB2aWV3cG9ydCByZXNvbHV0aW9uIG1vZGUsIHdoZW4gdGhlIGJyb3dzZXIgdmlld3BvcnQgaXMgcmVzaXplZCB3ZSBzZW5kIGEgcmVzaXplIGNvbW1hbmQgYmFjayB0byBVRS5cbiAgICAgICAgdGhpcy52aWRlb1BsYXllci5vbk1hdGNoVmlld3BvcnRSZXNvbHV0aW9uQ2FsbGJhY2sgPSAoXG4gICAgICAgICAgICB3aWR0aDogbnVtYmVyLFxuICAgICAgICAgICAgaGVpZ2h0OiBudW1iZXJcbiAgICAgICAgKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBkZXNjcmlwdG9yID0ge1xuICAgICAgICAgICAgICAgICdSZXNvbHV0aW9uLldpZHRoJzogd2lkdGgsXG4gICAgICAgICAgICAgICAgJ1Jlc29sdXRpb24uSGVpZ2h0JzogaGVpZ2h0XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnRvU3RyZWFtZXJIYW5kbGVycy5nZXQoXG4gICAgICAgICAgICAgICAgJ0NvbW1hbmQnXG4gICAgICAgICAgICApKFtKU09OLnN0cmluZ2lmeShkZXNjcmlwdG9yKV0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIEV2ZXJ5IHRpbWUgdmlkZW8gcGxheWVyIGlzIHJlc2l6ZWQgaW4gYnJvd3NlciB3ZSBuZWVkIHRvIHJlaW5pdGlhbGl6ZSB0aGUgbW91c2UgY29vcmRpbmF0ZSBjb252ZXJzaW9uIGFuZCBmcmVlemUgZnJhbWUgc2l6aW5nIGxvZ2ljLlxuICAgICAgICB0aGlzLnZpZGVvUGxheWVyLm9uUmVzaXplUGxheWVyQ2FsbGJhY2sgPSAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnNldFVwTW91c2VBbmRGcmVlemVGcmFtZSgpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMuc3RyZWFtQ29udHJvbGxlciA9IG5ldyBTdHJlYW1Db250cm9sbGVyKHRoaXMudmlkZW9QbGF5ZXIpO1xuXG4gICAgICAgIHRoaXMuY29vcmRpbmF0ZUNvbnZlcnRlciA9IG5ldyBDb29yZGluYXRlQ29udmVydGVyKHRoaXMudmlkZW9QbGF5ZXIpO1xuXG4gICAgICAgIHRoaXMuc2VuZHJlY3ZEYXRhQ2hhbm5lbENvbnRyb2xsZXIgPSBuZXcgRGF0YUNoYW5uZWxDb250cm9sbGVyKCk7XG4gICAgICAgIHRoaXMucmVjdkRhdGFDaGFubmVsQ29udHJvbGxlciA9IG5ldyBEYXRhQ2hhbm5lbENvbnRyb2xsZXIoKTtcbiAgICAgICAgdGhpcy5yZWdpc3RlckRhdGFDaGFubmVsRXZlbnRFbWl0dGVycyhcbiAgICAgICAgICAgIHRoaXMuc2VuZHJlY3ZEYXRhQ2hhbm5lbENvbnRyb2xsZXJcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5yZWdpc3RlckRhdGFDaGFubmVsRXZlbnRFbWl0dGVycyh0aGlzLnJlY3ZEYXRhQ2hhbm5lbENvbnRyb2xsZXIpO1xuICAgICAgICB0aGlzLmRhdGFDaGFubmVsU2VuZGVyID0gbmV3IERhdGFDaGFubmVsU2VuZGVyKFxuICAgICAgICAgICAgdGhpcy5zZW5kcmVjdkRhdGFDaGFubmVsQ29udHJvbGxlclxuICAgICAgICApO1xuICAgICAgICB0aGlzLmRhdGFDaGFubmVsU2VuZGVyLnJlc2V0QWZrV2FybmluZ1RpbWVyT25EYXRhU2VuZCA9ICgpID0+XG4gICAgICAgICAgICB0aGlzLmFma0NvbnRyb2xsZXIucmVzZXRBZmtXYXJuaW5nVGltZXIoKTtcblxuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyID0gbmV3IFN0cmVhbU1lc3NhZ2VDb250cm9sbGVyKCk7XG5cbiAgICAgICAgLy8gc2V0IHVwIHdlYnNvY2tldCBtZXRob2RzXG4gICAgICAgIHRoaXMud2ViU29ja2V0Q29udHJvbGxlciA9IG5ldyBXZWJTb2NrZXRDb250cm9sbGVyKCk7XG4gICAgICAgIHRoaXMud2ViU29ja2V0Q29udHJvbGxlci5vbkNvbmZpZyA9IChcbiAgICAgICAgICAgIG1lc3NhZ2VDb25maWc6IE1lc3NhZ2VSZWNlaXZlLk1lc3NhZ2VDb25maWdcbiAgICAgICAgKSA9PiB0aGlzLmhhbmRsZU9uQ29uZmlnTWVzc2FnZShtZXNzYWdlQ29uZmlnKTtcbiAgICAgICAgdGhpcy53ZWJTb2NrZXRDb250cm9sbGVyLm9uU3RyZWFtZXJMaXN0ID0gKFxuICAgICAgICAgICAgbWVzc2FnZUxpc3Q6IE1lc3NhZ2VSZWNlaXZlLk1lc3NhZ2VTdHJlYW1lckxpc3RcbiAgICAgICAgKSA9PiB0aGlzLmhhbmRsZVN0cmVhbWVyTGlzdE1lc3NhZ2UobWVzc2FnZUxpc3QpO1xuICAgICAgICB0aGlzLndlYlNvY2tldENvbnRyb2xsZXIub25QbGF5ZXJDb3VudCA9IChwbGF5ZXJDb3VudDogTWVzc2FnZVJlY2VpdmUuTWVzc2FnZVBsYXllckNvdW50KSA9PiB7IFxuICAgICAgICAgICAgdGhpcy5waXhlbFN0cmVhbWluZy5fb25QbGF5ZXJDb3VudChwbGF5ZXJDb3VudC5jb3VudCk7IFxuICAgICAgICB9O1xuICAgICAgICB0aGlzLndlYlNvY2tldENvbnRyb2xsZXIub25PcGVuLmFkZEV2ZW50TGlzdGVuZXIoJ29wZW4nLCAoKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBCcm93c2VyU2VuZHNPZmZlciA9IHRoaXMuY29uZmlnLmlzRmxhZ0VuYWJsZWQoXG4gICAgICAgICAgICAgICAgRmxhZ3MuQnJvd3NlclNlbmRPZmZlclxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGlmKCFCcm93c2VyU2VuZHNPZmZlcilcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICB0aGlzLndlYlNvY2tldENvbnRyb2xsZXIucmVxdWVzdFN0cmVhbWVyTGlzdCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy53ZWJTb2NrZXRDb250cm9sbGVyLm9uQ2xvc2UuYWRkRXZlbnRMaXN0ZW5lcignY2xvc2UnLCAoZXZlbnQgOiBDdXN0b21FdmVudCkgPT4ge1xuICAgICAgICAgICAgLy8gd2hlbiB3ZSByZWZyZXNoIHRoZSBwYWdlIGR1cmluZyBhIHN0cmVhbSB3ZSBnZXQgdGhlIGdvaW5nIGF3YXkgY29kZS5cbiAgICAgICAgICAgIC8vIGluIHRoYXQgY2FzZSB3ZSBkb24ndCB3YW50IHRvIHJlY29ubmVjdCBzaW5jZSB3ZSdyZSBuYXZpZ2F0aW5nIGF3YXkuXG4gICAgICAgICAgICAvLyBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9BUEkvQ2xvc2VFdmVudC9jb2RlXG4gICAgICAgICAgICAvLyBsaXN0cyBhbGwgdGhlIGNvZGVzLiBcbiAgICAgICAgICAgIGNvbnN0IENPREVfR09JTkdfQVdBWSA9IDEwMDE7XG5cbiAgICAgICAgICAgIGNvbnN0IHdpbGxUcnlSZWNvbm5lY3QgPSB0aGlzLnNob3VsZFJlY29ubmVjdFxuICAgICAgICAgICAgICAgJiYgZXZlbnQuZGV0YWlsLmNvZGUgIT0gQ09ERV9HT0lOR19BV0FZXG4gICAgICAgICAgICAgICAmJiB0aGlzLmNvbmZpZy5nZXROdW1lcmljU2V0dGluZ1ZhbHVlKE51bWVyaWNQYXJhbWV0ZXJzLk1heFJlY29ubmVjdEF0dGVtcHRzKSA+IDBcblxuICAgICAgICAgICAgY29uc3QgZGlzY29ubmVjdE1lc3NhZ2UgPSB0aGlzLmRpc2Nvbm5lY3RNZXNzYWdlID8gdGhpcy5kaXNjb25uZWN0TWVzc2FnZSA6IGV2ZW50LmRldGFpbC5yZWFzb247XG4gICAgICAgICAgICB0aGlzLnBpeGVsU3RyZWFtaW5nLl9vbkRpc2Nvbm5lY3QoZGlzY29ubmVjdE1lc3NhZ2UsICF3aWxsVHJ5UmVjb25uZWN0ICYmICF0aGlzLmlzUmVjb25uZWN0aW5nKTtcblxuICAgICAgICAgICAgdGhpcy5hZmtDb250cm9sbGVyLnN0b3BBZmtXYXJuaW5nVGltZXIoKTtcblxuICAgICAgICAgICAgLy8gc3RvcCBzZW5kaW5nIHN0YXRzIG9uIGludGVydmFsIGlmIHdlIGhhdmUgY2xvc2VkIG91ciBjb25uZWN0aW9uXG4gICAgICAgICAgICBpZiAodGhpcy5zdGF0c1RpbWVySGFuZGxlICYmIHRoaXMuc3RhdHNUaW1lckhhbmRsZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgd2luZG93LmNsZWFySW50ZXJ2YWwodGhpcy5zdGF0c1RpbWVySGFuZGxlKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gcmVzZXQgdGhlIHN0cmVhbSBxdWFsaXR5IGljb24uXG4gICAgICAgICAgICB0aGlzLnNldFZpZGVvRW5jb2RlckF2Z1FQKDApO1xuXG4gICAgICAgICAgICAvLyB1bnJlZ2lzdGVyIGFsbCBpbnB1dCBkZXZpY2UgZXZlbnQgaGFuZGxlcnMgb24gZGlzY29ubmVjdFxuICAgICAgICAgICAgdGhpcy5zZXRUb3VjaElucHV0RW5hYmxlZChmYWxzZSk7XG4gICAgICAgICAgICB0aGlzLnNldE1vdXNlSW5wdXRFbmFibGVkKGZhbHNlKTtcbiAgICAgICAgICAgIHRoaXMuc2V0S2V5Ym9hcmRJbnB1dEVuYWJsZWQoZmFsc2UpO1xuICAgICAgICAgICAgdGhpcy5zZXRHYW1lUGFkSW5wdXRFbmFibGVkKGZhbHNlKTtcblxuICAgICAgICAgICAgaWYgKHdpbGxUcnlSZWNvbm5lY3QpIHtcbiAgICAgICAgICAgICAgICAvLyBuZWVkIGEgc21hbGwgZGVsYXkgaGVyZSB0byBwcmV2ZW50IHJlY29ubmVjdCBzcGFtbWluZ1xuICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmlzUmVjb25uZWN0aW5nID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZWNvbm5lY3RBdHRlbXB0Kys7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMudHJ5UmVjb25uZWN0KGV2ZW50LmRldGFpbC5yZWFzb24pO1xuICAgICAgICAgICAgICAgIH0sIDIwMDApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBzZXQgdXAgdGhlIGZpbmFsIHdlYlJ0YyBwbGF5ZXIgY29udHJvbGxlciBtZXRob2RzIGZyb20gd2l0aGluIG91ciBhcHBsaWNhdGlvbiBzbyBhIGNvbm5lY3Rpb24gY2FuIGJlIGFjdGl2YXRlZFxuICAgICAgICB0aGlzLnNlbmRNZXNzYWdlQ29udHJvbGxlciA9IG5ldyBTZW5kTWVzc2FnZUNvbnRyb2xsZXIoXG4gICAgICAgICAgICB0aGlzLmRhdGFDaGFubmVsU2VuZGVyLFxuICAgICAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlclxuICAgICAgICApO1xuICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlc0NvbnRyb2xsZXIgPSBuZXcgVG9TdHJlYW1lck1lc3NhZ2VzQ29udHJvbGxlcihcbiAgICAgICAgICAgIHRoaXMuc2VuZE1lc3NhZ2VDb250cm9sbGVyXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcnMoKTtcbiAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci5wb3B1bGF0ZURlZmF1bHRQcm90b2NvbCgpO1xuXG4gICAgICAgIHRoaXMuaW5wdXRDbGFzc2VzRmFjdG9yeSA9IG5ldyBJbnB1dENsYXNzZXNGYWN0b3J5KFxuICAgICAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlcixcbiAgICAgICAgICAgIHRoaXMudmlkZW9QbGF5ZXIsXG4gICAgICAgICAgICB0aGlzLmNvb3JkaW5hdGVDb252ZXJ0ZXJcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLmlzVXNpbmdTRlUgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5pc1F1YWxpdHlDb250cm9sbGVyID0gZmFsc2U7XG4gICAgICAgIHRoaXMucHJlZmVycmVkQ29kZWMgPSAnJztcbiAgICAgICAgdGhpcy5zaG91bGRSZWNvbm5lY3QgPSB0cnVlO1xuICAgICAgICB0aGlzLmlzUmVjb25uZWN0aW5nID0gZmFsc2U7XG4gICAgICAgIHRoaXMucmVjb25uZWN0QXR0ZW1wdCA9IDA7XG5cbiAgICAgICAgdGhpcy5jb25maWcuX2FkZE9uT3B0aW9uU2V0dGluZ0NoYW5nZWRMaXN0ZW5lcihcbiAgICAgICAgICAgIE9wdGlvblBhcmFtZXRlcnMuU3RyZWFtZXJJZCxcbiAgICAgICAgICAgIChzdHJlYW1lcmlkKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYoc3RyZWFtZXJpZCA9PT0gXCJcIikge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gY2xvc2UgdGhlIGN1cnJlbnQgcGVlciBjb25uZWN0aW9uIGFuZCBjcmVhdGUgYSBuZXcgb25lXG4gICAgICAgICAgICAgICAgdGhpcy5wZWVyQ29ubmVjdGlvbkNvbnRyb2xsZXIucGVlckNvbm5lY3Rpb24uY2xvc2UoKTtcbiAgICAgICAgICAgICAgICB0aGlzLnBlZXJDb25uZWN0aW9uQ29udHJvbGxlci5jcmVhdGVQZWVyQ29ubmVjdGlvbihcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wZWVyQ29uZmlnLFxuICAgICAgICAgICAgICAgICAgICB0aGlzLnByZWZlcnJlZENvZGVjXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB0aGlzLnN1YnNjcmliZWRTdHJlYW0gPSBzdHJlYW1lcmlkO1xuICAgICAgICAgICAgICAgIHRoaXMud2ViU29ja2V0Q29udHJvbGxlci5zZW5kU3Vic2NyaWJlKHN0cmVhbWVyaWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMuc2V0VmlkZW9FbmNvZGVyQXZnUVAoLTEpO1xuXG4gICAgICAgIHRoaXMuc2lnbmFsbGluZ1VybEJ1aWxkZXIgPSAgKCkgPT4ge1xuICAgICAgICAgICAgbGV0IHNpZ25hbGxpbmdTZXJ2ZXJVcmwgPSB0aGlzLmNvbmZpZy5nZXRUZXh0U2V0dGluZ1ZhbHVlKFxuICAgICAgICAgICAgICAgIFRleHRQYXJhbWV0ZXJzLlNpZ25hbGxpbmdTZXJ2ZXJVcmxcbiAgICAgICAgICAgICk7XG4gICAgXG4gICAgICAgICAgICAvLyBJZiB3ZSBhcmUgY29ubmVjdGluZyB0byB0aGUgU0ZVIGFkZCBhIHNwZWNpYWwgdXJsIHBhcmFtZXRlciB0byB0aGUgdXJsXG4gICAgICAgICAgICBpZiAodGhpcy5jb25maWcuaXNGbGFnRW5hYmxlZChGbGFncy5Ccm93c2VyU2VuZE9mZmVyKSkge1xuICAgICAgICAgICAgICAgIHNpZ25hbGxpbmdTZXJ2ZXJVcmwgKz0gJz8nICsgRmxhZ3MuQnJvd3NlclNlbmRPZmZlciArICc9dHJ1ZSc7XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICAvLyBUaGlzIGNvZGUgaXMgbm8gbG9uZ2VyIG5lZWRlZCwgYnV0IGlzIGEgZ29vZCBleGFtcGxlIGZvciBob3cgc3Vic2VxdWVudCBjb25maWcgZmxhZ3MgY2FuIGJlIGFwcGVuZGVkXG4gICAgICAgICAgICAvLyBpZiAodGhpcy5jb25maWcuaXNGbGFnRW5hYmxlZChGbGFncy5Ccm93c2VyU2VuZE9mZmVyKSkge1xuICAgICAgICAgICAgLy8gICAgIHNpZ25hbGxpbmdTZXJ2ZXJVcmwgKz0gKHNpZ25hbGxpbmdTZXJ2ZXJVcmwuaW5jbHVkZXMoJz8nKSA/ICcmJyA6ICc/JykgKyBGbGFncy5Ccm93c2VyU2VuZE9mZmVyICsgJz10cnVlJztcbiAgICAgICAgICAgIC8vIH1cbiAgICBcbiAgICAgICAgICAgIHJldHVybiBzaWduYWxsaW5nU2VydmVyVXJsO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTWFrZSBhIHJlcXVlc3QgdG8gVW5xdWFudGl6ZWRBbmREZW5vcm1hbGl6ZVVuc2lnbmVkIGNvb3JkaW5hdGVzXG4gICAgICogQHBhcmFtIHggeCBheGlzIGNvb3JkaW5hdGVcbiAgICAgKiBAcGFyYW0geSB5IGF4aXMgY29vcmRpbmF0ZVxuICAgICAqL1xuICAgIHJlcXVlc3RVbnF1YW50aXplZEFuZERlbm9ybWFsaXplVW5zaWduZWQoXG4gICAgICAgIHg6IG51bWJlcixcbiAgICAgICAgeTogbnVtYmVyXG4gICAgKTogVW5xdWFudGl6ZWREZW5vcm1hbGl6ZWRVbnNpZ25lZENvb3JkIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY29vcmRpbmF0ZUNvbnZlcnRlci51bnF1YW50aXplQW5kRGVub3JtYWxpemVVbnNpZ25lZCh4LCB5KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGVzIHdoZW4gYSBtZXNzYWdlIGlzIHJlY2VpdmVkXG4gICAgICogQHBhcmFtIGV2ZW50IC0gTWVzc2FnZSBFdmVudFxuICAgICAqL1xuICAgIGhhbmRsZU9uTWVzc2FnZShldmVudDogTWVzc2FnZUV2ZW50KSB7XG4gICAgICAgIGNvbnN0IG1lc3NhZ2UgPSBuZXcgVWludDhBcnJheShldmVudC5kYXRhKTtcbiAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCAnTWVzc2FnZSBpbmNvbWluZzonICsgbWVzc2FnZSwgNik7XG5cbiAgICAgICAgLy90cnkge1xuICAgICAgICBjb25zdCBtZXNzYWdlVHlwZSA9XG4gICAgICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLmZyb21TdHJlYW1lck1lc3NhZ2VzLmdldChcbiAgICAgICAgICAgICAgICBtZXNzYWdlWzBdXG4gICAgICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLmZyb21TdHJlYW1lckhhbmRsZXJzLmdldChtZXNzYWdlVHlwZSkoXG4gICAgICAgICAgICBldmVudC5kYXRhXG4gICAgICAgICk7XG4gICAgICAgIC8vfSBjYXRjaCAoZSkge1xuICAgICAgICAvL0xvZ2dlci5FcnJvcihMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCBgQ3VzdG9tIGRhdGEgY2hhbm5lbCBtZXNzYWdlIHdpdGggbWVzc2FnZSB0eXBlIHRoYXQgaXMgdW5rbm93biB0byB0aGUgUGl4ZWwgU3RyZWFtaW5nIHByb3RvY29sLiBEb2VzIHlvdXIgUGl4ZWxTdHJlYW1pbmdQcm90b2NvbCBuZWVkIHVwZGF0aW5nPyBUaGUgbWVzc2FnZSB0eXBlIHdhczogJHttZXNzYWdlWzBdfWApO1xuICAgICAgICAvL31cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZWdpc3RlciBtZXNzYWdlIGFsbCBoYW5kbGVyc1xuICAgICAqL1xuICAgIHJlZ2lzdGVyTWVzc2FnZUhhbmRsZXJzKCkge1xuICAgICAgICAvLyBGcm9tIFN0cmVhbWVyXG4gICAgICAgIC8vIE1lc3NhZ2UgZXZlbnRzIGZyb20gdGhlIHN0cmVhbWVyIGhhdmUgYSBkYXRhIHR5cGUgb2YgQXJyYXlCdWZmZXIgYXMgd2UgZm9yY2UgdGhpcyB0eXBlIGluIHRoZSBEYXRhY2hhbm5lbENvbnRyb2xsZXJcbiAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci5yZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZURpcmVjdGlvbi5Gcm9tU3RyZWFtZXIsXG4gICAgICAgICAgICAnUXVhbGl0eUNvbnRyb2xPd25lcnNoaXAnLFxuICAgICAgICAgICAgKGRhdGE6IEFycmF5QnVmZmVyKSA9PiB0aGlzLm9uUXVhbGl0eUNvbnRyb2xPd25lcnNoaXAoZGF0YSlcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci5yZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZURpcmVjdGlvbi5Gcm9tU3RyZWFtZXIsXG4gICAgICAgICAgICAnUmVzcG9uc2UnLFxuICAgICAgICAgICAgKGRhdGE6IEFycmF5QnVmZmVyKSA9PiB0aGlzLnJlc3BvbnNlQ29udHJvbGxlci5vblJlc3BvbnNlKGRhdGEpXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VEaXJlY3Rpb24uRnJvbVN0cmVhbWVyLFxuICAgICAgICAgICAgJ0NvbW1hbmQnLFxuICAgICAgICAgICAgKGRhdGE6IEFycmF5QnVmZmVyKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5vbkNvbW1hbmQoZGF0YSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VEaXJlY3Rpb24uRnJvbVN0cmVhbWVyLFxuICAgICAgICAgICAgJ0ZyZWV6ZUZyYW1lJyxcbiAgICAgICAgICAgIChkYXRhOiBBcnJheUJ1ZmZlcikgPT4gdGhpcy5vbkZyZWV6ZUZyYW1lTWVzc2FnZShkYXRhKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLkZyb21TdHJlYW1lcixcbiAgICAgICAgICAgICdVbmZyZWV6ZUZyYW1lJyxcbiAgICAgICAgICAgICgpID0+IHRoaXMuaW52YWxpZGF0ZUZyZWV6ZUZyYW1lQW5kRW5hYmxlVmlkZW8oKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLkZyb21TdHJlYW1lcixcbiAgICAgICAgICAgICdWaWRlb0VuY29kZXJBdmdRUCcsXG4gICAgICAgICAgICAoZGF0YTogQXJyYXlCdWZmZXIpID0+IHRoaXMuaGFuZGxlVmlkZW9FbmNvZGVyQXZnUVAoZGF0YSlcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci5yZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZURpcmVjdGlvbi5Gcm9tU3RyZWFtZXIsXG4gICAgICAgICAgICAnTGF0ZW5jeVRlc3QnLFxuICAgICAgICAgICAgKGRhdGE6IEFycmF5QnVmZmVyKSA9PiB0aGlzLmhhbmRsZUxhdGVuY3lUZXN0UmVzdWx0KGRhdGEpXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VEaXJlY3Rpb24uRnJvbVN0cmVhbWVyLFxuICAgICAgICAgICAgJ0RhdGFDaGFubmVsTGF0ZW5jeVRlc3QnLFxuICAgICAgICAgICAgKGRhdGE6IEFycmF5QnVmZmVyKSA9PiB0aGlzLmhhbmRsZURhdGFDaGFubmVsTGF0ZW5jeVRlc3RSZXNwb25zZShkYXRhKVxuICAgICAgICApXG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VEaXJlY3Rpb24uRnJvbVN0cmVhbWVyLFxuICAgICAgICAgICAgJ0luaXRpYWxTZXR0aW5ncycsXG4gICAgICAgICAgICAoZGF0YTogQXJyYXlCdWZmZXIpID0+IHRoaXMuaGFuZGxlSW5pdGlhbFNldHRpbmdzKGRhdGEpXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VEaXJlY3Rpb24uRnJvbVN0cmVhbWVyLFxuICAgICAgICAgICAgJ0ZpbGVFeHRlbnNpb24nLFxuICAgICAgICAgICAgKGRhdGE6IEFycmF5QnVmZmVyKSA9PiB0aGlzLm9uRmlsZUV4dGVuc2lvbihkYXRhKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLkZyb21TdHJlYW1lcixcbiAgICAgICAgICAgICdGaWxlTWltZVR5cGUnLFxuICAgICAgICAgICAgKGRhdGE6IEFycmF5QnVmZmVyKSA9PiB0aGlzLm9uRmlsZU1pbWVUeXBlKGRhdGEpXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VEaXJlY3Rpb24uRnJvbVN0cmVhbWVyLFxuICAgICAgICAgICAgJ0ZpbGVDb250ZW50cycsXG4gICAgICAgICAgICAoZGF0YTogQXJyYXlCdWZmZXIpID0+IHRoaXMub25GaWxlQ29udGVudHMoZGF0YSlcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci5yZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZURpcmVjdGlvbi5Gcm9tU3RyZWFtZXIsXG4gICAgICAgICAgICAnVGVzdEVjaG8nLFxuICAgICAgICAgICAgKCkgPT4ge1xuICAgICAgICAgICAgICAgIC8qIERvIG5vdGhpbmcgKi9cbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci5yZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZURpcmVjdGlvbi5Gcm9tU3RyZWFtZXIsXG4gICAgICAgICAgICAnSW5wdXRDb250cm9sT3duZXJzaGlwJyxcbiAgICAgICAgICAgIChkYXRhOiBBcnJheUJ1ZmZlcikgPT4gdGhpcy5vbklucHV0Q29udHJvbE93bmVyc2hpcChkYXRhKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLkZyb21TdHJlYW1lcixcbiAgICAgICAgICAgICdHYW1lcGFkUmVzcG9uc2UnLFxuICAgICAgICAgICAgKGRhdGE6IEFycmF5QnVmZmVyKSA9PiB0aGlzLm9uR2FtZXBhZFJlc3BvbnNlKGRhdGEpXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VEaXJlY3Rpb24uRnJvbVN0cmVhbWVyLFxuICAgICAgICAgICAgJ1Byb3RvY29sJyxcbiAgICAgICAgICAgIChkYXRhOiBBcnJheUJ1ZmZlcikgPT4gdGhpcy5vblByb3RvY29sTWVzc2FnZShkYXRhKVxuICAgICAgICApO1xuXG4gICAgICAgIC8vIFRvIFN0cmVhbWVyXG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VEaXJlY3Rpb24uVG9TdHJlYW1lcixcbiAgICAgICAgICAgICdJRnJhbWVSZXF1ZXN0JyxcbiAgICAgICAgICAgICgpID0+XG4gICAgICAgICAgICAgICAgdGhpcy5zZW5kTWVzc2FnZUNvbnRyb2xsZXIuc2VuZE1lc3NhZ2VUb1N0cmVhbWVyKFxuICAgICAgICAgICAgICAgICAgICAnSUZyYW1lUmVxdWVzdCdcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VEaXJlY3Rpb24uVG9TdHJlYW1lcixcbiAgICAgICAgICAgICdSZXF1ZXN0UXVhbGl0eUNvbnRyb2wnLFxuICAgICAgICAgICAgKCkgPT5cbiAgICAgICAgICAgICAgICB0aGlzLnNlbmRNZXNzYWdlQ29udHJvbGxlci5zZW5kTWVzc2FnZVRvU3RyZWFtZXIoXG4gICAgICAgICAgICAgICAgICAgICdSZXF1ZXN0UXVhbGl0eUNvbnRyb2wnXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLlRvU3RyZWFtZXIsXG4gICAgICAgICAgICAnRnBzUmVxdWVzdCcsXG4gICAgICAgICAgICAoKSA9PiB0aGlzLnNlbmRNZXNzYWdlQ29udHJvbGxlci5zZW5kTWVzc2FnZVRvU3RyZWFtZXIoJ0Zwc1JlcXVlc3QnKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLlRvU3RyZWFtZXIsXG4gICAgICAgICAgICAnQXZlcmFnZUJpdHJhdGVSZXF1ZXN0JyxcbiAgICAgICAgICAgICgpID0+XG4gICAgICAgICAgICAgICAgdGhpcy5zZW5kTWVzc2FnZUNvbnRyb2xsZXIuc2VuZE1lc3NhZ2VUb1N0cmVhbWVyKFxuICAgICAgICAgICAgICAgICAgICAnQXZlcmFnZUJpdHJhdGVSZXF1ZXN0J1xuICAgICAgICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci5yZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZURpcmVjdGlvbi5Ub1N0cmVhbWVyLFxuICAgICAgICAgICAgJ1N0YXJ0U3RyZWFtaW5nJyxcbiAgICAgICAgICAgICgpID0+XG4gICAgICAgICAgICAgICAgdGhpcy5zZW5kTWVzc2FnZUNvbnRyb2xsZXIuc2VuZE1lc3NhZ2VUb1N0cmVhbWVyKFxuICAgICAgICAgICAgICAgICAgICAnU3RhcnRTdHJlYW1pbmcnXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLlRvU3RyZWFtZXIsXG4gICAgICAgICAgICAnU3RvcFN0cmVhbWluZycsXG4gICAgICAgICAgICAoKSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuc2VuZE1lc3NhZ2VDb250cm9sbGVyLnNlbmRNZXNzYWdlVG9TdHJlYW1lcihcbiAgICAgICAgICAgICAgICAgICAgJ1N0b3BTdHJlYW1pbmcnXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLlRvU3RyZWFtZXIsXG4gICAgICAgICAgICAnTGF0ZW5jeVRlc3QnLFxuICAgICAgICAgICAgKGRhdGE6IEFycmF5PG51bWJlciB8IHN0cmluZz4pID0+XG4gICAgICAgICAgICAgICAgdGhpcy5zZW5kTWVzc2FnZUNvbnRyb2xsZXIuc2VuZE1lc3NhZ2VUb1N0cmVhbWVyKFxuICAgICAgICAgICAgICAgICAgICAnTGF0ZW5jeVRlc3QnLCBkYXRhXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLlRvU3RyZWFtZXIsXG4gICAgICAgICAgICAnUmVxdWVzdEluaXRpYWxTZXR0aW5ncycsXG4gICAgICAgICAgICAoKSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuc2VuZE1lc3NhZ2VDb250cm9sbGVyLnNlbmRNZXNzYWdlVG9TdHJlYW1lcihcbiAgICAgICAgICAgICAgICAgICAgJ1JlcXVlc3RJbml0aWFsU2V0dGluZ3MnXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLlRvU3RyZWFtZXIsXG4gICAgICAgICAgICAnVGVzdEVjaG8nLFxuICAgICAgICAgICAgKCkgPT4ge1xuICAgICAgICAgICAgICAgIC8qIERvIG5vdGhpbmcgKi9cbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci5yZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZURpcmVjdGlvbi5Ub1N0cmVhbWVyLFxuICAgICAgICAgICAgJ1VJSW50ZXJhY3Rpb24nLFxuICAgICAgICAgICAgKGRhdGE6IEFycmF5PG51bWJlciB8IHN0cmluZz4pID0+XG4gICAgICAgICAgICAgICAgdGhpcy5zZW5kTWVzc2FnZUNvbnRyb2xsZXIuc2VuZE1lc3NhZ2VUb1N0cmVhbWVyKFxuICAgICAgICAgICAgICAgICAgICAnVUlJbnRlcmFjdGlvbicsIGRhdGFcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VEaXJlY3Rpb24uVG9TdHJlYW1lcixcbiAgICAgICAgICAgICdDb21tYW5kJyxcbiAgICAgICAgICAgIChkYXRhOiBBcnJheTxudW1iZXIgfCBzdHJpbmc+KSA9PiBcbiAgICAgICAgICAgICAgICB0aGlzLnNlbmRNZXNzYWdlQ29udHJvbGxlci5zZW5kTWVzc2FnZVRvU3RyZWFtZXIoXG4gICAgICAgICAgICAgICAgICAgICdDb21tYW5kJywgZGF0YVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci5yZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZURpcmVjdGlvbi5Ub1N0cmVhbWVyLFxuICAgICAgICAgICAgJ1RleHRib3hFbnRyeScsXG4gICAgICAgICAgICAoZGF0YTogQXJyYXk8bnVtYmVyIHwgc3RyaW5nPikgPT4gXG4gICAgICAgICAgICAgICAgdGhpcy5zZW5kTWVzc2FnZUNvbnRyb2xsZXIuc2VuZE1lc3NhZ2VUb1N0cmVhbWVyKFxuICAgICAgICAgICAgICAgICAgICAnVGV4dGJveEVudHJ5JywgZGF0YVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci5yZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZURpcmVjdGlvbi5Ub1N0cmVhbWVyLFxuICAgICAgICAgICAgJ0tleURvd24nLFxuICAgICAgICAgICAgKGRhdGE6IEFycmF5PG51bWJlciB8IHN0cmluZz4pID0+XG4gICAgICAgICAgICAgICAgdGhpcy5zZW5kTWVzc2FnZUNvbnRyb2xsZXIuc2VuZE1lc3NhZ2VUb1N0cmVhbWVyKFxuICAgICAgICAgICAgICAgICAgICAnS2V5RG93bicsXG4gICAgICAgICAgICAgICAgICAgIGRhdGFcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VEaXJlY3Rpb24uVG9TdHJlYW1lcixcbiAgICAgICAgICAgICdLZXlVcCcsXG4gICAgICAgICAgICAoZGF0YTogQXJyYXk8bnVtYmVyIHwgc3RyaW5nPikgPT5cbiAgICAgICAgICAgICAgICB0aGlzLnNlbmRNZXNzYWdlQ29udHJvbGxlci5zZW5kTWVzc2FnZVRvU3RyZWFtZXIoJ0tleVVwJywgZGF0YSlcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci5yZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZURpcmVjdGlvbi5Ub1N0cmVhbWVyLFxuICAgICAgICAgICAgJ0tleVByZXNzJyxcbiAgICAgICAgICAgIChkYXRhOiBBcnJheTxudW1iZXIgfCBzdHJpbmc+KSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuc2VuZE1lc3NhZ2VDb250cm9sbGVyLnNlbmRNZXNzYWdlVG9TdHJlYW1lcihcbiAgICAgICAgICAgICAgICAgICAgJ0tleVByZXNzJyxcbiAgICAgICAgICAgICAgICAgICAgZGF0YVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci5yZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZURpcmVjdGlvbi5Ub1N0cmVhbWVyLFxuICAgICAgICAgICAgJ01vdXNlRW50ZXInLFxuICAgICAgICAgICAgKGRhdGE6IEFycmF5PG51bWJlciB8IHN0cmluZz4pID0+XG4gICAgICAgICAgICAgICAgdGhpcy5zZW5kTWVzc2FnZUNvbnRyb2xsZXIuc2VuZE1lc3NhZ2VUb1N0cmVhbWVyKFxuICAgICAgICAgICAgICAgICAgICAnTW91c2VFbnRlcicsXG4gICAgICAgICAgICAgICAgICAgIGRhdGFcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VEaXJlY3Rpb24uVG9TdHJlYW1lcixcbiAgICAgICAgICAgICdNb3VzZUxlYXZlJyxcbiAgICAgICAgICAgIChkYXRhOiBBcnJheTxudW1iZXIgfCBzdHJpbmc+KSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuc2VuZE1lc3NhZ2VDb250cm9sbGVyLnNlbmRNZXNzYWdlVG9TdHJlYW1lcihcbiAgICAgICAgICAgICAgICAgICAgJ01vdXNlTGVhdmUnLFxuICAgICAgICAgICAgICAgICAgICBkYXRhXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLlRvU3RyZWFtZXIsXG4gICAgICAgICAgICAnTW91c2VEb3duJyxcbiAgICAgICAgICAgIChkYXRhOiBBcnJheTxudW1iZXIgfCBzdHJpbmc+KSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuc2VuZE1lc3NhZ2VDb250cm9sbGVyLnNlbmRNZXNzYWdlVG9TdHJlYW1lcihcbiAgICAgICAgICAgICAgICAgICAgJ01vdXNlRG93bicsXG4gICAgICAgICAgICAgICAgICAgIGRhdGFcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VEaXJlY3Rpb24uVG9TdHJlYW1lcixcbiAgICAgICAgICAgICdNb3VzZVVwJyxcbiAgICAgICAgICAgIChkYXRhOiBBcnJheTxudW1iZXIgfCBzdHJpbmc+KSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuc2VuZE1lc3NhZ2VDb250cm9sbGVyLnNlbmRNZXNzYWdlVG9TdHJlYW1lcihcbiAgICAgICAgICAgICAgICAgICAgJ01vdXNlVXAnLFxuICAgICAgICAgICAgICAgICAgICBkYXRhXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLlRvU3RyZWFtZXIsXG4gICAgICAgICAgICAnTW91c2VNb3ZlJyxcbiAgICAgICAgICAgIChkYXRhOiBBcnJheTxudW1iZXIgfCBzdHJpbmc+KSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuc2VuZE1lc3NhZ2VDb250cm9sbGVyLnNlbmRNZXNzYWdlVG9TdHJlYW1lcihcbiAgICAgICAgICAgICAgICAgICAgJ01vdXNlTW92ZScsXG4gICAgICAgICAgICAgICAgICAgIGRhdGFcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VEaXJlY3Rpb24uVG9TdHJlYW1lcixcbiAgICAgICAgICAgICdNb3VzZVdoZWVsJyxcbiAgICAgICAgICAgIChkYXRhOiBBcnJheTxudW1iZXIgfCBzdHJpbmc+KSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuc2VuZE1lc3NhZ2VDb250cm9sbGVyLnNlbmRNZXNzYWdlVG9TdHJlYW1lcihcbiAgICAgICAgICAgICAgICAgICAgJ01vdXNlV2hlZWwnLFxuICAgICAgICAgICAgICAgICAgICBkYXRhXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLlRvU3RyZWFtZXIsXG4gICAgICAgICAgICAnTW91c2VEb3VibGUnLFxuICAgICAgICAgICAgKGRhdGE6IEFycmF5PG51bWJlciB8IHN0cmluZz4pID0+XG4gICAgICAgICAgICAgICAgdGhpcy5zZW5kTWVzc2FnZUNvbnRyb2xsZXIuc2VuZE1lc3NhZ2VUb1N0cmVhbWVyKFxuICAgICAgICAgICAgICAgICAgICAnTW91c2VEb3VibGUnLFxuICAgICAgICAgICAgICAgICAgICBkYXRhXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLlRvU3RyZWFtZXIsXG4gICAgICAgICAgICAnVG91Y2hTdGFydCcsXG4gICAgICAgICAgICAoZGF0YTogQXJyYXk8bnVtYmVyIHwgc3RyaW5nPikgPT5cbiAgICAgICAgICAgICAgICB0aGlzLnNlbmRNZXNzYWdlQ29udHJvbGxlci5zZW5kTWVzc2FnZVRvU3RyZWFtZXIoXG4gICAgICAgICAgICAgICAgICAgICdUb3VjaFN0YXJ0JyxcbiAgICAgICAgICAgICAgICAgICAgZGF0YVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci5yZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZURpcmVjdGlvbi5Ub1N0cmVhbWVyLFxuICAgICAgICAgICAgJ1RvdWNoRW5kJyxcbiAgICAgICAgICAgIChkYXRhOiBBcnJheTxudW1iZXIgfCBzdHJpbmc+KSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuc2VuZE1lc3NhZ2VDb250cm9sbGVyLnNlbmRNZXNzYWdlVG9TdHJlYW1lcihcbiAgICAgICAgICAgICAgICAgICAgJ1RvdWNoRW5kJyxcbiAgICAgICAgICAgICAgICAgICAgZGF0YVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci5yZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZURpcmVjdGlvbi5Ub1N0cmVhbWVyLFxuICAgICAgICAgICAgJ1RvdWNoTW92ZScsXG4gICAgICAgICAgICAoZGF0YTogQXJyYXk8bnVtYmVyIHwgc3RyaW5nPikgPT5cbiAgICAgICAgICAgICAgICB0aGlzLnNlbmRNZXNzYWdlQ29udHJvbGxlci5zZW5kTWVzc2FnZVRvU3RyZWFtZXIoXG4gICAgICAgICAgICAgICAgICAgICdUb3VjaE1vdmUnLFxuICAgICAgICAgICAgICAgICAgICBkYXRhXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLlRvU3RyZWFtZXIsXG4gICAgICAgICAgICAnR2FtZXBhZENvbm5lY3RlZCcsXG4gICAgICAgICAgICAoKSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuc2VuZE1lc3NhZ2VDb250cm9sbGVyLnNlbmRNZXNzYWdlVG9TdHJlYW1lcihcbiAgICAgICAgICAgICAgICAgICAgJ0dhbWVwYWRDb25uZWN0ZWQnXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLlRvU3RyZWFtZXIsXG4gICAgICAgICAgICAnR2FtZXBhZEJ1dHRvblByZXNzZWQnLFxuICAgICAgICAgICAgKGRhdGE6IEFycmF5PG51bWJlciB8IHN0cmluZz4pID0+XG4gICAgICAgICAgICAgICAgdGhpcy5zZW5kTWVzc2FnZUNvbnRyb2xsZXIuc2VuZE1lc3NhZ2VUb1N0cmVhbWVyKFxuICAgICAgICAgICAgICAgICAgICAnR2FtZXBhZEJ1dHRvblByZXNzZWQnLFxuICAgICAgICAgICAgICAgICAgICBkYXRhXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLlRvU3RyZWFtZXIsXG4gICAgICAgICAgICAnR2FtZXBhZEJ1dHRvblJlbGVhc2VkJyxcbiAgICAgICAgICAgIChkYXRhOiBBcnJheTxudW1iZXIgfCBzdHJpbmc+KSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuc2VuZE1lc3NhZ2VDb250cm9sbGVyLnNlbmRNZXNzYWdlVG9TdHJlYW1lcihcbiAgICAgICAgICAgICAgICAgICAgJ0dhbWVwYWRCdXR0b25SZWxlYXNlZCcsXG4gICAgICAgICAgICAgICAgICAgIGRhdGFcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VEaXJlY3Rpb24uVG9TdHJlYW1lcixcbiAgICAgICAgICAgICdHYW1lcGFkQW5hbG9nJyxcbiAgICAgICAgICAgIChkYXRhOiBBcnJheTxudW1iZXIgfCBzdHJpbmc+KSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuc2VuZE1lc3NhZ2VDb250cm9sbGVyLnNlbmRNZXNzYWdlVG9TdHJlYW1lcihcbiAgICAgICAgICAgICAgICAgICAgJ0dhbWVwYWRBbmFsb2cnLFxuICAgICAgICAgICAgICAgICAgICBkYXRhXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLlRvU3RyZWFtZXIsXG4gICAgICAgICAgICAnR2FtZXBhZERpc2Nvbm5lY3RlZCcsXG4gICAgICAgICAgICAoZGF0YTogQXJyYXk8bnVtYmVyIHwgc3RyaW5nPikgPT5cbiAgICAgICAgICAgICAgICB0aGlzLnNlbmRNZXNzYWdlQ29udHJvbGxlci5zZW5kTWVzc2FnZVRvU3RyZWFtZXIoXG4gICAgICAgICAgICAgICAgICAgICdHYW1lcGFkRGlzY29ubmVjdGVkJyxcbiAgICAgICAgICAgICAgICAgICAgZGF0YVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci5yZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZURpcmVjdGlvbi5Ub1N0cmVhbWVyLFxuICAgICAgICAgICAgJ1hSSE1EVHJhbnNmb3JtJyxcbiAgICAgICAgICAgIChkYXRhOiBBcnJheTxudW1iZXIgfCBzdHJpbmc+KSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuc2VuZE1lc3NhZ2VDb250cm9sbGVyLnNlbmRNZXNzYWdlVG9TdHJlYW1lcihcbiAgICAgICAgICAgICAgICAgICAgJ1hSSE1EVHJhbnNmb3JtJyxcbiAgICAgICAgICAgICAgICAgICAgZGF0YVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci5yZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZURpcmVjdGlvbi5Ub1N0cmVhbWVyLFxuICAgICAgICAgICAgJ1hSQ29udHJvbGxlclRyYW5zZm9ybScsXG4gICAgICAgICAgICAoZGF0YTogQXJyYXk8bnVtYmVyIHwgc3RyaW5nPikgPT5cbiAgICAgICAgICAgICAgICB0aGlzLnNlbmRNZXNzYWdlQ29udHJvbGxlci5zZW5kTWVzc2FnZVRvU3RyZWFtZXIoXG4gICAgICAgICAgICAgICAgICAgICdYUkNvbnRyb2xsZXJUcmFuc2Zvcm0nLFxuICAgICAgICAgICAgICAgICAgICBkYXRhXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLlRvU3RyZWFtZXIsXG4gICAgICAgICAgICAnWFJTeXN0ZW0nLFxuICAgICAgICAgICAgKGRhdGE6IEFycmF5PG51bWJlciB8IHN0cmluZz4pID0+XG4gICAgICAgICAgICAgICAgdGhpcy5zZW5kTWVzc2FnZUNvbnRyb2xsZXIuc2VuZE1lc3NhZ2VUb1N0cmVhbWVyKFxuICAgICAgICAgICAgICAgICAgICAnWFJTeXN0ZW0nLFxuICAgICAgICAgICAgICAgICAgICBkYXRhXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlRGlyZWN0aW9uLlRvU3RyZWFtZXIsXG4gICAgICAgICAgICAnWFJCdXR0b25Ub3VjaGVkJyxcbiAgICAgICAgICAgIChkYXRhOiBBcnJheTxudW1iZXIgfCBzdHJpbmc+KSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuc2VuZE1lc3NhZ2VDb250cm9sbGVyLnNlbmRNZXNzYWdlVG9TdHJlYW1lcihcbiAgICAgICAgICAgICAgICAgICAgJ1hSQnV0dG9uVG91Y2hlZCcsXG4gICAgICAgICAgICAgICAgICAgIGRhdGFcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VEaXJlY3Rpb24uVG9TdHJlYW1lcixcbiAgICAgICAgICAgICdYUkJ1dHRvblByZXNzZWQnLFxuICAgICAgICAgICAgKGRhdGE6IEFycmF5PG51bWJlciB8IHN0cmluZz4pID0+XG4gICAgICAgICAgICAgICAgdGhpcy5zZW5kTWVzc2FnZUNvbnRyb2xsZXIuc2VuZE1lc3NhZ2VUb1N0cmVhbWVyKFxuICAgICAgICAgICAgICAgICAgICAnWFJCdXR0b25QcmVzc2VkJyxcbiAgICAgICAgICAgICAgICAgICAgZGF0YVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci5yZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZURpcmVjdGlvbi5Ub1N0cmVhbWVyLFxuICAgICAgICAgICAgJ1hSQnV0dG9uUmVsZWFzZWQnLFxuICAgICAgICAgICAgKGRhdGE6IEFycmF5PG51bWJlciB8IHN0cmluZz4pID0+XG4gICAgICAgICAgICAgICAgdGhpcy5zZW5kTWVzc2FnZUNvbnRyb2xsZXIuc2VuZE1lc3NhZ2VUb1N0cmVhbWVyKFxuICAgICAgICAgICAgICAgICAgICAnWFJCdXR0b25SZWxlYXNlZCcsXG4gICAgICAgICAgICAgICAgICAgIGRhdGFcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VEaXJlY3Rpb24uVG9TdHJlYW1lcixcbiAgICAgICAgICAgICdYUkFuYWxvZycsXG4gICAgICAgICAgICAoZGF0YTogQXJyYXk8bnVtYmVyIHwgc3RyaW5nPikgPT5cbiAgICAgICAgICAgICAgICB0aGlzLnNlbmRNZXNzYWdlQ29udHJvbGxlci5zZW5kTWVzc2FnZVRvU3RyZWFtZXIoXG4gICAgICAgICAgICAgICAgICAgICdYUkFuYWxvZycsXG4gICAgICAgICAgICAgICAgICAgIGRhdGFcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQWN0aXZhdGUgdGhlIGxvZ2ljIGFzc29jaWF0ZWQgd2l0aCBhIGNvbW1hbmQgZnJvbSBVRVxuICAgICAqIEBwYXJhbSBtZXNzYWdlXG4gICAgICovXG4gICAgb25Db21tYW5kKG1lc3NhZ2U6IEFycmF5QnVmZmVyKSB7XG4gICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgJ0RhdGFDaGFubmVsUmVjZWl2ZU1lc3NhZ2VUeXBlLkNvbW1hbmQnLFxuICAgICAgICAgICAgNlxuICAgICAgICApO1xuICAgICAgICBjb25zdCBjb21tYW5kQXNTdHJpbmcgPSBuZXcgVGV4dERlY29kZXIoJ3V0Zi0xNicpLmRlY29kZShcbiAgICAgICAgICAgIG1lc3NhZ2Uuc2xpY2UoMSlcbiAgICAgICAgKTtcblxuICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICdEYXRhIENoYW5uZWwgQ29tbWFuZDogJyArIGNvbW1hbmRBc1N0cmluZyxcbiAgICAgICAgICAgIDZcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgY29tbWFuZDogTWVzc2FnZU9uU2NyZWVuS2V5Ym9hcmQgPSBKU09OLnBhcnNlKGNvbW1hbmRBc1N0cmluZyk7XG4gICAgICAgIGlmIChjb21tYW5kLmNvbW1hbmQgPT09ICdvblNjcmVlbktleWJvYXJkJykge1xuICAgICAgICAgICAgdGhpcy5waXhlbFN0cmVhbWluZy5fYWN0aXZhdGVPblNjcmVlbktleWJvYXJkKGNvbW1hbmQpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSGFuZGxlcyBhIHByb3RvY29sIG1lc3NhZ2UgcmVjZWl2ZWQgZnJvbSB0aGUgc3RyZWFtZXJcbiAgICAgKiBAcGFyYW0gbWVzc2FnZSB0aGUgbWVzc2FnZSBkYXRhIGZyb20gdGhlIHN0cmVhbWVyXG4gICAgICovXG4gICAgb25Qcm90b2NvbE1lc3NhZ2UobWVzc2FnZTogQXJyYXlCdWZmZXIpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHByb3RvY29sU3RyaW5nID0gbmV3IFRleHREZWNvZGVyKCd1dGYtMTYnKS5kZWNvZGUoXG4gICAgICAgICAgICAgICAgbWVzc2FnZS5zbGljZSgxKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIGNvbnN0IHByb3RvY29sSlNPTiA9IEpTT04ucGFyc2UocHJvdG9jb2xTdHJpbmcpO1xuICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocHJvdG9jb2xKU09OLCAnRGlyZWN0aW9uJylcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgIExvZ2dlci5FcnJvcihcbiAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICAgICAgJ01hbGZvcm1lZCBwcm90b2NvbCByZWNlaXZlZC4gRW5zdXJlIHRoZSBwcm90b2NvbCBtZXNzYWdlIGNvbnRhaW5zIGEgZGlyZWN0aW9uJ1xuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBkaXJlY3Rpb24gPSBwcm90b2NvbEpTT04uRGlyZWN0aW9uO1xuICAgICAgICAgICAgZGVsZXRlIHByb3RvY29sSlNPTi5EaXJlY3Rpb247XG4gICAgICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgYFJlY2VpdmVkIG5ldyAke1xuICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPT0gTWVzc2FnZURpcmVjdGlvbi5Gcm9tU3RyZWFtZXJcbiAgICAgICAgICAgICAgICAgICAgICAgID8gJ0Zyb21TdHJlYW1lcidcbiAgICAgICAgICAgICAgICAgICAgICAgIDogJ1RvU3RyZWFtZXInXG4gICAgICAgICAgICAgICAgfSBwcm90b2NvbC4gVXBkYXRpbmcgZXhpc3RpbmcgcHJvdG9jb2wuLi5gXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgT2JqZWN0LmtleXMocHJvdG9jb2xKU09OKS5mb3JFYWNoKChtZXNzYWdlVHlwZSkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IG1lc3NhZ2UgPSBwcm90b2NvbEpTT05bbWVzc2FnZVR5cGVdO1xuICAgICAgICAgICAgICAgIHN3aXRjaCAoZGlyZWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgTWVzc2FnZURpcmVjdGlvbi5Ub1N0cmVhbWVyOlxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ2hlY2sgdGhhdCB0aGUgbWVzc2FnZSBjb250YWlucyBhbGwgdGhlIHJlbGV2YW50IHBhcmFtc1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdpZCdcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBMb2dnZXIuRXJyb3IoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBUb1N0cmVhbWVyLT4ke21lc3NhZ2VUeXBlfSBwcm90b2NvbCBkZWZpbml0aW9uIHdhcyBtYWxmb3JtZWQgYXMgaXQgZGlkbid0IGNvbnRhaW4gYXQgbGVhc3QgYW4gaWRcXG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBEZWZpbml0aW9uIHdhczogJHtKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICl9YFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmV0dXJuIGluIGEgZm9yRWFjaCBpcyBlcXVpdmFsZW50IHRvIGEgY29udGludWUgaW4gYSBub3JtYWwgZm9yIGxvb3BcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFVFNS4xIGFuZCBVRTUuMiBkb24ndCBzZW5kIGEgc3RydWN0dXJlIGZvciB0aGVzZSBtZXNzYWdlIHR5cGVzLCBidXQgdGhleSBhY3R1YWxseSBkbyBoYXZlIGEgc3RydWN0dXJlIHNvIGlnbm9yZSB1cGRhdGluZyB0aGVtXG4gICAgICAgICAgICAgICAgICAgICAgICBpZigobWVzc2FnZVR5cGUgPT09IFwiVUlJbnRlcmFjdGlvblwiIHx8IG1lc3NhZ2VUeXBlID09PSBcIkNvbW1hbmRcIiB8fCBtZXNzYWdlVHlwZSA9PT0gXCJMYXRlbmN5VGVzdFwiKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIudG9TdHJlYW1lckhhbmRsZXJzLmdldChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZVR5cGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJZiB3ZSd2ZSByZWdpc3RlcmVkIGEgaGFuZGxlciBmb3IgdGhpcyBtZXNzYWdlIHR5cGUgd2UgY2FuIGFkZCBpdCB0byBvdXIgc3VwcG9ydGVkIG1lc3NhZ2VzLiBpZSByZWdpc3Rlck1lc3NhZ2VIYW5kbGVyKC4uLilcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnRvU3RyZWFtZXJNZXNzYWdlcy5zZXQoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2VUeXBlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLkVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgVGhlcmUgd2FzIG5vIHJlZ2lzdGVyZWQgaGFuZGxlciBmb3IgXCIke21lc3NhZ2VUeXBlfVwiIC0gdHJ5IGFkZGluZyBvbmUgdXNpbmcgcmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihNZXNzYWdlRGlyZWN0aW9uLlRvU3RyZWFtZXIsIFwiJHttZXNzYWdlVHlwZX1cIiwgbXlIYW5kbGVyKWBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIGNhc2UgTWVzc2FnZURpcmVjdGlvbi5Gcm9tU3RyZWFtZXI6XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBDaGVjayB0aGF0IHRoZSBtZXNzYWdlIGNvbnRhaW5zIGFsbCB0aGUgcmVsZXZhbnQgcGFyYW1zXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChtZXNzYWdlLCAnaWQnKVxuICAgICAgICAgICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLkVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgRnJvbVN0cmVhbWVyLT4ke21lc3NhZ2VUeXBlfSBwcm90b2NvbCBkZWZpbml0aW9uIHdhcyBtYWxmb3JtZWQgYXMgaXQgZGlkbid0IGNvbnRhaW4gYXQgbGVhc3QgYW4gaWRcXG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBEZWZpbml0aW9uIHdhczogJHtKU09OLnN0cmluZ2lmeShtZXNzYWdlLCBudWxsLCAyKX1gXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyByZXR1cm4gaW4gYSBmb3JFYWNoIGlzIGVxdWl2YWxlbnQgdG8gYSBjb250aW51ZSBpbiBhIG5vcm1hbCBmb3IgbG9vcFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLmZyb21TdHJlYW1lckhhbmRsZXJzLmdldChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZVR5cGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJZiB3ZSd2ZSByZWdpc3RlcmVkIGEgaGFuZGxlciBmb3IgdGhpcyBtZXNzYWdlIHR5cGUuIGllIHJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIoLi4uKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIuZnJvbVN0cmVhbWVyTWVzc2FnZXMuc2V0KFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlLmlkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlVHlwZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIExvZ2dlci5FcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYFRoZXJlIHdhcyBubyByZWdpc3RlcmVkIGhhbmRsZXIgZm9yIFwiJHttZXNzYWdlfVwiIC0gdHJ5IGFkZGluZyBvbmUgdXNpbmcgcmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihNZXNzYWdlRGlyZWN0aW9uLkZyb21TdHJlYW1lciwgXCIke21lc3NhZ2VUeXBlfVwiLCBteUhhbmRsZXIpYFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgICAgIExvZ2dlci5FcnJvcihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBVbmtub3duIGRpcmVjdGlvbjogJHtkaXJlY3Rpb259YFxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgLy8gT25jZSB0aGUgcHJvdG9jb2wgaGFzIGJlZW4gcmVjZWl2ZWQsIHdlIGNhbiBzZW5kIG91ciBjb250cm9sIG1lc3NhZ2VzXG4gICAgICAgICAgICB0aGlzLnRvU3RyZWFtZXJNZXNzYWdlc0NvbnRyb2xsZXIuU2VuZFJlcXVlc3RJbml0aWFsU2V0dGluZ3MoKTtcbiAgICAgICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzQ29udHJvbGxlci5TZW5kUmVxdWVzdFF1YWxpdHlDb250cm9sKCk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIExvZ2dlci5Mb2coTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSwgZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGVzIGFuIGlucHV0IGNvbnRyb2wgbWVzc2FnZSB3aGVuIGl0IGlzIHJlY2VpdmVkIGZyb20gdGhlIHN0cmVhbWVyXG4gICAgICogQHBhcmFtIG1lc3NhZ2UgVGhlIGlucHV0IGNvbnRyb2wgbWVzc2FnZVxuICAgICAqL1xuICAgIG9uSW5wdXRDb250cm9sT3duZXJzaGlwKG1lc3NhZ2U6IEFycmF5QnVmZmVyKSB7XG4gICAgICAgIGNvbnN0IHZpZXcgPSBuZXcgVWludDhBcnJheShtZXNzYWdlKTtcbiAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAnRGF0YUNoYW5uZWxSZWNlaXZlTWVzc2FnZVR5cGUuSW5wdXRDb250cm9sT3duZXJzaGlwJyxcbiAgICAgICAgICAgIDZcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgaW5wdXRDb250cm9sT3duZXJzaGlwID0gbmV3IEJvb2xlYW4odmlld1sxXSkudmFsdWVPZigpO1xuICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgIGBSZWNlaXZlZCBpbnB1dCBjb250cm9sbGVyIG1lc3NhZ2UgLSB3aWxsIHlvdXIgaW5wdXQgY29udHJvbCB0aGUgc3RyZWFtOiAke2lucHV0Q29udHJvbE93bmVyc2hpcH1gXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMucGl4ZWxTdHJlYW1pbmcuX29uSW5wdXRDb250cm9sT3duZXJzaGlwKGlucHV0Q29udHJvbE93bmVyc2hpcCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogXG4gICAgICogQHBhcmFtIG1lc3NhZ2UgXG4gICAgICovXG4gICAgb25HYW1lcGFkUmVzcG9uc2UobWVzc2FnZTogQXJyYXlCdWZmZXIpIHtcbiAgICAgICAgY29uc3QgcmVzcG9uc2VTdHJpbmcgPSBuZXcgVGV4dERlY29kZXIoJ3V0Zi0xNicpLmRlY29kZShtZXNzYWdlLnNsaWNlKDEpKTtcbiAgICAgICAgY29uc3QgcmVzcG9uc2VKU09OID0gSlNPTi5wYXJzZShyZXNwb25zZVN0cmluZyk7XG4gICAgICAgIHRoaXMuZ2FtZVBhZENvbnRyb2xsZXIub25HYW1lcGFkUmVzcG9uc2VSZWNlaXZlZChyZXNwb25zZUpTT04uY29udHJvbGxlcklkKTtcbiAgICB9XG5cbiAgICBvbkFma1RyaWdnZXJlZCgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5hZmtDb250cm9sbGVyLm9uQWZrQ2xpY2soKTtcblxuICAgICAgICAvLyBpZiB0aGUgc3RyZWFtIGlzIHBhdXNlZCBwbGF5IGl0LCBpZiB3ZSBjYW5cbiAgICAgICAgaWYgKHRoaXMudmlkZW9QbGF5ZXIuaXNQYXVzZWQoKSAmJiB0aGlzLnZpZGVvUGxheWVyLmhhc1ZpZGVvU291cmNlKCkpIHtcbiAgICAgICAgICAgIHRoaXMucGxheVN0cmVhbSgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0IHdoZXRoZXIgd2Ugc2hvdWxkIHRpbWVvdXQgd2hlbiBhZmsuXG4gICAgICogQHBhcmFtIGFma0VuYWJsZWQgSWYgdHJ1ZSB3ZSB0aW1lb3V0IHdoZW4gaWRsZSBmb3Igc29tZSBnaXZlbiBhbW91bnQgb2YgdGltZS5cbiAgICAgKi9cbiAgICBzZXRBZmtFbmFibGVkKGFma0VuYWJsZWQ6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICAgICAgaWYgKGFma0VuYWJsZWQpIHtcbiAgICAgICAgICAgIHRoaXMub25BZmtUcmlnZ2VyZWQoKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuYWZrQ29udHJvbGxlci5zdG9wQWZrV2FybmluZ1RpbWVyKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBdHRlbXB0IGEgcmVjb25uZWN0aW9uIHRvIHRoZSBzaWduYWxsaW5nIHNlcnZlclxuICAgICAqL1xuICAgIHRyeVJlY29ubmVjdChtZXNzYWdlOiBzdHJpbmcpIHtcbiAgICAgICAgLy8gaWYgdGhlcmUgaXMgbm8gd2ViU29ja2V0Q29udHJvbGxlciByZXR1cm4gaW1tZWRpYXRlbHkgb3IgdGhpcyB3aWxsIG5vdCB3b3JrXG4gICAgICAgIGlmICghdGhpcy53ZWJTb2NrZXRDb250cm9sbGVyKSB7XG4gICAgICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgJ1RoZSBXZWIgU29ja2V0IENvbnRyb2xsZXIgZG9lcyBub3QgZXhpc3Qgc28gdGhpcyB3aWxsIG5vdCB3b3JrIHJpZ2h0IG5vdy4nXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gaWYgdGhlIGNvbm5lY3Rpb24gaXMgb3BlbiwgZmlyc3QgY2xvc2UgaXQuIHdhaXQgc29tZSB0aW1lIGFuZCB0cnkgYWdhaW4uXG4gICAgICAgIHRoaXMuaXNSZWNvbm5lY3RpbmcgPSB0cnVlO1xuICAgICAgICBpZiAodGhpcy53ZWJTb2NrZXRDb250cm9sbGVyLndlYlNvY2tldCAmJiB0aGlzLndlYlNvY2tldENvbnRyb2xsZXIud2ViU29ja2V0LnJlYWR5U3RhdGUgIT0gV2ViU29ja2V0LkNMT1NFRCkge1xuICAgICAgICAgICAgdGhpcy5jbG9zZVNpZ25hbGluZ1NlcnZlcihgJHttZXNzYWdlfSBSZXN0YXJ0aW5nIHN0cmVhbS4uLmApO1xuICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy50cnlSZWNvbm5lY3QobWVzc2FnZSk7XG4gICAgICAgICAgICB9LCAzMDAwKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMucGl4ZWxTdHJlYW1pbmcuX29uV2ViUnRjQXV0b0Nvbm5lY3QoKTtcbiAgICAgICAgICAgIHRoaXMuY29ubmVjdFRvU2lnbmFsbGluZ1NlcnZlcigpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTG9hZHMgYSBmcmVlemUgZnJhbWUgaWYgaXQgaXMgcmVxdWlyZWQgb3RoZXJ3aXNlIHNob3dzIHRoZSBwbGF5IG92ZXJsYXlcbiAgICAgKi9cbiAgICBsb2FkRnJlZXplRnJhbWVPclNob3dQbGF5T3ZlcmxheSgpIHtcbiAgICAgICAgdGhpcy5waXhlbFN0cmVhbWluZy5kaXNwYXRjaEV2ZW50KFxuICAgICAgICAgICAgbmV3IExvYWRGcmVlemVGcmFtZUV2ZW50KHtcbiAgICAgICAgICAgICAgICBzaG91bGRTaG93UGxheU92ZXJsYXk6IHRoaXMuc2hvdWxkU2hvd1BsYXlPdmVybGF5LFxuICAgICAgICAgICAgICAgIGlzVmFsaWQ6IHRoaXMuZnJlZXplRnJhbWVDb250cm9sbGVyLnZhbGlkLFxuICAgICAgICAgICAgICAgIGpwZWdEYXRhOiB0aGlzLmZyZWV6ZUZyYW1lQ29udHJvbGxlci5qcGVnXG4gICAgICAgICAgICB9KVxuICAgICAgICApO1xuICAgICAgICBpZiAodGhpcy5zaG91bGRTaG93UGxheU92ZXJsYXkgPT09IHRydWUpIHtcbiAgICAgICAgICAgIExvZ2dlci5Mb2coTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSwgJ3Nob3dpbmcgcGxheSBvdmVybGF5Jyk7XG4gICAgICAgICAgICB0aGlzLnJlc2l6ZVBsYXllclN0eWxlKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBMb2dnZXIuTG9nKExvZ2dlci5HZXRTdGFja1RyYWNlKCksICdzaG93aW5nIGZyZWV6ZSBmcmFtZScpO1xuICAgICAgICAgICAgdGhpcy5mcmVlemVGcmFtZUNvbnRyb2xsZXIuc2hvd0ZyZWV6ZUZyYW1lKCk7XG4gICAgICAgIH1cbiAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnZpZGVvUGxheWVyLnNldFZpZGVvRW5hYmxlZChmYWxzZSk7XG4gICAgICAgIH0sIHRoaXMuZnJlZXplRnJhbWVDb250cm9sbGVyLmZyZWV6ZUZyYW1lRGVsYXkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFByb2Nlc3MgdGhlIGZyZWV6ZSBmcmFtZSBhbmQgbG9hZCBpdFxuICAgICAqIEBwYXJhbSBtZXNzYWdlIFRoZSBmcmVlemUgZnJhbWUgZGF0YSBpbiBieXRlc1xuICAgICAqL1xuICAgIG9uRnJlZXplRnJhbWVNZXNzYWdlKG1lc3NhZ2U6IEFycmF5QnVmZmVyKSB7XG4gICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgJ0RhdGFDaGFubmVsUmVjZWl2ZU1lc3NhZ2VUeXBlLkZyZWV6ZUZyYW1lJyxcbiAgICAgICAgICAgIDZcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgdmlldyA9IG5ldyBVaW50OEFycmF5KG1lc3NhZ2UpO1xuICAgICAgICB0aGlzLmZyZWV6ZUZyYW1lQ29udHJvbGxlci5wcm9jZXNzRnJlZXplRnJhbWVNZXNzYWdlKHZpZXcsICgpID0+XG4gICAgICAgICAgICB0aGlzLmxvYWRGcmVlemVGcmFtZU9yU2hvd1BsYXlPdmVybGF5KClcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBFbmFibGUgdGhlIHZpZGVvIGFmdGVyIGhpZGluZyBhIGZyZWV6ZSBmcmFtZVxuICAgICAqL1xuICAgIGludmFsaWRhdGVGcmVlemVGcmFtZUFuZEVuYWJsZVZpZGVvKCkge1xuICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICdEYXRhQ2hhbm5lbFJlY2VpdmVNZXNzYWdlVHlwZS5GcmVlemVGcmFtZScsXG4gICAgICAgICAgICA2XG4gICAgICAgICk7XG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5waXhlbFN0cmVhbWluZy5kaXNwYXRjaEV2ZW50KFxuICAgICAgICAgICAgICAgIG5ldyBIaWRlRnJlZXplRnJhbWVFdmVudCgpXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgdGhpcy5mcmVlemVGcmFtZUNvbnRyb2xsZXIuaGlkZUZyZWV6ZUZyYW1lKCk7XG4gICAgICAgIH0sIHRoaXMuZnJlZXplRnJhbWVDb250cm9sbGVyLmZyZWV6ZUZyYW1lRGVsYXkpO1xuICAgICAgICBpZiAodGhpcy52aWRlb1BsYXllci5nZXRWaWRlb0VsZW1lbnQoKSkge1xuICAgICAgICAgICAgdGhpcy52aWRlb1BsYXllci5zZXRWaWRlb0VuYWJsZWQodHJ1ZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQcmVwIGRhdGFjaGFubmVsIGRhdGEgZm9yIHByb2Nlc3NpbmcgZmlsZSBleHRlbnNpb25cbiAgICAgKiBAcGFyYW0gZGF0YSB0aGUgZmlsZSBleHRlbnNpb24gZGF0YVxuICAgICAqL1xuICAgIG9uRmlsZUV4dGVuc2lvbihkYXRhOiBBcnJheUJ1ZmZlcikge1xuICAgICAgICBjb25zdCB2aWV3ID0gbmV3IFVpbnQ4QXJyYXkoZGF0YSk7XG4gICAgICAgIEZpbGVVdGlsLnNldEV4dGVuc2lvbkZyb21CeXRlcyh2aWV3LCB0aGlzLmZpbGUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFByZXAgZGF0YWNoYW5uZWwgZGF0YSBmb3IgcHJvY2Vzc2luZyB0aGUgZmlsZSBtaW1lIHR5cGVcbiAgICAgKiBAcGFyYW0gZGF0YSB0aGUgZmlsZSBtaW1lIHR5cGUgZGF0YVxuICAgICAqL1xuICAgIG9uRmlsZU1pbWVUeXBlKGRhdGE6IEFycmF5QnVmZmVyKSB7XG4gICAgICAgIGNvbnN0IHZpZXcgPSBuZXcgVWludDhBcnJheShkYXRhKTtcbiAgICAgICAgRmlsZVV0aWwuc2V0TWltZVR5cGVGcm9tQnl0ZXModmlldywgdGhpcy5maWxlKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBQcmVwIGRhdGFjaGFubmVsIGRhdGEgZm9yIHByb2Nlc3NpbmcgdGhlIGZpbGUgY29udGVudHNcbiAgICAgKiBAcGFyYW0gZGF0YSB0aGUgZmlsZSBjb250ZW50cyBkYXRhXG4gICAgICovXG4gICAgb25GaWxlQ29udGVudHMoZGF0YTogQXJyYXlCdWZmZXIpIHtcbiAgICAgICAgY29uc3QgdmlldyA9IG5ldyBVaW50OEFycmF5KGRhdGEpO1xuICAgICAgICBGaWxlVXRpbC5zZXRDb250ZW50c0Zyb21CeXRlcyh2aWV3LCB0aGlzLmZpbGUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFBsYXlzIHRoZSBzdHJlYW0gYXVkaW8gYW5kIHZpZGVvIHNvdXJjZSBhbmQgc2V0cyB1cCBvdGhlciBwaWVjZXMgd2hpbGUgdGhlIHN0cmVhbSBzdGFydHNcbiAgICAgKi9cbiAgICBwbGF5U3RyZWFtKCkge1xuICAgICAgICBpZiAoIXRoaXMudmlkZW9QbGF5ZXIuZ2V0VmlkZW9FbGVtZW50KCkpIHtcbiAgICAgICAgICAgIGNvbnN0IG1lc3NhZ2UgPVxuICAgICAgICAgICAgICAgICdDb3VsZCBub3QgcGxheSB2aWRlbyBzdHJlYW0gYmVjYXVzZSB0aGUgdmlkZW8gcGxheWVyIHdhcyBub3QgaW5pdGlhbGl6ZWQgY29ycmVjdGx5Lic7XG4gICAgICAgICAgICB0aGlzLnBpeGVsU3RyZWFtaW5nLmRpc3BhdGNoRXZlbnQoXG4gICAgICAgICAgICAgICAgbmV3IFBsYXlTdHJlYW1FcnJvckV2ZW50KHsgbWVzc2FnZSB9KVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIExvZ2dlci5FcnJvcihMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCBtZXNzYWdlKTtcblxuICAgICAgICAgICAgLy8gY2xvc2UgdGhlIGNvbm5lY3Rpb25cbiAgICAgICAgICAgIHRoaXMuY2xvc2VTaWduYWxpbmdTZXJ2ZXIoJ1N0cmVhbSBub3QgaW5pdGlhbGl6ZWQgY29ycmVjdGx5Jyk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIXRoaXMudmlkZW9QbGF5ZXIuaGFzVmlkZW9Tb3VyY2UoKSkge1xuICAgICAgICAgICAgTG9nZ2VyLldhcm5pbmcoXG4gICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICAnQ2Fubm90IHBsYXkgc3RyZWFtLCB0aGUgdmlkZW8gZWxlbWVudCBoYXMgbm8gc3JjT2JqZWN0IHRvIHBsYXkuJ1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0VG91Y2hJbnB1dEVuYWJsZWQodGhpcy5jb25maWcuaXNGbGFnRW5hYmxlZChGbGFncy5Ub3VjaElucHV0KSk7XG4gICAgICAgIHRoaXMucGl4ZWxTdHJlYW1pbmcuZGlzcGF0Y2hFdmVudChuZXcgUGxheVN0cmVhbUV2ZW50KCkpO1xuXG4gICAgICAgIGlmICh0aGlzLnN0cmVhbUNvbnRyb2xsZXIuYXVkaW9FbGVtZW50LnNyY09iamVjdCkge1xuICAgICAgICAgICAgY29uc3Qgc3RhcnRNdXRlZCA9IHRoaXMuY29uZmlnLmlzRmxhZ0VuYWJsZWQoRmxhZ3MuU3RhcnRWaWRlb011dGVkKVxuICAgICAgICAgICAgdGhpcy5zdHJlYW1Db250cm9sbGVyLmF1ZGlvRWxlbWVudC5tdXRlZCA9IHN0YXJ0TXV0ZWQ7XG5cbiAgICAgICAgICAgIGlmIChzdGFydE11dGVkKSB7XG4gICAgICAgICAgICAgIHRoaXMucGxheVZpZGVvKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuc3RyZWFtQ29udHJvbGxlci5hdWRpb0VsZW1lbnRcbiAgICAgICAgICAgICAgICAgICAgLnBsYXkoKVxuICAgICAgICAgICAgICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBsYXlWaWRlbygpO1xuICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICAuY2F0Y2goKG9uUmVqZWN0ZWRSZWFzb24pID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIExvZ2dlci5Mb2coTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSwgb25SZWplY3RlZFJlYXNvbik7XG4gICAgICAgICAgICAgICAgICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0Jyb3dzZXIgZG9lcyBub3Qgc3VwcG9ydCBhdXRvcGxheWluZyB2aWRlbyB3aXRob3V0IGludGVyYWN0aW9uIC0gdG8gcmVzb2x2ZSB0aGlzIHdlIGFyZSBnb2luZyB0byBzaG93IHRoZSBwbGF5IGJ1dHRvbiBvdmVybGF5LidcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBpeGVsU3RyZWFtaW5nLmRpc3BhdGNoRXZlbnQoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3IFBsYXlTdHJlYW1SZWplY3RlZEV2ZW50KHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVhc29uOiBvblJlamVjdGVkUmVhc29uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5wbGF5VmlkZW8oKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2hvdWxkU2hvd1BsYXlPdmVybGF5ID0gZmFsc2U7XG4gICAgICAgIHRoaXMuZnJlZXplRnJhbWVDb250cm9sbGVyLnNob3dGcmVlemVGcmFtZSgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFBsYXlzIHRoZSB2aWRlbyBzdHJlYW1cbiAgICAgKi9cbiAgICBwcml2YXRlIHBsYXlWaWRlbygpIHtcbiAgICAgICAgLy8gaGFuZGxlIHBsYXkoKSB3aXRoIHByb21pc2UgYXMgaXQgaXMgYW4gYXN5bmNocm9ub3VzIGNhbGxcbiAgICAgICAgdGhpcy52aWRlb1BsYXllci5wbGF5KCkuY2F0Y2goKG9uUmVqZWN0ZWRSZWFzb246IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgaWYgKHRoaXMuc3RyZWFtQ29udHJvbGxlci5hdWRpb0VsZW1lbnQuc3JjT2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zdHJlYW1Db250cm9sbGVyLmF1ZGlvRWxlbWVudC5wYXVzZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCBvblJlamVjdGVkUmVhc29uKTtcbiAgICAgICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICAnQnJvd3NlciBkb2VzIG5vdCBzdXBwb3J0IGF1dG9wbGF5aW5nIHZpZGVvIHdpdGhvdXQgaW50ZXJhY3Rpb24gLSB0byByZXNvbHZlIHRoaXMgd2UgYXJlIGdvaW5nIHRvIHNob3cgdGhlIHBsYXkgYnV0dG9uIG92ZXJsYXkuJ1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHRoaXMucGl4ZWxTdHJlYW1pbmcuZGlzcGF0Y2hFdmVudChcbiAgICAgICAgICAgICAgICBuZXcgUGxheVN0cmVhbVJlamVjdGVkRXZlbnQoeyByZWFzb246IG9uUmVqZWN0ZWRSZWFzb24gfSlcbiAgICAgICAgICAgICk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEVuYWJsZSB0aGUgdmlkZW8gdG8gcGxheSBhdXRvbWF0aWNhbGx5IGlmIGVuYWJsZUF1dG9wbGF5IGlzIHRydWVcbiAgICAgKi9cbiAgICBhdXRvUGxheVZpZGVvT3JTZXRVcFBsYXlPdmVybGF5KCkge1xuICAgICAgICBpZiAodGhpcy5jb25maWcuaXNGbGFnRW5hYmxlZChGbGFncy5BdXRvUGxheVZpZGVvKSkge1xuICAgICAgICAgICAgLy8gYXR0ZW1wdCB0byBwbGF5IHRoZSB2aWRlb1xuICAgICAgICAgICAgdGhpcy5wbGF5U3RyZWFtKCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5yZXNpemVQbGF5ZXJTdHlsZSgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENvbm5lY3QgdG8gdGhlIFNpZ25hbGluZyBzZXJ2ZXJcbiAgICAgKi9cbiAgICBjb25uZWN0VG9TaWduYWxsaW5nU2VydmVyKCkge1xuICAgICAgICB0aGlzLmxvY2FsbHlDbG9zZWQgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5zaG91bGRSZWNvbm5lY3QgPSB0cnVlO1xuICAgICAgICB0aGlzLmRpc2Nvbm5lY3RNZXNzYWdlID0gbnVsbDtcbiAgICAgICAgY29uc3Qgc2lnbmFsbGluZ1VybCA9IHRoaXMuc2lnbmFsbGluZ1VybEJ1aWxkZXIoKTtcbiAgICAgICAgdGhpcy53ZWJTb2NrZXRDb250cm9sbGVyLmNvbm5lY3Qoc2lnbmFsbGluZ1VybCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhpcyB3aWxsIHN0YXJ0IHRoZSBoYW5kc2hha2UgdG8gdGhlIHNpZ25hbGxpbmcgc2VydmVyXG4gICAgICogQHBhcmFtIHBlZXJDb25maWcgIC0gUlRDIENvbmZpZ3VyYXRpb24gT3B0aW9ucyBmcm9tIHRoZSBTaWduYWxpbmcgc2VydmVyXG4gICAgICogQHJlbWFyayBSVEMgUGVlciBDb25uZWN0aW9uIG9uIEljZSBDYW5kaWRhdGUgZXZlbnQgaGF2ZSBpdCBoYW5kbGVkIGJ5IGhhbmRsZSBTZW5kIEljZSBDYW5kaWRhdGVcbiAgICAgKi9cbiAgICBzdGFydFNlc3Npb24ocGVlckNvbmZpZzogUlRDQ29uZmlndXJhdGlvbikge1xuICAgICAgICB0aGlzLnBlZXJDb25maWcgPSBwZWVyQ29uZmlnO1xuICAgICAgICAvLyBjaGVjayBmb3IgZm9yY2luZyB0dXJuXG4gICAgICAgIGlmICh0aGlzLmNvbmZpZy5pc0ZsYWdFbmFibGVkKEZsYWdzLkZvcmNlVFVSTikpIHtcbiAgICAgICAgICAgIC8vIGNoZWNrIGZvciBhIHR1cm4gc2VydmVyXG4gICAgICAgICAgICBjb25zdCBoYXNUdXJuU2VydmVyID0gdGhpcy5jaGVja1R1cm5TZXJ2ZXJBdmFpbGFiaWxpdHkocGVlckNvbmZpZyk7XG5cbiAgICAgICAgICAgIC8vIGNsb3NlIGFuZCBlcnJvciBpZiB0dXJuIGlzIGZvcmNlZCBhbmQgdGhlcmUgaXMgbm8gdHVybiBzZXJ2ZXJcbiAgICAgICAgICAgIGlmICghaGFzVHVyblNlcnZlcikge1xuICAgICAgICAgICAgICAgIExvZ2dlci5JbmZvKFxuICAgICAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgICAgICAnTm8gdHVybiBzZXJ2ZXIgd2FzIGZvdW5kIGluIHRoZSBQZWVyIENvbm5lY3Rpb24gT3B0aW9ucy4gVFVSTiBjYW5ub3QgYmUgZm9yY2VkLCBjbG9zaW5nIGNvbm5lY3Rpb24uIFBsZWFzZSB1c2UgU1RVTiBpbnN0ZWFkJ1xuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgdGhpcy5jbG9zZVNpZ25hbGluZ1NlcnZlcignVFVSTiBjYW5ub3QgYmUgZm9yY2VkLCBjbG9zaW5nIGNvbm5lY3Rpb24uIFBsZWFzZSB1c2UgU1RVTiBpbnN0ZWFkLicpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHNldCB1cCB0aGUgcGVlciBjb25uZWN0aW9uIGNvbnRyb2xsZXJcbiAgICAgICAgdGhpcy5wZWVyQ29ubmVjdGlvbkNvbnRyb2xsZXIgPSBuZXcgUGVlckNvbm5lY3Rpb25Db250cm9sbGVyKFxuICAgICAgICAgICAgdGhpcy5wZWVyQ29uZmlnLFxuICAgICAgICAgICAgdGhpcy5jb25maWcsXG4gICAgICAgICAgICB0aGlzLnByZWZlcnJlZENvZGVjXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gc2V0IHVwIHBlZXIgY29ubmVjdGlvbiBjb250cm9sbGVyIHZpZGVvIHN0YXRzXG4gICAgICAgIHRoaXMucGVlckNvbm5lY3Rpb25Db250cm9sbGVyLm9uVmlkZW9TdGF0cyA9IChldmVudDogQWdncmVnYXRlZFN0YXRzKSA9PlxuICAgICAgICAgICAgdGhpcy5oYW5kbGVWaWRlb1N0YXRzKGV2ZW50KTtcblxuICAgICAgICAvKiBXaGVuIHRoZSBQZWVyIENvbm5lY3Rpb24gd2FudHMgdG8gc2VuZCBhbiBvZmZlciBoYXZlIGl0IGhhbmRsZWQgKi9cbiAgICAgICAgdGhpcy5wZWVyQ29ubmVjdGlvbkNvbnRyb2xsZXIub25TZW5kV2ViUlRDT2ZmZXIgPSAoXG4gICAgICAgICAgICBvZmZlcjogUlRDU2Vzc2lvbkRlc2NyaXB0aW9uSW5pdFxuICAgICAgICApID0+IHRoaXMuaGFuZGxlU2VuZFdlYlJUQ09mZmVyKG9mZmVyKTtcblxuICAgICAgICAvKiBXaGVuIHRoZSBQZWVyIENvbm5lY3Rpb24gd2FudHMgdG8gc2VuZCBhbiBhbnN3ZXIgaGF2ZSBpdCBoYW5kbGVkICovXG4gICAgICAgIHRoaXMucGVlckNvbm5lY3Rpb25Db250cm9sbGVyLm9uU2VuZFdlYlJUQ0Fuc3dlciA9IChcbiAgICAgICAgICAgIG9mZmVyOiBSVENTZXNzaW9uRGVzY3JpcHRpb25Jbml0XG4gICAgICAgICkgPT4gdGhpcy5oYW5kbGVTZW5kV2ViUlRDQW5zd2VyKG9mZmVyKTtcblxuICAgICAgICAvKiBXaGVuIHRoZSBQZWVyIENvbm5lY3Rpb24gaWNlIGNhbmRpZGF0ZSBpcyBhZGRlZCBoYXZlIGl0IGhhbmRsZWQgKi9cbiAgICAgICAgdGhpcy5wZWVyQ29ubmVjdGlvbkNvbnRyb2xsZXIub25QZWVySWNlQ2FuZGlkYXRlID0gKFxuICAgICAgICAgICAgcGVlckNvbm5lY3Rpb25JY2VFdmVudDogUlRDUGVlckNvbm5lY3Rpb25JY2VFdmVudFxuICAgICAgICApID0+IHRoaXMuaGFuZGxlU2VuZEljZUNhbmRpZGF0ZShwZWVyQ29ubmVjdGlvbkljZUV2ZW50KTtcblxuICAgICAgICAvKiBXaGVuIHRoZSBQZWVyIENvbm5lY3Rpb24gaGFzIGEgZGF0YSBjaGFubmVsIGNyZWF0ZWQgZm9yIGl0IGJ5IHRoZSBicm93c2VyLCBoYW5kbGUgaXQgKi9cbiAgICAgICAgdGhpcy5wZWVyQ29ubmVjdGlvbkNvbnRyb2xsZXIub25EYXRhQ2hhbm5lbCA9IChcbiAgICAgICAgICAgIGRhdGFjaGFubmVsRXZlbnQ6IFJUQ0RhdGFDaGFubmVsRXZlbnRcbiAgICAgICAgKSA9PiB0aGlzLmhhbmRsZURhdGFDaGFubmVsKGRhdGFjaGFubmVsRXZlbnQpO1xuXG4gICAgICAgIC8vIHNldCB1cCB3ZWJSdGMgdGV4dCBvdmVybGF5c1xuICAgICAgICB0aGlzLnBlZXJDb25uZWN0aW9uQ29udHJvbGxlci5zaG93VGV4dE92ZXJsYXlDb25uZWN0aW5nID0gKCkgPT5cbiAgICAgICAgICAgIHRoaXMucGl4ZWxTdHJlYW1pbmcuX29uV2ViUnRjQ29ubmVjdGluZygpO1xuICAgICAgICB0aGlzLnBlZXJDb25uZWN0aW9uQ29udHJvbGxlci5zaG93VGV4dE92ZXJsYXlTZXR1cEZhaWx1cmUgPSAoKSA9PlxuICAgICAgICAgICAgdGhpcy5waXhlbFN0cmVhbWluZy5fb25XZWJSdGNGYWlsZWQoKTtcbiAgICAgICAgbGV0IHdlYlJ0Y0Nvbm5lY3RlZFNlbnQgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5wZWVyQ29ubmVjdGlvbkNvbnRyb2xsZXIub25JY2VDb25uZWN0aW9uU3RhdGVDaGFuZ2UgPSAoKSA9PiB7XG4gICAgICAgICAgICAvLyBCcm93c2VycyBlbWl0IFwiY29ubmVjdGVkXCIgd2hlbiBnZXR0aW5nIGZpcnN0IGNvbm5lY3Rpb24gYW5kIFwiY29tcGxldGVkXCIgd2hlbiBmaW5pc2hpbmdcbiAgICAgICAgICAgIC8vIGNhbmRpZGF0ZSBjaGVja2luZy4gSG93ZXZlciwgc29tZXRpbWVzIGJyb3dzZXJzIGNhbiBza2lwIFwiY29ubmVjdGVkXCIgYW5kIG9ubHkgZW1pdCBcImNvbXBsZXRlZFwiLlxuICAgICAgICAgICAgLy8gVGhlcmVmb3JlIG5lZWQgdG8gY2hlY2sgYm90aCBjYXNlcyBhbmQgZW1pdCBvbldlYlJ0Y0Nvbm5lY3RlZCBvbmx5IG9uY2Ugb24gdGhlIGZpcnN0IGhpdC5cbiAgICAgICAgICAgIGlmICghd2ViUnRjQ29ubmVjdGVkU2VudCAmJiBcbiAgICAgICAgICAgICAgICBbXCJjb25uZWN0ZWRcIiwgXCJjb21wbGV0ZWRcIl0uaW5jbHVkZXModGhpcy5wZWVyQ29ubmVjdGlvbkNvbnRyb2xsZXIucGVlckNvbm5lY3Rpb24uaWNlQ29ubmVjdGlvblN0YXRlKSkge1xuICAgICAgICAgICAgICAgIHRoaXMucGl4ZWxTdHJlYW1pbmcuX29uV2ViUnRjQ29ubmVjdGVkKCk7XG4gICAgICAgICAgICAgICAgd2ViUnRjQ29ubmVjdGVkU2VudCA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgLyogUlRDIFBlZXIgQ29ubmVjdGlvbiBvbiBUcmFjayBldmVudCAtPiBoYW5kbGUgb24gdHJhY2sgKi9cbiAgICAgICAgdGhpcy5wZWVyQ29ubmVjdGlvbkNvbnRyb2xsZXIub25UcmFjayA9ICh0cmFja0V2ZW50OiBSVENUcmFja0V2ZW50KSA9PlxuICAgICAgICAgICAgdGhpcy5zdHJlYW1Db250cm9sbGVyLmhhbmRsZU9uVHJhY2sodHJhY2tFdmVudCk7XG5cbiAgICAgICAgLyogU3RhcnQgdGhlIEhhbmQgc2hha2UgcHJvY2VzcyBieSBjcmVhdGluZyBhbiBPZmZlciAqL1xuICAgICAgICBjb25zdCBCcm93c2VyU2VuZHNPZmZlciA9IHRoaXMuY29uZmlnLmlzRmxhZ0VuYWJsZWQoXG4gICAgICAgICAgICBGbGFncy5Ccm93c2VyU2VuZE9mZmVyXG4gICAgICAgICk7XG4gICAgICAgIGlmIChCcm93c2VyU2VuZHNPZmZlcikge1xuICAgICAgICAgICAgLy8gSWYgYnJvd3NlciBpcyBzZW5kaW5nIHRoZSBvZmZlciwgY3JlYXRlIGFuIG9mZmVyIGFuZCBzZW5kIGl0IHRvIHRoZSBzdHJlYW1lclxuICAgICAgICAgICAgdGhpcy5zZW5kcmVjdkRhdGFDaGFubmVsQ29udHJvbGxlci5jcmVhdGVEYXRhQ2hhbm5lbChcbiAgICAgICAgICAgICAgICB0aGlzLnBlZXJDb25uZWN0aW9uQ29udHJvbGxlci5wZWVyQ29ubmVjdGlvbixcbiAgICAgICAgICAgICAgICAnY2lycnVzJyxcbiAgICAgICAgICAgICAgICB0aGlzLmRhdGFjaGFubmVsT3B0aW9uc1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHRoaXMuc2VuZHJlY3ZEYXRhQ2hhbm5lbENvbnRyb2xsZXIuaGFuZGxlT25NZXNzYWdlID0gKFxuICAgICAgICAgICAgICAgIGV2OiBNZXNzYWdlRXZlbnQ8QXJyYXlCdWZmZXI+XG4gICAgICAgICAgICApID0+IHRoaXMuaGFuZGxlT25NZXNzYWdlKGV2KTtcbiAgICAgICAgICAgIHRoaXMucGVlckNvbm5lY3Rpb25Db250cm9sbGVyLmNyZWF0ZU9mZmVyKFxuICAgICAgICAgICAgICAgIHRoaXMuc2RwQ29uc3RyYWludHMsXG4gICAgICAgICAgICAgICAgdGhpcy5jb25maWdcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVja3MgdGhlIHBlZXIgY29ubmVjdGlvbiBvcHRpb25zIGZvciBhIHR1cm4gc2VydmVyIGFuZCByZXR1cm5zIHRydWUgb3IgZmFsc2VcbiAgICAgKi9cbiAgICBjaGVja1R1cm5TZXJ2ZXJBdmFpbGFiaWxpdHkob3B0aW9uczogUlRDQ29uZmlndXJhdGlvbikge1xuICAgICAgICAvLyBpZiBpY2VTZXJ2ZXJzIGlzIGVtcHR5IHJldHVybiBmYWxzZSB0aGlzIHNob3VsZCBub3QgYmUgdGhlIGdlbmVyYWwgdXNlIGNhc2UgYnV0IGlzIGhlcmUgaW5jYXNlXG4gICAgICAgIGlmICghb3B0aW9ucy5pY2VTZXJ2ZXJzKSB7XG4gICAgICAgICAgICBMb2dnZXIuSW5mbyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCAnQSB0dXJuIHNldmVyIHdhcyBub3QgZm91bmQnKTtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGxvb3AgdGhyb3VnaCB0aGUgaWNlIHNlcnZlcnMgdG8gY2hlY2sgZm9yIGEgdHVybiB1cmxcbiAgICAgICAgZm9yIChjb25zdCBpY2VTZXJ2ZXIgb2Ygb3B0aW9ucy5pY2VTZXJ2ZXJzKSB7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IHVybCBvZiBpY2VTZXJ2ZXIudXJscykge1xuICAgICAgICAgICAgICAgIGlmICh1cmwuaW5jbHVkZXMoJ3R1cm4nKSkge1xuICAgICAgICAgICAgICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGBBIHR1cm4gc2V2ZXIgd2FzIGZvdW5kIGF0ICR7dXJsfWBcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgTG9nZ2VyLkluZm8oTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSwgJ0EgdHVybiBzZXZlciB3YXMgbm90IGZvdW5kJyk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGVzIHdoZW4gYSBDb25maWcgTWVzc2FnZSBpcyByZWNlaXZlZCBjb250YWlucyB0aGUgUGVlciBDb25uZWN0aW9uIE9wdGlvbnMgcmVxdWlyZWQgKFNUVU4gYW5kIFRVUk4gU2VydmVyIEluZm8pXG4gICAgICogQHBhcmFtIG1lc3NhZ2VDb25maWcgLSBDb25maWcgTWVzc2FnZSByZWNlaXZlZCBmcm9tIHRoZSBzaWduYWxpbmcgc2VydmVyXG4gICAgICovXG4gICAgaGFuZGxlT25Db25maWdNZXNzYWdlKG1lc3NhZ2VDb25maWc6IE1lc3NhZ2VDb25maWcpIHtcbiAgICAgICAgdGhpcy5yZXNpemVQbGF5ZXJTdHlsZSgpO1xuXG4gICAgICAgIC8vIFRlbGwgdGhlIFdlYlJ0Y0NvbnRyb2xsZXIgdG8gc3RhcnQgYSBzZXNzaW9uIHdpdGggdGhlIHBlZXIgb3B0aW9ucyBzZW50IGZyb20gdGhlIHNpZ25hbGluZyBzZXJ2ZXJcbiAgICAgICAgdGhpcy5zdGFydFNlc3Npb24obWVzc2FnZUNvbmZpZy5wZWVyQ29ubmVjdGlvbk9wdGlvbnMpO1xuXG4gICAgICAgIC8vIFdoZW4gdGhlIHNpZ25hbGluZyBzZXJ2ZXIgc2VuZHMgYSBXZWJSVEMgQW5zd2VyIG92ZXIgdGhlIHdlYnNvY2tldCBjb25uZWN0aW9uIGhhdmUgdGhlIFdlYlJ0Y0NvbnRyb2xsZXIgaGFuZGxlIHRoZSBtZXNzYWdlXG4gICAgICAgIHRoaXMud2ViU29ja2V0Q29udHJvbGxlci5vbldlYlJ0Y0Fuc3dlciA9IChcbiAgICAgICAgICAgIG1lc3NhZ2VBbnN3ZXI6IE1lc3NhZ2VSZWNlaXZlLk1lc3NhZ2VBbnN3ZXJcbiAgICAgICAgKSA9PiB0aGlzLmhhbmRsZVdlYlJ0Y0Fuc3dlcihtZXNzYWdlQW5zd2VyKTtcbiAgICAgICAgdGhpcy53ZWJTb2NrZXRDb250cm9sbGVyLm9uV2ViUnRjT2ZmZXIgPSAoXG4gICAgICAgICAgICBtZXNzYWdlT2ZmZXI6IE1lc3NhZ2VSZWNlaXZlLk1lc3NhZ2VPZmZlclxuICAgICAgICApID0+IHRoaXMuaGFuZGxlV2ViUnRjT2ZmZXIobWVzc2FnZU9mZmVyKTtcbiAgICAgICAgdGhpcy53ZWJTb2NrZXRDb250cm9sbGVyLm9uV2ViUnRjUGVlckRhdGFDaGFubmVscyA9IChcbiAgICAgICAgICAgIG1lc3NhZ2VEYXRhQ2hhbm5lbHM6IE1lc3NhZ2VSZWNlaXZlLk1lc3NhZ2VQZWVyRGF0YUNoYW5uZWxzXG4gICAgICAgICkgPT4gdGhpcy5oYW5kbGVXZWJSdGNTRlVQZWVyRGF0YWNoYW5uZWxzKG1lc3NhZ2VEYXRhQ2hhbm5lbHMpO1xuXG4gICAgICAgIC8vIFdoZW4gdGhlIHNpZ25hbGluZyBzZXJ2ZXIgc2VuZHMgYSBJY2VDYW5kaWRhdGUgb3ZlciB0aGUgd2Vic29ja2V0IGNvbm5lY3Rpb24gaGF2ZSB0aGUgV2ViUnRjQ29udHJvbGxlciBoYW5kbGUgdGhlIG1lc3NhZ2VcbiAgICAgICAgdGhpcy53ZWJTb2NrZXRDb250cm9sbGVyLm9uSWNlQ2FuZGlkYXRlID0gKFxuICAgICAgICAgICAgaWNlQ2FuZGlkYXRlOiBSVENJY2VDYW5kaWRhdGVJbml0XG4gICAgICAgICkgPT4gdGhpcy5oYW5kbGVJY2VDYW5kaWRhdGUoaWNlQ2FuZGlkYXRlKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGVzIHdoZW4gdGhlIHNpZ25hbGxpbmcgc2VydmVyIGdpdmVzIHVzIHRoZSBsaXN0IG9mIHN0cmVhbWVyIGlkcy5cbiAgICAgKi9cbiAgICBoYW5kbGVTdHJlYW1lckxpc3RNZXNzYWdlKG1lc3NhZ2VTdHJlYW1lckxpc3Q6IE1lc3NhZ2VTdHJlYW1lckxpc3QpIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICBgR290IHN0cmVhbWVyIGxpc3QgJHttZXNzYWdlU3RyZWFtZXJMaXN0Lmlkc31gLFxuICAgICAgICAgICAgNlxuICAgICAgICApO1xuXG4gICAgICAgIC8vIGFkZCB0aGUgc3RyZWFtZXJzIHRvIHRoZSBVSVxuICAgICAgICBjb25zdCBzZXR0aW5nT3B0aW9ucyA9IFsuLi5tZXNzYWdlU3RyZWFtZXJMaXN0Lmlkc107IC8vIGNvcHkgdGhlIG9yaWdpbmFsIG1lc3NhZ2VTdHJlYW1lckxpc3QuaWRzXG4gICAgICAgIHNldHRpbmdPcHRpb25zLnVuc2hpZnQoJycpOyAvLyBhZGQgYW4gZW1wdHkgb3B0aW9uIGF0IHRoZSB0b3BcbiAgICAgICAgdGhpcy5jb25maWcuc2V0T3B0aW9uU2V0dGluZ09wdGlvbnMoXG4gICAgICAgICAgICBPcHRpb25QYXJhbWV0ZXJzLlN0cmVhbWVySWQsXG4gICAgICAgICAgICBzZXR0aW5nT3B0aW9uc1xuICAgICAgICApO1xuXG4gICAgICAgIGxldCB3YW50ZWRTdHJlYW1lcklkOiBzdHJpbmcgPSBudWxsO1xuICAgICAgICBsZXQgYXV0b1NlbGVjdGVkU3RyZWFtZXJJZDogc3RyaW5nICA9IG51bGw7XG4gICAgICAgIGNvbnN0IHdhaXRGb3JTdHJlYW1lciA9IHRoaXMuY29uZmlnLmlzRmxhZ0VuYWJsZWQoRmxhZ3MuV2FpdEZvclN0cmVhbWVyKTtcbiAgICAgICAgY29uc3QgcmVjb25uZWN0TGltaXQgPSB0aGlzLmNvbmZpZy5nZXROdW1lcmljU2V0dGluZ1ZhbHVlKE51bWVyaWNQYXJhbWV0ZXJzLk1heFJlY29ubmVjdEF0dGVtcHRzKTtcbiAgICAgICAgY29uc3QgcmVjb25uZWN0RGVsYXkgPSB0aGlzLmNvbmZpZy5nZXROdW1lcmljU2V0dGluZ1ZhbHVlKE51bWVyaWNQYXJhbWV0ZXJzLlN0cmVhbWVyQXV0b0pvaW5JbnRlcnZhbCk7XG5cbiAgICAgICAgLy8gZmlyc3Qgd2UgZmlndXJlIG91dCBhIHdhbnRlZCBzdHJlYW1lciBpZCB0aHJvdWdoIHZhcmlvdXMgbWVhbnNcbiAgICAgICAgY29uc3QgdXJsUGFyYW1zID0gbmV3IFVSTFNlYXJjaFBhcmFtcyh3aW5kb3cubG9jYXRpb24uc2VhcmNoKTtcbiAgICAgICAgaWYgKHVybFBhcmFtcy5oYXMoT3B0aW9uUGFyYW1ldGVycy5TdHJlYW1lcklkKSkge1xuICAgICAgICAgICAgLy8gaWYgd2UndmUgc2V0IHRoZSBzdHJlYW1lciBpZCBvbiB0aGUgdXJsIHdlIG9ubHkgd2FudCB0aGF0IHN0cmVhbWVyIGlkXG4gICAgICAgICAgICB3YW50ZWRTdHJlYW1lcklkID0gdXJsUGFyYW1zLmdldChPcHRpb25QYXJhbWV0ZXJzLlN0cmVhbWVySWQpO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc3Vic2NyaWJlZFN0cmVhbSkge1xuICAgICAgICAgICAgLy8gd2Ugd2VyZSBwcmV2aW91c2x5IHN1YnNjcmliZWQgdG8gYSBzdHJlYW1lciwgd2Ugd2FudCB0aGF0XG4gICAgICAgICAgICB3YW50ZWRTdHJlYW1lcklkID0gdGhpcy5zdWJzY3JpYmVkU3RyZWFtO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gbm93IGxldHMgc2VlIGlmIHdlIGNhbiBwaWNrIGl0LlxuICAgICAgICBpZiAod2FudGVkU3RyZWFtZXJJZCAmJiBtZXNzYWdlU3RyZWFtZXJMaXN0Lmlkcy5pbmNsdWRlcyh3YW50ZWRTdHJlYW1lcklkKSkge1xuICAgICAgICAgICAgLy8gaWYgdGhlIHdhbnRlZCBzdHJlYW0gaXMgaW4gdGhlIGxpc3QuIHdlIHBpY2sgdGhhdFxuICAgICAgICAgICAgYXV0b1NlbGVjdGVkU3RyZWFtZXJJZCA9IHdhbnRlZFN0cmVhbWVySWQ7XG4gICAgICAgIH0gZWxzZSBpZiAoKCF3YW50ZWRTdHJlYW1lcklkIHx8ICF3YWl0Rm9yU3RyZWFtZXIpICYmIG1lc3NhZ2VTdHJlYW1lckxpc3QuaWRzLmxlbmd0aCA9PSAxKSB7XG4gICAgICAgICAgICAvLyBvdGhlcndpc2UsIGlmIHdlJ3JlIG5vdCB3YWl0aW5nIGZvciB0aGUgd2FudGVkIHN0cmVhbWVyIGFuZCB0aGVyZSdzIG9ubHkgb25lIHN0cmVhbWVyLCBjb25uZWN0IHRvIGl0XG4gICAgICAgICAgICBhdXRvU2VsZWN0ZWRTdHJlYW1lcklkID0gbWVzc2FnZVN0cmVhbWVyTGlzdC5pZHNbMF07XG4gICAgICAgIH1cblxuICAgICAgICAvLyBpZiB3ZSBmb3VuZCBhIHN0cmVhbWVyIGlkIHRvIGF1dG8gc2VsZWN0LCBzZWxlY3QgaXRcbiAgICAgICAgaWYgKGF1dG9TZWxlY3RlZFN0cmVhbWVySWQpIHtcbiAgICAgICAgICAgIHRoaXMuaXNSZWNvbm5lY3RpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMucmVjb25uZWN0QXR0ZW1wdCA9IDA7XG4gICAgICAgICAgICB0aGlzLmNvbmZpZy5zZXRPcHRpb25TZXR0aW5nVmFsdWUoXG4gICAgICAgICAgICAgICAgT3B0aW9uUGFyYW1ldGVycy5TdHJlYW1lcklkLFxuICAgICAgICAgICAgICAgIGF1dG9TZWxlY3RlZFN0cmVhbWVySWRcbiAgICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBubyBhdXRvIHNlbGVjdGVkIHN0cmVhbWVyLlxuICAgICAgICAgICAgLy8gaWYgd2UncmUgd2FpdGluZyBmb3IgYSBzdHJlYW1lciB0aGVuIHRyeSByZWNvbm5lY3RpbmdcbiAgICAgICAgICAgIGlmICh3YWl0Rm9yU3RyZWFtZXIpIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5yZWNvbm5lY3RBdHRlbXB0IDwgcmVjb25uZWN0TGltaXQpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gc3RpbGwgcmVjb25uZWN0cyBhdmFpbGFibGVcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5pc1JlY29ubmVjdGluZyA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVjb25uZWN0QXR0ZW1wdCsrO1xuICAgICAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMud2ViU29ja2V0Q29udHJvbGxlci5yZXF1ZXN0U3RyZWFtZXJMaXN0KCk7XG4gICAgICAgICAgICAgICAgICAgIH0sIHJlY29ubmVjdERlbGF5KTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAvLyBXZSd2ZSBleGhhdXN0ZWQgb3VyIHJlY29ubmVjdCBhdHRlbXB0cywgcmV0dXJuIHRvIG1haW4gc2NyZWVuXG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVjb25uZWN0QXR0ZW1wdCA9IDA7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaXNSZWNvbm5lY3RpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zaG91bGRSZWNvbm5lY3QgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkaXNwYXRjaCB0aGlzIGV2ZW50IGZpbmFsbHlcbiAgICAgICAgdGhpcy5waXhlbFN0cmVhbWluZy5kaXNwYXRjaEV2ZW50KFxuICAgICAgICAgICAgbmV3IFN0cmVhbWVyTGlzdE1lc3NhZ2VFdmVudCh7XG4gICAgICAgICAgICAgICAgbWVzc2FnZVN0cmVhbWVyTGlzdCxcbiAgICAgICAgICAgICAgICBhdXRvU2VsZWN0ZWRTdHJlYW1lcklkLFxuICAgICAgICAgICAgICAgIHdhbnRlZFN0cmVhbWVySWRcbiAgICAgICAgICAgIH0pXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSGFuZGxlIHRoZSBSVEMgQW5zd2VyIGZyb20gdGhlIHNpZ25hbGluZyBzZXJ2ZXJcbiAgICAgKiBAcGFyYW0gQW5zd2VyIC0gQW5zd2VyIFNEUCBmcm9tIHRoZSBwZWVyLlxuICAgICAqL1xuICAgIGhhbmRsZVdlYlJ0Y0Fuc3dlcihBbnN3ZXI6IE1lc3NhZ2VBbnN3ZXIpIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCBgR290IGFuc3dlciBzZHAgJHtBbnN3ZXIuc2RwfWAsIDYpO1xuXG4gICAgICAgIGNvbnN0IHNkcEFuc3dlcjogUlRDU2Vzc2lvbkRlc2NyaXB0aW9uSW5pdCA9IHtcbiAgICAgICAgICAgIHNkcDogQW5zd2VyLnNkcCxcbiAgICAgICAgICAgIHR5cGU6ICdhbnN3ZXInXG4gICAgICAgIH07XG5cbiAgICAgICAgdGhpcy5wZWVyQ29ubmVjdGlvbkNvbnRyb2xsZXIucmVjZWl2ZUFuc3dlcihzZHBBbnN3ZXIpO1xuICAgICAgICB0aGlzLmhhbmRsZVBvc3RXZWJydGNOZWdvdGlhdGlvbigpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEhhbmRsZSB0aGUgUlRDIG9mZmVyIGZyb20gYSBXZWJSVEMgcGVlciAocmVjZWl2ZWQgdGhyb3VnaCB0aGUgc2lnbmFsbGluZyBzZXJ2ZXIpLlxuICAgICAqIEBwYXJhbSBPZmZlciAtIE9mZmVyIFNEUCBmcm9tIHRoZSBwZWVyLlxuICAgICAqL1xuICAgIGhhbmRsZVdlYlJ0Y09mZmVyKE9mZmVyOiBNZXNzYWdlT2ZmZXIpIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCBgR290IG9mZmVyIHNkcCAke09mZmVyLnNkcH1gLCA2KTtcblxuICAgICAgICB0aGlzLmlzVXNpbmdTRlUgPSBPZmZlci5zZnUgPyBPZmZlci5zZnUgOiBmYWxzZTtcbiAgICAgICAgaWYgKHRoaXMuaXNVc2luZ1NGVSkge1xuICAgICAgICAgICAgLy8gRGlzYWJsZSBuZWdvdGlhdGluZyB3aXRoIHRoZSBzZnUgYXMgdGhlIHNmdSBvbmx5IHN1cHBvcnRzIG9uZSBjb2RlYyBhdCBhIHRpbWVcbiAgICAgICAgICAgIHRoaXMucGVlckNvbm5lY3Rpb25Db250cm9sbGVyLnByZWZlcnJlZENvZGVjID0gJyc7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzZHBPZmZlcjogUlRDU2Vzc2lvbkRlc2NyaXB0aW9uSW5pdCA9IHtcbiAgICAgICAgICAgIHNkcDogT2ZmZXIuc2RwLFxuICAgICAgICAgICAgdHlwZTogJ29mZmVyJ1xuICAgICAgICB9O1xuXG4gICAgICAgIHRoaXMucGVlckNvbm5lY3Rpb25Db250cm9sbGVyLnJlY2VpdmVPZmZlcihzZHBPZmZlciwgdGhpcy5jb25maWcpO1xuICAgICAgICB0aGlzLmhhbmRsZVBvc3RXZWJydGNOZWdvdGlhdGlvbigpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEhhbmRsZSB3aGVuIHRoZSBTRlUgcHJvdmlkZXMgdGhlIHBlZXIgd2l0aCBpdHMgZGF0YSBjaGFubmVsc1xuICAgICAqIEBwYXJhbSBEYXRhQ2hhbm5lbHMgLSBUaGUgbWVzc2FnZSBmcm9tIHRoZSBTRlUgY29udGFpbmluZyB0aGUgZGF0YSBjaGFubmVscyBpZHNcbiAgICAgKi9cbiAgICBoYW5kbGVXZWJSdGNTRlVQZWVyRGF0YWNoYW5uZWxzKFxuICAgICAgICBEYXRhQ2hhbm5lbHM6IE1lc3NhZ2VSZWNlaXZlLk1lc3NhZ2VQZWVyRGF0YUNoYW5uZWxzXG4gICAgKSB7XG4gICAgICAgIGNvbnN0IFNlbmRPcHRpb25zOiBSVENEYXRhQ2hhbm5lbEluaXQgPSB7XG4gICAgICAgICAgICBvcmRlcmVkOiB0cnVlLFxuICAgICAgICAgICAgbmVnb3RpYXRlZDogdHJ1ZSxcbiAgICAgICAgICAgIGlkOiBEYXRhQ2hhbm5lbHMuc2VuZFN0cmVhbUlkXG4gICAgICAgIH07XG5cbiAgICAgICAgY29uc3QgdW5pZGlyZWN0aW9uYWwgPVxuICAgICAgICAgICAgRGF0YUNoYW5uZWxzLnNlbmRTdHJlYW1JZCAhPSBEYXRhQ2hhbm5lbHMucmVjdlN0cmVhbUlkO1xuXG4gICAgICAgIHRoaXMuc2VuZHJlY3ZEYXRhQ2hhbm5lbENvbnRyb2xsZXIuY3JlYXRlRGF0YUNoYW5uZWwoXG4gICAgICAgICAgICB0aGlzLnBlZXJDb25uZWN0aW9uQ29udHJvbGxlci5wZWVyQ29ubmVjdGlvbixcbiAgICAgICAgICAgIHVuaWRpcmVjdGlvbmFsID8gJ3NlbmQtZGF0YWNoYW5uZWwnIDogJ2RhdGFjaGFubmVsJyxcbiAgICAgICAgICAgIFNlbmRPcHRpb25zXG4gICAgICAgICk7XG5cbiAgICAgICAgaWYgKHVuaWRpcmVjdGlvbmFsKSB7XG4gICAgICAgICAgICBjb25zdCBSZWN2T3B0aW9uczogUlRDRGF0YUNoYW5uZWxJbml0ID0ge1xuICAgICAgICAgICAgICAgIG9yZGVyZWQ6IHRydWUsXG4gICAgICAgICAgICAgICAgbmVnb3RpYXRlZDogdHJ1ZSxcbiAgICAgICAgICAgICAgICBpZDogRGF0YUNoYW5uZWxzLnJlY3ZTdHJlYW1JZFxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdGhpcy5yZWN2RGF0YUNoYW5uZWxDb250cm9sbGVyLmNyZWF0ZURhdGFDaGFubmVsKFxuICAgICAgICAgICAgICAgIHRoaXMucGVlckNvbm5lY3Rpb25Db250cm9sbGVyLnBlZXJDb25uZWN0aW9uLFxuICAgICAgICAgICAgICAgICdyZWN2LWRhdGFjaGFubmVsJyxcbiAgICAgICAgICAgICAgICBSZWN2T3B0aW9uc1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHRoaXMucmVjdkRhdGFDaGFubmVsQ29udHJvbGxlci5oYW5kbGVPbk9wZW4gPSAoKSA9PlxuICAgICAgICAgICAgICAgIHRoaXMud2ViU29ja2V0Q29udHJvbGxlci5zZW5kU0ZVUmVjdkRhdGFDaGFubmVsUmVhZHkoKTtcbiAgICAgICAgICAgIC8vIElmIHdlJ3JlIHVuaS1kaXJlY3Rpb25hbCwgb25seSB0aGUgcmVjdiBkYXRhIGNoYW5uZWwgc2hvdWxkIGhhbmRsZSBpbmNvbWluZyBtZXNzYWdlc1xuICAgICAgICAgICAgdGhpcy5yZWN2RGF0YUNoYW5uZWxDb250cm9sbGVyLmhhbmRsZU9uTWVzc2FnZSA9IChcbiAgICAgICAgICAgICAgICBldjogTWVzc2FnZUV2ZW50XG4gICAgICAgICAgICApID0+IHRoaXMuaGFuZGxlT25NZXNzYWdlKGV2KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIGVsc2Ugb3VyIHByaW1hcnkgZGF0YWNoYW5uZWwgaXMgc2VuZC9yZWN2IHNvIGl0IGNhbiBoYW5kbGUgaW5jb21pbmcgbWVzc2FnZXNcbiAgICAgICAgICAgIHRoaXMuc2VuZHJlY3ZEYXRhQ2hhbm5lbENvbnRyb2xsZXIuaGFuZGxlT25NZXNzYWdlID0gKFxuICAgICAgICAgICAgICAgIGV2OiBNZXNzYWdlRXZlbnRcbiAgICAgICAgICAgICkgPT4gdGhpcy5oYW5kbGVPbk1lc3NhZ2UoZXYpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaGFuZGxlUG9zdFdlYnJ0Y05lZ290aWF0aW9uKCkge1xuICAgICAgICAvLyBzdGFydCB0aGUgYWZrIHdhcm5pbmcgdGltZXIgYXMgUFMgaXMgbm93IHJ1bm5pbmdcbiAgICAgICAgdGhpcy5hZmtDb250cm9sbGVyLnN0YXJ0QWZrV2FybmluZ1RpbWVyKCk7XG4gICAgICAgIC8vIHNob3cgdGhlIG92ZXJsYXkgdGhhdCB3ZSBoYXZlIG5lZ290aWF0ZWQgYSBjb25uZWN0aW9uXG4gICAgICAgIHRoaXMucGl4ZWxTdHJlYW1pbmcuX29uV2ViUnRjU2RwKCk7XG5cbiAgICAgICAgaWYgKHRoaXMuc3RhdHNUaW1lckhhbmRsZSAmJiB0aGlzLnN0YXRzVGltZXJIYW5kbGUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgd2luZG93LmNsZWFySW50ZXJ2YWwodGhpcy5zdGF0c1RpbWVySGFuZGxlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc3RhdHNUaW1lckhhbmRsZSA9IHdpbmRvdy5zZXRJbnRlcnZhbCgoKSA9PiB0aGlzLmdldFN0YXRzKCksIDEwMDApO1xuXG4gICAgICAgIC8qICAqL1xuICAgICAgICB0aGlzLnNldE1vdXNlSW5wdXRFbmFibGVkKHRoaXMuY29uZmlnLmlzRmxhZ0VuYWJsZWQoRmxhZ3MuTW91c2VJbnB1dCkpO1xuICAgICAgICB0aGlzLnNldEtleWJvYXJkSW5wdXRFbmFibGVkKHRoaXMuY29uZmlnLmlzRmxhZ0VuYWJsZWQoRmxhZ3MuS2V5Ym9hcmRJbnB1dCkpO1xuICAgICAgICB0aGlzLnNldEdhbWVQYWRJbnB1dEVuYWJsZWQodGhpcy5jb25maWcuaXNGbGFnRW5hYmxlZChGbGFncy5HYW1lcGFkSW5wdXQpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBXaGVuIGFuIGljZSBDYW5kaWRhdGUgaXMgcmVjZWl2ZWQgZnJvbSB0aGUgU2lnbmFsaW5nIHNlcnZlciBhZGQgaXQgdG8gdGhlIFBlZXIgQ29ubmVjdGlvbiBDbGllbnRcbiAgICAgKiBAcGFyYW0gaWNlQ2FuZGlkYXRlIC0gSWNlIENhbmRpZGF0ZSBmcm9tIFNlcnZlclxuICAgICAqL1xuICAgIGhhbmRsZUljZUNhbmRpZGF0ZShpY2VDYW5kaWRhdGU6IFJUQ0ljZUNhbmRpZGF0ZUluaXQpIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAnV2ViIFJUQyBDb250cm9sbGVyOiBvbldlYlJ0Y0ljZScsXG4gICAgICAgICAgICA2XG4gICAgICAgICk7XG5cbiAgICAgICAgY29uc3QgY2FuZGlkYXRlID0gbmV3IFJUQ0ljZUNhbmRpZGF0ZShpY2VDYW5kaWRhdGUpO1xuICAgICAgICB0aGlzLnBlZXJDb25uZWN0aW9uQ29udHJvbGxlci5oYW5kbGVPbkljZShjYW5kaWRhdGUpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNlbmQgdGhlIGljZSBDYW5kaWRhdGUgdG8gdGhlIHNpZ25hbGluZyBzZXJ2ZXIgdmlhIHdlYnNvY2tldFxuICAgICAqIEBwYXJhbSBpY2VFdmVudCAtIFJUQyBQZWVyIENvbm5lY3Rpb25JY2VFdmVudCkge1xuICAgICAqL1xuICAgIGhhbmRsZVNlbmRJY2VDYW5kaWRhdGUoaWNlRXZlbnQ6IFJUQ1BlZXJDb25uZWN0aW9uSWNlRXZlbnQpIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCAnT25JY2VDYW5kaWRhdGUnLCA2KTtcbiAgICAgICAgaWYgKGljZUV2ZW50LmNhbmRpZGF0ZSAmJiBpY2VFdmVudC5jYW5kaWRhdGUuY2FuZGlkYXRlKSB7XG4gICAgICAgICAgICB0aGlzLndlYlNvY2tldENvbnRyb2xsZXIuc2VuZEljZUNhbmRpZGF0ZShpY2VFdmVudC5jYW5kaWRhdGUpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2VuZCB0aGUgaWNlIENhbmRpZGF0ZSB0byB0aGUgc2lnbmFsaW5nIHNlcnZlciB2aWEgd2Vic29ja2V0XG4gICAgICogQHBhcmFtIGljZUV2ZW50IC0gUlRDIFBlZXIgQ29ubmVjdGlvbkljZUV2ZW50KSB7XG4gICAgICovXG4gICAgaGFuZGxlRGF0YUNoYW5uZWwoZGF0YWNoYW5uZWxFdmVudDogUlRDRGF0YUNoYW5uZWxFdmVudCkge1xuICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICdEYXRhIGNoYW5uZWwgY3JlYXRlZCBmb3IgdXMgYnkgYnJvd3NlciBhcyB3ZSBhcmUgYSByZWNlaXZpbmcgcGVlci4nLFxuICAgICAgICAgICAgNlxuICAgICAgICApO1xuICAgICAgICB0aGlzLnNlbmRyZWN2RGF0YUNoYW5uZWxDb250cm9sbGVyLmRhdGFDaGFubmVsID1cbiAgICAgICAgICAgIGRhdGFjaGFubmVsRXZlbnQuY2hhbm5lbDtcbiAgICAgICAgLy8gRGF0YSBjaGFubmVsIHdhcyBjcmVhdGVkIGZvciB1cywgc28gd2UganVzdCBuZWVkIHRvIHNldHVwIGl0cyBjYWxsYmFja3MgYW5kIGFycmF5IHR5cGVcbiAgICAgICAgdGhpcy5zZW5kcmVjdkRhdGFDaGFubmVsQ29udHJvbGxlci5zZXR1cERhdGFDaGFubmVsKCk7XG4gICAgICAgIHRoaXMuc2VuZHJlY3ZEYXRhQ2hhbm5lbENvbnRyb2xsZXIuaGFuZGxlT25NZXNzYWdlID0gKFxuICAgICAgICAgICAgZXY6IE1lc3NhZ2VFdmVudDxBcnJheUJ1ZmZlcj5cbiAgICAgICAgKSA9PiB0aGlzLmhhbmRsZU9uTWVzc2FnZShldik7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2VuZCB0aGUgUlRDIE9mZmVyIFNlc3Npb24gdG8gdGhlIFNpZ25hbGluZyBzZXJ2ZXIgdmlhIHdlYnNvY2tldFxuICAgICAqIEBwYXJhbSBvZmZlciAtIFJUQyBTZXNzaW9uIERlc2NyaXB0aW9uXG4gICAgICovXG4gICAgaGFuZGxlU2VuZFdlYlJUQ09mZmVyKG9mZmVyOiBSVENTZXNzaW9uRGVzY3JpcHRpb25Jbml0KSB7XG4gICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgJ1NlbmRpbmcgdGhlIG9mZmVyIHRvIHRoZSBTZXJ2ZXInLFxuICAgICAgICAgICAgNlxuICAgICAgICApO1xuICAgICAgICB0aGlzLndlYlNvY2tldENvbnRyb2xsZXIuc2VuZFdlYlJ0Y09mZmVyKG9mZmVyKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZW5kIHRoZSBSVEMgT2ZmZXIgU2Vzc2lvbiB0byB0aGUgU2lnbmFsaW5nIHNlcnZlciB2aWEgd2Vic29ja2V0XG4gICAgICogQHBhcmFtIGFuc3dlciAtIFJUQyBTZXNzaW9uIERlc2NyaXB0aW9uXG4gICAgICovXG4gICAgaGFuZGxlU2VuZFdlYlJUQ0Fuc3dlcihhbnN3ZXI6IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbkluaXQpIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAnU2VuZGluZyB0aGUgYW5zd2VyIHRvIHRoZSBTZXJ2ZXInLFxuICAgICAgICAgICAgNlxuICAgICAgICApO1xuICAgICAgICB0aGlzLndlYlNvY2tldENvbnRyb2xsZXIuc2VuZFdlYlJ0Y0Fuc3dlcihhbnN3ZXIpO1xuXG4gICAgICAgIGlmICh0aGlzLmlzVXNpbmdTRlUpIHtcbiAgICAgICAgICAgIHRoaXMud2ViU29ja2V0Q29udHJvbGxlci5zZW5kV2ViUnRjRGF0YWNoYW5uZWxSZXF1ZXN0KCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXQgdGhlIGZyZWV6ZSBmcmFtZSBvdmVybGF5IHRvIHRoZSBwbGF5ZXIgZGl2XG4gICAgICovXG4gICAgc2V0VXBNb3VzZUFuZEZyZWV6ZUZyYW1lKCkge1xuICAgICAgICAvLyBDYWxjdWxhdGluZyBhbmQgbm9ybWFsaXppbmcgcG9zaXRpb25zIGRlcGVuZHMgb24gdGhlIHdpZHRoIGFuZCBoZWlnaHQgb2YgdGhlIHBsYXllci5cbiAgICAgICAgdGhpcy52aWRlb0VsZW1lbnRQYXJlbnRDbGllbnRSZWN0ID0gdGhpcy52aWRlb1BsYXllclxuICAgICAgICAgICAgLmdldFZpZGVvUGFyZW50RWxlbWVudCgpXG4gICAgICAgICAgICAuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgIHRoaXMuY29vcmRpbmF0ZUNvbnZlcnRlci5zZXR1cE5vcm1hbGl6ZUFuZFF1YW50aXplKCk7XG4gICAgICAgIHRoaXMuZnJlZXplRnJhbWVDb250cm9sbGVyLmZyZWV6ZUZyYW1lLnJlc2l6ZSgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENsb3NlIHRoZSBDb25uZWN0aW9uIHRvIHRoZSBzaWduYWxpbmcgc2VydmVyXG4gICAgICovXG4gICAgY2xvc2VTaWduYWxpbmdTZXJ2ZXIobWVzc2FnZTogc3RyaW5nKSB7XG4gICAgICAgIC8vIFdlIGV4cGxpY2l0bHkgY2FsbGVkIGNsb3NlLCB0aGVyZWZvcmUgd2UgZG9uJ3Qgd2FudCB0byB0cmlnZ2VyIGF1dG8gcmVjb25uZWN0XG4gICAgICAgIHRoaXMubG9jYWxseUNsb3NlZCA9IHRydWU7XG4gICAgICAgIHRoaXMuc2hvdWxkUmVjb25uZWN0ID0gZmFsc2U7XG4gICAgICAgIHRoaXMuZGlzY29ubmVjdE1lc3NhZ2UgPSBtZXNzYWdlO1xuICAgICAgICB0aGlzLndlYlNvY2tldENvbnRyb2xsZXI/LmNsb3NlKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2xvc2UgdGhlIHBlZXIgY29ubmVjdGlvblxuICAgICAqL1xuICAgIGNsb3NlUGVlckNvbm5lY3Rpb24oKSB7XG4gICAgICAgIHRoaXMucGVlckNvbm5lY3Rpb25Db250cm9sbGVyPy5jbG9zZSgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENsb3NlIGFsbCBjb25uZWN0aW9uc1xuICAgICAqL1xuICAgIGNsb3NlKCkge1xuICAgICAgICB0aGlzLmNsb3NlU2lnbmFsaW5nU2VydmVyKCcnKTtcbiAgICAgICAgdGhpcy5jbG9zZVBlZXJDb25uZWN0aW9uKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRmlyZXMgYSBWaWRlbyBTdGF0cyBFdmVudCBpbiB0aGUgUlRDIFBlZXIgQ29ubmVjdGlvblxuICAgICAqL1xuICAgIGdldFN0YXRzKCkge1xuICAgICAgICB0aGlzLnBlZXJDb25uZWN0aW9uQ29udHJvbGxlci5nZW5lcmF0ZVN0YXRzKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2VuZCBhIExhdGVuY3kgVGVzdCBSZXF1ZXN0IHRvIHRoZSBVRSBJbnN0YW5jZVxuICAgICAqL1xuICAgIHNlbmRMYXRlbmN5VGVzdCgpIHtcbiAgICAgICAgdGhpcy5sYXRlbmN5U3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcblxuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnRvU3RyZWFtZXJIYW5kbGVycy5nZXQoXG4gICAgICAgICAgICAnTGF0ZW5jeVRlc3QnXG4gICAgICAgICkoW0pTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgIFN0YXJ0VGltZTogdGhpcy5sYXRlbmN5U3RhcnRUaW1lXG4gICAgICAgIH0pXSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2VuZCBhIERhdGEgQ2hhbm5lbCBMYXRlbmN5IFRlc3QgUmVxdWVzdCB0byB0aGUgVUUgSW5zdGFuY2VcbiAgICAgKi9cbiAgICBzZW5kRGF0YUNoYW5uZWxMYXRlbmN5VGVzdChkZXNjcmlwdG9yOiBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVxdWVzdCkge1xuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnRvU3RyZWFtZXJIYW5kbGVycy5nZXQoXG4gICAgICAgICAgICAnRGF0YUNoYW5uZWxMYXRlbmN5VGVzdCdcbiAgICAgICAgKShbSlNPTi5zdHJpbmdpZnkoZGVzY3JpcHRvcildKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZW5kIHRoZSBNaW5RUCBlbmNvZGVyIHNldHRpbmcgdG8gdGhlIFVFIEluc3RhbmNlLlxuICAgICAqIEBwYXJhbSBtaW5RUCAtIFRoZSBsb3dlciBib3VuZCBmb3IgUVAgd2hlbiBlbmNvZGluZ1xuICAgICAqIHZhbGlkIHZhbHVlcyBhcmUgKDEtNTEpIHdoZXJlOlxuICAgICAqIDEgPSBCZXN0IHF1YWxpdHkgYnV0IGhpZ2hlc3QgYml0cmF0ZS5cbiAgICAgKiA1MSA9IFdvcnN0IHF1YWxpdHkgYnV0IGxvd2VzdCBiaXRyYXRlLlxuICAgICAqIEJ5IGRlZmF1bHQgdGhlIG1pblFQIGlzIDEgbWVhbmluZyB0aGUgZW5jb2RlciBpcyBmcmVlXG4gICAgICogdG8gYWltIGZvciB0aGUgYmVzdCBxdWFsaXR5IGl0IGNhbiBvbiB0aGUgZ2l2ZW4gbmV0d29yayBsaW5rLlxuICAgICAqL1xuICAgIHNlbmRFbmNvZGVyTWluUVAobWluUVA6IG51bWJlcikge1xuICAgICAgICBMb2dnZXIuTG9nKExvZ2dlci5HZXRTdGFja1RyYWNlKCksIGBNaW5RUD0ke21pblFQfVxcbmAsIDYpO1xuXG4gICAgICAgIGlmIChtaW5RUCAhPSBudWxsKSB7XG4gICAgICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnRvU3RyZWFtZXJIYW5kbGVycy5nZXQoXG4gICAgICAgICAgICAgICAgJ0NvbW1hbmQnXG4gICAgICAgICAgICApKFtKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICAgICAgJ0VuY29kZXIuTWluUVAnOiBtaW5RUFxuICAgICAgICAgICAgfSldKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNlbmQgdGhlIE1heFFQIGVuY29kZXIgc2V0dGluZyB0byB0aGUgVUUgSW5zdGFuY2UuXG4gICAgICogQHBhcmFtIG1heFFQIC0gVGhlIHVwcGVyIGJvdW5kIGZvciBRUCB3aGVuIGVuY29kaW5nXG4gICAgICogdmFsaWQgdmFsdWVzIGFyZSAoMS01MSkgd2hlcmU6XG4gICAgICogMSA9IEJlc3QgcXVhbGl0eSBidXQgaGlnaGVzdCBiaXRyYXRlLlxuICAgICAqIDUxID0gV29yc3QgcXVhbGl0eSBidXQgbG93ZXN0IGJpdHJhdGUuXG4gICAgICogQnkgZGVmYXVsdCB0aGUgbWF4UVAgaXMgNTEgbWVhbmluZyB0aGUgZW5jb2RlciBpcyBmcmVlXG4gICAgICogdG8gZHJvcCBxdWFsaXR5IGFzIGxvdyBhcyBuZWVkZWQgb24gdGhlIGdpdmVuIG5ldHdvcmsgbGluay5cbiAgICAgKi9cbiAgICAgc2VuZEVuY29kZXJNYXhRUChtYXhRUDogbnVtYmVyKSB7XG4gICAgICAgIExvZ2dlci5Mb2coTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSwgYE1heFFQPSR7bWF4UVB9XFxuYCwgNik7XG5cbiAgICAgICAgaWYgKG1heFFQICE9IG51bGwpIHtcbiAgICAgICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIudG9TdHJlYW1lckhhbmRsZXJzLmdldChcbiAgICAgICAgICAgICAgICAnQ29tbWFuZCdcbiAgICAgICAgICAgICkoW0pTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICAnRW5jb2Rlci5NYXhRUCc6IG1heFFQXG4gICAgICAgICAgICB9KV0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2VuZCB0aGUgeyBXZWJSVEMuTWluQml0cmF0ZTogU29tZU51bWJlciB9fSBjb21tYW5kIHRvIFVFIHRvIHNldCBcbiAgICAgKiB0aGUgbWluaW11bSBiaXRyYXRlIHRoYXQgd2UgYWxsb3cgV2ViUlRDIHRvIHVzZSBcbiAgICAgKiAobm90ZSBzZXR0aW5nIHRoaXMgdG9vIGhpZ2ggaW4gcG9vciBuZXR3b3JrcyBjYW4gYmUgcHJvYmxlbWF0aWMpLlxuICAgICAqIEBwYXJhbSBtaW5CaXRyYXRlIC0gVGhlIG1pbmltdW0gYml0cmF0ZSB3ZSB3b3VsZCBsaWtlIFdlYlJUQyB0byBub3QgZmFsbCBiZWxvdy5cbiAgICAgKi9cbiAgICBzZW5kV2ViUlRDTWluQml0cmF0ZShtaW5CaXRyYXRlOiBudW1iZXIpIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCBgV2ViUlRDIE1pbiBCaXRyYXRlPSR7bWluQml0cmF0ZX1gLCA2KTtcbiAgICAgICAgaWYgKG1pbkJpdHJhdGUgIT0gbnVsbCkge1xuICAgICAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci50b1N0cmVhbWVySGFuZGxlcnMuZ2V0KFxuICAgICAgICAgICAgICAgICdDb21tYW5kJ1xuICAgICAgICAgICAgKShbSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgICAgICdXZWJSVEMuTWluQml0cmF0ZSc6IG1pbkJpdHJhdGVcbiAgICAgICAgICAgIH0pXSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZW5kIHRoZSB7IFdlYlJUQy5NYXhCaXRyYXRlOiBTb21lTnVtYmVyIH19IGNvbW1hbmQgdG8gVUUgdG8gc2V0IFxuICAgICAqIHRoZSBtaW5pbXVtIGJpdHJhdGUgdGhhdCB3ZSBhbGxvdyBXZWJSVEMgdG8gdXNlIFxuICAgICAqIChub3RlIHNldHRpbmcgdGhpcyB0b28gbG93IGNvdWxkIHJlc3VsdCBpbiBibG9ja3kgdmlkZW8pLlxuICAgICAqIEBwYXJhbSBtaW5CaXRyYXRlIC0gVGhlIG1pbmltdW0gYml0cmF0ZSB3ZSB3b3VsZCBsaWtlIFdlYlJUQyB0byBub3QgZmFsbCBiZWxvdy5cbiAgICAgKi9cbiAgICAgc2VuZFdlYlJUQ01heEJpdHJhdGUobWF4Qml0cmF0ZTogbnVtYmVyKSB7XG4gICAgICAgIExvZ2dlci5Mb2coTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSwgYFdlYlJUQyBNYXggQml0cmF0ZT0ke21heEJpdHJhdGV9YCwgNik7XG4gICAgICAgIGlmIChtYXhCaXRyYXRlICE9IG51bGwpIHtcbiAgICAgICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIudG9TdHJlYW1lckhhbmRsZXJzLmdldChcbiAgICAgICAgICAgICAgICAnQ29tbWFuZCdcbiAgICAgICAgICAgICkoW0pTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICAnV2ViUlRDLk1heEJpdHJhdGUnOiBtYXhCaXRyYXRlXG4gICAgICAgICAgICB9KV0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2VuZCB0aGUgeyBXZWJSVEMuRnBzOiBTb21lTnVtYmVyIH19IFVFIDUuMCtcbiAgICAgKiBhbmQgeyBXZWJSVEMuTWF4RnBzIH0gVUUgNC4yNyBjb21tYW5kIHRvIHNldCBcbiAgICAgKiB0aGUgbWF4aW11bSBmcHMgd2Ugd291bGQgbGlrZSBXZWJSVEMgdG8gc3RyZWFtIGF0LiBcbiAgICAgKiBAcGFyYW0gZnBzIC0gVGhlIG1heGltdW0gc3RyZWFtIGZwcy5cbiAgICAgKi9cbiAgICAgc2VuZFdlYlJUQ0ZwcyhmcHM6IG51bWJlcikge1xuICAgICAgICBMb2dnZXIuTG9nKExvZ2dlci5HZXRTdGFja1RyYWNlKCksIGBXZWJSVEMgRlBTPSR7ZnBzfWAsIDYpO1xuICAgICAgICBpZiAoZnBzICE9IG51bGwpIHtcbiAgICAgICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIudG9TdHJlYW1lckhhbmRsZXJzLmdldChcbiAgICAgICAgICAgICAgICAnQ29tbWFuZCdcbiAgICAgICAgICAgICkoW0pTT04uc3RyaW5naWZ5KHsnV2ViUlRDLkZwcyc6IGZwc30pXSk7XG5cbiAgICAgICAgICAgIC8qIFRPRE86IFJlbW92ZSB3aGVuIFVFIDQuMjcgdW5zdXBwb3J0ZWQuICovXG4gICAgICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnRvU3RyZWFtZXJIYW5kbGVycy5nZXQoXG4gICAgICAgICAgICAgICAgJ0NvbW1hbmQnXG4gICAgICAgICAgICApKFtKU09OLnN0cmluZ2lmeSh7J1dlYlJUQy5NYXhGcHMnOiBmcHN9KV0pOyBcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNlbmRzIHRoZSBVSSBEZXNjcmlwdG9yIGBzdGF0IGZwc2AgdG8gdGhlIFVFIEluc3RhbmNlXG4gICAgICovXG4gICAgc2VuZFNob3dGcHMoKTogdm9pZCB7XG4gICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgJy0tLS0gICBTZW5kaW5nIHNob3cgc3RhdCB0byBVRSAgIC0tLS0nLFxuICAgICAgICAgICAgNlxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIudG9TdHJlYW1lckhhbmRsZXJzLmdldChcbiAgICAgICAgICAgICdDb21tYW5kJ1xuICAgICAgICApKFtKU09OLnN0cmluZ2lmeSh7ICdzdGF0LmZwcyc6ICcnIH0pXSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2VuZCBhbiBJZnJhbWUgcmVxdWVzdCB0byB0aGUgc3RyZWFtZXJcbiAgICAgKi9cbiAgICBzZW5kSWZyYW1lUmVxdWVzdCgpOiB2b2lkIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAnLS0tLSAgIFNlbmRpbmcgUmVxdWVzdCBmb3IgYW4gSUZyYW1lICAtLS0tJyxcbiAgICAgICAgICAgIDZcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci50b1N0cmVhbWVySGFuZGxlcnMuZ2V0KCdJRnJhbWVSZXF1ZXN0JykoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZW5kIGEgVUlJbnRlcmFjdGlvbiBtZXNzYWdlXG4gICAgICovXG4gICAgZW1pdFVJSW50ZXJhY3Rpb24oZGVzY3JpcHRvcjogb2JqZWN0IHwgc3RyaW5nKSB7XG4gICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgJy0tLS0gICBTZW5kaW5nIGN1c3RvbSBVSUludGVyYWN0aW9uIG1lc3NhZ2UgICAtLS0tJyxcbiAgICAgICAgICAgIDZcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnRvU3RyZWFtZXJIYW5kbGVycy5nZXQoXG4gICAgICAgICAgICAnVUlJbnRlcmFjdGlvbidcbiAgICAgICAgKShbSlNPTi5zdHJpbmdpZnkoZGVzY3JpcHRvcildKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZW5kIGEgQ29tbWFuZCBtZXNzYWdlXG4gICAgICovXG4gICAgZW1pdENvbW1hbmQoZGVzY3JpcHRvcjogb2JqZWN0KSB7XG4gICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgJy0tLS0gICBTZW5kaW5nIGN1c3RvbSBDb21tYW5kIG1lc3NhZ2UgICAtLS0tJyxcbiAgICAgICAgICAgIDZcbiAgICAgICAgKTtcbiAgICAgICAgXG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIudG9TdHJlYW1lckhhbmRsZXJzLmdldChcbiAgICAgICAgICAgICdDb21tYW5kJ1xuICAgICAgICApKFtKU09OLnN0cmluZ2lmeShkZXNjcmlwdG9yKV0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNlbmQgYSBjb25zb2xlIGNvbW1hbmQgbWVzc2FnZVxuICAgICAqL1xuICAgIGVtaXRDb25zb2xlQ29tbWFuZChjb21tYW5kOiBzdHJpbmcpIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAnLS0tLSAgIFNlbmRpbmcgY3VzdG9tIENvbW1hbmQ6Q29uc29sZUNvbW1hbmQgbWVzc2FnZSAgIC0tLS0nLFxuICAgICAgICAgICAgNlxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIudG9TdHJlYW1lckhhbmRsZXJzLmdldChcbiAgICAgICAgICAgICdDb21tYW5kJ1xuICAgICAgICApKFtKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICBDb25zb2xlQ29tbWFuZDogY29tbWFuZCxcbiAgICAgICAgfSldKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZW5kcyBhIHJlcXVlc3QgdG8gdGhlIFVFIEluc3RhbmNlIHRvIGhhdmUgb3duZXJzaGlwIG9mIFF1YWxpdHlcbiAgICAgKi9cbiAgICBzZW5kUmVxdWVzdFF1YWxpdHlDb250cm9sT3duZXJzaGlwKCk6IHZvaWQge1xuICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICctLS0tICAgU2VuZGluZyBSZXF1ZXN0IHRvIENvbnRyb2wgUXVhbGl0eSAgLS0tLScsXG4gICAgICAgICAgICA2XG4gICAgICAgICk7XG4gICAgICAgIHRoaXMudG9TdHJlYW1lck1lc3NhZ2VzQ29udHJvbGxlci5TZW5kUmVxdWVzdFF1YWxpdHlDb250cm9sKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSGFuZGxlcyB3aGVuIGEgTGF0ZW5jeSBUZXN0IFJlc3VsdCBhcmUgcmVjZWl2ZWQgZnJvbSB0aGUgVUUgSW5zdGFuY2VcbiAgICAgKiBAcGFyYW0gbWVzc2FnZSAtIExhdGVuY3kgVGVzdCBUaW1pbmdzXG4gICAgICovXG4gICAgaGFuZGxlTGF0ZW5jeVRlc3RSZXN1bHQobWVzc2FnZTogQXJyYXlCdWZmZXIpIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAnRGF0YUNoYW5uZWxSZWNlaXZlTWVzc2FnZVR5cGUubGF0ZW5jeVRlc3QnLFxuICAgICAgICAgICAgNlxuICAgICAgICApO1xuICAgICAgICBjb25zdCBsYXRlbmN5QXNTdHJpbmcgPSBuZXcgVGV4dERlY29kZXIoJ3V0Zi0xNicpLmRlY29kZShcbiAgICAgICAgICAgIG1lc3NhZ2Uuc2xpY2UoMSlcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgbGF0ZW5jeVRlc3RSZXN1bHRzOiBMYXRlbmN5VGVzdFJlc3VsdHMgPSBuZXcgTGF0ZW5jeVRlc3RSZXN1bHRzKCk7XG4gICAgICAgIE9iamVjdC5hc3NpZ24obGF0ZW5jeVRlc3RSZXN1bHRzLCBKU09OLnBhcnNlKGxhdGVuY3lBc1N0cmluZykpO1xuICAgICAgICBsYXRlbmN5VGVzdFJlc3VsdHMucHJvY2Vzc0ZpZWxkcygpO1xuXG4gICAgICAgIGxhdGVuY3lUZXN0UmVzdWx0cy50ZXN0U3RhcnRUaW1lTXMgPSB0aGlzLmxhdGVuY3lTdGFydFRpbWU7XG4gICAgICAgIGxhdGVuY3lUZXN0UmVzdWx0cy5icm93c2VyUmVjZWlwdFRpbWVNcyA9IERhdGUubm93KCk7XG5cbiAgICAgICAgbGF0ZW5jeVRlc3RSZXN1bHRzLmxhdGVuY3lFeGNsdWRpbmdEZWNvZGUgPSB+fihcbiAgICAgICAgICAgIGxhdGVuY3lUZXN0UmVzdWx0cy5icm93c2VyUmVjZWlwdFRpbWVNcyAtXG4gICAgICAgICAgICBsYXRlbmN5VGVzdFJlc3VsdHMudGVzdFN0YXJ0VGltZU1zXG4gICAgICAgICk7XG4gICAgICAgIGxhdGVuY3lUZXN0UmVzdWx0cy50ZXN0RHVyYXRpb24gPSB+fihcbiAgICAgICAgICAgIGxhdGVuY3lUZXN0UmVzdWx0cy5UcmFuc21pc3Npb25UaW1lTXMgLVxuICAgICAgICAgICAgbGF0ZW5jeVRlc3RSZXN1bHRzLlJlY2VpcHRUaW1lTXNcbiAgICAgICAgKTtcbiAgICAgICAgbGF0ZW5jeVRlc3RSZXN1bHRzLm5ldHdvcmtMYXRlbmN5ID0gfn4oXG4gICAgICAgICAgICBsYXRlbmN5VGVzdFJlc3VsdHMubGF0ZW5jeUV4Y2x1ZGluZ0RlY29kZSAtXG4gICAgICAgICAgICBsYXRlbmN5VGVzdFJlc3VsdHMudGVzdER1cmF0aW9uXG4gICAgICAgICk7XG5cbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgbGF0ZW5jeVRlc3RSZXN1bHRzLmZyYW1lRGlzcGxheURlbHRhVGltZU1zICYmXG4gICAgICAgICAgICBsYXRlbmN5VGVzdFJlc3VsdHMuYnJvd3NlclJlY2VpcHRUaW1lTXNcbiAgICAgICAgKSB7XG4gICAgICAgICAgICBsYXRlbmN5VGVzdFJlc3VsdHMuZW5kVG9FbmRMYXRlbmN5ID1cbiAgICAgICAgICAgICAgICB+fihsYXRlbmN5VGVzdFJlc3VsdHMuZnJhbWVEaXNwbGF5RGVsdGFUaW1lTXMgK1xuICAgICAgICAgICAgICAgICAgICBsYXRlbmN5VGVzdFJlc3VsdHMubmV0d29ya0xhdGVuY3ksXG4gICAgICAgICAgICAgICAgK2xhdGVuY3lUZXN0UmVzdWx0cy5DYXB0dXJlVG9TZW5kTXMpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucGl4ZWxTdHJlYW1pbmcuX29uTGF0ZW5jeVRlc3RSZXN1bHQobGF0ZW5jeVRlc3RSZXN1bHRzKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGVzIHdoZW4gYSBEYXRhIENoYW5uZWwgTGF0ZW5jeSBUZXN0IFJlc3BvbnNlIGlzIHJlY2VpdmVkIGZyb20gdGhlIFVFIEluc3RhbmNlXG4gICAgICogQHBhcmFtIG1lc3NhZ2UgLSBEYXRhIENoYW5uZWwgTGF0ZW5jeSBUZXN0IFJlc3BvbnNlXG4gICAgICovXG4gICAgaGFuZGxlRGF0YUNoYW5uZWxMYXRlbmN5VGVzdFJlc3BvbnNlKG1lc3NhZ2U6IEFycmF5QnVmZmVyKSB7XG4gICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgJ0RhdGFDaGFubmVsUmVjZWl2ZU1lc3NhZ2VUeXBlLmRhdGFDaGFubmVsTGF0ZW5jeVJlc3BvbnNlJyxcbiAgICAgICAgICAgIDZcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgcmVzcG9uc2VBc1N0cmluZyA9IG5ldyBUZXh0RGVjb2RlcigndXRmLTE2JykuZGVjb2RlKFxuICAgICAgICAgICAgbWVzc2FnZS5zbGljZSgxKVxuICAgICAgICApO1xuICAgICAgICBjb25zdCBsYXRlbmN5VGVzdFJlc3BvbnNlOiBEYXRhQ2hhbm5lbExhdGVuY3lUZXN0UmVzcG9uc2UgPSBKU09OLnBhcnNlKHJlc3BvbnNlQXNTdHJpbmcpO1xuICAgICAgICB0aGlzLnBpeGVsU3RyZWFtaW5nLl9vbkRhdGFDaGFubmVsTGF0ZW5jeVRlc3RSZXNwb25zZShsYXRlbmN5VGVzdFJlc3BvbnNlKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGVzIHdoZW4gdGhlIEVuY29kZXIgYW5kIFdlYiBSVEMgU2V0dGluZ3MgYXJlIHJlY2VpdmVkIGZyb20gdGhlIFVFIEluc3RhbmNlXG4gICAgICogQHBhcmFtIG1lc3NhZ2UgLSBJbml0aWFsIEVuY29kZXIgYW5kIFdlYiBSVEMgU2V0dGluZ3NcbiAgICAgKi9cbiAgICBoYW5kbGVJbml0aWFsU2V0dGluZ3MobWVzc2FnZTogQXJyYXlCdWZmZXIpIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAnRGF0YUNoYW5uZWxSZWNlaXZlTWVzc2FnZVR5cGUuSW5pdGlhbFNldHRpbmdzJyxcbiAgICAgICAgICAgIDZcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgcGF5bG9hZEFzU3RyaW5nID0gbmV3IFRleHREZWNvZGVyKCd1dGYtMTYnKS5kZWNvZGUoXG4gICAgICAgICAgICBtZXNzYWdlLnNsaWNlKDEpXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHBhcnNlZEluaXRpYWxTZXR0aW5ncyA9IEpTT04ucGFyc2UocGF5bG9hZEFzU3RyaW5nKTtcblxuICAgICAgICBjb25zdCBpbml0aWFsU2V0dGluZ3M6IEluaXRpYWxTZXR0aW5ncyA9IG5ldyBJbml0aWFsU2V0dGluZ3MoKTtcblxuICAgICAgICBpZiAocGFyc2VkSW5pdGlhbFNldHRpbmdzLkVuY29kZXIpIHtcbiAgICAgICAgICAgIGluaXRpYWxTZXR0aW5ncy5FbmNvZGVyU2V0dGluZ3MgPSBwYXJzZWRJbml0aWFsU2V0dGluZ3MuRW5jb2RlcjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwYXJzZWRJbml0aWFsU2V0dGluZ3MuV2ViUlRDKSB7XG4gICAgICAgICAgICBpbml0aWFsU2V0dGluZ3MuV2ViUlRDU2V0dGluZ3MgPSBwYXJzZWRJbml0aWFsU2V0dGluZ3MuV2ViUlRDO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHBhcnNlZEluaXRpYWxTZXR0aW5ncy5QaXhlbFN0cmVhbWluZykge1xuICAgICAgICAgICAgaW5pdGlhbFNldHRpbmdzLlBpeGVsU3RyZWFtaW5nU2V0dGluZ3MgPVxuICAgICAgICAgICAgICAgIHBhcnNlZEluaXRpYWxTZXR0aW5ncy5QaXhlbFN0cmVhbWluZztcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChwYXJzZWRJbml0aWFsU2V0dGluZ3MuQ29uZmlnT3B0aW9ucyAmJiBwYXJzZWRJbml0aWFsU2V0dGluZ3MuQ29uZmlnT3B0aW9ucy5EZWZhdWx0VG9Ib3ZlciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICB0aGlzLmNvbmZpZy5zZXRGbGFnRW5hYmxlZChcbiAgICAgICAgICAgICAgICBGbGFncy5Ib3ZlcmluZ01vdXNlTW9kZSxcbiAgICAgICAgICAgICAgICAhIXBhcnNlZEluaXRpYWxTZXR0aW5ncy5Db25maWdPcHRpb25zLkRlZmF1bHRUb0hvdmVyXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgaW5pdGlhbFNldHRpbmdzLnVlQ29tcGF0aWJsZSgpO1xuICAgICAgICBMb2dnZXIuTG9nKExvZ2dlci5HZXRTdGFja1RyYWNlKCksIHBheWxvYWRBc1N0cmluZywgNik7XG5cbiAgICAgICAgdGhpcy5waXhlbFN0cmVhbWluZy5fb25Jbml0aWFsU2V0dGluZ3MoaW5pdGlhbFNldHRpbmdzKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGVzIHdoZW4gdGhlIFF1YW50aXphdGlvbiBQYXJhbWV0ZXIgYXJlIHJlY2VpdmVkIGZyb20gdGhlIFVFIEluc3RhbmNlXG4gICAgICogQHBhcmFtIG1lc3NhZ2UgLSBFbmNvZGVycyBRdWFudGl6YXRpb24gUGFyYW1ldGVyXG4gICAgICovXG4gICAgaGFuZGxlVmlkZW9FbmNvZGVyQXZnUVAobWVzc2FnZTogQXJyYXlCdWZmZXIpIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAnRGF0YUNoYW5uZWxSZWNlaXZlTWVzc2FnZVR5cGUuVmlkZW9FbmNvZGVyQXZnUVAnLFxuICAgICAgICAgICAgNlxuICAgICAgICApO1xuICAgICAgICBjb25zdCBBdmdRUCA9IE51bWJlcihcbiAgICAgICAgICAgIG5ldyBUZXh0RGVjb2RlcigndXRmLTE2JykuZGVjb2RlKG1lc3NhZ2Uuc2xpY2UoMSkpXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuc2V0VmlkZW9FbmNvZGVyQXZnUVAoQXZnUVApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEhhbmRsZXMgd2hlbiB0aGUgdmlkZW8gZWxlbWVudCBoYXMgYmVlbiBsb2FkZWQgd2l0aCBhIHNyY09iamVjdFxuICAgICAqL1xuICAgIGhhbmRsZVZpZGVvSW5pdGlhbGl6ZWQoKSB7XG4gICAgICAgIHRoaXMucGl4ZWxTdHJlYW1pbmcuX29uVmlkZW9Jbml0aWFsaXplZCgpO1xuXG4gICAgICAgIC8vIGVpdGhlciBhdXRvcGxheSB0aGUgdmlkZW8gb3Igc2V0IHVwIHRoZSBwbGF5IG92ZXJsYXlcbiAgICAgICAgdGhpcy5hdXRvUGxheVZpZGVvT3JTZXRVcFBsYXlPdmVybGF5KCk7XG4gICAgICAgIHRoaXMucmVzaXplUGxheWVyU3R5bGUoKTtcbiAgICAgICAgdGhpcy52aWRlb1BsYXllci51cGRhdGVWaWRlb1N0cmVhbVNpemUoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBGbGFnIHNldCBpZiB0aGUgdXNlciBoYXMgUXVhbGl0eSBPd25lcnNoaXBcbiAgICAgKiBAcGFyYW0gbWVzc2FnZSAtIERvZXMgdGhlIGN1cnJlbnQgY2xpZW50IGhhdmUgUXVhbGl0eSBPd25lcnNoaXBcbiAgICAgKi9cbiAgICBvblF1YWxpdHlDb250cm9sT3duZXJzaGlwKG1lc3NhZ2U6IEFycmF5QnVmZmVyKSB7XG4gICAgICAgIGNvbnN0IHZpZXcgPSBuZXcgVWludDhBcnJheShtZXNzYWdlKTtcbiAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAnRGF0YUNoYW5uZWxSZWNlaXZlTWVzc2FnZVR5cGUuUXVhbGl0eUNvbnRyb2xPd25lcnNoaXAnLFxuICAgICAgICAgICAgNlxuICAgICAgICApO1xuICAgICAgICB0aGlzLmlzUXVhbGl0eUNvbnRyb2xsZXIgPSBuZXcgQm9vbGVhbih2aWV3WzFdKS52YWx1ZU9mKCk7XG4gICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgYFJlY2VpdmVkIHF1YWxpdHkgY29udHJvbGxlciBtZXNzYWdlLCB3aWxsIGNvbnRyb2wgcXVhbGl0eTogJHt0aGlzLmlzUXVhbGl0eUNvbnRyb2xsZXJ9YFxuICAgICAgICApO1xuICAgICAgICB0aGlzLnBpeGVsU3RyZWFtaW5nLl9vblF1YWxpdHlDb250cm9sT3duZXJzaGlwKFxuICAgICAgICAgICAgdGhpcy5pc1F1YWxpdHlDb250cm9sbGVyXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSGFuZGxlcyB3aGVuIHRoZSBBZ2dyZWdhdGVkIHN0YXRzIGFyZSBDb2xsZWN0ZWRcbiAgICAgKiBAcGFyYW0gc3RhdHMgLSBBZ2dyZWdhdGVkIFN0YXRzXG4gICAgICovXG4gICAgaGFuZGxlVmlkZW9TdGF0cyhzdGF0czogQWdncmVnYXRlZFN0YXRzKSB7XG4gICAgICAgIHRoaXMucGl4ZWxTdHJlYW1pbmcuX29uVmlkZW9TdGF0cyhzdGF0cyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVG8gUmVzaXplIHRoZSBWaWRlbyBQbGF5ZXIgZWxlbWVudFxuICAgICAqL1xuICAgIHJlc2l6ZVBsYXllclN0eWxlKCk6IHZvaWQge1xuICAgICAgICB0aGlzLnZpZGVvUGxheWVyLnJlc2l6ZVBsYXllclN0eWxlKCk7XG4gICAgfVxuXG4gICAgc2V0UHJlZmVycmVkQ29kZWMoY29kZWM6IHN0cmluZykge1xuICAgICAgICB0aGlzLnByZWZlcnJlZENvZGVjID0gY29kZWM7XG4gICAgICAgIGlmICh0aGlzLnBlZXJDb25uZWN0aW9uQ29udHJvbGxlcikge1xuICAgICAgICAgICAgdGhpcy5wZWVyQ29ubmVjdGlvbkNvbnRyb2xsZXIucHJlZmVycmVkQ29kZWMgPSBjb2RlYztcbiAgICAgICAgICAgIHRoaXMucGVlckNvbm5lY3Rpb25Db250cm9sbGVyLnVwZGF0ZUNvZGVjU2VsZWN0aW9uID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBzZXRWaWRlb0VuY29kZXJBdmdRUChhdmdRUDogbnVtYmVyKSB7XG4gICAgICAgIHRoaXMudmlkZW9BdmdRcCA9IGF2Z1FQO1xuICAgICAgICB0aGlzLnBpeGVsU3RyZWFtaW5nLl9vblZpZGVvRW5jb2RlckF2Z1FQKHRoaXMudmlkZW9BdmdRcCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogZW5hYmxlcy9kaXNhYmxlcyBrZXlib2FyZCBldmVudCBsaXN0ZW5lcnNcbiAgICAgKi9cbiAgICBzZXRLZXlib2FyZElucHV0RW5hYmxlZChpc0VuYWJsZWQ6IGJvb2xlYW4pIHtcbiAgICAgICAgdGhpcy5rZXlib2FyZENvbnRyb2xsZXI/LnVucmVnaXN0ZXJLZXlCb2FyZEV2ZW50cygpO1xuICAgICAgICBpZiAoaXNFbmFibGVkKSB7XG4gICAgICAgICAgICB0aGlzLmtleWJvYXJkQ29udHJvbGxlciA9IHRoaXMuaW5wdXRDbGFzc2VzRmFjdG9yeS5yZWdpc3RlcktleUJvYXJkKFxuICAgICAgICAgICAgICAgIHRoaXMuY29uZmlnXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogZW5hYmxlcy9kaXNhYmxlcyBtb3VzZSBldmVudCBsaXN0ZW5lcnNcbiAgICAgKi9cbiAgICBzZXRNb3VzZUlucHV0RW5hYmxlZChpc0VuYWJsZWQ6IGJvb2xlYW4pIHtcbiAgICAgICAgdGhpcy5tb3VzZUNvbnRyb2xsZXI/LnVucmVnaXN0ZXJNb3VzZUV2ZW50cygpO1xuICAgICAgICBpZiAoaXNFbmFibGVkKSB7XG4gICAgICAgICAgICBjb25zdCBtb3VzZU1vZGUgPSB0aGlzLmNvbmZpZy5pc0ZsYWdFbmFibGVkKEZsYWdzLkhvdmVyaW5nTW91c2VNb2RlKVxuICAgICAgICAgICAgPyBDb250cm9sU2NoZW1lVHlwZS5Ib3ZlcmluZ01vdXNlXG4gICAgICAgICAgICA6IENvbnRyb2xTY2hlbWVUeXBlLkxvY2tlZE1vdXNlO1xuICAgICAgICAgICAgdGhpcy5tb3VzZUNvbnRyb2xsZXIgPVxuICAgICAgICAgICAgdGhpcy5pbnB1dENsYXNzZXNGYWN0b3J5LnJlZ2lzdGVyTW91c2UobW91c2VNb2RlKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIGVuYWJsZXMvZGlzYWJsZXMgdG91Y2ggZXZlbnQgbGlzdGVuZXJzXG4gICAgICovXG4gICAgc2V0VG91Y2hJbnB1dEVuYWJsZWQoaXNFbmFibGVkOiBib29sZWFuKSB7XG4gICAgICAgIHRoaXMudG91Y2hDb250cm9sbGVyPy51bnJlZ2lzdGVyVG91Y2hFdmVudHMoKTtcbiAgICAgICAgaWYgKGlzRW5hYmxlZCkge1xuICAgICAgICAgICAgdGhpcy50b3VjaENvbnRyb2xsZXIgPSB0aGlzLmlucHV0Q2xhc3Nlc0ZhY3RvcnkucmVnaXN0ZXJUb3VjaChcbiAgICAgICAgICAgICAgICB0aGlzLmNvbmZpZy5pc0ZsYWdFbmFibGVkKEZsYWdzLkZha2VNb3VzZVdpdGhUb3VjaGVzKSxcbiAgICAgICAgICAgICAgICB0aGlzLnZpZGVvRWxlbWVudFBhcmVudENsaWVudFJlY3RcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBlbmFibGVzL2Rpc2FibGVzIGdhbWUgcGFkIGV2ZW50IGxpc3RlbmVyc1xuICAgICAqL1xuICAgIHNldEdhbWVQYWRJbnB1dEVuYWJsZWQoaXNFbmFibGVkOiBib29sZWFuKSB7XG4gICAgICAgIHRoaXMuZ2FtZVBhZENvbnRyb2xsZXI/LnVucmVnaXN0ZXJHYW1lUGFkRXZlbnRzKCk7XG4gICAgICAgIGlmIChpc0VuYWJsZWQpIHtcbiAgICAgICAgICAgIHRoaXMuZ2FtZVBhZENvbnRyb2xsZXIgPSB0aGlzLmlucHV0Q2xhc3Nlc0ZhY3RvcnkucmVnaXN0ZXJHYW1lUGFkKCk7XG4gICAgICAgICAgICB0aGlzLmdhbWVQYWRDb250cm9sbGVyLm9uR2FtZXBhZENvbm5lY3RlZCA9ICgpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnRvU3RyZWFtZXJIYW5kbGVycy5nZXQoJ0dhbWVwYWRDb25uZWN0ZWQnKSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5nYW1lUGFkQ29udHJvbGxlci5vbkdhbWVwYWREaXNjb25uZWN0ZWQgPSAoY29udHJvbGxlcklkeDogbnVtYmVyKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5zdHJlYW1NZXNzYWdlQ29udHJvbGxlci50b1N0cmVhbWVySGFuZGxlcnMuZ2V0KCdHYW1lcGFkRGlzY29ubmVjdGVkJykoW2NvbnRyb2xsZXJJZHhdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJlZ2lzdGVyRGF0YUNoYW5uZWxFdmVudEVtaXR0ZXJzKGRhdGFDaGFubmVsOiBEYXRhQ2hhbm5lbENvbnRyb2xsZXIpIHtcbiAgICAgICAgZGF0YUNoYW5uZWwub25PcGVuID0gKGxhYmVsLCBldmVudCkgPT5cbiAgICAgICAgICAgIHRoaXMucGl4ZWxTdHJlYW1pbmcuZGlzcGF0Y2hFdmVudChcbiAgICAgICAgICAgICAgICBuZXcgRGF0YUNoYW5uZWxPcGVuRXZlbnQoeyBsYWJlbCwgZXZlbnQgfSlcbiAgICAgICAgICAgICk7XG4gICAgICAgIGRhdGFDaGFubmVsLm9uQ2xvc2UgPSAobGFiZWwsIGV2ZW50KSA9PlxuICAgICAgICAgICAgdGhpcy5waXhlbFN0cmVhbWluZy5kaXNwYXRjaEV2ZW50KFxuICAgICAgICAgICAgICAgIG5ldyBEYXRhQ2hhbm5lbENsb3NlRXZlbnQoeyBsYWJlbCwgZXZlbnQgfSlcbiAgICAgICAgICAgICk7XG4gICAgICAgIGRhdGFDaGFubmVsLm9uRXJyb3IgPSAobGFiZWwsIGV2ZW50KSA9PlxuICAgICAgICAgICAgdGhpcy5waXhlbFN0cmVhbWluZy5kaXNwYXRjaEV2ZW50KFxuICAgICAgICAgICAgICAgIG5ldyBEYXRhQ2hhbm5lbEVycm9yRXZlbnQoeyBsYWJlbCwgZXZlbnQgfSlcbiAgICAgICAgICAgICk7XG4gICAgfVxuXG4gICAgcHVibGljIHJlZ2lzdGVyTWVzc2FnZUhhbmRsZXIobmFtZTogc3RyaW5nLCBkaXJlY3Rpb246IE1lc3NhZ2VEaXJlY3Rpb24sIGhhbmRsZXI/OiAoZGF0YTogQXJyYXlCdWZmZXIgfCBBcnJheTxudW1iZXIgfCBzdHJpbmc+KSA9PiB2b2lkKSB7XG4gICAgICAgIGlmKGRpcmVjdGlvbiA9PT0gTWVzc2FnZURpcmVjdGlvbi5Gcm9tU3RyZWFtZXIgJiYgdHlwZW9mIGhhbmRsZXIgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICBMb2dnZXIuV2FybmluZyhcbiAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgIGBVbmFibGUgdG8gcmVnaXN0ZXIgaGFuZGxlciBmb3IgJHtuYW1lfSBhcyBubyBoYW5kbGVyIHdhcyBwYXNzZWRgXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgXG4gICAgICAgIHRoaXMuc3RyZWFtTWVzc2FnZUNvbnRyb2xsZXIucmVnaXN0ZXJNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIGRpcmVjdGlvbixcbiAgICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgICAoZGF0YTogQXJyYXk8bnVtYmVyIHwgc3RyaW5nPikgPT4gKHR5cGVvZiBoYW5kbGVyID09PSAndW5kZWZpbmVkJyAmJiBkaXJlY3Rpb24gPT09IE1lc3NhZ2VEaXJlY3Rpb24uVG9TdHJlYW1lcikgPyBcbiAgICAgICAgICAgICAgICB0aGlzLnNlbmRNZXNzYWdlQ29udHJvbGxlci5zZW5kTWVzc2FnZVRvU3RyZWFtZXIoXG4gICAgICAgICAgICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgICAgICAgICAgIGRhdGFcbiAgICAgICAgICAgICAgICApIDogICBcbiAgICAgICAgICAgICAgICBoYW5kbGVyKGRhdGEpXG4gICAgICAgICk7XG4gICAgfVxufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuLyoqXG4gKiBUaGUgVHlwZXMgb2YgTWVzc2FnZXMgdGhhdCB3aWxsIGJlIHJlY2VpdmVkXG4gKi9cbmV4cG9ydCBlbnVtIE1lc3NhZ2VSZWN2VHlwZXMge1xuICAgIENPTkZJRyA9ICdjb25maWcnLFxuICAgIFNUUkVBTUVSX0xJU1QgPSAnc3RyZWFtZXJMaXN0JyxcbiAgICBQTEFZRVJfQ09VTlQgPSAncGxheWVyQ291bnQnLFxuICAgIE9GRkVSID0gJ29mZmVyJyxcbiAgICBBTlNXRVIgPSAnYW5zd2VyJyxcbiAgICBJQ0VfQ0FORElEQVRFID0gJ2ljZUNhbmRpZGF0ZScsXG4gICAgUEVFUl9EQVRBX0NIQU5ORUxTID0gJ3BlZXJEYXRhQ2hhbm5lbHMnLFxuICAgIFBJTkcgPSAncGluZycsXG4gICAgV0FSTklORyA9ICd3YXJuaW5nJ1xufVxuXG4vKipcbiAqIENvbmNyZXRlIFJlY2VpdmVkIE1lc3NhZ2Ugd3JhcHBlclxuICovXG5leHBvcnQgY2xhc3MgTWVzc2FnZVJlY3Yge1xuICAgIHR5cGU6IHN0cmluZztcbiAgICBpZDogc3RyaW5nO1xufVxuXG4vKipcbiAqIEF1dGhlbnRpY2F0aW9uIFJlcXVpcmVkIE1lc3NhZ2Ugd3JhcHBlclxuICovXG5leHBvcnQgY2xhc3MgTWVzc2FnZUF1dGhSZXF1aXJlZCBleHRlbmRzIE1lc3NhZ2VSZWN2IHt9XG5cbi8qKlxuICogQ29uZmlnIE1lc3NhZ2UgV3JhcHBlclxuICovXG5leHBvcnQgY2xhc3MgTWVzc2FnZUNvbmZpZyBleHRlbmRzIE1lc3NhZ2VSZWN2IHtcbiAgICBwZWVyQ29ubmVjdGlvbk9wdGlvbnM6IFJUQ0NvbmZpZ3VyYXRpb247XG59XG5cbi8qKlxuICogU3RyZWFtZXIgTGlzdCBNZXNzYWdlIFdyYXBwZXJcbiAqL1xuZXhwb3J0IGNsYXNzIE1lc3NhZ2VTdHJlYW1lckxpc3QgZXh0ZW5kcyBNZXNzYWdlUmVjdiB7XG4gICAgaWRzOiBzdHJpbmdbXTtcbn1cblxuLyoqXG4gKiBQbGF5ZXIgQ291bnQgTWVzc2FnZSB3cmFwcGVyXG4gKi9cbmV4cG9ydCBjbGFzcyBNZXNzYWdlUGxheWVyQ291bnQgZXh0ZW5kcyBNZXNzYWdlUmVjdiB7XG4gICAgY291bnQ6IG51bWJlcjtcbn1cblxuLyoqXG4gKiBXZWIgUlRDIG9mZmVyIEFuc3dlciBNZXNzYWdlIHdyYXBwZXJcbiAqL1xuZXhwb3J0IGNsYXNzIE1lc3NhZ2VBbnN3ZXIgZXh0ZW5kcyBNZXNzYWdlUmVjdiB7XG4gICAgc2RwOiBzdHJpbmc7XG59XG5cbi8qKlxuICogV2ViUlRDIHNkcCBvZmZlciBNZXNzYWdlIHdyYXBwZXIuXG4gKi9cbmV4cG9ydCBjbGFzcyBNZXNzYWdlT2ZmZXIgZXh0ZW5kcyBNZXNzYWdlUmVjdiB7XG4gICAgc2RwOiBzdHJpbmc7XG4gICAgc2Z1PzogYm9vbGVhbjtcbiAgICBkZWZhdWx0VG9Ib3Zlcj86IHN0cmluZztcbn1cblxuLyoqXG4gKiBJY2UgQ2FuZGlkYXRlIE1lc3NhZ2Ugd3JhcHBlclxuICovXG5leHBvcnQgY2xhc3MgTWVzc2FnZUljZUNhbmRpZGF0ZSBleHRlbmRzIE1lc3NhZ2VSZWN2IHtcbiAgICBjYW5kaWRhdGU6IFJUQ0ljZUNhbmRpZGF0ZUluaXQ7XG59XG5cbi8qKlxuICogUGVlciBEYXRhIENoYW5uZWxzIE1lc3NhZ2Ugd3JhcHBlclxuICovXG5leHBvcnQgY2xhc3MgTWVzc2FnZVBlZXJEYXRhQ2hhbm5lbHMgZXh0ZW5kcyBNZXNzYWdlUmVjdiB7XG4gICAgcmVjdlN0cmVhbUlkOiBudW1iZXI7XG4gICAgc2VuZFN0cmVhbUlkOiBudW1iZXI7XG4gICAgdHlwZTogc3RyaW5nO1xufVxuXG5leHBvcnQgY2xhc3MgTWVzc2FnZU9uU2NyZWVuS2V5Ym9hcmQge1xuICAgIGNvbW1hbmQ6IHN0cmluZztcbiAgICBzaG93T25TY3JlZW5LZXlib2FyZDogYm9vbGVhbjtcbiAgICB4OiBudW1iZXI7XG4gICAgeTogbnVtYmVyO1xufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuaW1wb3J0IHsgTG9nZ2VyIH0gZnJvbSAnLi4vTG9nZ2VyL0xvZ2dlcic7XG5cbi8qKlxuICogVGhlIFNlbmQgVHlwZXMgdGhhdCBhcmUgcHVzaGVkIGZyb20gdGhlIHNpZ25hbGluZyBzZXJ2ZXJcbiAqL1xuZXhwb3J0IGVudW0gTWVzc2FnZVNlbmRUeXBlcyB7XG4gICAgTElTVF9TVFJFQU1FUlMgPSAnbGlzdFN0cmVhbWVycycsXG4gICAgU1VCU0NSSUJFID0gJ3N1YnNjcmliZScsXG4gICAgVU5TVUJTQ1JJQkUgPSAndW5zdWJzY3JpYmUnLFxuICAgIElDRV9DQU5ESURBVEUgPSAnaWNlQ2FuZGlkYXRlJyxcbiAgICBPRkZFUiA9ICdvZmZlcicsXG4gICAgQU5TV0VSID0gJ2Fuc3dlcicsXG4gICAgREFUQUNIQU5ORUxSRVFVRVNUID0gJ2RhdGFDaGFubmVsUmVxdWVzdCcsXG4gICAgU0ZVUkVDVkRBVEFDSEFOTkVMUkVBRFkgPSAncGVlckRhdGFDaGFubmVsc1JlYWR5JyxcbiAgICBQT05HID0gJ3BvbmcnXG59XG5cbi8qKlxuICogQSBXcmFwcGVyIGZvciB0aGUgbWVzc2FnZSB0byBzZW5kIHRvIHRoZSBzaWduYWxpbmcgc2VydmVyXG4gKi9cbmV4cG9ydCBjbGFzcyBNZXNzYWdlU2VuZCBpbXBsZW1lbnRzIFNlbmQge1xuICAgIHR5cGU6IHN0cmluZztcbiAgICBwZWVyQ29ubmVjdGlvbk9wdGlvbnM6IG9iamVjdDtcblxuICAgIC8qKlxuICAgICAqIFR1cm5zIHRoZSB3cmFwcGVyIGludG8gYSBKU09OIFN0cmluZ1xuICAgICAqIEByZXR1cm5zIC0gSlNPTiBTdHJpbmcgb2YgdGhlIE1lc3NhZ2UgdG8gc2VuZFxuICAgICAqL1xuICAgIHBheWxvYWQoKSB7XG4gICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgJ1NlbmRpbmcgPT4gXFxuJyArIEpTT04uc3RyaW5naWZ5KHRoaXMsIHVuZGVmaW5lZCwgNCksXG4gICAgICAgICAgICA2XG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeSh0aGlzKTtcbiAgICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2VuZCB7XG4gICAgLyoqXG4gICAgICogVHVybnMgdGhlIHdyYXBwZXIgaW50byBhIEpTT04gU3RyaW5nXG4gICAgICogQHJldHVybnMgLSBKU09OIFN0cmluZyBvZiB0aGUgTWVzc2FnZSB0byBzZW5kXG4gICAgICovXG4gICAgcGF5bG9hZDogKCkgPT4gc3RyaW5nO1xufVxuXG5leHBvcnQgY2xhc3MgTWVzc2FnZUxpc3RTdHJlYW1lcnMgZXh0ZW5kcyBNZXNzYWdlU2VuZCB7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKCk7XG4gICAgICAgIHRoaXMudHlwZSA9IE1lc3NhZ2VTZW5kVHlwZXMuTElTVF9TVFJFQU1FUlM7XG4gICAgfVxufVxuXG5leHBvcnQgY2xhc3MgTWVzc2FnZVN1YnNjcmliZSBleHRlbmRzIE1lc3NhZ2VTZW5kIHtcbiAgICBzdHJlYW1lcklkOiBzdHJpbmc7XG5cbiAgICBjb25zdHJ1Y3RvcihzdHJlYW1lcmlkOiBzdHJpbmcpIHtcbiAgICAgICAgc3VwZXIoKTtcbiAgICAgICAgdGhpcy50eXBlID0gTWVzc2FnZVNlbmRUeXBlcy5TVUJTQ1JJQkU7XG4gICAgICAgIHRoaXMuc3RyZWFtZXJJZCA9IHN0cmVhbWVyaWQ7XG4gICAgfVxufVxuXG5leHBvcnQgY2xhc3MgTWVzc2FnZVVuc3Vic2NyaWJlIGV4dGVuZHMgTWVzc2FnZVNlbmQge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlcigpO1xuICAgICAgICB0aGlzLnR5cGUgPSBNZXNzYWdlU2VuZFR5cGVzLlVOU1VCU0NSSUJFO1xuICAgIH1cbn1cblxuLyoqXG4gKiBJbnN0YW5jZSBSZXF1ZXN0IE1lc3NhZ2UgV3JhcHBlclxuICovXG5leHBvcnQgY2xhc3MgTWVzc2FnZVBvbmcgZXh0ZW5kcyBNZXNzYWdlU2VuZCB7XG4gICAgdGltZTogbnVtYmVyO1xuXG4gICAgY29uc3RydWN0b3IodGltZTogbnVtYmVyKSB7XG4gICAgICAgIHN1cGVyKCk7XG4gICAgICAgIHRoaXMudHlwZSA9IE1lc3NhZ2VTZW5kVHlwZXMuUE9ORztcbiAgICAgICAgdGhpcy50aW1lID0gdGltZTtcbiAgICB9XG59XG5cbi8qKlxuICogIFdlYiBSVEMgT2ZmZXIgbWVzc2FnZSB3cmFwcGVyXG4gKi9cbmV4cG9ydCBjbGFzcyBNZXNzYWdlV2ViUlRDT2ZmZXIgZXh0ZW5kcyBNZXNzYWdlU2VuZCB7XG4gICAgc2RwOiBzdHJpbmc7XG5cbiAgICAvKipcbiAgICAgKiBAcGFyYW0gb2ZmZXIgLSBHZW5lcmF0ZWQgV2ViIFJUQyBPZmZlclxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKG9mZmVyPzogUlRDU2Vzc2lvbkRlc2NyaXB0aW9uSW5pdCkge1xuICAgICAgICBzdXBlcigpO1xuICAgICAgICB0aGlzLnR5cGUgPSBNZXNzYWdlU2VuZFR5cGVzLk9GRkVSO1xuXG4gICAgICAgIGlmIChvZmZlcikge1xuICAgICAgICAgICAgdGhpcy50eXBlID0gb2ZmZXIudHlwZSBhcyBNZXNzYWdlU2VuZFR5cGVzO1xuICAgICAgICAgICAgdGhpcy5zZHAgPSBvZmZlci5zZHA7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbi8qKlxuICogIFdlYiBSVEMgQW5zd2VyIG1lc3NhZ2Ugd3JhcHBlclxuICovXG5leHBvcnQgY2xhc3MgTWVzc2FnZVdlYlJUQ0Fuc3dlciBleHRlbmRzIE1lc3NhZ2VTZW5kIHtcbiAgICBzZHA6IHN0cmluZztcblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSBhbnN3ZXIgLSBHZW5lcmF0ZWQgV2ViIFJUQyBPZmZlclxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKGFuc3dlcj86IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbkluaXQpIHtcbiAgICAgICAgc3VwZXIoKTtcbiAgICAgICAgdGhpcy50eXBlID0gTWVzc2FnZVNlbmRUeXBlcy5BTlNXRVI7XG5cbiAgICAgICAgaWYgKGFuc3dlcikge1xuICAgICAgICAgICAgdGhpcy50eXBlID0gYW5zd2VyLnR5cGUgYXMgTWVzc2FnZVNlbmRUeXBlcztcbiAgICAgICAgICAgIHRoaXMuc2RwID0gYW5zd2VyLnNkcDtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuLyoqXG4gKiAgV2ViIFJUQyBEYXRhIGNoYW5uZWwgcmVxdWVzdCBtZXNzYWdlIHdyYXBwZXJcbiAqL1xuZXhwb3J0IGNsYXNzIE1lc3NhZ2VXZWJSVENEYXRhY2hhbm5lbFJlcXVlc3QgZXh0ZW5kcyBNZXNzYWdlU2VuZCB7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKCk7XG4gICAgICAgIHRoaXMudHlwZSA9IE1lc3NhZ2VTZW5kVHlwZXMuREFUQUNIQU5ORUxSRVFVRVNUO1xuICAgIH1cbn1cblxuLyoqXG4gKiAgV2ViIFJUQyBTRlUgRGF0YSBjaGFubmVsIHJlYWR5IG1lc3NhZ2Ugd3JhcHBlclxuICovXG5leHBvcnQgY2xhc3MgTWVzc2FnZVNGVVJlY3ZEYXRhQ2hhbm5lbFJlYWR5IGV4dGVuZHMgTWVzc2FnZVNlbmQge1xuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlcigpO1xuICAgICAgICB0aGlzLnR5cGUgPSBNZXNzYWdlU2VuZFR5cGVzLlNGVVJFQ1ZEQVRBQ0hBTk5FTFJFQURZO1xuICAgIH1cbn1cblxuLyoqXG4gKiBSVEMgSWNlIENhbmRpZGF0ZSBXcmFwcGVyXG4gKi9cbmV4cG9ydCBjbGFzcyBNZXNzYWdlSWNlQ2FuZGlkYXRlIGltcGxlbWVudHMgU2VuZCB7XG4gICAgY2FuZGlkYXRlOiBSVENJY2VDYW5kaWRhdGU7XG4gICAgdHlwZTogTWVzc2FnZVNlbmRUeXBlcztcblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSBjYW5kaWRhdGUgLSBSVEMgSWNlIENhbmRpZGF0ZVxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKGNhbmRpZGF0ZTogUlRDSWNlQ2FuZGlkYXRlKSB7XG4gICAgICAgIHRoaXMudHlwZSA9IE1lc3NhZ2VTZW5kVHlwZXMuSUNFX0NBTkRJREFURTtcbiAgICAgICAgdGhpcy5jYW5kaWRhdGUgPSBjYW5kaWRhdGU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVHVybnMgdGhlIHdyYXBwZXIgaW50byBhIEpTT04gU3RyaW5nXG4gICAgICogQHJldHVybnMgLSBKU09OIFN0cmluZyBvZiB0aGUgTWVzc2FnZSB0byBzZW5kXG4gICAgICovXG4gICAgcGF5bG9hZCgpIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAnU2VuZGluZyA9PiBcXG4nICsgSlNPTi5zdHJpbmdpZnkodGhpcywgdW5kZWZpbmVkLCA0KSxcbiAgICAgICAgICAgIDZcbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHRoaXMpO1xuICAgIH1cbn1cbiIsIi8vIENvcHlyaWdodCBFcGljIEdhbWVzLCBJbmMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG5cbmltcG9ydCB7IExvZ2dlciB9IGZyb20gJy4uL0xvZ2dlci9Mb2dnZXInO1xuaW1wb3J0IHsgV2ViU29ja2V0Q29udHJvbGxlciB9IGZyb20gJy4vV2ViU29ja2V0Q29udHJvbGxlcic7XG5pbXBvcnQge1xuICAgIE1lc3NhZ2VSZWN2VHlwZXMsXG4gICAgTWVzc2FnZUNvbmZpZyxcbiAgICBNZXNzYWdlU3RyZWFtZXJMaXN0LFxuICAgIE1lc3NhZ2VQbGF5ZXJDb3VudCxcbiAgICBNZXNzYWdlQW5zd2VyLFxuICAgIE1lc3NhZ2VPZmZlcixcbiAgICBNZXNzYWdlSWNlQ2FuZGlkYXRlLFxuICAgIE1lc3NhZ2VQZWVyRGF0YUNoYW5uZWxzXG59IGZyb20gJy4vTWVzc2FnZVJlY2VpdmUnO1xuaW1wb3J0IHsgTWVzc2FnZVBvbmcgfSBmcm9tICcuL01lc3NhZ2VTZW5kJztcblxuLyoqXG4gKiBTaWduYWxsaW5nIHByb3RvY29sIGZvciBoYW5kbGluZyBtZXNzYWdlcyBmcm9tIHRoZSBzaWduYWxsaW5nIHNlcnZlci5cbiAqL1xuZXhwb3J0IGNsYXNzIFNpZ25hbGxpbmdQcm90b2NvbCB7XG4gICAgcHJpdmF0ZSBGcm9tVUVNZXNzYWdlSGFuZGxlcnM6IE1hcDxzdHJpbmcsIChwYXlsb2FkOiBzdHJpbmcpID0+IHZvaWQ+O1xuXG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHRoaXMuRnJvbVVFTWVzc2FnZUhhbmRsZXJzID0gbmV3IE1hcDxcbiAgICAgICAgICAgIHN0cmluZyxcbiAgICAgICAgICAgIChwYXlsb2FkOiBzdHJpbmcpID0+IHZvaWRcbiAgICAgICAgPigpO1xuICAgIH1cblxuICAgIGFkZE1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICBtZXNzYWdlSWQ6IHN0cmluZyxcbiAgICAgICAgbWVzc2FnZUhhbmRsZXI6IChwYXlsb2FkOiBzdHJpbmcpID0+IHZvaWRcbiAgICApIHtcbiAgICAgICAgdGhpcy5Gcm9tVUVNZXNzYWdlSGFuZGxlcnMuc2V0KG1lc3NhZ2VJZCwgbWVzc2FnZUhhbmRsZXIpO1xuICAgIH1cblxuICAgIGhhbmRsZU1lc3NhZ2UobWVzc2FnZUlkOiBzdHJpbmcsIG1lc3NhZ2VEYXRhOiBzdHJpbmcpIHtcbiAgICAgICAgaWYgKHRoaXMuRnJvbVVFTWVzc2FnZUhhbmRsZXJzLmhhcyhtZXNzYWdlSWQpKSB7XG4gICAgICAgICAgICB0aGlzLkZyb21VRU1lc3NhZ2VIYW5kbGVycy5nZXQobWVzc2FnZUlkKShtZXNzYWdlRGF0YSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBMb2dnZXIuRXJyb3IoXG4gICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICBgTWVzc2FnZSB0eXBlIG9mICR7bWVzc2FnZUlkfSBkb2VzIG5vdCBoYXZlIGEgbWVzc2FnZSBoYW5kbGVyIHJlZ2lzdGVyZWQgb24gdGhlIGZyb250ZW5kIC0gaWdub3JpbmcgbWVzc2FnZS5gXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0dXAgYW55IGRlZmF1bHQgc2lnbmFsbGluZyBtZXNzYWdlIGhhbmRsaW5nLCB0aGVzZSBjYW4gYmUgb3ZlcnJpZGRlbiBvciBhZGRpdGlvbmFsIGhhbmRsZXJzIGFkZGVkIHdpdGggYGFkZE1lc3NhZ2VIYW5kbGVyYC5cbiAgICAgKiBAcGFyYW0gd2Vic29ja2V0Q29udHJvbGxlciBUaGUgY29udHJvbGxlciB0byBzZXR1cCB0aGVzZSBoYW5kbGVycyBvbi5cbiAgICAgKi9cbiAgICBzdGF0aWMgc2V0dXBEZWZhdWx0SGFuZGxlcnMod2Vic29ja2V0Q29udHJvbGxlcjogV2ViU29ja2V0Q29udHJvbGxlcikge1xuICAgICAgICAvLyBQSU5HXG4gICAgICAgIHdlYnNvY2tldENvbnRyb2xsZXIuc2lnbmFsbGluZ1Byb3RvY29sLmFkZE1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZVJlY3ZUeXBlcy5QSU5HLFxuICAgICAgICAgICAgKHBpbmdQYXlsb2FkOiBzdHJpbmcpID0+IHtcbiAgICAgICAgICAgICAgICAvLyBzZW5kIG91ciBwb25nIHBheWxvYWQgYmFjayB0byB0aGUgc2lnbmFsbGluZyBzZXJ2ZXJcbiAgICAgICAgICAgICAgICBjb25zdCBwb25nUGF5bG9hZCA9IG5ldyBNZXNzYWdlUG9uZyhcbiAgICAgICAgICAgICAgICAgICAgbmV3IERhdGUoKS5nZXRUaW1lKClcbiAgICAgICAgICAgICAgICApLnBheWxvYWQoKTtcbiAgICAgICAgICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgICAgICBNZXNzYWdlUmVjdlR5cGVzLlBJTkcgKyAnOiAnICsgcGluZ1BheWxvYWQsXG4gICAgICAgICAgICAgICAgICAgIDZcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIHdlYnNvY2tldENvbnRyb2xsZXIud2ViU29ja2V0LnNlbmQocG9uZ1BheWxvYWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuXG4gICAgICAgIC8vIENPTkZJR1xuICAgICAgICB3ZWJzb2NrZXRDb250cm9sbGVyLnNpZ25hbGxpbmdQcm90b2NvbC5hZGRNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VSZWN2VHlwZXMuQ09ORklHLFxuICAgICAgICAgICAgKGNvbmZpZ1BheWxvYWQ6IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgICAgIExvZ2dlci5Mb2coTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSwgTWVzc2FnZVJlY3ZUeXBlcy5DT05GSUcsIDYpO1xuICAgICAgICAgICAgICAgIGNvbnN0IGNvbmZpZzogTWVzc2FnZUNvbmZpZyA9IEpTT04ucGFyc2UoY29uZmlnUGF5bG9hZCk7XG4gICAgICAgICAgICAgICAgd2Vic29ja2V0Q29udHJvbGxlci5vbkNvbmZpZyhjb25maWcpO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuXG4gICAgICAgIC8vIFNUUkVBTUVSX0xJU1RcbiAgICAgICAgd2Vic29ja2V0Q29udHJvbGxlci5zaWduYWxsaW5nUHJvdG9jb2wuYWRkTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlUmVjdlR5cGVzLlNUUkVBTUVSX0xJU1QsXG4gICAgICAgICAgICAobGlzdFBheWxvYWQ6IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgICAgIE1lc3NhZ2VSZWN2VHlwZXMuU1RSRUFNRVJfTElTVCxcbiAgICAgICAgICAgICAgICAgICAgNlxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgY29uc3Qgc3RyZWFtZXJMaXN0OiBNZXNzYWdlU3RyZWFtZXJMaXN0ID1cbiAgICAgICAgICAgICAgICAgICAgSlNPTi5wYXJzZShsaXN0UGF5bG9hZCk7XG4gICAgICAgICAgICAgICAgd2Vic29ja2V0Q29udHJvbGxlci5vblN0cmVhbWVyTGlzdChzdHJlYW1lckxpc3QpO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuXG4gICAgICAgIC8vIFBMQVlFUl9DT1VOVFxuICAgICAgICB3ZWJzb2NrZXRDb250cm9sbGVyLnNpZ25hbGxpbmdQcm90b2NvbC5hZGRNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VSZWN2VHlwZXMuUExBWUVSX0NPVU5ULFxuICAgICAgICAgICAgKHBsYXllckNvdW50UGF5bG9hZDogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICAgICAgTWVzc2FnZVJlY3ZUeXBlcy5QTEFZRVJfQ09VTlQsXG4gICAgICAgICAgICAgICAgICAgIDZcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIGNvbnN0IHBsYXllckNvdW50OiBNZXNzYWdlUGxheWVyQ291bnQgPVxuICAgICAgICAgICAgICAgICAgICBKU09OLnBhcnNlKHBsYXllckNvdW50UGF5bG9hZCk7XG4gICAgICAgICAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICAgICAgJ1BsYXllciBDb3VudDogJyArIHBsYXllckNvdW50LmNvdW50LFxuICAgICAgICAgICAgICAgICAgICA2XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB3ZWJzb2NrZXRDb250cm9sbGVyLm9uUGxheWVyQ291bnQocGxheWVyQ291bnQpXG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gQU5TV0VSXG4gICAgICAgIHdlYnNvY2tldENvbnRyb2xsZXIuc2lnbmFsbGluZ1Byb3RvY29sLmFkZE1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZVJlY3ZUeXBlcy5BTlNXRVIsXG4gICAgICAgICAgICAoYW5zd2VyUGF5bG9hZDogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gc2VuZCBvdXIgcG9uZyBwYXlsb2FkIGJhY2sgdG8gdGhlIHNpZ25hbGxpbmcgc2VydmVyXG4gICAgICAgICAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCBNZXNzYWdlUmVjdlR5cGVzLkFOU1dFUiwgNik7XG4gICAgICAgICAgICAgICAgY29uc3QgYW5zd2VyOiBNZXNzYWdlQW5zd2VyID0gSlNPTi5wYXJzZShhbnN3ZXJQYXlsb2FkKTtcbiAgICAgICAgICAgICAgICB3ZWJzb2NrZXRDb250cm9sbGVyLm9uV2ViUnRjQW5zd2VyKGFuc3dlcik7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gT0ZGRVJcbiAgICAgICAgd2Vic29ja2V0Q29udHJvbGxlci5zaWduYWxsaW5nUHJvdG9jb2wuYWRkTWVzc2FnZUhhbmRsZXIoXG4gICAgICAgICAgICBNZXNzYWdlUmVjdlR5cGVzLk9GRkVSLFxuICAgICAgICAgICAgKG9mZmVyUGF5bG9hZDogc3RyaW5nKSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gc2VuZCBvdXIgcG9uZyBwYXlsb2FkIGJhY2sgdG8gdGhlIHNpZ25hbGxpbmcgc2VydmVyXG4gICAgICAgICAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCBNZXNzYWdlUmVjdlR5cGVzLk9GRkVSLCA2KTtcbiAgICAgICAgICAgICAgICBjb25zdCBvZmZlcjogTWVzc2FnZU9mZmVyID0gSlNPTi5wYXJzZShvZmZlclBheWxvYWQpO1xuICAgICAgICAgICAgICAgIHdlYnNvY2tldENvbnRyb2xsZXIub25XZWJSdGNPZmZlcihvZmZlcik7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gSUNFIENBTkRJREFURVxuICAgICAgICB3ZWJzb2NrZXRDb250cm9sbGVyLnNpZ25hbGxpbmdQcm90b2NvbC5hZGRNZXNzYWdlSGFuZGxlcihcbiAgICAgICAgICAgIE1lc3NhZ2VSZWN2VHlwZXMuSUNFX0NBTkRJREFURSxcbiAgICAgICAgICAgIChpY2VDYW5kaWRhdGVQYXlsb2FkOiBzdHJpbmcpID0+IHtcbiAgICAgICAgICAgICAgICAvLyBzZW5kIG91ciBwb25nIHBheWxvYWQgYmFjayB0byB0aGUgc2lnbmFsbGluZyBzZXJ2ZXJcbiAgICAgICAgICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgICAgICAgICBMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLFxuICAgICAgICAgICAgICAgICAgICBNZXNzYWdlUmVjdlR5cGVzLklDRV9DQU5ESURBVEUsXG4gICAgICAgICAgICAgICAgICAgIDZcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIGNvbnN0IGljZUNhbmRpZGF0ZTogTWVzc2FnZUljZUNhbmRpZGF0ZSA9XG4gICAgICAgICAgICAgICAgICAgIEpTT04ucGFyc2UoaWNlQ2FuZGlkYXRlUGF5bG9hZCk7XG4gICAgICAgICAgICAgICAgd2Vic29ja2V0Q29udHJvbGxlci5vbkljZUNhbmRpZGF0ZShpY2VDYW5kaWRhdGUuY2FuZGlkYXRlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcblxuICAgICAgICAvLyBXQVJOSU5HXG4gICAgICAgIHdlYnNvY2tldENvbnRyb2xsZXIuc2lnbmFsbGluZ1Byb3RvY29sLmFkZE1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZVJlY3ZUeXBlcy5XQVJOSU5HLFxuICAgICAgICAgICAgKHdhcm5pbmdQYXlsb2FkOiBzdHJpbmcpID0+IHtcbiAgICAgICAgICAgICAgICBMb2dnZXIuV2FybmluZyhcbiAgICAgICAgICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICAgICAgICAgYFdhcm5pbmcgcmVjZWl2ZWQ6ICR7d2FybmluZ1BheWxvYWR9YFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gUEVFUiBEQVRBIENIQU5ORUxTXG4gICAgICAgIHdlYnNvY2tldENvbnRyb2xsZXIuc2lnbmFsbGluZ1Byb3RvY29sLmFkZE1lc3NhZ2VIYW5kbGVyKFxuICAgICAgICAgICAgTWVzc2FnZVJlY3ZUeXBlcy5QRUVSX0RBVEFfQ0hBTk5FTFMsXG4gICAgICAgICAgICAocGVlckRhdGFDaGFubmVsc1BheWxvYWQ6IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgICAgIExvZ2dlci5Mb2coXG4gICAgICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgICAgIE1lc3NhZ2VSZWN2VHlwZXMuUEVFUl9EQVRBX0NIQU5ORUxTLFxuICAgICAgICAgICAgICAgICAgICA2XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBjb25zdCBwZWVyRGF0YUNoYW5uZWxzOiBNZXNzYWdlUGVlckRhdGFDaGFubmVscyA9IEpTT04ucGFyc2UoXG4gICAgICAgICAgICAgICAgICAgIHBlZXJEYXRhQ2hhbm5lbHNQYXlsb2FkXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB3ZWJzb2NrZXRDb250cm9sbGVyLm9uV2ViUnRjUGVlckRhdGFDaGFubmVscyhwZWVyRGF0YUNoYW5uZWxzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICB9XG59XG4iLCIvLyBDb3B5cmlnaHQgRXBpYyBHYW1lcywgSW5jLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuXG5pbXBvcnQgeyBMb2dnZXIgfSBmcm9tICcuLi9Mb2dnZXIvTG9nZ2VyJztcbmltcG9ydCAqIGFzIE1lc3NhZ2VSZWNlaXZlIGZyb20gJy4vTWVzc2FnZVJlY2VpdmUnO1xuaW1wb3J0ICogYXMgTWVzc2FnZVNlbmQgZnJvbSAnLi9NZXNzYWdlU2VuZCc7XG5pbXBvcnQgeyBTaWduYWxsaW5nUHJvdG9jb2wgfSBmcm9tICcuL1NpZ25hbGxpbmdQcm90b2NvbCc7XG5cbi8vIGRlY2xhcmUgdGhlIG5ldyBtZXRob2QgZm9yIHRoZSB3ZWJzb2NrZXQgaW50ZXJmYWNlXG5kZWNsYXJlIGdsb2JhbCB7XG4gICAgaW50ZXJmYWNlIFdlYlNvY2tldCB7XG4gICAgICAgIG9ubWVzc2FnZWJpbmFyeT8oZXZlbnQ/OiBNZXNzYWdlRXZlbnQpOiB2b2lkO1xuICAgIH1cbn1cblxuLyoqXG4gKiBUaGUgY29udHJvbGxlciBmb3IgdGhlIFdlYlNvY2tldCBhbmQgYWxsIGFzc29jaWF0ZWQgbWV0aG9kc1xuICovXG5leHBvcnQgY2xhc3MgV2ViU29ja2V0Q29udHJvbGxlciB7XG4gICAgV1NfT1BFTl9TVEFURSA9IDE7XG4gICAgd2ViU29ja2V0OiBXZWJTb2NrZXQ7XG4gICAgb25PcGVuOiBFdmVudFRhcmdldDtcbiAgICBvbkNsb3NlOiBFdmVudFRhcmdldDtcbiAgICBzaWduYWxsaW5nUHJvdG9jb2w6IFNpZ25hbGxpbmdQcm90b2NvbDtcblxuICAgIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICB0aGlzLm9uT3BlbiA9IG5ldyBFdmVudFRhcmdldCgpO1xuICAgICAgICB0aGlzLm9uQ2xvc2UgPSBuZXcgRXZlbnRUYXJnZXQoKTtcbiAgICAgICAgdGhpcy5zaWduYWxsaW5nUHJvdG9jb2wgPSBuZXcgU2lnbmFsbGluZ1Byb3RvY29sKCk7XG4gICAgICAgIFNpZ25hbGxpbmdQcm90b2NvbC5zZXR1cERlZmF1bHRIYW5kbGVycyh0aGlzKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDb25uZWN0IHRvIHRoZSBzaWduYWxpbmcgc2VydmVyXG4gICAgICogQHBhcmFtIGNvbm5lY3Rpb25VUkwgLSBUaGUgQWRkcmVzcyBvZiB0aGUgc2lnbmFsaW5nIHNlcnZlclxuICAgICAqIEByZXR1cm5zIC0gSWYgdGhlcmUgaXMgYSBjb25uZWN0aW9uXG4gICAgICovXG4gICAgY29ubmVjdChjb25uZWN0aW9uVVJMOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgICAgTG9nZ2VyLkxvZyhMb2dnZXIuR2V0U3RhY2tUcmFjZSgpLCBjb25uZWN0aW9uVVJMLCA2KTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHRoaXMud2ViU29ja2V0ID0gbmV3IFdlYlNvY2tldChjb25uZWN0aW9uVVJMKTtcbiAgICAgICAgICAgIHRoaXMud2ViU29ja2V0Lm9ub3BlbiA9IChldmVudCkgPT4gdGhpcy5oYW5kbGVPbk9wZW4oZXZlbnQpO1xuICAgICAgICAgICAgdGhpcy53ZWJTb2NrZXQub25lcnJvciA9ICgpID0+IHRoaXMuaGFuZGxlT25FcnJvcigpO1xuICAgICAgICAgICAgdGhpcy53ZWJTb2NrZXQub25jbG9zZSA9IChldmVudCkgPT4gdGhpcy5oYW5kbGVPbkNsb3NlKGV2ZW50KTtcbiAgICAgICAgICAgIHRoaXMud2ViU29ja2V0Lm9ubWVzc2FnZSA9IChldmVudCkgPT4gdGhpcy5oYW5kbGVPbk1lc3NhZ2UoZXZlbnQpO1xuICAgICAgICAgICAgdGhpcy53ZWJTb2NrZXQub25tZXNzYWdlYmluYXJ5ID0gKGV2ZW50KSA9PlxuICAgICAgICAgICAgICAgIHRoaXMuaGFuZGxlT25NZXNzYWdlQmluYXJ5KGV2ZW50KTtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgTG9nZ2VyLkVycm9yKGVycm9yLCBlcnJvcik7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGVzIHdoYXQgaGFwcGVucyB3aGVuIGEgbWVzc2FnZSBpcyByZWNlaXZlZCBpbiBiaW5hcnkgZm9ybVxuICAgICAqIEBwYXJhbSBldmVudCAtIE1lc3NhZ2UgUmVjZWl2ZWRcbiAgICAgKi9cbiAgICBoYW5kbGVPbk1lc3NhZ2VCaW5hcnkoZXZlbnQ6IE1lc3NhZ2VFdmVudCkge1xuICAgICAgICAvLyBpZiB0aGUgZXZlbnQgaXMgZW1wdHkgcmV0dXJuXG4gICAgICAgIGlmICghZXZlbnQgfHwgIWV2ZW50LmRhdGEpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGhhbmRsZSB0aGUgYmluYXJ5IGFuZCB0aGVuIGhhbmRsZSB0aGUgbWVzc2FnZVxuICAgICAgICBldmVudC5kYXRhXG4gICAgICAgICAgICAudGV4dCgpXG4gICAgICAgICAgICAudGhlbigobWVzc2FnZVN0cmluZzogdW5rbm93bikgPT4ge1xuICAgICAgICAgICAgICAgIC8vIGJ1aWxkIGEgbmV3IG1lc3NhZ2VcbiAgICAgICAgICAgICAgICBjb25zdCBjb25zdHJ1Y3RlZE1lc3NhZ2UgPSBuZXcgTWVzc2FnZUV2ZW50KFxuICAgICAgICAgICAgICAgICAgICAnbWVzc2FnZUZyb21CaW5hcnknLFxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBkYXRhOiBtZXNzYWdlU3RyaW5nXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgICAgLy8gc2VuZCB0aGUgbmV3IHN0cmluZ2lmaWVkIGV2ZW50IGJhY2sgaW50byBgb25tZXNzYWdlYFxuICAgICAgICAgICAgICAgIHRoaXMuaGFuZGxlT25NZXNzYWdlKGNvbnN0cnVjdGVkTWVzc2FnZSk7XG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgLmNhdGNoKChlcnJvcjogRXJyb3IpID0+IHtcbiAgICAgICAgICAgICAgICBMb2dnZXIuRXJyb3IoXG4gICAgICAgICAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAgICAgICAgIGBGYWlsZWQgdG8gcGFyc2UgYmluYXJ5IGJsb2IgZnJvbSB3ZWJzb2NrZXQsIHJlYXNvbjogJHtlcnJvcn1gXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEhhbmRsZXMgd2hhdCBoYXBwZW5zIHdoZW4gYSBtZXNzYWdlIGlzIHJlY2VpdmVkXG4gICAgICogQHBhcmFtIGV2ZW50IC0gTWVzc2FnZSBSZWNlaXZlZFxuICAgICAqL1xuICAgIGhhbmRsZU9uTWVzc2FnZShldmVudDogTWVzc2FnZUV2ZW50KSB7XG4gICAgICAgIC8vIENoZWNrIGlmIHdlYnNvY2tldCBtZXNzYWdlIGlzIGJpbmFyeSwgaWYgc28sIHN0cmluZ2lmeSBpdC5cbiAgICAgICAgaWYgKGV2ZW50LmRhdGEgJiYgZXZlbnQuZGF0YSBpbnN0YW5jZW9mIEJsb2IpIHtcbiAgICAgICAgICAgIHRoaXMuaGFuZGxlT25NZXNzYWdlQmluYXJ5KGV2ZW50KTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IG1lc3NhZ2U6IE1lc3NhZ2VSZWNlaXZlLk1lc3NhZ2VSZWN2ID0gSlNPTi5wYXJzZShldmVudC5kYXRhKTtcbiAgICAgICAgTG9nZ2VyLkxvZyhcbiAgICAgICAgICAgIExvZ2dlci5HZXRTdGFja1RyYWNlKCksXG4gICAgICAgICAgICAncmVjZWl2ZWQgPT4gXFxuJyArXG4gICAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoSlNPTi5wYXJzZShldmVudC5kYXRhKSwgdW5kZWZpbmVkLCA0KSxcbiAgICAgICAgICAgIDZcbiAgICAgICAgKTtcblxuICAgICAgICAvLyBTZW5kIHRvIG91ciBzaWduYWxsaW5nIHByb3RvY29sIHRvIGhhbmRsZSB0aGUgaW5jb21pbmcgbWVzc2FnZVxuICAgICAgICB0aGlzLnNpZ25hbGxpbmdQcm90b2NvbC5oYW5kbGVNZXNzYWdlKG1lc3NhZ2UudHlwZSwgZXZlbnQuZGF0YSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSGFuZGxlcyB3aGVuIHRoZSBXZWJzb2NrZXQgaXMgb3BlbmVkXG4gICAgICogQHBhcmFtIGV2ZW50IC0gTm90IFVzZWRcbiAgICAgKi9cbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gICAgaGFuZGxlT25PcGVuKGV2ZW50OiBFdmVudCkge1xuICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICdDb25uZWN0ZWQgdG8gdGhlIHNpZ25hbGxpbmcgc2VydmVyIHZpYSBXZWJTb2NrZXQnLFxuICAgICAgICAgICAgNlxuICAgICAgICApO1xuICAgICAgICB0aGlzLm9uT3Blbi5kaXNwYXRjaEV2ZW50KG5ldyBFdmVudCgnb3BlbicpKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBIYW5kbGVzIHdoZW4gdGhlcmUgaXMgYW4gZXJyb3Igb24gdGhlIHdlYnNvY2tldFxuICAgICAqIEBwYXJhbSBldmVudCAtIEVycm9yIFBheWxvYWRcbiAgICAgKi9cbiAgICBoYW5kbGVPbkVycm9yKCkge1xuICAgICAgICBMb2dnZXIuRXJyb3IoTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSwgJ1dlYlNvY2tldCBlcnJvcicpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEhhbmRsZXMgd2hlbiB0aGUgV2Vic29ja2V0IGlzIGNsb3NlZFxuICAgICAqIEBwYXJhbSBldmVudCAtIENsb3NlIEV2ZW50XG4gICAgICovXG4gICAgaGFuZGxlT25DbG9zZShldmVudDogQ2xvc2VFdmVudCkge1xuICAgICAgICBMb2dnZXIuTG9nKFxuICAgICAgICAgICAgTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSxcbiAgICAgICAgICAgICdEaXNjb25uZWN0ZWQgdG8gdGhlIHNpZ25hbGxpbmcgc2VydmVyIHZpYSBXZWJTb2NrZXQ6ICcgK1xuICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGV2ZW50LmNvZGUpICtcbiAgICAgICAgICAgICAgICAnIC0gJyArXG4gICAgICAgICAgICAgICAgZXZlbnQucmVhc29uXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMub25DbG9zZS5kaXNwYXRjaEV2ZW50KG5ldyBDdXN0b21FdmVudCgnY2xvc2UnLCB7ICdkZXRhaWwnOiBldmVudCB9KSk7XG4gICAgfVxuXG4gICAgcmVxdWVzdFN0cmVhbWVyTGlzdCgpIHtcbiAgICAgICAgY29uc3QgcGF5bG9hZCA9IG5ldyBNZXNzYWdlU2VuZC5NZXNzYWdlTGlzdFN0cmVhbWVycygpO1xuICAgICAgICB0aGlzLndlYlNvY2tldC5zZW5kKHBheWxvYWQucGF5bG9hZCgpKTtcbiAgICB9XG5cbiAgICBzZW5kU3Vic2NyaWJlKHN0cmVhbWVyaWQ6IHN0cmluZykge1xuICAgICAgICBjb25zdCBwYXlsb2FkID0gbmV3IE1lc3NhZ2VTZW5kLk1lc3NhZ2VTdWJzY3JpYmUoc3RyZWFtZXJpZCk7XG4gICAgICAgIHRoaXMud2ViU29ja2V0LnNlbmQocGF5bG9hZC5wYXlsb2FkKCkpO1xuICAgIH1cblxuICAgIHNlbmRVbnN1YnNjcmliZSgpIHtcbiAgICAgICAgY29uc3QgcGF5bG9hZCA9IG5ldyBNZXNzYWdlU2VuZC5NZXNzYWdlVW5zdWJzY3JpYmUoKTtcbiAgICAgICAgdGhpcy53ZWJTb2NrZXQuc2VuZChwYXlsb2FkLnBheWxvYWQoKSk7XG4gICAgfVxuXG4gICAgc2VuZFdlYlJ0Y09mZmVyKG9mZmVyOiBSVENTZXNzaW9uRGVzY3JpcHRpb25Jbml0KSB7XG4gICAgICAgIGNvbnN0IHBheWxvYWQgPSBuZXcgTWVzc2FnZVNlbmQuTWVzc2FnZVdlYlJUQ09mZmVyKG9mZmVyKTtcbiAgICAgICAgdGhpcy53ZWJTb2NrZXQuc2VuZChwYXlsb2FkLnBheWxvYWQoKSk7XG4gICAgfVxuXG4gICAgc2VuZFdlYlJ0Y0Fuc3dlcihhbnN3ZXI6IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbkluaXQpIHtcbiAgICAgICAgY29uc3QgcGF5bG9hZCA9IG5ldyBNZXNzYWdlU2VuZC5NZXNzYWdlV2ViUlRDQW5zd2VyKGFuc3dlcik7XG4gICAgICAgIHRoaXMud2ViU29ja2V0LnNlbmQocGF5bG9hZC5wYXlsb2FkKCkpO1xuICAgIH1cblxuICAgIHNlbmRXZWJSdGNEYXRhY2hhbm5lbFJlcXVlc3QoKSB7XG4gICAgICAgIGNvbnN0IHBheWxvYWQgPSBuZXcgTWVzc2FnZVNlbmQuTWVzc2FnZVdlYlJUQ0RhdGFjaGFubmVsUmVxdWVzdCgpO1xuICAgICAgICB0aGlzLndlYlNvY2tldC5zZW5kKHBheWxvYWQucGF5bG9hZCgpKTtcbiAgICB9XG5cbiAgICBzZW5kU0ZVUmVjdkRhdGFDaGFubmVsUmVhZHkoKSB7XG4gICAgICAgIGNvbnN0IHBheWxvYWQgPSBuZXcgTWVzc2FnZVNlbmQuTWVzc2FnZVNGVVJlY3ZEYXRhQ2hhbm5lbFJlYWR5KCk7XG4gICAgICAgIHRoaXMud2ViU29ja2V0LnNlbmQocGF5bG9hZC5wYXlsb2FkKCkpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNlbmRzIGFuIFJUQyBJY2UgQ2FuZGlkYXRlIHRvIHRoZSBTZXJ2ZXJcbiAgICAgKiBAcGFyYW0gY2FuZGlkYXRlIC0gUlRDIEljZSBDYW5kaWRhdGVcbiAgICAgKi9cbiAgICBzZW5kSWNlQ2FuZGlkYXRlKGNhbmRpZGF0ZTogUlRDSWNlQ2FuZGlkYXRlKSB7XG4gICAgICAgIExvZ2dlci5Mb2coTG9nZ2VyLkdldFN0YWNrVHJhY2UoKSwgJ1NlbmRpbmcgSWNlIENhbmRpZGF0ZScpO1xuICAgICAgICBpZiAoXG4gICAgICAgICAgICB0aGlzLndlYlNvY2tldCAmJlxuICAgICAgICAgICAgdGhpcy53ZWJTb2NrZXQucmVhZHlTdGF0ZSA9PT0gdGhpcy5XU19PUEVOX1NUQVRFXG4gICAgICAgICkge1xuICAgICAgICAgICAgLy93cy5zZW5kKEpTT04uc3RyaW5naWZ5KHsgdHlwZTogJ2ljZUNhbmRpZGF0ZScsIGNhbmRpZGF0ZTogY2FuZGlkYXRlIH0pKTtcbiAgICAgICAgICAgIGNvbnN0IEljZUNhbmRpZGF0ZSA9IG5ldyBNZXNzYWdlU2VuZC5NZXNzYWdlSWNlQ2FuZGlkYXRlKGNhbmRpZGF0ZSk7XG5cbiAgICAgICAgICAgIHRoaXMud2ViU29ja2V0LnNlbmQoSWNlQ2FuZGlkYXRlLnBheWxvYWQoKSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDbG9zZXMgdGhlIFdlYnNvY2tldCBjb25uZWN0aW9uXG4gICAgICovXG4gICAgY2xvc2UoKSB7XG4gICAgICAgIHRoaXMud2ViU29ja2V0Py5jbG9zZSgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBNZXNzYWdlIENvbnRhaW5zIHRoZSBwYXlsb2FkIG9mIHRoZSBwZWVyIGNvbm5lY3Rpb24gb3B0aW9ucyB1c2VkIGZvciB0aGUgUlRDIFBlZXIgaGFuZCBzaGFrZVxuICAgICAqIEBwYXJhbSBtZXNzYWdlQ29uZmlnIC0gQ29uZmlnIE1lc3NhZ2UgcmVjZWl2ZWQgZnJvbSBoZSBzaWduYWxpbmcgc2VydmVyXG4gICAgICovXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFycywgQHR5cGVzY3JpcHQtZXNsaW50L25vLWVtcHR5LWZ1bmN0aW9uXG4gICAgb25Db25maWcobWVzc2FnZUNvbmZpZzogTWVzc2FnZVJlY2VpdmUuTWVzc2FnZUNvbmZpZykge31cblxuICAgIC8qKlxuICAgICAqIFRoZSBNZXNzYWdlIENvbnRhaW5zIHRoZSBwYXlsb2FkIG9mIHRoZSBwZWVyIGNvbm5lY3Rpb24gb3B0aW9ucyB1c2VkIGZvciB0aGUgUlRDIFBlZXIgaGFuZCBzaGFrZVxuICAgICAqIEBwYXJhbSBtZXNzYWdlQ29uZmlnIC0gQ29uZmlnIE1lc3NhZ2UgcmVjZWl2ZWQgZnJvbSBoZSBzaWduYWxpbmcgc2VydmVyXG4gICAgICovXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFycywgQHR5cGVzY3JpcHQtZXNsaW50L25vLWVtcHR5LWZ1bmN0aW9uXG4gICAgb25TdHJlYW1lckxpc3QobWVzc2FnZVN0cmVhbWVyTGlzdDogTWVzc2FnZVJlY2VpdmUuTWVzc2FnZVN0cmVhbWVyTGlzdCkge31cblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSBpY2VDYW5kaWRhdGUgLSBJY2UgQ2FuZGlkYXRlIHNlbnQgZnJvbSB0aGUgU2lnbmFsaW5nIHNlcnZlciBzZXJ2ZXIncyBSVEMgaGFuZCBzaGFrZVxuICAgICAqL1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnMsIEB0eXBlc2NyaXB0LWVzbGludC9uby1lbXB0eS1mdW5jdGlvblxuICAgIG9uSWNlQ2FuZGlkYXRlKGljZUNhbmRpZGF0ZTogUlRDSWNlQ2FuZGlkYXRlSW5pdCkge31cblxuICAgIC8qKlxuICAgICAqIEV2ZW50IGlzIGZpcmVkIHdoZW4gdGhlIHdlYnNvY2tldCByZWNlaXZlcyB0aGUgYW5zd2VyIGZvciB0aGUgUlRDIHBlZXIgQ29ubmVjdGlvblxuICAgICAqIEBwYXJhbSBtZXNzYWdlQW5zd2VyIC0gVGhlIFJUQyBBbnN3ZXIgcGF5bG9hZCBmcm9tIHRoZSBzaWduYWxpbmcgc2VydmVyXG4gICAgICovXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFycywgQHR5cGVzY3JpcHQtZXNsaW50L25vLWVtcHR5LWZ1bmN0aW9uXG4gICAgb25XZWJSdGNBbnN3ZXIobWVzc2FnZUFuc3dlcjogTWVzc2FnZVJlY2VpdmUuTWVzc2FnZUFuc3dlcikge31cblxuICAgIC8qKlxuICAgICAqIEV2ZW50IGlzIGZpcmVkIHdoZW4gdGhlIHdlYnNvY2tldCByZWNlaXZlcyB0aGUgb2ZmZXIgZm9yIHRoZSBSVEMgcGVlciBDb25uZWN0aW9uXG4gICAgICogQHBhcmFtIG1lc3NhZ2VPZmZlciAtIFRoZSBzZHAgb2ZmZXJcbiAgICAgKi9cbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzLCBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZW1wdHktZnVuY3Rpb25cbiAgICBvbldlYlJ0Y09mZmVyKG1lc3NhZ2VPZmZlcjogTWVzc2FnZVJlY2VpdmUuTWVzc2FnZU9mZmVyKSB7fVxuXG4gICAgLyoqXG4gICAgICogRXZlbnQgaXMgZmlyZWQgd2hlbiB0aGUgd2Vic29ja2V0IHJlY2VpdmVzIHRoZSBkYXRhIGNoYW5uZWxzIGZvciB0aGUgUlRDIHBlZXIgQ29ubmVjdGlvbiBmcm9tIHRoZSBTRlVcbiAgICAgKiBAcGFyYW0gbWVzc2FnZURhdGFDaGFubmVscyAtIFRoZSBkYXRhIGNoYW5uZWxzIGRldGFpbHNcbiAgICAgKi9cbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzLCBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tZW1wdHktZnVuY3Rpb25cbiAgICBvbldlYlJ0Y1BlZXJEYXRhQ2hhbm5lbHMobWVzc2FnZURhdGFDaGFubmVsczogTWVzc2FnZVJlY2VpdmUuTWVzc2FnZVBlZXJEYXRhQ2hhbm5lbHMpIHt9XG5cbiAgICAvKipcbiAgICAgKiBFdmVudCBpcyBmaXJlZCB3aGVuIHRoZSB3ZWJzb2NrZXQgcmVjZWl2ZXMgdGhlIGFuIHVwZGF0ZWQgcGxheWVyIGNvdW50IGZyb20gY2lycnVzXG4gICAgICogQHBhcmFtIE1lc3NhZ2VQbGF5ZXJDb3VudCAtIFRoZSBuZXcgcGxheWVyIGNvdW50XG4gICAgICovXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFycywgQHR5cGVzY3JpcHQtZXNsaW50L25vLWVtcHR5LWZ1bmN0aW9uXG4gICAgb25QbGF5ZXJDb3VudChwbGF5ZXJDb3VudDogTWVzc2FnZVJlY2VpdmUuTWVzc2FnZVBsYXllckNvdW50KSB7fVxufVxuIiwiLy8gQ29weXJpZ2h0IEVwaWMgR2FtZXMsIEluYy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblxuaW1wb3J0IHsgTG9nZ2VyIH0gZnJvbSAnLi4vTG9nZ2VyL0xvZ2dlcic7XG5pbXBvcnQgeyBXZWJSdGNQbGF5ZXJDb250cm9sbGVyIH0gZnJvbSAnLi4vV2ViUnRjUGxheWVyL1dlYlJ0Y1BsYXllckNvbnRyb2xsZXInO1xuaW1wb3J0IHsgV2ViR0xVdGlscyB9IGZyb20gJy4uL1V0aWwvV2ViR0xVdGlscyc7XG5pbXBvcnQgeyBDb250cm9sbGVyIH0gZnJvbSAnLi4vSW5wdXRzL0dhbWVwYWRUeXBlcyc7XG5pbXBvcnQgeyBYUkdhbWVwYWRDb250cm9sbGVyIH0gZnJvbSAnLi4vSW5wdXRzL1hSR2FtZXBhZENvbnRyb2xsZXInO1xuaW1wb3J0IHsgWHJGcmFtZUV2ZW50IH0gZnJvbSAnLi4vVXRpbC9FdmVudEVtaXR0ZXInXG5pbXBvcnQgeyBGbGFncyB9IGZyb20gJy4uL3BpeGVsc3RyZWFtaW5nZnJvbnRlbmQnO1xuXG5leHBvcnQgY2xhc3MgV2ViWFJDb250cm9sbGVyIHtcbiAgICBwcml2YXRlIHhyU2Vzc2lvbjogWFJTZXNzaW9uO1xuICAgIHByaXZhdGUgeHJSZWZTcGFjZTogWFJSZWZlcmVuY2VTcGFjZTtcbiAgICBwcml2YXRlIGdsOiBXZWJHTDJSZW5kZXJpbmdDb250ZXh0O1xuXG4gICAgcHJpdmF0ZSBwb3NpdGlvbkxvY2F0aW9uOiBudW1iZXI7XG4gICAgcHJpdmF0ZSB0ZXhjb29yZExvY2F0aW9uOiBudW1iZXI7XG4gICAgcHJpdmF0ZSByZXNvbHV0aW9uTG9jYXRpb246IFdlYkdMVW5pZm9ybUxvY2F0aW9uO1xuICAgIHByaXZhdGUgb2Zmc2V0TG9jYXRpb246IFdlYkdMVW5pZm9ybUxvY2F0aW9uO1xuXG4gICAgcHJpdmF0ZSBwb3NpdGlvbkJ1ZmZlcjogV2ViR0xCdWZmZXI7XG4gICAgcHJpdmF0ZSB0ZXhjb29yZEJ1ZmZlcjogV2ViR0xCdWZmZXI7XG5cbiAgICBwcml2YXRlIHdlYlJ0Y0NvbnRyb2xsZXI6IFdlYlJ0Y1BsYXllckNvbnRyb2xsZXI7XG4gICAgcHJpdmF0ZSB4ckdhbWVwYWRDb250cm9sbGVyOiBYUkdhbWVwYWRDb250cm9sbGVyO1xuICAgIHByaXZhdGUgeHJDb250cm9sbGVyczogQXJyYXk8Q29udHJvbGxlcj47XG5cbiAgICBvblNlc3Npb25TdGFydGVkOiBFdmVudFRhcmdldDtcbiAgICBvblNlc3Npb25FbmRlZDogRXZlbnRUYXJnZXQ7XG4gICAgb25GcmFtZTogRXZlbnRUYXJnZXQ7XG5cbiAgICBjb25zdHJ1Y3Rvcih3ZWJSdGNQbGF5ZXJDb250cm9sbGVyOiBXZWJSdGNQbGF5ZXJDb250cm9sbGVyKSB7XG4gICAgICAgIHRoaXMueHJTZXNzaW9uID0gbnVsbDtcbiAgICAgICAgdGhpcy53ZWJSdGNDb250cm9sbGVyID0gd2ViUnRjUGxheWVyQ29udHJvbGxlcjtcbiAgICAgICAgdGhpcy54ckNvbnRyb2xsZXJzID0gW107XG4gICAgICAgIHRoaXMueHJHYW1lcGFkQ29udHJvbGxlciA9IG5ldyBYUkdhbWVwYWRDb250cm9sbGVyKFxuICAgICAgICAgICAgdGhpcy53ZWJSdGNDb250cm9sbGVyLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMub25TZXNzaW9uRW5kZWQgPSBuZXcgRXZlbnRUYXJnZXQoKTtcbiAgICAgICAgdGhpcy5vblNlc3Npb25TdGFydGVkID0gbmV3IEV2ZW50VGFyZ2V0KCk7XG4gICAgICAgIHRoaXMub25GcmFtZSA9IG5ldyBFdmVudFRhcmdldCgpO1xuICAgIH1cblxuICAgIHB1YmxpYyB4ckNsaWNrZWQoKSB7XG4gICAgICAgIGlmICghdGhpcy54clNlc3Npb24pIHtcbiAgICAgICAgICAgIG5hdmlnYXRvci54clxuICAgICAgICAgICAgICAgIC5yZXF1ZXN0U2Vzc2lvbignaW1tZXJzaXZlLXZyJylcbiAgICAgICAgICAgICAgICAudGhlbigoc2Vzc2lvbjogWFJTZXNzaW9uKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMub25YclNlc3Npb25TdGFydGVkKHNlc3Npb24pO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy54clNlc3Npb24uZW5kKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBvblhyU2Vzc2lvbkVuZGVkKCkge1xuICAgICAgICBMb2dnZXIuTG9nKExvZ2dlci5HZXRTdGFja1RyYWNlKCksICdYUiBTZXNzaW9uIGVuZGVkJyk7XG4gICAgICAgIHRoaXMueHJTZXNzaW9uID0gbnVsbDtcbiAgICAgICAgdGhpcy5vblNlc3Npb25FbmRlZC5kaXNwYXRjaEV2ZW50KG5ldyBFdmVudCgneHJTZXNzaW9uRW5kZWQnKSk7XG4gICAgfVxuXG4gICAgb25YclNlc3Npb25TdGFydGVkKHNlc3Npb246IFhSU2Vzc2lvbikge1xuICAgICAgICBMb2dnZXIuTG9nKExvZ2dlci5HZXRTdGFja1RyYWNlKCksICdYUiBTZXNzaW9uIHN0YXJ0ZWQnKTtcblxuICAgICAgICB0aGlzLnhyU2Vzc2lvbiA9IHNlc3Npb247XG4gICAgICAgIHRoaXMueHJTZXNzaW9uLmFkZEV2ZW50TGlzdGVuZXIoJ2VuZCcsICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMub25YclNlc3Npb25FbmRlZCgpO1xuICAgICAgICB9KTtcblxuICAgICAgICBjb25zdCBjYW52YXMgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcbiAgICAgICAgdGhpcy5nbCA9IGNhbnZhcy5nZXRDb250ZXh0KCd3ZWJnbDInLCB7XG4gICAgICAgICAgICB4ckNvbXBhdGlibGU6IHRydWVcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy54clNlc3Npb24udXBkYXRlUmVuZGVyU3RhdGUoe1xuICAgICAgICAgICAgYmFzZUxheWVyOiBuZXcgWFJXZWJHTExheWVyKHRoaXMueHJTZXNzaW9uLCB0aGlzLmdsKVxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBzZXR1cCB2ZXJ0ZXggc2hhZGVyXG4gICAgICAgIGNvbnN0IHZlcnRleFNoYWRlciA9IHRoaXMuZ2wuY3JlYXRlU2hhZGVyKHRoaXMuZ2wuVkVSVEVYX1NIQURFUik7XG4gICAgICAgIHRoaXMuZ2wuc2hhZGVyU291cmNlKHZlcnRleFNoYWRlciwgV2ViR0xVdGlscy52ZXJ0ZXhTaGFkZXIoKSk7XG4gICAgICAgIHRoaXMuZ2wuY29tcGlsZVNoYWRlcih2ZXJ0ZXhTaGFkZXIpO1xuXG4gICAgICAgIC8vIHNldHVwIGZyYWdtZW50IHNoYWRlclxuICAgICAgICBjb25zdCBmcmFnbWVudFNoYWRlciA9IHRoaXMuZ2wuY3JlYXRlU2hhZGVyKHRoaXMuZ2wuRlJBR01FTlRfU0hBREVSKTtcbiAgICAgICAgdGhpcy5nbC5zaGFkZXJTb3VyY2UoZnJhZ21lbnRTaGFkZXIsIFdlYkdMVXRpbHMuZnJhZ21lbnRTaGFkZXIoKSk7XG4gICAgICAgIHRoaXMuZ2wuY29tcGlsZVNoYWRlcihmcmFnbWVudFNoYWRlcik7XG5cbiAgICAgICAgLy8gc2V0dXAgR0xTTCBwcm9ncmFtXG4gICAgICAgIGNvbnN0IHNoYWRlclByb2dyYW0gPSB0aGlzLmdsLmNyZWF0ZVByb2dyYW0oKTtcbiAgICAgICAgdGhpcy5nbC5hdHRhY2hTaGFkZXIoc2hhZGVyUHJvZ3JhbSwgdmVydGV4U2hhZGVyKTtcbiAgICAgICAgdGhpcy5nbC5hdHRhY2hTaGFkZXIoc2hhZGVyUHJvZ3JhbSwgZnJhZ21lbnRTaGFkZXIpO1xuICAgICAgICB0aGlzLmdsLmxpbmtQcm9ncmFtKHNoYWRlclByb2dyYW0pO1xuICAgICAgICB0aGlzLmdsLnVzZVByb2dyYW0oc2hhZGVyUHJvZ3JhbSk7XG5cbiAgICAgICAgLy8gbG9vayB1cCB3aGVyZSB2ZXJ0ZXggZGF0YSBuZWVkcyB0byBnb1xuICAgICAgICB0aGlzLnBvc2l0aW9uTG9jYXRpb24gPSB0aGlzLmdsLmdldEF0dHJpYkxvY2F0aW9uKFxuICAgICAgICAgICAgc2hhZGVyUHJvZ3JhbSxcbiAgICAgICAgICAgICdhX3Bvc2l0aW9uJ1xuICAgICAgICApO1xuICAgICAgICB0aGlzLnRleGNvb3JkTG9jYXRpb24gPSB0aGlzLmdsLmdldEF0dHJpYkxvY2F0aW9uKFxuICAgICAgICAgICAgc2hhZGVyUHJvZ3JhbSxcbiAgICAgICAgICAgICdhX3RleENvb3JkJ1xuICAgICAgICApO1xuICAgICAgICAvLyBDcmVhdGUgYSBidWZmZXIgdG8gcHV0IHRocmVlIDJkIGNsaXAgc3BhY2UgcG9pbnRzIGluXG4gICAgICAgIHRoaXMucG9zaXRpb25CdWZmZXIgPSB0aGlzLmdsLmNyZWF0ZUJ1ZmZlcigpO1xuICAgICAgICAvLyBCaW5kIGl0IHRvIEFSUkFZX0JVRkZFUiAodGhpbmsgb2YgaXQgYXMgQVJSQVlfQlVGRkVSID0gcG9zaXRpb25CdWZmZXIpXG4gICAgICAgIHRoaXMuZ2wuYmluZEJ1ZmZlcih0aGlzLmdsLkFSUkFZX0JVRkZFUiwgdGhpcy5wb3NpdGlvbkJ1ZmZlcik7XG5cbiAgICAgICAgLy8gVHVybiBvbiB0aGUgcG9zaXRpb24gYXR0cmlidXRlXG4gICAgICAgIHRoaXMuZ2wuZW5hYmxlVmVydGV4QXR0cmliQXJyYXkodGhpcy5wb3NpdGlvbkxvY2F0aW9uKTtcbiAgICAgICAgLy8gQ3JlYXRlIGEgdGV4dHVyZS5cbiAgICAgICAgY29uc3QgdGV4dHVyZSA9IHRoaXMuZ2wuY3JlYXRlVGV4dHVyZSgpO1xuICAgICAgICB0aGlzLmdsLmJpbmRUZXh0dXJlKHRoaXMuZ2wuVEVYVFVSRV8yRCwgdGV4dHVyZSk7XG4gICAgICAgIC8vIFNldCB0aGUgcGFyYW1ldGVycyBzbyB3ZSBjYW4gcmVuZGVyIGFueSBzaXplIGltYWdlLlxuICAgICAgICB0aGlzLmdsLnRleFBhcmFtZXRlcmkoXG4gICAgICAgICAgICB0aGlzLmdsLlRFWFRVUkVfMkQsXG4gICAgICAgICAgICB0aGlzLmdsLlRFWFRVUkVfV1JBUF9TLFxuICAgICAgICAgICAgdGhpcy5nbC5DTEFNUF9UT19FREdFXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuZ2wudGV4UGFyYW1ldGVyaShcbiAgICAgICAgICAgIHRoaXMuZ2wuVEVYVFVSRV8yRCxcbiAgICAgICAgICAgIHRoaXMuZ2wuVEVYVFVSRV9XUkFQX1QsXG4gICAgICAgICAgICB0aGlzLmdsLkNMQU1QX1RPX0VER0VcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5nbC50ZXhQYXJhbWV0ZXJpKFxuICAgICAgICAgICAgdGhpcy5nbC5URVhUVVJFXzJELFxuICAgICAgICAgICAgdGhpcy5nbC5URVhUVVJFX01JTl9GSUxURVIsXG4gICAgICAgICAgICB0aGlzLmdsLk5FQVJFU1RcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5nbC50ZXhQYXJhbWV0ZXJpKFxuICAgICAgICAgICAgdGhpcy5nbC5URVhUVVJFXzJELFxuICAgICAgICAgICAgdGhpcy5nbC5URVhUVVJFX01BR19GSUxURVIsXG4gICAgICAgICAgICB0aGlzLmdsLk5FQVJFU1RcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLnRleGNvb3JkQnVmZmVyID0gdGhpcy5nbC5jcmVhdGVCdWZmZXIoKTtcbiAgICAgICAgLy8gbG9va3VwIHVuaWZvcm1zXG4gICAgICAgIHRoaXMucmVzb2x1dGlvbkxvY2F0aW9uID0gdGhpcy5nbC5nZXRVbmlmb3JtTG9jYXRpb24oXG4gICAgICAgICAgICBzaGFkZXJQcm9ncmFtLFxuICAgICAgICAgICAgJ3VfcmVzb2x1dGlvbidcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5vZmZzZXRMb2NhdGlvbiA9IHRoaXMuZ2wuZ2V0VW5pZm9ybUxvY2F0aW9uKFxuICAgICAgICAgICAgc2hhZGVyUHJvZ3JhbSxcbiAgICAgICAgICAgICd1X29mZnNldCdcbiAgICAgICAgKTtcblxuICAgICAgICBzZXNzaW9uLnJlcXVlc3RSZWZlcmVuY2VTcGFjZSgnbG9jYWwnKS50aGVuKChyZWZTcGFjZSkgPT4ge1xuICAgICAgICAgICAgdGhpcy54clJlZlNwYWNlID0gcmVmU3BhY2U7XG4gICAgICAgICAgICB0aGlzLnhyU2Vzc2lvbi5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoXG4gICAgICAgICAgICAgICAgKHRpbWU6IERPTUhpZ2hSZXNUaW1lU3RhbXAsIGZyYW1lOiBYUkZyYW1lKSA9PlxuICAgICAgICAgICAgICAgICAgICB0aGlzLm9uWHJGcmFtZSh0aW1lLCBmcmFtZSlcbiAgICAgICAgICAgICk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMub25TZXNzaW9uU3RhcnRlZC5kaXNwYXRjaEV2ZW50KG5ldyBFdmVudCgneHJTZXNzaW9uU3RhcnRlZCcpKTtcbiAgICB9XG5cbiAgICBvblhyRnJhbWUodGltZTogRE9NSGlnaFJlc1RpbWVTdGFtcCwgZnJhbWU6IFhSRnJhbWUpIHtcbiAgICAgICAgY29uc3QgcG9zZSA9IGZyYW1lLmdldFZpZXdlclBvc2UodGhpcy54clJlZlNwYWNlKTtcbiAgICAgICAgaWYgKHBvc2UpIHtcbiAgICAgICAgICAgIGNvbnN0IG1hdHJpeCA9IHBvc2UudHJhbnNmb3JtLm1hdHJpeDtcbiAgICAgICAgICAgIGNvbnN0IG1hdCA9IFtdO1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCAxNjsgaSsrKSB7XG4gICAgICAgICAgICAgICAgbWF0W2ldID0gbmV3IEZsb2F0MzJBcnJheShbbWF0cml4W2ldXSlbMF07XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIHByZXR0aWVyLWlnbm9yZVxuICAgICAgICAgICAgdGhpcy53ZWJSdGNDb250cm9sbGVyLnN0cmVhbU1lc3NhZ2VDb250cm9sbGVyLnRvU3RyZWFtZXJIYW5kbGVycy5nZXQoJ1hSSE1EVHJhbnNmb3JtJykoW1xuICAgICAgICAgICAgICAgIG1hdFswXSwgbWF0WzRdLCBtYXRbOF0sIG1hdFsxMl0sXG4gICAgICAgICAgICAgICAgbWF0WzFdLCBtYXRbNV0sIG1hdFs5XSwgbWF0WzEzXSwgXG4gICAgICAgICAgICAgICAgbWF0WzJdLCBtYXRbNl0sIG1hdFsxMF0sIG1hdFsxNF0sIFxuICAgICAgICAgICAgICAgIG1hdFszXSwgbWF0WzddLCBtYXRbMTFdLCBtYXRbMTVdXG4gICAgICAgICAgICBdKTtcblxuICAgICAgICAgICAgY29uc3QgZ2xMYXllciA9IHRoaXMueHJTZXNzaW9uLnJlbmRlclN0YXRlLmJhc2VMYXllcjtcbiAgICAgICAgICAgIC8vIElmIHdlIGRvIGhhdmUgYSB2YWxpZCBwb3NlLCBiaW5kIHRoZSBXZWJHTCBsYXllcidzIGZyYW1lYnVmZmVyLFxuICAgICAgICAgICAgLy8gd2hpY2ggaXMgd2hlcmUgYW55IGNvbnRlbnQgdG8gYmUgZGlzcGxheWVkIG9uIHRoZSBYUkRldmljZSBtdXN0IGJlXG4gICAgICAgICAgICAvLyByZW5kZXJlZC5cbiAgICAgICAgICAgIHRoaXMuZ2wuYmluZEZyYW1lYnVmZmVyKHRoaXMuZ2wuRlJBTUVCVUZGRVIsIGdsTGF5ZXIuZnJhbWVidWZmZXIpO1xuXG4gICAgICAgICAgICAvLyBVcGxvYWQgdGhlIGltYWdlIGludG8gdGhlIHRleHR1cmUuIFdlYkdMIGtub3dzIGhvdyB0byBleHRyYWN0IHRoZSBjdXJyZW50IGZyYW1lIGZyb20gdGhlIHZpZGVvIGVsZW1lbnRcbiAgICAgICAgICAgIHRoaXMuZ2wudGV4SW1hZ2UyRChcbiAgICAgICAgICAgICAgICB0aGlzLmdsLlRFWFRVUkVfMkQsXG4gICAgICAgICAgICAgICAgMCxcbiAgICAgICAgICAgICAgICB0aGlzLmdsLlJHQkEsXG4gICAgICAgICAgICAgICAgdGhpcy5nbC5SR0JBLFxuICAgICAgICAgICAgICAgIHRoaXMuZ2wuVU5TSUdORURfQllURSxcbiAgICAgICAgICAgICAgICB0aGlzLndlYlJ0Y0NvbnRyb2xsZXIudmlkZW9QbGF5ZXIuZ2V0VmlkZW9FbGVtZW50KClcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICB0aGlzLnJlbmRlcih0aGlzLndlYlJ0Y0NvbnRyb2xsZXIudmlkZW9QbGF5ZXIuZ2V0VmlkZW9FbGVtZW50KCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMud2ViUnRjQ29udHJvbGxlci5jb25maWcuaXNGbGFnRW5hYmxlZChGbGFncy5YUkNvbnRyb2xsZXJJbnB1dCkpIHtcbiAgICAgICAgICAgIHRoaXMueHJTZXNzaW9uLmlucHV0U291cmNlcy5mb3JFYWNoKFxuICAgICAgICAgICAgICAgIChzb3VyY2U6IFhSSW5wdXRTb3VyY2UsIGluZGV4OiBudW1iZXIsIGFycmF5OiBYUklucHV0U291cmNlW10pID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy54ckdhbWVwYWRDb250cm9sbGVyLnVwZGF0ZVN0YXR1cyhcbiAgICAgICAgICAgICAgICAgICAgICAgIHNvdXJjZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGZyYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy54clJlZlNwYWNlXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB0aGlzXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy54clNlc3Npb24ucmVxdWVzdEFuaW1hdGlvbkZyYW1lKFxuICAgICAgICAgICAgKHRpbWU6IERPTUhpZ2hSZXNUaW1lU3RhbXAsIGZyYW1lOiBYUkZyYW1lKSA9PlxuICAgICAgICAgICAgICAgIHRoaXMub25YckZyYW1lKHRpbWUsIGZyYW1lKVxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMub25GcmFtZS5kaXNwYXRjaEV2ZW50KG5ldyBYckZyYW1lRXZlbnQoe1xuICAgICAgICAgICAgdGltZSxcbiAgICAgICAgICAgIGZyYW1lXG4gICAgICAgIH0pKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHJlbmRlcih2aWRlb0VsZW1lbnQ6IEhUTUxWaWRlb0VsZW1lbnQpIHtcbiAgICAgICAgaWYgKCF0aGlzLmdsKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBnbExheWVyID0gdGhpcy54clNlc3Npb24ucmVuZGVyU3RhdGUuYmFzZUxheWVyO1xuICAgICAgICB0aGlzLmdsLnZpZXdwb3J0KFxuICAgICAgICAgICAgMCxcbiAgICAgICAgICAgIDAsXG4gICAgICAgICAgICBnbExheWVyLmZyYW1lYnVmZmVyV2lkdGgsXG4gICAgICAgICAgICBnbExheWVyLmZyYW1lYnVmZmVySGVpZ2h0XG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuZ2wudW5pZm9ybTRmKHRoaXMub2Zmc2V0TG9jYXRpb24sIDEuMCwgMS4wLCAwLjAsIDAuMCk7XG5cbiAgICAgICAgLy8gU2V0IHJlY3RhbmdsZVxuICAgICAgICAvLyBwcmV0dGllci1pZ25vcmVcbiAgICAgICAgdGhpcy5nbC5idWZmZXJEYXRhKFxuICAgICAgICAgICAgdGhpcy5nbC5BUlJBWV9CVUZGRVIsXG4gICAgICAgICAgICBuZXcgRmxvYXQzMkFycmF5KFtcbiAgICAgICAgICAgICAgICAwLCAwLCBcbiAgICAgICAgICAgICAgICB2aWRlb0VsZW1lbnQudmlkZW9XaWR0aCwgMCxcbiAgICAgICAgICAgICAgICAwLCB2aWRlb0VsZW1lbnQudmlkZW9IZWlnaHQsIFxuICAgICAgICAgICAgICAgIDAsIHZpZGVvRWxlbWVudC52aWRlb0hlaWdodCxcbiAgICAgICAgICAgICAgICB2aWRlb0VsZW1lbnQudmlkZW9XaWR0aCwgMCxcbiAgICAgICAgICAgICAgICB2aWRlb0VsZW1lbnQudmlkZW9XaWR0aCwgdmlkZW9FbGVtZW50LnZpZGVvSGVpZ2h0XG4gICAgICAgICAgICBdKSxcbiAgICAgICAgICAgIHRoaXMuZ2wuU1RBVElDX0RSQVdcbiAgICAgICAgKTtcblxuICAgICAgICAvLyBQcm92aWRlIHRleHR1cmUgY29vcmRpbmF0ZXMgZm9yIHRoZSByZWN0YW5nbGVcbiAgICAgICAgdGhpcy5nbC5iaW5kQnVmZmVyKHRoaXMuZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLnRleGNvb3JkQnVmZmVyKTtcbiAgICAgICAgdGhpcy5nbC5idWZmZXJEYXRhKFxuICAgICAgICAgICAgdGhpcy5nbC5BUlJBWV9CVUZGRVIsXG4gICAgICAgICAgICBuZXcgRmxvYXQzMkFycmF5KFtcbiAgICAgICAgICAgICAgICAwLjAsIDAuMCwgMS4wLCAwLjAsIDAuMCwgMS4wLCAwLjAsIDEuMCwgMS4wLCAwLjAsIDEuMCwgMS4wXG4gICAgICAgICAgICBdKSxcbiAgICAgICAgICAgIHRoaXMuZ2wuU1RBVElDX0RSQVdcbiAgICAgICAgKTtcblxuICAgICAgICBsZXQgc2l6ZTsgLy8gY29tcG9uZW50cyBwZXIgaXRlcmF0aW9uXG4gICAgICAgIGxldCB0eXBlOyAvLyB0aGUgZGF0YSB0eXBlXG4gICAgICAgIGxldCBub3JtYWxpemU7IC8vIG5vcm1hbGl6ZSB0aGUgZGF0YVxuICAgICAgICBsZXQgc3RyaWRlOyAvLyAwID0gbW92ZSBmb3J3YXJkIHNpemUgKiBzaXplb2YodHlwZSkgZWFjaCBpdGVyYXRpb24gdG8gZ2V0IHRoZSBuZXh0IHBvc2l0aW9uXG4gICAgICAgIGxldCBvZmZzZXQ7IC8vIHN0YXJ0IHBvc2l0aW9uIG9mIHRoZSBidWZmZXJcblxuICAgICAgICAvLyBCaW5kIHRoZSBwb3NpdGlvbiBidWZmZXIuXG4gICAgICAgIHRoaXMuZ2wuYmluZEJ1ZmZlcih0aGlzLmdsLkFSUkFZX0JVRkZFUiwgdGhpcy5wb3NpdGlvbkJ1ZmZlcik7XG4gICAgICAgIC8vIFRlbGwgdGhlIHBvc2l0aW9uIGF0dHJpYnV0ZSBob3cgdG8gZ2V0IGRhdGEgb3V0IG9mIHBvc2l0aW9uQnVmZmVyIChBUlJBWV9CVUZGRVIpXG4gICAgICAgIHNpemUgPSAyOyAvLyAyIGNvbXBvbmVudHMgcGVyIGl0ZXJhdGlvblxuICAgICAgICB0eXBlID0gdGhpcy5nbC5GTE9BVDsgLy8gdGhlIGRhdGEgaXMgMzJiaXQgZmxvYXRzXG4gICAgICAgIG5vcm1hbGl6ZSA9IGZhbHNlOyAvLyBkb24ndCBub3JtYWxpemUgdGhlIGRhdGFcbiAgICAgICAgc3RyaWRlID0gMDsgLy8gMCA9IG1vdmUgZm9yd2FyZCBzaXplICogc2l6ZW9mKHR5cGUpIGVhY2ggaXRlcmF0aW9uIHRvIGdldCB0aGUgbmV4dCBwb3NpdGlvblxuICAgICAgICBvZmZzZXQgPSAwOyAvLyBzdGFydCBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBidWZmZXJcbiAgICAgICAgdGhpcy5nbC52ZXJ0ZXhBdHRyaWJQb2ludGVyKFxuICAgICAgICAgICAgdGhpcy5wb3NpdGlvbkxvY2F0aW9uLFxuICAgICAgICAgICAgc2l6ZSxcbiAgICAgICAgICAgIHR5cGUsXG4gICAgICAgICAgICBub3JtYWxpemUsXG4gICAgICAgICAgICBzdHJpZGUsXG4gICAgICAgICAgICBvZmZzZXRcbiAgICAgICAgKTtcbiAgICAgICAgLy8gVHVybiBvbiB0aGUgdGV4Y29vcmQgYXR0cmlidXRlXG4gICAgICAgIHRoaXMuZ2wuZW5hYmxlVmVydGV4QXR0cmliQXJyYXkodGhpcy50ZXhjb29yZExvY2F0aW9uKTtcbiAgICAgICAgLy8gYmluZCB0aGUgdGV4Y29vcmQgYnVmZmVyLlxuICAgICAgICB0aGlzLmdsLmJpbmRCdWZmZXIodGhpcy5nbC5BUlJBWV9CVUZGRVIsIHRoaXMudGV4Y29vcmRCdWZmZXIpO1xuICAgICAgICAvLyBUZWxsIHRoZSB0ZXhjb29yZCBhdHRyaWJ1dGUgaG93IHRvIGdldCBkYXRhIG91dCBvZiB0ZXhjb29yZEJ1ZmZlciAoQVJSQVlfQlVGRkVSKVxuICAgICAgICBzaXplID0gMjsgLy8gMiBjb21wb25lbnRzIHBlciBpdGVyYXRpb25cbiAgICAgICAgdHlwZSA9IHRoaXMuZ2wuRkxPQVQ7IC8vIHRoZSBkYXRhIGlzIDMyYml0IGZsb2F0c1xuICAgICAgICBub3JtYWxpemUgPSBmYWxzZTsgLy8gZG9uJ3Qgbm9ybWFsaXplIHRoZSBkYXRhXG4gICAgICAgIHN0cmlkZSA9IDA7IC8vIDAgPSBtb3ZlIGZvcndhcmQgc2l6ZSAqIHNpemVvZih0eXBlKSBlYWNoIGl0ZXJhdGlvbiB0byBnZXQgdGhlIG5leHQgcG9zaXRpb25cbiAgICAgICAgb2Zmc2V0ID0gMDsgLy8gc3RhcnQgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgYnVmZmVyXG4gICAgICAgIHRoaXMuZ2wudmVydGV4QXR0cmliUG9pbnRlcihcbiAgICAgICAgICAgIHRoaXMudGV4Y29vcmRMb2NhdGlvbixcbiAgICAgICAgICAgIHNpemUsXG4gICAgICAgICAgICB0eXBlLFxuICAgICAgICAgICAgbm9ybWFsaXplLFxuICAgICAgICAgICAgc3RyaWRlLFxuICAgICAgICAgICAgb2Zmc2V0XG4gICAgICAgICk7XG4gICAgICAgIC8vIHNldCB0aGUgcmVzb2x1dGlvblxuICAgICAgICB0aGlzLmdsLnVuaWZvcm0yZihcbiAgICAgICAgICAgIHRoaXMucmVzb2x1dGlvbkxvY2F0aW9uLFxuICAgICAgICAgICAgdmlkZW9FbGVtZW50LnZpZGVvV2lkdGgsXG4gICAgICAgICAgICB2aWRlb0VsZW1lbnQudmlkZW9IZWlnaHRcbiAgICAgICAgKTtcbiAgICAgICAgLy8gZHJhdyB0aGUgcmVjdGFuZ2xlLlxuICAgICAgICBjb25zdCBwcmltaXRpdmVUeXBlID0gdGhpcy5nbC5UUklBTkdMRVM7XG4gICAgICAgIGNvbnN0IGNvdW50ID0gNjtcbiAgICAgICAgb2Zmc2V0ID0gMDtcbiAgICAgICAgdGhpcy5nbC5kcmF3QXJyYXlzKHByaW1pdGl2ZVR5cGUsIG9mZnNldCwgY291bnQpO1xuICAgIH1cblxuICAgIHN0YXRpYyBpc1Nlc3Npb25TdXBwb3J0ZWQobW9kZTogWFJTZXNzaW9uTW9kZSk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgICAgICBpZiAobmF2aWdhdG9yLnhyKSB7XG4gICAgICAgICAgICByZXR1cm4gbmF2aWdhdG9yLnhyLmlzU2Vzc2lvblN1cHBvcnRlZChtb2RlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgUHJvbWlzZTxib29sZWFuPigoKSA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG59XG4iLCJtb2R1bGUuZXhwb3J0cyA9IF9fV0VCUEFDS19FWFRFUk5BTF9NT0RVTEVfc2RwX187IiwiLy8gVGhlIG1vZHVsZSBjYWNoZVxudmFyIF9fd2VicGFja19tb2R1bGVfY2FjaGVfXyA9IHt9O1xuXG4vLyBUaGUgcmVxdWlyZSBmdW5jdGlvblxuZnVuY3Rpb24gX193ZWJwYWNrX3JlcXVpcmVfXyhtb2R1bGVJZCkge1xuXHQvLyBDaGVjayBpZiBtb2R1bGUgaXMgaW4gY2FjaGVcblx0dmFyIGNhY2hlZE1vZHVsZSA9IF9fd2VicGFja19tb2R1bGVfY2FjaGVfX1ttb2R1bGVJZF07XG5cdGlmIChjYWNoZWRNb2R1bGUgIT09IHVuZGVmaW5lZCkge1xuXHRcdHJldHVybiBjYWNoZWRNb2R1bGUuZXhwb3J0cztcblx0fVxuXHQvLyBDcmVhdGUgYSBuZXcgbW9kdWxlIChhbmQgcHV0IGl0IGludG8gdGhlIGNhY2hlKVxuXHR2YXIgbW9kdWxlID0gX193ZWJwYWNrX21vZHVsZV9jYWNoZV9fW21vZHVsZUlkXSA9IHtcblx0XHQvLyBubyBtb2R1bGUuaWQgbmVlZGVkXG5cdFx0Ly8gbm8gbW9kdWxlLmxvYWRlZCBuZWVkZWRcblx0XHRleHBvcnRzOiB7fVxuXHR9O1xuXG5cdC8vIEV4ZWN1dGUgdGhlIG1vZHVsZSBmdW5jdGlvblxuXHRfX3dlYnBhY2tfbW9kdWxlc19fW21vZHVsZUlkXShtb2R1bGUsIG1vZHVsZS5leHBvcnRzLCBfX3dlYnBhY2tfcmVxdWlyZV9fKTtcblxuXHQvLyBSZXR1cm4gdGhlIGV4cG9ydHMgb2YgdGhlIG1vZHVsZVxuXHRyZXR1cm4gbW9kdWxlLmV4cG9ydHM7XG59XG5cbiIsIi8vIGdldERlZmF1bHRFeHBvcnQgZnVuY3Rpb24gZm9yIGNvbXBhdGliaWxpdHkgd2l0aCBub24taGFybW9ueSBtb2R1bGVzXG5fX3dlYnBhY2tfcmVxdWlyZV9fLm4gPSAobW9kdWxlKSA9PiB7XG5cdHZhciBnZXR0ZXIgPSBtb2R1bGUgJiYgbW9kdWxlLl9fZXNNb2R1bGUgP1xuXHRcdCgpID0+IChtb2R1bGVbJ2RlZmF1bHQnXSkgOlxuXHRcdCgpID0+IChtb2R1bGUpO1xuXHRfX3dlYnBhY2tfcmVxdWlyZV9fLmQoZ2V0dGVyLCB7IGE6IGdldHRlciB9KTtcblx0cmV0dXJuIGdldHRlcjtcbn07IiwiLy8gZGVmaW5lIGdldHRlciBmdW5jdGlvbnMgZm9yIGhhcm1vbnkgZXhwb3J0c1xuX193ZWJwYWNrX3JlcXVpcmVfXy5kID0gKGV4cG9ydHMsIGRlZmluaXRpb24pID0+IHtcblx0Zm9yKHZhciBrZXkgaW4gZGVmaW5pdGlvbikge1xuXHRcdGlmKF9fd2VicGFja19yZXF1aXJlX18ubyhkZWZpbml0aW9uLCBrZXkpICYmICFfX3dlYnBhY2tfcmVxdWlyZV9fLm8oZXhwb3J0cywga2V5KSkge1xuXHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIGtleSwgeyBlbnVtZXJhYmxlOiB0cnVlLCBnZXQ6IGRlZmluaXRpb25ba2V5XSB9KTtcblx0XHR9XG5cdH1cbn07IiwiX193ZWJwYWNrX3JlcXVpcmVfXy5vID0gKG9iaiwgcHJvcCkgPT4gKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmosIHByb3ApKSIsIi8vIGRlZmluZSBfX2VzTW9kdWxlIG9uIGV4cG9ydHNcbl9fd2VicGFja19yZXF1aXJlX18uciA9IChleHBvcnRzKSA9PiB7XG5cdGlmKHR5cGVvZiBTeW1ib2wgIT09ICd1bmRlZmluZWQnICYmIFN5bWJvbC50b1N0cmluZ1RhZykge1xuXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBTeW1ib2wudG9TdHJpbmdUYWcsIHsgdmFsdWU6ICdNb2R1bGUnIH0pO1xuXHR9XG5cdE9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnX19lc01vZHVsZScsIHsgdmFsdWU6IHRydWUgfSk7XG59OyIsIi8vIENvcHlyaWdodCBFcGljIEdhbWVzLCBJbmMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG5cbmV4cG9ydCB7IFdlYlJ0Y1BsYXllckNvbnRyb2xsZXIgfSBmcm9tICcuL1dlYlJ0Y1BsYXllci9XZWJSdGNQbGF5ZXJDb250cm9sbGVyJztcbmV4cG9ydCB7IFdlYlhSQ29udHJvbGxlciB9IGZyb20gJy4vV2ViWFIvV2ViWFJDb250cm9sbGVyJztcbmV4cG9ydCB7XG4gICAgQ29uZmlnLFxuICAgIENvbnRyb2xTY2hlbWVUeXBlLFxuICAgIEZsYWdzLFxuICAgIE51bWVyaWNQYXJhbWV0ZXJzLFxuICAgIFRleHRQYXJhbWV0ZXJzLFxuICAgIE9wdGlvblBhcmFtZXRlcnMsXG4gICAgRmxhZ3NJZHMsXG4gICAgTnVtZXJpY1BhcmFtZXRlcnNJZHMsXG4gICAgVGV4dFBhcmFtZXRlcnNJZHMsXG4gICAgT3B0aW9uUGFyYW1ldGVyc0lkcyxcbiAgICBBbGxTZXR0aW5nc1xufSBmcm9tICcuL0NvbmZpZy9Db25maWcnO1xuZXhwb3J0IHsgU2V0dGluZ0Jhc2UgfSBmcm9tICcuL0NvbmZpZy9TZXR0aW5nQmFzZSc7XG5leHBvcnQgeyBTZXR0aW5nRmxhZyB9IGZyb20gJy4vQ29uZmlnL1NldHRpbmdGbGFnJztcbmV4cG9ydCB7IFNldHRpbmdOdW1iZXIgfSBmcm9tICcuL0NvbmZpZy9TZXR0aW5nTnVtYmVyJztcbmV4cG9ydCB7IFNldHRpbmdPcHRpb24gfSBmcm9tICcuL0NvbmZpZy9TZXR0aW5nT3B0aW9uJztcbmV4cG9ydCB7IFNldHRpbmdUZXh0IH0gZnJvbSAnLi9Db25maWcvU2V0dGluZ1RleHQnO1xuZXhwb3J0IHsgUGl4ZWxTdHJlYW1pbmcgfSBmcm9tICcuL1BpeGVsU3RyZWFtaW5nL1BpeGVsU3RyZWFtaW5nJztcblxuZXhwb3J0IHsgQUZLQ29udHJvbGxlciBhcyBBZmtMb2dpYyB9IGZyb20gJy4vQUZLL0FGS0NvbnRyb2xsZXInO1xuXG5leHBvcnQgeyBMYXRlbmN5VGVzdFJlc3VsdHMgfSBmcm9tICcuL0RhdGFDaGFubmVsL0xhdGVuY3lUZXN0UmVzdWx0cyc7XG5leHBvcnQge1xuICAgIEVuY29kZXJTZXR0aW5ncyxcbiAgICBJbml0aWFsU2V0dGluZ3MsXG4gICAgV2ViUlRDU2V0dGluZ3Ncbn0gZnJvbSAnLi9EYXRhQ2hhbm5lbC9Jbml0aWFsU2V0dGluZ3MnO1xuZXhwb3J0IHsgQWdncmVnYXRlZFN0YXRzIH0gZnJvbSAnLi9QZWVyQ29ubmVjdGlvbkNvbnRyb2xsZXIvQWdncmVnYXRlZFN0YXRzJztcbmV4cG9ydCB7IExvZ2dlciB9IGZyb20gJy4vTG9nZ2VyL0xvZ2dlcic7XG5leHBvcnQgeyBVbnF1YW50aXplZERlbm9ybWFsaXplZFVuc2lnbmVkQ29vcmQgYXMgVW5xdWFudGl6ZWRBbmREZW5vcm1hbGl6ZVVuc2lnbmVkIH0gZnJvbSAnLi9VdGlsL0Nvb3JkaW5hdGVDb252ZXJ0ZXInO1xuZXhwb3J0IHsgTWVzc2FnZURpcmVjdGlvbiB9IGZyb20gJy4vVWVJbnN0YW5jZU1lc3NhZ2UvU3RyZWFtTWVzc2FnZUNvbnRyb2xsZXInO1xuZXhwb3J0IHsgTWVzc2FnZVNlbmQgfSBmcm9tICcuL1dlYlNvY2tldHMvTWVzc2FnZVNlbmQnO1xuZXhwb3J0IHsgTWVzc2FnZVJlY3YsIE1lc3NhZ2VTdHJlYW1lckxpc3QgfSBmcm9tICcuL1dlYlNvY2tldHMvTWVzc2FnZVJlY2VpdmUnO1xuZXhwb3J0IHsgV2ViU29ja2V0Q29udHJvbGxlciB9IGZyb20gJy4vV2ViU29ja2V0cy9XZWJTb2NrZXRDb250cm9sbGVyJztcbmV4cG9ydCB7IFNpZ25hbGxpbmdQcm90b2NvbCB9IGZyb20gJy4vV2ViU29ja2V0cy9TaWduYWxsaW5nUHJvdG9jb2wnO1xuXG5leHBvcnQgeyBDYW5kaWRhdGVQYWlyU3RhdHMgfSBmcm9tICcuL1BlZXJDb25uZWN0aW9uQ29udHJvbGxlci9DYW5kaWRhdGVQYWlyU3RhdHMnO1xuZXhwb3J0IHsgQ2FuZGlkYXRlU3RhdCB9IGZyb20gJy4vUGVlckNvbm5lY3Rpb25Db250cm9sbGVyL0NhbmRpZGF0ZVN0YXQnO1xuZXhwb3J0IHsgRGF0YUNoYW5uZWxTdGF0cyB9IGZyb20gJy4vUGVlckNvbm5lY3Rpb25Db250cm9sbGVyL0RhdGFDaGFubmVsU3RhdHMnO1xuZXhwb3J0IHtcbiAgICBJbmJvdW5kQXVkaW9TdGF0cyxcbiAgICBJbmJvdW5kVmlkZW9TdGF0c1xufSBmcm9tICcuL1BlZXJDb25uZWN0aW9uQ29udHJvbGxlci9JbmJvdW5kUlRQU3RhdHMnO1xuZXhwb3J0IHsgT3V0Qm91bmRWaWRlb1N0YXRzIH0gZnJvbSAnLi9QZWVyQ29ubmVjdGlvbkNvbnRyb2xsZXIvT3V0Qm91bmRSVFBTdGF0cyc7XG5leHBvcnQgKiBmcm9tICcuL1V0aWwvRXZlbnRFbWl0dGVyJztcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==