@bitgo-beta/sdk-coin-ethw 1.3.3-alpha.43 → 1.3.3-alpha.430

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,262 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const nock = __importStar(require("nock"));
37
+ const should = __importStar(require("should"));
38
+ const sdk_test_1 = require("@bitgo-beta/sdk-test");
39
+ const sdk_api_1 = require("@bitgo-beta/sdk-api");
40
+ const index_1 = require("../../src/index");
41
+ const recovery_nocks_1 = require("../lib/recovery-nocks");
42
+ nock.disableNetConnect();
43
+ const bitgo = sdk_test_1.TestBitGo.decorate(sdk_api_1.BitGoAPI, { env: 'test' });
44
+ bitgo.safeRegister('ethw', index_1.Ethw.createInstance);
45
+ describe('Ethereum pow', function () {
46
+ let basecoin;
47
+ before(function () {
48
+ bitgo.initializeTestVars();
49
+ basecoin = bitgo.coin('ethw');
50
+ });
51
+ after(function () {
52
+ nock.cleanAll();
53
+ });
54
+ it('should instantiate the coin', function () {
55
+ const basecoin = bitgo.coin('ethw');
56
+ basecoin.should.be.an.instanceof(index_1.Ethw);
57
+ });
58
+ describe('Recover Ethereum PoW', function () {
59
+ beforeEach(() => {
60
+ nock.cleanAll();
61
+ });
62
+ let recoveryParams;
63
+ before(() => {
64
+ recoveryParams = {
65
+ userKey: '{"iv":"+TkmT3GJ5msVWQjBrt3lsw==","v":1,"iter":10000,"ks":256,"ts":64,"mode"\n' +
66
+ ':"ccm","adata":"","cipher":"aes","salt":"cCE20fGIobs=","ct":"NVIdYIh91J3aRI\n' +
67
+ '8GG0JE3DhXW3AUmz2G5RqMejdz1+t4/vovIP7lleegI7VYyWiiLvlM0OCFf3EVvV/RyXr8+2vsn\n' +
68
+ 'Q0Vn8c2CV5FRZ80OjGYrW3A/6T/zpOz6E8CMvnD++iIpeO4r2eZJavejZxdzlxF0BRz7VI="}',
69
+ backupKey: '{"iv":"asB356ofC7nZtg4NBvQkiQ==","v":1,"iter":10000,"ks":256,"ts":64,"mode"\n' +
70
+ ':"ccm","adata":"","cipher":"aes","salt":"1hr2HhBbBIk=","ct":"8CZc6upt+XNOto\n' +
71
+ 'KDD38TUg3ZUjzW+DraZlkcku2bNp0JS2s1g/iC6YTGUGtPoxDxumDlXwlWQx+5WPjZu79M8DCrI\n' +
72
+ 't9aZaOvHkGH9aFtMbavFX419TcrwDmpUeQFN0hRkfrIHXyHNbTpGSVAjHvHMtzDMaw+ACg="}',
73
+ walletPassphrase: sdk_test_1.TestBitGo.V2.TEST_RECOVERY_PASSCODE,
74
+ walletContractAddress: '0x5df5a96b478bb1808140d87072143e60262e8670',
75
+ recoveryDestination: '0xac05da78464520aa7c9d4c19bd7a440b111b3054',
76
+ replayProtectionOptions: {
77
+ chain: 10001,
78
+ },
79
+ };
80
+ });
81
+ it('should throw on invalid gasLimit', async function () {
82
+ (0, recovery_nocks_1.nockEthwRecovery)(bitgo);
83
+ await basecoin
84
+ .recover({
85
+ ...recoveryParams,
86
+ gasLimit: -400000,
87
+ gasPrice: 25000000000,
88
+ })
89
+ .should.be.rejectedWith('Gas limit must be between 30000 and 20000000');
90
+ });
91
+ it('should throw if etherscan errs', async function () {
92
+ const nockUnsuccessfulEtherscanData = [
93
+ {
94
+ params: {
95
+ method: 'eth_getTransactionCount',
96
+ params: ['0x74c2137d54b0fc9f907e13f14e0dd18485fee924', 'latest'],
97
+ },
98
+ response: {
99
+ result: '0x0',
100
+ id: 0,
101
+ jsonrpc: '2.0',
102
+ },
103
+ },
104
+ {
105
+ params: {
106
+ method: 'eth_getBalance',
107
+ params: ['0x74c2137d54b0fc9f907e13f14e0dd18485fee924', 'latest'],
108
+ },
109
+ response: {
110
+ error: {
111
+ code: -32602,
112
+ message: 'invalid argument 0: json: cannot unmarshal hex string of odd length into Go value of type common.Address',
113
+ },
114
+ id: 0,
115
+ jsonrpc: '2.0',
116
+ },
117
+ },
118
+ ];
119
+ (0, recovery_nocks_1.nockEthwRecovery)(bitgo, nockUnsuccessfulEtherscanData);
120
+ await basecoin
121
+ .recover(recoveryParams)
122
+ .should.be.rejectedWith('ETHW full node error: -32602 - invalid argument 0: json: cannot unmarshal hex string of odd length into Go value of type common.Address');
123
+ });
124
+ it('should throw if backup key address has insufficient balance', async function () {
125
+ const insufficientFeeData = [
126
+ {
127
+ params: {
128
+ method: 'eth_getTransactionCount',
129
+ params: ['0x74c2137d54b0fc9f907e13f14e0dd18485fee924', 'latest'],
130
+ },
131
+ response: {
132
+ id: 0,
133
+ jsonrpc: '2.0',
134
+ result: '0x0',
135
+ },
136
+ },
137
+ {
138
+ params: {
139
+ method: 'eth_getBalance',
140
+ params: ['0x74c2137d54b0fc9f907e13f14e0dd18485fee924', 'latest'],
141
+ },
142
+ response: {
143
+ id: 0,
144
+ jsonrpc: '2.0',
145
+ result: '0x4d2',
146
+ },
147
+ },
148
+ ];
149
+ (0, recovery_nocks_1.nockEthwRecovery)(bitgo, insufficientFeeData);
150
+ await basecoin
151
+ .recover({
152
+ ...recoveryParams,
153
+ gasLimit: 300000,
154
+ gasPrice: 1000000000,
155
+ })
156
+ .should.be.rejectedWith('Backup key address 0x74c2137d54b0fc9f907e13f14e0dd18485fee924 has balance 0.000001234 Gwei.' +
157
+ 'This address must have a balance of at least 300000 Gwei to perform recoveries. Try sending some ETH to this address then retry.');
158
+ });
159
+ it('should throw on invalid gasPrice', async function () {
160
+ (0, recovery_nocks_1.nockEthwRecovery)(bitgo);
161
+ await basecoin
162
+ .recover({
163
+ ...recoveryParams,
164
+ gasLimit: 400000,
165
+ gasPrice: 2500000,
166
+ })
167
+ .should.be.rejectedWith('Gas price must be between 1000000000 and 2500000000000');
168
+ });
169
+ it('should successfully construct a tx with custom gas price and limit', async function () {
170
+ (0, recovery_nocks_1.nockEthwRecovery)(bitgo);
171
+ const recovery = await basecoin.recover({
172
+ ...recoveryParams,
173
+ gasLimit: 400000,
174
+ gasPrice: 1000000000,
175
+ });
176
+ // id and tx will always be different because of expireTime
177
+ should.exist(recovery);
178
+ recovery.should.have.property('id');
179
+ recovery.should.have.property('tx');
180
+ await checkRecoveryTxExplanation(recovery.tx, 2200000000000000000, recoveryParams.recoveryDestination);
181
+ });
182
+ it('should construct a recovery transaction without BitGo', async function () {
183
+ (0, recovery_nocks_1.nockEthwRecovery)(bitgo);
184
+ const recovery = await basecoin.recover(recoveryParams);
185
+ // id and tx will always be different because of expireTime
186
+ should.exist(recovery);
187
+ recovery.should.have.property('id');
188
+ recovery.should.have.property('tx');
189
+ await checkRecoveryTxExplanation(recovery.tx, 2200000000000000000, recoveryParams.recoveryDestination);
190
+ });
191
+ it('should construct a recovery transaction without BitGo and with KRS', async function () {
192
+ (0, recovery_nocks_1.nockEthwRecovery)(bitgo);
193
+ const recovery = await basecoin.recover({
194
+ ...recoveryParams,
195
+ backupKey: 'xpub661MyMwAqRbcGsCNiG4BzbxLmXnJFo4K5gVSE2b9AxufAtpuTun1SYwg9Uykqqf4DrKrDZ6KqPm9ehthWbCma7pnaMrtXY11nY7MeFbEDPm',
196
+ krsProvider: 'keyternal',
197
+ });
198
+ // id and tx will always be different because of expireTime
199
+ should.exist(recovery);
200
+ recovery.should.have.property('id');
201
+ recovery.should.have.property('tx');
202
+ await checkRecoveryTxExplanation(recovery.tx, 2200000000000000000, recoveryParams.recoveryDestination);
203
+ });
204
+ it('should error when the backup key is unfunded (cannot pay gas)', async function () {
205
+ (0, recovery_nocks_1.nockEthwRecovery)(bitgo);
206
+ await basecoin
207
+ .recover({
208
+ userKey: '{"iv":"VNvG6t3fHfxMcfvNuafYYA==","v":1,"iter":10000,"ks":256,"ts":64,"mode"\n' +
209
+ ':"ccm","adata":"","cipher":"aes","salt":"mc9pCk3H43w=","ct":"Qe4Z1evaXcrOMC\n' +
210
+ 'cQ/XMVVBO9M/99D1QQ6LxkG8z3fQtwwOVXM3/6doNrriprUqs+adpFC93KRcAaDroL1E6o17J2k\n' +
211
+ 'mcpXRd2CuXRFORZmZ/6QBfjKfCJ3aq0kEkDVv37gZNVT3aNtGkNSQdCEWKQLwd1++r5AkA="}\n',
212
+ backupKey: '{"iv":"EjD7x0OJX9kNM/C3yEDvyQ==","v":1,"iter":10000,"ks":256,"ts":64,"mode"\n' +
213
+ ':"ccm","adata":"","cipher":"aes","salt":"Na9NvRRe3n8=","ct":"B/AtSLHolsdNLr\n' +
214
+ '4Dlij4kQ0E6NyUUs6wo6T2HtPDAPO0hyhPPbh1OAYqIS7VlL9xmJRFC2zPxwRJvzf6OWC/m48HX\n' +
215
+ 'vgLoXYgahArhalzJVlRxcXUz4HOhozRWfv/eK3t5HJfm+25+WBOiW8YgSE7hVEYTbeBRD4="}',
216
+ walletContractAddress: '0x22ff743216b58aeb3efc46985406b50112e9e176',
217
+ walletPassphrase: sdk_test_1.TestBitGo.V2.TEST_RECOVERY_PASSCODE,
218
+ recoveryDestination: '0xac05da78464520aa7c9d4c19bd7a440b111b3054',
219
+ })
220
+ .should.be.rejectedWith('Backup key address 0xba6d9d82cf2920c544b834b72f4c6d11a3ef3de6 has balance 0 Gwei.This address must have a balance of at least 10000000 Gwei to perform recoveries. Try sending some ETH to this address then retry.');
221
+ });
222
+ it('should generate an ETH unsigned sweep', async function () {
223
+ (0, recovery_nocks_1.nockEthwRecovery)(bitgo);
224
+ const transaction = await basecoin.recover({
225
+ userKey: 'xpub661MyMwAqRbcFXDcWD2vxuebcT1ZpTF4Vke6qmMW8yzddwNYpAPjvYEEL5jLfyYXW2fuxtAxY8TgjPUJLcf1C8qz9N6VgZxArKX4EwB8rH5',
226
+ backupKey: 'xpub661MyMwAqRbcGhSaXikpuTC9KU88Xx9LrjKSw1JKsvXNgabpTdgjy7LSovh9ZHhcqhAHQu7uthu7FguNGdcC4aXTKK5gqTcPe4WvLYRbCSG',
227
+ walletContractAddress: sdk_test_1.TestBitGo.V2.TEST_ETH_WALLET_FIRST_ADDRESS,
228
+ recoveryDestination: sdk_test_1.TestBitGo.V2.TEST_ERC20_TOKEN_RECIPIENT,
229
+ gasPrice: '20000000000',
230
+ gasLimit: '500000',
231
+ });
232
+ should.exist(transaction);
233
+ transaction.should.have.property('tx');
234
+ transaction.should.have.property('contractSequenceId');
235
+ transaction.should.have.property('expireTime');
236
+ transaction.should.have.property('gasLimit');
237
+ transaction.gasLimit.should.equal('500000');
238
+ transaction.should.have.property('gasPrice');
239
+ transaction.gasPrice.should.equal('20000000000');
240
+ transaction.should.have.property('walletContractAddress');
241
+ transaction.walletContractAddress.should.equal(sdk_test_1.TestBitGo.V2.TEST_ETH_WALLET_FIRST_ADDRESS);
242
+ transaction.should.have.property('recipient');
243
+ transaction.recipient.should.have.property('address');
244
+ transaction.recipient.address.should.equal(sdk_test_1.TestBitGo.V2.TEST_ERC20_TOKEN_RECIPIENT);
245
+ transaction.recipient.should.have.property('amount');
246
+ transaction.recipient.amount.should.equal('9999999999999999928');
247
+ checkRecoveryTxExplanation(transaction.tx, 9999999999999999928, sdk_test_1.TestBitGo.V2.TEST_ERC20_TOKEN_RECIPIENT);
248
+ });
249
+ async function checkRecoveryTxExplanation(tx, recoveryAmount, recoveryDestination) {
250
+ const explanation = await basecoin.explainTransaction({ txHex: '0x' + tx, feeInfo: { fee: 1 } });
251
+ explanation.should.have.property('outputs');
252
+ explanation.outputs.should.containEql({
253
+ amount: recoveryAmount.toFixed(),
254
+ address: recoveryDestination,
255
+ });
256
+ explanation.should.have.property('changeOutputs', []);
257
+ explanation.should.have.property('changeAmount', '0');
258
+ explanation.should.have.property('fee', { fee: 1 });
259
+ }
260
+ });
261
+ });
262
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90ZXN0L3VuaXQvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSwyQ0FBNkI7QUFDN0IsK0NBQWlDO0FBRWpDLG1EQUErRDtBQUMvRCxpREFBK0M7QUFFL0MsMkNBQXVDO0FBQ3ZDLDBEQUF5RDtBQUV6RCxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztBQUV6QixNQUFNLEtBQUssR0FBaUIsb0JBQVMsQ0FBQyxRQUFRLENBQUMsa0JBQVEsRUFBRSxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUUsQ0FBQyxDQUFDO0FBQzFFLEtBQUssQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFLFlBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztBQUVoRCxRQUFRLENBQUMsY0FBYyxFQUFFO0lBQ3ZCLElBQUksUUFBUSxDQUFDO0lBRWIsTUFBTSxDQUFDO1FBQ0wsS0FBSyxDQUFDLGtCQUFrQixFQUFFLENBQUM7UUFDM0IsUUFBUSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDaEMsQ0FBQyxDQUFDLENBQUM7SUFFSCxLQUFLLENBQUM7UUFDSixJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDbEIsQ0FBQyxDQUFDLENBQUM7SUFFSCxFQUFFLENBQUMsNkJBQTZCLEVBQUU7UUFDaEMsTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNwQyxRQUFRLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLFlBQUksQ0FBQyxDQUFDO0lBQ3pDLENBQUMsQ0FBQyxDQUFDO0lBRUgsUUFBUSxDQUFDLHNCQUFzQixFQUFFO1FBQy9CLFVBQVUsQ0FBQyxHQUFHLEVBQUU7WUFDZCxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDbEIsQ0FBQyxDQUFDLENBQUM7UUFDSCxJQUFJLGNBQWMsQ0FBQztRQUNuQixNQUFNLENBQUMsR0FBRyxFQUFFO1lBQ1YsY0FBYyxHQUFHO2dCQUNmLE9BQU8sRUFDTCwrRUFBK0U7b0JBQy9FLCtFQUErRTtvQkFDL0UsK0VBQStFO29CQUMvRSwyRUFBMkU7Z0JBQzdFLFNBQVMsRUFDUCwrRUFBK0U7b0JBQy9FLCtFQUErRTtvQkFDL0UsK0VBQStFO29CQUMvRSwyRUFBMkU7Z0JBQzdFLGdCQUFnQixFQUFFLG9CQUFTLENBQUMsRUFBRSxDQUFDLHNCQUFzQjtnQkFDckQscUJBQXFCLEVBQUUsNENBQTRDO2dCQUNuRSxtQkFBbUIsRUFBRSw0Q0FBNEM7Z0JBQ2pFLHVCQUF1QixFQUFFO29CQUN2QixLQUFLLEVBQUUsS0FBSztpQkFDYjthQUNGLENBQUM7UUFDSixDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyxrQ0FBa0MsRUFBRSxLQUFLO1lBQzFDLElBQUEsaUNBQWdCLEVBQUMsS0FBSyxDQUFDLENBQUM7WUFDeEIsTUFBTSxRQUFRO2lCQUNYLE9BQU8sQ0FBQztnQkFDUCxHQUFHLGNBQWM7Z0JBQ2pCLFFBQVEsRUFBRSxDQUFDLE1BQU07Z0JBQ2pCLFFBQVEsRUFBRSxXQUFXO2FBQ3RCLENBQUM7aUJBQ0QsTUFBTSxDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQUMsOENBQThDLENBQUMsQ0FBQztRQUM1RSxDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyxnQ0FBZ0MsRUFBRSxLQUFLO1lBQ3hDLE1BQU0sNkJBQTZCLEdBQVU7Z0JBQzNDO29CQUNFLE1BQU0sRUFBRTt3QkFDTixNQUFNLEVBQUUseUJBQXlCO3dCQUNqQyxNQUFNLEVBQUUsQ0FBQyw0Q0FBNEMsRUFBRSxRQUFRLENBQUM7cUJBQ2pFO29CQUNELFFBQVEsRUFBRTt3QkFDUixNQUFNLEVBQUUsS0FBSzt3QkFDYixFQUFFLEVBQUUsQ0FBQzt3QkFDTCxPQUFPLEVBQUUsS0FBSztxQkFDZjtpQkFDRjtnQkFDRDtvQkFDRSxNQUFNLEVBQUU7d0JBQ04sTUFBTSxFQUFFLGdCQUFnQjt3QkFDeEIsTUFBTSxFQUFFLENBQUMsNENBQTRDLEVBQUUsUUFBUSxDQUFDO3FCQUNqRTtvQkFDRCxRQUFRLEVBQUU7d0JBQ1IsS0FBSyxFQUFFOzRCQUNMLElBQUksRUFBRSxDQUFDLEtBQUs7NEJBQ1osT0FBTyxFQUNMLDBHQUEwRzt5QkFDN0c7d0JBQ0QsRUFBRSxFQUFFLENBQUM7d0JBQ0wsT0FBTyxFQUFFLEtBQUs7cUJBQ2Y7aUJBQ0Y7YUFDRixDQUFDO1lBQ0YsSUFBQSxpQ0FBZ0IsRUFBQyxLQUFLLEVBQUUsNkJBQTZCLENBQUMsQ0FBQztZQUN2RCxNQUFNLFFBQVE7aUJBQ1gsT0FBTyxDQUFDLGNBQWMsQ0FBQztpQkFDdkIsTUFBTSxDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQ3JCLHlJQUF5SSxDQUMxSSxDQUFDO1FBQ04sQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsNkRBQTZELEVBQUUsS0FBSztZQUNyRSxNQUFNLG1CQUFtQixHQUFVO2dCQUNqQztvQkFDRSxNQUFNLEVBQUU7d0JBQ04sTUFBTSxFQUFFLHlCQUF5Qjt3QkFDakMsTUFBTSxFQUFFLENBQUMsNENBQTRDLEVBQUUsUUFBUSxDQUFDO3FCQUNqRTtvQkFDRCxRQUFRLEVBQUU7d0JBQ1IsRUFBRSxFQUFFLENBQUM7d0JBQ0wsT0FBTyxFQUFFLEtBQUs7d0JBQ2QsTUFBTSxFQUFFLEtBQUs7cUJBQ2Q7aUJBQ0Y7Z0JBQ0Q7b0JBQ0UsTUFBTSxFQUFFO3dCQUNOLE1BQU0sRUFBRSxnQkFBZ0I7d0JBQ3hCLE1BQU0sRUFBRSxDQUFDLDRDQUE0QyxFQUFFLFFBQVEsQ0FBQztxQkFDakU7b0JBQ0QsUUFBUSxFQUFFO3dCQUNSLEVBQUUsRUFBRSxDQUFDO3dCQUNMLE9BQU8sRUFBRSxLQUFLO3dCQUNkLE1BQU0sRUFBRSxPQUFPO3FCQUNoQjtpQkFDRjthQUNGLENBQUM7WUFDRixJQUFBLGlDQUFnQixFQUFDLEtBQUssRUFBRSxtQkFBbUIsQ0FBQyxDQUFDO1lBQzdDLE1BQU0sUUFBUTtpQkFDWCxPQUFPLENBQUM7Z0JBQ1AsR0FBRyxjQUFjO2dCQUNqQixRQUFRLEVBQUUsTUFBTTtnQkFDaEIsUUFBUSxFQUFFLFVBQVU7YUFDckIsQ0FBQztpQkFDRCxNQUFNLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FDckIsNkZBQTZGO2dCQUMzRixrSUFBa0ksQ0FDckksQ0FBQztRQUNOLENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLGtDQUFrQyxFQUFFLEtBQUs7WUFDMUMsSUFBQSxpQ0FBZ0IsRUFBQyxLQUFLLENBQUMsQ0FBQztZQUN4QixNQUFNLFFBQVE7aUJBQ1gsT0FBTyxDQUFDO2dCQUNQLEdBQUcsY0FBYztnQkFDakIsUUFBUSxFQUFFLE1BQU07Z0JBQ2hCLFFBQVEsRUFBRSxPQUFPO2FBQ2xCLENBQUM7aUJBQ0QsTUFBTSxDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQUMsd0RBQXdELENBQUMsQ0FBQztRQUN0RixDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyxvRUFBb0UsRUFBRSxLQUFLO1lBQzVFLElBQUEsaUNBQWdCLEVBQUMsS0FBSyxDQUFDLENBQUM7WUFDeEIsTUFBTSxRQUFRLEdBQUcsTUFBTSxRQUFRLENBQUMsT0FBTyxDQUFDO2dCQUN0QyxHQUFHLGNBQWM7Z0JBQ2pCLFFBQVEsRUFBRSxNQUFNO2dCQUNoQixRQUFRLEVBQUUsVUFBVTthQUNyQixDQUFDLENBQUM7WUFDSCwyREFBMkQ7WUFDM0QsTUFBTSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUN2QixRQUFRLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDcEMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3BDLE1BQU0sMEJBQTBCLENBQUMsUUFBUSxDQUFDLEVBQUUsRUFBRSxtQkFBbUIsRUFBRSxjQUFjLENBQUMsbUJBQW1CLENBQUMsQ0FBQztRQUN6RyxDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyx1REFBdUQsRUFBRSxLQUFLO1lBQy9ELElBQUEsaUNBQWdCLEVBQUMsS0FBSyxDQUFDLENBQUM7WUFDeEIsTUFBTSxRQUFRLEdBQUcsTUFBTSxRQUFRLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxDQUFDO1lBQ3hELDJEQUEyRDtZQUMzRCxNQUFNLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ3ZCLFFBQVEsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUNwQyxRQUFRLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDcEMsTUFBTSwwQkFBMEIsQ0FBQyxRQUFRLENBQUMsRUFBRSxFQUFFLG1CQUFtQixFQUFFLGNBQWMsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1FBQ3pHLENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLG9FQUFvRSxFQUFFLEtBQUs7WUFDNUUsSUFBQSxpQ0FBZ0IsRUFBQyxLQUFLLENBQUMsQ0FBQztZQUN4QixNQUFNLFFBQVEsR0FBRyxNQUFNLFFBQVEsQ0FBQyxPQUFPLENBQUM7Z0JBQ3RDLEdBQUcsY0FBYztnQkFDakIsU0FBUyxFQUNQLGlIQUFpSDtnQkFDbkgsV0FBVyxFQUFFLFdBQVc7YUFDekIsQ0FBQyxDQUFDO1lBRUgsMkRBQTJEO1lBQzNELE1BQU0sQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDdkIsUUFBUSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3BDLFFBQVEsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUNwQyxNQUFNLDBCQUEwQixDQUFDLFFBQVEsQ0FBQyxFQUFFLEVBQUUsbUJBQW1CLEVBQUUsY0FBYyxDQUFDLG1CQUFtQixDQUFDLENBQUM7UUFDekcsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsK0RBQStELEVBQUUsS0FBSztZQUN2RSxJQUFBLGlDQUFnQixFQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ3hCLE1BQU0sUUFBUTtpQkFDWCxPQUFPLENBQUM7Z0JBQ1AsT0FBTyxFQUNMLCtFQUErRTtvQkFDL0UsK0VBQStFO29CQUMvRSwrRUFBK0U7b0JBQy9FLDZFQUE2RTtnQkFDL0UsU0FBUyxFQUNQLCtFQUErRTtvQkFDL0UsK0VBQStFO29CQUMvRSwrRUFBK0U7b0JBQy9FLDJFQUEyRTtnQkFDN0UscUJBQXFCLEVBQUUsNENBQTRDO2dCQUNuRSxnQkFBZ0IsRUFBRSxvQkFBUyxDQUFDLEVBQUUsQ0FBQyxzQkFBc0I7Z0JBQ3JELG1CQUFtQixFQUFFLDRDQUE0QzthQUNsRSxDQUFDO2lCQUNELE1BQU0sQ0FBQyxFQUFFLENBQUMsWUFBWSxDQUNyQixxTkFBcU4sQ0FDdE4sQ0FBQztRQUNOLENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLHVDQUF1QyxFQUFFLEtBQUs7WUFDL0MsSUFBQSxpQ0FBZ0IsRUFBQyxLQUFLLENBQUMsQ0FBQztZQUV4QixNQUFNLFdBQVcsR0FBRyxNQUFNLFFBQVEsQ0FBQyxPQUFPLENBQUM7Z0JBQ3pDLE9BQU8sRUFDTCxpSEFBaUg7Z0JBQ25ILFNBQVMsRUFDUCxpSEFBaUg7Z0JBQ25ILHFCQUFxQixFQUFFLG9CQUFTLENBQUMsRUFBRSxDQUFDLDZCQUE2QjtnQkFDakUsbUJBQW1CLEVBQUUsb0JBQVMsQ0FBQyxFQUFFLENBQUMsMEJBQTBCO2dCQUM1RCxRQUFRLEVBQUUsYUFBYTtnQkFDdkIsUUFBUSxFQUFFLFFBQVE7YUFDbkIsQ0FBQyxDQUFDO1lBQ0gsTUFBTSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUMxQixXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDdkMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLG9CQUFvQixDQUFDLENBQUM7WUFDdkQsV0FBVyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQy9DLFdBQVcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUM3QyxXQUFXLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDNUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQzdDLFdBQVcsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUMsQ0FBQztZQUNqRCxXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsdUJBQXVCLENBQUMsQ0FBQztZQUMxRCxXQUFXLENBQUMscUJBQXFCLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxvQkFBUyxDQUFDLEVBQUUsQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDO1lBQzNGLFdBQVcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUM5QyxXQUFXLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQ3RELFdBQVcsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsb0JBQVMsQ0FBQyxFQUFFLENBQUMsMEJBQTBCLENBQUMsQ0FBQztZQUNwRixXQUFXLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ3JELFdBQVcsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMscUJBQXFCLENBQUMsQ0FBQztZQUNqRSwwQkFBMEIsQ0FBQyxXQUFXLENBQUMsRUFBRSxFQUFFLG1CQUFtQixFQUFFLG9CQUFTLENBQUMsRUFBRSxDQUFDLDBCQUEwQixDQUFDLENBQUM7UUFDM0csQ0FBQyxDQUFDLENBQUM7UUFFSCxLQUFLLFVBQVUsMEJBQTBCLENBQUMsRUFBRSxFQUFFLGNBQWMsRUFBRSxtQkFBbUI7WUFDL0UsTUFBTSxXQUFXLEdBQUcsTUFBTSxRQUFRLENBQUMsa0JBQWtCLENBQUMsRUFBRSxLQUFLLEVBQUUsSUFBSSxHQUFHLEVBQUUsRUFBRSxPQUFPLEVBQUUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ2pHLFdBQVcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUM1QyxXQUFXLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUM7Z0JBQ3BDLE1BQU0sRUFBRSxjQUFjLENBQUMsT0FBTyxFQUFFO2dCQUNoQyxPQUFPLEVBQUUsbUJBQW1CO2FBQzdCLENBQUMsQ0FBQztZQUNILFdBQVcsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxlQUFlLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDdEQsV0FBVyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLGNBQWMsRUFBRSxHQUFHLENBQUMsQ0FBQztZQUN0RCxXQUFXLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsS0FBSyxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDdEQsQ0FBQztJQUNILENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBub2NrIGZyb20gJ25vY2snO1xuaW1wb3J0ICogYXMgc2hvdWxkIGZyb20gJ3Nob3VsZCc7XG5cbmltcG9ydCB7IFRlc3RCaXRHbywgVGVzdEJpdEdvQVBJIH0gZnJvbSAnQGJpdGdvLWJldGEvc2RrLXRlc3QnO1xuaW1wb3J0IHsgQml0R29BUEkgfSBmcm9tICdAYml0Z28tYmV0YS9zZGstYXBpJztcblxuaW1wb3J0IHsgRXRodyB9IGZyb20gJy4uLy4uL3NyYy9pbmRleCc7XG5pbXBvcnQgeyBub2NrRXRod1JlY292ZXJ5IH0gZnJvbSAnLi4vbGliL3JlY292ZXJ5LW5vY2tzJztcblxubm9jay5kaXNhYmxlTmV0Q29ubmVjdCgpO1xuXG5jb25zdCBiaXRnbzogVGVzdEJpdEdvQVBJID0gVGVzdEJpdEdvLmRlY29yYXRlKEJpdEdvQVBJLCB7IGVudjogJ3Rlc3QnIH0pO1xuYml0Z28uc2FmZVJlZ2lzdGVyKCdldGh3JywgRXRody5jcmVhdGVJbnN0YW5jZSk7XG5cbmRlc2NyaWJlKCdFdGhlcmV1bSBwb3cnLCBmdW5jdGlvbiAoKSB7XG4gIGxldCBiYXNlY29pbjtcblxuICBiZWZvcmUoZnVuY3Rpb24gKCkge1xuICAgIGJpdGdvLmluaXRpYWxpemVUZXN0VmFycygpO1xuICAgIGJhc2Vjb2luID0gYml0Z28uY29pbignZXRodycpO1xuICB9KTtcblxuICBhZnRlcihmdW5jdGlvbiAoKSB7XG4gICAgbm9jay5jbGVhbkFsbCgpO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIGluc3RhbnRpYXRlIHRoZSBjb2luJywgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IGJhc2Vjb2luID0gYml0Z28uY29pbignZXRodycpO1xuICAgIGJhc2Vjb2luLnNob3VsZC5iZS5hbi5pbnN0YW5jZW9mKEV0aHcpO1xuICB9KTtcblxuICBkZXNjcmliZSgnUmVjb3ZlciBFdGhlcmV1bSBQb1cnLCBmdW5jdGlvbiAoKSB7XG4gICAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgICBub2NrLmNsZWFuQWxsKCk7XG4gICAgfSk7XG4gICAgbGV0IHJlY292ZXJ5UGFyYW1zO1xuICAgIGJlZm9yZSgoKSA9PiB7XG4gICAgICByZWNvdmVyeVBhcmFtcyA9IHtcbiAgICAgICAgdXNlcktleTpcbiAgICAgICAgICAne1wiaXZcIjpcIitUa21UM0dKNW1zVldRakJydDNsc3c9PVwiLFwidlwiOjEsXCJpdGVyXCI6MTAwMDAsXCJrc1wiOjI1NixcInRzXCI6NjQsXCJtb2RlXCJcXG4nICtcbiAgICAgICAgICAnOlwiY2NtXCIsXCJhZGF0YVwiOlwiXCIsXCJjaXBoZXJcIjpcImFlc1wiLFwic2FsdFwiOlwiY0NFMjBmR0lvYnM9XCIsXCJjdFwiOlwiTlZJZFlJaDkxSjNhUklcXG4nICtcbiAgICAgICAgICAnOEdHMEpFM0RoWFczQVVtejJHNVJxTWVqZHoxK3Q0L3ZvdklQN2xsZWVnSTdWWXlXaWlMdmxNME9DRmYzRVZ2Vi9SeVhyOCsydnNuXFxuJyArXG4gICAgICAgICAgJ1EwVm44YzJDVjVGUlo4ME9qR1lyVzNBLzZUL3pwT3o2RThDTXZuRCsraUlwZU80cjJlWkphdmVqWnhkemx4RjBCUno3Vkk9XCJ9JyxcbiAgICAgICAgYmFja3VwS2V5OlxuICAgICAgICAgICd7XCJpdlwiOlwiYXNCMzU2b2ZDN25adGc0TkJ2UWtpUT09XCIsXCJ2XCI6MSxcIml0ZXJcIjoxMDAwMCxcImtzXCI6MjU2LFwidHNcIjo2NCxcIm1vZGVcIlxcbicgK1xuICAgICAgICAgICc6XCJjY21cIixcImFkYXRhXCI6XCJcIixcImNpcGhlclwiOlwiYWVzXCIsXCJzYWx0XCI6XCIxaHIySGhCYkJJaz1cIixcImN0XCI6XCI4Q1pjNnVwdCtYTk90b1xcbicgK1xuICAgICAgICAgICdLREQzOFRVZzNaVWp6VytEcmFabGtja3UyYk5wMEpTMnMxZy9pQzZZVEdVR3RQb3hEeHVtRGxYd2xXUXgrNVdQalp1NzlNOERDcklcXG4nICtcbiAgICAgICAgICAndDlhWmFPdkhrR0g5YUZ0TWJhdkZYNDE5VGNyd0RtcFVlUUZOMGhSa2ZySUhYeUhOYlRwR1NWQWpIdkhNdHpETWF3K0FDZz1cIn0nLFxuICAgICAgICB3YWxsZXRQYXNzcGhyYXNlOiBUZXN0Qml0R28uVjIuVEVTVF9SRUNPVkVSWV9QQVNTQ09ERSxcbiAgICAgICAgd2FsbGV0Q29udHJhY3RBZGRyZXNzOiAnMHg1ZGY1YTk2YjQ3OGJiMTgwODE0MGQ4NzA3MjE0M2U2MDI2MmU4NjcwJyxcbiAgICAgICAgcmVjb3ZlcnlEZXN0aW5hdGlvbjogJzB4YWMwNWRhNzg0NjQ1MjBhYTdjOWQ0YzE5YmQ3YTQ0MGIxMTFiMzA1NCcsXG4gICAgICAgIHJlcGxheVByb3RlY3Rpb25PcHRpb25zOiB7XG4gICAgICAgICAgY2hhaW46IDEwMDAxLFxuICAgICAgICB9LFxuICAgICAgfTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgb24gaW52YWxpZCBnYXNMaW1pdCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIG5vY2tFdGh3UmVjb3ZlcnkoYml0Z28pO1xuICAgICAgYXdhaXQgYmFzZWNvaW5cbiAgICAgICAgLnJlY292ZXIoe1xuICAgICAgICAgIC4uLnJlY292ZXJ5UGFyYW1zLFxuICAgICAgICAgIGdhc0xpbWl0OiAtNDAwMDAwLFxuICAgICAgICAgIGdhc1ByaWNlOiAyNTAwMDAwMDAwMCxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ0dhcyBsaW1pdCBtdXN0IGJlIGJldHdlZW4gMzAwMDAgYW5kIDIwMDAwMDAwJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IGlmIGV0aGVyc2NhbiBlcnJzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3Qgbm9ja1Vuc3VjY2Vzc2Z1bEV0aGVyc2NhbkRhdGE6IGFueVtdID0gW1xuICAgICAgICB7XG4gICAgICAgICAgcGFyYW1zOiB7XG4gICAgICAgICAgICBtZXRob2Q6ICdldGhfZ2V0VHJhbnNhY3Rpb25Db3VudCcsXG4gICAgICAgICAgICBwYXJhbXM6IFsnMHg3NGMyMTM3ZDU0YjBmYzlmOTA3ZTEzZjE0ZTBkZDE4NDg1ZmVlOTI0JywgJ2xhdGVzdCddLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgcmVzcG9uc2U6IHtcbiAgICAgICAgICAgIHJlc3VsdDogJzB4MCcsXG4gICAgICAgICAgICBpZDogMCxcbiAgICAgICAgICAgIGpzb25ycGM6ICcyLjAnLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBwYXJhbXM6IHtcbiAgICAgICAgICAgIG1ldGhvZDogJ2V0aF9nZXRCYWxhbmNlJyxcbiAgICAgICAgICAgIHBhcmFtczogWycweDc0YzIxMzdkNTRiMGZjOWY5MDdlMTNmMTRlMGRkMTg0ODVmZWU5MjQnLCAnbGF0ZXN0J10sXG4gICAgICAgICAgfSxcbiAgICAgICAgICByZXNwb25zZToge1xuICAgICAgICAgICAgZXJyb3I6IHtcbiAgICAgICAgICAgICAgY29kZTogLTMyNjAyLFxuICAgICAgICAgICAgICBtZXNzYWdlOlxuICAgICAgICAgICAgICAgICdpbnZhbGlkIGFyZ3VtZW50IDA6IGpzb246IGNhbm5vdCB1bm1hcnNoYWwgaGV4IHN0cmluZyBvZiBvZGQgbGVuZ3RoIGludG8gR28gdmFsdWUgb2YgdHlwZSBjb21tb24uQWRkcmVzcycsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgaWQ6IDAsXG4gICAgICAgICAgICBqc29ucnBjOiAnMi4wJyxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgXTtcbiAgICAgIG5vY2tFdGh3UmVjb3ZlcnkoYml0Z28sIG5vY2tVbnN1Y2Nlc3NmdWxFdGhlcnNjYW5EYXRhKTtcbiAgICAgIGF3YWl0IGJhc2Vjb2luXG4gICAgICAgIC5yZWNvdmVyKHJlY292ZXJ5UGFyYW1zKVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aChcbiAgICAgICAgICAnRVRIVyBmdWxsIG5vZGUgZXJyb3I6IC0zMjYwMiAtIGludmFsaWQgYXJndW1lbnQgMDoganNvbjogY2Fubm90IHVubWFyc2hhbCBoZXggc3RyaW5nIG9mIG9kZCBsZW5ndGggaW50byBHbyB2YWx1ZSBvZiB0eXBlIGNvbW1vbi5BZGRyZXNzJ1xuICAgICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBpZiBiYWNrdXAga2V5IGFkZHJlc3MgaGFzIGluc3VmZmljaWVudCBiYWxhbmNlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgaW5zdWZmaWNpZW50RmVlRGF0YTogYW55W10gPSBbXG4gICAgICAgIHtcbiAgICAgICAgICBwYXJhbXM6IHtcbiAgICAgICAgICAgIG1ldGhvZDogJ2V0aF9nZXRUcmFuc2FjdGlvbkNvdW50JyxcbiAgICAgICAgICAgIHBhcmFtczogWycweDc0YzIxMzdkNTRiMGZjOWY5MDdlMTNmMTRlMGRkMTg0ODVmZWU5MjQnLCAnbGF0ZXN0J10sXG4gICAgICAgICAgfSxcbiAgICAgICAgICByZXNwb25zZToge1xuICAgICAgICAgICAgaWQ6IDAsXG4gICAgICAgICAgICBqc29ucnBjOiAnMi4wJyxcbiAgICAgICAgICAgIHJlc3VsdDogJzB4MCcsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIHBhcmFtczoge1xuICAgICAgICAgICAgbWV0aG9kOiAnZXRoX2dldEJhbGFuY2UnLFxuICAgICAgICAgICAgcGFyYW1zOiBbJzB4NzRjMjEzN2Q1NGIwZmM5ZjkwN2UxM2YxNGUwZGQxODQ4NWZlZTkyNCcsICdsYXRlc3QnXSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIHJlc3BvbnNlOiB7XG4gICAgICAgICAgICBpZDogMCxcbiAgICAgICAgICAgIGpzb25ycGM6ICcyLjAnLFxuICAgICAgICAgICAgcmVzdWx0OiAnMHg0ZDInLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICBdO1xuICAgICAgbm9ja0V0aHdSZWNvdmVyeShiaXRnbywgaW5zdWZmaWNpZW50RmVlRGF0YSk7XG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAucmVjb3Zlcih7XG4gICAgICAgICAgLi4ucmVjb3ZlcnlQYXJhbXMsXG4gICAgICAgICAgZ2FzTGltaXQ6IDMwMDAwMCxcbiAgICAgICAgICBnYXNQcmljZTogMTAwMDAwMDAwMCxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoXG4gICAgICAgICAgJ0JhY2t1cCBrZXkgYWRkcmVzcyAweDc0YzIxMzdkNTRiMGZjOWY5MDdlMTNmMTRlMGRkMTg0ODVmZWU5MjQgaGFzIGJhbGFuY2UgMC4wMDAwMDEyMzQgR3dlaS4nICtcbiAgICAgICAgICAgICdUaGlzIGFkZHJlc3MgbXVzdCBoYXZlIGEgYmFsYW5jZSBvZiBhdCBsZWFzdCAzMDAwMDAgR3dlaSB0byBwZXJmb3JtIHJlY292ZXJpZXMuIFRyeSBzZW5kaW5nIHNvbWUgRVRIIHRvIHRoaXMgYWRkcmVzcyB0aGVuIHJldHJ5LidcbiAgICAgICAgKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgb24gaW52YWxpZCBnYXNQcmljZScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIG5vY2tFdGh3UmVjb3ZlcnkoYml0Z28pO1xuICAgICAgYXdhaXQgYmFzZWNvaW5cbiAgICAgICAgLnJlY292ZXIoe1xuICAgICAgICAgIC4uLnJlY292ZXJ5UGFyYW1zLFxuICAgICAgICAgIGdhc0xpbWl0OiA0MDAwMDAsXG4gICAgICAgICAgZ2FzUHJpY2U6IDI1MDAwMDAsXG4gICAgICAgIH0pXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKCdHYXMgcHJpY2UgbXVzdCBiZSBiZXR3ZWVuIDEwMDAwMDAwMDAgYW5kIDI1MDAwMDAwMDAwMDAnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgc3VjY2Vzc2Z1bGx5IGNvbnN0cnVjdCBhIHR4IHdpdGggY3VzdG9tIGdhcyBwcmljZSBhbmQgbGltaXQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBub2NrRXRod1JlY292ZXJ5KGJpdGdvKTtcbiAgICAgIGNvbnN0IHJlY292ZXJ5ID0gYXdhaXQgYmFzZWNvaW4ucmVjb3Zlcih7XG4gICAgICAgIC4uLnJlY292ZXJ5UGFyYW1zLFxuICAgICAgICBnYXNMaW1pdDogNDAwMDAwLFxuICAgICAgICBnYXNQcmljZTogMTAwMDAwMDAwMCxcbiAgICAgIH0pO1xuICAgICAgLy8gaWQgYW5kIHR4IHdpbGwgYWx3YXlzIGJlIGRpZmZlcmVudCBiZWNhdXNlIG9mIGV4cGlyZVRpbWVcbiAgICAgIHNob3VsZC5leGlzdChyZWNvdmVyeSk7XG4gICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnaWQnKTtcbiAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCd0eCcpO1xuICAgICAgYXdhaXQgY2hlY2tSZWNvdmVyeVR4RXhwbGFuYXRpb24ocmVjb3ZlcnkudHgsIDIyMDAwMDAwMDAwMDAwMDAwMDAsIHJlY292ZXJ5UGFyYW1zLnJlY292ZXJ5RGVzdGluYXRpb24pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBjb25zdHJ1Y3QgYSByZWNvdmVyeSB0cmFuc2FjdGlvbiB3aXRob3V0IEJpdEdvJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbm9ja0V0aHdSZWNvdmVyeShiaXRnbyk7XG4gICAgICBjb25zdCByZWNvdmVyeSA9IGF3YWl0IGJhc2Vjb2luLnJlY292ZXIocmVjb3ZlcnlQYXJhbXMpO1xuICAgICAgLy8gaWQgYW5kIHR4IHdpbGwgYWx3YXlzIGJlIGRpZmZlcmVudCBiZWNhdXNlIG9mIGV4cGlyZVRpbWVcbiAgICAgIHNob3VsZC5leGlzdChyZWNvdmVyeSk7XG4gICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnaWQnKTtcbiAgICAgIHJlY292ZXJ5LnNob3VsZC5oYXZlLnByb3BlcnR5KCd0eCcpO1xuICAgICAgYXdhaXQgY2hlY2tSZWNvdmVyeVR4RXhwbGFuYXRpb24ocmVjb3ZlcnkudHgsIDIyMDAwMDAwMDAwMDAwMDAwMDAsIHJlY292ZXJ5UGFyYW1zLnJlY292ZXJ5RGVzdGluYXRpb24pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBjb25zdHJ1Y3QgYSByZWNvdmVyeSB0cmFuc2FjdGlvbiB3aXRob3V0IEJpdEdvIGFuZCB3aXRoIEtSUycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIG5vY2tFdGh3UmVjb3ZlcnkoYml0Z28pO1xuICAgICAgY29uc3QgcmVjb3ZlcnkgPSBhd2FpdCBiYXNlY29pbi5yZWNvdmVyKHtcbiAgICAgICAgLi4ucmVjb3ZlcnlQYXJhbXMsXG4gICAgICAgIGJhY2t1cEtleTpcbiAgICAgICAgICAneHB1YjY2MU15TXdBcVJiY0dzQ05pRzRCemJ4TG1YbkpGbzRLNWdWU0UyYjlBeHVmQXRwdVR1bjFTWXdnOVV5a3FxZjREcktyRFo2S3FQbTllaHRoV2JDbWE3cG5hTXJ0WFkxMW5ZN01lRmJFRFBtJyxcbiAgICAgICAga3JzUHJvdmlkZXI6ICdrZXl0ZXJuYWwnLFxuICAgICAgfSk7XG5cbiAgICAgIC8vIGlkIGFuZCB0eCB3aWxsIGFsd2F5cyBiZSBkaWZmZXJlbnQgYmVjYXVzZSBvZiBleHBpcmVUaW1lXG4gICAgICBzaG91bGQuZXhpc3QocmVjb3ZlcnkpO1xuICAgICAgcmVjb3Zlcnkuc2hvdWxkLmhhdmUucHJvcGVydHkoJ2lkJyk7XG4gICAgICByZWNvdmVyeS5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgndHgnKTtcbiAgICAgIGF3YWl0IGNoZWNrUmVjb3ZlcnlUeEV4cGxhbmF0aW9uKHJlY292ZXJ5LnR4LCAyMjAwMDAwMDAwMDAwMDAwMDAwLCByZWNvdmVyeVBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZXJyb3Igd2hlbiB0aGUgYmFja3VwIGtleSBpcyB1bmZ1bmRlZCAoY2Fubm90IHBheSBnYXMpJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbm9ja0V0aHdSZWNvdmVyeShiaXRnbyk7XG4gICAgICBhd2FpdCBiYXNlY29pblxuICAgICAgICAucmVjb3Zlcih7XG4gICAgICAgICAgdXNlcktleTpcbiAgICAgICAgICAgICd7XCJpdlwiOlwiVk52RzZ0M2ZIZnhNY2Z2TnVhZllZQT09XCIsXCJ2XCI6MSxcIml0ZXJcIjoxMDAwMCxcImtzXCI6MjU2LFwidHNcIjo2NCxcIm1vZGVcIlxcbicgK1xuICAgICAgICAgICAgJzpcImNjbVwiLFwiYWRhdGFcIjpcIlwiLFwiY2lwaGVyXCI6XCJhZXNcIixcInNhbHRcIjpcIm1jOXBDazNINDN3PVwiLFwiY3RcIjpcIlFlNFoxZXZhWGNyT01DXFxuJyArXG4gICAgICAgICAgICAnY1EvWE1WVkJPOU0vOTlEMVFRNkx4a0c4ejNmUXR3d09WWE0zLzZkb05ycmlwclVxcythZHBGQzkzS1JjQWFEcm9MMUU2bzE3SjJrXFxuJyArXG4gICAgICAgICAgICAnbWNwWFJkMkN1WFJGT1JabVovNlFCZmpLZkNKM2FxMGtFa0RWdjM3Z1pOVlQzYU50R2tOU1FkQ0VXS1FMd2QxKytyNUFrQT1cIn1cXG4nLFxuICAgICAgICAgIGJhY2t1cEtleTpcbiAgICAgICAgICAgICd7XCJpdlwiOlwiRWpEN3gwT0pYOWtOTS9DM3lFRHZ5UT09XCIsXCJ2XCI6MSxcIml0ZXJcIjoxMDAwMCxcImtzXCI6MjU2LFwidHNcIjo2NCxcIm1vZGVcIlxcbicgK1xuICAgICAgICAgICAgJzpcImNjbVwiLFwiYWRhdGFcIjpcIlwiLFwiY2lwaGVyXCI6XCJhZXNcIixcInNhbHRcIjpcIk5hOU52UlJlM244PVwiLFwiY3RcIjpcIkIvQXRTTEhvbHNkTkxyXFxuJyArXG4gICAgICAgICAgICAnNERsaWo0a1EwRTZOeVVVczZ3bzZUMkh0UERBUE8waHloUFBiaDFPQVlxSVM3VmxMOXhtSlJGQzJ6UHh3Ukp2emY2T1dDL200OEhYXFxuJyArXG4gICAgICAgICAgICAndmdMb1hZZ2FoQXJoYWx6SlZsUnhjWFV6NEhPaG96Uldmdi9lSzN0NUhKZm0rMjUrV0JPaVc4WWdTRTdoVkVZVGJlQlJEND1cIn0nLFxuICAgICAgICAgIHdhbGxldENvbnRyYWN0QWRkcmVzczogJzB4MjJmZjc0MzIxNmI1OGFlYjNlZmM0Njk4NTQwNmI1MDExMmU5ZTE3NicsXG4gICAgICAgICAgd2FsbGV0UGFzc3BocmFzZTogVGVzdEJpdEdvLlYyLlRFU1RfUkVDT1ZFUllfUEFTU0NPREUsXG4gICAgICAgICAgcmVjb3ZlcnlEZXN0aW5hdGlvbjogJzB4YWMwNWRhNzg0NjQ1MjBhYTdjOWQ0YzE5YmQ3YTQ0MGIxMTFiMzA1NCcsXG4gICAgICAgIH0pXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKFxuICAgICAgICAgICdCYWNrdXAga2V5IGFkZHJlc3MgMHhiYTZkOWQ4MmNmMjkyMGM1NDRiODM0YjcyZjRjNmQxMWEzZWYzZGU2IGhhcyBiYWxhbmNlIDAgR3dlaS5UaGlzIGFkZHJlc3MgbXVzdCBoYXZlIGEgYmFsYW5jZSBvZiBhdCBsZWFzdCAxMDAwMDAwMCBHd2VpIHRvIHBlcmZvcm0gcmVjb3Zlcmllcy4gVHJ5IHNlbmRpbmcgc29tZSBFVEggdG8gdGhpcyBhZGRyZXNzIHRoZW4gcmV0cnkuJ1xuICAgICAgICApO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBnZW5lcmF0ZSBhbiBFVEggdW5zaWduZWQgc3dlZXAnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBub2NrRXRod1JlY292ZXJ5KGJpdGdvKTtcblxuICAgICAgY29uc3QgdHJhbnNhY3Rpb24gPSBhd2FpdCBiYXNlY29pbi5yZWNvdmVyKHtcbiAgICAgICAgdXNlcktleTpcbiAgICAgICAgICAneHB1YjY2MU15TXdBcVJiY0ZYRGNXRDJ2eHVlYmNUMVpwVEY0VmtlNnFtTVc4eXpkZHdOWXBBUGp2WUVFTDVqTGZ5WVhXMmZ1eHRBeFk4VGdqUFVKTGNmMUM4cXo5TjZWZ1p4QXJLWDRFd0I4ckg1JyxcbiAgICAgICAgYmFja3VwS2V5OlxuICAgICAgICAgICd4cHViNjYxTXlNd0FxUmJjR2hTYVhpa3B1VEM5S1U4OFh4OUxyaktTdzFKS3N2WE5nYWJwVGRnank3TFNvdmg5WkhoY3FoQUhRdTd1dGh1N0ZndU5HZGNDNGFYVEtLNWdxVGNQZTRXdkxZUmJDU0cnLFxuICAgICAgICB3YWxsZXRDb250cmFjdEFkZHJlc3M6IFRlc3RCaXRHby5WMi5URVNUX0VUSF9XQUxMRVRfRklSU1RfQUREUkVTUyxcbiAgICAgICAgcmVjb3ZlcnlEZXN0aW5hdGlvbjogVGVzdEJpdEdvLlYyLlRFU1RfRVJDMjBfVE9LRU5fUkVDSVBJRU5ULFxuICAgICAgICBnYXNQcmljZTogJzIwMDAwMDAwMDAwJyxcbiAgICAgICAgZ2FzTGltaXQ6ICc1MDAwMDAnLFxuICAgICAgfSk7XG4gICAgICBzaG91bGQuZXhpc3QodHJhbnNhY3Rpb24pO1xuICAgICAgdHJhbnNhY3Rpb24uc2hvdWxkLmhhdmUucHJvcGVydHkoJ3R4Jyk7XG4gICAgICB0cmFuc2FjdGlvbi5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnY29udHJhY3RTZXF1ZW5jZUlkJyk7XG4gICAgICB0cmFuc2FjdGlvbi5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnZXhwaXJlVGltZScpO1xuICAgICAgdHJhbnNhY3Rpb24uc2hvdWxkLmhhdmUucHJvcGVydHkoJ2dhc0xpbWl0Jyk7XG4gICAgICB0cmFuc2FjdGlvbi5nYXNMaW1pdC5zaG91bGQuZXF1YWwoJzUwMDAwMCcpO1xuICAgICAgdHJhbnNhY3Rpb24uc2hvdWxkLmhhdmUucHJvcGVydHkoJ2dhc1ByaWNlJyk7XG4gICAgICB0cmFuc2FjdGlvbi5nYXNQcmljZS5zaG91bGQuZXF1YWwoJzIwMDAwMDAwMDAwJyk7XG4gICAgICB0cmFuc2FjdGlvbi5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnd2FsbGV0Q29udHJhY3RBZGRyZXNzJyk7XG4gICAgICB0cmFuc2FjdGlvbi53YWxsZXRDb250cmFjdEFkZHJlc3Muc2hvdWxkLmVxdWFsKFRlc3RCaXRHby5WMi5URVNUX0VUSF9XQUxMRVRfRklSU1RfQUREUkVTUyk7XG4gICAgICB0cmFuc2FjdGlvbi5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgncmVjaXBpZW50Jyk7XG4gICAgICB0cmFuc2FjdGlvbi5yZWNpcGllbnQuc2hvdWxkLmhhdmUucHJvcGVydHkoJ2FkZHJlc3MnKTtcbiAgICAgIHRyYW5zYWN0aW9uLnJlY2lwaWVudC5hZGRyZXNzLnNob3VsZC5lcXVhbChUZXN0Qml0R28uVjIuVEVTVF9FUkMyMF9UT0tFTl9SRUNJUElFTlQpO1xuICAgICAgdHJhbnNhY3Rpb24ucmVjaXBpZW50LnNob3VsZC5oYXZlLnByb3BlcnR5KCdhbW91bnQnKTtcbiAgICAgIHRyYW5zYWN0aW9uLnJlY2lwaWVudC5hbW91bnQuc2hvdWxkLmVxdWFsKCc5OTk5OTk5OTk5OTk5OTk5OTI4Jyk7XG4gICAgICBjaGVja1JlY292ZXJ5VHhFeHBsYW5hdGlvbih0cmFuc2FjdGlvbi50eCwgOTk5OTk5OTk5OTk5OTk5OTkyOCwgVGVzdEJpdEdvLlYyLlRFU1RfRVJDMjBfVE9LRU5fUkVDSVBJRU5UKTtcbiAgICB9KTtcblxuICAgIGFzeW5jIGZ1bmN0aW9uIGNoZWNrUmVjb3ZlcnlUeEV4cGxhbmF0aW9uKHR4LCByZWNvdmVyeUFtb3VudCwgcmVjb3ZlcnlEZXN0aW5hdGlvbikge1xuICAgICAgY29uc3QgZXhwbGFuYXRpb24gPSBhd2FpdCBiYXNlY29pbi5leHBsYWluVHJhbnNhY3Rpb24oeyB0eEhleDogJzB4JyArIHR4LCBmZWVJbmZvOiB7IGZlZTogMSB9IH0pO1xuICAgICAgZXhwbGFuYXRpb24uc2hvdWxkLmhhdmUucHJvcGVydHkoJ291dHB1dHMnKTtcbiAgICAgIGV4cGxhbmF0aW9uLm91dHB1dHMuc2hvdWxkLmNvbnRhaW5FcWwoe1xuICAgICAgICBhbW91bnQ6IHJlY292ZXJ5QW1vdW50LnRvRml4ZWQoKSxcbiAgICAgICAgYWRkcmVzczogcmVjb3ZlcnlEZXN0aW5hdGlvbixcbiAgICAgIH0pO1xuICAgICAgZXhwbGFuYXRpb24uc2hvdWxkLmhhdmUucHJvcGVydHkoJ2NoYW5nZU91dHB1dHMnLCBbXSk7XG4gICAgICBleHBsYW5hdGlvbi5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnY2hhbmdlQW1vdW50JywgJzAnKTtcbiAgICAgIGV4cGxhbmF0aW9uLnNob3VsZC5oYXZlLnByb3BlcnR5KCdmZWUnLCB7IGZlZTogMSB9KTtcbiAgICB9XG4gIH0pO1xufSk7XG4iXX0=