@bitgo-beta/sdk-coin-near 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 +784 -0
- package/LICENSE +191 -0
- package/README.md +30 -0
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +22 -0
- package/dist/src/lib/constants.d.ts +16 -0
- package/dist/src/lib/constants.d.ts.map +1 -0
- package/dist/src/lib/constants.js +19 -0
- package/dist/src/lib/contractCallWrapper.d.ts +33 -0
- package/dist/src/lib/contractCallWrapper.d.ts.map +1 -0
- package/dist/src/lib/contractCallWrapper.js +71 -0
- package/dist/src/lib/errors.d.ts +5 -0
- package/dist/src/lib/errors.d.ts.map +1 -0
- package/dist/src/lib/errors.js +12 -0
- package/dist/src/lib/fungibleTokenTransferBuilder.d.ts +64 -0
- package/dist/src/lib/fungibleTokenTransferBuilder.d.ts.map +1 -0
- package/dist/src/lib/fungibleTokenTransferBuilder.js +158 -0
- package/dist/src/lib/iface.d.ts +42 -0
- package/dist/src/lib/iface.d.ts.map +1 -0
- package/dist/src/lib/iface.js +3 -0
- package/dist/src/lib/index.d.ts +13 -0
- package/dist/src/lib/index.d.ts.map +1 -0
- package/dist/src/lib/index.js +59 -0
- package/dist/src/lib/keyPair.d.ts +25 -0
- package/dist/src/lib/keyPair.d.ts.map +1 -0
- package/dist/src/lib/keyPair.js +86 -0
- package/dist/src/lib/stakingActivateBuilder.d.ts +32 -0
- package/dist/src/lib/stakingActivateBuilder.d.ts.map +1 -0
- package/dist/src/lib/stakingActivateBuilder.js +105 -0
- package/dist/src/lib/stakingDeactivateBuilder.d.ts +32 -0
- package/dist/src/lib/stakingDeactivateBuilder.d.ts.map +1 -0
- package/dist/src/lib/stakingDeactivateBuilder.js +104 -0
- package/dist/src/lib/stakingWithdrawBuilder.d.ts +32 -0
- package/dist/src/lib/stakingWithdrawBuilder.d.ts.map +1 -0
- package/dist/src/lib/stakingWithdrawBuilder.js +104 -0
- package/dist/src/lib/storageDepositTransferBuilder.d.ts +36 -0
- package/dist/src/lib/storageDepositTransferBuilder.d.ts.map +1 -0
- package/dist/src/lib/storageDepositTransferBuilder.js +115 -0
- package/dist/src/lib/transaction.d.ts +117 -0
- package/dist/src/lib/transaction.d.ts.map +1 -0
- package/dist/src/lib/transaction.js +613 -0
- package/dist/src/lib/transactionBuilder.d.ts +95 -0
- package/dist/src/lib/transactionBuilder.d.ts.map +1 -0
- package/dist/src/lib/transactionBuilder.js +241 -0
- package/dist/src/lib/transactionBuilderFactory.d.ts +34 -0
- package/dist/src/lib/transactionBuilderFactory.d.ts.map +1 -0
- package/dist/src/lib/transactionBuilderFactory.js +84 -0
- package/dist/src/lib/transferBuilder.d.ts +26 -0
- package/dist/src/lib/transferBuilder.d.ts.map +1 -0
- package/dist/src/lib/transferBuilder.js +87 -0
- package/dist/src/lib/utils.d.ts +71 -0
- package/dist/src/lib/utils.d.ts.map +1 -0
- package/dist/src/lib/utils.js +139 -0
- package/dist/src/lib/walletInitializationBuilder.d.ts +12 -0
- package/dist/src/lib/walletInitializationBuilder.d.ts.map +1 -0
- package/dist/src/lib/walletInitializationBuilder.js +20 -0
- package/dist/src/near.d.ts +217 -0
- package/dist/src/near.d.ts.map +1 -0
- package/dist/src/near.js +853 -0
- package/dist/src/nep141Token.d.ts +20 -0
- package/dist/src/nep141Token.d.ts.map +1 -0
- package/dist/src/nep141Token.js +101 -0
- package/dist/src/register.d.ts +3 -0
- package/dist/src/register.d.ts.map +1 -0
- package/dist/src/register.js +15 -0
- package/dist/src/tnear.d.ts +7 -0
- package/dist/src/tnear.d.ts.map +1 -0
- package/dist/src/tnear.js +11 -0
- package/package.json +63 -0
package/dist/src/near.js
ADDED
|
@@ -0,0 +1,853 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @prettier
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
39
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
40
|
+
};
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.Near = void 0;
|
|
43
|
+
const _ = __importStar(require("lodash"));
|
|
44
|
+
const bignumber_js_1 = __importDefault(require("bignumber.js"));
|
|
45
|
+
const base58 = __importStar(require("bs58"));
|
|
46
|
+
const nearAPI = __importStar(require("near-api-js"));
|
|
47
|
+
const request = __importStar(require("superagent"));
|
|
48
|
+
const sdk_lib_mpc_1 = require("@bitgo-beta/sdk-lib-mpc");
|
|
49
|
+
const sdk_core_1 = require("@bitgo-beta/sdk-core");
|
|
50
|
+
const statics_1 = require("@bitgo-beta/statics");
|
|
51
|
+
const lib_1 = require("./lib");
|
|
52
|
+
const utils_1 = __importDefault(require("./lib/utils"));
|
|
53
|
+
const constants_1 = require("./lib/constants");
|
|
54
|
+
class Near extends sdk_core_1.BaseCoin {
|
|
55
|
+
constructor(bitgo, staticsCoin) {
|
|
56
|
+
super(bitgo);
|
|
57
|
+
this.network = this.bitgo.getEnv() === 'prod' ? 'main' : 'test';
|
|
58
|
+
if (!staticsCoin) {
|
|
59
|
+
throw new Error('missing required constructor parameter staticsCoin');
|
|
60
|
+
}
|
|
61
|
+
this._staticsCoin = staticsCoin;
|
|
62
|
+
}
|
|
63
|
+
static createInstance(bitgo, staticsCoin) {
|
|
64
|
+
return new Near(bitgo, staticsCoin);
|
|
65
|
+
}
|
|
66
|
+
allowsAccountConsolidations() {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Flag indicating if this coin supports TSS wallets.
|
|
71
|
+
* @returns {boolean} True if TSS Wallets can be created for this coin
|
|
72
|
+
*/
|
|
73
|
+
supportsTss() {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
/** inherited doc */
|
|
77
|
+
getDefaultMultisigType() {
|
|
78
|
+
return sdk_core_1.multisigTypes.tss;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* @inheritDoc
|
|
82
|
+
*/
|
|
83
|
+
getTokenEnablementConfig() {
|
|
84
|
+
return {
|
|
85
|
+
requiresTokenEnablement: true,
|
|
86
|
+
supportsMultipleTokenEnablements: false,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
getMPCAlgorithm() {
|
|
90
|
+
return 'eddsa';
|
|
91
|
+
}
|
|
92
|
+
getChain() {
|
|
93
|
+
return this._staticsCoin.name;
|
|
94
|
+
}
|
|
95
|
+
getBaseChain() {
|
|
96
|
+
return this.getChain();
|
|
97
|
+
}
|
|
98
|
+
getFamily() {
|
|
99
|
+
return this._staticsCoin.family;
|
|
100
|
+
}
|
|
101
|
+
getFullName() {
|
|
102
|
+
return this._staticsCoin.fullName;
|
|
103
|
+
}
|
|
104
|
+
getBaseFactor() {
|
|
105
|
+
return Math.pow(10, this._staticsCoin.decimalPlaces);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Flag for sending value of 0
|
|
109
|
+
* @returns {boolean} True if okay to send 0 value, false otherwise
|
|
110
|
+
*/
|
|
111
|
+
valuelessTransferAllowed() {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Generate ed25519 key pair
|
|
116
|
+
*
|
|
117
|
+
* @param seed
|
|
118
|
+
* @returns {Object} object with generated pub, prv
|
|
119
|
+
*/
|
|
120
|
+
generateKeyPair(seed) {
|
|
121
|
+
const keyPair = seed ? new lib_1.KeyPair({ seed }) : new lib_1.KeyPair();
|
|
122
|
+
const keys = keyPair.getKeys();
|
|
123
|
+
if (!keys.prv) {
|
|
124
|
+
throw new Error('Missing prv in key generation.');
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
pub: keys.pub,
|
|
128
|
+
prv: keys.prv,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Return boolean indicating whether input is valid public key for the coin.
|
|
133
|
+
*
|
|
134
|
+
* @param {String} pub the pub to be checked
|
|
135
|
+
* @returns {Boolean} is it valid?
|
|
136
|
+
*/
|
|
137
|
+
isValidPub(pub) {
|
|
138
|
+
return utils_1.default.isValidPublicKey(pub);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Return boolean indicating whether the supplied private key is a valid near private key
|
|
142
|
+
*
|
|
143
|
+
* @param {String} prv the prv to be checked
|
|
144
|
+
* @returns {Boolean} is it valid?
|
|
145
|
+
*/
|
|
146
|
+
isValidPrv(prv) {
|
|
147
|
+
return utils_1.default.isValidPrivateKey(prv);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Return boolean indicating whether input is valid public key for the coin
|
|
151
|
+
*
|
|
152
|
+
* @param {String} address the pub to be checked
|
|
153
|
+
* @returns {Boolean} is it valid?
|
|
154
|
+
*/
|
|
155
|
+
isValidAddress(address) {
|
|
156
|
+
return utils_1.default.isValidAddress(address);
|
|
157
|
+
}
|
|
158
|
+
/** @inheritDoc */
|
|
159
|
+
async signMessage(key, message) {
|
|
160
|
+
const nearKeypair = new lib_1.KeyPair({ prv: key.prv });
|
|
161
|
+
if (Buffer.isBuffer(message)) {
|
|
162
|
+
message = base58.encode(message);
|
|
163
|
+
}
|
|
164
|
+
return Buffer.from(nearKeypair.signMessage(message));
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Explain/parse transaction
|
|
168
|
+
* @param params
|
|
169
|
+
*/
|
|
170
|
+
async explainTransaction(params) {
|
|
171
|
+
const factory = this.getBuilder();
|
|
172
|
+
let rebuiltTransaction;
|
|
173
|
+
const txRaw = params.txPrebuild.txHex;
|
|
174
|
+
try {
|
|
175
|
+
const transactionBuilder = factory.from(txRaw);
|
|
176
|
+
rebuiltTransaction = await transactionBuilder.build();
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
throw new Error('Invalid transaction');
|
|
180
|
+
}
|
|
181
|
+
return rebuiltTransaction.explainTransaction();
|
|
182
|
+
}
|
|
183
|
+
verifySignTransactionParams(params) {
|
|
184
|
+
const prv = params.prv;
|
|
185
|
+
const txHex = params.txPrebuild.txHex;
|
|
186
|
+
if (_.isUndefined(txHex)) {
|
|
187
|
+
throw new Error('missing txPrebuild parameter');
|
|
188
|
+
}
|
|
189
|
+
if (!_.isString(txHex)) {
|
|
190
|
+
throw new Error(`txPrebuild must be an object, got type ${typeof txHex}`);
|
|
191
|
+
}
|
|
192
|
+
if (_.isUndefined(prv)) {
|
|
193
|
+
throw new Error('missing prv parameter to sign transaction');
|
|
194
|
+
}
|
|
195
|
+
if (!_.isString(prv)) {
|
|
196
|
+
throw new Error(`prv must be a string, got type ${typeof prv}`);
|
|
197
|
+
}
|
|
198
|
+
if (!_.has(params.txPrebuild, 'key')) {
|
|
199
|
+
throw new Error('missing public key parameter to sign transaction');
|
|
200
|
+
}
|
|
201
|
+
// if we are receiving addresses do not try to convert them
|
|
202
|
+
const signer = !utils_1.default.isValidAddress(params.txPrebuild.key)
|
|
203
|
+
? new lib_1.KeyPair({ pub: params.txPrebuild.key }).getAddress()
|
|
204
|
+
: params.txPrebuild.key;
|
|
205
|
+
return { txHex, prv, signer };
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Assemble keychain and half-sign prebuilt transaction
|
|
209
|
+
*
|
|
210
|
+
* @param params
|
|
211
|
+
* @param params.txPrebuild {TransactionPrebuild} prebuild object returned by platform
|
|
212
|
+
* @param params.prv {String} user prv
|
|
213
|
+
* @param callback
|
|
214
|
+
* @returns {Bluebird<SignedTransaction>}
|
|
215
|
+
*/
|
|
216
|
+
async signTransaction(params) {
|
|
217
|
+
const factory = this.getBuilder();
|
|
218
|
+
const txBuilder = factory.from(params.txPrebuild.txHex);
|
|
219
|
+
txBuilder.sign({ key: params.prv });
|
|
220
|
+
const transaction = await txBuilder.build();
|
|
221
|
+
if (!transaction) {
|
|
222
|
+
throw new Error('Invalid transaction');
|
|
223
|
+
}
|
|
224
|
+
const serializedTx = transaction.toBroadcastFormat();
|
|
225
|
+
return {
|
|
226
|
+
txHex: serializedTx,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Builds a funds recovery transaction without BitGo
|
|
231
|
+
* @param params
|
|
232
|
+
*/
|
|
233
|
+
async recover(params) {
|
|
234
|
+
if (!params.bitgoKey) {
|
|
235
|
+
throw new Error('missing bitgoKey');
|
|
236
|
+
}
|
|
237
|
+
if (!params.recoveryDestination || !this.isValidAddress(params.recoveryDestination)) {
|
|
238
|
+
throw new Error('invalid recoveryDestination');
|
|
239
|
+
}
|
|
240
|
+
let startIdx = params.startingScanIndex;
|
|
241
|
+
if (startIdx === undefined) {
|
|
242
|
+
startIdx = 0;
|
|
243
|
+
}
|
|
244
|
+
else if (!Number.isInteger(startIdx) || startIdx < 0) {
|
|
245
|
+
throw new Error('Invalid starting index to scan for addresses');
|
|
246
|
+
}
|
|
247
|
+
let numIteration = params.scan;
|
|
248
|
+
if (numIteration === undefined) {
|
|
249
|
+
numIteration = 20;
|
|
250
|
+
}
|
|
251
|
+
else if (!Number.isInteger(numIteration) || numIteration <= 0) {
|
|
252
|
+
throw new Error('Invalid scanning factor');
|
|
253
|
+
}
|
|
254
|
+
const bitgoKey = params.bitgoKey.replace(/\s/g, '');
|
|
255
|
+
const isUnsignedSweep = !params.userKey && !params.backupKey && !params.walletPassphrase;
|
|
256
|
+
const MPC = await sdk_core_1.EDDSAMethods.getInitializedMpcInstance();
|
|
257
|
+
const { storageAmountPerByte, transferCost, receiptConfig } = await this.getProtocolConfig();
|
|
258
|
+
let isStorageDepositEnabled = false;
|
|
259
|
+
if (params.tokenContractAddress) {
|
|
260
|
+
// check if receiver storage deposit is enabled
|
|
261
|
+
isStorageDepositEnabled = await this.checkIfStorageDepositIsEnabled(params.recoveryDestination, params.tokenContractAddress);
|
|
262
|
+
}
|
|
263
|
+
for (let i = startIdx; i < numIteration + startIdx; i++) {
|
|
264
|
+
const currPath = `m/${i}`;
|
|
265
|
+
const accountId = MPC.deriveUnhardened(bitgoKey, currPath).slice(0, 64);
|
|
266
|
+
let availableBalance = new bignumber_js_1.default(0);
|
|
267
|
+
try {
|
|
268
|
+
availableBalance = new bignumber_js_1.default(await this.getAccountBalance(accountId, storageAmountPerByte));
|
|
269
|
+
}
|
|
270
|
+
catch (e) {
|
|
271
|
+
// UNKNOWN_ACCOUNT error indicates that the address has not partake in any transaction so far, so we will
|
|
272
|
+
// treat it as a zero balance address
|
|
273
|
+
if (e.message !== 'UNKNOWN_ACCOUNT') {
|
|
274
|
+
throw e;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (availableBalance.toNumber() <= 0) {
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
const feeReserve = (0, bignumber_js_1.default)(statics_1.Networks[this.network].near.feeReserve);
|
|
281
|
+
const storageReserve = (0, bignumber_js_1.default)(statics_1.Networks[this.network].near.storageReserve);
|
|
282
|
+
// check for possible token recovery, recover the token provided by the user
|
|
283
|
+
if (params.tokenContractAddress) {
|
|
284
|
+
const tokenName = utils_1.default.findTokenNameFromContractAddress(params.tokenContractAddress);
|
|
285
|
+
if (!tokenName) {
|
|
286
|
+
throw new Error(`Token name not found for contract address ${params.tokenContractAddress}. The address may be invalid or unsupported. Please refer to the supported tokens in the BitGo documentation for guidance.`);
|
|
287
|
+
}
|
|
288
|
+
const token = utils_1.default.getTokenInstanceFromTokenName(tokenName);
|
|
289
|
+
if (!token) {
|
|
290
|
+
throw new Error(`Token instance could not be created for token name ${tokenName}. The token may be invalid or unsupported. Please refer to the supported tokens in the BitGo documentation for guidance.`);
|
|
291
|
+
}
|
|
292
|
+
let availableTokenBalance;
|
|
293
|
+
try {
|
|
294
|
+
availableTokenBalance = new bignumber_js_1.default(await this.getAccountFungibleTokenBalance(accountId, params.tokenContractAddress));
|
|
295
|
+
}
|
|
296
|
+
catch (e) {
|
|
297
|
+
throw e;
|
|
298
|
+
}
|
|
299
|
+
if (availableTokenBalance.toNumber() <= 0) {
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
const netAmount = availableBalance
|
|
303
|
+
.minus(utils_1.default.convertGasUnitsToYoctoNear(constants_1.MAX_GAS_LIMIT_FOR_FT_TRANSFER))
|
|
304
|
+
.minus(feeReserve)
|
|
305
|
+
.minus(storageReserve);
|
|
306
|
+
if (netAmount.toNumber() <= 0) {
|
|
307
|
+
throw new Error(`Found address ${i} with non-zero fund but fund is insufficient to support a token recover ` +
|
|
308
|
+
`transaction. Please start the next scan at address index ${i + 1}.`);
|
|
309
|
+
}
|
|
310
|
+
return this.recoverNearToken(params, token, accountId, currPath, i, bitgoKey, isStorageDepositEnabled, availableTokenBalance, isUnsignedSweep);
|
|
311
|
+
}
|
|
312
|
+
// first build the unsigned txn
|
|
313
|
+
const bs58EncodedPublicKey = nearAPI.utils.serialize.base_encode(new Uint8Array(Buffer.from(accountId, 'hex')));
|
|
314
|
+
const { nonce, blockHash } = await this.getAccessKey({ accountId, bs58EncodedPublicKey });
|
|
315
|
+
const gasPrice = await this.getGasPrice(blockHash);
|
|
316
|
+
const gasPriceFirstBlock = new bignumber_js_1.default(gasPrice);
|
|
317
|
+
const gasPriceSecondBlock = gasPriceFirstBlock.multipliedBy(1.05);
|
|
318
|
+
const totalGasRequired = new bignumber_js_1.default(transferCost.sendSir)
|
|
319
|
+
.plus(receiptConfig.sendSir)
|
|
320
|
+
.multipliedBy(gasPriceFirstBlock)
|
|
321
|
+
.plus(new bignumber_js_1.default(transferCost.execution).plus(receiptConfig.execution).multipliedBy(gasPriceSecondBlock));
|
|
322
|
+
// adding some padding to make sure the gas doesn't go below required gas by network
|
|
323
|
+
const totalGasWithPadding = totalGasRequired.multipliedBy(1.5);
|
|
324
|
+
const netAmount = availableBalance.minus(totalGasWithPadding).minus(feeReserve).minus(storageReserve);
|
|
325
|
+
if (netAmount.toNumber() <= 0) {
|
|
326
|
+
throw new Error(`Found address ${i} with non-zero fund but fund is insufficient to support a recover ` +
|
|
327
|
+
`transaction. Please start the next scan at address index ${i + 1}.`);
|
|
328
|
+
}
|
|
329
|
+
const factory = new lib_1.TransactionBuilderFactory(statics_1.coins.get(this.getChain()));
|
|
330
|
+
const txBuilder = factory
|
|
331
|
+
.getTransferBuilder()
|
|
332
|
+
.sender(accountId, accountId)
|
|
333
|
+
.nonce(nonce)
|
|
334
|
+
.receiverId(params.recoveryDestination)
|
|
335
|
+
.recentBlockHash(blockHash)
|
|
336
|
+
.amount(netAmount.toFixed());
|
|
337
|
+
const unsignedTransaction = (await txBuilder.build());
|
|
338
|
+
let serializedTx = unsignedTransaction.toBroadcastFormat();
|
|
339
|
+
if (!isUnsignedSweep) {
|
|
340
|
+
serializedTx = await this.signRecoveryTransaction(txBuilder, params, currPath, accountId);
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
return this.buildUnsignedSweepTransaction(txBuilder, accountId, params.recoveryDestination, bitgoKey, i, currPath, netAmount, totalGasWithPadding);
|
|
344
|
+
}
|
|
345
|
+
return { serializedTx: serializedTx, scanIndex: i };
|
|
346
|
+
}
|
|
347
|
+
throw new Error('Did not find an address with funds to recover');
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Function to handle near token recovery
|
|
351
|
+
* @param {MPCRecoveryOptions} params mpc recovery options input
|
|
352
|
+
* @param {Nep141Token} token the token object
|
|
353
|
+
* @param {String} senderAddress sender address
|
|
354
|
+
* @param {String} derivationPath the derivation path
|
|
355
|
+
* @param {Number} idx current index
|
|
356
|
+
* @param {String} bitgoKey bitgo key
|
|
357
|
+
* @param {Boolean} isStorageDepositEnabled flag indicating whether storage deposit is enabled on the receiver
|
|
358
|
+
* @param {BigNumber} availableTokenBalance currently available token balance on the address
|
|
359
|
+
* @param {Boolean} isUnsignedSweep flag indicating whether it is an unsigned sweep
|
|
360
|
+
* @returns {Promise<MPCTx | MPCSweepTxs>}
|
|
361
|
+
*/
|
|
362
|
+
async recoverNearToken(params, token, senderAddress, derivationPath, idx, bitgoKey, isStorageDepositEnabled, availableTokenBalance, isUnsignedSweep) {
|
|
363
|
+
const factory = new lib_1.TransactionBuilderFactory(token);
|
|
364
|
+
const bs58EncodedPublicKey = nearAPI.utils.serialize.base_encode(new Uint8Array(Buffer.from(senderAddress, 'hex')));
|
|
365
|
+
const { nonce, blockHash } = await this.getAccessKey({ accountId: senderAddress, bs58EncodedPublicKey });
|
|
366
|
+
const txBuilder = factory
|
|
367
|
+
.getFungibleTokenTransferBuilder()
|
|
368
|
+
.sender(senderAddress, senderAddress)
|
|
369
|
+
.nonce(nonce)
|
|
370
|
+
.receiverId(token.contractAddress)
|
|
371
|
+
.recentBlockHash(blockHash)
|
|
372
|
+
.ftReceiverId(params.recoveryDestination)
|
|
373
|
+
.gas(constants_1.MAX_GAS_LIMIT_FOR_FT_TRANSFER)
|
|
374
|
+
.deposit('1')
|
|
375
|
+
.amount(availableTokenBalance.toString());
|
|
376
|
+
if (!isStorageDepositEnabled) {
|
|
377
|
+
txBuilder.addStorageDeposit({
|
|
378
|
+
deposit: BigInt(token.storageDepositAmount),
|
|
379
|
+
gas: BigInt(constants_1.MAX_GAS_LIMIT_FOR_FT_TRANSFER),
|
|
380
|
+
accountId: params.recoveryDestination,
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
if (isUnsignedSweep) {
|
|
384
|
+
return this.buildUnsignedSweepTransaction(txBuilder, senderAddress, params.recoveryDestination, bitgoKey, idx, derivationPath, availableTokenBalance, new bignumber_js_1.default(utils_1.default.convertGasUnitsToYoctoNear(constants_1.MAX_GAS_LIMIT_FOR_FT_TRANSFER)), token);
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
const serializedTx = await this.signRecoveryTransaction(txBuilder, params, derivationPath, senderAddress);
|
|
388
|
+
return { serializedTx: serializedTx, scanIndex: idx };
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Function to build unsigned sweep transaction
|
|
393
|
+
* @param {TransactionBuilder} txBuilder the near transaction builder
|
|
394
|
+
* @param {String} senderAddress sender address
|
|
395
|
+
* @param {String} receiverAddress the receiver address
|
|
396
|
+
* @param {String} bitgoKey bitgo key
|
|
397
|
+
* @param {Number} index current index
|
|
398
|
+
* @param {String} derivationPath the derivation path
|
|
399
|
+
* @param {BigNumber} netAmount net amount to be recovered
|
|
400
|
+
* @param {BigNumber} netGas net gas required
|
|
401
|
+
* @param {Nep141Token} token optional nep141 token instance
|
|
402
|
+
* @returns {Promise<MPCSweepTxs>}
|
|
403
|
+
*/
|
|
404
|
+
async buildUnsignedSweepTransaction(txBuilder, senderAddress, receiverAddress, bitgoKey, index, derivationPath, netAmount, netGas, token) {
|
|
405
|
+
const isTokenTransaction = !!token;
|
|
406
|
+
const unsignedTransaction = (await txBuilder.build());
|
|
407
|
+
const serializedTx = unsignedTransaction.toBroadcastFormat();
|
|
408
|
+
const walletCoin = isTokenTransaction ? token.name : this.getChain();
|
|
409
|
+
const inputs = [
|
|
410
|
+
{
|
|
411
|
+
address: senderAddress,
|
|
412
|
+
valueString: netAmount.toString(),
|
|
413
|
+
value: netAmount.toNumber(),
|
|
414
|
+
},
|
|
415
|
+
];
|
|
416
|
+
const outputs = [
|
|
417
|
+
{
|
|
418
|
+
address: receiverAddress,
|
|
419
|
+
valueString: netAmount.toString(),
|
|
420
|
+
coinName: walletCoin,
|
|
421
|
+
},
|
|
422
|
+
];
|
|
423
|
+
const spendAmount = netAmount.toString();
|
|
424
|
+
const parsedTx = { inputs: inputs, outputs: outputs, spendAmount: spendAmount, type: '' };
|
|
425
|
+
const feeInfo = { fee: netGas.toNumber(), feeString: netGas.toFixed() }; // Include gas fees
|
|
426
|
+
const transaction = {
|
|
427
|
+
serializedTx: serializedTx, // Serialized unsigned transaction
|
|
428
|
+
scanIndex: index, // Current index in the scan
|
|
429
|
+
coin: walletCoin,
|
|
430
|
+
signableHex: unsignedTransaction.signablePayload.toString('hex'), // Hex payload for signing
|
|
431
|
+
derivationPath: derivationPath, // Derivation path for the account
|
|
432
|
+
parsedTx: parsedTx,
|
|
433
|
+
feeInfo: feeInfo,
|
|
434
|
+
coinSpecific: { commonKeychain: bitgoKey }, // Include block hash for NEAR
|
|
435
|
+
};
|
|
436
|
+
const transactions = [{ unsignedTx: transaction, signatureShares: [] }];
|
|
437
|
+
const txRequest = {
|
|
438
|
+
transactions: transactions,
|
|
439
|
+
walletCoin: walletCoin,
|
|
440
|
+
};
|
|
441
|
+
return { txRequests: [txRequest] };
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Function to sign the recovery transaction
|
|
445
|
+
* @param {TransactionBuilder} txBuilder the near transaction builder
|
|
446
|
+
* @param {MPCRecoveryOptions} params mpc recovery options input
|
|
447
|
+
* @param {String} derivationPath the derivation path
|
|
448
|
+
* @param {String} senderAddress the sender address
|
|
449
|
+
* @returns {Promise<String>}
|
|
450
|
+
*/
|
|
451
|
+
async signRecoveryTransaction(txBuilder, params, derivationPath, senderAddress) {
|
|
452
|
+
const unsignedTransaction = (await txBuilder.build());
|
|
453
|
+
// Sign the txn
|
|
454
|
+
/* ***************** START **************************************/
|
|
455
|
+
// TODO(BG-51092): This looks like a common part which can be extracted out too
|
|
456
|
+
if (!params.userKey) {
|
|
457
|
+
throw new Error('missing userKey');
|
|
458
|
+
}
|
|
459
|
+
if (!params.backupKey) {
|
|
460
|
+
throw new Error('missing backupKey');
|
|
461
|
+
}
|
|
462
|
+
if (!params.walletPassphrase) {
|
|
463
|
+
throw new Error('missing wallet passphrase');
|
|
464
|
+
}
|
|
465
|
+
// Clean up whitespace from entered values
|
|
466
|
+
const userKey = params.userKey.replace(/\s/g, '');
|
|
467
|
+
const backupKey = params.backupKey.replace(/\s/g, '');
|
|
468
|
+
// Decrypt private keys from KeyCard values
|
|
469
|
+
let userPrv;
|
|
470
|
+
try {
|
|
471
|
+
userPrv = this.bitgo.decrypt({
|
|
472
|
+
input: userKey,
|
|
473
|
+
password: params.walletPassphrase,
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
catch (e) {
|
|
477
|
+
throw new Error(`Error decrypting user keychain: ${e.message}`);
|
|
478
|
+
}
|
|
479
|
+
/** TODO BG-52419 Implement Codec for parsing */
|
|
480
|
+
const userSigningMaterial = JSON.parse(userPrv);
|
|
481
|
+
let backupPrv;
|
|
482
|
+
try {
|
|
483
|
+
backupPrv = this.bitgo.decrypt({
|
|
484
|
+
input: backupKey,
|
|
485
|
+
password: params.walletPassphrase,
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
catch (e) {
|
|
489
|
+
throw new Error(`Error decrypting backup keychain: ${e.message}`);
|
|
490
|
+
}
|
|
491
|
+
const backupSigningMaterial = JSON.parse(backupPrv);
|
|
492
|
+
/* ********************** END ***********************************/
|
|
493
|
+
// add signature
|
|
494
|
+
const signatureHex = await sdk_core_1.EDDSAMethods.getTSSSignature(userSigningMaterial, backupSigningMaterial, derivationPath, unsignedTransaction);
|
|
495
|
+
const publicKeyObj = { pub: senderAddress };
|
|
496
|
+
txBuilder.addSignature(publicKeyObj, signatureHex);
|
|
497
|
+
const completedTransaction = await txBuilder.build();
|
|
498
|
+
return completedTransaction.toBroadcastFormat();
|
|
499
|
+
}
|
|
500
|
+
async createBroadcastableSweepTransaction(params) {
|
|
501
|
+
const req = params.signatureShares;
|
|
502
|
+
const broadcastableTransactions = [];
|
|
503
|
+
let lastScanIndex = 0;
|
|
504
|
+
for (let i = 0; i < req.length; i++) {
|
|
505
|
+
const MPC = await sdk_core_1.EDDSAMethods.getInitializedMpcInstance();
|
|
506
|
+
const transaction = req[i].txRequest.transactions[0].unsignedTx;
|
|
507
|
+
// Validate signature shares
|
|
508
|
+
if (!req[i].ovc || !req[i].ovc[0].eddsaSignature) {
|
|
509
|
+
throw new Error('Missing signature(s)');
|
|
510
|
+
}
|
|
511
|
+
const signature = req[i].ovc[0].eddsaSignature;
|
|
512
|
+
// Validate signable hex
|
|
513
|
+
if (!transaction.signableHex) {
|
|
514
|
+
throw new Error('Missing signable hex');
|
|
515
|
+
}
|
|
516
|
+
const messageBuffer = Buffer.from(transaction.signableHex, 'hex');
|
|
517
|
+
const result = MPC.verify(messageBuffer, signature);
|
|
518
|
+
if (!result) {
|
|
519
|
+
throw new Error('Invalid signature');
|
|
520
|
+
}
|
|
521
|
+
// Prepare the signature in hex format
|
|
522
|
+
const signatureHex = Buffer.concat([Buffer.from(signature.R, 'hex'), Buffer.from(signature.sigma, 'hex')]);
|
|
523
|
+
// Validate transaction-specific fields
|
|
524
|
+
if (!transaction.coinSpecific?.commonKeychain) {
|
|
525
|
+
throw new Error('Missing common keychain');
|
|
526
|
+
}
|
|
527
|
+
const commonKeychain = transaction.coinSpecific.commonKeychain;
|
|
528
|
+
if (!transaction.derivationPath) {
|
|
529
|
+
throw new Error('Missing derivation path');
|
|
530
|
+
}
|
|
531
|
+
const derivationPath = transaction.derivationPath;
|
|
532
|
+
// Derive account ID and sender address
|
|
533
|
+
const accountId = MPC.deriveUnhardened(commonKeychain, derivationPath).slice(0, 64);
|
|
534
|
+
const txnBuilder = this.getBuilder().from(transaction.serializedTx);
|
|
535
|
+
// Add the signature
|
|
536
|
+
const nearKeyPair = new lib_1.KeyPair({ pub: accountId });
|
|
537
|
+
txnBuilder.addSignature({ pub: nearKeyPair.getKeys().pub }, signatureHex);
|
|
538
|
+
// Finalize and serialize the transaction
|
|
539
|
+
const signedTransaction = await txnBuilder.build();
|
|
540
|
+
const serializedTx = signedTransaction.toBroadcastFormat();
|
|
541
|
+
// Add the signed transaction to the list
|
|
542
|
+
broadcastableTransactions.push({
|
|
543
|
+
serializedTx: serializedTx,
|
|
544
|
+
scanIndex: transaction.scanIndex,
|
|
545
|
+
});
|
|
546
|
+
// Update the last scan index if applicable
|
|
547
|
+
if (i === req.length - 1 && transaction.coinSpecific.lastScanIndex) {
|
|
548
|
+
lastScanIndex = transaction.coinSpecific.lastScanIndex;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
// Return the broadcastable transactions and the last scan index
|
|
552
|
+
return { transactions: broadcastableTransactions, lastScanIndex };
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Make a request to one of the public EOS nodes available
|
|
556
|
+
* @param params.payload
|
|
557
|
+
*/
|
|
558
|
+
async getDataFromNode(params) {
|
|
559
|
+
const nodeUrls = this.getPublicNodeUrls();
|
|
560
|
+
for (const nodeUrl of nodeUrls) {
|
|
561
|
+
try {
|
|
562
|
+
return await request.post(nodeUrl).send(params.payload);
|
|
563
|
+
}
|
|
564
|
+
catch (e) {
|
|
565
|
+
console.debug(e);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
throw new Error(`Unable to call endpoint: '/' from nodes: ${_.join(nodeUrls, ', ')}`);
|
|
569
|
+
}
|
|
570
|
+
async getAccessKey({ accountId, bs58EncodedPublicKey, }) {
|
|
571
|
+
const response = await this.getDataFromNode({
|
|
572
|
+
payload: {
|
|
573
|
+
jsonrpc: '2.0',
|
|
574
|
+
id: 'dontcare',
|
|
575
|
+
method: 'query',
|
|
576
|
+
params: {
|
|
577
|
+
request_type: 'view_access_key',
|
|
578
|
+
finality: 'final',
|
|
579
|
+
account_id: accountId,
|
|
580
|
+
public_key: bs58EncodedPublicKey,
|
|
581
|
+
},
|
|
582
|
+
},
|
|
583
|
+
});
|
|
584
|
+
if (response.status !== 200) {
|
|
585
|
+
throw new Error('Account not found');
|
|
586
|
+
}
|
|
587
|
+
const accessKey = response.body.result;
|
|
588
|
+
return { nonce: accessKey.nonce + 1, blockHash: accessKey.block_hash };
|
|
589
|
+
}
|
|
590
|
+
async getAccountBalance(accountId, storageAmountPerByte) {
|
|
591
|
+
const response = await this.getDataFromNode({
|
|
592
|
+
payload: {
|
|
593
|
+
jsonrpc: '2.0',
|
|
594
|
+
id: 'dontcare',
|
|
595
|
+
method: 'query',
|
|
596
|
+
params: {
|
|
597
|
+
request_type: 'view_account',
|
|
598
|
+
finality: 'final',
|
|
599
|
+
account_id: accountId,
|
|
600
|
+
},
|
|
601
|
+
},
|
|
602
|
+
});
|
|
603
|
+
if (response.status !== 200) {
|
|
604
|
+
throw new Error('Failed to query account information');
|
|
605
|
+
}
|
|
606
|
+
const errorCause = response.body.error?.cause.name;
|
|
607
|
+
if (errorCause !== undefined) {
|
|
608
|
+
throw new Error(errorCause);
|
|
609
|
+
}
|
|
610
|
+
const account = response.body.result;
|
|
611
|
+
const costPerByte = new bignumber_js_1.default(storageAmountPerByte);
|
|
612
|
+
const stateStaked = new bignumber_js_1.default(account.storage_usage).multipliedBy(costPerByte);
|
|
613
|
+
const staked = new bignumber_js_1.default(account.locked);
|
|
614
|
+
const totalBalance = new bignumber_js_1.default(account.amount).plus(staked);
|
|
615
|
+
const availableBalance = totalBalance.minus(bignumber_js_1.default.max(staked, stateStaked));
|
|
616
|
+
return availableBalance.toString();
|
|
617
|
+
}
|
|
618
|
+
/**
|
|
619
|
+
* Function to get the fungible token balance for an account
|
|
620
|
+
* @param {String} accountId account for which the ft balance to be fetched
|
|
621
|
+
* @param tokenContractAddress the token contract address
|
|
622
|
+
* @returns {Promise<String>}
|
|
623
|
+
*/
|
|
624
|
+
async getAccountFungibleTokenBalance(accountId, tokenContractAddress) {
|
|
625
|
+
const base64Args = utils_1.default.convertToBase64({ account_id: accountId });
|
|
626
|
+
const response = await this.getDataFromNode({
|
|
627
|
+
payload: {
|
|
628
|
+
jsonrpc: '2.0',
|
|
629
|
+
id: 'dontcare',
|
|
630
|
+
method: 'query',
|
|
631
|
+
params: {
|
|
632
|
+
request_type: 'call_function',
|
|
633
|
+
finality: 'final',
|
|
634
|
+
account_id: tokenContractAddress,
|
|
635
|
+
method_name: 'ft_balance_of',
|
|
636
|
+
args_base64: base64Args,
|
|
637
|
+
},
|
|
638
|
+
},
|
|
639
|
+
});
|
|
640
|
+
if (response.status !== 200) {
|
|
641
|
+
throw new Error('Failed to fetch ft balance of the account');
|
|
642
|
+
}
|
|
643
|
+
const errorCause = response.body.error?.cause?.name;
|
|
644
|
+
if (errorCause !== undefined) {
|
|
645
|
+
throw new Error(errorCause);
|
|
646
|
+
}
|
|
647
|
+
const resultUint8Array = new Uint8Array(response.body.result.result);
|
|
648
|
+
const raw = new TextDecoder().decode(resultUint8Array);
|
|
649
|
+
return JSON.parse(raw);
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Function to check if storage deposit is enabled on an address for a token
|
|
653
|
+
* @param {String} accountId account for which the storage balance to be fetched
|
|
654
|
+
* @param tokenContractAddress the token contract address
|
|
655
|
+
* @returns {Promise<Boolean>} true if we find the storage balance, false if response is null
|
|
656
|
+
*/
|
|
657
|
+
async checkIfStorageDepositIsEnabled(accountId, tokenContractAddress) {
|
|
658
|
+
const base64Args = utils_1.default.convertToBase64({ account_id: accountId });
|
|
659
|
+
const response = await this.getDataFromNode({
|
|
660
|
+
payload: {
|
|
661
|
+
jsonrpc: '2.0',
|
|
662
|
+
id: 'dontcare',
|
|
663
|
+
method: 'query',
|
|
664
|
+
params: {
|
|
665
|
+
request_type: 'call_function',
|
|
666
|
+
finality: 'final',
|
|
667
|
+
account_id: tokenContractAddress,
|
|
668
|
+
method_name: 'storage_balance_of',
|
|
669
|
+
args_base64: base64Args,
|
|
670
|
+
},
|
|
671
|
+
},
|
|
672
|
+
});
|
|
673
|
+
if (response.status !== 200) {
|
|
674
|
+
throw new Error('Failed to fetch storage deposit of the account');
|
|
675
|
+
}
|
|
676
|
+
const errorCause = response.body.error?.cause?.name;
|
|
677
|
+
if (errorCause !== undefined) {
|
|
678
|
+
throw new Error(errorCause);
|
|
679
|
+
}
|
|
680
|
+
const resultUint8Array = new Uint8Array(response.body.result.result);
|
|
681
|
+
const raw = new TextDecoder().decode(resultUint8Array);
|
|
682
|
+
const decoded = JSON.parse(raw);
|
|
683
|
+
return decoded !== null;
|
|
684
|
+
}
|
|
685
|
+
async getProtocolConfig() {
|
|
686
|
+
const response = await this.getDataFromNode({
|
|
687
|
+
payload: {
|
|
688
|
+
jsonrpc: '2.0',
|
|
689
|
+
id: 'dontcare',
|
|
690
|
+
method: 'EXPERIMENTAL_protocol_config',
|
|
691
|
+
params: {
|
|
692
|
+
finality: 'final',
|
|
693
|
+
},
|
|
694
|
+
},
|
|
695
|
+
});
|
|
696
|
+
if (response.status !== 200) {
|
|
697
|
+
throw new Error('Account not found');
|
|
698
|
+
}
|
|
699
|
+
const config = response.body.result;
|
|
700
|
+
const storageAmountPerByte = config.runtime_config.storage_amount_per_byte;
|
|
701
|
+
const transferCostFromNetwork = config.runtime_config.transaction_costs.action_creation_config.transfer_cost;
|
|
702
|
+
const transferCost = {
|
|
703
|
+
sendSir: transferCostFromNetwork.send_sir,
|
|
704
|
+
sendNotSir: transferCostFromNetwork.send_not_sir,
|
|
705
|
+
execution: transferCostFromNetwork.execution,
|
|
706
|
+
};
|
|
707
|
+
const receiptConfigFromNetwork = config.runtime_config.transaction_costs.action_receipt_creation_config;
|
|
708
|
+
const receiptConfig = {
|
|
709
|
+
sendSir: receiptConfigFromNetwork.send_sir,
|
|
710
|
+
sendNotSir: receiptConfigFromNetwork.send_not_sir,
|
|
711
|
+
execution: receiptConfigFromNetwork.execution,
|
|
712
|
+
};
|
|
713
|
+
return { storageAmountPerByte, transferCost, receiptConfig };
|
|
714
|
+
}
|
|
715
|
+
async getGasPrice(blockHash) {
|
|
716
|
+
const response = await this.getDataFromNode({
|
|
717
|
+
payload: {
|
|
718
|
+
jsonrpc: '2.0',
|
|
719
|
+
id: 'dontcare',
|
|
720
|
+
method: 'gas_price',
|
|
721
|
+
params: [blockHash],
|
|
722
|
+
},
|
|
723
|
+
});
|
|
724
|
+
if (response.status !== 200) {
|
|
725
|
+
throw new Error('Account not found');
|
|
726
|
+
}
|
|
727
|
+
return response.body.result.gas_price;
|
|
728
|
+
}
|
|
729
|
+
getPublicNodeUrls() {
|
|
730
|
+
return sdk_core_1.Environments[this.bitgo.getEnv()].nearNodeUrls;
|
|
731
|
+
}
|
|
732
|
+
async parseTransaction(params) {
|
|
733
|
+
const transactionExplanation = await this.explainTransaction({
|
|
734
|
+
txPrebuild: params.txPrebuild,
|
|
735
|
+
publicKey: params.publicKey,
|
|
736
|
+
feeInfo: params.feeInfo,
|
|
737
|
+
});
|
|
738
|
+
if (!transactionExplanation) {
|
|
739
|
+
throw new Error('Invalid transaction');
|
|
740
|
+
}
|
|
741
|
+
const nearTransaction = transactionExplanation;
|
|
742
|
+
if (nearTransaction.outputs.length <= 0) {
|
|
743
|
+
return {
|
|
744
|
+
inputs: [],
|
|
745
|
+
outputs: [],
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
const senderAddress = nearTransaction.outputs[0].address;
|
|
749
|
+
const feeAmount = new bignumber_js_1.default(nearTransaction.fee.fee === '' ? '0' : nearTransaction.fee.fee);
|
|
750
|
+
// assume 1 sender, who is also the fee payer
|
|
751
|
+
const inputs = [
|
|
752
|
+
{
|
|
753
|
+
address: senderAddress,
|
|
754
|
+
amount: new bignumber_js_1.default(nearTransaction.outputAmount).plus(feeAmount).toFixed(),
|
|
755
|
+
},
|
|
756
|
+
];
|
|
757
|
+
const outputs = nearTransaction.outputs.map((output) => {
|
|
758
|
+
return {
|
|
759
|
+
address: output.address,
|
|
760
|
+
amount: new bignumber_js_1.default(output.amount).toFixed(),
|
|
761
|
+
};
|
|
762
|
+
});
|
|
763
|
+
return {
|
|
764
|
+
inputs,
|
|
765
|
+
outputs,
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
async isWalletAddress(params) {
|
|
769
|
+
throw new sdk_core_1.MethodNotImplementedError();
|
|
770
|
+
}
|
|
771
|
+
async verifyTransaction(params) {
|
|
772
|
+
let totalAmount = new bignumber_js_1.default(0);
|
|
773
|
+
const coinConfig = statics_1.coins.get(this.getChain());
|
|
774
|
+
const { txPrebuild: txPrebuild, txParams: txParams } = params;
|
|
775
|
+
const transaction = new lib_1.Transaction(coinConfig);
|
|
776
|
+
const rawTx = txPrebuild.txHex;
|
|
777
|
+
if (!rawTx) {
|
|
778
|
+
throw new Error('missing required tx prebuild property txHex');
|
|
779
|
+
}
|
|
780
|
+
transaction.fromRawTransaction(rawTx);
|
|
781
|
+
const explainedTx = transaction.explainTransaction();
|
|
782
|
+
// users do not input recipients for consolidation requests as they are generated by the server
|
|
783
|
+
if (txParams.recipients !== undefined) {
|
|
784
|
+
if (txParams.type === 'enabletoken') {
|
|
785
|
+
const tokenName = explainedTx.outputs[0].tokenName;
|
|
786
|
+
if (tokenName) {
|
|
787
|
+
const nepToken = utils_1.default.getTokenInstanceFromTokenName(tokenName);
|
|
788
|
+
if (nepToken) {
|
|
789
|
+
explainedTx.outputs.forEach((output) => {
|
|
790
|
+
if (output.amount !== nepToken.storageDepositAmount) {
|
|
791
|
+
throw new Error('Storage deposit amount not matching!');
|
|
792
|
+
}
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
const filteredRecipients = txParams.recipients?.map((recipient) => {
|
|
798
|
+
if (txParams.type !== 'enabletoken') {
|
|
799
|
+
return _.pick(recipient, ['address', 'amount']);
|
|
800
|
+
}
|
|
801
|
+
else {
|
|
802
|
+
return _.pick(recipient, ['address', 'tokenName']);
|
|
803
|
+
}
|
|
804
|
+
});
|
|
805
|
+
const filteredOutputs = explainedTx.outputs.map((output) => {
|
|
806
|
+
if (txParams.type !== 'enabletoken') {
|
|
807
|
+
return _.pick(output, ['address', 'amount']);
|
|
808
|
+
}
|
|
809
|
+
else {
|
|
810
|
+
return _.pick(output, ['address', 'tokenName']);
|
|
811
|
+
}
|
|
812
|
+
});
|
|
813
|
+
if (!_.isEqual(filteredOutputs, filteredRecipients)) {
|
|
814
|
+
throw new Error('Tx outputs does not match with expected txParams recipients');
|
|
815
|
+
}
|
|
816
|
+
for (const recipients of txParams.recipients) {
|
|
817
|
+
totalAmount = txParams.type !== 'enabletoken' ? totalAmount.plus(recipients.amount) : (0, bignumber_js_1.default)(0);
|
|
818
|
+
}
|
|
819
|
+
if (!totalAmount.isEqualTo(explainedTx.outputAmount) && txParams.type !== 'enabletoken') {
|
|
820
|
+
throw new Error('Tx total amount does not match with expected total amount field');
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
if (params.verification?.consolidationToBaseAddress) {
|
|
824
|
+
await this.verifyConsolidationToBaseAddress(params, explainedTx);
|
|
825
|
+
}
|
|
826
|
+
return true;
|
|
827
|
+
}
|
|
828
|
+
getBuilder() {
|
|
829
|
+
return new lib_1.TransactionBuilderFactory(statics_1.coins.get(this.getBaseChain()));
|
|
830
|
+
}
|
|
831
|
+
/** @inheritDoc */
|
|
832
|
+
auditDecryptedKey({ prv, publicKey, multiSigType }) {
|
|
833
|
+
if (multiSigType !== 'tss') {
|
|
834
|
+
throw new Error('Unsupported multiSigType');
|
|
835
|
+
}
|
|
836
|
+
(0, sdk_lib_mpc_1.auditEddsaPrivateKey)(prv, publicKey ?? '');
|
|
837
|
+
}
|
|
838
|
+
async verifyConsolidationToBaseAddress(params, explainedTx) {
|
|
839
|
+
const baseAddresses = await params.wallet.addresses({ sort: -1, limit: 1 });
|
|
840
|
+
if (!baseAddresses || baseAddresses.length === 0) {
|
|
841
|
+
throw new Error('No base address found on wallet');
|
|
842
|
+
}
|
|
843
|
+
const baseAddress = baseAddresses[0];
|
|
844
|
+
for (const output of explainedTx.outputs) {
|
|
845
|
+
if (output.address !== baseAddress.address) {
|
|
846
|
+
throw new Error('tx outputs does not match with expected address');
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
exports.Near = Near;
|
|
852
|
+
Near.initialized = false;
|
|
853
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmVhci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9uZWFyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7R0FFRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRUgsMENBQTRCO0FBQzVCLGdFQUFxQztBQUNyQyw2Q0FBK0I7QUFDL0IscURBQXVDO0FBQ3ZDLG9EQUFzQztBQUV0Qyx5REFBK0Q7QUFDL0QsbURBK0I4QjtBQUM5QixpREFBNEc7QUFFNUcsK0JBQTJHO0FBQzNHLHdEQUFvQztBQUNwQywrQ0FBZ0U7QUFzRWhFLE1BQWEsSUFBSyxTQUFRLG1CQUFRO0lBR2hDLFlBQVksS0FBZ0IsRUFBRSxXQUF1QztRQUNuRSxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7UUFVTCxZQUFPLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsS0FBSyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDO1FBVG5FLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUNqQixNQUFNLElBQUksS0FBSyxDQUFDLG9EQUFvRCxDQUFDLENBQUM7UUFDeEUsQ0FBQztRQUVELElBQUksQ0FBQyxZQUFZLEdBQUcsV0FBVyxDQUFDO0lBQ2xDLENBQUM7SUFNRCxNQUFNLENBQUMsY0FBYyxDQUFDLEtBQWdCLEVBQUUsV0FBdUM7UUFDN0UsT0FBTyxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFDdEMsQ0FBQztJQUVELDJCQUEyQjtRQUN6QixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7O09BR0c7SUFDSCxXQUFXO1FBQ1QsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQsb0JBQW9CO0lBQ3BCLHNCQUFzQjtRQUNwQixPQUFPLHdCQUFhLENBQUMsR0FBRyxDQUFDO0lBQzNCLENBQUM7SUFFRDs7T0FFRztJQUNILHdCQUF3QjtRQUN0QixPQUFPO1lBQ0wsdUJBQXVCLEVBQUUsSUFBSTtZQUM3QixnQ0FBZ0MsRUFBRSxLQUFLO1NBQ3hDLENBQUM7SUFDSixDQUFDO0lBRUQsZUFBZTtRQUNiLE9BQU8sT0FBTyxDQUFDO0lBQ2pCLENBQUM7SUFFRCxRQUFRO1FBQ04sT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQztJQUNoQyxDQUFDO0lBRUQsWUFBWTtRQUNWLE9BQU8sSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQ3pCLENBQUM7SUFFRCxTQUFTO1FBQ1AsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQztJQUNsQyxDQUFDO0lBRUQsV0FBVztRQUNULE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQyxRQUFRLENBQUM7SUFDcEMsQ0FBQztJQUVELGFBQWE7UUFDWCxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLElBQUksQ0FBQyxZQUFZLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDdkQsQ0FBQztJQUVEOzs7T0FHRztJQUNILHdCQUF3QjtRQUN0QixPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILGVBQWUsQ0FBQyxJQUFhO1FBQzNCLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxhQUFXLENBQUMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLGFBQVcsRUFBRSxDQUFDO1FBQ3JFLE1BQU0sSUFBSSxHQUFHLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUMvQixJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ2QsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDO1FBQ3BELENBQUM7UUFDRCxPQUFPO1lBQ0wsR0FBRyxFQUFFLElBQUksQ0FBQyxHQUFHO1lBQ2IsR0FBRyxFQUFFLElBQUksQ0FBQyxHQUFHO1NBQ2QsQ0FBQztJQUNKLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILFVBQVUsQ0FBQyxHQUFXO1FBQ3BCLE9BQU8sZUFBUyxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ3pDLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILFVBQVUsQ0FBQyxHQUFXO1FBQ3BCLE9BQU8sZUFBUyxDQUFDLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILGNBQWMsQ0FBQyxPQUFlO1FBQzVCLE9BQU8sZUFBUyxDQUFDLGNBQWMsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUMzQyxDQUFDO0lBRUQsa0JBQWtCO0lBQ2xCLEtBQUssQ0FBQyxXQUFXLENBQUMsR0FBWSxFQUFFLE9BQXdCO1FBQ3RELE1BQU0sV0FBVyxHQUFHLElBQUksYUFBVyxDQUFDLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBQ3RELElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQzdCLE9BQU8sR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ25DLENBQUM7UUFFRCxPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQ3ZELENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsa0JBQWtCLENBQUMsTUFBaUM7UUFDeEQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ2xDLElBQUksa0JBQW1DLENBQUM7UUFDeEMsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUM7UUFFdEMsSUFBSSxDQUFDO1lBQ0gsTUFBTSxrQkFBa0IsR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQy9DLGtCQUFrQixHQUFHLE1BQU0sa0JBQWtCLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDeEQsQ0FBQztRQUFDLE1BQU0sQ0FBQztZQUNQLE1BQU0sSUFBSSxLQUFLLENBQUMscUJBQXFCLENBQUMsQ0FBQztRQUN6QyxDQUFDO1FBRUQsT0FBTyxrQkFBa0IsQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO0lBQ2pELENBQUM7SUFFRCwyQkFBMkIsQ0FBQyxNQUE4QjtRQUN4RCxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDO1FBRXZCLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDO1FBRXRDLElBQUksQ0FBQyxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3pCLE1BQU0sSUFBSSxLQUFLLENBQUMsOEJBQThCLENBQUMsQ0FBQztRQUNsRCxDQUFDO1FBRUQsSUFBSSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUN2QixNQUFNLElBQUksS0FBSyxDQUFDLDBDQUEwQyxPQUFPLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDNUUsQ0FBQztRQUVELElBQUksQ0FBQyxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3ZCLE1BQU0sSUFBSSxLQUFLLENBQUMsMkNBQTJDLENBQUMsQ0FBQztRQUMvRCxDQUFDO1FBRUQsSUFBSSxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUNyQixNQUFNLElBQUksS0FBSyxDQUFDLGtDQUFrQyxPQUFPLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDbEUsQ0FBQztRQUVELElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUUsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNyQyxNQUFNLElBQUksS0FBSyxDQUFDLGtEQUFrRCxDQUFDLENBQUM7UUFDdEUsQ0FBQztRQUVELDJEQUEyRDtRQUMzRCxNQUFNLE1BQU0sR0FBRyxDQUFDLGVBQVMsQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUM7WUFDN0QsQ0FBQyxDQUFDLElBQUksYUFBVyxDQUFDLEVBQUUsR0FBRyxFQUFFLE1BQU0sQ0FBQyxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxVQUFVLEVBQUU7WUFDOUQsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDO1FBQzFCLE9BQU8sRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxDQUFDO0lBQ2hDLENBQUM7SUFFRDs7Ozs7Ozs7T0FRRztJQUNILEtBQUssQ0FBQyxlQUFlLENBQUMsTUFBOEI7UUFDbEQsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ2xDLE1BQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN4RCxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsR0FBRyxFQUFFLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBQ3BDLE1BQU0sV0FBVyxHQUFvQixNQUFNLFNBQVMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUU3RCxJQUFJLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDakIsTUFBTSxJQUFJLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO1FBQ3pDLENBQUM7UUFFRCxNQUFNLFlBQVksR0FBSSxXQUErQixDQUFDLGlCQUFpQixFQUFFLENBQUM7UUFFMUUsT0FBTztZQUNMLEtBQUssRUFBRSxZQUFZO1NBQ2IsQ0FBQztJQUNYLENBQUM7SUFFRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQTBCO1FBQ3RDLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDckIsTUFBTSxJQUFJLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1FBQ3RDLENBQUM7UUFDRCxJQUFJLENBQUMsTUFBTSxDQUFDLG1CQUFtQixJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxNQUFNLENBQUMsbUJBQW1CLENBQUMsRUFBRSxDQUFDO1lBQ3BGLE1BQU0sSUFBSSxLQUFLLENBQUMsNkJBQTZCLENBQUMsQ0FBQztRQUNqRCxDQUFDO1FBQ0QsSUFBSSxRQUFRLEdBQUcsTUFBTSxDQUFDLGlCQUFpQixDQUFDO1FBQ3hDLElBQUksUUFBUSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQzNCLFFBQVEsR0FBRyxDQUFDLENBQUM7UUFDZixDQUFDO2FBQU0sSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLElBQUksUUFBUSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3ZELE1BQU0sSUFBSSxLQUFLLENBQUMsOENBQThDLENBQUMsQ0FBQztRQUNsRSxDQUFDO1FBQ0QsSUFBSSxZQUFZLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQztRQUMvQixJQUFJLFlBQVksS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUMvQixZQUFZLEdBQUcsRUFBRSxDQUFDO1FBQ3BCLENBQUM7YUFBTSxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxZQUFZLENBQUMsSUFBSSxZQUFZLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDaEUsTUFBTSxJQUFJLEtBQUssQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO1FBQzdDLENBQUM7UUFDRCxNQUFNLFFBQVEsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDcEQsTUFBTSxlQUFlLEdBQUcsQ0FBQyxNQUFNLENBQUMsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQztRQUN6RixNQUFNLEdBQUcsR0FBRyxNQUFNLHVCQUFZLENBQUMseUJBQXlCLEVBQUUsQ0FBQztRQUMzRCxNQUFNLEVBQUUsb0JBQW9CLEVBQUUsWUFBWSxFQUFFLGFBQWEsRUFBRSxHQUFHLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7UUFDN0YsSUFBSSx1QkFBdUIsR0FBRyxLQUFLLENBQUM7UUFFcEMsSUFBSSxNQUFNLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztZQUNoQywrQ0FBK0M7WUFDL0MsdUJBQXVCLEdBQUcsTUFBTSxJQUFJLENBQUMsOEJBQThCLENBQ2pFLE1BQU0sQ0FBQyxtQkFBbUIsRUFDMUIsTUFBTSxDQUFDLG9CQUFvQixDQUM1QixDQUFDO1FBQ0osQ0FBQztRQUVELEtBQUssSUFBSSxDQUFDLEdBQUcsUUFBUSxFQUFFLENBQUMsR0FBRyxZQUFZLEdBQUcsUUFBUSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDeEQsTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUMxQixNQUFNLFNBQVMsR0FBRyxHQUFHLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDeEUsSUFBSSxnQkFBZ0IsR0FBRyxJQUFJLHNCQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDeEMsSUFBSSxDQUFDO2dCQUNILGdCQUFnQixHQUFHLElBQUksc0JBQVMsQ0FBQyxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxTQUFTLEVBQUUsb0JBQW9CLENBQUMsQ0FBQyxDQUFDO1lBQ2xHLENBQUM7WUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO2dCQUNYLHlHQUF5RztnQkFDekcscUNBQXFDO2dCQUNyQyxJQUFJLENBQUMsQ0FBQyxPQUFPLEtBQUssaUJBQWlCLEVBQUUsQ0FBQztvQkFDcEMsTUFBTSxDQUFDLENBQUM7Z0JBQ1YsQ0FBQztZQUNILENBQUM7WUFDRCxJQUFJLGdCQUFnQixDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUNyQyxTQUFTO1lBQ1gsQ0FBQztZQUNELE1BQU0sVUFBVSxHQUFHLElBQUEsc0JBQVMsRUFBQyxrQkFBUSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7WUFDckUsTUFBTSxjQUFjLEdBQUcsSUFBQSxzQkFBUyxFQUFDLGtCQUFRLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUU3RSw0RUFBNEU7WUFDNUUsSUFBSSxNQUFNLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztnQkFDaEMsTUFBTSxTQUFTLEdBQUcsZUFBUyxDQUFDLGdDQUFnQyxDQUFDLE1BQU0sQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO2dCQUMxRixJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7b0JBQ2YsTUFBTSxJQUFJLEtBQUssQ0FDYiw2Q0FBNkMsTUFBTSxDQUFDLG9CQUFvQiw0SEFBNEgsQ0FDck0sQ0FBQztnQkFDSixDQUFDO2dCQUNELE1BQU0sS0FBSyxHQUFHLGVBQVMsQ0FBQyw2QkFBNkIsQ0FBQyxTQUFTLENBQUMsQ0FBQztnQkFDakUsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO29CQUNYLE1BQU0sSUFBSSxLQUFLLENBQ2Isc0RBQXNELFNBQVMsMEhBQTBILENBQzFMLENBQUM7Z0JBQ0osQ0FBQztnQkFDRCxJQUFJLHFCQUFnQyxDQUFDO2dCQUNyQyxJQUFJLENBQUM7b0JBQ0gscUJBQXFCLEdBQUcsSUFBSSxzQkFBUyxDQUNuQyxNQUFNLElBQUksQ0FBQyw4QkFBOEIsQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDLG9CQUFvQixDQUFDLENBQ2xGLENBQUM7Z0JBQ0osQ0FBQztnQkFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO29CQUNYLE1BQU0sQ0FBQyxDQUFDO2dCQUNWLENBQUM7Z0JBQ0QsSUFBSSxxQkFBcUIsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQztvQkFDMUMsU0FBUztnQkFDWCxDQUFDO2dCQUNELE1BQU0sU0FBUyxHQUFHLGdCQUFnQjtxQkFDL0IsS0FBSyxDQUFDLGVBQVMsQ0FBQywwQkFBMEIsQ0FBQyx5Q0FBNkIsQ0FBQyxDQUFDO3FCQUMxRSxLQUFLLENBQUMsVUFBVSxDQUFDO3FCQUNqQixLQUFLLENBQUMsY0FBYyxDQUFDLENBQUM7Z0JBQ3pCLElBQUksU0FBUyxDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDO29CQUM5QixNQUFNLElBQUksS0FBSyxDQUNiLGlCQUFpQixDQUFDLDBFQUEwRTt3QkFDMUYsNERBQTRELENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FDdkUsQ0FBQztnQkFDSixDQUFDO2dCQUNELE9BQU8sSUFBSSxDQUFDLGdCQUFnQixDQUMxQixNQUFNLEVBQ04sS0FBSyxFQUNMLFNBQVMsRUFDVCxRQUFRLEVBQ1IsQ0FBQyxFQUNELFFBQVEsRUFDUix1QkFBdUIsRUFDdkIscUJBQXFCLEVBQ3JCLGVBQWUsQ0FDaEIsQ0FBQztZQUNKLENBQUM7WUFFRCwrQkFBK0I7WUFDL0IsTUFBTSxvQkFBb0IsR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUMsSUFBSSxVQUFVLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ2hILE1BQU0sRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLEdBQUcsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLEVBQUUsU0FBUyxFQUFFLG9CQUFvQixFQUFFLENBQUMsQ0FBQztZQUMxRixNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUksQ0FBQyxXQUFXLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDbkQsTUFBTSxrQkFBa0IsR0FBRyxJQUFJLHNCQUFTLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDbkQsTUFBTSxtQkFBbUIsR0FBRyxrQkFBa0IsQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDbEUsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLHNCQUFTLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQztpQkFDekQsSUFBSSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUM7aUJBQzNCLFlBQVksQ0FBQyxrQkFBa0IsQ0FBQztpQkFDaEMsSUFBSSxDQUFDLElBQUksc0JBQVMsQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxTQUFTLENBQUMsQ0FBQyxZQUFZLENBQUMsbUJBQW1CLENBQUMsQ0FBQyxDQUFDO1lBQy9HLG9GQUFvRjtZQUNwRixNQUFNLG1CQUFtQixHQUFHLGdCQUFnQixDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUMvRCxNQUFNLFNBQVMsR0FBRyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsbUJBQW1CLENBQUMsQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUMsS0FBSyxDQUFDLGNBQWMsQ0FBQyxDQUFDO1lBQ3RHLElBQUksU0FBUyxDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUM5QixNQUFNLElBQUksS0FBSyxDQUNiLGlCQUFpQixDQUFDLG9FQUFvRTtvQkFDcEYsNERBQTRELENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FDdkUsQ0FBQztZQUNKLENBQUM7WUFDRCxNQUFNLE9BQU8sR0FBRyxJQUFJLCtCQUF5QixDQUFDLGVBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUMxRSxNQUFNLFNBQVMsR0FBRyxPQUFPO2lCQUN0QixrQkFBa0IsRUFBRTtpQkFDcEIsTUFBTSxDQUFDLFNBQVMsRUFBRSxTQUFTLENBQUM7aUJBQzVCLEtBQUssQ0FBQyxLQUFLLENBQUM7aUJBQ1osVUFBVSxDQUFDLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQztpQkFDdEMsZUFBZSxDQUFDLFNBQVMsQ0FBQztpQkFDMUIsTUFBTSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQy9CLE1BQU0sbUJBQW1CLEdBQUcsQ0FBQyxNQUFNLFNBQVMsQ0FBQyxLQUFLLEVBQUUsQ0FBZ0IsQ0FBQztZQUNyRSxJQUFJLFlBQVksR0FBRyxtQkFBbUIsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBQzNELElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztnQkFDckIsWUFBWSxHQUFHLE1BQU0sSUFBSSxDQUFDLHVCQUF1QixDQUFDLFNBQVMsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLFNBQVMsQ0FBQyxDQUFDO1lBQzVGLENBQUM7aUJBQU0sQ0FBQztnQkFDTixPQUFPLElBQUksQ0FBQyw2QkFBNkIsQ0FDdkMsU0FBUyxFQUNULFNBQVMsRUFDVCxNQUFNLENBQUMsbUJBQW1CLEVBQzFCLFFBQVEsRUFDUixDQUFDLEVBQ0QsUUFBUSxFQUNSLFNBQVMsRUFDVCxtQkFBbUIsQ0FDcEIsQ0FBQztZQUNKLENBQUM7WUFDRCxPQUFPLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQUUsQ0FBQyxFQUFFLENBQUM7UUFDdEQsQ0FBQztRQUNELE1BQU0sSUFBSSxLQUFLLENBQUMsK0NBQStDLENBQUMsQ0FBQztJQUNuRSxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7OztPQVlHO0lBQ0ssS0FBSyxDQUFDLGdCQUFnQixDQUM1QixNQUEwQixFQUMxQixLQUFrQixFQUNsQixhQUFxQixFQUNyQixjQUFzQixFQUN0QixHQUFXLEVBQ1gsUUFBZ0IsRUFDaEIsdUJBQWdDLEVBQ2hDLHFCQUFnQyxFQUNoQyxlQUF3QjtRQUV4QixNQUFNLE9BQU8sR0FBRyxJQUFJLCtCQUF5QixDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3JELE1BQU0sb0JBQW9CLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsV0FBVyxDQUFDLElBQUksVUFBVSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsYUFBYSxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNwSCxNQUFNLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxHQUFHLE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxFQUFFLFNBQVMsRUFBRSxhQUFhLEVBQUUsb0JBQW9CLEVBQUUsQ0FBQyxDQUFDO1FBQ3pHLE1BQU0sU0FBUyxHQUFHLE9BQU87YUFDdEIsK0JBQStCLEVBQUU7YUFDakMsTUFBTSxDQUFDLGFBQWEsRUFBRSxhQUFhLENBQUM7YUFDcEMsS0FBSyxDQUFDLEtBQUssQ0FBQzthQUNaLFVBQVUsQ0FBQyxLQUFLLENBQUMsZUFBZSxDQUFDO2FBQ2pDLGVBQWUsQ0FBQyxTQUFTLENBQUM7YUFDMUIsWUFBWSxDQUFDLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQzthQUN4QyxHQUFHLENBQUMseUNBQTZCLENBQUM7YUFDbEMsT0FBTyxDQUFDLEdBQUcsQ0FBQzthQUNaLE1BQU0sQ0FBQyxxQkFBcUIsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1FBQzVDLElBQUksQ0FBQyx1QkFBdUIsRUFBRSxDQUFDO1lBQzdCLFNBQVMsQ0FBQyxpQkFBaUIsQ0FBQztnQkFDMUIsT0FBTyxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsb0JBQW9CLENBQUM7Z0JBQzNDLEdBQUcsRUFBRSxNQUFNLENBQUMseUNBQTZCLENBQUM7Z0JBQzFDLFNBQVMsRUFBRSxNQUFNLENBQUMsbUJBQW1CO2FBQ3RDLENBQUMsQ0FBQztRQUNMLENBQUM7UUFDRCxJQUFJLGVBQWUsRUFBRSxDQUFDO1lBQ3BCLE9BQU8sSUFBSSxDQUFDLDZCQUE2QixDQUN2QyxTQUFTLEVBQ1QsYUFBYSxFQUNiLE1BQU0sQ0FBQyxtQkFBbUIsRUFDMUIsUUFBUSxFQUNSLEdBQUcsRUFDSCxjQUFjLEVBQ2QscUJBQXFCLEVBQ3JCLElBQUksc0JBQVMsQ0FBQyxlQUFTLENBQUMsMEJBQTBCLENBQUMseUNBQTZCLENBQUMsQ0FBQyxFQUNsRixLQUFLLENBQ04sQ0FBQztRQUNKLENBQUM7YUFBTSxDQUFDO1lBQ04sTUFBTSxZQUFZLEdBQUcsTUFBTSxJQUFJLENBQUMsdUJBQXVCLENBQUMsU0FBUyxFQUFFLE1BQU0sRUFBRSxjQUFjLEVBQUUsYUFBYSxDQUFDLENBQUM7WUFDMUcsT0FBTyxFQUFFLFlBQVksRUFBRSxZQUFZLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxDQUFDO1FBQ3hELENBQUM7SUFDSCxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7OztPQVlHO0lBQ0ssS0FBSyxDQUFDLDZCQUE2QixDQUN6QyxTQUE2QixFQUM3QixhQUFxQixFQUNyQixlQUF1QixFQUN2QixRQUFnQixFQUNoQixLQUFhLEVBQ2IsY0FBc0IsRUFDdEIsU0FBb0IsRUFDcEIsTUFBaUIsRUFDakIsS0FBbUI7UUFFbkIsTUFBTSxrQkFBa0IsR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDO1FBQ25DLE1BQU0sbUJBQW1CLEdBQUcsQ0FBQyxNQUFNLFNBQVMsQ0FBQyxLQUFLLEVBQUUsQ0FBZ0IsQ0FBQztRQUNyRSxNQUFNLFlBQVksR0FBRyxtQkFBbUIsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1FBQzdELE1BQU0sVUFBVSxHQUFHLGtCQUFrQixDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDckUsTUFBTSxNQUFNLEdBQUc7WUFDYjtnQkFDRSxPQUFPLEVBQUUsYUFBYTtnQkFDdEIsV0FBVyxFQUFFLFNBQVMsQ0FBQyxRQUFRLEVBQUU7Z0JBQ2pDLEtBQUssRUFBRSxTQUFTLENBQUMsUUFBUSxFQUFFO2FBQzVCO1NBQ0YsQ0FBQztRQUNGLE1BQU0sT0FBTyxHQUFHO1lBQ2Q7Z0JBQ0UsT0FBTyxFQUFFLGVBQWU7Z0JBQ3hCLFdBQVcsRUFBRSxTQUFTLENBQUMsUUFBUSxFQUFFO2dCQUNqQyxRQUFRLEVBQUUsVUFBVTthQUNyQjtTQUNGLENBQUM7UUFDRixNQUFNLFdBQVcsR0FBRyxTQUFTLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDekMsTUFBTSxRQUFRLEdBQUcsRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsV0FBVyxFQUFFLFdBQVcsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLENBQUM7UUFDMUYsTUFBTSxPQUFPLEdBQUcsRUFBRSxHQUFHLEVBQUUsTUFBTSxDQUFDLFFBQVEsRUFBRSxFQUFFLFNBQVMsRUFBRSxNQUFNLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxDQUFDLG1CQUFtQjtRQUU1RixNQUFNLFdBQVcsR0FBVTtZQUN6QixZQUFZLEVBQUUsWUFBWSxFQUFFLGtDQUFrQztZQUM5RCxTQUFTLEVBQUUsS0FBSyxFQUFFLDRCQUE0QjtZQUM5QyxJQUFJLEVBQUUsVUFBVTtZQUNoQixXQUFXLEVBQUUsbUJBQW1CLENBQUMsZUFBZSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSwwQkFBMEI7WUFDNUYsY0FBYyxFQUFFLGNBQWMsRUFBRSxrQ0FBa0M7WUFDbEUsUUFBUSxFQUFFLFFBQVE7WUFDbEIsT0FBTyxFQUFFLE9BQU87WUFDaEIsWUFBWSxFQUFFLEVBQUUsY0FBYyxFQUFFLFFBQVEsRUFBRSxFQUFFLDhCQUE4QjtTQUMzRSxDQUFDO1FBRUYsTUFBTSxZQUFZLEdBQW9CLENBQUMsRUFBRSxVQUFVLEVBQUUsV0FBVyxFQUFFLGVBQWUsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ3pGLE1BQU0sU0FBUyxHQUFzQjtZQUNuQyxZQUFZLEVBQUUsWUFBWTtZQUMxQixVQUFVLEVBQUUsVUFBVTtTQUN2QixDQUFDO1FBQ0YsT0FBTyxFQUFFLFVBQVUsRUFBRSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7SUFDckMsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSyxLQUFLLENBQUMsdUJBQXVCLENBQ25DLFNBQTZCLEVBQzdCLE1BQTBCLEVBQzFCLGNBQXNCLEVBQ3RCLGFBQXFCO1FBRXJCLE1BQU0sbUJBQW1CLEdBQUcsQ0FBQyxNQUFNLFNBQVMsQ0FBQyxLQUFLLEVBQUUsQ0FBZ0IsQ0FBQztRQUNyRSxlQUFlO1FBQ2Ysa0VBQWtFO1FBQ2xFLCtFQUErRTtRQUMvRSxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ3BCLE1BQU0sSUFBSSxLQUFLLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUNyQyxDQUFDO1FBQ0QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQztZQUN0QixNQUFNLElBQUksS0FBSyxDQUFDLG1CQUFtQixDQUFDLENBQUM7UUFDdkMsQ0FBQztRQUNELElBQUksQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUM3QixNQUFNLElBQUksS0FBSyxDQUFDLDJCQUEyQixDQUFDLENBQUM7UUFDL0MsQ0FBQztRQUVELDBDQUEwQztRQUMxQyxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFDbEQsTUFBTSxTQUFTLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRXRELDJDQUEyQztRQUMzQyxJQUFJLE9BQU8sQ0FBQztRQUNaLElBQUksQ0FBQztZQUNILE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQztnQkFDM0IsS0FBSyxFQUFFLE9BQU87Z0JBQ2QsUUFBUSxFQUFFLE1BQU0sQ0FBQyxnQkFBZ0I7YUFDbEMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDWCxNQUFNLElBQUksS0FBSyxDQUFDLG1DQUFtQyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUNsRSxDQUFDO1FBQ0QsZ0RBQWdEO1FBQ2hELE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQXlDLENBQUM7UUFFeEYsSUFBSSxTQUFTLENBQUM7UUFDZCxJQUFJLENBQUM7WUFDSCxTQUFTLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUM7Z0JBQzdCLEtBQUssRUFBRSxTQUFTO2dCQUNoQixRQUFRLEVBQUUsTUFBTSxDQUFDLGdCQUFnQjthQUNsQyxDQUFDLENBQUM7UUFDTCxDQUFDO1FBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUNYLE1BQU0sSUFBSSxLQUFLLENBQUMscUNBQXFDLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1FBQ3BFLENBQUM7UUFDRCxNQUFNLHFCQUFxQixHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUEyQyxDQUFDO1FBQzlGLGtFQUFrRTtRQUVsRSxnQkFBZ0I7UUFDaEIsTUFBTSxZQUFZLEdBQUcsTUFBTSx1QkFBWSxDQUFDLGVBQWUsQ0FDckQsbUJBQW1CLEVBQ25CLHFCQUFxQixFQUNyQixjQUFjLEVBQ2QsbUJBQW1CLENBQ3BCLENBQUM7UUFDRixNQUFNLFlBQVksR0FBRyxFQUFFLEdBQUcsRUFBRSxhQUFhLEVBQUUsQ0FBQztRQUM1QyxTQUFTLENBQUMsWUFBWSxDQUFDLFlBQXlCLEVBQUUsWUFBWSxDQUFDLENBQUM7UUFFaEUsTUFBTSxvQkFBb0IsR0FBRyxNQUFNLFNBQVMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztRQUNyRCxPQUFPLG9CQUFvQixDQUFDLGlCQUFpQixFQUFFLENBQUM7SUFDbEQsQ0FBQztJQUVELEtBQUssQ0FBQyxtQ0FBbUMsQ0FBQyxNQUErQjtRQUN2RSxNQUFNLEdBQUcsR0FBRyxNQUFNLENBQUMsZUFBZSxDQUFDO1FBQ25DLE1BQU0seUJBQXlCLEdBQVksRUFBRSxDQUFDO1FBQzlDLElBQUksYUFBYSxHQUFHLENBQUMsQ0FBQztRQUV0QixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsR0FBRyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQ3BDLE1BQU0sR0FBRyxHQUFHLE1BQU0sdUJBQVksQ0FBQyx5QkFBeUIsRUFBRSxDQUFDO1lBQzNELE1BQU0sV0FBVyxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQztZQUVoRSw0QkFBNEI7WUFDNUIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLGNBQWMsRUFBRSxDQUFDO2dCQUNqRCxNQUFNLElBQUksS0FBSyxDQUFDLHNCQUFzQixDQUFDLENBQUM7WUFDMUMsQ0FBQztZQUNELE1BQU0sU0FBUyxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsY0FBYyxDQUFDO1lBRS9DLHdCQUF3QjtZQUN4QixJQUFJLENBQUMsV0FBVyxDQUFDLFdBQVcsRUFBRSxDQUFDO2dCQUM3QixNQUFNLElBQUksS0FBSyxDQUFDLHNCQUFzQixDQUFDLENBQUM7WUFDMUMsQ0FBQztZQUNELE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLFdBQVksRUFBRSxLQUFLLENBQUMsQ0FBQztZQUNuRSxNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsTUFBTSxDQUFDLGFBQWEsRUFBRSxTQUFTLENBQUMsQ0FBQztZQUNwRCxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQ1osTUFBTSxJQUFJLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1lBQ3ZDLENBQUM7WUFFRCxzQ0FBc0M7WUFDdEMsTUFBTSxZQUFZLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBRTNHLHVDQUF1QztZQUN2QyxJQUFJLENBQUMsV0FBVyxDQUFDLFlBQVksRUFBRSxjQUFjLEVBQUUsQ0FBQztnQkFDOUMsTUFBTSxJQUFJLEtBQUssQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO1lBQzdDLENBQUM7WUFDRCxNQUFNLGNBQWMsR0FBRyxXQUFXLENBQUMsWUFBYSxDQUFDLGNBQXlCLENBQUM7WUFFM0UsSUFBSSxDQUFDLFdBQVcsQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDaEMsTUFBTSxJQUFJLEtBQUssQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO1lBQzdDLENBQUM7WUFDRCxNQUFNLGNBQWMsR0FBRyxXQUFXLENBQUMsY0FBd0IsQ0FBQztZQUU1RCx1Q0FBdUM7WUFDdkMsTUFBTSxTQUFTLEdBQUcsR0FBRyxDQUFDLGdCQUFnQixDQUFDLGNBQWMsRUFBRSxjQUFjLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ3BGLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLFlBQXNCLENBQUMsQ0FBQztZQUU5RSxvQkFBb0I7WUFDcEIsTUFBTSxXQUFXLEdBQUcsSUFBSSxhQUFXLENBQUMsRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQztZQUN4RCxVQUFVLENBQUMsWUFBWSxDQUFDLEVBQUUsR0FBRyxFQUFFLFdBQVcsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxHQUFHLEVBQUUsRUFBRSxZQUFZLENBQUMsQ0FBQztZQUUxRSx5Q0FBeUM7WUFDekMsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLFVBQVUsQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNuRCxNQUFNLFlBQVksR0FBRyxpQkFBaUIsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO1lBRTNELHlDQUF5QztZQUN6Qyx5QkFBeUIsQ0FBQyxJQUFJLENBQUM7Z0JBQzdCLFlBQVksRUFBRSxZQUFZO2dCQUMxQixTQUFTLEVBQUUsV0FBVyxDQUFDLFNBQVM7YUFDakMsQ0FBQyxDQUFDO1lBRUgsMkNBQTJDO1lBQzNDLElBQUksQ0FBQyxLQUFLLEdBQUcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLFdBQVcsQ0FBQyxZQUFhLENBQUMsYUFBYSxFQUFFLENBQUM7Z0JBQ3BFLGFBQWEsR0FBRyxXQUFXLENBQUMsWUFBYSxDQUFDLGFBQXVCLENBQUM7WUFDcEUsQ0FBQztRQUNILENBQUM7UUFFRCxnRUFBZ0U7UUFDaEUsT0FBTyxFQUFFLFlBQVksRUFBRSx5QkFBeUIsRUFBRSxhQUFhLEVBQUUsQ0FBQztJQUNwRSxDQUFDO0lBRUQ7OztPQUdHO0lBQ08sS0FBSyxDQUFDLGVBQWUsQ0FBQyxNQUE2QztRQUMzRSxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztRQUMxQyxLQUFLLE1BQU0sT0FBTyxJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQy9CLElBQUksQ0FBQztnQkFDSCxPQUFPLE1BQU0sT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQzFELENBQUM7WUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO2dCQUNYLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDbkIsQ0FBQztRQUNILENBQUM7UUFDRCxNQUFNLElBQUksS0FBSyxDQUFDLDRDQUE0QyxDQUFDLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDeEYsQ0FBQztJQUVTLEtBQUssQ0FBQyxZQUFZLENBQUMsRUFDM0IsU0FBUyxFQUNULG9CQUFvQixHQUlyQjtRQUNDLE1BQU0sUUFBUSxHQUFHLE1BQU0sSUFBSSxDQUFDLGVBQWUsQ0FBQztZQUMxQyxPQUFPLEVBQUU7Z0JBQ1AsT0FBTyxFQUFFLEtBQUs7Z0JBQ2QsRUFBRSxFQUFFLFVBQVU7Z0JBQ2QsTUFBTSxFQUFFLE9BQU87Z0JBQ2YsTUFBTSxFQUFFO29CQUNOLFlBQVksRUFBRSxpQkFBaUI7b0JBQy9CLFFBQVEsRUFBRSxPQUFPO29CQUNqQixVQUFVLEVBQUUsU0FBUztvQkFDckIsVUFBVSxFQUFFLG9CQUFvQjtpQkFDakM7YUFDRjtTQUNGLENBQUMsQ0FBQztRQUNILElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxHQUFHLEVBQUUsQ0FBQztZQUM1QixNQUFNLElBQUksS0FBSyxDQUFDLG1CQUFtQixDQUFDLENBQUM7UUFDdkMsQ0FBQztRQUNELE1BQU0sU0FBUyxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO1FBQ3ZDLE9BQU8sRUFBRSxLQUFLLEVBQUUsU0FBUyxDQUFDLEtBQUssR0FBRyxDQUFDLEVBQUUsU0FBUyxFQUFFLFNBQVMsQ0FBQyxVQUFVLEVBQUUsQ0FBQztJQUN6RSxDQUFDO0lBRVMsS0FBSyxDQUFDLGlCQUFpQixDQUFDLFNBQWlCLEVBQUUsb0JBQTRCO1FBQy9FLE1BQU0sUUFBUSxHQUFHLE1BQU0sSUFBSSxDQUFDLGVBQWUsQ0FBQztZQUMxQyxPQUFPLEVBQUU7Z0JBQ1AsT0FBTyxFQUFFLEtBQUs7Z0JBQ2QsRUFBRSxFQUFFLFVBQVU7Z0JBQ2QsTUFBTSxFQUFFLE9BQU87Z0JBQ2YsTUFBTSxFQUFFO29CQUNOLFlBQVksRUFBRSxjQUFjO29CQUM1QixRQUFRLEVBQUUsT0FBTztvQkFDakIsVUFBVSxFQUFFLFNBQVM7aUJBQ3RCO2FBQ0Y7U0FDRixDQUFDLENBQUM7UUFDSCxJQUFJLFFBQVEsQ0FBQyxNQUFNLEtBQUssR0FBRyxFQUFFLENBQUM7WUFDNUIsTUFBTSxJQUFJLEtBQUssQ0FBQyxxQ0FBcUMsQ0FBQyxDQUFDO1FBQ3pELENBQUM7UUFDRCxNQUFNLFVBQVUsR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDO1FBQ25ELElBQUksVUFBVSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQzdCLE1BQU0sSUFBSSxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDOUIsQ0FBQztRQUVELE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO1FBQ3JDLE1BQU0sV0FBVyxHQUFHLElBQUksc0JBQVMsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1FBQ3hELE1BQU0sV0FBVyxHQUFHLElBQUksc0JBQVMsQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLENBQUMsWUFBWSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQ25GLE1BQU0sTUFBTSxHQUFHLElBQUksc0JBQVMsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDN0MsTUFBTSxZQUFZLEdBQUcsSUFBSSxzQkFBUyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDaEUsTUFBTSxnQkFBZ0IsR0FBRyxZQUFZLENBQUMsS0FBSyxDQUFDLHNCQUFTLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDO1FBQ2hGLE9BQU8sZ0JBQWdCLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDckMsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ08sS0FBSyxDQUFDLDhCQUE4QixDQUFDLFNBQWlCLEVBQUUsb0JBQTRCO1FBQzVGLE1BQU0sVUFBVSxHQUFHLGVBQVMsQ0FBQyxlQUFlLENBQUMsRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQztRQUN4RSxNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUksQ0FBQyxlQUFlLENBQUM7WUFDMUMsT0FBTyxFQUFFO2dCQUNQLE9BQU8sRUFBRSxLQUFLO2dCQUNkLEVBQUUsRUFBRSxVQUFVO2dCQUNkLE1BQU0sRUFBRSxPQUFPO2dCQUNmLE1BQU0sRUFBRTtvQkFDTixZQUFZLEVBQUUsZUFBZTtvQkFDN0IsUUFBUSxFQUFFLE9BQU87b0JBQ2pCLFVBQVUsRUFBRSxvQkFBb0I7b0JBQ2hDLFdBQVcsRUFBRSxlQUFlO29CQUM1QixXQUFXLEVBQUUsVUFBVTtpQkFDeEI7YUFDRjtTQUNGLENBQUMsQ0FBQztRQUNILElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxHQUFHLEVBQUUsQ0FBQztZQUM1QixNQUFNLElBQUksS0FBSyxDQUFDLDJDQUEyQyxDQUFDLENBQUM7UUFDL0QsQ0FBQztRQUNELE1BQU0sVUFBVSxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUM7UUFDcEQsSUFBSSxVQUFVLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDN0IsTUFBTSxJQUFJLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUM5QixDQUFDO1FBQ0QsTUFBTSxnQkFBZ0IsR0FBZSxJQUFJLFVBQVUsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNqRixNQUFNLEdBQUcsR0FBRyxJQUFJLFdBQVcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1FBQ3ZELE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUN6QixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDTyxLQUFLLENBQUMsOEJBQThCLENBQUMsU0FBaUIsRUFBRSxvQkFBNEI7UUFDNUYsTUFBTSxVQUFVLEdBQUcsZUFBUyxDQUFDLGVBQWUsQ0FBQyxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDO1FBQ3hFLE1BQU0sUUFBUSxHQUFHLE1BQU0sSUFBSSxDQUFDLGVBQWUsQ0FBQztZQUMxQyxPQUFPLEVBQUU7Z0JBQ1AsT0FBTyxFQUFFLEtBQUs7Z0JBQ2QsRUFBRSxFQUFFLFVBQVU7Z0JBQ2QsTUFBTSxFQUFFLE9BQU87Z0JBQ2YsTUFBTSxFQUFFO29CQUNOLFlBQVksRUFBRSxlQUFlO29CQUM3QixRQUFRLEVBQUUsT0FBTztvQkFDakIsVUFBVSxFQUFFLG9CQUFvQjtvQkFDaEMsV0FBVyxFQUFFLG9CQUFvQjtvQkFDakMsV0FBVyxFQUFFLFVBQVU7aUJBQ3hCO2FBQ0Y7U0FDRixDQUFDLENBQUM7UUFDSCxJQUFJLFFBQVEsQ0FBQyxNQUFNLEtBQUssR0FBRyxFQUFFLENBQUM7WUFDNUIsTUFBTSxJQUFJLEtBQUssQ0FBQyxnREFBZ0QsQ0FBQyxDQUFDO1FBQ3BFLENBQUM7UUFDRCxNQUFNLFVBQVUsR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDO1FBQ3BELElBQUksVUFBVSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQzdCLE1BQU0sSUFBSSxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDOUIsQ0FBQztRQUNELE1BQU0sZ0JBQWdCLEdBQWUsSUFBSSxVQUFVLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDakYsTUFBTSxHQUFHLEdBQUcsSUFBSSxXQUFXLEVBQUUsQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztRQUN2RCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ2hDLE9BQU8sT0FBTyxLQUFLLElBQUksQ0FBQztJQUMxQixDQUFDO0lBRVMsS0FBSyxDQUFDLGlCQUFpQjtRQUMvQixNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUksQ0FBQyxlQUFlLENBQUM7WUFDMUMsT0FBTyxFQUFFO2dCQUNQLE9BQU8sRUFBRSxLQUFLO2dCQUNkLEVBQUUsRUFBRSxVQUFVO2dCQUNkLE1BQU0sRUFBRSw4QkFBOEI7Z0JBQ3RDLE1BQU0sRUFBRTtvQkFDTixRQUFRLEVBQUUsT0FBTztpQkFDbEI7YUFDRjtTQUNGLENBQUMsQ0FBQztRQUNILElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxHQUFHLEVBQUUsQ0FBQztZQUM1QixNQUFNLElBQUksS0FBSyxDQUFDLG1CQUFtQixDQUFDLENBQUM7UUFDdkMsQ0FBQztRQUVELE1BQU0sTUFBTSxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO1FBQ3BDLE1BQU0sb0JBQW9CLEdBQUcsTUFBTSxDQUFDLGNBQWMsQ0FBQyx1QkFBdUIsQ0FBQztRQUMzRSxNQUFNLHVCQUF1QixHQUFHLE1BQU0sQ0FBQyxjQUFjLENBQUMsaUJBQWlCLENBQUMsc0JBQXNCLENBQUMsYUFBYSxDQUFDO1FBQzdHLE1BQU0sWUFBWSxHQUFrQjtZQUNsQyxPQUFPLEVBQUUsdUJBQXVCLENBQUMsUUFBUTtZQUN6QyxVQUFVLEVBQUUsdUJBQXVCLENBQUMsWUFBWTtZQUNoRCxTQUFTLEVBQUUsdUJBQXVCLENBQUMsU0FBUztTQUM3QyxDQUFDO1FBRUYsTUFBTSx3QkFBd0IsR0FBRyxNQUFNLENBQUMsY0FBYyxDQUFDLGlCQUFpQixDQUFDLDhCQUE4QixDQUFDO1FBQ3hHLE1BQU0sYUFBYSxHQUFrQjtZQUNuQyxPQUFPLEVBQUUsd0JBQXdCLENBQUMsUUFBUTtZQUMxQyxVQUFVLEVBQUUsd0JBQXdCLENBQUMsWUFBWTtZQUNqRCxTQUFTLEVBQUUsd0JBQXdCLENBQUMsU0FBUztTQUM5QyxDQUFDO1FBQ0YsT0FBTyxFQUFFLG9CQUFvQixFQUFFLFlBQVksRUFBRSxhQUFhLEVBQUUsQ0FBQztJQUMvRCxDQUFDO0lBRVMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxTQUFpQjtRQUMzQyxNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUksQ0FBQyxlQUFlLENBQUM7WUFDMUMsT0FBTyxFQUFFO2dCQUNQLE9BQU8sRUFBRSxLQUFLO2dCQUNkLEVBQUUsRUFBRSxVQUFVO2dCQUNkLE1BQU0sRUFBRSxXQUFXO2dCQUNuQixNQUFNLEVBQUUsQ0FBQyxTQUFTLENBQUM7YUFDcEI7U0FDRixDQUFDLENBQUM7UUFDSCxJQUFJLFFBQVEsQ0FBQyxNQUFNLEtBQUssR0FBRyxFQUFFLENBQUM7WUFDNUIsTUFBTSxJQUFJLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1FBQ3ZDLENBQUM7UUFDRCxPQUFPLFFBQVEsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQztJQUN4QyxDQUFDO0lBRVMsaUJBQWlCO1FBQ3pCLE9BQU8sdUJBQVksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsWUFBWSxDQUFDO0lBQ3hELENBQUM7SUFFRCxLQUFLLENBQUMsZ0JBQWdCLENBQUMsTUFBbUM7UUFDeEQsTUFBTSxzQkFBc0IsR0FBRyxNQUFNLElBQUksQ0FBQyxrQkFBa0IsQ0FBQztZQUMzRCxVQUFVLEVBQUUsTUFBTSxDQUFDLFVBQVU7WUFDN0IsU0FBUyxFQUFFLE1BQU0sQ0FBQyxTQUFTO1lBQzNCLE9BQU8sRUFBRSxNQUFNLENBQUMsT0FBTztTQUN4QixDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsc0JBQXNCLEVBQUUsQ0FBQztZQUM1QixNQUFNLElBQUksS0FBSyxDQUFDLHFCQUFxQixDQUFDLENBQUM7UUFDekMsQ0FBQztRQUVELE1BQU0sZUFBZSxHQUFHLHNCQUFvRCxDQUFDO1FBQzdFLElBQUksZUFBZSxDQUFDLE9BQU8sQ0FBQyxNQUFNLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDeEMsT0FBTztnQkFDTCxNQUFNLEVBQUUsRUFBRTtnQkFDVixPQUFPLEVBQUUsRUFBRTthQUNaLENBQUM7UUFDSixDQUFDO1FBRUQsTUFBTSxhQUFhLEdBQUcsZUFBZSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUM7UUFDekQsTUFBTSxTQUFTLEdBQUcsSUFBSSxzQkFBUyxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsR0FBRyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBRWhHLDZDQUE2QztRQUM3QyxNQUFNLE1BQU0sR0FBRztZQUNiO2dCQUNFLE9BQU8sRUFBRSxhQUFhO2dCQUN0QixNQUFNLEVBQUUsSUFBSSxzQkFBUyxDQUFDLGVBQWUsQ0FBQyxZQUFZLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsT0FBTyxFQUFFO2FBQzlFO1NBQ0YsQ0FBQztRQUVGLE1BQU0sT0FBTyxHQUF3QixlQUFlLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFO1lBQzFFLE9BQU87Z0JBQ0wsT0FBTyxFQUFFLE1BQU0sQ0FBQyxPQUFPO2dCQUN2QixNQUFNLEVBQUUsSUFBSSxzQkFBUyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxPQUFPLEVBQUU7YUFDL0MsQ0FBQztRQUNKLENBQUMsQ0FBQyxDQUFDO1FBRUgsT0FBTztZQUNMLE1BQU07WUFDTixPQUFPO1NBQ1IsQ0FBQztJQUNKLENBQUM7SUFFRCxLQUFLLENBQUMsZUFBZSxDQUFDLE1BQTRCO1FBQ2hELE1BQU0sSUFBSSxvQ0FBeUIsRUFBRSxDQUFDO0lBQ3hDLENBQUM7SUFFRCxLQUFLLENBQUMsaUJBQWlCLENBQUMsTUFBZ0M7UUFDdEQsSUFBSSxXQUFXLEdBQUcsSUFBSSxzQkFBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ25DLE1BQU0sVUFBVSxHQUFHLGVBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFDOUMsTUFBTSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxHQUFHLE1BQU0sQ0FBQztRQUM5RCxNQUFNLFdBQVcsR0FBRyxJQUFJLGlCQUFXLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDaEQsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLEtBQUssQ0FBQztRQUMvQixJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDWCxNQUFNLElBQUksS0FBSyxDQUFDLDZDQUE2QyxDQUFDLENBQUM7UUFDakUsQ0FBQztRQUVELFdBQVcsQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN0QyxNQUFNLFdBQVcsR0FBRyxXQUFXLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztRQUVyRCwrRkFBK0Y7UUFDL0YsSUFBSSxRQUFRLENBQUMsVUFBVSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3RDLElBQUksUUFBUSxDQUFDLElBQUksS0FBSyxhQUFhLEVBQUUsQ0FBQztnQkFDcEMsTUFBTSxTQUFTLEdBQUcsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7Z0JBQ25ELElBQUksU0FBUyxFQUFFLENBQUM7b0JBQ2QsTUFBTSxRQUFRLEdBQUcsZUFBUyxDQUFDLDZCQUE2QixDQUFDLFNBQVMsQ0FBQyxDQUFDO29CQUNwRSxJQUFJLFFBQVEsRUFBRSxDQUFDO3dCQUNiLFdBQVcsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUU7NEJBQ3JDLElBQUksTUFBTSxDQUFDLE1BQU0sS0FBSyxRQUFRLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztnQ0FDcEQsTUFBTSxJQUFJLEtBQUssQ0FBQyxzQ0FBc0MsQ0FBQyxDQUFDOzRCQUMxRCxDQUFDO3dCQUNILENBQUMsQ0FBQyxDQUFDO29CQUNMLENBQUM7Z0JBQ0gsQ0FBQztZQUNILENBQUM7WUFFRCxNQUFNLGtCQUFrQixHQUFHLFFBQVEsQ0FBQyxVQUFVLEVBQUUsR0FBRyxDQUFDLENBQUMsU0FBUyxFQUFFLEVBQUU7Z0JBQ2hFLElBQUksUUFBUSxDQUFDLElBQUksS0FBSyxhQUFhLEVBQUUsQ0FBQztvQkFDcEMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDLFNBQVMsRUFBRSxRQUFRLENBQUMsQ0FBQyxDQUFDO2dCQUNsRCxDQUFDO3FCQUFNLENBQUM7b0JBQ04sT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDLFNBQVMsRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDO2dCQUNyRCxDQUFDO1lBQ0gsQ0FBQyxDQUFDLENBQUM7WUFDSCxNQUFNLGVBQWUsR0FBRyxXQUFXLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFO2dCQUN6RCxJQUFJLFFBQVEsQ0FBQyxJQUFJLEtBQUssYUFBYSxFQUFFLENBQUM7b0JBQ3BDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxTQUFTLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQztnQkFDL0MsQ0FBQztxQkFBTSxDQUFDO29CQUNOLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxTQUFTLEVBQUUsV0FBVyxDQUFDLENBQUMsQ0FBQztnQkFDbEQsQ0FBQztZQUNILENBQUMsQ0FBQyxDQUFDO1lBRUgsSUFBSSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsZUFBZSxFQUFFLGtCQUFrQixDQUFDLEVBQUUsQ0FBQztnQkFDcEQsTUFBTSxJQUFJLEtBQUssQ0FBQyw2REFBNkQsQ0FBQyxDQUFDO1lBQ2pGLENBQUM7WUFDRCxLQUFLLE1BQU0sVUFBVSxJQUFJLFFBQVEsQ0FBQyxVQUFVLEVBQUUsQ0FBQztnQkFDN0MsV0FBVyxHQUFHLFFBQVEsQ0FBQyxJQUFJLEtBQUssYUFBYSxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBQSxzQkFBUyxFQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3JHLENBQUM7WUFDRCxJQUFJLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUMsWUFBWSxDQUFDLElBQUksUUFBUSxDQUFDLElBQUksS0FBSyxhQUFhLEVBQUUsQ0FBQztnQkFDeEYsTUFBTSxJQUFJLEtBQUssQ0FBQyxpRUFBaUUsQ0FBQyxDQUFDO1lBQ3JGLENBQUM7UUFDSCxDQUFDO1FBRUQsSUFBSSxNQUFNLENBQUMsWUFBWSxFQUFFLDBCQUEwQixFQUFFLENBQUM7WUFDcEQsTUFBTSxJQUFJLENBQUMsZ0NBQWdDLENBQUMsTUFBTSxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBQ25FLENBQUM7UUFFRCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFTyxVQUFVO1FBQ2hCLE9BQU8sSUFBSSwrQkFBeUIsQ0FBQyxlQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDdkUsQ0FBQztJQUVELGtCQUFrQjtJQUNsQixpQkFBaUIsQ0FBQyxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUEyQjtRQUN6RSxJQUFJLFlBQVksS0FBSyxLQUFLLEVBQUUsQ0FBQztZQUMzQixNQUFNLElBQUksS0FBSyxDQUFDLDBCQUEwQixDQUFDLENBQUM7UUFDOUMsQ0FBQztRQUNELElBQUEsa0NBQW9CLEVBQUMsR0FBRyxFQUFFLFNBQVMsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUM3QyxDQUFDO0lBRVMsS0FBSyxDQUFDLGdDQUFnQyxDQUM5QyxNQUFnQyxFQUNoQyxXQUFtQztRQUVuQyxNQUFNLGFBQWEsR0FBOEIsTUFBTSxNQUFNLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN2RyxJQUFJLENBQUMsYUFBYSxJQUFJLGFBQWEsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDakQsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDO1FBQ3JELENBQUM7UUFDRCxNQUFNLFdBQVcsR0FBRyxhQUFhLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFFckMsS0FBSyxNQUFNLE1BQU0sSUFBSSxXQUFXLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDekMsSUFBSSxNQUFNLENBQUMsT0FBTyxLQUFLLFdBQVcsQ0FBQyxPQUFPLEVBQUUsQ0FBQztnQkFDM0MsTUFBTSxJQUFJLEtBQUssQ0FBQyxpREFBaUQsQ0FBQyxDQUFDO1lBQ3JFLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQzs7QUFqOEJILG9CQWs4QkM7QUF0N0JrQixnQkFBVyxHQUFHLEtBQUssQUFBUixDQUFTIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAcHJldHRpZXJcbiAqL1xuXG5pbXBvcnQgKiBhcyBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgQmlnTnVtYmVyIGZyb20gJ2JpZ251bWJlci5qcyc7XG5pbXBvcnQgKiBhcyBiYXNlNTggZnJvbSAnYnM1OCc7XG5pbXBvcnQgKiBhcyBuZWFyQVBJIGZyb20gJ25lYXItYXBpLWpzJztcbmltcG9ydCAqIGFzIHJlcXVlc3QgZnJvbSAnc3VwZXJhZ2VudCc7XG5cbmltcG9ydCB7IGF1ZGl0RWRkc2FQcml2YXRlS2V5IH0gZnJvbSAnQGJpdGdvLWJldGEvc2RrLWxpYi1tcGMnO1xuaW1wb3J0IHtcbiAgQXVkaXREZWNyeXB0ZWRLZXlQYXJhbXMsXG4gIEJhc2VBZGRyZXNzLFxuICBCYXNlQ29pbixcbiAgQmFzZVRyYW5zYWN0aW9uLFxuICBCaXRHb0Jhc2UsXG4gIEVkZHNhLFxuICBFRERTQU1ldGhvZHMsXG4gIEVERFNBTWV0aG9kVHlwZXMsXG4gIEVudmlyb25tZW50cyxcbiAgS2V5UGFpcixcbiAgTWV0aG9kTm90SW1wbGVtZW50ZWRFcnJvcixcbiAgTVBDQWxnb3JpdGhtLFxuICBNUENSZWNvdmVyeU9wdGlvbnMsXG4gIE1QQ1N3ZWVwUmVjb3ZlcnlPcHRpb25zLFxuICBNUENTd2VlcFR4cyxcbiAgTVBDVHgsXG4gIE1QQ1R4cyxcbiAgTVBDVW5zaWduZWRUeCxcbiAgTXVsdGlzaWdUeXBlLFxuICBtdWx0aXNpZ1R5cGVzLFxuICBQYXJzZWRUcmFuc2FjdGlvbixcbiAgUGFyc2VUcmFuc2FjdGlvbk9wdGlvbnMgYXMgQmFzZVBhcnNlVHJhbnNhY3Rpb25PcHRpb25zLFxuICBQdWJsaWNLZXksXG4gIFJlY292ZXJ5VHhSZXF1ZXN0LFxuICBTaWduZWRUcmFuc2FjdGlvbixcbiAgU2lnblRyYW5zYWN0aW9uT3B0aW9ucyBhcyBCYXNlU2lnblRyYW5zYWN0aW9uT3B0aW9ucyxcbiAgVG9rZW5FbmFibGVtZW50Q29uZmlnLFxuICBUcmFuc2FjdGlvbkV4cGxhbmF0aW9uLFxuICBWZXJpZnlBZGRyZXNzT3B0aW9ucyxcbiAgVmVyaWZ5VHJhbnNhY3Rpb25PcHRpb25zLFxufSBmcm9tICdAYml0Z28tYmV0YS9zZGstY29yZSc7XG5pbXBvcnQgeyBCYXNlQ29pbiBhcyBTdGF0aWNzQmFzZUNvaW4sIENvaW5GYW1pbHksIGNvaW5zLCBOZXAxNDFUb2tlbiwgTmV0d29ya3MgfSBmcm9tICdAYml0Z28tYmV0YS9zdGF0aWNzJztcblxuaW1wb3J0IHsgS2V5UGFpciBhcyBOZWFyS2V5UGFpciwgVHJhbnNhY3Rpb24sIFRyYW5zYWN0aW9uQnVpbGRlciwgVHJhbnNhY3Rpb25CdWlsZGVyRmFjdG9yeSB9IGZyb20gJy4vbGliJztcbmltcG9ydCBuZWFyVXRpbHMgZnJvbSAnLi9saWIvdXRpbHMnO1xuaW1wb3J0IHsgTUFYX0dBU19MSU1JVF9GT1JfRlRfVFJBTlNGRVIgfSBmcm9tICcuL2xpYi9jb25zdGFudHMnO1xuXG5leHBvcnQgaW50ZXJmYWNlIFNpZ25UcmFuc2FjdGlvbk9wdGlvbnMgZXh0ZW5kcyBCYXNlU2lnblRyYW5zYWN0aW9uT3B0aW9ucyB7XG4gIHR4UHJlYnVpbGQ6IFRyYW5zYWN0aW9uUHJlYnVpbGQ7XG4gIHBydjogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRyYW5zYWN0aW9uUHJlYnVpbGQge1xuICB0eEhleDogc3RyaW5nO1xuICBrZXk6IHN0cmluZztcbiAgYmxvY2tIYXNoOiBzdHJpbmc7XG4gIG5vbmNlOiBiaWdpbnQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRXhwbGFpblRyYW5zYWN0aW9uT3B0aW9ucyB7XG4gIHR4UHJlYnVpbGQ6IFRyYW5zYWN0aW9uUHJlYnVpbGQ7XG4gIHB1YmxpY0tleTogc3RyaW5nO1xuICBmZWVJbmZvOiB7XG4gICAgZmVlOiBzdHJpbmc7XG4gIH07XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVmVyaWZpZWRUcmFuc2FjdGlvblBhcmFtZXRlcnMge1xuICB0eEhleDogc3RyaW5nO1xuICBwcnY6IHN0cmluZztcbiAgc2lnbmVyOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTmVhclBhcnNlVHJhbnNhY3Rpb25PcHRpb25zIGV4dGVuZHMgQmFzZVBhcnNlVHJhbnNhY3Rpb25PcHRpb25zIHtcbiAgdHhQcmVidWlsZDogVHJhbnNhY3Rpb25QcmVidWlsZDtcbiAgcHVibGljS2V5OiBzdHJpbmc7XG4gIGZlZUluZm86IHtcbiAgICBmZWU6IHN0cmluZztcbiAgfTtcbn1cblxuaW50ZXJmYWNlIFRyYW5zYWN0aW9uT3V0cHV0IHtcbiAgYWRkcmVzczogc3RyaW5nO1xuICBhbW91bnQ6IHN0cmluZztcbn1cblxuaW50ZXJmYWNlIE5lYXJUeEJ1aWxkZXJQYXJhbXNGcm9tTm9kZSB7XG4gIG5vbmNlOiBiaWdpbnQ7XG4gIGJsb2NrSGFzaDogc3RyaW5nO1xufVxuXG5pbnRlcmZhY2UgTmVhckZlZUNvbmZpZyB7XG4gIHNlbmRTaXI6IG51bWJlcjtcbiAgc2VuZE5vdFNpcjogbnVtYmVyO1xuICBleGVjdXRpb246IG51bWJlcjtcbn1cblxuaW50ZXJmYWNlIFByb3RvY29sQ29uZmlnT3V0cHV0IHtcbiAgc3RvcmFnZUFtb3VudFBlckJ5dGU6IG51bWJlcjtcbiAgdHJhbnNmZXJDb3N0OiBOZWFyRmVlQ29uZmlnO1xuICByZWNlaXB0Q29uZmlnOiBOZWFyRmVlQ29uZmlnO1xufVxuXG50eXBlIFRyYW5zYWN0aW9uSW5wdXQgPSBUcmFuc2FjdGlvbk91dHB1dDtcblxuZXhwb3J0IGludGVyZmFjZSBOZWFyUGFyc2VkVHJhbnNhY3Rpb24gZXh0ZW5kcyBQYXJzZWRUcmFuc2FjdGlvbiB7XG4gIC8vIHRvdGFsIGFzc2V0cyBiZWluZyBtb3ZlZCwgaW5jbHVkaW5nIGZlZXNcbiAgaW5wdXRzOiBUcmFuc2FjdGlvbklucHV0W107XG5cbiAgLy8gd2hlcmUgYXNzZXRzIGFyZSBtb3ZlZCB0b1xuICBvdXRwdXRzOiBUcmFuc2FjdGlvbk91dHB1dFtdO1xufVxuXG5leHBvcnQgdHlwZSBOZWFyVHJhbnNhY3Rpb25FeHBsYW5hdGlvbiA9IFRyYW5zYWN0aW9uRXhwbGFuYXRpb247XG5cbmV4cG9ydCBjbGFzcyBOZWFyIGV4dGVuZHMgQmFzZUNvaW4ge1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgX3N0YXRpY3NDb2luOiBSZWFkb25seTxTdGF0aWNzQmFzZUNvaW4+O1xuXG4gIGNvbnN0cnVjdG9yKGJpdGdvOiBCaXRHb0Jhc2UsIHN0YXRpY3NDb2luPzogUmVhZG9ubHk8U3RhdGljc0Jhc2VDb2luPikge1xuICAgIHN1cGVyKGJpdGdvKTtcbiAgICBpZiAoIXN0YXRpY3NDb2luKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcmVxdWlyZWQgY29uc3RydWN0b3IgcGFyYW1ldGVyIHN0YXRpY3NDb2luJyk7XG4gICAgfVxuXG4gICAgdGhpcy5fc3RhdGljc0NvaW4gPSBzdGF0aWNzQ29pbjtcbiAgfVxuXG4gIHByb3RlY3RlZCBzdGF0aWMgaW5pdGlhbGl6ZWQgPSBmYWxzZTtcbiAgcHJvdGVjdGVkIHN0YXRpYyBNUEM6IEVkZHNhO1xuICBwcm90ZWN0ZWQgbmV0d29yayA9IHRoaXMuYml0Z28uZ2V0RW52KCkgPT09ICdwcm9kJyA/ICdtYWluJyA6ICd0ZXN0JztcblxuICBzdGF0aWMgY3JlYXRlSW5zdGFuY2UoYml0Z286IEJpdEdvQmFzZSwgc3RhdGljc0NvaW4/OiBSZWFkb25seTxTdGF0aWNzQmFzZUNvaW4+KTogQmFzZUNvaW4ge1xuICAgIHJldHVybiBuZXcgTmVhcihiaXRnbywgc3RhdGljc0NvaW4pO1xuICB9XG5cbiAgYWxsb3dzQWNjb3VudENvbnNvbGlkYXRpb25zKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIEZsYWcgaW5kaWNhdGluZyBpZiB0aGlzIGNvaW4gc3VwcG9ydHMgVFNTIHdhbGxldHMuXG4gICAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIFRTUyBXYWxsZXRzIGNhbiBiZSBjcmVhdGVkIGZvciB0aGlzIGNvaW5cbiAgICovXG4gIHN1cHBvcnRzVHNzKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqIGluaGVyaXRlZCBkb2MgKi9cbiAgZ2V0RGVmYXVsdE11bHRpc2lnVHlwZSgpOiBNdWx0aXNpZ1R5cGUge1xuICAgIHJldHVybiBtdWx0aXNpZ1R5cGVzLnRzcztcbiAgfVxuXG4gIC8qKlxuICAgKiBAaW5oZXJpdERvY1xuICAgKi9cbiAgZ2V0VG9rZW5FbmFibGVtZW50Q29uZmlnKCk6IFRva2VuRW5hYmxlbWVudENvbmZpZyB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHJlcXVpcmVzVG9rZW5FbmFibGVtZW50OiB0cnVlLFxuICAgICAgc3VwcG9ydHNNdWx0aXBsZVRva2VuRW5hYmxlbWVudHM6IGZhbHNlLFxuICAgIH07XG4gIH1cblxuICBnZXRNUENBbGdvcml0aG0oKTogTVBDQWxnb3JpdGhtIHtcbiAgICByZXR1cm4gJ2VkZHNhJztcbiAgfVxuXG4gIGdldENoYWluKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuX3N0YXRpY3NDb2luLm5hbWU7XG4gIH1cblxuICBnZXRCYXNlQ2hhaW4oKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5nZXRDaGFpbigpO1xuICB9XG5cbiAgZ2V0RmFtaWx5KCk6IENvaW5GYW1pbHkge1xuICAgIHJldHVybiB0aGlzLl9zdGF0aWNzQ29pbi5mYW1pbHk7XG4gIH1cblxuICBnZXRGdWxsTmFtZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLl9zdGF0aWNzQ29pbi5mdWxsTmFtZTtcbiAgfVxuXG4gIGdldEJhc2VGYWN0b3IoKTogYW55IHtcbiAgICByZXR1cm4gTWF0aC5wb3coMTAsIHRoaXMuX3N0YXRpY3NDb2luLmRlY2ltYWxQbGFjZXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZsYWcgZm9yIHNlbmRpbmcgdmFsdWUgb2YgMFxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiBva2F5IHRvIHNlbmQgMCB2YWx1ZSwgZmFsc2Ugb3RoZXJ3aXNlXG4gICAqL1xuICB2YWx1ZWxlc3NUcmFuc2ZlckFsbG93ZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlIGVkMjU1MTkga2V5IHBhaXJcbiAgICpcbiAgICogQHBhcmFtIHNlZWRcbiAgICogQHJldHVybnMge09iamVjdH0gb2JqZWN0IHdpdGggZ2VuZXJhdGVkIHB1YiwgcHJ2XG4gICAqL1xuICBnZW5lcmF0ZUtleVBhaXIoc2VlZD86IEJ1ZmZlcik6IEtleVBhaXIge1xuICAgIGNvbnN0IGtleVBhaXIgPSBzZWVkID8gbmV3IE5lYXJLZXlQYWlyKHsgc2VlZCB9KSA6IG5ldyBOZWFyS2V5UGFpcigpO1xuICAgIGNvbnN0IGtleXMgPSBrZXlQYWlyLmdldEtleXMoKTtcbiAgICBpZiAoIWtleXMucHJ2KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ01pc3NpbmcgcHJ2IGluIGtleSBnZW5lcmF0aW9uLicpO1xuICAgIH1cbiAgICByZXR1cm4ge1xuICAgICAgcHViOiBrZXlzLnB1YixcbiAgICAgIHBydjoga2V5cy5wcnYsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gYm9vbGVhbiBpbmRpY2F0aW5nIHdoZXRoZXIgaW5wdXQgaXMgdmFsaWQgcHVibGljIGtleSBmb3IgdGhlIGNvaW4uXG4gICAqXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBwdWIgdGhlIHB1YiB0byBiZSBjaGVja2VkXG4gICAqIEByZXR1cm5zIHtCb29sZWFufSBpcyBpdCB2YWxpZD9cbiAgICovXG4gIGlzVmFsaWRQdWIocHViOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gbmVhclV0aWxzLmlzVmFsaWRQdWJsaWNLZXkocHViKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gYm9vbGVhbiBpbmRpY2F0aW5nIHdoZXRoZXIgdGhlIHN1cHBsaWVkIHByaXZhdGUga2V5IGlzIGEgdmFsaWQgbmVhciBwcml2YXRlIGtleVxuICAgKlxuICAgKiBAcGFyYW0ge1N0cmluZ30gcHJ2IHRoZSBwcnYgdG8gYmUgY2hlY2tlZFxuICAgKiBAcmV0dXJucyB7Qm9vbGVhbn0gaXMgaXQgdmFsaWQ/XG4gICAqL1xuICBpc1ZhbGlkUHJ2KHBydjogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIG5lYXJVdGlscy5pc1ZhbGlkUHJpdmF0ZUtleShwcnYpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBib29sZWFuIGluZGljYXRpbmcgd2hldGhlciBpbnB1dCBpcyB2YWxpZCBwdWJsaWMga2V5IGZvciB0aGUgY29pblxuICAgKlxuICAgKiBAcGFyYW0ge1N0cmluZ30gYWRkcmVzcyB0aGUgcHViIHRvIGJlIGNoZWNrZWRcbiAgICogQHJldHVybnMge0Jvb2xlYW59IGlzIGl0IHZhbGlkP1xuICAgKi9cbiAgaXNWYWxpZEFkZHJlc3MoYWRkcmVzczogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIG5lYXJVdGlscy5pc1ZhbGlkQWRkcmVzcyhhZGRyZXNzKTtcbiAgfVxuXG4gIC8qKiBAaW5oZXJpdERvYyAqL1xuICBhc3luYyBzaWduTWVzc2FnZShrZXk6IEtleVBhaXIsIG1lc3NhZ2U6IHN0cmluZyB8IEJ1ZmZlcik6IFByb21pc2U8QnVmZmVyPiB7XG4gICAgY29uc3QgbmVhcktleXBhaXIgPSBuZXcgTmVhcktleVBhaXIoeyBwcnY6IGtleS5wcnYgfSk7XG4gICAgaWYgKEJ1ZmZlci5pc0J1ZmZlcihtZXNzYWdlKSkge1xuICAgICAgbWVzc2FnZSA9IGJhc2U1OC5lbmNvZGUobWVzc2FnZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIEJ1ZmZlci5mcm9tKG5lYXJLZXlwYWlyLnNpZ25NZXNzYWdlKG1lc3NhZ2UpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHBsYWluL3BhcnNlIHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSBwYXJhbXNcbiAgICovXG4gIGFzeW5jIGV4cGxhaW5UcmFuc2FjdGlvbihwYXJhbXM6IEV4cGxhaW5UcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPE5lYXJUcmFuc2FjdGlvbkV4cGxhbmF0aW9uPiB7XG4gICAgY29uc3QgZmFjdG9yeSA9IHRoaXMuZ2V0QnVpbGRlcigpO1xuICAgIGxldCByZWJ1aWx0VHJhbnNhY3Rpb246IEJhc2VUcmFuc2FjdGlvbjtcbiAgICBjb25zdCB0eFJhdyA9IHBhcmFtcy50eFByZWJ1aWxkLnR4SGV4O1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHRyYW5zYWN0aW9uQnVpbGRlciA9IGZhY3RvcnkuZnJvbSh0eFJhdyk7XG4gICAgICByZWJ1aWx0VHJhbnNhY3Rpb24gPSBhd2FpdCB0cmFuc2FjdGlvbkJ1aWxkZXIuYnVpbGQoKTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCB0cmFuc2FjdGlvbicpO1xuICAgIH1cblxuICAgIHJldHVybiByZWJ1aWx0VHJhbnNhY3Rpb24uZXhwbGFpblRyYW5zYWN0aW9uKCk7XG4gIH1cblxuICB2ZXJpZnlTaWduVHJhbnNhY3Rpb25QYXJhbXMocGFyYW1zOiBTaWduVHJhbnNhY3Rpb25PcHRpb25zKTogVmVyaWZpZWRUcmFuc2FjdGlvblBhcmFtZXRlcnMge1xuICAgIGNvbnN0IHBydiA9IHBhcmFtcy5wcnY7XG5cbiAgICBjb25zdCB0eEhleCA9IHBhcmFtcy50eFByZWJ1aWxkLnR4SGV4O1xuXG4gICAgaWYgKF8uaXNVbmRlZmluZWQodHhIZXgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgdHhQcmVidWlsZCBwYXJhbWV0ZXInKTtcbiAgICB9XG5cbiAgICBpZiAoIV8uaXNTdHJpbmcodHhIZXgpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYHR4UHJlYnVpbGQgbXVzdCBiZSBhbiBvYmplY3QsIGdvdCB0eXBlICR7dHlwZW9mIHR4SGV4fWApO1xuICAgIH1cblxuICAgIGlmIChfLmlzVW5kZWZpbmVkKHBydikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyBwcnYgcGFyYW1ldGVyIHRvIHNpZ24gdHJhbnNhY3Rpb24nKTtcbiAgICB9XG5cbiAgICBpZiAoIV8uaXNTdHJpbmcocHJ2KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBwcnYgbXVzdCBiZSBhIHN0cmluZywgZ290IHR5cGUgJHt0eXBlb2YgcHJ2fWApO1xuICAgIH1cblxuICAgIGlmICghXy5oYXMocGFyYW1zLnR4UHJlYnVpbGQsICdrZXknKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHB1YmxpYyBrZXkgcGFyYW1ldGVyIHRvIHNpZ24gdHJhbnNhY3Rpb24nKTtcbiAgICB9XG5cbiAgICAvLyBpZiB3ZSBhcmUgcmVjZWl2aW5nIGFkZHJlc3NlcyBkbyBub3QgdHJ5IHRvIGNvbnZlcnQgdGhlbVxuICAgIGNvbnN0IHNpZ25lciA9ICFuZWFyVXRpbHMuaXNWYWxpZEFkZHJlc3MocGFyYW1zLnR4UHJlYnVpbGQua2V5KVxuICAgICAgPyBuZXcgTmVhcktleVBhaXIoeyBwdWI6IHBhcmFtcy50eFByZWJ1aWxkLmtleSB9KS5nZXRBZGRyZXNzKClcbiAgICAgIDogcGFyYW1zLnR4UHJlYnVpbGQua2V5O1xuICAgIHJldHVybiB7IHR4SGV4LCBwcnYsIHNpZ25lciB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEFzc2VtYmxlIGtleWNoYWluIGFuZCBoYWxmLXNpZ24gcHJlYnVpbHQgdHJhbnNhY3Rpb25cbiAgICpcbiAgICogQHBhcmFtIHBhcmFtc1xuICAgKiBAcGFyYW0gcGFyYW1zLnR4UHJlYnVpbGQge1RyYW5zYWN0aW9uUHJlYnVpbGR9IHByZWJ1aWxkIG9iamVjdCByZXR1cm5lZCBieSBwbGF0Zm9ybVxuICAgKiBAcGFyYW0gcGFyYW1zLnBydiB7U3RyaW5nfSB1c2VyIHBydlxuICAgKiBAcGFyYW0gY2FsbGJhY2tcbiAgICogQHJldHVybnMge0JsdWViaXJkPFNpZ25lZFRyYW5zYWN0aW9uPn1cbiAgICovXG4gIGFzeW5jIHNpZ25UcmFuc2FjdGlvbihwYXJhbXM6IFNpZ25UcmFuc2FjdGlvbk9wdGlvbnMpOiBQcm9taXNlPFNpZ25lZFRyYW5zYWN0aW9uPiB7XG4gICAgY29uc3QgZmFjdG9yeSA9IHRoaXMuZ2V0QnVpbGRlcigpO1xuICAgIGNvbnN0IHR4QnVpbGRlciA9IGZhY3RvcnkuZnJvbShwYXJhbXMudHhQcmVidWlsZC50eEhleCk7XG4gICAgdHhCdWlsZGVyLnNpZ24oeyBrZXk6IHBhcmFtcy5wcnYgfSk7XG4gICAgY29uc3QgdHJhbnNhY3Rpb246IEJhc2VUcmFuc2FjdGlvbiA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuXG4gICAgaWYgKCF0cmFuc2FjdGlvbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHRyYW5zYWN0aW9uJyk7XG4gICAgfVxuXG4gICAgY29uc3Qgc2VyaWFsaXplZFR4ID0gKHRyYW5zYWN0aW9uIGFzIEJhc2VUcmFuc2FjdGlvbikudG9Ccm9hZGNhc3RGb3JtYXQoKTtcblxuICAgIHJldHVybiB7XG4gICAgICB0eEhleDogc2VyaWFsaXplZFR4LFxuICAgIH0gYXMgYW55O1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkcyBhIGZ1bmRzIHJlY292ZXJ5IHRyYW5zYWN0aW9uIHdpdGhvdXQgQml0R29cbiAgICogQHBhcmFtIHBhcmFtc1xuICAgKi9cbiAgYXN5bmMgcmVjb3ZlcihwYXJhbXM6IE1QQ1JlY292ZXJ5T3B0aW9ucyk6IFByb21pc2U8TVBDVHggfCBNUENTd2VlcFR4cz4ge1xuICAgIGlmICghcGFyYW1zLmJpdGdvS2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgYml0Z29LZXknKTtcbiAgICB9XG4gICAgaWYgKCFwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbiB8fCAhdGhpcy5pc1ZhbGlkQWRkcmVzcyhwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignaW52YWxpZCByZWNvdmVyeURlc3RpbmF0aW9uJyk7XG4gICAgfVxuICAgIGxldCBzdGFydElkeCA9IHBhcmFtcy5zdGFydGluZ1NjYW5JbmRleDtcbiAgICBpZiAoc3RhcnRJZHggPT09IHVuZGVmaW5lZCkge1xuICAgICAgc3RhcnRJZHggPSAwO1xuICAgIH0gZWxzZSBpZiAoIU51bWJlci5pc0ludGVnZXIoc3RhcnRJZHgpIHx8IHN0YXJ0SWR4IDwgMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHN0YXJ0aW5nIGluZGV4IHRvIHNjYW4gZm9yIGFkZHJlc3NlcycpO1xuICAgIH1cbiAgICBsZXQgbnVtSXRlcmF0aW9uID0gcGFyYW1zLnNjYW47XG4gICAgaWYgKG51bUl0ZXJhdGlvbiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBudW1JdGVyYXRpb24gPSAyMDtcbiAgICB9IGVsc2UgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKG51bUl0ZXJhdGlvbikgfHwgbnVtSXRlcmF0aW9uIDw9IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBzY2FubmluZyBmYWN0b3InKTtcbiAgICB9XG4gICAgY29uc3QgYml0Z29LZXkgPSBwYXJhbXMuYml0Z29LZXkucmVwbGFjZSgvXFxzL2csICcnKTtcbiAgICBjb25zdCBpc1Vuc2lnbmVkU3dlZXAgPSAhcGFyYW1zLnVzZXJLZXkgJiYgIXBhcmFtcy5iYWNrdXBLZXkgJiYgIXBhcmFtcy53YWxsZXRQYXNzcGhyYXNlO1xuICAgIGNvbnN0IE1QQyA9IGF3YWl0IEVERFNBTWV0aG9kcy5nZXRJbml0aWFsaXplZE1wY0luc3RhbmNlKCk7XG4gICAgY29uc3QgeyBzdG9yYWdlQW1vdW50UGVyQnl0ZSwgdHJhbnNmZXJDb3N0LCByZWNlaXB0Q29uZmlnIH0gPSBhd2FpdCB0aGlzLmdldFByb3RvY29sQ29uZmlnKCk7XG4gICAgbGV0IGlzU3RvcmFnZURlcG9zaXRFbmFibGVkID0gZmFsc2U7XG5cbiAgICBpZiAocGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzKSB7XG4gICAgICAvLyBjaGVjayBpZiByZWNlaXZlciBzdG9yYWdlIGRlcG9zaXQgaXMgZW5hYmxlZFxuICAgICAgaXNTdG9yYWdlRGVwb3NpdEVuYWJsZWQgPSBhd2FpdCB0aGlzLmNoZWNrSWZTdG9yYWdlRGVwb3NpdElzRW5hYmxlZChcbiAgICAgICAgcGFyYW1zLnJlY292ZXJ5RGVzdGluYXRpb24sXG4gICAgICAgIHBhcmFtcy50b2tlbkNvbnRyYWN0QWRkcmVzc1xuICAgICAgKTtcbiAgICB9XG5cbiAgICBmb3IgKGxldCBpID0gc3RhcnRJZHg7IGkgPCBudW1JdGVyYXRpb24gKyBzdGFydElkeDsgaSsrKSB7XG4gICAgICBjb25zdCBjdXJyUGF0aCA9IGBtLyR7aX1gO1xuICAgICAgY29uc3QgYWNjb3VudElkID0gTVBDLmRlcml2ZVVuaGFyZGVuZWQoYml0Z29LZXksIGN1cnJQYXRoKS5zbGljZSgwLCA2NCk7XG4gICAgICBsZXQgYXZhaWxhYmxlQmFsYW5jZSA9IG5ldyBCaWdOdW1iZXIoMCk7XG4gICAgICB0cnkge1xuICAgICAgICBhdmFpbGFibGVCYWxhbmNlID0gbmV3IEJpZ051bWJlcihhd2FpdCB0aGlzLmdldEFjY291bnRCYWxhbmNlKGFjY291bnRJZCwgc3RvcmFnZUFtb3VudFBlckJ5dGUpKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgLy8gVU5LTk9XTl9BQ0NPVU5UIGVycm9yIGluZGljYXRlcyB0aGF0IHRoZSBhZGRyZXNzIGhhcyBub3QgcGFydGFrZSBpbiBhbnkgdHJhbnNhY3Rpb24gc28gZmFyLCBzbyB3ZSB3aWxsXG4gICAgICAgIC8vIHRyZWF0IGl0IGFzIGEgemVybyBiYWxhbmNlIGFkZHJlc3NcbiAgICAgICAgaWYgKGUubWVzc2FnZSAhPT0gJ1VOS05PV05fQUNDT1VOVCcpIHtcbiAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAoYXZhaWxhYmxlQmFsYW5jZS50b051bWJlcigpIDw9IDApIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBjb25zdCBmZWVSZXNlcnZlID0gQmlnTnVtYmVyKE5ldHdvcmtzW3RoaXMubmV0d29ya10ubmVhci5mZWVSZXNlcnZlKTtcbiAgICAgIGNvbnN0IHN0b3JhZ2VSZXNlcnZlID0gQmlnTnVtYmVyKE5ldHdvcmtzW3RoaXMubmV0d29ya10ubmVhci5zdG9yYWdlUmVzZXJ2ZSk7XG5cbiAgICAgIC8vIGNoZWNrIGZvciBwb3NzaWJsZSB0b2tlbiByZWNvdmVyeSwgcmVjb3ZlciB0aGUgdG9rZW4gcHJvdmlkZWQgYnkgdGhlIHVzZXJcbiAgICAgIGlmIChwYXJhbXMudG9rZW5Db250cmFjdEFkZHJlc3MpIHtcbiAgICAgICAgY29uc3QgdG9rZW5OYW1lID0gbmVhclV0aWxzLmZpbmRUb2tlbk5hbWVGcm9tQ29udHJhY3RBZGRyZXNzKHBhcmFtcy50b2tlbkNvbnRyYWN0QWRkcmVzcyk7XG4gICAgICAgIGlmICghdG9rZW5OYW1lKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgYFRva2VuIG5hbWUgbm90IGZvdW5kIGZvciBjb250cmFjdCBhZGRyZXNzICR7cGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzfS4gVGhlIGFkZHJlc3MgbWF5IGJlIGludmFsaWQgb3IgdW5zdXBwb3J0ZWQuIFBsZWFzZSByZWZlciB0byB0aGUgc3VwcG9ydGVkIHRva2VucyBpbiB0aGUgQml0R28gZG9jdW1lbnRhdGlvbiBmb3IgZ3VpZGFuY2UuYFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgdG9rZW4gPSBuZWFyVXRpbHMuZ2V0VG9rZW5JbnN0YW5jZUZyb21Ub2tlbk5hbWUodG9rZW5OYW1lKTtcbiAgICAgICAgaWYgKCF0b2tlbikge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIGBUb2tlbiBpbnN0YW5jZSBjb3VsZCBub3QgYmUgY3JlYXRlZCBmb3IgdG9rZW4gbmFtZSAke3Rva2VuTmFtZX0uIFRoZSB0b2tlbiBtYXkgYmUgaW52YWxpZCBvciB1bnN1cHBvcnRlZC4gUGxlYXNlIHJlZmVyIHRvIHRoZSBzdXBwb3J0ZWQgdG9rZW5zIGluIHRoZSBCaXRHbyBkb2N1bWVudGF0aW9uIGZvciBndWlkYW5jZS5gXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgYXZhaWxhYmxlVG9rZW5CYWxhbmNlOiBCaWdOdW1iZXI7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXZhaWxhYmxlVG9rZW5CYWxhbmNlID0gbmV3IEJpZ051bWJlcihcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuZ2V0QWNjb3VudEZ1bmdpYmxlVG9rZW5CYWxhbmNlKGFjY291bnRJZCwgcGFyYW1zLnRva2VuQ29udHJhY3RBZGRyZXNzKVxuICAgICAgICAgICk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICB0aHJvdyBlO1xuICAgICAgICB9XG4gICAgICAgIGlmIChhdmFpbGFibGVUb2tlbkJhbGFuY2UudG9OdW1iZXIoKSA8PSAwKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgbmV0QW1vdW50ID0gYXZhaWxhYmxlQmFsYW5jZVxuICAgICAgICAgIC5taW51cyhuZWFyVXRpbHMuY29udmVydEdhc1VuaXRzVG9Zb2N0b05lYXIoTUFYX0dBU19MSU1JVF9GT1JfRlRfVFJBTlNGRVIpKVxuICAgICAgICAgIC5taW51cyhmZWVSZXNlcnZlKVxuICAgICAgICAgIC5taW51cyhzdG9yYWdlUmVzZXJ2ZSk7XG4gICAgICAgIGlmIChuZXRBbW91bnQudG9OdW1iZXIoKSA8PSAwKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgYEZvdW5kIGFkZHJlc3MgJHtpfSB3aXRoIG5vbi16ZXJvIGZ1bmQgYnV0IGZ1bmQgaXMgaW5zdWZmaWNpZW50IHRvIHN1cHBvcnQgYSB0b2tlbiByZWNvdmVyIGAgK1xuICAgICAgICAgICAgICBgdHJhbnNhY3Rpb24uIFBsZWFzZSBzdGFydCB0aGUgbmV4dCBzY2FuIGF0IGFkZHJlc3MgaW5kZXggJHtpICsgMX0uYFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMucmVjb3Zlck5lYXJUb2tlbihcbiAgICAgICAgICBwYXJhbXMsXG4gICAgICAgICAgdG9rZW4sXG4gICAgICAgICAgYWNjb3VudElkLFxuICAgICAgICAgIGN1cnJQYXRoLFxuICAgICAgICAgIGksXG4gICAgICAgICAgYml0Z29LZXksXG4gICAgICAgICAgaXNTdG9yYWdlRGVwb3NpdEVuYWJsZWQsXG4gICAgICAgICAgYXZhaWxhYmxlVG9rZW5CYWxhbmNlLFxuICAgICAgICAgIGlzVW5zaWduZWRTd2VlcFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBmaXJzdCBidWlsZCB0aGUgdW5zaWduZWQgdHhuXG4gICAgICBjb25zdCBiczU4RW5jb2RlZFB1YmxpY0tleSA9IG5lYXJBUEkudXRpbHMuc2VyaWFsaXplLmJhc2VfZW5jb2RlKG5ldyBVaW50OEFycmF5KEJ1ZmZlci5mcm9tKGFjY291bnRJZCwgJ2hleCcpKSk7XG4gICAgICBjb25zdCB7IG5vbmNlLCBibG9ja0hhc2ggfSA9IGF3YWl0IHRoaXMuZ2V0QWNjZXNzS2V5KHsgYWNjb3VudElkLCBiczU4RW5jb2RlZFB1YmxpY0tleSB9KTtcbiAgICAgIGNvbnN0IGdhc1ByaWNlID0gYXdhaXQgdGhpcy5nZXRHYXNQcmljZShibG9ja0hhc2gpO1xuICAgICAgY29uc3QgZ2FzUHJpY2VGaXJzdEJsb2NrID0gbmV3IEJpZ051bWJlcihnYXNQcmljZSk7XG4gICAgICBjb25zdCBnYXNQcmljZVNlY29uZEJsb2NrID0gZ2FzUHJpY2VGaXJzdEJsb2NrLm11bHRpcGxpZWRCeSgxLjA1KTtcbiAgICAgIGNvbnN0IHRvdGFsR2FzUmVxdWlyZWQgPSBuZXcgQmlnTnVtYmVyKHRyYW5zZmVyQ29zdC5zZW5kU2lyKVxuICAgICAgICAucGx1cyhyZWNlaXB0Q29uZmlnLnNlbmRTaXIpXG4gICAgICAgIC5tdWx0aXBsaWVkQnkoZ2FzUHJpY2VGaXJzdEJsb2NrKVxuICAgICAgICAucGx1cyhuZXcgQmlnTnVtYmVyKHRyYW5zZmVyQ29zdC5leGVjdXRpb24pLnBsdXMocmVjZWlwdENvbmZpZy5leGVjdXRpb24pLm11bHRpcGxpZWRCeShnYXNQcmljZVNlY29uZEJsb2NrKSk7XG4gICAgICAvLyBhZGRpbmcgc29tZSBwYWRkaW5nIHRvIG1ha2Ugc3VyZSB0aGUgZ2FzIGRvZXNuJ3QgZ28gYmVsb3cgcmVxdWlyZWQgZ2FzIGJ5IG5ldHdvcmtcbiAgICAgIGNvbnN0IHRvdGFsR2FzV2l0aFBhZGRpbmcgPSB0b3RhbEdhc1JlcXVpcmVkLm11bHRpcGxpZWRCeSgxLjUpO1xuICAgICAgY29uc3QgbmV0QW1vdW50ID0gYXZhaWxhYmxlQmFsYW5jZS5taW51cyh0b3RhbEdhc1dpdGhQYWRkaW5nKS5taW51cyhmZWVSZXNlcnZlKS5taW51cyhzdG9yYWdlUmVzZXJ2ZSk7XG4gICAgICBpZiAobmV0QW1vdW50LnRvTnVtYmVyKCkgPD0gMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgYEZvdW5kIGFkZHJlc3MgJHtpfSB3aXRoIG5vbi16ZXJvIGZ1bmQgYnV0IGZ1bmQgaXMgaW5zdWZmaWNpZW50IHRvIHN1cHBvcnQgYSByZWNvdmVyIGAgK1xuICAgICAgICAgICAgYHRyYW5zYWN0aW9uLiBQbGVhc2Ugc3RhcnQgdGhlIG5leHQgc2NhbiBhdCBhZGRyZXNzIGluZGV4ICR7aSArIDF9LmBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGZhY3RvcnkgPSBuZXcgVHJhbnNhY3Rpb25CdWlsZGVyRmFjdG9yeShjb2lucy5nZXQodGhpcy5nZXRDaGFpbigpKSk7XG4gICAgICBjb25zdCB0eEJ1aWxkZXIgPSBmYWN0b3J5XG4gICAgICAgIC5nZXRUcmFuc2ZlckJ1aWxkZXIoKVxuICAgICAgICAuc2VuZGVyKGFjY291bnRJZCwgYWNjb3VudElkKVxuICAgICAgICAubm9uY2Uobm9uY2UpXG4gICAgICAgIC5yZWNlaXZlcklkKHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uKVxuICAgICAgICAucmVjZW50QmxvY2tIYXNoKGJsb2NrSGFzaClcbiAgICAgICAgLmFtb3VudChuZXRBbW91bnQudG9GaXhlZCgpKTtcbiAgICAgIGNvbnN0IHVuc2lnbmVkVHJhbnNhY3Rpb24gPSAoYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCkpIGFzIFRyYW5zYWN0aW9uO1xuICAgICAgbGV0IHNlcmlhbGl6ZWRUeCA9IHVuc2lnbmVkVHJhbnNhY3Rpb24udG9Ccm9hZGNhc3RGb3JtYXQoKTtcbiAgICAgIGlmICghaXNVbnNpZ25lZFN3ZWVwKSB7XG4gICAgICAgIHNlcmlhbGl6ZWRUeCA9IGF3YWl0IHRoaXMuc2lnblJlY292ZXJ5VHJhbnNhY3Rpb24odHhCdWlsZGVyLCBwYXJhbXMsIGN1cnJQYXRoLCBhY2NvdW50SWQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYnVpbGRVbnNpZ25lZFN3ZWVwVHJhbnNhY3Rpb24oXG4gICAgICAgICAgdHhCdWlsZGVyLFxuICAgICAgICAgIGFjY291bnRJZCxcbiAgICAgICAgICBwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbixcbiAgICAgICAgICBiaXRnb0tleSxcbiAgICAgICAgICBpLFxuICAgICAgICAgIGN1cnJQYXRoLFxuICAgICAgICAgIG5ldEFtb3VudCxcbiAgICAgICAgICB0b3RhbEdhc1dpdGhQYWRkaW5nXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICByZXR1cm4geyBzZXJpYWxpemVkVHg6IHNlcmlhbGl6ZWRUeCwgc2NhbkluZGV4OiBpIH07XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcignRGlkIG5vdCBmaW5kIGFuIGFkZHJlc3Mgd2l0aCBmdW5kcyB0byByZWNvdmVyJyk7XG4gIH1cblxuICAvKipcbiAgICogRnVuY3Rpb24gdG8gaGFuZGxlIG5lYXIgdG9rZW4gcmVjb3ZlcnlcbiAgICogQHBhcmFtIHtNUENSZWNvdmVyeU9wdGlvbnN9IHBhcmFtcyBtcGMgcmVjb3Zlcnkgb3B0aW9ucyBpbnB1dFxuICAgKiBAcGFyYW0ge05lcDE0MVRva2VufSB0b2tlbiB0aGUgdG9rZW4gb2JqZWN0XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzZW5kZXJBZGRyZXNzIHNlbmRlciBhZGRyZXNzXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBkZXJpdmF0aW9uUGF0aCB0aGUgZGVyaXZhdGlvbiBwYXRoXG4gICAqIEBwYXJhbSB7TnVtYmVyfSBpZHggY3VycmVudCBpbmRleFxuICAgKiBAcGFyYW0ge1N0cmluZ30gYml0Z29LZXkgYml0Z28ga2V5XG4gICAqIEBwYXJhbSB7Qm9vbGVhbn0gaXNTdG9yYWdlRGVwb3NpdEVuYWJsZWQgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgc3RvcmFnZSBkZXBvc2l0IGlzIGVuYWJsZWQgb24gdGhlIHJlY2VpdmVyXG4gICAqIEBwYXJhbSB7QmlnTnVtYmVyfSBhdmFpbGFibGVUb2tlbkJhbGFuY2UgY3VycmVudGx5IGF2YWlsYWJsZSB0b2tlbiBiYWxhbmNlIG9uIHRoZSBhZGRyZXNzXG4gICAqIEBwYXJhbSB7Qm9vbGVhbn0gaXNVbnNpZ25lZFN3ZWVwIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGl0IGlzIGFuIHVuc2lnbmVkIHN3ZWVwXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPE1QQ1R4IHwgTVBDU3dlZXBUeHM+fVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyByZWNvdmVyTmVhclRva2VuKFxuICAgIHBhcmFtczogTVBDUmVjb3ZlcnlPcHRpb25zLFxuICAgIHRva2VuOiBOZXAxNDFUb2tlbixcbiAgICBzZW5kZXJBZGRyZXNzOiBzdHJpbmcsXG4gICAgZGVyaXZhdGlvblBhdGg6IHN0cmluZyxcbiAgICBpZHg6IG51bWJlcixcbiAgICBiaXRnb0tleTogc3RyaW5nLFxuICAgIGlzU3RvcmFnZURlcG9zaXRFbmFibGVkOiBib29sZWFuLFxuICAgIGF2YWlsYWJsZVRva2VuQmFsYW5jZTogQmlnTnVtYmVyLFxuICAgIGlzVW5zaWduZWRTd2VlcDogYm9vbGVhblxuICApOiBQcm9taXNlPE1QQ1R4IHwgTVBDU3dlZXBUeHM+IHtcbiAgICBjb25zdCBmYWN0b3J5ID0gbmV3IFRyYW5zYWN0aW9uQnVpbGRlckZhY3RvcnkodG9rZW4pO1xuICAgIGNvbnN0IGJzNThFbmNvZGVkUHVibGljS2V5ID0gbmVhckFQSS51dGlscy5zZXJpYWxpemUuYmFzZV9lbmNvZGUobmV3IFVpbnQ4QXJyYXkoQnVmZmVyLmZyb20oc2VuZGVyQWRkcmVzcywgJ2hleCcpKSk7XG4gICAgY29uc3QgeyBub25jZSwgYmxvY2tIYXNoIH0gPSBhd2FpdCB0aGlzLmdldEFjY2Vzc0tleSh7IGFjY291bnRJZDogc2VuZGVyQWRkcmVzcywgYnM1OEVuY29kZWRQdWJsaWNLZXkgfSk7XG4gICAgY29uc3QgdHhCdWlsZGVyID0gZmFjdG9yeVxuICAgICAgLmdldEZ1bmdpYmxlVG9rZW5UcmFuc2ZlckJ1aWxkZXIoKVxuICAgICAgLnNlbmRlcihzZW5kZXJBZGRyZXNzLCBzZW5kZXJBZGRyZXNzKVxuICAgICAgLm5vbmNlKG5vbmNlKVxuICAgICAgLnJlY2VpdmVySWQodG9rZW4uY29udHJhY3RBZGRyZXNzKVxuICAgICAgLnJlY2VudEJsb2NrSGFzaChibG9ja0hhc2gpXG4gICAgICAuZnRSZWNlaXZlcklkKHBhcmFtcy5yZWNvdmVyeURlc3RpbmF0aW9uKVxuICAgICAgLmdhcyhNQVhfR0FTX0xJTUlUX0ZPUl9GVF9UUkFOU0ZFUilcbiAgICAgIC5kZXBvc2l0KCcxJylcbiAgICAgIC5hbW91bnQoYXZhaWxhYmxlVG9rZW5CYWxhbmNlLnRvU3RyaW5nKCkpO1xuICAgIGlmICghaXNTdG9yYWdlRGVwb3NpdEVuYWJsZWQpIHtcbiAgICAgIHR4QnVpbGRlci5hZGRTdG9yYWdlRGVwb3NpdCh7XG4gICAgICAgIGRlcG9zaXQ6IEJpZ0ludCh0b2tlbi5zdG9yYWdlRGVwb3NpdEFtb3VudCksXG4gICAgICAgIGdhczogQmlnSW50KE1BWF9HQVNfTElNSVRfRk9SX0ZUX1RSQU5TRkVSKSxcbiAgICAgICAgYWNjb3VudElkOiBwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbixcbiAgICAgIH0pO1xuICAgIH1cbiAgICBpZiAoaXNVbnNpZ25lZFN3ZWVwKSB7XG4gICAgICByZXR1cm4gdGhpcy5idWlsZFVuc2lnbmVkU3dlZXBUcmFuc2FjdGlvbihcbiAgICAgICAgdHhCdWlsZGVyLFxuICAgICAgICBzZW5kZXJBZGRyZXNzLFxuICAgICAgICBwYXJhbXMucmVjb3ZlcnlEZXN0aW5hdGlvbixcbiAgICAgICAgYml0Z29LZXksXG4gICAgICAgIGlkeCxcbiAgICAgICAgZGVyaXZhdGlvblBhdGgsXG4gICAgICAgIGF2YWlsYWJsZVRva2VuQmFsYW5jZSxcbiAgICAgICAgbmV3IEJpZ051bWJlcihuZWFyVXRpbHMuY29udmVydEdhc1VuaXRzVG9Zb2N0b05lYXIoTUFYX0dBU19MSU1JVF9GT1JfRlRfVFJBTlNGRVIpKSxcbiAgICAgICAgdG9rZW5cbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IHNlcmlhbGl6ZWRUeCA9IGF3YWl0IHRoaXMuc2lnblJlY292ZXJ5VHJhbnNhY3Rpb24odHhCdWlsZGVyLCBwYXJhbXMsIGRlcml2YXRpb25QYXRoLCBzZW5kZXJBZGRyZXNzKTtcbiAgICAgIHJldHVybiB7IHNlcmlhbGl6ZWRUeDogc2VyaWFsaXplZFR4LCBzY2FuSW5kZXg6IGlkeCB9O1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBGdW5jdGlvbiB0byBidWlsZCB1bnNpZ25lZCBzd2VlcCB0cmFuc2FjdGlvblxuICAgKiBAcGFyYW0ge1RyYW5zYWN0aW9uQnVpbGRlcn0gdHhCdWlsZGVyIHRoZSBuZWFyIHRyYW5zYWN0aW9uIGJ1aWxkZXJcbiAgICogQHBhcmFtIHtTdHJpbmd9IHNlbmRlckFkZHJlc3Mgc2VuZGVyIGFkZHJlc3NcbiAgICogQHBhcmFtIHtTdHJpbmd9IHJlY2VpdmVyQWRkcmVzcyB0aGUgcmVjZWl2ZXIgYWRkcmVzc1xuICAgKiBAcGFyYW0ge1N0cmluZ30gYml0Z29LZXkgYml0Z28ga2V5XG4gICAqIEBwYXJhbSB7TnVtYmVyfSBpbmRleCBjdXJyZW50IGluZGV4XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBkZXJpdmF0aW9uUGF0aCB0aGUgZGVyaXZhdGlvbiBwYXRoXG4gICAqIEBwYXJhbSB7QmlnTnVtYmVyfSBuZXRBbW91bnQgbmV0IGFtb3VudCB0byBiZSByZWNvdmVyZWRcbiAgICogQHBhcmFtIHtCaWdOdW1iZXJ9IG5ldEdhcyBuZXQgZ2FzIHJlcXVpcmVkXG4gICAqIEBwYXJhbSB7TmVwMTQxVG9rZW59IHRva2VuIG9wdGlvbmFsIG5lcDE0MSB0b2tlbiBpbnN0YW5jZVxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxNUENTd2VlcFR4cz59XG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGJ1aWxkVW5zaWduZWRTd2VlcFRyYW5zYWN0aW9uKFxuICAgIHR4QnVpbGRlcjogVHJhbnNhY3Rpb25CdWlsZGVyLFxuICAgIHNlbmRlckFkZHJlc3M6IHN0cmluZyxcbiAgICByZWNlaXZlckFkZHJlc3M6IHN0cmluZyxcbiAgICBiaXRnb0tleTogc3RyaW5nLFxuICAgIGluZGV4OiBudW1iZXIsXG4gICAgZGVyaXZhdGlvblBhdGg6IHN0cmluZyxcbiAgICBuZXRBbW91bnQ6IEJpZ051bWJlcixcbiAgICBuZXRHYXM6IEJpZ051bWJlcixcbiAgICB0b2tlbj86IE5lcDE0MVRva2VuXG4gICk6IFByb21pc2U8TVBDU3dlZXBUeHM+IHtcbiAgICBjb25zdCBpc1Rva2VuVHJhbnNhY3Rpb24gPSAhIXRva2VuO1xuICAgIGNvbnN0IHVuc2lnbmVkVHJhbnNhY3Rpb24gPSAoYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCkpIGFzIFRyYW5zYWN0aW9uO1xuICAgIGNvbnN0IHNlcmlhbGl6ZWRUeCA9IHVuc2lnbmVkVHJhbnNhY3Rpb24udG9Ccm9hZGNhc3RGb3JtYXQoKTtcbiAgICBjb25zdCB3YWxsZXRDb2luID0gaXNUb2tlblRyYW5zYWN0aW9uID8gdG9rZW4ubmFtZSA6IHRoaXMuZ2V0Q2hhaW4oKTtcbiAgICBjb25zdCBpbnB1dHMgPSBbXG4gICAgICB7XG4gICAgICAgIGFkZHJlc3M6IHNlbmRlckFkZHJlc3MsXG4gICAgICAgIHZhbHVlU3RyaW5nOiBuZXRBbW91bnQudG9TdHJpbmcoKSxcbiAgICAgICAgdmFsdWU6IG5ldEFtb3VudC50b051bWJlcigpLFxuICAgICAgfSxcbiAgICBdO1xuICAgIGNvbnN0IG91dHB1dHMgPSBbXG4gICAgICB7XG4gICAgICAgIGFkZHJlc3M6IHJlY2VpdmVyQWRkcmVzcyxcbiAgICAgICAgdmFsdWVTdHJpbmc6IG5ldEFtb3VudC50b1N0cmluZygpLFxuICAgICAgICBjb2luTmFtZTogd2FsbGV0Q29pbixcbiAgICAgIH0sXG4gICAgXTtcbiAgICBjb25zdCBzcGVuZEFtb3VudCA9IG5ldEFtb3VudC50b1N0cmluZygpO1xuICAgIGNvbnN0IHBhcnNlZFR4ID0geyBpbnB1dHM6IGlucHV0cywgb3V0cHV0czogb3V0cHV0cywgc3BlbmRBbW91bnQ6IHNwZW5kQW1vdW50LCB0eXBlOiAnJyB9O1xuICAgIGNvbnN0IGZlZUluZm8gPSB7IGZlZTogbmV0R2FzLnRvTnVtYmVyKCksIGZlZVN0cmluZzogbmV0R2FzLnRvRml4ZWQoKSB9OyAvLyBJbmNsdWRlIGdhcyBmZWVzXG5cbiAgICBjb25zdCB0cmFuc2FjdGlvbjogTVBDVHggPSB7XG4gICAgICBzZXJpYWxpemVkVHg6IHNlcmlhbGl6ZWRUeCwgLy8gU2VyaWFsaXplZCB1bnNpZ25lZCB0cmFuc2FjdGlvblxuICAgICAgc2NhbkluZGV4OiBpbmRleCwgLy8gQ3VycmVudCBpbmRleCBpbiB0aGUgc2NhblxuICAgICAgY29pbjogd2FsbGV0Q29pbixcbiAgICAgIHNpZ25hYmxlSGV4OiB1bnNpZ25lZFRyYW5zYWN0aW9uLnNpZ25hYmxlUGF5bG9hZC50b1N0cmluZygnaGV4JyksIC8vIEhleCBwYXlsb2FkIGZvciBzaWduaW5nXG4gICAgICBkZXJpdmF0aW9uUGF0aDogZGVyaXZhdGlvblBhdGgsIC8vIERlcml2YXRpb24gcGF0aCBmb3IgdGhlIGFjY291bnRcbiAgICAgIHBhcnNlZFR4OiBwYXJzZWRUeCxcbiAgICAgIGZlZUluZm86IGZlZUluZm8sXG4gICAgICBjb2luU3BlY2lmaWM6IHsgY29tbW9uS2V5Y2hhaW46IGJpdGdvS2V5IH0sIC8vIEluY2x1ZGUgYmxvY2sgaGFzaCBmb3IgTkVBUlxuICAgIH07XG5cbiAgICBjb25zdCB0cmFuc2FjdGlvbnM6IE1QQ1Vuc2lnbmVkVHhbXSA9IFt7IHVuc2lnbmVkVHg6IHRyYW5zYWN0aW9uLCBzaWduYXR1cmVTaGFyZXM6IFtdIH1dO1xuICAgIGNvbnN0IHR4UmVxdWVzdDogUmVjb3ZlcnlUeFJlcXVlc3QgPSB7XG4gICAgICB0cmFuc2FjdGlvbnM6IHRyYW5zYWN0aW9ucyxcbiAgICAgIHdhbGxldENvaW46IHdhbGxldENvaW4sXG4gICAgfTtcbiAgICByZXR1cm4geyB0eFJlcXVlc3RzOiBbdHhSZXF1ZXN0XSB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEZ1bmN0aW9uIHRvIHNpZ24gdGhlIHJlY292ZXJ5IHRyYW5zYWN0aW9uXG4gICAqIEBwYXJhbSB7VHJhbnNhY3Rpb25CdWlsZGVyfSB0eEJ1aWxkZXIgdGhlIG5lYXIgdHJhbnNhY3Rpb24gYnVpbGRlclxuICAgKiBAcGFyYW0ge01QQ1JlY292ZXJ5T3B0aW9uc30gcGFyYW1zIG1wYyByZWNvdmVyeSBvcHRpb25zIGlucHV0XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBkZXJpdmF0aW9uUGF0aCB0aGUgZGVyaXZhdGlvbiBwYXRoXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzZW5kZXJBZGRyZXNzIHRoZSBzZW5kZXIgYWRkcmVzc1xuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxTdHJpbmc+fVxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyBzaWduUmVjb3ZlcnlUcmFuc2FjdGlvbihcbiAgICB0eEJ1aWxkZXI6IFRyYW5zYWN0aW9uQnVpbGRlcixcbiAgICBwYXJhbXM6IE1QQ1JlY292ZXJ5T3B0aW9ucyxcbiAgICBkZXJpdmF0aW9uUGF0aDogc3RyaW5nLFxuICAgIHNlbmRlckFkZHJlc3M6IHN0cmluZ1xuICApOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IHVuc2lnbmVkVHJhbnNhY3Rpb24gPSAoYXdhaXQgdHhCdWlsZGVyLmJ1aWxkKCkpIGFzIFRyYW5zYWN0aW9uO1xuICAgIC8vIFNpZ24gdGhlIHR4blxuICAgIC8qICoqKioqKioqKioqKioqKioqIFNUQVJUICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuICAgIC8vIFRPRE8oQkctNTEwOTIpOiBUaGlzIGxvb2tzIGxpa2UgYSBjb21tb24gcGFydCB3aGljaCBjYW4gYmUgZXh0cmFjdGVkIG91dCB0b29cbiAgICBpZiAoIXBhcmFtcy51c2VyS2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgdXNlcktleScpO1xuICAgIH1cbiAgICBpZiAoIXBhcmFtcy5iYWNrdXBLZXkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyBiYWNrdXBLZXknKTtcbiAgICB9XG4gICAgaWYgKCFwYXJhbXMud2FsbGV0UGFzc3BocmFzZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHdhbGxldCBwYXNzcGhyYXNlJyk7XG4gICAgfVxuXG4gICAgLy8gQ2xlYW4gdXAgd2hpdGVzcGFjZSBmcm9tIGVudGVyZWQgdmFsdWVzXG4gICAgY29uc3QgdXNlcktleSA9IHBhcmFtcy51c2VyS2V5LnJlcGxhY2UoL1xccy9nLCAnJyk7XG4gICAgY29uc3QgYmFja3VwS2V5ID0gcGFyYW1zLmJhY2t1cEtleS5yZXBsYWNlKC9cXHMvZywgJycpO1xuXG4gICAgLy8gRGVjcnlwdCBwcml2YXRlIGtleXMgZnJvbSBLZXlDYXJkIHZhbHVlc1xuICAgIGxldCB1c2VyUHJ2O1xuICAgIHRyeSB7XG4gICAgICB1c2VyUHJ2ID0gdGhpcy5iaXRnby5kZWNyeXB0KHtcbiAgICAgICAgaW5wdXQ6IHVzZXJLZXksXG4gICAgICAgIHBhc3N3b3JkOiBwYXJhbXMud2FsbGV0UGFzc3BocmFzZSxcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRXJyb3IgZGVjcnlwdGluZyB1c2VyIGtleWNoYWluOiAke2UubWVzc2FnZX1gKTtcbiAgICB9XG4gICAgLyoqIFRPRE8gQkctNTI0MTkgSW1wbGVtZW50IENvZGVjIGZvciBwYXJzaW5nICovXG4gICAgY29uc3QgdXNlclNpZ25pbmdNYXRlcmlhbCA9IEpTT04ucGFyc2UodXNlclBydikgYXMgRUREU0FNZXRob2RUeXBlcy5Vc2VyU2lnbmluZ01hdGVyaWFsO1xuXG4gICAgbGV0IGJhY2t1cFBydjtcbiAgICB0cnkge1xuICAgICAgYmFja3VwUHJ2ID0gdGhpcy5iaXRnby5kZWNyeXB0KHtcbiAgICAgICAgaW5wdXQ6IGJhY2t1cEtleSxcbiAgICAgICAgcGFzc3dvcmQ6IHBhcmFtcy53YWxsZXRQYXNzcGhyYXNlLFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvciBkZWNyeXB0aW5nIGJhY2t1cCBrZXljaGFpbjogJHtlLm1lc3NhZ2V9YCk7XG4gICAgfVxuICAgIGNvbnN0IGJhY2t1cFNpZ25pbmdNYXRlcmlhbCA9IEpTT04ucGFyc2UoYmFja3VwUHJ2KSBhcyBFRERTQU1ldGhvZFR5cGVzLkJhY2t1cFNpZ25pbmdNYXRlcmlhbDtcbiAgICAvKiAqKioqKioqKioqKioqKioqKioqKioqIEVORCAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuICAgIC8vIGFkZCBzaWduYXR1cmVcbiAgICBjb25zdCBzaWduYXR1cmVIZXggPSBhd2FpdCBFRERTQU1ldGhvZHMuZ2V0VFNTU2lnbmF0dXJlKFxuICAgICAgdXNlclNpZ25pbmdNYXRlcmlhbCxcbiAgICAgIGJhY2t1cFNpZ25pbmdNYXRlcmlhbCxcbiAgICAgIGRlcml2YXRpb25QYXRoLFxuICAgICAgdW5zaWduZWRUcmFuc2FjdGlvblxuICAgICk7XG4gICAgY29uc3QgcHVibGljS2V5T2JqID0geyBwdWI6IHNlbmRlckFkZHJlc3MgfTtcbiAgICB0eEJ1aWxkZXIuYWRkU2lnbmF0dXJlKHB1YmxpY0tleU9iaiBhcyBQdWJsaWNLZXksIHNpZ25hdHVyZUhleCk7XG5cbiAgICBjb25zdCBjb21wbGV0ZWRUcmFuc2FjdGlvbiA9IGF3YWl0IHR4QnVpbGRlci5idWlsZCgpO1xuICAgIHJldHVybiBjb21wbGV0ZWRUcmFuc2FjdGlvbi50b0Jyb2FkY2FzdEZvcm1hdCgpO1xuICB9XG5cbiAgYXN5bmMgY3JlYXRlQnJvYWRjYXN0YWJsZVN3ZWVwVHJhbnNhY3Rpb24ocGFyYW1zOiBNUENTd2VlcFJlY292ZXJ5T3B0aW9ucyk6IFByb21pc2U8TVBDVHhzPiB7XG4gICAgY29uc3QgcmVxID0gcGFyYW1zLnNpZ25hdHVyZVNoYXJlcztcbiAgICBjb25zdCBicm9hZGNhc3RhYmxlVHJhbnNhY3Rpb25zOiBNUENUeFtdID0gW107XG4gICAgbGV0IGxhc3RTY2FuSW5kZXggPSAwO1xuXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCByZXEubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IE1QQyA9IGF3YWl0IEVERFNBTWV0aG9kcy5nZXRJbml0aWFsaXplZE1wY0luc3RhbmNlKCk7XG4gICAgICBjb25zdCB0cmFuc2FjdGlvbiA9IHJlcVtpXS50eFJlcXVlc3QudHJhbnNhY3Rpb25zWzBdLnVuc2lnbmVkVHg7XG5cbiAgICAgIC8vIFZhbGlkYXRlIHNpZ25hdHVyZSBzaGFyZXNcbiAgICAgIGlmICghcmVxW2ldLm92YyB8fCAhcmVxW2ldLm92Y1swXS5lZGRzYVNpZ25hdHVyZSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ01pc3Npbmcgc2lnbmF0dXJlKHMpJyk7XG4gICAgICB9XG4gICAgICBjb25zdCBzaWduYXR1cmUgPSByZXFbaV0ub3ZjWzBdLmVkZHNhU2lnbmF0dXJlO1xuXG4gICAgICAvLyBWYWxpZGF0ZSBzaWduYWJsZSBoZXhcbiAgICAgIGlmICghdHJhbnNhY3Rpb24uc2lnbmFibGVIZXgpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdNaXNzaW5nIHNpZ25hYmxlIGhleCcpO1xuICAgICAgfVxuICAgICAgY29uc3QgbWVzc2FnZUJ1ZmZlciA9IEJ1ZmZlci5mcm9tKHRyYW5zYWN0aW9uLnNpZ25hYmxlSGV4ISwgJ2hleCcpO1xuICAgICAgY29uc3QgcmVzdWx0ID0gTVBDLnZlcmlmeShtZXNzYWdlQnVmZmVyLCBzaWduYXR1cmUpO1xuICAgICAgaWYgKCFyZXN1bHQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHNpZ25hdHVyZScpO1xuICAgICAgfVxuXG4gICAgICAvLyBQcmVwYXJlIHRoZSBzaWduYXR1cmUgaW4gaGV4IGZvcm1hdFxuICAgICAgY29uc3Qgc2lnbmF0dXJlSGV4ID0gQnVmZmVyLmNvbmNhdChbQnVmZmVyLmZyb20oc2lnbmF0dXJlLlIsICdoZXgnKSwgQnVmZmVyLmZyb20oc2lnbmF0dXJlLnNpZ21hLCAnaGV4JyldKTtcblxuICAgICAgLy8gVmFsaWRhdGUgdHJhbnNhY3Rpb24tc3BlY2lmaWMgZmllbGRzXG4gICAgICBpZiAoIXRyYW5zYWN0aW9uLmNvaW5TcGVjaWZpYz8uY29tbW9uS2V5Y2hhaW4pIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdNaXNzaW5nIGNvbW1vbiBrZXljaGFpbicpO1xuICAgICAgfVxuICAgICAgY29uc3QgY29tbW9uS2V5Y2hhaW4gPSB0cmFuc2FjdGlvbi5jb2luU3BlY2lmaWMhLmNvbW1vbktleWNoYWluISBhcyBzdHJpbmc7XG5cbiAgICAgIGlmICghdHJhbnNhY3Rpb24uZGVyaXZhdGlvblBhdGgpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdNaXNzaW5nIGRlcml2YXRpb24gcGF0aCcpO1xuICAgICAgfVxuICAgICAgY29uc3QgZGVyaXZhdGlvblBhdGggPSB0cmFuc2FjdGlvbi5kZXJpdmF0aW9uUGF0aCBhcyBzdHJpbmc7XG5cbiAgICAgIC8vIERlcml2ZSBhY2NvdW50IElEIGFuZCBzZW5kZXIgYWRkcmVzc1xuICAgICAgY29uc3QgYWNjb3VudElkID0gTVBDLmRlcml2ZVVuaGFyZGVuZWQoY29tbW9uS2V5Y2hhaW4sIGRlcml2YXRpb25QYXRoKS5zbGljZSgwLCA2NCk7XG4gICAgICBjb25zdCB0eG5CdWlsZGVyID0gdGhpcy5nZXRCdWlsZGVyKCkuZnJvbSh0cmFuc2FjdGlvbi5zZXJpYWxpemVkVHggYXMgc3RyaW5nKTtcblxuICAgICAgLy8gQWRkIHRoZSBzaWduYXR1cmVcbiAgICAgIGNvbnN0IG5lYXJLZXlQYWlyID0gbmV3IE5lYXJLZXlQYWlyKHsgcHViOiBhY2NvdW50SWQgfSk7XG4gICAgICB0eG5CdWlsZGVyLmFkZFNpZ25hdHVyZSh7IHB1YjogbmVhcktleVBhaXIuZ2V0S2V5cygpLnB1YiB9LCBzaWduYXR1cmVIZXgpO1xuXG4gICAgICAvLyBGaW5hbGl6ZSBhbmQgc2VyaWFsaXplIHRoZSB0cmFuc2FjdGlvblxuICAgICAgY29uc3Qgc2lnbmVkVHJhbnNhY3Rpb24gPSBhd2FpdCB0eG5CdWlsZGVyLmJ1aWxkKCk7XG4gICAgICBjb25zdCBzZXJpYWxpemVkVHggPSBzaWduZWRUcmFuc2FjdGlvbi50b0Jyb2FkY2FzdEZvcm1hdCgpO1xuXG4gICAgICAvLyBBZGQgdGhlIHNpZ25lZCB0cmFuc2FjdGlvbiB0byB0aGUgbGlzdFxuICAgICAgYnJvYWRjYXN0YWJsZVRyYW5zYWN0aW9ucy5wdXNoKHtcbiAgICAgICAgc2VyaWFsaXplZFR4OiBzZXJpYWxpemVkVHgsXG4gICAgICAgIHNjYW5JbmRleDogdHJhbnNhY3Rpb24uc2NhbkluZGV4LFxuICAgICAgfSk7XG5cbiAgICAgIC8vIFVwZGF0ZSB0aGUgbGFzdCBzY2FuIGluZGV4IGlmIGFwcGxpY2FibGVcbiAgICAgIGlmIChpID09PSByZXEubGVuZ3RoIC0gMSAmJiB0cmFuc2FjdGlvbi5jb2luU3BlY2lmaWMhLmxhc3RTY2FuSW5kZXgpIHtcbiAgICAgICAgbGFzdFNjYW5JbmRleCA9IHRyYW5zYWN0aW9uLmNvaW5TcGVjaWZpYyEubGFzdFNjYW5JbmRleCBhcyBudW1iZXI7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gUmV0dXJuIHRoZSBicm9hZGNhc3RhYmxlIHRyYW5zYWN0aW9ucyBhbmQgdGhlIGxhc3Qgc2NhbiBpbmRleFxuICAgIHJldHVybiB7IHRyYW5zYWN0aW9uczogYnJvYWRjYXN0YWJsZVRyYW5zYWN0aW9ucywgbGFzdFNjYW5JbmRleCB9O1xuICB9XG5cbiAgLyoqXG4gICAqIE1ha2UgYSByZXF1ZXN0IHRvIG9uZSBvZiB0aGUgcHVibGljIEVPUyBub2RlcyBhdmFpbGFibGVcbiAgICogQHBhcmFtIHBhcmFtcy5wYXlsb2FkXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgZ2V0RGF0YUZyb21Ob2RlKHBhcmFtczogeyBwYXlsb2FkPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gfSk6IFByb21pc2U8cmVxdWVzdC5SZXNwb25zZT4ge1xuICAgIGNvbnN0IG5vZGVVcmxzID0gdGhpcy5nZXRQdWJsaWNOb2RlVXJscygpO1xuICAgIGZvciAoY29uc3Qgbm9kZVVybCBvZiBub2RlVXJscykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IHJlcXVlc3QucG9zdChub2RlVXJsKS5zZW5kKHBhcmFtcy5wYXlsb2FkKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY29uc29sZS5kZWJ1ZyhlKTtcbiAgICAgIH1cbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKGBVbmFibGUgdG8gY2FsbCBlbmRwb2ludDogJy8nIGZyb20gbm9kZXM6ICR7Xy5qb2luKG5vZGVVcmxzLCAnLCAnKX1gKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBhc3luYyBnZXRBY2Nlc3NLZXkoe1xuICAgIGFjY291bnRJZCxcbiAgICBiczU4RW5jb2RlZFB1YmxpY0tleSxcbiAgfToge1xuICAgIGFjY291bnRJZDogc3RyaW5nO1xuICAgIGJzNThFbmNvZGVkUHVibGljS2V5OiBzdHJpbmc7XG4gIH0pOiBQcm9taXNlPE5lYXJUeEJ1aWxkZXJQYXJhbXNGcm9tTm9kZT4ge1xuICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5nZXREYXRhRnJvbU5vZGUoe1xuICAgICAgcGF5bG9hZDoge1xuICAgICAgICBqc29ucnBjOiAnMi4wJyxcbiAgICAgICAgaWQ6ICdkb250Y2FyZScsXG4gICAgICAgIG1ldGhvZDogJ3F1ZXJ5JyxcbiAgICAgICAgcGFyYW1zOiB7XG4gICAgICAgICAgcmVxdWVzdF90eXBlOiAndmlld19hY2Nlc3Nfa2V5JyxcbiAgICAgICAgICBmaW5hbGl0eTogJ2ZpbmFsJyxcbiAgICAgICAgICBhY2NvdW50X2lkOiBhY2NvdW50SWQsXG4gICAgICAgICAgcHVibGljX2tleTogYnM1OEVuY29kZWRQdWJsaWNLZXksXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0pO1xuICAgIGlmIChyZXNwb25zZS5zdGF0dXMgIT09IDIwMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdBY2NvdW50IG5vdCBmb3VuZCcpO1xuICAgIH1cbiAgICBjb25zdCBhY2Nlc3NLZXkgPSByZXNwb25zZS5ib2R5LnJlc3VsdDtcbiAgICByZXR1cm4geyBub25jZTogYWNjZXNzS2V5Lm5vbmNlICsgMSwgYmxvY2tIYXNoOiBhY2Nlc3NLZXkuYmxvY2tfaGFzaCB9O1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIGdldEFjY291bnRCYWxhbmNlKGFjY291bnRJZDogc3RyaW5nLCBzdG9yYWdlQW1vdW50UGVyQnl0ZTogbnVtYmVyKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuZ2V0RGF0YUZyb21Ob2RlKHtcbiAgICAgIHBheWxvYWQ6IHtcbiAgICAgICAganNvbnJwYzogJzIuMCcsXG4gICAgICAgIGlkOiAnZG9udGNhcmUnLFxuICAgICAgICBtZXRob2Q6ICdxdWVyeScsXG4gICAgICAgIHBhcmFtczoge1xuICAgICAgICAgIHJlcXVlc3RfdHlwZTogJ3ZpZXdfYWNjb3VudCcsXG4gICAgICAgICAgZmluYWxpdHk6ICdmaW5hbCcsXG4gICAgICAgICAgYWNjb3VudF9pZDogYWNjb3VudElkLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9KTtcbiAgICBpZiAocmVzcG9uc2Uuc3RhdHVzICE9PSAyMDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRmFpbGVkIHRvIHF1ZXJ5IGFjY291bnQgaW5mb3JtYXRpb24nKTtcbiAgICB9XG4gICAgY29uc3QgZXJyb3JDYXVzZSA9IHJlc3BvbnNlLmJvZHkuZXJyb3I/LmNhdXNlLm5hbWU7XG4gICAgaWYgKGVycm9yQ2F1c2UgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGVycm9yQ2F1c2UpO1xuICAgIH1cblxuICAgIGNvbnN0IGFjY291bnQgPSByZXNwb25zZS5ib2R5LnJlc3VsdDtcbiAgICBjb25zdCBjb3N0UGVyQnl0ZSA9IG5ldyBCaWdOdW1iZXIoc3RvcmFnZUFtb3VudFBlckJ5dGUpO1xuICAgIGNvbnN0IHN0YXRlU3Rha2VkID0gbmV3IEJpZ051bWJlcihhY2NvdW50LnN0b3JhZ2VfdXNhZ2UpLm11bHRpcGxpZWRCeShjb3N0UGVyQnl0ZSk7XG4gICAgY29uc3Qgc3Rha2VkID0gbmV3IEJpZ051bWJlcihhY2NvdW50LmxvY2tlZCk7XG4gICAgY29uc3QgdG90YWxCYWxhbmNlID0gbmV3IEJpZ051bWJlcihhY2NvdW50LmFtb3VudCkucGx1cyhzdGFrZWQpO1xuICAgIGNvbnN0IGF2YWlsYWJsZUJhbGFuY2UgPSB0b3RhbEJhbGFuY2UubWludXMoQmlnTnVtYmVyLm1heChzdGFrZWQsIHN0YXRlU3Rha2VkKSk7XG4gICAgcmV0dXJuIGF2YWlsYWJsZUJhbGFuY2UudG9TdHJpbmcoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGdW5jdGlvbiB0byBnZXQgdGhlIGZ1bmdpYmxlIHRva2VuIGJhbGFuY2UgZm9yIGFuIGFjY291bnRcbiAgICogQHBhcmFtIHtTdHJpbmd9IGFjY291bnRJZCBhY2NvdW50IGZvciB3aGljaCB0aGUgZnQgYmFsYW5jZSB0byBiZSBmZXRjaGVkXG4gICAqIEBwYXJhbSB0b2tlbkNvbnRyYWN0QWRkcmVzcyB0aGUgdG9rZW4gY29udHJhY3QgYWRkcmVzc1xuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxTdHJpbmc+fVxuICAgKi9cbiAgcHJvdGVjdGVkIGFzeW5jIGdldEFjY291bnRGdW5naWJsZVRva2VuQmFsYW5jZShhY2NvdW50SWQ6IHN0cmluZywgdG9rZW5Db250cmFjdEFkZHJlc3M6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgY29uc3QgYmFzZTY0QXJncyA9IG5lYXJVdGlscy5jb252ZXJ0VG9CYXNlNjQoeyBhY2NvdW50X2lkOiBhY2NvdW50SWQgfSk7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLmdldERhdGFGcm9tTm9kZSh7XG4gICAgICBwYXlsb2FkOiB7XG4gICAgICAgIGpzb25ycGM6ICcyLjAnLFxuICAgICAgICBpZDogJ2RvbnRjYXJlJyxcbiAgICAgICAgbWV0aG9kOiAncXVlcnknLFxuICAgICAgICBwYXJhbXM6IHtcbiAgICAgICAgICByZXF1ZXN0X3R5cGU6ICdjYWxsX2Z1bmN0aW9uJyxcbiAgICAgICAgICBmaW5hbGl0eTogJ2ZpbmFsJyxcbiAgICAgICAgICBhY2NvdW50X2lkOiB0b2tlbkNvbnRyYWN0QWRkcmVzcyxcbiAgICAgICAgICBtZXRob2RfbmFtZTogJ2Z0X2JhbGFuY2Vfb2YnLFxuICAgICAgICAgIGFyZ3NfYmFzZTY0OiBiYXNlNjRBcmdzLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9KTtcbiAgICBpZiAocmVzcG9uc2Uuc3RhdHVzICE9PSAyMDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRmFpbGVkIHRvIGZldGNoIGZ0IGJhbGFuY2Ugb2YgdGhlIGFjY291bnQnKTtcbiAgICB9XG4gICAgY29uc3QgZXJyb3JDYXVzZSA9IHJlc3BvbnNlLmJvZHkuZXJyb3I/LmNhdXNlPy5uYW1lO1xuICAgIGlmIChlcnJvckNhdXNlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihlcnJvckNhdXNlKTtcbiAgICB9XG4gICAgY29uc3QgcmVzdWx0VWludDhBcnJheTogVWludDhBcnJheSA9IG5ldyBVaW50OEFycmF5KHJlc3BvbnNlLmJvZHkucmVzdWx0LnJlc3VsdCk7XG4gICAgY29uc3QgcmF3ID0gbmV3IFRleHREZWNvZGVyKCkuZGVjb2RlKHJlc3VsdFVpbnQ4QXJyYXkpO1xuICAgIHJldHVybiBKU09OLnBhcnNlKHJhdyk7XG4gIH1cblxuICAvKipcbiAgICogRnVuY3Rpb24gdG8gY2hlY2sgaWYgc3RvcmFnZSBkZXBvc2l0IGlzIGVuYWJsZWQgb24gYW4gYWRkcmVzcyBmb3IgYSB0b2tlblxuICAgKiBAcGFyYW0ge1N0cmluZ30gYWNjb3VudElkIGFjY291bnQgZm9yIHdoaWNoIHRoZSBzdG9yYWdlIGJhbGFuY2UgdG8gYmUgZmV0Y2hlZFxuICAgKiBAcGFyYW0gdG9rZW5Db250cmFjdEFkZHJlc3MgdGhlIHRva2VuIGNvbnRyYWN0IGFkZHJlc3NcbiAgICogQHJldHVybnMge1Byb21pc2U8Qm9vbGVhbj59IHRydWUgaWYgd2UgZmluZCB0aGUgc3RvcmFnZSBiYWxhbmNlLCBmYWxzZSBpZiByZXNwb25zZSBpcyBudWxsXG4gICAqL1xuICBwcm90ZWN0ZWQgYXN5bmMgY2hlY2tJZlN0b3JhZ2VEZXBvc2l0SXNFbmFibGVkKGFjY291bnRJZDogc3RyaW5nLCB0b2tlbkNvbnRyYWN0QWRkcmVzczogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgYmFzZTY0QXJncyA9IG5lYXJVdGlscy5jb252ZXJ0VG9CYXNlNjQoeyBhY2NvdW50X2lkOiBhY2NvdW50SWQgfSk7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLmdldERhdGFGcm9tTm9kZSh7XG4gICAgICBwYXlsb2FkOiB7XG4gICAgICAgIGpzb25ycGM6ICcyLjAnLFxuICAgICAgICBpZDogJ2RvbnRjYXJlJyxcbiAgICAgICAgbWV0aG9kOiAncXVlcnknLFxuICAgICAgICBwYXJhbXM6IHtcbiAgICAgICAgICByZXF1ZXN0X3R5cGU6ICdjYWxsX2Z1bmN0aW9uJyxcbiAgICAgICAgICBmaW5hbGl0eTogJ2ZpbmFsJyxcbiAgICAgICAgICBhY2NvdW50X2lkOiB0b2tlbkNvbnRyYWN0QWRkcmVzcyxcbiAgICAgICAgICBtZXRob2RfbmFtZTogJ3N0b3JhZ2VfYmFsYW5jZV9vZicsXG4gICAgICAgICAgYXJnc19iYXNlNjQ6IGJhc2U2NEFyZ3MsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0pO1xuICAgIGlmIChyZXNwb25zZS5zdGF0dXMgIT09IDIwMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdGYWlsZWQgdG8gZmV0Y2ggc3RvcmFnZSBkZXBvc2l0IG9mIHRoZSBhY2NvdW50Jyk7XG4gICAgfVxuICAgIGNvbnN0IGVycm9yQ2F1c2UgPSByZXNwb25zZS5ib2R5LmVycm9yPy5jYXVzZT8ubmFtZTtcbiAgICBpZiAoZXJyb3JDYXVzZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoZXJyb3JDYXVzZSk7XG4gICAgfVxuICAgIGNvbnN0IHJlc3VsdFVpbnQ4QXJyYXk6IFVpbnQ4QXJyYXkgPSBuZXcgVWludDhBcnJheShyZXNwb25zZS5ib2R5LnJlc3VsdC5yZXN1bHQpO1xuICAgIGNvbnN0IHJhdyA9IG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZShyZXN1bHRVaW50OEFycmF5KTtcbiAgICBjb25zdCBkZWNvZGVkID0gSlNPTi5wYXJzZShyYXcpO1xuICAgIHJldHVybiBkZWNvZGVkICE9PSBudWxsO1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIGdldFByb3RvY29sQ29uZmlnKCk6IFByb21pc2U8UHJvdG9jb2xDb25maWdPdXRwdXQ+IHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuZ2V0RGF0YUZyb21Ob2RlKHtcbiAgICAgIHBheWxvYWQ6IHtcbiAgICAgICAganNvbnJwYzogJzIuMCcsXG4gICAgICAgIGlkOiAnZG9udGNhcmUnLFxuICAgICAgICBtZXRob2Q6ICdFWFBFUklNRU5UQUxfcHJvdG9jb2xfY29uZmlnJyxcbiAgICAgICAgcGFyYW1zOiB7XG4gICAgICAgICAgZmluYWxpdHk6ICdmaW5hbCcsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0pO1xuICAgIGlmIChyZXNwb25zZS5zdGF0dXMgIT09IDIwMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdBY2NvdW50IG5vdCBmb3VuZCcpO1xuICAgIH1cblxuICAgIGNvbnN0IGNvbmZpZyA9IHJlc3BvbnNlLmJvZHkucmVzdWx0O1xuICAgIGNvbnN0IHN0b3JhZ2VBbW91bnRQZXJCeXRlID0gY29uZmlnLnJ1bnRpbWVfY29uZmlnLnN0b3JhZ2VfYW1vdW50X3Blcl9ieXRlO1xuICAgIGNvbnN0IHRyYW5zZmVyQ29zdEZyb21OZXR3b3JrID0gY29uZmlnLnJ1bnRpbWVfY29uZmlnLnRyYW5zYWN0aW9uX2Nvc3RzLmFjdGlvbl9jcmVhdGlvbl9jb25maWcudHJhbnNmZXJfY29zdDtcbiAgICBjb25zdCB0cmFuc2ZlckNvc3Q6IE5lYXJGZWVDb25maWcgPSB7XG4gICAgICBzZW5kU2lyOiB0cmFuc2ZlckNvc3RGcm9tTmV0d29yay5zZW5kX3NpcixcbiAgICAgIHNlbmROb3RTaXI6IHRyYW5zZmVyQ29zdEZyb21OZXR3b3JrLnNlbmRfbm90X3NpcixcbiAgICAgIGV4ZWN1dGlvbjogdHJhbnNmZXJDb3N0RnJvbU5ldHdvcmsuZXhlY3V0aW9uLFxuICAgIH07XG5cbiAgICBjb25zdCByZWNlaXB0Q29uZmlnRnJvbU5ldHdvcmsgPSBjb25maWcucnVudGltZV9jb25maWcudHJhbnNhY3Rpb25fY29zdHMuYWN0aW9uX3JlY2VpcHRfY3JlYXRpb25fY29uZmlnO1xuICAgIGNvbnN0IHJlY2VpcHRDb25maWc6IE5lYXJGZWVDb25maWcgPSB7XG4gICAgICBzZW5kU2lyOiByZWNlaXB0Q29uZmlnRnJvbU5ldHdvcmsuc2VuZF9zaXIsXG4gICAgICBzZW5kTm90U2lyOiByZWNlaXB0Q29uZmlnRnJvbU5ldHdvcmsuc2VuZF9ub3Rfc2lyLFxuICAgICAgZXhlY3V0aW9uOiByZWNlaXB0Q29uZmlnRnJvbU5ldHdvcmsuZXhlY3V0aW9uLFxuICAgIH07XG4gICAgcmV0dXJuIHsgc3RvcmFnZUFtb3VudFBlckJ5dGUsIHRyYW5zZmVyQ29zdCwgcmVjZWlwdENvbmZpZyB9O1xuICB9XG5cbiAgcHJvdGVjdGVkIGFzeW5jIGdldEdhc1ByaWNlKGJsb2NrSGFzaDogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuZ2V0RGF0YUZyb21Ob2RlKHtcbiAgICAgIHBheWxvYWQ6IHtcbiAgICAgICAganNvbnJwYzogJzIuMCcsXG4gICAgICAgIGlkOiAnZG9udGNhcmUnLFxuICAgICAgICBtZXRob2Q6ICdnYXNfcHJpY2UnLFxuICAgICAgICBwYXJhbXM6IFtibG9ja0hhc2hdLFxuICAgICAgfSxcbiAgICB9KTtcbiAgICBpZiAocmVzcG9uc2Uuc3RhdHVzICE9PSAyMDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQWNjb3VudCBub3QgZm91bmQnKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3BvbnNlLmJvZHkucmVzdWx0Lmdhc19wcmljZTtcbiAgfVxuXG4gIHByb3RlY3RlZCBnZXRQdWJsaWNOb2RlVXJscygpOiBzdHJpbmdbXSB7XG4gICAgcmV0dXJuIEVudmlyb25tZW50c1t0aGlzLmJpdGdvLmdldEVudigpXS5uZWFyTm9kZVVybHM7XG4gIH1cblxuICBhc3luYyBwYXJzZVRyYW5zYWN0aW9uKHBhcmFtczogTmVhclBhcnNlVHJhbnNhY3Rpb25PcHRpb25zKTogUHJvbWlzZTxOZWFyUGFyc2VkVHJhbnNhY3Rpb24+IHtcbiAgICBjb25zdCB0cmFuc2FjdGlvbkV4cGxhbmF0aW9uID0gYXdhaXQgdGhpcy5leHBsYWluVHJhbnNhY3Rpb24oe1xuICAgICAgdHhQcmVidWlsZDogcGFyYW1zLnR4UHJlYnVpbGQsXG4gICAgICBwdWJsaWNLZXk6IHBhcmFtcy5wdWJsaWNLZXksXG4gICAgICBmZWVJbmZvOiBwYXJhbXMuZmVlSW5mbyxcbiAgICB9KTtcblxuICAgIGlmICghdHJhbnNhY3Rpb25FeHBsYW5hdGlvbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHRyYW5zYWN0aW9uJyk7XG4gICAgfVxuXG4gICAgY29uc3QgbmVhclRyYW5zYWN0aW9uID0gdHJhbnNhY3Rpb25FeHBsYW5hdGlvbiBhcyBOZWFyVHJhbnNhY3Rpb25FeHBsYW5hdGlvbjtcbiAgICBpZiAobmVhclRyYW5zYWN0aW9uLm91dHB1dHMubGVuZ3RoIDw9IDApIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGlucHV0czogW10sXG4gICAgICAgIG91dHB1dHM6IFtdLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICBjb25zdCBzZW5kZXJBZGRyZXNzID0gbmVhclRyYW5zYWN0aW9uLm91dHB1dHNbMF0uYWRkcmVzcztcbiAgICBjb25zdCBmZWVBbW91bnQgPSBuZXcgQmlnTnVtYmVyKG5lYXJUcmFuc2FjdGlvbi5mZWUuZmVlID09PSAnJyA/ICcwJyA6IG5lYXJUcmFuc2FjdGlvbi5mZWUuZmVlKTtcblxuICAgIC8vIGFzc3VtZSAxIHNlbmRlciwgd2hvIGlzIGFsc28gdGhlIGZlZSBwYXllclxuICAgIGNvbnN0IGlucHV0cyA9IFtcbiAgICAgIHtcbiAgICAgICAgYWRkcmVzczogc2VuZGVyQWRkcmVzcyxcbiAgICAgICAgYW1vdW50OiBuZXcgQmlnTnVtYmVyKG5lYXJUcmFuc2FjdGlvbi5vdXRwdXRBbW91bnQpLnBsdXMoZmVlQW1vdW50KS50b0ZpeGVkKCksXG4gICAgICB9LFxuICAgIF07XG5cbiAgICBjb25zdCBvdXRwdXRzOiBUcmFuc2FjdGlvbk91dHB1dFtdID0gbmVhclRyYW5zYWN0aW9uLm91dHB1dHMubWFwKChvdXRwdXQpID0+IHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGFkZHJlc3M6IG91dHB1dC5hZGRyZXNzLFxuICAgICAgICBhbW91bnQ6IG5ldyBCaWdOdW1iZXIob3V0cHV0LmFtb3VudCkudG9GaXhlZCgpLFxuICAgICAgfTtcbiAgICB9KTtcblxuICAgIHJldHVybiB7XG4gICAgICBpbnB1dHMsXG4gICAgICBvdXRwdXRzLFxuICAgIH07XG4gIH1cblxuICBhc3luYyBpc1dhbGxldEFkZHJlc3MocGFyYW1zOiBWZXJpZnlBZGRyZXNzT3B0aW9ucyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIHRocm93IG5ldyBNZXRob2ROb3RJbXBsZW1lbnRlZEVycm9yKCk7XG4gIH1cblxuICBhc3luYyB2ZXJpZnlUcmFuc2FjdGlvbihwYXJhbXM6IFZlcmlmeVRyYW5zYWN0aW9uT3B0aW9ucyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGxldCB0b3RhbEFtb3VudCA9IG5ldyBCaWdOdW1iZXIoMCk7XG4gICAgY29uc3QgY29pbkNvbmZpZyA9IGNvaW5zLmdldCh0aGlzLmdldENoYWluKCkpO1xuICAgIGNvbnN0IHsgdHhQcmVidWlsZDogdHhQcmVidWlsZCwgdHhQYXJhbXM6IHR4UGFyYW1zIH0gPSBwYXJhbXM7XG4gICAgY29uc3QgdHJhbnNhY3Rpb24gPSBuZXcgVHJhbnNhY3Rpb24oY29pbkNvbmZpZyk7XG4gICAgY29uc3QgcmF3VHggPSB0eFByZWJ1aWxkLnR4SGV4O1xuICAgIGlmICghcmF3VHgpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyByZXF1aXJlZCB0eCBwcmVidWlsZCBwcm9wZXJ0eSB0eEhleCcpO1xuICAgIH1cblxuICAgIHRyYW5zYWN0aW9uLmZyb21SYXdUcmFuc2FjdGlvbihyYXdUeCk7XG4gICAgY29uc3QgZXhwbGFpbmVkVHggPSB0cmFuc2FjdGlvbi5leHBsYWluVHJhbnNhY3Rpb24oKTtcblxuICAgIC8vIHVzZXJzIGRvIG5vdCBpbnB1dCByZWNpcGllbnRzIGZvciBjb25zb2xpZGF0aW9uIHJlcXVlc3RzIGFzIHRoZXkgYXJlIGdlbmVyYXRlZCBieSB0aGUgc2VydmVyXG4gICAgaWYgKHR4UGFyYW1zLnJlY2lwaWVudHMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgaWYgKHR4UGFyYW1zLnR5cGUgPT09ICdlbmFibGV0b2tlbicpIHtcbiAgICAgICAgY29uc3QgdG9rZW5OYW1lID0gZXhwbGFpbmVkVHgub3V0cHV0c1swXS50b2tlbk5hbWU7XG4gICAgICAgIGlmICh0b2tlbk5hbWUpIHtcbiAgICAgICAgICBjb25zdCBuZXBUb2tlbiA9IG5lYXJVdGlscy5nZXRUb2tlbkluc3RhbmNlRnJvbVRva2VuTmFtZSh0b2tlbk5hbWUpO1xuICAgICAgICAgIGlmIChuZXBUb2tlbikge1xuICAgICAgICAgICAgZXhwbGFpbmVkVHgub3V0cHV0cy5mb3JFYWNoKChvdXRwdXQpID0+IHtcbiAgICAgICAgICAgICAgaWYgKG91dHB1dC5hbW91bnQgIT09IG5lcFRva2VuLnN0b3JhZ2VEZXBvc2l0QW1vdW50KSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTdG9yYWdlIGRlcG9zaXQgYW1vdW50IG5vdCBtYXRjaGluZyEnKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGZpbHRlcmVkUmVjaXBpZW50cyA9IHR4UGFyYW1zLnJlY2lwaWVudHM/Lm1hcCgocmVjaXBpZW50KSA9PiB7XG4gICAgICAgIGlmICh0eFBhcmFtcy50eXBlICE9PSAnZW5hYmxldG9rZW4nKSB7XG4gICAgICAgICAgcmV0dXJuIF8ucGljayhyZWNpcGllbnQsIFsnYWRkcmVzcycsICdhbW91bnQnXSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmV0dXJuIF8ucGljayhyZWNpcGllbnQsIFsnYWRkcmVzcycsICd0b2tlbk5hbWUnXSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgY29uc3QgZmlsdGVyZWRPdXRwdXRzID0gZXhwbGFpbmVkVHgub3V0cHV0cy5tYXAoKG91dHB1dCkgPT4ge1xuICAgICAgICBpZiAodHhQYXJhbXMudHlwZSAhPT0gJ2VuYWJsZXRva2VuJykge1xuICAgICAgICAgIHJldHVybiBfLnBpY2sob3V0cHV0LCBbJ2FkZHJlc3MnLCAnYW1vdW50J10pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiBfLnBpY2sob3V0cHV0LCBbJ2FkZHJlc3MnLCAndG9rZW5OYW1lJ10pO1xuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgICAgaWYgKCFfLmlzRXF1YWwoZmlsdGVyZWRPdXRwdXRzLCBmaWx0ZXJlZFJlY2lwaWVudHMpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVHggb3V0cHV0cyBkb2VzIG5vdCBtYXRjaCB3aXRoIGV4cGVjdGVkIHR4UGFyYW1zIHJlY2lwaWVudHMnKTtcbiAgICAgIH1cbiAgICAgIGZvciAoY29uc3QgcmVjaXBpZW50cyBvZiB0eFBhcmFtcy5yZWNpcGllbnRzKSB7XG4gICAgICAgIHRvdGFsQW1vdW50ID0gdHhQYXJhbXMudHlwZSAhPT0gJ2VuYWJsZXRva2VuJyA/IHRvdGFsQW1vdW50LnBsdXMocmVjaXBpZW50cy5hbW91bnQpIDogQmlnTnVtYmVyKDApO1xuICAgICAgfVxuICAgICAgaWYgKCF0b3RhbEFtb3VudC5pc0VxdWFsVG8oZXhwbGFpbmVkVHgub3V0cHV0QW1vdW50KSAmJiB0eFBhcmFtcy50eXBlICE9PSAnZW5hYmxldG9rZW4nKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVHggdG90YWwgYW1vdW50IGRvZXMgbm90IG1hdGNoIHdpdGggZXhwZWN0ZWQgdG90YWwgYW1vdW50IGZpZWxkJyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHBhcmFtcy52ZXJpZmljYXRpb24/LmNvbnNvbGlkYXRpb25Ub0Jhc2VBZGRyZXNzKSB7XG4gICAgICBhd2FpdCB0aGlzLnZlcmlmeUNvbnNvbGlkYXRpb25Ub0Jhc2VBZGRyZXNzKHBhcmFtcywgZXhwbGFpbmVkVHgpO1xuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRCdWlsZGVyKCk6IFRyYW5zYWN0aW9uQnVpbGRlckZhY3Rvcnkge1xuICAgIHJldHVybiBuZXcgVHJhbnNhY3Rpb25CdWlsZGVyRmFjdG9yeShjb2lucy5nZXQodGhpcy5nZXRCYXNlQ2hhaW4oKSkpO1xuICB9XG5cbiAgLyoqIEBpbmhlcml0RG9jICovXG4gIGF1ZGl0RGVjcnlwdGVkS2V5KHsgcHJ2LCBwdWJsaWNLZXksIG11bHRpU2lnVHlwZSB9OiBBdWRpdERlY3J5cHRlZEtleVBhcmFtcykge1xuICAgIGlmIChtdWx0aVNpZ1R5cGUgIT09ICd0c3MnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1Vuc3VwcG9ydGVkIG11bHRpU2lnVHlwZScpO1xuICAgIH1cbiAgICBhdWRpdEVkZHNhUHJpdmF0ZUtleShwcnYsIHB1YmxpY0tleSA/PyAnJyk7XG4gIH1cblxuICBwcm90ZWN0ZWQgYXN5bmMgdmVyaWZ5Q29uc29saWRhdGlvblRvQmFzZUFkZHJlc3MoXG4gICAgcGFyYW1zOiBWZXJpZnlUcmFuc2FjdGlvbk9wdGlvbnMsXG4gICAgZXhwbGFpbmVkVHg6IFRyYW5zYWN0aW9uRXhwbGFuYXRpb25cbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgYmFzZUFkZHJlc3NlczogQmFzZUFkZHJlc3NbXSB8IHVuZGVmaW5lZCA9IGF3YWl0IHBhcmFtcy53YWxsZXQuYWRkcmVzc2VzKHsgc29ydDogLTEsIGxpbWl0OiAxIH0pO1xuICAgIGlmICghYmFzZUFkZHJlc3NlcyB8fCBiYXNlQWRkcmVzc2VzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdObyBiYXNlIGFkZHJlc3MgZm91bmQgb24gd2FsbGV0Jyk7XG4gICAgfVxuICAgIGNvbnN0IGJhc2VBZGRyZXNzID0gYmFzZUFkZHJlc3Nlc1swXTtcblxuICAgIGZvciAoY29uc3Qgb3V0cHV0IG9mIGV4cGxhaW5lZFR4Lm91dHB1dHMpIHtcbiAgICAgIGlmIChvdXRwdXQuYWRkcmVzcyAhPT0gYmFzZUFkZHJlc3MuYWRkcmVzcykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3R4IG91dHB1dHMgZG9lcyBub3QgbWF0Y2ggd2l0aCBleHBlY3RlZCBhZGRyZXNzJyk7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG4iXX0=
|