From 2db1421d1caaaed140a6af5274c953954ccf02f4 Mon Sep 17 00:00:00 2001
From: Ignacio Oguiza <11656416+oguiza@users.noreply.github.com>
Date: Wed, 31 Jan 2024 19:40:13 +0100
Subject: [PATCH] updated tsai.utils test to avoid gh issue
---
nbs/002_utils.ipynb | 569 ++++++++++++++++++++++----------------------
nbs/models/test.pth | Bin 1100008 -> 1100136 bytes
tsai/utils.py | 228 +++++++++---------
3 files changed, 403 insertions(+), 394 deletions(-)
diff --git a/nbs/002_utils.ipynb b/nbs/002_utils.ipynb
index 85ce93056..3701054e7 100644
--- a/nbs/002_utils.ipynb
+++ b/nbs/002_utils.ipynb
@@ -104,9 +104,9 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "[4 5 7]\n",
- "[4 0 1]\n",
- "[100 99 13]\n"
+ "[5 7 5]\n",
+ "[0 1 6]\n",
+ "[ 4 83 100]\n"
]
}
],
@@ -182,7 +182,7 @@
"source": [
"# ensure these folders exist for testing purposes\n",
"fns = ['data', 'export', 'models']\n",
- "for fn in fns: \n",
+ "for fn in fns:\n",
" path = Path('.')/fn\n",
" if not os.path.exists(path): os.makedirs(path)"
]
@@ -198,7 +198,7 @@
" if isinstance(o, torch.Tensor): return o\n",
" elif isinstance(o, np.ndarray): return torch.from_numpy(o)\n",
" elif isinstance(o, pd.DataFrame): return torch.from_numpy(o.values)\n",
- " else: \n",
+ " else:\n",
" try: return torch.tensor(o)\n",
" except: warn(f\"Can't convert {type(o)} to torch.Tensor\", Warning)\n",
"\n",
@@ -210,8 +210,8 @@
" else:\n",
" try: return np.asarray(o)\n",
" except: warn(f\"Can't convert {type(o)} to np.array\", Warning)\n",
- " \n",
- " \n",
+ "\n",
+ "\n",
"def toL(o):\n",
" if isinstance(o, L): return o\n",
" elif isinstance(o, (np.ndarray, torch.Tensor)): return L(o.tolist())\n",
@@ -266,38 +266,38 @@
" elif o.ndim == 3: o = o[0,0]\n",
" elif o.ndim == 2: o = o[0]\n",
" assert False, f'Please, review input dimensions {o.ndim}'\n",
- " \n",
- " \n",
+ "\n",
+ "\n",
"def to3d(o):\n",
" if o.ndim == 3: return o\n",
" if isinstance(o, (np.ndarray, pd.DataFrame)): return to3darray(o)\n",
" if isinstance(o, torch.Tensor): return to3dtensor(o)\n",
- " \n",
- " \n",
+ "\n",
+ "\n",
"def to2d(o):\n",
" if o.ndim == 2: return o\n",
" if isinstance(o, np.ndarray): return to2darray(o)\n",
" if isinstance(o, torch.Tensor): return to2dtensor(o)\n",
- " \n",
- " \n",
+ "\n",
+ "\n",
"def to1d(o):\n",
" if o.ndim == 1: return o\n",
" if isinstance(o, np.ndarray): return to1darray(o)\n",
" if isinstance(o, torch.Tensor): return to1dtensor(o)\n",
- " \n",
- " \n",
+ "\n",
+ "\n",
"def to2dPlus(o):\n",
" if o.ndim >= 2: return o\n",
" if isinstance(o, np.ndarray): return to2darray(o)\n",
" elif isinstance(o, torch.Tensor): return to2dtensor(o)\n",
- " \n",
- " \n",
+ "\n",
+ "\n",
"def to3dPlus(o):\n",
" if o.ndim >= 3: return o\n",
" if isinstance(o, np.ndarray): return to3darray(o)\n",
" elif isinstance(o, torch.Tensor): return to3dtensor(o)\n",
- " \n",
- " \n",
+ "\n",
+ "\n",
"def to2dPlusTensor(o):\n",
" return to2dPlus(totensor(o))\n",
"\n",
@@ -364,7 +364,7 @@
"source": [
"#|export\n",
"def bytes2str(\n",
- " size_bytes : int, # Number of bytes \n",
+ " size_bytes : int, # Number of bytes\n",
" decimals=2 # Number of decimals in the output\n",
" )->str:\n",
" if size_bytes == 0: return \"0B\"\n",
@@ -379,7 +379,7 @@
"\n",
"\n",
"def get_size(\n",
- " o, # Any python object \n",
+ " o, # Any python object\n",
" return_str = False, # True returns size in human-readable format (KB, MB, GB, ...). False in bytes.\n",
" decimals = 2, # Number of decimals in the output\n",
"):\n",
@@ -397,13 +397,13 @@
" size = sum(get_size(k) + get_size(v) for k, v in o.items())\n",
" else:\n",
" size = sys.getsizeof(o)\n",
- " if return_str: \n",
+ " if return_str:\n",
" return bytes2str(size, decimals=decimals)\n",
" else:\n",
" return size\n",
"\n",
"def get_dir_size(\n",
- " dir_path : str, # path to directory \n",
+ " dir_path : str, # path to directory\n",
" return_str : bool = True, # True returns size in human-readable format (KB, MB, GB, ...). False in bytes.\n",
" decimals : int = 2, # Number of decimals in the output\n",
" verbose : bool = False, # Controls verbosity\n",
@@ -418,18 +418,18 @@
" fp_size = os.path.getsize(fp)\n",
" total_size += fp_size\n",
" pv(f'file: {fp[-50:]:50} size: {fp_size}', verbose)\n",
- " if return_str: \n",
+ " if return_str:\n",
" return bytes2str(total_size, decimals=decimals)\n",
" return total_size\n",
"\n",
"def get_file_size(\n",
- " file_path : str, # path to file \n",
+ " file_path : str, # path to file\n",
" return_str : bool = True, # True returns size in human-readable format (KB, MB, GB, ...). False in bytes.\n",
" decimals : int = 2, # Number of decimals in the output\n",
" ):\n",
" assert os.path.isfile(file_path)\n",
" fsize = os.path.getsize(file_path)\n",
- " if return_str: \n",
+ " if return_str:\n",
" return bytes2str(fsize, decimals=decimals)\n",
" return fsize"
]
@@ -516,7 +516,7 @@
"outputs": [],
"source": [
"#|export\n",
- "def reverse_dict(dictionary): \n",
+ "def reverse_dict(dictionary):\n",
" return {v: k for k, v in dictionary.items()}"
]
},
@@ -537,7 +537,7 @@
"outputs": [],
"source": [
"#|export\n",
- "def itemify(*o, tup_id=None): \n",
+ "def itemify(*o, tup_id=None):\n",
" o = [o_ for o_ in L(*o) if o_ is not None]\n",
" items = L(o).zip()\n",
" if tup_id is not None: return L([item[tup_id] for item in items])\n",
@@ -632,28 +632,28 @@
"\n",
"\n",
"def test_ok(f, *args, **kwargs):\n",
- " try: \n",
+ " try:\n",
" f(*args, **kwargs)\n",
" e = 0\n",
- " except: \n",
+ " except:\n",
" e = 1\n",
" pass\n",
" test_eq(e, 0)\n",
- " \n",
+ "\n",
"def test_not_ok(f, *args, **kwargs):\n",
- " try: \n",
+ " try:\n",
" f(*args, **kwargs)\n",
" e = 0\n",
- " except: \n",
+ " except:\n",
" e = 1\n",
" pass\n",
" test_eq(e, 1)\n",
- " \n",
+ "\n",
"def test_error(error, f, *args, **kwargs):\n",
" try: f(*args, **kwargs)\n",
- " except Exception as e: \n",
+ " except Exception as e:\n",
" test_eq(str(e), error)\n",
- " \n",
+ "\n",
"def test_eq_nan(a,b):\n",
" \"`test` that `a==b` excluding nan values (valid for torch.Tensor and np.ndarray)\"\n",
" mask_a = torch.isnan(a) if isinstance(a, torch.Tensor) else np.isnan(a)\n",
@@ -686,7 +686,7 @@
"def test_ge(a,b):\n",
" \"`test` that `a>=b`\"\n",
" test(a,b,ge,'>')\n",
- " \n",
+ "\n",
"def test_lt(a,b):\n",
" \"`test` that `a>b`\"\n",
" test(a,b,lt,'<')\n",
@@ -720,7 +720,6 @@
"outputs": [],
"source": [
"t = torch.rand(100)\n",
- "t[t<.5] = np.nan\n",
"test_eq(t, t)\n",
"test_eq_nan(t, t)"
]
@@ -738,8 +737,8 @@
" return retain_type(torch.stack(tuple(o), dim=axis), o[0]) if retain else torch.stack(tuple(o), dim=axis)\n",
" else:\n",
" return retain_type(np.stack(o, axis), o[0]) if retain else np.stack(o, axis)\n",
- " \n",
- " \n",
+ "\n",
+ "\n",
"def stack_pad(o, padding_value=np.nan):\n",
" 'Converts a an iterable into a numpy array using padding if necessary'\n",
" if not is_listy(o) or not is_array(o):\n",
@@ -847,7 +846,7 @@
" padding_value:float=np.nan, # Value used for padding.\n",
"):\n",
" \"Transforms an iterable with sequences into a 3d numpy array using padding or truncating sequences if necessary\"\n",
- " \n",
+ "\n",
" assert padding in ['pre', 'post']\n",
" assert truncating in ['pre', 'post']\n",
" assert is_iter(o)\n",
@@ -864,7 +863,7 @@
" if padding == 'pre':\n",
" result[i, :, -values.shape[-1]:] = values\n",
" else:\n",
- " result[i, :, :values.shape[-1]] = values \n",
+ " result[i, :, :values.shape[-1]] = values\n",
" return result"
]
},
@@ -1240,16 +1239,16 @@
" except KeyboardInterrupt:\n",
" pass\n",
"\n",
- " \n",
+ "\n",
"def cycle_dl_to_device(dl, show_progress_bar=True):\n",
" try:\n",
- " if show_progress_bar: \n",
+ " if show_progress_bar:\n",
" for bs in progress_bar(dl): [b.to(default_device()) for b in bs]\n",
" else:\n",
" for bs in dl: [b.to(default_device()) for b in bs]\n",
" except KeyboardInterrupt:\n",
" pass\n",
- " \n",
+ "\n",
"def cycle_dl_estimate(dl, iters=10):\n",
" iters = min(iters, len(dl))\n",
" iterator = iter(dl)\n",
@@ -1275,11 +1274,11 @@
" pv(f'{n_loops} loops', verbose)\n",
" timer.start(False)\n",
" for i in range(n_loops):\n",
- " o[slice(start,start + slice_len)] \n",
+ " o[slice(start,start + slice_len)]\n",
" if verbose and (i+1) % 10 == 0: print(f'{i+1:4} elapsed time: {timer.elapsed()}')\n",
" start += slice_len\n",
" pv(f'{i+1:4} total time : {timer.stop()}\\n', verbose)\n",
- " \n",
+ "\n",
"memmap2cache = cache_data\n",
"cache_memmap = cache_data"
]
@@ -1291,7 +1290,7 @@
"outputs": [],
"source": [
"#|export\n",
- "def get_func_defaults(f): \n",
+ "def get_func_defaults(f):\n",
" import inspect\n",
" fa = inspect.getfullargspec(f)\n",
" if fa.defaults is None: return dict(zip(fa.args, [''] * (len(fa.args))))\n",
@@ -1404,9 +1403,9 @@
"
\n",
" \n",
" 0 | \n",
- " 0.055708 | \n",
+ " 0.436034 | \n",
" ... | \n",
- " 0.189871 | \n",
+ " 0.231616 | \n",
"
\n",
" \n",
" ... | \n",
@@ -1416,9 +1415,9 @@
"
\n",
" \n",
" 69 | \n",
- " 0.370982 | \n",
+ " 0.633051 | \n",
" ... | \n",
- " 0.299734 | \n",
+ " 0.051762 | \n",
"
\n",
" \n",
"\n",
@@ -1427,9 +1426,9 @@
],
"text/plain": [
" 0 ... 24\n",
- "0 0.055708 ... 0.189871\n",
+ "0 0.436034 ... 0.231616\n",
".. ... ... ...\n",
- "69 0.370982 ... 0.299734\n",
+ "69 0.633051 ... 0.051762\n",
"\n",
"[70 rows x 25 columns]"
]
@@ -1460,11 +1459,11 @@
"\n",
"def kstest(data1, data2, alternative='two-sided', mode='auto', by_axis=None):\n",
" \"\"\"Performs the two-sample Kolmogorov-Smirnov test for goodness of fit.\n",
- " \n",
+ "\n",
" Parameters\n",
" data1, data2: Two arrays of sample observations assumed to be drawn from a continuous distributions. Sample sizes can be different.\n",
- " alternative: {‘two-sided’, ‘less’, ‘greater’}, optional. Defines the null and alternative hypotheses. Default is ‘two-sided’. \n",
- " mode: {‘auto’, ‘exact’, ‘asymp’}, optional. Defines the method used for calculating the p-value. \n",
+ " alternative: {‘two-sided’, ‘less’, ‘greater’}, optional. Defines the null and alternative hypotheses. Default is ‘two-sided’.\n",
+ " mode: {‘auto’, ‘exact’, ‘asymp’}, optional. Defines the method used for calculating the p-value.\n",
" by_axis (optional, int): for arrays with more than 1 dimension, the test will be run for each variable in that axis if by_axis is not None.\n",
" \"\"\"\n",
" if by_axis is None:\n",
@@ -1477,12 +1476,12 @@
" d1 = np.take(data1, indices=i, axis=by_axis)\n",
" d2 = np.take(data2, indices=i, axis=by_axis)\n",
" stat, p_value = ks_2samp(d1.flatten(), d2.flatten(), alternative=alternative, mode=mode)\n",
- " stats.append(stat) \n",
+ " stats.append(stat)\n",
" p_values.append(np.sign(stat) * p_value)\n",
- " return stats, p_values \n",
- " \n",
+ " return stats, p_values\n",
+ "\n",
"\n",
- "def tscore(o): \n",
+ "def tscore(o):\n",
" if o.std() == 0: return 0\n",
" else: return np.sqrt(len(o)) * o.mean() / o.std()"
]
@@ -1494,7 +1493,7 @@
"outputs": [
{
"data": {
- "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhYAAAGdCAYAAABO2DpVAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAWg0lEQVR4nO3dbWzV9fn48atCOOhsUbSoBBCdmw4ZzHFjGIvzBjUEje4BWZzLKi57QKob67aMPhk2i5ZlyaKZBJ1xsGRjuCVDFx0yJQIPFAUMiWjmZJPReQNuzhb6iwdDz//Bfv/+BgLllOv09LSvV/JNOKffcz5Xew7tO99zV1cqlUoBAJDgtGoPAAAMHcICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgzcqAX7Onpibfffjvq6+ujrq5uoJcHAPqhVCrFgQMHYvz48XHaacc/LjHgYfH222/HxIkTB3pZACBBR0dHTJgw4bhfH/CwqK+vj4j/DNbQ0DDQywMA/dDV1RUTJ07s/Tt+PAMeFv//4Y+GhgZhAQA1pq+nMXjyJgCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGnKCovJkydHXV3dx7bm5uZKzQcA1JCyPitk27Ztcfjw4d7Tu3btiuuvvz4WLlyYPhgAUHvKCovGxsYjTi9fvjw++clPxpe+9KXUoQCA2tTvTzc9dOhQ/OpXv4qWlpYTftJZsViMYrHYe7qrq6u/SwIAg1y/w+Lxxx+PDz74IO64444T7tfe3h5tbW39XQZIMHnpU33us2f5ggGYBBjq+v2qkEcffTTmz58f48ePP+F+ra2t0dnZ2bt1dHT0d0kAYJDr1xGLv//97/Hss8/G73//+z73LRQKUSgU+rMMAFBj+nXEYtWqVTFu3LhYsMChUwDg/5QdFj09PbFq1apoamqKkSP7/RQNAGAIKjssnn322di7d2/ceeedlZgHAKhhZR9yuOGGG6JUKlViFgCgxvmsEAAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgTdlh8dZbb8XXvva1OOecc+L000+Pz372s7F9+/ZKzAYA1JiR5ez873//O+bOnRvXXHNNrF+/PhobG+ONN96Is88+u1LzAQA1pKyw+PGPfxwTJ06MVatW9Z530UUXpQ8FANSmsh4K+cMf/hAzZ86MhQsXxrhx4+KKK66IRx55pFKzAQA1pqyw+Nvf/hYrV66MT33qU7Fhw4ZYvHhxfOtb34pf/vKXx71MsViMrq6uIzYAYGgq66GQnp6emDlzZtx3330REXHFFVfErl274qGHHoqmpqZjXqa9vT3a2tpOfVIAYNAr64jFBRdcEFOmTDnivM985jOxd+/e416mtbU1Ojs7e7eOjo7+TQoADHplHbGYO3duvP7660ec95e//CUuvPDC416mUChEoVDo33QAQE0p64jFd77zndi6dWvcd999sXv37lizZk38/Oc/j+bm5krNBwDUkLLCYtasWbFu3br4zW9+E1OnTo0f/ehHcf/998ftt99eqfkAgBpS1kMhERE33XRT3HTTTZWYBQCocT4rBABIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDRlhcU999wTdXV1R2yXXXZZpWYDAGrMyHIvcPnll8ezzz77f1cwsuyrAACGqLKrYOTIkXH++edXYhYAoMaV/RyLN954I8aPHx8XX3xx3H777bF3794T7l8sFqOrq+uIDQAYmupKpVLpZHdev359HDx4MC699NJ45513oq2tLd56663YtWtX1NfXH/My99xzT7S1tX3s/M7OzmhoaOj/5PC/Ji99qs999ixfMACT5Mv63k7mek5GLf4ch/L9AwZSV1dXjBkzps+/32UdsZg/f34sXLgwpk2bFjfeeGP88Y9/jA8++CB++9vfHvcyra2t0dnZ2bt1dHSUsyQAUENO6ZmXZ511Vnz605+O3bt3H3efQqEQhULhVJYBAGrEKb2PxcGDB+Ovf/1rXHDBBVnzAAA1rKyw+N73vhebN2+OPXv2xPPPPx9f/vKXY8SIEXHbbbdVaj4AoIaU9VDIP/7xj7jtttviX//6VzQ2NsYXv/jF2Lp1azQ2NlZqPgCghpQVFmvXrq3UHADAEOCzQgCANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANKcUFsuXL4+6urpYsmRJ0jgAQC3rd1hs27YtHn744Zg2bVrmPABADetXWBw8eDBuv/32eOSRR+Lss8/OngkAqFH9Covm5uZYsGBBzJs3r899i8VidHV1HbEBAEPTyHIvsHbt2nj55Zdj27ZtJ7V/e3t7tLW1lT0YRERMXvpUtUfgZNwz5qjTndWZo4Ky7ot7li9IuR4YrMo6YtHR0RHf/va349e//nWMHj36pC7T2toanZ2dvVtHR0e/BgUABr+yjljs2LEj9u/fH5///Od7zzt8+HBs2bIlHnzwwSgWizFixIgjLlMoFKJQKORMCwAMamWFxXXXXRevvPLKEectWrQoLrvssvjBD37wsagAAIaXssKivr4+pk6desR5n/jEJ+Kcc8752PkAwPDjnTcBgDRlvyrkaJs2bUoYAwAYChyxAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSlBUWK1eujGnTpkVDQ0M0NDTEnDlzYv369ZWaDQCoMWWFxYQJE2L58uWxY8eO2L59e1x77bVxyy23xKuvvlqp+QCAGjKynJ1vvvnmI07fe++9sXLlyti6dWtcfvnlqYMBALWnrLD4b4cPH47f/e530d3dHXPm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",
+ "image/png": "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y8N1LZ5rWh5flOtaX1/fp+MKf8PpkCFDYvLkybFu3bqefd3d3bFu3bqYMWNG0csBAFWmLN92WbhwYTQ1NcWUKVNi2rRpsWzZsujs7Iz58+eXYzkAoIqUJT6+853vxHvvvRe33HJL7N69O772ta/F008/HaNHjz7mc9fW1sbixYs/9a0ajo3rWh6ua3m4rsVzTcvDdT20mlKpLz8TAwBQDH/bBQBIJT4AgFTiAwBIJT4AgFRVGx87d+6Ma665JhobG2PYsGFx+umnx+LFi2P//v2VHq3q3X777XH++efH8ccf36df+MahLV++PCZMmBBDhw6N6dOnx0svvVTpkarehg0b4rLLLouxY8dGTU1NPPbYY5Ueqeq1trbG1KlTo66uLkaNGhXz5s2L119/vdJjVb0VK1bEeeed1/PLxWbMmBFPPfVUpcfqN6o2Pl577bXo7u6O+++/P1599dX47W9/G/fdd1/84he/qPRoVW///v1xxRVXxHXXXVfpUarWo48+GgsXLozFixfHtm3bYtKkSXHJJZfE3r17Kz1aVevs7IxJkybF8uXLKz3KgPH8889Hc3NzbNq0KZ599tn4+OOP4+KLL47Ozs5Kj1bVxo0bF0uXLo2tW7fGli1b4lvf+lZcfvnl8eqrr1Z6tH5hQP2o7Z133hkrVqyIt956q9KjDAgPPfRQLFiwID744INKj1J1pk+fHlOnTo177703Iv77W34bGhrihhtuiJaWlgpPNzDU1NTE2rVrY968eZUeZUB57733YtSoUfH888/HBRdcUOlxBpQRI0bEnXfeGddcc02lR6m4qr3zcSjt7e0xYsSISo/BF9z+/ftj69atMXv27J59gwYNitmzZ8fGjRsrOBkcWXt7e0SE19ICHThwINasWROdnZ3+zMj/qvhftS3Kjh074p577om77rqr0qPwBfevf/0rDhw48Knf6Dt69Oh47bXXKjQVHFl3d3csWLAgZs6cGRMnTqz0OFXv5ZdfjhkzZsS+ffvixBNPjLVr18bZZ59d6bH6hX5356OlpSVqamoOux38Ar5r16749re/HVdccUVce+21FZq8f/s81xX4Ymlubo5XXnkl1qxZU+lRBoSvfOUrsX379njxxRfjuuuui6ampvjHP/5R6bH6hX535+OnP/1pfP/73z/sMV/+8pd7/vO7774bs2bNivPPPz8eeOCBMk9XvY72uvL5nXLKKTF48ODYs2dPr/179uyJMWPGVGgqOLzrr78+nnjiidiwYUOMGzeu0uMMCEOGDIkzzjgjIiImT54cmzdvjt/97ndx//33V3iyyut38TFy5MgYOXJkn47dtWtXzJo1KyZPnhwrV66MQYP63Y2cfuNorivHZsiQITF58uRYt25dz5shu7u7Y926dXH99ddXdjg4SKlUihtuuCHWrl0b69evj8bGxkqPNGB1d3dHV1dXpcfoF/pdfPTVrl274sILL4zTTjst7rrrrnjvvfd6nvP/Lo/NO++8E++//3688847ceDAgdi+fXtERJxxxhlx4oknVna4KrFw4cJoamqKKVOmxLRp02LZsmXR2dkZ8+fPr/RoVe2jjz6KHTt29Dx+++23Y/v27TFixIgYP358BSerXs3NzbF69ep4/PHHo66uLnbv3h0REfX19TFs2LAKT1e9Fi1aFHPmzInx48fHhx9+GKtXr47169fHM888U+nR+odSlVq5cmUpIg65cWyampoOeV2fe+65So9WVe65557S+PHjS0OGDClNmzattGnTpkqPVPWee+65Q/53s6mpqdKjVa3Peh1duXJlpUeraldffXXptNNOKw0ZMqQ0cuTI0kUXXVT6y1/+Uumx+o0B9Xs+AID+z5skAIBU4gMASCU+AIBU4gMASCU+AIBU4gMASCU+AIBU4gMASCU+AIBU4gMASCU+AIBU4gMASPU/bf3YntcPb7EAAAAASUVORK5CYII=",
"text/plain": [
"