{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# <center style=\"font-family: consolas; font-size: 32px; font-weight: bold;\"> HuBMAP - Hacking The Human Vasculature </center>\n***","metadata":{}},{"cell_type":"code","source":"!pip install --no-index --no-deps /kaggle/input/pycocotools-206/wheels/*.whl\nimport pycocotools\n!pip show pycocotools","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:05.030600Z","iopub.execute_input":"2023-07-11T20:57:05.031087Z","iopub.status.idle":"2023-07-11T20:57:37.362195Z","shell.execute_reply.started":"2023-07-11T20:57:05.031046Z","shell.execute_reply":"2023-07-11T20:57:37.361025Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport os\nfrom collections import Counter\nfrom typing import Callable\nimport random\n\nfrom PIL import Image\nimport imageio\nimport json \nimport cv2\nimport ipywidgets as widgets\nimport IPython.display as ipd\nimport glob\nfrom pycocotools import _mask as coco_mask\nimport logging\nimport functools\n\nimport base64\nimport numpy as np\nimport typing as t\nimport zlib\n\nimport tensorflow as tf\nfrom keras import backend as K\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Input, Conv2D, Conv2DTranspose, MaxPooling2D, Dropout, concatenate\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\n\nprint(f\"tensorflow version: {tf.__version__}\")","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:37.366208Z","iopub.execute_input":"2023-07-11T20:57:37.366518Z","iopub.status.idle":"2023-07-11T20:57:43.876655Z","shell.execute_reply.started":"2023-07-11T20:57:37.366489Z","shell.execute_reply":"2023-07-11T20:57:43.875658Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# tf.random.set_seed(42)\n# np.random.seed(42)","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:43.878025Z","iopub.execute_input":"2023-07-11T20:57:43.879003Z","iopub.status.idle":"2023-07-11T20:57:43.883493Z","shell.execute_reply.started":"2023-07-11T20:57:43.878968Z","shell.execute_reply":"2023-07-11T20:57:43.882638Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## The Goal:\nThe goal of this competition is to segment instances of microvascular structures, including capillaries, arterioles, and venules.  \n### Submission:  \nFor each image in the test set, you must predict a list of instance segmentation masks and their associated detection score (Confidence).\n### The Evaluation Metric:\nSubmissions are evaluated by computing mean Average Precision","metadata":{}},{"cell_type":"code","source":"BASE_DIR = \"/kaggle/input/hubmap-hacking-the-human-vasculature/\"\n\ntile_metadata = pd.read_csv(BASE_DIR + 'tile_meta.csv')\nwsi_metadata = pd.read_csv(BASE_DIR + 'wsi_meta.csv')","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:43.886941Z","iopub.execute_input":"2023-07-11T20:57:43.887252Z","iopub.status.idle":"2023-07-11T20:57:43.922100Z","shell.execute_reply.started":"2023-07-11T20:57:43.887228Z","shell.execute_reply":"2023-07-11T20:57:43.921096Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_files = os.listdir(BASE_DIR + \"train\")\ntest_files = os.listdir(BASE_DIR + \"test\")\n\nprint(f\"There are {len(train_files)} training examples and {len(test_files)} test files\")","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:43.924947Z","iopub.execute_input":"2023-07-11T20:57:43.925189Z","iopub.status.idle":"2023-07-11T20:57:44.019136Z","shell.execute_reply.started":"2023-07-11T20:57:43.925167Z","shell.execute_reply":"2023-07-11T20:57:44.018275Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Understanding Tile Metadata\n\nThe competition data includes small pieces called \"tiles\" that come from five big pictures called \"Whole Slide Images\" (WSI). These WSIs are split into two groups called datasets. In Dataset 1, the tiles have been looked at by experts who reviewed and marked them. In Dataset 2, the tiles are from the same big pictures but they don't have as many marks, and the marks they do have haven't been reviewed by experts.\n\n- **source_wsi** Identifies the WSI this tile was extracted from.\n- **{i|j}** The location of the upper-left corner within the WSI where the tile was extracted.  \n- **dataset** The dataset this tile belongs to, as described above.","metadata":{}},{"cell_type":"code","source":"tile_metadata.head()","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:44.020464Z","iopub.execute_input":"2023-07-11T20:57:44.020824Z","iopub.status.idle":"2023-07-11T20:57:44.039489Z","shell.execute_reply.started":"2023-07-11T20:57:44.020793Z","shell.execute_reply":"2023-07-11T20:57:44.038663Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tile_metadata.describe()","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:44.041444Z","iopub.execute_input":"2023-07-11T20:57:44.041883Z","iopub.status.idle":"2023-07-11T20:57:44.065572Z","shell.execute_reply.started":"2023-07-11T20:57:44.041757Z","shell.execute_reply":"2023-07-11T20:57:44.064528Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Understanding the Dataset Column\n\n1. All of the test set tiles are from Dataset 1.\n2. Tiles from Dataset 1 have annotations that have been expert reviewed\n3. Dataset 2 comprises the remaining tiles from these same WSIs and contain sparse annotations that have not been expert reviewed.\n4. Datset 3 includes tiles that have not been annotated","metadata":{}},{"cell_type":"code","source":"number_of_datasets = tile_metadata[\"dataset\"].unique()\nprint(f\"There are {len(number_of_datasets)} unique datasets: {number_of_datasets}\")","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:44.066912Z","iopub.execute_input":"2023-07-11T20:57:44.067265Z","iopub.status.idle":"2023-07-11T20:57:44.076362Z","shell.execute_reply.started":"2023-07-11T20:57:44.067208Z","shell.execute_reply":"2023-07-11T20:57:44.075450Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"As we can see dataset 3 has the most examples however it is not annotated so we will need to use semi or self supervised learning techniques in order to use this data for predictions. We also see that the dataset 1 has the least amount of examples which is quite unfortunate since these annotations were created by experts","metadata":{}},{"cell_type":"code","source":"dataset_count = tile_metadata['dataset'].value_counts()\n\nplt.bar(list(map(str, dataset_count.index)), dataset_count.values)\n\nplt.xlabel('Dataset Number')\nplt.ylabel('Number of Examples')\nplt.title('Number of examples in each dataset')\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:44.077779Z","iopub.execute_input":"2023-07-11T20:57:44.078245Z","iopub.status.idle":"2023-07-11T20:57:44.300003Z","shell.execute_reply.started":"2023-07-11T20:57:44.078214Z","shell.execute_reply":"2023-07-11T20:57:44.298996Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f\"Number of unlabbeled images: {dataset_count[dataset_count.index == 3].values[0]}, Number of annotated images: {np.sum(dataset_count[dataset_count.index != 3].values)}\")","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:44.304855Z","iopub.execute_input":"2023-07-11T20:57:44.305894Z","iopub.status.idle":"2023-07-11T20:57:44.312440Z","shell.execute_reply.started":"2023-07-11T20:57:44.305855Z","shell.execute_reply":"2023-07-11T20:57:44.311197Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Understanding Source WSI\n\nWhole Slide Images (WSIs), also known as virtual slides or digital slides, refer to high-resolution digital representations of entire histopathology glass slides. These slides are typically generated by scanning glass slides using specialized slide scanners.\n\nWe should expect 14 unique sources of WSIs where 5 have been used for annotations by either a expert or non expert which then get put into dataset 1 and 2 respectively, and the other 9 correspond to WSIs for dataset 3 which have no annotations. Although we should expect 14 we see that there is only thirteen. A keen eye would see that number 5 is missing. This is probably because the 5th WSI belongs to the first dataset and was removed from the dataset to be used as the test set.","metadata":{}},{"cell_type":"code","source":"print(f\" There are {len(np.unique(tile_metadata.source_wsi))} unique source WSIs: {list(np.unique(tile_metadata.source_wsi))}\")","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:44.314413Z","iopub.execute_input":"2023-07-11T20:57:44.314801Z","iopub.status.idle":"2023-07-11T20:57:44.325073Z","shell.execute_reply.started":"2023-07-11T20:57:44.314766Z","shell.execute_reply":"2023-07-11T20:57:44.324166Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"As we can see most of the Whole Slide Images (WSIs) contain 600 tiles","metadata":{}},{"cell_type":"code","source":"source_wsi_count = Counter(tile_metadata.source_wsi)\n\nplt.bar(list(map(int, source_wsi_count.keys())), source_wsi_count.values())\n\nplt.xlabel(\"Source wsi number\")\nplt.ylabel(\"Number of tiles\")\nplt.title(\"Number of tiles in each wsi in the dataset\")\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:44.326556Z","iopub.execute_input":"2023-07-11T20:57:44.327520Z","iopub.status.idle":"2023-07-11T20:57:44.593112Z","shell.execute_reply.started":"2023-07-11T20:57:44.327485Z","shell.execute_reply":"2023-07-11T20:57:44.592250Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"As we can see there are 9 WSIs used for dataset 3 and these are never used in dataset 1 and 2. We see dataset 2 has two unique WSIs 3 and 4 while WSIs 1 and 2 are split across dataset 1 and dataset 2. This means tiles from WSI 1 and 2 are annotated by experts or non experts, while tiles from WSIs 3 and 4 are labelled entierely by non experts and tiles from WSI 6, 7, 8, 9, 10, 11, 12, 13, 14 are not labelled at all","metadata":{}},{"cell_type":"code","source":"tile_metadata_ds = tile_metadata.groupby(\"dataset\")\n\nunique_wsi_3 = tile_metadata_ds.get_group(3).source_wsi.unique()\nunique_wsi_2 = tile_metadata_ds.get_group(2).source_wsi.unique()\nunique_wsi_1 = tile_metadata_ds.get_group(1).source_wsi.unique()\n\nprint(f\"{len(unique_wsi_3)} WSIs in dataset_3 : {unique_wsi_3}, {len(unique_wsi_2)} WSIs in dataset_2 : {unique_wsi_2},{len(unique_wsi_1)} WSIs in dataset_1: {unique_wsi_1}\")","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:44.594383Z","iopub.execute_input":"2023-07-11T20:57:44.595384Z","iopub.status.idle":"2023-07-11T20:57:44.609961Z","shell.execute_reply.started":"2023-07-11T20:57:44.595346Z","shell.execute_reply":"2023-07-11T20:57:44.608692Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Understanding the Whole Slide Image metdata","metadata":{}},{"cell_type":"code","source":"wsi_metadata.head()","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:44.611742Z","iopub.execute_input":"2023-07-11T20:57:44.612329Z","iopub.status.idle":"2023-07-11T20:57:44.628786Z","shell.execute_reply.started":"2023-07-11T20:57:44.612287Z","shell.execute_reply":"2023-07-11T20:57:44.627582Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"wsi_metadata.describe()","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:44.630460Z","iopub.execute_input":"2023-07-11T20:57:44.632650Z","iopub.status.idle":"2023-07-11T20:57:44.659659Z","shell.execute_reply.started":"2023-07-11T20:57:44.632591Z","shell.execute_reply":"2023-07-11T20:57:44.658674Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sex_counts = wsi_metadata.sex.value_counts()\n\nplt.pie(sex_counts.values, labels=sex_counts.index, autopct='%1.1f%%')\nplt.title(\"Distribution of Sexes\")\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:44.661269Z","iopub.execute_input":"2023-07-11T20:57:44.661604Z","iopub.status.idle":"2023-07-11T20:57:44.778824Z","shell.execute_reply.started":"2023-07-11T20:57:44.661570Z","shell.execute_reply":"2023-07-11T20:57:44.777678Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"race_counts = wsi_metadata.race.value_counts()\n\nplt.pie(race_counts.values, labels=race_counts.index, autopct='%1.1f%%')\nplt.title(\"Distribution of races\")\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:44.780448Z","iopub.execute_input":"2023-07-11T20:57:44.780806Z","iopub.status.idle":"2023-07-11T20:57:44.935665Z","shell.execute_reply.started":"2023-07-11T20:57:44.780775Z","shell.execute_reply":"2023-07-11T20:57:44.934513Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Exploring Polygons.jsonl","metadata":{}},{"cell_type":"code","source":"polygons_df = pd.read_json(\"/kaggle/input/hubmap-hacking-the-human-vasculature/polygons.jsonl\", lines=True)\npolygons_df.head()","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:44.937339Z","iopub.execute_input":"2023-07-11T20:57:44.937668Z","iopub.status.idle":"2023-07-11T20:57:49.191700Z","shell.execute_reply.started":"2023-07-11T20:57:44.937636Z","shell.execute_reply":"2023-07-11T20:57:49.190746Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Each ID has only one set of annotations","metadata":{}},{"cell_type":"code","source":"polygons_df[\"id\"].value_counts().unique() # each if only has one annotation","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:49.193118Z","iopub.execute_input":"2023-07-11T20:57:49.194136Z","iopub.status.idle":"2023-07-11T20:57:49.202683Z","shell.execute_reply.started":"2023-07-11T20:57:49.194100Z","shell.execute_reply":"2023-07-11T20:57:49.201830Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(polygons_df) # this is the number of training examples","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:49.204114Z","iopub.execute_input":"2023-07-11T20:57:49.204815Z","iopub.status.idle":"2023-07-11T20:57:49.214174Z","shell.execute_reply.started":"2023-07-11T20:57:49.204774Z","shell.execute_reply":"2023-07-11T20:57:49.213126Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"training_examples = polygons_df['id'].to_numpy() ","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:49.216209Z","iopub.execute_input":"2023-07-11T20:57:49.216615Z","iopub.status.idle":"2023-07-11T20:57:49.224334Z","shell.execute_reply.started":"2023-07-11T20:57:49.216577Z","shell.execute_reply":"2023-07-11T20:57:49.223500Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Visualizations\nWe know there are three possible ids in each image, blood vessel, glomerulus, and unsure; however we should only show our predictions for the blood vessels","metadata":{}},{"cell_type":"code","source":"def create_empty_masks(IMAGE_WIDTH=512, IMAGE_HEIGHT=512, NUM_CHANNELS=3):\n    glomerulus_mask = np.zeros((IMAGE_WIDTH, IMAGE_HEIGHT, NUM_CHANNELS), dtype=np.uint8)\n    blood_vessel_mask = np.zeros((IMAGE_WIDTH, IMAGE_HEIGHT, NUM_CHANNELS), dtype=np.uint8)\n    unsure_mask = np.zeros((IMAGE_WIDTH, IMAGE_HEIGHT, NUM_CHANNELS), dtype=np.uint8)\n    return  {'glomerulus': glomerulus_mask,'blood_vessel':blood_vessel_mask ,'unsure':unsure_mask}\n\ndef fill_masks_with_annotations(image_id, masks):\n    try: \n        annots = polygons_df.loc[polygons_df[\"id\"] == image_id, 'annotations'].iloc[0]\n    except error as e: \n        print(\"Could not find image please make sure you entered the correct id and that the image has a corresponding annotation\")\n        return masks\n    \n    for annot in annots:\n        annot_type = annot['type']\n        coordinates = annot['coordinates']\n        color = np.random.randint(0, 255, size=3).tolist()  # Generate a unique color for each instance\n        cv2.fillPoly(masks[annot_type], [np.array(coordinates)], color)\n\n    return masks\n\ndef plot_masks(image_id):\n    \n    empty_masks = create_empty_masks()\n    masks = fill_masks_with_annotations(image_id, empty_masks)\n    \n    fig, axs = plt.subplots(1, 3, figsize=(8,8))\n    axs[0].imshow(masks['glomerulus'], cmap='gray')\n    axs[0].set_title('glomerulus mask')\n\n    axs[1].imshow(masks['blood_vessel'], cmap='gray')\n    axs[1].set_title('blood vessel mask')\n\n    axs[2].imshow(masks['unsure'], cmap='gray')\n    axs[2].set_title('unsure mask')\n    \n    plt.tight_layout()\n    plt.show()\n\ndef combine_masks(masks):\n    glomerulus_mask  = masks['glomerulus']\n    blood_vessel_mask = masks['blood_vessel']\n    unsure_mask = masks['unsure']\n\n    combined_image = np.concatenate([glomerulus_mask, blood_vessel_mask, unsure_mask], axis=2)\n    \n    return combined_image\n\ndef get_image(image_id):\n    image_path = BASE_DIR + \"train/\" + image_id + \".tif\"\n    image = imageio.v2.imread(image_path)\n    return image\n\ndef plot_masks_and_original_image(image_id):\n    empty_masks = create_empty_masks()\n    masks = fill_masks_with_annotations(image_id, empty_masks)\n    image = get_image(image_id)\n    mask_overlay_image, _ = get_mask_image_overlay(image_id)\n    \n    fig, axs = plt.subplots(1, 5, figsize=(16,16))\n    axs[0].imshow(masks['glomerulus'], cmap='gray')\n    axs[0].set_title('glomerulus mask')\n\n    axs[1].imshow(masks['blood_vessel'], cmap='gray')\n    axs[1].set_title('blood vessel mask')\n\n    axs[2].imshow(masks['unsure'], cmap='gray')\n    axs[2].set_title('unsure mask')\n    \n    axs[3].imshow(image)\n    axs[3].set_title('Ground Truth')\n    \n    axs[4].imshow(mask_overlay_image)\n    axs[4].set_title(\"mask on top of image\")\n    \n    for ax in axs.flat:\n        ax.set_xticks([]) \n        ax.set_yticks([]) \n        \n    plt.tight_layout()\n    plt.show()\n\ndef get_mask_image_overlay(image_id):    \n    annots = polygons_df.loc[polygons_df[\"id\"] == image_id, 'annotations'].iloc[0]\n    img = get_image(image_id)\n    \n    RED= (255,0,0)\n    GREEN= (0,255,0)\n    BLUE= (0,0,255)\n    color_map = {'blood_vessel':RED, 'glomerulus':BLUE, 'unsure':GREEN}\n    instance_count = {'blood_vessel':0, 'glomerulus':0, 'unsure':0}\n    \n    for annot in annots:\n        color = color_map[annot['type']]\n        instance_count[annot['type']]+=1\n        coords = np.array(annot['coordinates'])\n        cv2.polylines(img, coords, True, color, 3)\n    \n    return img, instance_count\n\ndef draw_mask_image_overlay(image_id):\n    img, instance_count = get_mask_image_overlay(image_id)\n    \n    fig, axs = plt.subplots(figsize=(10,10))\n    \n    print(f\"Blood Vessels (Red) Count: {instance_count['blood_vessel']}\")\n    print(f\"Glomerulus (Blue) Count: {instance_count['glomerulus']}\")\n    print(f\"Unsure (Green) Count: {instance_count['unsure']}\")\n\n    axs.imshow(img)\n    plt.axis('off')\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:49.226548Z","iopub.execute_input":"2023-07-11T20:57:49.227177Z","iopub.status.idle":"2023-07-11T20:57:49.250504Z","shell.execute_reply.started":"2023-07-11T20:57:49.227144Z","shell.execute_reply":"2023-07-11T20:57:49.249585Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img = get_image(training_examples[0])\nfig = plt.imshow(img)","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:49.253818Z","iopub.execute_input":"2023-07-11T20:57:49.254073Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f'Image has a shape of {img.shape}')","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:49.788904Z","iopub.execute_input":"2023-07-11T20:57:49.789274Z","iopub.status.idle":"2023-07-11T20:57:49.794881Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_masks_and_original_image('00168d1b7522')","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:49.796622Z","iopub.execute_input":"2023-07-11T20:57:49.796983Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"draw_mask_image_overlay(training_examples[1532])","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:50.451933Z","iopub.execute_input":"2023-07-11T20:57:50.452555Z","iopub.status.idle":"2023-07-11T20:57:51.091245Z","shell.execute_reply.started":"2023-07-11T20:57:50.452517Z","shell.execute_reply":"2023-07-11T20:57:51.090364Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_file_paths(directory_path, examples, file_extension = '.tif'):\n    file_paths = [directory_path + '/' + id + file_extension for id in examples]\n    return file_paths\n\ndef get_train_valid_pats(directory_path, examples, train_split_size=0.8):\n    file_paths = load_file_paths(directory_path, examples)\n\n    split_index = int(len(file_paths) * train_split_size)\n\n    # Split the list into training and testing sets\n    train_files = file_paths[:split_index]\n    valid_files = file_paths[split_index:]\n    \n    return train_files, valid_files\n\ntrain_directory_path = '/kaggle/input/hubmap-hacking-the-human-vasculature/train'\ntrain_file_paths, validation_file_paths = get_train_valid_pats(train_directory_path, training_examples)","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:59:00.646407Z","iopub.execute_input":"2023-07-11T20:59:00.646799Z","iopub.status.idle":"2023-07-11T20:59:00.657670Z","shell.execute_reply.started":"2023-07-11T20:59:00.646767Z","shell.execute_reply":"2023-07-11T20:59:00.656359Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def tf_get_image(path):\n    image = cv2.imread(path)\n    image = image/255\n    image = image.astype(np.float32)\n    return image\n\ndef get_id(string_path):\n    parts = string_path.split(\"/\")\n    file_name = parts[-1]\n    identity = file_name.split(\".\")[0]\n    return identity\n\ndef tf_get_mask(path):\n    image_id = get_id(path)\n\n    mask = np.zeros((512, 512, 1), dtype=np.uint8)\n    annots = polygons_df.loc[polygons_df[\"id\"] == image_id, 'annotations'].iloc[0]\n    for annot in annots:\n        annot_type = annot['type']\n        coordinates = annot['coordinates']\n        if annot_type == 'blood_vessel':\n            cv2.fillPoly(mask, [np.array(coordinates)], (255,))\n    mask = mask/255\n    mask = mask.astype(np.float32)\n    return mask\n    \ndef tf_map_function(path):\n    def preprocess(path):\n        path = path.decode()\n        \n        image = tf_get_image(path)\n        mask = tf_get_mask(path)\n        \n        return image, mask\n\n    image, mask = tf.numpy_function(preprocess, [path], [tf.float32, tf.float32])\n    image.set_shape([512,512,3])\n    mask.set_shape([512,512,1])\n    \n    return image, mask\n\ndef crop_flip_rotate(image, mask):\n    num_channels_image = 3\n    num_channels_mask = 1\n    \n    combined = tf.concat([image, mask], axis=-1) \n\n    #combined = tf.image.random_crop(combined, [512, 512, num_channels_image + num_channels_mask])\n\n    combined = tf.image.random_flip_left_right(combined)\n    combined = tf.image.random_flip_up_down(combined)\n\n    combined = tf.image.rot90(combined, tf.random.uniform(shape=[], minval=0, maxval=4, dtype=tf.int32))\n\n    image = combined[:, :, :num_channels_image]\n    mask = combined[:, :, num_channels_image:]\n\n#     noise = tf.random.normal(tf.shape(image), mean=0.0, stddev=0.1)\n#     image = tf.clip_by_value(image + noise, 0.0, 1.0)\n\n#     image = tf.image.random_contrast(image, lower=0.8, upper=1.2)\n#     image = tf.image.random_brightness(image, max_delta=0.1)\n\n    return image, mask\n\ndef tf_mosaic_augmentation(image, mask, image_paths=train_file_paths):\n    num_images = 4 \n    output_size = (512, 512) \n\n    random.shuffle(image_paths)\n\n    selected_paths = image_paths[:num_images]\n\n    images = []\n    masks = []\n    for path in selected_paths:\n        image = tf_get_image(path)\n        mask = tf_get_mask(path)\n        images.append(image)\n        masks.append(mask)\n\n    num_channels = images[0].shape[-1]\n\n    mosaic = np.hstack(images[:2]), np.hstack(images[2:])\n    mosaic = np.vstack(mosaic)\n\n    mask = np.hstack(masks[:2]), np.hstack(masks[2:])\n    mask = np.vstack(mask)\n\n    combined = tf.concat([mosaic, mask], axis=-1)\n\n    cropped_combined = tf.image.random_crop(combined, size=[output_size[0], output_size[1], combined.shape[-1]])\n\n    image = cropped_combined[:, :, :num_channels]\n    mask = cropped_combined[:, :, num_channels:]\n\n    image.set_shape([512,512,3])\n    mask.set_shape([512,512,1])\n\n    return image, mask\n\ndef tf_dataset(file_paths, batch_size=16, augment=True):\n    dataset = tf.data.Dataset.from_tensor_slices(file_paths)\n    dataset = dataset.map(tf_map_function, num_parallel_calls=tf.data.AUTOTUNE)\n\n    if augment:\n        mosaic_dataset = dataset.map(tf_mosaic_augmentation, num_parallel_calls=tf.data.AUTOTUNE)\n        rotated_dataset = dataset.map(crop_flip_rotate, num_parallel_calls=tf.data.AUTOTUNE)\n\n        dataset = dataset.concatenate(mosaic_dataset)\n        dataset = dataset.concatenate(rotated_dataset)\n\n    dataset = dataset.batch(batch_size)\n    return dataset\n","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:16:07.222252Z","iopub.execute_input":"2023-07-11T21:16:07.222672Z","iopub.status.idle":"2023-07-11T21:16:07.244864Z","shell.execute_reply.started":"2023-07-11T21:16:07.222630Z","shell.execute_reply":"2023-07-11T21:16:07.243931Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BATCH_SIZE=4\nTRAIN_LENGTH = len(train_file_paths)\nVAL_LENGTH = len(validation_file_paths)\n\nprint(f'Num training examples: {TRAIN_LENGTH}, Num validation examples: {VAL_LENGTH}')\ntrain_ds = tf_dataset(train_file_paths, BATCH_SIZE, augment=True)\nvalidation_ds = tf_dataset(validation_file_paths, BATCH_SIZE, augment=False)","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:16:07.887525Z","iopub.execute_input":"2023-07-11T21:16:07.888232Z","iopub.status.idle":"2023-07-11T21:16:09.382160Z","shell.execute_reply.started":"2023-07-11T21:16:07.888198Z","shell.execute_reply":"2023-07-11T21:16:09.381168Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image, mask = tf_mosaic_augmentation(1, 2, train_file_paths)\nfig, axs = plt.subplots(1, 2, figsize=(16, 8))\naxs[0].imshow(image)\naxs[1].imshow(mask)","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:16:10.006386Z","iopub.execute_input":"2023-07-11T21:16:10.007130Z","iopub.status.idle":"2023-07-11T21:16:10.805100Z","shell.execute_reply.started":"2023-07-11T21:16:10.007082Z","shell.execute_reply":"2023-07-11T21:16:10.803689Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def display_dataset(dataset):\n    for images, masks in dataset.take(1):\n        num_images = images.shape[0]\n        print(f\"images has shape {images.shape}\")\n        print(f\"masks have shape {masks.shape}\")\n        fig, axs = plt.subplots(num_images, 2, figsize = (6, 4 * num_images))\n        for i in range(num_images):\n            axs[i, 0].imshow(images[i])\n            axs[i, 0].set_title(\"Input Image\")\n            \n            axs[i, 1].imshow(masks[i], cmap='gray')\n            axs[i, 1].set_title(\"Mask\")\n            \n        plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:16:13.806338Z","iopub.execute_input":"2023-07-11T21:16:13.806749Z","iopub.status.idle":"2023-07-11T21:16:13.815179Z","shell.execute_reply.started":"2023-07-11T21:16:13.806712Z","shell.execute_reply":"2023-07-11T21:16:13.813899Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(train_ds)","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:16:15.597446Z","iopub.execute_input":"2023-07-11T21:16:15.597837Z","iopub.status.idle":"2023-07-11T21:16:15.606068Z","shell.execute_reply.started":"2023-07-11T21:16:15.597806Z","shell.execute_reply":"2023-07-11T21:16:15.604982Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_dataset(train_ds)","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:16:16.465257Z","iopub.execute_input":"2023-07-11T21:16:16.465646Z","iopub.status.idle":"2023-07-11T21:16:19.340988Z","shell.execute_reply.started":"2023-07-11T21:16:16.465595Z","shell.execute_reply":"2023-07-11T21:16:19.339990Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"display_dataset(validation_ds)","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:16:23.505161Z","iopub.execute_input":"2023-07-11T21:16:23.505565Z","iopub.status.idle":"2023-07-11T21:16:24.805450Z","shell.execute_reply.started":"2023-07-11T21:16:23.505532Z","shell.execute_reply":"2023-07-11T21:16:24.804648Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def convolution_block(\n    block_input,\n    num_filters=256,\n    kernel_size=3,\n    dilation_rate=1,\n    padding=\"same\",\n    use_bias=False,\n):\n    x = layers.Conv2D(\n        num_filters,\n        kernel_size=kernel_size,\n        dilation_rate=dilation_rate,\n        padding=\"same\",\n        use_bias=use_bias,\n        kernel_initializer=keras.initializers.HeNormal(),\n    )(block_input)\n    x = layers.BatchNormalization()(x)\n    return tf.nn.relu(x)\n\n\ndef DilatedSpatialPyramidPooling(dspp_input):\n    dims = dspp_input.shape\n    x = layers.AveragePooling2D(pool_size=(dims[-3], dims[-2]))(dspp_input)\n    x = convolution_block(x, kernel_size=1, use_bias=True)\n    out_pool = layers.UpSampling2D(\n        size=(dims[-3] // x.shape[1], dims[-2] // x.shape[2]), interpolation=\"bilinear\",\n    )(x)\n\n    out_1 = convolution_block(dspp_input, kernel_size=1, dilation_rate=1)\n    out_6 = convolution_block(dspp_input, kernel_size=3, dilation_rate=6)\n    out_12 = convolution_block(dspp_input, kernel_size=3, dilation_rate=12)\n    out_18 = convolution_block(dspp_input, kernel_size=3, dilation_rate=18)\n\n    x = layers.Concatenate(axis=-1)([out_pool, out_1, out_6, out_12, out_18])\n    output = convolution_block(x, kernel_size=1)\n    return output\n\ndef DeeplabV3Plus(image_size, num_classes):\n    model_input = keras.Input(shape=(image_size, image_size, 3))\n    resnet50 = keras.applications.ResNet50(\n        weights=\"/kaggle/input/resweights/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5\", include_top=False, input_tensor=model_input\n    )\n    x = resnet50.get_layer(\"conv4_block6_2_relu\").output\n    x = DilatedSpatialPyramidPooling(x)\n\n    input_a = layers.UpSampling2D(\n        size=(image_size // 4 // x.shape[1], image_size // 4 // x.shape[2]),\n        interpolation=\"bilinear\",\n    )(x)\n    input_b = resnet50.get_layer(\"conv2_block3_2_relu\").output\n    input_b = convolution_block(input_b, num_filters=48, kernel_size=1)\n\n    x = layers.Concatenate(axis=-1)([input_a, input_b])\n    x = convolution_block(x)\n    x = convolution_block(x)\n    x = layers.UpSampling2D(\n        size=(image_size // x.shape[1], image_size // x.shape[2]),\n        interpolation=\"bilinear\",\n    )(x)\n    model_output = layers.Conv2D(num_classes, kernel_size=(1, 1), padding=\"same\", activation='sigmoid')(x)\n    return keras.Model(inputs=model_input, outputs=model_output)\n","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:16:27.093670Z","iopub.execute_input":"2023-07-11T21:16:27.094213Z","iopub.status.idle":"2023-07-11T21:16:27.111852Z","shell.execute_reply.started":"2023-07-11T21:16:27.094159Z","shell.execute_reply":"2023-07-11T21:16:27.110868Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def simple_unet_model(IMG_HEIGHT, IMG_WIDTH, IMG_CHANNELS):\n#Build the model\n    inputs = Input((IMG_HEIGHT, IMG_WIDTH, IMG_CHANNELS))\n    s = inputs\n\n    #Contraction path\n    c1 = Conv2D(16, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(s)\n    c1 = Dropout(0.1)(c1)\n    c1 = Conv2D(16, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c1)\n    p1 = MaxPooling2D((2, 2))(c1)\n    \n    c2 = Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(p1)\n    c2 = Dropout(0.1)(c2)\n    c2 = Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c2)\n    p2 = MaxPooling2D((2, 2))(c2)\n     \n    c3 = Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(p2)\n    c3 = Dropout(0.2)(c3)\n    c3 = Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c3)\n    p3 = MaxPooling2D((2, 2))(c3)\n     \n    c4 = Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(p3)\n    c4 = Dropout(0.2)(c4)\n    c4 = Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c4)\n    p4 = MaxPooling2D(pool_size=(2, 2))(c4)\n     \n    c5 = Conv2D(256, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(p4)\n    c5 = Dropout(0.3)(c5)\n    c5 = Conv2D(256, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c5)\n    \n    #Expansive path \n    u6 = Conv2DTranspose(128, (2, 2), strides=(2, 2), padding='same')(c5)\n    u6 = concatenate([u6, c4])\n    c6 = Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(u6)\n    c6 = Dropout(0.2)(c6)\n    c6 = Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c6)\n     \n    u7 = Conv2DTranspose(64, (2, 2), strides=(2, 2), padding='same')(c6)\n    u7 = concatenate([u7, c3])\n    c7 = Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(u7)\n    c7 = Dropout(0.2)(c7)\n    c7 = Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c7)\n     \n    u8 = Conv2DTranspose(32, (2, 2), strides=(2, 2), padding='same')(c7)\n    u8 = concatenate([u8, c2])\n    c8 = Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(u8)\n    c8 = Dropout(0.1)(c8)\n    c8 = Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c8)\n     \n    u9 = Conv2DTranspose(16, (2, 2), strides=(2, 2), padding='same')(c8)\n    u9 = concatenate([u9, c1], axis=3)\n    c9 = Conv2D(16, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(u9)\n    c9 = Dropout(0.1)(c9)\n    c9 = Conv2D(16, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c9)\n     \n    outputs = Conv2D(1, (1, 1), activation='sigmoid')(c9)\n     \n    model = Model(inputs=[inputs], outputs=[outputs])\n    \n    return model\n\ndef jaccard_coef(y_true, y_pred):\n    y_true_f = K.flatten(y_true)\n    y_pred_f = K.flatten(y_pred)\n    intersection = K.sum(y_true_f * y_pred_f)\n    return (intersection + 1.0) / (K.sum(y_true_f) + K.sum(y_pred_f) - intersection + 1.0)\n\n\ndef jaccard_loss(y_true, y_pred):\n    return -jaccard_coef(y_true, y_pred)","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:16:27.603761Z","iopub.execute_input":"2023-07-11T21:16:27.604110Z","iopub.status.idle":"2023-07-11T21:16:27.634583Z","shell.execute_reply.started":"2023-07-11T21:16:27.604082Z","shell.execute_reply":"2023-07-11T21:16:27.633462Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"EPOCHS = 100\n#STEPS_PER_EPOCH = TRAIN_LENGTH//BATCH_SIZE","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:16:29.578868Z","iopub.execute_input":"2023-07-11T21:16:29.579539Z","iopub.status.idle":"2023-07-11T21:16:29.584586Z","shell.execute_reply.started":"2023-07-11T21:16:29.579495Z","shell.execute_reply":"2023-07-11T21:16:29.583423Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"checkpoint_path = \"deeplab_model_checkpoint.h5\"\ncheckpoint_callback = tf.keras.callbacks.ModelCheckpoint(\n    filepath=checkpoint_path,\n    save_weights_only=False,\n    save_best_only=True,\n    monitor='val_loss',\n    mode='min',\n    verbose=1\n)\n\nmodel = DeeplabV3Plus(image_size=512, num_classes=1)\n#model = simple_unet_model(512,512,3)\n\nlearning_rate=0.0001\noptimizer = tf.keras.optimizers.Adam(learning_rate)\nloss = tf.keras.losses.BinaryCrossentropy()\n\nmodel.compile(optimizer=optimizer,\n              loss=[jaccard_loss],\n              metrics=['accuracy', jaccard_coef])\n\nmodel_history = model.fit(train_ds, epochs=EPOCHS, validation_data=validation_ds, callbacks=[checkpoint_callback])\n                          #steps_per_epoch=STEPS_PER_EPOCH)","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:16:30.300933Z","iopub.execute_input":"2023-07-11T21:16:30.301285Z","iopub.status.idle":"2023-07-11T21:17:17.899975Z","shell.execute_reply.started":"2023-07-11T21:16:30.301257Z","shell.execute_reply":"2023-07-11T21:17:17.898325Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# with tf.keras.utils.custom_object_scope({'jaccard_loss': jaccard_loss, 'jaccard_coef':jaccard_coef}):\n#     model = tf.keras.models.load_model('/kaggle/input/deeplabv2/deeplab_model_checkpoint (1).h5')","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:51.378074Z","iopub.status.idle":"2023-07-11T20:57:51.378564Z","shell.execute_reply.started":"2023-07-11T20:57:51.378317Z","shell.execute_reply":"2023-07-11T20:57:51.378340Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(model_history.history.keys())","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:13:11.894190Z","iopub.execute_input":"2023-07-11T21:13:11.894582Z","iopub.status.idle":"2023-07-11T21:13:11.901647Z","shell.execute_reply.started":"2023-07-11T21:13:11.894553Z","shell.execute_reply":"2023-07-11T21:13:11.900598Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(model_history.history['loss'], label='Training Loss')\nplt.plot(model_history.history['val_loss'], label='Validation Loss')\nplt.title('Loss per epoch')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\nplt.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:13:13.773920Z","iopub.execute_input":"2023-07-11T21:13:13.774685Z","iopub.status.idle":"2023-07-11T21:13:14.027392Z","shell.execute_reply.started":"2023-07-11T21:13:13.774643Z","shell.execute_reply":"2023-07-11T21:13:14.026519Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(model_history.history['jaccard_coef'], label='Training IoU')\nplt.plot(model_history.history['val_jaccard_coef'], label='Validation IoU')\nplt.title('IoU Score per epoch')\nplt.xlabel('Epoch')\nplt.ylabel('IoU Score')\nplt.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:13:17.966391Z","iopub.execute_input":"2023-07-11T21:13:17.967687Z","iopub.status.idle":"2023-07-11T21:13:18.242916Z","shell.execute_reply.started":"2023-07-11T21:13:17.967632Z","shell.execute_reply":"2023-07-11T21:13:18.241955Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.plot(model_history.history['accuracy'], label='Training Accuracy')\nplt.plot(model_history.history['val_accuracy'], label='Validation Accuracy')\nplt.title('Accuracy per epoch')\nplt.xlabel('Epoch')\nplt.ylabel('Accuracy')\nplt.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:13:22.584567Z","iopub.execute_input":"2023-07-11T21:13:22.585529Z","iopub.status.idle":"2023-07-11T21:13:22.851391Z","shell.execute_reply.started":"2023-07-11T21:13:22.585495Z","shell.execute_reply":"2023-07-11T21:13:22.850512Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for image, mask in validation_ds.take(1):\n    pass","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:14:01.839305Z","iopub.execute_input":"2023-07-11T21:14:01.839686Z","iopub.status.idle":"2023-07-11T21:14:02.975427Z","shell.execute_reply.started":"2023-07-11T21:14:01.839658Z","shell.execute_reply":"2023-07-11T21:14:02.974340Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"CompasableFunction = Callable[[np.array], np.array]\n\ndef compose(*functions: CompasableFunction) -> CompasableFunction:\n    \"\"\"Function to chain multiple processing steps\"\"\"\n    return functools.reduce(lambda f, g: lambda x: g(f(x)), functions)\n\ndef dilate_image(predictions: np.array, kernel: tuple = (2,2), dilation_iterations: int = 1):\n    kernel = np.ones(kernel, np.uint8)\n    dilated_images = []\n\n    for prediction in predictions:\n        dilated_image = cv2.dilate(prediction, kernel, iterations=dilation_iterations)\n        dilated_images.append(dilated_image)\n    \n    return dilated_images\n    \ndef get_prediction(image, model):\n    predictions = model.predict(image)\n    return predictions\n\ndef process_prediction(predictions: np.array, *preprocessing: CompasableFunction) -> np.array:\n    prediction_processing = compose(*preprocessing)\n    proccessed_pred = prediction_processing(predictions)\n    return proccessed_pred\n\ndef calculate_average_iou(mask, predictions):\n    iou = 0\n    for i in range(0, len(predictions)):\n        iou += jaccard_coef(mask[i], predictions[i].astype(np.float32)).numpy()\n    \n    return iou/len(predictions)\n        \ndef plot_predictions(image, mask, predictions):\n    num_images = image.shape[0]\n    fig, axs = plt.subplots(num_images, 3, figsize=(12, 3 * num_images))\n    \n    for i in range(num_images):\n        \n        iou = jaccard_coef(mask[i], predictions[i].astype(np.float32)).numpy()\n        \n        axs[i, 0].imshow(predictions[i], cmap='gray')\n        axs[i, 0].set_title(f'Prediction, IoU: {iou:.3f}')\n        \n        axs[i, 1].imshow(image[i])\n        axs[i, 1].set_title('Image')\n        \n        axs[i, 2].imshow(mask[i], cmap='gray')\n        axs[i, 2].set_title('Mask')\n    \n    plt.tight_layout()\n    plt.subplots_adjust(hspace=0.4) \n    plt.show()\n\npredictions = get_prediction(image, model)\nprint(calculate_average_iou(mask, predictions))\nprocess_pred = process_prediction(predictions, dilate_image)\nprint(calculate_average_iou(mask, process_pred))\nplot_predictions(image, mask, predictions)\n","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:14:03.605226Z","iopub.execute_input":"2023-07-11T21:14:03.605944Z","iopub.status.idle":"2023-07-11T21:14:05.883078Z","shell.execute_reply.started":"2023-07-11T21:14:03.605907Z","shell.execute_reply":"2023-07-11T21:14:05.881350Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Implementing Watershed Algorithim","metadata":{}},{"cell_type":"markdown","source":"**What is Watershed**:  \nThe watershed algorithm is a classical image segmentation technique that treats a grayscale image as a topographic landscape. It views the intensity values of the image as elevations and simulates the process of filling basins with water.  \n  \nThe algorithm starts by identifying the local minima in the image, which represent potential regions or catchment basins. Each minimum is assigned a unique label. Then, the algorithm begins filling the basins with water from the minima and gradually increases the water level.  \n  \nAs the water level rises, it forms a \"flooding\" effect, where the basins start to merge and boundaries between regions emerge. These boundaries are known as watershed lines. Watershed lines occur where the water from different basins meets or separates.  \n  \nThe watershed algorithm segments the image into regions based on the watershed lines. Each region corresponds to a catchment basin that has been filled with water up to the level where it merges with neighboring basins. \n\nThis what a gray scale image looks like as a topgraphic landscape \n\n![image.png](attachment:4f098cd8-fd3d-43bb-84bf-d4989a25c79e.png)\n","metadata":{},"attachments":{"4f098cd8-fd3d-43bb-84bf-d4989a25c79e.png":{"image/png":"iVBORw0KGgoAAAANSUhEUgAAAf4AAAEBCAYAAACZq8fpAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAMF9SURBVHhe7f0vuCTJkaaL1140YmqmhnVZD1OzadjDetiKjaCWaZiarcAP6DINW7HbUMO0bIqtoJZJTM1uwxZTM4ntL97M853z5Zdm7h6Zef5U9Xmfx8vczc3NPTyj3MIj4mT+lx/96Ef/5+9///ubV95/Pvroozc//OEP7+W1fPPNN284N0h//etf33z33Xd3Na+87/zuv95lXvkg+OLT7Z+/bemzQ3H7z7uln12xBnz73ZtPN59//OOW/5h/jrz7KR298r7zf70G/Q8Pgv7bt2+vSvDxxx+/+Yd/+IdD/pUPlx/aR/yaP/I+5g/86U5eg4L+t1vAt6D/5s1v7uSRa8b6mj/yXPn/sgWJ/3OXf+U9Rzt9Be9LAzcXg99+++1hh49UnjsAr3wYvO74PyzefnSX2fjEP9vPL9n1//5OioeA/+6nX93lXnmf+b/u5CvvOVXQV1J5Jkn4Edzefw36Hza+C3Be9UfeBz1B/5O3b978covXyJNd/+/3PJ4j4CvoE+xJvz6UoAv6z3HM8Ko/slcPJ4Ffu8NX+X5KBWgSAZvADQTz1eAvX698P/jOnvT5QvGqP/I+6An4X/5uuwDYNvfIQ/rlVvH1sf4Q/L+aXQD4Lt9v6f/gTv7sTj6g/p/jmOFVf2SvHl5v9X8gaKdePd8noJNGcKGgCwZdPJC4mHh9se/D4/VW/4fDH7/dgv+/3BUcXvZDz/V/97Lft9v/6/vn+KfP8JPX2/zvP1wAcEFwv+N/3em932h3n/jLm3zGVRKef+X7Qe4EoNLBq/7IS9N/9afjLv8nW1w+Sf+xpZ9uBlv9t9vu/91PvztPXx59HPn5XWJ3n2lMju2xj/lVf2SvXncB7gN/BohX+f7IESs2TvVXHq+7/Q+X6nbg3luHr/ojz6H/+buj/tc/Od7qV/rxjx7yXBR8/MnRvkbP8vVcn539aap2+93Y4BbHBq/6I7fSi9db/R8ABHcCdnW7n1v8n3zyyf3t/upCQG/x521+3epHvvJh8Xqr/8OAwA+ffnwM8izyWvQ9Lz4//qXuCV/8dr6jf73N/2FxH/gVPCRfef9Yec6fgb8L+l9//fWh7jXof5go8FfBAVK/aide9UceW68d/89+fNz1z3jnf5a/8cVvXUEHW0chZ1/ak2N77GN+1R+5Rn92q9+DvoLEq3zZUqw850/woYsCXSAguUugC4hXPlx8gWBhELlwrNi96o88pR4o/+7r5jl/pOQ0qMvxqTy9ODjSjQ0e+5hf9Ueu0Ze3+gkGo2DxysvCPy92/Xt2/EDb11v93y9eb/W//2i3z+KOZNcPKgsv/9dPTutgfqv/b9sFwn/c5Xuy31deJnxOZ7f6X3n/yeBPwB895/fAzy1+vwB4DfwfJqNb/aPA4bzqjzyXXs/3qcMGfnL3Ep/apAQ955eu2tEn3e1+95tkXWXbtX+J+s/4HYRrfv9ghW9P/9LisY7rbMfvFwDKv8qXLfOz+sEPfnCT5/yvgf8U5vSxeaq/oKh2/N2i4TzWQiRe9Udm+tztS/71V3eGA86f8+/f8Xfjg1GdqGy6dk+l/+LzrdAG9u1qib+bfMzAf/8bCVsfcQEAtzpeeH2r/wOkut1PwJccBf7v+45/Jbj7Bddj8pgXAau3+keLxyvPR+72JXm7f4YeCYh54P/59AU/GJ0rL/08Ogb9bWKGwf2Rg38Efr5Y6da/hqjPofwCnwwMr7xcVj+rzi53+xn0uxcGPzQI+B70u/niooo7Kshbp+eAhaBC+tFCXvGqP/KYeu32HezQ/W6L4bPknAZ9vuqvkg/f11+hMVbnyqhO5DFWxwyPoSfgf/HbuBJ6Doqg/+nHn775opj6a45Xn0P5BT7Ka/F7lS9TQvdZOau701W7D40M+AThLriDLhJunbp+HhNfkKsFwunqX/VHnlJPnjpJ8fU38ySO/vRtfaR/u5PcY+aCQFLf1/9AN0ah+lGdSBsvd/1cqz8G/O3/1v0u32V3p22bvGH948BvMXzx27vCxjXzIF5v9b/HEKQyWBM0CBZ+m1+3+F+f7z+QAZV5IdjDLNgqMN8Sv7NS3Wm59W3/PW/1s4hUi8crT0/3bB/5jq/nnfBN3MB72PGzuz8P8LDny3tG58rsPJrV34LzW/q6fZ8XAN0a8Ai3+5vd/h//+Oao552MG9z29/k9u9Wf8pWXy6136N+XHb8Hdp3nGfR9950JsLtlcv9eFugeAxaDJHXVYrzSTrzqj9xSz2eSkp3hLJ371G6f3b3ymXrS3+hcmZ1HWZ++z8de66DTvyF23gd4Lqa1i8/g/7J2/ZB/fbF3fnx+2y/w8SDQXRS8yueVUOmcPcHcfXyoFwEKoBwrgVW39DMAq9ylW8Jcp1/lPfg/Br4YaJGoFmhR2Yx08Ko/cq1+9GwfWT3Pz5TtH76ff5RO6caYyK6yGdWJrPNy1b4bl27rH57lv7RXlga7ffJ//HbLfLx9cMVnsXd+nOGtfhbHDzUAfKgoaF1yq/9DfqPfgyoooLredcxLdzElbhWUu9v66P22/y1v9z/3W/3HW66nn8mUbWHMP3H6PjG6zY+svoc/YbPqzN/oX7vVv3qejOy6ulXfFeWt/d9veZa11J/t+lVXcaNb/pPAn1zyfQrCbdpb/fCYQZ9Fc2965YEqKHWBqvscPegT4D/EoE8Q9+DOHHEuSe/nl9vKbpSwwR55aR7kT0j/FLAYVEg/WkyqtqmrbL7Ygve732+ZPbdL7xbIw84t3nReGYf4EPR8JpWsdviZnJU3+kdB38fo54nrhXTV+VTVdb4h/XdlzrMXzc6gX1HNXVLZtLf6WZiE8reSl+KLrljt80OT1efUBXi36ejafigwB5w3epYPOo8ItCSfA9XRLoO18oCd7qbszcuP/FInVHY9+VuzuthCLrCVTepK/wR9YId64bNSnlfrImA2ju643lc95UpW382fSRx9+nP87o3+czQeH6NT6SvdyM8e+7bMjbLDOaYdPOfatpn5fMtX+vtdvsvu/JT9ZefvpeRz/tE8icrm2d7q37uYdbc58zbp9xWCB4FLwcJv8Xdf14u97/g9fQg7fp1b1bmmeUrclvlhzmb87W/aJe1HFyJ8Brrw8Fv7j3W7/5Zv9Vf1ozZf2N3Kd2sbm0Og952Rbnne618627iveUwxu82P/OaXd8YOp6a9rO/zfcs3+qvPu9JBp4esG9kmbnvY7Ss0sIzdB3POlS3qP/ft/it2+7e43X8f+BU4JF13SzxAiWoBHnGrxe+pudVFyuhzycDvFwCjwP8hPt9nHjhegqvOse68c73mSEF/FthXLg4qmGP3rfOaz+Wxg78Cf7VY7FlAkhW91tTfb6cXPyXrwWgFBaz34Tfi799l0EK/Hevsu9grHYEf0Ks+5d5n/Jd8R3+OrRrrqs6Z1Scz+8PF5d31zLasvfmYP3Xkv88h2PP//pmD/xWBH/xzGc1FV9fe6gfltRBeK8H9CxYypSxX6X2lCi57JXSfS0c150nl/0PAj0XzrwsCQEeSjkSeYE5QJumiqUtqtyeB+sk/JXxKfFFgkYDRgjqzWdG/3Q5TgYwvlPnxdt1EOgTJDQK7dJnU/3sR9BXg7xb2X3F8sajP5h/d7G1+yeqZfqZT/M39Lp2S48gyrOqgOuYK2Qm3zzrgJ4oJ+siP+eGi/9zSFp+J0099e/6MIujDwxv8vMRSfRYk1T1Qzd1sXstb/SxMj7H4V349GH6osKD7Bcs1O//RZ0OddrevO/4jCqYK7pIcO3NBWXPC/AgCvt8p8Hmr8PMYW31GXV4SmHeVlX+qHf8MFpCVRblbfFKP7qf/c5uvTfITsf/z620t3qbur9vujB3rT/7xmP/sqx9u5e/efLQt3pRd/uKfar+zcT412nW+247R71KQ33PhsnKbH3n5jn9rfPjt/XP57qf8JN0a1WeQusomWbEZQXvOMf1SofPrbef/7basffzFnQKeetffBP49XHK73+vO3uoHX6huiS92gsVMyXH9nvQSuVXQh2oORVU3sndu/Vm/JKpjQ6eLAF0UCe3yqcNOtp6o9zyoH+Z8lkcqD7q74Kx+dtfAYlAh/WgBrmzcX6WX7q+bzKBPmWf2LNojsGGdJf36D0d5fNZ/rM9jeq4yu82v//JQ7oJ+tgfpVoM+strhH9K/PuRP0S6S8XTyFPpxvMw4ktRVNkK+3GbUH2QZOH/wwWOkTFzTHG77Pxc3CPoV1dyJqu5sx89ilAuOdNdK9/V9gcAgqqA/m7OUozZAfwSs1x3/Ee3YNS+S0jEfzIuCroI4aK70GeZ8S6pOdqA7Bgl62qgdkNdOX/W5wyefumuodvwsELOFeVS/ShXMgLsAuhBAz8VB2nVSuI/qbsFTSl3MMB7uUnAX4w8/++4w5lX0SGR2/MineMa/isYkZuVbIJ86v7r50AXQ9l/uzcebzckdgMPun/Vhqzjs4m+8679h4J99NqM5fra3+l+5PQSf6lY/wUwSG6GA4wH/Qwz8Pi+jwJ/zkwFfFwVVUEfngb+DwE1bvwDQ54BEz9yTf+rA37GySK8u7KMdLIzqfuO3Zwu6C4rO52NLvwj5Zvu4ZuNXW+HHA10/kuVb/cE7izN6/DCieyShfkWW91C1nfkf9aeLpeFfOUgC715oT/aYgV9Bn8/gEPC5q+IDWeXYZvWzcVR39la/5113LY/t/31k7/Gv2CuweeBX0B8F/tcd/0PgJzBrnjTnCvo+fxXyXaFgjb9R4EcqyKv+sQJ/tUiMFg6xYiPSdhT8JSF1s8D5klDw6cau4xqRPiQrHfIpnvGvjNtJ+73tV3G/Or9W5gPyDsAb3g04XABk0L8i+J/t7gn6499BmDH7iwsn687e6gflJX0RvETCyP8K7utDwY9/zxyObJLVOa76+VAYzU8F9mrDxYEuCEgE9lHyOwF5V0A+Ce7QzXN1XjwWvhiwOEC3eMDMRvWO2yqYCS1IKZMq6Fd9vQQUeOC32wVWNXY/xjwOyu4j8XlySQDjLyaUfvyj8zw89EfwyWf6KU/pxiQefB9J+yyn/aXlyq/eaximf71rsP2XPFzbr7/LuAYBn2+sOnlbH8kaQP7ShI9Tqs+mm58nudXP4uVBKxc2yjMp9tq/NC4d54o9Ngo2BKHc8UtiB/h73fGf7/il1zxRBrUD3a6v8moncpfOvEtHXp8D8ql3/DNYOKoFxRnZVHUKaqqbSYKnI72Tuucs6+KG8srYO/bOEztcgrvKUOW1E772Gb/7npG2e9ruRfO2uuN3uBggJh826Cd/+7++63/3063+juMcE6iP6AVPOnn30/+4z3PrfnO6pW1iBndgXF7z2Zzd6u/k+8bseJ5LJp3+UjxIeeBX0O8CvwL+hxj4OV4CMvm9gd/zUAX2EcwxvhW0ac98C30GyoMuAjzIP1bg7xaIlYX5Fos3i/TKLfzHDBS3RoHHg/7eed4b9JH8+drhzfUJ7+7i/SXP+NVfkvrObsSozYp/dHqjn7z/Od+ofeXr10zN9t+yugDwwD7jdI5/++YPP/v7m8++Qve7w4uex7wC/x6OFw5OdRyO17df4JMStODtlVDlXTdi1c6ZHc9zyUT6nJNqjlZsFBiSrn8xq39fIUBybB44XYdU4JVeycui+jycSufQp2zcL3kuEHTn4KnIxVBUC4jXw4qN6PSrz+27BS39PndZ5E6/G383/0CZ+lX5u6+Pf0JYfUe/pwf0Pf0En06eQj8Vqe/sGGsinbdJuxX/qWM+QPOjPFCu8pJfbvP05Xbx9RUXSX/YLgC2/Buutfm2v908/J/+7Ksf3l9Mkf/Dz8gfg/7DRdZla0A1J+DHKZZu9bNQ+SL1GKiPlE5n08mXxlONU7va1x3/kdmuXzrt+n2XT3J76qvPDLvUU/bdPmXZIH2nr4BPXvagfOqu5bHf6odRuxX7vT5fIpccg+/2QfkV+ddfHduMeHfFjl+ovyT1nd2ljPxXd0lW/tJhCP8ttRn/fJuP80frLbnb31aJQ+7tR9va+tfjevKw6/c7AI4GcCq7zwVW5nx6q/9a3E/lc9bPteNQ++eW17Diw20UqDzgVz/Ug70C/4f6jB8UtD3Iu475YF4y8IPmy+3B5zuhjrnkQqMK/GqHjfLYeb3bP2bgrxaJlYVjxabisdpl/XOXV6naEcAAveqRlS7lpw9fQ9HCY2q45Bm/+nIq3YyuTer3+K7m7ZLn/B08/9dF0wx+OfI0kBP4YRvYxtuz4J8XAmOqwL8yV7KZ7vh9gVN+VXbM6m/BU/Sxh248OWcpnVUb7Wx9t68LgC7wK+CTuAig7kMK/D4vlwZ+2kvvoPPPgbx28FXQZ77B7cgroHuAf4ygD9WOf8/CMSJtZm322otVu6emGtfKWLHxZ9SXyHLHr83iHQpe1+z496LxVYzqOrJNtduHq3f8G4fv/b8jLyRyHJTrIK4dP8b/cBL4PX/aRh/cqdzzmeT4xKO+1e8LYi6OUNWnHNV18qWzZ5wrtmmjwJZBXxJ7oI0C/+uOvw/86NWmC/6Anjn0nT5UgV+fF3ZepwDv5acK/BXdwuGs2FSstku7Pf3N2t66nFT1ozZdAEtdJy/b8W+NLSi5HH1Xv/oVs/I1zHx1d0lW5mOG/6XEzCc7/bdtIH+43Q9u5/l3P/3u7qIsrtjuWNntZzk5+67+lNAtdDNYuITnRVWfErq6TlZjf24Jylfj7JDtiBWbWV8rY3mfueb4CORCO3ThfhWUFfQV8MkjSQr62Cjoq/6pgr7DAlEh/WjxmNmk7yyPfEPnv2rX9TVre+vyyjG6zu2roF/5r2wkT/5GvUkP6G/CCSSdPIV+RI5tVgZvD6vlyhdQr3mr0PcYkPx7DVbL32z/9eij8y+wIeivMXb2MAce9I/rTrfb3zv307f6QXktcqsSqnxXn4zqRlRjf24Jngcv59xUc7THxsl+K1Zs3lc8sCqQug5JQAYkScFWebUB7N0fyB6kA/TVZwLyA2rvuqfAFwhfGGYLB8xsVhYjkb5hZC/Ubk9fkP3dqnztMWKDrpNOZVO9xZ/pAb3VP0qn5BgqGIfj5Wy/twwjf0JzMnuzH0Zl5V3nPxLFD0Mhub3Prh3YuSvvb/E/cHTmdtnm+La/qHf+FRqnk8cHw1v9LFhPtQipr6rPrJtJb/MSGI3rMcap29J+q1+3+btb/brF/yHe6gfmg+MePeenrHrK6EF52SS6tQ/MG0EcHfMqNNdI3+lDBn2V5Uv5W/IUb/V3zGyr+tSNfOyxfUxm/Xq97/ZB+VWpNu1b/RY73j3CW/1ZnjFrX/nr+uhu80vuec7vz/N/vy1//HQ0yFf1i5LAj+68tdv1nveX97b/5VvaHN3JcZvTz2f1s1ihvdUPLELgulW8TdU+deqr6jPrZhKUl5/nkjAal9cl7qNjxQZG/cCs/kNgNtcK4ARZbD0paFPnCTzoCwJ29xnTj3QZ9IX7ekxYNJLUVYvKJTYqu23Vf+UrdaP+RrbdmMS1ZZCuGiN09eg73UyKaod/SP/xkH9Au3oCTCdPoT/wPiHLIFvh5Vn7yl+lE9TlnEiezMMkgcbp4x3BhYCCNhI873cDHjg6H7V5CPSsL8c1pqKbl2r80rW3+j2gpG4mwRexFZ+Jt99D+pOf55I+nm5+QHWVTdat2CSdXlQ+PzRGc6Bj9t2779gFgZoke78IQKc6T/jRhQMon0FfvvGlPDzmRYAvGloUuoUErrGp2qQuF6tZGVbGJGZjurYMlc7HnfWjZ9Toabsqq2f6mR7Y/4yffhL6dVRO2z1tRZZFZZdzIZnP7bsyu3j5ZbevN/g17tztY6PyOnSgiZCs0Vi4VZPf0gcP9UeyXM23dPeBP9Ei5Ug3k77AVgFlpKvarkqo+nhONB7wPFTjrsafdSs2TqVL3OalzN0t8cCswJrBWgFat+mlUwCWnfRqK71u4Ysu76D3uscM8jOqhWJlMbnEpitn21kZrulP3LospK/G6GCHzbWy2sVmekA7/lHqoU+gXyfLidrBrK2XZ+1yLiT3fINfh2wct+dNf3br3Q7e89sKeyL7Xf/P4ln/KTnebvzV2Nsv8Ol0L5lqnHkMTy19DJkXle4aXp/x1zAnHDuBnXw+5wfqmSMgkGu+VO9oHh19jppb5fHlFxS6mNBFSObhMS8CRl/gA53euZVNx6jtNeN+bGZj8PrqTX5I3aoc/gb9He+ueMavvjqyfmbfsdqumr9Kjr7RkOf67N5/9imB9/zZPvjuXrt9+GibV3RIXvRT4EZCl99WhS1tg2uf9fPZHL/NT2PoyLnKsqO69lY/pE4L3UxClZ/pRKVbwccu8hieWkKV92P0+tEcpYRRneN9VMzqPxSq40TnO3ddDAHBF10mGOmF8gr6jts9ZpAfkQuGqBYOr4dLbZy0B+m6scE143ay7toydMcs26xHj07SybqZrHb4/nyf9IB29QSZTp5CHxX0D1nvZdmIUTn9jGzJYz+SfvyZ5MNv9TuVDr8K+oLHBZ9+fAzgBG/o8g8cnaeddvr0k+R40qZqI1RX3uqfBY+ZhCo/0nmfqVuVUOmei2pcwucCVD+ao5QwqnNm8/ES5uspWDlOzWE+7/cLAmyUdMGgvOwo056ksmzkg7x2+tJTfo4LgW7B0EIzWlD22DiV/apOdHXVmPYumnvL6d/LaTt6tk+7yje6kaye6Wd6YP8zfkFfTo61Im1mZaeyreavm5vqmb7+Tv+b7b8au3jseI7Pzt/9jp7tE/ydv1q7MUygjM8b8Q2OfJFPhY/Nyc9kVD57qx9YkEC6PUHBbat2na/sE6RblZA6+XtqCdW4vL6zBa+rmNU76btixeZ9R7t3D7bSeR2JvIK86pQU2JWoV556kATPK7i77jnJxQFSVy0019pkXTUOmNmNytWYbrFoQldO/11/wC8T0g6blBWVXcpqR5vpAe34R+kU+gH66pCNeKxyNX+O1+k5v8rKO9Jr5++2jrfj4oHg/7s/b1cSG7d61p9jgxxLlrPNqHx2q78KRlnXSfAFbeSzagvefg/pR8jfU0sfT3X8MLJ1O+kqP1nnNqLSJZXvDxU/VgV6QJ/zzq5faPePjRI2akfSRYJ2+q7zoK8yddKTJz0lvhhoIakWHXErm6yrxgEjO5iVRS6SWb62n6rfWZ/sWB3q8XON1G42d7defkA7/lE6hX4S+nXS5rHKs+f7jvSe186deUHHzj6f7Ve7ffmhTD13DS5HA5U87vT9Z5193E6WhexFluHsVj8LUofqOukLquer+pW2qxLSj9c9BxoPeB5ybCNbkE6yOm6XCij5wh7Jd6WO65577h4TD8IKtCSVNQ8qaydPoiwU2NXedSTAl/sD1700qoUkF41b2YhK3y1oTrabldNn18dev1kG6Vb6RId91km3V668wa4X067F/VaoXty6DOj8+Efy3//3UVZU+kqHr7Nn+9uFATv133/zw4Oei6tLn/XjP6l0To4z7b0s2/JWv/IpZ/iCVi1uowWvarsqfXxd3VNL6PLVuKu86xy134v7IxApoOmCQBcHBDLkhwxzwRwoIIPnBXOtBH4RoLsBCvTosEuZQV/9Uq868s/BbCEcLTqX2nif2TbH05Wz3awsZv73+q36qXTZz57damfTyV//5KEMmfdd6xFFsVNZfVOct8NXMqq/Zdmf79Mn+VUJ2sn7bn/Ps/0sO4cLA/MzZhvU3W6/2+k7lc7H7Ixsz271g/IpMyClhCo/0lV1e/GxJ92xPLaEKu/HOLPNNtVcdRIIJgrmJP0CH8lvYXvf3wcUkIWCsAKx6hWgldB58osAJKgtEmgHaiNU/9z4ouELRbWY5EJyqU2lE1k3KyfZfzeeLz4//qgK35CGLNOvj7YVs36E9NW4qUM/k85Km9Pn+Kd1wO1sAtbxGT7p3+7kl1vi7T/Jc/BTId9VverEtWWBPvuTrpO6I+JQBwRwt0/QO17Ws/3Ldv10dv53mNkfuC7HmOVs7/WP+rO8l0LwYpFclaM2HdXfZSdatPdSjatjj+0edHzb51v+PT96BSy/OCChR34f+NGPfnQ/5/q7fkn0+kyQTnf+VOcM7UmqY37T7qkvBJ7ju/rT5tZlh8D+5mcnD7SNbbvGL6u09Rvffvfm020HyHew35w/NZ/1H7bzaou5HNeXn22hePC350Pufnb3zb/fyQ19Bz2+gR3rZ1/pZ3nPefvRp4fgtMQ2V++4VghGn881zO6WzOThnYftv692++zc9/zdPu38boD0+jv+z99+d1J+uwV4zWWV18/w3vK7+J2qffsFPp3s8PrKdtR+5vtSVoL7S0MBgTnxXfmlEMAI9gpmBP1PPvnkLPhXv8e/58LnqQPXLWEehAd/Bx3nqM5V5Ai31bnNfGqe/HOm/rkCf7UorCw0t7K5lHFgh1lwn9Q/U+B/8/P/tdX/83ZF+ubNb/7bFcF/aw9f/z/bYVp898+EgPbwm/znfPrxp2vH381Vc0Eg8vzYU74m+IPyP9kCPkFdX94juwz81W1/0PN+SdoyDwR/UPntIPjz1wlV4NdYnBVdZZOc3eqfSdCi54uf1ytf1Y/aum4GC/MszWAx79JzobHfIugDvphfDzQJ9XvmvuIlzeFeCLp5/MyXEmDDPMlW52wl3RYpP5TT51/+8peDfC5ywYDRonELG9WLlbJuzR+TtrSPxGMG/Q4P+rfgL1v6+M2bT7YgBcwhic8EyXsAR+o3+Qn6SwyCPvrqkYk+3zw/Pvvs1D7rVb52xw/Ke9AXGfSriwACfYU/2z9cDFi5grsPjKXa7WusjutoB2lXtRNqs+tWvy94jusrm64djOxTrgTzZBaAOp9anJ+SKgDcIoDqGPGlW/3a9UPe7mccyFVW5mo1uOl4nyMYqu88J/IzWDkPc050PK5/jmMUq7f6fbHsuJVNxcPOfltxT3boWa6Y2TT1TxH4Y9f/7W+3OP3rCPzX7vphu0bi+TO3sn/5Lw+3/IGARzCrbvl//vbTLeAtHP8k8B/0ym/d+B2A87s2b7cAuH0eG/zmPbfK3/30UDyD4A+cUx4AdZ6tSEH5F//0oM/dfbXbz52+S7/lL//Mw9ti149kx+9ojE6lmzFqs3yr/7kYLbK5IFfMFunKx3MsyF3wXAkyq3Cs/qyfz5Xgr8AvyfGvXvh0c1W1T9vZ5/fUnwPjyfN9dhHQkWN/KQFfvMTv6k/bLwgSxKRDcMggPQvqMLMp6p8i6IMH/m63f4vAzy3/4/X94Zk/gZ95JphxMUAgO/3d959tFwrb1ntjOgc7g/6p7eSz2dq9+fiPW+DfGt2h8+PaHX8lueUP1W4fCOjds/1R4Pfy2wj8kEF/FY1dZDnJ+uUdvy+I1UXBav1KnTNbeFcC42ixVr/PzSgYjMa/F+YLfwR+qHb9ewJTd4HgPlYvIiqeOkjO5nrPhVget87vlxT4nb2LR8UlNlk+2eX/fgsOLL4qP3bwf0mBH7Zg86tt1/tLe1HvIu4uAHhpEAho7Ph/9+fN/zbfx+BPNPtyC1ifHj6Pxw38MPhs7gL//XsGW1l3C6rAD6nbK/W8f7Tb97KCPeQFAD4Zd7frR6LzP98DjUfMyhUrNmdf4NPhAVn5Sgej+pU6FlclYDFW8jqS13VpBIux+3sOOO5q3KRbXpS4LwI95E5fY8E2x5IJfO58DtOmI9sqCffzFDAHStXcE8xXU/Lcz/NndIsFCwmMFpNrbLx82OU/F10ge0wWnu0TTG4JnwO7fe7wn/o+Bn1u8U/noJsr1ytfBv0BW7sM+rQ/PP/fzo9vijsgnEMKeJfKarfflR2/ABCjZ/1v727vX/LtfFmuSBv5FpR33er3vNhTn3R1vvADC38GA0F7/MxInwk+SM+xMFdBIpmNfy8+p3wBDfPIsa+MZYbPofyN5tU/TzEby3N8Tv6nf6s8xzhXeClv9bvNcaf/422F3XaB2yJ73Amy4kb5sXb922K8K0Bdw92Ov3y2n9zilr9z927k8W/Pj0Hr998cb/d//varQ+CfcrPAX3w2TeC/b3+otznbLp70Z5DA+aTzao/0tvDRJj3wr+72JfHFmH3XzwUAMnf6FRpbR9bPys6ul/vEKJhDVS/dqK4L7uir4CBWgiJ9eN+ZBx/XyPaWeZVncPyrPlfzTqUb0QVl/NAHKOjNLiby88PeA+as/UsNri+ZS271w2PY3Af8QwB4psD/5ust0Py9CU6PAIF/9U3+Wwd+4NY/L8j9bIvK33765vPPCP557HxAx//LJ2QgFq5Xfrrbj8/mENT3Bf37ObQLAM6tSyRUOr8I6AJ9Sn71z5E/f66vfpxV3SXIz1Lg74LFLKB07SDrcvEn0HUXApD2+OvGo7yeZwO73NGfzHX1t9brlns1XteBj1/s7TdR/1CNocv7uJwqSK8EZv98sXc/2X50IfB6EbDGS3mr/yzoSz558H96vv3yu/luX9zqWb+joPnm/m/71shgLFyv/NJtfvtsDoF9HPgP5bu3+jPwn1xI2YUAcP7pPHwKqT7B9Ze+0CfkS8zKIJ3en5ne6ncq3bVUAR/QK6/xuC1lH08GxQx8lF8ao8A8Cty3OpaVC4OK7mLBz43ZLn2EB+/083oRcB36P/XV58e5qRYJ6PTOtTYPb+1/DwP/IcAtBn249a7/xQR9uPtsCIgrQV/l32xzeBfozx6Z6Ph+889ndwFA+ceW2dfoFr9snEp3Kfx/e3f3HQnTHX8V7F1X5Uc6r4NqVy+dygI97eXDgz0BAH2Hglz6fE48gCaMtwrwmoNbMOp/RnXR4HcvFHT3XABwbHsD/egiQbxeADyQgd+ZLTIri9Aemy/0V2SHgP49C/5VAI2/7T/jhsGfQPkvW5oH5aAaN7he+eXAD9tn8+brLf1hPfBv5fuLp9jtHy8Efv3mox98+eavfztKnXcuIXWPJVf+Xn/GqE3WZfmLbe7ecaG9cdEz/ltAcMhg7AFfFwnSAXovg4IjvuRnxK2C5rX4xc8ebjX+S/tXEM2LEr8Q0AXAJX148NY5IEYXAXvqvs/o/0gV+DtWFqi9NvdBH75vgT8DWNJdANwq8G9+1gOy0Y3b9crvCvp3VH7Uvii//cftdPj9li9u8b/5+XFrewz82ye/hQ3OPZ2DlYSZzaVyz+19tXNWdSPKwM8Cq4XWZVXnusyLSpd4oK+CPqCXDtjle9DJW/xqN8IvHrrjeOy8ZAVBC9sOxr+3v8xfGgwJ6rRP8u4BFwJ+B2B1fCpDt4MXfgxpS510r4H/gQz8ly4o19qcBH74PgX/DGIj8iLg2mf9P9763NO/07VzvfJPEPjvy3bL/yHo8xxJbPHlB9/dn48rElZtV+Tev9cXnX5E51v/peCmO35fyIV0KTPoa0ESXk8b31FSJinveFAH9ef5TrrNU+RXuaaPLn8JapsXJu7zmiDrFw85zgzs1GsMeQHwGvR7MvA7K4vMLWwOz/bzmu77EvgzgO1la398G39rP3s0AAR67JBwaf9dO9cr/5RBf8vrdr9u75/y+Va3GW8XBJe+8Q+rtpXMv9dHdw3pY8UnX3r0zS8Xb/VXgWIlkHR6ZxT4vQ4/2tVrp09Ziz54sFff3TiV9zsF+PULC5G3swG7a/X0n2MUOf5q7EiOeTTukb7aie/F27oP3RHIOwCraNw5xhxnXggIBX0P/uL1IuD4f4o5/c1n/IrLnJVFZY/Nyd/qJy8t+B+CyunXxt6C4/fQT/oeUow/LwIU6JMMoqt07SIIH/LPFPiPL4oq8BMfOCm38+f+TsBmZy/7Aeekzs0VeUmb2W1+2Yosi07f4fYEfr63gf9O0N7qdyqdM6t3PEhn0Fcd/kgZ0EnKu62PW3VV8FMAlj5tVHa92oDqRJbFil55pJO6zsbnZg/+OVW+BXUCGw/kmmuhACtfCv57UFCuxpR9ewD34M6YSF3gh+978Nf/ted4q//kLf6nDvyHAPHHN99++el20f+w8xnxxW//dfv3B+Uvp13D4THH/fgvYfHCJckA2nE3V37Bw8/GQs6F6w8XNE8c9O/zh9v9BH3WHU445Cd2J+AY9G/5pv+szexLemQ3YsVGdLb6iuO//mphx5+LO7hutT6lB6wq8GNHIs/CTR6qXb58yh4ycKjsUnjZbUB5BbHuuFZ1Xqfj9b40/j3Izx5mgY8511xovDl+Bz1zpDaisnVo53hfVcDWXIEuBPBRXQQo6Fd14vt6AaBz5jne6j97i/8xg/+3fzr7LXgFqS8/++rwPfWMdQQ/1cp32H/75e0C/8f8GMzd1GsRvuxC4ILgn0E02eoV8HXRo2PXXIDPh/R+QdBdJIiz4+2CedZlOfJbdD/a5G7/cLFpgf/fN/mL+gLgUgmpm31RT8Wt7YDAD/zSoX5++KbP+GcouHmgzzxSAYTFXvUs8mqvIOSPAFQnPIApaIx2oviT35S3RP1rvDl29anjHuHBdiU/QoGQvrFHVscuHTbyjXR8nrHPPMnbqL8KjUvH4O10AQC0z8Av5OP7Hvz9nHrqt/pPnusruD9W4D8EgYcdK4HoDz/76hCg+EpamH3rGhx/vObhV9ZG9iuSX3f7yT8efxgH+cl2WFwEcBr/6eFUXrwQ2Bn4M4A6d/O1hapDkYB9DN6/u/+62d/+ZBvS9vnlfKB3qgsBhzfL4d3dRQ+c3TW4OOizzugk3CbXbvF/++U/n+76D8H//M/8QPlLJYxu78vWqXTOqD7rskzg96APw1v9I53nu/pEAU4BXnmgTFuCuYKJ6tCDbNQnyYOm7D2IgQeWbmwjFDAywF2CjgV8/K4HHUsF41Ag9DkZgY0Cpbf3vAKmz5X71efiAbfqO4+F+tSB69JHh/cN+kzQ48ODv0idXwB8n4I/55Q+r6d+q/9+ty8eK/iz4FoQY3eqgPWHn323O5Dztav6iVVYbVdJ/awrP5AjmRcC77bAR3DMiwFxelHw8Pv1K5TvFkTQ3/6Xb+nd/VyBz5fPR3eseTGQ8ONAHC/nB4wuFtoLgbPAzzFsxrHbv7/N/9UW6Nn13+32jxcCxzsEj/E3/nv+fK9D/q5Fgf9woXl3ofhoO34tMJIKcCw+5JGqV/BS0NdOHh14cCRpsSdfBUgWc3wTDOSDsss9yM8lbR0dn44H/Jg0VqiOC9KuYjTWrPOgiN4Da5aFt9fFQEXWqdwdG+Bbx1fl1bekfHrg93YZ7Lvyh47+3yn/y7fnAWNlobnEZvgW/80C/3eHxU23qI/8dgtQf78PVm/vfhJ1T+DnOAgu3gZm7VLqR154xEDgk8yLAOYuAyOPB3RBAO+2ei4A3tWb6mW++C3BUgFfbJFyC56aK/CLnvyt+ZVjlwTNg44N/EJBx1pR3hm4D/rA9p4TbztX4oU+3+UfeXgOxPh0zmpcyo90ncygr7pkrx6ybsWW7zD4hPcN9P/q2z/VP8urRdNx3awecoHei/x50MeXAl81BoeAoDY+FhZ8gsSehB8FxkuT+nWdxqR6kvL050lwXLJLNCdZ53OVdRmYKx/kPQG2JM9nyjqV89hIzA1S/pE+Fj8GoEzi/MAnF1Uquy1BTkGPRP6Vmm4Rci6yYSFnEd7i9Lc8b9wW/m+3VAZ92ILDWdBHfr7JQx3/H7ZV7K787qcK+uwa/wMPG5xv/3D44Zm320f+6ccPv4OOToFoBsdGW7UhSFwKvtQvUvMm+dPfvXnzb3fPY5VH/mqLxSze23+RN7/6z2P+sIhfyflfKzxMiuYK/Md7NJd75lBo7jhe5ZHVsf542/tl4nGN4DHM4XM/xG9dvHy2pbvJNL7VXB2qVM8FgNIpnL+M0aWTdS6rnb63x0as6IXqs67zASe2nDP83+H/3Mc/fAj8vlhq8a10MKp33QxstRj7bl96X8TJqw57JUdBhLFIKkiSCC6g8mrCl4LXpYkAK38+DkklxoutXwSAjk3gM+da/sDrRnr84NfnicQYdaHix6EkO82z5yud8lD5kx7cj8ZA3n158osX0Lnj5LnyfYJj13y8ffv2ZG5ysRDdQuOs2NzDR7R9vNt/4e3E2+QWqG/CtkMEPZN+OB4i6MPA/PfQBUFnFrwONivHN0C7XP2mu3b5Kqv+EPDuHgeQZ2yqY4fLnQDyPBq4xfuG2kE/8D+3xASOD/jst+Yncyh0bGqT0o/VLwYkDxc/24H7xcDp+csV5ja5d7f4tdt/eLZ/HuRH4JtzO6XjdSu397v/K50ev1DVq05UNtxtO+z27+64cZeIC6b7wM8CClXAcN2sPnVe16E2CW2pI+Cr7OSCD9gTQGSLjYIYulHwGSXAtwelPVJ+yJM8sJLkX3VID/7K448E2d6RLuessu1wW/LdsWlMI53ynb3yPuckSF2XdDHIMSvYnQS5O50HQvLfN5gr4YuFLySXLjRpA19vwe2Q/vKQP7v1n2xBYGnXv3G8ZX08ps+++uG2sCkqHgcz2vUTdGZcs8t16Etz5gv6aAxVnXSHi4FtSrj9Djn3s/IDOiiuxhjg0TB3/ZqvnI/R+PfCGOUz5zovBJBcOHEn4Hj3YrtquOPw1xPG/a7fjk/wXf58DvTt0sm6yibBxpmVIXVVH7Lp+j/xwf8z/s/AJr/47Q/ffLFd/5zd6mcBTlw3qxfSIX2R1cILyle7fSRJOi3m3hadUADxYJhlDywqP4VU0oWK+mf8jA9kI1T2RDvdARB+PAn+U685kz/GWO32VS/f1THpgmQ1gbd3nyRwvSe3dak5RZI4LzhnqNOx+nnyfUM7fP7fkAfNWTJbSEYLXWWDjmfRhx2HkeVL4DkwO5c3H/NMn1u97FaP6M+Xkmt27tfucv2Zvu/ype92+1lHe+rw4XqCf34+o/Lpbr86H8aTtXcu/a5GFdhVnxcRo7nm2HkXAp+H8++r7YJPz/Z/dnyB77jL/9Pxpf/Dc33Sv1le6RT8MV+STtYhZ7f4YVTGB6SNM7JRHaj+8G7N/QUPbIW7dyLKW/3Vgrla77oVWKA7WKDkTwEfuoWLIIV95VNBDKhX6gJKJaEKaLOk9gRUBXrGIt/SK+B6gtThk7ZKoABNEp6Hbm5GuM88LqH6mcz2mbDTnPjxuS4lc4akvT5jki4oOWadL7T5PqL/Q0jlhS8YInWzhQYqm9EitgTXKc2un13LET5b/l8zoGOHvlMVo13/CnzrmbfJADWCufJ+mBe1n/XvbavPSuDv+MLbud24rAHkQI5Gq7v+SxkFdqez+/l/Hnf/XAjxp5Effbaluzh+uuvnhFH6HyFJp/AZMU+VdCodnM7xvLziY2STdYdvyPyx7o7d3Smzi7mzW/2gfKWDUb2kFhh2G8BCrJ0HaMc+2u2TsFcb7ejQA4s9ZEBQIigoIHi9pALOngS03SOrdgpGGhuJ4/KLAFCd52mLT+k5HlDQczRX4H5oX80b/SJzzlaOnb5G5ZEE+tiTgPZKmlOk8o7PxYcOu3sSx/zJJ58c8vwfS3zB6BYRZ4/NYcdxB7t8pWs47vS3hWzbtRx3rZzvfNYMiI4HA9uodqqrwWcv2sUiCUza7SPZybPb1y642u1rB+x+gDxzTJv0B/nZZFlfxHMKc3h8o/9hDtfncjSHeWxpq+Pr6h3V5fzAl9sFgM69tx9tu/3DYWpH70k7ft/51+CP+eskO/38Ln7IOZ+Vnc6H09kQ8L/47d2t/eTbzfjuTzfPbvUnvlhWC2e3mPqCfgndwu39uQ2ByusUOGWj4KAgqcABGuuKVMqg2Um1U7BSnQd3BWy1kb1sSNKDypLY0pYEsgPP+/won/MmmDe11Vy5L6BM22wvXdarLD9VeY/UnJLQMR+C40rU7kNHt/R97gn6XECrXFEtNFpgxC4b3rW6e5vf0+HNfs9vC3grt/TmT5vhdkj+N+vnb6T3z6fFaNdPAJlx6S4X35oTpPoa+cjx5ByrvvJ32P0WpI+Hi6ZEhudzWe36+XNJ+jz82aTlJdlwVuBDY2Zs8is5w49H8/uT7SII/bFc7e59l++pBj/yV8nk2O8paTcrr/hIm2PA3z6Q4u7Y/a7/np+f3+pP6Yul8r54pM7rLqVaoLVbUR1SwVILv5IHSmyU90AhHwq2q5LkfkYJaMec0A6kV1m+qwsd9Ud7D2ogPf5oK7+gY07kD9vquDRv4BcVQF6fredBZZeO9G5DcrLtStklUM9ccPzVfGafHxLa4WuXT/KdPsnnSlSLF0hfLUJixUZ34v30vb/xsOkP+a39idxOufsy8Xwr59+sn7+R7owGtLkbVw/Zu8vNZ/uru/18tu+7fde7Pz4HEv1Ut/yp6+eNCaaBDjDlEX7eNgO9Qx/06xKwO3wHgLWV5DhWAr3w3T7zIPJ4jzCAPC4Zlg1OyGNxWf29vqOy5kDMyk7nQwx3+ILgz1jv34exHf9oQQVfNFVX6aq6vdDWd2y++9yDfGRbykpAcNuTVpG9gisgpSevOgKtJ2D8JLdBKkkvX+pLbdFV6LPBZuVzSj+0QbdXOlmfeaerdx86dp87IOBhUz1yct37TO7wSQR90IVA91n7guILV7XQ5MI2s/G3+bG9L5v+TBf66dv/JcdB7N31r7DnWT9z4X6ZA9nP+vO2Oe+O+3M79ATHMT54Lgj4QOXkVGqu6IPjuFQ60nExlRcDI5l3ENKvdv18I98RDDbFAaQaPOgvebM/SV1lQ1tnVh75uP+ly/sd/jZBvMCXu/57mI+fH9LwVr8vFCyuSaUT1FWLLSjPosyC5IszUnlsCPq5YOGbdiz0CnpKCo7UIz04gsrSSf+YeN8cC32D968xqQ6JvXauWrj9wkConWxpB7QRtKWv2byB8hobaNyPJZ3Verdxqt2+SF/vM9UOX7t8Je32Vy6eq0UGtNB09ZA2938/fAVqP97t67O+/Pm0IFjOAvIK2pEiCVR7d/vazbofIM88q43fTQDmnn7Q8zW4GUQe5o2D9AMlr/mDnMNtLd92+kAf+L2FdFbbSOpiQXh9zVZ5cn7IUOVzsk+neq4vqjFIl35mZcd9+PszQ362Nfp2C/73324YO34tnr6IaqFwXWWXOq/rGC1CvnBn8FpFC533o7wH3GuQv0466lMXHiCpOiX0slOg53gUkF2vMqisfkB1SJ/XKhAw1z7fkDYvCcbGOYEkMXYk8yDQcQGpi0/slZcE8u8jHA/Jd/gk0AW1JCkZLVKiWoymNtf/91rAz9XTZ/ySe3f92kGPUNs//eV4+zqlb7KYF3xqfpi30cVF1b+39/rc5QvpacN4zslOvHw+hw/yAfm/lXRW2yD//X/fNboDPbDZhYddv7M1PLsAYN7+15tvfr/JXz/4Segzb/GnbdW20uHLmZXl4+yN/ZMdfuz69Q1X97Dj/9m+n+Xdgy+oWmRBiy+LEYuyFiXplZc99T4OLfCX7FrVpgN7HfeK9DajfKK5AWxIlb3s0DMPguMncDNHtNMcAlJz6XOO3WzeqEf6PFHG16XyKfC+/Nj9QifPBx1jdU6ge8kosHOcHvDBzwWdM36cX3/99SH/8x/y5t0pLDTdgidWbA67kf6/2S7Gu30iqD5jdqzAsTPAB/l2C+wEeIfvmufWcV4YcGw6xmskfLRJduO5O6c82u17nXbv7G5TP9vtowOO83d/7uaNvL6xz6ExOnb7R0ej430sCTMbbu1D1v1umyf4hkh+fz4IL5PfnNx/v//5r/ZJjr6dT3Yiy6LTr3D4v8XmncB+/1sVHviRnOusB9sE3L/JDw+/y9De6meRdKpFvNJdiy/WoHFc21cej+N9kM++Or102T7zkoIFWIk6FmJJkL3bELiUQEFcddiByu5PdSuob/D8S0afC+PVfGnszBOJCwGSLqaUd51A9z6g41bQR6JDKk/w1/HNPs9ukXJWbM7e5i/e7F9Ou9BATuVs1w95XFqcL5XA7ejDpos88XVjdEehqpvt6hPf7aueCwH/nvtTvNO7gR+Q86N0n08pnc5GAV6oHRcE5I+7fpRbgwPIO6OT/BYn7x4frDzzB/Qi6708sgOvhyzfv7WvnT5B39/YPwn+nNMcyN0V0T3H5/snz/i1iEiC57VojHRedwm5MPlFAHUkFnYPlNIr2IHyCniyywAoe8Z9SR7pSDezcxiTEvgxOa5Dam4IavKfbRxdKNCPfJE0V9RL5/Pkx9BJ2VXyKfE+GZvQXLkuITjmBcBLQsGclGWCe5aVRPd55AIjpK8WKTG0Ycq3ILSdXvf5A8jMF7pDu+D8GbXWh3y+D8rXB6C300kVHBPHd42UHy4AfJfe7fazDnvay871SD37x0a7ffUL5BkL6fRv9zVvzKE/25eUk+Oz/e74nlo6I1vVSyp/PC4Kcqb8Fizvdvv6qV50uuUv3/5cX6BfobPT2LJe5fO39u1quPuRK1E821dq3+oH5asFtdJ520vAJwFIeF6oXw94Al220Zg8mCXY4MuP7ZI80pFOdpIdugBQcCZQd3oCNgkoS4cNfSovH4IgWI0j9bOx7kX+9kofv+dVX6F50vwAx8dO3nf4ykufdaSXAME84RgFnzc2HLOCvQI/dXleOr7gPCyQp3rh9dAtZj/ZNpeH9B/H71NX/l5mvtCpXY0CV8IANSgN9iirXX+FFvlbS4I/36w3AlvdGYDRrh707F821W4fKB93/NrxcRFAYifM7ZhfbemXd4m8p9PjeCnSQVc960fPrv9LfrTvT3rWT+Ot4oDnxWnZd/7O3rJIfR4LaHd/9nf5Bzbd59sHfVymjrS7fsc/+5/Xz/g9WO1FbavFFchjw6JEkNbiJL2k7KnHHwl7Fn8t7Eos8KpHygY8L7Chjy6f0utulXddh+Yi7dEDZc2jAhu6nEunmztQXvNFnvYzOWLF5hr4fHWugMp+HmnHD36MSJJAl+cL5acmA73mj89a49bb++jII2UD+nw4XhLP9pHffPPN4ZiqZ/wdLFbVAuW4jX43/ha8u9uw9M/2wZ/vCwaj8jH/9u5Z/+ouFmY2e6V88pjBd/vVrp66Ss+dASS38IHdvj/rB/UJ3NX4xT9139gn6qssLi5Gx/NSJHzDdUvBb7ZT/ec8m/85X96zNThAI/JbkLz7NT/f7R9/ze9o/+6numi4DI1zxumf52lN206O+8D/9ZtPP/77mz/yf2I7F06IZ/182dUXv+Xv9uuL5LNb/aDF0HXKz3S+kO6laitd7uQ73Ec3FsaruirvxwPSjdrszbtOMtEiz0LttuhVx2IuMqip7HgQFNXcZrsVPEiqPcf5mHjQhyxzvBwf40ASGMn7hYESOkkSpL/HRkGfsWl8SII7eer1Qh9QJzg2HWtS6UCLppO6atEa2Zz8Tf6VSb9A90C3DmhAGghlzz/s+rUQz6Sz2mYm5Ut/jkZQPj2+I9rVJ9Jrdy9y9+95LjLUdw/GJM53l6foOF6aJB3uGBWJeX7HjY3D7/UTXUlbAx3fj3/45uNfkDnWHb7u93BbH5vPtwCq2+Xn0L+TZWBsieza3f39jn0bvPTbeP/47Wb38ZYO371v2K7/4RsuuWA53ekrf3ar3xcIX/yVH+nU1hdNLaagvBaoXIRVdnsgkIECoCcFN/xJJ3vPC3RAP6t5pCPdavsuj3RU7zB+P373A5TRc/wZ1KlDL2in+fI8+EWD8HGmVL2jzw2yTv3slVDlXZdUdRpPFxgdP47HhkDuibGRCO7a1c8S/2/8/1JFN1++KGkxqhYqMbPhN9JvxRfbLowAefpGOug859zO5/v+2Sp/rLvmb9Gd1TadhCxzAcCf3mlXj77a7Xs9aLevCwL59Tz20h3RmiCZd0yOkrf5NUYfq8i655Skw12Uu8ScKf+78kYHAZ7v6v/Jtvhtk3/3LPzTjz99882ft8yhzIVADf0B/TtZlp3wdst/i7/I/e9Y3MPzfO5iILcroPtn/F+dv9WfC0S1SHYL52gxFp3NqK0HNA9kDjbuYzYW6jkO2e3JIx3pVtt3edclugDw3b+XpfMALr3KQB8Vrpeva3E/8r9XQpV3XY6XOh0/88G5gSQ4qp5EkFQCAr7Kykv/mGg89IPUjt6DOzB+1+35nPA7IxctyIVrZsOzeXbpt0j86dTpn0/xf98vbj2vQWiAPlDqzgfOuDmevdJZbbMq9S4A5SR3+9gn7g/I82jg9Bm45m0+fz62lE5n81QS9Ha/18Gv/nMLsttmP3/fgT+3XCV3/eqzQ32nncqH2/r3f4tf7O7LXb/KsOly138Gu3vf9T+k+2f8LAxaSDwvRrqsy4VUCyd5bFnACOC+S0Eqjz2LNWUFLAJcBrPRjlX2gjr8dfmUXrc3n9LrVvKuq/D58nI1r0AZmCPAv+YLe6TPV44jZeL6yqZrN2PmN0l7zYPPC8etCwHqsCP5eQOUfU6kvxUK5ozBb92DB3o/Zun9OLFJO4Edx0nqnvH7wul0eqeyufXz/dNn+0IXAL7bPz9+12u3rzE/hoRV25kkKI2e7WOD3p/tqz24L+z+x3YB9fCMX/OH1N/w0xB5JN+DAO9jJPfY3lqWz/k5zH/Zzqdt86sAzs7+cNvcdvsPsCvWHMEx/+6n7JrPUf8zsPuMpw0e3O//Fl+bi+3/+H3gR6beNyGb7u7N/vy+C6j/7xxpv8AHtDA6lU6oTgFnb+CXdHtfeLWQgfIai/LYI5V30OF/JZ/S6/bmU3pdl6/aOJpX1fvcEdiQridhqzSaO5B9JVfobDufKTtW7dF7AOV801xwvMyR8OMHBfzHCvwe9EmUpRMqI/1Y0w5WAj8BX8kDvzNbwFYWONamW8Dt2Xcngd8XYkfBHxgceUk45p/6z9Jg1XYm/YuA8gt7Ri/1gco8Sjg+Mqnm8XwObzVfsGp7C6k/cUwOt/sJK4fA+ftJ4K/JOwbq0xnpTl/eu23wrwO/josBbYMwOQz8l8ICCwQfBSjQwlsFflBZ9izO2GkBZiFT0mIN3cItqNPCeGk+pdftzaf0ui7vOvA5Bs0t5Qz8IB+kbu7Ux0wK5ln9e74i285w+z1tGQe2pOp8wxeJMmj3j87PMfJ+HpG/FgVtHYvf0te5D/SvOvROlkHtEvxwbKSneKv/p9vmsXuzehfbR8MP9XBL+/RNdAUtD16zXf/2f+OJg35KWLXtJMH/kt0+kguE0x0/aA7P56+6OwLu8xJ5Cx8z2Z5/BF3i4DYPn27zeHgz/hDw6939OX/bAv9/3OX30QZ8ySsD/+lz/QeWdvwsHiwUKau6Sud1HpTIKyBUCzFl6ZXHXkEftADjX4lFzBdldLlwO+jwf6t8Sq/bm0/pdZ53ncj51Zzn/Ap8KNCB8pqv7CvlCnweGtOedpfS9cFxo/fzzVEwzznQ+SYp3TV40Cep7FJ5YDwq+7g5Dv88K2gL2DJuBfxqx69F06l0SWXz83fsiu4KV/LJtuYdf0q037UcJa9ru+4cfV+7B4jnkrBqW0n+LA852u1Luu50x89LbVvFYb6YX6TK23rxg3878+USurpVeQsflRzu+Dn07b/Sp9vFwUPgn7E5PczN+Y7fUf+C8vG2PuvgNqgM9il3BP8u0Av+QuDbL/nTVb/YQx6PA9ov8JGEFZ2kFiUFoAxKvgizAGpxVh4bgj5lB533D+jAbbMd0A692t8ij3SkW23veaQj3cxOyA48n1BHEMAPn0EyarsHfeZQHduKhCpf2VXz4vUOtrJ/zDkABXOS+s039fl/4HklL6stSf+/EsatxGdMUtBHdseVixW4Lulsbhr0/+vmi+uSj1msHt5EPpcsxAQxArtklY7jZszPLZ3VNikJ+v5mP6jOcXsuGI6wZvoc5vwhT8n+naxblc5qmxVJgD9L/Dk7/MtRrAd92Jw20J+gf8EO/7OvtoB9I45v6393l+qgT7Dn+oD/h/DT3x3lA/rMj+mmz/hBCxOLvwI5KMCzkFWBX9LtcwemhY3EgobUroZ82jvUa+xI1z1GPqXX7c13UlTzTJkLI30OzBNlBX7mCDSPmq/VPsF1Vb0Y1V1L5xs9wRPynGMeKGPD8QN5P2+UT90q6ltjQ0rXScZHEoyRz66DMQv9PxA6LuA2P6DTrv+Xb8e7BqFFdQYLDr9VfwtYrN9t63L/jNLJRxZudxx4/uAKZMB4brlnTHrmrzaQdqkj+P/+m21iN3hJ7XgbmAvffLnv+KM86W9FwqptJ6/10e34gfOKQ363/XcY/W3+iNGuH+rb+qzN28BOdIUsdv2j3T3Bnh+b4jsc+FNQvqeCMvPA+wvkf3W4CDl+7k57q98Z6VJqoVLAyYCUi7DsVXZ7/GlBI++LtAKWFnAt0ORJWqyBMr49n9LrHiOf0usuyTuaW5LmHKl51hxrzoTKmjfAh/pJuQqfhT5HZ9WP2+1tQ99IkuYlzzlBG+z9HPMgT15SuhkZ8P2NfQ/w1HtZ0sfXwThB/x+ElwnumhPy0pE4jl//+KjTgpl0esdtCPw3eb4P22J1fAP7fME6hV3MnPfl2+ckYWbDV9GmHqr86TP+3735w8++u89vZ9OWNsM7/Pk+uP89smrLV+f+nG8B/sPWz5e93cjHTLbnINc43Oy4P7duF/jV/8kv550E9fXAX72klxDw3959C2UV+Hmsk/mHz5x3On7a7/hZMLTAiEqXKMgo+CgAdIuw9Mpjz46Mci7C9K3kgZ968mnvUI/PLp/S6x4jn9LrVvKug9FcUwZ0zA067f7xo7lK311f4LqqXmQdZZHtV/ys2IqcB51zHDugw4/mRPk8j1I3gmBOHyQFdklwHf2pnJ9Vgj/sSaAgn8Gf3T22oIAPHvw5BgV+RwtYx6j+cXb8s8AP+XLaucwdLCj/0uVorPlztJ5P+fCM/3gP+DQQbEYH+t0+VH5X5H3A/9H2f/L/Puq++ev/esPX4uoCoGrLj+JwXlV1nRzt+EHnFtwy+N/v9O937RnY14L/yvP7t3dBX5IADxy/dvqePw/+f7v9W/1auAhC5LtgpEVYeknZ63asFl0teiQP+shcmJUH6rUQ7smn9LrHyKf0ui7vOs0fqZprYG40p0B7zS24z6qPGZ2t+3dmvlf6HvWpcyzPOZ1bstN8+IUQUvk8vyoUwPHvb+uD+gXXuayOAdAzDkBmwCeQo5edXwhUgV/H8tXn9XFUaFHt0OL81+NvulzH9rGsvdGPrP8G3Zm90Q9d3UuTOdbV+f502+Eed/zHtRWOQUDlzdk2f6t//QAzGyS3mX/+/27x/b/dBX5nuwh48/H5797n791zbsGoH5fDu06cMnd/zw8PjzuOG4E5R9v8e/5dv5F/YcAHgj4o4EsS3Ee7fuaGi4Cj/fH/1PBW/4ouJUEHCODkkVAFI8qyV1n2QgsVvpW0QEO3WDvo8H1NPqXXPUY+pddlHkZzrTmmDWWkApjmSv466biuqodsrzE4+sy8PePKc2CF9EM5d9M6x3LHr2BJ35Q1Jzr3JKWroC98k8irb5caI+OA/Hwc7LAXyjNWjVe7ew/wUAV80Ng5FgV+LZpOpUvcRovzrV7u48Uk/OuZdL84+24VGBDlB8kOFjTekYSZzUuRsHqHRX8C+PtvTv9fvb0LHKL6M76VcVR1h6D/n1sg3wItwf8N58j9s+uN+7+f//1J8M+fvn3pO/5yp78z+K8Gff+8lJckwANzsLLrv+mOXwvY5vOQR4LySF+AKbuUvfCFGEnqgj74Ag3U4fcx8im97jHyKb0ONIck5T3gKVjQpponoE32433sQe0YC/zoRz+6D7j0rTF43xXY6bzYMzbqdJ75PMheu37s6MPzeT6lzlFgx2/1d/mqpyyU78aOnrEI8vr8kBnwR4Hfx6tjgGrHr8VzRNpoYf6Db86vgO/nB+1MTtEFAHL/bh+Un8k9ts8ll96p+MWW/h3JfOpV783BNmdvLZBcM1eSasO5wHsFDwHfAt99wGfbzWf51db3sb3v9inzvRCzPlOWc+LXjXfP+GHtUVLy8Pf87U5/MfDPAr6OK3f6npckuK/s+gn85MvAnwsPVLpEi/zm85BHQhWIKMteZdkLX3hBC6DG4YEfqbyDDt+PnU/pdY+Rdx3kfOsz8HbMPXNJXvNEHtxnSof26sfrq7YKcL7rZQx/+ctfDsGpGsM15Hh0XuV5lzt+nV/d+aTzEGQrOCZ8ksj7sZLwIZ3mg3517if4oY1DmbGRgLnLoO/BHnycGruzeqtfi0+Hdvu3er7PwkUAON2NaQB8tuSRs7/f39aXyd+jr0pYtX1KOdrdsuMW7PiP88mfcp3eJXl7FzhWb/PPJHDnhz/JLIMfwf3kT+mOO/7c6YPv9mHWN/KyHf/W8OTcmsivth2/gngX8CfBf2WXLxT4QZ+X5yUJ8MA8dLt+XVyd3ep3RrqUoMVs83kWiLDLBVh65WUvWLzw7Qsxix9lFm9fqGXvixx1Gh/SdY+dT+l1t8q7rppL8sw1dppDzRF5cD+d3Avt6Fe7fAU+xkT/f/7znw/BvxvHHro26D3gZuCnDNgpoPr5pjJ5P6/Iyy/gr9vpkwfJ0bFRR9+JxkciuKucAZ9xORqvkH/J0a1+6PSJFuebPN/feFiUZ7ux+evP7ICgCxKXSFi1fWx5trvVzvYXW2KXv5WPf7rmc3n6MuTbLWhA+q50K5Ld/iHoQwQ+gt3pc/Wj7L4DXxeV2U+lk1x5xs/P8B7vPPhYVvjxmy8/+7c3v6bZBYF/NdjreMCDPvB5jQJ/tesXfkdl6Wd5K13Ka9AOrEK7Mqeyr8aRi53rHjuPdKRbbb+SRzoqE2BhNK/Z9lI0pgT/9M9Y+AyRsvVx5TjSn8qdVPtsB5UOaMPFkdB4VuZEQR9bjkltXO8XBrro6HxLn2NFn8EbdJECGfSxVxLpP/vRAgNaVMH1wusd9NVv6V+S1mH1ZUAkzneS8pLHsWVwuEY6q20eS+r35pm3g/zL3TzyHTz/eiyfQpDjRYyt8WGOjn4qRv2OJL8s+Ib4RuK0JABu/x3qoMf/O8Z0Cn5E1Y+TdX4unSXmg/8a979y1/96XaZPP/7qza8+V9AnmONjc8ov5PHfneDe5ReDvo5bx0jQ59a8o0DveUne4eClWH6K+NOPj0FfvnLebvKMn8VFiyeLoe/elUf6rosyUnnZCxYzFiktdMoj8aN6LXKUfcGjzhc98pXuufIpve6SvOaT+dVOmznFhnlBao7IA/by0ckEH/lZgduT1zj+8R//8X4cJN/tyxZGfe5B/nSeKfD6eQfkOZbunEIqj17o2D24a3ePT+VBug7qNF4hHUnnPpIgrwRIjUtzCWpf+XaufasfnZ7B3uL5/uHb+u42fqc7VO3IUp7+GdpD/sitbl2vSli1vZXkz/l+/ZNj3/e7/A2C3Cf//Zg/7mrhfN4eY47u7/zQHbtrTs3Pt/8zzQ57tNtf6c/l7OVS3YngPDu98zDjb1sg/Y9tJ/2wez9K1oJtHRjs+lf+Lr+ieq4vXKc80vG5qR6jlLf6q8UjdV4HWlA3fyeB3ANSFfglZS9Y1HwBJvkijUwbXwABHb49X+leQj6l143yQnOOJPgoMGnOJDVH8jGTIzob9HzOGgeJz0zP9kmzcaww6l/H35132JC6cwqUV4DVOSrfkqDjBPpSv/SXqP/E9RobCfxHdhT8faydT5H1177VD7d8vn/67NUDf8fdW4AnAZ9BH8sENfDA8FQSVm2vldzaJtDDIdjf7fzPf+sA/Bn/+d/s55/SJSvBOIPv/bP+s7FsDbZxdN+E193mH8mV5/vAeXb+Rv/m4G5eSvn7bZxcwBDodwT/2U5fY0+65/rCdeShm5t8aRL91Tt+LSha4FgcFYRAC221AIPKsgcWNC18oDxytEAL6vHZ5Wf1LyGf0usyz1wq6GiXrbbssJGaI/LgvjvpVLoEG+AzVSBkPIyPOu32Ffhln31LB4xb54bb+FhUxhZJmp13QDudV6C8xqa8xqA59gCPT+UrfYJe/QnXSTIWkoK8Aj6J8YCf8xWjvq59q9+DwNLb5TPu3rZ+CPrajVVSb/QLBq3yeUAD5Z9aPmbfHmT1Fv3X/88x2D7sap3T3T7IX7UrdKqgnxcKb+0a9/45/8Zoh507fvxWb/ND6lIunYdn59mYtx99dbyz8gcF+pSsTeeBf7bT17gddJ999XD7XpyWaXR8NwOd7tpAzgd0F3P3z/g7ugVM5MKyB3yzKFegr/rmFrb3WfXvC16Vn9W/hDzSka5qIwg8+bxaZZF+V/F23q/nZYPU5+r9k/fPuxoLOtcr6IP7d1TGNusq9towr7pg8OCPDVJ50IVGBTb5mYF0kgR8gU7B31HQ93EqLyl/blP1L3IhAi0gwm20yOhZ8zXp7Cv37wNEJ32wPsgY8EYuiE8pndU2q9Jht8sX5dzf4j+gZ9QEOeTW0ObN/TlZFqP+gef7Sj/hPQM2u6QD9J/P08+Db+UXvN9OnjzPb9Lh0cMB9e/yPBHHf/2HuzWI//pnwZ8LqM1xPt+fwHgTD/pIcVreDnZDuu6zgE4PZ7f6U4pZvRbGzd8hj4TRzsul7NnN4FeLn/LqS/nclQnK+FvJ77F9aXlJ5k/Bh6Q5pp6kHb+CB3lwH53cQ+62NZ7Rjh8u7bOzR69zrDvnsJEt5xNj4aKkOrdA56aOCT1v8iMpC/VT4f060pN0zktqh6/PDsk8+/l+Kde+1X/THf92nXT+bX1cPBHkU1bP9h9k9YU9oPxLkdeOqXqv4nB7fwtGur18uqvtn+2PbvFTX+3Aq9vHX+Rd+7uP7N3h1nox4I3qGf8lt/lX3jM53IX4fPu/fP++wYx/3S5I/3k7wbfs3U7+Pn9yAcD6sK0Dk52+xpqgJ+jDWwv8SHFaPr+rVUm/iyOdWPpZXujqu4VuhexDsFiv+K1sfIGd5ffYvrQ8MlGQcwhoalv5SKl6J9uD54HgmO0YT+74nfRRkX1Lqq/KR45jRo4L0ocCPP1VX8mri4wKfHXjTL2Cvn5RTyj4Cx9fdbypq2zAFwMWB+F64fWgxaTaWe1Kd8+kPzu8GKbdFltGJLtEFmlJ/n4fQ642+CaWlA/jysUOsu65pLPaxqXvrpV4i75/pqy3+Y/IzyjoA3bY5Bgclc/u5PzHUT5Q//+o8L5W5DInb/Rn4vx6kL/6fAv64Dt55U+CPz63E3my02eswsfseg/6SHFaPj/g2Zx4HzB8xl8tTBXspIDFnzwSlEdWOy9J2UO34692ZZA7IOo0bqTruvwe25eSF8yhdqIk6knMS7Xbp66TtwBffM4+Juh2+1CNgfH7eTFDvnSOKRDnOUfCN9CmO7eQJMbgx4HEJ0j6uB30Gpfjekn6JlXfykfSmP1cT6r+UqfyNW/1+27/Fl/Te/5MWrv7jpNocoK+Bc4XP+VTjuqeS66OqfzeBL605+Rv1EFzyY7/p+UO25F/xz/v7kIBm+rOz8PvBGg84uEb8JK9O/7ROfgJ3dp/mdH7BsmXn311fLYfz+9z13/pC3zAS3xvm919p5/9NQZ0n5Ps7nf8LAguQQtG1lW2HbkQiU4PLNjpu9qVVT5oh17SdV1+j+1LyVd4oAPmTPajdh1VG9fNfDIeAhUBjbFQTnRMeWwE3I6qXx2z5Ii0qc6tyo8CPZCvzlOBPscpW+mR+GB+BDYe9J0M+tm3/Lo+x5BlLRRO6qpFSwtItfPcmx6eA4vxgrwd4V3iHEl5Si6KLp3O5qmlM7It75wQ0892tLpTcrwbMsPHQD9AEOG2cQYT1YtqTHD4jO/Hw1g0rp7uuCs5pLxOVv8+HsmHhP9DoIdm17/y9/k5xoPfDQ/6SOFBv9J38yBZBX31qbG0O/5q4epgNwWbr0MeCdplaZFUUPLdl9uzq6FPLYTKI2mvei2AlH0xpA6fnq90XX6P7UvIM3fajSqhp37leXrKjtV6JJ9x/v0+dXxW2r36eGA2BvfvNu5b5x7l0fmmdko6v0B5xofEXvOKLyTIbwd18llBPX0xbtD57n+yB5J+nle+V/rL+kvf6vfdH9zijX4CxNqv8SH9Gf8p/qY6+GK4R17T9rGkj6na4eot+tGdk2q3rz6ugXOiGpN+d4FAVD3jX32jfyS7Z/u50z/w+RZnFp/vn+z2Bf8d73b9s7f2QWMUXs6/05cUlX6205f0wC990r7VP1pIboV2WixsWgRnuyhRjc8XOOUrXZffY/vc+YR5c3KHrbYrpK36c73nfTzkfQdNWYEtxwjU48t9JKpLG5UJ+qvHx9jSthuX96c8Qb9DNumfshIBnHNdc6S5Ich7fx70Hfl220o3q6+oFggWjkSLCensue4FiV/jO98V5rN937lytVGleqGTblU6q20eW874mr9wPOPh/2GH+6avitR3dhX4J+j/4WfbBz0hjzPnoJItGfTh5G4I59LD7v4h/ezwLX0H3x70wXf9C+h4CPK//sObN//+v7ezd5O4IKCDB3fpoNM71Xzkbl9jSNq3+itdJ9lRwebrZAc/2oFBtXPCnxZD5ZGgvHY/vhMC6nxsM12X32P7XHnmULtRJfTU32q3P6pLsOXz9O8RIPGZMRbI8UA3BumyrrPVuVSda0iSgi1joA2pOr90IcCc0p6X+fAnnzOwkX/AbwV65kTjAMokBXw/v+V3D12bS9/qf4wd/9tf9bvCc/oAks/3by1h1faxZLnbZ9q202Tvbn+E+pxR7fa5iOP74mn/178dY4F+DvZI/Xzfz62U4Dr91j/fW5CUu/2N4/z865YbXRDZt/Rl4N+Y7fR93vxWvr5Hnztb/n36IBtJ4XqR8yKputH3MfjY2rf6IXWdvAQWJN9paUFFp/yIqm8tcr7YjXRdfo/tc+QTn0fI3b7Ah3y57FCd+oYuD7JXYCWYKdgSzPYgXzm+akwr+JzM2mJLkMcu++9wO4I2belPAR2ZSSifc6Sg3x2z9N53jrdrI7QQgBYQcH2iBYRU7eD3poddSrUDy8Q3rrHrJ/2PkDW+QF4jndU2t5YVh2f792iedIeERPkcfHZUfVX2X362BdqT7w548+bHP9qC22aL1HfN8+dqD7v+PvCuHDe6+nsL7iiC/gN6tq+k+ZH88s0feUSxY2fvMFbt8A/fl38XuPU9+oLv01dA96DvQd7L1ecBPj/553uJ+yif8bM4zBZHRzv4zdchjwTlkSyCuQuTdOg3d2SUWYzJqx66Hb/nR7qqzvOz+ufKM2/Vbl82e3b8yaw+kR1jYrfPZwzasfK5M5b8nMD7GfXX2ais84i+q/OMpAsQ6mmnVJ1fnLPMKeCLvHxWoKcdyKdQns+COvlQHr0CvmSe14n31+E2lf0lb/VXO7Jyx88Cp7V9If/u7ttT13b8cBLp7nnsHX8nYdX2UkmArXa4vtuHbg4veZsfOj3we/Rv+SY82/HzXJ+gnz8LC9r1d2MZ7fglfR782wqh2+kfuH++P97x3z/bJ/DfPc8X3W7f50jP7vXLeB7U9+76V5/pI1d3+uLsrX7wBWNFjugWqNHClXVatJ2qPePxsZPvdM7ILnXPnU8IZEnOl9qvoD6yL/fR+fN+GReBTLf5RR6XS6GLBtGNCQjuMxgXbUnkc/w+bmzwiY1fUHVQL3/ul4CvoK+/yaesQK+88KAvvG/P5/ghx+k2ylfHwqKQpM4XjVxwqh28/n57JX9KtwtLqR1/ppoc862ls9pmr2x3uP314S7oQ9CncL24r/99Xf/XOx27XGwJZnC66z+HOz953Cl9Hs7mZDQX98/3c8d/mujnEOy57l/c9WsOdGsfOPb7X8m7C+iX7PphNieHMQ/Q+EC2Zzt+X8hW0eK7+TrkkaAd12gnprbql50OUokFUuNRXruhbscvOdN1+ZGuqnuKPGiutMtXcvvVv5dP38ylPjeRNhXYMAba8vnih886d/mwMo4k692HziNYOceA9n6O5fml9nquD9J1eHtJ5h897RTUPdA76BXwc84S/Kk/z4tZvdj7Vn+1G4OrnvGzCP7LtpO6i9nv646/k7BqO5J6c73b4da7fSaXC9r6ebp8r1LZ8019/id72sG+vQtg4Lv+dz89P+fAfXOeAWWfBy4K+C2Aw18v0CePh7ie9vwIdvzn3wt9wpeffXr+Jv8W+L/98k9v/nT8r30GY+OCRsecx37prl/kPFS6fKFPdSOGX+CzihbWzdchjwQtvt2iLOmwUOXCTJldmRZpr8+FEp0WPPke6br8av3M7pZ55osgC3qJTl+JC9gSRBT8NTfykbIjLwLcPttS5nPVZw8KcLP+U66CvYIy7ZQfnWM6Hl0seqCVjnNMPphnHZfuCPgYGYOgjfwp+OtP88Qs+GsMQD/y7/mOmU1Vv3qrX4tItyBf+8t8p7/Kl7+Y1qEFnM+D4zrKj37w5cnYJCF1Ty2vGYPfSs8f44HzwK+gf+QxbvMDG2LB8/z/uQVfdvse6EABMAPUXni0cL+r57+RbsV7vgMb+j/5hcDkk83HFme2c/3jbZn9dmtzWFq2w/hym0LuMAh29xwXMEdc2OiY89izXu10AaCLA8AG9NmvyL23+eHsrX7Pr0ot+JuvQx4JWnRZQHNRBpUd/GnBVB4JHvjBF0ugTv6UH+mqOs/P6j1/SZvVPDBn2uEDUkEfO+aCoKKkecEPYCOf6fsS3Ic+T5GfiajGUI2FY9E5BLKRXscMOreUR6965d0XPvDHGF2ihwz8wvMe6IXOWeYef5Q9yCuf7YTPWQXHgt/MV3T1rt/7Vn/3/LX8Bjk4jT0PpP7u19JgfccP58Hspe34OwmrtvnG/P3P7d7tcMfP9vtvx+tQ3x2q53zgV+soE/DZjRPEqPMgp+fUK7vSUd9f5OF5sPd8A/M0f6P/X7fd/T9v/9e3QP+7zd3m978ev537/hhBu/Sf/OMWfyxw65glQRc9rkdX7fr3PNOXzBf60HV4/aPv+KXLwI9UHrQokbQYk7rAr/pcMNHhy/OVzvMju0q3kk/pdZfkmScFfnQKTm576W1+qHTOrL5i1HfKVbDXeaRgrHML0Ov8ktT5CATePH+QCtzs7tVGPsHzQm1E93W7QkE/z1lBW8aS+Y6Z/cjHNbf6QfnH2fEzCDqaSb63n/yRl7zj7+RsbL7LhMNvyhP873gI/L6T3RoeqH/vXr5Xqex1B4jgT4BU4AcPdDDb6Xfjcf1Z4AcP+J4vOAb+0W7/79v//R+/+eLtDw53L+hXx6W7GdUxKojnYw5JWNn1U8/dEqSOe0WO5lZ2FS/uVr8vyiQWV3R5qx+0iAvqtNjJ70jX5Ue6qm4ln9LrRnnBXCnwk3y3jz2JIHPtbX7R2WeZz4ByZbMqR+Bf5xP2Ood0ToF0oDkhkVdbgT/8eNBm3tDhT4Ff/tDrR3kSBXUdh8ouFezBz1WHtvjo8Po9tqJqv+et/m63jzx7xs9HUm2qKj26i57xi9Nd//uy4+8kpK58h+Iu8Cvow1Pe5vfzgTf4FRCZfyAIikuePycnt/gdD/aeTxbf6N9G/uZXn//pMD4CO8fEhRcXAKAg7YF+NfDnxZDQPKYc1Ul2QV82HdSf3erfK4EFFlhkfbHVIlwFfvAFW+BTi7Ly6scDP1J5B52Pcabr8qv1M7sun9LrMg/MmQd9fUkOYMv8ardP8sAP2Zcz6rcj21R4n52s6OrQc/zg5xRgr/MNO51bOhf1/F4Xi9go6byiHikfgj5djwTyfgEBGfzVn3Af3oczqkv22DqjW/2p0+4uFx5k7kj3ctkzfnH6stb7uOPvpMZc/vxu8Wyft+WPX5AzDvzqo2JUB6ofnQ8pR8+fQXYiy1Du9sVK8EdPkDx5vk8nW2f3Ejiffryd0/+8BftjUOf89t1+F/yBcc+e9V+yq4eq7tLb/PCsO37lQQsYyRfmLvBDLqrU4cfzI11V5/lZvecvaeP5lF7HHCnoK7mNgky124f0u5eVtrJx29RVNk6nB+p0/uT5BDqn3M7PQz9nsFHAVh6pwO+7dPno0NwLD/igfjW2xPVp09VVvqr6UZvVW/3Vbh+Uf563+sWHteNPefZ83xb6h6B/PD9PvxnvyGy3v4LGI2bng8tRYMpyBTafxRyc4cHe887CG/1HHmw+f/vlIeiz2/dgj4QM/F5+G4F/9uweurrOdnZBJdQ2uSrwazFR8GaRJK/FUotxLtTSSzoslPhUYlFGl7f6Va+FVaCTT+UrnedHdpVuJZ/S61byrmOeFPB9t48NKOADgUdzkr7cJ3i5ynf2qX8K6FPnT55Puj0P6ICyzkN0tNe86IIRnZLOLfC8LgZGZPDPoP9YcIyzsXWs3uqf7e5u8Yz/8KN6P/PFmWPi85xJ2R91H9KOHznb7RP0jwH/eJ5n8H+s2/xQjRfpdbNn+yvwJ4Ni+2/58La9SV7Gv6cI/g8XSbM7SqfvjPjuHxTg/SKAY2WXP9r1S1/NV8oVW/C5VZ3IcsXFt/odAhOw0JLXgqs8MgM/qCz70W4MPPCDFnBBnY9zpuvyI11Vt5JP6XWjPHPlO32S/BDwCXoEHgUfzQf1IFuXLw0fV47V65gL8pw3swtJPwcFvmh3yXkGXSBXvXA7xiO/yqf0utV8RVXftR/d6gfpqx2ey6W3+rs88BvyrMdnt2JXWHu5732UGfT9W+kU9OGt3U72wF8FffmuGNUB9aNfzgPXdTtS1Tup8/Lh+T7Xd3neCM4f/28ZgV9BH453lDpH1UXScV4TvwAYveQnfF72yKrtNRdT8gMX7/h9EdHiymJL3hdd7LqFWnnZQ7coe0DzgO95oF5jQ850XX61fmbX5VN6ncP8+E5fL/VhS7D34J/zAF1fgvnT/HteVG1g5HOVPW2x1flTnU+gMnAcficA8KHAz1xRVtI5NrqzRLsOn3ugX9o9Bu676mel70tu9UMuRDfZ8W8L6LuvV3ZkHQ8XAB9K8M/b/HDY7W/x7N02TQr88NaCP1+SQ4B7qtv8nRztSPfAjv/8Gx4f0PlzeHdPdwGs79PAPzq/Tu8ejeAxAIx2/dWzfNW5blWq7egWv+xFlp1nfcYvKXvoFmWk79ZyUXbQafFDznRd/hLbPW08nxKYn9zpM4eg2/vdTh86vyvkRcCKH9V52y5fMfPNHEB3PimvPqSnLSBHgV92HvhB9kjI8014X0lX5/qVfEdlM/Kxcqt/tNAD+XbHv8K2aB42X3d/y7//Gb94WN1ZjKtxVsfwUuXZs32mZTvlvvzlFp62/+76khzxNnb9+BmhvsSsDKtBf/XZM2Q/WQa/1X+Gzh/H7gB40Ifx+bV6oXSc59z1O9W83ELmbl91e6HdVbf6lWeBBRbcauGtFmpQWfbA4opPFl9QHokPpBZi8DxQj0/Pj3RVnedn9V0+pdet5pknD/zME/UkyJf5QO07+Rhc4tvbVO1z3EidL9X55JJ5yt0+4GNv4Fc9+Srw04faCdfN6vcw87uC2o1u9UvHYg+5ALm89q1+0Jv9l+34t0EcnhUgCfzv/44/51S72o/+ny3Ib0ulP0MWKldfiyu/17ByLiBHt6IvGYd/O+AKh7m6g3PKeTi/GMQ2mBP5cA4dyXrJIzrPYDYnKzYr8tIX+rIMz7rjV172MAv8qtfim4EfqMe35yud50d2lW5vPqXXZV4wNwT8fKGvur2PXng/KYWXu3xH5/Mxoa/Rjl96yn7+gcZKGgV+dHmrH2SPBOkd9bEHb9PlZ1TtVnzNbvVXOzxIHV/gIrw9rJZ//ZNrAj/0t/pB+fdFdt+N8PZXDzv9t0Xg3/v8V32KLIN0Kzv+S3ekaeflsx3/3VyU3NUROraloAj83Y5/dbf/QN5ZWpWwauvSg750IssrXBT4q8VEiyyLLnlsSOSlu1XwR3rA9zxQj1/JSlfVeX6kq+r25lN6nWBecsfPsRLwq1v8ld+Ue9jrw+svzbvOQa9zpwr8SOWZp6fa8XfQt/wp77oVqnZ7fYhsN7vV7ws9+CKUOn11qxYfz0NVlzaPGfwlIXUvTXY/v8uP4Bxu8//tNNgr+PMnY7kjlF+R5T2s7Pgv3ZGO2Lvjd3jHz+nPLT3fX+cW59ge270XdaD2wstnP8s7k+CLUEdlX8ECXcEC3fl3fyPftPexkk+f0lV2l7ZdySMd6WTnQV+2BCQFfYKPApDa7EWBDDwv1G9Kx/v2+kvzkvLLuDQ3M/xc4vyBlXYjZu293vM+L8pLdm2yr2wHMx+i85WwGHTkwuHkwiTpdeA+PC9k17xAvYNwXJBjfWmSZ/vc5v/JPx/HS7AnfbXFq2+2/+rYVHB7P3eEgF8nyyL9ZlkXgUBdjhtZ9S+yvDoO+uXW/TT9a6Hb0jm/KRK3FHhZb2+qqeamk87Itgv61DlZzj68vHvHz4LSLSIEK2DHpZ0XaEemnZjqtTjlLVrQgn/trn9vfqSr6jy/ajfKOwR9XQBQjx1Ut/hVP5KrMJf+WTidTy97e9dX46h0HTpnqh0/5HlEGf+C/GjHjy5v9auePO1Ac9/BGGiT+VWqNit+Zu08f8mt/pFkd5U6GOkyf/2uH467t/fxWb/+hO8Tnmj9Ykv/figefjCGPxM7/Mb7I9zin9Ht9l13ix1pQr/X/NWIdvzqp37Gj06DkG4m+/MLUrdXpo/Rbf4Vqjb3O/5VqoWlw22xY1HVTmwFbDv/7jvHBN2CN8t3Oudau1EeCGQk15H33b50oPYjuQcP+gp2Qr7Sp5e9veuV17ghdV7ndHqBHz+3ONdmbRK/YyB8/B1p4/163u26PKiN6yvdnnbg+QotDnuDPhLId6TduE21M1tN9Y6sGvNLkdze/+v/dzfQjd/4neftlOYWf745DtzenwVc/Cf0W5G2Xq7GLm61IxXY6RysdvKH1OzyPYnzfjQQHxB5GY5kHETg83OpdPLxSdZX4MfxNqq76Fa/530xUUDyHRVot8ROSjsq7bBAO6wMMqPFuxuPoB16td+TX6l3ujardpkHBU/mSEnla/F+urzwIJ71s7JIvebF9dJVdUJ1HR64/SLAfWPDMenugZLuFtCOetmA8poL6YXGSntR5f2Yqry3gUq/p52oxiJykRC5GM3k774+bwcreclf/Sc7WHa+vGz18wsTO7i77wA21N9LlNze/81/23b6//041kP5X7YMu/7tlKbM2/zAbv/ttssH2jtZBvyLmb3bAuWVi0DHy9Q7WRbpQ3bov94uesr0l0IXKal+qfABOtVARvI4uL/+7ddn8/AY0kHndOVs56juqrf6WURykRktltjnbVrdjlVZ9n7xoKQLBNpTT95tMiii0xiRrlvJX9vuEjufM/Ago+PDXlR+3N+l7PFR2a7qVqCdny9+/ui8Ul5zp/MqQafzZ/X8AtkjQXr6xW4P3qZqP/PZ1c/8Ot2t/urb2SB1lbzqb/oFHx87yN3f4uf8/uxWLIzG/lxSt/fZ1ftLfSq/+Y8t8P8PylzMPExw9TKfI/+X4G272/ySj3GLH+i3+hKjVXgnQnh/52/273+jXzz2d0aMPt9V5CvZFfhXFhwFKhZgX4i1QK8u3KDFlwUZlEfiA6kFGTwP1OP3mvyl7Tyf0usczR16ksqCY+t8puxgjjTHbjtqV9nN+hGV3chfV8d7DtCdP5J+voHaC/IrgR+ZNuTRgZ9njvfX5VeZtV/x2fno3uq/5Da/5LXf4gfcor3+Of8R3+H5ccHsWJ5KenAbBf83vzi9i8GFzZ7AoD4rurrqXADXdWNIn10fjtvQ9zXn0y/+qe7v/Lza/0a/eOz3SPyiSnqxtwyuuw/8WhQ66VQ6oQWXBZi8L8S0W124YbY4U09ei7DsBXUaq0uvW8lf2q7LpwQdv5eZC2xIoGNTufIlmXT6ij22zmwMl4I/nS/V+QMqM2fczu/6x9dK4O/OLST4eQb0h/0Mt6vyMz9VfedzhAJ/LhAsuIBOdavy6h0/T2fufq3vMQP/S5G5oy0DP99Edwj6p+8tZFv5TSp9Z5vMzoVRYFqha6PP6prziYvHivPzSn8Gug1mlzwP/KD8tfKSOyl7WN7xry44WohZgBW8QIFtZeF2tACv7PrJk3xRpoxfz6f0ui6/x/aSvOanK/sxAnq1T7kHb1O1H/lc7beyW/ErKM92/Mr7+Qboae9Q9uDvwZw6ynluQWXf4f1WY1jl0raz/l/yjv/81/ou49OPP33zx22df7fFTD8umB3LU8jq1/cOwf4/t+D/b8fyF7/VbWvmY2t0CDw/2QJ/f4ta/veS7Wbnwsodh/SZ5QpdcNzijX7IPk+Dv//Q02Z4n4eu/KB/rLf7L72TkmWodFc946/QglsFfulmCzc7NmxAiy0Ll9I1u37X7c1f2m6UB82Bjh00b9iSdExq28kk9cyPfO9h1k+y166yZ6zoSJqjLvD7HAL1+KxAn+cOknTJrp9+sct8x8x+plN+5idxmwz8LA6jX19bkeUOjf/Geueyywt0vNTGunzlc34FfXx89INPl4/hqWQV9MF3/cegr/+rW6OFoD9CfYssO5cG/ZHPDm/j/Z59g+EO3g1OndPn/Jc/44dLv8FvJH1upbsV8rfrVv9IJ1iAgQWYvBbivQs3ZV9w6ePSXT+g01hdet1K/tJ2o7yOnUSeOVA9kqRjA+kr2VHVu67Kj3xmXddmVk66es1Rdf6Ayn7+ADp8OpQV2P2cIa2cVxn4R3j/1VhEVTey71jtr7rVf+2u+GY7/u0C4Lpf6zsN/Nw5eOznsXvkrz7f5tp29cn9s/3tQuzNz7nNvzW8D/yfboH/s00+IL9Jp19Bu+5q/ApMe/ynbdfW+83fLNhDfmsfqM+H84oBkC8Gssitd/yrc5v1s3Jysx2/FhktuCzACmJwycKNv5UFmnryWoi7hRkb+vB8Sq/r8ntsR3nQvHDcejbNXIAfs45F7TspmAPN5UskxzsCW50f1fmDVN7nMUGHL9Kl5xX57vyS/8x3VDajdnvthdsonzv+0Q4PujqXN3nGz12A+1/ruyzwnwZ92D6n3/zzm4++nB/DY0p9HS9/uufP8pP+2f5xp3rtbf60yfLoAvDSW9CreN/ljt/vFHX5jXd26uRYHvPN/mtkN7dCdnup2i0F/j0LjgI5C7AWYtACvXfh9kWX/lZ2/aon+eJMGb+Srtubv7Rd5vP4kcwNZPBBAjbykbICH/ocwG27vEj/lX2268qph6quan/JW/2UaZug09xqXpVuveMXPpZuXBWV7Uy34r8K/FAtSC5HNrfY8YPe7IdLgn8G/ofyrx9t538I6rMLnx89BP1Z8D/e5ifwO1wNEPhHf49+jsa5SncuwLUvneVYsux933rHL84D/zbZB+4O8v7uCozz/Fmlz5HPVepmsptb2awws1X99At8wBcUUemuQc+2gUW3An3XX7UQJuiwk3Td3vyl7ZQnMJEIVCqT96DvcwLYXYIHfXA/VV7jBOlSQqUDlf14XTpVXWXnY0qqOnykHh3Bem/QB8qjoN+NX3naC8+DbEbtvG6kg6re8w4LgciFqJJO1vElM6QfbwFO+UvK19AH/WNZdMe3Rx6+ce8PW4D+853TG0HQp4/jbp/EtyOR9O2EpzCWxHVHX+dkO8racVdkYJr1C1lO3172vmnHBeClqaPe7TNIDZQBrOW7oJ/H2Nm4HM1t+gOvB5XTNu1UP93xs2BUC9VIRxADAo52XiQFNySLq+/aQGUFKunxu2exBrdTWaDTeJGu25t33So6Lo5T7dEhtaMVOh4dJ3i/3Thop3l00g4qHezRS9e1ESM712Ve54bmx88dpPIcc3erH/A1O5dAebch7+fXJTAu9eH5W7DH3+hWPyi/KoV+pjdtXOf5TvfLn2yKTe59u38c+PGzbQX/9M+Hl7l16x98LKuSF/QOt+XZ6Ws3f4NdP4Efji/2bR29Of3bvUtv9Y/qhJ8HkkB+dCt6xbdT2ftuH26x489+Tu8gUUEZyYHukdv584PjYxifq5mEqm52m1/I/lpu/lY/eGDTYgwZ3FYXby2yLLosbCzKoDxSi7n0akPeywId/iVdd0kedNwzOD5vq2NGchwcOxIbD1DYz2RH1lf2Ix977YVsOttVH0/5BT7ggR9kr3PMzyfvYyU/YtRG5Znfrt7zHvirxV4SurpK3uTb+7juvft7fli93T/f7W+f2V3Qf/Pz/3XMC7sQGB3f4cW8u0BPwL4m8L8h0G07PQ/8n7AhPYyvCvp/24I+3+azD429Q/Wj88B3pDN/FbM2eeEJZ8/4OS9Ob4LWuo13zSnzkp7vA3kP+qoXWa5YaZO66Vv9VV2nE1p0Fcx8McZ+z+It/6TZgk09QTMXbVC7BDv14dLrRnlgnIKxp69OgtpS1rwo8DNmbDXuFX97qdq6Lutn9lDZzJj1qXOlOndAZZ07lGmXoPO55VyRnjxznecQUvkq8F8CY8Vn5itm9bBi42TgBxYGLRCVXLF5jOf8sBL8Z4H/UP52Oz/+fTv2X5wH/rOLgQoP8FcE/0PQZ1vKD85b8D/4Isjev83P83zkNsGbrJ7va/6TTg9V3eg82LPbH/WbyNb7BvS3+jt+UD/nO/6t4vDhLw7YyPdFQPlVCZe+NyE/IyobdDd/qx+0GLMIk89AfsnijRwt2LIDL/vCLUaLNnY6Fpde5+iY0naGzxHtNCfoKZNH6oKFPHg/KR3aaR69vrJ9LLKvHO9sLF4/OneQynPMfrdIUMafPnufVyU/bzzwg+yRIL2Q/9V8xaW2FZ0v5RX4q10epG7V5uIdf+7ctjJ/0idmgX856H/73ZtPt9j5x7tAc2A16MM1gf/Hx/+Pb968PQb8LTr95l/+dHK7/+ELe/51S+db2dnf8Otz6OjqR+dBF/RnfUHarPQP5G/9zX3nu31x2a7/Fm/0r85tlq9lGPirxWW24IAHNS3GcO3iTb8K/tWijT1StkpapMljo8XbyYV8ho4RdHzC60bQjjExD+CBHzL4aPyd3Iu3q3zN8jPdXrq26HWudOeOpJ9rgI72IDk6h2Tjc6968l3g34OPyfMjZJf2l/gCD/xQLUrIUV1lc6sdP+SubRT8dwd+8mLTvfl4MfDD3uB/H/Cdu+C/7fYO9nfB/7MtBvHLb3qDP8kdvz6HGW73Ba4P707csR3/R//36Wfqn+21t/lXqM7D7kuOVtCP9Ph4Cfz88uNnX6XjuxdTDnDQNJjJbY25wY7/krmt7FI3s2lv9Tsjndcpr0WXRZi8L8bSXbJ4k7pFG7RYY9Pd8qcsf+53L4xRPkBjBdWB+vC8pAI+MGYdP+Oubjdne5cz0s7bixU/e5mNs9K7jvws6Cuv84Z62jmUmUds8/xRPfONvjp31KYK/PiUn5X8iEvaJCtjGO34Owkzm2v+9jrJXVsX+K8N+m//US/SbfzpOC9DisD/CRcph2Cq3bz1UXIe+N/8ZUubvzcfE5jqyVn91j59JskXX24+tuuK++CvObkLvCf8YbPlbsgC2d+ecnUO3uqX+cRxt/+7LfB/Z4GfOeZbkmxgO7h2x3/pLf5b0O74q0VndSFSEGQh9gVZC3W1gIPKswXcg78WYqBOCzY20rmNL9gOdjq+PVLoONEDY69gXAQWz2su5FPjzeCTfUtWdDb49s8DfE6qdt4mqcZQ6Zw9bdDrvEBqrijrfJLM40JHe0DSVnPLMaPzes03+NzLjry3vwYfm+crsn5WXmF1x9/Jrs01b2InueOHKvhfG/jPdGJ0ERDB//DXdtuuf2/w/9Xnf3rzy9/e+frP4xg17ge2ib3baea39jn6DEZ8sR0rF1RfEPsY7xZ82sC/HdehbrPn9w6clb5Wqc7Ba9/oz/Ep8MNp8P/tm7cf/X27WGB+STRakx/94O/3/biE1FXy2tv8lX6lLbqbPOPPhUcLLwsxeV+Qse0WcOWxJyBSTuhHCzh5LcyqY8GmHfW+0EuXXLOA6ziBMdOHgrpgDI4CvfK0yePkGKjL4APYknfpVLoEG96Sx66aE6G58b5htd/UzcqO143OG1C5O2/wpXOBY8JGc0qCLuiD2mmupHfoU+1X8hV7bCFtuvaVLwK/77RA+b3S2176/epfHtfkA/LN4q+8yMD/aEF/igf3Lf/7Lb838G/93+/2P95sD0GfgMT6UN8KyR1/zk+S9TyS+DV/KrnBBcAvf393/H6Rw6MJzc3dXK5+aVD2NytXu3245ff0e9CHh8DP303+wxb4v3u447PI6G/481hSlzt91a3Q2a74cJvhrf5VnZBOCzILsQI5zBZw8iqrDTbZD+VcyFmsQYsyNtRjRz3IRuNEajG/FMap8TFWQb863hluo3FDBiCNOeWMzk7zjPR5Asp/+Qv3Ho9zig/Isabf1TFVdP50nlTnDVJ5P88APe1JtNP5Ih0gdV5I5/MuW/L6XPR5XIrGlfkRslu1r/C2CvygBUmy0q3KS5/x88U98gPKVzs/D/7PF/jhNsH/+Ib/ZncI/A/HVrESgH0eHfT8EJO+a+FwAcBdlfsxGxH4Yc9fFKzSnYO3fKM/Az+8++l3J/q398Gfg+Edi/FBXfM3/KO/kHDU9jG4esdfLURaeBVUfEHGvlvA8SNdt4gDUgs55GIO33zzzb0deFADby/f3kfqqjpgvA51ksrP0NgYE34JPLqYoazjA/XtUnA8mresS6hn7D/60Y8OUvPMGOib+VOwU/9VnzOqdl1eZP3ev+GnnnaA9PNDQR5Uli24LXnQHPj5JuhX7VfyM/a2S5vV9v/w9+/aBeoaOf2FPtjKX94t+PDH7SMhwLsfIF8FAAX+5w36cIPAjx3PCb7dDvrj+k1+p3vG7/PWod21AqN2/mfB/+QC5OGbAr3vWX9Z35WrHT/yVm/0H4M7EOA1gH+42/U/fDZvTwK/7Houfb4/epkvy8mq/YpdGfirBWNlERIKIizE5LUgK49UgFEZ6AO0sFOHjfQOY8EHeHDSGJEs6mrrCz4o2I7QGDu8XmPR2IWOrQPbHLPKyivQkJe9yxFuU9kzPgKrLgAAO9Kf//znw64/+0+k9/rOtmPkW3OKZJ5V1tyq7OeZoD1t8hwhgc+37ACdjnsU+PfAGNVXl6/I+sp+5KPqi8APLAhaGG4hV3dqvsPn9vN/vduFuj/ofBL8nz/wwy2C/8ZJsAUmYDv4kHve6s867a5Bu374NS/SbXanAdPHcmR2t2E0lo5ux3+Ll/vwc/oG//HWvngbt/hVftDzvAF7DupUXvpG/+pu31HbESs2Atuz7+oHXyRE6ryu0nXIDwFTwTKDsiMbGPnHXwZZAgI6+iTvCb+zpDF2SfWMS37J0yeJMuT8uNR8zFi1S9QXKE8AS38ci3SyQyeq/hUI/XiE54X7SH9pL9+aU31mPsfSIz3oyxd90EaBm7IS51xeZGleSLQD1Y9Qf9DlwX1V+a5tjqGyT5uuTnktErkwXSvzO9P9O/j1nfwszG+3/6rYE/R/tsUT8kL+RryMoH8DCPh8lfDh2b6+i5/E7rqSp/i8Cc1dVec62X15Gg/v0Di47U0671uM+kv8c9Vu36H+Vm/0nwb9hziy/S+4kzO4nc9vJ1fyFI6DsY/k6GU+J8u0TS6xURnbsx0/C0a1iKRuBIsv5GJM8oVZizkBBh32ausLugKs6hzGpcVd5byQqMZ+6a6tQ8cEOkb6RVbjBh27xquxa7zKa6zyl1IwB5pzr0s7IT3jY9evF/7QMzZ2+7rlL3un8gkrfTudPXmdBzpXVK7OE5VpB0idG1Xglx14Oc8Ntdc5lvUzGJ98d/kZsh212VNX3eqH1O2VuTv3nT2Q/59fP+zwPe++hNvjO+uHt/2fLPBfsesn8Jc7/ZrRrjvnpsJvrfuuX/DIhdvjp3/vfgya+XXBo/6yrrLtdvurd40qfvFPD/083OZ31nb9n7/d5PbRHOtwSJsHmW/0Qx6HSwV9lS9l1n7V/1XP+LuFRouyFmPKngfaskhDLuhI5dVOFwcJ/dMecoHvoA67yt+l+HHh349NdYnG6GMmAFHWBYHGKlv5d7lKZ8/4uNX/j//4j4fx6qW+KuirfeVrNB6vG9k52M2e7yvPeeLnCG19XnOOkfjLeXZkj74L+vSHzSg/4xoflc2Kj9mt/lHdSOr5MeUqqI+CPqQ/fwyw65b/kwV9uCDw3wf8fiddcc1b/R70kf4cnb+qYK6BuXl485219Qdn/XbMxiNyLC5v8Ub/Q9A/jv8BBX4Gef5Gv8qngR+O9jB7ox9SV/3NvurFrNwxs6vqy1v9ys90vri41OLIYlntlki0ZcElAfXoPKkdiUVaeoc+WbyBxV8BgQCh4As+bq/HntTlZ3XSyS/jQzJeJPXA2DLJLtHxONjupZqrRDZIAr0H/YT26dNJ/27rdcp7fed31B/4XPlcav6Vr1DQT+hT5+OM7hiybXX8YuYj7b1c2XT+QHZaCLQopHQ6m0r+bgvmQBl4CUr5GfLTcfzTs7vCHStvuT8+2/8Vrni+Yo3b8p9vea5XVb6vq/j5lghSLiud5CndfDGXkPX+Wf1ki+VKqiO93YLfZ18R/Kk4X4squv5AdQl6jcXl19uUXZo4R3598qVDjN///9+90HAXxAnsHK9Q+fffbHKL+Q91OojjAVbjlnTQdV/Uk7ajMn4S6bIduH1Vfx/4q8VipKsWGrfvqHyyAOfiTB16XUQANtUingsjwRYdtgRlEmVJQNKHyl1edp73OpCO5BcGBHclqAI6OvkfsWKjiyvh43PcTjbomGsCvnb6mvu941NevkX68focK9I/N32WlPX5Kml+dZElHzomykra3YPyJNkp4Ov4SZov8hWMQXR59QnKr7QDbwtV+7Tp/MmuW6TQpXQ6m7TVs3t/0Wq22098t+/2Dn7/+O0WFN+nZ/v3u32xHcSJhNR53TnMg5Nz6s/T9VnpvQs+I3RcpBHwkmq3P+sPZNN9vug1FslrvqaX3zn46+bj99+4E+KF1l3yfqu/GZjx0clxPtziFzn+lBXeHmZlqHxVOrWd9X0f+DtyERK50CRaNEELsBZVUD1l7bqQJLVTvdpqAUaX/WvR92DrAcLzCs4eWFzn+pEu6wjiSJKjgI+eNiR0jBGdJEm+CHR5HDOwFT4/aiud24E+iyrAqQ0+yLt0vJx17gNUBs/DyE9SXUiBXxyuXFjpeNWfyn7OVcyOR/numC5p17WHmW+vBxaBbpHKuj022vX/dfsY0O2l6svxnb/snn/nz5XOeNfP344f0vm7YctUb9vDaL6Ezyt5nkA4XAB8+vHxVvfbk13/OaP+9JlXNtX5oHFVdXtgZ93tro9ovdDAjh2Odv2M6aHufIAadyer8VDnzMr4cbIM0mVbcHvVn93qT5mLhi8eXZsOLajVgsUCTXIf2JFy8WZhJ6ne8WBAgPMECqJKWR7pO1uS6rI/BXLqBWUPThU6Dj8+2lF22VHVVToCm/rg8/HPaNZHIj/g+fThZeWzLfMGSObK5xGp5J8ryA/HlcdT7fa9Xm2qgC87R76EjgU873arbaBqN2qvupVxaAFgUSCf0rnEhp2X24x2+7RRXnS7feWpJ3DxnfPakb7E3f677SLlGPAjyt6/NX9JOkXzJ7Lsu32heff5pMznJhh3tkuyL6jayI66fL4vLn2b/5Ntg687S6fP9kmKB+S129egJwd3h3b9q9/W5zJB35F1Kqefyu+or6ru7FZ/t8BU+lkb0IKpxZQydlpYtdD6rp969GqLlF5+QBcA8qmg4EF2dCHwGAnUZ16wCHQ+rhHdwl2R9SqnXvMHGnNnS5kxpHTUxvXKu78uD+lzRjd/fkFVzb/OGQebtBN+Hjp7jhUqe6jadLaiaj/zmVQLk3QpnT027PxlM8JtKn8V2HBH4VfbWs6fBnIB8KvDRcB2bm+B5Xk47uxPdv0tepZ/STol56uaP81rSgI9F1DkudXP7X92/RX6jBzvq6qXzu0gx1G1Xeb8v+cG64OvEbleMCA6PQ5sZddfjXkk/c/30AF6IZ3wOsgyZJssQ9WXUN3wrX4Wk2rh6PSgOrfxQKxA4zs35X13B6pTnsRijhTyB95PwljwTfsMDirfKt+Ng3FrTjQegjB5Xfgon/UKPuTlx+fB6epmbcB9d3LGqh24LXng8+dzZR6Zg2q3T97PJaC95kwXg0o+p0jZQOahCvarMD76yHyyagdV/V7fJ7obvNW/YsOfjHW796oNYK/3A6r8V388BnueT+MP3c8J+ptevz6X3H8n/aPzttjdn1P/qdkKf9v8n/5ZnfA5BMp8RW81z0jo6sa3zB9s91K9zQ+X7PbZ6RP03909jTidU9Zigr0ksOOHu07v4UDqN/yFjzXHX8lr/nyvanOJHyfb3wf+anEQXd2oTYUHRC3svnjjhzJBFGQD1Ekqj53yasfC7m1G45rVw6U2s3bU7Q1S5EG+kQIbzeU1yG8nO0b1XrfiR4HeLwQp6xzxcwX0eXvwxs/KxRRSefRCvhL6xX6UH3Gt3aj9qm/4O+fL3cfAgqCFoZLX2nCrtAv8wu3dpsojPfCjoy0XAPw8LrfXXzoPz+qZhO2glyVBcjtQQ3PXMfrTuZRQBX3ZdGR9Z89YIPu9KPDfBdc68DsK/vlin/IPvLXgf8mf7UmOLpxkJ7K8yoqfznd7q59FRGSdGLWBLK/C4gz41eIt0CkpMAq1U79eBzmeWT24TVWPLv2AdFWbVbiQmfUvqqCvtjk+D3CJ+uikU43Ndcp7W8+7rcY0C/pKGfTlCz8EbQVu9HkhRfL6laBPn4C9qPKygyrvbaCzr/zBqP1sDKDyaJFI6Vxio+fGHsRVD+6jCvSeZ9efu33aov/dn9+8+bJ+F+1FoOM9RcpVeY7mrmJP0Ed2AYu6CtpB1mdZduD9IS/e7W+cB/1jDHiQ4EFfA/M8nA545Xm+43XdHFIH2TbLQvbJHj+d7/at/lxgRC4kTrbJsi/IWqCR2JFHktD5Iq2FmwTKex1ttHhLl0hXHQO6bJN2Xq+6S9oAeQI7ASyDmoIdc0C9bFbJ45SU3i8SNGeXkH5BOvA8jOaKMWV9he4GJbrog7xgEqmvbKqgD6Oxe77z37WvbCp/s/5WxgBe9sUqF4isu9Ym3yB31FaM/vY/9f6XA7QDbuvz5SvCfT8nPvZr/gqhe7Mf8lgJQqmjrDlPmVRtnfw8oPLT2VX6Jer/phtaH5Ae/IUPjrwGcNTr2b7Gtio7qBcjO3BbcPuZn2ybZXBd+1Y/VLpcaEbtVnH7DEQs6NRr50//GoMvYrlgq12CzttBpQPpKj9dnfsZ1a2gILfSzuetGi9Uer8IWEFjWT3Oyq6qRz7mbh+U93rymrs8h4D+hOflEzwPXZuuPYzqoOpv1Z/yrtPiwWJAPqVzK5t80192gl07u3qCufIw2+2r3tuRFzkO7/MxSP+P3R+oDz9W3VYHzXU1F6qrdqppn2WnGoN0jvr88rPtc/r/7pSLsNMf3+L3YK/gr2f7oMFJaoDHMjt90JzslTmH6CuwTTpbmPnJ+srede2tfkhdtdCM2lULDmiB1ULtCy+J9iQFe+pVVpIN+IKOrfxJ72SZsaUOqmOFPJZL6wBd7vqlR0dSvdvgV1JQ72gOwO0gy0J6SfehvI/RcZ9ep/ysHtJnoguhZGW3n6zYgNspPxt/1QZG7d0OpK9sRdcGqn5dp8XK8QXMpXOtje/8q7Yj0tZ3+xXVN/2B+8n215Yhx5lltbnlrr+aR4LQ7FZ/Rx7XrAyVv07HX2D8/P/dxvjftkD+3+8qVji/NjdYB7RGaE2g7M8SNHBJDZDy+WBzvmayg3rHbbNuT7nqc9Yeylv9ucCIXGiSbmGatYO08aCjhR0bEv0Q1B30LPq6qBC0VbsEP6t6HVunB69zPYzqBONXXQaw7Fd0er8QyLF7/z7P0ku6j7ywEOmzG7P3CaqTZHcv+VJ2+6IbO3R58HaeX2kjfWU789vVJywI3aKVdY9pA9q1d/nRbr/Lqx0XG7oAoH8nx3JNOX135fRxa+jHd/sCPX1XcrZTHZVpn6SO8uG777eLsb27fPCdPsxf6PNNQj7f94N5GCjfypfkPI1k9ed7gvqOrNtbFupzZC+bs1v9kAtItZBUddXCI9JeC60WbNr6Iiyd9AQDJcrotZiTwMvYyJ/auS14HjS2Sr/HFjo9eB16gjwBjbzskOhIqiflrj/Jfp3KHp97yfE7Xs66bKdjUBAfwRwktOdzHaHP3hnNkfCxy747ti7v/WSfK22E10Pld6Vft9FikIuXpHMrG+Hf54+duPTZfpcHb8cdAC4EKrwN7C1DjnFWhlvu+jUm+ql2+450VZ2Tx5llqNq7ju9Y4FsADzt8foDnLw+7/eVdf3FdTtA//WbB3O2f/r/f/geY1ABPZc7LHumgq0i7LDsz25U+O5uzW/3VAlItJCmrdjNfji4Esl7BGz15BQAWc/znzh8U5GF0AZB9ebkau6Cu0sFefUVVl3cAOryt7L1dpRMje1C+OqaVPO0oS8eu3nf0e3b7+MAW+Hz9QpHku33p/Bwjr/NCekdt6VdIB7O8t6vye9rM6sH9QWXrNiwIuVBIl9K5xiZtVfbn8uTZtcPKbj/vDHi+aofkDoDfBQAfF+wtcywdVd3IfhW+qfAL+86CHBNojlMKLhD27FSznPZeJuB/8dvRlxitoTf4D2yfG7v9407/d0fdPQr0ugBAdrt9DfQo82d290jmL++YCGwc7B0v77GFLDvy1dmc3erPBUTkQpNU7aoFy9GCq+CsxdsXZNchWdBJBEIt7kjZydbbItUH6AIgLwJIwvMri2ylgxU9Ou3qPdh5vgqI+JCsoM4lVDq1H9mD52HFzvMarwI+qB5dR+72+Tw96MPowsj1nY2TY3a6Y/M8dH2O/FV2e+pntkkuYE7W3dpm9K1+XAA46TN39R1VO6E8dwGqCwGR/XRl7yttchzgumt/Z2D0lj/9MJ5OJj4uJ21VTvvPPmM8Pzyk47cYbhOrbzPUTn/vrt+uy/n5YC7mtNM//T2B3PEDz/cZpA5AUgN/OIBujmbSyTI2FWkHq7azMlS+3K681a98tZBk3awd+MKTdQmLOngbBXFwPYs9AQCfCgAOtrTDTu11AZAXAe7fE3psU69U1aNDOjruTu9kEMMmgx+gxy59ZB9Q6UQ1Brfv8jCzQ5II9Ar49MdFDhKdgn51caNUPZLQvDPf/vnpghB/6t/r9ZmB9A42Dv0Lr6vybruSH/UFe+r3jEELA4uBFjCXzmPZgHbilLtdO/bs2nVnwOu7fLfbR0fQ/5yfzb+zoSw7XQSQ+HnXf//fR7lSlg6/FRzHrTj8LgHx/uM/nu38YeXv93OXmuPzMm0clY+7+mOgn+7uf7zvsWI+1//oX45z+8n/+OHhGwl7WCsV/Oc7fv3NvvA5msnZuxECWyftst7LaTsqpx+Qzu3ObvWD8tVCknWr7ZTPOl+0WYxJlLHT4qw2sqWsnT8oAOTOX0mBQHXyo/7U3i8ClIfUzepBfas/HYvDHFCvPMHdAyJ4oMQ3koRedepHoIORLiVU9lDlZdvVKY/UsZCXnrGj15yRZOdUFzyg+aQd/fnYRV5AVTaJxgfKq11VB57v+qvyl/Q1q4dZv8BiUC0+6FI6t7RZ+RU/2unv89PHiLT13b6oxoRdZTsj2/idBBJ3E7y/PN5rd/1An4cAvF0E0JfmvZNJ6ioboYD/8NsEsEXlsrxNgPQf73jWH9fk3FLXl0H5d+uz63/46WB+y4DHAPwEIpIrIjpL+as7STqlmqvVORTUO52t7LJ+5FtkH1C1q3Rnt/orfMGoyIVHdIsOzHwSLEFBuWuvwEAAYBwKCNTLh5AOSTvlvS/1p3ylm9WDBzSVsVGiT9kK2QL5nFcdK+2rhR+9U+mlSwmVffoU3g4b2SEJ4Low0cUJFyvolUDHKx12JLVRoq2j+dbnp74pa96QPp+AfoZ8geehq0s776fLw96+vP2sfiU/WsSy7jFskPrbfu3KPa8duu/aO9tZO+kI0Lnbp0y9LjCQe4O/2qRvUt5N0J0Cf7TQv51+Tu72yd//8uDht/7/15u/bn0c3qDvZLxZz+fiePl0V7+ws5/x8Y/f/Nx28hW+04fjc/3+jsHDePn1Qi4CJP9tS1wEdJJ0PH/yHJ3JS97iX7FLm66cbWftQLqzW/2dhK4uF56qDXg+YdHOACwdiT4UKF3X7fy1y1dSnVJ1F0Cy0u2RGr8nUDBSQEKqHRDwwHf04MGT4K8gig7pgbJiNO/AGBy3V142aUsZG40DCeiUgDo/fhK2bg86FvzqQsfxufSxMIe0pY23ld8V3PaavI+ryq/4gCy7LxjVz/JaNFgIyKd0Htum2vlXgTfru3ziuu7ugdo7l1wAgPtWfwJ/7pddOn/mxnPqW+z693B/h2BL7JofAvtp+XQXD76z73b5WbZdv3RcvMSun19WPHvWvzUVvtPPXf+3X34Vb/kDHyzpf2yJ3X6Vjp9/dW6OpIOuYtUOZJs2s7JYsZPu7FZ/J2FUB6M2oLwWrFy4Eg+aCo5Vn/jRQq+AoKSLApBOuB1Jgdvze6X6pywd6Fg8AfYgO4e6bo7UThD0SEL+XKZOqA/Xpw2gw1Z19JcXHiRdmHgSrvM2Gj95/KveYc6o07x6ou6bb765v6DT54B+NMeO11+a9zF3+VUfM597+vQ8aAFzfFFz6TyWje/8u2f0Xg9VvmqH1A5c+mq33wX51QsA+ZJv2mV/QraMjzwvxR05/719Z7bbJ//mT/98sG3ZxnTf5rnhub/uAGzygOTGl7988+br7TOtvpcg+enJS/7+gW0n2ckOP9Mp3fnr8tK3+EXaQWWbdrMyrNgs3erPRcPp6kaLjhYsX/SEAqajQKkFnzzIlrJ2+cBCr4WfpDol6ZUgdZcmHydJ/WmsystWx8J40esChuDpAVV5BVXsMoCqDQl9Ss8DY3CJjyqPpJw+QX2rXnUciz4HEqhf2QO2JJUBO7UB+vd5ouxjE66HtPE+Otxmbx6q/sHzsOoDKj/epuunywsWBF/QnKx7Chvt/CFtCJrYzajaJfhRYE5ucQEwIn2QJ2D96rfHi4PjjnUc/KeMXqLb+YLdEe3aj/8Hj7gu67tyses/yat+k59vcoMs89Pt9D3Pb+dzF+M4h6cfLnO7/a/ZEsdPUv78pPLztJMOOpF1wm3A7bIOpEt/o/JKG9lMb/VDLjYrddWi4+1E5RMUKBPpciFTGUmQ6O4A0I9fBAB6/Lrd3jJJuI7+3FZ5jQsU1MADHnAcsgPNE3ayVcDFjnolLgSqPHgAl+zyku5DiTrVC8aldkreljrVAzrGTtltvE7zxlxpPpD6HMlrTkiUSbSTLW0pa75V52An9uQZp1jJ7/EBWfb20LXt8loMWAjIp3Se0oadv3bI1W6fPJDfu9vX83cF/NyNKyirvqO6AKh8df41Do0ZiR15OL6odh78V3b7w108QX/F7kXwp/tv57t8rPl3/tsJF2/1X/L3+/5sH9Al2DqVjajqVnwmoz6EbKa3+n2x2FMnKpuVdoLFWQs0C7YWb+x9AXcd0gO7BwTVK8kOvfIkryPN6qXLlP25XuMmUSY5zBNJAVLB0oOqH5t0Sm7nefmtAvkoMW75UBIaA3bo8Q3eHjKgIzU22qteYANcADHH8iM9ZF5zLsh7uUO+ocuL1GV/osp3vke2l7SFLq9FzMkF7rlseObNi2/s9oBgSb3yHdlHZVuN41JWLxQqGAftNB7GIV8/3v5b3WTnLwj4F+30ne2q5H6HLlyX9V15bdfPT/XyfgEXT28nO/1+1//Ag40+8IcTgc8gz8ORdLoythWr7Z3K514/WZ7e6vfFIunqugVJSOd2eyFYAr7kT0EUpEMqEOguABBkQO0zqU2XMtBzLH4RQBJuRxIqMy6NWxcAbquASvL2oACMDwXfUfI2fjGwmhJ8Mi7V/zAuJuhDSe1VR1mBXrbKA3PC8ebnStIck9exkfe58zbyQT2ozsFOVHmNCyrdSh66fmBkC1XbS8YALAa+qDlZ91w2+ewfqvzqbt/L1Ct4X8Olu/2vth27xqnxELTQg+/8d+/2Few94L/43f62y9+O/91P/7QF/Ye/cvhoOx/28vB3/jS+O5nuobytNxf8/f7s7/azDLQTM/uq/Ypub3npVv+eOhgtSJUdZL3bgRZuUHCkjA/5kZQtZQUCpAdlBQBQ4NiTsp36UaJ/78+TbAApncYsKQjqzIcHRgVNJelmycd8aaIvJXx6GTQm6kB6IE+dLlSkc3Ts2GhuxCivsj5/cBv/zJMco/C8fFU6mOUv7cPzkOVLxqCFoFvknOe0Ae38fYecpN6DOe2g6ktB+VrwtQrjUJ8aZ46Bsu/8//jt8e3z58V36MJ1Wd+Vtavf1uQvt/w2H+SPu/yf2XEfd/DM7Wynn7v+t9u1jcrbWX/493zXfwqfS55/KTuoT6Sr2qX9rCz2tuvK/+WHP/zh/zlmbwMLiy84M/baEzTENvaDdB3+cmEEt4G00Tguke5bwYygVcGYaZdBURLw537Iyx+BUH0Lz49Q22upfGgONDYfoz4n4XPDsfn80UbHmxdA5DkG5TVH5BXUPeAzBvToPOjL5lb4sXb5FWb2Wb/Sb+fzH/6+XTxvahYCSUjdc9q4LfzkbmfPLvmb7SPUzhl5CJS222fXnLv7rkzbS2Xu7KHzr92+6jV2t09/v/3Jtsnf6t/94RgUP/34q/3P9uFmu/1tMIfA7X5cl/VvDzt4IKDrWASPdH7yj8fPmc/0s69+uM3Hd8df8tsCNVDmXNDYCd6q6/LZZlsRtvQP9zba7XfnXCXz7/bR7eWSdpf2NWJ4q59Fo6Ory0WmsnNdtSiJqi2LthZuFnMt7Er40yIv30i3kZ0n2lwqCUZK0guCkyfVy558JtdrrPJFENW8uMx8lbjYIMhemwjKysun+mas6o+xkjzQA8chSV0eJ5I5EJRloz6E6oB6kI65TmTj4FPM8pUuxyOUn/kU3hZm9bN+Qfn0BbmwOVn3HDZui6z+3p+gKhuhAOxgryD8mMz8M1a3yXJyeON/S1wIsAv+47c/e/Pu/C/QnhCuvOa7/uMOnnQM+vCn7b/0l3d/vcBFAIkLn5//5/E4ecxBYM4d+6W7fm+z/Q84/CsbnVt7pIOuIu2E9F07UbWftYFsNyvf7/hZGFgkJJ29dSM7p2qz2lbBxtmO5SCzDr37Rt6KahzpX/1ql6+Ap3G5vvIH+HC/tMee9qQVqqDXoXGM5kvHpXxlxzgVxKv69J/HQtnb5wWBgnsGfT/WtHksGJ/G7/kZs3aj+q6u8uP8fZsTX4zId/Kl2Wjnz445d8rVbl93BFT2HbX0oPyqrHzljt1tfXevcfp4q7bScay0ZQ6+IPBvbd58cbfzJ//xH7cguxUa9Mz84atte77AdBvr6a7e2Qbiu/pvt83Pvx8DewV98+U6//budE5cAnmOj1167thvteu/9Ff4Rn+3j03FqA5m9ZA2s/Iq7Vv9LBxiTx2M7CodpJ/OTrCI50LOAk9SnRI6fEjCrWT2RaLOk/olaClwEbRTr7F7WxIgffy6eCBAcwEhfN4SBXPazZLo/KEn0bf61/hcclzygS5T6oXmQZDHn8bm9tiC6wB7Uocf20pedPXet+dh5LNqN/Or+qoOKj+erxYM6VI6L8FGO38FDIfgkVR+EwWhveDLg9gIxuFBzuUM2pH4+tw32w75zXZas/PnDsCbj4nUvzkEWD0jz5RvuQ/ZYvq32xw/7NpP0+G5PP1Lt43j41//7Hjx0vT98a9/2B6r65nPTz8+7vrJE8jhlrt+h/rqHHM5+jEjbDq6OrX3evcJlQ3Myknn96bP+FlYfPFZYbWN7Dr7bqe8Hd9d7khndwmMJceFrFC/aqOyAjgw1jy2fBcAvL0HPUn57CTQrhsrNtmf/Fd513XM6hNdIAFtGbugrICeQV/lDPjSX8rsGGdzVLFqB3vqZ7bAM35g4WAxSDmqeyk2vO3tO+W9u31QXcpRHXK0O3cd8pLdPmQ7dv08D//dn48Su8++enj7nd08fwLHTjfHzLsCqzAmPXf/eOuTN+0dfy4P/mw++0ViT0D2eqhskXq+nzv2LBPQsRvlvc3suT6krtvpJ2ojZuVLuGUfw1v9qRvVOTO7UZuZ3YxZYCe43oqqL/z7cbgEvwAAH4+CsiO77gJA0AeJAKmgR72PwfG2juyqxw+VH6er0wWHB/MZ9OXBGx/4Vx/IDPqAztvNAr4fU5d3VmxGzNrM/F/Sf9Xmfb7VX9lwEeC3/iGDqQIpdEEnZWe7N/CjV6DXOJEaj2wqf3mhoPYcNwH9GHi5APjd1v4Y9Ah44GNelX4c5D3Ig74aV22Az4Hg2vXr9VlXSb9YyBf9vKzjHeXVBvK86aRs88t6HNlfQ/qofF7Sz8zvzXb8q4uQc8nCtYfZRcA1bPN2l3ug6w9bxs9xgAdSHZsCrVCwBLWvgr+gXoHV58r9rKL+wC8AAF+VT3S5yxY6Rh/XCuoTaFsFdPlVeSXoazwrXGrb5ZMV/zObi/p9D97q32ujOwAEjwykVWDdI0H5UZBO/9ju3e27vwz23k62v/in444b3lrg1xhA+Zn0Y+uOqZKzXb3v4qv2Kd0fn++lu37/W/08d2ayusVP3Yi0mZUv5Vo/5Vv9LBgdXV0uMJVd6tpFaWCnupQVLPyebgkBJlP2p0SdjgEpPXnVEbQ9oReU3UZtlSgLykDQVOBUfjVpTCT1SR59jsXrQe08eX3VX5eAdj5/mjshPficuU2iNn7udPlLbKHKV+1m/sF9wai+y0O20+JRLSJZ9z7Y8GU/BFmCDO+eOQSTa/CgtBfGqXb4cDlDdtne0dvwQLAjz/PtS8fL3KofzztcIID64S18PZuv+v102z/4uGa4P8ag48uyjrfLV+eJdDOZVDrAXqTNrCzcB2RZSO9+VtuC6s6+wAdyMVqtG9lBpav8jOxUl3IFBY1rUweBJxOoDWWOQ2N2f+g8AQETtMtGT3v8ZNCVVNCUH2w7Wel8J1/5YbzkGYeOxevVvyf5IslW9quS5HMF1GkOyQvZJTqHhPxAlxczW/fd5Ud97PG5p8+qHWjhYCEgn9J5H20on1wI2C75Gka789wZa7fPbl27fO3aR7tq3+1LatePv+wng+ylaLePP8+D+gKNj125ONTHZzDC/XW4v/z2vtm3+bHTh9l50p1Lo9/az3L6hFmbmQ8vu23V12pbUN3ZW/3VQrFSByO7bgFKPzO7CrXxto+Jgo2nDgJSBqg8ZvejRB1JwR0InGrvyX1C6jtZ6dSf9+lJFwbU0wa8Hiq/kp46G5egOQH0Xgeel10F7cDPk1l+xRbkG7o8jHys+HSblT6rdsCCkAuGdCmd98UmpV8EkJTfK/NOwgz6VvBUoEMyrmngM3vAD/4q/O/ec9d/S3QskLv43PUns7sCiftnvnR8WR7t9GfS8Ton7bIsvN2szYoPsWq7p+3ZrX5fNJKubrRgidRlGzGyUz6l2khm/VOg4OTJ8SAGCm45dknZuT6fq4OCrQIvdvLtY1lJQDvvU74kdUGgsWSfyGyTsup7lIB2kl6HTyHbJM8D+YJZflbvvlfyIx8zn+DtobOdtQMWChYGSSfr3mebW7SRBC4ADs+gN8kFAbvf2W5fu3U9q8dOu+rZbl+yu2tBG9oS9Co0phF+58Hzfkw+vvu6bV7Ewe5ujqDqd89dgWRl1z/a6c+kGP3NvpNl99Gx18fIPm33tC1v9SufEirdaMGqdJBtZnagfMqkqnefT4WCkyBIkaQnMcYMjIBMG9+NK0kPBGO1p51wnyOp/rzPSmb/6Lw+fWUSsl2RJPwL8l52v0Kfufx051iXF6N6+YZZvvPjtnBp2z3ttEiwGJBP6XxINrdoI6k2fjfB7wy4DVAmGK6ggIk89BEB1IMx8Ga/dr2Qu/6Vfqt+ZtDGd/HP/awfXfVZ7ZGOl6l3sixu6WPV3llpe3arH5RPCambLUKVrmozs/O8I31KoXL6vFbuIYOSBy0PiLKjjn40ZukpV0l1BGKk2+NrRZLUBnxMnkD2njq7Tq6OS9J9o3PUX0I7x8uzvH/Os/qVPHR9QtqutF3pt+uTxSEXBulSOh+Sza3adHouCNgd5+6/21VLl7v9vDPguJ9L8ef51V0I9VmNGc52+Vae4f47Tvxv8+uofM1OX5Ln+rnbRz+D9k62uYUPSJuuvNL27FZ/Ry5EYraAQeqyjRjZeb5a2FKKrnyt1BhSdihoOQSwTB7cvE/pq0S92wN5las2mdJHJ6u2JOH2JPlMCZWfLgFtScLrOvJz8XKXB42xs1E9zPIrfabtrC3M+hWdDxYDFglJJ+s+dJtbtEkJBK1//9/HsgLlDAVCJL4A6cHWkY0/54fc9V/DaOwv4Vk/cvRZzGT+vT56Z1SmfcUtfIDs0mZWhq7t2a3+TuZCJAmerxasSlf5GdmB8pWdI33n5xZoDCmh6l/MgpUCmwc7/Iz6k0/3Tb3KCphdAm+LjvYp1Wcn014+u4TdnuTQvsPnXWOTTmWo8vmZdfbgtl0e9vSZfczsV/KVDy0ELAzkUzrfN5tbtJFUGy4ArtntV8HR61YCqOwcH0s1rhxfVZc+D7q7Y4fKZs9dgcR3+TxWgZXPYiQT9M6sDOnnFj5gxa4rZ1vpz271d1JUeuWrxWa2AK3agefBy1X7rq1sr5WJ9FX/SQZBD2QKdNKTx1clIfuTBNmMwEbJx5Mp+04Jbg/ou3QJ7jvJ+ffPSTrhdZVdV9/5rPIrPmA0NhjZXzoGFoBqUUCX0vm+2dyqDZJgxy3/0V8GKEAiaQ/ILsgms10/PhL5V/4SZrv+7PcWz/qRml8h3R45+i7+JOu8jL+KURvofKQdSJd9zcpC+qVv7mPByMUJOv2I1TZu1+VhTznrbsHM594+89v/ts/nLnfO6JsJCY4eXLtgufrthqNxOHsDejeux+CWn393Xu3pY9YudZ39zE/Fh/Bd/c9pk/KSNi4JbHpzX1J/AbCyAwfV40/fbAcESS4A8lvzRrt9kO3oub/7y2/vq77Nb2Rf+XSp3T1o7jyfclTn8tZfy3tJm2uY9VfVt9/VXy0gXZ2XK5u0h1W7jj22j0H2PzsO6VbHvRKQZ8FYQXg1uK5eBOzlMYN7Na9dXsxsZ/V72Nv+kj4qZv1+aN/V/5w2Ka9pwwWA/vSPgIuEDIzdrXdBkCSoCoI/ZL/cNq8CvwfdUZ36VB6//p39Wc621DNWn4PMj3Srsmp7yVfyirRdaTtr0/nYo+9sheqnO/5bLUSw6qtbtEbtK7uZn0vlKnvtk1sE4lsE3b3jeMpd/CrXfhYV7rPLV1xqC13bmR84sf8Av6v/Jdik3NNGEIz37Pa9Tmg3Dfq++lH/x0cERz/HNsf86m5fOl1w+K5f+HGOxnKJXPU52t0naiOyPGOvvdO13eNzZHvxj/SMFiSxshjBql1yabtr8X67/AjZpdzDajB+iUH4Wrp58/JsTme2Xf3Mr7On3cx2td/VPl9v9T++Tco9bUC7cQ+uyNluXygIs9tf6a/Ld+NQn6mjLe8zZB9PJcF1s2AvO5HlPay0vWV/Ym+/S7f6K51I3cxm1ddKXlQ6MWv7GFR9rvT9FOPL8TxFnzO6MXVyL95u5GOP/87nqo8Vu5HNnj4r29db/U9rk/KSNpJdIAbPa7e96nePreRKmxWbx5BVwFfdXrLdrOzs7XPF98znrH76Vj+kjsVDuB3MbFZ9zfJVO+lmPtNur4QuD1Wf2XfFis215Hgk4TH7le+U0I2pk07lz/Pg7dJHNY7OV2ULq/739AUjX6t9QmU7WkxSOq82l9ncoo2k/jqAHb1LAv2f/nKUejdgxZ9kxUqbFZtk1uZa6UEfnaBOuB6yDNJ5O5iVoWsruv5Hvld9Vm2c4Rf45AIiZgsNrNjAyK7LQ7YD6SS79mm3V0KXH40ZKtu0c5tbUY1FqG5lbKtke/lOudf/zC9Uvru8txOVL0jbvf6V31Nf2Xb1ys/sBAsCC4Skk3WvNneVd1xjc4s2TyWda2xu0WZVKuhTBnQVqa/sKp38iq48a7vSf/re6xNcJ9v2C3wgF5BuIVmx2+sLqnzVznVO5+saunEr3/U5spWsbGZylezD2/s4RTe2VZntO7x+5hNGft0O3KbKu33V1yx/iX9wW/A6mPmq6iH9juq0GLAQkE/pvNo8ns0t2jyVdK6xuUWbTvpOn3KCXZK6ygakT7+zMnRtO1bsZzbVcci2vdVfLTTVQrJqJ0Y27qvLV+2y/czPpRKq/sHz4G1gZCsqm5mE2bh9LNne6yp70fXfSSf9dv3MfKZ9+qnsujzIHrIvWMlD18dqG9WtjhU622zX1bEo5IIhXUrn1ebxbG7R5qmkc43NLdpI5k7fkQ47UemgsoG0g6ovp+sDsu3evmY2We917a3+XGhELixu9923390nJ9uIka8uD50/2c38XCq931l+tU1K8PwI2c3GLVnhdZX96licPKb0m3K1Dx8XpB/h5Srv/VV9d/VdvusPZm1mfvb2me06O2AhYHGQdLJuZvPNX//25q9/+9tBKl+1n/l5TpuXNOZbtHkq6Vxjc20bkW1hVZd0NurP630MompftYU9fSUrNl43vNVf6XJhAeV/+PHx70aRozaS6LuLhJHeF7D0KShXFyEzRvbe70oeZnYpwfN5fH6cbjdj5MfzQjr10bVPCdUxjVjtAyodjMpZ5+PKvqGqh1m7Kj9r4/XgdXBJnzDzq0WABYN8SmfF5qMf/OCQlH+rV8s3uvaVn+e0qXSSeVHgdG2ca2y6NisXWE8tnWts9rapfkMffUWlT92snGMC1436qNqO+luxX7ER6Hf9HT+LRy4oCYFTFwDCg2nWVbj9j97+aKlPqHxT5z50DJ100P3lm7/clY54H9mv++iOeTRWb1+Nx6lsO7nKXvuK9NGNKeWtGPnzus6us1lpO2LUpqq7tj8Y+X2ML/ABghGBP+sJUKA6wFZkG9V1elCd+sw+9vjwMUK26WT2AaM22QdlLpJUp7x8y0b27if7TDtwX+A+RvpbS7iFTUpY+Qa+SncrrvG9t+2K/crxl7f6WRwqqkWkotIT6AjAHhCBctorKCKzz86eVNWB+1C+k+5DOh+P13u/4D5UB7KXXvOQY1V78HxFZdvJak6g69/1XdsO+RDdmFLOqMYhndelv65O+fRb2UCXB/fR5UdtVNfZV/Ur+ZlfLQajhWKPTVevIEVQI++2qaeNAl6nJ4H8g/chKh/eL8nrpK/aUHZyPLJ31NZ9yD9SfcrG8/LlbdyP6mQH8ut62szmszreW0vnGpuU1U4ffVLpAD/O3jKk75U20lXjGrVfsV85/rNb/ZALxp6FBXxxcfbaQ9qC2xNAlaDyVfkYMRoPUJ/9Vn1Il+PlLgIXAK739lU+JXh+RNeP9OnH7au2Mwmen7HirxqrdD5GqGyE10Hld2/e+6jyVbuqztuC18GsH1jxC1oIWDTIp3RWbcTIh/LXoPYaCyiQSkdQI5ghK3wMatchW/lGyl51Hpgrf+gUlKsxuT/5AD8uQV/gdfKLdHIc6U/tcv4eUzrX2CBnpE2Ws6895c73zAdUuj3tobN3ujGevdVfLRh7F5ZcsIT0q/aQt9oh7avdteP9qb6TUPmo8H69D3QK8EI+1Sb78PZVPiUon8eQEpTPNlDpRm1nEpRX207CzF9l6zqY2SjftZce9uSrPsDznQ/IctVupQ/Pw8gvsADkgiFdSmfFJutdl/kq8AjlpdfO1AOn24P7wCfJUb8KklV9+qz6ENRVbUTWcQz0Sd/Sr/iTrqsDP163r8g2bv+U0tljwxv8Kz+nm+2zLLLtrAwrvlf8SLe3/Yp9N8azW/25YIiVhUW73ypYg7dxf5VewXMWJAG7Ud/UyYfadhLSf4f3632AArzAp46JNLugyWN2uvnoJHgesgydfWXbsXdso+MUVf+pq/y5zYr93jx0fWR/Ix9ersa10kfVbuaXRYKFQNLJulUbR3oP2B5koAo8lLGvArPswftzn0I+lKfe+9XOGeRLY6jIPvy45F823Xj8ggMbpHSyqcaQvh31Q1v5waegD/Q+TpLGrzrh/TyldEY2/rf6QB24D+nErJz9z8rZPqnGBFmGSrenPXT2Isd79l39nnedqOxeOUUXA6ALl0vnafWz6HCbtK98z/IzKbK8wsjnqi6p7G9B53dPf1k/sr+0D6hsnvq7+iF1BByCj3Tg9S4hg1llV0lwHX6q9mknCalzCSv2kLpbS7HHfmQDXd1TSR9D9Uz/lqhfMStDpau41tdKe2dUf3arH5T3xUVUdl7/PqDxprwV2u1rx+9zVuH951hWPos8jsoG0j59wyw/k0Llbmw+xm487nNVB+67sh+NAVbylV8Y9QedD8jynv66PiD9wmjRSems2CTYJOgIvk7lV5LERQJtfKcuunbI1HXtRdqP8HbC27qsdLeWpGRm39UhnZntY8kR2DjXlrO/WRlcl/5Aur2+xJ720NkL6su3+pPRggTVwgJpN0K2XZvUz3yP6jXelM7M/y3x/pXv+q/GmsdR+fB85aOz7cZRUdl2Y/MxVOMRlc+ZTv5cV9V3Y1jJQ+ff87DqA6pxrvRT9dHZChYAFgdJJ+v22IzaiJV2Lmc2zp66yqaqX2mXjGw7f9fKilX7zuYS21vL6pk+UOdcWxb062QZKl3lr9Lt8b+3/cye+rO3+jsJylcLS4UvRp3f9Jm+s15kOcn69JfM+nsMfCw5rm4eoNJV+DHM5qOz7caREjrbDq/PNpLpE/bqwPOO2+/Nd/6rscx8SFe1nfUjvA1UtrLR4sCCQD6lc43NrWTFiu2eultLZ0/dc0nnlrbXynymD9Q5ty7Tr5NlSN3MJ0h3iX/Y0x46+7Nb/Z0Ez4PKWkxSgvKd3/QpuvrKdydB+cqf28362yudzsb7Uj7bV+NKXecfunzlF1btU858q76yg2zjdaBy1b7zCV63OgaY5Su/sMd3ZwtZ3tNfVw+yYUHIxUC6lM41NreWzoqN2NP+VrKiqpv5eSrp3NJ2r+y+f58659Zlkf1mGaRb8VnprukDRu2741r65j4WD19UclG6FvlMKW7d58z/Lfrb46OyXdVdQvq5ld+KzrfrV2z2sNquG8NKfpU97bN+T3+7ff/97q9RNhULRcpR3a1tbi2fo8/vi9wzt3tskdXOfobailuXR4xsV/zu6atib3u3n97qB18wlK/sHNenbUr5TCmyT/B8RWWb/YmV/vYy8+H67B+q9qkbjc/r0i77q/qq8jMJqauODVzvefeV4xr1A8rPjkd0Y1jJQ+ff81X7ma10M/uqrfA6yHotAFoMUjqPbXNr6ay2eZVr0rmlbRf0qXeynP3cuiyyX6hsZbfid9ReVP12fcCovdtPb/XPFhpfULqFKG2rtol8zXzCqm325/YzH1k/k6LyAdK7rvJR2UmXdZUN7O0LqvxMQqWDqr8qr3bVuGb9eB66utkYYCXf+Vd+T7uuHip7SLvKRzcGFoRcOKRL6Ty2za2ls9rmVa5J51pbx8vZNsti5AOuLVfH4KhcjW/mG7r2lb9RHyvtYdeP9HSwoPgi5OWsS1SfsmPF98hm5j/Zay9uOYa9jPqecWnbynZv3yvM+sn6Ud01dH5X+5jZZf2e/ma+4SXd6l+xubV8jj6/L3LP3K7+Xb7aiCw/FXv6vXaMK8c86mPUfulWf5V3XS4yXvb8qG1Kp+ursoWRjcruMxkd2yorYxDVWKTzutRV7WDUd9XGdVXbrt+q3UwHXu7yoLLrR/1A1ld1wn3szXd+V/uQ3Wr9rL+qraj60AKgxSCl8xJsbi2d1Tavck06e2wBvaNy2lZtoWsvri13/Tpqs+f4nK595W/Ux6j99FY/VHnJalGBKj9q60if7SqfkPYwq0+fozpIu5mELg9ervqTThJSl+26/lb7mrXp5Kp/4eUqr7Yqpx4q3ajPys5t9uah67sbh/KX1sNKPzDrg8UhFwbpUjovwebW0llt8yrXpJN1/lwfHWSbLCdqJ2btry072Xd3DLDn+EbtRZZhpX9xH/grukXGqRYV6PKO66uFKtt1Piv7Wb3IutmCuSqhyst/lqHSQZYTtav6g9W+uvYzKtvUqR/vr8t3fc/66fqEVbs9+c6n8l37Uf8wqu/6hMquGwOwGLBISDpZ91Jtbi2d1Tavck066Jysh7TJMlTtYNb22jJk36NjuPT4uvaVvz39t7f6oVpkKrs9+ZSiWqhgVM46WK2v6mC0mK4yGkP6zzJ0Njn2amx7+obUVe1nEkY6UD/eX5eH9Ff5rXSgvHyu2sHePHT+V9uobuanq1e+suvGoIWAhYF8Sud9sbm1dFbbvMo1OXq2jw1g53hZNiLLo7ZwTXnWN3THAF1dZTtqL/b0L317q79bZNIO9uRTum/wNpB2Xl/5WK3POrep7NOukzAbg+eh8lHpcuyV79W+Kx1U7WcSRjr3D13f1ThGfisdeB5W7VbGVeUv8Sm7Sger9eB5yLL7ECwA1aKALqXzvtjcWjqrbV5lLfNP99A72MxIm65N+r62DCt9Vzr5GtWJqt+u/Wr/IH17q3+0sIhuUevyFfJdtXHdaDEb+YCqXqjO/Vf2adfJ2RggbdMHVLqO9Aezvitd135EZZc67wuqvqEahzPrq8vDit1sXNDlofJb2Xd9gtfBSh+Q7ao+0oaFhIVA0sm699nm1tJZbfMqj3Llub4jG7G3nL6vLad/p6uTPn1BV1fZjtqLagyVbnirv8q7rlrUoMpne/cDVRvXQde3qHw4rsv+YTSmVUZjWPE/GlcnxZ6+YbX9qF/ZzXRV2y5f9Q2jvqDKy3bVDi7Nd32A26/UdX11fWS7yo/baxFhUSCf0vmQbG4tndU232fpoEtmNnvLIv1eWnb/adPVVWOq/Imub6drX/mrxtXe6ocqL9ktTJ53sv3Mj3DdqE3np6qHyteK/5mELr/ifzSuTlb+oPIx01X5lX5HOsi20OUh+5711eU7v9DZXZOHqo+Rjepm46n8QtcOun5ZAHKRkC6l8yHZ3Fo6q22+T/KS5/pC9WJvOf1eW4ZKJ7q60XF2dat9z+YA1K681d8tKk61MEEuUl17MWoLIx0oX+kg63M8lX7Ufiahyu8ZP1TtOip/UPkY6aDLV1T1qavG77oun35mfXV5WDlWWBnXSn6lD+m7duB10Pmdtev6YGFgIZB0su5Dt7m1dFbbfOjSQedkPbhN1u8ti+x3bxmu8TE6zlGdyDJ07bPsbc9u9UO1qKje7bo8qF3XfqWt631MkG1g5FNUvmHF/4xR/3vHL7yd6lNCl4fsG0bjqfKdhJFO/Xid913lKz+g/KwePL/qdzYumOX39AFZ9jarPmHUrvKjRYHFgHxK5/tmc2vprLb5kCQ7/Xyhj7oO2kBlozqxt5w+95bhFj5g5ThXfI3aO253dqt/tphIQpX3Nk62X2nrNlCNp9JB1ne+XT/yP5Mw6h8q25HO60D1KaHKV31XOpj56iSMdELlrv9LxgKz/B6/YmWMXf7aPmS31+esHXiZhSEXDOlSOt83m1tLZ7XN+y4ddE6WIduA7LJub1nMxrEyzmt97DlOmPmDqn1ld3arv1tYnG7RglyAst6ZtQXPV/WrbSo7kB5G/mdy1j9UtiNdVZd0/ULVd6XrfIz6hap+1r7qHzwPMz9dfdqu+vX8yhi7PFzaR1cPKz5h1C5hQWCBkHSy7tXm9tJZbfO+ydlO38u0SaTLdkm2nZVH44CVcV7jIxkd52p/MNPJV3mrv8q7brZogfRZX/np2kJl4/WialNR+Rv1v8qo/xX/oz5VJz/dXKQdZN8wGk+XH/Vd6SDr3W6Wn42jq88+wfOXttuT39OH47bgdnt8Vu2kk9RiwEJAPqXzavP40llt8z5IJ8sJbZJKV/lJu1lZzMa40ldyK5+yG9WJyueon7Nb/VDl9y4wycjPzDfIRqi+a5P1Xgfub9T/qoQuv+IfUud1ID8jfzA7tln7Kj/qe+Yv28JKHtwPjOqrPkH5znbWDvbmYdaHdKt2MLOFqp10kiwKuaBIl9J5tXl86ay2eYky3+JHL6h3ZmWQ7ho/WXZfMCvP/MEen1V76bIddHWVbeq8r/ZneVk0fDHZi9rfyk/mL+XW/mbcesyrdG2e4phHeP8reTGrr1i1S7q+9uav4RI/e9q8bz/L+z7a3Fo+R5+XytWf230paOxiVq64hY+OUdtL+j271S/pC5lLqPKuA7Vf8VPphC9k6UuM2iczf7P2FaP23h9U/md95ji7/jzfzdVoPLN8ShjpIOu9/1ne/czqq/yqHXi+6gv25Gf9uA6y7D5h5g9GfbsOtBBoUUjpvNpcZnNr6ay2eQ5ZBX30FamflcXedrMyY3dm5Yq9PmZjAumq/ru6WRnObvXnglPpq7xkLjBi5KfSVYuXcHsYtU8JI3+z9ilh1B4q25EupZBd1R+s+IaqHmb5lDDSQVUP3Xi6sYHXwaxPsWKn/Mq4VvKzflwHs/5n/ma2aceiUS1E6FI6rzaX2dxaOqttnkpWuB47kfaj8qXtYFYW3gdkGWY2q+WVMVW6rj1kX4nqz97qB19EnG5RcnKBqexWdNXi5TaVf8/ngrfqT3TtU876h8p2pEuZY4OuX1A7x3WV35W8U+ln7VxXjQdy7FWbrp8uD6t2K+NaycOoH5DO6yp/nZ+uHXid43YsAiwekk7WvdrcVd5xjc2tpbPa5rFk9V38CXZJ2lZtq3bJzM+snH1Ufc5s9pZhNi6QbtTe6yofqi/f6s8FR3K0KOVCo/q0g1Vd5xPSP3i+YsVf2swY9T/qT1S6pBpb1a/XK1/pROUDunzVf6WDUX03piq/2g9U+fQDIzu4VX7Wj3RuB24DlR8YtVOddOlTCwCLA/mUzqvN49ncWjqrbW4pHXQi68B1bgtZzvZdeeZnVhaz/mB1TGLkY2Vcla5rD67Lvs9u9e9dmNImFxgx8l/poKqv/Ff1KWHFX9rMJHT5UX8jXWUDs/GrHpSvdF37Wb5qP/M5agMrechy15/nYbXdyjj25Gf95DhnNiv5qp10koKFIBcL6VI6rzaPZ3Nr6ay2uVSy0x+90IeNoA24rqOznZUT+RGz8sj/pWPKMlS62digGwNU9ml3dqs/FwhRLSYVufh4O6japm7UJv1DVZ9yZt/1OZNQ5VfHB6lLuTIfIm1htf1KHrIMI3tInY9pJQ9e7vpTvvPTtYOuzd48jPqB1KnsfjofVb5r5+QYWSBYECSdrHu1uau847Ftbi2d1TarMr+kB72TZdokXZs9tiLLkH5mZbHiK7lkfCD9ytgqXde+6r+81a98tZiM7Cr7lXZQte3qYcXGkb1Y8Tdj1PesP1jta3asnq9s97RfyYPKM/uu3udnlle7Pccx8gNVvmoDe/KzPmY69wmVPXgeunadby0OLALkUzqvNs9rc2vprLbppII+ZYHeybKjdittVm297OOCveX0PbOHS8eXdrDSn3RVe6j6P7vVD8pLdotH2nldMmoHys/6Gi14nq8Wvsp35y/bp4Sqb6+vbEe6ToqqP1jxDbP2MMvLn8oz+0rnY1rJuw+ofELauQ+4pN3e/KyPmQ72+JuNo7IDFotcEKRL6bzaPK/NraWz2saloJx4PWQZ9rRbsU2yzd6y6Mbg5W7cohrrNf2JSlf15bqzW/0VvuBALiKO6lJC1S51s75mC57yufBB1bbSQbZP2fWveqhsR7pOdn15HmTvpG7F194+RvYw8rGSh/TR9el5+VixrdrB3jx0fsVMJ3+dn8oWqnaiqmMhYNGQdLLu1eau8o6XYHNr6ay0mf29fvr0stsJ6UbtRGWbPqs+xMw2y9UYktm4szzqs+pvNkaQzttXurNb/Z0E5XMRcRvVpYRq8al0s3qo/ILnxait6PrpGPW5p78Vur6U9/6Ur3Qw8wV7+5jZj3zASj59VH3CqH/Y0+7S/MzvXh10efA24PVdnRYBFgXyKZ1Xm5dvc2vpVDYZ9NFBtgXVOZVdpUtG/aTOyzmGkS1U/kX6urS82uce+1Xd2a3+ToLnIW1ykRHd4jNb5Kp6183ykqO2roO07SR0+dX+UtdJ6PKg/kD5Srfir8vP+oDKfuYDZvnOB6yMFzo7z8NsLLCSh2o8qzrRjXXmR/mqDlhMckGQLqXzavPybW4tHXTVTj/tAFuofDhZhs5m1I+o/FXtYNZ2xde1ZRj1u9dejHRLt/q7BSfxRcvtusVntMhB1oPrZvlsP7Lp+u4kVPnquGHUfiahyntfOX4YzefePMz6SHsY+VjJw8jH6ng7O+VXxrI3n+OBFV3no8qv2EKWgUWARUXSybpXm7vKO94Xm1vLFbCFzj71ld2KTddPlmUnvDxr6+WRH9hbBulm4xB77Ee6//J//s//r/yRnldeeeWVV1555cNjacf/yiuvvPLKK698CLx58/8Hhb07UG2bjkkAAAAASUVORK5CYII="}}},{"cell_type":"code","source":"prediction = predictions[0]\nimage = image[0]\nmask = mask[0]\ny_true = mask.numpy().astype(np.float32)","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:14:19.201060Z","iopub.execute_input":"2023-07-11T21:14:19.201433Z","iopub.status.idle":"2023-07-11T21:14:19.210494Z","shell.execute_reply.started":"2023-07-11T21:14:19.201402Z","shell.execute_reply":"2023-07-11T21:14:19.209501Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, axs = plt.subplots(1, 3, figsize=(16,16))\naxs[0].imshow(image)\naxs[0].set_title('Image')\naxs[1].imshow(mask, cmap='gray')\naxs[1].set_title('mask')\naxs[2].imshow(prediction, cmap='gray')\naxs[2].set_title('prediction')\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:14:20.894564Z","iopub.execute_input":"2023-07-11T21:14:20.894950Z","iopub.status.idle":"2023-07-11T21:14:21.509054Z","shell.execute_reply.started":"2023-07-11T21:14:20.894920Z","shell.execute_reply":"2023-07-11T21:14:21.508245Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_watershed(prediction, plot=False):\n    normalized_prediction = cv2.normalize(prediction, None, 0, 255, cv2.NORM_MINMAX, cv2.CV_8UC3)\n    ret, thresh = cv2.threshold(normalized_prediction, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)\n    \n    kernel = np.ones((3,3),np.uint8)\n    opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 4)\n    \n    sure_bg = cv2.dilate(opening,kernel,iterations=3)\n    \n    dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)\n    ret, sure_fg = cv2.threshold(dist_transform,0.15*dist_transform.max(),255,0)\n    \n    sure_fg = np.uint8(sure_fg)\n    unknown = cv2.subtract(sure_bg,sure_fg)\n    \n    ret3, markers = cv2.connectedComponents(sure_fg)\n    \n    markers_norm = np.int32(markers + 10)\n    markers_norm[unknown == 255] = 0\n    \n    prediction_rgb = cv2.cvtColor(prediction.astype(np.float32), cv2.COLOR_GRAY2BGR)\n    image_cv = np.uint8(prediction_rgb)\n\n    markers = cv2.watershed(image_cv, markers_norm)\n    \n    if plot:\n        fig, axs = plt.subplots(6, 1, figsize=(6, 6 * 6))\n        \n        axs[0].imshow(thresh, cmap='gray')\n        axs[0].set_title(\"Thresholded Prediction\")\n        \n        axs[1].imshow(opening, cmap='gray')\n        axs[1].set_title('Prediction after removing noise')\n            \n        axs[2].imshow(sure_bg, cmap='gray')\n        axs[2].set_title('Sure Background')\n        \n        axs[3].imshow(sure_fg, cmap='gray')\n        axs[3].set_title('Sure Foreground')\n        \n        axs[4].imshow(unknown, cmap='gray')\n        axs[4].set_title('Unknown Region')\n        \n        axs[5].imshow(markers, cmap='gray')\n        axs[5].set_title('Watershed image (instantiated image)')\n        \n        plt.show()\n    return markers\n\ndef get_binary_masks(markers, background_label=10, marker_label=-1):\n    \"\"\"\n    takes watershed markers and \n    \"\"\"\n    unique_labels = np.unique(markers)\n    \n    if background_label in unique_labels:\n        unique_labels = unique_labels[unique_labels != background_label]\n    if marker_label in unique_labels:\n        unique_labels = unique_labels[unique_labels != marker_label]\n\n    binary_masks = []\n\n    for label in unique_labels:\n        mask = np.where(markers == label, 1, 0).astype(np.uint8)\n        kernel = np.ones((3, 3), np.uint8)\n        mask = cv2.dilate(mask, kernel, iterations=6)\n        binary_masks.append(mask)\n        \n    return binary_masks\n\ndef plot_binary_masks(prediction):\n    markers = get_watershed(prediction)\n    binary_masks = get_binary_masks(markers)\n\n    fig, axs = plt.subplots(len(binary_masks), 1, figsize=(6,len(binary_masks) * 6))\n    for i, mask in enumerate(binary_masks):\n        axs[i].imshow(mask, cmap='gray')\n        axs[i].set_title(f\"Instance Segmentation {i + 1}\")","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:14:26.809530Z","iopub.execute_input":"2023-07-11T21:14:26.810524Z","iopub.status.idle":"2023-07-11T21:14:26.829734Z","shell.execute_reply.started":"2023-07-11T21:14:26.810486Z","shell.execute_reply":"2023-07-11T21:14:26.828665Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"watershed = get_watershed(prediction, plot=True)","metadata":{"execution":{"iopub.status.busy":"2023-07-11T21:14:29.836766Z","iopub.execute_input":"2023-07-11T21:14:29.837135Z","iopub.status.idle":"2023-07-11T21:14:30.904406Z","shell.execute_reply.started":"2023-07-11T21:14:29.837104Z","shell.execute_reply":"2023-07-11T21:14:30.903522Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_binary_masks(prediction)","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:51.403914Z","iopub.status.idle":"2023-07-11T20:57:51.405008Z","shell.execute_reply.started":"2023-07-11T20:57:51.404732Z","shell.execute_reply":"2023-07-11T20:57:51.404759Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def encode_binary_mask(mask: np.ndarray) -> str:\n    # Check input mask\n    if mask.dtype != np.bool_:\n        raise ValueError(\n            \"encode_binary_mask expects a binary mask, received dtype == %s\" %\n            mask.dtype)\n\n    mask = np.squeeze(mask)\n    if len(mask.shape) != 2:\n        raise ValueError(\n            \"encode_binary_mask expects a 2d mask, received shape == %s\" %\n            mask.shape)\n\n    # convert input mask to expected COCO API input --\n    mask_to_encode = mask.reshape(mask.shape[0], mask.shape[1], 1)\n    mask_to_encode = mask_to_encode.astype(np.uint8)\n    mask_to_encode = np.asfortranarray(mask_to_encode)\n\n    # RLE encode mask --\n    encoded_mask = coco_mask.encode(mask_to_encode)[0][\"counts\"]\n\n    # compress and base64 encoding --\n    binary_str = zlib.compress(encoded_mask, zlib.Z_BEST_COMPRESSION)\n    base64_str = base64.b64encode(binary_str)\n    return base64_str\n\ndef encode_all_masks(binary_masks):\n    encoded_masks = []\n    for mask in binary_masks:\n        encoded_mask = encode_binary_mask(mask.astype(np.bool_))\n        encoded_masks.append(encoded_mask.decode('utf-8'))\n    prefixed_masks = ['0 1.0 ' + mask for mask in encoded_masks]\n    encoded_preds = ' '.join(prefixed_masks)\n    return encoded_preds\n\ndef create_submission(directory, model, plot=True):\n    file_paths = [os.path.join(directory, path) for path in os.listdir(directory)]\n    predictions = []\n    image_ids = []\n    for path in file_paths:\n        image_id = os.path.splitext(os.path.basename(path))[0]\n        image=cv2.imread(path)/255\n        resized_image = cv2.resize(image, (512, 512), interpolation=cv2.INTER_AREA)\n        if resized_image.shape[2] == 1:\n            resized_image = cv2.cvtColor(resized_image, cv2.COLOR_GRAY2BGR) \n        prediction = model.predict(np.expand_dims(resized_image, axis=0))[0]\n        markers = get_watershed(prediction, plot=False)\n        binary_masks = get_binary_masks(markers)\n        encoded_preds = encode_all_masks(binary_masks)\n        \n        image_ids.append(image_id)\n        predictions.append(encoded_preds)\n    \n    if plot:\n        fig,axs = plt.subplots(1, 3, figsize=(24, 8))\n        axs[0].imshow(resized_image)\n        axs[0].set_title(f\"Image {image_id}\")\n        \n        axs[1].imshow(prediction, cmap='gray')\n        axs[1].set_title(f\"U-net Prediction\")\n        \n        axs[2].imshow(markers, cmap='gray')\n        axs[2].set_title(\"watershed + postprocessing\")\n        \n    df = pd.DataFrame({'id': image_ids, 'height': 512, 'width':512 ,'prediction_string': predictions})\n\n    return df","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:51.406492Z","iopub.status.idle":"2023-07-11T20:57:51.407319Z","shell.execute_reply.started":"2023-07-11T20:57:51.407054Z","shell.execute_reply":"2023-07-11T20:57:51.407078Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = create_submission(\"/kaggle/input/hubmap-hacking-the-human-vasculature/test\", model)\ndf.to_csv('submission.csv', index=False)\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2023-07-11T20:57:51.409044Z","iopub.status.idle":"2023-07-11T20:57:51.409532Z","shell.execute_reply.started":"2023-07-11T20:57:51.409288Z","shell.execute_reply":"2023-07-11T20:57:51.409312Z"},"trusted":true},"execution_count":null,"outputs":[]}]}