UNPKG

matrix-react-sdk

Version:
323 lines (306 loc) 39.3 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.decryptMegolmKeyFile = decryptMegolmKeyFile; exports.encryptMegolmKeyFile = encryptMegolmKeyFile; var _logger = require("matrix-js-sdk/src/logger"); var _languageHandler = require("../languageHandler"); var _SdkConfig = _interopRequireDefault(require("../SdkConfig")); /* Copyright 2024 New Vector Ltd. Copyright 2020 The Matrix.org Foundation C.I.C. Copyright 2017 Vector Creations Ltd SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ const subtleCrypto = window.crypto.subtle; /** * Make an Error object which has a friendlyText property which is already * translated and suitable for showing to the user. * * @param {string} message message for the exception * @param {string} friendlyText * @returns {{message: string, friendlyText: string}} */ function friendlyError(message, friendlyText) { return { message, friendlyText }; } function cryptoFailMsg() { return (0, _languageHandler._t)("encryption|export_unsupported"); } /** * Decrypt a megolm key file * * @param {ArrayBuffer} data file to decrypt * @param {String} password * @return {Promise<String>} promise for decrypted output * * */ async function decryptMegolmKeyFile(data, password) { const body = unpackMegolmKeyFile(data); const brand = _SdkConfig.default.get().brand; // check we have a version byte if (body.length < 1) { throw friendlyError("Invalid file: too short", (0, _languageHandler._t)("encryption|import_invalid_keyfile", { brand })); } const version = body[0]; if (version !== 1) { throw friendlyError("Unsupported version", (0, _languageHandler._t)("encryption|import_invalid_keyfile", { brand })); } const ciphertextLength = body.length - (1 + 16 + 16 + 4 + 32); if (ciphertextLength < 0) { throw friendlyError("Invalid file: too short", (0, _languageHandler._t)("encryption|import_invalid_keyfile", { brand })); } const salt = body.subarray(1, 1 + 16); const iv = body.subarray(17, 17 + 16); const iterations = body[33] << 24 | body[34] << 16 | body[35] << 8 | body[36]; const ciphertext = body.subarray(37, 37 + ciphertextLength); const hmac = body.subarray(-32); const [aesKey, hmacKey] = await deriveKeys(salt, iterations, password); const toVerify = body.subarray(0, -32); let isValid; try { isValid = await subtleCrypto.verify({ name: "HMAC" }, hmacKey, hmac, toVerify); } catch (e) { throw friendlyError("subtleCrypto.verify failed: " + e, cryptoFailMsg()); } if (!isValid) { throw friendlyError("hmac mismatch", (0, _languageHandler._t)("encryption|import_invalid_passphrase")); } let plaintext; try { plaintext = await subtleCrypto.decrypt({ name: "AES-CTR", counter: iv, length: 64 }, aesKey, ciphertext); } catch (e) { throw friendlyError("subtleCrypto.decrypt failed: " + e, cryptoFailMsg()); } return new TextDecoder().decode(new Uint8Array(plaintext)); } /** * Encrypt a megolm key file * * @param {String} data * @param {String} password * @param {Object=} options * @param {Number=} options.kdf_rounds Number of iterations to perform of the * key-derivation function. * @return {Promise<ArrayBuffer>} promise for encrypted output */ async function encryptMegolmKeyFile(data, password, options // eslint-disable-line camelcase ) { options = options || {}; const kdfRounds = options.kdf_rounds || 500000; const salt = new Uint8Array(16); window.crypto.getRandomValues(salt); const iv = new Uint8Array(16); window.crypto.getRandomValues(iv); // clear bit 63 of the IV to stop us hitting the 64-bit counter boundary // (which would mean we wouldn't be able to decrypt on Android). The loss // of a single bit of iv is a price we have to pay. iv[8] &= 0x7f; const [aesKey, hmacKey] = await deriveKeys(salt, kdfRounds, password); const encodedData = new TextEncoder().encode(data); let ciphertext; try { ciphertext = await subtleCrypto.encrypt({ name: "AES-CTR", counter: iv, length: 64 }, aesKey, encodedData); } catch (e) { throw friendlyError("subtleCrypto.encrypt failed: " + e, cryptoFailMsg()); } const cipherArray = new Uint8Array(ciphertext); const bodyLength = 1 + salt.length + iv.length + 4 + cipherArray.length + 32; const resultBuffer = new Uint8Array(bodyLength); let idx = 0; resultBuffer[idx++] = 1; // version resultBuffer.set(salt, idx); idx += salt.length; resultBuffer.set(iv, idx); idx += iv.length; resultBuffer[idx++] = kdfRounds >> 24; resultBuffer[idx++] = kdfRounds >> 16 & 0xff; resultBuffer[idx++] = kdfRounds >> 8 & 0xff; resultBuffer[idx++] = kdfRounds & 0xff; resultBuffer.set(cipherArray, idx); idx += cipherArray.length; const toSign = resultBuffer.subarray(0, idx); let hmac; try { hmac = await subtleCrypto.sign({ name: "HMAC" }, hmacKey, toSign); } catch (e) { throw friendlyError("subtleCrypto.sign failed: " + e, cryptoFailMsg()); } const hmacArray = new Uint8Array(hmac); resultBuffer.set(hmacArray, idx); return packMegolmKeyFile(resultBuffer); } /** * Derive the AES and HMAC-SHA-256 keys for the file * * @param {Unit8Array} salt salt for pbkdf * @param {Number} iterations number of pbkdf iterations * @param {String} password password * @return {Promise<[CryptoKey, CryptoKey]>} promise for [aes key, hmac key] */ async function deriveKeys(salt, iterations, password) { const start = new Date(); let key; try { key = await subtleCrypto.importKey("raw", new TextEncoder().encode(password), { name: "PBKDF2" }, false, ["deriveBits"]); } catch (e) { throw friendlyError("subtleCrypto.importKey failed: " + e, cryptoFailMsg()); } let keybits; try { keybits = await subtleCrypto.deriveBits({ name: "PBKDF2", salt: salt, iterations: iterations, hash: "SHA-512" }, key, 512); } catch (e) { throw friendlyError("subtleCrypto.deriveBits failed: " + e, cryptoFailMsg()); } const now = new Date(); _logger.logger.log("E2e import/export: deriveKeys took " + (now.getTime() - start.getTime()) + "ms"); const aesKey = keybits.slice(0, 32); const hmacKey = keybits.slice(32); const aesProm = subtleCrypto.importKey("raw", aesKey, { name: "AES-CTR" }, false, ["encrypt", "decrypt"]).catch(e => { throw friendlyError("subtleCrypto.importKey failed for AES key: " + e, cryptoFailMsg()); }); const hmacProm = subtleCrypto.importKey("raw", hmacKey, { name: "HMAC", hash: { name: "SHA-256" } }, false, ["sign", "verify"]).catch(e => { throw friendlyError("subtleCrypto.importKey failed for HMAC key: " + e, cryptoFailMsg()); }); return Promise.all([aesProm, hmacProm]); } const HEADER_LINE = "-----BEGIN MEGOLM SESSION DATA-----"; const TRAILER_LINE = "-----END MEGOLM SESSION DATA-----"; /** * Unbase64 an ascii-armoured megolm key file * * Strips the header and trailer lines, and unbase64s the content * * @param {ArrayBuffer} data input file * @return {Uint8Array} unbase64ed content */ function unpackMegolmKeyFile(data) { // parse the file as a great big String. This should be safe, because there // should be no non-ASCII characters, and it means that we can do string // comparisons to find the header and footer, and feed it into window.atob. const fileStr = new TextDecoder().decode(new Uint8Array(data)); // look for the start line let lineStart = 0; // eslint-disable-next-line no-constant-condition while (1) { const lineEnd = fileStr.indexOf("\n", lineStart); if (lineEnd < 0) { throw new Error("Header line not found"); } const line = fileStr.slice(lineStart, lineEnd).trim(); // start the next line after the newline lineStart = lineEnd + 1; if (line === HEADER_LINE) { break; } } const dataStart = lineStart; // look for the end line // eslint-disable-next-line no-constant-condition while (1) { const lineEnd = fileStr.indexOf("\n", lineStart); const line = fileStr.slice(lineStart, lineEnd < 0 ? undefined : lineEnd).trim(); if (line === TRAILER_LINE) { break; } if (lineEnd < 0) { throw new Error("Trailer line not found"); } // start the next line after the newline lineStart = lineEnd + 1; } const dataEnd = lineStart; return decodeBase64(fileStr.slice(dataStart, dataEnd)); } /** * ascii-armour a megolm key file * * base64s the content, and adds header and trailer lines * * @param {Uint8Array} data raw data * @return {ArrayBuffer} formatted file */ function packMegolmKeyFile(data) { // we split into lines before base64ing, because encodeBase64 doesn't deal // terribly well with large arrays. const LINE_LENGTH = 72 * 4 / 3; const nLines = Math.ceil(data.length / LINE_LENGTH); const lines = new Array(nLines + 3); lines[0] = HEADER_LINE; let o = 0; let i; for (i = 1; i <= nLines; i++) { lines[i] = encodeBase64(data.subarray(o, o + LINE_LENGTH)); o += LINE_LENGTH; } lines[i++] = TRAILER_LINE; lines[i] = ""; return new TextEncoder().encode(lines.join("\n")).buffer; } /** * Encode a typed array of uint8 as base64. * @param {Uint8Array} uint8Array The data to encode. * @return {string} The base64. */ function encodeBase64(uint8Array) { // Misinterpt the Uint8Array as Latin-1. // window.btoa expects a unicode string with codepoints in the range 0-255. const latin1String = String.fromCharCode.apply(null, Array.from(uint8Array)); // Use the builtin base64 encoder. return window.btoa(latin1String); } /** * Decode a base64 string to a typed array of uint8. * @param {string} base64 The base64 to decode. * @return {Uint8Array} The decoded data. */ function decodeBase64(base64) { // window.atob returns a unicode string with codepoints in the range 0-255. const latin1String = window.atob(base64); // Encode the string as a Uint8Array const uint8Array = new Uint8Array(latin1String.length); for (let i = 0; i < latin1String.length; i++) { uint8Array[i] = latin1String.charCodeAt(i); } return uint8Array; } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9nZ2VyIiwicmVxdWlyZSIsIl9sYW5ndWFnZUhhbmRsZXIiLCJfU2RrQ29uZmlnIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInN1YnRsZUNyeXB0byIsIndpbmRvdyIsImNyeXB0byIsInN1YnRsZSIsImZyaWVuZGx5RXJyb3IiLCJtZXNzYWdlIiwiZnJpZW5kbHlUZXh0IiwiY3J5cHRvRmFpbE1zZyIsIl90IiwiZGVjcnlwdE1lZ29sbUtleUZpbGUiLCJkYXRhIiwicGFzc3dvcmQiLCJib2R5IiwidW5wYWNrTWVnb2xtS2V5RmlsZSIsImJyYW5kIiwiU2RrQ29uZmlnIiwiZ2V0IiwibGVuZ3RoIiwidmVyc2lvbiIsImNpcGhlcnRleHRMZW5ndGgiLCJzYWx0Iiwic3ViYXJyYXkiLCJpdiIsIml0ZXJhdGlvbnMiLCJjaXBoZXJ0ZXh0IiwiaG1hYyIsImFlc0tleSIsImhtYWNLZXkiLCJkZXJpdmVLZXlzIiwidG9WZXJpZnkiLCJpc1ZhbGlkIiwidmVyaWZ5IiwibmFtZSIsImUiLCJwbGFpbnRleHQiLCJkZWNyeXB0IiwiY291bnRlciIsIlRleHREZWNvZGVyIiwiZGVjb2RlIiwiVWludDhBcnJheSIsImVuY3J5cHRNZWdvbG1LZXlGaWxlIiwib3B0aW9ucyIsImtkZlJvdW5kcyIsImtkZl9yb3VuZHMiLCJnZXRSYW5kb21WYWx1ZXMiLCJlbmNvZGVkRGF0YSIsIlRleHRFbmNvZGVyIiwiZW5jb2RlIiwiZW5jcnlwdCIsImNpcGhlckFycmF5IiwiYm9keUxlbmd0aCIsInJlc3VsdEJ1ZmZlciIsImlkeCIsInNldCIsInRvU2lnbiIsInNpZ24iLCJobWFjQXJyYXkiLCJwYWNrTWVnb2xtS2V5RmlsZSIsInN0YXJ0IiwiRGF0ZSIsImtleSIsImltcG9ydEtleSIsImtleWJpdHMiLCJkZXJpdmVCaXRzIiwiaGFzaCIsIm5vdyIsImxvZ2dlciIsImxvZyIsImdldFRpbWUiLCJzbGljZSIsImFlc1Byb20iLCJjYXRjaCIsImhtYWNQcm9tIiwiUHJvbWlzZSIsImFsbCIsIkhFQURFUl9MSU5FIiwiVFJBSUxFUl9MSU5FIiwiZmlsZVN0ciIsImxpbmVTdGFydCIsImxpbmVFbmQiLCJpbmRleE9mIiwiRXJyb3IiLCJsaW5lIiwidHJpbSIsImRhdGFTdGFydCIsInVuZGVmaW5lZCIsImRhdGFFbmQiLCJkZWNvZGVCYXNlNjQiLCJMSU5FX0xFTkdUSCIsIm5MaW5lcyIsIk1hdGgiLCJjZWlsIiwibGluZXMiLCJBcnJheSIsIm8iLCJpIiwiZW5jb2RlQmFzZTY0Iiwiam9pbiIsImJ1ZmZlciIsInVpbnQ4QXJyYXkiLCJsYXRpbjFTdHJpbmciLCJTdHJpbmciLCJmcm9tQ2hhckNvZGUiLCJhcHBseSIsImZyb20iLCJidG9hIiwiYmFzZTY0IiwiYXRvYiIsImNoYXJDb2RlQXQiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvTWVnb2xtRXhwb3J0RW5jcnlwdGlvbi50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuQ29weXJpZ2h0IDIwMjQgTmV3IFZlY3RvciBMdGQuXG5Db3B5cmlnaHQgMjAyMCBUaGUgTWF0cml4Lm9yZyBGb3VuZGF0aW9uIEMuSS5DLlxuQ29weXJpZ2h0IDIwMTcgVmVjdG9yIENyZWF0aW9ucyBMdGRcblxuU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFHUEwtMy4wLW9ubHkgT1IgR1BMLTMuMC1vbmx5XG5QbGVhc2Ugc2VlIExJQ0VOU0UgZmlsZXMgaW4gdGhlIHJlcG9zaXRvcnkgcm9vdCBmb3IgZnVsbCBkZXRhaWxzLlxuKi9cblxuaW1wb3J0IHsgbG9nZ2VyIH0gZnJvbSBcIm1hdHJpeC1qcy1zZGsvc3JjL2xvZ2dlclwiO1xuXG5pbXBvcnQgeyBfdCB9IGZyb20gXCIuLi9sYW5ndWFnZUhhbmRsZXJcIjtcbmltcG9ydCBTZGtDb25maWcgZnJvbSBcIi4uL1Nka0NvbmZpZ1wiO1xuXG5jb25zdCBzdWJ0bGVDcnlwdG8gPSB3aW5kb3cuY3J5cHRvLnN1YnRsZTtcblxuLyoqXG4gKiBNYWtlIGFuIEVycm9yIG9iamVjdCB3aGljaCBoYXMgYSBmcmllbmRseVRleHQgcHJvcGVydHkgd2hpY2ggaXMgYWxyZWFkeVxuICogdHJhbnNsYXRlZCBhbmQgc3VpdGFibGUgZm9yIHNob3dpbmcgdG8gdGhlIHVzZXIuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2UgbWVzc2FnZSBmb3IgdGhlIGV4Y2VwdGlvblxuICogQHBhcmFtIHtzdHJpbmd9IGZyaWVuZGx5VGV4dFxuICogQHJldHVybnMge3ttZXNzYWdlOiBzdHJpbmcsIGZyaWVuZGx5VGV4dDogc3RyaW5nfX1cbiAqL1xuZnVuY3Rpb24gZnJpZW5kbHlFcnJvcihtZXNzYWdlOiBzdHJpbmcsIGZyaWVuZGx5VGV4dDogc3RyaW5nKTogeyBtZXNzYWdlOiBzdHJpbmc7IGZyaWVuZGx5VGV4dDogc3RyaW5nIH0ge1xuICAgIHJldHVybiB7IG1lc3NhZ2UsIGZyaWVuZGx5VGV4dCB9O1xufVxuXG5mdW5jdGlvbiBjcnlwdG9GYWlsTXNnKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIF90KFwiZW5jcnlwdGlvbnxleHBvcnRfdW5zdXBwb3J0ZWRcIik7XG59XG5cbi8qKlxuICogRGVjcnlwdCBhIG1lZ29sbSBrZXkgZmlsZVxuICpcbiAqIEBwYXJhbSB7QXJyYXlCdWZmZXJ9IGRhdGEgZmlsZSB0byBkZWNyeXB0XG4gKiBAcGFyYW0ge1N0cmluZ30gcGFzc3dvcmRcbiAqIEByZXR1cm4ge1Byb21pc2U8U3RyaW5nPn0gcHJvbWlzZSBmb3IgZGVjcnlwdGVkIG91dHB1dFxuICpcbiAqXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBkZWNyeXB0TWVnb2xtS2V5RmlsZShkYXRhOiBBcnJheUJ1ZmZlciwgcGFzc3dvcmQ6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgYm9keSA9IHVucGFja01lZ29sbUtleUZpbGUoZGF0YSk7XG4gICAgY29uc3QgYnJhbmQgPSBTZGtDb25maWcuZ2V0KCkuYnJhbmQ7XG5cbiAgICAvLyBjaGVjayB3ZSBoYXZlIGEgdmVyc2lvbiBieXRlXG4gICAgaWYgKGJvZHkubGVuZ3RoIDwgMSkge1xuICAgICAgICB0aHJvdyBmcmllbmRseUVycm9yKFwiSW52YWxpZCBmaWxlOiB0b28gc2hvcnRcIiwgX3QoXCJlbmNyeXB0aW9ufGltcG9ydF9pbnZhbGlkX2tleWZpbGVcIiwgeyBicmFuZCB9KSk7XG4gICAgfVxuXG4gICAgY29uc3QgdmVyc2lvbiA9IGJvZHlbMF07XG4gICAgaWYgKHZlcnNpb24gIT09IDEpIHtcbiAgICAgICAgdGhyb3cgZnJpZW5kbHlFcnJvcihcIlVuc3VwcG9ydGVkIHZlcnNpb25cIiwgX3QoXCJlbmNyeXB0aW9ufGltcG9ydF9pbnZhbGlkX2tleWZpbGVcIiwgeyBicmFuZCB9KSk7XG4gICAgfVxuXG4gICAgY29uc3QgY2lwaGVydGV4dExlbmd0aCA9IGJvZHkubGVuZ3RoIC0gKDEgKyAxNiArIDE2ICsgNCArIDMyKTtcbiAgICBpZiAoY2lwaGVydGV4dExlbmd0aCA8IDApIHtcbiAgICAgICAgdGhyb3cgZnJpZW5kbHlFcnJvcihcIkludmFsaWQgZmlsZTogdG9vIHNob3J0XCIsIF90KFwiZW5jcnlwdGlvbnxpbXBvcnRfaW52YWxpZF9rZXlmaWxlXCIsIHsgYnJhbmQgfSkpO1xuICAgIH1cblxuICAgIGNvbnN0IHNhbHQgPSBib2R5LnN1YmFycmF5KDEsIDEgKyAxNik7XG4gICAgY29uc3QgaXYgPSBib2R5LnN1YmFycmF5KDE3LCAxNyArIDE2KTtcbiAgICBjb25zdCBpdGVyYXRpb25zID0gKGJvZHlbMzNdIDw8IDI0KSB8IChib2R5WzM0XSA8PCAxNikgfCAoYm9keVszNV0gPDwgOCkgfCBib2R5WzM2XTtcbiAgICBjb25zdCBjaXBoZXJ0ZXh0ID0gYm9keS5zdWJhcnJheSgzNywgMzcgKyBjaXBoZXJ0ZXh0TGVuZ3RoKTtcbiAgICBjb25zdCBobWFjID0gYm9keS5zdWJhcnJheSgtMzIpO1xuXG4gICAgY29uc3QgW2Flc0tleSwgaG1hY0tleV0gPSBhd2FpdCBkZXJpdmVLZXlzKHNhbHQsIGl0ZXJhdGlvbnMsIHBhc3N3b3JkKTtcbiAgICBjb25zdCB0b1ZlcmlmeSA9IGJvZHkuc3ViYXJyYXkoMCwgLTMyKTtcblxuICAgIGxldCBpc1ZhbGlkO1xuICAgIHRyeSB7XG4gICAgICAgIGlzVmFsaWQgPSBhd2FpdCBzdWJ0bGVDcnlwdG8udmVyaWZ5KHsgbmFtZTogXCJITUFDXCIgfSwgaG1hY0tleSwgaG1hYywgdG9WZXJpZnkpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgdGhyb3cgZnJpZW5kbHlFcnJvcihcInN1YnRsZUNyeXB0by52ZXJpZnkgZmFpbGVkOiBcIiArIGUsIGNyeXB0b0ZhaWxNc2coKSk7XG4gICAgfVxuICAgIGlmICghaXNWYWxpZCkge1xuICAgICAgICB0aHJvdyBmcmllbmRseUVycm9yKFwiaG1hYyBtaXNtYXRjaFwiLCBfdChcImVuY3J5cHRpb258aW1wb3J0X2ludmFsaWRfcGFzc3BocmFzZVwiKSk7XG4gICAgfVxuXG4gICAgbGV0IHBsYWludGV4dDtcbiAgICB0cnkge1xuICAgICAgICBwbGFpbnRleHQgPSBhd2FpdCBzdWJ0bGVDcnlwdG8uZGVjcnlwdChcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkFFUy1DVFJcIixcbiAgICAgICAgICAgICAgICBjb3VudGVyOiBpdixcbiAgICAgICAgICAgICAgICBsZW5ndGg6IDY0LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGFlc0tleSxcbiAgICAgICAgICAgIGNpcGhlcnRleHQsXG4gICAgICAgICk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICB0aHJvdyBmcmllbmRseUVycm9yKFwic3VidGxlQ3J5cHRvLmRlY3J5cHQgZmFpbGVkOiBcIiArIGUsIGNyeXB0b0ZhaWxNc2coKSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShuZXcgVWludDhBcnJheShwbGFpbnRleHQpKTtcbn1cblxuLyoqXG4gKiBFbmNyeXB0IGEgbWVnb2xtIGtleSBmaWxlXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IGRhdGFcbiAqIEBwYXJhbSB7U3RyaW5nfSBwYXNzd29yZFxuICogQHBhcmFtIHtPYmplY3Q9fSBvcHRpb25zXG4gKiBAcGFyYW0ge051bWJlcj19IG9wdGlvbnMua2RmX3JvdW5kcyBOdW1iZXIgb2YgaXRlcmF0aW9ucyB0byBwZXJmb3JtIG9mIHRoZVxuICogICAga2V5LWRlcml2YXRpb24gZnVuY3Rpb24uXG4gKiBAcmV0dXJuIHtQcm9taXNlPEFycmF5QnVmZmVyPn0gcHJvbWlzZSBmb3IgZW5jcnlwdGVkIG91dHB1dFxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZW5jcnlwdE1lZ29sbUtleUZpbGUoXG4gICAgZGF0YTogc3RyaW5nLFxuICAgIHBhc3N3b3JkOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IHsga2RmX3JvdW5kcz86IG51bWJlciB9LCAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIGNhbWVsY2FzZVxuKTogUHJvbWlzZTxBcnJheUJ1ZmZlcj4ge1xuICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgIGNvbnN0IGtkZlJvdW5kcyA9IG9wdGlvbnMua2RmX3JvdW5kcyB8fCA1MDAwMDA7XG5cbiAgICBjb25zdCBzYWx0ID0gbmV3IFVpbnQ4QXJyYXkoMTYpO1xuICAgIHdpbmRvdy5jcnlwdG8uZ2V0UmFuZG9tVmFsdWVzKHNhbHQpO1xuXG4gICAgY29uc3QgaXYgPSBuZXcgVWludDhBcnJheSgxNik7XG4gICAgd2luZG93LmNyeXB0by5nZXRSYW5kb21WYWx1ZXMoaXYpO1xuXG4gICAgLy8gY2xlYXIgYml0IDYzIG9mIHRoZSBJViB0byBzdG9wIHVzIGhpdHRpbmcgdGhlIDY0LWJpdCBjb3VudGVyIGJvdW5kYXJ5XG4gICAgLy8gKHdoaWNoIHdvdWxkIG1lYW4gd2Ugd291bGRuJ3QgYmUgYWJsZSB0byBkZWNyeXB0IG9uIEFuZHJvaWQpLiBUaGUgbG9zc1xuICAgIC8vIG9mIGEgc2luZ2xlIGJpdCBvZiBpdiBpcyBhIHByaWNlIHdlIGhhdmUgdG8gcGF5LlxuICAgIGl2WzhdICY9IDB4N2Y7XG5cbiAgICBjb25zdCBbYWVzS2V5LCBobWFjS2V5XSA9IGF3YWl0IGRlcml2ZUtleXMoc2FsdCwga2RmUm91bmRzLCBwYXNzd29yZCk7XG4gICAgY29uc3QgZW5jb2RlZERhdGEgPSBuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUoZGF0YSk7XG5cbiAgICBsZXQgY2lwaGVydGV4dDtcbiAgICB0cnkge1xuICAgICAgICBjaXBoZXJ0ZXh0ID0gYXdhaXQgc3VidGxlQ3J5cHRvLmVuY3J5cHQoXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJBRVMtQ1RSXCIsXG4gICAgICAgICAgICAgICAgY291bnRlcjogaXYsXG4gICAgICAgICAgICAgICAgbGVuZ3RoOiA2NCxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBhZXNLZXksXG4gICAgICAgICAgICBlbmNvZGVkRGF0YSxcbiAgICAgICAgKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93IGZyaWVuZGx5RXJyb3IoXCJzdWJ0bGVDcnlwdG8uZW5jcnlwdCBmYWlsZWQ6IFwiICsgZSwgY3J5cHRvRmFpbE1zZygpKTtcbiAgICB9XG5cbiAgICBjb25zdCBjaXBoZXJBcnJheSA9IG5ldyBVaW50OEFycmF5KGNpcGhlcnRleHQpO1xuICAgIGNvbnN0IGJvZHlMZW5ndGggPSAxICsgc2FsdC5sZW5ndGggKyBpdi5sZW5ndGggKyA0ICsgY2lwaGVyQXJyYXkubGVuZ3RoICsgMzI7XG4gICAgY29uc3QgcmVzdWx0QnVmZmVyID0gbmV3IFVpbnQ4QXJyYXkoYm9keUxlbmd0aCk7XG4gICAgbGV0IGlkeCA9IDA7XG4gICAgcmVzdWx0QnVmZmVyW2lkeCsrXSA9IDE7IC8vIHZlcnNpb25cbiAgICByZXN1bHRCdWZmZXIuc2V0KHNhbHQsIGlkeCk7XG4gICAgaWR4ICs9IHNhbHQubGVuZ3RoO1xuICAgIHJlc3VsdEJ1ZmZlci5zZXQoaXYsIGlkeCk7XG4gICAgaWR4ICs9IGl2Lmxlbmd0aDtcbiAgICByZXN1bHRCdWZmZXJbaWR4KytdID0ga2RmUm91bmRzID4+IDI0O1xuICAgIHJlc3VsdEJ1ZmZlcltpZHgrK10gPSAoa2RmUm91bmRzID4+IDE2KSAmIDB4ZmY7XG4gICAgcmVzdWx0QnVmZmVyW2lkeCsrXSA9IChrZGZSb3VuZHMgPj4gOCkgJiAweGZmO1xuICAgIHJlc3VsdEJ1ZmZlcltpZHgrK10gPSBrZGZSb3VuZHMgJiAweGZmO1xuICAgIHJlc3VsdEJ1ZmZlci5zZXQoY2lwaGVyQXJyYXksIGlkeCk7XG4gICAgaWR4ICs9IGNpcGhlckFycmF5Lmxlbmd0aDtcblxuICAgIGNvbnN0IHRvU2lnbiA9IHJlc3VsdEJ1ZmZlci5zdWJhcnJheSgwLCBpZHgpO1xuXG4gICAgbGV0IGhtYWM7XG4gICAgdHJ5IHtcbiAgICAgICAgaG1hYyA9IGF3YWl0IHN1YnRsZUNyeXB0by5zaWduKHsgbmFtZTogXCJITUFDXCIgfSwgaG1hY0tleSwgdG9TaWduKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93IGZyaWVuZGx5RXJyb3IoXCJzdWJ0bGVDcnlwdG8uc2lnbiBmYWlsZWQ6IFwiICsgZSwgY3J5cHRvRmFpbE1zZygpKTtcbiAgICB9XG5cbiAgICBjb25zdCBobWFjQXJyYXkgPSBuZXcgVWludDhBcnJheShobWFjKTtcbiAgICByZXN1bHRCdWZmZXIuc2V0KGhtYWNBcnJheSwgaWR4KTtcbiAgICByZXR1cm4gcGFja01lZ29sbUtleUZpbGUocmVzdWx0QnVmZmVyKTtcbn1cblxuLyoqXG4gKiBEZXJpdmUgdGhlIEFFUyBhbmQgSE1BQy1TSEEtMjU2IGtleXMgZm9yIHRoZSBmaWxlXG4gKlxuICogQHBhcmFtIHtVbml0OEFycmF5fSBzYWx0ICBzYWx0IGZvciBwYmtkZlxuICogQHBhcmFtIHtOdW1iZXJ9IGl0ZXJhdGlvbnMgbnVtYmVyIG9mIHBia2RmIGl0ZXJhdGlvbnNcbiAqIEBwYXJhbSB7U3RyaW5nfSBwYXNzd29yZCAgcGFzc3dvcmRcbiAqIEByZXR1cm4ge1Byb21pc2U8W0NyeXB0b0tleSwgQ3J5cHRvS2V5XT59IHByb21pc2UgZm9yIFthZXMga2V5LCBobWFjIGtleV1cbiAqL1xuYXN5bmMgZnVuY3Rpb24gZGVyaXZlS2V5cyhzYWx0OiBVaW50OEFycmF5LCBpdGVyYXRpb25zOiBudW1iZXIsIHBhc3N3b3JkOiBzdHJpbmcpOiBQcm9taXNlPFtDcnlwdG9LZXksIENyeXB0b0tleV0+IHtcbiAgICBjb25zdCBzdGFydCA9IG5ldyBEYXRlKCk7XG5cbiAgICBsZXQga2V5O1xuICAgIHRyeSB7XG4gICAgICAgIGtleSA9IGF3YWl0IHN1YnRsZUNyeXB0by5pbXBvcnRLZXkoXCJyYXdcIiwgbmV3IFRleHRFbmNvZGVyKCkuZW5jb2RlKHBhc3N3b3JkKSwgeyBuYW1lOiBcIlBCS0RGMlwiIH0sIGZhbHNlLCBbXG4gICAgICAgICAgICBcImRlcml2ZUJpdHNcIixcbiAgICAgICAgXSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICB0aHJvdyBmcmllbmRseUVycm9yKFwic3VidGxlQ3J5cHRvLmltcG9ydEtleSBmYWlsZWQ6IFwiICsgZSwgY3J5cHRvRmFpbE1zZygpKTtcbiAgICB9XG5cbiAgICBsZXQga2V5Yml0cztcbiAgICB0cnkge1xuICAgICAgICBrZXliaXRzID0gYXdhaXQgc3VidGxlQ3J5cHRvLmRlcml2ZUJpdHMoXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJQQktERjJcIixcbiAgICAgICAgICAgICAgICBzYWx0OiBzYWx0LFxuICAgICAgICAgICAgICAgIGl0ZXJhdGlvbnM6IGl0ZXJhdGlvbnMsXG4gICAgICAgICAgICAgICAgaGFzaDogXCJTSEEtNTEyXCIsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAga2V5LFxuICAgICAgICAgICAgNTEyLFxuICAgICAgICApO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgdGhyb3cgZnJpZW5kbHlFcnJvcihcInN1YnRsZUNyeXB0by5kZXJpdmVCaXRzIGZhaWxlZDogXCIgKyBlLCBjcnlwdG9GYWlsTXNnKCkpO1xuICAgIH1cblxuICAgIGNvbnN0IG5vdyA9IG5ldyBEYXRlKCk7XG4gICAgbG9nZ2VyLmxvZyhcIkUyZSBpbXBvcnQvZXhwb3J0OiBkZXJpdmVLZXlzIHRvb2sgXCIgKyAobm93LmdldFRpbWUoKSAtIHN0YXJ0LmdldFRpbWUoKSkgKyBcIm1zXCIpO1xuXG4gICAgY29uc3QgYWVzS2V5ID0ga2V5Yml0cy5zbGljZSgwLCAzMik7XG4gICAgY29uc3QgaG1hY0tleSA9IGtleWJpdHMuc2xpY2UoMzIpO1xuXG4gICAgY29uc3QgYWVzUHJvbSA9IHN1YnRsZUNyeXB0b1xuICAgICAgICAuaW1wb3J0S2V5KFwicmF3XCIsIGFlc0tleSwgeyBuYW1lOiBcIkFFUy1DVFJcIiB9LCBmYWxzZSwgW1wiZW5jcnlwdFwiLCBcImRlY3J5cHRcIl0pXG4gICAgICAgIC5jYXRjaCgoZSkgPT4ge1xuICAgICAgICAgICAgdGhyb3cgZnJpZW5kbHlFcnJvcihcInN1YnRsZUNyeXB0by5pbXBvcnRLZXkgZmFpbGVkIGZvciBBRVMga2V5OiBcIiArIGUsIGNyeXB0b0ZhaWxNc2coKSk7XG4gICAgICAgIH0pO1xuXG4gICAgY29uc3QgaG1hY1Byb20gPSBzdWJ0bGVDcnlwdG9cbiAgICAgICAgLmltcG9ydEtleShcbiAgICAgICAgICAgIFwicmF3XCIsXG4gICAgICAgICAgICBobWFjS2V5LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiSE1BQ1wiLFxuICAgICAgICAgICAgICAgIGhhc2g6IHsgbmFtZTogXCJTSEEtMjU2XCIgfSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBmYWxzZSxcbiAgICAgICAgICAgIFtcInNpZ25cIiwgXCJ2ZXJpZnlcIl0sXG4gICAgICAgIClcbiAgICAgICAgLmNhdGNoKChlKSA9PiB7XG4gICAgICAgICAgICB0aHJvdyBmcmllbmRseUVycm9yKFwic3VidGxlQ3J5cHRvLmltcG9ydEtleSBmYWlsZWQgZm9yIEhNQUMga2V5OiBcIiArIGUsIGNyeXB0b0ZhaWxNc2coKSk7XG4gICAgICAgIH0pO1xuXG4gICAgcmV0dXJuIFByb21pc2UuYWxsKFthZXNQcm9tLCBobWFjUHJvbV0pO1xufVxuXG5jb25zdCBIRUFERVJfTElORSA9IFwiLS0tLS1CRUdJTiBNRUdPTE0gU0VTU0lPTiBEQVRBLS0tLS1cIjtcbmNvbnN0IFRSQUlMRVJfTElORSA9IFwiLS0tLS1FTkQgTUVHT0xNIFNFU1NJT04gREFUQS0tLS0tXCI7XG5cbi8qKlxuICogVW5iYXNlNjQgYW4gYXNjaWktYXJtb3VyZWQgbWVnb2xtIGtleSBmaWxlXG4gKlxuICogU3RyaXBzIHRoZSBoZWFkZXIgYW5kIHRyYWlsZXIgbGluZXMsIGFuZCB1bmJhc2U2NHMgdGhlIGNvbnRlbnRcbiAqXG4gKiBAcGFyYW0ge0FycmF5QnVmZmVyfSBkYXRhICBpbnB1dCBmaWxlXG4gKiBAcmV0dXJuIHtVaW50OEFycmF5fSB1bmJhc2U2NGVkIGNvbnRlbnRcbiAqL1xuZnVuY3Rpb24gdW5wYWNrTWVnb2xtS2V5RmlsZShkYXRhOiBBcnJheUJ1ZmZlcik6IFVpbnQ4QXJyYXkge1xuICAgIC8vIHBhcnNlIHRoZSBmaWxlIGFzIGEgZ3JlYXQgYmlnIFN0cmluZy4gVGhpcyBzaG91bGQgYmUgc2FmZSwgYmVjYXVzZSB0aGVyZVxuICAgIC8vIHNob3VsZCBiZSBubyBub24tQVNDSUkgY2hhcmFjdGVycywgYW5kIGl0IG1lYW5zIHRoYXQgd2UgY2FuIGRvIHN0cmluZ1xuICAgIC8vIGNvbXBhcmlzb25zIHRvIGZpbmQgdGhlIGhlYWRlciBhbmQgZm9vdGVyLCBhbmQgZmVlZCBpdCBpbnRvIHdpbmRvdy5hdG9iLlxuICAgIGNvbnN0IGZpbGVTdHIgPSBuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUobmV3IFVpbnQ4QXJyYXkoZGF0YSkpO1xuXG4gICAgLy8gbG9vayBmb3IgdGhlIHN0YXJ0IGxpbmVcbiAgICBsZXQgbGluZVN0YXJ0ID0gMDtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tY29uc3RhbnQtY29uZGl0aW9uXG4gICAgd2hpbGUgKDEpIHtcbiAgICAgICAgY29uc3QgbGluZUVuZCA9IGZpbGVTdHIuaW5kZXhPZihcIlxcblwiLCBsaW5lU3RhcnQpO1xuICAgICAgICBpZiAobGluZUVuZCA8IDApIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkhlYWRlciBsaW5lIG5vdCBmb3VuZFwiKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBsaW5lID0gZmlsZVN0ci5zbGljZShsaW5lU3RhcnQsIGxpbmVFbmQpLnRyaW0oKTtcblxuICAgICAgICAvLyBzdGFydCB0aGUgbmV4dCBsaW5lIGFmdGVyIHRoZSBuZXdsaW5lXG4gICAgICAgIGxpbmVTdGFydCA9IGxpbmVFbmQgKyAxO1xuXG4gICAgICAgIGlmIChsaW5lID09PSBIRUFERVJfTElORSkge1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBkYXRhU3RhcnQgPSBsaW5lU3RhcnQ7XG5cbiAgICAvLyBsb29rIGZvciB0aGUgZW5kIGxpbmVcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tY29uc3RhbnQtY29uZGl0aW9uXG4gICAgd2hpbGUgKDEpIHtcbiAgICAgICAgY29uc3QgbGluZUVuZCA9IGZpbGVTdHIuaW5kZXhPZihcIlxcblwiLCBsaW5lU3RhcnQpO1xuICAgICAgICBjb25zdCBsaW5lID0gZmlsZVN0ci5zbGljZShsaW5lU3RhcnQsIGxpbmVFbmQgPCAwID8gdW5kZWZpbmVkIDogbGluZUVuZCkudHJpbSgpO1xuICAgICAgICBpZiAobGluZSA9PT0gVFJBSUxFUl9MSU5FKSB7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChsaW5lRW5kIDwgMCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVHJhaWxlciBsaW5lIG5vdCBmb3VuZFwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHN0YXJ0IHRoZSBuZXh0IGxpbmUgYWZ0ZXIgdGhlIG5ld2xpbmVcbiAgICAgICAgbGluZVN0YXJ0ID0gbGluZUVuZCArIDE7XG4gICAgfVxuXG4gICAgY29uc3QgZGF0YUVuZCA9IGxpbmVTdGFydDtcbiAgICByZXR1cm4gZGVjb2RlQmFzZTY0KGZpbGVTdHIuc2xpY2UoZGF0YVN0YXJ0LCBkYXRhRW5kKSk7XG59XG5cbi8qKlxuICogYXNjaWktYXJtb3VyIGEgIG1lZ29sbSBrZXkgZmlsZVxuICpcbiAqIGJhc2U2NHMgdGhlIGNvbnRlbnQsIGFuZCBhZGRzIGhlYWRlciBhbmQgdHJhaWxlciBsaW5lc1xuICpcbiAqIEBwYXJhbSB7VWludDhBcnJheX0gZGF0YSAgcmF3IGRhdGFcbiAqIEByZXR1cm4ge0FycmF5QnVmZmVyfSBmb3JtYXR0ZWQgZmlsZVxuICovXG5mdW5jdGlvbiBwYWNrTWVnb2xtS2V5RmlsZShkYXRhOiBVaW50OEFycmF5KTogQXJyYXlCdWZmZXIge1xuICAgIC8vIHdlIHNwbGl0IGludG8gbGluZXMgYmVmb3JlIGJhc2U2NGluZywgYmVjYXVzZSBlbmNvZGVCYXNlNjQgZG9lc24ndCBkZWFsXG4gICAgLy8gdGVycmlibHkgd2VsbCB3aXRoIGxhcmdlIGFycmF5cy5cbiAgICBjb25zdCBMSU5FX0xFTkdUSCA9ICg3MiAqIDQpIC8gMztcbiAgICBjb25zdCBuTGluZXMgPSBNYXRoLmNlaWwoZGF0YS5sZW5ndGggLyBMSU5FX0xFTkdUSCk7XG4gICAgY29uc3QgbGluZXMgPSBuZXcgQXJyYXkobkxpbmVzICsgMyk7XG4gICAgbGluZXNbMF0gPSBIRUFERVJfTElORTtcbiAgICBsZXQgbyA9IDA7XG4gICAgbGV0IGk7XG4gICAgZm9yIChpID0gMTsgaSA8PSBuTGluZXM7IGkrKykge1xuICAgICAgICBsaW5lc1tpXSA9IGVuY29kZUJhc2U2NChkYXRhLnN1YmFycmF5KG8sIG8gKyBMSU5FX0xFTkdUSCkpO1xuICAgICAgICBvICs9IExJTkVfTEVOR1RIO1xuICAgIH1cbiAgICBsaW5lc1tpKytdID0gVFJBSUxFUl9MSU5FO1xuICAgIGxpbmVzW2ldID0gXCJcIjtcbiAgICByZXR1cm4gbmV3IFRleHRFbmNvZGVyKCkuZW5jb2RlKGxpbmVzLmpvaW4oXCJcXG5cIikpLmJ1ZmZlcjtcbn1cblxuLyoqXG4gKiBFbmNvZGUgYSB0eXBlZCBhcnJheSBvZiB1aW50OCBhcyBiYXNlNjQuXG4gKiBAcGFyYW0ge1VpbnQ4QXJyYXl9IHVpbnQ4QXJyYXkgVGhlIGRhdGEgdG8gZW5jb2RlLlxuICogQHJldHVybiB7c3RyaW5nfSBUaGUgYmFzZTY0LlxuICovXG5mdW5jdGlvbiBlbmNvZGVCYXNlNjQodWludDhBcnJheTogVWludDhBcnJheSk6IHN0cmluZyB7XG4gICAgLy8gTWlzaW50ZXJwdCB0aGUgVWludDhBcnJheSBhcyBMYXRpbi0xLlxuICAgIC8vIHdpbmRvdy5idG9hIGV4cGVjdHMgYSB1bmljb2RlIHN0cmluZyB3aXRoIGNvZGVwb2ludHMgaW4gdGhlIHJhbmdlIDAtMjU1LlxuICAgIGNvbnN0IGxhdGluMVN0cmluZyA9IFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkobnVsbCwgQXJyYXkuZnJvbSh1aW50OEFycmF5KSk7XG4gICAgLy8gVXNlIHRoZSBidWlsdGluIGJhc2U2NCBlbmNvZGVyLlxuICAgIHJldHVybiB3aW5kb3cuYnRvYShsYXRpbjFTdHJpbmcpO1xufVxuXG4vKipcbiAqIERlY29kZSBhIGJhc2U2NCBzdHJpbmcgdG8gYSB0eXBlZCBhcnJheSBvZiB1aW50OC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBiYXNlNjQgVGhlIGJhc2U2NCB0byBkZWNvZGUuXG4gKiBAcmV0dXJuIHtVaW50OEFycmF5fSBUaGUgZGVjb2RlZCBkYXRhLlxuICovXG5mdW5jdGlvbiBkZWNvZGVCYXNlNjQoYmFzZTY0OiBzdHJpbmcpOiBVaW50OEFycmF5IHtcbiAgICAvLyB3aW5kb3cuYXRvYiByZXR1cm5zIGEgdW5pY29kZSBzdHJpbmcgd2l0aCBjb2RlcG9pbnRzIGluIHRoZSByYW5nZSAwLTI1NS5cbiAgICBjb25zdCBsYXRpbjFTdHJpbmcgPSB3aW5kb3cuYXRvYihiYXNlNjQpO1xuICAgIC8vIEVuY29kZSB0aGUgc3RyaW5nIGFzIGEgVWludDhBcnJheVxuICAgIGNvbnN0IHVpbnQ4QXJyYXkgPSBuZXcgVWludDhBcnJheShsYXRpbjFTdHJpbmcubGVuZ3RoKTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGxhdGluMVN0cmluZy5sZW5ndGg7IGkrKykge1xuICAgICAgICB1aW50OEFycmF5W2ldID0gbGF0aW4xU3RyaW5nLmNoYXJDb2RlQXQoaSk7XG4gICAgfVxuICAgIHJldHVybiB1aW50OEFycmF5O1xufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7OztBQVNBLElBQUFBLE9BQUEsR0FBQUMsT0FBQTtBQUVBLElBQUFDLGdCQUFBLEdBQUFELE9BQUE7QUFDQSxJQUFBRSxVQUFBLEdBQUFDLHNCQUFBLENBQUFILE9BQUE7QUFaQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQU9BLE1BQU1JLFlBQVksR0FBR0MsTUFBTSxDQUFDQyxNQUFNLENBQUNDLE1BQU07O0FBRXpDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTQyxhQUFhQSxDQUFDQyxPQUFlLEVBQUVDLFlBQW9CLEVBQTZDO0VBQ3JHLE9BQU87SUFBRUQsT0FBTztJQUFFQztFQUFhLENBQUM7QUFDcEM7QUFFQSxTQUFTQyxhQUFhQSxDQUFBLEVBQVc7RUFDN0IsT0FBTyxJQUFBQyxtQkFBRSxFQUFDLCtCQUErQixDQUFDO0FBQzlDOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNPLGVBQWVDLG9CQUFvQkEsQ0FBQ0MsSUFBaUIsRUFBRUMsUUFBZ0IsRUFBbUI7RUFDN0YsTUFBTUMsSUFBSSxHQUFHQyxtQkFBbUIsQ0FBQ0gsSUFBSSxDQUFDO0VBQ3RDLE1BQU1JLEtBQUssR0FBR0Msa0JBQVMsQ0FBQ0MsR0FBRyxDQUFDLENBQUMs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