From 628c77bca315aa277cc51886c3743379208d350a Mon Sep 17 00:00:00 2001
From: Ezra Epstein
Date: Wed, 8 Nov 2017 21:10:25 -0800
Subject: [PATCH 01/16] Support for generating Java source from Truffle .json
contract files.
---
.../codegen/FunctionWrapperGenerator.java | 69 +
.../codegen/SolidityFunctionWrapper.java | 53 +-
.../SolidityFunctionWrapperGenerator.java | 61 +-
.../TruffleJsonFunctionWrapperGenerator.java | 480 ++++++
.../web3j/codegen/ContractJsonParseTest.java | 68 +
.../SolidityFunctionWrapperGeneratorTest.java | 1 -
...uffleJsonFunctionWrapperGeneratorTest.java | 101 ++
.../resources/truffle/MetaCoin/ConvertLib.sol | 8 +
.../resources/truffle/MetaCoin/MetaCoin.sol | 34 +
.../MetaCoin/build/contracts/ConvertLib.json | 281 ++++
.../MetaCoin/build/contracts/MetaCoin.json | 1431 +++++++++++++++++
.../main/java/org/web3j/console/Runner.java | 4 +
.../core/methods/response/AbiDefinition.java | 40 +
core/src/main/java/org/web3j/tx/Contract.java | 30 +
.../main/java/org/web3j/utils/Strings.java | 4 +
15 files changed, 2612 insertions(+), 53 deletions(-)
create mode 100644 codegen/src/main/java/org/web3j/codegen/FunctionWrapperGenerator.java
create mode 100644 codegen/src/main/java/org/web3j/codegen/TruffleJsonFunctionWrapperGenerator.java
create mode 100644 codegen/src/test/java/org/web3j/codegen/ContractJsonParseTest.java
create mode 100644 codegen/src/test/java/org/web3j/codegen/TruffleJsonFunctionWrapperGeneratorTest.java
create mode 100644 codegen/src/test/resources/truffle/MetaCoin/ConvertLib.sol
create mode 100644 codegen/src/test/resources/truffle/MetaCoin/MetaCoin.sol
create mode 100644 codegen/src/test/resources/truffle/MetaCoin/build/contracts/ConvertLib.json
create mode 100644 codegen/src/test/resources/truffle/MetaCoin/build/contracts/MetaCoin.json
diff --git a/codegen/src/main/java/org/web3j/codegen/FunctionWrapperGenerator.java b/codegen/src/main/java/org/web3j/codegen/FunctionWrapperGenerator.java
new file mode 100644
index 0000000000..4314f2e2a6
--- /dev/null
+++ b/codegen/src/main/java/org/web3j/codegen/FunctionWrapperGenerator.java
@@ -0,0 +1,69 @@
+package org.web3j.codegen;
+
+import java.io.File;
+
+import static org.web3j.codegen.Console.exitError;
+
+/**
+ * Abstract base class for the concrete function wrapper generators.
+ */
+abstract class FunctionWrapperGenerator {
+
+ static final String JAVA_TYPES_ARG = "--javaTypes";
+ static final String SOLIDITY_TYPES_ARG = "--solidityTypes";
+
+ final File destinationDirLocation;
+ final String basePackageName;
+ final boolean useJavaNativeTypes;
+
+ FunctionWrapperGenerator(
+ String destinationDirLocation,
+ String basePackageName,
+ boolean useJavaNativeTypes) {
+
+ this.destinationDirLocation = new File(destinationDirLocation);
+ this.basePackageName = basePackageName;
+ this.useJavaNativeTypes = useJavaNativeTypes;
+ }
+
+ static boolean useJavaNativeTypes(String argVal, String usageString) {
+ boolean useJavaNativeTypes = true;
+ if (SOLIDITY_TYPES_ARG.equals(argVal)) {
+ useJavaNativeTypes = false;
+ } else if (JAVA_TYPES_ARG.equals(argVal)) {
+ useJavaNativeTypes = true;
+ } else {
+ exitError(usageString);
+ }
+ return useJavaNativeTypes;
+ }
+
+ static String parsePositionalArg(String[] args, int idx) {
+ if (args != null && args.length > idx) {
+ return args[idx];
+ } else {
+ return "";
+ }
+ }
+
+ static String parseParameterArgument(String[] args, String... parameters) {
+ for (String parameter : parameters) {
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].equals(parameter)
+ && i + 1 < args.length) {
+ String parameterValue = args[i + 1];
+ if (!parameterValue.startsWith("-")) {
+ return parameterValue;
+ }
+ }
+ }
+ }
+ return "";
+ }
+
+ static String getFileNameNoExtension(String fileName) {
+ String[] splitName = fileName.split("\\.(?=[^.]*$)");
+ return splitName[0];
+ }
+
+}
diff --git a/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapper.java b/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapper.java
index dd5ac96c81..1021ca6bb5 100644
--- a/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapper.java
+++ b/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapper.java
@@ -5,7 +5,9 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.Callable;
import javax.lang.model.element.Modifier;
@@ -81,10 +83,21 @@ public SolidityFunctionWrapper(boolean useNativeJavaTypes) {
this.useNativeJavaTypes = useNativeJavaTypes;
}
+ @SuppressWarnings("unchecked")
public void generateJavaFiles(
String contractName, String bin, String abi, String destinationDir,
String basePackageName)
throws IOException, ClassNotFoundException {
+ generateJavaFiles(contractName, bin,
+ loadContractDefinition(abi),
+ destinationDir, basePackageName,
+ null);
+ }
+
+ void generateJavaFiles(
+ String contractName, String bin, List abi, String destinationDir,
+ String basePackageName, Map addresses)
+ throws IOException, ClassNotFoundException {
String className = Strings.capitaliseFirstLetter(contractName);
TypeSpec.Builder classBuilder = createClassBuilder(className, bin);
@@ -92,13 +105,51 @@ public void generateJavaFiles(
classBuilder.addMethod(buildConstructor(Credentials.class, CREDENTIALS));
classBuilder.addMethod(buildConstructor(TransactionManager.class, TRANSACTION_MANAGER));
classBuilder.addMethods(
- buildFunctionDefinitions(className, classBuilder, loadContractDefinition(abi)));
+ buildFunctionDefinitions(className, classBuilder, abi));
classBuilder.addMethod(buildLoad(className, Credentials.class, CREDENTIALS));
classBuilder.addMethod(buildLoad(className, TransactionManager.class, TRANSACTION_MANAGER));
+ addAddressesSupport(classBuilder, addresses);
+
write(basePackageName, classBuilder.build(), destinationDir);
}
+ private void addAddressesSupport(TypeSpec.Builder classBuilder, Map addresses) {
+ if (addresses != null) {
+
+ ClassName stringType = ClassName.get(String.class);
+ ClassName mapType = ClassName.get(HashMap.class);
+ TypeName mapStringString = ParameterizedTypeName.get(mapType, stringType, stringType);
+ FieldSpec addressesStaticField = FieldSpec
+ .builder(mapStringString, "_addresses",
+ Modifier.PROTECTED, Modifier.STATIC, Modifier.FINAL)
+ .build();
+ classBuilder.addField(addressesStaticField);
+
+ final CodeBlock.Builder staticInit = CodeBlock.builder();
+ staticInit.addStatement("_addresses = new HashMap<>()");
+ addresses.forEach((k, v) ->
+ staticInit.addStatement(String.format("_addresses.put(\"%1s\", \"%2s\")", k, v))
+ );
+ classBuilder.addStaticBlock(staticInit.build());
+
+ // See org.web3j.tx.Contract#getStaticDeployedAddress(String)
+ MethodSpec getAddress = MethodSpec
+ .methodBuilder("getStaticDeployedAddress")
+ .addModifiers(Modifier.PROTECTED)
+ .returns(stringType)
+ .addParameter(stringType, "networkId")
+ .addCode(CodeBlock
+ .builder()
+ .addStatement("return _addresses.get(networkId)")
+ .build())
+ .build();
+ classBuilder.addMethod(getAddress);
+
+ }
+ }
+
+
private TypeSpec.Builder createClassBuilder(String className, String binary) {
String javadoc = CODEGEN_WARNING + getWeb3jVersion();
diff --git a/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapperGenerator.java b/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapperGenerator.java
index cd0ec1d95d..7716578ecc 100644
--- a/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapperGenerator.java
+++ b/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapperGenerator.java
@@ -18,7 +18,7 @@
/**
* Java wrapper source code generator for Solidity ABI format.
*/
-public class SolidityFunctionWrapperGenerator {
+public class SolidityFunctionWrapperGenerator extends FunctionWrapperGenerator {
private static final String USAGE = "solidity generate "
+ "[--javaTypes|--solidityTypes] "
@@ -26,14 +26,8 @@ public class SolidityFunctionWrapperGenerator {
+ "-p|--package "
+ "-o|--output ";
- static final String JAVA_TYPES_ARG = "--javaTypes";
- static final String SOLIDITY_TYPES_ARG = "--solidityTypes";
-
- private String binaryFileLocation;
- private String absFileLocation;
- private File destinationDirLocation;
- private String basePackageName;
- private boolean useJavaNativeTypes;
+ private final String binaryFileLocation;
+ private final String absFileLocation;
private SolidityFunctionWrapperGenerator(
String binaryFileLocation,
@@ -42,11 +36,9 @@ private SolidityFunctionWrapperGenerator(
String basePackageName,
boolean useJavaNativeTypes) {
+ super(destinationDirLocation, basePackageName, useJavaNativeTypes);
this.binaryFileLocation = binaryFileLocation;
this.absFileLocation = absFileLocation;
- this.destinationDirLocation = new File(destinationDirLocation);
- this.basePackageName = basePackageName;
- this.useJavaNativeTypes = useJavaNativeTypes;
}
public static void run(String[] args) throws Exception {
@@ -72,14 +64,7 @@ public static void main(String[] args) throws Exception {
exitError(USAGE);
}
- boolean useJavaNativeTypes = true;
- if (fullArgs[0].equals(SOLIDITY_TYPES_ARG)) {
- useJavaNativeTypes = false;
- } else if (fullArgs[0].equals(JAVA_TYPES_ARG)) {
- useJavaNativeTypes = true;
- } else {
- exitError(USAGE);
- }
+ boolean useJavaNativeTypes = useJavaNativeTypes(fullArgs[0], USAGE);
String binaryFileLocation = parsePositionalArg(fullArgs, 1);
String absFileLocation = parsePositionalArg(fullArgs, 2);
@@ -102,27 +87,11 @@ public static void main(String[] args) throws Exception {
.generate();
}
- private static String parsePositionalArg(String[] args, int idx) {
- if (args != null && args.length > idx) {
- return args[idx];
- } else {
- return "";
- }
- }
-
- private static String parseParameterArgument(String[] args, String... parameters) {
- for (String parameter : parameters) {
- for (int i = 0; i < args.length; i++) {
- if (args[i].equals(parameter)
- && i + 1 < args.length) {
- String parameterValue = args[i + 1];
- if (!parameterValue.startsWith("-")) {
- return parameterValue;
- }
- }
- }
- }
- return "";
+ static List loadContractDefinition(File absFile)
+ throws IOException {
+ ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper();
+ AbiDefinition[] abiDefinition = objectMapper.readValue(absFile, AbiDefinition[].class);
+ return Arrays.asList(abiDefinition);
}
private void generate() throws IOException, ClassNotFoundException {
@@ -157,15 +126,5 @@ private void generate() throws IOException, ClassNotFoundException {
}
}
- private static List loadContractDefinition(File absFile)
- throws IOException {
- ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper();
- AbiDefinition[] abiDefinition = objectMapper.readValue(absFile, AbiDefinition[].class);
- return Arrays.asList(abiDefinition);
- }
- static String getFileNameNoExtension(String fileName) {
- String[] splitName = fileName.split("\\.(?=[^.]*$)");
- return splitName[0];
- }
}
\ No newline at end of file
diff --git a/codegen/src/main/java/org/web3j/codegen/TruffleJsonFunctionWrapperGenerator.java b/codegen/src/main/java/org/web3j/codegen/TruffleJsonFunctionWrapperGenerator.java
new file mode 100644
index 0000000000..bbeba6d832
--- /dev/null
+++ b/codegen/src/main/java/org/web3j/codegen/TruffleJsonFunctionWrapperGenerator.java
@@ -0,0 +1,480 @@
+package org.web3j.codegen;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.web3j.protocol.ObjectMapperFactory;
+import org.web3j.protocol.core.methods.response.AbiDefinition;
+import org.web3j.utils.Strings;
+
+import static org.web3j.codegen.Console.exitError;
+import static org.web3j.utils.Collection.tail;
+
+/**
+ * Java wrapper source code generator for Truffle JSON format. Truffle embeds the Solidity ABI
+ * formatted JSON in its own format. That format also gives access to the binary code. It also
+ * contains information about deployment addresses. This should make integration with Truffle
+ * easier.
+ */
+public class TruffleJsonFunctionWrapperGenerator extends FunctionWrapperGenerator {
+
+ private static final String USAGE = "truffle generate "
+ + "[--javaTypes|--solidityTypes] "
+ + " .json "
+ + "-p|--package "
+ + "-o|--output ";
+
+
+ private String jsonFileLocation;
+
+ private TruffleJsonFunctionWrapperGenerator(
+ String jsonFileLocation,
+ String destinationDirLocation,
+ String basePackageName,
+ boolean useJavaNativeTypes) {
+
+ super(destinationDirLocation, basePackageName, useJavaNativeTypes);
+ this.jsonFileLocation = jsonFileLocation;
+ }
+
+ public static void run(String[] args) throws Exception {
+ if (args.length < 1 || !"generate".equals(args[0])) {
+ exitError(USAGE);
+ } else {
+ main(tail(args));
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+
+ String[] fullArgs;
+ if (args.length == 5) {
+ fullArgs = new String[args.length + 1];
+ fullArgs[0] = JAVA_TYPES_ARG;
+ System.arraycopy(args, 0, fullArgs, 1, args.length);
+ } else {
+ fullArgs = args;
+ }
+
+ if (fullArgs.length != 6) {
+ exitError(USAGE);
+ }
+
+ boolean useJavaNativeTypes = useJavaNativeTypes(fullArgs[0], USAGE);
+
+ String jsonFileLocation = parsePositionalArg(fullArgs, 1);
+ String destinationDirLocation = parseParameterArgument(fullArgs, "-o", "--outputDir");
+ String basePackageName = parseParameterArgument(fullArgs, "-p", "--package");
+
+ if (Strings.isEmpty(jsonFileLocation)
+ || Strings.isEmpty(destinationDirLocation)
+ || Strings.isEmpty(basePackageName)) {
+ exitError(USAGE);
+ }
+
+ new TruffleJsonFunctionWrapperGenerator(
+ jsonFileLocation,
+ destinationDirLocation,
+ basePackageName,
+ useJavaNativeTypes)
+ .generate();
+ }
+
+ static Contract loadContractDefinition(File jsonFile)
+ throws IOException {
+ ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper();
+ return objectMapper.readValue(jsonFile, Contract.class);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void generate() throws IOException, ClassNotFoundException {
+
+ File truffleJsonFile = new File(jsonFileLocation);
+ if (!truffleJsonFile.exists() || !truffleJsonFile.canRead()) {
+ exitError("Invalid input json file specified: " + jsonFileLocation);
+ }
+
+ String fileName = truffleJsonFile.getName();
+ String contractName = getFileNameNoExtension(fileName);
+
+ Contract c = loadContractDefinition(truffleJsonFile);
+ if (c == null) {
+ exitError("Unable to parse input json file");
+ } else {
+ String className = Strings.capitaliseFirstLetter(contractName);
+ System.out.printf("Generating " + basePackageName + "." + className + " ... ");
+ Map addresses;
+ if (c.networks != null && !c.networks.isEmpty()) {
+ addresses = c.networks.entrySet().stream().collect(Collectors.toMap(
+ Map.Entry::getKey, e -> e.getValue().getAddress()
+ ));
+ } else {
+ addresses = Collections.EMPTY_MAP;
+ }
+ new SolidityFunctionWrapper(useJavaNativeTypes)
+ .generateJavaFiles(contractName,
+ c.bytecode,
+ c.abi,
+ destinationDirLocation.toString(),
+ basePackageName,
+ addresses);
+ System.out.println("File written to " + destinationDirLocation.toString() + "\n");
+ }
+ }
+
+ /**
+ * Truffle Contract Describes a contract exported by and consumable by Truffle, which may
+ * include information about deployed instances on networks.
+ */
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ @JsonPropertyOrder({
+ "contractName",
+ "abi",
+ "bytecode",
+ "deployedBytecode",
+ "sourceMap",
+ "deployedSourceMap",
+ "source",
+ "sourcePath",
+ "ast",
+ "compiler",
+ "networks",
+ "schemaVersion",
+ "updatedAt"
+ })
+ public static class Contract {
+
+ @JsonProperty("contractName")
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "^[a-zA-Z_][a-zA-Z0-9_]*$")
+ public String contractName;
+ @JsonProperty(value = "abi", required = true)
+ public List abi;
+ @JsonProperty("bytecode")
+ @JsonFormat(shape = JsonFormat.Shape.STRING,
+ pattern = "^0x0$|^0x([a-fA-F0-9]{2}|__.{38})+$")
+ public String bytecode;
+ @JsonProperty("deployedBytecode")
+ @JsonFormat(shape = JsonFormat.Shape.STRING,
+ pattern = "^0x0$|^0x([a-fA-F0-9]{2}|__.{38})+$")
+ public String deployedBytecode;
+ @JsonProperty("sourceMap")
+ public String sourceMap;
+ @JsonProperty("deployedSourceMap")
+ public String deployedSourceMap;
+ @JsonProperty("source")
+ public String source;
+ @JsonProperty("sourcePath")
+ public String sourcePath;
+ @JsonProperty("ast")
+ public JsonNode ast;
+ @JsonProperty("compiler")
+ public Compiler compiler;
+ @JsonProperty("networks")
+ public Map networks;
+ @JsonProperty("schemaVersion")
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "[0-9]+\\.[0-9]+\\.[0-9]+")
+ public String schemaVersion;
+ @JsonProperty("updatedAt")
+ @JsonFormat(shape = JsonFormat.Shape.STRING,
+ pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone = "GMT")
+ public Date updatedAt;
+
+ /**
+ * No args constructor for use in serialization.
+ */
+ public Contract() {
+ }
+
+ /**
+ * Default constructor.
+ */
+ public Contract(String contractName, List abi, String bytecode,
+ String deployedBytecode,
+ String sourceMap, String deployedSourceMap, String source, String sourcePath,
+ JsonNode ast,
+ Compiler compiler, Map networks, String schemaVersion,
+ Date updatedAt) {
+ super();
+ this.contractName = contractName;
+ this.abi = abi;
+ this.bytecode = bytecode;
+ this.deployedBytecode = deployedBytecode;
+ this.sourceMap = sourceMap;
+ this.deployedSourceMap = deployedSourceMap;
+ this.source = source;
+ this.sourcePath = sourcePath;
+ this.ast = ast;
+ this.compiler = compiler;
+ this.networks = networks;
+ this.schemaVersion = schemaVersion;
+ this.updatedAt = updatedAt;
+ }
+
+ public Contract withContractName(String contractName) {
+ this.contractName = contractName;
+ return this;
+ }
+
+ public Contract withAbi(List abi) {
+ this.abi = abi;
+ return this;
+ }
+
+ public Contract withBytecode(String bytecode) {
+ this.bytecode = bytecode;
+ return this;
+ }
+
+ public Contract withDeployedBytecode(String deployedBytecode) {
+ this.deployedBytecode = deployedBytecode;
+ return this;
+ }
+
+ public Contract withSourceMap(String sourceMap) {
+ this.sourceMap = sourceMap;
+ return this;
+ }
+
+ public Contract withDeployedSourceMap(String deployedSourceMap) {
+ this.deployedSourceMap = deployedSourceMap;
+ return this;
+ }
+
+ public Contract withSource(String source) {
+ this.source = source;
+ return this;
+ }
+
+ public Contract withSourcePath(String sourcePath) {
+ this.sourcePath = sourcePath;
+ return this;
+ }
+
+ public Contract withAst(JsonNode ast) {
+ this.ast = ast;
+ return this;
+ }
+
+ public Contract withCompiler(Compiler compiler) {
+ this.compiler = compiler;
+ return this;
+ }
+
+ public Contract withNetworks(Map networks) {
+ this.networks = networks;
+ return this;
+ }
+
+ public Contract withSchemaVersion(String schemaVersion) {
+ this.schemaVersion = schemaVersion;
+ return this;
+ }
+
+ public Contract withUpdatedAt(Date updatedAt) {
+ this.updatedAt = updatedAt;
+ return this;
+ }
+
+ public String getContractName() {
+ return contractName;
+ }
+
+ public List getAbi() {
+ return abi;
+ }
+
+ public String getBytecode() {
+ return bytecode;
+ }
+
+ public String getDeployedBytecode() {
+ return deployedBytecode;
+ }
+
+ public String getSourceMap() {
+ return sourceMap;
+ }
+
+ public String getDeployedSourceMap() {
+ return deployedSourceMap;
+ }
+
+ public String getSource() {
+ return source;
+ }
+
+ public String getSourcePath() {
+ return sourcePath;
+ }
+
+ public JsonNode getAst() {
+ return ast;
+ }
+
+ public Compiler getCompiler() {
+ return compiler;
+ }
+
+ public Map getNetworks() {
+ return networks;
+ }
+
+ public String getSchemaVersion() {
+ return schemaVersion;
+ }
+
+ public Date getUpdatedAt() {
+ return updatedAt;
+ }
+
+ public NetworkInfo getNetwork(String networkId) {
+ return networks.get(networkId);
+ }
+
+ public String getAddress(String networkId) {
+ NetworkInfo network = getNetwork(networkId);
+ return network == null ? null : network.getAddress();
+ }
+
+ /**
+ * Convenience method to get the deployed address of the contract.
+ *
+ * @param network the contract's address on this Ethereum network
+ * @return the contract's address or null
if there isn't one known.
+ */
+ public String getAddress(Network network) {
+ return getAddress(Long.toString(network.id));
+ }
+
+ enum Network {
+ olympic(0), mainnet(1), morden(2), ropsten(3), rinkeby(4), kovan(42);
+
+ public final long id;
+
+ Network(long id) {
+ this.id = id;
+ }
+ }
+
+ }
+
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ @JsonPropertyOrder({
+ "name",
+ "version"
+ })
+ public static class Compiler {
+
+ @JsonProperty("name")
+ public String name;
+ @JsonProperty("version")
+ public String version;
+ @JsonIgnore
+ private Map additionalProperties = new HashMap();
+
+ /**
+ * No args constructor for use in serialization.
+ */
+ public Compiler() {
+ }
+
+ /**
+ * Default constructor.
+ */
+ public Compiler(String name, String version) {
+ super();
+ this.name = name;
+ this.version = version;
+ }
+
+ public Compiler withName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public Compiler withVersion(String version) {
+ this.version = version;
+ return this;
+ }
+
+ @JsonAnyGetter
+ public Map getAdditionalProperties() {
+ return this.additionalProperties;
+ }
+
+ @JsonAnySetter
+ public void setAdditionalProperty(String name, JsonNode value) {
+ this.additionalProperties.put(name, value);
+ }
+
+ public Compiler withAdditionalProperty(String name, JsonNode value) {
+ this.additionalProperties.put(name, value);
+ return this;
+ }
+
+ }
+
+
+ // For now we just ignore "events"
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ @JsonPropertyOrder({
+ "events",
+ "links",
+ "address"
+ })
+ public static class NetworkInfo {
+
+ @JsonProperty("events")
+ public Map events;
+ @JsonProperty("links")
+ public Map links;
+ @JsonProperty("address")
+ public String address;
+
+ /**
+ * No args constructor for use in serialization.
+ */
+ public NetworkInfo() {
+ }
+
+ public NetworkInfo(Map events, Map links,
+ String address) {
+ super();
+ this.events = events;
+ this.links = links;
+ this.address = address;
+ }
+
+ public NetworkInfo withAddress(String address) {
+ this.address = address;
+ return this;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/codegen/src/test/java/org/web3j/codegen/ContractJsonParseTest.java b/codegen/src/test/java/org/web3j/codegen/ContractJsonParseTest.java
new file mode 100644
index 0000000000..e345c78496
--- /dev/null
+++ b/codegen/src/test/java/org/web3j/codegen/ContractJsonParseTest.java
@@ -0,0 +1,68 @@
+package org.web3j.codegen;
+
+import java.io.File;
+import java.net.URL;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.web3j.protocol.core.methods.response.AbiDefinition;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.web3j.codegen.TruffleJsonFunctionWrapperGenerator.Contract;
+import static org.web3j.codegen.TruffleJsonFunctionWrapperGenerator.loadContractDefinition;
+
+/**
+ * Test that we can parse Truffle Contract from JSON file.
+ */
+public class ContractJsonParseTest {
+
+ static final String BUILD_CONTRACTS = "build" + File.separator + "contracts";
+ private String contractBaseDir;
+
+ static String jsonFileLocation(String baseDir,
+ String contractName, String inputFileName) {
+ return baseDir + File.separator + contractName + File.separator + BUILD_CONTRACTS
+ + File.separator + inputFileName + ".json";
+ }
+
+ @SuppressWarnings("SameParameterValue")
+ static Contract parseContractJson(String baseDir,
+ String contractName, String inputFileName)
+ throws Exception {
+
+ String fileLocation = jsonFileLocation(baseDir, contractName, inputFileName);
+ return loadContractDefinition(new File(fileLocation));
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ URL url = SolidityFunctionWrapperGeneratorTest.class.getClass().getResource("/truffle");
+ contractBaseDir = url.getPath();
+ }
+
+ @Test
+ public void testParseMetaCoin() throws Exception {
+ Contract mc = parseContractJson(contractBaseDir, "MetaCoin", "MetaCoin");
+
+ assertEquals("Unexpected contract name", "MetaCoin", mc.getContractName());
+ }
+
+ @Test
+ public void testParseConvertLib() throws Exception {
+ Contract mc = parseContractJson(contractBaseDir, "MetaCoin", "ConvertLib");
+
+ assertEquals("Unexpected contract name", "ConvertLib", mc.getContractName());
+ assertEquals("Unexpected number of functions", 1, mc.abi.size());
+ AbiDefinition abi = mc.abi.get(0);
+ assertEquals("Unexpected function name", "convert", abi.getName());
+ assertTrue("Expected function to be 'constant'", abi.isConstant());
+ assertFalse("Expected function to not be 'payable'", abi.isPayable());
+ assertEquals("Expected abi to represent a function", "function", abi.getType());
+ assertEquals("Expected the 'pure' for the state mutability setting", "pure",
+ abi.getStateMutability());
+
+ }
+}
\ No newline at end of file
diff --git a/codegen/src/test/java/org/web3j/codegen/SolidityFunctionWrapperGeneratorTest.java b/codegen/src/test/java/org/web3j/codegen/SolidityFunctionWrapperGeneratorTest.java
index d899c903cb..966a192ea9 100644
--- a/codegen/src/test/java/org/web3j/codegen/SolidityFunctionWrapperGeneratorTest.java
+++ b/codegen/src/test/java/org/web3j/codegen/SolidityFunctionWrapperGeneratorTest.java
@@ -4,7 +4,6 @@
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
-import java.util.Collections;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
diff --git a/codegen/src/test/java/org/web3j/codegen/TruffleJsonFunctionWrapperGeneratorTest.java b/codegen/src/test/java/org/web3j/codegen/TruffleJsonFunctionWrapperGeneratorTest.java
new file mode 100644
index 0000000000..008d36dd67
--- /dev/null
+++ b/codegen/src/test/java/org/web3j/codegen/TruffleJsonFunctionWrapperGeneratorTest.java
@@ -0,0 +1,101 @@
+package org.web3j.codegen;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collections;
+
+import javax.tools.DiagnosticCollector;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardJavaFileManager;
+import javax.tools.ToolProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.web3j.TempFileProvider;
+import org.web3j.utils.Strings;
+
+import static org.junit.Assert.assertTrue;
+import static org.web3j.codegen.FunctionWrapperGenerator.JAVA_TYPES_ARG;
+import static org.web3j.codegen.FunctionWrapperGenerator.SOLIDITY_TYPES_ARG;
+
+public class TruffleJsonFunctionWrapperGeneratorTest extends TempFileProvider {
+
+ private static final String PackageName = "org.web3j.unittests.truffle.java";
+
+ private String contractBaseDir;
+
+ private static void verifyGeneratedCode(String sourceFile) throws IOException {
+ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+ DiagnosticCollector diagnostics = new DiagnosticCollector<>();
+
+ try (StandardJavaFileManager fileManager =
+ compiler.getStandardFileManager(diagnostics, null, null)) {
+ Iterable extends JavaFileObject> compilationUnits = fileManager
+ .getJavaFileObjectsFromStrings(Collections.singletonList(sourceFile));
+ JavaCompiler.CompilationTask task = compiler.getTask(
+ null, fileManager, diagnostics, null, null, compilationUnits);
+ assertTrue("Generated contract contains compile time error", task.call());
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ URL url = SolidityFunctionWrapperGeneratorTest.class.getClass().getResource("/truffle");
+ contractBaseDir = url.getPath();
+ }
+
+ @Test
+ public void testLibGeneration() throws Exception {
+ testCodeGenerationJvmTypes("MetaCoin", "ConvertLib");
+ testCodeGenerationSolidtyTypes("MetaCoin", "ConvertLib");
+ }
+
+ @Test
+ public void testContractGeneration() throws Exception {
+ testCodeGenerationJvmTypes("MetaCoin", "MetaCoin");
+ testCodeGenerationSolidtyTypes("MetaCoin", "MetaCoin");
+ }
+
+ @SuppressWarnings("SameParameterValue")
+ private void testCodeGenerationJvmTypes(
+ String contractName, String inputFileName) throws Exception {
+
+ testCodeGeneration(
+ contractName, inputFileName, PackageName, JAVA_TYPES_ARG);
+
+ }
+
+ @SuppressWarnings("SameParameterValue")
+ private void testCodeGenerationSolidtyTypes(
+ String contractName, String inputFileName) throws Exception {
+
+ testCodeGeneration(
+ contractName, inputFileName, PackageName, SOLIDITY_TYPES_ARG);
+
+ }
+
+ private void testCodeGeneration(
+ String contractName, String inputFileName, String packageName, String types)
+ throws Exception {
+
+ TruffleJsonFunctionWrapperGenerator.main(Arrays.asList(
+ types,
+ ContractJsonParseTest
+ .jsonFileLocation(contractBaseDir, contractName, inputFileName),
+ "-p", packageName,
+ "-o", tempDirPath
+ ).toArray(new String[0]));
+
+ verifyGeneratedCode(tempDirPath + File.separator
+ + packageName.replace('.', File.separatorChar) + File.separator
+ + Strings.capitaliseFirstLetter(inputFileName) + ".java");
+ }
+
+
+}
\ No newline at end of file
diff --git a/codegen/src/test/resources/truffle/MetaCoin/ConvertLib.sol b/codegen/src/test/resources/truffle/MetaCoin/ConvertLib.sol
new file mode 100644
index 0000000000..99f004dfe2
--- /dev/null
+++ b/codegen/src/test/resources/truffle/MetaCoin/ConvertLib.sol
@@ -0,0 +1,8 @@
+pragma solidity ^0.4.2;
+
+library ConvertLib{
+ function convert(uint amount,uint conversionRate) pure public returns (uint convertedAmount)
+ {
+ return amount * conversionRate;
+ }
+}
diff --git a/codegen/src/test/resources/truffle/MetaCoin/MetaCoin.sol b/codegen/src/test/resources/truffle/MetaCoin/MetaCoin.sol
new file mode 100644
index 0000000000..2658d0466f
--- /dev/null
+++ b/codegen/src/test/resources/truffle/MetaCoin/MetaCoin.sol
@@ -0,0 +1,34 @@
+pragma solidity ^0.4.2;
+
+import "./ConvertLib.sol";
+
+// This is just a simple example of a coin-like contract.
+// It is not standards compatible and cannot be expected to talk to other
+// coin/token contracts. If you want to create a standards-compliant
+// token, see: https://github.com/ConsenSys/Tokens. Cheers!
+
+contract MetaCoin {
+ mapping (address => uint) balances;
+
+ event Transfer(address indexed _from, address indexed _to, uint256 _value);
+
+ function MetaCoin() public {
+ balances[tx.origin] = 10000;
+ }
+
+ function sendCoin(address receiver, uint amount) public returns(bool sufficient) {
+ if (balances[msg.sender] < amount) return false;
+ balances[msg.sender] -= amount;
+ balances[receiver] += amount;
+ Transfer(msg.sender, receiver, amount);
+ return true;
+ }
+
+ function getBalanceInEth(address addr) view public returns(uint){
+ return ConvertLib.convert(getBalance(addr),2);
+ }
+
+ function getBalance(address addr) view public returns(uint) {
+ return balances[addr];
+ }
+}
diff --git a/codegen/src/test/resources/truffle/MetaCoin/build/contracts/ConvertLib.json b/codegen/src/test/resources/truffle/MetaCoin/build/contracts/ConvertLib.json
new file mode 100644
index 0000000000..a54254200b
--- /dev/null
+++ b/codegen/src/test/resources/truffle/MetaCoin/build/contracts/ConvertLib.json
@@ -0,0 +1,281 @@
+{
+ "contractName": "ConvertLib",
+ "abi": [
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "amount",
+ "type": "uint256"
+ },
+ {
+ "name": "conversionRate",
+ "type": "uint256"
+ }
+ ],
+ "name": "convert",
+ "outputs": [
+ {
+ "name": "convertedAmount",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "pure",
+ "type": "function"
+ }
+ ],
+ "bytecode": "0x6060604052341561000f57600080fd5b60b08061001d6000396000f300606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806396e4ee3d146044575b600080fd5b606160048080359060200190919080359060200190919050506077565b6040518082815260200191505060405180910390f35b60008183029050929150505600a165627a7a72305820fc2416f7929b800f6d4af1a1e6d2a8d7d8ac81998f8c072a99314c7bf5c2a5f80029",
+ "deployedBytecode": "0x606060405260043610603f576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806396e4ee3d146044575b600080fd5b606160048080359060200190919080359060200190919050506077565b6040518082815260200191505060405180910390f35b60008183029050929150505600a165627a7a72305820fc2416f7929b800f6d4af1a1e6d2a8d7d8ac81998f8c072a99314c7bf5c2a5f80029",
+ "sourceMap": "25:155:0:-;;;;;;;;;;;;;;;;;",
+ "deployedSourceMap": "25:155:0:-;;;;;;;;;;;;;;;;;;;;;;;;46:132;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;117:20;160:14;151:6;:23;144:30;;46:132;;;;:::o",
+ "source": "pragma solidity ^0.4.2;\n\nlibrary ConvertLib{\n\tfunction convert(uint amount,uint conversionRate) pure public returns (uint convertedAmount)\n\t{\n\t\treturn amount * conversionRate;\n\t}\n}\n",
+ "sourcePath": "/Users/ezra/Developer/blockchain/truffle_webpack/contracts/ConvertLib.sol",
+ "ast": {
+ "attributes": {
+ "absolutePath": "/Users/ezra/Developer/blockchain/truffle_webpack/contracts/ConvertLib.sol",
+ "exportedSymbols": {
+ "ConvertLib": [
+ 16
+ ]
+ }
+ },
+ "children": [
+ {
+ "attributes": {
+ "literals": [
+ "solidity",
+ "^",
+ "0.4",
+ ".2"
+ ]
+ },
+ "id": 1,
+ "name": "PragmaDirective",
+ "src": "0:23:0"
+ },
+ {
+ "attributes": {
+ "baseContracts": [
+ null
+ ],
+ "contractDependencies": [
+ null
+ ],
+ "contractKind": "library",
+ "documentation": null,
+ "fullyImplemented": true,
+ "linearizedBaseContracts": [
+ 16
+ ],
+ "name": "ConvertLib",
+ "scope": 17
+ },
+ "children": [
+ {
+ "attributes": {
+ "constant": true,
+ "implemented": true,
+ "isConstructor": false,
+ "modifiers": [
+ null
+ ],
+ "name": "convert",
+ "payable": false,
+ "scope": 16,
+ "stateMutability": "pure",
+ "superFunction": null,
+ "visibility": "public"
+ },
+ "children": [
+ {
+ "children": [
+ {
+ "attributes": {
+ "constant": false,
+ "name": "amount",
+ "scope": 15,
+ "stateVariable": false,
+ "storageLocation": "default",
+ "type": "uint256",
+ "value": null,
+ "visibility": "internal"
+ },
+ "children": [
+ {
+ "attributes": {
+ "name": "uint",
+ "type": "uint256"
+ },
+ "id": 2,
+ "name": "ElementaryTypeName",
+ "src": "63:4:0"
+ }
+ ],
+ "id": 3,
+ "name": "VariableDeclaration",
+ "src": "63:11:0"
+ },
+ {
+ "attributes": {
+ "constant": false,
+ "name": "conversionRate",
+ "scope": 15,
+ "stateVariable": false,
+ "storageLocation": "default",
+ "type": "uint256",
+ "value": null,
+ "visibility": "internal"
+ },
+ "children": [
+ {
+ "attributes": {
+ "name": "uint",
+ "type": "uint256"
+ },
+ "id": 4,
+ "name": "ElementaryTypeName",
+ "src": "75:4:0"
+ }
+ ],
+ "id": 5,
+ "name": "VariableDeclaration",
+ "src": "75:19:0"
+ }
+ ],
+ "id": 6,
+ "name": "ParameterList",
+ "src": "62:33:0"
+ },
+ {
+ "children": [
+ {
+ "attributes": {
+ "constant": false,
+ "name": "convertedAmount",
+ "scope": 15,
+ "stateVariable": false,
+ "storageLocation": "default",
+ "type": "uint256",
+ "value": null,
+ "visibility": "internal"
+ },
+ "children": [
+ {
+ "attributes": {
+ "name": "uint",
+ "type": "uint256"
+ },
+ "id": 7,
+ "name": "ElementaryTypeName",
+ "src": "117:4:0"
+ }
+ ],
+ "id": 8,
+ "name": "VariableDeclaration",
+ "src": "117:20:0"
+ }
+ ],
+ "id": 9,
+ "name": "ParameterList",
+ "src": "116:22:0"
+ },
+ {
+ "children": [
+ {
+ "attributes": {
+ "functionReturnParameters": 9
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "commonType": {
+ "typeIdentifier": "t_uint256",
+ "typeString": "uint256"
+ },
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": false,
+ "lValueRequested": false,
+ "operator": "*",
+ "type": "uint256"
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 3,
+ "type": "uint256",
+ "value": "amount"
+ },
+ "id": 10,
+ "name": "Identifier",
+ "src": "151:6:0"
+ },
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 5,
+ "type": "uint256",
+ "value": "conversionRate"
+ },
+ "id": 11,
+ "name": "Identifier",
+ "src": "160:14:0"
+ }
+ ],
+ "id": 12,
+ "name": "BinaryOperation",
+ "src": "151:23:0"
+ }
+ ],
+ "id": 13,
+ "name": "Return",
+ "src": "144:30:0"
+ }
+ ],
+ "id": 14,
+ "name": "Block",
+ "src": "140:38:0"
+ }
+ ],
+ "id": 15,
+ "name": "FunctionDefinition",
+ "src": "46:132:0"
+ }
+ ],
+ "id": 16,
+ "name": "ContractDefinition",
+ "src": "25:155:0"
+ }
+ ],
+ "id": 17,
+ "name": "SourceUnit",
+ "src": "0:181:0"
+ },
+ "compiler": {
+ "name": "solc",
+ "version": "0.4.18+commit.9cf6e910.Emscripten.clang"
+ },
+ "networks": {
+ "4": {
+ "events": {},
+ "links": {},
+ "address": "0x14d00a701a2f0d4d65eebaf191f4f60bbaa1da36"
+ },
+ "4447": {
+ "events": {},
+ "links": {},
+ "address": "0xcfeb869f69431e42cdb54a4f4f105c19c080a601"
+ }
+ },
+ "schemaVersion": "1.0.1",
+ "updatedAt": "2017-11-07T20:44:02.301Z"
+}
\ No newline at end of file
diff --git a/codegen/src/test/resources/truffle/MetaCoin/build/contracts/MetaCoin.json b/codegen/src/test/resources/truffle/MetaCoin/build/contracts/MetaCoin.json
new file mode 100644
index 0000000000..8bed99e71e
--- /dev/null
+++ b/codegen/src/test/resources/truffle/MetaCoin/build/contracts/MetaCoin.json
@@ -0,0 +1,1431 @@
+{
+ "contractName": "MetaCoin",
+ "abi": [
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "addr",
+ "type": "address"
+ }
+ ],
+ "name": "getBalanceInEth",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "receiver",
+ "type": "address"
+ },
+ {
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "sendCoin",
+ "outputs": [
+ {
+ "name": "sufficient",
+ "type": "bool"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "addr",
+ "type": "address"
+ }
+ ],
+ "name": "getBalance",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "_from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "name": "_to",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "_value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Transfer",
+ "type": "event"
+ }
+ ],
+ "bytecode": "0x6060604052341561000f57600080fd5b6127106000803273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506103c5806100636000396000f300606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680637bd703e81461005c57806390b98a11146100a9578063f8b2cb4f14610103575b600080fd5b341561006757600080fd5b610093600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610150565b6040518082815260200191505060405180910390f35b34156100b457600080fd5b6100e9600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101f8565b604051808215151515815260200191505060405180910390f35b341561010e57600080fd5b61013a600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610351565b6040518082815260200191505060405180910390f35b600073__ConvertLib____________________________6396e4ee3d61017584610351565b60026000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808381526020018281526020019250505060206040518083038186803b15156101d657600080fd5b6102c65a03f415156101e757600080fd5b505050604051805190509050919050565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015610249576000905061034b565b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190505b92915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490509190505600a165627a7a72305820f791829bf0c920a6d43123cac9b9894757ddc838c17efbad6d56773d6e3dcf4c0029",
+ "deployedBytecode": "0x606060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680637bd703e81461005c57806390b98a11146100a9578063f8b2cb4f14610103575b600080fd5b341561006757600080fd5b610093600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610150565b6040518082815260200191505060405180910390f35b34156100b457600080fd5b6100e9600480803573ffffffffffffffffffffffffffffffffffffffff169060200190919080359060200190919050506101f8565b604051808215151515815260200191505060405180910390f35b341561010e57600080fd5b61013a600480803573ffffffffffffffffffffffffffffffffffffffff16906020019091905050610351565b6040518082815260200191505060405180910390f35b600073__ConvertLib____________________________6396e4ee3d61017584610351565b60026000604051602001526040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808381526020018281526020019250505060206040518083038186803b15156101d657600080fd5b6102c65a03f415156101e757600080fd5b505050604051805190509050919050565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015610249576000905061034b565b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a3600190505b92915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490509190505600a165627a7a72305820f791829bf0c920a6d43123cac9b9894757ddc838c17efbad6d56773d6e3dcf4c0029",
+ "sourceMap": "315:675:1:-;;;452:62;;;;;;;;505:5;483:8;:19;492:9;483:19;;;;;;;;;;;;;;;:27;;;;315:675;;;;;;",
+ "deployedSourceMap": "315:675:1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;779:117;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;517:259;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;899:89;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;779:117;838:4;854:10;:18;873:16;884:4;873:10;:16::i;:::-;890:1;854:38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;847:45;;779:117;;;:::o;517:259::-;581:15;629:6;606:8;:20;615:10;606:20;;;;;;;;;;;;;;;;:29;602:47;;;644:5;637:12;;;;602:47;677:6;653:8;:20;662:10;653:20;;;;;;;;;;;;;;;;:30;;;;;;;;;;;709:6;687:8;:18;696:8;687:18;;;;;;;;;;;;;;;;:28;;;;;;;;;;;740:8;719:38;;728:10;719:38;;;750:6;719:38;;;;;;;;;;;;;;;;;;768:4;761:11;;517:259;;;;;:::o;899:89::-;953:4;970:8;:14;979:4;970:14;;;;;;;;;;;;;;;;963:21;;899:89;;;:::o",
+ "source": "pragma solidity ^0.4.2;\n\nimport \"./ConvertLib.sol\";\n\n// This is just a simple example of a coin-like contract.\n// It is not standards compatible and cannot be expected to talk to other\n// coin/token contracts. If you want to create a standards-compliant\n// token, see: https://github.com/ConsenSys/Tokens. Cheers!\n\ncontract MetaCoin {\n\tmapping (address => uint) balances;\n\n\tevent Transfer(address indexed _from, address indexed _to, uint256 _value);\n\n\tfunction MetaCoin() public {\n\t\tbalances[tx.origin] = 10000;\n\t}\n\n\tfunction sendCoin(address receiver, uint amount) public returns(bool sufficient) {\n\t\tif (balances[msg.sender] < amount) return false;\n\t\tbalances[msg.sender] -= amount;\n\t\tbalances[receiver] += amount;\n\t\tTransfer(msg.sender, receiver, amount);\n\t\treturn true;\n\t}\n\n\tfunction getBalanceInEth(address addr) view public returns(uint){\n\t\treturn ConvertLib.convert(getBalance(addr),2);\n\t}\n\n\tfunction getBalance(address addr) view public returns(uint) {\n\t\treturn balances[addr];\n\t}\n}\n",
+ "sourcePath": "/Users/ezra/Developer/blockchain/truffle_webpack/contracts/MetaCoin.sol",
+ "ast": {
+ "attributes": {
+ "absolutePath": "/Users/ezra/Developer/blockchain/truffle_webpack/contracts/MetaCoin.sol",
+ "exportedSymbols": {
+ "MetaCoin": [
+ 112
+ ]
+ }
+ },
+ "children": [
+ {
+ "attributes": {
+ "literals": [
+ "solidity",
+ "^",
+ "0.4",
+ ".2"
+ ]
+ },
+ "id": 18,
+ "name": "PragmaDirective",
+ "src": "0:23:1"
+ },
+ {
+ "attributes": {
+ "SourceUnit": 17,
+ "absolutePath": "/Users/ezra/Developer/blockchain/truffle_webpack/contracts/ConvertLib.sol",
+ "file": "./ConvertLib.sol",
+ "scope": 113,
+ "symbolAliases": [
+ null
+ ],
+ "unitAlias": ""
+ },
+ "id": 19,
+ "name": "ImportDirective",
+ "src": "25:26:1"
+ },
+ {
+ "attributes": {
+ "baseContracts": [
+ null
+ ],
+ "contractDependencies": [
+ null
+ ],
+ "contractKind": "contract",
+ "documentation": null,
+ "fullyImplemented": true,
+ "linearizedBaseContracts": [
+ 112
+ ],
+ "name": "MetaCoin",
+ "scope": 113
+ },
+ "children": [
+ {
+ "attributes": {
+ "constant": false,
+ "name": "balances",
+ "scope": 112,
+ "stateVariable": true,
+ "storageLocation": "default",
+ "type": "mapping(address => uint256)",
+ "value": null,
+ "visibility": "internal"
+ },
+ "children": [
+ {
+ "attributes": {
+ "type": "mapping(address => uint256)"
+ },
+ "children": [
+ {
+ "attributes": {
+ "name": "address",
+ "type": "address"
+ },
+ "id": 20,
+ "name": "ElementaryTypeName",
+ "src": "345:7:1"
+ },
+ {
+ "attributes": {
+ "name": "uint",
+ "type": "uint256"
+ },
+ "id": 21,
+ "name": "ElementaryTypeName",
+ "src": "356:4:1"
+ }
+ ],
+ "id": 22,
+ "name": "Mapping",
+ "src": "336:25:1"
+ }
+ ],
+ "id": 23,
+ "name": "VariableDeclaration",
+ "src": "336:34:1"
+ },
+ {
+ "attributes": {
+ "anonymous": false,
+ "name": "Transfer"
+ },
+ "children": [
+ {
+ "children": [
+ {
+ "attributes": {
+ "constant": false,
+ "indexed": true,
+ "name": "_from",
+ "scope": 31,
+ "stateVariable": false,
+ "storageLocation": "default",
+ "type": "address",
+ "value": null,
+ "visibility": "internal"
+ },
+ "children": [
+ {
+ "attributes": {
+ "name": "address",
+ "type": "address"
+ },
+ "id": 24,
+ "name": "ElementaryTypeName",
+ "src": "389:7:1"
+ }
+ ],
+ "id": 25,
+ "name": "VariableDeclaration",
+ "src": "389:21:1"
+ },
+ {
+ "attributes": {
+ "constant": false,
+ "indexed": true,
+ "name": "_to",
+ "scope": 31,
+ "stateVariable": false,
+ "storageLocation": "default",
+ "type": "address",
+ "value": null,
+ "visibility": "internal"
+ },
+ "children": [
+ {
+ "attributes": {
+ "name": "address",
+ "type": "address"
+ },
+ "id": 26,
+ "name": "ElementaryTypeName",
+ "src": "412:7:1"
+ }
+ ],
+ "id": 27,
+ "name": "VariableDeclaration",
+ "src": "412:19:1"
+ },
+ {
+ "attributes": {
+ "constant": false,
+ "indexed": false,
+ "name": "_value",
+ "scope": 31,
+ "stateVariable": false,
+ "storageLocation": "default",
+ "type": "uint256",
+ "value": null,
+ "visibility": "internal"
+ },
+ "children": [
+ {
+ "attributes": {
+ "name": "uint256",
+ "type": "uint256"
+ },
+ "id": 28,
+ "name": "ElementaryTypeName",
+ "src": "433:7:1"
+ }
+ ],
+ "id": 29,
+ "name": "VariableDeclaration",
+ "src": "433:14:1"
+ }
+ ],
+ "id": 30,
+ "name": "ParameterList",
+ "src": "388:60:1"
+ }
+ ],
+ "id": 31,
+ "name": "EventDefinition",
+ "src": "374:75:1"
+ },
+ {
+ "attributes": {
+ "constant": false,
+ "implemented": true,
+ "isConstructor": true,
+ "modifiers": [
+ null
+ ],
+ "name": "MetaCoin",
+ "payable": false,
+ "scope": 112,
+ "stateMutability": "nonpayable",
+ "superFunction": null,
+ "visibility": "public"
+ },
+ "children": [
+ {
+ "attributes": {
+ "parameters": [
+ null
+ ]
+ },
+ "children": [],
+ "id": 32,
+ "name": "ParameterList",
+ "src": "469:2:1"
+ },
+ {
+ "attributes": {
+ "parameters": [
+ null
+ ]
+ },
+ "children": [],
+ "id": 33,
+ "name": "ParameterList",
+ "src": "479:0:1"
+ },
+ {
+ "children": [
+ {
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": false,
+ "lValueRequested": false,
+ "operator": "=",
+ "type": "uint256"
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "isConstant": false,
+ "isLValue": true,
+ "isPure": false,
+ "lValueRequested": true,
+ "type": "uint256"
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 23,
+ "type": "mapping(address => uint256)",
+ "value": "balances"
+ },
+ "id": 34,
+ "name": "Identifier",
+ "src": "483:8:1"
+ },
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": false,
+ "lValueRequested": false,
+ "member_name": "origin",
+ "referencedDeclaration": null,
+ "type": "address"
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 191,
+ "type": "tx",
+ "value": "tx"
+ },
+ "id": 35,
+ "name": "Identifier",
+ "src": "492:2:1"
+ }
+ ],
+ "id": 36,
+ "name": "MemberAccess",
+ "src": "492:9:1"
+ }
+ ],
+ "id": 37,
+ "name": "IndexAccess",
+ "src": "483:19:1"
+ },
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "hexvalue": "3130303030",
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": true,
+ "lValueRequested": false,
+ "subdenomination": null,
+ "token": "number",
+ "type": "int_const 10000",
+ "value": "10000"
+ },
+ "id": 38,
+ "name": "Literal",
+ "src": "505:5:1"
+ }
+ ],
+ "id": 39,
+ "name": "Assignment",
+ "src": "483:27:1"
+ }
+ ],
+ "id": 40,
+ "name": "ExpressionStatement",
+ "src": "483:27:1"
+ }
+ ],
+ "id": 41,
+ "name": "Block",
+ "src": "479:35:1"
+ }
+ ],
+ "id": 42,
+ "name": "FunctionDefinition",
+ "src": "452:62:1"
+ },
+ {
+ "attributes": {
+ "constant": false,
+ "implemented": true,
+ "isConstructor": false,
+ "modifiers": [
+ null
+ ],
+ "name": "sendCoin",
+ "payable": false,
+ "scope": 112,
+ "stateMutability": "nonpayable",
+ "superFunction": null,
+ "visibility": "public"
+ },
+ "children": [
+ {
+ "children": [
+ {
+ "attributes": {
+ "constant": false,
+ "name": "receiver",
+ "scope": 83,
+ "stateVariable": false,
+ "storageLocation": "default",
+ "type": "address",
+ "value": null,
+ "visibility": "internal"
+ },
+ "children": [
+ {
+ "attributes": {
+ "name": "address",
+ "type": "address"
+ },
+ "id": 43,
+ "name": "ElementaryTypeName",
+ "src": "535:7:1"
+ }
+ ],
+ "id": 44,
+ "name": "VariableDeclaration",
+ "src": "535:16:1"
+ },
+ {
+ "attributes": {
+ "constant": false,
+ "name": "amount",
+ "scope": 83,
+ "stateVariable": false,
+ "storageLocation": "default",
+ "type": "uint256",
+ "value": null,
+ "visibility": "internal"
+ },
+ "children": [
+ {
+ "attributes": {
+ "name": "uint",
+ "type": "uint256"
+ },
+ "id": 45,
+ "name": "ElementaryTypeName",
+ "src": "553:4:1"
+ }
+ ],
+ "id": 46,
+ "name": "VariableDeclaration",
+ "src": "553:11:1"
+ }
+ ],
+ "id": 47,
+ "name": "ParameterList",
+ "src": "534:31:1"
+ },
+ {
+ "children": [
+ {
+ "attributes": {
+ "constant": false,
+ "name": "sufficient",
+ "scope": 83,
+ "stateVariable": false,
+ "storageLocation": "default",
+ "type": "bool",
+ "value": null,
+ "visibility": "internal"
+ },
+ "children": [
+ {
+ "attributes": {
+ "name": "bool",
+ "type": "bool"
+ },
+ "id": 48,
+ "name": "ElementaryTypeName",
+ "src": "581:4:1"
+ }
+ ],
+ "id": 49,
+ "name": "VariableDeclaration",
+ "src": "581:15:1"
+ }
+ ],
+ "id": 50,
+ "name": "ParameterList",
+ "src": "580:17:1"
+ },
+ {
+ "children": [
+ {
+ "attributes": {
+ "falseBody": null
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "commonType": {
+ "typeIdentifier": "t_uint256",
+ "typeString": "uint256"
+ },
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": false,
+ "lValueRequested": false,
+ "operator": "<",
+ "type": "bool"
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "isConstant": false,
+ "isLValue": true,
+ "isPure": false,
+ "lValueRequested": false,
+ "type": "uint256"
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 23,
+ "type": "mapping(address => uint256)",
+ "value": "balances"
+ },
+ "id": 51,
+ "name": "Identifier",
+ "src": "606:8:1"
+ },
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": false,
+ "lValueRequested": false,
+ "member_name": "sender",
+ "referencedDeclaration": null,
+ "type": "address"
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 181,
+ "type": "msg",
+ "value": "msg"
+ },
+ "id": 52,
+ "name": "Identifier",
+ "src": "615:3:1"
+ }
+ ],
+ "id": 53,
+ "name": "MemberAccess",
+ "src": "615:10:1"
+ }
+ ],
+ "id": 54,
+ "name": "IndexAccess",
+ "src": "606:20:1"
+ },
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 46,
+ "type": "uint256",
+ "value": "amount"
+ },
+ "id": 55,
+ "name": "Identifier",
+ "src": "629:6:1"
+ }
+ ],
+ "id": 56,
+ "name": "BinaryOperation",
+ "src": "606:29:1"
+ },
+ {
+ "attributes": {
+ "functionReturnParameters": 50
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "hexvalue": "66616c7365",
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": true,
+ "lValueRequested": false,
+ "subdenomination": null,
+ "token": "bool",
+ "type": "bool",
+ "value": "false"
+ },
+ "id": 57,
+ "name": "Literal",
+ "src": "644:5:1"
+ }
+ ],
+ "id": 58,
+ "name": "Return",
+ "src": "637:12:1"
+ }
+ ],
+ "id": 59,
+ "name": "IfStatement",
+ "src": "602:47:1"
+ },
+ {
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": false,
+ "lValueRequested": false,
+ "operator": "-=",
+ "type": "uint256"
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "isConstant": false,
+ "isLValue": true,
+ "isPure": false,
+ "lValueRequested": true,
+ "type": "uint256"
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 23,
+ "type": "mapping(address => uint256)",
+ "value": "balances"
+ },
+ "id": 60,
+ "name": "Identifier",
+ "src": "653:8:1"
+ },
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": false,
+ "lValueRequested": false,
+ "member_name": "sender",
+ "referencedDeclaration": null,
+ "type": "address"
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 181,
+ "type": "msg",
+ "value": "msg"
+ },
+ "id": 61,
+ "name": "Identifier",
+ "src": "662:3:1"
+ }
+ ],
+ "id": 62,
+ "name": "MemberAccess",
+ "src": "662:10:1"
+ }
+ ],
+ "id": 63,
+ "name": "IndexAccess",
+ "src": "653:20:1"
+ },
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 46,
+ "type": "uint256",
+ "value": "amount"
+ },
+ "id": 64,
+ "name": "Identifier",
+ "src": "677:6:1"
+ }
+ ],
+ "id": 65,
+ "name": "Assignment",
+ "src": "653:30:1"
+ }
+ ],
+ "id": 66,
+ "name": "ExpressionStatement",
+ "src": "653:30:1"
+ },
+ {
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": false,
+ "lValueRequested": false,
+ "operator": "+=",
+ "type": "uint256"
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "isConstant": false,
+ "isLValue": true,
+ "isPure": false,
+ "lValueRequested": true,
+ "type": "uint256"
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 23,
+ "type": "mapping(address => uint256)",
+ "value": "balances"
+ },
+ "id": 67,
+ "name": "Identifier",
+ "src": "687:8:1"
+ },
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 44,
+ "type": "address",
+ "value": "receiver"
+ },
+ "id": 68,
+ "name": "Identifier",
+ "src": "696:8:1"
+ }
+ ],
+ "id": 69,
+ "name": "IndexAccess",
+ "src": "687:18:1"
+ },
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 46,
+ "type": "uint256",
+ "value": "amount"
+ },
+ "id": 70,
+ "name": "Identifier",
+ "src": "709:6:1"
+ }
+ ],
+ "id": 71,
+ "name": "Assignment",
+ "src": "687:28:1"
+ }
+ ],
+ "id": 72,
+ "name": "ExpressionStatement",
+ "src": "687:28:1"
+ },
+ {
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": false,
+ "isStructConstructorCall": false,
+ "lValueRequested": false,
+ "names": [
+ null
+ ],
+ "type": "tuple()",
+ "type_conversion": false
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": [
+ {
+ "typeIdentifier": "t_address",
+ "typeString": "address"
+ },
+ {
+ "typeIdentifier": "t_address",
+ "typeString": "address"
+ },
+ {
+ "typeIdentifier": "t_uint256",
+ "typeString": "uint256"
+ }
+ ],
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 31,
+ "type": "function (address,address,uint256)",
+ "value": "Transfer"
+ },
+ "id": 73,
+ "name": "Identifier",
+ "src": "719:8:1"
+ },
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": false,
+ "lValueRequested": false,
+ "member_name": "sender",
+ "referencedDeclaration": null,
+ "type": "address"
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 181,
+ "type": "msg",
+ "value": "msg"
+ },
+ "id": 74,
+ "name": "Identifier",
+ "src": "728:3:1"
+ }
+ ],
+ "id": 75,
+ "name": "MemberAccess",
+ "src": "728:10:1"
+ },
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 44,
+ "type": "address",
+ "value": "receiver"
+ },
+ "id": 76,
+ "name": "Identifier",
+ "src": "740:8:1"
+ },
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 46,
+ "type": "uint256",
+ "value": "amount"
+ },
+ "id": 77,
+ "name": "Identifier",
+ "src": "750:6:1"
+ }
+ ],
+ "id": 78,
+ "name": "FunctionCall",
+ "src": "719:38:1"
+ }
+ ],
+ "id": 79,
+ "name": "ExpressionStatement",
+ "src": "719:38:1"
+ },
+ {
+ "attributes": {
+ "functionReturnParameters": 50
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "hexvalue": "74727565",
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": true,
+ "lValueRequested": false,
+ "subdenomination": null,
+ "token": "bool",
+ "type": "bool",
+ "value": "true"
+ },
+ "id": 80,
+ "name": "Literal",
+ "src": "768:4:1"
+ }
+ ],
+ "id": 81,
+ "name": "Return",
+ "src": "761:11:1"
+ }
+ ],
+ "id": 82,
+ "name": "Block",
+ "src": "598:178:1"
+ }
+ ],
+ "id": 83,
+ "name": "FunctionDefinition",
+ "src": "517:259:1"
+ },
+ {
+ "attributes": {
+ "constant": true,
+ "implemented": true,
+ "isConstructor": false,
+ "modifiers": [
+ null
+ ],
+ "name": "getBalanceInEth",
+ "payable": false,
+ "scope": 112,
+ "stateMutability": "view",
+ "superFunction": null,
+ "visibility": "public"
+ },
+ "children": [
+ {
+ "children": [
+ {
+ "attributes": {
+ "constant": false,
+ "name": "addr",
+ "scope": 99,
+ "stateVariable": false,
+ "storageLocation": "default",
+ "type": "address",
+ "value": null,
+ "visibility": "internal"
+ },
+ "children": [
+ {
+ "attributes": {
+ "name": "address",
+ "type": "address"
+ },
+ "id": 84,
+ "name": "ElementaryTypeName",
+ "src": "804:7:1"
+ }
+ ],
+ "id": 85,
+ "name": "VariableDeclaration",
+ "src": "804:12:1"
+ }
+ ],
+ "id": 86,
+ "name": "ParameterList",
+ "src": "803:14:1"
+ },
+ {
+ "children": [
+ {
+ "attributes": {
+ "constant": false,
+ "name": "",
+ "scope": 99,
+ "stateVariable": false,
+ "storageLocation": "default",
+ "type": "uint256",
+ "value": null,
+ "visibility": "internal"
+ },
+ "children": [
+ {
+ "attributes": {
+ "name": "uint",
+ "type": "uint256"
+ },
+ "id": 87,
+ "name": "ElementaryTypeName",
+ "src": "838:4:1"
+ }
+ ],
+ "id": 88,
+ "name": "VariableDeclaration",
+ "src": "838:4:1"
+ }
+ ],
+ "id": 89,
+ "name": "ParameterList",
+ "src": "837:6:1"
+ },
+ {
+ "children": [
+ {
+ "attributes": {
+ "functionReturnParameters": 89
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": false,
+ "isStructConstructorCall": false,
+ "lValueRequested": false,
+ "names": [
+ null
+ ],
+ "type": "uint256",
+ "type_conversion": false
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": [
+ {
+ "typeIdentifier": "t_uint256",
+ "typeString": "uint256"
+ },
+ {
+ "typeIdentifier": "t_rational_2_by_1",
+ "typeString": "int_const 2"
+ }
+ ],
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": false,
+ "lValueRequested": false,
+ "member_name": "convert",
+ "referencedDeclaration": 15,
+ "type": "function (uint256,uint256) pure returns (uint256)"
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 16,
+ "type": "type(library ConvertLib)",
+ "value": "ConvertLib"
+ },
+ "id": 90,
+ "name": "Identifier",
+ "src": "854:10:1"
+ }
+ ],
+ "id": 91,
+ "name": "MemberAccess",
+ "src": "854:18:1"
+ },
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": false,
+ "isStructConstructorCall": false,
+ "lValueRequested": false,
+ "names": [
+ null
+ ],
+ "type": "uint256",
+ "type_conversion": false
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": [
+ {
+ "typeIdentifier": "t_address",
+ "typeString": "address"
+ }
+ ],
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 111,
+ "type": "function (address) view returns (uint256)",
+ "value": "getBalance"
+ },
+ "id": 92,
+ "name": "Identifier",
+ "src": "873:10:1"
+ },
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 85,
+ "type": "address",
+ "value": "addr"
+ },
+ "id": 93,
+ "name": "Identifier",
+ "src": "884:4:1"
+ }
+ ],
+ "id": 94,
+ "name": "FunctionCall",
+ "src": "873:16:1"
+ },
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "hexvalue": "32",
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": true,
+ "lValueRequested": false,
+ "subdenomination": null,
+ "token": "number",
+ "type": "int_const 2",
+ "value": "2"
+ },
+ "id": 95,
+ "name": "Literal",
+ "src": "890:1:1"
+ }
+ ],
+ "id": 96,
+ "name": "FunctionCall",
+ "src": "854:38:1"
+ }
+ ],
+ "id": 97,
+ "name": "Return",
+ "src": "847:45:1"
+ }
+ ],
+ "id": 98,
+ "name": "Block",
+ "src": "843:53:1"
+ }
+ ],
+ "id": 99,
+ "name": "FunctionDefinition",
+ "src": "779:117:1"
+ },
+ {
+ "attributes": {
+ "constant": true,
+ "implemented": true,
+ "isConstructor": false,
+ "modifiers": [
+ null
+ ],
+ "name": "getBalance",
+ "payable": false,
+ "scope": 112,
+ "stateMutability": "view",
+ "superFunction": null,
+ "visibility": "public"
+ },
+ "children": [
+ {
+ "children": [
+ {
+ "attributes": {
+ "constant": false,
+ "name": "addr",
+ "scope": 111,
+ "stateVariable": false,
+ "storageLocation": "default",
+ "type": "address",
+ "value": null,
+ "visibility": "internal"
+ },
+ "children": [
+ {
+ "attributes": {
+ "name": "address",
+ "type": "address"
+ },
+ "id": 100,
+ "name": "ElementaryTypeName",
+ "src": "919:7:1"
+ }
+ ],
+ "id": 101,
+ "name": "VariableDeclaration",
+ "src": "919:12:1"
+ }
+ ],
+ "id": 102,
+ "name": "ParameterList",
+ "src": "918:14:1"
+ },
+ {
+ "children": [
+ {
+ "attributes": {
+ "constant": false,
+ "name": "",
+ "scope": 111,
+ "stateVariable": false,
+ "storageLocation": "default",
+ "type": "uint256",
+ "value": null,
+ "visibility": "internal"
+ },
+ "children": [
+ {
+ "attributes": {
+ "name": "uint",
+ "type": "uint256"
+ },
+ "id": 103,
+ "name": "ElementaryTypeName",
+ "src": "953:4:1"
+ }
+ ],
+ "id": 104,
+ "name": "VariableDeclaration",
+ "src": "953:4:1"
+ }
+ ],
+ "id": 105,
+ "name": "ParameterList",
+ "src": "952:6:1"
+ },
+ {
+ "children": [
+ {
+ "attributes": {
+ "functionReturnParameters": 105
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "isConstant": false,
+ "isLValue": true,
+ "isPure": false,
+ "lValueRequested": false,
+ "type": "uint256"
+ },
+ "children": [
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 23,
+ "type": "mapping(address => uint256)",
+ "value": "balances"
+ },
+ "id": 106,
+ "name": "Identifier",
+ "src": "970:8:1"
+ },
+ {
+ "attributes": {
+ "argumentTypes": null,
+ "overloadedDeclarations": [
+ null
+ ],
+ "referencedDeclaration": 101,
+ "type": "address",
+ "value": "addr"
+ },
+ "id": 107,
+ "name": "Identifier",
+ "src": "979:4:1"
+ }
+ ],
+ "id": 108,
+ "name": "IndexAccess",
+ "src": "970:14:1"
+ }
+ ],
+ "id": 109,
+ "name": "Return",
+ "src": "963:21:1"
+ }
+ ],
+ "id": 110,
+ "name": "Block",
+ "src": "959:29:1"
+ }
+ ],
+ "id": 111,
+ "name": "FunctionDefinition",
+ "src": "899:89:1"
+ }
+ ],
+ "id": 112,
+ "name": "ContractDefinition",
+ "src": "315:675:1"
+ }
+ ],
+ "id": 113,
+ "name": "SourceUnit",
+ "src": "0:991:1"
+ },
+ "compiler": {
+ "name": "solc",
+ "version": "0.4.18+commit.9cf6e910.Emscripten.clang"
+ },
+ "networks": {
+ "4": {
+ "events": {},
+ "links": {
+ "ConvertLib": "0x14d00a701a2f0d4d65eebaf191f4f60bbaa1da36"
+ },
+ "address": "0xaea9d31a4aeda9e510f7d85559261c16ea0b6b8b"
+ },
+ "4447": {
+ "events": {},
+ "links": {
+ "ConvertLib": "0xcfeb869f69431e42cdb54a4f4f105c19c080a601"
+ },
+ "address": "0x254dffcd3277c0b1660f6d42efbb754edababc2b"
+ }
+ },
+ "schemaVersion": "1.0.1",
+ "updatedAt": "2017-11-07T20:44:02.307Z"
+}
\ No newline at end of file
diff --git a/console/src/main/java/org/web3j/console/Runner.java b/console/src/main/java/org/web3j/console/Runner.java
index 5a3f95119d..f52c83bf8c 100644
--- a/console/src/main/java/org/web3j/console/Runner.java
+++ b/console/src/main/java/org/web3j/console/Runner.java
@@ -2,6 +2,7 @@
import org.web3j.codegen.Console;
import org.web3j.codegen.SolidityFunctionWrapperGenerator;
+import org.web3j.codegen.TruffleJsonFunctionWrapperGenerator;
import org.web3j.utils.Version;
import static org.web3j.utils.Collection.tail;
@@ -36,6 +37,9 @@ public static void main(String[] args) throws Exception {
case "solidity":
SolidityFunctionWrapperGenerator.run(tail(args));
break;
+ case "truffle":
+ TruffleJsonFunctionWrapperGenerator.run(tail(args));
+ break;
case "version":
Console.exitSuccess("Version: " + Version.getVersion() + "\n"
+ "Build timestamp: " + Version.getTimestamp());
diff --git a/core/src/main/java/org/web3j/protocol/core/methods/response/AbiDefinition.java b/core/src/main/java/org/web3j/protocol/core/methods/response/AbiDefinition.java
index ecdab20767..91d7e44c53 100644
--- a/core/src/main/java/org/web3j/protocol/core/methods/response/AbiDefinition.java
+++ b/core/src/main/java/org/web3j/protocol/core/methods/response/AbiDefinition.java
@@ -16,19 +16,44 @@ public class AbiDefinition {
private String type;
private boolean payable;
+ /**
+ * The stateMutability function modifier.
+ * this does not factor into the #hashCode()
or #equals()
logic
+ * since multiple functions with the same signature that only differ in mutability are not
+ * allowed in Solidity.
+ *
+ * Valid values are:
+ *
+ * pure
+ * view
+ * nonpayable
+ * payable
+ *
+ *
+ */
+ private String stateMutability;
+
public AbiDefinition() {
}
public AbiDefinition(boolean constant, List inputs, String name,
List outputs, String type, boolean payable) {
+ this(constant, inputs, name, outputs, type, payable, null);
+ }
+
+ public AbiDefinition(boolean constant, List inputs, String name,
+ List outputs, String type, boolean payable,
+ String stateMutability) {
this.constant = constant;
this.inputs = inputs;
this.name = name;
this.outputs = outputs;
this.type = type;
this.payable = payable;
+ this.stateMutability = stateMutability;
}
+
public boolean isConstant() {
return constant;
}
@@ -77,6 +102,14 @@ public void setPayable(boolean payable) {
this.payable = payable;
}
+ public String getStateMutability() {
+ return stateMutability;
+ }
+
+ public void setStateMutability(String stateMutability) {
+ this.stateMutability = stateMutability;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -106,6 +139,11 @@ public boolean equals(Object o) {
? !getOutputs().equals(that.getOutputs()) : that.getOutputs() != null) {
return false;
}
+ if (getStateMutability() != null
+ ? !getStateMutability().equals(that.getStateMutability())
+ : that.getStateMutability() != null) {
+ return false;
+ }
return getType() != null
? getType().equals(that.getType()) : that.getType() == null;
}
@@ -118,6 +156,7 @@ public int hashCode() {
result = 31 * result + (getOutputs() != null ? getOutputs().hashCode() : 0);
result = 31 * result + (getType() != null ? getType().hashCode() : 0);
result = 31 * result + (isPayable() ? 1 : 0);
+ result = 31 * result + (getStateMutability() != null ? getStateMutability().hashCode() : 0);
return result;
}
@@ -172,6 +211,7 @@ public boolean equals(Object o) {
if (isIndexed() != namedType.isIndexed()) {
return false;
}
+
if (getName() != null
? !getName().equals(namedType.getName()) : namedType.getName() != null) {
return false;
diff --git a/core/src/main/java/org/web3j/tx/Contract.java b/core/src/main/java/org/web3j/tx/Contract.java
index ee9af948d7..8f6f4e4818 100644
--- a/core/src/main/java/org/web3j/tx/Contract.java
+++ b/core/src/main/java/org/web3j/tx/Contract.java
@@ -4,7 +4,9 @@
import java.lang.reflect.Constructor;
import java.math.BigInteger;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import org.web3j.abi.EventEncoder;
@@ -41,6 +43,7 @@ public abstract class Contract extends ManagedTransaction {
private final BigInteger gasPrice;
private final BigInteger gasLimit;
private TransactionReceipt transactionReceipt;
+ private Map deployedAddresses;
protected Contract(String contractBinary, String contractAddress,
Web3j web3j, TransactionManager transactionManager,
@@ -369,4 +372,31 @@ protected List extractEventParameters(
return values;
}
+
+ /**
+ * Subclasses should implement this method to return pre-existing addresses for deployed
+ * contracts.
+ *
+ * @param networkId the network id, for example "1" for the main-net, "3" for ropsten, etc.
+ * @return the deployed address of the contract, if known, and null otherwise.
+ */
+ protected String getStaticDeployedAddress(String networkId) {
+ return null;
+ }
+
+ public final void setDeployedAddress(String networkId, String address) {
+ if (deployedAddresses == null) {
+ deployedAddresses = new HashMap<>();
+ }
+ deployedAddresses.put(networkId, address);
+ }
+
+ public final String getDeployedAddress(String networkId) {
+ String addr = null;
+ if (deployedAddresses != null) {
+ addr = deployedAddresses.get(networkId);
+ }
+ return addr == null ? getStaticDeployedAddress(networkId) : addr;
+ }
+
}
diff --git a/utils/src/main/java/org/web3j/utils/Strings.java b/utils/src/main/java/org/web3j/utils/Strings.java
index 37a1ada2c6..7d4376e4d9 100644
--- a/utils/src/main/java/org/web3j/utils/Strings.java
+++ b/utils/src/main/java/org/web3j/utils/Strings.java
@@ -47,4 +47,8 @@ public static String zeros(int n) {
public static String repeat(char value, int n) {
return new String(new char[n]).replace("\0", String.valueOf(value));
}
+
+ public static boolean isEmpty(String s) {
+ return s == null || s.length() == 0;
+ }
}
From ecfd6e954fc8e1fe8a8fa49caed88db2bb71738c Mon Sep 17 00:00:00 2001
From: Ezra Epstein
Date: Wed, 8 Nov 2017 23:04:44 -0800
Subject: [PATCH 02/16] Appeasing the coverage police
---
.../TruffleJsonFunctionWrapperGenerator.java | 130 +-----------------
.../test/java/org/web3j/tx/ContractTest.java | 7 +
gradle/wrapper/gradle-wrapper.jar | Bin 53556 -> 54727 bytes
gradle/wrapper/gradle-wrapper.properties | 3 +-
gradlew | 26 ++--
gradlew.bat | 6 -
.../java/org/web3j/utils/StringsTest.java | 14 +-
7 files changed, 43 insertions(+), 143 deletions(-)
diff --git a/codegen/src/main/java/org/web3j/codegen/TruffleJsonFunctionWrapperGenerator.java b/codegen/src/main/java/org/web3j/codegen/TruffleJsonFunctionWrapperGenerator.java
index bbeba6d832..851774c123 100644
--- a/codegen/src/main/java/org/web3j/codegen/TruffleJsonFunctionWrapperGenerator.java
+++ b/codegen/src/main/java/org/web3j/codegen/TruffleJsonFunctionWrapperGenerator.java
@@ -130,8 +130,8 @@ private void generate() throws IOException, ClassNotFoundException {
}
new SolidityFunctionWrapper(useJavaNativeTypes)
.generateJavaFiles(contractName,
- c.bytecode,
- c.abi,
+ c.getBytecode(),
+ c.getAbi(),
destinationDirLocation.toString(),
basePackageName,
addresses);
@@ -226,72 +226,7 @@ public Contract(String contractName, List abi, String bytecode,
this.schemaVersion = schemaVersion;
this.updatedAt = updatedAt;
}
-
- public Contract withContractName(String contractName) {
- this.contractName = contractName;
- return this;
- }
-
- public Contract withAbi(List abi) {
- this.abi = abi;
- return this;
- }
-
- public Contract withBytecode(String bytecode) {
- this.bytecode = bytecode;
- return this;
- }
-
- public Contract withDeployedBytecode(String deployedBytecode) {
- this.deployedBytecode = deployedBytecode;
- return this;
- }
-
- public Contract withSourceMap(String sourceMap) {
- this.sourceMap = sourceMap;
- return this;
- }
-
- public Contract withDeployedSourceMap(String deployedSourceMap) {
- this.deployedSourceMap = deployedSourceMap;
- return this;
- }
-
- public Contract withSource(String source) {
- this.source = source;
- return this;
- }
-
- public Contract withSourcePath(String sourcePath) {
- this.sourcePath = sourcePath;
- return this;
- }
-
- public Contract withAst(JsonNode ast) {
- this.ast = ast;
- return this;
- }
-
- public Contract withCompiler(Compiler compiler) {
- this.compiler = compiler;
- return this;
- }
-
- public Contract withNetworks(Map networks) {
- this.networks = networks;
- return this;
- }
-
- public Contract withSchemaVersion(String schemaVersion) {
- this.schemaVersion = schemaVersion;
- return this;
- }
-
- public Contract withUpdatedAt(Date updatedAt) {
- this.updatedAt = updatedAt;
- return this;
- }
-
+
public String getContractName() {
return contractName;
}
@@ -303,47 +238,7 @@ public List getAbi() {
public String getBytecode() {
return bytecode;
}
-
- public String getDeployedBytecode() {
- return deployedBytecode;
- }
-
- public String getSourceMap() {
- return sourceMap;
- }
-
- public String getDeployedSourceMap() {
- return deployedSourceMap;
- }
-
- public String getSource() {
- return source;
- }
-
- public String getSourcePath() {
- return sourcePath;
- }
-
- public JsonNode getAst() {
- return ast;
- }
-
- public Compiler getCompiler() {
- return compiler;
- }
-
- public Map getNetworks() {
- return networks;
- }
-
- public String getSchemaVersion() {
- return schemaVersion;
- }
-
- public Date getUpdatedAt() {
- return updatedAt;
- }
-
+
public NetworkInfo getNetwork(String networkId) {
return networks.get(networkId);
}
@@ -404,16 +299,6 @@ public Compiler(String name, String version) {
this.version = version;
}
- public Compiler withName(String name) {
- this.name = name;
- return this;
- }
-
- public Compiler withVersion(String version) {
- this.version = version;
- return this;
- }
-
@JsonAnyGetter
public Map getAdditionalProperties() {
return this.additionalProperties;
@@ -462,12 +347,7 @@ public NetworkInfo(Map events, Map links,
this.links = links;
this.address = address;
}
-
- public NetworkInfo withAddress(String address) {
- this.address = address;
- return this;
- }
-
+
public String getAddress() {
return address;
}
diff --git a/core/src/test/java/org/web3j/tx/ContractTest.java b/core/src/test/java/org/web3j/tx/ContractTest.java
index 7ab91e74bc..d2184eed53 100644
--- a/core/src/test/java/org/web3j/tx/ContractTest.java
+++ b/core/src/test/java/org/web3j/tx/ContractTest.java
@@ -37,6 +37,7 @@
import org.web3j.utils.Async;
import org.web3j.utils.Numeric;
+import static junit.framework.TestCase.assertNotNull;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertFalse;
@@ -254,6 +255,12 @@ public void testInvalidTransactionResponse() throws Throwable {
testErrorScenario();
}
+ @Test
+ public void testSetGetAddresses() throws Exception {
+ assertNull(contract.getDeployedAddress("1"));
+ contract.setDeployedAddress("1", "0x000000000000add0e00000000000");
+ assertNotNull(contract.getDeployedAddress("1"));
+ }
@Test(expected = RuntimeException.class)
public void testInvalidTransactionReceipt() throws Throwable {
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index ca78035ef0501d802d4fc55381ef2d5c3ce0ec6e..27768f1bbac3ce2d055b20d521f12da78d331e8e 100644
GIT binary patch
delta 28785
zcmZ5{b8sfWx8=mPZQHhO+cv-GOENJhwrziLX5xuCv29zk^LDrP_uh8Z?W)G@ziyrG
zd+zDhVu;Zi2xL_S2uRFt-(X?CefuW%EeV+f<3A(a0cuu}fAgA2qG|%!CwTYnx9(uy
z{-?*k{xiDv)6cm6=lBQi+c&0^T@vgR
zRSqJc&w@7U7v@Adg(S8O7>q0;+0eAPhP<7eEqn(YWUi&
zT*XF6na6d9sPHn9_9l`MNz$zh`?dOdFoxiP6{X)hsCT=<=CM#tC
zskAueLH4VY*;qR)w?sEWx@T<
z0|Y3qvhOo8d(Dm@5&yvHGB&i-=D7lZlzc0h9hXWhfX^xG8O2GriF*S*kex%hT5_Qp
z-CcH)LX{OocRwS{q-!gk%GB@So+C|}w%QU))4K2mj_foJR^1OscuN_8{ohj0X~*>6!Py
z!V8a9;(MGjrM?(nYYEf
zTD!91mLG17RAH1AsMVG!Hb{1a1T(XM(E1Wq$?(#K6kD~J=-*-$O8~sP`b2UzqDSc)
zy0FaYWW@}O?pDs5ZtG{ocFL1y`sOg(qvr;SpVp66zOcfu`Wx%ZImNZ#2T0tyIrZal
zrr_+TN;0pbtoBKNjtrhF=UafTO+oc5&z+&M;#^{Pqy+z2dk43v8<9u1wV+6mS8T5#
z@nbl|o32kz^uAn5TnQ+;e$aw6OElvY-!O0U${JYkT7Uvx0B9vHGYIt#@%}4`HDJN-
zX&Sc_EU}Sj(Mn(cZ3L|>kC>fWHikijhA;Z*V@MN=XhLOoA_^!v`BKhsqk}3d5~3;A
z7&DD`3wO|{+n?Wvt4_Znu#fUCVMMu^cl%gGV9_^H
zn>hL}B6*2i$3*hz{RabSN(Y*gzgpr`PWeL)lwQ^82pP}(w_Bt!vZ)J};eDiSsoG-}
z!A}z^Y?)bzmo-3hAk=PIm5oQA#$K@RiA|g$QWT9ZG(9dnQRU7K1?0e&2}#TV%iphi
z%t-bkGZqvTR&}X^nY;nSWP|)*Sg>qr+0oO07*e-Nj|1*d;#@M;AWyVsrDCtb49@KV
zJ@6HkG!Yq^q{#M^!;%e7m;tNw=2@HP<<0+_6g}buQ;`pCFN>B3_`TKd#w3=-?R%6BgzzWp6ng9{_Fyw1
zk#?U>b0BmgVH&RcF)H4L(W(a0?L5zZg>q4G(jIBJRJB_IW5h6MDbIW~?gPY-8t#uA
zb8|xY7rdeqnof^apd%5cd{6=*5jWLS$e?`)dTeN8ummnPAcZ8W_x|AqaAPw<@yQ5qc_G8t8$vf0!zv6aHkjEiDs8rMGA6gUIELdT3NyVDh7)}uMNWn+1-x7x#)qjPY^a`KWJVlu>H
z_hJPB?TqV-_0xPu=N7Q~kzM-gwfYeevVNN#vAuX>0G)la4n6Qf1o1O=J7wZ0OOD9w
zEffSWN+fxTWa20mx-U$G?WW>|WAy`oBo(MPYJ&Ts@R1hLaPr~+0W`Sf5&I3q2O|PH
z>|EbGx4pphIPZ|$Y7ud`9~B%Zo1}1bY-H_&JpUnz`ht~9o-%XUdJmU#&e7w6myZEhI4^IF=T+?kD3%3>g>&k=F%WR#H@_nyREfE6zH`5QX~OkfieQEf}#mg
zmkVFEk%gDj?MUd}n{|aZBVT%P6`Ri`;^Mz4Vei%uJaQYwWup;ZK1;)Ai+V@7+rLXp)ew=Q6(RKBRULC3&l29V>MR)PLlrBv#*<4UV4
z?yk1po^snhVRO!Q&pSO(9BG+QE1Wdmq>p}(G>-cZO;wd!u@gBxc&;~@R)|C~%x*qDB+nv10J6gnZ9fq*NLjHPS353~HUF`h
z2Q3R&9Gl6>s92X*P>EMhKd6z=aPU|wY@YjS>yMH&=ivd<`xs2Cx2I&uAYawglln}x
za}2@U)z%*;hS*UF{pG9Wp{h6ISZ37)r*Gp#3U2Kz*R%KCwURHUhX06Fc&aHFEIf5&
zV6GTi16PR-m-cT{vTe&K^*d(dX)4Bh+e(T(w5u66EfujwJsUZ93pp;?`4si-{GaQ=
zY~**}mzLl=sxa%~IY0##cM(p&rLsfr)LFojXUu$;heIiklayiMA9o2C05h*JAVG0{
z)cvY{e=GQ~EIGNlGprgm2Yfdlec;C(g}}KykXQ4HKpo*gZ_qbyyp(a9m?e8ReSAwd
z$l8iq#)>sCU%=Q?h?uI!Q2T4$oz3UfqrPpxgtlWke}M
z`N>aXs0Gb~V=I-ZB$}1kv_s*_Vvn3SZ7N4;a^DPtc%C|7)zY&+=?~vHA+k@*F9)h`TrSp#N
z&J2QAo2w9CQcfK~{$9^1k;*KG)@{`ygW;32M?7b-N8vj%gy5SL@#D;ge!{`Lf$j?H
zU9rhz!zKozSO+7p`~(Mvi_J7fVy}@7m>@fxpNwPZq<#d(!g0M0r$op#%*IAJtBJU|
zFI5RA36C9R+&VvpKEhmuvwE-^sl-N};9$OpNi&p5ZC=hxH=@Kw7NO`SkH5(no<+A6
zhNFa*F=aRB5W~^z^V4ymx>p8HLp7)fJ(coVA
zZmB?nCpf35W?CDYnX+fd@+vD#QpX?@U_zax-j6$8MN=o?7=$>JWv-s@E>Edw7HfBe
zF}5z%R8=pWmc+?s5u?|yXvbIv#HYS(uH+u(a}!R?Rey4lN_aD@<~u#|9FL_};?0)L
zGFQHV?7vNkZXeoEPetlxLYGP$nU?-|@>w>0Si
zAyT1F(je&)^6GBa!e%Tx#@B5*(*o5Y_g&{kiQkXybf$jq-ID*TBZxB(m{s6YB|$#k
z2}K=uG8b(IwHle#1qXc1slY$kITDIIK9JM+A*Z;^)@vf
z5bH}^Qij*Gs?u^4%PMA%Dt?daO~;~
z4;W9Ak8M)taFu~_@l8dFL(S;bWq0ssau#u`C^ovh%&X5JcquvH;T;P9)bnW}RvDd29
zoOCWUBHWzpHY?+~6_LI2PeYefIF{{}QWLKyWlP5_533#GyV@*1t+J_~WTthwcprb8
z#yG-k?HSUT?@jw|(#Y0cBj|5Frs!kUfBH6!c~mQ?>HEn50iWGGIK)(Kjfgi`mc#6w
zoqOPy%tSdjEuR9k2B?gITC|@inmc?gp%tDPSc%b(+s^S%O8ht*_hCaqSQq}~p<@g}
zBBf;S*a5E&atdV_<385wXDens-8fn|l{P*Of9-`+D-Hc(!^(|Zrtc;aRQuJj5`I(+
zU{kUpf)S7b9e?rV+K50E!g~-3P+8!Zy-J#jFq*)foge=UV7PJk@kGwtWVB;TC@(EerszygkhNU
zbHmBmKvK)#T}!jw%UG(A3B4o6)L>LAtfP==Y!fjac&RPFKJp1FA#OKka+ZLsTL~kQ
z&oJsFitTb_K5Nz^YLR~wEQ`I6s{_wHRG@44LsmxB$X#n9F@>~f5{ZTrTiFZkA(!Dd
zye&rHSq!%+56aq~n85Z$bRqMa&ioV8S40up#dxOD*5<=lTolkP(6O0!ajm{C<-s^y
z!nxxH?9qz0{bkh?pX*{H@+*t&sel%?2A>A|K*iUq_P{Una(Om$I6HsVD{Oyx4zpsX
zE!LJeI;`3D6t1;R20T_*Mxo()jy%Mbve>GL4E?vcg^H^ZgYmq-CtsIcyIM;H$XdmS
z5_hg;1#{a-G-pm7=2Z%bwLXN+cJj}EVY~mu`0!3Z2v@dck8-kt|+ZL-`oD?qg
zH~4k#w`^v&p5!zm4O&**c?dEL&V<83sQeUuULH!=movcgyqL(R
z^EgNs(L~6Wle3->&@^LL!RS(c#Q1r(VIpVGN9e$sgKr+SKaq*ncJ3)K(-!>ds4^0W
z`8@ye9u@mJv>fLpl|HQ8e}w$CIrh`&qdOMZjni~2Ket0R>{?H03EGj+gpxudp{6SM1fT(D4mjq%
zKu=N|Li4Zm;4ER+b``aZe)$nqgg-M9u3@+RiQe~OS4jF;Vj-L+^?N_8=VT-^D$pYR
zIyhGZl@85_lnBZQp4p@r%UVB&SJqA9dOv;BBdW-sH(x5{DWK}w-P2XJ4Dr$4X{m0QjUl>%zf@SUD>5u@Rl|gs&|`)lpLBcJ7W<{o!I{>IC$DG0Q)f
zI8+xns|fA|n;j#@QK<#$$s+N3TI8B$*{jI$T^~PD|^6*f!^YFBCwsQYJNv2nPKYXYtrqngVf<2bx#FNzQY?l=prFha}(0nA_
z-tWoGze~j^Cne#c201Z4aj`4zo
z_2$>kxww&e(MGvuCD~U(A4KW9DW&^0Nj;j~_QS-N<|BK3+iL2ygB4Wd6xK?e{N&dn
z+!u0=$QQD#snJkp!VKFudYvnN7G`vwD%tp{y#;hPC!us;%)AKnMIHxkAN%V7Kd)s-
zAb7*p`SS-lkp-jSxD@SqfejQ1bVw!(Nke>X0I|CA_1ofX6LlJ##Tzd!L(M@dB$oC;
z^$9#8A=*<;ttHZRH@#79sy?h1{v*?x90vZQ-PV%gi_Xg%ezjp9&zH(mSXC9#PcM?d
zdJG*mr9m$w1pGd_Sq;HF5rAE-s-U;s-p7jWE>y_Y9@cqvnir!FkXr!l1tcKAIGgso
zp>NvRpL)1hCMsj9Q>ue9;s9Pu+E{hQr`(TJ3jE`~Xy!iTeYq1QN^V4JSq`}eXiyx!
zD!v@ocpQ&=psB-?p$8g|xtB9;Yrh|v31+s~Q5igZtX|Z*q!DHH9vS?perOr3&&c(g
z>Z2cZlu1aJZ`LLNwi`NVzd>fV4nTy=d16LhTBU8cw${LaQkVeFRafuxNX>u=x75*H
zMTNx*oBH4Cg>hr&TI(jJQ8ch)xAOPk0_0*D-U=S+=kgWU{HB=q^lHsmL>MjT;W3ld
zbCXwpzsnRFy~f5l8tV(Yyh|R@$qMxyruWKY0x3aGtIM50Eg#Mbt~uszV+=9jHC2#{
zl^k}pg4Jp}+gZ}s*e=E5vL3k}lB0WsW>%w(5kuwsA_+;>WS!DO(u`*HZ@CDH79oc3
za_nv!-h{&$AkT=jHNz%sYs;-$`#Z
z^Un9V3j%fEICO;T;IAM;R@Nv8aA^ly=)Q0l1i`+yaH6_(WxY4(zVFxgFT}=VDiOK!
zJs~=O`ceB_c3?W}cDT4cPoccuod})d(z?~)q
zeWbS>^~DllG*J(=;l0+D9xz5(Fg_i@-%gl#Vhu!?1cLSM}P;@v>qH-gzG(Hl-Rm-QNTo%l}q7}
z`BQQ#sd*eHNw{eCQWl4Md}|sh2d1vEg|8+S2->)97s4kTyeXro%Qg&gH!s5e4PSGl
zUtdu<^VL!w%No@6=GdP($RD@($-%@Qy8;)nD5DB<2&-jF!jaYf*>0OR{*g|R1id%vt);Qg1I3O
zh-OlZxj8g0TZn)aN`!i&SJbA&V&~0@~RHk9NC}diIRT=4y8%JfB;G`>D!hY)k
zng7p5Ai`(tNtW~3lXE$GnSX{SNjHl-T#^ENDiZ_=srLeZZM30G^*#%(mQCQALA#qT
znn4AO|NGU>ts!}u?M}2IdzvFD7QFBa(4QWFv#t(@%sJ@VGNXP@HnXYL%i?S{?Q-)I#n9*-3!
z?ixHRG>k0QpC(h2t<}p8wOF#@LZu<(10J;#Qrbi2a}%kR&3;@<7h2lKN=wI1K*ABH
z0KA_v$iQE$TZ6Fpi~2*fLd1g=ya~XfU|>t&Ul^L(Z&GN3c1630YJ@m}v{9G5WZq4k
z*M~+CJ}_?72fv}%%VYc>ZV);BoMu%LY!3R-T{`f~Wzg#TLMaZWh}QzrZJcCdiOKQI
zF0jAE1ZBpG*}ozL^N(ldEHru2fn1}NfF8N)ncW&PAi~G7OoiNI#h^gpC-YmosmfvE
z1ffdA@v+3DH08ojMU9H8#$U!`-51TTxcU(P6`C97z2Rp7VTCEqru5O<4_FgzLYCVP
zau?>C)t(LWK7tBYeW@8qI#ip#|E&PU#eO?1Ds;op39B-P|S9KVF>`+*+bmucDKvarIxRN{;?v;x!17+;cOr-q7S2CO=as1N)e!AM1
z5J;kZix!|cJbL4XRqzV~Ubt#UgC4XahgC3Q^YKz!`kG5ppmPKD`YHu@NfrD^wtPq>
zF-ec>+Z)xv3Q$^eZ#V3_8YQ}WCI|}97;e9Dg4({_?@oU4r|(N7`F$8k9~4GX^8y!C
zy<=rysh$9d%8Nm!k-k&mB1zrtcZty7KWB@?(@M34r^8XRH^|b!=ubQi)GCX&Y?{K6BqHtAL~@ip#{?B90{x
ztRqy(5^Ob>))$9NO|{d{W7|tlIIn8$PyF-hC%xa~8kr?~GKOY%K}--CH(qRg$BQQy
zs(=6otz5=L(L_T-pC~rUi3gxP0(M|odvx{YqzcznIW%^7VygzV!6H
zENK>)g1lsm&nYQUUybc4Mr}fo(>WCHQpTT)vqA^P<9vOs>ds#p(Ugp|^8I=HEn9>F
zsl7ClFmjQHSbG-b#%Zh;yrqge5nj*z%8tE=Q}nv8C|9M+Oq3jfwY9uG1>_LpoA{>@
zP^Mz~w4BC0mDid4ktDxvXkTuHnY!l&(_aNsoyd1tPruhCajNde8cX48`IMgW#oXarwoHK4u
z8>xNA8cD{DqkAqKUT%=(2FPiob)qaC0Yo62KSE^78O_AR4~jOSdufZ<-f17=qgHii
z#Naq-QTi(bXa7PJ)Ub>4QW7d+_rmctP?}9wndj$MD?_q;qw}FOxP6O)WVcbZiw<=JbZk1(-iM-W+H3S+FJDzOoUmxhK@5T{*%1^8tHS}&)2I$6^7
z=Xau9QPV)b{%Lpuz6c;SnaWQGbtK*5HF~b=k_`!#>j(MG8b&r-l{3kM?y+_kB%^8n
zgbhT&i)dk3b>ul6=tl^&Nf!zhNLCgb&f7WSc%0tGRL)A4RjLnxD=}h%NohJ1OEanu
znJX>EPkbi)sXt=Tv#-!K$x;Z5fT{Qm>GjcE=5^Fd(flD3
zzXvb5ib^*f#ZTQR@CDF0q{W*K_+Hv+i;XdmIub5dOL|$|iL4_$TZA|-F?5V$IYDY@
zO4+(B*?I|~j)U19knIfS-)j>MPQyI7G30vHj8Seo0OlrlBa{<`E^qU?8r!THvF(eV
zkG&fng1jiPz`j#qzkJZ*F*^&%!op?MoZ^72K8`xmsLnK`jCn~GCW3>L+By@rv@w9{
zX^~CGL2xuwkiGl#mL8w0_QSw!>>*xDke2p}kizwmkU2(>`6A8<3Cf>O(yG>b^%49r
zyo1yGFgRM4h-_W?&UHH_VzF$)#zjl7NxU~>~|5$tJ@JfRuyRA_KtwMI+NxAKif3Crt9lFf
zJ-!<7@)$h0k3;tOdmO$@+ikHVz-^w*V?BZw`38X`p&K5*0{ttJG@`L!@P=z+N&*k~
zJP7bldxrqL!(X8sT{6g#9Y92!KZb>o!8jC_x`FSB5gei}s}pp9^SJ&YggoJ$+-8?#
z6K6z^UBJ{)UfEB{#IegB`XFZR+oDTFR4HuzgY#fjbb<0FPaF>P4JvdrUBOX>X{MbK
z&jHhsbuELuE)d6}!)Z;2RG_>ZC~N?-#fmzdQdS$J6^h%QV%kSF)5Z?#EkXmDOaG8O
z@Tic}@+cTgEUD}jYjag{E1RvlHafyjbV6$@njb=nYv^(jKB$;JLNezM;JfSR40qvm
z`;h(eV%qFUNMD*WLaLOaNH2lQX(ASw3+?q><605jb_^9eku!`~Z-nwG#9{#sXy=Zk
z@y2?u`|KwGqkM*twwJ@Xd*
zb-1{#o9JSv^bE6yt-7xzq%7eLB66r*hxNv7ky@>q9*r53e*H@8lW77v`3CL(qO8yU
z#WCGA-m0>5#sR8@dYC$_r)Hpqz$JBzniX3#CDE`ENjbsSz6LWGL>1}^2Db0&ZTw;N
zof+}?ZO4~wlxfnJXjE5V&8qMsAXx`Nr003%8~~05vNlTKU(Xs6AXi$nv(YFNh&2*A
zuVC|5hOKSsS!o5vjfoA;lZUSw_0;$$c>`$+d-*Gx(tY!zVjh-4TR;B&0
zKj=%4upFV<6syt{$GH?QsQvg9fhPSg?Q9`FY+gPbPGxQJsk1|Io!^arY*rJ^4Bo?;
z$ekc$PKRb5KKw$sv@LV1aCjybh(4Vg5!J)?zY>d20c~7N6`M%=0ns5i_;wDeq~P!v
zt;i-12H?AcDSZ%pIyc%oHW(^cWy`TrSwjND@w_yMGvqU3P3PolasHzGPc|tf9C8Qq
zKdQjI8r+w~e*_FSN=hOmeoFojG?0?*{|Xj#-u*Fk@PbsH*e9%mQT1I7Z0Dp`7?BW)
zRN+G4;hZEgL&Mz1AX~4^R(n_I;O)O0iJUCwgWPr1GWXW`2g?R4Smq21YaOTgPRUS5@71C1UoLf;@A%r
z^4L&lj%Y|_ds^xwNipn&J4-58`J)B$CacV({-k~-bM!JwVMLaYX4!xwO>|xgYMT_^
z$a``?F$PJ$jMT10b3ii&$tVr~tz3Y7gbIzT*ieDoUdxLidO?P1%8NL-3e`=kpfJTC
z&hVFlocLFBgbkNq1#p)E-pB^Ad(`_rB5;6S$ab}SAZCMZKQ5_lqqf$E!81m=pZ^R2(56Tic$16)d
zwW1jSRO+QYRV}evEJ*)N$g@bp3%_E`bmASpz{ScXN80;p1!`TbRyWogrJ_|_5P+Ec
zzNcHf`eQMdW~duxhI!Y#8N2vt#Hu|LYeXS;LRkk|O}kIdjZdbY5^L{B|9?)Q~=j);4e`5T<)JlM$J|4GCw{Y|8uIN(%7
z-r`~-6OhvF3KUW+VCz{Z$EjxVQEX8q_MYJfIbdQg!m*b+=5j_F;1$0+)7j*+IWXA+ss~;Z=qp0wI9oQD3b-=6q*Ge!4eE4;zd3)eCCTTvI-;6y
zW~({D4H_<44vfXh-uu!28grbLP(Wn<1u5IzXyH6O0n9Ozf6!lQkHSar|24MmoOLK{
z`L@7pFud$3nAmWR`^!1+v&>}F8}DimnMlCxXTq~-MuJ$t_r7e2(-&%DP2F|*l25D&
z=FI$rSYNTxf0>51TdcqSsE?&k6pmK_&i2A>AYKq@bH3#L`PKsP
ziSd!D20VW(y+_)+wZRXn-^Y0=OEB4Oj?nS^!2dbt2Gzn}-BE3(Jj&Hmz1x+r9aFF!
zvS=*ixK_@hEK5(l^fELTLNWdSIC}R6kk|44>Gr7}oAEreg%^cm>?^E?c{Z+i*
z;HxmYzIPYw7__O*NK>QlP}LYTW{z$-Xqhhv5A@mKMeaWmTDXCTVYskgmtNxzmNGG>
zWFj&J%snLHf-_M57r`XY?fCrqW^gj8w|USAP@JSzx300@HlH7
zAAFpLa(xAi*11P{P`O>@(06+e^CaSaabj2;+*@ZE`7*q_UZuY~Q2IN~pymJbjOh)+EKr}kjOxWLBnQ0~JA{n(J7LoGUMnMy2
z8(Z~_qxe7Gq3(9-B#5hQ9G{Vd%cP|-!e2+b4b;0DIYSx5o|2nnjEFy&hS0|s&0PL&
zHyXs@6reL;%j2$B=P3#D&-Y%=)Lsp%1Kq9HXcM!KPsq<8HHeM^!CS7iP2Cf7oSPBC
zww3O0S3GHXbgOw92xh%uTV-6p^*KD8j}#hUR_MUI|8DD)SnE7*yW^MPMf7?t3Nny8
z?gVm8tWRqXb$1;!Lh`yaObN1oJIyz28B!&adt1l6fH*BG$h?TtM>_-S1&*0Rph;
zJ+2w~*#ldmEY;`qBsr>97|pXZ1F&x=wQL(yTOd$e;}(eH{u(Fv-SnWnvm$nWzm+Y<
z?)4E2&-B${F_GExJ%Z=2*7YVD+t-=HtAC(R_i5Ns9Uiag`BcTPGXEo0yKN}-ELB@1
z8qFHeds8Z%R5vo{YkZU7``-Cohx4ETQB9+qSC*kwoB4ypOL06XGZ-|F~C
zXBCM!d^(Zz8>#|OmH
z$VO&q+oi+XO(cJRp?-y%wGqQCQX9*&`|2X?7FO?|d4WYP-s5Vq>^1tqB|_I`4Y9ug
zzM-%wr>5uJvKH*U(CBf70>4`#12pzE^@XBkUbM~Bi72xr4s^sWM`^Q&%?{dKGZhoq
zN9g^oD=sa#j3cf`aCd2`)Z|CHpOT73#Ur3ik{Wr^tBSAh&>s^16i#;U@}iymL>c}5
z3b{qnlQRU934a6B8lK^Nd1v{b7h@hmrzj=Hw{KuiDVrp8K)3*`!!{9`=cDPVsYWRA
zj#>)zF=B5{TKr_vCNfepHqt#xpX9g=s_8rh^mAcNQKux>z4X1gD+74otB+I9@NGYX*y|v6IS2ByLa94|R-nW|%
z!^$TvrW2Gnn$h&t{$Ug8i|hbjfL?qm$TL)NCwNMie#9Am9BGT3h~fs95mA{wanNFz
z4R1$(-x*VbWsG_d4$qQ|7c0S8kRkhbo|Gl!*d6T|=!qvlAt_~uae#Fv$dNd+mqsR>
zGXu9oai+na
zli42vxx?2bTI1J43E`U24v>@DITE{9FzcA%?vw%2Qkj_px2Rsfl5NpnH>NV=E$DI)
z=aij)jHE}?h5OKLU=%xNH5NvQ9^;t^csT3VTASRA?h_t?Z3N4#Se!=1*Yh;$
zYIQFyC!q(}Z>VX`{qo-A)8b^6x$^}szP^>RoU9M8=%{|qqOmxFsVdzZGp9v1T4LGO
z^SP-mt8t&M1s9*Jn+-*k>Af6V%=ySQCW-cVKMp&NyxppP>}R-0@60?ph4v}Q0I8~T
zPYyLEZZw@%n?#PZd{#PJOfdfmM};xqGd06F=N1(S&&8P%0X|z9tG~QLMxX6zbGl}n
zow}xG!wkOWi@hgL{FSx7yCK62K?{5?)~=z8K3-9Tmp0Ln!IblB1XBn`i9tFQ)))9j
zX#bNY=Ft?ouk)BJeVOsx{yDo}*2<6xh2ZM$kC|vPO6$&r6lwo)_RGGrwqNAHU|kn)
zd^rPc@2CX?4nh3=O*#TkB%uhk2t077ss!W^ziE(G6bK~jYtrsjF39RdWtz<`U9B}u
zKbyH~x6*d|+j@{);H}xIjV$R~1a{oKORb+pp+@TEx*x@=bJk}4#0T0!C_ly~7H*<8
zPgX*{hKzV$gFo!kT4kqA!T|`VzI5eor6OZulrh)GLD#3Jt|;Z~y(5rg=S%sYLIl
z@~PVB0$@yX+@6O}@R*=?Q@YzpGB?R|F&tBKp=b9;UA0MjEdVyzspRq~5#J5*Ak+3v
ze{#CRxq{K67D0O9fpx64)Qsl=Toa`0)@wFAX{jC@r;4xS)Y7PE%^C^}!Xc2h{9Yup
zk(=2{5uKU`Ry^qEH4t+Ox>UT8Ng5Qb=tg?wov1vo3$t9-qT@JIAIO(Z8CCv)W&t_9
zY!&Jv1r0eJGs3H@U*(J|;xGSO3DN$>7aEs-59crEqW~;Jwg!h6*mYNe|Vl95l
zm*13n8D&V}Y!HZN!s|UUZ+}nocamlLRl-4x+VZ*7U*
zHiI@n!e-g7%1j_1AZ5{6LB?MsG`E?N_C2#&UeF_@U6Xmql&Jvto!Uf`5oew#cG{rP
z6ig%KIGwBYXPzhh_^A=;l(-!>Qj0!qZI90=nRfoWQF$dEd8;gJ9^fvlIX0h6KQ>Y2
zyra`9Y6-na3&7qALS`|hkDU<-8K%k6@$kbz@zA3-)Xr_~ZYi;fTD(hH(#CG*J>8J%
z$z1fMD6)do5`eo;dI(CW)~QGI0yfB+p^FmSmPp}tp-o9s78ggYXk
zO))vxGpLo)29%8R-14CQS;c5J$C5mO3U|?d#qQHOTz>(2r(N#|BX@Kwne?Us
zbBIQsQiwn%LXOE*CuB)z2QSI@F!w81D!XQH!0qc6QxIY#QDr-ewR&p|t
zgZBwk{6T2Xv40AS`63v<`Kk*w4ZDK$XRGtls0lI#b^ESNK`SWY88*#EOL$<0?jtY_
zNNUQ6PvBq|qaSMqVJ6X*yCh^dX-5QCBb{>cUNkUM^8tQM60^ppML7LI{N5^1ei!?Z
zEc@8Z*$~<0XAvs0xcQHR%s9d%R(yb+y2_kuB{HmHJ#1#@X0DZB(6K
z;NombD2I}AKYEHQKl${9E9*+hs8jR^<`L}IJX%W?TC}JfWzAmYrREpf&!U?|tuMHr
zRd*_{OmUALR)ym(_cNM7k=s&8XL|3I4+3AE13y(?g~Uc#UO&kc607Dkzpw%(e_~$%
zCkZd(yeMMY?N;gd{AE9GLOP%fW=T#l!bLP+c>?0ce;%$U86@`76h0B1CH;_jY(F_r
z8I#EO+Q>NMSR7X`N$2Dq_xOS{hAp%oLi3>fjHW6pae*w4&rbCk$yeV4R4*k|;4LJi
zbb`GqF2g~U40$Uf<2^<&%%L7xIb(YRfk(|YrGJ!l`L6vK3oB;W+wx&BU{+TU)-`^=
zxOI0S56FcjbnLtG=+N@+YcR9Bnnt`O1l@X{{G8o4HTKKR`7uU(if{^>7-j0dUOg{u
zn|hXT0!kG*aW%t_DwVp)NF7HSD^1E8>!g}&$8d;XQGi##7rMp%l7jS}}KaxSU^O=F!v1pfQdAACpB
za(7lo1Jcc-Z=O}-o@;Pfmcyvi8{d)_nRqmF^x6OJ{>IncJqRwBL_w#4k2fP;^$-Nm
zR+7eTc@d4mR!AQ^GoE&B-^b7zCOd`xQ)7kaL%>!s3w3gv;UTF}L`)+7Iv9;N7Wm}z
z8=M@f1?T8mHVj!&ex~OJ3SNw`@o@cF<;HbG@M7#yye+1}a^)nGp1KsX<~hMUD^VvO
zFJm=Q)|g8f42%SLV^zxJWfMWHC`nR
z*GIUcnVWzpB`$WeI*gR1tKpRlXs0{3;yW^=n3r)MuPfjj<`f;7{X<9gt<>X1
zF0Ly=vkd`?^>BqiLta){4gHCM5Lag@z~MKnr-jAi%9A-Y_jK`5cGdde+BDAZ)ugZB
zGSghl?Qyvbr_xHALZ@oD6?_a+w6Z!qaQpQsoQ4@S~9G)BRt;i
zj@W@kf3He_^{~fp@I?o;fifc1Cl#w)v+m00-|V>5b$@_n-^pyS@^au(Tk0V(tn1?64>Bs7-kcTZY0W
zB<7wUN3-79DmeYB0weuXbRuR&wJo5{Dpsnams+yq&x9|)fSXLO+pVx{TtlLp$
znzR>XyfuF&GrE_)v@xE(B)Y;N+{?mFo_LYb^B|HA)xto3;4X
z6BdXJ9BP1ha&a{$4Hm{~@`ZvNlc5wmtqm2$<03erqdESavm-JJAn@FyG^na5imO@7
z@s+RrgFNqU`sxXH#c@?Q?7PURBiucCZIEsdW!sV1IzF%=#TDXOSfITjW-rBiLz$N)
zVc>lXK1QO6_-+l7xUsJELJ06+NSk$nJzpmS-qd+=58=b#pcj6E(a2V)@(C%(GzQ_j
ze&v4e!n-+rzD;Ksu)?fWdS`>R-|Nkdd)~;GIC%}RSR>iH2Ke%tSUf@}o|KA@s
zAYLgKtF}cy;PZjcjg$CuaZ$zLdG1Wi-kGS>tBxJ``7KXGlz>vB)wF*EUuv?ws*U=E
z94kC6bc%U#us=O$tr-d+g+2f^^=?}|;mu%tzqyQ%1J*t7c(g9VktK9XD%6tbkra|*-kd#k9w>_(bpiOcr7&~
z7)85+!jCezmALomru&9!Zh`752u|9Evh#`Dh`#L&kt-B6f^$lx`)The!m_}y(-CPs
zR}*ZGy20odZycH7U`z8EwH2H}GO|Ikpfc<88{oeX@-&J!15_085){eW8n`wBCPcW*
zuOqj59I!L=x;YPL{0j2xPZ;#PwJ3eoFwg*q`HM)o6Bio(1=|i$Ji+1>O!y`;GpAYT
zgs)10ujoZr3aH`C-|`xumvNq02p|qi4V^kXR2J0SHLHEB%hd`|+DT=HF~(}a1~Y*;
z$Ur(!9)BcSxlGaRUko1<@3{R7L`QsJ*X<28^~Iw0N20s%qWsXYMZ?4?N)I+-v+kAo
z8Md;IMw~nwsOy10`IkZF;1JJ)slr6yXgsOr>!E%bS{eO+)%6xoRc_D!Fen|;-5pAI
zOP6$acStuJ3F#0H(%s#Hba!_MDBX>8{Ey!I{R!9i-RnGSJ!d_inLWE_$IOP{KvWFc
zcTJ_QY9QxJj!Bbg((YjFk;OV3=P8h2E&LRP?X;86DStCVOaXRsID=yJ(rE`wgBq;E
zXGba!@baZG{G!sWc?$fUvN~7Q(e`kMQ@j&YYMtG2pP+dS0barex$`&oz)wiI^bN1r
z#+|ck`&^lB2xS764b1tGxK-Z{R&NU%4@JG*F&ew!qu55uIQN_~c!beR&nUY_qxSam
zx{-?%3t61`pX!W(JGfKXvQ-yw82d)2r4XFKC%8c0@@<7u3aS6!Qwqje9H(xB?
z@zL+%d*+3n{L~#5Tw|-y_T$Lg7a}aAn8NM%k-^>aCuC;v$!q&d{9t*(5A*#cI4D$5
zAfwHU!_c`8Tv-*0s*$C1oZ7Jv_n;a=8&Kz92ZySyzo?Xh+B;rmnyBKz4Dt{7FneP+u;G&>_3O
zGlKt~J^gT`v1$>v#O~E?Q+WGwO_Tw`fPn&CkmJsoEYyf#haJj|;B3tz~
zM#zgNE-JDaR9-wWy*9kEc)bnUjl%t9L;L%va~d`#Ko4&g<&j=OQ=`P@jS-K&gvmQJ
z67Zs>9vhj}xYxC)5V5bjWrZ+nF!zE#S2b2;s(IAQ9KGh7Xt?wS&O|Sc$(?yV7Sw*9
z*OAT$ro0wB8um=$I7>YmO0Ii+7~Ok(VfX4We1$h$IJT@;zD+DVhNcq{CrwQu_CQ8M
zomPse3!vX8tC541Rbk>{D8Dk`A{v-XYujyyuf=3N2-rHVq~<5=q&n`$=KqK#dQ%fR
z+IKgPExYE(?4{dngP|9^8pcF^tcb3My1_7bjKOrS65WE?J!|qHhWovC
zgZRl3bqf`hp6ZD=hJd`Cbwf=V7L`ozm*Fp=R)DxSkeV}92%cF5JdrEZoX+k()(#$)
z&K3riK0gPnZ9(R)_WV4K8iHOofj&y3=+4ETG%~=88H;`#i}X8aFFC~jH0+kQGq&})
z2q_Hdz9}Sw)EdQ#py;hAk7XC_e3j!G8wrzDL^irdju981I3Rz*&t-Y9f&TBr$6
z8~|)488GZxi3;DrUzsein-EwBE+PU8Zu6yGNY)w$7OQ?b%vZ2DHZ(Hz6tEXsOpaHs
z`^>H$n77+qo>eAUo9xj5OlxL`g}P@%U7e2UnqM`A*sWN5mt#QE4c9mo5I5xU^n}xk
zh@G+Sg%P+Eb}?E5atDaCAtzL-OZ3^VHv#+2{+wFIx}|g7uN$fbL-21Vgz1`Uc)i>v
z?eLrR-z7nI+GCtwOGQ@dR?4{Y0KeUG{Oq*)R;FzB?TbAmoDpwj@9xx0gTkw;5Y9As
z${BWcX^x0Oy4ec+sLf9smD!&VDWpgIhHg`SLif>i4!;>TLxR!R)~*WsN!n5_vt|Ow
z(-908>rEtyx_|JWH&+Hopbq%M=Y}@h_EEm})NOP3KCOyMKGY%1c
z88>0n;j86-=Hl%qn2D-mlXI!%>Sgs7``6X3S;{nt
z6FR;hyCS-ROuLIjywnz***V@KvMm~&`j7O4sTr`~^(WVc0?gfXP#HsYX3~rS4~BlZ
zpBYm{x;>U@mq-)3v=k)LBlJyYZL#;7P>@=O2m3qw+czzFm#3zCnsN7}YD;!aH@M1U
z$W{jiUSs=cxpGs}?8w_%kbLzwOUAW@7an{_HHbQ8f`TXNR3B7rYAvlht*C3a@+?%a
zyLmjvX{9o5zO+tNA0fcM_Khe4R9{2DMyLI#E0=eW$5qc!9NDAi3jogcKpK-1fd!LS
zKa7Nc4(U`WmfpA-nb~*JFU7=e^FXl=JS1!H7I8F8REZI>dFY2+=DkQ*{lR?fB56=M%)nD0qj
z+u9WRQUbO_uAZ<~=KxB_3xQmr0C$-Cv|M0|i@qeeF9k6rBhK6%17Bgv`}_%&npxz5
z+(1j1(VW0ZHWB(jm&~$0fZjOns{_(nMPX<)O^l#5aZaZoPG$R=z>%<(+lJnYou11b
zj|urTd1I_zHN~ZsLkUD3o}YFe$SVoP)c%}OVsa!hW5RPC6<7-xL{5A)-x5gqN-%uV
zbxr9P+;%Cy(0__ks<;BvA!b9%IfYe3&P(ldi%|?n@=AHZJfQuN6M&QxT+tkg#+H&|
zA+qXEbkTmqN^y*j=DOS&cWMJV{OZPuE|+u~Q?LTQ&TDOR3I(}*bexicACle>1nuB7
z$HyY_p0AO!8I?3^8TW=8y2#CrsxGWc>JEWr`Z3V#8bRry%zH7y9$y^V=+L+dWHf)rDJbe#1OR=V*!!X~CATSxt18t8=SC0CVe
zdWGvrB-`6^`ML2IaCYJO)Veznqo{Cju%#31&BJqmb89ureE=!BB`c&f1AJ?HPG6OB
zLsnhV69$bHSIHlb6lrK;l#?gM82;tNNeyAOsZP8brQEsOYdfC$^ntGAbb`%Y;_6ho
zWD~wO;5Ny-06As!_(c3$niT-
z540QqC=b#4bWn#|+!oT=aWrGv+VzX-^sQ;}&MWLuqOBD)1Fx7Zxs&4^WPY?Bv-uCB
zl~-FP`(0RbU13c(q~$H>J@NB*(Aw&{lV{taWDhR4?2u8(5+`!+WhLevUu?-CTNCjB1h`bmHO^
zcoQ2y=N-s3&1F(FpEBd#qYUpJ7Jzsjq1`}
z)P58&=cqauyN&G&*%0wYqqatF)aqq!BJ40eK$U84Mj}00!Le6a$!uZXxRsz8U8$-Q
z{M|ICCP034Z{{T``>gr~Q4w7)xr9^6JP?Au52~OMvkvj00bR(;)HO{V>S}7Hm-`)2HgQj4>oXZ
zv*-=DTKfe|!u$+*$6T{-RVrv)itV-T0Q)K_3n>KhI40$z^^KwfmOx7y*J|;D#@9Ja
zdIc4Qsk91`W`+1Yn812N%=fU>V6QTrJw|(g`?MT^QgnT?pG&9
z(Pg=AQ`JdQr`nL@$J!!ObRU}J&Tzt5^20_fvJak?o^tc_l5D@ovvA{kRoT`OL@GD#}E-C;9>tl1ue-
zU@f)eST<+2=7V?JH?D)GpYLggeRRU780cpB2?vd)k1(a#rg@oCRFpvlsUjmPu%Zbw
z(yC>0ur$q9Wt)ap?4}j>F24tG?pG>H?*W@^8<#ryyNXr}!XUVW+yFmZ0rULJz)iK0*&N(!~r5f)zqK)7=GD29hQ3
zZK{6otOfFTR)ioC7#K|znv8lo#7RFY_KRYdg2}IV?
z?-2Jxnw!z47yR?3GF^9
zo#5P$U?limkc&}R+Y3sh4&Yg8h7i3XD>L5{3ceI0ZE(Vf;?I@berQ`@db;jA|kEHJ}rb$0HhKs0_$!myuopTu4YbO
zj!%ais2Ca7B&$)44U>jQq!rP9weHrf;9P|Bsy&fw@N-b@~z7FhfAFR-Zn>Qz>+M1i4$3pWJRKvh0AoU
zBI1WOT%961F9Wo!j*>67d1V;Ud1X?Ug@%6ewn?8e0Uo2NN%Mj%cto{l
zW&oREzI}VfeNJk@&K$>UzTnEIo~1zU!4O7Ghq-il{^EW7!U
zo8%@SR5@h81)v}%JFJqchsE@b1PVz9kUNq>l9DIqS2HKt$jiU51>-!~f$y{bkpc8s
zaT9`*|2%yof1IN-H;o-g!%awrL6AchP}3(Sbwi?&7S@0fqJ~+z3t`&d&MT)Zj}A>i
ztg*37>;3^|{rUb7U{fl6nCEC*FL&l_y*h}pu4lP?5{Im;^
zn&IiC&F#28-8jG`;6LjLYahq-2tjtyAb(q6WT3~)!NAzsgwEB$zz$fVhyCU?^}wi<
z3_VS)41?6We#vQ>k^XgB+TqvzLo#0=pQ~A5Kq>=@r%INpf$xhaCuLXMdl=t=T*7U^
z0mJh}0BU$D=nt~Y2KosOAvqYC7@wvBa=PGizetY9D&iqx$v|3I?UUnlj2TmoykoqB
z{jM|Us`o8kL0eia{hr|Am20~_N&H!r!BQ!0qYeQr`sbdn3VCc?-Hno(w
z&B4gv^7@Ce;2=^$CWIVTooY4gyXb9p{|d`k<-qZhykfkcmV#_V)F0vO{WP)*lxs1R
z)||p<=5CX^?Lfwv8zS?{QW$IsCFUVc?Nu_l=I;~5WY}zEzNki6s*Fo7?iXbep(?Qf
z5ddo@KSj39t4*x}M;K8;Op#)RDHIgW9Z1cRlXNM^C8M@=rd4Y~H4PIEPljldGzVAZ
z$Hy*f9G1xYR{AU|2*zsBCrPz=QC_lL4l!O@y2r3
zJ^xN@X@)k$IX5mmEvwLh%|En_Sve&X-M`X9WKFb}czQu)6KjjLA#4e2tH8y2}TDP>td^MGo8t$Qiko&k>rQ7_O8%vi1v>RZHIqivCt^g=$
zmDOFZHEs%#46K}V0eSbp!KqF_If)2&jmA1D4W}ZG;CjgUkOgwFm=!t)ROo4ek?8?X
z3oYm?5Q;a*5Ock&4L^D-1B-)cjpK}ey5SiJuX8dGZ0K7ySHFq+@g6tvLdsPlci5r1
zXxHU-fO)9NGG&Z6g7;LFYGKrvs}pe5@Aml;V-Et8ZQm=0p_43UnoTL5>=8{wPJl7z
zrt)Ci%Jb_&I=Rd%51X%RF{jAkPPJ~T)oz0kPL9}6UuF_=>SuDtnE3s5>4%jEz6UN;
zEM4vkdpPdWkKdPB)io6CP<*MZ??vAI9Ey;B?X1{}b7FbPB@(T^Sht8XPf<7wgws
zYpe7%p8h8P>$q`T$y|sxLowu2u2gb=&ECq4HB6v7ub2Dj&3q_5|OaraR%A#4)qQ;y)4M^$sqj~
zNA)Kg-%d7m98X_z?73Ifik#@YpY?T&3vu)xd0}t6O2z@G>zP=8ElHK;Pf^upBL!c1
z1^cA)h?3#E;g;owhuBi1Ta@F%?yJZ_I|E+oit0wS=&
z4|*(JCQ>&mNl0jSzw4Wzd3Pxe~RX|qctc^WS$=&nYeQv5;Sry
zcOF!8A6e2@WfK363N4kdn6L5sp^xXfz{A5&4lstbZ`8F0Qr&n8H3mg5wV0NCahhmy
zHLkxBcH-N1*`dAf@BIc^1I;kf6;&0b4;|U1A<1>ki3P+@_<3QYEJps&DP$#6k1g`!
zwdxmF=qA9ZeKAcNhgdAHIL79p)mm&uYtlLNF7&j*FH(|BZ)^}li+WDy@xsm7YWJg;
zX_YnJ$Gc@<~X$65*to^^e+Fy!l95X
zx~c}BspEi!X3lVkBCL`LedLdl0F0rBe1i)C|;|b1(~4XNgUvTkoR#lf+EBG_|MT
z>zT5NDO37nQCHT)+Nsm!KS|u^hsS*^9ZfcL)7KO;3#BU{1p?e=`E_Db)gOD=o2=
z-K!iJim`+$lC1kVHz(%BBrtt^Pm&JvH<854$Whw**a%BVW&Q^>E
zQimSH)4$@Wo|fj@&SB<;_7AZ`E~k}Yo61T+IZe2xR(JMil&fThqs`Dv)*N0})>1)p
z5+*kT)Z$_LsFOO(P<0X+qm?Sg`{_9ClN4}&4yTA!pM8nOgJbtn5yp~Zw-cY(vpWS`
zIk<6IsO*<;nn_$-LX^CcD961JuBydc@zd4RM@RftDGWIa=VCQSK}1tnU%WziSnQUu
z!WVAoMnputZEGDJip1s>5H&xRw8xa)bx5TNVAbm++@C&%<)5yQlS*H4tiSi;-?Zf0
z!P{RWa8(jUefj22`(QWwP&(ZF3Qo`JO04J5Qz3WvlibjE%=xO$=pBs3kuZxvVhkar
zYPFFn@%Cgv!7jTaM$Cq?%a%qu!l~0i;fAQN+i+Z3PU-u7Ws;NQ1#URx>@?v1J183p
zKx?N*B{du?wlz0zX+DE>sE{sm0vonU1sm6?-b{3rib{WQJw8=v^?})5ut`!EIn7R6
zRd<%Nnm$!)&$p``BrmV5=DNIkzhT-8S(l$@WJ?ZVHj5M0i
zOZIr)jh8RSn#iyFT36vN2rc3>V-kMck`?=`p-4vgxvw
z;yXGc`0j=KnSP9~oymiy7Sb)`s8qbxu$MDsOOT4di$lNS*fOq(_5bwjz!js_CtF@(
zwJ?`_FG1dYKyKN2fSJ|gK!IUMVAB{zwM>)X%cmniapvyRt+VRbYHo-pjMn2>bGboY
z3}!$&s@QKvu0s@n++Qw>6_EK{uhrGD!fHfI3rjKR^jxI%!hMlHcNwD@%9!8y_`)xn
z&fB=e_q478essqtUFmyWh~sS09$^mCDzW?4s}xvz`o$-MXtqz;rNu$t&>&ZSFceK%=iC4VC?=9MSz0VoeouK>;rn8$Yz$^?9VHWJ4FBbZ4fS9t
zO5$K7Ha&$d0S+$H=IEv6p<4|`B_3+D4kYx4;J1o-#y
z_oNn>MTlu<((<^y#k?Mp`;ShdV2us)v_=jaUp=dlg5^6;m!-)?OBCxtHL?`6qs#HD
zM#h*!0gIea0akL8^4LDIv*QZf*lSrs@WD!|`mx}C@*;L()yCjJ98`h0@u8S93LEh|
zoCoBVE68y2z|jZlRnHkHs$_Iv=~grE(MD7J#q4xcI+&E(YqAI~9RE9}5ALw=%pz|F
zaZCVQFh8tI}9zUp0%Cx
z<3h7bR;kq4&fNx@+4G}@wwn!__3aZt$L+-~ZC0+}`0g=LWArjLSJ_;(NCs~d?XlGa
zn&B_xsn*d&RLFF4tsC%Tr@i;MPUffPC|us89=q+JdnF{zN0_PFm;WtK8e#GTYWA3-
z!D@0<6)?XWZEt8^yTV$d`9nii7|9tTk;aMo@>S%JM~18PRA_(?`fj9wz<^)0Tmc7_hLvLGu(r01?R*qcN
z%5Z%=L}h(Yz7YBn-*VZuV|i)3te#=s*g#iP0Rv8UzP~2q@=+n{Gx7(fMQA-?O9kV*&nXl;+NnIkt1nimTq4(9&vk?rQjbt=
zg0Up*TUt3u(ggXNBiVx?sF+B{QXw)4oGH%nMK`8i@>-i!g^G*V59YgtOID?3hRL8%
zn7U9mQYpAt<&d;WjE?9S>Zd)J$;-a4H{_N=h+Ap(S~pIWB`HGM(@8%;woA1@9X(Dt
z=Vgdwcx#hh{Z)L6b^1*Nsm4Yyyi5UI
z7W>|29RO+qDj-#z@1G_>1=!KdIL+4o60Dw?+o$*zhK3}Dl2Qhjsr}Qo4KmHy0B3mEA+3sYL(=z#
z?S8(Z&AjZDIdzf?lyNe#*if~x#T_<*>Ma$c`pQkh{fvrAWnRmcgaC=hTu!?_7R|HW
zj(Mz>371)m0C8GRAlJ8Z8k3EI$=%e3@s3qJN9RioXbKjRogs0a1NGun}e2470RToWhdhw&NEsaic^%MlLBB;WWC5FRYXo30OT&g0(#kRyt
zZ$IuTU%YC+=ZDd;rwoD3!BL!bXR*H98oG-snS2v?lHAbE_zmz#X-<#7!`_j-ojYbX
zd>+=$%*PhCxr)j6?xi+IT!}%Ibqp(WFoU)qfcT?Pzzq1oI!%s*oD1032>b1otP3aq
z?_^>=`uT3Y2`89&C$Ge;Jx|oEmip4#lNd)(whs2|RY#FI7Si>b4C8~bVEM*cXnAD-
zaK{P=XH3S|oST3vh*K|A3jU8OX(2GB&Y>=_7B;9#DE$PBBoS!!D#mv4+a}SSd=ueQ
zuTVx^Lf((bhOdtaoxl%?-q177Jq+#yad#^&r0r17llM248gbOoFM(?_MXZ6FS_lLN
zq3{QZN2hdR_alG~IqApNSj0#mPS{|`i)`}zTXmuTy@IB?xL)R2_x;(G^{K*96_ttl
zw71Xm8-afMpQq&R8M#mBz_X?>SJw~z#F-M(W2YLZVSu3mGg~SDEX-~EcR3E`U-3ZD
ze*=(CpOEFXG#%~8(CFFgVHqj9DzqxMgFk536AT6P$V-F2KnMHN_<)3M
zm^}YuA|t9SNGB;P2D18lj{3j5cR`mA*e==hp`BoBzi2>~^0&V9*;rIFP9u19aIB
z?q5Xae#WNRAjmZ6`L%lbC#XXGCXxk5{)_0@^%#FBKyTd8{}TPWErWpSNzOgH7vULA
zGVH%JFwFmW9r$m;o_W7~M!JLbKT@IpZ)ceQW%b9|Bp4XWGgkB1zgcm?5dW3j|8ouo
zDsj4JM8QPAiGn(ao+kDGe1>6zfzdw0Gm!qqr*z{##c%DaI~IX(-#`!PGduy^Z+rm+
z(qBUT@!IfTB53;GM5$fSz}s%brxE?nzV(6z42<|$M0jlf(x5)Y=ejdCsQ#+FprMQC
z8QxpsH~y{@rvkM%EU8HG5!6@2^y)ngBoL;{d%4{%*2=
zb|FC1#XoU_-l#!G*Yo-Q%H3@;#8Yulu}FjRgXtN;ur<)v2_LB2j}QN(sREBjeu-dY
z`_IR!zboILrAN>q&1W1t-vd`XsQ(gySWI*mdgr`~jY)bqL
zpWyNv|IZ8=_o>)1!@s1a_xSfa)>D4MVkQn@gw#AjSn0peu{rKlYWLb
z_5F=^9in}T7r-)q?1csc3j%f2e9!O@0l>_Dk*9J375aV&N*Vr}(Wky=5!bd=I3|F~
zsR&eWpEIJ40%negJdO0(hjBzRBZbQtD-(4h1+f^vZQ8GJ1T1SbP7
z*8djaDb2d!G}Q`-#uk*pzplvp6S&iX_5)(i#4Q>6mAP(NAZDaM#waM@@zC@1cn$sn
zkbMD4mXHD)2A?GcnA(KV1d53m)ZxAP6AkF?wh4r%|GQ<6{pJSV2HYPMd?rWb=&xv|
z+kwNQZ=WXS|8yV_)8~C^K_~EjjEwdl)#QIF&{O3GG@LvM*PTEneOyd=X-H62`IVW>
OV0s`GNU`hJzyAkB&5uTbAgTXDSzuJR*;U+N+4yyFSJ5~A2
z08%SM>4AE5}
zs$B+DIi{JI5OBB(O+P_^-ws5ny!=%rfCB+gseV>f*{)(pRNh@x7h8f$6{7OheoS2Je1_O#1Xo<9?JB*gH1jY`3?p7)TQ2R3HoLYqUPd`tKQxL!kz
zpMYWWiEj;V;M%!dAW;vYXYU1<2!E`lKl$Oif8cZ#{OQD{8LiZ#0TEdF^3q?D02>b$
z2@*9eTUYJ0Vz@rwh2#iYOP8TD<_R
z_+M}iu~Yn%xVYBF%Wc2Ip-JhtD0ByBf$iNB0kE2rTffVcN6<4n6)-ke82__2Q)uZA
z{zs{`q!Z?Wp#68P;T`F3kAedM{eek&z~TkSI-#25{k6}gus!-i^zVm-QzSxcqd#KhG;+A*I)X9K)8B91r0+4tf|G#b(UM
zVk8*Z@5o8-$4B@e_zTjVUg;4$GsU7*ib@y`7^vTf7HQLnJICQ#qH@ozG^silgc#{M=>}Zb6u?L?BOr
z`-jX6)gnEboqATOC#EE%I!yz@UHzSvHF~c?E4woz(!f`%Bu#6o)uk!7%*>sg!-4vv
z*JgB!(d^ko7*~~-P2YanY(=CgkY~71lU%Ar)kHzP{);syaH9-5D|a^X;~5q&_x`J+?n}Sahqjc>
zO_b!%Erj{CSJZS1h~9nI@WORv+jA1Q)(7%$6+XB;$*nd^6vM|v%qu22
zn5WLXEQX&D@D$uTnnlrcr}n9ps0lIGwO=HYU2C^iu;`#N{Tqo
zd|iUJ>vj2FlmR@+3VQeJmO6F*7bg?EU_ubJT4=Cdxe_;gS5MRqwOU^KkpZ&7oR
zPL*b8$jpZj0AJZVXC2|^hvOwOToO<4c%mfh{zyn?sD|7T5`WvGCWv7P{(d3o{t;Ec
zujS|UC_}454DXJ~&yZfh$n1HX*};Dx6=$-xnK6RbRGzlm(8qyNO5c$8CFHVgx9vlhrn9W>Y-3k$mr7#O
zFcV#L^1TxN=S?sJZy=HM4_16Yq!bcjr)*E*v^Z<0f&9FN^Y~=tO;c_#(4ywoQSVWMhT&Ls)DDy
zlX|1eQY+DfF)r*!7N0N$uzXN~BaAsZcJ>1)h&@zw_QNSi8nqPf#veU1`|-mYzi);!
zj68}__M;AG9A6A;7`azh{>g?j#LU@8y2xSnlRb4Dzt6+!#~pvW_aAho3@0497v=V*
zjP8L!h}DYGah?D;>1}IKb%mSLD7ltbZHI`@I=e{@CdsCJi;@mMv8oQIJY|eaMx0fY
zQ@WaFppi*9SaG)5DYL?EQsXeeo}pjkx5|yL%6V$grn`ZEQc#Q+;1T5R@w7D<*?trY
z9G}0M+iJ7+#eVZ
zEZMgc-5ar8GT@4D@tUqh);!bt%x!6DyYuoEcFF=I+T`SO;t@(cx-lF-VY_=+37@Kb
z+VdYQC46_OQtjm3<~;}M)=?d$JAd0b_n?Ejt&v615j{|H-6?iaoJj!_2XpHok+7wu#SuDH6k=IU($#Kk;h#JhqnGSyQ>l!xVtYu
zEa9>AT~p13C!5X%PknMyL#!2s$w0B?>T6X
zD&9v&gVR0AtQTWZVUPAY)Vx=nf58b_N;K015ZA!Imqi;!J=^vcAI$Vvc5b}OqYbDt
z2UP&HyHgZi$z<2{#F_h@L=D|a-t(gOj}d#{OGFbS9wgBLLj~%!$Li>SK|}ObFUj-^
z23{jHm+~4+uov56C*TIyqvqfc_sqh=x^7-=7JXCg{a4G+LUo$cl=2gb45^(`5qz(-3s_zPX3L1hdIsk;6+z{D1ll>s
zkF)~}>m0dsU+E#4>?v%ydyG-CV}=QM#onPjdAFJ;Jv-uBYbS7m6Ma=TT7!E2y%j#P
zriFp<9dGvm@Ia}4*P5CWagR;6BfeGCpA3}+H@kEAMhz?CYk29`tr&b;zgj&XC1-rKehjN^ed=-}zk<-0qxHYD#;
z_c%4Z-Rt3Sm7f2=qYc>gk|CY7cm-f=&my?tx^_AH_;NY`h0-nt&1u~Om?h@;YmaBj
zu}7ly=-UgfmPQkP!pYxZyE{YBLt~2hwrSDji%2uUNrNk58J()Zr<(8x>kQ6~XymRX
zK&HAO6d2A015`99h_aHp+nG6Wt~WlsI?X>6oXq-!>$PyX#cg99fi8-y5ezWGWdFhO
zS5{GZu46fi1&0(HYIS3HR
zO(=_MY>E{{$0Lx%gB}PfagEEW>QcH};cu;9PrYT6^%xUPdsTES;yEQ&;*-8-S7Hrv
zMpO^!wG7(t;iIJdM6rLnU!Y1^6Iff;l^BPJpACyV;YTOSQA~CA^9Q(r>bpjv)-Fy$
z=ARtXd7Q=9zPREEp)#|j@Z`~XU{2G&&$0AFZ81kt=UbUrlrxLc>8Dyg#A3?tWBd{D
z+YsF+G6V-+vR%O_ZZktc%y7OG`P2_(y~-MUWl>q}CF`}yH;I$5@=om{c>ALKZqX&s
zaTDjQShyIRaCAO-|6=4_c%#C@C-+#sLkc5etr@L%!c7oAN@Y4Q_Tm>H=VOOd
zTa2X;{n)5)wfD9g6U;A5Vnq~s>nVHtj|`}V?Q;eF&G1%WVM&!n5}wB&S!yUU=1)0)
z(U=u^6WixEqxHJ$P9;C^J7T-YL#{8_{QW_SXp<-)TP`5ku+FO$;+;zre;J0qCBhTx
zrv$vq3&6j7(i)FQYx6^!`uo57f3CguU0hTkplfO%AfkUwJw}QgJ0bwq5ACE)kg{iU
zlWv$6X=ut;jKn*F69)-iI&lLj@t%q3(#$hC_L}r|E?KNjCq`zqUrBdSqc*{WUR_yw
zfoj9Xzx}nSt*vcU!`AWYrmyeqb#MEV<_%!s!I@)*bi_FDZE@89NG`Juh1ds4B>qbOm%p`liR`;TM|JzdXTs
z*V7%idZ`D_pFDwh)u?*82d0N$j$M{nCzdNy)gr^3eR|hDvr+p64HZ1PwiK*OOUee$
z9ltEuLEVS-Dj%)^)tx*9?2*mSE~$Zg!8)qHlZ0)XEwuyHo!tQ29LAvUAs1>KZVzR=
zf2e$P%4O4py#RpPoO_0ffb7pa1S7uf-n&G9-_RW}aERATfA^~9BO_B(JJAW@Hd#=QHOa_@1PbsWZ|9}XfIGk8(<&QyxV;A>g);73v}rm+GYmB
z$Jt(Ta5{Fk7FD?~kCm_HaI)7qcDae}mbb};&1PKnJOi>L39f3b+fXcOUBQ>%|9H_^
zUohLo5J(F@+GhDBd0AE@8D%fxDY~t>Q9L`1R9;A*@9s(zmv0h`$N;$ZP-8}3n3nB2
zqU7N(oDY}kboJdQOOfpppia6RU^#xz4HhrQ?kSO_v3X+K&O|C>!eCGS=HV~jZeHzF
zw&FVkNd!FAv6+^)MPDQ@B`jVYvvYTCnCoWtzC1JzvNdhSV$)Yy^(1YSnkw-jAzmcW
z`wXStxmB!RvZTnd>T}09k|0YFLXpGmvf#{=j=HtiKblBDv^sd-G57Aj+1qgwdN^m9^@$f4prG6ROIH+!3)Rij-hT0Jge(iv>!#j_|R
z#a_a5g~J*|J)b5VDB7qoK<^?EN`{zZ6>OfpOCp7k#KEkYP_?lmJ)TdtY)ttOr0B7V_N`tdh^x5PSK%dCQki=25q*X&
zKrZE6G>rIEmhHBD6mSWE{dcpd79?i$xdFM`G}=AWN&NV+FZvQzmMVTNt!}NYl&cWV
z)nfRJzruYcWG;}mm%%5!XpmX#yb@S_dg2nzLvN4)BSC0t%R7gOHPxDmWT(Uy?Fp?p
zoF*eoiI&CGR_wf{-DxsdCHhRsUz6Opw^EA3FzW&jM*
zbI(TOP);154e2ClT0BKD;)YV8)T2p3a2boORxy)KrN_h?C1MNu~ss=eKel#tA7S$)@(9yNqDBLICu9EGA7
z9p-|4%$#nc5wL2@6+-&v?O1N~qYtK3i&D0@Xe|Z|?b|HN@Ra-K^cokoNKEL$R1@k{
zT@XtvMnUeHw5x3R8cLBmJBH47I0j?dC}#f9QPb&a@7}1WUOIFJx~Ye!L#vq-Jz-0G
zbLXnU8N$)(bFWQS`O?#KFhFLY$Wxt1?wjU2H=t;Vh`(gX{TVy0zQ|VHCzL?_LZY7_
zc3jPAs(8M-HOE2e!sk!zP>*_lkfYiM#a_w%+3#bEG{-|-^&h_d=$nrbnOV?U>2rVK
z6UN7kLh<@!sPnZpclAnDw4dfF-wzHjkK52(CvapR;lpk9{*Zy{Ckow>&U1=%;p6a^ecCN?<~b2S@{7{Yv!yM6`Kr1;
zN{j5Xm|9D>8*E(BtS9}iGuz!LE({%i9J*b~Uc5&2vO$eJ0zkx8_DWrLR;V*dF)1Eu
zI(c?}pw&evMC``((sWzA7+>{8cA6CVsDT2!I(@Wt*JycobF~JobovNOmU2q8Qh4rd
z?WpL*WBr;3+Ju$6M;wQZ(1|2?Ttby!B%$UzbXo!0IN@o)^_pl_3q#VvCz*dWpOB#H
z2b5sh=kP%W)qt~z?qcT^;`|fYjOs7CJ7gM3
zb%C*Y>M#AY0ZJn}0(@KRXq_5kVB;(og)4&Uv(|X8VvUq@UxPzTwI2b&)Tk}xFg(=-
z^BRvawSXi;lq!St(==m@DGVQ)fhk`l)ks0Ibc1O*T!2Ai)fZ?M$LFyvNBQF)FB+6~
zQGRa}@FrcyNGu-}r}D`zEfW+4$&oC44hY}pO!CFdA-q9D9up2uVq~fZGk3U?yeYxo
z>*zm8Q-Y@jm0zj>pr-r^G0_A6{q%<~>O|^1XD0K5{OS
z5+!FltgazXVlD08PTt{8np3OF&*$?;0scU6TFs+^lpOM
zwiN3zw+pRXF@eQ6kwd7an_*Fnz9JL0K<~}zFu-m>=Oea5o2tfKAKBBz#j#x8)#iu<
z$Lo+147Q-f>WU~=)PnIk-rOk+xTW8WKE&LN(*7DFM(_`;{@kfKWfxr5QF4D`{5=#b
zMMndJZLmbuZKH$qM+gFBdB2kmn4@);Ua}lPe%7_`u(O8W&4RzQvULjWo*!3}n~uH*
z9sr85sRfV8GIcE>zo5^gim$2OVfkBwk90ir5M3aZB_(dr0ajAXFd{Gg#&w43a$B-z
zT)lvVbMkjNi?snXs?R~Q^4LW8wxwPWS}vY2`LKe*>YVXb)KB-T8DDZUTvWwjju{~h
z==)*_J;@u45ojqk&zyquML2i&2`!1HEI^{c+IQoDtN(gMlSq>l#Om|3#BL>Tnu~Qa
zk$QtDm>`^Wp6eqGQ%f#b;l+oJK$IHOIW=43(goV+Otw(KSeIozQPh(#Mbdq0tTYFs
z-Qd&ARpx$jrwL5a%O#D}Q_sje!bAZM{miW9P&0OUcmAz-HMOYdSw89c4>?}W4dALU
z%~a&HQkHx&W0Mzmk^pz9jAl8j!YmmbJC_@ntV)-milf8g?^zOS;nOr0ve7e
zpUYY2qmq&^R^Jt`0+NFK>xqgqioTDFKA$n0L@X5xD-bJ#
z#k0=Ed=jn&hXs1(V%No^xF=6X6JU^-GrqgFYO-yxF{Tpr(7YO#zABK^nb{@)k)=nt
zLX|KLSy=%5LZ&-9vwlpIz&{)2#4GMigxhvoF*o^!GJeKOVQ>fcf}+*;-W{LH>mgTD
zKnVOK1kH*Tk2A}FfarxOjGl4!
zwoqppD6n97!tlQ1{>hj!>aT#3nd5Q#3YiMX)`z7(YlTnLsPRhw0K|L=?=OB@4Vv)~
zJfnYL8oGumG|)p~JTL3r^|3Kj%IPd9TH3+WEU`OYIS3MR{rD(dR3sC()D}%zb%hIfa~k>H;~EqlzJX1eqgMFliz(JCL{tgZEw?lVI@#CyBwbF^LROZq>5^9(I$_d7
z5Memb>y>U4Yqqv~FE(|y(GOI&&0;=B)3kjgETarAtK1>$aGj6s5bOVUtJ9jIKxe12Ju_Ak|d
z@K;=%;@j%xC6o&2aGBt2u@CMLuG>D$;jK*V4{rRS0f6;~%!O%X0WpGa-F1Yx(Ww9G
zmTU^(aSE7`*oAw4=I%X-anc6AS_*g$$@XGoyyCAolYaJF=eT*h_sutOTB05RWdJ|_
zixkOYN$8CTui~sLepn66#!0=fIzdFivNudA48Me(o~l4{>~!IcTuCyXPZWgJH9{DhV;aSRu7}piWSDpMd`O~7V^{A`e1r{Otb4wC3r!Pru7SgFjmsLz
zfo))KbC8klBi_zUlGfl#n5YQX!(S4(X8?*;U#yWAIE61d^))-$SB5q63R+Qmpgy!k
zpZq}R1}YLk@&dn>E5$bq0#Z_j9v8%{0H@9XP@X2
zU>*citc@&NxCX2{f}@a2or0^h>0Pk!
z>U^|cRriY%YeHKuM*&2j=gZ0P2CR#*CT)HZ#_cEPXFM+c?EvfIi}BlVYX;W{Uz$B2
z6Z@s{ERmMH!s@}2`a^hfQ*-vav85&F^WtvU)AgQv?)T*!pC5-CU2$4s )cGA>G#LHBO`Ec5TW_Iv!(>21z9hnv4#Zg
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