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