(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==
|