@bitgo-beta/sdk-coin-avaxp 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +5 -0
- package/.eslintrc.json +7 -0
- package/.mocharc.yml +8 -0
- package/CHANGELOG.md +168 -0
- package/LICENSE +191 -0
- package/README.md +39 -0
- package/dist/src/avaxp.d.ts +69 -0
- package/dist/src/avaxp.d.ts.map +1 -0
- package/dist/src/avaxp.js +248 -0
- package/dist/src/iface.d.ts +43 -0
- package/dist/src/iface.d.ts.map +1 -0
- package/dist/src/iface.js +3 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +30 -0
- package/dist/src/lib/atomicTransactionBuilder.d.ts +33 -0
- package/dist/src/lib/atomicTransactionBuilder.d.ts.map +1 -0
- package/dist/src/lib/atomicTransactionBuilder.js +122 -0
- package/dist/src/lib/delegatorTxBuilder.d.ts +96 -0
- package/dist/src/lib/delegatorTxBuilder.d.ts.map +1 -0
- package/dist/src/lib/delegatorTxBuilder.js +287 -0
- package/dist/src/lib/errors.d.ts +8 -0
- package/dist/src/lib/errors.d.ts.map +1 -0
- package/dist/src/lib/errors.js +19 -0
- package/dist/src/lib/exportTxBuilder.d.ts +34 -0
- package/dist/src/lib/exportTxBuilder.d.ts.map +1 -0
- package/dist/src/lib/exportTxBuilder.js +88 -0
- package/dist/src/lib/iface.d.ts +58 -0
- package/dist/src/lib/iface.d.ts.map +1 -0
- package/dist/src/lib/iface.js +18 -0
- package/dist/src/lib/importInCTxBuilder.d.ts +48 -0
- package/dist/src/lib/importInCTxBuilder.d.ts.map +1 -0
- package/dist/src/lib/importInCTxBuilder.js +152 -0
- package/dist/src/lib/importTxBuilder.d.ts +18 -0
- package/dist/src/lib/importTxBuilder.d.ts.map +1 -0
- package/dist/src/lib/importTxBuilder.js +67 -0
- package/dist/src/lib/index.d.ts +9 -0
- package/dist/src/lib/index.d.ts.map +1 -0
- package/dist/src/lib/index.js +29 -0
- package/dist/src/lib/keyPair.d.ts +59 -0
- package/dist/src/lib/keyPair.d.ts.map +1 -0
- package/dist/src/lib/keyPair.js +151 -0
- package/dist/src/lib/transaction.d.ts +81 -0
- package/dist/src/lib/transaction.d.ts.map +1 -0
- package/dist/src/lib/transaction.js +277 -0
- package/dist/src/lib/transactionBuilder.d.ts +122 -0
- package/dist/src/lib/transactionBuilder.d.ts.map +1 -0
- package/dist/src/lib/transactionBuilder.js +224 -0
- package/dist/src/lib/transactionBuilderFactory.d.ts +42 -0
- package/dist/src/lib/transactionBuilderFactory.d.ts.map +1 -0
- package/dist/src/lib/transactionBuilderFactory.js +107 -0
- package/dist/src/lib/transferBuilder.d.ts +18 -0
- package/dist/src/lib/transferBuilder.d.ts.map +1 -0
- package/dist/src/lib/transferBuilder.js +31 -0
- package/dist/src/lib/utils.d.ts +152 -0
- package/dist/src/lib/utils.d.ts.map +1 -0
- package/dist/src/lib/utils.js +300 -0
- package/dist/src/lib/utxoEngine.d.ts +45 -0
- package/dist/src/lib/utxoEngine.d.ts.map +1 -0
- package/dist/src/lib/utxoEngine.js +89 -0
- package/dist/src/lib/validatorTxBuilder.d.ts +37 -0
- package/dist/src/lib/validatorTxBuilder.d.ts.map +1 -0
- package/dist/src/lib/validatorTxBuilder.js +69 -0
- package/dist/src/tavaxp.d.ts +9 -0
- package/dist/src/tavaxp.d.ts.map +1 -0
- package/dist/src/tavaxp.js +14 -0
- package/dist/test/resources/avaxp.d.ts +178 -0
- package/dist/test/resources/avaxp.d.ts.map +1 -0
- package/dist/test/resources/avaxp.js +953 -0
- package/dist/test/resources/errors.d.ts +18 -0
- package/dist/test/resources/errors.d.ts.map +1 -0
- package/dist/test/resources/errors.js +21 -0
- package/dist/test/resources/keychains.d.ts +18 -0
- package/dist/test/resources/keychains.d.ts.map +1 -0
- package/dist/test/resources/keychains.js +30 -0
- package/dist/test/resources/tx/importC.d.ts +29 -0
- package/dist/test/resources/tx/importC.d.ts.map +1 -0
- package/dist/test/resources/tx/importC.js +42 -0
- package/dist/test/resources/tx/importP.d.ts +29 -0
- package/dist/test/resources/tx/importP.d.ts.map +1 -0
- package/dist/test/resources/tx/importP.js +42 -0
- package/dist/test/unit/avaxp.d.ts +2 -0
- package/dist/test/unit/avaxp.d.ts.map +1 -0
- package/dist/test/unit/avaxp.js +553 -0
- package/dist/test/unit/lib/exportP2CTxBuilder.d.ts +2 -0
- package/dist/test/unit/lib/exportP2CTxBuilder.d.ts.map +1 -0
- package/dist/test/unit/lib/exportP2CTxBuilder.js +173 -0
- package/dist/test/unit/lib/importC2PTxBuilder.d.ts +2 -0
- package/dist/test/unit/lib/importC2PTxBuilder.d.ts.map +1 -0
- package/dist/test/unit/lib/importC2PTxBuilder.js +85 -0
- package/dist/test/unit/lib/importP2CTxBuilder.d.ts +2 -0
- package/dist/test/unit/lib/importP2CTxBuilder.d.ts.map +1 -0
- package/dist/test/unit/lib/importP2CTxBuilder.js +125 -0
- package/dist/test/unit/lib/keyPair.d.ts +2 -0
- package/dist/test/unit/lib/keyPair.d.ts.map +1 -0
- package/dist/test/unit/lib/keyPair.js +172 -0
- package/dist/test/unit/lib/signFlowTestSuit.d.ts +20 -0
- package/dist/test/unit/lib/signFlowTestSuit.d.ts.map +1 -0
- package/dist/test/unit/lib/signFlowTestSuit.js +80 -0
- package/dist/test/unit/lib/transactionBuilderFactory.d.ts +2 -0
- package/dist/test/unit/lib/transactionBuilderFactory.d.ts.map +1 -0
- package/dist/test/unit/lib/transactionBuilderFactory.js +114 -0
- package/dist/test/unit/lib/utils.d.ts +2 -0
- package/dist/test/unit/lib/utils.d.ts.map +1 -0
- package/dist/test/unit/lib/utils.js +69 -0
- package/dist/test/unit/lib/utxoEngine.d.ts +2 -0
- package/dist/test/unit/lib/utxoEngine.d.ts.map +1 -0
- package/dist/test/unit/lib/utxoEngine.js +168 -0
- package/dist/test/unit/lib/validateTxBuilder.d.ts +2 -0
- package/dist/test/unit/lib/validateTxBuilder.d.ts.map +1 -0
- package/dist/test/unit/lib/validateTxBuilder.js +318 -0
- package/dist/tsconfig.tsbuildinfo +10238 -0
- package/package.json +62 -0
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
+
}) : function(o, v) {
|
|
12
|
+
o["default"] = v;
|
|
13
|
+
});
|
|
14
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
+
if (mod && mod.__esModule) return mod;
|
|
16
|
+
var result = {};
|
|
17
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
+
__setModuleDefault(result, mod);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
const AvaxpLib = __importStar(require("../../src/lib"));
|
|
23
|
+
const sdk_test_1 = require("@bitgo-beta/sdk-test");
|
|
24
|
+
const src_1 = require("../../src/");
|
|
25
|
+
const crypto_1 = require("crypto");
|
|
26
|
+
const should = __importStar(require("should"));
|
|
27
|
+
const sdk_api_1 = require("@bitgo-beta/sdk-api");
|
|
28
|
+
const statics_1 = require("@bitgo-beta/statics");
|
|
29
|
+
const testData = __importStar(require("../resources/avaxp"));
|
|
30
|
+
const keychains_1 = require("../resources/keychains");
|
|
31
|
+
const utils_1 = require("../../src/lib/utils");
|
|
32
|
+
const keyPair_1 = require("../../src/lib/keyPair");
|
|
33
|
+
const avalanche_1 = require("avalanche");
|
|
34
|
+
const _ = __importStar(require("lodash"));
|
|
35
|
+
const sdk_core_1 = require("@bitgo-beta/sdk-core");
|
|
36
|
+
const importP_1 = require("../resources/tx/importP");
|
|
37
|
+
const avaxp_1 = require("../resources/avaxp");
|
|
38
|
+
const importC_1 = require("../resources/tx/importC");
|
|
39
|
+
describe('Avaxp', function () {
|
|
40
|
+
const coinName = 'avaxp';
|
|
41
|
+
const tcoinName = 't' + coinName;
|
|
42
|
+
let bitgo;
|
|
43
|
+
let basecoin;
|
|
44
|
+
let newTxPrebuild;
|
|
45
|
+
let newTxParams;
|
|
46
|
+
const txPrebuild = {
|
|
47
|
+
txHex: testData.ADDVALIDATOR_SAMPLES.unsignedTxHex,
|
|
48
|
+
txInfo: {},
|
|
49
|
+
};
|
|
50
|
+
const txParams = {
|
|
51
|
+
recipients: [],
|
|
52
|
+
type: 'AddValidator',
|
|
53
|
+
stakingOptions: {
|
|
54
|
+
startTime: testData.ADDVALIDATOR_SAMPLES.startTime,
|
|
55
|
+
endTime: testData.ADDVALIDATOR_SAMPLES.endTime,
|
|
56
|
+
nodeID: testData.ADDVALIDATOR_SAMPLES.nodeID,
|
|
57
|
+
amount: testData.ADDVALIDATOR_SAMPLES.minValidatorStake,
|
|
58
|
+
delegationFeeRate: testData.ADDVALIDATOR_SAMPLES.delegationFee,
|
|
59
|
+
},
|
|
60
|
+
locktime: 0,
|
|
61
|
+
memo: {
|
|
62
|
+
value: testData.ADDVALIDATOR_SAMPLES.memo,
|
|
63
|
+
type: 'text',
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
before(function () {
|
|
67
|
+
bitgo = sdk_test_1.TestBitGo.decorate(sdk_api_1.BitGoAPI, {
|
|
68
|
+
env: 'mock',
|
|
69
|
+
});
|
|
70
|
+
bitgo.initializeTestVars();
|
|
71
|
+
bitgo.safeRegister(coinName, src_1.AvaxP.createInstance);
|
|
72
|
+
bitgo.safeRegister(tcoinName, src_1.TavaxP.createInstance);
|
|
73
|
+
basecoin = bitgo.coin(tcoinName);
|
|
74
|
+
newTxPrebuild = () => {
|
|
75
|
+
return _.cloneDeep(txPrebuild);
|
|
76
|
+
};
|
|
77
|
+
newTxParams = () => {
|
|
78
|
+
return _.cloneDeep(txParams);
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
it('should instantiate the coin', function () {
|
|
82
|
+
let localBasecoin = bitgo.coin(tcoinName);
|
|
83
|
+
localBasecoin.should.be.an.instanceof(src_1.TavaxP);
|
|
84
|
+
localBasecoin = bitgo.coin(coinName);
|
|
85
|
+
localBasecoin.should.be.an.instanceof(src_1.AvaxP);
|
|
86
|
+
});
|
|
87
|
+
it('should return ' + tcoinName, function () {
|
|
88
|
+
basecoin.getChain().should.equal(tcoinName);
|
|
89
|
+
});
|
|
90
|
+
it('should return full name', function () {
|
|
91
|
+
basecoin.getFullName().should.equal('Testnet Avalanche P-Chain');
|
|
92
|
+
});
|
|
93
|
+
describe('Keypairs:', () => {
|
|
94
|
+
it('should generate a keypair from random seed', function () {
|
|
95
|
+
const keyPair = basecoin.generateKeyPair();
|
|
96
|
+
keyPair.should.have.property('pub');
|
|
97
|
+
keyPair.should.have.property('prv');
|
|
98
|
+
});
|
|
99
|
+
it('should generate a keypair from a seed', function () {
|
|
100
|
+
const seedText = testData.SEED_ACCOUNT.seed;
|
|
101
|
+
const seed = Buffer.from(seedText, 'hex');
|
|
102
|
+
const keyPair = basecoin.generateKeyPair(seed);
|
|
103
|
+
keyPair.pub.should.equal(testData.SEED_ACCOUNT.publicKey);
|
|
104
|
+
keyPair.prv.should.equal(testData.SEED_ACCOUNT.privateKey);
|
|
105
|
+
});
|
|
106
|
+
it('should validate a public key', function () {
|
|
107
|
+
const keyPair = basecoin.generateKeyPair();
|
|
108
|
+
keyPair.should.have.property('pub');
|
|
109
|
+
keyPair.should.have.property('prv');
|
|
110
|
+
basecoin.isValidPub(keyPair.pub).should.equal(true);
|
|
111
|
+
});
|
|
112
|
+
it('should validate a private key', function () {
|
|
113
|
+
const keyPair = basecoin.generateKeyPair();
|
|
114
|
+
keyPair.should.have.property('pub');
|
|
115
|
+
keyPair.should.have.property('prv');
|
|
116
|
+
basecoin.isValidPrv(keyPair.prv).should.equal(true);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
describe('Sign Transaction', () => {
|
|
120
|
+
const factory = new AvaxpLib.TransactionBuilderFactory(statics_1.coins.get(tcoinName));
|
|
121
|
+
it('build and sign a transaction in regular mode', async () => {
|
|
122
|
+
var _a, _b;
|
|
123
|
+
const recoveryMode = false;
|
|
124
|
+
const txBuilder = new AvaxpLib.TransactionBuilderFactory(statics_1.coins.get(tcoinName))
|
|
125
|
+
.getValidatorBuilder()
|
|
126
|
+
.threshold(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.threshold)
|
|
127
|
+
.locktime(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.locktime)
|
|
128
|
+
.recoverMode(recoveryMode)
|
|
129
|
+
.fromPubKey(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.bitgoAddresses)
|
|
130
|
+
.startTime(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.startTime)
|
|
131
|
+
.endTime(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.endTime)
|
|
132
|
+
.stakeAmount(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.stakeAmount)
|
|
133
|
+
.delegationFeeRate(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.delegationFeeRate)
|
|
134
|
+
.nodeID(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.nodeId)
|
|
135
|
+
.memo(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.memo)
|
|
136
|
+
.utxos(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.utxos);
|
|
137
|
+
const tx = await txBuilder.build();
|
|
138
|
+
let txHex = tx.toBroadcastFormat();
|
|
139
|
+
txHex.should.equal(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.unsignedRawTxNonRecovery);
|
|
140
|
+
const privateKey = recoveryMode
|
|
141
|
+
? testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.backupPrivateKey
|
|
142
|
+
: testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.userPrivateKey;
|
|
143
|
+
const params = {
|
|
144
|
+
txPrebuild: {
|
|
145
|
+
txHex: tx.toBroadcastFormat(),
|
|
146
|
+
},
|
|
147
|
+
prv: privateKey,
|
|
148
|
+
};
|
|
149
|
+
const halfSignedTransaction = await basecoin.signTransaction(params);
|
|
150
|
+
txHex = (_b = (_a = halfSignedTransaction) === null || _a === void 0 ? void 0 : _a.halfSigned) === null || _b === void 0 ? void 0 : _b.txHex;
|
|
151
|
+
txHex.should.equal(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.halfSignedRawTxNonRecovery);
|
|
152
|
+
});
|
|
153
|
+
it('build and sign a transaction in recovery mode', async () => {
|
|
154
|
+
var _a, _b;
|
|
155
|
+
const recoveryMode = true;
|
|
156
|
+
const txBuilder = new AvaxpLib.TransactionBuilderFactory(statics_1.coins.get(tcoinName))
|
|
157
|
+
.getValidatorBuilder()
|
|
158
|
+
.threshold(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.threshold)
|
|
159
|
+
.locktime(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.locktime)
|
|
160
|
+
.recoverMode(recoveryMode)
|
|
161
|
+
.fromPubKey(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.bitgoAddresses)
|
|
162
|
+
.startTime(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.startTime)
|
|
163
|
+
.endTime(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.endTime)
|
|
164
|
+
.stakeAmount(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.stakeAmount)
|
|
165
|
+
.delegationFeeRate(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.delegationFeeRate)
|
|
166
|
+
.nodeID(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.nodeId)
|
|
167
|
+
.memo(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.memo)
|
|
168
|
+
.utxos(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.utxos);
|
|
169
|
+
const tx = await txBuilder.build();
|
|
170
|
+
let txHex = tx.toBroadcastFormat();
|
|
171
|
+
txHex.should.equal(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.unsignedRawtxRecovery);
|
|
172
|
+
const privateKey = recoveryMode
|
|
173
|
+
? testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.backupPrivateKey
|
|
174
|
+
: testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.userPrivateKey;
|
|
175
|
+
const params = {
|
|
176
|
+
txPrebuild: {
|
|
177
|
+
txHex: tx.toBroadcastFormat(),
|
|
178
|
+
},
|
|
179
|
+
prv: privateKey,
|
|
180
|
+
};
|
|
181
|
+
const halfSignedTransaction = await basecoin.signTransaction(params);
|
|
182
|
+
txHex = (_b = (_a = halfSignedTransaction) === null || _a === void 0 ? void 0 : _a.halfSigned) === null || _b === void 0 ? void 0 : _b.txHex;
|
|
183
|
+
txHex.should.equal(testData.BUILD_AND_SIGN_ADD_VALIDATOR_SAMPLE.halfSignedRawTxRecovery);
|
|
184
|
+
});
|
|
185
|
+
it('should be rejected if invalid key', async () => {
|
|
186
|
+
const invalidPrivateKey = 'AAAAA';
|
|
187
|
+
const builder = factory.from(testData.ADDVALIDATOR_SAMPLES.unsignedTxHex);
|
|
188
|
+
const tx = await builder.build();
|
|
189
|
+
const params = {
|
|
190
|
+
txPrebuild: {
|
|
191
|
+
txHex: tx.toBroadcastFormat(),
|
|
192
|
+
},
|
|
193
|
+
prv: invalidPrivateKey,
|
|
194
|
+
};
|
|
195
|
+
await basecoin.signTransaction(params).should.be.rejected();
|
|
196
|
+
});
|
|
197
|
+
it('should return the same mainnet address', () => {
|
|
198
|
+
const utils = new utils_1.Utils();
|
|
199
|
+
const xprv = testData.SEED_ACCOUNT.xPrivateKey;
|
|
200
|
+
const kp1 = new keyPair_1.KeyPair({ prv: xprv });
|
|
201
|
+
const addressBuffer1 = kp1.getAddressBuffer();
|
|
202
|
+
const address1 = utils.addressToString('avax', 'P', avalanche_1.Buffer.from(addressBuffer1));
|
|
203
|
+
const kp2 = new keyPair_1.KeyPair({ prv: xprv });
|
|
204
|
+
const addressBuffer2 = kp2.getAddressSafeBuffer();
|
|
205
|
+
const address2 = utils.addressToString('avax', 'P', avalanche_1.Buffer.from(addressBuffer2));
|
|
206
|
+
const kp3 = new keyPair_1.KeyPair({ prv: xprv });
|
|
207
|
+
const address3 = kp3.getAvaxPAddress('avax');
|
|
208
|
+
address1.should.equal(address2);
|
|
209
|
+
address1.should.equal(address3);
|
|
210
|
+
});
|
|
211
|
+
it('should return the same testnet address', () => {
|
|
212
|
+
const utils = new utils_1.Utils();
|
|
213
|
+
const xprv = testData.SEED_ACCOUNT.xPrivateKey;
|
|
214
|
+
const kp1 = new keyPair_1.KeyPair({ prv: xprv });
|
|
215
|
+
const addressBuffer1 = kp1.getAddressBuffer();
|
|
216
|
+
const address1 = utils.addressToString('fuji', 'P', avalanche_1.Buffer.from(addressBuffer1));
|
|
217
|
+
const kp2 = new keyPair_1.KeyPair({ prv: xprv });
|
|
218
|
+
const addressBuffer2 = kp2.getAddressSafeBuffer();
|
|
219
|
+
const address2 = utils.addressToString('fuji', 'P', avalanche_1.Buffer.from(addressBuffer2));
|
|
220
|
+
const kp3 = new keyPair_1.KeyPair({ prv: xprv });
|
|
221
|
+
const address3 = kp3.getAvaxPAddress('fuji');
|
|
222
|
+
address1.should.equal(address2);
|
|
223
|
+
address1.should.equal(address3);
|
|
224
|
+
});
|
|
225
|
+
it('should not be the same address from same key', () => {
|
|
226
|
+
const utils = new utils_1.Utils();
|
|
227
|
+
const kp1 = new keyPair_1.KeyPair({ prv: testData.ACCOUNT_1.privkey });
|
|
228
|
+
const addressBuffer1 = kp1.getAddressBuffer();
|
|
229
|
+
const address1 = utils.addressToString('avax', 'P', avalanche_1.Buffer.from(addressBuffer1));
|
|
230
|
+
const kp2 = new keyPair_1.KeyPair({ prv: testData.ACCOUNT_1.privkey });
|
|
231
|
+
const addressBuffer2 = kp2.getAddressSafeBuffer();
|
|
232
|
+
const address2 = utils.addressToString('fuji', 'P', avalanche_1.Buffer.from(addressBuffer2));
|
|
233
|
+
address1.should.not.equal(address2);
|
|
234
|
+
});
|
|
235
|
+
it('should not be the same address from different keys', () => {
|
|
236
|
+
const utils = new utils_1.Utils();
|
|
237
|
+
const kp1 = new keyPair_1.KeyPair({ prv: testData.ACCOUNT_1.privkey });
|
|
238
|
+
const addressBuffer1 = kp1.getAddressBuffer();
|
|
239
|
+
const address1 = utils.addressToString('avax', 'P', avalanche_1.Buffer.from(addressBuffer1));
|
|
240
|
+
const kp2 = new keyPair_1.KeyPair({ prv: testData.ACCOUNT_3.privkey });
|
|
241
|
+
const addressBuffer2 = kp2.getAddressSafeBuffer();
|
|
242
|
+
const address2 = utils.addressToString('avax', 'P', avalanche_1.Buffer.from(addressBuffer2));
|
|
243
|
+
address1.should.not.equal(address2);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
describe('Sign Message', () => {
|
|
247
|
+
it('should be performed', async () => {
|
|
248
|
+
const keyPairToSign = new AvaxpLib.KeyPair();
|
|
249
|
+
const prvKey = keyPairToSign.getPrivateKey();
|
|
250
|
+
const keyPair = keyPairToSign.getKeys();
|
|
251
|
+
const messageToSign = Buffer.from(crypto_1.randomBytes(32));
|
|
252
|
+
const signature = await basecoin.signMessage(keyPair, messageToSign.toString('hex'));
|
|
253
|
+
const verify = AvaxpLib.Utils.verifySignature(basecoin._staticsCoin.network, messageToSign, signature, prvKey);
|
|
254
|
+
verify.should.be.true();
|
|
255
|
+
});
|
|
256
|
+
it('should fail with missing private key', async () => {
|
|
257
|
+
const keyPair = new AvaxpLib.KeyPair({
|
|
258
|
+
pub: testData.SEED_ACCOUNT.publicKeyCb58,
|
|
259
|
+
}).getKeys();
|
|
260
|
+
const messageToSign = Buffer.from(crypto_1.randomBytes(32)).toString('hex');
|
|
261
|
+
await basecoin.signMessage(keyPair, messageToSign).should.be.rejectedWith('Invalid key pair options');
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
describe('Explain Transaction', () => {
|
|
265
|
+
it('should explain a half signed AddValidator transaction', async () => {
|
|
266
|
+
const testData = avaxp_1.ADDVALIDATOR_SAMPLES;
|
|
267
|
+
const txExplain = await basecoin.explainTransaction({ halfSigned: { txHex: testData.halfsigntxHex } });
|
|
268
|
+
txExplain.outputAmount.should.equal(testData.minValidatorStake);
|
|
269
|
+
txExplain.type.should.equal(sdk_core_1.TransactionType.AddValidator);
|
|
270
|
+
txExplain.outputs[0].address.should.equal(testData.nodeID);
|
|
271
|
+
txExplain.changeOutputs[0].address.split('~').length.should.equal(3);
|
|
272
|
+
txExplain.memo.should.equal(testData.memo);
|
|
273
|
+
});
|
|
274
|
+
it('should explain a signed AddValidator transaction', async () => {
|
|
275
|
+
const testData = avaxp_1.ADDVALIDATOR_SAMPLES;
|
|
276
|
+
const txExplain = await basecoin.explainTransaction({ txHex: testData.fullsigntxHex });
|
|
277
|
+
txExplain.outputAmount.should.equal(testData.minValidatorStake);
|
|
278
|
+
txExplain.type.should.equal(sdk_core_1.TransactionType.AddValidator);
|
|
279
|
+
txExplain.outputs[0].address.should.equal(testData.nodeID);
|
|
280
|
+
txExplain.changeOutputs[0].address.split('~').length.should.equal(3);
|
|
281
|
+
txExplain.memo.should.equal(testData.memo);
|
|
282
|
+
});
|
|
283
|
+
it('should explain a half signed export transaction', async () => {
|
|
284
|
+
const testData = avaxp_1.EXPORT_P_2_C;
|
|
285
|
+
const txExplain = await basecoin.explainTransaction({ halfSigned: { txHex: testData.halfsigntxHex } });
|
|
286
|
+
txExplain.outputAmount.should.equal(testData.amount);
|
|
287
|
+
txExplain.type.should.equal(sdk_core_1.TransactionType.Export);
|
|
288
|
+
txExplain.outputs[0].address.should.equal(testData.pAddresses.sort().join('~'));
|
|
289
|
+
txExplain.changeOutputs[0].address.should.equal(testData.pAddresses.sort().join('~'));
|
|
290
|
+
txExplain.memo.should.equal(testData.memo);
|
|
291
|
+
});
|
|
292
|
+
it('should explain a signed export transaction', async () => {
|
|
293
|
+
const testData = avaxp_1.EXPORT_P_2_C;
|
|
294
|
+
const txExplain = await basecoin.explainTransaction({ txHex: testData.fullsigntxHex });
|
|
295
|
+
txExplain.outputAmount.should.equal(testData.amount);
|
|
296
|
+
txExplain.type.should.equal(sdk_core_1.TransactionType.Export);
|
|
297
|
+
txExplain.outputs[0].address.should.equal(testData.pAddresses.sort().join('~'));
|
|
298
|
+
txExplain.changeOutputs[0].address.should.equal(testData.pAddresses.sort().join('~'));
|
|
299
|
+
txExplain.memo.should.equal(testData.memo);
|
|
300
|
+
});
|
|
301
|
+
it('should explain a half signed export transaction without cahngeoutput ', async () => {
|
|
302
|
+
const testData = avaxp_1.EXPORT_P_2_C_WITHOUT_CHANGEOUTPUT;
|
|
303
|
+
const txExplain = await basecoin.explainTransaction({
|
|
304
|
+
halfSigned: { txHex: testData.halfsigntxHex },
|
|
305
|
+
});
|
|
306
|
+
txExplain.outputAmount.should.equal(testData.amount);
|
|
307
|
+
txExplain.type.should.equal(sdk_core_1.TransactionType.Export);
|
|
308
|
+
txExplain.outputs[0].address.should.equal(testData.pAddresses.sort().join('~'));
|
|
309
|
+
txExplain.changeOutputs.should.be.empty();
|
|
310
|
+
txExplain.memo.should.equal(testData.memo);
|
|
311
|
+
});
|
|
312
|
+
it('should explain a signed export transaction without cahngeoutput ', async () => {
|
|
313
|
+
const testData = avaxp_1.EXPORT_P_2_C_WITHOUT_CHANGEOUTPUT;
|
|
314
|
+
const txExplain = await basecoin.explainTransaction({ txHex: testData.fullsigntxHex });
|
|
315
|
+
txExplain.outputAmount.should.equal(testData.amount);
|
|
316
|
+
txExplain.type.should.equal(sdk_core_1.TransactionType.Export);
|
|
317
|
+
txExplain.outputs[0].address.should.equal(testData.pAddresses.sort().join('~'));
|
|
318
|
+
txExplain.changeOutputs.should.be.empty();
|
|
319
|
+
txExplain.memo.should.equal(testData.memo);
|
|
320
|
+
});
|
|
321
|
+
it('should explain a half signed import transaction', async () => {
|
|
322
|
+
var _a;
|
|
323
|
+
const testData = importP_1.IMPORT_P;
|
|
324
|
+
const txExplain = await basecoin.explainTransaction({
|
|
325
|
+
halfSigned: { txHex: testData.halfsigntxHex },
|
|
326
|
+
});
|
|
327
|
+
txExplain.outputAmount.should.equal((Number(testData.amount) - ((_a = txExplain.fee) === null || _a === void 0 ? void 0 : _a.fee)).toString());
|
|
328
|
+
txExplain.type.should.equal(sdk_core_1.TransactionType.Import);
|
|
329
|
+
txExplain.outputs[0].address.should.equal(testData.pAddresses.sort().join('~'));
|
|
330
|
+
txExplain.changeOutputs.should.be.empty();
|
|
331
|
+
txExplain.memo.should.equal(testData.memo);
|
|
332
|
+
});
|
|
333
|
+
it('should explain a signed import transaction', async () => {
|
|
334
|
+
var _a;
|
|
335
|
+
const testData = importP_1.IMPORT_P;
|
|
336
|
+
const txExplain = await basecoin.explainTransaction({ txHex: testData.fullsigntxHex });
|
|
337
|
+
txExplain.outputAmount.should.equal((Number(testData.amount) - ((_a = txExplain.fee) === null || _a === void 0 ? void 0 : _a.fee)).toString());
|
|
338
|
+
txExplain.type.should.equal(sdk_core_1.TransactionType.Import);
|
|
339
|
+
txExplain.outputs[0].address.should.equal(testData.pAddresses.sort().join('~'));
|
|
340
|
+
txExplain.changeOutputs.should.be.empty();
|
|
341
|
+
txExplain.memo.should.equal(testData.memo);
|
|
342
|
+
});
|
|
343
|
+
it('should explain a half signed import in C transaction', async () => {
|
|
344
|
+
var _a;
|
|
345
|
+
const testData = importC_1.IMPORT_C;
|
|
346
|
+
const txExplain = await basecoin.explainTransaction({ txHex: testData.halfsigntxHex });
|
|
347
|
+
txExplain.outputAmount.should.equal((Number(testData.amount) - ((_a = txExplain.fee) === null || _a === void 0 ? void 0 : _a.fee)).toString());
|
|
348
|
+
txExplain.type.should.equal(sdk_core_1.TransactionType.Import);
|
|
349
|
+
txExplain.outputs[0].address.should.equal(testData.to);
|
|
350
|
+
txExplain.changeOutputs.should.be.empty();
|
|
351
|
+
should.not.exist(txExplain.memo);
|
|
352
|
+
});
|
|
353
|
+
it('should explain a signed import in C transaction', async () => {
|
|
354
|
+
var _a;
|
|
355
|
+
const testData = importC_1.IMPORT_C;
|
|
356
|
+
const txExplain = await basecoin.explainTransaction({ txHex: testData.fullsigntxHex });
|
|
357
|
+
txExplain.outputAmount.should.equal((Number(testData.amount) - ((_a = txExplain.fee) === null || _a === void 0 ? void 0 : _a.fee)).toString());
|
|
358
|
+
txExplain.type.should.equal(sdk_core_1.TransactionType.Import);
|
|
359
|
+
txExplain.outputs[0].address.should.equal(testData.to);
|
|
360
|
+
txExplain.changeOutputs.should.be.empty();
|
|
361
|
+
should.not.exist(txExplain.memo);
|
|
362
|
+
});
|
|
363
|
+
it('should fail when a tx is not passed as parameter', async () => {
|
|
364
|
+
await basecoin.explainTransaction({}).should.be.rejectedWith('missing transaction hex');
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
describe('verify transaction', function () {
|
|
368
|
+
it('should succeed to verify signed transaction', async () => {
|
|
369
|
+
const txPrebuild = {
|
|
370
|
+
txHex: testData.ADDVALIDATOR_SAMPLES.fullsigntxHex,
|
|
371
|
+
txInfo: {},
|
|
372
|
+
};
|
|
373
|
+
const txParams = newTxParams();
|
|
374
|
+
const isTransactionVerified = await basecoin.verifyTransaction({ txParams, txPrebuild });
|
|
375
|
+
isTransactionVerified.should.equal(true);
|
|
376
|
+
});
|
|
377
|
+
it('should succeed to verify half signed transaction', async () => {
|
|
378
|
+
const txPrebuild = {
|
|
379
|
+
txHex: testData.ADDVALIDATOR_SAMPLES.halfsigntxHex,
|
|
380
|
+
txInfo: {},
|
|
381
|
+
};
|
|
382
|
+
const txParams = newTxParams();
|
|
383
|
+
const isTransactionVerified = await basecoin.verifyTransaction({ txParams, txPrebuild });
|
|
384
|
+
isTransactionVerified.should.equal(true);
|
|
385
|
+
});
|
|
386
|
+
it('should succeed to verify unsigned transaction', async () => {
|
|
387
|
+
const txPrebuild = newTxPrebuild();
|
|
388
|
+
const txParams = newTxParams();
|
|
389
|
+
const isTransactionVerified = await basecoin.verifyTransaction({ txParams, txPrebuild });
|
|
390
|
+
isTransactionVerified.should.equal(true);
|
|
391
|
+
});
|
|
392
|
+
it('should succeed to verify transactions when recipients has extra data', async function () {
|
|
393
|
+
const txPrebuild = newTxPrebuild();
|
|
394
|
+
const txParams = newTxParams();
|
|
395
|
+
txParams.data = 'data';
|
|
396
|
+
const validTransaction = await basecoin.verifyTransaction({ txParams, txPrebuild });
|
|
397
|
+
validTransaction.should.equal(true);
|
|
398
|
+
});
|
|
399
|
+
it('should fail verify transactions when have different type', async function () {
|
|
400
|
+
const txParams = newTxParams();
|
|
401
|
+
const txPrebuild = newTxPrebuild();
|
|
402
|
+
txParams.type = 'addDelegator';
|
|
403
|
+
await basecoin
|
|
404
|
+
.verifyTransaction({
|
|
405
|
+
txParams,
|
|
406
|
+
txPrebuild,
|
|
407
|
+
})
|
|
408
|
+
.should.be.rejectedWith('Tx type does not match with expected txParams type');
|
|
409
|
+
});
|
|
410
|
+
it('should fail verify transactions when have different nodeId', async function () {
|
|
411
|
+
const txParams = newTxParams();
|
|
412
|
+
const txPrebuild = newTxPrebuild();
|
|
413
|
+
txParams.stakingOptions.nodeID = 'NodeID-MdteS9U987PY7iwA5Pcz3sKVprJAbAvE7';
|
|
414
|
+
await basecoin
|
|
415
|
+
.verifyTransaction({
|
|
416
|
+
txParams,
|
|
417
|
+
txPrebuild,
|
|
418
|
+
})
|
|
419
|
+
.should.be.rejectedWith('Tx outputs does not match with expected txParams');
|
|
420
|
+
});
|
|
421
|
+
it('should fail verify when input `nodeId` is absent', async function () {
|
|
422
|
+
const txPrebuild = newTxPrebuild();
|
|
423
|
+
const txParams = newTxParams();
|
|
424
|
+
txParams.stakingOptions.nodeID = undefined;
|
|
425
|
+
await basecoin
|
|
426
|
+
.verifyTransaction({
|
|
427
|
+
txParams,
|
|
428
|
+
txPrebuild,
|
|
429
|
+
})
|
|
430
|
+
.should.be.rejectedWith('Tx outputs does not match with expected txParams');
|
|
431
|
+
});
|
|
432
|
+
it('should fail verify transactions when have different amount', async function () {
|
|
433
|
+
const txParams = newTxParams();
|
|
434
|
+
const txPrebuild = newTxPrebuild();
|
|
435
|
+
txParams.stakingOptions.amount = '2000000000';
|
|
436
|
+
await basecoin
|
|
437
|
+
.verifyTransaction({
|
|
438
|
+
txParams,
|
|
439
|
+
txPrebuild,
|
|
440
|
+
})
|
|
441
|
+
.should.be.rejectedWith('Tx outputs does not match with expected txParams');
|
|
442
|
+
});
|
|
443
|
+
it('should fail verify transactions when amount is number', async function () {
|
|
444
|
+
const txParams = newTxParams();
|
|
445
|
+
const txPrebuild = newTxPrebuild();
|
|
446
|
+
txParams.stakingOptions.amount = 1000000000;
|
|
447
|
+
await basecoin
|
|
448
|
+
.verifyTransaction({
|
|
449
|
+
txParams,
|
|
450
|
+
txPrebuild,
|
|
451
|
+
})
|
|
452
|
+
.should.be.rejectedWith('Tx outputs does not match with expected txParams');
|
|
453
|
+
});
|
|
454
|
+
it('should fail verify transactions when amount is absent', async function () {
|
|
455
|
+
const txParams = newTxParams();
|
|
456
|
+
const txPrebuild = newTxPrebuild();
|
|
457
|
+
txParams.stakingOptions.amount = undefined;
|
|
458
|
+
await basecoin
|
|
459
|
+
.verifyTransaction({
|
|
460
|
+
txParams,
|
|
461
|
+
txPrebuild,
|
|
462
|
+
})
|
|
463
|
+
.should.be.rejectedWith('Tx outputs does not match with expected txParams');
|
|
464
|
+
});
|
|
465
|
+
});
|
|
466
|
+
describe('Validation', function () {
|
|
467
|
+
it('should validate address', function () {
|
|
468
|
+
const validAddress = 'P-fuji15jamwukfqkwhe8z26tjqxejtjd3jk9vj4kmxwa';
|
|
469
|
+
basecoin.isValidAddress(validAddress).should.be.true();
|
|
470
|
+
});
|
|
471
|
+
it('should fail to validate invalid address', function () {
|
|
472
|
+
const invalidAddresses = [undefined, '', 'asdadsaaf', '15x3z4rvk8e7vwa6g9lkyg89v5dwknp44858uex'];
|
|
473
|
+
for (const address of invalidAddresses) {
|
|
474
|
+
basecoin.isValidAddress(address).should.be.false();
|
|
475
|
+
}
|
|
476
|
+
});
|
|
477
|
+
it('should validate an array address', function () {
|
|
478
|
+
const validAddresses = [
|
|
479
|
+
'P-fuji15x3z4rvk8e7vwa6g9lkyg89v5dwknp44858uex',
|
|
480
|
+
'P-avax143q8lsy3y4ke9d6zeltre8u2ateed6uk9ka0nu',
|
|
481
|
+
'NodeID-143q8lsy3y4ke9d6zeltre8u2ateed6uk9ka0nu',
|
|
482
|
+
];
|
|
483
|
+
basecoin.isValidAddress(validAddresses).should.be.true();
|
|
484
|
+
});
|
|
485
|
+
it('should fail to validate an array address with invalid addresss', function () {
|
|
486
|
+
const validAddresses = [
|
|
487
|
+
'P-fuji15x3z4rvk8e7vwa6g9lkyg89v5dwknp44858uex',
|
|
488
|
+
'P-avax143q8lsy3y4ke9d6zeltre8u2ateed6uk9ka0nu',
|
|
489
|
+
'invalid-address',
|
|
490
|
+
];
|
|
491
|
+
basecoin.isValidAddress(validAddresses).should.be.false();
|
|
492
|
+
});
|
|
493
|
+
it('should validate a multsig address string', function () {
|
|
494
|
+
const multiSigValidAddress = 'P-fuji1yzpfsdalhfwkq2ceewgs9wv7k0uft40ydpuj59~P-fuji103cmntssp6qnucejahddy42wcy4qty0uj42822~P-fuji1hdk7ntw0huhqmlhlheme9t7scsy9lhfhw3ywy4';
|
|
495
|
+
basecoin.isValidAddress(multiSigValidAddress).should.be.true();
|
|
496
|
+
});
|
|
497
|
+
it('should fail to validate a multsig address string with invalid address', function () {
|
|
498
|
+
const multiSigValidAddress = 'P-fuji1yzpfsdalhfwkq2ceewgs9wv7k0uft40ydpuj59~invalid-address~P-fuji1hdk7ntw0huhqmlhlheme9t7scsy9lhfhw3ywy4';
|
|
499
|
+
basecoin.isValidAddress(multiSigValidAddress).should.be.false();
|
|
500
|
+
});
|
|
501
|
+
it('should throw when verifying address if address length doesnt match keychain length', function () {
|
|
502
|
+
const validAddresses = [
|
|
503
|
+
{
|
|
504
|
+
address: 'P-fuji15x3z4rvk8e7vwa6g9lkyg89v5dwknp44858uex',
|
|
505
|
+
keychains: keychains_1.keychains,
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
address: 'P-fuji1wq0d56pu54sgc5xpevm3ur6sf3l6kke70dz0l4',
|
|
509
|
+
keychains: keychains_1.keychains,
|
|
510
|
+
},
|
|
511
|
+
];
|
|
512
|
+
for (const addressParams of validAddresses) {
|
|
513
|
+
should.throws(() => basecoin.verifyAddress(addressParams));
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
it('should fail to verify invalid address', function () {
|
|
517
|
+
const invalidAddresses = [
|
|
518
|
+
{
|
|
519
|
+
address: 'P-fuji103cmntssp6qnucejahddy42wcy4qty0uj42822',
|
|
520
|
+
keychains: keychains_1.keychains,
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
address: 'P-avax143q8lsy3y4ke9d6zeltre8u2ateed6uk9ka0nu',
|
|
524
|
+
keychains: keychains_1.keychains,
|
|
525
|
+
},
|
|
526
|
+
];
|
|
527
|
+
for (const address of invalidAddresses) {
|
|
528
|
+
should.throws(() => basecoin.verifyAddress(address));
|
|
529
|
+
}
|
|
530
|
+
});
|
|
531
|
+
it('should successfully verify is wallet address', function () {
|
|
532
|
+
basecoin
|
|
533
|
+
.isWalletAddress({
|
|
534
|
+
address: 'P-fuji15x3z4rvk8e7vwa6g9lkyg89v5dwknp44858uex~P-fuji1wq0d56pu54sgc5xpevm3ur6sf3l6kke70dz0l4~P-fuji1cjk4cvdfy6ffd4fh8umpnnrmjt0xdap02tcep6',
|
|
535
|
+
keychains: keychains_1.keychains,
|
|
536
|
+
})
|
|
537
|
+
.should.be.true();
|
|
538
|
+
});
|
|
539
|
+
it('should throw when address length and keychain length dont match', function () {
|
|
540
|
+
should.throws(() => basecoin.isWalletAddress({
|
|
541
|
+
address: 'P-fuji1wq0d56pu54sgc5xpevm3ur6sf3l6kke70dz0l4~P-fuji1cjk4cvdfy6ffd4fh8umpnnrmjt0xdap02tcep6',
|
|
542
|
+
keychains: keychains_1.keychains,
|
|
543
|
+
}));
|
|
544
|
+
});
|
|
545
|
+
it('should throw when keychain is not of length 3', function () {
|
|
546
|
+
should.throws(() => basecoin.isWalletAddress({
|
|
547
|
+
address: 'P-fuji1wq0d56pu54sgc5xpevm3ur6sf3l6kke70dz0l4',
|
|
548
|
+
keychains: keychains_1.keychains[0],
|
|
549
|
+
}));
|
|
550
|
+
});
|
|
551
|
+
});
|
|
552
|
+
});
|
|
553
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXZheHAuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90ZXN0L3VuaXQvYXZheHAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsd0RBQTBDO0FBQzFDLG1EQUErRDtBQUMvRCxvQ0FBMkM7QUFDM0MsbUNBQXFDO0FBQ3JDLCtDQUFpQztBQUNqQyxpREFBK0M7QUFDL0MsaURBQTRDO0FBQzVDLDZEQUErQztBQUMvQyxzREFBbUQ7QUFDbkQsK0NBQTREO0FBQzVELG1EQUFnRDtBQUNoRCx5Q0FBaUQ7QUFDakQsMENBQTRCO0FBRTVCLG1EQUFxRjtBQUNyRixxREFBbUQ7QUFDbkQsOENBQTJHO0FBQzNHLHFEQUFtRDtBQUVuRCxRQUFRLENBQUMsT0FBTyxFQUFFO0lBQ2hCLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQztJQUN6QixNQUFNLFNBQVMsR0FBRyxHQUFHLEdBQUcsUUFBUSxDQUFDO0lBQ2pDLElBQUksS0FBbUIsQ0FBQztJQUN4QixJQUFJLFFBQVEsQ0FBQztJQUNiLElBQUksYUFBYSxDQUFDO0lBQ2xCLElBQUksV0FBVyxDQUFDO0lBRWhCLE1BQU0sVUFBVSxHQUFHO1FBQ2pCLEtBQUssRUFBRSxRQUFRLENBQUMsb0JBQW9CLENBQUMsYUFBYTtRQUNsRCxNQUFNLEVBQUUsRUFBRTtLQUNYLENBQUM7SUFFRixNQUFNLFFBQVEsR0FBRztRQUNmLFVBQVUsRUFBRSxFQUFFO1FBQ2QsSUFBSSxFQUFFLGNBQWM7UUFDcEIsY0FBYyxFQUFFO1lBQ2QsU0FBUyxFQUFFLFFBQVEsQ0FBQyxvQkFBb0IsQ0FBQyxTQUFTO1lBQ2xELE9BQU8sRUFBRSxRQUFRLENBQUMsb0JBQW9CLENBQUMsT0FBTztZQUM5QyxNQUFNLEVBQUUsUUFBUSxDQUFDLG9CQUFvQixDQUFDLE1BQU07WUFDNUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxvQkFBb0IsQ0FBQyxpQkFBaUI7WUFDdkQsaUJBQWlCLEVBQUUsUUFB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QUN4QixDQUFDLENBQ0gsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIEF2YXhwTGliIGZyb20gJy4uLy4uL3NyYy9saWInO1xuaW1wb3J0IHsgVGVzdEJpdEdvLCBUZXN0Qml0R29BUEkgfSBmcm9tICdAYml0Z28tYmV0YS9zZGstdGVzdCc7XG5pbXBvcnQgeyBBdmF4UCwgVGF2YXhQIH0gZnJvbSAnLi4vLi4vc3JjLyc7XG5pbXBvcnQgeyByYW5kb21CeXRlcyB9IGZyb20gJ2NyeXB0byc7XG5pbXBvcnQgKiBhcyBzaG91bGQgZnJvbSAnc2hvdWxkJztcbmltcG9ydCB7IEJpdEdvQVBJIH0gZnJvbSAnQGJpdGdvLWJldGEvc2RrLWFwaSc7XG5pbXBvcnQgeyBjb2lucyB9IGZyb20gJ0BiaXRnby1iZXRhL3N0YXRpY3MnO1xuaW1wb3J0ICogYXMgdGVzdERhdGEgZnJvbSAnLi4vcmVzb3VyY2VzL2F2YXhwJztcbmltcG9ydCB7IGtleWNoYWlucyB9IGZyb20gJy4uL3Jlc291cmNlcy9rZXljaGFpbnMnO1xuaW1wb3J0IHsgVXRpbHMgYXMgS2V5UGFpclV0aWxzIH0gZnJvbSAnLi4vLi4vc3JjL2xpYi91dGlscyc7XG5pbXBvcnQgeyBLZXlQYWlyIH0gZnJvbSAnLi4vLi4vc3JjL2xpYi9rZXlQYWlyJztcbmltcG9ydCB7IEJ1ZmZlciBhcyBCdWZmZXJBdmF4IH0gZnJvbSAnYXZhbGFuY2hlJztcbmltcG9ydCAqIGFzIF8gZnJvbSAnbG9kYXNoJztcblxuaW1wb3J0IHsgSGFsZlNpZ25lZEFjY291bnRUcmFuc2FjdGlvbiwgVHJhbnNhY3Rpb25UeXBlIH0gZnJvbSAnQGJpdGdvLWJldGEvc2RrLWNvcmUnO1xuaW1wb3J0IHsgSU1QT1JUX1AgfSBmcm9tICcuLi9yZXNvdXJjZXMvdHgvaW1wb3J0UCc7XG5pbXBvcnQgeyBBRERWQUxJREFUT1JfU0FNUExFUywgRVhQT1JUX1BfMl9DLCBFWFBPUlRfUF8yX0NfV0lUSE9VVF9DSEFOR0VPVVRQVVQgfSBmcm9tICcuLi9yZXNvdXJjZXMvYXZheHAnO1xuaW1wb3J0IHsgSU1QT1JUX0MgfSBmcm9tICcuLi9yZXNvdXJjZXMvdHgvaW1wb3J0Qyc7XG5cbmRlc2NyaWJlKCdBdmF4cCcsIGZ1bmN0aW9uICgpIHtcbiAgY29uc3QgY29pbk5hbWUgPSAnYXZheHAnO1xuICBjb25zdCB0Y29pbk5hbWUgPSAndCcgKyBjb2luTmFtZTtcbiAgbGV0IGJpdGdvOiBUZXN0Qml0R29BUEk7XG4gIGxldCBiYXNlY29pbjtcbiAgbGV0IG5ld1R4UHJlYnVpbGQ7XG4gIGxldCBuZXdUeFBhcmFtcztcblxuICBjb25zdCB0eFByZWJ1aWxkID0ge1xuICAgIHR4SGV4OiB0ZXN0RGF0YS5BRERWQUxJREFUT1JfU0FNUExFUy51bnNpZ25lZFR4SGV4LFxuICAgIHR4SW5mbzoge30sXG4gIH07XG5cbiAgY29uc3QgdHhQYXJhbXMgPSB7XG4gICAgcmVjaXBpZW50czogW10sXG4gICAgdHlwZTogJ0FkZFZhbGlkYXRvcicsXG4gICAgc3Rha2luZ09wdGlvbnM6IHtcbiAgICAgIHN0YXJ0VGltZTogdGVzdERhdGEuQUREVkFMSURBVE9SX1NBTVBMRVMuc3RhcnRUaW1lLFxuICAgICAgZW5kVGltZTogdGVzdERhdGEuQUREVkFMSURBVE9SX1NBTVBMRVMuZW5kVGltZSxcbiAgICAgIG5vZGVJRDogdGVzdERhdGEuQUREVkFMSURBVE9SX1NBTVBMRVMubm9kZUlELFxuICAgICAgYW1vdW50OiB0ZXN0RGF0YS5BRERWQUxJREFUT1JfU0FNUExFUy5taW5WYWxpZGF0b3JTdGFrZSxcbiAgICAgIGRlbGVnYXRpb25GZWVSYXRlOiB0ZXN0RGF0YS5BRERWQUxJREFUT1JfU0FNUExFUy5kZWxlZ2F0aW9uRmVlLFxuICAgIH0sXG4gICAgbG9ja3RpbWU6IDAsXG4gICAgbWVtbzoge1xuICAgICAgdmFsdWU6IHRlc3REYXRhLkFERFZBTElEQVRPUl9TQU1QTEVTLm1lbW8sXG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgfSxcbiAgfTtcblxuICBiZWZvcmUoZnVuY3Rpb24gKCkge1xuICAgIGJpdGdvID0gVGVzdEJpdEdvLmRlY29yYXRlKEJpdEdvQVBJLCB7XG4gICAgICBlbnY6ICdtb2NrJyxcbiAgICB9KTtcbiAgICBiaXRnby5pbml0aWFsaXplVGVzdFZhcnMoKTtcbiAgICBiaXRnby5zYWZlUmVnaXN0ZXIoY29pbk5hbWUsIEF2YXhQLmNyZWF0ZUluc3RhbmNlKTtcbiAgICBiaXRnby5zYWZlUmVnaXN0ZXIodGNvaW5OYW1lLCBUYXZheFAuY3JlYXRlSW5zdGFuY2UpO1xuICAgIGJhc2Vjb2luID0gYml0Z28uY29pbih0Y29pbk5hbWUpO1xuICAgIG5ld1R4UHJlYnVpbGQgPSAoKSA9PiB7XG4gICAgICByZXR1cm4gXy5jbG9uZURlZXAodHhQcmVidWlsZCk7XG4gICAgfTtcbiAgICBuZXdUeFBhcmFtcyA9ICgpID0+IHtcbiAgICAgIHJldHVybiBfLmNsb25lRGVlcCh0eFBhcmFtcyk7XG4gICAgfTtcbiAgfSk7XG5cbiAgaXQoJ3Nob3VsZCBpbnN0YW50aWF0ZSB0aGUgY29pbicsIGZ1bmN0aW9uICgpIHtcbiAgICBsZXQgbG9jYWxCYXNlY29pbiA9IGJpdGdvLmNvaW4odGNvaW5OYW1lKTtcbiAgICBsb2NhbEJhc2Vjb2luLnNob3VsZC5iZS5hbi5pbnN0YW5jZW9mKFRhdmF4UCk7XG5cbiAgICBsb2NhbEJhc2Vjb2luID0gYml0Z28uY29pbihjb2luTmFtZSk7XG4gICAgbG9jYWxCYXNlY29pbi5zaG91bGQuYmUuYW4uaW5zdGFuY2VvZihBdmF4UCk7XG4gIH0pO1xuXG4gIGl0KCdzaG91bGQgcmV0dXJuICcgKyB0Y29pbk5hbWUsIGZ1bmN0aW9uICgpIHtcbiAgICBiYXNlY29pbi5nZXRDaGFpbigpLnNob3VsZC5lcXVhbCh0Y29pbk5hbWUpO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHJldHVybiBmdWxsIG5hbWUnLCBmdW5jdGlvbiAoKSB7XG4gICAgYmFzZWNvaW4uZ2V0RnVsbE5hbWUoKS5zaG91bGQuZXF1YWwoJ1Rlc3RuZXQgQXZhbGFuY2hlIFAtQ2hhaW4nKTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ0tleXBhaXJzOicsICgpID0+IHtcbiAgICBpdCgnc2hvdWxkIGdlbmVyYXRlIGEga2V5cGFpciBmcm9tIHJhbmRvbSBzZWVkJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3Qga2V5UGFpciA9IGJhc2Vjb2luLmdlbmVyYXRlS2V5UGFpcigpO1xuICAgICAga2V5UGFpci5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgncHViJyk7XG4gICAgICBrZXlQYWlyLnNob3VsZC5oYXZlLnByb3BlcnR5KCdwcnYnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZ2VuZXJhdGUgYSBrZXlwYWlyIGZyb20gYSBzZWVkJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3Qgc2VlZFRleHQgPSB0ZXN0RGF0YS5TRUVEX0FDQ09VTlQuc2VlZDtcbiAgICAgIGNvbnN0IHNlZWQgPSBCdWZmZXIuZnJvbShzZWVkVGV4dCwgJ2hleCcpO1xuICAgICAgY29uc3Qga2V5UGFpciA9IGJhc2Vjb2luLmdlbmVyYXRlS2V5UGFpcihzZWVkKTtcbiAgICAgIGtleVBhaXIucHViLnNob3VsZC5lcXVhbCh0ZXN0RGF0YS5TRUVEX0FDQ09VTlQucHVibGljS2V5KTtcbiAgICAgIGtleVBhaXIucHJ2LnNob3VsZC5lcXVhbCh0ZXN0RGF0YS5TRUVEX0FDQ09VTlQucHJpdmF0ZUtleSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHZhbGlkYXRlIGEgcHVibGljIGtleScsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGtleVBhaXIgPSBiYXNlY29pbi5nZW5lcmF0ZUtleVBhaXIoKTtcbiAgICAgIGtleVBhaXIuc2hvdWxkLmhhdmUucHJvcGVydHkoJ3B1YicpO1xuICAgICAga2V5UGFpci5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgncHJ2Jyk7XG5cbiAgICAgIGJhc2Vjb2luLmlzVmFsaWRQdWIoa2V5UGFpci5wdWIpLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdmFsaWRhdGUgYSBwcml2YXRlIGtleScsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGtleVBhaXIgPSBiYXNlY29pbi5nZW5lcmF0ZUtleVBhaXIoKTtcbiAgICAgIGtleVBhaXIuc2hvdWxkLmhhdmUucHJvcGVydHkoJ3B1YicpO1xuICAgICAga2V5UGFpci5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgncHJ2Jyk7XG5cbiAgICAgIGJhc2Vjb2luLmlzVmFsaWRQcnYoa2V5UGFpci5wcnYpLnNob3VsZC5lcXVhbCh0cnVlKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ1NpZ24gVHJhbnNhY3Rpb24nLCAoKSA9PiB7XG4gICAgY29uc3QgZmFjdG9yeSA9IG5ldyBBdmF4cExpYi5UcmFuc2FjdGlvbkJ1aWxkZXJGYWN0b3J5KGNvaW5zLmdldCh0Y29pbk5hbWUpKTtcblxuICAgIGl0KCdidWlsZCBhbmQgc2lnbiBhIHRyYW5zYWN0aW9uIGluIHJlZ3VsYXIgbW9kZScsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHJlY292ZXJ5TW9kZSA9IGZhbHNlO1xuICAgICAgY29uc3QgdHhCdWlsZGVyID0gbmV3IEF2YXhwTGliLlRyYW5zYWN0aW9uQnVpbGRlckZhY3RvcnkoY29pbnMuZ2V0KHRjb2luTmFtZSkpXG4gICAgICAgIC5nZXRWYWxpZGF0b3JCdWlsZGVyKClcbiAgICAgICAgLnRocmVzaG9sZCh0ZXN0RGF0YS5CVUlMRF9BTkRfU0lHTl9BRERfVkFMSURBVE9SX1NBTVBMRS50aHJlc2hvbGQpXG4gICAgICAgIC5sb2NrdGltZSh0ZXN0RGF0YS5CVUlMRF9BTkRfU0lHTl9BRERfVkFMSURBVE9SX1NBTVBMRS5sb2NrdGltZSlcbiAgICAgICAgLnJlY292ZXJNb2RlKHJlY292ZXJ5TW9kZSlcbiAgICAgICAgLmZyb21QdWJLZXkodGVzdERhdGEuQlVJTERfQU5EX1NJR05fQUREX1ZBTElEQVRPUl9TQU1QTEUuYml0Z29BZGRyZXNzZXMpXG4gICAgICAgIC5zdGFydFRpbWUodGVzdERhdGEuQlVJTERfQU5EX1NJR05fQUREX1ZBTElEQVRPUl9TQU1QTEUuc3RhcnRUaW1lKVxuICAgICAgICAuZW5kVGltZSh0ZXN0RGF0YS5CVUlMRF9BTkRfU0lHTl9BRERfVkFMSURBVE9SX1NBTVBMRS5lbmRUaW1lKVxuICAgICAgICAuc3Rha2VBbW91bnQodGVzdERhdGEuQlVJTERfQU5EX1NJR05fQUREX1ZBTElEQVRPUl9TQU1QTEUuc3Rha2VBbW91bnQpXG4gICAgICAgIC5kZWxlZ2F0aW9uRmVlUmF0ZSh0ZXN0RGF0YS5CVUlMRF9BTkRfU0lHTl9BRERfVkFMSURBVE9SX1NBTVBMRS5kZWxlZ2F0aW9uRmVlUmF0ZSlcbiAgICAgICAgLm5vZGVJRCh0ZXN0RGF0YS5CVUlMRF9BTkRfU0lHTl9BRERfVkFMSURBVE9SX1NBTVBMRS5ub2RlSWQpXG4gICAgICAgIC5tZW1vKHRlc3REYXRhLkJVSUxEX0FORF9TSUdOX0FERF9WQUxJREFUT1JfU0FNUExFLm1lbW8pXG4gICAgICAgIC51dHhvcyh0ZXN0RGF0YS5CVUlMRF9BTkRfU0lHTl9BRERfVkFMSURBVE9SX1NBTVBMRS51dHhvcyk7XG4gICAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuXG4gICAgICBsZXQgdHhIZXggPSB0eC50b0Jyb2FkY2FzdEZvcm1hdCgpO1xuICAgICAgdHhIZXguc2hvdWxkLmVxdWFsKHRlc3REYXRhLkJVSUxEX0FORF9TSUdOX0FERF9WQUxJREFUT1JfU0FNUExFLnVuc2lnbmVkUmF3VHhOb25SZWNvdmVyeSk7XG5cbiAgICAgIGNvbnN0IHByaXZhdGVLZXkgPSByZWNvdmVyeU1vZGVcbiAgICAgICAgPyB0ZXN0RGF0YS5CVUlMRF9BTkRfU0lHTl9BRERfVkFMSURBVE9SX1NBTVBMRS5iYWNrdXBQcml2YXRlS2V5XG4gICAgICAgIDogdGVzdERhdGEuQlVJTERfQU5EX1NJR05fQUREX1ZBTElEQVRPUl9TQU1QTEUudXNlclByaXZhdGVLZXk7XG5cbiAgICAgIGNvbnN0IHBhcmFtcyA9IHtcbiAgICAgICAgdHhQcmVidWlsZDoge1xuICAgICAgICAgIHR4SGV4OiB0eC50b0Jyb2FkY2FzdEZvcm1hdCgpLFxuICAgICAgICB9LFxuICAgICAgICBwcnY6IHByaXZhdGVLZXksXG4gICAgICB9O1xuXG4gICAgICBjb25zdCBoYWxmU2lnbmVkVHJhbnNhY3Rpb24gPSBhd2FpdCBiYXNlY29pbi5zaWduVHJhbnNhY3Rpb24ocGFyYW1zKTtcbiAgICAgIHR4SGV4ID0gKGhhbGZTaWduZWRUcmFuc2FjdGlvbiBhcyBIYWxmU2lnbmVkQWNjb3VudFRyYW5zYWN0aW9uKT8uaGFsZlNpZ25lZD8udHhIZXg7XG4gICAgICB0eEhleC5zaG91bGQuZXF1YWwodGVzdERhdGEuQlVJTERfQU5EX1NJR05fQUREX1ZBTElEQVRPUl9TQU1QTEUuaGFsZlNpZ25lZFJhd1R4Tm9uUmVjb3ZlcnkpO1xuICAgIH0pO1xuICAgIGl0KCdidWlsZCBhbmQgc2lnbiBhIHRyYW5zYWN0aW9uIGluIHJlY292ZXJ5IG1vZGUnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCByZWNvdmVyeU1vZGUgPSB0cnVlO1xuICAgICAgY29uc3QgdHhCdWlsZGVyID0gbmV3IEF2YXhwTGliLlRyYW5zYWN0aW9uQnVpbGRlckZhY3RvcnkoY29pbnMuZ2V0KHRjb2luTmFtZSkpXG4gICAgICAgIC5nZXRWYWxpZGF0b3JCdWlsZGVyKClcbiAgICAgICAgLnRocmVzaG9sZCh0ZXN0RGF0YS5CVUlMRF9BTkRfU0lHTl9BRERfVkFMSURBVE9SX1NBTVBMRS50aHJlc2hvbGQpXG4gICAgICAgIC5sb2NrdGltZSh0ZXN0RGF0YS5CVUlMRF9BTkRfU0lHTl9BRERfVkFMSURBVE9SX1NBTVBMRS5sb2NrdGltZSlcbiAgICAgICAgLnJlY292ZXJNb2RlKHJlY292ZXJ5TW9kZSlcbiAgICAgICAgLmZyb21QdWJLZXkodGVzdERhdGEuQlVJTERfQU5EX1NJR05fQUREX1ZBTElEQVRPUl9TQU1QTEUuYml0Z29BZGRyZXNzZXMpXG4gICAgICAgIC5zdGFydFRpbWUodGVzdERhdGEuQlVJTERfQU5EX1NJR05fQUREX1ZBTElEQVRPUl9TQU1QTEUuc3RhcnRUaW1lKVxuICAgICAgICAuZW5kVGltZSh0ZXN0RGF0YS5CVUlMRF9BTkRfU0lHTl9BRERfVkFMSURBVE9SX1NBTVBMRS5lbmRUaW1lKVxuICAgICAgICAuc3Rha2VBbW91bnQodGVzdERhdGEuQlVJTERfQU5EX1NJR05fQUREX1ZBTElEQVRPUl9TQU1QTEUuc3Rha2VBbW91bnQpXG4gICAgICAgIC5kZWxlZ2F0aW9uRmVlUmF0ZSh0ZXN0RGF0YS5CVUlMRF9BTkRfU0lHTl9BRERfVkFMSURBVE9SX1NBTVBMRS5kZWxlZ2F0aW9uRmVlUmF0ZSlcbiAgICAgICAgLm5vZGVJRCh0ZXN0RGF0YS5CVUlMRF9BTkRfU0lHTl9BRERfVkFMSURBVE9SX1NBTVBMRS5ub2RlSWQpXG4gICAgICAgIC5tZW1vKHRlc3REYXRhLkJVSUxEX0FORF9TSUdOX0FERF9WQUxJREFUT1JfU0FNUExFLm1lbW8pXG4gICAgICAgIC51dHhvcyh0ZXN0RGF0YS5CVUlMRF9BTkRfU0lHTl9BRERfVkFMSURBVE9SX1NBTVBMRS51dHhvcyk7XG4gICAgICBjb25zdCB0eCA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuXG4gICAgICBsZXQgdHhIZXggPSB0eC50b0Jyb2FkY2FzdEZvcm1hdCgpO1xuICAgICAgdHhIZXguc2hvdWxkLmVxdWFsKHRlc3REYXRhLkJVSUxEX0FORF9TSUdOX0FERF9WQUxJREFUT1JfU0FNUExFLnVuc2lnbmVkUmF3dHhSZWNvdmVyeSk7XG5cbiAgICAgIGNvbnN0IHByaXZhdGVLZXkgPSByZWNvdmVyeU1vZGVcbiAgICAgICAgPyB0ZXN0RGF0YS5CVUlMRF9BTkRfU0lHTl9BRERfVkFMSURBVE9SX1NBTVBMRS5iYWNrdXBQcml2YXRlS2V5XG4gICAgICAgIDogdGVzdERhdGEuQlVJTERfQU5EX1NJR05fQUREX1ZBTElEQVRPUl9TQU1QTEUudXNlclByaXZhdGVLZXk7XG5cbiAgICAgIGNvbnN0IHBhcmFtcyA9IHtcbiAgICAgICAgdHhQcmVidWlsZDoge1xuICAgICAgICAgIHR4SGV4OiB0eC50b0Jyb2FkY2FzdEZvcm1hdCgpLFxuICAgICAgICB9LFxuICAgICAgICBwcnY6IHByaXZhdGVLZXksXG4gICAgICB9O1xuXG4gICAgICBjb25zdCBoYWxmU2lnbmVkVHJhbnNhY3Rpb24gPSBhd2FpdCBiYXNlY29pbi5zaWduVHJhbnNhY3Rpb24ocGFyYW1zKTtcbiAgICAgIHR4SGV4ID0gKGhhbGZTaWduZWRUcmFuc2FjdGlvbiBhcyBIYWxmU2lnbmVkQWNjb3VudFRyYW5zYWN0aW9uKT8uaGFsZlNpZ25lZD8udHhIZXg7XG4gICAgICB0eEhleC5zaG91bGQuZXF1YWwodGVzdERhdGEuQlVJTERfQU5EX1NJR05fQUREX1ZBTElEQVRPUl9TQU1QTEUuaGFsZlNpZ25lZFJhd1R4UmVjb3ZlcnkpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBiZSByZWplY3RlZCBpZiBpbnZhbGlkIGtleScsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGludmFsaWRQcml2YXRlS2V5ID0gJ0FBQUFBJztcbiAgICAgIGNvbnN0IGJ1aWxkZXIgPSBmYWN0b3J5LmZyb20odGVzdERhdGEuQUREVkFMSURBVE9SX1NBTVBMRVMudW5zaWduZWRUeEhleCk7XG5cbiAgICAgIGNvbnN0IHR4ID0gYXdhaXQgYnVpbGRlci5idWlsZCgpO1xuICAgICAgY29uc3QgcGFyYW1zID0ge1xuICAgICAgICB0eFByZWJ1aWxkOiB7XG4gICAgICAgICAgdHhIZXg6IHR4LnRvQnJvYWRjYXN0Rm9ybWF0KCksXG4gICAgICAgIH0sXG4gICAgICAgIHBydjogaW52YWxpZFByaXZhdGVLZXksXG4gICAgICB9O1xuXG4gICAgICBhd2FpdCBiYXNlY29pbi5zaWduVHJhbnNhY3Rpb24ocGFyYW1zKS5zaG91bGQuYmUucmVqZWN0ZWQoKTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIHJldHVybiB0aGUgc2FtZSBtYWlubmV0IGFkZHJlc3MnLCAoKSA9PiB7XG4gICAgICBjb25zdCB1dGlscyA9IG5ldyBLZXlQYWlyVXRpbHMoKTtcbiAgICAgIGNvbnN0IHhwcnYgPSB0ZXN0RGF0YS5TRUVEX0FDQ09VTlQueFByaXZhdGVLZXk7XG4gICAgICBjb25zdCBrcDEgPSBuZXcgS2V5UGFpcih7IHBydjogeHBydiB9KTtcbiAgICAgIGNvbnN0IGFkZHJlc3NCdWZmZXIxID0ga3AxLmdldEFkZHJlc3NCdWZmZXIoKTtcbiAgICAgIGNvbnN0IGFkZHJlc3MxID0gdXRpbHMuYWRkcmVzc1RvU3RyaW5nKCdhdmF4JywgJ1AnLCBCdWZmZXJBdmF4LmZyb20oYWRkcmVzc0J1ZmZlcjEpKTtcblxuICAgICAgY29uc3Qga3AyID0gbmV3IEtleVBhaXIoeyBwcnY6IHhwcnYgfSk7XG4gICAgICBjb25zdCBhZGRyZXNzQnVmZmVyMiA9IGtwMi5nZXRBZGRyZXNzU2FmZUJ1ZmZlcigpO1xuICAgICAgY29uc3QgYWRkcmVzczIgPSB1dGlscy5hZGRyZXNzVG9TdHJpbmcoJ2F2YXgnLCAnUCcsIEJ1ZmZlckF2YXguZnJvbShhZGRyZXNzQnVmZmVyMikpO1xuXG4gICAgICBjb25zdCBrcDMgPSBuZXcgS2V5UGFpcih7IHBydjogeHBydiB9KTtcbiAgICAgIGNvbnN0IGFkZHJlc3MzID0ga3AzLmdldEF2YXhQQWRkcmVzcygnYXZheCcpO1xuXG4gICAgICBhZGRyZXNzMS5zaG91bGQuZXF1YWwoYWRkcmVzczIpO1xuICAgICAgYWRkcmVzczEuc2hvdWxkLmVxdWFsKGFkZHJlc3MzKTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIHJldHVybiB0aGUgc2FtZSB0ZXN0bmV0IGFkZHJlc3MnLCAoKSA9PiB7XG4gICAgICBjb25zdCB1dGlscyA9IG5ldyBLZXlQYWlyVXRpbHMoKTtcbiAgICAgIGNvbnN0IHhwcnYgPSB0ZXN0RGF0YS5TRUVEX0FDQ09VTlQueFByaXZhdGVLZXk7XG4gICAgICBjb25zdCBrcDEgPSBuZXcgS2V5UGFpcih7IHBydjogeHBydiB9KTtcbiAgICAgIGNvbnN0IGFkZHJlc3NCdWZmZXIxID0ga3AxLmdldEFkZHJlc3NCdWZmZXIoKTtcbiAgICAgIGNvbnN0IGFkZHJlc3MxID0gdXRpbHMuYWRkcmVzc1RvU3RyaW5nKCdmdWppJywgJ1AnLCBCdWZmZXJBdmF4LmZyb20oYWRkcmVzc0J1ZmZlcjEpKTtcblxuICAgICAgY29uc3Qga3AyID0gbmV3IEtleVBhaXIoeyBwcnY6IHhwcnYgfSk7XG4gICAgICBjb25zdCBhZGRyZXNzQnVmZmVyMiA9IGtwMi5nZXRBZGRyZXNzU2FmZUJ1ZmZlcigpO1xuICAgICAgY29uc3QgYWRkcmVzczIgPSB1dGlscy5hZGRyZXNzVG9TdHJpbmcoJ2Z1amknLCAnUCcsIEJ1ZmZlckF2YXguZnJvbShhZGRyZXNzQnVmZmVyMikpO1xuXG4gICAgICBjb25zdCBrcDMgPSBuZXcgS2V5UGFpcih7IHBydjogeHBydiB9KTtcbiAgICAgIGNvbnN0IGFkZHJlc3MzID0ga3AzLmdldEF2YXhQQWRkcmVzcygnZnVqaScpO1xuXG4gICAgICBhZGRyZXNzMS5zaG91bGQuZXF1YWwoYWRkcmVzczIpO1xuICAgICAgYWRkcmVzczEuc2hvdWxkLmVxdWFsKGFkZHJlc3MzKTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIG5vdCBiZSB0aGUgc2FtZSBhZGRyZXNzIGZyb20gc2FtZSBrZXknLCAoKSA9PiB7XG4gICAgICBjb25zdCB1dGlscyA9IG5ldyBLZXlQYWlyVXRpbHMoKTtcbiAgICAgIGNvbnN0IGtwMSA9IG5ldyBLZXlQYWlyKHsgcHJ2OiB0ZXN0RGF0YS5BQ0NPVU5UXzEucHJpdmtleSB9KTtcbiAgICAgIGNvbnN0IGFkZHJlc3NCdWZmZXIxID0ga3AxLmdldEFkZHJlc3NCdWZmZXIoKTtcbiAgICAgIGNvbnN0IGFkZHJlc3MxID0gdXRpbHMuYWRkcmVzc1RvU3RyaW5nKCdhdmF4JywgJ1AnLCBCdWZmZXJBdmF4LmZyb20oYWRkcmVzc0J1ZmZlcjEpKTtcblxuICAgICAgY29uc3Qga3AyID0gbmV3IEtleVBhaXIoeyBwcnY6IHRlc3REYXRhLkFDQ09VTlRfMS5wcml2a2V5IH0pO1xuICAgICAgY29uc3QgYWRkcmVzc0J1ZmZlcjIgPSBrcDIuZ2V0QWRkcmVzc1NhZmVCdWZmZXIoKTtcbiAgICAgIGNvbnN0IGFkZHJlc3MyID0gdXRpbHMuYWRkcmVzc1RvU3RyaW5nKCdmdWppJywgJ1AnLCBCdWZmZXJBdmF4LmZyb20oYWRkcmVzc0J1ZmZlcjIpKTtcblxuICAgICAgYWRkcmVzczEuc2hvdWxkLm5vdC5lcXVhbChhZGRyZXNzMik7XG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCBub3QgYmUgdGhlIHNhbWUgYWRkcmVzcyBmcm9tIGRpZmZlcmVudCBrZXlzJywgKCkgPT4ge1xuICAgICAgY29uc3QgdXRpbHMgPSBuZXcgS2V5UGFpclV0aWxzKCk7XG4gICAgICBjb25zdCBrcDEgPSBuZXcgS2V5UGFpcih7IHBydjogdGVzdERhdGEuQUNDT1VOVF8xLnByaXZrZXkgfSk7XG4gICAgICBjb25zdCBhZGRyZXNzQnVmZmVyMSA9IGtwMS5nZXRBZGRyZXNzQnVmZmVyKCk7XG4gICAgICBjb25zdCBhZGRyZXNzMSA9IHV0aWxzLmFkZHJlc3NUb1N0cmluZygnYXZheCcsICdQJywgQnVmZmVyQXZheC5mcm9tKGFkZHJlc3NCdWZmZXIxKSk7XG5cbiAgICAgIGNvbnN0IGtwMiA9IG5ldyBLZXlQYWlyKHsgcHJ2OiB0ZXN0RGF0YS5BQ0NPVU5UXzMucHJpdmtleSB9KTtcbiAgICAgIGNvbnN0IGFkZHJlc3NCdWZmZXIyID0ga3AyLmdldEFkZHJlc3NTYWZlQnVmZmVyKCk7XG4gICAgICBjb25zdCBhZGRyZXNzMiA9IHV0aWxzLmFkZHJlc3NUb1N0cmluZygnYXZheCcsICdQJywgQnVmZmVyQXZheC5mcm9tKGFkZHJlc3NCdWZmZXIyKSk7XG5cbiAgICAgIGFkZHJlc3MxLnNob3VsZC5ub3QuZXF1YWwoYWRkcmVzczIpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnU2lnbiBNZXNzYWdlJywgKCkgPT4ge1xuICAgIGl0KCdzaG91bGQgYmUgcGVyZm9ybWVkJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3Qga2V5UGFpclRvU2lnbiA9IG5ldyBBdmF4cExpYi5LZXlQYWlyKCk7XG4gICAgICBjb25zdCBwcnZLZXkgPSBrZXlQYWlyVG9TaWduLmdldFByaXZhdGVLZXkoKTtcbiAgICAgIGNvbnN0IGtleVBhaXIgPSBrZXlQYWlyVG9TaWduLmdldEtleXMoKTtcbiAgICAgIGNvbnN0IG1lc3NhZ2VUb1NpZ24gPSBCdWZmZXIuZnJvbShyYW5kb21CeXRlcygzMikpO1xuICAgICAgY29uc3Qgc2lnbmF0dXJlID0gYXdhaXQgYmFzZWNvaW4uc2lnbk1lc3NhZ2Uoa2V5UGFpciwgbWVzc2FnZVRvU2lnbi50b1N0cmluZygnaGV4JykpO1xuXG4gICAgICBjb25zdCB2ZXJpZnkgPSBBdmF4cExpYi5VdGlscy52ZXJpZnlTaWduYXR1cmUoYmFzZWNvaW4uX3N0YXRpY3NDb2luLm5ldHdvcmssIG1lc3NhZ2VUb1NpZ24sIHNpZ25hdHVyZSwgcHJ2S2V5ISk7XG4gICAgICB2ZXJpZnkuc2hvdWxkLmJlLnRydWUoKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZmFpbCB3aXRoIG1pc3NpbmcgcHJpdmF0ZSBrZXknLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCBrZXlQYWlyID0gbmV3IEF2YXhwTGliLktleVBhaXIoe1xuICAgICAgICBwdWI6IHRlc3REYXRhLlNFRURfQUNDT1VOVC5wdWJsaWNLZXlDYjU4LFxuICAgICAgfSkuZ2V0S2V5cygpO1xuICAgICAgY29uc3QgbWVzc2FnZVRvU2lnbiA9IEJ1ZmZlci5mcm9tKHJhbmRvbUJ5dGVzKDMyKSkudG9TdHJpbmcoJ2hleCcpO1xuICAgICAgYXdhaXQgYmFzZWNvaW4uc2lnbk1lc3NhZ2Uoa2V5UGFpciwgbWVzc2FnZVRvU2lnbikuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgnSW52YWxpZCBrZXkgcGFpciBvcHRpb25zJyk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdFeHBsYWluIFRyYW5zYWN0aW9uJywgKCkgPT4ge1xuICAgIGl0KCdzaG91bGQgZXhwbGFpbiBhIGhhbGYgc2lnbmVkIEFkZFZhbGlkYXRvciB0cmFuc2FjdGlvbicsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHRlc3REYXRhID0gQUREVkFMSURBVE9SX1NBTVBMRVM7XG4gICAgICBjb25zdCB0eEV4cGxhaW4gPSBhd2FpdCBiYXNlY29pbi5leHBsYWluVHJhbnNhY3Rpb24oeyBoYWxmU2lnbmVkOiB7IHR4SGV4OiB0ZXN0RGF0YS5oYWxmc2lnbnR4SGV4IH0gfSk7XG4gICAgICB0eEV4cGxhaW4ub3V0cHV0QW1vdW50LnNob3VsZC5lcXVhbCh0ZXN0RGF0YS5taW5WYWxpZGF0b3JTdGFrZSk7XG4gICAgICB0eEV4cGxhaW4udHlwZS5zaG91bGQuZXF1YWwoVHJhbnNhY3Rpb25UeXBlLkFkZFZhbGlkYXRvcik7XG4gICAgICB0eEV4cGxhaW4ub3V0cHV0c1swXS5hZGRyZXNzLnNob3VsZC5lcXVhbCh0ZXN0RGF0YS5ub2RlSUQpO1xuICAgICAgdHhFeHBsYWluLmNoYW5nZU91dHB1dHNbMF0uYWRkcmVzcy5zcGxpdCgnficpLmxlbmd0aC5zaG91bGQuZXF1YWwoMyk7XG4gICAgICB0eEV4cGxhaW4ubWVtby5zaG91bGQuZXF1YWwodGVzdERhdGEubWVtbyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGV4cGxhaW4gYSBzaWduZWQgQWRkVmFsaWRhdG9yIHRyYW5zYWN0aW9uJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgdGVzdERhdGEgPSBBRERWQUxJREFUT1JfU0FNUExFUztcbiAgICAgIGNvbnN0IHR4RXhwbGFpbiA9IGF3YWl0IGJhc2Vjb2luLmV4cGxhaW5UcmFuc2FjdGlvbih7IHR4SGV4OiB0ZXN0RGF0YS5mdWxsc2lnbnR4SGV4IH0pO1xuICAgICAgdHhFeHBsYWluLm91dHB1dEFtb3VudC5zaG91bGQuZXF1YWwodGVzdERhdGEubWluVmFsaWRhdG9yU3Rha2UpO1xuICAgICAgdHhFeHBsYWluLnR5cGUuc2hvdWxkLmVxdWFsKFRyYW5zYWN0aW9uVHlwZS5BZGRWYWxpZGF0b3IpO1xuICAgICAgdHhFeHBsYWluLm91dHB1dHNbMF0uYWRkcmVzcy5zaG91bGQuZXF1YWwodGVzdERhdGEubm9kZUlEKTtcbiAgICAgIHR4RXhwbGFpbi5jaGFuZ2VPdXRwdXRzWzBdLmFkZHJlc3Muc3BsaXQoJ34nKS5sZW5ndGguc2hvdWxkLmVxdWFsKDMpO1xuICAgICAgdHhFeHBsYWluLm1lbW8uc2hvdWxkLmVxdWFsKHRlc3REYXRhLm1lbW8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBleHBsYWluIGEgaGFsZiBzaWduZWQgZXhwb3J0IHRyYW5zYWN0aW9uJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgdGVzdERhdGEgPSBFWFBPUlRfUF8yX0M7XG4gICAgICBjb25zdCB0eEV4cGxhaW4gPSBhd2FpdCBiYXNlY29pbi5leHBsYWluVHJhbnNhY3Rpb24oeyBoYWxmU2lnbmVkOiB7IHR4SGV4OiB0ZXN0RGF0YS5oYWxmc2lnbnR4SGV4IH0gfSk7XG4gICAgICB0eEV4cGxhaW4ub3V0cHV0QW1vdW50LnNob3VsZC5lcXVhbCh0ZXN0RGF0YS5hbW91bnQpO1xuICAgICAgdHhFeHBsYWluLnR5cGUuc2hvdWxkLmVxdWFsKFRyYW5zYWN0aW9uVHlwZS5FeHBvcnQpO1xuICAgICAgdHhFeHBsYWluLm91dHB1dHNbMF0uYWRkcmVzcy5zaG91bGQuZXF1YWwodGVzdERhdGEucEFkZHJlc3Nlcy5zb3J0KCkuam9pbignficpKTtcbiAgICAgIHR4RXhwbGFpbi5jaGFuZ2VPdXRwdXRzWzBdLmFkZHJlc3Muc2hvdWxkLmVxdWFsKHRlc3REYXRhLnBBZGRyZXNzZXMuc29ydCgpLmpvaW4oJ34nKSk7XG4gICAgICB0eEV4cGxhaW4ubWVtby5zaG91bGQuZXF1YWwodGVzdERhdGEubWVtbyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGV4cGxhaW4gYSBzaWduZWQgZXhwb3J0IHRyYW5zYWN0aW9uJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgdGVzdERhdGEgPSBFWFBPUlRfUF8yX0M7XG4gICAgICBjb25zdCB0eEV4cGxhaW4gPSBhd2FpdCBiYXNlY29pbi5leHBsYWluVHJhbnNhY3Rpb24oeyB0eEhleDogdGVzdERhdGEuZnVsbHNpZ250eEhleCB9KTtcbiAgICAgIHR4RXhwbGFpbi5vdXRwdXRBbW91bnQuc2hvdWxkLmVxdWFsKHRlc3REYXRhLmFtb3VudCk7XG4gICAgICB0eEV4cGxhaW4udHlwZS5zaG91bGQuZXF1YWwoVHJhbnNhY3Rpb25UeXBlLkV4cG9ydCk7XG4gICAgICB0eEV4cGxhaW4ub3V0cHV0c1swXS5hZGRyZXNzLnNob3VsZC5lcXVhbCh0ZXN0RGF0YS5wQWRkcmVzc2VzLnNvcnQoKS5qb2luKCd+JykpO1xuICAgICAgdHhFeHBsYWluLmNoYW5nZU91dHB1dHNbMF0uYWRkcmVzcy5zaG91bGQuZXF1YWwodGVzdERhdGEucEFkZHJlc3Nlcy5zb3J0KCkuam9pbignficpKTtcbiAgICAgIHR4RXhwbGFpbi5tZW1vLnNob3VsZC5lcXVhbCh0ZXN0RGF0YS5tZW1vKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZXhwbGFpbiBhIGhhbGYgc2lnbmVkIGV4cG9ydCB0cmFuc2FjdGlvbiB3aXRob3V0IGNhaG5nZW91dHB1dCAnLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCB0ZXN0RGF0YSA9IEVYUE9SVF9QXzJfQ19XSVRIT1VUX0NIQU5HRU9VVFBVVDtcbiAgICAgIGNvbnN0IHR4RXhwbGFpbiA9IGF3YWl0IGJhc2Vjb2luLmV4cGxhaW5UcmFuc2FjdGlvbih7XG4gICAgICAgIGhhbGZTaWduZWQ6IHsgdHhIZXg6IHRlc3REYXRhLmhhbGZzaWdudHhIZXggfSxcbiAgICAgIH0pO1xuICAgICAgdHhFeHBsYWluLm91dHB1dEFtb3VudC5zaG91bGQuZXF1YWwodGVzdERhdGEuYW1vdW50KTtcbiAgICAgIHR4RXhwbGFpbi50eXBlLnNob3VsZC5lcXVhbChUcmFuc2FjdGlvblR5cGUuRXhwb3J0KTtcbiAgICAgIHR4RXhwbGFpbi5vdXRwdXRzWzBdLmFkZHJlc3Muc2hvdWxkLmVxdWFsKHRlc3REYXRhLnBBZGRyZXNzZXMuc29ydCgpLmpvaW4oJ34nKSk7XG4gICAgICB0eEV4cGxhaW4uY2hhbmdlT3V0cHV0cy5zaG91bGQuYmUuZW1wdHkoKTtcbiAgICAgIHR4RXhwbGFpbi5tZW1vLnNob3VsZC5lcXVhbCh0ZXN0RGF0YS5tZW1vKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZXhwbGFpbiBhIHNpZ25lZCBleHBvcnQgdHJhbnNhY3Rpb24gd2l0aG91dCBjYWhuZ2VvdXRwdXQgJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgdGVzdERhdGEgPSBFWFBPUlRfUF8yX0NfV0lUSE9VVF9DSEFOR0VPVVRQVVQ7XG4gICAgICBjb25zdCB0eEV4cGxhaW4gPSBhd2FpdCBiYXNlY29pbi5leHBsYWluVHJhbnNhY3Rpb24oeyB0eEhleDogdGVzdERhdGEuZnVsbHNpZ250eEhleCB9KTtcbiAgICAgIHR4RXhwbGFpbi5vdXRwdXRBbW91bnQuc2hvdWxkLmVxdWFsKHRlc3REYXRhLmFtb3VudCk7XG4gICAgICB0eEV4cGxhaW4udHlwZS5zaG91bGQuZXF1YWwoVHJhbnNhY3Rpb25UeXBlLkV4cG9ydCk7XG4gICAgICB0eEV4cGxhaW4ub3V0cHV0c1swXS5hZGRyZXNzLnNob3VsZC5lcXVhbCh0ZXN0RGF0YS5wQWRkcmVzc2VzLnNvcnQoKS5qb2luKCd+JykpO1xuICAgICAgdHhFeHBsYWluLmNoYW5nZU91dHB1dHMuc2hvdWxkLmJlLmVtcHR5KCk7XG4gICAgICB0eEV4cGxhaW4ubWVtby5zaG91bGQuZXF1YWwodGVzdERhdGEubWVtbyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGV4cGxhaW4gYSBoYWxmIHNpZ25lZCBpbXBvcnQgdHJhbnNhY3Rpb24nLCBhc3luYyAoKSA9PiB7XG4gICAgICBjb25zdCB0ZXN0RGF0YSA9IElNUE9SVF9QO1xuICAgICAgY29uc3QgdHhFeHBsYWluID0gYXdhaXQgYmFzZWNvaW4uZXhwbGFpblRyYW5zYWN0aW9uKHtcbiAgICAgICAgaGFsZlNpZ25lZDogeyB0eEhleDogdGVzdERhdGEuaGFsZnNpZ250eEhleCB9LFxuICAgICAgfSk7XG4gICAgICB0eEV4cGxhaW4ub3V0cHV0QW1vdW50LnNob3VsZC5lcXVhbCgoTnVtYmVyKHRlc3REYXRhLmFtb3VudCkgLSB0eEV4cGxhaW4uZmVlPy5mZWUpLnRvU3RyaW5nKCkpO1xuICAgICAgdHhFeHBsYWluLnR5cGUuc2hvdWxkLmVxdWFsKFRyYW5zYWN0aW9uVHlwZS5JbXBvcnQpO1xuICAgICAgdHhFeHBsYWluLm91dHB1dHNbMF0uYWRkcmVzcy5zaG91bGQuZXF1YWwodGVzdERhdGEucEFkZHJlc3Nlcy5zb3J0KCkuam9pbignficpKTtcbiAgICAgIHR4RXhwbGFpbi5jaGFuZ2VPdXRwdXRzLnNob3VsZC5iZS5lbXB0eSgpO1xuICAgICAgdHhFeHBsYWluLm1lbW8uc2hvdWxkLmVxdWFsKHRlc3REYXRhLm1lbW8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBleHBsYWluIGEgc2lnbmVkIGltcG9ydCB0cmFuc2FjdGlvbicsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHRlc3REYXRhID0gSU1QT1JUX1A7XG4gICAgICBjb25zdCB0eEV4cGxhaW4gPSBhd2FpdCBiYXNlY29pbi5leHBsYWluVHJhbnNhY3Rpb24oeyB0eEhleDogdGVzdERhdGEuZnVsbHNpZ250eEhleCB9KTtcbiAgICAgIHR4RXhwbGFpbi5vdXRwdXRBbW91bnQuc2hvdWxkLmVxdWFsKChOdW1iZXIodGVzdERhdGEuYW1vdW50KSAtIHR4RXhwbGFpbi5mZWU/LmZlZSkudG9TdHJpbmcoKSk7XG4gICAgICB0eEV4cGxhaW4udHlwZS5zaG91bGQuZXF1YWwoVHJhbnNhY3Rpb25UeXBlLkltcG9ydCk7XG4gICAgICB0eEV4cGxhaW4ub3V0cHV0c1swXS5hZGRyZXNzLnNob3VsZC5lcXVhbCh0ZXN0RGF0YS5wQWRkcmVzc2VzLnNvcnQoKS5qb2luKCd+JykpO1xuICAgICAgdHhFeHBsYWluLmNoYW5nZU91dHB1dHMuc2hvdWxkLmJlLmVtcHR5KCk7XG4gICAgICB0eEV4cGxhaW4ubWVtby5zaG91bGQuZXF1YWwodGVzdERhdGEubWVtbyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGV4cGxhaW4gYSBoYWxmIHNpZ25lZCBpbXBvcnQgaW4gQyB0cmFuc2FjdGlvbicsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHRlc3REYXRhID0gSU1QT1JUX0M7XG4gICAgICBjb25zdCB0eEV4cGxhaW4gPSBhd2FpdCBiYXNlY29pbi5leHBsYWluVHJhbnNhY3Rpb24oeyB0eEhleDogdGVzdERhdGEuaGFsZnNpZ250eEhleCB9KTtcbiAgICAgIHR4RXhwbGFpbi5vdXRwdXRBbW91bnQuc2hvdWxkLmVxdWFsKChOdW1iZXIodGVzdERhdGEuYW1vdW50KSAtIHR4RXhwbGFpbi5mZWU/LmZlZSkudG9TdHJpbmcoKSk7XG4gICAgICB0eEV4cGxhaW4udHlwZS5zaG91bGQuZXF1YWwoVHJhbnNhY3Rpb25UeXBlLkltcG9ydCk7XG4gICAgICB0eEV4cGxhaW4ub3V0cHV0c1swXS5hZGRyZXNzLnNob3VsZC5lcXVhbCh0ZXN0RGF0YS50byk7XG4gICAgICB0eEV4cGxhaW4uY2hhbmdlT3V0cHV0cy5zaG91bGQuYmUuZW1wdHkoKTtcbiAgICAgIHNob3VsZC5ub3QuZXhpc3QodHhFeHBsYWluLm1lbW8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBleHBsYWluIGEgc2lnbmVkIGltcG9ydCBpbiBDIHRyYW5zYWN0aW9uJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgdGVzdERhdGEgPSBJTVBPUlRfQztcbiAgICAgIGNvbnN0IHR4RXhwbGFpbiA9IGF3YWl0IGJhc2Vjb2luLmV4cGxhaW5UcmFuc2FjdGlvbih7IHR4SGV4OiB0ZXN0RGF0YS5mdWxsc2lnbnR4SGV4IH0pO1xuICAgICAgdHhFeHBsYWluLm91dHB1dEFtb3VudC5zaG91bGQuZXF1YWwoKE51bWJlcih0ZXN0RGF0YS5hbW91bnQpIC0gdHhFeHBsYWluLmZlZT8uZmVlKS50b1N0cmluZygpKTtcbiAgICAgIHR4RXhwbGFpbi50eXBlLnNob3VsZC5lcXVhbChUcmFuc2FjdGlvblR5cGUuSW1wb3J0KTtcbiAgICAgIHR4RXhwbGFpbi5vdXRwdXRzWzBdLmFkZHJlc3Muc2hvdWxkLmVxdWFsKHRlc3REYXRhLnRvKTtcbiAgICAgIHR4RXhwbGFpbi5jaGFuZ2VPdXRwdXRzLnNob3VsZC5iZS5lbXB0eSgpO1xuICAgICAgc2hvdWxkLm5vdC5leGlzdCh0eEV4cGxhaW4ubWVtbyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGZhaWwgd2hlbiBhIHR4IGlzIG5vdCBwYXNzZWQgYXMgcGFyYW1ldGVyJywgYXN5bmMgKCkgPT4ge1xuICAgICAgYXdhaXQgYmFzZWNvaW4uZXhwbGFpblRyYW5zYWN0aW9uKHt9KS5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKCdtaXNzaW5nIHRyYW5zYWN0aW9uIGhleCcpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgndmVyaWZ5IHRyYW5zYWN0aW9uJywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgc3VjY2VlZCB0byB2ZXJpZnkgc2lnbmVkIHRyYW5zYWN0aW9uJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IHtcbiAgICAgICAgdHhIZXg6IHRlc3REYXRhLkFERFZBTElEQVRPUl9TQU1QTEVTLmZ1bGxzaWdudHhIZXgsXG4gICAgICAgIHR4SW5mbzoge30sXG4gICAgICB9O1xuICAgICAgY29uc3QgdHhQYXJhbXMgPSBuZXdUeFBhcmFtcygpO1xuICAgICAgY29uc3QgaXNUcmFuc2FjdGlvblZlcmlmaWVkID0gYXdhaXQgYmFzZWNvaW4udmVyaWZ5VHJhbnNhY3Rpb24oeyB0eFBhcmFtcywgdHhQcmVidWlsZCB9KTtcbiAgICAgIGlzVHJhbnNhY3Rpb25WZXJpZmllZC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHN1Y2NlZWQgdG8gdmVyaWZ5IGhhbGYgc2lnbmVkIHRyYW5zYWN0aW9uJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IHtcbiAgICAgICAgdHhIZXg6IHRlc3REYXRhLkFERFZBTElEQVRPUl9TQU1QTEVTLmhhbGZzaWdudHhIZXgsXG4gICAgICAgIHR4SW5mbzoge30sXG4gICAgICB9O1xuICAgICAgY29uc3QgdHhQYXJhbXMgPSBuZXdUeFBhcmFtcygpO1xuICAgICAgY29uc3QgaXNUcmFuc2FjdGlvblZlcmlmaWVkID0gYXdhaXQgYmFzZWNvaW4udmVyaWZ5VHJhbnNhY3Rpb24oeyB0eFBhcmFtcywgdHhQcmVidWlsZCB9KTtcbiAgICAgIGlzVHJhbnNhY3Rpb25WZXJpZmllZC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHN1Y2NlZWQgdG8gdmVyaWZ5IHVuc2lnbmVkIHRyYW5zYWN0aW9uJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IG5ld1R4UHJlYnVpbGQoKTtcbiAgICAgIGNvbnN0IHR4UGFyYW1zID0gbmV3VHhQYXJhbXMoKTtcbiAgICAgIGNvbnN0IGlzVHJhbnNhY3Rpb25WZXJpZmllZCA9IGF3YWl0IGJhc2Vjb2luLnZlcmlmeVRyYW5zYWN0aW9uKHsgdHhQYXJhbXMsIHR4UHJlYnVpbGQgfSk7XG4gICAgICBpc1RyYW5zYWN0aW9uVmVyaWZpZWQuc2hvdWxkLmVxdWFsKHRydWUpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBzdWNjZWVkIHRvIHZlcmlmeSB0cmFuc2FjdGlvbnMgd2hlbiByZWNpcGllbnRzIGhhcyBleHRyYSBkYXRhJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IG5ld1R4UHJlYnVpbGQoKTtcbiAgICAgIGNvbnN0IHR4UGFyYW1zID0gbmV3VHhQYXJhbXMoKTtcbiAgICAgIHR4UGFyYW1zLmRhdGEgPSAnZGF0YSc7XG5cbiAgICAgIGNvbnN0IHZhbGlkVHJhbnNhY3Rpb24gPSBhd2FpdCBiYXNlY29pbi52ZXJpZnlUcmFuc2FjdGlvbih7IHR4UGFyYW1zLCB0eFByZWJ1aWxkIH0pO1xuICAgICAgdmFsaWRUcmFuc2FjdGlvbi5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGZhaWwgdmVyaWZ5IHRyYW5zYWN0aW9ucyB3aGVuIGhhdmUgZGlmZmVyZW50IHR5cGUnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB0eFBhcmFtcyA9IG5ld1R4UGFyYW1zKCk7XG4gICAgICBjb25zdCB0eFByZWJ1aWxkID0gbmV3VHhQcmVidWlsZCgpO1xuICAgICAgdHhQYXJhbXMudHlwZSA9ICdhZGREZWxlZ2F0b3InO1xuICAgICAgYXdhaXQgYmFzZWNvaW5cbiAgICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgICB0eFBhcmFtcyxcbiAgICAgICAgICB0eFByZWJ1aWxkLFxuICAgICAgICB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgnVHggdHlwZSBkb2VzIG5vdCBtYXRjaCB3aXRoIGV4cGVjdGVkIHR4UGFyYW1zIHR5cGUnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZmFpbCB2ZXJpZnkgdHJhbnNhY3Rpb25zIHdoZW4gaGF2ZSBkaWZmZXJlbnQgbm9kZUlkJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdHhQYXJhbXMgPSBuZXdUeFBhcmFtcygpO1xuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IG5ld1R4UHJlYnVpbGQoKTtcbiAgICAgIHR4UGFyYW1zLnN0YWtpbmdPcHRpb25zLm5vZGVJRCA9ICdOb2RlSUQtTWR0ZVM5VTk4N1BZN2l3QTVQY3ozc0tWcHJKQWJBdkU3JztcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgICAgdHhQYXJhbXMsXG4gICAgICAgICAgdHhQcmVidWlsZCxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ1R4IG91dHB1dHMgZG9lcyBub3QgbWF0Y2ggd2l0aCBleHBlY3RlZCB0eFBhcmFtcycpO1xuICAgIH0pO1xuICAgIGl0KCdzaG91bGQgZmFpbCB2ZXJpZnkgd2hlbiBpbnB1dCBgbm9kZUlkYCBpcyBhYnNlbnQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB0eFByZWJ1aWxkID0gbmV3VHhQcmVidWlsZCgpO1xuICAgICAgY29uc3QgdHhQYXJhbXMgPSBuZXdUeFBhcmFtcygpO1xuICAgICAgdHhQYXJhbXMuc3Rha2luZ09wdGlvbnMubm9kZUlEID0gdW5kZWZpbmVkO1xuICAgICAgYXdhaXQgYmFzZWNvaW5cbiAgICAgICAgLnZlcmlmeVRyYW5zYWN0aW9uKHtcbiAgICAgICAgICB0eFBhcmFtcyxcbiAgICAgICAgICB0eFByZWJ1aWxkLFxuICAgICAgICB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgnVHggb3V0cHV0cyBkb2VzIG5vdCBtYXRjaCB3aXRoIGV4cGVjdGVkIHR4UGFyYW1zJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGZhaWwgdmVyaWZ5IHRyYW5zYWN0aW9ucyB3aGVuIGhhdmUgZGlmZmVyZW50IGFtb3VudCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHR4UGFyYW1zID0gbmV3VHhQYXJhbXMoKTtcbiAgICAgIGNvbnN0IHR4UHJlYnVpbGQgPSBuZXdUeFByZWJ1aWxkKCk7XG4gICAgICB0eFBhcmFtcy5zdGFraW5nT3B0aW9ucy5hbW91bnQgPSAnMjAwMDAwMDAwMCc7XG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAudmVyaWZ5VHJhbnNhY3Rpb24oe1xuICAgICAgICAgIHR4UGFyYW1zLFxuICAgICAgICAgIHR4UHJlYnVpbGQsXG4gICAgICAgIH0pXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKCdUeCBvdXRwdXRzIGRvZXMgbm90IG1hdGNoIHdpdGggZXhwZWN0ZWQgdHhQYXJhbXMnKTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIGZhaWwgdmVyaWZ5IHRyYW5zYWN0aW9ucyB3aGVuIGFtb3VudCBpcyBudW1iZXInLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB0eFBhcmFtcyA9IG5ld1R4UGFyYW1zKCk7XG4gICAgICBjb25zdCB0eFByZWJ1aWxkID0gbmV3VHhQcmVidWlsZCgpO1xuICAgICAgdHhQYXJhbXMuc3Rha2luZ09wdGlvbnMuYW1vdW50ID0gMTAwMDAwMDAwMDtcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgICAgdHhQYXJhbXMsXG4gICAgICAgICAgdHhQcmVidWlsZCxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ1R4IG91dHB1dHMgZG9lcyBub3QgbWF0Y2ggd2l0aCBleHBlY3RlZCB0eFBhcmFtcycpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmYWlsIHZlcmlmeSB0cmFuc2FjdGlvbnMgd2hlbiBhbW91bnQgaXMgYWJzZW50JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdHhQYXJhbXMgPSBuZXdUeFBhcmFtcygpO1xuICAgICAgY29uc3QgdHhQcmVidWlsZCA9IG5ld1R4UHJlYnVpbGQoKTtcbiAgICAgIHR4UGFyYW1zLnN0YWtpbmdPcHRpb25zLmFtb3VudCA9IHVuZGVmaW5lZDtcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC52ZXJpZnlUcmFuc2FjdGlvbih7XG4gICAgICAgICAgdHhQYXJhbXMsXG4gICAgICAgICAgdHhQcmVidWlsZCxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ1R4IG91dHB1dHMgZG9lcyBub3QgbWF0Y2ggd2l0aCBleHBlY3RlZCB0eFBhcmFtcycpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnVmFsaWRhdGlvbicsIGZ1bmN0aW9uICgpIHtcbiAgICBpdCgnc2hvdWxkIHZhbGlkYXRlIGFkZHJlc3MnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB2YWxpZEFkZHJlc3MgPSAnUC1mdWppMTVqYW13dWtmcWt3aGU4ejI2dGpxeGVqdGpkM2prOXZqNGtteHdhJztcbiAgICAgIGJhc2Vjb2luLmlzVmFsaWRBZGRyZXNzKHZhbGlkQWRkcmVzcykuc2hvdWxkLmJlLnRydWUoKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZmFpbCB0byB2YWxpZGF0ZSBpbnZhbGlkIGFkZHJlc3MnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBpbnZhbGlkQWRkcmVzc2VzID0gW3VuZGVmaW5lZCwgJycsICdhc2RhZHNhYWYnLCAnMTV4M3o0cnZrOGU3dndhNmc5bGt5Zzg5djVkd2tucDQ0ODU4dWV4J107XG4gICAgICBmb3IgKGNvbnN0IGFkZHJlc3Mgb2YgaW52YWxpZEFkZHJlc3Nlcykge1xuICAgICAgICBiYXNlY29pbi5pc1ZhbGlkQWRkcmVzcyhhZGRyZXNzKS5zaG91bGQuYmUuZmFsc2UoKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdmFsaWRhdGUgYW4gYXJyYXkgYWRkcmVzcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHZhbGlkQWRkcmVzc2VzID0gW1xuICAgICAgICAnUC1mdWppMTV4M3o0cnZrOGU3dndhNmc5bGt5Zzg5djVkd2tucDQ0ODU4dWV4JyxcbiAgICAgICAgJ1AtYXZheDE0M3E4bHN5M3k0a2U5ZDZ6ZWx0cmU4dTJhdGVlZDZ1azlrYTBudScsXG4gICAgICAgICdOb2RlSUQtMTQzcThsc3kzeTRrZTlkNnplbHRyZTh1MmF0ZWVkNnVrOWthMG51JyxcbiAgICAgIF07XG5cbiAgICAgIGJhc2Vjb2luLmlzVmFsaWRBZGRyZXNzKHZhbGlkQWRkcmVzc2VzKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmYWlsIHRvIHZhbGlkYXRlIGFuIGFycmF5IGFkZHJlc3Mgd2l0aCBpbnZhbGlkIGFkZHJlc3NzJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdmFsaWRBZGRyZXNzZXMgPSBbXG4gICAgICAgICdQLWZ1amkxNXgzejRydms4ZTd2d2E2Zzlsa3lnODl2NWR3a25wNDQ4NTh1ZXgnLFxuICAgICAgICAnUC1hdmF4MTQzcThsc3kzeTRrZTlkNnplbHRyZTh1MmF0ZWVkNnVrOWthMG51JyxcbiAgICAgICAgJ2ludmFsaWQtYWRkcmVzcycsXG4gICAgICBdO1xuXG4gICAgICBiYXNlY29pbi5pc1ZhbGlkQWRkcmVzcyh2YWxpZEFkZHJlc3Nlcykuc2hvdWxkLmJlLmZhbHNlKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHZhbGlkYXRlIGEgbXVsdHNpZyBhZGRyZXNzIHN0cmluZycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IG11bHRpU2lnVmFsaWRBZGRyZXNzID1cbiAgICAgICAgJ1AtZnVqaTF5enBmc2RhbGhmd2txMmNlZXdnczl3djdrMHVmdDQweWRwdWo1OX5QLWZ1amkxMDNjbW50c3NwNnFudWNlamFoZGR5NDJ3Y3k0cXR5MHVqNDI4MjJ+UC1mdWppMWhkazdudHcwaHVocW1saGxoZW1lOXQ3c2NzeTlsaGZodzN5d3k0JztcbiAgICAgIGJhc2Vjb2luLmlzVmFsaWRBZGRyZXNzKG11bHRpU2lnVmFsaWRBZGRyZXNzKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmYWlsIHRvIHZhbGlkYXRlIGEgbXVsdHNpZyBhZGRyZXNzIHN0cmluZyB3aXRoIGludmFsaWQgYWRkcmVzcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IG11bHRpU2lnVmFsaWRBZGRyZXNzID1cbiAgICAgICAgJ1AtZnVqaTF5enBmc2RhbGhmd2txMmNlZXdnczl3djdrMHVmdDQweWRwdWo1OX5pbnZhbGlkLWFkZHJlc3N+UC1mdWppMWhkazdudHcwaHVocW1saGxoZW1lOXQ3c2NzeTlsaGZodzN5d3k0JztcbiAgICAgIGJhc2Vjb2luLmlzVmFsaWRBZGRyZXNzKG11bHRpU2lnVmFsaWRBZGRyZXNzKS5zaG91bGQuYmUuZmFsc2UoKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgd2hlbiB2ZXJpZnlpbmcgYWRkcmVzcyBpZiBhZGRyZXNzIGxlbmd0aCBkb2VzbnQgbWF0Y2gga2V5Y2hhaW4gbGVuZ3RoJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdmFsaWRBZGRyZXNzZXMgPSBbXG4gICAgICAgIHtcbiAgICAgICAgICBhZGRyZXNzOiAnUC1mdWppMTV4M3o0cnZrOGU3dndhNmc5bGt5Zzg5djVkd2tucDQ0ODU4dWV4JyxcbiAgICAgICAgICBrZXljaGFpbnMsXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBhZGRyZXNzOiAnUC1mdWppMXdxMGQ1NnB1NTRzZ2M1eHBldm0zdXI2c2YzbDZra2U3MGR6MGw0JyxcbiAgICAgICAgICBrZXljaGFpbnMsXG4gICAgICAgIH0sXG4gICAgICBdO1xuXG4gICAgICBmb3IgKGNvbnN0IGFkZHJlc3NQYXJhbXMgb2YgdmFsaWRBZGRyZXNzZXMpIHtcbiAgICAgICAgc2hvdWxkLnRocm93cygoKSA9PiBiYXNlY29pbi52ZXJpZnlBZGRyZXNzKGFkZHJlc3NQYXJhbXMpKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZmFpbCB0byB2ZXJpZnkgaW52YWxpZCBhZGRyZXNzJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgaW52YWxpZEFkZHJlc3NlcyA9IFtcbiAgICAgICAge1xuICAgICAgICAgIGFkZHJlc3M6ICdQLWZ1amkxMDNjbW50c3NwNnFudWNlamFoZGR5NDJ3Y3k0cXR5MHVqNDI4MjInLFxuICAgICAgICAgIGtleWNoYWlucyxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIGFkZHJlc3M6ICdQLWF2YXgxNDNxOGxzeTN5NGtlOWQ2emVsdHJlOHUyYXRlZWQ2dWs5a2EwbnUnLFxuICAgICAgICAgIGtleWNoYWlucyxcbiAgICAgICAgfSxcbiAgICAgIF07XG5cbiAgICAgIGZvciAoY29uc3QgYWRkcmVzcyBvZiBpbnZhbGlkQWRkcmVzc2VzKSB7XG4gICAgICAgIHNob3VsZC50aHJvd3MoKCkgPT4gYmFzZWNvaW4udmVyaWZ5QWRkcmVzcyhhZGRyZXNzKSk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHN1Y2Nlc3NmdWxseSB2ZXJpZnkgaXMgd2FsbGV0IGFkZHJlc3MnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBiYXNlY29pblxuICAgICAgICAuaXNXYWxsZXRBZGRyZXNzKHtcbiAgICAgICAgICBhZGRyZXNzOlxuICAgICAgICAgICAgJ1AtZnVqaTE1eDN6NHJ2azhlN3Z3YTZnOWxreWc4OXY1ZHdrbnA0NDg1OHVleH5QLWZ1amkxd3EwZDU2cHU1NHNnYzV4cGV2bTN1cjZzZjNsNmtrZTcwZHowbDR+UC1mdWppMWNqazRjdmRmeTZmZmQ0Zmg4dW1wbm5ybWp0MHhkYXAwMnRjZXA2JyxcbiAgICAgICAgICBrZXljaGFpbnMsXG4gICAgICAgIH0pXG4gICAgICAgIC5zaG91bGQuYmUudHJ1ZSgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyB3aGVuIGFkZHJlc3MgbGVuZ3RoIGFuZCBrZXljaGFpbiBsZW5ndGggZG9udCBtYXRjaCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgIHNob3VsZC50aHJvd3MoKCkgPT5cbiAgICAgICAgYmFzZWNvaW4uaXNXYWxsZXRBZGRyZXNzKHtcbiAgICAgICAgICBhZGRyZXNzOiAnUC1mdWppMXdxMGQ1NnB1NTRzZ2M1eHBldm0zdXI2c2YzbDZra2U3MGR6MGw0flAtZnVqaTFjams0Y3ZkZnk2ZmZkNGZoOHVtcG5ucm1qdDB4ZGFwMDJ0Y2VwNicsXG4gICAgICAgICAga2V5Y2hhaW5zLFxuICAgICAgICB9KVxuICAgICAgKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgd2hlbiBrZXljaGFpbiBpcyBub3Qgb2YgbGVuZ3RoIDMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBzaG91bGQudGhyb3dzKCgpID0+XG4gICAgICAgIGJhc2Vjb2luLmlzV2FsbGV0QWRkcmVzcyh7XG4gICAgICAgICAgYWRkcmVzczogJ1AtZnVqaTF3cTBkNTZwdTU0c2djNXhwZXZtM3VyNnNmM2w2a2tlNzBkejBsNCcsXG4gICAgICAgICAga2V5Y2hhaW5zOiBrZXljaGFpbnNbMF0sXG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIH0pO1xuICB9KTtcbn0pO1xuIl19
|