myria-core-sdk
Version:
Latest version SDK
353 lines • 29.8 kB
JavaScript
import BigNumber from 'bignumber.js';
import _ from 'lodash';
// Contracts
import { ConfirmationType } from '../types/CommonTypes';
import { normalizeResponse, OUTCOMES } from './helpers';
// /**
// * Myria Contract
// */
export default class MContract {
constructor(provider, networkId, web3, contractInfo, sendOptions = {}) {
this.web3 = web3;
this.defaultOptions = {
gas: null,
gasPrice: undefined,
value: 0,
from: null,
confirmations: 0,
confirmationType: ConfirmationType.Confirmed,
gasMultiplier: 1.5,
...sendOptions,
};
this.networkId = networkId;
this.accountAddress = this.web3.eth.defaultAccount;
this.contractInfo = contractInfo;
this.setContractProvider(contractInfo.contract, contractInfo.json, provider, networkId);
this.currentTxHash = '';
}
setDefaultAccount(account) {
this.accountAddress = account;
}
setProvider(provider, networkId) {
this.networkId = networkId;
}
setContractProvider(contract, contractJson, provider, networkId) {
// Deployed smart contract address
const deployedInfo = contractJson.networks[networkId];
contract.options.address = deployedInfo && deployedInfo.address;
}
async call(method, specificOptions = {}) {
const { blockNumber, ...otherOptions } = this.toCallOptions({
...this.defaultOptions,
...specificOptions,
});
return await method.call(otherOptions, blockNumber || 'latest');
}
createTimeoutPromise(timeout, promi) {
/* eslint-disable */
return new Promise((resolve, _) => {
setTimeout(() => {
promi.on('transactionHash', (txHash) => {
console.log('Tx hash => ', txHash);
this.currentTxHash = txHash;
resolve(normalizeResponse({
transactionHash: txHash,
isNetworkTimeout: true,
message: 'Your transaction is taking longer than usual to verify due to Ethereum network congestion.'
}));
promi.off();
});
}, timeout);
});
/* eslint-disable */
}
async send(contract, method, specificOptions = {}) {
const sendOptions = {
...this.defaultOptions,
...specificOptions,
};
const result = await this._send(contract, method, sendOptions);
return result;
}
async _send(contract, method, sendOptions = {}) {
const { confirmations, confirmationType, gasMultiplier, enabledTimeout, timeout, ...txOptions } = sendOptions;
if (confirmationType && !Object.values(ConfirmationType).includes(confirmationType)) {
throw new Error(`Invalid confirmation type: ${confirmationType}`);
}
if (confirmationType === ConfirmationType.Simulate && !txOptions.gas) {
const gasEstimate = await this.estimateGas(method, txOptions);
txOptions.gas = Math.floor(gasEstimate * gasMultiplier);
if (confirmationType === ConfirmationType.Simulate) {
return {
gasEstimate,
gas: txOptions.gas,
};
}
}
let hashOutcome = OUTCOMES.INITIAL;
let confirmationOutcome = OUTCOMES.INITIAL;
if (confirmationType === ConfirmationType.Sender) {
const data = method.encodeABI();
const from = txOptions.from || this.web3.defaultAccount;
if (from === null) {
throw new Error('Cannot sendTransaction with from=null');
}
if (_.isNil(txOptions.nonce)) {
throw new Error('Cannot sendTransaction with nonce=null');
}
const nonceIsHexString = (typeof txOptions.nonce === 'string') &&
txOptions.nonce.includes('0x');
const nonceBn = new BigNumber(txOptions.nonce, nonceIsHexString ? 16 : 10);
console.log('Pre-submit on-chain', JSON.stringify({
gas: txOptions.gas,
value: txOptions.value,
gasPrice: txOptions.gasPrice,
to: contract.options.address,
from,
nonce: nonceBn.toNumber(),
data,
}));
if (!txOptions.gas) {
throw new Error("Gas is required");
}
const stPromi = this.web3.eth.sendTransaction({
gas: Number(txOptions.gas) || 500000,
value: txOptions.value,
gasPrice: txOptions.gasPrice,
to: contract.options.address,
from,
nonce: nonceBn.toNumber(),
data,
});
/* eslint-disable @typescript-eslint/no-floating-promises */
const stPromise = new Promise((resolve, reject) => {
stPromi.on('error', (error) => {
if (hashOutcome === OUTCOMES.INITIAL) {
hashOutcome = OUTCOMES.REJECTED;
reject(error);
stPromi.off();
}
});
stPromi.on('transactionHash', (txHash) => {
if (hashOutcome === OUTCOMES.INITIAL) {
hashOutcome = OUTCOMES.RESOLVED;
resolve(txHash);
stPromi.off();
}
});
});
const stResult = await stPromise;
/* eslint-disable @typescript-eslint/no-floating-promises */
return normalizeResponse({ transactionHash: stResult });
}
// const promi: PromiEvent<Contract> | any = method.send(
// this.toNativeSendOptions(txOptions) as any,
// );
const from = txOptions.from || this.web3.defaultAccount;
if (from === null) {
throw new Error('Cannot sendTransaction with from=null');
}
if (_.isNil(txOptions.nonce)) {
throw new Error('Cannot sendTransaction with nonce=null');
}
const data = method.encodeABI();
const nonceIsHexString = (typeof txOptions.nonce === 'string') &&
txOptions.nonce.includes('0x');
const nonceBn = new BigNumber(txOptions.nonce, nonceIsHexString ? 16 : 10);
console.log('Pre-submit on-chain', JSON.stringify({
gas: txOptions.gas,
value: txOptions.value,
gasPrice: txOptions.gasPrice,
to: contract.options.address,
from,
nonce: nonceBn.toNumber(),
data,
}));
const promi = this.web3.eth.sendTransaction({
gas: Number(txOptions.gas),
value: txOptions.value,
gasPrice: txOptions.gasPrice,
to: contract.options.address,
from,
nonce: nonceBn.toNumber(),
data,
});
let transactionHash;
let hashPromise;
let confirmationPromise;
if (confirmationType && [
ConfirmationType.Hash,
ConfirmationType.Both,
].includes(confirmationType)) {
hashPromise = new Promise((resolve, reject) => {
promi.on('error', (error) => {
if (hashOutcome === OUTCOMES.INITIAL) {
hashOutcome = OUTCOMES.REJECTED;
reject(error);
promi.off();
}
});
promi.on('transactionHash', (txHash) => {
if (hashOutcome === OUTCOMES.INITIAL) {
hashOutcome = OUTCOMES.RESOLVED;
resolve(txHash);
if (confirmationType !== ConfirmationType.Both) {
promi.off();
}
}
});
});
transactionHash = await hashPromise;
}
// Type of confirmed transaction to make sure
// the transaction is confirmed
if (confirmationType && [
ConfirmationType.Confirmed,
ConfirmationType.Both,
].includes(confirmationType)) {
if (enabledTimeout) {
confirmationPromise = Promise.race([
new Promise((resolve, reject) => {
promi.on('transactionHash', (txHash) => {
console.log('Tx hash => ', txHash);
this.currentTxHash = txHash;
});
promi.on('error', (error) => {
if (confirmationOutcome === OUTCOMES.INITIAL &&
(confirmationType === ConfirmationType.Confirmed ||
hashOutcome === OUTCOMES.RESOLVED)) {
confirmationOutcome = OUTCOMES.REJECTED;
const errMessage = error.toString();
const minedOnchainTxErr = '50 blocks';
const minedTimeout = 'mined within 750 seconds';
console.log('Error msg =>', JSON.stringify(error));
console.log('Current tx hash =>', JSON.stringify(error));
if (errMessage
&& !errMessage.includes(minedOnchainTxErr)
&& !errMessage.includes(minedTimeout) && !this.currentTxHash) {
confirmationOutcome = OUTCOMES.REJECTED;
reject(error);
promi.off();
}
else if (errMessage && (errMessage.includes(minedOnchainTxErr) || errMessage.includes(minedTimeout)) && this.currentTxHash.length > 0) {
confirmationOutcome = OUTCOMES.RESOLVED;
resolve(normalizeResponse({
transactionHash: this.currentTxHash,
isNetworkTimeout: true,
message: 'Your transaction is taking longer than usual to verify due to Ethereum network congestion.'
}));
promi.off();
}
else {
confirmationOutcome = OUTCOMES.REJECTED;
reject(error);
promi.off();
}
}
});
if (confirmations) {
promi.on('confirmation', (confNumber, receipt) => {
if (confNumber >= confirmations) {
if (confirmationOutcome === OUTCOMES.INITIAL) {
confirmationOutcome = OUTCOMES.RESOLVED;
resolve(receipt);
promi.off();
}
}
});
}
else {
promi.on('receipt', (receipt) => {
confirmationOutcome = OUTCOMES.RESOLVED;
resolve(receipt);
promi.off();
});
}
}),
this.createTimeoutPromise(timeout || 300000, promi),
]);
}
else {
confirmationPromise = new Promise((resolve, reject) => {
promi.on('error', (error) => {
if (confirmationOutcome === OUTCOMES.INITIAL &&
(confirmationType === ConfirmationType.Confirmed ||
hashOutcome === OUTCOMES.RESOLVED)) {
console.log('Error => ', error);
confirmationOutcome = OUTCOMES.REJECTED;
reject(error);
promi.off();
}
});
if (confirmations) {
promi.on('confirmation', (confNumber, receipt) => {
if (confNumber >= confirmations) {
if (confirmationOutcome === OUTCOMES.INITIAL) {
confirmationOutcome = OUTCOMES.RESOLVED;
resolve(receipt);
promi.off();
}
}
});
}
else {
promi.on('receipt', (receipt) => {
confirmationOutcome = OUTCOMES.RESOLVED;
resolve(receipt);
promi.off();
});
}
});
}
}
if (confirmationType === ConfirmationType.Hash) {
return normalizeResponse({ transactionHash });
}
if (confirmationType === ConfirmationType.Confirmed) {
return confirmationPromise;
}
return normalizeResponse({
transactionHash,
confirmation: confirmationPromise,
});
}
async estimateGas(method, txOptions) {
const estimateOptions = this.toEstimateOptions(txOptions);
try {
const gasEstimate = await method.estimateGas(estimateOptions);
return gasEstimate;
}
catch (error) {
error.transactionData = {
...estimateOptions,
data: method.encodeABI(),
to: method._parent._address,
};
throw error;
}
}
// ============ Parse Options ============
toEstimateOptions(options) {
return _.pick(options, [
'from',
'value',
]);
}
toCallOptions(options) {
return _.pick(options, [
'from',
'value',
'blockNumber',
]);
}
toNativeSendOptions(options) {
return _.pick(options, [
'from',
'value',
'gasPrice',
'gas',
'nonce',
]);
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29udHJhY3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY29yZS9Db250cmFjdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLFNBQVMsTUFBTSxjQUFjLENBQUM7QUFDckMsT0FBTyxDQUFDLE1BQU0sUUFBUSxDQUFDO0FBY3ZCLFlBQVk7QUFDWixPQUFPLEVBRUwsZ0JBQWdCLEVBS2pCLE1BQU0sc0JBQXNCLENBQUM7QUFDOUIsT0FBTyxFQUFFLGlCQUFpQixFQUFFLFFBQVEsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQWN4RCxNQUFNO0FBQ04sb0JBQW9CO0FBQ3BCLE1BQU07QUFDTixNQUFNLENBQUMsT0FBTyxPQUFPLFNBQVM7SUFXNUIsWUFDRSxRQUFrQixFQUNsQixTQUFpQixFQUNqQixJQUFVLEVBQ1YsWUFBMEIsRUFDMUIsY0FBMkIsRUFBRTtRQUU3QixJQUFJLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztRQUNqQixJQUFJLENBQUMsY0FBYyxHQUFHO1lBQ3BCLEdBQUcsRUFBRSxJQUFJO1lBQ1QsUUFBUSxFQUFFLFNBQVM7WUFDbkIsS0FBSyxFQUFFLENBQUM7WUFDUixJQUFJLEVBQUUsSUFBSTtZQUNWLGFBQWEsRUFBRSxDQUFDO1lBQ2hCLGdCQUFnQixFQUFFLGdCQUFnQixDQUFDLFNBQVM7WUFDNUMsYUFBYSxFQUFFLEdBQUc7WUFDbEIsR0FBRyxXQUFXO1NBQ2YsQ0FBQztRQUVGLElBQUksQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFDO1FBQzNCLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsY0FBd0IsQ0FBQztRQUM3RCxJQUFJLENBQUMsWUFBWSxHQUFHLFlBQVksQ0FBQztRQUNqQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsWUFBWSxDQUFDLFFBQVEsRUFBRSxZQUFZLENBQUMsSUFBSSxFQUFFLFFBQVEsRUFBRSxTQUFTLENBQUMsQ0FBQztRQUN4RixJQUFJLENBQUMsYUFBYSxHQUFHLEVBQUUsQ0FBQztJQUMxQixDQUFDO0lBRU0saUJBQWlCLENBQUMsT0FBZ0I7UUFDdkMsSUFBSSxDQUFDLGNBQWMsR0FBRyxPQUFPLENBQUM7SUFDaEMsQ0FBQztJQUVNLFdBQVcsQ0FDaEIsUUFBa0IsRUFDbEIsU0FBaUI7UUFFakIsSUFBSSxDQUFDLFNBQVMsR0FBRyxTQUFTLENBQUM7SUFDN0IsQ0FBQztJQUVNLG1CQUFtQixDQUN4QixRQUFrQixFQUNsQixZQUFrQixFQUNsQixRQUFrQixFQUNsQixTQUFpQjtRQUdqQixrQ0FBa0M7UUFDbEMsTUFBTSxZQUFZLEdBQUcsWUFBWSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUN0RCxRQUFRLENBQUMsT0FBTyxDQUFDLE9BQU8sR0FBRyxZQUFZLElBQUksWUFBWSxDQUFDLE9BQU8sQ0FBQztJQUNsRSxDQUFDO0lBRU0sS0FBSyxDQUFDLElBQUksQ0FDZixNQUEwQixFQUMxQixrQkFBK0IsRUFBRTtRQUVqQyxNQUFNLEVBQ0osV0FBVyxFQUNYLEdBQUcsWUFBWSxFQUNoQixHQUFHLElBQUksQ0FBQyxhQUFhLENBQUM7WUFDckIsR0FBRyxJQUFJLENBQUMsY0FBYztZQUN0QixHQUFHLGVBQWU7U0FDbkIsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxNQUFPLE1BQWMsQ0FBQyxJQUFJLENBQUMsWUFBWSxFQUFFLFdBQVcsSUFBSSxRQUFRLENBQUMsQ0FBQztJQUMzRSxDQUFDO0lBRU0sb0JBQW9CLENBQUMsT0FBZSxFQUFFLEtBQThDO1FBQ3pGLG9CQUFvQjtRQUNwQixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ2hDLFVBQVUsQ0FBQyxHQUFHLEVBQUU7Z0JBQ2QsS0FBSyxDQUFDLEVBQUUsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDLE1BQVcsRUFBRSxFQUFFO29CQUMxQyxPQUFPLENBQUMsR0FBRyxDQUFDLGFBQWEsRUFBRSxNQUFNLENBQUMsQ0FBQztvQkFDbkMsSUFBSSxDQUFDLGFBQWEsR0FBRyxNQUFNLENBQUM7b0JBQzVCLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQzt3QkFDeEIsZUFBZSxFQUFFLE1BQU07d0JBQ3ZCLGdCQUFnQixFQUFFLElBQUk7d0JBQ3RCLE9BQU8sRUFBRSw0RkFBNEY7cUJBQUMsQ0FBQyxDQUFDLENBQUM7b0JBQzFHLEtBQWEsQ0FBQyxHQUFHLEVBQUUsQ0FBQztnQkFDdkIsQ0FBQyxDQUFDLENBQUM7WUFDTCxDQUFDLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDZCxDQUFDLENBQUMsQ0FBQztRQUNILG9CQUFvQjtJQUN0QixDQUFDO0lBRU0sS0FBSyxDQUFDLElBQUksQ0FDZixRQUFrQixFQUNsQixNQUEwQixFQUMxQixrQkFBK0IsRUFBRTtRQUVqQyxNQUFNLFdBQVcsR0FBZ0I7WUFDL0IsR0FBRyxJQUFJLENBQUMsY0FBYztZQUN0QixHQUFHLGVBQWU7U0FDbkIsQ0FBQztRQUVGLE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FDN0IsUUFBUSxFQUNSLE1BQU0sRUFDTixXQUFXLENBQ1osQ0FBQztRQUNGLE9BQU8sTUFBTSxDQUFDO0lBQ2hCLENBQUM7SUFFTyxLQUFLLENBQUMsS0FBSyxDQUNqQixRQUFrQixFQUNsQixNQUEwQixFQUMxQixjQUEyQixFQUFFO1FBRTdCLE1BQU0sRUFDSixhQUFhLEVBQ2IsZ0JBQWdCLEVBQ2hCLGFBQWEsRUFDYixjQUFjLEVBQ2QsT0FBTyxFQUNQLEdBQUcsU0FBUyxFQUViLEdBQUcsV0FBVyxDQUFDO1FBRWhCLElBQUksZ0JBQWdCLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUMsUUFBUSxDQUFDLGdCQUFnQixDQUFDLEVBQUU7WUFDbkYsTUFBTSxJQUFJLEtBQUssQ0FBQyw4QkFBOEIsZ0JBQWdCLEVBQUUsQ0FBQyxDQUFDO1NBQ25FO1FBRUQsSUFBSSxnQkFBZ0IsS0FBSyxnQkFBZ0IsQ0FBQyxRQUFRLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFO1lBQ3BFLE1BQU0sV0FBVyxHQUFHLE1BQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLEVBQUUsU0FBUyxDQUFDLENBQUM7WUFDOUQsU0FBUyxDQUFDLEdBQUcsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVcsR0FBRyxhQUFjLENBQUMsQ0FBQztZQUV6RCxJQUFJLGdCQUFnQixLQUFLLGdCQUFnQixDQUFDLFFBQVEsRUFBRTtnQkFDbEQsT0FBTztvQkFDTCxXQUFXO29CQUNYLEdBQUcsRUFBRSxTQUFTLENBQUMsR0FBRztpQkFDbkIsQ0FBQzthQUNIO1NBQ0Y7UUFFRCxJQUFJLFdBQVcsR0FBRyxRQUFRLENBQUMsT0FBTyxDQUFDO1FBQ25DLElBQUksbUJBQW1CLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQztRQUUzQyxJQUFJLGdCQUFnQixLQUFLLGdCQUFnQixDQUFDLE1BQU0sRUFBRTtZQUNoRCxNQUFNLElBQUksR0FBVyxNQUFNLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDeEMsTUFBTSxJQUFJLEdBQWtCLFNBQVMsQ0FBQyxJQUFJLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUM7WUFFdkUsSUFBSSxJQUFJLEtBQUssSUFBSSxFQUFFO2dCQUNqQixNQUFNLElBQUksS0FBSyxDQUFDLHVDQUF1QyxDQUFDLENBQUM7YUFDMUQ7WUFDRCxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxFQUFFO2dCQUM1QixNQUFNLElBQUksS0FBSyxDQUFDLHdDQUF3QyxDQUFDLENBQUM7YUFDM0Q7WUFDRCxNQUFNLGdCQUFnQixHQUFZLENBQUMsT0FBTyxTQUFTLENBQUMsS0FBSyxLQUFLLFFBQVEsQ0FBQztnQkFDcEUsU0FBUyxDQUFDLEtBQWdCLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzdDLE1BQU0sT0FBTyxHQUFjLElBQUksU0FBUyxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7WUFFdEYsT0FBTyxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDO2dCQUNoRCxHQUFHLEVBQUUsU0FBUyxDQUFDLEdBQUc7Z0JBQ2xCLEtBQUssRUFBRSxTQUFTLENBQUMsS0FBSztnQkFDdEIsUUFBUSxFQUFFLFNBQVMsQ0FBQyxRQUFRO2dCQUM1QixFQUFFLEVBQUUsUUFBUSxDQUFDLE9BQU8sQ0FBQyxPQUFPO2dCQUM1QixJQUFJO2dCQUNKLEtBQUssRUFBRSxPQUFPLENBQUMsUUFBUSxFQUFFO2dCQUN6QixJQUFJO2FBQ0wsQ0FBQyxDQUFDLENBQUM7WUFFSixJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsRUFBRTtnQkFDbEIsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO2FBQ3BDO1lBRUQsTUFBTSxPQUFPLEdBQW1DLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQztnQkFDNUUsR0FBRyxFQUFFLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLElBQUksTUFBTTtnQkFDcEMsS0FBSyxFQUFFLFNBQVMsQ0FBQyxLQUFLO2dCQUN0QixRQUFRLEVBQUUsU0FBUyxDQUFDLFFBQVE7Z0JBQzVCLEVBQUUsRUFBRSxRQUFRLENBQUMsT0FBTyxDQUFDLE9BQU87Z0JBQzVCLElBQUk7Z0JBQ0osS0FBSyxFQUFFLE9BQU8sQ0FBQyxRQUFRLEVBQUU7Z0JBQ3pCLElBQUk7YUFDTCxDQUFDLENBQUM7WUFFSCw0REFBNEQ7WUFDNUQsTUFBTSxTQUFTLEdBQUcsSUFBSSxPQUFPLENBQzNCLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBUSxFQUFFO2dCQUN4QixPQUFPLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDLEtBQVksRUFBRSxFQUFFO29CQUNuQyxJQUFJLFdBQVcsS0FBSyxRQUFRLENBQUMsT0FBTyxFQUFFO3dCQUNwQyxXQUFXLEdBQUcsUUFBUSxDQUFDLFFBQVEsQ0FBQzt3QkFFaEMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO3dCQUNiLE9BQWUsQ0FBQyxHQUFHLEVBQUUsQ0FBQztxQkFDeEI7Z0JBQ0gsQ0FBQyxDQUFDLENBQUM7Z0JBRUgsT0FBTyxDQUFDLEVBQUUsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDLE1BQWMsRUFBUSxFQUFFO29CQUNyRCxJQUFJLFdBQVcsS0FBSyxRQUFRLENBQUMsT0FBTyxFQUFFO3dCQUNwQyxXQUFXLEdBQUcsUUFBUSxDQUFDLFFBQVEsQ0FBQzt3QkFDaEMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDO3dCQUNmLE9BQWUsQ0FBQyxHQUFHLEVBQUUsQ0FBQztxQkFDeEI7Z0JBQ0gsQ0FBQyxDQUFDLENBQUM7WUFDTCxDQUFDLENBQ0YsQ0FBQztZQUNGLE1BQU0sUUFBUSxHQUFHLE1BQU0sU0FBUyxDQUFDO1lBQ2pDLDREQUE0RDtZQUU1RCxPQUFPLGlCQUFpQixDQUFDLEVBQUUsZUFBZSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7U0FDekQ7UUFFRCx5REFBeUQ7UUFDekQsZ0RBQWdEO1FBQ2hELEtBQUs7UUFFTCxNQUFNLElBQUksR0FBa0IsU0FBUyxDQUFDLElBQUksSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQztRQUN2RSxJQUFJLElBQUksS0FBSyxJQUFJLEVBQUU7WUFDakIsTUFBTSxJQUFJLEtBQUssQ0FBQyx1Q0FBdUMsQ0FBQyxDQUFDO1NBQzFEO1FBQ0QsSUFBSSxDQUFDLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsRUFBRTtZQUM1QixNQUFNLElBQUksS0FBSyxDQUFDLHdDQUF3QyxDQUFDLENBQUM7U0FDM0Q7UUFFRCxNQUFNLElBQUksR0FBVyxNQUFNLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDeEMsTUFBTSxnQkFBZ0IsR0FBWSxDQUFDLE9BQU8sU0FBUyxDQUFDLEtBQUssS0FBSyxRQUFRLENBQUM7WUFDcEUsU0FBUyxDQUFDLEtBQWdCLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzdDLE1BQU0sT0FBTyxHQUFjLElBQUksU0FBUyxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFdEYsT0FBTyxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDO1lBQ2hELEdBQUcsRUFBRSxTQUFTLENBQUMsR0FBRztZQUNsQixLQUFLLEVBQUUsU0FBUyxDQUFDLEtBQUs7WUFDdEIsUUFBUSxFQUFFLFNBQVMsQ0FBQyxRQUFRO1lBQzVCLEVBQUUsRUFBRSxRQUFRLENBQUMsT0FBTyxDQUFDLE9BQU87WUFDNUIsSUFBSTtZQUNKLEtBQUssRUFBRSxPQUFPLENBQUMsUUFBUSxFQUFFO1lBQ3pCLElBQUk7U0FDTCxDQUFDLENBQUMsQ0FBQztRQUVKLE1BQU0sS0FBSyxHQUFtQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUM7WUFDMUUsR0FBRyxFQUFFLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDO1lBQzFCLEtBQUssRUFBRSxTQUFTLENBQUMsS0FBSztZQUN0QixRQUFRLEVBQUUsU0FBUyxDQUFDLFFBQVE7WUFDNUIsRUFBRSxFQUFFLFFBQVEsQ0FBQyxPQUFPLENBQUMsT0FBTztZQUM1QixJQUFJO1lBQ0osS0FBSyxFQUFFLE9BQU8sQ0FBQyxRQUFRLEVBQUU7WUFDekIsSUFBSTtTQUNMLENBQUMsQ0FBQztRQUVILElBQUksZUFBNkIsQ0FBQztRQUNsQyxJQUFJLFdBQTRCLENBQUM7UUFDakMsSUFBSSxtQkFBc0QsQ0FBQztRQUUzRCxJQUFJLGdCQUFnQixJQUFJO1lBQ3RCLGdCQUFnQixDQUFDLElBQUk7WUFDckIsZ0JBQWdCLENBQUMsSUFBSTtTQUN0QixDQUFDLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFO1lBQzVCLFdBQVcsR0FBRyxJQUFJLE9BQU8sQ0FDdkIsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7Z0JBQ2xCLEtBQUssQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUMsS0FBWSxFQUFFLEVBQUU7b0JBQ2pDLElBQUksV0FBVyxLQUFLLFFBQVEsQ0FBQyxPQUFPLEVBQUU7d0JBQ3BDLFdBQVcsR0FBRyxRQUFRLENBQUMsUUFBUSxDQUFDO3dCQUNoQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7d0JBQ2IsS0FBYSxDQUFDLEdBQUcsRUFBRSxDQUFDO3FCQUN0QjtnQkFDSCxDQUFDLENBQUMsQ0FBQztnQkFFSCxLQUFLLENBQUMsRUFBRSxDQUFDLGlCQUFpQixFQUFFLENBQUMsTUFBYyxFQUFFLEVBQUU7b0JBQzdDLElBQUksV0FBVyxLQUFLLFFBQVEsQ0FBQyxPQUFPLEVBQUU7d0JBQ3BDLFdBQVcsR0FBRyxRQUFRLENBQUMsUUFBUSxDQUFDO3dCQUNoQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7d0JBQ2hCLElBQUksZ0JBQWdCLEtBQUssZ0JBQWdCLENBQUMsSUFBSSxFQUFFOzRCQUM3QyxLQUFhLENBQUMsR0FBRyxFQUFFLENBQUM7eUJBQ3RCO3FCQUNGO2dCQUNILENBQUMsQ0FBQyxDQUFDO1lBQ0wsQ0FBQyxDQUNGLENBQUM7WUFDRixlQUFlLEdBQUcsTUFBTSxXQUFXLENBQUM7U0FDckM7UUFFRCw2Q0FBNkM7UUFDN0MsK0JBQStCO1FBRS9CLElBQUksZ0JBQWdCLElBQUk7WUFDdEIsZ0JBQWdCLENBQUMsU0FBUztZQUMxQixnQkFBZ0IsQ0FBQyxJQUFJO1NBQ3RCLENBQUMsUUFBUSxDQUFDLGdCQUFnQixDQUFDLEVBQUU7WUFHNUIsSUFBSSxjQUFjLEVBQUU7Z0JBQ2xCLG1CQUFtQixHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUM7b0JBQ2pDLElBQUksT0FBTyxDQUNULENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO3dCQUNsQixLQUFLLENBQUMsRUFBRSxDQUFDLGlCQUFpQixFQUFFLENBQUMsTUFBVyxFQUFFLEVBQUU7NEJBQzFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsYUFBYSxFQUFFLE1BQU0sQ0FBQyxDQUFDOzRCQUNuQyxJQUFJLENBQUMsYUFBYSxHQUFHLE1BQU0sQ0FBQzt3QkFDOUIsQ0FBQyxDQUFDLENBQUM7d0JBQ0gsS0FBSyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxLQUFZLEVBQUUsRUFBRTs0QkFDakMsSUFDRSxtQkFBbUIsS0FBSyxRQUFRLENBQUMsT0FBTztnQ0FDeEMsQ0FDRSxnQkFBZ0IsS0FBSyxnQkFBZ0IsQ0FBQyxTQUFTO29DQUMvQyxXQUFXLEtBQUssUUFBUSxDQUFDLFFBQVEsQ0FDbEMsRUFDRDtnQ0FFQSxtQkFBbUIsR0FBRyxRQUFRLENBQUMsUUFBUSxDQUFDO2dDQUN4QyxNQUFNLFVBQVUsR0FBRyxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUM7Z0NBQ3BDLE1BQU0saUJBQWlCLEdBQUcsV0FBVyxDQUFDO2dDQUN0QyxNQUFNLFlBQVksR0FBRywwQkFBMEIsQ0FBQztnQ0FFaEQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxjQUFjLEVBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO2dDQUNsRCxPQUFPLENBQUMsR0FBRyxDQUFDLG9CQUFvQixFQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztnQ0FDeEQsSUFBSSxVQUFVO3VDQUNULENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxpQkFBaUIsQ0FBQzt1Q0FDdkMsQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsRUFBRTtvQ0FDOUQsbUJBQW1CLEdBQUcsUUFBUSxDQUFDLFFBQVEsQ0FBQztvQ0FDeEMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO29DQUNiLEtBQWEsQ0FBQyxHQUFHLEVBQUUsQ0FBQztpQ0FDdEI7cUNBQU0sSUFBSSxVQUFVLElBQUksQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLGlCQUFpQixDQUFDLElBQUksVUFBVSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsQ0FBQyxJQUFLLElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtvQ0FDeEksbUJBQW1CLEdBQUcsUUFBUSxDQUFDLFFBQVEsQ0FBQztvQ0FDeEMsT0FBTyxDQUFDLGlCQUFpQixDQUFDO3dDQUN4QixlQUFlLEVBQUUsSUFBSSxDQUFDLGFBQWE7d0NBQ25DLGdCQUFnQixFQUFFLElBQUk7d0NBQ3RCLE9BQU8sRUFBRSw0RkFBNEY7cUNBQUMsQ0FBQyxDQUFDLENBQUM7b0NBQzFHLEtBQWEsQ0FBQyxHQUFHLEVBQUUsQ0FBQztpQ0FDdEI7cUNBQU07b0NBQ0wsbUJBQW1CLEdBQUcsUUFBUSxDQUFDLFFBQVEsQ0FBQztvQ0FDeEMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO29DQUNiLEtBQWEsQ0FBQyxHQUFHLEVBQUUsQ0FBQztpQ0FDdEI7NkJBQ0Y7d0JBQ0gsQ0FBQyxDQUFDLENBQUM7d0JBRUgsSUFBSSxhQUFhLEVBQUU7NEJBQ2pCLEtBQUssQ0FBQyxFQUFFLENBQUMsY0FBYyxFQUFFLENBQUMsVUFBZSxFQUFFLE9BQVksRUFBRSxFQUFFO2dDQUN6RCxJQUFJLFVBQVUsSUFBSSxhQUFhLEVBQUU7b0NBQy9CLElBQUksbUJBQW1CLEtBQUssUUFBUSxDQUFDLE9BQU8sRUFBRTt3Q0FDNUMsbUJBQW1CLEdBQUcsUUFBUSxDQUFDLFFBQVEsQ0FBQzt3Q0FDeEMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO3dDQUNoQixLQUFhLENBQUMsR0FBRyxFQUFFLENBQUM7cUNBQ3RCO2lDQUNGOzRCQUNILENBQUMsQ0FBQyxDQUFDO3lCQUNKOzZCQUFNOzRCQUNMLEtBQUssQ0FBQyxFQUFFLENBQUMsU0FBUyxFQUFFLENBQUMsT0FBWSxFQUFFLEVBQUU7Z0NBQ25DLG1CQUFtQixHQUFHLFFBQVEsQ0FBQyxRQUFRLENBQUM7Z0NBQ3hDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQztnQ0FDaEIsS0FBYSxDQUFDLEdBQUcsRUFBRSxDQUFDOzRCQUN2QixDQUFDLENBQUMsQ0FBQzt5QkFDSjtvQkFDSCxDQUFDLENBQUM7b0JBQ0YsSUFBSSxDQUFDLG9CQUFvQixDQUFDLE9BQU8sSUFBSSxNQUFNLEVBQUUsS0FBSyxDQUFDO2lCQUN0RCxDQUFDLENBQUM7YUFDSjtpQkFBTTtnQkFDTCxtQkFBbUIsR0FBRyxJQUFJLE9BQU8sQ0FDL0IsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7b0JBQ2xCLEtBQUssQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUMsS0FBWSxFQUFFLEVBQUU7d0JBQ2pDLElBQ0UsbUJBQW1CLEtBQUssUUFBUSxDQUFDLE9BQU87NEJBQ3hDLENBQ0UsZ0JBQWdCLEtBQUssZ0JBQWdCLENBQUMsU0FBUztnQ0FDL0MsV0FBVyxLQUFLLFFBQVEsQ0FBQyxRQUFRLENBQ2xDLEVBQ0Q7NEJBQ0EsT0FBTyxDQUFDLEdBQUcsQ0FBQyxXQUFXLEVBQUUsS0FBSyxDQUFDLENBQUM7NEJBQ2hDLG1CQUFtQixHQUFHLFFBQVEsQ0FBQyxRQUFRLENBQUM7NEJBQ3hDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQzs0QkFDYixLQUFhLENBQUMsR0FBRyxFQUFFLENBQUM7eUJBQ3RCO29CQUNILENBQUMsQ0FBQyxDQUFDO29CQUVILElBQUksYUFBYSxFQUFFO3dCQUNqQixLQUFLLENBQUMsRUFBRSxDQUFDLGNBQWMsRUFBRSxDQUFDLFVBQWUsRUFBRSxPQUFZLEVBQUUsRUFBRTs0QkFDekQsSUFBSSxVQUFVLElBQUksYUFBYSxFQUFFO2dDQUMvQixJQUFJLG1CQUFtQixLQUFLLFFBQVEsQ0FBQyxPQUFPLEVBQUU7b0NBQzVDLG1CQUFtQixHQUFHLFFBQVEsQ0FBQyxRQUFRLENBQUM7b0NBQ3hDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQztvQ0FDaEIsS0FBYSxDQUFDLEdBQUcsRUFBRSxDQUFDO2lDQUN0Qjs2QkFDRjt3QkFDSCxDQUFDLENBQUMsQ0FBQztxQkFDSjt5QkFBTTt3QkFDTCxLQUFLLENBQUMsRUFBRSxDQUFDLFNBQVMsRUFBRSxDQUFDLE9BQVksRUFBRSxFQUFFOzRCQUNuQyxtQkFBbUIsR0FBRyxRQUFRLENBQUMsUUFBUSxDQUFDOzRCQUN4QyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7NEJBQ2hCLEtBQWEsQ0FBQyxHQUFHLEVBQUUsQ0FBQzt3QkFDdkIsQ0FBQyxDQUFDLENBQUM7cUJBQ0o7Z0JBQ0gsQ0FBQyxDQUNGLENBQUM7YUFDSDtTQUdGO1FBRUQsSUFBSSxnQkFBZ0IsS0FBSyxnQkFBZ0IsQ0FBQyxJQUFJLEVBQUU7WUFDOUMsT0FBTyxpQkFBaUIsQ0FBQyxFQUFFLGVBQWUsRUFBRSxDQUFDLENBQUM7U0FDL0M7UUFFRCxJQUFJLGdCQUFnQixLQUFLLGdCQUFnQixDQUFDLFNBQVMsRUFBRTtZQUNuRCxPQUFPLG1CQUFtQixDQUFDO1NBQzVCO1FBRUQsT0FBTyxpQkFBaUIsQ0FBQztZQUN2QixlQUFlO1lBQ2YsWUFBWSxFQUFFLG1CQUFtQjtTQUNsQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU8sS0FBSyxDQUFDLFdBQVcsQ0FDdkIsTUFBMEIsRUFDMUIsU0FBc0I7UUFFdEIsTUFBTSxlQUFlLEdBQWMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ3JFLElBQUk7WUFDRixNQUFNLFdBQVcsR0FBRyxNQUFNLE1BQU0sQ0FBQyxXQUFXLENBQUMsZUFBcUMsQ0FBQyxDQUFDO1lBQ3BGLE9BQU8sV0FBVyxDQUFDO1NBQ3BCO1FBQUMsT0FBTyxLQUFVLEVBQUU7WUFDbkIsS0FBSyxDQUFDLGVBQWUsR0FBRztnQkFDdEIsR0FBRyxlQUFlO2dCQUNsQixJQUFJLEVBQUUsTUFBTSxDQUFDLFNBQVMsRUFBRTtnQkFDeEIsRUFBRSxFQUFHLE1BQWMsQ0FBQyxPQUFPLENBQUMsUUFBUTthQUNyQyxDQUFDO1lBQ0YsTUFBTSxLQUFLLENBQUM7U0FDYjtJQUNILENBQUM7SUFFRCwwQ0FBMEM7SUFFbEMsaUJBQWlCLENBQ3ZCLE9BQW9CO1FBRXBCLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUU7WUFDckIsTUFBTTtZQUNOLE9BQU87U0FDUixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU8sYUFBYSxDQUNuQixPQUFZO1FBRVosT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRTtZQUNyQixNQUFNO1lBQ04sT0FBTztZQUNQLGFBQWE7U0FDZCxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU8sbUJBQW1CLENBQ3pCLE9BQVk7UUFFWixPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFO1lBQ3JCLE1BQU07WUFDTixPQUFPO1lBQ1AsVUFBVTtZQUNWLEtBQUs7WUFDTCxPQUFPO1NBQ1IsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztDQUVGIn0=