{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# How to use NeXus/HDF5 Templates\n", "\n", "Show how to use templates to write powder diffraction data using the NeXus\n", "[NXmonopd](https://manual.nexusformat.org/classes/applications/NXmonopd.html#nxmonopd)\n", "application definition. Templates are used to:\n", "\n", "- make links from existing fields or groups to new locations\n", "- create new groups as directed\n", "- create constants for attributes or fields\n", "\n", "## Overview\n", "\n", "This powder diffraction experiment positions a sample on a rotation stage (called\n", "`th`, or $\\theta$) and a detector at some distance on a second rotation axis\n", "(called `tth`, or $2\\theta$). The experiment moves $2\\theta$ through an\n", "angular range while synchronizing $\\theta$ to half of the $2\\theta$\n", "value. The intensity of incident (`I0`) and scattered radiation (`sensor`) are\n", "sampled at discrete angular intervals. The `I0` detector is positioned before\n", "the sample. It does not move during the experiment. The `sensor` detector is\n", "mounted on a long arm projecting from the $2\\theta$ rotation." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Build the powder diffraction instrument\n", "\n", "We simulate a powder diffraction instrument with a monochromatic source with a\n", "Bluesky hardware setup similar to the\n", "[guide](https://bcda-aps.github.io/apstools/latest/examples/fw_nxwriter.html) to\n", "output scans(s) to a NeXus HDF5 file. These are the modifications of that setup:\n", "\n", "* Continue to use EPICS PVs for the simulation\n", "* Change `motor` to `tth` ($2\\theta$)\n", "* Add `th` ($\\theta$) motor\n", "* Change sensor to a simulated Lorentzian\n", " * based on `tth` readback value\n", " * calculation will re-compute as motor position changes\n", " * center: randomly placed between 3 .. 8 degrees\n", " * width: random between 0.01 .. 0.51 degrees\n", " * height: random (~10,000)\n", "* Add `I0` signal\n", " * Constant value: `100,000`" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "%matplotlib inline\n", "import random\n", "from apstools.synApps import setup_lorentzian_swait\n", "from apstools.synApps import setup_random_number_swait\n", "from apstools.synApps import SwaitRecord\n", "from bluesky import RunEngine\n", "from bluesky import plans as bp\n", "from bluesky import plan_stubs as bps\n", "from bluesky.callbacks.best_effort import BestEffortCallback\n", "from matplotlib import pyplot as plt\n", "from ophyd import EpicsMotor\n", "from ophyd import EpicsSignalRO\n", "from ophyd import Signal\n", "import databroker\n", "\n", "# bluesky-level\n", "best_effort_callback = BestEffortCallback()\n", "cat = databroker.temp().v2\n", "plt.ion() # enables matplotlib graphics\n", "RE = RunEngine({})\n", "RE.subscribe(cat.v1.insert)\n", "RE.subscribe(best_effort_callback) # LivePlot & LiveTable\n", "\n", "IOC = \"gp:\"\n", "\n", "# ophyd-level\n", "th = EpicsMotor(f\"{IOC}m9\", name=\"th\")\n", "tth = EpicsMotor(f\"{IOC}m10\", name=\"tth\")\n", "calc10 = SwaitRecord(f\"{IOC}userCalc10\", name=\"calc10\")\n", "I0 = Signal(name=\"I0\", value=100_000)\n", "sensor = EpicsSignalRO(calc10.calculated_value.pvname, name=\"sensor\")\n", "\n", "# set up calc10, updating at 10Hz\n", "calc10.wait_for_connection()\n", "tth.wait_for_connection()\n", "setup_lorentzian_swait(\n", " calc10,\n", " tth.user_readback,\n", " center=3 + 5 * random.random(),\n", " width=0.01 + 0.5 * random.random(),\n", " scale=10_000 * (0.98 + 0.04 * random.random()),\n", " noise=0.02\n", ")\n", "\n", "# wait for the other connections\n", "th.wait_for_connection()\n", "sensor.wait_for_connection()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Write data to a NeXus/HDF5 file\n", "\n", "Use the `NXWriter()` from `apstools`. Choose where to write the HDF5 file." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "from apstools.callbacks import NXWriter\n", "import json\n", "import pathlib\n", "\n", "h5_file = pathlib.Path(\"/tmp/nxwriter.h5\")\n", "\n", "nxwriter = NXWriter()\n", "RE.subscribe(nxwriter.receiver)\n", "nxwriter.file_name = str(h5_file)\n", "nxwriter.warn_on_missing_content = False" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Use the NXmonopd application definition\n", "\n", "Steps to configure the NXWriter to write raw data using the NeXus\n", "[NXmonopd](https://manual.nexusformat.org/classes/applications/NXmonopd.html#nxmonopd)\n", "powder diffraction application definition.\n", "\n", "1. Review the definition. Note what are the required groups and fields.\n", "2. Write them as comments into a prototype of the template structure to be used.\n", "3. Collect data from a $2\\theta:\\theta$ scan.\n", "4. Examine the HDF5 file.\n", "5. Create templates to connect existing data with NXmonopd definition.\n", "6. Add constants and attributes as appropriate.\n", "7. Collect data again with revised template and compare with the NXmonopd definition.\n", "\n", "### Decisions when making the template.\n", "\n", "To write data according to the *NXmonopd* definition, we must make some decisions\n", "about linking to existing data and creating any new required structures.\n", "\n", "First decision is where to write the structure of the application definition (\n", "whether or not to use a\n", "[NXsubentry](https://manual.nexusformat.org/classes/base_classes/NXsubentry.html#nxsubentry)\n", "group). The *NXsubentry* group is used for *multi-modal* experiments (such as\n", "SAXS/WAXS). Here, we are only writing raw monochromatic powder diffraction\n", "data. We do not need to use a *NXsubentry* group. We will write the structure\n", "into the NXentry group.\n", "\n", "A NeXus file that uses an [application\n", "definition](https://manual.nexusformat.org/classes/applications/index.html#application-definitions)\n", "needs a `definition` field with the name of the application definition. In this\n", "case, the name is `\"NXmonopd\"`. We write this with a *constant* template:\n", "\n", " [\"/entry/definition=\", \"NXmonopd\"]\n", "\n", "The *NXmonopd* definition requires the *NXentry* group contain these fields: `title`\n", "and `start_time`. These fields are already provided by `NXWriter()`. Nothing\n", "more needs to be done.\n", "\n", "*NXmonopd* requires a *NXcrystal* group with a `wavelength` field. This is a\n", "simulation, we can use any wavelength. It is convenient here to pass the\n", "wavelength as run metadata. (If it was available as an ophyd signal, it could\n", "be recorded in the `baseline` stream.) We'll call it `mono_wavelength` in the\n", "metadata. `NXWriter()` writes this metadata to the HDF5 address:\n", "`/entry/instrument/bluesky/metadata/mono_wavelength`\n", "\n", "The *NXcrystal* group is not created in the standard `NXWriter()`\n", "file. We can create it and give it the name of `crystal` by using a *class\n", "path*: `crystal:NXcrystal` which specifies both the group name and the NeXus\n", "base class for the new group. The next template connects the run metadata\n", "`wavelength` with the location required by *NXmonopd* (note that the name of the\n", "target field does not have to be the same as the source):\n", "\n", " [\n", " \"/entry/instrument/bluesky/metadata/mono_wavelength\",\n", " \"/entry/instrument/crystal:NXcrystal/wavelength\"\n", " ]\n", "\n", "A *NXdetector* group is required with fields `polar_angle` and `data`. These two\n", "fields correspond to `tth` and `sensor`. We use a class path for *NXdetector* in\n", "case the group does not already exist. These templates provide the links:\n", "\n", " [\n", " \"/entry/instrument/bluesky/streams/primary/tth/value\",\n", " \"/entry/instrument/detector:NXdetector/polar_angle\"\n", " ],\n", " [\n", " \"/entry/instrument/bluesky/streams/primary/sensor/value\",\n", " \"/entry/instrument/detector:NXdetector/data\"\n", " ],\n", "\n", "A sample name is required in a *NXsample* group. We'll give the sample name in\n", "the metadata, then link it with a template:\n", "\n", " [\n", " \"/entry/instrument/bluesky/metadata/sample_name\",\n", " \"/entry/instrument/sample:NXsample/name\"\n", " ]\n", "\n", "The *NXmonopd* definition is unclear whether or not a `rotation_angle` field is\n", "required. The text says it is optional but the presence of `\"(required)\"` means\n", "it must be provided. We'll set it to a constant of zero:\n", "\n", " [\"/entry/sample:NXsample/rotation_angle=\", 0],\n", "\n", "A *NXmonitor* group is required with fields `mode`, `preset`, and `integral`.\n", "This simulation uses a constant monitor count (`I0`), not a counting time. The\n", "`preset` field is the number of counts required for `I0` at each collection.\n", "These are the templates for the *NXmonitor* group:\n", "\n", " [\"/entry/monitor:NXmonitor/mode=\", \"monitor\"],\n", " [\"/entry/monitor:NXmonitor/preset=\", I0.get()],\n", " [\n", " \"/entry/instrument/bluesky/streams/primary/I0/value\",\n", " \"/entry/monitor:NXmonitor/integral\"\n", " ],\n", "\n", "The NeXus NXmonitor group acts like a *NXdata* group. We add a\n", "`@signal=\"integral\"` attribute that names `integral` as the default field in\n", "that group to be plotted. This is not required but is of great assistance when\n", "using visualization software such as [NeXPy](https://nexpy.github.io/nexpy/).\n", "\n", " [\"/entry/monitor:NXmonitor/@signal\", \"integral\"],\n", "\n", "The *NXmonopd* definition specifies a `DATA:NXdata` group. The `NXWriter()`\n", "creates a `data:NXdata` group and links all the detector and motor fields into\n", "this group. Since *NXmonopd* requres some different names, we choose to create\n", "an additional *NXdata* group. In a NeXus definition, a field name that is given\n", "in all upper case, such as `DATA` means that the name can be chosen by us.\n", "We'll use `monopd` as this group's name. The `@signal` attribute names the\n", "ordinate ($y$) axis to be plotted, the `@axes` attribute names any abcissae\n", "($x$). In this case, we only use $2\\theta$ (mapped to `polar_angle`) as the $x$\n", "axis, as customary for powder diffraction data.\n", "\n", " [\"/entry/instrument/bluesky/streams/primary/tth/value\", \"/entry/monopd:NXdata/polar_angle\"],\n", " [\"/entry/instrument/bluesky/streams/primary/sensor/value\", \"/entry/monopd:NXdata/data\"],\n", " [\"/entry/monopd/@signal\", \"data\"],\n", " [\"/entry/monopd/@axes\", [\"polar_angle\", ]],\n", "\n", "Finally, we change the default data group to point to our new `monopd` group:\n", "\n", " [\"/entry/@default\", \"monopd\"]," ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "templates = [\n", " [\"/entry/definition=\", \"NXmonopd\"], # satisfy the NXmonopd definnition\n", " # /entry/title already defined\n", " # /entry/start_time already defined\n", " # /entry/instrument/source/type already defined\n", " # /entry/instrument/source/name already defined\n", " # /entry/instrument/source/probe already defined\n", " [\"/entry/instrument/bluesky/metadata/mono_wavelength\", \"/entry/instrument/crystal:NXcrystal/wavelength\"],\n", " [\"/entry/instrument/bluesky/streams/primary/tth/value\", \"/entry/instrument/detector:NXdetector/polar_angle\"],\n", " [\"/entry/instrument/bluesky/streams/primary/sensor/value\", \"/entry/instrument/detector:NXdetector/data\"],\n", " [\"/entry/instrument/bluesky/metadata/sample_name\", \"/entry/sample:NXsample/name\"],\n", " [\"/entry/sample:NXsample/rotation_angle=\", 0], # sample has not been rotated\n", " [\"/entry/monitor:NXmonitor/mode=\", \"monitor\"], # in this simulation\n", " [\"/entry/monitor:NXmonitor/preset=\", I0.get()], # constant\n", " [\"/entry/instrument/bluesky/streams/primary/I0/value\", \"/entry/monitor:NXmonitor/integral\"],\n", " [\"/entry/instrument/bluesky/streams/primary/tth/value\", \"/entry/monopd:NXdata/polar_angle\"],\n", " [\"/entry/instrument/bluesky/streams/primary/sensor/value\", \"/entry/monopd:NXdata/data\"],\n", " [\"/entry/monopd/@signal\", \"data\"],\n", " [\"/entry/monopd/@axes\", [\"polar_angle\", ]],\n", " [\"/entry/@default\", \"monopd\"], # change the default plot group\n", " [\"/entry/monitor:NXmonitor/@signal\", \"integral\"], # in NXmonitor, same as for NXdata groups\n", "]" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "md = {\n", " \"title\": \"Demonstrate NeXus/HDF5 template support\", \n", " nxwriter.template_key: json.dumps(templates),\n", " \"mono_wavelength\": 1.0, # simulation\n", " \"sample_name\": \"simulation\",\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Run a $2\\theta:\\theta$ scan\n", "\n", "1. Make a bluesky plan\n", "2. Run the plan with the `RE`, stepping `tth` across the range where the\n", " Lorentzian peak is expected.\n", " 1. Print a table of the data as it is measured.\n", " 2. Plot the `sensor` and `I0` signals, separately.\n", "3. Verify the NeXus/HDF5 file has been saved." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n", "Transient Scan ID: 1 Time: 2023-12-02 13:15:51\n", "Persistent Unique Scan ID: '90acae1f-2475-406a-b86f-05b7ca2bb7d2'\n", "New stream: 'primary'\n", "+-----------+------------+------------+------------+------------+------------+\n", "| seq_num | time | tth | th | sensor | I0 |\n", "+-----------+------------+------------+------------+------------+------------+\n", "| 1 | 13:15:51.7 | 2.0000 | 1.0000 | 0.00000 | 100000 |\n", "| 2 | 13:15:52.8 | 2.8000 | 1.4000 | 182.83233 | 100000 |\n", "| 3 | 13:15:53.9 | 3.6000 | 1.8000 | 390.07416 | 100000 |\n", "| 4 | 13:15:55.0 | 4.4000 | 2.2000 | 1233.82536 | 100000 |\n", "| 5 | 13:15:56.1 | 5.2000 | 2.6000 | 8820.36874 | 100000 |\n", "| 6 | 13:15:57.3 | 6.0000 | 3.0000 | 1987.91262 | 100000 |\n", "| 7 | 13:15:58.5 | 6.8000 | 3.4000 | 503.62617 | 100000 |\n", "| 8 | 13:15:59.8 | 7.6000 | 3.8000 | 222.62671 | 100000 |\n", "| 9 | 13:16:00.9 | 8.4000 | 4.2000 | 122.16422 | 100000 |\n", "| 10 | 13:16:02.1 | 9.2000 | 4.6000 | 77.89379 | 100000 |\n", "| 11 | 13:16:03.3 | 10.0000 | 5.0000 | 53.29990 | 100000 |\n", "+-----------+------------+------------+------------+------------+------------+\n", "generator x2x_scan ['90acae1f'] (scan num: 1)\n", "\n", "\n", "\n", "h5_file.exists()=True h5_file=PosixPath('/tmp/nxwriter.h5')\n" ] }, { "data": { "text/plain": [ "('90acae1f-2475-406a-b86f-05b7ca2bb7d2',)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAeUAAAPYCAYAAADkS+E4AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/SrBM8AAAACXBIWXMAAA9hAAAPYQGoP6dpAAB2QUlEQVR4nO3de3xU1b3///fkNrmQTAiQTIab2FIEQVRsuYiCVQKWi9b+jq3QVKtVWwWK4KUceyraU7DWoq05ova0tdVWPN8qaq2NoLUgJVwKpIKoVEWuuSAkMyGQ+/r9EWaTIREIJNlrktfz8chDs/eaPWvPQ+edz15rr+0xxhgBAADXxbjdAQAA0IhQBgDAEoQyAACWIJQBALAEoQwAgCUIZQAALEEoAwBgCUK5gxljFAqFxO3hANA1tOZ7P64D+oMmQqGQ0tPTtXv3bqWlpbndHQBAOwuFQurbt6/Ky8vl8/lO2JZQ7mAVFRWSpL59+7rcEwBAR6qoqCCUbZOamipJVMoA0EWEK+Xw9/+JEModzOPxSJLS0tIIZQDoQsLf/yfCRC8AACxBKAMAYAkuXwMA2l19fb1qa2vd7ka7iI+PV2xsbJsci1AGALQbY4yKi4tVXl7udlfaVXp6uvx+/ymNG58IoQwAaDfhQM7MzFRycvIZh5ZtjDE6fPiwSktLJUnZ2dlndDxCGQDQLurr651A7tGjh9vdaTdJSUmSpNLSUmVmZp7RpWwmegEA2kV4DDk5OdnlnrS/8Dme6bg5oQwAaFed7ZJ1S9rqHAllAAAsQSgDAGAJQhkAAEsQygAAHGfVqlWaOnWqAoGAPB6PXnrppQ55X0IZAIDjVFZWavjw4crLy+vQ9+U+ZQBAhzHG6EhtvSvvnRQfe8qzpK+88kpdeeWV7dyj5ghlAECHOVJbryE/et2V9972wEQlJ9gde1y+BgDAEnb/yQAA6FSS4mO17YGJrr237QhlAECH8Xg81l9CdhOXrwEAsAR/rgAAcJxDhw7pww8/dH7fsWOHCgsLlZGRoX79+rXb+xLKAAAc55///Kcuu+wy5/e5c+dKkq6//no9/fTT7fa+hDIAAMcZP368jDEd/r6MKQMAYAlCGQAASxDKAABYglAGAMAShDIAoF25MWGqo7XVORLKAIB2ER8fL0k6fPiwyz1pf+FzDJ/z6eKWKABAu4iNjVV6erpKS0slScnJyaf86MRoYYzR4cOHVVpaqvT0dMXGntn62oQyAKDd+P1+SXKCubNKT093zvVMEMoAgHbj8XiUnZ2tzMxM1dbWut2ddhEfH3/GFXIYoQwAaHexsbFtFlydGRO9gC7i3X1B7fi00u1uADgBQhnoAkJVtbrm8TX6jycKusTtKUC0IpSBLmD3wcOqrmvQp4eqdbCyxu3uAPgMhDLQBZSGqp1/LwpWudgTACdCKANdQGnFsSAmlAF7EcpAF1DSpFIuDh5xsScAToRQBrqAppXyPiplwFqEMtAFRFbKhDJgK0IZ6AJKQ03HlLl8DdiKUAa6gNIKZl8D0YBQBjq5hgaj/ceFMguIAHYilIFO7uDhGtU1GIWfmFdT16Cyw53zwQBAtCOUgU6u5Oh4co+UBPXsliBJ2lfOuDJgI0IZ6OTC48mZqYny+xIlMQMbsBWhDHRy4ZnXmWleZfuSJElFIUIZsBHPUwY6ufC611mpifLGN/4dXsTla8BKhDLQyZVUHKuUkxIaHzLP5WvAToQy0MmFK+XMtESlehv/l+deZcBOhDLQyZVUhC9fe5WWFC+JVb0AWxHKQCe335nolajuyeFQblxAxBO+eRmAFZh9DXRiDQ3GuSUqK82rrLTGW6Kq6xpUzgIigHUIZaATK2uymlfPbl4lxseqR8rRBUS4hA1Yh1AGOrHwIxt7pCQoPrbxf3cWEAHsRSgDnVjp0duheqUmOtucBUQIZcA6hDLQiTkLh6R5nW3ZRytlZmAD9iGUgU4sXClnph4LZb8TylTKgG0IZaATK3Eq5WOXrwPpjCkDtiKUgU6sxUo5jTFlwFaEMtCJlTRZYjOs6ZiyMcaVfgFoGaEMdGLOYxtbGFOuqm1Q8AgLiAA2IZSBTqqhwWj/oeZjyonxscoILyBSziVswCaEMtBJlR2uUW194+Xpnt28Efv8R0O6OMRtUYBNoj6U6+rq9MMf/lADBgxQUlKSzj77bD3wwANqaGhw2hhjtGDBAgUCASUlJWn8+PF69913I45TXV2tWbNmqWfPnkpJSdG0adO0Z8+eiDZlZWXKzc2Vz+eTz+dTbm6uysvLO+I0gVYLr3ndIyVBCXGR/6uHZ2Az2QuwS9SH8k9/+lM98cQTysvL03vvvaeHHnpIP/vZz/TYY485bR566CEtXrxYeXl52rBhg/x+vyZMmKCKigqnzZw5c7Rs2TItXbpUq1ev1qFDhzRlyhTV19c7baZPn67CwkLl5+crPz9fhYWFys3N7dDzBU5VSSi8mpe32T7nXmUuXwNWifpHNxYUFOiqq67S5MmTJUlnnXWWnnvuOf3zn/+U1FglP/roo7r33nt1zTXXSJJ+97vfKSsrS3/84x916623KhgM6te//rWeeeYZXXHFFZKkZ599Vn379tUbb7yhiRMn6r333lN+fr7Wrl2rkSNHSpJ+9atfafTo0frggw80aNAgF84e+GzHng6V2GwfS20Cdor6Snns2LF68803tX37dknSv/71L61evVpf+cpXJEk7duxQcXGxcnJynNd4vV6NGzdOa9askSRt3LhRtbW1EW0CgYCGDh3qtCkoKJDP53MCWZJGjRoln8/ntGlJdXW1QqFQxA/QEVqaeR0Wvi2KMWXALlFfKd9zzz0KBoM655xzFBsbq/r6ev3kJz/RddddJ0kqLi6WJGVlZUW8LisrSzt37nTaJCQkqHv37s3ahF9fXFyszMzMZu+fmZnptGnJokWLdP/995/+CQKn6USVMpevATtFfaX8/PPP69lnn9Uf//hHbdq0Sb/73e/08MMP63e/+11EO4/HE/G7MabZtuMd36al9ic7zvz58xUMBp2f3bt3n8ppAWcsPKbc9GEUYYEml69ZQASwR9RXynfddZd+8IMf6Bvf+IYkadiwYdq5c6cWLVqk66+/Xn6/X1JjpZudne28rrS01Kme/X6/ampqVFZWFlEtl5aWasyYMU6bkpKSZu+/f//+ZlV4U16vV15v8y9FoL2FK+Wmj20MC1fKR2rrFTxSq/TkhA7tG4CWRX2lfPjwYcXERJ5GbGysc0vUgAED5Pf7tWLFCmd/TU2NVq5c6QTuiBEjFB8fH9GmqKhIW7duddqMHj1awWBQ69evd9qsW7dOwWDQaQPYpKXHNoYlxseqe3K8JCZ7ATaJ+kp56tSp+slPfqJ+/frp3HPP1ebNm7V48WLdeOONkhovOc+ZM0cLFy7UwIEDNXDgQC1cuFDJycmaPn26JMnn8+mmm27SvHnz1KNHD2VkZOjOO+/UsGHDnNnYgwcP1qRJk3TzzTfrySeflCTdcsstmjJlCjOvYR1jzLGHUbQwpiw1zsAuO1yr4mCVBmendWT3AHyGqA/lxx57TP/1X/+l2267TaWlpQoEArr11lv1ox/9yGlz991368iRI7rttttUVlamkSNHavny5UpNTXXaPPLII4qLi9O1116rI0eO6PLLL9fTTz+t2NhYp80f/vAHzZ4925mlPW3aNOXl5XXcyQKnqOxwrbOaV69uLQ+fZPsSta0opH1BZmADtvAYZnl0qFAoJJ/Pp2AwqLQ0qhO0j/eLQ5r06NvKSEnQpv+a0GKbe5dt0R/W7dKsL39e83K42gO0l9Z870f9mDKA5pxHNrZwj3JYIJ0FRADbEMpAJ+QsHPIZ48nSsYdSFHH5GrAGoQx0Qs7CISeolMOrelEpA/YglIFO6FilfIJQPnr5upgFRABrEMpAJ1QS+uwlNsPCl68P19QrdKSuQ/oF4MQIZaATKqn47IdRhCUlxCo9vIAID6YArEAoA51QeDWvE030kniEI2AbQhnoZIwx2l9x8luipCaTvXhaFGAFQhnoZMoP16qmvnHt914nCeXwgymKuS0KsAKhDHQy4fHk7snx8sbFnrBtgNuiAKsQykAnU3oKM6/D/IwpA1YhlIFOpuToPconu3QtNV1AhMvXgA0IZaCTcVbzOoVKuemqXiwgAriPUAY6GWc1r1OqlBsvXx+uqVeoigVEALcRykAn05pKuekCIsWMKwOuI5SBTiY8ppx1gnWvm+JpUYA9CGWgkwlXyr1ST14pSzwtCrAJoQx0IsaYJrdEnVqlHH5aFKEMuI9QBjqR4JFTX80rLDuNVb0AWxDKQCcSfmTjqazmFebn8jVgDUIZ6ERKnUc2ntp4siQFuHwNWINQBjqREueRjad26Vpq+lAKQhlwG6EMdCKnUymHZ18fqq5TqKq2XfoF4NQQykAn0tqZ15KUnBAnXxILiAA2IJSBTuRYpXzqoSxxrzJgC0IZ6ERKWvHYxqacGdjl3BYFuIlQBjqR8BKbrZnoJR17MAWVMuAuQhnoJIwxzhKbrZnoJR27fM2YMuAuQhnoJIJHalVT17rVvMLCl6/3saoX4CpCGegkwlVyenK8EuNPbTWvsMDRy9dUyoC7CGWgk3DGk1tZJUssIALYglAGOonS05x5LR0bU66orlMFC4gAriGUgU6i5Og9yq0dT5akFG+c0hLjJFEtA24ilIFO4kwqZYnbogAbEMpAJ3G6q3mFHXuEIzOwAbcQykAncaaVciCdpTYBtxHKQCcRHlNuzcMomvKncVsU4DZCGegEjDFOpdza1bzCsp0FRAhlwC2EMtAJhI7Uqfo0V/MKy04P36vMmDLgFkIZ6ATCk7x8Sa1fzSvMeXxjOZUy4BZCGegEjj2y8fSqZEnyH70ligVEAPcQykAncOx2qNMbT5akbt44pR5dQCS8ZCeAjkUoA51AuFJu7XOUj+dM9uISNuAKQhnoBNqiUpaOrerFbVGAOwhloBMobYMxZanJZC9CGXAFoQx0Asce23hmlTJLbQLuIpSBTqC0om0q5QAPpQBcRSgDUc4Y0+aVMmPKgDsIZSDKhaqOrebVZrOvuXwNuIJQBqJc6dEqOS0x7rRX8wrLTj+6gEhVnQ5V151x3wC0DqEMRLlj48lndulaOrqAiLdxAREuYQMdj1AGopwznnyGl67DmIENuIdQBqKcUymf4SSvsPAlbGZgAx2PUAaiXLhS7tVGlXJ2GjOwAbcQykCUa+tKmcvXgHsIZSDKlbbxmHIgnaU2AbcQykCUa8vZ19Kx5ypz+RroeIQyEMWarubVZhO9nMc3cvka6GiEMhDFKqrrVFXbNqt5hYVDOVRVp0oWEAE6FKEMRLG2XM0rLDUxXt3CC4iEuIQNdCRCGYhi4ecoZ7bReHKYMwO7nFAGOhKhDESxkoqj48ltdOk6LJvbogBXEMpAFHMq5Taa5BWWzSMcAVcQykAUK3EuX7dtpRy+LWofoQx0KEIZiGKlRy9ft3WlHHAqZS5fAx2JUAaiWPjydVuPKR9bapNKGehIhDIQxUraq1LmSVGAKwhlIEoZY9q9Ug4eqdXhGhYQAToKoQxEqYrqOh2prZfU9pVyqjdOKQmNi5EwAxvoOIQyEKXCVXJqYpySEtpmNa8wj8ejbC5hAx2OUAailPPIxtS2vXQdls1kL6DDEcpAlGrrRzYez5/GbVFARyOUgShV0t6VcjoLiAAdjVAGolR7V8ostQl0vE4Rynv37tU3v/lN9ejRQ8nJyTr//PO1ceNGZ78xRgsWLFAgEFBSUpLGjx+vd999N+IY1dXVmjVrlnr27KmUlBRNmzZNe/bsiWhTVlam3Nxc+Xw++Xw+5ebmqry8vCNOEWgmXCn3aqdKmQVEgI4X9aFcVlamiy++WPHx8frrX/+qbdu26ec//7nS09OdNg899JAWL16svLw8bdiwQX6/XxMmTFBFRYXTZs6cOVq2bJmWLl2q1atX69ChQ5oyZYrq6+udNtOnT1dhYaHy8/OVn5+vwsJC5ebmduTpAo72rpQDvvDsa8aUgQ5jotw999xjxo4d+5n7GxoajN/vNw8++KCzraqqyvh8PvPEE08YY4wpLy838fHxZunSpU6bvXv3mpiYGJOfn2+MMWbbtm1Gklm7dq3TpqCgwEgy77///in3NxgMGkkmGAye8muAlox76G+m/z2vmrUffdouxy8/XGP63/Oq6X/Pq+ZwdV27vAfQFbTmez/qK+VXXnlFF110kf7jP/5DmZmZuuCCC/SrX/3K2b9jxw4VFxcrJyfH2eb1ejVu3DitWbNGkrRx40bV1tZGtAkEAho6dKjTpqCgQD6fTyNHjnTajBo1Sj6fz2nTkurqaoVCoYgf4EwZY9q9Uk5LjFNyeAGREJewgY4Q9aH88ccfa8mSJRo4cKBef/11ffe739Xs2bP1+9//XpJUXFwsScrKyop4XVZWlrOvuLhYCQkJ6t69+wnbZGZmNnv/zMxMp01LFi1a5IxB+3w+9e3b9/RPFjjqUHWdDtccXc2rjZfYDPN4PMfuVS7nEjbQEaI+lBsaGnThhRdq4cKFuuCCC3Trrbfq5ptv1pIlSyLaeTyeiN+NMc22He/4Ni21P9lx5s+fr2Aw6Pzs3r37VE4LOKFwlZzqjVNyQly7vU+2j1W9gI4U9aGcnZ2tIUOGRGwbPHiwdu3aJUny+/2S1KyaLS0tdapnv9+vmpoalZWVnbBNSUlJs/ffv39/syq8Ka/Xq7S0tIgf4Ew59yi3U5UcFp6BzeVroGNEfShffPHF+uCDDyK2bd++Xf3795ckDRgwQH6/XytWrHD219TUaOXKlRozZowkacSIEYqPj49oU1RUpK1btzptRo8erWAwqPXr1ztt1q1bp2Aw6LQBOsr+o5VyWz+I4niBo6G8j8vXQIdov+teHeSOO+7QmDFjtHDhQl177bVav369nnrqKT311FOSGi85z5kzRwsXLtTAgQM1cOBALVy4UMnJyZo+fbokyefz6aabbtK8efPUo0cPZWRk6M4779SwYcN0xRVXSGqsvidNmqSbb75ZTz75pCTplltu0ZQpUzRo0CB3Th5dVrhSbutHNh7Pf/TyNQuIAB0j6kP5i1/8opYtW6b58+frgQce0IABA/Too49qxowZTpu7775bR44c0W233aaysjKNHDlSy5cvV2pqqtPmkUceUVxcnK699lodOXJEl19+uZ5++mnFxh57+s4f/vAHzZ4925mlPW3aNOXl5XXcyQJHhZ8QldlOM6/DwhO9WGoT6BgeY4xxuxNdSSgUks/nUzAYZHwZp23Wc5v153/t0w8nD9Z3Ljm73d7n/eKQJj36tronx2vzj3JO/gIAzbTmez/qx5SBrujYRK92rpTTGi9flx2uVVVt/UlaAzhThDIQhcITvbLaad3rsLSkOCXFNw7hcFsU0P4IZSAKdVSl7PF4lJ0efjAFM7CB9kYoA1EmYjWvdq6UJR7hCHQkQhmIMuEquZs3Tine9r+Bwp/Gql5ARyGUgShz7Hao9q+SJSnA5WugwxDKQJQprTg6ntwBl66lJkttUikD7Y5QBqJMuFJur0c2Hi9wdFWvfeWEMtDeCGUgyjgzrzu6UuahFEC7I5SBKBN+bGNHVcrh2dcHK2tYQARoZ4QyEGXClXKvDqqUfUnxzgIijCsD7YtQBqLM/g6ulD0ej1Mtc1sU0L4IZSDKdPSYstR0XJnbooD2RCgDUeRQdZ0qw6t5dVClLEnZzMAGOgShDESR0iareXXrgNW8wlhqE+gYhDIQRcIzrzvy0rV07PI1Y8pA+yKUgShy7OlQHRvKLLUJdAxCGYgi+51KuePGk6VjD6Xg8jXQvghlIIqEK+WsDq6Uw2PKB1hABGhXhDIQRUpdqpTTk+OVGN/4dVHCcptAuyGUgSji1phy4wIiPFcZaG+EMhBFnGcpd3ClLEn+NG6LAtoboQxEkWMPo+jYSlmSso/OwN7HDGyg3RDKQJSorK7Toeo6SR27mlcYC4gA7Y9QBqJEuEpOSYjt0NW8wvyMKQPtjlAGosSxSV4dXyVLUsDHAiJAeyOUgSjh1hKbYX4uXwPtjlAGokSpy5Vy+JaoTw/VqLqOBUSA9kAoA1HCmXntUqXcPTle3rijC4gEq13pA9DZEcpAlHBr4ZCwxgVEGFcG2hOhDESJ8MIhWS5dvpaOXcIuZqlNoF0QykCUKKloDMJeLl2+lo7dq7yvnFAG2gOhDESJ/RZUysdmYHP5GmgPhDIQBQ7X1KkivJqXm5VyOguIAO2JUAaiQHg8Odml1bzCstPCE70IZaA9EMpAFAjPvM5KS5TH43GtH34foQy0J0IZiALhe5TdnOQlSYH08AIi1aqpa3C1L0BnRCgDUaBppeym7snxSggvIMJtUUCbI5SBKLDf5XWvwyIXECGUgbbmSijX1tbqsssu0/bt2914eyDqHKuU3Q1lSazqBbQjV0I5Pj5eW7dudXXCChBNjj0hyt3L19KxVb2olIG259rl629961v69a9/7dbbA1HF7XWvm+IRjkD7ce2Gx5qaGv3v//6vVqxYoYsuukgpKSkR+xcvXuxSzwD7hO9TtqFSDjhLbXL5GmhrroXy1q1bdeGFF0pSs7FlLmsDxzRdzcuGMWU/D6UA2o1rofzWW2+59dZAVAlXyUnx7q7mFcbsa6D9WHFL1J49e7R37163uwFYKTzJKyvNa8VVpHAos4AI0PZcC+WGhgY98MAD8vl86t+/v/r166f09HT9+Mc/VkMD/6MDYc4kLwvGkyUpIyVBCbExMoYFRIC25tq1sHvvvVe//vWv9eCDD+riiy+WMUb/+Mc/tGDBAlVVVeknP/mJW10DrOLcDmXBeLLUOOfD70vUroOHVRyqUt+MZLe7BHQaroXy7373O/3v//6vpk2b5mwbPny4evfurdtuu41QBo4qtaxSlhovYe86eJgZ2EAbc+3y9cGDB3XOOec0237OOefo4MGDLvQIsFPTMWVbZHOvMtAuXAvl4cOHKy8vr9n2vLw8DR8+3IUeAXayaeGQMD+regHtwrXL1w899JAmT56sN954Q6NHj5bH49GaNWu0e/duvfbaa251C7COUylbdPk6kM7610B7cK1SHjdunLZv366vfvWrKi8v18GDB3XNNdfogw8+0CWXXOJWtwDrWFkpp3H5GmgPrq5EEAgEmNAFnMCRmnpVVDWu5pXp8rOUm+KhFED7cK1Szs/P1+rVq53f/+d//kfnn3++pk+frrKyMre6BViltKIx9JLiY5VqwWpeYdlHL1/vZwERoE25Fsp33XWXQqGQJGnLli2aO3euvvKVr+jjjz/W3Llz3eoWYJWm9yjbsJpXWEbysQVEwn84ADhzrv3pvWPHDg0ZMkSS9MILL2jq1KlauHChNm3apK985StudQuwSng82aZJXpIUE9NkAZFglfp0ZwERoC24ViknJCTo8OHDkqQ33nhDOTk5kqSMjAyngga6uvDDKHpZNMkrLPxc5X2MKwNtxrVKeezYsZo7d64uvvhirV+/Xs8//7ykxsc49unTx61uAVYpqbCzUpaaLiDCbVFAW3GtUs7Ly1NcXJz+9Kc/acmSJerdu7ck6a9//asmTZrkVrcAq+wP2bXudVPMwAbanmuVcr9+/fTqq6822/7II4+40BvATk6lbGUoH11ApJxQBtqKq/dYNDQ06MMPP1RpaWmzxzVeeumlLvUKsEdJuFK28PJ1eEy5iMc3Am3GtVBeu3atpk+frp07d8oYE7HP4/Govr7epZ4B9gg/IcrGSjlw9PI1Y8pA23EtlL/73e/qoosu0l/+8hdlZ2dbdQ8mYIOq2nqFjq7m1cviSrm0olq19Q2Kj3VtigrQabgWyv/+97/1pz/9SZ///Ofd6gJgtfDtUInxMUpLtGc1r7AeKQmKj/Wott6otKJavdOT3O4SEPVc+9N25MiR+vDDD916e8B64UlemamJVl5JCi8gInEJG2grrv35PWvWLM2bN0/FxcUaNmyY4uPjI/afd955LvUMsEO4UrZxPDksOy1Juw8e0b7yKo3o73ZvgOjnWih/7WtfkyTdeOONzjaPxyNjDBO9ADV5ZKOF48lhxyplZmADbcHVta8BfLamD6OwVfhpUSwgArQN10K5f3+udQEnUhoFlXJ2WjiUGVMG2oKr9zA888wzuvjiixUIBLRz505J0qOPPqqXX37ZzW4BVghXyjaPKftZahNoU66F8pIlS5xnKJeXlztjyOnp6Xr00Ufd6hZgjWgYUw6kM6YMtCXXQvmxxx7Tr371K917772KjY11tl900UXasmWLW90CrBEdlXJ4AZEq1dU3nKQ1gJNxLZR37NihCy64oNl2r9erysrK0z7uokWL5PF4NGfOHGebMUYLFixQIBBQUlKSxo8fr3fffTfiddXV1Zo1a5Z69uyplJQUTZs2TXv27IloU1ZWptzcXPl8Pvl8PuXm5qq8vPy0+wp8lqraegWP1Eqyu1LumeJVfKxHDebYHxEATp9roTxgwAAVFhY22/7Xv/5VQ4YMOa1jbtiwQU899VSze5wfeughLV68WHl5edqwYYP8fr8mTJigiooKp82cOXO0bNkyLV26VKtXr9ahQ4c0ZcqUiFuzpk+frsLCQuXn5ys/P1+FhYXKzc09rb4CJ7L/aMB542KUlmTfal5hMTEeZaUxAxtoM8Ylv/nNb0zv3r3N0qVLTUpKinnuuefMf//3fzv/3loVFRVm4MCBZsWKFWbcuHHm+9//vjHGmIaGBuP3+82DDz7otK2qqjI+n8888cQTxhhjysvLTXx8vFm6dKnTZu/evSYmJsbk5+cbY4zZtm2bkWTWrl3rtCkoKDCSzPvvv3/K/QwGg0aSCQaDrT5HdB0bdhww/e951Vzy07+53ZWT+v+W/MP0v+dV8+d/7XW7K4CVWvO971ql/O1vf1v33Xef7r77bh0+fFjTp0/Xk08+qV/84hf6xje+0erj3X777Zo8ebKuuOKKiO07duxQcXGxcnJynG1er1fjxo3TmjVrJEkbN25UbW1tRJtAIKChQ4c6bQoKCuTz+TRy5EinzahRo+Tz+Zw2LamurlYoFIr4AU7GuUc51d7x5DC/87QoKmXgTLl2XezIkSOaMWOGbr75Zn366af6+OOP9Y9//EN9+vRp9bGWLl2qTZs2acOGDc32FRcXS5KysrIitmdlZTm3YRUXFyshIUHdu3dv1ib8+uLiYmVmZjY7fmZmptOmJYsWLdL999/fuhNCl1fiPLLR3vHksICPy9dAW3GtUr7qqqv0+9//XpIUFxenadOmafHixbr66qu1ZMmSUz7O7t279f3vf1/PPvusEhM/+wvs+AX9zdHlPE/k+DYttT/ZcebPn69gMOj87N69+4TvCUjHKuVeUVEps4AI0FZcC+VNmzbpkksukST96U9/cirX3//+9/rlL395ysfZuHGjSktLNWLECMXFxSkuLk4rV67UL3/5S8XFxTkV8vHVbGlpqbPP7/erpqZGZWVlJ2xTUlLS7P3379/frApvyuv1Ki0tLeIHOJloqpSzqZSBNuNaKB8+fFipqamSpOXLl+uaa65RTEyMRo0a5VxWPhWXX365tmzZosLCQufnoosu0owZM1RYWKizzz5bfr9fK1ascF5TU1OjlStXasyYMZKkESNGKD4+PqJNUVGRtm7d6rQZPXq0gsGg1q9f77RZt26dgsGg0wZoK/ujaEw5mzFloM24Nqb8+c9/Xi+99JK++tWv6vXXX9cdd9whqbE6bU01mZqaqqFDh0ZsS0lJUY8ePZztc+bM0cKFCzVw4EANHDhQCxcuVHJysqZPny5J8vl8uummmzRv3jz16NFDGRkZuvPOOzVs2DBn4tjgwYM1adIk3XzzzXryySclSbfccoumTJmiQYMGnfHnATQVjZVySahxAZG4WFdX7wWimmuh/KMf/UjTp0/XHXfcocsvv1yjR4+W1Fg1t7SoyJm4++67deTIEd12220qKyvTyJEjtXz5cqdSl6RHHnlEcXFxuvbaa3XkyBFdfvnlevrppyNWG/vDH/6g2bNnO7O0p02bpry8vDbtKyBJJSH7nxAV1rObV3ExHtU1GO0/VO1UzgBaz2OMMW69eXFxsYqKijR8+HDFxDT+db1+/XqlpaXpnHPOcatb7SoUCsnn8ykYDDK+jBZV1dbrnP/KlyT960c58iXHu9yjk7v4wb9pb/kRvfC9MRrRv/vJXwB0Ia353nd1qSC/3y+/3x+x7Utf+pJLvQHsEB5PTrB8Na+msn2J2lt+hHFl4Awx+ANYprQiPJ7sPelte7bITg8/wpHbooAzQSgDlnHGky1+EMXxuC0KaBuEMmCZ0tCxSjla+NN4rjLQFghlwDIlFdFXKQfSWdULaAuEMmCZ0ii6HSos/FAKLl8DZ4ZQBiwTnugVTZVyeEy5tKJadfUNLvcGiF6EMmCZcKUcTWPK4QVE6huMPj1U43Z3gKhFKAOWKYnCSjk2xuMsCbqPcWXgtBHKgEWq6+pVfrhWUnRVytKxRzgyAxs4fYQyYJHwpeuEuBj5kuxfXrMp7lUGzhyhDFiktMkjG6NlNa8wJ5TLuXwNnC5CGbBIaRQ9svF4zm1RISpl4HQRyoBFmlbK0SbAmDJwxghlwCIlUV0pc/kaOFOEMmCRcKXcKwor5eyjl69LKqpV3+DaY9qBqEYoAxaJ5kq5V6pXsc4CItVudweISoQyYBFn3esorJRjYzzKOtrvfVzCBk4LoQxYJLzudTRWyhILiABnilAGLFFdV6+yo6t5RWOlLEnZ6TwtCjgThDJgif1HJ3klxMYoPTm6VvMKy07jucrAmSCUAUuUhI7NvI621bzCqJSBM0MoA5bY74wnR+ela+nYUpuMKQOnh1AGLFHizLyOzkleUpMFRAhl4LQQyoAlSjtBpRwILyASqmIBEeA0EMqAJZxKOUpvh5KOLSBS12B0gAVEgFYjlAFLRPPDKMJiYzxO//dxCRtoNUIZsET4sY3RXClLTSd7cVsU0FqEMmCJcKUczWPK0rEHUzDZC2g9QhmwQE1dgw5W1kiK7tnXEjOwgTNBKAMW2H90UlR8rEfdo3Q1r7BsQhk4bYQyYIHwIxszUxOjdjWvsPDla8aUgdYjlAELOI9sjPLxZOnY5et95VTKQGsRyoAFnIVDonw8WZIC6Y3nUBKqUgMLiACtQigDFuhMlXKvbl7FeKS6BqNPK1lABGgNQhmwQHhMOSvK71GWpLjYGGcGeRGXsIFWIZQBC4TvUe4Vxat5NZWdzgxs4HQQyoAFOlOlLLGqF3C6CGXAAp1h3eum/Gms6gWcDkIZcFnT1bw6S6Uc4PI1cFoIZcBlnWk1rzC/c/maUAZag1AGXFbaiVbzCguPKe9jTBloFUIZcFlJqHPNvJaOLbXJAiJA6xDKgMv2h1fz6gQLh4T1Sm1cQKS2ngVEgNYglAGXhSvlaH9kY1PxsTFO5c+4MnDqCGXAZaWdsFKWjl3CZgY2cOoIZcBlnbFSlpo8V7mcyV7AqSKUAZc5C4d01ko5RKUMnCpCGXBZ01uiOpNs7lUGWo1QBlxUW9+gA85qXp2rUvb7eFIU0FqEMuCi/UcvXcfFeNQ9OcHl3rQtZ6nNEGPKwKkilAEXNX0QRUxM51jNK8wfXkAkWM0CIsApIpQBF4Uf2dirkzyIoqnMVK88HqmmySV6ACdGKAMuClfKWZ1oic2w+NgY51GUTPYCTg2hDLgoPPO6szyy8Xh+ZwERxpWBU0EoAy4qDR0bU+6MstN4rjLQGoQy4KKSis5dKWenE8pAaxDKgIucxzZ2snuUw44tIMLla+BUEMqAi5zHNnay1bzCwmPK+6iUgVNCKAMuqa1v0KeHGm8V6mzrXocFWGoTaBVCGXDJp4eOreaV0clW8wrzNwllY1hABDgZQhlwiTOe3AlX8wrLSktkARGgFQhlwCXO06E66cxrqXEBkV7dWEAEOFWEMuCSkorOfY9yWHgGNrdFASdHKAMu2e+s5tW5Q9l5hCO3RQEnRSgDLilxVvPqvJevJSnbWWqTShk4GUIZcElpRdeolLO5LQo4ZYQy4JKuUimHL1/vK+fyNXAyhDLgkvBjGzvrwiFhgfTGy9fFISpl4GQIZcAFdfUNOlDZRSrlJk+KYgER4MQIZcAFnx6qkTFSbIxHPVI652peYc4CInUNOsgCIsAJEcqAC0qOXsrt1a3zruYVlhAXo55HFxBhBjZwYoQy4ILweHJnn3kdxgxs4NREfSgvWrRIX/ziF5WamqrMzExdffXV+uCDDyLaGGO0YMECBQIBJSUlafz48Xr33Xcj2lRXV2vWrFnq2bOnUlJSNG3aNO3ZsyeiTVlZmXJzc+Xz+eTz+ZSbm6vy8vL2PkV0Qk6l3MnHk8OyWUAEOCVRH8orV67U7bffrrVr12rFihWqq6tTTk6OKisrnTYPPfSQFi9erLy8PG3YsEF+v18TJkxQRUWF02bOnDlatmyZli5dqtWrV+vQoUOaMmWK6uvrnTbTp09XYWGh8vPzlZ+fr8LCQuXm5nbo+aJz6HqVMguIAKfEdDKlpaVGklm5cqUxxpiGhgbj9/vNgw8+6LSpqqoyPp/PPPHEE8YYY8rLy018fLxZunSp02bv3r0mJibG5OfnG2OM2bZtm5Fk1q5d67QpKCgwksz7779/yv0LBoNGkgkGg2d0nohu9/zpX6b/Pa+aX7yx3e2udIglf//Q9L/nVXPH0s1udwXocK353o/6Svl4wWBQkpSRkSFJ2rFjh4qLi5WTk+O08Xq9GjdunNasWSNJ2rhxo2prayPaBAIBDR061GlTUFAgn8+nkSNHOm1GjRoln8/ntGlJdXW1QqFQxA9Q2kUeRhEWvny9j8vXwAl1qlA2xmju3LkaO3ashg4dKkkqLi6WJGVlZUW0zcrKcvYVFxcrISFB3bt3P2GbzMzMZu+ZmZnptGnJokWLnDFon8+nvn37nv4JotMocR5G0TXGlMMLiPy75JCqautP0hroujpVKM+cOVPvvPOOnnvuuWb7PJ7I206MMc22He/4Ni21P9lx5s+fr2Aw6Pzs3r37ZKeBLiC8xGavLlIpn9fHp2xfog5U1ui59bvc7g5grU4TyrNmzdIrr7yit956S3369HG2+/1+SWpWzZaWljrVs9/vV01NjcrKyk7YpqSkpNn77t+/v1kV3pTX61VaWlrED7q2pqt5dZVK2RsXq5lf/rwk6fG/f6QjNVTLQEuiPpSNMZo5c6ZefPFF/e1vf9OAAQMi9g8YMEB+v18rVqxwttXU1GjlypUaM2aMJGnEiBGKj4+PaFNUVKStW7c6bUaPHq1gMKj169c7bdatW6dgMOi0AU5FV1rNq6n/GNFXfbonaX9FtZ5du9Pt7gBWivpQvv322/Xss8/qj3/8o1JTU1VcXKzi4mIdOdI4ocTj8WjOnDlauHChli1bpq1bt+qGG25QcnKypk+fLkny+Xy66aabNG/ePL355pvavHmzvvnNb2rYsGG64oorJEmDBw/WpEmTdPPNN2vt2rVau3atbr75Zk2ZMkWDBg1y7fwRfcKPbOwKq3k1lRAXo9lfHihJemLlR6qsrnO5R4B9oj6UlyxZomAwqPHjxys7O9v5ef755502d999t+bMmaPbbrtNF110kfbu3avly5crNTXVafPII4/o6quv1rXXXquLL75YycnJ+vOf/6zY2FinzR/+8AcNGzZMOTk5ysnJ0XnnnadnnnmmQ88X0c95ZGMXuUe5qWsu7K3+PZJ1oLJGvy+gWgaO5zGGx7Z0pFAoJJ/Pp2AwyPhyF/WHdTt177KtumJwlv73+ovc7k6He3HTHs39v38pPTleb999mVIT493uEtCuWvO9H/WVMhBtunKlLElXnd9bZ/dKUfnhWj39j0/c7g5gFUIZ6GD7j44pZ3WRda+PFxvj0ZwrviBJ+tXbHyt4pNblHgH2IJSBDtbVK2VJmjIsW1/I6qZQVZ1+vXqH290BrEEoAx0sPPu6qzyMoiUxMR7dcbRa/s3qHSqrrHG5R4AdCGWggzmVche9fB028Vy/Bmen6VB1nX719sdudwewAqEMdKC6+gYdOMTla6mxWp47obFafnrNJ87nAnRlhDLQgQ5U1qjBSDEeqUdK1w5lSbpicKbO6+PT4Zp6PbmKahkglIEOVNrkQRSxXWg1r8/i8Xh0x9Fq+fcFnzjj7UBXRSgDHSj8yMauPp7c1Pgv9NIF/dJVVdugJX//yO3uAK4ilIEOVFoRfjoUl67DPB6P5k1oXD/+D+t2qSh4xOUeAe4hlIEO5FTKXeSRjafq4s/30JfOylBNXYMef4tqGV0XoQx0oHClnJlKpdyUx+PR3JzGseWlG3ZpT9lhl3sEuINQBjpQaSi8cAiV8vFGnd1DYz7XQ7X1Rv/z1odudwdwBaEMdKCSivBELyrlloTvW/5//9yjXQeoltH1EMpABwrfEkWl3LKLzsrQpV/opboGo1/+7d9udwfocIQy0EHqG4w+PcSY8smEq+UXN+3Rjk8rXe4N0LEIZaCDHDhUfWw1r26E8mc5v2+6Lj8nUw1G+sUb293uDtChCGWgg4QfRNGzG6t5nUx4la+X/7VPH5ZWuNwboOMQykAHOfbIRsaTT2Zob58mnpslY6RH3mBsGV0HoQx0kGOPbOTS9amYc/R5y395p0jvF4dc7g3QMQhloIOEK2VW8zo1g7PTNPm8bEnSIysYW0bXQCgDHYRKufXmXD5QHo/0+rsl2ro36HZ3gHZHKAMdZD9jyq02MCtVVw0PSKJaRtdAKAMdhEr59My+fKBiPNKb75eqcHe5290B2hWhDHQQZl+fnrN7ddM1F/aRJC2mWkYnRygDHeDZtTtVEqpWjEfq3T3J7e5EndlfHqi4GI9Wbd+vf35y0O3uAO2GUAba2evvFutHL2+VJM368kBlpCS43KPo069Hsv7jIqpldH6EMtCONnxyULOf26wGI33ji30154qBbncpat1+2ecVH+vRmo8OqOCjA253B2gXhDLQTv5dUqGbnt6g6roGXTE4U/999VB5PCyvebr6dE/WN77YT5L0yBvbZYxxuUdA2yOUgXZQFDyi63+zXqGqOl3QL12PXXeh4mL53+1M3X7Z55UQF6P1Ow7qHx9SLaPz4VsCaGPBI7W64TcbtC9YpbN7peg3139RSQmxbnerU/D7EjVjZGO1vHjFB1TL6HQIZaANVdXW6+bf/1MflFQoM9Wr3337S+rOxK429b3xn1NifIw27SrX37fvd7s7QJsilIE2Ut9gdMfzhVq/46BSvXF6+ttfUt+MZLe71elkpibqW6PPktS4yhfVMjoTQhloA8YY3f/nd/XXrcVKiI3Rk98aoSGBNLe71WndeunZSk6I1Tt7gnrjvVK3uwO0GUIZaAOP//0j/b5gpzweafHXh2vM53q63aVOrUc3r64fc5akxvuWGxqoltE5EMrAGfp//9ytn73+gSTpvyYP0ZTzAi73qGu45ZKz1c0bp/eKQnr93WK3uwO0CUIZOANvfVCqH7y4RZJ067izdePYAS73qOvonpKgGy8+S1LjfctUy+gMCGXgNBXuLtdtz25SfYPRVy/orXsmnuN2l7qcmy45W6mJcdpeckivbilyuzvAGSOUgdOw49NK3fj0Bh2prdclA3vqp187TzExrNbV0XxJ8br5krMlSY++sV31VMuIcoQy0EqlFVX61m/W6WBljYb19mnJN0coIY7/ldzy7YvPUnpyvD7eX6mXC/e63R3gjPBNArTCoeo63fj0Bu0+eET9MpL1mxu+qG7eOLe71aWlJsbrlksbq+VfvPlv1dU3uNwj4PQRysApqqlr0Pee3aite0PqkZKg39/4JfVK9brdLUi6fvRZ6pGSoJ0HDuvFTVTLiF6EMnAKGhqM7v7Tv/T2vz9VckKsfnPDF3VWzxS3u4WjUrxx+u64z0mSfvm3f6umjmoZ0YlQBk7Bg/nv66XCfYqL8ejxGRdqeN90t7uE43xzVH/1SvVqT9kR/WnjHre7A5wWQhk4if99+2M9tepjSdJPv3aexg/KdLlHaElSQqxuG99YLef97d+qrqt3uUdA6xHKwAm88q99+u+/vCdJunvSIH1tRB+Xe4QTue5L/eRPS9S+YJWe37Db7e4ArUYoA59hzYefat7/FUqSbhhzlr53dMwS9kqMj9XtX/68JCnvbx+qqpZqGdGFUAZa8O6+oG55ZqNq642+Msyv/5oyRB4Pi4NEg69f1Fe905NUWlGtP6zb5XZ3gFYhlIHj7D54WDf8doMOVddp5IAMLb72fMWyWlfUSIiL0ayj1fKSv3+owzV1LvcIOHWEMtDEwcoaXf+b9dpfUa1z/Kl66lsXKTE+1u1uoZW+NqKP+mUk69NDNXqmYKfb3QFOGaEMHHW4pnG1ro8/rVTAl6inv/0l+ZLi3e4WTkN8bIxmXz5QkvTEyo90qJpqGdGBUAYk1dU3aNYfN6twd7l8SfH6/U1fkt+X6Ha3cAauPj+gs3umqOxwrX635hO3uwOcEkIZXZ4xRvcu26o33y+VNy5Gv77+In0+M9XtbuEMxcXG6PtXNFbLT636WKGqWpd7BJwcoYwu75EV2/X8P3crxiM9dt0FuuisDLe7hDYy5byABmZ2U/BIrX6zeofb3QFOilBGl/bs2p365d8+lCT9+OqhyjnX73KP0JZiYzyac8UXJEm/fnuHyg/XuNwj4MQIZXRZr79brB+9vFWSNPvygZoxsr/LPUJ7uHKoX+f4U1VRXac7ni/U+h0HZYxxu1tAiwhldEkbPjmo2c9tVoORvvHFvrrj6NgjOp+YGI/umXSOPB7prQ/269onCzTuZ3/Xo29s1+6Dh93uHhDBY/iTsUOFQiH5fD4Fg0GlpaW53Z0u6d8lFfrakjUKVdXpisGZeuKbIxQXy9+nnd2mXWVaun6XXttSHHGL1JcGZOj/u7CPvnJetrp541zsITqr1nzvE8odjFB2V1HwiL72+BrtC1bpgn7p+uN3RikpgcVBupIjNfV6/d1ivbBpj1Z/+KnC34CJ8TGadK5fXxvRR2M+15NV3NBmCGWLEcruCR6p1bVPFOiDkgqd3StFL3x3jLqnJLjdLbioKHhEyzbv1Qsb9+ij/ZXO9mxfor56QW99bUQffa5XNxd7iM6AULYYodyx9ldU6x8ffqpV/96vVds/1aeHqpWZ6tUL3xujvhnJbncPljDGqHB3uV7YtEd//leRgkeO3dN8ft90fW1EH007LyBfMiu8ofUIZYsRyu2ruq5e//ykTKv+vV9vb/9U24pCEft7dkvQ728cqSEBPnu0rLquXm++V6oXNu7R37fvV31D41dkQmyMrhiSqa9d2EfjvtCLeQg4ZYSyxQjltmWM0Yelh7Tq35/q7X/v19qPD6iqtiGizZDsNF36hV66dGBPXdi/Ow+YwCnbX1Gtlwv36oVNe/Vekz/wenZL0FXn99bXLuzDH3g4KULZYoTymTtYWaPVH36qt7fv19v//lTFoaqI/b1SvbpkYE9dOrCXLv58T/VK9brUU3Qm2/aF9MKmPXq5cK8+PXRsEZLB2Wn6/0b00VXnB9SzG/+toTlC2WKEcuvV1DVo064yvf3vxhDesjeopv/VeuNi9KUBGbp0YC9d8oWeGpSVKo+HmbNoH7X1DVq1fb/+tHGP3nyvVDX1jVdm4mI8Gj+ol752YR99eXCmvHFckUEjQtlihPLJGWP08aeVTiVc8PEBHa6pj2hzjj9VlwzsqUsG9tKXBmRwSRquKD9coz//a5/+tGmv/rW73NmenhyvqecF9LURfTS8j48/Ers4QtlihHLLgodr9Y+PGseFV23/VHvLj0Ts75GS4ITw2IE9lZXGYxVhlw9LK/TCpr1atmlvxJDK5zO76WsX9tFXL+jN40C7KELZYoRyo9r6BhXuLtfb2/dr1b8/1Tt7ytXQ5L/EhNgYXXRWd10ysJcuGdhTQ7LTFMNiDogC9Q1Gaz76VC9s3KP8d4udiYcejxTwJalvRpL6ZSSrX0ay+h79Z7+MZGWkJFBRd1KEssW6aiiHL0mv+eiA3t6+XwUfHVBFk6UOJWlgZrfGEP5CT40ckKHkBJY8RHSrqKrVX7cU608b92j9JwdP2DYlITYipPv1OBbafbonMUYdxQhli3WVUK5vMHq/OKT1Ow5q/Y6D2vDJwYgZq1LjuNvYz/d0Jmhl+5Jc6i3Q/g4cqtYnBw5r98HD2tXkZ/fBwyoOVelE38Qej+RPS4wM7SaVds9uVNk2I5Qt1llDuaauQVv3BSNCuKIqshJOiIvRBX3TdekXGi9Jnxvwsb4wIKmqtl57y484Ib3rQGRoVx430fF4SfGxx10OT1K/HuEqO5mJkC5rzfc+1wdxWo7U1Gvz7jInhDftKmu2aEc3b5xG9O+uLw3I0JcGZOi8Pj4uwQEtSIyP1ed6dWtxnW1jjA5W1kSE9LF/P6J9wSM6UluvD0oq9EFJRYvHz0rzqk/3ZKUnxSs1MU6picf/M05pLWxLSYhjLkcHI5RxSkJVtdq481gIv7OnXLX1kRdZuifH64tnNQbwyAE9NDg7laUIgTPk8XjUo5tXPbp5dUG/7s3219Q1OFV2S5X2oeo6lYSqVRKqPo33bvzjOq1JUKe2+O/xSmthWzdvnFK9BHtrEMqn4fHHH9fPfvYzFRUV6dxzz9Wjjz6qSy65xO1utakDh6q14ZODWnc0hN8rCkXMjpYa//oeOaCHUwl/vlc3/ucDOlhCXIwG9EzRgJ4pzfYZY1R+uFa7Dh7W3vIjCh2pVUVVnSqqahWqqnP+vaKqThXV4X2N22rrjYyRs+1MdPPGqZs3TonxMUqMj5U3LkbeuFh545v+M3JfYnhf0+3xJ96X2OSY0To0Rii30vPPP685c+bo8ccf18UXX6wnn3xSV155pbZt26Z+/fq53b3Ttq/8SEQIf1h6qFmb/j2S9aUmlXDfjCQmlwAW83g86p6SoO4pCRreN71Vr62qrY8M7Sb/Hmph2/GhHqqqU01d45DWoeo6Hao+s2BvrbgYT5OQbwzv//7qUI35XM8O7UdrMdGrlUaOHKkLL7xQS5YscbYNHjxYV199tRYtWnTS19sw0csYo08OHNb6HQe07uikrN0HjzRrNygr1amCvzQggwU7ALRKdV29E9SV1XWqqq1XdV2DquvqVVXb+M/q2oYm2xtaaNOg6tp6VR33z5q65q+rO/5y3nF+f+OXdOkXenXQ2R/DRK92UlNTo40bN+oHP/hBxPacnBytWbOmxddUV1eruvrYWE4oFGqxXUdYtnmP3nivVOt3HNT+isjxpdgYj4YG0pwx4S+elaHuKQku9RRAZ+CNi5W3W2yHPaijrr5BNfUNkYF/9J/VdQ0alJXaIf04E4RyK3z66aeqr69XVlZWxPasrCwVFxe3+JpFixbp/vvv74jundRb7+/XX94pktS4Ytb5fdOdKvjC/t3Vzct/DgCiV1xsjOJiY5QcxfUE38Kn4fhxVGPMZ46tzp8/X3PnznV+D4VC6tu3b7v277NcfUFAAzO76UsDMjS8bzr3LgKAZQjlVujZs6diY2ObVcWlpaXNqucwr9crr9eOZ6x++ZwsffmclvsJAHAfN5G2QkJCgkaMGKEVK1ZEbF+xYoXGjBnjUq8AAJ0FlXIrzZ07V7m5ubrooos0evRoPfXUU9q1a5e++93vut01AECUI5Rb6etf/7oOHDigBx54QEVFRRo6dKhee+019e/f3+2uAQCiHPcpdzAb7lMGAHSc1nzvM6YMAIAlCGUAACxBKAMAYAlCGQAASxDKAABYglAGAMAShDIAAJYglAEAsAShDACAJQhlAAAsQSgDAGAJQhkAAEsQygAAWIJQBgDAEoQyAACWIJQBALAEoQwAgCUIZQAALEEoAwBgCUIZAABLEMoAAFiCUAYAwBKEMgAAliCUAQCwBKEMAIAlCGUAACxBKAMAYAlCGQAASxDKAABYglAGAMAScW53oKsxxkiSQqGQyz0BAHSE8Pd9+Pv/RAjlDlZRUSFJ6tu3r8s9AQB0pIqKCvl8vhO28ZhTiW60mYaGBu3bt0+pqanyeDwd+t6hUEh9+/bV7t27lZaW1qHv3Rnw+Z0ZPr8zw+d3+tz+7IwxqqioUCAQUEzMiUeNqZQ7WExMjPr06eNqH9LS0vif+gzw+Z0ZPr8zw+d3+tz87E5WIYcx0QsAAEsQygAAWIJQ7kK8Xq/uu+8+eb1et7sSlfj8zgyf35nh8zt90fTZMdELAABLUCkDAGAJQhkAAEsQygAAWIJQBgDAEoQyAACWIJQBALAEoQwAgCUIZQAALEEoAwBgCUIZAABLEMoAAFiCUAYAwBKEMgAAliCUAQCwBKEMAIAlCGUAACxBKAMAYAlCGQAAS7gayqtWrdLUqVMVCATk8Xj00ksvRew3xmjBggUKBAJKSkrS+PHj9e677zY7TkFBgb785S8rJSVF6enpGj9+vI4cOeLsLysrU25urnw+n3w+n3Jzc1VeXh5xjF27dmnq1KlKSUlRz549NXv2bNXU1ES02bJli8aNG6ekpCT17t1bDzzwgIwxbfZ5AAC6NldDubKyUsOHD1deXl6L+x966CEtXrxYeXl52rBhg/x+vyZMmKCKigqnTUFBgSZNmqScnBytX79eGzZs0MyZMxUTc+zUpk+frsLCQuXn5ys/P1+FhYXKzc119tfX12vy5MmqrKzU6tWrtXTpUr3wwguaN2+e0yYUCmnChAkKBALasGGDHnvsMT388MNavHhxO3wyAIAuyVhCklm2bJnze0NDg/H7/ebBBx90tlVVVRmfz2eeeOIJZ9vIkSPND3/4w8887rZt24wks3btWmdbQUGBkWTef/99Y4wxr732momJiTF79+512jz33HPG6/WaYDBojDHm8ccfNz6fz1RVVTltFi1aZAKBgGloaDj9EwcA4Kg4l/8m+Ew7duxQcXGxcnJynG1er1fjxo3TmjVrdOutt6q0tFTr1q3TjBkzNGbMGH300Uc655xz9JOf/ERjx46V1FhJ+3w+jRw50jnOqFGj5PP5tGbNGg0aNEgFBQUaOnSoAoGA02bixImqrq7Wxo0bddlll6mgoEDjxo2T1+uNaDN//nx98sknGjBgQIvnUV1drerqauf3hoYGHTx4UD169JDH42mzzwsAYCdjjCoqKhQIBCKu4rbE2lAuLi6WJGVlZUVsz8rK0s6dOyVJH3/8sSRpwYIFevjhh3X++efr97//vS6//HJt3bpVAwcOVHFxsTIzM5sdPzMz03mP4uLiZu/TvXt3JSQkRLQ566yzmvUlvO+zQnnRokW6//77W3PqAIBOaPfu3erTp88J21gbymHHV5PGGGdbQ0ODJOnWW2/Vt7/9bUnSBRdcoDfffFO/+c1vtGjRohaPcfxxTreNOTrJ60QV7/z58zV37lzn92AwqH79+mn37t1KS0v7zNcBADqHUCikvn37KjU19aRtrQ1lv98vqbEKzc7OdraXlpY6FWp4+5AhQyJeO3jwYO3atcs5TklJSbPj79+/3zmO3+/XunXrIvaXlZWptrY2ok24am7aF6l5Nd+U1+uNuOQdlpaWRigDQBdyKkOW1t6nPGDAAPn9fq1YscLZVlNTo5UrV2rMmDGSpLPOOkuBQEAffPBBxGu3b9+u/v37S5JGjx6tYDCo9evXO/vXrVunYDDoHGf06NHaunWrioqKnDbLly+X1+vViBEjnDarVq2KuE1q+fLlCgQCzS5rAwBwWtycZVZRUWE2b95sNm/ebCSZxYsXm82bN5udO3caY4x58MEHjc/nMy+++KLZsmWLue6660x2drYJhULOMR555BGTlpZm/t//+3/m3//+t/nhD39oEhMTzYcffui0mTRpkjnvvPNMQUGBKSgoMMOGDTNTpkxx9tfV1ZmhQ4eayy+/3GzatMm88cYbpk+fPmbmzJlOm/LycpOVlWWuu+46s2XLFvPiiy+atLQ08/DDD7fqnIPBoJHkzOoGAHRurfnedzWU33rrLSOp2c/1119vjGm8Leq+++4zfr/feL1ec+mll5otW7Y0O86iRYtMnz59THJyshk9erR5++23I/YfOHDAzJgxw6SmpprU1FQzY8YMU1ZWFtFm586dZvLkySYpKclkZGSYmTNnRtz+ZIwx77zzjrnkkkuM1+s1fr/fLFiwoNW3QxHKANC1tOZ732MMS1J1pFAoJJ/Pp2AwyJgygC7BGKO6ujrV19e73ZV2ERsbq7i4uM8cM27N9761E70AANGvpqZGRUVFOnz4sNtdaVfJycnKzs5WQkLCGR2HUAYAtIuGhgbt2LFDsbGxCgQCSkhI6HSLJhljVFNTo/3792vHjh0aOHDgSRcIORFCGQDQLmpqatTQ0KC+ffsqOTnZ7e60m6SkJMXHx2vnzp2qqalRYmLiaR/L2luiAACdw5lUjtGirc6x839SAABECUIZAABLEMoAAFiCUAYA4DirVq3S1KlTFQgE5PF49NJLL3XI+xLKAAAcp7KyUsOHD1deXl6Hvi+3RAEAOowxRkdq3VnZKyk+9pTvk77yyit15ZVXtnOPmiOUAQAd5khtvYb86HVX3nvbAxOVnGB37HH5GgAAS9j9JwMAoFNJio/VtgcmuvbetiOUAQAdxuPxWH8J2U1cvgYAwBL8uQIAwHEOHTqkDz/80Pl9x44dKiwsVEZGhvr169du70soAwBwnH/+85+67LLLnN/nzp0rSbr++uv19NNPt9v7EsoAABxn/PjxMsZ0+PsypgwAgCUIZQAALEEoAwBgCUIZAABLEMoAgHblxoSpjtZW50goAwDaRXx8vCTp8OHDLvek/YXPMXzOp4tbogAA7SI2Nlbp6ekqLS2VJCUnJ5/yoxOjhTFGhw8fVmlpqdLT0xUbe2braxPKAIB24/f7JckJ5s4qPT3dOdczQSgDANqNx+NRdna2MjMzVVtb63Z32kV8fPwZV8hhhDIAoN3Fxsa2WXB1Zkz0AgDAEoQyAACWIJQBALAEoQwAgCUIZQAALEEoAwBgCUIZAABLEMoAAFiCUAYAwBKEMgAAliCUAQCwBKEMAIAlCGUAACxBKAMAYAlCGQAASxDKAABYglAGAMAShDIAAJYglAEAsAShDACAJQhlAAAsQSgDAGAJQhkAAEsQygAAWIJQBgDAEoQyAACWIJQBALAEoQwAgCUIZQAALEEoAwBgCUIZAABLEMoAAFiCUAYAwBKEMgAAliCUAQCwhKuhvGrVKk2dOlWBQEAej0cvvfRSxH5jjBYsWKBAIKCkpCSNHz9e7777bovHMsboyiuvbPE4ZWVlys3Nlc/nk8/nU25ursrLyyPa7Nq1S1OnTlVKSop69uyp2bNnq6amJqLNli1bNG7cOCUlJal379564IEHZIw5048BAABJLodyZWWlhg8frry8vBb3P/TQQ1q8eLHy8vK0YcMG+f1+TZgwQRUVFc3aPvroo/J4PC0eZ/r06SosLFR+fr7y8/NVWFio3NxcZ399fb0mT56syspKrV69WkuXLtULL7ygefPmOW1CoZAmTJigQCCgDRs26LHHHtPDDz+sxYsXn+GnAADAUcYSksyyZcuc3xsaGozf7zcPPvigs62qqsr4fD7zxBNPRLy2sLDQ9OnTxxQVFTU7zrZt24wks3btWmdbQUGBkWTef/99Y4wxr732momJiTF79+512jz33HPG6/WaYDBojDHm8ccfNz6fz1RVVTltFi1aZAKBgGloaDjl8wwGg0aSc1wAQOfWmu99a8eUd+zYoeLiYuXk5DjbvF6vxo0bpzVr1jjbDh8+rOuuu055eXny+/3NjlNQUCCfz6eRI0c620aNGiWfz+ccp6CgQEOHDlUgEHDaTJw4UdXV1dq4caPTZty4cfJ6vRFt9u3bp08++eQzz6O6ulqhUCjiBwCAllgbysXFxZKkrKysiO1ZWVnOPkm64447NGbMGF111VWfeZzMzMxm2zMzM53jFBcXN3uf7t27KyEh4YRtwr837c/xFi1a5Ixl+3w+9e3b9zPbAgC6NmtDOez4cWJjjLPtlVde0d/+9jc9+uijrTrG8cc53Tbm6CSvzxrLlqT58+crGAw6P7t37z5hXwEAXZe1oRy+FH18FVpaWupUqH/729/00UcfKT09XXFxcYqLi5Mkfe1rX9P48eOd45SUlDQ7/v79+53j+P3+Zu9TVlam2traE7YpLS2V1Lyab8rr9SotLS3iBwCAllgbygMGDJDf79eKFSucbTU1NVq5cqXGjBkjSfrBD36gd955R4WFhc6PJD3yyCP67W9/K0kaPXq0gsGg1q9f7xxn3bp1CgaDznFGjx6trVu3qqioyGmzfPlyeb1ejRgxwmmzatWqiNukli9frkAgoLPOOqtdPgMAQBfTzpPOTqiiosJs3rzZbN682UgyixcvNps3bzY7d+40xhjz4IMPGp/PZ1588UWzZcsWc91115ns7GwTCoU+85g6bva1McZMmjTJnHfeeaagoMAUFBSYYcOGmSlTpjj76+rqzNChQ83ll19uNm3aZN544w3Tp08fM3PmTKdNeXm5ycrKMtddd53ZsmWLefHFF01aWpp5+OGHW3XOzL4GgK6lNd/7robyW2+9ZSQ1+7n++uuNMY23Rd13333G7/cbr9drLr30UrNly5YTHrOlUD5w4ICZMWOGSU1NNampqWbGjBmmrKwsos3OnTvN5MmTTVJSksnIyDAzZ86MuP3JGGPeeecdc8kllxiv12v8fr9ZsGBBq26HMoZQBoCupjXf+x5jWJKqI4VCIfl8PgWDQcaXAaALaM33vrVjygAAdDWEMgAAliCUAQCwBKEMAIAlCGUAACxBKAMAYAlCGQAASxDKAABYglAGAMAShDIAAJYglAEAsAShDACAJQhlAAAsQSgDAGAJQhkAAEsQygAAWIJQBgDAEoQyAACWIJQBALAEoQwAgCUIZQAALEEoAwBgCUIZAABLEMoAAFiCUAYAwBKEMgAAliCUAQCwBKEMAIAlCGUAACxBKAMAYAlCGQAASxDKAABYglAGAMAShDIAAJYglAEAsAShDACAJQhlAAAsQSgDAGAJQhkAAEsQygAAWIJQBgDAEoQyAACWIJQBALAEoQwAgCUIZQAALEEoAwBgCUIZAABLEMoAAFiCUAYAwBKEMgAAliCUAQCwBKEMAIAlCGUAACxBKAMAYAlCGQAASxDKAABYglAGAMAShDIAAJYglAEAsAShDACAJQhlAAAsQSgDAGAJQhkAAEu4GsqrVq3S1KlTFQgE5PF49NJLL0XsN8ZowYIFCgQCSkpK0vjx4/Xuu+86+w8ePKhZs2Zp0KBBSk5OVr9+/TR79mwFg8GI45SVlSk3N1c+n08+n0+5ubkqLy+PaLNr1y5NnTpVKSkp6tmzp2bPnq2ampqINlu2bNG4ceOUlJSk3r1764EHHpAxpk0/EwBA1+VqKFdWVmr48OHKy8trcf9DDz2kxYsXKy8vTxs2bJDf79eECRNUUVEhSdq3b5/27dunhx9+WFu2bNHTTz+t/Px83XTTTRHHmT59ugoLC5Wfn6/8/HwVFhYqNzfX2V9fX6/JkyersrJSq1ev1tKlS/XCCy9o3rx5TptQKKQJEyYoEAhow4YNeuyxx/Twww9r8eLF7fDJAAC6JGMJSWbZsmXO7w0NDcbv95sHH3zQ2VZVVWV8Pp954oknPvM4//d//2cSEhJMbW2tMcaYbdu2GUlm7dq1TpuCggIjybz//vvGGGNee+01ExMTY/bu3eu0ee6554zX6zXBYNAYY8zjjz9ufD6fqaqqctosWrTIBAIB09DQcMrnGQwGjSTnuACAzq013/vWjinv2LFDxcXFysnJcbZ5vV6NGzdOa9as+czXBYNBpaWlKS4uTpJUUFAgn8+nkSNHOm1GjRoln8/nHKegoEBDhw5VIBBw2kycOFHV1dXauHGj02bcuHHyer0Rbfbt26dPPvnkM/tTXV2tUCgU8QMAQEusDeXi4mJJUlZWVsT2rKwsZ9/xDhw4oB//+Me69dZbI46TmZnZrG1mZqZznOLi4mbv0717dyUkJJywTfj3z+qPJC1atMgZy/b5fOrbt+9ntgUAdG3WhnKYx+OJ+N0Y02yb1DjmO3nyZA0ZMkT33XffCY/R0nFOp405OsmrpdeGzZ8/X8Fg0PnZvXv3Z7YFAHRt1oay3++X1LwKLS0tbVaxVlRUaNKkSerWrZuWLVum+Pj4iOOUlJQ0O/7+/fud4/j9/mbvU1ZWptra2hO2KS0tldS8mm/K6/UqLS0t4gcAgJZYG8oDBgyQ3+/XihUrnG01NTVauXKlxowZ42wLhULKyclRQkKCXnnlFSUmJkYcZ/To0QoGg1q/fr2zbd26dQoGg85xRo8era1bt6qoqMhps3z5cnm9Xo0YMcJps2rVqojbpJYvX65AIKCzzjqrTc8dANA1uRrKhw4dUmFhoQoLCyU1Tu4qLCzUrl275PF4NGfOHC1cuFDLli3T1q1bdcMNNyg5OVnTp0+X1Fgh5+TkqLKyUr/+9a8VCoVUXFys4uJi1dfXS5IGDx6sSZMm6eabb9batWu1du1a3XzzzZoyZYoGDRokScrJydGQIUOUm5urzZs3680339Sdd96pm2++2alsp0+fLq/XqxtuuEFbt27VsmXLtHDhQs2dO/eEl68BADhl7TwT/ITeeustI6nZz/XXX2+Mabwt6r777jN+v994vV5z6aWXmi1btpz09ZLMjh07nHYHDhwwM2bMMKmpqSY1NdXMmDHDlJWVRfRl586dZvLkySYpKclkZGSYmTNnRtz+ZIwx77zzjrnkkkuM1+s1fr/fLFiwoFW3QxnDLVEA0NW05nvfYwxLUnWkUCgkn8/n3LoFAOjcWvO9b+2YMgAAXQ2hDACAJQhlAAAsQSgDAGAJQhkAAEsQygAAWIJQBgDAEoQyAACWIJQBALAEoQwAgCUIZQAALEEoAwBgCUIZAABLEMoAAFiCUAYAwBKEMgAAliCUAQCwBKEMAIAlCGUAACxBKAMAYAlCGQAASxDKAABYglAGAMAShDIAAJYglAEAsAShDACAJQhlAAAsQSgDAGAJQhkAAEsQygAAWIJQBgDAEoQyAACWIJQBALAEoQwAgCUIZQAALEEoAwBgCUIZAABLEMoAAFiCUAYAwBKEMgAAliCUAQCwBKEMAIAlCGUAACxBKAMAYAlCGQAASxDKAABYglAGAMAShDIAAJYglAEAsAShDACAJQhlAAAsQSgDAGAJQhkAAEsQygAAWIJQBgDAEoQyAACWIJQBALAEoQwAgCUIZQAALEEoAwBgCUIZAABLEMoAAFiCUAYAwBKEMgAAlnA1lFetWqWpU6cqEAjI4/HopZdeithvjNGCBQsUCASUlJSk8ePH6913341oU11drVmzZqlnz55KSUnRtGnTtGfPnog2ZWVlys3Nlc/nk8/nU25ursrLyyPa7Nq1S1OnTlVKSop69uyp2bNnq6amJqLNli1bNG7cOCUlJal379564IEHZIxps88DANC1uRrKlZWVGj58uPLy8lrc/9BDD2nx4sXKy8vThg0b5Pf7NWHCBFVUVDht5syZo2XLlmnp0qVavXq1Dh06pClTpqi+vt5pM336dBUWFio/P1/5+fkqLCxUbm6us7++vl6TJ09WZWWlVq9eraVLl+qFF17QvHnznDahUEgTJkxQIBDQhg0b9Nhjj+nhhx/W4sWL2+GTAQB0RR7TylJvz549WrJkidasWaPi4mJ5PB5lZWVpzJgx+u53v6u+ffueXkc8Hi1btkxXX321pMYqORAIaM6cObrnnnskNVbFWVlZ+ulPf6pbb71VwWBQvXr10jPPPKOvf/3rkqR9+/apb9++eu211zRx4kS99957GjJkiNauXauRI0dKktauXavRo0fr/fff16BBg/TXv/5VU6ZM0e7duxUIBCRJS5cu1Q033KDS0lKlpaVpyZIlmj9/vkpKSuT1eiVJDz74oB577DHt2bNHHo/nlM4zFArJ5/MpGAwqLS3ttD6r02GM0ZHa+pM3BIBOKik+9pS/q9tSa77341pz4NWrV+vKK69U3759lZOTo5ycHBljVFpaqpdeekmPPfaY/vrXv+riiy8+oxOQpB07dqi4uFg5OTnONq/Xq3HjxmnNmjW69dZbtXHjRtXW1ka0CQQCGjp0qNasWaOJEyeqoKBAPp/PCWRJGjVqlHw+n9asWaNBgwapoKBAQ4cOdQJZkiZOnKjq6mpt3LhRl112mQoKCjRu3DgnkMNt5s+fr08++UQDBgxo8Tyqq6tVXV3t/B4Khc74szkdR2rrNeRHr7vy3gBgg20PTFRyQqtir8O1qnd33HGHvvOd7+iRRx75zP1z5szRhg0bzrhjxcXFkqSsrKyI7VlZWdq5c6fTJiEhQd27d2/WJvz64uJiZWZmNjt+ZmZmRJvj36d79+5KSEiIaHPWWWc1e5/wvs8K5UWLFun+++8/6fkCANCqUN66daueffbZz9x/66236oknnjjjTjV1/KUGY8xJLz8c36al9m3RJnzl/0T9mT9/vubOnev8HgqFTvsS/5lIio/Vtgcmdvj7AoAtkuJj3e7CSbUqlLOzs51Lvi0pKChQdnZ2m3TM7/dLaqxCmx6ztLTUqVD9fr9qampUVlYWUS2XlpZqzJgxTpuSkpJmx9+/f3/EcdatWxexv6ysTLW1tRFtwlVz0/eRmlfzTXm93ohL3m7xeDzWX7YBgK6uVbOv77zzTn33u9/VzJkz9fLLL2vt2rVat26dXn75Zc2cOVPf+973dPfdd7dJxwYMGCC/368VK1Y422pqarRy5UoncEeMGKH4+PiINkVFRdq6davTZvTo0QoGg1q/fr3TZt26dQoGgxFttm7dqqKiIqfN8uXL5fV6NWLECKfNqlWrIm6TWr58uQKBQLPL2gAAnBbTSkuXLjUjR440cXFxxuPxGI/HY+Li4szIkSPN888/36pjVVRUmM2bN5vNmzcbSWbx4sVm8+bNZufOncYYYx588EHj8/nMiy++aLZs2WKuu+46k52dbUKhkHOM7373u6ZPnz7mjTfeMJs2bTJf/vKXzfDhw01dXZ3TZtKkSea8884zBQUFpqCgwAwbNsxMmTLF2V9XV2eGDh1qLr/8crNp0ybzxhtvmD59+piZM2c6bcrLy01WVpa57rrrzJYtW8yLL75o0tLSzMMPP9yqcw4Gg0aSCQaDrXodACA6teZ7v9WhHFZTU2P27dtn9u3bZ2pqak7rGG+99ZaR1Ozn+uuvN8YY09DQYO677z7j9/uN1+s1l156qdmyZUvEMY4cOWJmzpxpMjIyTFJSkpkyZYrZtWtXRJsDBw6YGTNmmNTUVJOammpmzJhhysrKItrs3LnTTJ482SQlJZmMjAwzc+ZMU1VVFdHmnXfeMZdcconxer3G7/ebBQsWmIaGhladM6EMAF1La773W3Wf8jXXXHNK7V588cVW1utdh1v3KQMA3NFu9yn7fL4z6hgAAPhsrQrl3/72t+3VDwAAujyeEgUAgCUIZQAALEEoAwBgCUIZAABLEMoAAFiCUAYAwBKEMgAAliCUAQCwBKEMAIAlCGUAACxBKAMAYAlCGQAASxDKAABYglAGAMAShDIAAJYglAEAsAShDACAJQhlAAAsQSgDAGAJQhkAAEsQygAAWIJQBgDAEoQyAACWIJQBALAEoQwAgCUIZQAALEEoAwBgCUIZAABLEMoAAFiCUAYAwBKEMgAAliCUAQCwBKEMAIAlCGUAACxBKAMAYAlCGQAASxDKAABYglAGAMAShDIAAJYglAEAsAShDACAJQhlAAAsQSgDAGAJQhkAAEsQygAAWIJQBgDAEoQyAACWIJQBALAEoQwAgCUIZQAALEEoAwBgCUIZAABLEMoAAFiCUAYAwBKEMgAAliCUAQCwBKEMAIAlCGUAACxBKAMAYAlCGQAASxDKAABYwvpQrqio0Jw5c9S/f38lJSVpzJgx2rBhg7P/0KFDmjlzpvr06aOkpCQNHjxYS5YsiThGdXW1Zs2apZ49eyolJUXTpk3Tnj17ItqUlZUpNzdXPp9PPp9Pubm5Ki8vj2iza9cuTZ06VSkpKerZs6dmz56tmpqadjt3AEDXYn0of+c739GKFSv0zDPPaMuWLcrJydEVV1yhvXv3SpLuuOMO5efn69lnn9V7772nO+64Q7NmzdLLL7/sHGPOnDlatmyZli5dqtWrV+vQoUOaMmWK6uvrnTbTp09XYWGh8vPzlZ+fr8LCQuXm5jr76+vrNXnyZFVWVmr16tVaunSpXnjhBc2bN6/jPgwAQOdmLHb48GETGxtrXn311Yjtw4cPN/fee68xxphzzz3XPPDAAxH7L7zwQvPDH/7QGGNMeXm5iY+PN0uXLnX2792718TExJj8/HxjjDHbtm0zkszatWudNgUFBUaSef/9940xxrz22msmJibG7N2712nz3HPPGa/Xa4LB4CmfUzAYNJJa9RoAQPRqzfe+1ZVyXV2d6uvrlZiYGLE9KSlJq1evliSNHTtWr7zyivbu3StjjN566y1t375dEydOlCRt3LhRtbW1ysnJcV4fCAQ0dOhQrVmzRpJUUFAgn8+nkSNHOm1GjRoln88X0Wbo0KEKBAJOm4kTJ6q6ulobN278zHOorq5WKBSK+AEAoCVWh3JqaqpGjx6tH//4x9q3b5/q6+v17LPPat26dSoqKpIk/fKXv9SQIUPUp08fJSQkaNKkSXr88cc1duxYSVJxcbESEhLUvXv3iGNnZWWpuLjYaZOZmdns/TMzMyPaZGVlRezv3r27EhISnDYtWbRokTNO7fP51Ldv39P/QAAAnZrVoSxJzzzzjIwx6t27t7xer375y19q+vTpio2NldQYymvXrtUrr7yijRs36uc//7luu+02vfHGGyc8rjFGHo/H+b3pv59Jm+PNnz9fwWDQ+dm9e/dJzxkA0DXFud2Bk/nc5z6nlStXqrKyUqFQSNnZ2fr617+uAQMG6MiRI/rP//xPLVu2TJMnT5YknXfeeSosLNTDDz+sK664Qn6/XzU1NSorK4uolktLSzVmzBhJkt/vV0lJSbP33r9/v1Md+/1+rVu3LmJ/WVmZamtrm1XQTXm9Xnm93jP+HAAAnZ/1lXJYSkqKsrOzVVZWptdff11XXXWVamtrVVtbq5iYyNOIjY1VQ0ODJGnEiBGKj4/XihUrnP1FRUXaunWrE8qjR49WMBjU+vXrnTbr1q1TMBiMaLN161bnsrkkLV++XF6vVyNGjGi38wYAdB0eY4xxuxMn8vrrr8sYo0GDBunDDz/UXXfdJa/Xq9WrVys+Pl7jx4/Xp59+qry8PPXv318rV67U9773PS1evFjf+973JEnf+9739Oqrr+rpp59WRkaG7rzzTh04cEAbN250LoNfeeWV2rdvn5588klJ0i233KL+/fvrz3/+s6TGW6LOP/98ZWVl6Wc/+5kOHjyoG264QVdffbUee+yxUz6fUCgkn8+nYDCotLS0Nv60AAC2adX3fjvOAm8Tzz//vDn77LNNQkKC8fv95vbbbzfl5eXO/qKiInPDDTeYQCBgEhMTzaBBg8zPf/5z09DQ4LQ5cuSImTlzpsnIyDBJSUlmypQpZteuXRHvc+DAATNjxgyTmppqUlNTzYwZM0xZWVlEm507d5rJkyebpKQkk5GRYWbOnGmqqqpadT7cEgUAXUtrvvetr5Q7GyplAOhaWvO9HzVjygAAdHaEMgAAliCUAQCwBKEMAIAlCGUAACxBKAMAYAlCGQAASxDKAABYglAGAMAShDIAAJYglAEAsAShDACAJQhlAAAsQSgDAGAJQhkAAEsQygAAWIJQBgDAEoQyAACWIJQBALAEoQwAgCUIZQAALEEoAwBgCUIZAABLEMoAAFiCUAYAwBKEMgAAliCUAQCwBKEMAIAlCGUAACxBKAMAYAlCGQAASxDKAABYglAGAMAShDIAAJYglAEAsAShDACAJQhlAAAsQSgDAGAJQhkAAEsQygAAWIJQBgDAEoQyAACWIJQBALAEoQwAgCUIZQAALEEoAwBgCUIZAABLEMoAAFiCUAYAwBKEMgAAliCUAQCwBKEMAIAlCGUAACxBKAMAYAlCGQAASxDKAABYglAGAMAShDIAAJYglAEAsAShDACAJQhlAAAsQSgDAGAJQhkAAEtYH8oVFRWaM2eO+vfvr6SkJI0ZM0YbNmyIaPPee+9p2rRp8vl8Sk1N1ahRo7Rr1y5nf3V1tWbNmqWePXsqJSVF06ZN0549eyKOUVZWptzcXPl8Pvl8PuXm5qq8vDyiza5duzR16lSlpKSoZ8+emj17tmpqatrt3AEAXYv1ofyd73xHK1as0DPPPKMtW7YoJydHV1xxhfbu3StJ+uijjzR27Fidc845+vvf/65//etf+q//+i8lJiY6x5gzZ46WLVumpUuXavXq1Tp06JCmTJmi+vp6p8306dNVWFio/Px85efnq7CwULm5uc7++vp6TZ48WZWVlVq9erWWLl2qF154QfPmzeu4DwMA0LkZix0+fNjExsaaV199NWL78OHDzb333muMMebrX/+6+eY3v/mZxygvLzfx8fFm6dKlzra9e/eamJgYk5+fb4wxZtu2bUaSWbt2rdOmoKDASDLvv/++McaY1157zcTExJi9e/c6bZ577jnj9XpNMBg85XMKBoNGUqteAwCIXq353re6Uq6rq1N9fX1E1StJSUlJWr16tRoaGvSXv/xFX/jCFzRx4kRlZmZq5MiReumll5y2GzduVG1trXJycpxtgUBAQ4cO1Zo1ayRJBQUF8vl8GjlypNNm1KhR8vl8EW2GDh2qQCDgtJk4caKqq6u1cePGzzyH6upqhUKhiB8AAFpidSinpqZq9OjR+vGPf6x9+/apvr5ezz77rNatW6eioiKVlpbq0KFDevDBBzVp0iQtX75cX/3qV3XNNddo5cqVkqTi4mIlJCSoe/fuEcfOyspScXGx0yYzM7PZ+2dmZka0ycrKitjfvXt3JSQkOG1asmjRImec2ufzqW/fvmf0mQAAOi+rQ1mSnnnmGRlj1Lt3b3m9Xv3yl7/U9OnTFRsbq4aGBknSVVddpTvuuEPnn3++fvCDH2jKlCl64oknTnhcY4w8Ho/ze9N/P5M2x5s/f76CwaDzs3v37pOeMwCga7I+lD/3uc9p5cqVOnTokHbv3q3169ertrZWAwYMUM+ePRUXF6chQ4ZEvGbw4MHO7Gu/36+amhqVlZVFtCktLXUqX7/fr5KSkmbvvX///og2x1fEZWVlqq2tbVZBN+X1epWWlhbxAwBAS6wP5bCUlBRlZ2errKxMr7/+uq666iolJCToi1/8oj744IOIttu3b1f//v0lSSNGjFB8fLxWrFjh7C8qKtLWrVs1ZswYSdLo0aMVDAa1fv16p826desUDAYj2mzdulVFRUVOm+XLl8vr9WrEiBHtdt4AgK7DY4wxbnfiRF5//XUZYzRo0CB9+OGHuuuuu+T1erV69WrFx8dr2bJl+vrXv67/+Z//0WWXXab8/HzNmTNHf//73zV27FhJ0ve+9z29+uqrevrpp5WRkaE777xTBw4c0MaNGxUbGytJuvLKK7Vv3z49+eSTkqRbbrlF/fv315///GdJjbdEnX/++crKytLPfvYzHTx4UDfccIOuvvpqPfbYY6d8PqFQSD6fT8FgkKoZALqAVn3vt+c08Lbw/PPPm7PPPtskJCQYv99vbr/9dlNeXh7R5te//rX5/Oc/bxITE83w4cPNSy+9FLH/yJEjZubMmSYjI8MkJSWZKVOmmF27dkW0OXDggJkxY4ZJTU01qampZsaMGaasrCyizc6dO83kyZNNUlKSycjIMDNnzjRVVVWtOh9uiQKArqU13/vWV8qdDZUyAHQtrfnej5oxZQAAOjtCGQAASxDKAABYglAGAMAShDIAAJYglAEAsAShDACAJQhlAAAsQSgDAGAJQhkAAEsQygAAWIJQBgDAEoQyAACWIJQBALAEoQwAgCUIZQAALEEoAwBgCUIZAABLEMoAAFiCUAYAwBKEMgAAliCUAQCwBKEMAIAlCGUAACxBKAMAYAlCGQAASxDKAABYglAGAMAShDIAAJYglAEAsAShDACAJQhlAAAsQSgDAGAJQhkAAEsQygAAWIJQBgDAEoQyAACWIJQBALAEoQwAgCUIZQAALEEoAwBgCUIZAABLEMoAAFiCUAYAwBKEMgAAliCUAQCwBKEMAIAlCGUAACxBKAMAYAlCGQAASxDKAABYglAGAMAShDIAAJYglAEAsAShDACAJQhlAAAsQSgDAGAJQhkAAEsQygAAWIJQBgDAEoQyAACWIJQBALAEoQwAgCUIZQAALGF9KFdUVGjOnDnq37+/kpKSNGbMGG3YsKHFtrfeeqs8Ho8effTRiO3V1dWaNWuWevbsqZSUFE2bNk179uyJaFNWVqbc3Fz5fD75fD7l5uaqvLw8os2uXbs0depUpaSkqGfPnpo9e7Zqamra8nQBAF2Y9aH8ne98RytWrNAzzzyjLVu2KCcnR1dccYX27t0b0e6ll17SunXrFAgEmh1jzpw5WrZsmZYuXarVq1fr0KFDmjJliurr650206dPV2FhofLz85Wfn6/CwkLl5uY6++vr6zV58mRVVlZq9erVWrp0qV544QXNmzev/U4eANC1GIsdPnzYxMbGmldffTVi+/Dhw829997r/L5nzx7Tu3dvs3XrVtO/f3/zyCOPOPvKy8tNfHy8Wbp0qbNt7969JiYmxuTn5xtjjNm2bZuRZNauXeu0KSgoMJLM+++/b4wx5rXXXjMxMTFm7969TpvnnnvOeL1eEwwGT/mcgsGgkdSq1wAAoldrvvfj3P2T4MTq6upUX1+vxMTEiO1JSUlavXq1JKmhoUG5ubm66667dO655zY7xsaNG1VbW6ucnBxnWyAQ0NChQ7VmzRpNnDhRBQUF8vl8GjlypNNm1KhR8vl8WrNmjQYNGqSCggINHTo0ohKfOHGiqqurtXHjRl122WUtnkN1dbWqq6ud34PBoCQpFAqdxicCAIg24e97Y8xJ21odyqmpqRo9erR+/OMfa/DgwcrKytJzzz2ndevWaeDAgZKkn/70p4qLi9Ps2bNbPEZxcbESEhLUvXv3iO1ZWVkqLi522mRmZjZ7bWZmZkSbrKysiP3du3dXQkKC06YlixYt0v33399se9++fU9w5gCAzqaiokI+n++EbawOZUl65plndOONN6p3796KjY3VhRdeqOnTp2vTpk3auHGjfvGLX2jTpk3yeDytOq4xJuI1Lb3+dNocb/78+Zo7d67ze0NDgw4ePKgePXq0us9nKhQKqW/fvtq9e7fS0tI69L07Az6/M8Pnd2b4/E6f25+dMUYVFRUtznk6nvWh/LnPfU4rV65UZWWlQqGQsrOz9fWvf10DBgzQ22+/rdLSUvXr189pX19fr3nz5unRRx/VJ598Ir/fr5qaGpWVlUVUy6WlpRozZowkye/3q6SkpNl779+/36mO/X6/1q1bF7G/rKxMtbW1zSroprxer7xeb8S29PT0Vn8ObSktLY3/qc8An9+Z4fM7M3x+p8/Nz+5kFXKY9bOvw1JSUpSdna2ysjK9/vrruuqqq5Sbm6t33nlHhYWFzk8gENBdd92l119/XZI0YsQIxcfHa8WKFc6xioqKtHXrVieUR48erWAwqPXr1ztt1q1bp2AwGNFm69atKioqctosX75cXq9XI0aM6IiPAADQyVlfKb/++usyxmjQoEH68MMPddddd2nQoEH69re/rfj4ePXo0SOifXx8vPx+vwYNGiSp8a+Tm266SfPmzVOPHj2UkZGhO++8U8OGDdMVV1whSRo8eLAmTZqkm2++WU8++aQk6ZZbbtGUKVOc4+Tk5GjIkCHKzc3Vz372Mx08eFB33nmnbr75Zv5qBQC0Cesr5WAwqNtvv13nnHOOvvWtb2ns2LFavny54uPjT/kYjzzyiK6++mpde+21uvjii5WcnKw///nPio2Nddr84Q9/0LBhw5STk6OcnBydd955euaZZ5z9sbGx+stf/qLExERdfPHFuvbaa3X11Vfr4YcfbtPzbU9er1f33Xdfs8vpODV8fmeGz+/M8Pmdvmj67DzmVOZoAwCAdmd9pQwAQFdBKAMAYAlCGQAASxDKAABYglDuAhYtWqQvfvGLSk1NVWZmpq6++mp98MEHbncrKi1atEgej0dz5sxxuytRY+/evfrmN7+pHj16KDk5Weeff742btzodreiQl1dnX74wx9qwIABSkpK0tlnn60HHnhADQ0NbnfNSqtWrdLUqVMVCATk8Xj00ksvRew3xmjBggUKBAJKSkrS+PHj9e6777rT2c9AKHcBK1eu1O233661a9dqxYoV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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "def th2th(detectors, tth, th, start, finish, num, md={}):\n", " # Since x2x is a relative scan, first move to the absolute start positions.\n", " yield from bps.mv(tth, start, th, start/2)\n", " yield from bp.x2x_scan(detectors, tth, th, 0, finish-start, num, md=md)\n", " print(f\"{h5_file.exists()=} {h5_file=}\")\n", "\n", "RE(th2th([sensor, I0], tth, th, 2, 10, 11, md=md))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Look at the NeXus/HDF5 *NXmonopd* file" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "!!! WARNING: this program is not ready for distribution.\n", "\n", "/tmp/nxwriter.h5 : NeXus data file\n", " @HDF5_Version = \"1.14.0\"\n", " @NeXus_version = \"v2020.1\"\n", " @creator = \"NXWriter\"\n", " @default = \"entry\"\n", " @file_name = \"/tmp/nxwriter.h5\"\n", " @file_time = \"2023-12-02T13:16:03.536788\"\n", " @h5py_version = \"3.9.0\"\n", " entry:NXentry\n", " @NX_class = \"NXentry\"\n", " @default = \"monopd\"\n", " @target = \"/entry\"\n", " definition:NX_CHAR = b'NXmonopd'\n", " @target = \"/entry/definition\"\n", " duration:NX_FLOAT64[] = \n", " @units = \"s\"\n", " end_time:NX_CHAR = b'2023-12-02T13:16:03.365098'\n", " entry_identifier --> /entry/instrument/bluesky/metadata/run_start_uid\n", " plan_name --> /entry/instrument/bluesky/metadata/plan_name\n", " program_name:NX_CHAR = b'bluesky'\n", " start_time:NX_CHAR = b'2023-12-02T13:15:51.630091'\n", " title:NX_CHAR = b'x2x_scan-S0001-90acae1'\n", " data:NXdata\n", " @NX_class = \"NXdata\"\n", " @axes = [\"tth\", \"th\"]\n", " @signal = \"sensor\"\n", " @target = \"/entry/data\"\n", " EPOCH --> /entry/instrument/bluesky/streams/primary/tth_user_setpoint/time\n", " I0 --> /entry/instrument/bluesky/streams/primary/I0/value\n", " sensor --> /entry/instrument/bluesky/streams/primary/sensor/value\n", " th --> /entry/instrument/bluesky/streams/primary/th/value\n", " th_user_setpoint --> /entry/instrument/bluesky/streams/primary/th_user_setpoint/value\n", " tth --> /entry/instrument/bluesky/streams/primary/tth/value\n", " tth_user_setpoint --> /entry/instrument/bluesky/streams/primary/tth_user_setpoint/value\n", " instrument:NXinstrument\n", " @NX_class = \"NXinstrument\"\n", " @target = \"/entry/instrument\"\n", " bluesky:NXnote\n", " @NX_class = \"NXnote\"\n", " @target = \"/entry/instrument/bluesky\"\n", " plan_name --> /entry/instrument/bluesky/metadata/plan_name\n", " uid --> /entry/instrument/bluesky/metadata/run_start_uid\n", " metadata:NXnote\n", " @NX_class = \"NXnote\"\n", " @target = \"/entry/instrument/bluesky/metadata\"\n", " detectors:NX_CHAR = b'- sensor\\n- I0\\n'\n", " @target = \"/entry/instrument/bluesky/metadata/detectors\"\n", " @text_format = \"yaml\"\n", " hints:NX_CHAR = b'dimensions:\\n- !!python/tuple\\n - - tth\\n - th\\n - primary\\n'\n", " @target = \"/entry/instrument/bluesky/metadata/hints\"\n", " @text_format = \"yaml\"\n", " mono_wavelength:NX_FLOAT64[] = \n", " @target = \"/entry/instrument/bluesky/metadata/mono_wavelength\"\n", " motors:NX_CHAR = b'!!python/tuple\\n- tth\\n- th\\n'\n", " @target = \"/entry/instrument/bluesky/metadata/motors\"\n", " @text_format = \"yaml\"\n", " num_intervals:NX_INT64[] = \n", " @target = \"/entry/instrument/bluesky/metadata/num_intervals\"\n", " num_points:NX_INT64[] = \n", " @target = \"/entry/instrument/bluesky/metadata/num_points\"\n", " nxwriter_template:NX_CHAR = b'[[\"/entry/definition=\", \"NXmonopd\"], [\"/entry/instrument/bluesky/metadata/mono_wavelength\", \"/entry/instrument/crystal:NXcrystal/wavelength\"], [\"/entry/instrument/bluesky/streams/primary/tth/value\", \"/entry/instrument/detector:NXdetector/polar_angle\"], [\"/entry/instrument/bluesky/streams/primary/sensor/value\", \"/entry/instrument/detector:NXdetector/data\"], [\"/entry/instrument/bluesky/metadata/sample_name\", \"/entry/sample:NXsample/name\"], [\"/entry/sample:NXsample/rotation_angle=\", 0], [\"/entry/monitor:NXmonitor/mode=\", \"monitor\"], [\"/entry/monitor:NXmonitor/preset=\", 100000], [\"/entry/instrument/bluesky/streams/primary/I0/value\", \"/entry/monitor:NXmonitor/integral\"], [\"/entry/instrument/bluesky/streams/primary/tth/value\", \"/entry/monopd:NXdata/polar_angle\"], [\"/entry/instrument/bluesky/streams/primary/sensor/value\", \"/entry/monopd:NXdata/data\"], [\"/entry/monopd/@signal\", \"data\"], [\"/entry/monopd/@axes\", [\"polar_angle\"]], [\"/entry/@default\", \"monopd\"], [\"/entry/monitor:NXmonitor/@signal\", \"integral\"]]'\n", " @target = \"/entry/instrument/bluesky/metadata/nxwriter_template\"\n", " plan_args:NX_CHAR = b\"detectors:\\n- EpicsSignalRO(read_pv='gp:userCalc10.VAL', name='sensor', value=0.0, timestamp=1701544551.572926,\\n auto_monitor=True, string=False)\\n- Signal(name='I0', value=100000, timestamp=1701544551.4371457)\\nmotor1: tth\\nmotor2: th\\nnum: 11\\nper_step: None\\nstart: 0\\nstop: 8\\n\"\n", " @target = \"/entry/instrument/bluesky/metadata/plan_args\"\n", " @text_format = \"yaml\"\n", " plan_name:NX_CHAR = b'x2x_scan'\n", " @target = \"/entry/instrument/bluesky/metadata/plan_name\"\n", " plan_pattern:NX_CHAR = b'inner_product'\n", " @target = \"/entry/instrument/bluesky/metadata/plan_pattern\"\n", " plan_pattern_args:NX_CHAR = b\"args:\\n- EpicsMotor(prefix='gp:m10', name='tth', settle_time=0.0, timeout=None, read_attrs=['user_readback',\\n 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity',\\n 'acceleration', 'motor_egu'])\\n- 0\\n- 8\\n- EpicsMotor(prefix='gp:m9', name='th', settle_time=0.0, timeout=None, read_attrs=['user_readback',\\n 'user_setpoint'], configuration_attrs=['user_offset', 'user_offset_dir', 'velocity',\\n 'acceleration', 'motor_egu'])\\n- 0.0\\n- 4.0\\nnum: 11\\n\"\n", " @target = \"/entry/instrument/bluesky/metadata/plan_pattern_args\"\n", " @text_format = \"yaml\"\n", " plan_pattern_module:NX_CHAR = b'bluesky.plan_patterns'\n", " @target = \"/entry/instrument/bluesky/metadata/plan_pattern_module\"\n", " plan_type:NX_CHAR = b'generator'\n", " @target = \"/entry/instrument/bluesky/metadata/plan_type\"\n", " run_start_uid:NX_CHAR = b'90acae1f-2475-406a-b86f-05b7ca2bb7d2'\n", " @long_name = \"bluesky run uid\"\n", " @target = \"/entry/instrument/bluesky/metadata/run_start_uid\"\n", " sample_name:NX_CHAR = b'simulation'\n", " @target = \"/entry/instrument/bluesky/metadata/sample_name\"\n", " title:NX_CHAR = b'Demonstrate NeXus/HDF5 template support'\n", " @target = \"/entry/instrument/bluesky/metadata/title\"\n", " versions:NX_CHAR = b'bluesky: 1.10.0\\nophyd: 1.9.0\\n'\n", " @target = \"/entry/instrument/bluesky/metadata/versions\"\n", " @text_format = \"yaml\"\n", " streams:NXnote\n", " @NX_class = \"NXnote\"\n", " @target = \"/entry/instrument/bluesky/streams\"\n", " primary:NXnote\n", " @NX_class = \"NXnote\"\n", " @target = \"/entry/instrument/bluesky/streams/primary\"\n", " @uid = \"175a60a2-aec7-4307-bd24-ffe206ffc3ae\"\n", " I0:NXdata\n", " @NX_class = \"NXdata\"\n", " @axes = [\"time\"]\n", " @signal = \"value\"\n", " @signal_type = \"detector\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/I0\"\n", " EPOCH:NX_FLOAT64[11] = [1701544551.4371457, 1701544551.4371457, 1701544551.4371457, '...', 1701544551.4371457]\n", " @long_name = \"epoch time (s)\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/I0/EPOCH\"\n", " @units = \"s\"\n", " time:NX_FLOAT64[11] = [0.0, 0.0, 0.0, '...', 0.0]\n", " @long_name = \"time since first data (s)\"\n", " @start_time = 1701544551.4371457\n", " @start_time_iso = \"2023-12-02T13:15:51.437146\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/I0/time\"\n", " @units = \"s\"\n", " value:NX_INT64[11] = [100000, 100000, 100000, '...', 100000]\n", " @long_name = \"I0\"\n", " @lower_ctrl_limit = \"\"\n", " @precision = 0\n", " @signal_type = \"detector\"\n", " @source = \"SIM:I0\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/I0/value\"\n", " @units = \"\"\n", " @upper_ctrl_limit = \"\"\n", " sensor:NXdata\n", " @NX_class = \"NXdata\"\n", " @axes = [\"time\"]\n", " @signal = \"value\"\n", " @signal_type = \"detector\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/sensor\"\n", " EPOCH:NX_FLOAT64[11] = [1701544551.572926, 1701544552.871271, 1701544553.974374, '...', 1701544563.299544]\n", " @long_name = \"epoch time (s)\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/sensor/EPOCH\"\n", " @units = \"s\"\n", " time:NX_FLOAT64[11] = [0.0, 1.2983448505401611, 2.4014480113983154, '...', 11.72661805152893]\n", " @long_name = \"time since first data (s)\"\n", " @start_time = 1701544551.572926\n", " @start_time_iso = \"2023-12-02T13:15:51.572926\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/sensor/time\"\n", " @units = \"s\"\n", " value:NX_FLOAT64[11] = [0.0, 182.83233136804841, 390.0741582405076, '...', 53.2999002115527]\n", " @long_name = \"sensor\"\n", " @lower_ctrl_limit = 0.0\n", " @precision = 5\n", " @signal_type = \"detector\"\n", " @source = \"PV:gp:userCalc10.VAL\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/sensor/value\"\n", " @units = \"\"\n", " @upper_ctrl_limit = 0.0\n", " th:NXdata\n", " @NX_class = \"NXdata\"\n", " @axes = [\"time\"]\n", " @signal = \"value\"\n", " @signal_type = \"positioner\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/th\"\n", " EPOCH:NX_FLOAT64[11] = [1701543761.161202, 1701544552.469743, 1701544553.573023, '...', 1701544562.898525]\n", " @long_name = \"epoch time (s)\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/th/EPOCH\"\n", " @units = \"s\"\n", " time:NX_FLOAT64[11] = [0.0, 791.308541059494, 792.4118211269379, '...', 801.7373230457306]\n", " @long_name = \"time since first data (s)\"\n", " @start_time = 1701543761.161202\n", " @start_time_iso = \"2023-12-02T13:02:41.161202\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/th/time\"\n", " @units = \"s\"\n", " value:NX_FLOAT64[11] = [1.0, 1.4000000000000001, 1.8, '...', 5.0]\n", " @long_name = \"th\"\n", " @lower_ctrl_limit = -1000.0\n", " @precision = 4\n", " @signal_type = \"positioner\"\n", " @source = \"PV:gp:m9.RBV\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/th/value\"\n", " @units = \"degrees\"\n", " @upper_ctrl_limit = 1000.0\n", " th_user_setpoint:NXdata\n", " @NX_class = \"NXdata\"\n", " @axes = [\"time\"]\n", " @signal = \"value\"\n", " @signal_type = \"other\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/th_user_setpoint\"\n", " EPOCH:NX_FLOAT64[11] = [1701544551.636257, 1701544551.786764, 1701544552.965123, '...', 1701544562.2169707]\n", " @long_name = \"epoch time (s)\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/th_user_setpoint/EPOCH\"\n", " @units = \"s\"\n", " time:NX_FLOAT64[11] = [0.0, 0.15050697326660156, 1.3288660049438477, '...', 10.580713748931885]\n", " @long_name = \"time since first data (s)\"\n", " @start_time = 1701544551.636257\n", " @start_time_iso = \"2023-12-02T13:15:51.636257\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/th_user_setpoint/time\"\n", " @units = \"s\"\n", " value:NX_FLOAT64[11] = [1.0, 1.4, 1.8, '...', 5.0]\n", " @long_name = \"th_user_setpoint\"\n", " @lower_ctrl_limit = -1000.0\n", " @precision = 4\n", " @signal_type = \"other\"\n", " @source = \"PV:gp:m9.VAL\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/th_user_setpoint/value\"\n", " @units = \"degrees\"\n", " @upper_ctrl_limit = 1000.0\n", " tth:NXdata\n", " @NX_class = \"NXdata\"\n", " @axes = [\"time\"]\n", " @signal = \"value\"\n", " @signal_type = \"positioner\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/tth\"\n", " EPOCH:NX_FLOAT64[11] = [1701543761.160919, 1701544552.871001, 1701544553.974129, '...', 1701544563.299386]\n", " @long_name = \"epoch time (s)\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/tth/EPOCH\"\n", " @units = \"s\"\n", " time:NX_FLOAT64[11] = [0.0, 791.7100820541382, 792.8132100105286, '...', 802.1384670734406]\n", " @long_name = \"time since first data (s)\"\n", " @start_time = 1701543761.160919\n", " @start_time_iso = \"2023-12-02T13:02:41.160919\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/tth/time\"\n", " @units = \"s\"\n", " value:NX_FLOAT64[11] = [2.0, 2.8000000000000003, 3.6, '...', 10.0]\n", " @long_name = \"tth\"\n", " @lower_ctrl_limit = -1000.0\n", " @precision = 4\n", " @signal_type = \"positioner\"\n", " @source = \"PV:gp:m10.RBV\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/tth/value\"\n", " @units = \"degrees\"\n", " @upper_ctrl_limit = 1000.0\n", " tth_user_setpoint:NXdata\n", " @NX_class = \"NXdata\"\n", " @axes = [\"time\"]\n", " @signal = \"value\"\n", " @signal_type = \"other\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/tth_user_setpoint\"\n", " EPOCH:NX_FLOAT64[11] = [1701544551.6354487, 1701544551.785843, 1701544552.964422, '...', 1701544562.215509]\n", " @long_name = \"epoch time (s)\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/tth_user_setpoint/EPOCH\"\n", " @units = \"s\"\n", " time:NX_FLOAT64[11] = [0.0, 0.15039420127868652, 1.3289732933044434, '...', 10.580060243606567]\n", " @long_name = \"time since first data (s)\"\n", " @start_time = 1701544551.6354487\n", " @start_time_iso = \"2023-12-02T13:15:51.635449\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/tth_user_setpoint/time\"\n", " @units = \"s\"\n", " value:NX_FLOAT64[11] = [2.0, 2.8, 3.6, '...', 10.0]\n", " @long_name = \"tth_user_setpoint\"\n", " @lower_ctrl_limit = -1000.0\n", " @precision = 4\n", " @signal_type = \"other\"\n", " @source = \"PV:gp:m10.VAL\"\n", " @target = \"/entry/instrument/bluesky/streams/primary/tth_user_setpoint/value\"\n", " @units = \"degrees\"\n", " @upper_ctrl_limit = 1000.0\n", " crystal:NXcrystal\n", " @NX_class = \"NXcrystal\"\n", " @target = \"/entry/instrument/crystal\"\n", " wavelength --> /entry/instrument/bluesky/metadata/mono_wavelength\n", " detector:NXdetector\n", " @NX_class = \"NXdetector\"\n", " @target = \"/entry/instrument/detector\"\n", " data --> /entry/instrument/bluesky/streams/primary/sensor/value\n", " polar_angle --> /entry/instrument/bluesky/streams/primary/tth/value\n", " detectors:NXnote\n", " @NX_class = \"NXnote\"\n", " @target = \"/entry/instrument/detectors\"\n", " I0:NXdetector\n", " @NX_class = \"NXdetector\"\n", " @target = \"/entry/instrument/detectors/I0\"\n", " data --> /entry/instrument/bluesky/streams/primary/I0\n", " sensor:NXdetector\n", " @NX_class = \"NXdetector\"\n", " @target = \"/entry/instrument/detectors/sensor\"\n", " data --> /entry/instrument/bluesky/streams/primary/sensor\n", " positioners:NXnote\n", " @NX_class = \"NXnote\"\n", " @target = \"/entry/instrument/positioners\"\n", " th:NXpositioner\n", " @NX_class = \"NXpositioner\"\n", " @target = \"/entry/instrument/positioners/th\"\n", " value --> /entry/instrument/bluesky/streams/primary/th\n", " tth:NXpositioner\n", " @NX_class = \"NXpositioner\"\n", " @target = \"/entry/instrument/positioners/tth\"\n", " value --> /entry/instrument/bluesky/streams/primary/tth\n", " source:NXsource\n", " @NX_class = \"NXsource\"\n", " @target = \"/entry/instrument/source\"\n", " name:NX_CHAR = b'Bluesky framework'\n", " @short_name = \"bluesky\"\n", " probe:NX_CHAR = b'x-ray'\n", " type:NX_CHAR = b'Synchrotron X-ray Source'\n", " monitor:NXmonitor\n", " @NX_class = \"NXmonitor\"\n", " @signal = \"integral\"\n", " @target = \"/entry/monitor\"\n", " integral --> /entry/instrument/bluesky/streams/primary/I0/value\n", " mode:NX_CHAR = b'monitor'\n", " @target = \"/entry/monitor/mode\"\n", " preset:NX_INT64 = 100000\n", " @target = \"/entry/monitor/preset\"\n", " monopd:NXdata\n", " @NX_class = \"NXdata\"\n", " @axes = [\"polar_angle\"]\n", " @signal = \"data\"\n", " @target = \"/entry/monopd\"\n", " data --> /entry/instrument/bluesky/streams/primary/sensor/value\n", " polar_angle --> /entry/instrument/bluesky/streams/primary/tth/value\n", " sample:NXsample\n", " @NX_class = \"NXsample\"\n", " @target = \"/entry/sample\"\n", " name --> /entry/instrument/bluesky/metadata/sample_name\n", " rotation_angle:NX_INT64 = 0\n", " @target = \"/entry/sample/rotation_angle\"\n", "\n" ] } ], "source": [ "from apstools.utils import unix\n", "\n", "for line in unix(f\"punx tree {nxwriter.file_name}\"):\n", " print(line.decode().strip())" ] } ], "metadata": { "kernelspec": { "display_name": "base", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.6" } }, "nbformat": 4, "nbformat_minor": 2 }