matrix-react-sdk
Version:
SDK for matrix.org using React
402 lines (390 loc) • 58 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _logger = require("matrix-js-sdk/src/logger");
var _crypto = require("matrix-js-sdk/src/crypto");
var _dispatcher = _interopRequireDefault(require("../../dispatcher/dispatcher"));
var _verification = require("../../verification");
var _SettingsStore = _interopRequireDefault(require("../../settings/SettingsStore"));
var _RightPanelStorePhases = require("./RightPanelStorePhases");
var _SettingLevel = require("../../settings/SettingLevel");
var _AsyncStore = require("../AsyncStore");
var _ReadyWatchingStore = require("../ReadyWatchingStore");
var _RightPanelStoreIPanelState = require("./RightPanelStoreIPanelState");
var _actions = require("../../dispatcher/actions");
var _SDKContext = require("../../contexts/SDKContext");
var _MatrixClientPeg = require("../../MatrixClientPeg");
/*
Copyright 2024 New Vector Ltd.
Copyright 2019-2023 The Matrix.org Foundation C.I.C.
SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/
/**
* A class for tracking the state of the right panel between layouts and
* sessions. This state includes a history for each room. Each history element
* contains the phase (e.g. RightPanelPhase.RoomMemberInfo) and the state (e.g.
* the member) associated with it.
*/
class RightPanelStore extends _ReadyWatchingStore.ReadyWatchingStore {
constructor() {
super(_dispatcher.default);
(0, _defineProperty2.default)(this, "global", void 0);
(0, _defineProperty2.default)(this, "byRoom", {});
(0, _defineProperty2.default)(this, "viewedRoomId", void 0);
(0, _defineProperty2.default)(this, "onVerificationRequestUpdate", () => {
if (!this.currentCard?.state) return;
const {
member
} = this.currentCard.state;
if (!member) return;
const pendingRequest = (0, _verification.pendingVerificationRequestForUser)(_MatrixClientPeg.MatrixClientPeg.safeGet(), member);
if (pendingRequest) {
this.currentCard.state.verificationRequest = pendingRequest;
this.emitAndUpdateSettings();
}
});
this.reset();
}
/**
* Resets the store. Intended for test usage only.
*/
reset() {
this.global = undefined;
this.byRoom = {};
this.viewedRoomId = null;
}
async onReady() {
this.viewedRoomId = _SDKContext.SdkContextClass.instance.roomViewStore.getRoomId();
this.matrixClient?.on(_crypto.CryptoEvent.VerificationRequestReceived, this.onVerificationRequestUpdate);
this.loadCacheFromSettings();
this.emitAndUpdateSettings();
}
async onNotReady() {
this.matrixClient?.off(_crypto.CryptoEvent.VerificationRequestReceived, this.onVerificationRequestUpdate);
}
onDispatcherAction(payload) {
switch (payload.action) {
case _actions.Action.ActiveRoomChanged:
{
const changePayload = payload;
this.handleViewedRoomChange(changePayload.oldRoomId, changePayload.newRoomId);
break;
}
case _actions.Action.FocusMessageSearch:
{
if (this.currentCard.phase !== _RightPanelStorePhases.RightPanelPhases.RoomSummary) {
this.setCard({
phase: _RightPanelStorePhases.RightPanelPhases.RoomSummary,
state: {
focusRoomSearch: true
}
});
}
}
}
}
// Getters
/**
* If you are calling this from a component that already knows about a
* specific room from props / state, then it's best to prefer
* `isOpenForRoom` below to ensure all your data is for a single room
* during room changes.
*/
get isOpen() {
return this.byRoom[this.viewedRoomId ?? ""]?.isOpen ?? false;
}
isOpenForRoom(roomId) {
return this.byRoom[roomId]?.isOpen ?? false;
}
get roomPhaseHistory() {
return this.byRoom[this.viewedRoomId ?? ""]?.history ?? [];
}
/**
* If you are calling this from a component that already knows about a
* specific room from props / state, then it's best to prefer
* `currentCardForRoom` below to ensure all your data is for a single room
* during room changes.
*/
get currentCard() {
const hist = this.roomPhaseHistory;
if (hist.length >= 1) {
return hist[hist.length - 1];
}
return {
state: {},
phase: null
};
}
currentCardForRoom(roomId) {
const hist = this.byRoom[roomId]?.history ?? [];
if (hist.length > 0) {
return hist[hist.length - 1];
}
return {
state: {},
phase: null
};
}
get previousCard() {
const hist = this.roomPhaseHistory;
if (hist?.length >= 2) {
return hist[hist.length - 2];
}
return {
state: {},
phase: null
};
}
// Setters
setCard(card, allowClose = true, roomId) {
const rId = roomId ?? this.viewedRoomId ?? "";
// This function behaves as following:
// Update state: if the same phase is send but with a state
// Set right panel and erase history: if a "different to the current" phase is send (with or without a state)
// If the right panel is set, this function also shows the right panel.
const redirect = this.getVerificationRedirect(card);
const targetPhase = redirect?.phase ?? card.phase;
const cardState = redirect?.state ?? (Object.keys(card.state ?? {}).length === 0 ? null : card.state);
// Checks for wrong SetRightPanelPhase requests
if (!this.isPhaseValid(targetPhase, Boolean(rId))) return;
if (targetPhase === this.currentCardForRoom(rId)?.phase && !!cardState) {
// Update state: set right panel with a new state but keep the phase (don't know it this is ever needed...)
const hist = this.byRoom[rId]?.history ?? [];
hist[hist.length - 1].state = cardState;
this.emitAndUpdateSettings();
} else if (targetPhase !== this.currentCardForRoom(rId)?.phase || !this.byRoom[rId]) {
// Set right panel and initialize/erase history
const history = [{
phase: targetPhase,
state: cardState ?? {}
}];
this.byRoom[rId] = {
history,
isOpen: true
};
this.emitAndUpdateSettings();
} else {
this.show(rId);
this.emitAndUpdateSettings();
}
}
setCards(cards, allowClose = true, roomId = null) {
// This function sets the history of the right panel and shows the right panel if not already visible.
const rId = roomId ?? this.viewedRoomId ?? "";
const history = cards.map(c => ({
phase: c.phase,
state: c.state ?? {}
}));
this.byRoom[rId] = {
history,
isOpen: true
};
this.show(rId);
this.emitAndUpdateSettings();
}
// Appends a card to the history and shows the right panel if not already visible
pushCard(card, allowClose = true, roomId = null) {
const rId = roomId ?? this.viewedRoomId ?? "";
const redirect = this.getVerificationRedirect(card);
const targetPhase = redirect?.phase ?? card.phase;
const pState = redirect?.state ?? card.state ?? {};
// Checks for wrong SetRightPanelPhase requests
if (!this.isPhaseValid(targetPhase, Boolean(rId))) return;
const roomCache = this.byRoom[rId];
if (!!roomCache) {
// append new phase
roomCache.history.push({
state: pState,
phase: targetPhase
});
roomCache.isOpen = allowClose ? roomCache.isOpen : true;
} else {
// setup room panel cache with the new card
this.byRoom[rId] = {
history: [{
phase: targetPhase,
state: pState
}],
// if there was no right panel store object the the panel was closed -> keep it closed, except if allowClose==false
isOpen: !allowClose
};
}
this.show(rId);
this.emitAndUpdateSettings();
}
popCard(roomId = null) {
const rId = roomId ?? this.viewedRoomId ?? "";
if (!this.byRoom[rId]) return;
const removedCard = this.byRoom[rId].history.pop();
this.emitAndUpdateSettings();
return removedCard;
}
togglePanel(roomId) {
const rId = roomId ?? this.viewedRoomId ?? "";
if (!this.byRoom[rId]) return;
this.byRoom[rId].isOpen = !this.byRoom[rId].isOpen;
this.emitAndUpdateSettings();
}
show(roomId) {
if (!this.isOpenForRoom(roomId ?? this.viewedRoomId ?? "")) {
this.togglePanel(roomId);
}
}
hide(roomId) {
if (this.isOpenForRoom(roomId ?? this.viewedRoomId ?? "")) {
this.togglePanel(roomId);
}
}
/**
* Helper to show a right panel phase.
* If the UI is already showing that phase, the right panel will be hidden.
*
* Calling the same phase twice with a different state will update the current
* phase and push the old state in the right panel history.
* @param phase The right panel phase.
* @param cardState The state within the phase.
*/
showOrHidePhase(phase, cardState) {
if (this.currentCard.phase == phase && !cardState && this.isOpen) {
this.togglePanel(null);
} else {
this.setCard({
phase,
state: cardState
});
if (!this.isOpen) this.togglePanel(null);
}
}
loadCacheFromSettings() {
if (this.viewedRoomId) {
const room = this.mxClient?.getRoom(this.viewedRoomId);
if (!!room) {
this.global = this.global ?? (0, _RightPanelStoreIPanelState.convertToStatePanel)(_SettingsStore.default.getValue("RightPanel.phasesGlobal"), room);
this.byRoom[this.viewedRoomId] = this.byRoom[this.viewedRoomId] ?? (0, _RightPanelStoreIPanelState.convertToStatePanel)(_SettingsStore.default.getValue("RightPanel.phases", this.viewedRoomId), room);
} else {
_logger.logger.warn("Could not restore the right panel after load because there was no associated room object.");
}
}
}
emitAndUpdateSettings() {
this.filterValidCards(this.global);
const storePanelGlobal = (0, _RightPanelStoreIPanelState.convertToStorePanel)(this.global);
_SettingsStore.default.setValue("RightPanel.phasesGlobal", null, _SettingLevel.SettingLevel.DEVICE, storePanelGlobal);
if (!!this.viewedRoomId) {
const panelThisRoom = this.byRoom[this.viewedRoomId];
this.filterValidCards(panelThisRoom);
const storePanelThisRoom = (0, _RightPanelStoreIPanelState.convertToStorePanel)(panelThisRoom);
_SettingsStore.default.setValue("RightPanel.phases", this.viewedRoomId, _SettingLevel.SettingLevel.ROOM_DEVICE, storePanelThisRoom);
}
this.emit(_AsyncStore.UPDATE_EVENT, null);
}
filterValidCards(rightPanelForRoom) {
if (!rightPanelForRoom?.history) return;
rightPanelForRoom.history = rightPanelForRoom.history.filter(card => this.isCardStateValid(card));
if (!rightPanelForRoom.history.length) {
rightPanelForRoom.isOpen = false;
}
}
isCardStateValid(card) {
// this function does a sanity check on the card. this is required because
// some phases require specific state properties that might not be available.
// This can be caused on if element is reloaded and the tries to reload right panel data from id's stored in the local storage.
// we store id's of users and matrix events. If are not yet fetched on reload the right panel cannot display them.
// or potentially other errors.
// (A nicer fix could be to indicate, that the right panel is loading if there is missing state data and re-emit if the data is available)
switch (card.phase) {
case _RightPanelStorePhases.RightPanelPhases.ThreadView:
if (!card.state?.threadHeadEvent) {
_logger.logger.warn("removed card from right panel because of missing threadHeadEvent in card state");
}
return !!card.state?.threadHeadEvent;
case _RightPanelStorePhases.RightPanelPhases.RoomMemberInfo:
case _RightPanelStorePhases.RightPanelPhases.SpaceMemberInfo:
case _RightPanelStorePhases.RightPanelPhases.EncryptionPanel:
if (!card.state?.member) {
_logger.logger.warn("removed card from right panel because of missing member in card state");
}
return !!card.state?.member;
case _RightPanelStorePhases.RightPanelPhases.Room3pidMemberInfo:
case _RightPanelStorePhases.RightPanelPhases.Space3pidMemberInfo:
if (!card.state?.memberInfoEvent) {
_logger.logger.warn("removed card from right panel because of missing memberInfoEvent in card state");
}
return !!card.state?.memberInfoEvent;
case _RightPanelStorePhases.RightPanelPhases.Widget:
if (!card.state?.widgetId) {
_logger.logger.warn("removed card from right panel because of missing widgetId in card state");
}
return !!card.state?.widgetId;
}
return true;
}
getVerificationRedirect(card) {
if (card.phase === _RightPanelStorePhases.RightPanelPhases.RoomMemberInfo && card.state) {
// RightPanelPhases.RoomMemberInfo -> needs to be changed to RightPanelPhases.EncryptionPanel if there is a pending verification request
const {
member
} = card.state;
const pendingRequest = member ? (0, _verification.pendingVerificationRequestForUser)(_MatrixClientPeg.MatrixClientPeg.safeGet(), member) : undefined;
if (pendingRequest) {
return {
phase: _RightPanelStorePhases.RightPanelPhases.EncryptionPanel,
state: {
verificationRequest: pendingRequest,
member
}
};
}
}
return null;
}
isPhaseValid(targetPhase, isViewingRoom) {
if (!targetPhase || !_RightPanelStorePhases.RightPanelPhases[targetPhase]) {
_logger.logger.warn(`Tried to switch right panel to unknown phase: ${targetPhase}`);
return false;
}
if (!isViewingRoom) {
_logger.logger.warn(`Tried to switch right panel to a room phase: ${targetPhase}, ` + `but we are currently not viewing a room`);
return false;
}
return true;
}
handleViewedRoomChange(oldRoomId, newRoomId) {
if (!this.mxClient) return; // not ready, onReady will handle the first room
this.viewedRoomId = newRoomId;
// load values from byRoomCache with the viewedRoomId.
this.loadCacheFromSettings();
// when we're switching to a room, clear out any stale MemberInfo cards
// in order to fix https://github.com/vector-im/element-web/issues/21487
if (this.currentCard?.phase !== _RightPanelStorePhases.RightPanelPhases.EncryptionPanel) {
const panel = this.byRoom[this.viewedRoomId ?? ""];
if (panel?.history) {
panel.history = panel.history.filter(card => card.phase != _RightPanelStorePhases.RightPanelPhases.RoomMemberInfo && card.phase != _RightPanelStorePhases.RightPanelPhases.Room3pidMemberInfo);
}
}
// when we're switching to a room, clear out thread permalinks to not get you stuck in the middle of the thread
// in order to fix https://github.com/matrix-org/matrix-react-sdk/pull/11011
if (this.currentCard?.phase === _RightPanelStorePhases.RightPanelPhases.ThreadView && this.currentCard.state) {
this.currentCard.state.initialEvent = undefined;
this.currentCard.state.isInitialEventHighlighted = undefined;
this.currentCard.state.initialEventScrollIntoView = undefined;
}
this.emitAndUpdateSettings();
}
static get instance() {
if (!this.internalInstance) {
this.internalInstance = new RightPanelStore();
this.internalInstance.start();
}
return this.internalInstance;
}
}
exports.default = RightPanelStore;
(0, _defineProperty2.default)(RightPanelStore, "internalInstance", void 0);
window.mxRightPanelStore = RightPanelStore.instance;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9nZ2VyIiwicmVxdWlyZSIsIl9jcnlwdG8iLCJfZGlzcGF0Y2hlciIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJfdmVyaWZpY2F0aW9uIiwiX1NldHRpbmdzU3RvcmUiLCJfUmlnaHRQYW5lbFN0b3JlUGhhc2VzIiwiX1NldHRpbmdMZXZlbCIsIl9Bc3luY1N0b3JlIiwiX1JlYWR5V2F0Y2hpbmdTdG9yZSIsIl9SaWdodFBhbmVsU3RvcmVJUGFuZWxTdGF0ZSIsIl9hY3Rpb25zIiwiX1NES0NvbnRleHQiLCJfTWF0cml4Q2xpZW50UGVnIiwiUmlnaHRQYW5lbFN0b3JlIiwiUmVhZHlXYXRjaGluZ1N0b3JlIiwiY29uc3RydWN0b3IiLCJkZWZhdWx0RGlzcGF0Y2hlciIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJkZWZhdWx0IiwiY3VycmVudENhcmQiLCJzdGF0ZSIsIm1lbWJlciIsInBlbmRpbmdSZXF1ZXN0IiwicGVuZGluZ1ZlcmlmaWNhdGlvblJlcXVlc3RGb3JVc2VyIiwiTWF0cml4Q2xpZW50UGVnIiwic2FmZUdldCIsInZlcmlmaWNhdGlvblJlcXVlc3QiLCJlbWl0QW5kVXBkYXRlU2V0dGluZ3MiLCJyZXNldCIsImdsb2JhbCIsInVuZGVmaW5lZCIsImJ5Um9vbSIsInZpZXdlZFJvb21JZCIsIm9uUmVhZHkiLCJTZGtDb250ZXh0Q2xhc3MiLCJpbnN0YW5jZSIsInJvb21WaWV3U3RvcmUiLCJnZXRSb29tSWQiLCJtYXRyaXhDbGllbnQiLCJvbiIsIkNyeXB0b0V2ZW50IiwiVmVyaWZpY2F0aW9uUmVxdWVzdFJlY2VpdmVkIiwib25WZXJpZmljYXRpb25SZXF1ZXN0VXBkYXRlIiwibG9hZENhY2hlRnJvbVNldHRpbmdzIiwib25Ob3RSZWFkeSIsIm9mZiIsIm9uRGlzcGF0Y2hlckFjdGlvbiIsInBheWxvYWQiLCJhY3Rpb24iLCJBY3Rpb24iLCJBY3RpdmVSb29tQ2hhbmdlZCIsImNoYW5nZVBheWxvYWQiLCJoYW5kbGVWaWV3ZWRSb29tQ2hhbmdlIiwib2xkUm9vbUlkIiwibmV3Um9vbUlkIiwiRm9jdXNNZXNzYWdlU2VhcmNoIiwicGhhc2UiLCJSaWdodFBhbmVsUGhhc2VzIiwiUm9vbVN1bW1hcnkiLCJzZXRDYXJkIiwiZm9jdXNSb29tU2VhcmNoIiwiaXNPcGVuIiwiaXNPcGVuRm9yUm9vbSIsInJvb21JZCIsInJvb21QaGFzZUhpc3RvcnkiLCJoaXN0b3J5IiwiaGlzdCIsImxlbmd0aCIsImN1cnJlbnRDYXJkRm9yUm9vbSIsInByZXZpb3VzQ2FyZCIsImNhcmQiLCJhbGxvd0Nsb3NlIiwicklkIiwicmVkaXJlY3QiLCJnZXRWZXJpZmljYXRpb25SZWRpcmVjdCIsInRhcmdldFBoYXNlIiwiY2FyZFN0YXRlIiwiT2JqZWN0Iiwia2V5cyIsImlzUGhhc2VWYWxpZCIsIkJvb2xlYW4iLCJzaG93Iiwic2V0Q2FyZHMiLCJjYXJkcyIsIm1hcCIsImMiLCJwdXNoQ2FyZCIsInBTdGF0ZSIsInJvb21DYWNoZSIsInB1c2giLCJwb3BDYXJkIiwicmVtb3ZlZENhcmQiLCJwb3AiLCJ0b2dnbGVQYW5lbCIsImhpZGUiLCJzaG93T3JIaWRlUGhhc2UiLCJyb29tIiwibXhDbGllbnQiLCJnZXRSb29tIiwiY29udmVydFRvU3RhdGVQYW5lbCIsIlNldHRpbmdzU3RvcmUiLCJnZXRWYWx1ZSIsImxvZ2dlciIsIndhcm4iLCJmaWx0ZXJWYWxpZENhcmRzIiwic3RvcmVQYW5lbEdsb2JhbCIsImNvbnZlcnRUb1N0b3JlUGFuZWwiLCJzZXRWYWx1ZSIsIlNldHRpbmdMZXZlbCIsIkRFVklDRSIsInBhbmVsVGhpc1Jvb20iLCJzdG9yZVBhbmVsVGhpc1Jvb20iLCJST09NX0RFVklDRSIsImVtaXQiLCJVUERBVEVfRVZFTlQiLCJyaWdodFBhbmVsRm9yUm9vbSIsImZpbHRlciIsImlzQ2FyZFN0YXRlVmFsaWQiLCJUaHJlYWRWaWV3IiwidGhyZWFkSGVhZEV2ZW50IiwiUm9vbU1lbWJlckluZm8iLCJTcGFjZU1lbWJlckluZm8iLCJFbmNyeXB0aW9uUGFuZWwiLCJSb29tM3BpZE1lbWJlckluZm8iLCJTcGFjZTNwaWRNZW1iZXJJbmZvIiwibWVtYmVySW5mb0V2ZW50IiwiV2lkZ2V0Iiwid2lkZ2V0SWQiLCJpc1ZpZXdpbmdSb29tIiwicGFuZWwiLCJpbml0aWFsRXZlbnQiLCJpc0luaXRpYWxFdmVudEhpZ2hsaWdodGVkIiwiaW5pdGlhbEV2ZW50U2Nyb2xsSW50b1ZpZXciLCJpbnRlcm5hbEluc3RhbmNlIiwic3RhcnQiLCJleHBvcnRzIiwid2luZG93IiwibXhSaWdodFBhbmVsU3RvcmUiXSwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvc3RvcmVzL3JpZ2h0LXBhbmVsL1JpZ2h0UGFuZWxTdG9yZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMjQgTmV3IFZlY3RvciBMdGQuXG5Db3B5cmlnaHQgMjAxOS0yMDIzIFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5cblNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBR1BMLTMuMC1vbmx5IE9SIEdQTC0zLjAtb25seVxuUGxlYXNlIHNlZSBMSUNFTlNFIGZpbGVzIGluIHRoZSByZXBvc2l0b3J5IHJvb3QgZm9yIGZ1bGwgZGV0YWlscy5cbiovXG5cbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9sb2dnZXJcIjtcbmltcG9ydCB7IENyeXB0b0V2ZW50IH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2NyeXB0b1wiO1xuaW1wb3J0IHsgT3B0aW9uYWwgfSBmcm9tIFwibWF0cml4LWV2ZW50cy1zZGtcIjtcblxuaW1wb3J0IGRlZmF1bHREaXNwYXRjaGVyIGZyb20gXCIuLi8uLi9kaXNwYXRjaGVyL2Rpc3BhdGNoZXJcIjtcbmltcG9ydCB7IHBlbmRpbmdWZXJpZmljYXRpb25SZXF1ZXN0Rm9yVXNlciB9IGZyb20gXCIuLi8uLi92ZXJpZmljYXRpb25cIjtcbmltcG9ydCBTZXR0aW5nc1N0b3JlIGZyb20gXCIuLi8uLi9zZXR0aW5ncy9TZXR0aW5nc1N0b3JlXCI7XG5pbXBvcnQgeyBSaWdodFBhbmVsUGhhc2VzIH0gZnJvbSBcIi4vUmlnaHRQYW5lbFN0b3JlUGhhc2VzXCI7XG5pbXBvcnQgeyBTZXR0aW5nTGV2ZWwgfSBmcm9tIFwiLi4vLi4vc2V0dGluZ3MvU2V0dGluZ0xldmVsXCI7XG5pbXBvcnQgeyBVUERBVEVfRVZFTlQgfSBmcm9tIFwiLi4vQXN5bmNTdG9yZVwiO1xuaW1wb3J0IHsgUmVhZHlXYXRjaGluZ1N0b3JlIH0gZnJvbSBcIi4uL1JlYWR5V2F0Y2hpbmdTdG9yZVwiO1xuaW1wb3J0IHtcbiAgICBjb252ZXJ0VG9TdGF0ZVBhbmVsLFxuICAgIGNvbnZlcnRUb1N0b3JlUGFuZWwsXG4gICAgSVJpZ2h0UGFuZWxDYXJkLFxuICAgIElSaWdodFBhbmVsQ2FyZFN0YXRlLFxuICAgIElSaWdodFBhbmVsRm9yUm9vbSxcbn0gZnJvbSBcIi4vUmlnaHRQYW5lbFN0b3JlSVBhbmVsU3RhdGVcIjtcbmltcG9ydCB7IEFjdGlvblBheWxvYWQgfSBmcm9tIFwiLi4vLi4vZGlzcGF0Y2hlci9wYXlsb2Fkc1wiO1xuaW1wb3J0IHsgQWN0aW9uIH0gZnJvbSBcIi4uLy4uL2Rpc3BhdGNoZXIvYWN0aW9uc1wiO1xuaW1wb3J0IHsgQWN0aXZlUm9vbUNoYW5nZWRQYXlsb2FkIH0gZnJvbSBcIi4uLy4uL2Rpc3BhdGNoZXIvcGF5bG9hZHMvQWN0aXZlUm9vbUNoYW5nZWRQYXlsb2FkXCI7XG5pbXBvcnQgeyBTZGtDb250ZXh0Q2xhc3MgfSBmcm9tIFwiLi4vLi4vY29udGV4dHMvU0RLQ29udGV4dFwiO1xuaW1wb3J0IHsgTWF0cml4Q2xpZW50UGVnIH0gZnJvbSBcIi4uLy4uL01hdHJpeENsaWVudFBlZ1wiO1xuXG4vKipcbiAqIEEgY2xhc3MgZm9yIHRyYWNraW5nIHRoZSBzdGF0ZSBvZiB0aGUgcmlnaHQgcGFuZWwgYmV0d2VlbiBsYXlvdXRzIGFuZFxuICogc2Vzc2lvbnMuIFRoaXMgc3RhdGUgaW5jbHVkZXMgYSBoaXN0b3J5IGZvciBlYWNoIHJvb20uIEVhY2ggaGlzdG9yeSBlbGVtZW50XG4gKiBjb250YWlucyB0aGUgcGhhc2UgKGUuZy4gUmlnaHRQYW5lbFBoYXNlLlJvb21NZW1iZXJJbmZvKSBhbmQgdGhlIHN0YXRlIChlLmcuXG4gKiB0aGUgbWVtYmVyKSBhc3NvY2lhdGVkIHdpdGggaXQuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFJpZ2h0UGFuZWxTdG9yZSBleHRlbmRzIFJlYWR5V2F0Y2hpbmdTdG9yZSB7XG4gICAgcHJpdmF0ZSBzdGF0aWMgaW50ZXJuYWxJbnN0YW5jZTogUmlnaHRQYW5lbFN0b3JlO1xuXG4gICAgcHJpdmF0ZSBnbG9iYWw/OiBJUmlnaHRQYW5lbEZvclJvb207XG4gICAgcHJpdmF0ZSBieVJvb206IHsgW3Jvb21JZDogc3RyaW5nXTogSVJpZ2h0UGFuZWxGb3JSb29tIH0gPSB7fTtcbiAgICBwcml2YXRlIHZpZXdlZFJvb21JZDogT3B0aW9uYWw8c3RyaW5nPjtcblxuICAgIHByaXZhdGUgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHN1cGVyKGRlZmF1bHREaXNwYXRjaGVyKTtcbiAgICAgICAgdGhpcy5yZXNldCgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlc2V0cyB0aGUgc3RvcmUuIEludGVuZGVkIGZvciB0ZXN0IHVzYWdlIG9ubHkuXG4gICAgICovXG4gICAgcHVibGljIHJlc2V0KCk6IHZvaWQge1xuICAgICAgICB0aGlzLmdsb2JhbCA9IHVuZGVmaW5lZDtcbiAgICAgICAgdGhpcy5ieVJvb20gPSB7fTtcbiAgICAgICAgdGhpcy52aWV3ZWRSb29tSWQgPSBudWxsO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBhc3luYyBvblJlYWR5KCk6IFByb21pc2U8YW55PiB7XG4gICAgICAgIHRoaXMudmlld2VkUm9vbUlkID0gU2RrQ29udGV4dENsYXNzLmluc3RhbmNlLnJvb21WaWV3U3RvcmUuZ2V0Um9vbUlkKCk7XG4gICAgICAgIHRoaXMubWF0cml4Q2xpZW50Py5vbihDcnlwdG9FdmVudC5WZXJpZmljYXRpb25SZXF1ZXN0UmVjZWl2ZWQsIHRoaXMub25WZXJpZmljYXRpb25SZXF1ZXN0VXBkYXRlKTtcbiAgICAgICAgdGhpcy5sb2FkQ2FjaGVGcm9tU2V0dGluZ3MoKTtcbiAgICAgICAgdGhpcy5lbWl0QW5kVXBkYXRlU2V0dGluZ3MoKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgYXN5bmMgb25Ob3RSZWFkeSgpOiBQcm9taXNlPGFueT4ge1xuICAgICAgICB0aGlzLm1hdHJpeENsaWVudD8ub2ZmKENyeXB0b0V2ZW50LlZlcmlmaWNhdGlvblJlcXVlc3RSZWNlaXZlZCwgdGhpcy5vblZlcmlmaWNhdGlvblJlcXVlc3RVcGRhdGUpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBvbkRpc3BhdGNoZXJBY3Rpb24ocGF5bG9hZDogQWN0aW9uUGF5bG9hZCk6IHZvaWQge1xuICAgICAgICBzd2l0Y2ggKHBheWxvYWQuYWN0aW9uKSB7XG4gICAgICAgICAgICBjYXNlIEFjdGlvbi5BY3RpdmVSb29tQ2hhbmdlZDoge1xuICAgICAgICAgICAgICAgIGNvbnN0IGNoYW5nZVBheWxvYWQgPSA8QWN0aXZlUm9vbUNoYW5nZWRQYXlsb2FkPnBheWxvYWQ7XG4gICAgICAgICAgICAgICAgdGhpcy5oYW5kbGVWaWV3ZWRSb29tQ2hhbmdlKGNoYW5nZVBheWxvYWQub2xkUm9vbUlkLCBjaGFuZ2VQYXlsb2FkLm5ld1Jvb21JZCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNhc2UgQWN0aW9uLkZvY3VzTWVzc2FnZVNlYXJjaDoge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmN1cnJlbnRDYXJkLnBoYXNlICE9PSBSaWdodFBhbmVsUGhhc2VzLlJvb21TdW1tYXJ5KSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2V0Q2FyZCh7IHBoYXNlOiBSaWdodFBhbmVsUGhhc2VzLlJvb21TdW1tYXJ5LCBzdGF0ZTogeyBmb2N1c1Jvb21TZWFyY2g6IHRydWUgfSB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBHZXR0ZXJzXG4gICAgLyoqXG4gICAgICogSWYgeW91IGFyZSBjYWxsaW5nIHRoaXMgZnJvbSBhIGNvbXBvbmVudCB0aGF0IGFscmVhZHkga25vd3MgYWJvdXQgYVxuICAgICAqIHNwZWNpZmljIHJvb20gZnJvbSBwcm9wcyAvIHN0YXRlLCB0aGVuIGl0J3MgYmVzdCB0byBwcmVmZXJcbiAgICAgKiBgaXNPcGVuRm9yUm9vbWAgYmVsb3cgdG8gZW5zdXJlIGFsbCB5b3VyIGRhdGEgaXMgZm9yIGEgc2luZ2xlIHJvb21cbiAgICAgKiBkdXJpbmcgcm9vbSBjaGFuZ2VzLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgaXNPcGVuKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5ieVJvb21bdGhpcy52aWV3ZWRSb29tSWQgPz8gXCJcIl0/LmlzT3BlbiA/PyBmYWxzZTtcbiAgICB9XG5cbiAgICBwdWJsaWMgaXNPcGVuRm9yUm9vbShyb29tSWQ6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gdGhpcy5ieVJvb21bcm9vbUlkXT8uaXNPcGVuID8/IGZhbHNlO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgcm9vbVBoYXNlSGlzdG9yeSgpOiBBcnJheTxJUmlnaHRQYW5lbENhcmQ+IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYnlSb29tW3RoaXMudmlld2VkUm9vbUlkID8/IFwiXCJdPy5oaXN0b3J5ID8/IFtdO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIElmIHlvdSBhcmUgY2FsbGluZyB0aGlzIGZyb20gYSBjb21wb25lbnQgdGhhdCBhbHJlYWR5IGtub3dzIGFib3V0IGFcbiAgICAgKiBzcGVjaWZpYyByb29tIGZyb20gcHJvcHMgLyBzdGF0ZSwgdGhlbiBpdCdzIGJlc3QgdG8gcHJlZmVyXG4gICAgICogYGN1cnJlbnRDYXJkRm9yUm9vbWAgYmVsb3cgdG8gZW5zdXJlIGFsbCB5b3VyIGRhdGEgaXMgZm9yIGEgc2luZ2xlIHJvb21cbiAgICAgKiBkdXJpbmcgcm9vbSBjaGFuZ2VzLlxuICAgICAqL1xuICAgIHB1YmxpYyBnZXQgY3VycmVudENhcmQoKTogSVJpZ2h0UGFuZWxDYXJkIHtcbiAgICAgICAgY29uc3QgaGlzdCA9IHRoaXMucm9vbVBoYXNlSGlzdG9yeTtcbiAgICAgICAgaWYgKGhpc3QubGVuZ3RoID49IDEpIHtcbiAgICAgICAgICAgIHJldHVybiBoaXN0W2hpc3QubGVuZ3RoIC0gMV07XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHsgc3RhdGU6IHt9LCBwaGFzZTogbnVsbCB9O1xuICAgIH1cblxuICAgIHB1YmxpYyBjdXJyZW50Q2FyZEZvclJvb20ocm9vbUlkOiBzdHJpbmcpOiBJUmlnaHRQYW5lbENhcmQge1xuICAgICAgICBjb25zdCBoaXN0ID0gdGhpcy5ieVJvb21bcm9vbUlkXT8uaGlzdG9yeSA/PyBbXTtcbiAgICAgICAgaWYgKGhpc3QubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgcmV0dXJuIGhpc3RbaGlzdC5sZW5ndGggLSAxXTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4geyBzdGF0ZToge30sIHBoYXNlOiBudWxsIH07XG4gICAgfVxuXG4gICAgcHVibGljIGdldCBwcmV2aW91c0NhcmQoKTogSVJpZ2h0UGFuZWxDYXJkIHtcbiAgICAgICAgY29uc3QgaGlzdCA9IHRoaXMucm9vbVBoYXNlSGlzdG9yeTtcbiAgICAgICAgaWYgKGhpc3Q/Lmxlbmd0aCA+PSAyKSB7XG4gICAgICAgICAgICByZXR1cm4gaGlzdFtoaXN0Lmxlbmd0aCAtIDJdO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7IHN0YXRlOiB7fSwgcGhhc2U6IG51bGwgfTtcbiAgICB9XG5cbiAgICAvLyBTZXR0ZXJzXG4gICAgcHVibGljIHNldENhcmQoY2FyZDogSVJpZ2h0UGFuZWxDYXJkLCBhbGxvd0Nsb3NlID0gdHJ1ZSwgcm9vbUlkPzogc3RyaW5nKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHJJZCA9IHJvb21JZCA/PyB0aGlzLnZpZXdlZFJvb21JZCA/PyBcIlwiO1xuICAgICAgICAvLyBUaGlzIGZ1bmN0aW9uIGJlaGF2ZXMgYXMgZm9sbG93aW5nOlxuICAgICAgICAvLyBVcGRhdGUgc3RhdGU6IGlmIHRoZSBzYW1lIHBoYXNlIGlzIHNlbmQgYnV0IHdpdGggYSBzdGF0ZVxuICAgICAgICAvLyBTZXQgcmlnaHQgcGFuZWwgYW5kIGVyYXNlIGhpc3Rvcnk6IGlmIGEgXCJkaWZmZXJlbnQgdG8gdGhlIGN1cnJlbnRcIiBwaGFzZSBpcyBzZW5kICh3aXRoIG9yIHdpdGhvdXQgYSBzdGF0ZSlcbiAgICAgICAgLy8gSWYgdGhlIHJpZ2h0IHBhbmVsIGlzIHNldCwgdGhpcyBmdW5jdGlvbiBhbHNvIHNob3dzIHRoZSByaWdodCBwYW5lbC5cbiAgICAgICAgY29uc3QgcmVkaXJlY3QgPSB0aGlzLmdldFZlcmlmaWNhdGlvblJlZGlyZWN0KGNhcmQpO1xuICAgICAgICBjb25zdCB0YXJnZXRQaGFzZSA9IHJlZGlyZWN0Py5waGFzZSA/PyBjYXJkLnBoYXNlO1xuICAgICAgICBjb25zdCBjYXJkU3RhdGUgPSByZWRpcmVjdD8uc3RhdGUgPz8gKE9iamVjdC5rZXlzKGNhcmQuc3RhdGUgPz8ge30pLmxlbmd0aCA9PT0gMCA/IG51bGwgOiBjYXJkLnN0YXRlKTtcblxuICAgICAgICAvLyBDaGVja3MgZm9yIHdyb25nIFNldFJpZ2h0UGFuZWxQaGFzZSByZXF1ZXN0c1xuICAgICAgICBpZiAoIXRoaXMuaXNQaGFzZVZhbGlkKHRhcmdldFBoYXNlLCBCb29sZWFuKHJJZCkpKSByZXR1cm47XG5cbiAgICAgICAgaWYgKHRhcmdldFBoYXNlID09PSB0aGlzLmN1cnJlbnRDYXJkRm9yUm9vbShySWQpPy5waGFzZSAmJiAhIWNhcmRTdGF0ZSkge1xuICAgICAgICAgICAgLy8gVXBkYXRlIHN0YXRlOiBzZXQgcmlnaHQgcGFuZWwgd2l0aCBhIG5ldyBzdGF0ZSBidXQga2VlcCB0aGUgcGhhc2UgKGRvbid0IGtub3cgaXQgdGhpcyBpcyBldmVyIG5lZWRlZC4uLilcbiAgICAgICAgICAgIGNvbnN0IGhpc3QgPSB0aGlzLmJ5Um9vbVtySWRdPy5oaXN0b3J5ID8/IFtdO1xuICAgICAgICAgICAgaGlzdFtoaXN0Lmxlbmd0aCAtIDFdLnN0YXRlID0gY2FyZFN0YXRlO1xuICAgICAgICAgICAgdGhpcy5lbWl0QW5kVXBkYXRlU2V0dGluZ3MoKTtcbiAgICAgICAgfSBlbHNlIGlmICh0YXJnZXRQaGFzZSAhPT0gdGhpcy5jdXJyZW50Q2FyZEZvclJvb20ocklkKT8ucGhhc2UgfHwgIXRoaXMuYnlSb29tW3JJZF0pIHtcbiAgICAgICAgICAgIC8vIFNldCByaWdodCBwYW5lbCBhbmQgaW5pdGlhbGl6ZS9lcmFzZSBoaXN0b3J5XG4gICAgICAgICAgICBjb25zdCBoaXN0b3J5ID0gW3sgcGhhc2U6IHRhcmdldFBoYXNlLCBzdGF0ZTogY2FyZFN0YXRlID8/IHt9IH1dO1xuICAgICAgICAgICAgdGhpcy5ieVJvb21bcklkXSA9IHsgaGlzdG9yeSwgaXNPcGVuOiB0cnVlIH07XG4gICAgICAgICAgICB0aGlzLmVtaXRBbmRVcGRhdGVTZXR0aW5ncygpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5zaG93KHJJZCk7XG4gICAgICAgICAgICB0aGlzLmVtaXRBbmRVcGRhdGVTZXR0aW5ncygpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIHNldENhcmRzKGNhcmRzOiBJUmlnaHRQYW5lbENhcmRbXSwgYWxsb3dDbG9zZSA9IHRydWUsIHJvb21JZDogc3RyaW5nIHwgbnVsbCA9IG51bGwpOiB2b2lkIHtcbiAgICAgICAgLy8gVGhpcyBmdW5jdGlvbiBzZXRzIHRoZSBoaXN0b3J5IG9mIHRoZSByaWdodCBwYW5lbCBhbmQgc2hvd3MgdGhlIHJpZ2h0IHBhbmVsIGlmIG5vdCBhbHJlYWR5IHZpc2libGUuXG4gICAgICAgIGNvbnN0IHJJZCA9IHJvb21JZCA/PyB0aGlzLnZpZXdlZFJvb21JZCA/PyBcIlwiO1xuICAgICAgICBjb25zdCBoaXN0b3J5ID0gY2FyZHMubWFwKChjKSA9PiAoeyBwaGFzZTogYy5waGFzZSwgc3RhdGU6IGMuc3RhdGUgPz8ge30gfSkpO1xuICAgICAgICB0aGlzLmJ5Um9vbVtySWRdID0geyBoaXN0b3J5LCBpc09wZW46IHRydWUgfTtcbiAgICAgICAgdGhpcy5zaG93KHJJZCk7XG4gICAgICAgIHRoaXMuZW1pdEFuZFVwZGF0ZVNldHRpbmdzKCk7XG4gICAgfVxuXG4gICAgLy8gQXBwZW5kcyBhIGNhcmQgdG8gdGhlIGhpc3RvcnkgYW5kIHNob3dzIHRoZSByaWdodCBwYW5lbCBpZiBub3QgYWxyZWFkeSB2aXNpYmxlXG4gICAgcHVibGljIHB1c2hDYXJkKGNhcmQ6IElSaWdodFBhbmVsQ2FyZCwgYWxsb3dDbG9zZSA9IHRydWUsIHJvb21JZDogc3RyaW5nIHwgbnVsbCA9IG51bGwpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgcklkID0gcm9vbUlkID8/IHRoaXMudmlld2VkUm9vbUlkID8/IFwiXCI7XG4gICAgICAgIGNvbnN0IHJlZGlyZWN0ID0gdGhpcy5nZXRWZXJpZmljYXRpb25SZWRpcmVjdChjYXJkKTtcbiAgICAgICAgY29uc3QgdGFyZ2V0UGhhc2UgPSByZWRpcmVjdD8ucGhhc2UgPz8gY2FyZC5waGFzZTtcbiAgICAgICAgY29uc3QgcFN0YXRlID0gcmVkaXJlY3Q/LnN0YXRlID8/IGNhcmQuc3RhdGUgPz8ge307XG5cbiAgICAgICAgLy8gQ2hlY2tzIGZvciB3cm9uZyBTZXRSaWdodFBhbmVsUGhhc2UgcmVxdWVzdHNcbiAgICAgICAgaWYgKCF0aGlzLmlzUGhhc2VWYWxpZCh0YXJnZXRQaGFzZSwgQm9vbGVhbihySWQpKSkgcmV0dXJuO1xuXG4gICAgICAgIGNvbnN0IHJvb21DYWNoZSA9IHRoaXMuYnlSb29tW3JJZF07XG4gICAgICAgIGlmICghIXJvb21DYWNoZSkge1xuICAgICAgICAgICAgLy8gYXBwZW5kIG5ldyBwaGFzZVxuICAgICAgICAgICAgcm9vbUNhY2hlLmhpc3RvcnkucHVzaCh7IHN0YXRlOiBwU3RhdGUsIHBoYXNlOiB0YXJnZXRQaGFzZSB9KTtcbiAgICAgICAgICAgIHJvb21DYWNoZS5pc09wZW4gPSBhbGxvd0Nsb3NlID8gcm9vbUNhY2hlLmlzT3BlbiA6IHRydWU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBzZXR1cCByb29tIHBhbmVsIGNhY2hlIHdpdGggdGhlIG5ldyBjYXJkXG4gICAgICAgICAgICB0aGlzLmJ5Um9vbVtySWRdID0ge1xuICAgICAgICAgICAgICAgIGhpc3Rvcnk6IFt7IHBoYXNlOiB0YXJnZXRQaGFzZSwgc3RhdGU6IHBTdGF0ZSB9XSxcbiAgICAgICAgICAgICAgICAvLyBpZiB0aGVyZSB3YXMgbm8gcmlnaHQgcGFuZWwgc3RvcmUgb2JqZWN0IHRoZSB0aGUgcGFuZWwgd2FzIGNsb3NlZCAtPiBrZWVwIGl0IGNsb3NlZCwgZXhjZXB0IGlmIGFsbG93Q2xvc2U9PWZhbHNlXG4gICAgICAgICAgICAgICAgaXNPcGVuOiAhYWxsb3dDbG9zZSxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5zaG93KHJJZCk7XG4gICAgICAgIHRoaXMuZW1pdEFuZFVwZGF0ZVNldHRpbmdzKCk7XG4gICAgfVxuXG4gICAgcHVibGljIHBvcENhcmQocm9vbUlkOiBzdHJpbmcgfCBudWxsID0gbnVsbCk6IElSaWdodFBhbmVsQ2FyZCB8IHVuZGVmaW5lZCB7XG4gICAgICAgIGNvbnN0IHJJZCA9IHJvb21JZCA/PyB0aGlzLnZpZXdlZFJvb21JZCA/PyBcIlwiO1xuICAgICAgICBpZiAoIXRoaXMuYnlSb29tW3JJZF0pIHJldHVybjtcblxuICAgICAgICBjb25zdCByZW1vdmVkQ2FyZCA9IHRoaXMuYnlSb29tW3JJZF0uaGlzdG9yeS5wb3AoKTtcbiAgICAgICAgdGhpcy5lbWl0QW5kVXBkYXRlU2V0dGluZ3MoKTtcbiAgICAgICAgcmV0dXJuIHJlbW92ZWRDYXJkO1xuICAgIH1cblxuICAgIHB1YmxpYyB0b2dnbGVQYW5lbChyb29tSWQ6IHN0cmluZyB8IG51bGwpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgcklkID0gcm9vbUlkID8/IHRoaXMudmlld2VkUm9vbUlkID8/IFwiXCI7XG4gICAgICAgIGlmICghdGhpcy5ieVJvb21bcklkXSkgcmV0dXJuO1xuXG4gICAgICAgIHRoaXMuYnlSb29tW3JJZF0uaXNPcGVuID0gIXRoaXMuYnlSb29tW3JJZF0uaXNPcGVuO1xuICAgICAgICB0aGlzLmVtaXRBbmRVcGRhdGVTZXR0aW5ncygpO1xuICAgIH1cblxuICAgIHB1YmxpYyBzaG93KHJvb21JZDogc3RyaW5nIHwgbnVsbCk6IHZvaWQge1xuICAgICAgICBpZiAoIXRoaXMuaXNPcGVuRm9yUm9vbShyb29tSWQgPz8gdGhpcy52aWV3ZWRSb29tSWQgPz8gXCJcIikpIHtcbiAgICAgICAgICAgIHRoaXMudG9nZ2xlUGFuZWwocm9vbUlkKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBoaWRlKHJvb21JZDogc3RyaW5nIHwgbnVsbCk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5pc09wZW5Gb3JSb29tKHJvb21JZCA/PyB0aGlzLnZpZXdlZFJvb21JZCA/PyBcIlwiKSkge1xuICAgICAgICAgICAgdGhpcy50b2dnbGVQYW5lbChyb29tSWQpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSGVscGVyIHRvIHNob3cgYSByaWdodCBwYW5lbCBwaGFzZS5cbiAgICAgKiBJZiB0aGUgVUkgaXMgYWxyZWFkeSBzaG93aW5nIHRoYXQgcGhhc2UsIHRoZSByaWdodCBwYW5lbCB3aWxsIGJlIGhpZGRlbi5cbiAgICAgKlxuICAgICAqIENhbGxpbmcgdGhlIHNhbWUgcGhhc2UgdHdpY2Ugd2l0aCBhIGRpZmZlcmVudCBzdGF0ZSB3aWxsIHVwZGF0ZSB0aGUgY3VycmVudFxuICAgICAqIHBoYXNlIGFuZCBwdXNoIHRoZSBvbGQgc3RhdGUgaW4gdGhlIHJpZ2h0IHBhbmVsIGhpc3RvcnkuXG4gICAgICogQHBhcmFtIHBoYXNlIFRoZSByaWdodCBwYW5lbCBwaGFzZS5cbiAgICAgKiBAcGFyYW0gY2FyZFN0YXRlIFRoZSBzdGF0ZSB3aXRoaW4gdGhlIHBoYXNlLlxuICAgICAqL1xuICAgIHB1YmxpYyBzaG93T3JIaWRlUGhhc2UocGhhc2U6IFJpZ2h0UGFuZWxQaGFzZXMsIGNhcmRTdGF0ZT86IFBhcnRpYWw8SVJpZ2h0UGFuZWxDYXJkU3RhdGU+KTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmN1cnJlbnRDYXJkLnBoYXNlID09IHBoYXNlICYmICFjYXJkU3RhdGUgJiYgdGhpcy5pc09wZW4pIHtcbiAgICAgICAgICAgIHRoaXMudG9nZ2xlUGFuZWwobnVsbCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnNldENhcmQoeyBwaGFzZSwgc3RhdGU6IGNhcmRTdGF0ZSB9KTtcbiAgICAgICAgICAgIGlmICghdGhpcy5pc09wZW4pIHRoaXMudG9nZ2xlUGFuZWwobnVsbCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGxvYWRDYWNoZUZyb21TZXR0aW5ncygpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMudmlld2VkUm9vbUlkKSB7XG4gICAgICAgICAgICBjb25zdCByb29tID0gdGhpcy5teENsaWVudD8uZ2V0Um9vbSh0aGlzLnZpZXdlZFJvb21JZCk7XG4gICAgICAgICAgICBpZiAoISFyb29tKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5nbG9iYWwgPVxuICAgICAgICAgICAgICAgICAgICB0aGlzLmdsb2JhbCA/PyBjb252ZXJ0VG9TdGF0ZVBhbmVsKFNldHRpbmdzU3RvcmUuZ2V0VmFsdWUoXCJSaWdodFBhbmVsLnBoYXNlc0dsb2JhbFwiKSwgcm9vbSk7XG4gICAgICAgICAgICAgICAgdGhpcy5ieVJvb21bdGhpcy52aWV3ZWRSb29tSWRdID1cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5ieVJvb21bdGhpcy52aWV3ZWRSb29tSWRdID8/XG4gICAgICAgICAgICAgICAgICAgIGNvbnZlcnRUb1N0YXRlUGFuZWwoU2V0dGluZ3NTdG9yZS5nZXRWYWx1ZShcIlJpZ2h0UGFuZWwucGhhc2VzXCIsIHRoaXMudmlld2VkUm9vbUlkKSwgcm9vbSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGxvZ2dlci53YXJuKFxuICAgICAgICAgICAgICAgICAgICBcIkNvdWxkIG5vdCByZXN0b3JlIHRoZSByaWdodCBwYW5lbCBhZnRlciBsb2FkIGJlY2F1c2UgdGhlcmUgd2FzIG5vIGFzc29jaWF0ZWQgcm9vbSBvYmplY3QuXCIsXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgZW1pdEFuZFVwZGF0ZVNldHRpbmdzKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmZpbHRlclZhbGlkQ2FyZHModGhpcy5nbG9iYWwpO1xuICAgICAgICBjb25zdCBzdG9yZVBhbmVsR2xvYmFsID0gY29udmVydFRvU3RvcmVQYW5lbCh0aGlzLmdsb2JhbCk7XG4gICAgICAgIFNldHRpbmdzU3RvcmUuc2V0VmFsdWUoXCJSaWdodFBhbmVsLnBoYXNlc0dsb2JhbFwiLCBudWxsLCBTZXR0aW5nTGV2ZWwuREVWSUNFLCBzdG9yZVBhbmVsR2xvYmFsKTtcblxuICAgICAgICBpZiAoISF0aGlzLnZpZXdlZFJvb21JZCkge1xuICAgICAgICAgICAgY29uc3QgcGFuZWxUaGlzUm9vbSA9IHRoaXMuYnlSb29tW3RoaXMudmlld2VkUm9vbUlkXTtcbiAgICAgICAgICAgIHRoaXMuZmlsdGVyVmFsaWRDYXJkcyhwYW5lbFRoaXNSb29tKTtcbiAgICAgICAgICAgIGNvbnN0IHN0b3JlUGFuZWxUaGlzUm9vbSA9IGNvbnZlcnRUb1N0b3JlUGFuZWwocGFuZWxUaGlzUm9vbSk7XG4gICAgICAgICAgICBTZXR0aW5nc1N0b3JlLnNldFZhbHVlKFxuICAgICAgICAgICAgICAgIFwiUmlnaHRQYW5lbC5waGFzZXNcIixcbiAgICAgICAgICAgICAgICB0aGlzLnZpZXdlZFJvb21JZCxcbiAgICAgICAgICAgICAgICBTZXR0aW5nTGV2ZWwuUk9PTV9ERVZJQ0UsXG4gICAgICAgICAgICAgICAgc3RvcmVQYW5lbFRoaXNSb29tLFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmVtaXQoVVBEQVRFX0VWRU5ULCBudWxsKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGZpbHRlclZhbGlkQ2FyZHMocmlnaHRQYW5lbEZvclJvb20/OiBJUmlnaHRQYW5lbEZvclJvb20pOiB2b2lkIHtcbiAgICAgICAgaWYgKCFyaWdodFBhbmVsRm9yUm9vbT8uaGlzdG9yeSkgcmV0dXJuO1xuICAgICAgICByaWdodFBhbmVsRm9yUm9vbS5oaXN0b3J5ID0gcmlnaHRQYW5lbEZvclJvb20uaGlzdG9yeS5maWx0ZXIoKGNhcmQpID0+IHRoaXMuaXNDYXJkU3RhdGVWYWxpZChjYXJkKSk7XG4gICAgICAgIGlmICghcmlnaHRQYW5lbEZvclJvb20uaGlzdG9yeS5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJpZ2h0UGFuZWxGb3JSb29tLmlzT3BlbiA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBpc0NhcmRTdGF0ZVZhbGlkKGNhcmQ6IElSaWdodFBhbmVsQ2FyZCk6IGJvb2xlYW4ge1xuICAgICAgICAvLyB0aGlzIGZ1bmN0aW9uIGRvZXMgYSBzYW5pdHkgY2hlY2sgb24gdGhlIGNhcmQuIHRoaXMgaXMgcmVxdWlyZWQgYmVjYXVzZVxuICAgICAgICAvLyBzb21lIHBoYXNlcyByZXF1aXJlIHNwZWNpZmljIHN0YXRlIHByb3BlcnRpZXMgdGhhdCBtaWdodCBub3QgYmUgYXZhaWxhYmxlLlxuICAgICAgICAvLyBUaGlzIGNhbiBiZSBjYXVzZWQgb24gaWYgZWxlbWVudCBpcyByZWxvYWRlZCBhbmQgdGhlIHRyaWVzIHRvIHJlbG9hZCByaWdodCBwYW5lbCBkYXRhIGZyb20gaWQncyBzdG9yZWQgaW4gdGhlIGxvY2FsIHN0b3JhZ2UuXG4gICAgICAgIC8vIHdlIHN0b3JlIGlkJ3Mgb2YgdXNlcnMgYW5kIG1hdHJpeCBldmVudHMuIElmIGFyZSBub3QgeWV0IGZldGNoZWQgb24gcmVsb2FkIHRoZSByaWdodCBwYW5lbCBjYW5ub3QgZGlzcGxheSB0aGVtLlxuICAgICAgICAvLyBvciBwb3RlbnRpYWxseSBvdGhlciBlcnJvcnMuXG4gICAgICAgIC8vIChBIG5pY2VyIGZpeCBjb3VsZCBiZSB0byBpbmRpY2F0ZSwgdGhhdCB0aGUgcmlnaHQgcGFuZWwgaXMgbG9hZGluZyBpZiB0aGVyZSBpcyBtaXNzaW5nIHN0YXRlIGRhdGEgYW5kIHJlLWVtaXQgaWYgdGhlIGRhdGEgaXMgYXZhaWxhYmxlKVxuICAgICAgICBzd2l0Y2ggKGNhcmQucGhhc2UpIHtcbiAgICAgICAgICAgIGNhc2UgUmlnaHRQYW5lbFBoYXNlcy5UaHJlYWRWaWV3OlxuICAgICAgICAgICAgICAgIGlmICghY2FyZC5zdGF0ZT8udGhyZWFkSGVhZEV2ZW50KSB7XG4gICAgICAgICAgICAgICAgICAgIGxvZ2dlci53YXJuKFwicmVtb3ZlZCBjYXJkIGZyb20gcmlnaHQgcGFuZWwgYmVjYXVzZSBvZiBtaXNzaW5nIHRocmVhZEhlYWRFdmVudCBpbiBjYXJkIHN0YXRlXCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gISFjYXJkLnN0YXRlPy50aHJlYWRIZWFkRXZlbnQ7XG4gICAgICAgICAgICBjYXNlIFJpZ2h0UGFuZWxQaGFzZXMuUm9vbU1lbWJlckluZm86XG4gICAgICAgICAgICBjYXNlIFJpZ2h0UGFuZWxQaGFzZXMuU3BhY2VNZW1iZXJJbmZvOlxuICAgICAgICAgICAgY2FzZSBSaWdodFBhbmVsUGhhc2VzLkVuY3J5cHRpb25QYW5lbDpcbiAgICAgICAgICAgICAgICBpZiAoIWNhcmQuc3RhdGU/Lm1lbWJlcikge1xuICAgICAgICAgICAgICAgICAgICBsb2dnZXIud2FybihcInJlbW92ZWQgY2FyZCBmcm9tIHJpZ2h0IHBhbmVsIGJlY2F1c2Ugb2YgbWlzc2luZyBtZW1iZXIgaW4gY2FyZCBzdGF0ZVwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuICEhY2FyZC5zdGF0ZT8ubWVtYmVyO1xuICAgICAgICAgICAgY2FzZSBSaWdodFBhbmVsUGhhc2VzLlJvb20zcGlkTWVtYmVySW5mbzpcbiAgICAgICAgICAgIGNhc2UgUmlnaHRQYW5lbFBoYXNlcy5TcGFjZTNwaWRNZW1iZXJJbmZvOlxuICAgICAgICAgICAgICAgIGlmICghY2FyZC5zdGF0ZT8ubWVtYmVySW5mb0V2ZW50KSB7XG4gICAgICAgICAgICAgICAgICAgIGxvZ2dlci53YXJuKFwicmVtb3ZlZCBjYXJkIGZyb20gcmlnaHQgcGFuZWwgYmVjYXVzZSBvZiBtaXNzaW5nIG1lbWJlckluZm9FdmVudCBpbiBjYXJkIHN0YXRlXCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gISFjYXJkLnN0YXRlPy5tZW1iZXJJbmZvRXZlbnQ7XG4gICAgICAgICAgICBjYXNlIFJpZ2h0UGFuZWxQaGFzZXMuV2lkZ2V0OlxuICAgICAgICAgICAgICAgIGlmICghY2FyZC5zdGF0ZT8ud2lkZ2V0SWQpIHtcbiAgICAgICAgICAgICAgICAgICAgbG9nZ2VyLndhcm4oXCJyZW1vdmVkIGNhcmQgZnJvbSByaWdodCBwYW5lbCBiZWNhdXNlIG9mIG1pc3Npbmcgd2lkZ2V0SWQgaW4gY2FyZCBzdGF0ZVwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuICEhY2FyZC5zdGF0ZT8ud2lkZ2V0SWQ7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRWZXJpZmljYXRpb25SZWRpcmVjdChjYXJkOiBJUmlnaHRQYW5lbENhcmQpOiBJUmlnaHRQYW5lbENhcmQgfCBudWxsIHtcbiAgICAgICAgaWYgKGNhcmQucGhhc2UgPT09IFJpZ2h0UGFuZWxQaGFzZXMuUm9vbU1lbWJlckluZm8gJiYgY2FyZC5zdGF0ZSkge1xuICAgICAgICAgICAgLy8gUmlnaHRQYW5lbFBoYXNlcy5Sb29tTWVtYmVySW5mbyAtPiBuZWVkcyB0byBiZSBjaGFuZ2VkIHRvIFJpZ2h0UGFuZWxQaGFzZXMuRW5jcnlwdGlvblBhbmVsIGlmIHRoZXJlIGlzIGEgcGVuZGluZyB2ZXJpZmljYXRpb24gcmVxdWVzdFxuICAgICAgICAgICAgY29uc3QgeyBtZW1iZXIgfSA9IGNhcmQuc3RhdGU7XG4gICAgICAgICAgICBjb25zdCBwZW5kaW5nUmVxdWVzdCA9IG1lbWJlclxuICAgICAgICAgICAgICAgID8gcGVuZGluZ1ZlcmlmaWNhdGlvblJlcXVlc3RGb3JVc2VyKE1hdHJpeENsaWVudFBlZy5zYWZlR2V0KCksIG1lbWJlcilcbiAgICAgICAgICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIGlmIChwZW5kaW5nUmVxdWVzdCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgIHBoYXNlOiBSaWdodFBhbmVsUGhhc2VzLkVuY3J5cHRpb25QYW5lbCxcbiAgICAgICAgICAgICAgICAgICAgc3RhdGU6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZlcmlmaWNhdGlvblJlcXVlc3Q6IHBlbmRpbmdSZXF1ZXN0LFxuICAgICAgICAgICAgICAgICAgICAgICAgbWVtYmVyLFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBpc1BoYXNlVmFsaWQodGFyZ2V0UGhhc2U6IFJpZ2h0UGFuZWxQaGFzZXMgfCBudWxsLCBpc1ZpZXdpbmdSb29tOiBib29sZWFuKTogYm9vbGVhbiB7XG4gICAgICAgIGlmICghdGFyZ2V0UGhhc2UgfHwgIVJpZ2h0UGFuZWxQaGFzZXNbdGFyZ2V0UGhhc2VdKSB7XG4gICAgICAgICAgICBsb2dnZXIud2FybihgVHJpZWQgdG8gc3dpdGNoIHJpZ2h0IHBhbmVsIHRvIHVua25vd24gcGhhc2U6ICR7dGFyZ2V0UGhhc2V9YCk7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFpc1ZpZXdpbmdSb29tKSB7XG4gICAgICAgICAgICBsb2dnZXIud2FybihcbiAgICAgICAgICAgICAgICBgVHJpZWQgdG8gc3dpdGNoIHJpZ2h0IHBhbmVsIHRvIGEgcm9vbSBwaGFzZTogJHt0YXJnZXRQaGFzZX0sIGAgK1xuICAgICAgICAgICAgICAgICAgICBgYnV0IHdlIGFyZSBjdXJyZW50bHkgbm90IHZpZXdpbmcgYSByb29tYCxcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvblZlcmlmaWNhdGlvblJlcXVlc3RVcGRhdGUgPSAoKTogdm9pZCA9PiB7XG4gICAgICAgIGlmICghdGhpcy5jdXJyZW50Q2FyZD8uc3RhdGUpIHJldHVybjtcbiAgICAgICAgY29uc3QgeyBtZW1iZXIgfSA9IHRoaXMuY3VycmVudENhcmQuc3RhdGU7XG4gICAgICAgIGlmICghbWVtYmVyKSByZXR1cm47XG4gICAgICAgIGNvbnN0IHBlbmRpbmdSZXF1ZXN0ID0gcGVuZGluZ1ZlcmlmaWNhdGlvblJlcXVlc3RGb3JVc2VyKE1hdHJpeENsaWVudFBlZy5zYWZlR2V0KCksIG1lbWJlcik7XG4gICAgICAgIGlmIChwZW5kaW5nUmVxdWVzdCkge1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50Q2FyZC5zdGF0ZS52ZXJpZmljYXRpb25SZXF1ZXN0ID0gcGVuZGluZ1JlcXVlc3Q7XG4gICAgICAgICAgICB0aGlzLmVtaXRBbmRVcGRhdGVTZXR0aW5ncygpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHByaXZhdGUgaGFuZGxlVmlld2VkUm9vbUNoYW5nZShvbGRSb29tSWQ6IE9wdGlvbmFsPHN0cmluZz4sIG5ld1Jvb21JZDogT3B0aW9uYWw8c3RyaW5nPik6IHZvaWQge1xuICAgICAgICBpZiAoIXRoaXMubXhDbGllbnQpIHJldHVybjsgLy8gbm90IHJlYWR5LCBvblJlYWR5IHdpbGwgaGFuZGxlIHRoZSBmaXJzdCByb29tXG4gICAgICAgIHRoaXMudmlld2VkUm9vbUlkID0gbmV3Um9vbUlkO1xuICAgICAgICAvLyBsb2FkIHZhbHVlcyBmcm9tIGJ5Um9vbUNhY2hlIHdpdGggdGhlIHZpZXdlZFJvb21JZC5cbiAgICAgICAgdGhpcy5sb2FkQ2FjaGVGcm9tU2V0dGluZ3MoKTtcblxuICAgICAgICAvLyB3aGVuIHdlJ3JlIHN3aXRjaGluZyB0byBhIHJvb20sIGNsZWFyIG91dCBhbnkgc3RhbGUgTWVtYmVySW5mbyBjYXJkc1xuICAgICAgICAvLyBpbiBvcmRlciB0byBmaXggaHR0cHM6Ly9naXRodWIuY29tL3ZlY3Rvci1pbS9lbGVtZW50LXdlYi9pc3N1ZXMvMjE0ODdcbiAgICAgICAgaWYgKHRoaXMuY3VycmVudENhcmQ/LnBoYXNlICE9PSBSaWdodFBhbmVsUGhhc2VzLkVuY3J5cHRpb25QYW5lbCkge1xuICAgICAgICAgICAgY29uc3QgcGFuZWwgPSB0aGlzLmJ5Um9vbVt0aGlzLnZpZXdlZFJvb21JZCA/PyBcIlwiXTtcbiAgICAgICAgICAgIGlmIChwYW5lbD8uaGlzdG9yeSkge1xuICAgICAgICAgICAgICAgIHBhbmVsLmhpc3RvcnkgPSBwYW5lbC5oaXN0b3J5LmZpbHRlcihcbiAgICAgICAgICAgICAgICAgICAgKGNhcmQ6IElSaWdodFBhbmVsQ2FyZCkgPT5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNhcmQucGhhc2UgIT0gUmlnaHRQYW5lbFBoYXNlcy5Sb29tTWVtYmVySW5mbyAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgY2FyZC5waGFzZSAhPSBSaWdodFBhbmVsUGhhc2VzLlJvb20zcGlkTWVtYmVySW5mbyxcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vIHdoZW4gd2UncmUgc3dpdGNoaW5nIHRvIGEgcm9vbSwgY2xlYXIgb3V0IHRocmVhZCBwZXJtYWxpbmtzIHRvIG5vdCBnZXQgeW91IHN0dWNrIGluIHRoZSBtaWRkbGUgb2YgdGhlIHRocmVhZFxuICAgICAgICAvLyBpbiBvcmRlciB0byBmaXggaHR0cHM6Ly9naXRodWIuY29tL21hdHJpeC1vcmcvbWF0cml4LXJlYWN0LXNkay9wdWxsLzExMDExXG4gICAgICAgIGlmICh0aGlzLmN1cnJlbnRDYXJkPy5waGFzZSA9PT0gUmlnaHRQYW5lbFBoYXNlcy5UaHJlYWRWaWV3ICYmIHRoaXMuY3VycmVudENhcmQuc3RhdGUpIHtcbiAgICAgICAgICAgIHRoaXMuY3VycmVudENhcmQuc3RhdGUuaW5pdGlhbEV2ZW50ID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50Q2FyZC5zdGF0ZS5pc0luaXRpYWxFdmVudEhpZ2hsaWdodGVkID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50Q2FyZC5zdGF0ZS5pbml0aWFsRXZlbnRTY3JvbGxJbnRvVmlldyA9IHVuZGVmaW5lZDtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuZW1pdEFuZFVwZGF0ZVNldHRpbmdzKCk7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBnZXQgaW5zdGFuY2UoKTogUmlnaHRQYW5lbFN0b3JlIHtcbiAgICAgICAgaWYgKCF0aGlzLmludGVybmFsSW5zdGFuY2UpIHtcbiAgICAgICAgICAgIHRoaXMuaW50ZXJuYWxJbnN0YW5jZSA9IG5ldyBSaWdodFBhbmVsU3RvcmUoKTtcbiAgICAgICAgICAgIHRoaXMuaW50ZXJuYWxJbnN0YW5jZS5zdGFydCgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLmludGVybmFsSW5zdGFuY2U7XG4gICAgfVxufVxuXG53aW5kb3cubXhSaWdodFBhbmVsU3RvcmUgPSBSaWdodFBhbmVsU3RvcmUuaW5zdGFuY2U7XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7O0FBUUEsSUFBQUEsT0FBQSxHQUFBQyxPQUFBO0FBQ0EsSUFBQUMsT0FBQSxHQUFBRCxPQUFBO0FBR0EsSUFBQUUsV0FBQSxHQUFBQyxzQkFBQSxDQUFBSCxPQUFBO0FBQ0EsSUFBQUksYUFBQSxHQUFBSixPQUFBO0FBQ0EsSUFBQUssY0FBQSxHQUFBRixzQkFBQSxDQUFBSCxPQUFBO0FBQ0EsSUFBQU0sc0JBQUEsR0FBQU4sT0FBQTtBQUNBLElBQUFPLGFBQUEsR0FBQVAsT0FBQTtBQUNBLElBQUFRLFdBQUEsR0FBQVIsT0FBQTtBQUNBLElBQUFTLG1CQUFBLEdBQUFULE9BQUE7QUFDQSxJQUFBVSwyQkFBQSxHQUFBVixPQUFBO0FBUUEsSUFBQVcsUUFBQSxHQUFBWCxPQUFBO0FBRUEsSUFBQVksV0FBQSxHQUFBWixPQUFBO0FBQ0EsSUFBQWEsZ0JBQUEsR0FBQWIsT0FBQTtBQTlCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUEwQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ2UsTUFBTWMsZUFBZSxTQUFTQyxzQ0FBa0IsQ0FBQztFQU9wREMsV0FBV0EsQ0FBQSxFQUFHO0lBQ2xCLEtBQUssQ0FBQ0MsbUJBQWlCLENBQUM7SUFBQyxJQUFBQyxnQkFBQSxDQUFBQyxPQUFBO0lBQUEsSUFBQUQsZ0JBQUEsQ0FBQUMsT0FBQSxrQkFKOEIsQ0FBQyxDQUFDO0lBQUEsSUFBQUQsZ0JBQUEsQ0FBQUMsT0FBQTtJQUFBLElBQUFELGdCQUFBLENBQUFDLE9BQUEsdUNBZ1V2QixNQUFZO01BQzlDLElBQUksQ0FBQyxJQUFJLENBQUNDLFdBQVcsRUFBRUMsS0FBSyxFQUFFO01BQzlCLE1BQU07UUFBRUM7TUFBTyxD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