bitgo
Version:
BitGo JavaScript SDK
358 lines • 68.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const assert = require("assert");
const nock = require("nock");
const openpgp = require("openpgp");
const sdk_test_1 = require("@bitgo/sdk-test");
const sdk_core_1 = require("@bitgo/sdk-core");
const sdk_lib_mpc_1 = require("@bitgo/sdk-lib-mpc");
const src_1 = require("../../../../../../src");
const MPCv2PartiesEnum = sdk_core_1.ECDSAUtils.MPCv2PartiesEnum;
describe('TSS EdDSA MPCv2 Utils:', async function () {
const coinName = 'sol';
const walletId = '5b34252f1bf349930e34020a00000000';
const enterpriseId = '6449153a6f6bc20006d66771cdbe15d3';
let bgUrl;
let tssUtils;
let wallet;
let bitgo;
let baseCoin;
let bitgoGpgKeyPair;
let bitgoPrvKeyObj;
let constants;
beforeEach(async function () {
nock.cleanAll();
await nockGetBitgoPublicKeyBasedOnFeatureFlags(coinName, enterpriseId, bitgoGpgKeyPair);
nock(bgUrl).get('/api/v1/client/constants').times(10).reply(200, { ttl: 3600, constants });
});
before(async function () {
openpgp.config.rejectCurves = new Set();
bitgoGpgKeyPair = await openpgp.generateKey({
userIDs: [{ name: 'bitgo', email: 'bitgo@test.com' }],
curve: 'ed25519',
format: 'armored',
});
bitgoPrvKeyObj = await openpgp.readPrivateKey({ armoredKey: bitgoGpgKeyPair.privateKey });
constants = {
mpc: {
bitgoPublicKey: bitgoGpgKeyPair.publicKey,
bitgoMPCv2PublicKey: bitgoGpgKeyPair.publicKey,
},
};
bitgo = sdk_test_1.TestBitGo.decorate(src_1.BitGo, { env: 'mock' });
bitgo.initializeTestVars();
baseCoin = bitgo.coin(coinName);
bgUrl = sdk_core_1.common.Environments[bitgo.getEnv()].uri;
const walletData = {
id: walletId,
enterprise: enterpriseId,
coin: coinName,
coinSpecific: {},
multisigType: 'tss',
};
wallet = new sdk_core_1.Wallet(bitgo, baseCoin, walletData);
tssUtils = new sdk_core_1.EDDSAUtils.EddsaMPCv2Utils(bitgo, baseCoin, wallet);
});
after(function () {
nock.cleanAll();
});
describe('TSS key chains', async function () {
it('should generate TSS MPS keys', async function () {
const bitgoSession = new sdk_lib_mpc_1.EddsaMPSDkg.DKG(3, 2, 2);
const bitgoState = {};
const round1Nock = await nockMPSKeyGenRound1(bitgoSession, bitgoState, 1);
const round2Nock = await nockMPSKeyGenRound2(bitgoSession, bitgoState, 1);
const addKeyNock = await nockAddKeyChain(coinName, 3);
const params = {
passphrase: 'test',
enterprise: enterpriseId,
originalPasscodeEncryptionCode: '123456',
};
const { userKeychain, backupKeychain, bitgoKeychain } = await tssUtils.createKeychains(params);
assert.ok(round1Nock.isDone());
assert.ok(round2Nock.isDone());
assert.ok(addKeyNock.isDone());
assert.ok(userKeychain);
assert.equal(userKeychain.source, 'user');
assert.ok(userKeychain.commonKeychain);
assert.ok(userKeychain.encryptedPrv);
assert.ok(bitgo.decrypt({ input: userKeychain.encryptedPrv, password: params.passphrase }));
assert.ok(backupKeychain);
assert.equal(backupKeychain.source, 'backup');
assert.ok(backupKeychain.commonKeychain);
assert.ok(backupKeychain.encryptedPrv);
assert.ok(bitgo.decrypt({ input: backupKeychain.encryptedPrv, password: params.passphrase }));
assert.ok(bitgoKeychain);
assert.equal(bitgoKeychain.source, 'bitgo');
assert.ok(bitgoKeychain.commonKeychain);
assert.equal(userKeychain.commonKeychain, backupKeychain.commonKeychain);
assert.equal(userKeychain.commonKeychain, bitgoKeychain.commonKeychain);
});
it('should send webauthnInfo (with enterpriseId) on the user keychain when webauthnInfo is provided', async function () {
const commonKeychain = 'a'.repeat(64);
const capturedBodies = {};
const addKeyNock = nock('https://bitgo.fakeurl')
.post(`/api/v2/${coinName}/key`, (body) => body.keyType === 'tss' && body.isMPCv2)
.times(1)
.reply(200, async (uri, requestBody) => {
capturedBodies[requestBody.source] = requestBody;
return {
id: requestBody.source,
source: requestBody.source,
type: requestBody.keyType,
commonKeychain: requestBody.commonKeychain,
encryptedPrv: requestBody.encryptedPrv,
};
});
const webauthnInfo = { otpDeviceId: 'device-123', prfSalt: 'salt-abc', passphrase: 'prf-derived-passphrase' };
// Direct participant-keychain call avoids the EdDSA DKG ceremony while still exercising the
// user-keychain webauthn assembly that POSTs to /key.
await tssUtils.createParticipantKeychain(MPCv2PartiesEnum.USER, commonKeychain, Buffer.from('userPrivate'), Buffer.from('userReduced'), 'passphrase', undefined, webauthnInfo, undefined, enterpriseId);
assert.ok(addKeyNock.isDone());
// User keychain must carry webauthnInfo (the field the backend POST /key consumes), including
// enterpriseId, and must NOT use the deprecated webauthnDevices array.
const userBody = capturedBodies['user'];
assert.ok(userBody, 'user keychain should have been created');
assert.ok(userBody.webauthnInfo, 'user keychain body should include webauthnInfo');
assert.equal(userBody.webauthnInfo.otpDeviceId, webauthnInfo.otpDeviceId);
assert.equal(userBody.webauthnInfo.prfSalt, webauthnInfo.prfSalt);
assert.equal(userBody.webauthnInfo.enterpriseId, enterpriseId);
assert.ok(userBody.webauthnInfo.encryptedPrv, 'encryptedPrv should be set');
assert.ok(bitgo.decrypt({ input: userBody.webauthnInfo.encryptedPrv, password: webauthnInfo.passphrase }));
assert.strictEqual(userBody.webauthnDevices, undefined, 'deprecated webauthnDevices should not be sent');
});
it('should create TSS key chains', async function () {
const fakeCommonKeychain = 'a'.repeat(64);
const nockPromises = [
nockKeychain({
coin: coinName,
keyChain: { id: '1', pub: '1', type: 'tss', source: 'user', reducedEncryptedPrv: '' },
source: 'user',
}),
nockKeychain({
coin: coinName,
keyChain: { id: '2', pub: '2', type: 'tss', source: 'backup', reducedEncryptedPrv: '' },
source: 'backup',
}),
nockKeychain({
coin: coinName,
keyChain: { id: '3', pub: '3', type: 'tss', source: 'bitgo', reducedEncryptedPrv: '' },
source: 'bitgo',
}),
];
const [nockedUserKeychain, nockedBackupKeychain, nockedBitGoKeychain] = await Promise.all(nockPromises);
const [userKeychain, backupKeychain, bitgoKeychain] = await Promise.all([
tssUtils.createParticipantKeychain(MPCv2PartiesEnum.USER, fakeCommonKeychain, Buffer.from('userPrivate'), Buffer.from('userReduced'), 'passphrase'),
tssUtils.createParticipantKeychain(MPCv2PartiesEnum.BACKUP, fakeCommonKeychain, Buffer.from('backupPrivate'), Buffer.from('backupReduced'), 'passphrase'),
tssUtils.createParticipantKeychain(MPCv2PartiesEnum.BITGO, fakeCommonKeychain),
]);
assert.ok(userKeychain);
assert.equal(bitgoKeychain.source, 'bitgo');
assert.equal(userKeychain.id, nockedUserKeychain.id);
assert.equal(backupKeychain.id, nockedBackupKeychain.id);
assert.equal(bitgoKeychain.id, nockedBitGoKeychain.id);
({ ...userKeychain, reducedEncryptedPrv: '' }).should.deepEqual(nockedUserKeychain);
({ ...backupKeychain, reducedEncryptedPrv: '' }).should.deepEqual(nockedBackupKeychain);
({ ...bitgoKeychain, reducedEncryptedPrv: '' }).should.deepEqual(nockedBitGoKeychain);
// reducedEncryptedPrv must round-trip: decrypting with the passphrase should recover
// the browser-safe btoa encoding of the original reduced private material.
const encodeReduced = (buf) => btoa(String.fromCharCode.apply(null, Array.from(new Uint8Array(buf))));
assert.ok(userKeychain.reducedEncryptedPrv);
assert.equal(bitgo.decrypt({ input: userKeychain.reducedEncryptedPrv, password: 'passphrase' }), encodeReduced(Buffer.from('userReduced')));
assert.ok(backupKeychain.reducedEncryptedPrv);
assert.equal(bitgo.decrypt({ input: backupKeychain.reducedEncryptedPrv, password: 'passphrase' }), encodeReduced(Buffer.from('backupReduced')));
});
it('should reject when BitGo PGP signature on round 1 response is invalid', async function () {
nock(bgUrl)
.post('/api/v2/mpc/generatekey', (body) => body.round === 'MPCv2-R1')
.once()
.reply(200, {
sessionId: 'bad-session',
bitgoMsg1: {
message: Buffer.from('garbage').toString('base64'),
signature: '-----BEGIN PGP SIGNATURE-----\nFAKE\n-----END PGP SIGNATURE-----',
},
});
await assert.rejects(tssUtils.createKeychains({ passphrase: 'test', enterprise: enterpriseId }));
});
it('should reject when BitGo PGP signature on round 2 response is invalid', async function () {
const bitgoSession = new sdk_lib_mpc_1.EddsaMPSDkg.DKG(3, 2, 2);
const bitgoState = {};
await nockMPSKeyGenRound1(bitgoSession, bitgoState, 1);
nock(bgUrl)
.post('/api/v2/mpc/generatekey', (body) => body.round === 'MPCv2-R2')
.once()
.reply(200, {
sessionId: 'test-session-id',
commonPublicKeychain: 'a'.repeat(128),
bitgoMsg2: {
message: Buffer.from('garbage').toString('base64'),
signature: '-----BEGIN PGP SIGNATURE-----\nFAKE\n-----END PGP SIGNATURE-----',
},
});
await assert.rejects(tssUtils.createKeychains({ passphrase: 'test', enterprise: enterpriseId }));
});
it('should reject when session IDs from round 1 and round 2 do not match', async function () {
const bitgoSession = new sdk_lib_mpc_1.EddsaMPSDkg.DKG(3, 2, 2);
const bitgoState = {};
await nockMPSKeyGenRound1(bitgoSession, bitgoState, 1);
nock(bgUrl)
.post('/api/v2/mpc/generatekey', (body) => body.round === 'MPCv2-R2')
.once()
.reply(200, {
sessionId: 'different-session-id',
commonPublicKeychain: 'a'.repeat(128),
bitgoMsg2: { message: '', signature: '' },
});
await assert.rejects(tssUtils.createKeychains({ passphrase: 'test', enterprise: enterpriseId }), /Round 1 and round 2 session IDs do not match/);
});
it('should reject when commonPublicKeychain from BitGo does not match the locally computed keychain', async function () {
const bitgoSession = new sdk_lib_mpc_1.EddsaMPSDkg.DKG(3, 2, 2);
const bitgoState = {};
await nockMPSKeyGenRound1(bitgoSession, bitgoState, 1);
nock(bgUrl)
.post('/api/v2/mpc/generatekey', (body) => body.round === 'MPCv2-R2')
.once()
.reply(200, async (_uri, { payload }) => {
const { userMsg2, backupMsg2 } = payload;
assert.ok(bitgoState.msg2, 'BitGo round-2 message missing — round-1 nock must run first');
const userDeserMsg2 = {
from: 0,
payload: new Uint8Array(Buffer.from(userMsg2.message, 'base64')),
};
const backupDeserMsg2 = {
from: 1,
payload: new Uint8Array(Buffer.from(backupMsg2.message, 'base64')),
};
bitgoSession.handleIncomingMessages([userDeserMsg2, backupDeserMsg2, bitgoState.msg2]);
return {
sessionId: 'test-session-id',
commonPublicKeychain: 'fakefakeee'.repeat(16), // mutated — will not match user/backup computed keychain
bitgoMsg2: await sdk_lib_mpc_1.MPSComms.detachSignMpsMessage(Buffer.from(bitgoState.msg2.payload), bitgoPrvKeyObj),
};
});
await assert.rejects(tssUtils.createKeychains({ passphrase: 'test', enterprise: enterpriseId }), /does not match BitGo common keychain/);
});
it('should reject when BitGo GPG public key does not match known keys in prod/test envs', async function () {
// Use a staging env so envRequiresBitgoPubGpgKeyConfig returns true
const stagingBitgo = sdk_test_1.TestBitGo.decorate(src_1.BitGo, { env: 'staging' });
stagingBitgo.initializeTestVars();
const stagingBaseCoin = stagingBitgo.coin(coinName);
const stagingBgUrl = sdk_core_1.common.Environments[stagingBitgo.getEnv()].uri;
const stagingWallet = new sdk_core_1.Wallet(stagingBitgo, stagingBaseCoin, {
id: walletId,
enterprise: enterpriseId,
coin: coinName,
coinSpecific: {},
multisigType: 'tss',
});
const stagingTssUtils = new sdk_core_1.EDDSAUtils.EddsaMPCv2Utils(stagingBitgo, stagingBaseCoin, stagingWallet);
// Return a key that is NOT in the hardcoded BitGo MPC v2 key list
nock(stagingBgUrl).get(`/api/v2/${coinName}/tss/pubkey`).query({ enterpriseId }).reply(200, {
name: 'irrelevant',
publicKey: bitgoGpgKeyPair.publicKey,
mpcv2PublicKey: bitgoGpgKeyPair.publicKey,
eddsaMpcv2PublicKey: bitgoGpgKeyPair.publicKey,
enterpriseId,
});
nock(stagingBgUrl).get('/api/v1/client/constants').reply(200, { ttl: 3600, constants });
await assert.rejects(stagingTssUtils.createKeychains({ passphrase: 'test', enterprise: enterpriseId }), /Invalid BitGo GPG public key/);
});
});
// ---------------------------------------------------------------------------
// Nock helpers
// ---------------------------------------------------------------------------
async function nockGetBitgoPublicKeyBasedOnFeatureFlags(coin, enterprise, bitgoKeyPair) {
const response = {
name: 'irrelevant',
publicKey: bitgoKeyPair.publicKey,
mpcv2PublicKey: bitgoKeyPair.publicKey,
eddsaMpcv2PublicKey: bitgoKeyPair.publicKey,
enterpriseId: enterprise,
};
nock(bgUrl).get(`/api/v2/${coin}/tss/pubkey`).query({ enterpriseId: enterprise }).reply(200, response);
return response;
}
async function nockMPSKeyGenRound1(bitgoSession, bitgoState, times = 1) {
return nock(bgUrl)
.post('/api/v2/mpc/generatekey', (body) => body.round === 'MPCv2-R1')
.times(times)
.reply(200, async (_uri, { payload }) => {
const { userGpgPublicKey, backupGpgPublicKey, userMsg1, backupMsg1 } = payload;
openpgp.config.rejectCurves = new Set();
const userPubKeyObj = await openpgp.readKey({ armoredKey: userGpgPublicKey });
const backupPubKeyObj = await openpgp.readKey({ armoredKey: backupGpgPublicKey });
const userPk = await sdk_lib_mpc_1.MPSComms.extractEd25519PublicKey(userPubKeyObj);
const backupPk = await sdk_lib_mpc_1.MPSComms.extractEd25519PublicKey(backupPubKeyObj);
const [, bitgoSk] = await sdk_lib_mpc_1.MPSComms.extractEd25519KeyPair(bitgoPrvKeyObj);
bitgoSession.initDkg(bitgoSk, [userPk, backupPk]);
const bitgoRawMsg1 = bitgoSession.getFirstMessage();
await sdk_lib_mpc_1.MPSComms.verifyMpsMessage(userMsg1, userPubKeyObj);
await sdk_lib_mpc_1.MPSComms.verifyMpsMessage(backupMsg1, backupPubKeyObj);
// Process all 3 round-1 messages (including BitGo's own) to advance state and produce bitgoMsg2
const userDeserMsg1 = {
from: 0,
payload: new Uint8Array(Buffer.from(userMsg1.message, 'base64')),
};
const backupDeserMsg1 = {
from: 1,
payload: new Uint8Array(Buffer.from(backupMsg1.message, 'base64')),
};
const [bitgoRawMsg2] = bitgoSession.handleIncomingMessages([userDeserMsg1, backupDeserMsg1, bitgoRawMsg1]);
bitgoState.msg2 = bitgoRawMsg2;
return {
sessionId: 'test-session-id',
bitgoMsg1: await sdk_lib_mpc_1.MPSComms.detachSignMpsMessage(Buffer.from(bitgoRawMsg1.payload), bitgoPrvKeyObj),
};
});
}
async function nockMPSKeyGenRound2(bitgoSession, bitgoState, times = 1) {
return nock(bgUrl)
.post('/api/v2/mpc/generatekey', (body) => body.round === 'MPCv2-R2')
.times(times)
.reply(200, async (_uri, { payload }) => {
const { sessionId, userMsg2, backupMsg2 } = payload;
openpgp.config.rejectCurves = new Set();
assert.ok(bitgoState.msg2, 'BitGo round-2 message missing — round-1 nock must run first');
const userDeserMsg2 = {
from: 0,
payload: new Uint8Array(Buffer.from(userMsg2.message, 'base64')),
};
const backupDeserMsg2 = {
from: 1,
payload: new Uint8Array(Buffer.from(backupMsg2.message, 'base64')),
};
// Complete DKG with all 3 round-2 messages (user, backup, and BitGo's own msg2)
bitgoSession.handleIncomingMessages([userDeserMsg2, backupDeserMsg2, bitgoState.msg2]);
return {
sessionId,
commonPublicKeychain: bitgoSession.getCommonKeychain(),
bitgoMsg2: await sdk_lib_mpc_1.MPSComms.detachSignMpsMessage(Buffer.from(bitgoState.msg2.payload), bitgoPrvKeyObj),
};
});
}
async function nockKeychain(params, times = 1) {
nock(bgUrl)
.post(`/api/v2/${params.coin}/key`, (body) => body.keyType === 'tss' && body.source === params.source)
.times(times)
.reply(200, params.keyChain);
return params.keyChain;
}
async function nockAddKeyChain(coin, times = 1) {
return nock(bgUrl)
.post(`/api/v2/${coin}/key`, (body) => body.keyType === 'tss' && body.isMPCv2)
.times(times)
.reply(200, async (_uri, requestBody) => {
const key = {
id: requestBody.source,
source: requestBody.source,
type: requestBody.keyType,
commonKeychain: requestBody.commonKeychain,
encryptedPrv: requestBody.encryptedPrv,
};
nock(bgUrl).get(`/api/v2/${coin}/key/${requestBody.source}`).reply(200, key);
return key;
});
}
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlS2V5Y2hhaW5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vdGVzdC92Mi91bml0L2ludGVybmFsL3Rzc1V0aWxzL2VkZHNhTVBDdjIvY3JlYXRlS2V5Y2hhaW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsaUNBQWlDO0FBQ2pDLDZCQUE4QjtBQUM5QixtQ0FBbUM7QUFHbkMsOENBQXdEO0FBQ3hELDhDQUFpSDtBQUNqSCxvREFBcUU7QUFDckUsK0NBQWlFO0FBRWpFLE1BQU0sZ0JBQWdCLEdBQUcscUJBQVUsQ0FBQyxnQkFBZ0IsQ0FBQztBQUVyRCxRQUFRLENBQUMsd0JBQXdCLEVBQUUsS0FBSztJQUN0QyxNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUM7SUFDdkIsTUFBTSxRQUFRLEdBQUcsa0NBQWtDLENBQUM7SUFDcEQsTUFBTSxZQUFZLEdBQUcsa0NBQWtDLENBQUM7SUFFeEQsSUFBSSxLQUFhLENBQUM7SUFDbEIsSUFBSSxRQUFvQyxDQUFDO0lBQ3pDLElBQUksTUFBYyxDQUFDO0lBQ25CLElBQUksS0FBeUIsQ0FBQztJQUM5QixJQUFJLFFBQWtCLENBQUM7SUFFdkIsSUFBSSxlQUFzRixDQUFDO0lBQzNGLElBQUksY0FBa0MsQ0FBQztJQUN2QyxJQUFJLFNBQTJFLENBQUM7SUFFaEYsVUFBVSxDQUFDLEtBQUs7UUFDZCxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDaEIsTUFBTSx3Q0FBd0MsQ0FBQyxRQUFRLEVBQUUsWUFBWSxFQUFFLGVBQWUsQ0FBQyxDQUFDO1FBQ3hGLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUMsMEJBQTBCLENBQUMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQztJQUM3RixDQUFDLENBQUMsQ0FBQztJQUVI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LENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQ3hCLE1BQU0sQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztZQUMxQyxNQUFNLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUN2QyxNQUFNLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUNyQyxNQUFNLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsRUFBRSxLQUFLLEVBQUUsWUFBWSxDQUFDLFlBQVksRUFBRSxRQUFRLEVBQUUsTUFBTSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUU1RixNQUFNLENBQUMsRUFBRSxDQUFDLGNBQWMsQ0FBQyxDQUFDO1lBQzFCLE1BQU0sQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLE1BQU0sRUFBRSxRQUFRLENBQUMsQ0FBQztZQUM5QyxNQUFNLENBQUMsRUFBRSxDQUFDLGNBQWMsQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUN6QyxNQUFNLENBQUMsRUFBRSxDQUFDLGNBQWMsQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUN2QyxNQUFNLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsRUFBRSxLQUFLLEVBQUUsY0FBYyxDQUFDLFlBQVksRUFBRSxRQUFRLEVBQUUsTUFBTSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUU5RixNQUFNLENBQUMsRUFBRSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1lBQ3pCLE1BQU0sQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQztZQUM1QyxNQUFNLENBQUMsRUFBRSxDQUFDLGFBQWEsQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUV4QyxNQUFNLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxjQUFjLEVBQUUsY0FBYyxDQUFDLGNBQWMsQ0FBQyxDQUFDO1lBQ3pFLE1BQU0sQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLGNBQWMsRUFBRSxhQUFhLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDMUUsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsaUdBQWlHLEVBQUUsS0FBSztZQUN6RyxNQUFNLGNBQWMsR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ3RDLE1BQU0sY0FBYyxHQUF1QyxFQUFFLENBQUM7WUFDOUQsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLHVCQUF1QixDQUFDO2lCQUM3QyxJQUFJLENBQUMsV0FBVyxRQUFRLE1BQU0sRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLE9BQU8sS0FBSyxLQUFLLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQztpQkFDakYsS0FBSyxDQUFDLENBQUMsQ0FBQztpQkFDUixLQUFLLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsV0FBK0IsRUFBRSxFQUFFO2dCQUN6RCxjQUFjLENBQUMsV0FBVyxDQUFDLE1BQWdCLENBQUMsR0FBRyxXQUFXLENBQUM7Z0JBQzNELE9BQU87b0JBQ0wsRUFBRSxFQUFFLFdBQVcsQ0FBQyxNQUFNO29CQUN0QixNQUFNLEVBQUUsV0FBVyxDQUFDLE1BQU07b0JBQzFCLElBQUksRUFBRSxXQUFXLENBQUMsT0FBTztvQkFDekIsY0FBYyxFQUFFLFdBQVcsQ0FBQyxjQUFjO29CQUMxQyxZQUFZLEVBQUUsV0FBVyxDQUFDLFlBQVk7aUJBQ3ZDLENBQUM7WUFDSixDQUFDLENBQUMsQ0FBQztZQUVMLE1BQU0sWUFBWSxHQUFHLEVBQUUsV0FBVyxFQUFFLFlBQVksRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBRSx3QkFBd0IsRUFBRSxDQUFDO1lBQzlHLDRGQUE0RjtZQUM1RixzREFBc0Q7WUFDdEQsTUFBTSxRQUFRLENBQUMseUJBQXlCLENBQ3RDLGdCQUFnQixDQUFDLElBQUksRUFDckIsY0FBYyxFQUNkLE1BQU0sQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLEVBQzFCLE1BQU0sQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLEVBQzFCLFlBQVksRUFDWixTQUFTLEVBQ1QsWUFBWSxFQUNaLFNBQVMsRUFDVCxZQUFZLENBQ2IsQ0FBQztZQUNGLE1BQU0sQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7WUFFL0IsOEZBQThGO1lBQzlGLHVFQUF1RTtZQUN2RSxNQUFNLFFBQVEsR0FBRyxjQUFjLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDeEMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxRQUFRLEVBQUUsd0NBQXdDLENBQUMsQ0FBQztZQUM5RCxNQUFNLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxZQUFZLEVBQUUsZ0RBQWdELENBQUMsQ0FBQztZQUNuRixNQUFNLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsV0FBVyxFQUFFLFlBQVksQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUMxRSxNQUFNLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsT0FBTyxFQUFFLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNsRSxNQUFNLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsWUFBWSxFQUFFLFlBQVksQ0FBQyxDQUFDO1lBQy9ELE1BQU0sQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxZQUFZLEVBQUUsNEJBQTRCLENBQUMsQ0FBQztZQUM1RSxNQUFNLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsRUFBRSxLQUFLLEVBQUUsUUFBUSxDQUFDLFlBQVksQ0FBQyxZQUFZLEVBQUUsUUFBUSxFQUFFLFlBQVksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDM0csTUFBTSxDQUFDLFdBQVcsQ0FBQyxRQUFRLENBQUMsZUFBZSxFQUFFLFNBQVMsRUFBRSwrQ0FBK0MsQ0FBQyxDQUFDO1FBQzNHLENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLDhCQUE4QixFQUFFLEtBQUs7WUFDdEMsTUFBTSxrQkFBa0IsR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBRTFDLE1BQU0sWUFBWSxHQUFHO2dCQUNuQixZQUFZLENBQUM7b0JBQ1gsSUFBSSxFQUFFLFFBQVE7b0JBQ2QsUUFBUSxFQUFFLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxtQkFBbUIsRUFBRSxFQUFFLEVBQUU7b0JBQ3JGLE1BQU0sRUFBRSxNQUFNO2lCQUNmLENBQUM7Z0JBQ0YsWUFBWSxDQUFDO29CQUNYLElBQUksRUFBRSxRQUFRO29CQUNkLFFBQVEsRUFBRSxFQUFFLEVBQUUsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsbUJBQW1CLEVBQUUsRUFBRSxFQUFFO29CQUN2RixNQUFNLEVBQUUsUUFBUTtpQkFDakIsQ0FBQztnQkFDRixZQUFZLENBQUM7b0JBQ1gsSUFBSSxFQUFFLFFBQVE7b0JBQ2QsUUFBUSxFQUFFLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxFQUFFLEVBQUU7b0JBQ3RGLE1BQU0sRUFBRSxPQUFPO2lCQUNoQixDQUFDO2FBQ0gsQ0FBQztZQUNGLE1BQU0sQ0FBQyxrQkFBa0IsRUFBRSxvQkFBb0IsRUFBRSxtQkFBbUIsQ0FBQyxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUV4RyxNQUFNLENBQUMsWUFBWSxFQUFFLGNBQWMsRUFBRSxhQUFhLENBQUMsR0FBRyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUM7Z0JBQ3RFLFFBQVEsQ0FBQyx5QkFBeUIsQ0FDaEMsZ0JBQWdCLENBQUMsSUFBSSxFQUNyQixrQkFBa0IsRUFDbEIsTUFBTSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsRUFDMUIsTUFBTSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsRUFDMUIsWUFBWSxDQUNiO2dCQUNELFFBQVEsQ0FBQyx5QkFBeUIsQ0FDaEMsZ0JBQWdCLENBQUMsTUFBTSxFQUN2QixrQkFBa0IsRUFDbEIsTUFBTSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsRUFDNUIsTUFBTSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsRUFDNUIsWUFBWSxDQUNiO2dCQUNELFFBQVEsQ0FBQyx5QkFBeUIsQ0FBQyxnQkFBZ0IsQ0FBQyxLQUFLLEVBQUUsa0JBQWtCLENBQUM7YUFDL0UsQ0FBQyxDQUFDO1lBRUgsTUFBTSxDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUN4QixNQUFNLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFFNUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsRUFBRSxFQUFFLGtCQUFrQixDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ3JELE1BQU0sQ0FBQyxLQUFLLENBQUMsY0FBYyxDQUFDLEVBQUUsRUFBRSxvQkFBb0IsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUN6RCxNQUFNLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxFQUFFLEVBQUUsbUJBQW1CLENBQUMsRUFBRSxDQUFDLENBQUM7WUFFdkQsQ0FBQyxFQUFFLEdBQUcsWUFBWSxFQUFFLG1CQUFtQixFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1lBQ3BGLENBQUMsRUFBRSxHQUFHLGNBQWMsRUFBRSxtQkFBbUIsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsb0JBQW9CLENBQUMsQ0FBQztZQUN4RixDQUFDLEVBQUUsR0FBRyxhQUFhLEVBQUUsbUJBQW1CLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLG1CQUFtQixDQUFDLENBQUM7WUFFdEYscUZBQXFGO1lBQ3JGLDJFQUEyRTtZQUMzRSxNQUFNLGFBQWEsR0FBRyxDQUFDLEdBQVcsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBRTlHLE1BQU0sQ0FBQyxFQUFFLENBQUMsWUFBWSxDQUFDLG1CQUFtQixDQUFDLENBQUM7WUFDNUMsTUFBTSxDQUFDLEtBQUssQ0FDVixLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUUsS0FBSyxFQUFFLFlBQVksQ0FBQyxtQkFBbUIsRUFBRSxRQUFRLEVBQUUsWUFBWSxFQUFFLENBQUMsRUFDbEYsYUFBYSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FDMUMsQ0FBQztZQUNGLE1BQU0sQ0FBQyxFQUFFLENBQUMsY0FBYyxDQUFDLG1CQUFtQixDQUFDLENBQUM7WUFDOUMsTUFBTSxDQUFDLEtBQUssQ0FDVixLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUUsS0FBSyxFQUFFLGNBQWMsQ0FBQyxtQkFBbUIsRUFBRSxRQUFRLEVBQUUsWUFBWSxFQUFFLENBQUMsRUFDcEYsYUFBYSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FDNUMsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLHVFQUF1RSxFQUFFLEtBQUs7WUFDL0UsSUFBSSxDQUFDLEtBQUssQ0FBQztpQkFDUixJQUFJLENBQUMseUJBQXlCLEVBQUUsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLEtBQUssVUFBVSxDQUFDO2lCQUNwRSxJQUFJLEVBQUU7aUJBQ04sS0FBSyxDQUFDLEdBQUcsRUFBRTtnQkFDVixTQUFTLEVBQUUsYUFBYTtnQkFDeEIsU0FBUyxFQUFFO29CQUNULE9BQU8sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUM7b0JBQ2xELFNBQVMsRUFBRSxrRUFBa0U7aUJBQzlFO2FBQ0YsQ0FBQyxDQUFDO1lBRUwsTUFBTSxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxlQUFlLENBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDbkcsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsdUVBQXVFLEVBQUUsS0FBSztZQUMvRSxNQUFNLFlBQVksR0FBRyxJQUFJLHlCQUFXLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDbEQsTUFBTSxVQUFVLEdBQTRDLEVBQUUsQ0FBQztZQUMvRCxNQUFNLG1CQUFtQixDQUFDLFlBQVksRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFFdkQsSUFBSSxDQUFDLEtBQUssQ0FBQztpQkFDUixJQUFJLENBQUMseUJBQXlCLEVBQUUsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLEtBQUssVUFBVSxDQUFDO2lCQUNwRSxJQUFJLEVBQUU7aUJBQ04sS0FBSyxDQUFDLEdBQUcsRUFBRTtnQkFDVixTQUFTLEVBQUUsaUJBQWlCO2dCQUM1QixvQkFBb0IsRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQztnQkFDckMsU0FBUyxFQUFFO29CQUNULE9BQU8sRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUM7b0JBQ2xELFNBQVMsRUFBRSxrRUFBa0U7aUJBQzlFO2FBQ0YsQ0FBQyxDQUFDO1lBRUwsTUFBTSxNQUFNLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxlQUFlLENBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDbkcsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsc0VBQXNFLEVBQUUsS0FBSztZQUM5RSxNQUFNLFlBQVksR0FBRyxJQUFJLHlCQUFXLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDbEQsTUFBTSxVQUFVLEdBQTRDLEVBQUUsQ0FBQztZQUMvRCxNQUFNLG1CQUFtQixDQUFDLFlBQVksRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFFdkQsSUFBSSxDQUFDLEtBQUssQ0FBQztpQkFDUixJQUFJLENBQUMseUJBQXlCLEVBQUUsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLEtBQUssVUFBVSxDQUFDO2lCQUNwRSxJQUFJLEVBQUU7aUJBQ04sS0FBSyxDQUFDLEdBQUcsRUFBRTtnQkFDVixTQUFTLEVBQUUsc0JBQXNCO2dCQUNqQyxvQkFBb0IsRUFBRSxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQztnQkFDckMsU0FBUyxFQUFFLEVBQUUsT0FBTyxFQUFFLEVBQUUsRUFBRSxTQUFTLEVBQUUsRUFBRSxFQUFFO2FBQzFDLENBQUMsQ0FBQztZQUVMLE1BQU0sTUFBTSxDQUFDLE9BQU8sQ0FDbEIsUUFBUSxDQUFDLGVBQWUsQ0FBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLFlBQVksRUFBRSxDQUFDLEVBQzFFLDhDQUE4QyxDQUMvQyxDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsaUdBQWlHLEVBQUUsS0FBSztZQUN6RyxNQUFNLFlBQVksR0FBRyxJQUFJLHlCQUFXLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDbEQsTUFBTSxVQUFVLEdBQTRDLEVBQUUsQ0FBQztZQUMvRCxNQUFNLG1CQUFtQixDQUFDLFlBQVksRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFFdkQsSUFBSSxDQUFDLEtBQUssQ0FBQztpQkFDUixJQUFJLENBQUMseUJBQXlCLEVBQUUsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLEtBQUssVUFBVSxDQUFDO2lCQUNwRSxJQUFJLEVBQUU7aUJBQ04sS0FBSyxDQUFDLEdBQUcsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLEVBQUUsT0FBTyxFQUE4QyxFQUFFLEVBQUU7Z0JBQ2xGLE1BQU0sRUFBRSxRQUFRLEVBQUUsVUFBVSxFQUFFLEdBQUcsT0FBTyxDQUFDO2dCQUN6QyxNQUFNLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsNkRBQTZELENBQUMsQ0FBQztnQkFFMUYsTUFBTSxhQUFhLEdBQWlDO29CQUNsRCxJQUFJLEVBQUUsQ0FBQztvQkFDUCxPQUFPLEVBQUUsSUFBSSxVQUFVLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDO2lCQUNqRSxDQUFDO2dCQUNGLE1BQU0sZUFBZSxHQUFpQztvQkFDcEQsSUFBSSxFQUFFLENBQUM7b0JBQ1AsT0FBTyxFQUFFLElBQUksVUFBVSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxRQUFRLENBQUMsQ0FBQztpQkFDbkUsQ0FBQztnQkFDRixZQUFZLENBQUMsc0JBQXNCLENBQUMsQ0FBQyxhQUFhLEVBQUUsZUFBZSxFQUFFLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO2dCQUV2RixPQUFPO29CQUNMLFNBQVMsRUFBRSxpQkFBaUI7b0JBQzVCLG9CQUFvQixFQUFFLFlBQVksQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLEVBQUUseURBQXlEO29CQUN4RyxTQUFTLEVBQUUsTUFBTSxzQkFBUSxDQUFDLG9CQUFvQixDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRSxjQUFjLENBQUM7aUJBQ3JHLENBQUM7WUFDSixDQUFDLENBQUMsQ0FBQztZQUVMLE1BQU0sTUFBTSxDQUFDLE9BQU8sQ0FDbEIsUUFBUSxDQUFDLGVBQWUsQ0FBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLFlBQVksRUFBRSxDQUFDLEVBQzFFLHNDQUFzQyxDQUN2QyxDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMscUZBQXFGLEVBQUUsS0FBSztZQUM3RixvRUFBb0U7WUFDcEUsTUFBTSxZQUFZLEdBQUcsb0JBQVMsQ0FBQyxRQUFRLENBQUMsV0FBSyxFQUFFLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBRSxDQUFDLENBQUM7WUFDbkUsWUFBWSxDQUFDLGtCQUFrQixFQUFFLENBQUM7WUFDbEMsTUFBTSxlQUFlLEdBQUcsWUFBWSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUNwRCxNQUFNLFlBQVksR0FBRyxpQkFBTSxDQUFDLFlBQVksQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUM7WUFDcEUsTUFBTSxhQUFhLEdBQUcsSUFBSSxpQkFBTSxDQUFDLFlBQVksRUFBRSxlQUFlLEVBQUU7Z0JBQzlELEVBQUUsRUFBRSxRQUFRO2dCQUNaLFVBQVUsRUFBRSxZQUFZO2dCQUN4QixJQUFJLEVBQUUsUUFBUTtnQkFDZCxZQUFZLEVBQUUsRUFBRTtnQkFDaEIsWUFBWSxFQUFFLEtBQUs7YUFDcEIsQ0FBQyxDQUFDO1lBQ0gsTUFBTSxlQUFlLEdBQUcsSUFBSSxxQkFBVSxDQUFDLGVBQWUsQ0FBQyxZQUFZLEVBQUUsZUFBZSxFQUFFLGFBQWEsQ0FBQyxDQUFDO1lBRXJHLGtFQUFrRTtZQUNsRSxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUMsR0FBRyxDQUFDLFdBQVcsUUFBUSxhQUFhLENBQUMsQ0FBQyxLQUFLLENBQUMsRUFBRSxZQUFZLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUU7Z0JBQzFGLElBQUksRUFBRSxZQUFZO2dCQUNsQixTQUFTLEVBQUUsZUFBZSxDQUFDLFNBQVM7Z0JBQ3BDLGNBQWMsRUFBRSxlQUFlLENBQUMsU0FBUztnQkFDekMsbUJBQW1CLEVBQUUsZUFBZSxDQUFDLFNBQVM7Z0JBQzlDLFlBQVk7YUFDYixDQUFDLENBQUM7WUFDSCxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUMsR0FBRyxDQUFDLDBCQUEwQixDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQztZQUV4RixNQUFNLE1BQU0sQ0FBQyxPQUFPLENBQ2xCLGVBQWUsQ0FBQyxlQUFlLENBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsQ0FBQyxFQUNqRiw4QkFBOEIsQ0FDL0IsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7SUFFSCw4RUFBOEU7SUFDOUUsZUFBZTtJQUNmLDhFQUE4RTtJQUU5RSxLQUFLLFVBQVUsd0NBQXdDLENBQ3JELElBQVksRUFDWixVQUFrQixFQUNsQixZQUErQztRQUUvQyxNQUFNLFFBQVEsR0FBc0I7WUFDbEMsSUFBSSxFQUFFLFlBQVk7WUFDbEIsU0FBUyxFQUFFLFlBQVksQ0FBQyxTQUFTO1lBQ2pDLGNBQWMsRUFBRSxZQUFZLENBQUMsU0FBUztZQUN0QyxtQkFBbUIsRUFBRSxZQUFZLENBQUMsU0FBUztZQUMzQyxZQUFZLEVBQUUsVUFBVTtTQUN6QixDQUFDO1FBQ0YsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsQ0FBQyxXQUFXLElBQUksYUFBYSxDQUFDLENBQUMsS0FBSyxDQUFDLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxDQUFDLENBQUMsS0FBSyxDQUFDLEdBQUcsRUFBRSxRQUFRLENBQUMsQ0FBQztRQUN2RyxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBRUQsS0FBSyxVQUFVLG1CQUFtQixDQUNoQyxZQUE2QixFQUM3QixVQUFtRCxFQUNuRCxLQUFLLEdBQUcsQ0FBQztRQUVULE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQzthQUNmLElBQUksQ0FBQyx5QkFBeUIsRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLEtBQUssS0FBSyxVQUFVLENBQUM7YUFDcEUsS0FBSyxDQUFDLEtBQUssQ0FBQzthQUNaLEtBQUssQ0FBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFLE9BQU8sRUFBOEMsRUFBRSxFQUFFO1lBQ2xGLE1BQU0sRUFBRSxnQkFBZ0IsRUFBRSxrQkFBa0IsRUFBRSxRQUFRLEVBQUUsVUFBVSxFQUFFLEdBQUcsT0FBTyxDQUFDO1lBRS9FLE9BQU8sQ0FBQyxNQUFNLENBQUMsWUFBWSxHQUFHLElBQUksR0FBRyxFQUFFLENBQUM7WUFDeEMsTUFBTSxhQUFhLEdBQUcsTUFBTSxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixFQUFFLENBQUMsQ0FBQztZQUM5RSxNQUFNLGVBQWUsR0FBRyxNQUFNLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxVQUFVLEVBQUUsa0JBQWtCLEVBQUUsQ0FBQyxDQUFDO1lBRWxGLE1BQU0sTUFBTSxHQUFHLE1BQU0sc0JBQVEsQ0FBQyx1QkFBdUIsQ0FBQyxhQUFhLENBQUMsQ0FBQztZQUNyRSxNQUFNLFFBQVEsR0FBRyxNQUFNLHNCQUFRLENBQUMsdUJBQXVCLENBQUMsZUFBZSxDQUFDLENBQUM7WUFDekUsTUFBTSxDQUFDLEVBQUUsT0FBTyxDQUFDLEdBQUcsTUFBTSxzQkFBUSxDQUFDLHFCQUFxQixDQUFDLGNBQWMsQ0FBQyxDQUFDO1lBRXpFLFlBQVksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUM7WUFDbEQsTUFBTSxZQUFZLEdBQUcsWUFBWSxDQUFDLGVBQWUsRUFBRSxDQUFDO1lBRXBELE1BQU0sc0JBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLEVBQUUsYUFBYSxDQUFDLENBQUM7WUFDekQsTUFBTSxzQkFBUSxDQUFDLGdCQUFnQixDQUFDLFVBQVUsRUFBRSxlQUFlLENBQUMsQ0FBQztZQUU3RCxnR0FBZ0c7WUFDaEcsTUFBTSxhQUFhLEdBQWlDO2dCQUNsRCxJQUFJLEVBQUUsQ0FBQztnQkFDUCxPQUFPLEVBQUUsSUFBSSxVQUFVLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDO2FBQ2pFLENBQUM7WUFDRixNQUFNLGVBQWUsR0FBaUM7Z0JBQ3BELElBQUksRUFBRSxDQUFDO2dCQUNQLE9BQU8sRUFBRSxJQUFJLFVBQVUsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDLENBQUM7YUFDbkUsQ0FBQztZQUNGLE1BQU0sQ0FBQyxZQUFZLENBQUMsR0FBRyxZQUFZLENBQUMsc0JBQXNCLENBQUMsQ0FBQyxhQUFhLEVBQUUsZUFBZSxFQUFFLFlBQVksQ0FBQyxDQUFDLENBQUM7WUFDM0csVUFBVSxDQUFDLElBQUksR0FBRyxZQUFZLENBQUM7WUFFL0IsT0FBTztnQkFDTCxTQUFTLEVBQUUsaUJBQWlCO2dCQUM1QixTQUFTLEVBQUUsTUFBTSxzQkFBUSxDQUFDLG9CQUFvQixDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxFQUFFLGNBQWMsQ0FBQzthQUNsRyxDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRUQsS0FBSyxVQUFVLG1CQUFtQixDQUNoQyxZQUE2QixFQUM3QixVQUFtRCxFQUNuRCxLQUFLLEdBQUcsQ0FBQztRQUVULE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQzthQUNmLElBQUksQ0FBQyx5QkFBeUIsRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLEtBQUssS0FBSyxVQUFVLENBQUM7YUFDcEUsS0FBSyxDQUFDLEtBQUssQ0FBQzthQUNaLEtBQUssQ0FBQyxHQUFHLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFLE9BQU8sRUFBOEMsRUFBRSxFQUFFO1lBQ2xGLE1BQU0sRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBRSxHQUFHLE9BQU8sQ0FBQztZQUVwRCxPQUFPLENBQUMsTUFBTSxDQUFDLFlBQVksR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDO1lBRXhDLE1BQU0sQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSw2REFBNkQsQ0FBQyxDQUFDO1lBRTFGLE1BQU0sYUFBYSxHQUFpQztnQkFDbEQsSUFBSSxFQUFFLENBQUM7Z0JBQ1AsT0FBTyxFQUFFLElBQUksVUFBVSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sRUFBRSxRQUFRLENBQUMsQ0FBQzthQUNqRSxDQUFDO1lBQ0YsTUFBTSxlQUFlLEdBQWlDO2dCQUNwRCxJQUFJLEVBQUUsQ0FBQztnQkFDUCxPQUFPLEVBQUUsSUFBSSxVQUFVLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDO2FBQ25FLENBQUM7WUFFRixnRkFBZ0Y7WUFDaEYsWUFBWSxDQUFDLHNCQUFzQixDQUFDLENBQUMsYUFBYSxFQUFFLGVBQWUsRUFBRSxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztZQUV2RixPQUFPO2dCQUNMLFNBQVM7Z0JBQ1Qsb0JBQW9CLEVBQUUsWUFBWSxDQUFDLGlCQUFpQixFQUFFO2dCQUN0RCxTQUFTLEVBQUUsTUFBTSxzQkFBUSxDQUFDLG9CQUFvQixDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRSxjQUFjLENBQUM7YUFDckcsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVELEtBQUssVUFBVSxZQUFZLENBQ3pCLE1BQWlGLEVBQ2pGLEtBQUssR0FBRyxDQUFDO1FBRVQsSUFBSSxDQUFDLEtBQUssQ0FBQzthQUNSLElBQUksQ0FBQyxXQUFXLE1BQU0sQ0FBQyxJQUFJLE1BQU0sRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLE9BQU8sS0FBSyxLQUFLLElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxNQUFNLENBQUMsTUFBTSxDQUFDO2FBQ3JHLEtBQUssQ0FBQyxLQUFLLENBQUM7YUFDWixLQUFLLENBQUMsR0FBRyxFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUMvQixPQUFPLE1BQU0sQ0FBQyxRQUFRLENBQUM7SUFDekIsQ0FBQztJQUVELEtBQUssVUFBVSxlQUFlLENBQUMsSUFBWSxFQUFFLEtBQUssR0FBRyxDQUFDO1FBQ3BELE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQzthQUNmLElBQUksQ0FBQyxXQUFXLElBQUksTUFBTSxFQUFFLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsT0FBTyxLQUFLLEtBQUssSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDO2FBQzdFLEtBQUssQ0FBQyxLQUFLLENBQUM7YUFDWixLQUFLLENBQUMsR0FBRyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsV0FBK0IsRUFBRSxFQUFFO1lBQzFELE1BQU0sR0FBRyxHQUFHO2dCQUNWLEVBQUUsRUFBRSxXQUFXLENBQUMsTUFBTTtnQkFDdEIsTUFBTSxFQUFFLFdBQVcsQ0FBQyxNQUFNO2dCQUMxQixJQUFJLEVBQUUsV0FBVyxDQUFDLE9BQU87Z0JBQ3pCLGNBQWMsRUFBRSxXQUFXLENBQUMsY0FBYztnQkFDMUMsWUFBWSxFQUFFLFdBQVcsQ0FBQyxZQUFZO2FBQ3ZDLENBQUM7WUFDRixJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxDQUFDLFdBQVcsSUFBSSxRQUFRLFdBQVcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUM7WUFDN0UsT0FBTyxHQUFHLENBQUM7UUFDYixDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7QUFDSCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGFzc2VydCBmcm9tICdhc3NlcnQnO1xuaW1wb3J0IG5vY2sgPSByZXF1aXJlKCdub2NrJyk7XG5pbXBvcnQgKiBhcyBvcGVucGdwIGZyb20gJ29wZW5wZ3AnO1xuXG5pbXBvcnQgeyBFZGRzYU1QQ3YyS2V5R2VuUm91bmQxUmVxdWVzdCwgRWRkc2FNUEN2MktleUdlblJvdW5kMlJlcXVlc3QgfSBmcm9tICdAYml0Z28vcHVibGljLXR5cGVzJztcbmltcG9ydCB7IFRlc3RhYmxlQkcsIFRlc3RCaXRHbyB9IGZyb20gJ0BiaXRnby9zZGstdGVzdCc7XG5pbXBvcnQgeyBBZGRLZXljaGFpbk9wdGlvbnMsIEJhc2VDb2luLCBjb21tb24sIEVDRFNBVXRpbHMsIEVERFNBVXRpbHMsIEtleWNoYWluLCBXYWxsZXQgfSBmcm9tICdAYml0Z28vc2RrLWNvcmUnO1xuaW1wb3J0IHsgRWRkc2FNUFNEa2csIE1QU0NvbW1zLCBNUFNUeXBlcyB9IGZyb20gJ0BiaXRnby9zZGstbGliLW1wYyc7XG5pbXBvcnQgeyBCaXRHbywgQml0Z29HUEdQdWJsaWNLZXkgfSBmcm9tICcuLi8uLi8uLi8uLi8uLi8uLi9zcmMnO1xuXG5jb25zdCBNUEN2MlBhcnRpZXNFbnVtID0gRUNEU0FVdGlscy5NUEN2MlBhcnRpZXNFbnVtO1xuXG5kZXNjcmliZSgnVFNTIEVkRFNBIE1QQ3YyIFV0aWxzOicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgY29uc3QgY29pbk5hbWUgPSAnc29sJztcbiAgY29uc3Qgd2FsbGV0SWQgPSAnNWIzNDI1MmYxYmYzNDk5MzBlMzQwMjBhMDAwMDAwMDAnO1xuICBjb25zdCBlbnRlcnByaXNlSWQgPSAnNjQ0OTE1M2E2ZjZiYzIwMDA2ZDY2NzcxY2RiZTE1ZDMnO1xuXG4gIGxldCBiZ1VybDogc3RyaW5nO1xuICBsZXQgdHNzVXRpbHM6IEVERFNBVXRpbHMuRWRkc2FNUEN2MlV0aWxzO1xuICBsZXQgd2FsbGV0OiBXYWxsZXQ7XG4gIGxldCBiaXRnbzogVGVzdGFibGVCRyAmIEJpdEdvO1xuICBsZXQgYmFzZUNvaW46IEJhc2VDb2luO1xuXG4gIGxldCBiaXRnb0dwZ0tleVBhaXI6IG9wZW5wZ3AuU2VyaWFsaXplZEtleVBhaXI8c3RyaW5nPiAmIHsgcmV2b2NhdGlvbkNlcnRpZmljYXRlOiBzdHJpbmcgfTtcbiAgbGV0IGJpdGdvUHJ2S2V5T2JqOiBvcGVucGdwLlByaXZhdGVLZXk7XG4gIGxldCBjb25zdGFudHM6IHsgbXBjOiB7IGJpdGdvUHVibGljS2V5OiBzdHJpbmc7IGJpdGdvTVBDdjJQdWJsaWNLZXk6IHN0cmluZyB9IH07XG5cbiAgYmVmb3JlRWFjaChhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgbm9jay5jbGVhbkFsbCgpO1xuICAgIGF3YWl0IG5vY2tHZXRCaXRnb1B1YmxpY0tleUJhc2VkT25GZWF0dXJlRmxhZ3MoY29pbk5hbWUsIGVudGVycHJpc2VJZCwgYml0Z29HcGdLZXlQYWlyKTtcbiAgICBub2NrKGJnVXJsKS5nZXQoJy9hcGkvdjEvY2xpZW50L2NvbnN0YW50cycpLnRpbWVzKDEwKS5yZXBseSgyMDAsIHsgdHRsOiAzNjAwLCBjb25zdGFudHMgfSk7XG4gIH0pO1xuXG4gIGJlZm9yZShhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgb3BlbnBncC5jb25maWcucmVqZWN0Q3VydmVzID0gbmV3IFNldCgpO1xuXG4gICAgYml0Z29HcGdLZXlQYWlyID0gYXdhaXQgb3BlbnBncC5nZW5lcmF0ZUtleSh7XG4gICAgICB1c2VySURzOiBbeyBuYW1lOiAnYml0Z28nLCBlbWFpbDogJ2JpdGdvQHRlc3QuY29tJyB9XSxcbiAgICAgIGN1cnZlOiAnZWQyNTUxOScsXG4gICAgICBmb3JtYXQ6ICdhcm1vcmVkJyxcbiAgICB9KTtcblxuICAgIGJpdGdvUHJ2S2V5T2JqID0gYXdhaXQgb3BlbnBncC5yZWFkUHJpdmF0ZUtleSh7IGFybW9yZWRLZXk6IGJpdGdvR3BnS2V5UGFpci5wcml2YXRlS2V5IH0pO1xuXG4gICAgY29uc3RhbnRzID0ge1xuICAgICAgbXBjOiB7XG4gICAgICAgIGJpdGdvUHVibGljS2V5OiBiaXRnb0dwZ0tleVBhaXIucHVibGljS2V5LFxuICAgICAgICBiaXRnb01QQ3YyUHVibGljS2V5OiBiaXRnb0dwZ0tleVBhaXIucHVibGljS2V5LFxuICAgICAgfSxcbiAgICB9O1xuXG4gICAgYml0Z28gPSBUZXN0Qml0R28uZGVjb3JhdGUoQml0R28sIHsgZW52OiAnbW9jaycgfSk7XG4gICAgYml0Z28uaW5pdGlhbGl6ZVRlc3RWYXJzKCk7XG4gICAgYmFzZUNvaW4gPSBiaXRnby5jb2luKGNvaW5OYW1lKTtcbiAgICBiZ1VybCA9IGNvbW1vbi5FbnZpcm9ubWVudHNbYml0Z28uZ2V0RW52KCldLnVyaTtcblxuICAgIGNvbnN0IHdhbGxldERhdGEgPSB7XG4gICAgICBpZDogd2FsbGV0SWQsXG4gICAgICBlbnRlcnByaXNlOiBlbnRlcnByaXNlSWQsXG4gICAgICBjb2luOiBjb2luTmFtZSxcbiAgICAgIGNvaW5TcGVjaWZpYzoge30sXG4gICAgICBtdWx0aXNpZ1R5cGU6ICd0c3MnLFxuICAgIH07XG4gICAgd2FsbGV0ID0gbmV3IFdhbGxldChiaXRnbywgYmFzZUNvaW4sIHdhbGxldERhdGEpO1xuICAgIHRzc1V0aWxzID0gbmV3IEVERFNBVXRpbHMuRWRkc2FNUEN2MlV0aWxzKGJpdGdvLCBiYXNlQ29pbiwgd2FsbGV0KTtcbiAgfSk7XG5cbiAgYWZ0ZXIoZnVuY3Rpb24gKCkge1xuICAgIG5vY2suY2xlYW5BbGwoKTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ1RTUyBrZXkgY2hhaW5zJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgZ2VuZXJhdGUgVFNTIE1QUyBrZXlzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgYml0Z29TZXNzaW9uID0gbmV3IEVkZHNhTVBTRGtnLkRLRygzLCAyLCAyKTtcbiAgICAgIGNvbnN0IGJpdGdvU3RhdGU6IHsgbXNnMj86IE1QU1R5cGVzLkRlc2VyaWFsaXplZE1lc3NhZ2UgfSA9IHt9O1xuICAgICAgY29uc3Qgcm91bmQxTm9jayA9IGF3YWl0IG5vY2tNUFNLZXlHZW5Sb3VuZDEoYml0Z29TZXNzaW9uLCBiaXRnb1N0YXRlLCAxKTtcbiAgICAgIGNvbnN0IHJvdW5kMk5vY2sgPSBhd2FpdCBub2NrTVBTS2V5R2VuUm91bmQyKGJpdGdvU2Vzc2lvbiwgYml0Z29TdGF0ZSwgMSk7XG4gICAgICBjb25zdCBhZGRLZXlOb2NrID0gYXdhaXQgbm9ja0FkZEtleUNoYWluKGNvaW5OYW1lLCAzKTtcblxuICAgICAgY29uc3QgcGFyYW1zID0ge1xuICAgICAgICBwYXNzcGhyYXNlOiAndGVzdCcsXG4gICAgICAgIGVudGVycHJpc2U6IGVudGVycHJpc2VJZCxcbiAgICAgICAgb3JpZ2luYWxQYXNzY29kZUVuY3J5cHRpb25Db2RlOiAnMTIzNDU2JyxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHsgdXNlcktleWNoYWluLCBiYWNrdXBLZXljaGFpbiwgYml0Z29LZXljaGFpbiB9ID0gYXdhaXQgdHNzVXRpbHMuY3JlYXRlS2V5Y2hhaW5zKHBhcmFtcyk7XG5cbiAgICAgIGFzc2VydC5vayhyb3VuZDFOb2NrLmlzRG9uZSgpKTtcbiAgICAgIGFzc2VydC5vayhyb3VuZDJOb2NrLmlzRG9uZSgpKTtcbiAgICAgIGFzc2VydC5vayhhZGRLZXlOb2NrLmlzRG9uZSgpKTtcblxuICAgICAgYXNzZXJ0Lm9rKHVzZXJLZXljaGFpbik7XG4gICAgICBhc3NlcnQuZXF1YWwodXNlcktleWNoYWluLnNvdXJjZSwgJ3VzZXInKTtcbiAgICAgIGFzc2VydC5vayh1c2VyS2V5Y2hhaW4uY29tbW9uS2V5Y2hhaW4pO1xuICAgICAgYXNzZXJ0Lm9rKHVzZXJLZXljaGFpbi5lbmNyeXB0ZWRQcnYpO1xuICAgICAgYXNzZXJ0Lm9rKGJpdGdvLmRlY3J5cHQoeyBpbnB1dDogdXNlcktleWNoYWluLmVuY3J5cHRlZFBydiwgcGFzc3dvcmQ6IHBhcmFtcy5wYXNzcGhyYXNlIH0pKTtcblxuICAgICAgYXNzZXJ0Lm9rKGJhY2t1cEtleWNoYWluKTtcbiAgICAgIGFzc2VydC5lcXVhbChiYWNrdXBLZXljaGFpbi5zb3VyY2UsICdiYWNrdXAnKTtcbiAgICAgIGFzc2VydC5vayhiYWNrdXBLZXljaGFpbi5jb21tb25LZXljaGFpbik7XG4gICAgICBhc3NlcnQub2soYmFja3VwS2V5Y2hhaW4uZW5jcnlwdGVkUHJ2KTtcbiAgICAgIGFzc2VydC5vayhiaXRnby5kZWNyeXB0KHsgaW5wdXQ6IGJhY2t1cEtleWNoYWluLmVuY3J5cHRlZFBydiwgcGFzc3dvcmQ6IHBhcmFtcy5wYXNzcGhyYXNlIH0pKTtcblxuICAgICAgYXNzZXJ0Lm9rKGJpdGdvS2V5Y2hhaW4pO1xuICAgICAgYXNzZXJ0LmVxdWFsKGJpdGdvS2V5Y2hhaW4uc291cmNlLCAnYml0Z28nKTtcbiAgICAgIGFzc2VydC5vayhiaXRnb0tleWNoYWluLmNvbW1vbktleWNoYWluKTtcblxuICAgICAgYXNzZXJ0LmVxdWFsKHVzZXJLZXljaGFpbi5jb21tb25LZXljaGFpbiwgYmFja3VwS2V5Y2hhaW4uY29tbW9uS2V5Y2hhaW4pO1xuICAgICAgYXNzZXJ0LmVxdWFsKHVzZXJLZXljaGFpbi5jb21tb25LZXljaGFpbiwgYml0Z29LZXljaGFpbi5jb21tb25LZXljaGFpbik7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHNlbmQgd2ViYXV0aG5JbmZvICh3aXRoIGVudGVycHJpc2VJZCkgb24gdGhlIHVzZXIga2V5Y2hhaW4gd2hlbiB3ZWJhdXRobkluZm8gaXMgcHJvdmlkZWQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBjb21tb25LZXljaGFpbiA9ICdhJy5yZXBlYXQoNjQpO1xuICAgICAgY29uc3QgY2FwdHVyZWRCb2RpZXM6IFJlY29yZDxzdHJpbmcsIEFkZEtleWNoYWluT3B0aW9ucz4gPSB7fTtcbiAgICAgIGNvbnN0IGFkZEtleU5vY2sgPSBub2NrKCdodHRwczovL2JpdGdvLmZha2V1cmwnKVxuICAgICAgICAucG9zdChgL2FwaS92Mi8ke2NvaW5OYW1lfS9rZXlgLCAoYm9keSkgPT4gYm9keS5rZXlUeXBlID09PSAndHNzJyAmJiBib2R5LmlzTVBDdjIpXG4gICAgICAgIC50aW1lcygxKVxuICAgICAgICAucmVwbHkoMjAwLCBhc3luYyAodXJpLCByZXF1ZXN0Qm9keTogQWRkS2V5Y2hhaW5PcHRpb25zKSA9PiB7XG4gICAgICAgICAgY2FwdHVyZWRCb2RpZXNbcmVxdWVzdEJvZHkuc291cmNlIGFzIHN0cmluZ10gPSByZXF1ZXN0Qm9keTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgaWQ6IHJlcXVlc3RCb2R5LnNvdXJjZSxcbiAgICAgICAgICAgIHNvdXJjZTogcmVxdWVzdEJvZHkuc291cmNlLFxuICAgICAgICAgICAgdHlwZTogcmVxdWVzdEJvZHkua2V5VHlwZSxcbiAgICAgICAgICAgIGNvbW1vbktleWNoYWluOiByZXF1ZXN0Qm9keS5jb21tb25LZXljaGFpbixcbiAgICAgICAgICAgIGVuY3J5cHRlZFBydjogcmVxdWVzdEJvZHkuZW5jcnlwdGVkUHJ2LFxuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuXG4gICAgICBjb25zdCB3ZWJhdXRobkluZm8gPSB7IG90cERldmljZUlkOiAnZGV2aWNlLTEyMycsIHByZlNhbHQ6ICdzYWx0LWFiYycsIHBhc3NwaHJhc2U6ICdwcmYtZGVyaXZlZC1wYXNzcGhyYXNlJyB9O1xuICAgICAgLy8gRGlyZWN0IHBhcnRpY2lwYW50LWtleWNoYWluIGNhbGwgYXZvaWRzIHRoZSBFZERTQSBES0cgY2VyZW1vbnkgd2hpbGUgc3RpbGwgZXhlcmNpc2luZyB0aGVcbiAgICAgIC8vIHVzZXIta2V5Y2hhaW4gd2ViYXV0aG4gYXNzZW1ibHkgdGhhdCBQT1NUcyB0byAva2V5LlxuICAgICAgYXdhaXQgdHNzVXRpbHMuY3JlYXRlUGFydGljaXBhbnRLZXljaGFpbihcbiAgICAgICAgTVBDdjJQYXJ0aWVzRW51bS5VU0VSLFxuICAgICAgICBjb21tb25LZXljaGFpbixcbiAgICAgICAgQnVmZmVyLmZyb20oJ3VzZXJQcml2YXRlJyksXG4gICAgICAgIEJ1ZmZlci5mcm9tKCd1c2VyUmVkdWNlZCcpLFxuICAgICAgICAncGFzc3BocmFzZScsXG4gICAgICAgIHVuZGVmaW5lZCxcbiAgICAgICAgd2ViYXV0aG5JbmZvLFxuICAgICAgICB1bmRlZmluZWQsXG4gICAgICAgIGVudGVycHJpc2VJZFxuICAgICAgKTtcbiAgICAgIGFzc2VydC5vayhhZGRLZXlOb2NrLmlzRG9uZSgpKTtcblxuICAgICAgLy8gVXNlciBrZXljaGFpbiBtdXN0IGNhcnJ5IHdlYmF1dGhuSW5mbyAodGhlIGZpZWxkIHRoZSBiYWNrZW5kIFBPU1QgL2tleSBjb25zdW1lcyksIGluY2x1ZGluZ1xuICAgICAgLy8gZW50ZXJwcmlzZUlkLCBhbmQgbXVzdCBOT1QgdXNlIHRoZSBkZXByZWNhdGVkIHdlYmF1dGhuRGV2aWNlcyBhcnJheS5cbiAgICAgIGNvbnN0IHVzZXJCb2R5ID0gY2FwdHVyZWRCb2RpZXNbJ3VzZXInXTtcbiAgICAgIGFzc2VydC5vayh1c2VyQm9keSwgJ3VzZXIga2V5Y2hhaW4gc2hvdWxkIGhhdmUgYmVlbiBjcmVhdGVkJyk7XG4gICAgICBhc3NlcnQub2sodXNlckJvZHkud2ViYXV0aG5JbmZvLCAndXNlciBrZXljaGFpbiBib2R5IHNob3VsZCBpbmNsdWRlIHdlYmF1dGhuSW5mbycpO1xuICAgICAgYXNzZXJ0LmVxdWFsKHVzZXJCb2R5LndlYmF1dGhuSW5mby5vdHBEZXZpY2VJZCwgd2ViYXV0aG5JbmZvLm90cERldmljZUlkKTtcbiAgICAgIGFzc2VydC5lcXVhbCh1c2VyQm9keS53ZWJhdXRobkluZm8ucHJmU2FsdCwgd2ViYXV0aG5JbmZvLnByZlNhbHQpO1xuICAgICAgYXNzZXJ0LmVxdWFsKHVzZXJCb2R5LndlYmF1dGhuSW5mby5lbnRlcnByaXNlSWQsIGVudGVycHJpc2VJZCk7XG4gICAgICBhc3NlcnQub2sodXNlckJvZHkud2ViYXV0aG5JbmZvL