matrix-react-sdk
Version:
SDK for matrix.org using React
350 lines (342 loc) • 55.9 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 _react = _interopRequireDefault(require("react"));
var _logger = require("matrix-js-sdk/src/logger");
var _languageHandler = require("../../../languageHandler");
var _MatrixClientPeg = require("../../../MatrixClientPeg");
var _Modal = _interopRequireDefault(require("../../../Modal"));
var _dispatcher = _interopRequireDefault(require("../../../dispatcher/dispatcher"));
var _boundThreepids = require("../../../boundThreepids");
var _IdentityAuthClient = _interopRequireDefault(require("../../../IdentityAuthClient"));
var _UrlUtils = require("../../../utils/UrlUtils");
var _IdentityServerUtils = require("../../../utils/IdentityServerUtils");
var _promise = require("../../../utils/promise");
var _InlineSpinner = _interopRequireDefault(require("../elements/InlineSpinner"));
var _AccessibleButton = _interopRequireDefault(require("../elements/AccessibleButton"));
var _Field = _interopRequireDefault(require("../elements/Field"));
var _QuestionDialog = _interopRequireDefault(require("../dialogs/QuestionDialog"));
var _SettingsFieldset = _interopRequireDefault(require("./SettingsFieldset"));
var _SettingsSubsection = require("./shared/SettingsSubsection");
/*
Copyright 2024 New Vector Ltd.
Copyright 2019-2021 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.
*/
// We'll wait up to this long when checking for 3PID bindings on the IS.
const REACHABILITY_TIMEOUT = 10000; // ms
/**
* Check an IS URL is valid, including liveness check
*
* @param {string} u The url to check
* @returns {string} null if url passes all checks, otherwise i18ned error string
*/
async function checkIdentityServerUrl(u) {
const parsedUrl = (0, _UrlUtils.parseUrl)(u);
if (parsedUrl.protocol !== "https:") return (0, _languageHandler._t)("identity_server|url_not_https");
// XXX: duplicated logic from js-sdk but it's quite tied up in the validation logic in the
// js-sdk so probably as easy to duplicate it than to separate it out so we can reuse it
try {
const response = await fetch(u + "/_matrix/identity/v2");
if (response.ok) {
return null;
} else if (response.status < 200 || response.status >= 300) {
return (0, _languageHandler._t)("identity_server|error_invalid", {
code: response.status
});
} else {
return (0, _languageHandler._t)("identity_server|error_connection");
}
} catch (e) {
return (0, _languageHandler._t)("identity_server|error_connection");
}
}
class SetIdServer extends _react.default.Component {
constructor(props) {
super(props);
(0, _defineProperty2.default)(this, "dispatcherRef", void 0);
(0, _defineProperty2.default)(this, "onAction", payload => {
// We react to changes in the identity server in the event the user is staring at this form
// when changing their identity server on another device.
if (payload.action !== "id_server_changed") return;
this.setState({
currentClientIdServer: _MatrixClientPeg.MatrixClientPeg.safeGet().getIdentityServerUrl()
});
});
(0, _defineProperty2.default)(this, "onIdentityServerChanged", ev => {
const u = ev.target.value;
this.setState({
idServer: u
});
});
(0, _defineProperty2.default)(this, "getTooltip", () => {
if (this.state.checking) {
return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_InlineSpinner.default, null), (0, _languageHandler._t)("identity_server|checking"));
} else if (this.state.error) {
return /*#__PURE__*/_react.default.createElement("strong", {
className: "warning"
}, this.state.error);
} else {
return null;
}
});
(0, _defineProperty2.default)(this, "idServerChangeEnabled", () => {
return !!this.state.idServer && !this.state.busy;
});
(0, _defineProperty2.default)(this, "saveIdServer", fullUrl => {
// Account data change will update localstorage, client, etc through dispatcher
_MatrixClientPeg.MatrixClientPeg.safeGet().setAccountData("m.identity_server", {
base_url: fullUrl
});
this.setState({
busy: false,
error: undefined,
currentClientIdServer: fullUrl,
idServer: ""
});
});
(0, _defineProperty2.default)(this, "checkIdServer", async e => {
e.preventDefault();
const {
idServer,
currentClientIdServer
} = this.state;
this.setState({
busy: true,
checking: true,
error: undefined
});
const fullUrl = (0, _UrlUtils.unabbreviateUrl)(idServer);
let errStr = await checkIdentityServerUrl(fullUrl);
if (!errStr) {
try {
this.setState({
checking: false
}); // clear tooltip
// Test the identity server by trying to register with it. This
// may result in a terms of service prompt.
const authClient = new _IdentityAuthClient.default(fullUrl);
await authClient.getAccessToken();
let save = true;
// Double check that the identity server even has terms of service.
const hasTerms = await (0, _IdentityServerUtils.doesIdentityServerHaveTerms)(_MatrixClientPeg.MatrixClientPeg.safeGet(), fullUrl);
if (!hasTerms) {
const [confirmed] = await this.showNoTermsWarning(fullUrl);
save = !!confirmed;
}
// Show a general warning, possibly with details about any bound
// 3PIDs that would be left behind.
if (save && currentClientIdServer && fullUrl !== currentClientIdServer) {
const [confirmed] = await this.showServerChangeWarning({
title: (0, _languageHandler._t)("identity_server|change"),
unboundMessage: (0, _languageHandler._t)("identity_server|change_prompt", {}, {
current: sub => /*#__PURE__*/_react.default.createElement("strong", null, (0, _UrlUtils.abbreviateUrl)(currentClientIdServer)),
new: sub => /*#__PURE__*/_react.default.createElement("strong", null, (0, _UrlUtils.abbreviateUrl)(idServer))
}),
button: (0, _languageHandler._t)("action|continue")
});
save = !!confirmed;
}
if (save) {
this.saveIdServer(fullUrl);
}
} catch (e) {
_logger.logger.error(e);
errStr = (0, _languageHandler._t)("identity_server|error_invalid_or_terms");
}
}
this.setState({
busy: false,
checking: false,
error: errStr ?? undefined,
currentClientIdServer: _MatrixClientPeg.MatrixClientPeg.safeGet().getIdentityServerUrl()
});
});
(0, _defineProperty2.default)(this, "onDisconnectClicked", async () => {
this.setState({
disconnectBusy: true
});
try {
const [confirmed] = await this.showServerChangeWarning({
title: (0, _languageHandler._t)("identity_server|disconnect"),
unboundMessage: (0, _languageHandler._t)("identity_server|disconnect_server", {}, {
idserver: sub => /*#__PURE__*/_react.default.createElement("strong", null, (0, _UrlUtils.abbreviateUrl)(this.state.currentClientIdServer))
}),
button: (0, _languageHandler._t)("action|disconnect")
});
if (confirmed) {
this.disconnectIdServer();
}
} finally {
this.setState({
disconnectBusy: false
});
}
});
(0, _defineProperty2.default)(this, "disconnectIdServer", () => {
// Account data change will update localstorage, client, etc through dispatcher
_MatrixClientPeg.MatrixClientPeg.safeGet().setAccountData("m.identity_server", {
base_url: null // clear
});
let newFieldVal = "";
if ((0, _IdentityServerUtils.getDefaultIdentityServerUrl)()) {
// Prepopulate the client's default so the user at least has some idea of
// a valid value they might enter
newFieldVal = (0, _UrlUtils.abbreviateUrl)((0, _IdentityServerUtils.getDefaultIdentityServerUrl)());
}
this.setState({
busy: false,
error: undefined,
currentClientIdServer: _MatrixClientPeg.MatrixClientPeg.safeGet().getIdentityServerUrl(),
idServer: newFieldVal
});
});
let defaultIdServer = "";
if (!_MatrixClientPeg.MatrixClientPeg.safeGet().getIdentityServerUrl() && (0, _IdentityServerUtils.getDefaultIdentityServerUrl)()) {
// If no identity server is configured but there's one in the config, prepopulate
// the field to help the user.
defaultIdServer = (0, _UrlUtils.abbreviateUrl)((0, _IdentityServerUtils.getDefaultIdentityServerUrl)());
}
this.state = {
defaultIdServer,
currentClientIdServer: _MatrixClientPeg.MatrixClientPeg.safeGet().getIdentityServerUrl(),
idServer: "",
busy: false,
disconnectBusy: false,
checking: false
};
}
componentDidMount() {
this.dispatcherRef = _dispatcher.default.register(this.onAction);
}
componentWillUnmount() {
if (this.dispatcherRef) _dispatcher.default.unregister(this.dispatcherRef);
}
showNoTermsWarning(fullUrl) {
const {
finished
} = _Modal.default.createDialog(_QuestionDialog.default, {
title: (0, _languageHandler._t)("terms|identity_server_no_terms_title"),
description: /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("strong", {
className: "warning"
}, (0, _languageHandler._t)("identity_server|no_terms")), /*#__PURE__*/_react.default.createElement("span", null, "\xA0", (0, _languageHandler._t)("terms|identity_server_no_terms_description_2"))),
button: (0, _languageHandler._t)("action|continue")
});
return finished;
}
async showServerChangeWarning({
title,
unboundMessage,
button
}) {
const {
currentClientIdServer
} = this.state;
let threepids = [];
let currentServerReachable = true;
try {
threepids = await (0, _promise.timeout)((0, _boundThreepids.getThreepidsWithBindStatus)(_MatrixClientPeg.MatrixClientPeg.safeGet()), Promise.reject(new Error("Timeout attempting to reach identity server")), REACHABILITY_TIMEOUT);
} catch (e) {
currentServerReachable = false;
_logger.logger.warn(`Unable to reach identity server at ${currentClientIdServer} to check ` + `for 3PIDs during IS change flow`);
_logger.logger.warn(e);
}
const boundThreepids = threepids.filter(tp => tp.bound);
let message;
let danger = false;
const messageElements = {
idserver: sub => /*#__PURE__*/_react.default.createElement("strong", null, (0, _UrlUtils.abbreviateUrl)(currentClientIdServer)),
b: sub => /*#__PURE__*/_react.default.createElement("strong", null, sub)
};
if (!currentServerReachable) {
message = /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("identity_server|disconnect_offline_warning", {}, messageElements)), /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("identity_server|suggestions")), /*#__PURE__*/_react.default.createElement("ul", null, /*#__PURE__*/_react.default.createElement("li", null, (0, _languageHandler._t)("identity_server|suggestions_1")), /*#__PURE__*/_react.default.createElement("li", null, (0, _languageHandler._t)("identity_server|suggestions_2", {}, {
idserver: messageElements.idserver
})), /*#__PURE__*/_react.default.createElement("li", null, (0, _languageHandler._t)("identity_server|suggestions_3"))));
danger = true;
button = (0, _languageHandler._t)("identity_server|disconnect_anyway");
} else if (boundThreepids.length) {
message = /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("identity_server|disconnect_personal_data_warning_1", {}, messageElements)), /*#__PURE__*/_react.default.createElement("p", null, (0, _languageHandler._t)("identity_server|disconnect_personal_data_warning_2")));
danger = true;
button = (0, _languageHandler._t)("identity_server|disconnect_anyway");
} else {
message = unboundMessage;
}
const {
finished
} = _Modal.default.createDialog(_QuestionDialog.default, {
title,
description: message,
button,
cancelButton: (0, _languageHandler._t)("action|go_back"),
danger
});
return finished;
}
render() {
const idServerUrl = this.state.currentClientIdServer;
let sectionTitle;
let bodyText;
if (idServerUrl) {
sectionTitle = (0, _languageHandler._t)("identity_server|url", {
server: (0, _UrlUtils.abbreviateUrl)(idServerUrl)
});
bodyText = (0, _languageHandler._t)("identity_server|description_connected", {}, {
server: sub => /*#__PURE__*/_react.default.createElement("strong", null, (0, _UrlUtils.abbreviateUrl)(idServerUrl))
});
if (this.props.missingTerms) {
bodyText = (0, _languageHandler._t)("identity_server|change_server_prompt", {}, {
server: sub => /*#__PURE__*/_react.default.createElement("strong", null, (0, _UrlUtils.abbreviateUrl)(idServerUrl))
});
}
} else {
sectionTitle = (0, _languageHandler._t)("common|identity_server");
bodyText = (0, _languageHandler._t)("identity_server|description_disconnected");
}
let discoSection;
if (idServerUrl) {
let discoButtonContent = (0, _languageHandler._t)("action|disconnect");
let discoBodyText = (0, _languageHandler._t)("identity_server|disconnect_warning");
if (this.props.missingTerms) {
discoBodyText = (0, _languageHandler._t)("identity_server|description_optional");
discoButtonContent = (0, _languageHandler._t)("identity_server|do_not_use");
}
if (this.state.disconnectBusy) {
discoButtonContent = /*#__PURE__*/_react.default.createElement(_InlineSpinner.default, null);
}
discoSection = /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_SettingsSubsection.SettingsSubsectionText, null, discoBodyText), /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, {
onClick: this.onDisconnectClicked,
kind: "danger_sm"
}, discoButtonContent));
}
return /*#__PURE__*/_react.default.createElement(_SettingsFieldset.default, {
legend: sectionTitle,
description: bodyText
}, /*#__PURE__*/_react.default.createElement("form", {
className: "mx_SetIdServer",
onSubmit: this.checkIdServer
}, /*#__PURE__*/_react.default.createElement(_Field.default, {
label: (0, _languageHandler._t)("identity_server|url_field_label"),
type: "text",
autoComplete: "off",
placeholder: this.state.defaultIdServer,
value: this.state.idServer,
onChange: this.onIdentityServerChanged,
tooltipContent: this.getTooltip(),
tooltipClassName: "mx_SetIdServer_tooltip",
disabled: this.state.busy,
forceValidity: this.state.error ? false : undefined
}), /*#__PURE__*/_react.default.createElement(_AccessibleButton.default, {
type: "submit",
kind: "primary_sm",
onClick: this.checkIdServer,
disabled: !this.idServerChangeEnabled()
}, (0, _languageHandler._t)("action|change")), discoSection));
}
}
exports.default = SetIdServer;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9sb2dnZXIiLCJfbGFuZ3VhZ2VIYW5kbGVyIiwiX01hdHJpeENsaWVudFBlZyIsIl9Nb2RhbCIsIl9kaXNwYXRjaGVyIiwiX2JvdW5kVGhyZWVwaWRzIiwiX0lkZW50aXR5QXV0aENsaWVudCIsIl9VcmxVdGlscyIsIl9JZGVudGl0eVNlcnZlclV0aWxzIiwiX3Byb21pc2UiLCJfSW5saW5lU3Bpbm5lciIsIl9BY2Nlc3NpYmxlQnV0dG9uIiwiX0ZpZWxkIiwiX1F1ZXN0aW9uRGlhbG9nIiwiX1NldHRpbmdzRmllbGRzZXQiLCJfU2V0dGluZ3NTdWJzZWN0aW9uIiwiUkVBQ0hBQklMSVRZX1RJTUVPVVQiLCJjaGVja0lkZW50aXR5U2VydmVyVXJsIiwidSIsInBhcnNlZFVybCIsInBhcnNlVXJsIiwicHJvdG9jb2wiLCJfdCIsInJlc3BvbnNlIiwiZmV0Y2giLCJvayIsInN0YXR1cyIsImNvZGUiLCJlIiwiU2V0SWRTZXJ2ZXIiLCJSZWFjdCIsIkNvbXBvbmVudCIsImNvbnN0cnVjdG9yIiwicHJvcHMiLCJfZGVmaW5lUHJvcGVydHkyIiwiZGVmYXVsdCIsInBheWxvYWQiLCJhY3Rpb24iLCJzZXRTdGF0ZSIsImN1cnJlbnRDbGllbnRJZFNlcnZlciIsIk1hdHJpeENsaWVudFBlZyIsInNhZmVHZXQiLCJnZXRJZGVudGl0eVNlcnZlclVybCIsImV2IiwidGFyZ2V0IiwidmFsdWUiLCJpZFNlcnZlciIsInN0YXRlIiwiY2hlY2tpbmciLCJjcmVhdGVFbGVtZW50IiwiZXJyb3IiLCJjbGFzc05hbWUiLCJidXN5IiwiZnVsbFVybCIsInNldEFjY291bnREYXRhIiwiYmFzZV91cmwiLCJ1bmRlZmluZWQiLCJwcmV2ZW50RGVmYXVsdCIsInVuYWJicmV2aWF0ZVVybCIsImVyclN0ciIsImF1dGhDbGllbnQiLCJJZGVudGl0eUF1dGhDbGllbnQiLCJnZXRBY2Nlc3NUb2tlbiIsInNhdmUiLCJoYXNUZXJtcyIsImRvZXNJZGVudGl0eVNlcnZlckhhdmVUZXJtcyIsImNvbmZpcm1lZCIsInNob3dOb1Rlcm1zV2FybmluZyIsInNob3dTZXJ2ZXJDaGFuZ2VXYXJuaW5nIiwidGl0bGUiLCJ1bmJvdW5kTWVzc2FnZSIsImN1cnJlbnQiLCJzdWIiLCJhYmJyZXZpYXRlVXJsIiwibmV3IiwiYnV0dG9uIiwic2F2ZUlkU2VydmVyIiwibG9nZ2VyIiwiZGlzY29ubmVjdEJ1c3kiLCJpZHNlcnZlciIsImRpc2Nvbm5lY3RJZFNlcnZlciIsIm5ld0ZpZWxkVmFsIiwiZ2V0RGVmYXVsdElkZW50aXR5U2VydmVyVXJsIiwiZGVmYXVsdElkU2VydmVyIiwiY29tcG9uZW50RGlkTW91bnQiLCJkaXNwYXRjaGVyUmVmIiwiZGlzIiwicmVnaXN0ZXIiLCJvbkFjdGlvbiIsImNvbXBvbmVudFdpbGxVbm1vdW50IiwidW5yZWdpc3RlciIsImZpbmlzaGVkIiwiTW9kYWwiLCJjcmVhdGVEaWFsb2ciLCJRdWVzdGlvbkRpYWxvZyIsImRlc2NyaXB0aW9uIiwidGhyZWVwaWRzIiwiY3VycmVudFNlcnZlclJlYWNoYWJsZSIsInRpbWVvdXQiLCJnZXRUaHJlZXBpZHNXaXRoQmluZFN0YXR1cyIsIlByb21pc2UiLCJyZWplY3QiLCJFcnJvciIsIndhcm4iLCJib3VuZFRocmVlcGlkcyIsImZpbHRlciIsInRwIiwiYm91bmQiLCJtZXNzYWdlIiwiZGFuZ2VyIiwibWVzc2FnZUVsZW1lbnRzIiwiYiIsImxlbmd0aCIsImNhbmNlbEJ1dHRvbiIsInJlbmRlciIsImlkU2VydmVyVXJsIiwic2VjdGlvblRpdGxlIiwiYm9keVRleHQiLCJzZXJ2ZXIiLCJtaXNzaW5nVGVybXMiLCJkaXNjb1NlY3Rpb24iLCJkaXNjb0J1dHRvbkNvbnRlbnQiLCJkaXNjb0JvZHlUZXh0IiwiRnJhZ21lbnQiLCJTZXR0aW5nc1N1YnNlY3Rpb25UZXh0Iiwib25DbGljayIsIm9uRGlzY29ubmVjdENsaWNrZWQiLCJraW5kIiwibGVnZW5kIiwib25TdWJtaXQiLCJjaGVja0lkU2VydmVyIiwibGFiZWwiLCJ0eXBlIiwiYXV0b0NvbXBsZXRlIiwicGxhY2Vob2xkZXIiLCJvbkNoYW5nZSIsIm9uSWRlbnRpdHlTZXJ2ZXJDaGFuZ2VkIiwidG9vbHRpcENvbnRlbnQiLCJnZXRUb29sdGlwIiwidG9vbHRpcENsYXNzTmFtZSIsImRpc2FibGVkIiwiZm9yY2VWYWxpZGl0eSIsImlkU2VydmVyQ2hhbmdlRW5hYmxlZCIsImV4cG9ydHMiXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY29tcG9uZW50cy92aWV3cy9zZXR0aW5ncy9TZXRJZFNlcnZlci50c3giXSwic291cmNlc0NvbnRlbnQiOlsiLypcbkNvcHlyaWdodCAyMDI0IE5ldyBWZWN0b3IgTHRkLlxuQ29weXJpZ2h0IDIwMTktMjAyMSBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuXG5TUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQUdQTC0zLjAtb25seSBPUiBHUEwtMy4wLW9ubHlcblBsZWFzZSBzZWUgTElDRU5TRSBmaWxlcyBpbiB0aGUgcmVwb3NpdG9yeSByb290IGZvciBmdWxsIGRldGFpbHMuXG4qL1xuXG5pbXBvcnQgUmVhY3QsIHsgUmVhY3ROb2RlIH0gZnJvbSBcInJlYWN0XCI7XG5pbXBvcnQgeyBsb2dnZXIgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbG9nZ2VyXCI7XG5pbXBvcnQgeyBJVGhyZWVwaWQgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvbWF0cml4XCI7XG5cbmltcG9ydCB7IF90IH0gZnJvbSBcIi4uLy4uLy4uL2xhbmd1YWdlSGFuZGxlclwiO1xuaW1wb3J0IHsgTWF0cml4Q2xpZW50UGVnIH0gZnJvbSBcIi4uLy4uLy4uL01hdHJpeENsaWVudFBlZ1wiO1xuaW1wb3J0IE1vZGFsIGZyb20gXCIuLi8uLi8uLi9Nb2RhbFwiO1xuaW1wb3J0IGRpcyBmcm9tIFwiLi4vLi4vLi4vZGlzcGF0Y2hlci9kaXNwYXRjaGVyXCI7XG5pbXBvcnQgeyBnZXRUaHJlZXBpZHNXaXRoQmluZFN0YXR1cyB9IGZyb20gXCIuLi8uLi8uLi9ib3VuZFRocmVlcGlkc1wiO1xuaW1wb3J0IElkZW50aXR5QXV0aENsaWVudCBmcm9tIFwiLi4vLi4vLi4vSWRlbnRpdHlBdXRoQ2xpZW50XCI7XG5pbXBvcnQgeyBhYmJyZXZpYXRlVXJsLCBwYXJzZVVybCwgdW5hYmJyZXZpYXRlVXJsIH0gZnJvbSBcIi4uLy4uLy4uL3V0aWxzL1VybFV0aWxzXCI7XG5pbXBvcnQgeyBnZXREZWZhdWx0SWRlbnRpdHlTZXJ2ZXJVcmwsIGRvZXNJZGVudGl0eVNlcnZlckhhdmVUZXJtcyB9IGZyb20gXCIuLi8uLi8uLi91dGlscy9JZGVudGl0eVNlcnZlclV0aWxzXCI7XG5pbXBvcnQgeyB0aW1lb3V0IH0gZnJvbSBcIi4uLy4uLy4uL3V0aWxzL3Byb21pc2VcIjtcbmltcG9ydCB7IEFjdGlvblBheWxvYWQgfSBmcm9tIFwiLi4vLi4vLi4vZGlzcGF0Y2hlci9wYXlsb2Fkc1wiO1xuaW1wb3J0IElubGluZVNwaW5uZXIgZnJvbSBcIi4uL2VsZW1lbnRzL0lubGluZVNwaW5uZXJcIjtcbmltcG9ydCBBY2Nlc3NpYmxlQnV0dG9uIGZyb20gXCIuLi9lbGVtZW50cy9BY2Nlc3NpYmxlQnV0dG9uXCI7XG5pbXBvcnQgRmllbGQgZnJvbSBcIi4uL2VsZW1lbnRzL0ZpZWxkXCI7XG5pbXBvcnQgUXVlc3Rpb25EaWFsb2cgZnJvbSBcIi4uL2RpYWxvZ3MvUXVlc3Rpb25EaWFsb2dcIjtcbmltcG9ydCBTZXR0aW5nc0ZpZWxkc2V0IGZyb20gXCIuL1NldHRpbmdzRmllbGRzZXRcIjtcbmltcG9ydCB7IFNldHRpbmdzU3Vic2VjdGlvblRleHQgfSBmcm9tIFwiLi9zaGFyZWQvU2V0dGluZ3NTdWJzZWN0aW9uXCI7XG5cbi8vIFdlJ2xsIHdhaXQgdXAgdG8gdGhpcyBsb25nIHdoZW4gY2hlY2tpbmcgZm9yIDNQSUQgYmluZGluZ3Mgb24gdGhlIElTLlxuY29uc3QgUkVBQ0hBQklMSVRZX1RJTUVPVVQgPSAxMDAwMDsgLy8gbXNcblxuLyoqXG4gKiBDaGVjayBhbiBJUyBVUkwgaXMgdmFsaWQsIGluY2x1ZGluZyBsaXZlbmVzcyBjaGVja1xuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB1IFRoZSB1cmwgdG8gY2hlY2tcbiAqIEByZXR1cm5zIHtzdHJpbmd9IG51bGwgaWYgdXJsIHBhc3NlcyBhbGwgY2hlY2tzLCBvdGhlcndpc2UgaTE4bmVkIGVycm9yIHN0cmluZ1xuICovXG5hc3luYyBmdW5jdGlvbiBjaGVja0lkZW50aXR5U2VydmVyVXJsKHU6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nIHwgbnVsbD4ge1xuICAgIGNvbnN0IHBhcnNlZFVybCA9IHBhcnNlVXJsKHUpO1xuXG4gICAgaWYgKHBhcnNlZFVybC5wcm90b2NvbCAhPT0gXCJodHRwczpcIikgcmV0dXJuIF90KFwiaWRlbnRpdHlfc2VydmVyfHVybF9ub3RfaHR0cHNcIik7XG5cbiAgICAvLyBYWFg6IGR1cGxpY2F0ZWQgbG9naWMgZnJvbSBqcy1zZGsgYnV0IGl0J3MgcXVpdGUgdGllZCB1cCBpbiB0aGUgdmFsaWRhdGlvbiBsb2dpYyBpbiB0aGVcbiAgICAvLyBqcy1zZGsgc28gcHJvYmFibHkgYXMgZWFzeSB0byBkdXBsaWNhdGUgaXQgdGhhbiB0byBzZXBhcmF0ZSBpdCBvdXQgc28gd2UgY2FuIHJldXNlIGl0XG4gICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaCh1ICsgXCIvX21hdHJpeC9pZGVudGl0eS92MlwiKTtcbiAgICAgICAgaWYgKHJlc3BvbnNlLm9rKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfSBlbHNlIGlmIChyZXNwb25zZS5zdGF0dXMgPCAyMDAgfHwgcmVzcG9uc2Uuc3RhdHVzID49IDMwMCkge1xuICAgICAgICAgICAgcmV0dXJuIF90KFwiaWRlbnRpdHlfc2VydmVyfGVycm9yX2ludmFsaWRcIiwgeyBjb2RlOiByZXNwb25zZS5zdGF0dXMgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gX3QoXCJpZGVudGl0eV9zZXJ2ZXJ8ZXJyb3JfY29ubmVjdGlvblwiKTtcbiAgICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmV0dXJuIF90KFwiaWRlbnRpdHlfc2VydmVyfGVycm9yX2Nvbm5lY3Rpb25cIik7XG4gICAgfVxufVxuXG5pbnRlcmZhY2UgSVByb3BzIHtcbiAgICAvLyBXaGV0aGVyIG9yIG5vdCB0aGUgaWRlbnRpdHkgc2VydmVyIGlzIG1pc3NpbmcgdGVybXMuIFRoaXMgYWZmZWN0cyB0aGUgdGV4dFxuICAgIC8vIHNob3duIHRvIHRoZSB1c2VyLlxuICAgIG1pc3NpbmdUZXJtczogYm9vbGVhbjtcbn1cblxuaW50ZXJmYWNlIElTdGF0ZSB7XG4gICAgZGVmYXVsdElkU2VydmVyPzogc3RyaW5nO1xuICAgIGN1cnJlbnRDbGllbnRJZFNlcnZlcj86IHN0cmluZztcbiAgICBpZFNlcnZlcjogc3RyaW5nO1xuICAgIGVycm9yPzogc3RyaW5nO1xuICAgIGJ1c3k6IGJvb2xlYW47XG4gICAgZGlzY29ubmVjdEJ1c3k6IGJvb2xlYW47XG4gICAgY2hlY2tpbmc6IGJvb2xlYW47XG59XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFNldElkU2VydmVyIGV4dGVuZHMgUmVhY3QuQ29tcG9uZW50PElQcm9wcywgSVN0YXRlPiB7XG4gICAgcHJpdmF0ZSBkaXNwYXRjaGVyUmVmPzogc3RyaW5nO1xuXG4gICAgcHVibGljIGNvbnN0cnVjdG9yKHByb3BzOiBJUHJvcHMpIHtcbiAgICAgICAgc3VwZXIocHJvcHMpO1xuXG4gICAgICAgIGxldCBkZWZhdWx0SWRTZXJ2ZXIgPSBcIlwiO1xuICAgICAgICBpZiAoIU1hdHJpeENsaWVudFBlZy5zYWZlR2V0KCkuZ2V0SWRlbnRpdHlTZXJ2ZXJVcmwoKSAmJiBnZXREZWZhdWx0SWRlbnRpdHlTZXJ2ZXJVcmwoKSkge1xuICAgICAgICAgICAgLy8gSWYgbm8gaWRlbnRpdHkgc2VydmVyIGlzIGNvbmZpZ3VyZWQgYnV0IHRoZXJlJ3Mgb25lIGluIHRoZSBjb25maWcsIHByZXBvcHVsYXRlXG4gICAgICAgICAgICAvLyB0aGUgZmllbGQgdG8gaGVscCB0aGUgdXNlci5cbiAgICAgICAgICAgIGRlZmF1bHRJZFNlcnZlciA9IGFiYnJldmlhdGVVcmwoZ2V0RGVmYXVsdElkZW50aXR5U2VydmVyVXJsKCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5zdGF0ZSA9IHtcbiAgICAgICAgICAgIGRlZmF1bHRJZFNlcnZlcixcbiAgICAgICAgICAgIGN1cnJlbnRDbGllbnRJZFNlcnZlcjogTWF0cml4Q2xpZW50UGVnLnNhZmVHZXQoKS5nZXRJZGVudGl0eVNlcnZlclVybCgpLFxuICAgICAgICAgICAgaWRTZXJ2ZXI6IFwiXCIsXG4gICAgICAgICAgICBidXN5OiBmYWxzZSxcbiAgICAgICAgICAgIGRpc2Nvbm5lY3RCdXN5OiBmYWxzZSxcbiAgICAgICAgICAgIGNoZWNraW5nOiBmYWxzZSxcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBwdWJsaWMgY29tcG9uZW50RGlkTW91bnQoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuZGlzcGF0Y2hlclJlZiA9IGRpcy5yZWdpc3Rlcih0aGlzLm9uQWN0aW9uKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgY29tcG9uZW50V2lsbFVubW91bnQoKTogdm9pZCB7XG4gICAgICAgIGlmICh0aGlzLmRpc3BhdGNoZXJSZWYpIGRpcy51bnJlZ2lzdGVyKHRoaXMuZGlzcGF0Y2hlclJlZik7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvbkFjdGlvbiA9IChwYXlsb2FkOiBBY3Rpb25QYXlsb2FkKTogdm9pZCA9PiB7XG4gICAgICAgIC8vIFdlIHJlYWN0IHRvIGNoYW5nZXMgaW4gdGhlIGlkZW50aXR5IHNlcnZlciBpbiB0aGUgZXZlbnQgdGhlIHVzZXIgaXMgc3RhcmluZyBhdCB0aGlzIGZvcm1cbiAgICAgICAgLy8gd2hlbiBjaGFuZ2luZyB0aGVpciBpZGVudGl0eSBzZXJ2ZXIgb24gYW5vdGhlciBkZXZpY2UuXG4gICAgICAgIGlmIChwYXlsb2FkLmFjdGlvbiAhPT0gXCJpZF9zZXJ2ZXJfY2hhbmdlZFwiKSByZXR1cm47XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBjdXJyZW50Q2xpZW50SWRTZXJ2ZXI6IE1hdHJpeENsaWVudFBlZy5zYWZlR2V0KCkuZ2V0SWRlbnRpdHlTZXJ2ZXJVcmwoKSxcbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgb25JZGVudGl0eVNlcnZlckNoYW5nZWQgPSAoZXY6IFJlYWN0LkNoYW5nZUV2ZW50PEhUTUxJbnB1dEVsZW1lbnQ+KTogdm9pZCA9PiB7XG4gICAgICAgIGNvbnN0IHUgPSBldi50YXJnZXQudmFsdWU7XG5cbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IGlkU2VydmVyOiB1IH0pO1xuICAgIH07XG5cbiAgICBwcml2YXRlIGdldFRvb2x0aXAgPSAoKTogUmVhY3ROb2RlID0+IHtcbiAgICAgICAgaWYgKHRoaXMuc3RhdGUuY2hlY2tpbmcpIHtcbiAgICAgICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgICAgICAgICAgPElubGluZVNwaW5uZXIgLz5cbiAgICAgICAgICAgICAgICAgICAge190KFwiaWRlbnRpdHlfc2VydmVyfGNoZWNraW5nXCIpfVxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnN0YXRlLmVycm9yKSB7XG4gICAgICAgICAgICByZXR1cm4gPHN0cm9uZyBjbGFzc05hbWU9XCJ3YXJuaW5nXCI+e3RoaXMuc3RhdGUuZXJyb3J9PC9zdHJvbmc+O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBpZFNlcnZlckNoYW5nZUVuYWJsZWQgPSAoKTogYm9vbGVhbiA9PiB7XG4gICAgICAgIHJldHVybiAhIXRoaXMuc3RhdGUuaWRTZXJ2ZXIgJiYgIXRoaXMuc3RhdGUuYnVzeTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBzYXZlSWRTZXJ2ZXIgPSAoZnVsbFVybDogc3RyaW5nKTogdm9pZCA9PiB7XG4gICAgICAgIC8vIEFjY291bnQgZGF0YSBjaGFuZ2Ugd2lsbCB1cGRhdGUgbG9jYWxzdG9yYWdlLCBjbGllbnQsIGV0YyB0aHJvdWdoIGRpc3BhdGNoZXJcbiAgICAgICAgTWF0cml4Q2xpZW50UGVnLnNhZmVHZXQoKS5zZXRBY2NvdW50RGF0YShcIm0uaWRlbnRpdHlfc2VydmVyXCIsIHtcbiAgICAgICAgICAgIGJhc2VfdXJsOiBmdWxsVXJsLFxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5zZXRTdGF0ZSh7XG4gICAgICAgICAgICBidXN5OiBmYWxzZSxcbiAgICAgICAgICAgIGVycm9yOiB1bmRlZmluZWQsXG4gICAgICAgICAgICBjdXJyZW50Q2xpZW50SWRTZXJ2ZXI6IGZ1bGxVcmwsXG4gICAgICAgICAgICBpZFNlcnZlcjogXCJcIixcbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIHByaXZhdGUgY2hlY2tJZFNlcnZlciA9IGFzeW5jIChlOiBSZWFjdC5TeW50aGV0aWNFdmVudCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGNvbnN0IHsgaWRTZXJ2ZXIsIGN1cnJlbnRDbGllbnRJZFNlcnZlciB9ID0gdGhpcy5zdGF0ZTtcblxuICAgICAgICB0aGlzLnNldFN0YXRlKHsgYnVzeTogdHJ1ZSwgY2hlY2tpbmc6IHRydWUsIGVycm9yOiB1bmRlZmluZWQgfSk7XG5cbiAgICAgICAgY29uc3QgZnVsbFVybCA9IHVuYWJicmV2aWF0ZVVybChpZFNlcnZlcik7XG5cbiAgICAgICAgbGV0IGVyclN0ciA9IGF3YWl0IGNoZWNrSWRlbnRpdHlTZXJ2ZXJVcmwoZnVsbFVybCk7XG4gICAgICAgIGlmICghZXJyU3RyKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0U3RhdGUoeyBjaGVja2luZzogZmFsc2UgfSk7IC8vIGNsZWFyIHRvb2x0aXBcblxuICAgICAgICAgICAgICAgIC8vIFRlc3QgdGhlIGlkZW50aXR5IHNlcnZlciBieSB0cnlpbmcgdG8gcmVnaXN0ZXIgd2l0aCBpdC4gVGhpc1xuICAgICAgICAgICAgICAgIC8vIG1heSByZXN1bHQgaW4gYSB0ZXJtcyBvZiBzZXJ2aWNlIHByb21wdC5cbiAgICAgICAgICAgICAgICBjb25zdCBhdXRoQ2xpZW50ID0gbmV3IElkZW50aXR5QXV0aENsaWVudChmdWxsVXJsKTtcbiAgICAgICAgICAgICAgICBhd2FpdCBhdXRoQ2xpZW50LmdldEFjY2Vzc1Rva2VuKCk7XG5cbiAgICAgICAgICAgICAgICBsZXQgc2F2ZSA9IHRydWU7XG5cbiAgICAgICAgICAgICAgICAvLyBEb3VibGUgY2hlY2sgdGhhdCB0aGUgaWRlbnRpdHkgc2VydmVyIGV2ZW4gaGFzIHRlcm1zIG9mIHNlcnZpY2UuXG4gICAgICAgICAgICAgICAgY29uc3QgaGFzVGVybXMgPSBhd2FpdCBkb2VzSWRlbnRpdHlTZXJ2ZXJIYXZlVGVybXMoTWF0cml4Q2xpZW50UGVnLnNhZmVHZXQoKSwgZnVsbFVybCk7XG4gICAgICAgICAgICAgICAgaWYgKCFoYXNUZXJtcykge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBbY29uZmlybWVkXSA9IGF3YWl0IHRoaXMuc2hvd05vVGVybXNXYXJuaW5nKGZ1bGxVcmwpO1xuICAgICAgICAgICAgICAgICAgICBzYXZlID0gISFjb25maXJtZWQ7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gU2hvdyBhIGdlbmVyYWwgd2FybmluZywgcG9zc2libHkgd2l0aCBkZXRhaWxzIGFib3V0IGFueSBib3VuZFxuICAgICAgICAgICAgICAgIC8vIDNQSURzIHRoYXQgd291bGQgYmUgbGVmdCBiZWhpbmQuXG4gICAgICAgICAgICAgICAgaWYgKHNhdmUgJiYgY3VycmVudENsaWVudElkU2VydmVyICYmIGZ1bGxVcmwgIT09IGN1cnJlbnRDbGllbnRJZFNlcnZlcikge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBbY29uZmlybWVkXSA9IGF3YWl0IHRoaXMuc2hvd1NlcnZlckNoYW5nZVdhcm5pbmcoe1xuICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGU6IF90KFwiaWRlbnRpdHlfc2VydmVyfGNoYW5nZVwiKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHVuYm91bmRNZXNzYWdlOiBfdChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcImlkZW50aXR5X3NlcnZlcnxjaGFuZ2VfcHJvbXB0XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge30sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50OiAoc3ViKSA9PiA8c3Ryb25nPnthYmJyZXZpYXRlVXJsKGN1cnJlbnRDbGllbnRJZFNlcnZlcil9PC9zdHJvbmc+LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXc6IChzdWIpID0+IDxzdHJvbmc+e2FiYnJldmlhdGVVcmwoaWRTZXJ2ZXIpfTwvc3Ryb25nPixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGJ1dHRvbjogX3QoXCJhY3Rpb258Y29udGludWVcIiksXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBzYXZlID0gISFjb25maXJtZWQ7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKHNhdmUpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zYXZlSWRTZXJ2ZXIoZnVsbFVybCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIGxvZ2dlci5lcnJvcihlKTtcbiAgICAgICAgICAgICAgICBlcnJTdHIgPSBfdChcImlkZW50aXR5X3NlcnZlcnxlcnJvcl9pbnZhbGlkX29yX3Rlcm1zXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgYnVzeTogZmFsc2UsXG4gICAgICAgICAgICBjaGVja2luZzogZmFsc2UsXG4gICAgICAgICAgICBlcnJvcjogZXJyU3RyID8/IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIGN1cnJlbnRDbGllbnRJZFNlcnZlcjogTWF0cml4Q2xpZW50UGVnLnNhZmVHZXQoKS5nZXRJZGVudGl0eVNlcnZlclVybCgpLFxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBzaG93Tm9UZXJtc1dhcm5pbmcoZnVsbFVybDogc3RyaW5nKTogUHJvbWlzZTxbb2s/OiBib29sZWFuXT4ge1xuICAgICAgICBjb25zdCB7IGZpbmlzaGVkIH0gPSBNb2RhbC5jcmVhdGVEaWFsb2coUXVlc3Rpb25EaWFsb2csIHtcbiAgICAgICAgICAgIHRpdGxlOiBfdChcInRlcm1zfGlkZW50aXR5X3NlcnZlcl9ub190ZXJtc190aXRsZVwiKSxcbiAgICAgICAgICAgIGRlc2NyaXB0aW9uOiAoXG4gICAgICAgICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgICAgICAgICAgPHN0cm9uZyBjbGFzc05hbWU9XCJ3YXJuaW5nXCI+e190KFwiaWRlbnRpdHlfc2VydmVyfG5vX3Rlcm1zXCIpfTwvc3Ryb25nPlxuICAgICAgICAgICAgICAgICAgICA8c3Bhbj4mbmJzcDt7X3QoXCJ0ZXJtc3xpZGVudGl0eV9zZXJ2ZXJfbm9fdGVybXNfZGVzY3JpcHRpb25fMlwiKX08L3NwYW4+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICApLFxuICAgICAgICAgICAgYnV0dG9uOiBfdChcImFjdGlvbnxjb250aW51ZVwiKSxcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBmaW5pc2hlZDtcbiAgICB9XG5cbiAgICBwcml2YXRlIG9uRGlzY29ubmVjdENsaWNrZWQgPSBhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gICAgICAgIHRoaXMuc2V0U3RhdGUoeyBkaXNjb25uZWN0QnVzeTogdHJ1ZSB9KTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IFtjb25maXJtZWRdID0gYXdhaXQgdGhpcy5zaG93U2VydmVyQ2hhbmdlV2FybmluZyh7XG4gICAgICAgICAgICAgICAgdGl0bGU6IF90KFwiaWRlbnRpdHlfc2VydmVyfGRpc2Nvbm5lY3RcIiksXG4gICAgICAgICAgICAgICAgdW5ib3VuZE1lc3NhZ2U6IF90KFxuICAgICAgICAgICAgICAgICAgICBcImlkZW50aXR5X3NlcnZlcnxkaXNjb25uZWN0X3NlcnZlclwiLFxuICAgICAgICAgICAgICAgICAgICB7fSxcbiAgICAgICAgICAgICAgICAgICAgeyBpZHNlcnZlcjogKHN1YikgPT4gPHN0cm9uZz57YWJicmV2aWF0ZVVybCh0aGlzLnN0YXRlLmN1cnJlbnRDbGllbnRJZFNlcnZlcil9PC9zdHJvbmc+IH0sXG4gICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICBidXR0b246IF90KFwiYWN0aW9ufGRpc2Nvbm5lY3RcIiksXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIGlmIChjb25maXJtZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmRpc2Nvbm5lY3RJZFNlcnZlcigpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgICAgdGhpcy5zZXRTdGF0ZSh7IGRpc2Nvbm5lY3RCdXN5OiBmYWxzZSB9KTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBwcml2YXRlIGFzeW5jIHNob3dTZXJ2ZXJDaGFuZ2VXYXJuaW5nKHtcbiAgICAgICAgdGl0bGUsXG4gICAgICAgIHVuYm91bmRNZXNzYWdlLFxuICAgICAgICBidXR0b24sXG4gICAgfToge1xuICAgICAgICB0aXRsZTogc3RyaW5nO1xuICAgICAgICB1bmJvdW5kTWVzc2FnZTogUmVhY3ROb2RlO1xuICAgICAgICBidXR0b246IHN0cmluZztcbiAgICB9KTogUHJvbWlzZTxbb2s/OiBib29sZWFuXT4ge1xuICAgICAgICBjb25zdCB7IGN1cnJlbnRDbGllbnRJZFNlcnZlciB9ID0gdGhpcy5zdGF0ZTtcblxuICAgICAgICBsZXQgdGhyZWVwaWRzOiBJVGhyZWVwaWRbXSA9IFtdO1xuICAgICAgICBsZXQgY3VycmVudFNlcnZlclJlYWNoYWJsZSA9IHRydWU7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICB0aHJlZXBpZHMgPSBhd2FpdCB0aW1lb3V0KFxuICAgICAgICAgICAgICAgIGdldFRocmVlcGlkc1dpdGhCaW5kU3RhdHVzKE1hdHJpeENsaWVudFBlZy5zYWZlR2V0KCkpLFxuICAgICAgICAgICAgICAgIFByb21pc2UucmVqZWN0KG5ldyBFcnJvcihcIlRpbWVvdXQgYXR0ZW1wdGluZyB0byByZWFjaCBpZGVudGl0eSBzZXJ2ZXJcIikpLFxuICAgICAgICAgICAgICAgIFJFQUNIQUJJTElUWV9USU1FT1VULFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY3VycmVudFNlcnZlclJlYWNoYWJsZSA9IGZhbHNlO1xuICAgICAgICAgICAgbG9nZ2VyLndhcm4oXG4gICAgICAgICAgICAgICAgYFVuYWJsZSB0byByZWFjaCBpZGVudGl0eSBzZXJ2ZXIgYXQgJHtjdXJyZW50Q2xpZW50SWRTZXJ2ZXJ9IHRvIGNoZWNrIGAgK1xuICAgICAgICAgICAgICAgICAgICBgZm9yIDNQSURzIGR1cmluZyBJUyBjaGFuZ2UgZmxvd2AsXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgbG9nZ2VyLndhcm4oZSk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgYm91bmRUaHJlZXBpZHMgPSB0aHJlZXBpZHMuZmlsdGVyKCh0cCkgPT4gdHAuYm91bmQpO1xuICAgICAgICBsZXQgbWVzc2FnZTtcbiAgICAgICAgbGV0IGRhbmdlciA9IGZhbHNlO1xuICAgICAgICBjb25zdCBtZXNzYWdlRWxlbWVudHMgPSB7XG4gICAgICAgICAgICBpZHNlcnZlcjogKHN1Yjogc3RyaW5nKSA9PiA8c3Ryb25nPnthYmJyZXZpYXRlVXJsKGN1cnJlbnRDbGllbnRJZFNlcnZlcil9PC9zdHJvbmc+LFxuICAgICAgICAgICAgYjogKHN1Yjogc3RyaW5nKSA9PiA8c3Ryb25nPntzdWJ9PC9zdHJvbmc+LFxuICAgICAgICB9O1xuICAgICAgICBpZiAoIWN1cnJlbnRTZXJ2ZXJSZWFjaGFibGUpIHtcbiAgICAgICAgICAgIG1lc3NhZ2UgPSAoXG4gICAgICAgICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgICAgICAgICAgPHA+e190KFwiaWRlbnRpdHlfc2VydmVyfGRpc2Nvbm5lY3Rfb2ZmbGluZV93YXJuaW5nXCIsIHt9LCBtZXNzYWdlRWxlbWVudHMpfTwvcD5cbiAgICAgICAgICAgICAgICAgICAgPHA+e190KFwiaWRlbnRpdHlfc2VydmVyfHN1Z2dlc3Rpb25zXCIpfTwvcD5cbiAgICAgICAgICAgICAgICAgICAgPHVsPlxuICAgICAgICAgICAgICAgICAgICAgICAgPGxpPntfdChcImlkZW50aXR5X3NlcnZlcnxzdWdnZXN0aW9uc18xXCIpfTwvbGk+XG4gICAgICAgICAgICAgICAgICAgICAgICA8bGk+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge190KFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcImlkZW50aXR5X3NlcnZlcnxzdWdnZXN0aW9uc18yXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHt9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZHNlcnZlcjogbWVzc2FnZUVsZW1lbnRzLmlkc2VydmVyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICl9XG4gICAgICAgICAgICAgICAgICAgICAgICA8L2xpPlxuICAgICAgICAgICAgICAgICAgICAgICAgPGxpPntfdChcImlkZW50aXR5X3NlcnZlcnxzdWdnZXN0aW9uc18zXCIpfTwvbGk+XG4gICAgICAgICAgICAgICAgICAgIDwvdWw+XG4gICAgICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgZGFuZ2VyID0gdHJ1ZTtcbiAgICAgICAgICAgIGJ1dHRvbiA9IF90KFwiaWRlbnRpdHlfc2VydmVyfGRpc2Nvbm5lY3RfYW55d2F5XCIpO1xuICAgICAgICB9IGVsc2UgaWYgKGJvdW5kVGhyZWVwaWRzLmxlbmd0aCkge1xuICAgICAgICAgICAgbWVzc2FnZSA9IChcbiAgICAgICAgICAgICAgICA8ZGl2PlxuICAgICAgICAgICAgICAgICAgICA8cD57X3QoXCJpZGVudGl0eV9zZXJ2ZXJ8ZGlzY29ubmVjdF9wZXJzb25hbF9kYXRhX3dhcm5pbmdfMVwiLCB7fSwgbWVzc2FnZUVsZW1lbnRzKX08L3A+XG4gICAgICAgICAgICAgICAgICAgIDxwPntfdChcImlkZW50aXR5X3NlcnZlcnxkaXNjb25uZWN0X3BlcnNvbmFsX2RhdGFfd2FybmluZ18yXCIpfTwvcD5cbiAgICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBkYW5nZXIgPSB0cnVlO1xuICAgICAgICAgICAgYnV0dG9uID0gX3QoXCJpZGVudGl0eV9zZXJ2ZXJ8ZGlzY29ubmVjdF9hbnl3YXlcIik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBtZXNzYWdlID0gdW5ib3VuZE1lc3NhZ2U7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB7IGZpbmlzaGVkIH0gPSBNb2RhbC5jcmVhdGVEaWFsb2coUXVlc3Rpb25EaWFsb2csIHtcbiAgICAgICAgICAgIHRpdGxlLFxuICAgICAgICAgICAgZGVzY3JpcHRpb246IG1lc3NhZ2UsXG4gICAgICAgICAgICBidXR0b24sXG4gICAgICAgICAgICBjYW5jZWxCdXR0b246IF90KFwiYWN0aW9ufGdvX2JhY2tcIiksXG4gICAgICAgICAgICBkYW5nZXIsXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gZmluaXNoZWQ7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBkaXNjb25uZWN0SWRTZXJ2ZXIgPSAoKTogdm9pZCA9PiB7XG4gICAgICAgIC8vIEFjY291bnQgZGF0YSBjaGFuZ2Ugd2lsbCB1cGRhdGUgbG9jYWxzdG9yYWdlLCBjbGllbnQsIGV0YyB0aHJvdWdoIGRpc3BhdGNoZXJcbiAgICAgICAgTWF0cml4Q2xpZW50UGVnLnNhZmVHZXQoKS5zZXRBY2NvdW50RGF0YShcIm0uaWRlbnRpdHlfc2VydmVyXCIsIHtcbiAgICAgICAgICAgIGJhc2VfdXJsOiBudWxsLCAvLyBjbGVhclxuICAgICAgICB9KTtcblxuICAgICAgICBsZXQgbmV3RmllbGRWYWwgPSBcIlwiO1xuICAgICAgICBpZiAoZ2V0RGVmYXVsdElkZW50aXR5U2VydmVyVXJsKCkpIHtcbiAgICAgICAgICAgIC8vIFByZXBvcHVsYXRlIHRoZSBjbGllbnQncyBkZWZhdWx0IHNvIHRoZSB1c2VyIGF0IGxlYXN0IGhhcyBzb21lIGlkZWEgb2ZcbiAgICAgICAgICAgIC8vIGEgdmFsaWQgdmFsdWUgdGhleSBtaWdodCBlbnRlclxuICAgICAgICAgICAgbmV3RmllbGRWYWwgPSBhYmJyZXZpYXRlVXJsKGdldERlZmF1bHRJZGVudGl0eVNlcnZlclVybCgpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuc2V0U3RhdGUoe1xuICAgICAgICAgICAgYnVzeTogZmFsc2UsXG4gICAgICAgICAgICBlcnJvcjogdW5kZWZpbmVkLFxuICAgICAgICAgICAgY3VycmVudENsaWVudElkU2VydmVyOiBNYXRyaXhDbGllbnRQZWcuc2FmZUdldCgpLmdldElkZW50aXR5U2VydmVyVXJsKCksXG4gICAgICAgICAgICBpZFNlcnZlcjogbmV3RmllbGRWYWwsXG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICBwdWJsaWMgcmVuZGVyKCk6IFJlYWN0LlJlYWN0Tm9kZSB7XG4gICAgICAgIGNvbnN0IGlkU2VydmVyVXJsID0gdGhpcy5zdGF0ZS5jdXJyZW50Q2xpZW50SWRTZXJ2ZXI7XG4gICAgICAgIGxldCBzZWN0aW9uVGl0bGU7XG4gICAgICAgIGxldCBib2R5VGV4dDtcbiAgICAgICAgaWYgKGlkU2VydmVyVXJsKSB7XG4gICAgICAgICAgICBzZWN0aW9uVGl0bGUgPSBfdChcImlkZW50aXR5X3NlcnZlcnx1cmxcIiwgeyBzZXJ2ZXI6IGFiYnJldmlhdGVVcmwoaWRTZXJ2ZXJVcmwpIH0pO1xuICAgICAgICAgICAgYm9keVRleHQgPSBfdChcbiAgICAgICAgICAgICAgICBcImlkZW50aXR5X3NlcnZlcnxkZXNjcmlwdGlvbl9jb25uZWN0ZWRcIixcbiAgICAgICAgICAgICAgICB7fSxcbiAgICAgICAgICAgICAgICB7IHNlcnZlcjogKHN1YikgPT4gPHN0cm9uZz57YWJicmV2aWF0ZVVybChpZFNlcnZlclVybCl9PC9zdHJvbmc+IH0sXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgaWYgKHRoaXMucHJvcHMubWlzc2luZ1Rlcm1zKSB7XG4gICAgICAgICAgICAgICAgYm9keVRleHQgPSBfdChcbiAgICAgICAgICAgICAgICAgICAgXCJpZGVudGl0eV9zZXJ2ZXJ8Y2hhbmdlX3NlcnZlcl9wcm9tcHRcIixcbiAgICAgICAgICAgICAgICAgICAge30sXG4gICAgICAgICAgICAgICAgICAgIHsgc2VydmVyOiAoc3ViKSA9PiA8c3Ryb25nPnthYmJyZXZpYXRlVXJsKGlkU2VydmVyVXJsKX08L3N0cm9uZz4gfSxcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgc2VjdGlvblRpdGxlID0gX3QoXCJjb21tb258aWRlbnRpdHlfc2VydmVyXCIpO1xuICAgICAgICAgICAgYm9keVRleHQgPSBfdChcImlkZW50aXR5X3NlcnZlcnxkZXNjcmlwdGlvbl9kaXNjb25uZWN0ZWRcIik7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgZGlzY29TZWN0aW9uO1xuICAgICAgICBpZiAoaWRTZXJ2ZXJVcmwpIHtcbiAgICAgICAgICAgIGxldCBkaXNjb0J1dHRvbkNvbnRlbnQ6IFJlYWN0LlJlYWN0Tm9kZSA9IF90KFwiYWN0aW9ufGRpc2Nvbm5lY3RcIik7XG4gICAgICAgICAgICBsZXQgZGlzY29Cb2R5VGV4dCA9IF90KFwiaWRlbnRpdHlfc2VydmVyfGRpc2Nvbm5lY3Rfd2FybmluZ1wiKTtcbiAgICAgICAgICAgIGlmICh0aGlzLnByb3BzLm1pc3NpbmdUZXJtcykge1xuICAgICAgICAgICAgICAgIGRpc2NvQm9keVRleHQgPSBfdChcImlkZW50aXR5X3NlcnZlcnxkZXNjcmlwdGlvbl9vcHRpb25hbFwiKTtcbiAgICAgICAgICAgICAgICBkaXNjb0J1dHRvbkNvbnRlbnQgPSBfdChcImlkZW50aXR5X3NlcnZlcnxkb19ub3RfdXNlXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuZGlzY29ubmVjdEJ1c3kpIHtcbiAgICAgICAgICAgICAgICBkaXNjb0J1dHRvbkNvbnRlbnQgPSA8SW5saW5lU3Bpbm5lciAvPjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGRpc2NvU2VjdGlvbiA9IChcbiAgICAgICAgICAgICAgICA8PlxuICAgICAgICAgICAgICAgICAgICA8U2V0dGluZ3NTdWJzZWN0aW9uVGV4dD57ZGlzY29Cb2R5VGV4dH08L1NldHRpbmdzU3Vic2VjdGlvblRleHQ+XG4gICAgICAgICAgICAgICAgICAgIDxBY2Nlc3NpYmxlQnV0dG9uIG9uQ2xpY2s9e3RoaXMub25EaXNjb25uZWN0Q2xpY2tlZH0ga2luZD1cImRhbmdlcl9zbVwiPlxuICAgICAgICAgICAgICAgICAgICAgICAge2Rpc2NvQnV0dG9uQ29udGVudH1cbiAgICAgICAgICAgICAgICAgICAgPC9BY2Nlc3NpYmxlQnV0dG9uPlxuICAgICAgICAgICAgICAgIDwvPlxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICA8U2V0dGluZ3NGaWVsZHNldCBsZWdlbmQ9e3NlY3Rpb25UaXRsZX0gZGVzY3JpcHRpb249e2JvZHlUZXh0fT5cbiAgICAgICAgICAgICAgICA8Zm9ybSBjbGFzc05hbWU9XCJteF9TZXRJZFNlcnZlclwiIG9uU3VibWl0PXt0aGlzLmNoZWNrSWRTZXJ2ZXJ9PlxuICAgICAgICAgICAgICAgICAgICA8RmllbGRcbiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPXtfdChcImlkZW50aXR5X3NlcnZlcnx1cmxfZmllbGRfbGFiZWxcIil9XG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlPVwidGV4dFwiXG4gICAgICAgICAgICAgICAgICAgICAgICBhdXRvQ29tcGxldGU9XCJvZmZcIlxuICAgICAgICAgICAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9e3RoaXMuc3RhdGUuZGVmYXVsdElkU2VydmVyfVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU9e3RoaXMuc3RhdGUuaWRTZXJ2ZXJ9XG4gICAgICAgICAgICAgICAgICAgICAgICBvbkNoYW5nZT17dGhpcy5vbklkZW50aXR5U2VydmVyQ2hhbmdlZH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHRvb2x0aXBDb250ZW50PXt0aGlzLmdldFRvb2x0aXAoKX1cbiAgICAgICAgICAgICAgICAgICAgICAgIHRvb2x0aXBDbGFzc05hbWU9XCJteF9TZXRJZFNlcnZlcl90b29sdGlwXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRpc2FibGVkPXt0aGlzLnN0YXRlLmJ1c3l9XG4gICAgICAgICAgICAgICAgICAgICAgICBmb3JjZVZhbGlkaXR5PXt0aGlzLnN0YXRlLmVycm9yID8gZmFsc2UgOiB1bmRlZmluZWR9XG4gICAgICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgICAgICAgIDxBY2Nlc3NpYmxlQnV0dG9uXG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlPVwic3VibWl0XCJcbiAgICAgICAgICAgICAgICAgICAgICAgIGtpbmQ9XCJwcmltYXJ5X3NtXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uQ2xpY2s9e3RoaXMuY2hlY2tJZFNlcnZlcn1cbiAgICAgICAgICAgICAgICAgICAgICAgIGRpc2FibGVkPXshdGhpcy5pZFNlcnZlckNoYW5nZUVuYWJsZWQoKX1cbiAgICAgICAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgICAgICAgICAge190KFwiYWN0aW9ufGNoYW5nZVwiKX1cbiAgICAgICAgICAgICAgICAgICAgPC9BY2Nlc3NpYmxlQnV0dG9uPlxuICAgICAgICAgICAgICAgICAgICB7ZGlzY29TZWN0aW9ufVxuICAgICAgICAgICAgICAgIDwvZm9ybT5cbiAgICAgICAgICAgIDwvU2V0dGluZ3NGaWVsZHNldD5cbiAgICAgICAgKTtcbiAgICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7O0FBUUEsSUFBQUEsTUFBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUMsT0FBQSxHQUFBRCxPQUFBO0FBR0EsSUFBQUUsZ0JBQUEsR0FBQUYsT0FBQTtBQUNBLElBQUFHLGdCQUFBLEdBQUFILE9BQUE7QUFDQSxJQUFBSSxNQUFBLEdBQUFMLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBSyxXQUFBLEdBQUFOLHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBTSxlQUFBLEdBQUFOLE9BQUE7QUFDQSxJQUFBTyxtQkFBQSxHQUFBUixzQkFBQSxDQUFBQyxPQUFBO0FBQ0Es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