From 6ecfe6516f2948a3f3ce2eb91696f27d22ac9eff Mon Sep 17 00:00:00 2001 From: Corentin <> Date: Thu, 19 Jan 2023 16:28:48 +0100 Subject: [PATCH] myoquant v0.3.0 with ATP analysis --- .vscode/launch.json | 8 + CLI_Documentation.md | 104 ++++++++----- Makefile | 6 +- README.md | 18 ++- myoquant/__main__.py | 6 +- myoquant/commands/run_atp.py | 261 ++++++++++++++++++++++++++++++++ myoquant/src/ATP_analysis.py | 114 ++++++++++++++ notebooks/atp_exploration.ipynb | 4 +- poetry.lock | 182 +++++++++++----------- pyproject.toml | 2 +- sample_img/sample_atp.jpg | Bin 0 -> 1133646 bytes tests/test_cli.py | 14 ++ 12 files changed, 586 insertions(+), 133 deletions(-) create mode 100644 myoquant/commands/run_atp.py create mode 100644 myoquant/src/ATP_analysis.py create mode 100755 sample_img/sample_atp.jpg diff --git a/.vscode/launch.json b/.vscode/launch.json index c4fc913..a970ca1 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -19,6 +19,14 @@ "module": "myoquant", "justMyCode": true, "args": ["he-analysis", "sample_img/sample_he.jpg", "--stardist-path", "sample_img/sample_he_stardist_mask.tiff", "--cellpose-path", "sample_img/sample_he_cellpose_mask.tiff"], + }, + { + "name": "ATP Analysis", + "type": "python", + "request": "launch", + "module": "myoquant", + "justMyCode": true, + "args": ["atp-analysis", "sample_img/sample_atp.jpg", "--cellpose-path", "sample_img/sample_atp_cellpose_mask.tiff"], } ] } \ No newline at end of file diff --git a/CLI_Documentation.md b/CLI_Documentation.md index 7e2254a..48f0147 100644 --- a/CLI_Documentation.md +++ b/CLI_Documentation.md @@ -1,6 +1,6 @@ # `myoquant` -MyoQuant Analysis Command Line Interface +myoquant Analysis Command Line Interface **Usage**: @@ -10,13 +10,42 @@ $ myoquant [OPTIONS] COMMAND [ARGS]... **Options**: -* `--help`: Show this message and exit. +- `--help`: Show this message and exit. **Commands**: -* `docs`: Generate documentation -* `he-analysis`: Run the HE analysis and quantification on... -* `sdh-analysis`: Run the SDH analysis and quantification on... +- `atp-analysis`: Run the fibre type 1 vs type 2 analysis on... +- `docs`: Generate documentation +- `he-analysis`: Run the nuclei position analysis on HE and... +- `sdh-analysis`: Run the mitochondiral analysis and... + +## `myoquant atp-analysis` + +Run the fibre type 1 vs type 2 analysis on ATP images. +First input arguments and option are printed in stdout and all modules are imported. Then the input image is mask with the binary mask if provided. +Then depending on the presence of cellpose , Cellpose is run or not and mask accordingly if binary mask is provided. +Finally the ATP analysis is run with run_atp_analysis() function and the results are saved in the output folder and some info are printed in stdout. + +**Usage**: + +```console +$ myoquant atp-analysis [OPTIONS] IMAGE_PATH +``` + +**Arguments**: + +- `IMAGE_PATH`: The ATP image file path to analyse. [required] + +**Options**: + +- `--mask-path FILE`: The path to a binary mask to hide slide region during analysis. It needs to be of the same resolution as input image and only pixel marked as 1 will be analyzed. +- `--cellpose-path FILE`: The pre-computed CellPose mask to use for analysis. Will run Cellpose if no path provided. Required as an image file. +- `--output-path PATH`: The path to the folder to save the results. Will save in the same folder as input image if not specified. +- `--intensity-threshold INTEGER RANGE`: Fiber intensity threshold to differenciate between the two fiber types. If not specified, the analysis will try to deduce it. [1<=x<=254] +- `--cellpose-diameter INTEGER`: Approximative single cell diameter in pixel for CellPose detection. If not specified, Cellpose will try to deduce it. +- `--export-map / --no-export-map`: Export the original image with cells painted by classification label. [default: export-map] +- `--export-stats / --no-export-stats`: Export per fiber and per nuclei stat table. [default: export-stats] +- `--help`: Show this message and exit. ## `myoquant docs` @@ -30,11 +59,11 @@ $ myoquant docs [OPTIONS] COMMAND [ARGS]... **Options**: -* `--help`: Show this message and exit. +- `--help`: Show this message and exit. **Commands**: -* `generate`: Generate markdown version of usage... +- `generate`: Generate markdown version of usage... ### `myoquant docs generate` @@ -48,13 +77,16 @@ $ myoquant docs generate [OPTIONS] **Options**: -* `--name TEXT`: The name of the CLI program to use in docs. -* `--output FILE`: An output file to write docs to, like README.md. -* `--help`: Show this message and exit. +- `--name TEXT`: The name of the CLI program to use in docs. +- `--output FILE`: An output file to write docs to, like README.md. +- `--help`: Show this message and exit. ## `myoquant he-analysis` -Run the HE analysis and quantification on the image. +Run the nuclei position analysis on HE and fluo images. +First input arguments and option are printed in stdout and all modules are imported. Then the input image is mask with the binary mask if provided. +Then depending on the presence of cellpose and stardist path, Cellpose and Stardist are run or not and mask accordingly if binary mask is provided. +Finally the nuclei analysis is run with run_he_analysis() function and the results are saved in the output folder and some info are printed in stdout. **Usage**: @@ -64,26 +96,30 @@ $ myoquant he-analysis [OPTIONS] IMAGE_PATH **Arguments**: -* `IMAGE_PATH`: The HE image file path to analyse. If using single channel images, this will be used as cytoplasm image to run CellPose. Please use the --fluo-nuc option to indicate the path to the nuclei single image to run Stardist. [required] +- `IMAGE_PATH`: The HE image file path to analyse. If using single channel images, this will be used as cytoplasm image to run CellPose. Please use the --fluo-nuc option to indicate the path to the nuclei single image to run Stardist. [required] **Options**: -* `--mask-path FILE`: The path to a binary mask to hide slide region during analysis. It needs to be of the same resolution as input image and only pixel marked as 1 will be analyzed. -* `--cellpose-path FILE`: The pre-computed CellPose mask to use for analysis. Will run Cellpose if no path provided. Required as an image file. -* `--stardist-path FILE`: The pre-computed Stardist mask to use for analysis. Will run Stardist if no path provided. Required as an image file. -* `--output-path PATH`: The path to the folder to save the results. Will save in the same folder as input image if not specified. -* `--cellpose-diameter INTEGER`: Approximative single cell diameter in pixel for CellPose detection. If not specified, Cellpose will try to deduce it. -* `--nms-thresh FLOAT RANGE`: NMS Threshold for Stardist nuclei detection. [default: 0.4; 0<=x<=1] -* `--prob-thresh FLOAT RANGE`: Probability Threshold for Stardist nuclei detection. [default: 0.5; 0.5<=x<=1] -* `--eccentricity-thresh FLOAT RANGE`: Eccentricity threshold value for a nucleus to be considered as internalized during nuclei classification. When very close to 1 almost all nuclei are considered as internalized. [default: 0.75; 0<=x<=1] -* `--export-map / --no-export-map`: Export the original image with cells painted by classification label. [default: export-map] -* `--export-stats / --no-export-stats`: Export per fiber and per nuclei stat table. [default: export-stats] -* `--fluo-nuc FILE`: The path to single channel fluo image for nuclei. -* `--help`: Show this message and exit. +- `--mask-path FILE`: The path to a binary mask to hide slide region during analysis. It needs to be of the same resolution as input image and only pixel marked as 1 will be analyzed. +- `--cellpose-path FILE`: The pre-computed CellPose mask to use for analysis. Will run Cellpose if no path provided. Required as an image file. +- `--stardist-path FILE`: The pre-computed Stardist mask to use for analysis. Will run Stardist if no path provided. Required as an image file. +- `--output-path PATH`: The path to the folder to save the results. Will save in the same folder as input image if not specified. +- `--cellpose-diameter INTEGER`: Approximative single cell diameter in pixel for CellPose detection. If not specified, Cellpose will try to deduce it. +- `--nms-thresh FLOAT RANGE`: NMS Threshold for Stardist nuclei detection. [default: 0.4; 0<=x<=1] +- `--prob-thresh FLOAT RANGE`: Probability Threshold for Stardist nuclei detection. [default: 0.5; 0.5<=x<=1] +- `--eccentricity-thresh FLOAT RANGE`: Eccentricity threshold value for a nucleus to be considered as internalized during nuclei classification. When very close to 1 almost all nuclei are considered as internalized. [default: 0.75; 0<=x<=1] +- `--export-map / --no-export-map`: Export the original image with cells painted by classification label. [default: export-map] +- `--export-stats / --no-export-stats`: Export per fiber and per nuclei stat table. [default: export-stats] +- `--fluo-nuc FILE`: The path to single channel fluo image for nuclei. +- `--help`: Show this message and exit. ## `myoquant sdh-analysis` -Run the SDH analysis and quantification on the image. +Run the mitochondiral analysis and quantification on the image. +First input arguments and option are printed in stdout and all modules are imported and latest SDH model is downloaded. +Then the input image is mask with the binary mask if provided. +Then depending on the presence of cellpose path, Cellpose is run or not and mask accordingly if binary mask is provided. +Finally the mitochondiral classificaiton is run with run_sdh_analysis() function and the results are saved in the output folder and some info are printed in stdout. **Usage**: @@ -93,15 +129,15 @@ $ myoquant sdh-analysis [OPTIONS] IMAGE_PATH **Arguments**: -* `IMAGE_PATH`: The image file path to analyse. [required] +- `IMAGE_PATH`: The image file path to analyse. [required] **Options**: -* `--mask-path FILE`: The path to a binary mask to hide slide region during analysis. It needs to be of the same resolution as input image and only pixel marked as 1 will be analyzed. -* `--model-path FILE`: The SDH model path to use for analysis. Will download latest one if no path provided. -* `--cellpose-path FILE`: The pre-computed CellPose mask to use for analysis. Will run Cellpose if no path provided. Required as an image file. -* `--output-path PATH`: The path to the folder to save the results. Will save in the current folder if not specified. -* `--cellpose-diameter INTEGER`: Approximative single cell diameter in pixel for CellPose detection. If not specified, Cellpose will try to deduce it. -* `--export-map / --no-export-map`: Export the original image with cells painted by classification label. [default: export-map] -* `--export-stats / --no-export-stats`: Export per fiber stat table. [default: export-stats] -* `--help`: Show this message and exit. +- `--mask-path FILE`: The path to a binary mask to hide slide region during analysis. It needs to be of the same resolution as input image and only pixel marked as 1 will be analyzed. +- `--model-path FILE`: The SDH model path to use for analysis. Will download latest one if no path provided. +- `--cellpose-path FILE`: The pre-computed CellPose mask to use for analysis. Will run Cellpose if no path provided. Required as an image file. +- `--output-path PATH`: The path to the folder to save the results. Will save in the current folder if not specified. +- `--cellpose-diameter INTEGER`: Approximative single cell diameter in pixel for CellPose detection. If not specified, Cellpose will try to deduce it. +- `--export-map / --no-export-map`: Export the original image with cells painted by classification label. [default: export-map] +- `--export-stats / --no-export-stats`: Export per fiber stat table. [default: export-stats] +- `--help`: Show this message and exit. diff --git a/Makefile b/Makefile index 4304412..1f271d6 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ black: - black app + black myoquant black tests black-diff: - black app --diff + black myoquant --diff black tests --diff build: @@ -17,7 +17,7 @@ mkserve: mkdocs serve mypy: - mypy app/ --ignore-missing-imports + mypy myoquant/ --ignore-missing-imports pre-commit: black mypy ruff test diff --git a/README.md b/README.md index 4ec3e5c..689986a 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@
MyoQuant๐ฌ is a command-line tool to automatically quantify pathological features in muscle fiber histology images. -It is built using CellPose, Stardist, custom neural-network models and image analysis techniques to automatically analyze myopathy histology images. Currently MyoQuant is capable of quantifying centralization of nuclei in muscle fiber with HE staining and anomaly in the mitochondria distribution in muscle fibers with SDH staining. +It is built using CellPose, Stardist, custom neural-network models and image analysis techniques to automatically analyze myopathy histology images. +Currently MyoQuant is capable of quantifying centralization of nuclei in muscle fiber with HE staining, anomaly in the mitochondria distribution in muscle fibers with SDH staining and the number of type 1 muscle fiber vs type 2 muscle fiber with ATP staining. An online demo with a web interface is available at [https://lbgi.fr/MyoQuant/](https://lbgi.fr/MyoQuant/). This project is free and open-source under the AGPL license, feel free to fork and contribute to the development. @@ -41,6 +42,9 @@ Then you can perform SDH or HE analysis. You can use the command `myoquant --hel - **For HE Image Analysis** the command is: `myoquant he-analysis IMAGE_PATH` Don't forget to run `myoquant he-analysis --help` for information about options. +- **For ATP Image Analysis** the command is: + `myoquant atp-analysis IMAGE_PATH` + Don't forget to run `myoquant atp-analysis --help` for information about options. _If you're running into an issue such as `myoquant: command not found` please check if you activated your virtual environment with the package installed. And also you can try to run it with the full command: `python -m myoquant sdh-analysis --help`_ @@ -55,15 +59,19 @@ Creator and Maintainer: [**Corentin Meyer**, 3rd year PhD Student in the CSTB Te ## Examples For HE Staining analysis, you can download this sample image: [HERE](https://www.lbgi.fr/~meyer/SDH_models/sample_he.jpg) -For SDH Staining analysis, you can download this sample image: [HERE](https://www.lbgi.fr/~meyer/SDH_models/sample_sdh.jpg) +For SDH Staining analysis, you can download this sample image: [HERE](https://www.lbgi.fr/~meyer/SDH_models/sample_sdh.jpg) +For ATP Staining analysis, you can download this sample image: [HERE](https://www.lbgi.fr/~meyer/SDH_models/sample_atp.jpg) -1. Example of successful SDH analysis with: `myoquant sdh-analysis sample_sdh.jpg` +1. Example of successful SDH analysis output with: `myoquant sdh-analysis sample_sdh.jpg` ![image](https://user-images.githubusercontent.com/20109584/210328050-11b0b6d5-28ec-41a4-b9d3-264962d04fa3.png) +![image](https://i.imgur.com/4Nlnwdx.png) 2. Example of HE analysis: `myoquant he-analysis sample_he.jpg` -2. Example of successful HE analysis with: `myoquant he-analysis sample_he.jpg` +![image](https://i.imgur.com/q2cXgIf.png) -![image](https://user-images.githubusercontent.com/20109584/210328002-6c483ecf-5ba4-4dab-8347-6d71f5726c5e.png) +3. Example of ATP analysis with: `myoquan atp-analysis sample_atp.jpg` + +![image](https://i.imgur.com/2ceiOx8.png) ## Advanced information diff --git a/myoquant/__main__.py b/myoquant/__main__.py index 82726e1..2c6d1cf 100644 --- a/myoquant/__main__.py +++ b/myoquant/__main__.py @@ -2,7 +2,7 @@ from rich.console import Console from .commands.docs import app as docs_app -from .commands import run_sdh, run_he +from .commands import run_sdh, run_he, run_atp console = Console() @@ -16,7 +16,9 @@ app.registered_commands += ( - run_sdh.app.registered_commands + run_he.app.registered_commands + run_sdh.app.registered_commands + + run_he.app.registered_commands + + run_atp.app.registered_commands ) if __name__ == "__main__": diff --git a/myoquant/commands/run_atp.py b/myoquant/commands/run_atp.py new file mode 100644 index 0000000..6cde6b6 --- /dev/null +++ b/myoquant/commands/run_atp.py @@ -0,0 +1,261 @@ +""" +Module that contains the main function to run the ATP analysis +""" +import time +from pathlib import Path +import typer +from rich.console import Console +from rich.table import Table +from rich.progress import Progress, SpinnerColumn, TextColumn, TimeElapsedColumn + +app = typer.Typer() +console = Console() +table = Table(title="Analysis Results ๐ฅณ") + + +@app.command() +def atp_analysis( + image_path: Path = typer.Argument( + ..., + help="The ATP image file path to analyse.", + exists=True, + file_okay=True, + dir_okay=False, + writable=False, + readable=True, + resolve_path=True, + ), + mask_path: Path = typer.Option( + None, + help="The path to a binary mask to hide slide region during analysis. It needs to be of the same resolution as input image and only pixel marked as 1 will be analyzed.", + exists=True, + file_okay=True, + dir_okay=False, + writable=False, + readable=True, + resolve_path=True, + ), + cellpose_path: Path = typer.Option( + None, + help="The pre-computed CellPose mask to use for analysis. Will run Cellpose if no path provided. Required as an image file.", + exists=True, + file_okay=True, + dir_okay=False, + writable=False, + readable=True, + resolve_path=True, + ), + output_path: Path = typer.Option( + None, + help="The path to the folder to save the results. Will save in the same folder as input image if not specified.", + ), + intensity_threshold: int = typer.Option( + None, + min=1, + max=254, + help="Fiber intensity threshold to differenciate between the two fiber types. If not specified, the analysis will try to deduce it.", + ), + cellpose_diameter: int = typer.Option( + None, + help="Approximative single cell diameter in pixel for CellPose detection. If not specified, Cellpose will try to deduce it.", + ), + export_map: bool = typer.Option( + True, + help="Export the original image with cells painted by classification label.", + ), + export_stats: bool = typer.Option( + True, help="Export per fiber and per nuclei stat table." + ), +): + """Run the fibre type 1 vs type 2 analysis on ATP images. + First input arguments and option are printed in stdout and all modules are imported. Then the input image is mask with the binary mask if provided. + Then depending on the presence of cellpose , Cellpose is run or not and mask accordingly if binary mask is provided. + Finally the ATP analysis is run with run_atp_analysis() function and the results are saved in the output folder and some info are printed in stdout. + """ + start_time = time.time() + console.print( + "๐ [bold dark_orange]Welcome to the fiber type 1 vs 2 analysis (ATP images)", + ) + + # Print input arguments and options + console.print(f"๐ INPUT: raw image: {image_path}", style="blue") + + if cellpose_path is None: + console.print( + "๐ก INFO: No CellPose mask provided, will run CellPose during the analysis.", + style="blue", + ) + else: + console.print(f"๐ INPUT: CellPose mask: {cellpose_path}", style="blue") + + if mask_path is not None: + console.print(f"๐ INPUT: binary mask: {mask_path}", style="blue") + + # Import all modules + with Progress( + SpinnerColumn(), + TextColumn("[progress.description]{task.description}"), + TimeElapsedColumn(), + transient=False, + ) as progress: + progress.add_task(description="Importing the libraries...", total=None) + from ..src.common_func import ( + is_gpu_availiable, + load_cellpose, + run_cellpose, + label2rgb, + blend_image_with_label, + HiddenPrints, + ) + from ..src.ATP_analysis import run_atp_analysis + import numpy as np + from PIL import Image + + try: + from imageio.v2 import imread + except ImportError: + from imageio import imread + + if output_path is None: + output_path = image_path.parents[0] + else: + Path(output_path).mkdir(parents=True, exist_ok=True) + + if is_gpu_availiable(): + console.print("๐ก INFO: GPU is available.", style="blue") + else: + console.print("โ INFO: GPU is not available. Using CPU only.", style="red") + + # Load raw image, binary mask, cellpose mask if provided. + with Progress( + SpinnerColumn(), + TextColumn("[progress.description]{task.description}"), + TimeElapsedColumn(), + transient=False, + ) as progress: + progress.add_task(description="Reading all inputs...", total=None) + image_ndarray = imread(image_path) + + if mask_path is not None: + mask_ndarray = imread(mask_path) + if np.unique(mask_ndarray).shape[0] != 2: + console.print( + "The mask image should be a binary image with only 2 values (0 and 1).", + style="red", + ) + raise ValueError + if len(image_ndarray.shape) > 2: + mask_ndarray = np.repeat( + mask_ndarray.reshape( + mask_ndarray.shape[0], mask_ndarray.shape[1], 1 + ), + image_ndarray.shape[2], + axis=2, + ) + image_ndarray = image_ndarray * mask_ndarray + if cellpose_path is not None: + mask_cellpose = imread(cellpose_path) + + # Run Cellpose if no mask provided + if cellpose_path is None: + with Progress( + SpinnerColumn(), + TextColumn("[progress.description]{task.description}"), + TimeElapsedColumn(), + transient=False, + ) as progress: + progress.add_task(description="Running CellPose...", total=None) + model_cellpose = load_cellpose() + mask_cellpose = run_cellpose( + image_ndarray, model_cellpose, cellpose_diameter + ) + mask_cellpose = mask_cellpose.astype(np.uint16) + cellpose_mask_filename = image_path.stem + "_cellpose_mask.tiff" + Image.fromarray(mask_cellpose).save(output_path / cellpose_mask_filename) + console.print( + f"๐พ OUTPUT: CellPose mask saved as {output_path/cellpose_mask_filename}", + style="green", + ) + + # If binary mask provided, mask cellpose and stardist mask + if mask_path is not None: + with Progress( + SpinnerColumn(), + TextColumn("[progress.description]{task.description}"), + TimeElapsedColumn(), + transient=False, + ) as progress: + progress.add_task( + description="Masking Cellpose mask with binary mask...", + total=None, + ) + mask_ndarray = imread(mask_path) + mask_cellpose = mask_cellpose * mask_ndarray + + # Run the fiber type 1 vs 2 analysis and get the results table, label map and dataframes + with Progress( + SpinnerColumn(), + TextColumn("[progress.description]{task.description}"), + TimeElapsedColumn(), + transient=False, + ) as progress: + progress.add_task(description="Detecting fiber types...", total=None) + result_df, full_label_map, df_cellpose_details = run_atp_analysis( + image_ndarray, mask_cellpose, intensity_threshold + ) + if export_map: + with Progress( + SpinnerColumn(), + TextColumn("[progress.description]{task.description}"), + TimeElapsedColumn(), + transient=False, + ) as progress: + progress.add_task( + description="Blending label and original image together...", total=None + ) + labelRGB_map = label2rgb(image_ndarray, full_label_map) + overlay_img = blend_image_with_label(image_ndarray, labelRGB_map) + overlay_filename = image_path.stem + "_label_blend.tiff" + overlay_img.save(output_path / overlay_filename) + + # Construct the summary table, print all output in stdout and save files in output folder. + table.add_column("Feature", justify="left", style="cyan") + table.add_column("Raw Count", justify="center", style="magenta") + table.add_column("Proportion (%)", justify="right", style="green") + for index, row in result_df.iterrows(): + table.add_row( + str(row[0]), + str(row[1]), + str(row[2]), + ) + console.print(table) + csv_name = image_path.stem + "_results_summary.csv" + cell_details_name = image_path.stem + "_cell_details.csv" + result_df.to_csv( + output_path / csv_name, + index=False, + ) + console.print( + f"๐พ OUTPUT: Summary Table saved as {output_path/csv_name}", + style="green", + ) + if export_map: + console.print( + f"๐พ OUTPUT: Overlay image saved as {output_path/overlay_filename}", + style="green", + ) + if export_stats: + df_cellpose_details.drop("image", axis=1).to_csv( + output_path / cell_details_name, + index=False, + ) + console.print( + f"๐พ OUTPUT: Cell Table saved as {output_path/cell_details_name}", + style="green", + ) + label_map_name = image_path.stem + "_label_map.tiff" + Image.fromarray(full_label_map).save(output_path / label_map_name) + console.print( + f"๐พ OUTPUT: Label map saved as {output_path/label_map_name}", style="green" + ) + console.print("--- %s seconds ---" % (int(time.time() - start_time))) diff --git a/myoquant/src/ATP_analysis.py b/myoquant/src/ATP_analysis.py new file mode 100644 index 0000000..c653df0 --- /dev/null +++ b/myoquant/src/ATP_analysis.py @@ -0,0 +1,114 @@ +import pandas as pd +from skimage.measure import regionprops_table +from scipy.stats import gaussian_kde +from sklearn.mixture import GaussianMixture + +import numpy as np + +labels_predict = {1: "fiber type 1", 2: "fiber type 2"} +np.random.seed(42) + + +def get_all_intensity(image_array, df_cellpose): + all_cell_median_intensity = [] + for index in range(len(df_cellpose)): + single_cell_img = image_array[ + df_cellpose.iloc[index, 5] : df_cellpose.iloc[index, 7], + df_cellpose.iloc[index, 6] : df_cellpose.iloc[index, 8], + ].copy() + + single_cell_mask = df_cellpose.iloc[index, 9].copy() + single_cell_img[~single_cell_mask] = 0 + # Calculate median pixel intensity of the cell but ignore 0 values + single_cell_median_intensity = np.median(single_cell_img[single_cell_img > 0]) + all_cell_median_intensity.append(single_cell_median_intensity) + return all_cell_median_intensity + + +def estimate_threshold(intensity_list): + density = gaussian_kde(intensity_list) + density.covariance_factor = lambda: 0.25 + density._compute_covariance() + + # Create a vector of 256 values going from 0 to 256: + xs = np.linspace(0, 255, 256) + density_xs_values = density(xs) + gmm = GaussianMixture(n_components=2).fit(np.array(intensity_list).reshape(-1, 1)) + + # Find the x values of the two peaks + peaks_x = np.sort(gmm.means_.flatten()) + # Find the minimum point between the two peaks + min_index = np.argmin(density_xs_values[(xs > peaks_x[0]) & (xs < peaks_x[1])]) + threshold = peaks_x[0] + xs[min_index] + + return threshold + + +def predict_all_cells(histo_img, cellpose_df, intensity_threshold): + all_cell_median_intensity = get_all_intensity(histo_img, cellpose_df) + if intensity_threshold is None: + intensity_threshold = estimate_threshold(all_cell_median_intensity) + + muscle_fiber_type_all = [ + 1 if x > intensity_threshold else 2 for x in all_cell_median_intensity + ] + return muscle_fiber_type_all, all_cell_median_intensity + + +def paint_full_image(image_atp, df_cellpose, class_predicted_all): + image_atp_paint = np.zeros( + (image_atp.shape[0], image_atp.shape[1]), dtype=np.uint16 + ) + # for index in track(range(len(df_cellpose)), description="Painting cells"): + for index in range(len(df_cellpose)): + single_cell_mask = df_cellpose.iloc[index, 9].copy() + if class_predicted_all[index] == 1: + image_atp_paint[ + df_cellpose.iloc[index, 5] : df_cellpose.iloc[index, 7], + df_cellpose.iloc[index, 6] : df_cellpose.iloc[index, 8], + ][single_cell_mask] = 1 + elif class_predicted_all[index] == 2: + image_atp_paint[ + df_cellpose.iloc[index, 5] : df_cellpose.iloc[index, 7], + df_cellpose.iloc[index, 6] : df_cellpose.iloc[index, 8], + ][single_cell_mask] = 2 + return image_atp_paint + + +def run_atp_analysis(image_array, mask_cellpose, intensity_threshold=None): + props_cellpose = regionprops_table( + mask_cellpose, + properties=[ + "label", + "area", + "centroid", + "eccentricity", + "bbox", + "image", + "perimeter", + ], + ) + df_cellpose = pd.DataFrame(props_cellpose) + class_predicted_all, intensity_all = predict_all_cells( + image_array, df_cellpose, intensity_threshold + ) + df_cellpose["muscle_cell_type"] = class_predicted_all + df_cellpose["cell_intensity"] = intensity_all + count_per_label = np.unique(class_predicted_all, return_counts=True) + + # Result table dict + headers = ["Feature", "Raw Count", "Proportion (%)"] + data = [] + data.append(["Muscle Fibers", len(class_predicted_all), 100]) + for index, elem in enumerate(count_per_label[0]): + data.append( + [ + labels_predict[int(elem)], + count_per_label[1][int(index)], + 100 * count_per_label[1][int(index)] / len(class_predicted_all), + ] + ) + result_df = pd.DataFrame(columns=headers, data=data) + # Paint The Full Image + full_label_map = paint_full_image(image_array, df_cellpose, class_predicted_all) + return result_df, full_label_map, df_cellpose diff --git a/notebooks/atp_exploration.ipynb b/notebooks/atp_exploration.ipynb index aff0fcb..0197859 100644 --- a/notebooks/atp_exploration.ipynb +++ b/notebooks/atp_exploration.ipynb @@ -108,7 +108,7 @@ "\n", "# Create a vector of 256 values going from 0 to 256:\n", "xs = np.linspace(0, 255, 256)\n", - "\n", + "desnity_xs_values = density(xs)\n", "# Set the figure size\n", "plt.figure(figsize=(8, 4))\n", "\n", @@ -193,7 +193,7 @@ "source": [ "df_cellpose[\"cell_intensity\"] = all_cell_median_intensity\n", "df_cellpose[\"muscle_cell_type\"] = df_cellpose[\"cell_intensity\"].apply(\n", - " lambda x: 1 if x < threshold else 2\n", + " lambda x: 1 if x > threshold else 2\n", ")\n", "df_cellpose.head()" ] diff --git a/poetry.lock b/poetry.lock index 8d51003..af4de0c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1430,52 +1430,62 @@ testing = ["coverage", "pyyaml"] [[package]] name = "markupsafe" -version = "2.1.1" +version = "2.1.2" description = "Safely add untrusted strings to HTML/XML markup." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, - {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-win32.whl", hash = "sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603"}, + {file = "MarkupSafe-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-win32.whl", hash = "sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625"}, + {file = "MarkupSafe-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-win32.whl", hash = "sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859"}, + {file = "MarkupSafe-2.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-win32.whl", hash = "sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2"}, + {file = "MarkupSafe-2.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-win32.whl", hash = "sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7"}, + {file = "MarkupSafe-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed"}, + {file = "MarkupSafe-2.1.2.tar.gz", hash = "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d"}, ] [[package]] @@ -2017,39 +2027,39 @@ files = [ [[package]] name = "pandas" -version = "1.5.2" +version = "1.5.3" description = "Powerful data structures for data analysis, time series, and statistics" category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "pandas-1.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e9dbacd22555c2d47f262ef96bb4e30880e5956169741400af8b306bbb24a273"}, - {file = "pandas-1.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e2b83abd292194f350bb04e188f9379d36b8dfac24dd445d5c87575f3beaf789"}, - {file = "pandas-1.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2552bffc808641c6eb471e55aa6899fa002ac94e4eebfa9ec058649122db5824"}, - {file = "pandas-1.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fc87eac0541a7d24648a001d553406f4256e744d92df1df8ebe41829a915028"}, - {file = "pandas-1.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0d8fd58df5d17ddb8c72a5075d87cd80d71b542571b5f78178fb067fa4e9c72"}, - {file = "pandas-1.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:4aed257c7484d01c9a194d9a94758b37d3d751849c05a0050c087a358c41ad1f"}, - {file = "pandas-1.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:375262829c8c700c3e7cbb336810b94367b9c4889818bbd910d0ecb4e45dc261"}, - {file = "pandas-1.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc3cd122bea268998b79adebbb8343b735a5511ec14efb70a39e7acbc11ccbdc"}, - {file = "pandas-1.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b4f5a82afa4f1ff482ab8ded2ae8a453a2cdfde2001567b3ca24a4c5c5ca0db3"}, - {file = "pandas-1.5.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8092a368d3eb7116e270525329a3e5c15ae796ccdf7ccb17839a73b4f5084a39"}, - {file = "pandas-1.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6257b314fc14958f8122779e5a1557517b0f8e500cfb2bd53fa1f75a8ad0af2"}, - {file = "pandas-1.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:82ae615826da838a8e5d4d630eb70c993ab8636f0eff13cb28aafc4291b632b5"}, - {file = "pandas-1.5.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:457d8c3d42314ff47cc2d6c54f8fc0d23954b47977b2caed09cd9635cb75388b"}, - {file = "pandas-1.5.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c009a92e81ce836212ce7aa98b219db7961a8b95999b97af566b8dc8c33e9519"}, - {file = "pandas-1.5.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:71f510b0efe1629bf2f7c0eadb1ff0b9cf611e87b73cd017e6b7d6adb40e2b3a"}, - {file = "pandas-1.5.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a40dd1e9f22e01e66ed534d6a965eb99546b41d4d52dbdb66565608fde48203f"}, - {file = "pandas-1.5.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ae7e989f12628f41e804847a8cc2943d362440132919a69429d4dea1f164da0"}, - {file = "pandas-1.5.2-cp38-cp38-win32.whl", hash = "sha256:530948945e7b6c95e6fa7aa4be2be25764af53fba93fe76d912e35d1c9ee46f5"}, - {file = "pandas-1.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:73f219fdc1777cf3c45fde7f0708732ec6950dfc598afc50588d0d285fddaefc"}, - {file = "pandas-1.5.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9608000a5a45f663be6af5c70c3cbe634fa19243e720eb380c0d378666bc7702"}, - {file = "pandas-1.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:315e19a3e5c2ab47a67467fc0362cb36c7c60a93b6457f675d7d9615edad2ebe"}, - {file = "pandas-1.5.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e18bc3764cbb5e118be139b3b611bc3fbc5d3be42a7e827d1096f46087b395eb"}, - {file = "pandas-1.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0183cb04a057cc38fde5244909fca9826d5d57c4a5b7390c0cc3fa7acd9fa883"}, - {file = "pandas-1.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:344021ed3e639e017b452aa8f5f6bf38a8806f5852e217a7594417fb9bbfa00e"}, - {file = "pandas-1.5.2-cp39-cp39-win32.whl", hash = "sha256:e7469271497960b6a781eaa930cba8af400dd59b62ec9ca2f4d31a19f2f91090"}, - {file = "pandas-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:c218796d59d5abd8780170c937b812c9637e84c32f8271bbf9845970f8c1351f"}, - {file = "pandas-1.5.2.tar.gz", hash = "sha256:220b98d15cee0b2cd839a6358bd1f273d0356bf964c1a1aeb32d47db0215488b"}, + {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3749077d86e3a2f0ed51367f30bf5b82e131cc0f14260c4d3e499186fccc4406"}, + {file = "pandas-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:972d8a45395f2a2d26733eb8d0f629b2f90bebe8e8eddbb8829b180c09639572"}, + {file = "pandas-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:50869a35cbb0f2e0cd5ec04b191e7b12ed688874bd05dd777c19b28cbea90996"}, + {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ac844a0fe00bfaeb2c9b51ab1424e5c8744f89860b138434a363b1f620f354"}, + {file = "pandas-1.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a0a56cef15fd1586726dace5616db75ebcfec9179a3a55e78f72c5639fa2a23"}, + {file = "pandas-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:478ff646ca42b20376e4ed3fa2e8d7341e8a63105586efe54fa2508ee087f328"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6973549c01ca91ec96199e940495219c887ea815b2083722821f1d7abfa2b4dc"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c39a8da13cede5adcd3be1182883aea1c925476f4e84b2807a46e2775306305d"}, + {file = "pandas-1.5.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f76d097d12c82a535fda9dfe5e8dd4127952b45fea9b0276cb30cca5ea313fbc"}, + {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e474390e60ed609cec869b0da796ad94f420bb057d86784191eefc62b65819ae"}, + {file = "pandas-1.5.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f2b952406a1588ad4cad5b3f55f520e82e902388a6d5a4a91baa8d38d23c7f6"}, + {file = "pandas-1.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc4c368f42b551bf72fac35c5128963a171b40dce866fb066540eeaf46faa003"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:14e45300521902689a81f3f41386dc86f19b8ba8dd5ac5a3c7010ef8d2932813"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9842b6f4b8479e41968eced654487258ed81df7d1c9b7b870ceea24ed9459b31"}, + {file = "pandas-1.5.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:26d9c71772c7afb9d5046e6e9cf42d83dd147b5cf5bcb9d97252077118543792"}, + {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5fbcb19d6fceb9e946b3e23258757c7b225ba450990d9ed63ccceeb8cae609f7"}, + {file = "pandas-1.5.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:565fa34a5434d38e9d250af3c12ff931abaf88050551d9fbcdfafca50d62babf"}, + {file = "pandas-1.5.3-cp38-cp38-win32.whl", hash = "sha256:87bd9c03da1ac870a6d2c8902a0e1fd4267ca00f13bc494c9e5a9020920e1d51"}, + {file = "pandas-1.5.3-cp38-cp38-win_amd64.whl", hash = "sha256:41179ce559943d83a9b4bbacb736b04c928b095b5f25dd2b7389eda08f46f373"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c74a62747864ed568f5a82a49a23a8d7fe171d0c69038b38cedf0976831296fa"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c4c00e0b0597c8e4f59e8d461f797e5d70b4d025880516a8261b2817c47759ee"}, + {file = "pandas-1.5.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a50d9a4336a9621cab7b8eb3fb11adb82de58f9b91d84c2cd526576b881a0c5a"}, + {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd05f7783b3274aa206a1af06f0ceed3f9b412cf665b7247eacd83be41cf7bf0"}, + {file = "pandas-1.5.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f69c4029613de47816b1bb30ff5ac778686688751a5e9c99ad8c7031f6508e5"}, + {file = "pandas-1.5.3-cp39-cp39-win32.whl", hash = "sha256:7cec0bee9f294e5de5bbfc14d0573f65526071029d036b753ee6507d2a21480a"}, + {file = "pandas-1.5.3-cp39-cp39-win_amd64.whl", hash = "sha256:dfd681c5dc216037e0b0a2c821f5ed99ba9f03ebcf119c7dac0e9a7b960b9ec9"}, + {file = "pandas-1.5.3.tar.gz", hash = "sha256:74a3fd7e5a7ec052f183273dc7b0acd3a863edf7520f5d3a1765c04ffdb3b0b1"}, ] [package.dependencies] @@ -2794,28 +2804,28 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.0.223" +version = "0.0.226" description = "An extremely fast Python linter, written in Rust." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.0.223-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:7d4f5ba5e4779dcc8ca7e61f96ad867792c205bf961fc486890cd5fd24b73884"}, - {file = "ruff-0.0.223-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:2204aba39fe76bf4efd88290554899f1d0c0e3fd8b69fb80819abf6738fd889e"}, - {file = "ruff-0.0.223-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1151008716230ae3086fc0754e6abf2dde013e8504b77a911a03e07386eda85e"}, - {file = "ruff-0.0.223-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9613848d4ad72a79f185c3c78f8777e6d3e5f65bf15fbba97dabc01d17254014"}, - {file = "ruff-0.0.223-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edbc88507f8417102d002f15bccf457340d3e2c3c304f77472ff39927a0769a2"}, - {file = "ruff-0.0.223-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6fe10bf4d0efa81360c6d32ffb41f242de1ef187a65c81021fe7947e0a84e7cd"}, - {file = "ruff-0.0.223-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9656ba683f6627ca85257b4dc449ce76b68763c848172069811b222611d904c7"}, - {file = "ruff-0.0.223-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad3f84559be0f87788f11503a185f322360d45942c07a0461eda791dcfb3d83d"}, - {file = "ruff-0.0.223-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc554613ad218a82929e05d31d2da6e4fa85b6f6c82a09c6de5c9f79159c02e5"}, - {file = "ruff-0.0.223-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d115714dcf039ed6d75254f4e2023259ce5261330bd1ab2567f15f58680191b3"}, - {file = "ruff-0.0.223-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e856dcce47b695bee20fdc3f2da3e29026642ca1b71dbc98723cb62c38294952"}, - {file = "ruff-0.0.223-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cf64a6368eca3bb34aa4606425ed46c632cfd4197086ce6746efa6c5de188940"}, - {file = "ruff-0.0.223-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:57a302273315fa1582ec262bd3ca0d057d21cd96359f2ba9fb582ef30f897a68"}, - {file = "ruff-0.0.223-py3-none-win32.whl", hash = "sha256:25fe04755c3d68240c3320b3420dc0a4157c2c1952a063014c44d5c382bd8368"}, - {file = "ruff-0.0.223-py3-none-win_amd64.whl", hash = "sha256:2bad5fcfcf374f76744e96661dd6f04e65d83d51c54507db9faf580a9cd93ec3"}, - {file = "ruff-0.0.223.tar.gz", hash = "sha256:35359ee7fe710a19380e3eaba2fe45abe0a881057e0fe5a2ae7fbc29b6e8fca3"}, + {file = "ruff-0.0.226-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:199afcebc851350f4ab87987c83b1bf489510210700742e15fb129b4750d889a"}, + {file = "ruff-0.0.226-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:1baa384e94c42de9750b6e381807ca63c7572a3d283c98344a8347b93a17045d"}, + {file = "ruff-0.0.226-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80856915feed3786f16cd29a6af32f3e1527b5b16931d92bac01c12400ecc4fe"}, + {file = "ruff-0.0.226-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ebb106e359bd4a686d370ee5726fca7e92ecdfee61611a50e3f4214751829330"}, + {file = "ruff-0.0.226-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22bb40dc76cff2460efd7d1e81f0604d8905a4e442e45ea7e95ca994a258b84a"}, + {file = "ruff-0.0.226-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:de5089659d977901d7798e4bc67533c208e2be1360799d67df9f55c1e2ce5336"}, + {file = "ruff-0.0.226-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c7bb7f88d6aa0b6525603069949d21faeacd775b83e0d6303bc9dafe133275f7"}, + {file = "ruff-0.0.226-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32194ee22fc24c54ea5c9d05eaf3991bb6bc1f1ecbfb9372caba3e465b6e0834"}, + {file = "ruff-0.0.226-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:04130c170e2da762b5510ac73683ed80701d7b5efb8124228b374eba78eb465f"}, + {file = "ruff-0.0.226-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e5c364352ff8fc5d01d0416bed2e38f1b094d0efcff3d4fd18f8825aa69c8d49"}, + {file = "ruff-0.0.226-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f729a4f68f2f50538b03d4ad6ad753a895ce9256fa8c262bac374a85500ca82f"}, + {file = "ruff-0.0.226-py3-none-musllinux_1_2_i686.whl", hash = "sha256:275b3555662554253b319984380f70e3aa1f42cb2d074b33e4537bf672e83e3a"}, + {file = "ruff-0.0.226-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5c8cb58c721a35cbd05342943eed14399eae2184c425d39220e4eff2e741aecc"}, + {file = "ruff-0.0.226-py3-none-win32.whl", hash = "sha256:cecc2c291660e5064704e51792c7ef084afcfbb124dc473936b5c233cf21aad3"}, + {file = "ruff-0.0.226-py3-none-win_amd64.whl", hash = "sha256:bd9182fff882e14687eab0997b55b5edbf692a4e17a88902a1404058b142804a"}, + {file = "ruff-0.0.226.tar.gz", hash = "sha256:988334f0ff4a80ef91faf46f447f10292b757f1eb94f5f9cf5d1eef400142c33"}, ] [[package]] diff --git a/pyproject.toml b/pyproject.toml index 6b115c2..1a9ac5b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "myoquant" -version = "0.2.2" +version = "0.3.0" description = "MyoQuant๐ฌ: a tool to automatically quantify pathological features in muscle fiber histology images." authors = ["Corentin MeyerAsl%hr z(>%4Q$Jrtw@WCt88OtV?@p?bYA^m-x0wm#cqd5s$wBj4&v?DUQG|Au2X>aTGGry3x zR4)&Fa{C$FX^-&QAETo&N-FK(aS9M1{uwip$0{0B%(lfRVUv`N1Jyb5E2L4;a!al8 z2TCGmgU(@KA0)DRyI2cR0l86weNQ#42m8a#O{&}Y?Mgc0(=7l&FEDk)Dl1)i)OsIe z_f8z>KZBeOK7GE3__8k5N#Ko(vuYimw%7jn?(?k$v;gF?PIqal&7dte;&Ae(_eo;C zO8g@phRn^nk@3#A-w5sqW7g9nYm8TR+6hlm(R&|FT2GeLkL`;si5rT{3O${E0cd=5 zS}mI$k0}F`(8m!l%y|d3cnD<)YFU$c3{Za%p~$J6regC}lALo=q>XlitgEef62d)y zQyZPKEHk)#beBA}30)FhyBSo;F-@5TA>dReyCn-C*!kp^YDhb=@6$Eyh_C0tv@I zy0R)pn{PTN-Xvkwf^JGN@z_?9P}|U+{#AXb!VIx2T7k&U_Di_c_th| zM=NW+E;%%DO9(B8T&F^-HQh>g+g;Nc*0(@FZoYN${LCBXPoeG~4YZ%y(;G%m^n5fs zY-nn15+anzw2D{F UiU?d@V*BozTPlwBt9dh7{vI0gI{nnH>YldGovp*m~$}!CkEW2p{KQ zo9en|HBNi2zyH^@YIhC8yst*@H54J5Zq8wE0FIDh8nLkFjg5Hsa^aQz+M1xi!;! z?qvI0g4v`5sbi=DtSIS{)i6=zv?#E(J`$Letg 7G_c( z)@|@1e=YvS&^0#l^v`DsmexNuNW(IG{n)!AQ`170K(V%F@TO0lPfBCUu9r=vepoqo zpBqGdk0M4pU2D+Het8yZ58oMI_yY697?wJ^`KFlFP2Ymcds@t<(@%S;3j1g?-vAC@ zV##FYx30X90Z^?WGoqbZMFOFfrBR+091%$CnJR%;-GwE(7o2!1-F;Q01m14VN`j__ z!z>H|=CU>?rK=fnP5~OCll!yK(!I&5;VX~5SvRO!HzMH2X|-ymkwB1Dhy|C0 8PXXem`@fq=3Cp z&hp%}X1PUc7q$ck@6J?d&!nO|x}GwbuMB$?z4H0t8!8BVJKL%d?CFf3w*+NRgQgpV z_a}v?J|`Y%1t ejD98J*5ca= $0e%gWn97b2zz74PyDqpLfw|gyj9e;4hym;Po$|;4qkNGY1!q^Si=jpqEWayZ66KEN>7i##u1po(-+=Ni2^1 zOm$XP!G|M^bXj)du4H*B6>J8s?C=Xn*CnN9Q2%MGOYEna){x$8 ?(!t_6a4u)7Ozg6*$-87VTlJ1ONyF ^F z0xO>>=gwE}5OeL-2LOgsAf?84Ygp&x=^@kiMa=Vm{HcuYq?mPs^u|Xk#!TH+sMjA! znVIUZFZEr2W$9B%iE*Eq>*^$HU04uhxo7|_%q?Q7*W*AsS|r59j#@m9{xb7J;*$#& z=HtObQH7yAe4;m*n@LdHw6{G*j6w{l30?rAJiI_)AsX77c6gBn`L>%CcD*q>61qs! zwAhdB&l^F;CR`D>B>wr*!=lE5E_gLf2Qqi+TdIWV_)v@?89*XOMa3_smgRcBIVWm_ zlKvbZh%Tqx{4 szA#vT*;{|+XcI1^3oXe$B-nyjdP zmv_K`%Z+Y{PSR^De7E{gH+?O2?Dvcf@Wg><_DB#^bMNJ&6vop5w6k_v=GT+xhQ8en z>L9+|(5G||X2A)V%zVvob(~$P@uI0wpY2)3c3ZT8dk;_~RVF9nEh%md`@}iF-5a#0 zp*#@LI-Ldl*79juLxcYDvr)!ZP5N|wRECKKT6n|{0J7eKeHPODxdNoDi6j1Nvdwfh z*?792k((brdE}>o){`BcrLyS?W@ib^wzo6{Z)$@br#xDC1=HO&w^A;*7IUb-aR1n8 z+?v_<%uSJAp}&2JDMhU?F8J=7&b^+?P_SxfYC%l>-IqKk^!M^zhc(61vXO bet=zq}uLq9Jf4`wb2jDyR%v85peNS#0q%n6;Apv z;fpiEE5EP(QVHQWYlbolo4aJ168up1+?6)lRQ+V_!JSIe8qsDXEO0?_0%o07Jc10= zudcD4(?fLJ bse1v8D3r3E!X z>z1i%qnDP68+14}uZLQz2i--Q#i35K)!}H%vu-5ptphXjWPrXcRDRs!<3vBvN#Af! zl%L+SO?{(k$yb+dT9 wc_nbkp#9M`9*v~=u+qvu`)l0w5GJeqq0R10~3W_1_IiV)QyHOa8-cZPq z(IMcQjQXZxEJa9H%0IoyKlntU=lbqHmH|vmm)@uk&4P8VweMtLr*YD}x-c)xR~03! zu#K~cTX&2eYMe-^z_(< ga@GiNa6lnl@ti#FzGl{cpf^1Skq$4|T(qAWfh zEVVx^nuWW^)PakguQ>t_7mTLM6kjB8@zz795trH8OBr34Q{bz;giJB~b2>q*+7vC{ z-qN%!)3H%Twqcpn!e@O-6w@2YfPwN$gE?;~$J9uD$&+vj;-8W>T{*-X*4t8Yqh9-{ zT)Dq7ZPJ4qbIe;WV%)LPw|Ho=*am)-7zcck#Bb#W{9RY-o^5BGfwHItYR!TUH RFs+yacV|?F^vLwTzrO$zpr~9I@+(C1zuPe-E$OQfj??!EMNFQEDVy5 zcWf+nYT==`GHaS_Z*PL58Wz5CWe;I}sHJdrBlE_UH(-5Tm3x@%{jJ6W6Uo_uditrI z;N-p-f}`V$i}yvo;E4{7%IGg};J^su_O`A^Y-Ts(97Bn@J%}kXyy}gDbG`72+1`tv zG`yb}l^H&ni1iuz%E`aQe>OLnj}=5eh!$K8?gu8ZpBekAT)2={lBe(v(-+t$N^J=r zL};gm @FLFzJ*A{@e z!v2xX)B0nTC2K*$4)JGKLf@|N?G{JbZg1i{<8i5%>Cw#9gB7ZUX2I`+&VzoZk8-pX zIp*iBb*09ZJ$4WpCL3JJn*Z&En2yvtsfsTv2Dxkud*HOBeb*2T6Oe7A zPPY 2m;E%#6jl*6rCN`fOe!I_e(~KkDB_R z?x)BJ2&{_9x#bG7aic6_WIP)4R2<4Xc{WNc9x$9OuR Ap$;Jsh z#^n|l_2;-`N^}(4aB4L|%3`G1TY|JUPIbv9{&n2d_OQ<9<~Tp?sDc>f_I&LW=Yc9) z>NBMbjUSJaZrY=@P=pEXt?@Z?g^)bD+G%+*%wz2df%^qi#RGua*i;irun8@oDL<%w z%wGBaK%qBOjo`(*8r<)#$qR=5Vvfc@`HKZj&=R-aoUv-Q^1ocZf;qlhZge^Nc^vgo zJ~`Olf^x;NrLx5 d!n2T1cFoeFi;rtL#Ds=og)y=4^z2`|A&Z zkK0siq(`Eos ){6sIb#4X^Q=$oT(@}}}kj$7=av9aL3>7YS z6##p>{r-8$j-psNWcM;h4U6T|8Vk zwN~%{01ynkUsoQKY!LL~E}cD1K@R(K*cEBC1a~u03li-G@ys6A*tWwO;a*ehaR;~~ z!ZumlrT` >|a|rpcBTWb2eZuE=^QKjNH80;ybi7m|9f zL-w2Iz$i1vce8>Gn!vt$c5x4r-OzQlXymetzvE(reN~ipD#a(lJpDgMIHbUFPX zoqe&(Bq_zG{XDmzJfa9#bF=Q0a_RSTidYH+ zB01I+D(F3=;~?GPcQZWE29tyLUYd9+;K&kFm8CUw;Q5AL?`_Ql`_UP1yW+c`xJM-W zo|q=2X7!>uHkbuZ-qbt5YX{!naQ#^e738>|EMLI#x-#O69}t!trsxBFR-8!+;6PJ! z8-Da{$$pdQU|=YsqS>GA_T?*$lx^ow`42V#r?9Yb@vcdG&FZkhL^>-6EcALaNE2Ni zFrNs@iEHXg%Gr+HDm!gAnqL^tnyoWvF+iNpLlz@)vZ75qc;pP?kUa3}e1+y6-{P5x zldXKtG#4kkj_Imc*P=Z87piRGNkupSZ=vP#9%_K~AzgJ$cPO`5Ae#olsC$w9yMKpJ zI(KRxL3v20fHqt8`svI?`{WVw>?YVS?$}y|tS^b(R_?2Ef_tcVT(O4T7JEvc(AeT1 zN>~KClmZU{Z>q}^f6uCBN*e!aV7d9-pbR=xBzly?&;0IU3aoG}(SAJa9QN&KL3;^& z7$_KMjx4G?USd+oC{MukEk`YziErz|nvxC=4r3~X2eQp2yAW1BgKPzZ>=oEK)Bkub zoFL8#aJToz4?p8)eVWuZaunu^{Dfboun(}YVf$Pvp3PR?zMGVN dUspC2PoDXM)!ps3`TVBf?sEejypB)O}M!bwHT-*ZX8) z@DZw7N7EU#=; Hy=dJEAD()QNcO2&-^Z<^!0Vs;H~n<^cK9x5?-E`+LY0p zFIa;gZW;;4aAFGv*ka!k(W7K#oyFw5FF@i8s+2({1H%mgJJSOyTeQy-#eWX)_g8rt znz;MMqwcr0rozMeo+cxW!LHG)%`s;=dF78su$Y^whVd)^+4XVE?+VrPG&SjHHC%|2 zwa=(Q;y;MC3E@m*FA61xN*clpcALFs%q80QF8{7fe{EI~(Y*nS&RouEnR)JBddXQ` z1fE>R%6go9M%m QbgouMk_$s{EE_6RPaJ zuSZNqKl{zu*F1`NvT@skmG~!Rm_5xZg!7{-)(!lE>@Gcsbw7w6Q-Ee3yMk%(>vhjj zBgI49PfbRDEEU6&VWWi5f5y#D992mCJnbM?<|HKxnJ?S`Qyu`82s_UYHy3C} >?CH(q?&k> zHg)2PrsD1?4;GycHYfINzMC*M#@Q6FNdLQ`j6#1XWp0MyTHo-J&=LA<^CxR*Gg`K3 z>rFJs$tXtau)-z;3&BPWl&ABPy5D+CrR&NBzI+NY=vyv|-j=0VO<=)P^qu*dAFtKK z95f7PD~Qhy!YZ=;*0 Wk$SIIur1DA;oHSwZAKfci)>28}E_%JLSbhqjNI;`Osxu zCEp-j`Q^_c0(b`OyFBF~p5B-W3iRB7N$Klw)<5=I!h6x+qH*Y2{*JogyhYO@?@7^B zwvRz$8OIzLoPO9=Q+5)%n_W(hl+ zsqY4D3k~&~xxRhoqo;~bR~&S7)h7(V`@YDz<}=l(4ttmAJbJXO$ Hw=y!bgC4(BBK^&D2%h#d%g#dB1Z3vq1S3B|VR*f=9i}GyJg~r0} z=#WXJUWBpr%doqiq~%xjT*+mpNeSCi@6hq3C>AE)Na+@P>PG3DMhI~-7Wt@yI@Q^{ z8UgrHz0-ZP`A=?F6(+LpUU&)`H1C2M9*+7jPx)GVGZBvlcbywwFD_RLpQ+p=c4Ia7 zT*Cla_ZD#pMh;y#o=C)r4HB4-&+A6Jo4_T!T66Li5z3r}3kJcOA7}DA7yi66zg3@l zpWLONq`m?c9*B89P^U`!Pw?$_Q@ILRXBX=4TWNGTeEKawf9CL>#@ %Fs}NXA)=uf0$}~1 zk{HRjuHgBiZ?w6}s1<}_V$f m`R4TFDX#jl2TD!_IdN29+{x~GHPXx9i{##{4ev^H2LoHz zQ(}o%3=Xp9^s9% 8y8-{h2fGG&Aj|KHSjS<~g75iFli;WoTatn$CAfH>PvPvD=A z1EfyQG|=vUULYD~(zgvKGp~p)bhriCR+EP}Kc@}K#J?jIGEwB`JeaOdX@}P>L7|6J z)e-9Ex4PlQ%+@)1=?)7P J1sd5`H>9`0)Yn>HzjuG%gZm`m+r(|pvy-eppOr+Z z*kPw^)rCK^#$lYTj{8?}jNa9p1G6Q3WoZiL2Y)UtFYS?yob;$yNH369B+|Go-mZTV z8lV5?W_kcP2LpU*`f29!m?pb15r06qRjGzRS;f7VWD^%cgw2sd+XSD;!O6h&8tMl? zr;@z1sly!gKGe>tc$r100FFpHB67c7zzGRR8pr)aiw(g3Y|_`dW<%R|y}a89i(80s zmNU56@$9r@E`Rr-rdLkSu>DKl4cEj2AjWE+1^3^cY^`>M76P^FHF5VeZ4)Jp5gHSg zNUt1m{7;C=lxNHL=EjD!i%WIDJ#9eHNXJi>&O?;}M+-)1O@NMU8OLaj34+}EYO2Ts z{} ATg7A|Kk) Fuc;^W}0&FVqPm3z2v7OFGvJKVxy{vH0yA9oIdZSn{v<(Z8z`O4`0&|3`% z%8b5G!;YHT=hcxpZPooy96oMttm~?9ym;uk0I;WBOrv~
fZ5|4!yA6m*ipRfARq6^AUF`_?8Tm coZb?IV+l4UG zBFz!MF1qJe<@urzd5H3vM3G?|jrF7(B2aHG2$56YDXFAVQeXoI>Uit47&eYcAa8b@ z{@BY?VA@Lh<)+N+B^pl$*dG9(1*+l=5{5B;2^`>RwbE<1q-HH(ZR=g`J@bnFM< z%$V=E*mBbvP@r3dxHn-euL$_OwSG3a-!CtJva}S}kRNwzBVXtvFscF^)!MS>w99Zz zB?m<%hDwBdqTLk!S{-EWY%EpO0CUP0o?Lb;sq*^097lV4f1&==j?hE?(p_6KH@zL= z9CT@V>u{IcVb?**^{L^QX1|>qYL0d?{@aW@)ax%oX^^MkDho4y60o7N7`y2jly_3v z>oV{1D@&`i$UdJGHgF`i8F6zXVK8mBnQ+Kw{YXNf+FWrH?21!+)5Q1y5W43`KAqfG zn-0)$s$iNdM(!o`v8RLB-meK* ldgf~bQpo!-q4;pe`ZNTe6 z>`nID3NN&!JlJIXUPjzh4oDGwbCsZ?v9p0XRnK0}*T_*<6dpi{1gMY-?QS=ECZ$mQ z)OV)3b#3#PEVq;iuVCn9_{ro0pu2HW;OmA(TV9>5-4xQ8p6j)6z+i;E9%Ov@`FFBm z!_B90vYNqmq$fG)L#L|b3&p<~hLs4N1rU;~EDGGXky^PyYiPmVr;Gur4Jm6Hf556G zJJM$D6$ONL5a*mqC|$f%)Yt}LquFQgzTq;bh5%J3G Z26mx+xC%wFxpI+nnK^=jR`$qO4qMXhi(&NI}M0X{7U)xtsMWBUUt*R&K?Q z;kom>J~Sfylhm)-99zHi>&33)YKSn}{n#C~H2-79SxY(6_rbwrNfO(ao&7Bd9t|-} zYK+8POX{*MSZm_2^_BEa7R-Biv*>i!y&CgNL4468q&4=%<`*0R57W!oR;J*h?hoY} z{-vWN)fJM|H8+3oS$m+=pfA}Bneb)CPsC(Mw07fuTSNWXT M+`{5XrDv*ns{{K#dW+o!O9?MLGn?)I{ilz0D*NR8eWPm`4}uM*h(#N4-^ zaN 4^!7rv%t$)eBSEdoeBu`IG+fyyx*ij%E&C;O%+bFr-=C>LH|93Onn z$?YanY*wWk6gEnvYd})Qm?Sv$@? (3Da(IihSIf-6Z1flGWR5OIOn9{JXXAp0B81YAL5% z#|^Eco6nuMPc$Y(cXmvYxhexO+EqgFlU{`+{u%Kd$A`Q>=IR!D(YuP#VKT-;NpkBG z+$?xIqFuRYv&P(l0X6hIvHr)t3%l_ax2XJ3@hrN>h!gCV`X-rcH1HVkaFNEbF;pk- zs3F(@@;Cqr *hsoPHi;z0~8Yd+L+vWcr&y%T%J@E8SaNR;l~RtF^A4N6G&Hw|9uHejMsP3-AN! z?|G=EnQaUjmBV=!GFt{#lM-P=hy$y>-h9SLxg3wp9d}ZO(%ImMJ )IW=E|sQP-L27!7cB_6f(DQV5+tAU&4|F+v@0K!5OQh~ha`Dh=TBs> z*6H=reNKvB1v+xkzGm;Gr7LLet)fZU{-~3}-`N^9-JYkbCDb;Ta27U3OkJ5|W;*~Q za ?} z%8@*0cwl}?*0o(yJ41b_BRtaTA~>&Ni);}*PyVeVRzGxQn2s9(GupjE!qY&D!V~z0 z)*0_FjIZbG4 mc~%y zf8OKyE%1%)#q)n=!E0$?g6>JK^()0MCzj8>)ubR`ZTVv$=NLc_QPAt!x@dQkT<995 z?Ume0!DiEMZenfdGv>gtxH%`Csxy)?fluDL=4w~9n%>WqJK1WMot}m=g&8)Ql2Lb! zrKaiYc{kUq-?~4rKaSrFw9kyb2bJ{;Y3?-*BFZ$ 2 zwR=AgYi+0*wJkkvEzYGZXh+)Zrz%V58?f>I@euiuHVadejM{P5(Q*F(w_A;!?Y_5b z%_gt6BBH6vRcY(Zqq}!~TJ7ld(Q4l3<~NE)vS5c;xVLz;jZRg!M+&bCM)@9Cf4{<# z25?R~gT-m<+FR&W`b_#2^~L$sG@x$Lpp4sFTLk%`l0{Rr9Bdr!ErJdKBk1qi8}?lB z&%zxt!%2en=UK7S1b0nhGjhg2LNPKTZNmUD&?p{Y$p?3h_@X zA|J zYsw=A;@;c_4IQ~45=RK-PD # zG@H|+eopIW-(w%au<0;s+HRq%toD(?WVb7Dtodz)u&cOvYx~C~c7ifadsneZH^WPb z9(XLgLvST+@=WS?Jj4$$pP51D7%HF@$9&h#`lDWI+A><%Uzlz5h(Ob)17wp&87FH# ze|v-Sft;oYY@FB8KMb@D2gE)N(zPvLTf4QtVJs6wtHy2QG44L(gX_~E;}z2gDW|QH zleU}fe?G`1A9=ZRH*~b@t=jAKSH8L);jN~Vpm t4y(bhp!FR-+BhTCHJh1r%}VKR?ULRYpUn~?f1`y-8RcNdl4WKr0b)P^R|ll{ z0_w+4z44yA82 ux7gq@|EZbo*n1h*#?DO9tJrF-a;-6oynpULZc z-T4xh?lD%jvP-JbD`~BtZFlvPK-6?U1!$fm)HFFJ)b2G4J>DbJwFvh$t<=b432mR0 z?RMj7!+froAlHQWgIv{8-pSO*9-m-M%W2>dJd#~7*&K@?`_9~MAvTem9M`URSZT8S zC-JOaAiBM<_=39ZT85D+fVGvx5nQXs8^+7FR)m63gVb%17)Y)n+r`(KX1Ay&vu$Ur z+Fw}tS6Y|YQX5pblcNQ6bc$BUJDGy+ArPriSw=DCl2=K$dAqyYlcVKpnO{YFjy%$m zlw`C@OPT1E)Sp`?dp%RL`IuVlx{R>+OZ#r}D@`nUx5vxE+`uFtG*VBDqhRbC{!+Yw zk}HxcePOO@T85uBq0(<8Wwq32ka^NGrUuChks(qs)N~7sl4|>S)Ws;Z)wHX7xE}Pt zjdG1Wt6RR|6v)`Y!r(}U4z4rw*t?HL*K|u5m2K=luyqEyxQZ#aEz-vRYy~%MeT8@^ zS90`KZYtZ95>V!9>groc)>?1TE{j*$l^C}q-J8`eRkG;%H)iyA*VOUf4e7ohZxuW` zh4hRk)MIOnN!J@Kq`6JWxO~`U`F9*K`-7Yj^?!}LJ>fIrEiz94-rpo}7-8`d)UFvJ zx4JN^J=LOo$N^vrMx$vZb|1f=1MzjBwzbpzQKwu?vuhJY9GX}U8ryw}V5vM&58h>0 zGD?KEm;iB(mEGL XOGcfd{GNd29z_{y)YY3>>g=qRop!#9ea~L_6X466@7gO#@lD*1 zE|uXM8@~~~;gm|F?2t0Fu34MQ^CT {MMZgsl) zY8sr3E=AP#mTMo`?k)a*C^yV=ApsCE!l=&XBPS=LWzp{~8r@_sa~`Q?vcagv;#-&% zMpMjXY=$2)gUKp35TIn)z0`FLA~{8!>~~rguB#&3NQ2B-3V<0&BPK8h9WZim!m)JQ z>x*qxd&2QV&uGy@8@Ag;N5GNejQpX_0U uQ&N{Ji&wI4={Iz|(t7LZ6? C3!_<0 z6{XealH<*}V31B=Y!!FLFuPC9f)ua-VU2n=hv2^!_@i3Uycyw5IBMP?)NjSCt!(*A zOGN$Dw+fjLl>lK+-{kHHrn1FTrs&F>P19C!wzBq(`<$-rrlrc`ZLNI?Q=KWPQ<8NW zc6!^E){^O?O|5s>{i40_2gA?XE8%vZ@lh4LKjTji$vvgz-K24<++148wM3Z06=^fH zHt#H-khD$5ocLqIQ|LY(y3sE+8MPfs+VO+xH&F t zVbp9R@a?yWklDT6i$>CjiwI=9Exlccjf*U3dSql0E58pf_Ixk)hc!$^DBaB`taP_F zy1rW{eL1ggRP^DLTAf!-r5W!On!L7dHg3y%KQw%m;=dVdTAaG3pQQMF-}pyBzPLUj z)-9FDmUWSgtt5&{g<> LpE$+LoTujeCrFA(4MDn0^ z+UQE>{#lK&BCN%vuQ>SU@T 1y@s1<7M-Z-7I0~HF@j?z2{((jMo f=}N zQnc4`?}91saACB!Wx JB2*bnQy+F=q^~wUQW&qzot_rA@5)Wh$$KSza2_?0h3=`t|J5Yd5F~S!XFN z)Stv#%#$qJM=j0>9Q4I`UFV1_?X7KRvybf-ma@qXr7e-mN{)wN*&y?BoHh;);6j}7 zS)*9FlK$FRA)EU-lQ6*94>T_rC(Vsnw`T;5DwWSaHD@}Kx|EZ2 % Yf_=L)+R}{i@zc zcCL2WIbHG3-3p^_Qb=!?)Yn7eJ1rYe@y3yFr0ZX5@ao&6omm+J!MJ6&kUnoIfL;b% z9jE5&Z 17yDrVQc9pcX`l9ByuXu09u IiiNGOUY}>H4jz-D(=Prw!yuYaZo~Q;>+_zc~gd zk+>v*l`MYa9i3~r@b`#(PvMv?pTT;K#-A_Q7JH$27uv1dHXc}>ADK~QA@;r$A5Kj; zPITWZN~AeeuGQ0OHc|A|TKXcnES%f-lS$u8tu4)_mtAkY&&S^z>DFUY7Sh|zr(N7k zo_3!+Cf0ZmzS*H0kxuCP61?E<7!_r0^m~m$C?wS;(rjUkV3@RQ^BF>gGH+A!1p@&= z+6O;)l7C@*Yw&O2ukAIY*=t@m(w{}~jf?p=Hy$1fX0GbMnU**Txe|b6F_LzcW0Hh} z@>lH-`yzOg;qlThejDkx9ysvL&5UNvR7Co >64a?b zXYQueO(d;n%XeiKmC|jeZ&ZkdXGz6QFPXU7*SEdOuXy%vt?aJdmCuK7Bk-4n^=qkY zuP%H^XDyM2=Kg2$%o1R_$b8S2Y-Hf4-jMvOz^S9uEwAnEH2o2E&3|9ND>k17nPDyM zl*+j&8oWrudW eS-73;qezAkte_}9i>CclqJ@b7^yVntXU zWj;y2MjI7L&e*})#D|&DK2_1tKW&SxQ^C5w!}||`UJv+nt6o^N8dr!kr?tA&v}v+7 zc{8LC$rNf;LqwU5Ma*p=Uzq1gGEiRDKF$+v+}4)dn##?uwD;}U>{D``NI`SBsPju$ z?%J|$>9pRdJ)PCHN0xX$;8(`~0EoACZK}YY5Vlwhi+ke@MhK+SAcb=wv$Bp{g31W; zw;wsYwL3v1O>5)(FN8Dd9tH3@OTQD`>QY(j9ycL8{{S?6vm1Go?o#}xn2buO@*_Jz zHQ_h2c)MD@)ioa!d_(aS_Pb#xm=;||=HE>VBb+og_VPr4HzAa9f)wU30h3Mee!b$0 zE8SAc_fIEBB1^ZL@gZqd2KAOU2h1hoVll}Cp0$
;*y`e2&;AFjo!C*dh2gJF0}q2Tk3ZAF>0s8y4UuGqj<7SsX?jSscGGV4TWUb zIN*YzMlrLD*VaD)zB>NWUJ0{L_*UL38q{!cu4$V0`bE_GY<$R(U0}=$sLGrc3_~V9 zV_z!hx;~@g?JDxqXhhO{$(YZ%up %OI X1}RXn`9=v3wDsGZ92uK+DaEw?-dMg{s+%j>S!;N;eRSxNP)ZdNmn82l zWTyoxa&}EAa@pGM?OyKZ?4R1dW&Z%%%1;mYcj7;cb&rSt02*|UCrvhX@_mrcbB(C1 zlJR#JoOc!_wze50F_Bmo{{Zk!KN$QI@m$c}{6z4_i1b*lV%2o0uP&mtxQ^aM^R3o+ zS3YBu{opt*WCTf)6`S(A#=a@kVew9r@nb@3TOD^nyRf~xeL0rf?J`@;rd9HhvWqlD zizvzh$L}j)e`@?#HJ^&Q*M&YJUu(LIR#JR8(k|ZBZsqcpb+?V=MT{Mrm<;9jKOIN` zMzreA?+aR|Jrx*EgOhjVYvH>0Q;d^-YS&%3E8(d@)5OtIr75|p)YgzwP1&nS-YqEU zB=>r&U3}5;zu=$8KZ|drY5HcJ;g1Yx_OETH+W4bRmfFn#jf70i7zK>;U?eQ%zViti zo<5_~zh_AQ0AfFd`d5g2BNBMm$9_2b6gvL^itesH)b?$B1ard; )ednhTrhU}h*X!qh8*WZDU0pLDXY8@aBt;orrLV@FL} z!TvC~xbY9eo5^K1v1)S*o1G{CL@#eNtYnbIpWY$Klqg^XppvI(%~YwZDf_W}*0XlB zlv1{h{8rgNG8`P@(wj paLJ4i%mMKq5{pFC^$kN&lKSDJn86y`q@ztcRYWp5=Ohjg zxFdH2@m|T|PlWeRr9ts8Nbv-^hr_J~^4{k9(p%}g-zg+l5Zqfdg;p0+k2RNt!(hm` zuRihit*7{}Ua+(9Guvq18rH3ey;%0mZEJ9e$rEw_n*~ED#_%u{v903yqTG2W4bxUm zdM2cr)g`*us@p^;xT!^2)3+ +j3uxO-Xx^<|^u3?V z(K%kr-D&f6YF4)D{i3vQubJtZI$ikF!#)(hu<@P5*Pa=aNk7`z?k#P0{DL_js>d4O zEMtir2RpWtTNKj2yLS)6n;`|mIxmMJI+h8lH1SAfH7RQ zv+)W|AH()u4%6*4Jvzej)?FU?$!Ve$&RjP?Aa43e5Wp2*G8*aIOnxymtL0@ZN=G z;=Mxl*jw0Lx >eAi(= z-adI @YXp0TiOmINBcwbi^u zd8N-Jnt3+*zM8W^d2MkjM`>#!mQdg@A%YeP_{$uj3ySIV4Mt0U0%`sm@cr+H&{_#T z+o?LNw{EgC8Lj5H#&RP&B9nIYZ(dC&C1^@X-g0UCw|4SNm$!Q@bRC}9Fw%ELx3^+4d7pb zvv~gh0K((K={}!tWpMX5Gup}Ki_6Yc%&{iu);S%EK1RsMI8wydLGdsC35VhfpB-6v z_UGcKhpoS~tlMsbr0M8&J9!;AGX-LD2RUR4;IoV{=V(vbQ*>o3s7sm>acbH&qV~SF z^wlGttz`-GMJaP~rj@SU;i}bNci!#arH{p*99qd7(^+WI!=XW^T^X+?P04EJ2L+{9 zKOr0VVa^W#a&TUFgI4&5KZSH3hIV?6y>_nFdez;ooi+Bxz_*ih@FS}2Z2aYjWnYsa zTOYUo01toQkka_RE7bUl<16iJLAsUXI(3zw*}Thl{{WU!Kg#MPPnFr*<^=BNk@{`$ z8}?@Xn*RW09SYM(@F&BK3T Ysz{{VuVe$f}-75*&U zd<^i-(^_~>;lNuxUqcGfLp0EWA&%xg0Z)`V0t)V6 1xt9H zh%Fj|H?j|yuLaK_o^$BhVp{1QX0LN;CaETzLOsKP=@jhBRX}n>2+zzz4!8<_TvsFF zUk`Yf;k4-9DY3us#<{7;RWz&p>mfs)W{iNxYJszj#C+|9HF!^_P2jn8BdlD;&g?Jj zLO+(_m><6yHW+|@V%#?fb6iz$^&wFy!L3?S=2o1Qmsv*pJ#A-iL)xQSok*!B+IG6p z%T;?OwtA Y8C$E##g&`B4%{QMrL0V>1oJq010! zM$g0^6_>(#=7+6lcQg2c`cS$yuWHf(wFpqM>^Wf|U8pd@RmwI1$^8)0f8dqB9j$Z* zvhin*bZ-Y}8k291&1Hq9OO_cZeD^XI85rSXJun!G`p@CN>=E#D;HQBuyiM^VQ64PT zblYJjn3FQ?yqyC#m_u;Em|#Y$wMX7Nc8boNRA0F7JGr+zxWeyCKYHt`T4}pY*<&nS zJGV9M8)+p@HcB>EZOfJGs=7~Bx@vwid?)>rzA5}*mTg(qKLL0k9h2&sq@voy#TEmF z`#?q^RCZ=lBVZEb*XWnR+ppNa_IJFrUm9Cnd|&v5qlAM=7B-E43g1L a|OVYG;)`VLlmg?T!?$TyVg0i^Y+eri-oDOl5QmNCFuT{#t^io?>jrDx7 z+hnZTZ*}BLoagU0p-ne>G}M%wbW56P-K6zxZoAz2a>xD(JF4q4KAOG I1hr|B>5ZHKz@nFBv@8Ao46{|JGV%dgS(HWQ)kE;RBRI+rz`*Lf$KN|R6 zZ-|}>zPp}%?Jf43lv{`&$t@%KaU3d^1A;O~%nwmrRB ;7nz(Cdw-;+&?Cq}2 zei!4dL)bogbfGA#IV-!yPS$TnrMlaGn M^JS)o!8FmJdr%G`|Z#av|CeDPO{N-f^cWqye? ztiK+lLX;&XQk)cOd(LSjpS+^?vT|3|J#DYg!agm2(_T8i@ZPs;eWv(Q`@@ZH8%w^9 z*~6eau3X+|+NG7+#TB}$Nn&l?u;j5D zLNfwzn3sM}-8*abjC?=%Q}L$M+I%mS16{)``rem$GuztQ-GP}6y4*LHv^OoZ1(Aqo z)Qpk&HTyyQKGuF5>hpL ^d zCZ)`yql_M@XuIF0x<8($WNLECnyF9OYQ5;kNkzEo^h>SP+FzOES~rKGzmr;fZxiTV z9kYVkPqW;~a3HwU7B@SRH7u;tOt>3HHX-#mt7Av_ho(be;+R$~bHciMt(k2yA2Flc zhd*dZHxNMilp*Zda^n@mc%MY@)xL>oELyVam$r|vq?V#7;zm28Ni&R=axmm>#tAs; zzYKg~;yotz{{Tsz^H85cmfSpAd?H7SbflnSgDWRFIKaULvKWl <9>&9R9cmrNhITcweY)Xb$h4ZvbNy{v3G3xr`m+E!F4>+E5ynz<&t$d82kSK zDjrmUh6ka=7T4kYFAj~V+ghfWH5kk~jl^!U#AcIgdF8^ZM<3o(k-2b$=LVTShDGkT zsA%@SBC@qNR||U_TDki_*={7uswBjPP_2xDyGpWxI^%m^xS6zTO(RhnZ +Rt8^HGPKDQH{IC%Ujz;cWr#y z{{Vw+DYRRAeOE-%>@^#0T|B3}x4F}pI!x$-Pbez09m9>^-NEPqHP7GMU2FH+kuggZ z{GahIy$cMI$V5l?Y{giZk6>JUtDF!I8drWCpTN**ej?E|D@ipiGU6+(HamP2ytSE! zofMpHQrHACg3)8=47mn|k>i_tt#`z_;I!0qJ!4uC86@7b*$b6IvPy`f%Z(*}oq`NB zgOE33tw~*9ZMVE-7S@-&?$Wid<|#$AxnEUv%+pe`SLxe#dvs^E{0Y2+#l9QYzh`d| zJ1(%7GI*1~ml8hIg5n88vs&91C(CIF0m5V)m6djoOEg^*S(nAb!fE0CVEBtlxRh!U z$7yns5~Z;uahSr(&L07`?QO}F`G dz^@kgZqMPrgnT*TKNQVt1XnlE#SY7biICmP zJ<=g5Aj_m{$yNp>1q%^WqNe2tFLDm)y%xN;S8m#Fw$o&1C`zQMsHZ7bx|OXJPS#g# z>uIOo;uu-9VLq45;WJ45G1By-zJ0beRe@J|?Bt(FWhKHvtgd@}Q` zwHPmS%{u#3)a}wpt}MK%Pue%&uwDx;@(3(G@7^CO;=CK;_xuzaQ1N^^cCX-%hI&LE zEV+b#Y~1Qms@WvZ^UbzZMjMtwRZLkMPROze#{u9U+neLYm#x8dY2l9ot6L%S)(dGo z-<)LZk=1wfT=BsBr1Y%u6x=y^Idzh^HnLG_?b%8;ve7qn(9uw;w3CXmvT~ezB%ZHp zq_w`+PfMS;e-b=RtZ9e9+CA=}7ly4oP2qgWVXdkgW(yo>Es1p`Nf}}{e5|YzM*IBu zmWiZj&8q4V3yXWLO6+Wft>^Q;)dXq&sfrzm<}hp=@G?lnd`6$Q&ZqH5U(mcc@xQ}% z7V?{kEVOM>#w>l6=Nm*bJ8f7*oG;I_%u%qN+jI1%hjsZTWVO+B3u&!V ASd=ZnHMFP87*lO09$PKkte4MSe7yECoe5J`lTv?fQFn&vJ3Us9 z&Gp}}FXG>ao+4M(wb|6erpG+dTj^*+%>+ntr5CZ_mS3NL-wmDzlX!Q=TDFm`T-(?q z+QogdPrLrpSzg@3%Yf?NBueZK3V``5w2qbU+Q-K~2kESQJ*n7S-d|c7MAsr|CAO8f zZ)GwdVpul-u-dJK83MdxS=2l! 1%e`>YvYD$%I^Dnzt?0wOVPSYr49=z22ITNv{6@WZhqD7gko6HoHVH z$EHf5V!37^!Gch#GFT8- UCqAZvjloD5fX-fRJgK4eep6>B?+fKXpG;w#ldaq6G>3_Si z`j7B`;!lP3uLVh@d`(Pg{vr))1+>hu%^ZyxjyIVIDhkMVs3Cq{Neznm*W&NN{d?f% zo|k%bR^BK0apHTq7SmF)BJzDLuF_8_XOIFyrc^7Q9Y)40BIU6+cw<}APOW2fB(`{> zXarMDZXKA9GC=v{1C7goPEYY>zKrnaj_ngl(tIy85^7!*n%+B$sBV|-v5By&GcVp{ zErYjiR|*+M@M~IbFPENewHUW{xs tkM(SwS=CeJZfoN`H^EvThV@I!ZD!8zSGlti?^_v}mP8poWJGWx1bq1!Og4A| zm2~A&@lNhBSK9vURg%7~B)Z$k^f1y>in_F-xmu0w%(T0`{w?i)E~b6&_D+|f=$h@e zs`maYxtq(nvsDlFI3!Zfymbu28%{YtFvNKWcf$7?j-TO;Z&Esit>^Zm%q{Jv^49g< zUOeKN2b}O!03#cT1XnrX-2zXF9x98&nn1GAbs2RS hR34!LZCd6I7Y z*Y|Cvt95kj-K>-J@1fT(Y1K8%(t6)T%Vlp=?Q17{?0GMRv>X2b5O~|d+8DcWcdP2j zrs@|msC2fBGsz)xNM=-pcMNdFa1PU&_J4_%UKjA+iw1?@`$X|1Iz_yeo+7>46i0HL znF2yKw#@F@0Rtn;Ck EI3R*W zPv9MX<3jNu)i2uHQP-i?Wz=;`Ys@TKw0pwI1mFUsI5-TdHa^mcw+mFI?zbr2-`(hy zth?@ sNbYjpDWjHnq8ox+G8YJ1~$8 zZDI EWTHk zr98$Zm5_x1s~y{oRPd*Y{{UxCiNS1sAbd7&2 }b-8UY5feP(V-!P4a z$ro}Byl2Y3H_5GQUOCd{)h&OwJW;E`ZE9?^SOiwcn|DT5ILRDjg-~}$``DF1#Sag7 zGgs81zR@nUHqtJv+Ct9j`}R&5;l~)-xGl700UJwaG%MOSZ>K8g+Vc4=+S}B{`zR*4 zEcbGZn|8joz1F^do1^Z3g5R)CgRA(1QSl}3#hnWG!1|JXg29v^zJ?{qM`eyik=3I) z ~+Z@Nas%d>p)FFPGve8Bl= zR4!}zwfHUZ3&fueJ|YhdX;zwyurXvdFEp(h`K`kw4(zG8{`1Q~0U2@kTR+gB!~Xz` zns>mzh5A>-ABvKVF56Lv-rH%nn=S5MFuT08+; vXY9A)FB<4N9qV8G zE7l~IS;N3y4L;iF7ATis5)w2%Sm?~yQbdcE{Li$PK$Gn=>6$}9a}knDTj=gLJhMj3 z46O+a${S!MKIvTV=OVwO{V)CsPx~Bx)DN%xGWet6+wTV2T_lzk-XQS>sf$j(M^hXV z#c<#W7c4LwtMo JHybmu6$NomTP zOO@R?t*-5^s^{j#?z(jyE-gpIQClV5xkio~NCK2G@RG@lfXAxxM &k^XlzJOJP5 +Uq$bMo6FRoeXmp&K~Xcv dRPl#w3R`GH~!4cKj=2h2@q{?Gb$zo356zY6{sYL+(-e|@So z#L>b<+*Z)V3rvzo5NwGV`6b3O2x0*Q^1c_jlV12Z(l)bcWvX~q?ilPMfy3$(%OT)e z!n@>|_VU;StbaKVoLB8{{1cD%T=3_I77vadKb7@w8Ee`!YioJpHVOTUXC$Kx8eka& zK&+0V=bg3}`C|wzLQb9Djq+JvSfwbpvQ};>^lhhY6Kv+IS`dunqSUP61#5Fuak90N zv{TjDJyzP-{OS0&qiXt(#J`Gq1(u9FL9W p#MH>~oY0=wcv9g>i1`M4rstbI;gJ09%#Xs0<;g+T2 zThELB5Z2pTzt(NqZFc9ww{0Surynv*v1fM!5&}H8T$uK-D_?~_6Mtt-W8mk+e-(J* zTRleeMSWWC?c##kdxwtNVp=wM m_|h|k_&1$28Jcu7WGW6OP8Ug~M=(_7nD zwyhkn#YHHpvE-GMT%#+;p6R>uTFJKb@_o;pS47jL*JajxQR7={H{2t#ZARzq7iQlJ zvKMlE(oY~UJFo_O3g@+-4r{t*o2u$2J6qofOMcgoYLLpFd(Rl$i2|RQhTIllM+adW z#d+_Jd{g1gPsGOF(kZ5z{&b$w+Dl7;B(gNWy^qOwLwu!yC;%~#0|C0eh##}B#l_Gx z?-FRXSDM#`o65Mm(Qod}kJ-erhA(exJ`udKce-I&ly6)(BDv)mLGtrz(!6!qsJpc8 zw7clG-(5Wj%I}^|KMHZ?)i~*-R9jcKRJ8mT%~RiAYqI$w+TvTOq>c*{cv!Z;2}OoO zoPmbkPCEv`73#WXt!<*|T79;qt~?jEfXATn_9F#>+@#@7 @v_A~6xq0ABX5B6!k>s0k7*bFji!Q)iD^pNS-q*8=cC>G{k6$;_eGpEp zY@>cyyKJR we63GZv0cG+jx26f=KKP@Vto}yClkt zZHhtjO1qpAHV0VP*N|x1_N$^cwl#eVQPFPfwHxbOojUN#Z7hn?I{9j(`En;#Sph4x z)sW=ieVcFlP57_E7I!*l?2X`EH^P1$wRr62@g}RM`Ik2kI^oOPa3o!sE9R9UK1_)j z!0i{|ABjI`4+2GF;xXaP7vc<(HnR?;Zua&tYq3aLX(Ls3$n#}(Dx?>-EEShw29)HJ z 710{{kJlVWZ@rV lE`vQ6JbC#T{0lc_I;W$@mk zeG*(j;z_Un0MM;l=Y#B}_)(Ly%o!oM$-r;AK&_7j=-1l1%V*`s`>2xiTe3UsFgqC~ zX!@vTJAev619m&tzG{C2^bZW{OQ86OU+MlPwGtSuu3$4;vqO=*ydj`mu*wF@5JQkq zhOPTgg_^#H@VCU@6}%uWbzcx^Q{36=T6LYgw=#W!T;)Viq>M|&``FZNnqm)?xqo(A zr#g-@<+OI!ODn}}(tpa8zWbKvXuHYVnI+Al*=U>DZRO IyZyAWDkU%RrFpQyYbJ7tcUzb(_K?_rZSJX&B5EpC`cqR z%$Zu!@OHFs%Dp4e=;GRX-$wrc9l7UHN>Yuku9I}# ckFr>eq7n>&TtMZj|^0bI|WA)46x9o-BzlAf! zC&v*0@oZB^c^;1vM|Eu^YU;}s&@t_dJB^6UJjIZbz>T%+a(>mGIMa0Dq<9;{{u=PM zfix*A!(|# eTkEeqk)Iv0kt+e>?3bm?QZb(3fYUnNv3G>YFcFUho!Np>Q) z-^CvfwJ8@^(`>DD-9XI`+An6)V4i51N6dWEo@2MyE7);g56yKah%`BGbj@vl;Ud)F zjzg#UP9?Nh;}4mblEjtTm^p5*!tgY&{8YXk@Ro*j{ZeVQokCdjtyTwz&5|Z@wI6mc zJm$zO+$!Of!u1@VN!cfRG_>iXT(`S%eRuM)4w`FPNk?v%=-u^ATdTWzY}xnE!~Xyu zcw!HUb{dn-;k{{MiPCcxoo>306>v~Y6U->t`M~55qdP_`=P%pu_S4aR9%*;J0{C-! zwmROY3453o0G11@o+BT-#@z1O8w$L9m?7G}d-!kT_wWzIjV*QPrnnw+OLctcT03Zq z Wex);`go>(S|xX|c~4+OgXaE!07q?)~x= zhb3@0C{0u(rl+fRS}Qc~?)O?=E$XkYcW|LjoTQ^D$JwPR^E=C$QPY;q>#R~srS#}| zb;pb~JLoSjekg06AlKVfEhd?#-p@4labL_!EOFUxF~%7330 *XIT}Lm}77l_9ti@VX|^-zWAH3$KpQ~cxnwA8(S365<7XEn8Xu2 z3U;)GaHQ_!zbB9~K{)1M(zWjy_=eisLb#1QOK~jrkc%k{FkB0K7r srPPWSF$#S9*HqihX|-s@7! z=Cr@-V)Ne;&U*qMI4XA%dWFfWy61y+QK7)YOPcFXNuyT2L%PijE 8QRxYu4A~5ascZ4_it#)0CSKzuElk|U37aN3Z|zu zww~i`_V){rlOp{2ldj;vuHrspw+AP6L_Q>)?wYlh%U7>WEoW}s4KIFMd%Ifwx@~uD zU9_{m$me`V;@wNcM@_WU$|jqjTF0l`t*a1|9id`$$PD5!!y!8rw;Zv?Jwx_ wM*?%M3%xHkHI-ps=`#{JxDGYzFOH!(wy_2mn1Xmm^H UJEL#Zez$N<>b=%c}=zaK2dbtI=qrb%%Tg3c^L%csU35abDyYu&K%py z?KJwkJK0}-B$L+L5$>k17_{Qzl2=Yn$x7DUT`g7h-0ysM;lJ!p82H1%*0*43_ByK# zDsWGf_C)T1f|3IQrARsMLCNIv+FqPAoi|vwyMb>nBvATn(RGd2JN6>vfJWlk 3$->`mVQQuh`y;fhCo+L?#(h>J?N-?i(a1bHr}kVDr+lE-w`=;&`LEvA?xefXvDy zx4V`>mr;%a?k6YsNc-DPD!I1RZLXF}N2AkkpUV1_oRyo=O4mvD>h8Mk%35uM>b@4b zzrEJ&A+ocUQ$C*>AiscuRhe=@a;ew*$@73uL&281To+M5w|82Pg`_Vu_e~nB#WSmd z&Ojly5EV-iyC-PeD+vyUmb#6saa_xI>nztP2|HxDZdzFg;|ven94}P>0fWMK8nftr zDoA2oH%Zd8<-0IR^2sYM;OLzRY;7QR2S0q!?JXev=JnmClTELBTU~W-+gMz!#kISV z(#bnD9c=B@Y12-cqkhsoGsC_mmMsGDrk7H0IvG`DU`$1&5cz;%LMSV}ut?x=4rut& z?&HL5HOyLrXn$wAf=Bxm%UfTYxVC=vghfuy0~O^064)g1i{ZZ)YnHYavuRpZn{#nA zxm%mn2H^sbPTx$Z%AQW#DIIg%X!?JKbvSkXXIw5dNRnHpSP$-2^KRi7U%IMWsUvAU z2HaANtlG8PvP<6Oey-ME=eB_P6z?CiWz3ekJN%Qsb)!$n`bXhU?H}S#4clq{9r&P{ zmcOM;E$lR#`^cTIlF_!J$n!oPWI^11@W;!(^%?yFx$r}_o2U4j!Fo2ScWTkaeGSc} zvtCBYGOK00rGL6l0f1#71C}Ho!H*UA)5Q0)>DMoDEvyhmme!FKSqw3z0FjlzAx8|T zrz|tL=K{ZP{{Y~c9~`_@r&-?*6>ITo-VTa6blDc_C3x*7l~E(u7!kDc8>Z#}t{*$P zljV;+n@#fdveN14t6jIzJG*LeSEm%z(&V~IT(-0KlX_p>dMy=~UC*a~W?zOrBJqcc z?>;5?vR~}Y8^TEQ%^s(2ZO!0~OZjUQgJ}7X2asm~3~nTW@#pOo`)umIBKVi$&j9>8 zn&(f@G@GgHbvvlqCAX3{0c2g6*buQ`He<`k0PiFZ(ZAZq;^v3oKZ08I=YTcCb91O6 z`%F !nW5}@!2Rrv`c zj;qM8Ch-;Si>hmm+9r`bhMKZE+3D{4-q@}=V;*uqC!CN@2_xpLRJoPEmezJ}cCUR> zv$or%e^b%+X+C+{PnY4k<-M(C(&=iwJujIg(6#lQ#pJ Fm_dgM8*Hid2PqB{r-Xxt9&4pAdmWeQqPh3gIB#;hpGt 8!XejxtY zHqLAnu0GW|Z<0Nr1#Wii9P|Y9f}n77>pl edI;@45Lv~8BI zR2`B}2|iol8JTzCfo9n1cx+#XJ}tTMkHal tL1`F|od8!)FXi?d8;i z>TAnBA9$<7Q~XxZZvFt%KrFu|LR-S7{%tc>1cG9YWl*;R1ThhS7z}_wEDqq6FqPc- zqU`1KzMk@F=={8%h}+r5a;YTK 9-WZKM{$Aqr+T{6NAb40h* zrjqhJWujJQkwGiFZznimlB4DMhAZVp@jB{0GMd`+OORVF^1OD<76PNFRFBQa%oiBy z4i58^UhS{ydLM*5U*jJKd?xV~wyEGh6~Zs=B#F}Dpms$@wv2|#$O#NdQRWT~*9^zU zb#D&7pPTiXS@pwl6l|9f7^DSBK*BNtkgbAFc^Dw=#YODgT4^g;=+fFM&$m_8^kxn) zgl((5Q;qa%My&OBv$g*KGtoR%s!68UwvVXzYAr-w#*%5`X;{6qVL|yJIV2V2Z5e(G zfG|&;Sa^Ec%U9F2eKj6WF%sf^6{B!1oS&K{QOXn6Obi@}00dWD*6FNX=$5+XwR569 zy}9%CsmjV@n5ZzULQWAKvVgE45D;|&xt5n)@S^G(+G=oWX5Ues*3x;ES?=K^m6OZB z#_0LS3^>nDWkKs_bnP8%?`~anid(Ikce}NR2>Z6bDru(nO}#l|uSLC++fkk<@jr-s zKjU2s#l97tpc*XjUf)?X%&T froVL>uU>qH)-!Tpg3ibVd_eb%jt#R>J;g5&X zJBjSlKNk3E;uz#))Y>#RH@5Mva7uz@jz8VL7Fanhr{`@`#1ZQ2BkC4E+44JwlI}Us zq?~VJfB~~{ZgHG)opD}|@RMCW64o@25^1-7W|3{E+Yc05m6BL*G-+5Q_*Ks4g;}Io z05U00-GlQfr6+4>xmS|ebi4U~Nt!4}mzFW+l8aqc?v{ zJhE3h) zh-L9ITX>wy5{(K7cxc&@MvhWPIAMg^11SZM%ayL<;zh@SHO)7|_c|+FuZjNvv*LpL zM}gU3mPy27NtAuSByhhWAfs+@LT(l5f3$bQUj|-yoxUo34%hUb75GC{v$nX`wB!)H zx>f01%NZyF#VB%f@`boS9d^o&8^LVsbcro)^_FzC)C#bHRf@7p8YpL6ovI6f4hPP8 z=y 2fli;9eP z_nW%1eYJXTs%<~O^HFPh_fqMzSuAo}Pa%$LVyuA+WG_w1F~Da7BoSTr!<|E0@c#gd z;?y)dc9o)o?AMKO3q`VK8~nh2R>K3d@sa>s{KBb3d^=&{>8> rHCw<$ROwB<$)WG zJ$ AddmvQnyz%|u~b$< O@&5oA z8N*-$R4( Za1}+*4nqO%dzzatroH3e-YSON1|!kWwi0)^He%| z#cywKAlwv9A^;hQ3aqRdfY<=eYt23$+FL)yJwwBm^3QGI+dEtJ)pbc?-4)g9zSWN2 zLJA -Bi&Yz6+CyCNZjWoGU07JfqzTa-B8p3WLgAD5a-%T=?~JOl9BnyY zQD)P{o*!$CXHwH5zti;#8x}}BGi?gZJm+XDa>6{wT(|`yCAI+4G3Sir)t%G4lGQmY zCvIfaT5m_S?$x}4P_>$zos)`+liNql%-)x2K9=-3ABeX%`ZT^f@TQ{+{fk~%;jx6N zo6A{&XeLBZ%>i^7Dx)BL&5pJC-}X&v-tJEbwzGSt%@i|S>Jp*`l`T=7;*LahI}5@w z8xR;T-2j}Q();fpPosE1YuCCRnANpwlCxdv&`EKt+V)@|a7rmb<{V&@3b_kkpMM#w z^$RZ;Y92Dvq?=CD{848LE&b96p_*u7B50#77B&(LnLM^37^-kiDKBU7E2|`$w3D`* zYa4If{-%`QED~KB)#~?MUrTAXo%cK+#8$Tu+(Tn&cXz2;1zU?*=1rmHW4YO*P%>i} z#?|GR2Fb4PLB1B+Y??LSl|78n3&}0+9b-uDHl2+edzU3x@8^bWagk5fE@r>*_lNvo zuWI7RE|YN-VI%TmR@fRykPNE2mP7M9h9o)0E04XiwAJIbzgJb4Qq=6M)$&ppBQk|E zg(PiMCnu4+_=w4>cUFp8^yY8j>!a6AK3#8S?rQB$KJw8u_g!Af*G;#l{0`N}hrA(Y zb789`#r5W;15IafY}+EXxOL21iNKOLg8_!&oRHlYIu@2XPlqiM{$O>TQfmg4C5sJj zXr%+}C4+p~!l}kuPB;sS;e31H>20s1v%J+Iys(JcMHTE<3dAzuoG;8kjIbFa0~s8V zn%dMgsWcrL-BV68MW}t22(L_^F^x!K0`d`Efo<3&h}rcyZOZMe9hREAa(C|6XR5bi zc~#TpvR1wJZQ9FZn)G-4&q7^B>r(JdwZ^A(x0CA0J+7UnMUOX4k8vv@LC6Jr{{YKe zGqyH?SRV-fF?jy~;Gd1`HLr#m&Gn9@q}`;KwsBlZ_B+_1U}uCxt`atUut@;xkinxa zD>LF4yVCUS0`}5Wx1RFXKW4JxC4ivX?90qTLQl((%*C5HG|vlZ!%eod){@P&ORM%@ zDk#^@V{l?@#>fa_STWnTf ^Jcr#*k=!Aoy4<^&JAjN4l3q47O!5H%$wwMnK#%wnb80ksu-S zpXY<&cZ+;`;Exb$-Z9Xxb$<-W;muyxP>CT~plR6{nP8G3fiMGt?YSgP%Z3Ds{;+>% z586iS @{P2D!`4CsOd(w9@UoiC~V=B#q)nWMz_R@N$5zPTZb* z=b;t-418bxl)e#u)xHbU_03)#L&F{_vnrQ27J+T$g5f~ &?-z$!(+jSpK zu`-q^$CYzQHEwTrcc)D@=%259`7Ni1w5>`zJF9DbcF$0@xRL(Te-lMwkutDV*)UZt zl5%&M3!SNv( Qq`opH+Odzdvw{^*d*tB7DMwEQUetEazO)c2D(ij z;y$zSi^JDC5V?m#@g0@mn@o>nD`BZh_*h|iQB*p}PnN8~OfvoOLEI;^@V>EOcO~D& ztu`G7<4Uz?EoHn2B9+Mp?G{n1H=2vXNT-I#P)KFUr6|wegk4tGE&kMf=(}3?*7shi zbklcwa&g!Bud9oG?uo0W(z~|$Yi%vzy8ff#eO}_>>_(?+9*J%CcComzU~eBEESptu z`5~Mr+{gw=HRBgLYHBHQsd?JHuALgp#u#k#Z+$Wh!ERDi+zYVf$SS!w%VNEc$DbYi zJ>mH;?0h@nt9@5iv5ebGs$DEG*xaByLqIUDxX9kScSR-?F$!zsTYrgOFV%c&=J=1r zvG{vKx`sie=#X2)mUh=TA`>(0ZO6=Q%e|BaUF3q;t!CFRB$T6~i;9h{wWX{z)!(Xn z>#40Zbf%<|df7X+uM4dmmYufhdbf 1zZsPYWa zks_Ab+mDvm>s=?qpMah$ywmP=3ylj)h6!$ KY 18{HqrE#_ntC-v;~&{hn<69pPUb{8{mwULc=LL>3+x(qc&DTg6aR zUQ2Jen mN9-FOwPtz~E~we5c5?lwpZ-Q6tfAqOMR^8o5VV-fqHjE%MT z&%wJ*D?{)lrkZh= zy}p}0b=@bUR(%s!g-LrUtIktWPgP|bxVH4=y_1(~+iRor7f<+^@CW0+!yg*{&+y#G z;5!XU$!s)TN@BLwme=5sXAE*kp$v;Q(uK~$E@PB7@n4yL5xxfa KREFXNg}|0K z^H}Ca8DPpWwYbR{`B_P?u{<%Z>YgjnWB6I|GH4<2_2!GWN%3Xvz*)5D(iMy6x|8OR z#hsZ9?J8n7!(pqgo+40+!`58*Wj8put4f=aj*8CQy&7vvH+>Fjl;bITS}s&-zEvdO zG%7|iz24S;7QHXMv|o|2tha2|S7vyQn{u&<7JoJ-gdTbT0NOaf&OsdTPX42NrA>3D z>GtKEPZGpregeorUGcFSO76fp=uUbJkFd25*ymaBzMpq>;Voh>9%*-%*B2J88Vi%< zG=%MzL Ws!4OIvF))5$q+kRzyb4&jB| z!)o;>kWLPRjB3=UdXRSImaWA#9n!tEZQcCzH1_*Kq+Dk$EVg!QR`0KCX=kR%m-I^= zV^7y)(yVMGy735DZL~-&P+ZM2Uu`6nTwoo?es+XKW^=Rxe@VU_cu!CLnk;SpBkQt9 zC&Zr;X|ctp*h?ZGu*on75y03hf=iy8@?FZt6d#^E8{kbh_Ga*Vd|LRSt6W`p<6O09 zyd$IBZI HX7>Xzg5DbEx3~5r6lq=$6D6jc*MYOh(wB(#p_Kr5P=4mUa*_PUA z#tt%RT5{9fy1y#CwMktz_tUxPe-{2cYd8KTy}G`UqBH7EKA@T0rdb(xNgN^kq7dPV z4i_7cas@}Mc>43iT2-q50BFg3XACO#OA|C>%_*NQG!4iHlE4M)yDT$aE#kXh550x8 z&Yh`8sOr;sKW#S=w2;F!#? Fu(McvesKkfw2E$=bC)~ej9}D=q#5yjG zd!y<0y8VxXC%K+&B+5S0Y{ bG5PrD sAY2xonx*m1i-i0a Y~t_U%cYu1+N*1Q6d{YJXwEW8#_cUq+WM>CUpBoHK5mmvJ|5L|yQR}V(X|On zIEV*=*(Hz#$}lUy$3hvKBz3Ne!ph%5Ta8^jomC@1WN9N=+RdaNAw&RfC|DAQ8^8mo z=cDmtH~OK}+d>0R(JgfgdnrVve$by|Y)s)9NtnKP3P@nNR^6N+@cTsaL_AHS={E8t zcUM+gqz~p^+eQ>fB2ZK_9y%TIk~V`}^Ns4qmt}8vOKPd!Piw1RuKQZZ=uXKiD?Ki^ z)!y1!U(VZ}dEz@~)U{i9wADqL<}b9$H3c!or0rQ-Z*E8-SC5!rb*ybl3#Jw#>f27U zO(43 7#9F(%wRYPTD*3FNy1~F6z&9_jS5PPlz>G_2_(y4IUdkHVB}S zOM7zSCTPGPX F7PRmTX)!q$G=SQ~`8yp$#?$og~rTDBI7vQ)UN c6XEo)A3D#p{BNSiQ0 zvzBE%lDXU%jil0z9$ZZaCgld&noiD5+mhC^_^zI-<+F+3*ws;#T-s8N-ivto+FI{! zy$^=|I(&5TckKn@ogc*>A@Iewggh)nuv;yyvMdv%A&1(2%m5KHs+Lv&k`LbBBB=N# z?&NA3#rzs2gwEqonl-%h#0Gf8gdqd0erL*Y#?W^9*S+2NhW6V*xSvplds|H|=I=tV zhT+MTC4yIo#x2i6n?!|($xWr3aj%=a+e?oTEK@Z0;`;s;X0vvLpqawD;BbYQ2L~eo znEKbDT3S?tjh`}#S8nPq9}cZ+?&{sN>}^3sxJi50SGxXYmaf*j_g_mZorT_ ^>dpz83KOvuSr;AG^Q*0ED0}k}g{1(hGZ* za U)9*BVbz$Nk0BaWB8-T;8>6W%} z&v7P)GfaNPbCQ;_O&af%qLQKTufz3V3ve2Rr-Kv2&2ep_>aci)F52ZGxM{_t_Kd-h z11SPYhx=+7U#3&6_SU{E()>-XG?!NkVHL!JYuMgPn|;|kA~!F&b_Lps2?|&hPN3G_ zq2YgumvdR_de4RLE%cEXnhWV+j@moRZm`V^MVXi|!!ok&1c8i^T?*2bPu-@|j@re` z-F(+cTfWKa?b7%s7Z)4bZdqQ}+9_Js(|h?XPDUq+=`U`kv@$$8f7%7Bxs92We39%R zZ+QOjEC_7w!4>*R`#bze@xPBe8Kc2+?_(SmpV h)Q&`sO7Jp1P&3r>ITg`f{gUq0;l0w;ZQ~~P*4EM%5*ZkLj;Nrsasw4V!?~Gr zis1F#VV1%>NtG p!tKpZzFBPPwD9u9NCIj)$0v_k6YE2G-V&enSAeeCV> zIGTdAT&}%!*4pmcepX*`-N)mk&^4?3GSc1rJJr%1J73WAzTItDc~d$dAy^PUdH^kx z=0wXU-tD#T4EP_zx+aUO_*X=d)4&?jui14Nl*(;ob|P4AnTs;uXJJ#@V*w^}^OD_P z+E`rJ$!7~#YO%22a;&mP &dEk zdcm6_&h-}pSU}v-hbmp8Q?Twbl?N?WoN4lNdy%NQEU%;G_grmduBzH=>SW_7FLmFS z-q&7et9z~6o0`_PtEKiIdGPB))bz_{@b`!`+vUE$jn)g tHK8}Q}Evjy0M z+-h-H$|jOKS&3w}m8T`;5yUxc 2xy&~%>=Txu}h zY5xFYjdb{~w?i)7(3_c}0VFYV9A-`>LUKU>)mjoxqK_{w-8EX-t7x=-TBUGOj1u?d zQa4G &-8T9yFGIBPE}Ct0`|0lg0MKqMb zXs?GK2rO oc9y>CySD4CwO&ncx$wK;Bww;;!gsrySBF&b zmD>4I$8@On_7lqAy^ dcb{#bN9N5o%e)Zn+7jmDql z#PcJF&I@3K+$1|>40a9J$BB4@Q?}AIPZa7_x}^7iY1N{#5;!a5z*v2nG6q %GLlWbI;-2KlD+oc&wsvrMf+y_Nt5CO z=}_Fkr)hKA%^@}lW3xplSs%*;azHpk#^J^fT_1xV7Cd9(5AFW|7+J_>lUUUx@at-t zx*5~tm6BO4QJ9^pk>(a|%NFIuerR~^Pa8$9#i?oV!}d1PAWN%_ J?;;gl@iqSn?ude!Ub>7G8Od5oi`Ubac;xS=&a}ZXt zxLBh5UBk2d%Ld=LKtDbJ+L&CDD`VmJi?#hP?cN&l)^7>xNfR^|Qf?4VNITRq{n%E) zeu{D#cCb0~`4$5lI^s+(&HLEJr%i4=+d~7DCO60{m2>yN55FOsXvJ0W{gwTffc38s z#Vpo0x?ZKH&2C_mV_bQY9q}nr6t2^_lBHLxg0;OS>o`R&SvAcat*le+ZCckyrTZRy zz1d1GGjWu;WgEFWrtQ1w($7owS1~>@{?FgCp0jDKd}8>+r^6IJ7dvjHK1|PWyoXz8 z91$o(%#5VAFjbp`ADNye{i(lUe*)U-mc9}FoORC@_+rlI7kaB`Wo)E@iObwd(X3Fk z!#-D;wC=*=c13qTwKv4wTSL&k8hB$ bwwUNFOl^DuVgnh=`oMP q=IzG}#`Ugn; zy1os5(jN_P>^>T55qu)}nH0tuw5?BOkszOVjz%CA+%QS`PQ}1wCMV5*Hy#6r#Cm0% z*ZOvsYIHjrdF2TtfhBnzRh~%HV9l}4Jg$q7*v>_Bx-F)?eEL?8r@hK}hU-$j)Gn@U zWn{X0R+d?!wTeVLnA@Qd7Gsd8*igA6iW*Cr50*` )YlGqFigUB 5T)>%6qeWJkpr`Y53#Vh zVYqZ8gPQ(+JO}$s{7LvX<0O;9o+;I=WQCy`j-9A#6I?+nMEhiQiJgpOkl!k?MI;o! zVk`8)Kj5M|@5KEZLbHI}>3${ASsv}$NML |*dzs~>WtB(LuzoE##YTGN*Py?ph#$$VGvuZ(^gc#cH5@aC&J z+Jy@amjg?_R3`x=Ku8R6y@ @8-x(~|CAv)|r` z)X5#I!9K&d;Z#n*?G1)fNCWO~h5rDxFN6GV@eN@3oo#!k-`T8|*6vWtZF77SG%>n9 zPW5222Vl{$8%ZRgugf3X1LH=w<6jr}!rD8)x?Y*$Ic#)iggj HcW zrkmC-Ymp?HN-?{#TG`#U+wH!$>Du@*<43oG;A+-n>FV)BY($^Gl4fGu#>_cW^Qk8s z _NLne<1(PuoZ0cf;%3 zZ3JIxJ~h!{kR)xWP9%~pLM&(;lbi$h$lM1fAd~u8;cxgVE|Kt~PqUtX3+lF7p0t8H z%{ywon|%ur=R(n`Wr$0XQcgCx&&s6d@hd>nG@A<_6I@9w*LsDziR?@pRb`Q+<~HfH z9mmUI(B!rN#bit3D}8gt9u}KghU-t$VY{`px=EPI6*sC)A}G#qsvL#; 3008!Jl%G8~xix9>+AgK7X4SX%ZKIEOWBRu6r|m7_AKDMY zk!wE;ZfrC?X5J`nwT}rrqAf{4Q6$V@Ly}h{>_EUN62=%Y$Iago{8OoFdd2>iXMQd3 zr$?JmRzk*9j59L%kMe?BY-jkCe9AG%{J8M L`K YT8TeX1ixJuh^bZuzCi}P~PqbKGJX>V8lgq?v zrHc D9;o}J@!Yx6y6rSo$=?2x4(#rjA z&qDCWiFN%SP0}v(ZCUiIzdlFQ(%RvXkCgZxYed<^qa^?* fGM!#k;xdt-FEXQEOBQ^p!a6wxAp73ACuMB)j{hRz3ul!T+ zgdQi=BA(+$yoOj-adUH~xwLuJn=%s0g|;ar269;dHQ?Ige#Z71{CE1F!w57>+tf)X zlSWXj8n-zs2h0m({H&m{&M}- qB+~blt!q2G#kG6h-;sB|7S_B~eW*(E!*eTMNb)v5ZK&rPWl{;k{Hzy(I6MF= zyYU}^j)9@s%Pg|$3#eNN(?_!=VFa6Y`RuEi5rF}=02JWJag3kPEl%(DJh|2u7Spxu zJ58S9RT|zan_IY3Bcdv)-I7Zc1Tu4-+*hP(zp}T%&3j0T$3FzTW2)+U&YTkC{t=Bz z?Yz6N!*g3SG8S>>41V|k(H7r^P0LdiP1K#8no8X3Nk6q`(c6_I_tk4-S5~BD2RKdX z%B-(#E}Lmu`bj%G-rkGzN5e4N_?FvF@ZP4Yr^gMV19v05QpSmm@yhRmADfSqft|S> z^IX4->}|X$sKKFVwx8O9`sxLP?7utUxL1(5$yD2tNa_J67_YKCao}Al&es0`Ro1*4 zs(622irR9vJ6bz2cLER_&5Pu7F&I&~k(sv~WD5D3=U&nLE8#B}c;m!+c+<6;O*Jk2 zAeUz%?^9(YDh3O=Lu~{mR5Fh=fItLcB^z4GOG|0V6w=#9mHM^wTLfnrzFRxDdt2>E zCY9~mTWH>ei|-m~KLI>7sq6Yx-k+&>*IJe(drOHHabpaz1!Z+_njD1 HNgzgL5-783{Vr2@7LY(JrSY+ov zDd6Iw>M?|4c*Q%nWqB`iR_%R!?bFGf(1cWH8Cgr2UP{(UChWYfwe KZqQ a-eA%ICV_AR)YN=qLs2Ru@ 6LQ;U}B*1NJz`^$aRwcGG)<>_SY6=kPr-K%YTNqXAq_c>i= zL96(!A)K3eCAwcVazZX2J9lyA wZ){j zcej$i_I{xs$sF;tuO`T($uA!Lj4)GU6J9T;X?jiV?arsJtZ>b$J
ilB)ghFC>CcCslv(`a8E)A9dVL<8(z}R&z&@rdUEKK z)kf;=B;DH9-jdW(v-lE9QSUFZ_T4>yJ&)BGejIpiD4$W%yiz<>46@Af-CIZILkN+W z#HLbPx!63$KiyW~R~u^$-G_=UEL1tRHg5y{m=%qq+RlWs fvAdpn^&rNS(CZQ#@ylVxW%83vY<(8c~frExBK`r-}1#^>{_G_IZQ}MCZFDyJC ztEHk4wn=}dOC8i(G8iu94*NmI;nW4m$vEJ3O%^*X1IxX%zOmHpE>aNJHdhw@Ou?`n zUQ`Dle7ke8$rvOaX(blb?aiZ=+vu&U(e~eM^-kGyMp`L*)>mCRX{uk7_3A&tekIl9 z)UCAp>$$D;C}j{uV;p-C_HZ|L%MtP);UKn2BOiNsF77RAWYS&*wT9PB7jj8tSrw8d z;xJbXJjMCA<0Y}l#e9L`-v(<(Lrqz9i>*o4 I_4)Ka-~-xNWhG@&By}2 z_4r@m-xA$uQuwa>!_jztYkLN ;=qbY zV|7d&_}!4*2?|P(Yx*4)FwLe}c#FgSF4C7&)2$t*w4P|8xVM@iyq*fI+g~b2JMuA+ zy1oYeu>SyS4;xr`PR~j3=AES6>sL(Hx0kniaGE(JicuSsDjGmrXcB kdmy+%O00&Dyn5g?$)xX2c;|a!ZM%AxBiQ8FQ;?;D~AB^+pYh$Ra)3w#4(O+9f z1=|U1t|GZs Vrr(kd$r&9Q)H!TF!9Orq!eq@?=jo6_mqM(^jPt>w82 z)VVC$=f09wZ=!ZuTTSiV=#8%xc+&G+)ZWuUxw^5?3=x|+tiemEm2kUm1b;IOWtC2F zq?Y-!jQg8w4Ms8jiv;%iltCWnP`zD YnFHDmO8$j;|VnF zN+^+}xRF+SyLn<6A7^&?*KZ>^VYRle%f)q;o;L9=jia=wsoCm!jlza)R%Ir0D<)ap zq&eId9B`-oUjTELs_5PulIq67#(Rs|WSST?B)rc1IX+)HSh0W*FU_=Yc*lCq_={`c z-4gD{!+I{iKC5|iYLZIA+_k( z?g4pDT*9isjqhO3f$TJM}wt@Q%Le;jf7{7qi2Cr(D6SYTB2SsRK!CDo$-Y zz`s85Hk^jR{nTp8N{>MOq(5rg-;TOohik6e-r2|C`vtet>|+ZRt>p0{s=C`QG6_)O z2r;WR=4Su_=6bHH;!g|sYr_5=U3mmIjlS XPQEhLfjn|XT3zDFmACR$go%kA4o4fC2qu$n5(*FQ{oqGwp zNlkL9YE9E=YaLbg*}ZK2dl&ox;hFv zeOdb^{?wln{uum4UxK>dh+gO6r;5eag=r(8X!OguNrD*=vp9GgKfH_N49W_+$WHGY z@K&wjtqV`_J>i-=S+8uq&A!Xa7UtSWnO_crAxvil2G;X8Fd(&j<)V1UQ1EAo?Dfbr zrSSmME (hn(K7*cC-CK%_mly zeDtRuhNrx_oTAi~^^BGNC2elDvHc=g*nBPcd!b+WAL9Q2!#iIc=-R=#du@5GBa-S{ zd(W9!E(&>!h_W4s8wjLCafK&|kM;olihd+`8^yjYvRzBU-WbsmT|zAr(yUUF^aIgvP ze$H9hBOg4BIcWD0y}%XsAMFFFcp~TEpMa(K6)nZ@!@nL}!!L=o4L(n_NvEWUvr4ka zhdx}(krR)UjK-TJ$U9J+oSmmAB<|wceAa5sM*7`qn~Prcq~of7W+Ihp9Fm-83U#zq zsmVC%wfB?vCY+N|a#Bt@YOZ+K!9Ru{vNyqe>mDEYFE@#P*J&jBb;h!uZM>5&%WrYI z>7+mufWZ9BTO0O(qP_flY0&jO0N87qR-d5RUfrx~rfJsF+qIRl77$vX3Z;g|JKP0n zIbc8vYv*^@t*o>?BHO~Z7Izwcl&NV9SEmye1$O}v!Upq3=3;mR518hU5>FGwrN^wx z92%U-_NfJiKn)`-kt~F_$`1it@_u2!;-{G=)K!|ZS~Qny^jj}0TGnGxjFP%-yQL{L z&8IJ&uGR0>>s`;Qz6^N7TkzM2C$;!}b!&a6`Oea4x{AE1abn; pW*FlMYy=tqST;@Ygx>E$(Y;~0g2!)Na(5o$o$&Tz9YAU zJa>1hC7z)#oua{OYIOL^t+cELW|f!a+?!6^wp%AWb@#6b>zBSM@Ylp|h_h bG*-TwTOuy7L9ZzyZ|AQ8tWc1~9#jYgfQ5JZqu& zrt`*n> =^jk!+GAY0g2>Yierr^gIF&2$PmGo_L+j*@yo3d>svg`L9 z^eCuPoSiGU^7~23P06=wMiFvqA7wj5wwCt2vOFhe7L}{&dbRPpd1bdZdaM&(T)<|x zU;&CRHISi1`9X{fWEBJxpIP`#r2fx(-lgLY8QR<}pP38CsKu+M@|uJxvDeSI+^!K( z5P5r0kgdxxua@<%5o?|&@eJ4Z@;q8?)wqrnwu@m~NV2i+BafJIhWU<3Cm>^$h8x`$ z9Yk3xMWkv|@RK-5B#{X7g6$`eobU(^M@A;O?x85kE0#RYQi^F_S6A(& NT zwwJc4W-RpSe2L{Jb-SIbgMxAx6#%w513kwXuCCuu*Y#TsZW(PYC2bo{2|0^17~y33 ze5NBSxkgJV=aJ3{s&iEx_foQJqPH(iR;zb??bi2B9`l?d8%3!nJ6=zt)$8A;yWIBw z0EFMP@5CPm%Rh;HW#JtY;?>+L@qcAsJ+fU-We{l!{ivjZNhFIX(l!~D7jacWEA@l+ zTK%K`2l&I_cg2s1UI_SS2ZgV0OIdiY!goU6<~=^?11-UZ-5N;uh9*f}a6>A*WG(^x zCip?A{{UxS$E;i1#eW=f-a~Pw&O!50;_~oSzq$czjzGh&Lbdd7><{7rZSkAquY+&a zNPI2hjUMj)*Gb+ysIKjzk)#m94%T4Vk G!&JT%_Qo3cT@dNkXF9%_fwgwbl8qnzGW$*J=KhUVK*ZCZnQg+I-G5?*!|u1&*B- zn+$7WR`cYDPSAy1Gm)7YMr7rRxdy!F#J&)?@V=-0o2dxiQy{rgS)`I%YptRew{~uT zV7NGB1E;TLqiE4-o(0oyv}tYiFAiy%lN*a`=L*)$lJJqM<@R};lE55oE0*GrmThJ ($J=Gos) zYp(wQC)By(od-hJBk=~kVKvm37IypfECxk|T0F#6Ul=d2Zd`N5-kGnLKWXm@_&N;} z;hw8+b29k8O*OBYB{_Ljqsya@zUZ-?$=73K@`Tsb-Ye4lQQ_SN=HtXRYo_U5AhT0( zbz=T%-m1iRN*FHyD8>LgLE1K!74uK+39I;04G-aOi|2s4Po~^x))LPXpe-3#T1gd@ zeE$F_+Jo31mo;&fxl)a}la=k--B)cct=jv9FV6_3mEO&(wA@osTivI vyQ5OXL7=i{5ZBo2mk$N@XqVqbPOI=8A&Z%baCFT9pmjE^-xQa`s1>QnO$j(S3ZZf@i z;;$KWo2@SL(@};qs6ggXsI-Jl=gK!2gKhzWhUI|3A0`OqxnB=j>Dq?8@!o2y3bb2U zB#SY}I?0fz%ber_GDbQcgjMYq!+Q3$tZKJ*njD&rk)`Sh9sT5TFP9pVfbScT_o52G z0y!iMup*{5a$L#ZXKlBNZr1AGo8L`YrJpV4t;*B0x5Dkqwe8XS#0{cP;ww8l+an#U zcDKUXR`XUrI7KM=)d|d?fDSSW=Y!347usFzoy-?DaKStl@s_xaV%*FSg_q>Z 3!8oltuidR|w0-pZ%;P2S+VYaTR==&?wcl^S zowtLmJQuHccg6ZT+y&IXvt`vRx1Em^(S{@=vB>j2?$Mq{3xk^SpABldg!Yz6dnK^Y z>}R=-<~xWpbt}Xf2@>OTD&r@(QN~#2o8TE2Le}mtbrYL;8cSDK;Urs-%A2=vFh~pi z(s<8W?KKYyYPL6b!%B|ENK8#S>G#Z5UoJ%R1eV|rzC(P(jAIOW&0V0>W7WI=0Kiv$ z8(Ldv?YQKp7bwZ8ClvSp00-yGC9Agg-19r@jV{_d=`=9}_p-?HM>CI`%O@(EaB>%% zkTZ-9nXYQ)+fdZBmOJNVnnpLCQD|aw6o9y9jDo-`748A#3eeMZi;1PWywm{G%nvAa z4gpw6VC1PJ$*>K;3=%$W_^Vcp43W O|DL1E0Ev=VVrthuHZ6X^d)a@-qHx@c{5zCoSHsH*dkZu`5 z#QdmK=Yx)GKHcQ8pHZ^0xtM7SaWvBXp|`!-F&s$pF>Szbocw?&139hF4cbep>UKUK zzMkhzw3hSDp75iqrL1`}OrWZjEV$ruM+1^88^oGiR{Hj(Wu$5ef23Q QjO)g`IzAHbC%B)jSjV{Xx<=( z<3OHBq_j5j$8xMyBVquNNLE%mSCU5#*irz+KsvuM&1#$GYiM5FzI%Q)?Ee4|aZ-v- z>qOIc(eHk}Z`WJ&KYjlIYS=}Wz^?&a+&R07TkX2Ewx@c!r^r%Gop HJv @Kam?MN|!ZY<|)31Kku zJjFjYPz~UGm?~>T{n)8S`+3^$`^#&scl-=t1fsd5 Ca%^H zXc1lbYg1c4v`D(LNeoxJcC@US!Sc^e2gv1cxMN*jg<+vX;JsH+)sgM|NG{}9n;T=5 zNZQK~AQ6+2$BYAk@?xmo_>WZ7{8^>mYYV5%px9ilon^wM%UTB_GU%h`TyvK@$UiYG z1$u|ZT{710*GjU}uQcmO{{XYn@m|+ztdV6}I3*yA%eN|6{NpDhno_&8A-3-E*HvV; z?Q2^5KK3_~Z<5+J+ugmIx7yQQZ5LZTwLX5j)8o6ek~?idrnmWJdpP7NZv^Cdh2=tU zUyqb@W0QhwtnhD%bbAdl=G(-V>u+akGPF{JCv2ex*M};^?H~ydf(ZwV;L)W=W2b1B zHWF!n@ix9kXf8JIlgkQ1O!(ydy$8%t3>*$?$`;OByN0n7ExXHf71~ueP>u7rLUxca zSd3(n2SZt;-S2*Q%GT+pFGYJ=?)G*B-0d4SuXw-DT^oJ1JvUVGR+p*EG