@bitgo/sdk-coin-tempo 1.12.4 → 1.13.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.
@@ -0,0 +1,207 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const sinon_1 = __importDefault(require("sinon"));
7
+ const should_1 = __importDefault(require("should"));
8
+ const sdk_api_1 = require("@bitgo/sdk-api");
9
+ const sdk_test_1 = require("@bitgo/sdk-test");
10
+ const statics_1 = require("@bitgo/statics");
11
+ const tempo_1 = require("../../src/tempo");
12
+ const PATH_USD_ADDRESS = '0x20c0000000000000000000000000000000000000';
13
+ // secp256k1 generator point G (33 bytes) + 32-byte chaincode — valid commonKeyChain for deriveUnhardened
14
+ const TEST_BACKUP_KEY = '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798' +
15
+ '0000000000000000000000000000000000000000000000000000000000000001';
16
+ const TEST_RECOVERY_DESTINATION = '0x80151ebf635e6ec8a5455258f617be6cda1fbd7e';
17
+ describe('Tempo Recovery', function () {
18
+ let bitgo;
19
+ let basecoin;
20
+ let sandbox;
21
+ before(function () {
22
+ bitgo = sdk_test_1.TestBitGo.decorate(sdk_api_1.BitGoAPI, { env: 'mock' });
23
+ bitgo.safeRegister('tempo', (b) => {
24
+ const mockStaticsCoin = {
25
+ name: 'tempo',
26
+ fullName: 'Tempo',
27
+ family: statics_1.CoinFamily.TEMPO,
28
+ network: { type: 'mainnet' },
29
+ features: [],
30
+ };
31
+ return tempo_1.Tempo.createInstance(b, mockStaticsCoin);
32
+ });
33
+ bitgo.initializeTestVars();
34
+ basecoin = bitgo.coin('tempo');
35
+ });
36
+ beforeEach(function () {
37
+ sandbox = sinon_1.default.createSandbox();
38
+ });
39
+ afterEach(function () {
40
+ sandbox.restore();
41
+ });
42
+ describe('queryTempoRpc (via recoveryBlockchainExplorerQuery)', function () {
43
+ function mockFetch(responseBody) {
44
+ return sandbox.stub(global, 'fetch').resolves({
45
+ ok: true,
46
+ json: async () => responseBody,
47
+ });
48
+ }
49
+ it('returns { result: "0" } for account/balance without calling RPC', async function () {
50
+ const fetchStub = mockFetch({});
51
+ const result = await basecoin.recoveryBlockchainExplorerQuery({
52
+ module: 'account',
53
+ action: 'balance',
54
+ address: '0xabc',
55
+ });
56
+ result.should.deepEqual({ result: '0' });
57
+ fetchStub.called.should.equal(false);
58
+ });
59
+ it('calls eth_call with balanceOf selector for account/tokenbalance', async function () {
60
+ const fetchStub = mockFetch({ result: '0x4e20' }); // 20000 decimal
61
+ const result = await basecoin.recoveryBlockchainExplorerQuery({
62
+ module: 'account',
63
+ action: 'tokenbalance',
64
+ address: '0x1234567890123456789012345678901234567890',
65
+ contractaddress: PATH_USD_ADDRESS,
66
+ tag: 'latest',
67
+ });
68
+ result.should.deepEqual({ result: '20000' });
69
+ const body = JSON.parse(fetchStub.firstCall.args[1].body);
70
+ body.method.should.equal('eth_call');
71
+ body.params[0].data.should.startWith('0x70a08231');
72
+ });
73
+ it('calls eth_getTransactionCount for account/txlist and parses nonce', async function () {
74
+ mockFetch({ result: '0x5' });
75
+ const result = await basecoin.recoveryBlockchainExplorerQuery({
76
+ module: 'account',
77
+ action: 'txlist',
78
+ address: '0xabc',
79
+ });
80
+ result.should.deepEqual({ nonce: 5 });
81
+ });
82
+ it('returns { result: "0" } when RPC returns null body.result', async function () {
83
+ mockFetch({ result: null });
84
+ const result = await basecoin.recoveryBlockchainExplorerQuery({
85
+ module: 'account',
86
+ action: 'tokenbalance',
87
+ address: '0xabc',
88
+ contractaddress: PATH_USD_ADDRESS,
89
+ });
90
+ result.should.deepEqual({ result: '0' });
91
+ });
92
+ it('returns { result: "0" } when RPC returns malformed body.result', async function () {
93
+ mockFetch({ result: 'not-a-number' });
94
+ const result = await basecoin.recoveryBlockchainExplorerQuery({
95
+ module: 'account',
96
+ action: 'tokenbalance',
97
+ address: '0xabc',
98
+ contractaddress: PATH_USD_ADDRESS,
99
+ });
100
+ result.should.deepEqual({ result: '0' });
101
+ });
102
+ it('throws when the RPC returns an error field', async function () {
103
+ mockFetch({ error: { message: 'execution reverted' } });
104
+ await basecoin
105
+ .recoveryBlockchainExplorerQuery({
106
+ module: 'account',
107
+ action: 'tokenbalance',
108
+ address: '0xabc',
109
+ contractaddress: PATH_USD_ADDRESS,
110
+ })
111
+ .should.be.rejectedWith('Tempo RPC error: execution reverted');
112
+ });
113
+ it('throws for unsupported module/action', async function () {
114
+ await basecoin
115
+ .recoveryBlockchainExplorerQuery({ module: 'proxy', action: 'eth_blockNumber' })
116
+ .should.be.rejectedWith('queryTempoRpc: unsupported module=proxy action=eth_blockNumber');
117
+ });
118
+ });
119
+ describe('buildUnsignedSweepTxnTSS — gas margin calculation', function () {
120
+ function stubBalanceAndNonce(balance, nonce = 0) {
121
+ sandbox.stub(basecoin, 'queryAddressTokenBalance').resolves(balance);
122
+ sandbox.stub(basecoin, 'getAddressNonce').resolves(nonce);
123
+ }
124
+ it('deducts gasLimit × maxFeePerGas / 10^12 from pathUSD balance', async function () {
125
+ // gasMargin = 1_000_000 * 20_000_000_000 * 1.75 / 10^12 = 35_000
126
+ // sweepAmount = 1_000_000 - 35_000 = 965_000
127
+ stubBalanceAndNonce('1000000');
128
+ const result = (await basecoin.buildUnsignedSweepTxnTSS({
129
+ backupKey: TEST_BACKUP_KEY,
130
+ recoveryDestination: TEST_RECOVERY_DESTINATION,
131
+ tokenContractAddress: PATH_USD_ADDRESS,
132
+ gasLimit: 1000000,
133
+ eip1559: { maxFeePerGas: 20000000000, maxPriorityFeePerGas: 10000000000 },
134
+ }));
135
+ should_1.default.exist(result.txRequests);
136
+ result.txRequests[0].transactions[0].unsignedTx.should.have.property('serializedTxHex');
137
+ });
138
+ it('uses smaller margin when gasLimit is halved', async function () {
139
+ // gasMargin = 500_000 * 20_000_000_000 * 1.75 / 10^12 = 17_500
140
+ // sweepAmount = 50_000 - 17_500 = 32_500
141
+ stubBalanceAndNonce('50000');
142
+ const result = (await basecoin.buildUnsignedSweepTxnTSS({
143
+ backupKey: TEST_BACKUP_KEY,
144
+ recoveryDestination: TEST_RECOVERY_DESTINATION,
145
+ tokenContractAddress: PATH_USD_ADDRESS,
146
+ gasLimit: 500000,
147
+ eip1559: { maxFeePerGas: 20000000000, maxPriorityFeePerGas: 10000000000 },
148
+ }));
149
+ should_1.default.exist(result.txRequests);
150
+ });
151
+ it('throws when balance exactly equals the gas margin', async function () {
152
+ // gasMargin = 1_000_000 * 20_000_000_000 / 10^12 = 20_000; balance = 20_000 → sweepAmount = 0
153
+ stubBalanceAndNonce('20000');
154
+ await basecoin
155
+ .buildUnsignedSweepTxnTSS({
156
+ backupKey: TEST_BACKUP_KEY,
157
+ recoveryDestination: TEST_RECOVERY_DESTINATION,
158
+ tokenContractAddress: PATH_USD_ADDRESS,
159
+ gasLimit: 1000000,
160
+ eip1559: { maxFeePerGas: 20000000000, maxPriorityFeePerGas: 10000000000 },
161
+ })
162
+ .should.be.rejectedWith(/Insufficient balance/);
163
+ });
164
+ it('does not deduct margin when sweeping a non-pathUSD token', async function () {
165
+ const otherToken = '0x1111111111111111111111111111111111111111';
166
+ stubBalanceAndNonce('500');
167
+ const result = (await basecoin.buildUnsignedSweepTxnTSS({
168
+ backupKey: TEST_BACKUP_KEY,
169
+ recoveryDestination: TEST_RECOVERY_DESTINATION,
170
+ tokenContractAddress: otherToken,
171
+ gasLimit: 1000000,
172
+ eip1559: { maxFeePerGas: 20000000000, maxPriorityFeePerGas: 10000000000 },
173
+ }));
174
+ // Full balance of 500 swept; no margin deducted
175
+ should_1.default.exist(result.txRequests);
176
+ });
177
+ it('returns correct UnsignedSweepTxMPCv2 structure', async function () {
178
+ stubBalanceAndNonce('1000000');
179
+ const result = (await basecoin.buildUnsignedSweepTxnTSS({
180
+ backupKey: TEST_BACKUP_KEY,
181
+ recoveryDestination: TEST_RECOVERY_DESTINATION,
182
+ tokenContractAddress: PATH_USD_ADDRESS,
183
+ gasLimit: 1000000,
184
+ eip1559: { maxFeePerGas: 20000000000, maxPriorityFeePerGas: 10000000000 },
185
+ }));
186
+ const tx = result.txRequests[0].transactions[0];
187
+ tx.unsignedTx.derivationPath.should.equal('m/0');
188
+ tx.unsignedTx.coinSpecific.commonKeyChain.should.equal(TEST_BACKUP_KEY);
189
+ tx.signatureShares.should.deepEqual([]);
190
+ tx.nonce.should.equal(0);
191
+ });
192
+ });
193
+ describe('recoverTSS — unsigned sweep dispatch', function () {
194
+ it('routes to buildUnsignedSweepTxnTSS when keys are plain public keys', async function () {
195
+ const buildStub = sandbox.stub(basecoin, 'buildUnsignedSweepTxnTSS').resolves({ txRequests: [] });
196
+ sandbox.stub(basecoin, 'validateRecoveryParams').returns(undefined);
197
+ await basecoin.recoverTSS({
198
+ userKey: TEST_BACKUP_KEY,
199
+ backupKey: TEST_BACKUP_KEY,
200
+ isTss: true,
201
+ recoveryDestination: TEST_RECOVERY_DESTINATION,
202
+ });
203
+ buildStub.calledOnce.should.equal(true);
204
+ });
205
+ });
206
+ });
207
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVtcG8uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90ZXN0L3VuaXQvdGVtcG8udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxrREFBMEI7QUFDMUIsb0RBQTRCO0FBQzVCLDRDQUEwQztBQUMxQyw4Q0FBMEQ7QUFFMUQsNENBQXlFO0FBQ3pFLDJDQUF3QztBQUN4QyxNQUFNLGdCQUFnQixHQUFHLDRDQUE0QyxDQUFDO0FBRXRFLHlHQUF5RztBQUN6RyxNQUFNLGVBQWUsR0FDbkIsb0VBQW9FO0lBQ3BFLGtFQUFrRSxDQUFDO0FBQ3JFLE1BQU0seUJBQXlCLEdBQUcsNENBQTRDLENBQUM7QUFFL0UsUUFBUSxDQUFDLGdCQUFnQixFQUFFO0lBQ3pCLElBQUksS0FBbUIsQ0FBQztJQUN4QixJQUFJLFFBQWUsQ0FBQztJQUNwQixJQUFJLE9BQTJCLENBQUM7SUFFaEMsTUFBTSxDQUFDO1FBQ0wsS0FBSyxHQUFHLG9CQUFTLENBQUMsUUFBUSxDQUFDLGtCQUFRLEVBQUUsRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUN0RCxLQUFLLENBQUMsWUFBWSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQVksRUFBRSxFQUFFO1lBQzNDLE1BQU0sZUFBZSxHQUE4QjtnQkFDakQsSUFBSSxFQUFFLE9BQU87Z0JBQ2IsUUFBUSxFQUFFLE9BQU87Z0JBQ2pCLE1BQU0sRUFBRSxvQkFBVSxDQUFDLEtBQUs7Z0JBQ3hCLE9BQU8sRUFBRSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUU7Z0JBQzVCLFFBQVEsRUFBRSxFQUFFO2FBQ04sQ0FBQztZQUNULE9BQU8sYUFBSyxDQUFDLGNBQWMsQ0FBQyxDQUFDLEVBQUUsZUFBZSxDQUFDLENBQUM7UUFDbEQsQ0FBQyxDQUFDLENBQUM7UUFDSCxLQUFLLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztRQUMzQixRQUFRLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQVUsQ0FBQztJQUMxQyxDQUFDLENBQUMsQ0FBQztJQUVILFVBQVUsQ0FBQztRQUNULE9BQU8sR0FBRyxlQUFLLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDbEMsQ0FBQyxDQUFDLENBQUM7SUFFSCxTQUFTLENBQUM7UUFDUixPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDcEIsQ0FBQyxDQUFDLENBQUM7SUFFSCxRQUFRLENBQUMscURBQXFELEVBQUU7UUFDOUQsU0FBUyxTQUFTLENBQUMsWUFBcUM7WUFDdEQsT0FBTyxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxPQUFjLENBQUMsQ0FBQyxRQUFRLENBQUM7Z0JBQ25ELEVBQUUsRUFBRSxJQUFJO2dCQUNSLElBQUksRUFBRSxLQUFLLElBQUksRUFBRSxDQUFDLFlBQVk7YUFDeEIsQ0FBQyxDQUFDO1FBQ1osQ0FBQztRQUVELEVBQUUsQ0FBQyxpRUFBaUUsRUFBRSxLQUFLO1lBQ3pFLE1BQU0sU0FBUyxHQUFHLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUNoQyxNQUFNLE1BQU0sR0FBRyxNQUFNLFFBQVEsQ0FBQywrQkFBK0IsQ0FBQztnQkFDNUQsTUFBTSxFQUFFLFNBQVM7Z0JBQ2pCLE1BQU0sRUFBRSxTQUFTO2dCQUNqQixPQUFPLEVBQUUsT0FBTzthQUNqQixDQUFDLENBQUM7WUFDSCxNQUFNLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDO1lBQ3pDLFNBQVMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN2QyxDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyxpRUFBaUUsRUFBRSxLQUFLO1lBQ3pFLE1BQU0sU0FBUyxHQUFHLFNBQVMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUMsZ0JBQWdCO1lBQ25FLE1BQU0sTUFBTSxHQUFHLE1BQU0sUUFBUSxDQUFDLCtCQUErQixDQUFDO2dCQUM1RCxNQUFNLEVBQUUsU0FBUztnQkFDakIsTUFBTSxFQUFFLGNBQWM7Z0JBQ3RCLE9BQU8sRUFBRSw0Q0FBNEM7Z0JBQ3JELGVBQWUsRUFBRSxnQkFBZ0I7Z0JBQ2pDLEdBQUcsRUFBRSxRQUFRO2FBQ2QsQ0FBQyxDQUFDO1lBQ0gsTUFBTSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztZQUM3QyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzFELElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUNyQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQ3JELENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLG1FQUFtRSxFQUFFLEtBQUs7WUFDM0UsU0FBUyxDQUFDLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7WUFDN0IsTUFBTSxNQUFNLEdBQUcsTUFBTSxRQUFRLENBQUMsK0JBQStCLENBQUM7Z0JBQzVELE1BQU0sRUFBRSxTQUFTO2dCQUNqQixNQUFNLEVBQUUsUUFBUTtnQkFDaEIsT0FBTyxFQUFFLE9BQU87YUFDakIsQ0FBQyxDQUFDO1lBQ0gsTUFBTSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN4QyxDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQywyREFBMkQsRUFBRSxLQUFLO1lBQ25FLFNBQVMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1lBQzVCLE1BQU0sTUFBTSxHQUFHLE1BQU0sUUFBUSxDQUFDLCtCQUErQixDQUFDO2dCQUM1RCxNQUFNLEVBQUUsU0FBUztnQkFDakIsTUFBTSxFQUFFLGNBQWM7Z0JBQ3RCLE9BQU8sRUFBRSxPQUFPO2dCQUNoQixlQUFlLEVBQUUsZ0JBQWdCO2FBQ2xDLENBQUMsQ0FBQztZQUNILE1BQU0sQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDM0MsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsZ0VBQWdFLEVBQUUsS0FBSztZQUN4RSxTQUFTLENBQUMsRUFBRSxNQUFNLEVBQUUsY0FBYyxFQUFFLENBQUMsQ0FBQztZQUN0QyxNQUFNLE1BQU0sR0FBRyxNQUFNLFFBQVEsQ0FBQywrQkFBK0IsQ0FBQztnQkFDNUQsTUFBTSxFQUFFLFNBQVM7Z0JBQ2pCLE1BQU0sRUFBRSxjQUFjO2dCQUN0QixPQUFPLEVBQUUsT0FBTztnQkFDaEIsZUFBZSxFQUFFLGdCQUFnQjthQUNsQyxDQUFDLENBQUM7WUFDSCxNQUFNLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBQzNDLENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLDRDQUE0QyxFQUFFLEtBQUs7WUFDcEQsU0FBUyxDQUFDLEVBQUUsS0FBSyxFQUFFLEVBQUUsT0FBTyxFQUFFLG9CQUFvQixFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ3hELE1BQU0sUUFBUTtpQkFDWCwrQkFBK0IsQ0FBQztnQkFDL0IsTUFBTSxFQUFFLFNBQVM7Z0JBQ2pCLE1BQU0sRUFBRSxjQUFjO2dCQUN0QixPQUFPLEVBQUUsT0FBTztnQkFDaEIsZUFBZSxFQUFFLGdCQUFnQjthQUNsQyxDQUFDO2lCQUNELE1BQU0sQ0FBQyxFQUFFLENBQUMsWUFBWSxDQUFDLHFDQUFxQyxDQUFDLENBQUM7UUFDbkUsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsc0NBQXNDLEVBQUUsS0FBSztZQUM5QyxNQUFNLFFBQVE7aUJBQ1gsK0JBQStCLENBQUMsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxpQkFBaUIsRUFBRSxDQUFDO2lCQUMvRSxNQUFNLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxnRUFBZ0UsQ0FBQyxDQUFDO1FBQzlGLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7SUFFSCxRQUFRLENBQUMsbURBQW1ELEVBQUU7UUFDNUQsU0FBUyxtQkFBbUIsQ0FBQyxPQUFlLEVBQUUsS0FBSyxHQUFHLENBQUM7WUFDckQsT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFlLEVBQUUsMEJBQTBCLENBQUMsQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDNUUsT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFlLEVBQUUsaUJBQWlCLENBQUMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDbkUsQ0FBQztRQUVELEVBQUUsQ0FBQyw4REFBOEQsRUFBRSxLQUFLO1lBQ3RFLGlFQUFpRTtZQUNqRSw2Q0FBNkM7WUFDN0MsbUJBQW1CLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDL0IsTUFBTSxNQUFNLEdBQUcsQ0FBQyxNQUFPLFFBQWdCLENBQUMsd0JBQXdCLENBQUM7Z0JBQy9ELFNBQVMsRUFBRSxlQUFlO2dCQUMxQixtQkFBbUIsRUFBRSx5QkFBeUI7Z0JBQzlDLG9CQUFvQixFQUFFLGdCQUFnQjtnQkFDdEMsUUFBUSxFQUFFLE9BQVM7Z0JBQ25CLE9BQU8sRUFBRSxFQUFFLFlBQVksRUFBRSxXQUFjLEVBQUUsb0JBQW9CLEVBQUUsV0FBYyxFQUFFO2FBQ2hGLENBQUMsQ0FBUSxDQUFDO1lBQ1gsZ0JBQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQ2hDLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBQzFGLENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLDZDQUE2QyxFQUFFLEtBQUs7WUFDckQsK0RBQStEO1lBQy9ELHlDQUF5QztZQUN6QyxtQkFBbUIsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUM3QixNQUFNLE1BQU0sR0FBRyxDQUFDLE1BQU8sUUFBZ0IsQ0FBQyx3QkFBd0IsQ0FBQztnQkFDL0QsU0FBUyxFQUFFLGVBQWU7Z0JBQzFCLG1CQUFtQixFQUFFLHlCQUF5QjtnQkFDOUMsb0JBQW9CLEVBQUUsZ0JBQWdCO2dCQUN0QyxRQUFRLEVBQUUsTUFBTztnQkFDakIsT0FBTyxFQUFFLEVBQUUsWUFBWSxFQUFFLFdBQWMsRUFBRSxvQkFBb0IsRUFBRSxXQUFjLEVBQUU7YUFDaEYsQ0FBQyxDQUFRLENBQUM7WUFDWCxnQkFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDbEMsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsbURBQW1ELEVBQUUsS0FBSztZQUMzRCw4RkFBOEY7WUFDOUYsbUJBQW1CLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDN0IsTUFBTyxRQUFnQjtpQkFDcEIsd0JBQXdCLENBQUM7Z0JBQ3hCLFNBQVMsRUFBRSxlQUFlO2dCQUMxQixtQkFBbUIsRUFBRSx5QkFBeUI7Z0JBQzlDLG9CQUFvQixFQUFFLGdCQUFnQjtnQkFDdEMsUUFBUSxFQUFFLE9BQVM7Z0JBQ25CLE9BQU8sRUFBRSxFQUFFLFlBQVksRUFBRSxXQUFjLEVBQUUsb0JBQW9CLEVBQUUsV0FBYyxFQUFFO2FBQ2hGLENBQUM7aUJBQ0QsTUFBTSxDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQUMsc0JBQXNCLENBQUMsQ0FBQztRQUNwRCxDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQywwREFBMEQsRUFBRSxLQUFLO1lBQ2xFLE1BQU0sVUFBVSxHQUFHLDRDQUE0QyxDQUFDO1lBQ2hFLG1CQUFtQixDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQzNCLE1BQU0sTUFBTSxHQUFHLENBQUMsTUFBTyxRQUFnQixDQUFDLHdCQUF3QixDQUFDO2dCQUMvRCxTQUFTLEVBQUUsZUFBZTtnQkFDMUIsbUJBQW1CLEVBQUUseUJBQXlCO2dCQUM5QyxvQkFBb0IsRUFBRSxVQUFVO2dCQUNoQyxRQUFRLEVBQUUsT0FBUztnQkFDbkIsT0FBTyxFQUFFLEVBQUUsWUFBWSxFQUFFLFdBQWMsRUFBRSxvQkFBb0IsRUFBRSxXQUFjLEVBQUU7YUFDaEYsQ0FBQyxDQUFRLENBQUM7WUFDWCxnREFBZ0Q7WUFDaEQsZ0JBQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ2xDLENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLGdEQUFnRCxFQUFFLEtBQUs7WUFDeEQsbUJBQW1CLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDL0IsTUFBTSxNQUFNLEdBQUcsQ0FBQyxNQUFPLFFBQWdCLENBQUMsd0JBQXdCLENBQUM7Z0JBQy9ELFNBQVMsRUFBRSxlQUFlO2dCQUMxQixtQkFBbUIsRUFBRSx5QkFBeUI7Z0JBQzlDLG9CQUFvQixFQUFFLGdCQUFnQjtnQkFDdEMsUUFBUSxFQUFFLE9BQVM7Z0JBQ25CLE9BQU8sRUFBRSxFQUFFLFlBQVksRUFBRSxXQUFjLEVBQUUsb0JBQW9CLEVBQUUsV0FBYyxFQUFFO2FBQ2hGLENBQUMsQ0FBUSxDQUFDO1lBQ1gsTUFBTSxFQUFFLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDaEQsRUFBRSxDQUFDLFVBQVUsQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNqRCxFQUFFLENBQUMsVUFBVSxDQUFDLFlBQVksQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxlQUFlLENBQUMsQ0FBQztZQUN4RSxFQUFFLENBQUMsZUFBZSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDeEMsRUFBRSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzNCLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7SUFFSCxRQUFRLENBQUMsc0NBQXNDLEVBQUU7UUFDL0MsRUFBRSxDQUFDLG9FQUFvRSxFQUFFLEtBQUs7WUFDNUUsTUFBTSxTQUFTLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFlLEVBQUUsMEJBQTBCLENBQUMsQ0FBQyxRQUFRLENBQUMsRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUN6RyxPQUFPLENBQUMsSUFBSSxDQUFDLFFBQWUsRUFBRSx3QkFBd0IsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUUzRSxNQUFPLFFBQWdCLENBQUMsVUFBVSxDQUFDO2dCQUNqQyxPQUFPLEVBQUUsZUFBZTtnQkFDeEIsU0FBUyxFQUFFLGVBQWU7Z0JBQzFCLEtBQUssRUFBRSxJQUFJO2dCQUNYLG1CQUFtQixFQUFFLHlCQUF5QjthQUMvQyxDQUFDLENBQUM7WUFFSCxTQUFTLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDMUMsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHNpbm9uIGZyb20gJ3Npbm9uJztcbmltcG9ydCBzaG91bGQgZnJvbSAnc2hvdWxkJztcbmltcG9ydCB7IEJpdEdvQVBJIH0gZnJvbSAnQGJpdGdvL3Nkay1hcGknO1xuaW1wb3J0IHsgVGVzdEJpdEdvLCBUZXN0Qml0R29BUEkgfSBmcm9tICdAYml0Z28vc2RrLXRlc3QnO1xuaW1wb3J0IHsgQml0R29CYXNlIH0gZnJvbSAnQGJpdGdvL3Nkay1jb3JlJztcbmltcG9ydCB7IEJhc2VDb2luIGFzIFN0YXRpY3NCYXNlQ29pbiwgQ29pbkZhbWlseSB9IGZyb20gJ0BiaXRnby9zdGF0aWNzJztcbmltcG9ydCB7IFRlbXBvIH0gZnJvbSAnLi4vLi4vc3JjL3RlbXBvJztcbmNvbnN0IFBBVEhfVVNEX0FERFJFU1MgPSAnMHgyMGMwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwJztcblxuLy8gc2VjcDI1NmsxIGdlbmVyYXRvciBwb2ludCBHICgzMyBieXRlcykgKyAzMi1ieXRlIGNoYWluY29kZSDigJQgdmFsaWQgY29tbW9uS2V5Q2hhaW4gZm9yIGRlcml2ZVVuaGFyZGVuZWRcbmNvbnN0IFRFU1RfQkFDS1VQX0tFWSA9XG4gICcwMjc5YmU2NjdlZjlkY2JiYWM1NWEwNjI5NWNlODcwYjA3MDI5YmZjZGIyZGNlMjhkOTU5ZjI4MTViMTZmODE3OTgnICtcbiAgJzAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDEnO1xuY29uc3QgVEVTVF9SRUNPVkVSWV9ERVNUSU5BVElPTiA9ICcweDgwMTUxZWJmNjM1ZTZlYzhhNTQ1NTI1OGY2MTdiZTZjZGExZmJkN2UnO1xuXG5kZXNjcmliZSgnVGVtcG8gUmVjb3ZlcnknLCBmdW5jdGlvbiAoKSB7XG4gIGxldCBiaXRnbzogVGVzdEJpdEdvQVBJO1xuICBsZXQgYmFzZWNvaW46IFRlbXBvO1xuICBsZXQgc2FuZGJveDogc2lub24uU2lub25TYW5kYm94O1xuXG4gIGJlZm9yZShmdW5jdGlvbiAoKSB7XG4gICAgYml0Z28gPSBUZXN0Qml0R28uZGVjb3JhdGUoQml0R29BUEksIHsgZW52OiAnbW9jaycgfSk7XG4gICAgYml0Z28uc2FmZVJlZ2lzdGVyKCd0ZW1wbycsIChiOiBCaXRHb0Jhc2UpID0+IHtcbiAgICAgIGNvbnN0IG1vY2tTdGF0aWNzQ29pbjogUmVhZG9ubHk8U3RhdGljc0Jhc2VDb2luPiA9IHtcbiAgICAgICAgbmFtZTogJ3RlbXBvJyxcbiAgICAgICAgZnVsbE5hbWU6ICdUZW1wbycsXG4gICAgICAgIGZhbWlseTogQ29pbkZhbWlseS5URU1QTyxcbiAgICAgICAgbmV0d29yazogeyB0eXBlOiAnbWFpbm5ldCcgfSxcbiAgICAgICAgZmVhdHVyZXM6IFtdLFxuICAgICAgfSBhcyBhbnk7XG4gICAgICByZXR1cm4gVGVtcG8uY3JlYXRlSW5zdGFuY2UoYiwgbW9ja1N0YXRpY3NDb2luKTtcbiAgICB9KTtcbiAgICBiaXRnby5pbml0aWFsaXplVGVzdFZhcnMoKTtcbiAgICBiYXNlY29pbiA9IGJpdGdvLmNvaW4oJ3RlbXBvJykgYXMgVGVtcG87XG4gIH0pO1xuXG4gIGJlZm9yZUVhY2goZnVuY3Rpb24gKCkge1xuICAgIHNhbmRib3ggPSBzaW5vbi5jcmVhdGVTYW5kYm94KCk7XG4gIH0pO1xuXG4gIGFmdGVyRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgc2FuZGJveC5yZXN0b3JlKCk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdxdWVyeVRlbXBvUnBjICh2aWEgcmVjb3ZlcnlCbG9ja2NoYWluRXhwbG9yZXJRdWVyeSknLCBmdW5jdGlvbiAoKSB7XG4gICAgZnVuY3Rpb24gbW9ja0ZldGNoKHJlc3BvbnNlQm9keTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4pOiBzaW5vbi5TaW5vblN0dWIge1xuICAgICAgcmV0dXJuIHNhbmRib3guc3R1YihnbG9iYWwsICdmZXRjaCcgYXMgYW55KS5yZXNvbHZlcyh7XG4gICAgICAgIG9rOiB0cnVlLFxuICAgICAgICBqc29uOiBhc3luYyAoKSA9PiByZXNwb25zZUJvZHksXG4gICAgICB9IGFzIGFueSk7XG4gICAgfVxuXG4gICAgaXQoJ3JldHVybnMgeyByZXN1bHQ6IFwiMFwiIH0gZm9yIGFjY291bnQvYmFsYW5jZSB3aXRob3V0IGNhbGxpbmcgUlBDJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgZmV0Y2hTdHViID0gbW9ja0ZldGNoKHt9KTtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGJhc2Vjb2luLnJlY292ZXJ5QmxvY2tjaGFpbkV4cGxvcmVyUXVlcnkoe1xuICAgICAgICBtb2R1bGU6ICdhY2NvdW50JyxcbiAgICAgICAgYWN0aW9uOiAnYmFsYW5jZScsXG4gICAgICAgIGFkZHJlc3M6ICcweGFiYycsXG4gICAgICB9KTtcbiAgICAgIHJlc3VsdC5zaG91bGQuZGVlcEVxdWFsKHsgcmVzdWx0OiAnMCcgfSk7XG4gICAgICBmZXRjaFN0dWIuY2FsbGVkLnNob3VsZC5lcXVhbChmYWxzZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnY2FsbHMgZXRoX2NhbGwgd2l0aCBiYWxhbmNlT2Ygc2VsZWN0b3IgZm9yIGFjY291bnQvdG9rZW5iYWxhbmNlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgZmV0Y2hTdHViID0gbW9ja0ZldGNoKHsgcmVzdWx0OiAnMHg0ZTIwJyB9KTsgLy8gMjAwMDAgZGVjaW1hbFxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYmFzZWNvaW4ucmVjb3ZlcnlCbG9ja2NoYWluRXhwbG9yZXJRdWVyeSh7XG4gICAgICAgIG1vZHVsZTogJ2FjY291bnQnLFxuICAgICAgICBhY3Rpb246ICd0b2tlbmJhbGFuY2UnLFxuICAgICAgICBhZGRyZXNzOiAnMHgxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwJyxcbiAgICAgICAgY29udHJhY3RhZGRyZXNzOiBQQVRIX1VTRF9BRERSRVNTLFxuICAgICAgICB0YWc6ICdsYXRlc3QnLFxuICAgICAgfSk7XG4gICAgICByZXN1bHQuc2hvdWxkLmRlZXBFcXVhbCh7IHJlc3VsdDogJzIwMDAwJyB9KTtcbiAgICAgIGNvbnN0IGJvZHkgPSBKU09OLnBhcnNlKGZldGNoU3R1Yi5maXJzdENhbGwuYXJnc1sxXS5ib2R5KTtcbiAgICAgIGJvZHkubWV0aG9kLnNob3VsZC5lcXVhbCgnZXRoX2NhbGwnKTtcbiAgICAgIGJvZHkucGFyYW1zWzBdLmRhdGEuc2hvdWxkLnN0YXJ0V2l0aCgnMHg3MGEwODIzMScpO1xuICAgIH0pO1xuXG4gICAgaXQoJ2NhbGxzIGV0aF9nZXRUcmFuc2FjdGlvbkNvdW50IGZvciBhY2NvdW50L3R4bGlzdCBhbmQgcGFyc2VzIG5vbmNlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbW9ja0ZldGNoKHsgcmVzdWx0OiAnMHg1JyB9KTtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGJhc2Vjb2luLnJlY292ZXJ5QmxvY2tjaGFpbkV4cGxvcmVyUXVlcnkoe1xuICAgICAgICBtb2R1bGU6ICdhY2NvdW50JyxcbiAgICAgICAgYWN0aW9uOiAndHhsaXN0JyxcbiAgICAgICAgYWRkcmVzczogJzB4YWJjJyxcbiAgICAgIH0pO1xuICAgICAgcmVzdWx0LnNob3VsZC5kZWVwRXF1YWwoeyBub25jZTogNSB9KTtcbiAgICB9KTtcblxuICAgIGl0KCdyZXR1cm5zIHsgcmVzdWx0OiBcIjBcIiB9IHdoZW4gUlBDIHJldHVybnMgbnVsbCBib2R5LnJlc3VsdCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIG1vY2tGZXRjaCh7IHJlc3VsdDogbnVsbCB9KTtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGJhc2Vjb2luLnJlY292ZXJ5QmxvY2tjaGFpbkV4cGxvcmVyUXVlcnkoe1xuICAgICAgICBtb2R1bGU6ICdhY2NvdW50JyxcbiAgICAgICAgYWN0aW9uOiAndG9rZW5iYWxhbmNlJyxcbiAgICAgICAgYWRkcmVzczogJzB4YWJjJyxcbiAgICAgICAgY29udHJhY3RhZGRyZXNzOiBQQVRIX1VTRF9BRERSRVNTLFxuICAgICAgfSk7XG4gICAgICByZXN1bHQuc2hvdWxkLmRlZXBFcXVhbCh7IHJlc3VsdDogJzAnIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3JldHVybnMgeyByZXN1bHQ6IFwiMFwiIH0gd2hlbiBSUEMgcmV0dXJucyBtYWxmb3JtZWQgYm9keS5yZXN1bHQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBtb2NrRmV0Y2goeyByZXN1bHQ6ICdub3QtYS1udW1iZXInIH0pO1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYmFzZWNvaW4ucmVjb3ZlcnlCbG9ja2NoYWluRXhwbG9yZXJRdWVyeSh7XG4gICAgICAgIG1vZHVsZTogJ2FjY291bnQnLFxuICAgICAgICBhY3Rpb246ICd0b2tlbmJhbGFuY2UnLFxuICAgICAgICBhZGRyZXNzOiAnMHhhYmMnLFxuICAgICAgICBjb250cmFjdGFkZHJlc3M6IFBBVEhfVVNEX0FERFJFU1MsXG4gICAgICB9KTtcbiAgICAgIHJlc3VsdC5zaG91bGQuZGVlcEVxdWFsKHsgcmVzdWx0OiAnMCcgfSk7XG4gICAgfSk7XG5cbiAgICBpdCgndGhyb3dzIHdoZW4gdGhlIFJQQyByZXR1cm5zIGFuIGVycm9yIGZpZWxkJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbW9ja0ZldGNoKHsgZXJyb3I6IHsgbWVzc2FnZTogJ2V4ZWN1dGlvbiByZXZlcnRlZCcgfSB9KTtcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC5yZWNvdmVyeUJsb2NrY2hhaW5FeHBsb3JlclF1ZXJ5KHtcbiAgICAgICAgICBtb2R1bGU6ICdhY2NvdW50JyxcbiAgICAgICAgICBhY3Rpb246ICd0b2tlbmJhbGFuY2UnLFxuICAgICAgICAgIGFkZHJlc3M6ICcweGFiYycsXG4gICAgICAgICAgY29udHJhY3RhZGRyZXNzOiBQQVRIX1VTRF9BRERSRVNTLFxuICAgICAgICB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgnVGVtcG8gUlBDIGVycm9yOiBleGVjdXRpb24gcmV2ZXJ0ZWQnKTtcbiAgICB9KTtcblxuICAgIGl0KCd0aHJvd3MgZm9yIHVuc3VwcG9ydGVkIG1vZHVsZS9hY3Rpb24nLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAucmVjb3ZlcnlCbG9ja2NoYWluRXhwbG9yZXJRdWVyeSh7IG1vZHVsZTogJ3Byb3h5JywgYWN0aW9uOiAnZXRoX2Jsb2NrTnVtYmVyJyB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgncXVlcnlUZW1wb1JwYzogdW5zdXBwb3J0ZWQgbW9kdWxlPXByb3h5IGFjdGlvbj1ldGhfYmxvY2tOdW1iZXInKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ2J1aWxkVW5zaWduZWRTd2VlcFR4blRTUyDigJQgZ2FzIG1hcmdpbiBjYWxjdWxhdGlvbicsIGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBzdHViQmFsYW5jZUFuZE5vbmNlKGJhbGFuY2U6IHN0cmluZywgbm9uY2UgPSAwKSB7XG4gICAgICBzYW5kYm94LnN0dWIoYmFzZWNvaW4gYXMgYW55LCAncXVlcnlBZGRyZXNzVG9rZW5CYWxhbmNlJykucmVzb2x2ZXMoYmFsYW5jZSk7XG4gICAgICBzYW5kYm94LnN0dWIoYmFzZWNvaW4gYXMgYW55LCAnZ2V0QWRkcmVzc05vbmNlJykucmVzb2x2ZXMobm9uY2UpO1xuICAgIH1cblxuICAgIGl0KCdkZWR1Y3RzIGdhc0xpbWl0IMOXIG1heEZlZVBlckdhcyAvIDEwXjEyIGZyb20gcGF0aFVTRCBiYWxhbmNlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gZ2FzTWFyZ2luID0gMV8wMDBfMDAwICogMjBfMDAwXzAwMF8wMDAgKiAxLjc1IC8gMTBeMTIgPSAzNV8wMDBcbiAgICAgIC8vIHN3ZWVwQW1vdW50ID0gMV8wMDBfMDAwIC0gMzVfMDAwID0gOTY1XzAwMFxuICAgICAgc3R1YkJhbGFuY2VBbmROb25jZSgnMTAwMDAwMCcpO1xuICAgICAgY29uc3QgcmVzdWx0ID0gKGF3YWl0IChiYXNlY29pbiBhcyBhbnkpLmJ1aWxkVW5zaWduZWRTd2VlcFR4blRTUyh7XG4gICAgICAgIGJhY2t1cEtleTogVEVTVF9CQUNLVVBfS0VZLFxuICAgICAgICByZWNvdmVyeURlc3RpbmF0aW9uOiBURVNUX1JFQ09WRVJZX0RFU1RJTkFUSU9OLFxuICAgICAgICB0b2tlbkNvbnRyYWN0QWRkcmVzczogUEFUSF9VU0RfQUREUkVTUyxcbiAgICAgICAgZ2FzTGltaXQ6IDFfMDAwXzAwMCxcbiAgICAgICAgZWlwMTU1OTogeyBtYXhGZWVQZXJHYXM6IDIwXzAwMF8wMDBfMDAwLCBtYXhQcmlvcml0eUZlZVBlckdhczogMTBfMDAwXzAwMF8wMDAgfSxcbiAgICAgIH0pKSBhcyBhbnk7XG4gICAgICBzaG91bGQuZXhpc3QocmVzdWx0LnR4UmVxdWVzdHMpO1xuICAgICAgcmVzdWx0LnR4UmVxdWVzdHNbMF0udHJhbnNhY3Rpb25zWzBdLnVuc2lnbmVkVHguc2hvdWxkLmhhdmUucHJvcGVydHkoJ3NlcmlhbGl6ZWRUeEhleCcpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3VzZXMgc21hbGxlciBtYXJnaW4gd2hlbiBnYXNMaW1pdCBpcyBoYWx2ZWQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAvLyBnYXNNYXJnaW4gPSA1MDBfMDAwICogMjBfMDAwXzAwMF8wMDAgKiAxLjc1IC8gMTBeMTIgPSAxN181MDBcbiAgICAgIC8vIHN3ZWVwQW1vdW50ID0gNTBfMDAwIC0gMTdfNTAwID0gMzJfNTAwXG4gICAgICBzdHViQmFsYW5jZUFuZE5vbmNlKCc1MDAwMCcpO1xuICAgICAgY29uc3QgcmVzdWx0ID0gKGF3YWl0IChiYXNlY29pbiBhcyBhbnkpLmJ1aWxkVW5zaWduZWRTd2VlcFR4blRTUyh7XG4gICAgICAgIGJhY2t1cEtleTogVEVTVF9CQUNLVVBfS0VZLFxuICAgICAgICByZWNvdmVyeURlc3RpbmF0aW9uOiBURVNUX1JFQ09WRVJZX0RFU1RJTkFUSU9OLFxuICAgICAgICB0b2tlbkNvbnRyYWN0QWRkcmVzczogUEFUSF9VU0RfQUREUkVTUyxcbiAgICAgICAgZ2FzTGltaXQ6IDUwMF8wMDAsXG4gICAgICAgIGVpcDE1NTk6IHsgbWF4RmVlUGVyR2FzOiAyMF8wMDBfMDAwXzAwMCwgbWF4UHJpb3JpdHlGZWVQZXJHYXM6IDEwXzAwMF8wMDBfMDAwIH0sXG4gICAgICB9KSkgYXMgYW55O1xuICAgICAgc2hvdWxkLmV4aXN0KHJlc3VsdC50eFJlcXVlc3RzKTtcbiAgICB9KTtcblxuICAgIGl0KCd0aHJvd3Mgd2hlbiBiYWxhbmNlIGV4YWN0bHkgZXF1YWxzIHRoZSBnYXMgbWFyZ2luJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gZ2FzTWFyZ2luID0gMV8wMDBfMDAwICogMjBfMDAwXzAwMF8wMDAgLyAxMF4xMiA9IDIwXzAwMDsgYmFsYW5jZSA9IDIwXzAwMCDihpIgc3dlZXBBbW91bnQgPSAwXG4gICAgICBzdHViQmFsYW5jZUFuZE5vbmNlKCcyMDAwMCcpO1xuICAgICAgYXdhaXQgKGJhc2Vjb2luIGFzIGFueSlcbiAgICAgICAgLmJ1aWxkVW5zaWduZWRTd2VlcFR4blRTUyh7XG4gICAgICAgICAgYmFja3VwS2V5OiBURVNUX0JBQ0tVUF9LRVksXG4gICAgICAgICAgcmVjb3ZlcnlEZXN0aW5hdGlvbjogVEVTVF9SRUNPVkVSWV9ERVNUSU5BVElPTixcbiAgICAgICAgICB0b2tlbkNvbnRyYWN0QWRkcmVzczogUEFUSF9VU0RfQUREUkVTUyxcbiAgICAgICAgICBnYXNMaW1pdDogMV8wMDBfMDAwLFxuICAgICAgICAgIGVpcDE1NTk6IHsgbWF4RmVlUGVyR2FzOiAyMF8wMDBfMDAwXzAwMCwgbWF4UHJpb3JpdHlGZWVQZXJHYXM6IDEwXzAwMF8wMDBfMDAwIH0sXG4gICAgICAgIH0pXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9JbnN1ZmZpY2llbnQgYmFsYW5jZS8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ2RvZXMgbm90IGRlZHVjdCBtYXJnaW4gd2hlbiBzd2VlcGluZyBhIG5vbi1wYXRoVVNEIHRva2VuJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3Qgb3RoZXJUb2tlbiA9ICcweDExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTEnO1xuICAgICAgc3R1YkJhbGFuY2VBbmROb25jZSgnNTAwJyk7XG4gICAgICBjb25zdCByZXN1bHQgPSAoYXdhaXQgKGJhc2Vjb2luIGFzIGFueSkuYnVpbGRVbnNpZ25lZFN3ZWVwVHhuVFNTKHtcbiAgICAgICAgYmFja3VwS2V5OiBURVNUX0JBQ0tVUF9LRVksXG4gICAgICAgIHJlY292ZXJ5RGVzdGluYXRpb246IFRFU1RfUkVDT1ZFUllfREVTVElOQVRJT04sXG4gICAgICAgIHRva2VuQ29udHJhY3RBZGRyZXNzOiBvdGhlclRva2VuLFxuICAgICAgICBnYXNMaW1pdDogMV8wMDBfMDAwLFxuICAgICAgICBlaXAxNTU5OiB7IG1heEZlZVBlckdhczogMjBfMDAwXzAwMF8wMDAsIG1heFByaW9yaXR5RmVlUGVyR2FzOiAxMF8wMDBfMDAwXzAwMCB9LFxuICAgICAgfSkpIGFzIGFueTtcbiAgICAgIC8vIEZ1bGwgYmFsYW5jZSBvZiA1MDAgc3dlcHQ7IG5vIG1hcmdpbiBkZWR1Y3RlZFxuICAgICAgc2hvdWxkLmV4aXN0KHJlc3VsdC50eFJlcXVlc3RzKTtcbiAgICB9KTtcblxuICAgIGl0KCdyZXR1cm5zIGNvcnJlY3QgVW5zaWduZWRTd2VlcFR4TVBDdjIgc3RydWN0dXJlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgc3R1YkJhbGFuY2VBbmROb25jZSgnMTAwMDAwMCcpO1xuICAgICAgY29uc3QgcmVzdWx0ID0gKGF3YWl0IChiYXNlY29pbiBhcyBhbnkpLmJ1aWxkVW5zaWduZWRTd2VlcFR4blRTUyh7XG4gICAgICAgIGJhY2t1cEtleTogVEVTVF9CQUNLVVBfS0VZLFxuICAgICAgICByZWNvdmVyeURlc3RpbmF0aW9uOiBURVNUX1JFQ09WRVJZX0RFU1RJTkFUSU9OLFxuICAgICAgICB0b2tlbkNvbnRyYWN0QWRkcmVzczogUEFUSF9VU0RfQUREUkVTUyxcbiAgICAgICAgZ2FzTGltaXQ6IDFfMDAwXzAwMCxcbiAgICAgICAgZWlwMTU1OTogeyBtYXhGZWVQZXJHYXM6IDIwXzAwMF8wMDBfMDAwLCBtYXhQcmlvcml0eUZlZVBlckdhczogMTBfMDAwXzAwMF8wMDAgfSxcbiAgICAgIH0pKSBhcyBhbnk7XG4gICAgICBjb25zdCB0eCA9IHJlc3VsdC50eFJlcXVlc3RzWzBdLnRyYW5zYWN0aW9uc1swXTtcbiAgICAgIHR4LnVuc2lnbmVkVHguZGVyaXZhdGlvblBhdGguc2hvdWxkLmVxdWFsKCdtLzAnKTtcbiAgICAgIHR4LnVuc2lnbmVkVHguY29pblNwZWNpZmljLmNvbW1vbktleUNoYWluLnNob3VsZC5lcXVhbChURVNUX0JBQ0tVUF9LRVkpO1xuICAgICAgdHguc2lnbmF0dXJlU2hhcmVzLnNob3VsZC5kZWVwRXF1YWwoW10pO1xuICAgICAgdHgubm9uY2Uuc2hvdWxkLmVxdWFsKDApO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgncmVjb3ZlclRTUyDigJQgdW5zaWduZWQgc3dlZXAgZGlzcGF0Y2gnLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3JvdXRlcyB0byBidWlsZFVuc2lnbmVkU3dlZXBUeG5UU1Mgd2hlbiBrZXlzIGFyZSBwbGFpbiBwdWJsaWMga2V5cycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGJ1aWxkU3R1YiA9IHNhbmRib3guc3R1YihiYXNlY29pbiBhcyBhbnksICdidWlsZFVuc2lnbmVkU3dlZXBUeG5UU1MnKS5yZXNvbHZlcyh7IHR4UmVxdWVzdHM6IFtdIH0pO1xuICAgICAgc2FuZGJveC5zdHViKGJhc2Vjb2luIGFzIGFueSwgJ3ZhbGlkYXRlUmVjb3ZlcnlQYXJhbXMnKS5yZXR1cm5zKHVuZGVmaW5lZCk7XG5cbiAgICAgIGF3YWl0IChiYXNlY29pbiBhcyBhbnkpLnJlY292ZXJUU1Moe1xuICAgICAgICB1c2VyS2V5OiBURVNUX0JBQ0tVUF9LRVksXG4gICAgICAgIGJhY2t1cEtleTogVEVTVF9CQUNLVVBfS0VZLFxuICAgICAgICBpc1RzczogdHJ1ZSxcbiAgICAgICAgcmVjb3ZlcnlEZXN0aW5hdGlvbjogVEVTVF9SRUNPVkVSWV9ERVNUSU5BVElPTixcbiAgICAgIH0pO1xuXG4gICAgICBidWlsZFN0dWIuY2FsbGVkT25jZS5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG4gIH0pO1xufSk7XG4iXX0=