UNPKG

matrix-react-sdk

Version:
273 lines (265 loc) 39.9 kB
"use strict"; 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==