@bitgo/sdk-coin-eos 1.0.1-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +5 -0
- package/.mocharc.yml +8 -0
- package/CHANGELOG.md +8 -0
- package/LICENSE +191 -0
- package/README.md +30 -0
- package/dist/src/eos.d.ts +279 -0
- package/dist/src/eos.d.ts.map +1 -0
- package/dist/src/eos.js +872 -0
- package/dist/src/eosToken.d.ts +34 -0
- package/dist/src/eosToken.d.ts.map +1 -0
- package/dist/src/eosToken.js +68 -0
- package/dist/src/eosutil/eosabiprovider.d.ts +8 -0
- package/dist/src/eosutil/eosabiprovider.d.ts.map +1 -0
- package/dist/src/eosutil/eosabiprovider.js +30 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +17 -0
- package/dist/src/lib/address.d.ts +5 -0
- package/dist/src/lib/address.d.ts.map +1 -0
- package/dist/src/lib/address.js +7 -0
- package/dist/src/lib/enum.d.ts +5 -0
- package/dist/src/lib/enum.d.ts.map +1 -0
- package/dist/src/lib/enum.js +10 -0
- package/dist/src/lib/iface.d.ts +1 -0
- package/dist/src/lib/iface.d.ts.map +1 -0
- package/dist/src/lib/iface.js +1 -0
- package/dist/src/lib/index.d.ts +6 -0
- package/dist/src/lib/index.d.ts.map +1 -0
- package/dist/src/lib/index.js +17 -0
- package/dist/src/lib/keyPair.d.ts +18 -0
- package/dist/src/lib/keyPair.d.ts.map +1 -0
- package/dist/src/lib/keyPair.js +41 -0
- package/dist/src/lib/transaction.d.ts +7 -0
- package/dist/src/lib/transaction.d.ts.map +1 -0
- package/dist/src/lib/transaction.js +17 -0
- package/dist/src/lib/transactionBuilder.d.ts +15 -0
- package/dist/src/lib/transactionBuilder.d.ts.map +1 -0
- package/dist/src/lib/transactionBuilder.js +38 -0
- package/dist/src/lib/transactionBuilderFactory.d.ts +7 -0
- package/dist/src/lib/transactionBuilderFactory.d.ts.map +1 -0
- package/dist/src/lib/transactionBuilderFactory.js +17 -0
- package/dist/src/lib/utils.d.ts +8 -0
- package/dist/src/lib/utils.d.ts.map +1 -0
- package/dist/src/lib/utils.js +24 -0
- package/dist/src/teos.d.ts +10 -0
- package/dist/src/teos.d.ts.map +1 -0
- package/dist/src/teos.js +24 -0
- package/package.json +59 -0
package/dist/src/eos.js
ADDED
|
@@ -0,0 +1,872 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
10
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
11
|
+
}) : function(o, v) {
|
|
12
|
+
o["default"] = v;
|
|
13
|
+
});
|
|
14
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
15
|
+
if (mod && mod.__esModule) return mod;
|
|
16
|
+
var result = {};
|
|
17
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
18
|
+
__setModuleDefault(result, mod);
|
|
19
|
+
return result;
|
|
20
|
+
};
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.Eos = void 0;
|
|
23
|
+
/**
|
|
24
|
+
* @prettier
|
|
25
|
+
*/
|
|
26
|
+
const bignumber_js_1 = require("bignumber.js");
|
|
27
|
+
const bip32 = __importStar(require("bip32"));
|
|
28
|
+
const crypto_1 = require("crypto");
|
|
29
|
+
const eosjs_1 = require("eosjs");
|
|
30
|
+
const ecc = __importStar(require("eosjs-ecc"));
|
|
31
|
+
const _ = __importStar(require("lodash"));
|
|
32
|
+
const querystring = __importStar(require("querystring"));
|
|
33
|
+
const request = __importStar(require("superagent"));
|
|
34
|
+
const url = __importStar(require("url"));
|
|
35
|
+
const eosabiprovider_1 = require("./eosutil/eosabiprovider");
|
|
36
|
+
const utils_1 = require("./lib/utils");
|
|
37
|
+
const sdk_core_1 = require("@bitgo/sdk-core");
|
|
38
|
+
class NoopJsonRpc extends eosjs_1.JsonRpc {
|
|
39
|
+
constructor() {
|
|
40
|
+
super('');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
class NoopSignatureProvider {
|
|
44
|
+
async getAvailableKeys() {
|
|
45
|
+
throw new Error('noop signature provider implementation has no available keys');
|
|
46
|
+
}
|
|
47
|
+
async sign(args) {
|
|
48
|
+
throw new Error('noop implementation is unable to sign');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
class Eos extends sdk_core_1.BaseCoin {
|
|
52
|
+
static createInstance(bitgo) {
|
|
53
|
+
return new Eos(bitgo);
|
|
54
|
+
}
|
|
55
|
+
getChainId() {
|
|
56
|
+
return 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906'; // mainnet chain id
|
|
57
|
+
}
|
|
58
|
+
getChain() {
|
|
59
|
+
return 'eos';
|
|
60
|
+
}
|
|
61
|
+
getFamily() {
|
|
62
|
+
return 'eos';
|
|
63
|
+
}
|
|
64
|
+
getFullName() {
|
|
65
|
+
return 'EOS';
|
|
66
|
+
}
|
|
67
|
+
getBaseFactor() {
|
|
68
|
+
return 1e4;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Flag for sending value of 0
|
|
72
|
+
* @returns {boolean} True if okay to send 0 value, false otherwise
|
|
73
|
+
*/
|
|
74
|
+
valuelessTransferAllowed() {
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get URLs of some active public nodes
|
|
79
|
+
*/
|
|
80
|
+
getPublicNodeUrls() {
|
|
81
|
+
return sdk_core_1.Environments[this.bitgo.getEnv()].eosNodeUrls;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Generate secp256k1 key pair
|
|
85
|
+
*
|
|
86
|
+
* @param seed - Seed from which the new keypair should be generated, otherwise a random seed is used
|
|
87
|
+
*/
|
|
88
|
+
generateKeyPair(seed) {
|
|
89
|
+
if (!seed) {
|
|
90
|
+
// An extended private key has both a normal 256 bit private key and a 256
|
|
91
|
+
// bit chain code, both of which must be random. 512 bits is therefore the
|
|
92
|
+
// maximum entropy and gives us maximum security against cracking.
|
|
93
|
+
seed = crypto_1.randomBytes(512 / 8);
|
|
94
|
+
}
|
|
95
|
+
const extendedKey = bip32.fromSeed(seed);
|
|
96
|
+
const xpub = extendedKey.neutered().toBase58();
|
|
97
|
+
return {
|
|
98
|
+
pub: xpub,
|
|
99
|
+
prv: extendedKey.toBase58(),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Return boolean indicating whether input is valid public key for the coin.
|
|
104
|
+
*
|
|
105
|
+
* @param pub - the pub to be checked
|
|
106
|
+
*/
|
|
107
|
+
isValidPub(pub) {
|
|
108
|
+
try {
|
|
109
|
+
return bip32.fromBase58(pub).isNeutered();
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Return boolean indicating whether input is valid seed for the coin
|
|
117
|
+
*
|
|
118
|
+
* @param prv - the prv to be checked
|
|
119
|
+
*/
|
|
120
|
+
isValidPrv(prv) {
|
|
121
|
+
try {
|
|
122
|
+
return !bip32.fromBase58(prv).isNeutered();
|
|
123
|
+
}
|
|
124
|
+
catch (e) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Evaluates whether a memo is valid
|
|
130
|
+
*
|
|
131
|
+
* @param value - the memo to be checked
|
|
132
|
+
*/
|
|
133
|
+
isValidMemo({ value }) {
|
|
134
|
+
return _.isString(value) && value.length <= 256;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Return boolean indicating whether a memo id is valid
|
|
138
|
+
*
|
|
139
|
+
* @param memoId - the memo id to be checked
|
|
140
|
+
*/
|
|
141
|
+
isValidMemoId(memoId) {
|
|
142
|
+
return this.isValidMemo({ value: memoId });
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Process address into address and memo id
|
|
146
|
+
* @param address - the address
|
|
147
|
+
*/
|
|
148
|
+
getAddressDetails(address) {
|
|
149
|
+
const destinationDetails = url.parse(address);
|
|
150
|
+
const destinationAddress = destinationDetails.pathname;
|
|
151
|
+
if (!destinationAddress) {
|
|
152
|
+
throw new sdk_core_1.InvalidAddressError(`failed to parse address: ${address}`);
|
|
153
|
+
}
|
|
154
|
+
// EOS addresses have to be "human readable", which means up to 12 characters and only a-z1-5., i.e.mtoda1.bitgo
|
|
155
|
+
// source: https://developers.eos.io/eosio-cpp/docs/naming-conventions
|
|
156
|
+
if (!/^[a-z1-5.]*$/.test(destinationAddress) || destinationAddress.length > Eos.ADDRESS_LENGTH) {
|
|
157
|
+
throw new sdk_core_1.InvalidAddressError(`invalid address: ${address}`);
|
|
158
|
+
}
|
|
159
|
+
// address doesn't have a memo id
|
|
160
|
+
if (destinationDetails.pathname === address) {
|
|
161
|
+
return {
|
|
162
|
+
address: address,
|
|
163
|
+
memoId: undefined,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
if (!destinationDetails.query) {
|
|
167
|
+
throw new sdk_core_1.InvalidAddressError(`failed to parse query string: ${address}`);
|
|
168
|
+
}
|
|
169
|
+
const queryDetails = querystring.parse(destinationDetails.query);
|
|
170
|
+
if (!queryDetails.memoId) {
|
|
171
|
+
// if there are more properties, the query details need to contain the memoId property
|
|
172
|
+
throw new sdk_core_1.InvalidAddressError(`invalid property in address: ${address}`);
|
|
173
|
+
}
|
|
174
|
+
if (Array.isArray(queryDetails.memoId) && queryDetails.memoId.length !== 1) {
|
|
175
|
+
// valid addresses can only contain one memo id
|
|
176
|
+
throw new sdk_core_1.InvalidAddressError(`invalid address '${address}', must contain exactly one memoId`);
|
|
177
|
+
}
|
|
178
|
+
const [memoId] = _.castArray(queryDetails.memoId);
|
|
179
|
+
if (!this.isValidMemoId(memoId)) {
|
|
180
|
+
throw new sdk_core_1.InvalidAddressError(`invalid address: '${address}', memoId is not valid`);
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
address: destinationAddress,
|
|
184
|
+
memoId,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Convert a currency amount represented in base units (satoshi, wei, atoms, drops, stroops)
|
|
189
|
+
* to big units (btc, eth, xrp, xlm)
|
|
190
|
+
*/
|
|
191
|
+
baseUnitsToBigUnits(baseUnits) {
|
|
192
|
+
const dividend = this.getBaseFactor();
|
|
193
|
+
const bigNumber = new bignumber_js_1.BigNumber(baseUnits).dividedBy(dividend);
|
|
194
|
+
// set the format so commas aren't added to large coin amounts
|
|
195
|
+
return bigNumber.toFormat(4, null, { groupSeparator: '', decimalSeparator: '.' });
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Validate and return address with appended memo id
|
|
199
|
+
*
|
|
200
|
+
* @param address
|
|
201
|
+
* @param memoId
|
|
202
|
+
*/
|
|
203
|
+
normalizeAddress({ address, memoId }) {
|
|
204
|
+
if (memoId && this.isValidMemoId(memoId)) {
|
|
205
|
+
return `${address}?memoId=${memoId}`;
|
|
206
|
+
}
|
|
207
|
+
return address;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Return boolean indicating whether input is valid public key for the coin
|
|
211
|
+
*
|
|
212
|
+
* @param address - the address to be checked
|
|
213
|
+
*/
|
|
214
|
+
isValidAddress(address) {
|
|
215
|
+
try {
|
|
216
|
+
const addressDetails = this.getAddressDetails(address);
|
|
217
|
+
return address === this.normalizeAddress(addressDetails);
|
|
218
|
+
}
|
|
219
|
+
catch (e) {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* @param address - the address to verify
|
|
225
|
+
* @param rootAddress - the wallet's root address
|
|
226
|
+
* @return true iff address is a wallet address (based on rootAddress)
|
|
227
|
+
*/
|
|
228
|
+
isWalletAddress({ address, rootAddress }) {
|
|
229
|
+
if (!rootAddress || !_.isString(rootAddress)) {
|
|
230
|
+
throw new Error('missing required string rootAddress');
|
|
231
|
+
}
|
|
232
|
+
if (!this.isValidAddress(address)) {
|
|
233
|
+
throw new sdk_core_1.InvalidAddressError(`invalid address: ${address}`);
|
|
234
|
+
}
|
|
235
|
+
const addressDetails = this.getAddressDetails(address);
|
|
236
|
+
const rootAddressDetails = this.getAddressDetails(rootAddress);
|
|
237
|
+
if (!addressDetails || !rootAddressDetails) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
if (addressDetails.address !== rootAddressDetails.address) {
|
|
241
|
+
throw new sdk_core_1.UnexpectedAddressError(`address validation failure: ${addressDetails.address} vs ${rootAddressDetails.address}`);
|
|
242
|
+
}
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Assemble keychain and half-sign prebuilt transaction
|
|
247
|
+
*
|
|
248
|
+
* @param params
|
|
249
|
+
* @param params.txPrebuild {Object} prebuild object returned by platform
|
|
250
|
+
* @param params.prv {String} user prv
|
|
251
|
+
* @returns {Promise<EosSignedTransaction>}
|
|
252
|
+
*/
|
|
253
|
+
async signTransaction(params) {
|
|
254
|
+
const prv = params.prv;
|
|
255
|
+
const txHex = params.txPrebuild.txHex;
|
|
256
|
+
const transaction = params.txPrebuild.transaction;
|
|
257
|
+
const signBuffer = Buffer.from(txHex, 'hex');
|
|
258
|
+
const privateKeyBuffer = bip32.fromBase58(prv).privateKey;
|
|
259
|
+
if (!privateKeyBuffer) {
|
|
260
|
+
throw new Error('no privateKey');
|
|
261
|
+
}
|
|
262
|
+
const signature = ecc.Signature.sign(signBuffer, privateKeyBuffer).toString();
|
|
263
|
+
transaction.signatures.push(signature);
|
|
264
|
+
const txParams = {
|
|
265
|
+
transaction,
|
|
266
|
+
txHex,
|
|
267
|
+
recipients: params.txPrebuild.recipients,
|
|
268
|
+
headers: params.txPrebuild.headers,
|
|
269
|
+
txid: params.txPrebuild.txid,
|
|
270
|
+
};
|
|
271
|
+
return { halfSigned: txParams };
|
|
272
|
+
}
|
|
273
|
+
validateStakeActionData(stakeActionData) {
|
|
274
|
+
if (stakeActionData.from !== stakeActionData.receiver) {
|
|
275
|
+
throw new Error(`staker (${stakeActionData.from}) and receiver (${stakeActionData.receiver}) must be the same`);
|
|
276
|
+
}
|
|
277
|
+
if (stakeActionData.transfer !== 0) {
|
|
278
|
+
throw new Error('cannot transfer funds as part of delegatebw action');
|
|
279
|
+
}
|
|
280
|
+
// stake_cpu_quantity is used as the amount because the BitGo platform only stakes cpu for voting transactions
|
|
281
|
+
return {
|
|
282
|
+
address: stakeActionData.from,
|
|
283
|
+
amount: this.bigUnitsToBaseUnits(stakeActionData.stake_cpu_quantity.split(' ')[0]),
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
validateUnstakeActionData(unstakeActionData) {
|
|
287
|
+
if (unstakeActionData.from !== unstakeActionData.receiver) {
|
|
288
|
+
throw new Error(`unstaker (${unstakeActionData.from}) and receiver (${unstakeActionData.receiver}) must be the same`);
|
|
289
|
+
}
|
|
290
|
+
const cpuAmount = new bignumber_js_1.BigNumber(unstakeActionData.unstake_cpu_quantity.split(' ')[0]);
|
|
291
|
+
const netAmount = new bignumber_js_1.BigNumber(unstakeActionData.unstake_net_quantity.split(' ')[0]);
|
|
292
|
+
const totalAmount = cpuAmount.plus(netAmount).toNumber();
|
|
293
|
+
return {
|
|
294
|
+
address: unstakeActionData.receiver,
|
|
295
|
+
amount: this.bigUnitsToBaseUnits(totalAmount),
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
static validateVoteActionData(voteActionData) {
|
|
299
|
+
const proxyIsEmpty = _.isEmpty(voteActionData.proxy);
|
|
300
|
+
const producersIsEmpty = _.isEmpty(voteActionData.producers);
|
|
301
|
+
if ((proxyIsEmpty && producersIsEmpty) || (!proxyIsEmpty && !producersIsEmpty)) {
|
|
302
|
+
throw new Error('voting transactions must specify either producers or proxy to vote for');
|
|
303
|
+
}
|
|
304
|
+
return {
|
|
305
|
+
address: voteActionData.voter,
|
|
306
|
+
proxy: voteActionData.proxy,
|
|
307
|
+
producers: voteActionData.producers,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
static createTransactionIdHex(serializedTransactionBuffer) {
|
|
311
|
+
return crypto_1.createHash('sha256').update(serializedTransactionBuffer).digest().toString('hex');
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Deserialize a transaction
|
|
315
|
+
* @param transaction
|
|
316
|
+
* @param headers
|
|
317
|
+
*/
|
|
318
|
+
async deserializeTransaction({ transaction, headers, }) {
|
|
319
|
+
// create an eosjs API client
|
|
320
|
+
const api = new eosjs_1.Api({
|
|
321
|
+
abiProvider: new eosabiprovider_1.OfflineAbiProvider(),
|
|
322
|
+
rpc: new NoopJsonRpc(),
|
|
323
|
+
signatureProvider: new NoopSignatureProvider(),
|
|
324
|
+
chainId: this.getChainId(),
|
|
325
|
+
// Use a custom TextDecoder as the global TextDecoder leads to crashes in OVC / Electron.
|
|
326
|
+
textDecoder: new utils_1.StringTextDecoder(),
|
|
327
|
+
textEncoder: new TextEncoder(),
|
|
328
|
+
});
|
|
329
|
+
// type guards
|
|
330
|
+
const isTransferActionData = (txActionData) => {
|
|
331
|
+
return (txActionData.from !== undefined &&
|
|
332
|
+
txActionData.to !== undefined &&
|
|
333
|
+
txActionData.quantity !== undefined);
|
|
334
|
+
};
|
|
335
|
+
const isStakeActionData = (txActionData) => {
|
|
336
|
+
return (txActionData.from !== undefined &&
|
|
337
|
+
txActionData.receiver !== undefined &&
|
|
338
|
+
txActionData.transfer !== undefined &&
|
|
339
|
+
txActionData.stake_cpu_quantity !== undefined);
|
|
340
|
+
};
|
|
341
|
+
const isUnstakeActionData = (txActionData) => {
|
|
342
|
+
return (txActionData.from !== undefined &&
|
|
343
|
+
txActionData.receiver !== undefined &&
|
|
344
|
+
txActionData.unstake_cpu_quantity !== undefined &&
|
|
345
|
+
txActionData.unstake_net_quantity !== undefined);
|
|
346
|
+
};
|
|
347
|
+
const isVoteActionData = (txActionData) => {
|
|
348
|
+
return txActionData.voter !== undefined;
|
|
349
|
+
};
|
|
350
|
+
const isRefundActionData = (txActionData) => {
|
|
351
|
+
return txActionData.owner !== undefined;
|
|
352
|
+
};
|
|
353
|
+
// deserializeTransaction
|
|
354
|
+
const serializedTxBuffer = Buffer.from(transaction.packed_trx, 'hex');
|
|
355
|
+
const deserializedTxJsonFromPackedTrx = await api.deserializeTransactionWithActions(serializedTxBuffer);
|
|
356
|
+
if (!deserializedTxJsonFromPackedTrx) {
|
|
357
|
+
throw new Error('could not process transaction from txHex');
|
|
358
|
+
}
|
|
359
|
+
const tx = deserializedTxJsonFromPackedTrx;
|
|
360
|
+
// validate context free actions
|
|
361
|
+
if (tx.context_free_actions.length !== 0) {
|
|
362
|
+
if (tx.context_free_actions.length !== 1) {
|
|
363
|
+
throw new Error('number of context free actions must be 1');
|
|
364
|
+
}
|
|
365
|
+
if (!_.isEqual(_.pick(tx.context_free_actions[0], ['account', 'authorization', 'name']), {
|
|
366
|
+
account: 'eosio.null',
|
|
367
|
+
authorization: [],
|
|
368
|
+
name: 'nonce',
|
|
369
|
+
}) ||
|
|
370
|
+
_.isEmpty(tx.context_free_actions[0].data)) {
|
|
371
|
+
throw new Error('the context free action is invalid');
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
// Only support transactions with one (transfer | voteproducer) or two (delegatebw & voteproducer) actions
|
|
375
|
+
if (tx.actions.length !== 1 && tx.actions.length !== 2) {
|
|
376
|
+
throw new Error(`invalid number of actions: ${tx.actions.length}`);
|
|
377
|
+
}
|
|
378
|
+
const txAction = tx.actions[0];
|
|
379
|
+
if (!txAction) {
|
|
380
|
+
throw new Error('missing transaction action');
|
|
381
|
+
}
|
|
382
|
+
if (txAction.name === 'transfer') {
|
|
383
|
+
// Transfers should only have 1 action
|
|
384
|
+
if (tx.actions.length !== 1) {
|
|
385
|
+
throw new Error(`transfers should only have 1 action: ${tx.actions.length} given`);
|
|
386
|
+
}
|
|
387
|
+
if (!isTransferActionData(txAction.data)) {
|
|
388
|
+
throw new Error('Invalid or incomplete transfer action data');
|
|
389
|
+
}
|
|
390
|
+
const transferActionData = txAction.data;
|
|
391
|
+
tx.address = transferActionData.to;
|
|
392
|
+
tx.amount = this.bigUnitsToBaseUnits(transferActionData.quantity.split(' ')[0]);
|
|
393
|
+
tx.memo = transferActionData.memo;
|
|
394
|
+
}
|
|
395
|
+
else if (txAction.name === 'delegatebw') {
|
|
396
|
+
// The delegatebw action should only be part of voting transactions
|
|
397
|
+
if (tx.actions.length !== 2) {
|
|
398
|
+
throw new Error(`staking transactions that include the delegatebw action should have 2 actions: ${tx.actions.length} given`);
|
|
399
|
+
}
|
|
400
|
+
const txAction2 = tx.actions[1];
|
|
401
|
+
if (txAction2.name !== 'voteproducer') {
|
|
402
|
+
throw new Error(`invalid staking transaction action: ${txAction2.name}, expecting: voteproducer`);
|
|
403
|
+
}
|
|
404
|
+
if (!isStakeActionData(txAction.data) || !isVoteActionData(txAction2.data)) {
|
|
405
|
+
throw new Error('Invalid or incomplete stake or vote action data');
|
|
406
|
+
}
|
|
407
|
+
const stakeActionData = txAction.data;
|
|
408
|
+
const voteActionData = txAction2.data;
|
|
409
|
+
const deserializedStakeAction = this.validateStakeActionData(stakeActionData);
|
|
410
|
+
const deserializedVoteAction = Eos.validateVoteActionData(voteActionData);
|
|
411
|
+
if (deserializedStakeAction.address !== deserializedVoteAction.address) {
|
|
412
|
+
throw new Error(`staker (${deserializedStakeAction.address}) and voter (${deserializedVoteAction.address}) must be the same`);
|
|
413
|
+
}
|
|
414
|
+
tx.amount = deserializedStakeAction.amount;
|
|
415
|
+
tx.proxy = deserializedVoteAction.proxy;
|
|
416
|
+
tx.producers = deserializedVoteAction.producers;
|
|
417
|
+
}
|
|
418
|
+
else if (txAction.name === 'voteproducer') {
|
|
419
|
+
if (tx.actions.length > 2) {
|
|
420
|
+
throw new Error('voting transactions should not have more than 2 actions');
|
|
421
|
+
}
|
|
422
|
+
let deserializedStakeAction;
|
|
423
|
+
if (tx.actions.length === 2) {
|
|
424
|
+
const txAction2 = tx.actions[1];
|
|
425
|
+
if (txAction2.name !== 'delegatebw') {
|
|
426
|
+
throw new Error(`invalid staking transaction action: ${txAction2.name}, expecting: delegatebw`);
|
|
427
|
+
}
|
|
428
|
+
if (!isStakeActionData(txAction.data)) {
|
|
429
|
+
throw new Error('Invalid or incomplete stake action data');
|
|
430
|
+
}
|
|
431
|
+
const stakeActionData = txAction.data;
|
|
432
|
+
deserializedStakeAction = this.validateStakeActionData(stakeActionData);
|
|
433
|
+
}
|
|
434
|
+
if (!isVoteActionData(txAction.data)) {
|
|
435
|
+
throw new Error('Invalid or incomplete vote action data');
|
|
436
|
+
}
|
|
437
|
+
const voteActionData = txAction.data;
|
|
438
|
+
const deserializedVoteAction = Eos.validateVoteActionData(voteActionData);
|
|
439
|
+
if (!!deserializedStakeAction && deserializedStakeAction.address !== deserializedVoteAction.address) {
|
|
440
|
+
throw new Error(`staker (${deserializedStakeAction.address}) and voter (${deserializedVoteAction.address}) must be the same`);
|
|
441
|
+
}
|
|
442
|
+
tx.amount = !!deserializedStakeAction ? deserializedStakeAction.amount : '0';
|
|
443
|
+
tx.proxy = deserializedVoteAction.proxy;
|
|
444
|
+
tx.producers = deserializedVoteAction.producers;
|
|
445
|
+
}
|
|
446
|
+
else if (txAction.name === 'undelegatebw') {
|
|
447
|
+
if (tx.actions.length !== 1) {
|
|
448
|
+
throw new Error(`unstake should only have 1 action: ${tx.actions.length} given`);
|
|
449
|
+
}
|
|
450
|
+
if (!isUnstakeActionData(txAction.data)) {
|
|
451
|
+
throw new Error('Invalid or incomplete unstake action data');
|
|
452
|
+
}
|
|
453
|
+
const unstakeActionData = txAction.data;
|
|
454
|
+
const deserializedUnstakeAction = this.validateUnstakeActionData(unstakeActionData);
|
|
455
|
+
tx.amount = deserializedUnstakeAction.amount;
|
|
456
|
+
tx.address = deserializedUnstakeAction.address;
|
|
457
|
+
}
|
|
458
|
+
else if (txAction.name === 'refund') {
|
|
459
|
+
if (tx.actions.length !== 1) {
|
|
460
|
+
throw new Error(`refund should only have 1 action: ${tx.actions.length} given`);
|
|
461
|
+
}
|
|
462
|
+
if (!isRefundActionData(txAction.data)) {
|
|
463
|
+
throw new Error('Invalid or incomplete refund action data');
|
|
464
|
+
}
|
|
465
|
+
const refundActionData = txAction.data;
|
|
466
|
+
tx.address = refundActionData.owner;
|
|
467
|
+
tx.amount = '0';
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
throw new Error(`invalid action: ${txAction.name}`);
|
|
471
|
+
}
|
|
472
|
+
// Get the tx id if tx headers were provided
|
|
473
|
+
if (headers) {
|
|
474
|
+
let rebuiltTransaction;
|
|
475
|
+
try {
|
|
476
|
+
// remove Z at the end
|
|
477
|
+
if (headers.expiration.endsWith('Z')) {
|
|
478
|
+
headers.expiration = headers.expiration.slice(0, -1);
|
|
479
|
+
}
|
|
480
|
+
rebuiltTransaction = await api.transact({ ...tx, ...headers }, { sign: false, broadcast: false });
|
|
481
|
+
}
|
|
482
|
+
catch (e) {
|
|
483
|
+
throw new Error('Could not build transaction to get transaction_id. Please check transaction or headers format.');
|
|
484
|
+
}
|
|
485
|
+
tx.transaction_id = Eos.createTransactionIdHex(rebuiltTransaction.serializedTransaction);
|
|
486
|
+
}
|
|
487
|
+
return tx;
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Explain/parse transaction
|
|
491
|
+
* @param params - ExplainTransactionOptions
|
|
492
|
+
*/
|
|
493
|
+
async explainTransaction(params) {
|
|
494
|
+
let transaction;
|
|
495
|
+
try {
|
|
496
|
+
transaction = await this.deserializeTransaction(params);
|
|
497
|
+
}
|
|
498
|
+
catch (e) {
|
|
499
|
+
throw new Error('invalid EOS transaction or headers: ' + e.toString());
|
|
500
|
+
}
|
|
501
|
+
return {
|
|
502
|
+
displayOrder: [
|
|
503
|
+
'id',
|
|
504
|
+
'outputAmount',
|
|
505
|
+
'changeAmount',
|
|
506
|
+
'outputs',
|
|
507
|
+
'changeOutputs',
|
|
508
|
+
'fee',
|
|
509
|
+
'memo',
|
|
510
|
+
'proxy',
|
|
511
|
+
'producers',
|
|
512
|
+
],
|
|
513
|
+
id: transaction.transaction_id,
|
|
514
|
+
changeOutputs: [],
|
|
515
|
+
outputAmount: transaction.amount,
|
|
516
|
+
changeAmount: 0,
|
|
517
|
+
outputs: !!transaction.address ? [{ address: transaction.address, amount: transaction.amount }] : [],
|
|
518
|
+
fee: {},
|
|
519
|
+
memo: transaction.memo,
|
|
520
|
+
proxy: transaction.proxy,
|
|
521
|
+
producers: transaction.producers,
|
|
522
|
+
};
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* @deprecated
|
|
526
|
+
*/
|
|
527
|
+
initiateRecovery(params) {
|
|
528
|
+
throw new Error('deprecated method');
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Make a request to one of the public EOS nodes available
|
|
532
|
+
* @param params.endpoint
|
|
533
|
+
* @param params.payload
|
|
534
|
+
*/
|
|
535
|
+
async getDataFromNode(params) {
|
|
536
|
+
const nodeUrls = this.getPublicNodeUrls();
|
|
537
|
+
for (const nodeUrl of nodeUrls) {
|
|
538
|
+
try {
|
|
539
|
+
return await request.post(nodeUrl + params.endpoint).send(params.payload);
|
|
540
|
+
}
|
|
541
|
+
catch (e) {
|
|
542
|
+
// let's hope another call succeeds
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
throw new Error(`Unable to call endpoint: ${params.endpoint} from nodes: ${_.join(nodeUrls, ', ')}`);
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Get EOS chain info from a public node
|
|
549
|
+
*/
|
|
550
|
+
async getChainInfoFromNode() {
|
|
551
|
+
const response = await this.getDataFromNode({ endpoint: '/v1/chain/get_info' });
|
|
552
|
+
if (response.status !== 200) {
|
|
553
|
+
throw new Error('Unable to fetch chain info');
|
|
554
|
+
}
|
|
555
|
+
return response.body;
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Get data specific to an account from a public node
|
|
559
|
+
* @param address
|
|
560
|
+
*/
|
|
561
|
+
async getAccountFromNode({ address }) {
|
|
562
|
+
const response = await this.getDataFromNode({
|
|
563
|
+
endpoint: '/v1/chain/get_account',
|
|
564
|
+
payload: { account_name: address },
|
|
565
|
+
});
|
|
566
|
+
if (response.status !== 200) {
|
|
567
|
+
throw new Error('Account not found');
|
|
568
|
+
}
|
|
569
|
+
return response.body;
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Get block data from a public node using its block number or block id
|
|
573
|
+
* @param blockNumOrId
|
|
574
|
+
*/
|
|
575
|
+
async getBlockFromNode({ blockNumOrId }) {
|
|
576
|
+
const response = await this.getDataFromNode({
|
|
577
|
+
endpoint: '/v1/chain/get_block',
|
|
578
|
+
payload: { block_num_or_id: blockNumOrId },
|
|
579
|
+
});
|
|
580
|
+
if (response.status !== 200) {
|
|
581
|
+
throw new Error('Block not found');
|
|
582
|
+
}
|
|
583
|
+
return response.body;
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Get headers for an EOS tx from a public node
|
|
587
|
+
*/
|
|
588
|
+
async getTransactionHeadersFromNode() {
|
|
589
|
+
const chainInfo = await this.getChainInfoFromNode();
|
|
590
|
+
const headBlockInfoResult = await this.getBlockFromNode({ blockNumOrId: chainInfo.head_block_num });
|
|
591
|
+
const expireSeconds = 28800; // maximum tx expire time of 8h
|
|
592
|
+
const chainDate = new Date(chainInfo.head_block_time + 'Z').getTime();
|
|
593
|
+
const expirationDate = new Date(chainDate + expireSeconds * 1000);
|
|
594
|
+
return {
|
|
595
|
+
expiration: expirationDate.toISOString(),
|
|
596
|
+
ref_block_num: chainInfo.head_block_num & 0xffff,
|
|
597
|
+
ref_block_prefix: headBlockInfoResult.ref_block_prefix,
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
getTransferAction({ recipient, sender, amount, memo }) {
|
|
601
|
+
return {
|
|
602
|
+
account: 'eosio.token',
|
|
603
|
+
name: 'transfer',
|
|
604
|
+
authorization: [
|
|
605
|
+
{
|
|
606
|
+
actor: sender,
|
|
607
|
+
permission: 'active',
|
|
608
|
+
},
|
|
609
|
+
],
|
|
610
|
+
data: {
|
|
611
|
+
from: sender,
|
|
612
|
+
to: recipient,
|
|
613
|
+
quantity: `${this.baseUnitsToBigUnits(amount)} EOS`,
|
|
614
|
+
memo: !_.isNil(memo) ? memo : '', // Memo must be defined, set it to empty string if it is not
|
|
615
|
+
},
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Sign a transaction with a key
|
|
620
|
+
* @param signableTx
|
|
621
|
+
* @param signingKey
|
|
622
|
+
*/
|
|
623
|
+
signTx(signableTx, signingKey) {
|
|
624
|
+
const signBuffer = Buffer.from(signableTx, 'hex');
|
|
625
|
+
const privateKeyBuffer = signingKey.privateKey;
|
|
626
|
+
return ecc.Signature.sign(signBuffer, privateKeyBuffer).toString();
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Builds a funds recovery transaction without BitGo
|
|
630
|
+
* @param params
|
|
631
|
+
*/
|
|
632
|
+
async recover(params) {
|
|
633
|
+
if (!params.rootAddress) {
|
|
634
|
+
throw new Error('missing required string rootAddress');
|
|
635
|
+
}
|
|
636
|
+
const isKrsRecovery = sdk_core_1.getIsKrsRecovery(params);
|
|
637
|
+
const isUnsignedSweep = sdk_core_1.getIsUnsignedSweep(params);
|
|
638
|
+
const { krsProvider } = params;
|
|
639
|
+
if (sdk_core_1.getIsKrsRecovery(params)) {
|
|
640
|
+
sdk_core_1.checkKrsProvider(this, krsProvider);
|
|
641
|
+
}
|
|
642
|
+
if (!this.isValidAddress(params.recoveryDestination)) {
|
|
643
|
+
throw new Error('Invalid destination address!');
|
|
644
|
+
}
|
|
645
|
+
const keys = sdk_core_1.getBip32Keys(this.bitgo, params, { requireBitGoXpub: false });
|
|
646
|
+
const rootAddressDetails = this.getAddressDetails(params.rootAddress);
|
|
647
|
+
const account = await this.getAccountFromNode({ address: rootAddressDetails.address });
|
|
648
|
+
if (!account.core_liquid_balance) {
|
|
649
|
+
throw new Error('Could not find any balance to recovery for ' + params.rootAddress);
|
|
650
|
+
}
|
|
651
|
+
if (!account.permissions) {
|
|
652
|
+
throw new Error('Could not find permissions for ' + params.rootAddress);
|
|
653
|
+
}
|
|
654
|
+
const userPub = ecc.PublicKey.fromBuffer(keys[0].publicKey).toString();
|
|
655
|
+
const backupPub = ecc.PublicKey.fromBuffer(keys[1].publicKey).toString();
|
|
656
|
+
const activePermission = _.find(account.permissions, { perm_name: 'active' });
|
|
657
|
+
const requiredAuth = _.get(activePermission, 'required_auth');
|
|
658
|
+
if (!requiredAuth) {
|
|
659
|
+
throw new Error('Required auth for active permission not found in account');
|
|
660
|
+
}
|
|
661
|
+
if (requiredAuth.threshold !== 2) {
|
|
662
|
+
throw new Error('Unexpected active permission threshold');
|
|
663
|
+
}
|
|
664
|
+
const foundPubs = {};
|
|
665
|
+
const requiredAuthKeys = requiredAuth.keys;
|
|
666
|
+
for (const signer of requiredAuthKeys) {
|
|
667
|
+
if (signer.weight !== 1) {
|
|
668
|
+
throw new Error('invalid signer weight');
|
|
669
|
+
}
|
|
670
|
+
// if it's a dupe of a pub we already know, block
|
|
671
|
+
if (foundPubs[signer.key]) {
|
|
672
|
+
throw new Error('duplicate signer key');
|
|
673
|
+
}
|
|
674
|
+
foundPubs[signer.key] = (foundPubs[signer.key] || 0) + 1;
|
|
675
|
+
}
|
|
676
|
+
if (foundPubs[userPub] !== 1 || foundPubs[backupPub] !== 1) {
|
|
677
|
+
throw new Error('unexpected incidence frequency of user signer key');
|
|
678
|
+
}
|
|
679
|
+
const accountBalance = account.core_liquid_balance.split(' ')[0];
|
|
680
|
+
const recoveryAmount = this.bigUnitsToBaseUnits(new bignumber_js_1.BigNumber(accountBalance).toFixed());
|
|
681
|
+
const destinationAddress = params.recoveryDestination;
|
|
682
|
+
const destinationAddressDetails = this.getAddressDetails(destinationAddress);
|
|
683
|
+
const destinationAccount = await this.getAccountFromNode({ address: destinationAddressDetails.address });
|
|
684
|
+
if (!destinationAccount) {
|
|
685
|
+
throw new Error('Destination account not found');
|
|
686
|
+
}
|
|
687
|
+
const transactionHeaders = await this.getTransactionHeadersFromNode();
|
|
688
|
+
if (!transactionHeaders) {
|
|
689
|
+
throw new Error('Could not get transaction headers from node');
|
|
690
|
+
}
|
|
691
|
+
const headers = transactionHeaders;
|
|
692
|
+
const nativeDate = new Date(headers.expiration);
|
|
693
|
+
// drop milliseconds and trailing Z from expiration
|
|
694
|
+
nativeDate.setMilliseconds(0);
|
|
695
|
+
const expiration = nativeDate.toISOString();
|
|
696
|
+
if (expiration.endsWith('Z')) {
|
|
697
|
+
headers.expiration = expiration.slice(0, -1);
|
|
698
|
+
}
|
|
699
|
+
// create an offline eosjs API client
|
|
700
|
+
const api = new eosjs_1.Api({
|
|
701
|
+
rpc: new NoopJsonRpc(),
|
|
702
|
+
signatureProvider: new NoopSignatureProvider(),
|
|
703
|
+
abiProvider: new eosabiprovider_1.OfflineAbiProvider(),
|
|
704
|
+
chainId: this.getChainId(),
|
|
705
|
+
textDecoder: new TextDecoder(),
|
|
706
|
+
textEncoder: new TextEncoder(),
|
|
707
|
+
});
|
|
708
|
+
const transferAction = this.getTransferAction({
|
|
709
|
+
recipient: destinationAddressDetails.address,
|
|
710
|
+
sender: rootAddressDetails.address,
|
|
711
|
+
amount: new bignumber_js_1.BigNumber(recoveryAmount),
|
|
712
|
+
memo: destinationAddressDetails.memoId,
|
|
713
|
+
});
|
|
714
|
+
let serializedTransaction;
|
|
715
|
+
const tx = { actions: [transferAction] };
|
|
716
|
+
try {
|
|
717
|
+
serializedTransaction = await api.transact({ ...tx, ...headers }, { sign: false, broadcast: false });
|
|
718
|
+
}
|
|
719
|
+
catch (e) {
|
|
720
|
+
throw new Error('Eos API error: Could not build transaction');
|
|
721
|
+
}
|
|
722
|
+
// create transaction object
|
|
723
|
+
const serializedTransactionHex = Buffer.from(serializedTransaction.serializedTransaction).toString('hex');
|
|
724
|
+
const transactionId = Eos.createTransactionIdHex(serializedTransaction.serializedTransaction);
|
|
725
|
+
const txObject = {
|
|
726
|
+
transaction: {
|
|
727
|
+
compression: 'none',
|
|
728
|
+
packed_trx: serializedTransactionHex,
|
|
729
|
+
signatures: [],
|
|
730
|
+
},
|
|
731
|
+
txid: transactionId,
|
|
732
|
+
recoveryAmount: accountBalance,
|
|
733
|
+
coin: this.getChain(),
|
|
734
|
+
txHex: '',
|
|
735
|
+
};
|
|
736
|
+
const signableTx = Buffer.concat([
|
|
737
|
+
Buffer.from(this.getChainId(), 'hex'),
|
|
738
|
+
Buffer.from(serializedTransaction.serializedTransaction),
|
|
739
|
+
Buffer.from(new Uint8Array(32)), // Some padding
|
|
740
|
+
]).toString('hex');
|
|
741
|
+
if (isUnsignedSweep) {
|
|
742
|
+
txObject.txHex = signableTx;
|
|
743
|
+
return txObject;
|
|
744
|
+
}
|
|
745
|
+
const userSignature = this.signTx(signableTx, keys[0]);
|
|
746
|
+
txObject.transaction.signatures.push(userSignature);
|
|
747
|
+
if (!isKrsRecovery) {
|
|
748
|
+
const backupSignature = this.signTx(signableTx, keys[1]);
|
|
749
|
+
txObject.transaction.signatures.push(backupSignature);
|
|
750
|
+
}
|
|
751
|
+
return txObject;
|
|
752
|
+
}
|
|
753
|
+
async parseTransaction(params) {
|
|
754
|
+
return {};
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* Verify that a transaction prebuild complies with the original intention
|
|
758
|
+
*
|
|
759
|
+
* @param params
|
|
760
|
+
* @param params.txParams params used to build the transaction
|
|
761
|
+
* @param params.txPrebuild the prebuilt transaction
|
|
762
|
+
*/
|
|
763
|
+
async verifyTransaction(params) {
|
|
764
|
+
var _a;
|
|
765
|
+
const { txParams: txParams, txPrebuild: txPrebuild } = params;
|
|
766
|
+
// check if the transaction has a txHex
|
|
767
|
+
if (!txPrebuild.txHex) {
|
|
768
|
+
throw new Error('missing required tx prebuild property txHex');
|
|
769
|
+
}
|
|
770
|
+
// construct transaction from txHex
|
|
771
|
+
const txFromHex = Buffer.from(txPrebuild.txHex, 'hex');
|
|
772
|
+
const txDataWithPadding = txFromHex.slice(32);
|
|
773
|
+
const txData = txDataWithPadding.slice(0, txDataWithPadding.length - 32);
|
|
774
|
+
const deserializedTxJson = await this.deserializeTransaction({
|
|
775
|
+
transaction: { packed_trx: txData.toString('hex') },
|
|
776
|
+
headers: txPrebuild.headers,
|
|
777
|
+
});
|
|
778
|
+
if (!deserializedTxJson) {
|
|
779
|
+
throw new Error('could not process transaction from txHex');
|
|
780
|
+
}
|
|
781
|
+
const txJsonFromHex = deserializedTxJson;
|
|
782
|
+
// check that if txParams has a txPrebuild, it should be the same as txPrebuild
|
|
783
|
+
if (txParams.txPrebuild && !_.isEqual(txParams.txPrebuild, txPrebuild)) {
|
|
784
|
+
throw new Error('inputs txParams.txPrebuild and txPrebuild expected to be equal but were not');
|
|
785
|
+
}
|
|
786
|
+
// check if prebuild has a transaction
|
|
787
|
+
if (!txPrebuild.transaction) {
|
|
788
|
+
throw new Error('missing required transaction in txPrebuild');
|
|
789
|
+
}
|
|
790
|
+
// check if transaction has a packed_trx
|
|
791
|
+
if (!((_a = txPrebuild.transaction) === null || _a === void 0 ? void 0 : _a.packed_trx)) {
|
|
792
|
+
throw new Error('missing required transaction.packed_trx in txPrebuild');
|
|
793
|
+
}
|
|
794
|
+
// construct transaction using packed_trx
|
|
795
|
+
const deserializedTxJsonFromPackedTrx = await this.deserializeTransaction({
|
|
796
|
+
transaction: { packed_trx: txPrebuild.transaction.packed_trx },
|
|
797
|
+
headers: txPrebuild.headers,
|
|
798
|
+
});
|
|
799
|
+
if (!deserializedTxJsonFromPackedTrx) {
|
|
800
|
+
throw new Error('could not process transaction from packed_trx');
|
|
801
|
+
}
|
|
802
|
+
const txJsonFromPackedTrx = deserializedTxJsonFromPackedTrx;
|
|
803
|
+
// deep check of object from packed_trx and txHex
|
|
804
|
+
if (!_.isEqual(txJsonFromPackedTrx, txJsonFromHex)) {
|
|
805
|
+
throw new Error('unpacked packed_trx and unpacked txHex are not equal');
|
|
806
|
+
}
|
|
807
|
+
if (txParams.recipients.length > 1) {
|
|
808
|
+
throw new Error('only 0 or 1 recipients are supported');
|
|
809
|
+
}
|
|
810
|
+
// check the amounts, recipient, and coin name for transfers
|
|
811
|
+
if (txParams.recipients.length === 1) {
|
|
812
|
+
const expectedOutput = txParams.recipients[0];
|
|
813
|
+
// check output address and memoId
|
|
814
|
+
const expectedOutputAddressAndMemoId = this.getAddressDetails(expectedOutput.address);
|
|
815
|
+
const txHexAction = txJsonFromHex.actions[0];
|
|
816
|
+
const txHexTransferAction = txHexAction.data;
|
|
817
|
+
if (txHexTransferAction.to !== expectedOutputAddressAndMemoId.address) {
|
|
818
|
+
throw new Error('txHex receive address does not match expected recipient address');
|
|
819
|
+
}
|
|
820
|
+
// check if txaction memoid is equal to address memo id only if address also has memoid present
|
|
821
|
+
if (!_.isUndefined(expectedOutputAddressAndMemoId.memoId)) {
|
|
822
|
+
if (txHexTransferAction.memo !== expectedOutputAddressAndMemoId.memoId) {
|
|
823
|
+
throw new Error('txHex receive memoId does not match expected recipient memoId');
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
// check amount and coin
|
|
827
|
+
const expectedOutputAmount = expectedOutput.amount;
|
|
828
|
+
const actualAmountAndCoin = txHexTransferAction.quantity.split(' ');
|
|
829
|
+
const actualOutputAmount = this.bigUnitsToBaseUnits(actualAmountAndCoin[0]);
|
|
830
|
+
if (expectedOutputAmount !== actualOutputAmount) {
|
|
831
|
+
throw new Error('txHex receive amount does not match expected recipient amount');
|
|
832
|
+
}
|
|
833
|
+
if (txPrebuild.coin === 'eos' || txPrebuild.coin === 'teos') {
|
|
834
|
+
const expectedSymbol = _.isNil(txPrebuild.token) ? 'EOS' : txPrebuild.token.split(':')[1];
|
|
835
|
+
if (actualAmountAndCoin[1] !== expectedSymbol) {
|
|
836
|
+
throw new Error('txHex receive symbol does not match expected recipient symbol');
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
else {
|
|
840
|
+
// this should never happen
|
|
841
|
+
throw new Error('txHex coin name does not match expected coin name');
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
return true;
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* Generate a random EOS address.
|
|
848
|
+
*
|
|
849
|
+
* This is just a random string which abides by the EOS adddress constraints,
|
|
850
|
+
* and is not actually checked for availability on the EOS blockchain.
|
|
851
|
+
*
|
|
852
|
+
* Current EOS address constraints are:
|
|
853
|
+
* * Address must be exactly 12 characters
|
|
854
|
+
* * Address must only contain lowercase letters and numbers 1-5
|
|
855
|
+
* @returns a validly formatted EOS address, which may or may not actually be available on chain.
|
|
856
|
+
*/
|
|
857
|
+
generateRandomAddress(params) {
|
|
858
|
+
const address = [];
|
|
859
|
+
while (address.length < 12) {
|
|
860
|
+
const char = _.sample(Eos.VALID_ADDRESS_CHARS);
|
|
861
|
+
if (!char) {
|
|
862
|
+
throw new Error('failed to sample valid EOS address characters');
|
|
863
|
+
}
|
|
864
|
+
address.push(char);
|
|
865
|
+
}
|
|
866
|
+
return address.join('');
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
exports.Eos = Eos;
|
|
870
|
+
Eos.VALID_ADDRESS_CHARS = '12345abcdefghijklmnopqrstuvwxyz'.split('');
|
|
871
|
+
Eos.ADDRESS_LENGTH = 12;
|
|
872
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW9zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2Vvcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7O0dBRUc7QUFDSCwrQ0FBeUM7QUFDekMsNkNBQStCO0FBQy9CLG1DQUFpRDtBQUNqRCxpQ0FBbUU7QUFDbkUsK0NBQWlDO0FBQ2pDLDBDQUE0QjtBQUM1Qix5REFBMkM7QUFDM0Msb0RBQXNDO0FBQ3RDLHlDQUEyQjtBQUUzQiw2REFBOEQ7QUFDOUQsdUNBQWdEO0FBQ2hELDhDQXFCeUI7QUFvSnpCLE1BQU0sV0FBWSxTQUFRLGVBQU87SUFDL0I7UUFDRSxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDWixDQUFDO0NBQ0Y7QUFFRCxNQUFNLHFCQUFxQjtJQUN6QixLQUFLLENBQUMsZ0JBQWdCO1FBQ3BCLE1BQU0sSUFBSSxLQUFLLENBQUMsOERBQThELENBQUMsQ0FBQztJQUNsRixDQUFDO0lBRUQsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUF5QztRQUNsRCxNQUFNLElBQUksS0FBSyxDQUFDLHVDQUF1QyxDQUFDLENBQUM7SUFDM0QsQ0FBQztDQUNGO0FBRUQsTUFBYSxHQUFJLFNBQVEsbUJBQVE7SUFJL0IsTUFBTSxDQUFDLGNBQWMsQ0FBQyxLQUFnQjtRQUNwQyxPQUFPLElBQUksR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3hCLENBQUM7SUFFRCxVQUFVO1FBQ1IsT0FBTyxrRUFBa0UsQ0FBQyxDQUFDLG1CQUFtQjtJQUNoRyxDQUFDO0lBRUQsUUFBUTtRQUNOLE9BQU8sS0FBSyxDQUFDO0lBQ2YsQ0FBQztJQUVELFNBQVM7UUFDUCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCxXQUFXO1FBQ1QsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRUQsYUFBYTtRQUNYLE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQztJQUVEOzs7T0FHRztJQUNILHdCQUF3QjtR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QUU7b0JBQzdDLE1BQU0sSUFBSSxLQUFLLENBQUMsK0RBQStELENBQUMsQ0FBQztpQkFDbEY7YUFDRjtpQkFBTTtnQkFDTCwyQkFBMkI7Z0JBQzNCLE1BQU0sSUFBSSxLQUFLLENBQUMsbURBQW1ELENBQUMsQ0FBQzthQUN0RTtTQUNGO1FBRUQsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7T0FVRztJQUNILHFCQUFxQixDQUFDLE1BQTZCO1FBQ2pELE1BQU0sT0FBTyxHQUFhLEVBQUUsQ0FBQztRQUM3QixPQUFPLE9BQU8sQ0FBQyxNQUFNLEdBQUcsRUFBRSxFQUFFO1lBQzFCLE1BQU0sSUFBSSxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLG1CQUFtQixDQUFDLENBQUM7WUFDL0MsSUFBSSxDQUFDLElBQUksRUFBRTtnQkFDVCxNQUFNLElBQUksS0FBSyxDQUFDLCtDQUErQyxDQUFDLENBQUM7YUFDbEU7WUFDRCxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1NBQ3BCO1FBQ0QsT0FBTyxPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzFCLENBQUM7O0FBbjdCSCxrQkFvN0JDO0FBbjdCZSx1QkFBbUIsR0FBRyxpQ0FBaUMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7QUFDbEUsa0JBQWMsR0FBRyxFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBwcmV0dGllclxuICovXG5pbXBvcnQgeyBCaWdOdW1iZXIgfSBmcm9tICdiaWdudW1iZXIuanMnO1xuaW1wb3J0ICogYXMgYmlwMzIgZnJvbSAnYmlwMzInO1xuaW1wb3J0IHsgY3JlYXRlSGFzaCwgcmFuZG9tQnl0ZXMgfSBmcm9tICdjcnlwdG8nO1xuaW1wb3J0IHsgQXBpLCBBcGlJbnRlcmZhY2VzLCBKc29uUnBjLCBScGNJbnRlcmZhY2VzIH0gZnJvbSAnZW9zanMnO1xuaW1wb3J0ICogYXMgZWNjIGZyb20gJ2Vvc2pzLWVjYyc7XG5pbXBvcnQgKiBhcyBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgKiBhcyBxdWVyeXN0cmluZyBmcm9tICdxdWVyeXN0cmluZyc7XG5pbXBvcnQgKiBhcyByZXF1ZXN0IGZyb20gJ3N1cGVyYWdlbnQnO1xuaW1wb3J0ICogYXMgdXJsIGZyb20gJ3VybCc7XG5cbmltcG9ydCB7IE9mZmxpbmVBYmlQcm92aWRlciB9IGZyb20gJy4vZW9zdXRpbC9lb3NhYmlwcm92aWRlcic7XG5pbXBvcnQgeyBTdHJpbmdUZXh0RGVjb2RlciB9IGZyb20gJy4vbGliL3V0aWxzJztcbmltcG9ydCB7XG4gIEJhc2VDb2luLFxuICBCaXRHb0Jhc2UsXG4gIGNoZWNrS3JzUHJvdmlkZXIsXG4gIEVudmlyb25tZW50cyxcbiAgZ2V0QmlwMzJLZXlzLFxuICBnZXRJc0tyc1JlY292ZXJ5LFxuICBnZXRJc1Vuc2lnbmVkU3dlZXAsXG4gIEhhbGZTaWduZWRBY2NvdW50VHJhbnNhY3Rpb24gYXMgQmFzZUhhbGZTaWduZWRUcmFuc2FjdGlvbixcbiAgSW52YWxpZEFkZHJlc3NFcnJvcixcbiAgS2V5UGFpcixcbiAgUGFyc2VkVHJhbnNhY3Rpb24sXG4gIFBhcnNlVHJhbnNhY3Rpb25PcHRpb25zLFxuICBSZXF1ZXN0VHJhY2VyLFxuICBTaWduVHJhbnNhY3Rpb25PcHRpb25zIGFzIEJhc2VTaWduVHJhbnNhY3Rpb25PcHRpb25zLFxuICBUcmFuc2FjdGlvbkV4cGxhbmF0aW9uLFxuICBVbmV4cGVjdGVkQWRkcmVzc0Vycm9yLFxuICBWZXJpZmljYXRpb25PcHRpb25zLFxuICBWZXJpZnlBZGRyZXNzT3B0aW9ucyBhcyBCYXNlVmVyaWZ5QWRkcmVzc09wdGlvbnMsXG4gIFZlcmlmeVRyYW5zYWN0aW9uT3B0aW9ucyBhcyBCYXNlVmVyaWZ5VHJhbnNhY3Rpb25PcHRpb25zLFxuICBXYWxsZXQsXG59IGZyb20gJ0BiaXRnby9zZGstY29yZSc7XG5cbmludGVyZmFjZSBBZGRyZXNzRGV0YWlscyB7XG4gIGFkZHJlc3M6IHN0cmluZztcbiAgbWVtb0lkPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEVvc1R4IHtcbiAgc2lnbmF0dXJlczogc3RyaW5nW107XG4gIHBhY2tlZF90cng6IHN0cmluZztcbiAgY29tcHJlc3Npb246IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZWNpcGllbnQge1xuICBhZGRyZXNzOiBzdHJpbmc7XG4gIGFtb3VudDogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgRW9zVHJhbnNhY3Rpb25IZWFkZXJzIHtcbiAgcmVmX2Jsb2NrX3ByZWZpeDogbnVtYmVyO1xuICByZWZfYmxvY2tfbnVtOiBudW1iZXI7XG4gIGV4cGlyYXRpb24/OiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBFb3NUcmFuc2FjdGlvbkFjdGlvbiB7XG4gIGFjY291bnQ6IHN0cmluZztcbiAgbmFtZTogc3RyaW5nO1xuICBhdXRob3JpemF0aW9uOiBbeyBhY3Rvcjogc3RyaW5nOyBwZXJtaXNzaW9uOiBzdHJpbmcgfV07XG4gIGRhdGE6IFRyYW5zZmVyQWN0aW9uRGF0YSB8IFN0YWtlQWN0aW9uRGF0YSB8IFZvdGVBY3Rpb25EYXRhO1xufVxuXG5pbnRlcmZhY2UgRW9zVHJhbnNhY3Rpb25QcmVidWlsZCB7XG4gIHJlY2lwaWVudHM6IFJlY2lwaWVudFtdO1xuICBoZWFkZXJzOiBFb3NUcmFuc2FjdGlvbkhlYWRlcnM7XG4gIHR4SGV4OiBzdHJpbmc7IC8vIFRoZSBzaWduYWJsZSB0eCBoZXggc3RyaW5nXG4gIHRyYW5zYWN0aW9uOiBFb3NUeDtcbiAgdHhpZDogc3RyaW5nO1xuICBjb2luOiBzdHJpbmc7XG4gIC8vIGZ1bGwgdG9rZW4gbmFtZSB3aXRoIHRoZSBmb3JtYXQsIFt0XWVvczpTWU1CT0wuIFRoaXMgd2lsbCBvbmx5IGJlIHByZXNlbnQgZm9yIHRva2VuIHRyYW5zYWN0aW9ucy4gZS5nLiB0ZW9zOkNIRVguXG4gIHRva2VuPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEVvc1NpZ25UcmFuc2FjdGlvblBhcmFtcyBleHRlbmRzIEJhc2VTaWduVHJhbnNhY3Rpb25PcHRpb25zIHtcbiAgcHJ2OiBzdHJpbmc7XG4gIHR4UHJlYnVpbGQ6IEVvc1RyYW5zYWN0aW9uUHJlYnVpbGQ7XG4gIHJlY2lwaWVudHM6IFJlY2lwaWVudFtdO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEVvc1ZlcmlmeVRyYW5zYWN0aW9uT3B0aW9ucyBleHRlbmRzIEJhc2VWZXJpZnlUcmFuc2FjdGlvbk9wdGlvbnMge1xuICB0eFByZWJ1aWxkOiBFb3NUcmFuc2FjdGlvblByZWJ1aWxkO1xuICB0eFBhcmFtczogRW9zU2lnblRyYW5zYWN0aW9uUGFyYW1zO1xuICB3YWxsZXQ6IFdhbGxldDtcbiAgdmVyaWZpY2F0aW9uPzogVmVyaWZpY2F0aW9uT3B0aW9ucztcbiAgcmVxSWQ/OiBSZXF1ZXN0VHJhY2VyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEVvc0hhbGZTaWduZWQge1xuICByZWNpcGllbnRzOiBSZWNpcGllbnRbXTtcbiAgaGVhZGVyczogRW9zVHJhbnNhY3Rpb25IZWFkZXJzO1xuICB0eEhleDogc3RyaW5nOyAvLyBUaGUgc2lnbmFibGUgdHggaGV4IHN0cmluZ1xuICB0cmFuc2FjdGlvbjogRW9zVHg7XG4gIHR4aWQ6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFb3NTaWduZWRUcmFuc2FjdGlvbiBleHRlbmRzIEJhc2VIYWxmU2lnbmVkVHJhbnNhY3Rpb24ge1xuICBoYWxmU2lnbmVkOiBFb3NIYWxmU2lnbmVkO1xufVxuXG5pbnRlcmZhY2UgRGVzZXJpYWxpemVkRW9zVHJhbnNhY3Rpb24ge1xuICBleHBpcmF0aW9uOiBzdHJpbmc7XG4gIHJlZl9ibG9ja19udW06IHN0cmluZztcbiAgcmVmX2Jsb2NrX3ByZWZpeDogc3RyaW5nO1xuICBtYXhfbmV0X3VzYWdlX3dvcmRzOiBudW1iZXI7XG4gIG1heF9jcHVfdXNhZ2VfbXM6IG51bWJlcjtcbiAgZGVsYXlfc2VjOiBudW1iZXI7XG4gIGNvbnRleHRfZnJlZV9hY3Rpb25zOiBFb3NUcmFuc2FjdGlvbkFjdGlvbltdO1xuICBhY3Rpb25zOiBFb3NUcmFuc2FjdGlvbkFjdGlvbltdO1xuICB0cmFuc2FjdGlvbl9leHRlbnNpb25zOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdO1xuICBhZGRyZXNzOiBzdHJpbmc7XG4gIGFtb3VudDogc3RyaW5nO1xuICB0cmFuc2FjdGlvbl9pZDogc3RyaW5nO1xuICBtZW1vPzogc3RyaW5nO1xuICBwcm94eT86IHN0cmluZztcbiAgcHJvZHVjZXJzPzogc3RyaW5nW107XG59XG5cbmludGVyZmFjZSBUcmFuc2ZlckFjdGlvbkRhdGEge1xuICBmcm9tOiBzdHJpbmc7XG4gIHRvOiBzdHJpbmc7XG4gIHF1YW50aXR5OiBzdHJpbmc7XG4gIG1lbW8/OiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBTdGFrZUFjdGlvbkRhdGEge1xuICBhZGRyZXNzOiBzdHJpbmc7XG4gIGFtb3VudDogc3RyaW5nO1xuICBmcm9tOiBzdHJpbmc7XG4gIHJlY2VpdmVyOiBzdHJpbmc7XG4gIHRyYW5zZmVyOiBudW1iZXI7XG4gIHN0YWtlX2NwdV9xdWFudGl0eTogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgVW5zdGFrZUFjdGlvbkRhdGEge1xuICBhZGRyZXNzOiBzdHJpbmc7XG4gIGFtb3VudDogc3RyaW5nO1xuICBmcm9tOiBzdHJpbmc7XG4gIHJlY2VpdmVyOiBzdHJpbmc7XG4gIHVuc3Rha2VfY3B1X3F1YW50aXR5OiBzdHJpbmc7XG4gIHVuc3Rha2VfbmV0X3F1YW50aXR5OiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBSZWZ1bmRBY3Rpb25EYXRhIHtcbiAgYWRkcmVzczogc3RyaW5nO1xuICBvd25lcjogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgVm90ZUFjdGlvbkRhdGEge1xuICBhZGRyZXNzOiBzdHJpbmc7XG4gIHByb3h5OiBzdHJpbmc7XG4gIHByb2R1Y2Vyczogc3RyaW5nW107XG4gIHZvdGVyOiBzdHJpbmc7XG59XG5cbmludGVyZmFjZSBFeHBsYWluVHJhbnNhY3Rpb25PcHRpb25zIHtcbiAgdHJhbnNhY3Rpb246IHsgcGFja2VkX3RyeDogc3RyaW5nIH07XG4gIGhlYWRlcnM6IEVvc1RyYW5zYWN0aW9uSGVhZGVycztcbn1cblxuaW50ZXJmYWNlIFJlY292ZXJ5VHJhbnNhY3Rpb24ge1xuICB0cmFuc2FjdGlvbjogRW9zVHg7XG4gIHR4aWQ6IHN0cmluZztcbiAgcmVjb3ZlcnlBbW91bnQ6IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIFJlY292ZXJ5T3B0aW9ucyB7XG4gIHVzZXJLZXk6IHN0cmluZzsgLy8gQm94IEFcbiAgYmFja3VwS2V5OiBzdHJpbmc7IC8vIEJveCBCXG4gIGJpdGdvS2V5Pzogc3RyaW5nOyAvLyBCb3ggQ1xuICByZWNvdmVyeURlc3RpbmF0aW9uOiBzdHJpbmc7XG4gIGtyc1Byb3ZpZGVyPzogc3RyaW5nO1xuICB3YWxsZXRQYXNzcGhyYXNlPzogc3RyaW5nO1xuICByb290QWRkcmVzcz86IHN0cmluZztcbn1cblxuaW50ZXJmYWNlIFZlcmlmeUFkZHJlc3NPcHRpb25zIGV4dGVuZHMgQmFzZVZlcmlmeUFkZHJlc3NPcHRpb25zIHtcbiAgcm9vdEFkZHJlc3M6IHN0cmluZztcbn1cblxuY2xhc3MgTm9vcEpzb25ScGMgZXh0ZW5kcyBKc29uUnBjIHtcbiAgY29uc3RydWN0b3IoKSB7XG4gICAgc3VwZXIoJycpO1xuICB9XG59XG5cbmNsYXNzIE5vb3BTaWduYXR1cmVQcm92aWRlciBpbXBsZW1lbnRzIEFwaUludGVyZmFjZXMuU2lnbmF0dXJlUHJvdmlkZXIge1xuICBhc3luYyBnZXRBdmFpbGFibGVLZXlzKCk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ25vb3Agc2lnbmF0dXJlIHByb3ZpZGVyIGltcGxlbWVudGF0aW9uIGhhcyBubyBhdmFpbGFibGUga2V5cycpO1xuICB9XG5cbiAgYXN5bmMgc2lnbihhcmdzOiBBcGlJbnRlcmZhY2VzLlNpZ25hdHVyZVByb3ZpZGVyQXJncyk6IFByb21pc2U8UnBjSW50ZXJmYWNlcy5QdXNoVHJhbnNhY3Rpb25BcmdzPiB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdub29wIGltcGxlbWVudGF0aW9uIGlzIHVuYWJsZSB0byBzaWduJyk7XG4gIH1cbn1cblxuZXhwb3J0IGNsYXNzIEVvcyBleHRlbmRzIEJhc2VDb2luIHtcbiAgcHVibGljIHN0YXRpYyBWQUxJRF9BRERSRVNTX0NIQVJTID0gJzEyMzQ1YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXonLnNwbGl0KCcnKTtcbiAgcHVibGljIHN0YXRpYyBBRERSRVNTX0xFTkdUSCA9IDEyO1xuXG4gIHN0YXRpYyBjcmVhdGVJbnN0YW5jZShiaXRnbzogQml0R29CYXNlKTogQmFzZUNvaW4ge1xuICAgIHJldHVybiBuZXcgRW9zKGJpdGdvKTtcbiAgfVxuXG4gIGdldENoYWluSWQoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gJ2FjYTM3NmYyMDZiOGZjMjVhNmVkNDRkYmRjNjY1NDdjMzZjNmMzM2UzYTExOWZmYmVhZWY5NDM2NDJmMGU5MDYnOyAvLyBtYWlubmV0IGNoYWluIGlkXG4gIH1cblxuICBnZXRDaGFpbigpOiBzdHJpbmcge1xuICAgIHJldHVybiAnZW9zJztcbiAgfVxuXG4gIGdldEZhbWlseSgpOiBzdHJpbmcge1xuICAgIHJldHVybiAnZW9zJztcbiAgfVxuXG4gIGdldEZ1bGxOYW1lKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuICdFT1MnO1xuICB9XG5cbiAgZ2V0QmFzZUZhY3RvcigpOiBudW1iZXIge1xuICAgIHJldHVybiAxZTQ7XG4gIH1cblxuICAvKipcbiAgICogRmxhZyBmb3Igc2VuZGluZyB2YWx1ZSBvZiAwXG4gICAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIG9rYXkgdG8gc2VuZCAwIHZhbHVlLCBmYWxzZSBvdGhlcndpc2VcbiAgICovXG4gIHZhbHVlbGVzc1RyYW5zZmVyQWxsb3dlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgVVJMcyBvZiBzb21lIGFjdGl2ZSBwdWJsaWMgbm9kZXNcbiAgICovXG4gIGdldFB1YmxpY05vZGVVcmxzKCk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gRW52aXJvbm1lbnRzW3RoaXMuYml0Z28uZ2V0RW52KCldLmVvc05vZGVVcmxzO1xuICB9XG4gIC8qKlxuICAgKiBHZW5lcmF0ZSBzZWNwMjU2azEga2V5IHBhaXJcbiAgICpcbiAgICogQHBhcmFtIHNlZWQgLSBTZWVkIGZyb20gd2hpY2ggdGhlIG5ldyBrZXlwYWlyIHNob3VsZCBiZSBnZW5lcmF0ZWQsIG90aGVyd2lzZSBhIHJhbmRvbSBzZWVkIGlzIHVzZWRcbiAgICovXG4gIGdlbmVyYXRlS2V5UGFpcihzZWVkPzogQnVmZmVyKTogS2V5UGFpciB7XG4gICAgaWYgKCFzZWVkKSB7XG4gICAgICAvLyBBbiBleHRlbmRlZCBwcml2YXRlIGtleSBoYXMgYm90aCBhIG5vcm1hbCAyNTYgYml0IHByaXZhdGUga2V5IGFuZCBhIDI1NlxuICAgICAgLy8gYml0IGNoYWluIGNvZGUsIGJvdGggb2Ygd2hpY2ggbXVzdCBiZSByYW5kb20uIDUxMiBiaXRzIGlzIHRoZXJlZm9yZSB0aGVcbiAgICAgIC8vIG1heGltdW0gZW50cm9weSBhbmQgZ2l2ZXMgdXMgbWF4aW11bSBzZWN1cml0eSBhZ2FpbnN0IGNyYWNraW5nLlxuICAgICAgc2VlZCA9IHJhbmRvbUJ5dGVzKDUxMiAvIDgpO1xuICAgIH1cbiAgICBjb25zdCBleHRlbmRlZEtleSA9IGJpcDMyLmZyb21TZWVkKHNlZWQpO1xuICAgIGNvbnN0IHhwdWIgPSBleHRlbmRlZEtleS5uZXV0ZXJlZCgpLnRvQmFzZTU4KCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIHB1YjogeHB1YixcbiAgICAgIHBydjogZXh0ZW5kZWRLZXkudG9CYXNlNTgoKSxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBib29sZWFuIGluZGljYXRpbmcgd2hldGhlciBpbnB1dCBpcyB2YWxpZCBwdWJsaWMga2V5IGZvciB0aGUgY29pbi5cbiAgICpcbiAgICogQHBhcmFtIHB1YiAtIHRoZSBwdWIgdG8gYmUgY2hlY2tlZFxuICAgKi9cbiAgaXNWYWxpZFB1YihwdWI6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gYmlwMzIuZnJvbUJhc2U1OChwdWIpLmlzTmV1dGVyZWQoKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBib29sZWFuIGluZGljYXRpbmcgd2hldGhlciBpbnB1dCBpcyB2YWxpZCBzZWVkIGZvciB0aGUgY29pblxuICAgKlxuICAgKiBAcGFyYW0gcHJ2IC0gdGhlIHBydiB0byBiZSBjaGVja2VkXG4gICAqL1xuICBpc1ZhbGlkUHJ2KHBydjogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgdHJ5IHtcbiAgICAgIHJldHVybiAhYmlwMzIuZnJvbUJhc2U1OChwcnYpLmlzTmV1dGVyZWQoKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEV2YWx1YXRlcyB3aGV0aGVyIGEgbWVtbyBpcyB2YWxpZFxuICAgKlxuICAgKiBAcGFyYW0gdmFsdWUgLSB0aGUgbWVtbyB0byBiZSBjaGVja2VkXG4gICAqL1xuICBpc1ZhbGlkTWVtbyh7IHZhbHVlIH06IHsgdmFsdWU6IHN0cmluZyB9KTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIF8uaXNTdHJpbmcodmFsdWUpICYmIHZhbHVlLmxlbmd0aCA8PSAyNTY7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIGJvb2xlYW4gaW5kaWNhdGluZyB3aGV0aGVyIGEgbWVtbyBpZCBpcyB2YWxpZFxuICAgKlxuICAgKiBAcGFyYW0gbWVtb0lkIC0gdGhlIG1lbW8gaWQgdG8gYmUgY2hlY2tlZFxuICAgKi9cbiAgaXNWYWxpZE1lbW9JZChtZW1vSWQ6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzVmFsaWRNZW1vKHsgdmFsdWU6IG1lbW9JZCB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcm9jZXNzIGFkZHJlc3MgaW50byBhZGRyZXNzIGFuZCBtZW1vIGlkXG4gICAqIEBwYXJhbSBhZGRyZXNzIC0gdGhlIGFkZHJlc3NcbiAgICovXG4gIGdldEFkZHJlc3NEZXRhaWxzKGFkZHJlc3M6IHN0cmluZyk6IEFkZHJlc3NEZXRhaWxzIHtcbiAgICBjb25zdCBkZXN0aW5hdGlvbkRldGFpbHMgPSB1cmwucGFyc2UoYWRkcmVzcyk7XG4gICAgY29uc3QgZGVzdGluYXRpb25BZGRyZXNzID0gZGVzdGluYXRpb25EZXRhaWxzLnBhdGhuYW1lO1xuXG4gICAgaWYgKCFkZXN0aW5hdGlvbkFkZHJlc3MpIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkQWRkcmVzc0Vycm9yKGBmYWlsZWQgdG8gcGFyc2UgYWRkcmVzczogJHthZGRyZXNzfWApO1xuICAgIH1cblxuICAgIC8vIEVPUyBhZGRyZXNzZXMgaGF2ZSB0byBiZSBcImh1bWFuIHJlYWRhYmxlXCIsIHdoaWNoIG1lYW5zIHVwIHRvIDEyIGNoYXJhY3RlcnMgYW5kIG9ubHkgYS16MS01LiwgaS5lLm10b2RhMS5iaXRnb1xuICAgIC8vIHNvdXJjZTogaHR0cHM6Ly9kZXZlbG9wZXJzLmVvcy5pby9lb3Npby1jcHAvZG9jcy9uYW1pbmctY29udmVudGlvbnNcbiAgICBpZiAoIS9eW2EtejEtNS5dKiQvLnRlc3QoZGVzdGluYXRpb25BZGRyZXNzKSB8fCBkZXN0aW5hdGlvbkFkZHJlc3MubGVuZ3RoID4gRW9zLkFERFJFU1NfTEVOR1RIKSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZEFkZHJlc3NFcnJvcihgaW52YWxpZCBhZGRyZXNzOiAke2FkZHJlc3N9YCk7XG4gICAgfVxuXG4gICAgLy8gYWRkcmVzcyBkb2Vzbid0IGhhdmUgYSBtZW1vIGlkXG4gICAgaWYgKGRlc3RpbmF0aW9uRGV0YWlscy5wYXRobmFtZSA9PT0gYWRkcmVzcykge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYWRkcmVzczogYWRkcmVzcyxcbiAgICAgICAgbWVtb0lkOiB1bmRlZmluZWQsXG4gICAgICB9O1xuICAgIH1cblxuICAgIGlmICghZGVzdGluYXRpb25EZXRhaWxzLnF1ZXJ5KSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZEFkZHJlc3NFcnJvcihgZmFpbGVkIHRvIHBhcnNlIHF1ZXJ5IHN0cmluZzogJHthZGRyZXNzfWApO1xuICAgIH1cblxuICAgIGNvbnN0IHF1ZXJ5RGV0YWlscyA9IHF1ZXJ5c3RyaW5nLnBhcnNlKGRlc3RpbmF0aW9uRGV0YWlscy5xdWVyeSk7XG4gICAgaWYgKCFxdWVyeURldGFpbHMubWVtb0lkKSB7XG4gICAgICAvLyBpZiB0aGVyZSBhcmUgbW9yZSBwcm9wZXJ0aWVzLCB0aGUgcXVlcnkgZGV0YWlscyBuZWVkIHRvIGNvbnRhaW4gdGhlIG1lbW9JZCBwcm9wZXJ0eVxuICAgICAgdGhyb3cgbmV3IEludmFsaWRBZGRyZXNzRXJyb3IoYGludmFsaWQgcHJvcGVydHkgaW4gYWRkcmVzczogJHthZGRyZXNzfWApO1xuICAgIH1cblxuICAgIGlmIChBcnJheS5pc0FycmF5KHF1ZXJ5RGV0YWlscy5tZW1vSWQpICYmIHF1ZXJ5RGV0YWlscy5tZW1vSWQubGVuZ3RoICE9PSAxKSB7XG4gICAgICAvLyB2YWxpZCBhZGRyZXNzZXMgY2FuIG9ubHkgY29udGFpbiBvbmUgbWVtbyBpZFxuICAgICAgdGhyb3cgbmV3IEludmFsaWRBZGRyZXNzRXJyb3IoYGludmFsaWQgYWRkcmVzcyAnJHthZGRyZXNzfScsIG11c3QgY29udGFpbiBleGFjdGx5IG9uZSBtZW1vSWRgKTtcbiAgICB9XG5cbiAgICBjb25zdCBbbWVtb0lkXSA9IF8uY2FzdEFycmF5KHF1ZXJ5RGV0YWlscy5tZW1vSWQpO1xuICAgIGlmICghdGhpcy5pc1ZhbGlkTWVtb0lkKG1lbW9JZCkpIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkQWRkcmVzc0Vycm9yKGBpbnZhbGlkIGFkZHJlc3M6ICcke2FkZHJlc3N9JywgbWVtb0lkIGlzIG5vdCB2YWxpZGApO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBhZGRyZXNzOiBkZXN0aW5hdGlvbkFkZHJlc3MsXG4gICAgICBtZW1vSWQsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb252ZXJ0IGEgY3VycmVuY3kgYW1vdW50IHJlcHJlc2VudGVkIGluIGJhc2UgdW5pdHMgKHNhdG9zaGksIHdlaSwgYXRvbXMsIGRyb3BzLCBzdHJvb3BzKVxuICAgKiB0byBiaWcgdW5pdHMgKGJ0YywgZXRoLCB4cnAsIHhsbSlcbiAgICovXG4gIGJhc2VVbml0c1RvQmlnVW5pdHMoYmFzZVVuaXRzOiBzdHJpbmcgfCBudW1iZXIpOiBzdHJpbmcge1xuICAgIGNvbnN0IGRpdmlkZW5kID0gdGhpcy5nZXRCYXNlRmFjdG9yKCk7XG4gICAgY29uc3QgYmlnTnVtYmVyID0gbmV3IEJpZ051bWJlcihiYXNlVW5pdHMpLmRpdmlkZWRCeShkaXZpZGVuZCk7XG4gICAgLy8gc2V0IHRoZSBmb3JtYXQgc28gY29tbWFzIGFyZW4ndCBhZGRlZCB0byBsYXJnZSBjb2luIGFtb3VudHNcbiAgICByZXR1cm4gYmlnTnVtYmVyLnRvRm9ybWF0KDQsIG51bGwgYXMgYW55LCB7IGdyb3VwU2VwYXJhdG9yOiAnJywgZGVjaW1hbFNlcGFyYXRvcjogJy4nIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlIGFuZCByZXR1cm4gYWRkcmVzcyB3aXRoIGFwcGVuZGVkIG1lbW8gaWRcbiAgICpcbiAgICogQHBhcmFtIGFkZHJlc3NcbiAgICogQHBhcmFtIG1lbW9JZFxuICAgKi9cbiAgbm9ybWFsaXplQWRkcmVzcyh7IGFkZHJlc3MsIG1lbW9JZCB9OiBBZGRyZXNzRGV0YWlscyk6IHN0cmluZyB7XG4gICAgaWYgKG1lbW9JZCAmJiB0aGlzLmlzVmFsaWRNZW1vSWQobWVtb0lkKSkge1xuICAgICAgcmV0dXJuIGAke2FkZHJlc3N9P21lbW9JZD0ke21lbW9JZH1gO1xuICAgIH1cbiAgICByZXR1cm4gYWRkcmVzcztcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gYm9vbGVhbiBpbmRpY2F0aW5nIHdoZXRoZXIgaW5wdXQgaXMgdmFsaWQgcHVibGljIGtleSBmb3IgdGhlIGNvaW5cbiAgICpcbiAgICogQHBhcmFtIGFkZHJlc3MgLSB0aGUgYWRkcmVzcyB0byBiZSBjaGVja2VkXG4gICAqL1xuICBpc1ZhbGlkQWRkcmVzcyhhZGRyZXNzOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgYWRkcmVzc0RldGFpbHMgPSB0aGlzLmdldEFkZHJlc3NEZXRhaWxzKGFkZHJlc3MpO1xuICAgICAgcmV0dXJuIGFkZHJlc3MgPT09IHRoaXMubm9ybWFsaXplQWRkcmVzcyhhZGRyZXNzRGV0YWlscyk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0gYWRkcmVzcyAtIHRoZSBhZGRyZXNzIHRvIHZlcmlmeVxuICAgKiBAcGFyYW0gcm9vdEFkZHJlc3MgLSB0aGUgd2FsbGV0J3Mgcm9vdCBhZGRyZXNzXG4gICAqIEByZXR1cm4gdHJ1ZSBpZmYgYWRkcmVzcyBpcyBhIHdhbGxldCBhZGRyZXNzIChiYXNlZCBvbiByb290QWRkcmVzcylcbiAgICovXG4gIGlzV2FsbGV0QWRkcmVzcyh7IGFkZHJlc3MsIHJvb3RBZGRyZXNzIH06IFZlcmlmeUFkZHJlc3NPcHRpb25zKTogYm9vbGVhbiB7XG4gICAgaWYgKCFyb290QWRkcmVzcyB8fCAhXy5pc1N0cmluZyhyb290QWRkcmVzcykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyByZXF1aXJlZCBzdHJpbmcgcm9vdEFkZHJlc3MnKTtcbiAgICB9XG5cbiAgICBpZiAoIXRoaXMuaXNWYWxpZEFkZHJlc3MoYWRkcmVzcykpIHtcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkQWRkcmVzc0Vycm9yKGBpbnZhbGlkIGFkZHJlc3M6ICR7YWRkcmVzc31gKTtcbiAgICB9XG5cbiAgICBjb25zdCBhZGRyZXNzRGV0YWlscyA9IHRoaXMuZ2V0QWRkcmVzc0RldGFpbHMoYWRkcmVzcyk7XG4gICAgY29uc3Qgcm9vdEFkZHJlc3NEZXRhaWxzID0gdGhpcy5nZXRBZGRyZXNzRGV0YWlscyhyb290QWRkcmVzcyk7XG5cbiAgICBpZiAoIWFkZHJlc3NEZXRhaWxzIHx8ICFyb290QWRkcmVzc0RldGFpbHMpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBpZiAoYWRkcmVzc0RldGFpbHMuYWRkcmVzcyAhPT0gcm9vdEFkZHJlc3NEZXRhaWxzLmFkZHJlc3MpIHtcbiAgICAgIHRocm93IG5ldyBVbmV4cGVjdGVkQWRkcmVzc0Vycm9yKFxuICAgICAgICBgYWRkcmVzcyB2YWxpZGF0aW9uIGZhaWx1cmU6ICR7YWRkcmVzc0RldGFpbHMuYWRkcmVzc30gdnMgJHtyb290QWRkcmVzc0RldGFpbHMuYWRkcmVzc31gXG4gICAgICApO1xuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIEFzc2VtYmxlIGtleWNoYWluIGFuZCBoYWxmLXNpZ24gcHJlYnVpbHQgdHJhbnNhY3Rpb25cbiAgICpcbiAgICogQHBhcmFtIHBhcmFtc1xuICAgKiBAcGFyYW0gcGFyYW1zLnR4UHJlYnVpbGQge09iamVjdH0gcHJlYnVpbGQgb2JqZWN0IHJldHVybmVkIGJ5IHBsYXRmb3JtXG4gICAqIEBwYXJhbSBwYXJhbXMucHJ2IHtTdHJpbmd9IHVzZXIgcHJ2XG4gICAqIEByZXR1cm5zIHtQcm9taXNlPEVvc1NpZ25lZFRyYW5zYWN0aW9uPn1cbiAgICovXG4gIGFzeW5jIHNpZ25UcmFuc2FjdGlvbihwYXJhbXM6IEVvc1NpZ25UcmFuc2FjdGlvblBhcmFtcyk6IFByb21pc2U8RW9zU2lnbmVkVHJhbnNhY3Rpb24+IHtcbiAgICBjb25zdCBwcnY6IHN0cmluZyA9IHBhcmFtcy5wcnY7XG4gICAgY29uc3QgdHhIZXg6IHN0cmluZyA9IHBhcmFtcy50eFByZWJ1aWxkLnR4SGV4O1xuICAgIGNvbnN0IHRyYW5zYWN0aW9uOiBFb3NUeCA9IHBhcmFtcy50eFByZWJ1aWxkLnRyYW5zYWN0aW9uO1xuXG4gICAgY29uc3Qgc2lnbkJ1ZmZlcjogQnVmZmVyID0gQnVmZmVyLmZyb20odHhIZXgsICdoZXgnKTtcbiAgICBjb25zdCBwcml2YXRlS2V5QnVmZmVyID0gYmlwMzIuZnJvbUJhc2U1OChwcnYpLnByaXZhdGVLZXk7XG4gICAgaWYgKCFwcml2YXRlS2V5QnVmZmVyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ25vIHByaXZhdGVLZXknKTtcbiAgICB9XG4gICAgY29uc3Qgc2lnbmF0dXJlOiBzdHJpbmcgPSBlY2MuU2lnbmF0dXJlLnNpZ24oc2lnbkJ1ZmZlciwgcHJpdmF0ZUtleUJ1ZmZlcikudG9TdHJpbmcoKTtcblxuICAgIHRyYW5zYWN0aW9uLnNpZ25hdHVyZXMucHVzaChzaWduYXR1cmUpO1xuXG4gICAgY29uc3QgdHhQYXJhbXMgPSB7XG4gICAgICB0cmFuc2FjdGlvbixcbiAgICAgIHR4SGV4LFxuICAgICAgcmVjaXBpZW50czogcGFyYW1zLnR4UHJlYnVpbGQucmVjaXBpZW50cyxcbiAgICAgIGhlYWRlcnM6IHBhcmFtcy50eFByZWJ1aWxkLmhlYWRlcnMsXG4gICAgICB0eGlkOiBwYXJhbXMudHhQcmVidWlsZC50eGlkLFxuICAgIH07XG4gICAgcmV0dXJuIHsgaGFsZlNpZ25lZDogdHhQYXJhbXMgfTtcbiAgfVxuXG4gIHByaXZhdGUgdmFsaWRhdGVTdGFrZUFjdGlvbkRhdGEoc3Rha2VBY3Rpb25EYXRhOiBTdGFrZUFjdGlvbkRhdGEpOiBhbnkge1xuICAgIGlmIChzdGFrZUFjdGlvbkRhdGEuZnJvbSAhPT0gc3Rha2VBY3Rpb25EYXRhLnJlY2VpdmVyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHN0YWtlciAoJHtzdGFrZUFjdGlvbkRhdGEuZnJvbX0pIGFuZCByZWNlaXZlciAoJHtzdGFrZUFjdGlvbkRhdGEucmVjZWl2ZXJ9KSBtdXN0IGJlIHRoZSBzYW1lYCk7XG4gICAgfVxuXG4gICAgaWYgKHN0YWtlQWN0aW9uRGF0YS50cmFuc2ZlciAhPT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdjYW5ub3QgdHJhbnNmZXIgZnVuZHMgYXMgcGFydCBvZiBkZWxlZ2F0ZWJ3IGFjdGlvbicpO1xuICAgIH1cblxuICAgIC8vIHN0YWtlX2NwdV9xdWFudGl0eSBpcyB1c2VkIGFzIHRoZSBhbW91bnQgYmVjYXVzZSB0aGUgQml0R28gcGxhdGZvcm0gb25seSBzdGFrZXMgY3B1IGZvciB2b3RpbmcgdHJhbnNhY3Rpb25zXG4gICAgcmV0dXJuIHtcbiAgICAgIGFkZHJlc3M6IHN0YWtlQWN0aW9uRGF0YS5mcm9tLFxuICAgICAgYW1vdW50OiB0aGlzLmJpZ1VuaXRzVG9CYXNlVW5pdHMoc3Rha2VBY3Rpb25EYXRhLnN0YWtlX2NwdV9xdWFudGl0eS5zcGxpdCgnICcpWzBdKSxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSB2YWxpZGF0ZVVuc3Rha2VBY3Rpb25EYXRhKHVuc3Rha2VBY3Rpb25EYXRhOiBVbnN0YWtlQWN0aW9uRGF0YSk6IGFueSB7XG4gICAgaWYgKHVuc3Rha2VBY3Rpb25EYXRhLmZyb20gIT09IHVuc3Rha2VBY3Rpb25EYXRhLnJlY2VpdmVyKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGB1bnN0YWtlciAoJHt1bnN0YWtlQWN0aW9uRGF0YS5mcm9tfSkgYW5kIHJlY2VpdmVyICgke3Vuc3Rha2VBY3Rpb25EYXRhLnJlY2VpdmVyfSkgbXVzdCBiZSB0aGUgc2FtZWBcbiAgICAgICk7XG4gICAgfVxuICAgIGNvbnN0IGNwdUFtb3VudCA9IG5ldyBCaWdOdW1iZXIodW5zdGFrZUFjdGlvbkRhdGEudW5zdGFrZV9jcHVfcXVhbnRpdHkuc3BsaXQoJyAnKVswXSk7XG4gICAgY29uc3QgbmV0QW1vdW50ID0gbmV3IEJpZ051bWJlcih1bnN0YWtlQWN0aW9uRGF0YS51bnN0YWtlX25ldF9xdWFudGl0eS5zcGxpdCgnICcpWzBdKTtcbiAgICBjb25zdCB0b3RhbEFtb3VudCA9IGNwdUFtb3VudC5wbHVzKG5ldEFtb3VudCkudG9OdW1iZXIoKTtcblxuICAgIHJldHVybiB7XG4gICAgICBhZGRyZXNzOiB1bnN0YWtlQWN0aW9uRGF0YS5yZWNlaXZlcixcbiAgICAgIGFtb3VudDogdGhpcy5iaWdVbml0c1RvQmFzZVVuaXRzKHRvdGFsQW1vdW50KSxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgdmFsaWRhdGVWb3RlQWN0aW9uRGF0YSh2b3RlQWN0aW9uRGF0YTogVm90ZUFjdGlvbkRhdGEpIHtcbiAgICBjb25zdCBwcm94eUlzRW1wdHkgPSBfLmlzRW1wdHkodm90ZUFjdGlvbkRhdGEucHJveHkpO1xuICAgIGNvbnN0IHByb2R1Y2Vyc0lzRW1wdHkgPSBfLmlzRW1wdHkodm90ZUFjdGlvbkRhdGEucHJvZHVjZXJzKTtcbiAgICBpZiAoKHByb3h5SXNFbXB0eSAmJiBwcm9kdWNlcnNJc0VtcHR5KSB8fCAoIXByb3h5SXNFbXB0eSAmJiAhcHJvZHVjZXJzSXNFbXB0eSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndm90aW5nIHRyYW5zYWN0aW9ucyBtdXN0IHNwZWNpZnkgZWl0aGVyIHByb2R1Y2VycyBvciBwcm94eSB0byB2b3RlIGZvcicpO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBhZGRyZXNzOiB2b3RlQWN0aW9uRGF0YS52b3RlcixcbiAgICAgIHByb3h5OiB2b3RlQWN0aW9uRGF0YS5wcm94eSxcbiAgICAgIHByb2R1Y2Vyczogdm90ZUFjdGlvbkRhdGEucHJvZHVjZXJzLFxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyBjcmVhdGVUcmFuc2FjdGlvbklkSGV4KHNlcmlhbGl6ZWRUcmFuc2FjdGlvbkJ1ZmZlcjogQnVmZmVyKTogc3RyaW5nIHtcbiAgICByZXR1cm4gY3JlYXRlSGFzaCgnc2hhMjU2JykudXBkYXRlKHNlcmlhbGl6ZWRUcmFuc2FjdGlvbkJ1ZmZlcikuZGlnZXN0KCkudG9TdHJpbmcoJ2hleCcpO1xuICB9XG5cbiAgLyoqXG4gICAqIERlc2VyaWFsaXplIGEgdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSBoZWFkZXJzXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGRlc2VyaWFsaXplVHJhbnNhY3Rpb24oe1xuICAgIHRyYW5zYWN0aW9uLFxuICAgIGhlYWRlcnMsXG4gIH06IEV4cGxhaW5UcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPERlc2VyaWFsaXplZEVvc1RyYW5zYWN0aW9uPiB7XG4gICAgLy8gY3JlYXRlIGFuIGVvc2pzIEFQSSBjbGllbnRcbiAgICBjb25zdCBhcGkgPSBuZXcgQXBpKHtcbiAgICAgIGFiaVByb3ZpZGVyOiBuZXcgT2ZmbGluZUFiaVByb3ZpZGVyKCksXG4gICAgICBycGM6IG5ldyBOb29wSnNvblJwYygpLFxuICAgICAgc2lnbmF0dXJlUHJvdmlkZXI6IG5ldyBOb29wU2lnbmF0dXJlUHJvdmlkZXIoKSxcbiAgICAgIGNoYWluSWQ6IHRoaXMuZ2V0Q2hhaW5JZCgpLFxuICAgICAgLy8gVXNlIGEgY3VzdG9tIFRleHREZWNvZGVyIGFzIHRoZSBnbG9iYWwgVGV4dERlY29kZXIgbGVhZHMgdG8gY3Jhc2hlcyBpbiBPVkMgLyBFbGVjdHJvbi5cbiAgICAgIHRleHREZWNvZGVyOiBuZXcgU3RyaW5nVGV4dERlY29kZXIoKSxcbiAgICAgIHRleHRFbmNvZGVyOiBuZXcgVGV4dEVuY29kZXIoKSxcbiAgICB9KTtcblxuICAgIC8vIHR5cGUgZ3VhcmRzXG4gICAgY29uc3QgaXNUcmFuc2ZlckFjdGlvbkRhdGEgPSAodHhBY3Rpb25EYXRhOiBhbnkpOiB0eEFjdGlvbkRhdGEgaXMgVHJhbnNmZXJBY3Rpb25EYXRhID0+IHtcbiAgICAgIHJldHVybiAoXG4gICAgICAgICh0eEFjdGlvbkRhdGEgYXMgVHJhbnNmZXJBY3Rpb25EYXRhKS5mcm9tICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgKHR4QWN0aW9uRGF0YSBhcyBUcmFuc2ZlckFjdGlvbkRhdGEpLnRvICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgKHR4QWN0aW9uRGF0YSBhcyBUcmFuc2ZlckFjdGlvbkRhdGEpLnF1YW50aXR5ICE9PSB1bmRlZmluZWRcbiAgICAgICk7XG4gICAgfTtcbiAgICBjb25zdCBpc1N0YWtlQWN0aW9uRGF0YSA9ICh0eEFjdGlvbkRhdGE6IGFueSk6IHR4QWN0aW9uRGF0YSBpcyBTdGFrZUFjdGlvbkRhdGEgPT4ge1xuICAgICAgcmV0dXJuIChcbiAgICAgICAgKHR4QWN0aW9uRGF0YSBhcyBTdGFrZUFjdGlvbkRhdGEpLmZyb20gIT09IHVuZGVmaW5lZCAmJlxuICAgICAgICAodHhBY3Rpb25EYXRhIGFzIFN0YWtlQWN0aW9uRGF0YSkucmVjZWl2ZXIgIT09IHVuZGVmaW5lZCAmJlxuICAgICAgICAodHhBY3Rpb25EYXRhIGFzIFN0YWtlQWN0aW9uRGF0YSkudHJhbnNmZXIgIT09IHVuZGVmaW5lZCAmJlxuICAgICAgICAodHhBY3Rpb25EYXRhIGFzIFN0YWtlQWN0aW9uRGF0YSkuc3Rha2VfY3B1X3F1YW50aXR5ICE9PSB1bmRlZmluZWRcbiAgICAgICk7XG4gICAgfTtcbiAgICBjb25zdCBpc1Vuc3Rha2VBY3Rpb25EYXRhID0gKHR4QWN0aW9uRGF0YTogYW55KTogdHhBY3Rpb25EYXRhIGlzIFVuc3Rha2VBY3Rpb25EYXRhID0+IHtcbiAgICAgIHJldHVybiAoXG4gICAgICAgICh0eEFjdGlvbkRhdGEgYXMgVW5zdGFrZUFjdGlvbkRhdGEpLmZyb20gIT09IHVuZGVmaW5lZCAmJlxuICAgICAgICAodHhBY3Rpb25EYXRhIGFzIFVuc3Rha2VBY3Rpb25EYXRhKS5yZWNlaXZlciAhPT0gdW5kZWZpbmVkICYmXG4gICAgICAgICh0eEFjdGlvbkRhdGEgYXMgVW5zdGFrZUFjdGlvbkRhdGEpLnVuc3Rha2VfY3B1X3F1YW50aXR5ICE9PSB1bmRlZmluZWQgJiZcbiAgICAgICAgKHR4QWN0aW9uRGF0YSBhcyBVbnN0YWtlQWN0aW9uRGF0YSkudW5zdGFrZV9uZXRfcXVhbnRpdHkgIT09IHVuZGVmaW5lZFxuICAgICAgKTtcbiAgICB9O1xuICAgIGNvbnN0IGlzVm90ZUFjdGlvbkRhdGEgPSAodHhBY3Rpb25EYXRhOiBhbnkpOiB0eEFjdGlvbkRhdGEgaXMgVm90ZUFjdGlvbkRhdGEgPT4ge1xuICAgICAgcmV0dXJuICh0eEFjdGlvbkRhdGEgYXMgVm90ZUFjdGlvbkRhdGEpLnZvdGVyICE9PSB1bmRlZmluZWQ7XG4gICAgfTtcbiAgICBjb25zdCBpc1JlZnVuZEFjdGlvbkRhdGEgPSAodHhBY3Rpb25EYXRhOiBhbnkpOiB0eEFjdGlvbkRhdGEgaXMgUmVmdW5kQWN0aW9uRGF0YSA9PiB7XG4gICAgICByZXR1cm4gKHR4QWN0aW9uRGF0YSBhcyBSZWZ1bmRBY3Rpb25EYXRhKS5vd25lciAhPT0gdW5kZWZpbmVkO1xuICAgIH07XG5cbiAgICAvLyBkZXNlcmlhbGl6ZVRyYW5zYWN0aW9uXG4gICAgY29uc3Qgc2VyaWFsaXplZFR4QnVmZmVyID0gQnVmZmVyLmZyb20odHJhbnNhY3Rpb24ucGFja2VkX3RyeCwgJ2hleCcpO1xuICAgIGNvbnN0IGRlc2VyaWFsaXplZFR4SnNvbkZyb21QYWNrZWRUcnggPSBhd2FpdCBhcGkuZGVzZXJpYWxpemVUcmFuc2FjdGlvbldpdGhBY3Rpb25zKHNlcmlhbGl6ZWRUeEJ1ZmZlcik7XG5cbiAgICBpZiAoIWRlc2VyaWFsaXplZFR4SnNvbkZyb21QYWNrZWRUcngpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignY291bGQgbm90IHByb2Nlc3MgdHJhbnNhY3Rpb24gZnJvbSB0eEhleCcpO1xuICAgIH1cbiAgICBjb25zdCB0eDogRGVzZXJpYWxpemVkRW9zVHJhbnNhY3Rpb24gPSBkZXNlcmlhbGl6ZWRUeEpzb25Gcm9tUGFja2VkVHJ4O1xuXG4gICAgLy8gdmFsaWRhdGUgY29udGV4dCBmcmVlIGFjdGlvbnNcbiAgICBpZiAodHguY29udGV4dF9mcmVlX2FjdGlvbnMubGVuZ3RoICE9PSAwKSB7XG4gICAgICBpZiAodHguY29udGV4dF9mcmVlX2FjdGlvbnMubGVuZ3RoICE9PSAxKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignbnVtYmVyIG9mIGNvbnRleHQgZnJlZSBhY3Rpb25zIG11c3QgYmUgMScpO1xuICAgICAgfVxuXG4gICAgICBpZiAoXG4gICAgICAgICFfLmlzRXF1YWwoXy5waWNrKHR4LmNvbnRleHRfZnJlZV9hY3Rpb25zWzBdLCBbJ2FjY291bnQnLCAnYXV0aG9yaXphdGlvbicsICduYW1lJ10pLCB7XG4gICAgICAgICAgYWNjb3VudDogJ2Vvc2lvLm51bGwnLFxuICAgICAgICAgIGF1dGhvcml6YXRpb246IFtdLFxuICAgICAgICAgIG5hbWU6ICdub25jZScsXG4gICAgICAgIH0pIHx8XG4gICAgICAgIF8uaXNFbXB0eSh0eC5jb250ZXh0X2ZyZWVfYWN0aW9uc1swXS5kYXRhKVxuICAgICAgKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigndGhlIGNvbnRleHQgZnJlZSBhY3Rpb24gaXMgaW52YWxpZCcpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIE9ubHkgc3VwcG9ydCB0cmFuc2FjdGlvbnMgd2l0aCBvbmUgKHRyYW5zZmVyIHwgdm90ZXByb2R1Y2VyKSBvciB0d28gKGRlbGVnYXRlYncgJiB2b3RlcHJvZHVjZXIpIGFjdGlvbnNcbiAgICBpZiAodHguYWN0aW9ucy5sZW5ndGggIT09IDEgJiYgdHguYWN0aW9ucy5sZW5ndGggIT09IDIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgaW52YWxpZCBudW1iZXIgb2YgYWN0aW9uczogJHt0eC5hY3Rpb25zLmxlbmd0aH1gKTtcbiAgICB9XG5cbiAgICBjb25zdCB0eEFjdGlvbiA9IHR4LmFjdGlvbnNbMF07XG4gICAgaWYgKCF0eEFjdGlvbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHRyYW5zYWN0aW9uIGFjdGlvbicpO1xuICAgIH1cbiAgICBpZiAodHhBY3Rpb24ubmFtZSA9PT0gJ3RyYW5zZmVyJykge1xuICAgICAgLy8gVHJhbnNmZXJzIHNob3VsZCBvbmx5IGhhdmUgMSBhY3Rpb25cbiAgICAgIGlmICh0eC5hY3Rpb25zLmxlbmd0aCAhPT0gMSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHRyYW5zZmVycyBzaG91bGQgb25seSBoYXZlIDEgYWN0aW9uOiAke3R4LmFjdGlvbnMubGVuZ3RofSBnaXZlbmApO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWlzVHJhbnNmZXJBY3Rpb25EYXRhKHR4QWN0aW9uLmRhdGEpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBvciBpbmNvbXBsZXRlIHRyYW5zZmVyIGFjdGlvbiBkYXRhJyk7XG4gICAgICB9XG4gICAgICBjb25zdCB0cmFuc2ZlckFjdGlvbkRhdGEgPSB0eEFjdGlvbi5kYXRhO1xuXG4gICAgICB0eC5hZGRyZXNzID0gdHJhbnNmZXJBY3Rpb25EYXRhLnRvO1xuICAgICAgdHguYW1vdW50ID0gdGhpcy5iaWdVbml0c1RvQmFzZVVuaXRzKHRyYW5zZmVyQWN0aW9uRGF0YS5xdWFudGl0eS5zcGxpdCgnICcpWzBdKTtcbiAgICAgIHR4Lm1lbW8gPSB0cmFuc2ZlckFjdGlvbkRhdGEubWVtbztcbiAgICB9IGVsc2UgaWYgKHR4QWN0aW9uLm5hbWUgPT09ICdkZWxlZ2F0ZWJ3Jykge1xuICAgICAgLy8gVGhlIGRlbGVnYXRlYncgYWN0aW9uIHNob3VsZCBvbmx5IGJlIHBhcnQgb2Ygdm90aW5nIHRyYW5zYWN0aW9uc1xuICAgICAgaWYgKHR4LmFjdGlvbnMubGVuZ3RoICE9PSAyKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgc3Rha2luZyB0cmFuc2FjdGlvbnMgdGhhdCBpbmNsdWRlIHRoZSBkZWxlZ2F0ZWJ3IGFjdGlvbiBzaG91bGQgaGF2ZSAyIGFjdGlvbnM6ICR7dHguYWN0aW9ucy5sZW5ndGh9IGdpdmVuYFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB0eEFjdGlvbjIgPSB0eC5hY3Rpb25zWzFdO1xuICAgICAgaWYgKHR4QWN0aW9uMi5uYW1lICE9PSAndm90ZXByb2R1Y2VyJykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGludmFsaWQgc3Rha2luZyB0cmFuc2FjdGlvbiBhY3Rpb246ICR7dHhBY3Rpb24yLm5hbWV9LCBleHBlY3Rpbmc6IHZvdGVwcm9kdWNlcmApO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWlzU3Rha2VBY3Rpb25EYXRhKHR4QWN0aW9uLmRhdGEpIHx8ICFpc1ZvdGVBY3Rpb25EYXRhKHR4QWN0aW9uMi5kYXRhKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgb3IgaW5jb21wbGV0ZSBzdGFrZSBvciB2b3RlIGFjdGlvbiBkYXRhJyk7XG4gICAgICB9XG4gICAgICBjb25zdCBzdGFrZUFjdGlvbkRhdGEgPSB0eEFjdGlvbi5kYXRhO1xuICAgICAgY29uc3Qgdm90ZUFjdGlvbkRhdGEgPSB0eEFjdGlvbjIuZGF0YTtcblxuICAgICAgY29uc3QgZGVzZXJpYWxpemVkU3Rha2VBY3Rpb24gPSB0aGlzLnZhbGlkYXRlU3Rha2VBY3Rpb25EYXRhKHN0YWtlQWN0aW9uRGF0YSk7XG4gICAgICBjb25zdCBkZXNlcmlhbGl6ZWRWb3RlQWN0aW9uID0gRW9zLnZhbGlkYXRlVm90ZUFjdGlvbkRhdGEodm90ZUFjdGlvbkRhdGEpO1xuICAgICAgaWYgKGRlc2VyaWFsaXplZFN0YWtlQWN0aW9uLmFkZHJlc3MgIT09IGRlc2VyaWFsaXplZFZvdGVBY3Rpb24uYWRkcmVzcykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYHN0YWtlciAoJHtkZXNlcmlhbGl6ZWRTdGFrZUFjdGlvbi5hZGRyZXNzfSkgYW5kIHZvdGVyICgke2Rlc2VyaWFsaXplZFZvdGVBY3Rpb24uYWRkcmVzc30pIG11c3QgYmUgdGhlIHNhbWVgXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIHR4LmFtb3VudCA9IGRlc2VyaWFsaXplZFN0YWtlQWN0aW9uLmFtb3VudDtcbiAgICAgIHR4LnByb3h5ID0gZGVzZXJpYWxpemVkVm90ZUFjdGlvbi5wcm94eTtcbiAgICAgIHR4LnByb2R1Y2VycyA9IGRlc2VyaWFsaXplZFZvdGVBY3Rpb24ucHJvZHVjZXJzO1xuICAgIH0gZWxzZSBpZiAodHhBY3Rpb24ubmFtZSA9PT0gJ3ZvdGVwcm9kdWNlcicpIHtcbiAgICAgIGlmICh0eC5hY3Rpb25zLmxlbmd0aCA+IDIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCd2b3RpbmcgdHJhbnNhY3Rpb25zIHNob3VsZCBub3QgaGF2ZSBtb3JlIHRoYW4gMiBhY3Rpb25zJyk7XG4gICAgICB9XG5cbiAgICAgIGxldCBkZXNlcmlhbGl6ZWRTdGFrZUFjdGlvbjtcbiAgICAgIGlmICh0eC5hY3Rpb25zLmxlbmd0aCA9PT0gMikge1xuICAgICAgICBjb25zdCB0eEFjdGlvbjIgPSB0eC5hY3Rpb25zWzFdO1xuICAgICAgICBpZiAodHhBY3Rpb24yLm5hbWUgIT09ICdkZWxlZ2F0ZWJ3Jykge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgaW52YWxpZCBzdGFraW5nIHRyYW5zYWN0aW9uIGFjdGlvbjogJHt0eEFjdGlvbjIubmFtZX0sIGV4cGVjdGluZzogZGVsZWdhdGVid2ApO1xuICAgICAgICB9XG4gICAgICAgIGlmICghaXNTdGFrZUFjdGlvbkRhdGEodHhBY3Rpb24uZGF0YSkpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgb3IgaW5jb21wbGV0ZSBzdGFrZSBhY3Rpb24gZGF0YScpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHN0YWtlQWN0aW9uRGF0YSA9IHR4QWN0aW9uLmRhdGE7XG4gICAgICAgIGRlc2VyaWFsaXplZFN0YWtlQWN0aW9uID0gdGhpcy52YWxpZGF0ZVN0YWtlQWN0aW9uRGF0YShzdGFrZUFjdGlvbkRhdGEpO1xuICAgICAgfVxuXG4gICAgICBpZiAoIWlzVm90ZUFjdGlvbkRhdGEodHhBY3Rpb24uZGF0YSkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIG9yIGluY29tcGxldGUgdm90ZSBhY3Rpb24gZGF0YScpO1xuICAgICAgfVxuICAgICAgY29uc3Qgdm90ZUFjdGlvbkRhdGEgPSB0eEFjdGlvbi5kYXRhO1xuICAgICAgY29uc3QgZGVzZXJpYWxpemVkVm90ZUFjdGlvbiA9IEVvcy52YWxpZGF0ZVZvdGVBY3Rpb25EYXRhKHZvdGVBY3Rpb25EYXRhKTtcblxuICAgICAgaWYgKCEhZGVzZXJpYWxpemVkU3Rha2VBY3Rpb24gJiYgZGVzZXJpYWxpemVkU3Rha2VBY3Rpb24uYWRkcmVzcyAhPT0gZGVzZXJpYWxpemVkVm90ZUFjdGlvbi5hZGRyZXNzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICBgc3Rha2VyICgke2Rlc2VyaWFsaXplZFN0YWtlQWN0aW9uLmFkZHJlc3N9KSBhbmQgdm90ZXIgKCR7ZGVzZXJpYWxpemVkVm90ZUFjdGlvbi5hZGRyZXNzfSkgbXVzdCBiZSB0aGUgc2FtZWBcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgdHguYW1vdW50ID0gISFkZXNlcmlhbGl6ZWRTdGFrZUFjdGlvbiA/IGRlc2VyaWFsaXplZFN0YWtlQWN0aW9uLmFtb3VudCA6ICcwJztcbiAgICAgIHR4LnByb3h5ID0gZGVzZXJpYWxpemVkVm90ZUFjdGlvbi5wcm94eTtcbiAgICAgIHR4LnByb2R1Y2VycyA9IGRlc2VyaWFsaXplZFZvdGVBY3Rpb24ucHJvZHVjZXJzO1xuICAgIH0gZWxzZSBpZiAodHhBY3Rpb24ubmFtZSA9PT0gJ3VuZGVsZWdhdGVidycpIHtcbiAgICAgIGlmICh0eC5hY3Rpb25zLmxlbmd0aCAhPT0gMSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHVuc3Rha2Ugc2hvdWxkIG9ubHkgaGF2ZSAxIGFjdGlvbjogJHt0eC5hY3Rpb25zLmxlbmd0aH0gZ2l2ZW5gKTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFpc1Vuc3Rha2VBY3Rpb25EYXRhKHR4QWN0aW9uLmRhdGEpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBvciBpbmNvbXBsZXRlIHVuc3Rha2UgYWN0aW9uIGRhdGEnKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHVuc3Rha2VBY3Rpb25EYXRhID0gdHhBY3Rpb24uZGF0YTtcbiAgICAgIGNvbnN0IGRlc2VyaWFsaXplZFVuc3Rha2VBY3Rpb24gPSB0aGlzLnZhbGlkYXRlVW5zdGFrZUFjdGlvbkRhdGEodW5zdGFrZUFjdGlvbkRhdGEpO1xuXG4gICAgICB0eC5hbW91bnQgPSBkZXNlcmlhbGl6ZWRVbnN0YWtlQWN0aW9uLmFtb3VudDtcbiAgICAgIHR4LmFkZHJlc3MgPSBkZXNlcmlhbGl6ZWRVbnN0YWtlQWN0aW9uLmFkZHJlc3M7XG4gICAgfSBlbHNlIGlmICh0eEFjdGlvbi5uYW1lID09PSAncmVmdW5kJykge1xuICAgICAgaWYgKHR4LmFjdGlvbnMubGVuZ3RoICE9PSAxKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgcmVmdW5kIHNob3VsZCBvbmx5IGhhdmUgMSBhY3Rpb246ICR7dHguYWN0aW9ucy5sZW5ndGh9IGdpdmVuYCk7XG4gICAgICB9XG5cbiAgICAgIGlmICghaXNSZWZ1bmRBY3Rpb25EYXRhKHR4QWN0aW9uLmRhdGEpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBvciBpbmNvbXBsZXRlIHJlZnVuZCBhY3Rpb24gZGF0YScpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCByZWZ1bmRBY3Rpb25EYXRhID0gdHhBY3Rpb24uZGF0YTtcbiAgICAgIHR4LmFkZHJlc3MgPSByZWZ1bmRBY3Rpb25EYXRhLm93bmVyO1xuICAgICAgdHguYW1vdW50ID0gJzAnO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYGludmFsaWQgYWN0aW9uOiAke3R4QWN0aW9uLm5hbWV9YCk7XG4gICAgfVxuXG4gICAgLy8gR2V0IHRoZSB0eCBpZCBpZiB0eCBoZWFkZXJzIHdlcmUgcHJvdmlkZWRcbiAgICBpZiAoaGVhZGVycykge1xuICAgICAgbGV0IHJlYnVpbHRUcmFuc2FjdGlvbjtcbiAgICAgIHRyeSB7XG4gICAgICAgIC8vIHJlbW92ZSBaIGF0IHRoZSBlbmRcbiAgICAgICAgaWYgKChoZWFkZXJzLmV4cGlyYXRpb24gYXMgc3RyaW5nKS5lbmRzV2l0aCgnWicpKSB7XG4gICAgICAgICAgaGVhZGVycy5leHBpcmF0aW9uID0gKGhlYWRlcnMuZXhwaXJhdGlvbiBhcyBzdHJpbmcpLnNsaWNlKDAsIC0xKTtcbiAgICAgICAgfVxuICAgICAgICByZWJ1aWx0VHJhbnNhY3Rpb24gPSBhd2FpdCBhcGkudHJhbnNhY3QoeyAuLi50eCwgLi4uaGVhZGVycyB9LCB7IHNpZ246IGZhbHNlLCBicm9hZGNhc3Q6IGZhbHNlIH0pO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgJ0NvdWxkIG5vdCBidWlsZCB0cmFuc2FjdGlvbiB0byBnZXQgdHJhbnNhY3Rpb25faWQuIFBsZWFzZSBjaGVjayB0cmFuc2FjdGlvbiBvciBoZWFkZXJzIGZvcm1hdC4nXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIHR4LnRyYW5zYWN0aW9uX2lkID0gRW9zLmNyZWF0ZVRyYW5zYWN0aW9uSWRIZXgoKHJlYnVpbHRUcmFuc2FjdGlvbiBhcyBhbnkpLnNlcmlhbGl6ZWRUcmFuc2FjdGlvbik7XG4gICAgfVxuXG4gICAgcmV0dXJuIHR4O1xuICB9XG5cbiAgLyoqXG4gICAqIEV4cGxhaW4vcGFyc2UgdHJhbnNhY3Rpb25cbiAgICogQHBhcmFtIHBhcmFtcyAtIEV4cGxhaW5UcmFuc2FjdGlvbk9wdGlvbnNcbiAgICovXG4gIGFzeW5jIGV4cGxhaW5UcmFuc2FjdGlvbihwYXJhbXM6IEV4cGxhaW5UcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPFRyYW5zYWN0aW9uRXhwbGFuYXRpb24+IHtcbiAgICBsZXQgdHJhbnNhY3Rpb247XG4gICAgdHJ5IHtcbiAgICAgIHRyYW5zYWN0aW9uID0gYXdhaXQgdGhpcy5kZXNlcmlhbGl6ZVRyYW5zYWN0aW9uKHBhcmFtcyk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIEVPUyB0cmFuc2FjdGlvbiBvciBoZWFkZXJzOiAnICsgZS50b1N0cmluZygpKTtcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgIGRpc3BsYXlPcmRlcjogW1xuICAgICAgICAnaWQnLFxuICAgICAgICAnb3V0cHV0QW1vdW50JyxcbiAgICAgICAgJ2NoYW5nZUFtb3VudCcsXG4gICAgICAgICdvdXRwdXRzJyxcbiAgICAgICAgJ2NoYW5nZU91dHB1dHMnLFxuICAgICAgICAnZmVlJyxcbiAgICAgICAgJ21lbW8nLFxuICAgICAgICAncHJveHknLFxuICAgICAgICAncHJvZHVjZXJzJyxcbiAgICAgIF0sXG4gICAgICBpZDogdHJhbnNhY3Rpb24udHJhbnNhY3Rpb25faWQsXG4gICAgICBjaGFuZ2VPdXRwdXRzOiBbXSxcbiAgICAgIG91dHB1dEFtb3VudDogdHJhbnNhY3Rpb24uYW1vdW50LFxuICAgICAgY2hhbmdlQW1vdW50OiAwLFxuICAgICAgb3V0cHV0czogISF0cmFuc2FjdGlvbi5hZGRyZXNzID8gW3sgYWRkcmVzczogdHJhbnNhY3Rpb24uYWRkcmVzcywgYW1vdW50OiB0cmFuc2FjdGlvbi5hbW91bnQgfV0gOiBbXSxcbiAgICAgIGZlZToge30sXG4gICAgICBtZW1vOiB0cmFuc2FjdGlvbi5tZW1vLFxuICAgICAgcHJveHk6IHRyYW5zYWN0aW9uLnByb3h5LFxuICAgICAgcHJvZHVjZXJzOiB0cmFuc2FjdGlvbi5wcm9kdWNlcnMsXG4gICAgfSBhcyBhbnk7XG4gIH1cblxuICAvKipcbiAgICogQGRlcHJlY2F0ZWRcbiAgICovXG4gIGluaXRpYXRlUmVjb3ZlcnkocGFyYW1zOiBSZWNvdmVyeU9wdGlvbnMpOiBuZXZlciB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdkZXByZWNhdGVkIG1ldGhvZCcpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1ha2UgYSByZXF1ZXN0IHRvIG9uZSBvZiB0aGUgcHVibGljIEVPUyBub2RlcyBhdmFpbGFibGVcbiAgICogQHBhcmFtIHBhcmFtcy5lbmRwb2ludFxuICAgKiBAcGFyYW0gcGFyYW1zLnBheWxvYWRcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyBnZXREYXRhRnJvbU5vZGUocGFyYW1zOiB7XG4gICAgZW5kcG9pbnQ6IHN0cmluZztcbiAgICBwYXlsb2FkPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG4gIH0pOiBQcm9taXNlPHJlcXVlc3QuUmVzcG9uc2U+IHtcbiAgICBjb25zdCBub2RlVXJscyA9IHRoaXMuZ2V0UHVibGljTm9kZVVybHMoKTtcbiAgICBmb3IgKGNvbnN0IG5vZGVVcmwgb2Ygbm9kZVVybHMpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBhd2FpdCByZXF1ZXN0LnBvc3Qobm9kZVVybCArIHBhcmFtcy5lbmRwb2ludCkuc2VuZChwYXJhbXMucGF5bG9hZCk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIC8vIGxldCdzIGhvcGUgYW5vdGhlciBjYWxsIHN1Y2NlZWRzXG4gICAgICB9XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcihgVW5hYmxlIHRvIGNhbGwgZW5kcG9pbnQ6ICR7cGFyYW1zLmVuZHBvaW50fSBmcm9tIG5vZGVzOiAke18uam9pbihub2RlVXJscywgJywgJyl9YCk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IEVPUyBjaGFpbiBpbmZvIGZyb20gYSBwdWJsaWMgbm9kZVxuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIGdldENoYWluSW5mb0Zyb21Ob2RlKCk6IFByb21pc2U8YW55PiB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLmdldERhdGFGcm9tTm9kZSh7IGVuZHBvaW50OiAnL3YxL2NoYWluL2dldF9pbmZvJyB9KTtcbiAgICBpZiAocmVzcG9uc2Uuc3RhdHVzICE9PSAyMDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignVW5hYmxlIHRvIGZldGNoIGNoYWluIGluZm8nKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3BvbnNlLmJvZHk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGRhdGEgc3BlY2lmaWMgdG8gYW4gYWNjb3VudCBmcm9tIGEgcHVibGljIG5vZGVcbiAgICogQHBhcmFtIGFkZHJlc3NcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyBnZXRBY2NvdW50RnJvbU5vZGUoeyBhZGRyZXNzIH06IHsgYWRkcmVzczogc3RyaW5nIH0pOiBQcm9taXNlPGFueT4ge1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5nZXREYXRhRnJvbU5vZGUoe1xuICAgICAgZW5kcG9pbnQ6ICcvdjEvY2hhaW4vZ2V0X2FjY291bnQnLFxuICAgICAgcGF5bG9hZDogeyBhY2NvdW50X25hbWU6IGFkZHJlc3MgfSxcbiAgICB9KTtcbiAgICBpZiAocmVzcG9uc2Uuc3RhdHVzICE9PSAyMDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQWNjb3VudCBub3QgZm91bmQnKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3BvbnNlLmJvZHk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGJsb2NrIGRhdGEgZnJvbSBhIHB1YmxpYyBub2RlIHVzaW5nIGl0cyBibG9jayBudW1iZXIgb3IgYmxvY2sgaWRcbiAgICogQHBhcmFtIGJsb2NrTnVtT3JJZFxuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIGdldEJsb2NrRnJvbU5vZGUoeyBibG9ja051bU9ySWQgfTogeyBibG9ja051bU9ySWQ6IHN0cmluZyB9KTogUHJvbWlzZTxhbnk+IHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuZ2V0RGF0YUZyb21Ob2RlKHtcbiAgICAgIGVuZHBvaW50OiAnL3YxL2NoYWluL2dldF9ibG9jaycsXG4gICAgICBwYXlsb2FkOiB7IGJsb2NrX251bV9vcl9pZDogYmxvY2tOdW1PcklkIH0sXG4gICAgfSk7XG4gICAgaWYgKHJlc3BvbnNlLnN0YXR1cyAhPT0gMjAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Jsb2NrIG5vdCBmb3VuZCcpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzcG9uc2UuYm9keTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgaGVhZGVycyBmb3IgYW4gRU9TIHR4IGZyb20gYSBwdWJsaWMgbm9kZVxuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIGdldFRyYW5zYWN0aW9uSGVhZGVyc0Zyb21Ob2RlKCk6IFByb21pc2U8YW55PiB7XG4gICAgY29uc3QgY2hhaW5JbmZvID0gYXdhaXQgdGhpcy5nZXRDaGFpbkluZm9Gcm9tTm9kZSgpO1xuICAgIGNvbnN0IGhlYWRCbG9ja0luZm9SZXN1bHQgPSBhd2FpdCB0aGlzLmdldEJsb2NrRnJvbU5vZGUoeyBibG9ja051bU9ySWQ6IGNoYWluSW5mby5oZWFkX2Jsb2NrX251bSB9KTtcbiAgICBjb25zdCBleHBpcmVTZWNvbmRzID0gMjg4MDA7IC8vIG1heGltdW0gdHggZXhwaXJlIHRpbWUgb2YgOGhcbiAgICBjb25zdCBjaGFpbkRhdGUgPSBuZXcgRGF0ZShjaGFpbkluZm8uaGVhZF9ibG9ja190aW1lICsgJ1onKS5nZXRUaW1lKCk7XG4gICAgY29uc3QgZXhwaXJhdGlvbkRhdGUgPSBuZXcgRGF0ZShjaGFpbkRhdGUgKyBleHBpcmVTZWNvbmRzICogMTAwMCk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgZXhwaXJhdGlvbjogZXhwaXJhdGlvbkRhdGUudG9JU09TdHJpbmcoKSxcbiAgICAgIHJlZl9ibG9ja19udW06IGNoYWluSW5mby5oZWFkX2Jsb2NrX251bSAmIDB4ZmZmZixcbiAgICAgIHJlZl9ibG9ja19wcmVmaXg6IGhlYWRCbG9ja0luZm9SZXN1bHQucmVmX2Jsb2NrX3ByZWZpeCxcbiAgICB9O1xuICB9XG5cbiAgcHJvdGVjdGVkIGdldFRyYW5zZmVyQWN0aW9uKHsgcmVjaXBpZW50LCBzZW5kZXIsIGFtb3VudCwgbWVtbyB9OiBhbnkpOiBFb3NUcmFuc2FjdGlvbkFjdGlvbiB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGFjY291bnQ6ICdlb3Npby50b2tlbicsXG4gICAgICBuYW1lOiAndHJhbnNmZXInLFxuICAgICAgYXV0aG9yaXphdGlvbjogW1xuICAgICAgICB7XG4gICAgICAgICAgYWN0b3I6IHNlbmRlcixcbiAgICAgICAgICBwZXJtaXNzaW9uOiAnYWN0aXZlJyxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgICBkYXRhOiB7XG4gICAgICAgIGZyb206IHNlbmRlcixcbiAgICAgICAgdG86IHJlY2lwaWVudCxcbiAgICAgICAgcXVhbnRpdHk6IGAke3RoaXMuYmFzZVVuaXRzVG9CaWdVbml0cyhhbW91bnQpfSBFT1NgLFxuICAgICAgICBtZW1vOiAhXy5pc05pbChtZW1vKSA/IG1lbW8gOiAnJywgLy8gTWVtbyBtdXN0IGJlIGRlZmluZWQsIHNldCBpdCB0byBlbXB0eSBzdHJpbmcgaWYgaXQgaXMgbm90XG4gICAgICB9LFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogU2lnbiBhIHRyYW5zYWN0aW9uIHdpdGggYSBrZXlcbiAgICogQHBhcmFtIHNpZ25hYmxlVHhcbiAgICogQHBhcmFtIHNpZ25pbmdLZXlcbiAgICovXG4gIHNpZ25UeChzaWduYWJsZVR4OiBzdHJpbmcsIHNpZ25pbmdLZXk6IGJpcDMyLkJJUDMySW50ZXJmYWNlKTogc3RyaW5nIHtcbiAgICBjb25zdCBzaWduQnVmZmVyID0gQnVmZmVyLmZyb20oc2lnbmFibGVUeCwgJ2hleCcpO1xuICAgIGNvbnN0IHByaXZhdGVLZXlCdWZmZXIgPSBzaWduaW5nS2V5LnByaXZhdGVLZXk7XG4gICAgcmV0dXJuIGVjYy5TaWduYXR1cmUuc2lnbihzaWduQnVmZmVyLCBwcml2YXRlS2V5QnVmZmVyKS50b1N0cmluZygpO1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkcyBhIGZ1bmRzIHJlY292ZXJ5IHRyYW5zYWN0aW9uIHdpdGhvdXQgQml0R29cbiAgICogQHBhcmFtIHBhcmFtc1xuICAgKi9cbiAgYXN5bmMgcmVjb3ZlcihwYXJhbXM6IFJlY292ZXJ5T3B0aW9ucyk6IFByb21pc2U8UmVjb3ZlcnlUcmFuc2FjdGlvbj4ge1xuICAgIGlmICghcGFyYW1zLnJvb3RBZGRyZXNzKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgc3RyaW5nIHJvb3RBZGRyZXNzJyk7XG4gICAgfVxuXG4gICAgY29uc3QgaXNLcnNSZWNvdmVyeSA9IGdldElzS3JzUmVjb3ZlcnkocGFyYW1zKTtcbiAgICBjb25zdCBpc1Vuc2lnbmVkU3dlZXAgPSBnZXRJc1Vuc2lnbmVkU3dlZXAocGFyYW1zKTtcblxuICAgIGNvbnN0IHsga3JzUHJvdmlkZXIgfSA9IHBhcmFtcztcbiAgICBpZiAoZ2V0SXNLcnNSZWNvdmVyeShwYXJhbXMpKSB7XG4gICAgICBjaGVja0tyc1Byb3ZpZGVyKHRoaXMsIGtyc1Byb3ZpZGVyKTtcbiAgICB9XG5cbiAgICBpZiAoIXRoaXMuaXNWYWxpZEFkZHJlc3MocGFyYW1zLnJlY292ZXJ5RGVzdGluYXRpb24pKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgZGVzdGluYXRpb24gYWRkcmVzcyEnKTtcbiAgICB9XG5cbiAgICBjb25zdCBrZXlzID0gZ2V0QmlwMzJLZXlzKHRoaXMuYml0Z28sIHBhcmFtcywgeyByZXF1aXJlQml0R29YcHViOiBmYWxzZSB9KTtcblxuICAgIGNvbnN0IHJvb3RBZGRyZXNzRGV0YWlscyA9IHRoaXMuZ2V0QWRkcmVzc0RldGFpbHMocGFyYW1zLnJvb3RBZGRyZXNzKTtcbiAgICBjb25zdCBhY2NvdW50ID0gYXdhaXQgdGhpcy5nZXRBY2NvdW50RnJvbU5vZGUoeyBhZGRyZXNzOiByb290QWRkcmVzc0RldGFpbHMuYWRkcmVzcyB9KTtcblxuICAgIGlmICghYWNjb3VudC5jb3JlX2xpcXVpZF9iYWxhbmNlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvdWxkIG5vdCBmaW5kIGFueSBiYWxhbmNlIHRvIHJlY292ZXJ5IGZvciAnICsgcGFyYW1zLnJvb3RBZGRyZXNzKTtcbiAgICB9XG5cbiAgICBpZiAoIWFjY291bnQucGVybWlzc2lvbnMpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ291bGQgbm90IGZpbmQgcGVybWlzc2lvbnMgZm9yICcgKyBwYXJhbXMucm9vdEFkZHJlc3MpO1xuICAgIH1cbiAgICBjb25zdCB1c2VyUHViID0gZWNjLlB1YmxpY0tleS5mcm9tQnVmZmVyKGtleXNbMF0ucHVibGljS2V5KS50b1N0cmluZygpO1xuICAgIGNvbnN0IGJhY2t1cFB1YiA9IGVjYy5QdWJsaWNLZXkuZnJvbUJ1ZmZlcihrZXlzWzFdLnB1YmxpY0tleSkudG9TdHJpbmcoKTtcblxuICAgIGNvbnN0IGFjdGl2ZVBlcm1pc3Npb24gPSBfLmZpbmQoYWNjb3VudC5wZXJtaXNzaW9ucywgeyBwZXJtX25hbWU6ICdhY3RpdmUnIH0pO1xuICAgIGNvbnN0IHJlcXVpcmVkQXV0aCA9IF8uZ2V0KGFjdGl2ZVBlcm1pc3Npb24sICdyZXF1aXJlZF9hdXRoJyk7XG4gICAgaWYgKCFyZXF1aXJlZEF1dGgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignUmVxdWlyZWQgYXV0aCBmb3IgYWN0aXZlIHBlcm1pc3Npb24gbm90IGZvdW5kIGluIGFjY291bnQnKTtcbiAgICB9XG4gICAgaWYgKHJlcXVpcmVkQXV0aC50aHJlc2hvbGQgIT09IDIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignVW5leHBlY3RlZCBhY3RpdmUgcGVybWlzc2lvbiB0aHJlc2hvbGQnKTtcbiAgICB9XG5cbiAgICBjb25zdCBmb3VuZFB1YnMgPSB7fTtcbiAgICBjb25zdCByZXF1aXJlZEF1dGhLZXlzID0gcmVxdWlyZWRBdXRoLmtleXM7XG4gICAgZm9yIChjb25zdCBzaWduZXIgb2YgcmVxdWlyZWRBdXRoS2V5cykge1xuICAgICAgaWYgKHNpZ25lci53ZWlnaHQgIT09IDEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdpbnZhbGlkIHNpZ25lciB3ZWlnaHQnKTtcbiAgICAgIH1cbiAgICAgIC8vIGlmIGl0J3MgYSBkdXBlIG9mIGEgcHViIHdlIGFscmVhZHkga25vdywgYmxvY2tcbiAgICAgIGlmIChmb3VuZFB1YnNbc2lnbmVyLmtleV0pIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdkdXBsaWNhdGUgc2lnbmVyIGtleScpO1xuICAgICAgfVxuICAgICAgZm91bmRQdWJzW3NpZ25lci5rZXldID0gKGZvdW5kUHVic1tzaWduZXIua2V5XSB8fCAwKSArIDE7XG4gICAgfVxuICAgIGlmIChmb3VuZFB1YnNbdXNlclB1Yl0gIT09IDEgfHwgZm91bmRQdWJzW2JhY2t1cFB1Yl0gIT09IDEpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndW5leHBlY3RlZCBpbmNpZGVuY2UgZnJlcXVlbmN5IG9mIHVzZXIgc2lnbmVyIGtleScpO1xuICAgIH1cblxuICAgIGNvbnN0IGFjY291bnRCYWxhbmNlID0gYWNjb3VudC5jb3JlX2xpcXVpZF9iYWxhbmNlLnNwbGl0KCcgJylbMF07XG4gICAgY29uc3QgcmVjb3ZlcnlBbW91bnQgPSB0aGlzLmJpZ1VuaXRzVG9CYXNlVW5pdHMobmV3IEJpZ051bWJlcihhY2NvdW50QmFsYW5jZSkudG9GaXhlZCgpKTtcblxuICAgIGNvbnN0IGRlc3RpbmF0aW9uQWRkcmVzcyA9IHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uO1xuICAgIGNvbnN0IGRlc3RpbmF0aW9uQWRkcmVzc0RldGFpbHMgPSB0aGlzLmdldEFkZHJlc3NEZXRhaWxzKGRlc3RpbmF0aW9uQWRkcmVzcyk7XG4gICAgY29uc3QgZGVzdGluYXRpb25BY2NvdW50ID0gYXdhaXQgdGhpcy5nZXRBY2NvdW50RnJvbU5vZGUoeyBhZGRyZXNzOiBkZXN0aW5hdGlvbkFkZHJlc3NEZXRhaWxzLmFkZHJlc3MgfSk7XG4gICAgaWYgKCFkZXN0aW5hdGlvbkFjY291bnQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRGVzdGluYXRpb24gYWNjb3VudCBub3QgZm91bmQnKTtcbiAgICB9XG5cbiAgICBjb25zdCB0cmFuc2FjdGlvbkhlYWRlcnMgPSBhd2FpdCB0aGlzLmdldFRyYW5zYWN0aW9uSGVhZGVyc0Zyb21Ob2RlKCk7XG4gICAgaWYgKCF0cmFuc2FjdGlvbkhlYWRlcnMpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ291bGQgbm90IGdldCB0cmFuc2FjdGlvbiBoZWFkZXJzIGZyb20gbm9kZScpO1xuICAgIH1cbiAgICBjb25zdCBoZWFkZXJzOiBFb3NUcmFuc2FjdGlvbkhlYWRlcnMgPSB0cmFuc2FjdGlvbkhlYWRlcnM7XG4gICAgY29uc3QgbmF0aXZlRGF0ZSA9IG5ldyBEYXRlKGhlYWRlcnMuZXhwaXJhdGlvbiBhcyBzdHJpbmcpO1xuICAgIC8vIGRyb3AgbWlsbGlzZWNvbmRzIGFuZCB0cmFpbGluZyBaIGZyb20gZXhwaXJhdGlvblxuICAgIG5hdGl2ZURhdGUuc2V0TWlsbGlzZWNvbmRzKDApO1xuICAgIGNvbnN0IGV4cGlyYXRpb24gPSBuYXRpdmVEYXRlLnRvSVNPU3RyaW5nKCk7XG4gICAgaWYgKGV4cGlyYXRpb24uZW5kc1dpdGgoJ1onKSkge1xuICAgICAgaGVhZGVycy5leHBpcmF0aW9uID0gZXhwaXJhdGlvbi5zbGljZSgwLCAtMSk7XG4gICAgfVxuXG4gICAgLy8gY3JlYXRlIGFuIG9mZmxpbmUgZW9zanMgQVBJIGNsaWVudFxuICAgIGNvbnN0IGFwaSA9IG5ldyBBcGkoe1xuICAgICAgcnBjOiBuZXcgTm9vcEpzb25ScGMoKSxcbiAgICAgIHNpZ25hdHVyZVByb3ZpZGVyOiBuZXcgTm9vcFNpZ25hdHVyZVByb3ZpZGVyKCksXG4gICAgICBhYmlQcm92aWRlcjogbmV3IE9mZmxpbmVBYmlQcm92aWRlcigpLFxuICAgICAgY2hhaW5JZDogdGhpcy5nZXRDaGFpbklkKCksXG4gICAgICB0ZXh0RGVjb2RlcjogbmV3IFRleHREZWNvZGVyKCksXG4gICAgICB0ZXh0RW5jb2RlcjogbmV3IFRleHRFbmNvZGVyKCksXG4gICAgfSk7XG5cbiAgICBjb25zdCB0cmFuc2ZlckFjdGlvbiA9IHRoaXMuZ2V0VHJhbnNmZXJBY3Rpb24oe1xuICAgICAgcmVjaXBpZW50OiBkZXN0aW5hdGlvbkFkZHJlc3NEZXRhaWxzLmFkZHJlc3MsXG4gICAgICBzZW5kZXI6IHJvb3RBZGRyZXNzRGV0YWlscy5hZGRyZXNzLFxuICAgICAgYW1vdW50OiBuZXcgQmlnTnVtYmVyKHJlY292ZXJ5QW1vdW50KSxcbiAgICAgIG1lbW86IGRlc3RpbmF0aW9uQWRkcmVzc0RldGFpbHMubWVtb0lkLFxuICAgIH0pO1xuXG4gICAgbGV0IHNlcmlhbGl6ZWRUcmFuc2FjdGlvbjtcbiAgICBjb25zdCB0eCA9IHsgYWN0aW9uczogW3RyYW5zZmVyQWN0aW9uXSB9O1xuICAgIHRyeSB7XG4gICAgICBzZXJpYWxpemVkVHJhbnNhY3Rpb24gPSBhd2FpdCBhcGkudHJhbnNhY3QoeyAuLi50eCwgLi4uaGVhZGVycyB9LCB7IHNpZ246IGZhbHNlLCBicm9hZGNhc3Q6IGZhbHNlIH0pO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRW9zIEFQSSBlcnJvcjogQ291bGQgbm90IGJ1aWxkIHRyYW5zYWN0aW9uJyk7XG4gICAgfVxuXG4gICAgLy8gY3JlYXRlIHRyYW5zYWN0aW9uIG9iamVjdFxuICAgIGNvbnN0IHNlcmlhbGl6ZWRUcmFuc2FjdGlvbkhleCA9IEJ1ZmZlci5mcm9tKHNlcmlhbGl6ZWRUcmFuc2FjdGlvbi5zZXJpYWxpemVkVHJhbnNhY3Rpb24pLnRvU3RyaW5nKCdoZXgnKTtcbiAgICBjb25zdCB0cmFuc2FjdGlvbklkID0gRW9zLmNyZWF0ZVRyYW5zYWN0aW9uSWRIZXgoc2VyaWFsaXplZFRyYW5zYWN0aW9uLnNlcmlhbGl6ZWRUcmFuc2FjdGlvbik7XG4gICAgY29uc3QgdHhPYmplY3QgPSB7XG4gICAgICB0cmFuc2FjdGlvbjoge1xuICAgICAgICBjb21wcmVzc2lvbjogJ25vbmUnLFxuICAgICAgICBwYWNrZWRfdHJ4OiBzZXJpYWxpemVkVHJhbnNhY3Rpb25IZXgsXG4gICAgICAgIHNpZ25hdHVyZXM6IFtdIGFzIHN0cmluZ1tdLFxuICAgICAgfSxcbiAgICAgIHR4aWQ6IHRyYW5zYWN0aW9uSWQsXG4gICAgICByZWNvdmVyeUFtb3VudDogYWNjb3VudEJhbGFuY2UsXG4gICAgICBjb2luOiB0aGlzLmdldENoYWluKCksXG4gICAgICB0eEhleDogJycsXG4gICAgfTtcblxuICAgIGNvbnN0IHNpZ25hYmxlVHggPSBCdWZmZXIuY29uY2F0KFtcbiAgICAgIEJ1ZmZlci5mcm9tKHRoaXMuZ2V0Q2hhaW5JZCgpLCAnaGV4JyksIC8vIFRoZSBDaGFpbklEIHJlcHJlc2VudGluZyB0aGUgY2hhaW4gdGhhdCB3ZSBhcmUgb25cbiAgICAgIEJ1ZmZlci5mcm9tKHNlcmlhbGl6ZWRUcmFuc2FjdGlvbi5zZXJpYWxpemVkVHJhbnNhY3Rpb24pLCAvLyBUaGUgc2VyaWFsaXplZCB1bnNpZ25lZCB0eFxuICAgICAgQnVmZmVyLmZyb20obmV3IFVpbnQ4QXJyYXkoMzIpKSwgLy8gU29tZSBwYWRkaW5nXG4gICAgXSkudG9TdHJpbmcoJ2hleCcpO1xuXG4gICAgaWYgKGlzVW5zaWduZWRTd2VlcCkge1xuICAgICAgdHhPYmplY3QudHhIZXggPSBzaWduYWJsZVR4O1xuICAgICAgcmV0dXJuIHR4T2JqZWN0O1xuICAgIH1cblxuICAgIGNvbnN0IHVzZXJTaWduYXR1cmUgPSB0aGlzLnNpZ25UeChzaWduYWJsZVR4LCBrZXlzWzBdKTtcbiAgICB0eE9iamVjdC50cmFuc2FjdGlvbi5zaWduYXR1cmVzLnB1c2godXNlclNpZ25hdHVyZSk7XG5cbiAgICBpZiAoIWlzS3JzUmVjb3ZlcnkpIHtcbiAgICAgIGNvbnN0IGJhY2t1cFNpZ25hdHVyZSA9IHRoaXMuc2lnblR4KHNpZ25hYmxlVHgsIGtleXNbMV0pO1xuICAgICAgdHhPYmplY3QudHJhbnNhY3Rpb24uc2lnbmF0dXJlcy5wdXNoKGJhY2t1cFNpZ25hdHVyZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHR4T2JqZWN0O1xuICB9XG5cbiAgYXN5bmMgcGFyc2VUcmFuc2FjdGlvbihwYXJhbXM6IFBhcnNlVHJhbnNhY3Rpb25PcHRpb25zKTogUHJvbWlzZTxQYXJzZWRUcmFuc2FjdGlvbj4ge1xuICAgIHJldHVybiB7fTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWZXJpZnkgdGhhdCBhIHRyYW5zYWN0aW9uIHByZWJ1aWxkIGNvbXBsaWVzIHdpdGggdGhlIG9yaWdpbmFsIGludGVudGlvblxuICAgKlxuICAgKiBAcGFyYW0gcGFyYW1zXG4gICAqIEBwYXJhbSBwYXJhbXMudHhQYXJhbXMgcGFyYW1zIHVzZWQgdG8gYnVpbGQgdGhlIHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSBwYXJhbXMudHhQcmVidWlsZCB0aGUgcHJlYnVpbHQgdHJhbnNhY3Rpb25cbiAgICovXG4gIGFzeW5jIHZlcmlmeVRyYW5zYWN0aW9uKHBhcmFtczogRW9zVmVyaWZ5VHJhbnNhY3Rpb25PcHRpb25zKTogUHJvbWlzZTxhbnk+IHtcbiAgICBjb25zdCB7IHR4UGFyYW1zOiB0eFBhcmFtcywgdHhQcmVidWlsZDogdHhQcmVidWlsZCB9ID0gcGFyYW1zO1xuXG4gICAgLy8gY2hlY2sgaWYgdGhlIHRyYW5zYWN0aW9uIGhhcyBhIHR4SGV4XG4gICAgaWYgKCF0eFByZWJ1aWxkLnR4SGV4KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgdHggcHJlYnVpbGQgcHJvcGVydHkgdHhIZXgnKTtcbiAgICB9XG5cbiAgICAvLyBjb25zdHJ1Y3QgdHJhbnNhY3Rpb24gZnJvbSB0eEhleFxuICAgIGNvbnN0IHR4RnJvbUhleCA9IEJ1ZmZlci5mcm9tKHR4UHJlYnVpbGQudHhIZXgsICdoZXgnKTtcbiAgICBjb25zdCB0eERhdGFXaXRoUGFkZGluZyA9IHR4RnJvbUhleC5zbGljZSgzMik7XG4gICAgY29uc3QgdHhEYXRhID0gdHhEYXRhV2l0aFBhZGRpbmcuc2xpY2UoMCwgdHhEYXRhV2l0aFBhZGRpbmcubGVuZ3RoIC0gMzIpO1xuICAgIGNvbnN0IGRlc2VyaWFsaXplZFR4SnNvbiA9IGF3YWl0IHRoaXMuZGVzZXJpYWxpemVUcmFuc2FjdGlvbih7XG4gICAgICB0cmFuc2FjdGlvbjogeyBwYWNrZWRfdHJ4OiB0eERhdGEudG9TdHJpbmcoJ2hleCcpIH0sXG4gICAgICBoZWFkZXJzOiB0eFByZWJ1aWxkLmhlYWRlcnMsXG4gICAgfSk7XG4gICAgaWYgKCFkZXNlcmlhbGl6ZWRUeEpzb24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignY291bGQgbm90IHByb2Nlc3MgdHJhbnNhY3Rpb24gZnJvbSB0eEhleCcpO1xuICAgIH1cbiAgICBjb25zdCB0eEpzb25Gcm9tSGV4OiBEZXNlcmlhbGl6ZWRFb3NUcmFuc2FjdGlvbiA9IGRlc2VyaWFsaXplZFR4SnNvbjtcblxuICAgIC8vIGNoZWNrIHRoYXQgaWYgdHhQYXJhbXMgaGFzIGEgdHhQcmVidWlsZCwgaXQgc2hvdWxkIGJlIHRoZSBzYW1lIGFzIHR4UHJlYnVpbGRcbiAgICBpZiAodHhQYXJhbXMudHhQcmVidWlsZCAmJiAhXy5pc0VxdWFsKHR4UGFyYW1zLnR4UHJlYnVpbGQsIHR4UHJlYnVpbGQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2lucHV0cyB0eFBhcmFtcy50eFByZWJ1aWxkIGFuZCB0eFByZWJ1aWxkIGV4cGVjdGVkIHRvIGJlIGVxdWFsIGJ1dCB3ZXJlIG5vdCcpO1xuICAgIH1cblxuICAgIC8vIGNoZWNrIGlmIHByZWJ1aWxkIGhhcyBhIHRyYW5zYWN0aW9uXG4gICAgaWYgKCF0eFByZWJ1aWxkLnRyYW5zYWN0aW9uKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgdHJhbnNhY3Rpb24gaW4gdHhQcmVidWlsZCcpO1xuICAgIH1cblxuICAgIC8vIGNoZWNrIGlmIHRyYW5zYWN0aW9uIGhhcyBhIHBhY2tlZF90cnhcbiAgICBpZiAoIXR4UHJlYnVpbGQudHJhbnNhY3Rpb24/LnBhY2tlZF90cngpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyByZXF1aXJlZCB0cmFuc2FjdGlvbi5wYWNrZWRfdHJ4IGluIHR4UHJlYnVpbGQnKTtcbiAgICB9XG5cbiAgICAvLyBjb25zdHJ1Y3QgdHJhbnNhY3Rpb24gdXNpbmcgcGFja2VkX3RyeFxuICAgIGNvbnN0IGRlc2VyaWFsaXplZFR4SnNvbkZyb21QYWNrZWRUcnggPSBhd2FpdCB0aGlzLmRlc2VyaWFsaXplVHJhbnNhY3Rpb24oe1xuICAgICAgdHJhbnNhY3Rpb246IHsgcGFja2VkX3RyeDogdHhQcmVidWlsZC50cmFuc2FjdGlvbi5wYWNrZWRfdHJ4IH0sXG4gICAgICBoZWFkZXJzOiB0eFByZWJ1aWxkLmhlYWRlcnMsXG4gICAgfSk7XG4gICAgaWYgKCFkZXNlcmlhbGl6ZWRUeEpzb25Gcm9tUGFja2VkVHJ4KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2NvdWxkIG5vdCBwcm9jZXNzIHRyYW5zYWN0aW9uIGZyb20gcGFja2VkX3RyeCcpO1xuICAgIH1cbiAgICBjb25zdCB0eEpzb25Gcm9tUGFja2VkVHJ4OiBEZXNlcmlhbGl6ZWRFb3NUcmFuc2FjdGlvbiA9IGRlc2VyaWFsaXplZFR4SnNvbkZyb21QYWNrZWRUcng7XG5cbiAgICAvLyBkZWVwIGNoZWNrIG9mIG9iamVjdCBmcm9tIHBhY2tlZF90cnggYW5kIHR4SGV4XG4gICAgaWYgKCFfLmlzRXF1YWwodHhKc29uRnJvbVBhY2tlZFRyeCwgdHhKc29uRnJvbUhleCkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndW5wYWNrZWQgcGFja2VkX3RyeCBhbmQgdW5wYWNrZWQgdHhIZXggYXJlIG5vdCBlcXVhbCcpO1xuICAgIH1cblxuICAgIGlmICh0eFBhcmFtcy5yZWNpcGllbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignb25seSAwIG9yIDEgcmVjaXBpZW50cyBhcmUgc3VwcG9ydGVkJyk7XG4gICAgfVxuXG4gICAgLy8gY2hlY2sgdGhlIGFtb3VudHMsIHJlY2lwaWVudCwgYW5kIGNvaW4gbmFtZSBmb3IgdHJhbnNmZXJzXG4gICAgaWYgKHR4UGFyYW1zLnJlY2lwaWVudHMubGVuZ3RoID09PSAxKSB7XG4gICAgICBjb25zdCBleHBlY3RlZE91dHB1dCA9IHR4UGFyYW1zLnJlY2lwaWVudHNbMF07XG5cbiAgICAgIC8vIGNoZWNrIG91dHB1dCBhZGRyZXNzIGFuZCBtZW1vSWRcbiAgICAgIGNvbnN0IGV4cGVjdGVkT3V0cHV0QWRkcmVzc0FuZE1lbW9JZCA9IHRoaXMuZ2V0QWRkcmVzc0RldGFpbHMoZXhwZWN0ZWRPdXRwdXQuYWRkcmVzcyk7XG4gICAgICBjb25zdCB0eEhleEFjdGlvbiA9IHR4SnNvbkZyb21IZXguYWN0aW9uc1swXTtcbiAgICAgIGNvbnN0IHR4SGV4VHJhbnNmZXJBY3Rpb24gPSB0eEhleEFjdGlvbi5kYXRhIGFzIFRyYW5zZmVyQWN0aW9uRGF0YTtcblxuICAgICAgaWYgKHR4SGV4VHJhbnNmZXJBY3Rpb24udG8gIT09IGV4cGVjdGVkT3V0cHV0QWRkcmVzc0FuZE1lbW9JZC5hZGRyZXNzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigndHhIZXggcmVjZWl2ZSBhZGRyZXNzIGRvZXMgbm90IG1hdGNoIGV4cGVjdGVkIHJlY2lwaWVudCBhZGRyZXNzJyk7XG4gICAgICB9XG4gICAgICAvLyBjaGVjayBpZiB0eGFjdGlvbiBtZW1vaWQgaXMgZXF1YWwgdG8gYWRkcmVzcyBtZW1vIGlkIG9ubHkgaWYgYWRkcmVzcyBhbHNvIGhhcyBtZW1vaWQgcHJlc2VudFxuICAgICAgaWYgKCFfLmlzVW5kZWZpbmVkKGV4cGVjdGVkT3V0cHV0QWRkcmVzc0FuZE1lbW9JZC5tZW1vSWQpKSB7XG4gICAgICAgIGlmICh0eEhleFRyYW5zZmVyQWN0aW9uLm1lbW8gIT09IGV4cGVjdGVkT3V0cHV0QWRkcmVzc0FuZE1lbW9JZC5tZW1vSWQpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3R4SGV4IHJlY2VpdmUgbWVtb0lkIGRvZXMgbm90IG1hdGNoIGV4cGVjdGVkIHJlY2lwaWVudCBtZW1vSWQnKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBjaGVjayBhbW91bnQgYW5kIGNvaW5cbiAgICAgIGNvbnN0IGV4cGVjdGVkT3V0cHV0QW1vdW50ID0gZXhwZWN0ZWRPdXRwdXQuYW1vdW50O1xuICAgICAgY29uc3QgYWN0dWFsQW1vdW50QW5kQ29pbiA9IHR4SGV4VHJhbnNmZXJBY3Rpb24ucXVhbnRpdHkuc3BsaXQoJyAnKTtcbiAgICAgIGNvbnN0IGFjdHVhbE91dHB1dEFtb3VudCA9IHRoaXMuYmlnVW5pdHNUb0Jhc2VVbml0cyhhY3R1YWxBbW91bnRBbmRDb2luWzBdKTtcbiAgICAgIGlmIChleHBlY3RlZE91dHB1dEFtb3VudCAhPT0gYWN0dWFsT3V0cHV0QW1vdW50KSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcigndHhIZXggcmVjZWl2ZSBhbW91bnQgZG9lcyBub3QgbWF0Y2ggZXhwZWN0ZWQgcmVjaXBpZW50IGFtb3VudCcpO1xuICAgICAgfVxuXG4gICAgICBpZiAodHhQcmVidWlsZC5jb2luID09PSAnZW9zJyB8fCB0eFByZWJ1aWxkLmNvaW4gPT09ICd0ZW9zJykge1xuICAgICAgICBjb25zdCBleHBlY3RlZFN5bWJvbCA9IF8uaXNOaWwodHhQcmVidWlsZC50b2tlbikgPyAnRU9TJyA6IHR4UHJlYnVpbGQudG9rZW4uc3BsaXQoJzonKVsxXTtcblxuICAgICAgICBpZiAoYWN0dWFsQW1vdW50QW5kQ29pblsxXSAhPT0gZXhwZWN0ZWRTeW1ib2wpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3R4SGV4IHJlY2VpdmUgc3ltYm9sIGRvZXMgbm90IG1hdGNoIGV4cGVjdGVkIHJlY2lwaWVudCBzeW1ib2wnKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gdGhpcyBzaG91bGQgbmV2ZXIgaGFwcGVuXG4gICAgICAgIHRocm93IG5ldyBFcnJvcigndHhIZXggY29pbiBuYW1lIGRvZXMgbm90IG1hdGNoIGV4cGVjdGVkIGNvaW4gbmFtZScpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlIGEgcmFuZG9tIEVPUyBhZGRyZXNzLlxuICAgKlxuICAgKiBUaGlzIGlzIGp1c3QgYSByYW5kb20gc3RyaW5nIHdoaWNoIGFiaWRlcyBieSB0aGUgRU9TIGFkZGRyZXNzIGNvbnN0cmFpbnRzLFxuICAgKiBhbmQgaXMgbm90IGFjdHVhbGx5IGNoZWNrZWQgZm9yIGF2YWlsYWJpbGl0eSBvbiB0aGUgRU9TIGJsb2NrY2hhaW4uXG4gICAqXG4gICAqIEN1cnJlbnQgRU9TIGFkZHJlc3MgY29uc3RyYWludHMgYXJlOlxuICAgKiAqIEFkZHJlc3MgbXVzdCBiZSBleGFjdGx5IDEyIGNoYXJhY3RlcnNcbiAgICogKiBBZGRyZXNzIG11c3Qgb25seSBjb250YWluIGxvd2VyY2FzZSBsZXR0ZXJzIGFuZCBudW1iZXJzIDEtNVxuICAgKiBAcmV0dXJucyBhIHZhbGlkbHkgZm9ybWF0dGVkIEVPUyBhZGRyZXNzLCB3aGljaCBtYXkgb3IgbWF5IG5vdCBhY3R1YWxseSBiZSBhdmFpbGFibGUgb24gY2hhaW4uXG4gICAqL1xuICBnZW5lcmF0ZVJhbmRvbUFkZHJlc3MocGFyYW1zOiBSZWNvcmQ8c3RyaW5nLCBuZXZlcj4pOiBzdHJpbmcge1xuICAgIGNvbnN0IGFkZHJlc3M6IHN0cmluZ1tdID0gW107XG4gICAgd2hpbGUgKGFkZHJlc3MubGVuZ3RoIDwgMTIpIHtcbiAgICAgIGNvbnN0IGNoYXIgPSBfLnNhbXBsZShFb3MuVkFMSURfQUREUkVTU19DSEFSUyk7XG4gICAgICBpZiAoIWNoYXIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdmYWlsZWQgdG8gc2FtcGxlIHZhbGlkIEVPUyBhZGRyZXNzIGNoYXJhY3RlcnMnKTtcbiAgICAgIH1cbiAgICAgIGFkZHJlc3MucHVzaChjaGFyKTtcbiAgICB9XG4gICAgcmV0dXJuIGFkZHJlc3Muam9pbignJyk7XG4gIH1cbn1cbiJdfQ==
|