web3x
Version:
Typescript port of web3.js
305 lines (302 loc) • 20.1 kB
JavaScript
;
/*
This file is part of web3x.
web3x is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
web3x is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with web3x. If not, see <http://www.gnu.org/licenses/>.
*/
Object.defineProperty(exports, "__esModule", { value: true });
const util_1 = require("util");
const abi_coder_1 = require("../../ethers/abi-coder");
const utils_1 = require("../../utils");
/**
* ABICoder prototype should be used to encode/decode solidity params of any type
*/
class ABICoder {
constructor() {
this.ethersAbiCoder = new abi_coder_1.AbiCoder((type, value) => {
if (type.match(/^u?int/) && !util_1.isArray(value) && (!util_1.isObject(value) || value.constructor.name !== 'BN')) {
return value.toString();
}
return value;
});
}
/**
* Encodes the function name to its ABI representation, which are the first 4 bytes of the sha3 of the function name including types.
*
* @method encodeFunctionSignature
* @param {String|Object} functionName
* @return {String} encoded function name
*/
encodeFunctionSignature(functionName) {
if (util_1.isObject(functionName)) {
functionName = this.abiMethodToString(functionName);
}
return utils_1.sha3(functionName).slice(0, 10);
}
/**
* Encodes the function name to its ABI representation, which are the first 4 bytes of the sha3 of the function name including types.
*
* @method encodeEventSignature
* @param {String|Object} functionName
* @return {String} encoded function name
*/
encodeEventSignature(functionName) {
if (util_1.isObject(functionName)) {
functionName = this.abiMethodToString(functionName);
}
return utils_1.sha3(functionName);
}
/**
* Should be used to encode plain param
*
* @method encodeParameter
* @param {String} type
* @param {Object} param
* @return {String} encoded plain param
*/
encodeParameter(type, param) {
return this.encodeParameters([type], [param]);
}
/**
* Should be used to encode list of params
*
* @method encodeParameters
* @param {Array} types
* @param {Array} params
* @return {String} encoded list of params
*/
encodeParameters(types, params) {
return this.ethersAbiCoder.encode(this.mapTypes(types), params);
}
/**
* Encodes a function call from its json interface and parameters.
*
* @method encodeFunctionCall
* @param {Array} jsonInterface
* @param {Array} params
* @return {String} The encoded ABI for this function call
*/
encodeFunctionCall(jsonInterface, params) {
return (this.encodeFunctionSignature(jsonInterface) +
this.encodeParameters(jsonInterface.inputs, params).replace('0x', ''));
}
/**
* Should be used to decode bytes to plain param
*
* @method decodeParameter
* @param {String} type
* @param {String} bytes
* @return {Object} plain param
*/
decodeParameter(type, bytes) {
return this.decodeParameters([type], bytes)[0];
}
/**
* Should be used to decode list of params
*
* @method decodeParameter
* @param {Array} outputs
* @param {String} bytes
* @return {Array} array of plain params
*/
decodeParameters(outputs, bytes) {
if (!bytes || bytes === '0x' || bytes === '0X') {
throw new Error("Returned values aren't valid, did it run Out of Gas?");
}
const res = this.ethersAbiCoder.decode(this.mapTypes(outputs), '0x' + bytes.replace(/0x/i, ''));
const returnValue = {};
returnValue.__length__ = 0;
outputs.forEach((output, i) => {
let decodedValue = res[returnValue.__length__];
decodedValue = decodedValue === '0x' ? null : decodedValue;
returnValue[i] = decodedValue;
if (util_1.isObject(output) && output.name) {
returnValue[output.name] = decodedValue;
}
returnValue.__length__++;
});
return returnValue;
}
/**
* Decodes events non- and indexed parameters.
*
* @method decodeLog
* @param {Object} inputs
* @param {String} data
* @param {Array} topics
* @return {Array} array of plain params
*/
decodeLog(inputs, data, topics) {
topics = util_1.isArray(topics) ? topics : [topics];
data = data || '';
const notIndexedInputs = [];
const indexedParams = [];
let topicCount = 0;
// TODO check for anonymous logs?
inputs.forEach((input, i) => {
if (input.indexed) {
indexedParams[i] = ['bool', 'int', 'uint', 'address', 'fixed', 'ufixed'].some(t => input.type.includes(t))
? this.decodeParameter(input.type, topics[topicCount])
: topics[topicCount];
topicCount++;
}
else {
notIndexedInputs[i] = input;
}
});
const nonIndexedData = data;
const notIndexedParams = nonIndexedData && nonIndexedData !== '0x' ? this.decodeParameters(notIndexedInputs, nonIndexedData) : [];
const returnValue = {};
returnValue.__length__ = 0;
inputs.forEach((res, i) => {
returnValue[i] = res.type === 'string' ? '' : null;
if (typeof notIndexedParams[i] !== 'undefined') {
returnValue[i] = notIndexedParams[i];
}
if (typeof indexedParams[i] !== 'undefined') {
returnValue[i] = indexedParams[i];
}
if (res.name) {
returnValue[res.name] = returnValue[i];
}
returnValue.__length__++;
});
return returnValue;
}
/**
* Map types if simplified format is used
*
* @method mapTypes
* @param {Array} types
* @return {Array}
*/
mapTypes(types) {
const mappedTypes = [];
types.forEach(type => {
if (this.isSimplifiedStructFormat(type)) {
const structName = Object.keys(type)[0];
mappedTypes.push(Object.assign(this.mapStructNameAndType(structName), {
components: this.mapStructToCoderFormat(type[structName]),
}));
return;
}
mappedTypes.push(type);
});
return mappedTypes;
}
/**
* Check if type is simplified struct format
*
* @method isSimplifiedStructFormat
* @param {string | Object} type
* @returns {boolean}
*/
isSimplifiedStructFormat(type) {
return typeof type === 'object' && typeof type.components === 'undefined' && typeof type.name === 'undefined';
}
/**
* Maps the correct tuple type and name when the simplified format in encode/decodeParameter is used
*
* @method mapStructNameAndType
* @param {string} structName
* @return {{type: string, name: *}}
*/
mapStructNameAndType(structName) {
let type = 'tuple';
if (structName.indexOf('[]') > -1) {
type = 'tuple[]';
structName = structName.slice(0, -2);
}
return { type, name: structName };
}
/**
* Maps the simplified format in to the expected format of the ABICoder
*
* @method mapStructToCoderFormat
* @param {Object} struct
* @return {Array}
*/
mapStructToCoderFormat(struct) {
const components = [];
Object.keys(struct).forEach(key => {
if (typeof struct[key] === 'object') {
components.push(Object.assign(this.mapStructNameAndType(key), {
components: this.mapStructToCoderFormat(struct[key]),
}));
return;
}
components.push({
name: key,
type: struct[key],
});
});
return components;
}
/**
* Should be used to create full function/event name from json abi
*
* @method jsonInterfaceMethodToString
* @param {Object} json
* @return {String} full function/event name
*/
abiMethodToString(json) {
if (util_1.isObject(json) && json.name && json.name.indexOf('(') !== -1) {
return json.name;
}
return json.name + '(' + flattenTypes(false, json.inputs).join(',') + ')';
}
}
exports.ABICoder = ABICoder;
/**
* Should be used to flatten json abi inputs/outputs into an array of type-representing-strings
*
* @method flattenTypes
* @param {bool} includeTuple
* @param {Object} puts
* @return {Array} parameters as strings
*/
function flattenTypes(includeTuple, puts) {
// console.log("entered _flattenTypes. inputs/outputs: " + puts)
const types = [];
puts.forEach(param => {
if (typeof param.components === 'object') {
if (param.type.substring(0, 5) !== 'tuple') {
throw new Error('components found but type is not tuple; report on GitHub');
}
let suffix = '';
const arrayBracket = param.type.indexOf('[');
if (arrayBracket >= 0) {
suffix = param.type.substring(arrayBracket);
}
const result = flattenTypes(includeTuple, param.components);
// console.log("result should have things: " + result)
if (util_1.isArray(result) && includeTuple) {
// console.log("include tuple word, and its an array. joining...: " + result.types)
types.push('tuple(' + result.join(',') + ')' + suffix);
}
else if (!includeTuple) {
// console.log("don't include tuple, but its an array. joining...: " + result)
types.push('(' + result.join(',') + ')' + suffix);
}
else {
// console.log("its a single type within a tuple: " + result.types)
types.push('(' + result + ')');
}
}
else {
// console.log("its a type and not directly in a tuple: " + param.type)
types.push(param.type);
}
});
return types;
}
exports.abiCoder = new ABICoder();
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY29udHJhY3QvYWJpLWNvZGVyL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7Ozs7Ozs7O0VBZUU7O0FBRUYsK0JBQXlDO0FBQ3pDLHNEQUErRDtBQUMvRCx1Q0FBbUM7QUFHbkM7O0dBRUc7QUFDSCxNQUFhLFFBQVE7SUFHbkI7UUFDRSxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksb0JBQVMsQ0FBQyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRTtZQUNsRCxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxjQUFPLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLGVBQVEsQ0FBQyxLQUFLLENBQUMsSUFBSSxLQUFLLENBQUMsV0FBVyxDQUFDLElBQUksS0FBSyxJQUFJLENBQUMsRUFBRTtnQkFDcEcsT0FBTyxLQUFLLENBQUMsUUFBUSxFQUFFLENBQUM7YUFDekI7WUFDRCxPQUFPLEtBQUssQ0FBQztRQUNmLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNJLHVCQUF1QixDQUFDLFlBQVk7UUFDekMsSUFBSSxlQUFRLENBQUMsWUFBWSxDQUFDLEVBQUU7WUFDMUIsWUFBWSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxZQUFZLENBQUMsQ0FBQztTQUNyRDtRQUVELE9BQU8sWUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDekMsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNJLG9CQUFvQixDQUFDLFlBQVk7UUFDdEMsSUFBSSxlQUFRLENBQUMsWUFBWSxDQUFDLEVBQUU7WUFDMUIsWUFBWSxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxZQUFZLENBQUMsQ0FBQztTQUNyRDtRQUVELE9BQU8sWUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO0lBQzVCLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0ksZUFBZSxDQUFDLElBQUksRUFBRSxLQUFLO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBQ2hELENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0ksZ0JBQWdCLENBQUMsS0FBSyxFQUFFLE1BQU07UUFDbkMsT0FBTyxJQUFJLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ2xFLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0ksa0JBQWtCLENBQUMsYUFBYSxFQUFFLE1BQU07UUFDN0MsT0FBTyxDQUNMLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxhQUFhLENBQUM7WUFDM0MsSUFBSSxDQUFDLGdCQUFnQixDQUFDLGFBQWEsQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FDdEUsQ0FBQztJQUNKLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0ksZUFBZSxDQUFDLElBQUksRUFBRSxLQUFLO1FBQ2hDLE9BQU8sSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDakQsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSSxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsS0FBSztRQUNwQyxJQUFJLENBQUMsS0FBSyxJQUFJLEtBQUssS0FBSyxJQUFJLElBQUksS0FBSyxLQUFLLElBQUksRUFBRTtZQUM5QyxNQUFNLElBQUksS0FBSyxDQUFDLHNEQUFzRCxDQUFDLENBQUM7U0FDekU7UUFFRCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxFQUFFLElBQUksR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ2hHLE1BQU0sV0FBVyxHQUFRLEVBQUUsQ0FBQztRQUM1QixXQUFXLENBQUMsVUFBVSxHQUFHLENBQUMsQ0FBQztRQUUzQixPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQzVCLElBQUksWUFBWSxHQUFHLEdBQUcsQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDLENBQUM7WUFDL0MsWUFBWSxHQUFHLFlBQVksS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDO1lBRTNELFdBQVcsQ0FBQyxDQUFDLENBQUMsR0FBRyxZQUFZLENBQUM7WUFFOUIsSUFBSSxlQUFRLENBQUMsTUFBTSxDQUFDLElBQUksTUFBTSxDQUFDLElBQUksRUFBRTtnQkFDbkMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxZQUFZLENBQUM7YUFDekM7WUFFRCxXQUFXLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDM0IsQ0FBQyxDQUFDLENBQUM7UUFFSCxPQUFPLFdBQVcsQ0FBQztJQUNyQixDQUFDO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSSxTQUFTLENBQUMsTUFBa0IsRUFBRSxJQUFJLEVBQUUsTUFBTTtRQUMvQyxNQUFNLEdBQUcsY0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFN0MsSUFBSSxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7UUFFbEIsTUFBTSxnQkFBZ0IsR0FBVSxFQUFFLENBQUM7UUFDbkMsTUFBTSxhQUFhLEdBQVUsRUFBRSxDQUFDO1FBQ2hDLElBQUksVUFBVSxHQUFHLENBQUMsQ0FBQztRQUVuQixpQ0FBaUM7UUFFakMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUMxQixJQUFJLEtBQUssQ0FBQyxPQUFPLEVBQUU7Z0JBQ2pCLGFBQWEsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsUUFBUSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUM7b0JBQ3hHLENBQUMsQ0FBQyxJQUFJLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO29CQUN0RCxDQUFDLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO2dCQUN2QixVQUFVLEVBQUUsQ0FBQzthQUNkO2lCQUFNO2dCQUNMLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQzthQUM3QjtRQUNILENBQUMsQ0FBQyxDQUFDO1FBRUgsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDO1FBQzVCLE1BQU0sZ0JBQWdCLEdBQ3BCLGNBQWMsSUFBSSxjQUFjLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsZ0JBQWdCLEVBQUUsY0FBYyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUUzRyxNQUFNLFdBQVcsR0FBUSxFQUFFLENBQUM7UUFDNUIsV0FBVyxDQUFDLFVBQVUsR0FBRyxDQUFDLENBQUM7UUFFM0IsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUN4QixXQUFXLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFDLElBQUksS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1lBRW5ELElBQUksT0FBTyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsS0FBSyxXQUFXLEVBQUU7Z0JBQzlDLFdBQVcsQ0FBQyxDQUFDLENBQUMsR0FBRyxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQzthQUN0QztZQUNELElBQUksT0FBTyxhQUFhLENBQUMsQ0FBQyxDQUFDLEtBQUssV0FBVyxFQUFFO2dCQUMzQyxXQUFXLENBQUMsQ0FBQyxDQUFDLEdBQUcsYUFBYSxDQUFDLENBQUMsQ0FBQyxDQUFDO2FBQ25DO1lBRUQsSUFBSSxHQUFHLENBQUMsSUFBSSxFQUFFO2dCQUNaLFdBQVcsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDO2FBQ3hDO1lBRUQsV0FBVyxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQzNCLENBQUMsQ0FBQyxDQUFDO1FBRUgsT0FBTyxXQUFXLENBQUM7SUFDckIsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNLLFFBQVEsQ0FBQyxLQUFLO1FBQ3BCLE1BQU0sV0FBVyxHQUFVLEVBQUUsQ0FBQztRQUM5QixLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFO1lBQ25CLElBQUksSUFBSSxDQUFDLHdCQUF3QixDQUFDLElBQUksQ0FBQyxFQUFFO2dCQUN2QyxNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUN4QyxXQUFXLENBQUMsSUFBSSxDQUNkLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLFVBQVUsQ0FBQyxFQUFFO29CQUNuRCxVQUFVLEVBQUUsSUFBSSxDQUFDLHNCQUFzQixDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztpQkFDMUQsQ0FBQyxDQUNILENBQUM7Z0JBRUYsT0FBTzthQUNSO1lBRUQsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN6QixDQUFDLENBQUMsQ0FBQztRQUVILE9BQU8sV0FBVyxDQUFDO0lBQ3JCLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDSyx3QkFBd0IsQ0FBQyxJQUFJO1FBQ25DLE9BQU8sT0FBTyxJQUFJLEtBQUssUUFBUSxJQUFJLE9BQU8sSUFBSSxDQUFDLFVBQVUsS0FBSyxXQUFXLElBQUksT0FBTyxJQUFJLENBQUMsSUFBSSxLQUFLLFdBQVcsQ0FBQztJQUNoSCxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0ssb0JBQW9CLENBQUMsVUFBVTtRQUNyQyxJQUFJLElBQUksR0FBRyxPQUFPLENBQUM7UUFFbkIsSUFBSSxVQUFVLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFO1lBQ2pDLElBQUksR0FBRyxTQUFTLENBQUM7WUFDakIsVUFBVSxHQUFHLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDdEM7UUFFRCxPQUFPLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsQ0FBQztJQUNwQyxDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ0ssc0JBQXNCLENBQUMsTUFBTTtRQUNuQyxNQUFNLFVBQVUsR0FBVSxFQUFFLENBQUM7UUFDN0IsTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUU7WUFDaEMsSUFBSSxPQUFPLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxRQUFRLEVBQUU7Z0JBQ25DLFVBQVUsQ0FBQyxJQUFJLENBQ2IsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsb0JBQW9CLENBQUMsR0FBRyxDQUFDLEVBQUU7b0JBQzVDLFVBQVUsRUFBRSxJQUFJLENBQUMsc0JBQXNCLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2lCQUNyRCxDQUFDLENBQ0gsQ0FBQztnQkFFRixPQUFPO2FBQ1I7WUFFRCxVQUFVLENBQUMsSUFBSSxDQUFDO2dCQUNkLElBQUksRUFBRSxHQUFHO2dCQUNULElBQUksRUFBRSxNQUFNLENBQUMsR0FBRyxDQUFDO2FBQ2xCLENBQUMsQ0FBQztRQUNMLENBQUMsQ0FBQyxDQUFDO1FBRUgsT0FBTyxVQUFVLENBQUM7SUFDcEIsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNJLGlCQUFpQixDQUFDLElBQUk7UUFDM0IsSUFBSSxlQUFRLENBQUMsSUFBSSxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRTtZQUNoRSxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUM7U0FDbEI7UUFFRCxPQUFPLElBQUksQ0FBQyxJQUFJLEdBQUcsR0FBRyxHQUFHLFlBQVksQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxHQUFHLENBQUM7SUFDNUUsQ0FBQztDQUNGO0FBM1JELDRCQTJSQztBQUVEOzs7Ozs7O0dBT0c7QUFDSCxTQUFTLFlBQVksQ0FBQyxZQUFZLEVBQUUsSUFBSTtJQUN0QyxnRUFBZ0U7SUFDaEUsTUFBTSxLQUFLLEdBQVUsRUFBRSxDQUFDO0lBRXhCLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUU7UUFDbkIsSUFBSSxPQUFPLEtBQUssQ0FBQyxVQUFVLEtBQUssUUFBUSxFQUFFO1lBQ3hDLElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLE9BQU8sRUFBRTtnQkFDMUMsTUFBTSxJQUFJLEtBQUssQ0FBQywwREFBMEQsQ0FBQyxDQUFDO2FBQzdFO1lBQ0QsSUFBSSxNQUFNLEdBQUcsRUFBRSxDQUFDO1lBQ2hCLE1BQU0sWUFBWSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQzdDLElBQUksWUFBWSxJQUFJLENBQUMsRUFBRTtnQkFDckIsTUFBTSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLFlBQVksQ0FBQyxDQUFDO2FBQzdDO1lBQ0QsTUFBTSxNQUFNLEdBQUcsWUFBWSxDQUFDLFlBQVksRUFBRSxLQUFLLENBQUMsVUFBVSxDQUFDLENBQUM7WUFDNUQsc0RBQXNEO1lBQ3RELElBQUksY0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLFlBQVksRUFBRTtnQkFDbkMsbUZBQW1GO2dCQUNuRixLQUFLLENBQUMsSUFBSSxDQUFDLFFBQVEsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEdBQUcsR0FBRyxNQUFNLENBQUMsQ0FBQzthQUN4RDtpQkFBTSxJQUFJLENBQUMsWUFBWSxFQUFFO2dCQUN4Qiw4RUFBOEU7Z0JBQzlFLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsR0FBRyxHQUFHLE1BQU0sQ0FBQyxDQUFDO2FBQ25EO2lCQUFNO2dCQUNMLG1FQUFtRTtnQkFDbkUsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLEdBQUcsTUFBTSxHQUFHLEdBQUcsQ0FBQyxDQUFDO2FBQ2hDO1NBQ0Y7YUFBTTtZQUNMLHVFQUF1RTtZQUN2RSxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUN4QjtJQUNILENBQUMsQ0FBQyxDQUFDO0lBRUgsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDO0FBRVksUUFBQSxRQUFRLEdBQUcsSUFBSSxRQUFRLEVBQUUsQ0FBQyJ9