Created
October 30, 2024 21:44
-
-
Save ThomasMGeo/fa9ad3728ccef91262a1f3294f95092e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Code Golf" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"netCDF_file = 'raster1.nc'" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 21, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"PyTorch: 2.5.1\n", | |
"Xarray: 2024.9.0\n", | |
"netCDF4: 1.7.1.post2\n" | |
] | |
} | |
], | |
"source": [ | |
"import numpy as np\n", | |
"import numpy\n", | |
"import netCDF4 as nc\n", | |
"import xarray\n", | |
"import torch\n", | |
"from torch.utils.data import Dataset, DataLoader\n", | |
"import matplotlib.pyplot as plt\n", | |
"import os\n", | |
"import shutil\n", | |
"import glob\n", | |
"import plotly.express as px\n", | |
"from typing import Dict, Generator, Union, List\n", | |
"import timeit\n", | |
"import xarray as xr\n", | |
"\n", | |
"print(\"PyTorch:\", torch.__version__)\n", | |
"print(\"Xarray:\", xarray.__version__)\n", | |
"print(\"netCDF4:\", nc.__version__)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 17, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# initialize directory of files\n", | |
"dir_ = \"ncfiles\"\n", | |
"kb = 1_024\n", | |
"mb = kb * kb" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 18, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"def get_datasets(dir_):\n", | |
" return {\n", | |
" 'basic': load_nc_dir(dir_), # Simple loader (equivalent to 'generator')\n", | |
" 'memory_mapped': load_nc_dir_memmap(dir_), # Memory mapped version (equivalent to 'map')\n", | |
" 'pt_cached': load_nc_dir_cached_to_pt(dir_), # PyTorch cached version (equivalent to 'tfrecord')\n", | |
" 'cache_disk': load_nc_dir_cache_to_disk(dir_), # Disk caching\n", | |
" 'cache_mem': load_nc_dir_cache_to_mem(dir_), # Memory caching\n", | |
" }\n", | |
"\n", | |
"\n", | |
"class NCDataset(Dataset):\n", | |
" def __init__(self, dir_: str):\n", | |
" self.dir = dir_\n", | |
" self.file_list = glob.glob(os.path.join(dir_, \"*.nc\"))\n", | |
" sample_ds = xarray.open_dataset(self.file_list[0], engine='netcdf4')\n", | |
" self.variable = list(sample_ds.variables.keys())[0]\n", | |
" self.shape = sample_ds[self.variable].shape\n", | |
" self.dtype = torch.from_numpy(sample_ds[self.variable].values).dtype\n", | |
" sample_ds.close()\n", | |
"\n", | |
" def __len__(self):\n", | |
" return len(self.file_list)\n", | |
"\n", | |
" def __getitem__(self, idx):\n", | |
" file = self.file_list[idx]\n", | |
" ds = xarray.open_dataset(file, engine='netcdf4')\n", | |
" result = torch.from_numpy(ds[self.variable].values)\n", | |
" ds.close()\n", | |
" return result\n", | |
"\n", | |
"\n", | |
"class CachedDataset(Dataset):\n", | |
" def __init__(self, original_dataset: Dataset, cache_dir: str = None):\n", | |
" self.cache_dir = cache_dir\n", | |
" self.cached_data = []\n", | |
" self.memory_cache = {}\n", | |
" \n", | |
" if cache_dir is not None:\n", | |
" os.makedirs(cache_dir, exist_ok=True)\n", | |
" \n", | |
" for idx in range(len(original_dataset)):\n", | |
" if cache_dir is not None:\n", | |
" cache_path = os.path.join(cache_dir, f\"cache_{idx}.pt\")\n", | |
" if not os.path.exists(cache_path):\n", | |
" data = original_dataset[idx]\n", | |
" torch.save(data, cache_path)\n", | |
" self.cached_data.append(cache_path)\n", | |
" else:\n", | |
" self.memory_cache[idx] = original_dataset[idx]\n", | |
"\n", | |
" def __len__(self):\n", | |
" return len(self.cached_data) if self.cache_dir else len(self.memory_cache)\n", | |
"\n", | |
" def __getitem__(self, idx):\n", | |
" if self.cache_dir:\n", | |
" return torch.load(self.cached_data[idx])\n", | |
" else:\n", | |
" return self.memory_cache[idx]\n", | |
"\n", | |
"\n", | |
"def load_nc_dir(dir_, batch_size=1, shuffle=False):\n", | |
" \"\"\"Basic loader without caching\"\"\"\n", | |
" dataset = NCDataset(dir_)\n", | |
" return DataLoader(dataset, batch_size=batch_size, shuffle=shuffle)\n", | |
"\n", | |
"\n", | |
"def load_nc_dir_cached_to_pt(dir_, cache_file=\"local.pt\"):\n", | |
" \"\"\"Save and load using PyTorch's native format\"\"\"\n", | |
" dataset = NCDataset(dir_)\n", | |
" tensors = [dataset[i] for i in range(len(dataset))]\n", | |
" stacked_tensor = torch.stack(tensors)\n", | |
" torch.save(stacked_tensor, cache_file)\n", | |
" cached_tensor = torch.load(cache_file, map_location=torch.device('cpu'))\n", | |
" return DataLoader(CachedDataset([cached_tensor[i] for i in range(len(cached_tensor))]))\n", | |
"\n", | |
"\n", | |
"def load_nc_dir_memmap(dir_, save_path=\"local_memmap.pt\"):\n", | |
" \"\"\"Load using memory mapping\"\"\"\n", | |
" dataset = NCDataset(dir_)\n", | |
" tensors = [dataset[i] for i in range(len(dataset))]\n", | |
" stacked_tensor = torch.stack(tensors)\n", | |
" torch.save(stacked_tensor, save_path)\n", | |
" return DataLoader(MemoryMappedDataset(save_path))\n", | |
"\n", | |
"\n", | |
"def load_nc_dir_cache_to_disk(dir_, batch_size=1, shuffle=False):\n", | |
" \"\"\"Cache to disk\"\"\"\n", | |
" dataset = NCDataset(dir_)\n", | |
" cache_dir = os.path.join(dir_, \".cache\")\n", | |
" cached_dataset = CachedDataset(dataset, cache_dir=cache_dir)\n", | |
" return DataLoader(cached_dataset, batch_size=batch_size, shuffle=shuffle)\n", | |
"\n", | |
"\n", | |
"def load_nc_dir_cache_to_mem(dir_, batch_size=1, shuffle=False):\n", | |
" \"\"\"Cache to memory\"\"\"\n", | |
" dataset = NCDataset(dir_)\n", | |
" cached_dataset = CachedDataset(dataset, cache_dir=None)\n", | |
" return DataLoader(cached_dataset, batch_size=batch_size, shuffle=shuffle)\n", | |
"\n", | |
"\n", | |
"class MemoryMappedDataset(Dataset):\n", | |
" def __init__(self, filename: str):\n", | |
" self.tensor = torch.load(filename, map_location=torch.device('cpu'))\n", | |
" \n", | |
" def __len__(self):\n", | |
" return len(self.tensor)\n", | |
" \n", | |
" def __getitem__(self, idx):\n", | |
" return self.tensor[idx]" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Creating 64KB files...\n", | |
"Creating 256KB files...\n", | |
"Creating 1024KB files...\n", | |
"Creating 4096KB files...\n", | |
"Creating 16384KB files...\n", | |
"Creating 65536KB files...\n", | |
"Creating 262144KB files...\n", | |
"Creating 524288KB files...\n", | |
"Creating 1048576KB files...\n", | |
"Testing 64KB files...\n" | |
] | |
}, | |
{ | |
"name": "stderr", | |
"output_type": "stream", | |
"text": [ | |
"/var/folders/y6/r_9cqvrn4sx89g8rhgfqvrr40000gp/T/ipykernel_69263/3259067426.py:103: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n", | |
" self.tensor = torch.load(filename, map_location=torch.device('cpu'))\n", | |
"/var/folders/y6/r_9cqvrn4sx89g8rhgfqvrr40000gp/T/ipykernel_69263/3259067426.py:73: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n", | |
" cached_tensor = torch.load(cache_file, map_location=torch.device('cpu'))\n", | |
"/var/folders/y6/r_9cqvrn4sx89g8rhgfqvrr40000gp/T/ipykernel_69263/3259067426.py:56: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n", | |
" return torch.load(self.cached_data[idx])\n" | |
] | |
}, | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"Testing 256KB files...\n", | |
"Testing 1024KB files...\n", | |
"Testing 4096KB files...\n", | |
"Testing 16384KB files...\n", | |
"Testing 65536KB files...\n", | |
"Testing 262144KB files...\n", | |
"Testing 524288KB files...\n", | |
"Testing 1048576KB files...\n" | |
] | |
} | |
], | |
"source": [ | |
"def show_timings(dir_):\n", | |
" datasets = get_datasets(dir_)\n", | |
" return {\n", | |
" key: timeit.timeit(lambda: list(datasets[key]), number=2) \n", | |
" for key in datasets\n", | |
" }\n", | |
"\n", | |
"def create_sample_nc_file(filepath, size_kb):\n", | |
" # Calculate array size to approximately match desired file size\n", | |
" # Assuming float32 (4 bytes per value)\n", | |
" array_size = int((size_kb * 1024) / 4)\n", | |
" dim_size = int(np.sqrt(array_size)) # Make it roughly square\n", | |
" \n", | |
" # Create sample data\n", | |
" data = np.random.rand(dim_size, dim_size).astype(np.float32)\n", | |
" \n", | |
" # Create xarray dataset\n", | |
" ds = xr.Dataset({\n", | |
" 'data': (['x', 'y'], data)\n", | |
" })\n", | |
" \n", | |
" # Save to netCDF file\n", | |
" ds.to_netcdf(filepath)\n", | |
"\n", | |
"def create_test_files(base_dir, kb_size, num_files=20):\n", | |
" \"\"\"Create a set of test NC files of specified size\"\"\"\n", | |
" dir_path = os.path.join(base_dir, str(kb_size))\n", | |
" os.makedirs(dir_path, exist_ok=True)\n", | |
" \n", | |
" for i in range(num_files):\n", | |
" filepath = os.path.join(dir_path, f'test_{i}.nc')\n", | |
" create_sample_nc_file(filepath, kb_size)\n", | |
" \n", | |
" return dir_path\n", | |
"\n", | |
"# Create test files for each size\n", | |
"base_dir = \"test_data\"\n", | |
"\n", | |
"kb_range = [\n", | |
" 64, # 64 KB - tiny files\n", | |
" 256, # 256 KB - small files\n", | |
" 1024, # 1 MB\n", | |
" 4096, # 4 MB\n", | |
" 16384, # 16 MB\n", | |
" 65536, # 64 MB\n", | |
" 262144, # 256 MB\n", | |
" 524288, # 512 MB (~0.5 GB)\n", | |
" 1048576 # 1 GB\n", | |
"]\n", | |
"\n", | |
"test_dirs = {}\n", | |
"\n", | |
"for kb in kb_range:\n", | |
" print(f\"Creating {kb}KB files...\")\n", | |
" test_dirs[kb] = create_test_files(base_dir, kb)\n", | |
"\n", | |
"# Now run the timing tests\n", | |
"timings = {}\n", | |
"for kb in kb_range:\n", | |
" print(f\"Testing {kb}KB files...\")\n", | |
" timings[kb] = show_timings(test_dirs[kb])\n", | |
"\n", | |
"# Create the plot\n", | |
"plt.figure(figsize=(12, 6))\n", | |
"\n", | |
"# Plot a line for each loading method\n", | |
"methods = ['basic', 'memory_mapped', 'pt_cached', 'cache_disk', 'cache_mem']\n", | |
"colors = ['#2196F3', '#4CAF50', '#F44336', '#FF9800', '#9C27B0']\n", | |
"\n", | |
"for method, color in zip(methods, colors):\n", | |
" times = [timings[kb][method] for kb in kb_range]\n", | |
" plt.plot(kb_range, times, marker='o', label=method.replace('_', ' ').title(), color=color, linewidth=2)\n", | |
"\n", | |
"# Customize the plot\n", | |
"plt.xlabel('File Size (KB)')\n", | |
"plt.ylabel('Loading Time (seconds)')\n", | |
"plt.title('Data Loading Performance Comparison')\n", | |
"plt.grid(True, linestyle='--', alpha=0.7)\n", | |
"plt.legend()\n", | |
"plt.xscale('log')\n", | |
"plt.grid(True, which='minor', linestyle=':', alpha=0.4)\n", | |
"plt.tight_layout()\n", | |
"plt.show()" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAAJOCAYAAABm7rQwAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8hTgPZAAAACXBIWXMAAA9hAAAPYQGoP6dpAACY20lEQVR4nOzdd3RU1drH8d+ZSQ8kofeSUBNKEAiKSu8golwroiBggXAVUAEvegUUUFREJGCjqahcUfAVEEQBUVBJkGooKkFAeksgkDIz5/0DM2RIAjOQTCB8P2tlLeaZPWc/+5w9w8mTfc4YpmmaAgAAAAAAALzIUtgJAAAAAAAA4PpDUQoAAAAAAABeR1EKAAAAAAAAXkdRCgAAAAAAAF5HUQoAAAAAAABeR1EKAAAAAAAAXkdRCgAAAAAAAF5HUQoAAAAAAABeR1EKAAAAAAAAXkdRCgCAyzB79mwZhuH8CQgIUPny5dWmTRtNmDBBhw8fvuxtJyYmavTo0dq9e3f+JSxp9+7dMgxDr732Wr5u93JVr15dffv2dT5etWqVDMPQqlWrvJ5LVt9ZP1arVeXKldPdd9+tbdu25Xt/zz33nKpWrSofHx+FhYXl+/avR5s3b9bDDz+s8PBwBQQEqFixYmrcuLEmTpyo48ePF3Z6Ba5v376qXr16YacBAIBHKEoBAHAFZs2apZ9++knLly9XXFycGjVqpFdeeUWRkZH69ttvL2ubiYmJGjNmTL4Xpa52jRs31k8//aTGjRsXWg7jx4/XTz/9pJUrV2rEiBFavny5brnlFv3999/51seXX36pcePG6aGHHtL3339/2fME57333ntq0qSJ4uPj9cwzz2jp0qVasGCB7r77br399tvq379/YadY4J5//nktWLCgsNMAAMAjPoWdAAAA17L69euradOmzsf/+te/NHToUN16663q2bOnfv/9d5UrV64QM7x2hISE6KabbirUHGrVquXMoWXLlgoLC1P//v01e/ZsjRo16oq2febMGQUFBWnr1q2SpCeeeEJly5a94pyzb/t69NNPP2ngwIHq0KGDFi5cKH9/f+dzHTp00FNPPaWlS5cWYoYFK+vY16hRo7BTAQDAY6yUAgAgn1WtWlWvv/66Tp06pXfeeccZT0hI0H333afq1asrMDBQ1atX1/3336+//vrL2Wb27Nm6++67JUlt2rRxXk42e/ZsSdLy5cvVo0cPVa5cWQEBAapZs6Yee+wxHT16NN/y37Nnj3r37q2yZcvK399fkZGRev311+VwOFzajRkzRjfeeKNKliypkJAQNW7cWDNmzJBpmi7tMjMzNXz4cJUvX15BQUG69dZbtW7duhz95nb5Xt++fVWsWDH98ccf6tq1q4oVK6YqVaroqaeeUnp6usvr9+3bp7vuukvFixdXWFiYHnjgAcXHx7vsP09lFaiyH6N58+apefPmCg4OVrFixdSpUydt2LDB5XVZeW/ZskUdO3ZU8eLF1a5dO1WvXl3PPfecJKlcuXIyDEOjR4+WJDkcDk2cOFF169aVv7+/ypYtq4ceekj79u1z2Xbr1q1Vv359rV69WjfffLOCgoLUr18/5+WZr776ql555RXnPGvdurV27typzMxMjRw5UhUrVlRoaKjuvPPOHJeZzps3Tx07dlSFChUUGBioyMhIjRw5UqmpqbmOz53jkp6errFjxyoyMlIBAQEqVaqU2rRpo7Vr1zrbmKapadOmqVGjRgoMDFSJEiV01113adeuXZc8RuPHj5dhGHr33XddClJZ/Pz8dPvttzsfe7qff/rpJ918883O9+ysWbMkSYsXL1bjxo0VFBSkBg0a5Ch8jR49WoZhaMOGDerZs6dCQkIUGhqq3r1768iRI1e03y+cV1nPXXj53meffaYbb7xRoaGhCgoKUkREhPr16+fSxp33e/ZLfydNmqTw8HAVK1ZMzZs3188//3yxwwMAwEWxUgoAgALQtWtXWa1WrV692hnbvXu36tSpo/vuu08lS5bUgQMHNH36dMXExCgxMVGlS5dWt27dNH78eP3nP/9RXFyc81K2rFUQf/75p5o3b64BAwYoNDRUu3fv1qRJk3Trrbdqy5Yt8vX1vaK8jxw5optvvlkZGRl68cUXVb16dS1atEhPP/20/vzzT02bNs1lPI899piqVq0qSfr555/173//W3///bf++9//Ots98sgj+uCDD/T000+rQ4cO2rp1q3r27KlTp065lVNmZqZuv/129e/fX0899ZRWr16tF198UaGhoc5+UlNT1aZNGx0/flyvvPKKatasqaVLl+ree++9ov3xxx9/SJLKlCkj6VwB5LnnntPDDz+s5557ThkZGXr11VfVokULrVu3TlFRUc7XZmRk6Pbbb9djjz2mkSNHymazqUyZMoqLi9OMGTO0dOlShYaGqnLlypKkgQMH6t1339XgwYN12223affu3Xr++ee1atUq/frrrypdurRz2wcOHFDv3r01fPhwjR8/XhbL+b8zxsXFqWHDhoqLi9PJkyf11FNPqXv37rrxxhvl6+urmTNn6q+//tLTTz+tAQMG6P/+7/+cr/3999/VtWtXDRkyRMHBwdq+fbteeeUVrVu3TitWrPD4uNhsNnXp0kU//PCDhgwZorZt28pms+nnn3/Wnj17dPPNN0uSHnvsMc2ePVtPPPGEXnnlFR0/flxjx47VzTffrE2bNuW52tBut2vFihVq0qSJqlSp4tYx9WQ/Hzx4UA8//LCGDx+uypUr66233lK/fv20d+9ezZ8/X//5z38UGhqqsWPH6o477tCuXbtUsWJFl/7uvPNO3XPPPXr88cf122+/6fnnn1diYqJ++eUX5/vVk/2e27zKzU8//aR7771X9957r0aPHq2AgAD99ddfLtvz5P0unZtbdevW1eTJkyWdu2Swa9euSkpKUmhoqFv7HwAAFyYAAPDYrFmzTElmfHx8nm3KlStnRkZG5vm8zWYzT58+bQYHB5tvvvmmM/7ZZ5+ZksyVK1deNAeHw2FmZmaaf/31lynJ/PLLLy/aPikpyZRkvvrqq3m2GTlypCnJ/OWXX1ziAwcONA3DMHfs2JHr6+x2u5mZmWmOHTvWLFWqlOlwOEzTNM1t27aZksyhQ4e6tJ87d64pyezTp48ztnLlyhzj7tOnjynJ/N///ufy+q5du5p16tRxPo6LizMlmV9//bVLu8cee8yUZM6aNSvPMWfve968eWZmZqZ55swZc/Xq1WbNmjVNq9Vqbtq0ydyzZ4/p4+Nj/vvf/3Z57alTp8zy5cub99xzT468Z86cmaOvF154wZRkHjlyxBnL2k+DBg1yafvLL7+Yksz//Oc/zlirVq1MSeZ3333n0jbr+EZHR5t2u90Znzx5sinJvP32213aDxkyxJRkJicn57pPsubX999/b0oyN23alGN8lzouH3zwgSnJfO+993LtwzRN86effjIlma+//rpLfO/evWZgYKA5fPjwPF978OBBU5J533335dkmu8vZzwkJCc7YsWPHTKvVagYGBpp///23M75x40ZTkjllyhRnLOs45zX3P/roo1xzdGe/5zav+vTpY1arVs35+LXXXjMlmSdPnsxzf7j7fs+aWw0aNDBtNpuz3bp160xJ5ieffJJnHwAAXAyX7wEAUEDMCy5jO336tEaMGKGaNWvKx8dHPj4+KlasmFJTU93+hrfDhw/r8ccfV5UqVeTj4yNfX19Vq1ZNkvLlW+JWrFihqKgoNWvWzCXet29fmabpsspixYoVat++vUJDQ2W1WuXr66v//ve/OnbsmPOysJUrV0qSHnjgAZft3XPPPfLxcW/BtmEY6t69u0usYcOGLpfUff/99ypevLg6d+7s0u7+++93q48s9957r3x9fRUUFKSWLVvKbrdr/vz5atiwoZYtWyabzaaHHnpINpvN+RMQEKBWrVrl+q2B//rXv9zqN2s/Zf82Qklq1qyZIiMj9d1337nES5QoobZt2+a6ra5du7qsnIqMjJQkdevWzaVdVnzPnj3O2K5du9SrVy+VL1/eeUxbtWolKef8cue4fP311woICMhxyVh2ixYtkmEY6t27t8t+LV++vKKjo/P12xg93c8VKlRQkyZNnI9LliypsmXLqlGjRi4rorL2ZfaxZ8lr7mflInm23yX35lVMTIyzv//973+53qzfk/e7dG4OWa1W5+OGDRtKyn3cAAC4g8v3AAAoAKmpqTp27JgaNGjgjPXq1Uvfffednn/+ecXExCgkJESGYahr1646e/bsJbfpcDjUsWNH7d+/X88//7waNGig4OBgORwO3XTTTW5t41KOHTuW69fKZ/0CfuzYMUnSunXr1LFjR7Vu3VrvvfeeKleuLD8/Py1cuFDjxo1z5pLVvnz58i7b8/HxUalSpdzKKSgoSAEBAS4xf39/paWlueSd2yVent5k/pVXXlHbtm1ltVpVunRpl0vCDh06JOn8L/sXyl4Iyso7JCTErX6z9lOFChVyPFexYsUcv/Tn1i5LyZIlXR77+fldNJ61H0+fPq0WLVooICBAL730kmrXrq2goCDt3btXPXv2zDG/3DkuR44cUcWKFXPsm+wOHTok0zTzPFYRERF5vrZ06dIKCgpSUlJSnm2y83Q/X7jPpHP77VL7Mru85n5WLpez392ZVy1bttTChQs1ZcoUPfTQQ0pPT1e9evU0atQoZ7HW3fd7lgvfs1n38MqPzx4AwPWJohQAAAVg8eLFstvtat26tSQpOTlZixYt0gsvvKCRI0c626Wnp+v48eNubXPr1q3atGmTZs+erT59+jjjWfc9yg+lSpXSgQMHcsT3798vSc777Xz66afy9fXVokWLXAoTCxcuzLE96dy9eSpVquSM22y2HL/wXmneud08/eDBgx5tJyIiwuXbFLPLGvv8+fOdq9MuxjAMt/vN2k8HDhxw3mMqy/79+13uc+Tptt21YsUK7d+/X6tWrXKu0pGkkydPXvY2y5Qpox9//FEOhyPPwlTp0qVlGIZ++OGHXG9Unlssi9VqVbt27fT1119r3759OfbdhTzdz/khr7mflYun+92TY9+jRw/16NFD6enp+vnnnzVhwgT16tVL1atXV/Pmzd1+vwMAUFC4fA8AgHy2Z88ePf300woNDdVjjz0m6dwvkqZp5vgF+/3335fdbneJ5bX6IOuX0Qu3kf0b/q5Uu3btlJiYqF9//dUl/sEHH8gwDLVp08aZi4+Pj8ulPGfPntWHH37o8rqsotzcuXNd4v/73//yvEHz5WjVqpVOnTqlr7/+2iX+6aef5lsfnTp1ko+Pj/788081bdo015/LlXUp3kcffeQSj4+P17Zt25zfsFaQCmJ+denSRWlpaRf99sPbbrtNpmnq77//znWfZl9tmJtnn31WpmnqkUceUUZGRo7nMzMz9dVXX0kqnP2c19zPem94433t7++vVq1a6ZVXXpEk57dFuvt+BwCgoLBSCgCAK7B161bnPXAOHz6sH374QbNmzZLVatWCBQuc39oWEhKili1b6tVXX1Xp0qVVvXp1ff/995oxY4bCwsJctlm/fn1J0rvvvqvixYsrICBA4eHhqlu3rmrUqKGRI0fKNE2VLFlSX331lZYvX+5Rzlu2bNH8+fNzxGNiYjR06FB98MEH6tatm8aOHatq1app8eLFmjZtmgYOHKjatWtLOndvmUmTJqlXr1569NFHdezYMb322ms5frGOjIxU7969NXnyZPn6+qp9+/baunWrXnvtNbcvbXNHnz599MYbb6h379566aWXVLNmTX399ddatmyZpJyX1l2O6tWra+zYsRo1apR27dqlzp07q0SJEjp06JDWrVun4OBgjRkz5rK2XadOHT366KN66623ZLFY1KVLF+e3wlWpUkVDhw694vwv5eabb1aJEiX0+OOP64UXXpCvr6/mzp2rTZs2XfY277//fs2aNUuPP/64duzYoTZt2sjhcOiXX35RZGSk7rvvPt1yyy169NFH9fDDDyshIUEtW7ZUcHCwDhw4oB9//FENGjTQwIED8+yjefPmmj59ugYNGqQmTZpo4MCBqlevnjIzM7Vhwwa9++67ql+/vrp3714o+/mLL76Qj4+POnTo4Pz2vejoaN1zzz2SCma/S9J///tf7du3T+3atVPlypV18uRJvfnmmy73q3L3/Q4AQEGhKAUAwBV4+OGHJZ27p0xYWJgiIyM1YsQIDRgwwFmQyvLxxx/rySef1PDhw2Wz2XTLLbdo+fLlOW5AHR4ersmTJ+vNN99U69atZbfbNWvWLPXt21dfffWVnnzyST322GPy8fFR+/bt9e2336pq1apu5/zBBx/ogw8+yBHP6mPt2rV69tln9eyzzyolJUURERGaOHGihg0b5mzbtm1bzZw5U6+88oq6d++uSpUq6ZFHHlHZsmXVv39/l+3OmDFD5cqV0+zZszVlyhQ1atRIn3/+ue677z63c76U4OBgrVixQkOGDNHw4cNlGIY6duyoadOmqWvXrjkKf5fr2WefVVRUlN5880198sknSk9PV/ny5RUTE6PHH3/8irY9ffp01ahRQzNmzFBcXJxCQ0PVuXNnTZgwwe37b12JUqVKafHixXrqqafUu3dvBQcHq0ePHpo3b54aN258Wdv08fHRkiVLNGHCBH3yySeaPHmyihcvrujoaJeb0r/zzju66aab9M4772jatGlyOByqWLGibrnllhw34c7NI488ombNmumNN97QK6+8ooMHD8rX11e1a9dWr169NHjwYGdbb+/nL774QqNHj9b06dOdN4efPHmy8z5UBbHfJenGG29UQkKCRowYoSNHjigsLExNmzbVihUrVK9ePUnnLq905/0OAEBBMcwLvxoIAACgiBg/fryee+457dmz55L3GwLy0+jRozVmzBgdOXKEezMBAJAHVkoBAIAiYerUqZKkunXrKjMzUytWrNCUKVPUu3dvClIAAABXIYpSAACgSAgKCtIbb7yh3bt3Kz09XVWrVtWIESP03HPPFXZqAAAAyAWX7wEAAAAAAMDrrvyraAAAAAAAAAAPUZQCAAAAAACA11GUAgAAAAAAgNdxo/NLcDgc2r9/v4oXLy7DMAo7HQAAAAAAgKuaaZo6deqUKlasKIsl7/VQFKUuYf/+/apSpUphpwEAAAAAAHBN2bt3rypXrpzn8xSlLqF48eKSzu3IkJCQ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EhISXHJ86623VK1aNZmmmeeYb7vtNh07dkxr1qxxxmbPnq2OHTuqbNmyLm0/+ugjNW3aVMWLF1f58uXVq1cvHT58OEduixcvVnR0tAICAnTjjTdqy5YtLtsOCwvTwoULVbt2bQUEBKhDhw7au3evS19fffWVmjRpooCAAEVERGjMmDEuxbfff/9dLVu2VEBAgKKiorR8+fI8xwgAAAAAwLWCotR17OGHH3ZZOTRz5kz169cvR7vnnntOs2bN0vTp0/Xbb79p6NCh6t27t77//nuXdqNHj9bUqVO1du1a7d27V/fcc48mT56sjz/+WIsXL9by5cv11ltvOdsPHz5cn3/+uebMmaNff/1VNWvWVKdOnXT8+HGX7Q4fPlwTJkzQtm3bdPvtt6t9+/Y5VjzNmjVLffv2lWEYeY7Xz89PDzzwgMtrZ8+eneuYMzIy9OKLL2rTpk1auHChkpKS1Ldv3xztnnnmGb322muKj49X2bJldfvttyszM9P5/JkzZzRu3DjNmTNHa9asUUpKiu677z7n88uWLVPv3r31xBNPKDExUe+8845mz56tcePGSZIcDod69uwpq9Wqn3/+WW+//bZGjBiR5xgBAAAAALhWUJS6jj344IP68ccftXv3bv31119as2aNevfu7dImNTVVkyZN0syZM9WpUydFRESob9++6t27t9555x2Xti+99JJuueUW3XDDDerfv7++//57TZ8+XTfccINatGihu+66SytXrnRud/r06Xr11VfVpUsXRUVF6b333lNgYKBmzJjhst2xY8eqQ4cOqlGjhkqVKqUBAwbok08+UXp6uiRp06ZN2rhxox5++OFLjrl///763//+p9TUVK1evVrJycnq1q1bjnb9+vVTly5dFBERoZtuuklTpkzR119/rdOnT7u0e+GFF9ShQwc1aNBAc+bM0aFDh7Rgwfl7fGVmZmrq1Klq3ry5mjRpojlz5mjt2rVat26dJGncuHEaOXKk+vTpo4iICHXo0EEvvviic99+++232rZtmz788EM1atRILVu21Pjx4y85TgAAAAAArnbc6Pw6Vrp0aXXr1k1z5syRaZrq1q2bSpcu7dImMTFRaWlp6tChg0s8IyMjx2V+DRs2dP67XLlyCgoKUkREhEssqxjz559/KjMzU7fccovzeV9fXzVr1kzbtm1z2W7Tpk1dHt9xxx0aPHiwFixYoPvuu08zZ85UmzZtVL169UuOuWHDhqpVq5bmz5+vlStX6sEHH5Svr2+Odhs2bNDo0aO1ceNGHT9+XA6HQ5K0Z88eRUVFOds1b97c+e+SJUuqTp06Lvn7+Pi45F+3bl2FhYVp27ZtatasmdavX6/4+HjnyihJstvtSktL05kzZ7Rt2zZVrVpVlStXzrVPAAAAAACuVRSlrnP9+vXT4MGDJZ27ufuFsooxixcvVqVKlVye8/f3d3mcvbhjGEaOYo9hGM7tZd376cLL7UzTzBELDg52eezn56cHH3xQs2bNUs+ePfXxxx9r8uTJFx1ndv369VNcXJwSExOdRbLsUlNT1bFjR3Xs2FEfffSRypQpoz179qhTp07KyMi45PYvzD+3SwqzYg6HQ2PGjFHPnj1ztAkICMj1HlkXu0QRAAAAAIBrBZfvXec6d+6sjIwMZWRkqFOnTjmej4qKkr+/v/bs2aOaNWu6/FSpUuWy+61Zs6b8/Pz0448/OmOZmZlKSEhQZGTkJV8/YMAAffvtt5o2bZoyMzNzLerkpVevXtqyZYvq16/vsuopy/bt23X06FG9/PLLatGiherWretyk/Psfv75Z+e/T5w4oZ07d6pu3brOmM1mc7kp+44dO3Ty5Elnm8aNG2vHjh059m3NmjVlsVgUFRWlPXv2aP/+/c5t/PTTT26PFQAAAACAqxUrpa5zVqvVebmZ1WrN8Xzx4sX19NNPa+jQoXI4HLr11luVkpKitWvXqlixYurTp89l9RscHKyBAwfqmWeeUcmSJVW1alVNnDhRZ86cUf/+/S/5+sjISN10000aMWKE+vXrp8DAQLf7LlGihA4cOJDrZXuSVLVqVfn5+emtt97S448/rq1bt+rFF1/Mte3YsWNVqlQplStXTqNGjVLp0qV1xx13OJ/39fXVv//9b02ZMkW+vr4aPHiwbrrpJjVr1kyS9N///le33XabqlSporvvvlsWi0WbN2/Wli1b9NJLL6l9+/aqU6eOHnroIb3++utKSUnRqFGj3B4rAAAAAABXK1ZKQSEhIQoJCcnz+RdffFH//e9/NWHCBEVGRqpTp0766quvFB4efkX9vvzyy/rXv/6lBx98UI0bN9Yff/yhZcuWqUSJEm69vn///srIyMj12/MuJSwsLMdlgVnKlCmj2bNn67PPPlNUVJRefvllvfbaa3mO4cknn1STJk104MAB/d///Z/8/PyczwcFBWnEiBHq1auXmjdvrsDAQH366afO5zt16qRFixZp+fLliomJ0U033aRJkyapWrVqkiSLxaIFCxYoPT1dzZo104ABA1zuPwUAAAAAwLXKMHO7aQ2cUlJSFBoaquTk5ByFm7S0NCUlJSk8PFwBAQGFlOH1a9y4cfr000+1ZcsWr/e9atUqtWnTRidOnFBYWFiubWbPnq0hQ4bo5MmTXs2NeQkAAABcWyKmn750o3yya2Axr/XlFe946Z67j1E68cTFainZsVIK15zTp08rPj5eb731lp544onCTgcAAAAAAFwGilK45gwePFi33nqrWrVqdVmX7gEAAAAAgMJHUQrXnNmzZys9PV3z5s3L9ebs3tC6dWuZppnnpXuS1LdvX69fugcAAAAAwLWCohQAAAAAAAC8jqIUAAAAAAAAvI6iFAAAAAAAALyOohQAAAAAAAC8jqIUAAAAAAAAvI6iFAAAAAAAALyOohSuerNnz1ZYWFi+b3f37t0yDEMbN27M920DAAAAAICL8ynsBIqi1PY3erW/4G9/8ah93759NWfOHEmSj4+PqlSpop49e2rMmDEKDg7WqlWr1KZNG504ceKSxSDTNPXee+9pxowZ+u233+Tj46OaNWuqd+/eevTRRxUUFHS5wwIAAAAAAEUYK6WuU507d9aBAwe0a9cuvfTSS5o2bZqefvppj7fz4IMPasiQIerRo4dWrlypjRs36vnnn9eXX36pb775pgAyBwAAAAAARQFFqeuUv7+/ypcvrypVqqhXr1564IEHtHDhQu3evVtt2rSRJJUoUUKGYahv3765buN///uf5s6dq08++UT/+c9/FBMTo+rVq6tHjx5asWKFczvx8fHq0KGDSpcurdDQULVq1Uq//vqry7ZOnjypRx99VOXKlVNAQIDq16+vRYsWubRZtmyZIiMjVaxYMWdRLbtZs2YpMjJSAQEBqlu3rqZNm+by/Lp163TDDTcoICBATZs21YYNG65kFwIAAAAAgCvA5Xt5iIuLU1xcnOx2e2Gn4hWBgYHKzMxUlSpV9Pnnn+tf//qXduzYoZCQEAUGBub6mrlz56pOnTrq0aNHjucMw1BoaKgk6dSpU+rTp4+mTJkiSXr99dfVtWtX/f777ypevLgcDoe6dOmiU6dO6aOPPlKNGjWUmJgoq9Xq3N6ZM2f02muv6cMPP5TFYlHv3r319NNPa+7cuZKk9957Ty+88IKmTp2qG264QRs2bNAjjzyi4OBg9enTR6mpqbrtttvUtm1bffTRR0pKStKTTz6Z37sRAAAAAAC4iaJUHmJjYxUbG6uUlBRncaWoWrdunT7++GO1a9dOVqtVJUuWlCSVLVv2oveU+v3331WnTp1Lbr9t27Yuj9955x2VKFFC33//vW677TZ9++23WrdunbZt26batWtLkiIiIlxek5mZqbfffls1atSQJA0ePFhjx451Pv/iiy/q9ddfV8+ePSVJ4eHhSkxM1DvvvKM+ffpo7ty5stvtmjlzpoKCglSvXj3t27dPAwcOvPQOAgAAAAAA+Y6i1HVq0aJFKlasmGw2mzIzM9WjRw+99dZbHm3DNE0ZhnHJdocPH9Z///tfrVixQocOHZLdbteZM2e0Z88eSdLGjRtVuXJlZ0EqN0FBQc6ClCRVqFBBhw8fliQdOXJEe/fuVf/+/fXII48429hsNmdBcdu2bYqOjna58Xrz5s09Gi8AAAAAAMg/FKWuU23atNH06dPl6+urihUrytfX1+Nt1K5dW9u2bbtku759++rIkSOaPHmyqlWrJn9/fzVv3lwZGRmSlOflgdldmJ9hGDJNU5LkcDgknbuE78YbXb/5MOsSwKy2AAAAAADg6sCNzq9TwcHBqlmzpqpVq5aj4OPn5ydJl7yfVq9evbRz5059+eWXOZ4zTVPJycmSpB9++EFPPPGEunbtqnr16snf319Hjx51tm3YsKH27dunnTt3XtZYypUrp0qVKmnXrl2qWbOmy094eLgkKSoqSps2bdLZs2edr/v5558vqz8AAAAAAHDlKEohh2rVqskwDC1atEhHjhzR6dOnc213zz336N5779X999+vCRMmKCEhQX/99ZcWLVqk9u3ba+XKlZKkmjVr6sMPP9S2bdv0yy+/6IEHHnBZHdWqVSu1bNlS//rXv7R8+XIlJSXp66+/1tKlS93OefTo0ZowYYLefPNN7dy5U1u2bNGsWbM0adIkSecKaBaLRf3791diYqKWLFmi11577Qr2EgAAAAAAuBIUpZBDpUqVNGbMGI0cOVLlypXT4MGDc21nGIY+/vhjTZo0SQsWLFCrVq3UsGFDjR49Wj169FCnTp0kSTNnztSJEyd0ww036MEHH9QTTzyhsmXLumzr888/V0xMjO6//35FRUVp+PDhHn3z4YABA/T+++9r9uzZatCggVq1aqXZs2c7V0oVK1ZMX331lRITE3XDDTdo1KhReuWVVy5zDwEAAAAAgCtlmNxs56Kyvn0vOTlZISEhLs+lpaUpKSlJ4eHhCggIKKQMAVfMSwAAAODaEjE996tTCsKugcW81pdXvHPpL9/KF49ROvHExWop2bFSCgAAAAAAAF5HUQoAAAAAAABeR1EKAAAAAAAAXkdRCgAAAAAAAF5HUQoAAAAAAABeR1EKAAAAAAAAXkdRCgAAAAAAAF5HUQoAAAAAAABe51PYCQAAAAAAAFzNZtT90mt99d/ew2t9FTZWSqHAtG7dWkOGDCm0/mfPnq2wsLB8bwsAAAAAAK4cK6UKwjuGd/t7zPT4JQcPHtS4ceO0ePFi/f333ypbtqwaNWqkIUOGqF27dgWQZP4xjPP7NygoSBUrVtQtt9yif//732rSpInzuXvvvVddu3YtjBQBAAAAAMAlsFLqOrR79241adJEK1as0MSJE7VlyxYtXbpUbdq0UWxsbGGn55ZZs2bpwIED+u233xQXF6fTp0/rxhtv1AcffOBsExgYqLJlyxZilgAAAAAAIC8Upa5DgwYNkmEYWrdune666y7Vrl1b9erV07Bhw/Tzzz87202aNEkNGjRQcHCwqlSpokGDBun06dMu21qzZo1atWqloKAglShRQp06ddKJEyeczzscDg0fPlwlS5ZU+fLlNXr0aJfXJycn69FHH1XZsmUVEhKitm3batOmTZccQ1hYmMqXL6/q1aurY8eOmj9/vh544AENHjzY2f+Fl+Rt2rRJbdq0UfHixRUSEqImTZooISEh1+0fO3ZMzZo10+233660tLRL5gMAAAAAADxDUeo6c/z4cS1dulSxsbEKDg7O8Xz2Io7FYtGUKVO0detWzZkzRytWrNDw4cOdz2/cuFHt2rVTvXr19NNPP+nHH39U9+7dZbfbnW3mzJmj4OBg/fLLL5o4caLGjh2r5cuXS5JM01S3bt108OBBLVmyROvXr1fjxo3Vrl07HT9+3OOxDR06VKdOnXJu/0IPPPCAKleurPj4eK1fv14jR46Ur69vjnb79u1TixYtVLduXX3xxRcKCAjwOBcAAAAAAHBx3FPqOvPHH3/INE3VrVv3km2z36Q8PDxcL774ogYOHKhp06ZJkiZOnKimTZs6H0tSvXr1XLbRsGFDvfDCC5KkWrVqaerUqfruu+/UoUMHrVy5Ulu2bNHhw4fl7+8vSXrttde0cOFCzZ8/X48++qhHY8sa0+7du3N9fs+ePXrmmWec7WrVqpWjzc6dO9WhQwf16NFDb775psv9qwAAAAAAQP5hpdR1xjTP3RTdnWLLypUr1aFDB1WqVEnFixfXQw89pGPHjik1NVXS+ZVSF9OwYUOXxxUqVNDhw4clSevXr9fp06dVqlQpFStWzPmTlJSkP//8M9/HNmzYMA0YMEDt27fXyy+/nKOPs2fP6tZbb9Udd9yhKVOmUJACAAAAAKAAUZS6ztSqVUuGYWjbtm0XbffXX3+pa9euql+/vj7//HOtX79ecXFxkqTMzExJ524kfikXXh5nGIYcDoekc/ebqlChgjZu3Ojys2PHDj3zzDMejy1rTOHh4bk+P3r0aP3222/q1q2bVqxYoaioKC1YsMD5vL+/v9q3b6/Fixdr3759HvcPAAAAAADcR1HqOlOyZEl16tRJcXFxzhVP2Z08eVKSlJCQIJvNptdff1033XSTateurf3797u0bdiwob777rvLzqVx48Y6ePCgfHx8VLNmTZef0qVLe7y9yZMnKyQkRO3bt8+zTe3atTV06FB988036tmzp2bNmuV8zmKx6MMPP1STJk3Utm3bHOMFAAAAAAD5h6LUdWjatGmy2+1q1qyZPv/8c/3+++/atm2bpkyZoubNm0uSatSoIZvNprfeeku7du3Shx9+qLfffttlO88++6zi4+M1aNAgbd68Wdu3b9f06dN19OhRt/Jo3769mjdvrjvuuEPLli3T7t27tXbtWj333HN5fitelpMnT+rgwYP666+/tHz5ct111136+OOPNX36dJebtWc5e/asBg8erFWrVumvv/7SmjVrFB8fr8jISJd2VqtVc+fOVXR0tNq2bauDBw+6NRYAAAAAAOAZilLXofDwcP36669q06aNnnrqKdWvX18dOnTQd999p+nTp0uSGjVqpEmTJumVV15R/fr1NXfuXE2YMMFlO7Vr19Y333yjTZs2qVmzZmrevLm+/PJL+fi4d/98wzC0ZMkStWzZUv369VPt2rV13333affu3SpXrtxFX/vwww+rQoUKqlu3rgYOHKhixYpp3bp16tWrV67trVarjh07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EEIIpVIpli1bJuzs7IRcLhdPP/20iI+Pr/H9AERqaqrGY3JSihpK5UmpmvJXCCEWLVok2rVrJwwNDUWXLl3El19+KZRKpUqboqIi8c477whbW1thbm4uRo0aJS5duqSLU6JmKCcnR8yfP184OzsLY2Nj0alTJ/Hhhx+qfEEKDg7WOK4uW7ZMalNT7la1D/7tl7RVU40ghBBbtmwRTzzxhDA2NhZ9+/YVBw4ckLbdunVL+Pr6CltbW2FoaCicnJzEiy++KK5cuaJynOjoaOHt7S1at24tzM3NhZubmzhy5EiN/eKkFAkhxOTJk4W9vb0wNDQUDg4Owt/fXyQkJAghHtacml7h4eFV7rPypJS24+mxY8fE0KFDhaWlpbC2thZeXl7izJkzKm127dolXF1dhampqWjbtq0YP368SExMrLfPg+qPTAje6YuIiIiIiIiIiHSLF7wTEREREREREZHOcVKKiIiIiIiIiIh0jpNSRERERERERESkc5yUIiIiIiIiIiIineOkFBERERERERER6RwnpYiIiIiIiIiISOc4KUVERERERERERDrHSSkiIiIiIiIiItI5TkoRERERaWHEiBFYsGCB9HPHjh2xdu3aBj3m999/DysrqwY9BgB89NFHmD17dr3vt7CwEM7OzoiJian3fRMREVHTx0kpIiIiogdmzJgBmUym9kpOTsa+ffvwySef1OvxwsPD4enpidatW6NVq1bo0qULAgICUFJSAgCYPHkykpKS6vWYld2+fRv/+te/sGTJEik2Y8YMTJgwQaXdTz/9BGNjYwQGBgIAli9frvIZWVpaYvjw4YiMjJTeI5fL8e6772LRokUNeg5ERETUNHFSioiIiKgCHx8fZGRkqLxcXFzQunVrmJub19txEhIS4Ovri0GDBiEqKgrx8fFYt24dDA0NoVQqAQAmJiawtbWtt2NqsmXLFri7u6Njx45Vttm8eTOmTZuGoKAgvP/++1K8V69e0md05swZdOnSBWPHjoVCoZDaTJs2DSdOnEBiYmJDngYRERE1QZyUIiIiIqpALpfDzs5O5aWvr692+V5lCoUCs2fPhq2tLSwsLODl5YWLFy9W2T40NBT29vYIDAxE79690blzZ/j4+GDz5s0wMjICoH75XseOHTWu5Cp369YtTJ48GdbW1mjTpg38/PyQlpZW7fnu3r0b48ePr3J7YGAg3nrrLezcuROvvvqqyjYDAwPpM+rZsydWrFiBe/fuqazuatOmDYYMGYJdu3ZV2w8iIiJqeTgpRURERFRHQgiMGTMGmZmZOHLkCGJiYtC/f3+MHDkSd+7c0fgeOzs7ZGRkICoqSuvjREdHSyuTbt68CTc3NwwfPhwAkJ+fD09PT5iZmSEqKgonT56EmZkZfHx8UFRUpHF/d+/exaVLlzBw4ECN2xcvXoxPPvkEhw4dwsSJE6vtW2FhoTSJ1q1bN5VtTz31FE6cOKH1eRIREVHLYNDYHSAiIiJ6nBw6dAhmZmbSz76+vti7d2+17wkPD0d8fDyysrIgl8sBAF988QUOHDiAn376SeNNxCdNmoSQkBB4eHjAzs4Obm5uGDlyJF5++WVYWFhoPE7btm2l/54/fz4yMjIQHR0NoGzFk56eHjZv3iytngoODoaVlRUiIiLg7e2ttr/r169DCAEHBwe1bb/++it++eUXHD9+HF5eXhr7Ex8fL31W+fn5MDc3x549e9T67+joWOOKLSIiImp5OClFREREVIGnpye+/vpr6WdTU9Ma3xMTE4N79+6hTZs2KvGCggKkpKRofI++vj6Cg4OxcuVKhIWF4ezZs/j000/x2Wef4dy5c7C3t6/yeJs2bcKWLVtw6tQpaaIqJiYGycnJave9un//fpV9KCgoAAAYGxurbXvyySfx119/4f/+7/8waNAgjffT6tatGw4ePAgAyM3NxZ49ezBp0iSEh4errL4yMTFBfn5+ledDRERELRMnpYiIiIgqMDU1xRNPPFGr9yiVStjb2yMiIkJtW8V7Qmni6OiI6dOnY/r06Vi5ciW6du2KjRs3YsWKFRrbR0REYN68edi1axf69u2r0ocBAwbghx9+UHtPxRVWFdnY2AAou4yvchtHR0f8/PPP8PT0hI+PD44ePao2MWVkZKTyWbm6uuLAgQNYu3YtduzYIcXv3LlTZR+IiIio5eKkFBEREVEd9e/fH5mZmTAwMKj2KXY1sba2hr29PfLy8jRuT05OxsSJE7FkyRL4+/ur9WHPnj3Sjda10blzZ1hYWODy5cvo2rWr2nZnZ2dERkbC09MT3t7eCAkJqXHf+vr60gqscpcuXYKrq6tWfSIiIqKWgzc6JyIiIqqjUaNGwd3dHRMmTEBISAjS0tJw+vRpLF26FOfPn9f4nm+++QZvvPEGjh07hpSUFCQkJGDRokVISEjAuHHj1NoXFBRg3Lhx6NevH2bPno3MzEzpBQDTpk2DjY0N/Pz8cOLECaSmpiIyMhLz58/HzZs3NfZBT08Po0aNwsmTJ6s8NycnJ0RERCA7Oxve3t5QKBTStpKSEqkPV69excqVK3H58mX4+fmp7OPEiRMa72lFRERELRsnpYiIiIjqSCaT4ciRI3j66acxc+ZMdO3aFVOmTEFaWhratWun8T1PPfUU7t27hzlz5qBXr17w8PDA2bNnceDAAXh4eKi1v337Nq5cuYKwsDA4ODjA3t5eegFAq1atEBUVBWdnZ/j7+6NHjx6YOXMmCgoKql3dNHv2bOzevRtKpbLKNo6OjoiMjMTff/+NZ555Bn///TcAICEhQepDv3798OOPP+Lrr7/Gyy+/LL33zJkzUCgUeP7557X5KImIiKgFkQkhRGN3goiIiIgahxACbm5uWLBgAaZOnVrv+580aRJcXV2xZMmSet83ERERNW1cKUVERETUgslkMmzatAklJSX1vu/CwkL07dsXb7/9dr3vm4iIiJo+rpQiIiIiIiIiIiKd40opIiIiIiIiIiLSOU5KERERERERERGRznFSioiIiIiIiIiIdI6TUkREREREREREpHOclCIiIiIiIiIiIp3jpBQREREREREREekcJ6WIiIiIiIiIiEjnOClFREREREREREQ6x0kpIiIiIiIiIiLSOU5KERERERERERGRzv0//HyDZ2cvZi0AAAAASUVORK5CYII=", | |
"text/plain": [ | |
"<Figure size 1200x600 with 1 Axes>" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"# After running your timing tests, create the bar chart\n", | |
"plt.figure(figsize=(12, 6))\n", | |
"\n", | |
"# Set up positions for grouped bars\n", | |
"x = np.arange(len(kb_range))\n", | |
"width = 0.15 # Width of each bar\n", | |
"n_methods = 5\n", | |
"\n", | |
"# Plot bars for each method\n", | |
"methods = ['basic', 'memory_mapped', 'pt_cached', 'cache_disk', 'cache_mem']\n", | |
"colors = ['#2196F3', '#4CAF50', '#F44336', '#FF9800', '#9C27B0']\n", | |
"\n", | |
"for i, (method, color) in enumerate(zip(methods, colors)):\n", | |
" times = [timings[kb][method] for kb in kb_range]\n", | |
" position = x + (i - n_methods/2 + 0.5) * width\n", | |
" plt.bar(position, times, width, label=method.replace('_', ' ').title(), color=color)\n", | |
"\n", | |
"# Customize the plot\n", | |
"plt.xlabel('File Size (KB)')\n", | |
"plt.ylabel('Loading Time (seconds)')\n", | |
"plt.title('Data Loading Performance Comparison')\n", | |
"\n", | |
"# Set x-axis ticks and labels\n", | |
"plt.xticks(x, [str(kb) for kb in kb_range])\n", | |
"\n", | |
"# Add grid for easier reading of values\n", | |
"plt.grid(True, axis='y', linestyle='--', alpha=0.7)\n", | |
"\n", | |
"# Set y-axis to logarithmic scale\n", | |
"plt.yscale('log')\n", | |
"\n", | |
"# Add legend\n", | |
"plt.legend()\n", | |
"\n", | |
"# Tight layout to prevent label clipping\n", | |
"plt.tight_layout()\n", | |
"\n", | |
"# Show the plot\n", | |
"plt.show()\n" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "py312", | |
"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.7" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment