UNPKG

matrix-react-sdk

Version:
402 lines (390 loc) 58 kB
"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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