From 4dab4eae366776487b8d55ca5c61fb4241b9c6b8 Mon Sep 17 00:00:00 2001 From: C-Achard Date: Tue, 17 Dec 2024 08:27:04 +0100 Subject: [PATCH 01/33] Fix use of deprecated arg in colab training --- .../dev_scripts/colab_training.py | 2 +- notebooks/Colab_WNet3D_training.ipynb | 332 +++++++++++------- 2 files changed, 198 insertions(+), 136 deletions(-) diff --git a/napari_cellseg3d/dev_scripts/colab_training.py b/napari_cellseg3d/dev_scripts/colab_training.py index a5020fec..ce30d013 100644 --- a/napari_cellseg3d/dev_scripts/colab_training.py +++ b/napari_cellseg3d/dev_scripts/colab_training.py @@ -330,7 +330,7 @@ def train( wandb.init( config=config_dict, project="CellSeg3D (Colab)", - name=f"{self.config.model_info.name} training - {utils.get_date_time()}", + name=f"WNet3D training - {utils.get_date_time()}", mode=self.wandb_config.mode, tags=["WNet3D", "Colab"], ) diff --git a/notebooks/Colab_WNet3D_training.ipynb b/notebooks/Colab_WNet3D_training.ipynb index 0c5ed172..3aa52f46 100644 --- a/notebooks/Colab_WNet3D_training.ipynb +++ b/notebooks/Colab_WNet3D_training.ipynb @@ -1,27 +1,10 @@ { - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "provenance": [], - "gpuType": "T4", - "include_colab_link": true - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - }, - "accelerator": "GPU" - }, "cells": [ { "cell_type": "markdown", "metadata": { - "id": "view-in-github", - "colab_type": "text" + "colab_type": "text", + "id": "view-in-github" }, "source": [ "\"Open" @@ -29,6 +12,9 @@ }, { "cell_type": "markdown", + "metadata": { + "id": "BTUVNXX7R3Go" + }, "source": [ "# **WNet3D: self-supervised 3D cell segmentation**\n", "\n", @@ -37,20 +23,17 @@ "This notebook is part of the [CellSeg3D project](https://github.com/AdaptiveMotorControlLab/CellSeg3d) in the [Mathis Lab of Adaptive Intelligence](https://www.mackenziemathislab.org/).\n", "\n", "- 💜 The foundation of this notebook owes much to the **[ZeroCostDL4Mic](https://github.com/HenriquesLab/ZeroCostDL4Mic)** project and to the **[DeepLabCut](https://github.com/DeepLabCut/DeepLabCut)** team for bringing Colab into scientific open software." - ], - "metadata": { - "id": "BTUVNXX7R3Go" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "zmVCksV0EfVT" + }, "source": [ "#**1. Installing dependencies**\n", "---" - ], - "metadata": { - "id": "zmVCksV0EfVT" - } + ] }, { "cell_type": "code", @@ -66,22 +49,17 @@ }, { "cell_type": "markdown", + "metadata": { + "id": "nqctRognFGDT" + }, "source": [ "##**1.2 Load key dependencies**\n", "---" - ], - "metadata": { - "id": "nqctRognFGDT" - } + ] }, { "cell_type": "code", - "source": [ - "# @title\n", - "from pathlib import Path\n", - "from napari_cellseg3d.dev_scripts import colab_training as c\n", - "from napari_cellseg3d.config import WNetTrainingWorkerConfig, WandBConfig, WeightsInfo, PRETRAINED_WEIGHTS_DIR" - ], + "execution_count": 2, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -89,55 +67,63 @@ "id": "wOOhJjkxjXz-", "outputId": "8f94416d-a482-4ec6-f980-a728e908d90d" }, - "execution_count": 2, "outputs": [ { - "output_type": "stream", "name": "stderr", + "output_type": "stream", "text": [ "INFO:napari_cellseg3d.utils:wandb not installed, wandb config will not be taken into account\n", "WARNING:napari_cellseg3d.utils:wandb not installed, wandb config will not be taken into account\n" ] } + ], + "source": [ + "# @title\n", + "from pathlib import Path\n", + "from napari_cellseg3d.dev_scripts import colab_training as c\n", + "from napari_cellseg3d.config import WNetTrainingWorkerConfig, WandBConfig, WeightsInfo, PRETRAINED_WEIGHTS_DIR" ] }, { "cell_type": "markdown", + "metadata": { + "id": "Ax-vJAWRwIKi" + }, "source": [ "## (optional) **1.3 Initialize Weights & Biases integration **\n", "---\n", "If you wish to utilize Weights & Biases (WandB) for monitoring and logging your training session, execute the cell below.\n", "To enable it, just input your API key in the space provided." - ], - "metadata": { - "id": "Ax-vJAWRwIKi" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "QNgC3awjwb7G" + }, + "outputs": [], "source": [ "!pip install -q wandb\n", "import wandb\n", "wandb.login()" - ], - "metadata": { - "id": "QNgC3awjwb7G" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "Zi9gRBHFFyX-" + }, "source": [ "# **2. Complete the Colab session**\n", "---\n" - ], - "metadata": { - "id": "Zi9gRBHFFyX-" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "zSU-LYTfFnvF" + }, "source": [ "\n", "## **2.1. Check for GPU access**\n", @@ -150,27 +136,11 @@ "For Runtime type, ensure it's set to Python 3 (the programming language this program is written in).\n", "\n", "Under Accelerator, choose GPU (Graphics Processing Unit).\n" - ], - "metadata": { - "id": "zSU-LYTfFnvF" - } + ] }, { "cell_type": "code", - "source": [ - "#@markdown ##Execute the cell below to verify if GPU access is available.\n", - "\n", - "import torch\n", - "if not torch.cuda.is_available():\n", - " print('You do not have GPU access.')\n", - " print('Did you change your runtime?')\n", - " print('If the runtime setting is correct then Google did not allocate a GPU for your session')\n", - " print('Expect slow performance. To access GPU try reconnecting later')\n", - "\n", - "else:\n", - " print('You have GPU access')\n", - " !nvidia-smi\n" - ], + "execution_count": 3, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -178,11 +148,10 @@ "id": "Ie7bXiMgFtPH", "outputId": "3276444c-5109-47b4-f507-ea9acaab15ad" }, - "execution_count": 3, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "You have GPU access\n", "Fri May 3 17:19:13 2024 \n", @@ -207,10 +176,27 @@ "+---------------------------------------------------------------------------------------+\n" ] } + ], + "source": [ + "#@markdown ##Execute the cell below to verify if GPU access is available.\n", + "\n", + "import torch\n", + "if not torch.cuda.is_available():\n", + " print('You do not have GPU access.')\n", + " print('Did you change your runtime?')\n", + " print('If the runtime setting is correct then Google did not allocate a GPU for your session')\n", + " print('Expect slow performance. To access GPU try reconnecting later')\n", + "\n", + "else:\n", + " print('You have GPU access')\n", + " !nvidia-smi\n" ] }, { "cell_type": "markdown", + "metadata": { + "id": "X_bbk7RAF2yw" + }, "source": [ "## **2.2. Mount Google Drive**\n", "---\n", @@ -223,18 +209,11 @@ "3. Copy the generated authorization code and paste it into the cell, then press 'Enter'. This grants Colab access to read and write data to your Google Drive.\n", "\n", "4. After completion, you can view your data in the notebook. Simply click the Files tab on the top left and select 'Refresh'." - ], - "metadata": { - "id": "X_bbk7RAF2yw" - } + ] }, { "cell_type": "code", - "source": [ - "# mount user's Google Drive to Google Colab.\n", - "from google.colab import drive\n", - "drive.mount('/content/gdrive')" - ], + "execution_count": 4, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -242,54 +221,61 @@ "id": "AsIARCablq1V", "outputId": "77ffdbd1-4c89-4a56-e3da-7777a607a328" }, - "execution_count": 4, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "Mounted at /content/gdrive\n" ] } + ], + "source": [ + "# mount user's Google Drive to Google Colab.\n", + "from google.colab import drive\n", + "drive.mount('/content/gdrive')" ] }, { "cell_type": "markdown", + "metadata": { + "id": "r6FI22lkQLTv" + }, "source": [ "** If you cannot see your files, reactivate your session by connecting to your hosted runtime.**\n", "\n", "\n", "\"Example
Connect to a hosted runtime.
" - ], - "metadata": { - "id": "r6FI22lkQLTv" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "EtsK08ECwlnJ" + }, + "outputs": [], "source": [ "# @title\n", "# import wandb\n", "# wandb.login()" - ], - "metadata": { - "id": "EtsK08ECwlnJ" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "IkOpxYjaGM0m" + }, "source": [ "# **3. Select your parameters and paths**\n", "---" - ], - "metadata": { - "id": "IkOpxYjaGM0m" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "65FhTkYlGKRt" + }, "source": [ "## **3.1. Choosing parameters**\n", "\n", @@ -327,13 +313,16 @@ "\n", "* **`n_cuts_weight`** is the weight of the NCuts loss in the weighted sum for the backward pass. Default: 0.5\n", "* **`rec_loss_weight`** is the weight of the reconstruction loss. Default: 0.005\n" - ], - "metadata": { - "id": "65FhTkYlGKRt" - } + ] }, { "cell_type": "code", + "execution_count": 7, + "metadata": { + "cellView": "form", + "id": "tTSCC6ChGuuA" + }, + "outputs": [], "source": [ "#@markdown ###Path to the training data:\n", "training_source = \"./gdrive/MyDrive/CELLSEG_BENCHMARK/DATA/WNET/VIP_full\" #@param {type:\"string\"}\n", @@ -368,45 +357,44 @@ "#@markdown Weighted sum of losses:\n", "n_cuts_weight = 0.5 #@param {type:\"number\"}\n", "rec_loss_weight = 0.005 #@param {type:\"number\"}" - ], - "metadata": { - "cellView": "form", - "id": "tTSCC6ChGuuA" - }, - "execution_count": 7, - "outputs": [] + ] }, { "cell_type": "markdown", - "source": [], "metadata": { "id": "HtoIo5GcKIXX" - } + }, + "source": [] }, { "cell_type": "markdown", + "metadata": { + "id": "arWhMU6aKsri" + }, "source": [ "# **4. Train the network**\n", "---\n", "\n", "Important Reminder: Google Colab imposes a maximum session time to prevent extended GPU usage, such as for data mining. Ensure your training duration stays under 12 hours. If your training is projected to exceed this limit, consider reducing the `number_of_epochs`." - ], - "metadata": { - "id": "arWhMU6aKsri" - } + ] }, { "cell_type": "markdown", + "metadata": { + "id": "L59J90S_Kva3" + }, "source": [ "## **4.1. Initialize the config**\n", "---" - ], - "metadata": { - "id": "L59J90S_Kva3" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "YOgLyUwPjvUX" + }, + "outputs": [], "source": [ "# @title\n", "train_data_folder = Path(training_source)\n", @@ -463,36 +451,110 @@ " mode=\"disabled\" if not WANDB_INSTALLED else \"online\",\n", " save_model_artifact=False,\n", ")" - ], - "metadata": { - "id": "YOgLyUwPjvUX" - }, - "execution_count": null, - "outputs": [] + ] }, { "cell_type": "markdown", + "metadata": { + "id": "idowGpeQPIm2" + }, "source": [ "## **4.2. Start training**\n", "---" - ], - "metadata": { - "id": "idowGpeQPIm2" - } + ] }, { "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "OXxKZhGMqguz" + }, + "outputs": [], "source": [ "# @title\n", "worker = c.get_colab_worker(worker_config=train_config, wandb_config=wandb_config)\n", "for epoch_loss in worker.train():\n", " continue" - ], - "metadata": { - "id": "OXxKZhGMqguz" - }, + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Once you are done training, you will get a .pth file in the model folder you specified.\n", + "from tiffffile import imread\n", + "from napari_cellseg3d.dev_scripts import remote_inference as cs3d\n", + "from napari_cellseg3d.config import InferenceWorkerConfig, ModelInfo, WeightsInfo, PostProcessConfig, InstanceSegConfig\n", + "from napari_cellseg3d.code_models.instance_segmentation import VoronoiOtsu\n", + "# Add image path below\n", + "demo_image_path = \"/content/CellSeg3D/examples/c5image.tif\"\n", + "demo_image = imread(demo_image_path)\n", + "inference_config = InferenceWorkerConfig(\n", + " device=\"cuda:0\",\n", + " model_info=ModelInfo(\n", + " name=\"WNet3D\",\n", + " num_classes=2,\n", + " ),\n", + " weights_config=WeightsInfo(\n", + " path=\"./path/to/your/model.pth\",\n", + " use_custom=True,\n", + " ),\n", + " results_path=\"./results\",\n", + ")\n", + "\n", + "# select cle device for colab\n", + "import pyclesperanto_prototype as cle\n", + "cle.select_device(\"cupy\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "result = cs3d.inference_on_images(\n", + " demo_image,\n", + " config=inference_config,\n", + ")" + ] + }, + { + "cell_type": "code", "execution_count": null, - "outputs": [] + "metadata": {}, + "outputs": [], + "source": [ + "semantic = result.semantic_segmentation\n", + "\n", + "# Save the prediction\n", + "from tifffile import imwrite\n", + "dataset = \"Current dataset here...\"\n", + "imwrite(f\"{dataset}_raw_pred.tif\", semantic)\n", + "\n", + "# This should net you the raw prediction to use in the notebooks for plots\n", + "# To make the plots and post-processing, see https://github.com/C-Achard/cellseg3d-figures/blob/main/figures/FIgure3/self-supervised-extra.ipynb\n", + "# To find threshold value, I recommend the scripts in https://github.com/C-Achard/cellseg3d-figures/blob/main/thresholds_opti/wnet_find_thresholds.ipynb\n" + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "gpuType": "T4", + "include_colab_link": true, + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" } - ] + }, + "nbformat": 4, + "nbformat_minor": 0 } From 981b330cc5f799282cfa7354f85f080d8648d952 Mon Sep 17 00:00:00 2001 From: C-Achard Date: Sat, 21 Dec 2024 11:07:38 +0100 Subject: [PATCH 02/33] Refactor model save name path + comment wandb cell --- notebooks/Colab_WNet3D_training.ipynb | 1032 ++++++++++++------------- 1 file changed, 483 insertions(+), 549 deletions(-) diff --git a/notebooks/Colab_WNet3D_training.ipynb b/notebooks/Colab_WNet3D_training.ipynb index 3aa52f46..cd9f7855 100644 --- a/notebooks/Colab_WNet3D_training.ipynb +++ b/notebooks/Colab_WNet3D_training.ipynb @@ -1,560 +1,494 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "colab_type": "text", - "id": "view-in-github" - }, - "source": [ - "\"Open" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "BTUVNXX7R3Go" - }, - "source": [ - "# **WNet3D: self-supervised 3D cell segmentation**\n", - "\n", - "---\n", - "\n", - "This notebook is part of the [CellSeg3D project](https://github.com/AdaptiveMotorControlLab/CellSeg3d) in the [Mathis Lab of Adaptive Intelligence](https://www.mackenziemathislab.org/).\n", - "\n", - "- 💜 The foundation of this notebook owes much to the **[ZeroCostDL4Mic](https://github.com/HenriquesLab/ZeroCostDL4Mic)** project and to the **[DeepLabCut](https://github.com/DeepLabCut/DeepLabCut)** team for bringing Colab into scientific open software." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "zmVCksV0EfVT" - }, - "source": [ - "#**1. Installing dependencies**\n", - "---" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "td_vf_pneSak" - }, - "outputs": [], - "source": [ - "#@markdown ##Play to install WNet dependencies\n", - "!pip install napari-cellseg3d" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "nqctRognFGDT" - }, - "source": [ - "##**1.2 Load key dependencies**\n", - "---" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "wOOhJjkxjXz-", - "outputId": "8f94416d-a482-4ec6-f980-a728e908d90d" - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO:napari_cellseg3d.utils:wandb not installed, wandb config will not be taken into account\n", - "WARNING:napari_cellseg3d.utils:wandb not installed, wandb config will not be taken into account\n" - ] - } - ], - "source": [ - "# @title\n", - "from pathlib import Path\n", - "from napari_cellseg3d.dev_scripts import colab_training as c\n", - "from napari_cellseg3d.config import WNetTrainingWorkerConfig, WandBConfig, WeightsInfo, PRETRAINED_WEIGHTS_DIR" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Ax-vJAWRwIKi" - }, - "source": [ - "## (optional) **1.3 Initialize Weights & Biases integration **\n", - "---\n", - "If you wish to utilize Weights & Biases (WandB) for monitoring and logging your training session, execute the cell below.\n", - "To enable it, just input your API key in the space provided." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "QNgC3awjwb7G" - }, - "outputs": [], - "source": [ - "!pip install -q wandb\n", - "import wandb\n", - "wandb.login()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Zi9gRBHFFyX-" - }, - "source": [ - "# **2. Complete the Colab session**\n", - "---\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "zSU-LYTfFnvF" - }, - "source": [ - "\n", - "## **2.1. Check for GPU access**\n", - "---\n", - "\n", - "By default, this session is configured to use Python 3 and GPU acceleration. To verify or adjust these settings:\n", - "\n", - "Navigate to Runtime and select Change the Runtime type.\n", - "\n", - "For Runtime type, ensure it's set to Python 3 (the programming language this program is written in).\n", - "\n", - "Under Accelerator, choose GPU (Graphics Processing Unit).\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "Ie7bXiMgFtPH", - "outputId": "3276444c-5109-47b4-f507-ea9acaab15ad" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "You have GPU access\n", - "Fri May 3 17:19:13 2024 \n", - "+---------------------------------------------------------------------------------------+\n", - "| NVIDIA-SMI 535.104.05 Driver Version: 535.104.05 CUDA Version: 12.2 |\n", - "|-----------------------------------------+----------------------+----------------------+\n", - "| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |\n", - "| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |\n", - "| | | MIG M. |\n", - "|=========================================+======================+======================|\n", - "| 0 Tesla T4 Off | 00000000:00:04.0 Off | 0 |\n", - "| N/A 50C P8 10W / 70W | 3MiB / 15360MiB | 0% Default |\n", - "| | | N/A |\n", - "+-----------------------------------------+----------------------+----------------------+\n", - " \n", - "+---------------------------------------------------------------------------------------+\n", - "| Processes: |\n", - "| GPU GI CI PID Type Process name GPU Memory |\n", - "| ID ID Usage |\n", - "|=======================================================================================|\n", - "| No running processes found |\n", - "+---------------------------------------------------------------------------------------+\n" - ] - } - ], - "source": [ - "#@markdown ##Execute the cell below to verify if GPU access is available.\n", - "\n", - "import torch\n", - "if not torch.cuda.is_available():\n", - " print('You do not have GPU access.')\n", - " print('Did you change your runtime?')\n", - " print('If the runtime setting is correct then Google did not allocate a GPU for your session')\n", - " print('Expect slow performance. To access GPU try reconnecting later')\n", - "\n", - "else:\n", - " print('You have GPU access')\n", - " !nvidia-smi\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "X_bbk7RAF2yw" - }, - "source": [ - "## **2.2. Mount Google Drive**\n", - "---\n", - "To integrate this notebook with your personal data, save your data on Google Drive in accordance with the directory structures detailed in Section 0.\n", - "\n", - "1. **Run** the **cell** below and click on the provided link.\n", - "\n", - "2. Log in to your Google account and grant the necessary permissions by clicking 'Allow'.\n", - "\n", - "3. Copy the generated authorization code and paste it into the cell, then press 'Enter'. This grants Colab access to read and write data to your Google Drive.\n", - "\n", - "4. After completion, you can view your data in the notebook. Simply click the Files tab on the top left and select 'Refresh'." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "AsIARCablq1V", - "outputId": "77ffdbd1-4c89-4a56-e3da-7777a607a328" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Mounted at /content/gdrive\n" - ] - } - ], - "source": [ - "# mount user's Google Drive to Google Colab.\n", - "from google.colab import drive\n", - "drive.mount('/content/gdrive')" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "r6FI22lkQLTv" - }, - "source": [ - "** If you cannot see your files, reactivate your session by connecting to your hosted runtime.**\n", - "\n", - "\n", - "\"Example
Connect to a hosted runtime.
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "EtsK08ECwlnJ" - }, - "outputs": [], - "source": [ - "# @title\n", - "# import wandb\n", - "# wandb.login()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "IkOpxYjaGM0m" - }, - "source": [ - "# **3. Select your parameters and paths**\n", - "---" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "65FhTkYlGKRt" - }, - "source": [ - "## **3.1. Choosing parameters**\n", - "\n", - "---\n", - "\n", - "### **Paths to the training data and model**\n", - "\n", - "* **`training_source`** specifies the paths to the training data. They must be a single multipage TIF file each\n", - "\n", - "* **`model_path`** specifies the directory where the model checkpoints will be saved.\n", - "\n", - "**Tip:** To easily copy paths, navigate to the 'Files' tab, right-click on a folder or file, and choose 'Copy path'.\n", - "\n", - "### **Training parameters**\n", - "\n", - "* **`number_of_epochs`** is the number of times the entire training data will be seen by the model. Default: 50\n", - "\n", - "* **`batchs_size`** is the number of image that will be bundled together at each training step. Default: 4\n", - "\n", - "* **`learning_rate`** is the step size of the update of the model's weight. Try decreasing it if the NCuts loss is unstable. Default: 2e-5\n", - "\n", - "* **`num_classes`** is the number of brightness clusters to segment the image in. Try raising it to 3 if you have artifacts or \"halos\" around your cells that have significantly different brightness. Default: 2\n", - "\n", - "* **`weight_decay`** is a regularization parameter used to prevent overfitting. Default: 0.01\n", - "\n", - "* **`validation_frequency`** is the frequency at which the provided evaluation data is used to estimate the model's performance.\n", - "\n", - "* **`intensity_sigma`** is the standard deviation of the feature similarity term. Default: 1\n", - "\n", - "* **`spatial_sigma`** is the standard deviation of the spatial proximity term. Default: 4\n", - "\n", - "* **`ncuts_radius`** is the radius for the NCuts loss computation, in pixels. Default: 2\n", - "\n", - "* **`rec_loss`** is the loss to use for the decoder. Can be Mean Square Error (MSE) or Binary Cross Entropy (BCE). Default : MSE\n", - "\n", - "* **`n_cuts_weight`** is the weight of the NCuts loss in the weighted sum for the backward pass. Default: 0.5\n", - "* **`rec_loss_weight`** is the weight of the reconstruction loss. Default: 0.005\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "cellView": "form", - "id": "tTSCC6ChGuuA" - }, - "outputs": [], - "source": [ - "#@markdown ###Path to the training data:\n", - "training_source = \"./gdrive/MyDrive/CELLSEG_BENCHMARK/DATA/WNET/VIP_full\" #@param {type:\"string\"}\n", - "#@markdown ###Model name and path to model folder:\n", - "model_path = \"./gdrive/MyDrive/CELLSEG_BENCHMARK/WNET_TRAINING_RESULTS\" #@param {type:\"string\"}\n", - "#@markdown ---\n", - "#@markdown ###Perform validation on a test dataset\n", - "do_validation = False #@param {type:\"boolean\"}\n", - "#@markdown ###Path to evaluation data (optional, use if checked above):\n", - "eval_source = \"./gdrive/MyDrive/CELLSEG_BENCHMARK/DATA/WNET/eval/vol/\" #@param {type:\"string\"}\n", - "eval_target = \"./gdrive/MyDrive/CELLSEG_BENCHMARK/DATA/WNET/eval/lab/\" #@param {type:\"string\"}\n", - "#@markdown ---\n", - "#@markdown ###Training parameters\n", - "number_of_epochs = 50 #@param {type:\"number\"}\n", - "#@markdown ###Default advanced parameters\n", - "use_default_advanced_parameters = False #@param {type:\"boolean\"}\n", - "#@markdown If not, please change:\n", - "\n", - "#@markdown Training parameters:\n", - "batch_size = 4 #@param {type:\"number\"}\n", - "learning_rate = 2e-5 #@param {type:\"number\"}\n", - "num_classes = 2 #@param {type:\"number\"}\n", - "weight_decay = 0.01 #@param {type:\"number\"}\n", - "#@markdown Validation parameters:\n", - "validation_frequency = 2 #@param {type:\"number\"}\n", - "#@markdown SoftNCuts parameters:\n", - "intensity_sigma = 1.0 #@param {type:\"number\"}\n", - "spatial_sigma = 4.0 #@param {type:\"number\"}\n", - "ncuts_radius = 2 #@param {type:\"number\"}\n", - "#@markdown Reconstruction loss:\n", - "rec_loss = \"MSE\" #@param[\"MSE\", \"BCE\"]\n", - "#@markdown Weighted sum of losses:\n", - "n_cuts_weight = 0.5 #@param {type:\"number\"}\n", - "rec_loss_weight = 0.005 #@param {type:\"number\"}" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "HtoIo5GcKIXX" - }, - "source": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "arWhMU6aKsri" - }, - "source": [ - "# **4. Train the network**\n", - "---\n", - "\n", - "Important Reminder: Google Colab imposes a maximum session time to prevent extended GPU usage, such as for data mining. Ensure your training duration stays under 12 hours. If your training is projected to exceed this limit, consider reducing the `number_of_epochs`." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "L59J90S_Kva3" - }, - "source": [ - "## **4.1. Initialize the config**\n", - "---" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "YOgLyUwPjvUX" - }, - "outputs": [], - "source": [ - "# @title\n", - "train_data_folder = Path(training_source)\n", - "results_path = Path(model_path)\n", - "results_path.mkdir(exist_ok=True)\n", - "eval_image_folder = Path(eval_source)\n", - "eval_label_folder = Path(eval_target)\n", - "\n", - "eval_dict = c.create_eval_dataset_dict(\n", - " eval_image_folder,\n", - " eval_label_folder,\n", - " ) if do_validation else None\n", - "\n", - "try:\n", - " import wandb\n", - " WANDB_INSTALLED = True\n", - "except ImportError:\n", - " WANDB_INSTALLED = False\n", - "\n", - "\n", - "train_config = WNetTrainingWorkerConfig(\n", - " device=\"cuda:0\",\n", - " max_epochs=number_of_epochs,\n", - " learning_rate=2e-5,\n", - " validation_interval=2,\n", - " batch_size=4,\n", - " num_workers=2,\n", - " weights_info=WeightsInfo(),\n", - " results_path_folder=str(results_path),\n", - " train_data_dict=c.create_dataset_dict_no_labs(train_data_folder),\n", - " eval_volume_dict=eval_dict,\n", - ") if use_default_advanced_parameters else WNetTrainingWorkerConfig(\n", - " device=\"cuda:0\",\n", - " max_epochs=number_of_epochs,\n", - " learning_rate=learning_rate,\n", - " validation_interval=validation_frequency,\n", - " batch_size=batch_size,\n", - " num_workers=2,\n", - " weights_info=WeightsInfo(),\n", - " results_path_folder=str(results_path),\n", - " train_data_dict=c.create_dataset_dict_no_labs(train_data_folder),\n", - " eval_volume_dict=eval_dict,\n", - " # advanced\n", - " num_classes=num_classes,\n", - " weight_decay=weight_decay,\n", - " intensity_sigma=intensity_sigma,\n", - " spatial_sigma=spatial_sigma,\n", - " radius=ncuts_radius,\n", - " reconstruction_loss=rec_loss,\n", - " n_cuts_weight=n_cuts_weight,\n", - " rec_loss_weight=rec_loss_weight,\n", - ")\n", - "wandb_config = WandBConfig(\n", - " mode=\"disabled\" if not WANDB_INSTALLED else \"online\",\n", - " save_model_artifact=False,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "idowGpeQPIm2" - }, - "source": [ - "## **4.2. Start training**\n", - "---" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "id": "OXxKZhGMqguz" - }, - "outputs": [], - "source": [ - "# @title\n", - "worker = c.get_colab_worker(worker_config=train_config, wandb_config=wandb_config)\n", - "for epoch_loss in worker.train():\n", - " continue" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Once you are done training, you will get a .pth file in the model folder you specified.\n", - "from tiffffile import imread\n", - "from napari_cellseg3d.dev_scripts import remote_inference as cs3d\n", - "from napari_cellseg3d.config import InferenceWorkerConfig, ModelInfo, WeightsInfo, PostProcessConfig, InstanceSegConfig\n", - "from napari_cellseg3d.code_models.instance_segmentation import VoronoiOtsu\n", - "# Add image path below\n", - "demo_image_path = \"/content/CellSeg3D/examples/c5image.tif\"\n", - "demo_image = imread(demo_image_path)\n", - "inference_config = InferenceWorkerConfig(\n", - " device=\"cuda:0\",\n", - " model_info=ModelInfo(\n", - " name=\"WNet3D\",\n", - " num_classes=2,\n", - " ),\n", - " weights_config=WeightsInfo(\n", - " path=\"./path/to/your/model.pth\",\n", - " use_custom=True,\n", - " ),\n", - " results_path=\"./results\",\n", - ")\n", - "\n", - "# select cle device for colab\n", - "import pyclesperanto_prototype as cle\n", - "cle.select_device(\"cupy\")" - ] + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "colab_type": "text", + "id": "view-in-github" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BTUVNXX7R3Go" + }, + "source": [ + "# **WNet3D: self-supervised 3D cell segmentation**\n", + "\n", + "---\n", + "\n", + "This notebook is part of the [CellSeg3D project](https://github.com/AdaptiveMotorControlLab/CellSeg3d) in the [Mathis Lab of Adaptive Intelligence](https://www.mackenziemathislab.org/).\n", + "\n", + "- 💜 The foundation of this notebook owes much to the **[ZeroCostDL4Mic](https://github.com/HenriquesLab/ZeroCostDL4Mic)** project and to the **[DeepLabCut](https://github.com/DeepLabCut/DeepLabCut)** team for bringing Colab into scientific open software." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zmVCksV0EfVT" + }, + "source": [ + "#**1. Installing dependencies**\n", + "---" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "td_vf_pneSak" + }, + "outputs": [], + "source": [ + "#@markdown ##Play to install WNet dependencies\n", + "!pip install napari-cellseg3d" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "nqctRognFGDT" + }, + "source": [ + "##**1.2 Load key dependencies**\n", + "---" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "wOOhJjkxjXz-", + "outputId": "8f94416d-a482-4ec6-f980-a728e908d90d" + }, + "outputs": [ { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "result = cs3d.inference_on_images(\n", - " demo_image,\n", - " config=inference_config,\n", - ")" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:napari_cellseg3d.utils:wandb not installed, wandb config will not be taken into account\n", + "WARNING:napari_cellseg3d.utils:wandb not installed, wandb config will not be taken into account\n" + ] + } + ], + "source": [ + "# @title\n", + "from pathlib import Path\n", + "from napari_cellseg3d.dev_scripts import colab_training as c\n", + "from napari_cellseg3d.config import WNetTrainingWorkerConfig, WandBConfig, WeightsInfo, PRETRAINED_WEIGHTS_DIR" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Ax-vJAWRwIKi" + }, + "source": [ + "## (optional) **1.3 Initialize Weights & Biases integration **\n", + "---\n", + "If you wish to utilize Weights & Biases (WandB) for monitoring and logging your training session, execute the cell below.\n", + "To enable it, just input your API key in the space provided." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "QNgC3awjwb7G" + }, + "outputs": [], + "source": [ + "# !pip install -q wandb\n", + "# import wandb\n", + "# wandb.login()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Zi9gRBHFFyX-" + }, + "source": [ + "# **2. Complete the Colab session**\n", + "---\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zSU-LYTfFnvF" + }, + "source": [ + "\n", + "## **2.1. Check for GPU access**\n", + "---\n", + "\n", + "By default, this session is configured to use Python 3 and GPU acceleration. To verify or adjust these settings:\n", + "\n", + "Navigate to Runtime and select Change the Runtime type.\n", + "\n", + "For Runtime type, ensure it's set to Python 3 (the programming language this program is written in).\n", + "\n", + "Under Accelerator, choose GPU (Graphics Processing Unit).\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "Ie7bXiMgFtPH", + "outputId": "3276444c-5109-47b4-f507-ea9acaab15ad" + }, + "outputs": [ { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "semantic = result.semantic_segmentation\n", - "\n", - "# Save the prediction\n", - "from tifffile import imwrite\n", - "dataset = \"Current dataset here...\"\n", - "imwrite(f\"{dataset}_raw_pred.tif\", semantic)\n", - "\n", - "# This should net you the raw prediction to use in the notebooks for plots\n", - "# To make the plots and post-processing, see https://github.com/C-Achard/cellseg3d-figures/blob/main/figures/FIgure3/self-supervised-extra.ipynb\n", - "# To find threshold value, I recommend the scripts in https://github.com/C-Achard/cellseg3d-figures/blob/main/thresholds_opti/wnet_find_thresholds.ipynb\n" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "You have GPU access\n", + "Fri May 3 17:19:13 2024 \n", + "+---------------------------------------------------------------------------------------+\n", + "| NVIDIA-SMI 535.104.05 Driver Version: 535.104.05 CUDA Version: 12.2 |\n", + "|-----------------------------------------+----------------------+----------------------+\n", + "| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |\n", + "| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |\n", + "| | | MIG M. |\n", + "|=========================================+======================+======================|\n", + "| 0 Tesla T4 Off | 00000000:00:04.0 Off | 0 |\n", + "| N/A 50C P8 10W / 70W | 3MiB / 15360MiB | 0% Default |\n", + "| | | N/A |\n", + "+-----------------------------------------+----------------------+----------------------+\n", + " \n", + "+---------------------------------------------------------------------------------------+\n", + "| Processes: |\n", + "| GPU GI CI PID Type Process name GPU Memory |\n", + "| ID ID Usage |\n", + "|=======================================================================================|\n", + "| No running processes found |\n", + "+---------------------------------------------------------------------------------------+\n" + ] } - ], - "metadata": { - "accelerator": "GPU", + ], + "source": [ + "#@markdown ##Execute the cell below to verify if GPU access is available.\n", + "\n", + "import torch\n", + "if not torch.cuda.is_available():\n", + " print('You do not have GPU access.')\n", + " print('Did you change your runtime?')\n", + " print('If the runtime setting is correct then Google did not allocate a GPU for your session')\n", + " print('Expect slow performance. To access GPU try reconnecting later')\n", + "\n", + "else:\n", + " print('You have GPU access')\n", + " !nvidia-smi\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "X_bbk7RAF2yw" + }, + "source": [ + "## **2.2. Mount Google Drive**\n", + "---\n", + "To integrate this notebook with your personal data, save your data on Google Drive in accordance with the directory structures detailed in Section 0.\n", + "\n", + "1. **Run** the **cell** below and click on the provided link.\n", + "\n", + "2. Log in to your Google account and grant the necessary permissions by clicking 'Allow'.\n", + "\n", + "3. Copy the generated authorization code and paste it into the cell, then press 'Enter'. This grants Colab access to read and write data to your Google Drive.\n", + "\n", + "4. After completion, you can view your data in the notebook. Simply click the Files tab on the top left and select 'Refresh'." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { "colab": { - "gpuType": "T4", - "include_colab_link": true, - "provenance": [] + "base_uri": "https://localhost:8080/" }, - "kernelspec": { - "display_name": "Python 3", - "name": "python3" - }, - "language_info": { - "name": "python" + "id": "AsIARCablq1V", + "outputId": "77ffdbd1-4c89-4a56-e3da-7777a607a328" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Mounted at /content/gdrive\n" + ] } + ], + "source": [ + "# mount user's Google Drive to Google Colab.\n", + "from google.colab import drive\n", + "drive.mount('/content/gdrive')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "r6FI22lkQLTv" + }, + "source": [ + "** If you cannot see your files, reactivate your session by connecting to your hosted runtime.**\n", + "\n", + "\n", + "\"Example
Connect to a hosted runtime.
" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IkOpxYjaGM0m" + }, + "source": [ + "# **3. Select your parameters and paths**\n", + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "65FhTkYlGKRt" + }, + "source": [ + "## **3.1. Choosing parameters**\n", + "\n", + "---\n", + "\n", + "### **Paths to the training data and model**\n", + "\n", + "* **`training_source`** specifies the paths to the training data. They must be a single multipage TIF file each\n", + "\n", + "* **`model_save_path`** specifies the directory where the model checkpoints will be saved.\n", + "\n", + "**Tip:** To easily copy paths, navigate to the 'Files' tab, right-click on a folder or file, and choose 'Copy path'.\n", + "\n", + "### **Training parameters**\n", + "\n", + "* **`number_of_epochs`** is the number of times the entire training data will be seen by the model. Default: 50\n", + "\n", + "* **`batchs_size`** is the number of image that will be bundled together at each training step. Default: 4\n", + "\n", + "* **`learning_rate`** is the step size of the update of the model's weight. Try decreasing it if the NCuts loss is unstable. Default: 2e-5\n", + "\n", + "* **`num_classes`** is the number of brightness clusters to segment the image in. Try raising it to 3 if you have artifacts or \"halos\" around your cells that have significantly different brightness. Default: 2\n", + "\n", + "* **`weight_decay`** is a regularization parameter used to prevent overfitting. Default: 0.01\n", + "\n", + "* **`validation_frequency`** is the frequency at which the provided evaluation data is used to estimate the model's performance.\n", + "\n", + "* **`intensity_sigma`** is the standard deviation of the feature similarity term. Default: 1\n", + "\n", + "* **`spatial_sigma`** is the standard deviation of the spatial proximity term. Default: 4\n", + "\n", + "* **`ncuts_radius`** is the radius for the NCuts loss computation, in pixels. Default: 2\n", + "\n", + "* **`rec_loss`** is the loss to use for the decoder. Can be Mean Square Error (MSE) or Binary Cross Entropy (BCE). Default : MSE\n", + "\n", + "* **`n_cuts_weight`** is the weight of the NCuts loss in the weighted sum for the backward pass. Default: 0.5\n", + "* **`rec_loss_weight`** is the weight of the reconstruction loss. Default: 0.005\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "cellView": "form", + "id": "tTSCC6ChGuuA" + }, + "outputs": [], + "source": [ + "#@markdown ###Path to the training data:\n", + "training_source = \"./gdrive/MyDrive/CELLSEG_BENCHMARK/DATA/WNET/VIP_full\" #@param {type:\"string\"}\n", + "#@markdown ###Model name and path to model folder:\n", + "model_save_path = \"./gdrive/MyDrive/CELLSEG_BENCHMARK/WNET_TRAINING_RESULTS\" #@param {type:\"string\"}\n", + "#@markdown ---\n", + "#@markdown ###Perform validation on a test dataset\n", + "do_validation = False #@param {type:\"boolean\"}\n", + "#@markdown ###Path to evaluation data (optional, use if checked above):\n", + "eval_source = \"./gdrive/MyDrive/CELLSEG_BENCHMARK/DATA/WNET/eval/vol/\" #@param {type:\"string\"}\n", + "eval_target = \"./gdrive/MyDrive/CELLSEG_BENCHMARK/DATA/WNET/eval/lab/\" #@param {type:\"string\"}\n", + "#@markdown ---\n", + "#@markdown ###Training parameters\n", + "number_of_epochs = 50 #@param {type:\"number\"}\n", + "#@markdown ###Default advanced parameters\n", + "use_default_advanced_parameters = False #@param {type:\"boolean\"}\n", + "#@markdown If not, please change:\n", + "\n", + "#@markdown Training parameters:\n", + "batch_size = 4 #@param {type:\"number\"}\n", + "learning_rate = 2e-5 #@param {type:\"number\"}\n", + "num_classes = 2 #@param {type:\"number\"}\n", + "weight_decay = 0.01 #@param {type:\"number\"}\n", + "#@markdown Validation parameters:\n", + "validation_frequency = 2 #@param {type:\"number\"}\n", + "#@markdown SoftNCuts parameters:\n", + "intensity_sigma = 1.0 #@param {type:\"number\"}\n", + "spatial_sigma = 4.0 #@param {type:\"number\"}\n", + "ncuts_radius = 2 #@param {type:\"number\"}\n", + "#@markdown Reconstruction loss:\n", + "rec_loss = \"MSE\" #@param[\"MSE\", \"BCE\"]\n", + "#@markdown Weighted sum of losses:\n", + "n_cuts_weight = 0.5 #@param {type:\"number\"}\n", + "rec_loss_weight = 0.005 #@param {type:\"number\"}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HtoIo5GcKIXX" + }, + "source": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "arWhMU6aKsri" + }, + "source": [ + "# **4. Train the network**\n", + "---\n", + "\n", + "Important Reminder: Google Colab imposes a maximum session time to prevent extended GPU usage, such as for data mining. Ensure your training duration stays under 12 hours. If your training is projected to exceed this limit, consider reducing the `number_of_epochs`." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "L59J90S_Kva3" + }, + "source": [ + "## **4.1. Initialize the config**\n", + "---" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "YOgLyUwPjvUX" + }, + "outputs": [], + "source": [ + "# @title\n", + "train_data_folder = Path(training_source)\n", + "results_path = Path(model_save_path)\n", + "results_path.mkdir(exist_ok=True)\n", + "eval_image_folder = Path(eval_source)\n", + "eval_label_folder = Path(eval_target)\n", + "\n", + "eval_dict = c.create_eval_dataset_dict(\n", + " eval_image_folder,\n", + " eval_label_folder,\n", + " ) if do_validation else None\n", + "\n", + "try:\n", + " import wandb\n", + " WANDB_INSTALLED = True\n", + "except ImportError:\n", + " WANDB_INSTALLED = False\n", + "\n", + "\n", + "train_config = WNetTrainingWorkerConfig(\n", + " device=\"cuda:0\",\n", + " max_epochs=number_of_epochs,\n", + " learning_rate=2e-5,\n", + " validation_interval=2,\n", + " batch_size=4,\n", + " num_workers=2,\n", + " weights_info=WeightsInfo(),\n", + " results_path_folder=str(results_path),\n", + " train_data_dict=c.create_dataset_dict_no_labs(train_data_folder),\n", + " eval_volume_dict=eval_dict,\n", + ") if use_default_advanced_parameters else WNetTrainingWorkerConfig(\n", + " device=\"cuda:0\",\n", + " max_epochs=number_of_epochs,\n", + " learning_rate=learning_rate,\n", + " validation_interval=validation_frequency,\n", + " batch_size=batch_size,\n", + " num_workers=2,\n", + " weights_info=WeightsInfo(),\n", + " results_path_folder=str(results_path),\n", + " train_data_dict=c.create_dataset_dict_no_labs(train_data_folder),\n", + " eval_volume_dict=eval_dict,\n", + " # advanced\n", + " num_classes=num_classes,\n", + " weight_decay=weight_decay,\n", + " intensity_sigma=intensity_sigma,\n", + " spatial_sigma=spatial_sigma,\n", + " radius=ncuts_radius,\n", + " reconstruction_loss=rec_loss,\n", + " n_cuts_weight=n_cuts_weight,\n", + " rec_loss_weight=rec_loss_weight,\n", + ")\n", + "wandb_config = WandBConfig(\n", + " mode=\"disabled\" if not WANDB_INSTALLED else \"online\",\n", + " save_model_artifact=False,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "idowGpeQPIm2" + }, + "source": [ + "## **4.2. Start training**\n", + "---" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "OXxKZhGMqguz" + }, + "outputs": [], + "source": [ + "# @title\n", + "worker = c.get_colab_worker(worker_config=train_config, wandb_config=wandb_config)\n", + "for epoch_loss in worker.train():\n", + " continue" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Once you have trained the model, you will have the weights as a .pth file" + ] + } + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "gpuType": "T4", + "include_colab_link": true, + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" }, - "nbformat": 4, - "nbformat_minor": 0 + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 0 } From c201a0e82ac139d3288105a7b6fa6a12f0191563 Mon Sep 17 00:00:00 2001 From: C-Achard Date: Sat, 21 Dec 2024 11:30:00 +0100 Subject: [PATCH 03/33] Update Colab_WNet3D_training.ipynb --- notebooks/Colab_WNet3D_training.ipynb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/notebooks/Colab_WNet3D_training.ipynb b/notebooks/Colab_WNet3D_training.ipynb index cd9f7855..3e2685e4 100644 --- a/notebooks/Colab_WNet3D_training.ipynb +++ b/notebooks/Colab_WNet3D_training.ipynb @@ -44,7 +44,8 @@ "outputs": [], "source": [ "#@markdown ##Play to install WNet dependencies\n", - "!pip install napari-cellseg3d" + "!pip install -q napari-cellseg3d\n", + "print(\"Dependencies installed\")" ] }, { @@ -92,7 +93,7 @@ "source": [ "## (optional) **1.3 Initialize Weights & Biases integration **\n", "---\n", - "If you wish to utilize Weights & Biases (WandB) for monitoring and logging your training session, execute the cell below.\n", + "If you wish to utilize Weights & Biases (WandB) for monitoring and logging your training session, uncomment and execute the cell below.\n", "To enable it, just input your API key in the space provided." ] }, From c199b5f150dadea67f14bf71bf760db7ce965f4e Mon Sep 17 00:00:00 2001 From: C-Achard Date: Sat, 21 Dec 2024 11:40:37 +0100 Subject: [PATCH 04/33] Improve logging in Colab --- .../dev_scripts/colab_training.py | 30 ++++++++++++++++++- notebooks/Colab_WNet3D_training.ipynb | 2 +- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/napari_cellseg3d/dev_scripts/colab_training.py b/napari_cellseg3d/dev_scripts/colab_training.py index ce30d013..b99ff9f7 100644 --- a/napari_cellseg3d/dev_scripts/colab_training.py +++ b/napari_cellseg3d/dev_scripts/colab_training.py @@ -1,4 +1,5 @@ """Script to run WNet training in Google Colab.""" + import time from pathlib import Path @@ -55,7 +56,28 @@ ) WANDB_INSTALLED = False -# TODO subclass to reduce code duplication + +class LogFixture: + """Fixture for napari-less logging, replaces napari_cellseg3d.interface.Log in model_workers. + + This allows to redirect the output of the workers to stdout instead of a specialized widget. + """ + + def __init__(self): + """Creates a LogFixture object.""" + super(LogFixture, self).__init__() + + def print_and_log(self, text, printing=None): + """Prints and logs text.""" + print(text) + + def warn(self, warning): + """Logs warning.""" + logger.warning(warning) + + def error(self, e): + """Logs error.""" + raise (e) class WNetTrainingWorkerColab(TrainingWorkerBase): @@ -728,8 +750,14 @@ def get_colab_worker( worker_config (config.WNetTrainingWorkerConfig): config for the training worker wandb_config (config.WandBConfig): config for wandb """ + log = LogFixture() worker = WNetTrainingWorkerColab(worker_config) worker.wandb_config = wandb_config + + worker.log_signal.connect(log.print_and_log) + worker.warn_signal.connect(log.warn) + worker.error_signal.connect(log.error) + return worker diff --git a/notebooks/Colab_WNet3D_training.ipynb b/notebooks/Colab_WNet3D_training.ipynb index 3e2685e4..c8622701 100644 --- a/notebooks/Colab_WNet3D_training.ipynb +++ b/notebooks/Colab_WNet3D_training.ipynb @@ -91,7 +91,7 @@ "id": "Ax-vJAWRwIKi" }, "source": [ - "## (optional) **1.3 Initialize Weights & Biases integration **\n", + "## Optional - *1.3 Initialize Weights & Biases integration*\n", "---\n", "If you wish to utilize Weights & Biases (WandB) for monitoring and logging your training session, uncomment and execute the cell below.\n", "To enable it, just input your API key in the space provided." From 6a42d26abc544bd3f4668dce07fc274c79dadeee Mon Sep 17 00:00:00 2001 From: C-Achard Date: Sat, 21 Dec 2024 11:48:18 +0100 Subject: [PATCH 05/33] Subclass WnetTraininWorker to avoid duplication --- .../dev_scripts/colab_training.py | 657 +----------------- 1 file changed, 6 insertions(+), 651 deletions(-) diff --git a/napari_cellseg3d/dev_scripts/colab_training.py b/napari_cellseg3d/dev_scripts/colab_training.py index b99ff9f7..a23d7396 100644 --- a/napari_cellseg3d/dev_scripts/colab_training.py +++ b/napari_cellseg3d/dev_scripts/colab_training.py @@ -2,45 +2,21 @@ import time from pathlib import Path - -import torch -import torch.nn as nn +from typing import TYPE_CHECKING # MONAI -from monai.data import ( - CacheDataset, - DataLoader, - PatchDataset, - pad_list_data_collate, -) -from monai.data.meta_obj import set_track_meta -from monai.inferers import sliding_window_inference from monai.metrics import DiceMetric -from monai.transforms import ( - AsDiscrete, - Compose, - EnsureChannelFirstd, - EnsureTyped, - LoadImaged, - Orientationd, - RandFlipd, - RandRotate90d, - RandShiftIntensityd, - RandSpatialCropSamplesd, - ScaleIntensityRanged, - SpatialPadd, -) -from monai.utils import set_determinism # local from napari_cellseg3d import config, utils -from napari_cellseg3d.code_models.models.wnet.model import WNet -from napari_cellseg3d.code_models.models.wnet.soft_Ncuts import SoftNCutsLoss -from napari_cellseg3d.code_models.worker_training import TrainingWorkerBase +from napari_cellseg3d.code_models.worker_training import WNetTrainingWorker from napari_cellseg3d.code_models.workers_utils import ( PRETRAINED_WEIGHTS_DIR, ) +if TYPE_CHECKING: + from monai.data import DataLoader + logger = utils.LOGGER VERBOSE_SCHEDULER = True logger.debug(f"PRETRAINED WEIGHT DIR LOCATION : {PRETRAINED_WEIGHTS_DIR}") @@ -80,7 +56,7 @@ def error(self, e): raise (e) -class WNetTrainingWorkerColab(TrainingWorkerBase): +class WNetTrainingWorkerColab(WNetTrainingWorker): """A custom worker to run WNet (unsupervised) training jobs in. Inherits from :py:class:`napari.qt.threading.GeneratorWorker` via :py:class:`TrainingWorkerBase`. @@ -118,627 +94,6 @@ def __init__( self.eval_dataloader: DataLoader = None self.data_shape = None - def log(self, text): - """Log a message to the logger and to wandb if installed.""" - logger.info(text) - - def get_patch_dataset(self, train_transforms): - """Creates a Dataset from the original data using the tifffile library. - - Args: - train_transforms (Compose): The transforms to apply to the data - - Returns: - (tuple): A tuple containing the shape of the data and the dataset - """ - patch_func = Compose( - [ - LoadImaged(keys=["image"], image_only=True), - EnsureChannelFirstd(keys=["image"], channel_dim="no_channel"), - RandSpatialCropSamplesd( - keys=["image"], - roi_size=( - self.config.sample_size - ), # multiply by axis_stretch_factor if anisotropy - # max_roi_size=(120, 120, 120), - random_size=False, - num_samples=self.config.num_samples, - ), - Orientationd(keys=["image"], axcodes="PLI"), - SpatialPadd( - keys=["image"], - spatial_size=( - utils.get_padding_dim(self.config.sample_size) - ), - ), - EnsureTyped(keys=["image"]), - ] - ) - dataset = PatchDataset( - data=self.config.train_data_dict, - samples_per_image=self.config.num_samples, - patch_func=patch_func, - transform=train_transforms, - ) - - return self.config.sample_size, dataset - - def get_dataset_eval(self, eval_dataset_dict): - """Creates a Dataset applying some transforms/augmentation on the data using the MONAI library.""" - eval_transforms = Compose( - [ - LoadImaged(keys=["image", "label"]), - EnsureChannelFirstd( - keys=["image", "label"], channel_dim="no_channel" - ), - # RandSpatialCropSamplesd( - # keys=["image", "label"], - # roi_size=( - # self.config.sample_size - # ), # multiply by axis_stretch_factor if anisotropy - # # max_roi_size=(120, 120, 120), - # random_size=False, - # num_samples=self.config.num_samples, - # ), - Orientationd(keys=["image", "label"], axcodes="PLI"), - # SpatialPadd( - # keys=["image", "label"], - # spatial_size=( - # utils.get_padding_dim(self.config.sample_size) - # ), - # ), - EnsureTyped(keys=["image", "label"]), - ] - ) - - return CacheDataset( - data=eval_dataset_dict, - transform=eval_transforms, - ) - - def get_dataset(self, train_transforms): - """Creates a Dataset applying some transforms/augmentation on the data using the MONAI library. - - Args: - train_transforms (Compose): The transforms to apply to the data - - Returns: - (tuple): A tuple containing the shape of the data and the dataset - """ - train_files = self.config.train_data_dict - - first_volume = LoadImaged(keys=["image"])(train_files[0]) - first_volume_shape = first_volume["image"].shape - - # Transforms to be applied to each volume - load_single_images = Compose( - [ - LoadImaged(keys=["image"]), - EnsureChannelFirstd(keys=["image"]), - Orientationd(keys=["image"], axcodes="PLI"), - SpatialPadd( - keys=["image"], - spatial_size=(utils.get_padding_dim(first_volume_shape)), - ), - EnsureTyped(keys=["image"]), - # RemapTensord(keys=["image"], new_min=0.0, new_max=100.0), - ] - ) - - # Create the dataset - dataset = CacheDataset( - data=train_files, - transform=Compose([load_single_images, train_transforms]), - ) - - return first_volume_shape, dataset - - def _get_data(self): - if self.config.do_augmentation: - train_transforms = Compose( - [ - ScaleIntensityRanged( - keys=["image"], - a_min=0, - a_max=2000, - b_min=0.0, - b_max=1.0, - clip=True, - ), - RandShiftIntensityd(keys=["image"], offsets=0.1, prob=0.5), - RandFlipd(keys=["image"], spatial_axis=[1], prob=0.5), - RandFlipd(keys=["image"], spatial_axis=[2], prob=0.5), - RandRotate90d(keys=["image"], prob=0.1, max_k=3), - EnsureTyped(keys=["image"]), - ] - ) - else: - train_transforms = EnsureTyped(keys=["image"]) - - if self.config.sampling: - logger.debug("Loading patch dataset") - (self.data_shape, dataset) = self.get_patch_dataset( - train_transforms - ) - else: - logger.debug("Loading volume dataset") - (self.data_shape, dataset) = self.get_dataset(train_transforms) - - logger.debug(f"Data shape : {self.data_shape}") - self.dataloader = DataLoader( - dataset, - batch_size=self.config.batch_size, - shuffle=True, - num_workers=self.config.num_workers, - collate_fn=pad_list_data_collate, - ) - - if self.config.eval_volume_dict is not None: - eval_dataset = self.get_dataset_eval(self.config.eval_volume_dict) - - self.eval_dataloader = DataLoader( - eval_dataset, - batch_size=self.config.batch_size, - shuffle=False, - num_workers=self.config.num_workers, - collate_fn=pad_list_data_collate, - ) - else: - self.eval_dataloader = None - return self.dataloader, self.eval_dataloader, self.data_shape - - def log_parameters(self): - """Log the parameters of the training.""" - self.log("*" * 20) - self.log("-- Parameters --") - self.log(f"Device: {self.config.device}") - self.log(f"Batch size: {self.config.batch_size}") - self.log(f"Epochs: {self.config.max_epochs}") - self.log(f"Learning rate: {self.config.learning_rate}") - self.log(f"Validation interval: {self.config.validation_interval}") - if self.config.weights_info.use_custom: - self.log(f"Custom weights: {self.config.weights_info.path}") - elif self.config.weights_info.use_pretrained: - self.log(f"Pretrained weights: {self.config.weights_info.path}") - if self.config.sampling: - self.log( - f"Using {self.config.num_samples} samples of size {self.config.sample_size}" - ) - if self.config.do_augmentation: - self.log("Using data augmentation") - ############## - self.log("-- Model --") - self.log(f"Using {self.config.num_classes} classes") - self.log(f"Weight decay: {self.config.weight_decay}") - self.log("* NCuts : ") - self.log(f"- Intensity sigma {self.config.intensity_sigma}") - self.log(f"- Spatial sigma {self.config.spatial_sigma}") - self.log(f"- Radius : {self.config.radius}") - self.log(f"* Reconstruction loss : {self.config.reconstruction_loss}") - self.log( - f"Weighted sum : {self.config.n_cuts_weight}*NCuts + {self.config.rec_loss_weight}*Reconstruction" - ) - ############## - self.log("-- Data --") - self.log("Training data :\n") - [ - self.log(f"{v}") - for d in self.config.train_data_dict - for k, v in d.items() - ] - if self.config.eval_volume_dict is not None: - self.log("\nValidation data :\n") - [ - self.log(f"{k}: {v}") - for d in self.config.eval_volume_dict - for k, v in d.items() - ] - self.log("*" * 20) - - def train( - self, provided_model=None, provided_optimizer=None, provided_loss=None - ): - """Train the model.""" - try: - if self.config is None: - self.config = config.WNetTrainingWorkerConfig() - ############## - # disable metadata tracking in MONAI - set_track_meta(False) - ############## - if WANDB_INSTALLED: - config_dict = self.config.__dict__ - logger.debug(f"wandb config : {config_dict}") - wandb.init( - config=config_dict, - project="CellSeg3D (Colab)", - name=f"WNet3D training - {utils.get_date_time()}", - mode=self.wandb_config.mode, - tags=["WNet3D", "Colab"], - ) - - set_determinism(seed=self.config.deterministic_config.seed) - torch.use_deterministic_algorithms(True, warn_only=True) - - device = self.config.device - - self.log_parameters() - self.log("Initializing training...") - self.log("- Getting the data") - - self._get_data() - - ################################################### - # Training the model # - ################################################### - self.log("- Getting the model") - # Initialize the model - model = ( - WNet( - in_channels=self.config.in_channels, - out_channels=self.config.out_channels, - num_classes=self.config.num_classes, - dropout=self.config.dropout, - ) - if provided_model is None - else provided_model - ) - model.to(device) - - if self.config.use_clipping: - for p in model.parameters(): - p.register_hook( - lambda grad: torch.clamp( - grad, - min=-self.config.clipping, - max=self.config.clipping, - ) - ) - - if WANDB_INSTALLED: - wandb.watch(model, log_freq=100) - - if self.config.weights_info.use_custom: - if self.config.weights_info.use_pretrained: - weights_file = "wnet.pth" - self.downloader.download_weights("WNet3D", weights_file) - weights = PRETRAINED_WEIGHTS_DIR / Path(weights_file) - self.config.weights_info.path = weights - else: - weights = str(Path(self.config.weights_info.path)) - - try: - model.load_state_dict( - torch.load( - weights, - map_location=self.config.device, - ), - strict=True, - ) - except RuntimeError as e: - logger.error(f"Error when loading weights : {e}") - logger.exception(e) - warn = ( - "WARNING:\nIt'd seem that the weights were incompatible with the model,\n" - "the model will be trained from random weights" - ) - self.log(warn) - self.warn(warn) - self._weight_error = True - else: - self.log("Model will be trained from scratch") - self.log("- Getting the optimizer") - # Initialize the optimizers - if self.config.weight_decay is not None: - decay = self.config.weight_decay - optimizer = torch.optim.Adam( - model.parameters(), - lr=self.config.learning_rate, - weight_decay=decay, - ) - else: - optimizer = torch.optim.Adam( - model.parameters(), lr=self.config.learning_rate - ) - if provided_optimizer is not None: - optimizer = provided_optimizer - self.log("- Getting the loss functions") - # Initialize the Ncuts loss function - criterionE = SoftNCutsLoss( - data_shape=self.data_shape, - device=device, - intensity_sigma=self.config.intensity_sigma, - spatial_sigma=self.config.spatial_sigma, - radius=self.config.radius, - ) - - if self.config.reconstruction_loss == "MSE": - criterionW = nn.MSELoss() - elif self.config.reconstruction_loss == "BCE": - criterionW = nn.BCELoss() - else: - raise ValueError( - f"Unknown reconstruction loss : {self.config.reconstruction_loss} not supported" - ) - - model.train() - - self.log("Ready") - self.log("Training the model") - self.log("*" * 20) - - # Train the model - for epoch in range(self.config.max_epochs): - self.log(f"Epoch {epoch + 1} of {self.config.max_epochs}") - - epoch_ncuts_loss = 0 - epoch_rec_loss = 0 - epoch_loss = 0 - - for _i, batch in enumerate(self.dataloader): - # raise NotImplementedError("testing") - image_batch = batch["image"].to(device) - # Normalize the image - for i in range(image_batch.shape[0]): - for j in range(image_batch.shape[1]): - image_batch[i, j] = self.normalize_function( - image_batch[i, j] - ) - - # Forward pass - enc, dec = model(image_batch) - # Compute the Ncuts loss - Ncuts = criterionE(enc, image_batch) - - epoch_ncuts_loss += Ncuts.item() - if WANDB_INSTALLED: - wandb.log({"Train/Ncuts loss": Ncuts.item()}) - - # Compute the reconstruction loss - if isinstance(criterionW, nn.MSELoss): - reconstruction_loss = criterionW(dec, image_batch) - elif isinstance(criterionW, nn.BCELoss): - reconstruction_loss = criterionW( - torch.sigmoid(dec), - utils.remap_image(image_batch, new_max=1), - ) - - epoch_rec_loss += reconstruction_loss.item() - if WANDB_INSTALLED: - wandb.log( - { - "Train/Reconstruction loss": reconstruction_loss.item() - } - ) - - # Backward pass for the reconstruction loss - optimizer.zero_grad() - alpha = self.config.n_cuts_weight - beta = self.config.rec_loss_weight - - loss = alpha * Ncuts + beta * reconstruction_loss - if provided_loss is not None: - loss = provided_loss - epoch_loss += loss.item() - - if WANDB_INSTALLED: - wandb.log( - {"Train/Weighted sum of losses": loss.item()} - ) - - loss.backward(loss) - optimizer.step() - yield epoch_loss - - self.ncuts_losses.append( - epoch_ncuts_loss / len(self.dataloader) - ) - self.rec_losses.append(epoch_rec_loss / len(self.dataloader)) - self.total_losses.append(epoch_loss / len(self.dataloader)) - - if WANDB_INSTALLED: - wandb.log({"Ncuts loss for epoch": self.ncuts_losses[-1]}) - wandb.log( - {"Reconstruction loss for epoch": self.rec_losses[-1]} - ) - wandb.log( - {"Sum of losses for epoch": self.total_losses[-1]} - ) - wandb.log( - { - "LR/Model learning rate": optimizer.param_groups[ - 0 - ]["lr"] - } - ) - - self.log(f"Ncuts loss: {self.ncuts_losses[-1]:.5f}") - self.log(f"Reconstruction loss: {self.rec_losses[-1]:.5f}") - self.log( - f"Weighted sum of losses: {self.total_losses[-1]:.5f}" - ) - if epoch > 0: - self.log( - f"Ncuts loss difference: {self.ncuts_losses[-1] - self.ncuts_losses[-2]:.5f}" - ) - self.log( - f"Reconstruction loss difference: {self.rec_losses[-1] - self.rec_losses[-2]:.5f}" - ) - self.log( - f"Weighted sum of losses difference: {self.total_losses[-1] - self.total_losses[-2]:.5f}" - ) - - if ( - self.eval_dataloader is not None - and (epoch + 1) % self.config.validation_interval == 0 - ): - model.eval() - self.log("Validating...") - self.eval(model, epoch) # validation - - eta = ( - (time.time() - self.start_time) - * (self.config.max_epochs / (epoch + 1) - 1) - / 60 - ) - self.log(f"ETA: {eta:.1f} minutes") - self.log("-" * 20) - - # Save the model - if epoch % 5 == 0: - torch.save( - model.state_dict(), - self.config.results_path_folder + "/wnet_.pth", - ) - - self.log("Training finished") - if self.best_dice > -1: - best_dice_epoch = epoch - self.log( - f"Best dice metric : {self.best_dice} at epoch {best_dice_epoch}" - ) - - if WANDB_INSTALLED: - wandb.log( - { - "Validation/Best Dice": self.best_dice, - "Validation/Best Dice epoch": best_dice_epoch, - } - ) - - # Save the model - self.log( - f"Saving the model to: {self.config.results_path_folder}/wnet.pth", - ) - save_weights_path = self.config.results_path_folder + "/wnet.pth" - torch.save( - model.state_dict(), - save_weights_path, - ) - - if WANDB_INSTALLED and self.wandb_config.save_model_artifact: - model_artifact = wandb.Artifact( - "WNet3D", - type="model", - description="CellSeg3D WNet3D", - metadata=self.config.__dict__, - ) - model_artifact.add_file(save_weights_path) - wandb.log_artifact(model_artifact) - - except Exception as e: - msg = f"Training failed with exception: {e}" - self.log(msg) - self.raise_error(e, msg) - self.quit() - raise e - - def eval(self, model, _): - """Evaluate the model on the validation set.""" - with torch.no_grad(): - device = self.config.device - for _k, val_data in enumerate(self.eval_dataloader): - val_inputs, val_labels = ( - val_data["image"].to(device), - val_data["label"].to(device), - ) - - # normalize val_inputs across channels - for i in range(val_inputs.shape[0]): - for j in range(val_inputs.shape[1]): - val_inputs[i][j] = self.normalize_function( - val_inputs[i][j] - ) - logger.debug(f"Val inputs shape: {val_inputs.shape}") - val_outputs = sliding_window_inference( - val_inputs, - roi_size=[64, 64, 64], - sw_batch_size=1, - predictor=model.forward_encoder, - overlap=0.1, - mode="gaussian", - sigma_scale=0.01, - progress=True, - ) - val_decoder_outputs = sliding_window_inference( - val_outputs, - roi_size=[64, 64, 64], - sw_batch_size=1, - predictor=model.forward_decoder, - overlap=0.1, - mode="gaussian", - sigma_scale=0.01, - progress=True, - ) - val_outputs = AsDiscrete(threshold=0.5)(val_outputs) - logger.debug(f"Val outputs shape: {val_outputs.shape}") - logger.debug(f"Val labels shape: {val_labels.shape}") - logger.debug( - f"Val decoder outputs shape: {val_decoder_outputs.shape}" - ) - - # dices = [] - # Find in which channel the labels are (avoid background) - # for channel in range(val_outputs.shape[1]): - # dices.append( - # utils.dice_coeff( - # y_pred=val_outputs[ - # 0, channel : (channel + 1), :, :, : - # ], - # y_true=val_labels[0], - # ) - # ) - # logger.debug(f"DICE COEFF: {dices}") - # max_dice_channel = torch.argmax( - # torch.Tensor(dices) - # ) - # logger.debug( - # f"MAX DICE CHANNEL: {max_dice_channel}" - # ) - self.dice_metric( - y_pred=val_outputs, - # [ - # :, - # max_dice_channel : (max_dice_channel + 1), - # :, - # :, - # :, - # ], - y=val_labels, - ) - - # aggregate the final mean dice result - metric = self.dice_metric.aggregate().item() - self.dice_values.append(metric) - self.log(f"Validation Dice score: {metric:.3f}") - if self.best_dice < metric <= 1: - self.best_dice = metric - # save the best model - save_best_path = self.config.results_path_folder - # save_best_path.mkdir(parents=True, exist_ok=True) - save_best_name = "wnet" - save_path = ( - str(Path(save_best_path) / save_best_name) - + "_best_metric.pth" - ) - self.log(f"Saving new best model to {save_path}") - torch.save(model.state_dict(), save_path) - - if WANDB_INSTALLED: - # log validation dice score for each validation round - wandb.log({"Validation/Dice metric": metric}) - - self.dice_metric.reset() - - val_decoder_outputs = None - del val_decoder_outputs - val_outputs = None - del val_outputs - val_labels = None - del val_labels - val_inputs = None - del val_inputs - def get_colab_worker( worker_config: config.WNetTrainingWorkerConfig, From 6ecb2fc4f8936ef9d9c2788a1d4d3c730b3a1ff0 Mon Sep 17 00:00:00 2001 From: C-Achard Date: Sat, 21 Dec 2024 11:55:43 +0100 Subject: [PATCH 06/33] Remove strict channel first --- napari_cellseg3d/code_models/worker_training.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/napari_cellseg3d/code_models/worker_training.py b/napari_cellseg3d/code_models/worker_training.py index 05c576ac..d7059c67 100644 --- a/napari_cellseg3d/code_models/worker_training.py +++ b/napari_cellseg3d/code_models/worker_training.py @@ -200,7 +200,7 @@ def get_patch_dataset(self, train_transforms): patch_func = Compose( [ LoadImaged(keys=["image"], image_only=True), - EnsureChannelFirstd(keys=["image"], channel_dim="no_channel"), + EnsureChannelFirstd(keys=["image"], strict_check=False), RandSpatialCropSamplesd( keys=["image"], roi_size=( @@ -235,7 +235,7 @@ def get_dataset_eval(self, eval_dataset_dict): [ LoadImaged(keys=["image", "label"]), EnsureChannelFirstd( - keys=["image", "label"], channel_dim="no_channel" + keys=["image", "label"], strict_check=False ), # RandSpatialCropSamplesd( # keys=["image", "label"], @@ -280,7 +280,7 @@ def get_dataset(self, train_transforms): load_single_images = Compose( [ LoadImaged(keys=["image"]), - EnsureChannelFirstd(keys=["image"]), + EnsureChannelFirstd(keys=["image"], strict_check=False), Orientationd(keys=["image"], axcodes="PLI"), SpatialPadd( keys=["image"], @@ -1296,7 +1296,7 @@ def get_patch_loader_func(num_samples): return Compose( [ LoadImaged(keys=["image", "label"]), - EnsureChannelFirstd(keys=["image", "label"]), + EnsureChannelFirstd(keys=["image", "label"], strict_check=False), RandSpatialCropSamplesd( keys=["image", "label"], roi_size=( @@ -1381,7 +1381,7 @@ def get_patch_loader_func(num_samples): # image_only=True, # reader=WSIReader(backend="tifffile") ), - EnsureChannelFirstd(keys=["image", "label"]), + EnsureChannelFirstd(keys=["image", "label"], strict_check=False), Orientationd(keys=["image", "label"], axcodes="PLI"), QuantileNormalizationd(keys=["image"]), SpatialPadd( From b7aa88b2e5f9d61e77c53e5a2871050ff59c8060 Mon Sep 17 00:00:00 2001 From: C-Achard Date: Sat, 21 Dec 2024 11:59:23 +0100 Subject: [PATCH 07/33] Add missing channel_dim, remove strict_check=False --- napari_cellseg3d/code_models/worker_training.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/napari_cellseg3d/code_models/worker_training.py b/napari_cellseg3d/code_models/worker_training.py index d7059c67..23238a87 100644 --- a/napari_cellseg3d/code_models/worker_training.py +++ b/napari_cellseg3d/code_models/worker_training.py @@ -200,7 +200,7 @@ def get_patch_dataset(self, train_transforms): patch_func = Compose( [ LoadImaged(keys=["image"], image_only=True), - EnsureChannelFirstd(keys=["image"], strict_check=False), + EnsureChannelFirstd(keys=["image"], channel_dim="no_channel"), RandSpatialCropSamplesd( keys=["image"], roi_size=( @@ -235,7 +235,7 @@ def get_dataset_eval(self, eval_dataset_dict): [ LoadImaged(keys=["image", "label"]), EnsureChannelFirstd( - keys=["image", "label"], strict_check=False + keys=["image", "label"], channel_dim="no_channel" ), # RandSpatialCropSamplesd( # keys=["image", "label"], @@ -280,7 +280,7 @@ def get_dataset(self, train_transforms): load_single_images = Compose( [ LoadImaged(keys=["image"]), - EnsureChannelFirstd(keys=["image"], strict_check=False), + EnsureChannelFirstd(keys=["image"], channel_dim="no_channel"), Orientationd(keys=["image"], axcodes="PLI"), SpatialPadd( keys=["image"], @@ -1296,7 +1296,7 @@ def get_patch_loader_func(num_samples): return Compose( [ LoadImaged(keys=["image", "label"]), - EnsureChannelFirstd(keys=["image", "label"], strict_check=False), + EnsureChannelFirstd(keys=["image", "label"]), RandSpatialCropSamplesd( keys=["image", "label"], roi_size=( @@ -1381,7 +1381,7 @@ def get_patch_loader_func(num_samples): # image_only=True, # reader=WSIReader(backend="tifffile") ), - EnsureChannelFirstd(keys=["image", "label"], strict_check=False), + EnsureChannelFirstd(keys=["image", "label"]), Orientationd(keys=["image", "label"], axcodes="PLI"), QuantileNormalizationd(keys=["image"]), SpatialPadd( From a76037c766a47c975c3be37630116bcb60eb200d Mon Sep 17 00:00:00 2001 From: C-Achard Date: Sat, 21 Dec 2024 12:02:22 +0100 Subject: [PATCH 08/33] Update worker_training.py --- napari_cellseg3d/code_models/worker_training.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/napari_cellseg3d/code_models/worker_training.py b/napari_cellseg3d/code_models/worker_training.py index 23238a87..1fb15f2b 100644 --- a/napari_cellseg3d/code_models/worker_training.py +++ b/napari_cellseg3d/code_models/worker_training.py @@ -1,4 +1,5 @@ """Contains the workers used to train the models.""" + import platform import time from abc import abstractmethod @@ -280,7 +281,7 @@ def get_dataset(self, train_transforms): load_single_images = Compose( [ LoadImaged(keys=["image"]), - EnsureChannelFirstd(keys=["image"], channel_dim="no_channel"), + EnsureChannelFirstd(keys=["image"], channel_dim="no_channel", strict_check=False), Orientationd(keys=["image"], axcodes="PLI"), SpatialPadd( keys=["image"], @@ -1345,9 +1346,9 @@ def get_patch_loader_func(num_samples): ) sample_loader_eval = get_patch_loader_func(num_val_samples) else: - num_train_samples = ( - num_val_samples - ) = self.config.num_samples + num_train_samples = num_val_samples = ( + self.config.num_samples + ) sample_loader_train = get_patch_loader_func( num_train_samples From f722137fe8fddf44df0b82937df928c14aa6456a Mon Sep 17 00:00:00 2001 From: C-Achard Date: Sat, 21 Dec 2024 12:02:30 +0100 Subject: [PATCH 09/33] Update worker_training.py --- napari_cellseg3d/code_models/worker_training.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/napari_cellseg3d/code_models/worker_training.py b/napari_cellseg3d/code_models/worker_training.py index 1fb15f2b..d393868d 100644 --- a/napari_cellseg3d/code_models/worker_training.py +++ b/napari_cellseg3d/code_models/worker_training.py @@ -281,7 +281,11 @@ def get_dataset(self, train_transforms): load_single_images = Compose( [ LoadImaged(keys=["image"]), - EnsureChannelFirstd(keys=["image"], channel_dim="no_channel", strict_check=False), + EnsureChannelFirstd( + keys=["image"], + channel_dim="no_channel", + strict_check=False, + ), Orientationd(keys=["image"], axcodes="PLI"), SpatialPadd( keys=["image"], From 1565731bbd472a630b7f5aa2a64c6d881c9cf2a3 Mon Sep 17 00:00:00 2001 From: C-Achard Date: Sat, 21 Dec 2024 12:04:15 +0100 Subject: [PATCH 10/33] Disable strict checks for channelfirstd --- napari_cellseg3d/code_models/worker_training.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/napari_cellseg3d/code_models/worker_training.py b/napari_cellseg3d/code_models/worker_training.py index d393868d..056ed3f2 100644 --- a/napari_cellseg3d/code_models/worker_training.py +++ b/napari_cellseg3d/code_models/worker_training.py @@ -201,7 +201,7 @@ def get_patch_dataset(self, train_transforms): patch_func = Compose( [ LoadImaged(keys=["image"], image_only=True), - EnsureChannelFirstd(keys=["image"], channel_dim="no_channel"), + EnsureChannelFirstd(keys=["image"], channel_dim="no_channel", strict_check=False), RandSpatialCropSamplesd( keys=["image"], roi_size=( @@ -236,7 +236,7 @@ def get_dataset_eval(self, eval_dataset_dict): [ LoadImaged(keys=["image", "label"]), EnsureChannelFirstd( - keys=["image", "label"], channel_dim="no_channel" + keys=["image", "label"], channel_dim="no_channel", strict_check=False ), # RandSpatialCropSamplesd( # keys=["image", "label"], From 85b0640c16e85be4a0b7140a4e77f732f0b7e7fb Mon Sep 17 00:00:00 2001 From: C-Achard Date: Sat, 21 Dec 2024 12:04:31 +0100 Subject: [PATCH 11/33] Update worker_training.py --- napari_cellseg3d/code_models/worker_training.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/napari_cellseg3d/code_models/worker_training.py b/napari_cellseg3d/code_models/worker_training.py index 056ed3f2..bc3ab981 100644 --- a/napari_cellseg3d/code_models/worker_training.py +++ b/napari_cellseg3d/code_models/worker_training.py @@ -201,7 +201,11 @@ def get_patch_dataset(self, train_transforms): patch_func = Compose( [ LoadImaged(keys=["image"], image_only=True), - EnsureChannelFirstd(keys=["image"], channel_dim="no_channel", strict_check=False), + EnsureChannelFirstd( + keys=["image"], + channel_dim="no_channel", + strict_check=False, + ), RandSpatialCropSamplesd( keys=["image"], roi_size=( @@ -236,7 +240,9 @@ def get_dataset_eval(self, eval_dataset_dict): [ LoadImaged(keys=["image", "label"]), EnsureChannelFirstd( - keys=["image", "label"], channel_dim="no_channel", strict_check=False + keys=["image", "label"], + channel_dim="no_channel", + strict_check=False, ), # RandSpatialCropSamplesd( # keys=["image", "label"], From 766ceaa89e142e829dd83e32d26ba719d40504ee Mon Sep 17 00:00:00 2001 From: C-Achard Date: Sat, 21 Dec 2024 12:12:15 +0100 Subject: [PATCH 12/33] Temp disable channel first --- .../code_models/worker_training.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/napari_cellseg3d/code_models/worker_training.py b/napari_cellseg3d/code_models/worker_training.py index bc3ab981..41820f52 100644 --- a/napari_cellseg3d/code_models/worker_training.py +++ b/napari_cellseg3d/code_models/worker_training.py @@ -201,11 +201,11 @@ def get_patch_dataset(self, train_transforms): patch_func = Compose( [ LoadImaged(keys=["image"], image_only=True), - EnsureChannelFirstd( - keys=["image"], - channel_dim="no_channel", - strict_check=False, - ), + # EnsureChannelFirstd( + # keys=["image"], + # channel_dim="no_channel", + # strict_check=False, + # ), RandSpatialCropSamplesd( keys=["image"], roi_size=( @@ -287,11 +287,11 @@ def get_dataset(self, train_transforms): load_single_images = Compose( [ LoadImaged(keys=["image"]), - EnsureChannelFirstd( - keys=["image"], - channel_dim="no_channel", - strict_check=False, - ), + # EnsureChannelFirstd( + # keys=["image"], + # channel_dim="no_channel", + # strict_check=False, + # ), Orientationd(keys=["image"], axcodes="PLI"), SpatialPadd( keys=["image"], From e3286cee0e5f408f7e53919b2a7e1be5330fcdbb Mon Sep 17 00:00:00 2001 From: C-Achard Date: Sat, 21 Dec 2024 12:15:03 +0100 Subject: [PATCH 13/33] Fix init of Colab worker --- napari_cellseg3d/dev_scripts/colab_training.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/napari_cellseg3d/dev_scripts/colab_training.py b/napari_cellseg3d/dev_scripts/colab_training.py index a23d7396..6524b545 100644 --- a/napari_cellseg3d/dev_scripts/colab_training.py +++ b/napari_cellseg3d/dev_scripts/colab_training.py @@ -73,8 +73,8 @@ def __init__( worker_config: worker configuration wandb_config: optional wandb configuration """ - super().__init__() - self.config = worker_config + super().__init__(worker_config) + super().__init__(worker_config) self.wandb_config = ( wandb_config if wandb_config is not None else config.WandBConfig() ) From b647d98f59c246186298e3314cbd608037a1ddba Mon Sep 17 00:00:00 2001 From: C-Achard Date: Sat, 21 Dec 2024 12:22:51 +0100 Subject: [PATCH 14/33] Move issues with transforms to colab script + disable pad/channelfirst --- .../code_models/worker_training.py | 20 +++---- .../dev_scripts/colab_training.py | 58 +++++++++++++++++++ 2 files changed, 68 insertions(+), 10 deletions(-) diff --git a/napari_cellseg3d/code_models/worker_training.py b/napari_cellseg3d/code_models/worker_training.py index 41820f52..bc3ab981 100644 --- a/napari_cellseg3d/code_models/worker_training.py +++ b/napari_cellseg3d/code_models/worker_training.py @@ -201,11 +201,11 @@ def get_patch_dataset(self, train_transforms): patch_func = Compose( [ LoadImaged(keys=["image"], image_only=True), - # EnsureChannelFirstd( - # keys=["image"], - # channel_dim="no_channel", - # strict_check=False, - # ), + EnsureChannelFirstd( + keys=["image"], + channel_dim="no_channel", + strict_check=False, + ), RandSpatialCropSamplesd( keys=["image"], roi_size=( @@ -287,11 +287,11 @@ def get_dataset(self, train_transforms): load_single_images = Compose( [ LoadImaged(keys=["image"]), - # EnsureChannelFirstd( - # keys=["image"], - # channel_dim="no_channel", - # strict_check=False, - # ), + EnsureChannelFirstd( + keys=["image"], + channel_dim="no_channel", + strict_check=False, + ), Orientationd(keys=["image"], axcodes="PLI"), SpatialPadd( keys=["image"], diff --git a/napari_cellseg3d/dev_scripts/colab_training.py b/napari_cellseg3d/dev_scripts/colab_training.py index 6524b545..2f9d16fa 100644 --- a/napari_cellseg3d/dev_scripts/colab_training.py +++ b/napari_cellseg3d/dev_scripts/colab_training.py @@ -4,8 +4,19 @@ from pathlib import Path from typing import TYPE_CHECKING +from monai.data import CacheDataset + # MONAI from monai.metrics import DiceMetric +from monai.transforms import ( + AddChanneld, + Compose, + EnsureChannelFirstd, + EnsureTyped, + LoadImaged, + Orientationd, + SpatialPadd, +) # local from napari_cellseg3d import config, utils @@ -94,6 +105,53 @@ def __init__( self.eval_dataloader: DataLoader = None self.data_shape = None + def get_dataset(self, train_transforms): + """Creates a Dataset applying some transforms/augmentation on the data using the MONAI library. + + Args: + train_transforms (monai.transforms.Compose): The transforms to apply to the data + + Returns: + (tuple): A tuple containing the shape of the data and the dataset + """ + train_files = self.config.train_data_dict + + first_volume = LoadImaged(keys=["image"])(train_files[0]) + first_volume_shape = first_volume["image"].shape + + if len(first_volume_shape) != 3: + raise ValueError( + f"Expected 3D volumes, got {len(first_volume_shape)} dimensions" + ) + + # Transforms to be applied to each volume + load_single_images = Compose( + [ + LoadImaged(keys=["image"]), + # EnsureChannelFirstd( + # keys=["image"], + # channel_dim="no_channel", + # strict_check=False, + # ), + AddChanneld(keys=["image"]), + Orientationd(keys=["image"], axcodes="PLI"), + # SpatialPadd( + # keys=["image"], + # spatial_size=(utils.get_padding_dim(first_volume_shape)), + # ), + EnsureTyped(keys=["image"]), + # RemapTensord(keys=["image"], new_min=0.0, new_max=100.0), + ] + ) + + # Create the dataset + dataset = CacheDataset( + data=train_files, + transform=Compose([load_single_images, train_transforms]), + ) + + return first_volume_shape, dataset + def get_colab_worker( worker_config: config.WNetTrainingWorkerConfig, From 0e69ee4d0dea4e48cb5b9be35972787cfb7155fa Mon Sep 17 00:00:00 2001 From: C-Achard Date: Sat, 21 Dec 2024 12:29:29 +0100 Subject: [PATCH 15/33] Enable ChannelFirst again --- napari_cellseg3d/dev_scripts/colab_training.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/napari_cellseg3d/dev_scripts/colab_training.py b/napari_cellseg3d/dev_scripts/colab_training.py index 2f9d16fa..9d920f0e 100644 --- a/napari_cellseg3d/dev_scripts/colab_training.py +++ b/napari_cellseg3d/dev_scripts/colab_training.py @@ -9,13 +9,11 @@ # MONAI from monai.metrics import DiceMetric from monai.transforms import ( - AddChanneld, Compose, EnsureChannelFirstd, EnsureTyped, LoadImaged, Orientationd, - SpatialPadd, ) # local @@ -128,12 +126,11 @@ def get_dataset(self, train_transforms): load_single_images = Compose( [ LoadImaged(keys=["image"]), - # EnsureChannelFirstd( - # keys=["image"], - # channel_dim="no_channel", - # strict_check=False, - # ), - AddChanneld(keys=["image"]), + EnsureChannelFirstd( + keys=["image"], + channel_dim="no_channel", + strict_check=False, + ), Orientationd(keys=["image"], axcodes="PLI"), # SpatialPadd( # keys=["image"], From 788903e4630f3c481d77e13cc5c7dc0eb2bcdb8f Mon Sep 17 00:00:00 2001 From: C-Achard Date: Sat, 21 Dec 2024 12:31:44 +0100 Subject: [PATCH 16/33] Remove strict_check = False in original worker Seems to be a Colab-specific issue --- napari_cellseg3d/code_models/worker_training.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/napari_cellseg3d/code_models/worker_training.py b/napari_cellseg3d/code_models/worker_training.py index bc3ab981..e6d3173b 100644 --- a/napari_cellseg3d/code_models/worker_training.py +++ b/napari_cellseg3d/code_models/worker_training.py @@ -204,7 +204,6 @@ def get_patch_dataset(self, train_transforms): EnsureChannelFirstd( keys=["image"], channel_dim="no_channel", - strict_check=False, ), RandSpatialCropSamplesd( keys=["image"], @@ -242,7 +241,6 @@ def get_dataset_eval(self, eval_dataset_dict): EnsureChannelFirstd( keys=["image", "label"], channel_dim="no_channel", - strict_check=False, ), # RandSpatialCropSamplesd( # keys=["image", "label"], @@ -290,7 +288,6 @@ def get_dataset(self, train_transforms): EnsureChannelFirstd( keys=["image"], channel_dim="no_channel", - strict_check=False, ), Orientationd(keys=["image"], axcodes="PLI"), SpatialPadd( From d00d1b6b147067b29ed33e25eb522c4188dae53a Mon Sep 17 00:00:00 2001 From: C-Achard Date: Sat, 21 Dec 2024 12:45:21 +0100 Subject: [PATCH 17/33] Remove redundant code + Colab notebook tweaks --- napari_cellseg3d/dev_scripts/colab_training.py | 14 +------------- notebooks/Colab_WNet3D_training.ipynb | 15 ++++----------- 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/napari_cellseg3d/dev_scripts/colab_training.py b/napari_cellseg3d/dev_scripts/colab_training.py index 9d920f0e..79bcfdbb 100644 --- a/napari_cellseg3d/dev_scripts/colab_training.py +++ b/napari_cellseg3d/dev_scripts/colab_training.py @@ -30,17 +30,6 @@ VERBOSE_SCHEDULER = True logger.debug(f"PRETRAINED WEIGHT DIR LOCATION : {PRETRAINED_WEIGHTS_DIR}") -try: - import wandb - - WANDB_INSTALLED = True -except ImportError: - logger.warning( - "wandb not installed, wandb config will not be taken into account", - stacklevel=1, - ) - WANDB_INSTALLED = False - class LogFixture: """Fixture for napari-less logging, replaces napari_cellseg3d.interface.Log in model_workers. @@ -161,8 +150,7 @@ def get_colab_worker( wandb_config (config.WandBConfig): config for wandb """ log = LogFixture() - worker = WNetTrainingWorkerColab(worker_config) - worker.wandb_config = wandb_config + worker = WNetTrainingWorkerColab(worker_config, wandb_config) worker.log_signal.connect(log.print_and_log) worker.warn_signal.connect(log.warn) diff --git a/notebooks/Colab_WNet3D_training.ipynb b/notebooks/Colab_WNet3D_training.ipynb index c8622701..fc11e992 100644 --- a/notebooks/Colab_WNet3D_training.ipynb +++ b/notebooks/Colab_WNet3D_training.ipynb @@ -313,11 +313,11 @@ "outputs": [], "source": [ "#@markdown ###Path to the training data:\n", - "training_source = \"./gdrive/MyDrive/CELLSEG_BENCHMARK/DATA/WNET/VIP_full\" #@param {type:\"string\"}\n", - "#@markdown ###Model name and path to model folder:\n", - "model_save_path = \"./gdrive/MyDrive/CELLSEG_BENCHMARK/WNET_TRAINING_RESULTS\" #@param {type:\"string\"}\n", + "training_source = \"./gdrive/MyDrive/path/to/data\" #@param {type:\"string\"}\n", + "#@markdown ###Path to save the weights (make sure to have enough space in your drive):\n", + "model_save_path = \"./gdrive/MyDrive/WNET_TRAINING_RESULTS\" #@param {type:\"string\"}\n", "#@markdown ---\n", - "#@markdown ###Perform validation on a test dataset\n", + "#@markdown ###Perform validation on a test dataset (optional):\n", "do_validation = False #@param {type:\"boolean\"}\n", "#@markdown ###Path to evaluation data (optional, use if checked above):\n", "eval_source = \"./gdrive/MyDrive/CELLSEG_BENCHMARK/DATA/WNET/eval/vol/\" #@param {type:\"string\"}\n", @@ -396,13 +396,6 @@ " eval_label_folder,\n", " ) if do_validation else None\n", "\n", - "try:\n", - " import wandb\n", - " WANDB_INSTALLED = True\n", - "except ImportError:\n", - " WANDB_INSTALLED = False\n", - "\n", - "\n", "train_config = WNetTrainingWorkerConfig(\n", " device=\"cuda:0\",\n", " max_epochs=number_of_epochs,\n", From b42df9d49cf03dbcca6c899a70d3bcfad7b59cba Mon Sep 17 00:00:00 2001 From: C-Achard Date: Sat, 21 Dec 2024 12:51:03 +0100 Subject: [PATCH 18/33] Revert wandb check --- notebooks/Colab_WNet3D_training.ipynb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/notebooks/Colab_WNet3D_training.ipynb b/notebooks/Colab_WNet3D_training.ipynb index fc11e992..3f35c6c0 100644 --- a/notebooks/Colab_WNet3D_training.ipynb +++ b/notebooks/Colab_WNet3D_training.ipynb @@ -396,6 +396,13 @@ " eval_label_folder,\n", " ) if do_validation else None\n", "\n", + "try:\n", + " import wandb\n", + " WANDB_INSTALLED = True\n", + "except ImportError:\n", + " WANDB_INSTALLED = False\n", + "\n", + "\n", "train_config = WNetTrainingWorkerConfig(\n", " device=\"cuda:0\",\n", " max_epochs=number_of_epochs,\n", From a5acd55c4131e39160121b9c2a23365a5493aa55 Mon Sep 17 00:00:00 2001 From: C-Achard Date: Sat, 21 Dec 2024 15:55:07 +0100 Subject: [PATCH 19/33] Update docs + Colab inference --- docs/source/guides/training_wnet.rst | 10 +- notebooks/Colab_inference_demo.ipynb | 377 ++++++++++++++------------- 2 files changed, 207 insertions(+), 180 deletions(-) diff --git a/docs/source/guides/training_wnet.rst b/docs/source/guides/training_wnet.rst index 21fff524..91e7d752 100644 --- a/docs/source/guides/training_wnet.rst +++ b/docs/source/guides/training_wnet.rst @@ -20,21 +20,21 @@ You may find below some guidelines, based on our own data and testing. The WNet3D is designed to segment objects based on their brightness, and is particularly well-suited for images with a clear contrast between objects and background. -The WNet3D is not suitable for images with artifacts, therefore care should be taken that the images are clean and that the objects are at least somewhat distinguishable from the background. +The WNet3D is not suitable for images with strong noise or artifacts, therefore care should be taken that the images are clean and that the objects are at least somewhat distinguishable from the background. .. important:: For optimal performance, the following should be avoided for training: - Images with very large, bright regions - - Almost-empty and empty images + - Almost-empty and empty images, especially if noise is present - Images with large empty regions or "holes" - However, the model may be accomodate: + However, the model may accomodate: - Uneven brightness distribution - Varied object shapes and radius - - Noisy images + - Noisy images (as long as resolution is sufficient and boundaries are clear) - Uneven illumination across the image For optimal results, during inference, images should be similar to those the model was trained on; however this is not a strict requirement. @@ -88,7 +88,7 @@ Common issues troubleshooting If you do not find a satisfactory answer here, please do not hesitate to `open an issue`_ on GitHub. -- **The NCuts loss "explodes" after a few epochs** : Lower the learning rate, for example start with a factor of two, then ten. +- **The NCuts loss "explodes" upward after a few epochs** : Lower the learning rate, for example start with a factor of two, then ten. - **Reconstruction (decoder) performance is poor** : First, try increasing the weight of the reconstruction loss. If this is ineffective, switch to BCE loss and set the scaling factor of the reconstruction loss to 0.5, OR adjust the weight of the MSE loss. diff --git a/notebooks/Colab_inference_demo.ipynb b/notebooks/Colab_inference_demo.ipynb index 7212322c..9c1d1747 100644 --- a/notebooks/Colab_inference_demo.ipynb +++ b/notebooks/Colab_inference_demo.ipynb @@ -3,8 +3,8 @@ { "cell_type": "markdown", "metadata": { - "id": "view-in-github", - "colab_type": "text" + "colab_type": "text", + "id": "view-in-github" }, "source": [ "\"Open" @@ -48,17 +48,17 @@ "cell_type": "code", "execution_count": 1, "metadata": { - "id": "bnFKu6uFAm-z", - "collapsed": true, - "outputId": "a52993ed-bfc1-4b44-973c-3f7da876e33a", "colab": { "base_uri": "https://localhost:8080/" - } + }, + "collapsed": true, + "id": "bnFKu6uFAm-z", + "outputId": "a52993ed-bfc1-4b44-973c-3f7da876e33a" }, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "fatal: destination path './CellSeg3D' already exists and is not an empty directory.\n", "Requirement already satisfied: napari-cellseg3d in /usr/local/lib/python3.10/dist-packages (0.2.1)\n", @@ -220,8 +220,7 @@ "source": [ "#@markdown ##Install CellSeg3D and grab demo data\n", "!git clone https://github.com/AdaptiveMotorControlLab/CellSeg3d.git --branch main --single-branch ./CellSeg3D\n", - "!pip install napari-cellseg3d\n", - "!pip install pydensecrf" + "!pip install napari-cellseg3d" ] }, { @@ -238,16 +237,16 @@ "cell_type": "code", "execution_count": 2, "metadata": { - "id": "vzm75tE_Am-0", - "outputId": "81a95be8-fe48-4a5b-a64c-2f993772c418", "colab": { "base_uri": "https://localhost:8080/" - } + }, + "id": "vzm75tE_Am-0", + "outputId": "81a95be8-fe48-4a5b-a64c-2f993772c418" }, "outputs": [ { - "output_type": "stream", "name": "stderr", + "output_type": "stream", "text": [ "/usr/local/lib/python3.10/dist-packages/pytools/persistent_dict.py:52: RecommendedHashNotFoundWarning: Unable to import recommended hash 'siphash24.siphash13', falling back to 'hashlib.sha256'. Run 'python3 -m pip install siphash24' to install the recommended hash.\n", " warn(\"Unable to import recommended hash 'siphash24.siphash13', \"\n" @@ -261,6 +260,7 @@ "from pathlib import Path\n", "from napari_cellseg3d.dev_scripts import remote_inference as cs3d\n", "from napari_cellseg3d.utils import LOGGER as logger\n", + "from napari_cellseg3d.config import MODEL_LIST, ModelInfo\n", "\n", "import logging\n", "\n", @@ -300,16 +300,16 @@ "cell_type": "code", "execution_count": 3, "metadata": { - "id": "Fe8hNkOpAm-0", - "outputId": "3488c95a-b0d0-4557-d69f-1c89640cfaf3", "colab": { "base_uri": "https://localhost:8080/" - } + }, + "id": "Fe8hNkOpAm-0", + "outputId": "3488c95a-b0d0-4557-d69f-1c89640cfaf3" }, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "You have GPU access\n", "Sun Dec 15 21:09:57 2024 \n", @@ -360,37 +360,64 @@ "---" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Write a Colab dropdown menu to choose the model from MODEL_LIST\n", + "\n", + "import ipywidgets as widgets\n", + "from IPython.display import display\n", + "\n", + "model_list = [model for model in MODEL_LIST.keys()]\n", + "\n", + "model_dropdown = widgets.Dropdown(\n", + " options=model_list,\n", + " description='Model:',\n", + " disabled=False,\n", + ")\n", + "\n", + "display(model_dropdown)" + ] + }, { "cell_type": "code", "execution_count": 4, "metadata": { - "id": "O0jLRpARAm-0", - "outputId": "fdf0800b-976a-47ef-d848-b7c45621f2c4", "colab": { "base_uri": "https://localhost:8080/", "height": 35 - } + }, + "id": "O0jLRpARAm-0", + "outputId": "fdf0800b-976a-47ef-d848-b7c45621f2c4" }, "outputs": [ { - "output_type": "execute_result", "data": { - "text/plain": [ - "'cupy backend (experimental)'" - ], "application/vnd.google.colaboratory.intrinsic+json": { "type": "string" - } + }, + "text/plain": [ + "'cupy backend (experimental)'" + ] }, + "execution_count": 4, "metadata": {}, - "execution_count": 4 + "output_type": "execute_result" } ], "source": [ "demo_image_path = \"/content/CellSeg3D/examples/c5image.tif\"\n", "demo_image = imread(demo_image_path)\n", "inference_config = cs3d.CONFIG\n", - "post_process_config = cs3d.PostProcessConfig()\n", + "inference_config.model_info = ModelInfo(\n", + " name=model_dropdown.value,\n", + " model_input_size=[64, 64, 64],\n", + " num_classes=2,\n", + ")\n", + "post_process_config = cs3d.PostProcessConfig(threshold=MODEL_LIST[model_dropdown.value].default_threshold)\n", "# select cle device for colab\n", "import pyclesperanto_prototype as cle\n", "cle.select_device(\"cupy\")" @@ -400,16 +427,16 @@ "cell_type": "code", "execution_count": 5, "metadata": { - "id": "hIEKoyEGAm-0", - "outputId": "c616aab6-a4e7-463b-a051-923bf85b8380", "colab": { "base_uri": "https://localhost:8080/" - } + }, + "id": "hIEKoyEGAm-0", + "outputId": "c616aab6-a4e7-463b-a051-923bf85b8380" }, "outputs": [ { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "--------------------\n", "Parameters summary :\n", @@ -425,8 +452,8 @@ ] }, { - "output_type": "stream", "name": "stderr", + "output_type": "stream", "text": [ "monai.networks.nets.swin_unetr SwinUNETR.__init__:img_size: Argument `img_size` has been deprecated since version 1.3. It will be removed in version 1.5. The img_size argument is not required anymore and checks on the input size are run during forward().\n", "INFO:napari_cellseg3d.utils:********************\n", @@ -434,22 +461,22 @@ ] }, { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "Loading weights...\n" ] }, { - "output_type": "stream", "name": "stderr", + "output_type": "stream", "text": [ "You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n" ] }, { - "output_type": "stream", "name": "stdout", + "output_type": "stream", "text": [ "Weights status : \n", "Done\n", @@ -484,16 +511,16 @@ "cell_type": "code", "execution_count": 6, "metadata": { - "id": "IFbmZ3_zAm-1", - "outputId": "b9abbb7e-40a7-407e-eca5-48142a608712", "colab": { "base_uri": "https://localhost:8080/" - } + }, + "id": "IFbmZ3_zAm-1", + "outputId": "b9abbb7e-40a7-407e-eca5-48142a608712" }, "outputs": [ { - "output_type": "stream", "name": "stderr", + "output_type": "stream", "text": [ "1it [00:00, 11.29it/s]\n", "clesperanto's cupy / CUDA backend is experimental. Please use it with care. The following functions are known to cause issues in the CUDA backend:\n", @@ -517,8 +544,6 @@ "cell_type": "code", "execution_count": 7, "metadata": { - "id": "TMRiQ-m4Am-1", - "outputId": "96604c9f-cc6a-4b02-9c06-ada41acccb40", "colab": { "base_uri": "https://localhost:8080/", "height": 496, @@ -531,29 +556,27 @@ "a8a98fa6693c4271abb49e5dc59f3e99", "6bafd832de8f433fa7439b505e2fe922" ] - } + }, + "id": "TMRiQ-m4Am-1", + "outputId": "96604c9f-cc6a-4b02-9c06-ada41acccb40" }, "outputs": [ { - "output_type": "display_data", "data": { - "text/plain": [ - "interactive(children=(IntSlider(value=62, description='z', max=123), Output()), _dom_classes=('widget-interact…" - ], "application/vnd.jupyter.widget-view+json": { + "model_id": "14688e5b41f646449485e9aa4f724724", "version_major": 2, - "version_minor": 0, - "model_id": "14688e5b41f646449485e9aa4f724724" - } + "version_minor": 0 + }, + "text/plain": [ + "interactive(children=(IntSlider(value=62, description='z', max=123), Output()), _dom_classes=('widget-interact…" + ] }, - "metadata": {} + "metadata": {}, + "output_type": "display_data" }, { - "output_type": "execute_result", "data": { - "text/plain": [ - "" - ], "text/html": [ "
\n", - "
update_plot
def update_plot(z)
/content/<ipython-input-7-245acde924e0><no docstring>
" - ] - }, - "metadata": {}, - "execution_count": 7 - } - ], + "outputs": [], "source": [ "# @title Display the result\n", "#@markdown This cell displays the result of the inference and post-processing. Use the slider to navigate through the z-stack.\n", @@ -440,516 +461,11 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": { - "id": "Tw5exJ5EAm-1", - "outputId": "0384a401-b02a-4303-b698-44f4df84e28b", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 424 - } + "id": "Tw5exJ5EAm-1" }, - "outputs": [ - { - "output_type": "display_data", - "data": { - "text/plain": [ - " Volume Centroid x Centroid y Centroid z Sphericity (axes) \\\n", - "0 190.0 5.405263 69.157895 36.210526 0.778113 \n", - "1 18.0 5.833333 85.000000 83.944444 0.000007 \n", - "2 67.0 7.283582 65.492537 92.059701 0.867751 \n", - "3 108.0 10.324074 84.342593 68.861111 0.672490 \n", - "4 35.0 9.428571 84.314286 92.600000 0.649649 \n", - ".. ... ... ... ... ... \n", - "317 11.0 122.363636 14.727273 25.000000 0.951651 \n", - "318 24.0 122.166667 26.083333 38.083333 0.990075 \n", - "319 16.0 122.125000 34.125000 36.500000 0.944672 \n", - "320 13.0 122.076923 43.538462 53.615385 0.939852 \n", - "321 21.0 122.523810 49.666667 36.238095 0.895437 \n", - "\n", - " Image size Total image volume Total object volume (pixels) \\\n", - "0 (124, 86, 94) 1002416 33504.0 \n", - "1 \n", - "2 \n", - "3 \n", - "4 \n", - ".. ... ... ... \n", - "317 \n", - "318 \n", - "319 \n", - "320 \n", - "321 \n", - "\n", - " Filling ratio Number objects \n", - "0 0.033423 322 \n", - "1 \n", - "2 \n", - "3 \n", - "4 \n", - ".. ... ... \n", - "317 \n", - "318 \n", - "319 \n", - "320 \n", - "321 \n", - "\n", - "[322 rows x 10 columns]" - ], - "text/html": [ - "\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
VolumeCentroid xCentroid yCentroid zSphericity (axes)Image sizeTotal image volumeTotal object volume (pixels)Filling ratioNumber objects
0190.05.40526369.15789536.2105260.778113(124, 86, 94)100241633504.00.033423322
118.05.83333385.00000083.9444440.000007
267.07.28358265.49253792.0597010.867751
3108.010.32407484.34259368.8611110.672490
435.09.42857184.31428692.6000000.649649
.................................
31711.0122.36363614.72727325.0000000.951651
31824.0122.16666726.08333338.0833330.990075
31916.0122.12500034.12500036.5000000.944672
32013.0122.07692343.53846253.6153850.939852
32121.0122.52381049.66666736.2380950.895437
\n", - "

322 rows × 10 columns

\n", - "
\n", - "
\n", - "\n", - "
\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "
\n", - "\n", - "\n", - "
\n", - " \n", - "\n", - "\n", - "\n", - " \n", - "
\n", - "\n", - "
\n", - " \n", - " \n", - " \n", - "
\n", - "\n", - "
\n", - "
\n" - ], - "application/vnd.google.colaboratory.intrinsic+json": { - "type": "dataframe", - "variable_name": "data", - "summary": "{\n \"name\": \"data\",\n \"rows\": 322,\n \"fields\": [\n {\n \"column\": \"Volume\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 54.38970963263131,\n \"min\": 8.0,\n \"max\": 252.0,\n \"num_unique_values\": 157,\n \"samples\": [\n 14.0,\n 124.0,\n 169.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Centroid x\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 31.084053076294715,\n \"min\": 5.405263157894737,\n \"max\": 122.52380952380952,\n \"num_unique_values\": 321,\n \"samples\": [\n 73.65806451612903,\n 60.0,\n 81.18303571428571\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Centroid y\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 25.419664210044758,\n \"min\": 0.0,\n \"max\": 85.0,\n \"num_unique_values\": 320,\n \"samples\": [\n 0.6310679611650486,\n 1.7452229299363058,\n 13.709401709401709\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Centroid z\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 27.685581861438635,\n \"min\": 0.12903225806451613,\n \"max\": 93.0,\n \"num_unique_values\": 320,\n \"samples\": [\n 12.174757281553399,\n 10.108695652173912,\n 70.51282051282051\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Sphericity (axes)\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.12590741175173295,\n \"min\": 5.583882595237912e-06,\n \"max\": 0.9900749841550203,\n \"num_unique_values\": 318,\n \"samples\": [\n 0.8007911710122606,\n 0.8283576063212561,\n 0.7547372074750551\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Image size\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"\",\n [\n 124,\n 86,\n 94\n ]\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Total image volume\",\n \"properties\": {\n \"dtype\": \"date\",\n \"min\": \"1970-01-01 00:00:00.001002416\",\n \"max\": \"1970-01-01 00:00:00.001002416\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"\",\n 1002416\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Total object volume (pixels)\",\n \"properties\": {\n \"dtype\": \"date\",\n \"min\": \"1970-01-01 00:00:00.000033504\",\n \"max\": \"1970-01-01 00:00:00.000033504\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"\",\n 33504.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Filling ratio\",\n \"properties\": {\n \"dtype\": \"date\",\n \"min\": \"1970-01-01 00:00:00\",\n \"max\": \"1970-01-01 00:00:00\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"\",\n 0.03342324942937862\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Number objects\",\n \"properties\": {\n \"dtype\": \"date\",\n \"min\": \"1970-01-01 00:00:00.000000322\",\n \"max\": \"1970-01-01 00:00:00.000000322\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"\",\n 322\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" - } - }, - "metadata": {} - } - ], + "outputs": [], "source": [ "# @title Display the statistics\n", "# @markdown This cell displays the statistics of the post-processed result.\n", @@ -960,56 +476,11 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": { - "id": "0NhZ-YksAm-1", - "outputId": "81ebfeb6-c83e-4930-f96a-cdf7200e84e7", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 617 - } + "id": "0NhZ-YksAm-1" }, - "outputs": [ - { - "output_type": "display_data", - "data": { - "text/html": [ - "\n", - "\n", - "\n", - "
\n", - "
\n", - "\n", - "" - ] - }, - "metadata": {} - } - ], + "outputs": [], "source": [ "# @title Plot the a 3D view, with statistics\n", "# @markdown This cell plots a 3D view of the cells, with the volume as the size of the points and the sphericity as the color.\n", @@ -1057,7 +528,8 @@ "accelerator": "GPU", "colab": { "gpuType": "T4", - "provenance": [] + "provenance": [], + "include_colab_link": true }, "kernelspec": { "display_name": "Python 3", @@ -1065,260 +537,6 @@ }, "language_info": { "name": "python" - }, - "widgets": { - "application/vnd.jupyter.widget-state+json": { - "8d9102f8cae54ca492cfa939fc75f4dd": { - "model_module": "@jupyter-widgets/controls", - "model_name": "VBoxModel", - "model_module_version": "1.5.0", - "state": { - "_dom_classes": [ - "widget-interact" - ], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "VBoxModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "VBoxView", - "box_style": "", - "children": [ - "IPY_MODEL_408db0ee6c7741838b9b488185ee672d", - "IPY_MODEL_d2af6a9459174c5faf04cc8989dce00c" - ], - "layout": "IPY_MODEL_e039dcefc4d348e0ba543e785cc02431" - } - }, - "408db0ee6c7741838b9b488185ee672d": { - "model_module": "@jupyter-widgets/controls", - "model_name": "IntSliderModel", - "model_module_version": "1.5.0", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "IntSliderModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "IntSliderView", - "continuous_update": true, - "description": "z", - "description_tooltip": null, - "disabled": false, - "layout": "IPY_MODEL_0b548f2b5fff44c9bcc67b4e3638b8e3", - "max": 123, - "min": 0, - "orientation": "horizontal", - "readout": true, - "readout_format": "d", - "step": 1, - "style": "IPY_MODEL_bf55bb77edd24e8493f5b243bdc9e13c", - "value": 14 - } - }, - "d2af6a9459174c5faf04cc8989dce00c": { - "model_module": "@jupyter-widgets/output", - "model_name": "OutputModel", - "model_module_version": "1.0.0", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/output", - "_model_module_version": "1.0.0", - "_model_name": "OutputModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/output", - "_view_module_version": "1.0.0", - "_view_name": "OutputView", - "layout": "IPY_MODEL_99f4c261ee3d4303ab95e85fa8405715", - "msg_id": "", - "outputs": [ - { - "output_type": "display_data", - "data": { - "text/plain": "
", - "image/png": "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Y6Ojxz8+3tfX17SDcLpQjopRjmKUn2KaPUf87ahnO6VSyZ70pCeZWfOP7elAOSpGOSpGOYpZDvnRXlNHf9M0jnIUo/wUoxwV0+w5ms8+o3+zCCGEEEIIIYQQQoimRw+5hBBCCCGEEEIIIUTTs2QfcrW3t9sf/MEfWHt7+5kOZcmiHBWjHMUoP8UoR8sXjW0xylExylExylGM8rO80fgWoxzFKD/FKEfFnE05WnLG80IIIYQQQgghhBBCNMqS/SSXEEIIIYQQQgghhBDzRQ+5hBBCCCGEEEIIIUTTo4dcQgghhBBCCCGEEKLp0UMuIYQQQgghhBBCCNH0LNmHXDfffLOdd9551tHRYZdccol99atfPdMhnRF27txpz3nOc6y3t9fWrl1rL3/5y2337t3unKmpKdu+fbutWrXKenp67KqrrrKhoaEzFPGZ56abbrIkSey6666r/U45Mvvxj39sv/7rv26rVq2yzs5Oe8YznmFf+9rXauVpmtrb3/52W79+vXV2dtq2bdvsoYceOoMRnz4qlYrdeOONtnnzZuvs7LSnPOUp9id/8ieG38txNudnuaJ95jjaZxpH+8zcaJ+J0V5z9qF9po72msbQPjM32mditM+cIF2C3H777WlbW1v613/91+l3vvOd9H/+z/+Z9vf3p0NDQ2c6tNPO5Zdfnt56663pt7/97fQb3/hG+ou/+Ivppk2b0vHx8do5r3vd69KNGzemu3btSr/2ta+lz3ve89LnP//5ZzDqM8dXv/rV9LzzzksvvPDC9M1vfnPt92d7jg4fPpyee+656W/+5m+m9913X/rDH/4w/fznP5/+4Ac/qJ1z0003peVyOb3zzjvTb37zm+kv/dIvpZs3b06PHj16BiM/Pbzzne9MV61alX72s59NH3744fSOO+5Ie3p60r/4i7+onXM252c5on2mjvaZxtA+MzfaZ4rRXnN2oX3Go71m/mifmRvtM8VonznOknzI9dznPjfdvn177bhSqaQbNmxId+7ceQajWho8/vjjqZmld999d5qmaTo8PJy2tramd9xxR+2cBx98MDWz9J577jlTYZ4RxsbG0vPPPz/9whe+kL7whS+sbQrKUZq+9a1vTV/wghfkller1XTdunXpn/3Zn9V+Nzw8nLa3t6d/+7d/ezpCPKO85CUvSV/96le731155ZXp1Vdfnaap8rMc0T6Tj/aZfLTP5KN9phjtNWcX2mditNfMjfaZfLTPFKN95jhLTq44MzNjDzzwgG3btq32u1KpZNu2bbN77rnnDEa2NBgZGTEzs4GBATMze+CBB2x2dtbla8uWLbZp06azLl/bt2+3l7zkJS4XZsqRmdk//uM/2sUXX2yvfOUrbe3atfasZz3LPvKRj9TKH374Ydu/f7/LUblctksuueSsyNHzn/9827Vrl33/+983M7NvfvOb9pWvfMWuuOIKM1N+lhvaZ2K0z+SjfSYf7TPFaK85e9A+U4z2mrnRPpOP9plitM8cZ8WZDoA5ePCgVSoVGxwcdL8fHBy0733ve2coqqVBtVq16667zi699FJ7+tOfbmZm+/fvt7a2Nuvv73fnDg4O2v79+89AlGeG22+/3b7+9a/b/fffnylTjsx++MMf2i233GI7duyw//W//pfdf//99qY3vcna2trsmmuuqeVhrnV3NuTobW97m42OjtqWLVuspaXFKpWKvfOd77Srr77azOysz89yQ/tMPtpn8tE+E6N9phjtNWcP2mditNfMjfaZGO0zxWifOc6Se8gl8tm+fbt9+9vftq985StnOpQlxaOPPmpvfvOb7Qtf+IJ1dHSc6XCWJNVq1S6++GJ717veZWZmz3rWs+zb3/62fehDH7JrrrnmDEd35vnUpz5ln/zkJ+22226zpz3tafaNb3zDrrvuOtuwYYPyI84qtM/MjfaZYrTPFKO9RojjaK/Jon2mGO0zxWifOc6SkyuuXr3aWlpaMt8UMTQ0ZOvWrTtDUZ15rr32WvvsZz9r//Iv/2LnnHNO7ffr1q2zmZkZGx4eduefTfl64IEH7PHHH7dnP/vZtmLFCluxYoXdfffd9v73v99WrFhhg4ODZ32O1q9fb0996lPd7y644ALbs2ePmVktD2fruvu93/s9e9vb3mavetWr7BnPeIb9j//xP+z666+3nTt3mpnys9zQPjM32mfy0T5TjPaZYrTXnD1on8lHe83caJ8pRvtMMdpnjrPkHnK1tbXZRRddZLt27ar9rlqt2q5du2zr1q1nMLIzQ5qmdu2119qnP/1p+9KXvmSbN2925RdddJG1tra6fO3evdv27Nlz1uTrRS96kX3rW9+yb3zjG7Wfiy++2K6++ura67M9R5deemnma5q///3v27nnnmtmZps3b7Z169a5HI2Ojtp99913VuRocnLSSiV/O2xpabFqtWpmys9yQ/uMR/tMMdpnitE+U4z2mrMH7TNZtNfEaJ8pRvtMMdpnTnCGje/n5Pbbb0/b29vTj33sY+l3v/vd9LWvfW3a39+f7t+//0yHdtp5/etfn5bL5fRf//Vf03379tV+Jicna+e87nWvSzdt2pR+6UtfSr/2ta+lW7duTbdu3XoGoz7z4LeRpKly9NWvfjVdsWJF+s53vjN96KGH0k9+8pNpV1dX+olPfKJ2zk033ZT29/enn/nMZ9L/+q//Sl/2spctu6+TzeOaa65Jn/SkJ9W+bvcf/uEf0tWrV6dvectbaueczflZjmifqaN95uTQPuPRPlOM9pqzC+0zHu01jaN9xqN9phjtM8dZkg+50jRNP/CBD6SbNm1K29ra0uc+97npvffee6ZDOiOY2Zw/t956a+2co0ePpm94wxvSlStXpl1dXekv//Ivp/v27TtzQS8BeFNQjtL0rrvuSp/+9Ken7e3t6ZYtW9IPf/jDrrxaraY33nhjOjg4mLa3t6cvetGL0t27d5+haE8vo6Oj6Zvf/OZ006ZNaUdHR/rkJz85/d//+3+n09PTtXPO5vwsV7TPHEf7zMmhfSaL9pkY7TVnH9pn6mivaRztM1m0z8RonzlOkqZpero/PSaEEEIIIYQQQgghxEKy5Dy5hBBCCCGEEEIIIYRoFD3kEkIIIYQQQgghhBBNjx5yCSGEEEIIIYQQQoimRw+5hBBCCCGEEEIIIUTTo4dcQgghhBBCCCGEEKLp0UMuIYQQQgghhBBCCNH06CGXEEIIIYQQQgghhGh69JBLCCGEEEIIIYQQQjQ9esglhBBCCCGEEEIIIZoePeQSQgghhBBCCCGEEE2PHnIJIYQQQgghhBBCiKZHD7mEEEIIIYQQQgghRNPz/wcmH0jjf+r7JAAAAABJRU5ErkJggg==\n" - }, - "metadata": {} - } - ] - } - }, - "e039dcefc4d348e0ba543e785cc02431": { - "model_module": "@jupyter-widgets/base", - "model_name": "LayoutModel", - "model_module_version": "1.2.0", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "0b548f2b5fff44c9bcc67b4e3638b8e3": { - "model_module": "@jupyter-widgets/base", - "model_name": "LayoutModel", - "model_module_version": "1.2.0", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "bf55bb77edd24e8493f5b243bdc9e13c": { - "model_module": "@jupyter-widgets/controls", - "model_name": "SliderStyleModel", - "model_module_version": "1.5.0", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "SliderStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "", - "handle_color": null - } - }, - "99f4c261ee3d4303ab95e85fa8405715": { - "model_module": "@jupyter-widgets/base", - "model_name": "LayoutModel", - "model_module_version": "1.2.0", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - } - } } }, "nbformat": 4, From 262a9efaed05dc6fec3208a08c1856067223e670 Mon Sep 17 00:00:00 2001 From: Mackenzie Mathis Date: Sun, 22 Dec 2024 19:32:55 +0100 Subject: [PATCH 32/33] exec From 1fd7b3b5fa7a25153f0e7a39a80bc6a76ca848b2 Mon Sep 17 00:00:00 2001 From: Mackenzie Mathis Date: Sun, 22 Dec 2024 20:45:58 +0100 Subject: [PATCH 33/33] final --- notebooks/Colab_inference_demo.ipynb | 1221 +++++++++++++++++++++----- 1 file changed, 1013 insertions(+), 208 deletions(-) diff --git a/notebooks/Colab_inference_demo.ipynb b/notebooks/Colab_inference_demo.ipynb index 30259ccd..e5d3888e 100644 --- a/notebooks/Colab_inference_demo.ipynb +++ b/notebooks/Colab_inference_demo.ipynb @@ -7,7 +7,7 @@ "colab_type": "text" }, "source": [ - "\"Open" + "\"Open" ] }, { @@ -46,176 +46,12 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": { "id": "bnFKu6uFAm-z", - "collapsed": true, - "outputId": "7affcbb6-ae7e-43a8-97e1-56029e79dcf4", - "colab": { - "base_uri": "https://localhost:8080/" - } + "collapsed": true }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "fatal: destination path './CellSeg3D' already exists and is not an empty directory.\n", - "Requirement already satisfied: napari-cellseg3d in /usr/local/lib/python3.10/dist-packages (0.2.1)\n", - "Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from napari-cellseg3d) (1.26.4)\n", - "Requirement already satisfied: napari>=0.4.14 in /usr/local/lib/python3.10/dist-packages (from napari[all]>=0.4.14->napari-cellseg3d) (0.5.5)\n", - "Requirement already satisfied: QtPy in /usr/local/lib/python3.10/dist-packages (from napari-cellseg3d) (2.4.2)\n", - "Requirement already satisfied: scikit-image>=0.19.2 in /usr/local/lib/python3.10/dist-packages (from napari-cellseg3d) (0.25.0)\n", - "Requirement already satisfied: matplotlib>=3.4.1 in /usr/local/lib/python3.10/dist-packages (from napari-cellseg3d) (3.8.0)\n", - "Requirement already satisfied: tifffile>=2022.2.9 in /usr/local/lib/python3.10/dist-packages (from napari-cellseg3d) (2024.12.12)\n", - "Requirement already satisfied: imagecodecs>=2023.3.16 in /usr/local/lib/python3.10/dist-packages (from napari-cellseg3d) (2024.9.22)\n", - "Requirement already satisfied: torch>=1.11 in /usr/local/lib/python3.10/dist-packages (from napari-cellseg3d) (2.5.1+cu121)\n", - "Requirement already satisfied: monai>=0.9.0 in /usr/local/lib/python3.10/dist-packages (from monai[einops,nibabel]>=0.9.0->napari-cellseg3d) (1.4.0)\n", - "Requirement already satisfied: itk in /usr/local/lib/python3.10/dist-packages (from napari-cellseg3d) (5.4.0)\n", - "Requirement already satisfied: tqdm in /usr/local/lib/python3.10/dist-packages (from napari-cellseg3d) (4.67.1)\n", - "Requirement already satisfied: pyclesperanto-prototype in /usr/local/lib/python3.10/dist-packages (from napari-cellseg3d) (0.24.5)\n", - "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.4.1->napari-cellseg3d) (1.3.1)\n", - "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.4.1->napari-cellseg3d) (0.12.1)\n", - "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.4.1->napari-cellseg3d) (4.55.3)\n", - "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.4.1->napari-cellseg3d) (1.4.7)\n", - "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.4.1->napari-cellseg3d) (24.2)\n", - "Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.4.1->napari-cellseg3d) (11.0.0)\n", - "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.4.1->napari-cellseg3d) (3.2.0)\n", - "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.4.1->napari-cellseg3d) (2.8.2)\n", - "Requirement already satisfied: einops in /usr/local/lib/python3.10/dist-packages (from monai[einops,nibabel]>=0.9.0->napari-cellseg3d) (0.8.0)\n", - "Requirement already satisfied: nibabel in /usr/local/lib/python3.10/dist-packages (from monai[einops,nibabel]>=0.9.0->napari-cellseg3d) (5.3.2)\n", - "Requirement already satisfied: appdirs>=1.4.4 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (1.4.4)\n", - "Requirement already satisfied: app-model<0.4.0,>=0.3.0 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.3.1)\n", - "Requirement already satisfied: cachey>=0.2.1 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.2.1)\n", - "Requirement already satisfied: certifi>=2018.1.18 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2024.12.14)\n", - "Requirement already satisfied: dask>=2021.10.0 in /usr/local/lib/python3.10/dist-packages (from dask[array]>=2021.10.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2024.10.0)\n", - "Requirement already satisfied: imageio!=2.22.1,>=2.20 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2.36.1)\n", - "Requirement already satisfied: jsonschema>=3.2.0 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (4.23.0)\n", - "Requirement already satisfied: lazy_loader>=0.2 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.4)\n", - "Requirement already satisfied: magicgui>=0.7.0 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.10.0)\n", - "Requirement already satisfied: napari-console>=0.1.1 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.1.3)\n", - "Requirement already satisfied: napari-plugin-engine>=0.1.9 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.2.0)\n", - "Requirement already satisfied: napari-svg>=0.1.8 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.2.0)\n", - "Requirement already satisfied: npe2>=0.7.6 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.7.7)\n", - "Requirement already satisfied: numpydoc>=0.9.2 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (1.8.0)\n", - "Requirement already satisfied: pandas>=1.3.0 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2.2.2)\n", - "Requirement already satisfied: pint>=0.17 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.24.4)\n", - "Requirement already satisfied: psutil>=5.0 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (5.9.5)\n", - "Requirement already satisfied: psygnal>=0.5.0 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.11.1)\n", - "Requirement already satisfied: pydantic>=1.9.0 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2.10.3)\n", - "Requirement already satisfied: pygments>=2.6.0 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2.18.0)\n", - "Requirement already satisfied: PyOpenGL>=3.1.0 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (3.1.7)\n", - "Requirement already satisfied: PyYAML>=5.1 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (6.0.2)\n", - "Requirement already satisfied: scipy>=1.5.4 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (1.13.1)\n", - "Requirement already satisfied: superqt>=0.6.7 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.7.0)\n", - "Requirement already satisfied: toolz>=0.10.0 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.12.1)\n", - "Requirement already satisfied: typing_extensions>=4.2.0 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (4.12.2)\n", - "Requirement already satisfied: vispy<0.15,>=0.14.1 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.14.3)\n", - "Requirement already satisfied: wrapt>=1.11.1 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (1.17.0)\n", - "Requirement already satisfied: napari-plugin-manager<0.2.0,>=0.1.3 in /usr/local/lib/python3.10/dist-packages (from napari[all]>=0.4.14->napari-cellseg3d) (0.1.3)\n", - "Requirement already satisfied: networkx>=3.0 in /usr/local/lib/python3.10/dist-packages (from scikit-image>=0.19.2->napari-cellseg3d) (3.4.2)\n", - "Requirement already satisfied: filelock in /usr/local/lib/python3.10/dist-packages (from torch>=1.11->napari-cellseg3d) (3.16.1)\n", - "Requirement already satisfied: jinja2 in /usr/local/lib/python3.10/dist-packages (from torch>=1.11->napari-cellseg3d) (3.1.4)\n", - "Requirement already satisfied: fsspec in /usr/local/lib/python3.10/dist-packages (from torch>=1.11->napari-cellseg3d) (2024.10.0)\n", - "Requirement already satisfied: sympy==1.13.1 in /usr/local/lib/python3.10/dist-packages (from torch>=1.11->napari-cellseg3d) (1.13.1)\n", - "Requirement already satisfied: mpmath<1.4,>=1.1.0 in /usr/local/lib/python3.10/dist-packages (from sympy==1.13.1->torch>=1.11->napari-cellseg3d) (1.3.0)\n", - "Requirement already satisfied: itk-core==5.4.0 in /usr/local/lib/python3.10/dist-packages (from itk->napari-cellseg3d) (5.4.0)\n", - "Requirement already satisfied: itk-numerics==5.4.0 in /usr/local/lib/python3.10/dist-packages (from itk->napari-cellseg3d) (5.4.0)\n", - "Requirement already satisfied: itk-io==5.4.0 in /usr/local/lib/python3.10/dist-packages (from itk->napari-cellseg3d) (5.4.0)\n", - "Requirement already satisfied: itk-filtering==5.4.0 in /usr/local/lib/python3.10/dist-packages (from itk->napari-cellseg3d) (5.4.0)\n", - "Requirement already satisfied: itk-registration==5.4.0 in /usr/local/lib/python3.10/dist-packages (from itk->napari-cellseg3d) (5.4.0)\n", - "Requirement already satisfied: itk-segmentation==5.4.0 in /usr/local/lib/python3.10/dist-packages (from itk->napari-cellseg3d) (5.4.0)\n", - "Requirement already satisfied: pyopencl in /usr/local/lib/python3.10/dist-packages (from pyclesperanto-prototype->napari-cellseg3d) (2024.3)\n", - "Requirement already satisfied: transforms3d in /usr/local/lib/python3.10/dist-packages (from pyclesperanto-prototype->napari-cellseg3d) (0.4.2)\n", - "Requirement already satisfied: in-n-out>=0.1.5 in /usr/local/lib/python3.10/dist-packages (from app-model<0.4.0,>=0.3.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.2.1)\n", - "Requirement already satisfied: pydantic-compat>=0.1.1 in /usr/local/lib/python3.10/dist-packages (from app-model<0.4.0,>=0.3.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.1.2)\n", - "Requirement already satisfied: heapdict in /usr/local/lib/python3.10/dist-packages (from cachey>=0.2.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (1.0.1)\n", - "Requirement already satisfied: click>=8.1 in /usr/local/lib/python3.10/dist-packages (from dask>=2021.10.0->dask[array]>=2021.10.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (8.1.7)\n", - "Requirement already satisfied: cloudpickle>=3.0.0 in /usr/local/lib/python3.10/dist-packages (from dask>=2021.10.0->dask[array]>=2021.10.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (3.1.0)\n", - "Requirement already satisfied: partd>=1.4.0 in /usr/local/lib/python3.10/dist-packages (from dask>=2021.10.0->dask[array]>=2021.10.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (1.4.2)\n", - "Requirement already satisfied: importlib-metadata>=4.13.0 in /usr/local/lib/python3.10/dist-packages (from dask>=2021.10.0->dask[array]>=2021.10.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (8.5.0)\n", - "Requirement already satisfied: attrs>=22.2.0 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=3.2.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (24.3.0)\n", - "Requirement already satisfied: jsonschema-specifications>=2023.03.6 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=3.2.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2024.10.1)\n", - "Requirement already satisfied: referencing>=0.28.4 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=3.2.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.35.1)\n", - "Requirement already satisfied: rpds-py>=0.7.1 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=3.2.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.22.3)\n", - "Requirement already satisfied: docstring-parser>=0.7 in /usr/local/lib/python3.10/dist-packages (from magicgui>=0.7.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.16)\n", - "Requirement already satisfied: IPython>=7.7.0 in /usr/local/lib/python3.10/dist-packages (from napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (7.34.0)\n", - "Requirement already satisfied: ipykernel>=5.2.0 in /usr/local/lib/python3.10/dist-packages (from napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (5.5.6)\n", - "Requirement already satisfied: qtconsole!=4.7.6,!=5.4.2,>=4.5.1 in /usr/local/lib/python3.10/dist-packages (from napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (5.6.1)\n", - "Requirement already satisfied: pip in /usr/local/lib/python3.10/dist-packages (from napari-plugin-manager<0.2.0,>=0.1.3->napari[all]>=0.4.14->napari-cellseg3d) (24.1.2)\n", - "Requirement already satisfied: build>=1 in /usr/local/lib/python3.10/dist-packages (from npe2>=0.7.6->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (1.2.2.post1)\n", - "Requirement already satisfied: rich in /usr/local/lib/python3.10/dist-packages (from npe2>=0.7.6->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (13.9.4)\n", - "Requirement already satisfied: tomli-w in /usr/local/lib/python3.10/dist-packages (from npe2>=0.7.6->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (1.1.0)\n", - "Requirement already satisfied: tomli in /usr/local/lib/python3.10/dist-packages (from npe2>=0.7.6->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2.2.1)\n", - "Requirement already satisfied: typer in /usr/local/lib/python3.10/dist-packages (from npe2>=0.7.6->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.15.1)\n", - "Requirement already satisfied: sphinx>=6 in /usr/local/lib/python3.10/dist-packages (from numpydoc>=0.9.2->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (8.1.3)\n", - "Requirement already satisfied: tabulate>=0.8.10 in /usr/local/lib/python3.10/dist-packages (from numpydoc>=0.9.2->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.9.0)\n", - "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.10/dist-packages (from pandas>=1.3.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2024.2)\n", - "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.10/dist-packages (from pandas>=1.3.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2024.2)\n", - "Requirement already satisfied: platformdirs>=2.1.0 in /usr/local/lib/python3.10/dist-packages (from pint>=0.17->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (4.3.6)\n", - "Requirement already satisfied: flexcache>=0.3 in /usr/local/lib/python3.10/dist-packages (from pint>=0.17->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.3)\n", - "Requirement already satisfied: flexparser>=0.4 in /usr/local/lib/python3.10/dist-packages (from pint>=0.17->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.4)\n", - "Requirement already satisfied: annotated-types>=0.6.0 in /usr/local/lib/python3.10/dist-packages (from pydantic>=1.9.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.7.0)\n", - "Requirement already satisfied: pydantic-core==2.27.1 in /usr/local/lib/python3.10/dist-packages (from pydantic>=1.9.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2.27.1)\n", - "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil>=2.7->matplotlib>=3.4.1->napari-cellseg3d) (1.17.0)\n", - "Requirement already satisfied: pooch>=1.6.0 in /usr/local/lib/python3.10/dist-packages (from scikit-image[data]>=0.19.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (1.8.2)\n", - "Requirement already satisfied: freetype-py in /usr/local/lib/python3.10/dist-packages (from vispy<0.15,>=0.14.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2.5.1)\n", - "Requirement already satisfied: hsluv in /usr/local/lib/python3.10/dist-packages (from vispy<0.15,>=0.14.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (5.0.4)\n", - "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2->torch>=1.11->napari-cellseg3d) (3.0.2)\n", - "Requirement already satisfied: triangle in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (20230923)\n", - "Requirement already satisfied: numba>=0.57.1 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.60.0)\n", - "Requirement already satisfied: zarr>=2.12.0 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2.18.3)\n", - "Requirement already satisfied: importlib-resources>=5.12 in /usr/local/lib/python3.10/dist-packages (from nibabel->monai[einops,nibabel]>=0.9.0->napari-cellseg3d) (6.4.5)\n", - "Requirement already satisfied: pytools>=2024.1.5 in /usr/local/lib/python3.10/dist-packages (from pyopencl->pyclesperanto-prototype->napari-cellseg3d) (2024.1.21)\n", - "Requirement already satisfied: pyproject_hooks in /usr/local/lib/python3.10/dist-packages (from build>=1->npe2>=0.7.6->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (1.2.0)\n", - "Requirement already satisfied: zipp>=3.20 in /usr/local/lib/python3.10/dist-packages (from importlib-metadata>=4.13.0->dask>=2021.10.0->dask[array]>=2021.10.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (3.21.0)\n", - "Requirement already satisfied: ipython-genutils in /usr/local/lib/python3.10/dist-packages (from ipykernel>=5.2.0->napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.2.0)\n", - "Requirement already satisfied: traitlets>=4.1.0 in /usr/local/lib/python3.10/dist-packages (from ipykernel>=5.2.0->napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (5.7.1)\n", - "Requirement already satisfied: jupyter-client in /usr/local/lib/python3.10/dist-packages (from ipykernel>=5.2.0->napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (6.1.12)\n", - "Requirement already satisfied: tornado>=4.2 in /usr/local/lib/python3.10/dist-packages (from ipykernel>=5.2.0->napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (6.3.3)\n", - "Requirement already satisfied: setuptools>=18.5 in /usr/local/lib/python3.10/dist-packages (from IPython>=7.7.0->napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (75.1.0)\n", - "Requirement already satisfied: jedi>=0.16 in /usr/local/lib/python3.10/dist-packages (from IPython>=7.7.0->napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.19.2)\n", - "Requirement already satisfied: decorator in /usr/local/lib/python3.10/dist-packages (from IPython>=7.7.0->napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (4.4.2)\n", - "Requirement already satisfied: pickleshare in /usr/local/lib/python3.10/dist-packages (from IPython>=7.7.0->napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.7.5)\n", - "Requirement already satisfied: prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from IPython>=7.7.0->napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (3.0.48)\n", - "Requirement already satisfied: backcall in /usr/local/lib/python3.10/dist-packages (from IPython>=7.7.0->napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.2.0)\n", - "Requirement already satisfied: matplotlib-inline in /usr/local/lib/python3.10/dist-packages (from IPython>=7.7.0->napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.1.7)\n", - "Requirement already satisfied: pexpect>4.3 in /usr/local/lib/python3.10/dist-packages (from IPython>=7.7.0->napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (4.9.0)\n", - "Requirement already satisfied: llvmlite<0.44,>=0.43.0dev0 in /usr/local/lib/python3.10/dist-packages (from numba>=0.57.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.43.0)\n", - "Requirement already satisfied: locket in /usr/local/lib/python3.10/dist-packages (from partd>=1.4.0->dask>=2021.10.0->dask[array]>=2021.10.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (1.0.0)\n", - "Requirement already satisfied: requests>=2.19.0 in /usr/local/lib/python3.10/dist-packages (from pooch>=1.6.0->scikit-image[data]>=0.19.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2.32.3)\n", - "Requirement already satisfied: jupyter-core in /usr/local/lib/python3.10/dist-packages (from qtconsole!=4.7.6,!=5.4.2,>=4.5.1->napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (5.7.2)\n", - "Requirement already satisfied: sphinxcontrib-applehelp>=1.0.7 in /usr/local/lib/python3.10/dist-packages (from sphinx>=6->numpydoc>=0.9.2->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2.0.0)\n", - "Requirement already satisfied: sphinxcontrib-devhelp>=1.0.6 in /usr/local/lib/python3.10/dist-packages (from sphinx>=6->numpydoc>=0.9.2->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2.0.0)\n", - "Requirement already satisfied: sphinxcontrib-htmlhelp>=2.0.6 in /usr/local/lib/python3.10/dist-packages (from sphinx>=6->numpydoc>=0.9.2->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2.1.0)\n", - "Requirement already satisfied: sphinxcontrib-jsmath>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from sphinx>=6->numpydoc>=0.9.2->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (1.0.1)\n", - "Requirement already satisfied: sphinxcontrib-qthelp>=1.0.6 in /usr/local/lib/python3.10/dist-packages (from sphinx>=6->numpydoc>=0.9.2->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2.0.0)\n", - "Requirement already satisfied: sphinxcontrib-serializinghtml>=1.1.9 in /usr/local/lib/python3.10/dist-packages (from sphinx>=6->numpydoc>=0.9.2->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2.0.0)\n", - "Requirement already satisfied: docutils<0.22,>=0.20 in /usr/local/lib/python3.10/dist-packages (from sphinx>=6->numpydoc>=0.9.2->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.21.2)\n", - "Requirement already satisfied: snowballstemmer>=2.2 in /usr/local/lib/python3.10/dist-packages (from sphinx>=6->numpydoc>=0.9.2->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2.2.0)\n", - "Requirement already satisfied: babel>=2.13 in /usr/local/lib/python3.10/dist-packages (from sphinx>=6->numpydoc>=0.9.2->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2.16.0)\n", - "Requirement already satisfied: alabaster>=0.7.14 in /usr/local/lib/python3.10/dist-packages (from sphinx>=6->numpydoc>=0.9.2->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (1.0.0)\n", - "Requirement already satisfied: imagesize>=1.3 in /usr/local/lib/python3.10/dist-packages (from sphinx>=6->numpydoc>=0.9.2->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (1.4.1)\n", - "Requirement already satisfied: pyconify>=0.1.4 in /usr/local/lib/python3.10/dist-packages (from superqt[iconify]>=0.6.1->magicgui>=0.7.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.1.6)\n", - "Requirement already satisfied: asciitree in /usr/local/lib/python3.10/dist-packages (from zarr>=2.12.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.3.3)\n", - "Requirement already satisfied: numcodecs>=0.10.0 in /usr/local/lib/python3.10/dist-packages (from zarr>=2.12.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.13.1)\n", - "Requirement already satisfied: fasteners in /usr/local/lib/python3.10/dist-packages (from zarr>=2.12.0->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.19)\n", - "Requirement already satisfied: PyQt5!=5.15.0,>=5.13.2 in /usr/local/lib/python3.10/dist-packages (from napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (5.15.11)\n", - "Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.10/dist-packages (from rich->npe2>=0.7.6->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (3.0.0)\n", - "Requirement already satisfied: shellingham>=1.3.0 in /usr/local/lib/python3.10/dist-packages (from typer->npe2>=0.7.6->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (1.5.4)\n", - "Requirement already satisfied: parso<0.9.0,>=0.8.4 in /usr/local/lib/python3.10/dist-packages (from jedi>=0.16->IPython>=7.7.0->napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.8.4)\n", - "Requirement already satisfied: pyzmq>=13 in /usr/local/lib/python3.10/dist-packages (from jupyter-client->ipykernel>=5.2.0->napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (24.0.1)\n", - "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.10/dist-packages (from markdown-it-py>=2.2.0->rich->npe2>=0.7.6->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.1.2)\n", - "Requirement already satisfied: ptyprocess>=0.5 in /usr/local/lib/python3.10/dist-packages (from pexpect>4.3->IPython>=7.7.0->napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.7.0)\n", - "Requirement already satisfied: wcwidth in /usr/local/lib/python3.10/dist-packages (from prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0->IPython>=7.7.0->napari-console>=0.1.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (0.2.13)\n", - "Requirement already satisfied: PyQt5-sip<13,>=12.15 in /usr/local/lib/python3.10/dist-packages (from PyQt5!=5.15.0,>=5.13.2->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (12.16.1)\n", - "Requirement already satisfied: PyQt5-Qt5<5.16.0,>=5.15.2 in /usr/local/lib/python3.10/dist-packages (from PyQt5!=5.15.0,>=5.13.2->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (5.15.16)\n", - "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests>=2.19.0->pooch>=1.6.0->scikit-image[data]>=0.19.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (3.4.0)\n", - "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests>=2.19.0->pooch>=1.6.0->scikit-image[data]>=0.19.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (3.10)\n", - "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests>=2.19.0->pooch>=1.6.0->scikit-image[data]>=0.19.1->napari>=0.4.14->napari[all]>=0.4.14->napari-cellseg3d) (2.2.3)\n" - ] - } - ], + "outputs": [], "source": [ "#@markdown ##Install CellSeg3D and grab demo data\n", "!git clone https://github.com/AdaptiveMotorControlLab/CellSeg3d.git --branch main --single-branch ./CellSeg3D\n", @@ -236,22 +72,9 @@ "cell_type": "code", "execution_count": null, "metadata": { - "id": "vzm75tE_Am-0", - "outputId": "4ec61a88-e6de-421a-88d5-84c785bfcf54", - "colab": { - "base_uri": "https://localhost:8080/" - } + "id": "vzm75tE_Am-0" }, - "outputs": [ - { - "output_type": "stream", - "name": "stderr", - "text": [ - "/usr/local/lib/python3.10/dist-packages/pytools/persistent_dict.py:52: RecommendedHashNotFoundWarning: Unable to import recommended hash 'siphash24.siphash13', falling back to 'hashlib.sha256'. Run 'python3 -m pip install siphash24' to install the recommended hash.\n", - " warn(\"Unable to import recommended hash 'siphash24.siphash13', \"\n" - ] - } - ], + "outputs": [], "source": [ "# @title Load libraries\n", "import napari_cellseg3d\n", @@ -328,11 +151,30 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": { - "id": "O0jLRpARAm-0" + "id": "O0jLRpARAm-0", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "outputId": "e4e8549c-7100-4c0c-bc30-505c0dfeb138" }, - "outputs": [], + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "'cupy backend (experimental)'" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "string" + } + }, + "metadata": {}, + "execution_count": 4 + } + ], "source": [ "demo_image_path = \"/content/CellSeg3D/examples/c5image.tif\"\n", "demo_image = imread(demo_image_path)\n", @@ -355,14 +197,26 @@ { "cell_type": "code", "source": [ - "model_selection = \"WNet3D\" #@param [\"SwinUNetR\", \"WNet3D\", \"SegResNet\"]\n", + "model_selection = \"SwinUNetR\" #@param [\"SwinUNetR\", \"WNet3D\", \"SegResNet\"]\n", "print(f\"Selected model: {model_selection}\")" ], "metadata": { - "id": "5tkEI1q-loqB" + "id": "5tkEI1q-loqB", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "d41875da-3879-4158-8a0f-6330afe442af" }, - "execution_count": null, - "outputs": [] + "execution_count": 5, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Selected model: SwinUNetR\n" + ] + } + ] }, { "cell_type": "code", @@ -379,16 +233,87 @@ "metadata": { "id": "aPFS4WTdmPo3" }, - "execution_count": null, + "execution_count": 6, "outputs": [] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": { - "id": "hIEKoyEGAm-0" + "id": "hIEKoyEGAm-0", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "2103baf6-8875-433b-8799-41e0d1f3c7f0" }, - "outputs": [], + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "--------------------\n", + "Parameters summary :\n", + "Model is : SwinUNetR\n", + "Window inference is enabled\n", + "Window size is 64\n", + "Window overlap is 0.25\n", + "Dataset loaded on cuda device\n", + "--------------------\n", + "MODEL DIMS : [64, 64, 64]\n", + "Model name : SwinUNetR\n", + "Instantiating model...\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "monai.networks.nets.swin_unetr SwinUNETR.__init__:img_size: Argument `img_size` has been deprecated since version 1.3. It will be removed in version 1.5. The img_size argument is not required anymore and checks on the input size are run during forward().\n", + "INFO:napari_cellseg3d.utils:********************\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Loading weights...\n" + ] + }, + { + "output_type": "stream", + "name": "stderr", + "text": [ + "INFO:napari_cellseg3d.utils:Downloading the model from HuggingFace https://huggingface.co/C-Achard/cellseg3d/resolve/main/SwinUNetR_latest.tar.gz....\n", + "270729216B [00:10, 26012663.01B/s] \n", + "You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Weights status : \n", + "Done\n", + "--------------------\n", + "Parameters summary :\n", + "Model is : SwinUNetR\n", + "Window inference is enabled\n", + "Window size is 64\n", + "Window overlap is 0.25\n", + "Dataset loaded on cuda device\n", + "--------------------\n", + "Loading layer\n", + "2024-12-22 18:58:42,183 - INFO - Apply pending transforms - lazy: False, pending: 0, upcoming 'QuantileNormalization', transform is not lazy\n", + "2024-12-22 18:58:42,279 - INFO - Apply pending transforms - lazy: False, pending: 0, upcoming 'ToTensor', transform is not lazy\n", + "2024-12-22 18:58:42,290 - INFO - Apply pending transforms - lazy: False, pending: 0, upcoming 'EnsureType', transform is not lazy\n", + "Done\n", + "----------\n", + "Inference started on layer...\n", + "Post-processing...\n", + "Layer prediction saved as : volume_SwinUNetR_pred_1_2024_12_22_18_58_48\n" + ] + } + ], "source": [ "result = cs3d.inference_on_images(\n", " demo_image,\n", @@ -398,15 +323,35 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": { "id": "IFbmZ3_zAm-1", - "cellView": "form" + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "bde6a6c5-f47f-4164-9e1c-3bf5a94dd00d" }, - "outputs": [], + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "1it [00:00, 9.61it/s]\n", + "clesperanto's cupy / CUDA backend is experimental. Please use it with care. The following functions are known to cause issues in the CUDA backend:\n", + "affine_transform, apply_vector_field, create(uint64), create(int32), create(int64), resample, scale, spots_to_pointlist\n", + "divide by zero encountered in scalar divide\n", + "invalid value encountered in scalar multiply\n", + "WARNING:napari_cellseg3d.utils:0 invalid sphericities were set to NaN. This occurs for objects with a volume of 1 pixel.\n" + ] + } + ], "source": [ "# @title Post-process the result\n", "# @markdown This cell post-processes the result of the inference : thresholding, instance segmentation, and statistics.\n", + "\n", + "if model_selection == \"WNet3D\":\n", + " result[0].semantic_segmentation = result[0].semantic_segmentation[1]\n", + "\n", "instance_segmentation,stats = cs3d.post_processing(\n", " result[0].semantic_segmentation,\n", " config=post_process_config,\n", @@ -415,11 +360,67 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": { - "id": "TMRiQ-m4Am-1" + "id": "TMRiQ-m4Am-1", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 496, + "referenced_widgets": [ + "7a72ee57e14c440bb2ce281da67e1311", + "2692114df7304a1cbc703e8bd0f848c3", + "697f7288fff64aefbee1a5c0d4894987", + "1e79fde882a44cd984a54a71c3337759", + "9cb58613b1a74eaeb285f6d2d77d567b", + "a1d487697e4b4ea6b897f380c2b112cc", + "10441f745a6f41cf8655b2fafbb8204f" + ] + }, + "outputId": "2d819126-5478-4d98-a5e2-ecacb7872465" }, - "outputs": [], + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "interactive(children=(IntSlider(value=62, description='z', max=123), Output()), _dom_classes=('widget-interact…" + ], + "application/vnd.jupyter.widget-view+json": { + "version_major": 2, + "version_minor": 0, + "model_id": "7a72ee57e14c440bb2ce281da67e1311" + } + }, + "metadata": {} + }, + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "
\n", + "
update_plot
def update_plot(z)
/content/<ipython-input-9-245acde924e0><no docstring>
" + ] + }, + "metadata": {}, + "execution_count": 9 + } + ], "source": [ "# @title Display the result\n", "#@markdown This cell displays the result of the inference and post-processing. Use the slider to navigate through the z-stack.\n", @@ -461,11 +462,516 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": { - "id": "Tw5exJ5EAm-1" + "id": "Tw5exJ5EAm-1", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 424 + }, + "outputId": "3aa36115-0b22-495b-b7e9-3eba7c06069a" }, - "outputs": [], + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + " Volume Centroid x Centroid y Centroid z Sphericity (axes) \\\n", + "0 190.0 5.405263 69.157895 36.210526 0.778113 \n", + "1 18.0 5.833333 85.000000 83.944444 0.000007 \n", + "2 67.0 7.283582 65.492537 92.059701 0.867751 \n", + "3 108.0 10.324074 84.342593 68.861111 0.672490 \n", + "4 35.0 9.428571 84.314286 92.600000 0.649649 \n", + ".. ... ... ... ... ... \n", + "317 11.0 122.363636 14.727273 25.000000 0.951651 \n", + "318 24.0 122.166667 26.083333 38.083333 0.990075 \n", + "319 16.0 122.125000 34.125000 36.500000 0.944672 \n", + "320 13.0 122.076923 43.538462 53.615385 0.939852 \n", + "321 21.0 122.523810 49.666667 36.238095 0.895437 \n", + "\n", + " Image size Total image volume Total object volume (pixels) \\\n", + "0 (124, 86, 94) 1002416 33504.0 \n", + "1 \n", + "2 \n", + "3 \n", + "4 \n", + ".. ... ... ... \n", + "317 \n", + "318 \n", + "319 \n", + "320 \n", + "321 \n", + "\n", + " Filling ratio Number objects \n", + "0 0.033423 322 \n", + "1 \n", + "2 \n", + "3 \n", + "4 \n", + ".. ... ... \n", + "317 \n", + "318 \n", + "319 \n", + "320 \n", + "321 \n", + "\n", + "[322 rows x 10 columns]" + ], + "text/html": [ + "\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
VolumeCentroid xCentroid yCentroid zSphericity (axes)Image sizeTotal image volumeTotal object volume (pixels)Filling ratioNumber objects
0190.05.40526369.15789536.2105260.778113(124, 86, 94)100241633504.00.033423322
118.05.83333385.00000083.9444440.000007
267.07.28358265.49253792.0597010.867751
3108.010.32407484.34259368.8611110.672490
435.09.42857184.31428692.6000000.649649
.................................
31711.0122.36363614.72727325.0000000.951651
31824.0122.16666726.08333338.0833330.990075
31916.0122.12500034.12500036.5000000.944672
32013.0122.07692343.53846253.6153850.939852
32121.0122.52381049.66666736.2380950.895437
\n", + "

322 rows × 10 columns

\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + "\n", + "\n", + "\n", + " \n", + "
\n", + "\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "data", + "summary": "{\n \"name\": \"data\",\n \"rows\": 322,\n \"fields\": [\n {\n \"column\": \"Volume\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 54.38970963263131,\n \"min\": 8.0,\n \"max\": 252.0,\n \"num_unique_values\": 157,\n \"samples\": [\n 14.0,\n 124.0,\n 169.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Centroid x\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 31.084053076294715,\n \"min\": 5.405263157894737,\n \"max\": 122.52380952380952,\n \"num_unique_values\": 321,\n \"samples\": [\n 73.65806451612903,\n 60.0,\n 81.18303571428571\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Centroid y\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 25.419664210044758,\n \"min\": 0.0,\n \"max\": 85.0,\n \"num_unique_values\": 320,\n \"samples\": [\n 0.6310679611650486,\n 1.7452229299363058,\n 13.709401709401709\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Centroid z\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 27.685581861438635,\n \"min\": 0.12903225806451613,\n \"max\": 93.0,\n \"num_unique_values\": 320,\n \"samples\": [\n 12.174757281553399,\n 10.108695652173912,\n 70.51282051282051\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Sphericity (axes)\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0.12590741777097128,\n \"min\": 5.583882595237912e-06,\n \"max\": 0.9900749841550203,\n \"num_unique_values\": 318,\n \"samples\": [\n 0.8007911710122612,\n 0.8283576063212563,\n 0.7547372074750549\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Image size\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"\",\n [\n 124,\n 86,\n 94\n ]\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Total image volume\",\n \"properties\": {\n \"dtype\": \"date\",\n \"min\": \"1970-01-01 00:00:00.001002416\",\n \"max\": \"1970-01-01 00:00:00.001002416\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"\",\n 1002416\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Total object volume (pixels)\",\n \"properties\": {\n \"dtype\": \"date\",\n \"min\": \"1970-01-01 00:00:00.000033504\",\n \"max\": \"1970-01-01 00:00:00.000033504\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"\",\n 33504.0\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Filling ratio\",\n \"properties\": {\n \"dtype\": \"date\",\n \"min\": \"1970-01-01 00:00:00\",\n \"max\": \"1970-01-01 00:00:00\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"\",\n 0.03342324942937862\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Number objects\",\n \"properties\": {\n \"dtype\": \"date\",\n \"min\": \"1970-01-01 00:00:00.000000322\",\n \"max\": \"1970-01-01 00:00:00.000000322\",\n \"num_unique_values\": 2,\n \"samples\": [\n \"\",\n 322\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {} + } + ], "source": [ "# @title Display the statistics\n", "# @markdown This cell displays the statistics of the post-processed result.\n", @@ -476,11 +982,56 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": { - "id": "0NhZ-YksAm-1" + "id": "0NhZ-YksAm-1", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 617 + }, + "outputId": "15904f15-5b1c-4b04-8b09-265c42a20e3a" }, - "outputs": [], + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/html": [ + "\n", + "\n", + "\n", + "
\n", + "
\n", + "\n", + "" + ] + }, + "metadata": {} + } + ], "source": [ "# @title Plot the a 3D view, with statistics\n", "# @markdown This cell plots a 3D view of the cells, with the volume as the size of the points and the sphericity as the color.\n", @@ -518,7 +1069,7 @@ " title=f'Total number of cells : {int(data[\"Number objects\"][0])}',\n", " )\n", "\n", - " fig.show(renderer=\"colab\")\n", + " fig.show()\n", "\n", "plotly_cells_stats(data)" ] @@ -537,8 +1088,262 @@ }, "language_info": { "name": "python" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "7a72ee57e14c440bb2ce281da67e1311": { + "model_module": "@jupyter-widgets/controls", + "model_name": "VBoxModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [ + "widget-interact" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "VBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "VBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_2692114df7304a1cbc703e8bd0f848c3", + "IPY_MODEL_697f7288fff64aefbee1a5c0d4894987" + ], + "layout": "IPY_MODEL_1e79fde882a44cd984a54a71c3337759" + } + }, + "2692114df7304a1cbc703e8bd0f848c3": { + "model_module": "@jupyter-widgets/controls", + "model_name": "IntSliderModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "IntSliderModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "IntSliderView", + "continuous_update": true, + "description": "z", + "description_tooltip": null, + "disabled": false, + "layout": "IPY_MODEL_9cb58613b1a74eaeb285f6d2d77d567b", + "max": 123, + "min": 0, + "orientation": "horizontal", + "readout": true, + "readout_format": "d", + "step": 1, + "style": "IPY_MODEL_a1d487697e4b4ea6b897f380c2b112cc", + "value": 62 + } + }, + "697f7288fff64aefbee1a5c0d4894987": { + "model_module": "@jupyter-widgets/output", + "model_name": "OutputModel", + "model_module_version": "1.0.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/output", + "_model_module_version": "1.0.0", + "_model_name": "OutputModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/output", + "_view_module_version": "1.0.0", + "_view_name": "OutputView", + "layout": "IPY_MODEL_10441f745a6f41cf8655b2fafbb8204f", + "msg_id": "", + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": "
", + "image/png": "iVBORw0KGgoAAAANSUhEUgAABLkAAAFoCAYAAAC7YSngAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAADbmUlEQVR4nOy9eZikV132/629urq6a7pnn2QmTDYmQBYIMRkIiBCJyOsLEhB5UVDy6gsGlAS3qCAoEsUFRAMoPwyyySKyKiAGCVsSQgAJhMlGwiSZfaa36upauqp+fwx5nvt7Vz+npifTk66e+3Ndc13PmXOec75n76mp++5Ut9vtmhBCCCGEEEIIIYQQA0z6kQ5ACCGEEEIIIYQQQoiHiz7kEkIIIYQQQgghhBADjz7kEkIIIYQQQgghhBADjz7kEkIIIYQQQgghhBADjz7kEkIIIYQQQgghhBADjz7kEkIIIYQQQgghhBADjz7kEkIIIYQQQgghhBADjz7kEkIIIYQQQgghhBADjz7kEkIIIYQQQgghhBADjz7kEkIIIYQQQgghhBADz5J9yHXttdfaox71KCsWi3bhhRfaN77xjaVqSgghxAmI7hkhhBBLie4ZIYQYPFLdbrd7rCv98Ic/bC95yUvsne98p1144YX21re+1T760Y/aHXfcYevWrQu+2+l0bNeuXTYyMmKpVOpYhyaEECcc3W7XZmZmbNOmTZZOr4wv8D6ce8ZMd40QQhxrVtpdo3tGCCGWF0d8z3SXgJ/4iZ/oXnHFFVG63W53N23a1L3mmmv6vnv//fd3zUx/9Ed/9Ed/jvGf+++/fymO/EeEh3PPdLu6a/RHf/RHf5bqz0q5a3TP6I/+6I/+LM8//e6ZrB1jms2m3XrrrXb11VdHf5dOp+2SSy6xG2+8sad8o9GwRqMRpbs//mJZpVKJ/tej0+n05D8E/89IJpNJjA3fxToXqif0ySC/W6lUouds1g/p9PS0SzebzcR6Qm0w2A6PCaexL9xPLou02+3EeszCY43xz8/PH3GbrVYr2GY+n0+MD9cRv5vL5RLjwzrNevuFZXH+FiK0VpmhoaHEsnNzc4nxcF+wn6VSKTEeM78e+/WlWCxGzzyHOPaFQiEYH84p18NgvaF1bObHj/Pq9bpL437hPYrwePHYh+Z0MfuZ1xyCc89lefy4nzgXGGu327VGo2EjIyOJ7Q4Si71nzJLvmov+bKdli6NmZjZfSJ7fbsbnZevxmmvnfF6mFZ+z3eRj0szMUu3kvPmiXzeN4XjPzo7WXN7oIT+3qXYcX7bh9wf2Bfth1tuXUF6+xvXGz520Lxt6l8eonUveS6m2v8NC8XYpBhwHfo/LpjpxO2kKp0M/HuC7+B7nZeYp9iytm/kj/6YHvstthuB+tnPxAkxTPdkG3YXQ706uTXm8B+J3uxn6eavtBxDjD80D580XWlT2yL851M4lbzyM/XC7cfydTPheR3INf9ekod7ZsVkfT9af7aG+ZFtZSsf18nvcF9cmjQGWbZb8zwcd2gTZhHrbczN22/87Y0XcNcfynhFCCHFs6XfPHPMPuQ4cOGDtdtvWr1/v/n79+vW2Y8eOnvLXXHONveENb+j5+1QqFX0gE/qKL+cd6deB+72H/2ju98EaluV/bHMa311MvxabfzRt9mtjMWN9PNo8VmUfTj3Mw+nrsYivnzzgaPuyHMbveMRwtOfJsaz3WPVzsTEOEou9Z8yS75pscdSyQ4c/5LLFfMiVgv884A+5ssfmQy6jD7nm4R+emWFfcaY+6tJp/JArHfiQK0V3VOBDI87Ldo/8Q67QuzxGqUV8yBWKt2fO0slzxmWxnb4fcsG7HB/m4YefC8XA+SHwXW4zBPfTQh9ypZM/5Grn/cJN8QeK8CFIhz7kSvOHXG3cL8nzwHndh/Ehlx3lh1ypRXzIlcn4H7EzzbjeTIkWfY4+5Gon9yVDH3JlAh9yJX0YdbhNPwZYtk0fcqVoE4Q+PDNbGXfNsbxnhBBCHFv63TOPuGD+6quvtqmpqejP/fff/0iHJIQQYoWhu0YIIcRSontGCCGWB8f8m1xr1qyxTCZje/fudX+/d+9e27BhQ0/5QqHQI3cy89+eQokOy3X4UzyUWLEkCCVDLB/ib8CgpInLstwJv5pcq3kJCYN95b6gfIyleNwm1sOSqpA8kMeL68V3Z2f91+lD32jjvJDEj8ca+9rvU9lQWZ7vUF04Zv3WFOaHpIyhNsx6+40yPh4/lOL1k9Dh+FarVZcXmrPQmud2WQqK64/HiyWnobEOjV9oTXE+rzGOKbRusF4eAzaWxfHleLjfLBdMyuO6QvHxGg/Je0P7c9BZ7D1jlnzXzBe60Te4SvfEZ17z5LIr1yiT3G4q8G2jRjwv7TLJi1uhbx7R+Vzz6aEDcfyjhaLLS1E42A594crmS/DtY7+EeqRvuSnYOy1/L3XTtFZLIKOnvmTq1O9OXNd8mb+VRt+Ihr40Ki7LhibSkEeyuBZLt5LvhDRJOvGbaPxezzfPQt/GA1giWSS5J8plsw0aW7+MLEPzFoon9A27wkycyWshWyVJYgG/fecDatPWwjbbufC9noF5Yqkq5nG/eF6wbKvg6+Fvnlngm0i5ur8HcrA2miX6Bht9iw6/8BSSAq+518ssOi/7K5fe8cBToud1dz3Gl6VvxhUn4p8Xciwhpr3fLIGlQoFlpHG/hw/586U57O9u/jZeVEcjt+DfDyLH8p4RQohHmu/c/wOXPm/zWY9QJMeHY/5Nrnw+b+eff75df/310d91Oh27/vrrbfv27ce6OSGEECcYumeEEEIsJbpnhBBicDnm3+QyM7vqqqvspS99qT3xiU+0n/iJn7C3vvWtNjs7a7/6q7+6FM0JIYQ4wdA9I4QQYinRPSOEEIPJknzI9cIXvtD2799vr3vd62zPnj123nnn2ec+97ke88YQnU5nQeP5xfymudBvj+v3W95Q3hNqw8z/NrR+v4EQ81mSGJJNhaRkTMiMmt9jGRqOy2IkThwfjn1INmoWNvnn8Qv9RkeeU6yX20RZaz85ILIYaR7PL4Px8Rjh+HE83CamQ/GY+XnCMeB4zHz8vAfw6/ihdcwx9PutoaE54zHCdkNySobrxbFGmahZb783btwYPd97770uL/TbIHmMQuuc5yEk/Q399seVYPwb4ljcM2aHzbYfMtxubYwlio0yy6b8eNbWJxt/Z1rxWp1b5fcky8Xcb0ajI6O8OznubJXkWGRknWrH7cx61a2Tus2O+/jmyv63e65+MNYH5qdobZIMDaVRzRGS865P/m18WZLJsRwrV4dzlSR/zeG4LP/GSf4tdEh6ESblaZpf/g17mM95+Fvp2AScy+Jv45sdD/+MktTGgvkwnvm6P9PQqJyN5zvr+WcA+O231GZoTJpF3gP+3aEq/KZhypsHc3ReF62CPw8LNfiNwGTkzvONcjsu2yrQb0XsJJfl8cS+sqSvMBefC81hl2V/X/+wS9976sej53f//cdc3uSTV/t4i+0Fn83M2lmSV0JfeF4wb3qNPweYfCPuC851ux3Q0Q4gx+qeEUKI5QbKF1eidHFJPuQyM3vlK19pr3zlK5eqeiGEECc4umeEEEIsJbpnhBBi8HjEf7uiEEIIIYQQQgghhBAPF33IJYQQQgghhBBCCCEGniWTKz5cUqlU5CmDvjPsZcNeN+gzxGXr9Xr0zF477GWE7/bzBkLYC4h9cWq1WmIexhRqg2EPH+ynmfeq6ucpFfJE4jHDejmG0HscA441ew6F/J24TfZTCnk2YR77GnHZUOycDnlOsW/ZkXrNzc7OHnE9HE/I36nfWsD80H4J+c6Z+fnt56mHa7dSqbg83Dtmfp64Ht772BcePywbOjPMzKrVavQc8pbjNvv5s2FdIV8/bJ/bMPPnRsjrTixMppE8TuxXlAKPrgwdGR1YjvlZWm/kXZRpgUdOya+TZoU81yCZn/L11Nb4d/M1uDczPi9Ti9vM1X185QN+32Xq4D1WJ58o9qtsxWUL5N+Vrft0YyR5TwxN0l1ThHOL/LFy4HM1bCWXl2km+ysy7TyNEbzLllfsC4YxtYp+jAqt5Lsc/aYY9OdaCPQ0yxitE/bLAq+lfC05Hh6DQs3HgP1OtcPx4TrPNej+KPi7Br3K5n1RS3e6C5Yz6/W84nxkqOo9KOfK8dk+emDE5TVL9HMI9KVQ8z/j8VhjPp8ZSHHGd/R9q8516X/b87zo+bFrx3085OuHMaTIe4y90gzOAvasw3rQc2shkjzX2p2V5cklhBArlZXow4Xom1xCCCGEEEIIIYQQYuDRh1xCCCGEEEIIIYQQYuDRh1xCCCGEEEIIIYQQYuBZtp5cnU4n8pth3xkEPbjMvG8Pe9ugXxbnsQ8T+uCwVxGD8bGHD3vhoPcO+25hHr/HXl9Ytp/PUajfExMTlkTIZ8ssPC4YP48tey0dOnQoeubYuW/Y77m5OZfHY4QxcB6+Ozo66vLK5bJLow8SzwvHgGuB55fHC/vKaxz7zWPC/k4hn7LQ3mFCXlqhPI4ntK55Hnh+EY69VPJ+O9gunwOhMeI2MSZ+b9++fYn18loI+ehxHvct5BGH4zcy4r1jQusGPfNEMp10N/K4aRfi8exmkv31zLw/UTdDfl0BCzb2czJL9pti3yr0cGoV/PWNHlwcQ2EmeZ/la+QBV0/2JZuvkL8iDVFtTfxuccr3JVvz9c6OozeQj69Z8hWzV5QvnNy3TCuVmOY2GPSUauX7rIVCHB/7T+GcsUcTe1OVpoagrG+jVvH3aAcKpNmHiV7G8Q15j/XzMMP1yWOLvmlMyHuM603TXjKInccrRGHOn7kcA45ZdZx8L1tH/qMxe2Ah7Wzy/uWxvuMP/8alH1OO18L0ab6Nds57hiG5ed53yePAvmD1kXh8GyN+TDI0JsM1fx9HsdVzC/69EEKIR5aV7sHF6JtcQgghhBBCCCGEEGLg0YdcQgghhBBCCCGEEGLgWbZyxVQqFUlxUHaD0h0zs2Yz+WvbLOWZnp6OnlnexJIwfJdlPxxDNhsPI8u6OI1yIpZuodSSpW0s1RoaGkosG5K3cV9Ymod1heLjulhihePH88CSzvHx+Ndjz86SbCDrlyi2wzJIlpqF5gUlijwmPJ5YD8sTuV4sy/WwvA3b5X7iGHG/QmssFDunuR7eSyFpXkjKGJJI8ljzHIYkfwxK93hPhvYs9yXUT17XPJ5ISKbZb4+GpMEYXz9pKNaDbfD4iJh0JxXJyLow3Swd7JEgwpRl6pZIusX7IXmuM9RGturLtkpxXSxfy9eGXBqlhI2yn/+hibjezAxJwDIkTc7F6WzN18MyzeJUXDbdovOuRBLdgIzPSDWXbh+b/4+bWxX3letsFejMAMkfS98YlCh2AjJXlq+xzBBplHw86TZLL+M2WcbH8s/MPEjaqd8oy+xd8z6dNpCp98huPSEJIk8nqit5m3Uhk/vFEkTsJ8PvNkrx/inUyM6g7O/5ViG+G7Pz/g4oTQ27NK7lTs9eB7lx0c/vzmf4ORyeitdcruHrKU35eEPwEiuA7BDliWZmhVqcN706LHfHsa/DWLatsVBxIYQQ4riib3IJIYQQQgghhBBCiIFHH3IJIYQQQgghhBBCiIFHH3IJIYQQQgghhBBCiIFn2XpyZbPZyNsHvYL6eeSgHxD766B/DXvgsE8UlmUfHPbHwnfZIyfkrcUeSBg7txHy1OExYZ8j9OZhL7KZmRmXxr5y7NwOcqx8mULeaAz3JeSJxPVgWe5XyH+KYd8yrIvXJs9hyLcMx4HHhOcF11GoDY6P80Jprhfnm8eH48Oy/drE+NA3zax3ftG/rVqturxQTDyeIb8uBtcu95PHCPvC9fLeR489XlO4P7hNLovthNa/iEm3zNI/3qqdXHK5FB3BuVrymM6ujecpPxu+ZjPg2cU+R61S8rmfa/h60W/KzGxkV5yfp/O5C8nmGt/pDFnqpNpxTN00eTTVyLenENdVH+e95NMjB+I13yz5O5a9oFwtGV9PyM9pvpg8fuydxZ5X6XbyfZdp0p0BMXFeayQe0PkceWIe8n5OIdD3y4w8rzoce/L/X/LYuthbyXlmfn2yHxZ6Z5l5fyz2IutQva0iz1xyWZ/n28R2eLzmyv5nPPTZ2n/aHS6vvPZuX++OJ0fP3Yyvt1Hy+3Co6n8uQdAXjH3Ucg1/vzWLcT6PQYb8xdBLi88Qnu/pNfG9ue+M213e2M7To+dV+1f5NmldT6+Jf3ZslmIPs3Y3YFAohBBCHCf0TS4hhBBCCCGEEEIIMfDoQy4hhBBCCCGEEEIIMfAsW7liu92OJDYo+2GpUUiWNDzspQBYD8vrWFqGsiSWs4WkeSzFC0nouE2sl6VPIRkV18NjhLKvyclJl8cyJoyB+8L9LpfLiXkheSXnYTso2zLrlYri/HK/OY0yL24T8/g9nm98l8c2BNcbWqs81qH3Qu2wfC0kmeSx5TnEtcvxheaX4w1J5Xissc1169Yl5pmZ7d+/PzEejhf7yv3GGPrJPXGM+kmTj1YuyPOA0uVarebyWPaYtH9D83Wi003H8r0MKG1ahYXLPwRKG1nKiHKx4oTPmy/5tVCvxOsxX6Ozh2MF2VKuTtL9ul836RasP5KzYbwcO8oTD7cZv5upU+EM3YWQXZjyefNege+rIZlcSHLF/UQ6aZIykgoO5WzDEywrI1l4IXDG9cjHQHpO8rDSVLyQ2jl/ZqQD25IliCEJJ/e7MeQlYyjrYzkdrlXuF4MxtMr+vGsV/VlUmop//kp1aG3Sysb4WfYYItsiuwpoh8eL49t8c/xz0b895gqXt/5+X+85W+OyhdsvdHmd9JFLJuchme6Ex7owB5YKJBVs5/3C5v0SAtdGobLH5c0+bl9c5x0XuLzVD651aRz7OozBYuZPCCFOFL5800ww/6kXjRynSE4c9E0uIYQQQgghhBBCCDHw6EMuIYQQQgghhBBCCDHw6EMuIYQQQgghhBBCCDHwLFtPLvT1QV8h9tNhrxv0nmGPnMV4cmE97HMUqpfjQT8dLsv1IP08fDA+9h/ieOv12IOhn6cU1sUxcBrr6udlhBSL3hMEx6Sf9xPWy22wP1HIkwjbDPmmmfm1yOPHZTHNayyU5nWN9fTzUwp5cvFY4xjNzs66PO4bjhGuIY6JY2cwv9++q1Qq0fO2bdsS88zMvve97yXGF/LNC8W7mPOF/cR4/HD9sU9ZyD+OwXe5HMeAZXkMxMK0c11L/djTBr2rilPJflNmYY8p9NZKtens8UvVsgU4B3LhvY4+Q+zZlKsm+/KkwlvU0S76ejP1uN5mhXz7phbhn+Tt5JynWYZ8ttpkl5WGq7JVIg+kXLKfU2HGn+1Dh2Be+sxnvhbH1Bihc6Gd7CGWom2HPlfsPZZp0Rpr43PYp6xZis/yfM33k2mUwJ8yzesEByJ8ZqC3V63i/UXyNe+n2SrEk8beVJl58pgCH6v5XPJizbb8e1wP+ovVR/xZObbb3x87X/Ev0fMpf7jT5U39qOrS9/7mn0bPF9a/6PKaBf9zx8xYPC6r9q9yeSG/Ku6bmyfy4GI/vkYpvmv4XGgX/Lvje8aj551rTnN5hZl4jIpV72k7V/YHF8ZbmIvnvj2X/HOtEEKcSPTz4UoqK3+uY4P+FSSEEEIIIYQQQgghBh59yCWEEEIIIYQQQgghBh59yCWEEEIIIYQQQgghBp5l68mVzWYX9HXq51WFsH8NvsveRextg2n26WH/n1B8c3NzLo3tsk8Pvst+OlwW/ZTYU4r7gvWyvxPHh/nsG8R9w/HlMRoaij0aOL6Q/1RoHsy8p1Q/LyiEY0BqNW8WEyrLnmEMjhl7SIXa5XpxjfHccxrhMWHft5BPFHuaYZrXI84L1xPyKeu3VsvlcvR8zjnnuLyzzz7bpUdHR6PngwcPurypqSmXxnlZjH/cYvy7QmV5/DgGnCdeCyGfLZ4zLIt7sJ+v24lMppWyTPbwGkBPpK5fms5Dysx75mR6/JPAM7FEc99jixjX06H/dgpY+Fhuxu+79CHvsddeE3vqcF9CpMlSp5sBH8QeHys6FxrQlxx7e3Fn4ndTbT7T/LsYP3tVFcDPqzBDPnnkUza3Bryz2tyGL5uB+NCL6seZDlwLhRb9WAUeSezBVR/xg41eS1w23SC/zwPxzxIPvPSDLq/V8efs+s9eFj1zP9EDK9OkdZxPPtPKE+H7Db2q2G8q3fKbAL20GBfffHgh98wTMHTA9+2TtbdFz3u+N+nyvvJ9f64+K3t79Pz6j/6Uy/vTT33Zpdu5+PxuDPl60rDB0+0j/1mWfdTqZV9vCurlsqkO+77F7W6863SXNzcS/zw4tXa/y1t7/yaXLlbjNdaBNdWe87EJIVYG03fdFswfPePsYL44ctjLSx5dR8eiv8n15S9/2X7u537ONm3aZKlUyj7xiU+4/G63a6973ets48aNNjQ0ZJdccondddddxypeIYQQKxzdM0IIIZYS3TNCCLFyWfSHXLOzs3buuefatddeu2D+m9/8Znvb295m73znO+3mm2+24eFhu/TSS4PffhJCCCEeQveMEEKIpUT3jBBCrFwWLVd81rOeZc961rMWzOt2u/bWt77V/uiP/sie85znmJnZe9/7Xlu/fr194hOfsF/8xV884nZGRkYiaU61Gv86Z5YgstwJ5TwsQ8Ky/eQ7WA+XDcnHQlI3My9p6idhCoFlWbLEEjWEy/IYsYwzVBYlYCyxwn6G4uGyPCahGFhOyWC7LCXL5WK5BPern+QvBM4/rwWeX5wLXtehtRCqNzQPXLaf3DM0vqHxC8XOZbkv+MPjjh07XB6vTZTshuSUTCiP2+B5wTS3yX3BukISRK4rJEnkejhdKpUWfC8kcV2OHK97xsxsZt2cZUqH1/PYzljiydK8Zjl5DFkOiFIzlieyHDADMrR2gWWPtE46KB2keFie34nliina6hgTt5ElqSDHm1QPl023SBZH0kbM57KcRsnkPF1RHL+rp8CSMJBVBd4zM8tBX1BGaNYrJWyW4gEO1dsh/SlLy1rFuB6WU+Lcm5nNl+L0kyo3u7w761tdenhHLI2f2VZyeWkY2x7JZtP3G+WLLLfr0LvFGpx/uXawbKEWn50sr0vzOsd4sr7ekJxx19mTLn3V2mdHz/920W6X94TqXpce3RpLRfbl/PiN7PXn/lw5+d4MSRR5jLDfvG566oWyuYZvn6WgPMfI0Ex8/s1n/d0yW/FyaC+R7Cz4vNw5nveMEEKI48sxNZ6/9957bc+ePXbJJZdEf1epVOzCCy+0G2+88Vg2JYQQ4gRE94wQQoilRPeMEEIMNsfUeH7Pnj1mZrZ+/Xr39+vXr4/ymEaj4b4dMT09fSxDEkIIsYI4mnvGTHeNEEKII0P3jBBCDDbH9JtcR8M111xjlUol+rN58+ZHOiQhhBArDN01QgghlhLdM0IIsTw4pt/k2rBhg5mZ7d271zZu3Bj9/d69e+28885b8J2rr77arrrqqig9PT1tmzdvtuHh4cg7p1aL/ST6eV4hXBZ9adibKuSPxR5D7OkT8i5iDyJMo6+RmffXYb8kbhPr4fi4L+zbE8rDd/v5E+F4sucP+lgtxmuMYw95dPXzGcJ89tXCNM8Dz2dorDmN48n/g8f14pzy/OL6DM29me8nr5vQOgqtTbPwvsN6eGy5zcXsWRyzr3zlKy7v7rvvTiyLvn1mYY8ujgfXNfcltNdD88Dv8phwfCF/tKGh2CeF9yDvX/Q0w/YHzZMrxNHcM2bJd82ec26x9Mhh/6o137848f1MwZ8T6L0U8q1i2L/rSPOYdM032j243+c34/z6ef7bCLkaeFwVeW3Quoalyv1Mtf276GPG/mLcty56TJEHV7vo9we2w55C6F1VH/EBzhcD3nwtOv8CfklMO0f3QCZOs48VxoueVma9PlvsnxRqM5WO3/3STb9DZf04bD4z9pEKeTL1A/vG/axV5ly6UCvGsZLPVrbl38Xx47yjjY/9upjWW/4wej7rub/q8r5++Qtd+p8eXY6e/+rr73Z5a9f6sW6W4nFIV4ddngX6hmNgZpZrxOdNxmhNsbcbzCmvIa4XfeDqJX+fDFXjuyY7H/7nwVw57mc7Bz+7dhsLFR84jvU9I8SgM3rG2Y90CAPHUy8aScz78k0zR/WeOHKO6Te5tm7dahs2bLDrr78++rvp6Wm7+eabbfv27Qu+UygUbHR01P0RQgghFuJo7hkz3TVCCCGODN0zQggx2Cz6m1zVatV9o+Lee++173znOzY+Pm5btmyxV7/61fbGN77RzjjjDNu6dau99rWvtU2bNtlzn/vcYxm3EEKIFYruGSGEEEuJ7hkhhFi5LPpDrm9+85v2Uz/1U1H6oa/lvvSlL7X3vOc99ru/+7s2Oztrv/7rv26Tk5N28cUX2+c+9zkrFotJVQohhBARumeEEEIsJbpnhBBi5ZLqLjOzlunpaatUKnb66adHnjKHDh2K8tmDhn1xEO5ayN8p5MkV8qLid9nfib+qjJ4+5XLZ5U1OTkbP7A3E/UbPJvYY4ncxPu4ne5OhDxeXRb8fMz9G7CmE8fIcoccQx8AeV+xjhePLsYeW8mLyuE30pmKPJo4X+7YY7zb2lMJ+8jzwesTx5Xno57uF8BoLeTrhuuZ4cLzMzP1AyG0MD3vPEuw3rzf2iEP6+eZhjPwDKo49753x8XGXxnHgOeMxwr6Expbj7zeHSKgse+bV63WbmpqSfOLHPHTXbPvXH1mmdHhMNt0W+yCkpvw6ngVfIzOzTCvelymy/0HvqhRZEnbpGurAlTFfJN+lNvtaxXM6fK8//3Zf4Nfu0551ZfS8vbPD5b39vbHfHXs0Yb/MzHIzcT73heG+Ie2i70u2BuuzZ0zo3IJ2q+vpfgMPomydPB3J8wr9iApTvs35UvI+q67xZ1FmPtlbKeQFNZ/zeei7ZGbWhvzSlD/vyNbKzdvIAz529jSbOimOP1+jnxeK8dnE48V9wX73835aDFgX14MxcOzNkt8DOJ481sUZP9ZD++J2Dv7tc1xe5Wzv0ZU786LoubXtJJc3ebL3IkPStH8xpqGqv4cm1026dKYV/7wwMuF/VuS+4byFPOHM/Pi2CnQvgWcY+35xm41SvKbSsDjbs9N2x/O26q75MQ/dMyuVXV96S2LepqddmZgnhBAPl373zCP+2xWFEEIIIYQQQgghhHi46EMuIYQQQgghhBBCCDHwLNqT63hRrVYjmRZKcli6wxIhTLP0CCVCLCtkuVPSe2ZhySTXy/GVSrHkheVrKMfiNliyhm1yHreJsj7uC4PvhsaEY2AJIs4Zy85YYoVjwnPGZVF2xv0OjUNIqtpvrENyz9C8cL0M9o3HGueM5XUsD8SxZwknjq2ZH5N+awHXJ8eHksR+UsGkOs3CkkT+CiqnUS7I/WYJL8L7IxQv9w3f7XeG4FrmdcyEJIlYL68prhfXSkhuKmLKE2XLNg7LgVojID23UtIrZmbWzsXzkqH/L2rlYJ+1kqV3h+sBOSDJm/hdnO1u0a+/bMvP8SWt70XP4w2/Th44a2f0fNKd/tfbtwo+wE4a7reajydNbWLfWILIks5UG99lWaYlplmOhaoqlmalaPy6MNY412Zeymjm5yUkT+R3WYK4GFDehu2bhSVq1Y08JnQmQ/y5hu93pgUS8RF//6ZYIwm0Cr4sSwnb+TheljZyXzJNkNu1qS/wLs8vsxjJZPUkaPOun3V5106/2aWfu+Mz0fPa+30b06snXLpYjSX4w9P+DMF+815fd9/qxFgPbPFtzGf9PVCYi8/9fJ3uJRqzXCO+g+dz9LMPxMRz1Cr6O3aouvD52J5rLvj3QghxIvPgTdPB/JMukrz7WKNvcgkhhBBCCCGEEEKIgUcfcgkhhBBCCCGEEEKIgUcfcgkhhBBCCCGEEEKIgWfZenK1Wq3I7wh9j9g/h/2J0HuG/X/QI4frYX8d9L5hrx32z0HfI44n5KHD8eG7HB97DIU8r9ifCMePPXxCXj3sNxXyJwr5Go2MjATrCXl78XhimseW5zDkc4RjxD5gHB/Wy3MW8qPiPO4LzimPNbbD8bFHF+aHPMLM/JxxHreD+bz+sG+L8bfj+LheTG/YsCFYFtd9P/8zbJfjC3nh8d7CvvLeCY09r5vQ3gp5hvE+4/2c5AknT65kMvOpyPuqg0u55ce2k/Zjj/5AWb9MLNNOPnsydZ6LuGyH7Jzmi3SGlOI5zVf9flj72T0u/bc7b4qeH3jcfpd3xjfGo+fqSb5N9j3K1OK1Wq/4eIpT5IMYsK5iTy7rwFlEWd00e38lx5etxY2yjxXHgxZTWYqnXSBPLvCUalNh9qrqgjFYJ0M+atxQAKyXPZvSVC/6gIUdw8zys3CfFJLP52yL/EfJlwn7wnk5mpdQv3G8zPxYh2BvL/Y/wzFrVOaCdT1w9nej551ffZ/Ly0z7eM5/3l/EZT/g/brKExWXRp8rHoORA/HPiuipZmZW3O1/bmuuiff3pttW+djPPeTSbWiz0/J3TYbmFNdNmzy55mF8eWzZvwtBL69u4OwTK49NT7vykQ5BiBUBenbJn+vYoG9yCSGEEEIIIYQQQoiBRx9yCSGEEEIIIYQQQoiBRx9yCSGEEEIIIYQQQoiBZ9l6cnU6nchHhv1sQqBHDfvVoN9TP4+aUD0M+vawzxG/OzMzEz2zlxHGx3k8BujNs2/fvmDZI/V+MjObno41weVy2eWF/JS4n1hvyMvLLOxFFvIn4ja5HYyBvZaw3n6eYQj7VvH4hXyYQrDfFPaTvby4XhwH9JfqB48J14vph+NNhfH1K4scOHDApblvOEacF/JZ4xgwvn77A/3QeK+zF16IUAych/PUzxMO3016Fp5OOvZqCtknPeTb9RBYNO2Xm/OuKlTJq42Oly5kt3Pk8dfy76KPz9wYVXTxKS45vC+e883/s8bldWC7DE34ft158R0uPbZ7U/S88Vt+nx3a5kNAT6ehQ/4sT7f8GkxNzUbP3cqwz0s+gnvwfl3JvlVmZnnwFwv5h5mZ5ergr1giry/ylEJ/KvaqSoPPFvsjsS8Tek6xT1WmSe9mkvc0e5N1iskLG32jMvN0/1I/O9BmYY58GjPktdlJPtu5Hewb9xvHpGcP5pLHgOPJ1ek+hvg+8tM+74m7yXsuFZ/t+zcfdHnr7vN7qz4CHpmd5HjTDfLEHPPjOXL566LnF6W/6PJee+NHXHrt/evjegr+MGqUyAu0Ht/dGfLvSgfmjPPS8t4SQoiB5uDcTGLe6qGRxLxBQd/kEkIIIYQQQgghhBADjz7kEkIIIYQQQgghhBADz7KVK5rFciCU5LBEiOVtCMr/zLxkh/NYEobtsHSwVqsllmVYRoXSI5Y3lUrxr5fetGmTyzvrrLNces+e+NfFs2Tp4EH/dXpsB+VWZr0yptHR+NeWcr3cF5R2cVnsZz9ZHErLeD557LGdftI8LMsyNBwHjj0kvQzJE/ldbpP7hmmeB5wzzpubS/7V6NzmkcrZFooPxz4kk+M2Q2PST46Kskiul9dRaKxDskOWMobkgLzGUNrKZavVqkvjPPXbAzieIdkt53E6aS9JrphMN9217o9lWM1SPJ55KpcleVEXpFstkrOhrCo3RVKxNNcTp1me2CNfPEJZl5nZHKiohu/1d0337h3R8z/+6ctd3uYPHfJlzx6Pnp9y2tdcXuUB32ajAu/R1dwxuifXxXuJ5YnZWvJ6TZFMqjmSrG3k8cR2OD6UMpqZzY7HY8YSsPkcyd9BGscSMCybTYflYYVavOpQLmlmlq37shh/ipYYy/hwjXEerptGKSy5RokaS0F7pJedIy+Le4nLNobiOyHXIBsHkn9iPcNTJZfH83vaLedFz3959+dc3p5t33Pp1defGT0XeiR+vi8YE8srkeJuP9Y7Ln3ApW948D+j5+FZ389rn/Bhlx76xquj54lH+Xb4XOi4sU7eO22S3bZpzRvIHl2dARmtOHH51st2HnHZJ/zTliWMRIhHhpMuGu1faBnBUsZBlC/qm1xCCCGEEEIIIYQQYuDRh1xCCCGEEEIIIYQQYuDRh1xCCCGEEEIIIYQQYuBZtp5c+Xy+x1fHrNfTh/2TQl5Q6BXEvjzsc4Q+ONxmPu/dWjCffbbYMwfLsncR+oRdeumlLu9FL3qRS3/1q1+NntkLiNtEv7FQnpn3HOIx4fHE+Qn5koV8l8y891M/zyEc+37+WNgO9xP7wvPL9WI/uS+8jkLeR7yeee0eaT0cH9YTWm/92uB4cMy4zZBPGe8BnJeQhxTXFdrbXC/PPXu5YTtcL77LedwX3Gv9PMNCe4LfxXi5HlzH/fqJHmJYttvt2sxM8q8KPpHJNtKW/fF8lO6ZjTN4L5XovAGvG/Z3mi/Ee6uxJnkPMuytZH56DS100uTZxF5LjVK8jkpFX9FdV4xFz+N/fI/L+9wXvSfXuWftip4/89dPdXkXbv6oS6/aF/t3lQ94/8fcIb/XW+NxTLkZ8nQskY8QhI/+V2ZmmQbcqX28qVrlOM2eZvlZP7/FmbhR9uRihmbiu7te8ndNFjyc2FOKfY/mIZ2tc9mA1xH9qDRfpDECbyj29kIa3sbKcg26C2HNszdal7yYOpmAV1ozeU8U68m+W72+ZNRm4L9tefywLHujbf6fx/uYYC00h8mbisBx4THyAfnxOf2mU136ly5/YfRcnfdeKI0bf96l15ehTepLuuP7jXPaLPj7jb3m3Ht1/3MvrmXcH91Qn4U4Ati/Sx5dQhx/BtGDi9E3uYQQQgghhBBCCCHEwKMPuYQQQgghhBBCCCHEwKMPuYQQQgghhBBCCCHEwLNsPblGR0cX9BNiPyf2+EEfGva2wbLstcNgPntwhTyI+nk0lUqx6UWx6D1L0JNr7dq1Lu+0005z6fvuuy96Hh0ddXns01Or1aJnHhNmamoqeu7nPxVqM+R/xvOKPkIMzy+O0erVq4MxTE5ORs/YLzM/JuzDxH5JIV8r7lvIZ4vBenlN4dizNxqD8fbz5Ar5Y/F8Y5r7GdpnIU8uHh/uN8eE4Nxzvf36gjEuZo547NGnjNdbqN9cNjRPfN7g2PfzrMOyXI9YmHue8jVLjwybmdm69U+I/n7jf9WpZLI/QW6KfN7K8Xy2/TFvnTR54YFXUDp5+f/43fi5UPXnVKrg652txGfc1FYfxN894Rei54n7Z13eD7wll528P17XZ+33ebX1/i/W3r8+em6WaE+upzsChqxZIR8humrQ84x9jrAe9qJico24HfSpMjMb2uffbY7Fjb73wp9yeaM1H+8zRl4T13PLM10e+hwV5vyeTAc8r4IeXNbrR3WkpDsBr0AaW4zHzI89e5o1hpL9ndjzqksLHX2kunRneT80v4Z4DrFa9ufi8cTxK874n0G43mwjTqc7FAMdE81SXO98wKesfZpfC+WdftEPv/Hy6Dl1hj97xms+vsmT43uKfdSs5ceT5/RIYb8unBf0kmOfOXHiwt5aIszEO999xGXHXn55/0JC9GEl+G6F0De5hBBCCCGEEEIIIcTAow+5hBBCCCGEEEIIIcTAs2zliuVyOZLwoNSIZVMs10E5EYOSIJYssbwpJFHjsihLYokQy5RQnsX1YF9uueWWxPbNzH74wx9GzwcOHHB5PEYhqRZL80LSNy6L8YekoSxJY3ki1suSNG7zlFNOiZ6f+UwvCxkZ8V+7vOGGG6Lnm2++2eWh7BXnj2M3C0s8Q/I6jp3HAfO5LMbHayi0drkvvI4xhn57JyTrwzHhdcx9wZhCe6dffCFJIveTpYPYFy6L9fB7oXOBx4vrxbMgJPVdDDy2fN5gup80WRzmzSe/wUqjh9fdh056WvT3s1/9PVcus9NL8zLjq6LndtnvUZTXsTyxRy62iKWRgS3Zpf+imqv49VjZW46eWYr3R/Vfi56//eK/c3nPm7/TpTddsCZ6/tJ2H+y2fzrXxzAOsiWSs3E6PxvvdZaHkSLMwTI9lKG1ir6N4oyvqHAoHocHz/MS9kqu4tL/efrF0fPcy+9wea2ab+euX3tz9PzE7P9yeZlW8s8SITkgw+O3OOBeJ6lgqxifE5l5krcH4uGxLe/16UYlbqc6Fpbce0nikcOSxMVQnIr7ynuJpY24HlM0Dd3k6e0Zv3Tg/5XnNvqfD9q5eP82S35vHzrZj2dpajg5iAD5hr8/cG1kad2mgoMtiWI/nv3yHZYr9EqDPvG3Jz0C0YjlwmIkikKIxaFvcgkhhBBCCCGEEEKIgWdRH3Jdc801dsEFF9jIyIitW7fOnvvc59odd/j/4azX63bFFVfY6tWrrVwu22WXXWZ79+49pkELIYRYmeieEUIIsdTorhFCiJXLoj7kuuGGG+yKK66wm266yb7whS9Yq9WyZz7zmTY7G/92piuvvNI+/elP20c/+lG74YYbbNeuXfa85z3vmAcuhBBi5aF7RgghxFKju0YIIVYuqS6bziyC/fv327p16+yGG26wpz71qTY1NWVr1661D37wg/b85z/fzMx27NhhZ511lt1444120UUX9a1zenraKpWKnXrqqZH/DPrM1Go1V35uznsToG8Pe/ig/w975LD/EHoDsW9QyBOJPXPYpwf9ldhrCWGvnbGxMZdGv51qteryeIywr+yHxYT8z9AnistyX3Dsi0X/6+vL5bJLo5cW95t9rC644ILo+bd+67dcHrfzd38Xe8185jOfcXn79u1LbIPHL+TnFPIt47XAYF+53pCPWmjt8vxWKt5nBucJf5AzC+8l9qoKrd2QDxjvJU5jvf2OJsznMeIYQl59HAPC/cZ54XXD9aC/XMgjjOPlslhvyEPPzK8NXF/dbtemp6dtamrKRkdHbZBYinvGLL5r1t32KUuPHPa0SWXi8Xvc+5/hX0j7+W2NxGMf8ulplJN9+8zM8jWoh4qyN1WrEPAApKwc1Fuv+ABLB+IA58b8i9c890KX/kz5rOj5a+9/j8vr8d3KxunR3f48DvlszRfJf4+OTuwb+24hmabf99Vxf8Zd8bM/Hz0/7cGZYJunvmV39HzDRx50eTP+KrSffcH66Pnxf/KXLm/831+UHC95keVqcRr9zRYCfazYL4n9lLL1OL857L36cM7Yk4s9w+ZzcdmRvf6uvucFn3Tp31t3bfR83b/6+5f9vA6dPBk9D814X05sM9fw77GXF+bzGPBYZ1rJ+3dula8X/eMYrre6Jl4cHfKPQ3+2XN3XyV5znUy86FsFP2dp8vrCeQvNmZkfFx4/XEc8fqGymNeuTdv3XnSS7pof89A9IzzfetnOxLwn/NOW4xjJseeLb/n/EvMeP5T88+bDYezlly9JvcuN1//BDcl5b/rJ4xiJWA70u2celifX1NRh49bx8XEzM7v11lut1WrZJZdcEpXZtm2bbdmyxW688cYF62g0GjY9Pe3+CCGEEGbH5p4x010jhBAiGf2bRgghVg5H/SFXp9OxV7/61fbkJz/ZHve4x5mZ2Z49eyyfz9uqVatc2fXr19uePXsWrOeaa66xSqUS/dm8efPRhiSEEGIFcazuGTPdNUIIIRZG/6YRQoiVRfJ3sPtwxRVX2Pe+9z376le/+rACuPrqq+2qq66K0tPT07Z582abmpqKpDghORHLxRCWBKG0JyS3MlucBBHjYwkTl0UJEfcL5WIsJeM0tsP95HpxjFhyyPJAhMcIpVrcLrcZkl+x3A7bGR72vwqbJWv4g8X111/v8liueM899xxRfNyvUqmUGAOPH48R1htat5zP6xjXAs8Rjx/mc9nVq1e7NI4RSjYXiveh/9U06x0jbIdjX4wCmtvE8eV1w33DdrkejgHTPH44Z7xfee/jvkOZrVnvHsW+hCScHB+vKVwLofPOzEsk+62/QeBY3TNmyXfNWZ9+imWLh7/unLkXDIWH/XzWzvDzDcpGS/sl5WSHxSmSlJaOfH9kSBZXH4nP3MaQ3x8TG7wZ8nOe+Kbo+bv1bS6v+aHXRM/l3S7LXvfhW3y8IJEc3ufX1PTJ/l2UME1v9MGP7PPnM0rEOv7I7ZFupVrJ/x+H8qzSAR9febe/T7Y/Mf5WxdY7aJ9VSDp4UiyrP/VkPnt8fIUnb4yeq3VvLbAmsGVZppnuZBJKmqXayfuZpW8sXcXxZKlgOwd3FrXRzvl+Zg1kcS2fd+8Nf+rS9f+OJZ7r3+ZlJH/1Ub+fUaLIEr9WMV7nhTmah4zvaKEG0niW9AVkhcWqrzdX9/MwV0mWuw9NeYsAlA52Mv7ebJTievrJAb0EMVmeeDh/Yeng4Rj8eKY7cV0sc23nkiWyLHssTYEcHhZcqpW8hpczS/1vmpXK03/0rcS8L57yhMS8QZckPtKcKPLExcBSRskXxVF9yPXKV77SPvOZz9iXv/xlO/nk+KfcDRs2WLPZtMnJSfc/H3v37rUNGzYsWFehUOjrEyWEEOLE4ljeM2a6a4QQQvSif9MIIcTKY1FyxW63a6985Svt4x//uH3xi1+0rVu3uvzzzz/fcrmc+4bNHXfcYTt37rTt27cfm4iFEEKsWHTPCCGEWGp01wghxMplUd/kuuKKK+yDH/ygffKTn7SRkZFIOlapVGxoaMgqlYpdfvnldtVVV9n4+LiNjo7aq171Ktu+ffsR/8YrIYQQJy66Z4QQQiw1umuEEGLlsqgPud7xjneYmdnTnvY09/fXXXed/cqv/IqZmb3lLW+xdDptl112mTUaDbv00kvt7W9/+6IDa7fbkf8M+uKEPHLMvLcNe1VhHnsMcb38LhLyuuE8/tWWqM2vVqsub/fu2Bwl5H/F9PMMwzFinyP+zS9YF8fOXkFYF/scoa9VP8+mQ4cORc/oA8Wxm5kdPHgwesbxMuv1bHrwwdgTZGbG/7r4RiP2xuB4uJ84TxwPg2Pfb02FYkDvLP7qeyhejo/TGBN7j9VqtcR3eWwxhn4eXDj/XJbXKpbldcN+aNgXHiNej0jIs65fX3Bf4ro16/WT4z2M8LzgXno45wvSz79ruXI87xkzs3YhZani4XHtnBlLUDpk29jO+fFEj5958pRaDOjLlGHvKYoh04z3Sy7tM//m8S926Z+/Nj7ba0/c4fLOO+P/RM9ri+tdXt4fA86zKzXhz9FSya+/LoQ/udF7ms2sIz/IGngJ1ny/2asK0500nSHNeB5qayiPfJiee/fH4rJb7nd52dlVLt1+Zhzvx37l/7m8St3He9q9H4meH/UF779TL8d7m72UcD7NzJql+I7g2NkfC8cv12BvpQ6l4eci8lbCdtCvycxsnjyvstDv+riPZ9fj/XrcUDolep7O+PN5eK+Pt7Ym7ks7zz/rxHchz/3wlN94aDHVzfEa8rWiH1Wj5M9q9svKNeCOpblvDief87lG8s8Lc2W/H7jNdhY8T8k7i9cNjhmXLTR8WfTW4vnugvdXl4zd2A8Nfd7cup4fHE+u433XrARCHlziME+/8v8e1XsT73x3MF8+XEIsjkV9yHUkhtLFYtGuvfZau/baa486KCGEECcmumeEEEIsNbprhBBi5bIoTy4hhBBCCCGEEEIIIZYj+pBLCCGEEEIIIYQQQgw8i5IrHk9SqVTkuYN+QP2+Xoz57HuDHjUhXx6GfazYa4nTCPswTU5OLhgrw/GxdxGm8Vcbm/V6LR04cCAxjz2wEPZAQp8oM9839h8K+RzxeOK7IT8xMz8u7LPFZdFvjNvEsuzBxfViv3leuF6OH0EPLm6X68UxmZiYcHlDQ0OJbXA87PuG8zI3N+fyeJ5wjLhfuOZ5jYe8qDiP+40xsA8Y+2xhDOwtxx5dIS81nAfeyzyeOPbcby6L8ffzckN4rHH9cRs8Z0l78khkGScqqfbhP2ZmuQfjddRZM+LKtXO0VmGaMv6otBRcJ+mWH/v6mC+LFjp8eqTJWg5tuAo1v6Z2ZSs+3jPi5+lxf7+N/iAOYuRen9cp+T3Q/fa3o+fiP3/S5f3lxOdc+lduvCF6nit7c69cw+9nJNPy+zU/42OoV+IYszRKQxNx2WY57Ml1+pc2QOYml9eq+HrRX+w1Ize5vMl1ky59yj2ro+fGiD8XilXwziLvsVaJPK9q4OlIcz837ustVJN/7qhTDLl6XC/7vqHPVauQ7MF1+N14PAu3e0/Cy1/4v1y6cVI8p/Pvu8rllWhPoP1Tuk5+WJDu9PlvWfQmY18yfhfXUart10mr6O+pXD3ea+wXl6N4cXw5BgQ9t8y8V5aZ2VA1Pvd5HbOHGMY3RGuMvdycJ1c72eurdwx8P3HMmsOD6f8olid37N/n0n97w//n0m9//h8cz3COG/Lceni8/k0/+UiHIJYZ+iaXEEIIIYQQQgghhBh49CGXEEIIIYQQQgghhBh4Ut1lpmOZnp62SqViY2NjkXQIJXb9JEwo0WFpFJZleWJIFseyLm4T5U5cD8umMH6uJySnZKnb8PBw9Hzuuee6vHXr1rn0jh3xr49H6aJZr8wLY2LpFsvkcOn0k24hLIPEMWLpYK3mJS8hOSDHi33hOcTx47XAcxZaN7weMc3rj+cwJHPF+ee1ENoDHB/LU5HQ/uB2OFZsh+eE68F0P+lvSOoYkvyFzgEz3xeOF8eI1zGD8fKaYnAt87rmeQrJpTGPy3FfMH4ck263a41Gw6ampmx0dDQY94nCQ3fNk942admhw2NS2AvrKEfreoTWaiE+/1hOhFJGlIMtBL7bJPka14vSI85jGdWPzvle9HzaN85xefkqtEkSvxLJ0PZd99zo+dbX+7w6lT101aOi5xffcKPLKxzy8d3/hFiGPTw17PKGJ7w0PgXbkscoRJqKosxr+JA/R1ke2CrF4zKx0d+TTLEGd1jD73WU/HUzLKdMlg7yfHYyPj00GbfTpWuxPuI7gzI0BseIpW28xlDyN3IfWRSUfL/nS/G7LMvkfqOsj6WDOGb8HvcTJYAdGus01cvyQITHOtuK7x6uh8nXkmW5zVJ8/w1N+Z8zuC/FGT+eCK8jXNeVB/x79XGStMMcz5X9z2K4drtpXn++nuJMHH87H49luzZtt75sre6aH/PQPSOOnN/41zcdcdmVKl0UQvSn3z2jb3IJIYQQQgghhBBCiIFHH3IJIYQQQgghhBBCiIFHH3IJIYQQQgghhBBCiIHnyH+v/XEmnU5H/jfokcR+SexXhJ4/nIe+OOy9w2XZNwphbyCsiz2GuB70mGKfHoyB4+N0yEqN80ZGRhZsY6F6q9Vq9NzPUwrrYq8g9APq1ya+y95K3BfOR0L+ROjBZRZeC+wbFRprnu/QHHJZTHNZ7Es/fzaE/bp4/WFfuF5OhzzisB5eJ7wWsG/cT34X2+G+8L7DcejnsYft8joJ9ZPnDOsJ+fgt9G5Sm1xvqCyv/5BHHXtyiYXJ1M0yP5669kiyD07+APkMrkn23kHfm2yD9hU1EfKYSnfI/wemv9cHzKe3fSn2ajy0ZdblZSvxusnMk0cdxZArb46eU5Wqy5uf9fv3pK/GPnV/+5yfcHm/e91NLr355thHoXayj6FZovOwFfZBegj2KjIav2wrbqfH84o6jnWt2jfi8kKeUpwXiof92nrmG9sM+Gq1CuR5RWXzNfQF8++iF1mq4OPh8UTvpdpJuWBZsziNnlFmZrk6nc9QL8eOeczsqPfszDfAe7GVPF5mZrlGPCY87jwv7E+F8P5B+DX0AeM22YML83l+mUItHk8+B2qV5J9lGbc/6JwimzI33zhe/TwIhTiWsH+XPLqEEA+hb3IJIYQQQgghhBBCiIFHH3IJIYQQQgghhBBCiIFHH3IJIYQQQgghhBBCiIFn2XpypVKpHo8bs14/IvaowXeKxaLLm5mZiZ7Zo4Y9ckJ5XC96OLFPD3sOYdm5uTmXVy6XE99jfx+Maffu3S6P/X22bt0aPY+Njbm822+/3aV37NgRPU9OTro8jgnHkL2BMM3jNzQ05NI4h9zPkM8WrwX2cEL/Np5vTHOboTUV8lky82PEbYZ8rbgs9o2920J+UyG/M05zPDzWGBOPCdYTamOhNBLyzeN+h/youJ7QHPI6xjS3GfKl47XA6w/hMQjFsNC5l9RmyPcN10m32+3xmhOH6WZinyL0rho54E2aUm3yUIShZ5+tkLcS+00hHTK+YU+fVDu53g4dTfVK/HJln/ckxBjmyt6zp3HGapcePuN/R8+Pf87TXd637VqXrn01vou23eYH5VPPeYpLP2niv6Lntd/xYzJ9ZrI3Gns/Zetxx+tFv68yrWxi2Z45ytFgQz56rP04MzE+9k/CeHn+uC+Yz2shRx5T6CnW64flwbI9ayiX3E/0rTLrXWNHmsc0S/4syjWS5xupl/176UCjIR8tM7N8Lfm8NvYB6yT7brWzyfuZc+Zz8fqsj/g7qlUg37JGvHbT7fDgtiG82hq6EwJnRrpN/pSw5rK03loF+hkAvL9wrPuNuxBLiTy6hBAPoW9yCSGEEEIIIYQQQoiBRx9yCSGEEEIIIYQQQoiBZ9nKFbvdbiSXQpkNy3VY5oVMT0+7NEqCuB6WKYXqZakRyqb4PZYwoRRpMfI1jg9hWeGqVatc+glPeEL0/KQnPcnl/ed//qdLHzhwIHqu172MpVr1vz4eY+S+LEZyNTwcS2lYZsaSxFAbIXkg56HMq5+sEOcwJOnj9GLWamg98nshKSvL1zgdioHLYgwskQzJUUMx9BtrLDs7O2shQtJRjhcJxcvxhKSWIfmumZc1cz1cNnSGYExcz2LWmFiY+ULXrHB43FCiyHK2brJiydL+2HJiti4t03yNJELpeM7aOVp/9G7a4rLNHgmdByVsLI3KNOMYWCrWGPH7d/jZL4ye1/76N1zegdd6SWf6k/Gdse/bEy5va9vH+4Hfe1r0/OuHbqLo/TpHiV2W5Fc4TyyxYvldCsYz3QiPdaYFd3Wf/w5sFeMxw/nk+IzWEMvQsE2WWmKeme9boZ5OzOMYUqSh82uXpPuFZPksSyRD0tpuhmVxyT8f1Ef8nd8sxD//5Rv+56l8nSTEMIntnO9ohuV3IG0NyYsZnt9UhyWdyfsS42d5IkoZzcwKIKdk6SruXzM/9j1r/iglnQ2SlLLsEdduYyguy+MuxGJhiSFLEBcDvivpohAnFvomlxBCCCGEEEIIIYQYePQhlxBCCCGEEEIIIYQYePQhlxBCCCGEEEIIIYQYeJatJ1cmk4n8ZtCXqZ/nDPpIsY9VqRT7h7D3E6fRB4d9b9hzKORPFEqHPIXYG4j9f7BvnMceXXfeeWf0jD5BZmZ79uxJjIF9jTiNXmns34XzxPPA/cb4Q75QZn5cQn5nHAPHjmW5TZ6zkJdbaG3wvDC4brgvuB55bYb82fp5NmGay4b2wNDQkMvDseW5D40ne5pxfBxDUjxmfhz4PR579H0LeZxxXmgPFAoFl4f7gel3bmFfQj5q3Cb7loU8/8TC5Gopy3YPj1W6BZ56Lb8/5tYkj2dhyqdT4PHToe3K3l7ODyh5+ZuZ99thTyQGPZEybd8o+ju1875frQLdjSPxnVF89Nku7ymbfsOlv//EN0TPzbndLi+3wft3HSzH4zu13vs9sldVuRWfP+w5hPTzLsIxY++kXIN9rZL9ijgGrCtXP/Ifq9p58i/MJa8xnm/0AePxSpF/Uhu83NiGKZNBHysaP/IBmy/G+TzWTDsLXofkCzWy19932WpcduZcf45Or90fPQ9NV1ze6EGfDsHrGj2wijV/rnZorJ0/VprnzKfRu4r7zb5WyHDN7w8c+2yfNYXzwnNvfP6kcQ7pLsyB/y3F3iySr998wKRQCCGEeITRN7mEEEIIIYQQQgghxMCjD7mEEEIIIYQQQgghxMCjD7mEEEIIIYQQQgghxMCzbD25ut1u5EXTz88GCXkiYT3sTcVlQz5MHA96DnEeexChp0/Ir4vf43rR/4c9fNiT68Ybb4yev/3tb7u8AwcOuPT09HT0HBq/hdII9pN9jfg9jD/kq2Xmvau4bMhTiutBH6l+3kU4Djxn7KWF/nHs0cRziunQWHJ8HAOOL5dlDydcyzy/XBbTXBb7xrFzDJhmPzEeI8wPeaNxu4vpd8hni+thvzGsh/ddyE8sNGcM52G9i6mH1xeuTRHTzcQ+WZl9c9Hft8fIh478a9D7pkHWQF3wK8rP+PsjV6dzNAPnVJrOv4B/V6vg1wJ7Sh0p+Vk6n+mcQr+pbsnvq1P++jku/Z+vfVv0/BPPXuvyTl71Bpc+543nR89D5/v7OOQxlaJuosdUX+8imMMej6sce17F502h5uslizPLtuK/YM+rTmBacnUea2iD/Loys8l9Yx8mjgE9xDh2M/Booli7AY+uubI/u0tTfr/gunG+cwvQLsVBDU97b6pNH4j92qqXnuryptZ7M7xcHbyzyDNseMrXO1upRc/Fqr/HeRxwLnCuzXo9udDnKjdPP6PAPGSonrmyv2uwnR5vLxpP3C+8brq0GOYhXvbd8uXCnqLYJo51P682IRbL25//By79G//6piMuK4Q4cVnUT8XveMc77JxzzrHR0VEbHR217du322c/+9kov16v2xVXXGGrV6+2crlsl112me3du/eYBy2EEGJlontGCCHEUqO7RgghVi6L+pDr5JNPtj//8z+3W2+91b75zW/a05/+dHvOc55j3//+983M7Morr7RPf/rT9tGPftRuuOEG27Vrlz3vec9bksCFEEKsPHTPCCGEWGp01wghxMol1V2MFnABxsfH7S//8i/t+c9/vq1du9Y++MEP2vOf/3wzM9uxY4edddZZduONN9pFF110RPVNT09bpVKx008/PZLboIRodnbWla/Vai6N8iLuGkp7WIIYkqxxHsuUQkPI7WAMLIVCKRLL4EKwhImlWsPDw4mxLkZyxXIxbhfBfveT283NxRKhfnJP7Fs/aSO+y/3CGLhfPCaLkZEuZi1g/CyfxXZY0sdgPTwmpRL9WnKol+PhdtavXx89r1mzxuXt3r07et6/f7/LC0kbWa7I8ZbL5eiZ9zqPbUhSzGmcU44hFHsof2jIy3NwHXObXO+qVasS6+W9H5r/I13X3W7XWq2WTU1N2ejoaGJ9y5Vjfc+YxXfNuu993NIjh8/IsZFdUf7aj73ElWd5IMrdsvV0Yl5IrmZmlq/BWUlHapdlU7mARLxB5yFK3+g9lDul/HHXA0om81NUT82vv9ktIMen2LGfZmaHTp6Jnoeq/vxjCSXK5OaLLKED2VQ6/OMMjgPLO9skzWs7aVlYbodywR4ZZBHkYSTD7Fcv0iMlzCT3leWLobK4dnmd8HsoReM5Kk74eh8491D03BjyP6ed+lf3uPTr//l3oucnvd//XHTHc+M77NVv+jeXt+MlXoI9tme9JbFq97BLz7zoH6Ln9pd+KfE9My/raxbC9zHC0stWASWw/pzP1/zPFrUK3Jskw0UprZmXNvZbU6H12CrE+7le8mPL0sZCLf5ZDN9r16btey86SXfNj3nonhFCPLLcdc9c/0JmdsZpQ/0LHSHf/OyO6PmJz9p2zOoVh+l3zxy18Xy73bYPfehDNjs7a9u3b7dbb73VWq2WXXLJJVGZbdu22ZYtW5wnFNNoNGx6etr9EUIIIY7VPWOmu0YIIcTC6N80Qgixslj0h1y33XablctlKxQK9vKXv9w+/vGP22Me8xjbs2eP5fP5nm8orF+/3vbs2ZNY3zXXXGOVSiX6s3nz5kV3QgghxMrhWN8zZrprhBBCePRvGiGEWJks+kOuRz/60fad73zHbr75ZnvFK15hL33pS+32228/6gCuvvpqm5qaiv7cf//9R12XEEKIwedY3zNmumuEEEJ49G8aIYRYmYR/3/YC5PN5O/30083M7Pzzz7dbbrnF/vZv/9Ze+MIXWrPZtMnJSfc/H3v37rUNGzYk1lcoFHo8pMwOexQ95B+EHjrs08P+SejFwx4+6G2D3lhmYa8lzmNPKawr5JHD8XIM7KGTFI+Z72fIf8jMe3+xB1LIg4jz+F1sl/sZ8ktiLyOsl8cv5MPEPlbcTigGHvtQPSHvsdD4cXzcN1xX3M9GI/bD4HrYyw3r4bW6bt06l0bPK27z4MGDLo2eXFu2bHF5+C6/x+uP08imTZsS07ze2PsLfcFwvMzC3l88Z7gW2P+K1wJ6nPXzj8N1zpIFPsdC+5nTSGg/47p9mNaLx51jfc+YJd81Lzv5OiuOHl4va20q+vtPPvAL/v2cn9+JM+MxbZT8uinOxO2wRw77HqHHFHspMVhXTz2FZD8l9K1aLOjZ1Sr7+LJp9reL22Q/J453bPcI5PkzFj3DzHq9yhD04eL3mHnwlGqWyHsxk9zI0CHfz65fCtYog29jwBMJvYsO4+vFd3nOOgX2Igv4iLInF7yKnkxmZu0ctunfq5P3U3Emjrf4hW+5vIs/+OcuffV/PRg971vn5/7yx3zBpZ/0z7Fn19TXd7u80/esihN0ro9hnnlvqrH7/F7/41+7wKXPeeV90fPQZh/7zb/nPSh/95M3R8+ZFv2smPbzkmvEMfJ887tIfcSXxbHmdV0d9/dddiq+l3if8ZyiL1ia1kkH9mw75+c+3fAeYtmEvqQbyZ6Xy5Hj9W+avd//ro2OjPT8/dCWrQ+/E0KcIPzmD951xGXfdtavufTfNd8fPb8qH/ZhPFrQg2sxeWby7FoKjv4n3x/T6XSs0WjY+eefb7lczq6//voo74477rCdO3fa9u3bH24zQgghTlB0zwghhFhqdNcIIcTKYFHf5Lr66qvtWc96lm3ZssVmZmbsgx/8oH3pS1+yz3/+81apVOzyyy+3q666ysbHx210dNRe9apX2fbt2xf1G6+EEEKcuOieEUIIsdTorhFCiJXLoj7k2rdvn73kJS+x3bt3W6VSsXPOOcc+//nP20//9E+bmdlb3vIWS6fTdtlll1mj0bBLL73U3v72tx9VYLVaLZLpoAyIpUb8tWCU6IRkSSwBCsnFmJAsjqVtLCdKipVj4Hi47GLkTSxvQ+bm/K9UxTHi2IeH/a/gxjEK9SWf919zD8m6eM4WIzvjelEmx5I/jI/rQUma2eFfUfoQLDnk+LCukLyT4djxXZb7cb2Y5n6ef/75Lv3sZz87en7wwQdd3n/8x3+49MRE/Dvh2VcCJYr95LwYX2g/mPl54XU7MzPj0jjWHAPLUXHseb6xTR5rXruh9cd9C8lcQ2PE6wT7xmMSOqcw9m6327PXlyvH854xM7vuB79j6R/LeItT49Hfb/3mf7tymVUbXXp8IjYUnrzA/wrj+kg8L7mGX4u5erJkiSV+2TrdU/AqS5hQtmfmJWutgNQtS3KmbuD73WlS23Uz/t1cDfZ6ISybQpkmS6xyNZd0MXUovhz2hd6b90e5G5NeuR+PdRxThxRYmeRtZ9kGnfvwcrPk22A5Wwf2OssK87NkbwDjl6/R3ZdLPnt4/YUksrm6bzNfhbIdf/790V/e5tI/+vSPoud1j/b74xMv/RmXvvWx8USdv8bLt+65OB6/xn94+X1pyvezCbLhdsH3q9QMyDuHfD9/uX61S59Si+dtYqO/h0YP+r7hXMzn/ByixI/3dn3El8X116ZzYahKVgg9MtiYVJt+/oIYeH6ReZYrtunnXugbSjZZvrmcOZ53zfrHnnMsQxdC9GEx0kaxMlnUh1zvfve7g/nFYtGuvfZau/baax9WUEIIIU5MdM8IIYRYanTXCCHEyuVhe3IJIYQQQgghhBBCCPFIow+5hBBCCCGEEEIIIcTAsyi54vFkcnIy8qZBzyb2QBofH3dp9Kw5cOCAywt55LAXT4iQ9xN7hIV8mNjDB+thrx2uB8tyv3iMMN3PlyfkXcR+VNgueyCF/MU4BoyPx5bbRM8pnrOQnxd7K2G9nMe+RyHPppBnGPeT5xDXSrPZdHk4njx+DI5ZpVJxeaOj3i/kggviX6OO+8rMbN0673eyf//+6Pnee+91eeiPxbGH1jWPweTkpEtjXTyf6I1m5ueQ9x3PU2gMsWw/fzGcb+4Llw2tsZBfW8gvkOPj+cXxwzOk3xo6kTn9prMtO3R4HAs79kV/35je7cq97JNvcukb7OzoufvSX3d5h34+/lXQ7axfi+0yeS3V4rXBdjbsgdUEHyb29GFvrRQ2Q95U6EfFHlzsN4V+VN0Ml/XrCuPt5ML+e4Wp5LuRvbRcmz1eWoE2DtGeBFu1kEeYWe/4Im1/3FgePJt4PHFMCjPJfmxmZp1MHAN7rHF8Lh7y4GLfMlxX7H+Wb8WF2bsNPa7MzPK1+P4tvvfzLq/xan8+7zuAXqXTLu/U23zZX3j0G6LnLbPPc3nFv4i9I3NbfewHtnh/rJGJchz7iO/Lr9x8vUtve/efRc833varLu+s3/PtzPx0vJnaOb8pG0N+jHC/4942I58tmgf2ssrPwLyUfNnh/f7njnoFvdzo5zZKN0rxBh8+5ONz+B+trVX0/fS+YHH7qQYZ2IlF0fjO9xPzCuc99jhGIsQjz1L5ap1x2lD/QkfBE5+1zaW/+dkdiXli6dE3uYQQQgghhBBCCCHEwKMPuYQQQgghhBBCCCHEwKMPuYQQQgghhBBCCCHEwLNsPbk6nU7kI4OeOexBc/HFF7v07Oxs9HzjjTe6vOnp2Bein0cN5rN/Dr+L/knsvcO+QujbE6q3XC67PPamqlariW2WSt7QJOSJxPWGvMnYdwvT3E+sh32rQjH0KxvyT+J5wXEJ9ZPrYX8nfJfHFj3CzLyfF49JyKsq5CnFHmGh+HD9m5nddtttLv3hD384ep6YmHB5hw4dcmlsl8cP54X7xesx5GnG3nPoY9avXsznejleLMvzjX3hseU1xfUmtcGwXxeva4yJ28R1FPL4M/P7B+Ppdrs93mniMLWxpmV+7D2Un4m9gu58+/mu3E/97G+69E92vh09X/Uf/l7qvu2a6Lm60c99qk3nQB7O5zr5PfrjxcHeWY1KcjvoBWRmNp8JeNSRl1a2kezf1S5Q2Rp6SvmyafNlm+U4Bmzj8Lvk9dWBvU5eRm0Dzzry0WoXfToHY8b+YjwvCPthcQzFqbiyTN3noTcZj1+v71ecro/4s2Y+58+4bCtuk+NhWvlkr69UIbnfmXk6KyGk6vte5/I6L/lPl35cK9lDzNb4c3ZuJvaDLH7nQZfXOPukuNwqPybdjG+jAR5iw4f85inUfJuTb/7T6PlRG/3PNne8wntQFqvx3Vie8L6XaVo3Hdhb7GmG45lp+7FN0YZBLzz2jwudC7hXFgK9tNjzD72/vOdWr7dgJ7Pw/PKciGMH+3XJo0usdN521q+59FJ5dC0V8uF6ZNE3uYQQQgghhBBCCCHEwKMPuYQQQgghhBBCCCHEwLNs5YoISpHWrFnj8jZu3OjSKLlatWqVy0N5FkvAWE6E8iGWCIUkdAznYTshWRfLojiNZVnix2Cb/eRYKI3qVy/KFUPjxzJHlnVhembG/0rwoSH/a15DEkSeF5TCheahXz8xn/vC44dl+0liMaZQX1gSGaqXx++uu+5yaZS58thyO5s3b06sd9++fYnxcBrXQq1Wc3k8L5jmNcXyT5yLfjFgvSFZK8Mx4JrqJ2PGeENjYubnO3Se8BrnMcF6h4eHo+dOp+Pk2iIm28haNn14Lc3v/G709/ff82ZX7hPfmXPpIhwb/3zTV13ec9rxfI884NfJ3BqfTneSZWcZkhOxBBBplPxa6KbjtVus+jWeqx35/2+lYDl26KgkxZVlqyAdbNFaLSbLmDokkeSyw3thfwSOa5YgNkd8PfmZuJ7cbV6SZiNeclrftjp65r60STo4X8B5SyXmsSyTwX6jHHGxsPTSSePyPnaUsuZr4TbrIIkduc+vt8t2f9GlX/s3T46ez3jAT1pur4/vwe9eFT1/9Rq/B37jxlgGue6eMZfXGPLrugNrnvdSq+A30/0Xxj8DpmljVfavdel8PY4/1/B9YSlhqwj3esGPkRnYJDTJbiHt12p1TRwf718+B+oj8b2UoXWTq/ufWdr55PsF+8Ky1tAZUq/Avd3W/50vBpYgCiGSOVbyxS9/519d+qnnPf+oYxLLF91GQgghhBBCCCGEEGLg0YdcQgghhBBCCCGEEGLg0YdcQgghhBBCCCGEEGLgWbaeXO12O/K8Qb8i9vT53ve+59LoOcRl0UOHPXKaTf+rnsvlcvQc8psyC/v0sIcT9oX9dbCdfn5TpVIpMY99erBezuN40Z+I+xnqG+ehrxDnsQcW+qOxZ9jIyIhLh/yduG84pzzfOCYhXy1uk8vyPIW8n0LebiFvKs5jD6mQTxnuBzOzXbt2Rc/syTU25v1OcOxDayq0js3CHmIhrzSuh/cS7jvuN5fFGEOeehxPyL+L6+EYMP5+/l2htRqC9yim8YzgsRQxnVw78qnpduI5/NZT/JhdfMGwS5fWxh52b7r4ZJfX/UY8360y+SORz1a3E+ez11PWH3HWLMVrg/2x0h3fTgf+D4s9fLqB/95K0VJBn6uMt7K0trfxs/lysqdTtp7s0cX+P1w2XYvPn8xIsikX94u9x1owfrnKKpf33V/xHl3d7N3R86O/fGEwPvR/4nlAz6t5f731lEUvLfZ6ag6zv1MMj186Q3duPZ6XzCydjZ1kHyaOAfs5u8XXU9rrY/r9j98cPU9snHJ573vCpS79uP+J57Q4738WQ5+t3jWfvJCbJV8Pe5xlp/x+RjLzviyOC3t7zeeSY+iQz1YavNHYG4vbRNhjrZujn0mhb+zBleb9DJ5Zs2t9X3Cd8NrkvYR7bXLdZPTcnvX+nUIIsVSwRxfCfl3Pb4wllBQrFX2TSwghhBBCCCGEEEIMPPqQSwghhBBCCCGEEEIMPPqQSwghhBBCCCGEEEIMPMvWk6vT6UQ+NuiTg55CZt6Xx8x7B01OTrq8kO9NP18rju1oy6I3T8iPKOTfxGlun+tFf6KQh5SZ98TiNpmQFxnGxGPNaWwz5E3FMbEfEY8D9jvkExXy6+I0jwnHEPJTYq8vLMv95LKh+EL+Z+w1F8pjj7PQWsB1xPWgxxrD8XE6NL+hsuzlFtov/dYNwvXimlrMmcGE5jC0xvqNH6dFfxpDTcsMHV7Dq37yedHf/8EVZ7hyz/j0n7j0B6aeGz1vevnTXN78efE8oPfUYmEPIvTmaZR9va2CX3+5BqzVQAjdTDidbiXn9XhpdZLXH3t9occPe2lxO23w4WqTH5HzsSLvIh6/bAP8p9avcnlDE2tdem5sf/Rcq5Bn5wHvi8j+RQj6WKWon+lGsn+XtZJ9tZh62cfXypG3VhM8ufxV4+Y3leZ4fNluB7ypir6iQ6f5dPlAbNi2/k7vhfL7t3zNpb/3nNvj97673uWt3rdqwVjNzEYOeF/J2bH47mGPq3aWOg6kyNuLy2I+l2Wvr06mk5jnyrGPWmAN1UfIc5L9xQLtsJ+XwdrAdcFl0226Q2ns58biftaHY+/PjnkfUBGmcN5jXbrxne8fcVkhRDLs1/W2RygO8cihb3IJIYQQQgghhBBCiIFHH3IJIYQQQgghhBBCiIFn2coV0+n0gtIblkLt27fPpVECxvIhlFhxXkhKxnGEJHQMS6OQkMwQZVEcD6e5/ZAUiuvh+I5UNsV1hSR+/WRnITkgzzem+8k08/lYUsLjiW0upp5+fRkaiuUTLP/jdrAu7vfc3FxiXrFYdGlc1xxfSGbIa4HjQzkq7w8cI5bAcpuhvcR9Ca0FliYfaXxmfl54reK7PAahvTU7O+vyeBwWI/3FGLjsYqSruM5xDXE5EZNr5CyTOTzGBx8Tj9PqmVNduf/+439x6fEtpeh5/7PmXF4nHa+NkQMll9fOJUuas3VabzT1IdlhoeYldE7G1/L1onSQZYQsHZwvJMfr5HVm1i6AHJ8lc61kKVzWH5VBeurFOkny1SMJM4iv4Ms+6tubfb2Nk+N6cmEZpJN00vjhnOarvp7slJcZ5ktxxXNrePx8xSihHN/hz/1D2/z51yzFZXMN+lknc2RSS2aunCxLNzObWxXHVJzxbWYa/j4+82vnRs8s78UY6hXfr1bBn7l52AO8VzolWqu5uK7cPP2Mx7LSgJRwPpcsg2wW6U6ogTUDv0eSQ2yzS52ZZxkuvMv95j2KtPNkk9BIvmvaXrnv6q3sXxOXo3NILA5JEoUQ4tigb3IJIYQQQgghhBBCiIFHH3IJIYQQQgghhBBCiIFHH3IJIYQQQgghhBBCiIFn2XpypVKpyL8n5D/FvkIhzyH0A0KfpYVAbx5uMxQD+/KgF1A/ML5+Hjohnx72I8L40CeI2zTzfeN62BMJx5DjxfHjvGbT+5CEfNRCnmZc70Iebkl52M+RkZHEPIbzeDxxvjn2ajX5V2tz2ZBPFK9r9LVi7zH0ZTLzc8rzy4TKYnz9POtwnjh23oehdc9rHseM32MvtyOd05DvnJn3WWM/MS4b6guXxRh4THD+eX55rHmtHEksJzrpTiryv0EvntaWMVeuS0fRzJp4b7EfFvowsZ9Pt3PkHlfpBntMxelen6DkOW7nOA/WfNhaybXD9aDvF5Ol2NP+auzxtUKaZTonqugv5utFr6oUHWnowWXm/cU4Po6nXsEYKJ5a8nnCPlbeW8mXnd3i93OjFA/S9Oop3+YTPuPSvzPynuj5D//nH13eGV9/tEtPnhyvVfaQmivHbXYyfn5HDwy7dPFQ3JdWgc7jeb9B0A9tap33LyyM5BPL5up+TAozcb3s19Wh8xrXRn3ELzj270IaQ/5nkvmcP0fzDfDlJO+sLKVnK0dmMNco+Y2XaVG/wb+Lx5bBfndojfGZguNQrLKPX/zM6yTPfqSw93EMUq1wrEKI5ctH/+fqxLwXnHvNcYxEiIfPw/om15//+Z9bKpWyV7/61dHf1et1u+KKK2z16tVWLpftsssus7179z7cOIUQQpyA6J4RQgixlOieEUKIlcVRf8h1yy232D/8wz/YOeec4/7+yiuvtE9/+tP20Y9+1G644QbbtWuXPe95z3vYgQohhDix0D0jhBBiKdE9I4QQK4+j+pCrWq3ai1/8YnvXu95lY2OxpGNqasre/e5329/8zd/Y05/+dDv//PPtuuuus69//et20003HbOghRBCrGx0zwghhFhKdM8IIcTK5Kg8ua644gp79rOfbZdccom98Y1vjP7+1ltvtVarZZdcckn0d9u2bbMtW7bYjTfeaBdddNERt5HJZCKfGvSvYU8aBsuy9xPCHj3sK4TpkMcVE/J+MvPxh+rlNthrB/2xQr5VHFM/Dx/0lGIPJH435N+FcF9Cnk08XuythH5F3G9eG5gOzS+3yb5qGEOpVHJ57MmFbXJeqF4G+8YeTTwv4+PjC7ZvZnb//fe7NI49+zTxu7g2eM5w/Pg97ifWE/LVMvPrmseP1yp6nPH88jxhO+Vy2eXh/LPvHJ8hWJb99jhefJfHhMcB9wj3BWPnekKehDheoTNruXI87hkzs1wta9nu4TWcBmOmFNlYtUp+DNGbh72p0AeH3bDYswn9uzgPPaT6wV48rs2837/1crw28+QnVqj6irxnl89jj64u+k/RtRTy4MrWaEwayV5fPf2EGDp+C/Z4Z2UCHmLsTYb+Zz1l/TFhjUocQ63iM3GdlFt+rPMzPr7SF++Mnled81gfz/Z9Lr1qPm7n8Y/7gMs78P3Xu3SuEZ/RmaafmF5vt5jpNd5L6zNn/0xi2ed862su3SrEY9Imf6d0m9ZRNj63eK3iCZymzTQ06RdVsxQXKNT8vVSa8mNf3B3XPPMoX7Y6Th5itWQP17ky+T9C39jjbK4ce6ONHhh1eSEvr1AbZmaddDwOPJ+lQ7TxKvFjjvYHnjeju8O+tbNj8filYFOmQgfRMuR43TNCDDrs17VUHl3v/+XbEvN+6X1nL0mbYmWy6A+5PvShD9m3vvUtu+WWW3ry9uzZY/l83latWuX+fv369bZnz54F62s0Gu4fltPT04sNSQghxAriWN8zZrprhBBCxOieEUKIlcui/svl/vvvt9/6rd+yD3zgAz2/Wexoueaaa6xSqUR/Nm/efEzqFUIIMXgsxT1jprtGCCHEYXTPCCHEymZR3+S69dZbbd++ffaEJzwh+rt2u21f/vKX7e///u/t85//vDWbTZucnHT/+7F3717bsGHDgnVeffXVdtVVV0Xp6elp27x5s2Wz2QXliizlYRkVSrtC0kF+LyQDYjkbE5K+cRolYixZwrIcD0vLUArFcjaWJmG9IdmemZc4cZuLkWmihI3HgPuN7bB8jeViPC6hejHNeSgVDNXJ7/K6YckhjlFItmfmxyUkOeU21q5d69KPfvSjE8tOTEwkxhCSmJr5eeH5DUnxeN2MjsayDF5DPC8o+esnTcYzhvvC44kxcr04DxwP/yYlHD/ud+gM4XpD8kUeI/wBfG5uzuXx/qhUYi3K5ORkYp3LmaW4Z8yS7xoEJWuZOsl5cyQt68TnLsv2UILIssduJlkexnIslD0yLINslpLl+SxJrI7FUt/pNZMub91961wa+5KmozLd8mPSXcR/m6GcsV1IHpN+9WYghk6B7qyAkp/npU3/zkXpaK5B9gZtPy93X/z16HloxMsK19zwv6LnfvLT7kWPi9uc8mda9VNXufRvPCWWbaz6nye7vLEWy2fhrqG8dCcepOInvuzy3vze33HpmefeHre5Zdjl3fNn/+HSj3l/LG1Mk46UZbmZ+TgGllPiusZyZn5tmnmpY2bWn/P1ETpzZ3KQR7YIdboHTtkVtznv8yr7xl06C/LU/Zv9/dFJx/E1S/4sL09UXBrrsRrpcIkuHhwdsgAo+4XeKsTjUGr5svU1IHcv+ryRe309PBdRLAH563LikbxnhFiuLJUEMURInijEw2FRH3I94xnPsNtu84vxV3/1V23btm32e7/3e7Z582bL5XJ2/fXX22WXXWZmZnfccYft3LnTtm/fvmCdhUKhx8tGCCHEiclS3DNmumuEEEIcRveMEEKsbBb1IdfIyIg97nGPc383PDxsq1evjv7+8ssvt6uuusrGx8dtdHTUXvWqV9n27dtl0iiEEKIvumeEEEIsJbpnhBBiZXNUv10xxFve8hZLp9N22WWXWaPRsEsvvdTe/va3H+tmhBBCnKDonhFCCLGU6J4RQojB5WF/yPWlL33JpYvFol177bV27bXXPqx6k/yA2O+H0+iZwx5I6IPD77GvFXr8sB8R+/1g2VA8ZmalUil6Zp3+8HDscXHPPfcktsEx9BuTkPcTe/pgOyEPKbOwzxGm2UeI+4Jl8bfSmPV6CeG7IQ8uM7OhoaHomcdkdjb+FeGhued8HhP2wMIx4djZhwm/0s5thvrJ4G/v4fkM+dLxWsAx4RhCe4D7yeO5mP2Le4DrYbCvvG54zWEMtZr/Ve0h/z2uF+upVqsuj8cTvbR4XrgdjKHfGYLwvpuamkosO8gs1T3DoIdTJ+fXfL1CZzB4G6Xa5G1YjOewQ35S7ImEvlsZ8rjqpLuJZdPkfZOihvZu3Rk9/9V5L3V5rVRc9jU//AuXV5oaoXR8jvZ6U1ki7IfFfl6Y3yqRjyT1rQNeViGfMoZ9mNJt8O/K+H2Wq/uAcZ4Kh3zZia1+T25Z/93o+WDdeyaO37A/em5tO8nlzY3zmopjaKzx8ZT3+vSj//Vno+f5ksvq8YjL1+J3Wz2+ZbD+Npzq46GhRh+u0lnei4ppF8FjtEi+jenk+eb5Dfl1VdfUE8vyGirO+Hv0vifGPlv/9+JXuLyC+Xj/4od/ED1XfvRol9clI73pNfE9mmt42Vp5It5bjZK/WzLkj4VnSqHlz/laxb9bAM+9BnnztQrJ9wd73aEPGHp3mZlNnU4+l1Avxs5zO0gcr3tmpfLvD74wMe/ZJ334OEay8vmTr/yyS7/uKe97hCIRR8r7PvmdYP4vP+e84xLHicSifruiEEIIIYQQQgghhBDLEX3IJYQQQgghhBBCCCEGnmPuyXWsyGQykaQHJUIs6wrJqLgsSoJYAsbyIcwPyYW4TZZ8cXwoYUJplplZuVyOnvm3s7DECuPlPG4T48f2zXqlUSy5QjgmrJdleyij4nhY3oZplvRxPFhXSPJl5iVioTnkMeB4sS/cT24z1A7Hi30LjRGv1b17/a8lx35yPLw2sK+heTDzckGUfnK93C9O4z7sN1441txmSC7L64b7jXXxHsV6++11jI/3EksHk9owC489n1uhOWMZJK6pkHRWxGQbKcumD++/TD0ep5Q/FnokiZhmCSLOYIYkfSyjSjdAzhtWJjs5I0sFud4sSKVKbb+uD2XjtTsyvtPlrdvhTZXn1kB8JEXK0JggHB9LozJwlKZyyfWYmaUtWRqKMshCi+WUdGaUUBqafNeZmbVz0NeW7wxL3x647dnR87qdm1xeZ2t8LrT9kdEDrrlmyS/ANq0NlraG8txY05g0RuK+1c/f4vL+5Dfe5dI/+b4/iZ6/WL/Q5T36XT/r0nNjcfztLMky50ka2kSZocuyVBuk8SRlZIluiOI90y5dXleJnn/xPn+nFkmW+1cjsTR97f2rXV62ThLjgJwW92i6HY69CbLDmbEZlzd6sMLFI4oz9LNjxUv3c414IbFMGGWtsxV/hxpJOIeq8WIeZImiEIPISpIn/tL7znbp9//ybQklhVgc+iaXEEIIIYQQQgghhBh49CGXEEIIIYQQQgghhBh49CGXEEIIIYQQQgghhBh4lq0nV6vVinyK0OuG/ZNCXjPoccWwn87MjPc8QD+ikO8Xl2UvIC47PR37QvzgBz9weegbxN5PIUK+VZzP3kXsC4bxcV7ITynkf8ZeXuwxhfX083dCRkZGEvPMzKrV2EeDxyjk3cbjh3MRqsfMrNGIf7V3Py8yLBsao8nJSZc3Ojrq0lNTU5YEe0xhDJzH84JlMVaG+xnyieLx4v2Mc8F7gN/FdjgG3vvYl9AZwnPEPluYxn2/EJjP65jHfm4u9k3h9Rh6j/uNyJPryOjkYi+sNHhrdcmyKdfwY90qkHkQgN5B7CHV418DflT1EX8+M61CPP+je71nXX7Wr9XVu9ZHz6/4/nt9PZX90fOG7z/e5VU3+jYzEFLpPu/v09xYcun5AnjL5Xw/c+RzhKOXpm6zdxWOGXs24bvZQ/7MOPRYuk8CnkidjK94ZFc8ntUtfjF0qewZX4x9uJpr/Dk6uy4um+4keyAx+Rr5hFb9u/UxHJOwpxmOZ4Z+tChOxTHkd/ufX2YuPcelr7/236Ln5ogfg/pJvmL0purQpKEvVD/Yhwsp1PyabxWTz87umL8TKvvi8f38o3zexmbVpU/5yDMT25he4z0e8/W4b+zPFfKumivPJeYNT/v4WgW/Yarg2VUf9rGzRxyeE81hf5/g+cK0c8ll+/nbiRODZ5/04Uc6BLECYI8uIY4WfZNLCCGEEEIIIYQQQgw8+pBLCCGEEEIIIYQQQgw8+pBLCCGEEEIIIYQQQgw8y9aTa2RkJPKxQY+akP8Ql2UfGvTF6eedxWmEvYvQFwd9tRaKAf2AOAb0PeL3Qj5g7A20GP8k9ugqlWKPFY6BvZZCXloYE3tncbzoh8beVNwmtsP+RAyOdWg82aOJ0yHfI44BPZtCHmacDnkm8XqbnfUeIBgfl2V/p5DfU8iPivOwTc7jNcUxhcB32SeP5wHXecjbyyzs7RYaE16PvL8Rnl9skz0AeV1jv7kvIe+7UL/7ecKJwzxw1k5LDx8+o7beekr097l79rly1YvGXDrTBK+5Fp0RkE6Rh1SXliLmV+6lzLSvd2JrPIdzq2if1f0dUT4Qn7NjJe/L0z6wLnouzPnzeHifb7O6MQ5w/xN83vi9fk11IV725Ar5jZUO+TOCPbrQt6xF9WYPxPfo/Vf+q8u7qvIel377p/49MYbijN/r7SL2Nbx32IcLQW8t9nljX7cc/L8j+zfNr6F+15PrbeeS/eLaFGoHllzrNH9O9axroFHy511mnn6Ggux2NvmMNfN+bdxvrJX97Tg+XHO1ij9jO2nf8eJEXPYjf/dfviyNUakelz1wmq8XPbjMzFIwoGmj8zkXjwN7wGVbyT+Op6nf84H5tdNudcnZyVUuverW+N3m+d7rq1CLz4JMjnzo0sn97ILnWpdN84QQQtgvP+e8RzqEEw59k0sIIYQQQgghhBBCDDz6kEsIIYQQQgghhBBCDDzLVq546qmnRnKp/fvjX3fOUqh63f/aapTrsCQI5Tos82FJFcqUWG7HkiWUVbEsKiSLZFkh5qFUjGM381IkllRxDDgm3E8eB2yH5Vc89liW5ZTYDku1UBLJVKv+119zfBhDSI660LsIjl9oDBhugyVh/SSUR1ovpvvJ9nB8+0kvQ22G5je0pkLx8Lsh2SDH268vGG9ICmrm12dIbryY+Q1JDs38vhwfH3d5o6OjLn3o0KHo+YEHHnB5ExMTiW2GpLTiyLjR/q+N/vgq/LdXxOvkfb/0N65cq+DvAZRgZVr+DEYZFcsTGyNeulWcitv8f6+52OX91Pf9y+es+8PoecONT3d5OfNn8Hwh3r/lQ8M+9nwcQ6tA53zZ74/Sgbje1kkkDyv6NEovC1Uf+3zBl20Ox+3WK35MWIaGMrVWkc7YXHxXvmLVB13W2ZP+7HzUz74xej743j+zIwUlh2a9Ukyc05DEL9NKU5rldh147gbLolwVpbNmXv5n5uWfrZI/R4cm4rJzY3RfkHSwOxKnsy3fZqvgzz+UszEsO0SJIve7VpmLnktTyXJxMz9Gqbb/GSrdofFbA3cN9ZPXGMoM09QvlmliXSEJ53zOtzFU9fcmyhnzs74v45+626UtF58//7Lur11W5Ru/69J7fm1t9PxLX7zR5VXX+J+nfTz08xZIMTGPy4nD/NnHnmXF4V5Z82t+5lPHPZaP/fu3g/mXPfvxxykSIYRYOvRNLiGEEEIIIYQQQggx8OhDLiGEEEIIIYQQQggx8OhDLiGEEEIIIYQQQggx8CxbT64zzzzT8vnDv84YfWjYn4i9d9BHKORj1c/bBn2jHvOYx7i84WHvb3L33bE/wq5du1xeyKOLfawQjp19tzCf+8JgDDxe7HOE+Twm7BOGvkych2nuC3uRhXzU2HMN6w35RJn5voXK8piwZxOmeUx4/HBOuWzIC4r7jTHxezzWSe8tFEPIly4UL69VjIHnk+cbx5rrCcXXb/1hXzmP28GyHB+W7Rcf9oXPgYfOq4dAL7+zzz7b5Z122mkujWfI5OSky8O1wfHxusFx6HcuiMOUvjVppaHD4/qc3Fj09x849dGu3NhO7wc0vTEe3/kinQPgV8R52bo/i8Yuj322zn6q90rZccjv5x/+fewp9ZT5n3Z57GWUCvwXVq6eWfDZzKxJnk3lqfh5/C5/FrXJXjHdAm8l8uDK1Xw63YnrQi+qheiCzw97K3ULcfzvnn6+y7urcpNL33jnz0fPZx/ybTYrfsAa5eSYQp5hIdj7icmB91eG7HvqIy1Lgv3PmJl18T3KXlntXDx+6ANl1uv11SjBOZqm+4PqxXnK1POUlxwr5+Ua8UB0ye/J3/jea459rJhWEXy22j529hvDvvbznOL1mUSh5n+m43MhV4tj2HfalMub+MXNLv3MS18dPecvv8vlffGLB136/O8eiJ5/9I5/c3kjt8RnSps8wwo17xk2n+PRP0wnNLniEaOfD1dSWflzCSEGFX2TSwghhBBCCCGEEEIMPPqQSwghhBBCCCGEEEIMPPqQSwghhBBCCCGEEEIMPMvWk+uHP/xh5AlUrVajv2fPIfZaQg8d9t5BD6J+fj/oycVeO/xuKC/k8cNlsS+hNszCnlKhmEIeUma+362W9wDhdvBdHmssy55NnEafMvYR4hgwfp4X7hvGFPLkCvmJ8bvcBvtlhfydcGw5vunpaZc3NzeX+B7PA44R95Ph+JHQu/3qRXhMsE32TeMxCnlyhTzEQv0y83Ma8kbrFx+uOfbk4rWKaxnn06x3D+C7vP7Qj4896tirb2go9o06dOiQif7M/MQqS5UPj/m7zo89ubrXPuDKzW/d5tIh7x32xwrlvXz+C9Fzq8l3ln+3m4W1mvVrldPFarxWe/y6WvF+Zq+sDnlBza2J3820wudANw17kupJt5LTKfJEYl8wtPlh/6RuJm6z/ImXubybiy916bP2x0E1xn087AuG/k5MvuY7x15Rvl4YP8pDjyszs0Im3vs81uydFvIBy//qn7n0+lTcl6kP/ZHLc1ZaFGCukTwv6JV1OF7yL4R+8/hkGr6hViGul+vJ1eMxqY/4c7M0RV6lsDbYC68w49tkvzGE2wnB+y5fi/ddaF2Yhe+smfXx/XHo7Jtd3tjtF7j0vzzw4uj5TzL/4fLqtO+ac3G8v7T2Iy7v/ePnR8/F2bJ/r0D+j614XtDLjX3dhBBCiEcCfZNLCCGEEEIIIYQQQgw8+pBLCCGEEEIIIYQQQgw8y1aueMcdd0QSKZQQsSSIJU0oJ2LpG8q8WJbEErCpqfhXNt9zzz0uj+VEExMT0TPLibhejI/rwb5wPUxI9hhKs8SPZVMoS2OpVkiuyGVRPsZthPrdTzqI7bDsjEHpWyg+luKFpI2cxzJNjHfDhg0ub8uWLS6NEkVeY9gOr3mWvqFsjucoJMvlstwX3D88fhhDseh/tTjPN9bL88ltYpr7zWVRqsf7ObS/FyO95DaxXt6js7OzLo1jf9NNN7k8nm+sl2PHeeDx4znkd0V//vf9n7JMadTMzFZ/IN6TqbXh82VoMs7vkvKpk06W+OXpaL/yq5+Pnq//wLNd3um7/f7desYfR89nX+frrZ105BI6lIRx7ClSG4WklyzZbENduRnaO0Vfdr4AcnKqhyVrDoqnWYnLFkmhW2r5zqFEEefocDq5SZa28Zih7LA05e/Ydg72NsWOUjzOz5DMjGkOx21+4Cef6vJGL7/Tp5+wLnre8oznu7yT7jgjbp+kd520jy8kgeXxQzllWLZHclRaCzOV2M6gss9LxOsjZGeQTl5TzRKtVZCj8vxmaN3gPLWK/szNtpJlj62Cjw+ljKUpv19xP5iZFWfi/ML9j3Z5J3/W1zv6qk9Fz6d/+lMub/eT/5+P6eTY/uC9+17k8rb8IP4ZZfcZu11eruHXNfa7KYliX/7wss8+ou1f9uzHR88f+/dvH3FZIYQYVPRNLiGEEEIIIYQQQggx8CzqQ67Xv/71lkql3J9t22Iz3nq9bldccYWtXr3ayuWyXXbZZbZ3795jHrQQQoiVie4ZIYQQS43uGiGEWLks+ptcj33sY2337t3Rn69+9atR3pVXXmmf/vSn7aMf/ajdcMMNtmvXLnve8553TAMWQgixstE9I4QQYqnRXSOEECuTRXtyZbPZHq8hs8MeVu9+97vtgx/8oD396U83M7PrrrvOzjrrLLvpppvsoosuWlQ709PTkacN+kh16Heqs2cO+uBwWYS9qbieWi32gXjwwQddHvsThXx6OAb0EQrFzm2EvJXYY4i9qrgdhD19EB6j0HiGfMDYW4nTCPeF68Vx6ecphWVD9fTzicL5Zd+loaEhly6X41+7vXnzZpf3Mz/zMy69Z8+e6Bk94MzM7rvvvuiZ1xR6cJl5DyzuC89ZyJMrNPbs9YRjxPHx+kNPqdBa5Hd5nbDHHvYbx32hmEJrF8eTy3G/cf+G1rGZ7+vBgwddHvuqYb85BmyHz4WQL1ipFHuvdLtdd6Ytd47XPWNmVt5ftOzQYV+5+a2xv1yq7ddqq+DnJV9LQ1mqNPDfRx2y+tqwYyx6funXv+jbXOP97h71QBzD5Jm+0XSb9nod/BWTw+mJJwR7K6Ub/lzFutiDi5kvxvEWZtgDyb/bKsXtoteTmVk7F9eTKvHAB8pSPdy3uXK8t4aqfh7Qz8nM+xOl6VjI15JHn33BDLzIuJ7CXt/md1/wreh5zV/d5/I+84VJlz7jtpnoeceTft3lPe/u/46em7TemOnxeExGDvi7D8eW6Vh4LbiyNCaFOfBZLfkxyNXJaxOmn+eTfd7SHfAUbfG6Ia80mO8eHzVaC2nY/OhhZmZWmAocDAWfRL+xk3/g/Txnz/N9m3/SX0XP5/yZ92N7+kXfcen7yj+KnjsP+vsDfdZaBc7z8231RRwcy5jjedcsF+S5JYQ4EVj0N7nuuusu27Rpk5166qn24he/2Hbu3GlmZrfeequ1Wi275JJLorLbtm2zLVu22I033phYX6PRsOnpafdHCCHEicuxvmfMdNcIIYTw6N80QgixMlnUh1wXXnihvec977HPfe5z9o53vMPuvfdee8pTnmIzMzO2Z88ey+fztmrVKvfO+vXr3TdWmGuuucYqlUr0h7/9IoQQ4sRhKe4ZM901QgghYvRvGiGEWLksSq74rGc9K3o+55xz7MILL7RTTjnFPvKRj/TIto6Uq6++2q666qooPT09rUtBCCFOUJbinjHTXSOEECJG/6YRQoiVy6I9uZBVq1bZmWeeaXfffbf99E//tDWbTZucnHT/87F3794F9e4PUSgUnM/NQ6TT6cgjCD1q2EeIfaNCHlPsOYSwjxC2yV427HuEsE9PyCeKvZXQX4cv2JB/EsfOaXyXPaU4vpB3EdeLcL+xn+ylxOD881oI+TtxvSH/KZ4zjI9j53WCMXEe14seTpOTky6P0xgv93sx/cQ9wB5S7EWG8x3yluP8kDcV5/FaxTEKeXuZ+b7x2PI8Yf7MzIzL4/EMeeFhvNwmz3fIf4/rxTZ5DkP+YjxnITi+YjH21MF+9fNCW84ci3vGLPmuaZU61h06vO7QmydDvlDFKZ9ujsBarft5QD+gVs6PPXp5mZk1y3F+ukXnwIjf681SvG7Y76c3hviZT/W5VfFeamfJ56jhz1z0y2qWfE13Pvl7Lr3pjjPj+GaO3LOH6+31T4rT8xkq24jjw36ZmWWa/ozDsec20YPLzGz0QHw/t4p0NlK9rSKeeeSnCa+2c2GfKIS90uY2+rPp5NvOjZ6Hzl/n876436WLhbidbJO8QPfGfoG54nqXV93ox2j4UHy+sEcd94U9sRD23UJ/tB4vLRhrP85m8zRG7JcVisfvdV+WtmEwhtKU34c8Lkgb6u2SVRvHh/uH8zr0oyyWrV7yGJeXa/iyW289JXqe3ug7PrU+9gYtVkdcXqqd/PNzHvy52gPs1bWU/6YRQghxfFm0JxdSrVbtnnvusY0bN9r5559vuVzOrr/++ij/jjvusJ07d9r27dsfdqBCCCFOPHTPCCGEWGp01wghxMphUd/k+u3f/m37uZ/7OTvllFNs165d9sd//MeWyWTsRS96kVUqFbv88svtqquusvHxcRsdHbVXvepVtn379oH+LSRCCCGOH7pnhBBCLDW6a4QQYuWyqA+5HnjgAXvRi15kBw8etLVr19rFF19sN910k61du9bMzN7ylrdYOp22yy67zBqNhl166aX29re//agCS6VSkWwHJUws5WH5E6ZDEjqWOYbqCUm+uGxIvsb5LDsrlUqJbYTkivjeQulqtRo9s/QyJB/jGFAKZebHF+VW/C7L4kIyNB5rbhPHgaVaITkq1xuqh9dN0nsLlcVx2LFjh8tjuSJ+pZ1lpDhm5XLZ5fEcIjxn3G9cc7z+WEKHMfCchaSrvLdwjLhNlvxhvLxuuF6MgcvOzc25NK5zrgfb5PnlekNy6FAe1xOKNyTh5P0akibjuA+SXPF43jNmh2VLmWzv2ZFp0BlcorsHpGdZkjuhnAglhmZmtYqfw9JULE2fPpnmt07rZj5Oo9zKzGy+6PdWoxSvhcoDfp20c3E9Bzd5advGuzb6NuFov/TXX+jyfu7gj1z6N097UfTc/MwrfT0k8UN5W48csEXychjfDkk4WyDF4/HKz9DZXornbGjC59UqLmnD90CjdEfMnEZaM4BlhijNY0kfSyZ9Hp3H877Nsfvi++Nnare4vPd/7KdcurI3fn7bU8ddXuu2WHp1YKuXfedJepZpgTQ+H54zlCCmze8llJ8ybZLmoTyQ32OpLcr6OiRrTbVpznJwF6bDEnHsa6EW/rE5Dc2yrDBbg/hyfJ74stgXHEszs26OpLawVlLcKP2YXx+J+zI34u/JXD2e31SOrBlayf3uuHHXXSMeHv/+uf854rLP/plz+xcSQpyQLOpDrg996EPB/GKxaNdee61de+21DysoIYQQJya6Z4QQQiw1umuEEGLl8rA8uYQQQgghhBBCCCGEWA7oQy4hhBBCCCGEEEIIMfAsSq54PJmfn4+8ckI+VuwjhP467OeEfjZDQ0Muj32ZsF722gn5d/Xz3kG/LPbOwnhDnkIcL8fOv74YvaC4bMhzKORNtVBMSfWyLxTPGfab4+F3V69eHT2znxOPWcjnCNM8JtyvkDcVrw1Moxeamdk999zj0sPD8a+o5zaxb/084bBN3h9cFvvSz/MK87lebJPXG5fFNMfDnlKhsjwOmA6tRbPwesT559i53pA/YKhehtdGyAsv5PXFbeL6rFRik6FOp2MTExOJ9ZzIpNqH/5iFPXO6NJ3or5Sf8uum8K3Yq2r6J7cE22dvIx+bjwF9rdrky8NWPNOrp6Ln33/u/3Z5W2biNfV/uq/xbdz+iy6dPRB7AJ7UPejyRuZ8oz/c8/To+VTyx0IPMzMztEhiv67mMHlQgtFVuu3bzDXidJbsCqvr/R1WOgQ+fjU/7q2iv5f+8opLo+e/Wv1klzf9kb9y6S4YMfG8IKkGnRFUFOd7aKpAZf27s+vil/M1f3b/0ns+5dIz547Fiff7Nusnx/ck+y6xD1iP3RPA8xvypmqX2M8LzvJcsqdTftbHNztO928ueS91ir4semt1yUeK07g+e8YgsA9b1GZ9PG4zFb6ynOceryk+F3D+e3zfhpPvj9LUsEvjGsu26GdDGttmEbw2cf23/T4SJw537vpeYt6Zmx53zNqRD5cQ4kjQN7mEEEIIIYQQQgghxMCjD7mEEEIIIYQQQgghxMCjD7mEEEIIIYQQQgghxMCzbD25EPQnYh8h9r1BXyH2q1m/fn1iPbOzsy6N3jbsTcXeRdgO++kw6OmzdetWl4d9Yf+mkDcQ+/uw51Wj0VjwvYXqxX6zF1DIIynU734+TAj6VJl5XyEzs3K5HD3znO3atSuxXe5nyJMr5FvGa4H7hu9yWfbzqtXIQCahHl7HPH6Y5jb5XZ5/hD3sEPbdwrXBXmi8t5B+Yx3yvAr55vH89vMJO1JCa77f/GJ8XDbkRRbyNOs3JlgW56jfuSQOM18CT5oaj5kf++IhOP++/S2Xl3vPv0fP41TLgU9c7dJDk/FamFvl10nIn4i9gQpV/xen3Lgqen7OV/Yn1jP2mkMunT9AZ1wp3kv/8LHPubw/OvfbLv2YL8VeKZMn07lAHj/s+ePKNtkLCrzSMnSHgXdalv7frjhD+wyS9233Y/K11Ze59Pg/TUbPf/fTt7i85+/27cytiX8m4HlBfye2X+OyGchnX6jQCdYskVcpenBRXXNl72U5VI3P/XwtedzNzLLgKTZfIM+6zJGfMYUZ8nsqor8YrRM44+YqDZeXa/gzN1cPeGcF6PG4avmX0ROL92SKyqbt2Jy16NnVLvk6i1N+jGrjuGfJCy/rF10KBqbLpnCdzILlzMxaRb+fU230DIvvGm5PLB0/fP7fJOad+q9XHcdI+sN+XSGPLnluCSGOBfomlxBCCCGEEEIIIYQYePQhlxBCCCGEEEIIIYQYeJatXLHVavVIc8z6S7dQvsOyQpQTsSSIJVchqU9I4sf1suQPpZcsVyuVSon1cL+xTZbtsTQK40Xp4kL1Yj6PLfcFxzck1eJ5YDkb9nVmZsblsRwrFA+DfeO+hMaEpW44/1yWwXdDUjfOX2itLxTrQuA48Hhxv3FthGRx/drFeDl2fi9UlgnJNENlmcXIU0NSPi4bkuhyGsd6MXJBngeMgfsVig/3oOSKyXQzh/+YmaXh6Ozk/Por7PMycKtDesNmlzXbjs/y+2unuLzTv7Tbpdtnxu9mSv5szLR8DM3h5DOvS2th7pNvixOvX+vy0tW4ozt3ne/yVlG9jTVxTOUDPr7Hfu5C3+ZYvHaLM/4cZWVUqxiv5VxAumjmZXLtHMmxQD42X3JZbj7NzFog69v6MZ/3z3/rhaWvPBg/33mqP/eb36EzD+RsPXJKkG+lKvTzSyNZFofjY2aWbtNeB4ldq+jXRUgKivJEBtvnNsy83JPJ1n18KEFkuhQeKuNSJJHE+c3Mk11FYEyM6umRU3ZwTVHZDt3dUG+Krp2ed6GddCd8hyE8fsh8zq+FundxcLLSdsmfUyw7xJg69P/cWE9pyv/cNrrbp7vw6tx4HN98Tf93LnoJyROFEGIp0G0khBBCCCGEEEIIIQYefcglhBBCCCGEEEIIIQYefcglhBBCCCGEEEIIIQaeVHeZmbVMT09bpVKxsbGxyF8GQ2TvJwbzh4aGXB565LDfD/tYoUdXyM+J2wz58jBcL3pVsS8Pe0FhWfYT4zHCePv5CBWLsV8H9xM9fjgG9t06Wp+jUB6n0cPMLOyzFlo33C/2+grNC5fFfO4Le5GFfKKwHp4HbhP7xn5i3CbSz+sL80PzwPCaxxj61YNjwmuIxyjkyRby6wrl9WsT56WfZx2mQ2cGw/VgDDyfo6OjLo37ENd/p9OxPXv22NTUVM87JyoP3TVPefOkZYcOj0kKtnfbbyUr3DPh0u2Nq6Lney7a6fLO/AjcPeOrXN7sFj/36PfDPkbsiZQHv5tmyZdlzyH08yrtJo+herxHW2u8R9Ps2uQ7i8k0w15awXchPo6dbIScd1WrQJ51kOT32AcM6RmTXfsTy97zAl/Rqn3evwt9j9gPC/uZafkA6yN+rHP1+F32emJfJoS9n3he2vnAu+Brxeutt51gtiPkMcVeae1kmzA3Rv36xR5dCI8fzhP7qHE9mM957JuH85av+XibpTgGbpP71uMhBnBfnM8WeZGFfMFCZVd930/S91/+JZd+0/q/iJ5/78HXxnXOzNq+x/287pof89A9I4QQYnE8+N6bo+eTXnJhT36/e0bf5BJCCCGEEEIIIYQQA48+5BJCCCGEEEIIIYQQA09Y+/cIkkqlIpkOSppY3sSyH0yzDK1er0fPLEPiNMq+WKIWkqz1k5ah3IgliAjLprjfWC/Lprgvi1GkhiRqPNY8Dkion6GxDsnX+N2QVNDMS7e4TVwbLAHj8WTZF8JjglK9ox13Mz8OIZkjl+U1z+CYcF8WIyPFfobWOMfbb39gOyidXQiMbzGS4tBYL0ZOyWO9GJlwqF7uN87T+LiXSZ111lkujRLtHTt2uFj27Nljopdu5vAfM7NMA+SyaTpzTx5z6bsv+mH0fNo3TvV1TsZj39myllt0qWwD5WwsWeqN9SFYOtYxHy9K93adW3V5xVp85s7nZl1eruH3UkjWxWBMLH1j+VVIjsUSMJZV+bJxR9slkuWxjA/KNtZQRWs2uGQ7F3fmpDvobKRm3LyQFK/jh9OB8kQzs1YxrrhV8GdjrkH3b2BMeGzb2bA0/SHSlizTMzNLQ7wsDe2Vy0L7ObqbW0f+/6sYO/c5V/djEpTAZmhNBSSIITlgT3wkK8V1X6sk38ccO+/nNiyNfvHgGPH+De3DxlDd5Y09OBw9r37d1S7vK894u0s/uCvu213vfX30PD07byeZEEIIEQbliIspOzNXtW3/7xl939E3uYQQQgghhBBCCCHEwKMPuYQQQgghhBBCCCHEwKMPuYQQQgghhBBCCCHEwLNsPbkajUbkW4M+Pf38k9C/Bn2D+F32z2HPHPQK6uddFPJeYu8d9OnhejGP2+B+Y5rzGK4rlId96ddvTHM/Q++FvL5CHmtmfoz6+U/x2kiC5489m9AjiWPnGEJt8jxhXdwm1st1cgxYL48114t7gseW/bGwHR4jbJPXSWiMOC+0R/v5syEcA89LaD9jup8PGJbl8avVai6NHoAcO+aZeS+t0H7m+NijC+cf4wvtzxOdRrlj7aHD89rJxeOXm/FzNrver5sN926OnrNVv8/mnvLo6Jn9c3K15LlIdcLp+QKcz3Sss6cPMnpgxKXb+TjezLxfb+zfhF5GmWb4rnExpdmj6cjXIJdFz6tuh7yWoB32H0KPKzOz/AzcWTy2JZ/O1uOyIW80s14fLgT9qPrNWXEmPut5rHs82NLJeUynz88ID7H3lF0uPTRb9umZ+JzK1/IWAn3LsuR51RzpEzDWw4MGcL/ni/Ff8Bpi3y305GoV/ARym7gneF5wL5mZtUr+HkUKMGb8Xsg1LUtefezRhfH2+HeRFxl6vc3nfKz53fEd9obdX3V5Ox/0d+o9B+N99xO1+DlfO3IvUiGEEGKp0De5hBBCCCGEEEIIIcTAow+5hBBCCCGEEEIIIcTAow+5hBBCCCGEEEIIIcTAs2w9uTqdzoKeXOwbNDc359LoX8R57E+EhLyg+L2QVxV733DZkOcQ9y2pDa6nn6dUqJ6QZxj7BoW8oUJt9huTkGdTyFsp5DXG8PxiDCGvJ46Bx4D9k0L1cjqfj/05OL6QL1OhUEhss9FouDyON+TJFRqH0DxwPDwvGBPHg2Ng5vvCbbJ/F/pTcVnuC7Yb8uRiQnMYmnszP74hPzYzP4ZcD7Y5MTHh8u68806Xnp2djZ4nJycT6xQx6U7s7YM+Qu2in6Pybr+uW2WcU/Lxg2nqkjdVo+Lbz1fB+46OtDZZxKG/V7rBXjt+jnMN8Bcjzyj0HkvR0T1fTD57FuMDxv5YIU8u9FIyM7NF+Hch7HPEPkw4nuyjxePQzsXzxr5qXBbnLUueRPMFmDNjnzLyqiqB91OL26QxgXWFsZp5vykz71vG/lPjO4ej59KhzS7v7gvvcOlWIV68lX3eDzBXJ//MwPhxv9G3jPuCsDfVYugdT/A1JZ+tZsnfJ+hbV6v4nytLU0O+bDO57Fw5/pmqMBf2NHN19uyHZI8unoduJnk88w2KIR2388Jb/9tl3fq6J7n0k9fEm+nUyj9Hz51M1cyekNimEEIIYWZ20ksudOkH33vzEZc9Ehb9Ta4HH3zQfumXfslWr15tQ0NDdvbZZ9s3v/nNKL/b7drrXvc627hxow0NDdkll1xid91116IDE0IIcWKie0YIIcRSo7tGCCFWJov6kGtiYsKe/OQnWy6Xs89+9rN2++2321//9V/b2NhYVObNb36zve1tb7N3vvOddvPNN9vw8LBdeumlPd8KEkIIIRjdM0IIIZYa3TVCCLFySXX7abWA3//937evfe1r9pWvfGXB/G63a5s2bbLXvOY19tu//dtmZjY1NWXr16+397znPfaLv/iLfduYnp62SqViIyMjkaQHpT0s6WPZD0qYQjJDlg+xbArf5SHiyw3r4nr5XYyX5ZQhSRH2y8xLwrifIQkYwzIvrIulZVw2JL3E+FgWx6AMbWhoKDHPzI8ny+I4Poyfy2K9PEc8hzgmIUka1xWSqpp5idqpp57q8jZvjmUj1WrV5f3gBz9waZQD8privuH+KZf9r4ev1Woujf3mNYVlec54LWB8XA/vZyzL9fBY4/iFpKD9wBi4zZAUuJ/cE+eC83jMcH2G5J5cz6pVqxLLcvuzs7M2NTVlo6Ojtpw5HveMWXzXPPFdBy1bOjwm2TrMA0ms8lMkCcslS+o6cHSyLI5BqRvLEx8OTnpJEjCUMPWTFaKUsFWku2aWZNYBmSHHgOl8za95li+ivA0lfWY+fpZmFWboLA9I6EJyT57D+UJAUkcyUizL8fGY4Pj1k4biuyxB7FA7w4fihfUvT/Gys8Lv3h49j5231uWdeYmXrHUhiMr+NS5vqOoXL459t4/KsJNOHs/6SNw3njOWo4ZkewxLEl08NH5z5fi+W7VvFZX1EzO9ejp6zrR8DCgPzJD0slHyVgNZeJfL9q7d+cSyLPGcrcDdTXNWOhQfXPl7vTT+3mf7+DKtuOzGHauj5/m5afvK767SXfNjHrpnhDiR+PZv/d0Rl338375qCSMRK5l+98yivsn1qU99yp74xCfaC17wAlu3bp09/vGPt3e9611R/r333mt79uyxSy65JPq7SqViF154od14441HEb4QQogTCd0zQgghlhrdNUIIsXJZ1IdcP/zhD+0d73iHnXHGGfb5z3/eXvGKV9hv/uZv2j//82HTyT179piZ2fr1691769evj/KYRqNh09PT7o8QQogTk6W4Z8x01wghhIjRv2mEEGLlsqjfrtjpdOyJT3yivelNbzIzs8c//vH2ve99z975znfaS1/60qMK4JprrrE3vOENR/WuEEKIlcVS3DNmumuEEELE6N80QgixclnUh1wbN260xzzmMe7vzjrrLPvYxz5mZmYbNmwwM7O9e/faxo0bozJ79+618847b8E6r776arvqqqui9PT0tG3evNmGhoYibxr0wWHPHE6zxw+CHjrs9RTyfmJC3k9MyDeKPX1CPmDsuxWKNeQFhZ49C4FluR72BcN8jg/HhN8LeZGx3xmPNfY15FNmduRebtzmmjXea2RmZiZ6Zq8nXjfoc8X18njiu4961KNc3jOe8Yzoed++fS5vamrKpfE3/bDvF6+x2dnZ6JnHlscP4w35sYX8zjiGUBtcL4817zPM77dfVq+OPUN4/HBtcD0cb8iHjscI+8YeXOx/hv5i3M/Q/mW/NgT7sgjrxUecpbhnzJLvmsx8KvJCylfjOW0X/PutcrLfVIr8kpwPU4k8Hct+neRr6NNDnkPkvRPyLuJ3Q/5TxmmA/ZPQp6y3LHl9Qb3scRV6l72p2CcMYQ+kYi3eL7WKH9tUibyLivFe7+fZ5GJdxHfeG2UfX6Eav8z96tCPDs1S8pixH1qmCV6g837SUh0/nsXPfyN6XvuDB13eh26Iz5Azbp91eT94qvccesbO2LuI1zGD64jXLa8bHJce/zjwAev0iA86iWXbeT9e7Sx5tEIM7GM1O+bviLX3r7Ykhg75Sfy1F7wgev6je//E5T36vy+OntlbLjtVcmkcE/YPmyvRHQv+XV0yb2tQO/l6HC/PS3UN/Hxa8T4nxaq/s1qFuOyhLfG6adf8GlrOHM9/0wghFob9u+TRJY4Vi5IrPvnJT7Y77rjD/d2dd95pp5xyipmZbd261TZs2GDXX399lD89PW0333yzbd++fcE6C4WCjY6Ouj9CCCFOTJbinjHTXSOEECJG/6YRQoiVy6K+yXXllVfak570JHvTm95kv/ALv2Df+MY37B//8R/tH//xH83s8DcbXv3qV9sb3/hGO+OMM2zr1q322te+1jZt2mTPfe5zlyJ+IYQQKwjdM0IIIZYa3TVCCLFyWdSHXBdccIF9/OMft6uvvtr+5E/+xLZu3Wpvfetb7cUvfnFU5nd/93dtdnbWfv3Xf90mJyft4osvts997nM90jIhhBCC0T0jhBBiqdFdI4QQK5dUd5mZtUxPT1ulUrGTTz458sNBrxv2vUEvG7Owvw566LAnDnsX4bvsGxSqt59nGKbZNwj9dvrVg/3u50c0PDy8YBsLvYtprodjQL8i9k/CsjxHk5OTiWW5Tf5BAueJ+8JeRjhvHDu2wz5WnA55woXWRmhszbx/1wUXXODyHv/4x0fP/Nt5vvKVr7j0rl27omce28Wsa55D7DePdcgPi+cBPbp4bPldLMv1hPrCnlchnzxeY3imsJ8Yr12Mn2NnD7bQWcTt4LoK+YAtxjsQ57fb7Vqr1bKpqSnJJ37MQ3fNk98yadmhw2OSn4rHbL4UVvOjD9d8KblcYa+fs9rJfg90oJlcgzzrAh5cIV8jM+/DlfYhLMpjKluDMy1DPnRlHwP6grG3F8eAvmU9bTaSvavaOX9uYb95TEI+Vgy/i33p0Hjla+S1CV5aZIlkjVJ8DmTJ+6l3zpLzOD6OCWE/qvxsfHbeMP1Yl/eVv78zej5tq79v9/2L9yt62df/O3oeOeAXPceHXm7ss8Vp7Df3i+tNasPMbL4I/l2ZsCccwvtsrux9Q7tQ19juisvb+dgfunT5tK9Hz5MPnuvyTr317Oi59ICfo7mN/n6rj8QbpjTl72b2nmMfLqRYpXsdxr5V8Jsy10i+NxulZA+2NHqq1abtOy/ZoLvmxzx0zwhxIsE+W4tBnlziSOl3zyzKk0sIIYQQQgghhBBCiOWIPuQSQgghhBBCCCGEEAPPojy5jifz8/ORbAflOv3kTixpSirLX2+bnfW/9hjrYYlaSIbGciKWHoVkSSjNm5vzX5dnaRnKsULyJjMvz2IZF8s2MQaWCnJM2G8eo5BUC/PMzEqlWPbAsYfkgNzvI5Vu8bshKeNC8R4toXWzc+dOlzc1Ff8K84MHD7o8liTimusnc8Vx6Dd+uFZ4DHiMkuLhevutVYyP2+D4sC7ev1wvyg5De5IlmyHfDd4PvLcwzVJGlkEi3E8cE17HTJJM+CG5ouilNta0TCTFieef5XUdUvKgHC/jp9eyU/HLLEMa3jHj0jOPiWXLs2O+opDUiOVYLMXrdkB6TrFnWsn/v8XSrVQR5PjJ297MvFwsR5I+lkiiDC0kvWNYgtjOwv0WkFuZeVkc18Ok2vF4svxvPrANuV6UknVI7mmknuy2UbuaLP8zM0tbnM/zyfHOrInv+Wt/dYvL+7XHj0XP73iql1V95u/+w6WH1sT1zlW8hD20VnFdmJnN53x8KK3l9deGshmSe/IewHdZwpfq8HpMnsR8w/elWYilejXq98Z7TnHp1gMnRc8nUbxOKjju1+rBn3+vS0/OboieT/nyM1wejpeZWQf+v5oliLwe07DGOizvLRz5HdGB8cu04r7wOAshRAjJE8VSodtICCGEEEIIIYQQQgw8+pBLCCGEEEIIIYQQQgw8+pBLCCGEEEIIIYQQQgw8A+HJhSzGg4vf37RpU/TMnjjVatWl9+zZEz2zl03Is4m9gEJwDCGfI/ZEwnHgPPbtwTSPF8eLaY5naGjIpRuNxoLPHF/IT4zT3Bf2lArFHvIr4jkMea6F+sLjF/KNCnmjmXlPJ/bdwvU4M+M9fJpN/6u8sW8cX8hLq5+/3ZH2m/sVmu9+/myheELzy15aXBbHkOcb9yF7cHG/Q/5i7LuFMSzG14/Bd0PlGPTbW8x7JxrpTiryuEEfrtw+71c4v6bk0ukWjOk3vuHy/r83vTp6Pvk/pl3e/l/2vkcv/vzXoufqmf6cYs+cXCNej+zBxRZD6NPEnmHsL4ZkW36tsjcZkq/6ss3YXszmC+ShRz5CLj6ql32Z0L8LPYWYTIvb8DWzT1gIFx/V284l7yeOHX3CuB72S0q1A/cdvZtqxOlM3beZqdMEr40f3/UfH3VZf3bG7dHz1n95on9vDXl7jcX30uiBkcRYzfx8s59YaByyLV7X4Jk4S/cQzUO75O/GpHrMzNKt5Hlhj7P6SNwuesCZmbUK/g4bORD/nMT7LtOI4737ST9yeb+56kMu/ZXhx0fPB2vPdHnoF2dmNjse93uoWqSytHbzyR5nOEa8z9j/LIluJ3kNCyFODOSzJZYD+iaXEEIIIYQQQgghhBh49CGXEEIIIYQQQgghhBh49CGXEEIIIYQQQgghhBh4lq0nV6PRiLxo0JOGPXLYQwd9hthDatu2bQs+m5nt2LHDpdFnaGJiwuWF/LH6+QihPxHnoTcQ9xP9mxj2m+I0tsPxhXyjOC/kTcZlMX5uk/2J0MuI80JeRpwX8k/i+NBPifOGh4cTY+C+sH8X+mWFPNbM/LzMzs66PJzv0HyahX3pFuMRx33D+HmscQ/we+yPFVoL3BesdzE+VqH9wXWFYuA5Y/+zkEcce82hJxafGeznhWnOw3r7+Z8hOPfdbjdYVhymDddJ9v6dLq9x2pku/eCZ90fP//eqv3B5I//njuj569/0nlyb/83vj3e8d3v0/MwHPuzy1u3c5NLow5Vr+HXSKvj5zYMfEHtwZeDYqq7358vQpC/cDfxXWJeOlyz4RPF780XyioT84X3k0VSmfeY8k3w96E9UL/v9in5YZmb1dXDXdHyA7AXVAZOzLnmjsccUehl16czN15LPYPYIw3mqVXxfuN7CDPhnFsM+ajin7LV06s0XRM/1EX+fMSMTsekae8BxX9iTDWGfKPaXc/XCvPAams+F79gQGEPIC83MLFeH+PyPnDaf8/M0tS6+y3lNjeyLXx7bu87lvXnn7/g292+Onk8hn7e5MT9P+Zo/UxCepxbU1aXMDvy/dyd9dGPLnnRCCCHEI4G+ySWEEEIIIYQQQgghBh59yCWEEEIIIYQQQgghBp5lK1dMp9ORNAjlRSzlYRlQSLqF9aCUyKxXdoZlWSLEbYZkexwvlmVZV4hQPSHpk5mXWHFfuCz2m6VaLJvDsizVwr7xnPD4oVyRYXkYttNPBol9C8nMWMbFY4J94dh5vlE+20+ihjHx2IbklAyPAxLqWz9pKK4VXjcsEw4RkiCG1h+XDe0tjo/TIckzluVzgNcmxtBvr2NfeH5D48dzhrHzexwvSp6xzW632xOD6KWdi8c+tXa9y5te4yXF84V4bdzTOdnlddvx3Odzfh1XNnkZ/X+vj/PXfd3LE1n6gysuRWqiQjVZ+pY/QGd3Md4Dow/4/TC7zq+/DEgFUY64EBgTyxV7JGHQt7k1dJZT31AOyGB8M2Mz9J4PYtW+VXGbZb+32yR9Gz4U77UuSb5C48DyROwLy+34/xkzENJw2/980BihMy4XjxnHw/LUFDTL84CKtdJUweXR8DnZJks2Q/JEjNXMz5mZWR6kjiyBrY/Ea7edDUvoUIIaWjOH24GYWuGymVby/wdnmn4/Y70sp6yuiX+mGt3r3xv75E+5dLMMdgsUH8twW8X4js3V/X7meeqk4/xmieS98C5LdBtcthGXlURRCCHEckPf5BJCCCGEEEIIIYQQA48+5BJCCCGEEEIIIYQQA48+5BJCCCGEEEIIIYQQA8+y9eRCP5uQt83srPdJQX8d9iq66667oucHH3zQ5R04cMClDx06FD2zfxd7LSH9fI7Qb4e9d8bGxqJn9hSanva/hn5ubi565n6GPLrYRyjk51Qul12axx7T7Mm1atWq6Hl8fNzl8fhNTExEzyFvNDPvkbQYTykmaX0tVA/Gyz5l/C6WDY2tWdhTitdGqM2k9s165wXhtRDyEOM1he+ytxz3pVqtRs8hjzWuq59/HMLrhmPC8eR6MK/fXsL80Dlg5vvK/eR2cDw5D/c6e3Kxvxim8bnT6bh5EP3pjo+69Mavz7n0hgfi8++Bx77V5eVe863o+YnfmHB5f/rKx7j013/r76Lnka1+PqdOPnIftdwhX7Y9Eq+5VM3vjz3nJfsgrrvTn/szm+BMozMjVzs2/09WmCJ/p5LPr1Xic3dkr9/bDz5mf/T8mTN+zuXNkgfWC2/797ieiRGXNzfi5xc9hzLNsC9iCPTDYm+nrP/RwtIt8CRkTykfrvO56uc/xR5nPi/gd8beaA24E2hpdjO+nmYpfpnbYG+ybCN5fFd9N167u5/kz8bRA8MujetoeqO/q0NjxP5T9WHy3oT5R/8rs14PrE4m7lu25fuFPnDzRfIqJZtG3Fvsd8bjWWgl/yjPY819Rdp58Hpth/c25rez4P+YTv7ZRYiVwPSDB4P5oyetPk6RCCFC6JtcQgghhBBCCCGEEGLg0YdcQgghhBBCCCGEEGLgWbZyxU6nE8l9UDLEUp5QmqVRKDVjmeO+fftcGiWKLEsKSZpY0seEpIMoz2JZHMumWKYUig/hNrkd7CtKA816JXRY1+iol/Y85jGxJOdpT3taMIabbropev7+97/v8lDKaBYea5a34fxzm6F4GJSI8ZpCKdlC+QjPIZYNSfH6ge+yLI7TOL8ca2hNcVkcE5TZmvWOCa4bzgu1E5JaMizjY4kxSm953RQKhcR6eUxwjXF8LJnE/cNthCTFXC/KDEOSUjM/fhhPP+nsiUyhmrNsu3etpXbt8X9RpHWSjtfGHU+7z2XdszU+V3/v3P/j8rovu8ynH7c+ej5wml+3Q1W/rjOteH5RrmZm1ljv+5CB47u+laTnhVhukWt4+V9rxO91J0uiNjtlfycUQS6W8duhV86Wj9dydT1Jk0kqhRKoyZP9GXJb97nRc+3373J5q1s+vh/8ws9Gz8//3890ed+78VUu3UmDFC5PEuw1yVJllqihtAznz8ysk0tOd+lKYIkaqsI6afo5iCRpWRjPXIPOnsCPLCGZI8MxYF8XI2vldTP92KHo+XOnP8Xl3fVUH/yb3vq16LlQ8Wd3o8RzFg/gPK3rds53vFWYh7LzwbJIoeb3Vmkq7gvvpeKUXzcN2Ft5Gj+WIFofuSqC66hYJVk/NMNriPvSKsRj34GynYAcUohBpZ9E8UjLSsq4/Nk58aNg/paxU45TJOLhom9yCSGEEEIIIYQQQoiBRx9yCSGEEEIIIYQQQoiBRx9yCSGEEEIIIYQQQoiBZ9l6cqGHDHom5fP5hYov+B57SqEvTj9vIGyHfW9CvlvsfcNeRujpwzGghw77RHE9GN/Q0JDLY98ebIfrCflRcXzsFRTyF1u3bl30/PM///Mub3x83KVLpfj3xd97770ub9euXS4d8k8K+Q6xtxKWZS8vrgf9nbgs+5ThmPA8hPzQQvXwnPE84DyFvJ4YXsehdcR+U8PDsV8N+2Gxzxv6YYX2A6d5/Hjuccx4bLkszj/Xi/Hy2PK8hGJnsN8Mx4D7mfMwJm6T13XSngz140Qn1Y69hwo7Y/8zG1/lCzb8uk6NxPmnfWODy/vABdui5we+8Bsub82TvYfd7Fh8T7EHF/swoU9Oj0cTXUttqKq428e+5Ttxm92N3k+x5Y9nGzoUr6NMw5+NzYqPoV5J9hFif6dMM643zRZDdGyhd9A9F37L1/Op2P/k9m9OubwDMz7ep+Z+GD2//ilfcHmvuuvPXLpVgPOllTwPZr1zgTSH4/3cLPlByDX8ecO+TC6eIp2HtXjvz1X8+Tw05c+/ZinuC491Cvy6eA2lW+RVVYz72SEbu9CYVNf49Vd5gM5Z8CLLzPgg7nvm/8TvHfAL47S0P/+++9IvR8/b/v0Sl1cd8/Xi2DdKfvzYE65VhDuizj5WfkCx3k6GBjtg/9nJ+UystjFCfqOB9dYq0s8o5JWGnnG1ET8vuUbyPwlydR9fphWPA7aZDtQhhBBCHC/0TS4hhBBCCCGEEEIIMfAs6kOuRz3qUZZKpXr+XHHFFWZ2+JtTV1xxha1evdrK5bJddtlltnfv3iUJXAghxMpEd40QQoilRPeMEEKsXBb1Idctt9xiu3fvjv584QuHv+7/ghe8wMzMrrzySvv0pz9tH/3oR+2GG26wXbt22fOe97xjH7UQQogVi+4aIYQQS4nuGSGEWLksSjy/du1al/7zP/9zO+200+wnf/InbWpqyt797nfbBz/4QXv6059uZmbXXXednXXWWXbTTTfZRRddtKjACoVC5C+D3jbs/8P+Sehnw55DExMT0fPs7GywffTpYV+jxfjb8LsYH8eO/jrsJ8aeQyMjI9FzPx8hjIHHhONDbyD2VuJ30feIvdIefPDB6PkHP/iByzvttNNcev/+/dFztVp1eSEfK84L+RXxGOE88HixNxW2yWPA72JMvFYZfJdjD/nQ8RihzxX3k8vimHA/uS8YU8hLa2ZmJjEeM7OTTz45er7vvvtc3tSU99BBeG2GPLnYx4rfDfWFfa2S2uB3eY9ym4tZq1gXt4nnBMeOfnGcxvdCfnXLkeN517RzXUvlDo/PPT8zHf39R856rit3xyq/D9/6sf+Onkcf8OP71X+5Lno++VuTLu/gdr9uEPbwKdbobAd/nXbOt8m+UeivVDvJ15Ndc1L0nJvxbWZr5MNUSC34fLisS1onDWUpvnyVfCXh/9gy3hLJ5ks+XauAJ9Kq3S6vuX1N9Pyo6x/w8d3vKy5tju/N/1y33uUdPMmfRcVafN6UD/izPL/bnzepA/HPFs0z17m8+kg8DuzB1Sr4+yRbAH+sjh+v0lSyHynHl2IrKFgb7LsVeg89uMy8rxr/D2m65f+mC0n0DzMzmy+xxxnG4Mfo9K+fHz1f+sLLXN5rch9x6X+e/4Po+bfOeLzLO+k2bzZXWxPPC89DmkzhxnZX4vfI/yzTorM9l+xPhT507TzdASPkGQYeWI2S/1msOJPsTcp+YmnywpvPJXtJ4vnSZfM2+nGmOAPeY9BktxUwHltmHM97RgixMtg58aPoecvYKY9gJKIfR+3J1Ww27f3vf7+97GUvs1QqZbfeequ1Wi275JLY7HPbtm22ZcsWu/HGGxPraTQaNj097f4IIYQQZrprhBBCLC26Z4QQYmVx1B9yfeITn7DJyUn7lV/5FTMz27Nnj+XzeVu1apUrt379etuzZ09iPddcc41VKpXoz+bNm482JCGEECsM3TVCCCGWEt0zQgixsjjq3/X77ne/2571rGfZpk2bHlYAV199tV111VVRenp62jZv3mzFYjGS/6BMCaWLZr2SIZQBsewHpVssUZqcnHRplIixDInTKCFiGRKDsiqOAeVN/SSIjUb8lXmWFbI0CePtJ5tCuRNLo1guhn1hWdzdd98dPf/TP/2Ty9u6datLf/vb316w/YXSOC88fqOjoy6NckGW/OGYzc3NJbZh5iWKY2NjLo9NSENrlf9HD9vhdcz9RngOcZ54nfA6wjSvk5BENrQeDx065PJ4/HCN8VjjOjbzc8rzG5KjslyR+4bSTJYqh+SAXC+OCcfHZbFNjofbwfEMyaM5j9cCx7ASWOq7Jt1JRdKw6ob7ovxNB/z8zhT8Wp1eHe/n4sxqlze8N56n6Ses8nkTLG+K5zdDki+UDx0ue3Sy02yD1hts59ZIOjHPzEvUWFbYpf8mQ1kcx8plUaLWLJPtQNGfY8OH4jNl3dd+2uU9vfGz0fMNv/0Ul7fxR36vP/iTsQ7y2pv+3uWdelfFpRsVOONO9pLs0eKwS1fPjtNP/1+/6vI+ePfLo+dt/32hy2OZHFI4QD9LtEk63QLJ+Gn+zB3e5+d7DqR5HZKC5hrxxOSneH2RTB1+BOiSKo3XKstnXTyrfL+HJuNFh+NuZlYdi++M9W/4FZf3pguu8DFcGsuEN3/L39XW4rMx7gDLEws1P57FQ3DHpv3PQU2SEg4fin/umB2nO7WZLOXj8UNKU77NHqlyI1na2CZ5Isorc43kfwKQ6tHaWV9Ps7Tw/5F3A/1Yziz1PSMGm9GT4jt++sGDR/XeseR/Hvgflz735HOXpJ0TkX4SRJQriuXNUX3I9aMf/cj+67/+y/7t3/4t+rsNGzZYs9m0yclJ9z8fe/futQ0bNiTWVSgUej48EUIIIXTXCCGEWEp0zwghxMrjqOSK1113na1bt86e/exnR393/vnnWy6Xs+uvvz76uzvuuMN27txp27dvf/iRCiGEOKHQXSOEEGIp0T0jhBArj0V/k6vT6dh1111nL33pS51cp1Kp2OWXX25XXXWVjY+P2+joqL3qVa+y7du367eQCCGEWBS6a4QQQiwlumeEEGJlsugPuf7rv/7Ldu7caS972ct68t7ylrdYOp22yy67zBqNhl166aX29re//agCQx8a9DJiXx729EFfIfarwTrZE4d9hND7hn1uQp5c3Can+d0k2Gcr5P8T8iriNtlbid/FvrCnFPs94bvsIYXz8s1vftPl3X777S6Nfl4zM977hMcevwY+PDwcLLtmzZoFn83MGYdyv9CDy8z3c9++fYnxmPmx77fGMF70b+KY2CsrtP5C9XCa+xkitO+4X9wmzil7U/G72JeQbxWneUy4bxgD7w8sy/PJbXL8SbH3i4/TOL5cD8bL8YT82fC52+32nCnLneN112TqZpkfD9W57zsv+vvtr/xtV27rPz/Ppbfsjs+t2ml+XUxuifdH+UDR5TVLfg7ztXgt9PPcQp+jboa8F2k7o7cW5+HqS7WT85h58nPK+KPJtdMmb69W6ci9ekoHkr2LilV/ZuRg/J6c+5Jv8wXvden5r78gel437TtTXe8HKQ2mRBMbd1EU3rfnK+ufFT1nX363y/u9V98RPf986as+9oYfJPRO6xT8THTZf68Uv5vmszHHfljJY98qwM9FZTqnaN2wV1qIbifZkytX931hf68kDl3g7/xsy784+jcvjZ5nTuO3fdlWMb5/020fa6rNHnZxOl/jfvn1WB+JB429tFrFeLMVZ8jnkryscH/je4fjTd6luTr9/Efz0CpAv8mTC+vFcguB3l84fu32kf9csRw4XveMWDkslc9WP9iHKylP/lxLSz/PLrF8WPSHXM985jMT/6FXLBbt2muvtWuvvfZhByaEEOLERXeNEEKIpUT3jBBCrEyOypNLCCGEEEIIIYQQQojlhD7kEkIIIYQQQgghhBADz6LliseLbrcbfYUYPXMmJiaC76FnDfsI4VeSuZ4j9bZZqF7M7+eZg2n2yGF/IqRYJF8XeJe/as3xLsZHCL2C+D3uC8Y0Nzfn8nDO2DcNPbjM/Jhxm+yRhD5hXC+/i2XXrl3r8tCj6eDBgy4v5OXG88Djh8zOzro0e4ZhOuTDxP5SXA++y2uT+4L5vFbZrw0J+bHxOg75TfXzrDvSejjNc8/v4lrgviA81qG9sxi/PfZVY0L7LuT5x+sG48d6Qv040WmOdKwzdHhNZBqxp92Zf3KhK9fd6NfG7JmxpxN6ZZl5r6WMP6ZsqOHXCXpncT3sVYQeWOy7lG7xHAc8kWbiPcD1zOeSY2APrhRtpWY5eZ2xn1NxKq44N0V7u+Q73qjAvU6+ZRkYv1U7/RlW/9jlLj07HndgdtT7SOYb/v6dWB/7L66/13twrP6mP/NG1sR3yJ3/M+nyzrx+KnqeevSUyytNeY+pTi7uN3uY1ct+IQ1PxHdRYcqvqbmx5DMux+svnTxnbX/dWbYev9sYobuG1m6o3p52crAe6RgdORDvM/S7MjObz/kYJs/CdePz2AMr04rTzWF/p7LfXXMkOT7ud7oDdzd5abWzcP+mw95ZbYghP+vL9uyBOub5+LoB/y4GvcgyrbBRWjd95P5sQgghxPFG3+QSQgghhBBCCCGEEAOPPuQSQgghhBBCCCGEEAPPspUrplKpSIozNBRLSA4dOuTKhSRWLGdDSRDLzkKwDIllaBhDP7kdSqU49pBEkiVqKG0MSeY4nyVf3DeMv1Tyv2Kd42WJYlKb/B6PPdbDUjJOo8yUY2e5J87TgQMHXB6uDa6HpWXYF5az8bs4TzxnXBb79nBkozhPPL8Mvstj228dITinoTHg/JDskeNDyeZC9eJccFmOiSWySfBYhySdPA8cH77L8XAax55jQDko95PTi5lDcZhOOpYgza2Jx354asyVmzqd34vnu1CjeQFZ17w/Rp00y4wlQuH5Q+kgSxlZOoj0ShljeuSKJCscOhDnz5dIHkuSOpRccT9Rnmhmlr83Psvvfba/q2ce9QOXfvTnfip6zpJkMj8BsuUcneUkb8s14nlqFrzkcD7n929l/5roefwuf4e1vvOfLv3A36+Kns/MnOryDv5UnFe42999pSl/Z9UqcUy8poam6GcJkAO2C+F1k6/BfULrJleDOevzYxGvDYQldPlW3GYrF5YuovKNVXC4pni8eua3niyxC8kn+b1eSSL8RS4s00OJIsoTGR5L3vvYJu8lLhuSU+L5Yub3QKtAdxaMUaNEPz+T7LEwF89FqJ9CCCHEI4G+ySWEEEIIIYQQQgghBh59yCWEEEIIIYQQQgghBh59yCWEEEIIIYQQQgghBp5l68nVarUi35qQt03Iwynkc4Q+N2be98vM++uwbxB7SqGHDrfJ7WBd7OGDMbCPFfv/YJucxzHgmHBfOI0eP+wnxvVi2eFh/6vQcazZKyvkRVar+V/rHvKN4nq47P333x89sycXjh97t/GYhOaXwbkIzQOX5XWNMfTzzkJvKq6H1wbC48f9Du27UHxcb2iseQ+EvKk4BlyfIW85zmdftdBe4vhwP/PeDvmCcTwh7zSOIeRpxvFhvRgfty8WJgfeRTNn+HM+46fbcJbYBycX8NZi76JsO7lsqp2c5v+h6gb+y6qb8W20M8k+TMVDdL6UwSuS7IgKU9wOJEp9/g8N9mF19V5fzzydIVAv+xPNb4zju+eCb/s2hn2Ao/c8Lno+6fa1Lm/yZO8x2QFzqInT/ESsyv2cS//a318UPU9fsNrH8N34sUK+ZI1ysr8TeymF6OfvlMYjzx9/1KZPZ/xxbe1K/NzJUJvN5LuGaeepIXiXPbmc9xjtHW4zPwPnfMAvzozGxHwez0urAD9DUewcA/p7tcu+bB18rjLz9HNb26fR5iqV9vHNVfzENItxZzo0gF2ap1zd/zzm8jrxHcYeXNmWjw/7LU8uIZaec08+95EOQYiBQt/kEkIIIYQQQgghhBADjz7kEkIIIYQQQgghhBADjz7kEkIIIYQQQgghhBADz7L15JqdnY38edCThv2I2GsG80N+ROyrFaqXPYY4Xa/Xo+eQRxgTqpf9sNhzaG4u9g9hXx6uFwn5/Zh5XzD2T2IPIowx5N/F8bBHF441+yXh2Jr58eS553HAslwPx4BwvIvxvEJPpH6eUiF/L8wLecuZ9XpBITyeSD9PM6w3tI557nlsca1yX3j8MM2+VRwvjgPPL7eDayPUb4495MnFbYTGIeTBxXVxvbgPuZ7QuRXyBBMxnVw78tlplOO/Z2+gVtGPPXrWZOt+T9ZH4n3XKvg1xLQK8RwWq379ZVrkQRmop5M7cg+nZjleD0P7qFby/0E/ry5dqWnyfkJfMPZ36tC1VH/suuj5lO96H6vRHf7uqW+Jn6tj3jtrrgw+juTBVS57r6+pzfEe3fBD78k1utf7cjZGwHeQfI3m1vj9NFxbFT2P3OvLVrck/xxSqPr5zTXi+Z9Z4/tZnClQ2fjddobuwiL7MsXzxGsVvanYc43nzL1Hnk2t4jyl4+dCzd9R3faR//9qF/rGXmPs0YXxcl63Q1544L/X9kPr2jQzy9fgXiJPLi5brcR30VDV/5yJ3ln9zoV5mAv2/Du4ya/rdi6ud9Xe9b5wh9dYPEjdNHuPzS9YzqzX0wznOwVtpDhYIYQQ4hFAt5EQQgghhBBCCCGEGHj0IZcQQgghhBBCCCGEGHiWrVwxm81GUhyU5LDsJiTVCkl0WFrEciyUM3I9LAFbjJwSJUwsmUQZFb8XkotxmyFpFNfLZVEaxbI4Bt9laSO2w3ksUcN8lLYtFC++y3mLkWRh7DwP5XLZpVHCOTk56fJqtZpLh+YwJM0LxY7tcxtm/ecJQfldPwkdthOSPfLanJ2ddWlsJyQFNfPjwGPCclncS/0knNhv3vsodeS9FJLWcptcFvtdKpVcHvcFy4Ykzzxn3M+k81ByxWTSrYxlmof3IkrAahU/RyzXQVgahVKu4UP+fCl4RZ3VQPp28KQJl1eeGHHpXD2eX4zVzKwb0DLOjft1U5gB+VXJn0vdwHGSpmMAZY9mXk7WK2306dp4/Bf5Wb9uGyf5/dIqxJ1jCdiq3cOQ9xMub2KDl3Wd/oNHRc/F3X5+6xv9/nUSNZKCNkpeatbYFj8Xar7jKEnMTfl52PcYL7Ou7Iv7wvLJZomlZXAukISunfXpDtw19bLv9/BEPJ4sMWVwneepn5kcy9niynh/pNrJe4nVbqio4z3IEkQeo1CbKFHktdoq+MWKfWWZ5tAh/3InAz/jTfm8ViG+/1iazHJoHjNkbsN9Ll3YvzmxbPnQsEujzBDlk2ZmhVo8KHjWmPWuMR9re8FnIYQQ4pFC3+QSQgghhBBCCCGEEAOPPuQSQgghhBBCCCGEEAOPPuQSQgghhBBCCCGEEAPPsvXkyuVykT8OetKwtwz74qDPEfrwcB778rDvEXrfTE9Puzyul318QvFhX0LxcT+5DayX2+B6Q35e7BMVio/rwZjYYyjkrcT14liz51DIh4nnkD2RsJ3QWIfG1sz7HHF8XBZjCrVp5v2pQmPC8YU82PqtG4TnM+Q/xfVwXxAeE0xzP9mjK7QH+nm7Iez1hfPCawrjC+WZ+bXAeSG/QPT9WqgdjJfnJeT5x2VDcyYWZr4wb93IpwY8r8iTpnSA/IAycXpuzM8Del7lp3zebb/4RZdOTa+Nnk/7xjkub2Kjv3vSHe9VhWTSHF+8FthjCL2z2G+KyTbifPbVSgfe5bLs9/SQDxrHamZWuMf7+tmWMpT1Wblq/O6ae/z4rL7vVJdGH6aZR/n5zfnjxeojsCfTPr7hQ+S/B/5JPf5sMA7Vk+iuIQMqbKf0AAW00XuRNUbiAcWxNDMrzvhzFcd+bpWvFr3n2POKvdI6mXgtp9q+zVQ6eS3Mk0/T8IwfP+xLtk7nqlvHdDbSjza4rueLPpOdorBe9uvKzPu+sT8fMruW/Fxh7OcLfi3kGuBzSR5cvMbMOsl5835+G2N7ouf0nvUur1bxPqfZVtw39rfD2Ns5Gus6+YtB/F0Yv27Ab00IIYQ4XuibXEIIIYQQQgghhBBi4NGHXEIIIYQQQgghhBBi4NGHXEIIIYQQQgghhBBi4Fm2nlwI+sywD8/IyIhLF4uxx8DMzExiPWvXrnV5Z5xxhkvXarXo+bvf/W5iHsPxsW9PyD8p5GPFHj7lcuxRwvGw71EoPq4XvYvY74d9y0JeVbOzsadKyPeL01jnQmn0LmLfpVC9obHGWM16xwR9o/r5HM3Nxf4X7MM0PDycWC/Hh33r1ybWMzk56fJwnZiFvdx4DkNjjeuE4+P1h3PI/eQ5w7XC8THoIVatVhPbNPN9C/Wb42HPMOwrl+V9iOuIx4j3Eo4Le49hvHi+mfXOC7YTOmtETLqTiryI0ONneKdfx9//ubtd+rXn/mb0/J5/+bzL6773ndHzZV/9V5f3yVfd7tKFJ2+Mnp+aucXlbbx91KUPnhafKek2eRf1+BPF+ewxhL5R+VZ4n6GnVNvbIPZ4BXVzR77Ocv9/e3cfHFV97gH8yW6STTYJSSCQF0IgCl5E8Q0qBa12ahzHUsWXseMULV7mlqo4hXYuSm1DryINWsei6OjVUdQWpHqv7zNX5Qar5YK8ChahgAV5TxAh2YTNy2b3d/+InPM8T7LnZJGwb9/PDDPn5Hf2nN/5nd85T7Ls82wHm9d7Wh22JGorsjuh609lkz3n2wfK47fnqzp+bBz0flpKZO0iL6tdZFTxp06/ek6wczER2Qc+ZgX/lLHFXyjvZy5YpQabVL1FVvtI14sLR99tj/POil6ys0d9sbyvsqJsSRRWTXx+elRBLF1Xjdfh4nW1iIg6HeaUrqXF+8vrhxEReVUNMV4OLbtd1UpT91beV/Zrj1XJ3xd0XStey8qr7i1dm4zjtbKIZP91rbTKzy4R6xnsZHQtwVCOisfsOHr8+P2cFZR9D+k5z2p0RfysvlkE/3d+Oq04+LK1fPXQn0bd7sD8xj7vs7K21H0jAIAkF1M0CofDVFtbS9XV1ZSbm0tnn302zZ8/v8ebM/PmzaPy8nLKzc2lmpoa2rVr12nvOAAApB7EGQAA6G+INQAAqSumN7kefvhhevrpp+nJJ5+k7du308MPP0yPPPIILV682NrmkUceoSeeeIKeeeYZWrt2LeXl5dE111zT41MtAAAAGuIMAAD0N8QaAIDUFVO64urVq2nKlCk0efJkIiIaMWIEvfLKK7Ru3Toi6v4fj0WLFtFvf/tbmjJlChERvfzyy1RaWkpvvvkm3XrrrX0+Vnt7u5V6w1NwdLrOwIEDo65/9dVXoo2nko0YMUK0fe973xPrW7dutZa3bZPpJTr9jqdnuaXmObXx9EqeikXUM21KpzQ5cUoB0/vl46vTzkpKSqJue+jQIdHGz02fi06L46lluj96W96u0wx1f/m5OqV/6tfpX154u07/0+fG+6Tb9NjzPujz5HSb3i9PWeNphEQ9z0X3n9Ppdry/eq46zRO9Ld+P7p9ODdXpd5y+t/hzQacn6jGK1h8iOTecUl41fUw9x3hKolPaLZE8N70tH1/+DHM7Jl82xsT0zIinMxlniIja8tvJ6z85X+x5bfbuFdt9OGi6WB/5J3s8z7lpomhbuPoNa3nGn/5TtG3++KhYrz5u76ft6edEm3+xPGbBUfuadvqjPzOIZNpU9gk1V72m1+2IeqYpRdgjWaeZ9Txm9HQxndrob7bv0WMvTRNt735wWKyX7LLPdRKtEm2eA8et5YxiWYYg4lX3R7M9Dscqm0RbyCfvjwhLURy8X6b3eBxS/HjqHZEck45y+ftLdrPcUajAfm17gXw25rTI2MhTJDsK5Xl25agYy/pk1JhkhKK36fMM+aOnDmYFdVp99P9D1XOOp83pFEmevqjT9jRPB99WtuksOr5fPa87/J1qWztu+dpkbOmZ8sdW1Hny/nfkymM46ZGC6JMxt6PA/r2jrUKm/uaekDHf32yXTfB4Zd+Nl3c++jwm6nl/J6MzHWv6gqcnajol8VTTDk/XfpLd6u0ro7ZNOvcHZ7AnANAfYvok16RJk6i+vp527txJRERbtmyhVatW0bXXXktERHv27KGGhgaqqamxXlNYWEgTJkygNWvW9LrPjo4OCgQC4h8AAKSn/ogzRIg1AABgw980AACpK6ZPcs2dO5cCgQCNHj2avF4vhcNhWrBgAU2dOpWIiBoaGoiIqLRU/q9AaWmp1abV1dXRAw88cCp9BwCAFNMfcYYIsQYAAGz4mwYAIHXF9EmuV199lZYuXUrLli2jTZs20UsvvUSPPvoovfTSS6fcgV//+tfU3Nxs/du/f/8p7wsAAJJbf8QZIsQaAACw4W8aAIDUFdMnuebMmUNz58618tDHjh1Le/fupbq6Opo2bRqVlZUREVFjYyOVl9tfi97Y2EgXXXRRr/v0+Xw96vQQERUXF1u1c3itKl3Lxqn+D6/ZQyTr/+xV9VY+/vhjsc7rE+m6QXq//Ji63o+uV6Rfy/G6PPp1TnV6dB0rp23danLx/o0cOVK0XXHFFWKd1wOqr68Xbbz+jz5n3T9eJ2rAgAGiTdej4tdF1+TSeP/0ePLz1rWedJ0jPj+d6mrpdj1XdT05/lqnOaXb9DrvL6/DpNv0utO9Q9TzOnH83PTY6vHk+9HXM5Yadnqu8m31eevj8FpW+jz5eOo2p/44jS1R3+ts6dfqPvB1t7GOth+n80g0/RFniKLHGk/YQ56wx1o+6fh7c8V2nQ+pekRhe31Iq6rL89UBa3nZVFkT54ZVso5k7kV2Hani52eItozWFrEeKbfnEa8p1BteK0hvy+8O3eZtl+cZKmD7UbWWM1WNJG+IxbAcdUxV08f3if0NZW+9LT8V8emP1on1LDbNH9k0SbT9fuf/sePLYw76p3zmhvLt9tuvvkO0/a1znFjfvOMma7nj62LZ96Cu+WffX5nh6P932FYkY0JXjnr+sUJSvmD0OmpERBn8XNUhs4NyvyeK21mb7LuszyaPofcT8rE6b6p2W2eBrsHGuudSH8uw2lW6xpXTPNfzMcwutz6G1l4Qvf5jRHU4WGj/PuNR/fOo692VZd9dIZ/6fZXVscoMOf/6zV8bLJS/6/C6WkREg/fY83Pf+bIml9aWb8fCnKB8HvJz0fNN4zX2wuyc+XKiO5N/0yQS1OCKfdtTrdH14pHony4nIrpjSNkp7RcA3MX0Sa5gMNjjDzCv12v9AVVdXU1lZWXiDY9AIEBr166liRNlYV4AAAANcQYAAPobYg0AQOqK6ZNc1113HS1YsICqqqrovPPOo08//ZQee+wxmj69+xugMjIyaPbs2fTQQw/RqFGjqLq6mmpra6miooJuuOGG/ug/AACkEMQZAADob4g1AACpK6Y3uRYvXky1tbV0991305EjR6iiooJ+/vOf07x586xt7r33Xjpx4gTNmDGDmpqa6PLLL6f33nuvR6qWm4yMDCuNKDvb/ni9Tg9rbZUfzeZpVDqdjb/28GH5FeVNTU1inadIOqUPEck0Kp2ypNOL+GudUt38fr9o06lvnFsqEk/d0n13SrnS2xYWFop1Pva6vzyNSve9pKRErI8fP95aLi6WaSHbt28X619++WXUY/IUSSJ53jrVjYtlTPQ103PMKR1Vv5ZfN90/p+ug98PvD7d0Nr7ulJapj6vPSx+H4ymlRPI6xXJMt+vC+6DTE/U6HyM9JnzeuN1LTqmN+hnH57LuD3++6D44pTjrtEen1FW+Hz12iexMxhkiora8NvLmdY9rVod9HxaM+YnYbmrucbFee9vz1vK/b1gu2kaNG2Ytv/zA+6LtP+reFutn3T/BWm6fJK9TsFo+F7zsWZoZUve2Tjtk60ZuSh6WZpgZVGlw6hbgKWEhv3o2OqQ06dQ3nbpF7fazM7ND9t2nHtf8tjy7Qd4DoWL73vbt+lq0bb9VXrMv/sv+lrTj1x0Tbff+9KBYH589x1ru9MlnrsbTF73qNPkYeTtV+l+OfC7wdLGwumb6+nblRFib+jSKSuPTKYpch589J1Sanr5m/P7QqZdZ7bLDvla7Tx35cr+5x2V/gyUsxS9HPv86/fZrC47I+zui5wlLoev0y2vWUiyfuXkBO424tbhZtOW0ynTA/ON2OvzXQ+Wc8gVln/h9yV/XfZw2isajUn/b8oOsTY7X4VFfiPWPi6fb/SuQc+rGfbK+lKfLngueRpm25jRPeKolkZwrPIXThJ3TqBPJmY4135ZTmqFuOzC/sc+vhdPLLUURIBl1NEcvEeQrzIvaFk8xvclVUFBAixYtokWLFkXdJiMjgx588EF68MEHv23fAAAgzSDOAABAf0OsAQBIXTHV5AIAAAAAAAAAAEhEeJMLAAAAAAAAAACSXoZJsGItgUCACgsLadiwYVbNm/Z2u8CEU20qop51cjin1zrV/3Gr08Nf69Y/vl9dT4fX23GrrcT3o+v08PHSx9E1kPS58dpQuuZAZWWlWM/Ls3NwDxw4INp4vS5dt2rkyJFifc4cu/bJ8OHDRdtf/vIXsb5ixQpr+eBBWUNFH4ePmdNY61sglrngNDf0MXVdJt6en58v2vj1d7r2els3/Nz0vNHH4f116ruuEeY0d/WY6DpvJ7+ym0jOL6Ke9fe+/tquv6NrXOnrwsdMj59THTWnxyOv80VENHToULE+atSoqK/dtWuXWOc1AnVNM/5M0ddBz1V+TXWtwObmZmpubqYBAwZE7Vc6ORlrLlh6mLz+7jEZ0GjX0PEdUXWYvpI1nCjPrjXXVS7HtIuVCwz55FwMZ8trGPLZ9wuvw0PUs95Pbqu9ntmu6jCF+l4Lh9fd0nWNslrknA/nsHo7KrzqWl/8XPV56ppNeZuP2tvu/ky0/Xftf4j1gi/tmnUV4x4VbWNfv8JaDjw1XbQ9t+ZzsZ59vX2c+m0yVv9ovIyNq1dcYi0/v/hvoq2pStZ/zDtuXxePw68AGXJIHGucqTJMPa4v3zYrqGKWem2g1K4FFVF1t3idLV0XStcQk3XeZN95bS8iWZvK1yL3k9UqX9tWYq871XLLPyrvBz3/2guiDz6/z4iIPiq/2lrOXSHrF4WulPWLJh636+oN3Cfj0rEq+XsHv0d1TbN2vz1vcoJyvvHroF9beFCe92tXXCbWj9610VouGiz3e+j5fxHr9z32v9by1+Oj1+DKUBMwnKXrx/X+vAkHA7T5p2WINd84GWcg8azevjJq26Rzf9Dn/ZyuGlx3DClz3wiSyuGmZveNvlFelFjPCacaXG7OVI0utziDT3IBAAAAAAAAAEDSw5tcAAAAAAAAAACQ9PAmFwAAAAAAAAAAJL1M903io6Ojw6o3w2v86JpSukYNrw+kawxxuh5RR4esseFU58ipRpJ+Ha+Lo+m6Qfpc+tofvR9dY4iv6xo+uq4Qr/+ja1zt3btXrDvVteJ90uOlaw59/rldN+X48eOiTffBiT6OU70sp9poGm93q8/mVL/LqS6Y7jtv069z6oOuj+V0XXSb07rT3HTrH9+PrvOmc6kvvPBCa/mcc84RbYcOHRLr69evt5b37dsn2pqbZR48778ea7frH40eL/1M4feWvi5+v1+s8+eaU009p5qDRPI8na412AbtzKbMnO5rlRHqjL7h4IFyndXo8gZl/YFIlj3HvB49v1Ttu0z7muU1y/3oOj05zfZr3epjRTysbmOHqufkMI2MVz2nguyZliXbuuQ0pqwOT6/Luj9ERC2XlFjLBYWXi7YfP79M7rioyFoc06DrL9j7Lbhwmmj5t7xtYv2dwXOt5YE5sl5S/kAZC//Y/hNruVA9crODclteC8oTjl4rza3OlpOuHIfY41d1tlSNruJ9dq25zGY5x0PF9rno+my+w/JZRCH795CuUllH0huSY8Kvt66zRfmq9pcYB3kuXVn2uegx8IbkeeY32ieQ+YWsk3Pp47PF+udj1lrL73wh+zdh8G6xvmnRldby1ZENoq3gqLwJWkrs3294XTIioryAva2ud9Y6UP6u42M1uzIPB0TbgENyHLYdta9LoEXG6gs3yuOEhtr3z8BdctvWofZ10DX1SJ2LYbXdOtm9FI4416UFSBSx1N0C6ItYanA5vTbR6nMlK3ySCwAAAAAAAAAAkh7e5AIAAAAAAAAAgKSXsOmKXV1dVmoOTwPSaT469Yin9ekUq7Y2+2u0dfqQUwqYThXU6U08hUinJzqlFzmlr+n+6LRCvl/dP36eRH1POyNyTvfUr+XrOo2U90/3vbW1Vax/8MEH1nJBQYFo0+mLgYD9sX23c+F9iCWdUl8znsKpj6m35e1uaXxO83rw4MFR21paWsR6U1OTtczHh6hnuqfTmLiNJ8fTe/X46XuAn7dO6dPpihUVFdbyyJEjRZvub36+TJfhnOaqbuPjq4+hnxN8/PT15NeBiGjHjh3Wsj5vnZLI7xF9LzmlGjq1IV2xb5qqw+T1d88Jnl7U4ZfX/njpEbEe8drzKKujUbQN+LrYWs5pUdfTK6+Ft8s+Jk9dJCLKCMtnSEe+fU09KmQ5pcKFVDpbZjubxyqNMOxTxyy023V6Xac/en91/7RAif0cO1olY1bhEflV6vK6yG2zOux7K++q74u23OVyfdeyJdbyjz+UA7bkOpkqWvjHu6zl1nKdQhf9WenRWV45YdYmj2nUGPG0vpBPpn3pFEmeTpYRViUBBsrXZrXb7XvGybm6aPwt1vIFMiOc3hlRJNb/uPo5a3nYdvn85SmbRPJcI16XyRDldUQ9x4HT6YAhNndzR8o59K/7vhTrBaPt5/6PfXJOlVXKtPoultK5v1SmQea0Rv+q9Ii6KTMi9vX1qOdARN0wngi7f4fKOFnz/ZvF+v+8wNKjO+V+n/mB/J2qpcV+rvkKVFwqkGU7OK8aa56iyPuuzwMg1d0xRD5rXjzSEGVL99emqmf3PdnnbWdU3dOPPYF0gk9yAQAAAAAAAABA0sObXAAAAAAAAAAAkPQSLl3xZFqNMcZKt4nl2+14u972VL9Z7nRue6r76es3BcZ6TKdvwoulD05j7dRGJNMtdeqlTi2L5Ro6tfXX9T3VPpyuMXG6nrH2r6/7cUuF6+t5Esk0SP0tnDrFj7/2dJ33t5kLsXxb6re5hqfSxp+r0O3kWITbWPovS8kJk0ppPyHThCMsLy3SKVOqwkF7P11tKl1RpQcalsql0xW72mSKGueWrmhYaqFOkSSWrhjuUv1RKYldLKfOqG+z6yKVrhjpe7piOGiPZ9i0qzb1q4nDdfGwdMWuNpkqHVanfSJg9zcQlI1tAfks6mq3U7+7guredkhX7PEtdOz6RnS6Ypcc63CIlxaQc0rPhUiX3QejjsnbiIgyOux2PY+DbExUJnyPMeGv7WqTqfFhr+wvP1cTQ7qiHqOwx54bHvVto3qs+fzrapf7aWnReaT2WLeqidISkuveE6wMRkgOUjjo8M3DoejzWPc97JNlHMJB9juAmteRgLxfAqx/Ol1RX8NwkM3rNtm/cFb0dMUe/SV7W56iePK+RqzphnFIP236QQrU1tLmvlEKaFElY5KZLn+TiNyerxkmwZ7ABw4coGHDhsW7GwAAKWf//v1UWVkZ724kBMQaAID+gVjTDXEGAKB/uMWZhHuTKxKJ0KFDh8gYQ1VVVbR///4examhWyAQoGHDhmGMHGCMnGF83KXCGBljqKWlhSoqKhy/DCOdRCIR2rFjB40ZMyapr21/S4X5398wRu4wRs5SZXwQayT8TdN3qXIP9BeMjzuMkbtUGKO+xpmES1f0eDxUWVlpfUxuwIABSXsRzhSMkTuMkTOMj7tkH6PCwsJ4dyGheDweGjp0KBEl/7U9EzBG7jBG7jBGzlJhfBBrbPibJnYYI2cYH3cYI3fJPkZ9iTP4bxYAAAAAAAAAAEh6eJMLAAAAAAAAAACSXsK+yeXz+eh3v/sd+Xw+943TFMbIHcbIGcbHHcYodeHausMYucMYucMYOcP4pDZcX3cYI2cYH3cYI3fpNEYJV3geAAAAAAAAAAAgVgn7SS4AAAAAAAAAAIC+wptcAAAAAAAAAACQ9PAmFwAAAAAAAAAAJD28yQUAAAAAAAAAAEkvYd/keuqpp2jEiBGUk5NDEyZMoHXr1sW7S3FRV1dH3/nOd6igoICGDBlCN9xwA+3YsUNs097eTjNnzqRBgwZRfn4+3XzzzdTY2BinHsffwoULKSMjg2bPnm39DGNEdPDgQbrtttto0KBBlJubS2PHjqUNGzZY7cYYmjdvHpWXl1Nubi7V1NTQrl274tjjMyccDlNtbS1VV1dTbm4unX322TR//nzi38uRzuOTqhBnuiHOxA5xpneIM84Qa9IP4owNsSY2iDO9Q5xxhjjzDZOAli9fbrKzs80LL7xgPv/8c/Ozn/3MFBUVmcbGxnh37Yy75pprzJIlS8zWrVvN5s2bzQ9/+ENTVVVlWltbrW3uvPNOM2zYMFNfX282bNhgvvvd75pJkybFsdfxs27dOjNixAhzwQUXmFmzZlk/T/cxOnbsmBk+fLi54447zNq1a83u3bvN+++/b7744gtrm4ULF5rCwkLz5ptvmi1btpjrr7/eVFdXm7a2tjj2/MxYsGCBGTRokHn33XfNnj17zGuvvWby8/PN448/bm2TzuOTihBnbIgzsUGc6R3ijDvEmvSCOCMh1vQd4kzvEGfcIc50S8g3uS699FIzc+ZMaz0cDpuKigpTV1cXx14lhiNHjhgiMh999JExxpimpiaTlZVlXnvtNWub7du3GyIya9asiVc346KlpcWMGjXKrFixwlx55ZVWUMAYGXPfffeZyy+/PGp7JBIxZWVl5g9/+IP1s6amJuPz+cwrr7xyJroYV5MnTzbTp08XP7vpppvM1KlTjTEYn1SEOBMd4kx0iDPRIc64Q6xJL4gzzhBreoc4Ex3ijDvEmW4Jl67Y2dlJGzdupJqaGutnHo+HampqaM2aNXHsWWJobm4mIqKBAwcSEdHGjRspFAqJ8Ro9ejRVVVWl3XjNnDmTJk+eLMaCCGNERPT222/T+PHj6ZZbbqEhQ4bQxRdfTM8995zVvmfPHmpoaBBjVFhYSBMmTEiLMZo0aRLV19fTzp07iYhoy5YttGrVKrr22muJCOOTahBnnCHORIc4Ex3ijDvEmvSBOOMOsaZ3iDPRIc64Q5zplhnvDmhHjx6lcDhMpaWl4uelpaX0j3/8I069SgyRSIRmz55Nl112GZ1//vlERNTQ0EDZ2dlUVFQkti0tLaWGhoY49DI+li9fTps2baL169f3aMMYEe3evZuefvpp+tWvfkX3338/rV+/nn7xi19QdnY2TZs2zRqH3u67dBijuXPnUiAQoNGjR5PX66VwOEwLFiygqVOnEhGl/fikGsSZ6BBnokOccYY44w6xJn0gzjhDrOkd4owzxBl3iDPdEu5NLohu5syZtHXrVlq1alW8u5JQ9u/fT7NmzaIVK1ZQTk5OvLuTkCKRCI0fP55+//vfExHRxRdfTFu3bqVnnnmGpk2bFufexd+rr75KS5cupWXLltF5551HmzdvptmzZ1NFRQXGB9IK4kzvEGfcIc64Q6wB6IZY0xPijDvEGXeIM90SLl2xpKSEvF5vj2+KaGxspLKysjj1Kv7uueceevfdd+nDDz+kyspK6+dlZWXU2dlJTU1NYvt0Gq+NGzfSkSNH6JJLLqHMzEzKzMykjz76iJ544gnKzMyk0tLStB+j8vJyGjNmjPjZueeeS/v27SMissYhXe+7OXPm0Ny5c+nWW2+lsWPH0u23306//OUvqa6ujogwPqkGcaZ3iDPRIc64Q5xxh1iTPhBnokOs6R3ijDvEGXeIM90S7k2u7OxsGjduHNXX11s/i0QiVF9fTxMnToxjz+LDGEP33HMPvfHGG7Ry5Uqqrq4W7ePGjaOsrCwxXjt27KB9+/alzXhdddVV9Pe//502b95s/Rs/fjxNnTrVWk73Mbrssst6fE3zzp07afjw4UREVF1dTWVlZWKMAoEArV27Ni3GKBgMkscjH4der5cikQgRYXxSDeKMhDjjDnHGHeKMO8Sa9IE40xNijTPEGXeIM+4QZ74R58L3vVq+fLnx+XzmxRdfNNu2bTMzZswwRUVFpqGhId5dO+PuuusuU1hYaP7617+aw4cPW/+CwaC1zZ133mmqqqrMypUrzYYNG8zEiRPNxIkT49jr+OPfRmIMxmjdunUmMzPTLFiwwOzatcssXbrU+P1+8+c//9naZuHChaaoqMi89dZb5rPPPjNTpkxJua+TjWbatGlm6NCh1tftvv7666akpMTce++91jbpPD6pCHHGhjhzahBnJMQZd4g16QVxRkKsiR3ijIQ44w5xpltCvslljDGLFy82VVVVJjs721x66aXmk08+iXeX4oKIev23ZMkSa5u2tjZz9913m+LiYuP3+82NN95oDh8+HL9OJwAdFDBGxrzzzjvm/PPPNz6fz4wePdo8++yzoj0SiZja2lpTWlpqfD6fueqqq8yOHTvi1NszKxAImFmzZpmqqiqTk5NjzjrrLPOb3/zGdHR0WNuk8/ikKsSZbogzpwZxpifEGWeINekHccaGWBM7xJmeEGecIc50yzDGmDP96TEAAAAAAAAAAIDTKeFqcgEAAAAAAAAAAMQKb3IBAAAAAAAAAEDSw5tcAAAAAAAAAACQ9PAmFwAAAAAAAAAAJD28yQUAAAAAAAAAAEkPb3IBAAAAAAAAAEDSw5tcAAAAAAAAAACQ9PAmFwAAAAAAAAAAJD28yQUAAAAAAAAAAEkPb3IBAAAAAAAAAEDSw5tcAAAAAAAAAACQ9PAmFwAAAAAAAAAAJL3/B+GqamBl0g1ZAAAAAElFTkSuQmCC\n" + }, + "metadata": {} + } + ] + } + }, + "1e79fde882a44cd984a54a71c3337759": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "9cb58613b1a74eaeb285f6d2d77d567b": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "a1d487697e4b4ea6b897f380c2b112cc": { + "model_module": "@jupyter-widgets/controls", + "model_name": "SliderStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "SliderStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "", + "handle_color": null + } + }, + "10441f745a6f41cf8655b2fafbb8204f": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + } + } } }, "nbformat": 4, "nbformat_minor": 0 -} +} \ No newline at end of file