Controller Architecture
fastcs-odin provides a set of controller classes that map an odin-control server’s
REST API onto FastCS attributes and commands. This page explains each class and how
they relate to one another.
OdinController
OdinController is the root FastCS Controller for an odin-control server. It is the starting point for
any driver that communicates with odin-control.
On initialise it:
Opens an HTTP connection to the server.
Queries api/0.1/adapters to discover registered adapters.
Fetches the full parameter tree for each adapter with metadata headers to determine
the adapter’s module type.
Dispatches to the correct sub-controller class based on the module type:
Odin Controllers
OdinSubController
OdinSubController is a common base class for sub-controllers. It holds:
The shared HTTPConnection .
The list[OdinParameter] assigned to this node in the parameter tree.
The api_prefix string that identifies this node’s URL.
It exposes two protected helpers that subclasses call from their own initialise :
_create_attributes()
Iterates self.parameters and registers a FastCS Attribute for each one. Attributes
are backed by ParameterTreeAttributeIO , which reads and writes via the REST API using
the parameter’s URI.
_create_commands(path=())
GETs <api_prefix>/command[/<path>]/allowed , parses the response, and for each
allowed command name dynamically attaches a FastCS Command to the controller. The
command PUTs to .../execute when invoked. This means detector-specific commands
exposed through odin-control appear automatically without any extra code.
OdinAdapterController
OdinAdapterController is a thin convenience wrapper around OdinSubController . Its entire initialise
is:
async def initialise ( self ):
await self . _create_attributes ()
await self . _create_commands ()
It is the default used by OdinController for any adapter whose module type is not
recognised. For a simple adapter with no special tree structure it is all that is
needed, and it is a good starting point for a custom adapter controller.
odin-data Controllers
These controllers are provided to connect to common odin-data applications; the
frame receiver, frame processor and meta writer.
OdinDataAdapterController
OdinDataAdapterController is a FastCS ControllerVector that manages a numbered set
of identical child controllers — one per running odin-data process (frameReceiver or
frameProcessor application).
On initialise it:
Partitions self.parameters by leading numeric index in the URI
(0/status/... , 1/status/... , …).
Creates one _subcontroller_cls instance per index, scoped to
<api_prefix>/<idx> .
Keeps parameters without a numeric prefix at the adapter level and creates
attributes for them directly.
Calls _create_config_fan_attributes() to build fan-out write attributes at
the adapter level. Any config parameter that appears in every child controller and
is not listed in _unique_config gets a top-level attribute whose write
propagates to all child controllers simultaneously.
Subclasses set three class variables to specialise behaviour:
FrameReceiverAdapterController / FrameReceiverController
Merges the decoder and decoder_config sub-trees under a single decoder group
before calling add_attribute .
FrameProcessorAdapterController / FrameProcessorController
Declares class-level summary attributes backed by StatusSummaryAttributeIORef that
aggregate values across all FP instances — frames_written (sum) and writing (any ).
Top-level start_writing and stop_writing commands fan out to the HDF plugin of every
child controller.
Queries status/plugins/names to discover loaded plugins and creates a
FrameProcessorPluginController sub-controller for each one. Each plugin controller
calls _create_commands([plugin_name]) to auto-discover commands.
Building a Detector-Specific Driver
The classes above are designed to be combined or extended for a particular detector.
The diagram below gives an overview: fastcs-odin (right) provides the base
classes; a detector package (left, with fastcs-detector as an example) inherits
from or composes them. The centre column shows a concrete OdinController at runtime
with the sub-controllers it creates, colour-matched to the base classes on the right.
eyJ2ZXJzaW9uIjoiMSIsImVuY29kaW5nIjoiYnN0cmluZyIsImNvbXByZXNzZWQiOnRydWUsImVuY29kZWQiOiJ4nO1dWVdcIluyfj+/olb1a5u956HfcJ5QXHUwMDE0XHUwMDEw9Z67XFwggyhcdTAwMDIyy139329cdTAwMDRVSkLuhFx1MDAwNFLFLqh1hlx1MDAwMkxziPjii/n//vrx42fntVn6+e9cdTAwMWY/S4P7fK1abOX7P/+J7/dKrXa1UYeP2Ojv7Ua3dT/65kOn02z/+1//yjeb3vinvPvG86+fLNVKz6V6p1xy3/1cdTAwMWb4+49cdTAwMWb/N/o3fFIt4s8/Pj095Su3e4Nkvdk3+vGQn16nRj86+tLbXHS1SvedfL1SK40/XHUwMDFh4NkwSzzKqKHSMmO45u9cdTAwMWa/wseCKU9cdTAwMWGrODeCK8KkeP+4Xy12XHUwMDFl8Fxiknhcbl5GXHUwMDEzSjU1Wr5/5aFUrTx04DuUWY/DS3BJpJGWm/fv/Dqnf/8g7++0O63GU2mnUWu08MT/QUv4Z3zahfz9U6XV6NaL79/ptPL1djPfgvs0/l65WqulO6+jo8P9hvv6c+p35N4uYer9sJ+CX1p5qJfa+Czo+7uNZv6+2sG7Rcn4KvBcZptHxdFj+9/xObXyz6UjfG71bq32/na1Xizh0/iZp+Rg4vfVi79/39tTXHUwMDFmP1L++53/jM++VCqO7rY2xGrOxmczXHUwMDE2PyP59LtnjfpIXHUwMDE0KdeWXHUwMDEzeNLjp1Nt74L8dUaHLedr7dL4KeC57U3Lpl8+J8SvU1x1MDAxYYxcdTAwMWaNT3qbWbN9WTh5yWyltkn9pbFTTN3Xf75/7z//dFx1MDAxZvb3XHUwMDBmt296jdTZOeeFwydyXFzOZmuvicnf8vb7861Wo1x1MDAxZvW4T8Xh02Gy0z24qaYzTVwi61d7r/VcdTAwMTiOy65cdTAwMTUpplx1MDAxM1x1MDAxN9up1PPOfr1TfzopXHUwMDFlRjvu7/9cdTAwMWJLUrdZzP96LlRrRq0g8DLjJ16r1p+mxazWuH9cdTAwMWE/yr98JzyFKe6nXHUwMDEywJSJh/pcdTAwMGJOuGBcdTAwMWVRWikmjFx1MDAxMlKMwWBcdTAwMDQnhnpMKk6ktEpyxsay+Fx1MDAwNidUKE9rYVx1MDAwMSOsXHUwMDEygDpjYXyHXHUwMDEzn2Bv4GNcbj6u3PAx8f3fOMEo4LnlVitcdTAwMDdOaFx1MDAxYkCPMU5QgHKhfNK2XHUwMDAwTsQpwmOJREmEXHUwMDFisFx1MDAwYudw32m0dlx1MDAxYXV4XHUwMDE0tVqp5Xug8F66Olx1MDAxY12Bmnh3P/9cXK3hXHUwMDEzkFx1MDAxM1x1MDAwN0zUqlx1MDAxNbxcdTAwMTU/7+Hc/UeC+9GpgqV+/8JztVj0W9Z7OGi+Wi+1jqKY6EarWqnW87VMhIvIdzuNy1L712V0Wt2S/26VXHUwMDBl31xyLqjZXGb97m7LgjzYXHUwMDFmJK+KqdTFfXF48cxIdM7AifGoJiObr9hYlPFcdTAwMTZcdTAwMWFBPE2sMdSiKXFo+IdcdTAwMTNcdTAwMDZWtiUh/lx1MDAxY403qzNcdTAwMDarXHUwMDE5I0xcdTAwMTDjl/HfSEApXHKFXHUwMDAyzVxyk/Bzn0dcdTAwMThI5VEnbknpqluk+evqndTHuVxcVFx1MDAwM1xcfDnqlmnr7jU/XHUwMDFjtlx1MDAxM4VK2tZ7Olx1MDAwNsNOjlx1MDAxM3a30S3ePib3avru6UrXzGtcXIZcdTAwMWSMqDU6XHUwMDFlw+6+e5FcZruVnlx1MDAxMVRcdTAwMDJJXHUwMDA0mlxihnlS67X0uFZSciVcdTAwMTWcdkDp8XNcdTAwMDZWXcGPMlx1MDAwMZdcdTAwMTXUebWIVf/TdDzEK3CZdeDvXFz77ahPlVx1MDAwMbNDrTpQLivQXGLHbNVcdTAwMTeW31Cr/nc9Ucw3wVx1MDAxNP9dXy9cdTAwMDM/x56GXHUwMDE5+DnXXHUwMDEzj62njfvi4U1rb6u8V8n0ijV51zy8XFzc1nNlXHUwMDE5qP9YK37JNqOepVaCsVx1MDAxN1x1MDAwMr41fsyfZu3LxNxcdTAwMTPyXHUwMDA3IcHqXHUwMDAxXHUwMDAyzoyBXHUwMDA34uT9YO3F9NtvXHUwMDEwXHUwMDAxLlx1MDAxYvhsVn1ifCD3enNX2CUnJ1fbmabaJzYn6vn/OrPsvspIZtmAv62NNZRaXHUwMDA2ejilnlx1MDAxMsN3XG60U4OXx1Uwelx1MDAwN1x1MDAxYVxmZt1aa4RcdTAwMTaUUVx1MDAxYdTOhezyXHUwMDFmp41cdTAwMGL424pJqVxiXHUwMDBiscwm3DJLoSX849PXNbbM6W5hvYzzXHUwMDFjXHUwMDAzXHUwMDE4wTiHXFxSPPY5rVx1MDAxZbjhncJDKjm8yVx1MDAxZLRcbslS9yG6fVZgOynnoOCCXHUwMDEzXG5cIjaJXHUwMDAwnFxij2nw0aRcdTAwMTHwLzbm3Vx1MDAxYnf8TVx1MDAwMGKGhMOV7TPV1lx1MDAxMiOd8XtKeHhgzlx1MDAwMlx0o1x1MDAxOHr9PFx1MDAwM10uX+1cdTAwMWS/7GdcdTAwMWF3j/tPLyfm5LX+OIxqoF/4TilXPiV3lXziqnR/85xPlnhcXFx1MDAwNlpwoX1UZSVcdTAwMDPtvsooXHUwMDA2WoNcdTAwMDJqMNDAmzCBNsWfOTdcdTAwMWW4XdRqQGJqfNr7pp5cdTAwMTY0z6WSXHUwMDFib3mGXG5cdTAwMWUtXHUwMDEwXHUwMDA0J0CEXHJcdTAwMDGm5FA2a8KTZYTCU1x1MDAwNW1ky+hanGJcdTAwMWJqlFx1MDAxM83m2nrMc6xemFGef0nxXHUwMDE45UyvfTZ4rZ5ccuxWsp/Nt7Odo6PsXHUwMDAyRplLT0nJmFx1MDAxNIZz39PEO8pcdTAwMTX1lJWSXG6hgHBbXHUwMDFhVPpNTj1mQFxiYemL2GRKMUDOqDNZJuj0u284wVxiXHUwMDA38Fx1MDAwN1x1MDAxOfhEm7xzcZvopp937p9cdTAwMWL8+uZZXHUwMDE1XHUwMDBlb++vvzr5fTbkx7lOs56gO/Vujm2lL5pXu3FcdTAwMWP3oFo7ZZXyXHUwMDExeb1tl29vaOb5zsTEIYA5c0Fj4lx1MDAxMO6nXHUwMDEyhUMoTTxJudREUkmJmkqqU+VxQFx1MDAxMlx1MDAwM/9IXCKMcXj5hnhcdTAwMTa9/N/h97FybnLqXHUwMDEx4CNcdTAwMTedTmAsXHUwMDE0XHUwMDE4urIumFBaT7/7TieUXHUwMDAxoFCaLVx1MDAwNVx1MDAxM6FcdTAwMTJsXGbaIF/Jz1xudOK8WF0zXHUwMDEyMcdKh5GIsFx1MDAwYomHOtw/7eV3KneJMsk2moWnZLN/0LeLUFx1MDAwN+5cdTAwMTE0XHUwMDE33FpJOJ3UdSmFxylcdTAwMDV7L4niwpd731CHt6dcdTAwMWWz7ovVqVx1MDAwMyeYOjE+V8Ffj1x1MDAxN8i5j5PrXHUwMDE2bJD6xOR6vyA6Jyd7p8Pr7lU69bjfPerw1ldcdTAwMWL4y7NjKlx1MDAxYvQ51Vx1MDAxYT7d7lby1+K2dlx1MDAxN8NxZftcInud7G038nvDZIXtlnuySOOoXHUwMDFlTGT36n3eL56/dPKVXrkwyPS2YjjuXG7BkpnHXaEoYi6BXHUwMDEyXFxcdTAwMTPryzmvRKDc0lx1MDAxOYVAacI9xVxiY1pcdTAwMTJcdTAwMDJe+ySmXHUwMDFh41ltmNRMXHUwMDAy4/PRvXGSxHqrhmD+NNhcZilKcnImzonhlGknPpLAu++cSVx1MDAwYlx1MDAwMlx1MDAxMub/uVhCMFxcXHUwMDAzWLOVQjCTXHUwMDE04+/63/V14EtzqMk0X5p1XHUwMDEx8XClzkVuu3Z5c3tJsrJcXD5PpuvsUC7ClShorlWaY1xibyq2XG7W0yPgmFx1MDAwYiuVpNpuXG5cdTAwMTE/XFznd1YvTVBcdTAwMTSellx1MDAwMDBwQFx1MDAwMXi+oaVcdExcYqG5oUulSJcjS5WCrdZPquW9rduHx/N2XufqJ/qrSc2jeM31j1x1MDAwYmf87PT6vJZI9fK9l1ZcZsfNlFx1MDAwN5VMtlN9vN2nrJXNJY9faC4mksCZXHUwMDExUsdUSuF+KlFIglLSo8jVXHTnUlx1MDAwMfeehFx1MDAxM809sDeGUU5cclx1MDAwNVx1MDAxMlx1MDAxMWRcdFx1MDAwNnwza2d2LmyyNrPgY4FaXG5cbsRSai6Zu2KZhMZjgeVZMFx1MDAxY3HXUiwuw1x1MDAwMc4wLjzYx5uVajXu4fpcdTAwMWKtNc3gzLHd4WVcdTAwMTVcdTAwMGJcXF1MLGOLZ1x1MDAwZttcdTAwMTfJfrK/u1s01ze1bLVcdTAwMTCZZXBipVx1MDAwN1xuzaUhWlx1MDAwMWeYrHyWXHUwMDEyK58tXHUwMDExVlx1MDAxOOAgjtLnTUQmZpyIoVx1MDAwMFx1MDAxMii+USFcdTAwMDWQXCJcdTAwMTineVx1MDAwM1x1MDAwZstcdTAwMDS3YFx1MDAwM8ZcIvDhLKOU67RcdTAwMDb0qbKd3tfbXHUwMDE5tX99sdWJzDI+KiTzUaGT+o1tZe96j1fPw2q6cNCtb29lMnGxXGZNqWQxsVxm91OJwDI4VcrDWj6CPiYldjI3rCjxXGJcdTAwMThcdTAwMTJGXHUwMDE5+LZSOViGO1x1MDAxNrFJ38xcdTAwMDCMXHUwMDA1eIVUgll4XG5cdTAwMDFHY4RcZsGKrHdaoaSmktL4Q1x1MDAxMVx1MDAwYlxubYBWrF/aZo49nlx1MDAxZIaIm1x1MDAxY1xcXHUwMDFjdo76eX3ZY+V8VudcdTAwMWb2dy9PS4uQXHUwMDAzXHUwMDA1boGQ3Fx1MDAwMFx1MDAwMzDCXHUwMDE36lx1MDAxY6VmpfY0UFx1MDAwN0KAIUhgXHUwMDBmS5FcdTAwMDMl8CCCcPBQOHjHY1CIxYf4R4GVWaHw/dX8emVeXHUwMDAwmEyMMXCXXeovRWj4XHUwMDAxlJRcdTAwMTlLiFx1MDAxOEeZPpxcdTAwMTnc1u5uXHUwMDFhxct90m7lXHUwMDFm6oNjUU89qqiWNn3bbnaTpdbLRXJw99S52cn2XHUwMDEz8YxcIlx1MDAxMCChcmKQyEqW1n2VkSwtV1x1MDAxZVhR0EzCrPGB6K9JXHUwMDA0xKNwqoQpxpl02FlNPYXpXHUwMDAyTiTVUq86huBPc+ZvXHUwMDE3KMFETm2lm41LXHUwMDFlqnRYMKu1jNvkcqOIXFw5+v/br10vyzvH2Lks74zriMdcdTAwMDD3XHUwMDFh57nrYqF7XHUwMDA2vu/uaeLuuTU8jd6fODLARuCIXCKpXHUwMDA1lZPji7gwWDilrFx1MDAxOLnVZHy3P8v+RuiH+ke5XFw0efP9VT6/sv1lXHUwMDA0nqJmylkpQUEtw6DAUibBM/JVxn24+d3q1O5yPFU6rp6WzO3W08NRsXv0X2d+3VdcdTAwMTnJ/EpcdTAwMGWaZVxyJZRTPWl9uSZcdTAwMWUg/q/BYpJzXHUwMDFlVEzKtUdYjHOA/rDOxFxcYVx1MDAwMVx1MDAwM0xcdTAwMDDfNFx1MDAxMVwi4N6OLLBccq1Qolxme1x1MDAxNdhyWbdZXq9cdTAwMDCpoVx1MDAwYkiw01x1MDAwNK9dJ+JcdTAwMWNT5zK/XHUwMDFm2np4edltXHUwMDFlpExqi5V4oXDafHhOy4V8X+5cdTAwMDHuclxyyCvp1ERcdTAwMTBcdTAwMWNcdTAwMTLlcWvgYUplraP1eJN+j1njiyvbXyBKlHJ/yeFcdTAwMDRcdTAwMGXMqF5cdTAwMTbUSCo/s1axUUremeLtces1e3DBk9Xk8FRFXHUwMDFlXHUwMDA0tEKN3lx1MDAxY/uLXHUwMDBlhDV+eV/J/rqvMpL9XHUwMDE1wlx1MDAwMyagwcsllIBcdTAwMDJNqac0XHUwMDFlUfDELMfQhctcdTAwMDJcdTAwMGKHyVx1MDAxNVx1MDAxYp83XFxcdTAwMDFrXHUwMDBixJlcdTAwMDHQcHqaM84srVxy0zR4Wopx/2jPmJzeRWU2YHGTpU4+16qCgVxc04T1XHUwMDFjazdtfSNeTzyWePYk0yksmtBzrCz3OKOSgilcdTAwMTVTUS6pqIedx1pzYYWiwTBcdTAwMTfxrNRowYVijGmAg6DOc+WhhGD/XHUwMDEwXHUwMDA1QPGJySbVNFx1MDAwMVx1MDAwMWdRXHIwXHUwMDBiM8DGXHUwMDEwgpNcXFxcqEBEKCpcdTAwMDCEg+tMluv7nzeQcylcdTAwMWXebFSnrfv4/36MXHUwMDA1ZvSX9///3386v71cdTAwMTUupfhcbsjn+HhcdTAwMDFj3e7kW51teGTVemXy0fyes1x1MDAxZGViJ3z7uVFcdTAwMWNcdFmjVaj66Vx0XGLuoFRM4dVPXFw8XFylJ8m4LFx0X9Qjk6/giY9cdTAwMDWkVC/OP+3Sy25cIlHq1GUml9NP+8n20UVFuU67Wm9Xi6XI582pVehcIjJD6Vx1MDAxOGJ+P1x1MDAxYXyLSqbAmDGOrvqMq1x1MDAxON3+XHUwMDA0othDKVx1MDAxZtAkuEb/Z4BcZtUpv6NUKzT6XHUwMDBlcXtu9ErJ6q/zb+eqnYffXHUwMDAyXHUwMDFlgWHNvmfz56dcdTAwMWLjXHUwMDAxwlxubZUxik/m/1x1MDAxNGVcdTAwMWVyavxIXHUwMDEwtenWWlx1MDAwMn/HXCJ6vlW86G13klv14cHp5Wmi37lcdTAwMTPvs8BcdTAwMTaA6fPVu8FcdTAwMDVcdTAwMDVcXGTOmVx1MDAxMfBJaJiSaVx1MDAxMJSJ0tKPXHUwMDFmsC57p5RVdsTt8eXNINlcdTAwMTXZRP7pXHUwMDEzXHUwMDA2rFx1MDAwN1x1MDAxZcvqxmVcdTAwMTZ/cl5lXHUwMDA0N4lcdTAwMDGf9lx1MDAwNGVcdTAwMTjEUkZRNZlAUEp7XFxcdTAwMTGDyqusJcH5hlRcdTAwMGKP46XElCfcKGxQYVNufXX5VZZIS0JaiSjhoeNcXIA+KSlcYo+5/3pcdTAwMTVcbjVdXHUwMDE3vHbhzDmWM6xcdTAwMDL4Q0OaW6cvmerWizoy5frl3nNvu3vw2Fx1MDAwYlx1MDAwMlx1MDAwMVx1MDAxZXJcdTAwMWFcYlxi80CB6ajkXG7ntkxZcuEp0HVcblxmXTP/XGKGd1MuwFx1MDAwZlx1MDAxM1JyK3FcdTAwMGWD9lFcdTAwMDGfKWdcYlx1MDAxNkIoSy3Vln1/V2p8vl+CXGaRTXm4yyWQ2IZU/PnHI07HPFxyeiNaLVdcZrz+Tpf1pNJcdTAwMTKHXGZcYlx1MDAwM1x1MDAwZdfY68fXllx1MDAwNY9McE6FJIJcdTAwMTE/53dcdTAwMWZNWI9KdCGUZVxcSjnpRFDQaoNTXHLgY6OtlvNcdTAwMGVHlfCYNUZYcFxu4Y9gk8cjqKxcdTAwMTYnlVsmXHUwMDA1+C7zXHUwMDBlXGI83jNSXGLcWsKoMGM7PjqgxvZhoVx1MDAwMCOUVVbOP5xcdTAwMDC4sFx1MDAwNLDCXGKMr5qJ60VcdTAwMTRcdTAwMDCEIWbUi8JcdTAwMTiff7gwbMGXhrNcdTAwMTNcdTAwMDRhXHUwMDBikIlaXHUwMDE25eTAoUP55aOHOHGtVuNAWMngvFxyQFWEw3HhoV9ugEYx9GK4/3BcdTAwMTSeLVx1MDAwMdRUlMKxrFx1MDAxNWZ8vIC+T3nn085hyCdcdTAwMGI5lVx1MDAxM581XHUwMDFitdfKSNPnXHUwMDExzFdeO8tcdTAwMWVcdIDFYrlX3t1ONZLXmWhcdTAwMDRTU8+OSkBcdGPCXyH4OuJcdTAwMWRcZsd9wK2D222pdEzQXHUwMDA2XHUwMDA3c4RcdFx1MDAxNId4auNcYtD5xlx1MDAwNv5cdGZkXHUwMDAx+5COzlx1MDAxYykjVlx1MDAxYiqcIXlcdTAwMTFcZsmNc+Bcbkd8LVeG9q5cdTAwMGLxboua6dR95MAswSRA0EorfO7unoFj3t05XHUwMDE5rs+VmmC4ZuIw71x1MDAwNLZWKndm8NtOo1x1MDAxOUZuJ854mslcdTAwMDZPMVx1MDAxZfIqznjz5lxcbj2dV1xyqbbSiddi+yRcdTAwMTJ5XHUwMDA1M1x1MDAwNyZcdTAwMDUwXHUwMDE4rFx1MDAwMJq8XHSModR4VlGw5GAsgVuYYFx1MDAxY2p8W8dcXFx1MDAxNYynZ1xmN2BdXHLhkn5/rvpBYf+blTkolfDUsOvE1c3KZlxmIVx1MDAwNYZcdTAwMDb0jCy3gGdGOlx1MDAxMGvp+FI1sLFy0IlvXHUwMDA3XHUwMDA18lsyifx2o3zaS+QvXjMkx6ql43t+XHUwMDFmrUFcdTAwMWRYXHUwMDE50GSt4aFTXHUwMDAzXFxwMtZMsaaO4yZPRY3AmpuAllNp0cWdXHUwMDE5q/r+VOKDtHyBgnb4bUqhV+Sqo7Hh2ixxs1x1MDAxMvNXUsUyXHUwMDAzUGtcctq8klEu59ud+/ZW8XdcYmch21x1MDAxY1x1MDAxMn36INtcdTAwMWN6pvGY6Ntep1xcITf5K3Z9cXhWXHUwMDFm3JOn52JcdTAwMTTt5cDtwSlFK0ykXHUwMDA0njSZqce2UE21ooJQLcBcdTAwMTRcdTAwMDRbxShlnsDNmOGrOjbaXHUwMDFipr0htelO7Vx1MDAwNWREd9qZhWdihvqCc66Jjbs2Z7RbyXcyy6tvXHUwMDAzbN76q+7kWcbErM3xfSGbLp4/J9WwsvPA0vy5XHUwMDEzVNu5IyDggWhcdTAwMTOcMyUsXHUwMDAxkGWMcSm+YFx1MDAwNdb3r7NcdTAwMWJT5ezrbvF5u/x6ok7LXHUwMDBmLHOVSm7fkSVcIsOVlXO8XHUwMDE0nrUmQK+dI2ZU+IhcdTAwMTnAcC3ERFx1MDAxN+nHj/w+SknxlM/Vbux2a5vnr5u7x69RI1x1MDAwMuL6vHGYv7LJ19zT4OCkVSUpnp78LZ89NGrmcT90TFx1MDAwNDPMyJj2aLufSiS2XHUwMDAweEAsyJ+As1x1MDAxMXySLGgjMJpcdTAwMGUyZsH/M8I18Hv+LKo/rJQ3foh5WIBT4FZUXHUwMDFlspRTifAkXHUwMDEzkFxuMFx1MDAwNjTutPTiUlx1MDAxZeBcdTAwMTTfYkjVXHUwMDFjuz/NQD59NNXebq1tzlx1MDAxYnvyeDhcdTAwMWP098uZPdani/BcdTAwMTJcdTAwMDHMglx1MDAwMP2gVtPpiIDFxIxg4DBIq6hxNLlvlnMuXHUwMDAwXHUwMDFig4vj88r1oNfbsnuDp1JPqeuz4Vx1MDAxMrDxvHqbXHUwMDBlQ5+AuNv1VPBt30BxQVx1MDAwMYY+cXxcdTAwMTVV/cThiVx1MDAxObaTuWO1my1cdTAwMTUrt5fdr+YliWQv1zzd22n3r0w90ev3zVXiJYbjNvayxdtmq36quUjsdtuqmD5cdTAwMWXExUtcdTAwMDShhsc0vsr9VFwi8Vx1MDAxMmk8YyjAgVCIXHUwMDA1k01/VltcdTAwMGZDx5pwYcF2OZqKXHUwMDE481x1MDAxOJtcdTAwMTnEWIiXbFx1MDAwMCZcYjD16LxEI3ucXHUwMDE4m+tDXHUwMDEyeIqhvISBXHUwMDAwSFx1MDAxYXvxy+JSPoeXrFx1MDAxYiGZY/BnXHUwMDEzko9kXCK3Z9vHpFI57Vx1MDAxZj+Kaq9w1blrXHUwMDFmkiAkXHUwMDA0c4+cXHUwMDEy4ymiqMBaKDK1gthyXFxOhCspJbdYL1x1MDAxNOQgXHUwMDFmXTe3nlx1MDAxMLFcXN1cXFxcXHUwMDEw0Vg5ZYmZXG5FqbNVXHUwMDE4182GXCJcdTAwMDewUTmZ6vxq5NiUzb1cdTAwMWRvUzY35+Q2ZXM/fiyS7M6kXHUwMDEzg/zL/mBnv9TZSV091Fx1MDAwZm+Iiezf4iAgT+DgRFxyt93qydI5MCdcdTAwMWVu1Fx1MDAwNYGh3HzFZuv1tCzLkU/aTZQuu9dX1/1e+VpcdTAwMTav74/On7LLWJZcdTAwMTj2ZVx1MDAxMctcdTAwMTggQEjgnYfbXHUwMDE2QJnlu+PfT3AhXHUwMDA3Nz1olvZPXHS5k8lGKrf7+HhbUlwiqsOY2z9cdTAwMWaQ65NkK9G+OH7OvFx1MDAxY1x1MDAxZGaeazE4olx1MDAxZrVcdTAwMDXig1x1MDAxZNyJQPdKXHUwMDBlrvupRHBw0VCB0VKAu1x1MDAxNqyknsz1XHUwMDAx+ntMXHUwMDE5XHUwMDBiZkOBlTdL+bdcdTAwMGLtgNhAjFx1MDAwM2JcdTAwMTbYLYWbPFx1MDAxNDBO90C5WZOtlFx1MDAwNkoll2vVjFPKXHUwMDAzXHUwMDBlbtgmhXVzdefY/qhcdTAwMGJcIj7S6b1pmIeLISv2tlx1MDAxZvcrV41Sn5dcdTAwMWajXHUwMDE13CpcdTAwMDF+rVx1MDAwNFx1MDAwMi0pkFUjpiPvXHUwMDEyaDFm73CGu1x1MDAxNl/QLbaewLGc11x1MDAxYlx1MDAxYnDsrOz2Wqzx4NS5n8pVKvCGJ0pbXHUwMDBlXHUwMDFll4m5NmhcdTAwMDU42Xi9b8fbeL1zTm7j9f5YyOt9alx1MDAxM5k4sc+D18fkXWd/P/OydVhdrNpMUMLA8TVqem5cdTAwMWJcdTAwMDXTgrsmiFTwXHUwMDE0XHUwMDE5/4K5iutpWpbjpO3t4t718EB3h1x1MDAwZk2RuEpcdTAwMWSY9HF1XHTT0lxc2etFbVSgRu6hXCI6PKurNM78pZ/p9JZcdTAwMGZcdTAwMGVcZlx1MDAxOVx1MDAxNoup7GmTJFx1MDAxNHstluXpV2dfS4etXiN/wq9Or5nJXHUwMDFl3fdb+vg5Puc0vuyr++5FcE45XHUwMDBlRVx1MDAwNlx1MDAwNFx1MDAwNiOFnaSSTtWQU0M8zrjWgPmEyODGU6wyN5JcdTAwMTCiKDbQSN9Ckk36NS4oeInunVx1MDAwMsRbYa172+nMzcdcdTAwMDa4j2FrlERxp19TtS44eevmmc6xz7OTsLMuKVx1MDAxZa80IU+3ilx1MDAxOcmeaTXde96p7lxcXTb3I6ZiwaxLXHSsgVHOVFx1MDAwMFx1MDAxZlx1MDAwMD4kts7BXHUwMDBiyenGK13FK41cdTAwMGIvWis7pcBcdTAwMDCASLurOMBlXGJcdTAwMGZyaVB4oNlcdTAwMWZcdTAwMTDk2uRi51x1MDAxZG7jlfo+3XilXHUwMDFm75VedexjoqpcdTAwMDVPJ7cyicyVKTdcdTAwMTdYtFx1MDAwM1x1MDAwZtl6QlBcdTAwMGVcboB2ZtqyXHUwMDE4j4DjabHxXHUwMDE4yMlcdTAwMTdswV1P07JcdTAwMWNcdTAwMTUtXHUwMDE5sdPfTZ5cdTAwMTR3k+U66Vx1MDAxNm6Gpzs3y5iW1VfljmahXHUwMDAxpriLjbVcZndLqcB2V7VcdTAwMTRFfT+/xVZcdTAwMDLsXHKrXHUwMDA3+0pnT4u3latLnrDFl4uvzsV+sFtcdTAwMWFfztR991wiuKVgUKQnwVJcYlxuLom0063NVONcdTAwMTRcXKpcdTAwMTXQUqapI2lKjYdbgLArRWjirzvdZE1jw4JcdTAwMDW24IKBXHUwMDA20qGVu1x1MDAwMsPMYJRgcrnC0EKcjFIo8FeENovstFxuOKa+/GK1Vvo12X893dM5hnpG4jTShcXjpJ6/sMzL/e3l49PtXHUwMDBi2+ZDcXf88Fx1MDAxMMVJZVxuuFx1MDAxYlx1MDAwM1x1MDAxZVxyfofE3sSAk1xuxFxcmFF9ObOcOvqpN17qXHUwMDE3wEfIcpNcdTAwMDXcVIbpcoPuh9NPXHIu/fOtXHUwMDE5XHUwMDAzl4XoNSrG2Pipb8fb+KlzTm7jp/5YyE/dOdxNqptcXD9le7tG1/YuK/muY4Rz6EJcdTAwMDauPEOQMFx1MDAxMK1AXHUwMDFjpuZtXHUwMDFhhkuh4Vx1MDAwZcL3Jlx1MDAxNi29WVx1MDAxN02Mx1xyTlx1MDAwMucgzNLVOU9BbD3gqVxmW1pcZlx1MDAxOOpFNsJ+4didYr79UPrcuTvtXHUwMDA1SKdWXHUwMDFho1x1MDAwYs490CY4XHUwMDFh7335XHLVhsVfqSc4UFx1MDAxM1+F50q+1c3JS/b69OVo6274eL57Vd3J9I5uosu0XCLEXHUwMDAz70pLzOtxPVlsXHUwMDA2oOdJqVx1MDAxNJZMU6OUXGLm/TigNE6QJVxuV7hcdTAwMDAwuIIvlDNcdTAwMGb8dY5D5Fx1MDAwMFDJRqhDhXpcdTAwMDFXSqONc09cdTAwMTe34XNcdTAwMWZcdTAwMTSaK1x1MDAxM/dYRyE4Mb46gZVE+nmHdOl5r9/oJuVx2uiLMuGOicihRS5Se2DAXHUwMDAwO4E7wC2aLHPRhHtcZiiFoshcdTAwMTiBXywl0nDR2D6CK7tcdTAwMTVhvvaRjUBPXHT0XHUwMDAyw1xyjZCCgFx1MDAwMXXGXHUwMDAz6YxRJvAscUtZ7KNMqFx1MDAwNFx1MDAwM7DIrNJcdTAwMTlC/VRcdTAwMWM+XHUwMDFkJjvdg5tqOtMksn6191pcdTAwMGZcbrVrXHUwMDBmXHUwMDFmxsdcdTAwMTVQYSWQqZOpznghcXapYNpKKUDgXHUwMDFk+3CBmVx1MDAxOPyEXHUwMDAy/Vx1MDAxNZJxR21cdTAwMDYjQN5BlqWlRFx1MDAwMkL47vZai/Tnz/trR16GXHUwMDFinlVcdTAwMTVcdTAwMDZHrrqX4YpgR8H7ik6r8CF9yFwimaUm9sS7iy9UTPFcdTAwMTVcdTAwMTTQ8fH+mjpu1F18mV77bPBaPVx1MDAxYtitZD+bb2c7R0dZX1x1MDAwMH2pXXzgXHUwMDEyXHUwMDEyycEnXHUwMDAzXHUwMDAwXHR4ecTDecxcdTAwMDKolDREXHRLVOAqxtJcdTAwMTJpMd+H7Fx1MDAxM1RwjznhlqCB9I2rdHxcbs7qjEtYw618l2fHVDboc6o1fLrdreSvxW3tLlx1MDAxYVx1MDAxMGtpQFxiXHQ2/WA15SSxUFx1MDAwNlBcdTAwMWHHaeKWKLgrwc5cZuJcdTAwMTlw/TjDhZJSgqtcdTAwMTeEYcE9XHUwMDAxwo2DXFxxt6pZJE35R6FwZ2VcdTAwMTCmuFhcdTAwMWVJg3MyulxuTz9SK4FcdTAwMWLiXHUwMDAzjJluaCr9zcZfuFx1MDAxMzVETvFcdTAwMTWQ0NVh+P5pL79TuUuUSbbRLDwlm/2Dvl1cdTAwMTXCXHUwMDAyK1FXXHUwMDA12s5Fbrt2eXN7SbKyXFw+T6br7FDGfZZkxlmuIZbO7lx1MDAwNp6DpdrjIPfWUGORak+AqdHCw1mnllx1MDAxM01cdDcuMOVCK3DAmGGSKW7HhPVcdTAwMWRNJfeA3mgtLdJjXCI2eybC0HT1ZWdUXHUwMDEzcIaFu7WeaVx1MDAxNlxivY3hXHUwMDE0OIRcdTAwMDFJiHu4tcSYxFhwvmzTRKig4isgoqvD6adcdTAwMDDVynA6u4f3z4RTcpywu41u8fYxuVfTd09XumZcdTAwMWNDfV1wKjj3wCBcdTAwMTMtwXkyIG1cdTAwMTNwarXyXGLmsKQgVlx1MDAxM0fme1x1MDAxNPJcIlxm43jgWuEmXHUwMDEw5Y+nvEMqt+CjKWaxXHUwMDE0XHUwMDAzXHUwMDEzS2NA2kDqJKSuXHUwMDFlJsCNYVx1MDAxNohoMH39c9TLXHUwMDE3zlCJMYLHzU+FXHUwMDE00r+18lx1MDAwYvnpLFnFV0BKV0fV7rYsyIP9QfKqmEpd3Fx1MDAxN4dcdTAwMTfPjKxcdTAwMWSq0sZ98fCmtbdV3qtkesWavGtcdTAwMWVe/uGoOrv8ci5JlVxmx2szoDB6uqCIKONZLjGVgKl44+iYxVx1MDAwNVx1MDAwZUpxZTlXXHUwMDE4vHLVXHUwMDFmco9cdTAwMTgrXGa4VIRYQ1x1MDAxNoHU9awn+ihIXb1QSChAUy3dXHUwMDBiWEwwlzZGVKCSwsSOqetSJ7RcdTAwMTUuqPhcbojo6nj6OfzPs5OvlVx1MDAwMXZ2XHUwMDA15Z9cdLCJdO+CXHUwMDE3c8n86+BGXHUwMDBmKvWz1s7jTlx1MDAxMGBcdTAwMWTl3UwwXHUwMDBm6zKEXHUwMDA2akGFncRXZjSWrymgtCCahrrquzlcdTAwMWOAzG47/i6rq74gO9t1XHUwMDAzqrOGxljMmGs3dM5ATmWJlHLJ0fAz2ChjVMulXHUwMDE2Sb7Vbd+/lzC3/+Wszl6PnbDu04ypIfhE7TZcdTAwMTLNPYC9YuYpt3d722xWoqguPE/hafA3ubZGaWuni+GAgSuCbVlcdTAwMWPLXHUwMDA1XHUwMDFke2Q2mjt6d1nNXaBQXGJcYqrFZ+FcXD9cdTAwMWReVsFcYuVcdTAwMTSXfsadb2ZMcrpI+dtGc39cdTAwMDQ097Rxe/PIcoe2b4b9fLFx/HCViKi5XG5cdTAwMThcdTAwMDdcdTAwMTegoobCs1x1MDAxON+SX+VR2lOcalx1MDAwZfZcdTAwMTh3PI0/XHUwMDFkt1TBj290dVx1MDAxMV1ccvFb3HM7jFWaXHUwMDA2+6BQV4NcdTAwMDN8xt1RXGaIkop7aodgXFwzuVRK8k1VcefiXHUwMDFkXHUwMDFjNb/Oiuo6yXjU9LK0e3a5t/NwLfdL+eFR5aKnzV4kbqyI9Vx1MDAwNHBfXHTPVYFCTlx1MDAxYVjOlKdccvhihjDFXHJzlFx1MDAxYmxcdTAwMTR1UUXtRddTiiV3yGyci5jt9JvvempcZm4piD00i1OtlytcdTAwMWTY6OlIT1Xr3CZcdTAwMWVcdTAwMGVcdTAwMGJ5lWtf8rOXnd3GVjQ9ZUp6XGZncII5pYxMXHUwMDExYa2pXHUwMDA3XpMwXFxjw5RcclbQS/jxjZoupKZcdTAwMGJwX2OUlFY5R98xXHUwMDE1ak8xT2usjbuiWHDF1WrUXHUwMDE3VWDdVTR27eT1eqNbuCyrw+pjjuxeXlx1MDAxNoZcdTAwMGaFXHUwMDA1Olx1MDAwMlx1MDAwNPGwolx1MDAxNDgtN5KR6TCT9IhcdTAwMDYx0cxqxVx1MDAxZD0ugmHNXHUwMDEzMbjxnvpjwP6+LYw1XHUwMDFh3Fx1MDAxMmCZVt+kbu9cdTAwMGKUt7+AjYVbbqj0L13wtW2pUCNrcbUpJv/iVV7MNnK2SEHJXGaJnj2qclZSijNGPFx1MDAwMq6bIZxo7E6dkGZKlPW0xpZfXHUwMDFj9CpkMPRCPMVcdTAwMDRaI2pcdTAwMDRWWPn6scalU9hUXHUwMDAwWoHzcojWwHRcdTAwMTaQ6D8qK9WPoXaKYn8z08JcdTAwMTWhmTVmzYCoW6ljl/Q1mbJcdTAwMTYuqPhcboro+Hh/TVx1MDAxZDdqVmr2XHUwMDEyvVx1MDAxZmuS5Z89ZTKms/xmSajZXHUwMDFiXedcdTAwMDAq0Fx1MDAwZsIlJoexP39cdTAwMTJQsVx1MDAxNNUwnIKsmcGOy1x1MDAwMJ5Sj2B5XHUwMDFm11ZcdTAwMTKGzduOqSGSe1xunD+tMViugVx0jr+z1lxm4fPxdLAynDKQZDCD3J2qkjLcO8fdPFxuXHUwMDFj+7h3j45GMIzv15dl+cMlXHUwMDE1X0FcdTAwMTldXHUwMDFkUGevSV9cdTAwMTdA/Vx1MDAxNNj/ZoBav7Gt7F3v8ep5WE1cdTAwMTdcdTAwMGW69e2tjKNcdTAwMGI7XGZQcSCbXHUwMDAyvMR9NpOAqizxcL9cdTAwMDBcdTAwMGVcdTAwMTLh6J9cdTAwMDdcdTAwMDCVeaA1hGrg/oZqxmxpy1HdXHUwMDBmXlx1MDAxOYgqN5jDXHUwMDEwymwqUcNcdTAwMDA18qjGUETl6PZcdTAwMDJcdTAwMDdzrmRVJFx1MDAxY1BxPFx1MDAxNsWu7phcdTAwMDFcdTAwMTXn5LCvJ6hbsyRcdTAwMTVf0zK6OqB2tnj2sH2R7Cf7u7tFc31Ty1ZcdTAwMGJrXHUwMDA3qJ9cdTAwMDL731xmUM+G/DjXadZcdTAwMTN0p97Nsa30RfNqN2JcdTAwMWSqXHUwMDAyyMSJQdxYYieHtFxiqz3CjJHaotl2tEoxjzL053DYl1x1MDAwNfvuK8VcdTAwMTnzU1x1MDAxY96FNa74S8Cl+iYjWr5cdTAwMDBNV3f3JeFcXFx1MDAxYX98yt/+L0LRVCsgp8DQ4mano77TpSqp4lx1MDAwNtMwOcVXQEJXx9JcdTAwMGbp/49cdTAwMWRLP6U99pthaaY8qGSynerj7T5lrWwuefxCc9HIKTHWs0pwXHTCr1xy861CXHUwMDE5eftEeKBcdTAwMGVKgT1cdTAwMTdcXFDHJlx1MDAwYlx1MDAwMuRcdTAwMTaIjVXAXom2wlHSTzxuOcWCalx1MDAwNYrO/PVvXHUwMDFiOPXDacFcdTAwMWYmXnZxXCL4XHUwMDE4hHLnICzlXHUwMDBi10yn+CjnOKhSx54mWFx1MDAxM2c/XFxQR1x1MDAxZlx1MDAwN2V0dUD9XGLaN3HRI9xaXHUwMDE1UD+gQZYudJZcdTAwMDFAfVx1MDAwN827RrczOdh41uTLXHUwMDBmXHUwMDAw1tl7uOdcdTAwMDCr8ZRcdTAwMDLhJ9SCvzhFU621XHUwMDFlXHUwMDAxdVOcMsa5ddQrwTekXHUwMDE5LVx1MDAxMVwiQlxi5/BloMGgYCCroPHAotRcdTAwMDZXQ3E1hrSUkUpT4S5cdTAwMWNWOrRwmMOj0ULGXTe8NsBcdTAwMWEuqKOPXHUwMDAzMro6rn5EfDJ+XFz9gJau/1x1MDAxYVxcnb2rYy5hXHJd2spcYvFcdTAwMDTG8ilXiiri8P5cdPc4YVx1MDAxOIVcdTAwMTM4lUw6uvqZx3D+q1ZcdTAwMTS7sHBcdTAwMDHkXHUwMDA2V8NwdfUmVFx1MDAxY0wqiXIuVdO+Qt7grHpcdTAwMDBcdTAwMTUuYt/0vS64XHUwMDFhLqn4XG7K6Oq4+lx1MDAxMYn0+HH1XHUwMDAzek7/a3BVti+y18nediO/N0xW2G65J4s0Oq6OXHUwMDAyXHUwMDAxWETCpob5YY1cdTAwMTUzoGugc9K1WVxigVx1MDAxN/xObTRRuGlVuVaFeOT3RH9cdTAwMDPeJs6D3MBqXGKs0pVRVTFcXHEtnGR1xvgp8JJx70Ls46fWZppfuKCOPlx1MDAwZcro6rD6XHUwMDExOar4YfVcdTAwMDPiqv81sLq/VclcZjL1aknu0DR7SvC7bX+d8Ky2JWGxak/bX+N5pmCVXHUwMDFhz1x1MDAwMqZcdTAwMWFsXHUwMDFjxlx060FYZXxuW7A0nrFMXHUwMDE5XG5yS3Dy9Vx1MDAwNlVDUFVFL7ZmlGK9tXRcdTAwMTZbXHUwMDBiX5A7XHUwMDEwRiVGUc7jrkFcdTAwMTW4tsk3hHWZvWx7mX//eNthlijmm51Sa7y27O/6fmr88eQmbseX9/Z9x2o2XHUwMDFk30jm/v0jWerkf+1Jc3yhXHUwMDBmXHUwMDFmXHUwMDAwJP37R6LTafnWrvl6OMDTY1x1MDAwMMSjvnpcclSfT3zpi1o6vst9jKfX5Cq1c9FuVffq9ZtKt3VTTso7eVx1MDAxYVxy+ji2mcDDXHUwMDFibarlU9NMXGbXXHUwMDFlPFacMmQ5fMtcdTAwMTFcdTAwMDDVdP5IXHUwMDA07kk5qtwzoJRAMjbYXHUwMDE3gn06OvZJibtcdTAwMTOscVx1MDAwZUhcYk7pf3fIqZFWaUJjhj6K0+E180vvotCHf8E+ybv7xnOzXHUwMDA1V1x1MDAwZaf9W19y/1x1MDAwM8/mf/+uv39cdTAwMDX/hVI98fn3QadcdTAwMTgvNVx1MDAxZVx1MDAwMGHXilx1MDAxNNOJi+1U6nlnv96pP51cdTAwMTRcdTAwMGaj1flcYuRHYE9cdTAwMDXFLTZ8ulGNc49w+Fx1MDAxMD1cdTAwMWRcdTAwMGL4XHUwMDEwXHUwMDFj48mx7pJiXlOq0Vx1MDAwNFx1MDAwN4dTilOVJH5NUqGMMlx1MDAxYvpcdTAwMTRcdTAwMDYhxlxyIVx1MDAwYm360Fx1MDAwNLDeiSxUhlx1MDAwZk3C+lx1MDAxN078PW5cdTAwMWa+4lrXLo6IIPXb6+3tm73CcOtlh+Sir4xcdTAwMTZcbvc0+2tBv8zjXHJVXHUwMDAyfFx1MDAwNcU/4KEt7O++8tpZ9kiAvFx1MDAxNsu98u52qpG8zvhcdTAwMWTGtagj+pBNId+8jsgt9FHIXHUwMDFl19ZcdTAwMDM2Jy3TOIx2soqIg1x1MDAxM1xm4qWptqNcdTAwMTFKwSpcIqM8jnuKjdCA59SxXG7E5/tscHlcbpdcdTAwMTdcdTAwMThcdTAwMDDARilcdTAwMDP/xFxyX+l66KYlzjSn4NbGzeyMxr1PqzC7x2678zfcil9cdTAwMWWUk6aFXHJcdTAwMDL4oKXic/jONF9cdTAwMGK7gHjI19lBtXbKKuUj8nrbLt/e0MzznYlIvpj0JJfKWG6pb/Gqi3o5Vodj4SC1uEdcdTAwMTNMjjauJkC0PVx1MDAwNlfKKVxy7E0s1FP9Z2m4XZl5SUOZ1dK58pWS0I5qRongozj55zEv8VSopFx1MDAxMluDh3ayoHvXJXU87N0uyLxcdTAwMDTjX7/qXCJcXFx1MDAwN/BcdTAwMTWQ/j+FeH1Emfk/XHUwMDAzp/y9iJdb5qNcdTAwMTAvSZVHiVx1MDAxMri8S0omJudcdTAwMTdyXG60XGZcdTAwMDc9XHUwMDFixvA/NDj+QoBcdFx1MDAxOVxyg1x1MDAwNlx1MDAwZVx1MDAwN1x1MDAwZYt0XGZf2nCvUGRORKdemnLCOHVPtVxiTShYwcF5i73KhWnGXHUwMDA1XWlecFx1MDAxZiT87zpcdTAwMGU4Wlx1MDAwN9o1h+lM0y7XycdDuVx1MDAwZYfFZu3yLPV4f5KxT3dXXHUwMDAz3XthXHUwMDExXHUwMDAz5spcdTAwMTNSU9z5K6hfXHUwMDEzR6PTXHUwMDA08DErhMDdSEYrx/RvSj1LlcLhXHUwMDFmOJ7f0ddcdTAwMDa/gStcdTAwMDOcTeKuP+3/XHUwMDFk8zW7RDjl9E/R7L3omo1cdTAwMTMpLWHWWcFGQlsuLO5cdTAwMGWwMu6OXHUwMDBiXHUwMDA2j8lcdTAwMWamX0K196qVUSbLlb36uz5OPoWExZU1QFx1MDAxY6VcdTAwMTDEwFx0iYkvrYxcdTAwMDPLXHUwMDA2xlx1MDAxN7+mePDA8lxm0eV29WmXqmHenN50XHUwMDEyuypcdTAwMWFcdTAwMWVcYuFJxlx1MDAwNMhcdPxRU+Fv4IxcdTAwMWUhdtRfIFx1MDAxY2iglHOQXCLFtkKGfVx1MDAwN4ZQOCxdZDbbXHUwMDFmhlx1MDAwMFx1MDAwYsRVKFx1MDAwMVx1MDAxMm+ocGOAXHSNrGDXleHwdMdcdTAwMGY3XHUwMDA2XHUwMDEwXHUwMDAwXHUwMDFmiCrtXyCxXHUwMDA0XGKcg3H8nqpcdTAwMWV25vEodG73sjSsX13299Ns+HrYeOi+0OM4XHUwMDE0WmtcdTAwMGbnkIPrynCDQDAj/lx1MDAxMSqNzUn37I9R6ZA1dM40OPBj4GQ8YL/hM1x1MDAxM1xmoL6HTIRcdTAwMDFXyp9cco5Loa3kK1n1jUK7XHUwMDE1+rZZXHUwMDE4XHUwMDBlXHUwMDFmOiltXHUwMDFip6/VcrW71TtcdTAwMTfRXHUwMDE0WmKwgTHDmeVWyamh5Jp70kiMn1x1MDAxMlwi/Uth3tNcdTAwMWXWs0xcdTAwMTLCiaRaauPIe2zs9ds5zVfuXHUwMDA1XHUwMDE2XHUwMDBiSIKbvbQrXHJieHhcIlx1MDAxYbCZUmy8iJey41x1MDAxY2T/zphlKfv31fCZp1x1MDAxZo+al+D3XHUwMDFk3bX3d0snZO+cpVx02yo5XHUwMDA2zriSm0x5mFx1MDAxZFx1MDAxN0IxSqdCbEZYXHUwMDBmXHUwMDBibylV8DHoeUDLXHUwMDExXHUwMDA2QMlnaTlcdTAwMTNcdTAwMWWO9sRcdTAwMTBcdTAwMDBhoOl8oSqUP8uEN6NrOcM5XGJMXHUwMDFhZ29cdTAwMTmlOnS2jCA49NU/3TImI45cdTAwMTNql+ote9Pz6/aoquubO+NRrlwiXHUwMDFlrVx1MDAxZu7vXt5r20+dy7LYXHUwMDFmtOmuOu1E0not0HwzbkbDISWbbOCH51xiplx1MDAxZkxcYrVEU2OYo4CVWU9ohjv74Fjw8Fx1MDAxZFx1MDAwMTlGPPhF8Fx1MDAxZJRGXHUwMDFjjLZQT9Sfpfgv0Vx1MDAxNV9hQ6RRNKDgeC6chtewYvOTpCZ2d1xcYLZ8qZTklOL/2Fx1MDAxYuSfm/5AuE/bKTiIXHUwMDE0m0GNXHUwMDE1XFxcdTAwMTK9XtpcdTAwMWU89XhU/Dqrzo5N9+W41CpccpMvV9e9XHUwMDA0czQ9Olxyu/GMXHUwMDE5XHUwMDE1JVxuTenUslx1MDAxMlxu7NmzRozmwcBfXHUwMDFjs+Qk97DeXHSLatBcdTAwMDNcdTAwMTBcdTAwMGXvfGPa385pvoa3XHUwMDE20HBLcN+Qc5NcdI5UXHTVcLDBVlpcdTAwMWT7XHUwMDFhv+XXwU9p+G7n/pub9dAriEfft9Nblzc5mbX1QaX5XFy+zvfOtWNcdTAwMTSvS99cdDadgOvHjJL+3a2jyZHceGjowdRjwtVXhPhcdTAwMWV/s5uQ+q93l9bwTnRccrc4o4u7d/9ZXHUwMDFhWrJEXHUwMDE1MfgwfE83XHUwMDFlXHUwMDA1R5g3K3H3kZP7PTU79NRjalx1MDAxMum+7na3843t3Mv1QeqM9O6e9lx1MDAxY/NgXHUwMDE2Z+lMe1x1MDAxNCNwODGGg6lcdTAwMGVWKoLr7lx1MDAxOWpGjWi4O4Q5ZmuvxNL/MFxyX2RroFZCWKaNk6b7x+5cdTAwMDTicNjNYKyO2z9cdTAwMDeWplfzz0eK8lx1MDAxZEl6yInHtFi7UCo1b5uHvcLh7XOxf5nsKy4jmmzuWaBrXHUwMDE2J1MoYaaG52NcdTAwMDMoXHUwMDBlXHUwMDEwXHUwMDAy+6tcdTAwMTkxweCbxC49MbO8bSWG/odpd8g6XHUwMDEy565BiaVG1DnX2Vx1MDAwNlx1MDAwYpHHXHUwMDA0XHUwMDFkUFx1MDAxYTiUinmuc1xc9jvZqFc7jW9cdTAwMWJ5m39ccjE55em8uVx1MDAxZIjb5E4vl1x1MDAxNMX75NM1v4mYJSdcdTAwMWXHPIsgSlx1MDAwYl+55EiIOVx1MDAxNVx1MDAxZVx1MDAwZbxcdTAwMDI9Nca49lx1MDAxM2KdnJYzffJNXHUwMDE53Ns5zdX4/ehcbi9Gc/els8CVklx1MDAxOYydXHUwMDAx6+JY21x1MDAxOLPG41RrubrG7+frf9e/ecA94oXEo/vVYWfv/iRbuG7VmoP6wWWleXniKIF1dVx1MDAxZFksRydcdTAwMDJcdTAwMTSfov1cdTAwMTg/vFHbXHUwMDExYVx1MDAxZU6CINjIQrGcOsjmrfEwUodcdTAwMDXxXHUwMDFhOFx1MDAwMXGMI9/MIXs7p7naf7B6zzdFXGbGREmAzf9cdTAwMWPtJlxyRVx1MDAwNWMx1a4/sfPoXGJI4vnJnk1d3uxcXG3fXlxcZlNcdTAwMTeL9XwvXHUwMDFm5o97Jm+YXHUwMDFh/Pp4hSln080yIZ+s8TQv92OOQk1cZlOe1YJcdTAwMTlcdTAwMDJcdTAwMGUoXHUwMDE1k/FDynHUXHUwMDE33FNccp6dNsLRa8NcZoCbP13gQCdf38Q6oJGYev9L0WhngdiCXHUwMDAyt9BKa12wMyNcdTAwMDFohKDK+qNA65JcdTAwMDCstn/kQ1x1MDAwMlxu8XKMOZ02c6z7NPOYPO2Ywlx00qhbJYp75OV6a9C+yNzTXFw1XHUwMDFhwVx1MDAwMI/C01x1MDAwMHmWclx1MDAwZeRQT+owNjYzXG7kXHUwMDAymKwhrlx1MDAxZVx1MDAxYqs8LPXGbX5cdTAwMDL31zuihdRcdTAwMTNcYq+aMEwnc+OLRK+DRq9cdTAwMTW/WH1cdTAwMTlcdTAwMWZcdTAwMTZfKMZUYP4+nqLU4bV8Qlx1MDAwYkvkUlx1MDAxMcTl6MVBdys7uM5esFx1MDAwYnm1c9q9rlx1MDAxZb3m+t+RXoQrwejTgPh/PLn4+lx1MDAwZV73w41GKjDeobHrj2styFRcdTAwMTGCklx1MDAxZWGWXHUwMDE4JonFQGdcdTAwMDCSXHUwMDA086ThnDOiXHUwMDAwubRzoP2GU4RcItD5XCL5XG7M8Sv/XHUwMDFjqkicXHUwMDAyY/1gVVjcLVx1MDAwMatziof8mpCKOVx1MDAxNn2aVEyddzysXCJ92252k6XWy0VycPfUudnJ9lx1MDAxM9Em1XHGmEexrMBKLo2ZXGZbXGJqPaZccrE4opfhXHUwMDFjnYBcdTAwMGVcdTAwMTNvNHRdw3dcdTAwMTQmK5VyRS2ZJ8DUge+BXHUwMDE144Ru5qWEKnVcZtt+pFx1MDAwNeul3Et+XHJcdTAwMGbd9sO4VFx1MDAwMMW+XHUwMDFmi2l+ujBSfr3p35ohqfhcbshodNtcdTAwMWY2L6TXOM9dXHUwMDE3XHUwMDBi3TPB5e5p4u65NVxcdd+DY1CbZydfJnDiXHUwMDBijjm5OOxcdTAwMWP18/qyx8r5rM4/7O9enpZiP+1cdTAwMTlnucZcdTAwMTGYp0R2r97n/eL5Sydf6ZVcdTAwMGKDTG8rmv9cdTAwMDZ+mUdcdTAwMDXnXHUwMDEyiKXmYlx1MDAxMmmVXHUwMDE2ntGUXHUwMDAwVVx1MDAwMlZFXXsqKFxiMCFcdTAwMWN7MYSx1rVVXHKMKu5mwy56yYX1me1ccs5O4uzhyjCLXcrwxJxzqWbVacOjXHUwMDAzL97EvvxnTdZUhIspvlx1MDAwMlx1MDAwMro6yEbe/lCtt6vFUiS4gpOEu0rhWVx1MDAxOW7pOFxuMrpcdTAwMDNcdTAwMWWwJaqIXHUwMDE2OHpUa1x1MDAxZdxfvCDeXl52m1x1MDAwNymT2mIlXiicNlx1MDAxZp7TcmW8XHUwMDA1aTBMoXuluTbaTl6CXHUwMDExlFwiXHUwMDA2KcVcdTAwMTTG0Vx1MDAxN1x1MDAwMeOv91j3dtv57YunzEum0S1393Lph8p9NI9cdTAwMTXuilx1MDAwN8KncYaQ5VNltNZcblx1MDAwZkRcdTAwMTK3UeBOIVx1MDAxNiS7TFxuT2CGftZg96DHKjxNXHUwMDE1alx1MDAwNKGSXHUwMDEypX3L3f5sXHUwMDE0PlrAg/1V52i4q/FVyvCqecExhadt7GMqmLS+wY9LjqH68TY/88f9r6T2j2r9R/5XovtTvNtl0/LRTz5cdTAwMWVcdTAwMTe3bvPPdGfnVPdcdTAwMDbVXHUwMDA3LSupe815NJ1cdTAwMTfCIyNcdTAwMTiXQOuNL5v7a3ZcdTAwMDX1cLCvwVx1MDAxNcpYXHUwMDA1XHUwMDEyVHohPcY2Slx1MDAxZpfSXHUwMDFmR1d6sLFaKH+7g49jhVx1MDAxN9kyglx1MDAxYrJcYidLZeBn6rylPuJcdTAwMTanzpfz7c59+3uq/PS5x1SHl8o/ktOM0VvWVFx1MDAwZcvJw/Iw70iVteB0pijHr/GS2nhcbjhcdTAwMWF48lIrMVl9i7W5TFx1MDAxMVx0+lx0msm4XHUwMDBlZry5XHUwMDAwqsAx9klcdTAwMDFcdTAwMDFcdTAwMDR3aD1wKIZTNFx1MDAwMFSsXHUwMDE0jH9cdTAwMTd/q5hvP5Ri0PoxXHUwMDExtee94WMuc3+cVCmaeT5tZ9XV41uCaCFwWGByldBcdTAwMDJgnVx1MDAwNWdcdTAwMDCPXHUwMDFljVxugMZ43Vx1MDAwYrNgXHUwMDEwlFx1MDAwZkBWh1x1MDAwNy7A6Vx1MDAxOW1DW1x1MDAwMFx1MDAxZWZI//5j7eFoUCidX+pcdTAwMWHppvW9TvRcdTAwMWOVaGHSXHUwMDBm5MRjcG9w/1xmmDw7afS0wlwiXHUwMDFioEYg/FxuLKBD+jG1Y6i0jOHQdeNIXHUwMDE2a6I9LcFygjMnwPv8JrniNVx1MDAxNv6TXHUwMDA16DDwXG7gtMQ9XHUwMDFmQoWveVx1MDAwM1x1MDAwZYMrp8xy6eNPXHUwMDEy/odBu5Ptd1x1MDAwZSrpZvb0MWdv2sNsbVx1MDAxMejXXHUwMDE4ZZBCUFx1MDAxYzNcdTAwMThcdTAwMTB+61x1MDAwMVpLIIbgwTNcdTAwMTVkfMrTilxiTLOrkfg7XCJtQOfAkZRMXGIwXHUwMDBmzMpcdTAwMDUyXHUwMDFhTsF2KMA/yqPXOtK9j5D9RUZcdTAwMTZqXHUwMDAzt1xcumNvUoTORqEop0SytVx1MDAwNv7iy1G3TFt3r/nhsJ0oVNK23tNB2XdFmFx1MDAxNadAWVxiXHUwMDA1d4PBadnJXHUwMDA2XHUwMDA0XHUwMDA1ZFx1MDAwNYRcdTAwMTVrXHUwMDFmLPBcdTAwMWZcdTAwMTHcZaJcdTAwMTWwXHUwMDE5y4RcdTAwMDb7wLhlLspcdTAwMDPukrFgUcBfXHUwMDAy4yHUN6E8X+DnnLpcdTAwMDV6kUyeoaMt6cHNdaMnXHUwMDExvnZKMYJcdTAwMDUuLO62XHUwMDA0XHRcXHm5rSfxpvJCXHUwMDA1XHUwMDE1X0FcdTAwMTFcdTAwMWRcdTAwMWYvXHUwMDAwTHFcdTAwMDeZXHUwMDE3XG7RKiWx91x1MDAxN1x1MDAxN8SBXHUwMDA3oafCzFNcdTAwMWZcdTAwMDcuYsEoc3dbXHUwMDE25MH+IHlVTKUu7ovDi2dGVr1cdTAwMDSDt1x1MDAxN05cdTAwMTLzzVxcXHUwMDFi9c9cdTAwMTmf2m9cdTAwMTZlfuE7pVxc+ZTcVfKJq9L9zXM+WXJEnNxALD2DK2gsleBCTi1cdTAwMTBcdTAwMDXN9IhcdTAwMTHCXG7cXCLEtGP7n/BcZleSYO6cXHUwMDBizVx1MDAxY+OXXHUwMDAwXHUwMDE3PKtxgDI2XHUwMDFj0s3uvzBcdTAwMThOrlx1MDAwZcNwj1FcdTAwMDPdq6dcYlx0jUMhPFx1MDAxMcrirqhcdTAwMDBcdTAwMTg2/mK7r9vPx0BMNZZKUpxcdTAwMDZNxURBhSBY3lx1MDAwN6qvteTKKjvveNSzXHUwMDE2XHUwMDFiI1x1MDAwMSuQw9hxPSC+plx1MDAwNX5NQZ2MpmxqTFx1MDAwZVx1MDAwYvijzETVXHUwMDAztq9wXHUwMDBlxongXHUwMDAwIHDC1KqwnlZcdTAwMGbc8E7hIZVcdTAwMWPe5Fx1MDAwZVqFZKn7sLJlXCJYmKwx56I1PLmJ51xuuG4pXHUwMDA3SVx1MDAxY1x1MDAxNYUx8Ce/XHUwMDE3rp+1WC59cFndarFyq8FcdTAwMTKHzcypI67oyCRYjFx1MDAxYUqBXHUwMDAzeKTB2zNcdTAwMDHrOLGDUWO4XHUwMDExXHUwMDAw/Nw12Vx1MDAxZXB9slQniOtMecr/irnD71x1MDAxZlx1MDAwNVZmhcJ3r309W8BZXHUwMDE0klx1MDAxYox6uNppZlx1MDAwNFx0XHUwMDAx7ykwy7jThqvP6TgpvTrTXHUwMDA0XGadP9/Ld8FR0lx1MDAwNlx1MDAxZrTVeeJs40lcZjxcdTAwMWOlq/luNztMpU1V5lx1MDAxMtn6YfoqqMBh0SHNrKdccsNcdTAwMTZrroiY3Fx1MDAwZkhHS6ngUYFfj8N5fDXp7/lAMHvM91KuRl2uPe1/rVfFK516f1x1MDAxY1x1MDAxY210OnFcdTAwMDRHXHUwMDE30eWQMvYgQXvz44KlWIpoboWrjyY4w2NcdTAwMWNcYiW405WQuGvbXHUwMDE31vBfov7Xb1x1MDAwNvMz32ymO3DI93vws1ct9bfDXHUwMDAzhH/9viUoXHUwMDAwpdGt+89f//l/XHUwMDE5a6ZrIn0= DetectorController Detector Adapter Controller Detector Adapter SubController DetectorApp Adapter Controller DetectorOdinController OdinController Detector FrameProcessorAdapter Controller OdinController OdinAdapterController OdinSubController MetaWriterAdapter Controller DetectorSubController __main__ fastcs-detector fastcs-odin FrameProcessorAdapter Controller FrameProcessor Controller Detector FrameProcessor Controller FrameProcessorPlugin Controller Detector FileWriterPlugin Controller controllers/ controllers/ odin_data/ odin_data/ odin/ DET: DetectorAdapterController FP: DetectorFrameProcessorAdapterController EF: DetectorAppAdapterController MW: MetaWriterAdapterController writing: AttrR data_compression: AttrRW[str] data_datatype: AttrRW[str] just detector with odin Eiger FrameProcessorAdapter Controller OdinController OdinController EigerOdinController XspressAdapter Controller Xspress Example XspressDtc Controller EigerController Eiger Example EigerMonitor Controller EigerFan Adapter Controller is a has a with detector control in adapter with detector control in fastcs Key
This allows a lot of flexibility when implementing a driver for a specific detector to
rely primarily on the base implementations while adding detector specific logic through
composition and inheritance. The two key patterns are to acheive this are:
Creating base classes of the built-in controllers to add type hints that validate when
running against a specific odin server that the given attributes are introspected for
use in driver logic
Sub classing OdinController and overriding _create_adapter_controller to create
detector-specific adapter controllers that implement detector specific logic.
For a worked example of putting these pieces together, see the tutorial on
Creating an Odin Detector Driver .