{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# EODC Dask Tutorial\n", "\n", "Dask is a flexible parallel computing library for analytics that enables you to\n", "scale your computations from a single machine to a cluster. This tutorial will\n", "guide you through the basics of using Dask on the EODC cluster. The computation\n", "will take place on the cluster and you only need to download the result to your\n", "local machine for visualisation or further processing steps. As input data\n", "for this tutorial we will use output data from the Global Flood Monitoring (GFM)\n", "service. \n", "\n", "As an example, we will calculate the maximum flood extent of a certain time range\n", "over an area of interest in Morocco. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Prerequisites\n", "\n", "Before we start, make sure you have installed all the necessary Python libraries and\n", "packages with the correct versions. It is important that the cluster and client\n", "(your machine) have the same versions for the key Python libraries. The easiest\n", "way is to create a new Python environment with the package manager of your liking.\n", "See the required dependencies in the [EODC cluster image](https://github.com/eodcgmbh/cluster_image) repository.\n", "\n", "In order to spin up a dedicated cluster on the EODC cluster, you will need to\n", "request an EODC account. Please follow the instructions [here](https://docs.eodc.eu/services/dask.html#who-should-use-dask-gateway-at-eodc)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Prepare Python environment\n", "\n", "In this notebook, we are using Python 3.12.11. First, let's install some necessary Python packages. We also need to install the \"ipykernel\" packge to enable Jupyter notebooks to run Python code." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!pip install pyproj xarray shapely pystac_client odc-stac==0.4.0 odc-loader==0.5.1 matplotlib eodc-connect rioxarray ipykernel" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!pip install lz4==4.4.4 tornado==6.5.2 toolz==1.0.0 cloudpickle==3.1.1 msgpack==1.1.1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## First some imports" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [], "source": [ "import pyproj\n", "import rioxarray\n", "import xarray as xr\n", "from pathlib import Path\n", "from datetime import datetime\n", "from shapely.geometry import box\n", "from pystac_client import Client\n", "from odc import stac as odc_stac\n", "import matplotlib.pyplot as plt\n", "\n", "from eodc_connect.dask import EODCDaskGateway" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Initialize cluster\n", "\n", "Your username of your EODC account come here, usually it is your email address\n", "you have used for registration. \n", "After running the next cell, a prompt will open and ask you to enter your\n", "password. " ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Unclosed client session\n", "client_session: \n" ] } ], "source": [ "your_username = \"tobias.raiger-stachl@eodc.eu\"\n", "gateway = EODCDaskGateway(username=your_username)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Once authenticated, you can specify the details of your cluster. Specify the\n", "number of cores and size of memory of your worker machines. \n", "Additionally, you can specify any public docker image which has the same dask\n", "version installed like our Dask cluster. However, we suggest you are using our\n", "cluster image to avoid errors coming from mismatching software versions.\n", "\n", "You will find more detailed information about dask\n", "[here](https://docs.eodc.eu/services/dask.html).\n", "\n", "The client object provides you with an URL to the dashboard of your current\n", "cluster. Copy/paste this into your web browser to get an overview what is\n", "currently happening on your cluster.\n", "\n", "Please make sure to re-use or shutdown an existing cluster, before spawning a\n", "new one!" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "No existing cluster found.\n" ] } ], "source": [ "# Connect to the gateway and shutdown the existing cluster if it exists\n", "cluster_list = gateway.list_clusters()\n", "if len(cluster_list) > 0:\n", " gateway.connect(cluster_list[0].name).shutdown()\n", " print(f\"Shutting down {cluster_list[0].name}\")\n", "else:\n", " print(\"No existing cluster found.\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'https://dask.services.eodc.eu/clusters/dask-gateway.5541687a59e04f27a7d23390720e8494/status'" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" }, { "name": "stderr", "output_type": "stream", "text": [ "2026-04-08 15:33:36,587 - distributed.client - ERROR - Failed to reconnect to scheduler after 30.00 seconds, closing client\n" ] } ], "source": [ "# Define cluster options\n", "cluster_options = gateway.cluster_options()\n", "\n", "# Set the number of cores per worker\n", "cluster_options.worker_cores = 8\n", "\n", "# Set the memory per worker (in GB)\n", "cluster_options.worker_memory = 16\n", "\n", "# Specify the Docker image to use for the workers\n", "cluster_options.image = \"ghcr.io/eodcgmbh/cluster_image:2025.9.3\"\n", "\n", "# Create a new cluster with the specified options\n", "cluster = gateway.new_cluster(cluster_options)\n", "\n", "# Automatically scale the cluster between 1 and 10 workers based on workload\n", "# cluster.adapt(1, 2) \n", "\n", "# Optionally, scale the cluster to use only one worker\n", "cluster.scale(1)\n", "\n", "# Get a Dask client for the cluster\n", "client = cluster.get_client()\n", "client.dashboard_link" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Search and load data\n", "\n", "Now we will define our area (AOI) and time range of interest for which we want\n", "to calculate the maximum flood extent for.\n", "\n", "All GFM data is registered as a [STAC](https://stacspec.org/en/) collection.\n", "Please find more information about STAC in our [documentation](https://docs.eodc.eu/services/stac.html)." ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "On EODC we found 187 items for the given search query\n" ] } ], "source": [ "# Define the API URL\n", "api_url = \"https://stac.eodc.eu/api/v1\"\n", "\n", "# Define the STAC collection ID\n", "collection_id = \"GFM\"\n", "\n", "# Define the area of interest (AOI) as a bounding box\n", "# Use portal.gfm.eodc.eu to create an AOI and retrieve the coordinates or another tool like bboxfinder.com\n", "# aoi = box(min_lon, min_lat, max_lon, max_lat)\n", "aoi = box(-6.725286048,34.093280072,-4.792626025,36.073018993)\n", "\n", "# Define the time range for the search\n", "time_range = (datetime(2026, 2, 1), datetime(2026, 3, 1))\n", "\n", "# Open the STAC catalog using the specified API URL\n", "eodc_catalog = Client.open(api_url)\n", "\n", "# Perform a search in the catalog with the specified parameters\n", "search = eodc_catalog.search(\n", " max_items=1000, # Maximum number of items to return\n", " collections=collection_id, # The collection to search within\n", " intersects=aoi, # The area of interest\n", " datetime=time_range # The time range for the search\n", ")\n", "\n", "# Collect the found items into an item collection\n", "items = search.item_collection()\n", "\n", "print(f\"On EODC we found {len(items)} items for the given search query\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will use the retrieved STAC items to lazily load the data into an xarray.Dataset object. To accomplish this, we need to specify the bands to load, the coordinate reference system (CRS), and the data resolution. All necessary metadata is contained within each STAC item.\n", "\n", "There is no strict rule for determining the optimal chunk size, but a general guideline is to set the chunk size as a multiple of the raster file block size that will be read. Additionally, the chunk size should ideally be around 100-300 MB, depending on the available memory on the worker node. The following cell provides an overview of the total array size and estimated chunk size.\n", "\n", "In our specific case, the raster block size is 512x512 pixels and the worker has substantial memory capacity. Therefore, we will set the chunk size to 4096x4096 pixels and utilize all available timestamps (-1).\n", "\n", "If the processing on the worker node fails, please try reducing the chunk size to e. g. 1024x1024px." ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "\n", "
<xarray.DataArray 'ensemble_flood_extent' (time: 22, y: 12534, x: 11448)> Size: 3GB\n",
       "dask.array<ensemble_flood_extent, shape=(22, 12534, 11448), dtype=uint8, chunksize=(22, 4096, 4096), chunktype=numpy.ndarray>\n",
       "Coordinates:\n",
       "  * time         (time) datetime64[us] 176B 2026-02-01T18:32:49 ... 2026-02-2...\n",
       "  * y            (y) float64 100kB 9.249e+06 9.249e+06 ... 8.998e+06 8.998e+06\n",
       "  * x            (x) float64 92kB 2.944e+06 2.944e+06 ... 3.173e+06 3.173e+06\n",
       "    spatial_ref  int32 4B 0\n",
       "Attributes:\n",
       "    nodata:   255
" ], "text/plain": [ " Size: 3GB\n", "dask.array\n", "Coordinates:\n", " * time (time) datetime64[us] 176B 2026-02-01T18:32:49 ... 2026-02-2...\n", " * y (y) float64 100kB 9.249e+06 9.249e+06 ... 8.998e+06 8.998e+06\n", " * x (x) float64 92kB 2.944e+06 2.944e+06 ... 3.173e+06 3.173e+06\n", " spatial_ref int32 4B 0\n", "Attributes:\n", " nodata: 255" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Extract the coordinate reference system (CRS) from the first item's properties\n", "crs = pyproj.CRS.from_wkt(items[0].properties[\"proj:wkt2\"])\n", "\n", "# Set the resolution of the data\n", "resolution = items[0].properties['gsd']\n", "\n", "# Specify the bands to load\n", "bands = [\"ensemble_flood_extent\"]\n", "\n", "# Load the data using odc-stac with the specified parameters\n", "xx = odc_stac.load(\n", " items, \n", " bbox=aoi.bounds, # Define the bounding box for the area of interest\n", " crs=crs, # Set the coordinate reference system\n", " bands=bands, # Specify the bands to load\n", " resolution=resolution, # Set the resolution of the data\n", " dtype='uint8', # Define the data type\n", " chunks={\"x\": 4096, \"y\": 4096, \"time\": -1}, # Set the chunk size for Dask\n", " dask_client=client,\n", " groupby=\"solar_day\"\n", ")\n", "\n", "# Extract the 'ensemble_flood_extent' data from the loaded dataset\n", "data = xx.ensemble_flood_extent\n", "data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Process on the cluster\n", "\n", "First, we filter the data to exclude invalid values and calculate the sum along\n", "the time dimension. The maximum flood extent refers to the largest area covered \n", "by flooded pixels during the specified time range. Therefore, we convert the\n", "result to a binary mask where each pixel is set to 1 if it was flooded during\n", "the specified time range, and 0 if it was not. Then we start the computation on\n", "the cluster and save the result as a compressed TIFF file. This file can be\n", "visualized in e.g. QGIS." ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [], "source": [ "# Create output directory\n", "output = Path(\"./output\")\n", "output.mkdir(exist_ok=True)\n", "fname = \"max_flood_morocco_202602_dask.tif\"\n", "\n", "# Filter the data to exclude values of 255 (nodata) and 0 (no-flood), then sum\n", "# along the \"time\" dimension \n", "filtered_data = data.where((data != 255) & (data != 0))\n", "result = filtered_data.sum(dim=\"time\")\n", "\n", "# Convert the result to binary (1 where the sum is greater than 0, otherwise 0)\n", "# and set the data type to uint8 \n", "binary_result = xr.where(result > 0, 1, 0).astype(\"uint8\")\n", "\n", "# Compute\n", "computed_result = binary_result.compute()\n", "\n", "# 4. Save with specific block sizes and LZW compression\n", "output_path = output.joinpath(fname)\n", "computed_result = computed_result.rio.write_crs(crs)\n", "computed_result.rio.write_nodata(255, inplace=True)\n", "computed_result.rio.to_raster(\n", " output_path,\n", " crs=crs,\n", " compress=\"LZW\",\n", " tiled=True,\n", " blockxsize=512,\n", " blockysize=512\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Also, we can plot a part of the result with the plotting library matplotlib." ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjsAAAHHCAYAAABZbpmkAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAVxRJREFUeJzt3QecU2X28PEz9I4gXZGqIkhRUKQIooiFVRQLawNpriygwF+RohSRoiKCgrKCiuIqqFhWQRSVsggsSlFcEQRRkCIgvTMz9/2cx03eTCbJJDf15v6+fC4zubm5SW4yuSfnOc/zZFiWZQkAAECaypfsBwAAABBPBDsAACCtEewAAIC0RrADAADSGsEOAABIawQ7AAAgrRHsAACAtEawAwAA0hrBDgAASGsEO0AKysjIkBEjRojb3HvvvVK9evWk3Lfer94/gPRDsIOE2bJli/Tp00fOO+88KVasmFnq1q0rvXv3lu+++y7Htnqi1xN+oGXq1Kne7TzrevToEfA+hw4d6t1m7969IR/fjBkzvNsuXbo01/U6s0rVqlXN9X/5y19sHwc3+uWXX4K+npdddpk4SbDnocv9998f8f5eeOEF895LhHnz5rkyiAYKcAiQCB9//LF06tRJChQoIHfddZc0bNhQ8uXLJz/++KO899578uKLL5pgqFq1ajlup+tLlCiRY13Tpk1zXC5SpIjMmTPHnDQKFSqU47q33nrLXH/ixImwH6tu/+abb0rLli1zrF+8eLH89ttvUrhwYYm348ePm2OVbu644w65/vrrc6wrX768OM3VV18tnTt3zrVeA/lI6fu2XLlyCckqabAzZcoUAh64Tvp9miLlbN68Wf7617+aQOaLL76QypUr57j+ySefNB/4Gvz4u/XWW82JIJRrr71W/vWvf8knn3wiHTp08K5ftmyZCaBuueUWEwyFS0/G77zzjjz33HM5Ag4NgBo3bpxnhigWNOBKRxdffLHcfffd4nQa1KTD8wDcgmYsxN1TTz0lR48elVdffTVXoKM0oHjggQdME5EdZ511lrRq1coEI77++c9/Sv369eXCCy+MOPvwxx9/yIIFC7zrTp06Je+++67ceeedAW8zfvx4ad68uZx55plStGhRExTp9r70+WtTxyuvvJJj/ZgxY8x6/dYdrGbH06y3ceNGc5ItXbq0yYg89thjpnlt27ZtJtArVaqUVKpUSZ555pmATXTanORr0aJFZr3+9LjiiivMMdOmxdatW5vmxtq1a3ufj2a4NLumz/P888+Xzz//XOJJ3zv/93//Z94fmlXT+9Tjrc/bV2ZmpowaNUpq1aplttManCFDhsjJkydzbKe3e+KJJ+Tss882z61Nmzby3//+N6aPef369eb4+Gd/tHk0f/788sgjj5jL+hj1vvWYeprC9Ph7HDhwQPr16+d97vo66JeD7OzsXE2Eekxeeukl7/O/5JJL5Ouvv/Zup5kjzeoo36Y3wA0IdpCQJiz9kPZvfgrHvn37TCbFs+zfvz/gdhqEfPTRR3LkyBHviU+zM8GCk1D0BNSsWTPTBOahWaODBw+aDFUgkyZNkosuukgef/xxE7xoAHfbbbfJ3Llzvdt07drV1PoMGDDABCdq3bp1MnLkSOnevXuu5p1AtClQT3Tjxo0zx1NP2hMnTjTNKhr06YlQj/VDDz0kS5YsEbv0OOtj1fvQYFVPnvrcZ8+ebX7qY9XHoIGIZt8OHz4c1n6PHTuW4/XU5fTp00G318DkxhtvlGeffdZk8CZMmGCCnYcfftgcR19atzVs2DCTPdLtNVAbO3ZsrtdMt9EgUZtSn376aalZs6a0a9fOPJdwabOo//PQRYNidcEFF5jAa+bMmSbrqHT/GnDUqVPHvE+UvnYadOk63VYXrTPzHCt9Dm+88YYJmjTT2KJFCxk8eHCu56402Nfn87e//c28LzQI6tixo/f46np9nyjPfekCuIIFxNHBgwf167d100035bpu//791p49e7zLsWPHvNcNHz7c3M5/qVatWo596LrevXtb+/btswoVKmTNnDnTrJ87d66VkZFh/fLLL9596X2E8uqrr5rtvv76a2vy5MlWyZIlvY/ptttus9q0aWN+18fQvn37HLf1fezq1KlT1oUXXmhdeeWVOdbv3LnTKlu2rHX11VdbJ0+etC666CLrnHPOMcfJ/3np4/Y/Hvfdd593XWZmpnX22Web5zlu3Lgcx7Vo0aJWly5dcj23LVu25LifhQsXmvX606N169Zm3Ztvvuld9+OPP5p1+fLls1asWOFd/+mnn5r1uv9Q9H4DvZ7+962P2fc1/uCDD8w2TzzxRI793XrrreZ5b9q0yVxeu3at2a5Hjx45tnvooYfM+i+//NJc3r17t3mf6OuXnZ3t3W7IkCFmO99jFkyw56HLW2+95d0uKyvLatmypVWxYkVr79695n1aoEAB8/7yVa9ePXPM/Y0aNcoqXry4tXHjxhzrBw0aZOXPn9/aunVrjmN75plnmr8Djw8//NCs/+ijj7zr9DHwsQ83IrODuDp06JD56V9krDRdr00xnsWTYveltTbanORZtGkqkDJlyphv/p5sjH7L1WYl/4LncN1+++2mSFizUpq10J+hskTaZOGbFdEs0OWXXy6rV6/OsZ02Menz1Oei169du9Y0a2nzUzh8e51pc0iTJk1M9kMzQx5nnHGGyX78/PPPYpe+Xr4ZEd2f7lczFr4ZOs/v4d7Xfffdl+P11EUzLMFo054+T23m9KXNWvq8NePm2U75Zzx0O+XJsGmTm2Zf+vbtm6MJR5uKIqFNhv7PQxdtEvPQGjRtPtRs43XXXWfq0jQro69ZODQzqe8RfW/7Zo/atm0rWVlZuTJ3mvXTbT30tiqa9wGQLihQzoN+oGhqeNWqVbJz5055//335aabboroIOuHstZQaHv6r7/+agpu//73v3vT1emsZMmS5qenecnXP/7xDxNI/P7770GLPbUWJ68CZQ8NRu655x7ZunWrfPDBB6b5xS4NvvSkokGTNifoyUWba4LRYEibDjR48a0RCVQToUGENk3oCVhP/ldddVXYj+ucc87JcVlrd7SY2f8Y6XqtO7JLm1b8H7vu07+uStepYM2L/s4991xzXMOlfy9VqlTxvo88NOjyXO/5qcGFNuH5B5capPlu53kc/q+3b6AQzvEJ53lo/YzWW2mzm9ZBafNZuH766SdTNxWst9ru3btDvjc8zyfc1wZIZwQ7edB2dv3m2a1bN9P+bceDDz4on332mSkg1IJZrUPRxQ30ZKhFyd9//32u6zxZAf+iWbu0tkNrS7p06WICDs3OREODp549e8quXbvMN3M9aQby73//29y3Bmb67V2fb8GCBU1Bsn/RtNIg5JtvvjG///DDD6YGJ1BPtEA0yxHOOuVbwBusEFWDuHDvJ9z7SqZULLjVv321Y8cO89prABYOfV9ojc3AgQMDXu/fzT3VXxsgmWjGyoOe5PQb+8033xzwej2pajGoFocWL17cnMB9e7ZorwwdK+bDDz80J8QaNWqYnjqeQkE3aN++vWzatElWrlwZ1/vRpiTNuunx1+MbbkYoGH3NNQhZsWJFyCYsbWrT7Mqnn35qgmJ9z4T61q+DKGpGS4tntXeOFqnGm+dbvvbu8eXJdKQqbYbUIMG/AFrHZ/Jc7/mpwYFmQ3xp1lCfs+92yn+7PXv2xCUDogNgavPW6NGjTfOZFgmHG6BpVkgzovpeCrT4Z3KcGgwCiUCwEyUdEXj58uUya9Ysk3LWHjhaO+L5MNUeQtrbQ5s5NNDRnj5ad+GWzI7Sb6baxVcDAT35xPObpwaew4cPj6i5IFTdigaq2gxxww03BN1Ov1HrScQ3S6LZKm1K86fdt7VHk/ZkGjRokGnSevTRR02X8njSE6fyrfPQx6tNq6lMe33p45w8eXKO9drbSo+5Bpae7ZR/4Ki9tzwBt9IgQbNuzz//fI73XTwCTh3jSZuvdJwn7QKvmV3tmfX666/n2E6/JPkHoUozk/rZokG0P91eexxGSu/Lc3vATWjGioLWhmhThf7UugLPyXb+/PlmvXZB1uJA/fasxYb6Iacf3P379zf1H19++aW4gdZHaHOOjl+jha6eEZT1ZKMnBL1OMyhaBxEt3W+ogtdIaZNYXvREqidVDXI1A6S1FFqErPUjvtNg6PpevXqZIlYNkpWexBcuXGi6JGuWJ9zmrEjVq1fPTMugBbIaaJctW9YE6HZOmImkQaYeL61v0wBSX1ttFtJMqRYVe4I4Xa+vlQZveiLXLtuaSXzttddMts9TOKz1L/o3qlk17VqvQdKaNWtMoXMkmUANTrXuyl/FihVNVlHf2xrca7ZRA2alWR3NAmqztgZdns8MzfTqNppB1vdMhQoV5MorrzSBkgZH+jj1/aHbabO6DlegQbMej0izl7oPpQXf11xzjQnUgw2nAKSVZHcHcxI9XO+//7738scff2zWafdQ30W7l95+++1mm549e5ptNmzY4L3dqlWrzDrtzusm2k24V69eVu3ata0iRYqY7tF16tSx7r//ftN12Fe43cU9Xc9DsdP1PJRAXc9ffvll69xzz7UKFy5snpPuy3O/Hh07djTd2bU7vC9PF+Enn3wyz67n/s9Bu0rre86fdmXWLs2+Nm/ebLVt29Y8Ru0Ord2tFyxYELDruf9tgz3vcF8DT/fop59+OuR2/l3P1eHDh63+/ftbVapUsQoWLGiOs+7Ht+u4On36tDVy5EirRo0aZruqVatagwcPtk6cOJFjO+0SrttVrlzZvAevuOIK6/vvvzf3G23Xc08X8kmTJpnLc+bMyXFb7S5eqlQp6/rrr/eu27Vrlzmu+t7w3Yfnuetz0L8Z7TJfrlw5q3nz5tb48ePN8AZ5HVv/95EOV9C3b1+rfPnypus+pwC4RYb+l+yAyyk0be7bG0ubIzRLoSOg+hcHahOIFiJqk4pmeHwHTtMuzdqso99Q3VS7AwBAMtCMFQUdMVebpbR5wjOmhT8d8VSbCnR+KE/K3VOfYXcMGAAAED4yO3nQ3hDak8gT3Ghthrb/a82D9obQ8WG++uorM46OXq+9OnSyywYNGphaDu0honPUaKZHiyD1svbG0UHkPF1SAQBA/BDs5EG7MfuOiuqhxZA6Oqo2T2lhoRYfb9++3RQMaiGoznekY+oo7TqrI7ZqcKO9IbQHiQZHGjABAID4ItgBAAAxnUlAEwU6fYvWtOrI6zrEhvYqTBbG2QEAAHnOJBBo/sJAdEgRLePQVhGdQkeHidDx5QKNGZUoZHYAAICtXsmBPPLII2buP99pgnQ8Jx0DS8ehSwZ6YwWgRcRaZ6OTDzK8OgAgFB3BRac00YEi4zUwqDpx4oSZdiQWjzfDb+oQnVdQl1jQkb/9p8zRQSw1w5MsBDsBaKDjP7szAAChbNu2LSYjwQcLdGpUKyG7dgeevDcSJUqUMD2NfemYcDo1Tizo5Mk6mrgvvXzo0CEzzpyOLJ5oBDsBaEZHtZTrpYAUTPRrAgBwkEw5LUtlnvfcEQ+a0dFA59dV1aVUSfvZo0OHs6Va419MYKZDoHjEKquTqgh2AvCk9zTQKZBBsAMACOF/8xAkouyhRMkMs9iVLX/eVgMd32AnlnT2AP9Jn/Wy3l8ysjqKYAcAAIfIsrIly4ru9vHWrFkzmTdvXo51CxYsMOuTha7nAAA4RLZYUS+R0voe7UKui6druf6+detWc3nw4MHSuXNn7/b333+//PzzzzJw4ED58ccf5YUXXpC3335b+vfvL8lCsAMAAIL65ptvzHRIuigdLFB/HzZsmLmsAw16Ah9Vo0YN0/Vcszk6Po/OGDB9+nTTIytZaMYCAMAhss2/6G4fqSuuuMJ0Vw9Gp04KdJs1a9ZIqiDYAQDAIbIsyyzR3N6NaMYCAABpjcwOAAAOYbfI2COa2zoZwQ4AAA6hwUoWwU7EaMYCAABpjcwOAAAOQTOWPQQ7AAA4BL2x7KEZCwAApDUyOwAAOIQOCRjdoILuRLADAIBDZEXZGyuLrucAACCV6Yzn0c16Lq5EzQ4AAEhrNGMBAOAQ1OzYQ7ADAIBDZEuGZElGVLd3I5qxAABAWiOzAwCAQ2Rbfy7R3N6NCHYAAHCIrCibsbJoxgIAAEg/ZHYAAHAIMjv2EOwAAOAQ2VaGWaK5vRvRGwsAAKQ1MjsAADgEzVj2EOwAAOAQWZLPLPZv704EOwAAOIQVZc2ORc0OAABA+iGzAwCAQ1CzYw/BDgAADpFl5TOL/duLK9H1HAAApDUyOwAAOES2ZEh2FHmKbHFnaodgBwAAh6Bmxx6asQAAQFojswMAgGsKlC1xI4IdAAAcVbMTxUSgwkSgAAAAaYfMDgAADpEd5dxY2fTGAgAAqYyaHXvI7AAA4KDMDuPsRI6u5wAAIK2R2QEAwCGyrAyzRHN7NyLYAQDAIbKiLFDOcmmBMs1YAAAgrZHZAQDAIbKtfGaxf3tL3IhgBwAAh6AZyx6asQAAQFojswMAgENkR9mjKlvciWAHAADXDCqYT9zInc8aAAC4BpkdAABcMzdWPnEjgh0AABwiWzLMEs3t3YhgBwAAhyCzY48781kAAMA1yOwAAOCaQQXziRsR7AAA4BDZVoZZorm9G7kzxAMAAK5BZgcAAIfQQQGjaYrKdmmOg2AHAADXzHqeT9zInc8aAAC4BpkdAAAcIksyzBLN7d2IYAcAAIegGcsemrEAAEBaI7MDAIBDZEXZFJUl7pT0zM7hw4elX79+Uq1aNSlatKg0b95cvv7666Dbv/fee3L11VdL+fLlpVSpUtKsWTP59NNPc203ZcoUqV69uhQpUkSaNm0qK1eujPMzAQAgMc1Y0SxulPRn3aNHD1mwYIHMnDlT1q1bJ+3atZO2bdvK9u3bA26/ZMkSE+zMmzdPVq1aJW3atJEbbrhB1qxZ491m9uzZMmDAABk+fLisXr1aGjZsKNdcc43s3r07gc8MAID4TAQazeJGSX3Wx48flzlz5shTTz0lrVq1ktq1a8uIESPMzxdffDHgbSZOnCgDBw6USy65RM4991wZM2aM+fnRRx95t5kwYYL07NlTunbtKnXr1pWpU6dKsWLF5JVXXkngswMAID1MibC1RM/V559/vmmxqVq1qvTv319OnDghrgx2MjMzJSsryxw8X3pwli5dGtY+srOzTVNY2bJlzeVTp06ZjI9mhzzy5ctnLi9fvjzGzwAAgMSxJEOyo1gsG/U+kbaWvPnmmzJo0CCz/fr16+Xll182+xgyZIi4MtgpWbKkqbkZNWqU7NixwwQ+b7zxhglKdu7cGdY+xo8fL0eOHJHbb7/dXN67d6/ZT8WKFXNsp5d37doVcB8nT56UQ4cO5VgAAEg1yWjGmhBha8myZcukRYsWcuedd5pskJan3HHHHUmtnU16453W6liWJWeddZYULlxYnnvuOXNQNBuTF40eR44cKW+//bZUqFDB9mMYO3aslC5d2rtoyg0AgHR1yO8Lvn7pD8ROa4l2NNLbeIKbn3/+2dTZXn/99eLaYKdWrVqyePFik53Ztm2bOTinT5+WmjVrhrzdrFmzTHGzBjq+L0K5cuUkf/788vvvv+fYXi9XqlQp4L4GDx4sBw8e9C76OAAASDXZVkbUi9Iv9b5f8vVLfyB2Wks0o/P4449Ly5YtpWDBguY8f8UVV7i3GctX8eLFpXLlyrJ//37TlbxDhw5Bt33rrbdMOk1/tm/fPsd1hQoVksaNG8sXX3yRo65HL2uTWSCaUdJu7L4LAACpRmc8j3ZR+qXe90u+fumPlUWLFpnOQy+88IKp8dEhY+bOnWtKVlw7qKAGNtqMpVXbmzZtkocffljq1KljghmlL4B2Q3/99de9TVddunSRSZMmmYpwT2SpRc0anSotpNJtmjRpIpdeeqmpCj969Kh3nwAAuFmpML/Y22kteeyxx+See+4xrS+qfv365hx83333ydChQ8MqU0m7zI5GlL179zYBTufOnU3aSwMgTX0pLVTeunWrd/uXXnrJ9OLS22gmyLM8+OCD3m06depkCpeHDRsmjRo1krVr18r8+fNzpeEAAHBjM1a47LSWHDt2LFdAowGT0uSGKzM72ovK05MqkBkzZuRKj4WjT58+ZgEAIF1kSz6zRHP7SOXVWqKJCu1k5Kn70YF+tQfXRRddZFpgtNVGsz263hP0uC7YAQAAqatTp06yZ88e01qipSPaYuLbWqKtL76ZnEcffVQyMjLMTy1D0emdNNAZPXp00p5DhpWsnFIK0254Wv9zhXSQAhl/NqcBABBIpnVaFsmHpiwjXh1cPOelXv/uKIVL2D8vnTxyWl68/L24PtZURGYHAACHsFN34yua2zoZwQ4AAA5hRTlzucVEoAAAAOmHzA4AAA6RJRlmieb2bkSwAwCAQ2Rb0dXdZLu0S1LSBxUEAACIJ4IdADl8uuPbPK/PaxsA8aHFydEubuTOZw0gqGuqNMwzoNFt7CBQCn5cgHBkS0bUixsR7AAIGszE+iSs+7UbKKWzYMfEc/wJhoDoEOwAyMVzcg2U5fGsiwYn78iCIAJEeGRZGVEvbkSwAyBkUOKb5fENgqLByRuwh5ode+h6DiCHQFkcghMATkZmB0DYmR3f9YlG0xfwvwJlK4pF3NmMRWYHcDlPQBMomPDN6AT7PVHILgEiVpQ9qiyXBjtkdgCXC9RURa+p5CB7hbxEldWxopsx3ckIdgCXc+IJ1omPORxkr4D4INgBXMxJGR3/wmnAjeiNZQ81O4BL+QY6TggenPAYgXiLtikqm2YsAG6Trs1BAOCLzA7gYmRLAGeJdn6rbJf2xiLYAVwo3O7mAFILzVj2UKAMIAdmJgeQbsjsAC7km9XxHyHZN7PDVBFAaiGzYw/BDuAigYIX/6asYEXLBD5A8hHs2EMzFuDijI7vEkywDBCSg+MPRI7MDuAygQKbQE1Yvtf5B0hIDrJrILNjD5kdII2FmwUIFcSEk/1BYvAawPLpfm5nsRxwCK+88ko5cOBArvWHDh0y19lBsAOksXicHGlGAZLHDROBLlq0SE6dOpVr/YkTJ+Tf//63rX3SjAUAAJLuu+++8/7+ww8/yK5du7yXs7KyZP78+XLWWWfZ2jfBDoCI0JQCJE861+w0atRIMjIyzBKouapo0aLy/PPP29o3wQ4AAA6RzsHOli1bxLIsqVmzpqxcuVLKly/vva5QoUJSoUIFyZ8/v619E+wAAICkq1atmvmZnZ0d830T7AAA4BDpnNnx9dNPP8nChQtl9+7duYKfYcOGSaQIdgAAcAjLyjBLNLdPddOmTZNevXpJuXLlpFKlSqaGx0N/J9gBAACO9sQTT8jo0aPlkUceidk+yewAAOAQnsEBo7l9qtu/f7/cdtttMd0ngwoCAOAQbhhU8LbbbpPPPvsspvskswMAAFJG7dq15bHHHpMVK1ZI/fr1pWDBgjmuf+CBByLeJ8EOAAAO4YYC5ZdeeklKlCghixcvNosvLVAm2AGQJ2bOBpzLDV3Pt2zZEvN9UrMDuHS6Byb0BJyb2YlmcQqdDHTDhg2SmZkZ9b4IdgAAQMo4duyYdO/eXYoVKyb16tWTrVu3mvV9+/aVcePG2donwQ7gUkzoCTiPFWVPLMsBmZ3BgwfLt99+K4sWLZIiRYp417dt21Zmz55ta58UKAMA4BCWCXiiu32q++CDD0xQc9lll+UYPVmzPJs3b7a1TzI7AAAgZezZs8fMcO7v6NGjOYKfSBDsAADgsBGUo1lSXZMmTWTu3Lney54AZ/r06dKsWTNb+6QZCwAAh3DDODtjxoyR6667Tn744QfTE2vSpEnm92XLluUadydcZHYAAEDKaNmypaxdu9YEOjqCsk4doc1ay5cvl8aNG9vaJ5kdAAAcQntUZaT5oIKqVq1aMm3aNIkVMjsAADiE9sSKdkl1+fPnl927d+da/8cff5jr7CDYARBXjNQMIBJWkIjs5MmTUqhQIbGDZiwAcZt/i0AHiK10LlB+7rnnvL2vtOeVTgbqkZWVJUuWLJE6derY2jfBDoC4TTTqCXh8gx9GbgbsS+dg59lnn/VmdqZOnZqjyUozOtWrVzfr7SDYARATnkDGP5jxn3iUgAewL50LlLf8b7bzNm3ayHvvvSdlypSJ2b6p2QEQE3llbHwDIZq3AATzySefBA10du7cKXYQ7ABIqEDZHwDhcUNvrIsvvtiMs+Nvzpw50qBBA1v7JNgBAMAh/gxYMqJYJOVdccUVZhLQJ5980jsn1r333iv33HOPDBkyxNY+qdkBAAAp44UXXpD27dtLjx495OOPPzZNV9oza+XKlXLhhRfa2ifBDgAADpHOvbF86dxYHTt2lBdffFEKFCggH330ke1AR9GMBQCAQ1gxWFLd5s2bzezmmtX59NNPZeDAgXLjjTean6dPn7a1T4IdAIAXPeWQbI0aNZIaNWrIt99+K1dffbU88cQTsnDhQtMd/dJLL3VesHP48GHp16+fVKtWTYoWLSrNmzeXr7/+Ouj22m535513ynnnnSf58uUzt/U3Y8YMM/qi71KkSJE4PxMASI8gh+EBUlt0xckZjmjG0pqdWbNmyRlnnOFdp/HBmjVrTE8txwU7Wny0YMECmTlzpqxbt07atWsnbdu2le3btwedF6N8+fLy6KOPSsOGwbuulipVygRGnuXXX3+N47MAAOcLNhgkUowL2rHuuece8/PUqVOyYcMGyczMNJdLliwpL7/8srOCnePHj5s+80899ZS0atVKateuLSNGjDA/tSApEB0qetKkSdK5c2cpXbp00H1rNqdSpUrepWLFinF8JgAAJEi0WR3LXmZnypQp5hysLSVNmzY1PaNCOXDggPTu3VsqV64shQsXNi0y8+bNCzs+6N69uxQrVkzq1asnW7duNev79u3r7Y7umGBHIzWd2Mu/iUmbs5YuXRrVvo8cOWKaxqpWrSodOnSQ//73vyG314zRoUOHciwAAEBk9uzZMmDAABk+fLisXr3atKxcc801snv37oCHRzMyWmvzyy+/yLvvvmuyM9OmTZOzzjorrMM5aNAgU6+zaNGiHDGCtvxo85ajgh1NR2m19ahRo2THjh0m8HnjjTdk+fLltoeDVueff7688sor8uGHH5r9ZWdnm7a+3377Lehtxo4dazJFnkWDJAAAUk0yRlCeMGGC9OzZU7p27Sp169Y1k3Fq1kXPtYHo+n379skHH3wgLVq0MBmh1q1bhyw/8aW3mzx5srRs2dK01Hholkd7ajmuZkdrdXR2U432NM2l07vfcccdpvjYLg2gtJlLq7n14Gr1ttb5/OMf/wh6m8GDB8vBgwe9y7Zt22zfPwAAqV6gfMivNUNbOIJlaVatWmWyKh56jtbLmpwI5F//+pc5F2szlpaR6Pg4Y8aMMUmNcOzZs0cqVKiQa72OpOwb/Dgm2KlVq5YsXrzYNDtpgKFtgNqHvmbNmjG7j4IFC8pFF10kmzZtCrqNBlpa1Oy7AIgd3xnPASRf1apVc7RoaAtHIHv37jVBin/tq17etWtXwNv8/PPPpvlKb6d1Oo899pg888wzpgt5OJo0aSJz5871XvYEONOnTzdBlGNHUC5evLhZ9u/fbwYQ0qLlWNGDrT29rr/++pjtE0BkPD179KcGPPT0AWyKosjY+N9tNcHg+8Vev/THipaPaGbmpZdekvz580vjxo1NL+unn37a1P3kRbNAOoLyDz/8YOp7tWOS/r5s2TKTIHFcZkcDm/nz58uWLVtMF/Q2bdpInTp1TLugp3lJm6R86Uyoumg2SFNd+rseBI/HH39cPvvsMxNZaiHV3Xffbbqeazd3AHH8ew6StfFf7wl4ACSvZqeUX2tGsGCnXLlyJmD5/fffc6zXy9rbORDtgaW9r/R2HhdccIHJBGmzWF60VkfP7Rro1K9f35zTNXjSZjMNnByX2dH6GA1otHi4bNmycsstt8jo0aNN05PSQmVPlzMPbZLy0HbEN9980/S80qpvpdkhLaTSg1qmTBlzYDQa1KIqAPETLFsTaL3vOjI9QOoqVKiQOY9+8cUXctNNN3kzN3q5T58+AW+jRcl6btbtPDW4GzduNEGQ7i/cMhftwRXKuHHj5P77788x+GAwGZZWCCMHLdbSNswrpIMUyPgz8AIAIJBM67Qskg/NF/h41Xx6zkvVpj0m+YrZnxUg+9gJ+bXnqIgeq3Y979Kli+noo9M1TJw4Ud5++2358ccfTe2OtsBoRyNP3Y82kWnPKb2Njo3z008/Sbdu3eSBBx6QoUOHSqzo49cMUDh1vilRswMAAFJz1vNOnTqZspFhw4aZVhPt7awlKJ6iZW2B8e1FrcXPWqbSv39/adCggQmEHnzwQXnkkUdsP+7AzyX8XA3BDgAACEmbrII1W+ngf/6019SKFSskVRDsAADgJBSfRIxgBwAAh0hGM1Y6SGrXcwDxQdduIE25YNbzeCDYAdIQg/YBSHeXX365mTw8HDRjAXHEGDIAYkuboaJpisqQVKRd68Pl6TKvU1GEi2AHiCP/wfP818UraCLIQqrhPRkj0TZFWZKSdGDAcCf5DHdCUV8EO0Ac+QY4nmAlnA99/20imVOKkwpSEU2rCGXhwoXe33VGhEGDBsm9997rnfhTp4p47bXXgk5YmheCHSCO/AOccAuHoz0xEPAAaSpNMzutW7fOMcflhAkT5I477vCuu/HGG808WTq5qI7MHCkKlIE48wQ4ieoh5ZtFApCms55Hs6Q4zeI0adIk13pdt3LlSlv7JNgBohROEOPfJAUACEynmwg0Cej06dPNdXbQjAVE2UwUKnjxzep4mrF8g6NwAx+apQAonQ4qmum7rRRtxvL17LPPyi233CKffPKJNG3a1KzTjI5OKDpnzhxb+ySzA9gQbpDi36TkuezfSytUU1ewzBEDBwIu5IJBBa+//noT2Nxwww2yb98+s+jvGzduNNfZQWYHiDPfrI5vwXKw7fLaDwCku7PPPlvGjBkTs/0R7ABx5tvclVc2Jtj1vk1goZrPCIicgdcJtkVbZGylfoGyOnDggLz88suyfv16c7levXrSrVs3KV26tK390YwFJEk4NT+eJi/PyTGvzA6Zn9RH8yOikWFFv6S6b775RmrVqmVqdzzNWNoVXdetXr3a1j4JdoAkBzjhjKwcTRDDyTX1EJTCNhfU7PTv39+Mq6ODC7733ntm2bJli/zlL3+Rfv362donzVhAEgTqkeW/zr/ZKtz9+m/PiTV1EHgC4WV2tOt5gQL/P0TR3wcOHBhw/J1wkNkBksS3iSrU9cEEuh2BTerjNUJUXDCoYKlSpWTr1q251m/btk1Klixpa58EO0CSBBtzJ5Ju7ZHeH5IjmklgAbc1Y3Xq1Em6d+8us2fPNgGOLrNmzZIePXrkmEIiEjRjAQnmn80JNuGnncEHkZp4/YDwjR8/3syA3rlzZ8nMzDTrChYsKL169ZJx48aJHQQ7QBIEa74KVnPjv62dkycnXCANpOlEoL4KFSokkyZNMjOcb9682azTnljFihUTu2jGApIorwxOJDOlR4ImLcChXNCM5aHBTZkyZcwSTaCjCHaAJAsU0PiPuuxbzxOLDA1ZHgCpKjs7Wx5//HEzgGC1atXMcsYZZ8ioUaPMdXbQjAUkWaheVb7d0glQALhhBOWhQ4ea0ZO1PqdFixZm3dKlS2XEiBFy4sQJGT16dMT7JLMDJIiduptQvXhoigLcxw0jKL/22msyffp0U5DcoEEDs/z97383Y+/MmDHD1j4JdoAEsZuZCRXUEPAASDf79u2TOnXq5Fqv6/Q6Owh2gBRpsgp2XbAiZZq1ABdyQYFyw4YNZfLkybnW6zq9LiE1O126dDGD/bRq1crWHQJuFixAyWsG87xGUibwAZAunnrqKWnfvr18/vnn0qxZM7Nu+fLlZnDBefPm2dpnxJmdgwcPStu2beXcc8+VMWPGyPbt223dMYDQggUwsRhzB4AzaXlxVDU7kvpat24tGzdulJtvvlkOHDhglo4dO8qGDRvk8ssvT0xm54MPPpA9e/bIzJkzTRHR8OHDTfCj2Z4OHTqYUQ4BxFaw7I1/E5hvd3UAcKoqVarY6nUVTIZlWVG14K1evVpeffVVUzldokQJufvuu03VtGZ+nOrQoUOmf/8V0kEKZBC8ITUQxACpKdM6LYvkQ9PyoZNYxvO8VG3caMlXpIjt/WSfOCG/Dhoa18dqx3fffRf2tto7K6Hj7OzcuVMWLFhglvz588v1118v69atk7p165o2t/79+0eze8CVgUSwubFS5fEBSKI0nS6iUaNGZj6svPIvuk1WVlb8g53Tp0/Lv/71L5PN+eyzz0yE1a9fP7nzzju9UeL7778v3bp1I9iBY6RCIOEbcPn/DgDpbMuWLXHdf8TBTuXKlc1wzTrN+sqVK0005q9NmzZmaGcA4Qs0+zkAuCGzc/PNN8sXX3xh5sHSqSIeeuihqOfDiqo31rPPPis7duyQKVOmBAx0lAY68Y7SALfNlQUA6TqC8vr16+Xo0aPm95EjR8qRI0eSm9m55557YvoAAIQf/ISaIR0AnKpRo0bStWtXadmypanbGT9+vOn0FMiwYcMi3j8TgQIpKFCXcs9P/xnRAbhImjZjzZgxwwxl8/HHH5si5E8++UQKFMgdouh1BDtAmgk2tg7NWoBLpWmwc/7558usWbPM7/ny5TP1OxUqVIjZ/pkbC0hxwep3yOoASEfZ2dlhBTo6pYQOgRMOmrGAFBdozB0yO4A7RVtknJGimR07lixZIsePHw9rWzI7gEM5PeBx+uMHksLKiH5xITI7gMOkU2FyOj0XICHStGYn3sjsAA4ccBAAED6CHcAhQk0foeuc1CyU13Nw0nMBEildBxWMN5qxAIcIFgAEmjg01flnp+hhBoSJZixbyOwADhFo5vN0GFE5UKDjtOANQOINGTJEypYtG9a2BDtAmgVAqc4/iAkWxDnteQEJEW0TluWM12nmzJnSokULqVKlivz6669m3cSJE+XDDz/0bjN48OCwJx2nGQtwGCcEAdFmZZzwHIGkcEEz1osvvmimhOjXr5+MHj1asrKyzHoNbDTg6dChQ8T7JLMDpAn/4t5kNgN5sjW+i+/6eKDZC0gPzz//vEybNk2GDh0q+fPn965v0qSJrFu3ztY+yewAacI3oPD9mSri/XhS7fkCceGCzM6WLVvkoosuyrW+cOHCcvToUVv7JLMDAIBDuKHreY0aNWTt2rW51s+fP18uuOACW/skswMAAFLGgAEDpHfv3nLixAmxLEtWrlwpb731lowdO1amT59ua58EOwAAIGX06NFDihYtKo8++qgcO3ZM7rzzTtMra9KkSfLXv/7V1j4JdgAAcAoX1Oyou+66yywa7Bw5ckQqVKgg0aBmB0BE6PUEJI8banZ8FStWLOpAR5HZARARej0BiDXtfZWRkRHWtqtXr454/wQ7cCxG2QXgSg7LzoTjpptukngi2IFjhZpMkkAIQFpK05qd4cOHx3X/BDtIK74D6vnOBk7TCwA4yzfffCPr1683v9etW1caN25se18UKCOtimMDzQJOoBPbYxzr2wEInxsKlH/77Te5/PLL5dJLL5UHH3zQLJdccom0bNnSXGcHwQ4cJa/AJZLARk/OnKCjO4YcUyBJzVjRLA4YZ+f06dMmq7Nv3z6z6O/Z2dnmOscFO4cPHzazmlarVs0MINS8eXP5+uuvg26/c+dOM7jQeeedJ/ny5TO3DeSdd96ROnXqSJEiRaR+/foyb968OD4LJJvdgCXYpJQEQPb4T/oJAHYsXrzYzHx+/vnne9fp7zpB6JIlS5wX7GiEtmDBApk5c6aZybRdu3bStm1b2b59e8DtT548KeXLlzejKjZsGPgDddmyZXLHHXdI9+7dZc2aNabCW5fvv/8+zs8GiRAoEIl1cxUna/sIFIH4ckMzVtWqVU1mx19WVpYZSdlRwc7x48dlzpw58tRTT0mrVq2kdu3aMmLECPNTI7pAqlevboaL7ty5s5QuXTrgNnr9tddeKw8//LCZMGzUqFFy8cUXy+TJk+P8jJAovs1PnFxTB4XgQPo2Y02ZMsWcg7XFpGnTpma+qnDMmjXLjJ8TSdfyp59+Wvr27WsKlD30d63dGT9+vLOCnczMTBOl6YHzpc1ZS5cutb3f5cuXm+yQr2uuucasD0YzRocOHcqxILVPpuFmcwiGEoeMGJCeZs+ebSbn1O7hOqCftqzoeXX37t0hb/fLL7/IQw89ZIqN81KmTBkpW7asWbp27WpmPdegqnDhwmbR3/W+u3Xr5qyu5yVLlpRmzZqZzItmYCpWrGhmNdWgRLM7du3atcvsy5de1vXB6EyqI0eOtH2fiC/fgCXS7AEnYABpJQnj7EyYMEF69uxpghA1depUmTt3rrzyyisyaNCggLfRZIbObaXn1n//+99y4MCBkPcxceJESdtxdrRWR6O0s846S/Lnz2+am7TeZtWqVQl9HIMHDzZRq4dmdrTNEKmBgAUA/hRt3U3G/27r34LhyaD4O3XqlDkn63nSQzsIaQtKqBaTxx9/3MxppfWzGuzkpUuXLpK2wU6tWrVM1fXRo0fNga9cubJ06tRJatasaXuflSpVkt9//z3HOr2s64MJ9iIDAJCOmZ2qfl/otYlK62b97d2712RpArWY/PjjjwHvQktRXn75ZdMUFQ1tJtNFu5z7atCggTNHUC5evLhZ9u/fL59++qkpWrZLm8a++OKLHN3StceXrgcAACLbtm2TUqVKeQ9FrL7w65Ay99xzj0ybNk3KlStnax+aSdJMj46tY1k5Izstdtbgy1HBjgY2+kS0//ymTZtMDyodH8fTLqhpM+2G/vrrr3tv44kUjxw5Inv27DGXCxUqZIaSVlqt3bp1a3nmmWekffv2phJcq7hfeumlJD1LpCt6HwFwamanVKlSOYKdYDRg0TKTcFtMNm/ebAqTb7jhBu86T2amQIECsmHDBtOqE4qWt+h4epod0gxSuLOhp2ywc/DgQRPQ6PDPWoF9yy23yOjRo6VgwYLeQQS3bt2aaxp43+jvzTffNIMS6sFVOjChrtOxeIYMGSLnnnuufPDBB3LhhRcm+NkhnRHoAHByzU64NJmgc1Jpi4mn+7gGL3q5T58+ubbXhIWOm+dLz8ea8dGhYcKph/3555/N0DTRdFZKqWDn9ttvN0swM2bMyLXOP6UVyG233WYWIF4omgbgFgMGDDDNSk2aNDHzVWnPKa219bTC6Nh32tFIezbrcDL+yYUzzjjD/Aw36XDVVVfJt99+mz7BDgAASO2u5506dTJlI8OGDTPDuDRq1Ejmz5/vLVrWFhjtoRUr06dPN8GVznygAZKntcfjxhtvjHifBDtI6Skg4Bw07QHp14zloU1WgZqt1KJFiySUQK00oWiX9q+++ko++eSTXNfZLVBm1nOkTKAT6zmukFi8bgBiQaeKuPvuu03drtYH+S52Ah1FZgcpk9FhagcASL1mrET7448/pH///rnG9okGmR0khSewIRsAAKk/EWgidezYURYuXBjTfZLZQdLnuvKV7OAnVN0JNSkAEH86xo4OS6MjMdevXz9XgfIDDzwQ8T4JdpAyUjnQSYXHBwA6vF40Q+xlOOAQam+sEiVKmOmkdPEvUCbYQcqLZ11OtJkXghkAKc8FNTtbtmyJ+T6p2UHCBGuy8g0y7ARDoZrFACAdu55HsziFzriu00tkZmZGvS+CHSRFsG7mnssatIQTuHi2CdWzy7OvcPcZaB8AgMQ4duyYdO/eXYoVKyb16tXzThulXdLHjRtna58EO0jaeDq+QgU9du7Ld3/6u3/2KJz90qwFIOW4oDfW4MGDzXQROlihTj/h0bZtW5k9e7atfRLsIO5inU0Jls3JK0gJFPRE+1gAIOHSONBROnn35MmTpWXLljlmPNcsj86qbge9sRBXkXYtD3S975g8wfYX6bg94WxHZgcAEk/n4apQoUKu9Tr5qG/wEwkyO4ibaDIjgW4bqBDZv0kq0OVA+4u0fgcAUoEbCpSbNGkic+fO9V72BDjaJb1Zs2a29klmByk3uWeo20ZaaxOoEDqaeiAglhioEhFzQdfzMWPGyHXXXSc//PCD6Yk1adIk8/uyZctyjbsTLjI7SIhYNQl56m5862/89x1uz6toHhOBEmKBplIgN63VWbt2rQl0dATlzz77zDRr6WzojRs3FjvI7CDlP8zDHdU42vF6YvWYADhXqmfbom2KynBAZkfVqlVLpk2bFrP9kdlBzPjXx9j5wAhWqxOLXlpkY5BKeD+mplQOdNzS9Xz16tWybt067+UPP/xQbrrpJhkyZIgZaNAOgh2kTKATSiS9uPybucLdB5BIvB+BwP72t7/Jxo0bze8///yzdOrUyQww+M4778jAgQPFDoIdRC1VmoxilUlKxj4AIBxu6I21ceNGadSokfldA5zWrVvLm2++KTNmzJA5c+bY2ic1O0jZb6uJ+uYbTht9qG34hg4gYVzQG8uyLMnOzja/f/755/KXv/zF/F61alXZu3evrX2S2UHCBgwMR7AeVqmeNYr3bO5AovB+S3EuqNlp0qSJPPHEEzJz5kzT1bx9+/be2dArVqxoa58EO0iZQCfQfhMh1KjN0ewjVsgcIZF4vyHZJk6caIqU+/TpI0OHDpXatWub9e+++640b97c1j5pxoKrA51g+MAHkIrc0PW8QYMGOXpjeTz99NOSP39+W/sk2EFE4tXbKhb7TPXxMQAgai6o2fHQbua7d+/21u94nHPOORIpgh2kRKATC6n6uAAAkfXG6t69u5kewr9wWefJysrKkkgR7CAiBBQAkDwZesK37KdnMqK4baJ07dpVChQoIB9//LFUrlzZ9kznvgh24Lh6mkTyNI3RRIZ0wXvZ4VzQjLV27VpZtWqV1KlTJ2b7pDcW8uTWQCcZXeGBeOO9jFRXt25d2+PpBEOwg7DxIekMbg5OgXTnhhGUn3zySTMtxKJFi+SPP/6QQ4cO5VjsoBkLefI048AZCEpTD01HiBkXNGO1bdvW/Lzyyitz1OtQoIy4976K5wmUEwEAwGPhwoUSazRjIelZAjIR8UVWLrk4/oglNzRjtW7dWvLlyyfTpk2TQYMGmRGUdd3WrVttDypIsIOENl/p/jwLEoNgMrlS/fjzt+gwLpgba86cOXLNNddI0aJFZc2aNXLy5Emz/uDBgzJmzBhb+yTYQcI+qBPVLAZOYEC6ckNm54knnpCpU6eazE7BggW961u0aGHmzLKDYAeIg0Rnr+I1XxliI1VfD+rlkIo2bNggrVq1yrW+dOnScuDAAVv7pDcWxO0f+PF8rpxMAMSUC3pjVapUSTZt2iTVq1fPsX7p0qVSs2ZNW/skswPX8GQ/Epl1CRTgxeO+PfVV1F8g0vcNnCedm7BUz5495cEHH5T//Oc/puv5jh075J///Kc89NBD0qtXL7GDzA5cMWFoKk374Fv4nezHkiyp8DqkKo4N3G7QoEFmpvOrrrpKjh07Zpq0ChcubIKdvn372tonmR3EVKIzC77355/ZCPRY/HuYJSsb4inSjmXvNCcFD056rInGsUFIOpFntEuK02zO0KFDZd++ffL999/LihUrZM+ePTJq1Cjb+ySzg7T7Jhwo4PHPpvgHF8nI/IR7X6nyTT9VHgfgZtE2R2WkfqzjVahQITNPViyQ2YHj+GdD7AQM/rfxDYBSrfYlkgAjWNCX6McBe1LpfQekEzI7iJlA2ZJYniSDnQiCrQ/UZOX56f+YfLdL1Endzv3klV1JxvNA7DJiqVJXhhTmgt5Y8UBmBynxbTXUNv6ZFs+JIK8TQl77DLaPVP12Heok6J/pivRkmegxgVL1GMdDpK8FgQ5CyciOfnEjgh0XiuWJJtwCW7sBTzgBiy//pio7J45ogqh4CvW47DZfeV67RJ5gGUEbQKLRjOVC0Z7Y7J7sQxUIR7LvcAMgO/sKVMjs/9Nzu2iOYywDDN99RbJPt3d/jyeaohA3NGPZQmYHMcm02DnJJlq4hcy+24YKIqIJzGId6AR7rfwX3/WxfBygXgqJ4Ya5seKBYAcB+Z4Y/dcFmxYh3kL1pgqHneadaMfBicfM8R7+dUy+r0WwbI9nPUFO7MW7EB9wyzg78UCwg4D8T5DRNDvFSqRNVHnxDQbyOlEFClpC9ehKRu1UXpkp/+dJwBN7sfg74XWJD4JId6NmBxHV18QzU5FogQKEYM873Ca9QMcq2Mkr1ie1UE1aSIxEvdaIXLq8Bm4aVDCWyOwgJP9MQTqfSCN9bqnSa8u3aYrC2MRL578JpHCBcjSLC5HZcblwP6jD3S4WQVFe2Ylom49i9TjyatbybBPrACRUpi1dvr06id1jTmAKJA6ZHZeLplg11Mk9mscSSaDje7tYCtRjKZxxbiIZb8hOjU9eYwvBOXjdYAe9sewh2EHU4+bESl6BUjhFxMEKcIMFSeE+Ls9P30Jf3yAo3K7d/nVB0eBkCbgQvbFsIdiBY3rphJs1CpRlCdbkFElWKFTWKVhQ499UEW6X/rweR6q+RgCQigh2XCxQAJAKJ9Fwp0XIax/Bnk+kWZ68rssrAApUUxNJcEkBbHJx/JFKaMayh2DHxWJRcxOv4ChQtslut+pABc3hNpeFUwDs3zQV6HGHejzhYMTj5EnkFwACK+SJ3li20BsLUX3QxuPDOVRwEU0xtZ2eZ+H2mInnCTEVsm0A4GQEO2nAdzC5YNmaQFMGRNNryn//dveTiO63wbpqB+ptFWqgwEDPOx69wALdVzzvE6mDsZKQFwYVtIdgJw3k1TU6WACU1z7jOUVEON25Y8m/x5SvvEaIDnYs4hXo+F4msHEfXnOElG39udiV7c5RBanZcbhY1LDY3W+8PpSTWbcQKhiKZgyhSO431Ld7ToTOmn8tVlLpsSDJqNmxhcyOwyXz5BfNB3Ai54zyb6YKtf9QPaticcIJpwkxr+sIeOInUHF6KhzvVHgMgJMlPbNz+PBh6devn1SrVk2KFi0qzZs3l6+//jrkbRYtWiQXX3yxFC5cWGrXri0zZszIcf2IESMkIyMjx1KnTh1xi3BH8Q3VPdtfqCxDpGP0JPODO9yBCUPVJUWS6fHfJpwTaKjXxKnBrZPuM97H243HEbGTEW33c3GnpAc7PXr0kAULFsjMmTNl3bp10q5dO2nbtq1s37494PZbtmyR9u3bS5s2bWTt2rUmUNJ9fPrppzm2q1evnuzcudO7LF26VNwg1Ik0nJqVSIqQw+mSHexxOEGoYND3OEcS9AQaVDAvdm8X7uPxf2ypItiAjP6/O02yAlYnHzP4YARl5wU7x48flzlz5shTTz0lrVq1MlkazcrozxdffDHgbaZOnSo1atSQZ555Ri644ALp06eP3HrrrfLss8/m2K5AgQJSqVIl71KuXDlJJ+GM5BssA+F7Ag+nCDmv0YZ9M0WeE1SgbI/veiem5f2fV16FzbE6ufi/VrEITAKNBRSop1o4on3e4byXAz3mRHJCoBDPDgWA0yU12MnMzJSsrCwpUqRIjvXanBUsE7N8+XKT+fF1zTXXmPW+fvrpJ6lSpYrUrFlT7rrrLtm6daukk3C7fwfLyIR7wgxnZOFwRgDO60SV6h/IvgFHqExPNFmSvLqb53W8/TNA4fS482zrez+hHkMwvvcXaSDihMDXCY8xVJbWP5iFcyVrBOUpU6ZI9erVzfm6adOmsnLlyqDbTps2TS6//HIpU6aMWfScHWr7tA92SpYsKc2aNZNRo0bJjh07TODzxhtvmMBFm54C2bVrl1SsWDHHOr186NAhkylS+kJoHc/8+fNNhkibvvTAa31QICdPnjS3912cJliX6UDfjsNZF2yf/tv7d+m224PIKScTj7zqeuwIpwdWqBNWqIAo3OxJsG3DqTGK5DW0e6xi1eSWbid9/ya+SF5vOEwSemPNnj1bBgwYIMOHD5fVq1dLw4YNTZJh9+7dQetq77jjDlm4cKE5n1etWtWUqAQrT0mEDMvSBsDk2bx5s3Tr1k2WLFki+fPnN4XH5513nqxatUrWr1+fa3u9rmvXrjJ48GDvunnz5pk6nmPHjpmskL8DBw6YAugJEyZI9+7dc12vTWcjR47Mtf4K6SAFMgpKqgunx0iw+gf/k2cy6wmc+kEcyxNnOD3FnHqc4vVax2p/yfw7iPY5RPLYnfy3lqoyrdOySD6UgwcPSqlSpeJyH/olvHTp0tKyzQgpUCBna0gkMjNPyNKFIyJ6rJpAuOSSS2Ty5MnmcnZ2tglg+vbtK4MGDcrz9prI0AyP3r5z587iygLlWrVqyeLFi+XIkSOybds2k+o6ffq0aX4KROtvfv/99xzr9LK+aIECHXXGGWeYIGnTpk0Br9fASV94z6KPw0nf4MJJT/sHOv5ZgEBNGoHuM5zHZYeTP3ztZDbs3k86yKtezO7+8hLO30giXsdg9x1MtM3N0WyL1JNhWVEvyr81Q1s4Ajl16pRJPviWj+TLl89c9i8fCUYTEXpeL1u2rCRL0oMdj+LFi0vlypVl//79pmdVhw4dAm6nzV5ffPFFjnXam0vXB6OBlGaQdP+BaBd2DZZ8l1QUrB4jkm9qdr7VxasZKp2bEuzwbxIMtk26SPRzceqxI5BBDtkxWERMZkYzRZ5l7NixAQ/03r17TWYmUPmIlpWE45FHHjE1tP71tq4KdjSw0doaravRoEW7lOuYONpU5cm6+Ka97r//fvn5559l4MCB8uOPP8oLL7wgb7/9tvTv39+7zUMPPWSyRb/88ossW7ZMbr75ZtNEpm2ITharD+tg7fuhehvFg1NPPnmJJpgM1Z093YLDRHLDsUvXvyfEx7Zt23K0aPiWhsTSuHHjZNasWfL+++/n6ozkqhGUPQf5t99+MymuW265RUaPHi0FC/5ZK6OFyr49qbTb+dy5c01wM2nSJDn77LNl+vTppljKQ/elgc0ff/wh5cuXl5YtW8qKFSvM707l2/QUqBA5EuF04eWDM3Y9tsIp+A3Ubd+/mTKc14R6jNCvDeB0vk1Rdm+vwm3F0GFbNFkQqHxEy0pCGT9+vAl2Pv/8c2nQoIEkU9ILlFORpxAslQqUfU9iqXZCS7XHk4rCDVBDFZIDSE2JLFBu1XJY1AXKS5Y+HnGB8qWXXirPP/+8t0D5nHPOMePcBStQ1vHzNHGhrTeXXXaZJFvSm7EQmn+vqVQMLFLt8aQiu13BU2F8FP/u3m5oEsKfYtHNH84fQXnAgAFm7JzXXnvN9JLu1auXHD161FtuoqUmvs1gTz75pDz22GPyyiuvmLF5tLZHF62fdW0zFiJDYOFceY1pE84AjokWKLjmPegevNZQnTp1kj179siwYcNM0NKoUSNTa+spWtZSE+2h5aHj22kvLp3dwJeO06NDvSQDzVgOacZCekuljF00IynDfXhPJLYZq3Xzx6Juxlq8bFRcH2sqohkLSAGRBhDxbFpIxQwTUlesRxJHHpgI1BaCHYfhg8RdGPYfThMqKxgrfA4iUtTsOAzfrN0l1Ldm3gtwkkiGUAhnX26Vkf3nEs3t3YhgB3CQQNN+JAN1GrDDzUFKzNjsUeXl0tFmaMYCHCjZ3cA5aSHZaMpCJMjsAA4U68k0AadxbcCtiZlokjOWuBKZHcDh/Af9878u3vcNwHmznrsNwY7DcbJxN88Iy/6TuPpeH+/7D/Ye5L0JIFUQ7Dica1O5ccIJOnJMJotI/7b4O4sC4+zYQs0O4IPgEYj/3xZ/Z1HQVqhouo9b4kpkdoAUxbdfAP6o2bGHYAdIUenw7ZeAjeMMpAKasQDETToEbE7AcXZb1/NoBhUUVyLYAQDAKRhB2RaasQAAQFoj2AEQF9TrAHGQHYPFhQh2EogPf7gJdST8zSP26I1lD8FOAvHhD7gLf/POEGy6FaQPgh0ASBBOqKnLMYEpIyjbQrADIGncdvJ3zAnVZRz1uhDs2EKwAyBpHHWSAeBYBDsAEAa3ZaGQosjs2MKgggAQBrJQSAnadTwjytu7EJkdIEJ8w3f368rrj2Si67k9BDuAjW/4nPCi43/8knk8PfcdbubGfzveC0DqI9gBbKBJI7bHL5kBRLSvJe8FJBQ1O7YQ7AB8O085iQwgyMzAUbKt6BcXItgB+HbuarEMrAI1zxFMJRbHG4HQGwsAEtQ8h/hL+2PuacaK5vYuRLADAIBjRBnsiDuDHZqxAABAWiPYQcRoEweS9/fB35/L0RvLFoIdAHBQzUja16REEPC5MvCjN5YtBDsRcOUfVgB82AJIhc8gPosQLgqUI8AfFgAgqazsP5dobu9CZHZsIMMDINU46XPJSY815VCzYwvBjg1keAAkk9ODBT5Do0DNji0EOwni9A8nAKkdLBBAAMER7CQIH0QAYsnJX6Cc/NiTjmYsWyhQBgAHcvIXKCc/9qTTAZCjmi5CXInMDgAgZhOckrVBKiLYAQCEDFg0E+O7Ti8Hy86QtYkzmrFsoRkLAJADBdApLFvHycmO8vbuQ2YHAACkNYIdAIAXNTcpjmYsWwh2ACDNRBOwUHOT4gh2bCHYAYA0Q8AC5ESBMgAATpouIprBcrLdOdAOwQ4AAA5hWdlmieb2bkSwAwCAk2p2osnOWO7M7FCzAwAA0hrBTgp23aTrJwAgIHpj2UKwEwf+Q6vbuT0AAAFHQI52cSGCnTgiQwMAQPJRoBwnZGcAADFnCowpUI4UwQ4AAA5hZWeLlUHX80jRjAXQ5AgAaY3MDkCzIwCnoBnLFoIdAACcQgcUzKBmJ1I0YwEAgLSW9GDn8OHD0q9fP6lWrZoULVpUmjdvLl9//XXI2yxatEguvvhiKVy4sNSuXVtmzJiRa5spU6ZI9erVpUiRItK0aVNZuXJlHJ8FAACJGlQwO4rFcuXLlPRgp0ePHrJgwQKZOXOmrFu3Ttq1aydt27aV7du3B9x+y5Yt0r59e2nTpo2sXbvWBEq6j08//dS7zezZs2XAgAEyfPhwWb16tTRs2FCuueYa2b17dwKfGQAAsWVlW1EvbpTUYOf48eMyZ84ceeqpp6RVq1YmSzNixAjz88UXXwx4m6lTp0qNGjXkmWeekQsuuED69Okjt956qzz77LPebSZMmCA9e/aUrl27St26dc1tihUrJq+88koCnx0AADEWVVYn+8/FhkhbS9555x2pU6eO2b5+/foyb948cW2wk5mZKVlZWeZg+NLmrKVLlwa8zfLly03mx5dmbXS9OnXqlKxatSrHNvny5TOXPdv4O3nypBw6dCjHAgBwxyj2jHYfWqStJcuWLZM77rhDunfvLmvWrJGbbrrJLN9//724MtgpWbKkNGvWTEaNGiU7duwwgc8bb7xhgpKdO3cGvM2uXbukYsWKOdbpZQ1QNFO0d+9es59A2+htAxk7dqyULl3au1StWjWGzxIAEEvhBie+I9mHuo2TRrxPRjPWhAhbSyZNmiTXXnutPPzww6YFRs/xWmc7efJkcW3NjtbqWJYlZ511lik4fu6550xEqNmYRBk8eLAcPHjQu2zbti1h9w0ACE6DFP9AxU5w4qSAJpWasU7ZaC3JqwXGlePs1KpVSxYvXixHjx412ZnKlStLp06dpGbNmgG3r1Spkvz+++851unlUqVKmeav/PnzmyXQNnrbQDTI0sVDgy+VKaejmoIEzvT+xnVy83n1k/0wAMf9TcT6b0f3d+jwn79nWqclVZlzhc+5I+73ZUX/WA/5lWv4nwc9QrWW/PjjjxG1wARrXXFFsONRvHhxs+zfv9/0rNKi5UC02cu/0El7c+l6VahQIWncuLF88cUXpo1QZWdnm8tazBxud3i1VJJbUIXkKHOe/v8zhx+I8G8i1n87f+7PI/X/JvXcoaUQ8aDnNv3CvnRX9OelEiVK5CrX0Hoc7SCUrpIe7Ghgo9Hw+eefL5s2bTJtfFrBrW2DniYm7Yb++uuvm8v333+/afcbOHCgdOvWTb788kt5++23Ze7cud59aiFVly5dpEmTJnLppZfKxIkTTebIs8+8VKlSxTRlaU1RRkZG0O00MtY3jG6rmSXEBsc1fji2HFunccJ7Vs9hGujouSNetCOPDr2izUqxeLwZfue2QFkdVa5cuYhbS4K1wATb3hXBjtbIaEDz22+/SdmyZeWWW26R0aNHS8GCBc31Wqi8detW7/ba7VwDm/79+5siqLPPPlumT59u2gM9tBlsz549MmzYMJM2a9SokcyfPz9XWi0YbY/U/YZL/wBT9Y/QyTiuHFsn4n3rzuMar4yOf8Dj33s53grZaC3Rlha9XsfBC9QCkwwZViIaGdP4G4e+wTVgS+U/QqfhuHJsnYj3Lcc1nbued+nSRf7xj394W0u0RUVrdjSJ0LlzZ9PJSHs2e7qet27dWsaNG2cGAZ41a5aMGTPGdFu/8MIL3ZnZAQAAqatTHq0l2vri24Nap31688035dFHH5UhQ4bIueeeKx988EHSAh1FsBMFbePUoq5gbZ3guKYa3rMcW6fhPZsa+vTpE7TZSuer9HfbbbeZJVXQjAUAANJa0gcVBAAAiCeCHQAAkNYIdgAAQFoj2AEAAGmNYOd/s55fcsklZsTkChUqmIGTNmzYEPLAnT59Wh5//HEzt5cO8qRT3mtXPF869LaOUum76OjQbvLiiy9KgwYNvAOC6aBSn3zyScjbvPPOO+Y46XGtX79+rulBdGgo7QKp86jpfGg64dxPP/0kbhOPY3vvvffmes/q7MVuEulx/e9//2sGQ61evbo5XjoGSSBTpkwx2+ixb9q0qaxcuVLcJh7Hls9ZhINgR8RMRNq7d29ZsWKFGeVRA5l27dqZKSaC0fEDdICl559/Xn744QczjcXNN98sa9asybFdvXr1zCjQnmXp0qXiJjoStQ4spbPmfvPNN3LllVdKhw4dzIdYIDoYlc563717d3MsNfDU5fvvv/duo/OmPffcczJ16lT5z3/+Y+ZU0xG0T5w4IW4Sj2OrNLjxfc++9dZb4iaRHtdjx46ZiYv1NsGGw9dB2XQaGx2qQgdW0y9H+p7dvXu3uEk8jq1y++cswqAjKCOn3bt366jS1uLFi4MemsqVK1uTJ0/Osa5jx47WXXfd5b08fPhwq2HDhhxeP2XKlLGmT58e8LjcfvvtVvv27XOsa9q0qfW3v/3N/J6dnW1VqlTJevrpp73XHzhwwCpcuLD11ltvuf5YR3NsVZcuXawOHTq4/jhG8p71Va1aNevZZ5/Ntf7SSy+1evfu7b2clZVlValSxRo7dqzrj3W0x5bPWYSDzE4AOv2D0rm6gjl58mSuOUq0ScX/G4U2r+jkcPrt5K677soxz5fbZGVlmWHDNWMWbI6U5cuXm2YpX/oNWNcrnQhPR/D03Uan7NBmAc82bhSLY+s7QJg25+rkvL169ZI//vhD3Cqc45oXnbhRMxm+x15Hm9XLvGejO7YefM4iL4yg7EcnONPJy1q0aBFyaGs9SUyYMEFatWpl6nZ00rP33nvPfDh66Al4xowZ5qShqdWRI0fK5ZdfbpoNtD7ILdatW2c+zLSZqUSJEvL+++9L3bp1A26rgYz/hK16Wdd7rvesC7aNm8Ty2HqasDp27Ggm3N28ebMZ6v26664zJ2Wd+dgtIjmuedm7d6/5XAh07HVuIbeJ5bFVfM4iHAQ7frR2R4ORvNp8dcb1nj17mmJPLZzTgKdr167yyiuveLfRk4SHFuXpH2W1atXMBGpaN+EWGuytXbvWZMzeffddM6Gc1klF8wGH+Bzbv/71r97ftYBZ37f63tZsz1VXXeWaw8571jnHls9ZhINmLB8678fHH38sCxcuNIV0oZQvX95MbKYp2F9//dV8Q9NvKdpcFcwZZ5wh5513nmzatEncpFChQlK7dm1p3Lix6fmmxZkaLAaiRYi///57jnV62VOc6PkZahs3ieWxDUTfz+XKleM9G+K45kWPn2bFeM9G/p61w62fswiNYOd/XZk10NF06pdffmlS+OHSuh2d2j4zM1PmzJljehYEc+TIEdM0oF2m3d5UqDVPgWh6W5sEfWkPOU+bvr42enL23ebQoUOmV1a07f5uP7aB/Pbbb6Zmh/ds8OMazsldT+y+x15fJ73Mezb0e9YOPmcRUFhlzGmuV69eVunSpa1FixZZO3fu9C7Hjh3zbnPPPfdYgwYN8l5esWKFNWfOHGvz5s3WkiVLrCuvvNKqUaOGtX//fu82//d//2f2uWXLFuurr76y2rZta5UrV8709nILPWbaq02PwXfffWcuZ2RkWJ999lnA46rHqUCBAtb48eOt9evXm54WBQsWtNatW+fdZty4cdYZZ5xhffjhh2af2ntIj/3x48ctN4n1sT18+LD10EMPWcuXLzf7/Pzzz62LL77YOvfcc60TJ05YbhHpcT158qS1Zs0as2gvTT2G+vtPP/3k3WbWrFmmx+CMGTOsH374wbrvvvvMe3jXrl2Wm8Tj2PI5i3AQ7OhBEAm4vPrqq94D1bp1a9Mt10ODmAsuuMB8gJ155pnmj3T79u05Dm6nTp3MH2ihQoWss846y1zetGmT5SbdunUzXUb1GJQvX9666qqrvB9sgY6revvtt63zzjvP3KZevXrW3Llzc1yv3c8fe+wxq2LFiub46z43bNhguU2sj60G9+3atTP70iBI992zZ0/XnZAjPa564g70+aHb+Xr++eetc845x+xXu6LrFya3icex5XMW4cjQ/wLnfAAAAJyPmh0AAJDWCHYAAEBaI9gBAABpjWAHAACkNYIdAACQ1gh2AABAWiPYAQAAaY1gBwCQ1pYsWSI33HCDVKlSxUzcrPMaRkqHpBs/fryZd6tw4cJmmqDRo0fH5fEi9pj1HACQ1nTCZp1wtFu3btKxY0db+3jwwQfls88+MwFP/fr1Zd++fWaBMzCCMgDANTSzo5M+33TTTd51OhHp0KFD5a233pIDBw7IhRdeKE8++aRcccUV5vr169dLgwYN5Pvvv5fzzz8/iY8edtGMBSCkPXv2mJnmx4wZ4123bNkyM5u3/yzqgBP16dNHli9fLrNmzZLvvvtObrvtNrn22mvlp59+Mtd/9NFHUrNmTfn444+lRo0aUr16denRoweZHQchswMgT/PmzTPfhDXI0W+2jRo1kg4dOsiECRM4enB0Zmfr1q0mkNGfWtPj0bZtW7n00ktNkH///ffLjBkzzPv+6aeflqysLOnfv7+UKVNGvvzyyyQ+G4SLmh0Aebr++uulZ8+ectddd0mTJk2kePHiMnbsWI4cHG/dunUmeNHCY1/atHXmmWea37Ozs83l119/3bvdyy+/LI0bN5YNGzbQtOUABDsAwqKFmVrL8M4778iqVatMjxTA6Y4cOSL58+c372n96atEiRLmZ+XKlaVAgQI5AqILLrjA/NSMEHU8qY9gB0BYNm/eLDt27DDfcn/55RfTIwVwuosuushkdnbv3i2XX355wG1atGghmZmZ5m+gVq1aZt3GjRvNz2rVqiX08cIeanYA5OnUqVOmfkFrFvRb7MSJE036v0KFChw9OCJ7s2nTJm9wo7Vmbdq0kbJly8o555wjd999t3z11VfyzDPPmOu1KF+L77UHVvv27U2Af8kll5hMj7739XLv3r2lVKlSpjs6Uh/BDoA8Pfzww/Luu+/Kt99+az7wW7duLaVLlza9U4BUt2jRIhPc+OvSpYspPD59+rQ88cQTpiZn+/btUq5cObnssstk5MiR3gymZjX79u1rghutWbvuuutMcKQBE1IfwQ6APE8UV199tSxcuFBatmxp1mkzlg7SNm7cOOnVqxdHEEBKI9gBAABpjUEFAQBAWiPYAQAAaY1gBwAApDWCHQAAkNYIdgAAQFoj2AEAAGmNYAcAAKQ1gh0AAJDWCHYAAEBaI9gBAABpjWAHAACkNYIdAAAg6ez/Aa7ImOpCRkGnAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.figure()\n", "computed_result[:, :].plot()\n", "plt.title(\"GFM Maximum Flood Extent\")\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Shutdown cluster\n", "\n", "After successful processing, we need to shutdown our cluster to free up\n", "resources. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Shutting down dask-gateway.5541687a59e04f27a7d23390720e8494\n" ] } ], "source": [ "# Connect to the gateway and shutdown the existing cluster if it exists\n", "cluster_list = gateway.list_clusters()\n", "if len(cluster_list) > 0:\n", " gateway.connect(cluster_list[0].name).shutdown()\n", " print(f\"Shutting down {cluster_list[0].name}\")\n", "else:\n", " print(\"No existing cluster found.\")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.11" } }, "nbformat": 4, "nbformat_minor": 2 }