\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"metadata = {\n",
" \"platform\": platform.platform(),\n",
" \"python\": platform.python_version(),\n",
" \"tmol\": tmol.__version__,\n",
" \"torch\": torch.__version__,\n",
" \"device\": str(device),\n",
" \"cuda_runtime\": torch.version.cuda,\n",
"}\n",
"if device.type == \"cuda\":\n",
" props = torch.cuda.get_device_properties(device)\n",
" metadata.update(\n",
" {\n",
" \"gpu_name\": props.name,\n",
" \"compute_capability\": f\"{props.major}.{props.minor}\",\n",
" \"gpu_memory_GiB\": props.total_memory / 2**30,\n",
" }\n",
" )\n",
"metadata_frame = pd.DataFrame.from_dict(metadata, orient=\"index\", columns=[\"value\"])\n",
"show_table(metadata_frame.reset_index(names=\"property\"))"
]
},
{
"cell_type": "markdown",
"id": "c935bfcb",
"metadata": {},
"source": [
"## Build batches explicitly\n",
"\n",
"`PoseStackBuilder.from_poses` concatenates compatible pose stacks and repacks their tensors on the requested device. Repeating the same pose is useful for a controlled throughput demonstration; real workloads normally batch distinct but chemistry-compatible structures."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "d27f4853",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"single coords: (1, 327, 3)\n",
"batch coords: (4, 327, 3)\n",
"batch poses: 4\n"
]
}
],
"source": [
"preview_batch = PoseStackBuilder.from_poses([single_pose] * 4, device)\n",
"print(\"single coords:\", tuple(single_pose.coords.shape))\n",
"print(\"batch coords: \", tuple(preview_batch.coords.shape))\n",
"print(\"batch poses: \", preview_batch.n_poses)"
]
},
{
"cell_type": "markdown",
"id": "ec20d301",
"metadata": {},
"source": [
"## Score a heterogeneous CIF batch\n",
"\n",
"Repeating one pose isolates batching overhead, but production batches usually contain different structures. Here model 1 from each of three checked-in CIF entries is converted independently with optimized hydrogens (`no_optH=False`), combined into one `PoseStack`, scored in one call, and exposed through a structure selector. The 1R21 entry is an NMR ensemble, so its deposited model count is reported and its displayed structure is labeled explicitly as model 1 rather than as the complete ensemble. The batch pads its block and atom dimensions to the largest member, so every pose occupies the batch's fixed rectangular layout; grouping similarly sized structures reduces wasted storage and work.\n",
"\n",
"The preparation table gives deposited and TMol-built totals. Their difference can be reported, but it is not an exact atom-provenance statement: conversion may exclude unsupported material, select chemical variants, and build supported missing atoms, while the public API does not identify every output atom as retained or constructed. In this fixture set, 1BL8 contains a deposited `K` ion that TMol does not recognize and excludes; the table names that known removal explicitly.\n",
"\n",
"This is the core GPU workflow: one tensor operation returns one weighted total per structure, while the label table and switcher preserve every input's identity. Each structure is also scored by its own independently rendered module, and the notebook asserts agreement with the corresponding batched total within floating-point tolerance. These beta2016 totals are score-function units, not physical energies. Because the proteins are unrelated and differ in size and composition, their absolute totals are **not scientifically comparable**; this table demonstrates batch indexing and labeling, not a ranking."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "f266f2b6",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"\n",
" Loading ITables v2.9.1 from the internet...\n",
" (need help?)\n",
"
"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"workload_labels = [label for label in individual_poses for _ in range(2)]\n",
"workload_poses = [individual_poses[label] for label in workload_labels]\n",
"layout_groups = {\n",
" \"one heterogeneous batch\": [workload_poses],\n",
" \"three size buckets\": [\n",
" [individual_poses[label], individual_poses[label]] for label in individual_poses\n",
" ],\n",
"}\n",
"\n",
"\n",
"def build_layout(groups):\n",
" \"\"\"Build all batches and rendered scorers for one workload layout.\"\"\"\n",
" batches = [PoseStackBuilder.from_poses(group, device) for group in groups]\n",
" scorers = [\n",
" score_function.render_whole_pose_scoring_module(batch) for batch in batches\n",
" ]\n",
" return batches, scorers\n",
"\n",
"\n",
"def run_layout(batches, scorers):\n",
" \"\"\"Score each pre-rendered group and concatenate in workload order.\"\"\"\n",
" return torch.cat(\n",
" [scorer(batch.coords) for batch, scorer in zip(batches, scorers, strict=True)]\n",
" )\n",
"\n",
"\n",
"def time_layout(batches, scorers, repeats, warmup):\n",
" \"\"\"Measure aggregate latency for all calls in one workload layout.\"\"\"\n",
" with torch.no_grad():\n",
" for _ in range(warmup):\n",
" run_layout(batches, scorers)\n",
" if device.type == \"cuda\":\n",
" torch.cuda.synchronize(device)\n",
" baseline_bytes = torch.cuda.memory_allocated(device)\n",
" torch.cuda.reset_peak_memory_stats(device)\n",
" else:\n",
" baseline_bytes = np.nan\n",
" elapsed = []\n",
" for _ in range(repeats):\n",
" if device.type == \"cuda\":\n",
" torch.cuda.synchronize(device)\n",
" start_time = perf_counter()\n",
" run_layout(batches, scorers)\n",
" if device.type == \"cuda\":\n",
" torch.cuda.synchronize(device)\n",
" elapsed.append(perf_counter() - start_time)\n",
" if device.type == \"cuda\":\n",
" incremental_peak_bytes = max(\n",
" 0, torch.cuda.max_memory_allocated(device) - baseline_bytes\n",
" )\n",
" else:\n",
" incremental_peak_bytes = np.nan\n",
" return 1e3 * np.asarray(elapsed), incremental_peak_bytes\n",
"\n",
"\n",
"built_layouts = {label: build_layout(groups) for label, groups in layout_groups.items()}\n",
"with torch.no_grad():\n",
" layout_scores = {\n",
" label: run_layout(*layout).detach().cpu()\n",
" for label, layout in built_layouts.items()\n",
" }\n",
"torch.testing.assert_close(\n",
" layout_scores[\"one heterogeneous batch\"],\n",
" layout_scores[\"three size buckets\"],\n",
" rtol=1e-5,\n",
" atol=1e-3,\n",
")\n",
"\n",
"useful_atoms = sum(int(pose.real_atoms.sum().item()) for pose in workload_poses)\n",
"useful_blocks = sum(\n",
" int((pose.block_type_ind64 >= 0).sum().item()) for pose in workload_poses\n",
")\n",
"layout_rows = []\n",
"layout_repeats = 7 if device.type == \"cuda\" else 2\n",
"layout_warmup = 3 if device.type == \"cuda\" else 1\n",
"for label, (batches, scorers) in built_layouts.items():\n",
" elapsed_ms, incremental_peak_bytes = time_layout(\n",
" batches,\n",
" scorers,\n",
" repeats=layout_repeats,\n",
" warmup=layout_warmup,\n",
" )\n",
" atom_slots = sum(batch.n_poses * batch.max_n_pose_atoms for batch in batches)\n",
" block_slots = sum(batch.n_poses * batch.max_n_blocks for batch in batches)\n",
" layout_rows.append(\n",
" {\n",
" \"layout\": label,\n",
" \"score_calls_per_workload\": len(batches),\n",
" \"poses\": len(workload_poses),\n",
" \"useful_atom_slots\": useful_atoms,\n",
" \"rectangular_atom_slots\": atom_slots,\n",
" \"atom_padding_fraction\": 1.0 - useful_atoms / atom_slots,\n",
" \"useful_block_slots\": useful_blocks,\n",
" \"rectangular_block_slots\": block_slots,\n",
" \"block_padding_fraction\": 1.0 - useful_blocks / block_slots,\n",
" \"median_total_latency_ms\": float(np.median(elapsed_ms)),\n",
" \"throughput_poses_s\": float(\n",
" 1e3 * len(workload_poses) / np.median(elapsed_ms)\n",
" ),\n",
" \"latency_IQR_ms\": float(\n",
" np.percentile(elapsed_ms, 75) - np.percentile(elapsed_ms, 25)\n",
" ),\n",
" \"incremental_peak_cuda_MiB\": incremental_peak_bytes / 2**20,\n",
" \"measurement\": (\n",
" \"CUDA workload timing\"\n",
" if device.type == \"cuda\"\n",
" else \"CPU smoke timing; not GPU guidance\"\n",
" ),\n",
" }\n",
" )\n",
"layout_frame = pd.DataFrame(layout_rows)\n",
"show_table(layout_frame)\n",
"\n",
"fig, axes = plt.subplots(1, 2, figsize=(10, 4))\n",
"padding_plot = layout_frame.set_index(\"layout\")[\n",
" [\"atom_padding_fraction\", \"block_padding_fraction\"]\n",
"]\n",
"padding_plot.plot.bar(ax=axes[0], rot=10)\n",
"axes[0].set(\n",
" ylabel=\"fraction of rectangular slots that are padding\",\n",
" title=\"Bucketing removes avoidable padding\",\n",
")\n",
"axes[1].bar(\n",
" layout_frame[\"layout\"],\n",
" layout_frame[\"median_total_latency_ms\"],\n",
" color=[\"#3b82f6\", \"#f59e0b\"],\n",
")\n",
"axes[1].set(\n",
" ylabel=\"median total workload latency (ms)\",\n",
" title=(\n",
" \"Measured CUDA workload\"\n",
" if device.type == \"cuda\"\n",
" else \"CPU smoke timing — not GPU guidance\"\n",
" ),\n",
")\n",
"axes[1].tick_params(axis=\"x\", rotation=10)\n",
"for axis in axes:\n",
" axis.grid(axis=\"y\", alpha=0.3)\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"id": "bucketing-observations",
"metadata": {},
"source": [
"**Expected observations.** Size bucketing removes padding because each two-pose group has one shape, while the heterogeneous layout makes every member occupy the largest rectangular dimensions. The latency result may favor either layout: one mixed call has more padded work, whereas three buckets incur three launches. The incremental CUDA peak measures temporary PyTorch allocation above each post-warmup baseline, not total process or driver memory. Use measured throughput and memory on the target workload, not padding fraction alone, to choose bucket boundaries. The CPU row is an execution smoke check and must not be presented as GPU scaling evidence.\n"
]
},
{
"cell_type": "markdown",
"id": "eb2a7f17",
"metadata": {},
"source": [
"## Benchmark methodology\n",
"\n",
"`render_whole_pose_scoring_module(batch)` creates a scorer for that batch's fixed block, atom, and connectivity layout. Reuse it while only coordinates change within the same layout. Re-render when batch size, membership, padding dimensions, or chemical layout changes; `benchmark_scoring()` therefore renders once for each batch size and excludes that construction from the timed region.\n",
"\n",
"CUDA launches are asynchronous. A valid wall-clock measurement therefore:\n",
"\n",
"1. renders the scorer before timing and records the post-construction allocator baseline;\n",
"2. resets peak-memory statistics relative to that live baseline;\n",
"3. runs untimed warmup calls so lazy compilation and caches are not charged to steady-state latency;\n",
"4. synchronizes before starting and after finishing each timed call; and\n",
"5. reports multiple repeats rather than one launch.\n",
"\n",
"The table's `latency_ms` is median **total latency for one batch call** and is accompanied by Q1, Q3, IQR, minimum, and maximum. `latency_per_pose_ms` divides the median total by batch size and is an amortized throughput metric, not the time at which one pose's result becomes independently available. Plot error bars span Q1–Q3. CUDA memory reports the post-construction live allocation, total observed peak, and the incremental peak above that baseline. The CPU path uses the same timing function without CUDA synchronization and deliberately tiny sizes."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "d3fa1914",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"\n",
" Loading ITables v2.9.1 from the internet...\n",
" (need help?)\n",
"
\n",
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"def benchmark_scoring(batch_size, repeats=5, warmup=2):\n",
" batch = PoseStackBuilder.from_poses([single_pose] * batch_size, device)\n",
" scorer = score_function.render_whole_pose_scoring_module(batch)\n",
"\n",
" if device.type == \"cuda\":\n",
" torch.cuda.synchronize(device)\n",
" post_construction_bytes = torch.cuda.memory_allocated(device)\n",
" torch.cuda.reset_peak_memory_stats(device)\n",
" else:\n",
" post_construction_bytes = np.nan\n",
"\n",
" with torch.no_grad():\n",
" for _ in range(warmup):\n",
" scorer(batch.coords)\n",
" if device.type == \"cuda\":\n",
" torch.cuda.synchronize(device)\n",
"\n",
" elapsed = []\n",
" for _ in range(repeats):\n",
" if device.type == \"cuda\":\n",
" torch.cuda.synchronize(device)\n",
" start = perf_counter()\n",
" scorer(batch.coords)\n",
" if device.type == \"cuda\":\n",
" torch.cuda.synchronize(device)\n",
" elapsed.append(perf_counter() - start)\n",
"\n",
" elapsed_ms = 1e3 * np.asarray(elapsed)\n",
" latency_q1_ms, latency_q3_ms = np.percentile(elapsed_ms, [25, 75])\n",
" latency_ms = float(np.median(elapsed_ms))\n",
" if device.type == \"cuda\":\n",
" peak_bytes = torch.cuda.max_memory_allocated(device)\n",
" incremental_peak_bytes = max(0, peak_bytes - post_construction_bytes)\n",
" else:\n",
" peak_bytes = np.nan\n",
" incremental_peak_bytes = np.nan\n",
" return {\n",
" \"batch_size\": batch_size,\n",
" \"latency_min_ms\": float(elapsed_ms.min()),\n",
" \"latency_q1_ms\": float(latency_q1_ms),\n",
" \"latency_ms\": latency_ms,\n",
" \"latency_q3_ms\": float(latency_q3_ms),\n",
" \"latency_max_ms\": float(elapsed_ms.max()),\n",
" \"latency_iqr_ms\": float(latency_q3_ms - latency_q1_ms),\n",
" \"throughput_poses_s\": 1e3 * batch_size / latency_ms,\n",
" \"post_construction_cuda_MiB\": post_construction_bytes / 2**20,\n",
" \"peak_cuda_MiB\": peak_bytes / 2**20,\n",
" \"incremental_peak_cuda_MiB\": incremental_peak_bytes / 2**20,\n",
" \"repeats\": repeats,\n",
" }\n",
"\n",
"\n",
"batch_sizes = [1, 4, 16, 64] if device.type == \"cuda\" else [1, 2, 4]\n",
"repeats = 5 if device.type == \"cuda\" else 2\n",
"benchmark_frame = pd.DataFrame(\n",
" [benchmark_scoring(size, repeats=repeats) for size in batch_sizes]\n",
")\n",
"benchmark_frame[\"latency_per_pose_ms\"] = (\n",
" benchmark_frame[\"latency_ms\"] / benchmark_frame[\"batch_size\"]\n",
")\n",
"benchmark_frame[\"latency_per_pose_q1_ms\"] = (\n",
" benchmark_frame[\"latency_q1_ms\"] / benchmark_frame[\"batch_size\"]\n",
")\n",
"benchmark_frame[\"latency_per_pose_q3_ms\"] = (\n",
" benchmark_frame[\"latency_q3_ms\"] / benchmark_frame[\"batch_size\"]\n",
")\n",
"benchmark_frame[\"throughput_q1_poses_s\"] = (\n",
" 1e3 * benchmark_frame[\"batch_size\"] / benchmark_frame[\"latency_q3_ms\"]\n",
")\n",
"benchmark_frame[\"throughput_q3_poses_s\"] = (\n",
" 1e3 * benchmark_frame[\"batch_size\"] / benchmark_frame[\"latency_q1_ms\"]\n",
")\n",
"benchmark_frame[\"throughput_vs_batch_1\"] = (\n",
" benchmark_frame[\"throughput_poses_s\"]\n",
" / benchmark_frame.loc[0, \"throughput_poses_s\"]\n",
")\n",
"benchmark_frame.insert(\n",
" 0, \"measurement\", \"CUDA throughput\" if device.type == \"cuda\" else \"CPU smoke check\"\n",
")\n",
"show_table(benchmark_frame)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "5f697071",
"metadata": {
"tags": [
"collapse-code"
]
},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABEIAAAGNCAYAAAAVRNS/AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvctoD+AAAAAlwSFlzAAAPYQAAD2EBqD+naQAAxXlJREFUeJzs3XdcU9f7B/BPWGEP2bIEURG3qMiwdY866t6KInVbtbU/a21rHa1WrR221daJdbZqtVrrrFq3guLeAqIiUwlbIOf3B19SUoYhBsP4vF8vXiXnnnvz3JNUbp6c+xyJEEKAiIiIiIiIiKga0NF2AERERERERERErwsTIURERERERERUbTARQkRERERERETVBhMhRERERERERFRtMBFCRERERERERNUGEyFEREREREREVG0wEUJERERERERE1QYTIURERERERERUbTARQkRERERERETVBhMhRERExdi4cSMkEgkkEglGjRql7XCUtGjRQhFbREREtY+Dqr6S3mt8DxIRkTqYCCEiqmJycnKwYcMGdO/eHY6OjpBKpbC2tkaTJk0wffp0XLlyBQBw9uxZxQeIwj9SqRQeHh5455138ODBA8VxC/c3NDQs8rwdO3ZUbF+0aNFrO18ibfn4448V7/mlS5eWef+YmBh8/PHH8PX1RY0aNaCvrw87Ozs0bNgQo0aNwpYtWyCEUPQfPHhwkf9fdXR0YGFhAT8/P/z444/Iy8srtv+HH36o9NzXrl1TOk5WVpb6A0FERFTJ6Gk7ACIi0pyYmBj07t0bFy9eVGpPTk5GcnIyrly5gtTUVKxevbrEY7x48QKRkZFYvXo1fv31V5w4cQKNGzcu79CJqpX169dj0qRJyMjIUGpPSEhAQkICrl+/jtDQUPTp06fYxGMBIQRkMhnOnj2Ls2fP4tChQ/j999/LO3wiIqJKjTNCiIiqiKysLHTp0kWRBKlTpw7++OMPpKam4tmzZ7hw4QIWLFgABweHIvtKpVIIISCXy3H9+nV4e3sDAGQyWZFvkono1ezatQvBwcGKJMjgwYMRHh6OrKwsJCUl4eLFi/jqq6/QtGlTSCSSYo8xc+ZMCCGQkZGBlStXKh374MGDr+U8KoKwsDAIISCEQNOmTbUdDhERVRJMhBARVRErVqzAzZs3AQCGhoY4ePAgevbsCVNTU1haWqJFixaYPXs2FixYUOIxJBIJvL29MX36dEXb6dOnyyXe9PR0zJw5E/Xr14exsTHMzMzQrFkzTJs2DVevXlX0W79+vVKtjvDwcPj6+sLY2BgBAQG4fPkygPyaHvXq1YOpqSl8fX1x/PjxIs8pk8nw6aefonHjxjAxMYGhoSHq1q2LadOm4enTpyrFvWDBAkU8jRo1wuPHjwEA586dw8CBA+Hk5AQDAwNYWVmhQ4cOZf52/tKlSxg5ciTc3NwglUrh4uKCUaNGKd2m9F+rV69G7dq1YWZmBj8/P5w6dapIn7LGp04cABAXF4eGDRsqxmju3LllOn9N+m/9CFXG6fTp0+jfvz9q1qypGKe2bdti48aNSv0kEgk+//xzxeMPPvhA8Vwff/xxiTEJITB9+nTFLS8jRozAli1b0Lx5c0ilUtSoUQPNmjXDe++9h0uXLkEqlZZ6jkZGRhg3bhwaNGigdA7l4cyZM+jZsyfs7e2hr68PZ2dndO7cGStXrkRaWppSX1XeP/3791e6PUdfXx/29vbo1q0b9u3bp1JMqtYOUeW1//7771G3bl0YGRmhRYsWOH78OBYtWqTS60pERJWMICKiKqFNmzYCgAAggoODX9r/zJkziv5SqVRp288//6zYZmlp+dL+QgjRoUMHxfaFCxe+9PlHjBih6P/fH3t7e0W/devWKdo7deokrKyslPra2tqKb7/9tsgxjIyMxMOHDxXHefr0qahTp06Jz2lnZydu3bql6P/LL78otgUFBQkhhJg9e7aiLSAgQCQnJyti1NHRKfHYs2bNeul4CCHEhg0bhJ6eXrHH6NKli6Kfj4+Pon3MmDFF+pqamorY2FilMSxLfOrEcenSJfHo0SNRt25dAUDo6OiIFStWqHTe5aWs47Rq1apSx6ngfSCEKLEPADF79uwSYwoPD1fqe/PmTZXPZ9CgQYr9Zs6cqbTN29tbse2zzz57af+rV68qxZGZmVnqc8fExAgjI6MSz7nw//Oqvn/69etX6jhu375d0fe/77WytKvy2s+ZM6dIH6lUKgYOHKjS60pERJULZ4QQEVUR9+/fV/xe+NvhshBC4ObNm/j6668VbX5+fq8cW3FOnDgBAPD09ERMTAwyMzNx7do1fPfddyXGf+jQIXz//feQyWTo2bMngPyaCtOmTcPWrVuRkpKCrl27AgAyMzPx22+/Kfb98MMPcffuXQBA+/btER0djYSEBAwdOhQAEB8fjwkTJpQY74wZMxQzAHr06IFDhw7BysoKcXFxmDRpEuRyOTw9PREWFobs7Gzcu3cPzZo1AwAsWrQIN27cKHU84uPjMX78eOTm5gIAJk+ejIcPH+LZs2f4888/S5z2f+zYMVy+fBlPnz6Fj48PACAtLQ07d+4EgDLHp24c0dHReOONN3Dnzh1IpVJs27YN48ePL/WcX6eXjdPTp08xZcoUyOVyAMCaNWuQmpqKEydOwNbWFgAQGhqKP/74A0D+/yuzZ89WHH/JkiWKWzRKm3VV+P9TqVQKLy8vxePPPvusSDHU0o4F5L/Pf/rpJ6X3V3n8PxseHo7MzEwAwJw5c5CRkYH4+HgcPXoUY8aMgampKYCyvX+2b9+uGDMhBNLS0rB9+3bF9m+++UYjsb/stY+NjcUXX3yh6P/TTz9BJpNhx44ditebiIiqFhZLJSIiZGdnF1uLwNTUFAsXLiyX52zQoAGioqIQFxeH9evXo0GDBvD09MSECRMwZcqUYvfx8/NTJC46deqEPXv2AAD8/f0xaNAgAPlJiv379wMAoqKiFPsWvgVk8eLFcHV1BQB899132Lx5M4D8D0zPnz+HpaWl0vNu374d6enpAIBRo0Zh1apV0NPL/xN64MABRa2He/fuoUWLFkXiFkLgyJEjitorxfnrr78Ux2nSpAm+++47xWvy1ltv4a233ip2v08++URRzLZ3794IDw9XOveyxqduHMOGDUN6ejrMzMywa9cutG/fvsRzLbBr1y706dPnpf2K4+bmpvT6vszLxmn//v2KlVMCAwMRHBys+H3cuHGKhMSuXbvQq1cvtWL+r9zcXOTk5EBfX7/M+3755Zf48ssvi7T37NkTnTt31kR4SurXrw8dHR3I5XIcPXoUTk5OqF27NurXr69UfLks759bt25h4cKF+OeffxAbG4vs7Gyl5yycNHoVL3vt//77b+Tk5AAAfH19MXbsWABA9+7dMWjQIISGhmokDiIiqjg4I4SIqIqoXbu24vfr16+rfRx9fX3UqlULwcHBuHTpEpo0aQIAMDAwUPTJzc1VfHNeoPCHmJfVNQCAH3/8ER07dkRGRgY++eQT9O3bF40bN0aNGjXw/vvvKy0bWsDDw0Pxu5GRkeL3wudekKAA8lfAKYgtJSVF0V6rVi3F79bW1jAxMQGQnxCIj48v8rwFSRAA6NKli9JzqFpbRCaTlbq98HG8vb1LLJL5X4WTKwXnAfx77mWNT904CsbI1dVV8Z6pSF42TnFxcYq2wu8PID/pUkDV8SxJ4fdqXl4ebt++rXj82WefQQiB999/v0zHNDMzg6+vL7777jvFLAdA+f/Z/yYZCj8uqM9Rmrp162LVqlVwdnbGP//8g7Fjx6JDhw6oWbMmGjZsqJjhper75/Hjx2jdujU2bNiAqKioIvEB/742r+plr31iYqKizd3dXWnf/74XiIioamAihIioiij8zfrmzZvL9G15waoxQgjF8rlr1qyBp6enoo+Tk5Pi97y8PKXjCyGUiiA6Ozu/9DldXV1x6NAhPHv2DOfPn8dvv/2GLl26IDU1FcuWLcOvv/5aZJ/CCYjCCn+IKy6BIpVKYWFhoXhcOPakpCTFh3iJRAI7O7si+7ds2VKx//Dhw7F161bFtsL93377baWp/oV/Ct9GUZzCq/m87Daawgqfe3EfOssan7pxdOrUCUB+Eq5Dhw5ISkp66T69e/cuMZ6X/ZTl/Q28fJzs7e0Vv//32NHR0cX2UzVJVFizZs2UPlyrO+OqYNUYUWj53ClTpij9P1L4/9n/zq4o/NjR0RG6urovfc7g4GDExMQgMjISR44cwfLly2FhYYHr169j4MCBAFR//+zatUuRnGzTpg0ePnwIuVyusVkghb3stS+49QkAHj58qLStrO8zIiKqHJgIISKqIsaPH4969eoByF9Kt3Pnzti7dy/S0tIgk8kQERGBhQsX4pNPPlHr+Pb29kq3VXzwwQd48uQJnj9/js8//xxPnjwBABgbG6t0W8Tw4cOxcOFC3L9/H/Xq1UO3bt0U09cBKH1Trgm9e/dW/D5z5kzExMQgMTERU6dOVbS/+eabRW6LAfK/Ud6/fz/MzMyQl5eH4cOHY8uWLQCArl27wtDQEADwxx9/4Ntvv0VycjJSU1Nx9epVfP/992jZsqXSrJLidOvWDcbGxgCAy5cv491338WjR48gk8lw4MCBMs8SKFDW+NSN48svv8Q777yj2K99+/ZK37RXdIXH6eTJk1i7di3S0tJw6tQp/PTTT4p+hd9HNWrUUPx+/fp1lWYwSCQSfPXVV4oP5Js3b8a4ceNw48YN5OTkICUlRfH/0qvq0aOH4ve//voLO3bsQHp6Om7cuKFUE6Nwv5JcunQJ3bt3x65duyCEQGBgILp166ZIED59+hQymUzl90/hhI2hoSHMzMwQGxur9vv8VbRv316RLDl9+jQ2bNiAtLQ07Nu3D9u2bXvt8RAR0WtQLiVYiYhIK6KiokTTpk1LXYlhzJgxQoiXrwJTnLNnzwpjY+MSjy2RSMQPP/yg0rECAgJKPc7JkyeFEMqrxhRetWPVqlVFzkkIIVasWKFoHzdunKI9NjZWeHh4lPicNjY24saNG4r+xa0a888//yjOX1dXV2zevFkIkb/KTmmrjQAQqampLx2TDRs2CF1d3TKv1lLg66+/VrRPnTpV0V7W+NSNQy6Xi5EjRyraGjduLBISEl563uWlrOO0cuVKIZFIShyjYcOGKR2/8P9DhX8OHTr00thWrlwppFJpqa8JADF//nzFPqWtAlOS4lZMKfzj5uamtHpKSS5cuFDqcVq1aqXoq8r7Jzo6WpiZmRXZPnToUMXv1tbWimO+yqoxqrz2Ja0aM2DAAMXjjz/+WKUxJyKiio8zQoiIqhA3NzecO3cOa9euRbdu3WBvbw99fX1YWVmhcePGmDp1aomFSFXh6+uLiIgIjB07Fp6enpBKpdDX10fNmjXRt29f/P3335g4caJKx9q6dSu++OIL+Pn5wdbWFrq6urC1tUXXrl1x4MABBAQEqB1ncRwcHBAeHo7Zs2ejQYMGMDQ0hIGBATw9PTF58mRcvnwZ9evXL/UYbdq0we7du2FoaIi8vDyMGDECmzdvxjvvvINTp05h0KBBcHJygr6+PqytrdG8eXO89957CA8PV6yqUZoRI0bgwoULGD58OFxdXWFgYAAnJyeMHDkSP/zwg9rnXtb41I1DIpFg7dq1isK1V65cqVQzQ8aNG4d//vkHffr0gb29PfT09GBhYYE2bdpg/fr1+OWXX5T6t27dGosXL4abm5tKt5b897lu3LiB999/H02aNIGZmZni/6XmzZtj7Nix2LNnzyvPkFi9ejU2btyIjh07wtraGrq6ujAxMUGjRo0wa9YsXLx4Uel2lpI0b94chw8fxsiRI+Hl5QVDQ0MYGhqiXr16mDp1Kvbt26foq8r7x9XVFfv370dgYCBMTU3h4OCAWbNmYdmyZa90vur67LPP8N1336F27dqQSqVo3rw5Dhw4ABcXF0UfMzMzrcRGRESaJxGimJupiYiIiIiqOV9fX5w/fx4AsGfPHpVuIyIiooqPM0KIiIiIqFr766+/MH78eISFhSEtLQ0xMTGYMWOGIglSs2ZNdOzYUctREhGRpnBGCBERERFVa7t27VJaeaswExMT7NmzB+3atXvNURERUXlhIoSIiIiIqrWcnBxs3rwZa9aswfXr15Geng5nZ2d07NgRM2bMUFpKnIiIKj8mQoiIiIiIiIio2mCNECIiIiIiIiKqNpgIISIiIiIiIqJqg4kQIiIiIiIiIqo2mAghIiIiIiIiomqDiRAiIiIiIiIiqjaYCCEiIiIiIiKiaoOJECIiIiIiIiKqNpgIISIiIiIiIqJqg4kQIiIiIiIiIqo2mAghIiIiIiIiomqDiRAiIiIiIiIiqjaYCCEiIiIiIiKiaoOJECIiIiIiIiKqNpgIISIiIiIiIqJqg4kQIiIiIiIiIqo2mAghIiIiIiIiomqDiRAiIiIiIiIiqjaYCCEiIiIiIiKiaoOJECIiIiIiIiKqNpgIISIiIiIiIqJqg4kQIiIiIiIiIqo2mAghqmQmT54MS0vL1/68ixYtgkQiwfPnz0vtp634KrKZM2eiadOmEEJoO5TXasqUKfDz89N2GERE1ZKDgwNCQkK0HUaxDA0NMW3aNG2H8Uq2b98OiUSCsLAwbYdSZmfOnIG+vj7u3r2r7VBeqyNHjsDIyAhRUVHaDoUqACZCqNqYNWsWJBIJAgICtB3KS4WEhMDGxkbbYbx2VfG8IyMj8e2332LevHmQSCRFtp84cQJ9+/aFo6MjDAwM4ODggL59++Kff/4p0jc3NxeHDh1CSEgIrK2tIZFIsH379leOsSwxyGQyLF++HP7+/rC0tISNjQ38/f2xYcOGIome2bNn4/Lly9iyZcsrx0hEVJGlp6fjyy+/RJMmTWBhYQEbGxsEBATgm2++wbNnz7QdnlZYWlpi/Pjx2g6jStu7dy8kEglOnjyp8j5CCEybNg0jRoxAnTp1imx//Pgxpk6dirp168LQ0BAWFhYICAjAypUrkZubW6T/9evXMWfOHNSvXx8SiQTDhw9/pXMqawxyuRx//vkn3n77bTg5OcHU1BT169fHJ598UuT/vQ4dOqB169aYOXPmK8dIlR8TIVQt5ObmIjQ0FM7Ozjh9+jSuX7+u7ZDU9v333790VgZVHF999RUcHBzQs2fPIts+//xzvPnmm6hZsyaOHz+OtLQ0nDx5Es7Ozmjbti0+//xzpf4HDhzAkiVL0Lp1a8yfP18j8ZU1hlWrVuHp06f47rvv8PjxY1y5cgVt27ZFUFAQPv74Y6W+BQmVL774QiOxEhFVRLm5uejYsSMWLlyImTNn4v79+7h//z5CQkLwxRdf4JNPPtFKXE+fPsXq1au18txUcR05cgTnz5/HlClTimw7deoUGjVqhAsXLmDNmjV49uwZ7t+/j1GjRmHWrFno3Lkz0tPTlfYZOHAgdHR0NPalR1ljuHz5Mn755RdMmDABERERePz4MT7//HMsX74cbdu2LZI4mTRpEn777Tfcu3dPI/FSJSaIqoHff/9dABAnTpwQ1tbWYtq0adoOqVRjxowR1tbW2g5DycKFCwUA8ezZs1L7TZo0SVhYWKj1HBXxvF9Fenq6MDc3F7Nnzy6ybffu3QKA+PDDD4vd98MPPxQAxJ49e4rdvmXLFgFA/Pbbb2rH96oxFNa8efNiX7u//vpLABAnT55UO04ioorswIEDAoBYsmRJkW2PHj0S33//vRai0j4LCwsxbty4YrdJpVIxderU1xuQhv32228CgLhw4YLWYtizZ4/i+lZV/fr1Ew0aNCjSnpiYKGxtbUWzZs1ERkZGke2nTp0SOjo6YsyYMcUeNzMzUwAQw4YNU/0ENBxDYfPmzSt2bLKysoSFhYWYMWOG2nFS1cAZIVQtrFq1Ci1btkRgYCBGjx6NX375BdnZ2UX6DR8+HM7OzkhISED//v1hbm4OZ2dnrFixAgAQFxeHAQMGwMLCAra2tpgzZ06xz/fXX3+hTZs2MDU1hYmJCQIDA/Hnn38W+1yJiYkYOnQorKys0LJlS3Ts2BFr1qxBUlISJBKJ4icxMRFA0Rocx44dU+r335/CLl26hN69e8Pa2hpSqRQNGjTATz/9VCT+zZs3w9vbG4aGhmjQoAF27dpVluEuYsGCBUoxWVhYoEOHDvj7778VfV523qrGXzCuz58/x7Bhw2BhYYEaNWogJCQEGRkZRWK7dOkS+vXrBzs7OxgbG6Nly5bYunUrgPzZEjo6OsXeQ7tkyRJIJBLcuHGjxPM+fvw4ZDIZ2rdvX2TbvHnzYGlpiU8//bTYfT/99FNYWlpi3rx5JR7/VWkyBn19fZiYmBRpf+ONN6Cnp4c//vjjleMlIqqIkpOTAQBOTk5Ftjk5OWHSpElF2jds2IDWrVvD1NQUNjY26N27N65du6bYnpubiwULFqBevXqQSqWwtbXF0KFDERkZqXScglob//zzD1q3bg1DQ0MsWrQIQPE1Qgr6nz17VtHfw8MDq1atKhJjRkYGpk6dCnt7e5iamqJr166IiopCixYt0LFjxxLH4/nz55BIJEhJScFPP/2k+Hvetm3bIn1ViaO0c4yMjMTQoUNha2sLqVSKevXqYcGCBUqzAL755htIJBI8ffpU6bjXrl2DRCLBxo0bldqvXLmCTp06wdjYGPb29vjoo49w/fp1SCQSrF+/vthzXrp0KVxcXGBkZIQ333xT6bUE/q0ncuHCBcybNw81a9aEsbEx2rdvj4iICKW+qsb7/fffK2abtmnTRjHOpc0Cys3NxYEDB4q9LlmxYgUSEhLwxRdfwMjIqMh2f39/9O/fH+vXr0dMTEyJz/EqNBmDvr4+ABS5NpFKpfD39+d1CXFGCFV9MTExQldXV6xbt04IIcT9+/eFRCIRW7ZsKdJ32LBhwtHRUQwePFgcP35cpKSkiOXLlwsAYvfu3aJHjx7i77//FikpKWLFihUCgNi6davSMbZu3SokEomYMGGCiImJEY8ePRJTpkwREolEbNy4schz9enTRxw4cEAkJyeL9evXCyFKnxmhyoyL8PBwYWJiopTxP3bsmJBKpWLgwIHi9u3bIiUlRWzcuFGYmJiI+fPnK/pt2LBBABAzZ84UsbGxIjIyUgwbNkz07NlTIzNCcnNzxYMHD8TYsWOFoaGhuHHjhmJbaeetavwF4zp06FBx8OBBIZPJxO7du4WRkZF4//33lY555MgRYWBgIHr27CmuXLki0tLSRHh4uBgyZIh49OiRiIuLEwYGBmL69OlK+8nlclG7dm3RunXrUsfio48+EgBESkqKUntCQoIAIPr06VPq/r179xYSiUQkJiYW2faqM0I0EYMQQsTFxYkvvvhC6OnpiQ0bNhTbp0mTJi8dKyKiyur+/ftCX19ftG7dWjx69Oil/adNmyb09fXFF198IR4+fCiSk5PF7t27RUhIiKLPgAEDhLGxsdiwYYN4/vy5uHjxomjWrJmws7MTMTExin5SqVR069ZN9O7dW9y6dUtER0crZvHZ29sX+eZcKpWK7t27i0GDBonbt2+LpKQk8d577wkA4syZM0p9e/ToIaysrMTvv/8uUlJSxJkzZ0T37t1FgwYNRIcOHV56ni+bEaJqHCWdY0xMjGL2QHh4uHj+/Ln45ZdfhLGxsRgwYIBi/6+//loAELGxsUrHvXr1qgAgfvnlF0VbZGSksLS0FG+88Ya4ceOGSE5OFitWrBADBgwQABTXkkL8OyNk2LBhYtmyZSIxMVHcunVLNGrUSNSpU0fk5uYW6duvXz/x1VdfKfq2a9dOmJubi3v37qkVb1lnhJw/f14AEKGhoUW2BQQECKlUKl68eFHi/uvXrxcAxJo1a4ps08SMkFeNQQghUlNTxb59+4Stra0YOHBgsX3mzJkjAIinT5+qHStVfkyEUJU3d+5cUaNGDZGZmalo69q1q2jfvn2RvsOGDRMAxP79+5Xavb29hYmJidi7d69Se6NGjUSnTp0Uj+VyuXB2dhbNmzcvcuzWrVsLe3t7xR/GgufasWNHkb6vkgiJjo4Wjo6OwsHBQURFRSna69evLxo3bqz0h1kIIT777DNhaGgokpOTRV5ennBychJvvvmmUp8XL14IV1dXjd8aY2trq3RbRmnnrUr8Qvw7rvv27VPqN3r0aGFubq7UVqdOHVG/fv0ixyxsyJAhwsrKSmmKZsHtHqtWrSr1/IYPHy6MjY2LtIeHhwsAL71Fa+rUqQKAuHjxYpFtr5oIedUY3nzzTQFAABCGhobixx9/LPEYXbt2FY6OjmrFSURUGaxfv15YWFgIXV1d0apVKzFu3DixefPmIn8zIyIiBADx0UcflXis06dPCwDiiy++UGqPjIwUenp6SskFqVQqzM3NhUwmK3KckhIhtra2Ii0tTdGWnZ0trK2txejRoxVtJ06cEADEDz/8oLT/uXPnBACNJEJUiaO0c5w4caLQ09MT9+/fV2ovuJW3IDlQlsTCuHHjhKGhoYiLi1PqO3ny5BITIWPHjlXqW3Db6ZEjR4r0DQoKUuqbmJgoTExMxMiRIxVt5ZkI2b59uwAgDh48WGSbi4uLqFWrVqn7Hz16VAAQn376aZFtmkiEvEoMBeNW8DNkyJBib68RQoiVK1cKAOLcuXNqx0qVH2+NoSpNLpdj7dq1GD16NAwNDRXtEydOxNGjR3H//v0i++jr6xeZ8unl5YWsrCx07txZqb1+/fp48OCB4vHt27fx6NEj9O3bt8hx+/Xrh7i4OKXpkhKJBD169FD7/P5LJpOhe/fuSElJwd69e+Hm5gYAuH//Pm7evIm+fftCV1dXaZ+OHTsiKysL58+fx+3bt/H48WP06tVLqY++vj7eeuutV4rrgw8+UFT/Lpi+mZCQoFKxKlXjL6Cnp1fktWrYsCFkMpniVpu7d+/i7t27GDRoUJFjFjZp0iQ8e/ZMcbsMAPz4448wMTHBoEGDSo37+fPnMDMzK9IuVFxGt6BfafGp61VjOHbsGORyOWJiYjBr1ixMmjQJs2fPLvYY5ubmLPBLRFVaUFAQnjx5gt9//x1du3ZFTEwMRo8ejdq1a+P3339X9Nu3bx8AYOjQoSUe68iRIwBQ5FqiVq1a8PHxUWwv0K5du2L/1pSkbdu2SrcLGBgYoG7dukrXM0ePHgWAIoW+W7VqBTs7O5Wf61XjKFDcOR45cgRNmzaFh4eHUnv//v0V28vq6NGjxZ7jf6+LCuvevbvS44YNGwJAsefx3+NYW1ujTZs2SrcKl6eCv8XqXpuU53XJq8Ywbdo0CCGQnJyMHTt24OjRo2jTpg0yMzOLHMPc3BwAeG1SzTERQlXaoUOHEB0dja+++kqp7kSvXr0ghMCaNWuK7GNra1vkH1czMzNYW1sr7jcs3F74H9GkpCQA+ffl/ldBW+GaF7a2tjAwMFD7/ArLzc1F//79cePGDWzZsgU+Pj6KbQX3mc6bNw96enrQ1dWFrq4udHR0EBgYqIi9IH57e/sixy+uTVV9+/bFhg0b8M033yA2NhZyuRxCCNSqVQs5OTkv3V/V+AvY2dkVeQ3/+0cvPj4eQPH3dBcWEBCAJk2aKOrEPHz4EPv27cPAgQNfeuFpaWkJmUxWpL0gQRUdHV3q/g8fPgQAuLq6ltrvvzZu3FhizZgFCxZoLAaJRAJnZ2d8+umnGD58OBYtWoTHjx8X6SeTyWBlZVWmcyAiqmyMjY3Rs2dPzJ07F3/++Sfu3LkDKysrjBgxAgkJCQBU+9vzsmuJwtcRLztWcRwdHYu0/TdhXRBDcUkPTSVCVImjQHHnmJSUpPL1VnGK+9CdlJRU5nP+73mU9iG7pOurl8UKqP4FRmkKasyVdG0SGxtb6nWZutclaWlpJV6XtGjRQqMxWFlZoW/fvvjhhx8QHh5ebF2XgvPntUn1xkQIVWmrVq1Cjx49IPJvA1P6+frrr7Fu3boiy2r9t8Doy9oLq1GjBoD8oqr/VdBmY2OjaPtvYuVVjB8/HocOHcLXX39d5BuHgudcvHgxcnNzkZeXh7y8PEVCQgiBoUOHwtra+qXxl9WTJ09w5MgRvP/++3jrrbdgZWUFiUSC3NxcPHr0SKVjqBp/AVVeK1tbWwAo9oP7f02cOBEXLlxAWFgYfvrpJ+Tl5WHMmDEv3c/NzQ2ZmZlFLjhsbGzQvHlzHD16tNhvKgAgMzMTx44dg6+vr1JxXFUMHz682Pe8EEKxxK2mY2jcuDHkcjmioqKKbIuNjVUkXoiIqgtXV1eMHj0a6enpuHTpEgDV/va87Fqi8HUEUPZrCVX+RhZcDxQkbgorrk0dqsRRoLhzrFGjhkrXWxYWFgCA1NRUpX7FvQbW1tZlPueynEdJ8RaMd1njLauCv8X/LcQKAF26dEF2dnapM2n27dsHXV3dUovlFsfU1LTE65KwsLByiaFx48YAip+ZExsbC6DsCR2qWpgIoSorPj4ef/zxB7p27Vrs9m7duuHp06dFVnN5FfXq1YOTk1Oxq6zs3LkT9vb2aNCgwUuPY2JiUuyqNiX5/PPPsWbNGkydOhXvvvtusXHVrVsX27dvh1wuLzX+mjVrYs+ePUrtubm5ium86pJKpUqPN2/eXCQJVdJ5qxp/WdStWxd16tTBtm3bkJeXV2rfgtVnvv32W6xZswb16tVDQEDAS5+jYLZK4T/yBT755BM8f/68xBVZ5s2bh+fPn+ODDz5Q4WzUo8kYzp8/D11dXdSpU0epPSMjA9evX0ebNm00EjMRUUWzb98+/PXXX8VuK/jwWpBMLriNYvPmzSUer0OHDgCgdEsNkD+DLzw8XLG9PLVr1w4AilwjXbhwQeVESFmvZcqqQ4cOuHTpUpGZjTt27FBsB4DatWsDQJGVXPbu3VvkmO3atcOFCxcUM3hK66uO/15fJScn4+TJk0qvaVniLbi1SNVxbtq0KUxNTYu9LpkwYQJsbGzw0UcfISsrq8j206dPY8eOHRg6dCicnZ1Ver6y0mQMBbdM169fv9htdevWfaXZzlT5MRFCVVZoaChycnJKTITUq1cP7u7uxS7Vpi4dHR0sXrwYYWFhmDx5Mh4/fownT55g2rRpOH36NBYvXgw9Pb2XHqdhw4ZIS0vD0aNHX/oh/a+//sInn3yCt99+G8uWLSux388//4yIiAgMHjwYly9fRkZGBh4+fIjt27ejTZs2yMvLg46ODj7//HMcO3YMH330EeLi4hAdHY3g4GA0adKkzOMBADVr1oSPjw++/fZbXLp0CTKZDNu3b8e6desUf+xVOW9V4i+rlStX4v79++jbty+uXr2K9PR0XLx4EcOGDVP65sXExARBQUHYuHEj4uLiVJoNAuQvHWtubl7svb+9e/fGZ599hkWLFmHKlCm4d+8ecnJycP/+fUydOhWLFi3CRx99hH79+pX5vFSlTgxvv/02tm3bhujoaGRlZeHu3buYMWMGfvvtN3z44YdFpg//888/yM3NLfX+aiKiyqygPldISAguXbqE7OxsPHnyBF9//TVWrVqFtm3bomXLlgCAJk2aYOrUqViyZAkWLVqER48e4dmzZ9izZw/Gjh0LIH+J0L59+2LBggXYvHkzUlJSEBERgf79+8PCwqLEekyaFBgYiO7du2P27Nn4448/kJqainPnzmH+/PkqfaED5P9NP3funOLbd02bNWsWLC0t0a9fP0REREAmk2Hz5s2YP38++vbtq/gyIjAwEF5eXpgzZw5u3bqF5ORkLF++vNjbQz788ENIpVIMHDgQt27dwvPnz/Hzzz+rPSv2v1JTU/HNN98gOTkZd+7cwaBBgyCRSBSzNcsar5eXF/T09LB///5iEwf/paenh65duxZ7XWJjY4MdO3bgwYMHaN++PU6cOIGsrCwkJSVh9erV6N69O5o3b664Vbg8qBPDvHnzsGjRIly/fh0ZGRl4+vQp1q9fjylTpsDHxwfDhg1Teo7s7GycPn2a1yXE5XOp6qpbt67w9PQstc/EiROFrq6uYim6YcOGCScnpyL9goKChL29fZH2klY52bNnj/D39xfGxsbCyMhI+Pn5id27dyv1Kem5hMivnD5ixAhRo0YNIZFIBACRkJAghCi6KsuSJUuUqmT/96ewa9euiSFDhggHBwdhYGAgatWqJQYNGiROnjyp1G/Dhg3Cy8tLGBgYCC8vL7F9+3ZFFXZ1Vo2Jjo4WvXv3FpaWlsLS0lIMHDhQxMXFiXr16om3335bpfNWNf6SxnXVqlUCgLh7965Se1hYmHj77bdFjRo1hLGxsWjZsmWxSyvfunVLSCQSoaenV6bl1iZPnizc3NyEXC4vdvvRo0dF7969hZ2dndDR0REAhJ6eXpFVb4T4d8nbkn5e9tqUpCwxXLlyRYSEhIjatWsLfX19UaNGDdGhQwexbdu2Yo89bNgw0bBhQ7XiIiKqDF68eCF+//13MWDAAFG7dm1hYGAgTE1NRfPmzcWCBQuKXblizZo1wsfHRxgZGQlbW1vRp08fce3aNaVjzp07V3h6egp9fX1hbW0tBg0apLTMqhD5K6pMnTq12LhKWjWmuP5dunQRTZo0UWpLT08XU6ZMEba2tsLY2Fh06dJFREZGioYNG4q33nrrpeNy9epV4efnJ4yMjAQApRXpyhJHaed47949MWjQIGFtbS309fWFp6enmDt3bpHlV69fvy7atm0rpFKpcHR0FAsWLBBXrlwpsgqLEEJcvnxZdOjQQRgaGgo7Ozsxa9YsxUprmzdvVvQrWAnmwoULSvsX/K1esmRJkb7nzp0Tn3zyibC3txeGhoaibdu2Ijw8vMh5lSXeH3/8Ubi7uwtdXV2VVrQ7fPhwiSvSCZF/zTZ58mTFe7ngGmPq1KnFLmsbEBBQ4nVJ4VV2yqIsMSQmJorPP/9cNGvWTJiYmAhjY2PRpEkTMW/ePKVViQr89ttvQiKRiDt37qgVG1UdEiE0UHmHiKiKe/z4MVxdXdGrV68i05VLExUVBS8vL/z6668qffuwZcsWDBs2DEOHDsUvv/xSpnuPNUVTMTx9+hQeHh5Ys2YNhgwZouEoiYhIGwqKURZXcL6q+vPPP9GjRw/8/fffituGymL79u0YMGAALly4oFQcVFv8/PxQv359rF279qV9IyMjERAQAGNjY5w4caLYIrflTZMxtGvXDnZ2dti2bZsGI6TKiLfGEBGpoKA+yTvvvFOm/WrVqoVp06bh008/Vani+5AhQ/Dtt99i06ZNmDRpkrrhvhJNxfDFF1+gSZMmGDx4sAajIyIibfn777/x/PlzvPnmm9oO5bXasWMHjI2NFbc4VXbLli3DL7/8grt37760r7u7Ow4cOICkpCR06tRJaZW+10VTMfz99984c+YMvvzySw1HSJURZ4QQEb3Ew4cP0a5dO1hYWCA8PFwrszSIiIhep3Xr1iEjIwM9evSAlZUVTp06hfHjx8PMzAzh4eFFiqBXFRMmTECfPn3QqlUrpKWlITQ0FHPmzMHHH3+Mzz77TK1jVrQZIUTEGSFERKXy8vKCp6cn7O3tsWXLFiZBiIioWujduzfu3LmDjh07wtbWFiEhIejcuTOOHj1aZZMgADBq1Ch8++23qFevHjw9PbFt2zZ8++23aidBiKhi4owQIiIiIiIiIqo2OCOEiIiIiIiIiKoNJkKIiIiIiIiIqNrQ03YA2iCXy/HkyROYmZnxfn8iIiINEkIgNTUVNWvWhI4Ov2/5L16DEBERlY+yXINUy0TIkydP4OLiou0wiIiIqqyYmBg4OztrO4wKh9cgRERE5UuVa5BqmQgxMzMDkD9A5ubmGjmmXC5HQkICbG1t+Q1YMTg+peP4lIxjUzqOT+k4PiUrr7GRyWRwcXFR/K0lZbwGef04PqXj+JSMY1M6jk/pOD4lqwjXINUyEVIwFdXc3FyjFyFZWVkwNzfnG70YHJ/ScXxKxrEpHcendByfkpX32PC2j+LxGuT14/iUjuNTMo5N6Tg+peP4lKwiXIPwFSEiIiIiIiKiaoOJECIiIiIiIiKqNpgIISIiIiIiIqJqg4kQIiIiIiIiIqo2mAghIiIiIiIiomqDiRAiIiIiIiIiqjaYCCEiIiIiIiKiaoOJEA3IkwucfZCEg7eScfZBEvLkQtshEREREREREVEx9LQdQGW3/1os5u65gdiUrP+1RMLRwhBzenqja0NHrcZGREREREREVFHkyQXOPUjCvUfJ8EzTha+HDXR1JK89DiZC1BAvy0J8ajZO30vEF3/dKrI9NiUL4zdexEfdvODvaQM7MynszA21ECkRERERERGRdhR8dgaA0/cS8fOJB0hMe/G/rZGwMTXA2DYe8Pe0AYDX9tmZiRA1bDr3EN8eufvSfgVJkqkd6mB6p7rlHRYRERERERFRhfGyz86JaS+UJhe8rs/OrBGihmG+rviiT0OV+n7RpyGG+bqWc0REREREREREFcswX1fsnhQAG1ODUvvZmBpg96SA1/bZmYkQNdiZG8JEqtpkGhOpHm+LISIiIiIiomrHztwQGS/yCt0OU7zEtBfIeJH32j47MxGihnhZFtKzc1Xqm56di3hZ1ss7EhEREREREVUx8amqfR5WtZ8mMBGihk3nHuKj36+p1Pej369h07mH5RwRERERERERUcUhlwscuhGHlcfuq9Tfzuz13UnBYqlqGObrik7e9iWuGlPAydIQ3w5uBtcaxq8xOiIiIiIiIiLtyHiRix3hj7D2VBQiE9Nf2l8CwMHCEK3ca5R/cP/DRIga7MwNYWduiIZOFnC1NsbcPTcQm/LvNB5bMynSs3Px+HkWVh5/gJXDm2sxWiIiIiIiIqLyFSfLQujpKGw69xApmTkAADNDPXTxdoCDhRTfHy1+ZogAMNq/Fm7Gyrh8bmXRtaEjOnk74NyDRNx7lABPZ1v4etjg4sNnGLb6HA7fjMOnf1zH570bQiKRaDtcIiIiIiIiIo25/iQFa05EYs+VJ8jJEwAAN2tjBAe442lKFlYcf/mtMQV3Wryu5XOZCNEAXR0JWntYw8M0D3Z21tDRkaBlrRr4bnBTTNh0EZvPPYSjuSGmdKij7VCJiIiIiIiIXolcLnD0djxWn4jEmQdJivZWtWpgTBt3dKxvD10dCeJlWeje2FGxPU8ucO3xc8TEP4OLnRUaOllCV+ffCQN2ZtLXEj8TIeWoa0NHfNazAeb8cR1fHboDewtDDGzhou2wiIiIiIiIiMos80Uedlx8hLUnI/Hgf/U/dHUk6N7IEWMC3dHExVKpf0FZicIaOZkjPt4QdnZ20NHRzvotTISUsyD/Wngqy8KKY/cxa+dV2JpJ0a6enbbDIiIiIiIiIlJJvCwLG85EY+O5aDzP+Lf+x9BWrgjyr4WalkZajrBsmAh5Df6vSz3EpWRh56XHmLjxIraObV0kU0ZERETlSyaT4fnz53B2di7xG6jU1FQkJSXByckJ+vr6avchIiKqCm48kWHNyUj8cfmxov6HSw0jBAe4Y0ALF5hKK2dKQTvzUKoZiUSCRf0ao00dG2Tm5CF4/QVEJ718GSEiIiJ6ddevX4efnx+cnJzg6+sLNzc3HDhwQKlPbm4uxo0bBxsbG7Rq1Qr29vbYtGlTmfsQERFVdnK5wNFb8Ri2+ize+u4Edlx8hJw8gRZuVlg5vDmOzWiH0QHulTYJAjAR8toY6OlgxXAfNKhpjqT0Fxi59jwS07K1HRYREVGVlpeXh7fffhvOzs5ISEhAbGwsFi5ciD59+uDhw4eKfosWLcLvv/+Oq1evIj4+HkuXLkVQUBCuXLlSpj5ERESVVVZOHjafe4hOXx/H6PUXcOpeEnR1JOjR2BG/T/TH9gn+6NrQUam4aWWl1URIVFQUpk+fDl9fXwQEBGDmzJlITk7W+D4VhalUD+tGt4SzlRGikzIwZv0FZLzI1XZYREREVdbt27dx//59zJgxA4aG+cXahg8fDnt7e6xdu1bR76effkJISAjq1s1fsi84OBienp5YtWpVmfoQERFVNvGpWVh28Db8F/2Nj36/ivsJ6TCT6uGdNu44/kFbfD+0OZq5Wmk7TI3SWiIkLy8PXbp0Qa1atbB8+XJ8/vnnOHbsGDp06IDs7OJnSqizT0VjZ2aI0OBWsDLWx+VHKZi06SJy8+TaDouIiKhKMjU1BQClL01yc3Mhk8lw/vx5AMDTp0/x6NEjtG7dWmlfPz8/hIeHq9yHiIioMrn1VIYPfruMwEVH8d3f95Cc/gLOVkb4pIc3Ts9qj9ndveFsZaztMMuF1m7q0dXVxfXr16Gn928IGzZsgJeXF86dO4c33nhDI/tURLVtTbFmVEsMXXUWR28nYPbv17CoXyNIJJV/ihEREVFF4urqis6dO2PatGkQQsDGxgbfffcdsrKykJiYCABISkoCANjY2Cjta2Njg1OnTqncpzjZ2dlKX9bIZDIAgFwuh1yumS9C5HI5hBAaO15Vw/EpHcenZByb0nF8SldRx0cIgX/uJmLNyUicvJekaG/uaonggFro7G0PPd38+RLlFXt5jU1ZjqfV6iaFExpA/osCoNSEgDr7VETNXa2wfEhzjPslDNvCYuBgYYjpnepqOywiIqIqZ/v27ViyZAkWLlyIzMxMDBw4EEIIREdHA8j/ogUAXrx4obRfdna24rpDlT7FWbhwIebOnVukPSEhAVlZWeqfVCFyuRwpKSkQQpS4Gk51xvEpHcenZByb0nF8SlfRxicrV44Dt5Kx9WIcIpPz//7oSIB2nlYY3MwOjWr+bwZlUmK5x1JeY5Oamqpy3wpV5vWTTz5BrVq10KpVK43uU1G/jengZYt5vRrg493X8e2Ru7A3l2JwSxeNxFPRVNSMaEXB8SkZx6Z0HJ/ScXxKVhG+jXldzMzMMG/ePKW2hg0bws/PDwDg5OQEiUSC2NhYpT5Pnz6Fs7Ozyn2KM2vWLLz33nuKxzKZDC4uLrC1tYW5ufkrnVcBuVwOiUQCW1vbCnGxXdFwfErH8SkZx6Z0HJ/SVZTxSUzLxsazD7Hp3EMkpecn802luhjYwgWj/N20cutLeY1NQS0wVVSYRMhnn32Gffv24e+//4ZUKtXoPhX525iO7oZ44OuItedi8fGuazDIy0Sgh6VGYqpIKlpGtKLh+JSMY1M6jk/pOD4lqwjfxrwuubm5SrM2zp49i+vXr2P58uUA8hMlPj4+2L9/P4YMGQIgf+bH4cOHMWPGDJX7FEcqlRZ7jaKjo6PRcZdIJBo/ZlXC8Skdx6dkHJvScXxKp83xuROXijUnIvF7xGO8yM3/ksLJ0gijA2phUEsXmBnqv/aYCiuPsSnLsSpEImTRokVYsmQJ9u7dC19fX43vU9G/jZndyxayXB1sD3+Mj/+KxOYQXzR1sdRIXBVFRcmIVlQcn5JxbErH8Skdx6dkFeHbmNdl7ty5sLS0RLt27XD79m3MmDEDY8eORbt27ZT69OrVC40bN4afnx+WLVsGQ0NDjB8/vkx9iIiItEUIgRN3E7H6ZCT+uZOgaG/qYol32nigS4N/639Ud1pPhHz55ZeYN28e9u7dq3RBosl9KsO3MQv7NkZi2gscu52AkA3h2D7eDx62phqLrSJgxrh0HJ+ScWxKx/EpHcenZNr+NuZ1mTVrFhYsWIBx48bB0tIS8+fPx+jRo5X6vPXWW9i1axe+++47bNiwAY0aNcLJkydRo0aNMvUhIiJ63bJy8vBHxBOsPvkAd+LSAOTX/+ja0AFjAj3g41a1lr7VBK0mQpYuXapIaLRv377YPh999BEiIiKwb98+lfepjPR1dfDD0OYYsuosrjxKQdC689g5IQC2ZqrdJkRERETFMzY2xhdffIEvvvii1H49evRAjx49XrkPERHR65D0v/ofv5yNQmJafv0PEwNdDGzpguAAd7jUqJpL32qC1hIhz549wwcffABTU1OMHTtWadvChQsxYMAAAEB8fDwePnxYpn0qKxOpHtaOaol+K04jOikDo9efx9axfjCVan3iDhEREREREVUAd+NSsfZUJHZc/Lf+R00LQ4wKqIVBLV1hYaTd+h+VgdY+YVtYWODu3bvFbrOzs1P8vnDhQkVBU1X3qcxsTKUIHd0K/VacxrXHMkzcdBFrglpAn/dyERERERERVUtCCJy6l4TVJx/g2O1/6380drZASBsPdGvowM+MZaC1RIiOjg48PT1f2s/W1rbM+1R2tWxMsGZUSwz5+Sz+uZOAD3dcxdIBjSGRSLQdGhEREREREb0m2bn59T/WnIzEraf5K7NJJEBnb3uEtPFACzcrfk5UA++5qKCauljih2HN8M6GcOy4+AiOFoaY0aWetsMiIiIiIiKicpac/gKbzkYj9Ew0EtOyAQDGBroY2MIFowNqwc3aRMsRVm5MhFRg7b3s8UWfhpi54yq+P3oP9haGGNHaTdthERERERERUTm4F5+WX/8j/BGy/1f/w9HCEKP8a2FwS1dYGLP+hyaonQhJT0/H4cOH8eDBA0yfPh0AcOfOHdSpU4dTczRoUEtXPE3JxteH72DO7muwM5OiSwMHbYdFREREREREGiCEwJn7SVh9MhJ/34pXtDdyskBIG3e81ciR9T80TK1EyJ07d9C5c2dkZWUhLi5OkQiZP38+unfvjsGDB2s0yOru3Q6eeCrLxJbzMXh3yyVsfscXPm41tB0WERERERERqelFrhx7Lj/B6pORuBkrA5Bf/6NT/fz6Hy1rsf5HeVErrTRt2jQMHDgQsbGxSu1Tp07F0qVLNRIY/UsikWD+2w3RwcsO2blyjAkNw734NG2HRURERERERGX0LP0Fvv/7LgK//Bvv/3YZN2NlMNLXRZCfG46+3xY/j2yBVu41mAQpR2rNCDlz5gw2b95c5IXx8vLC1atXNRIYKdPT1cHyoc0wdNU5RMQ8R9Da89g50R/25obaDo2IiIiIiIhe4n5CGtaejMSOi4+QlZNf/8PeXIpR/u4Y0soFlsYGWo6w+lArESKXy/HixQsAUEqGREVFwcLCQjORURHGBnpYE9QC/VeeQWRiOkatu4Bfx7WGmSEL5hAREREREVU0Qgicvp+INScicaRQ/Y8GNc3xThsPvNXIEQZ6rP/xuqk14p06dVLcAlOQCElMTMS7776Lrl27ai46KsLaVIrQ0a1gY2qAm7EyjN8Yjhf/qyZMRERERERE2vciV46/biah5/enMHTVORy5FQ+JBOhY3x5bx7bG3imB6N3MiUkQLVFrRshXX32Ftm3bYs+ePRBCoF27dggLC4OtrS02btyo6RjpP1ytjbFuVCsM+vkMTt1Lwv9tv4xlA5tCR4f3kBEREREREWnL84wX2HTuIUJPRyE+NRsAYKivgwE+LhgdUAsetqZajpAANRMhbm5uuHLlCjZu3IiwsDDI5XL07dsXQUFBMDc313SMVIxGzhb4cVhzhISGYVfEE9hbGGJWt/raDouIiIiIiKjaiUxMx9qTkdge/giZOXkAABsTfYwKcMcwXzdYmbD+R0WiViIEAMzMzDBhwgTF46ioKOjpqX04UkPbenZY1K8xZvx2GT8dfwAHc0OMDnDXdlhERERERERVnhAC5yKTsfpEJI7cioMQ+e3ejuYYE1gLrRx04eToAB0d3v5S0aj1ioSHh2PKlCmKx8OHD4e7uzscHBxw+vRpjQVHL9ffxxkfdKkHAJi39wb2XY19yR5ERERERESkrpw8OXZdeoye35/E4J/P4vDN/CRIBy87bH7HF3++G4g+zZygr8sESEWl1hSOGTNmYP78+QCAa9euYc+ePTh79iwOHjyIWbNm4fjx4xoNkko3sW1tPE3Jwi9nozFtWwSsTQzg62Gt7bCIiIiIiIiqjJSMHGw+n1//46ksC0B+/Y9+zZ0RHOiO2oXqf4iC6SFUIamVCAkLC4OPjw8A4ODBg+jTpw98fX3RoEEDxWoy9PpIJBJ81qsB4mRZOHgjDu9sCMP2Cf6oa2+m7dCIiIiIiIgqtajEdKw7FYlfw/6t/2FrJkWQnxuG+rqhBut/VDpqJUJMTU0RFRWF+vXrY+/evRg1ahQAICUlBaamrIKrDbo6Enw3pBmGrT6H8OhnCFp7Hjsn+sPRwkjboREREREREVUqQghciHqG1Sce4NDNf+t/eDmYIaSNB3o2cYRUT1e7QZLa1EqE9O/fH927d0fDhg0RERGBnj17AgAOHDiAbt26aTRAUp2hvi5Wj2yB/itP435COkatvYBfx/vBwkhf26ERERERERFVeDl5cuy7Gos1JyNx5VGKor1dPVuEtPGAf21rSCQSLUZImqBWImTZsmXw9PREdHQ05s6dCysrKwDArVu3MGfOHI0GSGVjZWKA0OBW6PvjadyOS8W4X8IQGtyK2UoiIiIiIqISpGTmYOv5h1h/OgqxKfn1P6R6Oujb3BljAmvB045lB6oStRIh+vr6mDp1apH2xYsXv3JA9OqcrYyxbnRLDPrpLM4+SMb7v17Gd4ObQUeHmUsiIiIiIqICD5MysPZUJH4Ni0HGi/z6HzamBhjpVwvDfF1hbSrVcoRUHtRKhBS4d+8ebt68CSEEvL294enpqam46BU1qGmBn0b4YNS689h7JRYO5ob4uIe3tsMiIiIiIiLSKiEEwqOfYfWJSBy48VRR/6OevRnGtHFHryY1YajPGfVVmVqJkJSUFAQHB2Pnzp3Q0clfG1kul6Nv375Yu3YtLCwsNBokqSfA0wZL+jfBtG0RWH0yEg4Whghp46HtsIiIiIiIiF673Dw5/rr2FKtPRuJyzHNFe9t6thgT6I5ATxvW/6gm1EqETJs2Dffv38eJEyfg6+sLADh37hwmTZqE6dOnY+3atRoNktTXu5kT4mRZWPjXLSz48ybszA3Rq0lNbYdFRERERET0WsiycrDtfAzWn47C4+eZAAADPR30a+6E4AB31LFn/Y/qRq1EyO7du3Hq1CnUr19f0RYYGIitW7ciMDBQY8GRZox9wwOxKVlYfzoKM369DBtTA/jXttF2WEREREREROUmJjkD605FYduFh0gvVP9jROtaGNbaFTas/1FtqZUIyczMhI1N0Q/S1tbWyMjIeOWgSLMkEgk+6eGN+NQs7Lv6FOM2hOO3CX7wcjDXdmhEREREREQaFR79DGtOPsD+a08h/1/9jzp2pghp4463mzqx/geplwjx8/PDxx9/jOXLl8PAwAAAkJ2djdmzZ8PPz0+jAZJm6OpIsGxgUySmnsf5qGQErT2PnRMD4GRppO3QiIiIiIiIXklunhwHrsdh9ckHuPTwuaK9TR0bhLTxwBt1WP+D/qVWIuTrr79Gly5dsGvXLjRp0gQAEBERAR0dHRw4cECjAZLmGOrrYtXIFui/8jTuxqdh1Nrz2D7eHxbG+toOjYiIiIiIqMxSs3Kw7UIM1p0qVP9DVwe9m9XEmEAP1HNg/Q8qSq1ESJMmTXD37l2Ehobi+vXrkEgk6NWrF4KCgmBmxjdaRWZhrI/Q4Fbo+2N+MuSdDWHYMKYVp4cREREREVGl8ehZBtafisLWCzFIy84FANQwMcDw1m4Y0doNtmas/0ElUysRAgBmZmaYPHmyJmOh16SmpRHWB7fEgBVncD4qGdO3ReD7oc2hq8OpYkREREREVHFdevgMq09G4q+rsYr6H552phgT6I4+zVj/g1SjdiIkISEBq1evxs2bNwEA3t7eCAkJKbaIKlU8Xg7m+GmkD0atvYC/rj3FvD3X8VmvBrxvjoiIiIiIKpQ8ucDB60+x+mQkwqOfKdoDPW0wpo073qxjCx1+qUtloKPOTseOHYOHhwdWrVqFzMxMZGZm4ueff4aHhwf++eefMh0rJycHV69exc2bN/HixQuV94uMjMTZs2fx7Nmzl3emYvnXtsFXA/NrvISeicZP/zzQckRERERERET50rJzsfZkJNouPYoJmy4iPPoZDHR1MMDHGX9NbYONIb5oV8+OSRAqM7VmhEyZMgUTJ07EwoULoaOTn0uRy+WYNWsWJk+ejCtXrrz0GEIIzJs3Dz/++CPs7e2RkZGBjIwMrFixAm+//XaJ+2VmZmLw4ME4cuQI3N3dce/ePXzxxReYPn26OqdS7fVsUhNxsiws+PMmFv11C/bmUvRp5qztsIiIiIiIqJp6/DwToaejsOXcQ6T+r/6HlbE+RrR2w3A/N9iZGWo5Qqrs1EqE3L9/Hx9++KEiCQIAOjo6mDlzJpYvX67SMYQQEELg9u3bsLS0BADMnz8fQ4YMwf379+Ho6Fjsfp999hkuXbqE+/fvw97eHnv27EGvXr3g5+eH1q1bq3M61V5IGw88TcnC6pOR+OC3K7AxlaJNHVtth0VERERERNVIRMxzrDkZiX1XY5H3vwIgHrYmCAn0QJ9mTjAyYP0P0gy1bo2pW7cu7t27V6T9/v37qFu3rmpPrKODzz77TJEEAYCxY8ciMzMTly5dKnG/9evXIyQkBPb29gCAnj17onHjxli3bl3ZToKUfPRWffRsUhO5coHxv4Tj2uMUbYdERERERERVXJ5cYP+1WPRfcRq9fziFPZefIE8uEOBpjXWjWuLw9Dcx1NeVSRDSKLVmhIwfPx4DBgzAvHnz0LJlSwghEBYWhk8//RSzZs3Co0ePFH2dnVW/zeL8+fMAAE9Pz2K3P378GPHx8fDx8VFq9/HxKTV5kp2djezsbMVjmUwGIP92HrlcrnJ8pZHL5RBCaOx42rC4X0MkpmbhzINkjF5/ATvGt4azlbFGjl0Vxqc8cXxKxrEpHcendByfkpXX2HCsiYhIFWnZufgtLAbrTkXhYXIGAEBfV4JeTZwwJtAd3jXNtRwhVWVqJUImTJgAAAgKCiqybfz48UqPhRAqHTM+Ph6TJ0/GkCFDSpxVUlAYtUaNGkrtNjY2pRZNXbhwIebOnVukPSEhAVlZWSrF9zJyuRwpKSkQQijdMlTZzO/iinG/ZeJ+YiZGrD6Lnwd6wcJI7cWFFKrK+JQXjk/JODal4/iUjuNTsvIam9TUVI0di4iIqp4n/6v/sfn8Q6Rm5df/sDTWx3BfN4z0c4OdOet/UPlT6xNuwZK5mvLs2TN07doVzs7OWLVqVYn9DAwMAOQXTC0sIyNDsa04s2bNwnvvvad4LJPJ4OLiAltbW5ibaybTKJfLIZFIYGtrW6kvtu0A/DLGCv1WnkH0syzM+isaG8e0euX1uKvK+JQXjk/JODal4/iUjuNTsvIaG0NDXsASEVFRVx49x+oTkfizcP0PGxMEB7qjX3Nn3vpCr5VaiRAvLy+NBfD8+XN07twZhoaG2L9/P0xMTErs6+zsDB0dHTx+/Fip/fHjx3BzcytxP6lUCqlUWqRdR0dHoxd/EolE48fUhppWxtgQ3Ar9VpzGxYfPMXXbZawc7gPdV1yWqqqMT3nh+JSMY1M6jk/pOD4lK4+xqajjnJeXh9u3b+PZs2dwdXWFi4tLsf3u3r2LuLg4eHl5wcbGRu0+RESUX//j8M04rDkRifNRyYp2Pw9rhLRx59K3pDVavVpJSUlB586doaenh/3798PMzKxIn9u3b+PChQsAAGNjYwQEBOCPP/5QbE9LS8Phw4fRqVOn1xZ3dVDH3gyrg1rCQE8Hh27EYc4f11S+zYmIiKgiCQ8PR926ddG1a1f83//9Hxo0aIDu3bsjPT1d0ScjIwNvvfUWWrRogSlTpsDFxQVLly5VOo4qfYiICEjPzkXo6Si0/+oYxv0SjvNRydDTkaBvMyfsnRKILWNbo0N9eyZBSGtevfiDmnJyctC1a1dER0dj1apVuHjxomJbvXr1FMvnLlmyBGfPnsW1a9cAAJ9//jk6dOiADz74AH5+fvj+++/h4OCAd955RyvnUZW1cq+Bbwc1xcTNF7Hx7EM4WhhhUrviC9kSERFVVJMnT4a3tzd27doFXV1dxMbGwtvbG99//z1mzpwJAJgzZw6uX7+Ou3fvws7ODvv27UP37t3h7+8Pf39/lfsQEVVnsSmZCD0djc3noiH7X/0PCyN9DPN1xUi/WnCw4O2TVDFoLRGSkZEBqVSK+vXrY9myZUrbPvjgA3Tv3h1AflIkLy9Psa1Nmzb4559/8OOPP+Knn35C8+bNsXXrVpiamr7W+KuLbo0c8VnPBpjzx3UsOXAbdmZSDGhR/HRiIiKiiig5ORnt27eHrm7+/eeOjo6oWbOmUqH10NBQTJkyBXZ2dgCAt956C02bNsX69esVSQ5V+hARVUfXHqdg9YkH2HslFrn/q/9Ry9oYYwLd0c/HGcYGWvvYSVSsMr0j79y5U+KKLmVlYWGBY8eOvbTfBx98UKStdevWaN26tUbioJcL8q+F2JQsrDx+Hx/uvApbMyna1rPTdlhEREQqWbhwId59913UrFkTbm5uOHjwIPLy8jB58mQA+bXGEhIS0Lx5c6X9mjdvjoiICJX7FCc7OxvZ2dmKxzKZDEB+sVpNLTXMZaJLx/EpHcenZByb0uXm5uGf+8+wfdcDnI/6N7Hs614DYwJroX2h+h/VcQz5/ilZeY1NWY5XpkRIkyZN4Orqih49eqBHjx5o06YN9PSY3asO/q9LPcTJsvD7pceYuOkito31QyNnC22HRURE9FKtW7eGj48PFi5cCFdXV9y5cwdTp05V3IZbMDOkRo0aSvtZW1srtqnSpzgLFy7E3Llzi7QnJCQgKytL/ZMqhMtEl47jUzqOT8k4NsXLzMnDnzeSsO1SPGKe5yd6dXWAjnVrYEgzO3jZ5y9+kZiYoM0wtY7vn5KV19ikpqaq3LdMWYykpCQcOnQIe/fuxfDhw5Geno4uXbqgR48e6NatGyunV2E6OhJ82a8xElKzcfJeIkavP4+dEwLgam2s7dCIiIhKJIRA165dUb9+fURFRUFPTw+xsbFo0aIFcnNzMXfuXBgYGAAAMjMzlfbNyMhQbFOlT3FmzZqF9957T/FYJpPBxcUFtra2MDc318g5cpno0nF8SsfxKRnHRlmcLAsbzkRj8/kYpGTmAADMpLoY0soVQf5ucLQw0nKEFQvfPyUrr7ExNFS9Bk2ZEiHGxsZ4++238fbbb0MIgYsXL2Lv3r347rvvEBwcjFatWilmizRq1KjMgVPFZqCngxXDm2PQT2dxI1aGoHXnsX28H6xNiy5NTEREVBE8fvwYV69exeLFixWzWB0dHdGjRw/s27cPc+fOhYuLC3R0dPDo0SOlfR89eoRatWoBgEp9iiOVSiGVFv07qelli7lMdOk4PqXj+JSMY5Nf/2PtyUjsufIEOXn59T/crI0x2r8W3nAxQC1nx2o9PqXh+6dk5TE2ZTmW2s8qkUjg4+ODOXPm4MKFC4iJiUFwcDDOnz8Pf39/uLm5qXtoqsDMDPWxfnRLOFkaITIxHcGhYch4kavtsIiIiIplY2MDXV1dREVFKbVHRUXB3t4eAGBkZIQ2bdpg165diu2pqak4cuQIOnfurHIfIqKqQi4XOHIzDkN+Posey09i56XHyMkTaFWrBn4a4YO/32+LkX5uMDbQ1XaoRGrRWIEPBwcHjBkzBmPGjMGLFy9w9OhRTR2aKhg7c0OEBrdC/5WncTnmOaZsvoSfRvhAT5eZTiIiqlgMDQ0xceJEfPTRR8jKyoKHhwcOHjyIw4cP48CBA4p+X3zxBdq1a4fp06fDz88PP/zwA5ycnBASElKmPkRElVnmizzsuPgIa09G4kFiOgBAV0eC7o0cMSbQHU1cLBV95f9bHYaoMiqXT64GBgbo0qVLeRyaKghPO1OsCWoBqZ4OjtyKxye7r0EI/mNIREQVz7fffosffvgBERERWLVqFQAgLCwMHTt2VPTx9/fHqVOnkJKSgtDQUPj5+eHkyZMwMTEpUx8iosooXpaFpQduw2/REXy86xoeJKbDzFAP497wwIn/a4fvhjRTSoIQVXZc8oXU5uNWA98NaYYJG8Ox5XwMHMyNMLVjHW2HRURElVhpS9H+V9OmTVXqJ5FIMGTIEAwZMqTUfi1atMDatWtfuQ8RUWVx44kMa05G4o/LjxX1P1xrGCM4oBb6t3CBqZQfF6lq4jubXkmXBg6Y93ZDfLzrGr4+fAf25lIMbuWq7bCIiKiSatasmcp9ORORiKjs5HKB43cSsPrkA5y6l6Rob1nLCmMCPdDJ2x66OhItRkhU/jSWCImKioKdnR2MjbmcanUzvLUbnqZk4fuj9zB71zXYmknRob69tsMiIqJK6NmzZ4rft2/fjkWLFmHRokVo2bIlAODChQv48MMPMWvWLG2FSERUKWXl5GHnxcdYc/IB7if8W/+jW0MHhLTxQFPe+kLViFqJkPDwcKxfvx7Lly8HAAwfPhybNm2CmZkZ9u/fD39/f40GSRXf+53rIjYlCzsuPsKkzRex5Z3WaOZqpe2wiIiokrG0tFT8/u2332L79u1Kt8C4ubnB09MTI0eOxJgxY15/gERElUx8ahZ+ORONjWej8SwjBwBgJtXD4FYuCPKvBWcrfpFN1Y9aiZAZM2Zg/vz5AIBr165hz549OHv2LA4ePIhZs2bh+PHjGg2SKj6JRIJF/RohIS0b/9xJwJjQMOyY4A93GxaQIyIi9dy7dw8uLi5F2l1cXHDv3j0tREREVHncjP1f/Y+IJ3iRJwcAOFsZYXSAOwa2cIaZob6WIyTSHrVWjQkLC4OPjw8A4ODBg+jTpw98fX0xffr0MhU5o6pFX1cHK4Y1RyMnCySnv0DQ2vNISM3WdlhERFRJeXl5Yd68ecjNzVW05ebmYt68efDy8tJiZEREFZMQAsdux2P46nPo9u0JbA9/hBd5cjR3tcSPw5rj2Iy2GBPoziQIVXtqzQgxNTVFVFQU6tevj71792LUqFEAgJSUFJiammoyPqpkTKR6WDuqJfqtOI2HyRkIXn8BW8e2hpF+uazUTEREVdiPP/6IHj16KG6PEUIgIiICL168wJ9//qnt8IiIKoysnDzsuvQYa05G4m58GgBARwJ0a+iI4EB3+LjxlnWiwtRKhPTv3x/du3dHw4YNERERgZ49ewIADhw4gG7dumk0QKp8bM2kCA1uhX4rTuPq4xRM3HQRP49oru2wiIiokvHz88ODBw+wYcMG3LhxAwDQrVs3BAUFwdzcXMvRERFpX0JqNjaeza//kZT+AgBgKtXDoJYuGOVfCy41WP+DqDhqJUKWLVsGT09PREdHY+7cubCyys8w3rp1C3PmzNFogFQ5uduYYO2olhjy81kcv5OAj36/hhltuJIMERGVjYWFBaZMmaLtMIiIKpQ7calYcyISv0c8xovc/PofTpZGGB1QC4NauvDWF6KXUCsRoq+vj6lTpxZpX7x48SsHRFVHUxdL/DCsGd7ZEI4dFx/DXC8Pn/RmMoSIiFSXkZGBW7duITk5uci2jh07aiEiIiLtEELgxN1ErD4ZiX/uJCjam7pY4p02HujSwB56urwdnUgVKidCylIEtfAyd1S9tfeyx+e9G+LDnVex7vxTeDg+xAi/WtoOi4iIKoGDBw9i6NChSEpKKna7EOI1R0RE9Ppl5eThj4gnWH3yAe7E/Vv/o2tDB4wJ9GD9DyI1qJwIadasmcoH5YUJFTa4lStiUzLx7ZF7mPPHddibG6JzAwdth0VERBXctGnTEBISgpkzZypuwyUiqi4S0/6t/5GYll//w8RAF4NaumJ0AOt/EL0KlRMhz549U/y+fft2LFq0CIsWLULLli0BABcuXMCHH36IWbNmaT5KqvTebe+JyLjn+ONaIqZsuYTN77Rm9pqIiEoVHR2NTz75BCYmJtoOhYjotbkbl4o1JyOx89K/9T9qWhhidIA7BrVygTnrfxC9MpUTIZaWlorfv/32W8VSdgXc3Nzg6emJkSNHYsyYMZqMkaoAiUSC/2vvitQcCY7eTsCY0AvYMcEftW253DIRERXPy8sLUVFRaNCggbZDISIqV0IInLyXiNUnInG8UP2PJs4WCGnjga4NHaDP+h9EGqNWsdR79+7BxcWlSLuLiwvu3bv3ykFR1aSnI8HyIU0xbM0FXI55jqC157Fzgj/szA21HRoREVVAEyZMQFBQEJYsWQJPT09IJBKl7c7OzlqKjIhIM7Jz87A74gnWnozEraepAACJBOji7YCQNu7wcbMq8m8fEb06tRIhXl5emDdvHr766ivo6eUfIjc3F/PmzYOXl5dGA6SqxdhAD2uDWqDfitOISsrAqHUXsG1cay7xRURERbzzzjsAgPbt2xe7nTXJiKiySkrLxqZzD7HhTDQS07IBAMYGuhjYwgWjA2rBzZq3BBKVJ7USIT/++CN69OihuD1GCIGIiAi8ePECf/75p6ZjpCrG2lSK0OBW6LfiNG7EyjBh40WsHdUSBnqc7kdERP+6efOmtkMgItKoe/GpWHMyCjsvPkL2/+p/OFoYYpR/LQxu5QoLI345SPQ6qJUI8fPzw4MHD7BhwwbcuHEDANCtWzcEBQXB3NxcowFS1eRmbYK1o1pi8M9ncfJeImbuuIJlA5tw6h8RESlwlikRVQVCCJy+n4TVJx7g6O1/6380crJASBt3vNXIkfU/iF4ztRIhAGBhYYEpU6ZoMhaqZho7W+LHYc0xJjQMv196DAcLQ8zsyoteIiJSdu/ePdy8eRNCCHh7e8PT01PbIRERvVR2bh72XI7F6hMPlOp/dKpvj5A2HmhZi/U/iLRF7URIRkYGbt26heTk5CLbOnbs+EpBUfXRtp4dFvVthA+2X8GKY/fhYG6IIP9a2g6LiIgqgJSUFAQHB2Pnzp3Q0cn/tlQul6Nv375Yu3YtLCwstBwhEVFRz9JfYNO5aISeiUZCan79DyN9XQxs4YzRAe6oZcP6H0TaplYi5ODBgxg6dCiSkpKK3c7iZVQWA1q4IE6WhaUH7+CzPddhby5F14aO2g6LiIi0bNq0abh//z5OnDgBX19fAMC5c+cwadIkTJ8+HWvXrtVyhERE/7qfkIa1JyOx4+IjZOXk1/+wN5dilL87hrZyhYUx638QVRRqJUKmTZuGkJAQzJw5E1ZWVpqOiaqhSe08EZuShU3nHuLdrRHYFCJFy1o1tB0WERFp0e7du3Hq1CnUr19f0RYYGIitW7ciMDBQi5EREeUTQuDMgySsORGJI7fiFe0NncwREuiBtxo5ckEAogpIrURIdHQ0PvnkE5iYcFoXaYZEIsG8txsiPjUbh27EISQ0DNvH+6GOvZm2QyMiIi3JzMyEjY1NkXZra2tkZGRoISIionwvcuXYe+UJVp+IxI1YGYD8+h8dvOwR0sYdvu41WP+DqAJTKxHi5eWFqKgoNGjQ4JUDiI2NxZo1a3Dr1i3Mnj1b6Vufkhw7dgz79u3Ds2fP4OrqipEjR8LNze2VYyHt0tWR4LvBzTBs9VlcfPgcQWvPY+fEADhYGGo7NCIi0gI/Pz98/PHHWL58OQwMDAAA2dnZmD17Nvz8/LQcHRFVR88zXmDTuYcIPR2F+P/V/zDU18EAHxeMDqgFD1tTLUdIRKpQa57WhAkTEBQUhKNHjyImJgaPHj1S+lHVN998A19fXzx+/BibNm1CXFzcS/dZvHgx3nrrLejr66NVq1a4fPkyvL29ERERoc6pUAVjZKCLNUEt4WFrgicpWRi17jxkWTnaDouIiLTg66+/xu7du+Hi4oLOnTujc+fOcHFxwZ49e/D1119rOzwiqkYeJKThk13X4Lfwbyw5cBvxqdmwM5Pigy71cHZWB8zv3ZBJEKJKRK0ZIe+88w4AoH379sVuV7VYao8ePTBp0iTExcVh5cqVKu2zatUqTJ48GZ9//jkAICQkBPXq1cPmzZvRtGlTlY5BFZuViQFCR7dC3xWncetpKsZtCMf64JaQ6ulqOzQiInqNmjRpgrt37yI0NBTXr1+HRCJBr169EBQUBDMz3jpJROVLCIGLj1Kx80AMjtyKR8FHHG9Hc4S0cUePxjVZ/4OoklIrEXLz5k2NPLmnp2eZ96lVq5bSrJO0tDQ8f/4cHh4eGomJKgaXGsZYN6olBv98FmceJGHGb1fw7aCm0NHhvZZERNWJmZkZJk+erO0wiKgaeZErx76rsVh94gGuPZEp2jvWt0NwoDv8PKxZ/4OoklO7Roi2hIaGYvz48WjZsiXc3Nxw6dIlTJkyRTFLpTjZ2dnIzs5WPJbJ8v9Bk8vlkMvlGolLLpdDCKGx41U16oyPt6MZfhzWDMHrw7Dn8hPYm0nx0Vvae++VJ75/SsaxKR3Hp3Qcn5KV19ho8ngymQx//vknhgwZotS+ZcsWdO/eHebm5hp7LiKilIwcbD6fX//jqSwLACDVk6C/jwuCA91Rm7e+EFUZaiVCCty7dw83b96EEALe3t5qzfAoq+PHj+PMmTMIDg5G7dq1AQCbNm3CsGHDSpwVsnDhQsydO7dIe0JCArKysjQSl1wuR0pKCoQQ0NHhFLn/Und86poDszu5Ye6BKKw+GQkTnRwMaW5fjpFqB98/JePYlI7jUzqOT8nKa2xSU1M1dqz3338fvr6+RdrT0tLwf//3fyrfVktEVJqoxHSsOxWJX8MeITMnDwBgaybFyNau6ORhjLpuNfk3hKiKkQhVC3oUkpKSguDgYOzcuVPxj4JcLkffvn2xdu1aWFhYlOl4jx49gouLC44ePYq2bduW2C8rKwu2traYO3cu3nvvPUX7G2+8AQcHB/z666/F7lfcjBAXFxc8e/ZMY98myeVyJCQkwNbWlv9QFuNVx+enfx7gy/23AQDfDW6KHo0dNR2iVvH9UzKOTek4PqXj+JSsvMZGJpPBysoKKSkpr/w31traGvfu3YOVlZVSe3JyMry8vBAfH/9Kx9cGmUwGCwsLjYxPAblcjvj4eNjZ2fF9XgyOT+mq6/gIIXA+MhlrTkbi0M04Rf0PLwczhLTxQM8mjtDXkVTLsVFVdX3vqIrjU7LyGpuy/I1Va0bItGnTcP/+fZw4cULxTc25c+cwadIkTJ8+HWvXrlXnsC+VmJiItLS0Isv2NmjQAGFhYSXuJ5VKIZVKi7Tr6OhodOAlEonGj1mVvMr4jH+zNuJk2Vh/OgozfrsCWzND+NW2LocotYfvn5JxbErH8Skdx6dk5TE2mjyWXC5HUlJSkURIUlISXrx4obHnIaLqIyevoP5HJK4+TlG0t6tni5A2HvCv/W/9D95WSVR1qZUI2b17N06dOoX69esr2gIDA7F161YEBgZqLDgAWLNmDe7du4eFCxfCyckJdnZ22LlzJ7p06QIgfwruwYMH0aFDB40+L1UsEokEn/TwRpwsC39de4qxv4Tht/F+8HLg/eFERFVVp06dMGPGDGzcuBGmpvn35qempuK9995Dx44dtRwdEVUmKRk52HIhv/5HbEpB/Q8d9G3ujDGBteBpx5WoiKoTtRIhmZmZsLGxKdJubW2NjIwMlY9z4sQJ/PTTT4p9Pv/8c6xevRp9+/ZF3759AQBnzpzB2bNnsXDhQkgkEoSGhmL48OE4d+4cPDw8cObMGdSsWVOxnC5VXbo6Enw9qCmS0s7jfFQyRq29gJ0T/VHT0kjboRERUTlYsmQJ2rRpAzc3NzRr1gxCCFy6dAlmZmY4fvy4tsMjokogOikd605F4dewGGS8yK//YWNqgJF+tTDM1xXWpkVnjRNR1adWIsTPzw8ff/wxli9fDgMDAwD5dThmz54NPz8/lY/j5OSErl27AoAi8QEoL6sbEhKC3r17Kx537doVkZGRCA8PR1JSEj766CP4+PhwCatqwlBfF6tGtkD/ladxNz4No9adx2/j/GFhrK/t0IiISMPc3Nxw9epVbNiwARcvXoREIkHv3r0xcuTIMtcjI6LqQwiBsOhnWH3iAQ7e+Lf+Rz17M4xp445eTWrCUF9Xu0ESkVaplQj5+uuv0aVLF+zatQtNmjQBAEREREBHRwcHDhxQ+TgeHh4lrvRSoHXr1kXazMzMSi2qSlWbhbE+1ge3Qt8fT+FOXBre+SUMG4Jb8Q8aEVEVZGFhgSlTpmg7DCKqBHLz5Nh37SnWnHiAy4/+rf/Rtp4txgS6I9DThl+eEhEANRMhTZo0wd27dxEaGorr169DIpGgV69eCAoKgpkZ76+j8udkaYT1o1th4MozOB+ZjPd+jcD3Q5pDR4d/3IiIqpL09HQcPnwYDx48wPTp0wEAd+7cQZ06dfiBhogAALKsHGw7H4P1p6Pw+HkmAMBATwf9mjshOMAddez5+YSIlKmVCAHyZ2VMnjxZk7EQlUl9R3P8NNIHQWvPY9/Vp5hndgNzenrzwpiIqIq4c+cOOnfujKysLMTFxSkSIfPnz0f37t0xePBgLUdIRNoUk5yBdaeisO3CQ6QXqv8xonUtDGvtChvW/yCiEqiVCJHJZPjzzz8xZMgQpfYtW7age/fuL12zl0hT/Gvb4KuBTfHulktYfzoKNS0NMfaN2toOi4iINGDatGkYOHAgvvzyS6VleadOnYrx48czEUJURvGyLMSnZiu1yeVyJD/LQHxOSpHlr+3MpLAzN3ydIaokPPoZ1px8gP3XnkL+v/ofde1NERLogV5NWf+DiF5OrUTI+++/D19f3yLtaWlp+L//+z+sXLnylQMjUlWvJjURL8vCgj9v4ot9t2Bvboi3mzppOywiInpFZ86cwebNm4vM9PPy8sLVq1e1FBVR5bXp3EN8e+Suyv2ndqiD6Z3qlmNEqsvNk2P/9adYfSISETHPFe1v1LVFSKA72tRh/Q8iUp1aiZCdO3di8eLFRdr79euH2bNnMxFCr11IGw/EpmRhzclIzPjtMmxMpQjwLLrEMxERVR5yuRwvXrwAAKUPOFFRUWVaNSY0NBQ5OTlF2r28vBAYGKh4nJOTg2PHjiEuLg6NGjVSFIQvTJU+RBXVMF9XdPK2VzzOyslD/5VnAAC/jvWFsVR5FT47M+3fWiLLysGvF2Kw7lSh+h+6OujTzAnBge6o58D6H0RUdmolQuRyOZKSkmBlZaXUnpSUpLhgIXrdZr9VH09lWfjzSizG/RKOX8f5wbsmb9MiIqqsOnXqhKVLl2Lx4sWKREhiYiLeffdddO3aVeXjXLhwAVlZWYrHqamp+PXXX/H5558rEiFJSUno0KED0tLS0KhRI0yaNAkjRozA999/r9hPlT5EFZmduaHSrS4ZL3IVv3vXNIepoYE2wipWTHIG1p+OwrYLMUjLzo+zhokBRrR2w/DWbrCtAEkaIqq81EqEdOrUCTNmzMDGjRthamoKIP+i4r333kPHjh01GiCRqnR0JFg2sAmS0rJx9kEyRq07j50T/eFsZazt0IiISA1fffUV2rZtiz179kAIgXbt2iEsLAy2trbYuHGjysf5b6Ji5cqV2LFjB0aNGqVomzVrFnJycnD58mWYmJjgwoUL8PX1Rffu3dGtWzeV+xDRq7n48BnWnIjEX9diFfU/PO1MERLojt7NnFj/g4g0Qq1EyJIlS9CmTRu4ubmhWbNmEELg0qVLMDMzw/HjxzUdI5HKpHq6+GlECwxceQa341IRtPY8dkzwh6VxxfmGg4iIVOPm5oYrV65g48aNCAsLg1wuR9++fREUFPRKhdnXrFmD7t27o2bNmgDyZ7pu27YNn376KUxMTAAALVu2ROvWrbFlyxZ069ZNpT5EpJ7cPDkO3ojD6hMPcPHhc0V7mzo2GBPojjfq2EJHh/U/iEhz1EqEuLm54erVq9iwYQMuXrwIiUSC3r17Y+TIkWW6Z5eoPFgY6WN9cEv0/fE07iekIyQ0DBtDfPkNAhFRJWRmZoYJEyYoHkdFRUFPT63LFwDAlStXEBYWhj179ijaYmJiIJPJ4O3trdS3QYMGCA8PV7lPcbKzs5Gd/e8qHTKZDEB+8kUul6t9HoXJ5XIIITR2vKqG41OywmOiyfekqlKzcvBb+COsPx2NR88K6n9I0KtpTQQHuMNLUf9DQF4wPeQ14nundByf0nF8SlZeY1OW46l9JWFhYYEpU6aouztRuXK0MEJocCv0X3EaYdHPMHXrJfw4zAe6/DaBiKjSCA8Px/r167F8+XIAwPDhw7Fp0yaYmZlh//798Pf3L/MxV69eDScnJ6UZHAXJif/WPqtRo4Zimyp9irNw4ULMnTu3SHtCQoJS3ZJXIZfLkZKSAiFEkeVPieNTmsycPMXvCQkJyPhPsdTy8lT2Ar9GxGP3tQSkv8j/4GJhqIt+TezQr7EtrE30AWQiPj7ztcRTEr53SsfxKR3Hp2TlNTapqakq91U7EZKeno7Dhw/jwYMHmD59OgDgzp07qFOnDpeuogqhrr0ZVo1sgRFrzuPA9Th89sd1zHu7Ad+fRESVxIwZMzB//nwAwLVr17Bnzx6cPXsWBw8exKxZs8p8O252djY2bdqESZMmQVf331mCRkZGAIpeQKWmpiq2qdKnOLNmzcJ7772neCyTyeDi4gJbW9tXur2nMLlcDolEAltbW15sF4PjU7LCxVJtbW3LvVjq5ZjnWHMyCn9df4q8/83wqG1rguCAWuhTAet/8L1TOo5P6Tg+JSuvsTE0NHx5p/9RKxFy584ddO7cGVlZWYiLi1MkQubPn4/u3btj8ODB6hyWSON8Pazx9aCmmLzlIn45Gw0HC0NMauep7bCIiEgFYWFh8PHxAQAcPHgQffr0ga+vLxo0aIClS5eW+Xi///47nj9/juDgYKV2V1dX6OvrIyoqSqk9MjISnp6eKvcpjlQqhVRadHULHR0djV78SSQSjR+zKuH4FK/weJTX+OTJBQ7deIrVJyIRFv1M0R7gaY2QQA+8Wbdi1//ge6d0HJ/ScXxKVh5jU5ZjqfWs06ZNw8CBAxEbG6vUPnXqVLUuTIjKU/fGjvi0R/493UsO3Mb28EdajoiIiFRhamqqSDzs3bsX7du3BwCkpKQoVq0rizVr1qBTp06oVauWUruBgQG6dOmCrVu3Qoj8b6ljY2Nx9OhR9OzZU+U+RPSvtOxcrDsVibZLj2L8xosIi34GfV0J+jV3xr5322BTSGu087Kr0EkQIqq61JoRcubMGWzevLnILQZeXl64evWqRgIj0qTRAe54KsvCT8cf4MMdV2BrJsWbdW21HRYREZWif//+6N69Oxo2bIiIiAhFwuHAgQNlXqUlKioKR44cwW+//Vbs9i+//BL+/v7o168fWrdujdDQUPj4+GDEiBFl6kNU3T15nonQ01HYfP4hUrPyb72xNNbHcF83jPRzg5256lPXiYjKi1qJELlcjhcvXgCAUjIkKiqKq8ZQhTWzixfiUrKwK+IJJmwMx7axfmjkzPcrEVFFtWzZMnh6eiI6Ohpz585VFCq9desW5syZU6Zj3b9/H2PHjkWvXr2K3e7t7Y0rV65g/fr1iI6OxpQpUzB69Gjo6+uXqQ9RdXXl0XOsPhGJP6/GKup/eNiYIDjQHf2aO8PIoGLV/yCi6k2tREinTp2wdOlSLF68WJEISUxMxLvvvouuXbtqNEAiTdHRkWBx/yZISMvGqXtJGL3+PHZOCICrtbG2QyMiomLo6+tj6tSpRdoXL15c5mN16NABHTp0KLWPq6srPv3001fuQ1Rd5MkFDt+Mw5oTkTgflaxo9/OwRkgbd7Srx1tfiKhiUisR8tVXX6Ft27bYs2cPhBBo164dwsLCYGtri40bN2o6RiKNMdDTwcrhPhj401ncjJUhaN157Jjgjxom5VslnYiIiKiqSM/OxfbwR1h7KhLRSRkAAD0dCXo1qYngQHc0dOKMWyKq2NRKhLi5ueHKlSvYuHEjwsLCIJfL0bdvXwQFBWlsKTii8mJmqI/1o1ui74+nEZmYjuD1F7DlndacsklERERUitiUTISejsbmc9GQ/a/+h4WRPob5umKkXy04WLD+BxFVDmolQgDAzMwMEyZMUDyOioqCnp7ahyN6rezNDREa3Ar9V55GRMxzTNlyESuH+0BPl0tbERERERV29VEK1px8gL1XYpH7v/of7or6H04wNuBnACKqXNT61BceHo4pU6YoHg8fPhzu7u5wcHDA6dOnNRYcUXnytDPF6pEtINXTweGb8fhk9zXFkohERKQ9d+7c0XYIRNVCQVFTADgfmaz0WC4XOHQjDoN+OoOe35/ErognyJUL+LrXwKqRLXDkvTcxorUbkyBEVCmp9S/XjBkzMH/+fADAtWvXsGfPHpw9exYHDx7ErFmzcPz4cY0GSVReWtSqge+GNMOEjeHYcj4GjhZGeLdDHW2HRURUrTVp0gSurq7o0aMHevTogTZt2nDWKZGG7b8Wizl/XFc8Dg4Nh6OFIT7s5gVZZg7WnIxEVKH6Hz0aO2JMoAdX3COiKkGtq4qwsDD4+PgAAA4ePIg+ffrA19cXDRo0wNKlSzUaIFF569LAAXPfbohPdl3DskN34GBuiIEtXbQdFhFRtZWUlIRDhw5h7969GD58ONLT09GlSxf06NED3bp1g42NjbZDJKrU9l+LxYSNF/HfebCxKVmYujVC8djcUA9Dfd0Q5O8GRwuj1xojEVF5UuvWGFNTU0RFRQEA9u7di/bt2wMAUlJSYGpqqrHgiF6XEa3dMKldbQDArN+v4uiteC1HRERUfRkbG+Ptt9/GqlWr8OjRIxw5cgTe3t747rvv4OjoiICAACxcuBBXr17VdqhElU6eXGDunhtFkiCF6epIMKenN87M6oAPu3kxCUJEVY5aiZD+/fuje/fu6NWrFyIiItCzZ08AwIEDB9CtWzeNBkj0uszoXA99mzshTy4wcdNFXI55ru2QiIiqPYlEAh8fH8yZMwcXLlxATEwMgoODcf78efj7+8PNzU3bIRJVKucjkxGbklVqnzy5gJeDOUykvCWNiKomtRIhy5Ytw9SpU+Hp6YkjR47AysoKAHDr1i3MmTNHowESvS4SiQRf9muMN+raIjMnD8HrLyAqMV3bYRERUSEODg4YM2YMfv/9dyQlJeHnn3/WdkhElUp8aulJkLL2IyKqjNRK8+rr62Pq1KlF2hcvXvzKARFpk76uDn4c1hyDfz6Da49lCFp3Hjsm+MPGVKrt0IiI6D8MDAzQpUsXbYdBVKlk58hV6mdnZljOkRARaY/KiZBbt24BALy8vBS/l8TLy+vVoiLSIlOpHtaOaol+K04jOikDwesvYMs7rTk9lIiIiCq1/JVirpXaRwLAwcIQrdxrvJ6giIi0QOVPdvXr1wcACCEUv5dEiNLKLxFVfHZmhggd3Qr9VpzGlUcpmLT5IlaNbAF9XbXuJiMiIiLSGrlc4Jsjd/HdkbsAgHr2prgTlwYASkVTJf/775ye3tDVkYCIqKpSORESExNT7O+aIJfLkZGRASMjI+jq6qq8nxACQgjo6PDDKWmeh60p1oxqiaGrzuLY7QTM/v0qvuzXGBIJLwyIiLQlKioKdnZ2MDY21nYoRJVCWnYupm+LwKEbcQCA0QG1MPut+jh8Mw5z/riOOFm2oq+DhSHm9PRG14aO2gqXiOi1UDmD4OzsDGdnZ6XfS/pR1dOnT7FgwQK4u7vDzMwMJ06cUGm/K1euoHPnzjA0NISdnR1mzJiBrCwWdCLNa+5qhe+HNIeOBPg17BG+PnxX2yEREVUb4eHhmDJliuLx8OHD4e7uDgcHB5w+fVqLkRFVDlGJ6ejzwykcuhEHA10dLOnfGHN6NoCerg66NnTE4ffeVPRdG+SDkzPbMwlCRNWCyomQW7duqfyjqtWrVyMzMxObN29WeZ87d+6gTZs2qF+/PhISEvD48WO4uLjg8uXLKh+DqCw6ettjQe9GAIDvjtzF5nMPtRwREVH1MGPGDAwaNAgAcO3aNezZswdnz57FBx98gFmzZmk5OqKK7fidBPT6/iTuxqfBzkyKbeNaY0ALF6U+hW9/aeVeg7fDEFG1UeYaIapQtUbIxx9/DAB49OiRyseePXs2PD098c033yhuUShuBRsiTRrq64qnsix8d+QuPt51FXZmUnT0ttd2WEREVVpYWBh8fHwAAAcPHkSfPn3g6+uLBg0aYOnSpVqOjqhiEkJg1YkHWPTXLcgF0MzVEiuH+8DenKvAEBEVUKtGiLbk5eVh3759+PTTTyGRSJCbmws9Pa7kQa/H9I518DQlE7+GPcLkLRex+Z3WaO5qpe2wiIiqLFNTU0RFRaF+/frYu3cvRo0aBQBISUmBqampdoMjqoCycvLw4Y4r2BXxBAAwsIUz5vduCKme6jX4iIiqA5WzCGWp/VFeEhISkJGRgdzcXDRt2hTXr19HjRo1EBQUhAULFsDAwKDY/bKzs5Gd/W8hKJlMBiC/SKtcrtpa6i8jl8shhNDY8aqaqjI+899ugPjUbBy7nYAx6y/gt3Gt4WH76hfjVWV8ygPHpnQcn9JxfEpWXmOjyeP1798f3bt3R8OGDREREYGePXsCAA4cOIBu3bpp7HmIqoLHzzMx7pcwXHssg66OBJ/28MZIPzcWeSciKobKiZCy1P7w8vJSK5iXKbjlZunSpfjzzz/h5+eHsLAwdOvWDbq6uli4cGGx+y1cuBBz584t0p6QkKCxIqtyuRwpKSlcxaYEVWl85nR0QvzzdNyIy8CINeewepAXrE30X+mYVWl8NI1jUzqOT+k4PiUrr7FJTU3V2LGWLVsGT09PREdHY+7cubCyyp+Fd+vWLcyZM0djz0NU2Z2PTMbETeFITHsBK2N9/DCsOfxr22g7LCKiCkurNULKysbGBvr6+hg+fDj8/f0BAC1btsTo0aOxe/fuEhMhs2bNwnvvvad4LJPJ4OLiAltbW5ibm2skNrlcDolEAltbW15sF6Oqjc/6MTUw4KeziE7KwP/9GYUt7/jCVKr+bVpVbXw0iWNTOo5P6Tg+JSuvsTE01FwdAn19/WLrgC1evFhjz0FU2W08G43P/riOXLmAl4MZVo1sAZcaXF6aiKg0Fb5GSHZ2NuRyOYyMjKCvrw8/Pz+8ePGiSJ+SbosBAKlUCqlUWqRdR0dHoxd/EolE48esSqrS+NiZG2FDcCv0/fE0rj+RYdLmS1gT1BIGeuqfW1UaH03j2JSO41M6jk/JymNsND3O6enpOHz4MB48eIDp06cDyF9Brk6dOpzyT9Xai1w5PttzXbGaXfdGjlgyoDGMDVg/j4joZbRaIyQ3NxdZWVnIyMgAAGRmZiItLQ0GBgaKxMakSZNw9uxZXLt2DUD+qjH9+vVD165dERAQgHPnzmHdunWYN2+exuMjKo2btQnWjW6JwT+fxYm7ifhwxxV8NbDJSy/M42VZiE/NVmqTy+VIfpaB+JyUIh8i7MyksGOldyKqhu7cuYPOnTsjKysLcXFxikTI/Pnz0b17dwwePFjLERJpR0JqNiZuCseFqGeQSIAZnethYtvaTA4SEamozDVCvLy8XlovRNUaIdu2bcO4ceMAACYmJhgwYAAA4KOPPsJHH30EIH+KrbHxv9P7OnfujNDQUCxYsADR0dFwdXXFl19+iQkTJqh6KkQa09jZEj8Ma46Q0DDsvPQYDhaG+L+upb//N517iG+P3FX5OaZ2qIPpneq+aqhERJXOtGnTMHDgQHz55ZdKSeKpU6di/PjxTIRQtXTl0XOM+yUcsSlZMJPq4dshTdHey17bYRERVSplrhEihHhpvRBVa4QMGzYMw4YNK7XP999/X6Stb9++6Nu3r0rPQVTe2tWzw8K+jfB/26/gx2P34WBhiJF+tUrsP8zXFZ28/71gycrJQ/+VZwAAv471hbFUufCqnVnR27qIiKqDM2fOYPPmzUW+5fby8sLVq1e1FBWR9uy69Bgzd1xBdq4cHrYm+HlEC3jacSlpIqKyUqtGiLbqhRBVVANbuCAuJQtfHbqDOX9ch52ZIbo2dCi2r525odKtLhkvchW/e9c0h6lhyfVuiIiqE7lcrqgLVjgZEhUVBQsLC22FRfTa5ckFvtx/Cz//8wAA0N7LDt8Mbgpzw1dbtY6IqLpSq0ZIedQLIarsJrf3RKwsC5vPPcS7Wy9hU4gvWtaqoe2wiIgqrU6dOmHp0qVYvHixIhGSmJiId999F127dtVydESvR0pGDiZvuYgTdxMBAJPa1cZ7nepBV6fs9UD+W6csKydP8fuNJ7JiZ6WyThkRVUWvXFY6KyurSJsml84jqiwkEgnm9WqAeFk2Dt+MQ0hoGHZM8IOnnZm2QyMiqpS++uortG3bFnv27IEQAu3atUNYWBhsbW2xceNGbYdHVO7uxKXinQ1hiE7KgJG+LpYMaIwejWuqfbzS6pQN/PlckTbWKSOiqkqtRMjdu3cxceJEnDp1CpmZmUW2q1ojhKiq0dPVwfIhzTB09VlcevgcQWsvYOdEf9jz2xQiojJzc3PDlStXsHHjRoSFhUEul6Nv374ICgqCubm5tsMjKlcHrz/F9G0RSH+RBydLI/w80gcNar7aLWH/rVMGFKxc9ww1rKyKXbmOiKgqUisREhQUBGtra/z666+wtLTUcEhElZuRgS7WBLVE/xWn8SAxHUFrz+PX8X68j5eISA1mZmZKK8NFRUVBT++VJ7QSVVhyucDyv+/h68N3AACtPWrgh6HNYW366kmJ/9Ypy38+OeL1s2FnZ1EkEUJEVFWpdSVx6dIlxMbGMglCVIIaJgYIDW6FPj+exq2nqRj/SzjWj24FAz1eYBARqSo8PBzr16/H8uXLAQDDhw/Hpk2bYGZmhv3798Pf31/LERJpVlp2Lt7/NQIHrscBAEb518Ls7vWhr8vrByIiTVLrX1U3NzckJiZqOhaiKsWlhjHWj24JEwNdnL6fhA+2X4ZcztvGiIhUNWPGDAwaNAgAcO3aNezZswdnz57FBx98gFmzZmk5OiLNik5KR98fT+HA9TgY6Opgcb/G+KxXAyZBiIjKgVr/ss6dOxejR4/G2bNnkZCQgMTERKUfIsrX0MkCK4b7QE9Hgt0RT/Dl/lvaDomIqNIICwuDj48PAODgwYPo06cPfH19MX36dERERGg3OCINOnk3Eb2+P4U7cWmwNZNiy9jWGNjSRdthERFVWWolQuzt7XH16lX4+fnBzs4Otra2Sj9E9K836tpicf/GAICf/nmAtScjtRwREVHlYGpqiqioKADA3r170b59ewBASkoKTE1NtRgZkWYIIbD6xAOMXHsOKZk5aOJiiT2TA+HjZqXt0IiIqjS1aoRMmDABnTt3xsSJE1knhEgFfZs746ksC4v338b8P2/A3twQ3Rs7ajssIqIKrX///ujevTsaNmyIiIgI9OzZEwBw4MABdOvWTcvREb2arJw8fLTzKnZeegwA6NfcGZ/3aQhDfV0tR0ZEVPWplQiJjo7G2bNnYWHxakt4EVUnE96sjacpWdhwJhrTt0XA2tQArT2stR0WEVGFtWzZMnh6eiI6Ohpz586FlVX+t+S3bt3CnDlztBwdkfpiUzIx7pdwXHmUAl0dCWa/VR+jA2pBIpFoOzQiompBrUSIp6cnYmNjmQghKgOJRII5PRsgTpaFA9fj8M6GMGwf74+alv8uY3c+Mhlv1rOHrg4vhIiI9PX1MXXq1CLtixcv1kI0RJoRHp2Mcb9cRGJaNiyN9fHD0OYI8LTRdlhERNWKWomQoKAgDB8+HEuWLIGnp2eR7LWzs7NGgiOqanR1JPh2cDMMX30OYdHPMOjnM9AvlPQIDg2Ho4Uh5vT0RteGvHWGiAgA7t27h5s3b0IIAW9vb3h6emo7JCK1bDn/EJ/uvoacPAEvBzP8PKIFXK2NtR0WEVG1o1YiZMaMGQCgKFr2X0JwiVCikhjq62J1UAt0+eYfxMmyi2x/mpKFCRsvYsXw5kyGEFG1lpKSguDgYOzcuRM6Ovn13eVyOfr27Yu1a9dyZipVGjl5cszbcwO/nI0GAHRr6IClA5rARKrWpTgREb0itf71vXnzpqbjIKpWzAz1IS8hXygASADM3XMDnbwdeJsMEVVb06ZNw/3793HixAn4+voCAM6dO4dJkyZh+vTpWLt2bZmOd/nyZRw9ehTGxsbo06dPkZXuUlJSsHPnTsTFxaFRo0Z46623isx6VaUPUWGJadmYuOkizkcmAwDe71QXk9sXnVFNRESvj1qJEC8vL03HQVStnI9MRkJq0dkgBQSA2JQsnI9Mhl9tFlQloupp9+7dOHXqFOrXr69oCwwMxNatWxEYGKjycYQQePfdd7FhwwYMHjwYxsbGWL58OXbu3Ik6deoAAB4+fIjAwEA4OTmhRYsWWL58OVq1aoWdO3cqPrCq0oeosGuPUzDul3A8fp4JU6kevh7UFJ287bUdFhFRtcf5eERaEJ+apVK/daciYaAnQVMXK84MIaJqJzMzEzY2RYtIWltbIyMjQ+XjrF69GqtWrUJYWBgaNmwIAEhKSkJ29r8J6ZkzZ8LR0REnTpyAnp4epkyZAm9vb2zfvh0DBgxQuQ9RgT8uP8H/bb+MrBw53G1MsGqkDzztzLQdFhERAdDRdgBE1ZGdmeHLOwE4eCMO/VacQYsFhzBt6yXsjniM5xkvyjk6IqKKwc/PDx9//DFevPj3373s7GzMnj0bfn5+Kh/nm2++wZAhQxRJECA/mVKzZk0AQF5eHnbv3o0RI0ZATy//O6K6devijTfewPbt21XuQwQAeXKBRX/dwrtbLiErR44369pi16QAJkGIiCoQzggh0oJW7jXgaGGIpylZKKm0sKWRPgI8rXHibiKeZeRgV8QT7Ip4Ah0J0NzVCu287NCunh3qO5pxSjYRVUlff/01unTpgl27dqFJkyYAgIiICOjo6ODAgQMqHSMtLQ03btzABx98gMOHDyM8PBw1a9ZEjx49YGVlBSD/lpfMzEzFbTIF6tSpg3PnzqncpzjZ2dlKM09kMhmA/KKvcrlcpXN4GblcDiGExo5X1bzO8ZFl5mDqtss4ficBADDuDQ/M6FwXujqSCvv68P1TMo5N6Tg+peP4lKy8xqYsx2MihEgLdHUkmNPTGxM2XoQEUEqGFKQ0FvVrhK4NHZGbJ0d49DMcvZ2Ao7ficTsuFWHRzxAW/QxLDtyGg7kh2nnZol09OwR42rACPRFVGU2aNMHdu3cRGhqK69evQyKRoFevXggKCoKZmWrfrj9//hwAsHLlSujp6cHf3x/79u3D9OnTcfjwYTRt2hRpaWkAUGQVGktLS8U2VfoUZ+HChZg7d26R9oSEBGRlqXab5MvI5XKkpKRACKFYXYf+9brGJzI5E//3x33EPM+GVE+C2R1robOXFZISE8rtOTWB75+ScWxKx/EpHcenZOU1NqmpqSr3VfsTU0ZGBm7duoXk5OQi2zp27KjuYYmqja4NHbFieHPM+eO60jK6DhaGmNPTW7F0rp6uDnw9rOHrYY0Pu3nh8fNMHL0Vj6O34nHqfiKeyrKw5XwMtpyPgYGuDnw9aqBtPTu097KDu42Jtk6PiEgjzMzMMHnyZLX3NzHJ/3dQT08PJ06cUMyg69ChA2bOnIkDBw7A1NQUQP6KMIU9f/5csU2VPsWZNWsW3nvvPcVjmUwGFxcX2NrawtzcXO3zKkwul0MikcDW1pYX28V4HeNz5GYcpv96G2nZeahpaYifhjdHg5qVY3lnvn9KxrEpHcendByfkpXX2BgaqlZ+AFAzEXLw4EEMHToUSUlJxW4XoqTJ/kRUWNeGjgjwtEGjzw4CANYG+eDNevalFkZ1sjTC8NZuGN7aDVk5eTj7IAnHbifg71vxeJicgRN3E3HibiLm770BdxsTtK1ni/ZedmjlXgNSPd3XdWpERBqRkJCA1atX4+bNmwAAb29vhISEFFtEtThWVlawt7eHv7+/0m2EAQEB2LBhAwDAxcUFRkZGuHv3Lrp06aLoc/fuXdSrV0/lPsWRSqWQSqVF2nV0dDR68SeRSDR+zKqkvMZHCIEfjt7DV4fuQIj8W19/HNYcNqZFX/OKjO+fknFsSsfxKR3Hp2TlMTZlOZZazzpt2jSEhIQgOTkZQogiP0SkusJJj1buNcq0Ooyhvi7a1rPDZ70a4PgHbXH4vTfxcff68K9tDT0dCSIT07HuVBRGrDmPZvMO4Z0NYdhy/iFiUzLL41SIiDTq2LFj8PDwwKpVq5CZmYnMzEz8/PPP8PDwwD///KPycQYOHIjTp08rtZ06dQoNGjT4//buOzzKMmsD+D3pvc8kgTRSBwgldAgCCdXCwgKCSF0RDSgoq36AaxdFFxHEAuiuKEVcpUmRIhJKgIRAQk8llSRkJqT3Ms/3x8BoIBlCTDIp9++6vDbzzjNvTs6OyfHM+z4HgPpqkQkTJmDLli2orq4GAMTHx+PkyZOYPHlyg9dQx1JSUY0XfojCJ0fUTZBZg9yx7dmBba4JQkTUETXqipDU1FS8+eabmstNiUj3JBIJvGUW8JZZ4NlHPFFUXoXTiTk4FqtAaJwSyqIK/HY9G79dzwYAdHW2QvCdvUUC3Diel4han0WLFmHhwoVYuXKl5lMelUqF5cuX48UXX8Tly5cbdJ533nkHw4YNw9ChQzFkyBBEREQgLi4OoaGhmjUff/wxAgMDMWzYMPTr1w+7du3C+PHja43Fbcga6hjSc0sxf/N5xN4qgqG+BO9N8Mf0AW66DouIiBqoUY0QuVyOlJQUzScpRNT6WJoYYpy/M8b5O0OlErieVXinKaLAxfR8xGQVIiarEF+G3oCNmSGG+ahvoRnuK4WtuZGuwyciwo0bN7Bs2bJal7rq6elh6dKl+Pzzzxt8Hjs7O5w/fx67d+9Gamoqnn/+eYwfP77Whqtubm64evUqdu7ciezsbGzYsAGPP/54rdtpGrKG2r8ziTl44Yco5JVWwcHCGBtm9kE/Dztdh0VERA+hUY2QBQsWYM6cOVi1ahW8vb3vKwBcXFyaJDgiahp6ehL4d7aGf2drLB7pg9vFFTgRr0RonBIn4hTIL63C3kuZ2HtJPZ63t6sNguUyBMll6OZsxSKfiHTC19cXiYmJ6N+/f63jN27cgK+v70Ody8TEBNOnT9e6xtraGs8888xfXkPtkxACm06n4INfY1CjEujpYo2Ns/rC2dpU16EREdFDalQjZP78+QCA4ODgOp/nPiFErZu9hTEm9XHBpD4uqK5RITo9X321SKwCsbeKEJWWj6i0fHxyJB6OVsYI8pNhhJ8MQ30cYMHxvETUQkJCQvDkk0/ivffeQ//+/SGEwPnz5/HWW29h+fLluHnzpmYtP4Sh5lReVYN/7b6KnVHq99ykgM74cFIPmBhyE3IioraoUf9Fc3fndiJq+wz09dDfww79PeywdJwcmfllCI1TIDRWidOJOcgurMCPken4MTIdhvoSDOxir5lE4ymtf2QkEdFftWDBAgDAnDlz7nsuJCSk1mN+CEPNJbuwHM9tuYBL6fnQkwCvP9YV84Z24dWSRERtWKP3CCGi9qmTjSlmDHTHjIHq8bwRybkIvbO3SOrtUoQl5iAsMQcrDsTAw94MI/xkmvG8/GSMiJoSP3ghXbuQmoeQrRegLKqAtakhvng6AI/4SHUdFhER/UU6v8ZdpVLhyJEjiI2NxZQpUx7q0taEhAQcOHAAAQEBGD58eDNGSdQxmRjqY7ivFMN9pXhbdENSTommKXIuORcpt0vx3ZkUfHcmBaaG+gj0dkCwXIYRflJ0suE900T01/CDF9KlnyLT8caeq6isUcHX0QLfzO4Hd3tOTCQiag8a1Qiprq7G+vXr8fPPPyMtLQ3V1dW1nv/zPbva7Nq1C6+99hqcnJxw5swZ9O7du8GNkPLyckyePBk3btzA/Pnz2QghamYSiQReUgt4SdXjeYsrqhGWkKNpjCiKKnA0JhtHY9TjeeVOlgiSq68WCXC1gYG+3gO+AxERke5V1aiwYv91fH82FQAwtrsjVk/tzT2yiIjakUb9Rv/ggw/w/fffY/HixViyZAnWr1+Pc+fOYfPmzXj55ZcbfB4bGxv89ttvMDIygqur60PF8PLLL2P48OG1RuoRUcuxMDbAOH8njPN3ghAC1zILcTxOgWOxCkSn5yP2VhFibxVh/fEbsDY1xDBfKYLlUgz3lcGO43mJiKgVyi2pxMJtFxCelAsAWDLKF4uCvaGnx/1AiIjak0Y1Qr7//nv873//Q//+/bFkyRI8//zzCAkJQWBgILZv397g89ydOtPQK0ju2rlzJ06dOoXz589j8ODBD/VaIl1TFJZDUVSheVxeVaP5+npmIcyMDWutl1kaQ2Zl0mLxNYZE8sd43heDfZBbUomT8Uoci1XgRLwSBWVV2HcpE/suZUJydzyvn3o8b/dOHM9LRES6dy2zAM9tvoCM/DKYG+nj02m9Mba7k67DIiKiZtCoRkhaWhoCAgIAAKampigqKoKVlRWmTp2KxYsXN2mA90pNTcXChQtx+PBhmJo2bA+CiooKVFT88R+ehYWFANT7k6hUqiaJS6VSQQjRZOdrb5ifP2wNT8W6Y4l1Pjf164j7ji0O9sbLo3yaO6wmZWNqgL/1csbfejmjukaFizcLEBqrwPF4JWKyihCdlo/otHys/i0eMktjDPeVIshPWud4Xr53tGN+tGN+6tdcuWGuqS3afzkTr/18GWVVNXC3N8M3s/vB19FS12EREVEzaVQjpKamBgYG6pd26dIFYWFheOyxxxAXF9fg5kRjVFdXY/r06XjttdfQu3fvBr9u5cqVePfdd+87rlQqUV5e3iSxqVQqFBQUQAjB23XqwPz8YYyXGfo4da11TKhUKC4uhoWFBST35MfB3BAKhaIlQ2xybqbAnABbzAmwhaKoEmdSCnAmuQCR6UVQFFXg5ws38fOFmzDQk6B3ZwsM6WKNQA9ruNkaQwjB944W/HdLO+anfs2Vm6KioiY7F1Fzq1EJrD4Sh6+O3wAAPOLjgM+nB8DGjLdwEhG1Z39516eQkBBMnz4dgwcPxrlz5zBz5symiKtO27Ztw/Xr1/Hkk09i7dq1ANTNjOjoaKxduxYvvfRSnZfYL1++HP/85z81jwsLC+Hq6gqpVAorK6smiU2lUkEikUAqlbLYrgPz8wdZHcdUKhWUSmWHyI9MBvh7ueA5ABXVNTiXnIvQOCVC45RIvV2K8+lFOJ9ehHUnb8LNzhQjfKUIcDLCGA97mN5z2xDx360HYX7q11y5MTFp3bfyEd1VWF6Fl3+8iGOx6g8bnhvmif8b68fNvYmIOoBGNUKqqqo0Xy9atAhubm44e/YsnnrqKcyePbvJgruXl5cX5s6di9TUVM2xyspKFBYWIiUlBUKIOhshxsbGMDY2vu+4np5ekxZ/Eomkyc/ZnjA/2nXE/Jga6WG4nyOG+zniHQDJOSU4FqvA8TgFIpJykZZbhs3hadgMwPRAMgK97THizt4inTmeV6MjvnceBvNTv+bIDfNMbcENZTHmbz6PJGUJjA308PHknpgY0FnXYRERUQtpVCPk7m0xd02YMAETJkxokoDudfToUdy6dQszZ87E0KFDMXTo0FrPHz9+HMOHD9dcIUJEbVcXB3PMG9oF84Z2QUlFNcIS1eN5f79+C8qSKhyNUeBojPqTO7mTJUb4qcfz9nHjeF4iImqY0FgFFm+PRlFFNZytTfD1rH7o4WKt67CIiKgFNbgREhsbCwCQy+War+sjl8sbdM7r16/jyJEjKCgoAADs2LEDFy9exKBBgzBo0CAAwI8//ojw8PBmveWGiFofc2MDjO3uhNFdZcgeIsXtGlOcSMhRj+dNy9OM591w4gasTAzujOeVYbivFPYW918BRkREHZsQAl+GJuKTI3EQAujvYYuvZvSF1JJ/M4iIOpoGN0K6dlVv7iiE0HxdHyFEg85ZXFyMlJQUAMBLL70EAEhJSanVSBk9ejR8fOqfmDFjxgx4e3s36PsRUdskkUjQrZMV/F1s8EKQN/JKKnEy4Y/xvPmlVdh/OQv7L2dBIgF6udggWC5DkJ96PK+eHsfzEhF1ZGVVNXjpx0vYfyULADBjoBveHt8dRga8mpCIqCNqcCMkPT29zq//igEDBmDAgAFa10ybNk3r86+99lqTxEJEbYetuREm9O6MCb07o0YlcDE9D6Gx6sbI9axCXEzPx8X0fHz6WzyklsYYcedqkaE+DrA04YarREQdyc28Ujz3vzgk5JTBQE+Cdyd0x4yB7roOi4iIdKjBjRAXF5c6vyYi0iV9PQn6utuhr7sdXh3rh1sF5Tgep8CxWAXCEnOgvGc8b38PO/XVInIZvKTmdW6wTERE7cPZG7fxwrYLyC2tgr25ETbM6ov+Hna6DouIiHSswY2QixcvNvikvXv3bkQoRER/nZO1CZ4a4IanBrihoroGkcl5mkk0STklOJt0G2eTbuODX2PgameKYD8ZRshlGOxpDxNDfV2HT0RETUAIgc1nU/He/uuoUQn4yczw37kD4GJnruvQiIioFWhwIyQgIKDBJ23oHiFERM3J2EAfQ30cMNTHAW+N74aUO+N5Q++M503PLcP3Z1Px/dlUmBjqIdDLASPk6kk0HM9LRNQ2VVTX4K091/C/8+pbuSf07oQlQx3Rib/XiYjojgY3QvLy8jRf79ixAx999BE++ugj9O/fHwAQGRmJZcuWYfny5U0fJRFRE/BwMMczQ7vgmTvjeU8n5iA0TonQWAVuFZbj91gFfo9V4E0Avo4WCJLLEOwnQx93WxhyPC8RUaunKCxHyNYLiErLh54EWPaoHPMCPaBUKnUdGhERtSINboTY2Nhovv7ss8+wY8eOWrfAuLu7w9vbG7Nnz8a8efOaMkYioiZnbmyAMd2dMKa7E4QQiL1VpL5aJFaBqLQ8xGcXIz67GBtPJMHy7nhePxmG+0nhwPG8REStzsX0fDy/5TyyCytgZWKAz5/ug+G+UqhUKl2HRkRErUyDGyF/lpiYCFdX1/uOu7q6IjEx8S8HRUTUkiQSCbo6W6GrsxVeCPJGfmklTsQrcTxOieNxCuSVVuHA5SwcuDOet6eLDYL81JNo/DtZczwvEZGO7bhwE6/vvoLKahV8ZBb4ZnY/eDhwPxAiIqpboxohcrkc7733HlavXg0DA/Upqqur8d5770EulzdpgERELc3G7N7xvPmaSTTXMgtxKT0fl9LzsfZoAhwsjDHC74/xvFYcz0tE1GKqa1T48NdYfHs6GQAwupsj1kzrDQvjRpW4RETUQTTqr8RXX32FJ554QnN7jBACFy9eRGVlJQ4cONDUMRIR6Yx6PK8t+rrb4pUxfsgu/NN43oQc5BRXYMeFm9hxZzxvPw9b9XhePxm8ZRYcz0tE1EzySirx4vYonE68DQBYPNIHL4/04VV6RET0QI1qhAwePBhJSUnYvHkzrl+/DgB49NFHMWfOHFhZWTVpgERErYmjlQmm9XfDtP5uqKxWITIlVzOJJklZgvCkXIQn5eLDX2PhYmuqaYoM9uJ4XiKiphJ7qxDzN59Hem4ZzIz08enUXhjn76zrsIiIqI1o9HWD1tbWWLRoUVPGQkTUphgZ6CHQ2wGB3g5484luSL1dgtBYBY7FKRGedBs388qw+WwqNt8ZzzvEywFBflIEyWVwsTXTdfhERG3SwStZeOXnSyitrIGbnRm+nt0Xcid+EEdERA3X6EZISUkJjh49iqSkJCxZsgQAEB8fDx8fH14KTkQdkru9OeYGdsHcwC4orazGmcTbOBannkSTVVCOY7HqW2rwyzX4yCwQLJdhhJ8M/Tw4npeI6EFUKoG1R+Ox7ph6Y/6h3g744ukA2JgZ6TgyIiJqaxrVCImPj8eYMWNQXl6O7OxsTSPk/fffx+OPP46nnnqqSYMkImprzIwMMKqbI0Z1c4QQAnHZ6vG8x2OVuJCWhwRFMRIUxdh48s54Xh8pRvhJMcJPBqklx/MSEf1ZUXkVlvzvEo7GZAMA5g3tguWPymHAJjIRETVCoxohL7/8MqZOnYqPP/4Yenp//AF66aWXEBISwkYIEdGfSCQSyJ2sIHeywsIR3igorcKJBCWOxypwPF6J3JJKHLiShQNXsgAAvVysMcJPhmC5DD06czwvEXVsyTklmL/5PBIVxTAy0MPKv/fA5L4uug6LiIjasEY1Qs6ePYsffvjhvltg5HI5rly50iSBERG1V9Zmhvhbr074W69OqFEJXLqZj+OxChyLU+BqRiEu3SzApZsF+Oz3BDhYGGG4r0wzntfalON5iajjOB6nwOLt0Sgsr4aTlQk2zuqLXq42ug6LiIjauEY1QlQqFSorKwGgVjMkJSUF1tbWTRMZEVEHoK8nQR83W/Rxs8U/x/hBUViO43FKhMYpcCohBznFldgZdRM7o25CX0+Cfu53xvPKZfCRWeg6fCKiZiGEwNcnk/DxoVioBNDX3RbrZ/aBzNJE16EREVE70KhGyOjRo/HJJ5/g3//+t6YRkpOTg8WLF2PcuHFNGiARUUciszLB1P6umNrfFZXVKpxPyUVonHqT1RvKEkQk5yIiORcrD8ais40pRvhJ0cfJCONs7GFuwnvliajtK6uswdKdl7H3UiYA4Kn+rnh3QncYG3AEORERNY1GNUJWr16NESNGYN++fRBCICgoCOfPn4dUKsXWrVubOkYiog7JyEAPQ7wdMMTbAf96vBvSbpdqmiJnk24jI78M2yLSsA3A6weSMNjLXn21iJ8MrnYcz0tEbU9Gfhme23we1zILYaAnwdvju2HmIHdOJCQioibVqEaIu7s7Ll++jK1bt+L8+fNQqVSYNGkS5syZAysrznEnImoObvZmmDPEA3OGeKC0shpnb9zG7zHZ+D3mFrKLqnA8TonjcUoA1+CtGc8rRX8PO47nJaJWLyLpNhZui8LtkkrYmxvhqxl9MNDTXtdhERFRO9SoRggAWFpaYsGCBU0ZCxERNZCZkQFGdnVEkJ8UiwZLkS/McCIhB8diFbiQmodERTESFcX4+mQSLI0N8IivA0b4qRsjvMeeiFoTIQS2RqTh3b3XUK0S6N7JCl/P7ofONqa6Do2IiNqpRjdC7iovL7/vmIkJi2wiopYikUjg52iJrp2sETLcCwWlVTiVqMSxWAVOxClxu6QSv165hV+v3AIA9PzTeN6eHM9LRDpUWa3C23uvYvu5dADA+F6d8O/JPWFqxP1AiIio+TSqEZKQkICFCxfi9OnTKCsru+95IcRfDoyIiBrH2swQT/TshCd6doJKJXA5owDHYhUIjVXgSkYBLt9U/7Pu9wTYmxthuJ8UQX4yDPOVcjwvEbUYRVE5FmyNwoXUPEgkwNJxcjw/zJP7gRARUbNrVCNkzpw5sLe3x08//QQbG5smDomIiJqKnp4EvV1t0NvVBv8c7QtFUfmdvUQUOBWfg9slldgVlYFdURnQ15Ogr7stgu5cLeLraMH/ICGiZnH5Zj6e23wBtwrLYWligHXTAxDkJ9N1WERE1EE0qhESHR2NrKwsNkGIiNoYmaUJpvZzxdR+rqiqUSEyJRfH49S30SQqinEuORfnknPx8aE/xvMGy2UY4uXAS9WJqEnsirqJZbuuoLJaBS+pOb6Z3Q+eUgtdh0VERB1Io6fG5OTksBFCRNSGGerrYYiXA4Z4OeD1x7oiPfdP43lv/Gk8b0QajAz0MNjzj/G8bvYcz0ttx/fff4/Q0NBax1xcXLBixYpax1JSUrBp0yZkZ2ejR48emDdv3n37njVkDdWtukaFjw7G4j9hyQCAUV1lWDOtNyxNeEseERG1rEY1Qt5991384x//wKpVq+Dl5XXfpdMODg5NEhwREbUcVzszzB7sgdmDPVBWWYOzSTkIjVVfLZKRX4YT8UqciFfibVyDl9Rc0xTp52EHIwOO56XW6+zZs7h27RpeeOEFzTFbW9taa65evYrAwECMGTMGgwYNwoYNG7BlyxacOnUKhoaGDV5DdcsvrcSi7dE4lZADAFgU7I0lo3y5WTMREelEoxohjo6OuHLlCgYPHlzn89wslYiobTM10kew3BHBcke8JwQSFMUIjVVfLXI+NQ83lCW4oUzGN6eSYWFsgKHeDgiW3xnPa8VPx6n1cXd3x9y5c+t9funSpRgwYAB+/vlnAMDMmTPh7u6OzZs3Y968eQ1eQ/eLu1WE+ZvPIy23FKaG+lg9tRce6+Gs67CIiKgDa1QjZMGCBRgzZgwWLlzI22OIiNo5iUQCX0dL+Dpa4vnhXigoq0JYQo56PG+8AjnFlTh07RYOXVOP5/XvbIVgPxlGyGXo5WIDfX7iS61AbGwsFi5cCGtrazzyyCN47LHHNM9VVlbit99+w1dffaU55ujoiODgYOzbtw/z5s1r0Bq636Grt/DPny6itLIGLram+GZ2P3R1ttJ1WERE1ME1qhGSmpqK8PBwWFtbN3U8RETUylmbGuLxns54vKczVCqBK3fG8x6PU+DSzQJczSjE1YxCrDuWCDtzI4zwlWKEXIbhPlJYm/H2AWp5enp68PPzg1wuR0ZGBqZPn47x48dj69atAIC0tDRUVVXBw8Oj1us8PDxw6tSpBq+pS0VFBSoqKjSPCwsLAQAqlQoqlaoJfjr1uYQQTXa+pqBSCaw7loh1xxIBAIM97fH59N6wMzdq8ThbY35aE+anfsyNdsyPdsxP/ZorNw9zvkY1Qry9vZGVlcVGCBFRB6enJ0EvVxv0crXBktG+UBZV4ES8EqGxCpyMVyK3pBK7ojOwK/rOeF43W4yQqyfR+DlacjwvtYh33nkHMtkfo1knTZqEwYMH4+mnn8Zjjz2GsrIyAIC5uXmt11laWmqea8iauqxcuRLvvvvufceVSiXKy8sb9wPdQ6VSoaCgAEII6Onpfr+eksoavHc4BSdu5AMApvWWYdEwF1SX5ENR0vLxtLb8tDbMT/2YG+2YH+2Yn/o1V26KiooavLZRjZA5c+Zg5syZWLVqFby9ve8rZF1cXBp0HiEEDh8+jA0bNiA2NhabN2/GgAEDtL4mPT0d69atw5kzZ2BgYIChQ4fitdde4y06REStgNTSGFP6umBKXxdU1ahwITVPs7dIgqIY51JycS4lF/8+FIdO1iYYIZch2E+GId72MDNq1J8kogf6cxMEAAYOHAhXV1eEh4fjscceg5WV+laN/Pz8Wutyc3M1H/o0ZE1dli9fjn/+85+ax4WFhXB1dYVUKtWc869SqVSQSCSQSqU6L7ZTbpdgwY4oxCuKYaQvwYqJ/pjSt2F1YXNpTflpjZif+jE32jE/2jE/9Wuu3DzMFLdGVZ2vvvoqACA4OLjO5xu6WerSpUtx6dIlTJw4Eb/88gtKS0u1rq+pqUFwcDBCQkKwatUqlJaWYvny5Th06BDOnj0LIyOjh/tBiIio2Rjq62GQpz0Gedpj+Z3xvMfjFAiNU+J0Yg4yC8rxQ0QafrgznneQpz2C/NRXi7jbmz/4GxD9BaWlpZp6xdXVFdbW1rh27RoeffRRzZqrV6/C39+/wWvqYmxsDGNj4/uO6+npNWnxJ5FImvycD+tkvBIv/hCFwvJqyCyNsXFWXwS42T74hS2gNeSnNWN+6sfcaMf8aMf81K85cvMw52pUIyQmJqYxL7vP+++/D2NjY9y8eRMLFy584Hp9fX1cv3691og6FxcXdO3aFREREXjkkUeaJC4iImp6rnZmmDXYA7MGe6C8qgZnb9xGaJz6apGbeWU4Ga/EyXgl3t13HZ5ScwT5yRAsl6E/x/PSX1BdXY0DBw5gwoQJmmPr169HTk6OZsNUPT09TJs2Dd9++y1CQkJgYWGBiIgIRERE4J133mnwmo5KCIH/nErGyoMxUAkgwM0GG2b2hSMnSBERUSvVqEaIXC5vkm9e1yckD/LnJgjwcF0fIiJqHUwM9REklyFILsO7fxNIVBRrmiLnU/KQpCxBkjIZ/w1LhrmRPob6qMfzBvnJOJ6XHopEIsHWrVvx+uuvo1u3bkhLS0NMTAw+//xzDB48WLNu5cqVGDVqFHr06IEePXrg+PHjWLRoEcaOHftQazqa8qoaLN91BbujMwAAU/u54P2J/jA20NdxZERERPVr8zdkv/XWW3B3d9e6t0hH3bG9NWF+tGN+6sfcaNde8uMlNYeXtAueHdoFheXq8byhcUqciFcip7gSh69l4/C1bABA905WCPKTYoSf9IHjedtLfppDa9ixvSXo6+vj559/xo0bN3Dx4kXY2tqid+/esLOzq7XOzs4O586dw8mTJ5GdnY0PP/zwvlteGrKmI8nML8PzWy7gSkYB9PUkeOuJbpg92J2bIBMRUavXphshK1aswN69e/H7779rvbqkI+7Y3towP9oxP/VjbrRrr/np56iPfo5OeOURR8QpSnEmuQCnkwsQk12Ka5mFuJZZiC9Cb8DaRB+DPKwR6GGNgR5WsDap/WetveanKbSGHdtbkpeXF7y8vLSuMTAwqHf/s4dZ0xFEpuRiwdYLyCmuhK2ZIb6c0QdDvBx0HRYREVGDtNlGyKpVq/Dhhx9i7969tS5trUtH27G9NWJ+tGN+6sfcaNcR8uPkCAzvof46p7gCJ+NzEBqnwMmEHBSUV+NwbC4Ox+ZCTwIEuNkiyE+KID8p5E6WEEK0+/w0VmvYsZ3aph8i0vD23quoqhHo6myFr2f1haudma7DIiIiarA22QhZvXo13nrrLezduxejRo164PqOtGN7a8b8aMf81I+50a4j5UdmZYop/VwxpZ8rqmpUiErNw7E4BY7HKhGXXYQLqXm4kJqHT47Ew9naBCN8pQhwMsKjNvawNG2Tf/Kala53bKe2pbJahXf3XcO2iDQAwOM9nbFqSk+OviYiojan1f/levPNN3Hp0iXs3bsXALB27Vq8+eab2Lt3L0aPHq3j6IiISFcM9fUw0NMeAz3tsfzRrriZV4rjcUqExipw+kYOsgrKsT0yHdsBvPFrEgZ62msm0Xg4cDwv0cPIKa7Awq1ROJeSC4kEeHWMHxaO8OJ+IERE1CbptBGye/duLF++HNXV1QCA2bNnw8zMDC+++CJefPFFAEBWVhaSkpIAAHl5eViyZAksLS2xaNGiWudasWIFpkyZ0rI/ABERtRoutmaYOcgdMwe5o7yqBuFJt3EsRoGj17OQWViJUwk5OJWQg/f2X4engzlG3B3P28WWEy6ItLiaUYDnNp9HZkE5LI0N8Nn03giWO+o6LCIiokbTaSMkODgYe/bsue+4g8Mfm22tWLECZWVlAAArKyvExMTUeS5nZ+dmiZGIiNoeE0N9jPCTYZiPAxYMtEexxBzH43NwLFaByJRcJOWUICknGd+eVo/nDfRWj+cd4SeDkzX3uCC665eLGfi/HZdRUa2Cp9Qc38zuBy+pha7DIiIi+kt02gixtraGtbW11jVOTk6ar/X19SGXy5s7LCIiakckEgm8ZBbwcbLC/GGeKNKM51UgNE4JZVEFjlzPxpHr6vG83ZytECSXIlguQ29XW63jeYnaqxqVwL8PxWLjSfVVucFyGdY+1RtWJoY6joyIiOiva/V7hBARETUlSxNDPNrDGY/2cIZKJXAtsxChcQoci1Xg0s18XM8qxPWsQnwZegM2ZoYY7qtuigzzkcLW3EjX4RM1u4LSKiz+MRon4pUAgBeCvPDP0X5sChIRUbvBRggREXVYenoS9HCxRg8Xaywe6YPbxRU4Ea/EsVgFTsYrkV9ahV8uZuKXi5ma8bzBchmC/GTo6mzJjSKp3UnILsL8zeeRcrsUpob6WPVkTzzRs5OuwyIiImpSbIQQERHdYW9hjEl9XDCpjwuqa1SISstX30ITq0DsrT/G8646HAcnKxMEyaUY4SfDUG8HmBvzTyq1bb9dz8aS/11EcUU1OtuY4uvZfdG9k/ZbmImIiNoiVm1ERER1MNDXw4AudhjQxQ5Lx8mRkV+G43eaIqcTb+NWYTm2n0vH9nPpMLqzNkiunkTTheN5qQ1RqQS+CE3Ep7/FAwAGedrhy6f7wN7CWMeRERERNQ82QoiIiBqgs40pZgx0x4yB6vG8Ecm5CI1V7y2SlluKsMQchCXm4P391+Fhb6ZpigzoYsfxvNRqlVRU49WfL+Hg1VsAgLlDPPCvx7vCUF9Px5ERERE1HzZCiIiIHpKJoT6G+0ox3FeKt8d3Q1JOCUJjFQiNU+Bcci5Sbpdi0+kUbDqdArM743mD/GQIkkvhbG2q6/CJAABpt0vx3JbziL1VBCN9PayY6I+p/V11HRYREVGzYyOEiIjoL5BIJPCSWsBLaoFnH1GP5z2deFvTGFEUVeC369n47c543q7OVgjyU0+iCXDjeF7SjdOJOXjhhyjkl1ZBammMDTP7oq+7ra7DIiIiahFshBARETUhSxNDjPN3wjh/JwhxZzxvrALH4hS4mJ6PmKxCxGQV4qvj6vG8w3zujOf1lcKO43mpmQkh8O3pFHz4awxqVAK9XG2wcWZfOFmb6Do0IiKiFsNGCBERUTORSCTw72wN/87WWDTSB7kllTgRr0BorBIn7ozn3XspE3svqcfz9na1QbBchhF+MnTvZMXxvNSkyqtq8PruK9gVlQEAmNzHBR/83R8mhtzDhoiIOhY2QoiIiFqInbkR/h7ggr8HqMfzRqfnazZcjb1VhKi0fESl5eOTI/FwtDJGkJ+6KTLUxwEWHM9Lf8GtgnI8v+U8Lt0sgL6eBP96rCv+EejBZhsREXVIrKqIiIh0wEBfD/097NDfww7/N06OzPwyHI9T4lisAqcTc5BdWIEfI9PxY2Q6DPUl6vG8fn+M5+V/wFJDXUjNRcjWKCiLKmBjZogvn+6DQG8HXYdFRESkM2yEEBERtQKdbEzx9EA3PD3QDeVVNTiXnItjdzZcTb1ditOJt3E68TZWHIiBu73ZnSk0MgzsYsdbG6heP55Lw5u/XEVVjYDcyRJfz+oHN3szXYdFRESkU2yEEBERtTImhvoY5ivFMF8p3kF3JCmLERqnRGisAhHJt5F6uxTfnUnBd2dSYGp4ZzyvXIogPxk62Tx4PG+NSiAi6TYSb+bCu1gfAz0dOL2mnamqUeH9/dex+WwqAOBRfyd88mQvmPMWKyIiIjZCiIiIWjtPqQU8pRaYN7QLiiuqcToxRzOeN7uwAkdjsnE0Rj2eV+5kiSC5+haaAFcbGOjr1TrXoatZeHffdWQVlN85kgxnaxO8Pb4bxvk7t/BPRn9VXU2t/NJKLNwWhYjkXEgkwCujffFCkDdvpyIiIrqDjRAiIqI2xMLYAGO7O2Fsd/V43utZhXeaIkpEp+Uh9lYRYm8VYf3xG7A2NcQwXymC5VIM95XhXPJtLNgaBXHPOW8VlGPB1iisn9mHzZA2pK6mloOFEVQqILe0EhbGBlg7rTdGdXPUaZxEREStDRshREREbZREIkH3Ttbo3skaLwb7IK+kEifilQiNU2jG8+67lIl9lzIBAAZ6kvuaIAA0x97YcxXO1qZwtjaBzMqkxX4OeniHrmbV2dTKKa4EAMgsjfHD/IHwllm2fHBEREStHBshRERE7YStuREmBnTGxIDOqFEJXEzPw7FYBf4XmY6c4kpUq+pqg/whp7gSE748jZdG+mDJaN8WipoehqKwHFkF5Xhjz9U6m1p31agESipqoCgsZ1OLiIjoHnoPXkJERERtjb6eBH3d7fDaWDl+XfwIQoZ7Nuh1r431w4yBbs0cHTXWtog0TPjytObKj/rcLlE3tbZFpLVQZERERG0HGyFEREQdgJtdw0am2poZNnMk9FeM7e6IWYPcG7R21iB3jO3O/UGIiIjuxUYIERFRO7ctIg2v777aoLWv777KqwhascPXsrElPLVBa7eEp+LwtexmjoiIiKjt4R4hRERE7dyMgW4Y3c0RZxJz8OHB2HrXvf6oHEO8HSCzNG7B6OhhzBjohmC5DPO+j9R6e4yDhRH+O6c/nK25PwgREdG92AghIiJq52RW6ikw/p2t4WZvds/IVcDZ2gRvj+/G0bltwN3/L1dM9MeCrVEAUGvTVMmd/10x0R+9XG1aOjwiIqI2gY0QIiKiDmScvzNGd3NCRFIOEm8q4e0ixUBPB+jrSR78Ymo1xvk7Y/3MPvc1tZzY1CIiInogNkKIiIg6GH09CQZ52sPTogYymT302ARpk9jUIiIiahw2QoiIiIjaKDa1iIiIHh6nxhARERERERFRh8FGCBERERERERF1GGyEEBEREREREVGHwUYIEREREREREXUYbIQQERERERERUYfRIafGCCEAAIWFhU12TpVKhaKiIpiYmEBPj/2lezE/2jE/9WNutGN+tGN+6tdcubn7t/Xu31qqjTVIy2N+tGN+6sfcaMf8aMf81K811CAdshFSVFQEAHB1ddVxJERERO1TUVERrK2tdR1Gq8MahIiIqHk1pAaRiA74kY1KpUJmZiYsLS0hkUia5JyFhYVwdXVFeno6rKysmuSc7Qnzox3zUz/mRjvmRzvmp37NlRshBIqKitCpUyd+AlYH1iAtj/nRjvmpH3OjHfOjHfNTv9ZQg3TIK0L09PTg4uLSLOe2srLiG10L5kc75qd+zI12zI92zE/9miM3vBKkfqxBdIf50Y75qR9zox3zox3zUz9d1iD8qIaIiIiIiIiIOgw2QoiIiIiIiIiow2AjpIkYGxvj7bffhrGxsa5DaZWYH+2Yn/oxN9oxP9oxP/VjbtoP/n+pHfOjHfNTP+ZGO+ZHO+anfq0hNx1ys1QiIiIiIiIi6ph4RQgRERERERERdRhshBARERERERFRh8FGCBERERERERF1GAa6DqAtKS4uxqVLl+Dm5gZXV9cGvSY3Nxc3btyAi4sLnJ2dmzlC3crIyEBycjJ69eoFS0tLrWsTEhKQnZ1d65ilpSV69erVnCHqTElJCRISEiCTydCpU6cGvUalUuH69euoqamBv78/9PX1mzlK3VEqlcjIyICHhwdsbGy0ri0tLUVUVNR9x3v06NHgueFtTWZmJhQKRYPyc5dCoUBqaio8PDwglUqbN0AdUqlUiI+PhxACnp6eD9x06+rVq8jPz691zN7eHl27dm3GKHUvLi4OSqUSffv2hampqda11dXVuHbtGgwMDNCtWzdIJJIWipK0YQ2iHWuQ+rEG0Y41iHasQerHGqRhWm0NIuiBMjIyxAsvvCCcnZ2FkZGReP/99xv0unfffVcYGxuLbt26CWNjYzF37lxRXV3dzNG2vPDwcDFhwgTh4OAgAIizZ88+8DVz5swRUqlUBAYGav6ZN29eC0TbsjIyMsSsWbOEtbW16N27t7CxsRGPPPKISE1N1fq6a9euCW9vb+Hk5CQ6d+4s3NzcRGRkZAtF3XLOnDkjhg4dKmQymejdu7cwNTUVzz77rKiqqqr3NVeuXBEAxIABA2q9f6Kiolow8pZx+vRpMWDAAOHm5iZ69eolTExMxLx587TmR6VSiUWLFtX63fPKK6+0YNQtZ+PGjcLV1VV0795deHl5CVtbW7Fx40atrxk5cqRwcXGp9d5Zvnx5C0WsGzExMcLS0lIAEDExMVrXnjlzRnTu3Fm4uroKmUwm5HK5iIuLa6FIqS6sQbRjDVI/1iDasQbRjjWIdqxBGqY11yBshDTAyZMnxbp160R+fr5wd3dvUBGyf/9+YWBgIE6ePCmEECI+Pl7Y2NiI1atXN3e4Le6bb74Ru3btEjExMQ9VhMyYMaMFotOtM2fOiC1btmiKz8LCQhEYGCiCgoLqfU1NTY3o3r27mDJlilCpVEIIdb7c3d1FRUVFi8TdUr7//nsRFhameRwXFydsbW3FBx98UO9r7hYhWVlZLRGiTv3www/i6tWrmscxMTHCzMxMrF+/vt7X/Oc//xEWFhbi8uXLQgghIiMjhbGxsdi2bVuzx9vSPv30U5GTk6N5vHHjRiGRSMSNGzfqfc3IkSPF0qVLWyK8VqGsrEz07NlT/N///d8Di5DS0lLRqVMnsXDhQiGEENXV1eKxxx4Tffr0aalwqQ6sQbRjDVI/1iDasQbRjjWIdqxBHqy11yBshDykhhYhkyZNEqNGjap1LCQkRHTv3r25QtO5hISEhypCJk2aJM6fPy+SkpJETU1NC0TYOmzYsEEYGxtrCox7nTlzRgAQFy9e1BxLTEwUAMTBgwdbKkydmTJlinj00Ufrff5uEXL69GkRHR0tioqKWjA63fPy8hJvvPFGvc8PGTJEzJw5s9axiRMnipEjRzZ3aDoXHx8vANQqbO81cuRIsXDhQhEZGSnS0tLq/fewvViwYIF49tlnxdmzZx9YhOzatUtIJBKRmZmpORYWFiYAiOjo6BaIlh6ENUj9WIM0DGsQ7ViDaMcapH6sQe7X2msQbpbaTKKjo9G3b99axwYMGICYmBhUVFToKKrWZd++fXjmmWcwYMAAeHp64rffftN1SC0iMjISnp6e9d7zFh0dDQMDA/Ts2VNzzMvLC3Z2doiOjm6pMHWiuroaFy9ehLe39wPXTp06FU8//TTs7OzwwgsvoLKysgUibHnl5eUICwvDkSNH8MILL0ClUmH+/Pn1rq/vd097fe9kZWUhLCwMe/bswbPPPovx48dj8ODBWl/z7bff4tlnn0XPnj3Ro0cPREZGtlC0LWv37t04evQo1q5d26D10dHR6NSpU629JAYMGKB5jtoO1iAPxhqENci9WIPcjzWIdqxB6tcWahBultpMcnNzYW9vX+uYvb09VCoV8vPz4ejoqKPIWofx48dj9erVsLe3R3V1NV555RVMnjwZV69ehZubm67DazaHDx/Gpk2bsHXr1nrX5Obmws7O7r4ixd7eHrm5uc0dok698cYbyM7Oxssvv1zvGisrKxw8eBDjxo0DoP7lGBwcDBsbG3zwwQctFGnLuX37NpYtW4aCggIkJyfj9ddfh4uLS51ry8vLUVZWVufvnry8PAgh2t3Gl2fPnsWnn36KjIwM1NTUYMOGDdDTq7/H/8wzz2DPnj2wsLBAWVkZnnnmGUycOBHXr19vVxvdpaWlISQkBPv374e5uXmDXlPX3y1DQ0NYWlq2+9897Q1rEO1Yg7AGqQtrkPuxBtGONUjd2koNwitCmomhoSHKy8trHSsrKwMAGBkZ6SKkVmXy5MmaN7uBgQE++eQTVFdX48CBAzqOrPmEh4fjySefxPLlyzF9+vR619X13gHU75/2/N757LPPsHbtWvz000/w9PSsd52bm5umAAGAgIAAPP/88/jxxx9bIswW17lzZ4SFheHKlSuIjIzEmjVrsHLlyjrXGhoaAkCdv3sMDAzaXQECAJMmTUJYWBiSk5PxwQcf4IknntD66crTTz8NCwsLAICpqSnWrl2LzMxMnDx5sqVCbhEhISEYNmwYKioqEBYWhsuXLwMAoqKikJiYWOdr6vvdU15e3q5/97RHrEG0Yw3CGuRerEHqxhpEO9YgdWsrNQgbIc3E3d0dGRkZtY5lZGTA0tIStra2Ooqq9TI0NIStre19OWsvIiIiMHbsWCxcuBArVqzQutbd3R2FhYUoKirSHKusrIRSqWy3n1R98cUXWLp0KXbu3FmrwGgoR0fHdvve+bOuXbviiSeewMGDB+t8Xl9fH507d67zd4+7u3tLhKhTs2bNgqOjIw4fPtzg19jb20NfX7/dvX8cHByQlZWFZcuWYdmyZfjyyy8BAKtXr8bOnTvrfI27uztu3boFlUqlOaZQKFBVVdVuf/e0V6xBHg5rkD+wBmENUh/WINqxBvlDW6lB2AhpIgqFAmFhYaipqQEAjB49GgcPHkR1dbVmzS+//IJRo0bpKkSdio+Px6VLlwAANTU193X8rl27hszMTPj7++sivGYVGRmJsWPHIiQkBB999FGdayIiIpCWlgYACAoKgoGBAfbt26d5/vDhw6isrGyX758vv/wSr776Knbs2IHHH3/8vudLSkoQFhaGgoICzeN7/fbbb+3yvVPXz3rjxo1alw7evHkTZ86c0TwePXo09u3bByEEAPWM+3379mH06NHNH3ALKi8v1/y+vSs3N/e+SyuvXLmCmJgYAEBFRcV9r/n9999RU1PT7t4/mzdvRlhYmOafjRs3AgC2bduGpUuXataFhYUhKysLgPq9U1hYiOPHj2ue/+WXX2BkZIRhw4a1aPz0cFiDaMcahDVIfViD1I81SP1Yg2jXZmqQZtmCtZ0pKysTp06dEqdOnRJOTk5i/vz54tSpU+LKlSuaNZs2bRIARF5enhBCiFu3bgknJycxadIksXfvXrFgwQJhampaaxfu9iIrK0ucOnVK/PjjjwKA2Lhxozh16pRIT0/XrJkxY4bo27evEEKIoqIi0b17d7FmzRpx6NAhsWHDBuHq6iqGDBkiKisrdfVjNIurV68KGxsbMWrUKM176O4/f57Dbm9vL/71r39pHr/22mvC3t5efPvtt2LLli3C2dlZPPfcc7r4EZrVd999JyQSiVi2bFmt3Px5d+jo6GgBQISGhgohhHj11VfFc889J3766Sfxyy+/iOnTpwsjIyNx5MgR3fwQzWjw4MFixYoV4tdffxW7d+8W06ZNEyYmJuLMmTOaNStXrhTGxsaax/Hx8cLKykrMnTtX7N27Vzz99NPC1tZWpKSk6OJHaDaxsbGif//+Yv369eLIkSPi+++/FwEBAcLHx0cUFBRo1g0fPlxMmDBBCKGefNCnTx/x1VdficOHD4s1a9YIe3t78fe//11HP0XLqWvH9qqqKgFAfP7555pjs2bNEm5ubmLbtm3im2++EdbW1uKtt97SRch0B2sQ7ViD1I81iHasQbRjDVI/1iAPp7XWINwstQHubhQEqHfOvn79OpYtW4b+/ftjzZo1ANSXxQUGBsLAwEDzODw8HB9//DHWrl0LFxcXnD59Gr169dLZz9FcIiIisGrVKgBAYGAgNm/eDABYsGABZsyYAQDw8/ODiYkJAMDCwgKHDh3CF198gUOHDsHe3h5vvPEGnnnmGU3+2ovk5GR0794dZWVlmvfQXQcOHNBsjDRo0KBalw1+9NFH8Pb2xo4dO6BSqbB8+XIsWLCgRWNvCcnJyRgyZAhOnTqFU6dOaY77+Phg06ZNANTvl8DAQE2uPv74Y/zwww/YuXMnioqK4Ofnh5iYGK339LZVBw8exJdffomvvvoK+vr66NatG+Li4mpdIujq6orAwEDNYx8fH5w9exarV6/GmjVr4OXlhfDw8HZ3Waqfnx+2bNmC9evXY/fu3bC1tcXcuXPx7LPPwszMTLOuR48esLS0BKD+/b19+3Z89dVX2LNnD5ycnPDFF19g2rRpuvoxWoyVlRUCAwNr5UYikSAwMBCdOnXSHPvvf/+LL774Aps3b4aBgQHWrFmDuXPn6iBiuos1iHasQerHGkQ71iDasQapH2uQh9NaaxCJEHeuXSIiIiIiIiIiaue4RwgRERERERERdRhshBARERERERFRh8FGCBERERERERF1GGyEEBEREREREVGHwUYIEREREREREXUYbIQQERERERERUYfBRggRERERERERdRhshBBRvXbv3o20tLR28b337duHpKSkJjsfERERNR/WIETUnNgIIaJ6zZ8/H2fOnPnL59m7dy+Sk5N18r3vWrRoEY4dO9Zk5yMiIqLmwxqEiJoTGyFE1OwWLlyIEydO6DSG8ePHw8vLS6cxEBERUctiDUJEdTHQdQBE1PplZmbi0qVLsLKywpAhQyCRSDTPHT16FDk5OZBIJHB2dkZAQAAsLS01zx8+fBhlZWWIiIiAiYkJ9PX18eSTTwIAqqqqcO7cOeTl5aF///5wdHS873tnZ2fj4sWLsLCwwKBBg6Cvr6811qioKNy8eRM+Pj7o2rWr5viYMWPg7u4OAEhISMCFCxfue62fnx8CAgIAAJWVlQgPD0dBQQG6devGAoaIiEgHWIOwBiFqDmyEEJFW3377LV599VX07NkTkZGR6NWrFw4cOABjY2MAwIkTJ5CQkAAhBJKSkpCWloadO3di6NChAIDQ0FCUlZUhKioKeXl5MDIywpNPPono6GhMmjQJenp6kMvlWLRoEd5//33MnDlT872/++47/Otf/0K3bt1w4cIFeHt7IzQ0tM5CpKKiAo8++igSExPRp08f3LhxAz4+Pti5cyckEgkWLVqEN954A56enkhOTsaePXs0r62pqcHu3bvx0ksvISAgABcvXsTEiRNhZ2eHzp07Izw8HJMnT8aGDRuaN9lERESkwRqENQhRsxFERPWwt7cX7u7uQqlUCiGEyMrKEk5OTuLTTz+t9zUffPCB8Pf3r3Wsc+fOYtOmTZrH5eXlwtXVVcydO1dUV1cLIYQoKysThw4dqvW9BwwYIEpKSoQQQmRnZwtzc3Oxa9euOr/v/v37ha2trSguLtYc27Nnj6ipqRFCCOHu7i6++eabOl/7yiuvCKlUKlJSUkRlZaXw8PAQa9as0TyvUCiEs7Oz2L59e70/NxERETUd1iBqrEGImgevCCEirf7xj3/AwcEBAODk5ITZs2fjp59+wpIlSzRr0tLSEBMTg/z8fBgaGuLq1asoLS2FmZlZnec8duwY0tPT8dFHH2k+WTExMcHYsWNrrZszZ47mHDKZDF27dkVcXFyd5zQ1NUVFRQXi4uLQp08fAMCECRMe+PNt3boV69atw9GjR+Hu7o4jR44gNTUVMpkMO3bsgBACQgh4eXkhNDQUTz311APPSURERH8daxDWIETNhY0QItLKw8Oj1uMuXbpgy5YtmseLFi3Cpk2b0L9/fzg4OKCsrAwAoFQqNffD3istLQ1WVlZ13o/7Z3Z2drUeGxsbo7y8vM61wcHBWLx4MYKDg+Ho6IiRI0fiueeeQ+/eves9//nz5zF//nysW7cOw4YNAwCkpKTAyMgIe/furbW2c+fO8PX11RovERERNR3WIGqsQYiaHhshRKRVXl7efY/vfjoTFRWFL7/8EgkJCZqNvMLDw3HgwAEIIeo9p42NDYqLi1FRUaG5z7cprFy5Eu+99x4uXLiAH374AQMGDEB0dDS6d+9+39pbt25h4sSJ+Mc//oGQkBDNcSsrK1RWVuI///kPLCwsmiw2IiIiejisQYiouXB8LhFp9ecNvYQQ2L17NwIDAwGo/5CbmprW+tRlx44d953DwsKi1qcow4cPh4GBAbZt21ZrnVKpbHSct27dQk1NDQwNDTFo0CCsW7cOlpaWde7MXllZiUmTJsHb2xufffZZredGjBgBIyMjfP3117WO19TUIDs7u9HxERER0cNhDaLGGoSo6fGKECLS6tq1a5gyZQrGjBmD/fv3IzExUVNoDB48GBYWFpg6dSqeeOIJRERE4Oeff77vHP369cO3334LMzMzmJqa4sknn8SqVauwYMECXLlyBd26dcOZM2fg4OCAVatWNSrO06dP47333sOUKVPg5uaG0NBQSCQSBAcH37f2o48+QmRkJNasWYOdO3dqjt8dXbd27VosWrQIsbGxGDhwIG7evImdO3fiww8/xBNPPNGo+IiIiOjhsAZhDULUXHhFCBHVa9KkSdi1axfGjBmDCxcuwNfXF5GRkXBzcwMA2NraIjw8HN7e3jh+/Djc3Nxw8uRJTJs2Debm5przrFu3Dn/729/w+++/Y9++fQCAxYsXIzQ0FABw7tw5BAUF4d///net733v/b2jRo2Cv79/nbFOnjwZ27dvR1VVFU6cOAFvb29cvHgRLi4uAIDx48drLp11dXXF5MmTERYWhj179mj+uXLlCgAgJCQE586dg52dHU6ePAkA+Pnnn1mAEBERtRDWIKxBiJqTRGi7iY6IiIiIiIiIqB3hFSFERERERERE1GGwEUJEREREREREHQYbIURERERERETUYbARQkREREREREQdBhshRERERERERNRhsBFCRERERERERB0GGyFERERERERE1GGwEUJEREREREREHQYbIURERERERETUYbARQkREREREREQdBhshRERERERERNRhsBFCRERERERERB3G/wOQiGsFfmTT3AAAAABJRU5ErkJggg==",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, axes = plt.subplots(1, 2, figsize=(11, 4))\n",
"latency_yerr = np.vstack(\n",
" [\n",
" benchmark_frame[\"latency_per_pose_ms\"]\n",
" - benchmark_frame[\"latency_per_pose_q1_ms\"],\n",
" benchmark_frame[\"latency_per_pose_q3_ms\"]\n",
" - benchmark_frame[\"latency_per_pose_ms\"],\n",
" ]\n",
")\n",
"axes[0].errorbar(\n",
" benchmark_frame[\"batch_size\"],\n",
" benchmark_frame[\"latency_per_pose_ms\"],\n",
" yerr=latency_yerr,\n",
" marker=\"o\",\n",
" capsize=4,\n",
")\n",
"axes[0].set(\n",
" xlabel=\"batch size\",\n",
" ylabel=\"median milliseconds / pose\",\n",
" title=\"Amortized latency (Q1–Q3)\",\n",
")\n",
"throughput_yerr = np.vstack(\n",
" [\n",
" benchmark_frame[\"throughput_poses_s\"]\n",
" - benchmark_frame[\"throughput_q1_poses_s\"],\n",
" benchmark_frame[\"throughput_q3_poses_s\"]\n",
" - benchmark_frame[\"throughput_poses_s\"],\n",
" ]\n",
")\n",
"axes[1].errorbar(\n",
" benchmark_frame[\"batch_size\"],\n",
" benchmark_frame[\"throughput_poses_s\"],\n",
" yerr=throughput_yerr,\n",
" marker=\"o\",\n",
" capsize=4,\n",
")\n",
"axes[1].set(\n",
" xlabel=\"batch size\",\n",
" ylabel=\"poses / second\",\n",
" title=\"Scoring throughput (Q1–Q3)\",\n",
")\n",
"for axis in axes:\n",
" axis.grid(alpha=0.3)\n",
"fig.suptitle(\n",
" \"Measured CUDA batching\" if device.type == \"cuda\" else \"CPU smoke check — not GPU scaling\",\n",
" fontweight=\"bold\",\n",
")\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"id": "6f225fd1",
"metadata": {},
"source": [
"**Expected observations.** Over the range where one pose under-fills a GPU, total batch-call latency generally grows more slowly than batch size. That is why the separate amortized metric—total milliseconds divided by poses—falls and throughput rises until compute or memory bandwidth saturates. The total latency does not become a per-pose latency, and batching is not superlinear algorithmic scaling: scoring work still grows with the number of poses.\n",
"\n",
"The published documentation executes this notebook on a CI GPU after warmup, so its tables and plots are real CUDA measurements. They remain one runner-specific snapshot rather than portable performance claims: GPU model, software versions, structure sizes, and competing work all affect the curve. Rerun the notebook in its Colab GPU environment when those details matter. First-call compilation is intentionally excluded.\n",
"\n",
"## CUDA-only capacity probe\n",
"\n",
"This `gpu-only` cell demonstrates a larger batch and allocator memory. The GPU CI lane executes it, while the hosted CPU docs build preserves its checked-in output."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cb914094",
"metadata": {
"tags": [
"gpu-only"
]
},
"outputs": [],
"source": [
"#| tags: [gpu-only]\n",
"# gpu-only: this capacity point is omitted on CPU.\n",
"if device.type != \"cuda\":\n",
" print(\"Skipped: this cell requires CUDA.\")\n",
" gpu_capacity_point = None\n",
"else:\n",
" gpu_capacity_point = benchmark_scoring(128, repeats=5, warmup=2)\n",
" show_table(pd.DataFrame([gpu_capacity_point]))\n",
"gpu_capacity_point"
]
},
{
"cell_type": "markdown",
"id": "670c9440",
"metadata": {},
"source": [
"## Memory, padding, and chunking\n",
"\n",
"A larger batch is not always faster. `PoseStack` pads every member to the batch maxima for atoms and blocks, so one large structure can make all shorter members occupy a larger rectangular layout. Pairwise scoring intermediates may also grow with atom and block dimensions. Padding therefore affects both useful throughput and total memory; it is not merely display metadata.\n",
"\n",
"`post_construction_cuda_MiB` is the live PyTorch allocation after constructing the batch and rendered scorer. `peak_cuda_MiB` is the total peak observed during warmup and timed calls, and `incremental_peak_cuda_MiB` is their difference. This makes the temporary scoring increment explicit instead of presenting the live setup allocation as scoring-only memory. These allocator measurements still exclude non-PyTorch driver/process memory, are not per-pose quantities, and should not be divided by batch size: setup tensors, padding, and shared term intermediates are not independent per-pose allocations.\n",
"\n",
"Use both the baseline and incremental peak as capacity indicators, leave headroom for compilation and downstream tensors, and split a workload into chunks before allocator pressure causes an out-of-memory error. A practical pattern is: choose a conservative per-device chunk size, build and score one chunk, immediately detach or transfer the small results you need, release chunk references, and continue. Grouping similarly sized structures reduces padding waste.\n",
"\n",
"TMol has no built-in multi-GPU scheduler. One process should normally own one GPU; an external Slurm, Dask, Ray, or multiprocessing layer can shard independent chunks across devices."
]
},
{
"cell_type": "markdown",
"id": "92693810",
"metadata": {},
"source": [
"## Rosetta comparison: two complementary levels of parallelism\n",
"\n",
"TMol batching vectorizes compatible structures inside one process on one device. PyRosetta Chapter 16 mostly distributes independent jobs, trajectories, or protocols across processes and workers. Job distribution handles heterogeneous or long-running tasks; TMol batching amortizes kernels over tensor-compatible work. An outer scheduler can combine both ideas by assigning one TMol batch stream to each GPU. The [Rosetta-to-TMol crosswalk](rosetta_crosswalk.md) distinguishes this tensor batching from Rosetta protocol distribution.\n",
"\n",
"Representative Chapter 16 entry points:\n",
"\n",
"- [16.00 Running PyRosetta in Parallel](https://nbviewer.org/github/RosettaCommons/PyRosetta.notebooks/blob/master/notebooks/16.00-Running-PyRosetta-in-Parallel.ipynb) introduces the landscape.\n",
"- [16.03 GNU Parallel via Slurm](https://nbviewer.org/github/RosettaCommons/PyRosetta.notebooks/blob/master/notebooks/16.03-GNU-Parallel-Via-Slurm.ipynb) shows process/job distribution.\n",
"- [16.04 Dask delayed via Slurm](https://nbviewer.org/github/RosettaCommons/PyRosetta.notebooks/blob/master/notebooks/16.04-dask.delayed-Via-Slurm.ipynb) shows task-graph scheduling.\n",
"- [16.06 PyRosettaCluster simple protocol](https://nbviewer.org/github/RosettaCommons/PyRosetta.notebooks/blob/master/notebooks/16.06-PyRosettaCluster-Simple-protocol.ipynb) introduces protocol distribution.\n",
"\n",
"The rendered [PyRosetta notebook index](https://rosettacommons.github.io/PyRosetta.notebooks/) links the remaining Chapter 16 examples and setup material."
]
},
{
"cell_type": "markdown",
"id": "2b6ccb46",
"metadata": {},
"source": [
"## Next: interpret the scores\n",
"\n",
"Batch construction, timing, and capacity planning are now separated from scientific interpretation. Continue to [Scoring and Analysis](03_scoring_and_analysis.ipynb) to decompose weighted totals, inspect residue-pair contributions, and ask comparisons that use a consistent molecular system and protocol."
]
},
{
"cell_type": "markdown",
"id": "13d6abc3",
"metadata": {},
"source": [
"## Exercises\n",
"\n",
"1. Increase the repeat count and compare IQR with the full min–max timing range.\n",
"2. Increase CUDA batch sizes until throughput plateaus, stopping well before memory exhaustion.\n",
"3. Repeat the executed bucketing experiment with at least two members per size range, then choose bucket boundaries from measured memory and throughput rather than residue count alone.\n",
"4. Implement an outer loop that scores a large list in conservative chunks and concatenates detached totals.\n",
"5. Design a Slurm array where each task selects one GPU and processes many TMol batches; keep random seeds and metadata per task."
]
},
{
"cell_type": "markdown",
"id": "ce7c62c6",
"metadata": {},
"source": [
"## References\n",
"\n",
"- [Rosetta-to-TMol crosswalk](rosetta_crosswalk.md)\n",
"- [TMol repository](https://github.com/uw-ipd/tmol)\n",
"- [PyTorch CUDA semantics](https://pytorch.org/docs/stable/notes/cuda.html)\n",
"- [PyTorch benchmarking recipe](https://pytorch.org/tutorials/recipes/recipes/benchmark.html)\n",
"- [PyRosetta Chapter 16 index](https://rosettacommons.github.io/PyRosetta.notebooks/)\n",
"- [GNU Parallel via Slurm notebook](https://nbviewer.org/github/RosettaCommons/PyRosetta.notebooks/blob/master/notebooks/16.03-GNU-Parallel-Via-Slurm.ipynb)\n",
"- [Dask via Slurm notebook](https://nbviewer.org/github/RosettaCommons/PyRosetta.notebooks/blob/master/notebooks/16.04-dask.delayed-Via-Slurm.ipynb)"
]
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 5
}