From 779d8dc518cf09ce1ff6fd624e571469c7369c8e Mon Sep 17 00:00:00 2001 From: K Lauer Date: Fri, 19 Oct 2018 09:40:32 -0700 Subject: [PATCH 01/10] CLN: device_type -> Device map --- jet_tracking/devices.py | 65 +++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/jet_tracking/devices.py b/jet_tracking/devices.py index 81528c8..903c79e 100644 --- a/jet_tracking/devices.py +++ b/jet_tracking/devices.py @@ -596,41 +596,44 @@ def __init__(self, name, class SDS: - '''Sample delivery system - - Parameters - ---------- - devices : dict - A dictionary of dictionaries containing the devices to be made and their PV names - Key: str - Type of device to be made. Valid keys are 'selector', 'cooler_shaker', 'hplc', - 'pressure_controller', and 'flow_integrator' - Value: str dict - Dictionary of PVs of the device + ''' + Sample delivery system - Attributes - ---------- - SDS_devices : list - List containing all the devices that are in the sample delivery system - ''' + Parameters + ---------- + devices : dict + A dictionary of dictionaries containing the devices to be made and their PV names + Key: str + Type of device to be made. Valid keys are 'selector', 'cooler_shaker', 'hplc', + 'pressure_controller', and 'flow_integrator' + Value: str dict + Dictionary of PVs of the device - SDS_devices = [] + Attributes + ---------- + SDS_devices : list + List containing all the devices that are in the sample delivery system + ''' + + device_types = { + 'selector': Selector, + 'cooler_shaker': CoolerShaker, + 'hplc': HPLC, + 'pressure_controller': PressureController, + 'flow_integrator': FlowIntegrator, + } def __init__(self, devices): - - for device in devices: - if device == 'selector': - self.SDS_devices.append(Selector(**devices[device])) - elif device == 'cooler_shaker': - self.SDS_devices.append(CoolerShaker(**devices[device])) - elif device == 'hplc': - self.SDS_devices.append(HPLC(**devices[device])) - elif device == 'pressure_controller': - self.SDS_devices.append(PressureController(**devices[device])) - elif device == 'flow_integrator': - self.SDS_devices.append(FlowIntegrator(**devices[device])) - else: - print(f'{device} is not a valid device') + self.SDS_devices = [ + self.device_types[dev](**kwargs) + for dev, kwargs in devices.items() + if dev in self.device_types + ] + + invalid_devices = [dev for dev in devices + if dev not in self.device_types] + for device in invalid_devices: + print(f'WARNING: {device} is not a valid device type') class Offaxis(PCDSDetector): From d1acfa812baa17899485c416225bb8315f959f48 Mon Sep 17 00:00:00 2001 From: K Lauer Date: Fri, 19 Oct 2018 09:44:49 -0700 Subject: [PATCH 02/10] MNT: do not access EpicsSignal._read_pv --- jet_tracking/devices.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/jet_tracking/devices.py b/jet_tracking/devices.py index 903c79e..6d9e04e 100644 --- a/jet_tracking/devices.py +++ b/jet_tracking/devices.py @@ -1,4 +1,5 @@ import pandas as pd +import epics from ophyd.device import Device, FormattedComponent as FCpt, Component as Cpt from ophyd.signal import EpicsSignal @@ -19,7 +20,7 @@ def __init__(self, *args, **kwargs): def _update_descriptions(self): adesc = {} for name, signal in self._signals.items(): - adesc[name] = EpicsSignal(signal._read_pv.pvname + '.DESC').get() + adesc[name] = epics.caget(signal.pvname + '.DESC') self._descriptions = adesc @property @@ -33,8 +34,8 @@ def table(self): atable = {} for name, signal in sorted(self._signals.items()): atable[name] = { - 'value': signal._read_pv.value, - 'units': signal._read_pv.units, + 'value': signal.read()[signal.name]['value'], + 'units': signal.describe()[signal.name].get('units', ''), 'desc': self._descriptions.get(name), } From 3d89c8298ae4d631b6708cb67f10be3b5d192c63 Mon Sep 17 00:00:00 2001 From: K Lauer Date: Fri, 19 Oct 2018 11:25:50 -0700 Subject: [PATCH 03/10] FIX: bad format string in set_max_pressure --- jet_tracking/devices.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jet_tracking/devices.py b/jet_tracking/devices.py index 6d9e04e..a5d4de3 100644 --- a/jet_tracking/devices.py +++ b/jet_tracking/devices.py @@ -319,7 +319,7 @@ class HPLC(Device, _TableMixin): pressure = FCpt(EpicsSignal, '{self._pressure}') pressure_units = FCpt(EpicsSignal, '{self._pressure_units}') - set_max_pressure = FCpt(EpicsSignal, '{self._set_max_pressure') + set_max_pressure = FCpt(EpicsSignal, '{self._set_max_pressure}') max_pressure = FCpt(EpicsSignal, '{self._max_pressure}') clear_error = FCpt(EpicsSignal, '{self._clear_error}') From eef638e0be69172d3b75a61a98e5406a6dee47b9 Mon Sep 17 00:00:00 2001 From: K Lauer Date: Fri, 19 Oct 2018 15:17:56 -0700 Subject: [PATCH 04/10] MNT: missing colon on ROI-related plugins --- jet_tracking/devices.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/jet_tracking/devices.py b/jet_tracking/devices.py index a5d4de3..325a442 100644 --- a/jet_tracking/devices.py +++ b/jet_tracking/devices.py @@ -657,9 +657,9 @@ class Offaxis(PCDSDetector): Stats on ROI of original rate image ''' - ROI = FCpt(ROIPlugin, '{self.prefix}:{self._ROI_port}') - ROI_stats = FCpt(StatsPlugin, '{self.prefix}:{self._ROI_stats_port}') - ROI_image = FCpt(ImagePlugin, '{self.prefix}:{self._ROI_image_port}') + ROI = FCpt(ROIPlugin, '{self.prefix}:{self._ROI_port}:') + ROI_stats = FCpt(StatsPlugin, '{self.prefix}:{self._ROI_stats_port}:') + ROI_image = FCpt(ImagePlugin, '{self.prefix}:{self._ROI_image_port}:') def __init__(self, ROI_port, ROI_stats_port, @@ -699,9 +699,9 @@ class Questar(PCDSDetector): Stats on ROI of original rate image ''' - ROI = FCpt(ROIPlugin, '{self.prefix}:{self._ROI_port}') - ROI_stats = FCpt(StatsPlugin, '{self.prefix}:{self._ROI_stats_port}') - ROI_image = FCpt(ImagePlugin, '{self.prefix}:{self._ROI_image_port}') + ROI = FCpt(ROIPlugin, '{self.prefix}:{self._ROI_port}:') + ROI_stats = FCpt(StatsPlugin, '{self.prefix}:{self._ROI_stats_port}:') + ROI_image = FCpt(ImagePlugin, '{self.prefix}:{self._ROI_image_port}:') def __init__(self, ROI_port, ROI_stats_port, From 7ae21ea0bf3162a25ef51187e14069066340269f Mon Sep 17 00:00:00 2001 From: K Lauer Date: Fri, 19 Oct 2018 15:47:56 -0700 Subject: [PATCH 05/10] MNT: update device_load with latest hutch conf TODO: eventually, this should be removed from the repo --- jet_tracking/devices_load.py | 66 +++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/jet_tracking/devices_load.py b/jet_tracking/devices_load.py index 8f39d8f..a1f75f7 100644 --- a/jet_tracking/devices_load.py +++ b/jet_tracking/devices_load.py @@ -1,5 +1,7 @@ from hutch_python.utils import safe_load -from .devices import Injector, Questar, Parameters +from .devices import Injector, Questar, Parameters, Offaxis, Diffract +from .jet_control import JetControl + """ Load liquid and Questar camera devices for jet tracking processing @@ -15,6 +17,24 @@ 'fineZ': 'CXI:USR:MMS:03'} PI1_injector = Injector(**PI1) +with safe_load('SC1_questar'): + SC1_questar_ports = {'ROI_port': 'ROI1', + 'ROI_stats_port': 'Stats1', + 'ROI_image_port': 'IMAGE1'} + SC1_questar = Questar(**SC1_questar_ports, prefix='CXI:SC1:INLINE', + name='SC1_questar') + +with safe_load('SC1_params'): + SC1_params = Parameters(prefix='CXI:SC1:INLINE', name='SC1_params') + +with safe_load('SC1_diffract'): + SC1_diffract = Diffract(prefix='CXI:SC1:DIFFRACT', name='SC1_diffract') + +with safe_load('SC1_control'): + SC1_control = JetControl('SC1_control', PI1_injector, SC1_questar, + SC1_params, SC1_diffract) + + with safe_load('PI2_injector'): PI2 = {'name': 'PI2_injector', 'coarseX': 'CXI:PI2:MMS:01', @@ -25,6 +45,32 @@ 'fineZ': 'CXI:PI2:MMS:06'} PI2_injector = Injector(**PI2) +with safe_load('SC2_questar'): + SC2_questar_ports = {'ROI_port': 'ROI1', + 'ROI_stats_port': 'Stats1', + 'ROI_image_port': 'IMAGE1'} + SC2_questar = Questar(**SC2_questar_ports, prefix='CXI:SC2:INLINE', name='SC2_questar') + +with safe_load('SC2_offaxis'): + SC2_offaxis_ports = {'ROI_port': 'ROI1', + 'ROI_stats_port': 'Stats1', + 'ROI_image_port': 'IMAGE1'} + SC2_offaxis = Offaxis(**SC2_offaxis_ports, prefix='CXI:GIGE:06', name='SC2_offaxis') + +with safe_load('SC2_params'): + SC2_params = Parameters(prefix='CXI:SC2:INLINE', name='SC2_params') + +with safe_load('SC2_paroffaxis'): + SC2_paroffaxis = OffaxisParams(prefix='CXI:SC2:OFFAXIS', name='SC2_paroffaxis') + +with safe_load('SC2_diffract'): + SC2_diffract = Diffract(prefix='CXI:SC2:DIFFRACT', name='SC2_diffract') + +with safe_load('SC2_control'): + SC2_control = JetControl('SC2_control', + PI2_injector, SC2_questar, SC2_params, SC2_diffract) + + with safe_load('PI3_injector'): PI3 = {'name': 'PI3_injector', 'coarseX': 'CXI:PI3:MMS:01', @@ -34,21 +80,3 @@ 'fineY': 'CXI:PI3:MMS:05', 'fineZ': 'CXI:PI3:MMS:06'} PI3_injector = Injector(**PI3) - -with safe_load('SC1_questar'): - SC1_questar_ports = {'ROI_port': 'ROI1', - 'ROI_stats_port': 'Stats1', - 'ROI_image_port': 'IMAGE1'} - SC1_questar = Questar(**SC1_questar_ports, prefix='CXI:SC1:INLINE', name='SC1_questar') - -with safe_load('SC2_questar'): - SC2_questar_ports = {'ROI_port': 'ROI1', - 'ROI_stats_port': 'Stats1', - 'ROI_image_port': 'IMAGE1'} - SC2_questar = Questar(**SC2_questar_ports, prefix='CXI:SC2:INLINE', name='SC2_questar') - -with safe_load('SC1_params'): - SC1_params = Parameters(prefix='CXI:SC1:ONAXIS', name='SC1_params') - -with safe_load('SC2_params'): - SC2_params = Parameters(prefix='CXI:SC2:ONAXIS', name='SC2_params') From 8d726c57d28c1b13ee2cb0f40b92d3ba35ebe8ab Mon Sep 17 00:00:00 2001 From: K Lauer Date: Mon, 22 Oct 2018 09:57:12 -0700 Subject: [PATCH 06/10] DOC: support newer versions of matplotlib --- docs/source/conf.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 7e8e0b7..cb958a6 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -22,12 +22,14 @@ import sphinx_rtd_theme import datetime import matplotlib +matplotlib.use('Agg') module_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),'../../') sys.path.insert(0,module_path) + # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. @@ -44,7 +46,6 @@ 'IPython.sphinxext.ipython_directive', 'IPython.sphinxext.ipython_console_highlighting', 'matplotlib.sphinxext.mathmpl', - 'matplotlib.sphinxext.only_directives', 'matplotlib.sphinxext.plot_directive', # 'sphinx.ext.autosectionlabel' 'sphinx.ext.viewcode', @@ -55,6 +56,14 @@ 'sphinx.ext.mathjax', ] +try: + import matplotlib.sphinxext.only_directives +except ImportError: + ... +else: + extensions.append('matplotlib.sphinxext.only_directives') + + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] From e301ce9b35de25b200bc9f32ff89216ce50a8725 Mon Sep 17 00:00:00 2001 From: K Lauer Date: Mon, 22 Oct 2018 09:57:37 -0700 Subject: [PATCH 07/10] DOC: point docs to appropriate package location --- docs/source/control.rst | 4 +--- docs/source/devices.rst | 13 ++++++------- docs/source/sample_delivery.rst | 12 ++++++------ docs/source/shared_memory.rst | 9 ++------- 4 files changed, 15 insertions(+), 23 deletions(-) diff --git a/docs/source/control.rst b/docs/source/control.rst index a40bc9a..bd5ddc4 100644 --- a/docs/source/control.rst +++ b/docs/source/control.rst @@ -3,7 +3,7 @@ Jet Control Overview #################### -.. currentmodule:: jet_control +.. currentmodule:: jet_tracking.jet_control To start ipython for cxi hutch-python3. @@ -38,5 +38,3 @@ Attributes JetControl.calibrate JetControl.jet_calculate JetControl.jet_move - - diff --git a/docs/source/devices.rst b/docs/source/devices.rst index 23fe5b8..eb1afcd 100644 --- a/docs/source/devices.rst +++ b/docs/source/devices.rst @@ -1,6 +1,6 @@ .. _devices: -.. currentmodule:: jet_control +.. currentmodule:: jet_tracking.jet_control Jet Tracking Classes #################### @@ -9,7 +9,7 @@ Base classes used in jet tracking and control. JetControl Class ---------------- -.. autoclass:: jet_control.JetControl +.. autoclass:: JetControl .. autosummary:: :toctree: generated/ @@ -23,20 +23,19 @@ JetControl Class Injector Class -------------- -.. autoclass:: devices.Injector +.. autoclass:: jet_tracking.devices.Injector Questar Class ------------- -.. autoclass:: devices.Questar +.. autoclass:: jet_tracking.devices.Questar Parameters Class ---------------- -.. autoclass:: devices.Parameters +.. autoclass:: jet_tracking.devices.Parameters Diffract Class -------------- -.. autoclass:: devices.Diffract - +.. autoclass:: jet_tracking.devices.Diffract diff --git a/docs/source/sample_delivery.rst b/docs/source/sample_delivery.rst index 149fd69..9575677 100644 --- a/docs/source/sample_delivery.rst +++ b/docs/source/sample_delivery.rst @@ -27,37 +27,37 @@ API Sample Delivery System Class ---------------------------- -.. autoclass:: devices.SDS +.. autoclass:: jet_tracking.devices.SDS Selector Class -------------- -.. autoclass:: devices.Selector +.. autoclass:: jet_tracking.devices.Selector CoolerShaker Class ------------------ -.. autoclass:: devices.CoolerShaker +.. autoclass:: jet_tracking.devices.CoolerShaker HPLC Class ---------- -.. autoclass:: devices.HPLC +.. autoclass:: jet_tracking.devices.HPLC PressureController Class ------------------------ -.. autoclass:: devices.PressureController +.. autoclass:: jet_tracking.devices.PressureController FlowInegrator Class ------------------- -.. autoclass:: devices.FlowIntegrator +.. autoclass:: jet_tracking.devices.FlowIntegrator diff --git a/docs/source/shared_memory.rst b/docs/source/shared_memory.rst index 0c39170..750a19d 100644 --- a/docs/source/shared_memory.rst +++ b/docs/source/shared_memory.rst @@ -1,6 +1,6 @@ .. _shared_memory: -.. currentmodule:: psana2epics +.. currentmodule:: jet_tracking.psana Jet Tracking Shared Memory Application ###################################### @@ -62,9 +62,4 @@ API :nosignatures: :toctree: generated/ - psana2epics.output_cspad_sum - - - - - + output_cspad_sum From 5a7a9360ac3e1e506f9bd33a6816d9088c19aa68 Mon Sep 17 00:00:00 2001 From: K Lauer Date: Mon, 22 Oct 2018 09:59:01 -0700 Subject: [PATCH 08/10] MNT: easier access to submodules --- jet_tracking/__init__.py | 8 ++++++++ jet_tracking/psana/__init__.py | 1 + jet_tracking/psana/psana2epics.py | 1 - 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/jet_tracking/__init__.py b/jet_tracking/__init__.py index e44e9d1..c5d8e1f 100644 --- a/jet_tracking/__init__.py +++ b/jet_tracking/__init__.py @@ -1,3 +1,11 @@ from ._version import get_versions __version__ = get_versions()['version'] del get_versions + + +from . import jet_control # noqa +from . import devices # noqa +from . import cam_utils # noqa +from . import jet_tracking # noqa +from . import move_motor # noqa +from . import signal_config # noqa diff --git a/jet_tracking/psana/__init__.py b/jet_tracking/psana/__init__.py index e69de29..df15f9d 100644 --- a/jet_tracking/psana/__init__.py +++ b/jet_tracking/psana/__init__.py @@ -0,0 +1 @@ +from .psana2epics import * # noqa diff --git a/jet_tracking/psana/psana2epics.py b/jet_tracking/psana/psana2epics.py index 13a7444..9050d9e 100644 --- a/jet_tracking/psana/psana2epics.py +++ b/jet_tracking/psana/psana2epics.py @@ -362,4 +362,3 @@ def streak_angle_raw(self): calc_period=args.calc_period, calc_streak=args.calc_streak, nevents=args.nevents, plot=args.plot)) - From 4b0f8d17fd0badfc26dae64adaa49f2058f9194f Mon Sep 17 00:00:00 2001 From: K Lauer Date: Mon, 22 Oct 2018 09:59:40 -0700 Subject: [PATCH 09/10] DOC: tweak docstring to avoid sphinx warning --- jet_tracking/devices.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/jet_tracking/devices.py b/jet_tracking/devices.py index 325a442..4d9c027 100644 --- a/jet_tracking/devices.py +++ b/jet_tracking/devices.py @@ -603,12 +603,13 @@ class SDS: Parameters ---------- devices : dict - A dictionary of dictionaries containing the devices to be made and their PV names - Key: str - Type of device to be made. Valid keys are 'selector', 'cooler_shaker', 'hplc', - 'pressure_controller', and 'flow_integrator' - Value: str dict - Dictionary of PVs of the device + A dictionary of dictionaries containing the devices to be made and + their PV names. The dictionary key is a string, one of the following: + {'selector', 'cooler_shaker', 'hplc', 'pressure_controller', + 'flow_integrator'} + The values of the dictionary, are also dictionaries. These are passed + to the new device, allowing parameters such as PV names to be + specified. Attributes ---------- From 514469e729b2bbfeb7a8735ff00ac359ce85692a Mon Sep 17 00:00:00 2001 From: K Lauer Date: Mon, 22 Oct 2018 10:21:49 -0700 Subject: [PATCH 10/10] CI: auto build/deploy docs with doctr --- .travis.yml | 2 ++ github_deploy_key_pcdshub_jet_tracking.enc | 1 + 2 files changed, 3 insertions(+) create mode 100644 github_deploy_key_pcdshub_jet_tracking.enc diff --git a/.travis.yml b/.travis.yml index 2a927a5..c3978b9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,8 @@ sudo: false env: global: - OFFICIAL_REPO="pcdshub/jet_tracking" + # Doctr deploy key for pcdshub/jet_tracking + - secure: "vUuAt00AjoyYdCEfrqDiYEBN/0j5Rg0YF4er9fwbtgzlb/q9eHjyEI1XZm+WrTZE1k6U3RHM4SLct7FWMYVMrJ5nDehZF2iaFbDMjSBbANe3+zj7iaBZsLRDh9tivALv1pqavtVivZ98ypiX/GGwvGgtruOeFAsYdCAabPpsRHzsMZzWYr5vkm+ylUtncsJBRuqaHEczf3NMIL7TdO5B3Qwsws1ohgMQfedby2DI4cgZ8jLcJ5ZVnfS0gshy1RNpWc+lY0xb6/dIHW2V6Ca+YAl6VcN8uiF6RD4XgaDvzoZTfwWI5BcvgBULS1w1/aUzSWAWYARVEwA0v/QJ/ftFmx602a9yvFWje67TEPuCYR0uDU/osDYywnkEZNVZuv5CGO8KncBi12zBUGRW+aPpr+59cUOpQhkoRfJAFXRBwsCrKrXSYubNv1K64S+C6SkuPOIdGJdurh7naMPK4S3yUQmJ4I/samGq5MCy560YcKqj7KtDiRwgqXa5ho6meoaFKBCsfFpcF8flcygsSTCIa0WaKm4s79HcbiqJEO/CwZvWAjpz2DDuxApebM2uRWBa5S0AyY9vCQMAojyP67wd6z/RoZenDMl3Vrc197+RRbbujvpI/XkTS1SOV/9K2/+lX+Tj0Xv5XImiBTIdq8LPo2QgyMna7H7HmJ1uDeqXlGM=" matrix: include: diff --git a/github_deploy_key_pcdshub_jet_tracking.enc b/github_deploy_key_pcdshub_jet_tracking.enc new file mode 100644 index 0000000..f78ba70 --- /dev/null +++ b/github_deploy_key_pcdshub_jet_tracking.enc @@ -0,0 +1 @@ +gAAAAABbzgZ0wRAYI2ZyFtnTpQf5GWFW19Z2gPS8Nwlxg_NQAvnnxG_6sbNGmXv7tsP6TgHTIE3OEInJtV-M6n7BCjfXIpfhPWmrlaRiNxZMpKr5KXNLZFtYsfT2kL1_e1X_h8yIo7u8kEMSD-Fp2ndpEEEJM5tL7BEyweYJ_mp7C8dVFpiW7BZhQ5MiYMw5bevqXdbVXmNYavfJRoytnQq4I0sxCH7M8t7Fsbf87MKTohUh0QJzljvBVB37EyK4fcE-tfZ5jlkcwwgyElrJzrmYfXSArDsWHZ8sM0BFSVXd9dkLcuqstPcRMJFEFQcMfq7esbSPlJeq0put_DsWkGKGlAIqfJ-3LuQu6cKKJZ3NWRrYLna1Oe8TnBotM0dVv8W8JSIixDMzYf_cR9oP8r-AanTLwxAd2u-YzWnSAkHpGgc2TOW40OqIr6ovWnGttu31vvEvhXbY69TfumAr0qknLJZf5aHIVWGmvLMa8pUQfAB967ESYXO-4Uj4k2gc2FouKe7Sh6tmHVq1qxqSlIJCcGIs3IEIaAxdWjDhOqukE-yO-ol1WXVLNcGjvc5H6uwpvuORs3K-0cYQyHLpGG_uM9RUNf2lUz57ri9GYWSU68rqvqQYpBFFcf6PR330yQT5_-B1swa-DljlaCZafGAVOuUa5MZgyij6p8VTJBiyJ7NhExVe2Ux8p25dL5KpUQL4qeyaOQEyZvvvKPusbky-QUfMzsHFN1E8nGhXlEe8pdb7TaM_3xxySHOFsc7-VNXDB_kJYnYsRa5PoQjN-uOD5rl5KZN4gKR7plmg66d20bKlIuwcsi8bC4mANHh0l67qA_VMpq1adEATy6ghSdGg44O8uAYJxFww7mp-4bTrE0aEtU8DE-_ilBU7DmZ6ijGNgpF8vm4xwq606cy27WNQ5hf0C6crF0FIriTUaHslSIyUnDC4dpT0fTnvLbZvBqOL_Z3HonMDZN2fVEqzoEB-IEg0kJx2p1bUadyr38qUQiVyMDZEFeZOlGInEEvLHmhjhYeIhBH6Cmg4x_M7VGdDhhqssGQyyoO9bUF_OMiz4j208s-1AM__hApQvbd70r5ykzhQuGs5WHriogsfCQfOwtg3cLFMUikb41iMPMF1vtQvJVXJUJqsIYdxW-oAAOpUC-BJ4L21tpqczjJCXve8J78qEcbx-l__y0FaVYIyfL76jAv6A5J-UaA0AusHL0WH6siXeMcepzj-I9ZX4rpVfvbvqfg6zr78JhK_drSJOAdt-z939OrM9Ngbf4OprVOg2D5K3xYv3UL58OfqEk-_K8FKAz_t5GVX8uhQKh6BCYr0vouNKFX6R5qFUkjuM3F9m3MU0faxX47E_TPZjQpbng6eHw9LwvfmFLFUKoY6n1eyl4yydaj5_XPisBN27W73CWWyOo2zGiKytmlLKvwBlW03FnUixyHE_M3bDv5JwoewQrnBwno7Jt8dK_JmVwUTVMEuqf8I02F_um-gWH1Bd5YXgOKN18-mbSbK7pUdoeSQAKlxKzGqssNvqliI4MFytp1wyXnv6rz_l1DYxUrWne5m-5tibFuBl7rZI_WCtQDW_rqg5WcR4QtEjAU3gRo5SwLDQr8N12ESdJZuWNUji_ia0oIqqn4-eGJ0E9HioEiCNzjULKU9NmeS3pe1eeMC_1Ttp0eAw3EUZE8xzr7CZvz0s5KRS87HtpGRqF8dPWvCl3ah_JCjEuYrswrbTGYueOV7vnnz9yadVoIqZIi_yv177hrRgQ7l0MzxsT7FU4LjGfw6c46K4Nwi2YQyVTdLNXNt5wIMKvPQLkjr1NFySjj3xVjjlJ8-72DEONsIIT339i475X71ZPeHqFo2KDhvIH2MpsgxLKTB_O6rpQNft9vFZoVzXfNIXgyK34R1uo7mELSxjz-y61YisMAAVP4WxTGF0ZjnOxDaimzwARYpVyNxs1sxoiA6k3CGzU4cDZ5m6xThX9ImM9F9j1D-mzKZw99rWGWVHVhhZa2YWEQU8UPTOAdDio_HlQjtvBdvnwe2MLw1dKgQ0uZP1Z61OyVUFGZg7BJYTDnnmeqgcpDy6Ob4fD01Fw1rMUaWqxiWhpW_RHX_iwtW3s0ihjnELt5AIpjeF_WaRhZ60cW_mX3PIlmdG9r4Z8ZTfml56RhaPBFu9oSgwoaBppx2YZMxHDOq-Jq-Y5EGOCsJKmNN7vqzLRFM6CpcgzJ-QO_4xEWfhlmgqCmshke8Qq2lCVIAv-7y9w3UeEkDotq3XoCNAm-7G76zBp4pSe75E2sd_lsthWUYHcX_kW6He0PE78p7hjLQX4Msh4N_AW5Yv4yqrCM_PXqizPBRqbdIWPA1oIurNEW0XARRIu-TgLyFilu0HaKawHWQPKQKZCcCbLWyRhSeaLYgMkFQNaNUBXt6pOkhog6MHkBsUrSBtOIzG9aL5e8Z8P3KTz8wTUaiNAcbmEkR3fUZV-Fcz0qXtYxGTls6S1UBKUzDF7W6nVx5wR6hKOv0s6zq0R8Tk6J6kAIzOjY4ptQyWjGwi4CcnwzTa-lP2gi3BtlnetfTbJ_CVjEC4qkvlr9bc_DnHWkZYFzU_af5_tDeBb_-XCM3NKhCpYbymLTJXi7frJov0p0ElZ0JhQHSaZkqe0qKwyDiVZAEIK8sXA1a5SYYJfqRVUW-CyxWxC2gb-mpzLqVmwxryeI14NlD2qOKhQk0aUJuA9HtmAPJnoZ490TdLtv7n0uALlIEw1m3piA7dKoBhk_2V7bQGMvSbRvqPq0T5eeX8Q6n4zP2vV7GRDc2WPpEocRvd0RgB02ggQa_0yP8Z9MCXL96hfNC20tvmzDpxYkwhexu5tjN5qwaaMBMLXdSx9OheKW5E9iqdqAQ95Ue63CYSOdN1gyfp1Ily6wIvdyHqgoWCIi-zHLYefzZnrkF9tv7MeeyXy0ecv1XMCROr6_rBVXHZbZSQjQJJhc-sam3mHjDrTLOSqW7mHWih4HCv500Zc5x37BYUtNEbgpyRkQiMpN071OKWB4U4X6f3cnvKE-SMxFmaLs6vaFlGb5D2hfNWYS6DRAsyB6p0SP7GQooiYpxjYyo5ZM6TrdDYp0ObqbTk7Yel0WjUzJ8K57MtZaOoL7kYC_FD3k1VivjnZeVBNvNnLaOZWY_S6usnrPlr_r_GcTWeLcr9mof5tPdhZC7faWFEHBWFwfZ4bf5pigKHlYqL-ys2qdLBLsVggRGJEvnHwBL0dDLNIvEBRCT2bgTSwyp5NNb2RH0vcLWiWZV1K2O356O5YgqW1ihqQvWvgh3Edpiu9XDHaz6ReK0p8eSmaUZxfCYMpYgXo-7dl21E-_sL2lnokayWWuL88Vv0TBry8gKXTsv4ONacfgpPzLXcs8J5FoI2MTF85sgzABlclHmsuT1QF2Iabl-Ae7gVUYm9KAwxV7Ld46cnWGomEgOd1eNuG4INN9mXf_vE2WxpySPuhqzx5IMxsc6JOxXIUjZwqouPCdYqSDJ6rERWDc5QpnA4cGsG52UqHY5oU_TJfPnbM7grdsS2L0E_wBmdjW7qwgIDxg7-a-eyYFaQsi7Ub1g5gVD6Nx3K28_8yMD5CLQDOwtM3HrUTr7mHQcC-jxZswbUPV6KsrLFUvC-rIpCRRFFNF1Mz9VA7tkbM5u9HOX5wulJ5JYGN684pwIoaADxxQ1OvzWFivPoz_a04wiKa1V3n-wQcptWxMsozI_xwSbvHAs5FMWskddagjRzDb-VWc5nsCRsQPIuKMwCuYL9Aq0o-RKgIOqCsEHimB4XwmVsmRQV2BaTwlTKgiy7w5Hez8irNPB6pAJ7_vSyEXSsmcw7eEJeZQrZU1AoOem97olig4hCwKW6rFyipD349JdpBgjJK9WMLEv-b_7Hxhtt1CPJjeebrNBAkNyVGDSFPzpriw4kAhRDSIO9ItIn01te3BoUg215nbbxfP1bc7JP9aqWJo_NtF0znG5zp2Zgl1O24Nwd78p_2AnjVY0MEKJlvsbQBImLaG4WMvNeDtYxymenmVQCvTiFs_Nd11Z_fTNRjcFNSF5hulFPqx_rMPcDsZt0Lv0ms88uSwlAEhZ7cMCCVGvZykVwZ5c016uhP31xWDG2vxUo_6qNloGzlVyM0F4BbZ1hPmh7Otke92IltuGwBaLz43IaYceaiNQC_CzLZewr1VQmCifuiXCj2fBBf6pfe9sAxwWPWPUxVXkAd2JxtTSXV9CW-8sFymBbpXb9TUOCHlKjIhCrug3eEPNHbuySvsxEVvl9j3KjM2fqUl9HJE9isa0flTjWwgcn_jqh8StrcEh9i715VYRnQepffrC_iyXaIT-RKKFaCAtIjLkbnIWWqoHvMSUNexrYvzFHatAHDC-b-PiQKsnSUNXum2TtIOYyA2am-GsrDL1bMCbBWZZQbJvB6NvTFSFxcC_lIOvkQbr3lcomAM0XynwD4t-ncHEutnFow== \ No newline at end of file