@bitgo-beta/abstract-cosmos 0.0.0-semantic-release-managed
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +5 -0
- package/.mocharc.yml +8 -0
- package/CHANGELOG.md +1056 -0
- package/LICENSE +191 -0
- package/README.md +1 -0
- package/dist/resources/MsgCompiled.d.ts +1212 -0
- package/dist/resources/MsgCompiled.js +2761 -0
- package/dist/src/cosmosCoin.d.ts +196 -0
- package/dist/src/cosmosCoin.d.ts.map +1 -0
- package/dist/src/cosmosCoin.js +718 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +21 -0
- package/dist/src/lib/ContractCallBuilder.d.ts +13 -0
- package/dist/src/lib/ContractCallBuilder.d.ts.map +1 -0
- package/dist/src/lib/ContractCallBuilder.js +61 -0
- package/dist/src/lib/StakingActivateBuilder.d.ts +13 -0
- package/dist/src/lib/StakingActivateBuilder.d.ts.map +1 -0
- package/dist/src/lib/StakingActivateBuilder.js +61 -0
- package/dist/src/lib/StakingDeactivateBuilder.d.ts +13 -0
- package/dist/src/lib/StakingDeactivateBuilder.d.ts.map +1 -0
- package/dist/src/lib/StakingDeactivateBuilder.js +61 -0
- package/dist/src/lib/StakingRedelegateBuilder.d.ts +13 -0
- package/dist/src/lib/StakingRedelegateBuilder.d.ts.map +1 -0
- package/dist/src/lib/StakingRedelegateBuilder.js +61 -0
- package/dist/src/lib/StakingWithdrawRewardsBuilder.d.ts +13 -0
- package/dist/src/lib/StakingWithdrawRewardsBuilder.d.ts.map +1 -0
- package/dist/src/lib/StakingWithdrawRewardsBuilder.js +61 -0
- package/dist/src/lib/constants.d.ts +11 -0
- package/dist/src/lib/constants.d.ts.map +1 -0
- package/dist/src/lib/constants.js +14 -0
- package/dist/src/lib/iface.d.ts +109 -0
- package/dist/src/lib/iface.d.ts.map +1 -0
- package/dist/src/lib/iface.js +20 -0
- package/dist/src/lib/index.d.ts +14 -0
- package/dist/src/lib/index.d.ts.map +1 -0
- package/dist/src/lib/index.js +63 -0
- package/dist/src/lib/keyPair.d.ts +18 -0
- package/dist/src/lib/keyPair.d.ts.map +1 -0
- package/dist/src/lib/keyPair.js +51 -0
- package/dist/src/lib/transaction.d.ts +64 -0
- package/dist/src/lib/transaction.d.ts.map +1 -0
- package/dist/src/lib/transaction.js +333 -0
- package/dist/src/lib/transactionBuilder.d.ts +86 -0
- package/dist/src/lib/transactionBuilder.d.ts.map +1 -0
- package/dist/src/lib/transactionBuilder.js +181 -0
- package/dist/src/lib/transferBuilder.d.ts +13 -0
- package/dist/src/lib/transferBuilder.d.ts.map +1 -0
- package/dist/src/lib/transferBuilder.js +61 -0
- package/dist/src/lib/utils.d.ts +351 -0
- package/dist/src/lib/utils.d.ts.map +1 -0
- package/dist/src/lib/utils.js +856 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +60 -0
- package/resources/MsgCompiled.d.ts +1212 -0
- package/resources/MsgCompiled.js +2761 -0
|
@@ -0,0 +1,718 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.CosmosCoin = void 0;
|
|
40
|
+
const sdk_core_1 = require("@bitgo-beta/sdk-core");
|
|
41
|
+
const secp256k1_1 = require("@bitgo-beta/secp256k1");
|
|
42
|
+
const bignumber_js_1 = require("bignumber.js");
|
|
43
|
+
const buffer_1 = require("buffer");
|
|
44
|
+
const crypto_1 = require("crypto");
|
|
45
|
+
const _ = __importStar(require("lodash"));
|
|
46
|
+
const querystring = __importStar(require("querystring"));
|
|
47
|
+
const request = __importStar(require("superagent"));
|
|
48
|
+
const url = __importStar(require("url"));
|
|
49
|
+
const constants_1 = require("./lib/constants");
|
|
50
|
+
const utils_1 = __importDefault(require("./lib/utils"));
|
|
51
|
+
const sdk_lib_mpc_1 = require("@bitgo-beta/sdk-lib-mpc");
|
|
52
|
+
class CosmosCoin extends sdk_core_1.BaseCoin {
|
|
53
|
+
constructor(bitgo, staticsCoin) {
|
|
54
|
+
super(bitgo);
|
|
55
|
+
if (!staticsCoin) {
|
|
56
|
+
throw new Error('missing required constructor parameter staticsCoin');
|
|
57
|
+
}
|
|
58
|
+
this._staticsCoin = staticsCoin;
|
|
59
|
+
}
|
|
60
|
+
static createInstance(bitgo, staticsCoin) {
|
|
61
|
+
return new CosmosCoin(bitgo, staticsCoin);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Creates an instance of TransactionBuilderFactory for the coin specific sdk
|
|
65
|
+
*/
|
|
66
|
+
getBuilder() {
|
|
67
|
+
throw new Error('Method not implemented.');
|
|
68
|
+
}
|
|
69
|
+
/** @inheritDoc **/
|
|
70
|
+
getBaseFactor() {
|
|
71
|
+
throw new Error('Method not implemented');
|
|
72
|
+
}
|
|
73
|
+
/** @inheritDoc **/
|
|
74
|
+
getChain() {
|
|
75
|
+
return this._staticsCoin.name;
|
|
76
|
+
}
|
|
77
|
+
/** @inheritDoc **/
|
|
78
|
+
getFamily() {
|
|
79
|
+
return this._staticsCoin.family;
|
|
80
|
+
}
|
|
81
|
+
/** @inheritDoc **/
|
|
82
|
+
getFullName() {
|
|
83
|
+
return this._staticsCoin.fullName;
|
|
84
|
+
}
|
|
85
|
+
/** @inheritDoc */
|
|
86
|
+
supportsTss() {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
/** inherited doc */
|
|
90
|
+
getDefaultMultisigType() {
|
|
91
|
+
return sdk_core_1.multisigTypes.tss;
|
|
92
|
+
}
|
|
93
|
+
/** @inheritDoc **/
|
|
94
|
+
getMPCAlgorithm() {
|
|
95
|
+
return 'ecdsa';
|
|
96
|
+
}
|
|
97
|
+
/** @inheritDoc **/
|
|
98
|
+
isValidPub(pub) {
|
|
99
|
+
return utils_1.default.isValidPublicKey(pub);
|
|
100
|
+
}
|
|
101
|
+
/** @inheritDoc **/
|
|
102
|
+
isValidPrv(prv) {
|
|
103
|
+
return utils_1.default.isValidPrivateKey(prv);
|
|
104
|
+
}
|
|
105
|
+
isValidAddress(address) {
|
|
106
|
+
throw new Error('Method not implemented.');
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Builds a funds recovery transaction without BitGo
|
|
110
|
+
* @param {RecoveryOptions} params parameters needed to construct and
|
|
111
|
+
* (maybe) sign the transaction
|
|
112
|
+
*
|
|
113
|
+
* @returns {CosmosLikeCoinRecoveryOutput} the serialized transaction hex string and index
|
|
114
|
+
* of the address being swept
|
|
115
|
+
*/
|
|
116
|
+
async recover(params) {
|
|
117
|
+
const isUnsignedSweep = this.isUnsignedSweep(params);
|
|
118
|
+
this.validateRecoveryParams(params, isUnsignedSweep);
|
|
119
|
+
const { senderAddress, publicKey, keyShares } = await this.getSenderDetails(params, isUnsignedSweep);
|
|
120
|
+
const [chainId, accountDetails, balances] = await Promise.all([
|
|
121
|
+
this.getChainId(),
|
|
122
|
+
this.getAccountDetails(senderAddress),
|
|
123
|
+
this.getAccountBalance(senderAddress),
|
|
124
|
+
]);
|
|
125
|
+
const { actualBalance, remainingBalances } = this.processBalances(balances);
|
|
126
|
+
const messages = this.buildTransactionMessages(senderAddress, params.recoveryDestination, actualBalance, remainingBalances);
|
|
127
|
+
return this.buildAndSignTransaction({
|
|
128
|
+
messages,
|
|
129
|
+
chainId,
|
|
130
|
+
accountDetails,
|
|
131
|
+
publicKey: publicKey || '',
|
|
132
|
+
isUnsignedSweep,
|
|
133
|
+
keyShares,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Validates the recovery parameters
|
|
138
|
+
*/
|
|
139
|
+
validateRecoveryParams(params, isUnsignedSweep) {
|
|
140
|
+
if (!params.recoveryDestination || !this.isValidAddress(params.recoveryDestination)) {
|
|
141
|
+
throw new Error('invalid recoveryDestination');
|
|
142
|
+
}
|
|
143
|
+
if (!isUnsignedSweep) {
|
|
144
|
+
if (!params.userKey)
|
|
145
|
+
throw new Error('missing userKey');
|
|
146
|
+
if (!params.backupKey)
|
|
147
|
+
throw new Error('missing backupKey');
|
|
148
|
+
if (!params.walletPassphrase)
|
|
149
|
+
throw new Error('missing wallet passphrase');
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Checks if this is an unsigned sweep operation
|
|
154
|
+
*/
|
|
155
|
+
isUnsignedSweep(params) {
|
|
156
|
+
return !params.userKey && !params.backupKey && !params.walletPassphrase;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Gets sender details including address, public key and key shares
|
|
160
|
+
*/
|
|
161
|
+
async getSenderDetails(params, isUnsignedSweep) {
|
|
162
|
+
const MPC = new sdk_core_1.Ecdsa();
|
|
163
|
+
if (isUnsignedSweep) {
|
|
164
|
+
return {
|
|
165
|
+
senderAddress: params.rootAddress,
|
|
166
|
+
publicKey: MPC.deriveUnhardened(params.bitgoKey || '', constants_1.ROOT_PATH).slice(0, 66),
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
const keyShares = await this.getKeyShares(params);
|
|
170
|
+
const publicKey = MPC.deriveUnhardened(keyShares.commonKeyChain, constants_1.ROOT_PATH).slice(0, 66);
|
|
171
|
+
return {
|
|
172
|
+
senderAddress: this.getAddressFromPublicKey(publicKey),
|
|
173
|
+
publicKey,
|
|
174
|
+
keyShares,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Gets key shares from recovery parameters
|
|
179
|
+
*/
|
|
180
|
+
async getKeyShares(params) {
|
|
181
|
+
if (!params.userKey || !params.backupKey || !params.walletPassphrase) {
|
|
182
|
+
throw new Error('Missing required key parameters');
|
|
183
|
+
}
|
|
184
|
+
const userKey = params.userKey.replace(/\s/g, '');
|
|
185
|
+
const backupKey = params.backupKey.replace(/\s/g, '');
|
|
186
|
+
const walletPassphrase = params.walletPassphrase;
|
|
187
|
+
if (!userKey || !backupKey) {
|
|
188
|
+
throw new Error('Invalid key format');
|
|
189
|
+
}
|
|
190
|
+
return await sdk_core_1.ECDSAUtils.getMpcV2RecoveryKeyShares(userKey, backupKey, walletPassphrase);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Processes account balances and validates sufficient funds
|
|
194
|
+
*/
|
|
195
|
+
processBalances(balances) {
|
|
196
|
+
if (!balances?.length) {
|
|
197
|
+
throw new Error('No balance found on account');
|
|
198
|
+
}
|
|
199
|
+
const denomination = this.getDenomination();
|
|
200
|
+
if (!denomination) {
|
|
201
|
+
throw new Error('Invalid denomination');
|
|
202
|
+
}
|
|
203
|
+
let nativeBalance = new bignumber_js_1.BigNumber(0);
|
|
204
|
+
const remainingBalances = [];
|
|
205
|
+
const gasAmountDetails = this.getGasAmountDetails();
|
|
206
|
+
if (!gasAmountDetails?.gasAmount) {
|
|
207
|
+
throw new Error('Invalid gas amount');
|
|
208
|
+
}
|
|
209
|
+
const gasAmount = new bignumber_js_1.BigNumber(gasAmountDetails.gasAmount);
|
|
210
|
+
balances.forEach((balance) => {
|
|
211
|
+
if (!balance.amount) {
|
|
212
|
+
throw new Error('Invalid balance amount');
|
|
213
|
+
}
|
|
214
|
+
if (balance.denom === denomination) {
|
|
215
|
+
nativeBalance = new bignumber_js_1.BigNumber(balance.amount);
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
remainingBalances.push(balance);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
const actualBalance = nativeBalance.minus(gasAmount);
|
|
222
|
+
if (actualBalance.isLessThanOrEqualTo(0)) {
|
|
223
|
+
throw new Error('Did not have enough funds to recover');
|
|
224
|
+
}
|
|
225
|
+
return { nativeBalance, remainingBalances, actualBalance };
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Builds transaction messages for all balances
|
|
229
|
+
*/
|
|
230
|
+
buildTransactionMessages(senderAddress, recoveryDestination, actualBalance, remainingBalances) {
|
|
231
|
+
const nativeSendMessage = {
|
|
232
|
+
fromAddress: senderAddress,
|
|
233
|
+
toAddress: recoveryDestination,
|
|
234
|
+
amount: [
|
|
235
|
+
{
|
|
236
|
+
denom: this.getDenomination(),
|
|
237
|
+
amount: actualBalance.toFixed(),
|
|
238
|
+
},
|
|
239
|
+
],
|
|
240
|
+
};
|
|
241
|
+
const otherTokenMessages = remainingBalances.map((balance) => ({
|
|
242
|
+
fromAddress: senderAddress,
|
|
243
|
+
toAddress: recoveryDestination,
|
|
244
|
+
amount: [balance],
|
|
245
|
+
}));
|
|
246
|
+
return [...otherTokenMessages, nativeSendMessage];
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Builds and signs the transaction
|
|
250
|
+
*/
|
|
251
|
+
async buildAndSignTransaction(params) {
|
|
252
|
+
if (!params.chainId) {
|
|
253
|
+
throw new Error('Invalid chain ID');
|
|
254
|
+
}
|
|
255
|
+
const [accountNumber, sequenceNo] = params.accountDetails;
|
|
256
|
+
if (!accountNumber || !sequenceNo) {
|
|
257
|
+
throw new Error('Invalid account details');
|
|
258
|
+
}
|
|
259
|
+
const denomination = this.getDenomination();
|
|
260
|
+
const gasAmountDetails = this.getGasAmountDetails();
|
|
261
|
+
if (!denomination || !gasAmountDetails?.gasAmount || !gasAmountDetails?.gasLimit) {
|
|
262
|
+
throw new Error('Invalid gas configuration');
|
|
263
|
+
}
|
|
264
|
+
const gasBudget = {
|
|
265
|
+
amount: [
|
|
266
|
+
{
|
|
267
|
+
denom: denomination,
|
|
268
|
+
amount: gasAmountDetails.gasAmount,
|
|
269
|
+
},
|
|
270
|
+
],
|
|
271
|
+
gasLimit: gasAmountDetails.gasLimit,
|
|
272
|
+
};
|
|
273
|
+
const txnBuilder = this.getBuilder()
|
|
274
|
+
.getTransferBuilder()
|
|
275
|
+
.messages(params.messages)
|
|
276
|
+
.gasBudget(gasBudget)
|
|
277
|
+
.sequence(Number(sequenceNo))
|
|
278
|
+
.accountNumber(Number(accountNumber))
|
|
279
|
+
.chainId(params.chainId)
|
|
280
|
+
.publicKey(params.publicKey);
|
|
281
|
+
const unsignedTransaction = (await txnBuilder.build());
|
|
282
|
+
if (!unsignedTransaction) {
|
|
283
|
+
throw new Error('Failed to build unsigned transaction');
|
|
284
|
+
}
|
|
285
|
+
if (params.isUnsignedSweep) {
|
|
286
|
+
return {
|
|
287
|
+
signableHex: unsignedTransaction.signablePayload.toString('hex'),
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
return this.signTransactionWithMpc(unsignedTransaction, txnBuilder, params.keyShares, params.publicKey);
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Signs the transaction with MPC
|
|
294
|
+
*/
|
|
295
|
+
/**
|
|
296
|
+
* Signs the transaction using MPC (Multi-Party Computation)
|
|
297
|
+
* @param unsignedTransaction The unsigned transaction to sign
|
|
298
|
+
* @param txnBuilder The transaction builder instance
|
|
299
|
+
* @param keyShares The key shares for MPC signing
|
|
300
|
+
* @param publicKey The public key for verification
|
|
301
|
+
* @returns The signed transaction output
|
|
302
|
+
* @throws Error if validation fails or signing process encounters an error
|
|
303
|
+
*/
|
|
304
|
+
async signTransactionWithMpc(unsignedTransaction, txnBuilder, keyShares, publicKey) {
|
|
305
|
+
// Validate inputs
|
|
306
|
+
if (!unsignedTransaction?.signablePayload) {
|
|
307
|
+
throw new Error('Invalid unsigned transaction');
|
|
308
|
+
}
|
|
309
|
+
if (!keyShares?.userKeyShare || !keyShares?.backupKeyShare || !keyShares?.commonKeyChain) {
|
|
310
|
+
throw new Error('Invalid key shares');
|
|
311
|
+
}
|
|
312
|
+
if (!publicKey) {
|
|
313
|
+
throw new Error('Invalid public key');
|
|
314
|
+
}
|
|
315
|
+
try {
|
|
316
|
+
const MPC = new sdk_core_1.Ecdsa();
|
|
317
|
+
const message = unsignedTransaction.signablePayload;
|
|
318
|
+
// Get hash function and compute message hash
|
|
319
|
+
const hashFunction = utils_1.default.getHashFunction() || (0, crypto_1.createHash)('sha256');
|
|
320
|
+
if (!hashFunction) {
|
|
321
|
+
throw new Error('Failed to get hash function');
|
|
322
|
+
}
|
|
323
|
+
const messageHash = hashFunction.update(message).digest();
|
|
324
|
+
// Sign the transaction
|
|
325
|
+
const signature = await sdk_core_1.ECDSAUtils.signRecoveryMpcV2(messageHash, keyShares.userKeyShare, keyShares.backupKeyShare, keyShares.commonKeyChain);
|
|
326
|
+
// Verify the signature
|
|
327
|
+
const signableHex = unsignedTransaction.signablePayload.toString('hex');
|
|
328
|
+
const signableBuffer = buffer_1.Buffer.from(signableHex, 'hex');
|
|
329
|
+
MPC.verify(signableBuffer, signature, this.getHashFunction());
|
|
330
|
+
// Get cosmos key pair and validate
|
|
331
|
+
const cosmosKeyPair = this.getKeyPair(publicKey);
|
|
332
|
+
if (!cosmosKeyPair) {
|
|
333
|
+
throw new Error('Invalid cosmos key pair');
|
|
334
|
+
}
|
|
335
|
+
// Add signature to transaction
|
|
336
|
+
txnBuilder.addSignature({ pub: cosmosKeyPair.getKeys().pub }, buffer_1.Buffer.from(signature.r + signature.s, 'hex'));
|
|
337
|
+
// Build final transaction
|
|
338
|
+
const signedTransaction = await txnBuilder.build();
|
|
339
|
+
if (!signedTransaction) {
|
|
340
|
+
throw new Error('Failed to build signed transaction');
|
|
341
|
+
}
|
|
342
|
+
return {
|
|
343
|
+
serializedTx: signedTransaction.toBroadcastFormat(),
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
catch (error) {
|
|
347
|
+
throw new Error(`Failed to sign transaction: ${error.message}`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Builds a redelegate transaction
|
|
352
|
+
* @param {RecoveryOptions} params parameters needed to construct and
|
|
353
|
+
* (maybe) sign the transaction
|
|
354
|
+
*
|
|
355
|
+
* @returns {CosmosLikeCoinRecoveryOutput} the serialized transaction hex string
|
|
356
|
+
*/
|
|
357
|
+
async redelegate(params) {
|
|
358
|
+
if (!params.validatorSrcAddress || !this.isValidAddress(params.validatorSrcAddress)) {
|
|
359
|
+
throw new Error('invalid validatorSrcAddress');
|
|
360
|
+
}
|
|
361
|
+
if (!params.validatorDstAddress || !this.isValidAddress(params.validatorDstAddress)) {
|
|
362
|
+
throw new Error('invalid validatorDstAddress');
|
|
363
|
+
}
|
|
364
|
+
if (!params.userKey) {
|
|
365
|
+
throw new Error('missing userKey');
|
|
366
|
+
}
|
|
367
|
+
if (!params.backupKey) {
|
|
368
|
+
throw new Error('missing backupKey');
|
|
369
|
+
}
|
|
370
|
+
if (!params.walletPassphrase) {
|
|
371
|
+
throw new Error('missing wallet passphrase');
|
|
372
|
+
}
|
|
373
|
+
if (!params.amountToRedelegate) {
|
|
374
|
+
throw new Error('missing amountToRedelegate');
|
|
375
|
+
}
|
|
376
|
+
const userKey = params.userKey.replace(/\s/g, '');
|
|
377
|
+
const backupKey = params.backupKey.replace(/\s/g, '');
|
|
378
|
+
const { userKeyShare, backupKeyShare, commonKeyChain } = await sdk_core_1.ECDSAUtils.getMpcV2RecoveryKeyShares(userKey, backupKey, params.walletPassphrase); // baseAddress is not extracted
|
|
379
|
+
const MPC = new sdk_core_1.Ecdsa();
|
|
380
|
+
const chainId = await this.getChainId();
|
|
381
|
+
const publicKey = MPC.deriveUnhardened(commonKeyChain, constants_1.ROOT_PATH).slice(0, 66);
|
|
382
|
+
const senderAddress = this.getAddressFromPublicKey(publicKey);
|
|
383
|
+
const [accountNumber, sequenceNo] = await this.getAccountDetails(senderAddress);
|
|
384
|
+
const gasBudget = {
|
|
385
|
+
amount: [{ denom: this.getDenomination(), amount: this.getGasAmountDetails().gasAmount }],
|
|
386
|
+
gasLimit: this.getGasAmountDetails().gasLimit,
|
|
387
|
+
};
|
|
388
|
+
const amount = {
|
|
389
|
+
denom: this.getDenomination(),
|
|
390
|
+
amount: new bignumber_js_1.BigNumber(params.amountToRedelegate).toFixed(),
|
|
391
|
+
};
|
|
392
|
+
const sendMessage = [
|
|
393
|
+
{
|
|
394
|
+
delegatorAddress: senderAddress,
|
|
395
|
+
validatorSrcAddress: params.validatorSrcAddress,
|
|
396
|
+
validatorDstAddress: params.validatorDstAddress,
|
|
397
|
+
amount: amount,
|
|
398
|
+
},
|
|
399
|
+
];
|
|
400
|
+
const txnBuilder = this.getBuilder().getStakingRedelegateBuilder();
|
|
401
|
+
txnBuilder
|
|
402
|
+
.messages(sendMessage)
|
|
403
|
+
.gasBudget(gasBudget)
|
|
404
|
+
.publicKey(publicKey)
|
|
405
|
+
.sequence(Number(sequenceNo))
|
|
406
|
+
.accountNumber(Number(accountNumber))
|
|
407
|
+
.chainId(chainId);
|
|
408
|
+
const unsignedTransaction = (await txnBuilder.build());
|
|
409
|
+
let serializedTx = unsignedTransaction.toBroadcastFormat();
|
|
410
|
+
const signableHex = unsignedTransaction.signablePayload.toString('hex');
|
|
411
|
+
const message = unsignedTransaction.signablePayload;
|
|
412
|
+
const messageHash = (utils_1.default.getHashFunction() || (0, crypto_1.createHash)('sha256')).update(message).digest();
|
|
413
|
+
const signature = await sdk_core_1.ECDSAUtils.signRecoveryMpcV2(messageHash, userKeyShare, backupKeyShare, commonKeyChain);
|
|
414
|
+
const signableBuffer = buffer_1.Buffer.from(signableHex, 'hex');
|
|
415
|
+
MPC.verify(signableBuffer, signature, this.getHashFunction());
|
|
416
|
+
const cosmosKeyPair = this.getKeyPair(publicKey);
|
|
417
|
+
txnBuilder.addSignature({ pub: cosmosKeyPair.getKeys().pub }, buffer_1.Buffer.from(signature.r + signature.s, 'hex'));
|
|
418
|
+
const signedTransaction = await txnBuilder.build();
|
|
419
|
+
serializedTx = signedTransaction.toBroadcastFormat();
|
|
420
|
+
return { serializedTx: serializedTx };
|
|
421
|
+
}
|
|
422
|
+
/** @inheritDoc **/
|
|
423
|
+
async verifyTransaction(params) {
|
|
424
|
+
let totalAmount = new bignumber_js_1.BigNumber(0);
|
|
425
|
+
const { txPrebuild, txParams } = params;
|
|
426
|
+
const rawTx = txPrebuild.txHex;
|
|
427
|
+
if (!rawTx) {
|
|
428
|
+
throw new Error('missing required tx prebuild property txHex');
|
|
429
|
+
}
|
|
430
|
+
const transaction = await this.getBuilder().from(rawTx).build();
|
|
431
|
+
const explainedTx = transaction.explainTransaction();
|
|
432
|
+
if (txParams.recipients && txParams.recipients.length > 0) {
|
|
433
|
+
const filteredRecipients = txParams.recipients?.map((recipient) => _.pick(recipient, ['address', 'amount']));
|
|
434
|
+
const filteredOutputs = explainedTx.outputs.map((output) => _.pick(output, ['address', 'amount']));
|
|
435
|
+
if (!_.isEqual(filteredOutputs, filteredRecipients)) {
|
|
436
|
+
throw new Error('Tx outputs does not match with expected txParams recipients');
|
|
437
|
+
}
|
|
438
|
+
// WithdrawDelegatorRewards and ContractCall transaction don't have amount
|
|
439
|
+
if (transaction.type !== sdk_core_1.TransactionType.StakingWithdraw && transaction.type !== sdk_core_1.TransactionType.ContractCall) {
|
|
440
|
+
for (const recipients of txParams.recipients) {
|
|
441
|
+
totalAmount = totalAmount.plus(recipients.amount);
|
|
442
|
+
}
|
|
443
|
+
if (!totalAmount.isEqualTo(explainedTx.outputAmount)) {
|
|
444
|
+
throw new Error('Tx total amount does not match with expected total amount field');
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return true;
|
|
449
|
+
}
|
|
450
|
+
/** @inheritDoc **/
|
|
451
|
+
async explainTransaction(options) {
|
|
452
|
+
if (!options.txHex) {
|
|
453
|
+
throw new Error('missing required txHex parameter');
|
|
454
|
+
}
|
|
455
|
+
try {
|
|
456
|
+
const transactionBuilder = this.getBuilder().from(options.txHex);
|
|
457
|
+
const transaction = await transactionBuilder.build();
|
|
458
|
+
return transaction.explainTransaction();
|
|
459
|
+
}
|
|
460
|
+
catch (e) {
|
|
461
|
+
throw new Error('Invalid transaction: ' + e.message);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Sign a transaction with a single private key
|
|
466
|
+
* @param params parameters in the form of { txPrebuild: {txHex}, prv }
|
|
467
|
+
* @returns signed transaction in the form of { txHex }
|
|
468
|
+
*/
|
|
469
|
+
async signTransaction(params) {
|
|
470
|
+
const txHex = params?.txPrebuild?.txHex;
|
|
471
|
+
const privateKey = params?.prv;
|
|
472
|
+
if (!txHex) {
|
|
473
|
+
throw new sdk_core_1.SigningError('missing required txPrebuild parameter: params.txPrebuild.txHex');
|
|
474
|
+
}
|
|
475
|
+
if (!privateKey) {
|
|
476
|
+
throw new sdk_core_1.SigningError('missing required prv parameter: params.prv');
|
|
477
|
+
}
|
|
478
|
+
const txBuilder = this.getBuilder().from(params.txPrebuild.txHex);
|
|
479
|
+
txBuilder.sign({ key: params.prv });
|
|
480
|
+
const transaction = await txBuilder.build();
|
|
481
|
+
if (!transaction) {
|
|
482
|
+
throw new sdk_core_1.SigningError('Failed to build signed transaction');
|
|
483
|
+
}
|
|
484
|
+
const serializedTx = transaction.toBroadcastFormat();
|
|
485
|
+
return {
|
|
486
|
+
txHex: serializedTx,
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
/** @inheritDoc **/
|
|
490
|
+
async parseTransaction(params) {
|
|
491
|
+
const transactionExplanation = await this.explainTransaction({ txHex: params.txHex });
|
|
492
|
+
if (!transactionExplanation) {
|
|
493
|
+
throw new Error('Invalid transaction');
|
|
494
|
+
}
|
|
495
|
+
if (transactionExplanation.outputs.length <= 0) {
|
|
496
|
+
return {
|
|
497
|
+
inputs: [],
|
|
498
|
+
outputs: [],
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
const senderAddress = transactionExplanation.outputs[0].address;
|
|
502
|
+
const feeAmount = new bignumber_js_1.BigNumber(transactionExplanation.fee.fee === '' ? '0' : transactionExplanation.fee.fee);
|
|
503
|
+
const inputs = [
|
|
504
|
+
{
|
|
505
|
+
address: senderAddress,
|
|
506
|
+
amount: new bignumber_js_1.BigNumber(transactionExplanation.outputAmount).plus(feeAmount).toFixed(),
|
|
507
|
+
},
|
|
508
|
+
];
|
|
509
|
+
const outputs = transactionExplanation.outputs.map((output) => {
|
|
510
|
+
return {
|
|
511
|
+
address: output.address,
|
|
512
|
+
amount: new bignumber_js_1.BigNumber(output.amount).toFixed(),
|
|
513
|
+
};
|
|
514
|
+
});
|
|
515
|
+
return {
|
|
516
|
+
inputs,
|
|
517
|
+
outputs,
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Get the public node url from the Environments constant we have defined
|
|
522
|
+
*/
|
|
523
|
+
getPublicNodeUrl() {
|
|
524
|
+
throw new Error('Method not implemented.');
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Get account number from public node
|
|
528
|
+
*/
|
|
529
|
+
async getAccountFromNode(senderAddress) {
|
|
530
|
+
const nodeUrl = this.getPublicNodeUrl();
|
|
531
|
+
const getAccountPath = '/cosmos/auth/v1beta1/accounts/';
|
|
532
|
+
const fullEndpoint = nodeUrl + getAccountPath + senderAddress;
|
|
533
|
+
try {
|
|
534
|
+
return await request.get(fullEndpoint).send();
|
|
535
|
+
}
|
|
536
|
+
catch (e) {
|
|
537
|
+
console.debug(e);
|
|
538
|
+
}
|
|
539
|
+
throw new Error(`Unable to call endpoint ${getAccountPath + senderAddress} from node: ${nodeUrl}`);
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Get balance from public node
|
|
543
|
+
*/
|
|
544
|
+
async getBalanceFromNode(senderAddress) {
|
|
545
|
+
const nodeUrl = this.getPublicNodeUrl();
|
|
546
|
+
const getBalancePath = '/cosmos/bank/v1beta1/balances/';
|
|
547
|
+
const fullEndpoint = nodeUrl + getBalancePath + senderAddress;
|
|
548
|
+
try {
|
|
549
|
+
return await request.get(fullEndpoint).send();
|
|
550
|
+
}
|
|
551
|
+
catch (e) {
|
|
552
|
+
console.debug(e);
|
|
553
|
+
}
|
|
554
|
+
throw new Error(`Unable to call endpoint ${getBalancePath + senderAddress} from node: ${nodeUrl}`);
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Get chain id from public node
|
|
558
|
+
*/
|
|
559
|
+
async getChainIdFromNode() {
|
|
560
|
+
const nodeUrl = this.getPublicNodeUrl();
|
|
561
|
+
const getLatestBlockPath = '/cosmos/base/tendermint/v1beta1/blocks/latest';
|
|
562
|
+
const fullEndpoint = nodeUrl + getLatestBlockPath;
|
|
563
|
+
try {
|
|
564
|
+
return await request.get(fullEndpoint).send();
|
|
565
|
+
}
|
|
566
|
+
catch (e) {
|
|
567
|
+
console.debug(e);
|
|
568
|
+
}
|
|
569
|
+
throw new Error(`Unable to call endpoint ${getLatestBlockPath} from node: ${nodeUrl}`);
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Helper to fetch account balance
|
|
573
|
+
*/
|
|
574
|
+
async getAccountBalance(senderAddress) {
|
|
575
|
+
const response = await this.getBalanceFromNode(senderAddress);
|
|
576
|
+
if (response.status !== 200) {
|
|
577
|
+
throw new Error('Account not found');
|
|
578
|
+
}
|
|
579
|
+
return response.body.balances;
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Helper to fetch chainId
|
|
583
|
+
*/
|
|
584
|
+
async getChainId() {
|
|
585
|
+
const response = await this.getChainIdFromNode();
|
|
586
|
+
if (response.status !== 200) {
|
|
587
|
+
throw new Error('Account not found');
|
|
588
|
+
}
|
|
589
|
+
return response.body.block.header.chain_id;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Helper to fetch account number
|
|
593
|
+
*/
|
|
594
|
+
async getAccountDetails(senderAddress) {
|
|
595
|
+
const response = await this.getAccountFromNode(senderAddress);
|
|
596
|
+
if (response.status !== 200) {
|
|
597
|
+
throw new Error('Account not found');
|
|
598
|
+
}
|
|
599
|
+
return [response.body.account.account_number, response.body.account.sequence];
|
|
600
|
+
}
|
|
601
|
+
/** @inheritDoc **/
|
|
602
|
+
generateKeyPair(seed) {
|
|
603
|
+
if (!seed) {
|
|
604
|
+
// An extended private key has both a normal 256 bit private key and a 256
|
|
605
|
+
// bit chain code, both of which must be random. 512 bits is therefore the
|
|
606
|
+
// maximum entropy and gives us maximum security against cracking.
|
|
607
|
+
seed = (0, crypto_1.randomBytes)(512 / 8);
|
|
608
|
+
}
|
|
609
|
+
const extendedKey = secp256k1_1.bip32.fromSeed(seed);
|
|
610
|
+
return {
|
|
611
|
+
pub: extendedKey.neutered().toBase58(),
|
|
612
|
+
prv: extendedKey.toBase58(),
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Retrieves the address from a public key.
|
|
617
|
+
* @param {string} pubKey - The public key.
|
|
618
|
+
* @returns {string} The corresponding address.
|
|
619
|
+
*/
|
|
620
|
+
getAddressFromPublicKey(pubKey) {
|
|
621
|
+
throw new Error('Method not implemented');
|
|
622
|
+
}
|
|
623
|
+
/** @inheritDoc **/
|
|
624
|
+
async isWalletAddress(params) {
|
|
625
|
+
const addressDetails = this.getAddressDetails(params.address);
|
|
626
|
+
if (!this.isValidAddress(addressDetails.address)) {
|
|
627
|
+
throw new sdk_core_1.InvalidAddressError(`invalid address: ${addressDetails.address}`);
|
|
628
|
+
}
|
|
629
|
+
const rootAddress = params.coinSpecific.rootAddress;
|
|
630
|
+
if (addressDetails.address !== rootAddress) {
|
|
631
|
+
throw new sdk_core_1.UnexpectedAddressError(`address validation failure: ${addressDetails.address} vs ${rootAddress}`);
|
|
632
|
+
}
|
|
633
|
+
return true;
|
|
634
|
+
}
|
|
635
|
+
/** @inheritDoc **/
|
|
636
|
+
getHashFunction() {
|
|
637
|
+
return utils_1.default.getHashFunction();
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Process address into address and memo id
|
|
641
|
+
*
|
|
642
|
+
* @param address the address
|
|
643
|
+
* @returns object containing address and memo id
|
|
644
|
+
*/
|
|
645
|
+
getAddressDetails(address) {
|
|
646
|
+
const destinationDetails = url.parse(address);
|
|
647
|
+
const destinationAddress = destinationDetails.pathname || '';
|
|
648
|
+
// address doesn't have a memo id
|
|
649
|
+
if (destinationDetails.pathname === address) {
|
|
650
|
+
return {
|
|
651
|
+
address: address,
|
|
652
|
+
memoId: undefined,
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
if (!destinationDetails.query) {
|
|
656
|
+
throw new sdk_core_1.InvalidAddressError(`invalid address: ${address}`);
|
|
657
|
+
}
|
|
658
|
+
const queryDetails = querystring.parse(destinationDetails.query);
|
|
659
|
+
if (!queryDetails.memoId) {
|
|
660
|
+
// if there are more properties, the query details need to contain the memo id property
|
|
661
|
+
throw new sdk_core_1.InvalidAddressError(`invalid address: ${address}`);
|
|
662
|
+
}
|
|
663
|
+
if (Array.isArray(queryDetails.memoId)) {
|
|
664
|
+
throw new sdk_core_1.InvalidAddressError(`memoId may only be given at most once, but found ${queryDetails.memoId.length} instances in address ${address}`);
|
|
665
|
+
}
|
|
666
|
+
if (Array.isArray(queryDetails.memoId) && queryDetails.memoId.length !== 1) {
|
|
667
|
+
// valid addresses can only contain one memo id
|
|
668
|
+
throw new sdk_core_1.InvalidAddressError(`invalid address '${address}', must contain exactly one memoId`);
|
|
669
|
+
}
|
|
670
|
+
const [memoId] = _.castArray(queryDetails.memoId) || undefined;
|
|
671
|
+
if (!this.isValidMemoId(memoId)) {
|
|
672
|
+
throw new sdk_core_1.InvalidMemoIdError(`invalid address: '${address}', memoId is not valid`);
|
|
673
|
+
}
|
|
674
|
+
return {
|
|
675
|
+
address: destinationAddress,
|
|
676
|
+
memoId,
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Return boolean indicating whether a memo id is valid
|
|
681
|
+
*
|
|
682
|
+
* @param memoId memo id
|
|
683
|
+
* @returns true if memo id is valid
|
|
684
|
+
*/
|
|
685
|
+
isValidMemoId(memoId) {
|
|
686
|
+
return utils_1.default.isValidMemoId(memoId);
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* Helper method to return the respective coin's base unit
|
|
690
|
+
*/
|
|
691
|
+
getDenomination() {
|
|
692
|
+
throw new Error('Method not implemented');
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Helper method to fetch gas amount details for respective coin
|
|
696
|
+
*/
|
|
697
|
+
getGasAmountDetails() {
|
|
698
|
+
throw new Error('Method not implemented');
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* Helper method to get key pair for individual coin
|
|
702
|
+
* @param publicKey
|
|
703
|
+
*/
|
|
704
|
+
getKeyPair(publicKey) {
|
|
705
|
+
throw new Error('Method not implemented');
|
|
706
|
+
}
|
|
707
|
+
/** @inheritDoc **/
|
|
708
|
+
auditDecryptedKey({ multiSigType, publicKey, prv }) {
|
|
709
|
+
if (multiSigType !== 'tss') {
|
|
710
|
+
throw new Error('Unsupported multiSigType');
|
|
711
|
+
}
|
|
712
|
+
else {
|
|
713
|
+
(0, sdk_lib_mpc_1.auditEcdsaPrivateKey)(prv, publicKey);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
exports.CosmosCoin = CosmosCoin;
|
|
718
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29zbW9zQ29pbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb3Ntb3NDb2luLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLG1EQXVCOEI7QUFFOUIscURBQThDO0FBRTlDLCtDQUF5QztBQUN6QyxtQ0FBZ0M7QUFDaEMsbUNBQXVEO0FBQ3ZELDBDQUE0QjtBQUM1Qix5REFBMkM7QUFDM0Msb0RBQXNDO0FBQ3RDLHlDQUEyQjtBQWUzQiwrQ0FBNEM7QUFDNUMsd0RBQWdDO0FBQ2hDLHlEQUErRDtBQWlCL0QsTUFBYSxVQUFrQyxTQUFRLG1CQUFRO0lBRTdELFlBQXNCLEtBQWdCLEVBQUUsV0FBdUM7UUFDN0UsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRWIsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ2pCLE1BQU0sSUFBSSxLQUFLLENBQUMsb0RBQW9ELENBQUMsQ0FBQztRQUN4RSxDQUFDO1FBRUQsSUFBSSxDQUFDLFlBQVksR0FBRyxXQUFXLENBQUM7SUFDbEMsQ0FBQztJQUVELE1BQU0sQ0FBQyxjQUFjLENBQUMsS0FBZ0IsRUFBRSxXQUF1QztRQUM3RSxPQUFPLElBQUksVUFBVSxDQUFDLEtBQUssRUFBRSxXQUFXLENBQUMsQ0FBQztJQUM1QyxDQUFDO0lBRUQ7O09BRUc7SUFDSCxVQUFVO1FBQ1IsTUFBTSxJQUFJLEtBQUssQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO0lBQzdDLENBQUM7SUFFRCxtQkFBbUI7SUFDbkIsYUFBYTtRQUNYLE1BQU0sSUFBSSxLQUFLLENBQUMsd0JBQXdCLENBQUMsQ0FBQztJQUM1QyxDQUFDO0lBRUQsbUJBQW1CO0lBQ25CLFFBQVE7UUFDTixPQUFPLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDO0lBQ2hDLENBQUM7SUFFRCxtQkFBbUI7SUFDbkIsU0FBUztRQUNQLE9BQU8sSUFBSSxDQUFDLFlB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QUVEOzs7T0FHRztJQUNILFVBQVUsQ0FBQyxTQUFpQjtRQUMxQixNQUFNLElBQUksS0FBSyxDQUFDLHdCQUF3QixDQUFDLENBQUM7SUFDNUMsQ0FBQztJQUVELG1CQUFtQjtJQUNuQixpQkFBaUIsQ0FBQyxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUEyQjtRQUN6RSxJQUFJLFlBQVksS0FBSyxLQUFLLEVBQUUsQ0FBQztZQUMzQixNQUFNLElBQUksS0FBSyxDQUFDLDBCQUEwQixDQUFDLENBQUM7UUFDOUMsQ0FBQzthQUFNLENBQUM7WUFDTixJQUFBLGtDQUFvQixFQUFDLEdBQWEsRUFBRSxTQUFtQixDQUFDLENBQUM7UUFDM0QsQ0FBQztJQUNILENBQUM7Q0FDRjtBQWx5QkQsZ0NBa3lCQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEF1ZGl0RGVjcnlwdGVkS2V5UGFyYW1zLFxuICBCYXNlQ29pbixcbiAgQmFzZVRyYW5zYWN0aW9uLFxuICBCaXRHb0Jhc2UsXG4gIEVjZHNhLFxuICBFQ0RTQVV0aWxzLFxuICBFeHBsYW5hdGlvblJlc3VsdCxcbiAgSW52YWxpZEFkZHJlc3NFcnJvcixcbiAgSW52YWxpZE1lbW9JZEVycm9yLFxuICBLZXlQYWlyLFxuICBNUENBbGdvcml0aG0sXG4gIE11bHRpc2lnVHlwZSxcbiAgbXVsdGlzaWdUeXBlcyxcbiAgUGFyc2VkVHJhbnNhY3Rpb24sXG4gIFBhcnNlVHJhbnNhY3Rpb25PcHRpb25zLFxuICBTaWduZWRUcmFuc2FjdGlvbixcbiAgU2lnbmluZ0Vycm9yLFxuICBTaWduVHJhbnNhY3Rpb25PcHRpb25zLFxuICBUcmFuc2FjdGlvblR5cGUsXG4gIFVuZXhwZWN0ZWRBZGRyZXNzRXJyb3IsXG4gIFZlcmlmeUFkZHJlc3NPcHRpb25zLFxuICBWZXJpZnlUcmFuc2FjdGlvbk9wdGlvbnMsXG59IGZyb20gJ0BiaXRnby1iZXRhL3Nkay1jb3JlJztcbmltcG9ydCB7IEJhc2VDb2luIGFzIFN0YXRpY3NCYXNlQ29pbiwgQ29pbkZhbWlseSB9IGZyb20gJ0BiaXRnby1iZXRhL3N0YXRpY3MnO1xuaW1wb3J0IHsgYmlwMzIgfSBmcm9tICdAYml0Z28tYmV0YS9zZWNwMjU2azEnO1xuaW1wb3J0IHsgQ29pbiB9IGZyb20gJ0Bjb3NtanMvc3RhcmdhdGUnO1xuaW1wb3J0IHsgQmlnTnVtYmVyIH0gZnJvbSAnYmlnbnVtYmVyLmpzJztcbmltcG9ydCB7IEJ1ZmZlciB9IGZyb20gJ2J1ZmZlcic7XG5pbXBvcnQgeyBjcmVhdGVIYXNoLCBIYXNoLCByYW5kb21CeXRlcyB9IGZyb20gJ2NyeXB0byc7XG5pbXBvcnQgKiBhcyBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgKiBhcyBxdWVyeXN0cmluZyBmcm9tICdxdWVyeXN0cmluZyc7XG5pbXBvcnQgKiBhcyByZXF1ZXN0IGZyb20gJ3N1cGVyYWdlbnQnO1xuaW1wb3J0ICogYXMgdXJsIGZyb20gJ3VybCc7XG5pbXBvcnQge1xuICBDb3Ntb3NLZXlQYWlyLFxuICBDb3Ntb3NMaWtlQ29pblJlY292ZXJ5T3V0cHV0LFxuICBDb3Ntb3NUcmFuc2FjdGlvbixcbiAgRmVlRGF0YSxcbiAgR2FzQW1vdW50RGV0YWlscyxcbiAgUmVjb3ZlcnlPcHRpb25zLFxuICBSZWRlbGVnYXRlTWVzc2FnZSxcbiAgU2VuZE1lc3NhZ2UsXG4gIENvc21vc1RyYW5zYWN0aW9uQnVpbGRlcixcbiAgS2V5U2hhcmVzLFxuICBUcmFuc2FjdGlvbkJ1aWxkUGFyYW1zLFxuICBCYWxhbmNlUmVzdWx0LFxufSBmcm9tICcuL2xpYic7XG5pbXBvcnQgeyBST09UX1BBVEggfSBmcm9tICcuL2xpYi9jb25zdGFudHMnO1xuaW1wb3J0IHV0aWxzIGZyb20gJy4vbGliL3V0aWxzJztcbmltcG9ydCB7IGF1ZGl0RWNkc2FQcml2YXRlS2V5IH0gZnJvbSAnQGJpdGdvLWJldGEvc2RrLWxpYi1tcGMnO1xuXG4vKipcbiAqIENvc21vcyBhY2NvdW50cyBzdXBwb3J0IG1lbW8gSWQgYmFzZWQgYWRkcmVzc2VzXG4gKi9cbmludGVyZmFjZSBBZGRyZXNzRGV0YWlscyB7XG4gIGFkZHJlc3M6IHN0cmluZztcbiAgbWVtb0lkPzogc3RyaW5nIHwgdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIENvc21vcyBhY2NvdW50cyBzdXBwb3J0IG1lbW8gSWQgYmFzZWQgYWRkcmVzc2VzXG4gKi9cbmludGVyZmFjZSBDb3Ntb3NDb2luU3BlY2lmaWMge1xuICByb290QWRkcmVzczogc3RyaW5nO1xufVxuXG5leHBvcnQgY2xhc3MgQ29zbW9zQ29pbjxDdXN0b21NZXNzYWdlID0gbmV2ZXI+IGV4dGVuZHMgQmFzZUNvaW4ge1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgX3N0YXRpY3NDb2luOiBSZWFkb25seTxTdGF0aWNzQmFzZUNvaW4+O1xuICBwcm90ZWN0ZWQgY29uc3RydWN0b3IoYml0Z286IEJpdEdvQmFzZSwgc3RhdGljc0NvaW4/OiBSZWFkb25seTxTdGF0aWNzQmFzZUNvaW4+KSB7XG4gICAgc3VwZXIoYml0Z28pO1xuXG4gICAgaWYgKCFzdGF0aWNzQ29pbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHJlcXVpcmVkIGNvbnN0cnVjdG9yIHBhcmFtZXRlciBzdGF0aWNzQ29pbicpO1xuICAgIH1cblxuICAgIHRoaXMuX3N0YXRpY3NDb2luID0gc3RhdGljc0NvaW47XG4gIH1cblxuICBzdGF0aWMgY3JlYXRlSW5zdGFuY2UoYml0Z286IEJpdEdvQmFzZSwgc3RhdGljc0NvaW4/OiBSZWFkb25seTxTdGF0aWNzQmFzZUNvaW4+KTogQmFzZUNvaW4ge1xuICAgIHJldHVybiBuZXcgQ29zbW9zQ29pbihiaXRnbywgc3RhdGljc0NvaW4pO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgVHJhbnNhY3Rpb25CdWlsZGVyRmFjdG9yeSBmb3IgdGhlIGNvaW4gc3BlY2lmaWMgc2RrXG4gICAqL1xuICBnZXRCdWlsZGVyKCk6IGFueSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdNZXRob2Qgbm90IGltcGxlbWVudGVkLicpO1xuICB9XG5cbiAgLyoqIEBpbmhlcml0RG9jICoqL1xuICBnZXRCYXNlRmFjdG9yKCk6IHN0cmluZyB8IG51bWJlciB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdNZXRob2Qgbm90IGltcGxlbWVudGVkJyk7XG4gIH1cblxuICAvKiogQGluaGVyaXREb2MgKiovXG4gIGdldENoYWluKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuX3N0YXRpY3NDb2luLm5hbWU7XG4gIH1cblxuICAvKiogQGluaGVyaXREb2MgKiovXG4gIGdldEZhbWlseSgpOiBDb2luRmFtaWx5IHtcbiAgICByZXR1cm4gdGhpcy5fc3RhdGljc0NvaW4uZmFtaWx5O1xuICB9XG5cbiAgLyoqIEBpbmhlcml0RG9jICoqL1xuICBnZXRGdWxsTmFtZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLl9zdGF0aWNzQ29pbi5mdWxsTmFtZTtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdERvYyAqL1xuICBzdXBwb3J0c1RzcygpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKiBpbmhlcml0ZWQgZG9jICovXG4gIGdldERlZmF1bHRNdWx0aXNpZ1R5cGUoKTogTXVsdGlzaWdUeXBlIHtcbiAgICByZXR1cm4gbXVsdGlzaWdUeXBlcy50c3M7XG4gIH1cblxuICAvKiogQGluaGVyaXREb2MgKiovXG4gIGdldE1QQ0FsZ29yaXRobSgpOiBNUENBbGdvcml0aG0ge1xuICAgIHJldHVybiAnZWNkc2EnO1xuICB9XG5cbiAgLyoqIEBpbmhlcml0RG9jICoqL1xuICBpc1ZhbGlkUHViKHB1Yjogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHV0aWxzLmlzVmFsaWRQdWJsaWNLZXkocHViKTtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdERvYyAqKi9cbiAgaXNWYWxpZFBydihwcnY6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB1dGlscy5pc1ZhbGlkUHJpdmF0ZUtleShwcnYpO1xuICB9XG5cbiAgaXNWYWxpZEFkZHJlc3MoYWRkcmVzczogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdNZXRob2Qgbm90IGltcGxlbWVudGVkLicpO1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkcyBhIGZ1bmRzIHJlY292ZXJ5IHRyYW5zYWN0aW9uIHdpdGhvdXQgQml0R29cbiAgICogQHBhcmFtIHtSZWNvdmVyeU9wdGlvbnN9IHBhcmFtcyBwYXJhbWV0ZXJzIG5lZWRlZCB0byBjb25zdHJ1Y3QgYW5kXG4gICAqIChtYXliZSkgc2lnbiB0aGUgdHJhbnNhY3Rpb25cbiAgICpcbiAgICogQHJldHVybnMge0Nvc21vc0xpa2VDb2luUmVjb3ZlcnlPdXRwdXR9IHRoZSBzZXJpYWxpemVkIHRyYW5zYWN0aW9uIGhleCBzdHJpbmcgYW5kIGluZGV4XG4gICAqIG9mIHRoZSBhZGRyZXNzIGJlaW5nIHN3ZXB0XG4gICAqL1xuICBhc3luYyByZWNvdmVyKHBhcmFtczogUmVjb3ZlcnlPcHRpb25zKTogUHJvbWlzZTxDb3Ntb3NMaWtlQ29pblJlY292ZXJ5T3V0cHV0PiB7XG4gICAgY29uc3QgaXNVbnNpZ25lZFN3ZWVwID0gdGhpcy5pc1Vuc2lnbmVkU3dlZXAocGFyYW1zKTtcbiAgICB0aGlzLnZhbGlkYXRlUmVjb3ZlcnlQYXJhbXMocGFyYW1zLCBpc1Vuc2lnbmVkU3dlZXApO1xuXG4gICAgY29uc3QgeyBzZW5kZXJBZGRyZXNzLCBwdWJsaWNLZXksIGtleVNoYXJlcyB9ID0gYXdhaXQgdGhpcy5nZXRTZW5kZXJEZXRhaWxzKHBhcmFtcywgaXNVbnNpZ25lZFN3ZWVwKTtcblxuICAgIGNvbnN0IFtjaGFpbklkLCBhY2NvdW50RGV0YWlscywgYmFsYW5jZXNdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgdGhpcy5nZXRDaGFpbklkKCksXG4gICAgICB0aGlzLmdldEFjY291bnREZXRhaWxzKHNlbmRlckFkZHJlc3MpLFxuICAgICAgdGhpcy5nZXRBY2NvdW50QmFsYW5jZShzZW5kZXJBZGRyZXNzKSxcbiAgICBdKTtcblxuICAgIGNvbnN0IHsgYWN0dWFsQmFsYW5jZSwgcmVtYWluaW5nQmFsYW5jZXMgfSA9IHRoaXMucHJvY2Vzc0JhbGFuY2VzKGJhbGFuY2VzKTtcbiAgICBjb25zdCBtZXNzYWdlcyA9IHRoaXMuYnVpbGRUcmFuc2FjdGlvbk1lc3NhZ2VzKFxuICAgICAgc2VuZGVyQWRkcmVzcyxcbiAgICAgIHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uLFxuICAgICAgYWN0dWFsQmFsYW5jZSxcbiAgICAgIHJlbWFpbmluZ0JhbGFuY2VzXG4gICAgKTtcblxuICAgIHJldHVybiB0aGlzLmJ1aWxkQW5kU2lnblRyYW5zYWN0aW9uKHtcbiAgICAgIG1lc3NhZ2VzLFxuICAgICAgY2hhaW5JZCxcbiAgICAgIGFjY291bnREZXRhaWxzLFxuICAgICAgcHVibGljS2V5OiBwdWJsaWNLZXkgfHwgJycsXG4gICAgICBpc1Vuc2lnbmVkU3dlZXAsXG4gICAgICBrZXlTaGFyZXMsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGVzIHRoZSByZWNvdmVyeSBwYXJhbWV0ZXJzXG4gICAqL1xuICBwcml2YXRlIHZhbGlkYXRlUmVjb3ZlcnlQYXJhbXMocGFyYW1zOiBSZWNvdmVyeU9wdGlvbnMsIGlzVW5zaWduZWRTd2VlcDogYm9vbGVhbik6IHZvaWQge1xuICAgIGlmICghcGFyYW1zLnJlY292ZXJ5RGVzdGluYXRpb24gfHwgIXRoaXMuaXNWYWxpZEFkZHJlc3MocGFyYW1zLnJlY292ZXJ5RGVzdGluYXRpb24pKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2ludmFsaWQgcmVjb3ZlcnlEZXN0aW5hdGlvbicpO1xuICAgIH1cblxuICAgIGlmICghaXNVbnNpZ25lZFN3ZWVwKSB7XG4gICAgICBpZiAoIXBhcmFtcy51c2VyS2V5KSB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgdXNlcktleScpO1xuICAgICAgaWYgKCFwYXJhbXMuYmFja3VwS2V5KSB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgYmFja3VwS2V5Jyk7XG4gICAgICBpZiAoIXBhcmFtcy53YWxsZXRQYXNzcGhyYXNlKSB0aHJvdyBuZXcgRXJyb3IoJ21pc3Npbmcgd2FsbGV0IHBhc3NwaHJhc2UnKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoaXMgaXMgYW4gdW5zaWduZWQgc3dlZXAgb3BlcmF0aW9uXG4gICAqL1xuICBwcml2YXRlIGlzVW5zaWduZWRTd2VlcChwYXJhbXM6IFJlY292ZXJ5T3B0aW9ucyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhcGFyYW1zLnVzZXJLZXkgJiYgIXBhcmFtcy5iYWNrdXBLZXkgJiYgIXBhcmFtcy53YWxsZXRQYXNzcGhyYXNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMgc2VuZGVyIGRldGFpbHMgaW5jbHVkaW5nIGFkZHJlc3MsIHB1YmxpYyBrZXkgYW5kIGtleSBzaGFyZXNcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2V0U2VuZGVyRGV0YWlscyhcbiAgICBwYXJhbXM6IFJlY292ZXJ5T3B0aW9ucyxcbiAgICBpc1Vuc2lnbmVkU3dlZXA6IGJvb2xlYW5cbiAgKTogUHJvbWlzZTx7XG4gICAgc2VuZGVyQWRkcmVzczogc3RyaW5nO1xuICAgIHB1YmxpY0tleT86IHN0cmluZztcbiAgICBrZXlTaGFyZXM/OiBLZXlTaGFyZXM7XG4gIH0+IHtcbiAgICBjb25zdCBNUEMgPSBuZXcgRWNkc2EoKTtcblxuICAgIGlmIChpc1Vuc2lnbmVkU3dlZXApIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHNlbmRlckFkZHJlc3M6IHBhcmFtcy5yb290QWRkcmVzcyBhcyBzdHJpbmcsXG4gICAgICAgIHB1YmxpY0tleTogTVBDLmRlcml2ZVVuaGFyZGVuZWQocGFyYW1zLmJpdGdvS2V5IHx8ICcnLCBST09UX1BBVEgpLnNsaWNlKDAsIDY2KSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgY29uc3Qga2V5U2hhcmVzID0gYXdhaXQgdGhpcy5nZXRLZXlTaGFyZXMocGFyYW1zKTtcbiAgICBjb25zdCBwdWJsaWNLZXkgPSBNUEMuZGVyaXZlVW5oYXJkZW5lZChrZXlTaGFyZXMuY29tbW9uS2V5Q2hhaW4sIFJPT1RfUEFUSCkuc2xpY2UoMCwgNjYpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHNlbmRlckFkZHJlc3M6IHRoaXMuZ2V0QWRkcmVzc0Zyb21QdWJsaWNLZXkocHVibGljS2V5KSxcbiAgICAgIHB1YmxpY0tleSxcbiAgICAgIGtleVNoYXJlcyxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEdldHMga2V5IHNoYXJlcyBmcm9tIHJlY292ZXJ5IHBhcmFtZXRlcnNcbiAgICovXG4gIHByaXZhdGUgYXN5bmMgZ2V0S2V5U2hhcmVzKHBhcmFtczogUmVjb3ZlcnlPcHRpb25zKTogUHJvbWlzZTxLZXlTaGFyZXM+IHtcbiAgICBpZiAoIXBhcmFtcy51c2VyS2V5IHx8ICFwYXJhbXMuYmFja3VwS2V5IHx8ICFwYXJhbXMud2FsbGV0UGFzc3BocmFzZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdNaXNzaW5nIHJlcXVpcmVkIGtleSBwYXJhbWV0ZXJzJyk7XG4gICAgfVxuXG4gICAgY29uc3QgdXNlcktleSA9IHBhcmFtcy51c2VyS2V5LnJlcGxhY2UoL1xccy9nLCAnJyk7XG4gICAgY29uc3QgYmFja3VwS2V5ID0gcGFyYW1zLmJhY2t1cEtleS5yZXBsYWNlKC9cXHMvZywgJycpO1xuICAgIGNvbnN0IHdhbGxldFBhc3NwaHJhc2UgPSBwYXJhbXMud2FsbGV0UGFzc3BocmFzZTtcblxuICAgIGlmICghdXNlcktleSB8fCAhYmFja3VwS2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQga2V5IGZvcm1hdCcpO1xuICAgIH1cblxuICAgIHJldHVybiBhd2FpdCBFQ0RTQVV0aWxzLmdldE1wY1YyUmVjb3ZlcnlLZXlTaGFyZXModXNlcktleSwgYmFja3VwS2V5LCB3YWxsZXRQYXNzcGhyYXNlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcm9jZXNzZXMgYWNjb3VudCBiYWxhbmNlcyBhbmQgdmFsaWRhdGVzIHN1ZmZpY2llbnQgZnVuZHNcbiAgICovXG4gIHByaXZhdGUgcHJvY2Vzc0JhbGFuY2VzKGJhbGFuY2VzOiBDb2luW10pOiBCYWxhbmNlUmVzdWx0IHtcbiAgICBpZiAoIWJhbGFuY2VzPy5sZW5ndGgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTm8gYmFsYW5jZSBmb3VuZCBvbiBhY2NvdW50Jyk7XG4gICAgfVxuXG4gICAgY29uc3QgZGVub21pbmF0aW9uID0gdGhpcy5nZXREZW5vbWluYXRpb24oKTtcbiAgICBpZiAoIWRlbm9taW5hdGlvbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGRlbm9taW5hdGlvbicpO1xuICAgIH1cblxuICAgIGxldCBuYXRpdmVCYWxhbmNlID0gbmV3IEJpZ051bWJlcigwKTtcbiAgICBjb25zdCByZW1haW5pbmdCYWxhbmNlczogQ29pbltdID0gW107XG5cbiAgICBjb25zdCBnYXNBbW91bnREZXRhaWxzID0gdGhpcy5nZXRHYXNBbW91bnREZXRhaWxzKCk7XG4gICAgaWYgKCFnYXNBbW91bnREZXRhaWxzPy5nYXNBbW91bnQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBnYXMgYW1vdW50Jyk7XG4gICAgfVxuXG4gICAgY29uc3QgZ2FzQW1vdW50ID0gbmV3IEJpZ051bWJlcihnYXNBbW91bnREZXRhaWxzLmdhc0Ftb3VudCk7XG4gICAgYmFsYW5jZXMuZm9yRWFjaCgoYmFsYW5jZSkgPT4ge1xuICAgICAgaWYgKCFiYWxhbmNlLmFtb3VudCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgYmFsYW5jZSBhbW91bnQnKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGJhbGFuY2UuZGVub20gPT09IGRlbm9taW5hdGlvbikge1xuICAgICAgICBuYXRpdmVCYWxhbmNlID0gbmV3IEJpZ051bWJlcihiYWxhbmNlLmFtb3VudCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZW1haW5pbmdCYWxhbmNlcy5wdXNoKGJhbGFuY2UpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgY29uc3QgYWN0dWFsQmFsYW5jZSA9IG5hdGl2ZUJhbGFuY2UubWludXMoZ2FzQW1vdW50KTtcbiAgICBpZiAoYWN0dWFsQmFsYW5jZS5pc0xlc3NUaGFuT3JFcXVhbFRvKDApKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0RpZCBub3QgaGF2ZSBlbm91Z2ggZnVuZHMgdG8gcmVjb3ZlcicpO1xuICAgIH1cblxuICAgIHJldHVybiB7IG5hdGl2ZUJhbGFuY2UsIHJlbWFpbmluZ0JhbGFuY2VzLCBhY3R1YWxCYWxhbmNlIH07XG4gIH1cblxuICAvKipcbiAgICogQnVpbGRzIHRyYW5zYWN0aW9uIG1lc3NhZ2VzIGZvciBhbGwgYmFsYW5jZXNcbiAgICovXG4gIHByaXZhdGUgYnVpbGRUcmFuc2FjdGlvbk1lc3NhZ2VzKFxuICAgIHNlbmRlckFkZHJlc3M6IHN0cmluZyxcbiAgICByZWNvdmVyeURlc3RpbmF0aW9uOiBzdHJpbmcsXG4gICAgYWN0dWFsQmFsYW5jZTogQmlnTnVtYmVyLFxuICAgIHJlbWFpbmluZ0JhbGFuY2VzOiBDb2luW11cbiAgKTogU2VuZE1lc3NhZ2VbXSB7XG4gICAgY29uc3QgbmF0aXZlU2VuZE1lc3NhZ2U6IFNlbmRNZXNzYWdlID0ge1xuICAgICAgZnJvbUFkZHJlc3M6IHNlbmRlckFkZHJlc3MsXG4gICAgICB0b0FkZHJlc3M6IHJlY292ZXJ5RGVzdGluYXRpb24sXG4gICAgICBhbW91bnQ6IFtcbiAgICAgICAge1xuICAgICAgICAgIGRlbm9tOiB0aGlzLmdldERlbm9taW5hdGlvbigpLFxuICAgICAgICAgIGFtb3VudDogYWN0dWFsQmFsYW5jZS50b0ZpeGVkKCksXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH07XG5cbiAgICBjb25zdCBvdGhlclRva2VuTWVzc2FnZXMgPSByZW1haW5pbmdCYWxhbmNlcy5tYXAoKGJhbGFuY2UpID0+ICh7XG4gICAgICBmcm9tQWRkcmVzczogc2VuZGVyQWRkcmVzcyxcbiAgICAgIHRvQWRkcmVzczogcmVjb3ZlcnlEZXN0aW5hdGlvbixcbiAgICAgIGFtb3VudDogW2JhbGFuY2VdLFxuICAgIH0pKTtcblxuICAgIHJldHVybiBbLi4ub3RoZXJUb2tlbk1lc3NhZ2VzLCBuYXRpdmVTZW5kTWVzc2FnZV07XG4gIH1cblxuICAvKipcbiAgICogQnVpbGRzIGFuZCBzaWducyB0aGUgdHJhbnNhY3Rpb25cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgYnVpbGRBbmRTaWduVHJhbnNhY3Rpb24ocGFyYW1zOiBUcmFuc2FjdGlvbkJ1aWxkUGFyYW1zKTogUHJvbWlzZTxDb3Ntb3NMaWtlQ29pblJlY292ZXJ5T3V0cHV0PiB7XG4gICAgaWYgKCFwYXJhbXMuY2hhaW5JZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGNoYWluIElEJyk7XG4gICAgfVxuXG4gICAgY29uc3QgW2FjY291bnROdW1iZXIsIHNlcXVlbmNlTm9dID0gcGFyYW1zLmFjY291bnREZXRhaWxzO1xuICAgIGlmICghYWNjb3VudE51bWJlciB8fCAhc2VxdWVuY2VObykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGFjY291bnQgZGV0YWlscycpO1xuICAgIH1cblxuICAgIGNvbnN0IGRlbm9taW5hdGlvbiA9IHRoaXMuZ2V0RGVub21pbmF0aW9uKCk7XG4gICAgY29uc3QgZ2FzQW1vdW50RGV0YWlscyA9IHRoaXMuZ2V0R2FzQW1vdW50RGV0YWlscygpO1xuICAgIGlmICghZGVub21pbmF0aW9uIHx8ICFnYXNBbW91bnREZXRhaWxzPy5nYXNBbW91bnQgfHwgIWdhc0Ftb3VudERldGFpbHM/Lmdhc0xpbWl0KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgZ2FzIGNvbmZpZ3VyYXRpb24nKTtcbiAgICB9XG5cbiAgICBjb25zdCBnYXNCdWRnZXQ6IEZlZURhdGEgPSB7XG4gICAgICBhbW91bnQ6IFtcbiAgICAgICAge1xuICAgICAgICAgIGRlbm9tOiBkZW5vbWluYXRpb24sXG4gICAgICAgICAgYW1vdW50OiBnYXNBbW91bnREZXRhaWxzLmdhc0Ftb3VudCxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgICBnYXNMaW1pdDogZ2FzQW1vdW50RGV0YWlscy5nYXNMaW1pdCxcbiAgICB9O1xuXG4gICAgY29uc3QgdHhuQnVpbGRlciA9IHRoaXMuZ2V0QnVpbGRlcigpXG4gICAgICAuZ2V0VHJhbnNmZXJCdWlsZGVyKClcbiAgICAgIC5tZXNzYWdlcyhwYXJhbXMubWVzc2FnZXMpXG4gICAgICAuZ2FzQnVkZ2V0KGdhc0J1ZGdldClcbiAgICAgIC5zZXF1ZW5jZShOdW1iZXIoc2VxdWVuY2VObykpXG4gICAgICAuYWNjb3VudE51bWJlcihOdW1iZXIoYWNjb3VudE51bWJlcikpXG4gICAgICAuY2hhaW5JZChwYXJhbXMuY2hhaW5JZClcbiAgICAgIC5wdWJsaWNLZXkocGFyYW1zLnB1YmxpY0tleSk7XG5cbiAgICBjb25zdCB1bnNpZ25lZFRyYW5zYWN0aW9uID0gKGF3YWl0IHR4bkJ1aWxkZXIuYnVpbGQoKSkgYXMgQ29zbW9zVHJhbnNhY3Rpb248Q3VzdG9tTWVzc2FnZT47XG4gICAgaWYgKCF1bnNpZ25lZFRyYW5zYWN0aW9uKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ZhaWxlZCB0byBidWlsZCB1bnNpZ25lZCB0cmFuc2FjdGlvbicpO1xuICAgIH1cblxuICAgIGlmIChwYXJhbXMuaXNVbnNpZ25lZFN3ZWVwKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBzaWduYWJsZUhleDogdW5zaWduZWRUcmFuc2FjdGlvbi5zaWduYWJsZVBheWxvYWQudG9TdHJpbmcoJ2hleCcpLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5zaWduVHJhbnNhY3Rpb25XaXRoTXBjKHVuc2lnbmVkVHJhbnNhY3Rpb24sIHR4bkJ1aWxkZXIsIHBhcmFtcy5rZXlTaGFyZXMhLCBwYXJhbXMucHVibGljS2V5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTaWducyB0aGUgdHJhbnNhY3Rpb24gd2l0aCBNUENcbiAgICovXG4gIC8qKlxuICAgKiBTaWducyB0aGUgdHJhbnNhY3Rpb24gdXNpbmcgTVBDIChNdWx0aS1QYXJ0eSBDb21wdXRhdGlvbilcbiAgICogQHBhcmFtIHVuc2lnbmVkVHJhbnNhY3Rpb24gVGhlIHVuc2lnbmVkIHRyYW5zYWN0aW9uIHRvIHNpZ25cbiAgICogQHBhcmFtIHR4bkJ1aWxkZXIgVGhlIHRyYW5zYWN0aW9uIGJ1aWxkZXIgaW5zdGFuY2VcbiAgICogQHBhcmFtIGtleVNoYXJlcyBUaGUga2V5IHNoYXJlcyBmb3IgTVBDIHNpZ25pbmdcbiAgICogQHBhcmFtIHB1YmxpY0tleSBUaGUgcHVibGljIGtleSBmb3IgdmVyaWZpY2F0aW9uXG4gICAqIEByZXR1cm5zIFRoZSBzaWduZWQgdHJhbnNhY3Rpb24gb3V0cHV0XG4gICAqIEB0aHJvd3MgRXJyb3IgaWYgdmFsaWRhdGlvbiBmYWlscyBvciBzaWduaW5nIHByb2Nlc3MgZW5jb3VudGVycyBhbiBlcnJvclxuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIHNpZ25UcmFuc2FjdGlvbldpdGhNcGMoXG4gICAgdW5zaWduZWRUcmFuc2FjdGlvbjogQ29zbW9zVHJhbnNhY3Rpb248Q3VzdG9tTWVzc2FnZT4sXG4gICAgdHhuQnVpbGRlcjogQ29zbW9zVHJhbnNhY3Rpb25CdWlsZGVyLFxuICAgIGtleVNoYXJlczogS2V5U2hhcmVzLFxuICAgIHB1YmxpY0tleTogc3RyaW5nXG4gICk6IFByb21pc2U8Q29zbW9zTGlrZUNvaW5SZWNvdmVyeU91dHB1dD4ge1xuICAgIC8vIFZhbGlkYXRlIGlucHV0c1xuICAgIGlmICghdW5zaWduZWRUcmFuc2FjdGlvbj8uc2lnbmFibGVQYXlsb2FkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgdW5zaWduZWQgdHJhbnNhY3Rpb24nKTtcbiAgICB9XG5cbiAgICBpZiAoIWtleVNoYXJlcz8udXNlcktleVNoYXJlIHx8ICFrZXlTaGFyZXM/LmJhY2t1cEtleVNoYXJlIHx8ICFrZXlTaGFyZXM/LmNvbW1vbktleUNoYWluKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQga2V5IHNoYXJlcycpO1xuICAgIH1cblxuICAgIGlmICghcHVibGljS2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgcHVibGljIGtleScpO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBjb25zdCBNUEMgPSBuZXcgRWNkc2EoKTtcbiAgICAgIGNvbnN0IG1lc3NhZ2UgPSB1bnNpZ25lZFRyYW5zYWN0aW9uLnNpZ25hYmxlUGF5bG9hZDtcblxuICAgICAgLy8gR2V0IGhhc2ggZnVuY3Rpb24gYW5kIGNvbXB1dGUgbWVzc2FnZSBoYXNoXG4gICAgICBjb25zdCBoYXNoRnVuY3Rpb24gPSB1dGlscy5nZXRIYXNoRnVuY3Rpb24oKSB8fCBjcmVhdGVIYXNoKCdzaGEyNTYnKTtcbiAgICAgIGlmICghaGFzaEZ1bmN0aW9uKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignRmFpbGVkIHRvIGdldCBoYXNoIGZ1bmN0aW9uJyk7XG4gICAgICB9XG4gICAgICBjb25zdCBtZXNzYWdlSGFzaCA9IGhhc2hGdW5jdGlvbi51cGRhdGUobWVzc2FnZSkuZGlnZXN0KCk7XG5cbiAgICAgIC8vIFNpZ24gdGhlIHRyYW5zYWN0aW9uXG4gICAgICBjb25zdCBzaWduYXR1cmUgPSBhd2FpdCBFQ0RTQVV0aWxzLnNpZ25SZWNvdmVyeU1wY1YyKFxuICAgICAgICBtZXNzYWdlSGFzaCxcbiAgICAgICAga2V5U2hhcmVzLnVzZXJLZXlTaGFyZSxcbiAgICAgICAga2V5U2hhcmVzLmJhY2t1cEtleVNoYXJlLFxuICAgICAgICBrZXlTaGFyZXMuY29tbW9uS2V5Q2hhaW5cbiAgICAgICk7XG5cbiAgICAgIC8vIFZlcmlmeSB0aGUgc2lnbmF0dXJlXG4gICAgICBjb25zdCBzaWduYWJsZUhleCA9IHVuc2lnbmVkVHJhbnNhY3Rpb24uc2lnbmFibGVQYXlsb2FkLnRvU3RyaW5nKCdoZXgnKTtcbiAgICAgIGNvbnN0IHNpZ25hYmxlQnVmZmVyID0gQnVmZmVyLmZyb20oc2lnbmFibGVIZXgsICdoZXgnKTtcbiAgICAgIE1QQy52ZXJpZnkoc2lnbmFibGVCdWZmZXIsIHNpZ25hdHVyZSwgdGhpcy5nZXRIYXNoRnVuY3Rpb24oKSk7XG5cbiAgICAgIC8vIEdldCBjb3Ntb3Mga2V5IHBhaXIgYW5kIHZhbGlkYXRlXG4gICAgICBjb25zdCBjb3Ntb3NLZXlQYWlyID0gdGhpcy5nZXRLZXlQYWlyKHB1YmxpY0tleSk7XG4gICAgICBpZiAoIWNvc21vc0tleVBhaXIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGNvc21vcyBrZXkgcGFpcicpO1xuICAgICAgfVxuXG4gICAgICAvLyBBZGQgc2lnbmF0dXJlIHRvIHRyYW5zYWN0aW9uXG4gICAgICB0eG5CdWlsZGVyLmFkZFNpZ25hdHVyZSh7IHB1YjogY29zbW9zS2V5UGFpci5nZXRLZXlzKCkucHViIH0sIEJ1ZmZlci5mcm9tKHNpZ25hdHVyZS5yICsgc2lnbmF0dXJlLnMsICdoZXgnKSk7XG5cbiAgICAgIC8vIEJ1aWxkIGZpbmFsIHRyYW5zYWN0aW9uXG4gICAgICBjb25zdCBzaWduZWRUcmFuc2FjdGlvbiA9IGF3YWl0IHR4bkJ1aWxkZXIuYnVpbGQoKTtcbiAgICAgIGlmICghc2lnbmVkVHJhbnNhY3Rpb24pIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdGYWlsZWQgdG8gYnVpbGQgc2lnbmVkIHRyYW5zYWN0aW9uJyk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIHNlcmlhbGl6ZWRUeDogc2lnbmVkVHJhbnNhY3Rpb24udG9Ccm9hZGNhc3RGb3JtYXQoKSxcbiAgICAgIH07XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRmFpbGVkIHRvIHNpZ24gdHJhbnNhY3Rpb246ICR7ZXJyb3IubWVzc2FnZX1gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQnVpbGRzIGEgcmVkZWxlZ2F0ZSB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge1JlY292ZXJ5T3B0aW9uc30gcGFyYW1zIHBhcmFtZXRlcnMgbmVlZGVkIHRvIGNvbnN0cnVjdCBhbmRcbiAgICogKG1heWJlKSBzaWduIHRoZSB0cmFuc2FjdGlvblxuICAgKlxuICAgKiBAcmV0dXJucyB7Q29zbW9zTGlrZUNvaW5SZWNvdmVyeU91dHB1dH0gdGhlIHNlcmlhbGl6ZWQgdHJhbnNhY3Rpb24gaGV4IHN0cmluZ1xuICAgKi9cbiAgYXN5bmMgcmVkZWxlZ2F0ZShcbiAgICBwYXJhbXM6IFJlY292ZXJ5T3B0aW9ucyAmIHtcbiAgICAgIHZhbGlkYXRvclNyY0FkZHJlc3M6IHN0cmluZztcbiAgICAgIHZhbGlkYXRvckRzdEFkZHJlc3M6IHN0cmluZztcbiAgICAgIGFtb3VudFRvUmVkZWxlZ2F0ZTogc3RyaW5nO1xuICAgIH1cbiAgKTogUHJvbWlzZTxDb3Ntb3NMaWtlQ29pblJlY292ZXJ5T3V0cHV0PiB7XG4gICAgaWYgKCFwYXJhbXMudmFsaWRhdG9yU3JjQWRkcmVzcyB8fCAhdGhpcy5pc1ZhbGlkQWRkcmVzcyhwYXJhbXMudmFsaWRhdG9yU3JjQWRkcmVzcykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCB2YWxpZGF0b3JTcmNBZGRyZXNzJyk7XG4gICAgfVxuXG4gICAgaWYgKCFwYXJhbXMudmFsaWRhdG9yRHN0QWRkcmVzcyB8fCAhdGhpcy5pc1ZhbGlkQWRkcmVzcyhwYXJhbXMudmFsaWRhdG9yRHN0QWRkcmVzcykpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCB2YWxpZGF0b3JEc3RBZGRyZXNzJyk7XG4gICAgfVxuXG4gICAgaWYgKCFwYXJhbXMudXNlcktleSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHVzZXJLZXknKTtcbiAgICB9XG5cbiAgICBpZiAoIXBhcmFtcy5iYWNrdXBLZXkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyBiYWNrdXBLZXknKTtcbiAgICB9XG5cbiAgICBpZiAoIXBhcmFtcy53YWxsZXRQYXNzcGhyYXNlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3Npbmcgd2FsbGV0IHBhc3NwaHJhc2UnKTtcbiAgICB9XG5cbiAgICBpZiAoIXBhcmFtcy5hbW91bnRUb1JlZGVsZWdhdGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyBhbW91bnRUb1JlZGVsZWdhdGUnKTtcbiAgICB9XG5cbiAgICBjb25zdCB1c2VyS2V5ID0gcGFyYW1zLnVzZXJLZXkucmVwbGFjZSgvXFxzL2csICcnKTtcbiAgICBjb25zdCBiYWNrdXBLZXkgPSBwYXJhbXMuYmFja3VwS2V5LnJlcGxhY2UoL1xccy9nLCAnJyk7XG5cbiAgICBjb25zdCB7IHVzZXJLZXlTaGFyZSwgYmFja3VwS2V5U2hhcmUsIGNvbW1vbktleUNoYWluIH0gPSBhd2FpdCBFQ0RTQVV0aWxzLmdldE1wY1YyUmVjb3ZlcnlLZXlTaGFyZXMoXG4gICAgICB1c2VyS2V5LFxuICAgICAgYmFja3VwS2V5LFxuICAgICAgcGFyYW1zLndhbGxldFBhc3NwaHJhc2VcbiAgICApOyAvLyBiYXNlQWRkcmVzcyBpcyBub3QgZXh0cmFjdGVkXG5cbiAgICBjb25zdCBNUEMgPSBuZXcgRWNkc2EoKTtcbiAgICBjb25zdCBjaGFpbklkID0gYXdhaXQgdGhpcy5nZXRDaGFpbklkKCk7XG4gICAgY29uc3QgcHVibGljS2V5ID0gTVBDLmRlcml2ZVVuaGFyZGVuZWQoY29tbW9uS2V5Q2hhaW4sIFJPT1RfUEFUSCkuc2xpY2UoMCwgNjYpO1xuICAgIGNvbnN0IHNlbmRlckFkZHJlc3MgPSB0aGlzLmdldEFkZHJlc3NGcm9tUHVibGljS2V5KHB1YmxpY0tleSk7XG5cbiAgICBjb25zdCBbYWNjb3VudE51bWJlciwgc2VxdWVuY2VOb10gPSBhd2FpdCB0aGlzLmdldEFjY291bnREZXRhaWxzKHNlbmRlckFkZHJlc3MpO1xuICAgIGNvbnN0IGdhc0J1ZGdldDogRmVlRGF0YSA9IHtcbiAgICAgIGFtb3VudDogW3sgZGVub206IHRoaXMuZ2V0RGVub21pbmF0aW9uKCksIGFtb3VudDogdGhpcy5nZXRHYXNBbW91bnREZXRhaWxzKCkuZ2FzQW1vdW50IH1dLFxuICAgICAgZ2FzTGltaXQ6IHRoaXMuZ2V0R2FzQW1vdW50RGV0YWlscygpLmdhc0xpbWl0LFxuICAgIH07XG5cbiAgICBjb25zdCBhbW91bnQ6IENvaW4gPSB7XG4gICAgICBkZW5vbTogdGhpcy5nZXREZW5vbWluYXRpb24oKSxcbiAgICAgIGFtb3VudDogbmV3IEJpZ051bWJlcihwYXJhbXMuYW1vdW50VG9SZWRlbGVnYXRlKS50b0ZpeGVkKCksXG4gICAgfTtcblxuICAgIGNvbnN0IHNlbmRNZXNzYWdlOiBSZWRlbGVnYXRlTWVzc2FnZVtdID0gW1xuICAgICAge1xuICAgICAgICBkZWxlZ2F0b3JBZGRyZXNzOiBzZW5kZXJBZGRyZXNzLFxuICAgICAgICB2YWxpZGF0b3JTcmNBZGRyZXNzOiBwYXJhbXMudmFsaWRhdG9yU3JjQWRkcmVzcyxcbiAgICAgICAgdmFsaWRhdG9yRHN0QWRkcmVzczogcGFyYW1zLnZhbGlkYXRvckRzdEFkZHJlc3MsXG4gICAgICAgIGFtb3VudDogYW1vdW50LFxuICAgICAgfSxcbiAgICBdO1xuXG4gICAgY29uc3QgdHhuQnVpbGRlciA9IHRoaXMuZ2V0QnVpbGRlcigpLmdldFN0YWtpbmdSZWRlbGVnYXRlQnVpbGRlcigpO1xuICAgIHR4bkJ1aWxkZXJcbiAgICAgIC5tZXNzYWdlcyhzZW5kTWVzc2FnZSlcbiAgICAgIC5nYXNCdWRnZXQoZ2FzQnVkZ2V0KVxuICAgICAgLnB1YmxpY0tleShwdWJsaWNLZXkpXG4gICAgICAuc2VxdWVuY2UoTnVtYmVyKHNlcXVlbmNlTm8pKVxuICAgICAgLmFjY291bnROdW1iZXIoTnVtYmVyKGFjY291bnROdW1iZXIpKVxuICAgICAgLmNoYWluSWQoY2hhaW5JZCk7XG5cbiAgICBjb25zdCB1bnNpZ25lZFRyYW5zYWN0aW9uID0gKGF3YWl0IHR4bkJ1aWxkZXIuYnVpbGQoKSkgYXMgQ29zbW9zVHJhbnNhY3Rpb248Q3VzdG9tTWVzc2FnZT47XG4gICAgbGV0IHNlcmlhbGl6ZWRUeCA9IHVuc2lnbmVkVHJhbnNhY3Rpb24udG9Ccm9hZGNhc3RGb3JtYXQoKTtcbiAgICBjb25zdCBzaWduYWJsZUhleCA9IHVuc2lnbmVkVHJhbnNhY3Rpb24uc2lnbmFibGVQYXlsb2FkLnRvU3RyaW5nKCdoZXgnKTtcbiAgICBjb25zdCBtZXNzYWdlID0gdW5zaWduZWRUcmFuc2FjdGlvbi5zaWduYWJsZVBheWxvYWQ7XG4gICAgY29uc3QgbWVzc2FnZUhhc2ggPSAodXRpbHMuZ2V0SGFzaEZ1bmN0aW9uKCkgfHwgY3JlYXRlSGFzaCgnc2hhMjU2JykpLnVwZGF0ZShtZXNzYWdlKS5kaWdlc3QoKTtcbiAgICBjb25zdCBzaWduYXR1cmUgPSBhd2FpdCBFQ0RTQVV0aWxzLnNpZ25SZWNvdmVyeU1wY1YyKG1lc3NhZ2VIYXNoLCB1c2VyS2V5U2hhcmUsIGJhY2t1cEtleVNoYXJlLCBjb21tb25LZXlDaGFpbik7XG4gICAgY29uc3Qgc2lnbmFibGVCdWZmZXIgPSBCdWZmZXIuZnJvbShzaWduYWJsZUhleCwgJ2hleCcpO1xuICAgIE1QQy52ZXJpZnkoc2lnbmFibGVCdWZmZXIsIHNpZ25hdHVyZSwgdGhpcy5nZXRIYXNoRnVuY3Rpb24oKSk7XG4gICAgY29uc3QgY29zbW9zS2V5UGFpciA9IHRoaXMuZ2V0S2V5UGFpcihwdWJsaWNLZXkpO1xuICAgIHR4bkJ1aWxkZXIuYWRkU2lnbmF0dXJlKHsgcHViOiBjb3Ntb3NLZXlQYWlyLmdldEtleXMoKS5wdWIgfSwgQnVmZmVyLmZyb20oc2lnbmF0dXJlLnIgKyBzaWduYXR1cmUucywgJ2hleCcpKTtcbiAgICBjb25zdCBzaWduZWRUcmFuc2FjdGlvbiA9IGF3YWl0IHR4bkJ1aWxkZXIuYnVpbGQoKTtcbiAgICBzZXJpYWxpemVkVHggPSBzaWduZWRUcmFuc2FjdGlvbi50b0Jyb2FkY2FzdEZvcm1hdCgpO1xuXG4gICAgcmV0dXJuIHsgc2VyaWFsaXplZFR4OiBzZXJpYWxpemVkVHggfTtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdERvYyAqKi9cbiAgYXN5bmMgdmVyaWZ5VHJhbnNhY3Rpb24ocGFyYW1zOiBWZXJpZnlUcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBsZXQgdG90YWxBbW91bnQgPSBuZXcgQmlnTnVtYmVyKDApO1xuICAgIGNvbnN0IHsgdHhQcmVidWlsZCwgdHhQYXJhbXMgfSA9IHBhcmFtcztcbiAgICBjb25zdCByYXdUeCA9IHR4UHJlYnVpbGQudHhIZXg7XG4gICAgaWYgKCFyYXdUeCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHJlcXVpcmVkIHR4IHByZWJ1aWxkIHByb3BlcnR5IHR4SGV4Jyk7XG4gICAgfVxuICAgIGNvbnN0IHRyYW5zYWN0aW9uID0gYXdhaXQgdGhpcy5nZXRCdWlsZGVyKCkuZnJvbShyYXdUeCkuYnVpbGQoKTtcbiAgICBjb25zdCBleHBsYWluZWRUeCA9IHRyYW5zYWN0aW9uLmV4cGxhaW5UcmFuc2FjdGlvbigpO1xuICAgIGlmICh0eFBhcmFtcy5yZWNpcGllbnRzICYmIHR4UGFyYW1zLnJlY2lwaWVudHMubGVuZ3RoID4gMCkge1xuICAgICAgY29uc3QgZmlsdGVyZWRSZWNpcGllbnRzID0gdHhQYXJhbXMucmVjaXBpZW50cz8ubWFwKChyZWNpcGllbnQpID0+IF8ucGljayhyZWNpcGllbnQsIFsnYWRkcmVzcycsICdhbW91bnQnXSkpO1xuICAgICAgY29uc3QgZmlsdGVyZWRPdXRwdXRzID0gZXhwbGFpbmVkVHgub3V0cHV0cy5tYXAoKG91dHB1dCkgPT4gXy5waWNrKG91dHB1dCwgWydhZGRyZXNzJywgJ2Ftb3VudCddKSk7XG5cbiAgICAgIGlmICghXy5pc0VxdWFsKGZpbHRlcmVkT3V0cHV0cywgZmlsdGVyZWRSZWNpcGllbnRzKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1R4IG91dHB1dHMgZG9lcyBub3QgbWF0Y2ggd2l0aCBleHBlY3RlZCB0eFBhcmFtcyByZWNpcGllbnRzJyk7XG4gICAgICB9XG4gICAgICAvLyBXaXRoZHJhd0RlbGVnYXRvclJld2FyZHMgYW5kIENvbnRyYWN0Q2FsbCB0cmFuc2FjdGlvbiBkb24ndCBoYXZlIGFtb3VudFxuICAgICAgaWYgKHRyYW5zYWN0aW9uLnR5cGUgIT09IFRyYW5zYWN0aW9uVHlwZS5TdGFraW5nV2l0aGRyYXcgJiYgdHJhbnNhY3Rpb24udHlwZSAhPT0gVHJhbnNhY3Rpb25UeXBlLkNvbnRyYWN0Q2FsbCkge1xuICAgICAgICBmb3IgKGNvbnN0IHJlY2lwaWVudHMgb2YgdHhQYXJhbXMucmVjaXBpZW50cykge1xuICAgICAgICAgIHRvdGFsQW1vdW50ID0gdG90YWxBbW91bnQucGx1cyhyZWNpcGllbnRzLmFtb3VudCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCF0b3RhbEFtb3VudC5pc0VxdWFsVG8oZXhwbGFpbmVkVHgub3V0cHV0QW1vdW50KSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignVHggdG90YWwgYW1vdW50IGRvZXMgbm90IG1hdGNoIHdpdGggZXhwZWN0ZWQgdG90YWwgYW1vdW50IGZpZWxkJyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvKiogQGluaGVyaXREb2MgKiovXG4gIGFzeW5jIGV4cGxhaW5UcmFuc2FjdGlvbihvcHRpb25zOiB7IHR4SGV4OiBzdHJpbmcgfSk6IFByb21pc2U8RXhwbGFuYXRpb25SZXN1bHQ+IHtcbiAgICBpZiAoIW9wdGlvbnMudHhIZXgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyByZXF1aXJlZCB0eEhleCBwYXJhbWV0ZXInKTtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHRyYW5zYWN0aW9uQnVpbGRlciA9IHRoaXMuZ2V0QnVpbGRlcigpLmZyb20ob3B0aW9ucy50eEhleCk7XG4gICAgICBjb25zdCB0cmFuc2FjdGlvbiA9IGF3YWl0IHRyYW5zYWN0aW9uQnVpbGRlci5idWlsZCgpO1xuICAgICAgcmV0dXJuIHRyYW5zYWN0aW9uLmV4cGxhaW5UcmFuc2FjdGlvbigpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCB0cmFuc2FjdGlvbjogJyArIGUubWVzc2FnZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNpZ24gYSB0cmFuc2FjdGlvbiB3aXRoIGEgc2luZ2xlIHByaXZhdGUga2V5XG4gICAqIEBwYXJhbSBwYXJhbXMgcGFyYW1ldGVycyBpbiB0aGUgZm9ybSBvZiB7IHR4UHJlYnVpbGQ6IHt0eEhleH0sIHBydiB9XG4gICAqIEByZXR1cm5zIHNpZ25lZCB0cmFuc2FjdGlvbiBpbiB0aGUgZm9ybSBvZiB7IHR4SGV4IH1cbiAgICovXG4gIGFzeW5jIHNpZ25UcmFuc2FjdGlvbihcbiAgICBwYXJhbXM6IFNpZ25UcmFuc2FjdGlvbk9wdGlvbnMgJiB7IHR4UHJlYnVpbGQ6IHsgdHhIZXg6IHN0cmluZyB9OyBwcnY6IHN0cmluZyB9XG4gICk6IFByb21pc2U8U2lnbmVkVHJhbnNhY3Rpb24+IHtcbiAgICBjb25zdCB0eEhleCA9IHBhcmFtcz8udHhQcmVidWlsZD8udHhIZXg7XG4gICAgY29uc3QgcHJpdmF0ZUtleSA9IHBhcmFtcz8ucHJ2O1xuICAgIGlmICghdHhIZXgpIHtcbiAgICAgIHRocm93IG5ldyBTaWduaW5nRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgdHhQcmVidWlsZCBwYXJhbWV0ZXI6IHBhcmFtcy50eFByZWJ1aWxkLnR4SGV4Jyk7XG4gICAgfVxuICAgIGlmICghcHJpdmF0ZUtleSkge1xuICAgICAgdGhyb3cgbmV3IFNpZ25pbmdFcnJvcignbWlzc2luZyByZXF1aXJlZCBwcnYgcGFyYW1ldGVyOiBwYXJhbXMucHJ2Jyk7XG4gICAgfVxuICAgIGNvbnN0IHR4QnVpbGRlciA9IHRoaXMuZ2V0QnVpbGRlcigpLmZyb20ocGFyYW1zLnR4UHJlYnVpbGQudHhIZXgpO1xuICAgIHR4QnVpbGRlci5zaWduKHsga2V5OiBwYXJhbXMucHJ2IH0pO1xuICAgIGNvbnN0IHRyYW5zYWN0aW9uOiBCYXNlVHJhbnNhY3Rpb24gPSBhd2FpdCB0eEJ1aWxkZXIuYnVpbGQoKTtcbiAgICBpZiAoIXRyYW5zYWN0aW9uKSB7XG4gICAgICB0aHJvdyBuZXcgU2lnbmluZ0Vycm9yKCdGYWlsZWQgdG8gYnVpbGQgc2lnbmVkIHRyYW5zYWN0aW9uJyk7XG4gICAgfVxuICAgIGNvbnN0IHNlcmlhbGl6ZWRUeCA9IHRyYW5zYWN0aW9uLnRvQnJvYWRjYXN0Rm9ybWF0KCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIHR4SGV4OiBzZXJpYWxpemVkVHgsXG4gICAgfTtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdERvYyAqKi9cbiAgYXN5bmMgcGFyc2VUcmFuc2FjdGlvbihwYXJhbXM6IFBhcnNlVHJhbnNhY3Rpb25PcHRpb25zICYgeyB0eEhleDogc3RyaW5nIH0pOiBQcm9taXNlPFBhcnNlZFRyYW5zYWN0aW9uPiB7XG4gICAgY29uc3QgdHJhbnNhY3Rpb25FeHBsYW5hdGlvbiA9IGF3YWl0IHRoaXMuZXhwbGFpblRyYW5zYWN0aW9uKHsgdHhIZXg6IHBhcmFtcy50eEhleCB9KTtcbiAgICBpZiAoIXRyYW5zYWN0aW9uRXhwbGFuYXRpb24pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCB0cmFuc2FjdGlvbicpO1xuICAgIH1cblxuICAgIGlmICh0cmFuc2FjdGlvbkV4cGxhbmF0aW9uLm91dHB1dHMubGVuZ3RoIDw9IDApIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGlucHV0czogW10sXG4gICAgICAgIG91dHB1dHM6IFtdLFxuICAgICAgfTtcbiAgICB9XG4gICAgY29uc3Qgc2VuZGVyQWRkcmVzcyA9IHRyYW5zYWN0aW9uRXhwbGFuYXRpb24ub3V0cHV0c1swXS5hZGRyZXNzO1xuICAgIGNvbnN0IGZlZUFtb3VudCA9IG5ldyBCaWdOdW1iZXIodHJhbnNhY3Rpb25FeHBsYW5hdGlvbi5mZWUuZmVlID09PSAnJyA/ICcwJyA6IHRyYW5zYWN0aW9uRXhwbGFuYXRpb24uZmVlLmZlZSk7XG4gICAgY29uc3QgaW5wdXRzID0gW1xuICAgICAge1xuICAgICAgICBhZGRyZXNzOiBzZW5kZXJBZGRyZXNzLFxuICAgICAgICBhbW91bnQ6IG5ldyBCaWdOdW1iZXIodHJhbnNhY3Rpb25FeHBsYW5hdGlvbi5vdXRwdXRBbW91bnQpLnBsdXMoZmVlQW1vdW50KS50b0ZpeGVkKCksXG4gICAgICB9LFxuICAgIF07XG4gICAgY29uc3Qgb3V0cHV0cyA9IHRyYW5zYWN0aW9uRXhwbGFuYXRpb24ub3V0cHV0cy5tYXAoKG91dHB1dCkgPT4ge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYWRkcmVzczogb3V0cHV0LmFkZHJlc3MsXG4gICAgICAgIGFtb3VudDogbmV3IEJpZ051bWJlcihvdXRwdXQuYW1vdW50KS50b0ZpeGVkKCksXG4gICAgICB9O1xuICAgIH0pO1xuICAgIHJldHVybiB7XG4gICAgICBpbnB1dHMsXG4gICAgICBvdXRwdXRzLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBwdWJsaWMgbm9kZSB1cmwgZnJvbSB0aGUgRW52aXJvbm1lbnRzIGNvbnN0YW50IHdlIGhhdmUgZGVmaW5lZFxuICAgKi9cbiAgcHJvdGVjdGVkIGdldFB1YmxpY05vZGVVcmwoKTogc3RyaW5nIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ01ldGhvZCBub3QgaW1wbGVtZW50ZWQuJyk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGFjY291bnQgbnVtYmVyIGZyb20gcHVibGljIG5vZGVcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyBnZXRBY2NvdW50RnJvbU5vZGUoc2VuZGVyQWRkcmVzczogc3RyaW5nKTogUHJvbWlzZTxyZXF1ZXN0LlJlc3BvbnNlPiB7XG4gICAgY29uc3Qgbm9kZVVybCA9IHRoaXMuZ2V0UHVibGljTm9kZVVybCgpO1xuICAgIGNvbnN0IGdldEFjY291bnRQYXRoID0gJy9jb3Ntb3MvYXV0aC92MWJldGExL2FjY291bnRzLyc7XG4gICAgY29uc3QgZnVsbEVuZHBvaW50ID0gbm9kZVVybCArIGdldEFjY291bnRQYXRoICsgc2VuZGVyQWRkcmVzcztcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGF3YWl0IHJlcXVlc3QuZ2V0KGZ1bGxFbmRwb2ludCkuc2VuZCgpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGNvbnNvbGUuZGVidWcoZSk7XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcihgVW5hYmxlIHRvIGNhbGwgZW5kcG9pbnQgJHtnZXRBY2NvdW50UGF0aCArIHNlbmRlckFkZHJlc3N9IGZyb20gbm9kZTogJHtub2RlVXJsfWApO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBiYWxhbmNlIGZyb20gcHVibGljIG5vZGVcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyBnZXRCYWxhbmNlRnJvbU5vZGUoc2VuZGVyQWRkcmVzczogc3RyaW5nKTogUHJvbWlzZTxyZXF1ZXN0LlJlc3BvbnNlPiB7XG4gICAgY29uc3Qgbm9kZVVybCA9IHRoaXMuZ2V0UHVibGljTm9kZVVybCgpO1xuICAgIGNvbnN0IGdldEJhbGFuY2VQYXRoID0gJy9jb3Ntb3MvYmFuay92MWJldGExL2JhbGFuY2VzLyc7XG4gICAgY29uc3QgZnVsbEVuZHBvaW50ID0gbm9kZVVybCArIGdldEJhbGFuY2VQYXRoICsgc2VuZGVyQWRkcmVzcztcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGF3YWl0IHJlcXVlc3QuZ2V0KGZ1bGxFbmRwb2ludCkuc2VuZCgpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGNvbnNvbGUuZGVidWcoZSk7XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcihgVW5hYmxlIHRvIGNhbGwgZW5kcG9pbnQgJHtnZXRCYWxhbmNlUGF0aCArIHNlbmRlckFkZHJlc3N9IGZyb20gbm9kZTogJHtub2RlVXJsfWApO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBjaGFpbiBpZCBmcm9tIHB1YmxpYyBub2RlXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgZ2V0Q2hhaW5JZEZyb21Ob2RlKCk6IFByb21pc2U8cmVxdWVzdC5SZXNwb25zZT4ge1xuICAgIGNvbnN0IG5vZGVVcmwgPSB0aGlzLmdldFB1YmxpY05vZGVVcmwoKTtcbiAgICBjb25zdCBnZXRMYXRlc3RCbG9ja1BhdGggPSAnL2Nvc21vcy9iYXNlL3RlbmRlcm1pbnQvdjFiZXRhMS9ibG9ja3MvbGF0ZXN0JztcbiAgICBjb25zdCBmdWxsRW5kcG9pbnQgPSBub2RlVXJsICsgZ2V0TGF0ZXN0QmxvY2tQYXRoO1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gYXdhaXQgcmVxdWVzdC5nZXQoZnVsbEVuZHBvaW50KS5zZW5kKCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgY29uc29sZS5kZWJ1ZyhlKTtcbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKGBVbmFibGUgdG8gY2FsbCBlbmRwb2ludCAke2dldExhdGVzdEJsb2NrUGF0aH0gZnJvbSBub2RlOiAke25vZGVVcmx9YCk7XG4gIH1cblxuICAvKipcbiAgICogSGVscGVyIHRvIGZldGNoIGFjY291bnQgYmFsYW5jZVxuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIGdldEFjY291bnRCYWxhbmNlKHNlbmRlckFkZHJlc3M6IHN0cmluZyk6IFByb21pc2U8Q29pbltdPiB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLmdldEJhbGFuY2VGcm9tTm9kZShzZW5kZXJBZGRyZXNzKTtcbiAgICBpZiAocmVzcG9uc2Uuc3RhdHVzICE9PSAyMDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQWNjb3VudCBub3QgZm91bmQnKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3BvbnNlLmJvZHkuYmFsYW5jZXM7XG4gIH1cblxuICAvKipcbiAgICogSGVscGVyIHRvIGZldGNoIGNoYWluSWRcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyBnZXRDaGFpbklkKCk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLmdldENoYWluSWRGcm9tTm9kZSgpO1xuICAgIGlmIChyZXNwb25zZS5zdGF0dXMgIT09IDIwMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdBY2NvdW50IG5vdCBmb3VuZCcpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzcG9uc2UuYm9keS5ibG9jay5oZWFkZXIuY2hhaW5faWQ7XG4gIH1cblxuICAvKipcbiAgICogSGVscGVyIHRvIGZldGNoIGFjY291bnQgbnVtYmVyXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgZ2V0QWNjb3VudERldGFpbHMoc2VuZGVyQWRkcmVzczogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5nZXRBY2NvdW50RnJvbU5vZGUoc2VuZGVyQWRkcmVzcyk7XG4gICAgaWYgKHJlc3BvbnNlLnN0YXR1cyAhPT0gMjAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0FjY291bnQgbm90IGZvdW5kJyk7XG4gICAgfVxuICAgIHJldHVybiBbcmVzcG9uc2UuYm9keS5hY2NvdW50LmFjY291bnRfbnVtYmVyLCByZXNwb25zZS5ib2R5LmFjY291bnQuc2VxdWVuY2VdO1xuICB9XG5cbiAgLyoqIEBpbmhlcml0RG9jICoqL1xuICBnZW5lcmF0ZUtleVBhaXIoc2VlZD86IEJ1ZmZlcik6IEtleVBhaXIge1xuICAgIGlmICghc2VlZCkge1xuICAgICAgLy8gQW4gZXh0ZW5kZWQgcHJpdmF0ZSBrZXkgaGFzIGJvdGggYSBub3JtYWwgMjU2IGJpdCBwcml2YXRlIGtleSBhbmQgYSAyNTZcbiAgICAgIC8vIGJpdCBjaGFpbiBjb2RlLCBib3RoIG9mIHdoaWNoIG11c3QgYmUgcmFuZG9tLiA1MTIgYml0cyBpcyB0aGVyZWZvcmUgdGhlXG4gICAgICAvLyBtYXhpbXVtIGVudHJvcHkgYW5kIGdpdmVzIHVzIG1heGltdW0gc2VjdXJpdHkgYWdhaW5zdCBjcmFja2luZy5cbiAgICAgIHNlZWQgPSByYW5kb21CeXRlcyg1MTIgLyA4KTtcbiAgICB9XG4gICAgY29uc3QgZXh0ZW5kZWRLZXkgPSBiaXAzMi5mcm9tU2VlZChzZWVkKTtcbiAgICByZXR1cm4ge1xuICAgICAgcHViOiBleHRlbmRlZEtleS5uZXV0ZXJlZCgpLnRvQmFzZTU4KCksXG4gICAgICBwcnY6IGV4dGVuZGVkS2V5LnRvQmFzZTU4KCksXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgdGhlIGFkZHJlc3MgZnJvbSBhIHB1YmxpYyBrZXkuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwdWJLZXkgLSBUaGUgcHVibGljIGtleS5cbiAgICogQHJldHVybnMge3N0cmluZ30gVGhlIGNvcnJlc3BvbmRpbmcgYWRkcmVzcy5cbiAgICovXG4gIGdldEFkZHJlc3NGcm9tUHVibGljS2V5KHB1YktleTogc3RyaW5nKTogc3RyaW5nIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ01ldGhvZCBub3QgaW1wbGVtZW50ZWQnKTtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdERvYyAqKi9cbiAgYXN5bmMgaXNXYWxsZXRBZGRyZXNzKHBhcmFtczogVmVyaWZ5QWRkcmVzc09wdGlvbnMpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBjb25zdCBhZGRyZXNzRGV0YWlscyA9IHRoaXMuZ2V0QWRkcmVzc0RldGFpbHMocGFyYW1zLmFkZHJlc3MpO1xuXG4gICAgaWYgKCF0aGlzLmlzVmFsaWRBZGRyZXNzKGFkZHJlc3NEZXRhaWxzLmFkZHJlc3MpKSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZEFkZHJlc3NFcnJvcihgaW52YWxpZCBhZGRyZXNzOiAke2FkZHJlc3NEZXRhaWxzLmFkZHJlc3N9YCk7XG4gICAgfVxuICAgIGNvbnN0IHJvb3RBZGRyZXNzID0gKHBhcmFtcy5jb2luU3BlY2lmaWMgYXMgQ29zbW9zQ29pblNwZWNpZmljKS5yb290QWRkcmVzcztcbiAgICBpZiAoYWRkcmVzc0RldGFpbHMuYWRkcmVzcyAhPT0gcm9vdEFkZHJlc3MpIHtcbiAgICAgIHRocm93IG5ldyBVbmV4cGVjdGVkQWRkcmVzc0Vycm9yKGBhZGRyZXNzIHZhbGlkYXRpb24gZmFpbHVyZTogJHthZGRyZXNzRGV0YWlscy5hZGRyZXNzfSB2cyAke3Jvb3RBZGRyZXNzfWApO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdERvYyAqKi9cbiAgZ2V0SGFzaEZ1bmN0aW9uKCk6IEhhc2gge1xuICAgIHJldHVybiB1dGlscy5nZXRIYXNoRnVuY3Rpb24oKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcm9jZXNzIGFkZHJlc3MgaW50byBhZGRyZXNzIGFuZCBtZW1vIGlkXG4gICAqXG4gICAqIEBwYXJhbSBhZGRyZXNzIHRoZSBhZGRyZXNzXG4gICAqIEByZXR1cm5zIG9iamVjdCBjb250YWluaW5nIGFkZHJlc3MgYW5kIG1lbW8gaWRcbiAgICovXG4gIGdldEFkZHJlc3NEZXRhaWxzKGFkZHJlc3M6IHN0cmluZyk6IEFkZHJlc3NEZXRhaWxzIHtcbiAgICBjb25zdCBkZXN0aW5hdGlvbkRldGFpbHMgPSB1cmwucGFyc2UoYWRkcmVzcyk7XG4gICAgY29uc3QgZGVzdGluYXRpb25BZGRyZXNzID0gZGVzdGluYXRpb25EZXRhaWxzLnBhdGhuYW1lIHx8ICcnO1xuXG4gICAgLy8gYWRkcmVzcyBkb2Vzbid0IGhhdmUgYSBtZW1vIGlkXG4gICAgaWYgKGRlc3RpbmF0aW9uRGV0YWlscy5wYXRobmFtZSA9PT0gYWRkcmVzcykge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYWRkcmVzczogYWRkcmVzcyxcbiAgICAgICAgbWVtb0lkOiB1bmRlZmluZWQsXG4gICAgICB9O1xuICAgIH1cblxuICAgIGlmICghZGVzdGluYXRpb25EZXRhaWxzLnF1ZXJ5KSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZEFkZHJlc3NFcnJvcihgaW52YWxpZCBhZGRyZXNzOiAke2FkZHJlc3N9YCk7XG4gICAgfVxuXG4gICAgY29uc3QgcXVlcnlEZXRhaWxzID0gcXVlcnlzdHJpbmcucGFyc2UoZGVzdGluYXRpb25EZXRhaWxzLnF1ZXJ5KTtcbiAgICBpZiAoIXF1ZXJ5RGV0YWlscy5tZW1vSWQpIHtcbiAgICAgIC8vIGlmIHRoZXJlIGFyZSBtb3JlIHByb3BlcnRpZXMsIHRoZSBxdWVyeSBkZXRhaWxzIG5lZWQgdG8gY29udGFpbiB0aGUgbWVtbyBpZCBwcm9wZXJ0eVxuICAgICAgdGhyb3cgbmV3IEludmFsaWRBZGRyZXNzRXJyb3IoYGludmFsaWQgYWRkcmVzczogJHthZGRyZXNzfWApO1xuICAgIH1cblxuICAgIGlmIChBcnJheS5pc0FycmF5KHF1ZXJ5RGV0YWlscy5tZW1vSWQpKSB7XG4gICAgICB0aHJvdyBuZXcgSW52YWxpZEFkZHJlc3NFcnJvcihcbiAgICAgICAgYG1lbW9JZCBtYXkgb25seSBiZSBnaXZlbiBhdCBtb3N0IG9uY2UsIGJ1dCBmb3VuZCAke3F1ZXJ5RGV0YWlscy5tZW1vSWQubGVuZ3RofSBpbnN0YW5jZXMgaW4gYWRkcmVzcyAke2FkZHJlc3N9YFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAoQXJyYXkuaXNBcnJheShxdWVyeURldGFpbHMubWVtb0lkKSAmJiBxdWVyeURldGFpbHMubWVtb0lkLmxlbmd0aCAhPT0gMSkge1xuICAgICAgLy8gdmFsaWQgYWRkcmVzc2VzIGNhbiBvbmx5IGNvbnRhaW4gb25lIG1lbW8gaWRcbiAgICAgIHRocm93IG5ldyBJbnZhbGlkQWRkcmVzc0Vycm9yKGBpbnZhbGlkIGFkZHJlc3MgJyR7YWRkcmVzc30nLCBtdXN0IGNvbnRhaW4gZXhhY3RseSBvbmUgbWVtb0lkYCk7XG4gICAgfVxuXG4gICAgY29uc3QgW21lbW9JZF0gPSBfLmNhc3RBcnJheShxdWVyeURldGFpbHMubWVtb0lkKSB8fCB1bmRlZmluZWQ7XG4gICAgaWYgKCF0aGlzLmlzVmFsaWRNZW1vSWQobWVtb0lkKSkge1xuICAgICAgdGhyb3cgbmV3IEludmFsaWRNZW1vSWRFcnJvcihgaW52YWxpZCBhZGRyZXNzOiAnJHthZGRyZXNzfScsIG1lbW9JZCBpcyBub3QgdmFsaWRgKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgYWRkcmVzczogZGVzdGluYXRpb25BZGRyZXNzLFxuICAgICAgbWVtb0lkLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIGJvb2xlYW4gaW5kaWNhdGluZyB3aGV0aGVyIGEgbWVtbyBpZCBpcyB2YWxpZFxuICAgKlxuICAgKiBAcGFyYW0gbWVtb0lkIG1lbW8gaWRcbiAgICogQHJldHVybnMgdHJ1ZSBpZiBtZW1vIGlkIGlzIHZhbGlkXG4gICAqL1xuICBpc1ZhbGlkTWVtb0lkKG1lbW9JZDogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHV0aWxzLmlzVmFsaWRNZW1vSWQobWVtb0lkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBIZWxwZXIgbWV0aG9kIHRvIHJldHVybiB0aGUgcmVzcGVjdGl2ZSBjb2luJ3MgYmFzZSB1bml0XG4gICAqL1xuICBnZXREZW5vbWluYXRpb24oKTogc3RyaW5nIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ01ldGhvZCBub3QgaW1wbGVtZW50ZWQnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBIZWxwZXIgbWV0aG9kIHRvIGZldGNoIGdhcyBhbW91bnQgZGV0YWlscyBmb3IgcmVzcGVjdGl2ZSBjb2luXG4gICAqL1xuICBnZXRHYXNBbW91bnREZXRhaWxzKCk6IEdhc0Ftb3VudERldGFpbHMge1xuICAgIHRocm93IG5ldyBFcnJvcignTWV0aG9kIG5vdCBpbXBsZW1lbnRlZCcpO1xuICB9XG5cbiAgLyoqXG4gICAqIEhlbHBlciBtZXRob2QgdG8gZ2V0IGtleSBwYWlyIGZvciBpbmRpdmlkdWFsIGNvaW5cbiAgICogQHBhcmFtIHB1YmxpY0tleVxuICAgKi9cbiAgZ2V0S2V5UGFpcihwdWJsaWNLZXk6IHN0cmluZyk6IENvc21vc0tleVBhaXIge1xuICAgIHRocm93IG5ldyBFcnJvcignTWV0aG9kIG5vdCBpbXBsZW1lbnRlZCcpO1xuICB9XG5cbiAgLyoqIEBpbmhlcml0RG9jICoqL1xuICBhdWRpdERlY3J5cHRlZEtleSh7IG11bHRpU2lnVHlwZSwgcHVibGljS2V5LCBwcnYgfTogQXVkaXREZWNyeXB0ZWRLZXlQYXJhbXMpIHtcbiAgICBpZiAobXVsdGlTaWdUeXBlICE9PSAndHNzJykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdVbnN1cHBvcnRlZCBtdWx0aVNpZ1R5cGUnKTtcbiAgICB9IGVsc2Uge1xuICAgICAgYXVkaXRFY2RzYVByaXZhdGVLZXkocHJ2IGFzIHN0cmluZywgcHVibGljS2V5IGFzIHN0cmluZyk7XG4gICAgfVxuICB9XG59XG4iXX0=
|