1 | ;
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const tslib_1 = require("tslib");
|
4 | const client_common_1 = require("@neo-one/client-common");
|
5 | const utils_1 = require("@neo-one/utils");
|
6 | const lodash_1 = tslib_1.__importDefault(require("lodash"));
|
7 | const AssetType_1 = require("../AssetType");
|
8 | const constants_1 = require("../constants");
|
9 | const errors_1 = require("../errors");
|
10 | const ScriptContainer_1 = require("../ScriptContainer");
|
11 | const utils_2 = require("../utils");
|
12 | const Witness_1 = require("../Witness");
|
13 | const attribute_1 = require("./attribute");
|
14 | const common_1 = require("./common");
|
15 | const Input_1 = require("./Input");
|
16 | const Output_1 = require("./Output");
|
17 | const TransactionType_1 = require("./TransactionType");
|
18 | const getUtilityValue = ({ outputs, utilityToken, }) => outputs
|
19 | .filter((output) => client_common_1.common.uInt256Equal(output.asset, utilityToken.hash))
|
20 | .reduce((acc, output) => acc.add(output.value), utils_2.utils.ZERO);
|
21 | function TransactionBase(Base) {
|
22 | class TransactionBaseClass extends Base {
|
23 | constructor() {
|
24 | super(...arguments);
|
25 | this.equals = utils_2.utils.equals(this.constructor, this, (other) => client_common_1.common.uInt256Equal(this.hash, other.hash));
|
26 | this.toKeyString = utils_2.utils.toKeyString(TransactionBase, () => this.hashHex);
|
27 | this.getSortedScriptHashesForVerifying = utils_2.utils.lazyAsync(async (options) => {
|
28 | const hashes = await this.getScriptHashesForVerifying(options);
|
29 | return [...hashes].sort();
|
30 | });
|
31 | this.sizeInternal = utils_2.utils.lazy(() => client_common_1.IOHelper.sizeOfUInt8 +
|
32 | client_common_1.IOHelper.sizeOfArray(this.attributes, (attribute) => attribute.size) +
|
33 | client_common_1.IOHelper.sizeOfArray(this.inputs, (input) => input.size) +
|
34 | client_common_1.IOHelper.sizeOfArray(this.outputs, (output) => output.size) +
|
35 | client_common_1.IOHelper.sizeOfArray(this.scripts, (script) => script.size) +
|
36 | this.sizeExclusive());
|
37 | this.networkFee = utils_2.utils.lazyAsync(async (context) => {
|
38 | const { getOutput, utilityToken } = context;
|
39 | const outputsForInputs = await Promise.all(this.inputs.map(getOutput));
|
40 | const inputValue = getUtilityValue({
|
41 | outputs: outputsForInputs,
|
42 | utilityToken,
|
43 | });
|
44 | const outputValue = getUtilityValue({
|
45 | outputs: this.outputs,
|
46 | utilityToken,
|
47 | });
|
48 | const result = inputValue.sub(outputValue).sub(this.getSystemFee(context));
|
49 | return result.lt(utils_2.utils.ZERO) ? utils_2.utils.ZERO : result;
|
50 | });
|
51 | this.getReferencesInternal = utils_2.utils.lazyAsync(async ({ getOutput }) => Promise.all(this.inputs.map(async (input) => getOutput(input))));
|
52 | this.getTransactionResultsInternal = utils_2.utils.lazyAsync(async ({ getOutput }) => {
|
53 | const inputOutputs = await this.getReferences({ getOutput });
|
54 | const mutableResults = {};
|
55 | const addOutputs = (outputs, negative) => {
|
56 | outputs.forEach((output) => {
|
57 | const key = client_common_1.common.uInt256ToHex(output.asset);
|
58 | let result = mutableResults[key];
|
59 | if (result === undefined) {
|
60 | mutableResults[key] = result = utils_2.utils.ZERO;
|
61 | }
|
62 | mutableResults[key] = result.add(negative === true ? output.value.neg() : output.value);
|
63 | });
|
64 | };
|
65 | addOutputs(inputOutputs);
|
66 | addOutputs(this.outputs, true);
|
67 | return lodash_1.default.pickBy(mutableResults, (value) => value !== undefined && !value.eq(utils_2.utils.ZERO));
|
68 | });
|
69 | this.baseGetScriptHashesForVerifyingInternal = utils_2.utils.lazyAsync(async ({ getOutput, getAsset }) => {
|
70 | const [inputHashes, outputHashes] = await Promise.all([
|
71 | Promise.all(this.inputs.map(async (input) => {
|
72 | const output = await getOutput(input);
|
73 | return client_common_1.common.uInt160ToHex(output.address);
|
74 | })),
|
75 | Promise.all(this.outputs.map(async (output) => {
|
76 | const asset = await getAsset({ hash: output.asset });
|
77 | if (client_common_1.hasFlag(asset.type, AssetType_1.AssetType.DutyFlag)) {
|
78 | return client_common_1.common.uInt160ToHex(output.address);
|
79 | }
|
80 | return undefined;
|
81 | })).then((hashes) => hashes.filter(utils_1.utils.notNull)),
|
82 | ]);
|
83 | const attributeHashes = this.attributes
|
84 | .map((attribute) => attribute instanceof attribute_1.UInt160Attribute && attribute.usage === attribute_1.AttributeUsage.Script
|
85 | ? client_common_1.common.uInt160ToHex(attribute.value)
|
86 | : undefined)
|
87 | .filter(utils_1.utils.notNull);
|
88 | return new Set([...inputHashes, ...outputHashes, ...attributeHashes]);
|
89 | });
|
90 | this.sizeExclusive = () => 0;
|
91 | }
|
92 | static deserializeTransactionBaseStartWireBase({ reader, }) {
|
93 | const type = client_common_1.assertTransactionType(reader.readUInt8());
|
94 | const version = reader.readUInt8();
|
95 | return { type, version };
|
96 | }
|
97 | static deserializeTransactionBaseEndWireBase(options) {
|
98 | const { reader } = options;
|
99 | const attributes = reader.readArray(() => attribute_1.deserializeAttributeWireBase(options), client_common_1.MAX_TRANSACTION_ATTRIBUTES);
|
100 | const inputs = reader.readArray(() => Input_1.Input.deserializeWireBase(options));
|
101 | const outputs = reader.readArray(() => Output_1.Output.deserializeWireBase(options), utils_2.utils.USHORT_MAX_NUMBER + 1);
|
102 | const scripts = reader.readArray(() => Witness_1.Witness.deserializeWireBase(options));
|
103 | return { attributes, inputs, outputs, scripts };
|
104 | }
|
105 | static deserializeWireBase(_options) {
|
106 | throw new Error('Not Implemented');
|
107 | }
|
108 | static deserializeWire(options) {
|
109 | return this.deserializeWireBase({
|
110 | context: options.context,
|
111 | reader: new utils_2.BinaryReader(options.buffer),
|
112 | });
|
113 | }
|
114 | get size() {
|
115 | return this.sizeInternal();
|
116 | }
|
117 | async serializeTransactionBaseJSON(context) {
|
118 | const [networkFee, transactionData] = await Promise.all([
|
119 | this.getNetworkFee(context.feeContext),
|
120 | context.tryGetTransactionData(this),
|
121 | ]);
|
122 | return {
|
123 | txid: client_common_1.common.uInt256ToString(this.hashHex),
|
124 | size: this.size,
|
125 | version: this.version,
|
126 | attributes: this.attributes.map((attribute) => attribute.serializeJSON(context)),
|
127 | vin: this.inputs.map((input) => input.serializeJSON(context)),
|
128 | vout: this.outputs.map((output, index) => output.serializeJSON(context, index)),
|
129 | scripts: this.scripts.map((script) => script.serializeJSON(context)),
|
130 | sys_fee: client_common_1.JSONHelper.writeFixed8(this.getSystemFee(context.feeContext)),
|
131 | net_fee: client_common_1.JSONHelper.writeFixed8(networkFee),
|
132 | data: transactionData === undefined
|
133 | ? undefined
|
134 | : {
|
135 | blockHash: client_common_1.common.uInt256ToString(transactionData.blockHash),
|
136 | blockIndex: transactionData.startHeight,
|
137 | transactionIndex: transactionData.index,
|
138 | globalIndex: client_common_1.JSONHelper.writeUInt64(transactionData.globalIndex),
|
139 | },
|
140 | };
|
141 | }
|
142 | async serializeJSON(_context) {
|
143 | throw new Error('Not Implemented');
|
144 | }
|
145 | async getNetworkFee(context) {
|
146 | return this.networkFee(context);
|
147 | }
|
148 | getSystemFee({ fees }) {
|
149 | const fee = fees[this.type];
|
150 | return fee === undefined ? utils_2.utils.ZERO : fee;
|
151 | }
|
152 | async getReferences(options) {
|
153 | return this.getReferencesInternal(options);
|
154 | }
|
155 | async getTransactionResults(options) {
|
156 | return this.getTransactionResultsInternal(options);
|
157 | }
|
158 | async getScriptHashesForVerifying(options) {
|
159 | return this.baseGetScriptHashesForVerifyingInternal(options);
|
160 | }
|
161 | async verify(options) {
|
162 | if (this.size > constants_1.MAX_TRANSACTION_SIZE) {
|
163 | throw new errors_1.VerifyError('Transaction too large.');
|
164 | }
|
165 | const { memPool = [] } = options;
|
166 | if (common_1.hasDuplicateInputs(this.inputs)) {
|
167 | throw new errors_1.VerifyError('Duplicate inputs');
|
168 | }
|
169 | if (memPool.some((tx) => !tx.equals(this) && common_1.hasIntersectingInputs(tx.inputs, this.inputs))) {
|
170 | throw new errors_1.VerifyError('Input already exists in mempool');
|
171 | }
|
172 | if (this.attributes.filter((attribute) => attribute.usage === attribute_1.AttributeUsage.ECDH02 || attribute.usage === attribute_1.AttributeUsage.ECDH03).length > 1) {
|
173 | throw new errors_1.VerifyError('Too many ECDH attributes.');
|
174 | }
|
175 | const [results] = await Promise.all([
|
176 | this.verifyScripts(options),
|
177 | this.verifyDoubleSpend(options),
|
178 | this.verifyOutputs(options),
|
179 | this.verifyTransactionResults(options),
|
180 | ]);
|
181 | return results;
|
182 | }
|
183 | async verifyDoubleSpend({ isSpent }) {
|
184 | const isDoubleSpend = await Promise.all(this.inputs.map(isSpent));
|
185 | if (isDoubleSpend.some((value) => value)) {
|
186 | throw new errors_1.VerifyError('Transaction is a double spend');
|
187 | }
|
188 | }
|
189 | async verifyOutputs({ getAsset, currentHeight }) {
|
190 | const outputsGrouped = Object.entries(lodash_1.default.groupBy(this.outputs, (output) => client_common_1.common.uInt256ToHex(output.asset)));
|
191 | const hasInvalidOutputs = await Promise.all(outputsGrouped.map(async ([assetHex, outputs]) => {
|
192 | const asset = await getAsset({ hash: client_common_1.common.hexToUInt256(assetHex) });
|
193 | if (asset.expiration <= currentHeight + 1 &&
|
194 | asset.type !== AssetType_1.AssetType.GoverningToken &&
|
195 | asset.type !== AssetType_1.AssetType.UtilityToken) {
|
196 | return true;
|
197 | }
|
198 | return outputs.some((output) => !output.value.mod(utils_2.utils.TEN.pow(utils_2.utils.EIGHT.subn(asset.precision))).eq(utils_2.utils.ZERO));
|
199 | }));
|
200 | if (hasInvalidOutputs.some((value) => value)) {
|
201 | throw new errors_1.VerifyError('Transaction has invalid output');
|
202 | }
|
203 | }
|
204 | async verifyTransactionResults({ getOutput, utilityToken, governingToken, fees, registerValidatorFee, }) {
|
205 | const results = await this.getTransactionResults({ getOutput });
|
206 | const resultsDestroy = Object.entries(results).filter(([_key, value]) => value.gt(utils_2.utils.ZERO));
|
207 | if (resultsDestroy.length > 1 ||
|
208 | (resultsDestroy.length === 1 &&
|
209 | !client_common_1.common.uInt256Equal(client_common_1.common.hexToUInt256(resultsDestroy[0][0]), utilityToken.hash))) {
|
210 | throw new errors_1.VerifyError('Invalid destroyed output.');
|
211 | }
|
212 | const feeContext = {
|
213 | getOutput,
|
214 | governingToken,
|
215 | utilityToken,
|
216 | fees,
|
217 | registerValidatorFee,
|
218 | };
|
219 | const systemFee = this.getSystemFee(feeContext);
|
220 | if (systemFee.gt(utils_2.utils.ZERO) && (resultsDestroy.length === 0 || resultsDestroy[0][1].lt(systemFee))) {
|
221 | throw new errors_1.VerifyError('Not enough output value for system fee.');
|
222 | }
|
223 | const resultsIssue = Object.entries(results).filter(([__, value]) => value.lt(utils_2.utils.ZERO));
|
224 | switch (this.type) {
|
225 | case TransactionType_1.TransactionType.Miner:
|
226 | case TransactionType_1.TransactionType.Claim:
|
227 | if (resultsIssue.some(([assetHex]) => !client_common_1.common.uInt256Equal(client_common_1.common.hexToUInt256(assetHex), utilityToken.hash))) {
|
228 | throw new errors_1.VerifyError('Invalid miner/claim result');
|
229 | }
|
230 | break;
|
231 | case TransactionType_1.TransactionType.Issue:
|
232 | if (resultsIssue.some(([assetHex, __]) => client_common_1.common.uInt256Equal(client_common_1.common.hexToUInt256(assetHex), utilityToken.hash))) {
|
233 | throw new errors_1.VerifyError('Invalid issue result');
|
234 | }
|
235 | break;
|
236 | default:
|
237 | if (resultsIssue.length > 0) {
|
238 | throw new errors_1.VerifyError('Invalid results.');
|
239 | }
|
240 | }
|
241 | }
|
242 | async verifyScripts({ getAsset, getOutput, verifyScript, }) {
|
243 | const hashesArr = await this.getSortedScriptHashesForVerifying({
|
244 | getAsset,
|
245 | getOutput,
|
246 | });
|
247 | if (hashesArr.length !== this.scripts.length) {
|
248 | throw new errors_1.VerifyError(`Invalid witnesses. Found ${hashesArr.length} hashes and ${this.scripts.length} scripts.`);
|
249 | }
|
250 | const hashes = hashesArr.map((value) => client_common_1.common.hexToUInt160(value));
|
251 | return Promise.all(lodash_1.default.zip(hashes, this.scripts).map(async ([hash, witness]) => verifyScript({
|
252 | scriptContainer: {
|
253 | type: ScriptContainer_1.ScriptContainerType.Transaction,
|
254 | value: this,
|
255 | },
|
256 | hash: hash,
|
257 | witness: witness,
|
258 | })));
|
259 | }
|
260 | }
|
261 | TransactionBaseClass.WitnessConstructor = Witness_1.Witness;
|
262 | return TransactionBaseClass;
|
263 | }
|
264 | exports.TransactionBase = TransactionBase;
|
265 |
|
266 | //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIlRyYW5zYWN0aW9uQmFzZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwwREFjZ0M7QUFDaEMsMENBQW1FO0FBRW5FLDREQUF1QjtBQUd2Qiw0Q0FBeUM7QUFDekMsNENBQW9EO0FBRXBELHNDQUF3QztBQUN4Qyx3REFBeUQ7QUFPekQsb0NBQStDO0FBRy9DLHdDQUFxQztBQUNyQywyQ0FBd0c7QUFDeEcscUNBQXFFO0FBQ3JFLG1DQUFnQztBQUNoQyxxQ0FBNkM7QUFHN0MsdURBQW9EO0FBTXBELE1BQU0sZUFBZSxHQUFHLENBQUMsRUFDdkIsT0FBTyxFQUNQLFlBQVksR0FJYixFQUFFLEVBQUUsQ0FDSCxPQUFPO0tBQ0osTUFBTSxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxzQkFBTSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQztLQUN4RSxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsTUFBTSxFQUFFLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxhQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7QUF5Q2hFLFNBQWdCLGVBQWUsQ0FJN0IsSUFBVztJQUNYLE1BQWUsb0JBQXFCLFNBQVEsSUFBSTtRQUFoRDs7WUE0Q2tCLFdBQU0sR0FBVyxhQUFLLENBQUMsTUFBTSxDQUUzQyxJQUFJLENBQUMsV0FBa0IsRUFDdkIsSUFBSSxFQUNKLENBQUMsS0FBMkIsRUFBRSxFQUFFLENBQUMsc0JBQU0sQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLENBQzVFLENBQUM7WUFDYyxnQkFBVyxHQUFHLGFBQUssQ0FBQyxXQUFXLENBQUMsZUFBZSxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNyRSxzQ0FBaUMsR0FBRyxhQUFLLENBQUMsU0FBUyxDQUNqRSxLQUFLLEVBQUUsT0FBc0QsRUFBRSxFQUFFO2dCQUMvRCxNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQywyQkFBMkIsQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFHL0QsT0FBTyxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDNUIsQ0FBQyxDQUNGLENBQUM7WUFDZSxpQkFBWSxHQUFHLGFBQUssQ0FBQyxJQUFJLENBQ3hDLEdBQUcsRUFBRSxDQUNILHdCQUFRLENBQUMsV0FBVztnQkFDcEIsd0JBQVEsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQztnQkFDcEUsd0JBQVEsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQztnQkFDeEQsd0JBQVEsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQztnQkFDM0Qsd0JBQVEsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQztnQkFDM0QsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUN2QixDQUFDO1lBQ2UsZUFBVSxHQUFHLGFBQUssQ0FBQyxTQUFTLENBQzNDLEtBQUssRUFBRSxPQUFtQixFQUFlLEVBQUU7Z0JBQ3pDLE1BQU0sRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLEdBQUcsT0FBTyxDQUFDO2dCQUU1QyxNQUFNLGdCQUFnQixHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO2dCQUV2RSxNQUFNLFVBQVUsR0FBRyxlQUFlLENBQUM7b0JBQ2pDLE9BQU8sRUFBRSxnQkFBZ0I7b0JBQ3pCLFlBQVk7aUJBQ2IsQ0FBQyxDQUFDO2dCQUVILE1BQU0sV0FBVyxHQUFHLGVBQWUsQ0FBQztvQkFDbEMsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPO29CQUNyQixZQUFZO2lCQUNiLENBQUMsQ0FBQztnQkFFSCxNQUFNLE1BQU0sR0FBRyxVQUFVLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7Z0JBRTNFLE9BQU8sTUFBTSxDQUFDLEVBQUUsQ0FBQyxhQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLGFBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztZQUNyRCxDQUFDLENBQ0YsQ0FBQztZQUNlLDBCQUFxQixHQUFHLGFBQUssQ0FBQyxTQUFTLENBQUMsS0FBSyxFQUFFLEVBQUUsU0FBUyxFQUF3QixFQUFFLEVBQUUsQ0FDckcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUNoRSxDQUFDO1lBQ2Usa0NBQTZCLEdBQUcsYUFBSyxDQUFDLFNBQVMsQ0FDOUQsS0FBSyxFQUFFLEVBQUUsU0FBUyxFQUFnQyxFQUE0QyxFQUFFO2dCQUM5RixNQUFNLFlBQVksR0FBRyxNQUFNLElBQUksQ0FBQyxhQUFhLENBQUMsRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDO2dCQUM3RCxNQUFNLGNBQWMsR0FBMkIsRUFBRSxDQUFDO2dCQUNsRCxNQUFNLFVBQVUsR0FBRyxDQUFDLE9BQTBCLEVBQUUsUUFBa0IsRUFBRSxFQUFFO29CQUNwRSxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUU7d0JBQ3pCLE1BQU0sR0FBRyxHQUFHLHNCQUFNLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQzt3QkFDOUMsSUFBSSxNQUFNLEdBQUcsY0FBYyxDQUFDLEdBQUcsQ0FBQyxDQUFDO3dCQUNqQyxJQUFJLE1BQU0sS0FBSyxTQUFTLEVBQUU7NEJBQ3hCLGNBQWMsQ0FBQyxHQUFHLENBQUMsR0FBRyxNQUFNLEdBQUcsYUFBSyxDQUFDLElBQUksQ0FBQzt5QkFDM0M7d0JBRUQsY0FBYyxDQUFDLEdBQUcsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsUUFBUSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO29CQUMxRixDQUFDLENBQUMsQ0FBQztnQkFDTCxDQUFDLENBQUM7Z0JBQ0YsVUFBVSxDQUFDLFlBQVksQ0FBQyxDQUFDO2dCQUN6QixVQUFVLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsQ0FBQztnQkFFL0IsT0FBTyxnQkFBQyxDQUFDLE1BQU0sQ0FBQyxjQUFjLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEtBQUssS0FBSyxTQUFTLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLGFBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1lBQzNGLENBQUMsQ0FDRixDQUFDO1lBQ2UsNENBQXVDLEdBQUcsYUFBSyxDQUFDLFNBQVMsQ0FDeEUsS0FBSyxFQUFFLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBaUQsRUFBRSxFQUFFO2dCQUMvRSxNQUFNLENBQUMsV0FBVyxFQUFFLFlBQVksQ0FBQyxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQztvQkFDcEQsT0FBTyxDQUFDLEdBQUcsQ0FDVCxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLEVBQUU7d0JBQzlCLE1BQU0sTUFBTSxHQUFHLE1BQU0sU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDO3dCQUV0QyxPQUFPLHNCQUFNLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztvQkFDN0MsQ0FBQyxDQUFDLENBQ0g7b0JBRUQsT0FBTyxDQUFDLEdBQUcsQ0FDVCxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsTUFBTSxFQUFFLEVBQUU7d0JBQ2hDLE1BQU0sS0FBSyxHQUFHLE1BQU0sUUFBUSxDQUFDLEVBQUUsSUFBSSxFQUFFLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO3dCQUNyRCxJQUFJLHVCQUFPLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxxQkFBUyxDQUFDLFFBQVEsQ0FBQyxFQUFFOzRCQUMzQyxPQUFPLHNCQUFNLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQzt5QkFDNUM7d0JBRUQsT0FBTyxTQUFTLENBQUM7b0JBQ25CLENBQUMsQ0FBQyxDQUNILENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLGFBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQztpQkFDdkQsQ0FBQyxDQUFDO2dCQUVILE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxVQUFVO3FCQUNwQyxHQUFHLENBQUMsQ0FBQyxTQUFTLEVBQUUsRUFBRSxDQUNqQixTQUFTLFlBQVksNEJBQWdCLElBQUksU0FBUyxDQUFDLEtBQUssS0FBSywwQkFBYyxDQUFDLE1BQU07b0JBQ2hGLENBQUMsQ0FBQyxzQkFBTSxDQUFDLFlBQVksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDO29CQUN0QyxDQUFDLENBQUMsU0FBUyxDQUNkO3FCQUNBLE1BQU0sQ0FBQyxhQUFXLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBRS9CLE9BQU8sSUFBSSxHQUFHLENBQUMsQ0FBQyxHQUFHLFdBQVcsRUFBRSxHQUFHLFlBQVksRUFBRSxHQUFHLGVBQWUsQ0FBQyxDQUFDLENBQUM7WUFDeEUsQ0FBQyxDQUNGLENBQUM7WUFpR2lCLGtCQUFhLEdBQWlCLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQztRQWdJM0QsQ0FBQztRQWxYUSxNQUFNLENBQUMsdUNBQXVDLENBQUMsRUFDcEQsTUFBTSxHQUNxQjtZQUMzQixNQUFNLElBQUksR0FBRyxxQ0FBcUIsQ0FBQyxNQUFNLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQztZQUN2RCxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsU0FBUyxFQUFFLENBQUM7WUFFbkMsT0FBTyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQztRQUMzQixDQUFDO1FBRU0sTUFBTSxDQUFDLHFDQUFxQyxDQUNqRCxPQUFtQztZQU9uQyxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFDO1lBQzNCLE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFLENBQUMsd0NBQTRCLENBQUMsT0FBTyxDQUFDLEVBQUUsMENBQTBCLENBQUMsQ0FBQztZQUU3RyxNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMsU0FBUyxDQUFDLEdBQUcsRUFBRSxDQUFDLGFBQUssQ0FBQyxtQkFBbUIsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1lBQzFFLE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFLENBQUMsZUFBTSxDQUFDLG1CQUFtQixDQUFDLE9BQU8sQ0FBQyxFQUFFLGFBQUssQ0FBQyxpQkFBaUIsR0FBRyxDQUFDLENBQUMsQ0FBQztZQUV6RyxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsU0FBUyxDQUFDLEdBQUcsRUFBRSxDQUFDLGlCQUFPLENBQUMsbUJBQW1CLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztZQUU3RSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLENBQUM7UUFDbEQsQ0FBQztRQUdNLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxRQUFvQztZQUNwRSxNQUFNLElBQUksS0FBSyxDQUFDLGlCQUFpQixDQUFDLENBQUM7UUFDckMsQ0FBQztRQUdNLE1BQU0sQ0FBQyxlQUFlLENBQUMsT0FBK0I7WUFDM0QsT0FBTyxJQUFJLENBQUMsbUJBQW1CLENBQUM7Z0JBQzlCLE9BQU8sRUFBRSxPQUFPLENBQUMsT0FBTztnQkFDeEIsTUFBTSxFQUFFLElBQUksb0JBQVksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDO2FBQ3pDLENBQUMsQ0FBQztRQUNMLENBQUM7UUE0R0QsSUFBVyxJQUFJO1lBQ2IsT0FBTyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDN0IsQ0FBQztRQUVNLEtBQUssQ0FBQyw0QkFBNEIsQ0FBQyxPQUE2QjtZQUNyRSxNQUFNLENBQUMsVUFBVSxFQUFFLGVBQWUsQ0FBQyxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQztnQkFDdEQsSUFBSSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDO2dCQUV0QyxPQUFPLENBQUMscUJBQXFCLENBQUMsSUFBVyxDQUFDO2FBQzNDLENBQUMsQ0FBQztZQUVILE9BQU87Z0JBQ0wsSUFBSSxFQUFFLHNCQUFNLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7Z0JBQzFDLElBQUksRUFBRSxJQUFJLENBQUMsSUFBSTtnQkFDZixPQUFPLEVBQUUsSUFBSSxDQUFDLE9BQU87Z0JBQ3JCLFVBQVUsRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQUMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFFaEYsR0FBRyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUM3RCxJQUFJLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQztnQkFFL0UsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUNwRSxPQUFPLEVBQUUsMEJBQVUsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUM7Z0JBQ3RFLE9BQU8sRUFBRSwwQkFBVSxDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUM7Z0JBQzNDLElBQUksRUFDRixlQUFlLEtBQUssU0FBUztvQkFDM0IsQ0FBQyxDQUFDLFNBQVM7b0JBQ1gsQ0FBQyxDQUFDO3dCQUNFLFNBQVMsRUFBRSxzQkFBTSxDQUFDLGVBQWUsQ0FBQyxlQUFlLENBQUMsU0FBUyxDQUFDO3dCQUM1RCxVQUFVLEVBQUUsZUFBZSxDQUFDLFdBQVc7d0JBQ3ZDLGdCQUFnQixFQUFFLGVBQWUsQ0FBQyxLQUFLO3dCQUN2QyxXQUFXLEVBQUUsMEJBQVUsQ0FBQyxXQUFXLENBQUMsZUFBZSxDQUFDLFdBQVcsQ0FBQztxQkFDakU7YUFDUixDQUFDO1FBQ0osQ0FBQztRQUVNLEtBQUssQ0FBQyxhQUFhLENBQUMsUUFBOEI7WUFDdkQsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBQ3JDLENBQUM7UUFFTSxLQUFLLENBQUMsYUFBYSxDQUFDLE9BQW1CO1lBQzVDLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNsQyxDQUFDO1FBRU0sWUFBWSxDQUFDLEVBQUUsSUFBSSxFQUFjO1lBQ3RDLE1BQU0sR0FBRyxHQUFtQixJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBRTVDLE9BQU8sR0FBRyxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsYUFBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDO1FBQzlDLENBQUM7UUFFTSxLQUFLLENBQUMsYUFBYSxDQUFDLE9BQTZCO1lBQ3RELE9BQU8sSUFBSSxDQUFDLHFCQUFxQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzdDLENBQUM7UUFFTSxLQUFLLENBQUMscUJBQXFCLENBQUMsT0FBcUM7WUFDdEUsT0FBTyxJQUFJLENBQUMsNkJBQTZCLENBQUMsT0FBTyxDQUE0QyxDQUFDO1FBQ2hHLENBQUM7UUFFTSxLQUFLLENBQUMsMkJBQTJCLENBQ3RDLE9BQXNEO1lBRXRELE9BQU8sSUFBSSxDQUFDLHVDQUF1QyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQy9ELENBQUM7UUFFTSxLQUFLLENBQUMsTUFBTSxDQUFDLE9BQWlDO1lBQ25ELElBQUksSUFBSSxDQUFDLElBQUksR0FBRyxnQ0FBb0IsRUFBRTtnQkFDcEMsTUFBTSxJQUFJLG9CQUFXLENBQUMsd0JBQXdCLENBQUMsQ0FBQzthQUNqRDtZQUVELE1BQU0sRUFBRSxPQUFPLEdBQUcsRUFBRSxFQUFFLEdBQUcsT0FBTyxDQUFDO1lBQ2pDLElBQUksMkJBQWtCLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFO2dCQUNuQyxNQUFNLElBQUksb0JBQVcsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO2FBQzNDO1lBRUQsSUFBSSxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksOEJBQXFCLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRTtnQkFDM0YsTUFBTSxJQUFJLG9CQUFXLENBQUMsaUNBQWlDLENBQUMsQ0FBQzthQUMxRDtZQUVELElBQ0UsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQ3BCLENBQUMsU0FBUyxFQUFFLEVBQUUsQ0FBQyxTQUFTLENBQUMsS0FBSyxLQUFLLDBCQUFjLENBQUMsTUFBTSxJQUFJLFNBQVMsQ0FBQyxLQUFLLEtBQUssMEJBQWMsQ0FBQyxNQUFNLENBQ3RHLENBQUMsTUFBTSxHQUFHLENBQUMsRUFDWjtnQkFDQSxNQUFNLElBQUksb0JBQVcsQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO2FBQ3BEO1lBRUQsTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQztnQkFDbEMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUM7Z0JBQzNCLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLENBQUM7Z0JBQy9CLElBQUksQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDO2dCQUMzQixJQUFJLENBQUMsd0JBQXdCLENBQUMsT0FBTyxDQUFDO2FBQ3ZDLENBQUMsQ0FBQztZQUVILE9BQU8sT0FBTyxDQUFDO1FBQ2pCLENBQUM7UUFJTyxLQUFLLENBQUMsaUJBQWlCLENBQUMsRUFBRSxPQUFPLEVBQTRCO1lBQ25FLE1BQU0sYUFBYSxHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1lBRWxFLElBQUksYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLEVBQUU7Z0JBQ3hDLE1BQU0sSUFBSSxvQkFBVyxDQUFDLCtCQUErQixDQUFDLENBQUM7YUFDeEQ7UUFDSCxDQUFDO1FBRU8sS0FBSyxDQUFDLGFBQWEsQ0FBQyxFQUFFLFFBQVEsRUFBRSxhQUFhLEVBQTRCO1lBQy9FLE1BQU0sY0FBYyxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsZ0JBQUMsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsc0JBQU0sQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUU5RyxNQUFNLGlCQUFpQixHQUFHLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FDekMsY0FBYyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxRQUFRLEVBQUUsT0FBTyxDQUFDLEVBQUUsRUFBRTtnQkFDL0MsTUFBTSxLQUFLLEdBQUcsTUFBTSxRQUFRLENBQUMsRUFBRSxJQUFJLEVBQUUsc0JBQU0sQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUN0RSxJQUNFLEtBQUssQ0FBQyxVQUFVLElBQUksYUFBYSxHQUFHLENBQUM7b0JBQ3JDLEtBQUssQ0FBQyxJQUFJLEtBQUsscUJBQVMsQ0FBQyxjQUFjO29CQUN2QyxLQUFLLENBQUMsSUFBSSxLQUFLLHFCQUFTLENBQUMsWUFBWSxFQUNyQztvQkFDQSxPQUFPLElBQUksQ0FBQztpQkFDYjtnQkFFRCxPQUFPLE9BQU8sQ0FBQyxJQUFJLENBQ2pCLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLGFBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLGFBQUssQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLGFBQUssQ0FBQyxJQUFJLENBQUMsQ0FDL0YsQ0FBQztZQUNKLENBQUMsQ0FBQyxDQUNILENBQUM7WUFFRixJQUFJLGlCQUFpQixDQUFDLElBQUksQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLEVBQUU7Z0JBQzVDLE1BQU0sSUFBSSxvQkFBVyxDQUFDLGdDQUFnQyxDQUFDLENBQUM7YUFDekQ7UUFDSCxDQUFDO1FBRU8sS0FBSyxDQUFDLHdCQUF3QixDQUFDLEVBQ3JDLFNBQVMsRUFDVCxZQUFZLEVBQ1osY0FBYyxFQUNkLElBQUksRUFDSixvQkFBb0IsR0FDSztZQUN6QixNQUFNLE9BQU8sR0FBRyxNQUFNLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxFQUFFLFNBQVMsRUFBRSxDQUFDLENBQUM7WUFDaEUsTUFBTSxjQUFjLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxNQUFNLENBRW5ELENBQUMsQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsYUFBSyxDQUFDLElBQUksQ0FBQyxDQUN4QyxDQUFDO1lBRUYsSUFDRSxjQUFjLENBQUMsTUFBTSxHQUFHLENBQUM7Z0JBQ3pCLENBQUMsY0FBYyxDQUFDLE1BQU0sS0FBSyxDQUFDO29CQUMxQixDQUFDLHNCQUFNLENBQUMsWUFBWSxDQUFDLHNCQUFNLENBQUMsWUFBWSxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUNyRjtnQkFDQSxNQUFNLElBQUksb0JBQVcsQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO2FBQ3BEO1lBRUQsTUFBTSxVQUFVLEdBQUc7Z0JBQ2pCLFNBQVM7Z0JBQ1QsY0FBYztnQkFDZCxZQUFZO2dCQUNaLElBQUk7Z0JBQ0osb0JBQW9CO2FBQ3JCLENBQUM7WUFFRixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQ2hELElBQUksU0FBUyxDQUFDLEVBQUUsQ0FBQyxhQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxLQUFLLENBQUMsSUFBSSxjQUFjLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUU7Z0JBQ25HLE1BQU0sSUFBSSxvQkFBVyxDQUFDLHlDQUF5QyxDQUFDLENBQUM7YUFDbEU7WUFHRCxNQUFNLFlBQVksR0FBRyxNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLEtBQUssQ0FBQyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLGFBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1lBRTNGLFFBQVEsSUFBSSxDQUFDLElBQUksRUFBRTtnQkFDakIsS0FBSyxpQ0FBZSxDQUFDLEtBQUssQ0FBQztnQkFDM0IsS0FBSyxpQ0FBZSxDQUFDLEtBQUs7b0JBQ3hCLElBQ0UsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsc0JBQU0sQ0FBQyxZQUFZLENBQUMsc0JBQU0sQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLEVBQUUsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQ3pHO3dCQUNBLE1BQU0sSUFBSSxvQkFBVyxDQUFDLDRCQUE0QixDQUFDLENBQUM7cUJBQ3JEO29CQUNELE1BQU07Z0JBQ1IsS0FBSyxpQ0FBZSxDQUFDLEtBQUs7b0JBQ3hCLElBRUUsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxzQkFBTSxDQUFDLFlBQVksQ0FBQyxzQkFBTSxDQUFDLFlBQVksQ0FBQyxRQUFRLENBQUMsRUFBRSxZQUFZLENBQUMsSUFBSSxDQUFDLENBQUMsRUFDNUc7d0JBQ0EsTUFBTSxJQUFJLG9CQUFXLENBQUMsc0JBQXNCLENBQUMsQ0FBQztxQkFDL0M7b0JBQ0QsTUFBTTtnQkFDUjtvQkFDRSxJQUFJLFlBQVksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO3dCQUMzQixNQUFNLElBQUksb0JBQVcsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO3FCQUMzQzthQUNKO1FBQ0gsQ0FBQztRQUVPLEtBQUssQ0FBQyxhQUFhLENBQUMsRUFDMUIsUUFBUSxFQUNSLFNBQVMsRUFDVCxZQUFZLEdBQ2E7WUFDekIsTUFBTSxTQUFTLEdBQUcsTUFBTSxJQUFJLENBQUMsaUNBQWlDLENBQUM7Z0JBQzdELFFBQVE7Z0JBQ1IsU0FBUzthQUNWLENBQUMsQ0FBQztZQUVILElBQUksU0FBUyxDQUFDLE1BQU0sS0FBSyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRTtnQkFDNUMsTUFBTSxJQUFJLG9CQUFXLENBQ25CLDRCQUE0QixTQUFTLENBQUMsTUFBTSxlQUFlLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxXQUFXLENBQzFGLENBQUM7YUFDSDtZQUVELE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLHNCQUFNLENBQUMsWUFBWSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7WUFFcEUsT0FBTyxPQUFPLENBQUMsR0FBRyxDQUNoQixnQkFBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLEVBQUUsRUFBRSxDQUN4RCxZQUFZLENBQUM7Z0JBQ1gsZUFBZSxFQUFFO29CQUNmLElBQUksRUFBRSxxQ0FBbUIsQ0FBQyxXQUFXO29CQUVyQyxLQUFLLEVBQUUsSUFBVztpQkFDbkI7Z0JBQ0QsSUFBSSxFQUFFLElBQWU7Z0JBQ3JCLE9BQU8sRUFBRSxPQUFrQjthQUM1QixDQUFDLENBQ0gsQ0FDRixDQUFDO1FBQ0osQ0FBQzs7SUF4VXlCLHVDQUFrQixHQUF5QixpQkFBTyxDQUFDO0lBMlUvRSxPQUFPLG9CQUFvQixDQUFDO0FBQzlCLENBQUM7QUEzWEQsMENBMlhDIiwiZmlsZSI6Im5lby1vbmUtbm9kZS1jb3JlL3NyYy90cmFuc2FjdGlvbi9UcmFuc2FjdGlvbkJhc2UuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBhc3NlcnRUcmFuc2FjdGlvblR5cGUsXG4gIGNvbW1vbixcbiAgRUNQb2ludCxcbiAgaGFzRmxhZyxcbiAgSU9IZWxwZXIsXG4gIEpTT05IZWxwZXIsXG4gIE1BWF9UUkFOU0FDVElPTl9BVFRSSUJVVEVTLFxuICBUcmFuc2FjdGlvbkJhc2VKU09OLFxuICBUcmFuc2FjdGlvbkJhc2VNb2RlbCxcbiAgVHJhbnNhY3Rpb25CYXNlTW9kZWxBZGQsXG4gIFRyYW5zYWN0aW9uQmFzZU1vZGVsQWRkV2l0aFR5cGUsXG4gIFVJbnQxNjAsXG4gIFVJbnQxNjBIZXgsXG59IGZyb20gJ0BuZW8tb25lL2NsaWVudC1jb21tb24nO1xuaW1wb3J0IHsgQ29uc3RydWN0b3IsIHV0aWxzIGFzIGNvbW1vblV0aWxzIH0gZnJvbSAnQG5lby1vbmUvdXRpbHMnO1xuaW1wb3J0IHsgQk4gfSBmcm9tICdibi5qcyc7XG5pbXBvcnQgXyBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IHsgQWNjb3VudCwgQWNjb3VudEtleSB9IGZyb20gJy4uL0FjY291bnQnO1xuaW1wb3J0IHsgQXNzZXQsIEFzc2V0S2V5IH0gZnJvbSAnLi4vQXNzZXQnO1xuaW1wb3J0IHsgQXNzZXRUeXBlIH0gZnJvbSAnLi4vQXNzZXRUeXBlJztcbmltcG9ydCB7IE1BWF9UUkFOU0FDVElPTl9TSVpFIH0gZnJvbSAnLi4vY29uc3RhbnRzJztcbmltcG9ydCB7IEVxdWFscywgRXF1YXRhYmxlS2V5IH0gZnJvbSAnLi4vRXF1YXRhYmxlJztcbmltcG9ydCB7IFZlcmlmeUVycm9yIH0gZnJvbSAnLi4vZXJyb3JzJztcbmltcG9ydCB7IFNjcmlwdENvbnRhaW5lclR5cGUgfSBmcm9tICcuLi9TY3JpcHRDb250YWluZXInO1xuaW1wb3J0IHtcbiAgRGVzZXJpYWxpemVXaXJlQmFzZU9wdGlvbnMsXG4gIERlc2VyaWFsaXplV2lyZU9wdGlvbnMsXG4gIFNlcmlhbGl6YWJsZUpTT04sXG4gIFNlcmlhbGl6ZUpTT05Db250ZXh0LFxufSBmcm9tICcuLi9TZXJpYWxpemFibGUnO1xuaW1wb3J0IHsgQmluYXJ5UmVhZGVyLCB1dGlscyB9IGZyb20gJy4uL3V0aWxzJztcbmltcG9ydCB7IFZhbGlkYXRvciB9IGZyb20gJy4uL1ZhbGlkYXRvcic7XG5pbXBvcnQgeyBWZXJpZnlTY3JpcHQsIFZlcmlmeVNjcmlwdFJlc3VsdCB9IGZyb20gJy4uL3ZtJztcbmltcG9ydCB7IFdpdG5lc3MgfSBmcm9tICcuLi9XaXRuZXNzJztcbmltcG9ydCB7IEF0dHJpYnV0ZSwgQXR0cmlidXRlVXNhZ2UsIGRlc2VyaWFsaXplQXR0cmlidXRlV2lyZUJhc2UsIFVJbnQxNjBBdHRyaWJ1dGUgfSBmcm9tICcuL2F0dHJpYnV0ZSc7XG5pbXBvcnQgeyBoYXNEdXBsaWNhdGVJbnB1dHMsIGhhc0ludGVyc2VjdGluZ0lucHV0cyB9IGZyb20gJy4vY29tbW9uJztcbmltcG9ydCB7IElucHV0IH0gZnJvbSAnLi9JbnB1dCc7XG5pbXBvcnQgeyBPdXRwdXQsIE91dHB1dEtleSB9IGZyb20gJy4vT3V0cHV0JztcbmltcG9ydCB7IFJlZ2lzdGVyVHJhbnNhY3Rpb24gfSBmcm9tICcuL1JlZ2lzdGVyVHJhbnNhY3Rpb24nO1xuaW1wb3J0IHsgVHJhbnNhY3Rpb24gfSBmcm9tICcuL1RyYW5zYWN0aW9uJztcbmltcG9ydCB7IFRyYW5zYWN0aW9uVHlwZSB9IGZyb20gJy4vVHJhbnNhY3Rpb25UeXBlJztcblxuZXhwb3J0IGludGVyZmFjZSBUcmFuc2FjdGlvbkJhc2VBZGQgZXh0ZW5kcyBUcmFuc2FjdGlvbkJhc2VNb2RlbEFkZDxBdHRyaWJ1dGUsIElucHV0LCBPdXRwdXQsIFdpdG5lc3M+IHt9XG5leHBvcnQgaW50ZXJmYWNlIFRyYW5zYWN0aW9uQmFzZUFkZFdpdGhUeXBlPFR5cGUgZXh0ZW5kcyBUcmFuc2FjdGlvblR5cGU+XG4gIGV4dGVuZHMgVHJhbnNhY3Rpb25CYXNlTW9kZWxBZGRXaXRoVHlwZTxUeXBlLCBBdHRyaWJ1dGUsIElucHV0LCBPdXRwdXQsIFdpdG5lc3M+IHt9XG5cbmNvbnN0IGdldFV0aWxpdHlWYWx1ZSA9ICh7XG4gIG91dHB1dHMsXG4gIHV0aWxpdHlUb2tlbixcbn06IHtcbiAgcmVhZG9ubHkgb3V0cHV0czogcmVhZG9ubHkgT3V0cHV0W107XG4gIHJlYWRvbmx5IHV0aWxpdHlUb2tlbjogUmVnaXN0ZXJUcmFuc2FjdGlvbjtcbn0pID0+XG4gIG91dHB1dHNcbiAgICAuZmlsdGVyKChvdXRwdXQpID0+IGNvbW1vbi51SW50MjU2RXF1YWwob3V0cHV0LmFzc2V0LCB1dGlsaXR5VG9rZW4uaGFzaCkpXG4gICAgLnJlZHVjZSgoYWNjLCBvdXRwdXQpID0+IGFjYy5hZGQob3V0cHV0LnZhbHVlKSwgdXRpbHMuWkVSTyk7XG5cbmV4cG9ydCBpbnRlcmZhY2UgRmVlQ29udGV4dCB7XG4gIHJlYWRvbmx5IGdldE91dHB1dDogKGlucHV0OiBJbnB1dCkgPT4gUHJvbWlzZTxPdXRwdXQ+O1xuICByZWFkb25seSBnb3Zlcm5pbmdUb2tlbjogUmVnaXN0ZXJUcmFuc2FjdGlvbjtcbiAgcmVhZG9ubHkgdXRpbGl0eVRva2VuOiBSZWdpc3RlclRyYW5zYWN0aW9uO1xuICByZWFkb25seSBmZWVzOiB7IFtLIGluIFRyYW5zYWN0aW9uVHlwZV0/OiBCTiB9O1xuICByZWFkb25seSByZWdpc3RlclZhbGlkYXRvckZlZTogQk47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVHJhbnNhY3Rpb25HZXRTY3JpcHRIYXNoZXNGb3JWZXJpZnlpbmdPcHRpb25zIHtcbiAgcmVhZG9ubHkgZ2V0T3V0cHV0OiAoa2V5OiBPdXRwdXRLZXkpID0+IFByb21pc2U8T3V0cHV0PjtcbiAgcmVhZG9ubHkgZ2V0QXNzZXQ6IChrZXk6IEFzc2V0S2V5KSA9PiBQcm9taXNlPEFzc2V0Pjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBHZXRSZWZlcmVuY2VzT3B0aW9ucyB7XG4gIHJlYWRvbmx5IGdldE91dHB1dDogKGtleTogT3V0cHV0S2V5KSA9PiBQcm9taXNlPE91dHB1dD47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgR2V0VHJhbnNhY3Rpb25SZXN1bHRzT3B0aW9ucyB7XG4gIHJlYWRvbmx5IGdldE91dHB1dDogKGtleTogT3V0cHV0S2V5KSA9PiBQcm9taXNlPE91dHB1dD47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVHJhbnNhY3Rpb25WZXJpZnlPcHRpb25zIHtcbiAgcmVhZG9ubHkgY2FsY3VsYXRlQ2xhaW1BbW91bnQ6IChpbnB1dHM6IHJlYWRvbmx5IElucHV0W10pID0+IFByb21pc2U8Qk4+O1xuICByZWFkb25seSBpc1NwZW50OiAoa2V5OiBPdXRwdXRLZXkpID0+IFByb21pc2U8Ym9vbGVhbj47XG4gIHJlYWRvbmx5IGdldEFzc2V0OiAoa2V5OiBBc3NldEtleSkgPT4gUHJvbWlzZTxBc3NldD47XG4gIHJlYWRvbmx5IGdldE91dHB1dDogKGtleTogT3V0cHV0S2V5KSA9PiBQcm9taXNlPE91dHB1dD47XG4gIHJlYWRvbmx5IHRyeUdldEFjY291bnQ6IChrZXk6IEFjY291bnRLZXkpID0+IFByb21pc2U8QWNjb3VudCB8IHVuZGVmaW5lZD47XG4gIHJlYWRvbmx5IHN0YW5kYnlWYWxpZGF0b3JzOiByZWFkb25seSBFQ1BvaW50W107XG4gIHJlYWRvbmx5IGdldEFsbFZhbGlkYXRvcnM6ICgpID0+IFByb21pc2U8cmVhZG9ubHkgVmFsaWRhdG9yW10+O1xuICByZWFkb25seSB2ZXJpZnlTY3JpcHQ6IFZlcmlmeVNjcmlwdDtcbiAgcmVhZG9ubHkgY3VycmVudEhlaWdodDogbnVtYmVyO1xuICByZWFkb25seSBnb3Zlcm5pbmdUb2tlbjogUmVnaXN0ZXJUcmFuc2FjdGlvbjtcbiAgcmVhZG9ubHkgdXRpbGl0eVRva2VuOiBSZWdpc3RlclRyYW5zYWN0aW9uO1xuICByZWFkb25seSBmZWVzOiB7IFtLIGluIFRyYW5zYWN0aW9uVHlwZV0/OiBCTiB9O1xuICByZWFkb25seSByZWdpc3RlclZhbGlkYXRvckZlZTogQk47XG4gIHJlYWRvbmx5IG1lbVBvb2w/OiByZWFkb25seSBUcmFuc2FjdGlvbltdO1xufVxuXG4vKiogQGludGVybmFsICovXG5leHBvcnQgZnVuY3Rpb24gVHJhbnNhY3Rpb25CYXNlPFxuICBUeXBlIGV4dGVuZHMgVHJhbnNhY3Rpb25UeXBlLFxuICBUcmFuc2FjdGlvbkpTT04sXG4gIFRCYXNlIGV4dGVuZHMgQ29uc3RydWN0b3I8VHJhbnNhY3Rpb25CYXNlTW9kZWw8VHlwZSwgQXR0cmlidXRlLCBJbnB1dCwgT3V0cHV0LCBXaXRuZXNzPj5cbj4oQmFzZTogVEJhc2UpIHtcbiAgYWJzdHJhY3QgY2xhc3MgVHJhbnNhY3Rpb25CYXNlQ2xhc3MgZXh0ZW5kcyBCYXNlIGltcGxlbWVudHMgRXF1YXRhYmxlS2V5LCBTZXJpYWxpemFibGVKU09OPFRyYW5zYWN0aW9uSlNPTj4ge1xuICAgIHB1YmxpYyBzdGF0aWMgZGVzZXJpYWxpemVUcmFuc2FjdGlvbkJhc2VTdGFydFdpcmVCYXNlKHtcbiAgICAgIHJlYWRlcixcbiAgICB9OiBEZXNlcmlhbGl6ZVdpcmVCYXNlT3B0aW9ucyk6IHsgcmVhZG9ubHkgdHlwZTogVHJhbnNhY3Rpb25UeXBlOyByZWFkb25seSB2ZXJzaW9uOiBudW1iZXIgfSB7XG4gICAgICBjb25zdCB0eXBlID0gYXNzZXJ0VHJhbnNhY3Rpb25UeXBlKHJlYWRlci5yZWFkVUludDgoKSk7XG4gICAgICBjb25zdCB2ZXJzaW9uID0gcmVhZGVyLnJlYWRVSW50OCgpO1xuXG4gICAgICByZXR1cm4geyB0eXBlLCB2ZXJzaW9uIH07XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBkZXNlcmlhbGl6ZVRyYW5zYWN0aW9uQmFzZUVuZFdpcmVCYXNlKFxuICAgICAgb3B0aW9uczogRGVzZXJpYWxpemVXaXJlQmFzZU9wdGlvbnMsXG4gICAgKToge1xuICAgICAgcmVhZG9ubHkgYXR0cmlidXRlczogcmVhZG9ubHkgQXR0cmlidXRlW107XG4gICAgICByZWFkb25seSBpbnB1dHM6IHJlYWRvbmx5IElucHV0W107XG4gICAgICByZWFkb25seSBvdXRwdXRzOiByZWFkb25seSBPdXRwdXRbXTtcbiAgICAgIHJlYWRvbmx5IHNjcmlwdHM6IHJlYWRvbmx5IFdpdG5lc3NbXTtcbiAgICB9IHtcbiAgICAgIGNvbnN0IHsgcmVhZGVyIH0gPSBvcHRpb25zO1xuICAgICAgY29uc3QgYXR0cmlidXRlcyA9IHJlYWRlci5yZWFkQXJyYXkoKCkgPT4gZGVzZXJpYWxpemVBdHRyaWJ1dGVXaXJlQmFzZShvcHRpb25zKSwgTUFYX1RSQU5TQUNUSU9OX0FUVFJJQlVURVMpO1xuXG4gICAgICBjb25zdCBpbnB1dHMgPSByZWFkZXIucmVhZEFycmF5KCgpID0+IElucHV0LmRlc2VyaWFsaXplV2lyZUJhc2Uob3B0aW9ucykpO1xuICAgICAgY29uc3Qgb3V0cHV0cyA9IHJlYWRlci5yZWFkQXJyYXkoKCkgPT4gT3V0cHV0LmRlc2VyaWFsaXplV2lyZUJhc2Uob3B0aW9ucyksIHV0aWxzLlVTSE9SVF9NQVhfTlVNQkVSICsgMSk7XG5cbiAgICAgIGNvbnN0IHNjcmlwdHMgPSByZWFkZXIucmVhZEFycmF5KCgpID0+IFdpdG5lc3MuZGVzZXJpYWxpemVXaXJlQmFzZShvcHRpb25zKSk7XG5cbiAgICAgIHJldHVybiB7IGF0dHJpYnV0ZXMsIGlucHV0cywgb3V0cHV0cywgc2NyaXB0cyB9O1xuICAgIH1cblxuICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZSBuby1hbnlcbiAgICBwdWJsaWMgc3RhdGljIGRlc2VyaWFsaXplV2lyZUJhc2UoX29wdGlvbnM6IERlc2VyaWFsaXplV2lyZUJhc2VPcHRpb25zKTogYW55IHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignTm90IEltcGxlbWVudGVkJyk7XG4gICAgfVxuXG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLWFueVxuICAgIHB1YmxpYyBzdGF0aWMgZGVzZXJpYWxpemVXaXJlKG9wdGlvbnM6IERlc2VyaWFsaXplV2lyZU9wdGlvbnMpOiBhbnkge1xuICAgICAgcmV0dXJuIHRoaXMuZGVzZXJpYWxpemVXaXJlQmFzZSh7XG4gICAgICAgIGNvbnRleHQ6IG9wdGlvbnMuY29udGV4dCxcbiAgICAgICAgcmVhZGVyOiBuZXcgQmluYXJ5UmVhZGVyKG9wdGlvbnMuYnVmZmVyKSxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBzdGF0aWMgcmVhZG9ubHkgV2l0bmVzc0NvbnN0cnVjdG9yOiBDb25zdHJ1Y3RvcjxXaXRuZXNzPiA9IFdpdG5lc3M7XG5cbiAgICBwdWJsaWMgcmVhZG9ubHkgZXF1YWxzOiBFcXVhbHMgPSB1dGlscy5lcXVhbHMoXG4gICAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmUgbm8tYW55XG4gICAgICB0aGlzLmNvbnN0cnVjdG9yIGFzIGFueSxcbiAgICAgIHRoaXMsXG4gICAgICAob3RoZXI6IFRyYW5zYWN0aW9uQmFzZUNsYXNzKSA9PiBjb21tb24udUludDI1NkVxdWFsKHRoaXMuaGFzaCwgb3RoZXIuaGFzaCksXG4gICAgKTtcbiAgICBwdWJsaWMgcmVhZG9ubHkgdG9LZXlTdHJpbmcgPSB1dGlscy50b0tleVN0cmluZyhUcmFuc2FjdGlvbkJhc2UsICgpID0+IHRoaXMuaGFzaEhleCk7XG4gICAgcHVibGljIHJlYWRvbmx5IGdldFNvcnRlZFNjcmlwdEhhc2hlc0ZvclZlcmlmeWluZyA9IHV0aWxzLmxhenlBc3luYyhcbiAgICAgIGFzeW5jIChvcHRpb25zOiBUcmFuc2FjdGlvbkdldFNjcmlwdEhhc2hlc0ZvclZlcmlmeWluZ09wdGlvbnMpID0+IHtcbiAgICAgICAgY29uc3QgaGFzaGVzID0gYXdhaXQgdGhpcy5nZXRTY3JpcHRIYXNoZXNGb3JWZXJpZnlpbmcob3B0aW9ucyk7XG5cbiAgICAgICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLWFycmF5LW11dGF0aW9uXG4gICAgICAgIHJldHVybiBbLi4uaGFzaGVzXS5zb3J0KCk7XG4gICAgICB9LFxuICAgICk7XG4gICAgcHJpdmF0ZSByZWFkb25seSBzaXplSW50ZXJuYWwgPSB1dGlscy5sYXp5KFxuICAgICAgKCkgPT5cbiAgICAgICAgSU9IZWxwZXIuc2l6ZU9mVUludDggK1xuICAgICAgICBJT0hlbHBlci5zaXplT2ZBcnJheSh0aGlzLmF0dHJpYnV0ZXMsIChhdHRyaWJ1dGUpID0+IGF0dHJpYnV0ZS5zaXplKSArXG4gICAgICAgIElPSGVscGVyLnNpemVPZkFycmF5KHRoaXMuaW5wdXRzLCAoaW5wdXQpID0+IGlucHV0LnNpemUpICtcbiAgICAgICAgSU9IZWxwZXIuc2l6ZU9mQXJyYXkodGhpcy5vdXRwdXRzLCAob3V0cHV0KSA9PiBvdXRwdXQuc2l6ZSkgK1xuICAgICAgICBJT0hlbHBlci5zaXplT2ZBcnJheSh0aGlzLnNjcmlwdHMsIChzY3JpcHQpID0+IHNjcmlwdC5zaXplKSArXG4gICAgICAgIHRoaXMuc2l6ZUV4Y2x1c2l2ZSgpLFxuICAgICk7XG4gICAgcHJpdmF0ZSByZWFkb25seSBuZXR3b3JrRmVlID0gdXRpbHMubGF6eUFzeW5jKFxuICAgICAgYXN5bmMgKGNvbnRleHQ6IEZlZUNvbnRleHQpOiBQcm9taXNlPEJOPiA9PiB7XG4gICAgICAgIGNvbnN0IHsgZ2V0T3V0cHV0LCB1dGlsaXR5VG9rZW4gfSA9IGNvbnRleHQ7XG5cbiAgICAgICAgY29uc3Qgb3V0cHV0c0ZvcklucHV0cyA9IGF3YWl0IFByb21pc2UuYWxsKHRoaXMuaW5wdXRzLm1hcChnZXRPdXRwdXQpKTtcblxuICAgICAgICBjb25zdCBpbnB1dFZhbHVlID0gZ2V0VXRpbGl0eVZhbHVlKHtcbiAgICAgICAgICBvdXRwdXRzOiBvdXRwdXRzRm9ySW5wdXRzLFxuICAgICAgICAgIHV0aWxpdHlUb2tlbixcbiAgICAgICAgfSk7XG5cbiAgICAgICAgY29uc3Qgb3V0cHV0VmFsdWUgPSBnZXRVdGlsaXR5VmFsdWUoe1xuICAgICAgICAgIG91dHB1dHM6IHRoaXMub3V0cHV0cyxcbiAgICAgICAgICB1dGlsaXR5VG9rZW4sXG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGlucHV0VmFsdWUuc3ViKG91dHB1dFZhbHVlKS5zdWIodGhpcy5nZXRTeXN0ZW1GZWUoY29udGV4dCkpO1xuXG4gICAgICAgIHJldHVybiByZXN1bHQubHQodXRpbHMuWkVSTykgPyB1dGlscy5aRVJPIDogcmVzdWx0O1xuICAgICAgfSxcbiAgICApO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgZ2V0UmVmZXJlbmNlc0ludGVybmFsID0gdXRpbHMubGF6eUFzeW5jKGFzeW5jICh7IGdldE91dHB1dCB9OiBHZXRSZWZlcmVuY2VzT3B0aW9ucykgPT5cbiAgICAgIFByb21pc2UuYWxsKHRoaXMuaW5wdXRzLm1hcChhc3luYyAoaW5wdXQpID0+IGdldE91dHB1dChpbnB1dCkpKSxcbiAgICApO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgZ2V0VHJhbnNhY3Rpb25SZXN1bHRzSW50ZXJuYWwgPSB1dGlscy5sYXp5QXN5bmMoXG4gICAgICBhc3luYyAoeyBnZXRPdXRwdXQgfTogR2V0VHJhbnNhY3Rpb25SZXN1bHRzT3B0aW9ucyk6IFByb21pc2U8eyByZWFkb25seSBbSyBpbiBzdHJpbmddPzogQk4gfT4gPT4ge1xuICAgICAgICBjb25zdCBpbnB1dE91dHB1dHMgPSBhd2FpdCB0aGlzLmdldFJlZmVyZW5jZXMoeyBnZXRPdXRwdXQgfSk7XG4gICAgICAgIGNvbnN0IG11dGFibGVSZXN1bHRzOiB7IFtLIGluIHN0cmluZ10/OiBCTiB9ID0ge307XG4gICAgICAgIGNvbnN0IGFkZE91dHB1dHMgPSAob3V0cHV0czogcmVhZG9ubHkgT3V0cHV0W10sIG5lZ2F0aXZlPzogYm9vbGVhbikgPT4ge1xuICAgICAgICAgIG91dHB1dHMuZm9yRWFjaCgob3V0cHV0KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBrZXkgPSBjb21tb24udUludDI1NlRvSGV4KG91dHB1dC5hc3NldCk7XG4gICAgICAgICAgICBsZXQgcmVzdWx0ID0gbXV0YWJsZVJlc3VsdHNba2V5XTtcbiAgICAgICAgICAgIGlmIChyZXN1bHQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICBtdXRhYmxlUmVzdWx0c1trZXldID0gcmVzdWx0ID0gdXRpbHMuWkVSTztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbXV0YWJsZVJlc3VsdHNba2V5XSA9IHJlc3VsdC5hZGQobmVnYXRpdmUgPT09IHRydWUgPyBvdXRwdXQudmFsdWUubmVnKCkgOiBvdXRwdXQudmFsdWUpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuICAgICAgICBhZGRPdXRwdXRzKGlucHV0T3V0cHV0cyk7XG4gICAgICAgIGFkZE91dHB1dHModGhpcy5vdXRwdXRzLCB0cnVlKTtcblxuICAgICAgICByZXR1cm4gXy5waWNrQnkobXV0YWJsZVJlc3VsdHMsICh2YWx1ZSkgPT4gdmFsdWUgIT09IHVuZGVmaW5lZCAmJiAhdmFsdWUuZXEodXRpbHMuWkVSTykpO1xuICAgICAgfSxcbiAgICApO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgYmFzZUdldFNjcmlwdEhhc2hlc0ZvclZlcmlmeWluZ0ludGVybmFsID0gdXRpbHMubGF6eUFzeW5jKFxuICAgICAgYXN5bmMgKHsgZ2V0T3V0cHV0LCBnZXRBc3NldCB9OiBUcmFuc2FjdGlvbkdldFNjcmlwdEhhc2hlc0ZvclZlcmlmeWluZ09wdGlvbnMpID0+IHtcbiAgICAgICAgY29uc3QgW2lucHV0SGFzaGVzLCBvdXRwdXRIYXNoZXNdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgIFByb21pc2UuYWxsKFxuICAgICAgICAgICAgdGhpcy5pbnB1dHMubWFwKGFzeW5jIChpbnB1dCkgPT4ge1xuICAgICAgICAgICAgICBjb25zdCBvdXRwdXQgPSBhd2FpdCBnZXRPdXRwdXQoaW5wdXQpO1xuXG4gICAgICAgICAgICAgIHJldHVybiBjb21tb24udUludDE2MFRvSGV4KG91dHB1dC5hZGRyZXNzKTtcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICksXG5cbiAgICAgICAgICBQcm9taXNlLmFsbChcbiAgICAgICAgICAgIHRoaXMub3V0cHV0cy5tYXAoYXN5bmMgKG91dHB1dCkgPT4ge1xuICAgICAgICAgICAgICBjb25zdCBhc3NldCA9IGF3YWl0IGdldEFzc2V0KHsgaGFzaDogb3V0cHV0LmFzc2V0IH0pO1xuICAgICAgICAgICAgICBpZiAoaGFzRmxhZyhhc3NldC50eXBlLCBBc3NldFR5cGUuRHV0eUZsYWcpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGNvbW1vbi51SW50MTYwVG9IZXgob3V0cHV0LmFkZHJlc3MpO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICkudGhlbigoaGFzaGVzKSA9PiBoYXNoZXMuZmlsdGVyKGNvbW1vblV0aWxzLm5vdE51bGwpKSxcbiAgICAgICAgXSk7XG5cbiAgICAgICAgY29uc3QgYXR0cmlidXRlSGFzaGVzID0gdGhpcy5hdHRyaWJ1dGVzXG4gICAgICAgICAgLm1hcCgoYXR0cmlidXRlKSA9PlxuICAgICAgICAgICAgYXR0cmlidXRlIGluc3RhbmNlb2YgVUludDE2MEF0dHJpYnV0ZSAmJiBhdHRyaWJ1dGUudXNhZ2UgPT09IEF0dHJpYnV0ZVVzYWdlLlNjcmlwdFxuICAgICAgICAgICAgICA/IGNvbW1vbi51SW50MTYwVG9IZXgoYXR0cmlidXRlLnZhbHVlKVxuICAgICAgICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICAgICAgICApXG4gICAgICAgICAgLmZpbHRlcihjb21tb25VdGlscy5ub3ROdWxsKTtcblxuICAgICAgICByZXR1cm4gbmV3IFNldChbLi4uaW5wdXRIYXNoZXMsIC4uLm91dHB1dEhhc2hlcywgLi4uYXR0cmlidXRlSGFzaGVzXSk7XG4gICAgICB9LFxuICAgICk7XG5cbiAgICBwdWJsaWMgZ2V0IHNpemUoKTogbnVtYmVyIHtcbiAgICAgIHJldHVybiB0aGlzLnNpemVJbnRlcm5hbCgpO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBzZXJpYWxpemVUcmFuc2FjdGlvbkJhc2VKU09OKGNvbnRleHQ6IFNlcmlhbGl6ZUpTT05Db250ZXh0KTogUHJvbWlzZTxUcmFuc2FjdGlvbkJhc2VKU09OPiB7XG4gICAgICBjb25zdCBbbmV0d29ya0ZlZSwgdHJhbnNhY3Rpb25EYXRhXSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgdGhpcy5nZXROZXR3b3JrRmVlKGNvbnRleHQuZmVlQ29udGV4dCksXG4gICAgICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZSBuby1hbnlcbiAgICAgICAgY29udGV4dC50cnlHZXRUcmFuc2FjdGlvbkRhdGEodGhpcyBhcyBhbnkpLFxuICAgICAgXSk7XG5cbiAgICAgIHJldHVybiB7XG4gICAgICAgIHR4aWQ6IGNvbW1vbi51SW50MjU2VG9TdHJpbmcodGhpcy5oYXNoSGV4KSxcbiAgICAgICAgc2l6ZTogdGhpcy5zaXplLFxuICAgICAgICB2ZXJzaW9uOiB0aGlzLnZlcnNpb24sXG4gICAgICAgIGF0dHJpYnV0ZXM6IHRoaXMuYXR0cmlidXRlcy5tYXAoKGF0dHJpYnV0ZSkgPT4gYXR0cmlidXRlLnNlcmlhbGl6ZUpTT04oY29udGV4dCkpLFxuXG4gICAgICAgIHZpbjogdGhpcy5pbnB1dHMubWFwKChpbnB1dCkgPT4gaW5wdXQuc2VyaWFsaXplSlNPTihjb250ZXh0KSksXG4gICAgICAgIHZvdXQ6IHRoaXMub3V0cHV0cy5tYXAoKG91dHB1dCwgaW5kZXgpID0+IG91dHB1dC5zZXJpYWxpemVKU09OKGNvbnRleHQsIGluZGV4KSksXG5cbiAgICAgICAgc2NyaXB0czogdGhpcy5zY3JpcHRzLm1hcCgoc2NyaXB0KSA9PiBzY3JpcHQuc2VyaWFsaXplSlNPTihjb250ZXh0KSksXG4gICAgICAgIHN5c19mZWU6IEpTT05IZWxwZXIud3JpdGVGaXhlZDgodGhpcy5nZXRTeXN0ZW1GZWUoY29udGV4dC5mZWVDb250ZXh0KSksXG4gICAgICAgIG5ldF9mZWU6IEpTT05IZWxwZXIud3JpdGVGaXhlZDgobmV0d29ya0ZlZSksXG4gICAgICAgIGRhdGE6XG4gICAgICAgICAgdHJhbnNhY3Rpb25EYXRhID09PSB1bmRlZmluZWRcbiAgICAgICAgICAgID8gdW5kZWZpbmVkXG4gICAgICAgICAgICA6IHtcbiAgICAgICAgICAgICAgICBibG9ja0hhc2g6IGNvbW1vbi51SW50MjU2VG9TdHJpbmcodHJhbnNhY3Rpb25EYXRhLmJsb2NrSGFzaCksXG4gICAgICAgICAgICAgICAgYmxvY2tJbmRleDogdHJhbnNhY3Rpb25EYXRhLnN0YXJ0SGVpZ2h0LFxuICAgICAgICAgICAgICAgIHRyYW5zYWN0aW9uSW5kZXg6IHRyYW5zYWN0aW9uRGF0YS5pbmRleCxcbiAgICAgICAgICAgICAgICBnbG9iYWxJbmRleDogSlNPTkhlbHBlci53cml0ZVVJbnQ2NCh0cmFuc2FjdGlvbkRhdGEuZ2xvYmFsSW5kZXgpLFxuICAgICAgICAgICAgICB9LFxuICAgICAgfTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgc2VyaWFsaXplSlNPTihfY29udGV4dDogU2VyaWFsaXplSlNPTkNvbnRleHQpOiBQcm9taXNlPFRyYW5zYWN0aW9uSlNPTj4ge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdOb3QgSW1wbGVtZW50ZWQnKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZ2V0TmV0d29ya0ZlZShjb250ZXh0OiBGZWVDb250ZXh0KTogUHJvbWlzZTxCTj4ge1xuICAgICAgcmV0dXJuIHRoaXMubmV0d29ya0ZlZShjb250ZXh0KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0U3lzdGVtRmVlKHsgZmVlcyB9OiBGZWVDb250ZXh0KTogQk4ge1xuICAgICAgY29uc3QgZmVlOiBCTiB8IHVuZGVmaW5lZCA9IGZlZXNbdGhpcy50eXBlXTtcblxuICAgICAgcmV0dXJuIGZlZSA9PT0gdW5kZWZpbmVkID8gdXRpbHMuWkVSTyA6IGZlZTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZ2V0UmVmZXJlbmNlcyhvcHRpb25zOiBHZXRSZWZlcmVuY2VzT3B0aW9ucyk6IFByb21pc2U8cmVhZG9ubHkgT3V0cHV0W10+IHtcbiAgICAgIHJldHVybiB0aGlzLmdldFJlZmVyZW5jZXNJbnRlcm5hbChvcHRpb25zKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgZ2V0VHJhbnNhY3Rpb25SZXN1bHRzKG9wdGlvbnM6IEdldFRyYW5zYWN0aW9uUmVzdWx0c09wdGlvbnMpOiBQcm9taXNlPHsgcmVhZG9ubHkgW2tleTogc3RyaW5nXTogQk4gfT4ge1xuICAgICAgcmV0dXJuIHRoaXMuZ2V0VHJhbnNhY3Rpb25SZXN1bHRzSW50ZXJuYWwob3B0aW9ucykgYXMgUHJvbWlzZTx7IHJlYWRvbmx5IFtrZXk6IHN0cmluZ106IEJOIH0+O1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBnZXRTY3JpcHRIYXNoZXNGb3JWZXJpZnlpbmcoXG4gICAgICBvcHRpb25zOiBUcmFuc2FjdGlvbkdldFNjcmlwdEhhc2hlc0ZvclZlcmlmeWluZ09wdGlvbnMsXG4gICAgKTogUHJvbWlzZTxTZXQ8VUludDE2MEhleD4+IHtcbiAgICAgIHJldHVybiB0aGlzLmJhc2VHZXRTY3JpcHRIYXNoZXNGb3JWZXJpZnlpbmdJbnRlcm5hbChvcHRpb25zKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgdmVyaWZ5KG9wdGlvbnM6IFRyYW5zYWN0aW9uVmVyaWZ5T3B0aW9ucyk6IFByb21pc2U8cmVhZG9ubHkgVmVyaWZ5U2NyaXB0UmVzdWx0W10+IHtcbiAgICAgIGlmICh0aGlzLnNpemUgPiBNQVhfVFJBTlNBQ1RJT05fU0laRSkge1xuICAgICAgICB0aHJvdyBuZXcgVmVyaWZ5RXJyb3IoJ1RyYW5zYWN0aW9uIHRvbyBsYXJnZS4nKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgeyBtZW1Qb29sID0gW10gfSA9IG9wdGlvbnM7XG4gICAgICBpZiAoaGFzRHVwbGljYXRlSW5wdXRzKHRoaXMuaW5wdXRzKSkge1xuICAgICAgICB0aHJvdyBuZXcgVmVyaWZ5RXJyb3IoJ0R1cGxpY2F0ZSBpbnB1dHMnKTtcbiAgICAgIH1cblxuICAgICAgaWYgKG1lbVBvb2wuc29tZSgodHgpID0+ICF0eC5lcXVhbHModGhpcykgJiYgaGFzSW50ZXJzZWN0aW5nSW5wdXRzKHR4LmlucHV0cywgdGhpcy5pbnB1dHMpKSkge1xuICAgICAgICB0aHJvdyBuZXcgVmVyaWZ5RXJyb3IoJ0lucHV0IGFscmVhZHkgZXhpc3RzIGluIG1lbXBvb2wnKTtcbiAgICAgIH1cblxuICAgICAgaWYgKFxuICAgICAgICB0aGlzLmF0dHJpYnV0ZXMuZmlsdGVyKFxuICAgICAgICAgIChhdHRyaWJ1dGUpID0+IGF0dHJpYnV0ZS51c2FnZSA9PT0gQXR0cmlidXRlVXNhZ2UuRUNESDAyIHx8IGF0dHJpYnV0ZS51c2FnZSA9PT0gQXR0cmlidXRlVXNhZ2UuRUNESDAzLFxuICAgICAgICApLmxlbmd0aCA+IDFcbiAgICAgICkge1xuICAgICAgICB0aHJvdyBuZXcgVmVyaWZ5RXJyb3IoJ1RvbyBtYW55IEVDREggYXR0cmlidXRlcy4nKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgW3Jlc3VsdHNdID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICB0aGlzLnZlcmlmeVNjcmlwdHMob3B0aW9ucyksXG4gICAgICAgIHRoaXMudmVyaWZ5RG91YmxlU3BlbmQob3B0aW9ucyksXG4gICAgICAgIHRoaXMudmVyaWZ5T3V0cHV0cyhvcHRpb25zKSxcbiAgICAgICAgdGhpcy52ZXJpZnlUcmFuc2FjdGlvblJlc3VsdHMob3B0aW9ucyksXG4gICAgICBdKTtcblxuICAgICAgcmV0dXJuIHJlc3VsdHM7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIHJlYWRvbmx5IHNpemVFeGNsdXNpdmU6ICgpID0+IG51bWJlciA9ICgpID0+IDA7XG5cbiAgICBwcml2YXRlIGFzeW5jIHZlcmlmeURvdWJsZVNwZW5kKHsgaXNTcGVudCB9OiBUcmFuc2FjdGlvblZlcmlmeU9wdGlvbnMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgIGNvbnN0IGlzRG91YmxlU3BlbmQgPSBhd2FpdCBQcm9taXNlLmFsbCh0aGlzLmlucHV0cy5tYXAoaXNTcGVudCkpO1xuXG4gICAgICBpZiAoaXNEb3VibGVTcGVuZC5zb21lKCh2YWx1ZSkgPT4gdmFsdWUpKSB7XG4gICAgICAgIHRocm93IG5ldyBWZXJpZnlFcnJvcignVHJhbnNhY3Rpb24gaXMgYSBkb3VibGUgc3BlbmQnKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIHZlcmlmeU91dHB1dHMoeyBnZXRBc3NldCwgY3VycmVudEhlaWdodCB9OiBUcmFuc2FjdGlvblZlcmlmeU9wdGlvbnMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgIGNvbnN0IG91dHB1dHNHcm91cGVkID0gT2JqZWN0LmVudHJpZXMoXy5ncm91cEJ5KHRoaXMub3V0cHV0cywgKG91dHB1dCkgPT4gY29tbW9uLnVJbnQyNTZUb0hleChvdXRwdXQuYXNzZXQpKSk7XG5cbiAgICAgIGNvbnN0IGhhc0ludmFsaWRPdXRwdXRzID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgIG91dHB1dHNHcm91cGVkLm1hcChhc3luYyAoW2Fzc2V0SGV4LCBvdXRwdXRzXSkgPT4ge1xuICAgICAgICAgIGNvbnN0IGFzc2V0ID0gYXdhaXQgZ2V0QXNzZXQoeyBoYXNoOiBjb21tb24uaGV4VG9VSW50MjU2KGFzc2V0SGV4KSB9KTtcbiAgICAgICAgICBpZiAoXG4gICAgICAgICAgICBhc3NldC5leHBpcmF0aW9uIDw9IGN1cnJlbnRIZWlnaHQgKyAxICYmXG4gICAgICAgICAgICBhc3NldC50eXBlICE9PSBBc3NldFR5cGUuR292ZXJuaW5nVG9rZW4gJiZcbiAgICAgICAgICAgIGFzc2V0LnR5cGUgIT09IEFzc2V0VHlwZS5VdGlsaXR5VG9rZW5cbiAgICAgICAgICApIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBvdXRwdXRzLnNvbWUoXG4gICAgICAgICAgICAob3V0cHV0KSA9PiAhb3V0cHV0LnZhbHVlLm1vZCh1dGlscy5URU4ucG93KHV0aWxzLkVJR0hULnN1Ym4oYXNzZXQucHJlY2lzaW9uKSkpLmVxKHV0aWxzLlpFUk8pLFxuICAgICAgICAgICk7XG4gICAgICAgIH0pLFxuICAgICAgKTtcblxuICAgICAgaWYgKGhhc0ludmFsaWRPdXRwdXRzLnNvbWUoKHZhbHVlKSA9PiB2YWx1ZSkpIHtcbiAgICAgICAgdGhyb3cgbmV3IFZlcmlmeUVycm9yKCdUcmFuc2FjdGlvbiBoYXMgaW52YWxpZCBvdXRwdXQnKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIHZlcmlmeVRyYW5zYWN0aW9uUmVzdWx0cyh7XG4gICAgICBnZXRPdXRwdXQsXG4gICAgICB1dGlsaXR5VG9rZW4sXG4gICAgICBnb3Zlcm5pbmdUb2tlbixcbiAgICAgIGZlZXMsXG4gICAgICByZWdpc3RlclZhbGlkYXRvckZlZSxcbiAgICB9OiBUcmFuc2FjdGlvblZlcmlmeU9wdGlvbnMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgIGNvbnN0IHJlc3VsdHMgPSBhd2FpdCB0aGlzLmdldFRyYW5zYWN0aW9uUmVzdWx0cyh7IGdldE91dHB1dCB9KTtcbiAgICAgIGNvbnN0IHJlc3VsdHNEZXN0cm95ID0gT2JqZWN0LmVudHJpZXMocmVzdWx0cykuZmlsdGVyKFxuICAgICAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW51c2VkXG4gICAgICAgIChbX2tleSwgdmFsdWVdKSA9PiB2YWx1ZS5ndCh1dGlscy5aRVJPKSxcbiAgICAgICk7XG5cbiAgICAgIGlmIChcbiAgICAgICAgcmVzdWx0c0Rlc3Ryb3kubGVuZ3RoID4gMSB8fFxuICAgICAgICAocmVzdWx0c0Rlc3Ryb3kubGVuZ3RoID09PSAxICYmXG4gICAgICAgICAgIWNvbW1vbi51SW50MjU2RXF1YWwoY29tbW9uLmhleFRvVUludDI1NihyZXN1bHRzRGVzdHJveVswXVswXSksIHV0aWxpdHlUb2tlbi5oYXNoKSlcbiAgICAgICkge1xuICAgICAgICB0aHJvdyBuZXcgVmVyaWZ5RXJyb3IoJ0ludmFsaWQgZGVzdHJveWVkIG91dHB1dC4nKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZmVlQ29udGV4dCA9IHtcbiAgICAgICAgZ2V0T3V0cHV0LFxuICAgICAgICBnb3Zlcm5pbmdUb2tlbixcbiAgICAgICAgdXRpbGl0eVRva2VuLFxuICAgICAgICBmZWVzLFxuICAgICAgICByZWdpc3RlclZhbGlkYXRvckZlZSxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHN5c3RlbUZlZSA9IHRoaXMuZ2V0U3lzdGVtRmVlKGZlZUNvbnRleHQpO1xuICAgICAgaWYgKHN5c3RlbUZlZS5ndCh1dGlscy5aRVJPKSAmJiAocmVzdWx0c0Rlc3Ryb3kubGVuZ3RoID09PSAwIHx8IHJlc3VsdHNEZXN0cm95WzBdWzFdLmx0KHN5c3RlbUZlZSkpKSB7XG4gICAgICAgIHRocm93IG5ldyBWZXJpZnlFcnJvcignTm90IGVub3VnaCBvdXRwdXQgdmFsdWUgZm9yIHN5c3RlbSBmZWUuJyk7XG4gICAgICB9XG5cbiAgICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZSBuby11bnVzZWRcbiAgICAgIGNvbnN0IHJlc3VsdHNJc3N1ZSA9IE9iamVjdC5lbnRyaWVzKHJlc3VsdHMpLmZpbHRlcigoW19fLCB2YWx1ZV0pID0+IHZhbHVlLmx0KHV0aWxzLlpFUk8pKTtcblxuICAgICAgc3dpdGNoICh0aGlzLnR5cGUpIHtcbiAgICAgICAgY2FzZSBUcmFuc2FjdGlvblR5cGUuTWluZXI6XG4gICAgICAgIGNhc2UgVHJhbnNhY3Rpb25UeXBlLkNsYWltOlxuICAgICAgICAgIGlmIChcbiAgICAgICAgICAgIHJlc3VsdHNJc3N1ZS5zb21lKChbYXNzZXRIZXhdKSA9PiAhY29tbW9uLnVJbnQyNTZFcXVhbChjb21tb24uaGV4VG9VSW50MjU2KGFzc2V0SGV4KSwgdXRpbGl0eVRva2VuLmhhc2gpKVxuICAgICAgICAgICkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFZlcmlmeUVycm9yKCdJbnZhbGlkIG1pbmVyL2NsYWltIHJlc3VsdCcpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBUcmFuc2FjdGlvblR5cGUuSXNzdWU6XG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lIG5vLXVudXNlZFxuICAgICAgICAgICAgcmVzdWx0c0lzc3VlLnNvbWUoKFthc3NldEhleCwgX19dKSA9PiBjb21tb24udUludDI1NkVxdWFsKGNvbW1vbi5oZXhUb1VJbnQyNTYoYXNzZXRIZXgpLCB1dGlsaXR5VG9rZW4uaGFzaCkpXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVmVyaWZ5RXJyb3IoJ0ludmFsaWQgaXNzdWUgcmVzdWx0Jyk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIGlmIChyZXN1bHRzSXNzdWUubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFZlcmlmeUVycm9yKCdJbnZhbGlkIHJlc3VsdHMuJyk7XG4gICAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgdmVyaWZ5U2NyaXB0cyh7XG4gICAgICBnZXRBc3NldCxcbiAgICAgIGdldE91dHB1dCxcbiAgICAgIHZlcmlmeVNjcmlwdCxcbiAgICB9OiBUcmFuc2FjdGlvblZlcmlmeU9wdGlvbnMpOiBQcm9taXNlPHJlYWRvbmx5IFZlcmlmeVNjcmlwdFJlc3VsdFtdPiB7XG4gICAgICBjb25zdCBoYXNoZXNBcnIgPSBhd2FpdCB0aGlzLmdldFNvcnRlZFNjcmlwdEhhc2hlc0ZvclZlcmlmeWluZyh7XG4gICAgICAgIGdldEFzc2V0LFxuICAgICAgICBnZXRPdXRwdXQsXG4gICAgICB9KTtcblxuICAgICAgaWYgKGhhc2hlc0Fyci5sZW5ndGggIT09IHRoaXMuc2NyaXB0cy5sZW5ndGgpIHtcbiAgICAgICAgdGhyb3cgbmV3IFZlcmlmeUVycm9yKFxuICAgICAgICAgIGBJbnZhbGlkIHdpdG5lc3Nlcy4gRm91bmQgJHtoYXNoZXNBcnIubGVuZ3RofSBoYXNoZXMgYW5kICR7dGhpcy5zY3JpcHRzLmxlbmd0aH0gc2NyaXB0cy5gLFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBoYXNoZXMgPSBoYXNoZXNBcnIubWFwKCh2YWx1ZSkgPT4gY29tbW9uLmhleFRvVUludDE2MCh2YWx1ZSkpO1xuXG4gICAgICByZXR1cm4gUHJvbWlzZS5hbGwoXG4gICAgICAgIF8uemlwKGhhc2hlcywgdGhpcy5zY3JpcHRzKS5tYXAoYXN5bmMgKFtoYXNoLCB3aXRuZXNzXSkgPT5cbiAgICAgICAgICB2ZXJpZnlTY3JpcHQoe1xuICAgICAgICAgICAgc2NyaXB0Q29udGFpbmVyOiB7XG4gICAgICAgICAgICAgIHR5cGU6IFNjcmlwdENvbnRhaW5lclR5cGUuVHJhbnNhY3Rpb24sXG4gICAgICAgICAgICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZSBuby1hbnlcbiAgICAgICAgICAgICAgdmFsdWU6IHRoaXMgYXMgYW55LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGhhc2g6IGhhc2ggYXMgVUludDE2MCxcbiAgICAgICAgICAgIHdpdG5lc3M6IHdpdG5lc3MgYXMgV2l0bmVzcyxcbiAgICAgICAgICB9KSxcbiAgICAgICAgKSxcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIFRyYW5zYWN0aW9uQmFzZUNsYXNzO1xufVxuIl19
|