From 213e00b69a1c4d365e3b1ed35965d30935c33ec2 Mon Sep 17 00:00:00 2001 From: ThisIsLibra Date: Wed, 15 Jul 2020 15:01:27 +0200 Subject: [PATCH] Version 1.1-stable --- pom.xml | 2 +- src/main/java/concurrency/DownloadWorker.java | 149 ++++++++++ src/main/java/endpoints/GenericEndpoint.java | 18 +- .../IEndpoint.java} | 22 +- src/main/java/endpoints/Koodous.java | 21 +- src/main/java/endpoints/MalShare.java | 24 +- src/main/java/endpoints/MalwareBazaar.java | 18 +- src/main/java/endpoints/VirusTotal.java | 61 +++++ .../Error429TooManyRequestsException.java | 30 -- .../java/exceptions/HttpConnectionFailed.java | 31 --- .../exceptions/SampleNotFoundException.java | 4 +- src/main/java/malpull/ArgumentHandler.java | 171 ++++++++++++ src/main/java/malpull/Arguments.java | 139 ++++++++++ src/main/java/malpull/Downloader.java | 35 +-- src/main/java/malpull/MalPull.java | 259 +++++++----------- ...Pull-1.1-stable-jar-with-dependencies.jar} | Bin 2476404 -> 2482455 bytes 16 files changed, 689 insertions(+), 295 deletions(-) create mode 100644 src/main/java/concurrency/DownloadWorker.java rename src/main/java/{exceptions/Error404NotFoundException.java => endpoints/IEndpoint.java} (64%) create mode 100644 src/main/java/endpoints/VirusTotal.java delete mode 100644 src/main/java/exceptions/Error429TooManyRequestsException.java delete mode 100644 src/main/java/exceptions/HttpConnectionFailed.java create mode 100644 src/main/java/malpull/ArgumentHandler.java create mode 100644 src/main/java/malpull/Arguments.java rename target/{MalPull-1.0-stable-jar-with-dependencies.jar => MalPull-1.1-stable-jar-with-dependencies.jar} (95%) diff --git a/pom.xml b/pom.xml index 59cca3f..ee9a43c 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 malwarepuller MalPull - 1.0-stable + 1.1-stable jar UTF-8 diff --git a/src/main/java/concurrency/DownloadWorker.java b/src/main/java/concurrency/DownloadWorker.java new file mode 100644 index 0000000..4ae1acc --- /dev/null +++ b/src/main/java/concurrency/DownloadWorker.java @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package concurrency; + +import endpoints.*; +import exceptions.SampleNotFoundException; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; +import malpull.MalPull; + +/** + * A worker class that extends the runnable interface, meaning it can be + * executed as a thread. This class tries to download the given sample from any + * of the endpoints in the list. If it fails, the hash is added to the missing + * hashes list in the main class. + * + * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + */ +public class DownloadWorker implements Runnable { + + /** + * The list of endpoints iterate through in an attempt to download the hash + */ + private List endpoints; + + /** + * The path to write the file to if it is found + */ + private String path; + + /** + * The hash of the sample to download + */ + private String hash; + + /** + * The number of this worker in the queue, used to print if the sample can + * be downloaded to display the progress to the user + */ + private int count; + + /** + * The total amount of samples that are in the queue, used to display the + * progress to the user + */ + private int total; + + /** + * Creates a worker object, which can be queued for the thread pool + * + * @param endpoints the list of endpoints to attempt to download from + * @param path the location to write the file to the disk + * @param hash the hash to look for + * @param count the queue number of this worker, remains unchanged after + * creation + * @param total the total number of samples to be downloaded + */ + public DownloadWorker(List endpoints, String path, String hash, int count, int total) { + this.endpoints = endpoints; + this.path = path; + this.hash = hash; + this.count = count; + this.total = total; + } + + /** + * Downloads the sample to the given location. If the sample cannot be + * found, the hash is added to the list of missing hashes, which is printed + * at the end. + */ + @Override + public void run() { + try { + //Add the hash to the file name + String filePath = path + File.separator + hash; + //The boolean to check if the sample has been downloaded + boolean isDownloaded = false; + //Iterate through all the endpoints + for (IEndpoint endpoint : endpoints) { + //Try to dowload the file + try { + /** + * If it is already downloaded, the iteration loop should be + * broken to avoid more API calls than are required, and to + * move on to the next worker in the queue + */ + if (isDownloaded) { + break; + } + //Get the sample from the endpoint + byte[] output = endpoint.getSample(hash); + //If the output is not zero bytes + if (output.length > 0) { + //The file is written to disk + writeToDisk(output, filePath); + //A message is printed for the user + System.out.println("Wrote " + output.length + " bytes to " + filePath + " from " + endpoint.getName() + " (" + count + " / " + total + ")"); + //The boolean is set to true, causing the next iteration to break out of the loop + isDownloaded = true; + } + } catch (SampleNotFoundException e) { + /** + * The exception message can be ignored, as failure to + * download the sample results in the missing hash, but only + * if none of the configured endpoints has the hash + */ + //System.out.println(e.getMessage()); + } + } + //If the sample is not downloaded after the loop, it is missing + if (isDownloaded == false) { + //This method is thread safe + MalPull.addMissingHash(hash); + } + } catch (Exception ex) { + System.out.println(ex.getMessage()); + } + } + + /** + * Writes the given byte array to the disk to the given location + * + * @param output the data to write to the disk + * @param path the location to write the given data to + */ + private void writeToDisk(byte[] output, String path) { + try (FileOutputStream fos = new FileOutputStream(path)) { + fos.write(output); + } catch (IOException ex) { + System.out.println("An error occured when writing the sample to \"" + path + "\". Verify your permissions and try again!"); + } + } +} diff --git a/src/main/java/endpoints/GenericEndpoint.java b/src/main/java/endpoints/GenericEndpoint.java index 7e27406..0b85f13 100644 --- a/src/main/java/endpoints/GenericEndpoint.java +++ b/src/main/java/endpoints/GenericEndpoint.java @@ -31,15 +31,31 @@ public abstract class GenericEndpoint { */ protected Downloader downloader; + /** + * The name of the endpoint + */ + public String name; + /** * The base URL of the API, to which specific API actions can be appended */ protected String apiBase; - public GenericEndpoint(String apiBase) { + public GenericEndpoint(String apiBase, String name) { //Sets the apiBase variable this.apiBase = apiBase; //Initialises the downloader class downloader = new Downloader(); + //Sets the name variable + this.name = name; + } + + /** + * Gets the endpoint name + * + * @return the name of the endpoint + */ + public String getName() { + return name; } } diff --git a/src/main/java/exceptions/Error404NotFoundException.java b/src/main/java/endpoints/IEndpoint.java similarity index 64% rename from src/main/java/exceptions/Error404NotFoundException.java rename to src/main/java/endpoints/IEndpoint.java index 672854f..2ec9c39 100644 --- a/src/main/java/exceptions/Error404NotFoundException.java +++ b/src/main/java/endpoints/IEndpoint.java @@ -14,17 +14,27 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package exceptions; +package endpoints; /** - * This exception is used when the HTTP request returns a 404 (Not Found) status - * code * * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] */ -public class Error404NotFoundException extends Exception { +public interface IEndpoint { - public Error404NotFoundException() { + /** + * Gets the sample from the endpoint, based on the given hash + * + * @param hash the hash of the file to download + * @return a byte[] that contains the file's data + * @throws Exception in case any error occurs + */ + public byte[] getSample(String hash) throws Exception; - } + /** + * Gets the name of the endpoint + * + * @return + */ + public String getName(); } diff --git a/src/main/java/endpoints/Koodous.java b/src/main/java/endpoints/Koodous.java index 17677ba..4ed64f9 100644 --- a/src/main/java/endpoints/Koodous.java +++ b/src/main/java/endpoints/Koodous.java @@ -16,9 +16,6 @@ */ package endpoints; -import exceptions.Error404NotFoundException; -import exceptions.Error429TooManyRequestsException; -import exceptions.HttpConnectionFailed; import exceptions.SampleNotFoundException; import okhttp3.Request; import org.json.JSONArray; @@ -29,7 +26,7 @@ * * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] */ -public class Koodous extends GenericEndpoint { +public class Koodous extends GenericEndpoint implements IEndpoint { /** * The API key that is used to interact with the MalShare API @@ -43,7 +40,7 @@ public class Koodous extends GenericEndpoint { */ public Koodous(String key) { //Sets the apiBase variable in the abstract GenericEndpoint class - super("https://koodous.com/api/apks"); + super("https://koodous.com/api/apks", "Koodous"); //Sets the key variable this.key = key; } @@ -54,14 +51,10 @@ public Koodous(String key) { * * @param hash the hash to look for * @return the sample as a byte array - * @throws HttpConnectionFailed if no connection can be made from the - * current machine, or to the given host * @throws SampleNotFoundException if the sample cannot be found - * @throws Error404NotFoundException if the target returns a 404 status code - * @throws Error429TooManyRequestsException if the target returns a 429 - * status code */ - public byte[] getSample(String hash) throws HttpConnectionFailed, SampleNotFoundException, Error404NotFoundException, Error429TooManyRequestsException { + @Override + public byte[] getSample(String hash) throws SampleNotFoundException { //Get the SHA-256 hash via the search function of the API, as only SHA-256 hashes can be used when downloading a sample String sha256Hash = getSha256Hash(hash); //Return the API's response @@ -81,7 +74,7 @@ public byte[] getSample(String hash) throws HttpConnectionFailed, SampleNotFound * @throws Error404NotFoundException if the target returns a 404 status code * @throws Error429TooManyRequestsException if the target returns a 429 */ - private String getSha256Hash(String hash) throws HttpConnectionFailed, SampleNotFoundException, Error404NotFoundException, Error429TooManyRequestsException { + private String getSha256Hash(String hash) throws SampleNotFoundException { //Create the url String url = apiBase + "?search=" + hash + "&page=%1&page_size=%100"; //Create the requested, based on the given URL and with the required header token @@ -97,7 +90,7 @@ private String getSha256Hash(String hash) throws HttpConnectionFailed, SampleNot int count = jsonObject.optInt("count", 0); if (count == 0) { //If there are no hits, the sample is not present - throw new SampleNotFoundException(); + throw new SampleNotFoundException("Sample " + hash + " not found on Koodous!"); } //Get the results if there are any JSONArray results = jsonObject.getJSONArray("results"); @@ -115,7 +108,7 @@ private String getSha256Hash(String hash) throws HttpConnectionFailed, SampleNot * @throws Error404NotFoundException if the target returns a 404 status code * @throws Error429TooManyRequestsException if the target returns a 429 */ - private byte[] download(String hash) throws HttpConnectionFailed, Error404NotFoundException, Error429TooManyRequestsException { + private byte[] download(String hash) throws SampleNotFoundException { //Create the URL String url = apiBase + "/" + hash + "/download"; //Prepare the request with teh API token diff --git a/src/main/java/endpoints/MalShare.java b/src/main/java/endpoints/MalShare.java index 990a336..5cbc48f 100644 --- a/src/main/java/endpoints/MalShare.java +++ b/src/main/java/endpoints/MalShare.java @@ -16,10 +16,7 @@ */ package endpoints; -import exceptions.Error404NotFoundException; -import exceptions.Error429TooManyRequestsException; import exceptions.SampleNotFoundException; -import exceptions.HttpConnectionFailed; import okhttp3.Request; /** @@ -27,12 +24,7 @@ * * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] */ -public class MalShare extends GenericEndpoint { - - /** - * The API key that is used to interact with the MalShare API - */ - private String key; +public class MalShare extends GenericEndpoint implements IEndpoint { /** * Creates an object to interact with the MalShare API @@ -41,9 +33,7 @@ public class MalShare extends GenericEndpoint { */ public MalShare(String key) { //Sets the apiBase variable in the abstract GenericEndpoint class - super("https://malshare.com/api.php?api_key=" + key + "&action="); - //Sets the key variable - this.key = key; + super("https://malshare.com/api.php?api_key=" + key + "&action=", "MalShare"); } /** @@ -64,14 +54,10 @@ private String getDownloadUrl(String hash) { * * @param hash the hash to look for * @return the sample as a byte array - * @throws HttpConnectionFailed if no connection can be made from the - * current machine, or to the given host * @throws SampleNotFoundException if the sample cannot be found - * @throws Error404NotFoundException if the target returns a 404 status code - * @throws Error429TooManyRequestsException if the target returns a 429 - * status code */ - public byte[] getSample(String hash) throws HttpConnectionFailed, SampleNotFoundException, Error404NotFoundException, Error429TooManyRequestsException { + @Override + public byte[] getSample(String hash) throws SampleNotFoundException { //Gets the URL String url = getDownloadUrl(hash); //Create the request based on the URL @@ -90,7 +76,7 @@ public byte[] getSample(String hash) throws HttpConnectionFailed, SampleNotFound */ if (temp.contains("Sample not found by hash")) { //If the sample cannot be found, an exception is thrown - throw new SampleNotFoundException(); + throw new SampleNotFoundException("Sample " + hash + " not found on MalShare!"); } //Return the sample return result; diff --git a/src/main/java/endpoints/MalwareBazaar.java b/src/main/java/endpoints/MalwareBazaar.java index 851d3fc..9911b33 100644 --- a/src/main/java/endpoints/MalwareBazaar.java +++ b/src/main/java/endpoints/MalwareBazaar.java @@ -16,7 +16,6 @@ */ package endpoints; -import exceptions.HttpConnectionFailed; import exceptions.SampleNotFoundException; import okhttp3.MultipartBody; import okhttp3.RequestBody; @@ -28,7 +27,7 @@ * * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] */ -public class MalwareBazaar extends GenericEndpoint { +public class MalwareBazaar extends GenericEndpoint implements IEndpoint { /** * Creates an object to interact with the MalwareBazaar API @@ -36,7 +35,7 @@ public class MalwareBazaar extends GenericEndpoint { */ public MalwareBazaar() { //Sets the apiBase variable in the abstract GenericEndpoint class - super("https://mb-api.abuse.ch/api/v1/"); + super("https://mb-api.abuse.ch/api/v1/", "MalwareBazaar"); } /** @@ -45,16 +44,15 @@ public MalwareBazaar() { * * @param hash the hash to look for * @return the sample as a byte array - * @throws HttpConnectionFailed if no connection can be made from the - * current machine, or to the given host * @throws SampleNotFoundException if the sample cannot be found */ - public byte[] getSample(String hash) throws HttpConnectionFailed, SampleNotFoundException { + @Override + public byte[] getSample(String hash) throws SampleNotFoundException { //Get the SHA-256 hash via the search function of the API, as only SHA-256 hashes can be used when downloading a sample String sha256Hash = getSha256Hash(hash); //If it cannot be found, there is no such sample if (sha256Hash.isEmpty()) { - throw new SampleNotFoundException(); + throw new SampleNotFoundException("Sample " + hash + " not found on MalwareBazaar!"); } //If the sample exists, download it return download(sha256Hash); @@ -71,7 +69,7 @@ public byte[] getSample(String hash) throws HttpConnectionFailed, SampleNotFound * current machine, or to the given host * @throws SampleNotFoundException if the sample cannot be found */ - private String getSha256Hash(String hash) throws HttpConnectionFailed, SampleNotFoundException { + private String getSha256Hash(String hash) throws SampleNotFoundException { //Create a new request body for the HTTP POST request RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) @@ -90,7 +88,7 @@ private String getSha256Hash(String hash) throws HttpConnectionFailed, SampleNot return jsonObject.getJSONArray("data").getJSONObject(0).getString("sha256_hash"); } else { //If the status is not OK, the sample is not present - throw new SampleNotFoundException(); + throw new SampleNotFoundException("Sample " + hash + " not found on MalwareBazaar!"); } } @@ -102,7 +100,7 @@ private String getSha256Hash(String hash) throws HttpConnectionFailed, SampleNot * @throws HttpConnectionFailed if no connection can be made from the * current machine, or to the given host */ - private byte[] download(String hash) throws HttpConnectionFailed { + private byte[] download(String hash) throws SampleNotFoundException { //Create the request body for the HTTP POST request with the form data RequestBody requestBody = new MultipartBody.Builder() .setType(MultipartBody.FORM) diff --git a/src/main/java/endpoints/VirusTotal.java b/src/main/java/endpoints/VirusTotal.java new file mode 100644 index 0000000..d165538 --- /dev/null +++ b/src/main/java/endpoints/VirusTotal.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package endpoints; + +import exceptions.SampleNotFoundException; +import okhttp3.Request; + +/** + * + * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + */ +public class VirusTotal extends GenericEndpoint implements IEndpoint { + + /** + * The API key for VirusTotal + */ + private String key; + + /** + * Creates an object to interact with the VirusTotal endpoint, based on API version 2 + * + * @param key + */ + public VirusTotal(String key) { + super("https://www.virustotal.com/vtapi/v2/", "VirusTotal"); + this.key = key; + } + + /** + * Download the sample from the API + * + * @param hash the SHA-256 hash of the sample to download + * @return the API's response, which is the raw file + * @throws SampleNotFoundException if the sample cannot be found + */ + @Override + public byte[] getSample(String hash) throws SampleNotFoundException { + //Create the URL + String url = apiBase + "file/download?apikey=" + key + "&hash=" + hash; + //Prepare the request with the API token + Request request = new Request.Builder() + .url(url) + .build(); + //Return the value of the direct download link + return downloader.get(request); + } +} diff --git a/src/main/java/exceptions/Error429TooManyRequestsException.java b/src/main/java/exceptions/Error429TooManyRequestsException.java deleted file mode 100644 index 501e774..0000000 --- a/src/main/java/exceptions/Error429TooManyRequestsException.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package exceptions; - -/** - * This exception is used when the HTTP request returns a 429 (Too Many - * Requests) status code - * - * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] - */ -public class Error429TooManyRequestsException extends Exception { - - public Error429TooManyRequestsException() { - - } -} diff --git a/src/main/java/exceptions/HttpConnectionFailed.java b/src/main/java/exceptions/HttpConnectionFailed.java deleted file mode 100644 index fe4edb5..0000000 --- a/src/main/java/exceptions/HttpConnectionFailed.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package exceptions; - -/** - * This exception is thrown when the HTTP request fails due to either of two - * reasons. Firstly, the machine where this JAR is executed from, has no - * internet connection. Or, secondly, the target host is unreachable - * - * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] - */ -public class HttpConnectionFailed extends Exception { - - public HttpConnectionFailed() { - - } -} diff --git a/src/main/java/exceptions/SampleNotFoundException.java b/src/main/java/exceptions/SampleNotFoundException.java index 76e98b2..07c00fe 100644 --- a/src/main/java/exceptions/SampleNotFoundException.java +++ b/src/main/java/exceptions/SampleNotFoundException.java @@ -24,7 +24,7 @@ */ public class SampleNotFoundException extends Exception { - public SampleNotFoundException() { + public SampleNotFoundException(String message) { + super(message); } - } diff --git a/src/main/java/malpull/ArgumentHandler.java b/src/main/java/malpull/ArgumentHandler.java new file mode 100644 index 0000000..6e208be --- /dev/null +++ b/src/main/java/malpull/ArgumentHandler.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package malpull; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This class parses the given arguments into an Arguments object, thereby + * simplifying the code in the main function, and splitting the sanity checks + * from the rest of the code + * + * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + */ +public class ArgumentHandler { + + /** + * Parses the arguments into an Arguments object. Stops MalPull upon the + * occurence of an exception and prints a help message for the user + * + * @param args the arguments to parse + * @return the parsed arguments + */ + public static Arguments handle(String[] args) { + //Only 4 arguments are accepted: + //java -jar malpull.jar threadCount /path/to/keys.txt /path/to/hashes.txt /path/to/write/samples/to + if (args.length != 4) { + //If that is the case, the usage should be printed + printUsage(); + //Then the system should exit + System.exit(0); + } + //Test if the thread count is a valid number + try { + Integer.parseInt(args[0]); + } catch (Exception e) { + System.out.println("Please provide a valid number for the thread count: " + args[0]); + System.exit(0); + } + //Get the thread count if its a valid number + int threadCount = Integer.parseInt(args[0]); + if (threadCount <= 0) { + System.out.println("At least 1 thread is required!"); + System.exit(0); + } + + //Get each key per line, sanity checks are performed within the loadFile function + List keys = loadFile(args[1]); + /** + * Initialise all strings as null, only changing the value if it is + * included in the keys list. Only if the value is not null, it should + * be used later on + */ + String koodousKey = null; + String malwareBazaarKey = null; + String malShareKey = null; + String virusTotalKey = null; + //Iterate through all keys, note that the endpoint prefix is case insensitive + for (String key : keys) { + if (key.toLowerCase().startsWith("koodous=".toLowerCase())) { + koodousKey = key.substring("koodous".length(), key.length()); + } else if (key.toLowerCase().startsWith("malwarebazaar=".toLowerCase())) { + malwareBazaarKey = key.substring("malwarebazaar=".length(), key.length()); + } else if (key.toLowerCase().startsWith("malshare=".toLowerCase())) { + malShareKey = key.substring("malshare=".length(), key.length()); + } else if (key.toLowerCase().startsWith("virustotal=".toLowerCase())) { + virusTotalKey = key.substring("virustotal=".length(), key.length()); + } + } + + //Create a new set to store all hashes in, as a set cannot contain duplicate strings + Set hashes = new HashSet<>(); + //Add all hashes from the file into the set, sanity checks are performed within the loadFile function + hashes.addAll(loadFile(args[2])); + + //Get the output path as a file object. The path is filtered for the home symbol + File path = new File(filterPath(args[3])); + //If it does not exist, any missing folder is created + if (path.exists() == false) { + path.mkdirs(); + } + + //Return the parsed arguments + return new Arguments(hashes, path.getAbsolutePath(), threadCount, koodousKey, malwareBazaarKey, malShareKey, virusTotalKey); + } + + /** + * Loads a file at the given path. The program exists if the file does not + * exist, if the the given location is a folder, or if an IOException occurs + * + * @param path the path to load + * @return the content of the file, one line per entry in the list + */ + private static List loadFile(String path) { + //Create the output list + List output = new ArrayList<>(); + //Create the file object based on the given path + path = filterPath(path); + File file = new File(path); + + //Perform santiy checks + if (file.isDirectory()) { + System.out.println("The file at " + file.getAbsolutePath() + " is a directory!"); + System.exit(0); + } else if (file.exists() == false) { + System.out.println("The file at " + file.getAbsolutePath() + " does not exist!"); + System.exit(0); + } + + //Read the file, line by line where one line contains one hash + try (BufferedReader br = new BufferedReader(new FileReader(file))) { + String line; + while ((line = br.readLine()) != null) { + output.add(line); + } + } catch (IOException ex) { + System.out.println("An exception occured when reading " + file.getAbsolutePath() + ":"); + Logger.getLogger(MalPull.class.getName()).log(Level.SEVERE, null, ex); + System.exit(0); + } + return output; + } + + /** + * Replaces (if present) a starting tilde with the user's home directory + * + * @param path the path to check + * @return the corrected path + */ + private static String filterPath(String path) { + if (path.startsWith("~")) { + path = System.getProperty("user.home") + path.substring(1, path.length()); + } + return path; + } + + /** + * Prints the program's usage + */ + private static void printUsage() { + System.out.println("This tool downloads samples from MalShare, MalwareBazaar, Koodous, and VirusTotal based on given MD-5, SHA-1, or SHA-256 hashes."); + System.out.println("The sample is written to the given output directory. API Keys for any of the used services is required."); + System.out.println("Once all samples are downloaded, the hashes that couldn't be found will be listed."); + System.out.println("For detailed information on the usage of MalPull, please visit https://maxkersten.nl/wordpress/projects/malpull/#usage"); + System.out.println(""); + System.out.println("Sample usage of this program:"); + System.out.println("\t\tjava -jar /path/toMalPull.jar threadCount /path/to/keys.txt /path/to/hashes.txt /path/to/write/samples/to"); + } +} diff --git a/src/main/java/malpull/Arguments.java b/src/main/java/malpull/Arguments.java new file mode 100644 index 0000000..7ce60e6 --- /dev/null +++ b/src/main/java/malpull/Arguments.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2020 Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package malpull; + +import java.util.Set; + +/** + * The argument class, which contains all relevant information from the parsed + * arguments + * + * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] + */ +public class Arguments { + + /** + * The set that contains all loaded hashes + */ + private Set hashes; + + /** + * The folder to write all samples to + */ + private String outputPath; + + /** + * The amount of threads to use, minimally one + */ + private int threadCount; + + /** + * The API key for Koodous + */ + private String koodousKey; + + /** + * The API key for Malware Bazaar is not required, meaning any value will enable downloading from this service + */ + private String malwareBazaarKey; + + /** + * The API key for MalShare + */ + private String malShareKey; + + /** + * The API key for VirusTotal + */ + private String virusTotalKey; + + /** + * Creates an object that contains all parsed arguments + * @param hashes all loaded hashes + * @param outputPath the folder to write the downloads to + * @param threadCount the amount of threads to use + * @param koodousKey the API key for Koodous + * @param malwareBazaarKey the API key for Malware Bazaar + * @param malShareKey the API key for MalShare + * @param virusTotalKey the API key for VirusTotal + */ + public Arguments(Set hashes, String outputPath, int threadCount, String koodousKey, String malwareBazaarKey, String malShareKey, String virusTotalKey) { + this.hashes = hashes; + this.outputPath = outputPath; + this.threadCount = threadCount; + this.koodousKey = koodousKey; + this.malwareBazaarKey = malwareBazaarKey; + this.malShareKey = malShareKey; + this.virusTotalKey = virusTotalKey; + } + + /** + * Gets all loaded hashes without duplicates + * @return all loaded hashes + */ + public Set getHashes() { + return hashes; + } + + /** + * Get the output folder where the downloads should be written to + * @return the path to the output folder + */ + public String getOutputPath() { + return outputPath; + } + + /** + * Get the given thread count to use when downloading samples + * @return the thread count + */ + public int getThreadCount() { + return threadCount; + } + + /** + * Get the API key of Koodous, can be null if the API key is not used + * @return the API key + */ + public String getKoodousKey() { + return koodousKey; + } + + /** + * The API key of Malware Bazaar does not exist, so this value is either null or not null. Exclusion from the keys file means the service wont be used + * @return a value to see if this endpoint is to be used + */ + public String getMalwareBazaarKey() { + return malwareBazaarKey; + } + + /** + * Gets the API key of MalShare, can be null if the API key is not used + * @return the API key + */ + public String getMalShareKey() { + return malShareKey; + } + + /** + * The API key of VirusTotal, can be null if the API key is not used + * @return the API key + */ + public String getVirusTotalKey() { + return virusTotalKey; + } +} diff --git a/src/main/java/malpull/Downloader.java b/src/main/java/malpull/Downloader.java index 0f35c51..0d30bac 100644 --- a/src/main/java/malpull/Downloader.java +++ b/src/main/java/malpull/Downloader.java @@ -16,9 +16,7 @@ */ package malpull; -import exceptions.Error404NotFoundException; -import exceptions.Error429TooManyRequestsException; -import exceptions.HttpConnectionFailed; +import exceptions.SampleNotFoundException; import java.io.IOException; import okhttp3.OkHttpClient; import okhttp3.Request; @@ -56,11 +54,9 @@ public Downloader() { * @param url the URL to contact * @param requestBody the request body with the form data * @return the data that the API returned in the form of a byte array - * @throws HttpConnectionFailed if no HTTP connection can be established - * (either because the machine that executes the JAR has no internet, or - * because the host is unreachable) + * @throws SampleNotFoundException is thrown if the sample cannot be found */ - public byte[] post(String url, RequestBody requestBody) throws HttpConnectionFailed { + public byte[] post(String url, RequestBody requestBody) throws SampleNotFoundException { //Create the request object based on the given URL, where the given request body is also used Request request = new Request.Builder() .url(url) @@ -71,13 +67,13 @@ public byte[] post(String url, RequestBody requestBody) throws HttpConnectionFai try (Response response = httpClient.newCall(request).execute()) { //Check the return value if (!response.isSuccessful()) { - throw new HttpConnectionFailed(); + throw new SampleNotFoundException("Sample not found, HTTP status code: " + response.code() + " for URL: " + request.url()); } //Return response body return response.body().bytes(); } catch (IOException e) { - throw new HttpConnectionFailed(); + throw new SampleNotFoundException("IOException in Dowlnoader.post for " + request.url()); } } @@ -87,33 +83,20 @@ public byte[] post(String url, RequestBody requestBody) throws HttpConnectionFai * @param request the request to send, which is already addressed to a * specific URL * @return the data that the API returned in the form of a byte array - * @throws HttpConnectionFailed if no HTTP connection can be established - * (either because the machine that executes the JAR has no internet, or - * because the host is unreachable) - * @throws Error404NotFoundException if the returned status code is 404 (Not - * Found) - * @throws Error429TooManyRequestsException if the returned status code is - * 429 (Too Many Requests) + * @throws SampleNotFoundException if the sample cannot be found */ - public byte[] get(Request request) throws HttpConnectionFailed, Error404NotFoundException, Error429TooManyRequestsException { + public byte[] get(Request request) throws SampleNotFoundException { //Make the call try (Response response = httpClient.newCall(request).execute()) { //Check the response code if (!response.isSuccessful()) { - switch (response.code()) { - case 404: - throw new Error404NotFoundException(); - case 429: - throw new Error429TooManyRequestsException(); - default: - throw new HttpConnectionFailed(); - } + throw new SampleNotFoundException("Sample not found, HTTP status code: " + response.code() + " for URL: " + request.url()); } //Return response body return response.body().bytes(); } catch (IOException e) { - throw new HttpConnectionFailed(); + throw new SampleNotFoundException("IOException in Dowlnoader.get for " + request.url()); } } } diff --git a/src/main/java/malpull/MalPull.java b/src/main/java/malpull/MalPull.java index c0db147..1837f26 100644 --- a/src/main/java/malpull/MalPull.java +++ b/src/main/java/malpull/MalPull.java @@ -16,15 +16,18 @@ */ package malpull; +import concurrency.DownloadWorker; +import endpoints.IEndpoint; import endpoints.Koodous; import endpoints.MalShare; import endpoints.MalwareBazaar; -import exceptions.Error404NotFoundException; -import exceptions.Error429TooManyRequestsException; -import exceptions.HttpConnectionFailed; -import exceptions.SampleNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; +import endpoints.VirusTotal; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; /** * This class is the main class of the project, and creates and calls all @@ -36,190 +39,136 @@ * class around the OkHttp3 library that is being used to perform the HTTP * requests. * - * To compile this project, use : mvn clean compile assembly:single + * To compile this project, use: mvn clean compile assembly:single * * @author Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl] */ public class MalPull { /** - * A variable that is used to debug the program during development. If set - * to true, the argument length check is skipped, and the parameters are - * instantiated based on hard coded values within the main function. + * A list of hashes that could not be downloaded, taken from the + * deduplicated input */ - private static final boolean DEBUG = false; + private static List missingHashes = new ArrayList<>(); + /** + * Build using: + * + * mvn clean compile assembly:single + * + * @param args the command-line arguments + */ public static void main(String[] args) { + //Get the start time + long start = Instant.now().getEpochSecond(); //Show the version information printVersionInformation(); /** - * If the length of the arguments is not equal to four, not all - * information is provided. Additionally, the debug flag should be set - * to false + * Parse the arguments into a newly created object. If the arguments + * cannot be parsed properly, the error message is displayed and MalPull + * shuts down. */ - if (args.length != 4 && !DEBUG) { - //If that is the case, the usage should be printed - printUsage(); - //Then the system should exit - System.exit(0); - } + Arguments arguments = ArgumentHandler.handle(args); - /** - * Initialise local variables which are either set based on the given - * arguments, or based on hard coded values when debugging - */ - String keyMalShare; - String keyKoodous; - String hash; - String path; + //Show the input back to the user, as this helps to avoid mistakes + System.out.println("Read " + arguments.getHashes().size() + " hashes"); + System.out.println("Downloading will be done using " + arguments.getThreadCount() + " thread(s)"); + System.out.println("Output will be written to: " + arguments.getOutputPath()); + System.out.println(""); - if (DEBUG) { - //The MalShare key to use during debugging - keyMalShare = ""; - //The Koodous key to use during debugging - keyKoodous = ""; - /** - * Sample hashes to test with: - * - * Hash for MalShare: 78f29761f7f0f57a8f92e5f23d9e4d2d6465e848 - * - * Hash for MalwareBazaar: - * 094fd325049b8a9cf6d3e5ef2a6d4cc6a567d7d49c35f8bb8dd9e3c6acf3d78d - * - * Hash for Koodous: a24f14c4b95994d8440ed8f1c001a6135706716f - */ - hash = "a24f14c4b95994d8440ed8f1c001a6135706716f"; - //The path to write the sample to - path = "/home/user/test"; - } else { - //Get the keys, hash, and path from the command line arguments - keyMalShare = args[0]; - keyKoodous = args[1]; - hash = args[2]; - path = args[3]; - } + //Get all hashes in deduplicated form + Set hashes = arguments.getHashes(); - /** - * To get a sample, a try[ServiceName] function is called. This function - * uses the respective service's endpoint class to check for the - * availability of the sample. If it is present, it is download, after - * which MalwarePuller shuts down to avoid using more API calls than - * required. - */ - tryMalShare(keyMalShare, hash, path); - tryMalwareBazaar(hash, path); - tryKoodous(keyKoodous, hash, path); - } + //Get the thread count from the parsed arguments + ExecutorService executor = Executors.newFixedThreadPool(arguments.getThreadCount()); + //Keep track of the count so each thread can print what number it had comapred to the total amount of downloads + int count = 0; + //Iterate through all hashes, adding an endpoint for each of the configured endpoints + for (String hash : hashes) { + count++; + List endpoints = new ArrayList<>(); + if (arguments.getMalwareBazaarKey() != null) { + IEndpoint malwareBazaar = new MalwareBazaar(); + endpoints.add(malwareBazaar); + } + if (arguments.getMalShareKey() != null) { + IEndpoint malShare = new MalShare(arguments.getMalShareKey()); + endpoints.add(malShare); + } + if (arguments.getKoodousKey() != null) { + IEndpoint koodous = new Koodous(arguments.getKoodousKey()); + endpoints.add(koodous); + } + if (arguments.getVirusTotalKey() != null) { + IEndpoint virusTotal = new VirusTotal(arguments.getVirusTotalKey()); + endpoints.add(virusTotal); + } - /** - * Tries to get the sample from MalShare using the given API key. If it is - * present, it is written to the given path and closes MalwarePuller. - * - * @param key the API key for MalShare - * @param hash the sample's hash - * @param path the path to write the sample to - */ - private static void tryMalShare(String key, String hash, String path) { - try { - System.out.println("Searching MalShare..."); - byte[] output = new MalShare(key).getSample(hash); - System.out.println("Sample found on MalShare!"); - System.out.println("Saving the sample to " + path); - writeToDisk(output, path); - System.out.println("Wrote sample to disk!"); - System.out.println("Exiting now"); - System.exit(0); - } catch (HttpConnectionFailed ex) { - System.out.println("An error occured when contacting MalShare, verify your own internet connection, as well as the uptime of MalShare!"); - } catch (SampleNotFoundException | Error404NotFoundException ex) { - System.out.println("Sample not found on MalShare"); - } catch (Error429TooManyRequestsException ex) { - System.out.println("MalShare reports that there are too many requests with this API key, try again later!"); + //Create a download worker for the hash, with all configured endpoints embedded + DownloadWorker downloadWorker = new DownloadWorker(endpoints, arguments.getOutputPath(), hash, count, hashes.size()); + //Execute the download worker in the future, disregarding when specifically + executor.execute(downloadWorker); } - } + //Once all tasks are done, shut the executor down, meaning no new tasks can be added + executor.shutdown(); + //Wait until the executor is terminated, which only happens when all downloads are finished + while (!executor.isTerminated()) { + } + //Notify the user that all downloads are finished + System.out.println(""); + System.out.println("All downloads finished! The sample number count is not always printed ascending as the threads print the messages."); - /** - * Tries to get the sample from MalwareBazaar. If it is present, it is - * written to the given path and closes MalwarePuller. - * - * @param hash the sample's hash - * @param path the path to write the sample to - */ - private static void tryMalwareBazaar(String hash, String path) { - try { - System.out.println("Searching MalwareBazaar..."); - byte[] output = new MalwareBazaar().getSample(hash); - System.out.println("Sample found on MalwareBazaar!"); - System.out.println("Saving the sample to " + path); - writeToDisk(output, path); - System.out.println("Wrote sample to disk!"); - System.out.println("Exiting now"); - System.exit(0); - } catch (HttpConnectionFailed ex) { - System.out.println("An error occured when contacting MalwareBazaar, verify your own internet connection, as well as the uptime of MalwareBazaar!"); - } catch (SampleNotFoundException ex) { - System.out.println("Sample not found on Malware Bazaar"); + //If some hashes could not be found, these are printed + if (missingHashes.size() > 0) { + System.out.println("\n\nMissing " + missingHashes.size() + " hashes:"); + for (String missingHash : missingHashes) { + System.out.println(missingHash); + } } + //Get the time since the start of the downloading + String time = getDuration(start); + //Display the time that the download process took + System.out.println("\nDownloaded " + hashes.size() + " samples in " + time + "!"); + //Exit the program explicitly, as it sometimes remains open in some edge cases + System.exit(0); } /** - * Tries to get the sample from Koodous using the given API key. If it is - * present, it is written to the given path and closes MalwarePuller. + * Gets the duration from the given starting point until the moment this + * function is executed in the format of hh:mm:ss. * - * @param key the API key for Koodous - * @param hash the sample's hash - * @param path the path to write the sample to + * @param start the time to start in seconds from epoch */ - private static void tryKoodous(String key, String hash, String path) { - try { - System.out.println("Searching Koodous..."); - byte[] output = new Koodous(key).getSample(hash); - System.out.println("Sample found on Koodous!"); - System.out.println("Saving the sample to " + path); - writeToDisk(output, path); - System.out.println("Wrote sample to disk!"); - System.out.println("Exiting now"); - System.exit(0); - } catch (HttpConnectionFailed ex) { - System.out.println("An error occured when contacting Koodous, verify your own internet connection, as well as the uptime of Koodous!"); - } catch (SampleNotFoundException | Error404NotFoundException ex) { - System.out.println("Sample not found on Koodous"); - } catch (Error429TooManyRequestsException ex) { - System.out.println("Koodous reports that there are too many requests with this API key, try again later!"); - } + private static String getDuration(long start) { + //Get the end time + long end = Instant.now().getEpochSecond(); + //Calculate the time difference + long duration = end - start; + + //Calculate the amount of seconds + long seconds = duration % 60; + //Calculate the amount of minutes + long minutes = (duration / 60) % 60; + //Calculate the amount of hours + long hours = (duration / (60 * 60)) % 24; + //Format the times into a single string and return those + return String.format("%02d:%02d:%02d", hours, minutes, seconds); } /** - * Writes the given byte array to the disk to the given location + * As the add function is not thread safe, this synchronised function is + * used as a wrapper * - * @param output the data to write to the disk - * @param path the location to write the given data to + * @param missingHash the hash to add */ - private static void writeToDisk(byte[] output, String path) { - try (FileOutputStream fos = new FileOutputStream(path)) { - fos.write(output); - } catch (IOException ex) { - System.out.println("An error occured when writing the sample to \"" + path + "\". Verify your permissions and try again!"); - } + public static synchronized void addMissingHash(String missingHash) { + missingHashes.add(missingHash); } /** * Prints the version information, together with an additional newline */ private static void printVersionInformation() { - System.out.println("MalPull version 1.0-stable by Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl]\n"); + System.out.println("MalPull version 1.1-stable by Max 'Libra' Kersten [@LibraAnalysis, https://maxkersten.nl]\n"); } - - /** - * Prints the program's usage - */ - private static void printUsage() { - System.out.println("This tool downloads a sample from MalShare, MalwareBazaar, and Koodous based on a given MD-5, SHA-1, or SHA-256 hash."); - System.out.println("The sample is written to the given output directory. API Keys for both MalShare and Koodous are required."); - System.out.println("Once the sample is found, it is downloaded and saved, after which MalwarePuller will exit."); - System.out.println(""); - System.out.println("Sample usage of this program:"); - System.out.println("\t\tjava -jar /path/toMalwarePuller.jar malshare_api_key koodous_api_key sampleHash /path/to/save/the/sample/to"); - } - } diff --git a/target/MalPull-1.0-stable-jar-with-dependencies.jar b/target/MalPull-1.1-stable-jar-with-dependencies.jar similarity index 95% rename from target/MalPull-1.0-stable-jar-with-dependencies.jar rename to target/MalPull-1.1-stable-jar-with-dependencies.jar index e593321c4156b7a7c86d087101aa5fa563aefede..497f3c9b6f02e321a34636a64d6e8ecb0eebc73f 100644 GIT binary patch delta 42756 zcmZtt1z1&0_dgE9p}V_;Lw7ewOLupNbV?sZLIG*mw9?((C5?0(QcCGYLJ|JQ+wb%I zp8LJt&2=vJd{)e?wPwwpnZ4&a34jOs0eCD;6$C_dxIY)A%UL28Jr;$_nWo(<2={9k zl$j_=37Hs2@8`yi*!nHCLCck(i4kVIgW%~|gm&t--e z4~lYz`^>=yS3)1B%z&cnJ*|E7hDR#&NI661^v5lqmQDWTn^tYzX@j&&&n=yPF2n{L z;8lo2mQ9B%k^inEa$j~%cRst`=fISUCUin^_&3l9D0~DI6ahtufFedfks_eT5m1x} zC~5>0Edq)j0mX=bVn#r*BB0n2P@D)TZUhuB0*W62C5V6$MnH)opu`bSk_aei1e7cS zN*)2Fh=5W?K&c|2)Dcjc2?HXIC~T5k%kJc z+s>Wb$Z(~gI-a6f{~%IB^?sV=gUaX5Ek!p6rd~3-uh@ zVw+SXJ&ygo==p&1K-#zGGRv<9q6xg|JPY933;DR$dC;Tr_>-d7`A%z)GnQF6uRkg= z(8o%*Pl+fr_MM$6JAriugb=xe;+(TsSJg(Lj|{1SHIp0vbI^8>{{G(QQ&ZeMz1XcV zT+ZlkAw(bUq)3BHWrjPU421N0$FK7?wQ(_|*;y4?TG^$|eAXvwGkDnz`WIVsh%fv0 zZ37z%X%cXSQ|h%(KZUoS<{F`0*5>fj^AGE!@g$mL3f1%d>{L>7hODXYf3M6{Lu)Hd zSszRR=Sg%IW@ThMDa0?2r#T%dfybx4hWygoYs5m0ddgp@tsB2n?^sT0;?`{clH$qW zAbgsT(V?jtqK`!NR#|+X8Buk4rfzg+314AIZJBuL(91}tRj(*{ zI$>Rr9yCA3CCy^21c7Qh_00`A8E6y^|A;l{3Tp%glAXDIgr&9IifqX+G4kk6v7fU*7b53lY%!KT6n+v16=5?f zk85KSGaG9y*(7Lo5eioFm+vp&<0~16tLPA6%6>L(ZG}a%Lx3f8UIq;r@|zZk5)BHMrj?_)q)mpU07F@MSfz@(R6?rE2YDKV`yCJ;^K;kFw9>zI(k!3_@^(uo< z-N;ICy%AlF1QPtit@rYytGrZ<6tO`s01- zpj_90rtP+z(db|9V}`GPw2{57?!wM5tsRm&EY*8U+IvMkvikD6NVsst`2fju$?Pq{ zi_;s%nCDh2Vfr5ec|~%@ZH4uzz$~C)=T6e%@A3L1kU=odN z8&L^?2Ahzqpm*&k2~VFUqui?18sToF6$rmT}udH88Yd8;G{g_cNI=w)D zz$DrqmwmsBH&GCpf2%R_JD@av`WY>w3J*kaQuY_pFa2rZmM}(9{+8z5I{AH*D@SM7 z5-A`~y!rdgJ?^UhpcZpHiS?U=&dBNn2v&|v%WrDPijDFJjrJup07qJb1bwZVGY8g{w4cCNx1{DKIm-kf)9NEMUZPtj;+tE-8vb=WLtxQd}8MA-tbp;jz_`PABkFq+!_$ z+5?)yF!6wAce5>%fTt7Pc4ARa5_=+V^|fmlgjKsRn$l=s@=?G?P8@1t^Z1zXRo2YI zJ4mscCRz4UPSN}W602J3BV7S{@tcK<%ZIJS>b?l*}()8dCllRx`qb0J?zeos+0{bJzE1VMrH&I#) zEPdPOA&SxqmL-2`jdm~hmlI6T8?EfTA!$U;9!YJD85fIW z8R2%K5dEHYjaRjQ*l@h2e8@Vv4I$<;(D*G#>u_SAZEojjDm9qlDNtf-CLzz zT~0byx&wZbv(+oK%(6;HDP zu5%Tvp8f{((5fvVfA!5>WDOu+Jfsiz)z|`+w*%)O?w8qwL3KLm0rv|rYw3Zri_XaB zn@Ignh9~?FcvJXH_moC?TN-x_uaiDH`{Qvr`IA9tA(K~Sb6X{o=nBb*28`IlM4>DG zyspAo{P;t@sx)EgujkJV9@M1RCWx^*Jj$-Gy~!Urn;uYd_ilE^-bF&TjYe;4X!m~g zQ&0}?15z{R?rmDDGAPOu2azRn#s?&_8q*v(xhL0CNrmCA?SVr#J`M2{O6BBKyX-0v znaFZwkbbuM0KEZc?SiF?$VjlEMfiJ;^|*Dm2JL|?VbMn2Y(`K61@AoV^M#X1^XdgFu}^WV_K9$7U4YS1v4}XqGNyPzJ7g z_|A)=eh*h)NG_v3?6mS--!|^@HIrQrGtMzgE8rvkScdYW!TcG^TLMa!o!O&8@%Ufj zt5G4(=$R?Ocoj<&#+g3E)=N`3;JKPrGf9X#wK_ORJE!pz+>^M|Rk11)t)-7mY75bNXhf2em6Z-nNgLa;@h!g&m4_NX+ z>YU7axWZ)u9;@egm&Iuj^arF)bha-7+92WS<}K?U*Xf;U*10(b1?IEp)#F<~(mQ#M zy1GHilKS%eWK4W%ujtX(J#9L1qQ}OIv7N9g6g=f=##ld2f2MQep6Hy2cI(_0UC^*7 z3IMn*zNO;3CUIpcficy{rc}q~7Am(|?URG?RH;t1H`(&$)0SpOx)$ha5UaBkj3FB) z3WCn|_#j{R1NBh@KQ~Y@8bgRVdIHhn$eSTJ+BS3s@TGOZG3rt#L`Z}8MBEM zR4_9n_vuh9o^$Lj*;*~k|4xIcWBF7dM=zZ5OnQlra%w#@$>5+=S<@2A%cnFdb?;-{ zmUZND^<7^+D^o#0*o7V+D{XMk7Sbqnq}Obxg>|obj`T|)J-)&t5XIZPyFRISX?kl# zf0FO*F9|A%?_0hPPHMx+kI$p8{pH8ZBy>aHH8@@zse7qX=Y9Js8(L@^Dex=4M0+JP zR_N*!Pyl?5n|*!@do_Kp5539S{b)Y&JUHU6o+*~SvK|u%)!r}pppa=@91rmyu1{9V z#B;XiBFN8HmEHOIbg{;|(c!XBtJ7(JlOF5X>Z`Vz`Neq`=qDAww9^RdE#FUPe-fY` z{BAHEM?5^48MhQ~^nmLe_P}Oiw@dNCmCu3aMn>EDMs{sV8cnbk>(}Q1=!iZBX)PMZ z@%RO{3$`F2K58VwcG8>~l?qwK6?vUBi@;pPBC!J}V}f!=2Z7s?)m*uitzxH<3ukjd z(c(dM4fno}HQ|1fow^e_LYp+~j!PjgPQPtOM_n!P4h`g4WGwRTJt)Ytf>I6NpD@+4 z$(ZW%?ih;;GLJ7;dHKRvxwLBXuG8D}ZcjMvM9@7SMK=bu$bJMy^azGS0$zeKeWbS9uBP83 zGGwI~$&`TZ@;gN-{tGQEy*|G@%P3IA=5wshHw=`M8CT@j zOPXGY7(}*&(03y>aJkQBx{`k?I;)F>>yS-5dSltNY~X;wt$BX9B`1Rqpm$5SYlV|G z1|mJE`v~tAes0CZLHf*1K8K?EottU3&c)apUkfwoU)TVf|a-w{euh zKdslT8g-+v3!=v{P-;cZ8SD7o4I&ugClDv-5;I*S`lqk)VYD(4Y!f|%!bSiw6_;N9}A>( zM9o$gHcF)UA{3o$?JYK0(^V6QRx_EqU-Psl8JoqRc?A2IDeShNzv}`r#6)t9Sa(!> zni36&m4PoVL?M|Yi7tA|^f*R8&enLN(h z&kljx8!0C*M=RIB{q#fN*NE9+hhHau!ngWt?3nHEVO|jPWTE!eJt8gYwxBz0MIE&J z7G3>s$O@)6AMQi-x-D|fmUe$N-9Ne>f0L&R#^IK8XXMhz6NzOYIJkGnaBw95e`e&~oREJe<4rnd8grI}q3ymW-K1|X zwshs>eb`1GdgBpg^63>QEqLockCQkyTQ9->&f`>`Vn{Nf>Hb?d=lvgT#m`pN3{41Z zw&kY`ro1Nu)HQmZ9)4o=(os7k4xV808gAwf4N`HQdU?jj{4!-P_y4q=hgkHb-L;F& z%KtYcfvO>MkKDd0uR{f&7puUIXUW?Kjqj~HfUsn%U$N*xHSm(73YX3~=rnQ9jjx5n zia!%fyVp#WLshww`%O7v5%p@N8ONo@WJ!abP;4T2oboqI&~Q3fMg(18g^*xlx^ByV z-E7sa_&n8afOm}uEl1h$(ebv)asMmbLNOvFU_o;Fei2jU>$PZ5d&BsRYR+8qZN{=~ zT;FeVO}|y-lh#Ic+c@#LN(oP6^A{~^oF}%{xSn3~FLLxBt&g5E9EyuNrh=GwwaXOZ zYy~NQ4LD(Ho@gLv0mE@WBP~pD{VRm*o!sdS)d<>JUTxL4&!Pq zM8d%WVtuVHDQBT5RlR;Ff=GkLcl!BNcS}{GiPRbMQr}| z?N(N+LXSyWs5%jvIr-!@1bHx&+DQAmk zPTrFEE1mI$g5P8p$Lix#^wsY*8|$}aA+W(Y{+ek_W1DU?i=XHm#CvF4HOEgeACk=K zZbiPDKBzKbg#s`;Gwr_}PX~n)oo^C5B;XS7B@hxj&|<_~DWb*jX@w8AmA1pzdMgc?ZzKKlGpCq3Zq+M5qwKQKOmp9MaN#OiE1Wr z!i1joJiJ$d{Z8LyPq+0d%g}>?xH7ztsc!QnyCK$F4Vyk=c3~>yo_M6G_m%e+|L)@l z3-0ilXmD^PcyMq;aBu)*h=CaL!4NH&aDnWf#bpL2ybL~O6eb<6X8pFj5i>b1H!diX z@WXuC=xGAgat<0_gNP;~+sf?9;!9TvV-x2$&D1|iMGCcpP^+q{ZfZ-anwo$voR?+M zPeL6^f>F&6p%Y@=XCY_5x^JHz&s=kZPi6+-CW)tO@q+|RqmI7qtwYEcHzmk#wz`V^ zY1}l=L$T0r%I{vgJTKi+2rk7G+OijUsEszU{e_1`Gg!symb|^Hx0bhUQ~%48=+(QfM(1b%ZMXbq8seyHtjL$P>kv30H2b zklO@xBDO)suW~Mx-tsY(-PMQHINq^#7h8$uYI@4`X}v)sTfKEH`7JZ2VbtAQIK(!g z&X{B^&^VSYj^u@2k2H9u|U)VRrKfo+s7l`xW+@K^GP8;`|x4^n)+O4&$Doy!eGKfxK-zHpOD~2R<%uGd4b_ z`GLvi{1D5XTVmG@-1y(9w5v`TJDu{YX?!Z5@k*kqK0yqvwDRp%5o7(4sZ$)QxP02K zBs7lIq`o@-lf%stQcQL|E%WBGaP?cE8DGHrBi9y3KLwk9UwosfhHN>F<1jq!1H0(a zl)euaTAwPPeVym;@^j<1%l1H2e(1dh!Pmu|YVu^&$-FAYWGD{x&@L8FectyT>BYQD z#EkK}J{?8tb+Gvx59Y{c&7w8aE&(}y{YhC&Yn5Oj_XHGc2S|F^VPe$69FM={)$nWU z&Po;239^G#icbzQ-jt0n*3lD_oGA9IrEqB$|0qb2 z?OF|tW*GoXvygy&=P!+!wTn<*`9SIc-`U)_AC9``DRJ&QVxqZ2e4;la8E1!g)ZI0k zD5AN8IBiq=>jw5GKH7A(yVm2XtbV2fwr)zMuCp$0W^%@k2<97Iw2Tdk$HbeBfZPIQ|6 zlhXOY9SJ1v;7*9#w=)(%>@MtP zIZ_%J3`R^$Ej=LOka?+ zzZYry( z0}2k`A3*I^!N`1i|`|3*?{}-DhRB!Sqg^10FJ7W|e(b zrb&>;XsQ;KOQ~E_^axwP%WL`&TPX1*wh}|4d-J}Es{1X&Z7yS)n5TAy)EB^8ia5)0XpaAHFYSs7($VW1d$(KD}IRW5hF|AIa)s*OF{*jVf*l@R0x zb!d{Ge`Hl{RD#5RRtH0(UHC}2esO?8^M}r|ls3)%;Ef4;JW!^@YxAJr^5qWPlvj1R z_2WY|;@erL;)cZ`SJlB0Hj`)ue{bNx12N*!m5fQ+rinX?YbQ1Mdh8>pP^B4*lE{iG z|M=?k+baYIYnK4uJX&+O{?S9x=)Dezuxe73E)A z^D*03zwnHp@kzx|xDtp(O*k**owyq1yO=3nb56&g5q-Dk#G{#!Kth{>h&U7`t>>_E~yFefjKARrb;AIN@JnCBH3tRWh-ko%6gIfj2AnnAb znT!i3z<~TYZq%!3pnunb6sD8 zU62Blle#wp^eVsYnT`XG{9AlT#$*GA_RzAof~~!=mAzx3LeWMa0oTOgaGPgQ?;*bN z=r7g}-SXH(p{!}x8C<6?OhL@}pnW*V7x+EAXFq5`O!xtNxUaI_i^p#+D+!;_Cfsbf zw!#CO)TYtDX2w)aBL|>i1^!~WePVZUK}_bK^(6yWJTTF;Vhht>yXNCVPOJsBxA_YP zUkc}=RkxyweJ(nWh)_?I21cw)pl{g*LrocSdpR!%tBEys$S>HdIife)>4=u1;CfOw zsEPoNYxx~F@-Ex>Ag6298~cV=PRu7e?%Vo{IxMd^ifT-RU*Vh{Yd;wB|5Zc5;Q7~51D?+YosaVpMu&ha3Oy4m77QG%w6&B6_PNlXq~v)H-Wdbm5e`FL~bJ9+tf>$>|`x%_>F;H!J2 zP9RPA7)jh*g^>!9?|iGMl2-}x8n%YCp{2bHPauVGoG2PJcO01;hu~Yt5^%hymwb(5 zC*DxyI-BNlbDVLOeLv~y_xSMp2SqR4MtB0Im1r1kVgEZTg?<;rF2$I^?CBKT-0*YV z(kpyoa6%%nwb47Gt!DB*@>57EwX0*~ z_oOMs`Z@8CG2Au5m~7h2In3PKF^4rtttlVQ{fV&hkLAsbi&)(IY5Y;NxjPCoyaEHh zDLP+nvI*w&e9=iH_fG4Ko5S5ZO+Mcm(Xo`NzpuY>$&s$VXNni&9I%}1WNxc&`qWt^ z`r6iyO3kru%n2=ccJX5OBy2Kn`^cQ_T`u5oBUl(Zf5hUJDfa84eCaE+v&B4 zn;H0JGT(m|)jEWy3VcF=IPVqCsb9s;^r(kl-@NlySdzjyC}@@Uiq(%o#RXv&TC*>D zzn6OXohj^VNY5&WNh|?wopOJe|8$zw{Og;JR+PI;OZ)4!VT5|Ljhbt$St0L;jaR_F z%J0{@vdqMc(t(=$c=&wRiyk}s=)7$|rWUz1W%)HYh2{h>L!BA%Ath{R{t9L6vVG{^ z>!KMdf1wo}=4GPUolk2pOWVc$I^d*@MHA1rW*nuaU$v1b3BExzdV^}kOUx{DNAvG= zFh0*#s)nV(73@d$uXIq7|G&)mn+;+=+?OPgk&y|ICH)}CZhpwr3dob!^GTbZ*TS-O z6_9zbK30CNm;0Ulxzp$OW>Wq{r;qa&MHyV6F#tWwz9Rfw}ihmdLxee1)0#wVH581wIo8B18>-j;20oUpfWUOiO_LCz>nK`<#h-*{|IVr=_ zetU5x;99 zD~>73;|}{HN~FKDWSdlJeP+cALUSV1v4%(wHA1-*aAAwcJQ1*!V3>YkmM0k(#!K}f zHs01}e7wk?b6pv~WE)K zo_hTPXiE%hmZ&s*ssmzu)1*ha_KxJuUZS$jv)n%}w0R1|bi{R@#bq|ucXEHBlFfFW zVB~Ud#f0Q2txqhcSp`<7ZAUn-%@8~=?oHy#UWJ_&1l47xstlX<-hUTSDRAxl$AY(#ahxV}XS zz`U%VoT*9iSyC|+0ToF&aeR}Qk}Oo)a7fmN&Op|+`)nM~3(S2ul0mqua`swNfsbkq z(gc(zE`ipaW7L-y-7H)53(?Y(MoSZ6gWf(uuBq9Tk}vOYYx=4+aH0GHb zcP)r_P_EtpzBv0#S5r?j?+GjsUT^Cm4SSgOIkyhhn$+wR=wa}<1r+FyPAt5!+4sjy zl7oyg@A`Z-rg^K|MXGl$x?u?=7U19#<#LhZ;ALdNh(D|kIH+43P z%v5dL4nlj&_weH-7P|?4Ux(ISGlN$|oo`{ks9Q1_U6d$guujAtruT;SIlQFqIi4Ha z9qC8rJHi+A!Nr^2!F{!lec^I)7Q8N)%n+P_A0MXLsBe|$Hkl}Ekc7@i8g}r&(sN!GUdAQ1AC472NN=qJAF8&I zeZaB?Qtl`|VpvVKtzh}pjxC&fyO%a@tGn;=Zr=|T=u;j-mK)01BbyC3DVtD?3L&^F z2x6~aQ{|+qYDNBdqjDhfR%5-^mzS}vok=lrpbjqLboZ&5h|KX@+gj;2LJh4Slga5; zyQ5M;mESZK5_Bh^V4uNpU-wCQn-+$cPD=nC=|ne&O}mgs-NQijX}~LNxY;yXl$y|Y zn&4YcaURq~#&W}Dd85mVDx|*?K^fAXdwdlp)@*4UCwV+fZfN(CJ>sXu#DdcBmhPIN zWl&XyltprODUNqV&HW+IIwi#scCdx>N3yR7elsMz*pa`lwcPS^%(;yPM5&~~T2kKe zWAl;d)!KPPc56jd<$$*D4Sh{7n$S-iYlAYW)5M6j!6F{-WZKJM z%Y9VfnV%_7_2C;ixmW^t**nFRlH_1f>2gNn2A|$F-y1X_9FY*epkE7tj9MD@qrx*< z>GnH)6qfB@IRCJ~792D2p7%3Nc#TQ#5)tCp^+2%eg^eKdl>C_Y`%8A*8buzH3RcRR zJ;Iv3dF^p0UrmRQj=l4wuld)XW}XH}X72xgo-G?5&(DM5;ox4wrdu@sdbR*LZ^6V6 zt#S2!DMASwj8tPJBAQJM0~vwEQn3#hA1T5xu-=cuGYS`~DzW@D$y8M2zd(3k-pP^S z$6H?;ZoAF(=DoVO|B1bcn%1iAKkgjLPBhCjBN z^3Q$^gR>TqCt06J76*&wQwQrRd{p}R458RQKiY|Rta!0dTzUj^mXL3LeXdwqbdGr=n;l; z(l6U#X=;BOEG^`ihKs0bei@P0yj3JmP#Ydb*kqm*;bP>sbgXcqabYn}#*~pr_WShg zqT%P78Y*TXU(V>Pywl3jjayHDn)I-pJ;tbN&ma+PcXs*|sALA%~_T{5nqIx$*MYunRI8Vh1L za2YMHy5X>5uY|towcPL;?{?_0vLr6lsT?U6;F=C`?9z`Up+vi;f*5Wk-8LNg*FSU~ zqN@6A&yDixCrZnIih`35*kvOg$Z>h)O|PjlZM^Wa&K@bRS87A7GCU75yyh7F4k$I2 z{*qU(V)R+&XoO^+BeLGdFd>xCA*ClQ(w#pYG<3m` zVjtC1WQx_GA*WtX4YDnJj2g?v+L!G_t;F9x`_Qz}|2I5)djt)4N_+bX{49ko>XtCMo9}O`FIXPMoL4byDMak@=x06+$ ztsV}2;n|#&<@cQE`c#?4B zL>m{Zy%h63cnb+w%(d{Q^e*H0mN75S;yth(z475HU8`cSp+iL8ge$;}*>!>9prMl_ zKuO+iGp+J|l%#d2h3!krDMEMndUik!<%_n}@7*z1`|~`X)e+3fPDQQf9<)8Ned)E0 z5q`Rh&qiRr0E6FZJ(CG9Oya?bnuHOHq zwkjQ_(0jtSc_8RdzKm*WiLW!yat^^QzyfDvx@~s#^CbDq1XaX!i~d~NKb%#iLh!D$ zDfCmY#xl)~iT|wg))(`4G{rFKh6vijn9`;}Rth=ky)*p{qjCnF;2Y{V44)g+5dT>C zUG8v(Btu$A2I$FpvF`nccXu+$+F5sgG5(+_=GHhV3TJs zB@){s*ivSIiTqTqr-NMbTiDpt-5_cy?{z>*N02|h84e9elCkvE)4!+0T8#>=8n7wx zTiB=Qe_r1GzlE@hJ3tx%#)6ovil8)os%S~l3`;T3>_mj(C zHykt`AC6kS!gt1=>2>C9$42U73VlKXlSgTZWb1JkOZSPCNpcl=5|Kc3RTVGPkldXN z-*|g*>#CM3s_=kObox?E`KxF#RAdS433vJV!8Q3Rk`6>rR!SlytgOOjlb2l19$RJS z-wI2&qoXTWt65sBE!F$PKtDvT+NC-nL#@_@myr@VbGTrKYb+HDP0?P|v$0#Mb zB~GHX%!b78Xup>hLRB)uSsTitVkXb_k;m*HL}l3Z;5X;#dGHH~Ighzz_3C9U?&2?# zC%?k>7^X6lle>a^|4fB(B+{natHQ?SbQ!vqn$>RoH_pYAqr_ry6sPO*Kl++FPbOs8 zb1LLyJ2CkLzl-+?j@3Za=a8t4)9^Ita}bprCb@)K)Ze{?(5qx>i+1-fflMY|3KaEw zQTjYk+wh^5UEEGmWNLoi>f`(zcC|rUbK=pBcQdEy8-!pBx&(UOGi2=i z9KrWuBPFI~EzPNTRF3O<3dbd^<;2e@WiWH#t?90-=nnlEq+&0wSc^nE^+oO($BwMeDbt71R}4;Bt@MI@2Sun$64~hTG|-%t z4aJ1xi#=JFPB^VX$S6eVt{kb|<5DhyUo?uqCg$DYA5Q9up*T>{c(ol2LoUwaJMDM+ z3fnmC?wnRCQL~jE3yXKn_{}QVhX~j=e9D&Z>L4Gb@dt$C@UAUW$jAl|CvDJ4G(YKn zmR}oQy~9g}HyE(`tXEB~*Q&h9xmvYb9>0+z+#kaD4wBN2I@5k38b_-mOL^fBE<}B=9Qt$D(pkB}e?5sX=fD~RUY zM;yqEzwVMRjoZh&9I}kLoMYr*uV!uVE*c9jh)c0@4|SM6|HX9-^^b~2zBKUThKthR zPE^2I_p75{>%UI3ES~Pav%mJeql+fR*0sSpO@R!Ud9|8g-;VTY&X7bzBX}w5fw5@I z9?5OFH4z98&Hr83o80V@P^_IQ$_^pX^bUv*cP*bM^7|LzCSKb znZIx}k-ywvf!4miDt7$%RzmcEmT9yWk%rv4Euu!5aQ?Ov(G+tjvA(E#R@xq`VYaa2 zngirBMsCIjCe2Cv_YFOjYyg+6_1E=>@qRP9{y zR%HVRAVjK|Gux4{YrL6NT4|5~S3K+NYgBbl4x`9)c)`0gyOuLKDG=lc$;z>>jlnNw zNQyB1=;22ZVnka|r=#E(zm@J~wt^Xmz^DP)NLO6eFW(gISN`z1WmQ&xQE)cM)j?A@ zHsC;YAu-sf%fau{-oWnDFpUQ~@vyy8)JYh?gKQ*|13GI(b>P6@JqoNgtC zs%}5{_b*78FsYoqI;J!_+Yu)CBt$?fp&nVUFo;4f`56sKEk8Dl;!MEnzEW{zLwzIO z2Z@@9#z~kZ;^@25$4DNh(B*q6Krv_foJVrzoTYh!yFRG5F3NUHAUJYryfR}HqBY&T zFdMN0jdLsU*N`)&A;(SQj0x*K+;}~0_S`Grm=Vc2bMY`J+~y{JAFNuCOQJsMV-_H{ zUOU^q7rU=8#9gJwo_6(B;-;`nvEvtZG+|7S-^-)LFgqgm?d|1J&hdMLhB<<`t>s1% z!OMW+RHm1?C9n5fQk5h1D%4N_$cGuCfC5{-?Pa@z@!y8 zabUs@`pCdfqcG$LAJvMIj#6;2+zp;B9Z%Hg@lTO^i$H!*GB$mz*k*hvE@L^(*>zy@;=x_Gl=401t5Bdc^X&PbYJG2t- zD8}`Cen&`mM~^m>^4|Y-Hc?~OY7b69Y7pO{gUm(Qc2^?m z*SLKVWD;%9tY`^2<3aP(4#bC>%p6L;3$bCi`DJ{fvR;uDbX{lygadYhYmVwsV)g02 z2RQ%kKA@^Co!r14eh}Dh5%Zt5h`)`U2jCwD+o{*=P#=)O%@!C!CO}1$CPK$W!eMdS z51W0aZR8X?YmuESV*6G8Mr6CCG=cdJPLkC+q!T?HntWsL@XDbu#H6be)GEW(Pu@=J zCwq(+=3JCYg@-+vgi=T7N$W#h(yT2?ldFOD_#s0@Mo7z8J=2S^LX3wk{eXdyU{F`L zybAJM>FY*Crbp(;uqtOIZ+o1M7ALw0kDm* z(&vsRLhZCSkHaT>v3Yel07X*;9z=)$TbaRT27gWo1MSIR{(qkn27V=jb>No)jTEpl zd^C`m0v3R;1*Tyo5F%kR4Iw!Yun)!s6jH(D@FIX!Dp(c7DG1Euf=PklR4_k01b9dV z%fj;mQfaV%WI%Wt_yznOFp&mU1NoUJCz?|MpYCA_6ag?f!m1@4ka!0s01j)w#6TPj z0)4YivLOLVdFe4>ry9YCz|0@;hdVG+j6wmRrh~abNUxKhy{7x41;#Q6V{u7`sWK0P z19}d?#K{R^&w!qEFe_*>0`UBSLXs4T`?p5A3|N!p0ErB+BuFPF*)4_=$jAV*BH(5I zR}u~2d_YD1%l-?-4$>+}HtVBKjxN9eq%y&*@Bx5xCin#?w;rg9MI}j|uEzpGPhi&U zXTq4r+JUies5AgL3oL?Q(f!x7T%(|7m;jr*RUXY!r-}95DI6WS2?c2^ozn`P1b8*|wJrtG{L;d2E6D zZ-aPpV1U*K=?;k;NJml zAHgc11snjc02WabUIug^AO&WgOCcB=goyhGCIier!Ri(Hr@#)p#)ZcNl(7DU`cE8} zKEc}jn)nYRJ3x~MmWF2otn$G2AV%817>pkk_?-t90M)SnMJ)5dvY024*9UKyYCr$7e8mw}Oh&|)we zz)%bp0g(d#hNVDXi~k4NCsnr0xS&L!T}Pi!PLMrQxG;#TMu&} z2QKKJma~H15&V~i156WuaQ-IK9tr5*z4M|H)=|VL|1xto!dm~D5=0Jgi~MIGsj7n6 z5kd2pp_>Lo2^?0ydc-Xg=zlZokm+3`K_Q|Eg03NT`N6JM#H| z>%;&^YhWhtnfygy=CA_oNdFPHxA<30Mi&3&!UjHBfRKUn8kk>6Q~rU|wm?Y0^IBLB zY6JcsUs^f{9jL8^u`yNuMJ=mAw7_)pe~e_SgBfXG`|VxB$FHuq|kK^B;9EV+erKMwo2f?mxhvNaFxmjUWsFvkA-tA~^a369C#x ze+HuCzXeMX1T>(e2_}Vh@;`{w2`qGf2LH4kSWGCIVMg&?{0|+s8`iA?E>(1s(+Q>o{t@FwM)=2yzjU1z7@Yy_f9TF=2n;|^3rsB= z-d`A|5f3131&e|@i2foTtzdnSJN4fJtg)EDc`Gb6?*Q61upWq4jFOmR61ZSYt;A)$8^AIAJhFW zj~x6wz}*S<1SQ-4mjNAEv;AutE->hb@V`C2)$tFP)E~v7pf0z+B2`^rd656BKZSo> z^Bg`2(Cmiw_J@qW7|cp?KrIvDpLG1=E^1KLr@tgFW&~7V<3_6@8a_P_dMT+U0q#WU0q#WU0pqU$k>$YoL@@Fn?eepO0jz>@gOY! zi~=w+=73b~MmGzLq1c}C(XDIvygBE{7k+;>Z2IJj3a2Z&s4Z{#8^+^MyjL6B<{y8hERNgx1s4rVdLsP zWsstyFq}g^GO~FeG1kh*VAa-|AVp`5j#Ts!t+I}R_7sj1FQB7+oRx>HwQQ?-s$D#VcDhtRUl~rYV^QXU#1ADC-tIHo}ZAC?HRt#8Rqm6nzqoSow+;w8F1ov+7gP%2V1q8NtGnAXu#`qoKSEsrjFR zFq_n5&GLR&Sy5(9D;t{j#i*i*r+}T`sI(Ionp{69*cG@PD3{S zsTNIsKMgx@s;33^rOQTJD(PiyN2*>{j^yHG_7nWipud&FEgGXgC8eLiGHXvO&KR?} ztBa*t?8YiR3H@|B)#t!O z`hJE0fml=AIjq&b7Z^mIQ&|lA&%qw-ziL5A9@w|5R&F#%VIEWG^B}k2Z-zDhJX9>M zs4S%_^yPwSda6OA6pJb0f-#Z1@W}%0+y!HMuKy1PiM|M}ouj1smmr9oi}1}lsaOG0 z@wOO>cnRdnQ}iXQ?=Wu(1zYi6$YqeXwGEAaWD?Fzpm8@s7zrpvJU2Ch6`*o6 zH`3P2#$@<{>MQv3m$kl~s!h)S*)6BIQl;i|DSw=#*rWDz~SDw)h=2I>75 z3Ws_zHq1JprVDGKg|eGyeGTkpll~fm4C|TGcdS!8H~9~*I`dH#z}Y; zXxVkB@%fEXA%dp;Yjl-25w9D-Uz;!C!>HYW*lKT=3T_0mVMP;`nDF*Kv$j-^P0tw8 z?Pu0%>K`gN$nK>I&v{J$smi^opZlMTlyeK4Rjt3FgO@A-WB7)y@iQsPU_n@on=aYylK#FjCg7YDT*-s{UPY(=4~__9?l@TLKu{YD5;>K zj6!35?vG}yFs{hxOtV*DL*nm%Q9~R9*SG@%J~@#UTDG^br9+7}{fvb@6 zE^vI?m*O~6+Fev1PGOMuDK;uPnFl#sy$i~oJsG%JPa7W##eFfr#&SOH4q#Y4?-^?= z?$C;R#;%HcIYsb88sxGXFkFY5v_cYy8(k`b>uFfa3YchX3b+q{Yy1WVNxyGwr0^rf z17iT)xNi)CX~DnK6nkm#1LH`}Y9B-U@c?2yLq5I9;*`1SG9^C5 zZk4UHRg&L7Sk%w{vVc^$X5-9Gx^w@*o-`AyzZCn--!`t);xPp9@gJzWH>n>P+i>pX zDB_9HGp8bYnDq#%+*K(71j<#~+S0Q}kYEQmCK4p_F&MbxX2!Rt#gC0O6%Xk0V@Ty! z3V&kk%KZ_@aGwO)I+J&Z*@?XT1R}o}Y;LME9nmBgxbjn}DuPv2w)KzFpSMKT?jgl~3j-D=_mp#L}GBJU7NErqaL9L3-yJTlqNpat*{C z`!9x*{=%rmVJ7>9v6W&DJ$PYk$VVKrr549*brx!r^b(w3EtGlnqM0v^HTbblY*}Dp z;}cs~=|pWBiWtU%TKhmlLqNadu{EQ^T^E99v3^yQEeo}Yhz1A zKT3EFE7*}%NTs<{{My(;af9l%7W3=KD4fq!mwuScm3n_FVhxf+j{QIwR zf0lgAdJjJSv9ZswwU+}LCh?!DWUuo4Iof@d?8~L~?=y60dX+G`zsiV{kQ7G<_yA_> zQ=JdS25{%HJ{Vi^Jv-ae_|Enfq{xtpoIir+Ey*U$rnE26;eMO#Y0726;ct5srdC zH7_yx*zfyjhAGY%HH-9u70m#gfAq#R&}+ugQrQn%ULq1-?b@GBoV(xFF=J~C-aumvmCD9u)gRTRLw2ub{s zua30ytD}LnSzO|1sT?yY#ZG9<^EOVTvvD%Wqp$7Yq>{35m$}5KANHNqYgp#c> z_>oQ+{E!SMnv>xaAoG1vf?S&9L@y^f`2iBFu&0X7Xn1b1lcXr{?45;Lid}TZ8A2~l zo=Tyq;u$3?g&4(dS}T<@saT1+5ftSjU=bd7qCv-<{AKDpT);^@U2?&=4v?ElXu{un zCo`lW+cQR2rk5%pU8mJ5h@v_@S3&<&{>~KQ@9azQYH(CQqt!xH#Ut9H7HV=zEv@jt zC`(YqMVks+`~+8O?J88|9_m^3a#x`Nx6#N7cZ|+za&SX~HX?(>xe4_-ggs?atKEbs z?vD^w_$(D#S7L=0?oiJOVXOd>YD!<}jH8tt>~a^hoO@MLYXmJRJdzf)Dqx8LPYPDb(UdC9y)N7Yf=AtdQv? z)ZuJ8u|kbbY%qwvdO>peq|ylOxsKgfZI(u;%k3G+3eN{RyGi3#(Ps@h>XpX8+1?mP zl($fuTRXTEA_ajjdkby2vl$Fl#|M-~k7WhO%Ykxzgm7;EWC;>RKYTFa*VCjzCF+u4Ad{YBI%+;httRPGIq6csy z{DBj{n6)bK17yAg$@$F!@w<=UOT`kn*)j$mz0540hFXB%FPFexG+c`b$2UD>cFmLM zKpoUjoK6N&$v;@-O!r5-x>F^c5X`%+cBT~%-F&FoYG-GPF+ha7*Ep*zJb(>roGHCZ zfEU8B&PqyKXmp^vIzf+{ixQm>$M48@rpx)xUew{6)0f@O<@%=$9ng1BSX(Mi6MSVlOHrk$ zL%R%EFXQN&0j7f}CIHs?H<}&*n|OzA1YkiL$Y>O5D_T&pQE1OsDsrac)=Ce$2p}&! zcBXmtl{!j(40XOx5iVS@03JQwI9odUc5g@}!U&x+D(z^TfH_|CmQsv@j*8won|v^| z(<*YwMHHHGXFf=^?lefmRx*}0i$Xk?UBYO1m507%=yQTmKemeAk^CwOdRk*tS_<`7 z1X9%^rVBl)sFDb=KPfL6>>wo_3Q`6#4@w^jR%-`hcH4zebf|z>OrQ{s!|;kgSfJml zD5bHvlS?(d4cUbW9^_X6G)C1{G6}S-0CUur=2Z}S@x$uN$f1-q1u`fK0^u4#KtA3? zN%xy5!&rwh{Btv<+q8gYbx%50m)Gf znb>_`a6>xNmLNfw6JxHD=OC&g8h1}tQYNe{jjf2K^P-0=wgVL*!cGJ6Z1a5%p@j#PwDpG4n@%58I?~I< zm?ZsJ^l|D+87}r+kOgD_(;~1!`q9b=>^F;U$Tb0^tc;Zwb5lv@6Gd-oQ&|Y( z``=d5)Z5Ac>1-IxFT10pOD$3N8g+`Dq^%+(^T!`R4<0Brw73dT+C5TIizK~hZ zxF<@woTB$2p(+~0Qk$w^xbF+dzoqC-lYB+Byk1XL#eAN51>*7Wd%gmfFMgw>i*5D3 z)U+B((eIR`OB4@3TGEjT3TJG#<%}2mptfM zbvQjK6jnp%$h}lh{RS|GYieNsI&4k%YYUz^9bK%cq=rzBYhgz#Vgw`2v~$6M9M>2! zYg1}MPy(%}DRkl{!~CHM)s_CQsF91j%LQ{SRScY|a`C3*8c^=vBB5`sTqUpx#9|wUdvjK`mIMVme$)=*fN6mC|m;RSIB*<+b6eZKk5y=sdTg1oNkkQQ&oL zC`0%=)Wu!eYE^VC3Veo9ag@-3`!kYtmKEhU<1i`a+T5yR>()fF0Zn&zw!S`T{$*N*i!vmO@T#SU@} z{8+693z^G1`A;bLjT2W6CE zdb6F(b8Hy|`>~}6DvBNJf(UN|^FH*TA^00V&H_Pb1jpokrUm3_j^H5=W_cqZcOPF` z@$$cg{Fd@+x!P9;xR|I&46=XF6gLLGodmUgYZK< z_Q%yyA$1EYd};>b8@IATY%B^}wz0xesnBjGE6m-A$*tJ}%-b{vhpuF3E+k5!Z<*qP z=Ac-vfE6A$M>`!pMlbbMGY&QX9%F^j;~=st3=ZC^IKi9Sd6I#PPXa8vF(2bVJC)Qe zKs)w4tDV>aQf zlBOi$#Ic_)Bnq+oogXf=yaNnxcqBUPUWxRM@Oqqc>kGO6Uc9 zmbYK!KrQQujuaLF+gzj(U1@r2LCH@>_!H>fw5_#Jf!~9Yp{`0V9WI>6p$#1Tk2aK_ zBvhbCTa^=aZG%l9)6s;qp$)u^;n=(7CSGlECS2iaDrL6C$@8U$sdTrk(2)1mm`ZIm zDj(|F4y1AnCeVg`tJ@1b z`B)@-$aTNAhls4}%B3naa4<$PH%YLj;0}T}Kfk^S3k*6?dIz{or)fn8AsJqyqN9+? zPi+fp);!N`b$*;_313s;{Qxn(dF?fEgkI)sk~yPWQy-1L@1(Yd>5fRe`S=6 z5=@2Z@YrP^Ah0VoR<{fp-kdI_2<@q34bhEN{*WqnjF&5WQNd@kPdcG7H z86)Ra_7oW*#oBto#cxURy`Ux!XiG1lEw`+&v?F<8`O71U=?xyb7fDqDP3rQw3z~9?Qn!Z9yeqo7<@=H_(it1}J4NLlB zCZ6N+e|!$+_Do;U(b3nwLJL0GP0a`-_Y>;yF`g!rH5;8>BwNk)ip%|A?xxVoemEwn zs78Mrexm%<)ZSk$$5k29`u^y{Rj;N>dbL5ir3~g1MKvwU(tA?H0kAPe)M2xLr;4x2uCF@32Yo@1$B+avlm#|LZ;oZX8aM;m_3` zG4ane5&>%pII;zc^O!O_RrOpE94ucjuZwd4kA2_Q{Of+j1q?Nc*tTg ztP`WK1HAnq_h_W>5)5nf81xV`8ml77gSuwGlNmD_?vs@_>Bpe}X}D9VFZdOBe38zT zzUf?jSktQEu9i#$QkM)^{3CQI18e0%byrE`8mcfx22D@;V#!?R& zn%me_P98v9e+(A!Q+hK7iWW!p#tM!2>?Bv(kmRbRN@FnU{IPO?^5R$^3?7%w zGZ3ulB4ts^r_S}`LEbo9s;f(trs5zggMB9e?69D;i8E~~bho836F?~%;yAu%C zda}X-C;E3+Te?J$3L~<*%rxMHH&IAO%76abu!lQQkpjz?T%(p>Qo3uGNGba4uJ zPR}-hr(&8;Q_57Fa&|3au#`a%#;vK?w`;Ft5dAcv8)sZ=s^04rL1(66y7&zYQe}gi zJ0+Zkj#i(JwKJ6xrwgsPCfiu8JnMs2dO6bEZ7{Xbvmp*S^m1mWo26DBAk_>g%h5xu z8OGy8C5PO+ewuBx8@77+Qx&*S>zpUv*y#K|DKG2CML#2}@$T&UrUmid-sj zARYh5&xBA5E-{4SOBltu73R9@sKX7#+nLzVLT;AwWKYq3MH^CiL!9Y1-K;6UF0?|d#n`@Xx*&HOyMvs#pvbq$Br9WpwlD(dkLfomiyvBhv za{wOn+ytJ3z-{g;R*>ac_{t3?S~9Lr=YV4Oe_5S2RaDZ9GjQAG-lDQm_xR)g(w>Y{nqBlkc*LQoQq){u$Bs*IrD^6ZjHVCZplY^KqD1=*9@DoHf?S$<*6Xllf4#a^4o? zT6$x3HEoV|@<0yH2jOIGDS{wfo}20d7ocvPk=5z9y1UUUqdP8v7eLLg21;Npo3jfG z5K#WDq6G1vvlZPPC7Z9JDhtv6FXRYgT!i-Fv}hruvA;4y4DW@_@ZCZzO229hCp^P5 zoW@oIgM&_*8T?Sw-BLB5)?}y0-UoM6r;mC>%#6-uF7jHbCg zB#3EhZuW5ZlCBR-Yhm$X^tPZcYa(+AyIPl?;$NmQuB)y-Oh6qqz(*JJ-{J9Df7k!!ik? zr|{+OHtfv#%Wq(@-6jcap#0yk1HQ>;bRdfw(z*`j3b!*la)((6ON?eXWSDP1%kgSUD zmqQ1tykX6Mve_{Y>$Stb5;%x*{{_$RsZ=EXSB729f2_#&*KDJx(iaqe3I$L$$jN8qL-ko3R9A@!uh--VHU$!Jdr*qBl>JY~fR z=8MMR!N78N9r zy$JEb!C0Khy>a3l`p|6j7O#T;GvZgd=U__j=hUXbsU@=_@{0fE50Fvc zkR^nbENwIiHz1~DJB;wZn`MUo{HBcNM^5W-Y&m}yYbYdMC>*tH8ymUk5ydKV59i3b$VXSaCe&*n=qH{UMeZPX6oha zM)cya%Y?7mgkHk;%B9A%U=tcD5B}uQi8>sFD{*d}x%J3nUY1(X|Cp)eFPqV_>n%p>R+PWRbvZ{Y#b1HI@3h?EeHON9cgVnm~PvGG6A%ly8G=Bd(MSIF49<*V- z;J|GxFLhO(@(SIZ>C$9)9I}rya2qJ(2bEH&LNnfC>y-6vZK%d_*IE)eUUdkua6 zMf9THdojAeouK!77h16sS3Su)aiZ!+c{_!Ud`5Q-ZEkJQlJ72TR?T}!7@jny7e@H= z%4@#;Mv-t8rqa-&{3z|Xg6gfYuBcc6rz)ElJ@RKhm*%M@XOuU zTgoqCy{AbXBH=&-CzX#W@Uw+q6!cZ^_iXK#PFBEj&8V%KJicTNJn#}QdfE5>M>3*>JlJ0R3mRG~o! zkS^1e3JxHVqAuAV6zcQ;-qn!HJ&l}pF2|c)>Em*|>>7KYRun)v)*S@n8|6YMy}z&V zpbpj1dEg<)D(I1f<4ehpG^R84PzlUEk-(vJ;1IUn3(puGT_)lwx&jD3{xyS)eXVh2 zC-KPzU^$)g3WUB~)laNedst}B4gJOn;|>dPTn(NKN5Ij&!%&47(jO7}aej^zaS2zv zc}LKd7h>2F!kZ(&Uapa9Lg~^`!IoZYylt2(DC_#vqu}zQUnxQZ&Q;HvM(e#j8BZ;a z0q2rY!qL*k+vX@>t_0SJ5?D`{LcEbP7v+sCDbYJnGSJBDtl(|AR-Pf{N@64KHm1B@ zkhd*m9fv>{g_Kh8wP0*iSeeEH!WdUe!n|>9D(%Y6PN4gBa5<%M>U;UPP)1E3(~kXz zRJXkbtE-!Zm~*Ye(8?bYxIbQ@SaKX9F&oTPh%O7Zr|d$+6!Rl+NRkr+?w>^CoiU|Y zPV_y-Tg67&>=f!eo3sALjWsy4{+3AKj6|u4EPV+66g-R_Z5U$0R0Coxr=bUvJ20{Z z9lXOC#lq7P#V)LA*Dl^liadouH#`IIgJcQpOIc&E$KmJ_#^E)$c}(u~<_rQhzmwrC zq9%XP+_N|#P8`8{Ea{IPmFIBo4@0`RB)GiW*cJMn!?D+H66-8s5+wZM97Hl?Due8u z>Mb7*OupCJnckMGatVz;5C5ugE+hD|AG(mG?R5dX&R>qA>ZyerUewmyzD?lP=Tl!Fh=JB0qbUc&kK z&ShK;ym2;x8eGBsZ<1PW1F;=J5Pz=PtZ%!o!2bN_X+p(1vmx87*i5hb$oM{F?~6WC zuA-0DI!mlWSF!);k(4fXtGa;&nr8H|p*`}EUpjEt3iPqutV083+#s6$7x-BcD$}nh zNwxt$D%?aT^%_bkRZXQos`>~lhJZkmHO1ESaj|&y8byZda7BcAJ``Qgrwa3UPhQ7( zt~C0|Rs-IpsShO2uHAfa$dR&5Wg|81Ch*_&M3)(20D|H^ zcsMBaRw%)H_mk-aTPRKBEx;EJm#18y_@==YBMZ-0HucF1TWnW#1?||%mqGlxg(7D=t694t8#p(Ajik_ zT1i5>2_*PECVn z%WJ{ZWU&IRtPF$oVx5oWQoBp_?;#+(a1(G=81T4eDkOAq6Nb0VOu>1> zu?W09&X++3>RJTf0`b5i#AcW8@S$;e25hZy%uLf+Iep zeu-)0Ncphd`Ns+C=BVX&)uMeuk$10Ipa?B@bb}CY)!4)BeF2 zA}Q}5TpwS#O!uFFkm?as?A2Ady@3Wk5^8Yj>r$039e#xVZvM^ilsDOMf)&H5`D394 zSA0jRa3k$qR1`dh`0CyFq54}5p2R;vifBu!{{%Oz{hqP*%b!6bR=gzDDV(hO!YBGrOEzXQv>-f_B!v-&^(HDUTi7$sI4SY?DoAy@}HMH$5 zLXln#DeWDoKYc6IRE#0RJ1o=vH0T{v1<&T?s*~+~wN(5LgK61Gg7{I*f3XUxbVa&s zS6}u>Sr*P8|6-y)B>R#&#n)GgXaw^gx}($s^Ya>SbD57_tB-FP%iah1lvT8zlnl7! zBx7%X4?6zozEZ}b2enN1b)gbJ_#^Ty`smG~Qn82dY38fqv3-`7in?hVxGbo5mHV5Nq?VhWgPaM@;WZ1?n<0 zWeNC_>ssl0UJCtenBZr*_?Ateq7o!&#BpL}+|_1sViG@U`p-eC$&nW$c*Sf}C(*P0 zRP59=ffs!g6DgM$8}Wbqjzil*ti*4;7{(1*D-B;yEv&?F#TFW8CAQ-?Z2L*Tjt08m z&AOwt7{O)i!l?0V*jlW@wLKuUD^DA(#hTo?!<1=-d38Dhd6eFahS-Sks?SPzLA2f4 zv*PC^79bT zI`qxYn!FvvVEzPLhQar+b0<4MP}i-fKC*ww!`fevP7Q3AdFlW@w%Ga8Sv!BcK9J&I z^&J8F%fVk#=K#ub6oWCu4US@4h*#kxcITtvy>#~R$2&47^y03=<%G`PpWT)`b3)@b zA^y@LYDl%5K(B){1oi<>V_l#rbDSX#52&ofO0lz8pUdmQYUD+ItBb!2J4MNhdax2r z(|eX8;A0O;u@<)yIeIRlkz8Cb=Nv`5h`srF2l1jZ8#$jl^l)d8{^hDsnIC$TlOCRK zI_z(@G*7&hOTpCR9uNXOfKd5^KehY-3pH(t z$>A6wf%*UZN%xvw-Qx~>5Sd9MW}+>TkEVm(C&o%0mq z;Rg75i7k<2-QP=Wj}+TuUeK0M^3gy*Exol=$5rc3lQm*>1x{ERu@RDC72aZfd_)0% zyr`qM*ibQ>mU)XQcvV#5EhgfV4T(NtE5%w`By#aXwK`Typ|PkL;D@=X(N0S) z9JYhBc3ODE0O66>BR|-e*bZ7Lufu~fI%rLSG5K6^rjypvm>uXuE?TVQSDmzWw8S4I zQ*ePcCRxkA#=*`a?^Csw7WD}!wGhe5URpZTORN341J2NbPXn#iVz5U>X<5EZbA5m^ zXEeCO7dnFZd1LSjy%Xf$P6vHBFiuN~Y=bWi8zZp%<=r|=U+wWAx(0DMq?m-^p_aEE z!rnz)^5_Rt)l477p*PD1%s#U-x-~y!BBOpDvUJg+ad8LZK18s5n&Y#H|!)YZMggihz)WTsyN8YG=@z zN?7Z^(zi+=JGX|8HrCLI5<;+I4*eP?w&vG2(n&9He2}fK^CVq32Dz%SM9e?~q{4l< zU?f#Poh=;+$KHH2o(%QGno<&IRW7a-!!4={yMBI?&Z9Kc7R=eSXLa8r#7bO@snD{r zSc9AQv*1j~>$InXl|jrQl{Em43EVkVr=r#yOF>LdN_Jxi-z0?1W7#N?i&=;3 zHl9(+8?SSxJw42b*Q-Is0==y!_J*nb$ zAphUo(z+n(JWp3yN=r2LFOtsEl;NXX@^paAZf^Rr(t?rVm#XaOYz>U})JmPDCEG`D zBgN6&giQ=t9%ODUu{SqjD}$Vm32>*9^(t$Mu8m3FvrPia0+drLqqyI8GQ^b0IyFA^ zgj`kG+m;6q8ifJe-op@j}p6b+YXn~GUZC<*9M0J>Y!097I|qu=F~_e zHA!{ur&!(HJ3435)fH=V`_8d0zyp+^t{Bd3!itwP69cM;=k)q|VqdO7VJXaoW*6%4 zzFms*UaAJ8aJ3!?=iMnK>_%cV=I1M}-^6xYgQt`jEmovyPoeqs8iUEt(ZJvLf`Oy! zi*30%#jK$8(&MOCjMXJ0p8i;7iuQkGSm_46isBoHaonzNr9^y5^Bn__+wl#t4Fo9k zbT~FZPtgsL7l;;TVOA zW*PJjRJRGtkvvm(8lk&Wo|b4Bh_A#;Fh9=kC)|@R`RR3x#~K)f#S^_?#DvV;%KYJV zOA|D|WzT! zf}a$R=JEOfMp)SrOqL|#P9+g1<3=sTNH|{OTEZ!tKo?qKz}wpDrAJJ`3_Up>=n+Xc zFD2;%87Qf}-g0Hf(uH_9U=vB7fIb({-~_RQVkezV0Pqa?CyJf zULq8JG@VTp+bDLBz7<-Xq`|EqjC$Sm)Tz6#3*2UZ7yk_{UXs zYdFJwddu(t`q5gf#Rv2=VI{PIU)Hg|Wt*LC#3=sYKs`%H|1{7%nN8YafaTIm@LFl+ z-giszztd%SFqO0g`3^(y2w8fAfDG+;ytP=~P8`H%4KwwE^m#mH9EK$#D_rX&w2vQQ zYJqfdcN(=3lfM&iMIK#F5|inz6c3$pdn@hOmsI>TB| zoJXlW;r<~d&6x`3nR{)~1;%T`d{!stZ57Wq%V*C5z2%m&aRI~1%XYJ)mtAmZYn;O% z$d-!X1`{hF4akPpl9`C`YZ)S5zcQ>#_6B86G7gTvEs+48bZ!YUzU65doeY+)=Q2Dw z$40r#OwDF_8ET)AeklzKX$Ob|w-D77mLhs{5Azr}IYn&D{q;L5AVtrVhliqs8yd_*8mEMVd=NW2y}^vQ zryCHjZe(>xqD4Y+H!+gyw3$K7*?T6kBfA6p*cPeIlh$_^8*rO%Nd=sCZkctgau48S zBTG{1?NFiKk8zYOfg9anU}P6H<>n)KQo_;oge$p>QhJIVxf`D(m?znNHj^vqiFSAp zG;bhKG2N}XJbPBagalCjc!=uvBO~ z!j=)_{JF9Hq0qSo29dOr3MI(u022`@RT#-Ac2s8oz$HcoM(UU&)e>+OBP+`O0T}wu z@~rOF0I?o7J~Eil!Qt9ksakIsilr~M3xc9ACU|d zYGF(FBF#cOkq#j%=zcnc99N&AU}0HP$H7=E6B;ncpA8V0kY#XhFz~m~m%(B?g$pGP zfj?BI32hyYDBZpxF!08v1}Q0|62q?f3k>G%W(FEONQ2~ySc7SEoh891G&j(S@kp~c z_=^~YiT?VF*ot$AXT)m8o7G^-Q1poJH4KHJoR?^j@>)#PBZq;?&Q=B~EyRlk4ud(K z-`XH0%!IP;N3}IrZj|`C)^Kcw6_VtBJ*i`onV&_&(T9=phr=er2_7!?L3E?f2r(At zq-`U_mfYABiWrSCB9p_J&WkRtD>7H-?2=2PNGb z3AJ#+cP=IB$OOT2fwMUKeD7!OVr0)Ujr;dxsB=d_g9>`FLiiIT*lftc*~eov1~QDo zM`O_)q`9Nvd|&R*kdPc;a>c442;wYywxb}uKl1g-8IMOG$qc^11w<%RK75c zLHx&vO}KyzR!GP&n6{`bV?aA$ECb(_aAu8T1thbmEkxIMED%R#vN~0Yw+s1iKv3?q z1YR?Nfguk>s3(|3QDq$J{+-C`WRCic!>YN8%m#@^BpYa02SwwsB^FL*V5H;3aRJD6 zkZ`gx#aJ$L8Y>_L1_zl;Ou&Ze41!#e=G^NUtgtLgjN!Y_!iOkHi=@RYsMo)<4dgNh z-mknC`i_VGJ(^>X;yS^Sbq!WT(CzWqwuj6!(42XQKgxJrCIIiyd;{H{Z>YgQZ5Ec% z%or-1AhzU>*P% z?HkTI*a;96;qoLX!ZC`NEOtTD?8$IuH>{TNys2olSwSmJLHmtsU>;W(Dt(|(w<2O@BaWo5qwtNREXl$IvHKQrEbi>$7P^ugSqpMQ_*DU-% zPeX*G(q;@$y5~&VgftRaIM&mFE0BJ=*oBYHH&timo2&Ptnisbkq^sNVtcCLosKKYL zjBM--_=S7^#2ows&hn(vlx;E;sq-AzvJZ#wQSbt+NocDYj}}C4{`g^obeUP6=Jo`rb~biu-BC)M zizrUZqvl;`b~YsP{WLC_bpA-WJ8K@}eZb-Nf6EqIOQ+enIE_4~b#ujT2>m+E1MmQ) z%!Au-0Z%uiOO=cB;7Tke)qJ@BZ7FrW*oKR|&#KPMhZq+;G|-lZ=5<|n0fbKfFlGiV z!08P)$qV3xJCV~uC|3#fTZlf^(!qr|b_9`X5kkX7GZL%Hgw5A8^0u ztq3q}PKMtA{}=D?5N)o=P)7j-SuOkxi?qNBpYHdD=ket?ob5`iTC|DI>Ix{|9 z29}Bea#9DFRzdCM=w%(XTaFzq&ozMdy9Sud`(vrbixhbfC_coK2Xm3`h3kK>fNHF( zXL+EOt^r7ch=Z)RYrO+3cgiJ{xB@q1?P%EwNb)>xm7e+ISTCbi(3fG<7w1~}wJCz% zCP(arp$xIRwDfoI@H+;B&}aYx%w|bdSP4d&!s;iU$8%M4thq7Yviwg_`J9PZ3%vpZ zEWZ-iKG1|PEigdG*s==>z_ad^h>d)$V5&su7Iz0L;S23qg^nD8P4MTdz)o0501L#% zuNE8g6GP=vBwbpK6aF=PN&^=Prc>Y9a8UM}0Lll$1EgDi4|)@B9)hNFnXx+3vNf3R zHuQRp*q!sPN`_5{p}ic7An5Ye*q=A7#WI?RXEU2%5)rae(ZywFTbP=2oomu~h&*_AdQ?M^-*?4z_0C^ZD?{@s)D9LF862 z^;cU~@M{;~P5ZWjvp4M+q(%}Zb<{(UKsQ!YG$EXqYe$=OG*aY8|Y;uRDNy&V%zR(%i!D6-9xZ#SB?hI>!UEvxQjIrZe0N3ucAQ(VgrQ! zwie)?X)%2%5SuG@QSX!P-OPcxPq zm^vVR*nk1}@g&o)10jz<#_;zQeYCZJ@$*Mq{~u2Ae}a#$8*qO9!r-X?r9{QYMPJ1% zaylVu0@zP8sb16^wH-ebI|wNWn$o<5a^+Ty-vNa`A(pQpaWLvr!IWrV>~k+y&c6)S z@?k&uu0N#ruz@`X4Q-k_sK)?0e97ouNori*=G?q>_>J&s__3qXZ(xGRs_{PK%QmLm z$^wG;X!Gn^nqrB4xpHgO<;wm1jRz72U4-4eb1 zg5Pc`D~N6L=<_MDqKx&wzl?6~Vb%C3qTZ*(P??F+-{gi|%8LHOVoN4kqz-7^Cl$AP zxkfjc{Qv&6?@#hymeTf9qF7TB&j0@M*OaDE%KaH|320 delta 37283 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