@bitgo/sdk-api 2.0.0-hotfix.0 → 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/dist/package.json +33 -28
- package/dist/src/api.d.ts +9 -8
- package/dist/src/api.d.ts.map +1 -1
- package/dist/src/api.js +132 -72
- package/dist/src/bitgoAPI.d.ts +366 -22
- package/dist/src/bitgoAPI.d.ts.map +1 -1
- package/dist/src/bitgoAPI.js +1286 -212
- package/dist/src/encrypt.d.ts +16 -6
- package/dist/src/encrypt.d.ts.map +1 -1
- package/dist/src/encrypt.js +92 -14
- package/dist/src/encryptV2.d.ts +68 -0
- package/dist/src/encryptV2.d.ts.map +1 -0
- package/dist/src/encryptV2.js +202 -0
- package/dist/src/encryptionSession.d.ts +34 -0
- package/dist/src/encryptionSession.d.ts.map +1 -0
- package/dist/src/encryptionSession.js +95 -0
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +8 -3
- package/dist/src/types.d.ts +195 -65
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +5 -15
- package/dist/src/util.d.ts +12 -8
- package/dist/src/util.d.ts.map +1 -1
- package/dist/src/util.js +54 -20
- package/dist/src/v1/blockchain.d.ts +5 -0
- package/dist/src/v1/blockchain.d.ts.map +1 -0
- package/dist/src/v1/blockchain.js +127 -0
- package/dist/src/v1/keychains.d.ts +5 -0
- package/dist/src/v1/keychains.d.ts.map +1 -0
- package/dist/src/v1/keychains.js +328 -0
- package/dist/src/v1/markets.d.ts +5 -0
- package/dist/src/v1/markets.d.ts.map +1 -0
- package/dist/src/v1/markets.js +68 -0
- package/dist/src/v1/pendingapproval.d.ts +6 -0
- package/dist/src/v1/pendingapproval.d.ts.map +1 -0
- package/dist/src/v1/pendingapproval.js +361 -0
- package/dist/src/v1/pendingapprovals.d.ts +6 -0
- package/dist/src/v1/pendingapprovals.d.ts.map +1 -0
- package/dist/src/v1/pendingapprovals.js +102 -0
- package/dist/src/v1/signPsbt.d.ts +14 -0
- package/dist/src/v1/signPsbt.d.ts.map +1 -0
- package/dist/src/v1/signPsbt.js +69 -0
- package/dist/src/v1/transactionBuilder.d.ts +5 -0
- package/dist/src/v1/transactionBuilder.d.ts.map +1 -0
- package/dist/src/v1/transactionBuilder.js +1034 -0
- package/dist/src/v1/travelRule.d.ts +5 -0
- package/dist/src/v1/travelRule.d.ts.map +1 -0
- package/dist/src/v1/travelRule.js +316 -0
- package/dist/src/v1/verifyAddress.d.ts +6 -0
- package/dist/src/v1/verifyAddress.d.ts.map +1 -0
- package/dist/src/v1/verifyAddress.js +50 -0
- package/dist/src/v1/wallet.d.ts +6 -0
- package/dist/src/v1/wallet.d.ts.map +1 -0
- package/dist/src/v1/wallet.js +2366 -0
- package/dist/src/v1/wallets.d.ts +5 -0
- package/dist/src/v1/wallets.d.ts.map +1 -0
- package/dist/src/v1/wallets.js +537 -0
- package/dist/test/unit/api.d.ts +2 -0
- package/dist/test/unit/api.d.ts.map +1 -0
- package/dist/test/unit/api.js +307 -0
- package/dist/test/unit/bitgoAPI.d.ts +2 -0
- package/dist/test/unit/bitgoAPI.d.ts.map +1 -0
- package/dist/test/unit/bitgoAPI.js +1001 -0
- package/dist/test/unit/encrypt.d.ts +2 -0
- package/dist/test/unit/encrypt.d.ts.map +1 -0
- package/dist/test/unit/encrypt.js +355 -0
- package/dist/test/unit/hmacStrategy.d.ts +2 -0
- package/dist/test/unit/hmacStrategy.d.ts.map +1 -0
- package/dist/test/unit/hmacStrategy.js +136 -0
- package/dist/test/unit/utils.d.ts +2 -0
- package/dist/test/unit/utils.d.ts.map +1 -0
- package/dist/test/unit/utils.js +65 -0
- package/dist/test/unit/v1/fixtures/accelerate-tx.d.ts +4 -0
- package/dist/test/unit/v1/fixtures/accelerate-tx.d.ts.map +1 -0
- package/dist/test/unit/v1/fixtures/accelerate-tx.js +53 -0
- package/dist/test/unit/v1/fixtures/index.d.ts +3 -0
- package/dist/test/unit/v1/fixtures/index.d.ts.map +1 -0
- package/dist/test/unit/v1/fixtures/index.js +24 -0
- package/dist/test/unit/v1/signPsbt.d.ts +2 -0
- package/dist/test/unit/v1/signPsbt.d.ts.map +1 -0
- package/dist/test/unit/v1/signPsbt.js +53 -0
- package/dist/test/unit/v1/travelRule.d.ts +2 -0
- package/dist/test/unit/v1/travelRule.d.ts.map +1 -0
- package/dist/test/unit/v1/travelRule.js +125 -0
- package/dist/test/unit/v1/wallet.d.ts +2 -0
- package/dist/test/unit/v1/wallet.d.ts.map +1 -0
- package/dist/test/unit/v1/wallet.js +1658 -0
- package/dist/tsconfig.tsbuildinfo +1 -5259
- package/package.json +33 -28
- package/.eslintignore +0 -5
- package/CHANGELOG.md +0 -67
- package/dist/src/bip32path.d.ts +0 -24
- package/dist/src/bip32path.d.ts.map +0 -1
- package/dist/src/bip32path.js +0 -45
- package/dist/web/browser.html +0 -1
- package/dist/web/main.js +0 -2
- package/dist/web/main.js.LICENSE.txt +0 -30
|
@@ -0,0 +1,1001 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
const assert = __importStar(require("assert"));
|
|
40
|
+
require("should");
|
|
41
|
+
const bitgoAPI_1 = require("../../src/bitgoAPI");
|
|
42
|
+
const proxy_agent_1 = require("proxy-agent");
|
|
43
|
+
const sinon = __importStar(require("sinon"));
|
|
44
|
+
const nock_1 = __importDefault(require("nock"));
|
|
45
|
+
describe('Constructor', function () {
|
|
46
|
+
describe('cookiesPropagationEnabled argument', function () {
|
|
47
|
+
it('cookiesPropagationEnabled is enabled explicitly', function () {
|
|
48
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
49
|
+
env: 'custom',
|
|
50
|
+
customRootURI: 'https://app.example.local',
|
|
51
|
+
cookiesPropagationEnabled: true,
|
|
52
|
+
});
|
|
53
|
+
bitgo.should.have.property('cookiesPropagationEnabled');
|
|
54
|
+
bitgo.cookiesPropagationEnabled.should.equal(true);
|
|
55
|
+
});
|
|
56
|
+
it('cookiesPropagationEnabled is disabled explicitly', function () {
|
|
57
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
58
|
+
env: 'custom',
|
|
59
|
+
customRootURI: 'https://app.example.local',
|
|
60
|
+
cookiesPropagationEnabled: false,
|
|
61
|
+
});
|
|
62
|
+
bitgo.should.have.property('cookiesPropagationEnabled');
|
|
63
|
+
bitgo.cookiesPropagationEnabled.should.equal(false);
|
|
64
|
+
});
|
|
65
|
+
it('cookiesPropagationEnabled is disabled by default', function () {
|
|
66
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
67
|
+
env: 'custom',
|
|
68
|
+
customRootURI: 'https://app.example.local',
|
|
69
|
+
});
|
|
70
|
+
bitgo.should.have.property('cookiesPropagationEnabled');
|
|
71
|
+
bitgo.cookiesPropagationEnabled.should.equal(false);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
describe('requestIdPrefix argument', function () {
|
|
75
|
+
afterEach(function () {
|
|
76
|
+
nock_1.default.cleanAll();
|
|
77
|
+
});
|
|
78
|
+
it('should prepend requestIdPrefix to Request-ID header when set', async function () {
|
|
79
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
80
|
+
env: 'custom',
|
|
81
|
+
customRootURI: 'https://app.example.local',
|
|
82
|
+
requestIdPrefix: 'test-prefix-',
|
|
83
|
+
});
|
|
84
|
+
const scope = (0, nock_1.default)('https://app.example.local')
|
|
85
|
+
.get('/api/v1/ping')
|
|
86
|
+
.matchHeader('Request-ID', /^test-prefix-/)
|
|
87
|
+
.reply(200, { status: 'ok' });
|
|
88
|
+
await bitgo.ping({
|
|
89
|
+
reqId: {
|
|
90
|
+
toString: () => '12345',
|
|
91
|
+
inc: () => {
|
|
92
|
+
/* mock */
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
scope.isDone().should.be.true();
|
|
97
|
+
});
|
|
98
|
+
it('should not modify Request-ID header when requestIdPrefix is not set', async function () {
|
|
99
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
100
|
+
env: 'custom',
|
|
101
|
+
customRootURI: 'https://app.example.local',
|
|
102
|
+
});
|
|
103
|
+
const scope = (0, nock_1.default)('https://app.example.local')
|
|
104
|
+
.get('/api/v1/ping')
|
|
105
|
+
.matchHeader('Request-ID', /^12345$/)
|
|
106
|
+
.reply(200, { status: 'ok' });
|
|
107
|
+
await bitgo.ping({
|
|
108
|
+
reqId: {
|
|
109
|
+
toString: () => '12345',
|
|
110
|
+
inc: () => {
|
|
111
|
+
/* mock */
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
scope.isDone().should.be.true();
|
|
116
|
+
});
|
|
117
|
+
it('should correctly format Request-ID with prefix and numeric sequence', async function () {
|
|
118
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
119
|
+
env: 'custom',
|
|
120
|
+
customRootURI: 'https://app.example.local',
|
|
121
|
+
requestIdPrefix: 'myapp-v1-',
|
|
122
|
+
});
|
|
123
|
+
const scope = (0, nock_1.default)('https://app.example.local')
|
|
124
|
+
.get('/api/v1/ping')
|
|
125
|
+
.matchHeader('Request-ID', 'myapp-v1-trace-123')
|
|
126
|
+
.reply(200, { status: 'ok' });
|
|
127
|
+
await bitgo.ping({
|
|
128
|
+
reqId: {
|
|
129
|
+
toString: () => 'trace-123',
|
|
130
|
+
inc: () => {
|
|
131
|
+
/* mock */
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
scope.isDone().should.be.true();
|
|
136
|
+
});
|
|
137
|
+
it('should work with empty string prefix', async function () {
|
|
138
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
139
|
+
env: 'custom',
|
|
140
|
+
customRootURI: 'https://app.example.local',
|
|
141
|
+
requestIdPrefix: '',
|
|
142
|
+
});
|
|
143
|
+
const scope = (0, nock_1.default)('https://app.example.local')
|
|
144
|
+
.get('/api/v1/ping')
|
|
145
|
+
.matchHeader('Request-ID', 'abc-123')
|
|
146
|
+
.reply(200, { status: 'ok' });
|
|
147
|
+
await bitgo.ping({
|
|
148
|
+
reqId: {
|
|
149
|
+
toString: () => 'abc-123',
|
|
150
|
+
inc: () => {
|
|
151
|
+
/* mock */
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
scope.isDone().should.be.true();
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
describe('http proxy agent', function () {
|
|
159
|
+
it('http proxy agent shall be created when proxy(customProxyagent) is set', function () {
|
|
160
|
+
const customProxyAgent = new proxy_agent_1.ProxyAgent({
|
|
161
|
+
getProxyForUrl: () => 'http://localhost:3000',
|
|
162
|
+
});
|
|
163
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
164
|
+
env: 'custom',
|
|
165
|
+
customRootURI: 'https://app.example.local',
|
|
166
|
+
customProxyAgent,
|
|
167
|
+
});
|
|
168
|
+
bitgo.should.have.property('_customProxyAgent', customProxyAgent);
|
|
169
|
+
});
|
|
170
|
+
it('bitgo api is still initiated when proxy(customProxyAgent) is not set', function () {
|
|
171
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
172
|
+
env: 'custom',
|
|
173
|
+
customRootURI: 'https://app.example.local',
|
|
174
|
+
});
|
|
175
|
+
bitgo.should.have.property('_customProxyAgent', undefined);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
describe('verifyAddress', function () {
|
|
179
|
+
it('should successfully verify a base58 address', function () {
|
|
180
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
181
|
+
env: 'test',
|
|
182
|
+
});
|
|
183
|
+
bitgo.verifyAddress({ address: '2N6paT2TU4N1XpaZjJiApWJXoeyrL3UWpkZ' }).should.be.true();
|
|
184
|
+
});
|
|
185
|
+
it('should successfully verify a bech32 address', function () {
|
|
186
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
187
|
+
env: 'test',
|
|
188
|
+
});
|
|
189
|
+
bitgo
|
|
190
|
+
.verifyAddress({ address: 'tb1qguzyk4w6kaqtpsczs5aj0w8r7598jq36egm8e98wqph3rwmex68seslgsg' })
|
|
191
|
+
.should.be.true();
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
describe('url', function () {
|
|
195
|
+
it('should return the correct URL for version 1', function () {
|
|
196
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
197
|
+
env: 'test',
|
|
198
|
+
customRootURI: 'https://test.bitgo.com',
|
|
199
|
+
});
|
|
200
|
+
const path = '/test-path';
|
|
201
|
+
const expectedUrl = 'https://test.bitgo.com/api/v1/test-path';
|
|
202
|
+
const result = bitgo.url(path, 1);
|
|
203
|
+
result.should.equal(expectedUrl);
|
|
204
|
+
});
|
|
205
|
+
it('should return the correct URL for version 2', function () {
|
|
206
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
207
|
+
env: 'test',
|
|
208
|
+
customRootURI: 'https://test.bitgo.com',
|
|
209
|
+
});
|
|
210
|
+
const path = '/test-path';
|
|
211
|
+
const expectedUrl = 'https://test.bitgo.com/api/v2/test-path';
|
|
212
|
+
const result = bitgo.url(path, 2);
|
|
213
|
+
result.should.equal(expectedUrl);
|
|
214
|
+
});
|
|
215
|
+
it('should return the correct URL for version 3', function () {
|
|
216
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
217
|
+
env: 'test',
|
|
218
|
+
customRootURI: 'https://test.bitgo.com',
|
|
219
|
+
});
|
|
220
|
+
const path = '/test-path';
|
|
221
|
+
const expectedUrl = 'https://test.bitgo.com/api/v3/test-path';
|
|
222
|
+
const result = bitgo.url(path, 3);
|
|
223
|
+
result.should.equal(expectedUrl);
|
|
224
|
+
});
|
|
225
|
+
it('should default to version 1 if no version is provided', function () {
|
|
226
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
227
|
+
env: 'test',
|
|
228
|
+
customRootURI: 'https://test.bitgo.com',
|
|
229
|
+
});
|
|
230
|
+
const path = '/test-path';
|
|
231
|
+
const expectedUrl = 'https://test.bitgo.com/api/v1/test-path';
|
|
232
|
+
const result = bitgo.url(path);
|
|
233
|
+
result.should.equal(expectedUrl);
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
describe('decryptKeys', function () {
|
|
237
|
+
let bitgo;
|
|
238
|
+
beforeEach(function () {
|
|
239
|
+
bitgo = new bitgoAPI_1.BitGoAPI({ env: 'test' });
|
|
240
|
+
});
|
|
241
|
+
afterEach(function () {
|
|
242
|
+
sinon.restore();
|
|
243
|
+
});
|
|
244
|
+
it('should throw if no params are provided', async function () {
|
|
245
|
+
// @ts-expect-error - intentionally calling with no params for test
|
|
246
|
+
await bitgo.decryptKeys().should.be.rejectedWith('Missing parameter: walletIdEncryptedKeyPairs');
|
|
247
|
+
});
|
|
248
|
+
it('should throw if walletIdEncryptedKeyPairs is missing', async function () {
|
|
249
|
+
await bitgo
|
|
250
|
+
// @ts-expect-error - intentionally missing required param
|
|
251
|
+
.decryptKeys({ password: 'password123' })
|
|
252
|
+
.should.be.rejectedWith('Missing parameter: walletIdEncryptedKeyPairs');
|
|
253
|
+
});
|
|
254
|
+
it('should throw if password is missing', async function () {
|
|
255
|
+
// @ts-expect-error - intentionally missing required param
|
|
256
|
+
await bitgo.decryptKeys({ walletIdEncryptedKeyPairs: [] }).should.be.rejectedWith('Missing parameter: password');
|
|
257
|
+
});
|
|
258
|
+
it('should throw if walletIdEncryptedKeyPairs is not an array', async function () {
|
|
259
|
+
await bitgo
|
|
260
|
+
// @ts-expect-error - intentionally providing wrong type
|
|
261
|
+
.decryptKeys({ walletIdEncryptedKeyPairs: 'not an array', password: 'password123' })
|
|
262
|
+
.should.be.rejectedWith('walletIdEncryptedKeyPairs must be an array');
|
|
263
|
+
});
|
|
264
|
+
it('should return empty array for empty walletIdEncryptedKeyPairs', async function () {
|
|
265
|
+
const result = await bitgo.decryptKeys({ walletIdEncryptedKeyPairs: [], password: 'password123' });
|
|
266
|
+
result.should.be.an.Array();
|
|
267
|
+
result.should.be.empty();
|
|
268
|
+
});
|
|
269
|
+
it('should throw if any walletId is missing or not a string', async function () {
|
|
270
|
+
await bitgo
|
|
271
|
+
.decryptKeys({
|
|
272
|
+
walletIdEncryptedKeyPairs: [
|
|
273
|
+
// @ts-expect-error - intentionally missing walletId
|
|
274
|
+
{ encryptedPrv: 'encrypted-data' },
|
|
275
|
+
],
|
|
276
|
+
password: 'password123',
|
|
277
|
+
})
|
|
278
|
+
.should.be.rejectedWith('each key pair must have a string walletId');
|
|
279
|
+
await bitgo
|
|
280
|
+
.decryptKeys({
|
|
281
|
+
walletIdEncryptedKeyPairs: [
|
|
282
|
+
// @ts-expect-error - intentionally providing wrong type
|
|
283
|
+
{ walletId: 123, encryptedPrv: 'encrypted-data' },
|
|
284
|
+
],
|
|
285
|
+
password: 'password123',
|
|
286
|
+
})
|
|
287
|
+
.should.be.rejectedWith('each key pair must have a string walletId');
|
|
288
|
+
});
|
|
289
|
+
it('should throw if any encryptedPrv is missing or not a string', async function () {
|
|
290
|
+
await bitgo
|
|
291
|
+
.decryptKeys({
|
|
292
|
+
walletIdEncryptedKeyPairs: [
|
|
293
|
+
// @ts-expect-error - intentionally missing encryptedPrv
|
|
294
|
+
{ walletId: 'wallet-id-1' },
|
|
295
|
+
],
|
|
296
|
+
password: 'password123',
|
|
297
|
+
})
|
|
298
|
+
.should.be.rejectedWith('each key pair must have a string encryptedPrv');
|
|
299
|
+
await bitgo
|
|
300
|
+
.decryptKeys({
|
|
301
|
+
walletIdEncryptedKeyPairs: [
|
|
302
|
+
// @ts-expect-error - intentionally providing wrong type
|
|
303
|
+
{ walletId: 'wallet-id-1', encryptedPrv: 123 },
|
|
304
|
+
],
|
|
305
|
+
password: 'password123',
|
|
306
|
+
})
|
|
307
|
+
.should.be.rejectedWith('each key pair must have a string encryptedPrv');
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
describe('decryptKeys', function () {
|
|
311
|
+
let bitgo;
|
|
312
|
+
beforeEach(function () {
|
|
313
|
+
bitgo = new bitgoAPI_1.BitGoAPI({ env: 'test' });
|
|
314
|
+
});
|
|
315
|
+
afterEach(function () {
|
|
316
|
+
sinon.restore();
|
|
317
|
+
});
|
|
318
|
+
it('should return walletIds of keys that failed to decrypt', async function () {
|
|
319
|
+
const decryptAsyncStub = sinon.stub(bitgo, 'decrypt');
|
|
320
|
+
decryptAsyncStub.onFirstCall().resolves('decrypted-key-1');
|
|
321
|
+
decryptAsyncStub.onSecondCall().rejects(new Error('decryption failed'));
|
|
322
|
+
const result = await bitgo.decryptKeys({
|
|
323
|
+
walletIdEncryptedKeyPairs: [
|
|
324
|
+
{ walletId: 'wallet-id-1', encryptedPrv: 'encrypted-data-1' },
|
|
325
|
+
{ walletId: 'wallet-id-2', encryptedPrv: 'encrypted-data-2' },
|
|
326
|
+
],
|
|
327
|
+
password: 'password123',
|
|
328
|
+
});
|
|
329
|
+
result.should.be.an.Array();
|
|
330
|
+
result.should.have.length(1);
|
|
331
|
+
result[0].should.equal('wallet-id-2');
|
|
332
|
+
});
|
|
333
|
+
it('should correctly process multiple wallet keys', async function () {
|
|
334
|
+
const decryptAsyncStub = sinon.stub(bitgo, 'decrypt');
|
|
335
|
+
decryptAsyncStub
|
|
336
|
+
.withArgs({ input: 'encrypted-data-2', password: 'password123' })
|
|
337
|
+
.rejects(new Error('decryption failed'));
|
|
338
|
+
decryptAsyncStub
|
|
339
|
+
.withArgs({ input: 'encrypted-data-4', password: 'password123' })
|
|
340
|
+
.rejects(new Error('decryption failed'));
|
|
341
|
+
decryptAsyncStub.resolves('success');
|
|
342
|
+
const result = await bitgo.decryptKeys({
|
|
343
|
+
walletIdEncryptedKeyPairs: [
|
|
344
|
+
{ walletId: 'wallet-id-1', encryptedPrv: 'encrypted-data-1' },
|
|
345
|
+
{ walletId: 'wallet-id-2', encryptedPrv: 'encrypted-data-2' },
|
|
346
|
+
{ walletId: 'wallet-id-3', encryptedPrv: 'encrypted-data-3' },
|
|
347
|
+
{ walletId: 'wallet-id-4', encryptedPrv: 'encrypted-data-4' },
|
|
348
|
+
],
|
|
349
|
+
password: 'password123',
|
|
350
|
+
});
|
|
351
|
+
decryptAsyncStub.callCount.should.equal(4);
|
|
352
|
+
result.should.be.an.Array();
|
|
353
|
+
result.should.have.length(2);
|
|
354
|
+
result.should.containDeep(['wallet-id-2', 'wallet-id-4']);
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
describe('User-Agent header based on environment', function () {
|
|
358
|
+
afterEach(function () {
|
|
359
|
+
nock_1.default.cleanAll();
|
|
360
|
+
sinon.restore();
|
|
361
|
+
});
|
|
362
|
+
it('should set User-Agent header when running in Node.js (typeof window === undefined)', async function () {
|
|
363
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
364
|
+
env: 'custom',
|
|
365
|
+
customRootURI: 'https://app.example.local',
|
|
366
|
+
userAgent: 'TestAgent/1.0',
|
|
367
|
+
});
|
|
368
|
+
// Ensure we're in a Node.js environment by verifying window is undefined
|
|
369
|
+
(typeof window).should.equal('undefined');
|
|
370
|
+
const scope = (0, nock_1.default)('https://app.example.local')
|
|
371
|
+
.get('/api/v1/ping')
|
|
372
|
+
.matchHeader('User-Agent', 'TestAgent/1.0')
|
|
373
|
+
.reply(200, { status: 'ok' });
|
|
374
|
+
await bitgo.ping({
|
|
375
|
+
reqId: {
|
|
376
|
+
toString: () => 'test-123',
|
|
377
|
+
inc: () => {
|
|
378
|
+
/* mock */
|
|
379
|
+
},
|
|
380
|
+
},
|
|
381
|
+
});
|
|
382
|
+
scope.isDone().should.be.true();
|
|
383
|
+
});
|
|
384
|
+
it('should not set User-Agent header when running in browser (typeof window !== undefined)', async function () {
|
|
385
|
+
// Mock the window object to simulate browser environment
|
|
386
|
+
const windowStub = { location: 'mock' };
|
|
387
|
+
global.window = windowStub;
|
|
388
|
+
try {
|
|
389
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
390
|
+
env: 'custom',
|
|
391
|
+
customRootURI: 'https://app.example.local',
|
|
392
|
+
userAgent: 'TestAgent/1.0',
|
|
393
|
+
});
|
|
394
|
+
const scope = (0, nock_1.default)('https://app.example.local')
|
|
395
|
+
.get('/api/v1/ping')
|
|
396
|
+
.reply(function () {
|
|
397
|
+
// Verify User-Agent header is NOT set to our custom value
|
|
398
|
+
const userAgent = this.req.headers['user-agent'];
|
|
399
|
+
if (userAgent && userAgent.includes('TestAgent/1.0')) {
|
|
400
|
+
throw new Error('User-Agent should not be set in browser environment');
|
|
401
|
+
}
|
|
402
|
+
return [200, { status: 'ok' }];
|
|
403
|
+
});
|
|
404
|
+
await bitgo.ping({
|
|
405
|
+
reqId: {
|
|
406
|
+
toString: () => 'test-123',
|
|
407
|
+
inc: () => {
|
|
408
|
+
/* mock */
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
});
|
|
412
|
+
scope.isDone().should.be.true();
|
|
413
|
+
}
|
|
414
|
+
finally {
|
|
415
|
+
// Clean up the global window mock
|
|
416
|
+
delete global.window;
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
describe('hmacAuthStrategy token lifecycle', function () {
|
|
421
|
+
const ROOT = 'https://app.example.local';
|
|
422
|
+
// Builds a mock strategy whose setToken / clearToken are sinon stubs.
|
|
423
|
+
function makeStrategy(overrides = {}) {
|
|
424
|
+
const setTokenStub = sinon.stub().resolves();
|
|
425
|
+
const clearTokenStub = sinon.stub().resolves();
|
|
426
|
+
const strategy = {
|
|
427
|
+
calculateRequestHeaders: sinon.stub().resolves({ hmac: 'hmac', timestamp: 1, tokenHash: 'hash' }),
|
|
428
|
+
verifyResponse: sinon.stub().resolves({
|
|
429
|
+
isValid: true,
|
|
430
|
+
expectedHmac: 'hmac',
|
|
431
|
+
signatureSubject: '',
|
|
432
|
+
isInResponseValidityWindow: true,
|
|
433
|
+
verificationTime: Date.now(),
|
|
434
|
+
}),
|
|
435
|
+
calculateHMAC: sinon.stub().resolves('hashed-pw'),
|
|
436
|
+
setToken: setTokenStub,
|
|
437
|
+
clearToken: clearTokenStub,
|
|
438
|
+
...overrides,
|
|
439
|
+
};
|
|
440
|
+
return { strategy, setTokenStub, clearTokenStub };
|
|
441
|
+
}
|
|
442
|
+
afterEach(function () {
|
|
443
|
+
nock_1.default.cleanAll();
|
|
444
|
+
sinon.restore();
|
|
445
|
+
});
|
|
446
|
+
describe('authenticate()', function () {
|
|
447
|
+
it('calls setToken with the access_token received from the server', async function () {
|
|
448
|
+
const { strategy, setTokenStub } = makeStrategy();
|
|
449
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({ env: 'custom', customRootURI: ROOT, hmacAuthStrategy: strategy });
|
|
450
|
+
(0, nock_1.default)(ROOT)
|
|
451
|
+
.post('/api/auth/v1/session')
|
|
452
|
+
.reply(200, {
|
|
453
|
+
user: { username: 'test@example.com' },
|
|
454
|
+
access_token: 'v2xmyaccesstoken',
|
|
455
|
+
});
|
|
456
|
+
await bitgo.authenticate({ username: 'test@example.com', password: 'hunter2' });
|
|
457
|
+
setTokenStub.calledOnce.should.be.true();
|
|
458
|
+
setTokenStub.firstCall.args[0].should.equal('v2xmyaccesstoken');
|
|
459
|
+
});
|
|
460
|
+
it('awaits setToken before making ensureEcdhKeychain requests', async function () {
|
|
461
|
+
// This is the core regression test: if setToken is not awaited, the
|
|
462
|
+
// strategy's key material won't be ready before calculateRequestHeaders
|
|
463
|
+
// is called for the GET /user/settings request, and it would throw.
|
|
464
|
+
let keyReady = false;
|
|
465
|
+
const { strategy } = makeStrategy({
|
|
466
|
+
setToken: sinon.stub().callsFake(async () => {
|
|
467
|
+
// Simulate non-trivial async key derivation (like crypto.subtle.importKey).
|
|
468
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
469
|
+
keyReady = true;
|
|
470
|
+
}),
|
|
471
|
+
calculateRequestHeaders: sinon.stub().callsFake(async () => {
|
|
472
|
+
if (!keyReady) {
|
|
473
|
+
throw new Error('No token available. Call setToken() or restoreToken() first.');
|
|
474
|
+
}
|
|
475
|
+
return { hmac: 'hmac', timestamp: Date.now(), tokenHash: 'hash' };
|
|
476
|
+
}),
|
|
477
|
+
});
|
|
478
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({ env: 'custom', customRootURI: ROOT, hmacAuthStrategy: strategy });
|
|
479
|
+
(0, nock_1.default)(ROOT)
|
|
480
|
+
.post('/api/auth/v1/session')
|
|
481
|
+
.reply(200, {
|
|
482
|
+
user: { username: 'test@example.com' },
|
|
483
|
+
access_token: 'v2xmytoken',
|
|
484
|
+
});
|
|
485
|
+
// The GET /user/settings request made by ensureUserEcdhKeychainIsCreated
|
|
486
|
+
// must succeed — it would throw if setToken wasn't awaited first.
|
|
487
|
+
(0, nock_1.default)(ROOT)
|
|
488
|
+
.get('/api/v1/user/settings')
|
|
489
|
+
.reply(200, {
|
|
490
|
+
settings: { ecdhKeychain: 'xpub123' },
|
|
491
|
+
});
|
|
492
|
+
await bitgo.authenticate({
|
|
493
|
+
username: 'test@example.com',
|
|
494
|
+
password: 'hunter2',
|
|
495
|
+
ensureEcdhKeychain: true,
|
|
496
|
+
});
|
|
497
|
+
keyReady.should.be.true();
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
describe('authenticateWithPasskey()', function () {
|
|
501
|
+
const validPasskey = JSON.stringify({
|
|
502
|
+
id: 'credential-id',
|
|
503
|
+
rawId: 'raw-id',
|
|
504
|
+
type: 'public-key',
|
|
505
|
+
response: {
|
|
506
|
+
authenticatorData: 'auth-data',
|
|
507
|
+
clientDataJSON: 'client-data',
|
|
508
|
+
signature: 'sig',
|
|
509
|
+
userHandle: 'user-handle-123',
|
|
510
|
+
},
|
|
511
|
+
});
|
|
512
|
+
it('calls setToken with the access_token received from the server', async function () {
|
|
513
|
+
const { strategy, setTokenStub } = makeStrategy();
|
|
514
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({ env: 'custom', customRootURI: ROOT, hmacAuthStrategy: strategy });
|
|
515
|
+
(0, nock_1.default)(ROOT)
|
|
516
|
+
.post('/api/auth/v1/session')
|
|
517
|
+
.reply(200, {
|
|
518
|
+
user: { username: 'test@example.com' },
|
|
519
|
+
access_token: 'v2xpasskeytoken',
|
|
520
|
+
});
|
|
521
|
+
await bitgo.authenticateWithPasskey(validPasskey);
|
|
522
|
+
setTokenStub.calledOnce.should.be.true();
|
|
523
|
+
setTokenStub.firstCall.args[0].should.equal('v2xpasskeytoken');
|
|
524
|
+
});
|
|
525
|
+
});
|
|
526
|
+
describe('clearAsync()', function () {
|
|
527
|
+
it('clears _token and calls clearToken on the strategy', async function () {
|
|
528
|
+
const { strategy, clearTokenStub } = makeStrategy();
|
|
529
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({ env: 'custom', customRootURI: ROOT, hmacAuthStrategy: strategy });
|
|
530
|
+
bitgo.authenticateWithAccessToken({ accessToken: 'v2xsometoken' });
|
|
531
|
+
bitgo._token.should.equal('v2xsometoken');
|
|
532
|
+
await bitgo.clearAsync();
|
|
533
|
+
(bitgo._token === undefined).should.be.true();
|
|
534
|
+
clearTokenStub.calledOnce.should.be.true();
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
describe('refreshToken()', function () {
|
|
538
|
+
it('calls setToken with the new access_token from the OAuth response', async function () {
|
|
539
|
+
const { strategy, setTokenStub } = makeStrategy();
|
|
540
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
541
|
+
env: 'custom',
|
|
542
|
+
customRootURI: ROOT,
|
|
543
|
+
hmacAuthStrategy: strategy,
|
|
544
|
+
clientId: 'client-id',
|
|
545
|
+
clientSecret: 'client-secret',
|
|
546
|
+
});
|
|
547
|
+
bitgo._refreshToken = 'old-refresh-token';
|
|
548
|
+
(0, nock_1.default)(ROOT).post('/oauth/token').reply(200, {
|
|
549
|
+
access_token: 'v2xnewtoken',
|
|
550
|
+
refresh_token: 'new-refresh-token',
|
|
551
|
+
});
|
|
552
|
+
await bitgo.refreshToken();
|
|
553
|
+
setTokenStub.calledOnce.should.be.true();
|
|
554
|
+
setTokenStub.firstCall.args[0].should.equal('v2xnewtoken');
|
|
555
|
+
});
|
|
556
|
+
});
|
|
557
|
+
describe('authenticateWithAuthCode()', function () {
|
|
558
|
+
it('calls setToken with the access_token from the OAuth response', async function () {
|
|
559
|
+
const { strategy, setTokenStub } = makeStrategy();
|
|
560
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
561
|
+
env: 'custom',
|
|
562
|
+
customRootURI: ROOT,
|
|
563
|
+
hmacAuthStrategy: strategy,
|
|
564
|
+
clientId: 'client-id',
|
|
565
|
+
clientSecret: 'client-secret',
|
|
566
|
+
});
|
|
567
|
+
(0, nock_1.default)(ROOT).post('/oauth/token').reply(200, {
|
|
568
|
+
access_token: 'v2xauthcodetoken',
|
|
569
|
+
refresh_token: 'refresh-token',
|
|
570
|
+
});
|
|
571
|
+
// authenticateWithAuthCode calls this.me() after setting the token
|
|
572
|
+
(0, nock_1.default)(ROOT)
|
|
573
|
+
.get('/api/v1/user/me')
|
|
574
|
+
.reply(200, {
|
|
575
|
+
user: { username: 'test@example.com' },
|
|
576
|
+
});
|
|
577
|
+
await bitgo.authenticateWithAuthCode({ authCode: 'my-auth-code' });
|
|
578
|
+
setTokenStub.calledOnce.should.be.true();
|
|
579
|
+
setTokenStub.firstCall.args[0].should.equal('v2xauthcodetoken');
|
|
580
|
+
});
|
|
581
|
+
});
|
|
582
|
+
describe('sync token-setting methods', function () {
|
|
583
|
+
it('authenticateWithAccessToken does not call setToken (synchronous — caller must invoke setToken on the strategy manually)', function () {
|
|
584
|
+
const { strategy, setTokenStub } = makeStrategy();
|
|
585
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({ env: 'custom', customRootURI: ROOT, hmacAuthStrategy: strategy });
|
|
586
|
+
bitgo.authenticateWithAccessToken({ accessToken: 'v2xsynctoken' });
|
|
587
|
+
setTokenStub.called.should.be.false();
|
|
588
|
+
});
|
|
589
|
+
it('fromJSON does not call setToken (synchronous — caller must invoke setToken on the strategy manually)', function () {
|
|
590
|
+
const { strategy, setTokenStub } = makeStrategy();
|
|
591
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({ env: 'custom', customRootURI: ROOT, hmacAuthStrategy: strategy });
|
|
592
|
+
bitgo.fromJSON({ user: { username: 'test@example.com' }, token: 'v2xjsontoken' });
|
|
593
|
+
setTokenStub.called.should.be.false();
|
|
594
|
+
});
|
|
595
|
+
});
|
|
596
|
+
describe('addAccessToken()', function () {
|
|
597
|
+
const validParams = {
|
|
598
|
+
label: 'test-token',
|
|
599
|
+
scope: ['wallet_view_all'],
|
|
600
|
+
duration: 3600,
|
|
601
|
+
};
|
|
602
|
+
it('should use HMAC auth when ecdhXprv is absent but hmacAuthStrategy is authenticated', async function () {
|
|
603
|
+
const { strategy } = makeStrategy({
|
|
604
|
+
isAuthenticated: sinon.stub().returns(true),
|
|
605
|
+
});
|
|
606
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({ env: 'custom', customRootURI: ROOT, hmacAuthStrategy: strategy });
|
|
607
|
+
// Do NOT set _ecdhXprv — simulates SSO/WebCrypto session
|
|
608
|
+
// Set a v2x token so the request goes through the v2 auth path
|
|
609
|
+
bitgo.authenticateWithAccessToken({ accessToken: 'v2xstrategytoken' });
|
|
610
|
+
const scope = (0, nock_1.default)(ROOT).post('/api/auth/v1/accesstoken').reply(200, {
|
|
611
|
+
token: 'v2xnewplaintoken',
|
|
612
|
+
label: 'test-token',
|
|
613
|
+
});
|
|
614
|
+
const result = await bitgo.addAccessToken(validParams);
|
|
615
|
+
scope.isDone().should.be.true();
|
|
616
|
+
// forceV1Auth should NOT have been set, so no downgrade warning
|
|
617
|
+
result.should.not.have.property('warning');
|
|
618
|
+
// The plain token from the response body should be returned directly
|
|
619
|
+
result.token.should.equal('v2xnewplaintoken');
|
|
620
|
+
});
|
|
621
|
+
it('should return plain token from response body when ecdhXprv is absent but strategyAuthenticated', async function () {
|
|
622
|
+
const handleTokenSpy = sinon.spy(bitgoAPI_1.BitGoAPI.prototype, 'handleTokenIssuance');
|
|
623
|
+
const { strategy } = makeStrategy({
|
|
624
|
+
isAuthenticated: sinon.stub().returns(true),
|
|
625
|
+
});
|
|
626
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({ env: 'custom', customRootURI: ROOT, hmacAuthStrategy: strategy });
|
|
627
|
+
bitgo.authenticateWithAccessToken({ accessToken: 'v2xstrategytoken' });
|
|
628
|
+
(0, nock_1.default)(ROOT).post('/api/auth/v1/accesstoken').reply(200, {
|
|
629
|
+
token: 'v2xplaintoken',
|
|
630
|
+
label: 'test-token',
|
|
631
|
+
});
|
|
632
|
+
const result = await bitgo.addAccessToken(validParams);
|
|
633
|
+
// handleTokenIssuance should NOT be called — no ECDH decryption needed
|
|
634
|
+
handleTokenSpy.called.should.be.false();
|
|
635
|
+
result.token.should.equal('v2xplaintoken');
|
|
636
|
+
handleTokenSpy.restore();
|
|
637
|
+
});
|
|
638
|
+
it('should still force V1 auth when neither ecdhXprv nor strategy is authenticated', async function () {
|
|
639
|
+
const { strategy } = makeStrategy({
|
|
640
|
+
isAuthenticated: sinon.stub().returns(false),
|
|
641
|
+
});
|
|
642
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({ env: 'custom', customRootURI: ROOT, hmacAuthStrategy: strategy });
|
|
643
|
+
bitgo.authenticateWithAccessToken({ accessToken: 'v2xlegacytoken' });
|
|
644
|
+
(0, nock_1.default)(ROOT).post('/api/auth/v1/accesstoken').reply(200, {
|
|
645
|
+
token: 'v2xlegacyresult',
|
|
646
|
+
label: 'test-token',
|
|
647
|
+
});
|
|
648
|
+
const result = await bitgo.addAccessToken(validParams);
|
|
649
|
+
// V1 auth path should add the downgrade warning
|
|
650
|
+
result.warning.should.match(/protocol downgrade/);
|
|
651
|
+
});
|
|
652
|
+
it('should still force V1 auth when isAuthenticated is not defined on strategy', async function () {
|
|
653
|
+
const { strategy } = makeStrategy();
|
|
654
|
+
// strategy has no isAuthenticated method by default from makeStrategy
|
|
655
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({ env: 'custom', customRootURI: ROOT, hmacAuthStrategy: strategy });
|
|
656
|
+
bitgo.authenticateWithAccessToken({ accessToken: 'v2xnoauthmethod' });
|
|
657
|
+
(0, nock_1.default)(ROOT).post('/api/auth/v1/accesstoken').reply(200, {
|
|
658
|
+
token: 'v2xresult',
|
|
659
|
+
label: 'test-token',
|
|
660
|
+
});
|
|
661
|
+
const result = await bitgo.addAccessToken(validParams);
|
|
662
|
+
// Without isAuthenticated, should fall back to V1 auth
|
|
663
|
+
result.warning.should.match(/protocol downgrade/);
|
|
664
|
+
});
|
|
665
|
+
});
|
|
666
|
+
});
|
|
667
|
+
describe('constants parameter', function () {
|
|
668
|
+
it('should allow passing constants via options and expose via fetchConstants', async function () {
|
|
669
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
670
|
+
env: 'custom',
|
|
671
|
+
customRootURI: 'https://app.example.local',
|
|
672
|
+
clientConstants: { maxFeeRate: '123123123123123' },
|
|
673
|
+
});
|
|
674
|
+
const constants = await bitgo.fetchConstants();
|
|
675
|
+
constants.should.have.property('maxFeeRate', '123123123123123');
|
|
676
|
+
});
|
|
677
|
+
it('should refresh constants when cache has expired', async function () {
|
|
678
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
679
|
+
env: 'custom',
|
|
680
|
+
customRootURI: 'https://app.example.local',
|
|
681
|
+
});
|
|
682
|
+
// Set up cached constants with an expired cache
|
|
683
|
+
bitgoAPI_1.BitGoAPI._constants = bitgoAPI_1.BitGoAPI._constants || {};
|
|
684
|
+
bitgoAPI_1.BitGoAPI._constantsExpire = bitgoAPI_1.BitGoAPI._constantsExpire || {};
|
|
685
|
+
bitgoAPI_1.BitGoAPI._constants['custom'] = { maxFeeRate: 'old-value' };
|
|
686
|
+
bitgoAPI_1.BitGoAPI._constantsExpire['custom'] = new Date(Date.now() - 1000); // Expired 1 second ago
|
|
687
|
+
const scope = (0, nock_1.default)('https://app.example.local')
|
|
688
|
+
.get('/api/v1/client/constants')
|
|
689
|
+
.reply(200, {
|
|
690
|
+
constants: { maxFeeRate: 'new-value', newConstant: 'added' },
|
|
691
|
+
});
|
|
692
|
+
const constants = await bitgo.fetchConstants();
|
|
693
|
+
// Should return the new constants from the server
|
|
694
|
+
constants.should.have.property('maxFeeRate', 'new-value');
|
|
695
|
+
constants.should.have.property('newConstant', 'added');
|
|
696
|
+
scope.isDone().should.be.true();
|
|
697
|
+
nock_1.default.cleanAll();
|
|
698
|
+
});
|
|
699
|
+
it('should use cached constants when cache is still valid', async function () {
|
|
700
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
701
|
+
env: 'custom',
|
|
702
|
+
customRootURI: 'https://app.example.local',
|
|
703
|
+
});
|
|
704
|
+
// Set up cached constants with a future expiry
|
|
705
|
+
const cachedConstants = { maxFeeRate: 'cached-value', anotherSetting: 'cached-setting' };
|
|
706
|
+
bitgoAPI_1.BitGoAPI._constants = bitgoAPI_1.BitGoAPI._constants || {};
|
|
707
|
+
bitgoAPI_1.BitGoAPI._constantsExpire = bitgoAPI_1.BitGoAPI._constantsExpire || {};
|
|
708
|
+
bitgoAPI_1.BitGoAPI._constants['custom'] = cachedConstants;
|
|
709
|
+
bitgoAPI_1.BitGoAPI._constantsExpire['custom'] = new Date(Date.now() + 5 * 60 * 1000); // Valid for 5 more minutes
|
|
710
|
+
const scope = (0, nock_1.default)('https://app.example.local')
|
|
711
|
+
.get('/api/v1/client/constants')
|
|
712
|
+
.reply(200, { constants: { shouldNotBeUsed: true } });
|
|
713
|
+
const constants = await bitgo.fetchConstants();
|
|
714
|
+
// Should return the cached constants
|
|
715
|
+
constants.should.deepEqual(cachedConstants);
|
|
716
|
+
// Verify that no HTTP request was made (since cache was valid)
|
|
717
|
+
scope.isDone().should.be.false();
|
|
718
|
+
nock_1.default.cleanAll();
|
|
719
|
+
});
|
|
720
|
+
it('should use cached constants when no cache expiry is set', async function () {
|
|
721
|
+
const bitgo = new bitgoAPI_1.BitGoAPI({
|
|
722
|
+
env: 'custom',
|
|
723
|
+
customRootURI: 'https://app.example.local',
|
|
724
|
+
});
|
|
725
|
+
// Set up cached constants with no expiry
|
|
726
|
+
const cachedConstants = { maxFeeRate: 'no-expiry-value' };
|
|
727
|
+
bitgoAPI_1.BitGoAPI._constants = bitgoAPI_1.BitGoAPI._constants || {};
|
|
728
|
+
bitgoAPI_1.BitGoAPI._constantsExpire = bitgoAPI_1.BitGoAPI._constantsExpire || {};
|
|
729
|
+
bitgoAPI_1.BitGoAPI._constants['custom'] = cachedConstants;
|
|
730
|
+
bitgoAPI_1.BitGoAPI._constantsExpire['custom'] = undefined;
|
|
731
|
+
const scope = (0, nock_1.default)('https://app.example.local')
|
|
732
|
+
.get('/api/v1/client/constants')
|
|
733
|
+
.reply(200, { constants: { shouldNotBeUsed: true } });
|
|
734
|
+
const constants = await bitgo.fetchConstants();
|
|
735
|
+
// Should return the cached constants
|
|
736
|
+
constants.should.deepEqual(cachedConstants);
|
|
737
|
+
// Verify that no HTTP request was made (since no expiry means cache is always valid)
|
|
738
|
+
scope.isDone().should.be.false();
|
|
739
|
+
nock_1.default.cleanAll();
|
|
740
|
+
});
|
|
741
|
+
});
|
|
742
|
+
describe('packKeychainsFFD', function () {
|
|
743
|
+
let bitgo;
|
|
744
|
+
before(function () {
|
|
745
|
+
bitgo = new bitgoAPI_1.BitGoAPI({ env: 'custom', customRootURI: 'https://app.example.local' });
|
|
746
|
+
});
|
|
747
|
+
function ffd(keychains, v2Keychains, maxBatchSizeBytes) {
|
|
748
|
+
return bitgo.packKeychainsFFD(keychains, v2Keychains, maxBatchSizeBytes);
|
|
749
|
+
}
|
|
750
|
+
it('returns an empty array when both inputs are empty', function () {
|
|
751
|
+
const bins = ffd({}, {}, 1024);
|
|
752
|
+
bins.should.be.an.Array();
|
|
753
|
+
bins.should.have.length(0);
|
|
754
|
+
});
|
|
755
|
+
it('packs all items into a single bin when they fit within the limit', function () {
|
|
756
|
+
// Each entry: 2-byte id + 10-byte value = 12 bytes; 5 entries = 60 bytes < 200 limit
|
|
757
|
+
const keychains = { k1: 'aaaaaaaaaa', k2: 'bbbbbbbbbb', k3: 'cccccccccc' };
|
|
758
|
+
const v2Keychains = { v1: 'dddddddddd', v2: 'eeeeeeeeee' };
|
|
759
|
+
const bins = ffd(keychains, v2Keychains, 200);
|
|
760
|
+
bins.should.have.length(1);
|
|
761
|
+
Object.keys(bins[0].v1Batch).should.have.length(3);
|
|
762
|
+
Object.keys(bins[0].v2Batch).should.have.length(2);
|
|
763
|
+
});
|
|
764
|
+
it('splits into multiple bins when a single bin cannot fit all items', function () {
|
|
765
|
+
// id='k1' (2 bytes) + 600-char value = 602 bytes; 2 entries exceed 700-byte limit
|
|
766
|
+
const keychains = { k1: 'x'.repeat(600), k2: 'y'.repeat(600) };
|
|
767
|
+
const bins = ffd(keychains, {}, 700);
|
|
768
|
+
bins.should.have.length(2);
|
|
769
|
+
});
|
|
770
|
+
it('throws when a single item exceeds maxBatchSizeBytes', function () {
|
|
771
|
+
// id='k1' (2 bytes) + 200-char value = 202 bytes > 100-byte limit
|
|
772
|
+
const keychains = { k1: 'x'.repeat(200) };
|
|
773
|
+
try {
|
|
774
|
+
ffd(keychains, {}, 100);
|
|
775
|
+
throw new Error('Expected error not thrown');
|
|
776
|
+
}
|
|
777
|
+
catch (e) {
|
|
778
|
+
e.message.should.match(/exceeds the maximum batch size/);
|
|
779
|
+
}
|
|
780
|
+
});
|
|
781
|
+
it('places V1 keychains in v1Batch and V2 keychains in v2Batch', function () {
|
|
782
|
+
const keychains = { k1: 'v1value' };
|
|
783
|
+
const v2Keychains = { k2: 'v2value' };
|
|
784
|
+
const bins = ffd(keychains, v2Keychains, 10000);
|
|
785
|
+
bins.should.have.length(1);
|
|
786
|
+
bins[0].v1Batch.should.have.property('k1', 'v1value');
|
|
787
|
+
bins[0].v2Batch.should.have.property('k2', 'v2value');
|
|
788
|
+
bins[0].v1Batch.should.not.have.property('k2');
|
|
789
|
+
bins[0].v2Batch.should.not.have.property('k1');
|
|
790
|
+
});
|
|
791
|
+
it('uses FFD ordering so the largest item is packed first', function () {
|
|
792
|
+
// 'big': id(3) + 497 bytes = 500 bytes; 's1','s2': id(2) + 98 bytes = 100 bytes each
|
|
793
|
+
// maxBatchSizeBytes = 600
|
|
794
|
+
// FFD order (descending): big(500), s1(100), s2(100)
|
|
795
|
+
// bin0: big(500). s1: 500+100=600 <=600, fits. s2: 600+100=700 > 600, new bin1.
|
|
796
|
+
// Result: bin0={big,s1}, bin1={s2}
|
|
797
|
+
const keychains = { big: 'x'.repeat(497), s1: 'y'.repeat(98), s2: 'z'.repeat(98) };
|
|
798
|
+
const bins = ffd(keychains, {}, 600);
|
|
799
|
+
bins.should.have.length(2);
|
|
800
|
+
// 'big' should share its bin with one small item (FFD packs the largest first)
|
|
801
|
+
const binWithBig = bins.find((b) => 'big' in b.v1Batch);
|
|
802
|
+
Object.keys(binWithBig.v1Batch).should.have.length(2);
|
|
803
|
+
});
|
|
804
|
+
});
|
|
805
|
+
describe('processKeychainPasswordUpdatesInBatches', function () {
|
|
806
|
+
const ROOT = 'https://app.example.local';
|
|
807
|
+
let bitgo;
|
|
808
|
+
beforeEach(function () {
|
|
809
|
+
const strategy = {
|
|
810
|
+
calculateRequestHeaders: sinon.stub().resolves({ hmac: 'hmac', timestamp: Date.now(), tokenHash: 'hash' }),
|
|
811
|
+
verifyResponse: sinon.stub().resolves({
|
|
812
|
+
isValid: true,
|
|
813
|
+
expectedHmac: 'hmac',
|
|
814
|
+
signatureSubject: '',
|
|
815
|
+
isInResponseValidityWindow: true,
|
|
816
|
+
verificationTime: Date.now(),
|
|
817
|
+
}),
|
|
818
|
+
calculateHMAC: sinon.stub().resolves('hashed-pw'),
|
|
819
|
+
setToken: sinon.stub().resolves(),
|
|
820
|
+
clearToken: sinon.stub().resolves(),
|
|
821
|
+
};
|
|
822
|
+
bitgo = new bitgoAPI_1.BitGoAPI({ env: 'custom', customRootURI: ROOT, hmacAuthStrategy: strategy });
|
|
823
|
+
});
|
|
824
|
+
afterEach(function () {
|
|
825
|
+
nock_1.default.cleanAll();
|
|
826
|
+
sinon.restore();
|
|
827
|
+
});
|
|
828
|
+
async function runBatches(keychains, v2Keychains, maxBatchSizeKB, maxRetries = 3) {
|
|
829
|
+
return bitgo.processKeychainPasswordUpdatesInBatches(keychains, v2Keychains, maxBatchSizeKB, maxRetries);
|
|
830
|
+
}
|
|
831
|
+
it('makes a single PUT request for a small payload', async function () {
|
|
832
|
+
const scope = (0, nock_1.default)(ROOT).put('/api/v2/user/keychains').reply(200, {});
|
|
833
|
+
await runBatches({ k1: 'small' }, {}, 1024);
|
|
834
|
+
scope.isDone().should.be.true();
|
|
835
|
+
});
|
|
836
|
+
it('makes two PUT requests when the payload spans two bins', async function () {
|
|
837
|
+
// id='k1'(2) + 600 = 602 bytes each; 2 entries exceed 1 KB limit => 2 bins
|
|
838
|
+
const keychains = { k1: 'x'.repeat(600), k2: 'y'.repeat(600) };
|
|
839
|
+
const scope = (0, nock_1.default)(ROOT).put('/api/v2/user/keychains').twice().reply(200, {});
|
|
840
|
+
await runBatches(keychains, {}, 1);
|
|
841
|
+
scope.isDone().should.be.true();
|
|
842
|
+
});
|
|
843
|
+
it('retries a failed batch and succeeds on the second attempt', async function () {
|
|
844
|
+
(0, nock_1.default)(ROOT).put('/api/v2/user/keychains').reply(500, { error: 'internal error' });
|
|
845
|
+
(0, nock_1.default)(ROOT).put('/api/v2/user/keychains').reply(200, {});
|
|
846
|
+
// Should not throw
|
|
847
|
+
await runBatches({ k1: 'value' }, {}, 1024, 3);
|
|
848
|
+
});
|
|
849
|
+
it('throws after exhausting all retries on persistent HTTP errors', async function () {
|
|
850
|
+
(0, nock_1.default)(ROOT).put('/api/v2/user/keychains').times(3).reply(500, { error: 'internal error' });
|
|
851
|
+
let thrownError;
|
|
852
|
+
try {
|
|
853
|
+
await runBatches({ k1: 'value' }, {}, 1024, 3);
|
|
854
|
+
}
|
|
855
|
+
catch (e) {
|
|
856
|
+
thrownError = e;
|
|
857
|
+
}
|
|
858
|
+
thrownError.message.should.match(/failed after 3 retries/);
|
|
859
|
+
});
|
|
860
|
+
it('throws after exhausting all retries when the server reports failed keychains', async function () {
|
|
861
|
+
(0, nock_1.default)(ROOT)
|
|
862
|
+
.put('/api/v2/user/keychains')
|
|
863
|
+
.times(3)
|
|
864
|
+
.reply(200, { failed: { v1: { k1: 'encryption error' } } });
|
|
865
|
+
let thrownError;
|
|
866
|
+
try {
|
|
867
|
+
await runBatches({ k1: 'value' }, {}, 1024, 3);
|
|
868
|
+
}
|
|
869
|
+
catch (e) {
|
|
870
|
+
thrownError = e;
|
|
871
|
+
}
|
|
872
|
+
thrownError.message.should.match(/had failed keychains/);
|
|
873
|
+
});
|
|
874
|
+
});
|
|
875
|
+
describe('changePassword batching flow', function () {
|
|
876
|
+
const ROOT = 'https://app.example.local';
|
|
877
|
+
let bitgo;
|
|
878
|
+
let sandbox;
|
|
879
|
+
beforeEach(function () {
|
|
880
|
+
sandbox = sinon.createSandbox();
|
|
881
|
+
const strategy = {
|
|
882
|
+
calculateRequestHeaders: sandbox.stub().resolves({ hmac: 'hmac', timestamp: Date.now(), tokenHash: 'hash' }),
|
|
883
|
+
verifyResponse: sandbox.stub().resolves({
|
|
884
|
+
isValid: true,
|
|
885
|
+
expectedHmac: 'hmac',
|
|
886
|
+
signatureSubject: '',
|
|
887
|
+
isInResponseValidityWindow: true,
|
|
888
|
+
verificationTime: Date.now(),
|
|
889
|
+
}),
|
|
890
|
+
calculateHMAC: sandbox.stub().resolves('hashed-pw'),
|
|
891
|
+
setToken: sandbox.stub().resolves(),
|
|
892
|
+
clearToken: sandbox.stub().resolves(),
|
|
893
|
+
};
|
|
894
|
+
bitgo = new bitgoAPI_1.BitGoAPI({ env: 'custom', customRootURI: ROOT, hmacAuthStrategy: strategy });
|
|
895
|
+
bitgo._user = { username: 'test@bitgo.com' };
|
|
896
|
+
sandbox.stub(bitgo, 'verifyPassword').resolves(true);
|
|
897
|
+
sandbox.stub(bitgo, 'keychains').returns({
|
|
898
|
+
updatePassword: sandbox.stub().resolves({ keychains: { k1: 'v1enc' }, version: 25 }),
|
|
899
|
+
});
|
|
900
|
+
sandbox.stub(bitgo, 'coin').returns({
|
|
901
|
+
keychains: () => ({
|
|
902
|
+
updatePassword: sandbox.stub().resolves({ v2k1: 'v2enc' }),
|
|
903
|
+
}),
|
|
904
|
+
});
|
|
905
|
+
});
|
|
906
|
+
afterEach(function () {
|
|
907
|
+
nock_1.default.cleanAll();
|
|
908
|
+
sandbox.restore();
|
|
909
|
+
});
|
|
910
|
+
it('calls PUT /user/keychains and POST /user/changepassword without keychains when batching is enabled', async function () {
|
|
911
|
+
(0, nock_1.default)(ROOT)
|
|
912
|
+
.get('/api/v2/user/checkBatchingPasswordFlow')
|
|
913
|
+
.query(true)
|
|
914
|
+
.reply(200, { isBatchingFlowEnabled: true, maxBatchSizeKB: 900 });
|
|
915
|
+
const batchPutScope = (0, nock_1.default)(ROOT).put('/api/v2/user/keychains').reply(200, {});
|
|
916
|
+
const changePassScope = (0, nock_1.default)(ROOT)
|
|
917
|
+
.post('/api/v1/user/changepassword', (body) => !body.keychains && !body.v2_keychains)
|
|
918
|
+
.reply(200, {});
|
|
919
|
+
await bitgo.changePassword({ oldPassword: 'oldpw', newPassword: 'newpw' });
|
|
920
|
+
batchPutScope.isDone().should.be.true();
|
|
921
|
+
changePassScope.isDone().should.be.true();
|
|
922
|
+
});
|
|
923
|
+
it('sends keychains in the POST body (legacy flow) when the server disables batching', async function () {
|
|
924
|
+
(0, nock_1.default)(ROOT).get('/api/v2/user/checkBatchingPasswordFlow').query(true).reply(200, { isBatchingFlowEnabled: false });
|
|
925
|
+
const legacyScope = (0, nock_1.default)(ROOT)
|
|
926
|
+
.post('/api/v1/user/changepassword', (body) => !!body.keychains && !!body.v2_keychains)
|
|
927
|
+
.reply(200, {});
|
|
928
|
+
await bitgo.changePassword({ oldPassword: 'oldpw', newPassword: 'newpw' });
|
|
929
|
+
legacyScope.isDone().should.be.true();
|
|
930
|
+
});
|
|
931
|
+
it('falls back to legacy flow when the batching check request fails', async function () {
|
|
932
|
+
(0, nock_1.default)(ROOT).get('/api/v2/user/checkBatchingPasswordFlow').query(true).reply(503, { error: 'service unavailable' });
|
|
933
|
+
const legacyScope = (0, nock_1.default)(ROOT)
|
|
934
|
+
.post('/api/v1/user/changepassword', (body) => !!body.keychains && !!body.v2_keychains)
|
|
935
|
+
.reply(200, {});
|
|
936
|
+
await bitgo.changePassword({ oldPassword: 'oldpw', newPassword: 'newpw' });
|
|
937
|
+
legacyScope.isDone().should.be.true();
|
|
938
|
+
});
|
|
939
|
+
});
|
|
940
|
+
describe('createUserEcdhKeychain - encryptionVersion threading', function () {
|
|
941
|
+
const ROOT = 'https://app.bitgo-test.com';
|
|
942
|
+
let bitgo;
|
|
943
|
+
beforeEach(function () {
|
|
944
|
+
bitgo = new bitgoAPI_1.BitGoAPI({ env: 'test' });
|
|
945
|
+
});
|
|
946
|
+
afterEach(function () {
|
|
947
|
+
nock_1.default.cleanAll();
|
|
948
|
+
sinon.restore();
|
|
949
|
+
});
|
|
950
|
+
it('passes encryptionVersion: 2 to encrypt', async function () {
|
|
951
|
+
const encryptAsyncSpy = sinon.spy(bitgo, 'encrypt');
|
|
952
|
+
(0, nock_1.default)(ROOT).post('/api/v1/keychain').reply(200, { xpub: 'xpub123', id: 'key-id' });
|
|
953
|
+
await bitgo.createUserEcdhKeychain('loginPassword', 2);
|
|
954
|
+
assert.ok(encryptAsyncSpy.calledOnce);
|
|
955
|
+
assert.strictEqual(encryptAsyncSpy.firstCall.args[0].encryptionVersion, 2);
|
|
956
|
+
});
|
|
957
|
+
it('passes encryptionVersion: undefined when not set (defaults to v1)', async function () {
|
|
958
|
+
const encryptAsyncSpy = sinon.spy(bitgo, 'encrypt');
|
|
959
|
+
(0, nock_1.default)(ROOT).post('/api/v1/keychain').reply(200, { xpub: 'xpub123', id: 'key-id' });
|
|
960
|
+
await bitgo.createUserEcdhKeychain('loginPassword');
|
|
961
|
+
assert.ok(encryptAsyncSpy.calledOnce);
|
|
962
|
+
assert.strictEqual(encryptAsyncSpy.firstCall.args[0].encryptionVersion, undefined);
|
|
963
|
+
});
|
|
964
|
+
});
|
|
965
|
+
describe('splitSecret - encryptionVersion threading', function () {
|
|
966
|
+
let bitgo;
|
|
967
|
+
beforeEach(function () {
|
|
968
|
+
bitgo = new bitgoAPI_1.BitGoAPI({ env: 'test' });
|
|
969
|
+
});
|
|
970
|
+
afterEach(function () {
|
|
971
|
+
sinon.restore();
|
|
972
|
+
});
|
|
973
|
+
it('passes encryptionVersion: 2 to every encrypt shard call', async function () {
|
|
974
|
+
const encryptAsyncSpy = sinon.spy(bitgo, 'encrypt');
|
|
975
|
+
const passwords = ['pw1', 'pw2', 'pw3'];
|
|
976
|
+
await bitgo.splitSecret({
|
|
977
|
+
seed: 'a'.repeat(64),
|
|
978
|
+
passwords,
|
|
979
|
+
m: 2,
|
|
980
|
+
encryptionVersion: 2,
|
|
981
|
+
});
|
|
982
|
+
assert.strictEqual(encryptAsyncSpy.callCount, 3, 'should encrypt each shard');
|
|
983
|
+
for (const call of encryptAsyncSpy.getCalls()) {
|
|
984
|
+
assert.strictEqual(call.args[0].encryptionVersion, 2);
|
|
985
|
+
}
|
|
986
|
+
});
|
|
987
|
+
it('passes encryptionVersion: undefined when not set', async function () {
|
|
988
|
+
const encryptAsyncSpy = sinon.spy(bitgo, 'encrypt');
|
|
989
|
+
await bitgo.splitSecret({
|
|
990
|
+
seed: 'b'.repeat(64),
|
|
991
|
+
passwords: ['pw1', 'pw2'],
|
|
992
|
+
m: 2,
|
|
993
|
+
});
|
|
994
|
+
assert.strictEqual(encryptAsyncSpy.callCount, 2);
|
|
995
|
+
for (const call of encryptAsyncSpy.getCalls()) {
|
|
996
|
+
assert.strictEqual(call.args[0].encryptionVersion, undefined);
|
|
997
|
+
}
|
|
998
|
+
});
|
|
999
|
+
});
|
|
1000
|
+
});
|
|
1001
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYml0Z29BUEkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi90ZXN0L3VuaXQvYml0Z29BUEkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSwrQ0FBaUM7QUFDakMsa0JBQWdCO0FBQ2hCLGlEQUE4QztBQUM5Qyw2Q0FBeUM7QUFDekMsNkNBQStCO0FBQy9CLGdEQUF3QjtBQUd4QixRQUFRLENBQUMsYUFBYSxFQUFFO0lBQ3RCLFFBQVEsQ0FBQyxvQ0FBb0MsRUFBRTtRQUM3QyxFQUFFLENBQUMsaURBQWlELEVBQUU7WUFDcEQsTUFBTSxLQUFLLEdBQUcsSUFBSSxtQkFBUSxDQUFDO2dCQUN6QixHQUFHLEVBQUUsUUFBUTtnQkFDYixhQUFhLEVBQUUsMkJBQTJCO2dCQUMxQyx5QkFBeUIsRUFBRSxJQUFJO2FBQ2hDLENBQUMsQ0FBQztZQUVILEtBQUssQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO1lBQ3hELEtBQUssQ0FBQyx5QkFBeUIsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3JELENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLGtEQUFrRCxFQUFFO1lBQ3JELE1BQU0sS0FBSyxHQUFHLElBQUksbUJBQVEsQ0FBQztnQkFDekIsR0FBRyxFQUFFLFFBQVE7Z0JBQ2IsYUFBYSxFQUFFLDJCQUEyQjtnQkFDMUMseUJBQXlCLEVBQUUsS0FBSzthQUNqQyxDQUFDLENBQUM7WUFFSCxLQUFLLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsMkJBQTJCLENBQUMsQ0FBQztZQUN4RCxLQUFLLENBQUMseUJBQXlCLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN0RCxDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyxrREFBa0Qs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QUcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsU0FBUyxDQUFDLENBQUM7WUFFcEQsTUFBTSxLQUFLLENBQUMsV0FBVyxDQUFDO2dCQUN0QixJQUFJLEVBQUUsR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7Z0JBQ3BCLFNBQVMsRUFBRSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUM7Z0JBQ3pCLENBQUMsRUFBRSxDQUFDO2FBQ0wsQ0FBQyxDQUFDO1lBRUgsTUFBTSxDQUFDLFdBQVcsQ0FBQyxlQUFlLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFDO1lBQ2pELEtBQUssTUFBTSxJQUFJLElBQUksZUFBZSxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUM7Z0JBQzlDLE1BQU0sQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxpQkFBaUIsRUFBRSxTQUFTLENBQUMsQ0FBQztZQUNoRSxDQUFDO1FBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgYXNzZXJ0IGZyb20gJ2Fzc2VydCc7XG5pbXBvcnQgJ3Nob3VsZCc7XG5pbXBvcnQgeyBCaXRHb0FQSSB9IGZyb20gJy4uLy4uL3NyYy9iaXRnb0FQSSc7XG5pbXBvcnQgeyBQcm94eUFnZW50IH0gZnJvbSAncHJveHktYWdlbnQnO1xuaW1wb3J0ICogYXMgc2lub24gZnJvbSAnc2lub24nO1xuaW1wb3J0IG5vY2sgZnJvbSAnbm9jayc7XG5pbXBvcnQgdHlwZSB7IElIbWFjQXV0aFN0cmF0ZWd5IH0gZnJvbSAnQGJpdGdvL3Nkay1obWFjJztcblxuZGVzY3JpYmUoJ0NvbnN0cnVjdG9yJywgZnVuY3Rpb24gKCkge1xuICBkZXNjcmliZSgnY29va2llc1Byb3BhZ2F0aW9uRW5hYmxlZCBhcmd1bWVudCcsIGZ1bmN0aW9uICgpIHtcbiAgICBpdCgnY29va2llc1Byb3BhZ2F0aW9uRW5hYmxlZCBpcyBlbmFibGVkIGV4cGxpY2l0bHknLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBiaXRnbyA9IG5ldyBCaXRHb0FQSSh7XG4gICAgICAgIGVudjogJ2N1c3RvbScsXG4gICAgICAgIGN1c3RvbVJvb3RVUkk6ICdodHRwczovL2FwcC5leGFtcGxlLmxvY2FsJyxcbiAgICAgICAgY29va2llc1Byb3BhZ2F0aW9uRW5hYmxlZDogdHJ1ZSxcbiAgICAgIH0pO1xuXG4gICAgICBiaXRnby5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnY29va2llc1Byb3BhZ2F0aW9uRW5hYmxlZCcpO1xuICAgICAgYml0Z28uY29va2llc1Byb3BhZ2F0aW9uRW5hYmxlZC5zaG91bGQuZXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnY29va2llc1Byb3BhZ2F0aW9uRW5hYmxlZCBpcyBkaXNhYmxlZCBleHBsaWNpdGx5JywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgYml0Z28gPSBuZXcgQml0R29BUEkoe1xuICAgICAgICBlbnY6ICdjdXN0b20nLFxuICAgICAgICBjdXN0b21Sb290VVJJOiAnaHR0cHM6Ly9hcHAuZXhhbXBsZS5sb2NhbCcsXG4gICAgICAgIGNvb2tpZXNQcm9wYWdhdGlvbkVuYWJsZWQ6IGZhbHNlLFxuICAgICAgfSk7XG5cbiAgICAgIGJpdGdvLnNob3VsZC5oYXZlLnByb3BlcnR5KCdjb29raWVzUHJvcGFnYXRpb25FbmFibGVkJyk7XG4gICAgICBiaXRnby5jb29raWVzUHJvcGFnYXRpb25FbmFibGVkLnNob3VsZC5lcXVhbChmYWxzZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnY29va2llc1Byb3BhZ2F0aW9uRW5hYmxlZCBpcyBkaXNhYmxlZCBieSBkZWZhdWx0JywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgYml0Z28gPSBuZXcgQml0R29BUEkoe1xuICAgICAgICBlbnY6ICdjdXN0b20nLFxuICAgICAgICBjdXN0b21Sb290VVJJOiAnaHR0cHM6Ly9hcHAuZXhhbXBsZS5sb2NhbCcsXG4gICAgICB9KTtcblxuICAgICAgYml0Z28uc2hvdWxkLmhhdmUucHJvcGVydHkoJ2Nvb2tpZXNQcm9wYWdhdGlvbkVuYWJsZWQnKTtcbiAgICAgIGJpdGdvLmNvb2tpZXNQcm9wYWdhdGlvbkVuYWJsZWQuc2hvdWxkLmVxdWFsKGZhbHNlKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ3JlcXVlc3RJZFByZWZpeCBhcmd1bWVudCcsIGZ1bmN0aW9uICgpIHtcbiAgICBhZnRlckVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgbm9jay5jbGVhbkFsbCgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBwcmVwZW5kIHJlcXVlc3RJZFByZWZpeCB0byBSZXF1ZXN0LUlEIGhlYWRlciB3aGVuIHNldCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGJpdGdvID0gbmV3IEJpdEdvQVBJKHtcbiAgICAgICAgZW52OiAnY3VzdG9tJyxcbiAgICAgICAgY3VzdG9tUm9vdFVSSTogJ2h0dHBzOi8vYXBwLmV4YW1wbGUubG9jYWwnLFxuICAgICAgICByZXF1ZXN0SWRQcmVmaXg6ICd0ZXN0LXByZWZpeC0nLFxuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IHNjb3BlID0gbm9jaygnaHR0cHM6Ly9hcHAuZXhhbXBsZS5sb2NhbCcpXG4gICAgICAgIC5nZXQoJy9hcGkvdjEvcGluZycpXG4gICAgICAgIC5tYXRjaEhlYWRlcignUmVxdWVzdC1JRCcsIC9edGVzdC1wcmVmaXgtLylcbiAgICAgICAgLnJlcGx5KDIwMCwgeyBzdGF0dXM6ICdvaycgfSk7XG5cbiAgICAgIGF3YWl0IGJpdGdvLnBpbmcoe1xuICAgICAgICByZXFJZDoge1xuICAgICAgICAgIHRvU3RyaW5nOiAoKSA9PiAnMTIzNDUnLFxuICAgICAgICAgIGluYzogKCkgPT4ge1xuICAgICAgICAgICAgLyogbW9jayAqL1xuICAgICAgICAgIH0sXG4gICAgICAgIH0gYXMgYW55LFxuICAgICAgfSk7XG5cbiAgICAgIHNjb3BlLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIG5vdCBtb2RpZnkgUmVxdWVzdC1JRCBoZWFkZXIgd2hlbiByZXF1ZXN0SWRQcmVmaXggaXMgbm90IHNldCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGJpdGdvID0gbmV3IEJpdEdvQVBJKHtcbiAgICAgICAgZW52OiAnY3VzdG9tJyxcbiAgICAgICAgY3VzdG9tUm9vdFVSSTogJ2h0dHBzOi8vYXBwLmV4YW1wbGUubG9jYWwnLFxuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IHNjb3BlID0gbm9jaygnaHR0cHM6Ly9hcHAuZXhhbXBsZS5sb2NhbCcpXG4gICAgICAgIC5nZXQoJy9hcGkvdjEvcGluZycpXG4gICAgICAgIC5tYXRjaEhlYWRlcignUmVxdWVzdC1JRCcsIC9eMTIzNDUkLylcbiAgICAgICAgLnJlcGx5KDIwMCwgeyBzdGF0dXM6ICdvaycgfSk7XG5cbiAgICAgIGF3YWl0IGJpdGdvLnBpbmcoe1xuICAgICAgICByZXFJZDoge1xuICAgICAgICAgIHRvU3RyaW5nOiAoKSA9PiAnMTIzNDUnLFxuICAgICAgICAgIGluYzogKCkgPT4ge1xuICAgICAgICAgICAgLyogbW9jayAqL1xuICAgICAgICAgIH0sXG4gICAgICAgIH0gYXMgYW55LFxuICAgICAgfSk7XG5cbiAgICAgIHNjb3BlLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGNvcnJlY3RseSBmb3JtYXQgUmVxdWVzdC1JRCB3aXRoIHByZWZpeCBhbmQgbnVtZXJpYyBzZXF1ZW5jZScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGJpdGdvID0gbmV3IEJpdEdvQVBJKHtcbiAgICAgICAgZW52OiAnY3VzdG9tJyxcbiAgICAgICAgY3VzdG9tUm9vdFVSSTogJ2h0dHBzOi8vYXBwLmV4YW1wbGUubG9jYWwnLFxuICAgICAgICByZXF1ZXN0SWRQcmVmaXg6ICdteWFwcC12MS0nLFxuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IHNjb3BlID0gbm9jaygnaHR0cHM6Ly9hcHAuZXhhbXBsZS5sb2NhbCcpXG4gICAgICAgIC5nZXQoJy9hcGkvdjEvcGluZycpXG4gICAgICAgIC5tYXRjaEhlYWRlcignUmVxdWVzdC1JRCcsICdteWFwcC12MS10cmFjZS0xMjMnKVxuICAgICAgICAucmVwbHkoMjAwLCB7IHN0YXR1czogJ29rJyB9KTtcblxuICAgICAgYXdhaXQgYml0Z28ucGluZyh7XG4gICAgICAgIHJlcUlkOiB7XG4gICAgICAgICAgdG9TdHJpbmc6ICgpID0+ICd0cmFjZS0xMjMnLFxuICAgICAgICAgIGluYzogKCkgPT4ge1xuICAgICAgICAgICAgLyogbW9jayAqL1xuICAgICAgICAgIH0sXG4gICAgICAgIH0gYXMgYW55LFxuICAgICAgfSk7XG5cbiAgICAgIHNjb3BlLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHdvcmsgd2l0aCBlbXB0eSBzdHJpbmcgcHJlZml4JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgYml0Z28gPSBuZXcgQml0R29BUEkoe1xuICAgICAgICBlbnY6ICdjdXN0b20nLFxuICAgICAgICBjdXN0b21Sb290VVJJOiAnaHR0cHM6Ly9hcHAuZXhhbXBsZS5sb2NhbCcsXG4gICAgICAgIHJlcXVlc3RJZFByZWZpeDogJycsXG4gICAgICB9KTtcblxuICAgICAgY29uc3Qgc2NvcGUgPSBub2NrKCdodHRwczovL2FwcC5leGFtcGxlLmxvY2FsJylcbiAgICAgICAgLmdldCgnL2FwaS92MS9waW5nJylcbiAgICAgICAgLm1hdGNoSGVhZGVyKCdSZXF1ZXN0LUlEJywgJ2FiYy0xMjMnKVxuICAgICAgICAucmVwbHkoMjAwLCB7IHN0YXR1czogJ29rJyB9KTtcblxuICAgICAgYXdhaXQgYml0Z28ucGluZyh7XG4gICAgICAgIHJlcUlkOiB7XG4gICAgICAgICAgdG9TdHJpbmc6ICgpID0+ICdhYmMtMTIzJyxcbiAgICAgICAgICBpbmM6ICgpID0+IHtcbiAgICAgICAgICAgIC8qIG1vY2sgKi9cbiAgICAgICAgICB9LFxuICAgICAgICB9IGFzIGFueSxcbiAgICAgIH0pO1xuXG4gICAgICBzY29wZS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgIH0pO1xuICB9KTtcbiAgZGVzY3JpYmUoJ2h0dHAgcHJveHkgYWdlbnQnLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ2h0dHAgcHJveHkgYWdlbnQgc2hhbGwgYmUgY3JlYXRlZCB3aGVuIHByb3h5KGN1c3RvbVByb3h5YWdlbnQpIGlzIHNldCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGN1c3RvbVByb3h5QWdlbnQgPSBuZXcgUHJveHlBZ2VudCh7XG4gICAgICAgIGdldFByb3h5Rm9yVXJsOiAoKSA9PiAnaHR0cDovL2xvY2FsaG9zdDozMDAwJyxcbiAgICAgIH0pO1xuICAgICAgY29uc3QgYml0Z28gPSBuZXcgQml0R29BUEkoe1xuICAgICAgICBlbnY6ICdjdXN0b20nLFxuICAgICAgICBjdXN0b21Sb290VVJJOiAnaHR0cHM6Ly9hcHAuZXhhbXBsZS5sb2NhbCcsXG4gICAgICAgIGN1c3RvbVByb3h5QWdlbnQsXG4gICAgICB9KTtcblxuICAgICAgYml0Z28uc2hvdWxkLmhhdmUucHJvcGVydHkoJ19jdXN0b21Qcm94eUFnZW50JywgY3VzdG9tUHJveHlBZ2VudCk7XG4gICAgfSk7XG5cbiAgICBpdCgnYml0Z28gYXBpIGlzIHN0aWxsIGluaXRpYXRlZCB3aGVuIHByb3h5KGN1c3RvbVByb3h5QWdlbnQpIGlzIG5vdCBzZXQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBiaXRnbyA9IG5ldyBCaXRHb0FQSSh7XG4gICAgICAgIGVudjogJ2N1c3RvbScsXG4gICAgICAgIGN1c3RvbVJvb3RVUkk6ICdodHRwczovL2FwcC5leGFtcGxlLmxvY2FsJyxcbiAgICAgIH0pO1xuXG4gICAgICBiaXRnby5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnX2N1c3RvbVByb3h5QWdlbnQnLCB1bmRlZmluZWQpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgndmVyaWZ5QWRkcmVzcycsIGZ1bmN0aW9uICgpIHtcbiAgICBpdCgnc2hvdWxkIHN1Y2Nlc3NmdWxseSB2ZXJpZnkgYSBiYXNlNTggYWRkcmVzcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGJpdGdvID0gbmV3IEJpdEdvQVBJKHtcbiAgICAgICAgZW52OiAndGVzdCcsXG4gICAgICB9KTtcblxuICAgICAgYml0Z28udmVyaWZ5QWRkcmVzcyh7IGFkZHJlc3M6ICcyTjZwYVQyVFU0TjFYcGFaakppQXBXSlhvZXlyTDNVV3BrWicgfSkuc2hvdWxkLmJlLnRydWUoKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgc3VjY2Vzc2Z1bGx5IHZlcmlmeSBhIGJlY2gzMiBhZGRyZXNzJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgYml0Z28gPSBuZXcgQml0R29BUEkoe1xuICAgICAgICBlbnY6ICd0ZXN0JyxcbiAgICAgIH0pO1xuXG4gICAgICBiaXRnb1xuICAgICAgICAudmVyaWZ5QWRkcmVzcyh7IGFkZHJlc3M6ICd0YjFxZ3V6eWs0dzZrYXF0cHNjenM1YWowdzhyNzU5OGpxMzZlZ204ZTk4d3FwaDNyd21leDY4c2VzbGdzZycgfSlcbiAgICAgICAgLnNob3VsZC5iZS50cnVlKCk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCd1cmwnLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCByZXR1cm4gdGhlIGNvcnJlY3QgVVJMIGZvciB2ZXJzaW9uIDEnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBiaXRnbyA9IG5ldyBCaXRHb0FQSSh7XG4gICAgICAgIGVudjogJ3Rlc3QnLFxuICAgICAgICBjdXN0b21Sb290VVJJOiAnaHR0cHM6Ly90ZXN0LmJpdGdvLmNvbScsXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHBhdGggPSAnL3Rlc3QtcGF0aCc7XG4gICAgICBjb25zdCBleHBlY3RlZFVybCA9ICdodHRwczovL3Rlc3QuYml0Z28uY29tL2FwaS92MS90ZXN0LXBhdGgnO1xuICAgICAgY29uc3QgcmVzdWx0ID0gYml0Z28udXJsKHBhdGgsIDEpO1xuICAgICAgcmVzdWx0LnNob3VsZC5lcXVhbChleHBlY3RlZFVybCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJldHVybiB0aGUgY29ycmVjdCBVUkwgZm9yIHZlcnNpb24gMicsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGJpdGdvID0gbmV3IEJpdEdvQVBJKHtcbiAgICAgICAgZW52OiAndGVzdCcsXG4gICAgICAgIGN1c3RvbVJvb3RVUkk6ICdodHRwczovL3Rlc3QuYml0Z28uY29tJyxcbiAgICAgIH0pO1xuICAgICAgY29uc3QgcGF0aCA9ICcvdGVzdC1wYXRoJztcbiAgICAgIGNvbnN0IGV4cGVjdGVkVXJsID0gJ2h0dHBzOi8vdGVzdC5iaXRnby5jb20vYXBpL3YyL3Rlc3QtcGF0aCc7XG4gICAgICBjb25zdCByZXN1bHQgPSBiaXRnby51cmwocGF0aCwgMik7XG4gICAgICByZXN1bHQuc2hvdWxkLmVxdWFsKGV4cGVjdGVkVXJsKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgcmV0dXJuIHRoZSBjb3JyZWN0IFVSTCBmb3IgdmVyc2lvbiAzJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgYml0Z28gPSBuZXcgQml0R29BUEkoe1xuICAgICAgICBlbnY6ICd0ZXN0JyxcbiAgICAgICAgY3VzdG9tUm9vdFVSSTogJ2h0dHBzOi8vdGVzdC5iaXRnby5jb20nLFxuICAgICAgfSk7XG4gICAgICBjb25zdCBwYXRoID0gJy90ZXN0LXBhdGgnO1xuICAgICAgY29uc3QgZXhwZWN0ZWRVcmwgPSAnaHR0cHM6Ly90ZXN0LmJpdGdvLmNvbS9hcGkvdjMvdGVzdC1wYXRoJztcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGJpdGdvLnVybChwYXRoLCAzKTtcbiAgICAgIHJlc3VsdC5zaG91bGQuZXF1YWwoZXhwZWN0ZWRVcmwpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBkZWZhdWx0IHRvIHZlcnNpb24gMSBpZiBubyB2ZXJzaW9uIGlzIHByb3ZpZGVkJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgYml0Z28gPSBuZXcgQml0R29BUEkoe1xuICAgICAgICBlbnY6ICd0ZXN0JyxcbiAgICAgICAgY3VzdG9tUm9vdFVSSTogJ2h0dHBzOi8vdGVzdC5iaXRnby5jb20nLFxuICAgICAgfSk7XG4gICAgICBjb25zdCBwYXRoID0gJy90ZXN0LXBhdGgnO1xuICAgICAgY29uc3QgZXhwZWN0ZWRVcmwgPSAnaHR0cHM6Ly90ZXN0LmJpdGdvLmNvbS9hcGkvdjEvdGVzdC1wYXRoJztcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGJpdGdvLnVybChwYXRoKTtcbiAgICAgIHJlc3VsdC5zaG91bGQuZXF1YWwoZXhwZWN0ZWRVcmwpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnZGVjcnlwdEtleXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgbGV0IGJpdGdvOiBCaXRHb0FQSTtcblxuICAgIGJlZm9yZUVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgYml0Z28gPSBuZXcgQml0R29BUEkoeyBlbnY6ICd0ZXN0JyB9KTtcbiAgICB9KTtcblxuICAgIGFmdGVyRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICBzaW5vbi5yZXN0b3JlKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IGlmIG5vIHBhcmFtcyBhcmUgcHJvdmlkZWQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAvLyBAdHMtZXhwZWN0LWVycm9yIC0gaW50ZW50aW9uYWxseSBjYWxsaW5nIHdpdGggbm8gcGFyYW1zIGZvciB0ZXN0XG4gICAgICBhd2FpdCBiaXRnby5kZWNyeXB0S2V5cygpLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ01pc3NpbmcgcGFyYW1ldGVyOiB3YWxsZXRJZEVuY3J5cHRlZEtleVBhaXJzJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IGlmIHdhbGxldElkRW5jcnlwdGVkS2V5UGFpcnMgaXMgbWlzc2luZycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGJpdGdvXG4gICAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3IgLSBpbnRlbnRpb25hbGx5IG1pc3NpbmcgcmVxdWlyZWQgcGFyYW1cbiAgICAgICAgLmRlY3J5cHRLZXlzKHsgcGFzc3dvcmQ6ICdwYXNzd29yZDEyMycgfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ01pc3NpbmcgcGFyYW1ldGVyOiB3YWxsZXRJZEVuY3J5cHRlZEtleVBhaXJzJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IGlmIHBhc3N3b3JkIGlzIG1pc3NpbmcnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAvLyBAdHMtZXhwZWN0LWVycm9yIC0gaW50ZW50aW9uYWxseSBtaXNzaW5nIHJlcXVpcmVkIHBhcmFtXG4gICAgICBhd2FpdCBiaXRnby5kZWNyeXB0S2V5cyh7IHdhbGxldElkRW5jcnlwdGVkS2V5UGFpcnM6IFtdIH0pLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ01pc3NpbmcgcGFyYW1ldGVyOiBwYXNzd29yZCcpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBpZiB3YWxsZXRJZEVuY3J5cHRlZEtleVBhaXJzIGlzIG5vdCBhbiBhcnJheScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGJpdGdvXG4gICAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3IgLSBpbnRlbnRpb25hbGx5IHByb3ZpZGluZyB3cm9uZyB0eXBlXG4gICAgICAgIC5kZWNyeXB0S2V5cyh7IHdhbGxldElkRW5jcnlwdGVkS2V5UGFpcnM6ICdub3QgYW4gYXJyYXknLCBwYXNzd29yZDogJ3Bhc3N3b3JkMTIzJyB9KVxuICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgnd2FsbGV0SWRFbmNyeXB0ZWRLZXlQYWlycyBtdXN0IGJlIGFuIGFycmF5Jyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJldHVybiBlbXB0eSBhcnJheSBmb3IgZW1wdHkgd2FsbGV0SWRFbmNyeXB0ZWRLZXlQYWlycycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGJpdGdvLmRlY3J5cHRLZXlzKHsgd2FsbGV0SWRFbmNyeXB0ZWRLZXlQYWlyczogW10sIHBhc3N3b3JkOiAncGFzc3dvcmQxMjMnIH0pO1xuICAgICAgcmVzdWx0LnNob3VsZC5iZS5hbi5BcnJheSgpO1xuICAgICAgcmVzdWx0LnNob3VsZC5iZS5lbXB0eSgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBpZiBhbnkgd2FsbGV0SWQgaXMgbWlzc2luZyBvciBub3QgYSBzdHJpbmcnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBhd2FpdCBiaXRnb1xuICAgICAgICAuZGVjcnlwdEtleXMoe1xuICAgICAgICAgIHdhbGxldElkRW5jcnlwdGVkS2V5UGFpcnM6IFtcbiAgICAgICAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3IgLSBpbnRlbnRpb25hbGx5IG1pc3Npbmcgd2FsbGV0SWRcbiAgICAgICAgICAgIHsgZW5jcnlwdGVkUHJ2OiAnZW5jcnlwdGVkLWRhdGEnIH0sXG4gICAgICAgICAgXSxcbiAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3b3JkMTIzJyxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ2VhY2gga2V5IHBhaXIgbXVzdCBoYXZlIGEgc3RyaW5nIHdhbGxldElkJyk7XG5cbiAgICAgIGF3YWl0IGJpdGdvXG4gICAgICAgIC5kZWNyeXB0S2V5cyh7XG4gICAgICAgICAgd2FsbGV0SWRFbmNyeXB0ZWRLZXlQYWlyczogW1xuICAgICAgICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvciAtIGludGVudGlvbmFsbHkgcHJvdmlkaW5nIHdyb25nIHR5cGVcbiAgICAgICAgICAgIHsgd2FsbGV0SWQ6IDEyMywgZW5jcnlwdGVkUHJ2OiAnZW5jcnlwdGVkLWRhdGEnIH0sXG4gICAgICAgICAgXSxcbiAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3b3JkMTIzJyxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ2VhY2gga2V5IHBhaXIgbXVzdCBoYXZlIGEgc3RyaW5nIHdhbGxldElkJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IGlmIGFueSBlbmNyeXB0ZWRQcnYgaXMgbWlzc2luZyBvciBub3QgYSBzdHJpbmcnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBhd2FpdCBiaXRnb1xuICAgICAgICAuZGVjcnlwdEtleXMoe1xuICAgICAgICAgIHdhbGxldElkRW5jcnlwdGVkS2V5UGFpcnM6IFtcbiAgICAgICAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3IgLSBpbnRlbnRpb25hbGx5IG1pc3NpbmcgZW5jcnlwdGVkUHJ2XG4gICAgICAgICAgICB7IHdhbGxldElkOiAnd2FsbGV0LWlkLTEnIH0sXG4gICAgICAgICAgXSxcbiAgICAgICAgICBwYXNzd29yZDogJ3Bhc3N3b3JkMTIzJyxcbiAgICAgICAgfSlcbiAgICAgICAgLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoJ2VhY2gga2V5IHBhaXIgbXVzdCBoYXZlIGEgc3RyaW5nIGVuY3J5cHRlZFBydicpO1xuXG4gICAgICBhd2FpdCBiaXRnb1xuICAgICAgICAuZGVjcnlwdEtleXMoe1xuICAgICAgICAgIHdhbGxldElkRW5jcnlwdGVkS2V5UGFpcnM6IFtcbiAgICAgICAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3IgLSBpbnRlbnRpb25hbGx5IHByb3ZpZGluZyB3cm9uZyB0eXBlXG4gICAgICAgICAgICB7IHdhbGxldElkOiAnd2FsbGV0LWlkLTEnLCBlbmNyeXB0ZWRQcnY6IDEyMyB9LFxuICAgICAgICAgIF0sXG4gICAgICAgICAgcGFzc3dvcmQ6ICdwYXNzd29yZDEyMycsXG4gICAgICAgIH0pXG4gICAgICAgIC5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKCdlYWNoIGtleSBwYWlyIG11c3QgaGF2ZSBhIHN0cmluZyBlbmNyeXB0ZWRQcnYnKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ2RlY3J5cHRLZXlzJywgZnVuY3Rpb24gKCkge1xuICAgIGxldCBiaXRnbzogQml0R29BUEk7XG5cbiAgICBiZWZvcmVFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgIGJpdGdvID0gbmV3IEJpdEdvQVBJKHsgZW52OiAndGVzdCcgfSk7XG4gICAgfSk7XG5cbiAgICBhZnRlckVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgc2lub24ucmVzdG9yZSgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCByZXR1cm4gd2FsbGV0SWRzIG9mIGtleXMgdGhhdCBmYWlsZWQgdG8gZGVjcnlwdCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGRlY3J5cHRBc3luY1N0dWIgPSBzaW5vbi5zdHViKGJpdGdvLCAnZGVjcnlwdCcpO1xuICAgICAgZGVjcnlwdEFzeW5jU3R1Yi5vbkZpcnN0Q2FsbCgpLnJlc29sdmVzKCdkZWNyeXB0ZWQta2V5LTEnKTtcbiAgICAgIGRlY3J5cHRBc3luY1N0dWIub25TZWNvbmRDYWxsKCkucmVqZWN0cyhuZXcgRXJyb3IoJ2RlY3J5cHRpb24gZmFpbGVkJykpO1xuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBiaXRnby5kZWNyeXB0S2V5cyh7XG4gICAgICAgIHdhbGxldElkRW5jcnlwdGVkS2V5UGFpcnM6IFtcbiAgICAgICAgICB7IHdhbGxldElkOiAnd2FsbGV0LWlkLTEnLCBlbmNyeXB0ZWRQcnY6ICdlbmNyeXB0ZWQtZGF0YS0xJyB9LFxuICAgICAgICAgIHsgd2FsbGV0SWQ6ICd3YWxsZXQtaWQtMicsIGVuY3J5cHRlZFBydjogJ2VuY3J5cHRlZC1kYXRhLTInIH0sXG4gICAgICAgIF0sXG4gICAgICAgIHBhc3N3b3JkOiAncGFzc3dvcmQxMjMnLFxuICAgICAgfSk7XG5cbiAgICAgIHJlc3VsdC5zaG91bGQuYmUuYW4uQXJyYXkoKTtcbiAgICAgIHJlc3VsdC5zaG91bGQuaGF2ZS5sZW5ndGgoMSk7XG4gICAgICByZXN1bHRbMF0uc2hvdWxkLmVxdWFsKCd3YWxsZXQtaWQtMicpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBjb3JyZWN0bHkgcHJvY2VzcyBtdWx0aXBsZSB3YWxsZXQga2V5cycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGRlY3J5cHRBc3luY1N0dWIgPSBzaW5vbi5zdHViKGJpdGdvLCAnZGVjcnlwdCcpO1xuICAgICAgZGVjcnlwdEFzeW5jU3R1YlxuICAgICAgICAud2l0aEFyZ3MoeyBpbnB1dDogJ2VuY3J5cHRlZC1kYXRhLTInLCBwYXNzd29yZDogJ3Bhc3N3b3JkMTIzJyB9KVxuICAgICAgICAucmVqZWN0cyhuZXcgRXJyb3IoJ2RlY3J5cHRpb24gZmFpbGVkJykpO1xuICAgICAgZGVjcnlwdEFzeW5jU3R1YlxuICAgICAgICAud2l0aEFyZ3MoeyBpbnB1dDogJ2VuY3J5cHRlZC1kYXRhLTQnLCBwYXNzd29yZDogJ3Bhc3N3b3JkMTIzJyB9KVxuICAgICAgICAucmVqZWN0cyhuZXcgRXJyb3IoJ2RlY3J5cHRpb24gZmFpbGVkJykpO1xuICAgICAgZGVjcnlwdEFzeW5jU3R1Yi5yZXNvbHZlcygnc3VjY2VzcycpO1xuXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBiaXRnby5kZWNyeXB0S2V5cyh7XG4gICAgICAgIHdhbGxldElkRW5jcnlwdGVkS2V5UGFpcnM6IFtcbiAgICAgICAgICB7IHdhbGxldElkOiAnd2FsbGV0LWlkLTEnLCBlbmNyeXB0ZWRQcnY6ICdlbmNyeXB0ZWQtZGF0YS0xJyB9LFxuICAgICAgICAgIHsgd2FsbGV0SWQ6ICd3YWxsZXQtaWQtMicsIGVuY3J5cHRlZFBydjogJ2VuY3J5cHRlZC1kYXRhLTInIH0sXG4gICAgICAgICAgeyB3YWxsZXRJZDogJ3dhbGxldC1pZC0zJywgZW5jcnlwdGVkUHJ2OiAnZW5jcnlwdGVkLWRhdGEtMycgfSxcbiAgICAgICAgICB7IHdhbGxldElkOiAnd2FsbGV0LWlkLTQnLCBlbmNyeXB0ZWRQcnY6ICdlbmNyeXB0ZWQtZGF0YS00JyB9LFxuICAgICAgICBdLFxuICAgICAgICBwYXNzd29yZDogJ3Bhc3N3b3JkMTIzJyxcbiAgICAgIH0pO1xuXG4gICAgICBkZWNyeXB0QXN5bmNTdHViLmNhbGxDb3VudC5zaG91bGQuZXF1YWwoNCk7XG4gICAgICByZXN1bHQuc2hvdWxkLmJlLmFuLkFycmF5KCk7XG4gICAgICByZXN1bHQuc2hvdWxkLmhhdmUubGVuZ3RoKDIpO1xuICAgICAgcmVzdWx0LnNob3VsZC5jb250YWluRGVlcChbJ3dhbGxldC1pZC0yJywgJ3dhbGxldC1pZC00J10pO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnVXNlci1BZ2VudCBoZWFkZXIgYmFzZWQgb24gZW52aXJvbm1lbnQnLCBmdW5jdGlvbiAoKSB7XG4gICAgYWZ0ZXJFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgIG5vY2suY2xlYW5BbGwoKTtcbiAgICAgIHNpbm9uLnJlc3RvcmUoKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgc2V0IFVzZXItQWdlbnQgaGVhZGVyIHdoZW4gcnVubmluZyBpbiBOb2RlLmpzICh0eXBlb2Ygd2luZG93ID09PSB1bmRlZmluZWQpJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgYml0Z28gPSBuZXcgQml0R29BUEkoe1xuICAgICAgICBlbnY6ICdjdXN0b20nLFxuICAgICAgICBjdXN0b21Sb290VVJJOiAnaHR0cHM6Ly9hcHAuZXhhbXBsZS5sb2NhbCcsXG4gICAgICAgIHVzZXJBZ2VudDogJ1Rlc3RBZ2VudC8xLjAnLFxuICAgICAgfSk7XG5cbiAgICAgIC8vIEVuc3VyZSB3ZSdyZSBpbiBhIE5vZGUuanMgZW52aXJvbm1lbnQgYnkgdmVyaWZ5aW5nIHdpbmRvdyBpcyB1bmRlZmluZWRcbiAgICAgICh0eXBlb2Ygd2luZG93KS5zaG91bGQuZXF1YWwoJ3VuZGVmaW5lZCcpO1xuXG4gICAgICBjb25zdCBzY29wZSA9IG5vY2soJ2h0dHBzOi8vYXBwLmV4YW1wbGUubG9jYWwnKVxuICAgICAgICAuZ2V0KCcvYXBpL3YxL3BpbmcnKVxuICAgICAgICAubWF0Y2hIZWFkZXIoJ1VzZXItQWdlbnQnLCAnVGVzdEFnZW50LzEuMCcpXG4gICAgICAgIC5yZXBseSgyMDAsIHsgc3RhdHVzOiAnb2snIH0pO1xuXG4gICAgICBhd2FpdCBiaXRnby5waW5nKHtcbiAgICAgICAgcmVxSWQ6IHtcbiAgICAgICAgICB0b1N0cmluZzogKCkgPT4gJ3Rlc3QtMTIzJyxcbiAgICAgICAgICBpbmM6ICgpID0+IHtcbiAgICAgICAgICAgIC8qIG1vY2sgKi9cbiAgICAgICAgICB9LFxuICAgICAgICB9IGFzIGFueSxcbiAgICAgIH0pO1xuXG4gICAgICBzY29wZS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBub3Qgc2V0IFVzZXItQWdlbnQgaGVhZGVyIHdoZW4gcnVubmluZyBpbiBicm93c2VyICh0eXBlb2Ygd2luZG93ICE9PSB1bmRlZmluZWQpJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gTW9jayB0aGUgd2luZG93IG9iamVjdCB0byBzaW11bGF0ZSBicm93c2VyIGVudmlyb25tZW50XG4gICAgICBjb25zdCB3aW5kb3dTdHViID0geyBsb2NhdGlvbjogJ21vY2snIH07XG4gICAgICAoZ2xvYmFsIGFzIGFueSkud2luZG93ID0gd2luZG93U3R1YjtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgYml0Z28gPSBuZXcgQml0R29BUEkoe1xuICAgICAgICAgIGVudjogJ2N1c3RvbScsXG4gICAgICAgICAgY3VzdG9tUm9vdFVSSTogJ2h0dHBzOi8vYXBwLmV4YW1wbGUubG9jYWwnLFxuICAgICAgICAgIHVzZXJBZ2VudDogJ1Rlc3RBZ2VudC8xLjAnLFxuICAgICAgICB9KTtcblxuICAgICAgICBjb25zdCBzY29wZSA9IG5vY2soJ2h0dHBzOi8vYXBwLmV4YW1wbGUubG9jYWwnKVxuICAgICAgICAgIC5nZXQoJy9hcGkvdjEvcGluZycpXG4gICAgICAgICAgLnJlcGx5KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIC8vIFZlcmlmeSBVc2VyLUFnZW50IGhlYWRlciBpcyBOT1Qgc2V0IHRvIG91ciBjdXN0b20gdmFsdWVcbiAgICAgICAgICAgIGNvbnN0IHVzZXJBZ2VudCA9IHRoaXMucmVxLmhlYWRlcnNbJ3VzZXItYWdlbnQnXTtcbiAgICAgICAgICAgIGlmICh1c2VyQWdlbnQgJiYgdXNlckFnZW50LmluY2x1ZGVzKCdUZXN0QWdlbnQvMS4wJykpIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdVc2VyLUFnZW50IHNob3VsZCBub3QgYmUgc2V0IGluIGJyb3dzZXIgZW52aXJvbm1lbnQnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBbMjAwLCB7IHN0YXR1czogJ29rJyB9XTtcbiAgICAgICAgICB9KTtcblxuICAgICAgICBhd2FpdCBiaXRnby5waW5nKHtcbiAgICAgICAgICByZXFJZDoge1xuICAgICAgICAgICAgdG9TdHJpbmc6ICgpID0+ICd0ZXN0LTEyMycsXG4gICAgICAgICAgICBpbmM6ICgpID0+IHtcbiAgICAgICAgICAgICAgLyogbW9jayAqL1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9IGFzIGFueSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgc2NvcGUuaXNEb25lKCkuc2hvdWxkLmJlLnRydWUoKTtcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIC8vIENsZWFuIHVwIHRoZSBnbG9iYWwgd2luZG93IG1vY2tcbiAgICAgICAgZGVsZXRlIChnbG9iYWwgYXMgYW55KS53aW5kb3c7XG4gICAgICB9XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdobWFjQXV0aFN0cmF0ZWd5IHRva2VuIGxpZmVjeWNsZScsIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCBST09UID0gJ2h0dHBzOi8vYXBwLmV4YW1wbGUubG9jYWwnO1xuXG4gICAgLy8gQnVpbGRzIGEgbW9jayBzdHJhdGVneSB3aG9zZSBzZXRUb2tlbiAvIGNsZWFyVG9rZW4gYXJlIHNpbm9uIHN0dWJzLlxuICAgIGZ1bmN0aW9uIG1ha2VTdHJhdGVneShvdmVycmlkZXM6IFBhcnRpYWw8SUhtYWNBdXRoU3RyYXRlZ3k+ID0ge30pOiB7XG4gICAgICBzdHJhdGVneTogSUhtYWNBdXRoU3RyYXRlZ3k7XG4gICAgICBzZXRUb2tlblN0dWI6IHNpbm9uLlNpbm9uU3R1YjtcbiAgICAgIGNsZWFyVG9rZW5TdHViOiBzaW5vbi5TaW5vblN0dWI7XG4gICAgfSB7XG4gICAgICBjb25zdCBzZXRUb2tlblN0dWIgPSBzaW5vbi5zdHViKCkucmVzb2x2ZXMoKTtcbiAgICAgIGNvbnN0IGNsZWFyVG9rZW5TdHViID0gc2lub24uc3R1YigpLnJlc29sdmVzKCk7XG4gICAgICBjb25zdCBzdHJhdGVneTogSUhtYWNBdXRoU3RyYXRlZ3kgPSB7XG4gICAgICAgIGNhbGN1bGF0ZVJlcXVlc3RIZWFkZXJzOiBzaW5vbi5zdHViKCkucmVzb2x2ZXMoeyBobWFjOiAnaG1hYycsIHRpbWVzdGFtcDogMSwgdG9rZW5IYXNoOiAnaGFzaCcgfSksXG4gICAgICAgIHZlcmlmeVJlc3BvbnNlOiBzaW5vbi5zdHViKCkucmVzb2x2ZXMoe1xuICAgICAgICAgIGlzVmFsaWQ6IHRydWUsXG4gICAgICAgICAgZXhwZWN0ZWRIbWFjOiAnaG1hYycsXG4gICAgICAgICAgc2lnbmF0dXJlU3ViamVjdDogJycsXG4gICAgICAgICAgaXNJblJlc3BvbnNlVmFsaWRpdHlXaW5kb3c6IHRydWUsXG4gICAgICAgICAgdmVyaWZpY2F0aW9uVGltZTogRGF0ZS5ub3coKSxcbiAgICAgICAgfSksXG4gICAgICAgIGNhbGN1bGF0ZUhNQUM6IHNpbm9uLnN0dWIoKS5yZXNvbHZlcygnaGFzaGVkLXB3JyksXG4gICAgICAgIHNldFRva2VuOiBzZXRUb2tlblN0dWIsXG4gICAgICAgIGNsZWFyVG9rZW46IGNsZWFyVG9rZW5TdHViLFxuICAgICAgICAuLi5vdmVycmlkZXMsXG4gICAgICB9O1xuICAgICAgcmV0dXJuIHsgc3RyYXRlZ3ksIHNldFRva2VuU3R1YiwgY2xlYXJUb2tlblN0dWIgfTtcbiAgICB9XG5cbiAgICBhZnRlckVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgbm9jay5jbGVhbkFsbCgpO1xuICAgICAgc2lub24ucmVzdG9yZSgpO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoJ2F1dGhlbnRpY2F0ZSgpJywgZnVuY3Rpb24gKCkge1xuICAgICAgaXQoJ2NhbGxzIHNldFRva2VuIHdpdGggdGhlIGFjY2Vzc190b2tlbiByZWNlaXZlZCBmcm9tIHRoZSBzZXJ2ZXInLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IHsgc3RyYXRlZ3ksIHNldFRva2VuU3R1YiB9ID0gbWFrZVN0cmF0ZWd5KCk7XG4gICAgICAgIGNvbnN0IGJpdGdvID0gbmV3IEJpdEdvQVBJKHsgZW52OiAnY3VzdG9tJywgY3VzdG9tUm9vdFVSSTogUk9PVCwgaG1hY0F1dGhTdHJhdGVneTogc3RyYXRlZ3kgfSk7XG5cbiAgICAgICAgbm9jayhST09UKVxuICAgICAgICAgIC5wb3N0KCcvYXBpL2F1dGgvdjEvc2Vzc2lvbicpXG4gICAgICAgICAgLnJlcGx5KDIwMCwge1xuICAgICAgICAgICAgdXNlcjogeyB1c2VybmFtZTogJ3Rlc3RAZXhhbXBsZS5jb20nIH0sXG4gICAgICAgICAgICBhY2Nlc3NfdG9rZW46ICd2MnhteWFjY2Vzc3Rva2VuJyxcbiAgICAgICAgICB9KTtcblxuICAgICAgICBhd2FpdCBiaXRnby5hdXRoZW50aWNhdGUoeyB1c2VybmFtZTogJ3Rlc3RAZXhhbXBsZS5jb20nLCBwYXNzd29yZDogJ2h1bnRlcjInIH0pO1xuXG4gICAgICAgIHNldFRva2VuU3R1Yi5jYWxsZWRPbmNlLnNob3VsZC5iZS50cnVlKCk7XG4gICAgICAgIHNldFRva2VuU3R1Yi5maXJzdENhbGwuYXJnc1swXS5zaG91bGQuZXF1YWwoJ3YyeG15YWNjZXNzdG9rZW4nKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnYXdhaXRzIHNldFRva2VuIGJlZm9yZSBtYWtpbmcgZW5zdXJlRWNkaEtleWNoYWluIHJlcXVlc3RzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyBUaGlzIGlzIHRoZSBjb3JlIHJlZ3Jlc3Npb24gdGVzdDogaWYgc2V0VG9rZW4gaXMgbm90IGF3YWl0ZWQsIHRoZVxuICAgICAgICAvLyBzdHJhdGVneSdzIGtleSBtYXRlcmlhbCB3b24ndCBiZSByZWFkeSBiZWZvcmUgY2FsY3VsYXRlUmVxdWVzdEhlYWRlcnNcbiAgICAgICAgLy8gaXMgY2FsbGVkIGZvciB0aGUgR0VUIC91c2VyL3NldHRpbmdzIHJlcXVlc3QsIGFuZCBpdCB3b3VsZCB0aHJvdy5cbiAgICAgICAgbGV0IGtleVJlYWR5ID0gZmFsc2U7XG4gICAgICAgIGNvbnN0IHsgc3RyYXRlZ3kgfSA9IG1ha2VTdHJhdGVneSh7XG4gICAgICAgICAgc2V0VG9rZW46IHNpbm9uLnN0dWIoKS5jYWxsc0Zha2UoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgLy8gU2ltdWxhdGUgbm9uLXRyaXZpYWwgYXN5bmMga2V5IGRlcml2YXRpb24gKGxpa2UgY3J5cHRvLnN1YnRsZS5pbXBvcnRLZXkpLlxuICAgICAgICAgICAgYXdhaXQgbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUpID0+IHNldEltbWVkaWF0ZShyZXNvbHZlKSk7XG4gICAgICAgICAgICBrZXlSZWFkeSA9IHRydWU7XG4gICAgICAgICAgfSksXG4gICAgICAgICAgY2FsY3VsYXRlUmVxdWVzdEhlYWRlcnM6IHNpbm9uLnN0dWIoKS5jYWxsc0Zha2UoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgaWYgKCFrZXlSZWFkeSkge1xuICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIHRva2VuIGF2YWlsYWJsZS4gQ2FsbCBzZXRUb2tlbigpIG9yIHJlc3RvcmVUb2tlbigpIGZpcnN0LicpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHsgaG1hYzogJ2htYWMnLCB0aW1lc3RhbXA6IERhdGUubm93KCksIHRva2VuSGFzaDogJ2hhc2gnIH07XG4gICAgICAgICAgfSksXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBiaXRnbyA9IG5ldyBCaXRHb0FQSSh7IGVudjogJ2N1c3RvbScsIGN1c3RvbVJvb3RVUkk6IFJPT1QsIGhtYWNBdXRoU3RyYXRlZ3k6IHN0cmF0ZWd5IH0pO1xuXG4gICAgICAgIG5vY2soUk9PVClcbiAgICAgICAgICAucG9zdCgnL2FwaS9hdXRoL3YxL3Nlc3Npb24nKVxuICAgICAgICAgIC5yZXBseSgyMDAsIHtcbiAgICAgICAgICAgIHVzZXI6IHsgdXNlcm5hbWU6ICd0ZXN0QGV4YW1wbGUuY29tJyB9LFxuICAgICAgICAgICAgYWNjZXNzX3Rva2VuOiAndjJ4bXl0b2tlbicsXG4gICAgICAgICAgfSk7XG4gICAgICAgIC8vIFRoZSBHRVQgL3VzZXIvc2V0dGluZ3MgcmVxdWVzdCBtYWRlIGJ5IGVuc3VyZVVzZXJFY2RoS2V5Y2hhaW5Jc0NyZWF0ZWRcbiAgICAgICAgLy8gbXVzdCBzdWNjZWVkIOKAlCBpdCB3b3VsZCB0aHJvdyBpZiBzZXRUb2tlbiB3YXNuJ3QgYXdhaXRlZCBmaXJzdC5cbiAgICAgICAgbm9jayhST09UKVxuICAgICAgICAgIC5nZXQoJy9hcGkvdjEvdXNlci9zZXR0aW5ncycpXG4gICAgICAgICAgLnJlcGx5KDIwMCwge1xuICAgICAgICAgICAgc2V0dGluZ3M6IHsgZWNkaEtleWNoYWluOiAneHB1YjEyMycgfSxcbiAgICAgICAgICB9KTtcblxuICAgICAgICBhd2FpdCBiaXRnby5hdXRoZW50aWNhdGUoe1xuICAgICAgICAgIHVzZXJuYW1lOiAndGVzdEBleGFtcGxlLmNvbScsXG4gICAgICAgICAgcGFzc3dvcmQ6ICdodW50ZXIyJyxcbiAgICAgICAgICBlbnN1cmVFY2RoS2V5Y2hhaW46IHRydWUsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGtleVJlYWR5LnNob3VsZC5iZS50cnVlKCk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKCdhdXRoZW50aWNhdGVXaXRoUGFzc2tleSgpJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdmFsaWRQYXNza2V5ID0gSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICBpZDogJ2NyZWRlbnRpYWwtaWQnLFxuICAgICAgICByYXdJZDogJ3Jhdy1pZCcsXG4gICAgICAgIHR5cGU6ICdwdWJsaWMta2V5JyxcbiAgICAgICAgcmVzcG9uc2U6IHtcbiAgICAgICAgICBhdXRoZW50aWNhdG9yRGF0YTogJ2F1dGgtZGF0YScsXG4gICAgICAgICAgY2xpZW50RGF0YUpTT046ICdjbGllbnQtZGF0YScsXG4gICAgICAgICAgc2lnbmF0dXJlOiAnc2lnJyxcbiAgICAgICAgICB1c2VySGFuZGxlOiAndXNlci1oYW5kbGUtMTIzJyxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnY2FsbHMgc2V0VG9rZW4gd2l0aCB0aGUgYWNjZXNzX3Rva2VuIHJlY2VpdmVkIGZyb20gdGhlIHNlcnZlcicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgeyBzdHJhdGVneSwgc2V0VG9rZW5TdHViIH0gPSBtYWtlU3RyYXRlZ3koKTtcbiAgICAgICAgY29uc3QgYml0Z28gPSBuZXcgQml0R29BUEkoeyBlbnY6ICdjdXN0b20nLCBjdXN0b21Sb290VVJJOiBST09ULCBobWFjQXV0aFN0cmF0ZWd5OiBzdHJhdGVneSB9KTtcblxuICAgICAgICBub2NrKFJPT1QpXG4gICAgICAgICAgLnBvc3QoJy9hcGkvYXV0aC92MS9zZXNzaW9uJylcbiAgICAgICAgICAucmVwbHkoMjAwLCB7XG4gICAgICAgICAgICB1c2VyOiB7IHVzZXJuYW1lOiAndGVzdEBleGFtcGxlLmNvbScgfSxcbiAgICAgICAgICAgIGFjY2Vzc190b2tlbjogJ3YyeHBhc3NrZXl0b2tlbicsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgYXdhaXQgYml0Z28uYXV0aGVudGljYXRlV2l0aFBhc3NrZXkodmFsaWRQYXNza2V5KTtcblxuICAgICAgICBzZXRUb2tlblN0dWIuY2FsbGVkT25jZS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgICAgICBzZXRUb2tlblN0dWIuZmlyc3RDYWxsLmFyZ3NbMF0uc2hvdWxkLmVxdWFsKCd2MnhwYXNza2V5dG9rZW4nKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoJ2NsZWFyQXN5bmMoKScsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGl0KCdjbGVhcnMgX3Rva2VuIGFuZCBjYWxscyBjbGVhclRva2VuIG9uIHRoZSBzdHJhdGVneScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgeyBzdHJhdGVneSwgY2xlYXJUb2tlblN0dWIgfSA9IG1ha2VTdHJhdGVneSgpO1xuICAgICAgICBjb25zdCBiaXRnbyA9IG5ldyBCaXRHb0FQSSh7IGVudjogJ2N1c3RvbScsIGN1c3RvbVJvb3RVUkk6IFJPT1QsIGhtYWNBdXRoU3RyYXRlZ3k6IHN0cmF0ZWd5IH0pO1xuXG4gICAgICAgIGJpdGdvLmF1dGhlbnRpY2F0ZVdpdGhBY2Nlc3NUb2tlbih7IGFjY2Vzc1Rva2VuOiAndjJ4c29tZXRva2VuJyB9KTtcbiAgICAgICAgKGJpdGdvIGFzIGFueSkuX3Rva2VuLnNob3VsZC5lcXVhbCgndjJ4c29tZXRva2VuJyk7XG5cbiAgICAgICAgYXdhaXQgYml0Z28uY2xlYXJBc3luYygpO1xuXG4gICAgICAgICgoYml0Z28gYXMgYW55KS5fdG9rZW4gPT09IHVuZGVmaW5lZCkuc2hvdWxkLmJlLnRydWUoKTtcbiAgICAgICAgY2xlYXJUb2tlblN0dWIuY2FsbGVkT25jZS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZSgncmVmcmVzaFRva2VuKCknLCBmdW5jdGlvbiAoKSB7XG4gICAgICBpdCgnY2FsbHMgc2V0VG9rZW4gd2l0aCB0aGUgbmV3IGFjY2Vzc190b2tlbiBmcm9tIHRoZSBPQXV0aCByZXNwb25zZScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgeyBzdHJhdGVneSwgc2V0VG9rZW5TdHViIH0gPSBtYWtlU3RyYXRlZ3koKTtcbiAgICAgICAgY29uc3QgYml0Z28gPSBuZXcgQml0R29BUEkoe1xuICAgICAgICAgIGVudjogJ2N1c3RvbScsXG4gICAgICAgICAgY3VzdG9tUm9vdFVSSTogUk9PVCxcbiAgICAgICAgICBobWFjQXV0aFN0cmF0ZWd5OiBzdHJhdGVneSxcbiAgICAgICAgICBjbGllbnRJZDogJ2NsaWVudC1pZCcsXG4gICAgICAgICAgY2xpZW50U2VjcmV0OiAnY2xpZW50LXNlY3JldCcsXG4gICAgICAgIH0pO1xuICAgICAgICAoYml0Z28gYXMgYW55KS5fcmVmcmVzaFRva2VuID0gJ29sZC1yZWZyZXNoLXRva2VuJztcblxuICAgICAgICBub2NrKFJPT1QpLnBvc3QoJy9vYXV0aC90b2tlbicpLnJlcGx5KDIwMCwge1xuICAgICAgICAgIGFjY2Vzc190b2tlbjogJ3YyeG5ld3Rva2VuJyxcbiAgICAgICAgICByZWZyZXNoX3Rva2VuOiAnbmV3LXJlZnJlc2gtdG9rZW4nLFxuICAgICAgICB9KTtcblxuICAgICAgICBhd2FpdCBiaXRnby5yZWZyZXNoVG9rZW4oKTtcblxuICAgICAgICBzZXRUb2tlblN0dWIuY2FsbGVkT25jZS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgICAgICBzZXRUb2tlblN0dWIuZmlyc3RDYWxsLmFyZ3NbMF0uc2hvdWxkLmVxdWFsKCd2MnhuZXd0b2tlbicpO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZSgnYXV0aGVudGljYXRlV2l0aEF1dGhDb2RlKCknLCBmdW5jdGlvbiAoKSB7XG4gICAgICBpdCgnY2FsbHMgc2V0VG9rZW4gd2l0aCB0aGUgYWNjZXNzX3Rva2VuIGZyb20gdGhlIE9BdXRoIHJlc3BvbnNlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCB7IHN0cmF0ZWd5LCBzZXRUb2tlblN0dWIgfSA9IG1ha2VTdHJhdGVneSgpO1xuICAgICAgICBjb25zdCBiaXRnbyA9IG5ldyBCaXRHb0FQSSh7XG4gICAgICAgICAgZW52OiAnY3VzdG9tJyxcbiAgICAgICAgICBjdXN0b21Sb290VVJJOiBST09ULFxuICAgICAgICAgIGhtYWNBdXRoU3RyYXRlZ3k6IHN0cmF0ZWd5LFxuICAgICAgICAgIGNsaWVudElkOiAnY2xpZW50LWlkJyxcbiAgICAgICAgICBjbGllbnRTZWNyZXQ6ICdjbGllbnQtc2VjcmV0JyxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgbm9jayhST09UKS5wb3N0KCcvb2F1dGgvdG9rZW4nKS5yZXBseSgyMDAsIHtcbiAgICAgICAgICBhY2Nlc3NfdG9rZW46ICd2MnhhdXRoY29kZXRva2VuJyxcbiAgICAgICAgICByZWZyZXNoX3Rva2VuOiAncmVmcmVzaC10b2tlbicsXG4gICAgICAgIH0pO1xuICAgICAgICAvLyBhdXRoZW50aWNhdGVXaXRoQXV0aENvZGUgY2FsbHMgdGhpcy5tZSgpIGFmdGVyIHNldHRpbmcgdGhlIHRva2VuXG4gICAgICAgIG5vY2soUk9PVClcbiAgICAgICAgICAuZ2V0KCcvYXBpL3YxL3VzZXIvbWUnKVxuICAgICAgICAgIC5yZXBseSgyMDAsIHtcbiAgICAgICAgICAgIHVzZXI6IHsgdXNlcm5hbWU6ICd0ZXN0QGV4YW1wbGUuY29tJyB9LFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgIGF3YWl0IGJpdGdvLmF1dGhlbnRpY2F0ZVdpdGhBdXRoQ29kZSh7IGF1dGhDb2RlOiAnbXktYXV0aC1jb2RlJyB9KTtcblxuICAgICAgICBzZXRUb2tlblN0dWIuY2FsbGVkT25jZS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgICAgICBzZXRUb2tlblN0dWIuZmlyc3RDYWxsLmFyZ3NbMF0uc2hvdWxkLmVxdWFsKCd2MnhhdXRoY29kZXRva2VuJyk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKCdzeW5jIHRva2VuLXNldHRpbmcgbWV0aG9kcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGl0KCdhdXRoZW50aWNhdGVXaXRoQWNjZXNzVG9rZW4gZG9lcyBub3QgY2FsbCBzZXRUb2tlbiAoc3luY2hyb25vdXMg4oCUIGNhbGxlciBtdXN0IGludm9rZSBzZXRUb2tlbiBvbiB0aGUgc3RyYXRlZ3kgbWFudWFsbHkpJywgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCB7IHN0cmF0ZWd5LCBzZXRUb2tlblN0dWIgfSA9IG1ha2VTdHJhdGVneSgpO1xuICAgICAgICBjb25zdCBiaXRnbyA9IG5ldyBCaXRHb0FQSSh7IGVudjogJ2N1c3RvbScsIGN1c3RvbVJvb3RVUkk6IFJPT1QsIGhtYWNBdXRoU3RyYXRlZ3k6IHN0cmF0ZWd5IH0pO1xuXG4gICAgICAgIGJpdGdvLmF1dGhlbnRpY2F0ZVdpdGhBY2Nlc3NUb2tlbih7IGFjY2Vzc1Rva2VuOiAndjJ4c3luY3Rva2VuJyB9KTtcblxuICAgICAgICBzZXRUb2tlblN0dWIuY2FsbGVkLnNob3VsZC5iZS5mYWxzZSgpO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdmcm9tSlNPTiBkb2VzIG5vdCBjYWxsIHNldFRva2VuIChzeW5jaHJvbm91cyDigJQgY2FsbGVyIG11c3QgaW52b2tlIHNldFRva2VuIG9uIHRoZSBzdHJhdGVneSBtYW51YWxseSknLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IHsgc3RyYXRlZ3ksIHNldFRva2VuU3R1YiB9ID0gbWFrZVN0cmF0ZWd5KCk7XG4gICAgICAgIGNvbnN0IGJpdGdvID0gbmV3IEJpdEdvQVBJKHsgZW52OiAnY3VzdG9tJywgY3VzdG9tUm9vdFVSSTogUk9PVCwgaG1hY0F1dGhTdHJhdGVneTogc3RyYXRlZ3kgfSk7XG5cbiAgICAgICAgKGJpdGdvIGFzIGFueSkuZnJvbUpTT04oeyB1c2VyOiB7IHVzZXJuYW1lOiAndGVzdEBleGFtcGxlLmNvbScgfSwgdG9rZW46ICd2Mnhqc29udG9rZW4nIH0pO1xuXG4gICAgICAgIHNldFRva2VuU3R1Yi5jYWxsZWQuc2hvdWxkLmJlLmZhbHNlKCk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKCdhZGRBY2Nlc3NUb2tlbigpJywgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdmFsaWRQYXJhbXMgPSB7XG4gICAgICAgIGxhYmVsOiAndGVzdC10b2tlbicsXG4gICAgICAgIHNjb3BlOiBbJ3dhbGxldF92aWV3X2FsbCddLFxuICAgICAgICBkdXJhdGlvbjogMzYwMCxcbiAgICAgIH07XG5cbiAgICAgIGl0KCdzaG91bGQgdXNlIEhNQUMgYXV0aCB3aGVuIGVjZGhYcHJ2IGlzIGFic2VudCBidXQgaG1hY0F1dGhTdHJhdGVneSBpcyBhdXRoZW50aWNhdGVkJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCB7IHN0cmF0ZWd5IH0gPSBtYWtlU3RyYXRlZ3koe1xuICAgICAgICAgIGlzQXV0aGVudGljYXRlZDogc2lub24uc3R1YigpLnJldHVybnModHJ1ZSksXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBiaXRnbyA9IG5ldyBCaXRHb0FQSSh7IGVudjogJ2N1c3RvbScsIGN1c3RvbVJvb3RVUkk6IFJPT1QsIGhtYWNBdXRoU3RyYXRlZ3k6IHN0cmF0ZWd5IH0pO1xuICAgICAgICAvLyBEbyBOT1Qgc2V0IF9lY2RoWHBydiDigJQgc2ltdWxhdGVzIFNTTy9XZWJDcnlwdG8gc2Vzc2lvblxuICAgICAgICAvLyBTZXQgYSB2MnggdG9rZW4gc28gdGhlIHJlcXVlc3QgZ29lcyB0aHJvdWdoIHRoZSB2MiBhdXRoIHBhdGhcbiAgICAgICAgYml0Z28uYXV0aGVudGljYXRlV2l0aEFjY2Vzc1Rva2VuKHsgYWNjZXNzVG9rZW46ICd2MnhzdHJhdGVneXRva2VuJyB9KTtcblxuICAgICAgICBjb25zdCBzY29wZSA9IG5vY2soUk9PVCkucG9zdCgnL2FwaS9hdXRoL3YxL2FjY2Vzc3Rva2VuJykucmVwbHkoMjAwLCB7XG4gICAgICAgICAgdG9rZW46ICd2MnhuZXdwbGFpbnRva2VuJyxcbiAgICAgICAgICBsYWJlbDogJ3Rlc3QtdG9rZW4nLFxuICAgICAgICB9KTtcblxuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBiaXRnby5hZGRBY2Nlc3NUb2tlbih2YWxpZFBhcmFtcyk7XG5cbiAgICAgICAgc2NvcGUuaXNEb25lKCkuc2hvdWxkLmJlLnRydWUoKTtcbiAgICAgICAgLy8gZm9yY2VWMUF1dGggc2hvdWxkIE5PVCBoYXZlIGJlZW4gc2V0LCBzbyBubyBkb3duZ3JhZGUgd2FybmluZ1xuICAgICAgICAocmVzdWx0IGFzIGFueSkuc2hvdWxkLm5vdC5oYXZlLnByb3BlcnR5KCd3YXJuaW5nJyk7XG4gICAgICAgIC8vIFRoZSBwbGFpbiB0b2tlbiBmcm9tIHRoZSByZXNwb25zZSBib2R5IHNob3VsZCBiZSByZXR1cm5lZCBkaXJlY3RseVxuICAgICAgICByZXN1bHQudG9rZW4uc2hvdWxkLmVxdWFsKCd2MnhuZXdwbGFpbnRva2VuJyk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ3Nob3VsZCByZXR1cm4gcGxhaW4gdG9rZW4gZnJvbSByZXNwb25zZSBib2R5IHdoZW4gZWNkaFhwcnYgaXMgYWJzZW50IGJ1dCBzdHJhdGVneUF1dGhlbnRpY2F0ZWQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IGhhbmRsZVRva2VuU3B5ID0gc2lub24uc3B5KEJpdEdvQVBJLnByb3RvdHlwZSwgJ2hhbmRsZVRva2VuSXNzdWFuY2UnKTtcbiAgICAgICAgY29uc3QgeyBzdHJhdGVneSB9ID0gbWFrZVN0cmF0ZWd5KHtcbiAgICAgICAgICBpc0F1dGhlbnRpY2F0ZWQ6IHNpbm9uLnN0dWIoKS5yZXR1cm5zKHRydWUpLFxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgYml0Z28gPSBuZXcgQml0R29BUEkoeyBlbnY6ICdjdXN0b20nLCBjdXN0b21Sb290VVJJOiBST09ULCBobWFjQXV0aFN0cmF0ZWd5OiBzdHJhdGVneSB9KTtcbiAgICAgICAgYml0Z28uYXV0aGVudGljYXRlV2l0aEFjY2Vzc1Rva2VuKHsgYWNjZXNzVG9rZW46ICd2MnhzdHJhdGVneXRva2VuJyB9KTtcblxuICAgICAgICBub2NrKFJPT1QpLnBvc3QoJy9hcGkvYXV0aC92MS9hY2Nlc3N0b2tlbicpLnJlcGx5KDIwMCwge1xuICAgICAgICAgIHRva2VuOiAndjJ4cGxhaW50b2tlbicsXG4gICAgICAgICAgbGFiZWw6ICd0ZXN0LXRva2VuJyxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYml0Z28uYWRkQWNjZXNzVG9rZW4odmFsaWRQYXJhbXMpO1xuXG4gICAgICAgIC8vIGhhbmRsZVRva2VuSXNzdWFuY2Ugc2hvdWxkIE5PVCBiZSBjYWxsZWQg4oCUIG5vIEVDREggZGVjcnlwdGlvbiBuZWVkZWRcbiAgICAgICAgaGFuZGxlVG9rZW5TcHkuY2FsbGVkLnNob3VsZC5iZS5mYWxzZSgpO1xuICAgICAgICByZXN1bHQudG9rZW4uc2hvdWxkLmVxdWFsKCd2MnhwbGFpbnRva2VuJyk7XG5cbiAgICAgICAgaGFuZGxlVG9rZW5TcHkucmVzdG9yZSgpO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgc3RpbGwgZm9yY2UgVjEgYXV0aCB3aGVuIG5laXRoZXIgZWNkaFhwcnYgbm9yIHN0cmF0ZWd5IGlzIGF1dGhlbnRpY2F0ZWQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IHsgc3RyYXRlZ3kgfSA9IG1ha2VTdHJhdGVneSh7XG4gICAgICAgICAgaXNBdXRoZW50aWNhdGVkOiBzaW5vbi5zdHViKCkucmV0dXJucyhmYWxzZSksXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBiaXRnbyA9IG5ldyBCaXRHb0FQSSh7IGVudjogJ2N1c3RvbScsIGN1c3RvbVJvb3RVUkk6IFJPT1QsIGhtYWNBdXRoU3RyYXRlZ3k6IHN0cmF0ZWd5IH0pO1xuICAgICAgICBiaXRnby5hdXRoZW50aWNhdGVXaXRoQWNjZXNzVG9rZW4oeyBhY2Nlc3NUb2tlbjogJ3YyeGxlZ2FjeXRva2VuJyB9KTtcblxuICAgICAgICBub2NrKFJPT1QpLnBvc3QoJy9hcGkvYXV0aC92MS9hY2Nlc3N0b2tlbicpLnJlcGx5KDIwMCwge1xuICAgICAgICAgIHRva2VuOiAndjJ4bGVnYWN5cmVzdWx0JyxcbiAgICAgICAgICBsYWJlbDogJ3Rlc3QtdG9rZW4nLFxuICAgICAgICB9KTtcblxuICAgICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBiaXRnby5hZGRBY2Nlc3NUb2tlbih2YWxpZFBhcmFtcyk7XG5cbiAgICAgICAgLy8gVjEgYXV0aCBwYXRoIHNob3VsZCBhZGQgdGhlIGRvd25ncmFkZSB3YXJuaW5nXG4gICAgICAgIChyZXN1bHQgYXMgYW55KS53YXJuaW5nLnNob3VsZC5tYXRjaCgvcHJvdG9jb2wgZG93bmdyYWRlLyk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ3Nob3VsZCBzdGlsbCBmb3JjZSBWMSBhdXRoIHdoZW4gaXNBdXRoZW50aWNhdGVkIGlzIG5vdCBkZWZpbmVkIG9uIHN0cmF0ZWd5JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCB7IHN0cmF0ZWd5IH0gPSBtYWtlU3RyYXRlZ3koKTtcbiAgICAgICAgLy8gc3RyYXRlZ3kgaGFzIG5vIGlzQXV0aGVudGljYXRlZCBtZXRob2QgYnkgZGVmYXVsdCBmcm9tIG1ha2VTdHJhdGVneVxuICAgICAgICBjb25zdCBiaXRnbyA9IG5ldyBCaXRHb0FQSSh7IGVudjogJ2N1c3RvbScsIGN1c3RvbVJvb3RVUkk6IFJPT1QsIGhtYWNBdXRoU3RyYXRlZ3k6IHN0cmF0ZWd5IH0pO1xuICAgICAgICBiaXRnby5hdXRoZW50aWNhdGVXaXRoQWNjZXNzVG9rZW4oeyBhY2Nlc3NUb2tlbjogJ3YyeG5vYXV0aG1ldGhvZCcgfSk7XG5cbiAgICAgICAgbm9jayhST09UKS5wb3N0KCcvYXBpL2F1dGgvdjEvYWNjZXNzdG9rZW4nKS5yZXBseSgyMDAsIHtcbiAgICAgICAgICB0b2tlbjogJ3YyeHJlc3VsdCcsXG4gICAgICAgICAgbGFiZWw6ICd0ZXN0LXRva2VuJyxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgYml0Z28uYWRkQWNjZXNzVG9rZW4odmFsaWRQYXJhbXMpO1xuXG4gICAgICAgIC8vIFdpdGhvdXQgaXNBdXRoZW50aWNhdGVkLCBzaG91bGQgZmFsbCBiYWNrIHRvIFYxIGF1dGhcbiAgICAgICAgKHJlc3VsdCBhcyBhbnkpLndhcm5pbmcuc2hvdWxkLm1hdGNoKC9wcm90b2NvbCBkb3duZ3JhZGUvKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnY29uc3RhbnRzIHBhcmFtZXRlcicsIGZ1bmN0aW9uICgpIHtcbiAgICBpdCgnc2hvdWxkIGFsbG93IHBhc3NpbmcgY29uc3RhbnRzIHZpYSBvcHRpb25zIGFuZCBleHBvc2UgdmlhIGZldGNoQ29uc3RhbnRzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgYml0Z28gPSBuZXcgQml0R29BUEkoe1xuICAgICAgICBlbnY6ICdjdXN0b20nLFxuICAgICAgICBjdXN0b21Sb290VVJJOiAnaHR0cHM6Ly9hcHAuZXhhbXBsZS5sb2NhbCcsXG4gICAgICAgIGNsaWVudENvbnN0YW50czogeyBtYXhGZWVSYXRlOiAnMTIzMTIzMTIzMTIzMTIzJyB9LFxuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IGNvbnN0YW50cyA9IGF3YWl0IGJpdGdvLmZldGNoQ29uc3RhbnRzKCk7XG4gICAgICBjb25zdGFudHMuc2hvdWxkLmhhdmUucHJvcGVydHkoJ21heEZlZVJhdGUnLCAnMTIzMTIzMTIzMTIzMTIzJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJlZnJlc2ggY29uc3RhbnRzIHdoZW4gY2FjaGUgaGFzIGV4cGlyZWQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBiaXRnbyA9IG5ldyBCaXRHb0FQSSh7XG4gICAgICAgIGVudjogJ2N1c3RvbScsXG4gICAgICAgIGN1c3RvbVJvb3RVUkk6ICdodHRwczovL2FwcC5leGFtcGxlLmxvY2FsJyxcbiAgICAgIH0pO1xuXG4gICAgICAvLyBTZXQgdXAgY2FjaGVkIGNvbnN0YW50cyB3aXRoIGFuIGV4cGlyZWQgY2FjaGVcbiAgICAgIChCaXRHb0FQSSBhcyBhbnkpLl9jb25zdGFudHMgPSAoQml0R29BUEkgYXMgYW55KS5fY29uc3RhbnRzIHx8IHt9O1xuICAgICAgKEJpdEdvQVBJIGFzIGFueSkuX2NvbnN0YW50c0V4cGlyZSA9IChCaXRHb0FQSSBhcyBhbnkpLl9jb25zdGFudHNFeHBpcmUgfHwge307XG4gICAgICAoQml0R29BUEkgYXMgYW55KS5fY29uc3RhbnRzWydjdXN0b20nXSA9IHsgbWF4RmVlUmF0ZTogJ29sZC12YWx1ZScgfTtcbiAgICAgIChCaXRHb0FQSSBhcyBhbnkpLl9jb25zdGFudHNFeHBpcmVbJ2N1c3RvbSddID0gbmV3IERhdGUoRGF0ZS5ub3coKSAtIDEwMDApOyAvLyBFeHBpcmVkIDEgc2Vjb25kIGFnb1xuXG4gICAgICBjb25zdCBzY29wZSA9IG5vY2soJ2h0dHBzOi8vYXBwLmV4YW1wbGUubG9jYWwnKVxuICAgICAgICAuZ2V0KCcvYXBpL3YxL2NsaWVudC9jb25zdGFudHMnKVxuICAgICAgICAucmVwbHkoMjAwLCB7XG4gICAgICAgICAgY29uc3RhbnRzOiB7IG1heEZlZVJhdGU6ICduZXctdmFsdWUnLCBuZXdDb25zdGFudDogJ2FkZGVkJyB9LFxuICAgICAgICB9KTtcblxuICAgICAgY29uc3QgY29uc3RhbnRzID0gYXdhaXQgYml0Z28uZmV0Y2hDb25zdGFudHMoKTtcblxuICAgICAgLy8gU2hvdWxkIHJldHVybiB0aGUgbmV3IGNvbnN0YW50cyBmcm9tIHRoZSBzZXJ2ZXJcbiAgICAgIGNvbnN0YW50cy5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnbWF4RmVlUmF0ZScsICduZXctdmFsdWUnKTtcbiAgICAgIGNvbnN0YW50cy5zaG91bGQuaGF2ZS5wcm9wZXJ0eSgnbmV3Q29uc3RhbnQnLCAnYWRkZWQnKTtcblxuICAgICAgc2NvcGUuaXNEb25lKCkuc2hvdWxkLmJlLnRydWUoKTtcblxuICAgICAgbm9jay5jbGVhbkFsbCgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB1c2UgY2FjaGVkIGNvbnN0YW50cyB3aGVuIGNhY2hlIGlzIHN0aWxsIHZhbGlkJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgYml0Z28gPSBuZXcgQml0R29BUEkoe1xuICAgICAgICBlbnY6ICdjdXN0b20nLFxuICAgICAgICBjdXN0b21Sb290VVJJOiAnaHR0cHM6Ly9hcHAuZXhhbXBsZS5sb2NhbCcsXG4gICAgICB9KTtcblxuICAgICAgLy8gU2V0IHVwIGNhY2hlZCBjb25zdGFudHMgd2l0aCBhIGZ1dHVyZSBleHBpcnlcbiAgICAgIGNvbnN0IGNhY2hlZENvbnN0YW50cyA9IHsgbWF4RmVlUmF0ZTogJ2NhY2hlZC12YWx1ZScsIGFub3RoZXJTZXR0aW5nOiAnY2FjaGVkLXNldHRpbmcnIH07XG4gICAgICAoQml0R29BUEkgYXMgYW55KS5fY29uc3RhbnRzID0gKEJpdEdvQVBJIGFzIGFueSkuX2NvbnN0YW50cyB8fCB7fTtcbiAgICAgIChCaXRHb0FQSSBhcyBhbnkpLl9jb25zdGFudHNFeHBpcmUgPSAoQml0R29BUEkgYXMgYW55KS5fY29uc3RhbnRzRXhwaXJlIHx8IHt9O1xuICAgICAgKEJpdEdvQVBJIGFzIGFueSkuX2NvbnN0YW50c1snY3VzdG9tJ10gPSBjYWNoZWRDb25zdGFudHM7XG4gICAgICAoQml0R29BUEkgYXMgYW55KS5fY29uc3RhbnRzRXhwaXJlWydjdXN0b20nXSA9IG5ldyBEYXRlKERhdGUubm93KCkgKyA1ICogNjAgKiAxMDAwKTsgLy8gVmFsaWQgZm9yIDUgbW9yZSBtaW51dGVzXG5cbiAgICAgIGNvbnN0IHNjb3BlID0gbm9jaygnaHR0cHM6Ly9hcHAuZXhhbXBsZS5sb2NhbCcpXG4gICAgICAgIC5nZXQoJy9hcGkvdjEvY2xpZW50L2NvbnN0YW50cycpXG4gICAgICAgIC5yZXBseSgyMDAsIHsgY29uc3RhbnRzOiB7IHNob3VsZE5vdEJlVXNlZDogdHJ1ZSB9IH0pO1xuXG4gICAgICBjb25zdCBjb25zdGFudHMgPSBhd2FpdCBiaXRnby5mZXRjaENvbnN0YW50cygpO1xuXG4gICAgICAvLyBTaG91bGQgcmV0dXJuIHRoZSBjYWNoZWQgY29uc3RhbnRzXG4gICAgICBjb25zdGFudHMuc2hvdWxkLmRlZXBFcXVhbChjYWNoZWRDb25zdGFudHMpO1xuXG4gICAgICAvLyBWZXJpZnkgdGhhdCBubyBIVFRQIHJlcXVlc3Qgd2FzIG1hZGUgKHNpbmNlIGNhY2hlIHdhcyB2YWxpZClcbiAgICAgIHNjb3BlLmlzRG9uZSgpLnNob3VsZC5iZS5mYWxzZSgpO1xuXG4gICAgICBub2NrLmNsZWFuQWxsKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHVzZSBjYWNoZWQgY29uc3RhbnRzIHdoZW4gbm8gY2FjaGUgZXhwaXJ5IGlzIHNldCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGJpdGdvID0gbmV3IEJpdEdvQVBJKHtcbiAgICAgICAgZW52OiAnY3VzdG9tJyxcbiAgICAgICAgY3VzdG9tUm9vdFVSSTogJ2h0dHBzOi8vYXBwLmV4YW1wbGUubG9jYWwnLFxuICAgICAgfSk7XG5cbiAgICAgIC8vIFNldCB1cCBjYWNoZWQgY29uc3RhbnRzIHdpdGggbm8gZXhwaXJ5XG4gICAgICBjb25zdCBjYWNoZWRDb25zdGFudHMgPSB7IG1heEZlZVJhdGU6ICduby1leHBpcnktdmFsdWUnIH07XG4gICAgICAoQml0R29BUEkgYXMgYW55KS5fY29uc3RhbnRzID0gKEJpdEdvQVBJIGFzIGFueSkuX2NvbnN0YW50cyB8fCB7fTtcbiAgICAgIChCaXRHb0FQSSBhcyBhbnkpLl9jb25zdGFudHNFeHBpcmUgPSAoQml0R29BUEkgYXMgYW55KS5fY29uc3RhbnRzRXhwaXJlIHx8IHt9O1xuICAgICAgKEJpdEdvQVBJIGFzIGFueSkuX2NvbnN0YW50c1snY3VzdG9tJ10gPSBjYWNoZWRDb25zdGFudHM7XG4gICAgICAoQml0R29BUEkgYXMgYW55KS5fY29uc3RhbnRzRXhwaXJlWydjdXN0b20nXSA9IHVuZGVmaW5lZDtcblxuICAgICAgY29uc3Qgc2NvcGUgPSBub2NrKCdodHRwczovL2FwcC5leGFtcGxlLmxvY2FsJylcbiAgICAgICAgLmdldCgnL2FwaS92MS9jbGllbnQvY29uc3RhbnRzJylcbiAgICAgICAgLnJlcGx5KDIwMCwgeyBjb25zdGFudHM6IHsgc2hvdWxkTm90QmVVc2VkOiB0cnVlIH0gfSk7XG5cbiAgICAgIGNvbnN0IGNvbnN0YW50cyA9IGF3YWl0IGJpdGdvLmZldGNoQ29uc3RhbnRzKCk7XG5cbiAgICAgIC8vIFNob3VsZCByZXR1cm4gdGhlIGNhY2hlZCBjb25zdGFudHNcbiAgICAgIGNvbnN0YW50cy5zaG91bGQuZGVlcEVxdWFsKGNhY2hlZENvbnN0YW50cyk7XG5cbiAgICAgIC8vIFZlcmlmeSB0aGF0IG5vIEhUVFAgcmVxdWVzdCB3YXMgbWFkZSAoc2luY2Ugbm8gZXhwaXJ5IG1lYW5zIGNhY2hlIGlzIGFsd2F5cyB2YWxpZClcbiAgICAgIHNjb3BlLmlzRG9uZSgpLnNob3VsZC5iZS5mYWxzZSgpO1xuXG4gICAgICBub2NrLmNsZWFuQWxsKCk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdwYWNrS2V5Y2hhaW5zRkZEJywgZnVuY3Rpb24gKCkge1xuICAgIGxldCBiaXRnbzogQml0R29BUEk7XG5cbiAgICBiZWZvcmUoZnVuY3Rpb24gKCkge1xuICAgICAgYml0Z28gPSBuZXcgQml0R29BUEkoeyBlbnY6ICdjdXN0b20nLCBjdXN0b21Sb290VVJJOiAnaHR0cHM6Ly9hcHAuZXhhbXBsZS5sb2NhbCcgfSk7XG4gICAgfSk7XG5cbiAgICBmdW5jdGlvbiBmZmQoXG4gICAgICBrZXljaGFpbnM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4sXG4gICAgICB2MktleWNoYWluczogUmVjb3JkPHN0cmluZywgc3RyaW5nPixcbiAgICAgIG1heEJhdGNoU2l6ZUJ5dGVzOiBudW1iZXJcbiAgICApOiBBcnJheTx7IHYxQmF0Y2g6IFJlY29yZDxzdHJpbmcsIHN0cmluZz47IHYyQmF0Y2g6IFJlY29yZDxzdHJpbmcsIHN0cmluZz47IHNpemVCeXRlczogbnVtYmVyIH0+IHtcbiAgICAgIHJldHVybiAoYml0Z28gYXMgYW55KS5wYWNrS2V5Y2hhaW5zRkZEKGtleWNoYWlucywgdjJLZXljaGFpbnMsIG1heEJhdGNoU2l6ZUJ5dGVzKTtcbiAgICB9XG5cbiAgICBpdCgncmV0dXJucyBhbiBlbXB0eSBhcnJheSB3aGVuIGJvdGggaW5wdXRzIGFyZSBlbXB0eScsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGJpbnMgPSBmZmQoe30sIHt9LCAxMDI0KTtcbiAgICAgIGJpbnMuc2hvdWxkLmJlLmFuLkFycmF5KCk7XG4gICAgICBiaW5zLnNob3VsZC5oYXZlLmxlbmd0aCgwKTtcbiAgICB9KTtcblxuICAgIGl0KCdwYWNrcyBhbGwgaXRlbXMgaW50byBhIHNpbmdsZSBiaW4gd2hlbiB0aGV5IGZpdCB3aXRoaW4gdGhlIGxpbWl0JywgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gRWFjaCBlbnRyeTogMi1ieXRlIGlkICsgMTAtYnl0ZSB2YWx1ZSA9IDEyIGJ5dGVzOyA1IGVudHJpZXMgPSA2MCBieXRlcyA8IDIwMCBsaW1pdFxuICAgICAgY29uc3Qga2V5Y2hhaW5zID0geyBrMTogJ2FhYWFhYWFhYWEnLCBrMjogJ2JiYmJiYmJiYmInLCBrMzogJ2NjY2NjY2NjY2MnIH07XG4gICAgICBjb25zdCB2MktleWNoYWlucyA9IHsgdjE6ICdkZGRkZGRkZGRkJywgdjI6ICdlZWVlZWVlZWVlJyB9O1xuICAgICAgY29uc3QgYmlucyA9IGZmZChrZXljaGFpbnMsIHYyS2V5Y2hhaW5zLCAyMDApO1xuICAgICAgYmlucy5zaG91bGQuaGF2ZS5sZW5ndGgoMSk7XG4gICAgICBPYmplY3Qua2V5cyhiaW5zWzBdLnYxQmF0Y2gpLnNob3VsZC5oYXZlLmxlbmd0aCgzKTtcbiAgICAgIE9iamVjdC5rZXlzKGJpbnNbMF0udjJCYXRjaCkuc2hvdWxkLmhhdmUubGVuZ3RoKDIpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3NwbGl0cyBpbnRvIG11bHRpcGxlIGJpbnMgd2hlbiBhIHNpbmdsZSBiaW4gY2Fubm90IGZpdCBhbGwgaXRlbXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAvLyBpZD0nazEnICgyIGJ5dGVzKSArIDYwMC1jaGFyIHZhbHVlID0gNjAyIGJ5dGVzOyAyIGVudHJpZXMgZXhjZWVkIDcwMC1ieXRlIGxpbWl0XG4gICAgICBjb25zdCBrZXljaGFpbnMgPSB7IGsxOiAneCcucmVwZWF0KDYwMCksIGsyOiAneScucmVwZWF0KDYwMCkgfTtcbiAgICAgIGNvbnN0IGJpbnMgPSBmZmQoa2V5Y2hhaW5zLCB7fSwgNzAwKTtcbiAgICAgIGJpbnMuc2hvdWxkLmhhdmUubGVuZ3RoKDIpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Rocm93cyB3aGVuIGEgc2luZ2xlIGl0ZW0gZXhjZWVkcyBtYXhCYXRjaFNpemVCeXRlcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIC8vIGlkPSdrMScgKDIgYnl0ZXMpICsgMjAwLWNoYXIgdmFsdWUgPSAyMDIgYnl0ZXMgPiAxMDAtYnl0ZSBsaW1pdFxuICAgICAgY29uc3Qga2V5Y2hhaW5zID0geyBrMTogJ3gnLnJlcGVhdCgyMDApIH07XG4gICAgICB0cnkge1xuICAgICAgICBmZmQoa2V5Y2hhaW5zLCB7fSwgMTAwKTtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdFeHBlY3RlZCBlcnJvciBub3QgdGhyb3duJyk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGUubWVzc2FnZS5zaG91bGQubWF0Y2goL2V4Y2VlZHMgdGhlIG1heGltdW0gYmF0Y2ggc2l6ZS8pO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgaXQoJ3BsYWNlcyBWMSBrZXljaGFpbnMgaW4gdjFCYXRjaCBhbmQgVjIga2V5Y2hhaW5zIGluIHYyQmF0Y2gnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBrZXljaGFpbnMgPSB7IGsxOiAndjF2YWx1ZScgfTtcbiAgICAgIGNvbnN0IHYyS2V5Y2hhaW5zID0geyBrMjogJ3YydmFsdWUnIH07XG4gICAgICBjb25zdCBiaW5zID0gZmZkKGtleWNoYWlucywgdjJLZXljaGFpbnMsIDEwMDAwKTtcbiAgICAgIGJpbnMuc2hvdWxkLmhhdmUubGVuZ3RoKDEpO1xuICAgICAgYmluc1swXS52MUJhdGNoLnNob3VsZC5oYXZlLnByb3BlcnR5KCdrMScsICd2MXZhbHVlJyk7XG4gICAgICBiaW5zWzBdLnYyQmF0Y2guc2hvdWxkLmhhdmUucHJvcGVydHkoJ2syJywgJ3YydmFsdWUnKTtcbiAgICAgIGJpbnNbMF0udjFCYXRjaC5zaG91bGQubm90LmhhdmUucHJvcGVydHkoJ2syJyk7XG4gICAgICBiaW5zWzBdLnYyQmF0Y2guc2hvdWxkLm5vdC5oYXZlLnByb3BlcnR5KCdrMScpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3VzZXMgRkZEIG9yZGVyaW5nIHNvIHRoZSBsYXJnZXN0IGl0ZW0gaXMgcGFja2VkIGZpcnN0JywgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gJ2JpZyc6IGlkKDMpICsgNDk3IGJ5dGVzID0gNTAwIGJ5dGVzOyAnczEnLCdzMic6IGlkKDIpICsgOTggYnl0ZXMgPSAxMDAgYnl0ZXMgZWFjaFxuICAgICAgLy8gbWF4QmF0Y2hTaXplQnl0ZXMgPSA2MDBcbiAgICAgIC8vIEZGRCBvcmRlciAoZGVzY2VuZGluZyk6IGJpZyg1MDApLCBzMSgxMDApLCBzMigxMDApXG4gICAgICAvLyAgIGJpbjA6IGJpZyg1MDApLiBzMTogNTAwKzEwMD02MDAgPD02MDAsIGZpdHMuIHMyOiA2MDArMTAwPTcwMCA+IDYwMCwgbmV3IGJpbjEuXG4gICAgICAvLyAgIFJlc3VsdDogYmluMD17YmlnLHMxfSwgYmluMT17czJ9XG4gICAgICBjb25zdCBrZXljaGFpbnMgPSB7IGJpZzogJ3gnLnJlcGVhdCg0OTcpLCBzMTogJ3knLnJlcGVhdCg5OCksIHMyOiAneicucmVwZWF0KDk4KSB9O1xuICAgICAgY29uc3QgYmlucyA9IGZmZChrZXljaGFpbnMsIHt9LCA2MDApO1xuICAgICAgYmlucy5zaG91bGQuaGF2ZS5sZW5ndGgoMik7XG4gICAgICAvLyAnYmlnJyBzaG91bGQgc2hhcmUgaXRzIGJpbiB3aXRoIG9uZSBzbWFsbCBpdGVtIChGRkQgcGFja3MgdGhlIGxhcmdlc3QgZmlyc3QpXG4gICAgICBjb25zdCBiaW5XaXRoQmlnID0gYmlucy5maW5kKChiKSA9PiAnYmlnJyBpbiBiLnYxQmF0Y2gpITtcbiAgICAgIE9iamVjdC5rZXlzKGJpbldpdGhCaWcudjFCYXRjaCkuc2hvdWxkLmhhdmUubGVuZ3RoKDIpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgncHJvY2Vzc0tleWNoYWluUGFzc3dvcmRVcGRhdGVzSW5CYXRjaGVzJywgZnVuY3Rpb24gKCkge1xuICAgIGNvbnN0IFJPT1QgPSAnaHR0cHM6Ly9hcHAuZXhhbXBsZS5sb2NhbCc7XG4gICAgbGV0IGJpdGdvOiBCaXRHb0FQSTtcblxuICAgIGJlZm9yZUVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3Qgc3RyYXRlZ3k6IElIbWFjQXV0aFN0cmF0ZWd5ID0ge1xuICAgICAgICBjYWxjdWxhdGVSZXF1ZXN0SGVhZGVyczogc2lub24uc3R1YigpLnJlc29sdmVzKHsgaG1hYzogJ2htYWMnLCB0aW1lc3RhbXA6IERhdGUubm93KCksIHRva2VuSGFzaDogJ2hhc2gnIH0pLFxuICAgICAgICB2ZXJpZnlSZXNwb25zZTogc2lub24uc3R1YigpLnJlc29sdmVzKHtcbiAgICAgICAgICBpc1ZhbGlkOiB0cnVlLFxuICAgICAgICAgIGV4cGVjdGVkSG1hYzogJ2htYWMnLFxuICAgICAgICAgIHNpZ25hdHVyZVN1YmplY3Q6ICcnLFxuICAgICAgICAgIGlzSW5SZXNwb25zZVZhbGlkaXR5V2luZG93OiB0cnVlLFxuICAgICAgICAgIHZlcmlmaWNhdGlvblRpbWU6IERhdGUubm93KCksXG4gICAgICAgIH0pLFxuICAgICAgICBjYWxjdWxhdGVITUFDOiBzaW5vbi5zdHViKCkucmVzb2x2ZXMoJ2hhc2hlZC1wdycpLFxuICAgICAgICBzZXRUb2tlbjogc2lub24uc3R1YigpLnJlc29sdmVzKCksXG4gICAgICAgIGNsZWFyVG9rZW46IHNpbm9uLnN0dWIoKS5yZXNvbHZlcygpLFxuICAgICAgfTtcbiAgICAgIGJpdGdvID0gbmV3IEJpdEdvQVBJKHsgZW52OiAnY3VzdG9tJywgY3VzdG9tUm9vdFVSSTogUk9PVCwgaG1hY0F1dGhTdHJhdGVneTogc3RyYXRlZ3kgfSk7XG4gICAgfSk7XG5cbiAgICBhZnRlckVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgbm9jay5jbGVhbkFsbCgpO1xuICAgICAgc2lub24ucmVzdG9yZSgpO1xuICAgIH0pO1xuXG4gICAgYXN5bmMgZnVuY3Rpb24gcnVuQmF0Y2hlcyhcbiAgICAgIGtleWNoYWluczogUmVjb3JkPHN0cmluZywgc3RyaW5nPixcbiAgICAgIHYyS2V5Y2hhaW5zOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+LFxuICAgICAgbWF4QmF0Y2hTaXplS0I6IG51bWJlcixcbiAgICAgIG1heFJldHJpZXMgPSAzXG4gICAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICByZXR1cm4gKGJpdGdvIGFzIGFueSkucHJvY2Vzc0tleWNoYWluUGFzc3dvcmRVcGRhdGVzSW5CYXRjaGVzKGtleWNoYWlucywgdjJLZXljaGFpbnMsIG1heEJhdGNoU2l6ZUtCLCBtYXhSZXRyaWVzKTtcbiAgICB9XG5cbiAgICBpdCgnbWFrZXMgYSBzaW5nbGUgUFVUIHJlcXVlc3QgZm9yIGEgc21hbGwgcGF5bG9hZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IHNjb3BlID0gbm9jayhST09UKS5wdXQoJy9hcGkvdjIvdXNlci9rZXljaGFpbnMnKS5yZXBseSgyMDAsIHt9KTtcbiAgICAgIGF3YWl0IHJ1bkJhdGNoZXMoeyBrMTogJ3NtYWxsJyB9LCB7fSwgMTAyNCk7XG4gICAgICBzY29wZS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ21ha2VzIHR3byBQVVQgcmVxdWVzdHMgd2hlbiB0aGUgcGF5bG9hZCBzcGFucyB0d28gYmlucycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIC8vIGlkPSdrMScoMikgKyA2MDAgPSA2MDIgYnl0ZXMgZWFjaDsgMiBlbnRyaWVzIGV4Y2VlZCAxIEtCIGxpbWl0ID0+IDIgYmluc1xuICAgICAgY29uc3Qga2V5Y2hhaW5zID0geyBrMTogJ3gnLnJlcGVhdCg2MDApLCBrMjogJ3knLnJlcGVhdCg2MDApIH07XG4gICAgICBjb25zdCBzY29wZSA9IG5vY2soUk9PVCkucHV0KCcvYXBpL3YyL3VzZXIva2V5Y2hhaW5zJykudHdpY2UoKS5yZXBseSgyMDAsIHt9KTtcbiAgICAgIGF3YWl0IHJ1bkJhdGNoZXMoa2V5Y2hhaW5zLCB7fSwgMSk7XG4gICAgICBzY29wZS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3JldHJpZXMgYSBmYWlsZWQgYmF0Y2ggYW5kIHN1Y2NlZWRzIG9uIHRoZSBzZWNvbmQgYXR0ZW1wdCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIG5vY2soUk9PVCkucHV0KCcvYXBpL3YyL3VzZXIva2V5Y2hhaW5zJykucmVwbHkoNTAwLCB7IGVycm9yOiAnaW50ZXJuYWwgZXJyb3InIH0pO1xuICAgICAgbm9jayhST09UKS5wdXQoJy9hcGkvdjIvdXNlci9rZXljaGFpbnMnKS5yZXBseSgyMDAsIHt9KTtcbiAgICAgIC8vIFNob3VsZCBub3QgdGhyb3dcbiAgICAgIGF3YWl0IHJ1bkJhdGNoZXMoeyBrMTogJ3ZhbHVlJyB9LCB7fSwgMTAyNCwgMyk7XG4gICAgfSk7XG5cbiAgICBpdCgndGhyb3dzIGFmdGVyIGV4aGF1c3RpbmcgYWxsIHJldHJpZXMgb24gcGVyc2lzdGVudCBIVFRQIGVycm9ycycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIG5vY2soUk9PVCkucHV0KCcvYXBpL3YyL3VzZXIva2V5Y2hhaW5zJykudGltZXMoMykucmVwbHkoNTAwLCB7IGVycm9yOiAnaW50ZXJuYWwgZXJyb3InIH0pO1xuICAgICAgbGV0IHRocm93bkVycm9yOiBFcnJvciB8IHVuZGVmaW5lZDtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHJ1bkJhdGNoZXMoeyBrMTogJ3ZhbHVlJyB9LCB7fSwgMTAyNCwgMyk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93bkVycm9yID0gZTtcbiAgICAgIH1cbiAgICAgIHRocm93bkVycm9yIS5tZXNzYWdlLnNob3VsZC5tYXRjaCgvZmFpbGVkIGFmdGVyIDMgcmV0cmllcy8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Rocm93cyBhZnRlciBleGhhdXN0aW5nIGFsbCByZXRyaWVzIHdoZW4gdGhlIHNlcnZlciByZXBvcnRzIGZhaWxlZCBrZXljaGFpbnMnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBub2NrKFJPT1QpXG4gICAgICAgIC5wdXQoJy9hcGkvdjIvdXNlci9rZXljaGFpbnMnKVxuICAgICAgICAudGltZXMoMylcbiAgICAgICAgLnJlcGx5KDIwMCwgeyBmYWlsZWQ6IHsgdjE6IHsgazE6ICdlbmNyeXB0aW9uIGVycm9yJyB9IH0gfSk7XG4gICAgICBsZXQgdGhyb3duRXJyb3I6IEVycm9yIHwgdW5kZWZpbmVkO1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgcnVuQmF0Y2hlcyh7IGsxOiAndmFsdWUnIH0sIHt9LCAxMDI0LCAzKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgdGhyb3duRXJyb3IgPSBlO1xuICAgICAgfVxuICAgICAgdGhyb3duRXJyb3IhLm1lc3NhZ2Uuc2hvdWxkLm1hdGNoKC9oYWQgZmFpbGVkIGtleWNoYWlucy8pO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnY2hhbmdlUGFzc3dvcmQgYmF0Y2hpbmcgZmxvdycsIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCBST09UID0gJ2h0dHBzOi8vYXBwLmV4YW1wbGUubG9jYWwnO1xuICAgIGxldCBiaXRnbzogQml0R29BUEk7XG4gICAgbGV0IHNhbmRib3g6IHNpbm9uLlNpbm9uU2FuZGJveDtcblxuICAgIGJlZm9yZUVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgc2FuZGJveCA9IHNpbm9uLmNyZWF0ZVNhbmRib3goKTtcblxuICAgICAgY29uc3Qgc3RyYXRlZ3k6IElIbWFjQXV0aFN0cmF0ZWd5ID0ge1xuICAgICAgICBjYWxjdWxhdGVSZXF1ZXN0SGVhZGVyczogc2FuZGJveC5zdHViKCkucmVzb2x2ZXMoeyBobWFjOiAnaG1hYycsIHRpbWVzdGFtcDogRGF0ZS5ub3coKSwgdG9rZW5IYXNoOiAnaGFzaCcgfSksXG4gICAgICAgIHZlcmlmeVJlc3BvbnNlOiBzYW5kYm94LnN0dWIoKS5yZXNvbHZlcyh7XG4gICAgICAgICAgaXNWYWxpZDogdHJ1ZSxcbiAgICAgICAgICBleHBlY3RlZEhtYWM6ICdobWFjJyxcbiAgICAgICAgICBzaWduYXR1cmVTdWJqZWN0OiAnJyxcbiAgICAgICAgICBpc0luUmVzcG9uc2VWYWxpZGl0eVdpbmRvdzogdHJ1ZSxcbiAgICAgICAgICB2ZXJpZmljYXRpb25UaW1lOiBEYXRlLm5vdygpLFxuICAgICAgICB9KSxcbiAgICAgICAgY2FsY3VsYXRlSE1BQzogc2FuZGJveC5zdHViKCkucmVzb2x2ZXMoJ2hhc2hlZC1wdycpLFxuICAgICAgICBzZXRUb2tlbjogc2FuZGJveC5zdHViKCkucmVzb2x2ZXMoKSxcbiAgICAgICAgY2xlYXJUb2tlbjogc2FuZGJveC5zdHViKCkucmVzb2x2ZXMoKSxcbiAgICAgIH07XG5cbiAgICAgIGJpdGdvID0gbmV3IEJpdEdvQVBJKHsgZW52OiAnY3VzdG9tJywgY3VzdG9tUm9vdFVSSTogUk9PVCwgaG1hY0F1dGhTdHJhdGVneTogc3RyYXRlZ3kgfSk7XG4gICAgICAoYml0Z28gYXMgYW55KS5fdXNlciA9IHsgdXNlcm5hbWU6ICd0ZXN0QGJpdGdvLmNvbScgfTtcblxuICAgICAgc2FuZGJveC5zdHViKGJpdGdvLCAndmVyaWZ5UGFzc3dvcmQnKS5yZXNvbHZlcyh0cnVlKTtcblxuICAgICAgc2FuZGJveC5zdHViKGJpdGdvLCAna2V5Y2hhaW5zJykucmV0dXJucyh7XG4gICAgICAgIHVwZGF0ZVBhc3N3b3JkOiBzYW5kYm94LnN0dWIoKS5yZXNvbHZlcyh7IGtleWNoYWluczogeyBrMTogJ3YxZW5jJyB9LCB2ZXJzaW9uOiAyNSB9KSxcbiAgICAgIH0gYXMgYW55KTtcblxuICAgICAgc2FuZGJveC5zdHViKGJpdGdvLCAnY29pbicpLnJldHVybnMoe1xuICAgICAgICBrZXljaGFpbnM6ICgpID0+ICh7XG4gICAgICAgICAgdXBkYXRlUGFzc3dvcmQ6IHNhbmRib3guc3R1YigpLnJlc29sdmVzKHsgdjJrMTogJ3YyZW5jJyB9KSxcbiAgICAgICAgfSksXG4gICAgICB9IGFzIGFueSk7XG4gICAgfSk7XG5cbiAgICBhZnRlckVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgbm9jay5jbGVhbkFsbCgpO1xuICAgICAgc2FuZGJveC5yZXN0b3JlKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnY2FsbHMgUFVUIC91c2VyL2tleWNoYWlucyBhbmQgUE9TVCAvdXNlci9jaGFuZ2VwYXNzd29yZCB3aXRob3V0IGtleWNoYWlucyB3aGVuIGJhdGNoaW5nIGlzIGVuYWJsZWQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBub2NrKFJPT1QpXG4gICAgICAgIC5nZXQoJy9hcGkvdjIvdXNlci9jaGVja0JhdGNoaW5nUGFzc3dvcmRGbG93JylcbiAgICAgICAgLnF1ZXJ5KHRydWUpXG4gICAgICAgIC5yZXBseSgyMDAsIHsgaXNCYXRjaGluZ0Zsb3dFbmFibGVkOiB0cnVlLCBtYXhCYXRjaFNpemVLQjogOTAwIH0pO1xuXG4gICAgICBjb25zdCBiYXRjaFB1dFNjb3BlID0gbm9jayhST09UKS5wdXQoJy9hcGkvdjIvdXNlci9rZXljaGFpbnMnKS5yZXBseSgyMDAsIHt9KTtcblxuICAgICAgY29uc3QgY2hhbmdlUGFzc1Njb3BlID0gbm9jayhST09UKVxuICAgICAgICAucG9zdCgnL2FwaS92MS91c2VyL2NoYW5nZXBhc3N3b3JkJywgKGJvZHk6IGFueSkgPT4gIWJvZHkua2V5Y2hhaW5zICYmICFib2R5LnYyX2tleWNoYWlucylcbiAgICAgICAgLnJlcGx5KDIwMCwge30pO1xuXG4gICAgICBhd2FpdCBiaXRnby5jaGFuZ2VQYXNzd29yZCh7IG9sZFBhc3N3b3JkOiAnb2xkcHcnLCBuZXdQYXNzd29yZDogJ25ld3B3JyB9KTtcblxuICAgICAgYmF0Y2hQdXRTY29wZS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgICAgY2hhbmdlUGFzc1Njb3BlLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2VuZHMga2V5Y2hhaW5zIGluIHRoZSBQT1NUIGJvZHkgKGxlZ2FjeSBmbG93KSB3aGVuIHRoZSBzZXJ2ZXIgZGlzYWJsZXMgYmF0Y2hpbmcnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBub2NrKFJPT1QpLmdldCgnL2FwaS92Mi91c2VyL2NoZWNrQmF0Y2hpbmdQYXNzd29yZEZsb3cnKS5xdWVyeSh0cnVlKS5yZXBseSgyMDAsIHsgaXNCYXRjaGluZ0Zsb3dFbmFibGVkOiBmYWxzZSB9KTtcblxuICAgICAgY29uc3QgbGVnYWN5U2NvcGUgPSBub2NrKFJPT1QpXG4gICAgICAgIC5wb3N0KCcvYXBpL3YxL3VzZXIvY2hhbmdlcGFzc3dvcmQnLCAoYm9keTogYW55KSA9PiAhIWJvZHkua2V5Y2hhaW5zICYmICEhYm9keS52Ml9rZXljaGFpbnMpXG4gICAgICAgIC5yZXBseSgyMDAsIHt9KTtcblxuICAgICAgYXdhaXQgYml0Z28uY2hhbmdlUGFzc3dvcmQoeyBvbGRQYXNzd29yZDogJ29sZHB3JywgbmV3UGFzc3dvcmQ6ICduZXdwdycgfSk7XG5cbiAgICAgIGxlZ2FjeVNjb3BlLmlzRG9uZSgpLnNob3VsZC5iZS50cnVlKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnZmFsbHMgYmFjayB0byBsZWdhY3kgZmxvdyB3aGVuIHRoZSBiYXRjaGluZyBjaGVjayByZXF1ZXN0IGZhaWxzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbm9jayhST09UKS5nZXQoJy9hcGkvdjIvdXNlci9jaGVja0JhdGNoaW5nUGFzc3dvcmRGbG93JykucXVlcnkodHJ1ZSkucmVwbHkoNTAzLCB7IGVycm9yOiAnc2VydmljZSB1bmF2YWlsYWJsZScgfSk7XG5cbiAgICAgIGNvbnN0IGxlZ2FjeVNjb3BlID0gbm9jayhST09UKVxuICAgICAgICAucG9zdCgnL2FwaS92MS91c2VyL2NoYW5nZXBhc3N3b3JkJywgKGJvZHk6IGFueSkgPT4gISFib2R5LmtleWNoYWlucyAmJiAhIWJvZHkudjJfa2V5Y2hhaW5zKVxuICAgICAgICAucmVwbHkoMjAwLCB7fSk7XG5cbiAgICAgIGF3YWl0IGJpdGdvLmNoYW5nZVBhc3N3b3JkKHsgb2xkUGFzc3dvcmQ6ICdvbGRwdycsIG5ld1Bhc3N3b3JkOiAnbmV3cHcnIH0pO1xuXG4gICAgICBsZWdhY3lTY29wZS5pc0RvbmUoKS5zaG91bGQuYmUudHJ1ZSgpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnY3JlYXRlVXNlckVjZGhLZXljaGFpbiAtIGVuY3J5cHRpb25WZXJzaW9uIHRocmVhZGluZycsIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCBST09UID0gJ2h0dHBzOi8vYXBwLmJpdGdvLXRlc3QuY29tJztcbiAgICBsZXQgYml0Z286IEJpdEdvQVBJO1xuXG4gICAgYmVmb3JlRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICBiaXRnbyA9IG5ldyBCaXRHb0FQSSh7IGVudjogJ3Rlc3QnIH0pO1xuICAgIH0pO1xuXG4gICAgYWZ0ZXJFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgIG5vY2suY2xlYW5BbGwoKTtcbiAgICAgIHNpbm9uLnJlc3RvcmUoKTtcbiAgICB9KTtcblxuICAgIGl0KCdwYXNzZXMgZW5jcnlwdGlvblZlcnNpb246IDIgdG8gZW5jcnlwdCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGVuY3J5cHRBc3luY1NweSA9IHNpbm9uLnNweShiaXRnbywgJ2VuY3J5cHQnKTtcbiAgICAgIG5vY2soUk9PVCkucG9zdCgnL2FwaS92MS9rZXljaGFpbicpLnJlcGx5KDIwMCwgeyB4cHViOiAneHB1YjEyMycsIGlkOiAna2V5LWlkJyB9KTtcblxuICAgICAgYXdhaXQgYml0Z28uY3JlYXRlVXNlckVjZGhLZXljaGFpbignbG9naW5QYXNzd29yZCcsIDIpO1xuXG4gICAgICBhc3NlcnQub2soZW5jcnlwdEFzeW5jU3B5LmNhbGxlZE9uY2UpO1xuICAgICAgYXNzZXJ0LnN0cmljdEVxdWFsKGVuY3J5cHRBc3luY1NweS5maXJzdENhbGwuYXJnc1swXS5lbmNyeXB0aW9uVmVyc2lvbiwgMik7XG4gICAgfSk7XG5cbiAgICBpdCgncGFzc2VzIGVuY3J5cHRpb25WZXJzaW9uOiB1bmRlZmluZWQgd2hlbiBub3Qgc2V0IChkZWZhdWx0cyB0byB2MSknLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBlbmNyeXB0QXN5bmNTcHkgPSBzaW5vbi5zcHkoYml0Z28sICdlbmNyeXB0Jyk7XG4gICAgICBub2NrKFJPT1QpLnBvc3QoJy9hcGkvdjEva2V5Y2hhaW4nKS5yZXBseSgyMDAsIHsgeHB1YjogJ3hwdWIxMjMnLCBpZDogJ2tleS1pZCcgfSk7XG5cbiAgICAgIGF3YWl0IGJpdGdvLmNyZWF0ZVVzZXJFY2RoS2V5Y2hhaW4oJ2xvZ2luUGFzc3dvcmQnKTtcblxuICAgICAgYXNzZXJ0Lm9rKGVuY3J5cHRBc3luY1NweS5jYWxsZWRPbmNlKTtcbiAgICAgIGFzc2VydC5zdHJpY3RFcXVhbChlbmNyeXB0QXN5bmNTcHkuZmlyc3RDYWxsLmFyZ3NbMF0uZW5jcnlwdGlvblZlcnNpb24sIHVuZGVmaW5lZCk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdzcGxpdFNlY3JldCAtIGVuY3J5cHRpb25WZXJzaW9uIHRocmVhZGluZycsIGZ1bmN0aW9uICgpIHtcbiAgICBsZXQgYml0Z286IEJpdEdvQVBJO1xuXG4gICAgYmVmb3JlRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICBiaXRnbyA9IG5ldyBCaXRHb0FQSSh7IGVudjogJ3Rlc3QnIH0pO1xuICAgIH0pO1xuXG4gICAgYWZ0ZXJFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgIHNpbm9uLnJlc3RvcmUoKTtcbiAgICB9KTtcblxuICAgIGl0KCdwYXNzZXMgZW5jcnlwdGlvblZlcnNpb246IDIgdG8gZXZlcnkgZW5jcnlwdCBzaGFyZCBjYWxsJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgZW5jcnlwdEFzeW5jU3B5ID0gc2lub24uc3B5KGJpdGdvLCAnZW5jcnlwdCcpO1xuICAgICAgY29uc3QgcGFzc3dvcmRzID0gWydwdzEnLCAncHcyJywgJ3B3MyddO1xuXG4gICAgICBhd2FpdCBiaXRnby5zcGxpdFNlY3JldCh7XG4gICAgICAgIHNlZWQ6ICdhJy5yZXBlYXQoNjQpLFxuICAgICAgICBwYXNzd29yZHMsXG4gICAgICAgIG06IDIsXG4gICAgICAgIGVuY3J5cHRpb25WZXJzaW9uOiAyLFxuICAgICAgfSk7XG5cbiAgICAgIGFzc2VydC5zdHJpY3RFcXVhbChlbmNyeXB0QXN5bmNTcHkuY2FsbENvdW50LCAzLCAnc2hvdWxkIGVuY3J5cHQgZWFjaCBzaGFyZCcpO1xuICAgICAgZm9yIChjb25zdCBjYWxsIG9mIGVuY3J5cHRBc3luY1NweS5nZXRDYWxscygpKSB7XG4gICAgICAgIGFzc2VydC5zdHJpY3RFcXVhbChjYWxsLmFyZ3NbMF0uZW5jcnlwdGlvblZlcnNpb24sIDIpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgaXQoJ3Bhc3NlcyBlbmNyeXB0aW9uVmVyc2lvbjogdW5kZWZpbmVkIHdoZW4gbm90IHNldCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGVuY3J5cHRBc3luY1NweSA9IHNpbm9uLnNweShiaXRnbywgJ2VuY3J5cHQnKTtcblxuICAgICAgYXdhaXQgYml0Z28uc3BsaXRTZWNyZXQoe1xuICAgICAgICBzZWVkOiAnYicucmVwZWF0KDY0KSxcbiAgICAgICAgcGFzc3dvcmRzOiBbJ3B3MScsICdwdzInXSxcbiAgICAgICAgbTogMixcbiAgICAgIH0pO1xuXG4gICAgICBhc3NlcnQuc3RyaWN0RXF1YWwoZW5jcnlwdEFzeW5jU3B5LmNhbGxDb3VudCwgMik7XG4gICAgICBmb3IgKGNvbnN0IGNhbGwgb2YgZW5jcnlwdEFzeW5jU3B5LmdldENhbGxzKCkpIHtcbiAgICAgICAgYXNzZXJ0LnN0cmljdEVxdWFsKGNhbGwuYXJnc1swXS5lbmNyeXB0aW9uVmVyc2lvbiwgdW5kZWZpbmVkKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfSk7XG59KTtcbiJdfQ==
|