matrix-react-sdk
Version:
SDK for matrix.org using React
270 lines (256 loc) • 42.1 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireDefault(require("react"));
var _matrix = require("matrix-js-sdk/src/matrix");
var _logger = require("matrix-js-sdk/src/logger");
var _languageHandler = require("../languageHandler");
var _SdkConfig = _interopRequireDefault(require("../SdkConfig"));
/*
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.
*/
const LIVELINESS_DISCOVERY_ERRORS = [_matrix.AutoDiscovery.ERROR_INVALID_HOMESERVER, _matrix.AutoDiscovery.ERROR_INVALID_IDENTITY_SERVER];
const AutoDiscoveryErrors = Object.values(_matrix.AutoDiscoveryError);
const isAutoDiscoveryError = err => {
return AutoDiscoveryErrors.includes(err);
};
const mapAutoDiscoveryErrorTranslation = err => {
switch (err) {
case _matrix.AutoDiscoveryError.GenericFailure:
return (0, _languageHandler._td)("auth|autodiscovery_invalid");
case _matrix.AutoDiscoveryError.Invalid:
return (0, _languageHandler._td)("auth|autodiscovery_generic_failure");
case _matrix.AutoDiscoveryError.InvalidHsBaseUrl:
return (0, _languageHandler._td)("auth|autodiscovery_invalid_hs_base_url");
case _matrix.AutoDiscoveryError.InvalidHomeserver:
return (0, _languageHandler._td)("auth|autodiscovery_invalid_hs");
case _matrix.AutoDiscoveryError.InvalidIsBaseUrl:
return (0, _languageHandler._td)("auth|autodiscovery_invalid_is_base_url");
case _matrix.AutoDiscoveryError.InvalidIdentityServer:
return (0, _languageHandler._td)("auth|autodiscovery_invalid_is");
case _matrix.AutoDiscoveryError.InvalidIs:
return (0, _languageHandler._td)("auth|autodiscovery_invalid_is_response");
case _matrix.AutoDiscoveryError.MissingWellknown:
return (0, _languageHandler._td)("auth|autodiscovery_no_well_known");
case _matrix.AutoDiscoveryError.InvalidJson:
return (0, _languageHandler._td)("auth|autodiscovery_invalid_json");
case _matrix.AutoDiscoveryError.UnsupportedHomeserverSpecVersion:
return (0, _languageHandler._td)("auth|autodiscovery_hs_incompatible");
}
};
class AutoDiscoveryUtils {
/**
* Checks if a given error or error message is considered an error
* relating to the liveliness of the server. Must be an error returned
* from this AutoDiscoveryUtils class.
* @param {string | Error} error The error to check
* @returns {boolean} True if the error is a liveliness error.
*/
static isLivelinessError(error) {
if (!error) return false;
let msg = error;
if (error instanceof _languageHandler.UserFriendlyError) {
msg = error.cause;
} else if (error instanceof Error) {
msg = error.message;
}
return LIVELINESS_DISCOVERY_ERRORS.includes(msg);
}
/**
* Gets the common state for auth components (login, registration, forgot
* password) for a given validation error.
* @param {Error} err The error encountered.
* @param {string} pageName The page for which the error should be customized to. See
* implementation for known values.
* @returns {*} The state for the component, given the error.
*/
static authComponentStateForError(err, pageName = "login") {
if (!err) {
return {
serverIsAlive: true,
serverErrorIsFatal: false,
serverDeadError: null
};
}
let title = (0, _languageHandler._t)("cannot_reach_homeserver");
let body = (0, _languageHandler._t)("cannot_reach_homeserver_detail");
if (!AutoDiscoveryUtils.isLivelinessError(err)) {
const brand = _SdkConfig.default.get().brand;
title = (0, _languageHandler._t)("auth|misconfigured_title", {
brand
});
body = (0, _languageHandler._t)("auth|misconfigured_body", {
brand
}, {
a: sub => {
return /*#__PURE__*/_react.default.createElement("a", {
href: "https://github.com/vector-im/element-web/blob/master/docs/config.md",
target: "_blank",
rel: "noreferrer noopener"
}, sub);
}
});
}
let isFatalError = true;
const errorMessage = err instanceof Error ? err.message : err;
if (errorMessage === _matrix.AutoDiscovery.ERROR_INVALID_IDENTITY_SERVER) {
isFatalError = false;
title = (0, _languageHandler._t)("auth|failed_connect_identity_server");
// It's annoying having a ladder for the third word in the same sentence, but our translations
// don't make this easy to avoid.
if (pageName === "register") {
body = (0, _languageHandler._t)("auth|failed_connect_identity_server_register");
} else if (pageName === "reset_password") {
body = (0, _languageHandler._t)("auth|failed_connect_identity_server_reset_password");
} else {
body = (0, _languageHandler._t)("auth|failed_connect_identity_server_other");
}
}
return {
serverIsAlive: false,
serverErrorIsFatal: isFatalError,
serverDeadError: /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("strong", null, title), /*#__PURE__*/_react.default.createElement("div", null, body))
};
}
/**
* Validates a server configuration, using a pair of URLs as input.
* @param {string} homeserverUrl The homeserver URL.
* @param {string} identityUrl The identity server URL.
* @param {boolean} syntaxOnly If true, errors relating to liveliness of the servers will
* not be raised.
* @returns {Promise<ValidatedServerConfig>} Resolves to the validated configuration.
*/
static async validateServerConfigWithStaticUrls(homeserverUrl, identityUrl, syntaxOnly = false) {
if (!homeserverUrl) {
throw new _languageHandler.UserFriendlyError("auth|no_hs_url_provided");
}
const wellknownConfig = {
"m.homeserver": {
base_url: homeserverUrl
}
};
if (identityUrl) {
wellknownConfig["m.identity_server"] = {
base_url: identityUrl
};
}
const result = await _matrix.AutoDiscovery.fromDiscoveryConfig(wellknownConfig);
const url = new URL(homeserverUrl);
const serverName = url.hostname;
return AutoDiscoveryUtils.buildValidatedConfigFromDiscovery(serverName, result, syntaxOnly, true);
}
/**
* Validates a server configuration, using a homeserver domain name as input.
* @param {string} serverName The homeserver domain name (eg: "matrix.org") to validate.
* @returns {Promise<ValidatedServerConfig>} Resolves to the validated configuration.
*/
static async validateServerName(serverName) {
const result = await _matrix.AutoDiscovery.findClientConfig(serverName);
return AutoDiscoveryUtils.buildValidatedConfigFromDiscovery(serverName, result);
}
/**
* Validates a server configuration, using a pre-calculated AutoDiscovery result as
* input.
* @param {string} serverName The domain name the AutoDiscovery result is for.
* @param {*} discoveryResult The AutoDiscovery result.
* @param {boolean} syntaxOnly If true, errors relating to liveliness of the servers will not be raised.
* @param {boolean} isSynthetic If true, then the discoveryResult was synthesised locally.
* @returns {Promise<ValidatedServerConfig>} Resolves to the validated configuration.
*/
static async buildValidatedConfigFromDiscovery(serverName, discoveryResult, syntaxOnly = false, isSynthetic = false) {
if (!discoveryResult?.["m.homeserver"]) {
// This shouldn't happen without major misconfiguration, so we'll log a bit of information
// in the log so we can find this bit of code but otherwise tell the user "it broke".
_logger.logger.error("Ended up in a state of not knowing which homeserver to connect to.");
throw new _languageHandler.UserFriendlyError("auth|autodiscovery_unexpected_error_hs");
}
const hsResult = discoveryResult["m.homeserver"];
const isResult = discoveryResult["m.identity_server"];
const defaultConfig = _SdkConfig.default.get("validated_server_config");
// Validate the identity server first because an invalid identity server causes
// an invalid homeserver, which may not be picked up correctly.
// Note: In the cases where we rely on the default IS from the config (namely
// lack of identity server provided by the discovery method), we intentionally do not
// validate it. This has already been validated and this helps some off-the-grid usage
// of Element.
let preferredIdentityUrl = defaultConfig && defaultConfig["isUrl"];
if (isResult && isResult.state === _matrix.AutoDiscovery.SUCCESS) {
preferredIdentityUrl = isResult["base_url"] ?? undefined;
} else if (isResult && isResult.state !== _matrix.AutoDiscovery.PROMPT) {
_logger.logger.error("Error determining preferred identity server URL:", isResult);
if (isResult.state === _matrix.AutoDiscovery.FAIL_ERROR) {
if (isAutoDiscoveryError(isResult.error)) {
throw new _languageHandler.UserFriendlyError(mapAutoDiscoveryErrorTranslation(isResult.error), {
cause: hsResult.error
});
}
throw new _languageHandler.UserFriendlyError("auth|autodiscovery_unexpected_error_is");
} // else the error is not related to syntax - continue anyways.
// rewrite homeserver error since we don't care about problems
hsResult.error = _matrix.AutoDiscovery.ERROR_INVALID_IDENTITY_SERVER;
// Also use the user's supplied identity server if provided
if (isResult["base_url"]) preferredIdentityUrl = isResult["base_url"];
}
if (hsResult.state !== _matrix.AutoDiscovery.SUCCESS) {
_logger.logger.error("Error processing homeserver config:", hsResult);
if (!syntaxOnly || !AutoDiscoveryUtils.isLivelinessError(hsResult.error)) {
if (isAutoDiscoveryError(hsResult.error)) {
throw new _languageHandler.UserFriendlyError(mapAutoDiscoveryErrorTranslation(hsResult.error), {
cause: hsResult.error
});
}
throw new _languageHandler.UserFriendlyError("auth|autodiscovery_unexpected_error_hs");
} // else the error is not related to syntax - continue anyways.
}
const preferredHomeserverUrl = hsResult["base_url"];
if (!preferredHomeserverUrl) {
_logger.logger.error("No homeserver URL configured");
throw new _languageHandler.UserFriendlyError("auth|autodiscovery_unexpected_error_hs");
}
let preferredHomeserverName = serverName ?? hsResult["server_name"];
const url = new URL(preferredHomeserverUrl);
if (!preferredHomeserverName) preferredHomeserverName = url.hostname;
// It should have been set by now, so check it
if (!preferredHomeserverName) {
_logger.logger.error("Failed to parse homeserver name from homeserver URL");
throw new _languageHandler.UserFriendlyError("auth|autodiscovery_unexpected_error_hs");
}
// This isn't inherently auto-discovery but used to be in an earlier incarnation of the MSC,
// and shuttling the data together makes a lot of sense
let delegatedAuthentication;
let delegatedAuthenticationError;
try {
const tempClient = new _matrix.MatrixClient({
baseUrl: preferredHomeserverUrl
});
const {
issuer
} = await tempClient.getAuthIssuer();
delegatedAuthentication = await (0, _matrix.discoverAndValidateOIDCIssuerWellKnown)(issuer);
} catch (e) {
if (e instanceof _matrix.MatrixError && e.httpStatus === 404 && e.errcode === "M_UNRECOGNIZED") {
// 404 M_UNRECOGNIZED means the server does not support OIDC
} else {
delegatedAuthenticationError = e;
}
}
return {
hsUrl: preferredHomeserverUrl,
hsName: preferredHomeserverName,
hsNameIsDifferent: url.hostname !== preferredHomeserverName,
isUrl: preferredIdentityUrl,
isDefault: false,
warning: hsResult.error ?? delegatedAuthenticationError ?? null,
isNameResolvable: !isSynthetic,
delegatedAuthentication
};
}
}
exports.default = AutoDiscoveryUtils;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwicmVxdWlyZSIsIl9tYXRyaXgiLCJfbG9nZ2VyIiwiX2xhbmd1YWdlSGFuZGxlciIsIl9TZGtDb25maWciLCJMSVZFTElORVNTX0RJU0NPVkVSWV9FUlJPUlMiLCJBdXRvRGlzY292ZXJ5IiwiRVJST1JfSU5WQUxJRF9IT01FU0VSVkVSIiwiRVJST1JfSU5WQUxJRF9JREVOVElUWV9TRVJWRVIiLCJBdXRvRGlzY292ZXJ5RXJyb3JzIiwiT2JqZWN0IiwidmFsdWVzIiwiQXV0b0Rpc2NvdmVyeUVycm9yIiwiaXNBdXRvRGlzY292ZXJ5RXJyb3IiLCJlcnIiLCJpbmNsdWRlcyIsIm1hcEF1dG9EaXNjb3ZlcnlFcnJvclRyYW5zbGF0aW9uIiwiR2VuZXJpY0ZhaWx1cmUiLCJfdGQiLCJJbnZhbGlkIiwiSW52YWxpZEhzQmFzZVVybCIsIkludmFsaWRIb21lc2VydmVyIiwiSW52YWxpZElzQmFzZVVybCIsIkludmFsaWRJZGVudGl0eVNlcnZlciIsIkludmFsaWRJcyIsIk1pc3NpbmdXZWxsa25vd24iLCJJbnZhbGlkSnNvbiIsIlVuc3VwcG9ydGVkSG9tZXNlcnZlclNwZWNWZXJzaW9uIiwiQXV0b0Rpc2NvdmVyeVV0aWxzIiwiaXNMaXZlbGluZXNzRXJyb3IiLCJlcnJvciIsIm1zZyIsIlVzZXJGcmllbmRseUVycm9yIiwiY2F1c2UiLCJFcnJvciIsIm1lc3NhZ2UiLCJhdXRoQ29tcG9uZW50U3RhdGVGb3JFcnJvciIsInBhZ2VOYW1lIiwic2VydmVySXNBbGl2ZSIsInNlcnZlckVycm9ySXNGYXRhbCIsInNlcnZlckRlYWRFcnJvciIsInRpdGxlIiwiX3QiLCJib2R5IiwiYnJhbmQiLCJTZGtDb25maWciLCJnZXQiLCJhIiwic3ViIiwiZGVmYXVsdCIsImNyZWF0ZUVsZW1lbnQiLCJocmVmIiwidGFyZ2V0IiwicmVsIiwiaXNGYXRhbEVycm9yIiwiZXJyb3JNZXNzYWdlIiwidmFsaWRhdGVTZXJ2ZXJDb25maWdXaXRoU3RhdGljVXJscyIsImhvbWVzZXJ2ZXJVcmwiLCJpZGVudGl0eVVybCIsInN5bnRheE9ubHkiLCJ3ZWxsa25vd25Db25maWciLCJiYXNlX3VybCIsInJlc3VsdCIsImZyb21EaXNjb3ZlcnlDb25maWciLCJ1cmwiLCJVUkwiLCJzZXJ2ZXJOYW1lIiwiaG9zdG5hbWUiLCJidWlsZFZhbGlkYXRlZENvbmZpZ0Zyb21EaXNjb3ZlcnkiLCJ2YWxpZGF0ZVNlcnZlck5hbWUiLCJmaW5kQ2xpZW50Q29uZmlnIiwiZGlzY292ZXJ5UmVzdWx0IiwiaXNTeW50aGV0aWMiLCJsb2dnZXIiLCJoc1Jlc3VsdCIsImlzUmVzdWx0IiwiZGVmYXVsdENvbmZpZyIsInByZWZlcnJlZElkZW50aXR5VXJsIiwic3RhdGUiLCJTVUNDRVNTIiwidW5kZWZpbmVkIiwiUFJPTVBUIiwiRkFJTF9FUlJPUiIsInByZWZlcnJlZEhvbWVzZXJ2ZXJVcmwiLCJwcmVmZXJyZWRIb21lc2VydmVyTmFtZSIsImRlbGVnYXRlZEF1dGhlbnRpY2F0aW9uIiwiZGVsZWdhdGVkQXV0aGVudGljYXRpb25FcnJvciIsInRlbXBDbGllbnQiLCJNYXRyaXhDbGllbnQiLCJiYXNlVXJsIiwiaXNzdWVyIiwiZ2V0QXV0aElzc3VlciIsImRpc2NvdmVyQW5kVmFsaWRhdGVPSURDSXNzdWVyV2VsbEtub3duIiwiZSIsIk1hdHJpeEVycm9yIiwiaHR0cFN0YXR1cyIsImVycmNvZGUiLCJoc1VybCIsImhzTmFtZSIsImhzTmFtZUlzRGlmZmVyZW50IiwiaXNVcmwiLCJpc0RlZmF1bHQiLCJ3YXJuaW5nIiwiaXNOYW1lUmVzb2x2YWJsZSIsImV4cG9ydHMiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvQXV0b0Rpc2NvdmVyeVV0aWxzLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMjQgTmV3IFZlY3RvciBMdGQuXG5Db3B5cmlnaHQgMjAxOS0yMDIxIFRoZSBNYXRyaXgub3JnIEZvdW5kYXRpb24gQy5JLkMuXG5cblNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBR1BMLTMuMC1vbmx5IE9SIEdQTC0zLjAtb25seVxuUGxlYXNlIHNlZSBMSUNFTlNFIGZpbGVzIGluIHRoZSByZXBvc2l0b3J5IHJvb3QgZm9yIGZ1bGwgZGV0YWlscy5cbiovXG5cbmltcG9ydCBSZWFjdCwgeyBSZWFjdE5vZGUgfSBmcm9tIFwicmVhY3RcIjtcbmltcG9ydCB7XG4gICAgQXV0b0Rpc2NvdmVyeSxcbiAgICBBdXRvRGlzY292ZXJ5RXJyb3IsXG4gICAgQ2xpZW50Q29uZmlnLFxuICAgIGRpc2NvdmVyQW5kVmFsaWRhdGVPSURDSXNzdWVyV2VsbEtub3duLFxuICAgIElDbGllbnRXZWxsS25vd24sXG4gICAgTWF0cml4Q2xpZW50LFxuICAgIE1hdHJpeEVycm9yLFxuICAgIE9pZGNDbGllbnRDb25maWcsXG59IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9tYXRyaXhcIjtcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gXCJtYXRyaXgtanMtc2RrL3NyYy9sb2dnZXJcIjtcblxuaW1wb3J0IHsgX3QsIF90ZCwgVHJhbnNsYXRpb25LZXksIFVzZXJGcmllbmRseUVycm9yIH0gZnJvbSBcIi4uL2xhbmd1YWdlSGFuZGxlclwiO1xuaW1wb3J0IFNka0NvbmZpZyBmcm9tIFwiLi4vU2RrQ29uZmlnXCI7XG5pbXBvcnQgeyBWYWxpZGF0ZWRTZXJ2ZXJDb25maWcgfSBmcm9tIFwiLi9WYWxpZGF0ZWRTZXJ2ZXJDb25maWdcIjtcblxuY29uc3QgTElWRUxJTkVTU19ESVNDT1ZFUllfRVJST1JTOiBBdXRvRGlzY292ZXJ5RXJyb3JbXSA9IFtcbiAgICBBdXRvRGlzY292ZXJ5LkVSUk9SX0lOVkFMSURfSE9NRVNFUlZFUixcbiAgICBBdXRvRGlzY292ZXJ5LkVSUk9SX0lOVkFMSURfSURFTlRJVFlfU0VSVkVSLFxuXTtcblxuZXhwb3J0IGludGVyZmFjZSBJQXV0aENvbXBvbmVudFN0YXRlIHtcbiAgICBzZXJ2ZXJJc0FsaXZlOiBib29sZWFuO1xuICAgIHNlcnZlckVycm9ySXNGYXRhbDogYm9vbGVhbjtcbiAgICBzZXJ2ZXJEZWFkRXJyb3I/OiBSZWFjdE5vZGU7XG59XG5cbmNvbnN0IEF1dG9EaXNjb3ZlcnlFcnJvcnMgPSBPYmplY3QudmFsdWVzKEF1dG9EaXNjb3ZlcnlFcnJvcik7XG5cbmNvbnN0IGlzQXV0b0Rpc2NvdmVyeUVycm9yID0gKGVycjogdW5rbm93bik6IGVyciBpcyBBdXRvRGlzY292ZXJ5RXJyb3IgPT4ge1xuICAgIHJldHVybiBBdXRvRGlzY292ZXJ5RXJyb3JzLmluY2x1ZGVzKGVyciBhcyBBdXRvRGlzY292ZXJ5RXJyb3IpO1xufTtcblxuY29uc3QgbWFwQXV0b0Rpc2NvdmVyeUVycm9yVHJhbnNsYXRpb24gPSAoZXJyOiBBdXRvRGlzY292ZXJ5RXJyb3IpOiBUcmFuc2xhdGlvbktleSA9PiB7XG4gICAgc3dpdGNoIChlcnIpIHtcbiAgICAgICAgY2FzZSBBdXRvRGlzY292ZXJ5RXJyb3IuR2VuZXJpY0ZhaWx1cmU6XG4gICAgICAgICAgICByZXR1cm4gX3RkKFwiYXV0aHxhdXRvZGlzY292ZXJ5X2ludmFsaWRcIik7XG4gICAgICAgIGNhc2UgQXV0b0Rpc2NvdmVyeUVycm9yLkludmFsaWQ6XG4gICAgICAgICAgICByZXR1cm4gX3RkKFwiYXV0aHxhdXRvZGlzY292ZXJ5X2dlbmVyaWNfZmFpbHVyZVwiKTtcbiAgICAgICAgY2FzZSBBdXRvRGlzY292ZXJ5RXJyb3IuSW52YWxpZEhzQmFzZVVybDpcbiAgICAgICAgICAgIHJldHVybiBfdGQoXCJhdXRofGF1dG9kaXNjb3ZlcnlfaW52YWxpZF9oc19iYXNlX3VybFwiKTtcbiAgICAgICAgY2FzZSBBdXRvRGlzY292ZXJ5RXJyb3IuSW52YWxpZEhvbWVzZXJ2ZXI6XG4gICAgICAgICAgICByZXR1cm4gX3RkKFwiYXV0aHxhdXRvZGlzY292ZXJ5X2ludmFsaWRfaHNcIik7XG4gICAgICAgIGNhc2UgQXV0b0Rpc2NvdmVyeUVycm9yLkludmFsaWRJc0Jhc2VVcmw6XG4gICAgICAgICAgICByZXR1cm4gX3RkKFwiYXV0aHxhdXRvZGlzY292ZXJ5X2ludmFsaWRfaXNfYmFzZV91cmxcIik7XG4gICAgICAgIGNhc2UgQXV0b0Rpc2NvdmVyeUVycm9yLkludmFsaWRJZGVudGl0eVNlcnZlcjpcbiAgICAgICAgICAgIHJldHVybiBfdGQoXCJhdXRofGF1dG9kaXNjb3ZlcnlfaW52YWxpZF9pc1wiKTtcbiAgICAgICAgY2FzZSBBdXRvRGlzY292ZXJ5RXJyb3IuSW52YWxpZElzOlxuICAgICAgICAgICAgcmV0dXJuIF90ZChcImF1dGh8YXV0b2Rpc2NvdmVyeV9pbnZhbGlkX2lzX3Jlc3BvbnNlXCIpO1xuICAgICAgICBjYXNlIEF1dG9EaXNjb3ZlcnlFcnJvci5NaXNzaW5nV2VsbGtub3duOlxuICAgICAgICAgICAgcmV0dXJuIF90ZChcImF1dGh8YXV0b2Rpc2NvdmVyeV9ub193ZWxsX2tub3duXCIpO1xuICAgICAgICBjYXNlIEF1dG9EaXNjb3ZlcnlFcnJvci5JbnZhbGlkSnNvbjpcbiAgICAgICAgICAgIHJldHVybiBfdGQoXCJhdXRofGF1dG9kaXNjb3ZlcnlfaW52YWxpZF9qc29uXCIpO1xuICAgICAgICBjYXNlIEF1dG9EaXNjb3ZlcnlFcnJvci5VbnN1cHBvcnRlZEhvbWVzZXJ2ZXJTcGVjVmVyc2lvbjpcbiAgICAgICAgICAgIHJldHVybiBfdGQoXCJhdXRofGF1dG9kaXNjb3ZlcnlfaHNfaW5jb21wYXRpYmxlXCIpO1xuICAgIH1cbn07XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEF1dG9EaXNjb3ZlcnlVdGlscyB7XG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGlmIGEgZ2l2ZW4gZXJyb3Igb3IgZXJyb3IgbWVzc2FnZSBpcyBjb25zaWRlcmVkIGFuIGVycm9yXG4gICAgICogcmVsYXRpbmcgdG8gdGhlIGxpdmVsaW5lc3Mgb2YgdGhlIHNlcnZlci4gTXVzdCBiZSBhbiBlcnJvciByZXR1cm5lZFxuICAgICAqIGZyb20gdGhpcyBBdXRvRGlzY292ZXJ5VXRpbHMgY2xhc3MuXG4gICAgICogQHBhcmFtIHtzdHJpbmcgfCBFcnJvcn0gZXJyb3IgVGhlIGVycm9yIHRvIGNoZWNrXG4gICAgICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgdGhlIGVycm9yIGlzIGEgbGl2ZWxpbmVzcyBlcnJvci5cbiAgICAgKi9cbiAgICBwdWJsaWMgc3RhdGljIGlzTGl2ZWxpbmVzc0Vycm9yKGVycm9yOiB1bmtub3duKTogYm9vbGVhbiB7XG4gICAgICAgIGlmICghZXJyb3IpIHJldHVybiBmYWxzZTtcbiAgICAgICAgbGV0IG1zZzogdW5rbm93biA9IGVycm9yO1xuICAgICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBVc2VyRnJpZW5kbHlFcnJvcikge1xuICAgICAgICAgICAgbXNnID0gZXJyb3IuY2F1c2U7XG4gICAgICAgIH0gZWxzZSBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICAgICAgbXNnID0gZXJyb3IubWVzc2FnZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gTElWRUxJTkVTU19ESVNDT1ZFUllfRVJST1JTLmluY2x1ZGVzKG1zZyBhcyBBdXRvRGlzY292ZXJ5RXJyb3IpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIGNvbW1vbiBzdGF0ZSBmb3IgYXV0aCBjb21wb25lbnRzIChsb2dpbiwgcmVnaXN0cmF0aW9uLCBmb3Jnb3RcbiAgICAgKiBwYXNzd29yZCkgZm9yIGEgZ2l2ZW4gdmFsaWRhdGlvbiBlcnJvci5cbiAgICAgKiBAcGFyYW0ge0Vycm9yfSBlcnIgVGhlIGVycm9yIGVuY291bnRlcmVkLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwYWdlTmFtZSBUaGUgcGFnZSBmb3Igd2hpY2ggdGhlIGVycm9yIHNob3VsZCBiZSBjdXN0b21pemVkIHRvLiBTZWVcbiAgICAgKiBpbXBsZW1lbnRhdGlvbiBmb3Iga25vd24gdmFsdWVzLlxuICAgICAqIEByZXR1cm5zIHsqfSBUaGUgc3RhdGUgZm9yIHRoZSBjb21wb25lbnQsIGdpdmVuIHRoZSBlcnJvci5cbiAgICAgKi9cbiAgICBwdWJsaWMgc3RhdGljIGF1dGhDb21wb25lbnRTdGF0ZUZvckVycm9yKGVycjogdW5rbm93biwgcGFnZU5hbWUgPSBcImxvZ2luXCIpOiBJQXV0aENvbXBvbmVudFN0YXRlIHtcbiAgICAgICAgaWYgKCFlcnIpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgc2VydmVySXNBbGl2ZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICBzZXJ2ZXJFcnJvcklzRmF0YWw6IGZhbHNlLFxuICAgICAgICAgICAgICAgIHNlcnZlckRlYWRFcnJvcjogbnVsbCxcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHRpdGxlID0gX3QoXCJjYW5ub3RfcmVhY2hfaG9tZXNlcnZlclwiKTtcbiAgICAgICAgbGV0IGJvZHk6IFJlYWN0Tm9kZSA9IF90KFwiY2Fubm90X3JlYWNoX2hvbWVzZXJ2ZXJfZGV0YWlsXCIpO1xuICAgICAgICBpZiAoIUF1dG9EaXNjb3ZlcnlVdGlscy5pc0xpdmVsaW5lc3NFcnJvcihlcnIpKSB7XG4gICAgICAgICAgICBjb25zdCBicmFuZCA9IFNka0NvbmZpZy5nZXQoKS5icmFuZDtcbiAgICAgICAgICAgIHRpdGxlID0gX3QoXCJhdXRofG1pc2NvbmZpZ3VyZWRfdGl0bGVcIiwgeyBicmFuZCB9KTtcbiAgICAgICAgICAgIGJvZHkgPSBfdChcbiAgICAgICAgICAgICAgICBcImF1dGh8bWlzY29uZmlndXJlZF9ib2R5XCIsXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBicmFuZCxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgYTogKHN1YikgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8YVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBocmVmPVwiaHR0cHM6Ly9naXRodWIuY29tL3ZlY3Rvci1pbS9lbGVtZW50LXdlYi9ibG9iL21hc3Rlci9kb2NzL2NvbmZpZy5tZFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldD1cIl9ibGFua1wiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbD1cIm5vcmVmZXJyZXIgbm9vcGVuZXJcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge3N1Yn1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8L2E+XG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGlzRmF0YWxFcnJvciA9IHRydWU7XG4gICAgICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiBlcnI7XG4gICAgICAgIGlmIChlcnJvck1lc3NhZ2UgPT09IEF1dG9EaXNjb3ZlcnkuRVJST1JfSU5WQUxJRF9JREVOVElUWV9TRVJWRVIpIHtcbiAgICAgICAgICAgIGlzRmF0YWxFcnJvciA9IGZhbHNlO1xuICAgICAgICAgICAgdGl0bGUgPSBfdChcImF1dGh8ZmFpbGVkX2Nvbm5lY3RfaWRlbnRpdHlfc2VydmVyXCIpO1xuXG4gICAgICAgICAgICAvLyBJdCdzIGFubm95aW5nIGhhdmluZyBhIGxhZGRlciBmb3IgdGhlIHRoaXJkIHdvcmQgaW4gdGhlIHNhbWUgc2VudGVuY2UsIGJ1dCBvdXIgdHJhbnNsYXRpb25zXG4gICAgICAgICAgICAvLyBkb24ndCBtYWtlIHRoaXMgZWFzeSB0byBhdm9pZC5cbiAgICAgICAgICAgIGlmIChwYWdlTmFtZSA9PT0gXCJyZWdpc3RlclwiKSB7XG4gICAgICAgICAgICAgICAgYm9keSA9IF90KFwiYXV0aHxmYWlsZWRfY29ubmVjdF9pZGVudGl0eV9zZXJ2ZXJfcmVnaXN0ZXJcIik7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHBhZ2VOYW1lID09PSBcInJlc2V0X3Bhc3N3b3JkXCIpIHtcbiAgICAgICAgICAgICAgICBib2R5ID0gX3QoXCJhdXRofGZhaWxlZF9jb25uZWN0X2lkZW50aXR5X3NlcnZlcl9yZXNldF9wYXNzd29yZFwiKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgYm9keSA9IF90KFwiYXV0aHxmYWlsZWRfY29ubmVjdF9pZGVudGl0eV9zZXJ2ZXJfb3RoZXJcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgc2VydmVySXNBbGl2ZTogZmFsc2UsXG4gICAgICAgICAgICBzZXJ2ZXJFcnJvcklzRmF0YWw6IGlzRmF0YWxFcnJvcixcbiAgICAgICAgICAgIHNlcnZlckRlYWRFcnJvcjogKFxuICAgICAgICAgICAgICAgIDxkaXY+XG4gICAgICAgICAgICAgICAgICAgIDxzdHJvbmc+e3RpdGxlfTwvc3Ryb25nPlxuICAgICAgICAgICAgICAgICAgICA8ZGl2Pntib2R5fTwvZGl2PlxuICAgICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgKSxcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBWYWxpZGF0ZXMgYSBzZXJ2ZXIgY29uZmlndXJhdGlvbiwgdXNpbmcgYSBwYWlyIG9mIFVSTHMgYXMgaW5wdXQuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGhvbWVzZXJ2ZXJVcmwgVGhlIGhvbWVzZXJ2ZXIgVVJMLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBpZGVudGl0eVVybCBUaGUgaWRlbnRpdHkgc2VydmVyIFVSTC5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN5bnRheE9ubHkgSWYgdHJ1ZSwgZXJyb3JzIHJlbGF0aW5nIHRvIGxpdmVsaW5lc3Mgb2YgdGhlIHNlcnZlcnMgd2lsbFxuICAgICAqIG5vdCBiZSByYWlzZWQuXG4gICAgICogQHJldHVybnMge1Byb21pc2U8VmFsaWRhdGVkU2VydmVyQ29uZmlnPn0gUmVzb2x2ZXMgdG8gdGhlIHZhbGlkYXRlZCBjb25maWd1cmF0aW9uLlxuICAgICAqL1xuICAgIHB1YmxpYyBzdGF0aWMgYXN5bmMgdmFsaWRhdGVTZXJ2ZXJDb25maWdXaXRoU3RhdGljVXJscyhcbiAgICAgICAgaG9tZXNlcnZlclVybDogc3RyaW5nLFxuICAgICAgICBpZGVudGl0eVVybD86IHN0cmluZyxcbiAgICAgICAgc3ludGF4T25seSA9IGZhbHNlLFxuICAgICk6IFByb21pc2U8VmFsaWRhdGVkU2VydmVyQ29uZmlnPiB7XG4gICAgICAgIGlmICghaG9tZXNlcnZlclVybCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFVzZXJGcmllbmRseUVycm9yKFwiYXV0aHxub19oc191cmxfcHJvdmlkZWRcIik7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB3ZWxsa25vd25Db25maWc6IElDbGllbnRXZWxsS25vd24gPSB7XG4gICAgICAgICAgICBcIm0uaG9tZXNlcnZlclwiOiB7XG4gICAgICAgICAgICAgICAgYmFzZV91cmw6IGhvbWVzZXJ2ZXJVcmwsXG4gICAgICAgICAgICB9LFxuICAgICAgICB9O1xuXG4gICAgICAgIGlmIChpZGVudGl0eVVybCkge1xuICAgICAgICAgICAgd2VsbGtub3duQ29uZmlnW1wibS5pZGVudGl0eV9zZXJ2ZXJcIl0gPSB7XG4gICAgICAgICAgICAgICAgYmFzZV91cmw6IGlkZW50aXR5VXJsLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IEF1dG9EaXNjb3ZlcnkuZnJvbURpc2NvdmVyeUNvbmZpZyh3ZWxsa25vd25Db25maWcpO1xuXG4gICAgICAgIGNvbnN0IHVybCA9IG5ldyBVUkwoaG9tZXNlcnZlclVybCk7XG4gICAgICAgIGNvbnN0IHNlcnZlck5hbWUgPSB1cmwuaG9zdG5hbWU7XG5cbiAgICAgICAgcmV0dXJuIEF1dG9EaXNjb3ZlcnlVdGlscy5idWlsZFZhbGlkYXRlZENvbmZpZ0Zyb21EaXNjb3Zlcnkoc2VydmVyTmFtZSwgcmVzdWx0LCBzeW50YXhPbmx5LCB0cnVlKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBWYWxpZGF0ZXMgYSBzZXJ2ZXIgY29uZmlndXJhdGlvbiwgdXNpbmcgYSBob21lc2VydmVyIGRvbWFpbiBuYW1lIGFzIGlucHV0LlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBzZXJ2ZXJOYW1lIFRoZSBob21lc2VydmVyIGRvbWFpbiBuYW1lIChlZzogXCJtYXRyaXgub3JnXCIpIHRvIHZhbGlkYXRlLlxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPFZhbGlkYXRlZFNlcnZlckNvbmZpZz59IFJlc29sdmVzIHRvIHRoZSB2YWxpZGF0ZWQgY29uZmlndXJhdGlvbi5cbiAgICAgKi9cbiAgICBwdWJsaWMgc3RhdGljIGFzeW5jIHZhbGlkYXRlU2VydmVyTmFtZShzZXJ2ZXJOYW1lOiBzdHJpbmcpOiBQcm9taXNlPFZhbGlkYXRlZFNlcnZlckNvbmZpZz4ge1xuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBBdXRvRGlzY292ZXJ5LmZpbmRDbGllbnRDb25maWcoc2VydmVyTmFtZSk7XG4gICAgICAgIHJldHVybiBBdXRvRGlzY292ZXJ5VXRpbHMuYnVpbGRWYWxpZGF0ZWRDb25maWdGcm9tRGlzY292ZXJ5KHNlcnZlck5hbWUsIHJlc3VsdCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVmFsaWRhdGVzIGEgc2VydmVyIGNvbmZpZ3VyYXRpb24sIHVzaW5nIGEgcHJlLWNhbGN1bGF0ZWQgQXV0b0Rpc2NvdmVyeSByZXN1bHQgYXNcbiAgICAgKiBpbnB1dC5cbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gc2VydmVyTmFtZSBUaGUgZG9tYWluIG5hbWUgdGhlIEF1dG9EaXNjb3ZlcnkgcmVzdWx0IGlzIGZvci5cbiAgICAgKiBAcGFyYW0geyp9IGRpc2NvdmVyeVJlc3VsdCBUaGUgQXV0b0Rpc2NvdmVyeSByZXN1bHQuXG4gICAgICogQHBhcmFtIHtib29sZWFufSBzeW50YXhPbmx5IElmIHRydWUsIGVycm9ycyByZWxhdGluZyB0byBsaXZlbGluZXNzIG9mIHRoZSBzZXJ2ZXJzIHdpbGwgbm90IGJlIHJhaXNlZC5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IGlzU3ludGhldGljIElmIHRydWUsIHRoZW4gdGhlIGRpc2NvdmVyeVJlc3VsdCB3YXMgc3ludGhlc2lzZWQgbG9jYWxseS5cbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxWYWxpZGF0ZWRTZXJ2ZXJDb25maWc+fSBSZXNvbHZlcyB0byB0aGUgdmFsaWRhdGVkIGNvbmZpZ3VyYXRpb24uXG4gICAgICovXG4gICAgcHVibGljIHN0YXRpYyBhc3luYyBidWlsZFZhbGlkYXRlZENvbmZpZ0Zyb21EaXNjb3ZlcnkoXG4gICAgICAgIHNlcnZlck5hbWU/OiBzdHJpbmcsXG4gICAgICAgIGRpc2NvdmVyeVJlc3VsdD86IENsaWVudENvbmZpZyxcbiAgICAgICAgc3ludGF4T25seSA9IGZhbHNlLFxuICAgICAgICBpc1N5bnRoZXRpYyA9IGZhbHNlLFxuICAgICk6IFByb21pc2U8VmFsaWRhdGVkU2VydmVyQ29uZmlnPiB7XG4gICAgICAgIGlmICghZGlzY292ZXJ5UmVzdWx0Py5bXCJtLmhvbWVzZXJ2ZXJcIl0pIHtcbiAgICAgICAgICAgIC8vIFRoaXMgc2hvdWxkbid0IGhhcHBlbiB3aXRob3V0IG1ham9yIG1pc2NvbmZpZ3VyYXRpb24sIHNvIHdlJ2xsIGxvZyBhIGJpdCBvZiBpbmZvcm1hdGlvblxuICAgICAgICAgICAgLy8gaW4gdGhlIGxvZyBzbyB3ZSBjYW4gZmluZCB0aGlzIGJpdCBvZiBjb2RlIGJ1dCBvdGhlcndpc2UgdGVsbCB0aGUgdXNlciBcIml0IGJyb2tlXCIuXG4gICAgICAgICAgICBsb2dnZXIuZXJyb3IoXCJFbmRlZCB1cCBpbiBhIHN0YXRlIG9mIG5vdCBrbm93aW5nIHdoaWNoIGhvbWVzZXJ2ZXIgdG8gY29ubmVjdCB0by5cIik7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVXNlckZyaWVuZGx5RXJyb3IoXCJhdXRofGF1dG9kaXNjb3ZlcnlfdW5leHBlY3RlZF9lcnJvcl9oc1wiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGhzUmVzdWx0ID0gZGlzY292ZXJ5UmVzdWx0W1wibS5ob21lc2VydmVyXCJdO1xuICAgICAgICBjb25zdCBpc1Jlc3VsdCA9IGRpc2NvdmVyeVJlc3VsdFtcIm0uaWRlbnRpdHlfc2VydmVyXCJdO1xuXG4gICAgICAgIGNvbnN0IGRlZmF1bHRDb25maWcgPSBTZGtDb25maWcuZ2V0KFwidmFsaWRhdGVkX3NlcnZlcl9jb25maWdcIik7XG5cbiAgICAgICAgLy8gVmFsaWRhdGUgdGhlIGlkZW50aXR5IHNlcnZlciBmaXJzdCBiZWNhdXNlIGFuIGludmFsaWQgaWRlbnRpdHkgc2VydmVyIGNhdXNlc1xuICAgICAgICAvLyBhbiBpbnZhbGlkIGhvbWVzZXJ2ZXIsIHdoaWNoIG1heSBub3QgYmUgcGlja2VkIHVwIGNvcnJlY3RseS5cblxuICAgICAgICAvLyBOb3RlOiBJbiB0aGUgY2FzZXMgd2hlcmUgd2UgcmVseSBvbiB0aGUgZGVmYXVsdCBJUyBmcm9tIHRoZSBjb25maWcgKG5hbWVseVxuICAgICAgICAvLyBsYWNrIG9mIGlkZW50aXR5IHNlcnZlciBwcm92aWRlZCBieSB0aGUgZGlzY292ZXJ5IG1ldGhvZCksIHdlIGludGVudGlvbmFsbHkgZG8gbm90XG4gICAgICAgIC8vIHZhbGlkYXRlIGl0LiBUaGlzIGhhcyBhbHJlYWR5IGJlZW4gdmFsaWRhdGVkIGFuZCB0aGlzIGhlbHBzIHNvbWUgb2ZmLXRoZS1ncmlkIHVzYWdlXG4gICAgICAgIC8vIG9mIEVsZW1lbnQuXG4gICAgICAgIGxldCBwcmVmZXJyZWRJZGVudGl0eVVybCA9IGRlZmF1bHRDb25maWcgJiYgZGVmYXVsdENvbmZpZ1tcImlzVXJsXCJdO1xuICAgICAgICBpZiAoaXNSZXN1bHQgJiYgaXNSZXN1bHQuc3RhdGUgPT09IEF1dG9EaXNjb3ZlcnkuU1VDQ0VTUykge1xuICAgICAgICAgICAgcHJlZmVycmVkSWRlbnRpdHlVcmwgPSBpc1Jlc3VsdFtcImJhc2VfdXJsXCJdID8/IHVuZGVmaW5lZDtcbiAgICAgICAgfSBlbHNlIGlmIChpc1Jlc3VsdCAmJiBpc1Jlc3VsdC5zdGF0ZSAhPT0gQXV0b0Rpc2NvdmVyeS5QUk9NUFQpIHtcbiAgICAgICAgICAgIGxvZ2dlci5lcnJvcihcIkVycm9yIGRldGVybWluaW5nIHByZWZlcnJlZCBpZGVudGl0eSBzZXJ2ZXIgVVJMOlwiLCBpc1Jlc3VsdCk7XG4gICAgICAgICAgICBpZiAoaXNSZXN1bHQuc3RhdGUgPT09IEF1dG9EaXNjb3ZlcnkuRkFJTF9FUlJPUikge1xuICAgICAgICAgICAgICAgIGlmIChpc0F1dG9EaXNjb3ZlcnlFcnJvcihpc1Jlc3VsdC5lcnJvcikpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IFVzZXJGcmllbmRseUVycm9yKG1hcEF1dG9EaXNjb3ZlcnlFcnJvclRyYW5zbGF0aW9uKGlzUmVzdWx0LmVycm9yKSwge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2F1c2U6IGhzUmVzdWx0LmVycm9yLFxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IFVzZXJGcmllbmRseUVycm9yKFwiYXV0aHxhdXRvZGlzY292ZXJ5X3VuZXhwZWN0ZWRfZXJyb3JfaXNcIik7XG4gICAgICAgICAgICB9IC8vIGVsc2UgdGhlIGVycm9yIGlzIG5vdCByZWxhdGVkIHRvIHN5bnRheCAtIGNvbnRpbnVlIGFueXdheXMuXG5cbiAgICAgICAgICAgIC8vIHJld3JpdGUgaG9tZXNlcnZlciBlcnJvciBzaW5jZSB3ZSBkb24ndCBjYXJlIGFib3V0IHByb2JsZW1zXG4gICAgICAgICAgICBoc1Jlc3VsdC5lcnJvciA9IEF1dG9EaXNjb3ZlcnkuRVJST1JfSU5WQUxJRF9JREVOVElUWV9TRVJWRVI7XG5cbiAgICAgICAgICAgIC8vIEFsc28gdXNlIHRoZSB1c2VyJ3Mgc3VwcGxpZWQgaWRlbnRpdHkgc2VydmVyIGlmIHByb3ZpZGVkXG4gICAgICAgICAgICBpZiAoaXNSZXN1bHRbXCJiYXNlX3VybFwiXSkgcHJlZmVycmVkSWRlbnRpdHlVcmwgPSBpc1Jlc3VsdFtcImJhc2VfdXJsXCJdO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGhzUmVzdWx0LnN0YXRlICE9PSBBdXRvRGlzY292ZXJ5LlNVQ0NFU1MpIHtcbiAgICAgICAgICAgIGxvZ2dlci5lcnJvcihcIkVycm9yIHByb2Nlc3NpbmcgaG9tZXNlcnZlciBjb25maWc6XCIsIGhzUmVzdWx0KTtcbiAgICAgICAgICAgIGlmICghc3ludGF4T25seSB8fCAhQXV0b0Rpc2NvdmVyeVV0aWxzLmlzTGl2ZWxpbmVzc0Vycm9yKGhzUmVzdWx0LmVycm9yKSkge1xuICAgICAgICAgICAgICAgIGlmIChpc0F1dG9EaXNjb3ZlcnlFcnJvcihoc1Jlc3VsdC5lcnJvcikpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IFVzZXJGcmllbmRseUVycm9yKG1hcEF1dG9EaXNjb3ZlcnlFcnJvclRyYW5zbGF0aW9uKGhzUmVzdWx0LmVycm9yKSwge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2F1c2U6IGhzUmVzdWx0LmVycm9yLFxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IFVzZXJGcmllbmRseUVycm9yKFwiYXV0aHxhdXRvZGlzY292ZXJ5X3VuZXhwZWN0ZWRfZXJyb3JfaHNcIik7XG4gICAgICAgICAgICB9IC8vIGVsc2UgdGhlIGVycm9yIGlzIG5vdCByZWxhdGVkIHRvIHN5bnRheCAtIGNvbnRpbnVlIGFueXdheXMuXG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBwcmVmZXJyZWRIb21lc2VydmVyVXJsID0gaHNSZXN1bHRbXCJiYXNlX3VybFwiXTtcblxuICAgICAgICBpZiAoIXByZWZlcnJlZEhvbWVzZXJ2ZXJVcmwpIHtcbiAgICAgICAgICAgIGxvZ2dlci5lcnJvcihcIk5vIGhvbWVzZXJ2ZXIgVVJMIGNvbmZpZ3VyZWRcIik7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVXNlckZyaWVuZGx5RXJyb3IoXCJhdXRofGF1dG9kaXNjb3ZlcnlfdW5leHBlY3RlZF9lcnJvcl9oc1wiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBwcmVmZXJyZWRIb21lc2VydmVyTmFtZSA9IHNlcnZlck5hbWUgPz8gaHNSZXN1bHRbXCJzZXJ2ZXJfbmFtZVwiXTtcblxuICAgICAgICBjb25zdCB1cmwgPSBuZXcgVVJMKHByZWZlcnJlZEhvbWVzZXJ2ZXJVcmwpO1xuICAgICAgICBpZiAoIXByZWZlcnJlZEhvbWVzZXJ2ZXJOYW1lKSBwcmVmZXJyZWRIb21lc2VydmVyTmFtZSA9IHVybC5ob3N0bmFtZTtcblxuICAgICAgICAvLyBJdCBzaG91bGQgaGF2ZSBiZWVuIHNldCBieSBub3csIHNvIGNoZWNrIGl0XG4gICAgICAgIGlmICghcHJlZmVycmVkSG9tZXNlcnZlck5hbWUpIHtcbiAgICAgICAgICAgIGxvZ2dlci5lcnJvcihcIkZhaWxlZCB0byBwYXJzZSBob21lc2VydmVyIG5hbWUgZnJvbSBob21lc2VydmVyIFVSTFwiKTtcbiAgICAgICAgICAgIHRocm93IG5ldyBVc2VyRnJpZW5kbHlFcnJvcihcImF1dGh8YXV0b2Rpc2NvdmVyeV91bmV4cGVjdGVkX2Vycm9yX2hzXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gVGhpcyBpc24ndCBpbmhlcmVudGx5IGF1dG8tZGlzY292ZXJ5IGJ1dCB1c2VkIHRvIGJlIGluIGFuIGVhcmxpZXIgaW5jYXJuYXRpb24gb2YgdGhlIE1TQyxcbiAgICAgICAgLy8gYW5kIHNodXR0bGluZyB0aGUgZGF0YSB0b2dldGhlciBtYWtlcyBhIGxvdCBvZiBzZW5zZVxuICAgICAgICBsZXQgZGVsZWdhdGVkQXV0aGVudGljYXRpb246IE9pZGNDbGllbnRDb25maWcgfCB1bmRlZmluZWQ7XG4gICAgICAgIGxldCBkZWxlZ2F0ZWRBdXRoZW50aWNhdGlvbkVycm9yOiBFcnJvciB8IHVuZGVmaW5lZDtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IHRlbXBDbGllbnQgPSBuZXcgTWF0cml4Q2xpZW50KHsgYmFzZVVybDogcHJlZmVycmVkSG9tZXNlcnZlclVybCB9KTtcbiAgICAgICAgICAgIGNvbnN0IHsgaXNzdWVyIH0gPSBhd2FpdCB0ZW1wQ2xpZW50LmdldEF1dGhJc3N1ZXIoKTtcbiAgICAgICAgICAgIGRlbGVnYXRlZEF1dGhlbnRpY2F0aW9uID0gYXdhaXQgZGlzY292ZXJBbmRWYWxpZGF0ZU9JRENJc3N1ZXJXZWxsS25vd24oaXNzdWVyKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgaWYgKGUgaW5zdGFuY2VvZiBNYXRyaXhFcnJvciAmJiBlLmh0dHBTdGF0dXMgPT09IDQwNCAmJiBlLmVycmNvZGUgPT09IFwiTV9VTlJFQ09HTklaRURcIikge1xuICAgICAgICAgICAgICAgIC8vIDQwNCBNX1VOUkVDT0dOSVpFRCBtZWFucyB0aGUgc2VydmVyIGRvZXMgbm90IHN1cHBvcnQgT0lEQ1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBkZWxlZ2F0ZWRBdXRoZW50aWNhdGlvbkVycm9yID0gZSBhcyBFcnJvcjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBoc1VybDogcHJlZmVycmVkSG9tZXNlcnZlclVybCxcbiAgICAgICAgICAgIGhzTmFtZTogcHJlZmVycmVkSG9tZXNlcnZlck5hbWUsXG4gICAgICAgICAgICBoc05hbWVJc0RpZmZlcmVudDogdXJsLmhvc3RuYW1lICE9PSBwcmVmZXJyZWRIb21lc2VydmVyTmFtZSxcbiAgICAgICAgICAgIGlzVXJsOiBwcmVmZXJyZWRJZGVudGl0eVVybCxcbiAgICAgICAgICAgIGlzRGVmYXVsdDogZmFsc2UsXG4gICAgICAgICAgICB3YXJuaW5nOiBoc1Jlc3VsdC5lcnJvciA/PyBkZWxlZ2F0ZWRBdXRoZW50aWNhdGlvbkVycm9yID8/IG51bGwsXG4gICAgICAgICAgICBpc05hbWVSZXNvbHZhYmxlOiAhaXNTeW50aGV0aWMsXG4gICAgICAgICAgICBkZWxlZ2F0ZWRBdXRoZW50aWNhdGlvbixcbiAgICAgICAgfSBhcyBWYWxpZGF0ZWRTZXJ2ZXJDb25maWc7XG4gICAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBUUEsSUFBQUEsTUFBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUMsT0FBQSxHQUFBRCxPQUFBO0FBVUEsSUFBQUUsT0FBQSxHQUFBRixPQUFBO0FBRUEsSUFBQUcsZ0JBQUEsR0FBQUgsT0FBQTtBQUNBLElBQUFJLFVBQUEsR0FBQUwsc0JBQUEsQ0FBQUMsT0FBQTtBQXRCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFtQkEsTUFBTUssMkJBQWlELEdBQUcsQ0FDdERDLHFCQUFhLENBQUNDLHdCQUF3QixFQUN0Q0QscUJBQWEsQ0FBQ0UsNkJBQTZCLENBQzlDO0FBUUQsTUFBTUMsbUJBQW1CLEdBQUdDLE1BQU0sQ0FBQ0MsTUFBTSxDQUFDQywwQkFBa0IsQ0FBQztBQUU3RCxNQUFNQyxvQkFBb0IsR0FBSUMsR0FBWSxJQUFnQztFQUN0RSxPQUFPTCxtQkFBbUIsQ0FBQ00sUUFBUSxDQUFDRCxHQUF5QixDQUFDO0FBQ2xFLENBQUM7QUFFRCxNQUFNRSxnQ0FBZ0MsR0FBSUYsR0FBdUIsSUFBcUI7RUFDbEYsUUFBUUEsR0FBRztJQUNQLEtBQUtGLDBCQUFrQixDQUFDSyxjQUFjO01BQ2xDLE9BQU8sSUFBQUMsb0JBQUcsRUFBQyw0QkFBNEIsQ0FBQztJQUM1QyxL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