matrix-react-sdk
Version:
SDK for matrix.org using React
273 lines (265 loc) • 39.9 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.AccessCancelledError = void 0;
exports.accessSecretStorage = accessSecretStorage;
exports.crossSigningCallbacks = void 0;
exports.isSecretStorageBeingAccessed = isSecretStorageBeingAccessed;
exports.withSecretStorageKeyCache = withSecretStorageKeyCache;
var _cryptoApi = require("matrix-js-sdk/src/crypto-api");
var _logger = require("matrix-js-sdk/src/logger");
var _Modal = _interopRequireDefault(require("./Modal"));
var _MatrixClientPeg = require("./MatrixClientPeg");
var _languageHandler = require("./languageHandler");
var _WellKnownUtils = require("./utils/WellKnownUtils");
var _AccessSecretStorageDialog = _interopRequireDefault(require("./components/views/dialogs/security/AccessSecretStorageDialog"));
var _ModuleRunner = require("./modules/ModuleRunner");
var _QuestionDialog = _interopRequireDefault(require("./components/views/dialogs/QuestionDialog"));
var _InteractiveAuthDialog = _interopRequireDefault(require("./components/views/dialogs/InteractiveAuthDialog"));
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } /*
Copyright 2024 New Vector Ltd.
Copyright 2019, 2020 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.
*/
// This stores the secret storage private keys in memory for the JS SDK. This is
// only meant to act as a cache to avoid prompting the user multiple times
// during the same single operation. Use `accessSecretStorage` below to scope a
// single secret storage operation, as it will clear the cached keys once the
// operation ends.
let secretStorageKeys = {};
let secretStorageKeyInfo = {};
let secretStorageBeingAccessed = false;
/**
* This can be used by other components to check if secret storage access is in
* progress, so that we can e.g. avoid intermittently showing toasts during
* secret storage setup.
*
* @returns {bool}
*/
function isSecretStorageBeingAccessed() {
return secretStorageBeingAccessed;
}
class AccessCancelledError extends Error {
constructor() {
super("Secret storage access canceled");
}
}
exports.AccessCancelledError = AccessCancelledError;
async function confirmToDismiss() {
const [sure] = await _Modal.default.createDialog(_QuestionDialog.default, {
title: (0, _languageHandler._t)("encryption|cancel_entering_passphrase_title"),
description: (0, _languageHandler._t)("encryption|cancel_entering_passphrase_description"),
danger: false,
button: (0, _languageHandler._t)("action|go_back"),
cancelButton: (0, _languageHandler._t)("action|cancel")
}).finished;
return !sure;
}
function makeInputToKey(keyInfo) {
return async ({
passphrase,
recoveryKey
}) => {
if (passphrase) {
return (0, _cryptoApi.deriveRecoveryKeyFromPassphrase)(passphrase, keyInfo.passphrase.salt, keyInfo.passphrase.iterations);
} else if (recoveryKey) {
return (0, _cryptoApi.decodeRecoveryKey)(recoveryKey);
}
throw new Error("Invalid input, passphrase or recoveryKey need to be provided");
};
}
async function getSecretStorageKey({
keys: keyInfos
}) {
const cli = _MatrixClientPeg.MatrixClientPeg.safeGet();
let keyId = await cli.getDefaultSecretStorageKeyId();
let keyInfo;
if (keyId) {
// use the default SSSS key if set
keyInfo = keyInfos[keyId];
if (!keyInfo) {
// if the default key is not available, pretend the default key
// isn't set
keyId = null;
}
}
if (!keyId) {
// if no default SSSS key is set, fall back to a heuristic of using the
// only available key, if only one key is set
const keyInfoEntries = Object.entries(keyInfos);
if (keyInfoEntries.length > 1) {
throw new Error("Multiple storage key requests not implemented");
}
[keyId, keyInfo] = keyInfoEntries[0];
}
_logger.logger.debug(`getSecretStorageKey: request for 4S keys [${Object.keys(keyInfos)}]: looking for key ${keyId}`);
// Check the in-memory cache
if (secretStorageBeingAccessed && secretStorageKeys[keyId]) {
_logger.logger.debug(`getSecretStorageKey: returning key ${keyId} from cache`);
return [keyId, secretStorageKeys[keyId]];
}
const keyFromCustomisations = _ModuleRunner.ModuleRunner.instance.extensions.cryptoSetup.getSecretStorageKey();
if (keyFromCustomisations) {
_logger.logger.log("getSecretStorageKey: Using secret storage key from CryptoSetupExtension");
cacheSecretStorageKey(keyId, keyInfo, keyFromCustomisations);
return [keyId, keyFromCustomisations];
}
_logger.logger.debug("getSecretStorageKey: prompting user for key");
const inputToKey = makeInputToKey(keyInfo);
const {
finished
} = _Modal.default.createDialog(_AccessSecretStorageDialog.default, /* props= */
{
keyInfo,
checkPrivateKey: async input => {
const key = await inputToKey(input);
return _MatrixClientPeg.MatrixClientPeg.safeGet().secretStorage.checkKey(key, keyInfo);
}
}, /* className= */undefined, /* isPriorityModal= */false, /* isStaticModal= */false, /* options= */{
onBeforeClose: async reason => {
if (reason === "backgroundClick") {
return confirmToDismiss();
}
return true;
}
});
const [keyParams] = await finished;
if (!keyParams) {
throw new AccessCancelledError();
}
_logger.logger.debug("getSecretStorageKey: got key from user");
const key = await inputToKey(keyParams);
// Save to cache to avoid future prompts in the current session
cacheSecretStorageKey(keyId, keyInfo, key);
return [keyId, key];
}
function cacheSecretStorageKey(keyId, keyInfo, key) {
if (secretStorageBeingAccessed) {
secretStorageKeys[keyId] = key;
secretStorageKeyInfo[keyId] = keyInfo;
}
}
const crossSigningCallbacks = exports.crossSigningCallbacks = {
getSecretStorageKey,
cacheSecretStorageKey
};
/**
* Carry out an operation that may require multiple accesses to secret storage, caching the key.
*
* Use this helper to wrap an operation that may require multiple accesses to secret storage; the user will be prompted
* to enter the 4S key or passphrase on the first access, and the key will be cached for the rest of the operation.
*
* @param func - The operation to be wrapped.
*/
async function withSecretStorageKeyCache(func) {
_logger.logger.debug("SecurityManager: enabling 4S key cache");
secretStorageBeingAccessed = true;
try {
return await func();
} finally {
// Clear secret storage key cache now that work is complete
_logger.logger.debug("SecurityManager: disabling 4S key cache");
secretStorageBeingAccessed = false;
secretStorageKeys = {};
secretStorageKeyInfo = {};
}
}
/**
* This helper should be used whenever you need to access secret storage. It
* ensures that secret storage (and also cross-signing since they each depend on
* each other in a cycle of sorts) have been bootstrapped before running the
* provided function.
*
* Bootstrapping secret storage may take one of these paths:
* 1. Create secret storage from a passphrase and store cross-signing keys
* in secret storage.
* 2. Access existing secret storage by requesting passphrase and accessing
* cross-signing keys as needed.
* 3. All keys are loaded and there's nothing to do.
*
* Additionally, the secret storage keys are cached during the scope of this function
* to ensure the user is prompted only once for their secret storage
* passphrase. The cache is then cleared once the provided function completes.
*
* @param {Function} [func] An operation to perform once secret storage has been
* bootstrapped. Optional.
* @param {bool} [forceReset] Reset secret storage even if it's already set up
*/
async function accessSecretStorage(func = async () => {}, forceReset = false) {
await withSecretStorageKeyCache(() => doAccessSecretStorage(func, forceReset));
}
/** Helper for {@link #accessSecretStorage} */
async function doAccessSecretStorage(func, forceReset) {
try {
const cli = _MatrixClientPeg.MatrixClientPeg.safeGet();
const crypto = cli.getCrypto();
if (!crypto) {
throw new Error("End-to-end encryption is disabled - unable to access secret storage.");
}
let createNew = false;
if (forceReset) {
_logger.logger.debug("accessSecretStorage: resetting 4S");
createNew = true;
} else if (!(await cli.secretStorage.hasKey())) {
_logger.logger.debug("accessSecretStorage: no 4S key configured, creating a new one");
createNew = true;
}
if (createNew) {
// This dialog calls bootstrap itself after guiding the user through
// passphrase creation.
const {
finished
} = _Modal.default.createDialogAsync(Promise.resolve().then(() => _interopRequireWildcard(require("./async-components/views/dialogs/security/CreateSecretStorageDialog"))), {
forceReset
}, undefined, /* priority = */false, /* static = */true, /* options = */{
onBeforeClose: async reason => {
// If Secure Backup is required, you cannot leave the modal.
if (reason === "backgroundClick") {
return !(0, _WellKnownUtils.isSecureBackupRequired)(cli);
}
return true;
}
});
const [confirmed] = await finished;
if (!confirmed) {
throw new Error("Secret storage creation canceled");
}
} else {
_logger.logger.debug("accessSecretStorage: bootstrapCrossSigning");
await crypto.bootstrapCrossSigning({
authUploadDeviceSigningKeys: async makeRequest => {
_logger.logger.debug("accessSecretStorage: performing UIA to upload cross-signing keys");
const {
finished
} = _Modal.default.createDialog(_InteractiveAuthDialog.default, {
title: (0, _languageHandler._t)("encryption|bootstrap_title"),
matrixClient: cli,
makeRequest
});
const [confirmed] = await finished;
if (!confirmed) {
throw new Error("Cross-signing key upload auth canceled");
}
_logger.logger.debug("accessSecretStorage: Cross-signing key upload successful");
}
});
_logger.logger.debug("accessSecretStorage: bootstrapSecretStorage");
await crypto.bootstrapSecretStorage({});
}
_logger.logger.debug("accessSecretStorage: 4S now ready");
// `return await` needed here to ensure `finally` block runs after the
// inner operation completes.
await func();
_logger.logger.debug("accessSecretStorage: operation complete");
} catch (e) {
_ModuleRunner.ModuleRunner.instance.extensions.cryptoSetup.catchAccessSecretStorageError(e);
_logger.logger.error("accessSecretStorage: error during operation", e);
// Re-throw so that higher level logic can abort as needed
throw e;
}
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfY3J5cHRvQXBpIiwicmVxdWlyZSIsIl9sb2dnZXIiLCJfTW9kYWwiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwiX01hdHJpeENsaWVudFBlZyIsIl9sYW5ndWFnZUhhbmRsZXIiLCJfV2VsbEtub3duVXRpbHMiLCJfQWNjZXNzU2VjcmV0U3RvcmFnZURpYWxvZyIsIl9Nb2R1bGVSdW5uZXIiLCJfUXVlc3Rpb25EaWFsb2ciLCJfSW50ZXJhY3RpdmVBdXRoRGlhbG9nIiwiX2dldFJlcXVpcmVXaWxkY2FyZENhY2hlIiwiZSIsIldlYWtNYXAiLCJyIiwidCIsIl9pbnRlcm9wUmVxdWlyZVdpbGRjYXJkIiwiX19lc01vZHVsZSIsImRlZmF1bHQiLCJoYXMiLCJnZXQiLCJuIiwiX19wcm90b19fIiwiYSIsIk9iamVjdCIsImRlZmluZVByb3BlcnR5IiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yIiwidSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsImkiLCJzZXQiLCJzZWNyZXRTdG9yYWdlS2V5cyIsInNlY3JldFN0b3JhZ2VLZXlJbmZvIiwic2VjcmV0U3RvcmFnZUJlaW5nQWNjZXNzZWQiLCJpc1NlY3JldFN0b3JhZ2VCZWluZ0FjY2Vzc2VkIiwiQWNjZXNzQ2FuY2VsbGVkRXJyb3IiLCJFcnJvciIsImNvbnN0cnVjdG9yIiwiZXhwb3J0cyIsImNvbmZpcm1Ub0Rpc21pc3MiLCJzdXJlIiwiTW9kYWwiLCJjcmVhdGVEaWFsb2ciLCJRdWVzdGlvbkRpYWxvZyIsInRpdGxlIiwiX3QiLCJkZXNjcmlwdGlvbiIsImRhbmdlciIsImJ1dHRvbiIsImNhbmNlbEJ1dHRvbiIsImZpbmlzaGVkIiwibWFrZUlucHV0VG9LZXkiLCJrZXlJbmZvIiwicGFzc3BocmFzZSIsInJlY292ZXJ5S2V5IiwiZGVyaXZlUmVjb3ZlcnlLZXlGcm9tUGFzc3BocmFzZSIsInNhbHQiLCJpdGVyYXRpb25zIiwiZGVjb2RlUmVjb3ZlcnlLZXkiLCJnZXRTZWNyZXRTdG9yYWdlS2V5Iiwia2V5cyIsImtleUluZm9zIiwiY2xpIiwiTWF0cml4Q2xpZW50UGVnIiwic2FmZUdldCIsImtleUlkIiwiZ2V0RGVmYXVsdFNlY3JldFN0b3JhZ2VLZXlJZCIsImtleUluZm9FbnRyaWVzIiwiZW50cmllcyIsImxlbmd0aCIsImxvZ2dlciIsImRlYnVnIiwia2V5RnJvbUN1c3RvbWlzYXRpb25zIiwiTW9kdWxlUnVubmVyIiwiaW5zdGFuY2UiLCJleHRlbnNpb25zIiwiY3J5cHRvU2V0dXAiLCJsb2ciLCJjYWNoZVNlY3JldFN0b3JhZ2VLZXkiLCJpbnB1dFRvS2V5IiwiQWNjZXNzU2VjcmV0U3RvcmFnZURpYWxvZyIsImNoZWNrUHJpdmF0ZUtleSIsImlucHV0Iiwia2V5Iiwic2VjcmV0U3RvcmFnZSIsImNoZWNrS2V5IiwidW5kZWZpbmVkIiwib25CZWZvcmVDbG9zZSIsInJlYXNvbiIsImtleVBhcmFtcyIsImNyb3NzU2lnbmluZ0NhbGxiYWNrcyIsIndpdGhTZWNyZXRTdG9yYWdlS2V5Q2FjaGUiLCJmdW5jIiwiYWNjZXNzU2VjcmV0U3RvcmFnZSIsImZvcmNlUmVzZXQiLCJkb0FjY2Vzc1NlY3JldFN0b3JhZ2UiLCJjcnlwdG8iLCJnZXRDcnlwdG8iLCJjcmVhdGVOZXciLCJoYXNLZXkiLCJjcmVhdGVEaWFsb2dBc3luYyIsIlByb21pc2UiLCJyZXNvbHZlIiwidGhlbiIsImlzU2VjdXJlQmFja3VwUmVxdWlyZWQiLCJjb25maXJtZWQiLCJib290c3RyYXBDcm9zc1NpZ25pbmciLCJhdXRoVXBsb2FkRGV2aWNlU2lnbmluZ0tleXMiLCJtYWtlUmVxdWVzdCIsIkludGVyYWN0aXZlQXV0aERpYWxvZyIsIm1hdHJpeENsaWVudCIsImJvb3RzdHJhcFNlY3JldFN0b3JhZ2UiLCJjYXRjaEFjY2Vzc1NlY3JldFN0b3JhZ2VFcnJvciIsImVycm9yIl0sInNvdXJjZXMiOlsiLi4vc3JjL1NlY3VyaXR5TWFuYWdlci50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMjQgTmV3IFZlY3RvciBMdGQuXG5Db3B5cmlnaHQgMjAxOSwgMjAyMCBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuXG5TUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQUdQTC0zLjAtb25seSBPUiBHUEwtMy4wLW9ubHlcblBsZWFzZSBzZWUgTElDRU5TRSBmaWxlcyBpbiB0aGUgcmVwb3NpdG9yeSByb290IGZvciBmdWxsIGRldGFpbHMuXG4qL1xuXG5pbXBvcnQgeyBJQ3J5cHRvQ2FsbGJhY2tzLCBTZWNyZXRTdG9yYWdlIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL21hdHJpeFwiO1xuaW1wb3J0IHsgZGVyaXZlUmVjb3ZlcnlLZXlGcm9tUGFzc3BocmFzZSwgZGVjb2RlUmVjb3ZlcnlLZXkgfSBmcm9tIFwibWF0cml4LWpzLXNkay9zcmMvY3J5cHRvLWFwaVwiO1xuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2xvZ2dlclwiO1xuXG5pbXBvcnQgdHlwZSBDcmVhdGVTZWNyZXRTdG9yYWdlRGlhbG9nIGZyb20gXCIuL2FzeW5jLWNvbXBvbmVudHMvdmlld3MvZGlhbG9ncy9zZWN1cml0eS9DcmVhdGVTZWNyZXRTdG9yYWdlRGlhbG9nXCI7XG5pbXBvcnQgTW9kYWwgZnJvbSBcIi4vTW9kYWxcIjtcbmltcG9ydCB7IE1hdHJpeENsaWVudFBlZyB9IGZyb20gXCIuL01hdHJpeENsaWVudFBlZ1wiO1xuaW1wb3J0IHsgX3QgfSBmcm9tIFwiLi9sYW5ndWFnZUhhbmRsZXJcIjtcbmltcG9ydCB7IGlzU2VjdXJlQmFja3VwUmVxdWlyZWQgfSBmcm9tIFwiLi91dGlscy9XZWxsS25vd25VdGlsc1wiO1xuaW1wb3J0IEFjY2Vzc1NlY3JldFN0b3JhZ2VEaWFsb2csIHsgS2V5UGFyYW1zIH0gZnJvbSBcIi4vY29tcG9uZW50cy92aWV3cy9kaWFsb2dzL3NlY3VyaXR5L0FjY2Vzc1NlY3JldFN0b3JhZ2VEaWFsb2dcIjtcbmltcG9ydCB7IE1vZHVsZVJ1bm5lciB9IGZyb20gXCIuL21vZHVsZXMvTW9kdWxlUnVubmVyXCI7XG5pbXBvcnQgUXVlc3Rpb25EaWFsb2cgZnJvbSBcIi4vY29tcG9uZW50cy92aWV3cy9kaWFsb2dzL1F1ZXN0aW9uRGlhbG9nXCI7XG5pbXBvcnQgSW50ZXJhY3RpdmVBdXRoRGlhbG9nIGZyb20gXCIuL2NvbXBvbmVudHMvdmlld3MvZGlhbG9ncy9JbnRlcmFjdGl2ZUF1dGhEaWFsb2dcIjtcblxuLy8gVGhpcyBzdG9yZXMgdGhlIHNlY3JldCBzdG9yYWdlIHByaXZhdGUga2V5cyBpbiBtZW1vcnkgZm9yIHRoZSBKUyBTREsuIFRoaXMgaXNcbi8vIG9ubHkgbWVhbnQgdG8gYWN0IGFzIGEgY2FjaGUgdG8gYXZvaWQgcHJvbXB0aW5nIHRoZSB1c2VyIG11bHRpcGxlIHRpbWVzXG4vLyBkdXJpbmcgdGhlIHNhbWUgc2luZ2xlIG9wZXJhdGlvbi4gVXNlIGBhY2Nlc3NTZWNyZXRTdG9yYWdlYCBiZWxvdyB0byBzY29wZSBhXG4vLyBzaW5nbGUgc2VjcmV0IHN0b3JhZ2Ugb3BlcmF0aW9uLCBhcyBpdCB3aWxsIGNsZWFyIHRoZSBjYWNoZWQga2V5cyBvbmNlIHRoZVxuLy8gb3BlcmF0aW9uIGVuZHMuXG5sZXQgc2VjcmV0U3RvcmFnZUtleXM6IFJlY29yZDxzdHJpbmcsIFVpbnQ4QXJyYXk+ID0ge307XG5sZXQgc2VjcmV0U3RvcmFnZUtleUluZm86IFJlY29yZDxzdHJpbmcsIFNlY3JldFN0b3JhZ2UuU2VjcmV0U3RvcmFnZUtleURlc2NyaXB0aW9uPiA9IHt9O1xubGV0IHNlY3JldFN0b3JhZ2VCZWluZ0FjY2Vzc2VkID0gZmFsc2U7XG5cbi8qKlxuICogVGhpcyBjYW4gYmUgdXNlZCBieSBvdGhlciBjb21wb25lbnRzIHRvIGNoZWNrIGlmIHNlY3JldCBzdG9yYWdlIGFjY2VzcyBpcyBpblxuICogcHJvZ3Jlc3MsIHNvIHRoYXQgd2UgY2FuIGUuZy4gYXZvaWQgaW50ZXJtaXR0ZW50bHkgc2hvd2luZyB0b2FzdHMgZHVyaW5nXG4gKiBzZWNyZXQgc3RvcmFnZSBzZXR1cC5cbiAqXG4gKiBAcmV0dXJucyB7Ym9vbH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzU2VjcmV0U3RvcmFnZUJlaW5nQWNjZXNzZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHNlY3JldFN0b3JhZ2VCZWluZ0FjY2Vzc2VkO1xufVxuXG5leHBvcnQgY2xhc3MgQWNjZXNzQ2FuY2VsbGVkRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gICAgcHVibGljIGNvbnN0cnVjdG9yKCkge1xuICAgICAgICBzdXBlcihcIlNlY3JldCBzdG9yYWdlIGFjY2VzcyBjYW5jZWxlZFwiKTtcbiAgICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNvbmZpcm1Ub0Rpc21pc3MoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgW3N1cmVdID0gYXdhaXQgTW9kYWwuY3JlYXRlRGlhbG9nKFF1ZXN0aW9uRGlhbG9nLCB7XG4gICAgICAgIHRpdGxlOiBfdChcImVuY3J5cHRpb258Y2FuY2VsX2VudGVyaW5nX3Bhc3NwaHJhc2VfdGl0bGVcIiksXG4gICAgICAgIGRlc2NyaXB0aW9uOiBfdChcImVuY3J5cHRpb258Y2FuY2VsX2VudGVyaW5nX3Bhc3NwaHJhc2VfZGVzY3JpcHRpb25cIiksXG4gICAgICAgIGRhbmdlcjogZmFsc2UsXG4gICAgICAgIGJ1dHRvbjogX3QoXCJhY3Rpb258Z29fYmFja1wiKSxcbiAgICAgICAgY2FuY2VsQnV0dG9uOiBfdChcImFjdGlvbnxjYW5jZWxcIiksXG4gICAgfSkuZmluaXNoZWQ7XG4gICAgcmV0dXJuICFzdXJlO1xufVxuXG5mdW5jdGlvbiBtYWtlSW5wdXRUb0tleShcbiAgICBrZXlJbmZvOiBTZWNyZXRTdG9yYWdlLlNlY3JldFN0b3JhZ2VLZXlEZXNjcmlwdGlvbixcbik6IChrZXlQYXJhbXM6IEtleVBhcmFtcykgPT4gUHJvbWlzZTxVaW50OEFycmF5PiB7XG4gICAgcmV0dXJuIGFzeW5jICh7IHBhc3NwaHJhc2UsIHJlY292ZXJ5S2V5IH0pOiBQcm9taXNlPFVpbnQ4QXJyYXk+ID0+IHtcbiAgICAgICAgaWYgKHBhc3NwaHJhc2UpIHtcbiAgICAgICAgICAgIHJldHVybiBkZXJpdmVSZWNvdmVyeUtleUZyb21QYXNzcGhyYXNlKHBhc3NwaHJhc2UsIGtleUluZm8ucGFzc3BocmFzZS5zYWx0LCBrZXlJbmZvLnBhc3NwaHJhc2UuaXRlcmF0aW9ucyk7XG4gICAgICAgIH0gZWxzZSBpZiAocmVjb3ZlcnlLZXkpIHtcbiAgICAgICAgICAgIHJldHVybiBkZWNvZGVSZWNvdmVyeUtleShyZWNvdmVyeUtleSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCBpbnB1dCwgcGFzc3BocmFzZSBvciByZWNvdmVyeUtleSBuZWVkIHRvIGJlIHByb3ZpZGVkXCIpO1xuICAgIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldFNlY3JldFN0b3JhZ2VLZXkoe1xuICAgIGtleXM6IGtleUluZm9zLFxufToge1xuICAgIGtleXM6IFJlY29yZDxzdHJpbmcsIFNlY3JldFN0b3JhZ2UuU2VjcmV0U3RvcmFnZUtleURlc2NyaXB0aW9uPjtcbn0pOiBQcm9taXNlPFtzdHJpbmcsIFVpbnQ4QXJyYXldPiB7XG4gICAgY29uc3QgY2xpID0gTWF0cml4Q2xpZW50UGVnLnNhZmVHZXQoKTtcbiAgICBsZXQga2V5SWQgPSBhd2FpdCBjbGkuZ2V0RGVmYXVsdFNlY3JldFN0b3JhZ2VLZXlJZCgpO1xuICAgIGxldCBrZXlJbmZvITogU2VjcmV0U3RvcmFnZS5TZWNyZXRTdG9yYWdlS2V5RGVzY3JpcHRpb247XG4gICAgaWYgKGtleUlkKSB7XG4gICAgICAgIC8vIHVzZSB0aGUgZGVmYXVsdCBTU1NTIGtleSBpZiBzZXRcbiAgICAgICAga2V5SW5mbyA9IGtleUluZm9zW2tleUlkXTtcbiAgICAgICAgaWYgKCFrZXlJbmZvKSB7XG4gICAgICAgICAgICAvLyBpZiB0aGUgZGVmYXVsdCBrZXkgaXMgbm90IGF2YWlsYWJsZSwgcHJldGVuZCB0aGUgZGVmYXVsdCBrZXlcbiAgICAgICAgICAgIC8vIGlzbid0IHNldFxuICAgICAgICAgICAga2V5SWQgPSBudWxsO1xuICAgICAgICB9XG4gICAgfVxuICAgIGlmICgha2V5SWQpIHtcbiAgICAgICAgLy8gaWYgbm8gZGVmYXVsdCBTU1NTIGtleSBpcyBzZXQsIGZhbGwgYmFjayB0byBhIGhldXJpc3RpYyBvZiB1c2luZyB0aGVcbiAgICAgICAgLy8gb25seSBhdmFpbGFibGUga2V5LCBpZiBvbmx5IG9uZSBrZXkgaXMgc2V0XG4gICAgICAgIGNvbnN0IGtleUluZm9FbnRyaWVzID0gT2JqZWN0LmVudHJpZXMoa2V5SW5mb3MpO1xuICAgICAgICBpZiAoa2V5SW5mb0VudHJpZXMubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTXVsdGlwbGUgc3RvcmFnZSBrZXkgcmVxdWVzdHMgbm90IGltcGxlbWVudGVkXCIpO1xuICAgICAgICB9XG4gICAgICAgIFtrZXlJZCwga2V5SW5mb10gPSBrZXlJbmZvRW50cmllc1swXTtcbiAgICB9XG4gICAgbG9nZ2VyLmRlYnVnKGBnZXRTZWNyZXRTdG9yYWdlS2V5OiByZXF1ZXN0IGZvciA0UyBrZXlzIFske09iamVjdC5rZXlzKGtleUluZm9zKX1dOiBsb29raW5nIGZvciBrZXkgJHtrZXlJZH1gKTtcblxuICAgIC8vIENoZWNrIHRoZSBpbi1tZW1vcnkgY2FjaGVcbiAgICBpZiAoc2VjcmV0U3RvcmFnZUJlaW5nQWNjZXNzZWQgJiYgc2VjcmV0U3RvcmFnZUtleXNba2V5SWRdKSB7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhgZ2V0U2VjcmV0U3RvcmFnZUtleTogcmV0dXJuaW5nIGtleSAke2tleUlkfSBmcm9tIGNhY2hlYCk7XG4gICAgICAgIHJldHVybiBba2V5SWQsIHNlY3JldFN0b3JhZ2VLZXlzW2tleUlkXV07XG4gICAgfVxuXG4gICAgY29uc3Qga2V5RnJvbUN1c3RvbWlzYXRpb25zID0gTW9kdWxlUnVubmVyLmluc3RhbmNlLmV4dGVuc2lvbnMuY3J5cHRvU2V0dXAuZ2V0U2VjcmV0U3RvcmFnZUtleSgpO1xuICAgIGlmIChrZXlGcm9tQ3VzdG9taXNhdGlvbnMpIHtcbiAgICAgICAgbG9nZ2VyLmxvZyhcImdldFNlY3JldFN0b3JhZ2VLZXk6IFVzaW5nIHNlY3JldCBzdG9yYWdlIGtleSBmcm9tIENyeXB0b1NldHVwRXh0ZW5zaW9uXCIpO1xuICAgICAgICBjYWNoZVNlY3JldFN0b3JhZ2VLZXkoa2V5SWQsIGtleUluZm8sIGtleUZyb21DdXN0b21pc2F0aW9ucyk7XG4gICAgICAgIHJldHVybiBba2V5SWQsIGtleUZyb21DdXN0b21pc2F0aW9uc107XG4gICAgfVxuXG4gICAgbG9nZ2VyLmRlYnVnKFwiZ2V0U2VjcmV0U3RvcmFnZUtleTogcHJvbXB0aW5nIHVzZXIgZm9yIGtleVwiKTtcbiAgICBjb25zdCBpbnB1dFRvS2V5ID0gbWFrZUlucHV0VG9LZXkoa2V5SW5mbyk7XG4gICAgY29uc3QgeyBmaW5pc2hlZCB9ID0gTW9kYWwuY3JlYXRlRGlhbG9nKFxuICAgICAgICBBY2Nlc3NTZWNyZXRTdG9yYWdlRGlhbG9nLFxuICAgICAgICAvKiBwcm9wcz0gKi9cbiAgICAgICAge1xuICAgICAgICAgICAga2V5SW5mbyxcbiAgICAgICAgICAgIGNoZWNrUHJpdmF0ZUtleTogYXN5bmMgKGlucHV0OiBLZXlQYXJhbXMpOiBQcm9taXNlPGJvb2xlYW4+ID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBrZXkgPSBhd2FpdCBpbnB1dFRvS2V5KGlucHV0KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gTWF0cml4Q2xpZW50UGVnLnNhZmVHZXQoKS5zZWNyZXRTdG9yYWdlLmNoZWNrS2V5KGtleSwga2V5SW5mbyk7XG4gICAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICAvKiBjbGFzc05hbWU9ICovIHVuZGVmaW5lZCxcbiAgICAgICAgLyogaXNQcmlvcml0eU1vZGFsPSAqLyBmYWxzZSxcbiAgICAgICAgLyogaXNTdGF0aWNNb2RhbD0gKi8gZmFsc2UsXG4gICAgICAgIC8qIG9wdGlvbnM9ICovIHtcbiAgICAgICAgICAgIG9uQmVmb3JlQ2xvc2U6IGFzeW5jIChyZWFzb24pOiBQcm9taXNlPGJvb2xlYW4+ID0+IHtcbiAgICAgICAgICAgICAgICBpZiAocmVhc29uID09PSBcImJhY2tncm91bmRDbGlja1wiKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBjb25maXJtVG9EaXNtaXNzKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICApO1xuICAgIGNvbnN0IFtrZXlQYXJhbXNdID0gYXdhaXQgZmluaXNoZWQ7XG4gICAgaWYgKCFrZXlQYXJhbXMpIHtcbiAgICAgICAgdGhyb3cgbmV3IEFjY2Vzc0NhbmNlbGxlZEVycm9yKCk7XG4gICAgfVxuICAgIGxvZ2dlci5kZWJ1ZyhcImdldFNlY3JldFN0b3JhZ2VLZXk6IGdvdCBrZXkgZnJvbSB1c2VyXCIpO1xuICAgIGNvbnN0IGtleSA9IGF3YWl0IGlucHV0VG9LZXkoa2V5UGFyYW1zKTtcblxuICAgIC8vIFNhdmUgdG8gY2FjaGUgdG8gYXZvaWQgZnV0dXJlIHByb21wdHMgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvblxuICAgIGNhY2hlU2VjcmV0U3RvcmFnZUtleShrZXlJZCwga2V5SW5mbywga2V5KTtcblxuICAgIHJldHVybiBba2V5SWQsIGtleV07XG59XG5cbmZ1bmN0aW9uIGNhY2hlU2VjcmV0U3RvcmFnZUtleShcbiAgICBrZXlJZDogc3RyaW5nLFxuICAgIGtleUluZm86IFNlY3JldFN0b3JhZ2UuU2VjcmV0U3RvcmFnZUtleURlc2NyaXB0aW9uLFxuICAgIGtleTogVWludDhBcnJheSxcbik6IHZvaWQge1xuICAgIGlmIChzZWNyZXRTdG9yYWdlQmVpbmdBY2Nlc3NlZCkge1xuICAgICAgICBzZWNyZXRTdG9yYWdlS2V5c1trZXlJZF0gPSBrZXk7XG4gICAgICAgIHNlY3JldFN0b3JhZ2VLZXlJbmZvW2tleUlkXSA9IGtleUluZm87XG4gICAgfVxufVxuXG5leHBvcnQgY29uc3QgY3Jvc3NTaWduaW5nQ2FsbGJhY2tzOiBJQ3J5cHRvQ2FsbGJhY2tzID0ge1xuICAgIGdldFNlY3JldFN0b3JhZ2VLZXksXG4gICAgY2FjaGVTZWNyZXRTdG9yYWdlS2V5LFxufTtcblxuLyoqXG4gKiBDYXJyeSBvdXQgYW4gb3BlcmF0aW9uIHRoYXQgbWF5IHJlcXVpcmUgbXVsdGlwbGUgYWNjZXNzZXMgdG8gc2VjcmV0IHN0b3JhZ2UsIGNhY2hpbmcgdGhlIGtleS5cbiAqXG4gKiBVc2UgdGhpcyBoZWxwZXIgdG8gd3JhcCBhbiBvcGVyYXRpb24gdGhhdCBtYXkgcmVxdWlyZSBtdWx0aXBsZSBhY2Nlc3NlcyB0byBzZWNyZXQgc3RvcmFnZTsgdGhlIHVzZXIgd2lsbCBiZSBwcm9tcHRlZFxuICogdG8gZW50ZXIgdGhlIDRTIGtleSBvciBwYXNzcGhyYXNlIG9uIHRoZSBmaXJzdCBhY2Nlc3MsIGFuZCB0aGUga2V5IHdpbGwgYmUgY2FjaGVkIGZvciB0aGUgcmVzdCBvZiB0aGUgb3BlcmF0aW9uLlxuICpcbiAqIEBwYXJhbSBmdW5jIC0gVGhlIG9wZXJhdGlvbiB0byBiZSB3cmFwcGVkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gd2l0aFNlY3JldFN0b3JhZ2VLZXlDYWNoZTxUPihmdW5jOiAoKSA9PiBQcm9taXNlPFQ+KTogUHJvbWlzZTxUPiB7XG4gICAgbG9nZ2VyLmRlYnVnKFwiU2VjdXJpdHlNYW5hZ2VyOiBlbmFibGluZyA0UyBrZXkgY2FjaGVcIik7XG4gICAgc2VjcmV0U3RvcmFnZUJlaW5nQWNjZXNzZWQgPSB0cnVlO1xuICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBhd2FpdCBmdW5jKCk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgICAgLy8gQ2xlYXIgc2VjcmV0IHN0b3JhZ2Uga2V5IGNhY2hlIG5vdyB0aGF0IHdvcmsgaXMgY29tcGxldGVcbiAgICAgICAgbG9nZ2VyLmRlYnVnKFwiU2VjdXJpdHlNYW5hZ2VyOiBkaXNhYmxpbmcgNFMga2V5IGNhY2hlXCIpO1xuICAgICAgICBzZWNyZXRTdG9yYWdlQmVpbmdBY2Nlc3NlZCA9IGZhbHNlO1xuICAgICAgICBzZWNyZXRTdG9yYWdlS2V5cyA9IHt9O1xuICAgICAgICBzZWNyZXRTdG9yYWdlS2V5SW5mbyA9IHt9O1xuICAgIH1cbn1cblxuLyoqXG4gKiBUaGlzIGhlbHBlciBzaG91bGQgYmUgdXNlZCB3aGVuZXZlciB5b3UgbmVlZCB0byBhY2Nlc3Mgc2VjcmV0IHN0b3JhZ2UuIEl0XG4gKiBlbnN1cmVzIHRoYXQgc2VjcmV0IHN0b3JhZ2UgKGFuZCBhbHNvIGNyb3NzLXNpZ25pbmcgc2luY2UgdGhleSBlYWNoIGRlcGVuZCBvblxuICogZWFjaCBvdGhlciBpbiBhIGN5Y2xlIG9mIHNvcnRzKSBoYXZlIGJlZW4gYm9vdHN0cmFwcGVkIGJlZm9yZSBydW5uaW5nIHRoZVxuICogcHJvdmlkZWQgZnVuY3Rpb24uXG4gKlxuICogQm9vdHN0cmFwcGluZyBzZWNyZXQgc3RvcmFnZSBtYXkgdGFrZSBvbmUgb2YgdGhlc2UgcGF0aHM6XG4gKiAxLiBDcmVhdGUgc2VjcmV0IHN0b3JhZ2UgZnJvbSBhIHBhc3NwaHJhc2UgYW5kIHN0b3JlIGNyb3NzLXNpZ25pbmcga2V5c1xuICogICAgaW4gc2VjcmV0IHN0b3JhZ2UuXG4gKiAyLiBBY2Nlc3MgZXhpc3Rpbmcgc2VjcmV0IHN0b3JhZ2UgYnkgcmVxdWVzdGluZyBwYXNzcGhyYXNlIGFuZCBhY2Nlc3NpbmdcbiAqICAgIGNyb3NzLXNpZ25pbmcga2V5cyBhcyBuZWVkZWQuXG4gKiAzLiBBbGwga2V5cyBhcmUgbG9hZGVkIGFuZCB0aGVyZSdzIG5vdGhpbmcgdG8gZG8uXG4gKlxuICogQWRkaXRpb25hbGx5LCB0aGUgc2VjcmV0IHN0b3JhZ2Uga2V5cyBhcmUgY2FjaGVkIGR1cmluZyB0aGUgc2NvcGUgb2YgdGhpcyBmdW5jdGlvblxuICogdG8gZW5zdXJlIHRoZSB1c2VyIGlzIHByb21wdGVkIG9ubHkgb25jZSBmb3IgdGhlaXIgc2VjcmV0IHN0b3JhZ2VcbiAqIHBhc3NwaHJhc2UuIFRoZSBjYWNoZSBpcyB0aGVuIGNsZWFyZWQgb25jZSB0aGUgcHJvdmlkZWQgZnVuY3Rpb24gY29tcGxldGVzLlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IFtmdW5jXSBBbiBvcGVyYXRpb24gdG8gcGVyZm9ybSBvbmNlIHNlY3JldCBzdG9yYWdlIGhhcyBiZWVuXG4gKiBib290c3RyYXBwZWQuIE9wdGlvbmFsLlxuICogQHBhcmFtIHtib29sfSBbZm9yY2VSZXNldF0gUmVzZXQgc2VjcmV0IHN0b3JhZ2UgZXZlbiBpZiBpdCdzIGFscmVhZHkgc2V0IHVwXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBhY2Nlc3NTZWNyZXRTdG9yYWdlKGZ1bmMgPSBhc3luYyAoKTogUHJvbWlzZTx2b2lkPiA9PiB7fSwgZm9yY2VSZXNldCA9IGZhbHNlKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgd2l0aFNlY3JldFN0b3JhZ2VLZXlDYWNoZSgoKSA9PiBkb0FjY2Vzc1NlY3JldFN0b3JhZ2UoZnVuYywgZm9yY2VSZXNldCkpO1xufVxuXG4vKiogSGVscGVyIGZvciB7QGxpbmsgI2FjY2Vzc1NlY3JldFN0b3JhZ2V9ICovXG5hc3luYyBmdW5jdGlvbiBkb0FjY2Vzc1NlY3JldFN0b3JhZ2UoZnVuYzogKCkgPT4gUHJvbWlzZTx2b2lkPiwgZm9yY2VSZXNldDogYm9vbGVhbik6IFByb21pc2U8dm9pZD4ge1xuICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGNsaSA9IE1hdHJpeENsaWVudFBlZy5zYWZlR2V0KCk7XG4gICAgICAgIGNvbnN0IGNyeXB0byA9IGNsaS5nZXRDcnlwdG8oKTtcbiAgICAgICAgaWYgKCFjcnlwdG8pIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkVuZC10by1lbmQgZW5jcnlwdGlvbiBpcyBkaXNhYmxlZCAtIHVuYWJsZSB0byBhY2Nlc3Mgc2VjcmV0IHN0b3JhZ2UuXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGNyZWF0ZU5ldyA9IGZhbHNlO1xuICAgICAgICBpZiAoZm9yY2VSZXNldCkge1xuICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKFwiYWNjZXNzU2VjcmV0U3RvcmFnZTogcmVzZXR0aW5nIDRTXCIpO1xuICAgICAgICAgICAgY3JlYXRlTmV3ID0gdHJ1ZTtcbiAgICAgICAgfSBlbHNlIGlmICghKGF3YWl0IGNsaS5zZWNyZXRTdG9yYWdlLmhhc0tleSgpKSkge1xuICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKFwiYWNjZXNzU2VjcmV0U3RvcmFnZTogbm8gNFMga2V5IGNvbmZpZ3VyZWQsIGNyZWF0aW5nIGEgbmV3IG9uZVwiKTtcbiAgICAgICAgICAgIGNyZWF0ZU5ldyA9IHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY3JlYXRlTmV3KSB7XG4gICAgICAgICAgICAvLyBUaGlzIGRpYWxvZyBjYWxscyBib290c3RyYXAgaXRzZWxmIGFmdGVyIGd1aWRpbmcgdGhlIHVzZXIgdGhyb3VnaFxuICAgICAgICAgICAgLy8gcGFzc3BocmFzZSBjcmVhdGlvbi5cbiAgICAgICAgICAgIGNvbnN0IHsgZmluaXNoZWQgfSA9IE1vZGFsLmNyZWF0ZURpYWxvZ0FzeW5jKFxuICAgICAgICAgICAgICAgIGltcG9ydChcIi4vYXN5bmMtY29tcG9uZW50cy92aWV3cy9kaWFsb2dzL3NlY3VyaXR5L0NyZWF0ZVNlY3JldFN0b3JhZ2VEaWFsb2dcIikgYXMgdW5rbm93biBhcyBQcm9taXNlPFxuICAgICAgICAgICAgICAgICAgICB0eXBlb2YgQ3JlYXRlU2VjcmV0U3RvcmFnZURpYWxvZ1xuICAgICAgICAgICAgICAgID4sXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBmb3JjZVJlc2V0LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIC8qIHByaW9yaXR5ID0gKi8gZmFsc2UsXG4gICAgICAgICAgICAgICAgLyogc3RhdGljID0gKi8gdHJ1ZSxcbiAgICAgICAgICAgICAgICAvKiBvcHRpb25zID0gKi8ge1xuICAgICAgICAgICAgICAgICAgICBvbkJlZm9yZUNsb3NlOiBhc3luYyAocmVhc29uKTogUHJvbWlzZTxib29sZWFuPiA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBJZiBTZWN1cmUgQmFja3VwIGlzIHJlcXVpcmVkLCB5b3UgY2Fubm90IGxlYXZlIHRoZSBtb2RhbC5cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZWFzb24gPT09IFwiYmFja2dyb3VuZENsaWNrXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gIWlzU2VjdXJlQmFja3VwUmVxdWlyZWQoY2xpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29uc3QgW2NvbmZpcm1lZF0gPSBhd2FpdCBmaW5pc2hlZDtcbiAgICAgICAgICAgIGlmICghY29uZmlybWVkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiU2VjcmV0IHN0b3JhZ2UgY3JlYXRpb24gY2FuY2VsZWRcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsb2dnZXIuZGVidWcoXCJhY2Nlc3NTZWNyZXRTdG9yYWdlOiBib290c3RyYXBDcm9zc1NpZ25pbmdcIik7XG4gICAgICAgICAgICBhd2FpdCBjcnlwdG8uYm9vdHN0cmFwQ3Jvc3NTaWduaW5nKHtcbiAgICAgICAgICAgICAgICBhdXRoVXBsb2FkRGV2aWNlU2lnbmluZ0tleXM6IGFzeW5jIChtYWtlUmVxdWVzdCk6IFByb21pc2U8dm9pZD4gPT4ge1xuICAgICAgICAgICAgICAgICAgICBsb2dnZXIuZGVidWcoXCJhY2Nlc3NTZWNyZXRTdG9yYWdlOiBwZXJmb3JtaW5nIFVJQSB0byB1cGxvYWQgY3Jvc3Mtc2lnbmluZyBrZXlzXCIpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB7IGZpbmlzaGVkIH0gPSBNb2RhbC5jcmVhdGVEaWFsb2coSW50ZXJhY3RpdmVBdXRoRGlhbG9nLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aXRsZTogX3QoXCJlbmNyeXB0aW9ufGJvb3RzdHJhcF90aXRsZVwiKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG1hdHJpeENsaWVudDogY2xpLFxuICAgICAgICAgICAgICAgICAgICAgICAgbWFrZVJlcXVlc3QsXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBbY29uZmlybWVkXSA9IGF3YWl0IGZpbmlzaGVkO1xuICAgICAgICAgICAgICAgICAgICBpZiAoIWNvbmZpcm1lZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ3Jvc3Mtc2lnbmluZyBrZXkgdXBsb2FkIGF1dGggY2FuY2VsZWRcIik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKFwiYWNjZXNzU2VjcmV0U3RvcmFnZTogQ3Jvc3Mtc2lnbmluZyBrZXkgdXBsb2FkIHN1Y2Nlc3NmdWxcIik7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKFwiYWNjZXNzU2VjcmV0U3RvcmFnZTogYm9vdHN0cmFwU2VjcmV0U3RvcmFnZVwiKTtcbiAgICAgICAgICAgIGF3YWl0IGNyeXB0by5ib290c3RyYXBTZWNyZXRTdG9yYWdlKHt9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhcImFjY2Vzc1NlY3JldFN0b3JhZ2U6IDRTIG5vdyByZWFkeVwiKTtcbiAgICAgICAgLy8gYHJldHVybiBhd2FpdGAgbmVlZGVkIGhlcmUgdG8gZW5zdXJlIGBmaW5hbGx5YCBibG9jayBydW5zIGFmdGVyIHRoZVxuICAgICAgICAvLyBpbm5lciBvcGVyYXRpb24gY29tcGxldGVzLlxuICAgICAgICBhd2FpdCBmdW5jKCk7XG4gICAgICAgIGxvZ2dlci5kZWJ1ZyhcImFjY2Vzc1NlY3JldFN0b3JhZ2U6IG9wZXJhdGlvbiBjb21wbGV0ZVwiKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIE1vZHVsZVJ1bm5lci5pbnN0YW5jZS5leHRlbnNpb25zLmNyeXB0b1NldHVwLmNhdGNoQWNjZXNzU2VjcmV0U3RvcmFnZUVycm9yKGUgYXMgRXJyb3IpO1xuICAgICAgICBsb2dnZXIuZXJyb3IoXCJhY2Nlc3NTZWNyZXRTdG9yYWdlOiBlcnJvciBkdXJpbmcgb3BlcmF0aW9uXCIsIGUpO1xuICAgICAgICAvLyBSZS10aHJvdyBzbyB0aGF0IGhpZ2hlciBsZXZlbCBsb2dpYyBjYW4gYWJvcnQgYXMgbmVlZGVkXG4gICAgICAgIHRocm93IGU7XG4gICAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQVNBLElBQUFBLFVBQUEsR0FBQUMsT0FBQTtBQUNBLElBQUFDLE9BQUEsR0FBQUQsT0FBQTtBQUdBLElBQUFFLE1BQUEsR0FBQUMsc0JBQUEsQ0FBQUgsT0FBQTtBQUNBLElBQUFJLGdCQUFBLEdBQUFKLE9BQUE7QUFDQSxJQUFBSyxnQkFBQSxHQUFBTCxPQUFBO0FBQ0EsSUFBQU0sZUFBQSxHQUFBTixPQUFBO0FBQ0EsSUFBQU8sMEJBQUEsR0FBQUosc0JBQUEsQ0FBQUgsT0FBQTtBQUNBLElBQUFRLGFBQUEsR0FBQVIsT0FBQTtBQUNBLElBQUFTLGVBQUEsR0FBQU4sc0JBQUEsQ0FBQUgsT0FBQTtBQUNBLElBQUFVLHNCQUFBLEdBQUFQLHNCQUFBLENBQUFILE9BQUE7QUFBcUYsU0FBQVcseUJBQUFDLENBQUEsNkJBQUFDLE9BQUEsbUJBQUFDLENBQUEsT0FBQUQsT0FBQSxJQUFBRSxDQUFBLE9BQUFGLE9BQUEsWUFBQUYsd0JBQUEsWUFBQUEsQ0FBQUMsQ0FBQSxXQUFBQSxDQUFBLEdBQUFHLENBQUEsR0FBQUQsQ0FBQSxLQUFBRixDQUFBO0FBQUEsU0FBQUksd0JBQUFKLENBQUEsRUFBQUUsQ0FBQSxTQUFBQSxDQUFBLElBQUFGLENBQUEsSUFBQUEsQ0FBQSxDQUFBSyxVQUFBLFNBQUFMLENBQUEsZUFBQUEsQ0FBQSx1QkFBQUEsQ0FBQSx5QkFBQUEsQ0FBQSxXQUFBTSxPQUFBLEVBQUFOLENBQUEsUUFBQUcsQ0FBQSxHQUFBSix3QkFBQSxDQUFBRyxDQUFBLE9BQUFDLENBQUEsSUFBQUEsQ0FBQSxDQUFBSSxHQUFBLENBQUFQLENBQUEsVUFBQUcsQ0FBQSxDQUFBSyxHQUFBLENBQUFSLENBQUEsT0FBQVMsQ0FBQSxLQUFBQyxTQUFBLFVBQUFDLENBQUEsR0FBQUMsTUFBQSxDQUFBQyxjQUFBLElBQUFELE1BQUEsQ0FBQUUsd0JBQUEsV0FBQUMsQ0FBQSxJQUFBZixDQUFBLG9CQUFBZSxDQUFBLE9BQUFDLGNBQUEsQ0FBQUMsSUFBQSxDQUFBakIsQ0FBQSxFQUFBZSxDQUFBLFNBQUFHLENBQUEsR0FBQVAsQ0FBQSxHQUFBQyxNQUFBLENBQUFFLHdCQUFBLENBQUFkLENBQUEsRUFBQWUsQ0FBQSxVQUFBRyxDQUFBLEtBQUFBLENBQUEsQ0FBQVYsR0FBQSxJQUFBVSxDQUFBLENBQUFDLEdBQUEsSUFBQVAsTUFBQSxDQUFBQyxjQUFBLENBQUFKLENBQUEsRUFBQU0sQ0FBQSxFQUFBRyxDQUFBLElBQUFULENBQUEsQ0FBQU0sQ0FBQSxJQUFBZixDQUFBLENBQUFlLENBQUEsWUFBQU4sQ0FBQSxDQUFBSCxPQUFBLEdBQUFOLENBQUEsRUFBQUcsQ0FBQSxJQUFBQSxDQUFBLENBQUFnQixHQUFBLENBQUFuQixDQUFBLEVBQUFTLENBQUEsR0FBQUEsQ0FBQSxJQXBCckY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFnQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUlXLGlCQUE2QyxHQUFHLENBQUMsQ0FBQztBQUN0RCxJQUFJQyxvQkFBK0UsR0FBRyxDQUFDLENBQUM7QUFDeEYsSUFBSUMsMEJBQTBCLEdBQUcsS0FBSzs7QUFFdEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDTyxTQUFTQyw0QkFBNEJBLENBQUEsRUFBWTtFQUNwRCxPQUFPRCwwQkFBMEI7QUFDckM7QUFFTyxNQUFNRSxvQkFBb0IsU0FBU0MsS0FBSyxDQUFDO0VBQ3JDQyxXQUFXQSxDQUFBLEVBQUc7SUFDakIsS0FBSyxDQUFDLGdDQUFnQyxDQUFDO0VBQzNDO0FBQ0o7QUFBQ0MsT0FBQSxDQUFBSCxvQkFBQSxHQUFBQSxvQkFBQTtBQUVELGVBQWVJLGdCQUFnQkEsQ0FBQSxFQUFxQjtFQUNoRCxNQUFNLENBQUNDLElBQUksQ0FBQyxHQUFHLE1BQU1DLGNBQUssQ0FBQ0MsWUFBWSxDQUFDQyx1QkFBYyxFQUFFO0lBQ3BEQyxLQUFLLEVBQUUsSUFBQUMsbUJBQUUsRUFBQyw2Q0FBNkMsQ0FBQztJQUN4REMsV0FBVyxFQUFFLElBQUFELG1CQUFFLEVBQUMsbURBQW1ELENBQUM7SUFDcEVFLE1BQU0sRUFBRSxLQUFLO0lBQ2JDLE1BQU0sRUFBRSxJQUFBSCxtQkFBRSxFQUFDLGdCQUFnQixDQUFDO0lBQzVCSSxZQUFZLEVBQUUsSUFBQUosbUJBQUUsRUFBQyxlQUFlO0VBQ3BDLENBQUMsQ0FBQyxDQUFDSyxRQUFRO0VBQ1gsT0FBTyxDQUFDVixJQUFJO0FBQ2hCO0FBRUEsU0FBU1csY0FBY0EsQ0FDbkJDLE9BQWtELEVBQ0w7RUFDN0MsT0FBTyxPQUFPO0lBQUVDLFVBQVU7SUFBRUM7RUFBWSxDQUFDLEtBQTBCO0lBQy9ELElBQUlELFVBQVUsRUFBRTtNQUNaLE9BQU8sSUFBQUUsMENBQStCLEVBQUNGLFVBQVUsRUFBRUQsT0FBTyxDQUFDQyxVQUFVLENBQUNHLElBQUksRUFBRUosT0FBTyxDQUFDQyxVQUFVLENBQUNJLFVBQVUsQ0FBQztJQUM5RyxDQUFDLE1BQU0sSUFBSUgsV0FBVyxFQUFFO01BQ3BCLE9BQU8sSUFBQUksNEJBQWlCLEVBQUNKLFdBQVcsQ0FBQztJQUN6QztJQUNBLE1BQU0sSUFBSWxCLEtBQUssQ0FBQyw4REFBOEQsQ0FBQztFQUNuRixDQUFDO0FBQ0w7QUFFQSxlQUFldUIsbUJBQW1CQSxDQUFDO0VBQy9CQyxJQUFJLEVBQUVDO0FBR1YsQ0FBQyxFQUFpQztFQUM5QixNQUFNQyxHQUFHLEdBQUdDLGdDQUFlLENBQUNDLE9BQU8sQ0FBQyxDQUFDO0VBQ3JDLElBQUlDLEtBQUssR0FBRyxNQUFNSCxHQUFHLENBQUNJLDRCQUE0QixDQUFDLENBQUM7RUFDcEQsSUFBSWQsT0FBbUQ7RUFDdkQsSUFBSWEsS0FBSyxFQUFFO0lBQ1A7SUFDQWIsT0FBTyxHQUFHUyxRQUFRLENBQUNJLEtBQUssQ0FBQztJQUN6QixJQUFJLENBQUNiLE9BQU8sRUFBRTtNQUNWO01BQ0E7TUFDQWEsS0FBSyxHQUFHLElBQUk7SUFDaEI7RUFDSjtFQUNBLElBQUksQ0FBQ0EsS0FBSyxFQUFFO0lBQ1I7SUFDQTtJQUNBLE1BQU1FLGNBQWMsR0FBRzVDLE1BQU0sQ0FBQzZDLE9BQU8sQ0FBQ1AsUUFBUSxDQUFDO0lBQy9DLElBQUlNLGNBQWMsQ0FBQ0UsTUFBTSxHQUFHLENBQUMsRUFBRTtNQUMzQixNQUFNLElBQUlqQyxLQUFLLENBQUMsK0NBQStDLENBQUM7SUFDcEU7SUFDQSxDQUFDNkIsS0FBSyxFQUFFYixPQUFPLENBQUMsR0FBR2UsY0FBYyxDQUFDLENBQUMsQ0FBQztFQUN4QztFQUNBRyxjQUFNLENBQUNDLEtBQUssQ0FBQyw2Q0FBNkNoRCxNQUFNLENBQUNxQyxJQUFJLENBQUNDLFFBQVEsQ0FBQyxzQkFBc0JJLEtBQUssRUFBRSxDQUFDOztFQUU3RztFQUNBLElBQUloQywwQkFBMEIsSUFBSUYsaUJBQWlCLENBQUNrQyxLQUFLLENBQUMsRUFBRTtJQUN4REssY0FBTSxDQUFDQyxLQUFLLENBQUMsc0NBQXNDTixLQUFLLGFBQWEsQ0FBQztJQUN0RSxPQUFPLENBQUNBLEtBQUssRUFBRWxDLGlCQUFpQixDQUFDa0MsS0FBSyxDQUFDLENBQUM7RUFDNUM7RUFFQSxNQUFNTyxxQkFBcUIsR0FBR0MsMEJBQVksQ0FBQ0MsUUFBUSxDQUFDQyxVQUFVLENBQUNDLFdBQVcsQ0FBQ2pCLG1CQUFtQixDQUFDLENBQUM7RUFDaEcsSUFBSWEscUJBQXFCLEVBQUU7SUFDdkJGLGNBQU0sQ0FBQ08sR0FBRyxDQUFDLHlFQUF5RSxDQUFDO0lBQ3JGQyxxQkFBcUIsQ0FBQ2IsS0FBSyxFQUFFYixPQUFPLEVBQUVvQixxQkFBcUIsQ0FBQztJQUM1RCxPQUFPLENBQUNQLEtBQUssRUFBRU8scUJBQXFCLENBQUM7RUFDekM7RUFFQUYsY0FBTSxDQUFDQyxLQUFLLENBQUMsNkNBQTZDLENBQUM7RUFDM0QsTUFBTVEsVUFBVSxHQUFHNUIsY0FBYyxDQUFDQyxPQUFPLENBQUM7RUFDMUMsTUFBTTtJQUFFRjtFQUFTLENBQUMsR0FBR1QsY0FBSyxDQUFDQyxZQUFZLENBQ25Dc0Msa0NBQXlCLEVBQ3pCO0VBQ0E7SUFDSTVCLE9BQU87SUFDUDZCLGVBQWUsRUFBRSxNQUFPQyxLQUFnQixJQUF1QjtNQUMzRCxNQUFNQyxHQUFHLEdBQUcsTUFBTUosVUFBVSxDQUFDRyxLQUFLLENBQUM7TUFDbkMsT0FBT25CLGdDQUFlLENBQUNDLE9BQU8sQ0FBQyxDQUFDLENBQUNvQixhQUFhLENBQUNDLFFBQVEsQ0FBQ0YsR0FBRyxFQUFFL0IsT0FBTyxDQUFDO0lBQ3pFO0VBQ0osQ0FBQyxFQUNELGdCQUFpQmtDLFNBQVMsRUFDMUIsc0JBQXVCLEtBQUssRUFDNUIsb0JBQXFCLEtBQUssRUFDMUIsY0FBZTtJQUNYQyxhQUFhLEVBQUUsTUFBT0MsTUFBTSxJQUF1QjtNQUMvQyxJQUFJQSxNQUFNLEtBQUssaUJBQWlCLEVBQUU7UUFDOUIsT0FBT2pELGdCQUFnQixDQUFDLENBQUM7TUFDN0I7TUFDQSxPQUFPLElBQUk7SUFDZjtFQUNKLENBQ0osQ0FBQztFQUNELE1BQU0sQ0FBQ2tELFNBQVMsQ0FBQyxHQUFHLE1BQU12QyxRQUFRO0VBQ2xDLElBQUksQ0FBQ3VDLFNBQVMsRUFBRTtJQUNaLE1BQU0sSUFBSXRELG9CQUFvQixDQUFDLENBQUM7RUFDcEM7RUFDQW1DLGNBQU0sQ0FBQ0MsS0FBSyxDQUFDLHdDQUF3QyxDQUFDO0VBQ3RELE1BQU1ZLEdBQUcsR0FBRyxNQUFNSixVQUFVLENBQUNVLFNBQVMsQ0FBQzs7RUFFdkM7RUFDQVgscUJBQXFCLENBQUNiLEtBQUssRUFBRWIsT0FBTyxFQUFFK0IsR0FBRyxDQUFDO0VBRTFDLE9BQU8sQ0FBQ2xCLEtBQUssRUFBRWtCLEdBQUcsQ0FBQztBQUN2QjtBQUVBLFNBQVNMLHFCQUFxQkEsQ0FDMUJiLEtBQWEsRUFDYmIsT0FBa0QsRUFDbEQrQixHQUFlLEVBQ1g7RUFDSixJQUFJbEQsMEJBQTBCLEVBQUU7SUFDNUJGLGlCQUFpQixDQUFDa0MsS0FBSyxDQUFDLEdBQUdrQixHQUFHO0lBQzlCbkQsb0JBQW9CLENBQUNpQyxLQUFLLENBQUMsR0FBR2IsT0FBTztFQUN6QztBQUNKO0FBRU8sTUFBTXNDLHFCQUF1QyxHQUFBcEQsT0FBQSxDQUFBb0QscUJBQUEsR0FBRztFQUNuRC9CLG1CQUFtQjtFQUNuQm1CO0FBQ0osQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ08sZUFBZWEseUJBQXlCQSxDQUFJQyxJQUFzQixFQUFjO0VBQ25GdEIsY0FBTSxDQUFDQyxLQUFLLENBQUMsd0NBQXdDLENBQUM7RUFDdER0QywwQkFBMEIsR0FBRyxJQUFJO0VBQ2pDLElBQUk7SUFDQSxPQUFPLE1BQU0yRCxJQUFJLENBQUMsQ0FBQztFQUN2QixDQUFDLFNBQVM7SUFDTjtJQUNBdEIsY0FBTSxDQUFDQyxLQUFLLENBQUMseUNBQXlDLENBQUM7SUFDdkR0QywwQkFBMEIsR0FBRyxLQUFLO0lBQ2xDRixpQkFBaUIsR0FBRyxDQUFDLENBQUM7SUFDdEJDLG9CQUFvQixHQUFHLENBQUMsQ0FBQztFQUM3QjtBQUNKOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNPLGVBQWU2RCxtQkFBbUJBLENBQUNELElBQUksR0FBRyxNQUFBQSxDQUFBLEtBQTJCLENBQUMsQ0FBQyxFQUFFRSxVQUFVLEdBQUcsS0FBSyxFQUFpQjtFQUMvRyxNQUFNSCx5QkFBeUIsQ0FBQyxNQUFNSSxxQkFBcUIsQ0FBQ0gsSUFBSSxFQUFFRSxVQUFVLENBQUMsQ0FBQztBQUNsRjs7QUFFQTtBQUNBLGVBQWVDLHFCQUFxQkEsQ0FBQ0gsSUFBeUIsRUFBRUUsVUFBbUIsRUFBaUI7RUFDaEcsSUFBSTtJQUNBLE1BQU1oQyxHQUFHLEdBQUdDLGdDQUFlLENBQUNDLE9BQU8sQ0FBQyxDQUFDO0lBQ3JDLE1BQU1nQyxNQUFNLEdBQUdsQyxHQUFHLENBQUNtQyxTQUFTLENBQUMsQ0FBQztJQUM5QixJQUFJLENBQUNELE1BQU0sRUFBRTtNQUNULE1BQU0sSUFBSTVELEtBQUssQ0FBQyxzRUFBc0UsQ0FBQztJQUMzRjtJQUVBLElBQUk4RCxTQUFTLEdBQUcsS0FBSztJQUNyQixJQUFJSixVQUFVLEVBQUU7TUFDWnhCLGNBQU0sQ0FBQ0MsS0FBSyxDQUFDLG1DQUFtQyxDQUFDO01BQ2pEMkIsU0FBUyxHQUFHLElBQUk7SUFDcEIsQ0FBQyxNQUFNLElBQUksRUFBRSxNQUFNcEMsR0FBRyxDQUFDc0IsYUFBYSxDQUFDZSxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUU7TUFDNUM3QixjQUFNLENBQUNDLEtBQUssQ0FBQywrREFBK0QsQ0FBQztNQUM3RTJCLFNBQVMsR0FBRyxJQUFJO0lBQ3BCO0lBRUEsSUFBSUEsU0FBUyxFQUFFO01BQ1g7TUFDQTtNQUNBLE1BQU07UUFBRWhEO01BQVMsQ0FBQyxHQUFHVCxjQUFLLENBQUMyRCxpQkFBaUIsQ0FBQUMsT0FBQSxDQUFBQyxPQUFBLEdBQUFDLElBQUEsT0FBQXhGLHVCQUFBLENBQUFoQixPQUFBLENBQ2pDLHFFQUFxRSxLQUc1RTtRQUNJK0Y7TUFDSixDQUFDLEVBQ0RSLFNBQVMsRUFDVCxnQkFBaUIsS0FBSyxFQUN0QixjQUFlLElBQUksRUFDbkIsZUFBZ0I7UUFDWkMsYUFBYSxFQUFFLE1BQU9DLE1BQU0sSUFBdUI7VUFDL0M7VUFDQSxJQUFJQSxNQUFNLEtBQUssaUJBQWlCLEVBQUU7WUFDOUIsT0FBTyxDQUFDLElBQUFnQixzQ0FBc0IsRUFBQzFDLEdBQUcsQ0FBQztVQUN2QztVQUNBLE9BQU8sSUFBSTtRQUNmO01BQ0osQ0FDSixDQUFDO01BQ0QsTUFBTSxDQUFDMkMsU0FBUyxDQUFDLEdBQUcsTUFBTXZELFFBQVE7TUFDbEMsSUFBSSxDQUFDdUQsU0FBUyxFQUFFO1FBQ1osTUFBTSxJQUFJckUsS0FBSyxDQUFDLGtDQUFrQyxDQUFDO01BQ3ZEO0lBQ0osQ0FBQyxNQUFNO01BQ0hrQyxjQUFNLENBQUNDLEtBQUssQ0FBQyw0Q0FBNEMsQ0FBQztNQUMxRCxNQUFNeUIsTUFBTSxDQUFDVSxxQkFBcUIsQ0FBQztRQUMvQkMsMkJBQTJCLEVBQUUsTUFBT0MsV0FBVyxJQUFvQjtVQUMvRHRDLGNBQU0sQ0FBQ0MsS0FBSyxDQUFDLGtFQUFrRSxDQUFDO1VBQ2hGLE1BQU07WUFBRXJCO1VBQVMsQ0FBQyxHQUFHVCxjQUFLLENBQUNDLFlBQVksQ0FBQ21FLDhCQUFxQixFQUFFO1lBQzNEakUsS0FBSyxFQUFFLElBQUFDLG1CQUFFLEVBQUMsNEJBQTRCLENBQUM7WUFDdkNpRSxZQUFZLEVBQUVoRCxHQUFHO1lBQ2pCOEM7VUFDSixDQUFDLENBQUM7VUFDRixNQUFNLENBQUNILFNBQVMsQ0FBQyxHQUFHLE1BQU12RCxRQUFRO1VBQ2xDLElBQUksQ0FBQ3VELFNBQVMsRUFBRTtZQUNaLE1BQU0sSUFBSXJFLEtBQUssQ0FBQyx3Q0FBd0MsQ0FBQztVQUM3RDtVQUNBa0MsY0FBTSxDQUFDQyxLQUFLLENBQUMsMERBQTBELENBQUM7UUFDNUU7TUFDSixDQUFDLENBQUM7TUFDRkQsY0FBTSxDQUFDQyxLQUFLLENBQUMsNkNBQTZDLENBQUM7TUFDM0QsTUFBTXlCLE1BQU0sQ0FBQ2Usc0JBQXNCLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDM0M7SUFFQXpDLGNBQU0sQ0FBQ0MsS0FBSyxDQUFDLG1DQUFtQyxDQUFDO0lBQ2pEO0lBQ0E7SUFDQSxNQUFNcUIsSUFBSSxDQUFDLENBQUM7SUFDWnRCLGNBQU0sQ0FBQ0MsS0FBSyxDQUFDLHlDQUF5QyxDQUFDO0VBQzNELENBQUMsQ0FBQyxPQUFPNUQsQ0FBQyxFQUFFO0lBQ1I4RCwwQkFBWSxDQUFDQyxRQUFRLENBQUNDLFVBQVUsQ0FBQ0MsV0FBVyxDQUFDb0MsNkJBQTZCLENBQUNyRyxDQUFVLENBQUM7SUFDdEYyRCxjQUFNLENBQUMyQyxLQUFLLENBQUMsNkNBQTZDLEVBQUV0RyxDQUFDLENBQUM7SUFDOUQ7SUFDQSxNQUFNQSxDQUFDO0VBQ1g7QUFDSiIsImlnbm9yZUxpc3QiOltdfQ==