From 1019e6610788a8683421b38292c85f9ee3b90cf2 Mon Sep 17 00:00:00 2001
From: JacksonBurns
Date: Thu, 16 Jan 2025 10:15:22 -0500
Subject: [PATCH 01/18] condense paper announcement and update supported python
versions
---
README.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/README.md b/README.md
index 40888de..fee48b8 100644
--- a/README.md
+++ b/README.md
@@ -12,8 +12,8 @@
# Announcements
-## alphaXiv
-The `fastprop` paper is freely available online at [arxiv.org/abs/2404.02058](https://arxiv.org/abs/2404.02058) and we are conducting open source peer review on [alphaXiv](https://alphaxiv.org/abs/2404.02058) - comments are appreciated!
+## alphaXiv Paper
+The companion academic paper describing `fastprop` is freely available online at [alphaXiv](https://www.alphaxiv.org/abs/2404.02058).
The source for the paper is stored in this repository under the `paper` directory.
## Initial Release :tada:
@@ -22,7 +22,7 @@ Please try `fastprop` on your datasets and let us know what you think.
Feature requests and bug reports are **very** appreciated!
# Installing `fastprop`
-`fastprop` supports Mac, Windows, and Linux on Python versions 3.8 to 3.12.
+`fastprop` supports Mac, Windows, and Linux on Python versions 3.8 or newer.
Installing from `pip` is the best way to get `fastprop`, but if you need to check out a specific GitHub branch or you want to contribute to `fastprop` a source installation is recommended.
Pending interest from users, a `conda` package will be added.
From 08b34ed51bcd48240852a5cb3af1c978e0925e41 Mon Sep 17 00:00:00 2001
From: JacksonBurns
Date: Thu, 16 Jan 2025 10:15:52 -0500
Subject: [PATCH 02/18] increment minor version pending some changes
---
pyproject.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index 3b3f890..9aacafa 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "fastprop"
-version = "1.0.6"
+version = "1.1.0"
authors = [
{ name = "Jackson Burns" },
]
From 5b0993360b2af5f74cd7adeee950cb842e2df83f Mon Sep 17 00:00:00 2001
From: JacksonBurns
Date: Thu, 16 Jan 2025 11:11:30 -0500
Subject: [PATCH 03/18] add support for molecular standardization
---
README.md | 1 +
examples/example_fastprop_train_config.yml | 2 ++
fastprop/cli/base.py | 4 +++-
fastprop/cli/predict.py | 3 ++-
fastprop/cli/train.py | 3 ++-
fastprop/data.py | 6 +++++-
fastprop/defaults.py | 1 +
7 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index fee48b8..520df7e 100644
--- a/README.md
+++ b/README.md
@@ -69,6 +69,7 @@ There are four distinct steps in `fastprop` that define its framework:
_or_
- Load precomputed descriptors: filepath to where descriptors are already cached either manually or by `fastprop`
2. Preprocessing
+ - standardize: call `rdkit`'s `rdMolStandardize.Cleanup` function on the input molecules before calculating descriptors (`False` by default)
- _not configurable_: `fastprop` will always rescale input features, set invariant and missing features to zero, and impute missing values with the per-feature mean
3. Training
- Number of Repeats: How many times to split/train/test on the dataset (increments random seed by 1 each time).
diff --git a/examples/example_fastprop_train_config.yml b/examples/example_fastprop_train_config.yml
index 081d56e..b461a83 100644
--- a/examples/example_fastprop_train_config.yml
+++ b/examples/example_fastprop_train_config.yml
@@ -26,6 +26,8 @@ optimize: False # True
#
# Which set of descriptors to calculate (either all or optimized)
descriptor_set: all
+# Call rdMolStandardize.Cleanup on molecules before calculating descriptors
+standardize: False
# Allow caching of descriptors
enable_cache: True
#
diff --git a/fastprop/cli/base.py b/fastprop/cli/base.py
index 7b3cdc1..e777836 100644
--- a/fastprop/cli/base.py
+++ b/fastprop/cli/base.py
@@ -32,6 +32,7 @@ def main():
train_subparser.add_argument("-tc", "--target-columns", nargs="+", help="column name(s) for target(s)")
train_subparser.add_argument("-sc", "--smiles-column", help="column name for SMILES")
train_subparser.add_argument("-ds", "--descriptor-set", help="descriptors to calculate (one of all, optimized, or debug)")
+ train_subparser.add_argument("-s", "--standardize", action="store_true", default=False, help="call rdMolStandardize.Cleanup function on molecules")
train_subparser.add_argument("-ec", "--enable-cache", type=bool, help="allow saving and loading of cached descriptors")
train_subparser.add_argument("-p", "--precomputed", help="precomputed descriptors from fastprop or mordred")
@@ -60,6 +61,7 @@ def main():
input_group.add_argument("-sf", "--smiles-file", help="file containing SMILES strings only")
input_group = predict_subparser.add_mutually_exclusive_group(required=True)
input_group.add_argument("-ds", "--descriptor-set", help="descriptors to calculate (one of all, optimized, or debug)")
+ input_group.add_argument("-s", "--standardize", action="store_true", default=False, help="call rdMolStandardize.Cleanup function on molecules")
input_group.add_argument("-pd", "--precomputed-descriptors", help="precomputed descriptors")
predict_subparser.add_argument("-o", "--output", required=False, help="output file for predictions (defaults to stdout)")
@@ -94,7 +96,7 @@ def main():
training_default = dict(DEFAULT_TRAINING_CONFIG)
optim_requested = args.pop("optimize")
if args["config_file"] is not None:
- if any(value is not None and arg_name not in {"clamp_input", "config_file"} for arg_name, value in args.items()):
+ if any(value is not None and arg_name not in {"clamp_input", "config_file", "standardize"} for arg_name, value in args.items()):
raise parser.error("Cannot specify config_file with other command line arguments (except --optimize).")
with open(args["config_file"], "r") as f:
cfg = yaml.safe_load(f)
diff --git a/fastprop/cli/predict.py b/fastprop/cli/predict.py
index 1848a81..e883ef9 100644
--- a/fastprop/cli/predict.py
+++ b/fastprop/cli/predict.py
@@ -20,6 +20,7 @@ def predict_fastprop(
checkpoints_dir: str,
smiles_strings: List[str],
descriptor_set: str,
+ standardize: bool = False,
smiles_file: Optional[str] = None,
precomputed_descriptors: Optional[np.ndarray] = None,
output: Optional[str] = None,
@@ -31,7 +32,7 @@ def predict_fastprop(
# load the models
if precomputed_descriptors is None:
- _, rdkit_mols, _ = clean_dataset(np.zeros((1, len(smiles_strings))), np.array(smiles_strings))
+ _, rdkit_mols, _ = clean_dataset(np.zeros((1, len(smiles_strings))), np.array(smiles_strings), standardize=standardize)
descs = get_descriptors(cache_filepath=False, descriptors=DESCRIPTOR_SET_LOOKUP[descriptor_set], rdkit_mols=rdkit_mols)
descs = descs.to_numpy(dtype=float)
else:
diff --git a/fastprop/cli/train.py b/fastprop/cli/train.py
index 94ef26f..ba75de6 100644
--- a/fastprop/cli/train.py
+++ b/fastprop/cli/train.py
@@ -66,6 +66,7 @@ def train_fastprop(
sampler: str,
random_seed: int,
patience: int,
+ standardize: bool,
hopt: bool = False,
):
if hopt and (tune is None or OptunaSearch is None):
@@ -93,7 +94,7 @@ def train_fastprop(
logger.info(f"Found cached descriptor data at {cache_file}, loading instead of recalculating.")
descriptors = load_saved_descriptors(cache_file)
else:
- targets, rdkit_mols, smiles = clean_dataset(targets, smiles)
+ targets, rdkit_mols, smiles = clean_dataset(targets, smiles, standardize=standardize)
descriptors = get_descriptors(enable_cache and cache_file, DESCRIPTOR_SET_LOOKUP[descriptor_set], rdkit_mols)
descriptors = descriptors.to_numpy(dtype=float)
diff --git a/fastprop/data.py b/fastprop/data.py
index e229181..16299d0 100644
--- a/fastprop/data.py
+++ b/fastprop/data.py
@@ -114,17 +114,21 @@ def inverse_standard_scale(data: torch.Tensor, means: torch.Tensor, variances: t
return data * variances.sqrt() + means
-def clean_dataset(targets: np.ndarray, smiles: np.ndarray):
+def clean_dataset(targets: np.ndarray, smiles: np.ndarray, standardize: bool = False):
"""Removes targets with missing values and SMILES which cannot be converted to molecules.
Args:
targets (np.ndarray): Targets corresponding to mols.
smiles (np.ndarray): SMILES corresponding to the targets.
+ standardize (bool, optional): Call rdMolStandardize.Cleanup on molecules. Default False.
Returns:
tuple[np.ndarray, np.ndarray]: Valid targets and RDKit Molecules.
"""
rdkit_mols = np.array(list(Chem.MolFromSmiles(i) for i in smiles))
+ if standardize:
+ for mol in rdkit_mols:
+ Chem.Cleanup(mol)
starting_length = len(rdkit_mols)
# remove dataset entries where the molecule could not be built
diff --git a/fastprop/defaults.py b/fastprop/defaults.py
index e348852..b9682df 100644
--- a/fastprop/defaults.py
+++ b/fastprop/defaults.py
@@ -59,6 +59,7 @@ def init_logger(module_name: str) -> logging.Logger:
hidden_size=1800,
hopt=False,
patience=5,
+ standardize=False,
)
)
From 2e6a2400dec4658632d6047715e210af51c5cb6f Mon Sep 17 00:00:00 2001
From: JacksonBurns
Date: Thu, 16 Jan 2025 11:20:40 -0500
Subject: [PATCH 04/18] clarify the choice of mordred as the featurizer
---
paper/paper.md | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/paper/paper.md b/paper/paper.md
index 5b1a0b7..407f472 100644
--- a/paper/paper.md
+++ b/paper/paper.md
@@ -144,7 +144,9 @@ At its core the `fastprop` 'architecture' is simply the `mordred` molecular desc
In the latter mode the user simply specifies a set of SMILES [@smiles], a linear textual encoding of molecules, and their corresponding properties.
`fastprop` automatically calculates and caches the corresponding molecular descriptors with `mordred`, re-scales both the descriptors and the targets appropriately, and then trains an FNN to predict the indicated target properties.
By default this FNN is two hidden layers with 1800 neurons each connected by ReLU activation functions, though the configuration can be readily changed via the command line interface or configuration file.
-`fastprop` owes its success to the cogent set of descriptors assembled by the developers of `mordred`, the ease of training FNNs with modern software like PyTorch Lightning, and the careful application of Research Software Engineering best practices that make it as user friendly as the best-maintained alternatives.
+`fastprop` principally owes its success to the cogent set of descriptors assembled by the developers of `mordred`.
+Multiple descriptor calculators from the very thorough review by McGibbon et al. [@representation_review] could be used instead, though none are as readily interoperable as `mordred`.
+Additionally, the ease of training FNNs with modern software like PyTorch Lightning and the careful application of Research Software Engineering best practices make `fastprop` as user friendly as the best-maintained alternatives.
![`fastprop` logo.\label{logo}](../fastprop_logo.png){ width=2in }
@@ -165,7 +167,6 @@ Most importantly this approach is successful on the _smallest_ of real-world dat
By starting from such an informed initialization the FNN can be readily trained on datasets with as few as _forty_ training examples (see [PAHs](#pahs)).
[^2]: The original `mordred` package is no longer maintained. `fastprop` uses a fork of `mordred` called `mordredcommunity` that is maintained by community-contributed patches (see github.com/JacksonBurns/mordred-community).
-Multiple descriptor calculators from the very thorough review by McGibbon et al. [@representation_review] could be used instead, though none are as readily interoperable as `mordred`.
## Example Usage
`fastprop` is built with ease of use at the forefront of design.
From 8516c46a7c6ed8c8f3876b8d4a06f991cd14f4c1 Mon Sep 17 00:00:00 2001
From: JacksonBurns
Date: Thu, 16 Jan 2025 11:24:26 -0500
Subject: [PATCH 05/18] clarify explicit support for multitask problems
---
paper/paper.md | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/paper/paper.md b/paper/paper.md
index 407f472..76cc5d1 100644
--- a/paper/paper.md
+++ b/paper/paper.md
@@ -140,10 +140,11 @@ For the purposes of this study, it will be used to refer to datasets with ~1000
# Implementation
At its core the `fastprop` 'architecture' is simply the `mordred` molecular descriptor calculator [^2] [@mordred] connected to a Feedforward Neural Network (FNN) implemented in PyTorch Lightning [@lightning] (Figure \ref{logo}) - an existing approach formalized into an easy-to-use, reliable, and correct implementation.
-`fastprop` is highly modular for seamless integration into existing workflows and includes end-to-end interfaces for general use.
-In the latter mode the user simply specifies a set of SMILES [@smiles], a linear textual encoding of molecules, and their corresponding properties.
-`fastprop` automatically calculates and caches the corresponding molecular descriptors with `mordred`, re-scales both the descriptors and the targets appropriately, and then trains an FNN to predict the indicated target properties.
-By default this FNN is two hidden layers with 1800 neurons each connected by ReLU activation functions, though the configuration can be readily changed via the command line interface or configuration file.
+`fastprop` is highly modular for seamless integration into existing workflows and includes and end-to-end Command Line Interface (CLI) for general use.
+In the latter mode the user simply specifies a set of SMILES [@smiles], a linear textual encoding of molecules, and their corresponding target values.
+`fastprop` automatically calculates and caches the corresponding molecular descriptors with `mordred`, re-scales both the descriptors and the targets appropriately, and then trains an FNN to predict the indicated targets.
+By default this FNN is two hidden layers with 1800 neurons each connected by ReLU activation functions, though the configuration can be readily changed via the CLI or configuration file.
+Multitask regression and multi-label classification are also supported and configurable in the same manner.
`fastprop` principally owes its success to the cogent set of descriptors assembled by the developers of `mordred`.
Multiple descriptor calculators from the very thorough review by McGibbon et al. [@representation_review] could be used instead, though none are as readily interoperable as `mordred`.
Additionally, the ease of training FNNs with modern software like PyTorch Lightning and the careful application of Research Software Engineering best practices make `fastprop` as user friendly as the best-maintained alternatives.
From 24bc50a1018808a04f1ddbf1255f51422c758dab Mon Sep 17 00:00:00 2001
From: JacksonBurns
Date: Thu, 16 Jan 2025 11:34:38 -0500
Subject: [PATCH 06/18] clarify existing support for SHAP anlysis of trained
fastprop models
---
paper/paper.md | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/paper/paper.md b/paper/paper.md
index 76cc5d1..ebd7295 100644
--- a/paper/paper.md
+++ b/paper/paper.md
@@ -162,7 +162,7 @@ Yalamanchi and coauthors used DL on `mordred` descriptors as part of a two-heade
The reason `fastprop` stands out from these studies and contradicts previous reports is for the simple reason that it works.
As discussed at length in the [Results & Discussion](#results--discussion) section, this approach matches the performance of leading LR approaches on common benchmark datasets and bespoke QSPR models on small real-world datasets.
`fastprop` also overcomes the limitations of LRs discussed above.
-Because all inputs to the FNN are physically meaningful molecular descriptors, intermediate representations in the FNN are also physically meaningful and can be directly interpreted.
+The FNN architecture and use of physically meaningful molecular descriptors enables the application of SHAP [@shap], a common tool for feature importance analysis (see [Interpretability](#interpretability)).
The simplicity of the framework enables domain experts to apply it easily and makes model training dramatically faster than LRs.
Most importantly this approach is successful on the _smallest_ of real-world datasets.
By starting from such an informed initialization the FNN can be readily trained on datasets with as few as _forty_ training examples (see [PAHs](#pahs)).
@@ -812,9 +812,11 @@ For example, in its current state `mordred` does not include any connectivity ba
While some of the 3D descriptors it implements could implicitly reflect sterochemistry, more explicit descriptors like the Stereo Signature Molecular Descriptor [@stereo_signature] may prove helpful in the future if re-implemented in `mordred`.
## Interpretability
-Though not discussed here for the sake of length, `fastprop` already contains the functionality to perform feature importance studies on trained models.
-By using SHAP values [@shap] to assign a scalar 'importance' to each of the input features, users can determine which of the `mordred` descriptors has the largest impact on model predictions.
-The utility of these values can be explored in greater detail on a case-by-case basis.
+Though not discussed here for the sake of length, `fastprop` contains the functionality to perform feature importance studies on trained models.
+By using SHAP values [@shap] once can assign a scalar 'importance' to each of the input features with respect to the target value, such as molecular weight having a significant positive impact on boiling point in alkanes.
+Experts users can leverage this information to guide molecular design and optimization or inform future lines of inquiry.
+Via the `fastprop` CLI users can train a model and then use `fastprop shap` to analyze the resulting trained network.
+`fastprop shap` will then generate diagrams to visualize the SHAP values.
# Availability
- Project name: fastprop
From d09a4b63dc455878cb44865bd014c55983c3a462 Mon Sep 17 00:00:00 2001
From: JacksonBurns
Date: Thu, 16 Jan 2025 12:06:18 -0500
Subject: [PATCH 07/18] stop using QOI; restructure abstract to focus more on
fastprop
---
paper/paper.md | 24 ++++++++++--------------
1 file changed, 10 insertions(+), 14 deletions(-)
diff --git a/paper/paper.md b/paper/paper.md
index ebd7295..34d2f10 100644
--- a/paper/paper.md
+++ b/paper/paper.md
@@ -41,19 +41,15 @@ note: |
# Abstract
-Quantitative Structure-Property Relationship studies (QSPR), often referred to interchangeably as QSAR, seek to establish a mapping between molecular structure and an arbitrary Quantity of Interest (QOI).
-Historically this was done on a QOI-by-QOI basis with new descriptors being devised by researchers to _specifically_ map to their QOI.
-A large number of descriptors have been invented, and can be computed using packages like DRAGON (later E-dragon), PaDEL-descriptor (and padelpy), Mordred, CODESSA, and many others.
-The sheer number of different descriptor packages resulted in the creation of 'meta-packages' which served only to aggregate these other calculators, including tools like molfeat, ChemDes, Parameter Client, and AIMSim.
-
-Generalizable descriptor-based modeling was a natural evolution of these meta-packages' development.
-Historically QSPR researchers focused almost exclusively on linear methods.
-Another community of researchers focused on finding nonlinear correlations between molecular structures and a QOI, often using Deep learning (DL).
-The DL community typically used molecular fingerprints instead of the complex descriptors popular in QSPR community.
-Recently the DL community has turned to learned representations primarily via message passing graph neural networks.
-This approach has proved remarkably effective but is not without drawbacks.
-Learning a representation requires large datasets to avoid over-fitting or even learn at all, loses interpretability since an embedding's meaning can only be induced retroactively, and needs significant execution time given the complexity of the underlying message passing algorithm.
-This paper introduces `fastprop`, a software package and general Deep-QSPR framework that combines a cogent set of molecular descriptors with DL to achieve state-of-the-art performance on datasets ranging from tens to tens of thousands of molecules.
+Quantitative Structure-Property Relationship studies (QSPR), often referred to interchangeably as QSAR, seek to establish a mapping between molecular structure and an arbitrary target property.
+Historically this was done on a target-by-target basis with new descriptors being devised to _specifically_ map to a given target.
+Today software packages exist that calculate thousands of these descriptors, enabling general modeling typically with classical and machine learning methods.
+Also present today are learned representation methods in which deep learning models generate a target-specific representation during training.
+The former requires less training data and offers improved speed and interpretability while the latter offers excellent generality, while the intersection of the two remains under-explored.
+
+This paper introduces `fastprop`, a software package and general Deep-QSPR framework that combines a cogent set of molecular descriptors with deep learning to achieve state-of-the-art performance on datasets ranging from tens to tens of thousands of molecules.
+`fastprop` provides both a user-friendly Command Line Interface and highly interoperable set of Python modules for the training and deployment of feedforward neural networks for property prediction.
+This approach yields improvements in speed and interpretability over existing methods without sacrificing performance.
`fastprop` is designed with Research Software Engineering best practices and is free and open source, hosted at github.com/jacksonburns/fastprop.
## Scientific Contribution
@@ -295,7 +291,7 @@ Only the results for Flash and PAH are statistically significant at 95% confiden
Originally described in Scientific Data [@qm9] and perhaps the most established property prediction benchmark, Quantum Machine 9 (QM9) provides quantum mechanics derived descriptors for many small molecules containing one to nine heavy atoms, totaling ~134k.
The data was retrieved from MoleculeNet [@moleculenet] in a readily usable format.
As a point of comparison, performance metrics are retrieved from the paper presenting the UniMol architecture [@unimol] previously mentioned.
-In that study they trained on only three especially difficult QOIs (homo, lumo, and gap) using scaffold-based splitting (a more challenging alternative to random splitting), reporting mean and standard deviation across 3 repetitions.
+In that study they trained on only three especially difficult targets (homo, lumo, and gap) using scaffold-based splitting (a more challenging alternative to random splitting), reporting mean and standard deviation across 3 repetitions.
`fastprop` achieves 0.0060 $\pm$ 0.0002 mean absolute error, whereas Chemprop achieves 0.00814 $\pm$ 0.00001 and the UniMol framework manages 0.00467 $\pm$ 0.00004.
This places the `fastprop` framework ahead of previous learned representation approaches but still trailing UniMol.
From 286d57202612ec6976ef5c68b560bc79e30ada30 Mon Sep 17 00:00:00 2001
From: JacksonBurns
Date: Thu, 16 Jan 2025 14:02:54 -0500
Subject: [PATCH 08/18] small comments as suggested by reviewer 3
---
paper/paper.bib | 12 ++++++++++++
paper/paper.md | 41 ++++++++++++++++++++---------------------
2 files changed, 32 insertions(+), 21 deletions(-)
diff --git a/paper/paper.bib b/paper/paper.bib
index 5f64af1..614b196 100644
--- a/paper/paper.bib
+++ b/paper/paper.bib
@@ -1,3 +1,15 @@
+@inbook{descriptors_book,
+ author = {Todeschini, Roberto and Consonni, Viviana},
+ year = {2009},
+ month = {07},
+ pages = {1252},
+ title = {Molecular Descriptors for Chemoinformatics},
+ volume = {1},
+ isbn = {978-3-527-31852-0},
+ journal = {Methods and principles in medicinal chemistry},
+ doi = {10.1002/9783527628766}
+}
+
@Article{muratov_qsar,
author ="Muratov, Eugene N. and Bajorath, Jürgen and Sheridan, Robert P. and Tetko, Igor V. and Filimonov, Dmitry and Poroikov, Vladimir and Oprea, Tudor I. and Baskin, Igor I. and Varnek, Alexandre and Roitberg, Adrian and Isayev, Olexandr and Curtalolo, Stefano and Fourches, Denis and Cohen, Yoram and Aspuru-Guzik, Alan and Winkler, David A. and Agrafiotis, Dimitris and Cherkasov, Artem and Tropsha, Alexander",
title ="QSAR without borders",
diff --git a/paper/paper.md b/paper/paper.md
index 34d2f10..4cbcc79 100644
--- a/paper/paper.md
+++ b/paper/paper.md
@@ -71,10 +71,9 @@ An abridged version of the history behind QSPR is presented here to contextualiz
## Historical Approaches
Early in the history of computing, limited computational power meant that significant human expertise was required to guide QSPR models toward effectiveness.
-This materialized in the form of bespoke molecular descriptors: the Wiener Index in 1947 [@wiener_index], Atom-Bond Connectivity indices in 1998 [@estrada_abc], and _thousands_ of others.
+This materialized in the form of bespoke molecular descriptors - scalar-valued functions which operate on the molecular graph in such a way to reflect relevant structural and electronic information.
+Examples include rudimentary counting descriptors, the Wiener Index in 1947 [@wiener_index], Atom-Bond Connectivity indices in 1998 [@estrada_abc], and many others [@descriptors_book].
To this day descriptors are still being developed - the geometric-harmonic-Zagreb degree based descriptors were proposed by Arockiaraj et al. in 2023 [@pah].
-In each case, domain experts devised an algorithm which mapped a molecular structure to some scalar value.
-This algorithm would take into account features of the molecule which that expert deduced were relevant to the property at hand.
This time consuming technique is of course highly effective but the dispersed nature of this chemical knowledge means that these descriptors are spread out throughout many journals and domains with no single source to compute them all.
The range of regression techniques applied to these descriptors has also been limited.
@@ -224,7 +223,7 @@ All of these `fastprop` benchmarks are reproducible, and complete instructions f
## Benchmark Methods
The method for splitting data into training, validation, and testing sets varies on a per-study basis and is described in each sub-section.
Sampling is performed using the `astartes` package [@astartes] which implements a variety of sampling algorithms and is highly reproducible.
-For datasets containing missing target values or invalid SMILES strings, those entries were dropped.
+For datasets containing missing target values or invalid SMILES strings, those entries were dropped, as is the default behavior of `fastprop`.
Results for `fastprop` are reported as the average value of a metric and its standard deviation across a number of repetitions (repeated re-sampling of the dataset).
The number of repetitions is chosen to either match referenced literature studies or else increased from two until the performance no longer meaningfully changes.
@@ -257,7 +256,7 @@ Those presented here are summarized below, first for regression:
and classification:
- Area Under the Receiver Operating Curve (AUROC, AUC, or ROC-AUC): Summary statistic combining all possible classification errors; scale-independent, range 0.5 (worst, random guessing) to 1.0 (perfect classifier).
- - Accuracy: Fraction of correct classifications, expressed as either a percentage or a number; scale-independent, range 0 (worst) to 1 (perfect classifier).
+ - Accuracy: Fraction of correct classifications, expressed as a percentage; scale-independent, range 0 (worst) to 100 (perfect classifier).
## Benchmark Results
See Table \ref{results_table} for a summary of all the results.
@@ -266,29 +265,29 @@ Subsequent sections explore each in greater detail.
Table: Summary of benchmark results, best state-of-the-art method vs. `fastprop` and Chemprop. \label{results_table}
+---------------+--------------------+-------------+--------------+------------+-------------------------+------+
-| Benchmark | Samples (k) | Metric | SOTA | `fastprop` | Chemprop | p |
+| Benchmark | Samples | Metric | SOTA | `fastprop` | Chemprop | p |
+===============+====================+=============+==============+============+=========================+======+
-|QM9 |~134 |MAE |0.0047$^a$ |0.0060 |0.0081$^a$ | ~ |
+|QM9 |133,885 |MAE |0.0047$^a$ |0.0060 |0.0081$^a$ | ~ |
+---------------+--------------------+-------------+--------------+------------+-------------------------+------+
-|Pgp |~1.3 |AUROC |0.94$^b$ |0.90 |0.89$^b$ | ~ |
+|Pgp |1,275 |AUROC |0.94$^b$ |0.90 |0.89$^b$ | ~ |
+---------------+--------------------+-------------+--------------+------------+-------------------------+------+
-|ARA |~0.8 |Accuracy |91$^c$ |88 |82* |0.083 |
+|ARA |842 |Accuracy |91$^c$ |88 |82* |0.083 |
+---------------+--------------------+-------------+--------------+------------+-------------------------+------+
-|Flash |~0.6 |RMSE |13.2$^d$ |13.0 |21.2* |0.021 |
+|Flash |632 |RMSE |13.2$^d$ |__13.0__ |21.2* |0.021 |
+---------------+--------------------+-------------+--------------+------------+-------------------------+------+
-|YSI |~0.4 |MAE |22.3$^e$ |25.0 |28.9* |0.29 |
+|YSI |442 |MAE |22.3$^e$ |25.0 |28.9* |0.29 |
+---------------+--------------------+-------------+--------------+------------+-------------------------+------+
-|PAH |~0.06 |R2 |0.96$^f$ |0.97 |0.59* |0.0012|
+|PAH |55 |R2 |0.96$^f$ |__0.97__ |0.59* |0.0012|
+---------------+--------------------+-------------+--------------+------------+-------------------------+------+
a [@unimol] b [@pgp_best] c [@ara] d [@flash] e [@ysi] f [@pah] * These reference results were generated for this study.
Statistical comparisons of `fastprop` to Chemprop (shown in the `p` column) are performed using the non-parametric Wilcoxon-Mann-Whitney Test as implemented in GNumeric.
Values are only shown for results generated in this study which are known to be performed using the same methods.
-Only the results for Flash and PAH are statistically significant at 95% confidence (p<0.05).
+Only the results for Flash and PAH are statistically significant at 95% confidence (p<0.05), see benchmark-specific subsections for confidence intervals.
### QM9
-Originally described in Scientific Data [@qm9] and perhaps the most established property prediction benchmark, Quantum Machine 9 (QM9) provides quantum mechanics derived descriptors for many small molecules containing one to nine heavy atoms, totaling ~134k.
+Originally described in Scientific Data [@qm9] and perhaps the most established property prediction benchmark, Quantum Machine 9 (QM9) provides quantum mechanics derived descriptors for many small molecules containing one to nine heavy atoms, totaling 133,885.
The data was retrieved from MoleculeNet [@moleculenet] in a readily usable format.
As a point of comparison, performance metrics are retrieved from the paper presenting the UniMol architecture [@unimol] previously mentioned.
In that study they trained on only three especially difficult targets (homo, lumo, and gap) using scaffold-based splitting (a more challenging alternative to random splitting), reporting mean and standard deviation across 3 repetitions.
@@ -380,7 +379,7 @@ test_gap_root_mean_squared_error_loss 3.0 1.556471e-02 8.
### Pgp
First reported in 2011 by Broccatelli and coworkers [@pgp], this dataset has since become a standard benchmark and is included in the Therapeutic Data Commons (TDC) [@tdc] model benchmarking suite.
-The dataset maps approximately 1.2k small molecule drugs to a binary label indicating if they inhibit P-glycoprotein (Pgp).
+The dataset maps 1,275 small molecule drugs to a binary label indicating if they inhibit P-glycoprotein (Pgp).
TDC serves this data through a Python package, but due to installation issues the data was retrieved from the original study instead.
The recommended splitting approach is a 70/10/20 scaffold-based split which is done here with 4 replicates.
@@ -424,11 +423,11 @@ test_binary_average_precision 4.0 0.925318 0.015881 0.911060 0.913512 0.
[^3]: See [the TDC Pgp leaderboard](https://tdcommons.ai/benchmark/admet_group/03pgp/).
### ARA
-Compiled by Schaduangrat et al. in 2023 [@ara], this dataset maps ~0.8k small molecules to a binary label indicating if the molecule is an Androgen Receptor Antagonist (ARA).
-The reference study introduced DeepAR, a highly complex modeling approach, which achieved an accuracy of 0.911 and an AUROC of 0.945.
+Compiled by Schaduangrat et al. in 2023 [@ara], this dataset maps 842 small molecules to a binary label indicating if the molecule is an Androgen Receptor Antagonist (ARA).
+The reference study introduced DeepAR, a highly complex modeling approach, which achieved an accuracy of 91.1% and an AUROC of 0.945.
For this study an 80/10/10 random splitting is repeated four times on the dataset since no analogous split to the reference study can be determined.
-Chemprop takes 16 minutes and 55 seconds to run on this dataset and achieves only 0.824 $\pm$ 0.020 accuracy and 0.898 $\pm$ 0.022 AUROC.
+Chemprop takes 16 minutes and 55 seconds to run on this dataset and achieves only 82.4 $\pm$ 2.0% accuracy and 0.898 $\pm$ 0.022 AUROC.
`fastprop` takes only 1 minute and 54 seconds (1 minute and 39 seconds for descriptor calculation) and is competitive with the reference study in performance, achieving a 88.2 $\pm$ 3.7% accuracy and 0.935 $\pm$ 0.034 AUROC.
The purely linear QSPR model falls far behind these methods with a 71.8 $\pm$ 6.6% accuracy and 0.824 $\pm$ 0.052 AUROC.
### Flash
-First assembled and fitted to by Saldana and coauthors [@flash] the dataset (Flash) includes around 0.6k entries, primarily alkanes and some oxygen-containing compounds, and their literature-reported flash point.
+First assembled and fitted to by Saldana and coauthors [@flash] the dataset (Flash) includes around 632 entries, primarily alkanes and some oxygen-containing compounds, and their literature-reported flash point.
The reference study reports the performance on only one repetition, but manually confirms that the distribution of points in the three splits follows the parent dataset.
The split itself was a 70/20/10 random split, which is repeated four times for this study.
@@ -561,7 +560,7 @@ Mean 21.17199532359917
Standard Error 1.1064790292313673 -->
### YSI
-Assembled by Das and coauthors [@ysi] from a collection of other smaller datasets, this dataset maps ~0.4k molecular structures to a unified-scale Yield Sooting Index (YSI), a molecular property of interest to the combustion community.
+Assembled by Das and coauthors [@ysi] from a collection of other smaller datasets, this dataset maps 442 molecular structures to a unified-scale Yield Sooting Index (YSI), a molecular property of interest to the combustion community.
The reference study performs leave-one-out cross validation to fit a per-fragment contribution model, effectively a training size of >99%, without a holdout set.
Though this is not standard practice and can lead to overly optimistic reported performance, the results will be carried forward regardless.
The original study did not report overall performance metrics, so they have been re-calculated for this study using the predictions made by the reference model as provided on GitHub [^4].
@@ -692,7 +691,7 @@ First described by Esaki and coauthors, the Fraction of Unbound Drug in the Brai
This specific target in combination with the small dataset size makes this benchmark highly relevant for typical QSPR studies, particular via delta learning.
DeepDelta [@deepdelta] performed a 90/0/10 cross-validation study of the Fubrain dataset in which the training and testing molecules were intra-combined to generate all possible pairs and then the differences in the property [^5] were predicted, rather than the absolute values, increasing the amount of training data by a factor of 300.
-DeepDelta reported an RMSE of 0.830 $\pm$ 0.023 at predicting differences, whereas a typical Chemprop model trained to directly predict property values was only able to reach an accuracy of 0.965 $\pm$ 0.019 when evaluated on its capacity to predict property differences.
+DeepDelta reported an RMSE of 0.830 $\pm$ 0.023 at predicting differences, whereas a typical Chemprop model trained to directly predict property values was only able to reach an accuracy of 96.5 $\pm$ 1.9% when evaluated on its capacity to predict property differences.
`fastprop` is able to outperform Chemprop, though not DeepDelta, achieving an RMSE of 0.930 $\pm$ 0.029 when using the same splitting procedure above.
It is evident that delta learning is still a powerful technique for regressing small datasets.
From 19d1db642132666727e96d32dbc26e5603a169b1 Mon Sep 17 00:00:00 2001
From: JacksonBurns
Date: Thu, 16 Jan 2025 14:31:57 -0500
Subject: [PATCH 09/18] editor note on additional benchmarks; shore up
performance claims
---
paper/additional_file_1.md | 45 ++++++++++++++++++++++++++++++++++++++
paper/paper.bib | 11 ++++++++++
paper/paper.md | 18 ++++++++++++---
3 files changed, 71 insertions(+), 3 deletions(-)
create mode 100644 paper/additional_file_1.md
diff --git a/paper/additional_file_1.md b/paper/additional_file_1.md
new file mode 100644
index 0000000..9e3cab0
--- /dev/null
+++ b/paper/additional_file_1.md
@@ -0,0 +1,45 @@
+---
+header-includes:
+- |
+ ```{=latex}
+ \usepackage{pdflscape}
+ \newcommand{\blandscape}{\begin{landscape}}
+ \newcommand{\elandscape}{\end{landscape}}
+ ```
+...
+
+
+# Additional File 1
+## Table S1
+
+The following table shows the performance (see Metric column) for Chemprop, Transformer-CNN, and `fastprop` across various open datasets.
+All datasets are retrieved from MoleculeNet, except Tox24 which was retrieved from [OChem.eu](https://ochem.eu/static/challenge.do).
+Benchmarks are sorted by size, descending.
+
+Each result is the average and standard deviation across five randomly selected train/val/test splits of 0.70/0.10/0.20.
+All models were trained with their default settings.
+Augmentation at training or inference time was not performed, although suggested for Transformer-CNN by its authors, to ensure a fair comparison is made.
+For Mean Absolute Error (MAE) and Root Mean Squared Error (RMSE) lower is better and for Receiver Operating Characteristic Area Under the Curve (ROC-AUC) higher is better.
+The Tukey test is used to check for pairwise statistical differences between the three models.
+The best performing model(s) which are statistically significantly different from the others are shown in bold.
+
+For further information about exact software versions for reproducing these results, see this GitHub repository which hosts both the training code and the results: [github.com/JacksonBurns/fastprop-benchmark](https://github.com/JacksonBurns/fastprop-benchmark).
+\newpage
+
+\blandscape
+
+| Dataset | Entries | Metric | Chemprop | Transformer-CNN | fastprop |
+|:-------------:|:-------:|:-------:|:--------:|:---------------:|:--------:|
+| HIV |41,127| ROC-AUC |\textbf{0.828(0.015)}|0.56(0.13)|\textbf{0.784(0.020)}|
+| QM8 |21,786| MAE |\textbf{0.0056(0.0001)}|0.0136(0.0004)|0.0164(0.0002)|
+| QM7 |6,834| MAE |68.1(2.7)|62.4(2.2)|\textbf{57.1(2.8)}|
+| Lipophilicity |4,200| RMSE |0.597(0.033)|\textbf{0.702(0.030)}|\textbf{0.736(0.020)}|
+| BBBP |2,050| ROC-AUC |0.918(0.016)|\textbf{0.9650(0.0032)}|0.903(0.013)|
+| BACE |1,513| ROC-AUC |0.856(0.010)|\textbf{0.899(0.016)}|\textbf{0.878(0.015)}|
+| ClinTox |1,484| ROC-AUC |\textbf{0.877(0.035)}|\textbf{0.9814(0.0083)}|0.64(0.13)|
+| SIDER |1,427| ROC-AUC |\textbf{0.662(0.039)}|\textbf{0.612(0.031)}|\textbf{0.629(0.016)}|
+| Tox24 |1,212| RMSE |\textbf{26.3(1.9)}|\textbf{25.0(1.1)}|\textbf{27.4(1.7)}|
+| ESOL |1,128| RMSE |\textbf{0.683(0.044)}|\textbf{0.701(0.057)}|\textbf{0.81(0.15)}|
+| FreeSolv |642| RMSE |\textbf{1.32(0.23)}|\textbf{1.50(0.23)}|\textbf{1.29(0.15)}|
+
+\elandscape
diff --git a/paper/paper.bib b/paper/paper.bib
index 614b196..3b7f97f 100644
--- a/paper/paper.bib
+++ b/paper/paper.bib
@@ -485,6 +485,17 @@ @article{hopv15_subset
pages = {23764-23775}
}
+@article{tcnn,
+ doi = {10.48550/ARXIV.1911.06603},
+ url = {https://arxiv.org/abs/1911.06603},
+ author = {Karpov, Pavel and Godin, Guillaume and Tetko, Igor V.},
+ keywords = {Quantitative Methods (q-bio.QM), Computation and Language (cs.CL), Machine Learning (cs.LG), FOS: Biological sciences, FOS: Biological sciences, FOS: Computer and information sciences, FOS: Computer and information sciences},
+ title = {Transformer-CNN: Fast and Reliable tool for QSAR},
+ publisher = {arXiv},
+ year = {2019},
+ copyright = {Creative Commons Attribution Non Commercial Share Alike 4.0 International}
+}
+
@article{hopv15_original,
title = {The Harvard organic photovoltaic dataset},
volume = {3},
diff --git a/paper/paper.md b/paper/paper.md
index 4cbcc79..446a7a0 100644
--- a/paper/paper.md
+++ b/paper/paper.md
@@ -36,6 +36,13 @@ note: |
--pdf-engine=pdflatex --pdf-engine-opt=-output-directory=foo
Which leaves the intermediate TeX file in the `foo` directory. I then manually
fix an image filepath which pandoc incorrectly leaves.
+note: |
+ Compile the additional file with:
+ pandoc --citeproc -s additional_file_1.md -o additional_file_1.pdf --template default.latex \
+ --pdf-engine=pdflatex --pdf-engine-opt=-output-directory=foo
+ or with the following, for arxiv:
+ pandoc --citeproc -s additional_file_1.md -o additional_file_1.pdf --template default.latex \
+ --pdf-engine=pdflatex --pdf-engine-opt=-output-directory=foo
---
@@ -49,7 +56,7 @@ The former requires less training data and offers improved speed and interpretab
This paper introduces `fastprop`, a software package and general Deep-QSPR framework that combines a cogent set of molecular descriptors with deep learning to achieve state-of-the-art performance on datasets ranging from tens to tens of thousands of molecules.
`fastprop` provides both a user-friendly Command Line Interface and highly interoperable set of Python modules for the training and deployment of feedforward neural networks for property prediction.
-This approach yields improvements in speed and interpretability over existing methods without sacrificing performance.
+This approach yields improvements in speed and interpretability over existing methods while statistically equaling or exceeding their performance across most of the tested benchmarks.
`fastprop` is designed with Research Software Engineering best practices and is free and open source, hosted at github.com/jacksonburns/fastprop.
## Scientific Contribution
@@ -123,6 +130,7 @@ Efforts are of course underway to address this limitation, though none are broad
One simple but incredibly computationally expensive approach is to use delta learning, which artificially increases dataset size by generating all possible _pairs_ of molecules from the available data (thus squaring the size of the dataset).
This was attempted by Nalini et al. [@deepdelta], who used an unmodified version of Chemprop referred to as 'DeepDelta' to predict _differences_ in molecular properties for _pairs_ of molecules.
They achieve increased performance over standard LR approaches but _lost_ the ability to train on large datasets due to simple runtime limitations.
+Another promising line of inquiry is the Transformer-CNN model of Karpov et al. [@tcnn], which leverages a pre-trained transformer model for prediction, circumventing the need for massive datasets and offering additional benefits in interpretability.
Other increasingly complex approaches are discussed in the outstanding review by van Tilborg et al. [@low_data_review].
While iterations on LRs and novel approaches to low-data regimes have been in development, the classical QSPR community has continued their work.
@@ -137,7 +145,7 @@ For the purposes of this study, it will be used to refer to datasets with ~1000
At its core the `fastprop` 'architecture' is simply the `mordred` molecular descriptor calculator [^2] [@mordred] connected to a Feedforward Neural Network (FNN) implemented in PyTorch Lightning [@lightning] (Figure \ref{logo}) - an existing approach formalized into an easy-to-use, reliable, and correct implementation.
`fastprop` is highly modular for seamless integration into existing workflows and includes and end-to-end Command Line Interface (CLI) for general use.
In the latter mode the user simply specifies a set of SMILES [@smiles], a linear textual encoding of molecules, and their corresponding target values.
-`fastprop` automatically calculates and caches the corresponding molecular descriptors with `mordred`, re-scales both the descriptors and the targets appropriately, and then trains an FNN to predict the indicated targets.
+`fastprop` optionally standardizes input molecule and then automatically calculates and caches the corresponding molecular descriptors with `mordred`, re-scales both the descriptors and the targets appropriately, and then trains an FNN to predict the indicated targets.
By default this FNN is two hidden layers with 1800 neurons each connected by ReLU activation functions, though the configuration can be readily changed via the CLI or configuration file.
Multitask regression and multi-label classification are also supported and configurable in the same manner.
`fastprop` principally owes its success to the cogent set of descriptors assembled by the developers of `mordred`.
@@ -155,7 +163,7 @@ Esaki and coauthors started a QSPR study with `mordred` descriptors for a datase
Yalamanchi and coauthors used DL on `mordred` descriptors as part of a two-headed representation, but their network architecture was sequential hidden layers _decreasing_ in size to only 12 features [@yalamanchi] as opposed to the constant 1800 in `fastprop`.
The reason `fastprop` stands out from these studies and contradicts previous reports is for the simple reason that it works.
-As discussed at length in the [Results & Discussion](#results--discussion) section, this approach matches the performance of leading LR approaches on common benchmark datasets and bespoke QSPR models on small real-world datasets.
+As discussed at length in the [Results & Discussion](#results--discussion) section, this approach statistically matches or exceeds the performance of leading LR approaches on common benchmark datasets and bespoke QSPR models on small real-world datasets.
`fastprop` also overcomes the limitations of LRs discussed above.
The FNN architecture and use of physically meaningful molecular descriptors enables the application of SHAP [@shap], a common tool for feature importance analysis (see [Interpretability](#interpretability)).
The simplicity of the framework enables domain experts to apply it easily and makes model training dramatically faster than LRs.
@@ -240,6 +248,10 @@ The insignificant time spent manually collating Chemprop results (Chemprop does
The coarse comparison of the two packages is intended to emphasize the scaling of LRs and Deep-QSPR and that `fastprop` is, generally speaking, much faster.
All models trained for this study were run on a Dell Precision series laptop with an NVIDIA Quadro RTX 4000 GPU and Intel Xeon E-2286M CPU.
+Because the diversity of methods across these different datasets complicates inter-dataset comparisons, an additional set of benchmarks using an identical method across all datasets is included in Additional File 1, Table S1.
+This benchmark compares `fastprop`, Chemprop, and the aforementioned Transformer-CNN, which is especially suitable for the small datasets included therein.
+No long-form commentary on benchmark results is provided, though the conclusions are largely the same as those shown here.
+
### Performance Metrics
The evaluation metrics used in each of these benchmarks are chosen to match literature precedent, particularly as established by MoleculeNet [@moleculenet], where available.
It is common to use scale-dependent metrics that require readers to understand the relative magnitude of the target variables.
From 6bf5a25a69f222ed369d7b4ef69189d501bf4668 Mon Sep 17 00:00:00 2001
From: JacksonBurns
Date: Thu, 16 Jan 2025 14:40:19 -0500
Subject: [PATCH 10/18] allow not using the whole cpu for mordred calculation
---
README.md | 3 +++
fastprop/descriptors.py | 7 ++++++-
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 520df7e..d5eadb4 100644
--- a/README.md
+++ b/README.md
@@ -103,6 +103,9 @@ After installation, `fastprop` is accessible from the command line via `fastprop
Try `fastprop --help` or `fastprop subcommand --help` for more information and see below.
+> [!TIP]
+> `fastprop` will use all of your CPUs for descriptor calculation by default - set the `MORDRED_NUM_PROC` environment variable to some other number to change this behavior.
+
### Configuration File [recommended]
See `examples/example_fastprop_train_config.yaml` for configuration files that show all options that can be configured during training.
It is everything shown in the [Configurable Parameters](#configurable-parameters) section.
diff --git a/fastprop/descriptors.py b/fastprop/descriptors.py
index 3154988..489e5f4 100644
--- a/fastprop/descriptors.py
+++ b/fastprop/descriptors.py
@@ -1,3 +1,4 @@
+import os
import datetime
from importlib.metadata import version
from time import perf_counter
@@ -14,6 +15,10 @@
logger = init_logger(__name__)
+_N_CPUS = psutil.cpu_count(logical=True)
+if (_n_cpus := int(os.environ.get("MORDRED_NUM_PROC", 0))) > 0:
+ _N_CPUS = _n_cpus
+
def _descriptor_names_to_mordred_class(string_list: List[str] = [], include_3d: bool = False):
"""Wraps a weird quirk of the mordred calculator library - descriptors must be passed
@@ -51,7 +56,7 @@ def _mols_to_desciptors(descriptors: List[Descriptor], rdkit_mols: List[rdchem.M
start = perf_counter()
mordred_calc = Calculator(descriptors)
logger.info("Calculating descriptors")
- mordred_descs = np.array(list(mordred_calc.map(rdkit_mols, nproc=psutil.cpu_count(logical=True), quiet=False)))
+ mordred_descs = np.array(list(mordred_calc.map(rdkit_mols, nproc=_N_CPUS, quiet=False)))
logger.info(f"Descriptor calculation complete, elapsed time: {str(datetime.timedelta(seconds=perf_counter() - start))}")
return mordred_descs
From 8a0b354074e8e5e2a5f0450115cd9f141299b0c1 Mon Sep 17 00:00:00 2001
From: JacksonBurns
Date: Thu, 16 Jan 2025 15:03:12 -0500
Subject: [PATCH 11/18] fix bug where hopt would not run if gpu not present
---
fastprop/cli/train.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/fastprop/cli/train.py b/fastprop/cli/train.py
index ba75de6..78d579a 100644
--- a/fastprop/cli/train.py
+++ b/fastprop/cli/train.py
@@ -146,6 +146,9 @@ def train_fastprop(
targets_ref = ray.put(targets)
descriptors_ref = ray.put(descriptors)
metric = fastprop.get_metric(problem_type)
+ resources = {"cpu": psutil.cpu_count()}
+ if torch.cuda.is_available():
+ resources["gpu"] = 1
tuner = tune.Tuner(
tune.with_resources(
lambda trial: _hopt_objective(
@@ -173,7 +176,7 @@ def train_fastprop(
target_columns,
output_subdirectory,
),
- resources={"gpu": 1, "cpu": psutil.cpu_count()},
+ resources=resources,
),
tune_config=tune.TuneConfig(
metric=metric,
From df073d2fa5f73e8fa43c7e17daff0ad8025e88b0 Mon Sep 17 00:00:00 2001
From: JacksonBurns
Date: Thu, 16 Jan 2025 15:03:25 -0500
Subject: [PATCH 12/18] expand on some possible drawbacks
---
paper/paper.bib | 20 ++++++++++++++++++++
paper/paper.md | 7 +++++++
2 files changed, 27 insertions(+)
diff --git a/paper/paper.bib b/paper/paper.bib
index 3b7f97f..e8557c5 100644
--- a/paper/paper.bib
+++ b/paper/paper.bib
@@ -470,6 +470,26 @@ @article{wu_photovoltaic
pages = {18991-19000}
}
+@Article{tetko_overfit,
+ author={Tetko, Igor V.
+ and van Deursen, Ruud
+ and Godin, Guillaume},
+ title={Be aware of overfitting by hyperparameter optimization!},
+ journal={Journal of Cheminformatics},
+ year={2024},
+ month={Dec},
+ day={09},
+ volume={16},
+ number={1},
+ pages={139},
+ abstract={Hyperparameter optimization is very frequently employed in machine learning. However, an optimization of a large space of parameters could result in overfitting of models. In recent studies on solubility prediction the authors collected seven thermodynamic and kinetic solubility datasets from different data sources. They used state-of-the-art graph-based methods and compared models developed for each dataset using different data cleaning protocols and hyperparameter optimization. In our study we showed that hyperparameter optimization did not always result in better models, possibly due to overfitting when using the same statistical measures. Similar results could be calculated using pre-set hyperparameters, reducing the computational effort by around 10,000 times. We also extended the previous analysis by adding a representation learning method based on Natural Language Processing of smiles called Transformer CNN. We show that across all analyzed sets using exactly the same protocol, Transformer CNN provided better results than graph-based methods for 26 out of 28 pairwise comparisons by using only a tiny fraction of time as compared to other methods. Last but not least we stressed the importance of comparing calculation results using exactly the same statistical measures.},
+ issn={1758-2946},
+ doi={10.1186/s13321-024-00934-w},
+ url={https://doi.org/10.1186/s13321-024-00934-w}
+}
+
+
+
@article{hopv15_subset,
title = {Predicting Power Conversion Efficiency of Organic Photovoltaics: Models and Data Analysis},
volume = {6},
diff --git a/paper/paper.md b/paper/paper.md
index 446a7a0..3db3823 100644
--- a/paper/paper.md
+++ b/paper/paper.md
@@ -698,6 +698,13 @@ sys 0m30.473s
# Limitations and Future Work
## Negative Results
+The `fastprop` framework is not without its drawbacks.
+The two subsequent sections explore in greater detail two specific cases where `fastprop` loses out to existing methods, but some general notes about out-of-distribution predictions and overfitting are also included here.
+Like all machine learning methods, `fastprop` is not intended to make predictions outside of its training feature space.
+The use of molecular descriptors, which can become out-of-distribution, may exacerbate this problem but `fastprop` can optionally winsorize the descriptors to counteract this issue.
+Additionally, hyperparameter optimization of machine learning models in cheminformatics has been known to cause overfitting [@tetko_overfit], especially on small datasets.
+Users should be cautious when optimizing `fastprop` models and rely on defaults when possible.
+
### Delta Learning with Fubrain
First described by Esaki and coauthors, the Fraction of Unbound Drug in the Brain (Fubrain) dataset is a collection of about 0.3k small molecule drugs and their corresponding experimentally measured unbound fraction in the brain, a critical metric for drug development [@fubrain].
This specific target in combination with the small dataset size makes this benchmark highly relevant for typical QSPR studies, particular via delta learning.
From fcac7925b792bc74a47bf6679bdef515231480a5 Mon Sep 17 00:00:00 2001
From: JacksonBurns
Date: Thu, 16 Jan 2025 15:06:45 -0500
Subject: [PATCH 13/18] clarify how to get to the datasets
---
paper/additional_file_1.md | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/paper/additional_file_1.md b/paper/additional_file_1.md
index 9e3cab0..5333c3b 100644
--- a/paper/additional_file_1.md
+++ b/paper/additional_file_1.md
@@ -13,9 +13,11 @@ header-includes:
## Table S1
The following table shows the performance (see Metric column) for Chemprop, Transformer-CNN, and `fastprop` across various open datasets.
-All datasets are retrieved from MoleculeNet, except Tox24 which was retrieved from [OChem.eu](https://ochem.eu/static/challenge.do).
-Benchmarks are sorted by size, descending.
+For further information about exact software versions for reproducing these results, see this GitHub repository which hosts both the training code and the results: [github.com/JacksonBurns/fastprop-benchmark](https://github.com/JacksonBurns/fastprop-benchmark).
+All datasets are retrieved from MoleculeNet, except Tox24 which was retrieved from [OChem.eu](https://ochem.eu/static/challenge.do) - direct links are provided in the aforementioned repository.
+
+Benchmarks are sorted by size, descending.
Each result is the average and standard deviation across five randomly selected train/val/test splits of 0.70/0.10/0.20.
All models were trained with their default settings.
Augmentation at training or inference time was not performed, although suggested for Transformer-CNN by its authors, to ensure a fair comparison is made.
@@ -23,7 +25,6 @@ For Mean Absolute Error (MAE) and Root Mean Squared Error (RMSE) lower is better
The Tukey test is used to check for pairwise statistical differences between the three models.
The best performing model(s) which are statistically significantly different from the others are shown in bold.
-For further information about exact software versions for reproducing these results, see this GitHub repository which hosts both the training code and the results: [github.com/JacksonBurns/fastprop-benchmark](https://github.com/JacksonBurns/fastprop-benchmark).
\newpage
\blandscape
From 7f13caca96cd9073d991b7eae9b8729224074abd Mon Sep 17 00:00:00 2001
From: JacksonBurns
Date: Thu, 16 Jan 2025 15:58:15 -0500
Subject: [PATCH 14/18] allow using entire dataset for training
---
README.md | 3 ++-
fastprop/data.py | 52 +++++++++++++++++++++++++++++++-----------------
2 files changed, 36 insertions(+), 19 deletions(-)
diff --git a/README.md b/README.md
index d5eadb4..2eac44f 100644
--- a/README.md
+++ b/README.md
@@ -77,7 +77,7 @@ There are four distinct steps in `fastprop` that define its framework:
_and_
- Number of FNN layers (default 2; repeated fully connected layers of hidden size)
- Hidden Size: number of neurons per FNN layer (default 1800)
- - Clamp Input: Enable/Disable input clamp to +/-3 to aid in extrapolation (default False).
+ - Clamp Input: Enable/Disable input clamp to +/-3 (winsorization) to aid in extrapolation (default False).
_or_
- Hyperparameter optimization: runs hyperparameter optimization identify the optimal number of layers and hidden size
@@ -87,6 +87,7 @@ There are four distinct steps in `fastprop` that define its framework:
- Learning rate
- Batch size
- Problem type (one of: regression, binary, multiclass (start labels from 0), multilabel)
+ - Training, Validation, and Testing fraction (set testing to zero to use all data for training and validation)
4. Prediction
- Input SMILES: either a single SMILES or file of SMILES strings on individual lines
- Output format: filepath to write the results or nothing, defaults to stdout
diff --git a/fastprop/data.py b/fastprop/data.py
index 16299d0..7acff0f 100644
--- a/fastprop/data.py
+++ b/fastprop/data.py
@@ -1,9 +1,10 @@
+
from typing import List, Literal, Optional, Tuple
import numpy as np
import torch
-from astartes import train_val_test_split
-from astartes.molecules import train_val_test_split_molecules
+from astartes import train_val_test_split, train_test_split
+from astartes.molecules import train_val_test_split_molecules, train_test_split_molecules
from rdkit import Chem
from torch.utils.data import DataLoader as TorchDataloader
from torch.utils.data import Dataset as TorchDataset
@@ -37,30 +38,45 @@ def split(
Returns:
tuple[np.ndarray, np.ndarray, np.ndarray]: Indices for training, validation, and testing.
"""
+ if sampler not in {"random", "scaffold"}:
+ raise TypeError(f"Unknown sampler {sampler=}.")
split_kwargs = dict(
train_size=train_size,
- val_size=val_size,
- test_size=test_size,
sampler=sampler,
random_state=random_seed,
return_indices=True,
)
if sampler == "random":
- (
- *_,
- train_idxs,
- val_idxs,
- test_idxs,
- ) = train_val_test_split(np.arange(len(smiles)), **split_kwargs)
+ if test_size:
+ (
+ *_,
+ train_idxs,
+ val_idxs,
+ test_idxs,
+ ) = train_val_test_split(np.arange(len(smiles)), test_size=test_size, val_size=val_size, **split_kwargs)
+ else:
+ (
+ *_,
+ train_idxs,
+ val_idxs,
+ ) = train_test_split(np.arange(len(smiles)), test_size=val_size, **split_kwargs)
+ test_idxs = np.array([])
elif sampler == "scaffold":
- (
- *_,
- train_idxs,
- val_idxs,
- test_idxs,
- ) = train_val_test_split_molecules(smiles, **split_kwargs)
- else:
- raise TypeError(f"Unknown sampler {sampler=}.")
+ if test_size:
+ (
+ *_,
+ train_idxs,
+ val_idxs,
+ test_idxs,
+ ) = train_val_test_split_molecules(smiles, test_size=test_size, val_size=val_size, **split_kwargs)
+ else:
+ (
+ *_,
+ train_idxs,
+ val_idxs,
+ ) = train_test_split_molecules(smiles, test_size=val_size, **split_kwargs)
+ test_idxs = np.array([])
+
return train_idxs, val_idxs, test_idxs
From 7b720fa4f4715b365d223a8d651b1e18cf44c833 Mon Sep 17 00:00:00 2001
From: JacksonBurns
Date: Thu, 16 Jan 2025 15:58:46 -0500
Subject: [PATCH 15/18] formatting
---
examples/oom_training.py | 3 +--
fastprop/cli/base.py | 4 +++-
fastprop/data.py | 3 +--
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/examples/oom_training.py b/examples/oom_training.py
index f8d79a4..8dd306d 100644
--- a/examples/oom_training.py
+++ b/examples/oom_training.py
@@ -227,8 +227,7 @@ def __init__(
# mock the target scaler used for reporting some human-readable metrics
self.target_scaler = SimpleNamespace(n_features_in_=1, inverse_transform=lambda i: np.array(i))
- def setup(self, stage=None):
- ... # skip feature scaling and dataset splitting
+ def setup(self, stage=None): ... # skip feature scaling and dataset splitting
def _init_dataloader(self, shuffle, idxs):
return TorchDataloader(
diff --git a/fastprop/cli/base.py b/fastprop/cli/base.py
index e777836..27c12ef 100644
--- a/fastprop/cli/base.py
+++ b/fastprop/cli/base.py
@@ -32,7 +32,9 @@ def main():
train_subparser.add_argument("-tc", "--target-columns", nargs="+", help="column name(s) for target(s)")
train_subparser.add_argument("-sc", "--smiles-column", help="column name for SMILES")
train_subparser.add_argument("-ds", "--descriptor-set", help="descriptors to calculate (one of all, optimized, or debug)")
- train_subparser.add_argument("-s", "--standardize", action="store_true", default=False, help="call rdMolStandardize.Cleanup function on molecules")
+ train_subparser.add_argument(
+ "-s", "--standardize", action="store_true", default=False, help="call rdMolStandardize.Cleanup function on molecules"
+ )
train_subparser.add_argument("-ec", "--enable-cache", type=bool, help="allow saving and loading of cached descriptors")
train_subparser.add_argument("-p", "--precomputed", help="precomputed descriptors from fastprop or mordred")
diff --git a/fastprop/data.py b/fastprop/data.py
index 7acff0f..ee90dc4 100644
--- a/fastprop/data.py
+++ b/fastprop/data.py
@@ -1,4 +1,3 @@
-
from typing import List, Literal, Optional, Tuple
import numpy as np
@@ -76,7 +75,7 @@ def split(
val_idxs,
) = train_test_split_molecules(smiles, test_size=val_size, **split_kwargs)
test_idxs = np.array([])
-
+
return train_idxs, val_idxs, test_idxs
From 2579d02dedf39d2b42ea866ef849f547d3684600 Mon Sep 17 00:00:00 2001
From: JacksonBurns
Date: Thu, 16 Jan 2025 16:01:53 -0500
Subject: [PATCH 16/18] allow disabling scaling, in case you already did it
outside of predict
---
fastprop/model.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/fastprop/model.py b/fastprop/model.py
index c5c2be1..eaa0bf9 100644
--- a/fastprop/model.py
+++ b/fastprop/model.py
@@ -161,17 +161,18 @@ def test_step(self, batch, batch_idx):
self._human_loss(y_hat, batch, "test")
return loss
- def predict_step(self, batch: Tuple[torch.Tensor]):
+ def predict_step(self, batch: Tuple[torch.Tensor], rescale: bool = True):
"""Applies feature scaling and appropriate activation function to a Tensor of descriptors.
Args:
batch (tuple[torch.Tensor]): Unscaled descriptors.
+ rescale (bool, optional): Apply rescaling according to trained means and vars. Default True.
Returns:
torch.Tensor: Predictions.
"""
descriptors = batch[0]
- if self.feature_means is not None and self.feature_vars is not None:
+ if rescale and self.feature_means is not None and self.feature_vars is not None:
descriptors = standard_scale(descriptors, self.feature_means, self.feature_vars)
with torch.inference_mode():
logits = self.forward(descriptors)
From f45906513fced73f206ea6990623aacf063a548c Mon Sep 17 00:00:00 2001
From: JacksonBurns
Date: Thu, 16 Jan 2025 16:09:31 -0500
Subject: [PATCH 17/18] delete trash file
---
benchmarks/pgp/benchmark_data.csv.1 | 63 -----------------------------
1 file changed, 63 deletions(-)
delete mode 100644 benchmarks/pgp/benchmark_data.csv.1
diff --git a/benchmarks/pgp/benchmark_data.csv.1 b/benchmarks/pgp/benchmark_data.csv.1
deleted file mode 100644
index 4fda611..0000000
--- a/benchmarks/pgp/benchmark_data.csv.1
+++ /dev/null
@@ -1,63 +0,0 @@
-Code,Set,Journal,Title,Authors,Year,Number,Volume,"First Page","Last Page"
-1,Internal,"Biochem. Biophys. Res. Commun.","Reversal of P-glycoprotein-mediated MDR by 5,7,3',4',5'-pentamethoxyflavone and SAR","Choi, C.H.; Kim, J.H.; Kim, S.H.",2004,320,3,672,679
-2,Internal,"Chem. Res. Toxicol.","Quantitative distinctions of active site molecular recognition by P-glycoprotein and cytochrome P450 3A4","Wang, E.; Lew, K.; Barecki, M.; Casciano, C.N.; Clement, R.P.; Johnson, W.W.",2001,14,12,1596,1603
-3,Internal,"Clin. Cancer Res.","VX-710 (biricodar) increases drug retention and enhances chemosensitivity in resistant cells overexpressing P-glycoprotein, multidrug resistance protein, and breast cancer resistance protein","Minderman, H.; O'Loughlin, K.L.; Pendyala, L.; Baer, M.R.",2004,10,5,1826,1834
-4,Internal,"Drug Metab. Dispos.","Mibefradil is a P-glycoprotein substrate and a potent inhibitor of both P-glycoprotein and CYP3A in vitro","Wandel, C.; Kim, R.B.; Guengerich, F.P.; Wood, A.J.",2000,28,8,895,898
-5,Internal,"Drug Metab. Dispos.","The anthelminthic agent albendazole does not interact with p-glycoprotein","Merino, G.; Alvarez, A.I.; Prieto, J.G.; Kim, R.B.",2002,30,4,365,369
-6,Internal,"Drug Metab. Dispos.","Differential interaction of 3-hydroxy-3-methylglutaryl-coa reductase inhibitors with ABCB1, ABCC2, and OATP1B1","Chen, C.; Mireles, R.J.; Campbell, S.D.; Lin, J.; Mills, J.B.; Xu, J.J.; Smolarek, T.A.",2005,33,4,537,546
-7,Internal,"Drug Metab. Dispos.","In vitro p-glycoprotein inhibition assays for assessment of clinical drug interaction potential of new drug candidates: a recommendation for probe substrates","Rautio, J.; Humphreys, J.E.; Webster, L.O.; Balakrishnan, A.; Keogh, J.P.; Kunta, J.R.; Serabjit-Singh, C.J.; Polli, J.W.",2006,34,5,786,792
-8,Internal,"Drug Metab. Dispos.","In vitro P-glycoprotein assays to predict the in vivo interactions of P-glycoprotein with drugs in the central nervous system","Feng, B.; Mills, J.B.; Davidson, R.E.; Mireles, R.J.; Janiszewski, J.S.; Troutman, M.D.; de Morais, S.M.",2008,36,2,268,275
-9,Internal,"Eur. J. Pharm. Sci.","Inhibitory effects of CYP3A4 substrates and their metabolites on P-glycoprotein-mediated transport.","Katoh, M.; Nakajima, M.; Yamazaki, H.; Yokoi, T.",2001,12,4,505,513
-10,Internal,"Eur. J. Pharm. Sci.","Development, validation and utility of an in vitro technique for assessment of potential clinical drug-drug interactions involving P-glycoprotein","Keogh, J.P.; Kunta, J.R.",2006,27,5,543,554
-11,Internal,"Eur. J. Pharm. Sci.","The potential inhibitory effect of antiparasitic drugs and natural products on P-glycoprotein mediated efflux","Hayeshi, R.; Masimirembwa, C.; Mukanganyama, S.; Ungell, A.L.",2006,29,1,70,81
-13,Internal,"Cancer Res.","Reversal of P-glycoprotein-mediated multidrug resistance by a potent cyclopropyldibenzosuberane modulator, LY335979","Dantzig, A.H.; Shepard, R.L.; Cao, J.; Law, K.L.; Ehlhardt, W.J.; Baughman, T.M.; Bumol, T.F.; Starling, J.J.",1996,56,18,4171,4179
-14,Internal,"Jpn. J. Pharmacol.","Reversal of multidrug resistance in human leukemia K562 by tamolarizine, a novel calcium antagonist","Miyake, N.; Fujita, R.; Ishikawa, M.; Takayanagi, M.; Takayanagi, Y.; Sasaki, K.",2000,86,3,265,268
-15,Internal,"J. Med. Chem.","Comparison of in vitro P-glycoprotein screening assays: recommendations for their use in drug discovery","Schwab, D.; Fischer, H.; Tabatabaei, A.; Poli, S.; Huwyler, J.",2003,46,9,1716,1725
-16,Internal,"J. Med. Chem.","Substituted 4-acylpyrazoles and 4-acylpyrazolones: synthesis and multidrug resistance-modulating activity","Chiba, P.; Holzer, W.; Landau, M.; Bechmann, G.; Lorenz, K.; Plagens, B.; Hitzler, M.; Richter, E.; Ecker, G.",1998,41,21,4001,4011
-17,Internal,"J. Pharm. Sci.","Characterization of dexloxiglumide in vitro biopharmaceutical properties and active transport","Tolle-Sander, S.; Grill, A.; Joshi, H.; Kapil, R.; Persiani, S.; Polli, J.E.",2003,92,10,1968,1980
-18,Internal,"J. Pharm. Sci.","Limited influence of P-glycoprotein on small-intestinal absorption of cilostazol, a high absorptive permeability drug","Toyobuku, H.; Tamai, I.; Ueno, K.; Tsuji, A.",2003,92,11,2249,2259
-19,Internal,"J. Biomol. Screening","High-Throughput Screening for Daunorubicin-Mediated Drug Resistance Identifies Mometasone Furoate as a Novel ABCB1-Reversal Agent","Winter, S.S.; Lovato, M.L.; Khawaja, H.M.; Edwards B.S.; Steele I.D.; Young, S.M.; Oprea, T.I.; Skylar, L.A.; Larson, R.S.",2008,13,3,185,193
-20,Internal,"J. Pharmacol. Exp. Ther.","Characterization of the major metabolites of verapamil as substrates and inhibitors of P-glycoprotein","Pauli-Magnus, C.; von Richter, O.; Burk, O.; Ziegler, A.; Mettang, T.; Eichelbaum, M.; Fromm, M.F.",2000,293,2,376,378
-21,Internal,"J. Pharmacol. Exp. Ther.","Rational use of in vitro P-glycoprotein assays in drug discovery","Polli, J.W.; Wring, S.A.; Humphreys, J.E.; Huang, L.; Morgan, J.B.; Webster, L.O.; Serabjit-Singh, C.S.",2001,299,2,620,628
-22,Internal,"J. Pharmacol. Exp. Ther.","Passive permeability and P-glycoprotein-mediated efflux differentiate central nervous system (CNS) and non-CNS marketed drugs","Mahar Doan, K.M.; Humphreys, J.E.; Webster, L.O.; Wring, S.A.; Shampine, L.J.; Serabjit-Singh, C.J.; Adkison, K.K.; Polli, J.W.",2002,303,3,1029,1037
-23,Internal,"J. Pharmacol. Exp. Ther.","Characterization of P-glycoprotein inhibition by major cannabinoids from marijuana","Zhu, H.J.; Wang, J.S.; Markowitz, J.S.; Donovan, J.L.; Gibson, B.B.; Gefroh, H.A.; Devane, C.L.",2006,317,2,850,857
-24,Internal,"J. Vet. Pharmacol. Ther.","Selamectin is a potent substrate and inhibitor of human and canine P-glycoprotein","Griffin, J.; Fletcher, N.; Clemence, R.; Blanchflower, S.; Brayden, D.J.",2005,28,3,257,265
-25,Internal,"Mol. Pharmacol.","Three-dimensional quantitative structure-activity relationships of inhibitors of P-glycoprotein","Ekins, S.; Kim, R.B.; Leake, B.F.; Dantzig, A.H.; Schuetz, E.G.; Lan L.B.; Yasuda K.; Shepard, R.L.; Winter, M.A.; Schuetz, J.D.; Wikel, J.H.; Wrighton, S.A.",2002,61,5,964,973
-26,Internal,"Mol. Pharmacol.","Application of three-dimensional quantitative structure-activity relationships of P-glycoprotein inhibitors and substrates","Ekins, S.; Kim, R.B.; Leake, B.F.; Dantzig, A.H.; Schuetz, E.G.; Lan, L.B.; Yasuda, K.; Shepard, R.L.; Winter, M.A.; Schuetz, J.D.; Wikel, J.H.; Wrighton, S.A.",2002,61,5,974,981
-27,Internal,"Naunyn-Schmiedeberg's Arch. Pharmacol.","A novel screening strategy to identify ABCB1 substrates and inhibitors","von Richter, O.; Glavinas, H.; Krajcsi, P.; Liehner, S.; Siewert, B.; Zech, K.",2009,379,1,11,26
-28,Internal,http://pdsp.med.unc.edu/indexR.html,,,,,,,
-29,Internal,"Pfluegers Arch.","P-glycoprotein inhibition by glibenclamide and related compounds","Golstein, P.E.; Boom, A.; van Geffel, J.; Jacobs, P.; Masereel, B.; Beauwens, R.",1999,437,5,652,660
-30,Internal,"Pharm. Res.","Chemogenomic analysis identifies geldanamycins as substrates and inhibitors of ABCB1","Huang, Y.; Blower, P.E.; Liu, R.; Dai, Z.; Pham, A.N.; Moon, H.; Fang, J.; Sadée, W.",2007,24,9,1702,1712
-31,Internal,"Pharm. Res.","Interrelationship between substrates and inhibitors of human CYP3A and P-glycoprotein","Kim, R.B.; Wandel, C.; Leake, B.; Cvetkovi,c M.; Fromm, M.F.; Dempsey, P.J.; Roden, M.M.; Belas, F.; Chaudhary, A.K.; Roden, D.M.; Wood, A.J.; Wilkinson, G.R.",1999,16,3,408,414
-32,Internal,"Pharm. Res.","Rapid assessment of P-glycoprotein inhibition and induction in vitro","Perloff, M.D.; Störmer, E.; von Moltke, L.L.; Greenblatt, D.J.",2003,20,8,1177,1184
-33,Internal,Psychopharmacology,"Evaluation of antipsychotic drugs as inhibitors of multidrug resistance transporter P-glycoprotein","Wang, J.S.; Zhu, H.J.; Markowitz, J.S.; Donovan, J.L.; DeVane, C.L.",2006,187,4,415,423
-34,Internal,"Toxicol. Appl. Pharmacol.","Interaction of structurally diverse pesticides with the human MDR1 gene product P-glycoprotein","Bain, L.J.; LeBlanc, G.A.",1996,141,1,288,298
-35,Internal,"Cancer Lett.","Reversal of P-glycoprotein mediated multidrug resistance by a newly synthesized 1,4-benzothiazipine derivative, JTV-519","Che, X.F.; Nakajima, Y.; Sumizawa, T.; Ikeda, R.; Ren, X.Q.; Zheng, C.L.; Mukai, M.; Furukawa, T.; Haraguchi, M.; Gao, H.; Sugimoto, Y.; Akiyama S.",2002,187,1,111,119
-36,Internal,Blood,"Comparative evaluation of S9788, verapamil, and cyclosporine A in K562 human leukemia cell lines and in P-glycoprotein-expressing samples from patients with hematologic malignancies","Merlin, J.L.; Guerci, A.; Marchal, S.; Missoum, N.; Ramacci, C.; Humbert, J.C.; Tsuruo, T.; Guerci, O.",1994,84,1,262,269
-37,Internal,"Biochem. Pharmacol.","Mechanism of action of dexniguldipine-HCl (B8509-035), a new potent modulator of multidrug resistance","Hofmann, J.; Gekeler, V.; Ise, W.; Noller, A.; Mitterdorfer, J.; Hofer, S.; Utz, I.; Gotwald, M.; Boer, R.; Glossmann, H. Grunicke, H.H.",1995,49,5,603,609
-38,Internal,"Cancer Chemother. Pharmacol.","New multidrug-resistance-reversing drugs, MS-209 and SDZ PSC 833","Naito, M.; Tsuruo, T.",1997,40,S,20,24
-39,Internal,"Biochem. Pharmacol.","Structure-activity relationship of verapamil analogs and reversal of multidrug resistance","Toffoli, G.; Simone, F.; Corona, G.; Raschack, M.; Cappelletto, B.; Gigante, M.; Boiocchi, M.",1995,50,8,1245,1255
-40,Internal,"Cancer Res.","P-glycoprotein and cytochrome P-450 3A inhibition: dissociation of inhibitory potencies","Wandel, C.; Kim, R.B.; Kajiji, S.; Guengerich, P.; Wilkinson, G.R.; Wood, A.J.",1999,59,16,3944,3948
-41,Internal,"Eur. J. Pharmacol.","Selective inhibition of MDR1 (ABCB1) by HM30181 increases oral bioavailability and therapeutic efficacy of paclitaxel","Kwak, J.O.; Lee, S.H.; Lee, G.S.; Kim, M.S.; Ahn, Y.G.; Lee, J.H.; Kim, S.W.; Kim, K.H.; Lee, M.G.",2010,627,1,92,98
-42,External,"J. Med. Chem.","A comparative molecular field analysis (CoMFA) and comparative molecular similarity indices analysis (CoMSIA) of anthranilamide derivatives that are multidrug resistance modulators","Labrie, P.; Maddaford, S.P.; Fortin, S.; Rakhit, S.; Kotra, L.P.; Gaudreault, R.C.",2006,49,26,7646,7660
-43,External,"J. Med. Chem.","Studies on pyrrolopyrimidines as selective inhibitors of multidrug-resistance-associated protein in multidrug resistance","Wang, S.; Folkes, A.; Chuckowree, I.; Cockcroft, X.; Sohal, S.; Miller, W.; Milton, J.; Wren, S.P.; Vicker, N.; Depledge, P.; Scott, J.; Smith, L.; Jones, H.; Mistry, P.; Faint, R.; Thompson, D.; Cocks, S.",2004,47,6,1329,1338
-44,External,"J. Med. Chem.","Three-dimensional quantitative structure-activity relationship analysis of propafenone-type multidrug resistance modulators: influence of variable selection on test set predictivity","Fleischer, R.; Wiese, M.",2003,46,23,4988,5004
-45,External,"J. Med. Chem.","Substituted 4-acylpyrazoles and 4-acylpyrazolones: synthesis and multidrug resistance-modulating activity","Chiba, P.; Holzer, W.; Landau, M.; Bechmann, G.; Lorenz, K.; Plagens, B.; Hitzler, M.; Richter, E.; Ecker, G.",1998,41,21,4001,4011
-46,External,"J. Med. Chem.","Synthesis and in vitro multidrug resistance modulating activity of a series of dihydrobenzopyrans and tetrahydroquinolines","Hiessböck, R.; Wolf, C.; Richter, E.; Hitzler, M.; Chiba, P.; Kratzel, M.; Ecker, G.",1999,42,11,1921,1926
-47,External,"J. Med. Chem.","Synthesis and biological evaluation of (hetero)arylmethyloxy- and arylmethylamine-phenyl derivatives as potent P-glycoprotein modulating agents","Colabufo, N.A.; Berardi, F.; Perrone, R.; Rapposelli, S.; Digiacomo, M.; Vanni, M.; Balsamo, A.",2008,51,5,1415,1422
-49,External,"J. Med. Chem.","Biological evaluation of bishydroxymethyl-substituted cage dimeric 1,4-dihydropyridines as a novel class of p-glycoprotein modulating agents in cancer cells","Richter, M.; Molnár, J.; Hilgeroth, A.",2006,49,9,2838,2840
-51,External,"J. Med. Chem.","New potent P-glycoprotein inhibitors carrying a polycyclic scaffold","Bisi, A.; Gobbi, S.; Rampa, A.; Belluti, F.; Piazzi, L.; Valenti, P.; Gyemant, N.; Molnár, J.",2006,49,11,3049,3051
-52,External,"Bioorg. Med. Chem. Lett.","Synthesis and evaluation of hapalosin and analogs as MDR-reversing agents","O'Connell, C.E.; Salvato, K.A.; Meng, Z.; Littlefield, B.A.; Schwartz, C.E.",1999,9,11,1541,1546
-53,External,"Eur. J. Med. Chem.","Anti-calmodulin acridone derivatives modulate vinblastine resistance in multidrug resistant (MDR) cancer cells","Hegde, R.; Thimmaiah, P.; Yerigeri, M.C.; Krishnegowda, G.; Thimmaiah, K.N.; Houghton, P.J.",2004,39,2,161,167
-54,External,"Bioorg. Med. Chem. Lett.","2,4,5-Trisubstituted imidazoles: novel nontoxic modulators of P-glycoprotein mediated multidrug resistance. Part 1","Sarshar, S.; Zhang, C.; Moran, E.J.; Krane, S.; Rodarte, J.C.; Benbatoul, K.D.; Dixon, R.; Mjalli, A.M.",2000,10,23,2599,2601
-55,External,"Bioorg. Med. Chem. Lett.","2,4,5-Trisubstituted imidazoles: novel nontoxic modulators of P-glycoprotein mediated multidrug resistance. Part 2","Zhang, C.; Sarshar, S.; Moran, E.J.; Krane, S.; Rodarte, J.C.; Benbatoul, K.D.; Dixon, R.; Mjalli, A.M.",2000,10,23,2603,2605
-56,External,"Bioorg. Med. Chem.","In vitro activity of novel dual action MDR anthranilamide modulators with inhibitory activity on CYP-450 (Part 2)","Labrie, P.; Maddaford, S.P.; Lacroix, J.; Catalano, C.; Lee, D.K.; Rakhit, S.; Gaudreault, R.C.",2007,15,11,3854,3856
-57,External,"Bioorg. Med. Chem.","Functional assay and structure-activity relationships of new third-generation P-glycoprotein inhibitors","Müller, H.; Pajeva, I.K.; Globisch, C.; Wiese, M.",2008,16,5,2448,2462
-58,External,"Bioorg. Med. Chem.","New derivatives of silybin and 2,3-dehydrosilybin and their cytotoxic and P-glycoprotein modulatory activity","Dzubák, P.; Hajdúch, M.; Gazák, R.; Svobodová, A.; Psotová, J.; Walterová, D.; Sedmera, P.; Kren, V.",2006,14,11,3793,3810
-59,External,"Bioorg. Med. Chem.","New functional assay of P-glycoprotein activity using Hoechst 33342","Müller, H.; Klinkhammer, W.; Globisch, C.; Kassack, M.U.; Pajeva, I.K.; Wiese, M.",2007,15,23,7470,7479
-60,External,"Mol. Pharmacol.","Quantitative structure-activity relationship of multidrug resistance reversal agents","Klopman, G.; Shi, L.M.; Ramu, A.",1997,52,2,323,324
-61,Internal,"J. Med. Chem.","Increased anti-P-glycoprotein activity of baicalein by alkylation on the A ring","Lee, Y.; Yeo, H.; Liu, S.H.; Jiang, Z.; Savizky, R.M.; Austin, D.J.; Cheng, Y.C.",2004,47,22,5555,5566
-62,Internal,"J. Med. Chem.","Self-organizing maps for identification of new inhibitors of P-glycoprotein","Kaiser, D.; Terfloth, L.; Kopp, S.; Schulz, J.; de Laet, R.; Chiba, P.; Ecker, G.F.; Gasteiger, J.",2007,50,7,1698,1702
-63,Internal,"J. Med. Chem.","2-[(3-Methoxyphenylethyl)phenoxy]-based ABCB1 inhibitors: effect of different basic side-chains on their biological properties","Colabufo, N.A.; Berardi, F.; Perrone, R.; Rapposelli, S.; Digiacomo, M.; Vanni, M.; Balsamo, A.",2008,51,23,7602,7612
-64,Internal,"J. Med. Chem.","C-7 analogues of progesterone as potent inhibitors of the P-glycoprotein efflux pump","Leonessa, F.; Kim, J.H.; Ghiorghis, A.; Kulawiec, R.J.; Hammer, C.; Talebian, A.; Clarke, R.",2002,45,2,390,398
-65,External,"J. Med. Chem.","Flavonoid dimers as bivalent modulators for P-glycoprotein-based multidrug resistance: synthetic apigenin homodimers linked with defined-length poly(ethylene glycol) spacers increase drug retention and enhance chemosensitivity in resistant cancer cells","Chan, K.F.; Zhao, Y.; Burkett, B.A.; Wong, I.L.; Chow, L.M.; Chan, T.H.",2006,49,23,6742,6759
From 01ac0269e6929b594e18405a7c59a86c31079367 Mon Sep 17 00:00:00 2001
From: JacksonBurns
Date: Thu, 16 Jan 2025 16:24:28 -0500
Subject: [PATCH 18/18] re-render PDFs
---
paper/additional_file_1.pdf | Bin 0 -> 106671 bytes
paper/paper.pdf | Bin 603619 -> 606546 bytes
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 paper/additional_file_1.pdf
diff --git a/paper/additional_file_1.pdf b/paper/additional_file_1.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..6eb04488202131fc743cdc944d813620531d8b70
GIT binary patch
literal 106671
zcma%?Ly#~4uVve|ZQHhO+qP}@*S2ljwr$(C=YONkTg+sYTiKs`E2)qwh=|cL(y>C3
z&M%LwLoqTCFc8=qSwZpeK+(&X+L^mp5HPZ^GZOsIf}$6*v~e+YBA^$uF?2B%F*UX~
zF@@segK~CpGBvb?^4RoMm$u*HKlCwwH`|QzW3BFD<*lGl^`C94|~O
zPIUACnRTETvrO#K$R^~Z_j{@zcgq;(>qYMKt-IaT^--XjLQSirYV5L2m7ch&oTzL(
z4W()7BK(Thtu>hq8vrpbv(u?D)op|~TW+3I_uum+;^efSVwyzU=#1~4AeC&_Zi#Zu
zI+<*95ogn!+Nvxsw4w_MiYA&W!lat3>^>F>`UgC@eq>v3Vm-D{8x_WzX(?VEZ!)xa
zXIN(z$9F^17F)%tvtZXXnc*64ceykQuLxB~tXQuNyETxJJH8t$Fc%I9cQU-GCH_|X
z_UYjA3IV=b#BK2Ed=z?IXqWgVm;n|gPC0i(h%%>*f+gI3
z;}dbICnlG|Q@89?f0gsH;5~t-W;(%Tew~fM77AFMF7YuRI(xOx`Oz=xcnT&|U?b2?
zH4z72Rce3%n3870%?)8sg2KFnHWY
z>>0nG1e6uR4O=VjIJ7;cK4z
zHBAn)HgY(IU*)Q)Vq-2qOp(jp-4-4#uNw#0{pQx0xpPd9He5Zy$D8mGKD*-_uW)wl
zgd=$m1XOr0I!`ySb?V-wG8O%aqBf2qI|nuk>!2+d#NpkqI%{`R{^hxxXROpyX8Y5$
zHYNa0KrMx){9#@Y0U8L#to_f4#Ifl~B>M_G;-&Z+`jmK$S@8-T6SF3bHBB_?(jZ$*
zz)0(#S*JWE(m_OIU<9x%yjjGg!IaFiEGy_Nkid(eya!yMJopMUgy3yoj-KZfX|ZSX
z#pQPbg6_HRG`xn#6_AwzLN09XXUhAje#|@_VMfc{0FDQA04|RcY(e{lTz%*e2qBVD
zA{Y=&j{=#|9@uJr$th=RmPhz_C)Y!;i28C|M$&k)SEg
zwc)pD@>)RFIh7J)G+lXO47%V~yd17La-u|+F2EO1LnUp8m68u=-AL#@=Pyc-F%}yo
zw8;cq#qjw8@=*d+A{iBykUWfby3a!cq1Py)^ZXW_7&;`rBD~0Ky_*bo-??zblih%9
zn;&&|WkNTNk_TmKBiJ(NCtnJBv5|HqVzG98dM7p>Q+RWs(N$!+4U&*RXlsP5Wj~H>
zK4FZZ{n<`#?7L@MaJl$g;Beu0)WH0MN{%xHby=*s!Wef8_iz$NaIL`upekUA16T~5
zngyts_TlBkT!?sVbh4H#K((
z36*Q7qZpz;3Yi16OcWuS+d8*Tn(5(j~H*~Kf0
zn`>M44v!=aW<|2Th>mZiJC&!ZOx#|&EfwGw2uA#1U>ji2R)zKNmEN{WNu;xBrW8Rk
zBb5!ruP?pM^Hr=M?E54k-O^>;TE2NfF|)~mK*?6|6V~Dc2-X+?n5yuIIxe(ZSsdDCxzsdj}8Zxt}ZV&0-#*&
z?p&}W;is}0lx8SW58g<|!HMRU*ky-CG;yPwZ2#R*16Kxl_ShvMFS}>0yU%s)AL7XI
z??j+-InCG!k*mrJfZGPX9%sBYbR#mqSW=}~qKs@jcrK-|^bDEgg)NmF*%|R%a}2Y2
zeF7()s7_r8nOSS1%tu-P%;x2Eba=nvBW4&cK$+T^{BM%~r~5A#U}FC7cEHKX^1s}G
z;Qwt0IcgJ5*z5>BPt*<|RU8iX>#=0Aq;8sSBupI~eC0M&W+|-_)inNjqc+(I9FA1z
zk-#vWdsluxUtsX~3XOJ#2Uzf=q`C
zfQ1`=ta;a2RYNOFw+wYa(d#ce*@?V7x9;*!QhU*_K4tRy&w!xUms_{52M@o3_@Kjf
zXOTBYD?3XsI5$5>H@6L1zVG>28S8rbyttR{{Pue@t6P98aMcm+NV!ib*<>HN`6Bx~
zUc@wT-S!+m@2_c|sFVdMo}p;yQ1Fzq)Uk&*rUmbgsy(^N&HQyxz3S$Ca6w3-W63PG
zxNtg!&(t0Ov{`HT>)Duqg3oY|4-xP)kjF=XiitS5mqPvoWR}hdGRO0kMZ|C=Gj#4Y
z^s`BgE8nROh{_Z%XEt;Cb@C>lY06t+Rj5ZLClMa2x>pC~Is&kH;!GM*!nv
z07~HHA&hI9+Tfbswz&F1N&(Cc@u$rN51ObbXGOv$5
zO|>oIqUfBhtoxLv^|R(OegrX{S}&Lu)R$LLqrIz3nTD%Ul-FQ>7DjYwQ+dtZ`%NXG
zVhSFdabmS`1hntc8nJ$$!vTsyK9FVmJ-0HOUj$7Q`jivf}Q%10*iI
z0k9j#8cXepMMiHGv3)k~Yr?(8MVTPKD&?fL`-Eqs|M{L&_aa`qWjPVHe-xb)fn$qA
zUt%7Tm?;j$E*pxC*$zc&8xWf4-r}5WIF$tvuP>p)g&iZ^|8*GVw9n{vw?F=jSz`cS
z=`=`gT)fq+D8_U`m!JOu<|OcJ|928FbNn|FFcL6wu(14}n8-xH#K^$(f8~F`@qZ=+
zOiYaIZ2zADvf0a2C2MArRbe|y8ydv@zluW6A;{X%JqpFW4eh^l+M(8U(VX+Fw@FUl
z-lWv+bncYdTrXKilaN?(xe&RDk+}(#o%xl>n8@5XY8p(z}-3mW$UHB2**}d&$6Y7!RI>w|5gwJXco2>
zSC*e661%sz;u-FgJGr~|r9aeHxsav2^i}^XU>sT5KjN6sf+PLj#;B-90Bqs>nxu-F
zf|`e}f~10^CgS}m{q?V<<&eWWAXz}7S%UdI9H+l*pdbBA|5Q4gw_YY)Yk7O&wZC0P
zVQq8qIRB$l{xn+~^D77!7pHITLdt#^3){~!uQ7gau;w4=B;>?2By?rPk|baBT-u!M
z9d7Q{XE{4Lf6c#0auTX3*nJZda0bT)AdEdxDl=;$BXi>?y%yqc{7;dlLxqLHd7YDW!q@VB`Zje9v>Fs66eh3Cvfb>pGZH8~j
zmo%l{ei{FLcc^aOo11Guv#{0J(p>@Or8nsAvZ8`$%6`aWo6DPzJLEskAoD|jbby$g
zUD4lNihF<2v_{q@V22;rKJ~}B3V$2^6Mb2!m)!y~x7O8L0Ayum4=_*eGIvIW-@l87
zze&DBdF5DRNK12bcAj39xq+xvfaSpN~g9!x#b8^g;t
z^a%hM=e9T5ySf0cvvRut%-jgyc`-ijM(@@${`-B1XaK>O_qybN;0%4hZnOFRfH(kP
zTW_S_`2CZh2K8TWjKl#0yZ1ewHL^3msOc#e_!Q^-k3Gyo2KG=un;GBKfY<>83(F(R
zulf*I+(0g0Ywx_NNucA;dzC(O7spm_b@kZ*VDQTGd;R{8mG5T)A65Dof1=O)a+`gl
zRB{B|)XK2=6JKT1eHr7JT!8_0T>tKj%)Q3;@c(?u-tZyEe^<)>PHAau&Q2xACMV$X
zjZck$85)?K0MgSnG`jzW*52=g@9M<7)ra}V{N->0Dk`!n7{3?0a~S3GO`UulBI7i6
zO(;(SIyC(fUeVaE_HOO|Hms7OriLlmmVG#P(PoeYiCx?RfJ<__u^)8wF&p)?P~O
zQIXlnq=LA^_?-Ci;zvTn8ka9tzL$>Ce5JP{D`JbAoLZtZ%9b*ZG9dx1h{uR@YH;He
zr;qH*)g^~JOJ=G#6>347WMDA}tXbMbQMy~@qmyj+W>wu^C)xQkM&QpwV;Sb(n@f>yE+i!fyazYzM9$-U87j=~
z1$%vxtxv!XNU7mfaFbvF^5B!j%SJm>BLNy_b9k-#O;4_(4Tw`WcZDHrQ2{&CE1+dy
z!^4T<45kNpxL_G&>WQF4KBq%MxgYr-Izk>13voPCD0iBhVqqtU(wsHyzJd@mQw76-
z5?p?_Q?L};5~+RQoqHuixtRB(js@Gcv2kqfr@xQ8DxnkS%h6hHw3u^Yq~>)T
zo~CEzL;@IaZ*OrD`8G?{%HH#n7iO%A{dPM{=y2y<@?o-QD|_pozWEBa)NL_>zg?6Z
zBl=>y+8Xg7RvbPh^FIp#E-&whYD>%W$FtoKXxB0nvqDbYsy-fRsgDeSIUkR&!lOjV
z(#9AU>_*RWQx^Q#SRmrHQQD(=OGxZ69*&V=^Y;(a83`XqPa`=F!kDKz*rf&;KG-Dq
z$IgS(woZJYW=hH0t~4k(NPV3h=cGl+OBuv>-sFRM{SDe;huJy3?6`^|?ar&LmX~WsjEBtSB14+p)Jp75v3r3!}?{CKGe*F}v-hJeq
zp!JONT_vBpu1H~ns}vMbKp0&qFIQEC#g0m3us=zkop?G;c91>^Myy>RdG^p0dZr+U
z*#bQo(^&^HhOFU&B8UR|M|?_;?XhYtO)BtgI*GB}D}TQ7;$Y`*w-t^v*Y#NPUc!t?
zzl%Y#mb9sF{dNg+>-bjZYIbSM2?FfPFvDuab&R#+wvGa7lJ+{7Vaz$efI()?VBS!q
z?m~tRCu$12nJ?UwX;d%pI;_j>Xt{m<`okCXReM7^Co10$w8a5+Ge%F^#AF|lSHnm4
z=Ym2F+pncA5H7Aj6ns;Y8-A6+OEXJDkDo4(h#DXTJe0vTtmx<3neOt{UHMqB_?{$Q
zTkJEyp2;DhQ*_X1_&GV!F3_d(8$ixAdGdUul%5gmSpK=qc3(GQsx$cHEBzsJ#(SVr
zDbb`wjui;+xb$lH;KP~x`R*v|HCx)BI;SqCp8*$4q{r%NLEn$591;dCdXh6d8Z21&
zDoabsWSEPaTO4LOSx~#{I-BG%5`nwiO3HtnxPeVm@F$9hCQv`WUB$L>Mf#&AJ~-C<03c@bZbuc
z!Z@1jIcjC43ar)TNa`vO8yQh3z%vti^{O}3xz9ehksDyk{sZ-j%~D1l(l!l*iJM;T
zhOPjnKr#^|A5qQU{a|zh6%DX~KeoHKO<*_Jw9xXhl-Tq~J09Nvew`|`Ox4bahA#f1
z>F#fYq}Pi3^6Vz)Y1*kQE2jd@u4g5#Jv|!fmuM@tv9%2<@K6e4&P(EQlw-8ntRVxj
z!WcxdW=i16yB^^cIJwSMGo7E!=N=XL^QB?`u(B3#qGPacy;Rn%;h9@U5ldq-65pbb
z>a9urD;NLEq;$%W%S>^BRl*zj0Lx-Z^IG=pNPOkNf#~d+T+o#&m;+~p6J<#qnr|6!88fz(sR}S;>9^L77yUBY22{19h?X@t(_jW_IzLFbybs|8^*iq_&(Q
zIZBf{Fp`dH@7DN?gohh)NxzA0UI{;$DzY}jY>0Fr*D^)
zO)~2XZ4qI@yb8HV3ntVh^zpq=v(ZmfJ@|X!1mHB~_qte^+OMbNiuZ1s4X`FZW^{`~
zVO$}VQJx)IOh-F)QPV$Q=aYG@I@{mk2u|O0(w_*@s!xxlfB3C6DO0@diBv4Q!(Y>D
zeW4vKBwB)DudBpIJ=35hR7w`M%t+t4|F{n=VN!<2dnu6)$4QDrOa}EDwa#7}y>}w`
zrp`i(XgpQqyZ~AN@96!b?j_Ma6&gI4e=(M`TH`*i2{gu<>^+ASttu5
zfygP8m&6WK=VGYC(u2Gf;J#Hc$%g@Z=p%T6$5QN$=WQnaa9AyaV?{M_U8=r5aZR~$
zYrQGIu3HSH(hjt!^@~ww69lwnR(@L)PWw0`_MC05=byYR*GEJl6Ih7NQmPd{I
z_`0!3z)+gxQp<`W6{Zj0dx70(N55SaW!lCJ#;Upred0tK)QK1D&5C~b#efz`3A|fO
zqzHs%BZkH8Rm0|7ebI)bsq4PKIoOA;GH|vEm6b6m=y7+Zu2A7Qkk~d^n|0TJ_TBp
z7qhn$?ZAjfux?X9#kcG0F#GfZtiE!~MfaTnT+21SRSiC_doM*si^dQ@$C$2GeW#9U
zOoIv3#elRIw#%>rIVbE-K^0k1iv8g{(VbA+hq*y;tphe&_V7xje^ga+CHZt7*XGi<
z|I
zF0;gzxhF9f-Zd^tABx7|_||d^<#eg_jk7E>jL^1kIoRfsZH2z>YHG~jdRns?W?+Jp
z?-UtaoDW`zq%i4R2!tJj?1n-L6iLt1m@*5bZ1Uobvu6jgvs=Tq2%-GyN8_*1>)an~
ziZ?KR-6awr_A&^=qP|KmdD3#2@b#K=U+t)n{F_rQrGB{;HPRtdt2)9vU8KygK(_&m-&q%QE9x9F=x7bvFeoh|8XM_{?|PSn4z}A{{GpHn%@x-vozy4`$-Aj=M$^!lON!>KhvxIqRF_=b
za<@Noq-Ona3pefu-xbb)r3`e06Yk@qz36_y0F3~3`b7Mgk!gnOAZk1<+csjOjeES6
zJz|v*#;EH7%Wp<#ACLsgo?UJiO>E22=q&??11>40qEhi~eK*onu--CnnJRnA@G$m9
zqg=m?Q4HA{Np-)!ir}#R6c0qJUUh-~q3ZH32yG`09Wbsz9Ryd)vh&D|zVZV^-9$(&
z1^CAUGaB?4SjJJ+>6xL6x}Xd{N-j4^RPV7bnH}jOQzl$^lje^8@1LfHVX|ab_}bq(
z8$^D7)B7=wN9YE>s;Lyc46NoY)
zI&1@U0gN(f0tJhn>Wi+@T|9g^$CHjy)ap@5ji|e~E+p-*A#>FzHKk9~SW#G@+*Y%5
z{3@nHo55#MW(F)#r>c4vwn@YnWR
z{*St*)I%U?5=PTcY#V~5dfb|{)}pBOd`1fzXp^hev#f6zQMRe={`Uk)zokub05T_5
zaH$w&>WxcmP8wKg?2dt6e
zMhXnu;(zXl!-@{Z7&k;2Wn>Sw%jaRld3wX(<93F*-HN2Wryfw6UEE(GI}yX>Ox;pX
z7P_+d#9#aB#RovT-|p1WMV8DQ|H2fi46+o>Ho*NW65JpXwGL6}5feP|QnYvC`hCzB
z^9XY=yWBZ@J2s!Ol2aO*Z>|*=DQp*gL0{+{G9*i&U9O~#C^vDUJdsbG!Oc>4Kv5f`
z_RVAL{z(*(!D(pGZM*9FV}E4^%lQYLljw{;@d6I?QjMbjsN-)kBoRYk^?r+2w6zti
z9w1>&>dFnUPl}3nuWnrk1}@evzQZ2_gNeOapi}>6zr6ngb&0%~LZ+==qS9ypSCF@S
zNg#tqTy=z%3{@zyAXS|C3NIc8E^M5F4M!-_5?w3UhElx<+cFW6#XtqyozT0SzApVk
z?}=pOn1+e2?i^9>$_nZ%Yd@MVNMzEV|_0j;+2?s*79(s<_n*u{@P|g@0B&;q>&oxInWB
z`}OL`eOn^SP0gR!yP(>WVHzo=PTGdnyJ}`uh4HdJ93N^;+J(hJ#Oyvj&=;|
zxDb7tf-XDqV-u+DSN2}d2P_Wi5y+;CZNPCnALFg{nNN8Pv}mJfkPAgCw6F=lV2>wS
ziNWQ}GlChP)DV6d@@H|y_qsHhMeB{C-jzJWUB?Tf4zn!sXpA>g%OtX5;xdkmGfw~s
zlm+LXtevU|8R`>>^#Rkz>)gEwC%LX&6>&=DZ%uacL!k;+cw$j~gWefT-~_E*co_&R
zZQgyYxL1WjbU!irwcdr`o}u3j{Ur(#@n|_&+5oXD{{8TShjn(Jid94AU9?y!sIghX
z#^%83f7b=AqjcWo@oEdBA>&+5uOb3~YHFt=J22(StLUB{G*W%Ox;epm&ja9c5
zgzQDoskog@?cJM>GGTKwhq0*kXb19w$dO~_L+fsfIvIJGyl2uPU86C@Z9
zu@1M;#%M>sJk=9FNF6LwKXfRkg~XwIou90v`y}`7xt6b7)DJY=BRs|Wc`EeEpir-bMEPE<0(q&=lC?T{5YaikPk>KRgGu%=oSes}AW>M{5qG;+3)$j^iap2hKCQ&8AjmXB9~fL40gb6lqn+zcyncB;1%
z8&;Y5+eoUE-L7k5{euO#u|Y)#FuSlJ9f|Al!wN~y+~Jk&@zf;C+Py7^mB$0!n25uC
zmA+rj^Ya4kuyOWJC8;h$-nBY`1-{f@=V|O5WD9xU8S>%Iq%6Y0y>ypvrea)d?v_EU5i3?wK3>50V|oXK*f5w>(Fdn
zUx`qoiz^8M2*u;XZ&K0xaFd>6=)pACK8z$#$MZ{KfPoQ*e;*b@6dGPI{L;9BLunoKszL2@Pg+S2PXbPmra+}T)kdlEK&>-Z*Hxdj9B_z-ItjHmAz
zxJchf)m6GNf!ZnilL@oO&+fi25Yg`_uY1q$HsVdS+y*JW_{hjrK=j8p=3~LO$U>Z>
z-^=JjvLeYIwde3@-ZdhKxJCsbj22_YZP#;o3#DbX>(_%H|4v$@=Xfq9WS#TxO^qFFw~xN>KYyDhxGKOk(k6BH|2VJ#7u|^qe^-d?1%iTM^mwTpUzI-
zbzH3@&8a~JOGI{<*Hy4tp%1HXpyXZUcXxr{O5IE`utRE_xzz4E@nmxS$c%9%OV)YG
zNgHN%e`IYb*G>roCOo!QG(5Y0PMVo!S2;-;9y0+UAQ{R(va9En-(G^p@j_Qdn)_C>
z4F}9F%E;WYCRdt$)zogh^IYhv=uf1GAYH_4m
z+rR=KkMG5r!hFJHR%X$+1B9!w3wVXtz-}NRGbm6jUDxtt2=eN0V2!kvUf<1=S+HiG
zBqG3t`}M|uUg+TMxhOwZXpU>o*Csml(B1h>A7g@V;qr2QlKMc4P1!_&@AH*X2c;}>
zStFm`d7KAOS#@~OiAbzqcPR*;P8YT;Uu&Q?q$|gqP?(Xzhk~VIon;CqN7V3J%q8j4dX{r6(yqT_oU{e~_~cXLM+Gq?K82#}XeIqX4Ep8PLi
zHIm^sAu84e7Fc$R(qdOH&^mWURokko$L?K-BB>#L=C4o4ZbkK}Y+4V+Kgy-5r9sy%
zd8Y!fSAU#Dft^WZd(lkL-QI*V>Smiu$j@NVv8hVlB*eD#p&CClK_^&AA(reH<34BP
z*uGh%-^GyDG@-2h{Y#)?N=J`uNP(=vYd+EjVA0aS^xnp$CYs?8*xK*yLZn)`sa@mH
ze*G_OLP&mo%YTIib6BzIw)|)V&b}ige?B>^NX9>(2EEL
zK|-c{*j7rl5vlZKek3Tc=ml1{?`A|W#e{UDWfu6*nhbj03?
zumNK!zHR94E6lcW+eutNpTT=0CLZB$ScOofofOJzv=+C*L{fF@AF$CQteC@zo3PW
zBmWRRZrCJE@AIjriXS-p(**eZVW~`a0K$_VfALKFPnD3dIEZuX1RaUn8XZ1X^}SF*
z{U_WgK%g~@HbvAyr_xblMx^sj4sKWu15wZ>yK&5_`VND)EI5i@KVM&A_2lBa`jk&X
z=oHx{CbyrS);hkL31H9jze}8cPsX^=b+Ch=`BvZKvblX9hB0(za|5=`#Rtae-Zer0
z3y(^$<)_;sl=0*z^Ye@WyC$(yR8E1*bg+?w%l!=s{($YA@pC!SMBSbaADDNZaz-A-Q~<$OtP@|!JK}XM?(E+e
ziGE_Hz~fZ~CW)FmAl!>uLjj*EfZiuYa6DZ97PDP?or^G-CEsc+=Rv(e?TL`5VdFCy
z2oqG+=)dT;4zHlPxn#W(IRa(k3xE5`^#ibHmrCIES_$tP|B%z-czaeiOvCD+m9luoc8yJy;Q70Y`
zP0d+`)t}*rM8z`LnPwKIQ8FHApVmiF$hvk0yc8LW#)S0i8OY(RXM23c47{9t7iP9h
z3?B~z3Mq!y;?ISGB#=z$kk!vCHZox`&*0`~RZTq?hlK%(l5uqwY+3EB`)%RILlbqZ
z6_oR_g;BsttOsHQQU1H3cQExZP4z47@m0GzMY(&}j!+EV;;=8|CUeLsj1{>FOAF#*
z%^G$wrzSx~lPN2BMDtlRyC;cvY(^}a(h7uvRko=X&vt|v15a#LL|}c)h9A<|_|xh7
z$Ij$b??=AwY6E5BQAHn_2am%w;Kxo152WnuD9%!-0@RW?9um(a)-?LB8!2S=8U8Y|
z_uDGarPqdoe?PA
z@6=pBWQ1K2CjLWFmRIAxieLKegc$NESX@OH7!ZpXLaTxp{fPty^&421jLB11d2F+Z
zwfJja*vdb7#EdP}O9{A%<_Qvyn+Zbb^q7n~&YV+fkw(hbAE_-oc8TWbpCBv4Y-eS=aIvtaS}kdp2N_YgTRQob$5fkIP*|o-{ITbH
zI+;E!ybP-|7N)I({JvGz`J|wwiH(8J&pGnjPu>nzt&~I*$Pd~YJ~J_}jP*_Intp%s
zB6))jsh;j2($53#N(1S<3yyHa*z7rUwchuub`HY!U4t;w8KghafH$eZhzoE);^i0N
zus*uj@HG@zJr7r%=t^g-SePRwr%4(UMGGcGq$8()YlXQX2Bl;(SU+>9XHM#~9{EJXM%xu!c>RL&MW=_
zjI;L5Ch^bJt6ER{8CdKeH~_0@#ePmS^L}OgMb^kOEV$(K>4r+k+B?;j!~Oap^SlvQ
z&B?dsDjPEWi{2HBh}?^JgE?r|GQOlUVxNzh;uB07+vrC^Wn
zJB^z8)?}gb&2kXNc1Wp?{&GNX)?PG5+rMC?`{J!%^^6>;#nHGI^b)Wn_i23b|<4W`vuzQjcj$@5H>ko|R=T!s`
z(q(S0eDn)vbt(^QX*b}Y=#zA^AIKo(=a&%d;0Y3GFLmEf+d_gDt^ntrzVvitJ$Ca1
zbxRW>=ImAznpdanaUjFT3w?&JwhMf)6D3z8UeiM*j0~=-y4msa&}zD{P6~%oK#53f
z1$jQD21$YpW5q?kIqg@*^cjbCLv%TdnT5p;_t0%{QXZp?I;}&cf4uwi`z=mDGtuQY
zA*GoPOAh>qwxD=P9?`d*gIJaM2FO?U!C+T3xZ)PnE*zr9f_QcPD`ohb&lF~U`FS=VXBdqu8cm?T@VuNwg72CEjh((`2l)<%#Ib16?6u$G{PQh{C&^bkdZsoe=5Y4
z^sgn?%89F3nIkXb?sm5&`n0g7s!HlUq&*&@P!6+Xxr3^|o-G7UPR(v3{K~jR;%V$r
z=L?=mQ<;EER5MJUXi-?4rgl0~?b+61{T^)fCx-oz!UxZ2{ee%A$l+QRrdKL5l;-Rv
zAO$l`3zi~4@$QjyVQ-isTR~cwcF6sTmYjDg9QY3!ddGIL&6=a|G3b#)N;dnFxa|Ba
zerKA$A5sx;@=Tit5O*c$>FX_ME=_q1x3OQ_A;Uzz&}2lCunOo{rn%GP(C_298PvS8
zKOHK})Z|FxgbP{YWAqo}c$PB8Y#F=i(3(pLml2f>%B_1lk3wKl;hvP@P!CuO6PbYp
z7`r@Uf)HFBXtToa39$#v@j5~oq69+iUEe_UR$`W_Lv=J5L}tq*?HM$E%@tnw4h=Y_
z?9f#*Cr#FMmn}!O1CnW2M999i&`yKthfuM>m7Q)-IY=9OKSdM|2Cqz_gByHU-90c<
zelhK5B*6>E5hj#xQwo0{(Whf`%5v&$*nK9IW%upXP8OxQrST}a>UFlu_sVB9kytxG
z@yfJtNFj~!-U7|>f5&*+H;6UvmddGPt{UpOh3SL0A;eQe9@>hA{^jMqYAGy<>q0@-iz@bXx@45S=AJZZe#
zPq)4FQfBW`VB$|BtpN7geW5N1M;v;IZyCAH+E7*D<6eb{wfgoECD`=|Y_IEU{2-ZN
zj@FmF)zEOpzFPkW>{^b-FOs?tX+;$>!hu%h7pj~sLK6?#N@01+oO2%)#E`lICy1YQv%))sX9w&
zClfHN{>V`l*!OtWz{@t8JY6GD(HSK{r`kcs!`k>GbK1_A>LWfpFaB?ML!Sw#BAmAA
zBMGmw9vO0h;@=j*^SF+L^=xx6s*UUc3L04d#*9Z)H8bX3I#-yOz_ekqh$Ey+$X;20
zNI8RGJvVFa1$SD~kA}3=%&QA+9H7$5Z#=~C8XqHh(^sQ~`^77wLuK%i49QzC$rR|!>m>wQw1`T;+Qp;_)LDn5*(^I2b
zig3|XkIWe6MmneUTKPR}I_jL3{6$%@jDGnQz-_}x58+~>0+xtWzM#DJ3fB}?}XNumRM7=
zF7HlkM)hKU_Lc^@3_Z1&ydure0aOlWEB~(=*ek
zqmWstztypx)^gvespW`w$^^P2Q#K5Rre|22aCb{4z?1!|X8jFMmk8Mt4b_A$AkC}_
z`~>$#a_w&coyP^s>+8s{X;^EhHwe6~1%!>zJ9HUGLK`3k!e7eHD7m{3>0G!e6kA9Q
z-@59N^YB#tk-)%+m|{-0Q{@Vpl%*u7w91<#6yXiyUS;uMpQhlGMmnqRDE5@AuRT6{
zL7({Cy_hQzVOy&UBA|Tq`sG0LaJT|KIFgGi#f%o)!Jyfg6T$QSHtfjxqmKF?@3pS%x5@4;p7dTU9hZI#s25GqN+v;&sA
zAD-X!$fYKU0rkZBWafnP&B#MEUYk#08c5vP!pc~s&T-S~Gi*{ifw0JCw%+qXuc!Qm
z9LUY8Do<;NB~8vEvmr(reJrt~?~QB+qqnEgG#&d%)V30mV)`@UNz7Ozr<>@@WNAIPeDS$zvcVgg5+|{wT7?a%v3KW-8lV)Vov_%
z!KV9wcUh?_!2@=q0%cjim|h19hvaEG{W0W1*wKtF=lwXgAwDNa-PBvMNeF^v%42#m
zlUO!653{H^CBLcH=w^JS?XH^_)-XzCR@P9Cw!xj=L7DB9Gf6hNY>
zyqsC+N!w@esIXn3fz)VH3YG
zHO~A{EGD@|2E?9%oPbif5Z%b;8W&BT#s(e;JJ25QR%2C{M)fb4!)kd&mRFmV)p7SE}h6^Y=D@`TI4z%A-~ZsNL=1H~y9`bo~(
zN9B*^Qrx^?3SI6ZhhF(Enb|G*ct-~dOBq2uj+Qg}I^yn301)T^PPk5+IdZ&(lAf>n
zFod|6);KQo=+^)I6qZiblJ+3K3!M*dc*YeNdEvo3E3);aae~6L>};LTdnn0oT3_Br
zCDP&ygSoHj5@oo#bhvol@@(V#B`Y&Jq%P<`*bk(k(Rzue0lR}?ckjg44PkBgex~(8
zG`trIp>|N{9==m+$P4x7tPvmnqb2n^hdL7KGG~`oYrvxVp))nK*^lm$v&K7TGIrU8
zpMYdqC~YvkP>iFXc#sjaQ@a#XoZsj~cntj-xR=+=z
z(dWWM^9whN7>$%|K)EvS$ZH$+%j!1VPKd6(jxzukb5FGgQ$WF5QkgN{+G6d@4AkGi
z7M?9Vt+3J^C{n=>c&Dt9DZLFXQN
zdF+k(SMffjRYi3t;cR>P?UwVd`8lW~a@8;@IiZSqk!m&V%5SXPVtP%V(JaNv?if8w
z5w#4bxUu1D6iV(S4|uY@N8jsCx`Q#2XfWS>c8?qfqU2f1tlPNn{wx$*!hplJJ+eX_
z-aH_8G=j!rIX4kaxcyJci1}@3f=bVqVd?c}F%1s4Ud4O=0C@bs1kNq-)@W6*S{V6U
z?Q)?ViiB^K*B}%>QD^tE@$o|fMzO%3mn56=-WvJ?gzvBa<_%+w`7WB$czPXuEl{?U
zL#a)g`goorsskDpXzX2rK`y_v8oAD$L(A_Hs2k5qv@)_;LYS9?v*M-WnzjPX>WxaI
zl})Q&PMeBMD}tf=lFJMgb)egs&^ir?4qvr`wjIN){B+7aG9DdlutSSF*lEqN6%saf
zq5XGf6OAt3w(qY%Zb3lV;zdNVf9dWkA7yLbAw?^YFG%1oZtRqWnu}Ca20+kq_bC%f
zRNPA31(4Y0nkc+bX#1w{@1d+6_1{4xF0pH#=A1a@k!Kvovq!g6Vxv6b@gfue^)pz6
zs%IKebUqbGdr}>t-L2?g_@||)NOePwSgpug2osppnj4*kf4o$=pq^^Jb;^O6WOM
zk{$z_v1G7IZ}>NaZt*ibCLO{Wqw#(BbsKe;w{rlaNkm5L{%~fk=3#ZmmjgG>bRh18
z8hI-Cq$__iC&%NE=nkJAdxR=9GL=@#VEh#Txsq@pyscVzT{8qwWqvfmy_pWDDs~)p
zD1+?6<*it**8yyj6O6|dKotVZVRxBFVc0X_Z|^R8I_hk}Z}r%xv(tE@HEvJr%~4dE
zZ5F|(r+<{*MNNPtNbgNc!x(CN1mIOR_OD4rHt--#K|(~Wv9;tLUn!(y4bjwq2pA31
zpk)X%kIcMK?BB?zrtV^l*cIjmc#`@JAupM7YmHJi%d=VS8bHsuPHc$^`FKe6f_V1C
zTD+FeR6E48&dXYwD6YO5XW08gP^00i$`wkC7>@KZ<`_n;!k=izCUpu3W6W;N$iYy|
z`)G~<;pJ;wR`84(#=7+gkx7s3x=S7vP>O^HcQMwoIcB3cTFfU6>Ih-annDVz4n2u^
zedPYkky*w;v65dz>!z#L)1(cB&eALEm%Yj>T<4469c4rprf33sG@3gry575_KlZ6D
z>0o^=U3ra!_|<`OJ7RBOUy>~V78nA?yo}hjb9XTrqpKZc=2B(^=hkF2OgK7R!*61i
zVlO}HXjs9iiAaj=Zy2U>Y^T9h%wxyu2jTC)U|yTNyiygjoDyf1CNcd)m`$EO+%T9C
zkvHY^nsgGY*AJMHj4<$HwT!}pLiqf<{2)>(B2tj1-+iSNho8cfO>=Hm7lEXuW&j
zf$f5_DLKk(0@pE{zh%xT69Y}u?ho*C(b*ObP-z5;c+(t*e4?&j?kr}&53R0x`d-x-
zwP1{mt|Pr1?RwI462<0(eM#4PDAom|)^vIf#<$j$2`YRCJ6_2>HN+ojfo+gFR)_;D
zh+$G0@;`QS{wa|a?~FiZ;uKa4(lmP4aeQPe%FrE?24WigU62|1R0=usOSTNe8A^t$
zys?$y&;~|*MEZY6l8LVthT){nWP#D2La>%s&
z@{+@@xyIgazrHI0rnp`tG3o0T^D^h!hz_P8aUPXL_MgjCbNC~YLCeTtLo>Rk>Z+)|
z8RzUWl^Y>K5@vb*3gc0D$kagik?3{_8|fZEff%DJ=}P3ald#4~)EtM;;k2p>GXcni
zDO@)eNDyzmA03`Nr`(U5+w;a!;k)W^prR$;;OTHL@bT}WIQ}@Q5Y;Dh0C3
z^Wq}MuK(P0S6E!HiXj?c?sRCr=aH`Mlv^YYbqW~tCQ)viV+3&k&stZKv}e%-BN4YR
zj^C**;HIV8$QFk*q&&k77@&7wLptvekG5!gFQxO4POaJ+%TRnXSm$+s=*qJ_03G>&
z1|kG-3i>SUx|4A9U)&uMF41Mj6b}(Q70Z58?rl3wG7ktOJ`p3A>uf;14`RZwi6z88
zkSrD__gV?GfG%`(d$NPPVl(}}4`Wsktm=(m?zEz^j;BNh5dH^a_t2#Y7iwSPv?{Fzimi#|Yp
zo_kd3jHa0!@eol95CJ0IE}XF(M_l;-pu&iDavb~A?0){Z?K%N8JNN*%6CAZK#;r;c
zugi|qu8V#LlAx+}Z}gQ|o=%wGAJZ!QrRtkG%0H$B6-%^2vr!k87QX5bXo8F+PH90F#X|)smMts!GACIzl0q6?MREbna_Lm7A|N14&Oty}cKGjIfr=J!=0H
z6X{@MxOpmr$2_xSXR*zWey%l2ni3=!El%07rE$)T0ACv0MBCMH-DqzEhqA57TUhi}
za(6S)%ks2;$z1T2G~DT=Sw?B0$$Ukkz8_O+%Yn&1CA9lWRb)uBKPPAlZhaDF3dBAO
zSjer@`k&-Qtb-cbIn`+Cac92&B-K%(JBEnJeDNyz%l+^?pq&Y&^5~%%+0c>(Pcr?b
zJgd3%cX>zX?C7t_{qr}G@hPQ&2FikShiOL4cP4k!D3`>H0(||s(aS+y#+0d|q_yhV
zUKeLP7cF%?JWE1Bp99*ZT6=a5th4Yyb+O=enYP5R0NJVN#hntvZoJ7XL=Yq?NG>9m
z^p)SSqA~#{V0Yw^lw>ope#JC
z%f1ap5FPkoYOc&4HED2wp3BV@-KOT4fFT{nL_XgzYPn6{f*
z*4frrnV@UoaAH?6odGMm#{*{s1-_7Sz8Vc}rxkX^THBgz1#(Cg7)IlPn^G&M&(7{J
z7G(4IV0t4{mMksf>IN#oJb+zFrZms3N%EDpqcgnR77y6|>ULT6K@k_W+K?2x$027IwlWTFV8?WTAte
z*=oOEGxzA_`^Tu9=&Fjn#u63-)%R#8d_5{oJWg~TQ25dYDlFXreJ+WhAnzh^*Alb6
zxjaZL(#-g>l1#F3?i`oPVV)XOjAJ>C1_>+&xLQ@)?dBbkY!7@ths38ST
zNQqMyN(`ZU6QfD`jFy~xnUl&8g=EW7ys!k-YYo9kPOQk0d9Q{*1W4SW>BoCvxBHq&
zBwhL2S$m+TzwOsNf3H+(lPT2uHo#eF*Nbu~75xu-W+jfH1g~`D7uT%AXDSXz##N|h
ztHzV#-?X^>FE%iUi;h*jvUQ|26hQ?>N)2tMfcNLz&txNFsh7$~s=7>&^g!AkT+o%{P_`>Q$LMMX4LWzF>WkkG47YWit+sd%k{cXv9;k
zo50v;-SkD;7e#ZiAiRn5=xAirUw!F{}2MeyFfgpKodIJr7V_jO@m^Ff_c
z(HOsDcu|aFNF$@yl6M7*eVnZ9REP!5@L@K>nqmwvGaV7T>=2Sl;*9=@XTe0du(v%=
zQnGANqcDLpBt%J1xuRQ@|6xPgm>Bo4^!OMHqCGz@X-GdS={|6*w#?iG1&Nq?rslsi_q>!-2e?+jk
zJl~2ATH=kp?Fvk_>#ke{ZSC8OLk@K~<$eA8_ZUk`c
zlO=w=JTX>xIglc-*aC%19Vd06F@>z0?mKB&Fj(VUFDhJ*^kU4z~4Cx29KSZSRl)w6PQQq`~z
zw2EcAoTZMXTZ9fD7s})32|`Q_X6LA`-1m$Y!vUqyxvRMi0vgqDJB>yx6-+53a3Ha
zly`NC2~hE_n%rSRQ^(4|{f5xFI#R-s(a4W;1HG4QJ-UAZ&EpLqXzLr<$#*8W4b}3kOQ2ZBx@GL
zy@<`79l|wiEh}_#UVDdl_DZk|Ha1D>FgclFV$)16r)eqyHlIKNTN>j#I1a@{st0L9
zB-0-hz0`s5EwAi3t7yPMn~ic+0a(%#t_eo}#1U&xVOqhn^C;Z0zC`v*nU$dl)rmx9
zZrZ-rcT4$oHOKF!Wl`wPGtlz|9HUZE6-FDj51><{R4kD)=)L
zhGM*Jzt=g9UkJw^?rX>-UgUg}6}=RFL>NdovHIY7){=ciibFcA#f=1DoXe%1^Z-3S
z_7vXpX6Z*z-vdFWW4$u{lK@nn$gQP49AXp}@NLg}Fu-=N!GD+IpL>9jn;)#&)ZS0*
zR!$bhhD`Wem0C(YY{naO?58n6$j9L*;$Lav+8;tC*%cWm!qnpOFh@TkVO)LU9i)iI
zvS;s7z10Swq?iXB`kV+8kK@>Si0;^irN6|YtBe-p_)E{}Py6pzWuUj|p&-Z@H+egv
zspWtAQ{WHC?MMGz!#u{IALW#cl&A0p7x>4SB&1ib3x0`1Nt_O2JBMrJd;PfS4UIml
z5kP&~eB~;1chz)1Oe-cBX7gR{=~IC4*Kg>UKu<<0p*lo&c`(!J5og1wcH4u>_!piuszU-tm5qB4Q
zEBtHT&5k{dC`CoHyGu+xeSX|)tDqcCSX
z3>XEkbV8%Tr?JbeLIBlQJ&gigG^$fBSh6l5E+UGu(FQ!D3(Aa+AP@eFRO^4_=|SrIi!X7i~AmuP&Zw+zl#!Z
zq{KgfL@#Y8bw{MEo)ZW_NbJ|BXsNfP*1g9j{NAAxae3E!1sY%vkIvyI8{IN{f_%@g
ztoEu2vfBn!ow3D}-X1FPqv0`cJ3)7qp08g+$&&OaR)`H*UF;nG*em7ozZTI?Q$63?
zzYt!Hv*U^+2n;bOrbOZ1YIC*b5xl#TH}6s25NU^VDsJuInzfpcm|wk!JO%^y@d6LY
zCa|hKA&|UZ2UjYBg+Sb#+%H;?S;-s;kcJG>koR#*emW8r^_!YQQE{}+AovWdTTlt*
zp8Dzj?iNy^p7Ni5p{^!?jHOk+1t?fExB>}xqR@BzE8L%@z_!RIEUt4Yp}EaZ`_<*i;BEB
zA9t3
z!WH`8srIE>f_qt#s0bJp^&gxzR*KtUue;||)Q58M=-#WEIeWl%@YUrAS4J%$b7IGz
zr{difjUa7ygZwI_{MWgXXs5U0Pboprd
z=Lc!kWgh}4z-%rT$ZMyR2yYFMn#A*466JKZUQMA%>&^m&5`=g-HALraAlkx$vcIMo
zd#9Rkc9O2TWi-Xl?J<^6+^qxNDI%G(%UX|eMYf;e$z$p`9$^0z$PQI!*R;UgH@P7i%OVf(nv3`EJg
zvlNGmb0+#K>sf@(k$e#&$Y;wdMV{(8=;j^l(n_m-u`tzKX?hs7D%om=Ifl3&=S;H_
zcG+d%s3kbn;zjXTT{XElHOQ@UYmT8n-opKRHvG$NP7gsa2T~==zc_ug;x9RhaFcDI
zLZauX5tT5ZgYgD2nFdMn>i0ViLC&Ldfl5o0$AGjk1Dne}-U#R!4GePqo*d;1u0TuY
zmkx7o3!YzWEw{MUDMlI#x}C*q$!hZ}@q&ssOeoXa*3U&3KVFps#tvqnMtop5P3S
z(0>DRt7^YzSSM7aBFip@*z?TS|B?>A)aA~z#C+IyR}TY9WQidmxq|+kp51MLSpQcy
zowFAfV~hlNpal)sG`t#9a^!t4tf5wlS~1Z=dzmS03ZW7cLoAur{iN8Yv4lbcO!qgn
zkNW3U%_mjn4$iG@?=smc@M2r^Blq{v{xn&}XYV
z#uHlPNqF%Kp>O=)xGBtxz4N)U!>yN3f&DP>b?85?I38m?X(M`t=xr4NRRZYyLTUJ+
zky^Ahj3y2ZK2cv$_U$;fW%hbzE%YPVWM(Hk-S!w99bC1=pQi}gB#h2f3PDkyyhvSi
zymfpqZy?^`pjI2@W|avnR0tKUDu@$aOfwZZ4~(bB+>#sRRH6zwrD$|(cB#yZpNe!q
zGGmk|r#nqfLSPs&-Mk0gvXZ4LAu%$afj-fw|2a{|L%Ex->p;Qh4SM^zHb2C`(IG0`
zDJ>6~AN<2XmT?=oli@I7%sS?UE0Mk&jprw$JH+W}iONCYN&vpW>wGib-xwEvHtDR?sO$@EzaPeMea8#mY2;3QVzINBVRQo
zbK)fXLt3i@HhHchJQV8AMu+FU`Bm`nK(WsuNIjqSlKjRxOZPpI@tex{G7ZTApY+G=
ztc$4F;QVdbL=-(IVBUY1d5twq8I%^7MroOmHl#4mU7@t(eJ}
zLYct>O)3mtS|LM9W#w&Zg)_GaRi>J|$uj@Z@ZXno!G6eyDu)sPw_y@TCz$Yj)sKuh
zwK3NI?QoA>h{P4SQ@#?@UH~2GUI>943D!HC#WLECSTsH
zw{$a5`|<;0t%!(s2^9K6vil{to~H2dkGs{?uR^#xs=SV#9)18JwHr|j(=d->hGEam
z3!$@10~f0~9rysB9xQ!brGxYL6xj_x;GMtOW8r|jnH)BH#ARmq$`LGLVjODa{y@@P
zdZUxpZd-0jgj#LH6g3H(lbdw8hj5#k(f{1#z|Aug9#$}K!m!}js}K*>>21JsX#pA~
zTvekK;88m@9XLA>v1F#K&daf(R}PvKEjD9a+_Fw;ws1MusIhMBfyg=ir1}Nw$909-G{&_gv1vh69y1
z_v6kn5E;busEst4ig{OPn~$)R`S7iV!B~1*Gc?`MlZQ1N3Go?YZ=6Nzb%*z+97|SDGbZx@I%kE*eGe&FJ1gJ7cEw^<+f|3)g+sXfd6e
zG6S0Lg5?qZUn+WE{KVT_dl*L1#hSu&8oy47Q}$i%r*BZCjn`@>L?{koJ`FULP^r-4
zs5Vo7gK*w%=>oyed-LaX<1@$0<(7kvFiP+P5>P_D-MO?5RCy%$2ItyCt3%)}KK*na
z%RaaLrC;UZlHBnCwhsx6ysc6d-z2Y9va2>uBMSGqZO-D-A+n~tO8)&|G$XCHXETW$
zZ|fpPz^aO>h#v+=4DLH6KaE#o{x*fRzKax^0lMT+#(W6lX@_OBXB9V*#6`s!0lGdB
zNXJ>LkeM|w*+)~mf$SK6V(kvMG$8qd0wJGY>J(}SoyI-WeXoxt3$apljiWe$U%;;5
z{H_}E_C7u*vm7|-K-$VQ7ycVaVlmsrlNP`1-TCviHUj(KiKw4RY!NnU;d}wD|D*@!
z4msy(vw}W`=pm5Anez*yU-9F7eVdfw-Dj{@n+J5o(%0Zkj^A^o$(I2YV*{7PI#s^H
zxR@nMv>EXVmsmDFKlFlMS^xA&EFRq|Rabml42tI
zOQE*JdsZb-P{D6IpG$dAxyN@p_OS#reGY*MGZ-lrYg1s#D$?3jbU>FH_jN0CX}b7(
zOZox>k?9U%zmp+XK)S-K{Nj(pIkDG2NirKBInd(z0I@$+pGb>=HpgEd*$MCF=*0=7
ztn(n-jZd*O-E4#2`df_aX-DAYVM9c^)$x^L_^T$|qO{rA8;aynAA}}0a9LtFpw;Pr
zV@cOg2L;3M&6mJaj~?Kv;Rf*Oc#s3(z&4h}UpFN2M!ld+cvMgcq%3hz^xS5SE(18r_=AoGFEqjvdQS2vWSDau)TQDo_2rO|E7c{?lH4K%pDn8#U}
z@}-8?HE4*M;(Jdwp&eLXlj?*iV+gz4hB8kdD&50@vP9bqo6CoB?t1R=#?Evgyo5-_
zyo6%pM)=U*z6pM$yQc7-!x2Y}Qcg{NfToRR!x3#VaBVCfr|#;5tTo#7_s_$MWUh`!
z`j6_^1IXIg#M-5S>?ZsZTIFh|SU0vu5OJ
zSB>pBGI6a=+BXG~(tZRSmI8#f_sp)*_;SIg{{C$x-WL2}nqgEq@1>mtj-wAey0qzE
zFe!Y^hQ9fjWt_-QqEb;Vp!MmBu~?Yvy8Pu;Qte;IqpLBy{sMw%$M0Q`jYf{mLHat8
z6xPnTKE`ETADjk8rg!+EZ&u&pCInt;r={3uMNeTR2_xsD%SCr`pb9?wUEfiMgZsx`w
zGo}GUv;mY|bdU-;h(C)7Sz#7b+g=ELiJqM?h==#L%pc|?URfT`p}{~nU+-VfR9kHl
zCQI8OW_r_!6Ue@CNW$`p_ZU82liORun`I#1u-+f7zW6`Nxg8pXnQF01u7s`aD11mH
zMQwhaB{4~;8GKDMlel~>X#sGYoDOysy9Zp%PpkT`9{GPMH|z}9mltKLeZVfm-7LKL
z5JZ<(>e1k?s+Ef!aKFV
zP^;ezN?T~YrOcY&a<3;G{7;TnGT?vH*X+h(k-ydI_-qEC+m=0F@-zy(Zprv$xUyyw
zW1u(p0t~Wu?X3aKp8u_fhJnSz_OO|(Z2CbedVrwz8ij9Rv4WsFyi8$TqgA$kK#1#;
zWTknb#Hx%d?X`Sq1ot_xAbik??1c=zrQR)NBO6^z4ee-R7onX}U0RQIx2e(Q;oJnv
z4N5dawO5QM=7UH1vJyuXqW2cDV4=OC^+BX_hh5K4I5NMC8wyktpm+}RbN-c{AJ+&2
z&>KZ{UCv_V(>1c-I5NJpU4cXnJhy?x^13ZxGpcXMCHErRirgsHddE=efxEdII>CpD
zgP!?gjZ!=Xyy6=opVP3%-udfrEKf8XqT%NR(aoz2S
znTPPHPPzc~hI?>%51IFy6g@Ldp|7cK3h1PTCmSCL+-Fi32WG-@?piBu#^&Vuv}Y%U
z5wI{gC0DC4%}S1c3Yc~1TQ}ltWr^k=ky)k)lM@PU?}vUBVPd(L~Y*Y3`!F4Y+rq*aP1pM&{zrvR>kw~C&e#|+DTbEWnN
zHBLz2FT86PVnfEswv
zmkhn5g;%GbxA{-%?ER576)j6hUwx=(nxq8WM~)LgVd0wbc9_mi%P*s?c3DMty(faI
z9#8Py%4LL!ocZ}6wtNT;=fGWs1pE8lq|fa>vbU$2(>T=(%a@f@LeKF@ONsF^FXOtB
zwvc~h%OhstuM8V$F+8Z*5m;ZGsTt3p@eD0(BCTe5UXg6dsW(j-;tr_1p!F@6xT{@9Gg`cd*#~CNn*Uf}QR}NPN96^&_g=Le3dndTT{F5%p}ruc}05Y9|9lubS_ZLf6pnv)}L4Q&5k7nkk-J(%!6E-o|s|LV8@xwuU1
zEL{Kl{l8pXW)5za|6dok)5Ud5?~@;I)4jxLajnIUH=Qf}zh_hZaKzG#YO$;R
z_Vm;7`^R^+s=udAaCQ9@ZUtvTLAv5;;J=n}9@yAUNKSe{1SAn*WI#GE+
zSxwPL`hHuebSkC>s`{cjiiP>tB@WOO5NBRuZy4?}Bx_%9xo=ShZ@|@$Jy2e~tCQ27
zk*TYPhee&Eo4XMZw-yuE+RwDY^uh%89)fcNun!+Euw4KEab$Vt$|Q>+r4NAiW+MgU
ztX?AIZLwz{g^~y0x)zXlkAE`qc*m@d6>j@dTYMqh2eKf#>)p`A;r-2~EiEF0tYd9y
z@BrSx-OTg@>%i)4;{lEOY4P0(Fkkv5f&vTg;NkvW7X8U(C|tb_a--+rxTXs!R+C1R?_r66gj6{db7
zZW#%^y0{fb{fV7C=L&0J5EEyM8^nipI;da{Qdf5Lwm%RirAA)uD}d(*mzc=~
zWU5M5PeAOaUJ2=^hQZDO0mSil@T>nQx8_&JFQb?9{4^Hd8ls`~87vKW8W{^+h=I^J
z@BP;z_FI7wT0=(%+=Q2C8i4o&D2%$UvgQBfy#a`@1pt(a-vMMg+%lS;K+{Q8y0Y}Y
z%*%kaV!bFqF-BVlBiJv^_+GgSz%}V6V!t0Ak2)Y*3&_h{{^j@H*K&Sogy8H7Zg1~x
z6Z|W!|M%`2>&w6vIEqFa2S&NU;75`H02#5F88}sSMGr)Gg$HCpNok@0R)Pp$SJw#I
zl`dFh3-R=(Lk1)P;T<jIA0f
zB2J_jz?WT+fBMiR8WicxaO7^MuStO@=5iq)-~7DbO|pE)_$5k|Xe_sDL0#*2jD4X`
zj$;g(phxG0Il8q#ZXJJP(+Z6I75W?P-d{!qXCVSHlK+dF!EsOTNy2@ueXaHpcdOQ^
zaLZ;yl$>UO-=YNofFGLS#uK~SC8C5-RDC_kS7`riShuEB3f@ji*rdt#WJQBm;DcBU
z7`4Fd#_?h_-0De33rh-W$8ipcBj(2OFWS=g64pr%va2?odaEV^V$8mxj
z*foe<-uW-7kmMtVtNl^bRWY_J)DO)DzDO+hsS%0NYZtqHv3V=HszN*@Ms+s%MUuA)
zx6zSVH{KLrl(L{nPhIs)gg?x^mhm*o;N;7tKAuBP)rnvFo1b*wDhBT$;Xu9LvY@d-+6mR`5Rp{I3ho#uiYEwEe+Qalv
z7%&J)OC;L7(;@L-63EO?9rgPV-L$|<#euS^87A*
zl&QJT_lUMwbkgp=xjZS(ap^t1rjtx|@N@~wl-Gv}P0xeDO=O+{mxU%4-%rW*MhZ?j
z;&G@{X*3ivd#%)=UF*6fFTORLfd!s-xe&&jNjmELuxH?6l@jRcU2Z}ZSbl(ArS{}(
z#^hztWO`h3$SIy`WHqps8jcNq47kg$a?EOtB=q@-$w|E`&O6(InMK$5N-==S+|hnI
zMAt|OehLekK}XjBb$No886=TU^q^VNH2rlbF}}>C@DP#F^XzSvWsS#{dTy%(eRMm5
zh0E=Vnm%OS$!$UW7kw%21_@UhS*H+ZWFlXUGhH%a??|#VWU_5??ACZYY~i>StvC(4
z)$WskPoxy5YR{L(St8q%J((B#wsG
zRdz_o79?yB&!>t!KEp&NNRNfMnyzMG=Yy0XYTqmR1u;lvmGf6$9FD(A&UxooP5gZ`
zks_SRqV0AMm6M*d!AR3jHA2b-EEZg$gL?XA*=s)4AKGJvUV3IwT^tl|-j^wYGiQGpw
z<3%}hu%op;g>%chuxbf6P6BLT=8EfKNO&>JutC}jV6az8m4?BS`V_>kw>C7@hp}dE
z@wn}$GR3m{wN_&d#-kgduhrR>o*Y*Eo}t`1jHe5({vC?*G!+SnM{xTo%p{UCfoDvr
z>a-(!9sezT@v$G1mk>kfz@D1Dxm29Pip(a`>He^{nfRoY-~3Jz1d$U8wkjg(I7YXs
z^ic`~jn;4A$q%XzmSq#qd!L(iXL{-S*VDbaO}aj^Zv;l-?&?vAZk+>-!{M-a#Y)WPG%FBBY;HN
z&qOfAK%-n_VDj6=e(o5)>g+wUtF|Ab=;N>gFL&6;TUx-sDoF9zMs7NXrpvCN^A89W
z)ik|+;XmNAh8h-N*Hh?AAVWqt47rH12-AqATUyRYe#^K1B0zb(yt>lsp(+}x0@#1@
zt%qwXg^O)I8AZg(4pL7|Uka<{CKfK?&}i~*1|Y_Y*Ri2M&iJ|b{@Wo2?5DAQZpgfU
z1?w9Nz_T+|AJ)_n0)
zo0ty(*QV>7+z<3eZ}u5GQf$^^Qe3W%A&n$9H+9GIG9WJS925nU6MFKj!I{kjnT>w`
z9l&tW?z}Qu;D@eB*)s-jl$5~HsF(Cg)~T74cTqZtO){@Kox!Bs!UpMDI}%u(S(
z>W&+{fCsJ@!LN9y7LP(H2bp>H|2v(QsjUY0Tmq)N{7HSnOjK~#v7rI)
zI!C)|IMi5gX~D&IYTD#a{2jLSU(r;K+^y3Xu5n0k_~wk-pGxU^`6zmh5bg%V_`Sb*
z&zIxM3Q3x1tihJgZyBr7GF`H_UP~^$kpn|(v#7T1
zTn>7Y#%-;H9{xL+TlR^!>6emYrin=pRvR%G`jNnH=IXz#Qv6hXL53uq!dKOZ9PES?
zq8XmP00=1=RN`s2Hk#d2qIEU#<%`Z{uNQKdCw8S{Dtb4#BnIZTObB)myr#pVipZcbwiL2C?>-=EuS&G|wowo{}IIP?th;#A%cZETZ
zW3>*Jo1w#HB3kxtz`1!(pU%po{}meu)@4GDS>c3pEU6F<@MTqhs3_MZ{q<7BWH(G)
zyK;Ak>G;8DlT{+340eM4h2puE`FXsLMkp}Vs4=UKI3fFcOi(j*awY5%5pnHj2-YUI
z9}5!05GUAv)i7s|lps6upgz{rN`Pvx1+LL1*NwW914Fnh8rdxLi6Hr5^P59(bA;O`FMdcc&
zp}cdHS6jZ4(C)k>2E0#QD!jG4LD5Pxgl=_8^Yup`(=mk6^0nmpkoZ9FFjH2Q{grDd
zk3QUpeE}s{f|H%#Vmh<4cyWw7;k(W$-6ebruGQOrIEw!EeXa3G&bd`wo&F{;uQkCp
z*jjB<#H>MO>*O4q%?A@x6$$g7Uk~*X^&13xZo8^m#
zeFE=bCp-R_kkCn8xGL!tenTd?h#K7R%P1YB#XCvmzE_FZay~ycED6^3^(hOW*x--N
zb5QRir0s5}LCF%nG|{{!Zkxd2p*aJdfg}GXZ%BKHl6;jDd;Un9!w;)u?0x;pu*L}w
zppNRa*a>v_K8Wi=@fsZw;bc3+)In+f7s*I`;G=G0x7pVb5d(j`AOjC-;peS5a8;)c
z-#kA==L5|MT}KZr(X$t#q}LNPTY_5k}3^|n6s#%?BC=+&V5v!0>RI{J>H9N
z)`B%{JG&o=obf6bn@Bi@c_cZ`%-2{my4_N00(0?&FxcdM8$9zfWUd9*Jzx)CmDULr
zub5Q*a}*OJ8QFnmMaa$a6qs-f>m8Ov-rsc9deR%C*b?^~f*k5!g$|X>-co?R4XpWr
z*IVrd*az|7QO(|l(zpCTIbLlkkl53Z
zh?8M3wdY*`I#d1iJW|f^0H6DRgW->0CQN1LrnLMY62A}Qyz6YycK5jnYGQlX&bWmT
z@WsR_m^Ov`JR()bh88EGQ%)}1rNlJ_`IA!7i587p&c~u_DX_Kzf4Ja`!^;vP^*wQ<
zVyT17F{Nb=jmo!@Yl#q69UDGy{B7?ztWb_(4X1RbjhimR-TkQ?OtEgFOKpMwN?FRd
z74^G6f5^7T?Gdg>#{yUu4b_yt!8^3q5qZq)+K!95_E(o22-!ns;4yYzmmKSO2!3gn
z@Vd(;%Y9xlL~>Dg9dhjJzB0Ut2`0oZ9)id|-i$C8z!w+ZreOInA5<%~{D7!OBE@fS
zrn6zZ)DciXOB*k_UDT4bo$(;e7&Sph3scY?*I9lC&2E#0Ij^YaEk)=i{y07*$A?v8
zT#-?2MP_JuBZ~r6RoPeqJxqy2rjtaRCcZIREpscOERqCipG4S$7`Lqv1p30?@opX6
zg|J?gZ0L6U3*A{Y&b^rrr0)~$h)C66Og*WKD9ab@6{V?@m&LStF&LSG~|4z%ZgNh12Z+jlyc~U!as)_z(m-jMC6wU43T;cBMeVE
ztF|-A3#yfBk)w4|+~4cjQ0m^RQg>gf^*szNTIZ-oS(}
zF;8o%J(G$_!iYYwkj#ud8Lx+Nf#dzV04b;y^%TT@tRwyicG^FaunJD&1*jOti3%)k
zB(TkCY|ra|R`UtzJ5-Z(v8FqUC;26x!7lGMNXQs#SOHk6)}RJ?8_i~vjvlj)t*edk&=TZ{Vj$qr^BIt-)pbSDXHEQ@YDOs
z9gh;>sqg?J&{<9HQ`qVBXpP%z%fQAZwY{14QYW=X9iR_hxrt-`NCD6hn%$>JiDf3}
zCDMR_!2ueH2ed&h^-N&YsH|c?7%92km?7-Q`2176@s4(Y!r2zs(3P
zN|F^sQkif2Bcf^1!a@@wK>|Nx?0ya!(#@l{kMq^T{GAn;5B{`Z${O?aqQ?x>(8h
z@5k(Z>U5lBTJQ914slO_6~r|b{Zvl+m+0FOO4b=L{3#3HZN0CV$<5ifXaBf?YHo9U
z^So&e*9Db&KJ~AK%H+Ex+>C-1$_q;SmBxpZ&m1K6iOf|bBi!aE0<{aXdlVL8zOUq5
zuTiJGN%dto+%EGXC|Baq7(XprxP;V+IaA=q0d;4MAK3J#vQw*FQRHu?nH>3
zDw;SLnyh<9h}=R(l~tm>r8qCP-_jP0%j=SgCC@M-Yu>_ob%|^JY#_6Un2t8K@)N{d2~q-Id`NCXpwpsQpxH=%@W}
zhGcwKOKOs9GpD|tj_8>ZIE?x&8?S7&AjC8ii^>ztC;FGfC0dWK3O>w&n2iChPL+%3
zW-0a9NoIC(k28%PniW-LKnR^!F3zP?c}##gi($qJEu{)K){7Vr$U})XXZ~D;v&hKO!Bs+FZLGVWJo&znBdf1N^z@=fHUY2BQg>up3alU8&
zju?pOufg%VK)s!AQNZFVsH;4jgYn`T4D0v6#Km28VAJ$E3pLq3m)By4PY-Vbda0d%
z6)5u{-!jrok9234TYwwz}eU$
z#r-QTFGdoWcajNSVgBEx6Qn{jF!_?>3Qv={(7ZL1Rz5#htd>SCy;SLKt&uc7P6i<}
zl+I+%eniea89rhT?~_gQaK@wcz3!^)7LqDFjD*^LXJ7g$;`>YTSO1@N>TGPX$RyTV
z*V{%e?vsiEQnZV=WMAb|KH(gUlEI@99IlpA3(RDp^BYbGIT+7}tQs+F-AmV7ZasJml<4}=
z=MYo<-TU<~chi+FNn{B{AY457+~bl0;LbpO`J(PXn9kR+;k!XK`F!H+BYPLo*8Bb|
zGj44;=P1LxBK~h7Gb_WQov#qkpp6frr60V&HfdSI9n`TKZ|G9~v}m1ip`mc^2OC0I
zPJWr!fV(Y+2K8~*;46;`y#{?!%RyqUs*0!uXey}$^Z1EJ-7L38zP#;jC~bji7$4d^
z<~CR$Rjkbgf(z)oEKim133XSQv-ypeU%^@L3nov>V&2g1GSQ^C?*!icxLS%m844I%@m
zUU7r%SV;)`pt=sf)%Ug&U7xjs$`}Vk)$sMpqWkQcwF+7C{srCnv-sU4ht7JxZ1=_M
zrEo%petn7o4=4yJbTqFWfZ@+uZB-WMhw-0mOJ{84r(e8r1wg9+Dl^IG|Ja-6JsM1b
zRR8gQRp4mH+ard_jBx{zps?s0dy5=4l`xl1$`!Bm00Yx!uS9zda>Koso`yNf5^6nS
zS`nyazk1PbC$a8Td_ZO~t~9mLDz!@ui#jJ41w?NZ2H?-bJ!WZoCwOIo4U4dQKFFu(
z7oKja7m@Rkur5mV!qL!I_ont=hy?eKo#|W>etMRRA=^nMVI4MWdc)Ft-w0Dq`g1(Z
zXI`1FD?VI__5!@DjxIZH>J>ImHLZ38b^$9Cut3~2?(bc)
z?2M&c>EX+KoR>kdeN6*YyM)$LlU>!l;?d)sQJJEsEpA>lQk9qccwFtilACxrxzQUN
z=A0{wH9y7vdx18Xd9as*e=N*x?wW&YUP=8N9(Yv*KNe-l7ez109q*5bOhqcTa2HyQ!SYcG`J88kGMb3sTP&T~def
z-)Ddz=phW3-*pn;p@=t8tkoMp<|!>zAr^{>>&Ps+{p*>9X8QPG@DM)L8FJWU)%F4J
zpY_gbyw#Q>w2>rkeG9p%-Qrkt92ynruhY(z2S1FAUDqU`+T3)b-wtGpAi{=j4q*k6
z&Hq;GHC`(EW($$(V$O!yKQgi(Fwz`LK`+*R6ejv{u&=B%@2Y2VW-+6#^~!z>t{Ja#
zxx3}qp>+4`K%wj{x-k@4(_vl04^HF^;X9nPTADDj1bJ!DUlc2pWR`lati*;uKb)q=
z^#&nV{;ASKNjlyBfqP6#x|HaeM^A;ZU_NT`8M$}Hk&)_#aY#8duIR|1Y{t|Fs8J=9
z_*rkxOA46^;WL((Xa^wV?*@6jeXFkw&$uuq)8T!Vz${hP6Y=2BDm-FmM;J9``95q~*A_|b>RHNw&=
z;CGf*T0ivv`!Yu$BYk!=O&b5F(T{UGHD06=TGli}BGRg$pDiqLufkC!eH|NV^?4iZOyZdp9!2b5
z45ck6^V3};;#xV6?giFEcS6!3VYPshun3yZarI(OmLqx4XY8=JP#$B7L3G
zbPE06DmU~6vabn(Oi@`H-WqU1{E^Dd*>qX@XMFCl=QO$pt0rG&9f;uE)
z_%F)`mwn2oJx_@_ba~A)D$?byrOTq|>L>q)p5Q}cH*hBAhk>sLASYQ=*X?!;Ys)On
zDwQwD@CW;|fL1)c$yLK1bwk6=N_
zc*-73ye=2G3Zjgs5=CZx7*fk6@umd&EMnJUK}U|Bp}$l{G`}2*#;!jRSEV(QyXiCw
zOb^XZWS7`ts3bVjFbXhH&LhK;R8F#@I;Sq7XX(_-s9)|Ua$!QycD~Gs9{0l@cHyi1
zjyfRY{SFR+L8-0T6|U~kxMsJYLuh+Tk=nouXX8nfySzfQ3uQTa=FpBL^Kp^QQbv*V
zuWNO^xz*V^F*42ykUTQGXKjCw-aHAvEgAe6oj87GT<4b55khKb0A%2zU4-
z{!ZMzn1DH)P^j|#%JcjY(1uqM{59D5BQ2VZ#psQDD^pQU-kQ2hau3r|-Cyx!YICTO
zm-}jw0OUspF*BIKa!H{ubN0>M!7kz5bf;_)Yu_E?%birvkr(1d6pfPIZjo&Sl+bnT
zpwq1xjzq9REW(ls%zDA$Le*Go$W+2Tc8c@|AH9bLS(gm3bV(4@qg%C%5TtxJRUGnv
z7`uli;kqSCz-8OEZQHhO+qP}nwq5m>ZQHil-{eO0pa(rU5qbW>&dBwwMX#nTEAdga
z4{w5hY_2ZyOj4;;)N-1-QI%crSdWxR_M?>}E^sHns8f{6bACT|4`sTmz50sxpgwC%
z7Ye-*iZQ(JfIv!HVD9Kze>*uW$$_~T!S*d^AV4A_=_0*+UV7ns$GARt9`(^TSgajd
zrQlkM?Qft+y`{od3=UybMQSsEJW>g1_OO>%-s&ksBII-mkq43T*F@xD+@lo*50
zqn~{_WUPQ9OLYV8NYs5kF7amuTc#n^zqh=>&4@TOH2e0T@~!Sfg9CRujHT|r;=v({
zhZF6()2|RJwLBLr()c&=r-5%FN!@Io9`l>WwzSn1R8-Jozj!EEilGgfSF4kJXDGo1
z+Q!y8I!tAB6-)9p
zbUYgqcl4y>Hgb^t3ci)rGk#>CGN%(*YN6JT>r)&!KSwr6vV>_u)BY96qmgkdWeXKrt
zuN!hvG%)k2pZr9a}(=ZwkR)YMq{K|)D&7wMotjL}OuB8YVBi>$@V=xEKF|R#;
zNUkn32*&fb12eRA7RQ@4emS0Z+6Q&aN~F$V(Q*Mb8)0mwQ|6J?eR2#gS147EM8KeV
z*yl^or$>7n(4AAAe`(ybR)3sqe8)7wE4gggfPSz5X}^&d)Gty5?s>oC5T|Nfm#Oe3zU
zk{XkI#R_UF9YwfYNWksmKY%dAr{lcaBw^;WGpeZNk(UH3ofpgq#zk>FsGP*{z9{hJ+*Kp_8@os?TKGSsHKm
z2mEc;jCcbaa9-AUp|=Ax>QL171-Y{o)-6}7B+*`_38)72|G+zUgO!%w^P8@MF&_4B
zu42fq<+*!5h8rba6y#z|s-N3$u}1u>{;UkJiEtCf-|n%(j=?TeSqV*(2GOYgh226d=Qj_!o##t5IcDwA2jX!X_t
z;rICsn-G01;7dAcgl(K%^{hY$G+m0(>chi$)X1G$X1>pS>{5$#4=fFBSp|!mr#@q$)i(D5CP`Wmd
z5hJ}0?3+S#@faPu~KT^B~UhOa8N+sX@ZKDL{T75BXL9+##?hFb8cRk>s~)=|77;(EW%
zAf}2PM<}OW@@!P;xa*0tD{j-26ySB@UI@&vvlz!xdFjfBv`?{DfMuFR)-(pb@jj%L
zM&!7Zon)z>)tkR1kT<~?)^%E+9$rH~N$?t^@6=q|gw^H2znplErF&kH=jVt!v6vLC
z@!~a*1=7m~
zWt%Js5}V^bkgp5*NO?`083|Xyp0v;mvGlHSlU)_j>#yvv0@?=#fzB0KPRS6E0DK&4g|6R<
zPuujCn;5~io>22<44>s{M)}OVm6{5-Q{1;vLRK-&+Q6iW$zN?MJ!a2CDJTQ^5ji^>
z&OG$6+JEJ#^MO9qnv?4m-b{#upbSg?dkV|qTE_G2hG)%^xvEDNf82R?PaE{HXh=Sq
z`d7mEFh18_r0OHM;7)TTX*Je(3^&i`A`Xhdr+5aZ#pg*6b*+&lAWEhPGI3!|l~j)M
z#8?u5Ib9FZY4TyqGP$uJ3ll4j?Cm;iRK#;8X0nBqWmZ_Sf?;k`$;CG8&UHirhG7*G
z4MV_A+ICUsIB_uJJLOSTeVTS#vS4eRtUEV{k~0?va7v--kjvZ?z$
zi5oc>WAC}`tyOUC(q#A;RUH$;uJ|j|&!3q^=$gP#l3($2qNnpP?kI+GsD-OqObekL
zqxq>JCe0Xn*tT19UFEcCeZE3Gmii$&Q_u@|W>go4meZrp`z+C=O(enIvCJ3Yd~EiQ
zM^WYV3mxyEka*zlcQc@N>_1CX
zGp9Le#ti_V4-~S)-62G#)?^q>aX#=gdN#rKMmiB
zvAp#P1f4Jwu~KiE+qp%qNGRs67>Yk31Jzy17&7YRn0Ti=6kC50SQk?Z=F@7LrD+BY
z6v_UP0TWJoul9J#u97N|fkqX9TrI(OD)C_Q3lDZR%eVDWY!x*iVfFZV<9tL$1ZI)5
zWMi2U_~Xpg;8tJ?`DC(Kj+!?_Y5iP*f~~hZ@9W6d>Ov=k%DXUIK)D!FWXW}GZ64Uy
zii(~ium1DGp7s1nt892iR;W9i7$wij<|UFlWSlDEY5WI|99Hc`uI4v&@pEsiOxO)o
zZZ;Fv6gH)3%B7@wH|`SJsKtRL0G?bp-#EqD+jiS
z5p49^;Kr0Y{EnzcrgWR*t2mjGd*wCw_I-pidQhh2OkCxQoiYQFCh^QtcLkRaaXL{7
zv%U~}`^Rcy79zY%oPCP-HpR`6q1{bU1T)@>XqwV-g<6RYPETf
zB(o(d?@^LQH6YMtYwMj6Hq3c8gW{0kYJc(3TBhC4|8tI{H{ii5Pc2gC&cbRVfetm{
zgju?j^^<`2#twIBL7*&8R=Iz(sH1l^)_d$R|cQr&ihCd%hVml1*EQv7ZB+(${#P1hD%KnsE^mir55
zcv1{l9LisOrFyCQkx3YH|9QMi&VfxTRyQ-ib4Vq~;wmz+XL*Z!(~xJH0wtKFUsSqwWHMW)_{mbv{(P!2n|^LXas?SLK)
znf<6VL#SQH4xgo3Hz$n4V9e>_G(XQZ#bj^eL+1K2#QSssFq)tR>ED$!752jA6*r={
z0AG>ok2YLWA)=_~7QF?O)n&1y;f3bVB#Lx^wTj@_E65EdJx%ST4Q>DRGZK&JShj-P
z4b;P>iH?#tau2{)DC+|H{&ol(gx^vtuQ0bSa3|=_N(S<$}
zW0!JZHoW)bm95tssdbv9Dj`8guLgqjn=dwkAEG^-`Rm*kR};+Ut?g2kwL^~o%8`=X
z(8{$vKOfE8LS_*#b{bIqz^!vgvlftOM-1;ETYBGGNp4D{P4@Fa2{L+vXDb
z6Ve{Q?2mY!tJ9N+;~{d-IP0!9Gj%;2kl5=i^RJ>XrQ`l4iq59}cEA{sOYN6>!YxH@
zr6mIFb;yVmY{|maXTCj2ty}frbl(UZ|LhB1-)H=liI1aQ?i`
zAIS|S1VQ4Wahz4M9#oLN?_t!<=PZxkoSsgASp$MAf2XWI!Se4ml@M!~^_GG4EteWy
zhj*M8d@l|I*Vn#tigh0c`S(P;4Df0``~0EIU!d_h-Mww5Molf;Vt*(D5;{^R%E|_d
zk;IK+p`%Ngldk#w@!RXUTW-8F6WH#i>^sAhgwW8QykUq?lXc*UuB#n4`;uHj#4-!|
zE@~?lTm+9DCkt$6zTtk9faou_GfawHzK9#kQ!>2s0<0aa-#083I;E5w?>n<(li@xE
zTGB+4OG2QUQ41l5c|@{ArEWlMZ|?5$9$>P3v0g`jQC}xSgQ*MCuYYp7-%@>LkjW7@
zl8A8B59Z}~J{Ox8-2tc&N@|us>x0*tfk+^Q(^@k*vN~Xb?$yo?*y(eu^~u}$VtHy&
zlK7&TIme62M><4BC$kEeq9N=`peSKF>Cc~fcBaqM
zdnXn&=qlLZs9VdpfL@&9>K-(#_^#OK@@jt|pTlaMQdJLxyOXW%5QoCWjKxH^ZR4Rm
zHtjO-nDodYj``4as2WA7GMoBv+)B=k{n%NI5!P)+NMB}e~!LbOmPwCHmK
zt!}sb(T)~m_U8*6$c0QwHwqd%h
zA<2yP8{utV0o)e!8m}v76VxsgX^Q{c_*7+)V(IAd6nU2yz;F+UPT0HVzz+xP@BgE>fOQ1u^@YG_$@AVytYUUNK;^+zaTNZ6MHe2?
zEi}#ZMPhhiaWpEjO*y2J=*Xsol}sbGJ9euuM5%Tp#K@>i4;2k5b_8vr)mJk$-RFZb
zp3bNuOu=KwgrHkJwIB6{3j_}c!?IQuf6sQqBw42O5_0DS?FS9^5-GiJ4TbT@C!^oa
z%4=xnJyi!Y)S7zv0!C}Jn`R&m?86TqTeozX;`k87tQ_e)|#O}$p7bQzB>Ce4pT0JQ<
zGkY0|T-e*RVH76aKP@v1!&ro1tT^qU9sRdsTg|LV+prNzW=zI{Ab~j@1TK;TfCQrr
zlPzo4))G_sMbB$|7Fr+wuN%!adT*=twRam@dxJm;`FxA>37ZiZVt5mb*H-cP+tR=e
z&S;=W$R3`>9l-2yKh+s$uFuhz>fEL
zG6(l|lV1pDp%vkYls#z(8gpljRXg3&?H~##Ugdt9@}X}b&K|C+Q;~-yV?Q-Z{CP##
zG1}FFYoFoZj5B-)Gb0}J6%+F~Fja3ldPQ?HwJzE_Umf4)Uskewsr~|>3jQb(+i^3U
zMxS4v6C(l7Z>NT4ZNp
z4QL`{s#DdD?Kotq4in9a>7^6kZkb;S$(8H!<8Q{8GEIKB$SWydib4jsA2&kuE;FGG
z#vZ|#@D%H=W?c*JQo*O}MOJ>$7!mH3kyXgVIe0(QVPdT;()yjHu*bGA;a8stT{4c-
z(22t!Vx{Swm(GtS%|%T0poa<&5!=(;nmgeHw84^6n4e%_B#ssOuor~hc{w&@bAUiX
zPA$fP!w8_Dl=7}Ly7xNAPv}KV)WiD+U?51$_djjZ6FMglaNWgh7_?VRR@jfY+sq|d
z8ogw~TyOdZ_&TlsRyF>sf7GGKL?qVB;C9^lnbS9v?VkrZBLf#?#CX8mM7o7La#0O`
zB8F4!M5AyFv;rlB&i=RZ
zZ_B6E815Kt(mLIQ<099^DIV=7hh52-Dtk$urZ{?K7M5|Hnb9c0D
zvt22)MI1eGY*@0vV!o!$uX=yXe4KrgOR6pBA9Nf_iZ7%8m^<=e?4a!y!>p*^BhXf4
z50Hfj_$W2CN<+qyrC{)j<)!K6geJ(EgE!Vl;b!Fod9JVE2}GvJJ}X=~BC?|^1LGg4
z#}Aoz$T$V85SKVvsP$$)(E_dkgh37#6+&dhFK-tJDEri<_9I>$Kp1Dr~uZ$jdbfHIj`u5AGM&5no0d;Yn!Md*v>;6-eZkJsd
z>*cgyIbMO!om+CP%1rF6JRpu)&o7U!As{feqir|YK=W08?e`_{qZ
zj<>u7>TZ_DcBWpysv4Ea`k766R)sz=)f|L`!!Xv<$hrq)anThM0un2pmJlB^7bfF4
zF4CoQhIG+5Gw_eY7un(vz7=X%i0%Ys9>ON!=$1Zf^Gt?xs9<)o0YYz?}c^gR|J55nLBt?vY%Ncoq|h2U)fVE
zU;Aa%uVM6?oWvTcosb+M^(b1S?0UeReC!R?)03L!$giNOX07=3%~#MRvR>UMeisJh
zh5LA1Fbda?-*Ch$`_j_plf0vNED-5wK`Bnvt
zi?Q*e0bNaRL1mG_L4WTQ<|?TBdsdy5EUG7c?%^BE;zVwrCQ#K$qx5$8!d^F
z!IgSYKUKM?=ox5?QYCw?wOpnJSPz#A+p!C;4?~`FvM3&eKRSG<71Svs)5^i)%r1i=
z;F|k4>Ww?YOd=ih-KHF23C$rixNp00>Qqo_o?+SQJ+km3BY6p}N*!HAQjRR{M9%%Q
zO#G{fRx62@FNvU0Ce2-frZJs*_ph6)6sZ-}59g-LloZ2Z6~fQ;9z&GZz+bFOw7%OK
zP{iiLP!xaT3#tkADV1QpwtftkL&tpzBua0G_9y-8JZw$(R$g~
zJmA>ETsZw{@ZakT#;c-oJVGVukkcDqyrU5X{!96Kc;Ds|jBK&VJHs77IGtk~%}4AQ
zaNlR74(02i$$8%_tc9c{RPmM~GRfB@rVSi)9q09Js7R%Ui*WCGS&OXwz}lDE!K<7Fa0%owN>U0JY)#Xf*xGOz1y=
zkdA{;x=r10^;F-ok9aIt$TyZ21?}>>29MX|JM6NWFes$YKpG-=39GFw>=nq0*XgkD46$WBBezU
zjd7+Ub)J$X17Ia$6nr1ElUD2j=W=aZ}h*VjN*GKx%Y?n+H2D4T7FDcDVuHvM8d
zS=;qQ7e9R>-2y$>noe$TW`|j7Pn+hIuU-|-O#XT=(oNRO!sQT(OI_XxiLbUI@}|5m
zFx;>6X#Zu-rwDiFN}B}oa>tq{;4LV5o$}$j+JxiNY#7ZSqA`W-?wrE9J;mE8QiEhD
zm>xYWQN`~~rNGZg^!S5>T|}SpoP-`%3rJl2n|+IpO+v_9=k^y6RoeJq5c8P&aO%Ou
zGHuiu4oVBc%lBobWdT3CkoLF!Aw`yHhSF1bRBAM4=>BWMO7YSj0O=KRx;T$0gX~)V
z{N`Nox~`Q3nfHP$lQR*f!MJCZ_t<_Pde3U;w}#)(JlciI#y%n5&MytA5o?W!XAcj=
zYp%<6m+AD~sAhQqgT5C(0eWtO$$gYn%15kkVdg2w4?Lc_z_@Mp;!mWSF#y?`jim1u
z(jcSYzwn&J+7|q$r~(0lsr_H67=n#`E|Q)Ru6A6gBs1ab;A6^o?mAUZ)v+DWGG8)(
zmfAMn=?V?(sxQ|j=X+pW#Dg?yQcxh+o%W=yG`30rG8^>Yy+ZqUJVyf~JkA4NTuWiw
z&=t8LuyCkr#B5d$e$0IesOh9+g%aGbnB)p?p_+qKc!XPTQp})ECtdJO4_!{Z(b7cN
zk`Zd$QX$}F8wV+86BOd4bhNKO+{h9bT*HJVV5GjA{Yf6rY6MX<
z0r^!`NT087=Xo9l&?_|IAAcXHoXPQwPau0y*(Kyw*WQBO%_?C}=Pyh)N8v=S~N%
z=jF!jP*pd~P!FqPz)bb*mx+YTP;tkieCJ|4GTOTzROyrJ)b_to-U(e=_ZK=cDvhVu
zdWh@zb7k5-F1B%qVXI2UhA+Kx#G5QFIep)U3<6yPIAH1pb+KN1y=SpNBM$~U?q+Cw
z13zj{L7TNgvzprUiPF%&iJW|TQ_J~(!KS>w6eL~Ov9X^A@;CHl>ruU(lyi%=rAD~m
zYq?H&J&N|WtRjT;ethi}{C8l03qf|{uo91J@uHjDb&n#ma*DpfS*X(;lJulV!ZvlH
za48B1cL}K8g5gCsBUVACGBUlHzpu5hy}h6w*!5F}QDIowJ6Q7)bRJ{#R9mn8QtzOK
zP|O*Hy9L4cS=e!WeDvTis;t*HB`yZYvVlz2E$jvlW4X8+N%ysrB%;J#GBqa8=H6Th
zF;epDZB(i2m39^I9biaLu|flJcqI`z7Z2gB0EpuLWC@8k!v({+*Tv^qm=r7
z@4FtJD=U@XyZU3m_#2Bq**W7VbE-In}q`L7;pCW3#h@c#jfhkk>?i$giF
z_t_4;pQ4j?C}~72k}^%7N7}j>2QwcIgBZmBmmx2RlhMy?N?YslqrMlU@9xZJfrB<{
zOI+6V5t0yi>hhJkmCQA)NL$$%N&w#TDFm(a-np&Rn{fZ46JmA#mlRev+G{|m#2Lbh
zSC%iLMJ17A2;6cNxSpw7VBJ-O&EcGx_5KIyfE<7AG4XrLUoS1yg9tvnO(Ex_z3X+%
zxBLa@w(E*6+N=t$6-bbOxKHJmA%*`2cB~}0#0l!q1o9|dzS{mV@eRgypauf@6Uk%y
zG)EBQQ{DtmCGZ)zVGue;8`?N)j}!u}gj-CS=Ef7n<;js)d75X9QK^+n?u>Ee#9>L-
zemci&I8=jf92U8+q{Qp0QILPsTWybe+E<&NobhPCU;*=waqMR4xMhOD?=e|Ke;FJC
z5X^yD2}u#KR=82F-VmY`lKa~7-35(ei&QGD`(K4ZNr(l}v*W9VqPn&}4J3N&Qw5KJ
zDz+yy^+w0@+2Cl4G>2e5Yc6=|Hq<*#a3`b>oXMD%VtwS>^Z^Kst3W%P*8vNk_F!0n
zu%(q~kS3ZZ3M?a>d=Nt?va#~(UM2^U5{1bA{yvN0fb(U{C0}f3x$#36bJ)IO_u$x9
zv`!x{rLLaKjE1=$sYm6E9nSTL|K;qcs4V&2^@lWernf#4AvhwD6Q<~{v07KUHRPGS
zs&$g*cVfz6h?#2<3fqUV%2c|rFV@I9qx_t0Y$vYnE>)<(M8k;Qg3%_aXK0OnHj`ZyCsy`DP@SBFTYX!Bkgir$41O)AMBvp
zU>HvAm)*vcqJ3tk0l(o@WfgRHIy?KU}}(=j9IXX`~3Z-i)zfUd~FY>wX@-1J|rZ=M^9NN%UN&NhsD?ehIK(0Em}dyi*8tY&pOaCZ{|O+Rm&+
z1>OYx9Jnb(H!DqeOi`FU-8nEKfOAtFdse7QR^^5xE+a;*vsF>!*bFn9LJbFTL4P?h
z2jbhy)x54({3$-W$#|P-t!T=Gi9(I1%EXOkPZuX%2foCkVer7z|xM?qo<1U+hRYZ<5%Tge-
zloKr|cVcXwMf5;T6}9hq@!8N2Rot*Smarp;nC9M4!SzD;u!KEq{6>7;nX@
z=35d;WncA|yb+7Ulv
z!(9`+h+kk>*{Olcn-Hnh(rYh0_9{-(oj@L+N_+{LgT<8;JzusBlfyep_9W(}pXem0x_wqa(PtIH&P&61M
z?eQygI?8la&m%Tbht=tpz_#ziee)Ex6ycpHX|}boi&oBt?r*-8_HZ7$@3$XeqDU?`
zUlY-?;^nH@6(k}{h2U(UkmQe3N?2~!`v(rLRxMXZ9>VXQ<&(IM$4^Wh0Xy<2=~^R=
z_XzfzV6iUPESm2s*S_t=J!W`VfL)+wvwBQKo#TLWE#K?bnwfyR+GT|#k8Ycm|1;ux
zGfYo4nVP3HmYS45+%GOykdqR#G#Zu>#bxPz_q7OqR;XU^%n$V}V5_p1Z-bNsf1P5a
z3;)_0))OrV2fIHY(Igi%wKl<7XP6c-aPjDfvWo*TA9x$@@u@Qbs4|Q1TN0UKcu_SL
zA#G*>#P1#|o%9U-x3t)FEAx^#m(0E1sMy@JwCfe4U#j+d2f6nFzk>|2CeHqexp|wz{!GSt=>*
zX3@EZNcp`|B7i?XxXoLkBRz6GL=;EPVu=Y69oAER^1~76BAHG1)%v;G6MeIjrm1W2
zG=>Cp*G-(}2I$pcaKLzzby24nc1U!mJi=VhO_FZNVfk}
zFl5Ec^5G49y;kZ?*2mGu&T`PC4p`_1J{M!SbR;o`NWm~4C?3*eZ%!pZw
zwsRb=z26)G8(#tbYW#*Q2yyYXBd!P(+_1C^F%LXJ*~xdRAMEaNnFuD&FjO`M@h
z!k0%u3T+`-8*$E&>w9wmyGU)<`8)cQIeq*x5@#7RiIA>Y>dWPUQ>7zl89>vwtTp8H
zLsUDpKYfG?qH$sJ%*E8|-nA9CX36odOQ6W4ossRMo`n+_^R-lXWqIvq=UExLQNhPe
zTaOGqU#@ATzHfvdxLWb2yJO0$N<8a!@sYU|`)Q-75}(NGb+8EXwyTE<5fcp?CLL&N
z4>8=2XV=h%Qps6HS!XOo^l2MIy`#Z28+*o?F-~$ir7%7R9s)w|zu=*rR;@K>?F3BOHQLT259RicxsqZjUS{*+tLlyi^
zst3#eC1MPYBq4rO6<|W^ao0j92TkR9BKWJqD*i6r?}HWg(o|Bqj8$N&XuKf+0U(kd
z$CN|3KzEk-Vs(%?7ef1kjAdB~*Xk|?J0vTs55kSS+smxx-1@$WkJ<#6P`2fz2Z=l6aSR8BXid@cuSPKa}{gg5y`
z1*j~qwXr7Il%|~0%v3{v!V^%4WewVY5j#kCAF>gv3dHDHqk3A$e@i)JiAi
z@pqy@B#wS$J~VOMKvc_*Iw=HPoI}z%i`cxaIhr(>v6Vv%al`kYLFLmY
zpraLP-4Yj)>O^1)yTrm4n06&&zE!z2kEw<#Q3l-&*7f_BTXy)Q{E`E>0;rz_}Qy0DTVnnajIZUoJHisn^4<{OI@+?MVc{V=1}hBTc;!_N7x<6_cn5cMDwT9)|j9u
z&{mR$0K~8FdYNSZBpi$
z<05(K2RsE;)tGkit&fs^k}?i$N^qK=n&Go0>n|2Mie*0I5A<>)ZxP3KUv&K*e