bitgo
Version:
BitGo JavaScript SDK
431 lines • 63.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBitGoPartyGpgKeyPrv = getBitGoPartyGpgKeyPrv;
exports.getUserPartyGpgKeyPublic = getUserPartyGpgKeyPublic;
const sdk_core_1 = require("@bitgo/sdk-core");
const sdk_lib_mpc_1 = require("@bitgo/sdk-lib-mpc");
const fs = require("fs");
const common_1 = require("../common");
const openpgp = require("openpgp");
const nock = require("nock");
const sdk_test_1 = require("@bitgo/sdk-test");
const src_1 = require("../../../../../../src");
const createKeccakHash = require('keccak');
describe('signTxRequest:', function () {
let tssUtils;
let wallet;
let bitgo;
let baseCoin;
let bitgoGpgKey;
const coinName = 'hteth';
const reqId = new sdk_core_1.RequestTracer();
const txRequestId = 'randomTxReqId';
const signableHex = 'e27aecaea559fbedc9ae8a22b0ab6654c2d686403c2aeb434b302545c94eed3b';
const txRequest = {
txRequestId,
enterpriseId: '4517abfb-f567-4b7a-9f91-407509d29403',
transactions: [
{
unsignedTx: {
serializedTxHex: 'TOO MANY SECRETS',
signableHex,
derivationPath: 'm/0', // Needs this when key derivation is supported
},
state: 'pendingSignature',
signatureShares: [],
},
],
unsignedTxs: [],
date: new Date().toISOString(),
intent: {
intentType: 'payment',
},
latest: true,
state: 'pendingUserSignature',
walletType: 'hot',
walletId: 'walletId',
policiesChecked: true,
version: 1,
userId: 'userId',
apiVersion: 'full',
};
const txRequestForMessageSigning = {
txRequestId,
enterpriseId: '4517abfb-f567-4b7a-9f91-407509d29403',
messages: [
{
messageRaw: 'TOO MANY SECRETS',
derivationPath: 'm/0',
state: 'pendingSignature',
signatureShares: [],
},
],
unsignedTxs: [],
date: new Date().toISOString(),
intent: {
intentType: 'payment',
},
latest: true,
state: 'pendingUserSignature',
walletType: 'hot',
walletId: 'walletId',
policiesChecked: true,
version: 1,
userId: 'userId',
apiVersion: 'full',
};
const vector = {
party1: 0,
party2: 2,
party3: 1,
};
// To generate the fixtures, run DKG as in the dklsDkg.ts tests and save the resulting party.getKeyShare in a file by doing fs.writeSync(party.getKeyShare()).
const shareFiles = [
`${__dirname}/fixtures/userShare`,
`${__dirname}/fixtures/backupShare`,
`${__dirname}/fixtures/bitgoShare`,
];
let bitgoParty;
before(async () => {
bitgo = sdk_test_1.TestBitGo.decorate(src_1.BitGo, { env: 'mock' });
bitgo.initializeTestVars();
const bgUrl = sdk_core_1.common.Environments[bitgo.getEnv()].uri;
bitgoGpgKey = await openpgp.generateKey({
userIDs: [
{
name: 'bitgo',
},
],
curve: 'secp256k1',
config: {
rejectCurves: new Set(),
},
});
const constants = {
mpc: {
bitgoPublicKey: bitgoGpgKey.publicKey,
bitgoMPCv2PublicKey: bitgoGpgKey.publicKey,
},
};
nock(bgUrl).get('/api/v1/client/constants').times(20).reply(200, { ttl: 3600, constants });
baseCoin = bitgo.coin(coinName);
let hashFn;
try {
hashFn = baseCoin.getHashFunction();
}
catch (err) {
hashFn = createKeccakHash('keccak256');
}
const hashBuffer = hashFn.update(Buffer.from(signableHex, 'hex')).digest();
// Nock out both the user and bitgo side responses to create valid signatures
bitgoParty = new sdk_lib_mpc_1.DklsDsg.Dsg(fs.readFileSync(shareFiles[vector.party2]), vector.party2, txRequest.transactions[0].unsignedTx.derivationPath, hashBuffer);
// // Round 1 ////
const walletData = {
id: txRequest.walletId,
enterprise: txRequest.enterpriseId,
coin: coinName,
coinSpecific: {},
multisigType: 'tss',
multisigTypeVersion: 'MPCv2',
};
wallet = new sdk_core_1.Wallet(bitgo, baseCoin, walletData);
tssUtils = new sdk_core_1.ECDSAUtils.EcdsaMPCv2Utils(bitgo, baseCoin, wallet);
});
beforeEach(async function () {
await nockGetBitgoPublicKeyBasedOnFeatureFlags(coinName, txRequest.enterpriseId, bitgoGpgKey);
});
after(function () {
nock.cleanAll();
});
afterEach(function () {
bitgoParty.endSession();
nock.cleanAll();
});
it('successfully signs a txRequest with user key for a dkls hot wallet with WP', async function () {
const nockPromises = [
await nockTxRequestResponseSignatureShareRoundOne(bitgoParty, txRequest, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundTwo(bitgoParty, txRequest, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundThree(txRequest),
await nockSendTxRequest(txRequest),
];
await Promise.all(nockPromises);
const userShare = fs.readFileSync(shareFiles[vector.party1]);
const userPrvBase64 = Buffer.from(userShare).toString('base64');
await tssUtils.signTxRequest({
txRequest,
prv: userPrvBase64,
reqId,
});
nockPromises[0].isDone().should.be.true();
nockPromises[1].isDone().should.be.true();
nockPromises[2].isDone().should.be.true();
});
it('successfully signs a txRequest with backup key for a dkls hot wallet with WP', async function () {
const nockPromises = [
await nockTxRequestResponseSignatureShareRoundOne(bitgoParty, txRequest, bitgoGpgKey, 1),
await nockTxRequestResponseSignatureShareRoundTwo(bitgoParty, txRequest, bitgoGpgKey, 1),
await nockTxRequestResponseSignatureShareRoundThree(txRequest),
await nockSendTxRequest(txRequest),
];
await Promise.all(nockPromises);
const backupShare = fs.readFileSync(shareFiles[vector.party3]);
const backupPrvBase64 = Buffer.from(backupShare).toString('base64');
await tssUtils.signTxRequest({
txRequest,
prv: backupPrvBase64,
mpcv2PartyId: 1,
reqId,
});
nockPromises[0].isDone().should.be.true();
nockPromises[1].isDone().should.be.true();
nockPromises[2].isDone().should.be.true();
});
it('successfully signs a txRequest with a message for a dkls hot wallet with WP', async function () {
const nockPromises = [
await nockTxRequestResponseSignatureShareRoundOne(bitgoParty, txRequestForMessageSigning, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundTwo(bitgoParty, txRequestForMessageSigning, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundThree(txRequestForMessageSigning),
await nockSendTxRequest(txRequestForMessageSigning),
];
await Promise.all(nockPromises);
const userShare = fs.readFileSync(shareFiles[vector.party1]);
const userPrvBase64 = Buffer.from(userShare).toString('base64');
await tssUtils.signTxRequest({
txRequest,
prv: userPrvBase64,
reqId,
});
nockPromises[0].isDone().should.be.true();
nockPromises[1].isDone().should.be.true();
nockPromises[2].isDone().should.be.true();
});
it('successfully signs a txRequest for a dkls hot wallet after receiving multiple 429 errors', async function () {
const nockPromises = [
await nockTxRequestResponseSignatureShareRoundOne(bitgoParty, txRequest, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundTwo(bitgoParty, txRequest, bitgoGpgKey, 0, 3),
await nockTxRequestResponseSignatureShareRoundThree(txRequest),
await nockSendTxRequest(txRequest),
];
await Promise.all(nockPromises);
const userShare = fs.readFileSync(shareFiles[vector.party1]);
const userPrvBase64 = Buffer.from(userShare).toString('base64');
await tssUtils.signTxRequest({
txRequest,
prv: userPrvBase64,
reqId,
});
nockPromises[0].isDone().should.be.true();
nockPromises[1].isDone().should.be.true();
nockPromises[2].isDone().should.be.true();
});
it('fails to signs a txRequest for a dkls hot wallet after receiving over 3 429 errors', async function () {
const nockPromises = [
await nockTxRequestResponseSignatureShareRoundOne(bitgoParty, txRequest, bitgoGpgKey),
await nockTxRequestResponseSignatureShareRoundTwo(bitgoParty, txRequest, bitgoGpgKey, 0, 4),
];
await Promise.all(nockPromises);
const userShare = fs.readFileSync(shareFiles[vector.party1]);
const userPrvBase64 = Buffer.from(userShare).toString('base64');
await tssUtils
.signTxRequest({
txRequest,
prv: userPrvBase64,
reqId,
})
.should.be.rejectedWith('Too many requests, slow down!');
nockPromises[0].isDone().should.be.true();
nockPromises[1].isDone().should.be.false();
});
});
function getBitGoPartyGpgKeyPrv(key) {
return {
partyId: 2,
gpgKey: key.privateKey,
};
}
function getUserPartyGpgKeyPublic(userPubKey, partyId = 0) {
return {
partyId: partyId,
gpgKey: userPubKey,
};
}
async function nockTxRequestResponseSignatureShareRoundOne(bitgoSession, txRequest, bitgoGpgKey, partyId = 0) {
const transactions = (0, common_1.getRoute)('ecdsa');
return nock('https://bitgo.fakeurl')
.persist(true)
.post(`/api/v2/wallet/${txRequest.walletId}/txrequests/${txRequest.txRequestId + transactions}/sign`, (body) => JSON.parse(body.signatureShares[0].share).type === 'round1Input')
.times(1)
.reply(200, async (uri, body) => {
// Do the actual signing on BitGo's side based on User's messages
const signatureShare = JSON.parse(body.signatureShares[0].share);
const deserializedMessages = sdk_lib_mpc_1.DklsTypes.deserializeMessages({
p2pMessages: [],
broadcastMessages: [
{
from: signatureShare.data.msg1.from,
payload: signatureShare.data.msg1.message,
},
],
});
if (signatureShare.type === 'round1Input') {
const bitgoToUserRound1BroadcastMsg = await bitgoSession.init();
const bitgoToUserRound2Msg = bitgoSession.handleIncomingMessages({
p2pMessages: [],
broadcastMessages: deserializedMessages.broadcastMessages,
});
const serializedBitGoToUserRound1And2Msgs = sdk_lib_mpc_1.DklsTypes.serializeMessages({
p2pMessages: bitgoToUserRound2Msg.p2pMessages,
broadcastMessages: [bitgoToUserRound1BroadcastMsg],
});
const authEncMessages = await sdk_lib_mpc_1.DklsComms.encryptAndAuthOutgoingMessages(serializedBitGoToUserRound1And2Msgs, [getUserPartyGpgKeyPublic(body.signerGpgPublicKey, partyId)], [getBitGoPartyGpgKeyPrv(bitgoGpgKey)]);
const bitgoToUserSignatureShare = {
type: 'round1Output',
data: {
msg1: {
from: authEncMessages.broadcastMessages[0].from,
signature: authEncMessages.broadcastMessages[0].payload.signature,
message: authEncMessages.broadcastMessages[0].payload.message,
},
msg2: {
from: authEncMessages.p2pMessages[0].from,
to: authEncMessages.p2pMessages[0].to,
encryptedMessage: authEncMessages.p2pMessages[0].payload.encryptedMessage,
signature: authEncMessages.p2pMessages[0].payload.signature,
},
},
};
return {
txRequestId: txRequest.txRequestId,
transactions: [
{
signatureShares: [
{
from: sdk_core_1.SignatureShareType.BITGO,
to: partyId === 0 ? sdk_core_1.SignatureShareType.USER : sdk_core_1.SignatureShareType.BACKUP,
share: JSON.stringify(bitgoToUserSignatureShare),
},
],
},
],
};
}
});
}
async function nockTxRequestResponseSignatureShareRoundTwo(bitgoSession, txRequest, bitgoGpgKey, partyId = 0, rateLimitErrorCount = 0) {
const transactions = (0, common_1.getRoute)('ecdsa');
const scope = nock('https://bitgo.fakeurl');
if (rateLimitErrorCount > 0) {
scope
.post(`/api/v2/wallet/${txRequest.walletId}/txrequests/${txRequest.txRequestId + transactions}/sign`, (body) => JSON.parse(body.signatureShares[0].share).type === 'round2Input')
.times(rateLimitErrorCount)
.reply(429, {
error: 'Too many requests, slow down!',
name: 'TooManyRequests',
requestId: 'cm5qx01lh0013b2ek2sxl4w00',
context: {},
});
}
return scope
.post(`/api/v2/wallet/${txRequest.walletId}/txrequests/${txRequest.txRequestId + transactions}/sign`, (body) => JSON.parse(body.signatureShares[0].share).type === 'round2Input')
.times(1)
.reply(200, async (uri, body) => {
// Do the actual signing on BitGo's side based on User's messages
const parsedSignatureShare = JSON.parse(body.signatureShares[0].share);
const serializedMessages = await sdk_lib_mpc_1.DklsComms.decryptAndVerifyIncomingMessages({
p2pMessages: [
{
from: parsedSignatureShare.data.msg2.from,
to: parsedSignatureShare.data.msg2.to,
payload: {
encryptedMessage: parsedSignatureShare.data.msg2.encryptedMessage,
signature: parsedSignatureShare.data.msg2.signature,
},
},
{
from: parsedSignatureShare.data.msg3.from,
to: parsedSignatureShare.data.msg3.to,
payload: {
encryptedMessage: parsedSignatureShare.data.msg3.encryptedMessage,
signature: parsedSignatureShare.data.msg3.signature,
},
},
],
broadcastMessages: [],
}, [getUserPartyGpgKeyPublic(body.signerGpgPublicKey, partyId)], [getBitGoPartyGpgKeyPrv(bitgoGpgKey)]);
const deserializedMessages = sdk_lib_mpc_1.DklsTypes.deserializeMessages({
p2pMessages: [serializedMessages.p2pMessages[0]],
broadcastMessages: [],
});
if (parsedSignatureShare.type === 'round2Input') {
const bitgoToUserRound3Msg = bitgoSession.handleIncomingMessages(deserializedMessages);
const serializedBitGoToUserRound3Msgs = sdk_lib_mpc_1.DklsTypes.serializeMessages(bitgoToUserRound3Msg);
const authEncMessages = await sdk_lib_mpc_1.DklsComms.encryptAndAuthOutgoingMessages(serializedBitGoToUserRound3Msgs, [getUserPartyGpgKeyPublic(body.signerGpgPublicKey, partyId)], [getBitGoPartyGpgKeyPrv(bitgoGpgKey)]);
const bitgoToUserSignatureShare = {
type: 'round2Output',
data: {
msg3: {
from: authEncMessages.p2pMessages[0].from,
to: authEncMessages.p2pMessages[0].to,
encryptedMessage: authEncMessages.p2pMessages[0].payload.encryptedMessage,
signature: authEncMessages.p2pMessages[0].payload.signature,
},
},
};
return {
txRequestId: txRequest.txRequestId,
transactions: [
{
signatureShares: [
{
from: partyId === 0 ? sdk_core_1.SignatureShareType.USER : sdk_core_1.SignatureShareType.BACKUP,
to: sdk_core_1.SignatureShareType.BITGO,
share: 'some old share we dont care about',
},
{
from: sdk_core_1.SignatureShareType.BITGO,
to: partyId === 0 ? sdk_core_1.SignatureShareType.USER : sdk_core_1.SignatureShareType.BACKUP,
share: JSON.stringify(bitgoToUserSignatureShare),
},
],
},
],
};
}
});
}
async function nockTxRequestResponseSignatureShareRoundThree(txRequest) {
const transactions = (0, common_1.getRoute)('ecdsa');
return nock('https://bitgo.fakeurl')
.post(`/api/v2/wallet/${txRequest.walletId}/txrequests/${txRequest.txRequestId + transactions}/sign`, (body) => JSON.parse(body.signatureShares[0].share).type === 'round3Input')
.times(1)
.reply(200, async (uri, body) => {
// Do the actual signing on BitGo's side based on User's messages
return {
txRequestId: txRequest.txRequestId,
};
});
}
async function nockSendTxRequest(txRequest) {
const transactions = (0, common_1.getRoute)('ecdsa');
return nock('https://bitgo.fakeurl')
.post(`/api/v2/wallet/${txRequest.walletId}/txrequests/${txRequest.txRequestId + transactions}/send`)
.times(1)
.reply(200, {
txRequestId: txRequest.txRequestId,
});
}
async function nockGetBitgoPublicKeyBasedOnFeatureFlags(coin, enterpriseId, bitgoGpgKeyPair) {
const bitgoGPGPublicKeyResponse = {
name: 'irrelevant',
publicKey: bitgoGpgKeyPair.publicKey,
mpcv2PublicKey: bitgoGpgKeyPair.publicKey,
enterpriseId,
};
nock('https://bitgo.fakeurl')
.get(`/api/v2/${coin}/tss/pubkey`)
.times(4)
.query({ enterpriseId })
.reply(200, bitgoGPGPublicKeyResponse);
return bitgoGPGPublicKeyResponse;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnblR4UmVxdWVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Rlc3QvdjIvdW5pdC9pbnRlcm5hbC90c3NVdGlscy9lY2RzYU1QQ3YyL3NpZ25UeFJlcXVlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUE4UkEsd0RBS0M7QUFFRCw0REFLQztBQXpTRCw4Q0FVeUI7QUFDekIsb0RBQW1FO0FBQ25FLHlCQUF5QjtBQUN6QixzQ0FBcUM7QUFTckMsbUNBQW1DO0FBQ25DLDZCQUE4QjtBQUM5Qiw4Q0FBd0Q7QUFDeEQsK0NBQThDO0FBQzlDLE1BQU0sZ0JBQWdCLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBTzNDLFFBQVEsQ0FBQyxnQkFBZ0IsRUFBRTtJQUN6QixJQUFJLFFBQW9DLENBQUM7SUFDekMsSUFBSSxNQUFjLENBQUM7SUFDbkIsSUFBSSxLQUF5QixDQUFDO0lBQzlCLElBQUksUUFBa0IsQ0FBQztJQUN2QixJQUFJLFdBQThDLENBQUM7SUFDbkQsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDO0lBRXpCLE1BQU0sS0FBSyxHQUFHLElBQUksd0JBQWEsRUFBRSxDQUFDO0lBQ2xDLE1BQU0sV0FBVyxHQUFHLGVBQWUsQ0FBQztJQUNwQyxNQUFNLFdBQVcsR0FBRyxrRUFBa0UsQ0FBQztJQUN2RixNQUFNLFNBQVMsR0FBYztRQUMzQixXQUFXO1FBQ1gsWUFBWSxFQUFFLHNDQUFzQztRQUNwRCxZQUFZLEVBQUU7WUFDWjtnQkFDRSxVQUFVLEVBQUU7b0JBQ1YsZUFBZSxFQUFFLGtCQUFrQjtvQkFDbkMsV0FBVztvQkFDWCxjQUFjLEVBQUUsS0FBSyxFQUFFLDhDQUE4QztpQkFDdEU7Z0JBQ0QsS0FBSyxFQUFFLGtCQUFrQjtnQkFDekIsZUFBZSxFQUFFLEVBQUU7YUFDcEI7U0FDRjtRQUNELFdBQVcsRUFBRSxFQUFFO1FBQ2YsSUFBSSxFQUFFLElBQUksSUFBSSxFQUFFLENBQUMs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QUcsRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFO1FBQzlCLGlFQUFpRTtRQUVqRSxPQUFPO1lBQ0wsV0FBVyxFQUFFLFNBQVMsQ0FBQyxXQUFXO1NBQ25DLENBQUM7SUFDSixDQUFDLENBQUMsQ0FBQztBQUNQLENBQUM7QUFFRCxLQUFLLFVBQVUsaUJBQWlCLENBQUMsU0FBb0I7SUFDbkQsTUFBTSxZQUFZLEdBQUcsSUFBQSxpQkFBUSxFQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3ZDLE9BQU8sSUFBSSxDQUFDLHVCQUF1QixDQUFDO1NBQ2pDLElBQUksQ0FBQyxrQkFBa0IsU0FBUyxDQUFDLFFBQVEsZUFBZSxTQUFTLENBQUMsV0FBVyxHQUFHLFlBQVksT0FBTyxDQUFDO1NBQ3BHLEtBQUssQ0FBQyxDQUFDLENBQUM7U0FDUixLQUFLLENBQUMsR0FBRyxFQUFFO1FBQ1YsV0FBVyxFQUFFLFNBQVMsQ0FBQyxXQUFXO0tBQ25DLENBQUMsQ0FBQztBQUNQLENBQUM7QUFFRCxLQUFLLFVBQVUsd0NBQXdDLENBQ3JELElBQVksRUFDWixZQUFvQixFQUNwQixlQUFrRDtJQUVsRCxNQUFNLHlCQUF5QixHQUFzQjtRQUNuRCxJQUFJLEVBQUUsWUFBWTtRQUNsQixTQUFTLEVBQUUsZUFBZSxDQUFDLFNBQVM7UUFDcEMsY0FBYyxFQUFFLGVBQWUsQ0FBQyxTQUFTO1FBQ3pDLFlBQVk7S0FDYixDQUFDO0lBQ0YsSUFBSSxDQUFDLHVCQUF1QixDQUFDO1NBQzFCLEdBQUcsQ0FBQyxXQUFXLElBQUksYUFBYSxDQUFDO1NBQ2pDLEtBQUssQ0FBQyxDQUFDLENBQUM7U0FDUixLQUFLLENBQUMsRUFBRSxZQUFZLEVBQUUsQ0FBQztTQUN2QixLQUFLLENBQUMsR0FBRyxFQUFFLHlCQUF5QixDQUFDLENBQUM7SUFDekMsT0FBTyx5QkFBeUIsQ0FBQztBQUNuQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSGFzaCB9IGZyb20gJ2NyeXB0byc7XG5pbXBvcnQge1xuICBCYXNlQ29pbixcbiAgQml0Z29HUEdQdWJsaWNLZXksXG4gIGNvbW1vbixcbiAgRUNEU0FVdGlscyxcbiAgUmVxdWVzdFRyYWNlcixcbiAgU2lnbmF0dXJlU2hhcmVSZWNvcmQsXG4gIFNpZ25hdHVyZVNoYXJlVHlwZSxcbiAgVHhSZXF1ZXN0LFxuICBXYWxsZXQsXG59IGZyb20gJ0BiaXRnby9zZGstY29yZSc7XG5pbXBvcnQgeyBEa2xzRHNnLCBEa2xzVHlwZXMsIERrbHNDb21tcyB9IGZyb20gJ0BiaXRnby9zZGstbGliLW1wYyc7XG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgeyBnZXRSb3V0ZSB9IGZyb20gJy4uL2NvbW1vbic7XG5pbXBvcnQge1xuICBNUEN2MlNpZ25hdHVyZVNoYXJlUm91bmQxT3V0cHV0LFxuICBNUEN2MlNpZ25hdHVyZVNoYXJlUm91bmQxSW5wdXQsXG4gIE1QQ3YyU2lnbmF0dXJlU2hhcmVSb3VuZDJJbnB1dCxcbiAgTVBDdjJTaWduYXR1cmVTaGFyZVJvdW5kMk91dHB1dCxcbiAgTVBDdjJTaWduYXR1cmVTaGFyZVJvdW5kM0lucHV0LFxuICBNUEN2MlBhcnR5RnJvbVN0cmluZ09yTnVtYmVyLFxufSBmcm9tICdAYml0Z28vcHVibGljLXR5cGVzJztcbmltcG9ydCAqIGFzIG9wZW5wZ3AgZnJvbSAnb3BlbnBncCc7XG5pbXBvcnQgbm9jayA9IHJlcXVpcmUoJ25vY2snKTtcbmltcG9ydCB7IFRlc3RhYmxlQkcsIFRlc3RCaXRHbyB9IGZyb20gJ0BiaXRnby9zZGstdGVzdCc7XG5pbXBvcnQgeyBCaXRHbyB9IGZyb20gJy4uLy4uLy4uLy4uLy4uLy4uL3NyYyc7XG5jb25zdCBjcmVhdGVLZWNjYWtIYXNoID0gcmVxdWlyZSgna2VjY2FrJyk7XG5cbmludGVyZmFjZSBTaWduYXR1cmVTaGFyZUFwaUJvZHkge1xuICBzaWduYXR1cmVTaGFyZXM6IFNpZ25hdHVyZVNoYXJlUmVjb3JkW107XG4gIHNpZ25lckdwZ1B1YmxpY0tleTogc3RyaW5nO1xufVxuXG5kZXNjcmliZSgnc2lnblR4UmVxdWVzdDonLCBmdW5jdGlvbiAoKSB7XG4gIGxldCB0c3NVdGlsczogRUNEU0FVdGlscy5FY2RzYU1QQ3YyVXRpbHM7XG4gIGxldCB3YWxsZXQ6IFdhbGxldDtcbiAgbGV0IGJpdGdvOiBUZXN0YWJsZUJHICYgQml0R287XG4gIGxldCBiYXNlQ29pbjogQmFzZUNvaW47XG4gIGxldCBiaXRnb0dwZ0tleTogb3BlbnBncC5TZXJpYWxpemVkS2V5UGFpcjxzdHJpbmc+O1xuICBjb25zdCBjb2luTmFtZSA9ICdodGV0aCc7XG5cbiAgY29uc3QgcmVxSWQgPSBuZXcgUmVxdWVzdFRyYWNlcigpO1xuICBjb25zdCB0eFJlcXVlc3RJZCA9ICdyYW5kb21UeFJlcUlkJztcbiAgY29uc3Qgc2lnbmFibGVIZXggPSAnZTI3YWVjYWVhNTU5ZmJlZGM5YWU4YTIyYjBhYjY2NTRjMmQ2ODY0MDNjMmFlYjQzNGIzMDI1NDVjOTRlZWQzYic7XG4gIGNvbnN0IHR4UmVxdWVzdDogVHhSZXF1ZXN0ID0ge1xuICAgIHR4UmVxdWVzdElkLFxuICAgIGVudGVycHJpc2VJZDogJzQ1MTdhYmZiLWY1NjctNGI3YS05ZjkxLTQwNzUwOWQyOTQwMycsXG4gICAgdHJhbnNhY3Rpb25zOiBbXG4gICAgICB7XG4gICAgICAgIHVuc2lnbmVkVHg6IHtcbiAgICAgICAgICBzZXJpYWxpemVkVHhIZXg6ICdUT08gTUFOWSBTRUNSRVRTJyxcbiAgICAgICAgICBzaWduYWJsZUhleCxcbiAgICAgICAgICBkZXJpdmF0aW9uUGF0aDogJ20vMCcsIC8vIE5lZWRzIHRoaXMgd2hlbiBrZXkgZGVyaXZhdGlvbiBpcyBzdXBwb3J0ZWRcbiAgICAgICAgfSxcbiAgICAgICAgc3RhdGU6ICdwZW5kaW5nU2lnbmF0dXJlJyxcbiAgICAgICAgc2lnbmF0dXJlU2hhcmVzOiBbXSxcbiAgICAgIH0sXG4gICAgXSxcbiAgICB1bnNpZ25lZFR4czogW10sXG4gICAgZGF0ZTogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgIGludGVudDoge1xuICAgICAgaW50ZW50VHlwZTogJ3BheW1lbnQnLFxuICAgIH0sXG4gICAgbGF0ZXN0OiB0cnVlLFxuICAgIHN0YXRlOiAncGVuZGluZ1VzZXJTaWduYXR1cmUnLFxuICAgIHdhbGxldFR5cGU6ICdob3QnLFxuICAgIHdhbGxldElkOiAnd2FsbGV0SWQnLFxuICAgIHBvbGljaWVzQ2hlY2tlZDogdHJ1ZSxcbiAgICB2ZXJzaW9uOiAxLFxuICAgIHVzZXJJZDogJ3VzZXJJZCcsXG4gICAgYXBpVmVyc2lvbjogJ2Z1bGwnLFxuICB9O1xuXG4gIGNvbnN0IHR4UmVxdWVzdEZvck1lc3NhZ2VTaWduaW5nOiBUeFJlcXVlc3QgPSB7XG4gICAgdHhSZXF1ZXN0SWQsXG4gICAgZW50ZXJwcmlzZUlkOiAnNDUxN2FiZmItZjU2Ny00YjdhLTlmOTEtNDA3NTA5ZDI5NDAzJyxcbiAgICBtZXNzYWdlczogW1xuICAgICAge1xuICAgICAgICBtZXNzYWdlUmF3OiAnVE9PIE1BTlkgU0VDUkVUUycsXG4gICAgICAgIGRlcml2YXRpb25QYXRoOiAnbS8wJyxcbiAgICAgICAgc3RhdGU6ICdwZW5kaW5nU2lnbmF0dXJlJyxcbiAgICAgICAgc2lnbmF0dXJlU2hhcmVzOiBbXSxcbiAgICAgIH0sXG4gICAgXSxcbiAgICB1bnNpZ25lZFR4czogW10sXG4gICAgZGF0ZTogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgIGludGVudDoge1xuICAgICAgaW50ZW50VHlwZTogJ3BheW1lbnQnLFxuICAgIH0sXG4gICAgbGF0ZXN0OiB0cnVlLFxuICAgIHN0YXRlOiAncGVuZGluZ1VzZXJTaWduYXR1cmUnLFxuICAgIHdhbGxldFR5cGU6ICdob3QnLFxuICAgIHdhbGxldElkOiAnd2FsbGV0SWQnLFxuICAgIHBvbGljaWVzQ2hlY2tlZDogdHJ1ZSxcbiAgICB2ZXJzaW9uOiAxLFxuICAgIHVzZXJJZDogJ3VzZXJJZCcsXG4gICAgYXBpVmVyc2lvbjogJ2Z1bGwnLFxuICB9O1xuXG4gIGNvbnN0IHZlY3RvciA9IHtcbiAgICBwYXJ0eTE6IDAsXG4gICAgcGFydHkyOiAyLFxuICAgIHBhcnR5MzogMSxcbiAgfTtcbiAgLy8gVG8gZ2VuZXJhdGUgdGhlIGZpeHR1cmVzLCBydW4gREtHIGFzIGluIHRoZSBka2xzRGtnLnRzIHRlc3RzIGFuZCBzYXZlIHRoZSByZXN1bHRpbmcgcGFydHkuZ2V0S2V5U2hhcmUgaW4gYSBmaWxlIGJ5IGRvaW5nIGZzLndyaXRlU3luYyhwYXJ0eS5nZXRLZXlTaGFyZSgpKS5cbiAgY29uc3Qgc2hhcmVGaWxlcyA9IFtcbiAgICBgJHtfX2Rpcm5hbWV9L2ZpeHR1cmVzL3VzZXJTaGFyZWAsXG4gICAgYCR7X19kaXJuYW1lfS9maXh0dXJlcy9iYWNrdXBTaGFyZWAsXG4gICAgYCR7X19kaXJuYW1lfS9maXh0dXJlcy9iaXRnb1NoYXJlYCxcbiAgXTtcblxuICBsZXQgYml0Z29QYXJ0eTogRGtsc0RzZy5Ec2c7XG5cbiAgYmVmb3JlKGFzeW5jICgpID0+IHtcbiAgICBiaXRnbyA9IFRlc3RCaXRHby5kZWNvcmF0ZShCaXRHbywgeyBlbnY6ICdtb2NrJyB9KTtcbiAgICBiaXRnby5pbml0aWFsaXplVGVzdFZhcnMoKTtcbiAgICBjb25zdCBiZ1VybCA9IGNvbW1vbi5FbnZpcm9ubWVudHNbYml0Z28uZ2V0RW52KCldLnVyaTtcbiAgICBiaXRnb0dwZ0tleSA9IGF3YWl0IG9wZW5wZ3AuZ2VuZXJhdGVLZXkoe1xuICAgICAgdXNlcklEczogW1xuICAgICAgICB7XG4gICAgICAgICAgbmFtZTogJ2JpdGdvJyxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgICBjdXJ2ZTogJ3NlY3AyNTZrMScsXG4gICAgICBjb25maWc6IHtcbiAgICAgICAgcmVqZWN0Q3VydmVzOiBuZXcgU2V0KCksXG4gICAgICB9LFxuICAgIH0pO1xuICAgIGNvbnN0IGNvbnN0YW50cyA9IHtcbiAgICAgIG1wYzoge1xuICAgICAgICBiaXRnb1B1YmxpY0tleTogYml0Z29HcGdLZXkucHVibGljS2V5LFxuICAgICAgICBiaXRnb01QQ3YyUHVibGljS2V5OiBiaXRnb0dwZ0tleS5wdWJsaWNLZXksXG4gICAgICB9LFxuICAgIH07XG4gICAgbm9jayhiZ1VybCkuZ2V0KCcvYXBpL3YxL2NsaWVudC9jb25zdGFudHMnKS50aW1lcygyMCkucmVwbHkoMjAwLCB7IHR0bDogMzYwMCwgY29uc3RhbnRzIH0pO1xuXG4gICAgYmFzZUNvaW4gPSBiaXRnby5jb2luKGNvaW5OYW1lKTtcblxuICAgIGxldCBoYXNoRm46IEhhc2g7XG4gICAgdHJ5IHtcbiAgICAgIGhhc2hGbiA9IGJhc2VDb2luLmdldEhhc2hGdW5jdGlvbigpO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgaGFzaEZuID0gY3JlYXRlS2VjY2FrSGFzaCgna2VjY2FrMjU2JykgYXMgSGFzaDtcbiAgICB9XG4gICAgY29uc3QgaGFzaEJ1ZmZlciA9IGhhc2hGbi51cGRhdGUoQnVmZmVyLmZyb20oc2lnbmFibGVIZXgsICdoZXgnKSkuZGlnZXN0KCk7XG5cbiAgICAvLyBOb2NrIG91dCBib3RoIHRoZSB1c2VyIGFuZCBiaXRnbyBzaWRlIHJlc3BvbnNlcyB0byBjcmVhdGUgdmFsaWQgc2lnbmF0dXJlc1xuICAgIGJpdGdvUGFydHkgPSBuZXcgRGtsc0RzZy5Ec2coXG4gICAgICBmcy5yZWFkRmlsZVN5bmMoc2hhcmVGaWxlc1t2ZWN0b3IucGFydHkyXSksXG4gICAgICB2ZWN0b3IucGFydHkyLFxuICAgICAgdHhSZXF1ZXN0LnRyYW5zYWN0aW9ucyFbMF0udW5zaWduZWRUeC5kZXJpdmF0aW9uUGF0aCxcbiAgICAgIGhhc2hCdWZmZXJcbiAgICApO1xuICAgIC8vIC8vIFJvdW5kIDEgLy8vL1xuICAgIGNvbnN0IHdhbGxldERhdGEgPSB7XG4gICAgICBpZDogdHhSZXF1ZXN0LndhbGxldElkLFxuICAgICAgZW50ZXJwcmlzZTogdHhSZXF1ZXN0LmVudGVycHJpc2VJZCxcbiAgICAgIGNvaW46IGNvaW5OYW1lLFxuICAgICAgY29pblNwZWNpZmljOiB7fSxcbiAgICAgIG11bHRpc2lnVHlwZTogJ3RzcycsXG4gICAgICBtdWx0aXNpZ1R5cGVWZXJzaW9uOiAnTVBDdjInLFxuICAgIH07XG4gICAgd2FsbGV0ID0gbmV3IFdhbGxldChiaXRnbywgYmFzZUNvaW4sIHdhbGxldERhdGEpO1xuICAgIHRzc1V0aWxzID0gbmV3IEVDRFNBVXRpbHMuRWNkc2FNUEN2MlV0aWxzKGJpdGdvLCBiYXNlQ29pbiwgd2FsbGV0KTtcbiAgfSk7XG5cbiAgYmVmb3JlRWFjaChhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgYXdhaXQgbm9ja0dldEJpdGdvUHVibGljS2V5QmFzZWRPbkZlYXR1cmVGbGFncyhjb2luTmFtZSwgdHhSZXF1ZXN0LmVudGVycHJpc2VJZCEsIGJpdGdvR3BnS2V5KTtcbiAgfSk7XG5cbiAgYWZ0ZXIoZnVuY3Rpb24gKCkge1xuICAgIG5vY2suY2xlYW5BbGwoKTtcbiAgfSk7XG5cbiAgYWZ0ZXJFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICBiaXRnb1BhcnR5LmVuZFNlc3Npb24oKTtcbiAgICBub2NrLmNsZWFuQWxsKCk7XG4gIH0pO1xuXG4gIGl0KCdzdWNjZXNzZnVsbHkgc2lnbnMgYSB0eFJlcXVlc3Qgd2l0aCB1c2VyIGtleSBmb3IgYSBka2xzIGhvdCB3YWxsZXQgd2l0aCBXUCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCBub2NrUHJvbWlzZXMgPSBbXG4gICAgICBhd2FpdCBub2NrVHhSZXF1ZXN0UmVzcG9uc2VTaWduYXR1cmVTaGFyZVJvdW5kT25lKGJpdGdvUGFydHksIHR4UmVxdWVzdCwgYml0Z29HcGdLZXkpLFxuICAgICAgYXdhaXQgbm9ja1R4UmVxdWVzdFJlc3BvbnNlU2lnbmF0dXJlU2hhcmVSb3VuZFR3byhiaXRnb1BhcnR5LCB0eFJlcXVlc3QsIGJpdGdvR3BnS2V5KSxcbiAgICAgIGF3YWl0IG5vY2tUeFJlcXVlc3RSZXNwb25zZVNpZ25hdHVyZVNoYXJlUm91bmRUaHJlZSh0eFJlcXVlc3QpLFxuICAgICAgYXdhaXQgbm9ja1NlbmRUeFJlcXVlc3QodHhSZXF1ZXN0KSxcbiAgICBdO1xuICAgIGF3YWl0IFByb21pc2UuYWxsKG5vY2tQcm9taXNlcyk7XG5cbiAgICBjb25zdCB1c2VyU2hhcmUgPSBmcy5yZWFkRmlsZVN5bmMoc2hhcmVGaWxlc1t2ZWN0b3IucGFydHkxXSk7XG4gICAgY29uc3QgdXNlclBydkJhc2U2NCA9IEJ1ZmZlci5mcm9tKHVzZXJTaGFyZSkudG9TdHJpbmcoJ2Jhc2U2NCcpO1xuICAgIGF3YWl0IHRzc1V0aWxzLnNpZ25UeFJlcXVlc3Qoe1xuICAgICAgdHhSZXF1ZXN0LFxuICAgICAgcHJ2OiB1c2VyUHJ2QmFzZTY0LFxuICAgICAgcmVxSWQsXG4gICAgfSk7XG4gICAgbm9ja1Byb21pc2VzWzBdLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgbm9ja1Byb21pc2VzWzFdLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgbm9ja1Byb21pc2VzWzJdLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gIH0pO1xuXG4gIGl0KCdzdWNjZXNzZnVsbHkgc2lnbnMgYSB0eFJlcXVlc3Qgd2l0aCBiYWNrdXAga2V5IGZvciBhIGRrbHMgaG90IHdhbGxldCB3aXRoIFdQJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IG5vY2tQcm9taXNlcyA9IFtcbiAgICAgIGF3YWl0IG5vY2tUeFJlcXVlc3RSZXNwb25zZVNpZ25hdHVyZVNoYXJlUm91bmRPbmUoYml0Z29QYXJ0eSwgdHhSZXF1ZXN0LCBiaXRnb0dwZ0tleSwgMSksXG4gICAgICBhd2FpdCBub2NrVHhSZXF1ZXN0UmVzcG9uc2VTaWduYXR1cmVTaGFyZVJvdW5kVHdvKGJpdGdvUGFydHksIHR4UmVxdWVzdCwgYml0Z29HcGdLZXksIDEpLFxuICAgICAgYXdhaXQgbm9ja1R4UmVxdWVzdFJlc3BvbnNlU2lnbmF0dXJlU2hhcmVSb3VuZFRocmVlKHR4UmVxdWVzdCksXG4gICAgICBhd2FpdCBub2NrU2VuZFR4UmVxdWVzdCh0eFJlcXVlc3QpLFxuICAgIF07XG4gICAgYXdhaXQgUHJvbWlzZS5hbGwobm9ja1Byb21pc2VzKTtcblxuICAgIGNvbnN0IGJhY2t1cFNoYXJlID0gZnMucmVhZEZpbGVTeW5jKHNoYXJlRmlsZXNbdmVjdG9yLnBhcnR5M10pO1xuICAgIGNvbnN0IGJhY2t1cFBydkJhc2U2NCA9IEJ1ZmZlci5mcm9tKGJhY2t1cFNoYXJlKS50b1N0cmluZygnYmFzZTY0Jyk7XG4gICAgYXdhaXQgdHNzVXRpbHMuc2lnblR4UmVxdWVzdCh7XG4gICAgICB0eFJlcXVlc3QsXG4gICAgICBwcnY6IGJhY2t1cFBydkJhc2U2NCxcbiAgICAgIG1wY3YyUGFydHlJZDogMSxcbiAgICAgIHJlcUlkLFxuICAgIH0pO1xuICAgIG5vY2tQcm9taXNlc1swXS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgIG5vY2tQcm9taXNlc1sxXS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgIG5vY2tQcm9taXNlc1syXS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuICB9KTtcblxuICBpdCgnc3VjY2Vzc2Z1bGx5IHNpZ25zIGEgdHhSZXF1ZXN0IHdpdGggYSBtZXNzYWdlIGZvciBhIGRrbHMgaG90IHdhbGxldCB3aXRoIFdQJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IG5vY2tQcm9taXNlcyA9IFtcbiAgICAgIGF3YWl0IG5vY2tUeFJlcXVlc3RSZXNwb25zZVNpZ25hdHVyZVNoYXJlUm91bmRPbmUoYml0Z29QYXJ0eSwgdHhSZXF1ZXN0Rm9yTWVzc2FnZVNpZ25pbmcsIGJpdGdvR3BnS2V5KSxcbiAgICAgIGF3YWl0IG5vY2tUeFJlcXVlc3RSZXNwb25zZVNpZ25hdHVyZVNoYXJlUm91bmRUd28oYml0Z29QYXJ0eSwgdHhSZXF1ZXN0Rm9yTWVzc2FnZVNpZ25pbmcsIGJpdGdvR3BnS2V5KSxcbiAgICAgIGF3YWl0IG5vY2tUeFJlcXVlc3RSZXNwb25zZVNpZ25hdHVyZVNoYXJlUm91bmRUaHJlZSh0eFJlcXVlc3RGb3JNZXNzYWdlU2lnbmluZyksXG4gICAgICBhd2FpdCBub2NrU2VuZFR4UmVxdWVzdCh0eFJlcXVlc3RGb3JNZXNzYWdlU2lnbmluZyksXG4gICAgXTtcbiAgICBhd2FpdCBQcm9taXNlLmFsbChub2NrUHJvbWlzZXMpO1xuXG4gICAgY29uc3QgdXNlclNoYXJlID0gZnMucmVhZEZpbGVTeW5jKHNoYXJlRmlsZXNbdmVjdG9yLnBhcnR5MV0pO1xuICAgIGNvbnN0IHVzZXJQcnZCYXNlNjQgPSBCdWZmZXIuZnJvbSh1c2VyU2hhcmUpLnRvU3RyaW5nKCdiYXNlNjQnKTtcbiAgICBhd2FpdCB0c3NVdGlscy5zaWduVHhSZXF1ZXN0KHtcbiAgICAgIHR4UmVxdWVzdCxcbiAgICAgIHBydjogdXNlclBydkJhc2U2NCxcbiAgICAgIHJlcUlkLFxuICAgIH0pO1xuICAgIG5vY2tQcm9taXNlc1swXS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgIG5vY2tQcm9taXNlc1sxXS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgIG5vY2tQcm9taXNlc1syXS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuICB9KTtcblxuICBpdCgnc3VjY2Vzc2Z1bGx5IHNpZ25zIGEgdHhSZXF1ZXN0IGZvciBhIGRrbHMgaG90IHdhbGxldCBhZnRlciByZWNlaXZpbmcgbXVsdGlwbGUgNDI5IGVycm9ycycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCBub2NrUHJvbWlzZXMgPSBbXG4gICAgICBhd2FpdCBub2NrVHhSZXF1ZXN0UmVzcG9uc2VTaWduYXR1cmVTaGFyZVJvdW5kT25lKGJpdGdvUGFydHksIHR4UmVxdWVzdCwgYml0Z29HcGdLZXkpLFxuICAgICAgYXdhaXQgbm9ja1R4UmVxdWVzdFJlc3BvbnNlU2lnbmF0dXJlU2hhcmVSb3VuZFR3byhiaXRnb1BhcnR5LCB0eFJlcXVlc3QsIGJpdGdvR3BnS2V5LCAwLCAzKSxcbiAgICAgIGF3YWl0IG5vY2tUeFJlcXVlc3RSZXNwb25zZVNpZ25hdHVyZVNoYXJlUm91bmRUaHJlZSh0eFJlcXVlc3QpLFxuICAgICAgYXdhaXQgbm9ja1NlbmRUeFJlcXVlc3QodHhSZXF1ZXN0KSxcbiAgICBdO1xuICAgIGF3YWl0IFByb21pc2UuYWxsKG5vY2tQcm9taXNlcyk7XG5cbiAgICBjb25zdCB1c2VyU2hhcmUgPSBmcy5yZWFkRmlsZVN5bmMoc2hhcmVGaWxlc1t2ZWN0b3IucGFydHkxXSk7XG4gICAgY29uc3QgdXNlclBydkJhc2U2NCA9IEJ1ZmZlci5mcm9tKHVzZXJTaGFyZSkudG9TdHJpbmcoJ2Jhc2U2NCcpO1xuICAgIGF3YWl0IHRzc1V0aWxzLnNpZ25UeFJlcXVlc3Qoe1xuICAgICAgdHhSZXF1ZXN0LFxuICAgICAgcHJ2OiB1c2VyUHJ2QmFzZTY0LFxuICAgICAgcmVxSWQsXG4gICAgfSk7XG4gICAgbm9ja1Byb21pc2VzWzBdLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgbm9ja1Byb21pc2VzWzFdLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgbm9ja1Byb21pc2VzWzJdLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gIH0pO1xuXG4gIGl0KCdmYWlscyB0byBzaWducyBhIHR4UmVxdWVzdCBmb3IgYSBka2xzIGhvdCB3YWxsZXQgYWZ0ZXIgcmVjZWl2aW5nIG92ZXIgMyA0MjkgZXJyb3JzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IG5vY2tQcm9taXNlcyA9IFtcbiAgICAgIGF3YWl0IG5vY2tUeFJlcXVlc3RSZXNwb25zZVNpZ25hdHVyZVNoYXJlUm91bmRPbmUoYml0Z2