diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 0000000..eef68c2 --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,22 @@ +environment: + matrix: +# - PYTHON: "C:\\Python35-x64" + - PYTHON: "C:\\Python36-x64" + +build: false + +install: + - cmd: set PATH=%PYTHON%\;%PYTHON%\Scripts;%PATH% + - cmd: echo %PATH% + - cmd: dir %PYTHON% + - python --version + - "python -m pip install -U pip setuptools" + - "python -m pip install Cython==0.28.3" + - "python -m pip install -r requirements.txt" + - "python -m pip install -r test-requirements.txt" + +before_test: + - "python utils/build_uic.py dgp/gui/ui" + +test_script: + - "pytest --cov=dgp tests" diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..28ce312 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,13 @@ +[run] +branch = True + +[report] +omit = + dgp/resources_rc.py + dgp/gui/ui/*.py + dgp/__main__.py + +exclude_lines = + pragma: no cover + def __repr__ + raise NotImplementedError diff --git a/.gitignore b/.gitignore index 80353b2..d2182e0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,26 @@ +# Ignored file extensions *.idea +*.pdf *.pyc *.pyo +*.coverage +*.vsdx +*.hdf5 +*.h5 + +# Ignored directories __pycache__/ scratch/ -*.pdf venv/ -*.coverage \ No newline at end of file +docs/build/ +.cache/ +.pytest_cache/ +build/ +dist/ + +# Specific Directives +examples/local* +tests/sample_data/eotvos_long_result.csv +tests/sample_data/eotvos_long_input.txt +dgp/gui/ui/*.py +dgp/resources_rc.py diff --git a/.travis.yml b/.travis.yml index 47a2e0d..5649474 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,25 @@ language: python +cache: pip python: - - "3.5" - "3.6" +before_install: + - sudo apt-get install -y libgeos-dev + - sudo apt-get install -y proj-bin install: + - pip install Cython==0.28.3 - pip install -r requirements.txt - - pip install coverage + - pip install -r test-requirements.txt +before_script: + - "export DISPLAY=:99.0" + - "sh -e /etc/init.d/xvfb start" + - sleep 3 + - python utils/build_uic.py script: - coverage run --source=dgp -m unittest discover + pytest --capture=no --cov=dgp tests +after_success: + - coveralls notifications: - slack: polargeophysicsgroup:FO0QAgTctTetembHbEJq8hxP + slack: + rooms: + - polargeophysicsgroup:FO0QAgTctTetembHbEJq8hxP + on_success: change diff --git a/README.rst b/README.rst index 0c97ac0..35c9c74 100644 --- a/README.rst +++ b/README.rst @@ -3,17 +3,65 @@ DGP (Dynamic Gravity Processor) .. image:: https://travis-ci.org/DynamicGravitySystems/DGP.svg?branch=master :target: https://travis-ci.org/DynamicGravitySystems/DGP +.. image:: https://ci.appveyor.com/api/projects/status/np3s77n1s8hpvn5u?svg=true + :target: https://ci.appveyor.com/project/bradyzp/dgp + +.. image:: https://coveralls.io/repos/github/DynamicGravitySystems/DGP/badge.svg?branch=feature%2Fproject-structure + :target: https://coveralls.io/github/DynamicGravitySystems/DGP?branch=develop + +.. image:: https://readthedocs.org/projects/dgp/badge/?version=develop + :target: https://dgp.readthedocs.io/en/develop + :alt: Documentation Status + +What is it +---------- +**DGP** is an library as well an application for processing gravity data collected +with dynamic gravity systems, such as those run on ships and aircraft. + +The library can be used to automate the processing workflow and experiment with +new techniques. The application was written to fulfill the needs of of gravity +processing in production environment. + +The project aims to bring all gravity data processing under a single umbrella by: + +- accommodating various sensor types, data formats, and processing techniques +- providing a flexible framework to allow for experimentation with the workflow +- providing a robust and efficient system for production-level processing + +Dependencies +------------ +- numpy >= 1.13.1 +- pandas >= 0.20.3 +- scipy >= 0.19.1 +- matplotlib >= 2.0.2 +- PyQt5 >= 5.9 +- PyTables_ >= 3.0.0 + +.. _PyTables: http://www.pytables.org + +License +------- +`Apache License, Version 2.0`_ + +.. _`Apache License, Version 2.0`: https://www.apache.org/licenses/LICENSE-2.0 + +Documentation +------------- +The Sphinx documentation included in the repository and hosted on readthedocs_ +should provide a good starting point for learning how to use the library. + +.. _readthedocs: http://dgp.readthedocs.io/en/latest/ + +Documentation on how to use the application to follow. + +Contributing to DGP ------------------- -Package Structure -------------------- -1. dgp - 1. lib - 1. gravity_ingestor.py - Functions for importing Gravity data - 2. trajectory_ingestor.py - Functions for importing GPS (Trajectory) data - 2. ui - - Contains all Qt Designer UI files and resources - 3. main.pyw - Primary GUI classes and code - 4. loader.py - GUI Threading code - 5. resources_rc.py - Compiled PyQt resources file -2. docs -3. tests +All contributions in the form of bug reports, bug fixes, documentation +improvements, enhancements, and ideas are welcome. + +If you would like to contribute in any of these ways, then you can start at +the `GitHub "issues" tab`_. A detailed guide on how to contribute can be found +here_. + +.. _`GitHub "issues" tab`: https://github.com/DynamicGravitySystems/DGP/issues +.. _here: http://dgp.readthedocs.io/en/latest/contributing.html diff --git a/dgp/__init__.py b/dgp/__init__.py index e69de29..6010a08 100644 --- a/dgp/__init__.py +++ b/dgp/__init__.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +__version__ = "0.1.0" + +__about__ = f""" +DGP version {__version__} + +DGP (Dynamic Gravity Processor) is an open source project licensed under the Apache v2 license. + +The source for DGP is available at https://github.com/DynamicGravitySystems/DGP + +DGP is written in Python, utilizing the Qt framework with the PyQt5 Python bindings. + +""" diff --git a/dgp/__main__.py b/dgp/__main__.py index 26c4aef..4e5faf1 100644 --- a/dgp/__main__.py +++ b/dgp/__main__.py @@ -1,18 +1,45 @@ -# coding: utf-8 - -import os +# -*- coding: utf-8 -*- import sys +import time +import traceback -sys.path.append(os.path.dirname(__file__)) - -# from dgp import resources_rc -from dgp import resources_rc +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QPixmap +from PyQt5 import QtCore from PyQt5.QtWidgets import QApplication, QSplashScreen -from dgp.gui.splash import SplashScreen -"""Program Main Entry Point - Loads SplashScreen GUI""" -if __name__ == "__main__": - print("CWD: {}".format(os.getcwd())) +from dgp.gui.main import MainWindow + +app = None + + +def excepthook(type_, value, traceback_): + """This allows IDE to properly display unhandled exceptions which are + otherwise silently ignored as the application is terminated. + Override default excepthook with + >>> sys.excepthook = excepthook + + See: http://pyqt.sourceforge.net/Docs/PyQt5/incompatibilities.html + """ + traceback.print_exception(type_, value, traceback_) + QtCore.qFatal('') + + +def main(): + _align = Qt.AlignBottom | Qt.AlignHCenter + global app + sys.excepthook = excepthook app = QApplication(sys.argv) - form = SplashScreen() + splash = QSplashScreen(QPixmap(":/icons/dgp_large")) + splash.showMessage("Loading Dynamic Gravity Processor", _align) + splash.show() + time.sleep(.5) + window = MainWindow() + splash.finish(window) + window.sigStatusMessage.connect(lambda msg: splash.showMessage(msg, _align)) + window.load() sys.exit(app.exec_()) + + +if __name__ == "__main__": + main() diff --git a/dgp/core/__init__.py b/dgp/core/__init__.py new file mode 100644 index 0000000..2a08eae --- /dev/null +++ b/dgp/core/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +from .oid import OID +from .types.reference import Reference +from .types.enumerations import DataType, StateAction, Icon + +__all__ = ['OID', 'Reference', 'DataType', 'StateAction', 'Icon'] diff --git a/dgp/core/controllers/__init__.py b/dgp/core/controllers/__init__.py new file mode 100644 index 0000000..40a96af --- /dev/null +++ b/dgp/core/controllers/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/dgp/core/controllers/controller_helpers.py b/dgp/core/controllers/controller_helpers.py new file mode 100644 index 0000000..378ddb4 --- /dev/null +++ b/dgp/core/controllers/controller_helpers.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- +import shlex +import sys +from pathlib import Path +from typing import Optional, Union + +from PyQt5.QtCore import QObject, QProcess +from PyQt5.QtWidgets import QWidget, QMessageBox, QInputDialog + +__all__ = ['confirm_action', 'get_input', 'show_in_explorer'] + + +def confirm_action(title: str, message: str, + parent: Optional[Union[QWidget, QObject]]=None): # pragma: no cover + """ + Prompt the user for a yes/no confirmation, useful when performing + destructive actions e.g. deleting a project member. + + Parameters + ---------- + title : str + message : str + parent : QWidget, optional + The parent widget for this dialog, if not specified the dialog + may not be destroyed when the main UI application quits. + + Returns + ------- + bool + True if user confirms the dialog (selects 'Yes') + False if the user cancels or otherwise aborts the dialog + + """ + dlg = QMessageBox(QMessageBox.Question, title, message, + QMessageBox.Yes | QMessageBox.No, parent=parent) + dlg.setDefaultButton(QMessageBox.No) + dlg.exec_() + return dlg.result() == QMessageBox.Yes + + +def get_input(title: str, label: str, text: str = "", parent: QWidget=None): # pragma: no cover + """ + Get text input from the user using a simple Qt Dialog Box + + Parameters + ---------- + title : str + label : str + text : str, optional + Existing string to display in the input dialog + + parent : QWidget, optional + The parent widget for this dialog, if not specified the dialog + may not be destroyed when the main UI application quits. + + Returns + ------- + + """ + new_text, result = QInputDialog.getText(parent, title, label, text=text) + if result: + return new_text + return False + + +def show_in_explorer(path: Path): # pragma: no cover + """Reveal the specified path in the OS's explorer/file-browser/finder + + Parameters + ---------- + path : :class:`pathlib.Path` + + """ + dest = path.absolute().resolve() + if sys.platform == 'darwin': + target = 'oascript' + args = f'-e tell application "Finder" -e activate -e select POSIX file ' \ + f'"{dest!s}" -e end tell' + elif sys.platform == 'win32': + target = 'explorer' + args = shlex.quote(f'{dest!s}') + elif sys.platform == 'linux': + target = 'xdg-open' + args = shlex.quote(f'{dest!s}') + else: + return + + QProcess.startDetached(target, shlex.split(args)) + diff --git a/dgp/core/controllers/controller_interfaces.py b/dgp/core/controllers/controller_interfaces.py new file mode 100644 index 0000000..6f61093 --- /dev/null +++ b/dgp/core/controllers/controller_interfaces.py @@ -0,0 +1,405 @@ +# -*- coding: utf-8 -*- +from pathlib import Path +from typing import Union, Generator, List, Tuple, Any, Set, Dict +from weakref import WeakKeyDictionary, WeakSet, WeakMethod, ref + +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QStandardItem, QStandardItemModel +from PyQt5.QtWidgets import QWidget + +from dgp.core.oid import OID +from dgp.core.controllers.controller_mixins import AttributeProxy +from dgp.core.types.enumerations import DataType, StateAction + +""" +Interface module, while not exactly Pythonic, helps greatly by providing +interface definitions for the various controller modules, which often cannot +be imported as a type hints in various modules due to circular imports. + +Abstract Base Classes (collections.ABC) are not used due to the complications +invited with multiple inheritance and metaclass mis-matching. As most controller +level classes also subclass QStandardItem and/or AttributeProxy. +""" + +MenuBinding = Tuple[str, Tuple[Any, ...]] +MaybeChild = Union['VirtualBaseController', None] + + +class VirtualBaseController(QStandardItem, AttributeProxy): + """VirtualBaseController provides a base interface for creating Controllers + + .. versionadded:: 0.1.0 + + This class provides some concrete implementations for various features + common to all controllers: + + - Encapsulation of a model (dgp.core.models) object + - Exposure of the underlying model entities' UID + - Observer registration (notify observers on StateAction's) + - Clone registration (notify clones of updates to the base object) + - Child lookup function (get_child) to find child by its UID + + The following methods must be explicitly implemented by subclasses: + + - clone() + - menu @property + + The following methods may be optionally implemented by subclasses: + + - children @property + - add_child() + - remove_child() + + Parameters + ---------- + model + The underlying model (from dgp.core.models) entity of this controller + project : :class:`IAirborneController` + A weak-reference is stored to the project controller for direct access + by the controller via the :meth:`project` @property + parent : :class:`VirtualBaseController`, optional + A strong-reference is maintained to the parent controller object, + accessible via the :meth:`get_parent` method + *args + Positional arguments are supplied to the QStandardItem constructor + *kwargs + Keyword arguments are supplied to the QStandardItem constructor + + Notes + ----- + When removing/deleting a controller, the delete() method should be called on + the child, in order for it to notify any subscribers of its impending doom. + + The update method should be extended by subclasses in order to perform + visual updates (e.g. Item text, tooltips) when an entity attribute has been + updated (via AttributeProxy::set_attr), call the super() method to propagate + updates to any observers automatically. + + """ + + def __init__(self, model, project, *args, parent=None, **kwargs): + super().__init__(*args, **kwargs) + self._model = model + self._project = ref(project) if project is not None else None + self._parent: VirtualBaseController = parent + self._clones: Set[VirtualBaseController] = WeakSet() + self.__cloned = False + self._observers: Dict[StateAction, Dict] = {state: WeakKeyDictionary() + for state in StateAction} + + self.setEditable(False) + self.setText(model.name if hasattr(model, "name") else str(model)) + self.setData(model, Qt.UserRole) + + @property + def uid(self) -> OID: + """Return the unique Object IDentifier for the controllers' model + + Returns + ------- + oid : :class:`~dgp.core.OID` + Unique Identifier of this Controller/Entity + + """ + return self._model.uid + + @property + def entity(self): + """Returns the underlying core/model object of this controller""" + return self._model + + @property + def project(self) -> 'IAirborneController': + """Return a reference to the top-level project owner of this controller + + Returns + ------- + :class:`IAirborneController` or :const:`None` + + """ + return self._project() if self._project is not None else None + + @property + def clones(self): + """Yields any active (referenced) clones of this controller + + Yields + ------ + :class:`VirtualBaseController` + + """ + for clone in self._clones: + yield clone + + def clone(self): + """Return a clone of this controller for use in other UI models + + Must be overridden by subclasses, subclasses should call register_clone + on the cloned instance to ensure update events are propagated to the + clone. + + Returns + ------- + :class:`VirtualBaseController` + Clone of this controller with a shared reference to the entity + + """ + raise NotImplementedError + + @property + def is_clone(self) -> bool: + """Determine if this controller is a clone + + Returns + ------- + bool + True if this controller is a clone, else False + + """ + return self.__cloned + + @is_clone.setter + def is_clone(self, value: bool): + self.__cloned = value + + def register_clone(self, clone: 'VirtualBaseController') -> None: + """Registers a cloned copy of this controller for updates + + Parameters + ---------- + clone : :class:`VirtualBaseController` + The cloned copy of the root controller to register + + """ + clone.is_clone = True + self._clones.add(clone) + + @property + def is_active(self) -> bool: + """Return True if there are any active observers of this controller""" + return len(self._observers[StateAction.DELETE]) > 0 + + @property + def menu(self) -> List[MenuBinding]: + """Return a list of MenuBinding's to construct a context menu + + Must be overridden by subclasses + """ + raise NotImplementedError + + @property + def parent_widget(self) -> Union[QWidget, None]: + """Get the parent QWidget of this items' QAbstractModel + + Returns + ------- + :class:`pyqt.QWidget` or :const:`None` + QWidget parent if it exists, else None + """ + try: + return self.model().parent() + except AttributeError: + return None + + def get_parent(self) -> 'VirtualBaseController': + """Get the parent controller of this controller + + Notes + ----- + :meth:`get_parent` and :meth:`set_parent` are defined as methods to + avoid naming conflicts with :class:`pyqt.QStandardItem` parent method. + + Returns + ------- + :class:`VirtualBaseController` or None + Parent controller (if it exists) of this controller + + """ + return self._parent + + def set_parent(self, parent: 'VirtualBaseController'): + self._parent = parent + + def register_observer(self, observer, callback, state: StateAction) -> None: + """Register an observer callback with this controller for the given state + + Observers will be notified when the controller undergoes the applicable + StateAction (UPDATE/DELETE), via the supplied callback method. + + Parameters + ---------- + observer : object + The observer object, note must be weak reference'able, when the + observer is deleted or gc'd any callbacks will be dropped. + callback : bound method + Bound method to call when the state action occurs. + Note this must be a *bound* method of an object, builtin functions + or PyQt signals will raise an error. + state : StateAction + Action to observe in the controller, currently only meaningful for + UPDATE or DELETE + + """ + self._observers[state][observer] = WeakMethod(callback) + + def delete(self) -> None: + """Notify any observers and clones that this controller is being deleted + + Also calls delete() on any children of this controller to cleanup after + the parent has been deleted. + """ + for child in self.children: + child.delete() + for cb in self._observers[StateAction.DELETE].values(): + cb()() + for clone in self.clones: + clone.delete() + + def update(self) -> None: + """Notify observers and clones that the controller has updated""" + for cb in self._observers[StateAction.UPDATE].values(): + cb()() + for clone in self.clones: + clone.update() + + @property + def children(self) -> Generator['VirtualBaseController', None, None]: + """Yields children of this controller + + Override this property to provide generic access to controller children + + Yields + ------ + :class:`VirtualBaseController` + Child controllers + + """ + yield from () + + def add_child(self, child) -> 'VirtualBaseController': + """Add a child object to the controller, and its underlying + data object. + + Parameters + ---------- + child : + The child data object to be added (from :mod:`dgp.core.models`) + + Returns + ------- + :class:`VirtualBaseController` + A reference to the controller object wrapping the added child + + Raises + ------ + :exc:`TypeError` + If the child is not a permissible type for the controller. + """ + pass + + def remove_child(self, uid: OID, confirm: bool = True) -> bool: + """Remove a child from this controller, and notify the child of its deletion + + Parameters + ---------- + uid : OID + OID of the child to remove + confirm : bool, optional + Optionally request that the controller confirms the action before + removing the child, default is True + + Returns + ------- + bool + True on successful removal of child + False on failure (i.e. invalid uid supplied) + + """ + pass + + def get_child(self, uid: OID) -> MaybeChild: + """Get a child of this object by matching OID + + Parameters + ---------- + uid : :class:`~dgp.core.oid.OID` + Unique identifier of the child to get + + Returns + ------- + :const:`MaybeChild` + Returns the child controller object referred to by uid if it exists + else None + + """ + for child in self.children: + if uid == child.uid: + return child + + def __str__(self): + return str(self.entity) + + def __hash__(self): + return hash(self.uid) + + +# noinspection PyAbstractClass +class IAirborneController(VirtualBaseController): + def add_flight_dlg(self): + raise NotImplementedError + + def add_gravimeter_dlg(self): + raise NotImplementedError + + def load_file_dlg(self, datatype: DataType, + flight: 'IFlightController' = None, + dataset: 'IDataSetController' = None): # pragma: no cover + raise NotImplementedError + + @property + def hdfpath(self) -> Path: + raise NotImplementedError + + @property + def path(self) -> Path: + raise NotImplementedError + + @property + def flight_model(self) -> QStandardItemModel: + raise NotImplementedError + + @property + def meter_model(self) -> QStandardItemModel: + raise NotImplementedError + + +# noinspection PyAbstractClass +class IFlightController(VirtualBaseController): + pass + + +# noinspection PyAbstractClass +class IMeterController(VirtualBaseController): + pass + + +# noinspection PyAbstractClass +class IDataSetController(VirtualBaseController): + @property + def hdfpath(self) -> Path: + raise NotImplementedError + + def add_datafile(self, datafile) -> None: + """ + Add a :obj:`DataFile` to the :obj:`DataSetController`, potentially + overwriting an existing file of the same group (gravity/trajectory) + + Parameters + ---------- + datafile : :obj:`DataFile` + + """ + raise NotImplementedError + + def get_datafile(self, group): + raise NotImplementedError diff --git a/dgp/core/controllers/controller_mixins.py b/dgp/core/controllers/controller_mixins.py new file mode 100644 index 0000000..0c3d669 --- /dev/null +++ b/dgp/core/controllers/controller_mixins.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +from typing import Any, Union + +from PyQt5.QtGui import QValidator + + +class AttributeProxy: + """ + This mixin class provides an interface to selectively allow getattr calls + against the proxied or underlying object in a wrapper class. getattr + returns successfully only for attributes decorated with @property in the + proxied instance. + """ + + @property + def entity(self) -> object: + """Return the underlying model of the proxy class.""" + raise NotImplementedError + + def update(self): + """Called when an attribute is set, override this to perform + UI specific updates, e.g. set the DisplayRole data for a component. + """ + pass + + def get_attr(self, key: str) -> Any: + if hasattr(self.entity, key): + return getattr(self.entity, key) + else: + raise AttributeError("Object {!r} has no attribute {}".format(self.entity, key)) + + def set_attr(self, key: str, value: Any): + if not hasattr(self.entity, key): + raise AttributeError("Object {!r} has no attribute {}".format(self.entity, key)) + if not self.writeable(key): + raise AttributeError("Attribute [{}] is not writeable".format(key)) + + validator = self.validator(key) + if validator is not None: + valid = validator.validate(value, 0)[0] + if not valid == QValidator.Acceptable: + raise ValueError("Value does not pass validation") + + setattr(self.entity, key, value) + self.update() + + def writeable(self, key: str) -> bool: + """Get the write status for a specified proxied attribute key. + + Override this method to implement write-protection on proxied attributes. + + Parameters + ---------- + key : str + The attribute key to retrieve write status of + + Returns + ------- + bool + True if attribute is writeable + False if attribute is write-protected (set_attr calls will fail) + + """ + return True + + def validator(self, key: str) -> Union[QValidator, None]: + """Get the QValidator class for a specified proxied attribute key. + + Override this method to implement write-validation on attributes. + + This method should return a QValidator subtype for the specified + key, or None if no validation should occur. + """ + return None diff --git a/dgp/core/controllers/datafile_controller.py b/dgp/core/controllers/datafile_controller.py new file mode 100644 index 0000000..41278bf --- /dev/null +++ b/dgp/core/controllers/datafile_controller.py @@ -0,0 +1,86 @@ +# -*- coding: utf-8 -*- +import logging +from typing import cast, Generator + +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QIcon + +from dgp.core import DataType +from dgp.core.hdf5_manager import HDF5Manager +from dgp.core.oid import OID +from dgp.core.types.enumerations import Icon +from dgp.core.controllers.controller_interfaces import IDataSetController, VirtualBaseController +from dgp.core.controllers.controller_helpers import show_in_explorer +from dgp.core.models.datafile import DataFile + + +class DataFileController(VirtualBaseController): + def __init__(self, datafile: DataFile, project: VirtualBaseController, + parent: IDataSetController = None): + super().__init__(datafile, project, parent=parent) + self.log = logging.getLogger(__name__) + + self.set_datafile(datafile) + + self._bindings = [ + ('addAction', ('Properties', self._properties_dlg)), + ('addAction', (Icon.OPEN_FOLDER.icon(), 'Show in Explorer', + self._launch_explorer)) + ] + self.update() + + @property + def uid(self) -> OID: + try: + return super().uid + # This can occur when no underlying datafile is set + # TODO: This behavior should change in future, a better way to handle + # empty/unset data files is needed + except AttributeError: + return None + + @property + def entity(self) -> DataFile: + return cast(DataFile, super().entity) + + @property + def menu(self): # pragma: no cover + return self._bindings + + @property + def group(self): + return self.entity.group + + def clone(self): + raise NotImplementedError + + def update(self): + super().update() + if self.entity is not None: + self.setText(self.entity.name) + + def set_datafile(self, datafile: DataFile): + self._model = datafile + if datafile is None: + self.setText("No Data") + self.setToolTip("No Data") + self.setData(None, Qt.UserRole) + else: + self.setText(datafile.label) + self.setToolTip("Source path: {!s}".format(datafile.source_path)) + self.setData(datafile, role=Qt.UserRole) + if self.entity.group is DataType.GRAVITY: + self.setIcon(Icon.GRAVITY.icon()) + elif self.entity.group is DataType.TRAJECTORY: + self.setIcon(Icon.TRAJECTORY.icon()) + + def _properties_dlg(self): # pragma: no cover + if self.entity is None: + return + # TODO: Launch dialog to show datafile properties (name, path, data etc) + data = HDF5Manager.load_data(self.entity, self.get_parent().hdfpath) + self.log.info(f'\n{data.describe()}') + + def _launch_explorer(self): # pragma: no cover + if self.entity is not None: + show_in_explorer(self.entity.source_path.parent) diff --git a/dgp/core/controllers/dataset_controller.py b/dgp/core/controllers/dataset_controller.py new file mode 100644 index 0000000..425660f --- /dev/null +++ b/dgp/core/controllers/dataset_controller.py @@ -0,0 +1,286 @@ +# -*- coding: utf-8 -*- +import logging +import warnings +import weakref +from pathlib import Path +from typing import List, Union, Set, cast + +from PyQt5.QtWidgets import QInputDialog +from pandas import DataFrame, Timestamp, concat +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QStandardItemModel, QStandardItem + +from dgp.core import OID, Icon +from dgp.core.hdf5_manager import HDF5Manager +from dgp.core.models.datafile import DataFile +from dgp.core.models.dataset import DataSet, DataSegment +from dgp.core.types.enumerations import DataType +from dgp.lib.etc import align_frames +from dgp.gui.plotting.helpers import LineUpdate + +from . import controller_helpers +from .gravimeter_controller import GravimeterController +from .controller_interfaces import IFlightController, IDataSetController, VirtualBaseController +from .project_containers import ProjectFolder +from .datafile_controller import DataFileController + +_log = logging.getLogger(__name__) + + +class DataSegmentController(VirtualBaseController): + """Controller for :class:`DataSegment` + + Implements reference tracking feature allowing the mutation of segments + representations displayed on a plot surface. + """ + def __init__(self, segment: DataSegment, project, + parent: IDataSetController = None): + super().__init__(segment, project, parent=parent) + self.update() + + self._menu = [ + ('addAction', ('Delete', self._action_delete)), + ('addAction', ('Properties', self._action_properties)) + ] + + @property + def entity(self) -> DataSegment: + return cast(DataSegment, super().entity) + + @property + def menu(self): + return self._menu + + def clone(self) -> 'DataSegmentController': + clone = DataSegmentController(self.entity, self.project, self.get_parent()) + self.register_clone(clone) + return clone + + def _action_delete(self): + self.get_parent().remove_child(self.uid, confirm=True) + + def update(self): + super().update() + self.setText(str(self.entity)) + self.setToolTip(repr(self.entity)) + + def _action_properties(self): + warnings.warn("Properties feature not yet implemented") + + +class DataSetController(IDataSetController): + def __init__(self, dataset: DataSet, project, flight: IFlightController): + super().__init__(model=dataset, project=project, parent=flight) + + self.setIcon(Icon.PLOT_LINE.icon()) + self._grav_file = DataFileController(self.entity.gravity, self.project, self) + self._traj_file = DataFileController(self.entity.trajectory, self.project, self) + self._child_map = {DataType.GRAVITY: self._grav_file, + DataType.TRAJECTORY: self._traj_file} + + self._segments = ProjectFolder("Segments", Icon.LINE_MODE.icon()) + for segment in dataset.segments: + seg_ctrl = DataSegmentController(segment, project, parent=self) + self._segments.appendRow(seg_ctrl) + + self.appendRow(self._grav_file) + self.appendRow(self._traj_file) + self.appendRow(self._segments) + + self._sensor = None + if dataset.sensor is not None: + ctrl = self.project.get_child(dataset.sensor.uid) + if ctrl is not None: + self._sensor = ctrl.clone() + self.appendRow(self._sensor) + + self._gravity: DataFrame = DataFrame() + self._trajectory: DataFrame = DataFrame() + self._dataframe: DataFrame = DataFrame() + + self._channel_model = QStandardItemModel() + + self._menu_bindings = [ # pragma: no cover + ('addAction', ('Open', lambda: self.model().item_activated(self.index()))), + ('addAction', ('Set Name', self._action_set_name)), + ('addAction', (Icon.METER.icon(), 'Set Sensor', + self._action_set_sensor_dlg)), + ('addSeparator', ()), + ('addAction', (Icon.GRAVITY.icon(), 'Import Gravity', + lambda: self.project.load_file_dlg(DataType.GRAVITY, dataset=self))), + ('addAction', (Icon.TRAJECTORY.icon(), 'Import Trajectory', + lambda: self.project.load_file_dlg(DataType.TRAJECTORY, dataset=self))), + ('addAction', ('Align Data', self.align)), + ('addSeparator', ()), + ('addAction', ('Delete', self._action_delete)), + ('addAction', ('Properties', self._action_properties)) + ] + + self._clones: Set[DataSetController] = weakref.WeakSet() + + def clone(self): + clone = DataSetController(self.entity, self.get_parent(), self.project) + self.register_clone(clone) + return clone + + @property + def entity(self) -> DataSet: + return cast(DataSet, super().entity) + + @property + def menu(self): # pragma: no cover + return self._menu_bindings + + @property + def hdfpath(self) -> Path: + return self.project.hdfpath + + @property + def series_model(self) -> QStandardItemModel: + if 0 == self._channel_model.rowCount(): + self._update_channel_model() + return self._channel_model + + @property + def segment_model(self) -> QStandardItemModel: # pragma: no cover + return self._segments.internal_model + + @property + def columns(self) -> List[str]: + return [col for col in self.dataframe()] + + def _update_channel_model(self): + df = self.dataframe() + self._channel_model.clear() + for col in df: + series_item = QStandardItem(col) + series_item.setData(df[col], Qt.UserRole) + self._channel_model.appendRow(series_item) + + @property + def gravity(self) -> Union[DataFrame]: + if not self._gravity.empty: + return self._gravity + if self.entity.gravity is None: + return self._gravity + try: + self._gravity = HDF5Manager.load_data(self.entity.gravity, self.hdfpath) + except Exception: + _log.exception(f'Exception loading gravity from HDF') + finally: + return self._gravity + + @property + def trajectory(self) -> Union[DataFrame, None]: + if not self._trajectory.empty: + return self._trajectory + if self.entity.trajectory is None: + return self._trajectory + try: + self._trajectory = HDF5Manager.load_data(self.entity.trajectory, self.hdfpath) + except Exception: + _log.exception(f'Exception loading trajectory data from HDF') + finally: + return self._trajectory + + def dataframe(self) -> DataFrame: + if self._dataframe.empty: + self._dataframe: DataFrame = concat([self.gravity, self.trajectory], axis=1, sort=True) + return self._dataframe + + def align(self): # pragma: no cover + """ + TODO: Utility of this is questionable, is it built into transform graphs? + """ + if self.gravity.empty or self.trajectory.empty: + _log.info(f'Gravity or Trajectory is empty, cannot align.') + return + from dgp.lib.gravity_ingestor import DGS_AT1A_INTERP_FIELDS + from dgp.lib.trajectory_ingestor import TRAJECTORY_INTERP_FIELDS + + fields = DGS_AT1A_INTERP_FIELDS | TRAJECTORY_INTERP_FIELDS + n_grav, n_traj = align_frames(self._gravity, self._trajectory, + interp_only=fields) + self._gravity = n_grav + self._trajectory = n_traj + _log.info(f'DataFrame aligned.') + + def add_datafile(self, datafile: DataFile) -> None: + if datafile.group is DataType.GRAVITY: + self.entity.gravity = datafile + self._grav_file.set_datafile(datafile) + self._gravity = DataFrame() + elif datafile.group is DataType.TRAJECTORY: + self.entity.trajectory = datafile + self._traj_file.set_datafile(datafile) + self._trajectory = DataFrame() + else: + raise TypeError("Invalid DataFile group provided.") + + self._dataframe = DataFrame() + self._update_channel_model() + + def get_datafile(self, group) -> DataFileController: + return self._child_map[group] + + @property + def children(self): + for i in range(self._segments.rowCount()): + yield self._segments.child(i) + + def add_child(self, child: LineUpdate) -> DataSegmentController: + """Add a DataSegment as a child to this DataSet""" + + segment = DataSegment(child.uid, child.start, child.stop, + self._segments.rowCount(), label=child.label) + self.entity.segments.append(segment) + segment_c = DataSegmentController(segment, self.project, parent=self) + self._segments.appendRow(segment_c) + return segment_c + + def remove_child(self, uid: OID, confirm: bool = True): + # if confirm: + # pass + seg_c: DataSegmentController = self.get_child(uid) + if seg_c is None: + raise KeyError("Invalid uid supplied, child does not exist.") + + _log.debug(f'Deleting segment {seg_c} {uid}') + seg_c.delete() + self._segments.removeRow(seg_c.row()) + self.entity.segments.remove(seg_c.entity) + + def update(self): + self.setText(self.entity.name) + super().update() + + # Context Menu Handlers + def _action_set_name(self): # pragma: no cover + name = controller_helpers.get_input("Set DataSet Name", "Enter a new name:", + self.get_attr('name'), + parent=self.parent_widget) + if name: + self.set_attr('name', name) + + def _action_set_sensor_dlg(self): # pragma: no cover + sensors = {} + for i in range(self.project.meter_model.rowCount()): + sensor = self.project.meter_model.item(i) + sensors[sensor.text()] = sensor + + item, ok = QInputDialog.getItem(self.parent_widget, "Select Gravimeter", + "Sensor", sensors.keys(), editable=False) + if ok: + if self._sensor is not None: + self.removeRow(self._sensor.row()) + + sensor: GravimeterController = sensors[item] + self.set_attr('sensor', sensor) + self._sensor: GravimeterController = sensor.clone() + self.appendRow(self._sensor) + + def _action_delete(self, confirm: bool = True): # pragma: no cover + self.get_parent().remove_child(self.uid, confirm) + + def _action_properties(self): # pragma: no cover + warnings.warn("Properties action not yet implemented") diff --git a/dgp/core/controllers/flight_controller.py b/dgp/core/controllers/flight_controller.py new file mode 100644 index 0000000..7ab0f75 --- /dev/null +++ b/dgp/core/controllers/flight_controller.py @@ -0,0 +1,201 @@ +# -*- coding: utf-8 -*- +import logging +from typing import Union, Generator, cast + +from PyQt5.QtGui import QStandardItemModel + +from . import controller_helpers as helpers +from dgp.core.oid import OID +from dgp.core.controllers.dataset_controller import DataSetController +from dgp.core.controllers.controller_interfaces import IAirborneController, IFlightController +from dgp.core.models.dataset import DataSet +from dgp.core.models.flight import Flight +from dgp.core.types.enumerations import DataType, Icon +from dgp.gui.dialogs.add_flight_dialog import AddFlightDialog + + +class FlightController(IFlightController): + """ + FlightController is a wrapper around :obj:`Flight` objects, and provides + a presentation and interaction layer for use of the underlying Flight + instance. + All user-space mutations or queries to a Flight object should be proxied + through a FlightController in order to ensure that the data and presentation + state is kept synchronized. + + As a subclass of :obj:`QStandardItem` the FlightController can be directly + added as a child to another QStandardItem, or as a row/child in a + :obj:`QAbstractItemModel` or :obj:`QStandardItemModel` + The default display behavior is to provide the Flights Name. + A :obj:`QIcon` or string path to a resource can be provided for decoration. + + FlightController implements the AttributeProxy mixin (via VirtualBaseController), + which allows access to the underlying :class:`Flight` attributes via the + get_attr and set_attr methods. + + Parameters + ---------- + flight : :class:`Flight` + The underlying Flight model object to wrap with this controller + project : :class:`IAirborneController` + The parent (owning) project for this flight controller + + """ + + def __init__(self, flight: Flight, project: IAirborneController): + """Assemble the view/controller repr from the base flight object.""" + super().__init__(model=flight, project=project, parent=project) + self.log = logging.getLogger(__name__) + self.setIcon(Icon.AIRBORNE.icon()) + + self._dataset_model = QStandardItemModel() + + for dataset in self.entity.datasets: + control = DataSetController(dataset, project, self) + self.appendRow(control) + self._dataset_model.appendRow(control.clone()) + + # Add a default DataSet if none defined + if not len(self.entity.datasets): + self.add_child(DataSet(name='DataSet-0')) + + # TODO: Consider adding MenuPrototype class which could provide the means to build QMenu + self._bindings = [ # pragma: no cover + ('addAction', ('Add Dataset', self._add_dataset)), + ('addAction', ('Open Flight Tab', lambda: self.model().item_activated(self.index()))), + ('addAction', ('Import Gravity', + lambda: self._load_file_dialog(DataType.GRAVITY))), + ('addAction', ('Import Trajectory', + lambda: self._load_file_dialog(DataType.TRAJECTORY))), + ('addSeparator', ()), + ('addAction', (f'Delete {self.entity.name}', self._action_delete_self)), + ('addAction', ('Rename Flight', self._set_name)), + ('addAction', ('Properties', self._show_properties_dlg)) + ] + self.update() + + @property + def entity(self) -> Flight: + return cast(Flight, super().entity) + + @property + def children(self) -> Generator[DataSetController, None, None]: + for i in range(self.rowCount()): + yield self.child(i, 0) + + @property + def menu(self): # pragma: no cover + return self._bindings + + @property + def datasets(self) -> QStandardItemModel: + return self._dataset_model + + def update(self): + self.setText(self.entity.name) + self.setToolTip(str(self.entity.uid)) + super().update() + + def clone(self): + clone = FlightController(self.entity, self.project) + self.register_clone(clone) + return clone + + def add_child(self, child: DataSet) -> DataSetController: + """Adds a child to the underlying Flight, and to the model representation + for the appropriate child type. + + Parameters + ---------- + child : :obj:`DataSet` + The child model instance - either a FlightLine or DataFile + + Returns + ------- + :obj:`DataSetController` + Returns a reference to the controller encapsulating the added child + + Raises + ------ + :exc:`TypeError` + if child is not a :obj:`DataSet` + + """ + if not isinstance(child, DataSet): + raise TypeError(f'Invalid child of type {type(child)} supplied to' + f'FlightController, must be {type(DataSet)}') + + self.entity.datasets.append(child) + control = DataSetController(child, self.project, self) + self.appendRow(control) + self._dataset_model.appendRow(control.clone()) + self.update() + return control + + def remove_child(self, uid: OID, confirm: bool = True) -> bool: + """ + Remove the specified child primitive from the underlying + :obj:`~dgp.core.models.flight.Flight` and from the respective model + representation within the FlightController + + Parameters + ---------- + uid : :obj:`OID` + The child model object to be removed + confirm : bool, optional + If True spawn a confirmation dialog requiring user confirmation + + Returns + ------- + bool + True if successful + False if user does not confirm removal action + + Raises + ------ + :exc:`TypeError` + if child is not a :obj:`FlightLine` or :obj:`DataFile` + + """ + child = self.get_child(uid) + if child is None: + raise KeyError(f'Child with uid {uid!s} not in flight {self!s}') + if confirm: # pragma: no cover + if not helpers.confirm_action("Confirm Deletion", + f'Are you sure you want to delete {child!r}', + self.parent_widget): + return False + + child.delete() + self.entity.datasets.remove(child.entity) + self._dataset_model.removeRow(child.row()) + self.removeRow(child.row()) + self.update() + return True + + def get_child(self, uid: Union[OID, str]) -> DataSetController: + return super().get_child(uid) + + # Menu Action Handlers + def _activate_self(self): + self.get_parent().activate_child(self.uid, emit=True) + + def _add_dataset(self): + self.add_child(DataSet(name=f'DataSet-{self.datasets.rowCount()}')) + + def _action_delete_self(self, confirm: bool = True): + self.get_parent().remove_child(self.uid, confirm) + + def _set_name(self): # pragma: no cover + name = helpers.get_input("Set Name", "Enter a new name:", + self.get_attr('name'), + parent=self.parent_widget) + if name: + self.set_attr('name', name) + + def _load_file_dialog(self, datatype: DataType): # pragma: no cover + self.get_parent().load_file_dlg(datatype, flight=self) + + def _show_properties_dlg(self): # pragma: no cover + AddFlightDialog.from_existing(self, self.get_parent(), + parent=self.parent_widget).exec_() diff --git a/dgp/core/controllers/gravimeter_controller.py b/dgp/core/controllers/gravimeter_controller.py new file mode 100644 index 0000000..98638b5 --- /dev/null +++ b/dgp/core/controllers/gravimeter_controller.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +from typing import cast + +from dgp.core import Icon +from dgp.core.controllers.controller_interfaces import IAirborneController, IMeterController +from dgp.core.controllers.controller_helpers import get_input +from dgp.core.models.meter import Gravimeter + + +class GravimeterController(IMeterController): + + def __init__(self, meter: Gravimeter, project, parent: IAirborneController = None): + super().__init__(meter, project, parent=parent) + self.setIcon(Icon.METER.icon()) + + self._bindings = [ + ('addAction', ('Delete <%s>' % self.entity.name, + (lambda: self.get_parent().remove_child(self.uid, True)))), + ('addAction', ('Rename', self.set_name_dlg)) + ] + + @property + def entity(self) -> Gravimeter: + return cast(Gravimeter, super().entity) + + @property + def menu(self): + return self._bindings + + def clone(self): + clone = GravimeterController(self.entity, self.project) + self.register_clone(clone) + return clone + + def update(self): + self.setText(self.entity.name) + super().update() + + def set_name_dlg(self): # pragma: no cover + name = get_input("Set Name", "Enter a new name:", self.entity.name, + self.parent_widget) + if name: + self.set_attr('name', name) + diff --git a/dgp/core/controllers/project_containers.py b/dgp/core/controllers/project_containers.py new file mode 100644 index 0000000..edaf2d0 --- /dev/null +++ b/dgp/core/controllers/project_containers.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +from typing import Generator + +from PyQt5.QtGui import QStandardItem, QStandardItemModel, QIcon + +from dgp.core import Icon + + +class ProjectFolder(QStandardItem): + """Displayable StandardItem used for grouping sub-elements. + An internal QStandardItemModel representation is maintained for use in + other Qt elements e.g. a combo-box or list view. + + The ProjectFolder (QStandardItem) appends the source item to itself + for display in a view, a clone of the item is created and also added to + an internal QStandardItemModel for + + Notes + ----- + Overriding object methods like __getitem__ __iter__ etc seems to break + """ + + def __init__(self, label: str, icon: QIcon = None, **kwargs): + super().__init__(label) + if icon is None: + icon = Icon.OPEN_FOLDER.icon() + self.setIcon(icon) + self._model = QStandardItemModel() + self.setEditable(False) + self._attributes = kwargs + + @property + def internal_model(self) -> QStandardItemModel: + return self._model + + def appendRow(self, item: QStandardItem): + """ + Notes + ----- + The same item cannot be added to two parents as the parent attribute + is mutated when added. Use clone() or similar method to create two identical copies. + """ + super().appendRow(item) + self._model.appendRow(item.clone()) + + def removeRow(self, row: int): + super().removeRow(row) + self._model.removeRow(row) + + def items(self) -> Generator[QStandardItem, None, None]: + return (self.child(i, 0) for i in range(self.rowCount())) diff --git a/dgp/core/controllers/project_controllers.py b/dgp/core/controllers/project_controllers.py new file mode 100644 index 0000000..9ca9adf --- /dev/null +++ b/dgp/core/controllers/project_controllers.py @@ -0,0 +1,296 @@ +# -*- coding: utf-8 -*- +import functools +import itertools +import logging +from pathlib import Path +from typing import Union, List, Generator, cast + +from PyQt5.QtCore import Qt, QRegExp +from PyQt5.QtGui import QColor, QStandardItemModel, QRegExpValidator +from pandas import DataFrame + +from .project_treemodel import ProjectTreeModel +from .flight_controller import FlightController +from .gravimeter_controller import GravimeterController +from .project_containers import ProjectFolder +from .controller_helpers import confirm_action, get_input, show_in_explorer +from .controller_interfaces import (IAirborneController, IFlightController, + IDataSetController) +from dgp.core.oid import OID +from dgp.core.file_loader import FileLoader +from dgp.core.hdf5_manager import HDF5Manager +from dgp.core.models.datafile import DataFile +from dgp.core.models.flight import Flight +from dgp.core.models.meter import Gravimeter +from dgp.core.models.project import GravityProject, AirborneProject +from dgp.core.types.enumerations import DataType, Icon, StateColor +from dgp.gui.utils import ProgressEvent +from dgp.gui.dialogs.add_flight_dialog import AddFlightDialog +from dgp.gui.dialogs.add_gravimeter_dialog import AddGravimeterDialog +from dgp.gui.dialogs.data_import_dialog import DataImportDialog +from dgp.gui.dialogs.project_properties_dialog import ProjectPropertiesDialog +from dgp.lib.gravity_ingestor import read_at1a +from dgp.lib.trajectory_ingestor import import_trajectory + + +class AirborneProjectController(IAirborneController): + """Construct an AirborneProjectController around an AirborneProject + + Parameters + ---------- + project : :class:`AirborneProject` + path : :class:`pathlib.Path`, Optional + Optionally supply the directory path where the project was loaded from + in order to update the stored state. + + """ + def __init__(self, project: AirborneProject, path: Path = None): + super().__init__(project, self) + self.log = logging.getLogger(__name__) + if path: + self.entity.path = path + + self._active = None + + self.setIcon(Icon.DGP_NOTEXT.icon()) + self.setToolTip(str(self.entity.path.resolve())) + + self.flights = ProjectFolder("Flights") + self.appendRow(self.flights) + self.meters = ProjectFolder("Gravimeters") + self.appendRow(self.meters) + + self._child_map = {Flight: self.flights, + Gravimeter: self.meters} + + # It is important that GravimeterControllers are defined before Flights + # Flights may create references to a Gravimeter object, but not vice versa + for meter in self.entity.gravimeters: + controller = GravimeterController(meter, self, parent=self) + self.meters.appendRow(controller) + + for flight in self.entity.flights: + controller = FlightController(flight, project=self) + self.flights.appendRow(controller) + + self._bindings = [ + ('addAction', ('Set Project Name', self.set_name)), + ('addAction', ('Show in Explorer', + lambda: show_in_explorer(self.path))), + ('addAction', ('Project Properties', self.properties_dlg)), + ('addAction', ('Close Project', self._close_project)) + ] + + # Experiment - declare underlying properties for UI use + # dict key is the attr name (use get_attr to retrieve the value) + # tuple of ( editable: True/False, Validator: QValidator ) + self._fields = { + 'name': (True, QRegExpValidator(QRegExp("[A-Za-z]+.{4,30}"))), + 'uid': (False, None), + 'path': (False, None), + 'description': (True, None), + 'create_date': (False, None), + 'modify_date': (False, None) + } + + def validator(self, key: str): # pragma: no cover + if key in self._fields: + return self._fields[key][1] + return None + + def writeable(self, key: str): # pragma: no cover + if key in self._fields: + return self._fields[key][0] + return True + + @property + def entity(self) -> AirborneProject: + return cast(AirborneProject, super().entity) + + @property + def menu(self): # pragma: no cover + return self._bindings + + def clone(self): + raise NotImplementedError + + @property + def children(self) -> Generator[IFlightController, None, None]: + for child in itertools.chain(self.flights.items(), self.meters.items()): + yield child + + @property + def fields(self) -> List[str]: + """Return list of public attribute keys (for UI display)""" + return list(self._fields.keys()) + + @property + def path(self) -> Path: + return self.entity.path + + @property + def hdfpath(self) -> Path: + return self.entity.path.joinpath("dgpdata.hdf5") + + @property + def meter_model(self) -> QStandardItemModel: + return self.meters.internal_model + + @property + def flight_model(self) -> QStandardItemModel: + return self.flights.internal_model + + def add_child(self, child: Union[Flight, Gravimeter]) -> Union[FlightController, GravimeterController]: + if isinstance(child, Flight): + controller = FlightController(child, self) + self.flights.appendRow(controller) + elif isinstance(child, Gravimeter): + controller = GravimeterController(child, self, parent=self) + self.meters.appendRow(controller) + else: + raise ValueError("{0!r} is not a valid child type for {1.__name__}".format(child, self.__class__)) + self.entity.add_child(child) + self.update() + return controller + + def remove_child(self, uid: OID, confirm: bool = True): + child = self.get_child(uid) + if child is None: + self.log.warning(f'UID {uid!s} has no corresponding object in this ' + f'project') + raise KeyError(f'{uid!s}') + if confirm: # pragma: no cover + if not confirm_action("Confirm Deletion", + "Are you sure you want to delete {!s}" + .format(child.get_attr('name')), + parent=self.parent_widget): + return + + child.delete() + self.entity.remove_child(child.uid) + self._child_map[child.entity.__class__].removeRow(child.row()) + self.update() + + def get_parent(self) -> ProjectTreeModel: + return self.model() + + def get_child(self, uid: Union[str, OID]) -> Union[FlightController, + GravimeterController]: + return super().get_child(uid) + + def set_active(self, state: bool): + self._active = bool(state) + if self._active: + self.setBackground(QColor(StateColor.ACTIVE.value)) + else: + self.setBackground(QColor(StateColor.INACTIVE.value)) + + @property + def is_active(self): + return self._active + + def save(self, to_file=True): + return self.entity.to_json(indent=2, to_file=to_file) + + def set_name(self): # pragma: no cover + new_name = get_input("Set Project Name", "Enter a Project Name", + self.entity.name, parent=self.parent_widget) + if new_name: + self.set_attr('name', new_name) + + def add_flight_dlg(self): # pragma: no cover + dlg = AddFlightDialog(project=self, parent=self.parent_widget) + return dlg.exec_() + + def add_gravimeter_dlg(self): # pragma: no cover + """Launch a Dialog to import a Gravimeter configuration""" + dlg = AddGravimeterDialog(self, parent=self.parent_widget) + return dlg.exec_() + + def update(self): # pragma: no cover + """Emit an update event from the parent Model, signalling that + data has been added/removed/modified in the project.""" + self.setText(self.entity.name) + try: + self.get_parent().project_mutated(self) + except AttributeError: + self.log.warning(f"project {self.get_attr('name')} has no parent") + super().update() + + def _post_load(self, datafile: DataFile, dataset: IDataSetController, + data: DataFrame) -> None: # pragma: no cover + """ + This is a slot called upon successful loading of a DataFile by a + FileLoader Thread. + + Parameters + ---------- + datafile : :obj:`dgp.core.models.data.DataFile` + The DataFile reference object to be processed + data : DataFrame + The ingested pandas DataFrame to be dumped to the HDF5 store + + """ + if HDF5Manager.save_data(data, datafile, path=self.hdfpath): + self.log.info("Data imported and saved to HDF5 Store") + dataset.add_datafile(datafile) + try: + self.get_parent().project_mutated(self) + except AttributeError: + self.log.warning(f"project {self.get_attr('name')} has no parent") + + def load_file_dlg(self, datatype: DataType = DataType.GRAVITY, + flight: IFlightController = None, + dataset: IDataSetController = None) -> None: # pragma: no cover + """ + Project level dialog for importing/loading Gravity or Trajectory data + files. The Dialog generates a DataFile and a parameter map (dict) which + is passed along to a FileLoader thread to ingest the raw data-file. + On completion of the FileLoader, AirborneProjectController._post_load is + called, which saves the ingested data to the project's HDF5 file, and + adds the DataFile object to the relevant parent. + + Parameters + ---------- + datatype : DataType + + flight : IFlightController, optional + Set the default flight selected when launching the dialog + dataset : IDataSetController, optional + Set the default Dataset selected when launching the dialog + + """ + def _on_load(datafile: DataFile, params: dict, parent: IDataSetController): + if datafile.group is DataType.GRAVITY: + method = read_at1a + elif datafile.group is DataType.TRAJECTORY: + method = import_trajectory + else: + self.log.error("Unrecognized data group: " + datafile.group) + return + progress_event = ProgressEvent(self.uid, f"Loading " + f"{datafile.group.value}", + stop=0) + self.get_parent().progressNotificationRequested.emit(progress_event) + loader = FileLoader(datafile.source_path, method, + parent=self.parent_widget, **params) + loader.loaded.connect(functools.partial(self._post_load, datafile, + parent)) + loader.finished.connect(lambda: self.get_parent().progressNotificationRequested.emit(progress_event)) + loader.start() + + dlg = DataImportDialog(self, datatype, parent=self.parent_widget) + if flight is not None: + dlg.set_initial_flight(flight) + dlg.load.connect(_on_load) + dlg.exec_() + + def properties_dlg(self): # pragma: no cover + dlg = ProjectPropertiesDialog(self, parent=self.parent_widget) + dlg.exec_() + + def _close_project(self): + try: + self.get_parent().remove_project(self) + except AttributeError: + self.log.warning(f"project {self.get_attr('name')} has no parent") diff --git a/dgp/core/controllers/project_treemodel.py b/dgp/core/controllers/project_treemodel.py new file mode 100644 index 0000000..83b68c5 --- /dev/null +++ b/dgp/core/controllers/project_treemodel.py @@ -0,0 +1,152 @@ +# -*- coding: utf-8 -*- +import logging +from typing import Optional, Generator, Union + +from PyQt5.QtCore import QObject, QModelIndex, pyqtSignal +from PyQt5.QtGui import QStandardItemModel + +from dgp.core import OID, DataType +from dgp.core.controllers.controller_interfaces import (IFlightController, + IAirborneController, + IDataSetController, + VirtualBaseController) +from dgp.core.controllers.controller_helpers import confirm_action +from dgp.gui.utils import ProgressEvent + +__all__ = ['ProjectTreeModel'] + + +class ProjectTreeModel(QStandardItemModel): + activeProjectChanged = pyqtSignal(str) + projectMutated = pyqtSignal() + projectClosed = pyqtSignal(OID) + tabOpenRequested = pyqtSignal(object, object) + progressNotificationRequested = pyqtSignal(ProgressEvent) + sigDataChanged = pyqtSignal(object) + + """Extension of QStandardItemModel which handles Project/Model specific + events and defines signals for domain specific actions. + + All signals/events should be connected via the model vs the View itself. + + Parameters + ---------- + project : IAirborneController + parent : QObject, optional + + Attributes + ---------- + activeProjectChanged : pyqtSignal(str) + Signal emitted to notify application that the active project has changed + the name of the newly activated project is passed. + projectMutated : pyqtSignal[] + Signal emitted to notify application that project data has changed. + tabOpenRequested : pyqtSignal[IFlightController] + Signal emitted to request a tab be opened for the supplied Flight + progressNotificationRequested : pyqtSignal[ProgressEvent] + Signal emitted to request a QProgressDialog from the main window. + ProgressEvent is passed defining the parameters for the progress bar + + """ + def __init__(self, project: IAirborneController = None, + parent: Optional[QObject] = None): + super().__init__(parent) + self.log = logging.getLogger(__name__) + if project is not None: + self.appendRow(project) + project.set_active(True) + + @property + def active_project(self) -> Union[IAirborneController, None]: + """Return the active project, if no projects are active then activate + and return the next project which is a child of the model. + + Returns + ------- + IAirborneController or None + The first project controller where is_active is True + If no projects exist in the model None will be returned instead + """ + active = next((prj for prj in self.projects if prj.is_active), None) + if active is None: + try: + active = next(self.projects) + active.set_active(True) + self.activeProjectChanged.emit(active.get_attr('name')) + return active + except StopIteration: + return None + else: + return active + + @property + def projects(self) -> Generator[IAirborneController, None, None]: + for i in range(self.rowCount()): + yield self.item(i, 0) + + def add_project(self, child: IAirborneController): + self.appendRow(child) + + def remove_project(self, child: IAirborneController, + confirm: bool = True) -> None: # pragma: no cover + if confirm and not confirm_action("Confirm Project Close", + f"Close Project " + f"{child.get_attr('name')}?", + self.parent()): + return + child.save() + child.delete() + self.removeRow(child.row()) + self.projectClosed.emit(child.uid) + + def item_selected(self, index: QModelIndex): + """Single-click handler for View events""" + pass + + def item_activated(self, index: QModelIndex): + """Double-click handler for View events""" + + item = self.itemFromIndex(index) + if not isinstance(item, VirtualBaseController): + return + + if isinstance(item, IAirborneController): + for project in self.projects: + if project is item: + project.set_active(True) + else: + project.set_active(False) + self.activeProjectChanged.emit(item.get_attr('name')) + + self.tabOpenRequested.emit(item.uid, item) + + def project_mutated(self, project: IAirborneController): + self.projectMutated.emit() + + def save_projects(self): + for i in range(self.rowCount()): + prj: IAirborneController = self.item(i, 0) + prj.save() + + def import_gps(self): # pragma: no cover + if self.active_project is None: + return self._warn_no_active_project() + self.active_project.load_file_dlg(DataType.TRAJECTORY) + + def import_gravity(self): # pragma: no cover + if self.active_project is None: + return self._warn_no_active_project() + self.active_project.load_file_dlg(DataType.GRAVITY) + + def add_gravimeter(self): # pragma: no cover + if self.active_project is None: + return self._warn_no_active_project() + self.active_project.add_gravimeter_dlg() + + def add_flight(self): # pragma: no cover + if self.active_project is None: + return self._warn_no_active_project() + self.active_project.add_flight_dlg() + + def _warn_no_active_project(self): # pragma: no cover + self.log.warning("No active projects.") diff --git a/dgp/core/file_loader.py b/dgp/core/file_loader.py new file mode 100644 index 0000000..ff2582e --- /dev/null +++ b/dgp/core/file_loader.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +import inspect +import logging +from pathlib import Path +from typing import Callable + +from PyQt5.QtCore import QThread +from PyQt5.QtCore import pyqtSignal +from pandas import DataFrame + + +class FileLoader(QThread): + loaded = pyqtSignal(DataFrame, Path) + error = pyqtSignal(object) + + def __init__(self, path: Path, method: Callable, parent, **kwargs): + super().__init__(parent=parent) + self.log = logging.getLogger(__name__) + self._path = Path(path) + self._method = method + self._kwargs = kwargs + + def run(self): + try: + sig = inspect.signature(self._method) + kwargs = {k: v for k, v in self._kwargs.items() if k in sig.parameters} + result = self._method(str(self._path), **kwargs) + except Exception as e: + self.log.exception("Error loading datafile: %s" % str(self._path)) + self.error.emit(e) + else: + self.loaded.emit(result, self._path) diff --git a/dgp/core/hdf5_manager.py b/dgp/core/hdf5_manager.py new file mode 100644 index 0000000..2534a9a --- /dev/null +++ b/dgp/core/hdf5_manager.py @@ -0,0 +1,168 @@ +# -*- coding: utf-8 -*- +import logging +import warnings +from pathlib import Path +from typing import Any + +import tables +import pandas.io.pytables +from pandas import HDFStore, DataFrame + +from dgp.core.models.datafile import DataFile + +__all__ = ['HDF5Manager'] +# Suppress PyTables warnings due to mixed data-types (typically NaN's in cols) +warnings.filterwarnings('ignore', + category=pandas.io.pytables.PerformanceWarning) + +# Define Data Types/Extensions +HDF5_NAME = 'dgpdata.hdf5' + + +class HDF5Manager: + """HDF5Manager is a utility class used to read/write pandas DataFrames to and from + an HDF5 data file. This class is essentially a wrapper around the pandas HDFStore, + and features of the underlying pytables module, designed to allow easy storage + and retrieval of DataFrames based on a :obj:`~dgp.core.models.data.DataFile` + + HDF5Manager should not be directly instantiated, it provides classmethod's + and staticmethod's to store/retrieve data, without maintaining state, + except for the data cache as described below. + + The HDF5 Manager maintains a class level cache, which obviates the need to perform + expensive file-system operations to load data that has previously been loaded during + a session. + + HDF5Manager also provides utility methods to allow read/write of metadata attributes + on a particular node within the HDF5 file. + + """ + log = logging.getLogger(__name__) + _cache = {} + + @classmethod + def save_data(cls, data: DataFrame, datafile: DataFile, path: Path) -> bool: + """ + Save a Pandas Series or DataFrame to the HDF5 Store + + Data is added to the local cache, keyed by its generated UID. + The generated UID is passed back to the caller for later reference. + + Parameters + ---------- + data : DataFrame + Data object to be stored on disk via specified format. + datafile : DataFile + The DataFile metadata associated with the supplied data + path : Path + Path to the HDF5 file + + Returns + ------- + bool: + True on successful save + + Raises + ------ + :exc:`FileNotFoundError` + :exc:`PermissionError` + + """ + + cls._cache[datafile] = data + + with HDFStore(str(path)) as hdf: + try: + hdf.put(datafile.nodepath, data, format='fixed', data_columns=True) + except (IOError, PermissionError): # pragma: no cover + cls.log.exception("Exception writing file to HDF5 _store.") + raise + else: + cls.log.info(f"Wrote file to HDF5 _store at node: {datafile.nodepath}") + + return True + + @classmethod + def load_data(cls, datafile: DataFile, path: Path) -> DataFrame: + """ + Load data from a managed repository by UID + This public method is a dispatch mechanism that calls the relevant + loader based on the data type of the data represented by UID. + This method will first check the local cache for UID, and if the key + is not located, will load it from the HDF5 Data File. + + Parameters + ---------- + datafile : DataFile + path : Path + Path to the HDF5 file where datafile is stored + + Returns + ------- + DataFrame + Data retrieved from _store. + + Raises + ------ + KeyError + If data key (/flightid/grpid/uid) does not exist + """ + if datafile in cls._cache: + cls.log.info(f"Loading data node {datafile.uid!s} from cache.") + return cls._cache[datafile] + else: + cls.log.debug(f"Loading data node {datafile.nodepath} from hdf5store.") + + try: + with HDFStore(str(path), mode='r') as hdf: + data = hdf.get(datafile.nodepath) + except OSError as e: + cls.log.exception(e) + raise FileNotFoundError from e + except KeyError as e: + cls.log.exception(e) + raise + + # Cache the data + cls._cache[datafile] = data + return data + + @classmethod + def delete_data(cls, file: DataFile, path: Path) -> bool: + raise NotImplementedError + + # See https://www.pytables.org/usersguide/libref/file_class.html#tables.File.set_node_attr + # For more details on setting/retrieving metadata from hdf5 file using pytables + # Note that the _v_ and _f_ prefixes are meant for instance variables and public methods + # within pytables - so the inspection warning can be safely ignored + + @classmethod + def list_node_attrs(cls, nodepath: str, path: Path) -> list: + with tables.open_file(str(path), mode='r') as hdf: + try: + return hdf.get_node(nodepath)._v_attrs._v_attrnames + except tables.exceptions.NoSuchNodeError: + raise KeyError(f"Specified node {nodepath} does not exist.") + + @classmethod + def _get_node_attr(cls, nodepath, attrname, path: Path): + with tables.open_file(str(path), mode='r') as hdf: + try: + return hdf.get_node_attr(nodepath, attrname) + except AttributeError: + return None + + @classmethod + def _set_node_attr(cls, nodepath: str, attrname: str, value: Any, path: Path): + with tables.open_file(str(path), 'a') as hdf: + try: + hdf.set_node_attr(nodepath, attrname, value) + except tables.exceptions.NoSuchNodeError: + raise KeyError(f"Specified node {nodepath} does not exist") + else: + return True + + @classmethod + def clear_cache(cls): + del cls._cache + cls._cache = {} diff --git a/dgp/core/models/__init__.py b/dgp/core/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dgp/core/models/datafile.py b/dgp/core/models/datafile.py new file mode 100644 index 0000000..ab32f23 --- /dev/null +++ b/dgp/core/models/datafile.py @@ -0,0 +1,63 @@ +# -*- encoding: utf-8 -*- +from datetime import datetime +from pathlib import Path +from typing import Optional + +from dgp.core import DataType +from dgp.core.oid import OID + + +class DataFile: + """The DataFile is a model reference object which maintains the path and + identifier for an entity stored in a project's HDF5 file database. + + In addition to storing the HDF5 Node Path, the DataFile maintains some + meta-data attributes such as the date associated with the file, its original + absolute path on the file-system where it was imported, the data + column-format used to import the data, and the name of the file. + + The reason why the DataFile does not provide any direct access to the data + it references is due to the nature of the project structure. The HDF5 data + file is assumed to contain many data entities, and is maintained by the base + project. To avoid passing references to the HDF5 file throughout the project + hierarchy, we delegate the loading of data to a higher level controller, + which simply uses the :class:`DataFile` as the address. + + """ + __slots__ = ('uid', 'date', 'name', 'group', 'source_path', + 'column_format') + + def __init__(self, group: DataType, date: datetime, source_path: Path, + name: Optional[str] = None, column_format=None, + uid: Optional[OID] = None): + self.uid = uid or OID(self) + self.uid.set_pointer(self) + self.group = group + self.date = date + self.source_path = Path(source_path) + self.name = name or self.source_path.name + self.column_format = column_format + + @property + def label(self) -> str: + return f'[{self.group.value}] {self.name}' + + @property + def nodepath(self) -> str: + """Returns the HDF5 Node where the data associated with this + DataFile is stored within the project's HDF5 file. + + Notes + ----- + An underscore (_) is prepended to the parent and uid ID's to avoid the + NaturalNameWarning generated if the UID begins with a number. + """ + return f'/{self.group.value}/_{self.uid.base_uuid}' + + def __str__(self): + return f'({self.group.value}) :: {self.nodepath}' + + def __hash__(self): + return hash(self.uid) + + diff --git a/dgp/core/models/dataset.py b/dgp/core/models/dataset.py new file mode 100644 index 0000000..d8f0621 --- /dev/null +++ b/dgp/core/models/dataset.py @@ -0,0 +1,121 @@ +# -*- coding: utf-8 -*- +from pathlib import Path +from typing import List +from datetime import datetime + +from pandas import Timestamp + +from dgp.core.types.reference import Reference +from dgp.core.models.datafile import DataFile +from dgp.core.oid import OID + +__all__ = ['DataSegment', 'DataSet'] + + +class DataSegment: + def __init__(self, uid: OID, start: int, stop: int, sequence: int, + label: str = None): + self.uid = uid + self.uid.set_pointer(self) + if isinstance(start, Timestamp): + self._start = start.value + else: + self._start = start + if isinstance(stop, Timestamp): + self._stop = stop.value + else: + self._stop = stop + self.sequence = sequence + self.label = label + + @property + def start(self) -> Timestamp: + try: + return Timestamp(self._start) + except OSError: + return Timestamp(0) + + @start.setter + def start(self, value: Timestamp) -> None: + self._start = value.value + + @property + def stop(self) -> Timestamp: + try: + return Timestamp(self._stop) + except OSError: + return Timestamp(0) + + @stop.setter + def stop(self, value: Timestamp) -> None: + self._stop = value.value + + def __str__(self): + return f'<{self.start.to_pydatetime(warn=False):%H:%M} -' \ + f' {self.stop.to_pydatetime(warn=False):%H:%M}>' + + def __repr__(self): + return f'' + + +class DataSet: + """DataSet is a paired set of Gravity and Trajectory Data + + DataSets can have segments defined, e.g. for an Airborne project these + would be Flight Lines. + + Parameters + ---------- + path : Path, optional + File system path to the HDF5 file where data from this dataset will reside + gravity : :obj:`DataFile`, optional + Optional Gravity DataFile to initialize this DataSet with + trajectory : :obj:`DataFile`, optional + Optional Trajectory DataFile to initialize this DataSet with + segments : List[:obj:`DataSegment`], optional + Optional list of DataSegment's to initialize this DataSet with + uid + + Notes + ----- + Once this class is implemented, DataFiles will be created and added only to + a DataSet, they will not be permitted as direct children of Flights + + """ + def __init__(self, gravity: DataFile = None, trajectory: DataFile = None, + segments: List[DataSegment]=None, sensor=None, + name: str = None, uid: OID = None): + self.uid = uid or OID(self) + self.uid.set_pointer(self) + self.name = name or "Data Set" + self.segments = segments or [] + self._sensor = Reference(self, 'sensor', sensor) + + self.gravity: DataFile = gravity + self.trajectory: DataFile = trajectory + + @property + def sensor(self): + return self._sensor.dereference() + + @sensor.setter + def sensor(self, value): + self._sensor.ref = value + + # TODO: Implement align_frames functionality as below + # TODO: Consider the implications of multiple data files + # OR: insert align_frames into the transform graph and deal with it there + + # gravity = flight.gravity + # trajectory = flight.trajectory + # if gravity is not None and trajectory is not None: + # # align and crop the gravity and trajectory frames + # + # from lib.gravity_ingestor import DGS_AT1A_INTERP_FIELDS + # from lib.trajectory_ingestor import TRAJECTORY_INTERP_FIELDS + # + # fields = DGS_AT1A_INTERP_FIELDS | TRAJECTORY_INTERP_FIELDS + # new_gravity, new_trajectory = align_frames(gravity, trajectory, + # interp_only=fields) diff --git a/dgp/core/models/flight.py b/dgp/core/models/flight.py new file mode 100644 index 0000000..9062759 --- /dev/null +++ b/dgp/core/models/flight.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +from datetime import datetime +from typing import List, Optional, Union + +from dgp.core.types.reference import Reference +from dgp.core.models.dataset import DataSet +from dgp.core.models.meter import Gravimeter +from dgp.core.oid import OID + + +class Flight: + """ + Flight base model (Airborne Project) + + The Flight is one of the central components of an Airborne Gravity Project, + representing a single gravity survey flight (takeoff -> landing). + The :class:`Flight` contains meta-data common to the overall flight + date flown, duration, notes, etc. + + The Flight is also the parent container for 1 or more :class:`DataSet` s + which group the Trajectory and Gravity data collected during a flight, and + can define segments of data (flight lines), based on the flight path. + + Parameters + ---------- + name : str + Flight name/human-readable reference + date : :class:`datetime`, optional + Optional, specify the date the flight was flown, if not specified, + today's date is used. + notes : str, optional + Optional, add/specify flight specific notes + sequence : int, optional + Optional, specify flight sequence within context of an airborne campaign + duration : int, optional + Optional, specify duration of the flight in hours + meter : str, Optional + Not yet implemented - associate a meter with this flight + May be deprecated in favor of associating a Gravimeter with DataSets + within the flight. + + """ + __slots__ = ('uid', 'name', 'datasets', 'date', 'notes', 'sequence', + 'duration', '_parent') + + def __init__(self, name: str, date: Optional[datetime] = None, notes: Optional[str] = None, + sequence: int = 0, duration: int = 0, + uid: Optional[OID] = None, **kwargs): + self._parent = Reference(self, 'parent') + self.uid = uid or OID(self, name) + self.uid.set_pointer(self) + self.name = name + self.date = date or datetime.today() + self.notes = notes + self.sequence = sequence + self.duration = duration + + self.datasets = kwargs.get('datasets', []) # type: List[DataSet] + + @property + def parent(self): + return self._parent.dereference() + + @parent.setter + def parent(self, value): + self._parent.ref = value + + def __str__(self) -> str: + return self.name + + def __repr__(self) -> str: + return f'' diff --git a/dgp/core/models/meter.py b/dgp/core/models/meter.py new file mode 100644 index 0000000..aac59d8 --- /dev/null +++ b/dgp/core/models/meter.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- + +""" +New pure data class for Meter configurations +""" +import configparser +from pathlib import Path +from typing import Optional, Union, Dict + +from dgp.core.types.reference import Reference +from dgp.core.oid import OID + + +sensor_fields = ['g0', 'GravCal', 'LongCal', 'CrossCal', 'LongOffset', 'CrossOffset', 'stempgain', + 'Temperature', 'stempoffset', 'pressgain', 'presszero', 'beamgain', 'beamzero', + 'Etempgain', 'Etempzero', 'Meter'] +# Cross coupling Fields +cc_fields = ['vcc', 've', 'al', 'ax', 'monitors'] + +# Platform Fields +platform_fields = ['Cross_Damping', 'Cross_Periode', 'Cross_Lead', 'Cross_Gain', 'Cross_Comp', + 'Cross_Phcomp', 'Cross_sp', 'Long_Damping', 'Long_Periode', 'Long_Lead', 'Long_Gain', + 'Long_Comp', 'Long_Phcomp', 'Long_sp', 'zerolong', 'zerocross', 'CrossSp', 'LongSp'] + +valid_fields = set().union(sensor_fields, cc_fields, platform_fields) + + +class Gravimeter: + def __init__(self, name: str, config: dict = None, uid: Optional[OID] = None, **kwargs): + self._parent = Reference(self, 'parent') + self.uid = uid or OID(self) + self.uid.set_pointer(self) + self.type = "AT1A" + self.name = name + self.column_format = "AT1A Airborne" + self.config = config + self.attributes = kwargs.get('attributes', {}) + + @property + def parent(self): + return self._parent.dereference() + + @parent.setter + def parent(self, value): + self._parent.ref = value + + @staticmethod + def read_config(path: Path) -> Dict[str, Union[str, int, float]]: + if not path.exists(): + raise FileNotFoundError + config = configparser.ConfigParser(strict=False) + try: + config.read(str(path)) + except configparser.MissingSectionHeaderError: + return {} + + sensor_fld = dict(config['Sensor']) + xcoupling_fld = dict(config['crosscouplings']) + platform_fld = dict(config['Platform']) + + def safe_cast(value): + try: + return float(value) + except ValueError: + return value + + merged = {**sensor_fld, **xcoupling_fld, **platform_fld} + return {k.lower(): safe_cast(v) for k, v in merged.items() if k.lower() in map(str.lower, valid_fields)} + + @classmethod + def from_ini(cls, path: Path, name=None): + """ + Read an AT1 Meter Configuration from a meter ini file + """ + config = cls.read_config(Path(path)) + return cls(name, config=config) diff --git a/dgp/core/models/project.py b/dgp/core/models/project.py new file mode 100644 index 0000000..be36589 --- /dev/null +++ b/dgp/core/models/project.py @@ -0,0 +1,387 @@ +# -*- coding: utf-8 -*- +import json +import json.decoder +import datetime +import warnings +from pathlib import Path +from typing import Optional, List, Any, Dict, Union, Tuple, Callable + +from dgp.core import DataType +from dgp.core.types.reference import Reference +from dgp.core.oid import OID +from .flight import Flight +from .meter import Gravimeter +from .dataset import DataSet, DataSegment +from .datafile import DataFile + +PROJECT_FILE_NAME = 'dgp.json' +project_entities = {'Flight': Flight, + 'DataSet': DataSet, + 'DataFile': DataFile, + 'DataSegment': DataSegment, + 'Gravimeter': Gravimeter} + +ObjectTransform = Tuple[str, Callable[[object], str]] + +# Declare object -> serialized value transforms +object_value_map: Dict[object, ObjectTransform] = { + OID: ('base_uuid', lambda o: o.base_uuid), + datetime.datetime: ('timestamp', lambda o: o.timestamp()), + datetime.date: ('ordinal', lambda o: o.toordinal()), + Path: ('path', lambda o: f'{o.resolve()!s}'), + DataType: ('value', lambda o: o.value) +} + +# Declare serialized value -> object transforms +value_object_map: Dict[str, Callable[[Dict], str]] = { + OID.__name__: lambda x: OID(**x), + datetime.datetime.__name__: lambda x: datetime.datetime.fromtimestamp(*x.values()), + datetime.date.__name__: lambda x: datetime.date.fromordinal(*x.values()), + Path.__name__: lambda x: Path(*x.values()), + DataType.__name__: lambda x: DataType(**x) +} + + +class ProjectEncoder(json.JSONEncoder): + """ + The ProjectEncoder allows complex project objects to be encoded into + a standard JSON representation. + Classes are matched and encoded by type, with Project class instances + defined in the project_entities module variable. + Project classes simply have their __slots__ or __dict__ mapped to a JSON + object (Dictionary), with any recognized complex objects within the class + iteratively encoded by the encoder. + + A select number of other 'complex' objects are also capable of being + encoded by this encoder, such as OID's, datetimes, and pathlib.Path objects. + An _type variable is inserted into the JSON output, and used by the decoder + to determine how to decode and reconstruct the object into a Python native + object. + + The object_value_map is used to declare various types and their serialization + method (a lambda function). This provides an extensible way to add new types + to the projects serialization process. Note that the inverse + (de-serialization) declaration should also be added to the value_object_map + when adding any new type. + + The :class:`Reference` object is a special case; project model objects may + utilize the Reference class to maintain links to a parent or other related + model object. The Project Encoder/Decoders identify Reference objects and + serialize the metadata of the Reference in order to facilitate re-linking + during de-serialization. + + """ + + def default(self, o: Any): + if isinstance(o, (AirborneProject, *project_entities.values())): + keys = o.__slots__ if hasattr(o, '__slots__') else o.__dict__.keys() + attrs = {key.lstrip('_'): getattr(o, key) for key in keys} + attrs['_type'] = o.__class__.__name__ + attrs['_module'] = o.__class__.__module__ + return attrs + json_str = {'_type': o.__class__.__name__, + '_module': o.__class__.__module__} + if o.__class__ in object_value_map: + attr, serializer = object_value_map[o.__class__] + json_str[attr] = serializer(o) + return json_str + elif isinstance(o, Path): + # Path requires special handling due to OS dependant class names + json_str['_type'] = 'Path' + json_str['path'] = str(o.resolve()) + return json_str + elif isinstance(o, Reference): + # Reference is a special case, as it can return None + return o.serialize() + + return super().default(o) + + +JsonRef = Tuple[str, str, str] + + +class ProjectDecoder(json.JSONDecoder): + """ + ProjectDecoder is a custom JSONDecoder object which enables us to de-serialize + circular references. This is useful in our case as the gravity projects are + represented in a tree-type hierarchy. Objects in the tree keep a reference to + their parent to facilitate a variety of actions. + + All project entities are decoded and a reference is stored in an internal + registry (keyed by UID) to facilitate the re-linking of :class:`Reference` + entities after decoding is complete. + + A second pass is made over the decoded project structure due to the way the + JSON is decoded (depth-first), such that the deepest nested children may + contain references to a parent object which has not been decoded yet. + This allows us to store only a single canonical serialized representation of + the parent objects in the hierarchy, and then assemble the references after + the fact. + + """ + + def __init__(self, klass): + super().__init__(object_hook=self.object_hook) + self._registry = {} + self._references: List[JsonRef] = [] + self._klass = klass + + def decode(self, s, _w=json.decoder.WHITESPACE.match): + decoded = super().decode(s) + # Re-link References + for parent_uid, attr, child_uid in self._references: + parent = self._registry[parent_uid] + child = self._registry[child_uid] + setattr(parent, attr, child) + + return decoded + + def object_hook(self, json_o: dict): + """Object Hook in json.load will iterate upwards from the deepest + nested JSON object (dictionary), calling this hook on each, then passing + the result up to the next level object. + Thus we can re-assemble the entire Project hierarchy given that all classes + can be created via their __init__ methods + (i.e. they must accept passing child objects through a parameter) + + The _type attribute is expected (and injected during serialization), for + any custom objects which should be processed by the project_hook. + + The type of the current project class (or sub-class) is injected into + the class map which allows for this object hook to be utilized by any + inheritor without modification. + + The value_object_map dictionary is used to define custom de-serialization + routines for specific objects in a declarative fashion. This is due to + the non-uniform way in which various objects are serialized and + de-serialized. + For example a :obj:`datetime` object's serial representation is its float + 'timestamp' value. In order to reconstruct the datetime object we must + call datetime.fromtimestamp(ts). Thus we need some object specific + declarations to de-serialize certain types. + + """ + if '_type' not in json_o: + # JSON objects without _type are interpreted as Python dictionaries + return json_o + _type = json_o.pop('_type') + try: + _module = json_o.pop('_module') + except KeyError: + _module = None + + params = {key.lstrip('_'): value for key, value in json_o.items()} + if _type in value_object_map: + factory = value_object_map[_type] + return factory(params) + elif _type == Reference.__name__: + # References are a special case, None is returned as an interim val + self._references.append((json_o['parent'], json_o['attr'], json_o['ref'])) + return None + else: + # Handle project entity types (also inject the Project sub-class) + klass = {self._klass.__name__: self._klass, **project_entities}.get(_type, None) + if klass is None: # pragma: no cover + raise AttributeError(f"Unhandled class {_type} in JSON data. Class is not defined" + f" in entity map.") + else: + try: + instance = klass(**params) + self._registry[instance.uid] = instance + return instance + except TypeError: # pragma: no cover + # This may occur if an outdated project JSON file is loaded + print(f'Exception instantiating class {klass} with params {params}') + raise + + +class GravityProject: + """GravityProject base class. + + This class is not designed to be instantiated directly, but is used + as the common base-class for Airborne Gravity Projects, and in future Marine + Gravity Projects. + + This base class stores common attributes such as the Project name, + description, path, and Gravimeters (which all Gravity Projects may use). + + Modification time is tracked on the project, and any mutations made via + properties in this class will update the modify time. + + The GravityProject class also provides the utility to_json/from_json methods + which should work with any child classes. The JSON serialization methods + simply call the appropriate :class:`ProjectEncoder` or + :class:`ProjectDecoder` to serialize/de-serialize the project respectively. + + Parameters + ---------- + name : str + Name of the project + path : :class:`Path` + Directory path where the project is located + description : str, optional + Optional, description for the project + create_date : :class:`datetime`, optional + Specify creation date of the project, current UTC time is used if None + modify_date : :class:`datetime`, optional + This parameter should be used only during the de-serialization process, + otherwise the modification date is automatically handled by the class + properties. + + See Also + -------- + :class:`AirborneProject` + + """ + + def __init__(self, name: str, path: Path, description: Optional[str] = None, + create_date: Optional[datetime.datetime] = None, + modify_date: Optional[datetime.datetime] = None, + uid: Optional[str] = None, **kwargs): + self.uid = uid or OID(self, tag=name) + self.uid.set_pointer(self) + self._name = name + self._path = path + self._projectfile = PROJECT_FILE_NAME + self._description = description or "" + self.create_date = create_date or datetime.datetime.utcnow() + self.modify_date = modify_date or datetime.datetime.utcnow() + + self._gravimeters = kwargs.get('gravimeters', []) # type: List[Gravimeter] + + @property + def name(self) -> str: + return self._name + + @name.setter + def name(self, value: str) -> None: + self._name = value.strip() + self._modify() + + @property + def path(self) -> Path: + return Path(self._path) + + @path.setter + def path(self, value: str) -> None: + self._path = Path(value) + self._modify() + + @property + def description(self) -> str: + return self._description + + @description.setter + def description(self, value: str): + self._description = value.strip() + self._modify() + + @property + def gravimeters(self) -> List[Gravimeter]: + return self._gravimeters + + def get_child(self, child_id: OID): + return [meter for meter in self._gravimeters if meter.uid == child_id][0] + + def add_child(self, child) -> None: + if isinstance(child, Gravimeter): + self._gravimeters.append(child) + self._modify() + else: + raise TypeError("Invalid child type: {!r}".format(child)) + + def remove_child(self, child_id: OID) -> bool: + child = child_id.reference # type: Gravimeter + if child in self._gravimeters: + self._gravimeters.remove(child) + return True + return False + + def __repr__(self): + return f'<{self.__class__.__name__}: {self.name}/{self.path!s}>' + + # Protected utility methods + def _modify(self): + """Set the modify_date to now""" + self._modify_date = datetime.datetime.utcnow() + + # Serialization/De-Serialization methods + @classmethod + def from_json(cls, json_str: str) -> 'GravityProject': + return json.loads(json_str, cls=ProjectDecoder, klass=cls) + + def to_json(self, to_file=False, indent=None) -> Union[str, bool]: + """Encode the Project to a JSON string, optionally writing to disk + + This function will perform the json encoding operation and store the + result in memory before writing the result to the project file + (if to_file is True), this should prevent corruption of the project file + in cases where the JSON encoder fails partway through the serialization, + leaving the output file in an inconsistent state. + + Parameters + ---------- + to_file : bool, optional + If False the JSON string will be returned to the caller + If True the JSON string will be written to the project file + indent : None, int, optional + Optionally provide an indent value to nicely format the JSON output + """ + try: + json_s = json.dumps(self, cls=ProjectEncoder, indent=indent) + except TypeError as e: + warnings.warn(f"Unable to encode project: {e!s}") + return False + + if to_file: + with self.path.joinpath(self._projectfile).open('w') as fp: + fp.write(json_s) + return True + else: + return json_s + + +class AirborneProject(GravityProject): + """AirborneProject class + + This class is a sub-class of :class:`GravityProject` and simply extends the + functionality of the base GravityProject, allowing the addition/removal + of :class:`Flight` objects, in addition to :class:`Gravimeter` s + + Parameters + ---------- + kwargs + See :class:`GravityProject` for permitted key-word arguments. + + """ + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self._flights = kwargs.get('flights', []) + for flight in self._flights: + flight.parent = self + + @property + def flights(self) -> List[Flight]: + return self._flights + + def add_child(self, child): + if isinstance(child, Flight): + self._flights.append(child) + self._modify() + else: + super().add_child(child) + child.parent = self + + def get_child(self, child_id: OID) -> Union[Flight, Gravimeter]: + try: + return [flt for flt in self._flights if flt.uid == child_id][0] + except IndexError: + return super().get_child(child_id) + + def remove_child(self, child_id: OID) -> bool: + if child_id.reference in self._flights: + self._flights.remove(child_id.reference) + return True + else: + return super().remove_child(child_id) diff --git a/dgp/core/oid.py b/dgp/core/oid.py new file mode 100644 index 0000000..37f199d --- /dev/null +++ b/dgp/core/oid.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- + +from typing import Optional, Union, Any +from uuid import uuid4 + + +class OID: + """Object IDentifier + + Designed as a replacement for the simple string UUID's used previously. + OID's hold a reference to the object it was created for. + OID's can also contain simple meta-data such as a tag for the object it + references. + """ + + def __init__(self, obj: Optional[Any] = None, tag: Optional[str] = None, base_uuid: str = None): + if base_uuid is not None and isinstance(base_uuid, str): + assert len(base_uuid) == 32 + self._base_uuid = base_uuid or uuid4().hex + self._tag = tag + self._pointer = obj + + def set_pointer(self, obj): + self._pointer = obj + + @property + def base_uuid(self): + return self._base_uuid + + @property + def uuid(self): + return f'{self.group}_{self._base_uuid}' + + @property + def reference(self) -> object: + return self._pointer + + @property + def group(self) -> str: + if self._pointer is not None: + return self._pointer.__class__.__name__.lower() + return "oid" + + @property + def tag(self): + return self._tag + + def __str__(self): + return self.uuid + + def __repr__(self): + return f'' + + def __eq__(self, other: Union['OID', str]) -> bool: + if isinstance(other, str): + return other == self._base_uuid or other == self.uuid + try: + return self._base_uuid == other.base_uuid + except AttributeError: + return False + + def __hash__(self): + return hash(self.base_uuid) diff --git a/dgp/core/types/__init__.py b/dgp/core/types/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dgp/core/types/enumerations.py b/dgp/core/types/enumerations.py new file mode 100644 index 0000000..6b72eb6 --- /dev/null +++ b/dgp/core/types/enumerations.py @@ -0,0 +1,112 @@ +# -*- coding: utf-8 -*- +import logging +from enum import Enum, auto + +from PyQt5.QtCore import QUrl +from PyQt5.QtGui import QIcon + +__all__ = ['StateAction', 'StateColor', 'Icon', 'ProjectTypes', + 'MeterTypes', 'DataType'] + +LOG_LEVEL_MAP = {'debug': logging.DEBUG, 'info': logging.INFO, + 'warning': logging.WARNING, 'error': logging.ERROR, + 'critical': logging.CRITICAL} + + +class StateAction(Enum): + CREATE = auto() + UPDATE = auto() + DELETE = auto() + + +class StateColor(Enum): + ACTIVE = '#11dd11' + INACTIVE = '#ffffff' + + +class Icon(Enum): + """Resource Icon paths for Qt resources""" + AUTOSIZE = "autosize" + OPEN_FOLDER = "folder_open" + AIRBORNE = "airborne" + MARINE = "marine" + METER = "sensor" + DGS = "dgs" + DGP = "dgp_large" + DGP_SMALL = "dgp" + DGP_NOTEXT = "dgp_notext" + GRAVITY = "gravity" + TRAJECTORY = "gps" + NEW_FILE = "new_file" + SAVE = "save" + DELETE = "delete" + ARROW_LEFT = "chevron-left" + ARROW_RIGHT = "chevron-right" + ARROW_UP = "chevron-up" + ARROW_DOWN = "chevron-down" + LINE_MODE = "line_mode" + PLOT_LINE = "plot_line" + SETTINGS = "settings" + SELECT = "select" + INFO = "info" + HELP = "help_outline" + GRID = "grid_on" + NO_GRID = "grid_off" + TREE = "tree" + + def icon(self, prefix="icons"): + return QIcon(f':/{prefix}/{self.value}') + + +class LogColors(Enum): + DEBUG = 'blue' + INFO = 'yellow' + WARNING = 'brown' + ERROR = 'red' + CRITICAL = 'orange' + + +class ProjectTypes(Enum): + AIRBORNE = 'airborne' + MARINE = 'marine' + + +class MeterTypes(Enum): + """Gravity Meter Types""" + AT1A = 'at1a' + AT1M = 'at1m' + ZLS = 'zls' + TAGS = 'tags' + + +class DataType(Enum): + """Gravity/Trajectory Data Types""" + GRAVITY = 'gravity' + TRAJECTORY = 'trajectory' + + +class GravityTypes(Enum): + # TODO: add set of fields specific to each dtype + AT1A = ('gravity', 'long_accel', 'cross_accel', 'beam', 'temp', 'status', + 'pressure', 'Etemp', 'gps_week', 'gps_sow') + AT1M = ('at1m',) + ZLS = ('line_name', 'year', 'day', 'hour', 'minute', 'second', 'sensor', + 'spring_tension', 'cross_coupling', 'raw_beam', 'vcc', 'al', 'ax', + 've2', 'ax2', 'xacc2', 'lacc2', 'xacc', 'lacc', 'par_port', + 'platform_period') + TAGS = ('tags', ) + + +class GPSFields(Enum): + sow = ('week', 'sow', 'lat', 'long', 'ell_ht') + hms = ('mdy', 'hms', 'lat', 'long', 'ell_ht') + serial = ('datenum', 'lat', 'long', 'ell_ht') + + +class Links(Enum): + DEV_DOCS = "https://dgp.readthedocs.io/en/develop/" + MASTER_DOCS = "https://dgp.readthedocs.io/en/latest/" + GITHUB = "https://github.com/DynamicGravitySystems/DGP" + + def url(self): + return QUrl(self.value) diff --git a/dgp/core/types/reference.py b/dgp/core/types/reference.py new file mode 100644 index 0000000..30e9645 --- /dev/null +++ b/dgp/core/types/reference.py @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- + + +class Reference: + """Reference is a simple wrapper class designed to facilitate object + references within the DGP project models. This is necessary due to the + nature of the project's JSON serialization/de-serialization protocol, as the + JSON standard does not allow cyclical links (where some object makes + reference to another object that has already been encoded). + + Parameters + ---------- + owner : + Owner of this reference, must have a 'uid' attribute and be serializable + by the ProjectEncoder + attr : str + Name of the attribute which holds this reference, this name is used by + setattr during decoding to re-link the de-referenced object. + ref : Optional + Object to which the :class:`Reference` refers, must have a 'uid' + attribute and be serializable by the ProjectEncoder + + Examples + -------- + >>> class Sensor: + >>> def __init__(self, dataset=None): + >>> # Note the attr param refers to the parent property + >>> # In this case the actual variable self._parent is immaterial + >>> self._parent = Reference(self, 'parent', dataset) + >>> # A reference can also be instantiated without a referred object + >>> self.link = Reference(self, 'link') + >>> assert self.link.isnull + >>> + >>> @property + >>> def parent(self): + >>> return self._parent.dereference() + >>> + >>> @parent.setter + >>> def parent(self, value): + >>> self._parent.ref = value + + Note that it is currently necessary to define properties as in the above + example to create the reference when an object is passed, and it is also + useful to define the getter such that it will return the de-referenced + object - making the Reference object effectively transparent to any outside + callers. + + See Also + -------- + + :class:`~dgp.core.models.project.ProjectEncoder` + :class:`~dgp.core.models.project.ProjectDecoder` + + """ + def __init__(self, owner, attr: str, ref=None): + self.owner = owner + self.ref = ref + self.attr = attr + + @property + def isnull(self) -> bool: + """Check if this reference is null (an incomplete reference) + + Returns + ------- + True + If any of owner, ref, or attr are None + False + If owner, ref, and attr are defined + + """ + return not all([x is not None for x in self.__dict__.values()]) + + def dereference(self): + return self.ref + + def serialize(self): + """Generate a JSON serializable representation of this Reference for the + ProjectEncoder. + + Returns + ------- + None if self.isnull + else + Dictionary containing object type, parent, attr, and ref + + """ + if self.isnull: + return None + return { + '_type': self.__class__.__name__, + 'parent': self.owner.uid, + 'attr': self.attr, + 'ref': self.ref.uid + } diff --git a/dgp/gui/__init__.py b/dgp/gui/__init__.py index 8c44fcf..d47a06e 100644 --- a/dgp/gui/__init__.py +++ b/dgp/gui/__init__.py @@ -1,5 +1,4 @@ -# coding: utf-8 +# -*- coding: utf-8 -*- +from .settings import settings, SettingsKey, RecentProjectManager, UserSettings -# from dgp.gui.splash import SplashScreen -# from dgp.gui.main import MainWindow -# from dgp.gui.dialogs import CreateProject, ImportData, AddFlight +__all__ = ['settings', 'SettingsKey', 'RecentProjectManager', 'UserSettings'] diff --git a/dgp/gui/dialogs.py b/dgp/gui/dialogs.py deleted file mode 100644 index c2181b7..0000000 --- a/dgp/gui/dialogs.py +++ /dev/null @@ -1,202 +0,0 @@ -# coding: utf-8 - -import os -import sys -import json -import logging -import datetime -from pathlib import Path -from typing import Dict, Union - -from PyQt5 import Qt, QtWidgets, QtCore -from PyQt5.uic import loadUiType - -import dgp.lib.project as prj - - -data_dialog, _ = loadUiType('dgp/gui/ui/data_import_dialog.ui') - - -class ImportData(QtWidgets.QDialog, data_dialog): - """ - - Rationalization: - This dialog will be used to import gravity and/or GPS data. - A drop down box will be populated with the available project flights into which the data will be associated - User will specify wheter the data is a gravity or gps file (TODO: maybe we can programatically determine the type) - User will specify file path - Maybe we can dynamically load the first 5 or so lines of data and display column headings, which would allow user - to change the headers if necesarry - - This class does not handle the actual loading of data, it only sets up the parameters (path, type etc) for the - calling class to do the loading. - """ - def __init__(self, project: prj.AirborneProject=None, flight: prj.Flight=None, *args): - """ - - :param project: - :param flight: Currently selected flight to auto-select in list box - :param args: - """ - super().__init__(*args) - self.setupUi(self) - - # Setup button actions - self.button_browse.clicked.connect(self.browse_file) - self.buttonBox.accepted.connect(self.pre_accept) - - dgsico = Qt.QIcon(':images/assets/geoid_icon.png') - - self.setWindowIcon(dgsico) - self.path = None - self.dtype = 'gravity' - self.flight = flight - - if project is not None: - for flight in project: - # TODO: Change dict index to human readable value - self.combo_flights.addItem(flight.name, flight.uid) - if flight == self.flight: # scroll to this item if it matches self.flight - self.combo_flights.setCurrentIndex(self.combo_flights.count() - 1) - for meter in project.meters: - self.combo_meters.addItem(meter.name) - else: - self.combo_flights.setEnabled(False) - self.combo_meters.setEnabled(False) - self.combo_flights.addItem("") - self.combo_meters.addItem("") - - self.file_model = Qt.QFileSystemModel() - self.init_tree() - - def init_tree(self): - self.file_model.setRootPath(os.getcwd()) - self.file_model.setNameFilters(["*.csv", "*.dat"]) - - self.tree_directory.setModel(self.file_model) - self.tree_directory.scrollTo(self.file_model.index(os.getcwd())) - - self.tree_directory.resizeColumnToContents(0) - for i in range(1, 4): # Remove size/date/type columns from view - self.tree_directory.hideColumn(i) - self.tree_directory.clicked.connect(self.select_tree_file) - - def select_tree_file(self, index): - path = Path(self.file_model.filePath(index)) - # TODO: Verify extensions for selected files before setting below - if path.is_file(): - self.field_path.setText(os.path.normpath(path)) # TODO: Change this to use pathlib function - self.path = path - else: - return - - def browse_file(self): - path, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Select Data File", os.getcwd(), "Data (*.dat *.csv)") - if path: - self.path = Path(path) - self.field_path.setText(self.path.name) - index = self.file_model.index(str(self.path.resolve())) - self.tree_directory.scrollTo(self.file_model.index(str(self.path.resolve()))) - self.tree_directory.setCurrentIndex(index) - - def pre_accept(self): - self.dtype = {'GPS Data': 'gps', 'Gravity Data': 'gravity'}.get(self.group_radiotype.checkedButton().text(), 'gravity') - self.flight = self.combo_flights.currentData() - self.accept() - - @property - def content(self) -> (Path, str, prj.Flight): - return self.path, self.dtype, self.flight - - -flight_dialog, _ = loadUiType('dgp/gui/ui/add_flight_dialog.ui') - - -class AddFlight(QtWidgets.QDialog, flight_dialog): - def __init__(self, project, *args): - super().__init__(*args) - self.setupUi(self) - self._project = project - self._flight = None - self.combo_meter.addItems(project.meters) - self.date_flight.setDate(datetime.datetime.today()) - self._uid = prj.Flight.generate_uuid() - self.text_uuid.setText(self._uid) - - def accept(self): - # TODO: Change test meter to actual meter - qdate = self.date_flight.date() # type: QtCore.QDate - date = datetime.date(qdate.year(), qdate.month(), qdate.day()) - self._flight = prj.Flight(self._project, self.text_name.text(), self._project.get_meter( - self.combo_meter.currentText()), uuid=self._uid, date=date) - super().accept() - - @property - def flight(self): - return self._flight - - -project_dialog, _ = loadUiType('dgp/gui/ui/project_dialog.ui') - - -class CreateProject(QtWidgets.QDialog, project_dialog): - def __init__(self, *args): - super().__init__(*args) - self.setupUi(self) - self.prj_create.clicked.connect(self.create_project) - self.prj_browse.clicked.connect(self.select_dir) - - self._project = None - - # Populate the type selection list - dgs_airborne = Qt.QListWidgetItem(Qt.QIcon(':images/assets/flight_icon.png'), 'DGS Airborne', self.prj_type_list) - dgs_airborne.setData(QtCore.Qt.UserRole, 'dgs_airborne') - self.prj_type_list.setCurrentItem(dgs_airborne) - dgs_marine = Qt.QListWidgetItem(Qt.QIcon(':images/assets/boat_icon.png'), 'DGS Marine', self.prj_type_list) - dgs_marine.setData(QtCore.Qt.UserRole, 'dgs_marine') - - def create_project(self): - """ - Called upon 'Create' button push, do some basic validation of fields then - accept() if required fields are filled, otherwise color the labels red - :return: None - """ - required_fields = {'prj_name': 'label_name', 'prj_dir': 'label_dir'} - - invalid_input = False - for attr in required_fields.keys(): - if not self.__getattribute__(attr).text(): - self.__getattribute__(required_fields[attr]).setStyleSheet('color: red') - invalid_input = True - else: - self.__getattribute__(required_fields[attr]).setStyleSheet('color: black') - - if not os.path.isdir(self.prj_dir.text()): - invalid_input = True - self.label_dir.setStyleSheet('color: red') - self.label_required.setText("Invalid Directory") - self.label_required.setStyleSheet('color: red') - - if invalid_input: - return - - if self.prj_type_list.currentItem().data(QtCore.Qt.UserRole) == 'dgs_airborne': - name = str(self.prj_name.text()).rstrip() - path = Path(self.prj_dir.text()).joinpath(name) - if not path.exists(): - path.mkdir(parents=True) - self._project = prj.AirborneProject(path, name, self.prj_description.toPlainText().rstrip()) - else: - self.label_required.setText('Invalid project type (Not Implemented)') - return - - self.accept() - - def select_dir(self): - path = QtWidgets.QFileDialog.getExistingDirectory(self, "Select Project Parent Directory") - if path: - self.prj_dir.setText(path) - - @property - def project(self): - return self._project diff --git a/dgp/gui/dialogs/__init__.py b/dgp/gui/dialogs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dgp/gui/dialogs/add_flight_dialog.py b/dgp/gui/dialogs/add_flight_dialog.py new file mode 100644 index 0000000..6e86144 --- /dev/null +++ b/dgp/gui/dialogs/add_flight_dialog.py @@ -0,0 +1,81 @@ +# -*- coding: utf-8 -*- +import datetime +from typing import Optional, List + +from PyQt5.QtCore import Qt, QDate, QRegExp +from PyQt5.QtGui import QRegExpValidator +from PyQt5.QtWidgets import QDialog, QWidget, QFormLayout + +from dgp.core.models.meter import Gravimeter +from dgp.core.controllers.controller_interfaces import IAirborneController, IFlightController +from dgp.core.models.flight import Flight +from .dialog_mixins import FormValidator +from ..ui.add_flight_dialog import Ui_NewFlight + + +class AddFlightDialog(QDialog, Ui_NewFlight, FormValidator): + def __init__(self, project: IAirborneController, flight: IFlightController = None, + parent: Optional[QWidget] = None): + super().__init__(parent) + self.setupUi(self) + self._project = project + self._flight = flight + + # Configure Form Validation + self._name_validator = QRegExpValidator(QRegExp("[A-Za-z]+.{2,20}")) + self.qle_flight_name.setValidator(self._name_validator) + + if self._flight is not None: + self._set_flight(self._flight) + else: + self.qde_flight_date.setDate(datetime.date.today()) + self.qsb_sequence.setValue(project.flight_model.rowCount()) + + @property + def validation_targets(self) -> List[QFormLayout]: + return [self.qfl_flight_form] + + @property + def validation_error(self): + return self.ql_validation_err + + def accept(self): + if not self.validate(): + return + + name = self.qle_flight_name.text() + qdate: QDate = self.qde_flight_date.date() + date = datetime.date(qdate.year(), qdate.month(), qdate.day()) + notes = self.qte_notes.toPlainText() + sequence = self.qsb_sequence.value() + duration = self.qsb_duration.value() + + if self._flight is not None: + # Existing flight - update + self._flight.set_attr('name', name) + self._flight.set_attr('date', date) + self._flight.set_attr('notes', notes) + self._flight.set_attr('sequence', sequence) + self._flight.set_attr('duration', duration) + else: + # Create new flight and add it to project + flt = Flight(self.qle_flight_name.text(), date=date, + notes=self.qte_notes.toPlainText(), + sequence=sequence, duration=duration) + self._project.add_child(flt) + + super().accept() + + def _set_flight(self, flight: IFlightController): + self.setWindowTitle("Properties: " + flight.get_attr('name')) + self.qle_flight_name.setText(flight.get_attr('name')) + self.qte_notes.setText(flight.get_attr('notes')) + self.qsb_duration.setValue(flight.get_attr('duration')) + self.qsb_sequence.setValue(flight.get_attr('sequence')) + self.qde_flight_date.setDate(flight.get_attr('date')) + + @classmethod + def from_existing(cls, flight: IFlightController, + project: IAirborneController, + parent: Optional[QWidget] = None): + return cls(project, flight, parent=parent) diff --git a/dgp/gui/dialogs/add_gravimeter_dialog.py b/dgp/gui/dialogs/add_gravimeter_dialog.py new file mode 100644 index 0000000..c8fdf4f --- /dev/null +++ b/dgp/gui/dialogs/add_gravimeter_dialog.py @@ -0,0 +1,110 @@ +# -*- coding: utf-8 -*- +from pathlib import Path +from pprint import pprint +from typing import Optional, List + +from PyQt5.QtGui import QIntValidator, QIcon, QStandardItemModel, QStandardItem +from PyQt5.QtWidgets import QDialog, QWidget, QFileDialog, QListWidgetItem, QFormLayout + +from dgp.core.controllers.controller_interfaces import IAirborneController +from dgp.core.models.meter import Gravimeter +from dgp.gui.ui.add_meter_dialog import Ui_AddMeterDialog +from .dialog_mixins import FormValidator, VALIDATION_ERR_MSG + + +class AddGravimeterDialog(QDialog, Ui_AddMeterDialog, FormValidator): + + def __init__(self, project: IAirborneController, parent: Optional[QWidget] = None): + super().__init__(parent) + self.setupUi(self) + self._project = project + self._valid_ext = ('.ini', '.txt', '.conf') + + AT1A = QListWidgetItem(QIcon(":/icons/dgs"), "AT1A") + AT1M = QListWidgetItem(QIcon(":/icons/dgs"), "AT1M") + + self.qlw_metertype.addItem(AT1A) + self.qlw_metertype.addItem(AT1M) + self.qlw_metertype.addItem("TAGS") + self.qlw_metertype.addItem("ZLS") + self.qlw_metertype.addItem("AirSeaII") + self.qlw_metertype.currentRowChanged.connect(self._type_changed) + self.qlw_metertype.setCurrentRow(0) + + self.qtb_browse_config.clicked.connect(self._browse_config) + self.qle_config_path.textChanged.connect(self._path_changed) + self.qle_serial.textChanged.connect(lambda text: self._serial_changed(text)) + self.qle_serial.setValidator(QIntValidator(1, 1000)) + + self._config_model = QStandardItemModel() + self._config_model.itemChanged.connect(self._config_data_changed) + + self.qtv_config_view.setModel(self._config_model) + + @property + def validation_targets(self) -> List[QFormLayout]: + return [self.qfl_meter_form] + + @property + def validation_error(self): + return self.ql_validation_err + + @property + def config_path(self): + if not len(self.qle_config_path.text()): + return None + _path = Path(self.qle_config_path.text()) + if not _path.exists(): + return None + if not _path.is_file(): + return None + if _path.suffix not in self._valid_ext: + return None + return _path + + def accept(self): + if not self.validate(): + return + + if self.qle_config_path.text(): + meter = Gravimeter.from_ini(Path(self.qle_config_path.text()), name=self.qle_name.text()) + else: + meter = Gravimeter(self.qle_name.text()) + self._project.add_child(meter) + + super().accept() + + def _path_changed(self, text: str): + if self.config_path is not None and self.config_path.exists(): + self._preview_config() + + def get_sensor_type(self) -> str: + return self.qlw_metertype.currentItem().text() + + def _browse_config(self): # pragma: no cover + # TODO: Look into useing getOpenURL methods for files on remote/network drives + path, _ = QFileDialog.getOpenFileName(self, "Select Configuration File", str(Path().resolve()), + "Configuration (*.ini);;Any (*.*)") + if path: + self.qle_config_path.setText(path) + + def _config_data_changed(self, item: QStandardItem): # pragma: no cover + # TODO: Implement this if desire to enable editing of config from the preview table + index = self._config_model.index(item.row(), item.column()) + sibling = self._config_model.index(item.row(), 0 if item.column() else 1) + + def _preview_config(self): + if self.config_path is None: + return + config = Gravimeter.read_config(self.config_path) + + self._config_model.clear() + self._config_model.setHorizontalHeaderLabels(["Config Key", "Value"]) + for key, value in config.items(): + self._config_model.appendRow([QStandardItem(key), QStandardItem(str(value))]) + + def _type_changed(self, row: int): + self._serial_changed(self.qle_serial.text()) + + def _serial_changed(self, text: str): + self.qle_name.setText("%s-%s" % (self.get_sensor_type(), text)) diff --git a/dgp/gui/dialogs/create_project_dialog.py b/dgp/gui/dialogs/create_project_dialog.py new file mode 100644 index 0000000..d9e037e --- /dev/null +++ b/dgp/gui/dialogs/create_project_dialog.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +import logging +from pathlib import Path +from typing import List + +from PyQt5.QtCore import Qt, QRegExp, pyqtSignal +from PyQt5.QtGui import QIcon, QRegExpValidator +from PyQt5.QtWidgets import QDialog, QListWidgetItem, QFileDialog, QFormLayout + +from dgp.core.models.project import AirborneProject +from dgp.core.types.enumerations import ProjectTypes +from dgp.gui.ui.create_project_dialog import Ui_CreateProjectDialog +from .dialog_mixins import FormValidator +from .custom_validators import DirectoryValidator + + +class CreateProjectDialog(QDialog, Ui_CreateProjectDialog, FormValidator): + sigProjectCreated = pyqtSignal(AirborneProject) + + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + + self._project = None + + self.prj_browse.clicked.connect(self.select_dir) + desktop = Path().home().joinpath('Desktop') + self.prj_dir.setText(str(desktop)) + + # Populate the type selection list + flt_icon = QIcon(':icons/airborne') + boat_icon = QIcon(':icons/marine') + dgs_airborne = QListWidgetItem(flt_icon, 'DGS Airborne', + self.prj_type_list) + dgs_airborne.setData(Qt.UserRole, ProjectTypes.AIRBORNE) + self.prj_type_list.setCurrentItem(dgs_airborne) + dgs_marine = QListWidgetItem(boat_icon, 'DGS Marine', + self.prj_type_list) + dgs_marine.setData(Qt.UserRole, ProjectTypes.MARINE) + + # Configure Validation + self.prj_name.setValidator(QRegExpValidator(QRegExp("[A-Za-z]+.{3,30}"))) + self.prj_dir.setValidator(DirectoryValidator(exist_ok=True)) + + @property + def validation_targets(self) -> List[QFormLayout]: + return [self.qfl_create_form] + + @property + def validation_error(self): + return self.ql_validation_err + + def accept(self): + """ + Called upon 'Create' button push, do some basic validation of fields + then accept() if required fields are filled, otherwise color the + labels red and display a warning message. + """ + if not self.validate(): + return + + # TODO: Future implementation for Project types other than DGS AT1A + prj_type = self.prj_type_list.currentItem().data(Qt.UserRole) + if prj_type == ProjectTypes.AIRBORNE: + name = str(self.prj_name.text()).rstrip() + name = "".join([word.capitalize() for word in name.split(' ')]) + path = Path(self.prj_dir.text()).joinpath(name) + if not path.exists(): # pragma: no branch + path.mkdir(parents=True) + + self._project = AirborneProject(name=name, path=path, description=self.qpte_notes.toPlainText()) + self._project.to_json(to_file=True, indent=2) + self.sigProjectCreated.emit(self._project) + else: # pragma: no cover + self.ql_validation_err.setText("Invalid Project Type - Not Implemented") + return + + super().accept() + + def select_dir(self): # pragma: no cover + path = QFileDialog.getExistingDirectory( + self, "Select Project Parent Directory") + if path: + self.prj_dir.setText(path) + + def show(self): + self.setModal(True) + super().show() + + @property + def project(self): + return self._project diff --git a/dgp/gui/dialogs/custom_validators.py b/dgp/gui/dialogs/custom_validators.py new file mode 100644 index 0000000..a44310c --- /dev/null +++ b/dgp/gui/dialogs/custom_validators.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +from pathlib import Path +from typing import Tuple + +from PyQt5.QtGui import QValidator + + +class FileExistsValidator(QValidator): + # TODO: Move this into its own module (custom_validators?) + def __init__(self, parent=None): + super().__init__(parent=parent) + + def validate(self, value: str, pos: int): + """Note, the Python implementation of this differs from the C++ API + value and pos are passed as pointers in C++ allowing them to be mutated + within the validate function. + As this cannot be done in Python, the return type signature is changed instead + to incorporate value and pos as a tuple with the QValidator State + """ + try: + path = Path(value) + except TypeError: + return QValidator.Invalid, value, pos + + if path.is_file(): + # Checking .exists() is redundant + return QValidator.Acceptable, value, pos + return QValidator.Intermediate, value, pos + + +class DirectoryValidator(QValidator): + """Used to validate a directory path. + + If exist_ok is True, validation will be successful if the directory already exists. + If exist_ok is False, validation will only be successful if the parent of the specified + path is a directory, and it exists. + """ + def __init__(self, exist_ok=True, parent=None): + super().__init__(parent=parent) + self._exist_ok = exist_ok + + def validate(self, value: str, pos: int) -> Tuple[int, str, int]: + """TODO: Think about the logic here, allow nonexistent path if parent exists? e.g. creating new dir""" + try: + path = Path(value) + except TypeError: + return QValidator.Invalid, value, pos + + if path.is_reserved(): + return QValidator.Invalid, value, pos + if path.is_file(): + return QValidator.Invalid, value, pos + + if path.is_dir() and self._exist_ok: + return QValidator.Acceptable, str(path.absolute()), pos + + if path.is_dir() and not self._exist_ok: + return QValidator.Intermediate, value, pos + + return QValidator.Intermediate, value, pos diff --git a/dgp/gui/dialogs/data_import_dialog.py b/dgp/gui/dialogs/data_import_dialog.py new file mode 100644 index 0000000..8680137 --- /dev/null +++ b/dgp/gui/dialogs/data_import_dialog.py @@ -0,0 +1,250 @@ +# -*- coding: utf-8 -*- +import csv +import logging +import shutil +from datetime import datetime +from pathlib import Path +from typing import Union, Optional, List + +from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal, QDate, QRegExp +from PyQt5.QtGui import QStandardItemModel, QStandardItem, QIcon, QRegExpValidator +from PyQt5.QtWidgets import QDialog, QFileDialog, QListWidgetItem, QCalendarWidget, QWidget, QFormLayout + +from dgp.core import Icon, DataType +from dgp.core.controllers.gravimeter_controller import GravimeterController +from dgp.core.controllers.dataset_controller import DataSetController +from dgp.core.controllers.controller_interfaces import IAirborneController, IFlightController, IDataSetController +from dgp.core.models.datafile import DataFile +from dgp.gui.ui.data_import_dialog import Ui_DataImportDialog +from .dialog_mixins import FormValidator +from .custom_validators import FileExistsValidator + +__all__ = ['DataImportDialog'] + + +class DataImportDialog(QDialog, Ui_DataImportDialog, FormValidator): + + load = pyqtSignal(DataFile, dict, DataSetController) + + def __init__(self, project: IAirborneController, + datatype: DataType, base_path: str = None, + parent: Optional[QWidget] = None): + super().__init__(parent=parent) + self.setupUi(self) + self.log = logging.getLogger(__name__) + + self._project = project + self._datatype = datatype + self._base_path = base_path or str(Path().home().resolve()) + self._type_map = {DataType.GRAVITY: 0, DataType.TRAJECTORY: 1} + self._type_filters = {DataType.GRAVITY: "Gravity (*.dat *.csv);;Any (*.*)", + DataType.TRAJECTORY: "Trajectory (*.dat *.csv *.txt);;Any (*.*)"} + + # Declare parameter names and values mapped from the dialog for specific DataType + # These match up with the methods in trajectory/gravity_ingestor + self._params_map = { + DataType.GRAVITY: { + 'columns': lambda: None, # TODO: Change in future based on Sensor Type + 'interp': lambda: self.qchb_grav_interp.isChecked(), + 'skiprows': lambda: 1 if self.qchb_grav_hasheader.isChecked() else 0 + }, + DataType.TRAJECTORY: { + 'timeformat': lambda: self.qcb_traj_timeformat.currentText().lower(), + 'columns': lambda: self.qcb_traj_timeformat.currentData(Qt.UserRole), + 'skiprows': lambda: 1 if self.qchb_traj_hasheader.isChecked() else 0, + 'is_utc': lambda: self.qchb_traj_isutc.isChecked() + } + } + + self._gravity = QListWidgetItem(Icon.GRAVITY.icon(), "Gravity") + self._gravity.setData(Qt.UserRole, DataType.GRAVITY) + self._trajectory = QListWidgetItem(Icon.TRAJECTORY.icon(), "Trajectory") + self._trajectory.setData(Qt.UserRole, DataType.TRAJECTORY) + + self.qlw_datatype.addItem(self._gravity) + self.qlw_datatype.addItem(self._trajectory) + self.qlw_datatype.setCurrentRow(self._type_map.get(datatype, 0)) + + self.qcb_flight.currentIndexChanged.connect(self._flight_changed) + self.qcb_flight.setModel(self.project.flight_model) + + self.qde_date.setDate(datetime.today()) + self._calendar = QCalendarWidget() + self.qde_date.setCalendarWidget(self._calendar) + self.qde_date.setCalendarPopup(True) + self.qpb_date_from_flight.clicked.connect(self._set_date) + + # Gravity Widget + self.qcb_gravimeter.currentIndexChanged.connect(self._gravimeter_changed) + self._meter_model = self.project.meter_model # type: QStandardItemModel + self.qcb_gravimeter.setModel(self._meter_model) + self.qpb_add_sensor.clicked.connect(self.project.add_gravimeter_dlg) + # if self._meter_model.rowCount() == 0: + # print("NO meters available") + self.qcb_gravimeter.setCurrentIndex(0) + + # Trajectory Widget + self._traj_timeformat_model = QStandardItemModel() + self.qcb_traj_timeformat.setModel(self._traj_timeformat_model) + self.qcb_traj_timeformat.currentIndexChanged.connect(self._traj_timeformat_changed) + sow = QStandardItem("SOW") + sow.setData(['week', 'sow', 'lat', 'long', 'ell_ht'], Qt.UserRole) + hms = QStandardItem("HMS") + hms.setData(['mdy', 'hms', 'lat', 'long', 'ell_ht'], Qt.UserRole) + serial = QStandardItem("Serial") + serial.setData(['datenum', 'lat', 'long', 'ell_ht'], Qt.UserRole) + self._traj_timeformat_model.appendRow(hms) + self._traj_timeformat_model.appendRow(sow) + self._traj_timeformat_model.appendRow(serial) + + # Signal connections + self.qle_filepath.textChanged.connect(self._filepath_changed) + self.qlw_datatype.currentItemChanged.connect(self._datatype_changed) + self.qpb_browse.clicked.connect(self._browse) + self.qpb_add_flight.clicked.connect(self.project.add_flight_dlg) + + self.qsw_advanced_properties.setCurrentIndex(self._type_map[datatype]) + + # Configure Validators + self.qle_filepath.setValidator(FileExistsValidator()) + self.qcb_dataset.setValidator(QRegExpValidator(QRegExp("[A-Za-z]\+"))) + + def set_initial_flight(self, flight: IFlightController): + for i in range(self.qcb_flight.model().rowCount()): # pragma: no branch + child = self.qcb_flight.model().item(i, 0) + if child.uid == flight.uid: # pragma: no branch + self.qcb_flight.setCurrentIndex(i) + break + + @property + def validation_targets(self) -> List[QFormLayout]: + return [self.qfl_common] + + @property + def validation_error(self): + return self.ql_validation_err + + @property + def project(self) -> IAirborneController: + return self._project + + @property + def flight(self) -> IFlightController: + fc = self.qcb_flight.model().item(self.qcb_flight.currentIndex()) + return self.project.get_child(fc.uid) + + @property + def dataset(self) -> IDataSetController: + model: QStandardItemModel = self.qcb_dataset.model() + dsc: IDataSetController = model.item(self.qcb_dataset.currentIndex()) + return self.flight.get_child(dsc.uid) + + @property + def file_path(self) -> Union[Path, None]: + if not len(self.qle_filepath.text()): + return None + return Path(self.qle_filepath.text()) + + @property + def datatype(self) -> DataType: + return self.qlw_datatype.currentItem().data(Qt.UserRole) + + @property + def _browse_path(self): + return self.file_path or self._base_path + + @property + def date(self) -> datetime: + _date: QDate = self.qde_date.date() + return datetime(_date.year(), _date.month(), _date.day()) + + def accept(self): # pragma: no cover + if not self.validate(empty_combo_ok=False): + print("Dialog input not valid") + return + + file = DataFile(self.datatype, date=self.date, + source_path=self.file_path, name=self.qle_rename.text()) + param_map = self._params_map[self.datatype] + params = {key: value() for key, value in param_map.items()} + self.load.emit(file, params, self.dataset) + + if self.qchb_copy_file.isChecked(): + self._copy_file() + return super().accept() + + def _copy_file(self): # pragma: no cover + src = self.file_path + dest_name = src.name + if self.qle_rename.text(): + dest_name = self.qle_rename.text() + '.dat' + + dest = self.project.path.resolve().joinpath(dest_name) + try: + shutil.copy(src, dest) + except IOError: + self.log.exception("Unable to copy source file to project directory.") + + def _set_date(self): + self.qde_date.setDate(self.flight.get_attr('date')) + + @pyqtSlot(name='_browse') + def _browse(self): # pragma: no cover + path, _ = QFileDialog.getOpenFileName(self, "Browse for data file", + str(self._browse_path), + self._type_filters[self._datatype]) + if path: + self.qle_filepath.setText(path) + + @pyqtSlot(QListWidgetItem, QListWidgetItem, name='_datatype_changed') + def _datatype_changed(self, current: QListWidgetItem, previous: QListWidgetItem): # pragma: no cover + self._datatype = current.data(Qt.UserRole) + self.qsw_advanced_properties.setCurrentIndex(self._type_map[self._datatype]) + + @pyqtSlot(str, name='_filepath_changed') + def _filepath_changed(self, text: str): # pragma: no cover + """ + Detect attributes of file and display them in the dialog info section + """ + path = Path(text) + if not path.is_file(): + return + self.qle_filename.setText(path.name) + st_size_mib = path.stat().st_size / 1048576 # 1024 ** 2 + self.qle_filesize.setText("{:.3f} MiB".format(st_size_mib)) + with path.open(mode='r', newline='') as fd: + try: + has_header = csv.Sniffer().has_header(fd.read(8192)) + except csv.Error: + has_header = False + print("File has header row: " + str(has_header)) + fd.seek(0) + + # Detect line count + lines = fd.readlines() + line_count = len(lines) + col_count = len(lines[0].split(',')) + self.qle_linecount.setText(str(line_count)) + self.qle_colcount.setText(str(col_count)) + + @pyqtSlot(int, name='_gravimeter_changed') + def _gravimeter_changed(self, index: int): # pragma: no cover + meter_ctrl = self.project.meter_model.item(index) + if not meter_ctrl: + self.log.debug("No meter available") + return + if isinstance(meter_ctrl, GravimeterController): + sensor_type = meter_ctrl.get_attr('type') or "Unknown" + self.qle_sensortype.setText(sensor_type) + self.qle_grav_format.setText(meter_ctrl.get_attr('column_format')) + + @pyqtSlot(int, name='_traj_timeformat_changed') + def _traj_timeformat_changed(self, index: int): # pragma: no cover + timefmt = self._traj_timeformat_model.item(index) + cols = ', '.join(timefmt.data(Qt.UserRole)) + self.qle_traj_format.setText(cols) + + @pyqtSlot(int, name='_flight_changed') + def _flight_changed(self, row: int): + self.qcb_dataset.setModel(self.flight.datasets) + diff --git a/dgp/gui/dialogs/dialog_mixins.py b/dgp/gui/dialogs/dialog_mixins.py new file mode 100644 index 0000000..47642a0 --- /dev/null +++ b/dgp/gui/dialogs/dialog_mixins.py @@ -0,0 +1,112 @@ +# -*- coding: utf-8 -*- +from typing import List + +from PyQt5.QtGui import QValidator, QRegExpValidator, QIntValidator, QDoubleValidator +from PyQt5.QtWidgets import (QFormLayout, QWidget, QLineEdit, QLabel, QHBoxLayout, QLayoutItem, + QVBoxLayout, QComboBox) + +__all__ = ['FormValidator', 'VALIDATION_ERR_MSG'] +VALIDATION_ERR_MSG = "Ensure all marked fields are filled." + + +class FormValidator: + """FormValidator Mixin Class + + This mixin provides a simple interface to run automatic validation + on one or more QFormLayout objects in a Qt Object (typically within + a QDialog). + + The mixin also supports validation of fields that are nested within a + layout, for example it is common to use a QHBoxLayout (horizontal layout) + within the FormLayout field area to have both a QLineEdit input and a + QPushButton next to it (to browse for a file for example). + The validate method will introspect any sub-layouts and retrieve the FIRST + widget that can be validated, which has a validator or input mask set. + + TODO: Create a subclass of QRegExpValidator that allows a human error + message to be set + TODO: Consider some way to hook into fields and validate on changes + That is a dynamic validation, so when the user corrects an invalid field + the state is updated + + + """ + ERR_STYLE = "QLabel { color: red; }" + _CAN_VALIDATE = (QLineEdit, QComboBox) + + @property + def validation_targets(self) -> List[QFormLayout]: + """Override this property with the QFormLayout object to be validated""" + raise NotImplementedError + + @property + def validation_error(self) -> QLabel: + return QLabel() + + def _validate_field(self, widget: QWidget, label: QLabel, check_combo=False) -> bool: + if check_combo and isinstance(widget, QComboBox): + if not len(widget.currentText()) > 0: + label.setStyleSheet(self.ERR_STYLE) + label.setToolTip("ComboBox must have a value selected.") + return False + else: + label.setStyleSheet("") + return True + + validator: QValidator = widget.validator() + if widget.hasAcceptableInput(): + label.setStyleSheet("") + return True + else: + label.setStyleSheet(self.ERR_STYLE) + if isinstance(validator, QRegExpValidator): + reason = "Input must match regular expression: {0!s}".format(validator.regExp().pattern()) + elif isinstance(validator, (QIntValidator, QDoubleValidator)): + reason = "Input must be between {0} and {1}".format( + validator.bottom(), validator.top()) + elif isinstance(validator, QValidator): # TODO: Test Coverage + reason = "Input does not pass validation." + else: + reason = "Invalid Input: input must conform to mask: {}".format(widget.inputMask()) + label.setToolTip(reason) + return False + + def _validate_form(self, form: QFormLayout, check_combo=False): + res = [] + for i in range(form.rowCount()): + try: + label: QLabel = form.itemAt(i, QFormLayout.LabelRole).widget() + except AttributeError: + label = QLabel() + field: QLayoutItem = form.itemAt(i, QFormLayout.FieldRole) + if field is None: + continue + + if field.layout() is not None and isinstance(field.layout(), (QHBoxLayout, QVBoxLayout)): + layout = field.layout() + for j in range(layout.count()): + _field = layout.itemAt(j) + _widget: QWidget = _field.widget() + if isinstance(_widget, self._CAN_VALIDATE): + if _widget.validator() or (hasattr(_widget, 'inputMask') and _widget.inputMask()): + field = _field + break + elif check_combo and isinstance(_widget, QComboBox): + field = _field + break + + widget = field.widget() + if widget is not None and isinstance(widget, self._CAN_VALIDATE): + res.append(self._validate_field(widget, label, check_combo)) + + return all(result for result in res) + + def validate(self, notify=True, empty_combo_ok=True) -> bool: + res = [] + for form in self.validation_targets: + res.append(self._validate_form(form, check_combo=not empty_combo_ok)) + valid = all(result for result in res) + if not valid and notify: + self.validation_error.setText(VALIDATION_ERR_MSG) + + return valid diff --git a/dgp/gui/dialogs/project_properties_dialog.py b/dgp/gui/dialogs/project_properties_dialog.py new file mode 100644 index 0000000..f809e23 --- /dev/null +++ b/dgp/gui/dialogs/project_properties_dialog.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- +from datetime import datetime +from pathlib import Path +from typing import List, Any + +from PyQt5.QtWidgets import QFormLayout, QLineEdit, QDateTimeEdit, QWidget +from PyQt5.QtWidgets import QDialog + +from dgp.core.oid import OID +from dgp.core.controllers.controller_interfaces import IAirborneController +from .dialog_mixins import FormValidator +from ..ui.project_properties_dialog import Ui_ProjectPropertiesDialog + + +class ProjectPropertiesDialog(QDialog, Ui_ProjectPropertiesDialog, FormValidator): + + def __init__(self, project: IAirborneController, parent=None): + super().__init__(parent=parent) + self.setupUi(self) + self._project = project + self.setWindowTitle(self._project.get_attr('name')) + self._updates = {} + self._field_map = { + str: (lambda v: v.strip(), QLineEdit), + Path: (lambda v: str(v.resolve()), QLineEdit), + datetime: (lambda v: v, QDateTimeEdit), + OID: (lambda v: v.base_uuid, QLineEdit) + } + + self._setup_properties_tab() + + def _get_field_attr(self, _type: Any): + try: + attrs = self._field_map[_type] + except KeyError: + for key in self._field_map.keys(): + if issubclass(_type, key): + return self._field_map[key] + return None + return attrs + + def _setup_properties_tab(self): + for key in self._project.fields: + enabled = self._project.writeable(key) + validator = self._project.validator(key) + + raw_value = self._project.get_attr(key) + data_type = type(raw_value) + + value_lambda, widget_type = self._get_field_attr(data_type) + + widget: QWidget = widget_type(value_lambda(raw_value)) + widget.setEnabled(enabled) + if validator: + widget.setValidator(validator) + + self.qfl_properties.addRow(str(key.strip('_')).capitalize(), widget) + if enabled: + self._updates[key] = data_type, widget + + @property + def validation_targets(self) -> List[QFormLayout]: + return [self.qfl_properties] + + @property + def validation_error(self): + return self.ql_validation_err + + def accept(self): + print("Updating values for fields:") + for key in self._updates: + print(key) + try: + self._project.set_attr(key, self._updates[key][1].text()) + except AttributeError: + print("Can't update key: {}".format(key)) + + if not self.validate(): + print("A value is invalid") + return + + super().accept() diff --git a/dgp/gui/dialogs/recent_project_dialog.py b/dgp/gui/dialogs/recent_project_dialog.py new file mode 100644 index 0000000..5458953 --- /dev/null +++ b/dgp/gui/dialogs/recent_project_dialog.py @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- +import sys +import logging +from pathlib import Path +from typing import Union + +import PyQt5.QtWidgets as QtWidgets +from PyQt5.QtCore import QModelIndex, pyqtSignal + +from dgp.gui import RecentProjectManager +from dgp.gui.utils import ConsoleHandler, LOG_FORMAT, LOG_COLOR_MAP, load_project_from_path +from dgp.gui.dialogs.create_project_dialog import CreateProjectDialog +from dgp.gui.ui.recent_project_dialog import Ui_RecentProjects + + +class RecentProjectDialog(QtWidgets.QDialog, Ui_RecentProjects): + """Display a QDialog with a recent project's list, and ability to browse for, + or create a new project. + Recent projects are retrieved via the QSettings object and global DGP keys. + + """ + sigProjectLoaded = pyqtSignal(object) + + def __init__(self, *args): + super().__init__(*args) + self.setupUi(self) + + # Configure Logging + self.log = self.setup_logging() + # Experimental: Add a logger that sets the label_error text + error_handler = ConsoleHandler(self.write_error) + error_handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s')) + error_handler.setLevel(logging.DEBUG) + self.log.addHandler(error_handler) + + self.recents = RecentProjectManager() + + self.qpb_new_project.clicked.connect(self.new_project) + self.qpb_browse.clicked.connect(self.browse_project) + self.qpb_clear_recents.clicked.connect(self.recents.clear) + + self.qlv_recents.setModel(self.recents.model) + self.qlv_recents.doubleClicked.connect(self._activated) + + self.show() + + @staticmethod + def setup_logging(level=logging.DEBUG): + root_log = logging.getLogger() + std_err_handler = logging.StreamHandler(sys.stderr) + std_err_handler.setLevel(level) + std_err_handler.setFormatter(LOG_FORMAT) + root_log.addHandler(std_err_handler) + return logging.getLogger(__name__) + + def _activated(self, index: QModelIndex): + self.accept() + + @property + def project_path(self) -> Union[Path, None]: + return self.recents.path(self.qlv_recents.currentIndex()) + + def load_project(self, path: Path): + """Load a project from file and emit the result + + Parameters + ---------- + path + + Returns + ------- + + """ + assert isinstance(path, Path) + project = load_project_from_path(path) + project.path = path # update project's path in case folder was moved + self.sigProjectLoaded.emit(project) + super().accept() + + def accept(self): + if self.project_path is not None: + self.load_project(self.project_path) + super().accept() + else: + self.log.warning("No project selected") + + def new_project(self): + """Allow the user to create a new project""" + dialog = CreateProjectDialog(parent=self) + dialog.sigProjectCreated.connect(self.sigProjectLoaded.emit) + if dialog.exec_(): + super().accept() + + def browse_project(self): + """Allow the user to browse for a project directory and load.""" + path = QtWidgets.QFileDialog.getExistingDirectory(self, "Select Project Dir") + if not path: + return + self.load_project(Path(path)) + + def write_error(self, msg, level=None) -> None: + self.label_error.setText(msg) + self.label_error.setStyleSheet('color: {}'.format(LOG_COLOR_MAP[level])) diff --git a/dgp/gui/loader.py b/dgp/gui/loader.py deleted file mode 100644 index 9e0b10d..0000000 --- a/dgp/gui/loader.py +++ /dev/null @@ -1,29 +0,0 @@ -# coding: utf-8 - -import pathlib - -from pandas import DataFrame -from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, QThread, pyqtBoundSignal - -from dgp.lib.types import DataPacket -from dgp.lib.gravity_ingestor import read_at1a -from dgp.lib.trajectory_ingestor import import_trajectory - - -class LoadFile(QThread): - progress = pyqtSignal(int) # type: pyqtBoundSignal - loaded = pyqtSignal() # type: pyqtBoundSignal - data = pyqtSignal(DataPacket) # type: pyqtBoundSignal - - def __init__(self, path: pathlib.Path, datatype: str, flight_id: str, parent=None, **kwargs): - super().__init__(parent) - self._path = path - self._dtype = datatype - self._flight = flight_id - self._functor = {'gravity': read_at1a, 'gps': import_trajectory}.get(datatype, None) - - def run(self): - df = self._functor(self._path) - data = DataPacket(df, self._path, self._flight, self._dtype) - self.data.emit(data) - self.loaded.emit() diff --git a/dgp/gui/main.py b/dgp/gui/main.py index 4d9a2c3..31e1ebe 100644 --- a/dgp/gui/main.py +++ b/dgp/gui/main.py @@ -1,521 +1,376 @@ -# coding: utf-8 - -import functools +# -*- coding: utf-8 -*- import logging -import os -from typing import Tuple, List, Dict - -from pandas import Series, DataFrame -from PyQt5 import QtCore, QtWidgets, QtGui -from PyQt5.QtCore import pyqtSignal, pyqtBoundSignal -from PyQt5.QtGui import QColor -from PyQt5.uic import loadUiType - -import dgp.lib.project as prj -from dgp.gui.loader import LoadFile -from dgp.lib.plotter import LineGrabPlot -from dgp.gui.utils import ConsoleHandler, LOG_FORMAT, get_project_file -from dgp.gui.dialogs import ImportData, AddFlight, CreateProject - -# Load .ui form -main_window, _ = loadUiType('dgp/gui/ui/main_window.ui') - - -def autosave(method): - """Decorator to call save_project for functions that alter project state.""" - def enclosed(self, *args, **kwargs): - if kwargs: - result = method(self, *args, **kwargs) - elif len(args) > 1: - result = method(self, *args) - else: - result = method(self) - self.save_project() - return result - return enclosed - - -class MainWindow(QtWidgets.QMainWindow, main_window): +import warnings +from pathlib import Path + +import PyQt5.QtWidgets as QtWidgets +from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal, QByteArray +from PyQt5.QtGui import QColor, QCloseEvent, QDesktopServices +from PyQt5.QtWidgets import QProgressDialog, QFileDialog, QMessageBox, QMenu, QAction + +from dgp import __about__ +from dgp.core.oid import OID +from dgp.core.controllers.controller_interfaces import VirtualBaseController +from dgp.core.types.enumerations import Links, Icon +from dgp.core.controllers.project_controllers import AirborneProjectController +from dgp.core.controllers.project_treemodel import ProjectTreeModel +from dgp.core.models.project import AirborneProject, GravityProject +from dgp.gui import settings, SettingsKey, RecentProjectManager, UserSettings +from dgp.gui.utils import (ConsoleHandler, LOG_FORMAT, LOG_LEVEL_MAP, + LOG_COLOR_MAP, ProgressEvent, load_project_from_path) +from dgp.gui.dialogs.create_project_dialog import CreateProjectDialog +from dgp.gui.dialogs.recent_project_dialog import RecentProjectDialog +from dgp.gui.widgets.workspace_widget import WorkspaceWidget +from dgp.gui.workspaces import tab_factory +from dgp.gui.ui.main_window import Ui_MainWindow + + +class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): """An instance of the Main Program Window""" + sigStatusMessage = pyqtSignal(str) - # Define signals to allow updating of loading progress - status = pyqtSignal(str) # type: pyqtBoundSignal - progress = pyqtSignal(int) # type: pyqtBoundSignal - - def __init__(self, project: prj.GravityProject=None, *args): + def __init__(self, *args): super().__init__(*args) + self.setupUi(self) + self.title = 'Dynamic Gravity Processor [*]' + self.setWindowTitle(self.title) - self.setupUi(self) # Set up ui within this class - which is base_class defined by .ui file - self.title = 'Dynamic Gravity Processor' - - # Setup logging - self.log = logging.getLogger(__name__) + # Attach to the root logger to capture all child events + self.log = logging.getLogger() + # Setup logging handler to log to GUI panel console_handler = ConsoleHandler(self.write_console) console_handler.setFormatter(LOG_FORMAT) + sb_handler = ConsoleHandler(self.show_status) + sb_handler.setFormatter(logging.Formatter("%(message)s")) self.log.addHandler(console_handler) + self.log.addHandler(sb_handler) self.log.setLevel(logging.DEBUG) - # Setup Project - self.project = project - # self.update_project() - - # See http://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtreeview - # Set Stylesheet customizations for GUI Window - self.setStyleSheet(""" - QTreeView::item { - - } - QTreeView::branch:has-siblings:adjoins-them { - /*border: 1px solid black; */ - } - QTreeView::branch { - background: palette(base); - } - - QTreeView::branch:has-siblings:!adjoins-item { - /*background: cyan;*/ - } - - QTreeView::branch:has-siblings:adjoins-item { - background: orange; - } - - QTreeView::branch:!has-children:!has-siblings:adjoins-item { - background: blue; - } - - QTreeView::branch:closed:has-children:has-siblings { - background: none; - image: url(:/images/assets/branch-closed.png); - } - - QTreeView::branch:has-children:!has-siblings:closed { - image: url(:/images/assets/branch-closed.png); - } - - QTreeView::branch:open:has-children:has-siblings { - background: none; - image: url(:/images/assets/branch-open.png); - } - - QTreeView::branch:open:has-children:!has-siblings { - image: url(:/images/assets/branch-open.png); - } - """) - - # Initialize plotter canvas - self.gravity_stack = QtWidgets.QStackedWidget() - self.gravity_plot_layout.addWidget(self.gravity_stack) - - # Initialize Variables - # TODO: Change this to use pathlib.Path - self.import_base_path = os.path.join(os.getcwd(), '../tests') - - # Lock object used as simple Flag supporting the context manager protocol - self.current_flight = None # type: prj.Flight - self.flight_data = {} # Stores DataFrames for loaded flights - self.flight_plots = {} # Stores plotter objects for flights - # self.plot_curves = None # Initialized in self.init_plot() - - # TESTING - self.project_tree = ProjectTreeView(parent=self) - self.scan_flights() - # self.data_tab_layout.addWidget(self.project_tree) - self.gridLayout_2.addWidget(self.project_tree, 1, 0, 1, 2) - # TESTING - - def load(self): - self._init_plots() - self._init_slots() - self.update_project(signal_flight=True) - self.setWindowState(QtCore.Qt.WindowMaximized) - self.save_project() - self.show() - try: - self.progress.disconnect() - self.status.disconnect() - except TypeError: - # This will happen if there are no slots connected - pass + self.workspace: WorkspaceWidget + self.recents = RecentProjectManager() + self.user_settings = UserSettings() + self._progress_events = {} + # Instantiate the Project Model and display in the ProjectTreeView + self.model = ProjectTreeModel(parent=self) + self.project_tree.setModel(self.model) - def _init_plots(self) -> None: - """ - Initialize plots for flight objects in project. - This allows us to switch between individual plots without re-plotting giving a vast - performance increase. - Returns - ------- - None - """ - self.progress.emit(0) - if self.project is None: - return - for i, flight in enumerate(self.project): # type: prj.Flight - if flight.uid in self.flight_plots: - continue - vlayout = QtWidgets.QVBoxLayout() - f_plot = LineGrabPlot(2, title=flight.name) - toolbar = f_plot.get_toolbar() - widget = QtWidgets.QWidget() - vlayout.addWidget(f_plot) - vlayout.addWidget(toolbar) - widget.setLayout(vlayout) - self.flight_plots[flight.uid] = f_plot, widget - self.gravity_stack.addWidget(widget) - gravity = self.flight_data[flight.uid].get('gravity') - if gravity is not None: - # self.plot_gravity(f_plot, (gravity['gravity'], [gravity['long'], gravity['cross']])) - self.plot_gravity2(f_plot, gravity, {0: 'gravity', 1: ['long', 'cross']}) - self.log.debug("Initialized Flight Plot: {}".format(f_plot)) - self.status.emit('Flight Plot {} Initialized'.format(flight.name)) - self.progress.emit(i+1) - # TODO: Add hook here to update status message on a splash screen when loading - - def _init_slots(self): - """Initialize PyQt Signals/Slots for UI Buttons and Menus""" + # Add sub-menu to display recent projects + self.recent_menu = QMenu("Recent Projects") + self.menuFile.addMenu(self.recent_menu) + + self.import_base_path = Path('~').expanduser().joinpath('Desktop') + self._default_status_timeout = 5000 # Status Msg timeout in milli-sec + + # Initialize signal/slot connections: + + # Use dock's toggleViewAction to generate QAction, resolves issue where + # dock visibility would be hidden after minimizing the main window + self.action_project_dock: QAction = self.project_dock.toggleViewAction() + self.action_project_dock.setIcon(Icon.TREE.icon()) + self.toolbar.addAction(self.action_project_dock) + self.menuView.addAction(self.action_project_dock) + + # Model Event Signals # + self.model.tabOpenRequested.connect(self._tab_open_requested) + # self.model.tabCloseRequested.connect(self.workspace.close_tab) + self.model.progressNotificationRequested.connect(self._progress_event_handler) + self.model.projectMutated.connect(self._project_mutated) + self.model.projectClosed.connect(lambda x: self._update_recent_menu()) # File Menu Actions # - self.action_exit.triggered.connect(self.exit) - self.action_file_new.triggered.connect(self.new_project) - self.action_file_open.triggered.connect(self.open_project) - self.action_file_save.triggered.connect(self.save_project) + self.action_exit.triggered.connect(self.close) + self.action_file_new.triggered.connect(self.new_project_dialog) + self.action_file_open.triggered.connect(self.open_project_dialog) + self.action_file_save.triggered.connect(self.save_projects) # Project Menu Actions # - self.action_import_data.triggered.connect(self.import_data) - self.action_add_flight.triggered.connect(self.add_flight) + self.action_import_gps.triggered.connect(self.model.import_gps) + self.action_import_grav.triggered.connect(self.model.import_gravity) + self.action_add_flight.triggered.connect(self.model.add_flight) + self.action_add_meter.triggered.connect(self.model.add_gravimeter) - # Project Tree View Actions # - # self.prj_tree.doubleClicked.connect(self.log_tree) - # self.prj_tree.clicked.connect(self.flight_changed) - # self.prj_tree.currentItemChanged(self.update_channels) - self.project_tree.clicked.connect(self.flight_changed) + # Help Menu Actions # + self.action_docs.triggered.connect(self.show_documentation) + self.action_about.triggered.connect(self.show_about) # Project Control Buttons # - self.prj_add_flight.clicked.connect(self.add_flight) - self.prj_import_data.clicked.connect(self.import_data) + self.prj_add_flight.clicked.connect(self.model.add_flight) + self.prj_add_meter.clicked.connect(self.model.add_gravimeter) + self.prj_import_gps.clicked.connect(self.model.import_gps) + self.prj_import_grav.clicked.connect(self.model.import_gravity) - # Channel Panel Buttons # - # self.selectAllChannels.clicked.connect(self.set_channel_state) + # Console Window Actions # + self.combo_console_verbosity.currentIndexChanged[str].connect( + self.set_logging_level) + + # Define recent projects menu action + self.recents.sigRecentProjectsChanged.connect(self._update_recent_menu) + self._update_recent_menu() + + def load(self, project: GravityProject = None, restore: bool = True): + """Interactively load the DGP MainWindow, restoring previous widget/dock + state, and any saved geometry state. + + If a project is explicitly specified then the project will be loaded into + the MainWindow, and the window shown. + If no project is specified, the users local settings are checked for the + last project that was active/opened, and it will be loaded into the + window. + Otherwise, a RecentProjectDialog is shown where the user can select from + a list of known recent projects, browse for a project folder, or create + a new project. - # self.gravity_channels.itemChanged.connect(self.channel_changed) - # self.resample_value.valueChanged[int].connect(self.resample_rate_changed) + Parameters + ---------- + project : :class:`GravityProject` + Explicitly pass a GravityProject or sub-type to be loaded into the + main window. + restore : bool, optional + If True (default) the MainWindow state and geometry will be restored + from the local settings repository. - # Console Window Actions # - self.combo_console_verbosity.currentIndexChanged[str].connect(self.set_logging_level) - - def exit(self): - """PyQt Slot: Exit the PyQt application by closing the main window (self)""" - self.close() - - # Experimental Context Menu - def create_actions(self): - info_action = QtWidgets.QAction('&Info') - info_action.triggered.connect(self.flight_info) - return [info_action] - - def flight_info(self): - self.log.info("Printing info about the selected flight: {}".format(self.current_flight)) - - # Experimental - def set_progress_bar(self, value=100, progress=None): - if progress is None: - progress = QtWidgets.QProgressBar() - progress.setValue(value) - self.statusBar().addWidget(progress) + """ + if restore: + self.restoreState(settings().value(SettingsKey.WindowState(), QByteArray())) + self.restoreGeometry(settings().value(SettingsKey.WindowGeom(), QByteArray())) + + self.show() + if project is not None: + self.sigStatusMessage.emit(f'Loading project {project.name}') + self.add_project(project) + elif self.recents.last_project_path() is not None and self.user_settings.reopen_last: + self.sigStatusMessage.emit(f'Loading last project') + self.log.info(f"Loading most recent project.") + project = load_project_from_path(self.recents.last_project_path()) + self.add_project(project) + else: + self.sigStatusMessage.emit("Selecting project") + recent_dlg = RecentProjectDialog() + recent_dlg.sigProjectLoaded.connect(self.add_project) + recent_dlg.exec_() + + self.project_tree.expandAll() + + def add_project(self, project: GravityProject): + """Add a project model to the window, first wrapping it in an + appropriate controller class + + Parameters + ---------- + project : :class:`GravityProject` + path : :class:`pathlib.Path` + + + """ + if isinstance(project, AirborneProject): + control = AirborneProjectController(project) else: - progress.setValue(value) + raise TypeError(f'Unsupported project type: {type(project)}') + + self.model.add_project(control) + self.project_tree.setExpanded(control.index(), True) + self.recents.add_recent_project(control.uid, control.get_attr('name'), + control.path) + + def open_project(self, path: Path, prompt: bool = True) -> None: + """Open/load a project from the given path. + + Parameters + ---------- + path : :class:`pathlib.Path` + Directory path containing valid DGP project *.json file + prompt : bool, optional + If True display a message box asking the user if they would like to + open the project in a new window. + Else the project is opened into the current MainWindow - return progress + """ + project = load_project_from_path(path) + if prompt and self.model.rowCount() > 0: + msg_dlg = QMessageBox(QMessageBox.Question, + "Open in New Window", + "Open Project in New Window?", + QMessageBox.Yes | QMessageBox.No, self) + res = msg_dlg.exec_() + else: + res = QMessageBox.No + + if res == QMessageBox.Yes: # Open new MainWindow instance + window = MainWindow() + window.load(project, restore=False) + window.activateWindow() + elif res == QMessageBox.No: # Open in current MainWindow + if project.uid in [p.uid for p in self.model.projects]: + self.log.warning("Project already opened in current workspace") + else: + self.add_project(project) + self.raise_() + + def closeEvent(self, event: QCloseEvent): + self.log.info("Saving project and closing.") + self.save_projects() + settings().setValue(SettingsKey.WindowState(), self.saveState()) + settings().setValue(SettingsKey.WindowGeom(), self.saveGeometry()) + + # Set last project to active project + if self.model.active_project is not None: + settings().setValue(SettingsKey.LastProjectUid(), + self.model.active_project.uid.base_uuid) + settings().setValue(SettingsKey.LastProjectPath(), + str(self.model.active_project.path.absolute())) + settings().setValue(SettingsKey.LastProjectName(), + self.model.active_project.get_attr("name")) + super().closeEvent(event) def set_logging_level(self, name: str): - """PyQt Slot: Changes logging level to passed string logging level name.""" + """PyQt Slot: Changes logging level to passed logging level name.""" self.log.debug("Changing logging level to: {}".format(name)) - # TODO: Replace this with gui.utils LOG_COLOR_MAP - level = {'debug': logging.DEBUG, 'info': logging.INFO, 'warning': logging.WARNING, 'error': logging.ERROR, - 'critical': logging.CRITICAL}[name.lower()] + level = LOG_LEVEL_MAP[name.lower()] self.log.setLevel(level) def write_console(self, text, level): - """PyQt Slot: Log a message to the GUI console""" - log_color = {'DEBUG': QColor('Blue'), 'INFO': QColor('Green'), 'WARNING': QColor('Red'), - 'ERROR': QColor('Pink'), 'CRITICAL': QColor('Orange')}.get(level, QColor('Black')) - + """PyQt Slot: Logs a message to the GUI console""" + log_color = QColor(LOG_COLOR_MAP.get(level.lower(), 'black')) self.text_console.setTextColor(log_color) self.text_console.append(str(text)) - self.text_console.verticalScrollBar().setValue(self.text_console.verticalScrollBar().maximum()) - - # TODO: Delete after testing - def log_tree(self, index: QtCore.QModelIndex): - item = self.prj_tree.model().itemFromIndex(index) # type: QtWidgets.QListWidgetItem - text = str(item.text()) - return - # if text.startswith('Flight:'): - # self.log.debug("Clicked Flight object") - # _, flight_id = text.split(' ') - # flight = self.project.get_flight(flight_id) # type: prj.Flight - # self.log.debug(flight) - # grav_data = flight.gravity - # - # if grav_data is not None: - # self.log.debug(grav_data.describe()) - # else: - # self.log.debug("No grav data") - # - # self.log.debug(text) - # - # self.log.debug(item.toolTip()) - # print(dir(item)) - - ##### - # Plot functions - ##### - - def scan_flights(self): - """Scan flights and load data into self.flight_data""" - self.log.info("Rescanning and loading flight data.") - for flight in self.project: - if flight.uid not in self.flight_data: - self.flight_data[flight.uid] = {'gravity': flight.gravity, 'gps': flight.gps} - else: - self.flight_data[flight.uid].update({'gravity': flight.gravity, 'gps': flight.gps}) + self.text_console.verticalScrollBar().setValue( + self.text_console.verticalScrollBar().maximum()) + + def show_status(self, text, level): + """Displays a message in the MainWindow's status bar for specific + log level events.""" + if level.lower() == 'error' or level.lower() == 'info': + self.statusBar().showMessage(text, self._default_status_timeout) + + def _update_recent_menu(self): + """Regenerate the recent projects' menu actions - def flight_changed(self, index: QtCore.QModelIndex) -> None: + Retrieves the recent projects references from the + :class:`RecentProjectManager` and adds them to the recent projects list + if they are not already active/open in the workspace. """ - PyQt Slot called upon change in flight selection using the Project Tree View. - When a new flight is selected we want to plot the gravity channel in subplot 0, with cross and long in subplot 1 - GPS data will be plotted in the GPS tab on its own plot. + self.recent_menu.clear() + recents = [ref for ref in self.recents.project_refs + if ref.uid not in [p.uid for p in self.model.projects]] + if len(recents) == 0: + self.recent_menu.setEnabled(False) + else: + self.recent_menu.setEnabled(True) + for ref in recents: + self.recent_menu.addAction(ref.name, lambda: self.open_project(Path(ref.path))) + + def _tab_open_requested(self, uid: OID, controller: VirtualBaseController): + """pyqtSlot(OID, IBaseController, str) + Parameters ---------- - index : QtCore.QModelIndex - Model index referencing the newly selected TreeView Item - - Returns - ------- - None + uid + controller """ - qitem = self.project_tree.model().itemFromIndex(index) # type: QtGui.QStandardItem - if qitem is None: + if uid is None: return - qitem_data = qitem.data(QtCore.Qt.UserRole) - - if not isinstance(qitem_data, prj.Flight): - # Return as we're not interested in handling non-flight selections at this time - return None + existing = self.workspace.get_tab(uid) + if existing is not None: + self.workspace.setCurrentWidget(existing) else: - flight = qitem_data # type: prj.Flight - - if self.current_flight == flight: - # Return as this is the same flight as previously selected - return None - else: - self.current_flight = flight - - # Write flight information to TextEdit box in GUI - self.text_info.clear() - self.text_info.appendPlainText(str(flight)) - - # Check if there is a plot for this flight already - if self.flight_plots.get(flight.uid, None) is not None: - self.log.debug("Already have a plot for this flight: {}".format(flight.name)) - curr_plot, stack_widget = self.flight_plots[flight.uid] # type: LineGrabPlot - self.gravity_stack.setCurrentWidget(stack_widget) - pass - - grav_data = self.flight_data[flight.uid].get('gravity', None) - gps_data = self.flight_data[flight.uid].get('gps', None) - - # TODO: Move this (and gps plot) into separate functions - # so we can call this on app startup to pre-plot everything - if grav_data is not None: - # Data series for plotting - gravity = grav_data['gravity'] # type: Series - long = grav_data['long'] - cross = grav_data['cross'] - # Experimental - so that we only have to draw the plot once, then we switch between - if not curr_plot.plotted: - self.log.debug("Plotting gravity channel in subplot 0") - # self.plot_gravity(curr_plot, (gravity, [long, cross])) - self.plot_gravity2(curr_plot, grav_data, {0: 'gravity', 1: ['long', 'cross']}) - self.log.debug("Already plotted, switching widget stack") - - if gps_data is not None: - pass - - @staticmethod - def plot_gravity(plot: LineGrabPlot, data: Tuple): - # TODO: Change this to accept a dataframe for data, and a tuple of [fields] to plot in respective subplot - plot.clear() - for i, series in enumerate(data): - if not isinstance(series, List): - plot.plot(plot[i], series.index, series.values, label=series.name) - else: - for line in series: - plot.plot(plot[i], line.index, line.values, label=line.name) - - plot.draw() - plot.plotted = True - - def plot_gravity2(self, plot: LineGrabPlot, data: DataFrame, fields: Dict): - plot.clear() - for index in fields: - if isinstance(fields[index], str): - series = data.get(fields[index]) # type: Series - plot.plot(plot[index], series.index, series.values, label=series.name) - continue - for field in fields[index]: - series = data.get(field) # type: Series - plot.plot(plot[index], series.index, series.values, label=series.name) - plot.draw() - plot.plotted = True - - ##### - # Project functions - ##### - - def import_data(self) -> None: - """Load data file (GPS or Gravity) using a background Thread, then hand it off to the project.""" - dialog = ImportData(self.project, self.current_flight) - if dialog.exec_(): - path, dtype, flt_id = dialog.content - if self.project is not None: - flight = self.project.get_flight(flt_id) - self.log.info("Importing {} file from {} into flight: {}".format(dtype, path, flight.uid)) - else: - flight = None - if self.project is not None: - self.log.debug("Importing file using new thread method") - ld2 = LoadFile(path, 'gravity', flight, self) - ld2.data.connect(self.project.add_data) - ld2.loaded.connect(functools.partial(self.update_project, signal_flight=True)) - ld2.loaded.connect(self.save_project) - ld2.loaded.connect(self.scan_flights) - self.current_flight = None - ld2.start() + constructor = tab_factory(controller) + if constructor is not None: + tab = constructor(controller) + self.workspace.addTab(tab) else: - self.log.warning("No active project, not importing.") - - # gps_fields = ['mdy', 'hms', 'lat', 'lon', 'ell_ht', 'ortho_ht', 'num_sats', 'pdop'] - # self.gps_data = ti.import_trajectory(path, columns=gps_fields, skiprows=1) - - def new_project(self) -> QtWidgets.QMainWindow: - new_window = True - dialog = CreateProject() - if dialog.exec_(): - self.log.info("Creating new project") - project = dialog.project - if new_window: - self.log.debug("Opening project in new window") - return MainWindow(project) - else: - self.project = project - self.project.save() - self.update_project() - - # TODO: This will eventually require a dialog to allow selection of project type - def open_project(self) -> None: - path = QtWidgets.QFileDialog.getExistingDirectory(self, "Open Project Directory", os.path.abspath('..')) - if not path: - return + warnings.warn(f"Tab control not implemented for type " + f"{type(controller)}") - prj_file = get_project_file(path) # TODO: Migrate this func to a utility module - if prj_file is None: - self.log.warning("No project file's found in directory: {}".format(path)) - return - self.project.save() - self.project = prj.AirborneProject.load(prj_file) - self.update_project() - return - - def update_project(self, signal_flight=False) -> None: - self.log.debug("Update project called") - if self.project is None: - return - # self.prj_tree.setModel(self.project.generate_model()) - # self.prj_tree.expandAll() - model, index = self.project.generate_model() - # self.project_tree.refresh(index) - self.project_tree.setModel(model) - self.project_tree.expandAll() - self.project_tree.setCurrentIndex(index) - if signal_flight: - self.flight_changed(index) + @pyqtSlot(name='_project_mutated') + def _project_mutated(self): + """pyqtSlot(None) - def save_project(self) -> None: - if self.project is None: - return - if self.project.save(): - self.setWindowTitle(self.title + ' - {} [*]'.format(self.project.name)) - self.setWindowModified(False) - self.log.info("Project saved.") + Update the MainWindow title bar to reflect unsaved changes in the project + """ + self.setWindowModified(True) + + @pyqtSlot(ProgressEvent, name='_progress_event_handler') + def _progress_event_handler(self, event: ProgressEvent): + if event.uid in self._progress_events: + # Update progress + self.log.debug(f"Updating progress bar for UID {event.uid}") + dlg: QProgressDialog = self._progress_events[event.uid] + dlg.setValue(event.value) + + if event.completed: + self.log.debug("Event completed, closing progress dialog") + dlg.reset() + dlg.close() + del self._progress_events[event.uid] + return + + dlg.setLabelText(event.label) else: - self.log.info("Error saving project.") - - @autosave - def add_flight(self) -> None: - # TODO: do I need these checks? self.project should not ever be None - if self.project is None: - return - dialog = AddFlight(self.project) - if dialog.exec_(): - self.log.info("Adding flight:") - flight = dialog.flight - self.project.add_flight(flight) - self.update_project() - self.scan_flights() - self._init_plots() - return + flags = (Qt.WindowSystemMenuHint | + Qt.WindowTitleHint | + Qt.WindowMinimizeButtonHint) + dlg = QProgressDialog(event.label, "", event.start, event.stop, self, flags) + dlg.setMinimumDuration(0) + dlg.setModal(event.modal) + dlg.setValue(event.value) + if event.receiver: + dlg.open(event.receiver) + else: + dlg.setValue(1) + dlg.show() + self._progress_events[event.uid] = dlg + + def save_projects(self) -> None: + self.model.save_projects() + self.setWindowModified(False) + self.log.info("Project saved.") + + # Project create/open dialog functions ################################### + + def new_project_dialog(self) -> QtWidgets.QDialog: + """pyqtSlot() + Launch a :class:`CreateProjectDialog` to enable the user to create a new + project instance. + If a new project is created it is opened in a new MainWindow if the + dialog's sigProjectCreated new_window flag is True, else it is added + to the current window Project Tree View, below any already opened + projects. + Returns + ------- + :class:`CreateProjectDialog` + Reference to modal CreateProjectDialog -class ProjectTreeView(QtWidgets.QTreeView): - def __init__(self, model=None, project=None, parent=None): - super().__init__(parent=parent) - self.setMinimumSize(QtCore.QSize(0, 300)) - self.setAlternatingRowColors(True) - self.setAutoExpandDelay(1) - self.setRootIsDecorated(False) - self.setUniformRowHeights(True) - self.setHeaderHidden(True) - self.setObjectName('project_tree') - self.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu) - self.refresh() - # self.setModel(model) - # self.expandAll() - - def refresh(self, curr_index=None): - """Regenerate model and set current selection to curr_index""" - # self.generate_airborne_model() - if curr_index is not None: - self.setCurrentIndex(curr_index) - self.expandAll() - - def generate_airborne_model(self): - pass - - def contextMenuEvent(self, event: QtGui.QContextMenuEvent, *args, **kwargs): - context_ind = self.indexAt(event.pos()) - context_focus = self.model().itemFromIndex(context_ind) - print(context_focus) - print(context_focus.text()) - - info_slot = functools.partial(self.flight_info, context_focus) - menu = QtWidgets.QMenu() - info_action = QtWidgets.QAction("Info") - info_action.triggered.connect(info_slot) - menu.addAction(info_action) - menu.exec_(event.globalPos()) - event.accept() - - def flight_info(self, item): - data = item.getData(QtCore.Qt.UserRole) - if isinstance(data, prj.Flight): - dialog = QtWidgets.QDialog(self) - dialog.setLayout(QtWidgets.QVBoxLayout()) - dialog.exec_() - print("Flight info: {}".format(item.text())) - else: - print("Info event: Not a flight") + """ + dialog = CreateProjectDialog(parent=self) + dialog.sigProjectCreated.connect(lambda prj: self.open_project(prj.path, prompt=False)) + dialog.show() + return dialog + def open_project_dialog(self, *args): # pragma: no cover + """pyqtSlot() + Opens an existing project within the current Project MainWindow, + adding the opened project as a tree item to the Project Tree navigator. + Parameters + ---------- + args + Consume positional arguments, some buttons connected to this slot + will pass a 'checked' boolean flag which is not applicable here. + """ + dialog = QFileDialog(self, "Open Project", str(self.import_base_path)) + dialog.setFileMode(QFileDialog.DirectoryOnly) + dialog.setViewMode(QFileDialog.List) + dialog.fileSelected.connect(lambda file: self.open_project(Path(file))) + dialog.exec_() + + def show_documentation(self): # pragma: no cover + """Launch DGP's online documentation (RTD) in the default browser""" + QDesktopServices.openUrl(Links.DEV_DOCS.url()) + + def show_about(self): # pragma: no cover + """Display 'About' information for the DGP project""" + QMessageBox.about(self, "About DGP", __about__) diff --git a/dgp/gui/plotting.py b/dgp/gui/plotting.py deleted file mode 100644 index ed70ec0..0000000 --- a/dgp/gui/plotting.py +++ /dev/null @@ -1,176 +0,0 @@ -import matplotlib as mpl -mpl.use('Qt5Agg') - -import matplotlib.pyplot as plt -from matplotlib.figure import Figure -from matplotlib.dates import DateFormatter, num2date -import matplotlib.patches as patches -import numpy as np -import os - -class Plots: - def __init__(self): - self.rects = [] - self.figure = None - self.axes = [] - self.clicked = None - - def generate_subplots(self, x, *args): - def _on_xlims_change(axes): - # reset the x-axis format when the plot is resized - axes.get_xaxis().set_major_formatter(DateFormatter('%H:%M:%S')) - - i = 0 - numplots = len(args) - fig = plt.figure() - - self.cidclick = fig.canvas.mpl_connect('button_press_event', self.onclick) - self.cidrelease = fig.canvas.mpl_connect('button_release_event', self.onrelease) - self.cidmotion = fig.canvas.mpl_connect('motion_notify_event', self.onmotion) - - for arg in args: - if i == 0: - a = fig.add_subplot(numplots, 1, i+1) - else: - a = fig.add_subplot(numplots, 1, i+1, sharex=self.axes[0]) - - a.plot(x.to_pydatetime(), arg) - a.fmt_xdata = DateFormatter('%H:%M:%S') - a.grid(True) - a.callbacks.connect('xlim_changed', _on_xlims_change) - self.axes.append(a) - i += 1 - - if not mpl.is_interactive(): - fig.show() - - self.figure = fig - plt.show() - - # TO DO: Consider PatchCollection for rectangles. - def onclick(self, event): - # TO DO: Don't place rectangle when zooming. - # TO DO: Resize rectangles when plot extent changes. - - # check if clicked in subplot - for subplot in self.figure.axes: - if event.inaxes == subplot: - break - else: - return - - flag = False - - # don't add rectangle if click on existing rectangle - for partners in self.rects: - # TO DO: Fix logic in this loop. Don't need to loop through all - # partners to determine whether click was in an occupied region, just one. - # Also, use of the flag is a bit kludgy. - - index = 0 - for attr in partners: - rect = attr['rect'] - - # contains, attrd = rect.contains(event) - # if contains: - - if event.xdata > rect.get_x() and event.xdata < rect.get_x() + rect.get_width(): - flag = True - x0, _ = rect.xy - self.clicked = partners, index, x0, event.xdata, event.ydata - - # draw everything but the selected rectangle and store the pixel buffer - canvas = rect.figure.canvas - axes = rect.axes - rect.set_animated(True) - canvas.draw() - attr['bg'] = canvas.copy_from_bbox(axes.bbox) - - # now redraw just the rectangle - axes.draw_artist(rect) - - # and blit just the redrawn area - # canvas.blit(axes.bbox) - - index += 1 - - if flag: - return - - # create rectangle if click in empty area - partners = [] - for subplot in self.figure.axes: - ylim = subplot.get_ylim() - xlim = subplot.get_xlim() - x_extent = (xlim[-1] - xlim[0]) * np.float64(0.1) - - # bottom left corner - x0 = event.xdata - x_extent/2 - y0 = ylim[0] - width = x_extent - height = ylim[-1] - ylim[0] - - r = patches.Rectangle((x0, y0), width, height, alpha=0.1) - attr = {} - attr['rect'] = r - subplot.add_patch(r) - - attr['bg'] = None - partners.append(attr) - - self.rects.append(partners) - # self.rect.figure.canvas.draw() - self.figure.canvas.draw() - - def onmotion(self, event): - # check if pointer is still in subplot - for subplot in self.figure.axes: - if event.inaxes == subplot: - break - else: - return - - if self.clicked is None: - return - else: - self._move_rect(event) - - # def _near_edge(self, event, prox=5): - # for partners in self.rects: - # attr = partners[0] - # left = attr['rect'].get_x() - # right = left + attr['rect'].get_width() - # if ((event.xdata < left and event.xdata > left - prox) or - # (event.xdata > left and event.xdata < left + prox)): - # return ("L", partners) - # elif ((event.xdata < right and event.xdata > right - prox) or - # (event.xdata > right and event.xdata < right + prox)): - # return ("R", partners) - # else: - # return None - - def _move_rect(self, event): - partners, index, x0, xclick, yclick = self.clicked - - # move rectangles - dx = event.xdata - xclick - for attr in partners: - rect = attr['rect'] - rect.set_x(x0 + dx) - canvas = rect.figure.canvas - axes = rect.axes - canvas.restore_region(attr['bg']) - axes.draw_artist(rect) - canvas.blit(axes.bbox) - - def onrelease(self, event): - for partners in self.rects: - for attr in partners: - rect = attr['rect'] - rect.set_animated(False) - attr['bg'] = None - - self.clicked = None - - # redraw the full figure - self.figure.canvas.draw() diff --git a/dgp/gui/plotting/__init__.py b/dgp/gui/plotting/__init__.py new file mode 100644 index 0000000..aa4ee8c --- /dev/null +++ b/dgp/gui/plotting/__init__.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- + +__help__ = """ +Click and drag on the plot to pan +Right click and drag the plot to interactively zoom +Right click on the plot to view options specific to each plot area +""" diff --git a/dgp/gui/plotting/backends.py b/dgp/gui/plotting/backends.py new file mode 100644 index 0000000..9ea3514 --- /dev/null +++ b/dgp/gui/plotting/backends.py @@ -0,0 +1,749 @@ +# -*- coding: utf-8 -*- +from enum import Enum, auto +from itertools import cycle +from typing import List, Union, Tuple, Generator, Dict +from weakref import WeakValueDictionary + +import pandas as pd +from PyQt5.QtCore import pyqtSignal +from PyQt5.QtWidgets import QMenu, QWidgetAction, QWidget, QAction, QToolBar, QMessageBox +from pyqtgraph.widgets.GraphicsView import GraphicsView +from pyqtgraph.graphicsItems.GraphicsLayout import GraphicsLayout +from pyqtgraph.graphicsItems.PlotItem import PlotItem +from pyqtgraph import SignalProxy, PlotDataItem + +from dgp.core import Icon +from dgp.gui.ui.plot_options_widget import Ui_PlotOptions +from .helpers import PolyAxis + +__all__ = ['GridPlotWidget', 'Axis', 'AxisFormatter'] + + +class AxisFormatter(Enum): + """Enumeration defining axis formatter types""" + DATETIME = auto() + SCALAR = auto() + + +class Axis(Enum): + """Enumeration of selectable plot axis' Left/Right""" + LEFT = 'left' + RIGHT = 'right' + + +LINE_COLORS = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', + '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf'] + +# type aliases +MaybePlot = Union['DgpPlotItem', None] +MaybeSeries = Union[pd.Series, None] +SeriesIndex = Tuple[str, int, int, Axis] + + +class _CustomPlotControl(QWidget, Ui_PlotOptions): + """QWidget used by DgpPlotItem to provide a custom plot-controls menu.""" + def __init__(self, parent=None): + super().__init__() + self.setupUi(self) + self._action = QWidgetAction(parent) + self._action.setDefaultWidget(self) + self.qpbReset.clicked.connect(self.reset_controls) + + def reset_controls(self): + """Reset all controls to a default state/value""" + self.alphaGroup.setChecked(True) + self.alphaSlider.setValue(1000) + self.gridAlphaSlider.setValue(128) + self.xGridCheck.setChecked(True) + self.yGridCheck.setChecked(True) + self.yGridCheckRight.setChecked(False) + self.averageCheck.setChecked(False) + self.downsampleCheck.setChecked(False) + self.downsampleSpin.setValue(1) + + @property + def action(self) -> QWidgetAction: + return self._action + + +class LinkedPlotItem(PlotItem): + """LinkedPlotItem creates a twin plot linked to the right y-axis of the base + + This class is used by DgpPlotItem to enable plots which have a dual y-axis + scale in order to display two (or potentially more) Series on the same plot + with different magnitudes. + + Parameters + ---------- + base : :class:`pyqtgraph.PlotItem` or :class:`DgpPlotItem` + The base PlotItem which this plot will link itself to + + Notes + ----- + This class is a simple wrapper around a :class:`~pyqtgraph.PlotItem`, it sets + some sensible default parameters, and configures itself to link its x-axis + to the specified 'base' PlotItem, and finally inserts itself into the layout + container of the parent plot. + + Also note that the linked plot does not use its own independent legend, + it links its legend attribute to the base plot's legend (so that legend + add/remove actions can be performed without validating or looking up the + explicit base plot reference). + + """ + def __init__(self, base: PlotItem): + super().__init__(enableMenu=False) + self._base = base + self.legend = base.legend + self.setXLink(self._base) + self.buttonsHidden = True + self.hideAxis('left') + self.hideAxis('bottom') + self.setZValue(-100) + self.setLimits(maxYRange=1e17, maxXRange=1e17) + + base.showAxis('right') + base.getAxis('right').setGrid(False) + base.getAxis('right').linkToView(self.getViewBox()) + base.layout.addItem(self, 2, 1) + + +class DgpPlotItem(PlotItem): + """Custom PlotItem derived from pyqtgraph's :class:`~pyqtgraph.PlotItem` + + The primary focus of this custom PlotItem is to override the default + 'Plot Options' sub-menu provided by PlotItem for context-menu (right-click) + events on the plot surface. + + Secondarily this class provides a simple way to create/enable a secondary + y-axis, for plotting multiple data curves of differing magnitudes. + + Many of the menu actions defined by the original PlotItem class do not work + correctly (or generate RuntimeErrors) when dealing with typical DataFrames + in our context. The original menu is also heavily nested, and provides many + functions which are currently unnecessary for our use-case. + + The custom Plot Options menu provided by this class is a single frame + pop-out context menu, providing the functions/actions described in the notes + below. + + Parameters + ---------- + multiy : bool, optional + If True the plot item will be created with multiple y-axis scales. + Curves can be plotted to the second (right axis) plot using the 'right' + property + kwargs + See valid kwargs for :class:`~pyqtgraph.PlotItem` + + Notes + ----- + Custom menu functionality provided: + + - Plot curve alpha (transparency) setting + - Grid line visibility (on/off/transparency) + - Average curve (on/off) + - Downsampling/decimation - selectable data-decimation by step (2 to 10) + + """ + ctrl_overrides = ('alphaSlider', 'alphaGroup', 'gridAlphaSlider', + 'xGridCheck', 'yGridCheck', 'downsampleCheck', + 'downsampleSpin') + + def __init__(self, multiy: bool = False, **kwargs): + super().__init__(**kwargs) + self.setLimits(maxYRange=1e17, maxXRange=1e17) + self.setYRange(-1, 1) + self.addLegend(offset=(15, 15)) + + self.customControl = _CustomPlotControl() + self.ctrlMenu = QMenu("Plot Options") + self.ctrlMenu.addAction(self.customControl.action) + + # Ensure default state in original ui ctrl + self.ctrl.alphaGroup.setChecked(True) + self.ctrl.autoAlphaCheck.setChecked(False) + + # Set signal connections for custom controls + self.customControl.alphaGroup.toggled.connect(self.updateAlpha) + self.customControl.alphaSlider.valueChanged.connect(self.updateAlpha) + self.customControl.gridAlphaSlider.valueChanged.connect(self.updateGrid) + self.customControl.xGridCheck.toggled.connect(self.updateGrid) + self.customControl.yGridCheck.toggled.connect(self.updateGrid) + self.customControl.yGridCheckRight.toggled.connect(self.updateGrid) + self.customControl.averageCheck.toggled.connect(self.ctrl.averageGroup.setChecked) + self.customControl.downsampleCheck.toggled.connect(self.updateDownsampling) + self.customControl.downsampleSpin.valueChanged.connect(self.updateDownsampling) + + # Patch original controls whose state/value is used in various updates + # e.g. PlotItem.updateGrid checks the checked state of x/yGridCheck + # This is done so we don't have to override every base update function + for attr in self.ctrl_overrides: + setattr(self.ctrl, attr, getattr(self.customControl, attr)) + + self.updateGrid() + + self.clearAction = QAction("Clear Plot", self) + self.clearAction.triggered.connect(self.clearPlots) + + # Connect the 'View All' action so it autoRanges both (left/right) plots + self.vb.menu.viewAll.triggered.disconnect() + self.vb.menu.viewAll.triggered.connect(self.autoRange) + + # Configure right-y plot (sharing x-axis) + self._right = LinkedPlotItem(self) if multiy else None + + @property + def left(self) -> 'DgpPlotItem': + """@property: Return the primary plot (self). This is an identity + property and is provided for symmetry with the `right` property. + + Returns + ------- + :class:`DgpPlotItem` + Left axis plot surface (self) + + """ + return self + + @property + def right(self) -> MaybePlot: + """@property: Return the sibling plot linked to the right y-axis + (if it exists). + + Returns + ------- + :class:`LinkedPlotItem` + Right axis plot surface if it is enabled/created, else :const:`None` + + """ + return self._right + + def autoRange(self, *args, **kwargs): + """Overrides :meth:`pyqtgraph.ViewBox.autoRange` + + Auto-fit left/right plot :class:`~pyqtgraph.ViewBox` to curve data limits + """ + self.vb.autoRange(items=self.curves) + if self.right is not None: + self.right.vb.autoRange(items=self.right.curves) + + def clearPlots(self): + """Overrides :meth:`pyqtgraph.PlotItem.clearPlots` + + Clear all curves from left and right plots, as well as removing any + legend entries. + """ + for c in self.curves[:]: + self.legend.removeItem(c.name()) + self.removeItem(c) + self.avgCurves = {} + + if self.right is not None: + for c in self.right.curves[:]: + self.legend.removeItem(c.name()) + self.right.removeItem(c) + + def updateAlpha(self, *args): + """Overrides :meth:`pyqtgraph.PlotItem.updateAlpha` + + Override the base implementation to update alpha value of curves on the + right plot (if it is enabled) + """ + super().updateAlpha(*args) + if self.right is not None: + alpha, auto_ = self.alphaState() + for c in self.right.curves: + c.setAlpha(alpha ** 2, auto_) + + def updateDownsampling(self): + """Extends :meth:`pyqtgraph.PlotItem.updateDownsampling` + + Override the base implementation in order to effect updates on the right + plot (if it is enabled). + """ + super().updateDownsampling() + if self.right is not None: + ds, auto_, method = self.downsampleMode() + for c in self.right.curves: + c.setDownsampling(ds, auto_, method) + + def downsampleMode(self): + """Overrides :meth:`pyqtgraph.PlotItem.downsampleMode` + + Called by updateDownsampling to get control state. Our custom + implementation does not allow for all of the options that the original + does. + """ + if self.ctrl.downsampleCheck.isChecked(): + ds = self.ctrl.downsampleSpin.value() + else: + ds = 1 + return ds, False, 'subsample' + + def updateGrid(self, *args): + """Overrides :meth:`pyqtgraph.PlotItem.updateGrid` + + This method provides special handling of the left/right axis grids. + The plot custom control allows the user to show/hide either the left + or right y-axis grid lines independently. + """ + alpha = self.customControl.gridAlphaSlider.value() + x = alpha if self.customControl.xGridCheck.isChecked() else False + y = alpha if self.customControl.yGridCheck.isChecked() else False + yr = alpha if self.customControl.yGridCheckRight.isChecked() else False + + self.getAxis('bottom').setGrid(x) + self.getAxis('left').setGrid(y) + self.getAxis('right').setGrid(yr) + + def getContextMenus(self, event): + if self.menuEnabled(): + return [self.ctrlMenu, self.clearAction] + else: + return None + + +class GridPlotWidget(GraphicsView): + """ + Base plotting class used to create a group of one or more + :class:`pyqtgraph.PlotItem` in a layout + (rows/columns). + This class is a subclass of :class:`QWidget` and can be directly added to a + QtWidget based application. + + This is essentially a wrapper around PyQtGraph's GraphicsLayout, which + handles the complexities of creating/laying-out plots in the view. This + class aims to simplify the API for our use cases, and add functionality for + easily plotting pandas Series. + + Parameters + ---------- + rows : int, Optional + Rows of plots to generate (stacked from top to bottom), default is 1 + background : Optional + Background color for the widget and nested plots. Can be any value + accepted by :func:`pyqtgraph.mkBrush` or :func:`pyqtgraph.mkColor` + e.g. QColor, hex string, RGB(A) tuple + grid : bool + If True displays gridlines on the plot surface + sharex : bool + If True links all x-axis values to the first plot + multiy : bool + If True all plots will have a sister plot with its own y-axis and scale + enabling the plotting of 2 (or more) Series with differing scales on a + single plot surface. + parent : QWidget, optional + Optional QWidget parent for the underlying QGraphicsView object + + Notes + ----- + The GridPlotWidget explicitly disables the :class:`pyqtgraph.GraphicsScene` + 'Export' context menu action, as the default pyqtgraph export dialog is not + stable and causes runtime errors in various contexts. + + See Also + -------- + :func:`pyqtgraph.mkPen` for customizing plot-line pens (creates a QgGui.QPen) + :func:`pyqtgraph.mkColor` for color options in the plot (creates a QtGui.QColor) + + """ + sigPlotCleared = pyqtSignal() + + def __init__(self, rows=1, cols=1, background='w', grid=True, sharex=False, + multiy=False, timeaxis=False, parent=None): + super().__init__(background=background, parent=parent) + self.gl = GraphicsLayout(parent=parent) + self.setCentralItem(self.gl) + + # Clear the 'Export' action from the scene context menu + self.sceneObj.contextMenu = [] + + self.rows = rows + self.cols = cols + + # Note: increasing pen width can drastically reduce performance + self._pens = cycle([{'color': v, 'width': 1} for v in LINE_COLORS]) + + # Maintain weak references to Series/PlotDataItems for lookups + self._series: Dict[SeriesIndex: pd.Series] = WeakValueDictionary() + self._items: Dict[SeriesIndex: PlotDataItem] = WeakValueDictionary() + + for row in range(self.rows): + for col in range(self.cols): + axis_items = {'bottom': PolyAxis(orientation='bottom', + timeaxis=timeaxis)} + plot = DgpPlotItem(background=background, axisItems=axis_items, + multiy=multiy) + self.gl.addItem(plot, row=row, col=col) + plot.clear() + plot.showGrid(x=grid, y=grid) + + if row > 0 and sharex: + plot.setXLink(self.get_plot(0, 0)) + + self.__signal_proxies = [] + + @property + def plots(self) -> Generator[DgpPlotItem, None, None]: + """Yields each plot by row in this GridPlotWidget + + Yields + ------ + :class:`.DgpPlotItem` + + Warnings + -------- + This property does not yet account for GridPlotWidgets with more than a + single column. + Also note that it will not yield RIGHT plots, only the base LEFT plot. + """ + for i in range(self.rows): + yield self.get_plot(i, 0) + + @property + def pen(self): + """Return the next pen parameters in the cycle""" + return next(self._pens) + + def autorange(self): + """Calls auto-range on all plots in the GridPlotWidget""" + for plot in self.plots: + plot.autoRange() + + def get_plot(self, row: int, col: int = 0, axis: Axis = Axis.LEFT) -> MaybePlot: + """Get the DgpPlotItem within this GridPlotWidget specified by row/col/axis + + Parameters + ---------- + row : int + col : int, optional + Column index of the plot to retrieve, optional, default is 0 + axis : Axis, optional + Select the LEFT or RIGHT axis plot, optional, default is Axis.LEFT + + Returns + ------- + :data:`~.MaybePlot` + :class:`DgpPlotItem` if a plot exists at the given row/col/axis + else :const:`None` + + """ + plot: DgpPlotItem = self.gl.getItem(row, col) + if axis is Axis.RIGHT: + return plot.right + else: + return plot + + def add_series(self, series: pd.Series, row: int, col: int = 0, + axis: Axis = Axis.LEFT, pen=None, + autorange: bool = True) -> PlotDataItem: + """Add a pandas :class:`pandas.Series` to the plot at the specified + row/column + + Parameters + ---------- + series : :class:`~pandas.Series` + The Pandas Series to add; series.index and series.values are taken + to be the x and y axis respectively + row : int + col : int, optional + axis : str, optional + 'left' or 'right' - specifies which y-scale the series should be + plotted on. Only has effect if self.multiy is True. + autorange : bool, optional + + Returns + ------- + :class:`pyqtgraph.PlotDataItem` + The generated PlotDataItem or derivative created from the data + + Raises + ------ + :exc:`AttributeError` + If the provided axis is invalid for the plot, i.e. axis=Axis.RIGHT + but multiy is not enabled. + + """ + index = self.make_index(series.name, row, col, axis) + if self._items.get(index, None) is not None: + return self._items[index] + + self._series[index] = series + plot = self.get_plot(row, col, axis) + xvals = pd.to_numeric(series.index, errors='coerce') + yvals = pd.to_numeric(series.values, errors='coerce') + item = plot.plot(x=xvals, y=yvals, name=series.name, pen=pen or self.pen) + self._items[index] = item + if autorange: + plot.autoRange() + return item + + def get_series(self, name: str, row: int, col: int = 0, + axis: Axis = Axis.LEFT) -> MaybeSeries: + """Get the pandas.Series data for a plotted series + + Parameters + ---------- + name : str + row, col : int + Row/column index of the plot where target series is plotted. + Column is optional, default is 0 + axis : :data:`Axis`, optional + Plot axis where the series is plotted (LEFT or RIGHT), defaults to + :data:`Axis.LEFT` + + Returns + ------- + :data:`MaybeSeries` + Returns a :class:`pandas.Series` object if the series is found with + the specified parameters or else returns :const:`None` + + """ + idx = self.make_index(name, row, col, axis) + return self._series.get(idx, None) + + def remove_series(self, name: str, row: int, col: int = 0, + axis: Axis = Axis.LEFT, autorange: bool = True) -> None: + """Remove a named series from the plot at the specified row/col/axis. + + Parameters + ---------- + name : str + row : int + col : int, optional + Defaults to 0 + axis : :data:`Axis`, optional + Defaults to :data:`Axis.LEFT` + autorange : bool, optional + Auto-range plot x/y view after removing the series, default True + + """ + plot = self.get_plot(row, col, axis) + index = self.make_index(name, row, col, axis) + plot.removeItem(self._items[index]) + plot.legend.removeItem(name) + if autorange: + plot.autoRange() + + def clear(self) -> None: + """Clear all plot data curves from all plots""" + for i in range(self.rows): + for j in range(self.cols): + plot = self.get_plot(i, j) + for curve in plot.curves[:]: + name = curve.name() + plot.removeItem(curve) + plot.legend.removeItem(name) + if plot.right: + plot_r = plot.right + for curve in plot_r.curves[:]: + plot_r.legend.removeItem(curve.name()) + plot_r.removeItem(curve) + self.sigPlotCleared.emit() + + def remove_plotitem(self, item: PlotDataItem, autorange=True) -> None: + """Alternative method of removing a line by its + :class:`pyqtgraph.PlotDataItem` reference, as opposed to using + remove_series to remove a named series from a specific plot at row/col + index. + + Parameters + ---------- + item : :class:`~pyqtgraph.PlotDataItem` + The PlotDataItem reference to be removed from whichever plot it + resides + + """ + for plot in self.plots: + plot.legend.removeItem(item.name()) + plot.removeItem(item) + if plot.right is not None: + plot.right.removeItem(item) + if autorange: + self.autorange() + + def find_series(self, name: str) -> List[SeriesIndex]: + """Find and return a list of all plot indexes where a series with + 'name' is plotted. + + Parameters + ---------- + name : str + Name of the :class:`pandas.Series` to find indexes of + + Returns + ------- + List of :data:`SeriesIndex` + List of Series indexes, see :func:`make_index` + If no indexes are found an empty list is returned + + """ + indexes = [] + for index, series in self._series.items(): + if series.name == name: # pragma: no branch + indexes.append(index) + + return indexes + + def set_xaxis_formatter(self, formatter: AxisFormatter, row: int, col: int = 0): + """Allow setting of the X-Axis tick formatter to display DateTime or + scalar values. + + This is an explicit call, as opposed to letting the AxisItem infer the + axis type due to the possibility of plotting two series with different + indexes. This may be revised in future. + + Parameters + ---------- + formatter : :data:`AxisFormatter` + row : int + Plot row index + col : int, optional + Plot column index, optional, defaults to 0 + + """ + plot = self.get_plot(row, col) + axis: PolyAxis = plot.getAxis('bottom') + axis.timeaxis = formatter is AxisFormatter.DATETIME + + def get_xlim(self, row: int, col: int = 0) -> Tuple[float, float]: + """Get the x-limits (left-right span) for the plot ViewBox at the + specified row/column. + + Parameters + ---------- + row : int + col : int, optional + Plot column index, optional, defaults to 0 + + Returns + ------- + Tuple (float, float) + 2-Tuple of minimum/maximum x-limits of the current view (xmin, xmax) + + """ + return self.get_plot(row, col).vb.viewRange()[0] + + def set_xlink(self, linked: bool = True, autorange: bool = False): + """Enable or disable linking of x-axis' between all plots in the grid. + + Parameters + ---------- + linked : bool, Optional + If True sets all plots to link x-axis scales with plot 0, 0 + If False, un-links all plot x-axis' + Default is True (enable x-link) + autorange : bool, Optional + If True automatically re-scale the view box after linking/unlinking. + Default is False + + """ + base = self.get_plot(0, 0) if linked else None + for i in range(1, self.rows): + plot = self.get_plot(i, 0) + plot.setXLink(base) + if autorange: + plot.autoRange() + + def toggle_grids(self, state: bool): + for plot in self.plots: + plot.customControl.xGridCheck.setChecked(state) + plot.customControl.yGridCheck.setChecked(state) + + def add_onclick_handler(self, slot, ratelimit: int = 60): # pragma: no cover + """Creates a SignalProxy to forward Mouse Clicked events on the + GraphicsLayout scene to the provided slot. + + Parameters + ---------- + slot : pyqtSlot(MouseClickEvent) + pyqtSlot accepting a :class:`pyqtgraph.MouseClickEvent` + ratelimit : int, optional + Limit the SignalProxy to an emission rate of `ratelimit` signals/sec + + """ + sp = SignalProxy(self.gl.scene().sigMouseClicked, rateLimit=ratelimit, + slot=slot) + self.__signal_proxies.append(sp) + return sp + + def get_toolbar(self, parent=None) -> QToolBar: + """Return a QToolBar with standard controls for the plot surface(s) + + Returns + ------- + QToolBar + + """ + toolbar = QToolBar(parent) + action_viewall = QAction(Icon.AUTOSIZE.icon(), "View All", self) + action_viewall.triggered.connect(self.autorange) + toolbar.addAction(action_viewall) + + action_grid = QAction(Icon.GRID.icon(), "Toggle Grid", self) + action_grid.setCheckable(True) + action_grid.setChecked(True) + action_grid.toggled.connect(self.toggle_grids) + toolbar.addAction(action_grid) + + action_clear = QAction(Icon.DELETE.icon(), "Clear Plots", self) + action_clear.triggered.connect(self.clear) + toolbar.addAction(action_clear) + + action_help = QAction(Icon.SETTINGS.HELP.icon(), "Plot Help", self) + action_help.triggered.connect(lambda: self.help_dialog(parent)) + toolbar.addAction(action_help) + + action_settings = QAction(Icon.SETTINGS.icon(), "Plot Settings", self) + toolbar.addAction(action_settings) + + toolbar.addSeparator() + + return toolbar + + @staticmethod + def help_dialog(parent=None): + from . import __help__ + QMessageBox.information(parent, "Plot Controls Help", __help__) + + @staticmethod + def make_index(name: str, row: int, col: int = 0, + axis: Axis = Axis.LEFT) -> SeriesIndex: + """Generate an index referring to a specific plot curve + + Plot curves (items) can be uniquely identified within the GridPlotWidget + by their name, and the specific plot which they reside on (row/col/axis) + A plot item can only be plotted once on a given plot, so the index is + guaranteed to be unique for the specific named item. + + Parameters + ---------- + name : str + Name for the data series this index refers to. Note that the name + value is automatically lower-cased, and as such two indexes created + with differently cased but identical names will be equivalent when + all other properties are the same. + row, col : int + Row/column plot index (col is optional, defaults to 0) + axis : Axis, optional + Optionally specify the plot axis this index is for (LEFT or RIGHT), + defaults to Axis.LEFT + + Returns + ------- + :data:`SeriesIndex` + A :data:`SeriesIndex` tuple of (str, int, int, Axis) corresponding + to: (name, row, col, Axis) + + Raises + ------ + :exc:`ValueError` + If supplied name is invalid (None or empty string: '') + + """ + if axis not in Axis: + axis = Axis.LEFT + if name is None or name is '': + raise ValueError("Cannot create plot index from empty name.") + return name.lower(), row, col, axis diff --git a/dgp/gui/plotting/helpers.py b/dgp/gui/plotting/helpers.py new file mode 100644 index 0000000..9bd7a8a --- /dev/null +++ b/dgp/gui/plotting/helpers.py @@ -0,0 +1,383 @@ +# -*- coding: utf-8 -*- +import logging +import weakref +from collections import namedtuple +from typing import List, Iterable, Tuple + +import pandas as pd + +from PyQt5.QtCore import Qt, pyqtSignal, QTimer, QObject +from PyQt5.QtWidgets import QInputDialog, QMenu +from pyqtgraph import LinearRegionItem, TextItem, AxisItem, PlotItem +from pyqtgraph.GraphicsScene.mouseEvents import MouseClickEvent + +from dgp.core import OID, StateAction + +_log = logging.getLogger(__name__) + +LineUpdate = namedtuple('LineUpdate', + ['action', 'uid', 'start', 'stop', 'label']) + + +class PolyAxis(AxisItem): + """AxisItem which can display tick strings formatted for a date/time value, + or as scalar values. + + Parameters + ---------- + orientation : str, optional + timeaxis : bool, optional + Enable the time-axis formatter, default is False + kwargs + See :class:`pyqtgraph.AxisItem` for permitted kwargs + + Attributes + ---------- + timeaxis : bool + If True format tick strings by their date values, + If False use the default scalar formatter + + See Also + -------- + :class:`pyqtgraph.AxisItem` + :meth:`pyqtgraph.AxisItem.tickStrings` + :meth:`pyqtgraph.AxisItem.tickSpacing` + :meth:`pyqtgraph.AxisItem.tickValues` + + """ + def __init__(self, orientation='bottom', timeaxis=False, **kwargs): + super().__init__(orientation, **kwargs) + self.timeaxis = timeaxis + + # Define time-format scales for time-range <= key + self._timescales = { + pd.Timedelta(seconds=1).value: '%M:%S:%f', + pd.Timedelta(minutes=1).value: '%M:%S', + pd.Timedelta(hours=1).value: '%H:%M:%S', + pd.Timedelta(days=1).value: '%d %H:%M', + pd.Timedelta(weeks=1).value: '%m-%d %H' + } + + def dateTickStrings(self, values, spacing): + """Create formatted date strings for the tick locations specified by + values. + + Parameters + ---------- + values : List + List of values to generate tick strings for + spacing : float + + Returns + ------- + List[str] + List of labels corresponding to each input value. + + """ + # Select the first formatter where the scale (sec/min/hour/day etc) is + # greater than the range + fmt = next((fmt for period, fmt in sorted(self._timescales.items()) + if period >= spacing), '%m-%d') + + labels = [] + for i, loc in enumerate(values): + try: + ts: pd.Timestamp = pd.Timestamp(loc) + except (OverflowError, ValueError, OSError): + _log.exception(f'Exception converting {loc} to date string.') + labels.append('') + continue + + try: + if i == 0 and len(values) > 2: + label = ts.strftime('%d-%b-%y %H:%M:%S') + else: + label = ts.strftime(fmt) + except ValueError: + _log.warning("Timestamp conversion out-of-bounds") + label = 'OoB' + + labels.append(label) + return labels + + def tickStrings(self, values, scale, spacing): + """Return the tick strings that should be placed next to ticks. + + This method overrides the base implementation in :class:`AxisItem`, and + will selectively provide date formatted strings if :attr:`timeaxis` is + True. Otherwise the base method is called to provide the tick strings. + + Parameters + ---------- + values : List + List of values to generate tick strings for + scale : Scalar + Used to specify the scale of the values, useful when the axis label + is configured to show the display as some SI fraction (e.g. milli), + the scaled display value can be properly calculated. + spacing : Scalar + Spacing between values/ticks + + Returns + ------- + List[str] + List of strings used to label the plot at the given values + + Notes + ----- + This function may be called multiple times for the same plot, + where multiple tick-levels are defined i.e. Major/Minor/Sub-Minor ticks. + The range of the values may also differ between invocations depending on + the positioning of the chart. And the spacing will be different + dependent on how the ticks were placed by the + :meth:`pyqtgraph.AxisItem.tickSpacing` method. + + """ + if self.timeaxis: + return self.dateTickStrings(values, spacing) + else: # pragma: no cover + return super().tickStrings(values, scale, spacing) + + +class LinearSegment(LinearRegionItem): + """Custom LinearRegionItem class used to interactively select data segments. + + Parameters + ---------- + plot : :class:`~pyqtgraph.PlotItem` or :class:`.DgpPlotItem` + PlotItem to add the LinearSegment to + left, right : float + Initial left/right values for the segment + label : str, optional + Set the initial label text for this segment + movable : bool, optional + Set the initial movable/editable state of the LinearSegment + + Attributes + ---------- + sigLabelChanged : :class:`~pyqt.pyqtSignal` ( :class:`str` ) + Emitted when the label text of this segment has changed + sigDeleteRequested : :class:`~pyqt.pyqtSignal` () + Emitted when a delete action is triggered for this segment + + """ + sigLabelChanged = pyqtSignal(str) + sigDeleteRequested = pyqtSignal() + + def __init__(self, plot: PlotItem, left, right, label=None, movable=False): + super().__init__(values=(left, right), + orientation=LinearRegionItem.Vertical, + movable=movable, brush=None, bounds=None) + self._plot = weakref.ref(plot) + self._label = TextItem(text=label or '', color=(0, 0, 0), anchor=(0, 0)) + self._update_label_pos() + self.sigRegionChanged.connect(self._update_label_pos) + + self._menu = QMenu() + self._menu.addAction('Remove', self.sigDeleteRequested.emit) + self._menu.addAction('Set Label', self._get_label_dlg) + + plot.addItem(self) + plot.addItem(self._label) + plot.sigYRangeChanged.connect(self.y_rng_changed) + + @property + def label_text(self) -> str: + """@property Returns the current plain-text of the segment's label""" + return self._label.textItem.toPlainText() + + @label_text.setter + def label_text(self, value: str): + """Set the label text, limiting input to 10 characters""" + self._label.setText(value[:10]) + self._update_label_pos() + + def remove(self) -> None: + """Remove this segment from the plot""" + self._plot().removeItem(self._label) + self._plot().removeItem(self) + try: + self._plot().sigYRangeChanged.disconnect(self.y_rng_changed) + except TypeError: + pass + + def mouseClickEvent(self, ev: MouseClickEvent): + """Intercept right-click on segment to display context menu + + This click handler will check if the segments are editable (movable), + if so, right-clicks will activate a context menu, left-clicks will be + passed to the super-class to handle resizing/moving. + """ + if not self.movable: + return + elif ev.button() == Qt.RightButton and not self.moving: + ev.accept() + pos = ev.screenPos().toPoint() + self._menu.popup(pos) + else: + return super().mouseClickEvent(ev) + + def y_rng_changed(self, vb, ylims): # pragma: no cover + """:class:`pyqtSlot`: Update label position on change of ViewBox y-limits""" + x = self._label.pos()[0] + y = ylims[1] + self._label.setPos(x, y) + + def _update_label_pos(self): + """:class:`pyqtSlot`: Update label position to new segment/view bounds""" + x0, _ = self.getRegion() + _, y1 = self._plot().viewRange()[1] + self._label.setPos(x0, y1) + + def _get_label_dlg(self): # pragma: no cover + """:class:`pyqtSlot`: Popup an Input Dialog to take user string input + + Emits sigLabelChanged(str) with the result of the accepted dialog value + """ + # TODO: Assign parent or create dialog with Icon + text, result = QInputDialog.getText(None, "Enter Label", "Segment Label:", + text=self.label_text) + if result: + self.sigLabelChanged.emit(str(text).strip()) + + +class LinearSegmentGroup(QObject): + """Container for related LinearSegments which are linked across multiple + plots + + LinearSegmentGroup encapsulates the logic required to create and update a + set of LinearSegment's across a group of plot items. + + Parameters + ---------- + plots : Iterable of :class:`PlotItem` + Iterable object containing plots to add LinearSegments to. Must have at + least 1 item. + group : :class:`~dgp.core.OID` + Unique identifier for this LinearSegmentGroup + left, right : float + Initial left/right (x) values for the segments in this group. + label : str, optional + Optional label to display on each segment + movable : bool, optional + Set the initial movable state of the segments, default is False + + Attributes + ---------- + sigSegmentUpdate : pyqtSignal(LineUpdate) + Qt Signal, emits a :class:`LineUpdate` object when the segment group has + been mutated (Updated/Deleted) + + Notes + ----- + An update timer (QTimer) is utilized to rate-limit segment update signal + emissions during resize operations. Instead of a signal being emitted for + every discrete movement/drag-resize of a segment, updates are emitted only + when the timer expires. The timer is also reset with every movement so that + updates are not triggered until the user has momentarily paused dragging, or + finished their movement. + + """ + sigSegmentUpdate = pyqtSignal(object) + + def __init__(self, plots: Iterable[PlotItem], uid: OID, + left: float, right: float, label: str = '', + movable: bool = False, parent: QObject = None): + super().__init__(parent=parent) + self._uid = uid + self._segments: List[LinearSegment] = [] + self._label_text = label + self._updating = False + self._timer = QTimer(self) + self._timer.setInterval(50) + self._timer.timeout.connect(self._update_done) + + for plot in plots: + segment = LinearSegment(plot, left, right, label=label, + movable=movable) + segment.sigRegionChanged.connect(self._update_region) + segment.sigLabelChanged.connect(self._update_label) + segment.sigDeleteRequested.connect(self.delete) + self._segments.append(segment) + + @property + def left(self) -> pd.Timestamp: + return pd.to_datetime(self._segments[0].getRegion()[0]) + + @property + def right(self) -> pd.Timestamp: + return pd.to_datetime(self._segments[0].getRegion()[1]) + + @property + def region(self) -> Tuple[float, float]: + """Return the left/right region bounds of the group""" + for segment in self._segments: + return segment.getRegion() + + @property + def movable(self) -> bool: + return self._segments[0].movable + + @property + def label_text(self) -> str: + return self._label_text + + def set_movable(self, movable: bool): + """Set the movable property of the segments in this group""" + for segment in self._segments: + segment.setMovable(movable) + + def set_visibility(self, visible: bool): + for segment in self._segments: + segment.setVisible(visible) + segment._label.setVisible(visible) + + def remove(self): + self.delete(emit=False) + + def delete(self, emit=True): + """Delete all child segments and emit a DELETE update""" + for segment in self._segments: + segment.remove() + if emit: + self.emit_update(StateAction.DELETE) + + def emit_update(self, action: StateAction = StateAction.UPDATE): + """Emit a LineUpdate object with the current segment attributes + + Creates and emits a LineUpdate named-tuple with the current left and + right x-values of the segment, and the current label-text. + + Parameters + ---------- + action : StateAction, optional + Optionally specify the action for the update, defaults to UPDATE. + Use this parameter to trigger a DELETE action for instance. + + """ + update = LineUpdate(action, self._uid, self.left, self.right, + self._label_text) + self.sigSegmentUpdate.emit(update) + + def _update_label(self, label: str): + """Updates the label text on all sibling segments and emits an update""" + for segment in self._segments: + segment.label_text = label + self._label_text = label + self.emit_update(StateAction.UPDATE) + + def _update_region(self, segment: LinearSegment): + """Update sibling segments to new region bounds""" + if self._updating: + return + else: + self._updating = True + self._timer.start() + for seg in [x for x in self._segments if x is not segment]: + seg.setRegion(segment.getRegion()) + self._updating = False + + def _update_done(self): + """Emit an update object when the rate-limit timer has expired""" + self._timer.stop() + self.emit_update(StateAction.UPDATE) diff --git a/dgp/gui/plotting/plotters.py b/dgp/gui/plotting/plotters.py new file mode 100644 index 0000000..e59211d --- /dev/null +++ b/dgp/gui/plotting/plotters.py @@ -0,0 +1,243 @@ +# -*- coding: utf-8 -*- +import logging +from typing import Dict + +import pandas as pd +from PyQt5.QtCore import pyqtSignal, Qt +from PyQt5.QtWidgets import QAction +from pyqtgraph import Point +from pyqtgraph.GraphicsScene.mouseEvents import MouseClickEvent + +from dgp.core import Icon +from dgp.core import StateAction +from dgp.core.oid import OID +from .helpers import LinearSegmentGroup, LineUpdate +from .backends import GridPlotWidget, AxisFormatter + +__all__ = ['TransformPlot', 'LineSelectPlot', 'AxisFormatter', 'LineUpdate'] + +_log = logging.getLogger(__name__) + +""" +Task specific Plotting Class definitions. + +This module adds various Plotting classes based on :class:`GridPlotWidget` +which are tailored for specific tasks, e.g. the LineSelectPlot provides methods +and user-interaction features to allow a user to create line-segments (defining +a section of interesting data). + +""" + + +class TransformPlot(GridPlotWidget): + """Plot interface used for displaying transformation results. + May need to display data plotted against time series or scalar series. + + Parameters + ---------- + kwargs : + Keyword arguments are supplied to the base :class:`GridPlotWidget` + The TransformPlot sets sharex=True, multiy=False and timeaxis=True by + default + + rows : int + cols : int + grid : bool + + """ + def __init__(self, **kwargs): + super().__init__(**kwargs, sharex=True, multiy=False, timeaxis=True) + + def set_axis_formatters(self, formatter: AxisFormatter): + for i in range(self.rows): + self.set_xaxis_formatter(formatter, i, 0) + + +class LineSelectPlot(GridPlotWidget): + """LineSelectPlot is a task specific plot widget which provides the user + with a click/drag interaction allowing them to create and edit data + 'segments' visually on the plot surface. + + Parameters + ---------- + rows : int, optional + Number of rows of linked plots to create, default is 1 + parent : QWidget, optional + + Attributes + ---------- + sigSegmentChanged : :class:`~pyqt.pyqtSignal` [ :class:`LineUpdate` ] + Qt Signal emitted whenever a data segment (LinearSegment) is created, + modified, or deleted. + Emits a :class:`.LineUpdate` + + """ + sigSegmentChanged = pyqtSignal(LineUpdate) + + def __init__(self, rows=1, parent=None): + super().__init__(rows=rows, cols=1, grid=True, sharex=True, + multiy=True, timeaxis=True, parent=parent) + self._selecting = False + self._segments: Dict[OID, LinearSegmentGroup] = {} + self.add_onclick_handler(self.onclick) + + @property + def selection_mode(self) -> bool: + """@property Return the current selection mode state + + Returns + ------- + bool + True if selection mode is enabled, else False + """ + return self._selecting + + def set_select_mode(self, mode: bool) -> None: + """Set the selection mode of the LineSelectPlot + + """ + self._selecting = mode + for group in self._segments.values(): + group.set_movable(mode) + + def add_segment(self, start: float, stop: float, label: str = None, + uid: OID = None, emit: bool = True) -> LinearSegmentGroup: + """Add a LinearSegment selection across all linked x-axes with width + ranging from start -> stop with an optional label. + + To non-interactively add a segment group (e.g. when loading a saved + project) this method should be called with the uid parameter, and emit + set to False. + + Parameters + ---------- + start : float + stop : float + label : str, optional + Optional text label to display within the segment on the plot + uid : :class:`.OID`, optional + Specify the uid of the segment group, used for re-creating segments + when loading a plot + emit : bool, optional + If False, sigSegmentChanged will not be emitted on addition of the + segment + + Returns + ------- + :class:`.LinearSegmentGroup` + A reference to the newly created :class:`.LinearSegmentGroup` + + """ + if isinstance(start, pd.Timestamp): + start = start.value + if isinstance(stop, pd.Timestamp): + stop = stop.value + + uid = uid or OID(tag='segment') + group = LinearSegmentGroup(self.plots, uid, start, stop, label=label, + movable=self._selecting) + group.sigSegmentUpdate.connect(self.sigSegmentChanged.emit) + group.sigSegmentUpdate.connect(self._segment_updated) + self._segments[uid] = group + + if emit: + update = LineUpdate(StateAction.CREATE, uid, group.left, + group.right, group.label_text) + self.sigSegmentChanged.emit(update) + return group + + def get_segment(self, uid: OID) -> LinearSegmentGroup: + """Get a :class:`.LinearSegmentGroup` by its :class:`.OID` + + Returns + ------- + :class:`.LinearSegmentGroup` or :const:`None` + The Segment group by the given OID if it exists, else None + """ + return self._segments.get(uid, None) + + def onclick(self, ev): # pragma: no cover + """Onclick handler for mouse left/right click. + + Creates a new data-segment if :attr:`.selection_mode` is True on left-click + """ + event: MouseClickEvent = ev[0] + try: + pos: Point = event.pos() + except AttributeError: + # Avoid error when clicking around plot, due to an attempt to + # call mapFromScene on None in pyqtgraph/mouseEvents.py + return + if event.button() == Qt.RightButton: + return + + if event.button() == Qt.LeftButton: + if not self.selection_mode: + return + p0 = self.get_plot(row=0) + if p0.vb is None: + return + event.accept() + # Map click location to data coordinates + xpos = p0.vb.mapToView(pos).x() + v0, v1 = self.get_xlim(0) + vb_span = v1 - v0 + if not self._check_proximity(xpos, vb_span): + return + + start = xpos - (vb_span * 0.05) + stop = xpos + (vb_span * 0.05) + self.add_segment(start, stop) + + def get_toolbar(self, parent=None): + toolbar = super().get_toolbar(parent) + + action_mode = QAction(Icon.SELECT.icon(), "Toggle Selection Mode", self) + action_mode.setCheckable(True) + action_mode.setChecked(self.selection_mode) + action_mode.toggled.connect(self.set_select_mode) + toolbar.addAction(action_mode) + + action_seg_visibility = QAction(Icon.LINE_MODE.icon(), + "Toggle Segment Visibility", self) + action_seg_visibility.setCheckable(True) + action_seg_visibility.setChecked(True) + action_seg_visibility.toggled.connect(self.set_segment_visibility) + toolbar.addAction(action_seg_visibility) + + return toolbar + + def set_segment_visibility(self, state: bool): + for segment in self._segments.values(): + segment.set_visibility(state) + + def _check_proximity(self, x, span, proximity=0.03) -> bool: + """Check the proximity of a mouse click at location 'x' in relation to + any already existing LinearRegions. + + Parameters + ---------- + x : float + Mouse click position in data coordinate + span : float + X-axis span of the view box + proximity : float + Proximity as a percentage of the ViewBox span + + Returns + ------- + True if x is not in proximity to any existing LinearRegionItems + False if x is inside or in proximity to an existing LinearRegionItem + + """ + prox = span * proximity + for group in self._segments.values(): + x0, x1 = group.region + if x0 - prox <= x <= x1 + prox: + _log.warning("New segment is too close to an existing segment") + return False + return True + + def _segment_updated(self, update: LineUpdate): + if update.action is StateAction.DELETE: + del self._segments[update.uid] diff --git a/dgp/gui/settings.py b/dgp/gui/settings.py new file mode 100644 index 0000000..fe6b000 --- /dev/null +++ b/dgp/gui/settings.py @@ -0,0 +1,227 @@ +# -*- coding: utf-8 -*- +import time +from contextlib import contextmanager +from enum import Enum +from pathlib import Path +from typing import Union, Generator + +from PyQt5.QtCore import QSettings, QModelIndex, QObject, pyqtSignal +from PyQt5.QtGui import QStandardItemModel, QStandardItem + +from dgp.core import OID + +PathRole = 0x101 +RefRole = 0x102 +UidRole = 0x103 +ModRole = 0x104 + +MaybePath = Union[Path, None] + +_ORG = "DynamicGravitySystems" +_APP = "DynamicGravityProcessor" +_settings = QSettings(QSettings.NativeFormat, QSettings.UserScope, _ORG, _APP) +_recent_model = QStandardItemModel() + + +def set_settings(handle: QSettings): + """Set the global QSettings object to a custom handler""" + global _settings + _settings = handle + + +def settings() -> QSettings: + """Expose the global QSettings object""" + return _settings + + +class SettingsKey(Enum): + WindowState = "Window/state" + WindowGeom = "Window/geom" + LastProjectPath = "Project/latest/path" + LastProjectName = "Project/latest/name" + LastProjectUid = "Project/latest/uid" + RecentProjects = "Project/recent" + + # User Option Properties + LoadLastProject = "User/LoadLast" + RestoreWorkspace = "User/RestoreWorkspace" + OpenInNewWindow = "User/OpenInNewWindow" + + def __call__(self): + """Allow retrieval of the enum value using call syntax `()` """ + return self.value + + +@contextmanager +def settings_group(key: str): + _settings.beginGroup(key) + yield settings + _settings.endGroup() + + +class RecentProject: + """Simple project reference, contains the metadata required to load or refer + to a DGP project on the local computer. + Used by the RecentProjectManager to maintain a structured reference to any + specific project. + + RecentProject provides a __hash__ method allowing references to be compared + by their UID hash + """ + def __init__(self, uid: str, name: str, path: str, modified=None, **kwargs): + self.uid: str = uid + self.name: str = name + self.path: str = str(path) + self.modified = modified or time.time() + + def __hash__(self): + return hash(self.uid) + + +class RecentProjectManager(QObject): + """QSettings wrapper used to manage the retrieval/setting of recent projects + that have been loaded for the user. + + """ + sigRecentProjectsChanged = pyqtSignal() + + def __init__(self, qsettings: QSettings = None, parent=None): + super().__init__(parent=parent) + self._settings = qsettings or _settings + self._key = SettingsKey.RecentProjects() + self._model = _recent_model + self._load_recent_projects() + + @property + def model(self): + return self._model + + @property + def project_refs(self) -> Generator[RecentProject, None, None]: + for i in range(self.model.rowCount()): + yield self.model.item(i).data(RefRole) + + def last_project_path(self) -> MaybePath: + raw_path = self._settings.value(SettingsKey.LastProjectPath(), None) + if raw_path is not None: + return Path(raw_path) + else: + return None + + def last_project_name(self) -> Union[str, None]: + return self._settings.value(SettingsKey.LastProjectName(), None) + + def add_recent_project(self, uid: OID, name: str, path: Path) -> None: + """Add a project to the list of recent projects, managed via the + QSettings object + + If the project UID already exists in the recent projects list, update + the entry, otherwise create a new entry, commit it, and add an item + to the model representation. + + Parameters + ---------- + uid : OID + name : str + path : :class:`pathlib.Path` + + """ + self.refresh() + str_path = str(path.absolute()) + ref = RecentProject(uid.base_uuid, name, str_path) + + for i in range(self._model.rowCount()): + child: QStandardItem = self._model.item(i) + if child.data(UidRole) == uid: + child.setText(name) + child.setToolTip(str_path) + child.setData(path, PathRole) + child.setData(ref, RefRole) + break + else: # no break + item = self.item_from_ref(ref) + self._model.insertRow(0, item) + + self._commit_recent_projects() + self.sigRecentProjectsChanged.emit() + + def clear(self) -> None: + """Clear recent projects from the model AND persistent settings state""" + self._model.clear() + self._settings.remove(self._key) + self.sigRecentProjectsChanged.emit() + + def refresh(self) -> None: + """Force a refresh of the recent projects list by reloading state + + Alias for _load_recent_projects + + """ + self._load_recent_projects() + + def path(self, index: QModelIndex) -> MaybePath: + """Retrieve path data from a model item, given the items QModelIndex + + Returns + ------- + Path or None + pathlib.Path object if the item and data exists, else None + + """ + item: QStandardItem = self._model.itemFromIndex(index) + if item == 0: + return None + return item.data(PathRole) + + def _commit_recent_projects(self) -> None: + """Commit the recent projects model to file (via QSettings interface), + replacing any current items at the recent projects key. + + """ + self._settings.remove(self._key) + self._settings.beginWriteArray(self._key) + for i in range(self._model.rowCount()): + self._settings.setArrayIndex(i) + ref = self._model.item(i).data(RefRole) + for key in ref.__dict__: + self._settings.setValue(key, getattr(ref, key, None)) + + self._settings.endArray() + + def _load_recent_projects(self) -> None: + self._model.clear() + + size = self._settings.beginReadArray(self._key) + for i in range(size): + self._settings.setArrayIndex(i) + keys = self._settings.childKeys() + params = {key: self._settings.value(key) for key in keys} + + ref = RecentProject(**params) + item = self.item_from_ref(ref) + self._model.appendRow(item) + self._settings.endArray() + self.sigRecentProjectsChanged.emit() + + @staticmethod + def item_from_ref(ref: RecentProject) -> QStandardItem: + """Create a standardized QStandardItem for the model given a RecentProject + + """ + item = QStandardItem(ref.name) + item.setToolTip(str(ref.path)) + item.setData(Path(ref.path), PathRole) + item.setData(ref.uid, UidRole) + item.setData(ref, RefRole) + item.setEditable(False) + return item + + +class UserSettings: + @property + def reopen_last(self) -> bool: + return bool(_settings.value(SettingsKey.LoadLastProject(), False)) + + @property + def new_window(self) -> bool: + return bool(_settings.value(SettingsKey.OpenInNewWindow(), False)) diff --git a/dgp/gui/splash.py b/dgp/gui/splash.py deleted file mode 100644 index 39d9b36..0000000 --- a/dgp/gui/splash.py +++ /dev/null @@ -1,193 +0,0 @@ -# coding: utf-8 - - -import sys -import json -import logging -from pathlib import Path -from typing import Dict, Union - -from PyQt5 import QtWidgets, QtCore -from PyQt5.uic import loadUiType - -from dgp.gui.main import MainWindow -from dgp.gui.utils import ConsoleHandler, LOG_FORMAT, LOG_COLOR_MAP, get_project_file -from dgp.gui.dialogs import CreateProject -import dgp.lib.project as prj - -splash_screen, _ = loadUiType('dgp/gui/ui/splash_screen.ui') - - -class SplashScreen(QtWidgets.QDialog, splash_screen): - def __init__(self, *args): - super().__init__(*args) - self.log = self.setup_logging() - # Experimental: Add a logger that sets the label_error text - error_handler = ConsoleHandler(self.write_error) - error_handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s')) - error_handler.setLevel(logging.DEBUG) - self.log.addHandler(error_handler) - - self.setupUi(self) - - self.settings_dir = Path.home().joinpath('AppData\Local\DynamicGravitySystems\DGP') - self.recent_file = self.settings_dir.joinpath('recent.json') - if not self.settings_dir.exists(): - self.log.info("Settings Directory doesn't exist, creating.") - self.settings_dir.mkdir(parents=True) - - # self.dialog_buttons.accepted.connect(self.accept) - self.btn_newproject.clicked.connect(self.new_project) - self.btn_browse.clicked.connect(self.browse_project) - self.list_projects.currentItemChanged.connect(self.set_selection) - - self.project_path = None # type: Path - - self.set_recent_list() - self.show() - - @staticmethod - def setup_logging(level=logging.DEBUG): - root_log = logging.getLogger() - std_err_handler = logging.StreamHandler(sys.stderr) - std_err_handler.setLevel(level) - std_err_handler.setFormatter(LOG_FORMAT) - root_log.addHandler(std_err_handler) - return logging.getLogger(__name__) - - def accept(self, project=None): - """Runs some basic verification before calling QDialog accept().""" - - # Case where project object is passed to accept() (when creating new project) - if isinstance(project, prj.GravityProject): - self.log.debug("Opening new project: {}".format(project.name)) - elif not self.project_path: - self.log.error("No valid project selected.") - else: - try: - project = prj.AirborneProject.load(self.project_path) - except FileNotFoundError: - self.log.error("Project could not be loaded from path: {}".format(self.project_path)) - return - - self.update_recent_files(self.recent_file, {project.name: project.projectdir}) - # Show a progress dialog for loading the project (as we generate plots upon load) - progress = QtWidgets.QProgressDialog("Loading Project", "Cancel", 0, len(project), self) - progress.setWindowFlags(QtCore.Qt.Dialog | QtCore.Qt.FramelessWindowHint | QtCore.Qt.CustomizeWindowHint) - progress.setModal(True) - progress.setMinimumDuration(0) - progress.setCancelButton(None) # Remove the cancel button. Possibly add a slot that has load() check and cancel - progress.setValue(1) # Set an initial value to show the dialog - - main_window = MainWindow(project) - main_window.status.connect(progress.setLabelText) - main_window.progress.connect(progress.setValue) - main_window.load() - progress.close() # This isn't necessary if the min/max is set correctly, but just in case. - super().accept() - return main_window - - def set_recent_list(self) -> None: - recent_files = self.get_recent_files(self.recent_file) - if not recent_files: - no_recents = QtWidgets.QListWidgetItem("No Recent Projects", self.list_projects) - no_recents.setFlags(QtCore.Qt.NoItemFlags) - return None - - for name, path in recent_files.items(): - item = QtWidgets.QListWidgetItem('{name} :: {path}'.format(name=name, path=str(path)), self.list_projects) - item.setData(QtCore.Qt.UserRole, path) - item.setToolTip(str(path.resolve())) - self.list_projects.setCurrentRow(0) - return None - - def set_selection(self, item: QtWidgets.QListWidgetItem, *args): - """Called when a recent item is selected""" - self.project_path = get_project_file(item.data(QtCore.Qt.UserRole)) - if not self.project_path: - # TODO: Fix this, when user selects item multiple time the statement is re-appended - item.setText("{} - Project Moved or Deleted".format(item.data(QtCore.Qt.UserRole))) - - self.log.debug("Project path set to {}".format(self.project_path)) - - def new_project(self): - """Allow the user to create a new project""" - dialog = CreateProject() - if dialog.exec_(): - project = dialog.project # type: prj.AirborneProject - project.save() - # self.update_recent_files(self.recent_file, {project.name: project.projectdir}) - self.accept(project) - - def browse_project(self): - """Allow the user to browse for a project directory and load.""" - path = QtWidgets.QFileDialog.getExistingDirectory(self, "Select Project Directory") - if not path: - return - - prj_file = self.get_project_file(Path(path)) - if not prj_file: - self.log.error("No project files found") - return - - self.project_path = prj_file - self.accept() - - def write_error(self, msg, level=None) -> None: - self.label_error.setText(msg) - self.label_error.setStyleSheet('color: {}'.format(LOG_COLOR_MAP[level])) - - @staticmethod - def update_recent_files(path: Path, update: Dict[str, Path]) -> None: - recents = SplashScreen.get_recent_files(path) - recents.update(update) - SplashScreen.set_recent_files(recents, path) - - @staticmethod - def get_recent_files(path: Path) -> Dict[str, Path]: - """ - Ingests a JSON file specified by path, containing project_name: project_directory mappings and returns dict of - valid projects (conducting path checking and conversion to pathlib.Path) - Parameters - ---------- - path : Path - Path object referencing JSON object containing mappings of recent projects -> project directories - - Returns - ------- - Dict - Dictionary of (str) project_name: (pathlib.Path) project_directory mappings - If the specified path cannot be found, an empty dictionary is returned - - """ - try: - with path.open('r') as fd: - raw_dict = json.load(fd) - _checked = {} - for name, strpath in raw_dict.items(): - _path = Path(strpath) - if get_project_file(_path) is not None: - _checked[name] = _path - except FileNotFoundError: - return {} - else: - return _checked - - @staticmethod - def set_recent_files(recent_files: Dict[str, Path], path: Path) -> None: - """ - Take a dictionary of recent projects (project_name: project_dir) and write it out to a JSON formatted file - specified by path - Parameters - ---------- - recent_files : Dict[str, Path] - - path : Path - - Returns - ------- - None - """ - serializable = {name: str(path) for name, path in recent_files.items()} - with path.open('w+') as fd: - json.dump(serializable, fd) diff --git a/dgp/gui/ui/.gitignore b/dgp/gui/ui/.gitignore new file mode 100644 index 0000000..f104652 --- /dev/null +++ b/dgp/gui/ui/.gitignore @@ -0,0 +1 @@ +*.py diff --git a/dgp/gui/ui/add_flight_dialog.ui b/dgp/gui/ui/add_flight_dialog.ui index f1082aa..1894247 100644 --- a/dgp/gui/ui/add_flight_dialog.ui +++ b/dgp/gui/ui/add_flight_dialog.ui @@ -6,210 +6,154 @@ 0 0 - 400 - 400 + 405 + 583 - 450 - 450 + 16777215 + 16777215 Add Flight - - :/images/assets/flight_icon.png:/images/assets/flight_icon.png + + :/icons/airborne:/icons/airborne - - - - - Flight Name (Reference)* - - - text_name - - - - - - - - - - Flight Date - - - date_flight - - - - - - - yyyy-MM-dd - - - true - - - - 2017 - 1 - 1 - - - - - - - - Gravity Meter - - - combo_meter - - - - - - - - - - Flight Parameters - - - table_flight_param - - - - - - - - Tie Value - - - - - Tie Location - - - - - Still Reading - - - - - Pre Reading - - - - - Post Reading - - + + true + + + + - - - - - Known Gravity Tie Value (mGal) - + + + Flight Name (Reference)* + + + qle_flight_name + + - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - + + + + Required: Specify a name/reference for this flight + + + + + + + Flight Date + + + qde_flight_date + + + + + + + yyyy-MM-dd + + + true + + + + 2017 + 1 + 1 + + + + + + + + Flight Sequence + + + + + + + [Optional] Set the flight sequence within the project + + + + + + + Flight Duration (hrs) + + + + + + + [Optional] Set the duration of the flight (hours) + + + + + + + Flight Notes + + + + + + + [Optional] Add notes regarding this flight + + + + - - + + - Flight UUID + Flight Parameters - - + + false - - true - - + <html><head/><body><p align="right">*required fields</p></body></html> - - - - Gravity Data - - - path_gravity - - - - - - - - + + - - - - 30 - 16777215 - + + + QLabel { color: red; } - ... + - - - - - - GPS Data - - - lineEdit - - - - - - - - - - - - 30 - 16777215 - - - - ... + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok @@ -217,23 +161,12 @@ - - text_name - date_flight - combo_meter - path_gravity - browse_grav - lineEdit - pushButton - table_flight_param - text_uuid - - + - buttons_dialog + qdbb_dialog_btns rejected() NewFlight reject() @@ -249,7 +182,7 @@ - buttons_dialog + qdbb_dialog_btns accepted() NewFlight accept() diff --git a/dgp/gui/ui/add_meter_dialog.ui b/dgp/gui/ui/add_meter_dialog.ui new file mode 100644 index 0000000..13c328d --- /dev/null +++ b/dgp/gui/ui/add_meter_dialog.ui @@ -0,0 +1,242 @@ + + + AddMeterDialog + + + + 0 + 0 + 640 + 480 + + + + Add Gravimeter + + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + QAbstractItemView::NoEditTriggers + + + + + + + 9 + + + + + 9 + + + + + Gravimeter Serial # + + + qle_serial + + + + + + + + + + Name + + + + + + + false + + + + + + + Tag/Description + + + + + + + + + + Configuration (ini) + + + qle_config_path + + + + + + + + + + 0 + 0 + + + + + + + + Browse for a meter configuration file + + + Browse... + + + + + + + + + Copy the original configuration into the project directory + + + Copy configuration to project folder + + + + + + + Configuration + + + + + + + + 0 + 0 + + + + + 0 + 50 + + + + QAbstractItemView::NoEditTriggers + + + false + + + true + + + true + + + false + + + + + + + + + Qt::Horizontal + + + + + + + + + QLabel { color: red; } + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + + + + + dialog_btns + accepted() + AddMeterDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + dialog_btns + rejected() + AddMeterDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/dgp/gui/ui/advanced_data_import.ui b/dgp/gui/ui/advanced_data_import.ui new file mode 100644 index 0000000..4be9951 --- /dev/null +++ b/dgp/gui/ui/advanced_data_import.ui @@ -0,0 +1,471 @@ + + + AdvancedImportData + + + + 0 + 0 + 450 + 418 + + + + + 0 + 0 + + + + + 50 + 0 + + + + Advanced Import + + + + :/icons/new_file.png:/icons/new_file.png + + + + 0 + + + 5 + + + 5 + + + + + + 0 + 0 + + + + + + + + + + Path* + + + line_path + + + + + + + + + + 0 + 0 + + + + true + + + Browse to File + + + + + + + + 0 + 0 + + + + + 9 + + + + ... + + + + + + + + + Flight + + + combo_flights + + + + + + + + 0 + 0 + + + + + + + + Meter + + + combo_meters + + + + + + + + 0 + 0 + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 10 + + + + File Properties: + + + 2 + + + Qt::NoTextInteraction + + + + + + + 5 + + + 5 + + + 10 + + + + + Data End + + + 2 + + + dte_data_end + + + + + + + Line Count + + + + + + + 0 + + + + + + + 0 Mib + + + + + + + false + + + Trim + + + + + + + false + + + + + + + Column Count: + + + + + + + false + + + + 0 + 0 + + + + + + + + Data Start + + + 2 + + + dte_data_start + + + + + + + File Size (Mib) + + + + + + + 0 + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + 0 + 0 + + + + Column Format: + + + cb_data_fmt + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Maximum + + + + 40 + 20 + + + + + + + + false + + + + 0 + 0 + + + + + 9 + + + + Edit Columns + + + + :/images/assets/meter_config.png:/images/assets/meter_config.png + + + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 20 + 50 + + + + + + + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + false + + + + + + + + + + + btn_dialog + accepted() + AdvancedImportData + accept() + + + 253 + 408 + + + 157 + 274 + + + + + btn_dialog + rejected() + AdvancedImportData + reject() + + + 321 + 408 + + + 286 + 274 + + + + + diff --git a/dgp/gui/ui/assets/boat_icon.png b/dgp/gui/ui/assets/boat_icon.png deleted file mode 100644 index a82b610..0000000 Binary files a/dgp/gui/ui/assets/boat_icon.png and /dev/null differ diff --git a/dgp/gui/ui/assets/branch-closed.png b/dgp/gui/ui/assets/branch-closed.png deleted file mode 100644 index 213ffdd..0000000 Binary files a/dgp/gui/ui/assets/branch-closed.png and /dev/null differ diff --git a/dgp/gui/ui/assets/branch-open.png b/dgp/gui/ui/assets/branch-open.png deleted file mode 100644 index e8cad95..0000000 Binary files a/dgp/gui/ui/assets/branch-open.png and /dev/null differ diff --git a/dgp/gui/ui/assets/flight_icon.png b/dgp/gui/ui/assets/flight_icon.png deleted file mode 100644 index 863f550..0000000 Binary files a/dgp/gui/ui/assets/flight_icon.png and /dev/null differ diff --git a/dgp/gui/ui/create_project_dialog.ui b/dgp/gui/ui/create_project_dialog.ui new file mode 100644 index 0000000..936f731 --- /dev/null +++ b/dgp/gui/ui/create_project_dialog.ui @@ -0,0 +1,463 @@ + + + CreateProjectDialog + + + + 0 + 0 + 800 + 450 + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + 50 + 50 + + + + Create New Project + + + + :/icons/dgs:/icons/dgs + + + + + + true + + + false + + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + QFrame::Raised + + + 1 + + + + 20 + 20 + + + + QListView::ListMode + + + true + + + + + + + 3 + + + 5 + + + 5 + + + + + QLayout::SetNoConstraint + + + QFormLayout::ExpandingFieldsGrow + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing + + + 3 + + + + + + 0 + 0 + + + + + 0 + 25 + + + + Project Name:* + + + prj_name + + + + + + + + + + 0 + 1 + + + + + 0 + 25 + + + + + 8 + + + + Project name must begin with a letter. + + + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + Project Directory:* + + + prj_dir + + + + + + + 2 + + + 0 + + + 0 + + + + + + 0 + 1 + + + + + 0 + 25 + + + + + 8 + + + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + + + + + 0 + 0 + + + + Browse... + + + + + + + + + Project Notes + + + + + + + + + + + 75 + true + + + + required fields* + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + Properties + + + + + + + + + + + + + false + + + + + + + + + + + QLabel { color: red; } + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Cancel + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Create + + + + + + + + + + + btn_create + prj_type_list + + + + + + + btn_cancel + clicked() + CreateProjectDialog + reject() + + + 219 + 278 + + + 249 + 149 + + + + + prj_properties + clicked() + widget_advanced + show() + + + 301 + 82 + + + 526 + 405 + + + + + btn_create + clicked() + CreateProjectDialog + accept() + + + 851 + 427 + + + 449 + 224 + + + + + diff --git a/dgp/gui/ui/data_import_dialog.ui b/dgp/gui/ui/data_import_dialog.ui index 66031e1..b6c1f5b 100644 --- a/dgp/gui/ui/data_import_dialog.ui +++ b/dgp/gui/ui/data_import_dialog.ui @@ -1,138 +1,674 @@ - Dialog - - - Qt::ApplicationModal - + DataImportDialog + 0 0 - 418 - 500 + 732 + 683 - + 0 0 - - - 300 - 500 - - - + - 600 - 1200 + 50 + 0 Import Data - - :/images/assets/geoid_icon.png:/images/assets/geoid_icon.png + + :/icons/new_file.png:/icons/new_file.png - - - - - Data Type + + true + + + + 0 + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + 5 + + + 0 + + + + + 6 - - - - - &Gravity Data - - - true - - - group_radiotype - - - - - - - G&PS Data - - - group_radiotype - - - - - + + + + + 0 + 0 + + + + + - - - - Qt::Horizontal + + + + 8 - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + 2 - - - - - - - - - - - - true + + 9 - - - - - - - - - &Browse - - - - - - - <html><head/><body><p align="center"><span style=" font-size:12pt;">Flight</span></p></body></html> + + 9 - - - - - - <html><head/><body><p align="center"><span style=" font-size:12pt;">Meter</span></p></body></html> - - + + + + 8 + + + 4 + + + 4 + + + 4 + + + 4 + + + + + Path* + + + qle_filepath + + + + + + + 2 + + + + + + + + Browse for file + + + Browse for a data file + + + Browse... + + + + 16 + 16 + + + + + + + + + + (Re)name + + + qle_rename + + + + + + + + + Rename the source file within the project + + + + + + + Copy source file to project directory + + + Copy to Project Dir + + + + + + + + + Flight + + + qcb_flight + + + + + + + 2 + + + + + + 0 + 0 + + + + + + + + Add new flight to project + + + Add Flight... + + + + + + + + + Dataset + + + + + + + 2 + + + + + + + + false + + + + 0 + 0 + + + + New Dataset + + + + + + + + + Date + + + + + + + + + + + + + 0 + 0 + + + + Use date from associated flight + + + From Flight + + + + :/icons/airborne:/icons/airborne + + + + + + + + + Notes + + + qpte_notes + + + + + + + Qt::ScrollBarAlwaysOff + + + + + + + + + + 0 + 0 + + + + 1 + + + + + 0 + + + 0 + + + + + Gravity Import + + + 0 + + + + + + + 0 + + + + + Sensor + + + + + + + 2 + + + + + + 0 + 0 + + + + + + + + Add new Gravimeter to project + + + Add Sensor... + + + + + + + + + Sensor Type + + + + + + + false + + + + + + + Column Format + + + + + + + 2 + + + + + false + + + + + + + false + + + ... + + + + + + + + + Has Header Row + + + + + + + Interpolate Missing Numeric Fields + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 0 + + + 0 + + + + + Trajectory Import + + + + + + + + + GPS Time Format + + + + + + + + + + Is UTC Time + + + true + + + + + + + Has Header Row + + + + + + + Column Names + + + + + + + false + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + File Info + + + + + + + + + File Size (MiB) + + + + + + + false + + + + + + + Line Count + + + + + + + false + + + + + + + Column Count + + + + + + + false + + + + + + + File Name + + + + + + + false + + + + + + + + + + + + + QLabel { color: red; } + + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + false + + + + + + + + qlw_datatype + qle_filepath + qpb_browse + qle_rename + qchb_copy_file + qcb_flight + qpb_add_flight + qpte_notes + qcb_gravimeter + qpb_add_sensor + qle_sensortype + qle_grav_format + qtb_grav_format_adv + qle_filesize + qle_linecount + qle_colcount + qcb_traj_timeformat + - + - buttonBox + qdbb_buttons + accepted() + DataImportDialog + accept() + + + 513 + 618 + + + 157 + 274 + + + + + qdbb_buttons rejected() - Dialog + DataImportDialog reject() - 316 - 260 + 581 + 618 286 @@ -141,7 +677,4 @@ - - - diff --git a/dgp/gui/ui/edit_import_view.ui b/dgp/gui/ui/edit_import_view.ui new file mode 100644 index 0000000..6a94c58 --- /dev/null +++ b/dgp/gui/ui/edit_import_view.ui @@ -0,0 +1,214 @@ + + + Dialog + + + + 0 + 0 + 304 + 296 + + + + + 0 + 0 + + + + Data Preview + + + true + + + true + + + + + + Double Click Column Headers to Change Order + + + + + + + + + Autosize Column Widths + + + + + + + :/icons/AutosizeStretch_16x.png:/icons/AutosizeStretch_16x.png + + + + + + + Check to skip first line in file + + + Has header + + + + + + + Field Set: + + + + + + + + + + + + + 0 + 0 + + + + QAbstractScrollArea::AdjustToContentsOnFirstShow + + + QAbstractItemView::AnyKeyPressed|QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked + + + true + + + true + + + + + + + + + + + + + + + + + 0 + 0 + + + + Reset + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Cancel + + + + + + + + 0 + 0 + + + + Confirm + + + + + + + + + + + + + btn_cancel + clicked() + Dialog + reject() + + + 421 + 328 + + + 274 + 174 + + + + + btn_confirm + clicked() + Dialog + accept() + + + 502 + 328 + + + 274 + 174 + + + + + btn_autosize + clicked() + table_col_edit + resizeColumnsToContents() + + + 24 + 38 + + + 151 + 146 + + + + + diff --git a/dgp/gui/ui/info_dialog.ui b/dgp/gui/ui/info_dialog.ui new file mode 100644 index 0000000..639eaa0 --- /dev/null +++ b/dgp/gui/ui/info_dialog.ui @@ -0,0 +1,67 @@ + + + InfoDialog + + + + 0 + 0 + 213 + 331 + + + + Info + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + InfoDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + InfoDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/dgp/gui/ui/main_window.ui b/dgp/gui/ui/main_window.ui index 03e092c..2d951f8 100644 --- a/dgp/gui/ui/main_window.ui +++ b/dgp/gui/ui/main_window.ui @@ -20,249 +20,28 @@ Dynamic Gravity Processor - - :/images/assets/geoid_icon.png:/images/assets/geoid_icon.png + + :/images/geoid:/images/geoid QTabWidget::Triangular + + 0 + + + 0 + + + 0 + + + 0 + - - - Qt::Vertical - - - false - - - - - - - - 0 - 500 - - - - 0 - - - - Gravity - - - - - - - - - - GPS - - - - - - - - - - - - - - - 0 - 100 - - - - - - - - 1 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - true - - - - 1 - 0 - - - - true - - - - - - Selection Info - - - - - - - - - - - 2 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - 0 - 0 - - - - - 0 - 100 - - - - - 5000 - 400 - - - - - - - - - 160 - 160 - 160 - - - - - - - - - 160 - 160 - 160 - - - - - - - - - 240 - 240 - 240 - - - - - - - - true - - - QFrame::StyledPanel - - - true - - - - - - - - - - Debug - - - - - Info - - - - - Warning - - - - - Error - - - - - Critical - - - - - - - - - 100 - 16777215 - - - - Clear - - - - - - - <html><head/><body><p align="right">Logging Level:</p></body></html> - - - - - - - - - - - + @@ -289,20 +68,22 @@ Help - + + Panels - + Project - + + @@ -320,7 +101,7 @@ true - + true @@ -332,14 +113,14 @@ - 300 - 632 + 198 + 165 - 300 - 800 + 524287 + 524287 @@ -351,28 +132,55 @@ 1 - + + + + 0 + 0 + + + + 3 + + + 0 + + + 0 + + + 0 + - + 5 - - + + 3 + + + - Import Data - - - - :/images/assets/geoid_icon.png:/images/assets/geoid_icon.png + Project Tree: - - + + - Project Tree: + Import Gravity + + + + :/icons/gravity:/icons/gravity + + + + 16 + 16 + @@ -382,18 +190,37 @@ Add Flight - - :/images/assets/flight_icon.png:/images/assets/flight_icon.png + + :/icons/airborne:/icons/airborne + + + + + + + Import GPS + + + + :/icons/gps:/icons/gps - - - - QFrame::StyledPanel + + + + Add Meter + + + + :/icons/sensor:/icons/sensor - - QFrame::Raised + + + + + + QAbstractItemView::NoEditTriggers @@ -402,10 +229,286 @@ - + + + Toolbar + + + false + + + TopToolBarArea + + + false + + + + + + + + + + + + + + + + 0 + 0 + + + + + 248 + 246 + + + + + 524287 + 246 + + + + + 0 + 0 + + + + false + + + QDockWidget::AllDockWidgetFeatures + + + Qt::BottomDockWidgetArea|Qt::TopDockWidgetArea + + + Console + + + 8 + + + + + 0 + 0 + + + + + 5 + + + 0 + + + 5 + + + 0 + + + 0 + + + + + + 2 + 0 + + + + + 2 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 5 + + + 6 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + + + + + 160 + 160 + 160 + + + + + + + + + 160 + 160 + 160 + + + + + + + + + 240 + 240 + 240 + + + + + + + + true + + + QFrame::StyledPanel + + + true + + + + + + + + + + 0 + 0 + + + + + Debug + + + + + Info + + + + + Warning + + + + + Error + + + + + Critical + + + + + + + + + 100 + 16777215 + + + + Clear + + + + + + + <html><head/><body><p align="right">Logging Level:</p></body></html> + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + :/icons/open_in_new:/icons/open_in_new + Documentation + + View Online Documentation + F1 @@ -418,20 +521,6 @@ Ctrl+Q - - - true - - - true - - - Channels - - - Alt+1 - - true @@ -447,6 +536,10 @@ + + + :/icons/new_file:/icons/new_file + New Project... @@ -455,6 +548,10 @@ + + + :/icons/folder_open:/icons/folder_open + Open Project @@ -463,6 +560,10 @@ + + + :/icons/save:/icons/save + Save Project @@ -471,6 +572,10 @@ + + + :/icons/airborne:/icons/airborne + Add Flight @@ -479,6 +584,10 @@ + + + :/icons/sensor:/icons/sensor + Add Meter @@ -487,6 +596,10 @@ + + + :/icons/info:/icons/info + Project Info... @@ -494,27 +607,83 @@ Ctrl+I - + + + true + + + true + - Import Data + Console - Ctrl+O + Alt+3 + + + + + + :/icons/gps:/icons/gps + + + Import GPS + + + + + + :/icons/gravity:/icons/gravity + + + Import Gravity + + + + + true + + + + :/icons/console:/icons/console + + + Debug Console + + + Toggle Debug Console + + + + + About + + + ProjectTreeView + QTreeView +
dgp.gui.views.project_tree_view
+
+ + WorkspaceWidget + QTabWidget +
dgp.gui.widgets.workspace_widget
+ 1 +
+
prj_add_flight - dataPlotTabWidget - + - action_channel_dock + action_info_dock toggled(bool) - channelDock + info_dock setVisible(bool) @@ -522,20 +691,20 @@ -1 - 149 - 419 + 744 + 990 - channelDock + info_dock visibilityChanged(bool) - action_channel_dock + action_info_dock setChecked(bool) - 149 - 419 + 744 + 973 -1 @@ -543,5 +712,53 @@ + + btn_clear_console + clicked() + text_console + clear() + + + 62 + 1101 + + + 750 + 987 + + + + + info_dock + visibilityChanged(bool) + action_debug_Console + setChecked(bool) + + + 744 + 991 + + + -1 + -1 + + + + + action_debug_Console + toggled(bool) + info_dock + setVisible(bool) + + + -1 + -1 + + + 744 + 991 + + + diff --git a/dgp/gui/ui/plot_options_widget.ui b/dgp/gui/ui/plot_options_widget.ui new file mode 100644 index 0000000..60bc96a --- /dev/null +++ b/dgp/gui/ui/plot_options_widget.ui @@ -0,0 +1,211 @@ + + + PlotOptions + + + + 0 + 0 + 205 + 285 + + + + Form + + + + + + + 0 + 0 + + + + Enable transparency for plot data curves + + + Trace Alpha + + + true + + + + + + Adjust the alpha (transparency) of the curves on this plot + + + 1000 + + + 100 + + + 250 + + + 1000 + + + Qt::Horizontal + + + false + + + false + + + + + + + + + + Grid Visibility + + + + + + Adjust the alpha (transparency) of the grid lines + + + 255 + + + 8 + + + 16 + + + 128 + + + Qt::Horizontal + + + + + + + Show or hide vertical (x-axis) grid-lines + + + X + + + true + + + + + + + Show or hide horizontal (y-axis) grid lines for the left y-axis + + + Y (Left) + + + true + + + + + + + Alpha + + + + + + + Show or hide horizontal (y-axis) grid lines for the right y-axis + + + Y (Right) + + + + + + + + + + Compute and display an average curve of all curves displayed on the primary (left) axis. + + + Show Average Curve + + + + + + + Enable down-sampling to visually decimate data (may improve interactive performance) + + + Down Sampling + + + false + + + true + + + false + + + + + + x + + + 1 + + + 10 + + + 1 + + + 1 + + + + + + + Step + + + + + + + + + + Reset plot options to their default values. + + + Reset Options + + + + + + + + diff --git a/dgp/gui/ui/project_dialog.ui b/dgp/gui/ui/project_dialog.ui index ff5aec4..cb74913 100644 --- a/dgp/gui/ui/project_dialog.ui +++ b/dgp/gui/ui/project_dialog.ui @@ -6,107 +6,366 @@ 0 0 - 700 - 300 + 900 + 450 - + 0 0 - 500 - 300 + 0 + 0 - 700 - 300 + 16777215 + 16777215 + + + + + 50 + 50 Create New Project + + + :/icons/dgs:/icons/dgs + + + true + false - + 0 - - - - - - Project Name:* + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + QFrame::Raised + + + 1 + + + + 20 + 20 + + + + QListView::ListMode + + + true + + + + + + + 3 + + + + + QLayout::SetNoConstraint - - prj_name + + QFormLayout::ExpandingFieldsGrow - - - - - - - 200 - 0 - + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - + + Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing + + + 3 + + + + + + 0 + 0 + + + + + 0 + 25 + + + + Project Name:* + + + prj_name + + + + + + + + + + 0 + 1 + + + + + 0 + 25 + + + + + 8 + + + + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + Project Directory:* + + + prj_dir + + + + + + + 2 + + + 0 + + + 0 + + + + + + 0 + 1 + + + + + 0 + 25 + + + + + 8 + + + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + + + + + + 0 + 0 + + + + ... + + + + + + + + + + 75 + true + + + + required fields* + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + Properties + + + + + + - - + + - Project Directory:* - - - prj_dir + - - + + + + + + false + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + - + - + 0 - 1 + 0 - 200 + 0 0 + + + 16777215 + 16777215 + + + + Cancel + - + + + + 0 + 0 + + - 10 + 0 0 - 30 + 16777215 16777215 - ... + Create @@ -114,135 +373,18 @@ - - - - - - - 75 - 0 - - - - - 500 - 16777215 - - - - Cancel - - - - - - - - 100 - 0 - - - - - 500 - 16777215 - - - - Create - - - - - - - - - - 100 - 0 - - - - - 125 - 16777215 - - - - QFrame::Raised - - - 1 - - - - 20 - 20 - - - - QListView::ListMode - - - true - - - - - - - Description: - - - prj_description - - - - - - - - 12 - - - - New Gravity Project - - - - - - - - - - - 75 - true - - - - required fields* - - - - prj_name - prj_dir - prj_browse - prj_description - prj_cancel - prj_create + btn_create prj_type_list - + + + - prj_cancel + btn_cancel clicked() Dialog reject() @@ -257,5 +399,37 @@ + + prj_properties + clicked() + widget_advanced + show() + + + 301 + 82 + + + 526 + 405 + + + + + btn_create + clicked() + Dialog + accept() + + + 851 + 427 + + + 449 + 224 + + + diff --git a/dgp/gui/ui/project_properties_dialog.ui b/dgp/gui/ui/project_properties_dialog.ui new file mode 100644 index 0000000..f8320ad --- /dev/null +++ b/dgp/gui/ui/project_properties_dialog.ui @@ -0,0 +1,103 @@ + + + ProjectPropertiesDialog + + + + 0 + 0 + 578 + 445 + + + + Dialog + + + + + + QTabWidget::West + + + 0 + + + + Properties + + + + + + + + + + Miscellaneous + + + + + + + + + + QLabel { color: red; } + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + qdbb_dialog_btns + accepted() + ProjectPropertiesDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + qdbb_dialog_btns + rejected() + ProjectPropertiesDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/dgp/gui/ui/recent_project_dialog.ui b/dgp/gui/ui/recent_project_dialog.ui new file mode 100644 index 0000000..c499d4d --- /dev/null +++ b/dgp/gui/ui/recent_project_dialog.ui @@ -0,0 +1,262 @@ + + + RecentProjects + + + + 0 + 0 + 475 + 752 + + + + + 0 + 0 + + + + Dynamic Gravity Processor + + + + :/images/geoid:/images/geoid + + + + + + QFrame::NoFrame + + + + + + :/icons/dgp + + + false + + + Qt::AlignCenter + + + + + + + <html><head/><body><p align="center">Version 0.1</p><p align="center">Licensed under the Apache-2.0 License</p></body></html> + + + + + + + + + + true + + + false + + + + 0 + + + 0 + + + 0 + + + + + + 2 + 0 + + + + Open Recent Project: + + + + + + + + 100 + 0 + + + + Clear Recent + + + + + + + + + + + 0 + 0 + + + + + + + + + + + Qt::AlignCenter + + + true + + + + 3 + + + 0 + + + 0 + + + + + &New Project + + + + + + + Browse for a project + + + Qt::ImhNone + + + &Browse... + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 40 + 0 + + + + color: rgb(255, 0, 0) + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Qt::ImhPreferUppercase + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + browse + + + Ctrl+O + + + + + + + + + dialog_buttons + rejected() + RecentProjects + reject() + + + 340 + 469 + + + 299 + 249 + + + + + dialog_buttons + accepted() + RecentProjects + accept() + + + 387 + 469 + + + 299 + 249 + + + + + diff --git a/dgp/gui/ui/resources.qrc b/dgp/gui/ui/resources.qrc deleted file mode 100644 index fbbe3e0..0000000 --- a/dgp/gui/ui/resources.qrc +++ /dev/null @@ -1,10 +0,0 @@ - - - assets/branch-closed.png - assets/branch-open.png - assets/boat_icon.png - assets/dgs_icon.xpm - assets/flight_icon.png - assets/geoid_icon.png - - diff --git a/dgp/gui/ui/resources/autosize.png b/dgp/gui/ui/resources/autosize.png new file mode 100644 index 0000000..8bbac86 Binary files /dev/null and b/dgp/gui/ui/resources/autosize.png differ diff --git a/dgp/gui/ui/resources/boat.png b/dgp/gui/ui/resources/boat.png new file mode 100644 index 0000000..3620adc Binary files /dev/null and b/dgp/gui/ui/resources/boat.png differ diff --git a/dgp/gui/ui/resources/chevron_down.png b/dgp/gui/ui/resources/chevron_down.png new file mode 100644 index 0000000..4c76133 Binary files /dev/null and b/dgp/gui/ui/resources/chevron_down.png differ diff --git a/dgp/gui/ui/resources/chevron_left.png b/dgp/gui/ui/resources/chevron_left.png new file mode 100644 index 0000000..cbf41b4 Binary files /dev/null and b/dgp/gui/ui/resources/chevron_left.png differ diff --git a/dgp/gui/ui/resources/chevron_right.png b/dgp/gui/ui/resources/chevron_right.png new file mode 100644 index 0000000..893a7ca Binary files /dev/null and b/dgp/gui/ui/resources/chevron_right.png differ diff --git a/dgp/gui/ui/resources/chevron_up.png b/dgp/gui/ui/resources/chevron_up.png new file mode 100644 index 0000000..540d3e1 Binary files /dev/null and b/dgp/gui/ui/resources/chevron_up.png differ diff --git a/dgp/gui/ui/resources/console.png b/dgp/gui/ui/resources/console.png new file mode 100644 index 0000000..455ef8d Binary files /dev/null and b/dgp/gui/ui/resources/console.png differ diff --git a/dgp/gui/ui/resources/delete.png b/dgp/gui/ui/resources/delete.png new file mode 100644 index 0000000..0369a90 Binary files /dev/null and b/dgp/gui/ui/resources/delete.png differ diff --git a/dgp/gui/ui/resources/dgp-splash.png b/dgp/gui/ui/resources/dgp-splash.png new file mode 100644 index 0000000..4d028d9 Binary files /dev/null and b/dgp/gui/ui/resources/dgp-splash.png differ diff --git a/dgp/gui/ui/resources/dgp_icon.png b/dgp/gui/ui/resources/dgp_icon.png new file mode 100644 index 0000000..313bdb6 Binary files /dev/null and b/dgp/gui/ui/resources/dgp_icon.png differ diff --git a/dgp/gui/ui/resources/dgp_icon_large.png b/dgp/gui/ui/resources/dgp_icon_large.png new file mode 100644 index 0000000..8d425d3 Binary files /dev/null and b/dgp/gui/ui/resources/dgp_icon_large.png differ diff --git a/dgp/gui/ui/resources/dgp_simple.png b/dgp/gui/ui/resources/dgp_simple.png new file mode 100644 index 0000000..c13917b Binary files /dev/null and b/dgp/gui/ui/resources/dgp_simple.png differ diff --git a/dgp/gui/ui/assets/dgs_icon.xpm b/dgp/gui/ui/resources/dgs_icon.xpm similarity index 100% rename from dgp/gui/ui/assets/dgs_icon.xpm rename to dgp/gui/ui/resources/dgs_icon.xpm diff --git a/dgp/gui/ui/resources/flight.png b/dgp/gui/ui/resources/flight.png new file mode 100644 index 0000000..e62e937 Binary files /dev/null and b/dgp/gui/ui/resources/flight.png differ diff --git a/dgp/gui/ui/resources/folder_closed.png b/dgp/gui/ui/resources/folder_closed.png new file mode 100644 index 0000000..3cb81f8 Binary files /dev/null and b/dgp/gui/ui/resources/folder_closed.png differ diff --git a/dgp/gui/ui/resources/folder_open.png b/dgp/gui/ui/resources/folder_open.png new file mode 100644 index 0000000..96558f3 Binary files /dev/null and b/dgp/gui/ui/resources/folder_open.png differ diff --git a/dgp/gui/ui/assets/geoid_icon.png b/dgp/gui/ui/resources/geoid.png similarity index 100% rename from dgp/gui/ui/assets/geoid_icon.png rename to dgp/gui/ui/resources/geoid.png diff --git a/dgp/gui/ui/resources/gps.png b/dgp/gui/ui/resources/gps.png new file mode 100644 index 0000000..1f98d96 Binary files /dev/null and b/dgp/gui/ui/resources/gps.png differ diff --git a/dgp/gui/ui/resources/grav_icon.png b/dgp/gui/ui/resources/grav_icon.png new file mode 100644 index 0000000..38f2249 Binary files /dev/null and b/dgp/gui/ui/resources/grav_icon.png differ diff --git a/dgp/gui/ui/resources/grid_off.png b/dgp/gui/ui/resources/grid_off.png new file mode 100644 index 0000000..2364166 Binary files /dev/null and b/dgp/gui/ui/resources/grid_off.png differ diff --git a/dgp/gui/ui/resources/grid_on.png b/dgp/gui/ui/resources/grid_on.png new file mode 100644 index 0000000..61ade8c Binary files /dev/null and b/dgp/gui/ui/resources/grid_on.png differ diff --git a/dgp/gui/ui/resources/help_outline.png b/dgp/gui/ui/resources/help_outline.png new file mode 100644 index 0000000..b160d34 Binary files /dev/null and b/dgp/gui/ui/resources/help_outline.png differ diff --git a/dgp/gui/ui/resources/info.png b/dgp/gui/ui/resources/info.png new file mode 100644 index 0000000..eec7131 Binary files /dev/null and b/dgp/gui/ui/resources/info.png differ diff --git a/dgp/gui/ui/resources/line_mode.png b/dgp/gui/ui/resources/line_mode.png new file mode 100644 index 0000000..c87df74 Binary files /dev/null and b/dgp/gui/ui/resources/line_mode.png differ diff --git a/dgp/gui/ui/resources/location.png b/dgp/gui/ui/resources/location.png new file mode 100644 index 0000000..eb2c8fa Binary files /dev/null and b/dgp/gui/ui/resources/location.png differ diff --git a/dgp/gui/ui/resources/new_file.png b/dgp/gui/ui/resources/new_file.png new file mode 100644 index 0000000..ab0badf Binary files /dev/null and b/dgp/gui/ui/resources/new_file.png differ diff --git a/dgp/gui/ui/resources/open_in_new.png b/dgp/gui/ui/resources/open_in_new.png new file mode 100644 index 0000000..2ee464b Binary files /dev/null and b/dgp/gui/ui/resources/open_in_new.png differ diff --git a/dgp/gui/ui/resources/plot_line.png b/dgp/gui/ui/resources/plot_line.png new file mode 100644 index 0000000..62723bc Binary files /dev/null and b/dgp/gui/ui/resources/plot_line.png differ diff --git a/dgp/gui/ui/resources/project_tree.png b/dgp/gui/ui/resources/project_tree.png new file mode 100644 index 0000000..cbcca1b Binary files /dev/null and b/dgp/gui/ui/resources/project_tree.png differ diff --git a/dgp/gui/ui/resources/resources.qrc b/dgp/gui/ui/resources/resources.qrc new file mode 100644 index 0000000..87abf95 --- /dev/null +++ b/dgp/gui/ui/resources/resources.qrc @@ -0,0 +1,36 @@ + + + open_in_new.png + select.png + console.png + chevron_left.png + chevron_up.png + dgp_simple.png + dgp_icon.png + dgp_icon_large.png + grid_off.png + grid_on.png + settings.png + info.png + help_outline.png + delete.png + line_mode.png + plot_line.png + folder_open.png + autosize.png + new_file.png + sensor.png + save_project.png + grav_icon.png + location.png + dgs_icon.xpm + project_tree.png + boat.png + chevron_down.png + flight.png + chevron_right.png + + + geoid.png + + diff --git a/dgp/gui/ui/resources/save_project.png b/dgp/gui/ui/resources/save_project.png new file mode 100644 index 0000000..f57f504 Binary files /dev/null and b/dgp/gui/ui/resources/save_project.png differ diff --git a/dgp/gui/ui/resources/select.png b/dgp/gui/ui/resources/select.png new file mode 100644 index 0000000..aa2b345 Binary files /dev/null and b/dgp/gui/ui/resources/select.png differ diff --git a/dgp/gui/ui/resources/sensor.png b/dgp/gui/ui/resources/sensor.png new file mode 100644 index 0000000..81364e2 Binary files /dev/null and b/dgp/gui/ui/resources/sensor.png differ diff --git a/dgp/gui/ui/resources/settings.png b/dgp/gui/ui/resources/settings.png new file mode 100644 index 0000000..e3ea7ef Binary files /dev/null and b/dgp/gui/ui/resources/settings.png differ diff --git a/dgp/gui/ui/resources/time_line.png b/dgp/gui/ui/resources/time_line.png new file mode 100644 index 0000000..3d68973 Binary files /dev/null and b/dgp/gui/ui/resources/time_line.png differ diff --git a/dgp/gui/ui/splash_screen.ui b/dgp/gui/ui/splash_screen.ui deleted file mode 100644 index 03d4c66..0000000 --- a/dgp/gui/ui/splash_screen.ui +++ /dev/null @@ -1,157 +0,0 @@ - - - Launcher - - - - 0 - 0 - 600 - 500 - - - - Dynamic Gravity Processor - - - - :/images/assets/geoid_icon.png:/images/assets/geoid_icon.png - - - - - - <html><head/><body><p align="center"><span style=" font-size:16pt; font-weight:600; color:#55557f;">Dynamic Gravity Processor</span></p></body></html> - - - - - - - QFrame::NoFrame - - - - - - :/images/assets/geoid_icon.png - - - true - - - Qt::AlignCenter - - - - - - - <html><head/><body><p align="center">Version 0.1</p><p align="center">Licensed under the Apache-2.0 License</p></body></html> - - - - - - - Open Recent Project: - - - - - - - - - - - - - - - - &New Project... - - - - - - - Qt::ImhNone - - - &Browse... - - - - - - - color: rgb(255, 0, 0) - - - - - - - - - - Qt::ImhPreferUppercase - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - browse - - - Ctrl+O - - - - - - - - - dialog_buttons - rejected() - Launcher - reject() - - - 340 - 469 - - - 299 - 249 - - - - - dialog_buttons - accepted() - Launcher - accept() - - - 387 - 469 - - - 299 - 249 - - - - - diff --git a/dgp/gui/ui/transform_tab_widget.ui b/dgp/gui/ui/transform_tab_widget.ui new file mode 100644 index 0000000..a080bec --- /dev/null +++ b/dgp/gui/ui/transform_tab_widget.ui @@ -0,0 +1,165 @@ + + + TransformInterface + + + + 0 + 0 + 298 + 450 + + + + + 1 + 0 + + + + Form + + + + QLayout::SetNoConstraint + + + + + + 0 + 0 + + + + false + + + 0 + + + false + + + + Transforms + + + + + + + + Transform Graph: + + + + + + + + + + + + + + + + Execute transform graph + + + Transform + + + + + + + false + + + Export + + + + + + + Channels (Y-Axis): + + + + + + + QAbstractItemView::NoEditTriggers + + + + + + + + + Select All + + + + + + + Deselect All + + + + + + + + + + + X-Axis: + + + + + + + + + + Toggle segment mode to plot by data-segments + + + Segment Mode + + + true + + + + + + + + + + Graph Source + + + + + + + + + + + + + + + + diff --git a/dgp/gui/utils.py b/dgp/gui/utils.py index e00e17f..eb8d082 100644 --- a/dgp/gui/utils.py +++ b/dgp/gui/utils.py @@ -1,40 +1,159 @@ -# coding: utf-8 - +# -*- coding: utf-8 -*- +import json import logging from pathlib import Path -from typing import Union +from typing import Callable + +from PyQt5.QtCore import QThread, pyqtSignal, pyqtBoundSignal + +from dgp.core.models.project import GravityProject, AirborneProject +from dgp.core.oid import OID + +__all__ = ['LOG_FORMAT', 'LOG_COLOR_MAP', 'LOG_LEVEL_MAP', 'ConsoleHandler', + 'ProgressEvent', 'ThreadedFunction', 'clear_signal', + 'load_project_from_path'] -LOG_FORMAT = logging.Formatter(fmt="%(asctime)s:%(levelname)s - %(module)s:%(funcName)s :: %(message)s", +LOG_FORMAT = logging.Formatter(fmt="%(asctime)s:%(levelname)s - %(module)s:" + "%(funcName)s :: %(message)s", datefmt="%H:%M:%S") -LOG_COLOR_MAP = {'debug': 'blue', 'info': 'yellow', 'warning': 'brown', 'error': 'red', 'critical': 'orange'} +LOG_COLOR_MAP = {'debug': 'blue', 'info': 'yellow', 'warning': 'brown', + 'error': 'red', 'critical': 'orange'} +LOG_LEVEL_MAP = {'debug': logging.DEBUG, 'info': logging.INFO, + 'warning': logging.WARNING, 'error': logging.ERROR, + 'critical': logging.CRITICAL} +_loaders = {GravityProject.__name__: GravityProject, + AirborneProject.__name__: AirborneProject} + +_log = logging.getLogger(__name__) class ConsoleHandler(logging.Handler): - """Custom Logging Handler allowing the specification of a custom destination e.g. a QTextEdit area.""" - def __init__(self, destination): + """ + Custom Logging Handler allowing the specification of a custom destination + e.g. a QTextEdit area. + """ + def __init__(self, destination: Callable[[str, str], None]): """ - Initialize the Handler with a destination function to be called on emit(). - Destination should take 2 parameters, however emit will fallback to passing a single parameter on exception. - :param destination: callable function accepting 2 parameters: (log entry, log level name) + Initialize the Handler with a destination function to send logs to. + Destination should take 2 parameters, however emit will fallback to + passing a single parameter on exception. + :param destination: callable function accepting 2 parameters: + (log entry, log level name) """ super().__init__() - self.dest = destination + self._dest = destination def emit(self, record: logging.LogRecord): - """Emit the log record, first running it through any specified formatter.""" + """Emit the log record, first running it through any specified + formatter.""" entry = self.format(record) try: - self.dest(entry, record.levelname.lower()) + self._dest(entry, record.levelname.lower()) except TypeError: - self.dest(entry) + self._dest(entry) + +class ProgressEvent: + """Progress Event is used to define a request for the application to display + a progress notification to the user, typically in the form of a QProgressBar + + ProgressEvents are emitted from the ProjectTreeModel model class, and should + be captured by the application's MainWindow, which uses the ProgressEvent + object to generate and display a QProgressDialog, or QProgressBar somewhere + within the application. -def get_project_file(path: Path) -> Union[Path, None]: """ - Attempt to retrieve a project file (*.d2p) from the given dir path, otherwise signal failure by returning False - :param path: str or pathlib.Path : Directory path to project - :return: pathlib.Path : absolute path to *.d2p file if found, else False + def __init__(self, uid: OID, label: str = None, start: int = 0, + stop: int = 100, value: int = 0, modal: bool = True, + receiver: object = None): + self.uid = uid + self.label = label + self.start = start + self.stop = stop + self._value = value + self.modal = modal + self.receiver = receiver + + @property + def completed(self): + return self._value >= self.stop + + @property + def value(self) -> int: + return self._value + + @value.setter + def value(self, value: int) -> None: + self._value = value + + +class ThreadedFunction(QThread): + result = pyqtSignal(object) + + def __init__(self, functor, *args, parent): + super().__init__(parent) + self._functor = functor + self._args = args + + def run(self): + try: + res = self._functor(*self._args) + self.result.emit(res) + except Exception as e: + _log.exception(f"Exception executing {self._functor!r}") + + +def load_project_from_path(path: Path) -> GravityProject: + """Search a directory path for a valid DGP json file, then load the project + using the appropriate class loader. + + Any discovered .json files are loaded and parsed using a naive JSON loader, + the top level object is then inspected for an `_type` attribute, which + determines the project loader to use. + + The project's path attribute is updated to the path where it was loaded from + upon successful decoding. This is to ensure any relative paths encoded in + the project do not break if the project's directory has been moved/renamed. + + Parameters + ---------- + path: :class:`pathlib.Path` + Directory path which contains a valid DGP project .json file. + If the path specified is not a directory, the parent is automatically + used + + Raises + ------ + :exc:`FileNotFoundError` + If supplied `path` does not exist, or + If no valid project JSON file could be loaded from the path + + + ToDo: Use QLockFile to try and lock the project json file for exclusive use + """ - for child in sorted(path.glob('*.d2p')): - return child.resolve() - return None + if not path.exists(): + raise FileNotFoundError(f'Non-existent path supplied {path!s}') + if not path.is_dir(): + path = path.parent + + for child in path.glob('*.json'): + with child.open('r') as fd: + raw_str = fd.read() + raw_json: dict = json.loads(raw_str) + + loader = _loaders.get(raw_json.get('_type', None), None) + if loader is not None: + project = loader.from_json(raw_str) + project.path = path + return project + raise FileNotFoundError(f'No valid DGP JSON file could be loaded from {path!s}') + + +def clear_signal(signal: pyqtBoundSignal): + """Utility method to clear all connections from a bound signal""" + while True: + try: + signal.disconnect() + except TypeError: + break diff --git a/dgp/gui/views/__init__.py b/dgp/gui/views/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dgp/gui/views/project_tree_view.py b/dgp/gui/views/project_tree_view.py new file mode 100644 index 0000000..242783b --- /dev/null +++ b/dgp/gui/views/project_tree_view.py @@ -0,0 +1,132 @@ +# -*- coding: utf-8 -*- +from typing import Optional, List + +from PyQt5 import QtCore +from PyQt5.QtCore import QObject, QModelIndex, pyqtSlot +from PyQt5.QtGui import QContextMenuEvent +from PyQt5.QtWidgets import QTreeView, QMenu + +from dgp.core.controllers.controller_interfaces import (IAirborneController, + VirtualBaseController, + MenuBinding) +from dgp.core.controllers.project_treemodel import ProjectTreeModel + + +class ProjectTreeView(QTreeView): + """ProjectTreeView is a customized QTreeView use to display and interact + with the hierarchy of a Gravity project(s) in the User Interface. + + This class is instantiated as a Promoted Widget within a Qt .ui form + created wit Qt Designer. + Because of this, the constructor does not accept a model instance, and the + model should be instead set with the :func:`setModel` method. + + """ + def __init__(self, parent: Optional[QObject]=None): + super().__init__(parent=parent) + self.setMinimumSize(QtCore.QSize(0, 300)) + self.setAlternatingRowColors(False) + self.setAutoExpandDelay(1) + self.setExpandsOnDoubleClick(False) + self.setRootIsDecorated(False) + self.setUniformRowHeights(True) + self.setHeaderHidden(True) + self.setObjectName('project_tree_view') + self.setContextMenuPolicy(QtCore.Qt.DefaultContextMenu) + + # Set Stylesheet for Tree View, see: + # http://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtreeview + self.setStyleSheet(""" + QTreeView::item { + } + QTreeView::branch { + /*background: palette(base);*/ + } + QTreeView::branch:closed:has-children { + background: none; + image: url(:/icons/chevron-right); + } + QTreeView::branch:open:has-children { + background: none; + image: url(:/icons/chevron-down); + } + """) + + self.clicked.connect(self._on_click) + self.doubleClicked.connect(self._on_double_click) + self._action_refs = [] + + def model(self) -> ProjectTreeModel: + return super().model() + + @pyqtSlot(QModelIndex, name='_on_click') + def _on_click(self, index: QModelIndex): + self.model().item_selected(index) + + @pyqtSlot(QModelIndex, name='_on_double_click') + def _on_double_click(self, index: QModelIndex): + """Selectively expand/collapse an item depending on its active state""" + item = self.model().itemFromIndex(index) + if isinstance(item, VirtualBaseController): + if item.is_active: + self.setExpanded(index, not self.isExpanded(index)) + else: + self.setExpanded(index, True) + else: + self.setExpanded(index, not self.isExpanded(index)) + self.model().item_activated(index) + + def _build_menu(self, menu: QMenu, bindings: List[MenuBinding]): + self._action_refs.clear() + for attr, args in bindings: + if hasattr(QMenu, attr): + res = getattr(menu, attr)(*args) + self._action_refs.append(res) + + def contextMenuEvent(self, event: QContextMenuEvent, *args, **kwargs): + index = self.indexAt(event.pos()) + item: VirtualBaseController = self.model().itemFromIndex(index) + expanded = self.isExpanded(index) + + menu = QMenu(self) + # bindings = getattr(item, 'menu_bindings', [])[:] # type: List + if isinstance(item, VirtualBaseController): + bindings = item.menu[:] + else: + bindings = [] + + # Experimental Menu Inheritance/Extend functionality + # if hasattr(event_item, 'inherit_context') and event_item.inherit_context: + # print("Inheriting parent menu(s)") + # ancestors = [] + # parent = event_item.parent() + # while parent is not None: + # ancestors.append(parent) + # if not hasattr(parent, 'inherit_context'): + # break + # parent = parent.parent() + # print(ancestors) + # + # ancestor_bindings = [] + # for item in reversed(ancestors): + # if hasattr(item, 'menu_bindings'): + # ancestor_bindings.extend(item.menu_bindings) + # pprint(ancestor_bindings) + # bindings.extend(ancestor_bindings) + + bindings.append(('addSeparator', ())) + if isinstance(item, IAirborneController): + bindings.append(('addAction', ("Expand All", self.expandAll))) + + if item.rowCount(): + bindings.append(('addAction', ("Expand" if not expanded else "Collapse", + lambda: self.setExpanded(index, not expanded)))) + # bindings.append(('addAction', ("Properties", self._get_item_attr(item, 'properties')))) + + self._build_menu(menu, bindings) + menu.exec_(event.globalPos()) + event.accept() + + @staticmethod + def _get_item_attr(item, attr): + return getattr(item, attr, lambda *x, **y: None) diff --git a/dgp/gui/widgets/__init__.py b/dgp/gui/widgets/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dgp/gui/widgets/channel_control_widgets.py b/dgp/gui/widgets/channel_control_widgets.py new file mode 100644 index 0000000..f56fde4 --- /dev/null +++ b/dgp/gui/widgets/channel_control_widgets.py @@ -0,0 +1,451 @@ +# -*- coding: utf-8 -*- +import logging +import itertools +from functools import partial +from typing import List, Dict, Tuple +from weakref import WeakValueDictionary + +from PyQt5.QtCore import Qt, pyqtSignal, QModelIndex, QAbstractItemModel, QSize, QPoint +from PyQt5.QtGui import QStandardItem, QStandardItemModel, QMouseEvent, QColor, QPalette +from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QListView, QMenu, QAction, + QSizePolicy, QStyledItemDelegate, + QStyleOptionViewItem, QHBoxLayout, QLabel, + QColorDialog, QToolButton, QFrame, QComboBox) +from pandas import Series +from pyqtgraph import PlotDataItem + +from dgp.core import Icon, OID +from dgp.gui.plotting.backends import GridPlotWidget, Axis, LINE_COLORS + +__all__ = ['ChannelController', 'ChannelItem'] +_log = logging.getLogger(__name__) + + +class ColorPicker(QLabel): + """ColorPicker creates a colored label displaying its current color value + + Clicking on the picker launches a QColorDialog, allowing the user to choose + a color. + + Parameters + ---------- + color : QColor, optional + Specify the initial color value of the color picker + parent : QWidget, optional + + """ + sigColorChanged = pyqtSignal(object) + + def __init__(self, color: QColor = QColor(), parent=None): + super().__init__(parent) + self.setAutoFillBackground(True) + self.setSizePolicy(QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred)) + self.setToolTip("Customize channel line color") + self._color = color + self._update() + + @property + def color(self) -> QColor: + return self._color + + def mouseReleaseEvent(self, event: QMouseEvent): + color: QColor = QColorDialog.getColor(self._color, parent=self) + if color.isValid(): + self._color = color + self.sigColorChanged.emit(self._color) + self._update() + + def sizeHint(self): + return QSize(30, 30) + + def _update(self): + """Updates the background color for display""" + palette: QPalette = self.palette() + palette.setColor(self.backgroundRole(), self._color) + self.setPalette(palette) + + +class DataChannelEditor(QFrame): + """This object defines the widget displayed when a data channel is selected + within the ChannelController listr view. + + This widget provides controls enabling a user to select which plot and axis + a channel is plotted on, and to set the visibility and color of the channel. + + """ + SIZE = QSize(140, 35) + + def __init__(self, item: 'ChannelItem', rows=1, parent=None): + super().__init__(parent, flags=Qt.Widget) + self.setFrameStyle(QFrame.Box) + self.setLineWidth(1) + self.setAutoFillBackground(True) + + self._item = item + + layout = QHBoxLayout(self) + layout.setContentsMargins(2, 2, 2, 2) + layout.setSpacing(1) + sp_btn = QSizePolicy(QSizePolicy.Minimum, QSizePolicy.MinimumExpanding) + sp_combo = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.MinimumExpanding) + + self._label = QLabel(item.name) + self._picker = ColorPicker(color=item.line_color, parent=self) + self._picker.sigColorChanged.connect(item.set_color) + + # Plot Row Selection ComboBox + + self._row_cb = QComboBox() + self._row_cb.setToolTip("Plot channel on selected row") + self._row_cb.setSizePolicy(sp_combo) + for i in range(rows): + self._row_cb.addItem(str(i), i) + self._row_cb.setCurrentIndex(item.target_row) + self._row_cb.currentIndexChanged.connect(self.change_row) + + # Left/Right Axis Controls + self._left = QToolButton() + self._left.setCheckable(False) + self._left.setToolTip("Plot channel on left y-axis") + self._left.setIcon(Icon.ARROW_LEFT.icon()) + self._left.setSizePolicy(sp_btn) + self._left.clicked.connect(partial(self.change_axis, Axis.LEFT)) + self._right = QToolButton() + self._right.setCheckable(False) + self._right.setToolTip("Plot channel on right y-axis") + self._right.setIcon(Icon.ARROW_RIGHT.icon()) + self._right.setSizePolicy(sp_btn) + self._right.clicked.connect(partial(self.change_axis, Axis.RIGHT)) + + # Channel Settings ToolButton + self._settings = QToolButton() + self._settings.setSizePolicy(sp_btn) + self._settings.setIcon(Icon.SETTINGS.icon()) + + layout.addWidget(self._label) + layout.addSpacing(5) + layout.addWidget(self._picker) + layout.addSpacing(2) + layout.addWidget(self._row_cb) + layout.addSpacing(5) + layout.addWidget(self._left) + layout.addWidget(self._right) + layout.addWidget(self._settings) + + def toggle_axis(self, axis: Axis, checked: bool): + pass + + def change_axis(self, axis): + + self._item.set_axis(axis, emit=False) + if self._item.checkState() == Qt.Checked: + self._item.update() + else: + self._item.setCheckState(Qt.Checked) + + def change_row(self, index): + row: int = self._row_cb.currentData(Qt.UserRole) + self._item.set_row(row) + + def mouseDoubleClickEvent(self, event: QMouseEvent): + self._item.setCheckState(Qt.Unchecked if self._item.visible else Qt.Checked) + + +class ChannelDelegate(QStyledItemDelegate): + def __init__(self, rows=1, parent=None): + super().__init__(parent=parent) + self._rows = rows + + def createEditor(self, parent: QWidget, option: QStyleOptionViewItem, + index: QModelIndex): + item = index.model().itemFromIndex(index) + editor = DataChannelEditor(item, self._rows, parent) + + return editor + + def setModelData(self, editor: QWidget, model: QAbstractItemModel, + index: QModelIndex): + """Do nothing, editor does not directly mutate model data""" + pass + + def sizeHint(self, option: QStyleOptionViewItem, index: QModelIndex): + return DataChannelEditor.SIZE + + +class ChannelItem(QStandardItem): + """The ChannelItem defines the UI representation of a plotable data channel + + ChannelItems maintain the desired state of the channel in relation to its + visibility, line color, plot axis, and plot row/column. It is the + responsibility of the owning controller to act on state changes of the + channel item. + + The itemChanged signal is emitted (via the QStandardItemModel owner) by the + ChannelItem whenever its internal state has been updated. + + Parameters + ---------- + name: str + Display name for the channel + color : QColor, optional + Optional base color for this channel item + + Notes + ----- + Setter methods are used instead of property setters in order to facilitate + signal connections, or setting of properties from within a lambda expression + + """ + _base_color = QColor(Qt.white) + + def __init__(self, name: str, color=QColor()): + super().__init__() + self.setCheckable(True) + self.name = name + self._row = 0 + self._col = 0 + self._axis = Axis.LEFT + self._color = color + self.uid = OID(tag=name) + + self.update(emit=False) + + @property + def target_row(self): + return self._row + + def set_row(self, row, emit=True): + self._row = row + if emit: + self.update() + + @property + def target_axis(self): + return self._axis + + def set_axis(self, axis: Axis, emit=True): + self._axis = axis + if emit: + self.update() + + @property + def line_color(self) -> QColor: + return self._color + + def set_color(self, color: QColor, emit=True): + self._color = color + if emit: + self.update() + + @property + def visible(self) -> bool: + return self.checkState() == Qt.Checked + + def set_visible(self, visible: bool, emit=True): + self.setCheckState(Qt.Checked if visible else Qt.Unchecked) + if emit: + self.update() + + def update(self, emit=True): + if self.visible: + self.setText(f'{self.name} - {self.target_row} | {self.target_axis.value}') + self.setBackground(self.line_color) + else: + self.setText(f'{self.name}') + self.setBackground(self._base_color) + if emit: + self.emitDataChanged() + + def key(self) -> Tuple[int, int, Axis]: + return self._row, self._col, self._axis + + def __hash__(self): + return hash(self.uid) + + +class ChannelController(QWidget): + """The ChannelController widget is associated with a Plotter, e.g. a + :class:`GridPlotWidget`, and provides an interface for a user to select and + plot any of the various :class:`pandas.Series` objects supplied to it. + + Parameters + ---------- + plotter : :class:`~dgp.gui.plotting.backends.GridPlotWidget` + *series : :class:`pandas.Series` + binary_series : List of :class:`pandas.Series`, optional + Optional list of series to be interpreted/grouped as binary data, e.g. + for status bits + parent : QWidget, optional + + """ + def __init__(self, plotter: GridPlotWidget, *series: Series, + binary_series: List[Series] = None, parent: QWidget = None): + super().__init__(parent, flags=Qt.Widget) + self.plotter = plotter + self.plotter.sigPlotCleared.connect(self._channels_cleared) + self.setSizePolicy(QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred)) + self._layout = QVBoxLayout(self) + + self._model = QStandardItemModel() + self._model.itemChanged.connect(self.channel_changed) + self._binary_model = QStandardItemModel() + self._binary_model.itemChanged.connect(self.binary_changed) + + self._series: Dict[OID, Series] = {} + self._active: Dict[OID, PlotDataItem] = WeakValueDictionary() + self._indexes: Dict[OID, Tuple[int, int, Axis]] = {} + + self._colors = itertools.cycle(LINE_COLORS) + + # Define/configure List Views + series_delegate = ChannelDelegate(rows=self.plotter.rows, parent=self) + self.series_view = QListView(parent=self) + self.series_view.setMinimumWidth(250) + self.series_view.setUniformItemSizes(True) + self.series_view.setEditTriggers(QListView.SelectedClicked | + QListView.DoubleClicked | + QListView.CurrentChanged) + self.series_view.setItemDelegate(series_delegate) + self.series_view.setContextMenuPolicy(Qt.CustomContextMenu) + self.series_view.customContextMenuRequested.connect(self._context_menu) + self.series_view.setModel(self._model) + + self._layout.addWidget(self.series_view, stretch=2) + + self.binary_view = QListView(parent=self) + self.binary_view.setEditTriggers(QListView.NoEditTriggers) + self.binary_view.setUniformItemSizes(True) + self.binary_view.setModel(self._binary_model) + + self._status_label = QLabel("Status Channels") + self._layout.addWidget(self._status_label, alignment=Qt.AlignHCenter) + + self._layout.addWidget(self.binary_view, stretch=1) + + self.set_series(*series) + binary_series = binary_series or [] + self.set_binary_series(*binary_series) + + def set_series(self, *series, clear=True): + if clear: + self._model.clear() + + for s in series: + item = ChannelItem(s.name, QColor(next(self._colors))) + self._series[item.uid] = s + self._model.appendRow(item) + + def set_binary_series(self, *series, clear=True): + if clear: + self._binary_model.clear() + + for b in series: + item = QStandardItem(b.name) + item.uid = OID() + item.setCheckable(True) + self._series[item.uid] = b + self._binary_model.appendRow(item) + + def get_state(self): + active_state = {} + for uid, item in self._active.items(): + row, col, axis = self._indexes[uid] + active_state[item.name()] = row, col, axis.value + return active_state + + def restore_state(self, state: Dict[str, Tuple[int, int, str]]): + for i in range(self._model.rowCount()): + item: ChannelItem = self._model.item(i, 0) + if item.name in state: + key = state[item.name] + item.set_visible(True, emit=False) + item.set_row(key[0], emit=False) + item.set_axis(Axis(key[2]), emit=True) + + for i in range(self._binary_model.rowCount()): + item: QStandardItem = self._binary_model.item(i, 0) + if item.text() in state: + item.setCheckState(Qt.Checked) + + def channel_changed(self, item: ChannelItem): + item.update(emit=False) + if item.uid in self._active: # Channel is already somewhere on the plot + if not item.visible: + self._remove_series(item) + else: + self._update_series(item) + + elif item.visible: # Channel is not yet plotted + self._add_series(item) + series = self._series[item.uid] + line = self.plotter.add_series(series, item.target_row, + axis=item.target_axis) + self._active[item.uid] = line + else: # Item is not active, and its state is not visible (do nothing) + pass + + def _add_series(self, item: ChannelItem): + """Add a new series to the controls plotter""" + series = self._series[item.uid] + row = item.target_row + axis = item.target_axis + + line = self.plotter.add_series(series, row, col=0, axis=axis, + pen=item.line_color) + self._active[item.uid] = line + self._indexes[item.uid] = item.key() + + def _update_series(self, item: ChannelItem): + """Update paramters (color, axis, row) of an already plotted series""" + line = self._active[item.uid] + line.setPen(item.line_color) + + # Need to know the current axis and row of an _active line + if item.key() != self._indexes[item.uid]: + self._remove_series(item) + self._add_series(item) + + def _remove_series(self, item: ChannelItem): + line = self._active[item.uid] + self.plotter.remove_plotitem(line) + try: + del self._indexes[item.uid] + except KeyError: + pass + + def _channels_cleared(self): + """Respond to plot notification that all lines have been cleared""" + _log.debug("Plot channels cleared") + for i in range(self._model.rowCount()): + item: ChannelItem = self._model.item(i) + item.set_visible(False, emit=False) + item.update(emit=False) + for i in range(self._binary_model.rowCount()): + item: QStandardItem = self._binary_model.item(i) + item.setCheckState(Qt.Unchecked) + + def binary_changed(self, item: QStandardItem): + if item.checkState() == Qt.Checked: + if item.uid in self._active: + return + else: + series = self._series[item.uid] + line = self.plotter.add_series(series, 1, 0, axis=Axis.RIGHT) + self._active[item.uid] = line + self._indexes[item.uid] = 1, 0, Axis.RIGHT + else: + try: + line = self._active[item.uid] + self.plotter.remove_plotitem(line) + except KeyError: + # Item may have already been deleted by the plot + pass + + def _context_menu(self, point: QPoint): + index: QModelIndex = self.series_view.indexAt(point) + if not index.isValid(): + # DEBUG + print("Providing general context menu (clear items)") + else: + # DEBUG + print(f'Providing menu for item {self._model.itemFromIndex(index).text()}') diff --git a/dgp/gui/widgets/data_transform_widget.py b/dgp/gui/widgets/data_transform_widget.py new file mode 100644 index 0000000..fb0ad85 --- /dev/null +++ b/dgp/gui/widgets/data_transform_widget.py @@ -0,0 +1,263 @@ +# -*- coding: utf-8 -*- +import inspect +import logging +from enum import Enum, auto +from typing import List + +import pandas as pd +from PyQt5.QtCore import pyqtSignal, Qt, pyqtSlot +from PyQt5.QtGui import QStandardItemModel, QStandardItem +from PyQt5.QtWidgets import QWidget, QTextEdit + +from dgp.core.controllers.dataset_controller import DataSetController, DataSegmentController +from dgp.gui.plotting.backends import AxisFormatter +from dgp.gui.plotting.plotters import TransformPlot +from dgp.gui.ui.transform_tab_widget import Ui_TransformInterface +from dgp.lib.transform.graph import TransformGraph +from dgp.lib.transform.transform_graphs import AirbornePost + +try: + from pygments import highlight + from pygments.lexers import PythonLexer + from pygments.formatters import HtmlFormatter + HAS_HIGHLIGHTER = True +except ImportError: + HAS_HIGHLIGHTER = False + + +class _Mode(Enum): + NORMAL = auto() + SEGMENTS = auto() + + +class TransformWidget(QWidget, Ui_TransformInterface): + result = pyqtSignal() + + # User Roles for specific data within a channel + TIME = 0x0101 + LATITUDE = 0x0102 + LONGITUDE = 0x103 + + def __init__(self, dataset: DataSetController, plotter: TransformPlot): + super().__init__() + self.setupUi(self) + self.log = logging.getLogger(__name__) + self._dataset: DataSetController = dataset + self._plot = plotter + self._mode = _Mode.NORMAL + self._segment_indexes = {} + + self._result: pd.DataFrame = None + self.result.connect(self._on_result) + + # Line mask to view individual lines + self._mask = None + + # Initialize Models for ComboBoxes + self.plot_index = QStandardItemModel() + self.transform_graphs = QStandardItemModel() + # Set ComboBox Models + self.qcb_plot_index.setModel(self.plot_index) + self.qcb_transform_graphs.setModel(self.transform_graphs) + self.qcb_transform_graphs.currentIndexChanged.connect(self._graph_source) + + self.qcb_plot_index.currentIndexChanged[int].connect(self._index_changed) + + # Initialize model for transformed channels + self._channel_model = QStandardItemModel() + self._channel_model.itemChanged.connect(self._channel_state_changed) + self.qlv_channels.setModel(self._channel_model) + + self._index_map = { + 'Time': self.TIME, + 'Latitude': self.LATITUDE, + 'Longitude': self.LONGITUDE + } + for key, value in self._index_map.items(): + item = QStandardItem(key) + item.setData(value, Qt.UserRole) + self.plot_index.appendRow(item) + + self.qcb_plot_index.setCurrentIndex(0) + + for choice, method in [('Airborne Post', AirbornePost)]: + item = QStandardItem(choice) + item.setData(method, Qt.UserRole) + self.transform_graphs.appendRow(item) + + self.qpb_execute_transform.clicked.connect(self.execute_transform) + self.qpb_select_all.clicked.connect(lambda: self._set_all_channels(Qt.Checked)) + self.qpb_select_none.clicked.connect(lambda: self._set_all_channels(Qt.Unchecked)) + self.qpb_toggle_mode.clicked.connect(self._mode_toggled) + self.qte_source_browser.setReadOnly(True) + self.qte_source_browser.setLineWrapMode(QTextEdit.NoWrap) + + @property + def xaxis_index(self) -> int: + return self.qcb_plot_index.currentData(Qt.UserRole) + + @property + def raw_gravity(self) -> pd.DataFrame: + return self._dataset.gravity + + @property + def raw_trajectory(self) -> pd.DataFrame: + return self._dataset.trajectory + + @property + def dataframe(self) -> pd.DataFrame: + return self._dataset.dataframe() + + @property + def transform(self) -> TransformGraph: + return self.qcb_transform_graphs.currentData(Qt.UserRole) + + @property + def _channels(self) -> List[QStandardItem]: + return [self._channel_model.item(i) + for i in range(self._channel_model.rowCount())] + + @property + def _segments(self) -> List[DataSegmentController]: + return [self._dataset.segment_model.item(i) + for i in range(self._dataset.segment_model.rowCount())] + + def _graph_source(self, index): # pragma: no cover + """Utility to display the transform graph source (__init__) method + containing the definition for the graph. + + If Pygments is available the source code will be highlighted + + Notes + ----- + The inspection of the source code is somewhat fragile and dependent on + the way the graph is defined in the source. The current method gets the + __init__ source code for the TransformGraph descendant then searches for + the string index of 'self.transform_graph', and takes from the first '{' + until the first '}'. + + """ + graph = self.transform + src = inspect.getsource(graph.__init__) + start_str = 'self.transform_graph' + start_i = src.find('{', src.find(start_str)) + 1 + src = src[start_i:src.find('}')] + trimmed = map(lambda x: x.lstrip(' '), src.split('\n')) + src = '' + for line in trimmed: + src += f'{line}\n' + + if HAS_HIGHLIGHTER: + css = HtmlFormatter().get_style_defs('.highlight') + style_block = f'' + html = highlight(src, PythonLexer(stripall=True), HtmlFormatter()) + self.qte_source_browser.setHtml(f'{style_block}{html}') + else: + self.qte_source_browser.setText(src) + + def _mode_toggled(self): + """Toggle the mode state between Normal or Segments""" + self._set_all_channels(state=Qt.Unchecked) + if self._mode is _Mode.NORMAL: + self._mode = _Mode.SEGMENTS + else: + self._mode = _Mode.NORMAL + self.log.debug(f'Changed mode to {self._mode}') + return + + def _set_all_channels(self, state=Qt.Checked): + for i in range(self._channel_model.rowCount()): + self._channel_model.item(i).setCheckState(state) + + def _add_series(self, series: pd.Series, row=0): + if self._mode is _Mode.NORMAL: + self._plot.add_series(series, row) + elif self._mode is _Mode.SEGMENTS: + self._segment_indexes[series.name] = [] + for i, segment in enumerate(self._segments): + start_i = self._result.index.searchsorted(segment.get_attr('start')) + stop_i = self._result.index.searchsorted(segment.get_attr('stop')) + seg_data = series.iloc[start_i:stop_i] + + seg_data.name = f'{series.name}-{segment.get_attr("label") or i}' + self._segment_indexes[series.name].append(seg_data.name) + self._plot.add_series(seg_data, row=0) + + def _remove_series(self, series: pd.Series): + if self._mode is _Mode.NORMAL: + self._plot.remove_series(series.name, row=0) + elif self._mode is _Mode.SEGMENTS: + for name in self._segment_indexes[series.name]: + self._plot.remove_series(name, row=0) + del self._segment_indexes[series.name] + + def _channel_state_changed(self, item: QStandardItem): + data: pd.Series = item.data(self.xaxis_index) + if item.checkState() == Qt.Checked: + self._add_series(data, row=0) + else: + self._remove_series(data) + + @pyqtSlot(int, name='_index_changed') + def _index_changed(self, index: int): + self.log.debug(f'X-Axis changed to {self.qcb_plot_index.currentText()}') + if self._result is None: + return + if self.xaxis_index in {self.LATITUDE, self.LONGITUDE}: + self._plot.set_axis_formatters(AxisFormatter.SCALAR) + else: + self._plot.set_axis_formatters(AxisFormatter.DATETIME) + + for channel in self._channels: + if channel.checkState() == Qt.Checked: + channel.setCheckState(Qt.Unchecked) + channel.setCheckState(Qt.Checked) + + @pyqtSlot(name='_on_result') + def _on_result(self): + """_on_result called when Transformation DataFrame has been computed. + + This method creates the channel objects for the interface. + """ + default_channels = ['fac'] + + time_df = self._result + lat_df = time_df.set_index('lat') + lon_df = time_df.set_index('lon') + + for i in range(self._channel_model.rowCount()): + item = self._channel_model.item(i) + del item + + self._channel_model.clear() + for col in sorted(time_df.columns): + item = QStandardItem(col) + item.setCheckable(True) + item.setData(time_df[col], self.TIME) + if col == 'lat': + item.setData(pd.Series(), self.LATITUDE) + else: + item.setData(lat_df[col], self.LATITUDE) + + if col == 'lon': + item.setData(pd.Series(), self.LONGITUDE) + else: + item.setData(lon_df[col], self.LONGITUDE) + self._channel_model.appendRow(item) + if col in default_channels: + item.setCheckState(Qt.Checked) + + def execute_transform(self): + gravity = self.raw_gravity + trajectory = self.raw_trajectory + if gravity.empty or trajectory.empty: + self.log.warning("Missing trajectory or gravity") + return + + transform = self.qcb_transform_graphs.currentData(Qt.UserRole) + graph = transform(trajectory, gravity, 0, 0) + self.log.info("Executing graph") + graph.execute() + del self._result + self._result = graph.result_df() + self.result.emit() diff --git a/dgp/gui/widgets/workspace_widget.py b/dgp/gui/widgets/workspace_widget.py new file mode 100644 index 0000000..e2e5536 --- /dev/null +++ b/dgp/gui/widgets/workspace_widget.py @@ -0,0 +1,116 @@ +# -*- coding: utf-8 -*- +import PyQt5.QtWidgets as QtWidgets +from PyQt5.QtGui import QContextMenuEvent, QKeySequence +from PyQt5.QtCore import Qt +from PyQt5.QtWidgets import QAction + +from dgp.core.oid import OID +from ..workspaces.base import WorkspaceTab + + +class _WorkspaceTabBar(QtWidgets.QTabBar): + """Custom Tab Bar to allow us to implement a custom Context Menu to + handle right-click events.""" + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setShape(self.RoundedNorth) + self.setTabsClosable(True) + self.setMovable(True) + + key_close_action = QAction("Close") + key_close_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_W)) + key_close_action.triggered.connect( + lambda: self.tabCloseRequested.emit(self.currentIndex())) + + tab_right_action = QAction("TabRight") + tab_right_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_Tab)) + tab_right_action.triggered.connect(self._tab_right) + + tab_left_action = QAction("TabLeft") + tab_left_action.setShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_Tab)) + tab_left_action.triggered.connect(self._tab_left) + + self._actions = [key_close_action, tab_right_action, tab_left_action] + for action in self._actions: + self.addAction(action) + + def contextMenuEvent(self, event: QContextMenuEvent, *args, **kwargs): + tab = self.tabAt(event.pos()) + + menu = QtWidgets.QMenu() + menu.setTitle('Tab: ') + close_action = QAction("Close") + close_action.triggered.connect(lambda: self.tabCloseRequested.emit(tab)) + + menu.addAction(close_action) + + menu.exec_(event.globalPos()) + event.accept() + + def _tab_right(self, *args): + index = self.currentIndex() + 1 + if index > self.count() - 1: + index = 0 + self.setCurrentIndex(index) + + def _tab_left(self, *args): + index = self.currentIndex() - 1 + if index < 0: + index = self.count() - 1 + self.setCurrentIndex(index) + + +class WorkspaceWidget(QtWidgets.QTabWidget): + """Custom QTabWidget promoted in main_window.ui supporting a custom + TabBar which enables the attachment of custom event actions e.g. right + click context-menus for the tab bar buttons. + + """ + def __init__(self, parent=None): + super().__init__(parent=parent) + self.setTabBar(_WorkspaceTabBar()) + self.tabCloseRequested.connect(self.close_tab_by_index) + + def widget(self, index: int) -> WorkspaceTab: + return super().widget(index) + + def addTab(self, tab: WorkspaceTab, label: str = None): + if label is None: + label = tab.title + super().addTab(tab, label) + tab.sigControllerUpdated.connect(lambda: self._update_name(tab)) + self.setCurrentWidget(tab) + + # Utility functions for referencing Tab widgets by OID + + def get_tab(self, uid: OID): + for i in range(self.count()): + tab = self.widget(i) + if tab.uid == uid: + return tab + + def get_tab_index(self, uid: OID): + for i in range(self.count()): + if uid == self.widget(i).uid: + return i + return -1 + + def close_tab_by_index(self, index: int): + print(f"closing tab at index {index}") + if index == -1: + return + tab = self.widget(index) + self.removeTab(index) + tab.close() + + def close_tab(self, uid: OID): + tab = self.get_tab(uid) + if tab is not None: + tab.close() + index = self.get_tab_index(uid) + if index is not None: + self.removeTab(index) + + def _update_name(self, tab: WorkspaceTab): + index = self.indexOf(tab) + self.setTabText(index, tab.title) diff --git a/dgp/gui/workspaces/__init__.py b/dgp/gui/workspaces/__init__.py new file mode 100644 index 0000000..255dd13 --- /dev/null +++ b/dgp/gui/workspaces/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- + +from dgp.core.controllers.controller_interfaces import VirtualBaseController +from .project import ProjectTab, AirborneProjectController +from .flight import FlightTab, FlightController +from .dataset import DataSetTab, DataSetController + +__all__ = ['ProjectTab', 'FlightTab', 'DataSetTab', 'tab_factory'] + +# Note: Disabled ProjectTab/FlightTab until they are implemented +_tabmap = { + # AirborneProjectController: ProjectTab, + FlightController: FlightTab, + DataSetController: DataSetTab +} + + +def tab_factory(controller: VirtualBaseController): + """Return the workspace tab constructor for the given controller type""" + return _tabmap.get(controller.__class__, None) diff --git a/dgp/gui/workspaces/base.py b/dgp/gui/workspaces/base.py new file mode 100644 index 0000000..c62ad73 --- /dev/null +++ b/dgp/gui/workspaces/base.py @@ -0,0 +1,126 @@ +# -*- coding: utf-8 -*- +import json +import logging +import weakref + +from PyQt5.QtCore import pyqtSignal, Qt +from PyQt5.QtGui import QCloseEvent +from PyQt5.QtWidgets import QWidget + +from dgp.core import OID, StateAction +from dgp.core.controllers.controller_interfaces import VirtualBaseController +from dgp.gui import settings + +__all__ = ['WorkspaceTab', 'SubTab'] +_log = logging.getLogger(__name__) + + +class WorkspaceTab(QWidget): + sigControllerUpdated = pyqtSignal() + + def __init__(self, controller: VirtualBaseController, *args, **kwargs): + super().__init__(*args, **kwargs) + self.setAttribute(Qt.WA_DeleteOnClose, True) + controller.register_observer(self, self.close, StateAction.DELETE) + controller.register_observer(self, self._slot_update, StateAction.UPDATE) + self._controller = weakref.ref(controller) + + @property + def uid(self) -> OID: + return self.controller.uid + + @property + def controller(self) -> VirtualBaseController: + return self._controller() + + @property + def title(self) -> str: + raise NotImplementedError + + @property + def state_key(self) -> str: + return f'Workspace/{self.uid!s}' + + def get_state(self) -> dict: + key = f'Workspace/{self.uid!s}' + return json.loads(settings().value(key, '{}')) + + def save_state(self, state=None) -> None: + """Save/dump the current state of the WorkspaceTab + + This method is called when the tab is closed, and should be used to + retrieve and store the state of the WorkspaceTab and its sub-tabs or + other components. + + Override this method to provide state handling for a WorkspaceTab + """ + _log.debug(f"Saving tab {self.__class__.__name__} ({self.uid}) state") + _jsons = json.dumps(state) + settings().setValue(self.state_key, _jsons) + + def close(self): + # Note: this must be defined in order to provide a bound method for + super().close() + + def closeEvent(self, event: QCloseEvent): + self.save_state() + self.setParent(None) + event.accept() + + def _slot_update(self): + self.sigControllerUpdated.emit() + + def __del__(self): + _log.debug(f"Deleting {self.__class__.__name__}") + + +class SubTab(QWidget): + sigLoaded = pyqtSignal(object) + + def __init__(self, control: VirtualBaseController, *args, **kwargs): + super().__init__(*args, **kwargs) + self.setAttribute(Qt.WA_DeleteOnClose, True) + control.register_observer(self, self.close, StateAction.DELETE) + self._control = weakref.ref(control) + + @property + def control(self): + return self._control() + + def get_state(self): + """Get a representation of the current state of the SubTab + + This method should be overridden by sub-classes of SubTab, in order to + provide a tab/context specific state representation. + + The returned dictionary and all of its values (including nested dicts) + must be serializable by the default Python json serializer. + + The state dictionary returned by this method will be supplied to the + restore_state method when the tab is loaded. + + Returns + ------- + dict + dict of JSON serializable key: value pairs + + """ + return {} + + def restore_state(self, state: dict) -> None: + """Restore the tab to reflect the saved state supplied to this method + + Parameters + ---------- + state : dict + Dictionary containing the state representation for this object. As + produced by :meth:`get_state` + + """ + pass + + def close(self): + super().close() + + def __del__(self): + _log.debug(f"Deleting {self.__class__.__name__}") diff --git a/dgp/gui/workspaces/dataset.py b/dgp/gui/workspaces/dataset.py new file mode 100644 index 0000000..927d336 --- /dev/null +++ b/dgp/gui/workspaces/dataset.py @@ -0,0 +1,177 @@ +# -*- coding: utf-8 -*- +import logging + +from PyQt5 import QtWidgets +from PyQt5.QtCore import Qt +from PyQt5.QtWidgets import QAction, QSizePolicy + +from dgp.core import StateAction, Icon +from dgp.core.controllers.dataset_controller import DataSetController +from dgp.gui.plotting.helpers import LineUpdate +from dgp.gui.plotting.plotters import LineSelectPlot, TransformPlot +from dgp.gui.widgets.channel_control_widgets import ChannelController +from dgp.gui.widgets.data_transform_widget import TransformWidget +from dgp.gui.utils import ThreadedFunction +from .base import WorkspaceTab, SubTab + +_log = logging.getLogger(__name__) + + +class SegmentSelectTab(SubTab): + """Sub-tab displayed within the DataSetTab Workspace""" + def __init__(self, dataset: DataSetController, parent=None): + super().__init__(dataset, parent=parent, flags=Qt.Widget) + + self._plot = LineSelectPlot(rows=2) + self._plot.sigSegmentChanged.connect(self._slot_segment_changed) + + for segment in self.control.children: + group = self._plot.add_segment(segment.get_attr('start'), + segment.get_attr('stop'), + segment.get_attr('label'), + segment.uid, emit=False) + segment.register_observer(group, group.remove, StateAction.DELETE) + + # Create/configure the tab layout/widgets/controls + qhbl_main_layout = QtWidgets.QHBoxLayout(self) + qvbl_plot_layout = QtWidgets.QVBoxLayout() + qhbl_main_layout.addLayout(qvbl_plot_layout) + self.toolbar = self._plot.get_toolbar(self) + qvbl_plot_layout.addWidget(self.toolbar, alignment=Qt.AlignLeft) + qvbl_plot_layout.addWidget(self._plot) + + self.controller = ChannelController(self._plot, parent=self) + qhbl_main_layout.addWidget(self.controller) + + # Toggle control to hide/show data channels dock + qa_channel_toggle = QAction(Icon.PLOT_LINE.icon(), "Data Channels", self) + qa_channel_toggle.setCheckable(True) + qa_channel_toggle.setChecked(True) + qa_channel_toggle.toggled.connect(self.controller.setVisible) + self.toolbar.addAction(qa_channel_toggle) + + # Load data channel selection widget + th = ThreadedFunction(self.control.dataframe, parent=self) + th.result.connect(self._dataframe_loaded) + th.start() + + @property + def control(self) -> DataSetController: + return super().control + + def _dataframe_loaded(self, df): + data_cols = ('gravity', 'long_accel', 'cross_accel', 'beam', 'temp', + 'pressure', 'Etemp', 'gps_week', 'gps_sow', 'lat', 'long', + 'ell_ht') + cols = [df[col] for col in df if col in data_cols] + stat_cols = [df[col] for col in df if col not in data_cols] + self.controller.set_series(*cols) + self.controller.set_binary_series(*stat_cols) + _log.debug("Dataframe loaded for SegmentSelectTab") + self.sigLoaded.emit(self) + + def get_state(self): + """Get the current state of the dataset workspace + + The 'state' of the workspace refers to things which we would like the + ability to restore based on user preferences when they next load the tab + + This may include which channels are plotted, and on which plot/axis. + This may also include the plot configuration, e.g. how many rows/columns + and perhaps visibility settings (grid alpha, line alpha, axis display) + + Returns + ------- + dict + Dictionary of state key/values, possibly nested + + """ + return self.controller.get_state() + + def restore_state(self, state): + self.controller.restore_state(state) + + def _slot_segment_changed(self, update: LineUpdate): + if update.action is StateAction.DELETE: + self.control.remove_child(update.uid, confirm=False) + elif update.action is StateAction.UPDATE: + seg_c = self.control.get_child(update.uid) + if update.start: + seg_c.set_attr('start', update.start) + if update.stop: + seg_c.set_attr('stop', update.stop) + if update.label: + seg_c.set_attr('label', update.label) + elif update.action is StateAction.CREATE: + seg_c = self.control.add_child(update) + seg_grp = self._plot.get_segment(update.uid) + seg_c.register_observer(seg_grp, seg_grp.remove, StateAction.DELETE) + + +class DataTransformTab(SubTab): + def __init__(self, dataset: DataSetController, parent=None): + super().__init__(dataset, parent=parent, flags=Qt.Widget) + layout = QtWidgets.QHBoxLayout(self) + plotter = TransformPlot(rows=1) + plotter.setSizePolicy(QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)) + plot_layout = QtWidgets.QVBoxLayout() + plot_layout.addWidget(plotter.get_toolbar(self), alignment=Qt.AlignRight) + plot_layout.addWidget(plotter) + + transform_control = TransformWidget(self.control, plotter) + + layout.addWidget(transform_control, stretch=0, alignment=Qt.AlignLeft) + layout.addLayout(plot_layout, stretch=5) + + self.sigLoaded.emit(self) + + @property + def control(self) -> DataSetController: + return super().control + + def get_state(self): + pass + + def restore_state(self, state): + pass + + +class DataSetTab(WorkspaceTab): + """Root workspace tab for DataSet controller manipulation""" + + def __init__(self, dataset: DataSetController, parent=None): + super().__init__(controller=dataset, parent=parent, flags=Qt.Widget) + self.ws_settings: dict = self.get_state() + + layout = QtWidgets.QVBoxLayout(self) + self.workspace = QtWidgets.QTabWidget(self) + self.workspace.setTabPosition(QtWidgets.QTabWidget.West) + layout.addWidget(self.workspace) + + self.segment_tab = SegmentSelectTab(dataset, parent=self) + self.segment_tab.sigLoaded.connect(self._tab_loaded) + self.transform_tab = DataTransformTab(dataset, parent=self) + self.transform_tab.sigLoaded.connect(self._tab_loaded) + + self.workspace.addTab(self.segment_tab, "Data") + self.workspace.addTab(self.transform_tab, "Transform") + self.workspace.setCurrentIndex(0) + + @property + def title(self): + return f'{self.controller.get_attr("name")} ' \ + f'[{self.controller.parent().get_attr("name")}]' + + def _tab_loaded(self, tab: SubTab): + """Restore tab state after initial loading is complete""" + state = self.ws_settings.get(tab.__class__.__name__, {}) + tab.restore_state(state) + + def save_state(self, state=None): + """Save current sub-tabs state then accept close event.""" + state = {} + for i in range(self.workspace.count()): + tab: SubTab = self.workspace.widget(i) + state[tab.__class__.__name__] = tab.get_state() + + super().save_state(state=state) diff --git a/dgp/gui/workspaces/flight.py b/dgp/gui/workspaces/flight.py new file mode 100644 index 0000000..93ec11d --- /dev/null +++ b/dgp/gui/workspaces/flight.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +from PyQt5 import QtWidgets +from PyQt5.QtCore import Qt + +from dgp.core.controllers.flight_controller import FlightController +from .base import WorkspaceTab, SubTab + + +class FlightMapTab(SubTab): + def __init__(self, flight: FlightController, parent=None): + super().__init__(flight, parent=parent, flags=Qt.Widget) + + @property + def control(self) -> FlightController: + return super().control + + +class FlightTab(WorkspaceTab): + def __init__(self, flight: FlightController, parent=None): + super().__init__(flight, parent=parent, flags=Qt.Widget) + layout = QtWidgets.QHBoxLayout(self) + self.workspace = QtWidgets.QTabWidget() + self.workspace.addTab(FlightMapTab(flight), "Flight Map") + + layout.addWidget(self.workspace) + + @property + def title(self): + return f'{self.controller.get_attr("name")}' diff --git a/dgp/gui/workspaces/project.py b/dgp/gui/workspaces/project.py new file mode 100644 index 0000000..6eaee10 --- /dev/null +++ b/dgp/gui/workspaces/project.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from PyQt5.QtCore import Qt + +from dgp.core.controllers.project_controllers import AirborneProjectController +from .base import WorkspaceTab + + +class ProjectTab(WorkspaceTab): + def __init__(self, project: AirborneProjectController, parent=None): + super().__init__(parent=parent, flags=Qt.Widget) + self.project = project + + @property + def title(self) -> str: + return f'{self.project.get_attr("name")}' + + @property + def uid(self): + return self.project.uid diff --git a/dgp/lib/eotvos.py b/dgp/lib/eotvos.py deleted file mode 100644 index b6ab49e..0000000 --- a/dgp/lib/eotvos.py +++ /dev/null @@ -1,154 +0,0 @@ -# coding: utf-8 - -import numpy as np -from numpy import array - - -def derivative(y: array, datarate, n=None): - """ - Based on Matlab function 'd' Created by Sandra Martinka, August 2001 - Function to numerically estimate the nth time derivative of y - In both cases of n len(dy) = len(y) - 2 :: One element from each end is lost in calculation - usage dy = derivative(y, n, datarate) - - :param y: Array input - :param datarate: Scalar data sampling rate in Hz - :param n: nth time derivative 1, 2 or None. If None return tuple of first and second order time derivatives - :return: nth time derivative of y - """ - if n is None: - d1 = derivative(y, 1, datarate) - d2 = derivative(y, 2, datarate) - return d1, d2 - - if n == 1: - dy = (y[3:] - y[1:-2]) * (datarate / 2) - return dy - elif n == 2: - dy = ((y[1:-2] - 2 * y[2:-1]) + y[3:]) * (np.power(datarate, 2)) - return dy - else: - return ValueError('Invalid value for parameter n {1 or 2}') - - -# TODO: Need sample input to test -def calc_eotvos(lat: array, lon: array, ht: array, datarate: float, a=None, ecc=None): - """ - Based on Matlab function 'calc_eotvos_full Created by Sandra Preaux, NGS, NOAA August 24, 2009 - - Usage: - - - References: - Harlan 1968, "Eotvos Corrections for Airborne Gravimetry" JGR 73,n14 - - :param lat: Array geodetic latitude in decimal degrees - :param lon: Array longitude in decimal degrees - :param ht: ellipsoidal height in meters - :param datarate: Scalar data rate in Hz - :param a: Scalar semi-major axis of ellipsoid in meters - :param ecc: Scalar eccentricity of ellipsoid - :return: Tuple Eotvos values in mgals - (rdoubledot, angular acceleration of the ref frame, coriolis, centrifugal, centrifugal acceleration of earth) - """ - - # Constants - # TODO: Allow a and ecc to be specified in kwargs - a = 6378137.0 # Default semi-major axis - b = 6356752.3142 # Default semi-minor axis - ecc = (a - b) / a # Eccentricity (eq 5 Harlan) - We = 0.00007292115 # sidereal rotation rate, radians/sec - mps2mgal = 100000 # m/s/s to mgal - - # Convert lat/lon in degrees to radians - rad_lat = np.deg2rad(lat) - rad_lon = np.deg2rad(lon) - - dlat, ddlat = derivative(rad_lat, datarate) - dlon, ddlon = derivative(rad_lon, datarate) - dht, ddht = derivative(ht, datarate) - - # Calculate sin(lat), cos(lat), sin(2*lat), and cos(2*lat) - # Beware MATLAB uses an array index starting with one (1), whereas python uses zero indexed arrays - sin_lat = np.sin(rad_lat[1:-1]) - cos_lat = np.cos(rad_lat[1:-1]) - sin_2lat = np.sin(2 * rad_lat[1:-1]) - cos_2lat = np.cos(2 * rad_lat[1:-1]) - - # Calculate the r' and its derivatives - r_prime = a * (1-ecc * sin_lat * sin_lat) - dr_prime = a * dlat * ecc * sin_2lat - ddr_prime = None - - # Calculate the deviation from the normal and its derivatives - D = np.arctan(ecc * sin_2lat) - dD = 2.0 * dlat * ecc * cos_2lat - ddD = 2.0 * ddlat * ecc * cos_2lat - 4.0 * dlat * dlat * ecc * sin_2lat - - # Calculate r and its derivatives - r = array([ - -r_prime * np.sin(D), - np.zeros(r_prime.shape), - -r_prime * np.cos(D)-ht[1:-1] - ]) - rdot = array([ - -dr_prime * np.sin(D) - r_prime * dD * np.cos(D), - np.zeros(r_prime.shape), - -dr_prime * np.cos(D) + r_prime * dD * np.sin(D) - dht - ]) - # ci=(-ddrp.*sin(D)-2.0.*drp.*dD.*cos(D)-rp.*(ddD.*cos(D)-dD.*dD.*sin(D))); - ci = (-ddr_prime * np.sin(D) - 2.0 * dr_prime * dD * np.cos(D) - r_prime * - (ddD * np.cos(D) - dD * dD * np.sin(D))) - # ck = (-ddrp. * cos(D) + 2.0. * drp. * dD. * sin(D) + rp. * (ddD. * sin(D) + dD. * dD. * cos(D)) - ddht); - ck = (-ddr_prime * np.cos(D) + 2.0 * dr_prime * dD * np.sin(D) + r_prime * - (ddD * np.sin(D) + dD * dD * np.cos(D)) - ddht) - r2dot = array([ - ci, - np.zeros(ci.shape), - ck - ]) - - # Define w and its derivative - w = array([ - (dlon + We) * cos_lat, - -dlat, - -(dlon + We) * sin_lat - ]) - wdot = array([ - dlon * cos_lat - (dlon + We) * dlat * sin_lat, - -ddlat, - (-ddlon * sin_lat - (dlon + We) * dlat * cos_lat) - ]) - w2_x_rdot = np.cross(2.0 * w, rdot) - wdot_x_r = np.cross(wdot, r) - w_x_r = np.cross(w, r) - wxwxr = np.cross(w, w_x_r) - - # Calculate wexwexre (that is the centrifugal acceleration due to the earth - re = array([ - -r_prime * np.sin(D), - np.zeros(r_prime.shape), - -r_prime * np.cos(D) - ]) - we = array([ - We * cos_lat, - np.zeros(sin_lat.shape), - -We * sin_lat - ]) - we_x_re = np.cross(we, re) - wexwexre = np.cross(we, we_x_re) - we_x_r = np.cross(we, r) - wexwexr = np.cross(we, we_x_r) - - # Calculate total acceleration for the aircraft - acc = r2dot + w2_x_rdot + wdot_x_r + wxwxr - - # Eotvos correction is the vertical component of the total acceleration of - # the aircraft - the centrifugal acceleration of the earth, converted to mgal - E = (acc[3,:] - wexwexr[3,:]) * mps2mgal - # TODO: Pad the start/end due to loss during derivative computation - return E - - # Final Return 5-Tuple - eotvos = (r2dot, w2_x_rdot, wdot_x_r, wxwxr, wexwexr) - return eotvos diff --git a/dgp/lib/etc.py b/dgp/lib/etc.py index 64a86c8..219a2a8 100644 --- a/dgp/lib/etc.py +++ b/dgp/lib/etc.py @@ -1,7 +1,248 @@ +# coding: utf-8 + +import uuid +import functools +import collections + import numpy as np + +def align_frames(frame1, frame2, align_to='left', interp_method='time', + interp_only=None, fill=None, item='both'): + # TODO: Is there a more appropriate place for this function? + # TODO: Add ability to specify interpolation method per column. + # TODO: Ensure that dtypes are preserved unless interpolated. + """ + Align and crop two objects + + Parameters + ---------- + frame1: :obj:`DataFrame` or :obj:`Series + Must have a time-like index + frame2: :obj:`DataFrame` or :obj:`Series + Must have a time-like index + align_to: {'left', 'right'}, :obj:`DatetimeIndex` + Index to which data are aligned. + interp_method: {‘linear’, ‘time’, ‘index’, ‘values’, ‘nearest’, ‘zero’, + ‘slinear’, ‘quadratic’, ‘cubic’, ‘barycentric’, ‘krogh’, ‘polynomial’, + ‘spline’, ‘piecewise_polynomial’, ‘from_derivatives’, ‘pchip’, ‘akima’} + - ‘linear’: ignore the index and treat the values as equally spaced. + This is the only method supported on MultiIndexes. + - ‘time’: interpolation works on daily and higher resolution data to + interpolate given length of interval. default + - ‘index’, ‘values’: use the actual numerical values of the index + - ‘nearest’, ‘zero’, ‘slinear’, ‘quadratic’, ‘cubic’, ‘barycentric’, + ‘polynomial’ is passed to scipy.interpolate.interp1d. Both + ‘polynomial’ and ‘spline’ require that you also specify an order + (int), e.g. df.interpolate(method=’polynomial’, order=4). These + use the actual numerical values of the index. + - ‘krogh’, ‘piecewise_polynomial’, ‘spline’, ‘pchip’ and ‘akima’ are + all wrappers around the scipy interpolation methods of similar + names. These use the actual numerical values of the index. + For more information on their behavior, see the scipy + documentation and tutorial documentation + - ‘from_derivatives’ refers to BPoly.from_derivatives which replaces + ‘piecewise_polynomial’ interpolation method in scipy 0.18 + interp_only: set or list + If empty, then all columns except for those indicated in `fill` are + interpolated. Otherwise, only columns listed here are interpolated. + Any column not interpolated and not listed in `fill` is filled with + `ffill`. + fill: dict + Indicate which columns are not to be interpolated. Available fill + methods are {'bfill', 'ffill', None}, or specify a value to fill. + If a column is not present in the dictionary, then it will be + interpolated. + + Returns + ------- + (frame1, frame2) + Aligned and cropped objects + + Raises + ------ + ValueError + When frames do not overlap, and if an incorrect `align_to` argument + is given. + """ + if interp_only is None: + interp_only = [] + + if fill is None: + fill = {} + + def fill_nans(frame): + # TODO: Refactor this function to be less repetitive + if hasattr(frame, 'columns'): + for column in frame.columns: + if interp_only: + if column in interp_only: + frame[column] = frame[column].interpolate(method=interp_method) + elif column in fill.keys(): + if fill[column] in ('bfill', 'ffill'): + frame[column] = frame[column].fillna(method=fill[column]) + else: + # TODO: Validate value + frame[column] = frame[column].fillna(value=fill[column]) + else: + frame[column] = frame[column].fillna(method='ffill') + else: + if column not in fill.keys(): + frame[column] = frame[column].interpolate(method=interp_method) + else: + if fill[column] in ('bfill', 'ffill'): + frame[column] = frame[column].fillna(method=fill[column]) + else: + # TODO: Validate value + frame[column] = frame[column].fillna(value=fill[column]) + else: + frame = frame.interpolate(method=interp_method) + return frame + + if align_to not in ('left', 'right'): + raise ValueError('Invalid value for align_to parameter: {val}' + .format(val=align_to)) + + if frame1.index.min() >= frame2.index.max() \ + or frame1.index.max() <= frame2.index.min(): + raise ValueError('Frames do not overlap') + + if align_to == 'left': + new_index = frame1.index + elif align_to == 'right': + new_index = frame2.index + + left, right = frame1.align(frame2, axis=0, copy=True) + + left = fill_nans(left) + right = fill_nans(right) + + left = left.reindex(new_index).dropna() + right = right.reindex(new_index).dropna() + + # crop frames + if left.index.min() > right.index.min(): + begin = left.index.min() + else: + begin = right.index.min() + + if left.index.max() < right.index.max(): + end = left.index.max() + else: + end = right.index.max() + + left = left.loc[begin:end] + right = right.loc[begin:end] + + if item in ('left', 'l', 'L'): + return left + elif item in ('right', 'r', 'R'): + return right + elif item in ('both', 'b', 'B'): + return left, right + + def interp_nans(y): + # TODO: SettingWithCopyWarning nans = np.isnan(y) x = lambda z: z.nonzero()[0] y[nans] = np.interp(x(nans), x(~nans), y[~nans]) return y + + +def dedup_dict(d): + t = [(k, d[k]) for k in d] + t.sort() + res = {} + + for key, val in t: + if val in res.values(): + continue + res[key] = val + + return res + + +def gen_uuid(prefix: str=''): + """ + Generate a UUID4 String with optional prefix replacing the first len(prefix) + characters of the UUID. + + Parameters + ---------- + prefix : [str] + Optional string prefix to be prepended to the generated UUID + + Returns + ------- + str: + UUID String of length 32 + """ + base_uuid = uuid.uuid4().hex + return '{}{}'.format(prefix, base_uuid[len(prefix):]) + + +def dispatch(type_=None): + """ + @Decorator + Pattern matching dispatcher of optional type constraint. + This works similar to the single dispatch decorator in the Python + functools module, however instead of dispatching based on type only, + this provides a more general dispatcher that can operate based on value + comparison. + + If type_ is specified, the registration function checks to ensure the + registration value is of the appropriate type. Otherwise any value is + permitted (as long as it is Hashable). + + """ + + def dispatch_inner(base_func): + dispatch_map = {} + + @functools.wraps(base_func) + def wrapper(match, *args, **kwargs): + # Strip args[0] off as match - delegated functions don't need it + if match in dispatch_map: + return dispatch_map[match](*args, **kwargs) + + return base_func(match, *args, **kwargs) + + def register(value): + """ + register is a decorator which takes a parameter of the type + specified in the dispatch() decorated method. + + The supplied enum value is then registered within the closures + dispatch_map for execution by the base dispatch function. + + Parameters + ---------- + value : type(type_) + + Returns + ------- + + """ + if not isinstance(value, collections.Hashable): + raise ValueError("Registration value must be Hashable") + if type_ is not None: + if not isinstance(value, type_): + raise TypeError("Invalid dispatch registration type, " + "must be of type {}".format(type_)) + elif isinstance(value, type): + # Don't allow builtin type registrations e.g. float, must be + # an instance of a builtin type (if there is no type_ declared) + raise TypeError("Invalid registration value, must be an " + "instance, not an instance of type.") + + def register_inner(func): + def reg_wrapper(*args, **kwargs): + return func(*args, **kwargs) + dispatch_map[value] = reg_wrapper + return reg_wrapper + return register_inner + + wrapper.register = register + return wrapper + return dispatch_inner diff --git a/dgp/lib/gravity_ingestor.py b/dgp/lib/gravity_ingestor.py index 5769109..f6fe0fd 100644 --- a/dgp/lib/gravity_ingestor.py +++ b/dgp/lib/gravity_ingestor.py @@ -6,10 +6,8 @@ """ -import csv import numpy as np import pandas as pd -import functools import datetime import struct import fnmatch @@ -17,7 +15,7 @@ import re from .time_utils import convert_gps_time -from .etc import interp_nans + def _extract_bits(bitfield, columns=None, as_bool=False): """ @@ -30,7 +28,7 @@ def _extract_bits(bitfield, columns=None, as_bool=False): Parameters ---------- - bitfields : numpy.array or pandas.Series + bitfield : numpy.array or pandas.Series 16, 32, or 64-bit integers columns : list, optional If a list is given, then the column names are given to the resulting @@ -43,6 +41,7 @@ def _extract_bits(bitfield, columns=None, as_bool=False): pandas.DataFrame """ + def _unpack_bits(n): x = np.array(struct.unpack('4B', struct.pack('>I', n)), dtype=np.uint8) return np.flip(np.unpackbits(x), axis=0) @@ -66,65 +65,81 @@ def _unpack_bits(n): else: return df -def read_at1a(path, fill_with_nans=True, interp=False): + +DGS_AT1A_INTERP_FIELDS = {'gravity', 'long_accel', 'cross_accel', 'beam', + 'temp', 'pressure', 'Etemp'} + + +def read_at1a(path, columns=None, fill_with_nans=True, interp=False, + skiprows=None): """ Read and parse gravity data file from DGS AT1A (Airborne) meter. CSV Columns: - gravity, long, cross, beam, temp, status, pressure, Etemp, GPSweek, GPSweekseconds + gravity, long, cross, beam, temp, status, pressure, Etemp, GPSweek, + GPSweekseconds Parameters ---------- path : str Filesystem path to gravity data file + columns: List + Optional List of fields to specify when importing the data, otherwise + defaults are assumed. + This can be used if the data file has fields in an abnormal order fill_with_nans : boolean, default True Fills time gaps with NaNs for all fields interp : boolean, default False Interpolate all NaNs for fields of type numpy.number + skiprows Returns ------- pandas.DataFrame Gravity data indexed by datetime. """ - fields = ['gravity', 'long', 'cross', 'beam', 'temp', 'status', 'pressure', - 'Etemp', 'GPSweek', 'GPSweekseconds'] + columns = columns or ['gravity', 'long_accel', 'cross_accel', 'beam', + 'temp', 'status', 'pressure', 'Etemp', 'gps_week', + 'gps_sow'] - data = [] - df = pd.read_csv(path, header=None, engine='c', na_filter=False) - df.columns = fields + df = pd.read_csv(path, header=None, engine='c', na_filter=False, + skiprows=skiprows) + df.columns = columns # expand status field - status_field_names = ['clamp', 'unclamp', 'gps_sync', 'feedback', 'reserved1', - 'reserved2', 'ad_lock', 'cmd_rcvd', 'nav_mode_1', 'nav_mode_2', - 'plat_comm', 'sens_comm', 'gps_input', 'ad_sat', - 'long_sat', 'cross_sat', 'on_line'] + status_field_names = ['clamp', 'unclamp', 'gps_sync', 'feedback', + 'reserved1', 'reserved2', 'ad_lock', 'cmd_rcvd', + 'nav_mode_1', 'nav_mode_2', 'plat_comm', 'sens_comm', + 'gps_input', 'ad_sat', 'long_sat', 'cross_sat', + 'on_line'] status = _extract_bits(df['status'], columns=status_field_names, - as_bool=True) + as_bool=True) df = pd.concat([df, status], axis=1) df.drop('status', axis=1, inplace=True) # create datetime index - dt_list = [] - for (week, sow) in zip(df['GPSweek'], df['GPSweekseconds']): - dt_list.append(convert_gps_time(week, sow, format='datetime')) - - df.index = pd.DatetimeIndex(dt_list) + dt = convert_gps_time(df['gps_week'], df['gps_sow'], format='datetime') + df.index = pd.DatetimeIndex(dt) if fill_with_nans: - # select rows where time is synced with the GPS NMEA - df = df.loc[df['gps_sync']] + # select rows where time is synced with GPS time + # TODO: Does not work. Can show true when time is not synced. + # df = df.loc[df['gps_sync']] + + # TODO: This is not perfect either. Sometimes sync of sow lags. + df = df.loc[df['gps_week'] > 0] # fill gaps with NaNs interval = '100000U' index = pd.date_range(df.index[0], df.index[-1], freq=interval) df = df.reindex(index) + # TODO: Replace interp_nans with pandas interpolate if interp: numeric = df.select_dtypes(include=[np.number]) - numeric = numeric.apply(interp_nans) + numeric = numeric.interpolate(method='time') # replace columns for col in numeric.columns: @@ -132,26 +147,28 @@ def read_at1a(path, fill_with_nans=True, interp=False): return df -def _parse_ZLS_file_name(filename): - # split by underscore - fname = [e.split('.') for e in filename.split('_')] - # split hour from day and then flatten into one tuple - b = [int(el) for fname_parts in fname for el in fname_parts] +def _parse_zls_file_name(filename): + # split by underscore + fname = [e.split('.') for e in filename.split('_')] + + # split hour from day and then flatten into one tuple + b = [int(el) for fname_parts in fname for el in fname_parts] + + # generate datetime + c = datetime.datetime(b[0], 1, 1) + datetime.timedelta(days=b[2] - 1, + hours=b[1]) + return c - # generate datetime - c = datetime.datetime(b[0], 1, 1) + datetime.timedelta(days=b[2]-1, - hours=b[1]) - return c -def _read_ZLS_format_file(filepath): +def _read_zls_format_file(filepath): col_names = ['line_name', 'year', 'day', 'hour', 'minute', 'second', - 'sensor', 'spring_tension', 'cross_coupling', - 'raw_beam', 'vcc', 'al', 'ax', 've2', 'ax2', 'xacc2', - 'lacc2', 'xacc', 'lacc', 'par_port', 'platform_period'] + 'sensor', 'spring_tension', 'cross_coupling', + 'raw_beam', 'vcc', 'al', 'ax', 've2', 'ax2', 'xacc2', + 'lacc2', 'xacc', 'lacc', 'par_port', 'platform_period'] col_widths = [10, 4, 3, 2, 2, 2, 8, 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 6] + 8, 6] time_columns = ['year', 'day', 'hour', 'minute', 'second'] @@ -162,8 +179,8 @@ def _read_ZLS_format_file(filepath): time_fmt = lambda x: '{:02d}'.format(x) t = df['year'].map(str) + df['day'].map(day_fmt) + \ - df['hour'].map(time_fmt) + df['minute'].map(time_fmt) + \ - df['second'].map(time_fmt) + df['hour'].map(time_fmt) + df['minute'].map(time_fmt) + \ + df['second'].map(time_fmt) # index by datetime df.index = pd.to_datetime(t, format='%Y%j%H%M%S') @@ -171,6 +188,7 @@ def _read_ZLS_format_file(filepath): return df + def read_zls(dirpath, begin_time=None, end_time=None, excludes=['.*']): """ Read and parse gravity data file from ZLS meter. @@ -203,28 +221,28 @@ def read_zls(dirpath, begin_time=None, end_time=None, excludes=['.*']): excludes = r'|'.join([fnmatch.translate(x) for x in excludes]) or r'$.' # list files in directory - files = [_parse_ZLS_file_name(f) for f in os.listdir(dirpath) + files = [_parse_zls_file_name(f) for f in os.listdir(dirpath) if os.path.isfile(os.path.join(dirpath, f)) - if not re.match(excludes, f)] + if not re.match(excludes, f)] # sort files files = sorted(files) # validate begin and end times if begin_time is None and end_time is None: - begin_time = files[0] - end_time = files[-1] + datetime.timedelta(hours=1) + begin_time = files[0] + end_time = files[-1] + datetime.timedelta(hours=1) elif begin_time is None and end_time is not None: - begin_time = files[0] - if end_time < begin_time or end_time > files[-1]: - raise ValueError('end time ({end}) is out of bounds' + begin_time = files[0] + if end_time < begin_time or end_time > files[-1]: + raise ValueError('end time ({end}) is out of bounds' .format(end=end_time)) elif begin_time is not None and end_time is None: - end_time = files[-1] - if begin_time > end_time or begin_time < files[0]: - raise ValueError('begin time ({begin}) is out of bounds' + end_time = files[-1] + if begin_time > end_time or begin_time < files[0]: + raise ValueError('begin time ({begin}) is out of bounds' .format(begin=begin_time)) else: @@ -233,21 +251,22 @@ def read_zls(dirpath, begin_time=None, end_time=None, excludes=['.*']): .format(begin=begin_time, end=end_time)) # filter file list based on begin and end times - files = filter(lambda x: (x >= begin_time and x <= end_time) - or (begin_time >= x and - begin_time <= x + datetime.timedelta(hours=1)) - or (end_time - datetime.timedelta(hours=1) <= x and - end_time >= x), files) + files = filter(lambda x: (begin_time <= x <= end_time) + or (begin_time - datetime.timedelta(hours=1) <= x <= begin_time) + or (end_time - datetime.timedelta(hours=1) <= x <= end_time), files) # convert to ZLS-type file names files = [dt.strftime('%Y_%H.%j') for dt in files] df = pd.DataFrame() for f in files: - frame = _read_ZLS_format_file(os.path.join(dirpath, f)) - df = pd.concat([df, frame]) + frame = _read_zls_format_file(os.path.join(dirpath, f)) + df = pd.concat([df, frame]) df.drop(df.index[df.index < begin_time], inplace=True) df.drop(df.index[df.index > end_time], inplace=True) return df + + +FUNCTION_MAP = {'at1a': read_at1a, 'zls': read_zls} diff --git a/dgp/lib/meterconfig.py b/dgp/lib/meterconfig.py deleted file mode 100644 index 5d5c07d..0000000 --- a/dgp/lib/meterconfig.py +++ /dev/null @@ -1,111 +0,0 @@ -# coding: utf-8 - -import os -import configparser - -""" -Dynamic Gravity Processor (DGP) :: meterconfig.py -License: Apache License V2 - -Overview: -meterconfig.py provides the object framework for dealing with Gravity Meter/Sensor configurations, -each sensor may have different configuration values that may impact the data processing, and these -classes will provide a way to easily store and retrieve those configuration values when a meter -is associated with a particular project/flight. -""" - - -class MeterConfig: - """ - MeterConfig will contain the configuration of a specific gravity meter, giving the - surveyer an easy way to specify the use of different meters on different flight lines. - Initially dealing only with DGS AT1[A/M] meter types, need to add logic to handle other meters later. - """ - def __init__(self, name, meter_type='AT1', **config): - # TODO: Consider other meter types, what to do about different config values etc. - - self.name = name - self.type = meter_type - self.config = {k.lower(): v for k, v in config.items()} - - @staticmethod - def from_ini(path): - raise NotImplementedError - - def __getitem__(self, item): - """Allow getting of configuration values using container type syntax e.g. value = MeterConfig['key']""" - if isinstance(item, slice): - raise NotImplementedError - return self.config.get(item.lower(), None) - - def __setitem__(self, key, value): - """Allow setting of configuration values using container type syntax e.g. MeterConfig['key'] = value""" - try: - value = float(value) - except ValueError: - pass - self.config[key.lower()] = value - - def __len__(self): - return len(self.config) - - -class AT1Meter(MeterConfig): - """ - Subclass of MeterConfig for DGS AT1 Airborne/Marine meter configurations. - Configuration values are cast to float upon - """ - def __init__(self, name, **config): - # Do some pre-processing of fields before passing to super - at1config = self.process_config(self.get_valid_fields(), **config) - super().__init__(name, 'AT1', **at1config) - - @staticmethod - def get_valid_fields(): - # Sensor fields - sensor_fields = ['g0', 'GravCal', 'LongCal', 'CrossCal', 'LongOffset', 'CrossOffset', 'stempgain', - 'Temperature', 'stempoffset', 'pressgain', 'presszero', 'beamgain', 'beamzero', - 'Etempgain', 'Etempzero'] - # Cross coupling Fields - cc_fields = ['vcc', 've', 'al', 'ax', 'monitors'] - - # Platform Fields - platform_fields = ['Cross_Damping', 'Cross_Periode', 'Cross_Lead', 'Cross_Gain', 'Cross_Comp', - 'Cross_Phcomp', 'Cross_sp', 'Long_Damping', 'Long_Periode', 'Long_Lead', 'Long_Gain', - 'Long_Comp', 'Long_Phcomp', 'Long_sp', 'zerolong', 'zerocross', 'CrossSp', 'LongSp'] - - # Create a set with all unique and valid field keys - return set().union(sensor_fields, cc_fields, platform_fields) - - @staticmethod - def process_config(valid_fields, **config): - """Return a config dictionary by filtering out invalid fields, and lower-casing all keys""" - def cast(value): - try: - return float(value) - except ValueError: - return value - - return {k.lower(): cast(v) for k, v in config.items() if k.lower() in map(str.lower, valid_fields)} - - @staticmethod - def from_ini(path): - """ - Read an AT1 Meter Configuration from a meter ini file - :param path: path to meter ini file - :return: instance of AT1Meter with configuration set by ini file - """ - if not os.path.exists(path): - raise OSError("Invalid path to ini.") - config = configparser.ConfigParser(strict=False) - config.read(path) - - sensor_fld = dict(config['Sensor']) - xcoupling_fld = dict(config['crosscouplings']) - platform_fld = dict(config['Platform']) - - name = str.strip(sensor_fld['meter'], '"') - - merge_config = {**sensor_fld, **xcoupling_fld, **platform_fld} - at1config = AT1Meter.process_config(AT1Meter.get_valid_fields(), **merge_config) - return AT1Meter(name, **at1config) diff --git a/dgp/lib/plots.py b/dgp/lib/plots.py new file mode 100644 index 0000000..744f83e --- /dev/null +++ b/dgp/lib/plots.py @@ -0,0 +1,130 @@ +# coding=utf-8 + +""" +plots.py +Library for plotting functions + +""" +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.cm as cm +import matplotlib.dates as mdates +import cartopy.crs as ccrs +from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER +import shapely.geometry as sgeom + + +def read_meterconfig(ini_file, parameter): + f1 = open(ini_file,"r") + for line in f1.readlines(): + line_list = line.split('=') + if line_list[0] == parameter: + value = float(line_list[1]) + f1.close() + return value + + +def timeseries_gravity_diagnostic(df, my_varlist, my_varunits, st, et, plottitle, plotname, **kwargs): + """ + Plots any number of varaibles in a single dataframe, but please adjust the figure size + until I figure out how to do it more better. + Parameters + ---------- + df : pandas.DataFrame + Base DataFrame + my_varlist : list + variables to be plotted (must be same as DataFrame columns) + my_varunits : list + variable units + st : datetime + start time + et : datetime + end time + plottitle : string + plotname : string + + + Returns + ------- + plot : plt.figure + Multi-paneled Timeseries Figure + """ + my_ls = '-' + my_lw = 0.5 + my_marker = None + print('p v') + plt.subplots_adjust(hspace=0.000) + plt.style.use('ggplot') + number_of_subplots = np.shape(my_varlist)[0] + fig = plt.figure(figsize=(8, 6), facecolor='white', dpi=96) + fig.suptitle(plottitle) + for p, v in enumerate(my_varlist): + # for p,v in enumerate(range(number_of_subplots)): + p = p + 1 + print('{} {}'.format(p, v)) + ax = plt.subplot(number_of_subplots, 1, p) + # ax.plot(df.loc[st:et].index, df[v].loc[st:et], color='red', label='ModelOnly', + # ax.plot(df[v].index, df[v].values, color='red', label='ModelOnly', + # ls=my_ls, lw=my_lw, marker=my_marker) + df[v].plot(ax=ax, color='black', label=v, ls=my_ls, lw=my_lw, marker=my_marker) + ax.set_title(v) + ax.set_ylabel(my_varunits[p - 1]) + + ax.xaxis.set_major_formatter(mdates.DateFormatter('%d-%b %H:%M')) + fig.autofmt_xdate() + plt.tight_layout() + fig.subplots_adjust(top=0.89) + # ax.legend(ncol=1, loc='upper right') + # plt.figlegend((ax, ax2), ('ModelOnly', 'Obs'), loc='upper right')#, labelspacing=0.) + # plt.legend(ncol=1, bbox_to_anchor=(1.1, 1.05)) + plt.savefig(plotname) + plt.close() + + +def mapplot_line(pnt_full, pnt, data, var, units='', ptitle='test_map', pfile='test_map'): + """ + This makes a map plot of line segment + :param pnt_full: + :param pnt: + :param data: + :param var: + :param units: + :param ptitle: + :param pfile: + :return: + """ + try: + # box = sgeom.box(minx=160, maxx=210, miny=-83, maxy=-77) # TODO: do this more better + box = sgeom.box(minx=pnt['long'].min() - 3, maxx=pnt['long'].max() + 3, + miny=pnt['lat'].min() - 3, maxy=pnt['lat'].max() + 3) + x0, y0, x1, y1 = box.bounds + if x0 < 0: + myproj = ccrs.SouthPolarStereo(central_longitude=180) + else: + myproj = ccrs.NorthPolarStereo(central_longitude=0) + fig = plt.figure(figsize=(8, 4), facecolor='white', dpi=144) + ax = plt.axes(projection=myproj) + + s1 = plt.scatter(pnt_full['long'], pnt_full['lat'], c='black', s=1, transform=ccrs.PlateCarree()) + s2 = plt.scatter(pnt['long'], pnt['lat'], c=data[var], cmap=cm.Spectral, s=10, transform=ccrs.PlateCarree()) + p1 = ax.plot(pnt['long'][0], pnt['lat'][0], 'k*', markersize=7, transform=ccrs.PlateCarree()) + cb = fig.colorbar(s2, ax=ax, label=units, + orientation='vertical', shrink=0.8, pad=0.05) + cb.ax.set_yticklabels(cb.ax.get_yticklabels(), rotation=0) + cb.ax.tick_params(labelsize=6) + + ax.coastlines(resolution='10m') + ax.xlabels_top = ax.ylabels_right = False + ax.gridlines(draw_labels=False, alpha=0.3, color='grey') + ax.xformatter = LONGITUDE_FORMATTER + ax.yformatter = LATITUDE_FORMATTER + ax.set_extent([x0, x1, y0, y1], ccrs.PlateCarree()) + + plt.tight_layout() + plt.subplots_adjust(top=0.90) + plt.suptitle(ptitle, y=0.98) + plt.savefig(pfile, bbox_inches='tight') # save the figure to file + plt.close() + except IndexError: + print("Couldn't make Map Plot.") + return diff --git a/dgp/lib/plotter.py b/dgp/lib/plotter.py deleted file mode 100644 index 3a4accd..0000000 --- a/dgp/lib/plotter.py +++ /dev/null @@ -1,237 +0,0 @@ -# coding: utf-8 - -""" -Class to handle Matplotlib plotting of data to be displayed in Qt GUI -""" - -import logging -from collections import namedtuple -from typing import List, Tuple - -from PyQt5 import QtWidgets -from PyQt5.QtWidgets import QSizePolicy -from matplotlib.backends.backend_qt5agg import (FigureCanvasQTAgg as FigureCanvas, - NavigationToolbar2QT as NavigationToolbar) -from matplotlib.figure import Figure -from matplotlib.axes import Axes -from matplotlib.dates import DateFormatter -from matplotlib.backend_bases import MouseEvent -from matplotlib.patches import Rectangle - -import numpy as np - - -class BasePlottingCanvas(FigureCanvas): - """ - BasePlottingCanvas sets up the basic Qt Canvas parameters, and is designed - to be subclassed for different plot types. - """ - def __init__(self, parent=None, width=8, height=4, dpi=100): - self.log = logging.getLogger(__name__) - self.parent = parent - fig = Figure(figsize=(width, height), dpi=dpi, tight_layout=True) - FigureCanvas.__init__(self, fig) - - self.setParent(parent) - FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Expanding) - FigureCanvas.updateGeometry(self) - - self._axes = [] - - self.figure.canvas.mpl_connect('button_press_event', self.onclick) - self.figure.canvas.mpl_connect('button_release_event', self.onrelease) - self.figure.canvas.mpl_connect('motion_notify_event', self.onmotion) - - def generate_subplots(self, rows: int) -> None: - """Generate vertically stacked subplots for comparing data""" - # TODO: Experimenting with generating multiple plots, work with Chris on this class - # def set_x_formatter(axes): - # print("Xlimit changed") - # axes.get_xaxis().set_major_formatter(DateFormatter('%H:%M:%S')) - - # Clear any current axes first - self._axes = [] - for i in range(rows): - if i == 0: - sp = self.figure.add_subplot(rows, 1, i+1) # type: Axes - else: # Share x-axis with plot 0 - sp = self.figure.add_subplot(rows, 1, i + 1, sharex=self._axes[0]) # type: Axes - - sp.grid(True) - sp.name = 'Axes {}'.format(i) - # sp.callbacks.connect('xlim_changed', set_x_formatter) - self._axes.append(sp) - i += 1 - - self.compute_initial_figure() - - def add_subplot(self): - pass - - def compute_initial_figure(self): - pass - - def clear(self): - pass - - def onclick(self, event: MouseEvent): - pass - - def onrelease(self, event: MouseEvent): - pass - - def onmotion(self, event: MouseEvent): - pass - - def __len__(self): - return len(self._axes) - - -ClickInfo = namedtuple('ClickInfo', ['partners', 'x0', 'xpos', 'ypos']) - - -class LineGrabPlot(BasePlottingCanvas): - """ LineGrabPlot implements BasePlottingCanvas and provides an onclick method to select flight line segments.""" - def __init__(self, n=1, parent=None, title=None): - BasePlottingCanvas.__init__(self, parent=parent) - self.rects = [] - self.zooming = False - self.panning = False - self.clicked = None # type: ClickInfo - self.generate_subplots(n) - self.plotted = False - if title: - self.figure.suptitle(title, y=1) - - def clear(self): - for ax in self._axes: # type: Axes - ax.cla() - ax.grid(True) - ax.callbacks.connect('xlim_changed', self._on_xlim_changed) - self.draw() - - def onclick(self, event: MouseEvent): - if self.zooming or self.panning: # Don't do anything when zooming is enabled - return - - # Check that the click event happened within one of the subplot axes - if event.inaxes not in self._axes: - return - - caxes = event.inaxes # type: Axes - other_axes = [ax for ax in self._axes if ax != caxes] - # print("Current axes: {}\nOther axes obj: {}".format(repr(caxes), other_axes)) - - for partners in self.rects: - patch = partners[0]['rect'] - if patch.get_x() <= event.xdata <= patch.get_x() + patch.get_width(): - # Then we clicked an existing rectangle - print("Clicked on existing rectangle {}, with partners: {}".format(repr(patch), partners[1:])) - x0, _ = patch.xy - self.clicked = ClickInfo(partners, x0, event.xdata, event.ydata) - - for attrs in partners: - rect = attrs['rect'] - rect.set_animated(True) - r_canvas = rect.figure.canvas - r_axes = rect.axes # type: Axes - r_canvas.draw() - attrs['bg'] = r_canvas.copy_from_bbox(r_axes.bbox) - return - - # else: Create a new rectangle on all axes - print("Creating new rectangles") - ylim = caxes.get_ylim() # type: Tuple - xlim = caxes.get_xlim() # type: Tuple - width = (xlim[1] - xlim[0]) * np.float64(0.01) - # Get the bottom left corner of the rectangle which will be centered at the mouse click - x0 = event.xdata - width/2 - y0 = ylim[0] - height = ylim[1] - ylim[0] - c_rect = Rectangle((x0, y0), width, height*2, alpha=0.1) - - print("Adding rectangle to c_axes: {}".format(caxes)) - caxes.add_patch(c_rect) - - partners = [{'rect': c_rect, 'bg': None}] - for ax in other_axes: - - print("Adding rectangle to axes: {}".format(ax)) - x0 = event.xdata - width/2 - ylim = ax.get_ylim() - y0 = ylim[0] - height = ylim[1] - ylim[0] - a_rect = Rectangle((x0, y0), width, height*2, alpha=0.1) - ax.add_patch(a_rect) - partners.append({'rect': a_rect, 'bg': None}) - - self.rects.append(partners) - self.figure.canvas.draw() - self.draw() - return - - def toggle_zoom(self): - if self.panning: - self.panning = False - self.zooming = not self.zooming - print("Toggling zoom, state: {}".format(self.zooming)) - - def toggle_pan(self): - if self.zooming: - self.zooming = False - self.panning = not self.panning - print("Toggling pan") - - def onmotion(self, event: MouseEvent): - if event.inaxes not in self._axes: - return - if self.clicked is not None: - partners, x0, xclick, yclick = self.clicked - dx = event.xdata - xclick - new_x = x0 + dx - for attrs in partners: - rect = attrs['rect'] # type: Rectangle - rect.set_x(new_x) - canvas = rect.figure.canvas - axes = rect.axes # type: Axes - canvas.restore_region(attrs['bg']) - axes.draw_artist(rect) - canvas.blit(axes.bbox) - - def onrelease(self, event: MouseEvent): - if self.clicked is None: - return # Nothing Selected - partners = self.clicked.partners - for attrs in partners: - attrs['rect'].set_animated(False) - attrs['bg'] = None - self.clicked = None - self.draw() - - def plot(self, ax: Axes, xdata, ydata, **kwargs): - ax.plot(xdata, ydata, **kwargs) - ax.legend() - - @staticmethod - def _on_xlim_changed(ax: Axes): - ax.get_xaxis().set_major_formatter(DateFormatter('%H:%M:%S')) - - def get_toolbar(self, parent=None) -> QtWidgets.QToolBar: - """ - Get a Matplotlib Toolbar for the current plot instance, and set toolbar actions (pan/zoom) specific to this plot. - Parameters - ---------- - [parent] - Optional Qt Parent for this object - - Returns - ------- - QtWidgets.QToolBar : Matplotlib Qt Toolbar used to control this plot instance - """ - toolbar = NavigationToolbar(self, parent=parent) - toolbar.actions()[4].triggered.connect(self.toggle_pan) - toolbar.actions()[5].triggered.connect(self.toggle_zoom) - return toolbar - - def __getitem__(self, item): - return self._axes[item] diff --git a/dgp/lib/project.py b/dgp/lib/project.py deleted file mode 100644 index faa3fe2..0000000 --- a/dgp/lib/project.py +++ /dev/null @@ -1,437 +0,0 @@ -# coding: utf-8 - -import os -import uuid -import pickle -import pathlib -import logging -from typing import Tuple - -from pandas import HDFStore -from PyQt5 import QtCore -from PyQt5.QtGui import QStandardItemModel, QStandardItem, QIcon -from PyQt5.QtCore import QModelIndex - - -from dgp.lib.meterconfig import MeterConfig, AT1Meter -from dgp.lib.types import Location, StillReading, FlightLine, DataPacket - -""" -Dynamic Gravity Processor (DGP) :: project.py -License: Apache License V2 - -Overview: -project.py provides the object framework for setting up a gravity processing project, which may include project specific -configurations and settings, project specific files and imports, and the ability to segment a project into individual -flights and flight lines. - -Workflow: - User creates new project - enters project name, description, and location to save project. - - User can additionaly define survey parameters specific to the project - - User can then add a Gravity Meter configuration to the project - - User then creates new flights each day a flight is flown, flight parameters are defined - - Data files are imported into project and associated with a flight - - Upon import the file will be converted to pandas DataFrame then written out to the - project directory as HDF5. - - - User selects between flights in GUI to view in plot, data is pulled from the Flight object - -""" - - -def can_pickle(attribute): - """Helper function used by __getstate__ to determine if an attribute should be pickled.""" - # TODO: As necessary change this to check against a list of un-pickleable types - if isinstance(attribute, logging.Logger): - return False - return True - - -class GravityProject: - """ - GravityProject will be the base class defining common values for both airborne - and marine gravity survey projects. - """ - def __init__(self, path: pathlib.Path, name: str="Untitled Project", description: str=None): - """ - :param path: Project directory path - where all project files will be stored - :param name: Project name - :param description: Project description - """ - self.log = logging.getLogger(__name__) - if isinstance(path, pathlib.Path): - self.projectdir = path # type: pathlib.Path - else: - self.projectdir = pathlib.Path(path) - if not self.projectdir.exists(): - raise FileNotFoundError - - if not self.projectdir.is_dir(): - raise NotADirectoryError - - self.name = name - self.description = description - - # self.hdf_path = os.path.join(self.projectdir, 'prjdata.h5') - self.hdf_path = self.projectdir.joinpath('prjdata.h5') - - # Store MeterConfig objects in dictionary keyed by the meter name - self.sensors = {} - - self.log.debug("Gravity Project Initialized") - - def load_data(self, uid: str, prefix: str): - pass - - def add_meter(self, meter: MeterConfig) -> MeterConfig: - """Add an existing MeterConfig class to the dictionary of available meters""" - if isinstance(meter, MeterConfig): - self.sensors[meter.name] = meter - return self.sensors[meter.name] - else: - raise ValueError("meter parameter is not an instance of MeterConfig") - - def get_meter(self, name) -> MeterConfig: - return self.sensors.get(name, None) - - def import_meter(self, path: pathlib.Path): - """Import a meter configuration from an ini file and add it to the sensors dict""" - # TODO: Way to construct different meter types (other than AT1 meter) dynamically - if path.exists(): - try: - meter = AT1Meter.from_ini(path) - self.sensors[meter.name] = meter - except ValueError: - raise ValueError("Meter .ini file could not be imported, check format.") - else: - return self.sensors[meter.name] - else: - raise OSError("Path {} doesn't exist.".format(path)) - - @property - def meters(self): - """Return list of meter names assigned to this project.""" - if not self.sensors: - return [] - else: - return list(self.sensors.keys()) - - def save(self, path: pathlib.Path=None): - """ - Export the project class as a pickled python object - :param path: Path to save file - :return: - """ - if path is None: - path = self.projectdir.joinpath('{}.d2p'.format(self.name)) - if not isinstance(path, pathlib.Path): - path = pathlib.Path(path) - with path.open('wb') as f: - pickle.dump(self, f) - return True - - def generate_model(self): - pass - - @staticmethod - def load(path): - """Use python pickling to load project""" - if not isinstance(path, pathlib.Path): - path = pathlib.Path(path) - if not path.exists(): - raise FileNotFoundError - - with path.open('rb') as pickled: - project = pickle.load(pickled) - # Override whatever the project dir was with the directory where it was opened - project.projectdir = path.parent - return project - - def __iter__(self): - pass - - def __getstate__(self): - """Prune any non-pickleable objects from the class __dict__""" - return {k: v for k, v in self.__dict__.items() if can_pickle(v)} - - def __setstate__(self, state): - """Re-initialize a logger upon un-pickling""" - self.__dict__ = state - self.log = logging.getLogger(__name__) - - -class Flight: - """ - Define a Flight class used to record and associate data with an entire survey flight (takeoff -> landing) - This class is iterable, yielding the flightlines named tuple objects from its lines dictionary - """ - def __init__(self, parent: GravityProject, name: str, meter: MeterConfig=None, **kwargs): - """ - The Flight object represents a single literal survey flight, and accepts various parameters related to the - flight. - Currently a single GPS data and Gravity data file each may be assigned to a flight. In the future this - functionality must be expanded to handle more complex cases requiring the input of multiple data files. - At present a single gravity meter may be assigned to the flight. In future, as/if the project requires this - may be expanded to allow for a second meter to be optionally assigned. - :param parent: GravityProject - the Parent project item of this meter, used to retrieve linked data. - :param name: Str - a human readable reference name for the flight - :param meter: MeterConfig - a Gravity meter configuration object that will be associated with this flight. - :param kwargs: Optional key-word arguments may be passed to assign other attributes, e.g. date within the flight - date: a Datetime object specifying the date of the flight - uuid: a UUID string to assign to this flight (otherwise a random UUID is generated upon creation) - """ - # If uuid is passed use the value else assign new uuid - # the letter 'f' is prepended to the uuid to ensure that we have a natural python name - # as python variables cannot start with a number (this takes care of warning when storing data in pytables) - self.parent = parent - self.name = name - self.uid = kwargs.get('uuid', self.generate_uuid()) - self.meter = meter - if 'date' in kwargs: - self.date = kwargs['date'] - - self.log = logging.getLogger(__name__) - - # These private attributes will hold a file reference string used to retrieve data from hdf5 store. - self._gpsdata = None # type: str - self._gravdata = None # type: str - - # Known Absolute Site Reading/Location - self.tie_value = None - self.tie_location = None - - self.pre_still_reading = None - self.post_still_reading = None - - self.flight_timeshift = 0 - - # Flight data files - self.data = {} - - # Flight lines keyed by UUID - self.lines = {} - - @property - def gps(self): - return self.parent.load_data(self._gpsdata, 'gps') - - @gps.setter - def gps(self, value): - if self._gpsdata: - self.log.warning('GPS Data File already exists, overwriting with new value.') - self._gpsdata = value - - @property - def gps_file(self): - try: - return self.parent.data_map[self._gpsdata], self._gpsdata - except KeyError: - return None, None - - @property - def gravity(self): - self.log.warning("Loading gravity data from file. (Expensive Operation)") - return self.parent.load_data(self._gravdata, 'gravity') - - @gravity.setter - def gravity(self, value): - if self._gravdata: - self.log.warning('Gravity Data File already exists, overwriting with new value.') - self._gravdata = value - - @property - def gravity_file(self): - try: - return self.parent.data_map[self._gravdata], self._gravdata - except KeyError: - return None, None - - def get_channel_data(self, channel): - return self.gravity[channel] - - def set_gravity_tie(self, gravity: float, loc: Location): - self.tie_value = gravity - self.tie_location = loc - - def pre_still_reading(self, gravity: float, loc: Location, time: float): - self.pre_still_reading = StillReading(gravity, loc, time) - - def post_still_reading(self, gravity: float, loc: Location, time: float): - self.post_still_reading = StillReading(gravity, loc, time) - - def add_line(self, start: float, end: float): - """Add a flight line to the flight by start/stop index and sequence number""" - uid = uuid.uuid4().hex - line = FlightLine(uid, len(self.lines), None, start, end) - self.lines[uid] = line - return line - - @staticmethod - def generate_uuid(): - return 'f{}'.format(uuid.uuid4().hex[1:]) - - def __iter__(self): - """Iterate over flight lines in the Flight instance""" - for k, line in self.lines.items(): - yield line - - def __len__(self): - return len(self.lines) - - def __repr__(self): - return "Flight({parent}, {name}, {meter})".format(parent=self.parent, name=self.name, meter=self.meter) - - def __str__(self): - if self.meter is not None: - mname = self.meter.name - else: - mname = '' - desc = """Flight: {name}\n -UID: {uid} -Meter: {meter} -# Lines: {lines} -Data Files: - """.format(name=self.name, uid=self.uid, meter=mname, lines=len(self)) - return desc - - def __getstate__(self): - return {k: v for k, v in self.__dict__.items() if can_pickle(v)} - - def __setstate__(self, state): - self.__dict__ = state - self.log = logging.getLogger(__name__) - - -class AirborneProject(GravityProject): - """ - A subclass of the base GravityProject, AirborneProject will define an Airborne survey - project with parameters unique to airborne operations, and defining flight lines etc. - - This class is iterable, yielding the Flight objects contained within its flights dictionary - """ - def __init__(self, path, name, description=None): - super().__init__(path, name, description) - - # Dictionary of Flight objects keyed by the flight uuid - self.flights = {} - self.active = None # type: Flight - self.log.debug("Airborne project initialized") - self.data_map = {} - - def set_active(self, flight_id): - flight = self.get_flight(flight_id) - self.active = flight - - def load_data(self, uid: str, prefix: str): - """ - Load data from a specified group (prefix) - gps or gravity, from the projects HDF5 store. - :param str uid: Datafile Unique Identifier - :param str prefix: Data type prefix [gps or gravity] - :return: - """ - with HDFStore(str(self.hdf_path)) as store: - try: - data = store.get('{}/{}'.format(prefix, uid)) - except KeyError: - return None - else: - return data - - def add_data(self, packet: DataPacket): - """ - Import a DataFrame into the project - :param packet: DataPacket custom class containing file path, dataframe, data type and flight association - :return: Void - """ - self.log.debug("Ingesting data and exporting to hdf5 store") - - file_uid = 'f' + uuid.uuid4().hex[1:] # Fixes NaturalNameWarning by ensuring first char is letter ('f'). - - with HDFStore(str(self.hdf_path)) as store: - # Separate data into groups by data type (GPS & Gravity Data) - # format: 'table' pytables format enables searching/appending, fixed is more performant. - store.put('{}/{}'.format(packet.data_type, file_uid), packet.data, format='fixed', data_columns=True) - # Store a reference to the original file path - self.data_map[file_uid] = packet.path - try: - flight = self.flights[packet.flight.uid] - if packet.data_type == 'gravity': - flight.gravity = file_uid - elif packet.data_type == 'gps': - flight.gps = file_uid - except KeyError: - return False - - def add_flight(self, flight: Flight): - self.flights[flight.uid] = flight - - def get_flight(self, flight_id): - flt = self.flights.get(flight_id, None) - self.log.debug("Found flight {}:{}".format(flt.name, flt.uid)) - return flt - - def generate_model(self) -> Tuple[QStandardItemModel, QModelIndex]: - """Generate a Qt Model based on the project structure.""" - model = QStandardItemModel() - root = model.invisibleRootItem() - - # TODO: Add these icon resources to library or something so they are not loaded every time - dgs_ico = QIcon('ui/assets/DGSIcon.xpm') - flt_ico = QIcon('ui/assets/flight_icon.png') - - prj_header = QStandardItem(dgs_ico, "{name}: {path}".format(name=self.name, path=self.projectdir)) - prj_header.setEditable(False) - fli_header = QStandardItem(flt_ico, "Flights") - fli_header.setEditable(False) - # TODO: Add a human readable identifier to flights - first_flight = None - for uid, flight in self.flights.items(): - fli_item = QStandardItem(flt_ico, "Flight: {}".format(flight.name)) - if first_flight is None: - first_flight = fli_item - fli_item.setToolTip("UUID: {}".format(uid)) - fli_item.setEditable(False) - fli_item.setData(flight, QtCore.Qt.UserRole) - - gps_path, gps_uid = flight.gps_file - gps = QStandardItem("GPS: {}".format(gps_uid)) - gps.setToolTip("File Path: {}".format(gps_path)) - gps.setEditable(False) - gps.setData(gps_uid) # For future use - - grav_path, grav_uid = flight.gravity_file - if grav_path is not None: - _, grav_fname = os.path.split(grav_path) - else: - grav_fname = '' - grav = QStandardItem("Gravity: {}".format(grav_fname)) - grav.setToolTip("File Path: {}".format(grav_path)) - grav.setEditable(False) - grav.setData(grav_uid) # For future use - - fli_item.appendRow(gps) - fli_item.appendRow(grav) - - for line in flight: - line_item = QStandardItem("Line {}:{}".format(line.start, line.end)) - line_item.setEditable(False) - fli_item.appendRow(line_item) - fli_header.appendRow(fli_item) - prj_header.appendRow(fli_header) - - root.appendRow(prj_header) - self.log.debug("Tree Model generated") - first_index = model.indexFromItem(first_flight) - return model, first_index - - def __iter__(self): - for uid, flight in self.flights.items(): - yield flight - - def __len__(self): - return len(self.flights) - - def __str__(self): - return "Project: {name}\nPath: {path}\nDescription: {desc}".format(name=self.name, - path=self.projectdir, - desc=self.description) diff --git a/dgp/lib/time_utils.py b/dgp/lib/time_utils.py index 0946db1..ac8db7d 100644 --- a/dgp/lib/time_utils.py +++ b/dgp/lib/time_utils.py @@ -1,10 +1,31 @@ -import datetime +from datetime import datetime, timedelta import pandas as pd import collections +from functools import lru_cache + +leap_second_table = [(datetime(1980, 1, 1), datetime(1981, 7, 1)), + (datetime(1981, 7, 1), datetime(1982, 7, 1)), + (datetime(1982, 7, 1), datetime(1983, 7, 1)), + (datetime(1983, 7, 1), datetime(1985, 7, 1)), + (datetime(1985, 7, 1), datetime(1988, 1, 1)), + (datetime(1988, 1, 1), datetime(1990, 1, 1)), + (datetime(1990, 1, 1), datetime(1991, 1, 1)), + (datetime(1991, 1, 1), datetime(1992, 7, 1)), + (datetime(1992, 7, 1), datetime(1993, 7, 1)), + (datetime(1993, 7, 1), datetime(1994, 7, 1)), + (datetime(1994, 7, 1), datetime(1996, 1, 1)), + (datetime(1996, 1, 1), datetime(1997, 7, 1)), + (datetime(1997, 7, 1), datetime(1999, 1, 1)), + (datetime(1999, 1, 1), datetime(2006, 1, 1)), + (datetime(2006, 1, 1), datetime(2009, 1, 1)), + (datetime(2009, 1, 1), datetime(2012, 7, 1)), + (datetime(2012, 7, 1), datetime(2015, 7, 1)), + (datetime(2015, 7, 1), datetime(2017, 1, 1))] + def datetime_to_sow(dt): def _to_sow(dt): - delta = dt - datetime.datetime(1980, 1, 6) + delta = dt - datetime(1980, 1, 6) week = delta.days // 7 sow = (delta.days % 7) * 86400. + delta.seconds + delta.microseconds * 1e-6 return week, sow @@ -17,23 +38,39 @@ def _to_sow(dt): else: return _to_sow(dt) + def convert_gps_time(gpsweek, gpsweekseconds, format='unix'): """ - convert_gps_time :: (String -> String) -> Float + Converts a GPS time format (weeks + seconds since 6 Jan 1980) to a UNIX + timestamp (seconds since 1 Jan 1970) without correcting for UTC leap + seconds. - Converts a GPS time format (weeks + seconds since 6 Jan 1980) to a UNIX timestamp - (seconds since 1 Jan 1970) without correcting for UTC leap seconds. + Static values gps_delta and gpsweek_cf are defined by the below functions + (optimization) gps_delta is the time difference (in seconds) between UNIX + time and GPS time. - Static values gps_delta and gpsweek_cf are defined by the below functions (optimization) - gps_delta is the time difference (in seconds) between UNIX time and GPS time. gps_delta = (dt.datetime(1980, 1, 6) - dt.datetime(1970, 1, 1)).total_seconds() gpsweek_cf is the coefficient to convert weeks to seconds gpsweek_cf = 7 * 24 * 60 * 60 # 604800 - :param gpsweek: Number of weeks since beginning of GPS time (1980-01-06 00:00:00) - :param gpsweekseconds: Number of seconds since the GPS week parameter - :return: (float) unix timestamp (number of seconds since 1970-01-01 00:00:00) + Parameters + ---------- + gpsweek : int + Number of weeks since beginning of GPS time (1980-01-06 00:00:00) + + gpsweekseconds : float + Number of seconds since the GPS week parameter + + format : {'unix', 'datetime'} + Format of returned value + + Returns + ------- + float or :obj:`datetime` + UNIX timestamp (number of seconds since 1970-01-01 00:00:00) without + leapseconds subtracted if 'unix' is specified for format. + Otherwise, a :obj:`datetime` is returned. """ # GPS time begins 1980 Jan 6 00:00, UNIX time begins 1970 Jan 1 00:00 gps_delta = 315964800.0 @@ -48,46 +85,57 @@ def convert_gps_time(gpsweek, gpsweekseconds, format='unix'): if format == 'unix': return timestamp + elif format == 'datetime': - return datetime.datetime(1970, 1, 1) + pd.to_timedelta(timestamp, unit='s') + return datetime(1970, 1, 1) + pd.to_timedelta(timestamp * 1e9) def leap_seconds(**kwargs): """ - leapseconds :: Variable type -> Integer + Look-up for the number of leap seconds for a given date - Look-up for the number of leapseconds for a given date. + Parameters + ---------- + week : int, optional + Number of weeks since beginning of GPS time (1980-01-06 00:00:00) - :param week: Number of weeks since beginning of GPS time (1980-01-06 00:00:00) - :param seconds: If week is specified, then seconds of week since the - beginning of Sunday of that week, otherwise, Unix time in - seconds since January 1, 1970 UTC. - :param date: Date either in the format MM-DD-YYYY or MM/DD/YYYY - :param datetime: datetime-like - :return: (integer) Number of accumulated leap seconds as of the given date. - """ + seconds : float, optional + If week is specified, then seconds of week since the beginning of + Sunday of that week, otherwise, Unix time in seconds since + January 1, 1970 UTC. + + date : :obj:`str`, optional + Date string in the format specified by dateformat. + + dateformat : :obj:`str`, optional + Format of the date string if date is used. Default: '%m-%d-%Y' + .. _Format codes: + https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior + + datetime : :obj:`datetime` + + Returns + ------- + int + Number of accumulated leap seconds as of the given date. + """ if 'seconds' in kwargs: - # GPS week + seconds of week if 'week' in kwargs: - dt = (datetime.datetime(1980, 1, 6) + - datetime.timedelta(weeks=kwargs['week']) + - datetime.timedelta(seconds=kwargs['seconds'])) + dt = (datetime(1980, 1, 6) + + timedelta(weeks=kwargs['week']) + + timedelta(seconds=kwargs['seconds'])) else: - # TO DO: Check for value out of bounds? - # week not specified, assume Unix time in seconds - dt = (datetime.datetime(1970, 1, 1) + - datetime.timedelta(seconds=kwargs['seconds'])) + # TODO Check for value out of bounds? + dt = (datetime(1970, 1, 1) + + timedelta(seconds=kwargs['seconds'])) elif 'date' in kwargs: - d = kwargs['date'].split('-') - if len(d) != 3: - d = kwargs['date'].split('/') - if len(d) != 3: - raise ValueError('Date not correctly formatted. ' - 'Expect MM-DD-YYYY or MM/DD/YYYY. Got: {date}' - .format(date=kwargs['date'])) + if 'dateformat' in kwargs: + fmt = kwargs['dateformat'] + else: + fmt = '%m-%d-%Y' - dt = datetime.datetime(int(d[2]), int(d[0]), int(d[1])) + dt = datetime.strptime(kwargs['date'], fmt) elif 'datetime' in kwargs: dt = kwargs['datetime'] @@ -97,41 +145,26 @@ def leap_seconds(**kwargs): 'number and seconds of week, Unix time in seconds ' 'since January 1, 1970 UTC, or datetime.') - ls_table = [(1980,1,1,1981,7,1),\ - (1981,7,1,1982,7,1),\ - (1982,7,1,1983,7,1),\ - (1983,7,1,1985,7,1),\ - (1985,7,1,1988,1,1),\ - (1988,1,1,1990,1,1),\ - (1990,1,1,1991,1,1),\ - (1991,1,1,1992,7,1),\ - (1992,7,1,1993,7,1),\ - (1993,7,1,1994,7,1),\ - (1994,7,1,1996,1,1),\ - (1996,1,1,1997,7,1),\ - (1997,7,1,1999,1,1),\ - (1999,1,1,2006,1,1),\ - (2006,1,1,2009,1,1),\ - (2009,1,1,2012,7,1),\ - (2012,7,1,2015,7,1),\ - (2015,7,1,2017,1,1)] - - leap_seconds = 0 - for entry in ls_table: - if (dt >= datetime.datetime(entry[0], entry[1], entry[2]) and - dt < datetime.datetime(entry[3],entry[4],entry[5])): - break + return _get_leap_seconds(dt) + +@lru_cache(maxsize=1000) +def _get_leap_seconds(dt): + ls = 0 + for entry in leap_second_table: + if entry[0] <= dt < entry[1]: + break else: - leap_seconds = leap_seconds + 1 + ls += 1 + return ls - return leap_seconds def datenum_to_datetime(timestamp): - if isinstance(timestamp, pd.Series): - return (timestamp.astype(int).map(datetime.datetime.fromordinal) + - pd.to_timedelta(timestamp % 1, unit='D') - - pd.to_timedelta('366 days')) - else: - return (datetime.datetime.fromordinal(int(timestamp) - 366) + - datetime.timedelta(days=timestamp % 1)) + raise NotImplementedError + # if isinstance(timestamp, pd.Series): + # return (timestamp.astype(int).map(datetime.fromordinal) + + # pd.to_timedelta(timestamp % 1, unit='D') - + # pd.to_timedelta('366 days')) + # else: + # return (datetime.fromordinal(int(timestamp) - 366) + + # timedelta(days=timestamp % 1)) diff --git a/dgp/lib/timesync.py b/dgp/lib/timesync.py new file mode 100644 index 0000000..b87ffb8 --- /dev/null +++ b/dgp/lib/timesync.py @@ -0,0 +1,213 @@ +# coding=utf-8 + +import numpy as np +from pandas import DataFrame +import pandas as pd +from pandas.tseries.frequencies import to_offset +from pandas.tseries.offsets import DateOffset +from scipy.interpolate import interp1d +import warnings + + +def interpolate_1d_vector(vector: np.array, factor: int): + """ + Interpolate i.e. up sample a give 1D vector by interpolation factor + + Parameters + ---------- + vector: np.array + 1D Data Vector + factor: int + Interpolation factor + + Returns + ------- + np.array: + 1D Array interpolated by 'factor' + + """ + x = np.arange(np.size(vector)) + y = vector + f = interp1d(x, y) + # f = np.interp(x, x, y) + + x_extended_by_factor = np.linspace(x[0], x[-1], np.size(x) * factor) + y_interpolated = np.zeros(np.size(x_extended_by_factor)) + + i = 0 + for x in x_extended_by_factor: + y_interpolated[i] = f(x) + i += 1 + + return y_interpolated + + +def find_time_delay(s1, s2, datarate=1, resolution: bool=False): + """ + Finds the time shift or delay between two signals + If s1 is advanced to s2, then the delay is positive. + + Parameters + ---------- + s1: array-like + s2: array-like + datarate: int, optional + Input data sample rate in Hz. If objects with time-like indexes are + given in the first two arguments, then this argument is ignored. + resolution: bool + If False use data without oversampling + If True, calculates time delay with 10* oversampling + + Returns + ------- + Scalar: + Time shift between s1 and s2. If datarate is not specified, then the + delay is given in fractional samples. Otherwise, delay is given in + seconds. If both inputs have a time-like index, then the frequency + is inferred from there. + + """ + + if hasattr(s1, 'index') and not hasattr(s2, 'index'): + warnings.warn('s2 has no index. Ignoring index for s1.', stacklevel=2) + in1 = s1.values + in2 = s2 + elif not hasattr(s1, 'index') and hasattr(s2, 'index'): + warnings.warn('s1 has no index. Ignoring index for s1.', stacklevel=2) + in1 = s1 + in2 = s2.values + elif hasattr(s1, 'index') and hasattr(s2, 'index'): + if not isinstance(s1.index, pd.DatetimeIndex): + warnings.warn('Index of s1 is not a DateTimeIndex. Ignoring both ' + 'indexes.', stacklevel=2) + in1 = s1.values + + try: + in2 = s2.values + except AttributeError: + in2 = s2 + + elif not isinstance(s2.index, pd.DatetimeIndex): + warnings.warn('Index of s2 is not a DateTimeIndex. Ignoring both ' + 'indexes.', stacklevel=2) + in2 = s2.values + + try: + in1 = s1.values + except AttributeError: + in1 = s1 + else: + in1 = s1.values + in2 = s2.values + + # TODO: Option to normalize the two indexes + if s1.index.freq is not None: + s1_freq = s1.index.freq + else: + s1_freq = s1.index.inferred_freq + + if s2.index.freq is not None: + s2_freq = s2.index.freq + else: + s2_freq = s2.index.inferred_freq + + if s1_freq != s2_freq: + raise ValueError('Indexes have different frequencies') + + if s1_freq is None: + raise ValueError('Index frequency cannot be inferred') + + freq = pd.to_timedelta(to_offset(s1_freq)).microseconds * 1e-6 + datarate = 1 / freq + + else: + in1 = s1 + in2 = s2 + + lagwith = 200 + len_s1 = len(in1) + + if not resolution: + c = np.correlate(in1, in2, mode='full') + scale = datarate + else: + in1 = interpolate_1d_vector(in1, datarate) + in2 = interpolate_1d_vector(in2, datarate) + c = np.correlate(in1, in2, mode='full') + scale = datarate * 10 + + shift = np.linspace(-lagwith, lagwith, 2 * lagwith + 1) + corre = c[len_s1 - 1 - lagwith:len_s1 + lagwith] + maxi = np.argmax(corre) + dm1 = abs(corre[maxi] - corre[maxi - 1]) + dp1 = abs(corre[maxi] - corre[maxi + 1]) + if dm1 < dp1: + x = shift[maxi-2: maxi+1] + z = np.polyfit(x, corre[maxi - 2:maxi + 1], 2) + else: + z = np.polyfit(shift[maxi - 1:maxi + 2], corre[maxi - 1:maxi + 2], 2) + + dt1 = z[1] / (2 * z[0]) + delay = dt1 / scale + return dt1 / scale + + +def shift_frame(frame, delay): + return frame.tshift(delay * 1e6, freq='U') + + +def shift_frames(gravity: DataFrame, gps: DataFrame, eotvos: DataFrame, + datarate=10) -> DataFrame: + """ + Synchronize and join a gravity and gps DataFrame (DF) into a single time + shifted DF. + Time lag/shift is found using the find_time_delay function, which cross + correlates the gravity channel with Eotvos corrections. + The DFs (gravity and gps) are then upsampled to a 1ms period using cubic + interpolation. + The Gravity DataFrame is then shifted by the time shift factor returned by + find_time_delay at ms precision. + We then join the GPS DF on the Gravity DF using a left join resulting in a + single DF with Gravity and GPS data at 1ms frequency. + Finally the joined DF is downsampled back to the original frequency 1/10Hz + + Parameters + ---------- + gravity: DataFrame + Gravity data DataFrame to time shift and join + gps: DataFrame + GPS/Trajectory DataFrame to correlate with Gravity data + eotvos: DataFrame + Eotvos correction for input Trajectory + datarate: int + Scalar datarate in Hz + + Returns + ------- + DataFrame: + Synchronized and joined DataFrame containing: + set{gravity.columns, gps.columns} + If gps contains duplicate column names relative to gravity DF, they will + be suffixed with '_gps' + + """ + + # eotvos = calc_eotvos(gps['lat'].values, gps['longitude'].values, + # gps['ell_ht'].values, datarate) + delay = find_time_delay(gravity['gravity'].values, eotvos, 10) + time_shift = DateOffset(seconds=delay) + + # Upsample and then shift: + grav_1ms = gravity.resample('1L').interpolate(method='cubic').fillna(method='pad') + gps_1ms = gps.resample('1L').interpolate(method='cubic').fillna(method='pad') + gravity_synced = grav_1ms.shift(freq=time_shift) # type: DataFrame + + # Join shifted DataFrames: + joined = gravity_synced.join(gps_1ms, how='left', rsuffix='_gps') + + # Now downsample back to original period + down_sample = "{}S".format(1/datarate) + # TODO: What method to use when downsampling - mean, or some other method? + # Can use .apply() to apply custom filter/sampling method + return joined.resample(down_sample).mean() + diff --git a/dgp/lib/trajectory_ingestor.py b/dgp/lib/trajectory_ingestor.py index 6b1436f..0e90841 100644 --- a/dgp/lib/trajectory_ingestor.py +++ b/dgp/lib/trajectory_ingestor.py @@ -5,61 +5,72 @@ Library for trajectory data import functions """ - -import csv import numpy as np import pandas as pd -import functools -import datetime +from pandas.tseries.offsets import Milli from .time_utils import leap_seconds, convert_gps_time, datenum_to_datetime -from .etc import interp_nans -def import_trajectory(filepath, delim_whitespace=False, interval=0, interp=False, is_utc=False, - columns=None, skiprows=None, timeformat='sow'): - """ - import_trajectory +TRAJECTORY_INTERP_FIELDS = {'lat', 'long', 'ell_ht'} + + +def import_trajectory(filepath, delim_whitespace=False, interval=0, + interp=False, is_utc=False, columns=None, skiprows=None, + timeformat='sow'): + """ Read and parse ASCII trajectory data in a comma-delimited format. - :param path: str + Parameters + ---------- + filepath : str or File-like object. Filesystem path to trajectory data file - :param interval: float, default 0 + delim_whitespace : bool + interval : float, Optional Output data rate. Default behavior is to infer the rate. - :param interp: list of ints or list of strs, default None + interp : Union[List[str], List[int]], Optional Gaps in data will be filled with interpolated values. List of column indices (list of ints) or list of column names (list of strs) to interpolate. Default behavior is not to interpolate. - :param is_utc: boolean, default False + is_utc : bool, Optional Indicates that the timestamps are UTC. The index datetimes will be shifted to remove the GPS-UTC leap second offset. - :param colums: list of strs, default: None + columns : List[str] Strings to use as the column names. - :param skiprows: list-like or integer or callable, default None + If none supplied (default), columns will be determined based on + timeformat + skiprows : Union[None, Iterable, int, Callable], Optional Line numbers to skip (0-indexed) or number of lines to skip (int) at the start of the file. If callable, the callable function will be evaluated against the row indices, returning True if the row should be skipped and False otherwise. An example of a valid callable argument would be lambda x: x in [0, 2]. - :param timeformat: 'sow' | 'hms' | 'serial', default: 'hms' + timeformat : str + 'sow' | 'hms' | 'serial' Default: 'hms' Indicates the time format to expect. The 'sow' format requires a field named 'week' with the GPS week, and a field named 'sow' with the GPS seconds of week. The 'hms' format requires a field named 'mdy' with the date in the format 'MM/DD/YYYY', and a field named 'hms' with the time in the format 'HH:MM:SS.SSS'. The 'serial' format (not yet implemented) requires a field named 'datenum' with the serial date number. - :return: DataFrame + + Returns + ------- + DataFrame + Pandas DataFrame of ingested Trajectory data. + """ - df = pd.read_csv(filepath, delim_whitespace=delim_whitespace, header=None, engine='c', na_filter=False, skiprows=skiprows) + df = pd.read_csv(filepath, delim_whitespace=delim_whitespace, header=None, + engine='c', na_filter=False, skiprows=skiprows) # assumed position of these required fields if columns is None: - if timeformat == 'sow': + if timeformat.lower() == 'sow': columns = ['week', 'sow', 'lat', 'long', 'ell_ht'] - elif timeformat == 'hms': + elif timeformat.lower() == 'hms': columns = ['mdy', 'hms', 'lat', 'long', 'ell_ht'] - elif timeformat == 'serial': + elif timeformat.lower() == 'serial': columns = ['datenum', 'lat', 'long', 'ell_ht'] else: raise ValueError('timeformat value {fmt!r} not recognized' @@ -86,9 +97,11 @@ def import_trajectory(filepath, delim_whitespace=False, interval=0, interp=False # create index if timeformat == 'sow': df.index = convert_gps_time(df['week'], df['sow'], format='datetime') + df.index = df.index.round(Milli()) df.drop(['sow', 'week'], axis=1, inplace=True) elif timeformat == 'hms': - df.index = pd.to_datetime(df['mdy'].str.strip() + df['hms'].str.strip(), format="%m/%d/%Y%H:%M:%S.%f") + df.index = pd.to_datetime(df['mdy'].str.strip() + df['hms'].str.strip(), + format="%m/%d/%Y%H:%M:%S.%f") df.drop(['mdy', 'hms'], axis=1, inplace=True) elif timeformat == 'serial': raise NotImplementedError @@ -97,7 +110,7 @@ def import_trajectory(filepath, delim_whitespace=False, interval=0, interp=False # remove leap second if is_utc: # TO DO: Check dates at beginning and end to determine whether a leap second was added in the middle of the survey. - shift = leap_seconds(df.index[0]) + shift = leap_seconds(datetime=df.index[0]) df.index = df.index.shift(-shift, freq='S') # set or infer the interval @@ -113,7 +126,7 @@ def import_trajectory(filepath, delim_whitespace=False, interval=0, interp=False if interp: numeric = df.select_dtypes(include=[np.number]) - numeric = numeric.apply(interp_nans) + numeric = numeric.interpolate(method='time') # replace columns for col in numeric.columns: diff --git a/dgp/lib/transform/__init__.py b/dgp/lib/transform/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dgp/lib/transform/derivatives.py b/dgp/lib/transform/derivatives.py new file mode 100644 index 0000000..b0ad52a --- /dev/null +++ b/dgp/lib/transform/derivatives.py @@ -0,0 +1,31 @@ +# coding: utf-8 + +import numpy as np +from scipy.signal import convolve + + +def central_difference(data_in, n=1, order=2, dt=0.1): + """ central difference differentiator """ + if order == 2: + # first derivative + if n == 1: + dy = (data_in[2:] - data_in[0:-2]) / (2 * dt) + # second derivative + elif n == 2: + dy = ((data_in[0:-2] - 2 * data_in[1:-1] + data_in[2:]) / + np.power(dt, 2)) + else: + raise ValueError('Invalid value for parameter n {1 or 2}') + else: + raise NotImplementedError + + return np.pad(dy, (1, 1), 'edge') + + +# TODO: Add option to specify order +def taylor_fir(data_in, n=1, dt=0.1): + """ 10th order Taylor series FIR differentiator """ + coeff = np.array([1 / 1260, -5 / 504, 5 / 84, -5 / 21, 5 / 6, 0, -5 / 6, 5 / 21, -5 / 84, 5 / 504, -1 / 1260]) + for _ in range(1, n + 1): + y = convolve(data_in, coeff, mode='same') + return y * (1/dt)**n diff --git a/dgp/lib/transform/etc.py b/dgp/lib/transform/etc.py new file mode 100644 index 0000000..f796ada --- /dev/null +++ b/dgp/lib/transform/etc.py @@ -0,0 +1,10 @@ +# coding: utf-8 + +import pandas as pd + + +def named_series(*args, **kwargs): + def wrapper(*args, **kwargs): + return pd.Series(*args, **kwargs) + return wrapper + diff --git a/dgp/lib/transform/filters.py b/dgp/lib/transform/filters.py new file mode 100644 index 0000000..0f4f527 --- /dev/null +++ b/dgp/lib/transform/filters.py @@ -0,0 +1,39 @@ +# coding: utf-8 + +from scipy import signal +import pandas as pd +import numpy as np + + +# TODO: Add Gaussian filter +# TODO: Add B-spline +# TODO: Move detrend + +def lp_filter(data_in, filter_len=100, fs=1): + fc = 1 / filter_len + nyq = fs / 2 + wn = fc / nyq + n = int(2 * filter_len * fs) + taps = signal.firwin(n, wn, window='blackman') + filtered_data = signal.filtfilt(taps, 1.0, data_in, padtype='even', + padlen=80) + name = 'filt_blackman_' + str(filter_len) + return pd.Series(filtered_data, index=data_in.index, name=name) + + +def detrend(data_in, begin, end): + # TODO: Do ndarrays with both dimensions greater than 1 work? + + # TODO: Duck type this check? + if isinstance(data_in, pd.DataFrame): + length = len(data_in.index) + else: + length = len(data_in) + + trend = np.linspace(begin, end, num=length) + if isinstance(data_in, (pd.Series, pd.DataFrame)): + trend = pd.Series(trend, index=data_in.index) + result = data_in.sub(trend, axis=0) + else: + result = data_in - trend + return result diff --git a/dgp/lib/transform/graph.py b/dgp/lib/transform/graph.py new file mode 100644 index 0000000..55dd87d --- /dev/null +++ b/dgp/lib/transform/graph.py @@ -0,0 +1,185 @@ +# coding: utf-8 +from copy import copy +from functools import partial +from collections.abc import Iterable + + +class GraphError(Exception): + def __init__(self, graph, message): + self.graph = graph + self.message = message + +# TODO: Better validation and more descriptive error messages to aid debugging +# TODO: Looping? +class TransformGraph: + def __init__(self, graph=None, verbose=False): + if graph is not None: + self.transform_graph = graph + self._init_graph() + self._results = None + self._graph_changed = True + self.verbose = verbose + + @classmethod + def run(cls, *args, item=None): + """ + Use the graph as a node in another graph + + Parameters + ---------- + *args + arguments to pass to graph initializer + + item: str or list of str + keys of the results graph to be returned + + Returns + ------- + Function whose output is the result of the graph according to the + keys specified + """ + def func(*args): + c = cls(*args) + results = c.execute() + if item is None: + return results + else: + return results[item] + return func + + def _init_graph(self): + """ + Initialize the transform graph + + This is an internal method. + Do not modify the transform graph in place. Instead, use the setter. + """ + self._graph = self._make_graph() + self._order = self._graph.topo_sort() + + @property + def order(self): + return self._order + + @property + def graph(self): + """ iterable: Transform graph + + Setter recomputes a topological sorting of the new graph. + """ + return self.transform_graph + + @graph.setter + def graph(self, g): + self.transform_graph = g + self._init_graph() + self._graph_changed = True + + @property + def results(self): + """ dict: Most recent result""" + return self._results + + def _make_graph(self): + adjacency_list = {k: [] for k in self.transform_graph} + + for k in self.transform_graph: + node = self.transform_graph[k] + if isinstance(node, tuple): + for x in node[1:]: + if isinstance(x, str): + adjacency_list[k].append(x) + else: + adjacency_list[k] += x + return Graph(adjacency_list) + + def execute(self): + """ Execute the transform graph """ + if self._graph_changed: + order = copy(self._order) + results = {} + + def _tuple_to_func(tup): + func = tup[0] + args = [] + for arg in tup[1:]: + # TODO: Account for any kind of iterable, including generators. + if isinstance(arg, list): + args.append([results[x] for x in arg]) + else: + args.append(results[arg]) + new_tup = tuple([func] + args) + return partial(*new_tup) + + while order: + k = order.pop() + if self.verbose: + print('Processing node {k!r}'.format(k=k)) + node = self.transform_graph[k] + if isinstance(node, tuple): + f = _tuple_to_func(node) + results[k] = f() + else: + results[k] = self.transform_graph[k] + self._results = results + self._graph_changed = False + + return self._results + + def __str__(self): + return str(self.transform_graph) + + +class Graph: + def __init__(self, graph): + if not isinstance(graph, Iterable): + raise TypeError('Cannot construct graph from type {typ}' + .format(typ=type(graph))) + + if all(isinstance(x, Iterable) and not isinstance(x, (str, bytes, bytearray)) for x in graph): + raise TypeError('Graph must contain all iterables') + + self._graph = graph + self._topo = [] + + def add_edge(self, u, v): + """ Add an edge to the graph """ + self._graph[u].append(v) + if v not in self._graph: + self._graph[v] = [] + + def remove_edge(self, u, v): + """ Remove an edge from the graph """ + self._graph[u].remove(v) + + def _visit(self, node, visited, stack): + if node in stack: + return + elif node in visited: + raise GraphError(self._graph, 'Cycle detected') + + visited.append(node) + for i in self._graph[node]: + self._visit(i, visited, stack) + + stack.insert(0, node) + + def topo_sort(self): + """ + Topological sorting of the graph + + Returns + ------- + list + Order of execution as a stack + """ + visited = [] + stack = [] + + for node in self._graph: + self._visit(node, visited, stack) + return stack + + def __str__(self): + return str(self._graph) + diff --git a/dgp/lib/transform/gravity.py b/dgp/lib/transform/gravity.py new file mode 100644 index 0000000..ea8d133 --- /dev/null +++ b/dgp/lib/transform/gravity.py @@ -0,0 +1,257 @@ +# coding: utf-8 + +import numpy as np +import pandas as pd +from numpy import array + +from .derivatives import central_difference, taylor_fir +from ..etc import align_frames +from ..timesync import find_time_delay, shift_frame + +# constants +a = 6378137.0 # Default semi-major axis +b = 6356752.3142 # Default semi-minor axis +ecc = (a - b) / a # Eccentricity +We = 0.00007292115 # sidereal rotation rate, radians/sec +mps2mgal = 100000 # m/s/s to mgal + + +def gps_velocities(data_in, output='series', differentiator=central_difference): + # phi + lat = np.deg2rad(data_in['lat'].values) + + # lambda + lon = np.deg2rad(data_in['long'].values) + + h = data_in['ell_ht'].values + + cn = a / np.sqrt(1 - (ecc * np.sin(lat))**2) + cm = ((1 - ecc**2) / a**2) * cn**3 + lon_dot = differentiator(lon) + lat_dot = differentiator(lat) + ve = (cn + h) * np.cos(lat) * lon_dot + vn = (cm + h) * lat_dot + hdot = differentiator(h) + + if output in ('series', 'Series'): + ve_s = pd.Series(ve, name='ve', index=data_in.index) + vn_s = pd.Series(vn, name='vn', index=data_in.index) + vu_s = pd.Series(hdot, name='vu', index=data_in.index) + return ve_s, vn_s, vu_s + elif output in ('array', 'Array'): + return ve, vn, hdot + + +def gps_acceleration(data_in, differentiator=central_difference): + h = data_in['ell_ht'].values + hddot = differentiator(h, n=2) * mps2mgal + + return pd.Series(hddot, name='gps_accel', index=data_in.index) + + +def fo_eotvos(data_in, differentiator=central_difference): + lat = np.deg2rad(data_in['lat'].values) + h = data_in['ell_ht'].values + + ve, vn, vu = gps_velocities(data_in, differentiator=differentiator) + + term1 = vn ** 2 / a * (1 - h / a + ecc * (2 - 3 * np.sin(lat) ** 2)) + term2 = ve ** 2 / a * (1 - h / a - ecc * np.sin(lat) ** 2) + 2 * We * ve * np.cos(lat) + + return (term1 + term2) * mps2mgal + + +def kinematic_accel(data_in): + eotvos = fo_eotvos(data_in, differentiator=taylor_fir) + gps_accel = gps_acceleration(data_in, differentiator=taylor_fir) + # gps_accel = gps_accel.iloc[10:-10].copy() + eotvos, gps_accel = align_frames(eotvos, gps_accel) + + return eotvos - gps_accel + + +def eotvos_correction(data_in, differentiator=central_difference): + """ + Eotvos correction + + Parameters + ---------- + data_in: DataFrame + trajectory frame containing latitude, longitude, and + height above the ellipsoid + dt: float + sample period + + Returns + ------- + Series + index taken from the input + + Notes + ----- + Added to observed gravity when the positive direction of the sensitive axis is + down, otherwise, subtracted. + + References + --------- + Harlan 1968, "Eotvos Corrections for Airborne Gravimetry" JGR 73,n14 + """ + + dt = 0.1 + + lat = np.deg2rad(data_in['lat'].values) + lon = np.deg2rad(data_in['long'].values) + ht = data_in['ell_ht'].values + + dlat = differentiator(lat, n=1, dt=dt) + ddlat = differentiator(lat, n=2, dt=dt) + dlon = differentiator(lon, n=1, dt=dt) + ddlon = differentiator(lon, n=2, dt=dt) + dht = differentiator(ht, n=1, dt=dt) + ddht = differentiator(ht, n=2, dt=dt) + + sin_lat = np.sin(lat) + cos_lat = np.cos(lat) + sin_2lat = np.sin(2.0 * lat) + cos_2lat = np.cos(2.0 * lat) + + # Calculate the r' and its derivatives + r_prime = a * (1.0 - ecc * sin_lat ** 2) + dr_prime = -a * dlat * ecc * sin_2lat + ddr_prime = (-a * ddlat * ecc * sin_2lat - 2.0 * a * (dlat ** 2) * + ecc * cos_2lat) + + # Calculate the deviation from the normal and its derivatives + D = np.arctan(ecc * sin_2lat) + dD = 2.0 * dlat * ecc * cos_2lat + ddD = (2.0 * ddlat * ecc * cos_2lat - 4.0 * dlat * dlat * + ecc * sin_2lat) + + # Calculate this value once (used many times) + sinD = np.sin(D) + cosD = np.cos(D) + + # Calculate r and its derivatives + r = array([ + -r_prime * sinD, + np.zeros(r_prime.size), + -r_prime * cosD - ht + ]) + + rdot = array([ + (-dr_prime * sinD - r_prime * dD * cosD), + np.zeros(r_prime.size), + (-dr_prime * cosD + r_prime * dD * sinD - dht) + ]) + + ci = (-ddr_prime * sinD - 2.0 * dr_prime * dD * cosD - r_prime * + (ddD * cosD - dD * dD * sinD)) + ck = (-ddr_prime * cosD + 2.0 * dr_prime * dD * sinD + r_prime * + (ddD * sinD + dD * dD * cosD) - ddht) + r2dot = array([ + ci, + np.zeros(ci.size), + ck + ]) + + # Define w and its derivative + w = array([ + (dlon + We) * cos_lat, + -dlat, + (-(dlon + We)) * sin_lat + ]) + + wdot = array([ + dlon * cos_lat - (dlon + We) * dlat * sin_lat, + -ddlat, + (-ddlon * sin_lat - (dlon + We) * dlat * cos_lat) + ]) + + w2_x_rdot = np.cross(2.0 * w, rdot, axis=0) + wdot_x_r = np.cross(wdot, r, axis=0) + w_x_r = np.cross(w, r, axis=0) + wxwxr = np.cross(w, w_x_r, axis=0) + + we = array([ + We * cos_lat, + np.zeros(sin_lat.shape), + -We * sin_lat + ]) + + wexr = np.cross(we, r, axis=0) + wexwexr = np.cross(we, wexr, axis=0) + + kin_accel = r2dot * mps2mgal + eotvos = (w2_x_rdot + wdot_x_r + wxwxr - wexwexr) * mps2mgal + + # acc = r2dot + w2_x_rdot + wdot_x_r + wxwxr + + eotvos = pd.Series(eotvos[2], index=data_in.index, name='eotvos') + kin_accel = pd.Series(kin_accel[2], index=data_in.index, name='kin_accel') + + return pd.concat([eotvos, kin_accel], axis=1, join='outer') + + +def latitude_correction(data_in): + """ + WGS84 latitude correction + + Accounts for the Earth's elliptical shape and rotation. The gravity value + that would be observed if Earth were a perfect, rotating ellipsoid is + referred to as normal gravity. Gravity increases with increasing latitude. + The correction is added as one moves toward the equator. + + Parameters + ---------- + data_in: DataFrame + trajectory frame containing latitude, longitude, and + height above the ellipsoid + + Returns + ------- + :obj:`Series` + units are mGal + + Notes + ----- + Added to observed gravity when the positive direction of the sensitive axis is + down, otherwise, subtracted. + """ + lat = np.deg2rad(data_in['lat'].values) + sin_lat2 = np.sin(lat) ** 2 + num = 1 + np.float(0.00193185265241) * sin_lat2 + den = np.sqrt(1 - np.float(0.00669437999014) * sin_lat2) + corr = -np.float(978032.53359) * num / den + return pd.Series(corr, index=data_in.index, name='lat_corr') + + +def free_air_correction(data_in): + """ + 2nd order Free Air Correction + + Compensates for the change in the gravitational field with respect to + distance from the center of the ellipsoid. Does not include the effect + of mass between the observation point and the datum. + + Parameters + ---------- + data_in: :class:`DataFrame` + trajectory frame containing latitude, longitude, and + height above the ellipsoid + + Returns + ------- + :obj:`Series` + units are mGal + + Notes + ----- + Added to observed gravity when the positive direction of the sensitive axis is + down, otherwise, subtracted. + """ + lat = np.deg2rad(data_in['lat'].values) + ht = data_in['ell_ht'].values + sin_lat2 = np.sin(lat) ** 2 + fac = ((np.float(0.3087691) - np.float(0.0004398) * sin_lat2) * + ht) - np.float(7.2125e-8) * (ht ** 2) + return pd.Series(fac, index=data_in.index, name='fac') \ No newline at end of file diff --git a/dgp/lib/transform/transform.py b/dgp/lib/transform/transform.py new file mode 100644 index 0000000..66319a3 --- /dev/null +++ b/dgp/lib/transform/transform.py @@ -0,0 +1,179 @@ +# coding=utf-8 + +from pandas import DataFrame +import inspect +from functools import wraps + +from dgp.lib.etc import gen_uuid, dedup_dict + + +transform_registry = {} + + +def createtransform(func): + """ + Function decorator that generates a transform class for the decorated + function. + + This decorator is an alternative to defining a subclass of Transform. + The class generated by this decorator is automatically inserted into the + transform registry. + + Positional arguments are reserved for data. + Required keyword arguments are made into attributes of the class. + + Returns + ------- + Transform + A callable instance of a class that subclasses Transform + """ + + def class_func(self, *args, **kwargs): + return func(*args, **kwargs) + + sig = inspect.signature(func) + class_id = func.__name__ + cls = type(class_id, (Transform,), + dict(func=class_func, _sig=sig)) + transform_registry[class_id] = cls + + @wraps(func) + def wrapper(*args, **kwargs): + return cls(*args, **kwargs) + + return wrapper + + +def register_transform_class(cls): + """ + Class decorator for constructing transform classes. + + The decorator adds an entry for the decorated class into the transform + class registry. + """ + class_id = cls.__name__ + if class_id in transform_registry: + raise KeyError('Transform class {cls} already exists in registry.' + .format(cls=class_id)) + + transform_registry[class_id] = cls + return cls + + +class Transform: + """ + Transform base class. + + All transform classes should subclass this one. + + The class instance is callable. When a class instance is called, all of the + variables specified in the function signature must have a value, otherwise + a ValueError will be raised. + + There are three ways to specify and set values for variables used by the + function: + - in the function signature + - as keyword arguments with values when instantiating the class + - as keywords when the instance is called + + In all cases, variables are made into attributes of the class set with + the values specified. + + Additional variables can be added as attributes (as metadata, for example) + of the class by passing the names and values as keyword arguments when + instantiating the class. + """ + + def __init__(self, **kwargs): + self._uid = gen_uuid('tf') + self._var_list = [] + + if getattr(self, '_sig', None) is None: + self._sig = inspect.signature(self.func) + + for param in self._sig.parameters.values(): + if param.kind == param.KEYWORD_ONLY and getattr(self, param.name, None) is None: + if param.default is not param.empty: + setattr(self, param.name, param.default) + self._var_list.append(param.name) + + # add attributes not explicitly used by the function + for k, v in kwargs.items(): + setattr(self, k, v) + + @property + def uid(self): + return self._uid + + def __call__(self, *args, **kwargs): + keywords = {name: self.__dict__[name] for name in self._var_list + if name in self.__dict__} + + # override keywords explicitly set in function call + for k, v in kwargs.items(): + if getattr(self, k, None) is None: + setattr(self, k, v) + + keywords[k] = v + + # check whether all attributes have values set + notset = [] + for name in self._var_list: + if name not in keywords: + notset.append(name) + + if notset: + raise ValueError('Required attributes not set: {attr}' + .format(attr=', '.join(notset))) + + return self.func(*args, **keywords) + + def __str__(self): + attrs = ', '.join(['{var}={val}'.format(var=k, val=v) + for k, v in [(var, self.__dict__[var]) + for var in self._var_list]]) + return '{cls}({attrs})'.format(cls=self.__class__.__name__, + attrs=attrs) + + +class DataWrapper: + """ + A container for transformed DataFrames. Multiple transform chains may + be specified and the resultant DataFrames will be held in this class + instance. + """ + def __init__(self, frame: DataFrame): + self.df = frame # original DataFrame; not ever modified + self.modified = {} + self._transform_chains = {} + self._defaultchain = None + + def removechain(self, uid): + del self._transform_chains[uid] + del self.modified[uid] + + def applychain(self, tc): + if not isinstance(tc, TransformChain): + raise TypeError('expected an instance or subclass of ' + 'TransformChain, but got {typ}' + .format(typ=type(tc))) + + if tc.uid not in self._transform_chains: + self._transform_chains[tc.uid] = tc + if self._defaultchain is None: + self._defaultchain = self._transform_chains[tc.uid] + self.modified[tc.uid] = self._transform_chains[tc.uid].apply(self.df) + return self.modified[tc.uid] + + @property + def data(self, reapply=False): + if self._defaultchain is not None: + if reapply: + return self.applychain(self._defaultchain) + else: + return self.modified[self._defaultchain.uid] + else: + return self.df + + def __len__(self): + return len(self.modified.items()) diff --git a/dgp/lib/transform/transform_graphs.py b/dgp/lib/transform/transform_graphs.py new file mode 100644 index 0000000..4408dd9 --- /dev/null +++ b/dgp/lib/transform/transform_graphs.py @@ -0,0 +1,83 @@ +# coding: utf-8 +from functools import partial +import pandas as pd +import numpy as np + +from .graph import TransformGraph +from .gravity import (eotvos_correction, latitude_correction, + free_air_correction, kinematic_accel) +from .filters import lp_filter +from ..timesync import find_time_delay, shift_frame +from ..etc import align_frames +from .derivatives import taylor_fir, central_difference + + +def demux(df, col): + return df[col] + + +class SyncGravity(TransformGraph): + # TODO: align_frames only works with this ordering, but should work for either + def __init__(self, kin_accel, gravity): + self.transform_graph = {'gravity': gravity, + 'raw_grav': gravity['gravity'], + 'kin_accel': kin_accel, + 'delay': (find_time_delay, 'kin_accel', 'raw_grav'), + 'shifted_gravity': (shift_frame, 'gravity', 'delay'), + } + super().__init__() + + def result_df(self) -> pd.DataFrame: + return pd.DataFrame() + + +class AirbornePost(TransformGraph): + # concat = partial(pd.concat, axis=1, join='outer') + + def total_corr(self, *args): + return pd.Series(sum(*args), name='total_corr') + + def corrected_grav(self, *args): + return pd.Series(sum(*args), name='corrected_grav') + + # TODO: What if a function takes a string argument? Use partial for now. + # TODO: Little tricky to debug these graphs. Breakpoints? Print statements? + def __init__(self, trajectory, gravity, begin_static, end_static): + self.begin_static = begin_static + self.end_static = end_static + self.transform_graph = {'trajectory': trajectory, + 'gravity': gravity, + 'eotvos_and_accel': (partial(eotvos_correction, differentiator=central_difference), 'trajectory'), + 'eotvos': (partial(demux, col='eotvos'), 'eotvos_and_accel'), + 'kin_accel': (partial(demux, col='kin_accel'), 'eotvos_and_accel'), + 'aligned_eotvos': (partial(align_frames, item='r'), 'trajectory', 'eotvos'), + 'aligned_kin_accel': (partial(align_frames, item='r'), 'trajectory', 'kin_accel'), + 'lat_corr': (latitude_correction, 'trajectory'), + 'fac': (free_air_correction, 'trajectory'), + 'total_corr': (self.total_corr, ['aligned_kin_accel', 'aligned_eotvos', 'lat_corr', 'fac']), + 'abs_grav': (partial(demux, col='gravity'), 'gravity'), + 'corrected_grav': (self.corrected_grav, ['total_corr', 'abs_grav']), + 'filtered_grav': (partial(lp_filter, fs=10), 'corrected_grav') + } + super().__init__() + + # TODO: Add an empty method to super for descendant implementation? + def result_df(self) -> pd.DataFrame: + """Concatenate the resultant dictionary into a pandas DataFrame""" + if self.results is not None: + trajectory = self.results['trajectory'] + time_index = pd.Series(trajectory.index.astype(np.int64) / 10 ** 9, index=trajectory.index, + name='unix_time') + output_frame = pd.concat([time_index, trajectory[['lat', 'long', 'ell_ht']], + self.results['aligned_eotvos'], + self.results['aligned_kin_accel'], self.results['lat_corr'], + self.results['fac'], self.results['total_corr'], + self.results['abs_grav'], self.results['corrected_grav']], + axis=1) + output_frame.columns = ['unix_time', 'lat', 'lon', 'ell_ht', 'eotvos', + 'kin_accel', 'lat_corr', 'fac', 'total_corr', + 'vert_accel', 'gravity'] + return output_frame + else: + self.execute() + return self.result_df() diff --git a/dgp/lib/types.py b/dgp/lib/types.py deleted file mode 100644 index bea2c30..0000000 --- a/dgp/lib/types.py +++ /dev/null @@ -1,27 +0,0 @@ -# coding: utf-8 - -from collections import namedtuple - -""" -Dynamic Gravity Processor (DGP) :: types.py -License: Apache License V2 - -Overview: -types.py is a library utility module used to define custom reusable types for use in other areas of the project. -""" - - -Location = namedtuple('Location', ['lat', 'long', 'alt']) - -StillReading = namedtuple('StillReading', ['gravity', 'location', 'time']) - -FlightLine = namedtuple('FlightLine', ['id', 'sequence', 'file_ref', 'start', 'end']) - -DataCurve = namedtuple('DataCurve', ['channel', 'data']) - -class DataPacket: - def __init__(self, data, path, flight, data_type, *args, **kwargs): - self.data = data - self.path = path - self.flight = flight - self.data_type = data_type \ No newline at end of file diff --git a/dgp/resources_rc.py b/dgp/resources_rc.py deleted file mode 100644 index 8e79d49..0000000 --- a/dgp/resources_rc.py +++ /dev/null @@ -1,9574 +0,0 @@ -# -*- coding: utf-8 -*- - -# Resource object code -# -# Created by: The Resource Compiler for PyQt5 (Qt v5.9.1) -# -# WARNING! All changes made in this file will be lost! - -from PyQt5 import QtCore - -qt_resource_data = b"\ -\x00\x00\x01\xde\ -\x89\ -\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ -\x00\x00\x1a\x00\x00\x00\x1a\x08\x06\x00\x00\x00\xa9\x4a\x4c\xce\ -\x00\x00\x01\xa5\x49\x44\x41\x54\x48\x4b\xb5\x96\x81\x31\x04\x41\ -\x10\x45\xff\x45\x80\x08\x10\x01\x22\x40\x06\x32\x40\x04\x88\x00\ -\x11\x20\x02\x2e\x02\x44\x80\x0c\x5c\x04\x64\xe0\x64\xa0\xde\xd5\ -\xb4\xea\xed\x9d\xdd\x99\x5d\x6b\xaa\xb6\xea\x6a\x77\xa6\x5f\x4f\ -\xf7\xef\xee\x9b\xe9\x7f\xd6\x96\xa4\x4b\x49\x07\x92\xf8\x7d\x31\ -\x9b\x98\xb3\x2e\xe9\x46\xd2\x49\xb4\x3b\x25\x08\xc8\x8b\xa4\xdd\ -\x8c\xf3\x8b\x5a\x90\x79\xba\x0a\x83\xa4\xf7\x60\xac\x0f\xc2\xd6\ -\xb9\x81\xd8\x78\x96\x0e\xbf\x3a\x23\xdf\x92\x3e\x83\xa7\xd7\x92\ -\xae\xdc\x9e\x12\x84\xad\xdb\x80\x6a\x36\xfa\x0b\x00\xe6\x61\x71\ -\x33\x12\x9e\x0b\x97\x9d\x99\x93\x33\x40\x24\x0e\x0f\x37\x27\x16\ -\x06\xe6\x16\xc9\x91\xa5\xcf\xd1\x91\x24\x7b\xd6\x26\x80\xfe\x42\ -\xb0\x95\x13\x03\xa1\x04\xc8\x4d\xf7\x47\x02\x1b\x90\x2e\x90\xb7\ -\x8d\xca\x00\xf2\xd4\x86\xb6\x05\xa9\x01\x79\x28\x49\xa7\x4e\x4a\ -\xeb\x4e\xd2\xf9\xd8\x82\x1d\xa2\xcc\xb7\x24\x80\x06\xab\xa6\x60\ -\x87\x40\x30\x3e\x0a\x34\x14\x02\x88\x1a\x7b\x90\xf4\xec\x3b\x48\ -\xdf\x8d\xc6\x40\x7c\xb8\x1a\x37\xeb\x02\xd5\x40\x50\x17\x49\xef\ -\x12\xc8\xaa\x23\x18\xd9\x40\xbc\xb8\x2f\xc9\xc9\x7d\xf7\x12\x26\ -\x54\x51\xfa\xd9\x3a\xfa\x0b\x04\x36\xb7\x62\x06\xf9\xb5\x21\x69\ -\xe9\x5f\x70\x23\xba\x00\x35\xc2\xb3\x53\xb8\x55\xae\x18\x29\xea\ -\x8f\x70\x6e\x2f\x8e\x92\x98\x23\x72\x63\xdd\x18\x4f\x7d\xcf\xcb\ -\x56\x7c\x02\x30\x5a\x7c\xbb\x3a\x94\xe4\xc7\x4d\xb6\xd7\x99\x73\ -\x74\x74\xe6\xbe\xad\x56\x38\xdc\xb7\x18\xfe\x41\x20\x42\xfa\xe8\ -\x8c\x95\x4a\x01\x51\x58\x04\x06\x81\x08\xe3\x57\x25\x88\x6d\x14\ -\xe9\x71\xda\xcf\xb8\xbf\x8d\x62\xe8\xcb\x3f\x13\xd4\x04\x52\x6a\ -\x57\x3e\x02\x71\xdc\xf7\xe6\x08\x07\xf0\x8a\xff\x12\xa7\xc9\xe3\ -\x52\xa9\x11\x3e\x64\x8d\xa0\x5a\xf2\xee\x3b\x8c\x97\x84\x90\xb0\ -\xd4\x2c\x44\xf1\x14\x21\x1c\xfc\x01\x4b\x5d\x59\x1a\xcf\x90\x46\ -\xca\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\ -\x00\x01\xf6\xff\ -\x89\ -\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ -\x00\x00\xf2\x00\x00\x00\xf0\x08\x06\x00\x00\x00\x3a\xa0\x39\xaf\ -\x00\x00\x00\x06\x62\x4b\x47\x44\x00\xff\x00\xff\x00\xff\xa0\xbd\ -\xa7\x93\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0b\x12\x00\x00\ -\x0b\x12\x01\xd2\xdd\x7e\xfc\x00\x00\x00\x07\x74\x49\x4d\x45\x07\ -\xdf\x07\x19\x10\x2d\x21\xc0\xe8\x29\x9e\x00\x00\x20\x00\x49\x44\ -\x41\x54\x78\xda\xec\xbd\x59\x90\x64\xd7\x79\xe7\xf7\x3b\x77\xcf\ -\x9b\x4b\x65\x66\x65\xed\xd5\xd5\x55\xd5\xd5\xd5\xd5\x7b\x37\x1a\ -\x40\x63\x23\x16\x02\x20\x09\x92\xe2\xaa\xe1\xd0\xf2\x78\x14\x96\ -\x27\xe8\x25\x1c\x31\x13\xd2\x38\x86\x2f\x0e\x73\x62\x1e\x86\xb2\ -\xfc\x30\x0f\x7e\xd2\x38\x64\x8f\x64\x29\x24\x92\xa6\x44\x8a\x24\ -\x48\x6c\x24\xb1\x36\x80\xde\xf7\xaa\xee\xae\xea\xda\xf7\xdc\x33\ -\xef\x7e\x8f\x1f\x6e\x56\xa1\x01\x82\x92\x6c\x3a\x42\x0c\x13\x37\ -\x22\xe3\xe6\x72\x6f\xe6\xcd\x73\xbf\xff\xf9\xb6\xff\xf7\x1d\x21\ -\xa5\xe4\xa3\xed\x57\xd9\xe2\xce\x43\xf9\xc0\xfb\xca\x87\x1f\xde\ -\x19\x6e\x19\xc7\xc4\x71\x8c\xaa\x2b\xc9\x7b\x02\x9a\x8d\x06\x99\ -\x6c\x96\x66\xb3\x49\x2a\x95\x46\x51\x55\xe2\xce\x69\x11\x50\x6d\ -\xd4\xcf\x2a\xaa\xfe\x52\xc6\x4e\x7d\x1d\xa0\xe9\xba\xdf\xb4\x2c\ -\xeb\xeb\xa2\x73\x8c\x00\xd4\xce\xde\xf7\x5d\x9a\xcd\xba\x8c\x43\ -\x89\x65\x59\xcf\xda\xb6\xfd\x52\xad\xd6\x28\x47\x31\x05\x29\xa1\ -\x54\x2a\x0a\xa9\x40\x2d\x0a\xca\x86\xaa\xdf\xef\xcb\xf0\x6c\x14\ -\xfa\x05\x43\xe8\x7f\xa8\x21\xbf\x6e\x6b\x06\x81\xe7\xa3\xa3\xa1\ -\xa9\x02\x45\x88\xf7\xfe\x6e\x18\x11\x87\x31\x81\x8c\x89\x74\x05\ -\xa9\x2a\x68\xaa\x8a\xae\x80\x10\xc9\xef\x27\xc7\x4a\xa4\x94\x48\ -\x11\x23\x3a\xe7\x4b\x91\x7c\x85\x24\x42\xbe\x6f\xb4\x04\x0a\x20\ -\x64\x32\x6e\x62\xf7\xf7\x04\xb2\xf3\x74\xe7\xdc\x9d\x61\x14\x80\ -\x90\x12\x05\xf1\xde\xf1\xbf\xa1\x9b\xf8\x08\xc8\xff\x40\xb0\x4a\ -\x05\xc4\x87\xec\xff\xbe\x4d\x76\x84\xb9\x23\x9c\x42\xa8\xc4\x71\ -\x4c\x14\x45\x09\x90\x25\x68\x8a\x4a\x18\x47\xb4\x5d\x77\x3c\x97\ -\xef\x9a\x95\x1d\xe0\x7a\x91\x44\x0a\x41\x24\xc0\x0b\xfc\xb3\x7e\ -\x18\x9e\x52\x75\x0d\xa1\x2a\x6c\x6d\x6d\xb1\xb8\xba\xc6\xf4\x9d\ -\xbb\x08\x45\x25\x0c\x03\x7c\xcf\x43\x41\x92\xd2\x0d\xe2\x20\xc4\ -\x69\x37\x89\x82\x98\x62\xb1\x88\x22\x34\xc2\x30\xa2\x5a\xad\x63\ -\xdb\x36\x9a\x6a\xa0\xa7\x74\x7c\xcd\xa3\xd1\xae\xd1\xd7\xd3\x47\ -\xb3\x5a\x65\x74\x68\x84\x63\x87\x0f\x53\xdb\xaa\x30\xd8\xdb\x4b\ -\xec\x85\x28\x71\x8c\xa1\xe8\xe7\x32\x76\xea\x7e\xc3\xd2\x77\x27\ -\x23\x54\x68\x0b\x08\xee\x99\x48\x84\x94\xc8\x28\x44\x89\x25\xaa\ -\x8c\x49\xe9\xe6\x7b\xd0\x93\x3b\x33\x41\x02\x72\x14\x88\x95\x98\ -\x48\x80\xda\x81\xbf\xd8\xdd\xab\x9d\xe1\x93\xbb\x50\x4f\x80\x2c\ -\x3e\x00\xe4\xf8\x23\x20\x7f\x04\xe4\x7f\xa8\xc6\xfd\x7f\xb1\x75\ -\x24\x4d\xc6\x31\x61\x14\x25\x02\xa9\xa8\x68\x9a\x86\x7c\x4f\x67\ -\xa1\x76\x86\xdf\xf3\x22\xfc\x30\x44\xe8\x1a\x7e\x2c\x9f\x59\xde\ -\x58\x7b\x71\xbb\x5c\x65\x71\x75\x85\x7a\xb3\x41\xa3\xdd\xa2\xd9\ -\x6e\xb1\x5d\xa9\xe0\x38\x0e\xbd\xfd\x7d\x8c\x8e\xed\x63\x68\x7c\ -\x1f\xaa\xae\xe1\x39\x2e\xd5\x6a\x19\x11\xc5\x14\x72\x5d\x64\xec\ -\x34\x48\x89\xa2\x28\x74\xe5\x0a\x84\x5e\x88\xa6\x19\x54\xeb\x0d\ -\x32\x99\x1c\x5b\x5b\x5b\xd4\x9b\x35\x6a\x6e\x99\xae\x7c\x86\x73\ -\xef\x9e\x65\xdf\xd8\x18\xf9\x4c\x8e\x6b\x57\xae\x90\x36\x2c\x56\ -\x97\x96\xd9\xd3\x3f\x48\x2e\x93\xa1\x2b\x9d\xc5\x36\x2d\x4c\xd3\ -\x24\xdf\xd5\x45\x7f\x7f\x3f\xf9\x52\xb7\xf0\x0d\x71\x36\x56\x39\ -\xa5\xc1\x1f\x6a\xf0\x75\xbd\x63\x15\x28\x3b\x0f\x09\x8a\x94\x89\ -\xaa\x96\xf1\x7b\x60\x96\x12\x04\xc4\x8a\x44\x0a\x89\xb8\x07\xc2\ -\x7f\x17\x90\x91\x82\x58\xdc\x2b\xc0\x1f\x01\xf9\x23\x20\xff\x3f\ -\x02\xf0\x87\x01\x5a\xf9\x10\x33\xfa\xc3\x81\x1f\xa1\xec\x2a\xb2\ -\x40\x82\xe3\x79\xcf\xf8\x7e\xf0\x62\x65\xab\x8a\xaa\xea\x6c\x95\ -\xb7\xa9\x37\x5a\x5c\x9b\xb9\x09\x9a\x46\xbd\xdd\x22\x92\x30\x39\ -\x35\x85\x99\xb2\xe8\x1f\x1c\xa0\x58\x2c\xb2\x55\xd9\x62\x61\x61\ -\x01\x5d\xd7\x19\x19\x19\xe1\xe6\xf4\x34\xa6\x9d\x22\x70\x3d\xb6\ -\x36\x37\xf1\x7d\x9f\x52\xa1\x40\xa9\x58\x42\xd7\x75\xe2\x18\x6c\ -\xdb\x26\x8a\x15\xc2\x30\x22\x92\x02\x55\xd5\xd9\xd8\xdc\x66\x75\ -\x75\x99\x5c\x57\x8a\xb6\xd3\x64\xff\xfe\xfd\xc4\x61\x44\x77\x77\ -\x37\xa6\xa6\x73\xf1\xe2\x45\x26\xf7\xef\x27\x9b\xce\x20\x84\xc0\ -\x69\xb6\x58\x5e\x5e\x66\x7e\x7e\x9e\x56\xab\x45\x2e\x97\xa3\xbb\ -\x50\x24\x6f\x59\x64\xd2\x29\x4a\x85\x22\xdd\xdd\x45\xb2\xb9\xf4\ -\xb7\x2d\x43\xfb\x8a\x10\x20\x24\xa8\x1a\xf7\xc0\x53\x76\x46\x2a\ -\x26\xb1\x51\x12\x8b\x44\xec\x58\x2b\xf7\x8a\xa2\x50\x77\x4d\xeb\ -\xdd\xb9\x51\x24\xdf\xf4\x3e\x89\x95\x71\xc7\xd2\xf9\x08\xc8\x1f\ -\x61\xf6\x57\x00\xb2\x44\x79\x9f\x87\x2c\x76\x8f\x55\x76\x15\x73\ -\x84\xc4\x97\x12\xcf\x0f\xc7\x6b\xad\xd6\x9d\x8d\xcd\x6d\x56\xd6\ -\xd7\x28\x57\x6a\x34\x5b\x2e\x8e\xe3\xe1\x78\x01\x27\x1e\x38\x45\ -\x3a\x93\x63\xef\xc4\x08\x17\x2e\x5e\xe3\xec\x85\xf3\x8c\x8d\x8d\ -\x51\x6f\x34\x10\x42\xd0\xdb\x53\x22\x9f\xcf\x13\x87\x3e\xad\x56\ -\x8b\xc0\x73\x39\x7a\xe8\x00\xf9\x5c\x96\x38\x86\x8d\x8d\x35\x1c\ -\xc7\xa1\xab\xab\x8b\x52\xa1\x84\x6a\xe8\xd4\x1b\x4d\x2c\x3b\x8d\ -\x69\xa9\x6c\x6e\x3b\x18\x56\x0a\x3f\x8c\x09\xc2\x98\xd5\x8d\x75\ -\x52\x86\xc9\xbe\x7d\x25\xca\x35\x49\xb9\x5c\xa6\x5e\xaf\xb3\xbe\ -\xbe\x4e\x57\x57\x17\xdd\xdd\xdd\x54\x2a\x15\x1a\x8d\x06\xcd\x66\ -\x13\x29\x48\x00\xdc\xdd\x4d\x2e\x97\xc3\xd6\x34\x36\xe7\x17\x70\ -\x6a\x55\xaa\xdb\x65\x1c\xb7\x85\x61\x68\xf4\xf5\x96\x18\x1e\x1c\ -\xa2\x54\x2c\x30\x3c\x54\x12\x3b\xbe\xfb\xae\xf9\xdd\x01\xb2\x22\ -\x63\x74\x29\x76\x81\xfc\x7e\xc9\x14\x89\xfb\xf2\x0b\xf2\x29\x3e\ -\x70\x57\x3e\x02\xf2\x47\x40\xde\xd1\x96\x51\x44\x10\x04\xa8\xaa\ -\x8a\xae\xeb\xef\x7b\x5f\x51\x13\x01\xa9\x37\xea\x64\x32\x19\x54\ -\xa1\xd0\x76\x1d\x52\x56\x8a\x90\x18\xd7\x8b\x30\x4d\x13\xcf\xf3\ -\xf0\x5d\xef\x6b\xf9\x6c\xee\x8f\x11\x31\x02\x85\x20\x8e\x51\x55\ -\x85\x99\xbb\xf3\x72\x69\x6d\x8d\x6a\xd3\x61\x71\x65\x95\x74\x57\ -\x17\x0b\x2b\xcb\x1c\x39\x71\x8a\x4c\xbe\xc8\xf5\xe9\x19\x26\xa7\ -\x0e\xb1\x55\xde\x46\x33\x2c\xae\x5c\xbb\xca\x13\x4f\x7e\x1c\xdf\ -\xf7\x19\x1c\xe8\xe3\xed\xb7\xdf\xe5\x81\x93\x27\xc8\xd8\x3a\x22\ -\x02\x3b\x05\xf3\xb3\x2b\x4c\x5f\xbd\xc8\xf1\x89\x51\x6c\x43\x63\ -\x65\x65\x15\xc7\x73\xd8\xdc\xdc\x44\xb7\x4c\x4c\x2b\x45\x77\xa9\ -\x97\xe5\x8d\x0d\xd2\x5d\x79\x82\x58\xd0\xf2\x7c\x22\x14\x32\xf9\ -\x02\xb7\x66\xe7\x50\x34\x8b\x52\xef\x10\x42\x37\xb0\x2c\x8b\x76\ -\xbb\x4d\xa3\xd5\xa4\xb7\xb7\x97\x3d\x7b\x47\xd0\x75\x41\x31\x07\ -\xd5\x26\x6c\x6c\x54\xb1\x33\x19\x36\x37\x37\x79\xe9\xa5\x97\x38\ -\x72\xe4\x08\xaf\xbc\xf4\x02\xc5\x8c\xcd\xd8\xe8\x1e\xd6\x57\x57\ -\x99\x18\x1b\xa5\x98\xcb\x72\xeb\xfa\x75\xca\xeb\xab\x8c\xf4\xf7\ -\xd3\x93\xcb\x31\x50\x2a\x71\xf2\xf0\x61\x06\x7b\x7b\x44\x4a\x55\ -\x31\x8d\x24\xc0\xe7\x3b\x2e\x86\x6d\x41\x1c\x81\xaa\x12\xf8\x3e\ -\xba\x61\xd0\x6a\x36\x31\x4d\x13\x4d\xbf\xc7\x1f\x8f\x24\x71\x1c\ -\xa3\x28\x0a\x28\xf7\x68\x69\xe2\xdd\xd7\xbb\x01\xb5\x7b\x64\xfa\ -\x37\x05\xe0\xbf\xf1\x40\x8e\xa2\x08\x55\x55\x3f\xf4\xb3\x20\x0a\ -\x93\xcf\x75\x1d\x45\x28\xf7\x08\x8f\xc4\x0b\x7c\xa4\x22\x90\x68\ -\x78\x81\xff\xcd\x8c\x65\x7d\x3d\x08\x22\x34\xa1\x20\xa5\xe4\xda\ -\xb5\x6b\xf2\xd6\xec\x1d\xe6\x16\x16\xe8\xee\xeb\xa7\xe9\x87\x18\ -\x99\x1c\x07\x8f\x1f\x67\x7d\xbb\xcc\xd8\xc4\x04\x6f\x5f\xbc\x8c\ -\x92\x4a\xf3\xfa\x99\x77\xb0\xd3\x69\x82\x58\xf2\xa9\xe7\x9e\xa3\ -\x50\x2a\x50\xaf\xb7\x49\x19\x26\x9a\xa2\x32\x73\xfd\x1a\x5b\x2b\ -\x2b\x18\x8a\xa0\x3b\x97\xc3\x6b\xd5\x39\x32\x75\x00\x03\xc9\xc5\ -\x37\x5e\xe5\xc4\x91\x43\x8c\x4f\xec\xa3\xed\xb9\xf4\xf4\xf6\xf2\ -\xca\xcf\x7e\xce\x63\x4f\x3e\xc1\xca\xc6\x06\xc5\xde\x3e\xbc\x18\ -\xe6\x96\x57\xd9\xaa\x36\xd0\xd3\x69\xd0\x34\x5e\x7a\xf9\xe7\xdc\ -\x5d\x5d\x65\x70\xef\x7e\xb6\xcb\x55\xca\xb5\x2a\xab\xab\xab\xa8\ -\xaa\x4a\x26\x93\xa1\x54\x2a\x11\x04\x01\x03\xbd\x7d\xec\xd9\xb3\ -\x87\x4a\xa5\xc2\xa9\x53\xa7\x78\xe1\xc7\x3f\x61\x61\x61\x81\x74\ -\x3a\xcd\xf6\xe6\x3a\xae\x53\xc3\xd0\x15\xaa\xdb\x65\x7a\x8b\x05\ -\x9c\x66\x83\xfd\x7b\xf7\xd0\x5f\x2c\xf2\xc8\xfd\xf7\x91\xd1\x74\ -\xea\x5b\x5b\x10\xb8\x44\x8e\x4b\x6b\x6b\x9b\x87\xee\x3f\x45\x7f\ -\x5f\x0f\x07\xa7\x26\x84\xeb\x06\x58\xa9\x64\xf2\xac\xd7\xdb\x58\ -\x96\x85\x10\x02\x5d\x17\x78\x5e\x44\x14\x86\x40\x8c\x65\x59\x28\ -\x3b\x00\x8e\x3a\x32\xab\x0a\xe2\x38\x02\xe5\x3d\x8d\x7c\x2f\x70\ -\xa5\x94\x1f\x01\xf9\x37\x65\xf3\x5d\x0f\xc3\x30\x3a\x01\x27\x8f\ -\x18\x89\x61\x18\x28\xaa\x4a\x28\x93\xc9\xbe\xe5\xba\x58\x96\x45\ -\xbd\xd5\xfc\xa6\xa2\xaa\x2f\xa5\xad\xd4\x4b\x6d\xcf\x1d\xd7\x4d\ -\x6b\x56\x00\xed\x20\xf8\x96\xae\x6a\x5f\x99\x9f\x9f\x97\x6b\xcb\ -\x2b\x64\x3a\x9a\xeb\xce\xdd\x79\x8a\xbd\x7d\x8c\xec\xdb\x8f\x99\ -\xcb\xf3\xd2\x6b\xaf\xe3\x0b\x95\x7d\x53\x87\x99\x5b\x5c\xe4\xe8\ -\x83\xa7\xf9\x5f\xff\xe4\x4f\x58\xd9\x2c\xf3\xfb\xbf\xff\xfb\xdc\ -\x9c\xbe\xc5\x5f\x7e\xfb\x5b\x64\x32\x39\x56\x56\x56\x38\x79\xec\ -\x28\x77\xef\xcc\xa2\x04\x01\x5d\x96\xc1\xde\x81\x41\xfe\xc5\x3f\ -\xfb\x1d\x86\x7a\xbb\xf1\x5b\x6d\x26\x06\x6d\x2e\x5d\x5a\x60\x74\ -\x74\x04\x45\x4b\xdc\xc9\x5a\xdd\xe3\xfa\xcc\x34\xf7\x3f\x7c\x8c\ -\x96\x0f\x0d\x0f\x86\x8a\x70\xab\x0a\xdf\xfb\xd1\x4f\x79\xe7\xe2\ -\x05\xca\xcd\x26\x2d\x27\x60\x7c\xff\x04\x6b\x95\x6d\xbc\xc0\x27\ -\x0c\x43\x3c\xcf\x63\xb0\x7f\x00\x21\x04\x32\x8a\x68\x35\x9a\xe8\ -\x42\xe1\x63\x8f\x3e\x46\x21\xd7\x45\xe0\xb8\xdc\xbc\x7e\x03\xdb\ -\x4a\x71\x60\xff\x7e\x08\x02\xa6\x26\xc7\x28\x15\x73\xcc\xde\xbe\ -\x43\x6f\x5f\x89\x57\x5e\xf8\x09\x9a\x0a\xfb\x46\x46\xc8\xa4\x0c\ -\xee\xde\x9e\xe6\xb1\x87\x4e\x23\xe2\x90\x7a\x79\x9b\x76\xbd\x42\ -\x7f\xa9\x44\xca\x32\xa8\xac\x6f\xd2\xdf\x55\xe4\xd1\x07\x4f\x8b\ -\x1d\x5f\x5a\xd7\xa0\xed\x44\xb4\xdb\x4d\x59\xcc\x77\x09\xbd\x33\ -\xc7\x86\xbe\x24\x0a\x43\x74\x45\xec\x4e\xbc\x71\x1c\x23\x15\xb9\ -\x0b\xe4\xdf\x64\x13\xfb\x23\xd3\xba\xf3\xf7\xa3\x30\x44\x4a\x89\ -\xa2\xa9\x08\x45\xe9\xe4\x3a\x93\xcd\x0d\x63\x74\x4d\xe9\x84\x67\ -\x92\xcd\x09\xc2\xaf\x19\xba\xf6\xc7\x1b\xb5\xba\x3c\x7f\xe1\x12\ -\x6f\xbe\xfe\x06\xa7\x1f\xbc\x1f\xaf\xed\x70\xfe\xd2\x45\x9e\x7b\ -\xee\x33\xec\x9b\x3c\xc0\x76\xad\x46\xb5\xe5\x33\xb7\xba\x46\xba\ -\xa7\x1f\x2d\x93\x65\x76\x79\x95\x42\x4f\x0f\xff\xf1\xcf\xfe\x9c\ -\x6d\xc7\x23\x53\x2c\xb2\xb6\xba\x81\x6e\x1a\xd4\x1a\x2d\xc2\x38\ -\xa2\xa7\xbb\x84\x2a\x24\xb6\xa6\x61\x0a\xc1\x48\x6f\x0f\x9f\xfd\ -\xf8\x53\xdc\x9d\xbe\xc9\x7f\xfd\xe5\x27\x58\xab\x48\x2c\x5d\xf0\ -\xea\xeb\xe7\x49\xa5\x52\xc4\x52\xa0\xe8\x1a\x7f\xfb\xa3\x1f\xe2\ -\x86\x21\x91\x50\x98\x3a\x76\x82\x5a\xdb\x65\x60\x74\x9c\xf9\xb5\ -\x75\xce\x5f\xb9\x4e\x33\x08\xf0\x63\xa8\x97\x2b\x88\xb4\x85\x91\ -\x36\xd0\x0c\x95\x76\xbb\x8d\x2a\x14\xd2\xe9\x34\x9a\xa2\xe0\xb4\ -\x12\x8b\x40\x57\x54\x46\x87\xf6\xb0\x74\x77\x1e\xdb\xb4\x68\xd6\ -\xea\x7c\xf9\x73\x5f\x40\x01\x52\xa6\x41\x36\x93\x22\x8a\x03\xf6\ -\x0c\xf6\x62\xa5\xe0\xfa\xd5\x3b\xec\x1d\xea\x47\x53\x25\x93\x23\ -\x19\x2a\xe5\x88\xf9\x3b\xb7\x18\xea\x2b\xb1\xba\x30\xc7\xf1\xc3\ -\x87\xa9\x57\x2b\x5c\x78\xf7\x1d\xda\xb5\x2a\x1f\x3f\xfd\x28\x3f\ -\x7b\xe9\x65\xfa\xfa\xfa\x78\xe8\xa1\xd3\xa4\xd3\x69\xb2\xd9\x2c\ -\xf9\xb4\x2a\x62\xa0\xd5\xf4\xbe\x95\xcb\x98\x5f\xd1\x00\xdf\x0d\ -\x51\x15\x30\x74\x0d\x24\xb4\x5a\x6d\x2c\xcb\xf8\x08\xc8\x1f\x01\ -\xb9\x13\x98\x0a\x23\x62\x01\x8a\x9a\x24\x4e\xc2\x38\xc2\x0b\x22\ -\x84\xa2\xa1\xea\x0a\x81\x84\x46\xdb\x95\x29\xdb\x12\xf5\x96\x2b\ -\xa7\xa7\xa7\x59\x5b\x5f\x67\x73\x7b\x8b\xae\xee\x12\xb3\xb3\xb3\ -\xec\x9f\x98\xc0\x34\x75\xf6\x8f\xef\xc3\xb6\x33\xfc\xf0\xf9\x1f\ -\x93\xca\xe6\xb0\xf3\x45\x84\x61\x31\x32\x75\x98\x74\xb7\x4e\x0b\ -\x58\x29\xc3\x5b\x67\x2f\x71\xfe\xfa\x0d\xde\x7e\xf5\x4d\xb0\xd3\ -\x88\x74\x06\xcd\x34\xe8\xe9\xed\x25\x8e\x63\xca\x95\x2d\xfc\x6a\ -\x8d\xfb\xee\xbf\x8f\x27\x1f\x3a\x4d\x79\x65\x89\xc6\xfa\x3a\x4b\ -\x77\xa6\x69\x6e\x6d\x32\xb5\x6f\x94\x7d\xa3\xfb\x38\x7e\xdf\x69\ -\xde\x7a\xf7\x2c\x95\x4a\x8d\xb6\xeb\xb0\x5d\xab\xb2\xb0\xb2\x4a\ -\xc3\xf1\xe8\x1b\x1a\x46\xb7\xb3\x8c\x1d\x98\xa2\xd2\x74\xb8\x76\ -\xfb\x0e\x5e\x20\x68\x47\x21\xa8\x1a\xd9\x6c\x9a\x7a\x73\x93\x54\ -\xca\xa0\xb5\xb5\x85\x96\xcd\x12\xb6\xdb\xa0\xeb\xb0\xb5\x05\xc5\ -\x22\xf8\x21\x9a\x61\xa0\x44\x92\x5c\x26\xcb\xd6\xca\x2a\xa5\xee\ -\x12\x96\x69\xf2\xc4\x93\x4f\x32\xbf\xbe\x84\xe3\xba\xdc\xb8\x7e\ -\x15\x85\x98\x8c\x65\x51\xcc\xd8\x7c\xfe\xd3\x9f\xe2\xf4\xf1\x51\ -\xd2\x3a\x34\x36\x7d\x6a\x1b\x6b\x34\xb7\x36\xe9\x4e\x67\xb8\x72\ -\xe1\x2c\x47\x0f\x1e\x64\x6c\x74\x14\x45\xc2\xcb\x2f\xbe\xc0\xd0\ -\xd0\x10\xa6\x69\xb2\xb8\x34\x4f\x5f\x5f\x1f\xdd\xf9\x2e\xba\x8b\ -\x05\x86\x87\xfa\xc8\xa7\x4c\xb1\x4b\x74\xf1\x3c\x14\x04\x96\xa1\ -\xa1\x20\x88\xa2\xe8\x7d\x20\xfe\x08\xc8\xbf\xa9\xda\x38\x0a\x3a\ -\x26\x9a\x40\x51\x55\xa2\x48\xe2\x86\x11\x9a\x6e\xa2\xa8\x50\x69\ -\xb6\xcb\xd9\x8c\x5d\xf4\x62\xc6\xdb\x6e\x74\xe7\xe6\xcc\x34\xd3\ -\x33\xb7\x18\x1a\x1a\xa2\xab\x54\xe4\xe6\xed\x5b\x1c\x3b\x76\x0c\ -\x43\xd7\x51\x14\x41\xab\xde\x64\x76\x76\x96\x7c\xb1\xc4\xe8\xbe\ -\x49\xf4\xac\xc9\xd9\xab\x73\xd4\x82\x08\x57\xd5\xf9\x4f\xdf\xfa\ -\x2e\x87\x1f\x78\x80\xb5\xed\x1a\x97\x6e\xce\xa0\xea\x16\x6e\x14\ -\xa1\x68\x06\xba\x65\xe2\x06\x3e\x4e\xbb\xcd\xc4\xfe\xfd\xcc\xde\ -\xbe\x49\xec\xb8\x14\xb2\x36\x47\xf7\x8d\xe1\x56\xb7\x79\xf8\xc4\ -\x31\x66\x6f\x5c\xe5\x33\xcf\x7c\x9c\xe1\x81\x7e\x7a\xba\x0d\xa6\ -\xef\x6c\xb2\xbc\xbc\xcc\xfe\xc9\x49\x86\xfb\x6d\x5e\x3d\x77\x87\ -\xa5\xd5\xc4\x27\xde\xae\x36\x29\xf4\xf4\x51\x69\x39\xdc\x5d\x5e\ -\xc5\x8f\x14\xaa\x4d\x07\xc5\x30\xf1\x02\x17\x45\x05\x29\x23\x1a\ -\xf5\x1a\xa5\x81\x01\x1c\xc7\x41\x33\x74\x6a\xdb\x5b\xe8\x1d\x5f\ -\x79\xf5\xf6\x1d\xf4\x74\x86\xa0\xdd\xa6\x7f\x78\x98\xed\x8d\x4d\ -\x00\xf2\xdd\x45\x36\xd7\x37\xc0\x71\xc8\x0e\x0d\xd0\xaa\xd7\x19\ -\xee\xef\xc3\xad\x57\xa9\xac\x2f\x73\xe2\xe0\x14\xbf\xf3\x85\xcf\ -\xe3\x56\xcb\xec\xed\xe9\xa1\xcb\xd4\xb1\x55\x0d\x5b\x53\xb8\x78\ -\xf6\x5d\x32\x29\x9b\x7d\x93\xfb\x29\x16\x6d\xca\xe5\x26\x37\xa7\ -\x6f\x50\x2c\x16\xc9\x66\xd3\xbc\xfa\xca\xcb\xa4\x2c\x83\x2f\x7c\ -\xee\x33\x04\x9e\x4b\x4a\xd7\xe8\xc9\xe6\x84\xb6\x3b\xff\x86\xe8\ -\x8a\x46\x1c\x85\xbb\x79\xe4\x8f\x80\xfc\x1b\x6d\x56\x77\x28\x96\ -\x42\x21\x0c\x43\x14\x45\x43\x2a\x0a\x91\x84\xba\xe3\x7e\xb3\xe9\ -\x7a\xff\x66\x75\x6d\x83\x1b\xb7\x6e\xb3\xbe\xb1\x49\x2c\x20\x95\ -\xce\xa0\xeb\x3a\x8e\xe7\x91\x2b\xe6\xe9\x1f\x1c\xa4\xd5\x68\xe0\ -\x39\x6d\xf2\xb9\x02\x83\xc3\x43\x0c\x0e\xf5\xd0\x74\xc1\x57\xe0\ -\xca\xed\x55\x6e\xaf\xac\xf1\x97\x7f\xfb\x23\xb6\xbd\x88\xc8\x34\ -\xd1\xed\x2e\x1a\x8e\x47\xa9\x7f\x88\x28\x06\x3f\x08\xd9\xbe\x35\ -\x0d\xbd\xbd\xa0\x2b\xb0\xb1\x41\x76\x7c\x8c\x56\xad\x8c\xa9\xc4\ -\x38\xeb\x2b\xec\x1d\xee\xe7\xc8\xf8\x28\x93\x23\xc3\x6c\xaf\xad\ -\xf0\xf4\xa3\x0f\x32\xde\x9f\x45\x57\x22\x66\x66\x6e\x33\x3e\x31\ -\x81\x14\x0a\xeb\x1b\x9b\x34\x1d\x97\xfd\x93\x87\x68\xb4\x3d\x6a\ -\x2d\x97\x9b\xb7\xee\xf2\xce\xc5\xcb\xcc\x2d\xac\xb2\xbc\xba\x46\ -\xb1\xb7\x8f\xb6\x17\x73\xf4\xc4\xfd\x2c\xae\x6c\xd0\x68\xb7\x12\ -\x06\x59\x14\xd0\x74\x1d\xb4\x94\x89\x61\xa7\xf0\xe2\x10\xa1\x28\ -\xb8\x4e\x1b\x23\x95\xc2\xdf\xde\xc2\x1e\x1c\xa4\xbd\xb6\x06\xba\ -\x09\xd2\xa2\x2b\x9b\x43\x55\x05\x0a\x31\x86\xaa\xb0\xb6\xb4\x40\ -\x5c\x2d\x93\x4a\x59\x98\x4a\x4c\x77\x3a\xc5\x91\xf1\x31\xfe\xab\ -\xff\xfc\x77\x18\x2c\x2a\x98\x40\xad\x16\xa3\x29\x82\xe7\x9f\x7f\ -\x9e\xa1\xa1\x21\x54\x55\x25\x08\x3d\xb6\x37\xd6\x49\xd9\x16\xed\ -\x46\x95\xea\xf6\x16\x5d\xb9\x2c\xd9\x94\xc5\x70\x7f\x0f\x13\xa3\ -\xa3\x0c\xf5\xf7\xfd\xa1\x2d\xf4\xaf\x0b\x62\xa2\x28\xc4\x12\xea\ -\xfb\x08\x21\x1f\x05\xbb\x7e\x6d\xf2\xb5\x3b\x18\x53\x7e\xf9\x45\ -\xff\xa2\x8b\xfb\xf7\x1e\xf7\xcb\x0e\x8e\xbc\x10\xd5\xd0\x90\x12\ -\x5c\x2f\xc0\xb2\x75\x22\x60\xfa\xf6\x82\x7c\xe7\xfc\x79\x36\xca\ -\xdb\x0c\x8f\x8c\x32\x36\x31\xc1\xda\xe6\x06\xed\xb6\xcb\xe0\xf0\ -\x50\x92\x4f\xed\x2b\xb1\xb2\xb1\xcd\x85\x4b\x17\xb1\x2c\x8b\x42\ -\x77\x0f\x6d\xd7\xa1\xde\x76\x91\x8a\x41\xae\xd4\xc3\xb9\xab\xd7\ -\x99\x5d\x59\x27\x5d\xea\xe7\xec\xd5\x1b\xb4\xa4\x20\xd7\xdd\xcb\ -\xcc\xf4\x0c\x56\xb1\x97\x48\x82\x6a\x9a\xb8\x8e\x87\x6a\x99\x44\ -\xad\x16\x44\x3e\x4a\x57\x0e\x11\x47\x14\xb2\x36\xb1\xd7\x22\xa8\ -\x57\xe8\x4e\x9b\x28\xbe\x83\xad\xc2\xe7\x3f\xfb\x29\xac\xd0\xe5\ -\xd3\x8f\x9d\x64\x7d\xe1\x0e\x73\x73\xf3\x84\x61\x48\xa1\xd8\x8d\ -\xa2\x28\xbc\x73\xf6\x1c\x93\x53\x47\x88\x25\x04\x52\x41\x51\x0d\ -\xbc\x08\xda\x6e\xc8\xc2\xe2\x12\xa6\x65\x73\x67\x7e\x99\x9e\xe1\ -\x09\x96\xd6\x36\x29\xf5\xf4\xd0\x70\xdb\xf8\x71\xc4\xb5\xe9\x1b\ -\xa4\x0b\x45\x3c\x19\x11\x6b\x2a\x95\x56\x03\x61\x18\x68\x29\x9b\ -\x48\x81\x30\x86\xb8\xd1\x84\xb6\x07\xb1\x0e\xc2\xc0\xca\x66\x09\ -\x3c\x87\xa8\xd5\xa4\xd4\x53\xc4\x77\x1d\x86\x07\x7a\xf1\x9b\x75\ -\x9a\xd5\x6d\x72\x96\x89\x1e\x87\xec\xdb\x33\xc8\x63\x0f\x3f\x4c\ -\x4a\xd7\xa8\x6e\xac\x31\x31\x3a\x8a\x42\xcc\xf5\xeb\xd7\xd9\xbf\ -\x7f\x1f\xb5\x4a\x95\x8b\x97\xce\xb3\xbd\xb9\x41\x65\x7b\x9b\x81\ -\xbe\x3e\x26\xc7\xc7\xc8\x67\x52\x94\xb7\xb7\xd0\x90\x1c\x9c\x9a\ -\xe4\xc4\x91\xc3\xf4\xa5\x73\x42\x07\x0c\xf9\x5e\xea\x79\x27\xab\ -\xb0\x23\x57\x62\x57\x0a\x94\x0f\x97\x89\x7f\x80\x8c\x7c\xf0\x44\ -\xf9\x77\xc9\xd8\x6f\x26\x90\xe3\x84\xb6\xf7\x21\x03\x15\xdf\xc3\ -\x01\x4a\x3e\x7e\x0f\xd8\xca\xfb\xc6\x5d\x74\x02\x53\x9d\xef\x91\ -\xd1\xee\x2c\xac\xc8\x84\x5d\xa4\x28\x49\x70\x24\xf2\x62\xa2\x20\ -\xc2\xb0\x75\x08\x93\xf4\xa5\x62\x42\xab\x0d\x76\x26\x11\xd0\xb6\ -\x0b\xd7\x66\x6e\xca\x37\xdf\x3a\x83\x61\xa7\xf8\xe4\xa7\x9f\x63\ -\x7e\x69\x11\xc7\xf1\xc8\x77\x17\xd9\xbb\x77\x0f\xb5\x5a\x0d\xcf\ -\xf3\xb8\xbb\xb4\x8c\x9e\xce\x92\xee\xea\x22\x53\x2c\x62\x66\x0c\ -\x3c\x05\x6e\x2d\xd5\x78\xf1\x8d\x37\x78\xed\x9d\xf3\x6c\x54\x6a\ -\xd8\xf9\x1e\xca\x8d\x26\x42\x35\x19\x18\x1a\x01\xa1\x52\xaf\x37\ -\x71\x82\x90\x28\x0a\xc0\x4a\x81\x26\x20\x08\x49\xe7\xf3\x20\x63\ -\x5a\x5b\x5b\x64\x73\x36\xf9\xb4\xc9\xf6\xf2\x12\xfb\xf7\x0e\x71\ -\xe9\xed\x37\xd8\xd3\xd7\xcd\xc1\x7d\xe3\xfc\xd6\x73\x9f\x60\xfa\ -\xe2\x05\x06\x6d\x8b\xc9\x91\x61\x0c\xc3\x60\x63\x63\x83\x13\x27\ -\x4e\x10\x86\x21\xf3\xf3\x8b\x94\x7a\x7b\x59\x5c\x5c\xc6\xce\xa4\ -\x11\x28\x3c\x78\x6c\x3f\x0b\x5b\x6d\xe6\xe6\xe6\x19\x1d\x1f\xc7\ -\xf5\x03\x36\x2a\x0d\x9c\x20\x24\x57\xc8\xd3\x6c\xb5\xb8\x7b\xf7\ -\x2e\xe5\x46\x8d\xde\xa1\x61\x96\x36\xd6\xf9\xf1\xcf\x5e\x25\x50\ -\x15\xac\x7c\x37\xbe\xa6\x53\x6e\x3b\xa8\x76\x86\x56\xdb\x05\x45\ -\x27\xad\x5a\x84\x4e\x80\xb7\xb2\x0a\x76\x9a\x94\x65\x12\xc7\x31\ -\xa5\x62\x3e\xf9\x6f\x9a\xc4\x6d\x35\x69\xb7\x6a\xf8\xed\x36\x22\ -\xf4\xe8\xee\xca\x71\xe4\xc0\x14\x47\x26\xc7\x38\xb9\x7f\x2f\xe3\ -\x23\xfd\x54\x2a\x0d\x4c\x33\xc5\x8d\x6b\x37\x90\x52\x32\x35\x79\ -\x90\x3f\xfa\xa3\x3f\xe2\xe3\x4f\x3c\xc9\xec\x9d\x5b\x68\x8a\xe4\ -\xf3\x9f\xff\x2d\xd6\x56\x17\xb9\x7c\xe9\x22\xf5\x7a\x95\xcf\x3c\ -\xfe\x38\x4f\x1f\xbf\xef\x0f\xf3\x3a\x5f\x07\x08\xe3\x38\x09\xd4\ -\x79\x2d\x52\xa6\x41\x14\x27\xe9\x43\x43\x37\x11\xa8\xc4\x12\x54\ -\x14\x84\x80\x38\x06\xcf\x0b\x31\x0c\x0d\xd1\x61\x90\x2a\xe2\x1e\ -\x94\x7e\x10\x16\x8a\x44\x0a\x90\x22\x26\xba\x67\x82\x10\x92\x5f\ -\x0b\x8a\xe8\xaf\x07\x90\x77\xb9\x79\xe2\x1e\x20\x27\xfb\x1d\xa0\ -\x2a\x28\x1f\x98\x5b\xdf\x0f\xe4\x1d\x33\x59\x4a\x89\x50\x24\x4a\ -\xe7\xb5\x22\x34\x5a\xcd\x26\x86\x61\x63\xe8\x1a\x6e\x3b\xb9\x79\ -\x61\x08\x86\x01\xcb\x2b\x55\xd9\x3f\x9c\x17\xcd\x36\xbc\xfa\xfa\ -\x5b\x72\xa3\xbc\xc5\x66\xa5\x8c\x9e\xb2\xb8\xff\xc1\xd3\xfc\xe4\ -\xe5\x97\xe8\xee\xef\x45\xd3\x4d\x74\x5d\xc7\x4a\xdb\x6c\x6e\x6e\ -\x12\xc7\x31\x42\x51\x19\x1e\x9f\x20\x57\xea\xc3\xc8\xa4\x99\x5d\ -\x5b\xe5\xf5\xf3\x17\x39\x7b\xe3\x26\x15\x2f\x40\xc9\x64\x91\x7a\ -\x8a\x74\xb6\x80\xeb\x7a\xac\xad\x6e\x21\xa4\x82\x6c\x36\xc1\xb4\ -\x31\xec\x14\x7e\xec\x83\x22\x50\x0d\x63\x37\x80\x63\x69\x2a\x91\ -\xe7\x50\x5e\x5b\xc3\x54\x62\xfa\x0a\x39\x36\x16\xef\xf2\xe4\xa3\ -\x0f\x92\xd6\x55\x9e\xfe\xd8\xa3\xf4\x75\x77\x53\xb0\x2d\xd6\x67\ -\xee\xf0\xc8\x7d\x07\xa8\xd6\x23\xae\x5c\xb9\xc2\xc0\xc0\x00\xbd\ -\xbd\xbd\xcc\xce\xce\x32\x30\x30\x80\xe7\x79\x14\x8b\x05\xa4\x84\ -\x7a\xbd\x4e\x6f\x6f\x8e\xe7\x9f\xff\x29\x4f\x3d\xf5\x14\x86\x05\ -\x2f\xfe\xf4\x6d\x8e\x1c\x3b\x8a\x61\x59\x6c\x6f\x6f\xb3\xb6\xb6\ -\xc6\xd4\xd1\xc3\x54\x1b\x4d\x5e\x79\xe3\x0d\xfe\xaf\xbf\x7d\x9e\ -\xc8\x34\x71\x15\x9d\xc0\x4c\x51\xf3\x02\xd0\x0c\x48\xd9\x0c\x0c\ -\x8f\xb1\xbe\xbc\x02\xb1\xc0\xd6\xcd\xe4\xfe\x04\x09\xb9\xc6\x75\ -\x9c\x0e\x91\x5c\xa2\xa4\x0c\xf2\x5d\x19\x32\x76\x8a\xc8\x73\x69\ -\xd5\xaa\x48\xcf\x27\xa5\xc6\xec\x29\x65\x31\x75\x05\x5d\xd1\x99\ -\x3a\x70\x90\x6c\xb6\x40\x18\xc4\xf8\x6e\xc0\x2b\xaf\xbc\x82\x6d\ -\xdb\x04\xae\xc7\xec\xdc\x0c\x56\x4a\xc3\xd4\x75\x4e\xde\x77\x94\ -\x38\x0e\xd1\x7d\x9f\x67\x8e\x1c\xe1\xe0\xe0\x10\xfb\xc6\xf7\x52\ -\xca\x99\xa2\xde\x6a\xc9\x42\x3a\x2d\x14\x42\x04\x31\x02\x91\x00\ -\xda\x4f\xdc\x26\x5d\x37\xdf\xc7\x09\x88\xa2\xf7\x64\x6a\xb7\x72\ -\x4b\x7e\x00\xd0\xe2\xc3\x80\x2c\x01\xe5\x23\x20\x7f\xb8\x46\x56\ -\x3e\x04\xc8\xf2\x7d\x0a\x5b\xe1\x1e\xdc\x27\x43\x98\xb0\xf8\x76\ -\xca\x03\x65\x84\x50\xe4\xee\x7d\x88\x89\x10\x8a\x4e\x28\x23\x2a\ -\xf5\x06\xb9\xae\x02\x41\x10\x80\xa2\x62\xaa\x2a\x0a\xf0\xc3\x1f\ -\xbd\x22\x97\x56\x56\xa9\x36\x9b\xf4\x0d\x0d\x33\x38\x3a\xc2\xdd\ -\xa5\x65\xa4\xae\xf3\xf8\xc7\x3f\x8e\x30\x05\x51\x0c\x0d\x27\xe6\ -\xfa\x8d\x69\x6c\xdb\xe6\xc0\xa1\xbd\x58\x2a\xfc\xf0\xa7\x17\xb9\ -\x7a\x73\x9a\x6b\xb7\x66\xd8\x6a\xb6\x69\x49\x68\x47\x31\x32\x65\ -\x63\xe6\xba\xd0\x52\x36\xb5\xcd\x72\xc2\x1d\xd6\x4c\xba\x32\x5d\ -\xd4\x2a\x55\x4c\x55\xc3\x4e\x99\x64\x6c\x9d\x74\xca\x62\x63\x63\ -\x83\x4a\x75\x9b\x8c\x9d\x26\xa5\x6b\x88\x28\x42\x89\x03\x0e\x8c\ -\x8d\xb1\x32\x7f\x87\x53\x47\x0f\xf1\xd5\x2f\x7f\x9e\x42\x5a\xe1\ -\xc6\x95\x19\xee\x3f\x31\x49\xb3\xec\x30\x73\xe5\x0a\x7d\xc5\x12\ -\x87\x0e\x8d\x33\x37\xb7\x8a\x10\x82\xd1\xd1\x7e\xae\x5f\x9f\xc5\ -\xf7\x7d\x0e\x1f\x9e\x42\xd7\x41\x51\x20\x0c\xa1\x52\x69\x71\xe9\ -\xd2\x25\x9e\x7d\xf6\x11\x16\x97\x6b\x34\xea\x2d\xba\x7b\x7b\xc8\ -\x64\x74\xee\xcc\x2d\xa2\xeb\x3a\xa3\xe3\xfd\x5c\xb9\x31\xcf\xf0\ -\xf8\x5e\x6e\x2f\x6d\xf0\xfa\xd9\xf3\x6c\x34\xda\x5c\x9b\x5f\x60\ -\xbd\xde\xc6\xef\x4c\x60\x77\x2e\x5d\x82\x74\x0e\x54\x9d\x3d\x83\ -\x43\xb4\x9b\x2d\xbc\xb6\x03\x40\x73\x73\x03\x4c\x03\x4c\x13\x34\ -\x41\x2a\x6d\x91\xb6\x53\x10\x06\xb4\x6a\x55\xdc\x7a\x13\xc2\x00\ -\xd9\x6e\x80\x65\xd1\x95\x2b\x60\x18\x26\xb9\x6c\x91\x62\xb1\xc4\ -\xf8\xde\x31\x1e\x7e\xf8\x30\x37\x6f\xae\x30\x7f\x77\x8e\x1b\x37\ -\xae\x61\xa7\x0d\x9a\xb5\x1a\x86\xa9\xd0\x6e\x37\xe9\xcd\xda\x4c\ -\x15\xba\x30\x5c\x87\xa3\x07\x27\x19\xee\xeb\xe1\x99\xd3\xc7\xfe\ -\x30\x8a\xe5\xd7\x82\x66\xa3\xd0\x9b\xcb\x09\x19\xbb\x28\x71\x8c\ -\xae\xea\xbb\xb6\xb7\xe7\x05\x28\x8a\x82\xa6\x9b\x04\x71\x02\xd0\ -\x04\x8c\x1d\x2b\xae\x23\x63\x52\xee\x50\x6d\xef\x2d\xc3\x8c\x91\ -\xe2\x3d\x8d\x2c\x63\x7e\x2d\x82\x6c\xbf\x76\x3e\xb2\xfc\xc0\xbb\ -\xf2\x1e\x1b\x67\x07\xc4\xbb\x43\x26\x95\x04\xe2\xb2\x43\xc9\x15\ -\x20\x62\xd9\x99\x3d\xe3\xdd\x93\xea\xed\x26\x29\x3b\x47\x4c\x52\ -\x72\xd7\x09\x6f\x8d\x9f\x39\xfb\xf6\x9d\xab\xe7\xae\x10\x47\x0a\ -\x23\xe3\xfb\x78\xf8\xb1\xc7\xb8\xbb\xba\xca\x9d\xc5\x45\x0e\x1e\ -\x3b\x81\x91\x49\xd3\x08\x62\xd4\x94\xc2\xb5\xe9\x25\x54\xd3\xc2\ -\xb4\x6d\xb6\xca\x55\xce\x9e\x3d\xcf\xda\xc6\x3a\x2d\x27\x60\x79\ -\x2d\x99\x04\xd2\x85\x6e\x52\x85\x02\xed\x58\x52\x77\x5d\xfc\x28\ -\x4e\x6c\x38\x55\x47\x51\x35\xe2\x20\x46\x45\x30\x50\xea\xc5\x73\ -\x5d\x9a\xe5\x4d\x44\xbb\x02\xa1\xc7\xf1\xe3\xc7\x09\x3c\x9f\xbb\ -\xb3\x77\x38\x34\x75\x90\xa7\x3e\xf6\x18\xa3\xc3\x43\x98\x9a\x20\ -\x63\x19\xac\xcc\xdf\x25\x6b\xe8\x1c\x3f\x38\xc4\xcc\xcc\x22\x22\ -\x8e\x98\xda\x3f\x4a\x5a\x85\x1f\x3c\xff\x2a\xcf\x3d\xf7\x38\xdb\ -\xdb\x2e\x0b\x0b\x0b\xf4\xf7\xf7\x13\x86\x21\xb7\x6e\xdd\xe2\x81\ -\x07\x1e\x20\x8e\x63\xc2\x30\xa4\xbb\xdb\x62\x7a\x7a\x09\xc7\x71\ -\x38\x70\x60\x3f\x67\xce\xbc\xc3\xe4\xe4\x14\xa5\x52\x8e\xed\xed\ -\x06\x33\x33\x37\x79\xe8\xa1\x07\x58\xd9\x28\xb3\xb6\xb1\x4e\xcf\ -\xd0\x10\xe9\x7c\x8e\xcd\x46\xc0\xa5\x5b\x77\x18\x99\x9a\xe2\xcf\ -\xbf\xfb\x7d\xde\xbd\x74\x85\xda\xe2\x32\x85\xc3\x87\x69\x78\x1e\ -\x51\x2c\xb1\x0c\x13\xa7\xd9\x04\xa9\x50\x2c\x16\xd1\xac\x14\xd9\ -\x5c\x8e\xa5\xf5\x55\x3c\xcf\x05\xdf\x49\xee\xae\xaa\x62\x68\x3a\ -\x19\x23\xa1\x85\xc6\x48\x6a\x8d\x16\xbe\x1f\x10\x79\x21\xbd\xbd\ -\x03\xa4\x52\x69\x56\x56\xd6\x30\x4d\x13\x55\x28\x08\x21\x89\x02\ -\x8f\x6c\x36\x4d\xa5\xba\x45\x14\x7b\xf8\x8e\x43\xce\x36\x19\xcb\ -\xe7\x71\xb7\x37\xe8\x2b\xe4\x39\x39\x35\x41\xc9\xb6\xf8\x17\x5f\ -\xfa\x04\x0a\x9c\xd3\xc2\xe8\xeb\x16\xf2\x25\x8d\x08\x4d\x80\xa2\ -\x08\xa4\x94\x84\x61\x98\xc8\x86\xa6\x10\x0b\x8d\xb8\x53\x46\x79\ -\x6f\xfd\x95\xb2\x13\x2c\xeb\xd4\x47\xef\xda\x83\x3b\x72\xd5\x01\ -\x6e\xfc\x11\x90\x3f\x3c\x72\x20\x3f\x00\xf0\x7b\x81\xbc\x0b\xe2\ -\xdd\x68\xb3\x96\xd0\x24\x3b\xd5\x71\x42\x02\x52\x22\x44\x62\x70\ -\x4b\x01\x6d\xb7\x85\x65\xa7\xa9\x7b\xad\x71\xdd\x4c\xcd\xae\xd7\ -\xca\xf2\xe6\xad\x19\x96\x37\xd6\xb0\x53\x39\x52\x5a\x8a\xad\x72\ -\x9d\x58\x51\xd9\xd8\xae\xa0\xa6\xd3\x14\x06\x06\xa9\xb6\x5d\xd2\ -\xc5\x1e\xae\xdd\x99\xa3\xe2\xb8\x38\xa1\xc4\xca\x74\x71\xee\xe2\ -\x65\xca\xf5\x06\x52\xa8\x34\x9b\x4d\x08\x25\xa9\x42\x9e\x62\x4f\ -\x2f\x9a\x95\xa2\xed\xfb\xd4\xdd\x36\x41\x2c\x11\xaa\x92\x50\x0c\ -\xeb\x75\xf0\x42\x8c\x42\x1e\xbf\x5a\xa3\xa7\xa7\x8f\x5a\xa5\x42\ -\x5f\xda\xe2\xe0\x50\x91\xb3\xaf\xbd\xc2\x40\xff\x10\xa7\x4f\x9f\ -\xe6\x33\xcf\x3d\x47\xa9\xa8\x73\xfe\x9d\x1b\x94\x8a\x05\x06\xfa\ -\x7a\x18\x2b\xaa\xd4\x7d\x78\xe3\xe7\x6f\x72\xea\xf8\x31\xf2\x99\ -\x0c\x0b\xf3\x73\x78\x9e\x47\x77\xa9\x97\x9f\xfd\xec\x67\x74\x77\ -\x77\x33\x30\x30\xc0\xd5\xab\x57\x01\x98\x9a\x9a\xe2\xc2\x85\x0b\ -\x8c\x8d\x8d\xed\x16\x3f\xd4\x6a\xb5\x24\x3a\x1c\x04\x98\xa6\xc9\ -\xca\xca\x2a\xc7\x8e\x1c\xc5\x71\x1c\x56\x97\x57\xb8\xef\xfe\xfb\ -\x18\x1b\xdb\xcb\xdf\x7c\xff\x07\x7c\xf2\xb9\xe7\xe8\xce\xa9\x2c\ -\xd4\x60\x66\x7e\x91\xa9\x63\x7b\x68\x03\xdf\xfe\xe1\x59\xfe\xfa\ -\x07\x3f\x22\x5f\xea\x63\xa3\x56\xa5\x16\x87\x68\x29\x93\xd0\x0b\ -\x31\x4d\x13\x5d\x35\x08\xa3\x18\xcd\x4a\xd1\x70\xda\xc4\xa2\xe3\ -\x78\x0a\x12\xe2\x06\x02\x4d\x0a\x4c\x55\xc1\xd0\x75\x1a\xad\x06\ -\x9a\xa6\x81\x14\xb8\xae\x8f\x6c\x7b\xa0\x9b\xa4\xec\x2c\xaa\xaa\ -\xd2\xac\xd7\xb1\x6d\x0b\xcf\x73\x88\x22\x17\x3c\x17\x3d\x97\x22\ -\x68\xb7\xa1\x59\xc7\x2a\x94\x70\x6b\x35\x4c\x24\x63\xfd\x3d\x1c\ -\xde\x33\xc8\x89\x7d\x7b\xc9\x2b\x31\xbf\xf3\xe9\x27\x9f\xb5\xe0\ -\x25\x03\x08\x9c\x16\x9e\xdb\xfa\x96\x6d\x19\x5f\x31\x52\x49\x8d\ -\xb4\xeb\xbb\x08\x23\xd5\x31\xc0\xdf\x03\xf2\xbd\x64\x5c\xe5\x1e\ -\x20\x8b\x5d\xe5\xd1\x11\xd6\x4e\x99\xea\xbd\x14\xd1\x8f\x80\x2c\ -\x3e\x2c\xc6\x90\x54\xc9\xec\x98\xd2\xe2\x7d\x07\x74\x52\x46\x42\ -\x25\xe4\x1e\x93\x28\x96\x28\xa2\x73\x8e\x88\x93\xd4\x89\xef\xa1\ -\x18\x26\x15\xb7\x55\xde\xac\x94\x0b\x67\xce\x9f\xa7\xd0\x5d\xe4\ -\xc2\x95\x6b\x0c\x0c\x8c\x32\x32\x3e\x41\x88\xa0\xd8\xdf\x4f\x3b\ -\x96\xac\x6e\x57\xa8\x3a\x01\x3f\x7d\xeb\x0c\x57\x6e\xcf\x61\x64\ -\x72\x6c\xd6\x1a\x64\x8b\x3d\x58\x99\x1c\xeb\xdb\x65\xea\xf5\x06\ -\x56\x3a\x83\x8c\x40\x28\x1a\x6e\xe0\x83\xd3\x4e\x22\x26\x69\x3b\ -\xb1\x65\x83\x00\x35\x65\xa2\xc6\x90\x4f\xa7\xc8\xdb\x36\x4b\xb3\ -\xb3\xd8\xaa\x8e\xdb\x6c\x70\xfa\xc8\x14\x5f\x7a\xfc\x01\x8c\xc8\ -\xe5\xd0\xc1\xc3\xcc\xcc\xdc\xa2\xdd\x6c\xf2\xe4\xe3\x27\x09\x5c\ -\x58\x5b\xdd\x62\x73\x7d\x8d\x23\x87\x0e\x11\x78\x2e\x84\x21\x0b\ -\xf3\x73\x1c\x3b\x7c\x84\x17\x5f\xf8\x31\x3d\x7d\xbd\x94\x6b\x2d\ -\x4e\xdc\x77\x92\xab\x57\xaf\xf2\xd8\x63\x8f\xb2\xb5\xb5\xcd\xd2\ -\xd2\x12\xc7\x8e\x1d\xe3\xea\xd5\xab\x94\x4a\x25\xf6\xee\x1d\xa0\ -\xd5\x0a\x88\xa2\xc4\x8f\x3e\x78\xf0\x20\xcb\xcb\xcb\x18\x86\x41\ -\x6f\x77\x89\xe5\xe5\x65\xfa\x7b\x7a\xd9\xde\xde\xe4\xd2\xd5\x6b\ -\xec\xd9\xb3\x87\xc9\x03\x07\xb8\x79\xfb\x36\xdd\x03\x43\x64\x8b\ -\x3d\x84\x8a\xc2\xdc\xea\x06\x55\x37\x40\x98\x26\x3f\x7d\xf5\x0d\ -\x7e\x76\xe6\x2d\xda\x9a\x82\x66\xdb\x78\xf5\x06\xd9\x62\x77\x52\ -\xf3\x5c\x6b\xa1\xa4\x2c\xa2\x5a\x1d\x6b\x64\x84\x58\x24\xf4\xd1\ -\x38\x82\xd8\xf3\xc1\x0b\x20\x0a\x41\x48\x14\x05\xe2\xc0\x83\x48\ -\x92\xea\xea\x4a\xc0\xec\xfa\xe8\xe9\x1c\x41\xa5\x42\xcf\xe8\x28\ -\xad\x56\x03\xdf\x77\xb1\x52\x06\x42\xc4\x49\x0c\x44\x01\x2b\x95\ -\x66\x6d\xbd\x0c\x9b\x5b\x4c\x9e\x3c\xc1\xcc\x9b\xaf\xd1\xdf\x53\ -\x24\x23\x03\x9e\x39\x7d\x0a\xad\xdd\xe0\xf7\xfe\xe9\x97\x19\xed\ -\xed\xda\x67\xc3\xac\x46\x4c\x14\x38\x09\x33\x8c\x98\x20\xf0\x11\ -\x9a\x4e\x24\x94\xf7\x01\x99\x5f\x74\x8f\x51\x76\x5a\x1f\xc8\x4e\ -\x47\x97\x1d\x20\xcb\x5f\x0f\x20\xab\xdf\xf8\xc6\x37\xfe\x91\xe3\ -\xe6\xef\x8f\x58\x8b\xf7\x3d\x44\xa2\x61\x7f\x01\xc4\x1d\x5d\xad\ -\x48\x3c\x04\x01\x31\xb1\x88\x13\xb3\x47\xc4\xbb\xc1\x0c\x21\x55\ -\x6a\xd5\xfa\xd7\x32\xe9\xcc\xb9\xf5\xad\x8a\xfc\xee\x77\xbf\x97\ -\x3a\x77\xee\x32\xd3\x33\xb7\x39\x75\xea\x21\x1e\x7a\xf4\x49\xfa\ -\xf6\x1d\xe0\xce\xca\x36\xd2\xb4\x49\x97\x7a\x70\x14\x83\x9a\x1f\ -\xf3\xee\xb5\x1b\xbc\xf0\xfa\x5b\x88\x94\x4d\x3d\x8c\xd1\xb3\x5d\ -\x48\x23\xc5\x7a\xb5\x46\xbb\xd1\xc0\x2a\xf5\xe0\x23\x50\xcd\x34\ -\x66\x26\x87\x61\xa7\x09\x35\x1d\x29\xd4\xc4\xce\xf7\x3c\x68\xb7\ -\x90\x41\x80\x12\x46\xe0\xb6\x29\xaf\x2c\xf1\xb9\x67\x9e\xe6\x5f\ -\xff\xf7\xff\x94\x47\x4f\x3e\x4c\x97\x22\x69\xad\xcf\x33\x98\xcf\ -\xd1\xd7\x95\x63\x7c\xb8\x8f\x7c\x3a\xc3\xd5\xf3\x57\xd9\x58\x59\ -\xe3\xc4\xe1\x7d\xec\xe9\xef\xe5\xe7\xaf\xfc\x8c\xac\x6d\x13\x79\ -\x2e\x77\xef\xcc\x32\x77\xfb\x0e\xc7\x8e\x1e\xa1\xaf\xbf\x9f\x4a\ -\xbd\xc1\xe4\x81\x7d\x78\x5e\x40\xb5\x5a\x23\x9f\xcf\x53\xad\x56\ -\xb1\x6d\x1b\x29\x93\x8a\xa1\x6c\xb6\x0b\xd3\x54\x29\x65\x34\xce\ -\x9c\xbd\xc4\xa9\x53\x87\x99\x9f\x5f\xa6\xa7\xa7\x87\x81\xfe\x3c\ -\x97\x2e\x5d\xe1\xc0\xfe\xfd\xd4\xea\x15\x7a\x4b\x3d\x1c\x3b\x7e\ -\x8c\x4b\x97\x2e\x52\xad\x56\x91\x52\xf2\xfa\x6b\x6f\x60\x9a\x26\ -\x03\xfd\xfd\x14\x8b\x79\x44\x2c\xd9\x5a\x5f\xc3\x34\x74\x72\x85\ -\x0c\x82\x88\x38\x08\x89\x3c\x9f\xc0\x71\x51\x10\x14\xf2\x45\xfa\ -\xc6\x46\x93\xa6\x0a\x08\xfc\x30\x46\x7a\x01\x84\x49\xa8\x08\x45\ -\x47\x53\x34\x4a\x3d\x05\x0c\x4b\x47\xd5\x74\x2c\xcb\xc2\x32\x2c\ -\x0c\xcb\x26\x6d\xa7\xd0\x4c\x93\x28\x08\xc8\xe5\xd2\x64\x33\x36\ -\xbe\xe7\xe2\xb9\x0e\xc8\x18\x55\x11\x78\x41\x4c\xba\xab\x84\xde\ -\xdd\xcb\xc6\xd6\x26\xe9\xee\x22\x46\xca\x06\x55\xe1\xfa\xcc\x2d\ -\x6a\xad\x16\x5b\xd5\x0a\x7e\x14\xff\xcb\xee\xde\xbe\x6f\xe8\xaa\ -\xf2\x6f\x85\x6a\x10\x84\x21\xc4\xa0\x2a\x1a\x42\x26\xf9\x10\x95\ -\xa4\x9d\xd1\x0e\x39\x77\xa7\xea\x59\xd9\xc1\xec\xae\x5f\x2c\xde\ -\xa7\x91\x13\x6b\xe3\x1f\x1f\xc8\xda\xaf\x7d\xa2\xfb\x97\xe6\xf7\ -\x94\x4e\xca\x29\xea\x18\xe0\x32\x89\x60\x0b\xd1\xe9\x22\xd3\x31\ -\x81\x14\xf3\xa5\x5b\x73\xab\xf2\xfb\xcf\xff\x84\x07\x1f\x7b\x8c\ -\x95\xad\x2d\x7e\xfb\xd4\x29\x62\x01\xad\x58\xe1\xfb\x2f\xbf\x86\ -\x59\xe8\xe6\xee\xf4\x15\xaa\x3f\x3f\xc3\xc2\xda\x1a\xe7\xaf\x5e\ -\x45\x18\x16\x7a\xb6\x8b\x7a\xb9\x01\xa6\x05\x0d\x07\x1c\x17\xf2\ -\x05\x08\x23\xdc\xb6\x0b\x7e\x88\xa7\x84\x78\x41\x8c\x6e\x18\x08\ -\x4d\x43\x15\x02\x4d\x4d\x4c\x47\x53\x48\xa4\xef\xa2\x06\x1e\xe3\ -\xc3\x43\x6c\x2f\x2f\x62\xcb\x80\xf3\xaf\x5e\x60\xb0\xa7\xc4\x27\ -\x3e\x76\x92\xa2\x0a\xed\x4a\x99\x73\xef\xbc\x49\x5f\x4f\x2f\xfb\ -\xf7\x1f\xe0\xc4\xd1\x43\x38\x8e\xc3\x5b\xaf\xbf\x8d\x6d\xdb\x94\ -\xf2\x5d\x5c\xbb\x7c\x89\xc9\xc9\x49\x1e\x79\xe4\x11\xa2\x28\x62\ -\x6d\x6d\x8d\x42\x4f\x2f\x13\x13\x13\x4c\x4f\xdf\xe1\xc0\x81\x7d\ -\xbc\xf8\xe2\x4f\x19\x1d\x1d\xc5\xb6\x6d\x9a\xcd\x26\xaa\xaa\xe2\ -\xba\x2e\x42\x80\xa1\xc3\xb5\x3b\xab\xf4\xf4\xf4\xe0\xfb\x49\x04\ -\xbb\x58\xcc\x73\xe6\x9d\x0b\x8c\x4f\xec\x43\x33\x35\x2a\xb5\x1a\ -\xc7\x8f\x1f\x67\x6e\xee\x0e\xc5\x62\x91\x47\x1e\x7b\x88\x8b\x57\ -\xa6\xb1\x4c\x95\xb3\x67\xde\xe2\x93\xbd\x3d\xdc\x9a\x9e\x66\x6c\ -\x72\x92\x56\x65\x93\x2f\x7e\xfa\x13\xdc\x5a\x59\x60\xb3\x56\x23\ -\x65\x65\xa9\x56\xeb\xcc\x2f\xad\xb2\xb4\xba\xc1\xe6\xed\x19\x2a\ -\xf5\x3e\x42\x09\x68\x3a\x18\x26\xaa\x61\x61\xd8\x06\x1a\x22\x89\ -\x6e\x87\x3e\x1b\x9b\x15\xf2\x85\x1c\xba\x69\x52\xde\xda\x4a\xa0\ -\xa3\xaa\xd0\xd8\x4c\xac\x1a\x55\xa5\xbe\x5d\x4e\x48\x32\x22\x09\ -\x83\xfa\x4d\x8f\xb6\xae\x23\x4c\x0b\xb9\xd5\x4a\x2c\xa0\x7a\x03\ -\xbf\x90\xa5\xec\xbb\x0c\xf7\xf4\x20\x6c\x93\xf9\xf5\x15\x56\x5e\ -\x7d\x8d\x5b\xcb\x4b\x2c\x6c\x6c\xf2\xe8\xf1\xa3\x72\x72\xb0\xef\ -\xdb\x59\xcd\xfa\xca\x4e\x40\x4b\x44\xc1\x4e\xc4\x0a\x14\x90\x42\ -\x41\xed\x24\x3d\x65\x27\x5f\x22\x76\x54\xf3\x4e\x9d\xf9\xaf\x21\ -\xc7\xe4\x1f\x1d\xc8\xf2\xef\x21\x6f\x04\x7e\x84\x6e\x18\x80\xc4\ -\x71\x1c\x52\xb6\x9d\xf8\x37\x8e\x83\x69\xeb\xa8\x04\x48\x02\x54\ -\x34\xc2\x58\x22\xc3\x18\xc3\xc8\xd2\x76\x02\xb6\xcb\x75\x79\xe5\ -\xda\x0c\xa9\xae\x02\x13\x47\xef\x67\xa5\xe6\x93\x1f\x9e\xe4\x8d\ -\x8b\x33\x38\x71\xcc\x6a\xad\x46\x43\x5a\x2c\x4c\x2f\xb2\xb0\xbc\ -\xc4\x76\xad\x4a\x28\xa1\x77\xef\x24\x18\x46\x42\xd4\x08\x23\x14\ -\x43\xc7\x0f\x22\x9a\x4e\x1b\x55\xd3\xb1\x7b\x7b\x89\x63\x68\x34\ -\x5a\xd8\x99\x3c\xed\xcd\x2d\x02\x55\x83\x76\x0b\x90\x44\xaa\x82\ -\x47\x48\x5f\xa1\x40\x97\x6d\xe2\x79\x2d\x2c\xdf\xe3\x0b\x1f\x7f\ -\x8a\xde\xae\x0c\x63\xc3\x03\xcc\x5c\xbf\xc6\xf5\x76\x99\x53\x07\ -\x0f\x50\xe8\x2e\x72\xea\x81\x07\x50\x80\xd7\xdf\x7c\x8d\x9e\x9e\ -\x1e\xfa\xfb\x06\x71\x3c\x97\x20\x0a\x71\x5d\x97\xc7\x3f\xfe\x34\ -\x8b\x8b\x8b\xcc\xdc\xbd\xcb\x89\x13\xc7\x28\x37\x5b\xcc\x2e\x2c\ -\x71\xf4\xf8\x04\xaf\xbf\xf9\x1a\xc3\xc3\x83\x9c\x38\x71\x8c\x4b\ -\x97\x2e\x30\x32\x32\xc2\xe2\xe2\x22\x27\x4f\x9e\xe4\xf2\xe5\xcb\ -\x48\x29\x31\x11\x84\xa1\xbf\x83\x0d\x7c\xdf\x25\x8a\x22\x5a\xed\ -\x36\x47\x8f\x1f\xe1\xfc\xc5\x0b\x8c\x8c\xee\xa5\xd1\x6a\x52\xad\ -\xd7\x38\x7d\xfa\x14\x77\xe7\x57\x09\x42\x9f\xaf\xfe\x67\x5f\x24\ -\x88\xe1\xdf\xfd\xfb\xff\x85\xcd\x4a\x9d\xa7\x9e\x7d\x96\xc3\xfb\ -\xc7\x68\x57\xb7\x38\x30\x34\xc0\xe7\x3e\xf1\x08\x86\x02\x4e\x00\ -\xdf\xfb\xe1\x9b\x94\x57\xd7\xe9\xeb\xef\x63\xbd\xd6\x24\x55\x28\ -\x12\xe9\x1a\xa6\x9d\xc1\xb4\xd3\xf8\x8e\x97\x00\xd3\x8b\x92\xa8\ -\x76\x00\x95\xbb\xeb\x60\x58\x98\x3d\x03\x58\xa6\x8d\xe3\x38\xc4\ -\xb6\x24\x95\xb2\x70\x5d\x17\x55\x4b\x82\x54\x51\x14\x60\x18\x06\ -\x96\x65\xe0\x79\x1e\xad\x7a\x0d\x33\xa7\x26\xcd\x01\xfb\xfb\x70\ -\xfc\x36\x61\xa3\xc1\xec\xea\x22\xa4\x2d\x72\xc5\x3c\x4e\x43\xe1\ -\xd2\xda\x06\xb9\xf9\x25\x8c\x6c\x81\xb3\x17\xae\xff\x93\x47\x8e\ -\x9d\x90\x87\xf7\x16\x84\x0e\xe8\xe8\xc4\x9e\x8b\x62\x1a\x10\x86\ -\x08\x11\x83\xaa\xe0\x7b\x1e\xa6\x69\xee\xd6\x36\x8b\x5f\xa6\x61\ -\xee\xa9\x81\xfe\xc7\xd4\xca\xff\xe8\x3e\xf2\xdf\x07\xe4\x28\x0c\ -\x51\x55\x15\xcf\xf3\x10\xaa\x82\x61\x18\x04\x41\x80\xef\x87\xd8\ -\x69\x93\x72\x63\x9d\x7c\x36\x87\x82\xc2\xfa\x76\x45\xf6\x74\xf7\ -\x8b\xab\xd7\x6f\xc9\x17\x7f\xfa\x1a\x8a\x9e\xe1\xc1\x47\x9f\x60\ -\xab\xe9\x72\x7b\x65\x05\x23\x9b\xc7\x53\x34\x66\x57\x57\x58\xdf\ -\x2e\xb3\xd1\x6c\xe3\xab\x06\xdb\x8d\x16\x95\x46\x9d\x30\x4e\x6a\ -\x8f\x35\xcb\x40\x35\x74\x84\xae\xe1\xfa\x1e\xae\xe7\x11\xc7\x31\ -\x9a\x69\xa0\xeb\x46\xd2\x4c\x4f\x4a\x10\x2a\xae\x1f\xa3\xeb\x26\ -\x81\xeb\x20\xe3\x90\x7c\x26\x8b\x6d\xa8\xac\xdc\x9d\xa3\x27\x9b\ -\xa6\xbe\xb9\x41\x5a\x85\x83\x63\x7b\x19\x1b\xec\xe3\xab\x5f\xf8\ -\x1c\x13\x45\x05\x0f\x08\x7d\x78\xf9\x85\x97\x30\x75\x95\xa9\xa9\ -\x29\x7a\x7b\x7b\x69\x35\x9a\xdc\xb8\x71\x83\xc5\xc5\x45\x8e\x1d\ -\x3b\xc6\x40\x6f\x1f\x3d\x3d\x79\xa6\x6f\x2f\x30\x34\x34\x44\xb5\ -\x52\x63\x7e\x7e\x9e\xe3\xc7\x4f\x32\x3d\x7d\x83\x94\x69\x70\xec\ -\xe8\x3e\x2e\x5c\xbc\xc9\x9e\x3d\x7b\xb8\x71\xe3\x06\xe3\xe3\xe3\ -\xdc\xbd\x7b\x97\x28\x8a\x98\x9b\x9b\xdb\xcd\x27\x57\x2a\x15\x86\ -\x87\x87\x29\x14\x0a\xd8\xb6\x4d\xab\xd5\x62\x64\x2c\x01\xbd\xe7\ -\x38\x3c\xfc\xe0\x49\x7e\xf4\xfc\xcb\x9c\xb8\xef\x24\x73\x73\x73\ -\xa8\xba\xce\xf1\x93\xc7\x98\xb9\xbd\xc0\xed\x3b\xb3\xf4\xef\xd9\ -\xc3\xf3\xe5\x61\x10\xf8\x00\x00\x20\x00\x49\x44\x41\x54\x2f\xbe\ -\xc4\x85\x8b\x17\xe9\x1b\x18\xe4\xdf\x7f\xf3\x7f\xe4\xd2\xd5\xbb\ -\x8c\x8f\x8f\xf2\xee\xb9\xcb\x38\x6e\xc8\xf1\xfb\xef\x63\xbd\xee\ -\xf0\xc2\x6b\x67\x38\xfd\xd4\x53\xfc\x4f\xdf\xfc\x9f\x71\x82\x10\ -\x42\x99\x68\x66\xd5\x00\x45\x23\x9d\xca\x60\xa7\xd3\x78\x52\xe2\ -\x87\x49\x7a\xc7\x30\x0c\x84\x10\x84\x61\x88\x94\xa0\x28\x0a\x51\ -\x14\xd2\x6e\xb7\x81\x08\xd3\x4e\x61\x68\x3a\x7e\xe8\x11\x87\x11\ -\xba\x90\x28\x41\x1b\xe9\xfb\x44\xba\x82\x95\x4e\xa1\xa6\x2d\x82\ -\xc8\xa7\xd1\xa8\x20\x9b\x4d\x4c\x53\xc7\xaf\x56\xd1\x9b\x2d\x86\ -\xd2\x19\xfe\xf9\xe7\xbe\x84\xa8\x37\xd8\x3f\x30\xc4\x73\x8f\x1f\ -\xda\x97\x53\x99\x8d\x9d\xa4\x26\xdd\xf7\x1d\x0c\x53\x43\xd1\x55\ -\x88\x82\x0e\x27\x21\xe9\x15\xb6\x9b\x7e\xda\xe9\x46\xb6\x4b\x23\ -\xfb\xf5\x68\x62\xf0\x6b\x0f\xe4\x30\x8a\xd1\xb4\xc4\x4c\x76\xbd\ -\x00\x54\x05\x5d\x53\x3b\xf5\x0e\x3e\xa6\x2e\xf1\x1b\xf5\x6f\x4a\ -\xa1\x7f\xdd\xcc\xe4\x98\x5f\x58\x93\xb7\x97\x56\xb9\x39\xb7\x4c\ -\xf7\x9e\x31\xee\xac\xac\x73\xf0\xd4\x83\xa8\xb9\x1c\xab\xf5\x36\ -\x7f\xf3\xc2\x8b\xcc\xad\xae\xe1\x49\x09\x9a\xc9\xc6\x66\x0d\xc7\ -\x8f\x20\x4a\xbe\x1b\x4d\x05\xd9\xa1\x7d\xc9\x08\x2c\x13\x7c\x37\ -\xb9\x71\xa6\x85\xa6\xab\x44\x51\x84\x8c\x62\x84\xaa\x20\xa3\x84\ -\x04\x01\x92\x5c\x77\x01\x25\x92\x14\x32\x36\x8d\xad\x2d\xd2\x86\ -\x82\x16\xfa\x3c\x7c\xdf\x71\xee\x3b\x34\xc5\xc9\x23\xa3\xbc\xfd\ -\xb3\x33\x04\x5e\x0b\x4b\x53\x79\xe2\xb1\x47\x49\xa7\x93\xa2\xfa\ -\x8b\x17\xae\xb2\xb2\xb2\x82\xa9\x1b\x9c\x3a\x75\x0a\x5d\x51\xa9\ -\xd7\xeb\xd4\xeb\x75\x1c\xc7\xa1\x58\xec\x66\x6d\x6d\x8d\xe1\x91\ -\x51\xfa\xfa\x4a\xbc\x7b\xee\x12\x63\x7b\x47\xa8\x6d\xae\x63\x1a\ -\x1a\x67\xcf\x9e\xe5\xe0\xc1\x83\xdc\xbe\x7d\x1b\x5d\xd7\x09\xc3\ -\x90\x67\x9e\x79\x86\x33\x67\xce\xf0\x99\xcf\x7c\x82\x56\xcb\xa7\ -\x5c\x2e\xd3\x6c\x36\x39\x7b\xf6\x6c\x02\xe4\x76\x9b\xbe\xc1\x3e\ -\xda\xae\xc3\x93\x8f\x3f\xc1\x8f\x7f\xfc\x63\x3e\xf7\xd9\xcf\xee\ -\x36\x0e\x18\x18\x1a\xe4\x95\x9f\xbd\xca\xc8\xe8\x38\xbd\xfd\x7d\ -\x5c\xbc\x74\x99\xb5\xed\x4d\x34\xc3\xe0\xfe\x07\x4f\xf3\xad\xbf\ -\xfc\x2b\x3e\xf6\xf0\x23\x34\x1b\x6d\x3e\xf5\xf8\x7d\x4c\xaf\xb9\ -\x08\xc3\xe2\xc2\xf4\x6d\xb6\xda\x3e\x7f\xf2\xad\x6f\xa3\x66\xbb\ -\x68\x23\x08\x85\x8a\x6e\xd8\x98\x66\x0a\x4d\x51\x51\xa2\xa4\xa9\ -\xc3\xc6\xc6\x7a\x32\xee\x52\x26\x89\x6e\x99\xa4\xa8\xd8\x69\xf6\ -\xa0\x29\xe0\x38\x49\x9e\xc7\xd2\x41\x51\x21\x0c\x00\x81\x66\xa8\ -\x84\xf5\x3a\xaa\x90\xc4\x9a\x82\x34\x0d\xb0\x4d\x84\xa9\x23\xa3\ -\x10\x7c\x17\xa1\xeb\x94\xd2\x19\xda\xeb\x1b\xd8\x61\x48\xb8\x51\ -\xe1\x63\x27\xee\x63\x5f\x6f\x3f\x23\xdd\x5d\xfc\xee\x17\x1f\xda\ -\x47\x1b\x32\x36\xb3\x02\x08\xfd\x98\xd0\xf7\x11\x51\x38\x9e\xee\ -\xca\xcc\x12\x27\x8d\x0d\x76\xba\x90\xc8\x4e\x13\x40\xd9\x69\x5e\ -\x24\xee\x0d\xc6\xfe\x66\x03\x39\xbe\x07\xc8\xca\x2f\x86\x0c\x77\ -\x88\x21\x12\xfc\x48\x12\xc5\x31\xba\xb1\x03\xe4\x18\x25\x74\xb0\ -\x0c\x13\x14\x8d\x3f\xfd\x8b\x6f\xc9\xeb\x77\xe6\x19\x9a\x38\xc8\ -\xe4\x89\xfb\x38\x7b\xf3\x36\x47\x1f\x7a\x84\x5a\x04\xd7\xe6\x17\ -\x78\xfd\xdc\x45\xde\x78\xed\xf5\xa4\x7a\xbd\x54\x42\xa8\x26\x22\ -\x52\x11\x42\x43\x37\x35\x52\xa9\x14\xaa\xae\xe2\x87\x21\x61\xe4\ -\x23\xa5\x24\x08\x3c\x6c\xcb\x40\x51\x14\x42\xdf\x03\xc0\x34\x0c\ -\xc2\x30\xa0\xdd\x6e\xa3\x1b\x26\xae\xeb\x62\x1b\x26\xba\xa6\x52\ -\x59\x5b\x03\xdf\x63\xb0\xb7\x97\x43\x13\xfb\x38\x72\x60\x1f\x5e\ -\xad\xc2\xc4\xde\x61\x1e\x39\x35\x46\xba\xf3\xb7\x9a\x8e\xe4\xe2\ -\xf9\xb3\xac\xae\xac\x33\x34\x38\xc8\xe3\x8f\xde\xc7\xf7\xbf\xff\ -\x02\x4f\x3c\xf1\x04\x33\xd3\x37\x89\x82\x90\xc3\x87\x0f\xe3\xba\ -\x2e\x41\x10\xb0\x30\x77\x97\x87\x1e\x7d\x80\x77\xde\xb9\xc8\xec\ -\xdc\x1c\x5f\xfd\xea\x17\xf9\xb3\x3f\xfd\x2b\xfa\xf2\x05\xba\x8b\ -\x79\xba\xba\xba\x70\x5d\x97\x87\x4f\x1f\xe7\xff\xfc\x8b\xef\xf2\ -\xd4\x53\x4f\xb1\xba\xba\x4a\xbd\x5e\xe7\xd8\xb1\x63\xf4\x17\x6d\ -\xfe\xe2\x3b\x3f\xe0\x9f\xfd\xf6\x67\xf9\xde\x4f\x7e\x4e\xa1\x50\ -\xa0\xaf\xbf\x9f\xf5\xad\x75\x2c\xcb\xe2\xdc\xb9\x73\x0c\x0f\x0e\ -\x22\xa5\xa4\xd1\x68\xf0\xec\xb3\xcf\xf2\xf3\xd7\x5e\xe3\xf8\xf1\ -\x93\x94\xab\x15\x6e\xcf\xde\xe5\xa9\xa7\x3f\x8e\x6e\x2a\x5c\xbf\ -\x79\x9b\x96\xd3\x26\x9b\xb2\x31\xa4\x82\x90\x82\xb5\xad\x6d\xec\ -\x6c\x9e\x46\x10\xf3\x27\x7f\xf9\x2d\xac\xee\x5e\xc6\x8e\x1e\xe7\ -\xe5\xb7\xdf\xa6\x19\x41\xdd\xf3\x89\xbd\x28\xb9\xc7\x8a\x4e\x52\ -\x29\xe2\x93\x2d\xe5\x51\x3a\xb7\x3d\xde\xe9\xf5\xdd\x69\xb9\xa4\ -\xea\x0a\x9e\xe7\xa1\xeb\x3a\x51\xc7\xb5\x92\x32\x4e\xee\x93\x9a\ -\x00\x5a\x8b\xc1\xd2\x35\xdc\x38\x66\xb3\xd9\x20\xf6\x3a\x65\x98\ -\x56\x0a\x34\x2d\xc9\x24\xe8\x3a\xdd\xa9\x34\xa2\xd5\xc4\x70\x02\ -\xfc\x6a\x85\x83\x7b\xc7\x39\x3e\x31\x4a\x8f\x21\xf9\xd8\xfd\xc7\ -\x39\x71\xa0\x7f\x5f\x14\xf2\xb5\xc8\x89\xbe\xd6\x9d\x55\x8b\xea\ -\x4e\xca\x58\xee\x14\xd5\x08\x10\xf1\x47\x40\xfe\x65\x64\x90\x5f\ -\x0a\xe4\x7b\x9e\xb7\xda\x3e\x91\x00\x33\x65\x10\x01\x41\x08\xa8\ -\x09\x3d\x59\x03\x16\x97\xb7\xe4\x5f\x7c\xe7\x3b\xd8\x5d\xdd\x3c\ -\xf6\xec\xa7\xe8\x1d\xca\xf2\xfd\xd7\xae\x63\x14\xba\x79\xeb\xd2\ -\x55\x5e\x79\xe7\x2c\x95\xb6\x43\xaa\xbb\x44\xa1\x7f\x80\x96\x1f\ -\xe0\x84\x3e\xf5\x7a\x13\x11\x28\xe8\x8a\x96\xf4\xb9\x32\x4d\x62\ -\x62\x7c\x3f\xe9\x98\x21\x84\x24\x8a\x22\xac\x94\x81\x2a\x14\x42\ -\xdf\x4d\x4c\x6c\x25\xd1\xca\xae\xeb\xa2\x2a\x30\x38\x38\x40\xa3\ -\x5a\xa3\x55\xab\x33\xba\x67\x98\xf2\xc6\x3a\x4a\x10\x30\xb5\x7f\ -\x1f\xff\xcd\xef\x7d\x91\x56\x25\xe4\x8d\x9f\xbf\xc2\x6b\xaf\xbc\ -\x80\xef\x34\xf8\xe4\xb3\xcf\xf2\x99\x4f\x7f\x8a\x7c\x26\x4d\x29\ -\x25\xb8\x79\x7b\x9d\x77\xce\xbc\xc9\xd1\x23\x87\x28\x15\xf2\x18\ -\xba\x46\xc6\x4e\xf3\xf6\x5b\x6f\x50\x2c\x16\x39\x72\xe4\x08\x42\ -\xc2\xf3\x3f\xf9\x31\xe3\x63\x13\x14\x4a\xdd\xbc\xfb\xee\x59\x3e\ -\xf1\xf4\xd3\x2c\xcc\xde\x61\x74\xef\x5e\xde\x7a\xeb\x2d\x6c\xdb\ -\x26\x97\xcb\xb1\x67\xcf\x1e\x66\x66\x66\xd0\x34\x8d\x62\xb1\x48\ -\xa1\x50\x00\xe0\x85\x17\x5e\xe0\xe9\xa7\x9f\x66\x73\x73\x93\x7a\ -\xbd\xce\xd4\xd4\x14\x6f\xbd\xfd\x26\x07\x0f\x1e\x24\x8e\xa0\xdd\ -\x6a\x31\x32\x32\xc2\xec\xec\x2c\xd3\xd3\xd3\x3c\xfd\xcc\x33\x5c\ -\xbf\x7e\x9d\x52\x5f\x2f\x63\x63\x63\xac\x6d\xac\x33\xbf\xb8\x08\ -\x8a\xe0\xbe\xfb\x4f\xa1\x4a\xc1\x3b\xaf\xbe\x8a\x8c\xa0\xe5\x7a\ -\x7c\xec\xe9\x67\x59\xde\xaa\xf2\x1f\xfe\xf8\x7f\xe3\xfc\xed\x3b\ -\xa8\xb9\x02\x8e\x6e\x10\xe8\x26\x81\xaa\x23\x15\x05\x4d\x4b\x61\ -\x9b\x36\xba\xaa\xa1\xc4\x11\x6a\xec\x13\x85\x6e\x92\x42\x51\x55\ -\xa2\x28\xc0\xf1\x5c\x14\x45\xc1\xb2\x2c\x22\x19\x63\x9a\x06\x71\ -\x1c\xd3\x6e\xb7\x09\x65\x8c\x61\x18\x68\x9a\x46\x18\x86\x18\x6a\ -\xe2\xc7\x7a\x51\x8c\x1f\x4b\x14\x33\x85\x99\xce\x10\x49\x70\x1c\ -\x87\x60\xbb\x0c\x86\x8e\xa1\x28\xf8\xd5\x32\x69\xd3\x40\x93\x11\ -\x79\x3b\x43\x5a\xc4\xa4\xc2\x36\x27\x0f\xec\xe7\x13\x8f\x7f\x8c\ -\x03\xa3\x83\xf4\xd9\x54\x6c\x28\xca\x00\xf4\x28\xc2\xd2\xd5\x84\ -\x04\xdc\x41\x6b\x42\xd3\x64\xb7\xa5\xb1\x40\x7c\x04\xe4\xf7\x80\ -\x2c\x7f\xa1\x4a\x65\x67\xef\x7a\x11\xba\xa9\x12\x01\x2d\x37\x02\ -\x5d\xc5\x50\xc1\x8f\x61\xbb\xd6\x66\x79\x63\x5b\xfe\xef\x7f\xfe\ -\xe7\xdc\xff\xc8\x63\x3c\xfa\xd4\x63\xcc\xae\xd6\xf8\x3f\xbe\xf5\ -\x1d\xca\xae\x87\x83\x4a\xa4\x59\xcc\x2c\x2c\x62\x74\xe5\x88\x84\ -\x8a\x9d\xcd\xb0\x55\xad\x81\xaa\x60\x18\x16\x5e\xb5\x09\x42\x4b\ -\x4c\x6a\x00\xdf\x03\xd7\x4d\x4c\x39\x4d\x05\xdb\x02\xcf\x07\x45\ -\x45\x58\x16\x32\x8a\xa0\xd9\x4c\xcc\x04\xdb\x82\xc0\x81\xc0\xc7\ -\xca\x75\x11\x47\x11\xfe\xfa\x3a\xfb\x0e\x1f\xe2\xb9\x67\x9e\xc6\ -\x6d\x36\xe9\x4a\x5b\x04\x4e\x8b\x97\x7e\xf2\x23\x6c\x53\x45\x89\ -\x43\x52\xa6\xc1\xe2\xd2\x3c\x4f\x3e\xfc\x08\x23\xbd\x03\x74\x67\ -\xb3\x4c\x8c\x8f\x33\xd0\xdf\xc5\xe2\xdd\x25\x6e\x5c\xbf\x46\x29\ -\xdf\xc5\x53\x8f\x3f\xc4\xd6\x66\x95\x77\xde\x39\xb3\x0b\xc8\x8d\ -\xad\x72\x47\x4b\x99\x74\x75\x75\x71\xff\xf1\x29\xbe\xfd\x9d\x1f\ -\x70\xe0\xc0\x01\xfa\xfb\xfb\x79\xeb\xad\xb7\x38\x7d\xfa\x34\xb7\ -\x6f\xdf\x26\x08\x02\xf2\xf9\x3c\x42\x08\xee\x3f\x7e\x80\x9f\xbe\ -\x7e\x96\x3d\x7b\xf6\x70\xe1\xc2\x05\x0e\x1d\x3a\x44\xb5\x5a\x25\ -\x0e\x83\x8e\xbf\xec\x30\x36\x36\x46\xbb\xdd\xa6\x52\xa9\xd0\x6e\ -\xb7\xa9\x35\xea\x8c\x8e\x8e\x92\xb2\x6d\xe2\x38\x66\x65\x7d\x8d\ -\xb1\x7d\xe3\x44\x44\xcc\xcc\xcc\xe0\xb5\x9a\x7c\xfa\xa9\x67\x88\ -\x82\x90\xcd\x4a\x9d\x8b\xd7\x6e\x60\x16\x4a\x8c\x1f\x3d\xc4\xa6\ -\x27\x79\x77\xfa\x16\xff\xe9\x3b\xdf\xc5\x37\x4d\x22\xcd\x24\x90\ -\xe0\xb9\x61\x42\xfa\xf0\x7c\x88\x43\x14\xdb\x22\xee\xb8\x2e\x9a\ -\x61\x10\x45\x01\xb2\xdd\x4e\x34\xa1\x69\xa2\x65\x52\x84\xbe\x9f\ -\x48\x84\xa6\x11\xcb\x38\x31\xb5\x01\x2c\x2b\xc9\xeb\x46\xb2\xc3\ -\x0f\xd2\xd1\xec\x1c\xa9\x54\x9a\x58\x0a\x3c\xcf\xa7\xbb\x50\xa4\ -\x56\x29\xe3\x56\x36\x19\x18\x1d\xa6\xb2\xbd\x81\x8c\x7d\xbc\x8d\ -\x0d\x74\xdb\x62\xa4\xa7\x08\xed\x06\x93\xc3\x23\x3c\x7c\xe4\x10\ -\x0f\x1e\x3e\xc8\xbe\x9e\x02\x69\xa0\xdb\x42\x68\x51\x92\x47\x4e\ -\x42\xdc\x71\xd2\x8b\xfb\x23\x20\x7f\x18\x90\xa3\x84\xcb\xfa\xbe\ -\x86\xb2\x4a\x27\xbd\x04\x2d\x37\xc0\xb2\x92\xd2\xc2\xa6\x9b\x34\ -\x70\x8f\x24\xac\xae\x6f\x7e\x73\xa5\x5a\xff\x37\x33\x5b\x65\x4a\ -\x7b\xc7\x58\x5c\xdd\xe0\xc7\x2f\xbf\xc2\xe5\x99\x3b\xec\x3f\x72\ -\x0c\x69\x59\x84\x42\x63\x7e\x79\x95\x58\x51\x31\xcc\x14\xeb\x5b\ -\x5b\x89\x1f\xa6\x28\x49\xc9\x93\x65\xa3\xa5\x33\x08\x4d\x45\xd5\ -\x35\x14\x45\xc1\x8f\x42\xc2\x28\xe9\xdb\x65\xd9\x29\x02\x3f\xc2\ -\xf3\x3c\x54\x45\xc1\x34\x4d\x22\x3f\x4a\xa8\x88\xaa\x4e\x57\xd6\ -\xc6\x77\x6a\xec\x1b\xdf\xcb\xd5\x4b\x97\x39\x72\xe8\x30\xcf\x3d\ -\xfb\x0c\x13\x63\x29\xae\x5e\x5c\xc3\x6b\x35\x19\xea\xeb\xe1\xec\ -\xbb\x6f\xb1\x30\x3b\xcb\xe2\xfc\x1d\x0c\x4d\xa5\x5a\xd9\xe2\xd8\ -\xf1\x23\xfc\xfe\x7f\xfb\xdf\x11\x6c\x55\x68\x6c\x6d\x72\xe1\xdc\ -\x39\x4e\x1c\x39\x08\x71\xc4\xc7\x1e\x7e\x18\xa7\x59\xe5\xdd\xb7\ -\xcf\x90\xcb\x66\xb1\xed\x14\xb6\x6d\x73\xed\xda\x35\x06\x07\x87\ -\x78\xe0\x81\x07\xb8\x71\x73\x86\xed\xed\x6d\xa2\x28\xe2\xe4\xc9\ -\x93\xdc\xb8\x71\x83\x5c\x2e\xb7\x6b\x29\xf8\xbe\x4f\x2e\x97\xc3\ -\x30\x0c\x5c\xd7\xa5\xbb\xbb\x9b\x66\xb3\xc9\xf2\xf2\x32\xd9\x6c\ -\x96\xae\xae\x2e\x16\xe7\x17\x38\x75\xe2\x14\x33\x33\x33\x8c\x8c\ -\x8c\xe0\x79\x1e\x97\x2f\x5f\x66\x68\x68\x88\x53\xa7\x1e\x60\x79\ -\x79\x99\xdb\xb7\x67\x58\xdd\x58\xe7\x91\x47\x1e\xe2\xee\xc2\x3c\ -\x83\xc3\x43\xb4\x5d\x37\x09\xa8\xcd\xde\x66\x65\xee\x2e\xbd\xdd\ -\x25\x42\x14\x0a\x03\x43\x4c\x2f\x2c\xf3\xc0\x93\x0f\x71\xf9\xee\ -\x16\xd3\xab\x6b\xfc\xe9\xdf\x7c\x8f\x7a\x1c\x13\x48\x25\x69\x72\ -\x2d\xf4\x4e\xb0\xcb\x26\x93\xc9\xd1\x68\x79\x09\x33\x4f\x91\x9d\ -\x5e\x5c\x89\x79\x1d\xc6\x9d\x95\x38\x0c\x15\xdf\xf7\x77\x35\x74\ -\x2c\x25\x6e\xbb\x9d\xdc\x47\x4d\x21\x6d\x5b\x10\x4b\xe2\x50\xe2\ -\x3b\x3e\x51\xc3\x03\xd7\x07\xd5\x40\x33\x2d\xc2\xb6\xc3\xbe\x83\ -\x93\x78\x91\xcb\xd2\xe5\x73\xf4\x1f\x9f\xa2\xed\x35\x69\xbb\x6d\ -\x64\xe0\x13\xd5\xab\x64\x53\x16\x19\x14\xe2\x6a\x85\x07\x27\xf7\ -\xf3\x7b\x5f\xfa\x3c\x0f\x4e\x8e\x50\x54\x10\x7a\x0c\x6a\xcc\x6e\ -\xea\x0b\x11\x77\xc8\x5d\xc9\x72\x3e\xff\x3f\x02\x72\xfc\xa1\xe6\ -\xf0\x3f\xdc\x3f\x8e\x77\x1d\x62\x71\xaf\x63\xdc\xe9\x19\x1d\x01\ -\xed\x30\xa6\xe1\x7a\x49\x7f\x28\xe0\xc2\xf4\x92\x9c\xb9\x75\x1b\ -\xbb\x7f\x90\xef\xbc\xfe\x26\xd3\x2b\xab\xf8\xb1\xa4\xda\x6c\x83\ -\x6e\x90\x2f\xf5\xe0\x44\x31\xeb\x6b\xeb\xc9\x35\xe9\x06\x42\x33\ -\xb0\x6d\x1b\x01\x98\xa6\xc9\xf6\xca\x2a\xa5\xa1\xc1\x24\xa6\xa6\ -\x08\xa4\x22\x08\xc2\xb8\xe3\x93\x86\x28\x46\x72\xbc\xe7\x05\x9d\ -\xe6\x7c\x0a\xbe\xeb\x11\x7a\x89\x50\x69\x9a\x8e\x22\x62\xb2\x29\ -\x8d\x42\x3e\xcb\xc6\xda\x1a\x8f\x3d\xf6\x18\xe7\xcf\xbe\x4b\x4f\ -\xa1\x48\xe4\xb9\xf4\x97\x4a\xdc\xba\x71\x1d\x25\x8e\x19\x19\x1c\ -\x20\xf0\x5c\x6a\xd5\x32\xbf\xfb\xbb\xff\x05\xba\xae\xb2\x76\x77\ -\x8e\xdb\x17\xce\x71\xfd\xfc\x39\x0e\x4e\x4d\xf2\xc0\xc9\x13\x7c\ -\xec\xa1\x87\x58\x98\xbb\xcd\xca\xc2\x3c\x7b\x86\x06\x29\x64\x73\ -\x2c\x2d\x2e\x60\x18\x46\x67\x95\x87\x02\xed\x76\x9b\xcd\xed\x32\ -\x0f\x9c\x3e\xcd\xd5\xeb\xd7\xd0\x75\x9d\x62\xb1\x48\xb9\x5c\xc6\ -\xb6\x6d\x66\x6e\x4e\x73\xf0\xe0\x41\x56\x56\x56\x76\x4d\xd0\xb1\ -\xbd\x7b\x59\x5a\x59\xa1\xd9\x6c\x32\x38\x38\x48\xa3\xd1\xc0\x71\ -\x1c\x86\xfa\x87\x88\xe3\x18\xcf\xf3\xd0\x34\x8d\xae\x6c\x0e\xcf\ -\xf3\x58\x98\x5b\x60\x62\x62\x82\x54\x26\xc5\x95\x2b\x57\x58\xdf\ -\x58\xe5\x8b\x5f\xfe\x12\x2f\xbd\xf2\x0a\xdd\x3d\x25\x1c\xa7\xc5\ -\xc4\xbe\x7d\x0c\xf7\xf7\xd3\x68\x34\x12\x6d\x9c\xe9\x62\xb3\xe5\ -\xb0\x50\xad\x31\x76\xfc\x3e\xba\x47\x7a\xf8\x1f\xfe\xdd\x7f\xa0\ -\x19\x4b\x42\x4d\xc7\xb0\xd3\xc8\x50\x52\xaf\x35\x88\xdd\x00\x34\ -\x1d\x2b\x5b\x44\x33\xcc\xce\x35\x38\x08\x21\x50\x8d\x24\x58\x17\ -\xb5\x5a\x60\x68\xe8\x1d\x9f\x38\x8a\xa2\x24\xcf\xab\x2a\x78\x9e\ -\x0f\xad\x26\x8a\x6d\xa0\x09\xd0\x55\x03\x43\xe8\x04\x8e\x8f\xdb\ -\x74\xd0\x84\x86\x6d\xdb\x64\xd3\x36\xf3\xd3\xd7\xc1\x50\xc9\x0e\ -\x74\xd3\x58\x9c\x85\x52\x81\xee\x81\x5e\x5a\xad\x06\xb1\xeb\xe3\ -\x97\x2b\x68\x71\x84\xe9\xb9\xe4\xe2\x90\xa9\x81\x3e\x9e\x7b\xf8\ -\x34\xbf\xfd\xc9\xa7\xe9\xb3\x15\xa1\x4b\xd0\xa5\x7c\x8f\xa5\x2f\ -\x76\xd2\x4e\x0a\x52\xbe\x57\xce\xb8\x1b\xc9\xfe\x3b\x6b\x97\xe3\ -\x0f\x70\x22\xfe\xbf\xc9\x4b\xff\x8a\xcc\xae\x9d\xea\x25\xf9\x5e\ -\x15\x53\xe2\x40\x10\xcb\x84\x03\x1d\xc9\x64\x99\x1f\xc9\x87\x85\ -\xa7\x05\x31\x0a\x7e\x18\xe3\x87\x01\x8a\x10\x48\x21\x09\xc2\x80\ -\x30\x0a\x88\x55\x89\x1b\x45\x34\x82\x10\x3b\x9d\xc2\x05\xaa\xc0\ -\xb7\x7f\xf4\xda\x37\x5c\xc5\xe6\xcf\xfe\xf6\x05\x96\xda\x21\x2d\ -\xd5\xa4\xe9\x43\xa0\xe8\xc4\xaa\xce\x56\xbd\x41\xb3\xd1\x42\x58\ -\x29\xec\xae\x3c\x46\x26\x4d\xb1\xa7\x1b\xc5\xd0\xa8\xb7\x9b\x38\ -\x71\x40\xa6\xd4\x8d\x1f\x86\xf8\xae\x83\xae\x24\x3d\x95\x1b\xdb\ -\xdb\xc4\xd5\x2a\x84\x11\xd2\xf7\xf0\x2b\x15\x62\xb7\x4d\x10\x04\ -\x04\xe5\x2d\xe2\xe5\x45\x52\xf9\x2e\xfc\x46\x8d\xd8\x6f\x13\x34\ -\x6b\xdc\x7f\xf2\x28\x07\x26\xc6\xb8\x7a\xf9\x22\x95\xea\x36\x2b\ -\xcb\x8b\x8c\x8c\xec\xe1\xd2\xf9\xb3\x6c\xac\xac\x20\x7d\x1f\x2d\ -\x92\x94\x32\x79\x9e\x78\xf4\x31\xc6\x86\xf6\xa2\x49\x95\xbf\xfe\ -\xd6\x5f\x73\xe3\xda\x75\x3e\xfb\x5b\x9f\x42\xa8\x92\x74\xc6\xe6\ -\xcb\xbf\xfd\x25\x6e\x5c\xbf\x8e\xeb\x3a\xe8\xaa\xca\xe4\xc4\x04\ -\xe7\xde\x3d\x8b\xa5\x1a\xa4\xad\x14\xf9\x6c\x81\xf5\xd5\x4d\x22\ -\x3f\x62\x62\x6c\x92\x2b\x97\xaf\xe1\xf8\x1e\x8d\x66\x8b\xf5\xf5\ -\x0d\xfa\xfb\x07\x68\x35\x5a\x6c\xac\xae\xb3\xbe\xb2\x86\xef\xfa\ -\xac\xcc\x2f\x12\xfb\x21\x4e\xa3\xcd\xc6\xea\x3a\x6b\xcb\xab\x64\ -\x2c\x9b\x1b\x57\xaf\x33\xb9\xff\x00\x21\x82\x6a\xbd\x41\xab\xed\ -\xa0\xa8\x1a\x8b\x8b\x0b\x64\x52\x36\x9a\xa2\xb0\xb1\xb1\x8e\x2e\ -\x14\x0c\x55\x23\x65\x18\x9c\x79\xe3\x4d\xbe\xf8\x5b\x9f\xa3\x59\ -\xad\xe1\xb5\x1c\xea\xb5\x2a\xe5\x6a\x85\xa5\x8d\x35\x26\x0f\x1f\ -\xa6\x30\x38\xc8\x76\xdb\xe7\xd2\xf4\x6d\x32\x3d\xfd\xdc\x9c\x5b\ -\xc5\x4c\xe7\xb9\x7a\xfe\x12\x41\xcb\x47\x28\x1a\xcd\xad\x0a\xd2\ -\x0f\x20\x08\xc0\xf3\x09\xeb\x75\x24\xe0\xd5\xaa\x48\xdf\x25\x6e\ -\x35\x89\xb6\xb7\x50\x15\x8d\xd8\xf7\xa0\x56\x27\xf6\x7c\xc2\xb6\ -\x43\x5c\x6f\x10\x37\x5a\x09\xc0\xdb\x2e\xb4\xdb\xc8\x30\x26\x0a\ -\x43\xe2\x38\x71\xce\x14\x55\x24\x26\xb8\x88\x71\x7c\x07\xd5\xd2\ -\x91\x96\x8e\xd9\x95\xc3\x30\x4d\x7c\xdd\x42\xd6\x9b\x38\xb5\x16\ -\x31\x06\xa1\x27\xa0\x1d\x33\x3a\x7e\x00\xdf\x0b\x90\x31\x04\x41\ -\x40\xff\x40\x7f\xb2\x1f\xea\xfb\x86\x26\xf8\xb7\x6d\xd7\x1f\x57\ -\x84\xac\x68\x6a\x52\xdb\x1e\x36\x9a\x28\xba\x4e\x1c\x04\x48\xd9\ -\x59\xe4\x4e\xca\x64\xd1\x39\xf9\x5e\x25\x64\x2c\xe4\x6e\xbd\xbc\ -\x90\x12\x21\xe3\x04\x10\x71\x67\x4f\xb2\xbe\xd7\xaf\xaa\xcd\x7f\ -\x45\x8d\x7c\x4f\x3d\x71\xdc\x01\xa9\xd4\x3a\x9f\x74\x00\xdd\x99\ -\xa8\x76\x27\xab\x0f\x5c\xef\x4e\xcb\x59\x00\x19\x7b\xc8\x38\xee\ -\x4c\x76\x82\x50\x2a\xa0\x18\x78\xc0\xa6\x0f\x4d\x38\xfb\x57\xdf\ -\x7f\xf9\xd4\xeb\xef\x5e\xc4\x91\x2a\x15\x3f\xa4\xae\x19\x54\x7d\ -\x9f\xd0\x75\x51\x4d\x93\x74\x2e\x43\x18\x86\xf8\x61\x87\x3c\x90\ -\x4a\x11\xc4\x11\x91\x8c\x69\x7b\x6e\xc2\xce\x52\xd5\x84\x8c\x10\ -\xc6\x50\x6f\x74\x4c\xbe\xe4\x7a\x35\x3b\x45\x36\xdf\x85\xdd\x21\ -\x9e\xd4\xca\x95\xe4\x79\x2c\x89\x3c\x9f\xed\xad\x4d\x46\x86\x06\ -\x59\x5b\x59\x65\x70\xa0\x8f\x7f\xfd\xfb\xbf\xc7\x77\xbf\xf7\x22\ -\xb7\xee\xdc\xa6\xdd\x6e\xe3\xfa\x1e\xbd\xa5\x6e\xbc\x46\x0b\x25\ -\x08\xf8\x27\xbf\xf5\x05\x32\x9a\xc1\xd4\xf8\x18\x03\x25\xb8\x70\ -\x7e\x85\x3f\xf8\x83\x3f\xe0\xf4\x43\x0f\x31\xbc\xa7\x97\xe3\x27\ -\xa7\xc8\x65\x2d\x36\x57\xd7\x28\x64\x33\x78\x8d\x1a\x59\xd3\xe2\ -\xc8\xe4\x24\x37\xae\x5c\x26\x9f\xc9\xe2\x36\x5b\x49\x80\x2d\x94\ -\x89\xeb\xae\x69\x28\xaa\x46\x3a\x97\xc5\xce\xa5\xa9\x54\xb6\x59\ -\x5b\x5d\xa5\x51\xab\xd3\x9d\x2f\x30\xb6\x77\x94\xf9\xb9\x39\x54\ -\xa1\x50\xaf\xd6\x18\x18\x18\x60\x68\x68\x88\x3b\x77\xee\x80\x22\ -\xb8\x70\xe1\x02\x5f\xfd\xea\x57\x59\x5a\x59\xe6\xd2\xcd\xeb\x08\ -\x45\x63\x74\xef\x5e\x06\x06\x06\x68\xd7\x6a\x34\xeb\x75\x46\x47\ -\xf6\x52\xa9\x54\x68\xd6\x1b\x8c\x8d\x8d\x71\xf5\xfa\x15\x26\x26\ -\x26\x38\xf3\xce\xdb\x3c\xf8\xf0\x43\x94\x4a\x25\xde\x39\x7f\x8e\ -\x7c\x29\x4f\xad\xd5\x26\xdd\xdd\xc3\xd5\x5b\xb3\xfc\xe4\xb5\x37\ -\x08\xcc\x34\x3d\x23\x13\x9c\x7a\xec\x09\xcc\xae\x3c\x3f\x78\xfe\ -\x05\x16\x57\xd7\xf0\xa3\x10\x21\x04\xc5\x62\x91\xc0\xf5\xa8\x54\ -\xaa\x48\x29\x76\xc7\x5a\x51\x94\x5d\x1b\xcf\xb2\xec\x5d\x37\x41\ -\xd3\x34\x54\x55\x27\xde\x21\x67\x88\x4e\x15\x53\x1c\xd1\x6c\x36\ -\x92\xe8\xb4\x94\x49\x71\xf1\x4e\xfa\x2a\x8e\x21\x0c\xb1\xf2\xf9\ -\xdd\x76\xc7\x3b\xbf\xd1\x6a\xb5\x08\x7c\x1f\x3b\x9d\x25\xf6\x42\ -\x7c\xcf\x25\x2e\x6f\x32\xbc\x77\x98\x8c\x1a\x53\x34\x55\x9a\x6b\ -\x0b\x3c\x71\xff\x09\x9e\x7e\xe0\x24\x47\xf7\x8d\xd0\x63\x28\x42\ -\x95\x31\xaa\x1f\x60\x6a\x1d\xaa\xa6\xe7\x21\x75\x03\x29\xd4\xdd\ -\x6b\x47\x76\xc8\x9d\x4a\xe2\x4b\x87\xbb\x54\xcf\x38\x59\x13\x6b\ -\x07\xc0\x3b\x78\x51\x14\xa4\xa2\xfe\xca\x40\xfe\x15\x35\xb2\xe4\ -\xfd\x0b\xf6\x74\x4c\x62\xf1\x1e\x17\xb5\x83\xc9\x9d\x6b\xee\xd0\ -\x53\x3b\xb4\x4a\x21\x11\x42\x21\x8a\x23\x22\xcf\x45\x48\x81\xae\ -\x1a\x49\xdf\xac\x50\x10\xc6\x0a\xa1\x50\xd8\x6a\x47\x72\xdb\x09\ -\xbf\xf1\xe2\x99\xb3\x83\x2f\xbf\x7b\x96\x4b\x77\xe7\x71\x0d\x0d\ -\x57\x37\xd8\x2a\x6f\x13\x6b\x1a\x46\x36\x43\x3a\x97\x45\x51\x55\ -\x1c\xcf\x23\x96\x92\x74\x26\x93\xf8\xbc\x61\x84\xd3\x68\x82\xeb\ -\x23\xac\x34\x29\x3b\x83\x26\x34\x0c\x5d\xa3\x7f\x60\x08\xd3\xb2\ -\x92\x59\x51\x37\xd0\x34\x9d\x28\x92\xb4\xdb\x0e\xcd\x56\x1b\x21\ -\x14\x6a\xe5\x0a\xad\xa5\x25\x62\x4d\x47\x00\x95\xf5\x35\x54\x5d\ -\xa7\xb7\xbb\x9b\x46\xcd\xe1\xc6\xd5\xeb\x6c\xae\xaf\x27\xc4\x91\ -\x30\xc0\x77\x5a\x54\x36\xd6\xe9\x4a\x59\x08\x3f\xe0\xc4\xd4\x01\ -\xdc\x6a\x85\x9b\x57\x6e\x71\xe9\xdd\xb7\xd9\x5e\x5f\xe6\x0b\x9f\ -\xfb\x34\xc5\x42\x96\x54\xc6\x42\xb7\x2c\x7e\xfc\xe3\x9f\x70\xe0\ -\xc0\x01\x3e\xfe\xd4\xa3\x4c\x8e\x8d\xf0\xee\xc5\xcb\xdc\x9c\x99\ -\xa6\xd0\xd3\x43\xb1\xaf\x8f\x4a\xb3\x81\x34\x54\x72\xdd\xdd\x6c\ -\xd6\x2a\x6c\xd5\xaa\x34\x9c\x26\x1b\x6b\xab\x54\x2b\xdb\x80\xa4\ -\xd4\xdd\xcd\xb5\x6b\x57\x18\x1f\x1b\xa5\x52\xde\x66\x6e\x76\x96\ -\xbe\xbe\x5e\x7c\xdf\x63\x73\x6b\x83\xd9\xb9\x3b\x8c\x8e\xee\x65\ -\x70\x70\x00\x2f\xf0\x58\x5b\x5b\x25\x0a\x03\x1e\x7e\xe8\x21\x6a\ -\x95\x0a\x97\xce\x9f\xa7\xab\xab\x8b\xbe\xde\x5e\x7e\xf2\xc2\x0b\ -\x98\x96\x45\xb6\x90\xa7\xe9\xb4\xc9\x97\xba\x39\x73\xf1\x3c\xe3\ -\x53\x07\xd8\xac\x55\x69\x85\x3e\x0f\x3f\xf1\x38\x66\x2e\xcf\xe0\ -\xd8\x38\xd7\x6f\xcf\xb1\x5e\x6b\x72\x63\x6e\x89\x56\x28\xb9\x36\ -\x73\x8b\x33\x17\x2e\x50\xec\xed\xa5\xed\x07\xa0\x40\xb9\x52\x26\ -\xa8\x55\x69\x07\x3e\xcd\x7a\x8d\xb8\x52\x25\x4e\x99\x78\x9e\x4f\ -\x0c\xc9\x44\xe8\xba\x78\xbe\x4f\x6b\xbb\x8c\xd3\x6c\x10\x78\x1e\ -\x9e\xe3\xe0\xb8\x3e\xa1\x8c\x89\xa5\x24\x8a\x23\x62\x99\xac\x3a\ -\xe1\xfb\x1e\x5a\x67\xc2\x36\x2c\x8b\x54\x3a\x8d\x9d\x4e\xa3\x19\ -\x06\x21\x10\x94\xcb\x78\x80\x57\xaf\xe3\x55\xab\xb8\x9d\xc9\x40\ -\xc6\x31\x8a\xaa\x24\x6b\x5b\x21\xe8\xea\x2e\xb2\xf6\xce\x19\x64\ -\x3a\x85\xe7\xb6\xd8\x5c\xdf\xe0\xbf\xfc\xdd\x7f\xce\xca\xca\x32\ -\x6f\xbd\xf9\x26\x0f\x1c\x3f\xbc\xaa\x09\x71\x4e\x02\x9a\xaa\x25\ -\x91\x6c\x55\x05\x45\x41\x28\x02\xa1\xbc\xcf\x2b\xdc\x8d\x6c\x7f\ -\xb0\x1c\x57\x88\x7b\x8a\x25\x77\x34\x9c\x50\x7e\x0d\x80\x7c\x8f\ -\xc1\x2f\xef\x65\xbc\xec\x5c\x6e\xe7\x0f\xbe\xd7\x94\xa1\x13\x30\ -\xe8\x18\x1c\x8a\x10\x84\x81\x4f\x14\x46\x98\x46\x0a\x21\x54\x22\ -\x5f\x12\x4a\x15\xdd\x54\x08\x04\x2c\x57\xfd\x6f\xbc\x71\xf9\x1a\ -\x3f\xbf\x70\x99\x57\x2f\x5d\x22\x33\x34\xc0\x66\xe8\xd1\x92\x12\ -\x25\x9b\x23\xdf\xd3\x4b\x3a\x9b\x21\x88\x42\x1a\xad\x26\x71\xab\ -\x89\xf4\x5c\xdc\x30\xe9\xe2\x21\x84\x42\xe8\x05\x80\x42\x3e\x57\ -\xc4\xd4\x3b\xb5\xc1\x8a\x42\x14\xc6\xd4\xeb\x0d\x3c\xc7\x21\x96\ -\x92\x50\x0a\x42\xdf\x27\x74\x3d\xe2\x20\x24\x74\x5d\xac\x74\x1a\ -\xc5\x4e\x91\xb1\x53\x64\xb3\x69\xfe\xd5\xbf\xfa\x97\x98\x86\xce\ -\x23\xa7\x1f\xe4\xda\xa5\x4b\x3c\x78\xdf\x49\x5a\x8d\x26\x6b\x77\ -\x6e\x31\x38\x3c\x48\x4a\x37\xf8\xca\x17\xbf\xc0\xea\xc2\x3c\x7b\ -\x7a\x8a\x2c\xde\xbe\xc5\xa7\x3f\xf1\x28\x07\xc6\x06\x29\x6f\x6c\ -\xb2\xb4\x38\xcb\xa7\x3f\xf1\x34\x87\x0f\x4d\xb1\x6f\xdf\x1e\x74\ -\xd5\x64\x6a\x62\x12\xcf\x71\xb9\x75\x73\x96\x3b\x73\x77\x11\x52\ -\x92\x4e\x67\x38\x7c\xf8\x08\xba\x6e\x30\x38\x38\xc0\xfc\xc2\x02\ -\xae\xef\x53\xe8\x2e\x72\x67\x6e\x8e\x6c\x3a\x8d\x88\x03\x56\x57\ -\x96\x48\xe9\x26\xf5\x5a\x85\xf1\xd1\x71\xea\x95\x32\xc7\x8f\x1e\ -\x67\x69\x71\x9e\x99\x99\x5b\x84\xa1\x4f\x36\x9b\xa3\xd5\x6a\x70\ -\x77\x7e\x81\x7c\x21\xc7\x1b\x6f\xbc\xc9\xe4\xe4\x24\x81\xe7\xf3\ -\xe6\xeb\xaf\x13\x87\x01\xb9\x6c\x0e\xcf\x75\x39\x77\xee\x1c\x9f\ -\xfb\xc2\x17\x50\x0d\x9d\xe5\xf5\x35\xf2\xa5\x22\xa3\x93\x13\x3c\ -\xfe\xf8\x83\x9c\xbf\x7e\x83\xf5\x5a\x99\x42\x4f\x2f\x37\xef\xce\ -\x32\xbf\xb4\x4e\xbe\xa7\x1f\x61\xd9\xa0\x5b\x6c\x35\x5b\x78\x12\ -\x34\x3b\x83\x13\xc6\xcc\x2d\x2e\xa0\x99\x06\xe9\x6c\x0e\x45\x51\ -\x10\xa6\x46\x26\x9b\x26\x5f\x2c\x90\x1f\x18\x20\x08\x42\xe2\x58\ -\xd2\xd5\xd5\x85\x6e\x99\x64\xb3\x39\x4a\xbd\x3d\x08\xc3\x24\x5b\ -\x2c\xf2\x7f\x13\xf7\xe6\x31\x7e\xe6\xf7\x7d\xdf\xeb\xfb\xdc\xcf\ -\xf3\xbb\xcf\xb9\x87\x43\x72\xc8\x19\xde\xdc\x5d\x72\xb9\xb7\xa8\ -\xdd\x95\x25\x07\x92\x92\xca\xb5\xd6\x46\xed\x38\x2d\x5a\xd5\x46\ -\xd2\x3a\x45\x0b\xc4\x40\xea\x54\x2a\x50\xb4\x09\x12\x20\xa8\x63\ -\x1b\x56\xec\xb8\x89\x62\x59\x95\x2c\xc9\x5a\x59\xe7\xae\x8e\x95\ -\x96\x7b\x70\x2f\xee\xf2\x3e\x66\x38\x9c\xfb\xf8\xdd\xc7\x73\x1f\ -\xfd\xe3\x19\x72\x57\x8a\xdc\x7f\xb4\x81\x08\x0c\x7e\x24\x48\xe2\ -\x37\xf8\xcd\xf3\xf9\x7e\x3f\x9f\xf7\xe7\x7d\x24\x92\x44\x2c\x49\ -\x08\x59\x49\xe5\x8e\x80\xeb\xb9\x04\xbe\x4f\x10\x47\xe0\xfb\xc4\ -\x51\x44\x98\x24\xbb\x37\x77\x3a\x4b\xdf\xd5\x1c\x1b\xf9\xf4\x7d\ -\x25\x55\x45\xe8\xa9\x7c\x31\x89\xd2\xff\x17\xf5\x7a\x08\x5d\x23\ -\x89\xd3\x68\xa0\xf1\xf9\x39\xd6\x97\x6e\xa3\x1a\x3a\xe3\x23\x23\ -\x9c\x3f\x7f\x9e\xb3\x67\x3f\x40\x1c\x47\x64\x32\x85\x8f\x49\xaa\ -\xfa\x69\x45\x91\x3f\x17\x25\x51\x3b\x0c\x42\x54\x4d\x4b\x59\xd9\ -\xe2\xbd\xca\xa9\x84\x24\x89\x53\xd9\x85\x78\x6f\x85\xbc\x2b\xc8\ -\x15\x77\xff\xbd\x10\xf7\x6a\xe6\x17\xdf\x5a\xdf\x75\xd5\x4a\xee\ -\x06\x52\xdf\xdd\xee\x27\x3f\x81\xe4\xa5\xaf\xf1\xbd\x95\xd3\xdd\ -\xf7\xf5\x83\x30\x4d\x76\x40\x86\x44\x22\xf4\x53\xae\x40\x22\x43\ -\xac\xc0\xf9\xab\xdb\xc9\xb7\x5f\x7d\x95\x6b\x3b\xdb\x7c\xf3\xfc\ -\x79\xd4\x91\x1a\xa2\x9c\xc7\x53\x54\x42\xc7\x41\xb6\x0a\x18\xaa\ -\xc1\xb0\x3f\x80\x6e\x37\xb5\xd0\xc9\xe7\x53\xcf\x63\x3f\x4a\x59\ -\x44\x92\x84\xdd\x1f\x90\x44\x11\x99\x4c\x9e\x28\x0e\x70\x07\x0e\ -\x92\x22\x11\x07\x7e\x3a\xaf\xa9\x0a\x72\x3e\x87\xa1\x5b\xa9\x35\ -\xae\x24\xa1\x1b\x2a\xbe\xe3\x12\xfa\x1e\x4e\xb7\x83\x22\x49\x9c\ -\x38\x72\x98\x77\xde\x7e\x8b\x4a\x21\xcf\xfc\xec\x2c\x4f\x3c\xf8\ -\x30\xff\xee\xdf\x7e\x96\xd5\xdb\xb7\x38\x70\xf2\x28\x4b\x4b\xb7\ -\xf9\xf0\x2f\x3d\xcd\xea\xd2\x02\x07\xa7\xa6\xb1\xdb\x2d\xc6\xcb\ -\x65\x66\xc6\xc7\x30\x65\x99\xab\x97\xdf\x66\x6c\x7c\x84\xc1\x60\ -\x40\xa5\x36\xc6\xfa\x7a\x03\xc3\xc8\xb2\xb1\xb6\xce\x48\xad\x82\ -\x22\x09\xaa\xe5\x02\xbd\x76\x8b\xc9\xf1\x51\x56\x97\x57\xd8\x37\ -\x33\x8d\xa1\x69\x0c\x87\x43\xba\x9d\x0e\x92\x24\x31\x3a\x3a\x8a\ -\x61\x68\x5c\xbe\xf8\x16\xf5\x7a\x8d\xcb\x17\x2f\x13\xfa\x1e\x8a\ -\xa4\x30\xe8\xf5\xf0\x3c\x1f\x43\x53\xa9\x94\xab\xf4\xfa\x5d\x54\ -\xdd\xa0\x50\xc8\xe3\x78\x1e\xa6\x69\xe0\x07\x29\xf5\x71\x7c\x64\ -\x94\xcd\xcd\x4d\xb2\xf9\x1c\xe3\x63\x93\x14\x4a\x45\xac\x5c\x96\ -\xab\xd7\xaf\x51\xa9\xd5\x30\xb3\x39\x54\xcb\xc0\x8f\x13\xae\xdd\ -\xba\xc9\xc1\x23\x87\x78\xe9\xd5\x57\x98\x9d\x3d\x40\x88\xe0\x85\ -\x1f\xbf\xca\xe4\xd4\x0c\x47\x4e\xde\xc7\x1f\xfd\xe9\x9f\x71\xfb\ -\xca\x75\x0a\x07\xe6\xd0\x0a\x05\xba\xb6\x87\x1f\xf8\xe4\x47\x46\ -\x89\x48\x18\x0e\x06\x69\xfb\x1b\x45\xa9\xd8\x25\x91\x40\x36\xd3\ -\x4e\x29\x9f\x27\x21\x41\x53\x35\xac\x6c\x86\x5e\x77\x80\xa6\x69\ -\x29\xea\x1e\xf8\x24\x49\x4a\xe1\x94\x65\x99\x30\x8a\x10\x80\xa2\ -\xaa\xc4\x71\x4c\xbf\xdb\x4d\xd5\x66\x9a\x76\x4f\x3e\x8a\x2c\xa3\ -\x99\x26\x92\x24\xe1\xb6\x5a\x18\xe5\x32\xb5\x5a\x8d\x7e\xbf\x4f\ -\x10\xa4\x16\xc8\xce\xf6\xf6\x6e\xbb\x28\xa8\x8d\x8f\x32\xe8\x77\ -\x09\x5d\x97\x7a\x31\x4f\x67\x73\x0d\xa7\xd9\xe0\x43\x8f\x9d\xe1\ -\x37\x7e\xe5\xef\xd1\x58\xbc\x49\xc9\x90\x79\xf4\xe4\x31\xea\x86\ -\x22\x64\x20\x89\x7c\x64\x59\x46\x26\xe1\x5e\x58\x6e\x9c\xdc\x8d\ -\xa8\xdb\x95\x6f\x4a\xf7\x3c\xe8\xee\x5e\xda\xf2\xee\x57\xea\x42\ -\x92\xbc\x2f\xc6\x04\x3f\x37\x6a\x9d\xdc\x2b\xce\x9f\xda\x03\xc7\ -\xef\xe5\xa0\x26\xef\x79\x4d\x7e\xc2\x2c\x20\x88\x42\x54\x59\x43\ -\xa0\x30\xb4\x7d\x34\x43\x23\x91\x60\xa7\x43\xf2\xda\x95\x45\x3e\ -\xff\xec\x37\xb8\xbe\xbd\xcd\xc5\xf5\x35\xf6\x3e\x70\x1f\x77\x06\ -\x1d\xa6\x8e\xcc\xb3\x74\xed\x22\x62\x74\x9c\x64\x6d\x1b\x32\x85\ -\x94\x25\xe2\x38\x90\xc9\x53\x28\x95\x10\xc8\x44\x61\xc8\xa0\x33\ -\x48\xc3\xc6\x7d\x1f\x10\xa8\xaa\x91\x7e\xac\xbb\xdc\xde\x58\xc4\ -\x44\x24\x48\xb2\x7a\x8f\x41\xe4\x05\xfe\x3d\x86\x91\xbf\xb6\x02\ -\x86\x81\x66\x1a\xf8\x3b\x9b\x10\x85\x14\xea\x75\xc6\xeb\x75\x3e\ -\xfc\xc1\xb3\x7c\xf7\x2b\x7f\x8d\x3d\x18\x62\xbb\x43\x7e\xff\x7f\ -\xfb\x7d\xa6\xa6\x0d\xbc\x00\xdc\x61\x44\x67\x7b\x07\x35\x0a\x98\ -\x1a\x19\x61\xbc\xac\xf1\xc2\xf7\x5f\xc1\xd2\x35\xde\xb9\x78\x81\ -\xbd\x7b\x67\xf8\xa5\x0f\x3d\xc9\xd6\xa6\xc7\xe7\xff\xe2\x8b\x58\ -\x86\xc9\xb1\xe3\x47\x98\xdd\xb3\x87\xef\x7c\xf7\x5b\xfc\x57\xcf\ -\xfc\x0a\xce\xd0\x85\x38\xe4\xc2\x5b\x6f\x90\x33\x8c\x94\x77\x4e\ -\x1a\x93\x7a\xf5\xca\x15\x76\x9a\xdb\x6c\x6c\xac\x30\x3e\x31\xc6\ -\xd4\xd4\x14\x37\xaf\xdf\x40\x95\x15\x86\xc3\x21\x51\x10\x30\x31\ -\x31\x41\xab\xd5\x42\xd7\x75\x86\x8e\x43\xb5\x5a\xc5\x0b\x7c\xda\ -\xdd\x0e\x86\x61\xa0\xca\x0a\xce\xd0\xe6\xcc\xa9\x07\x69\xf7\xba\ -\xbc\xf5\xf6\x05\x66\xf6\xec\xc3\x09\x7d\x8e\x1e\x3f\x86\xa4\xa9\ -\xb8\x61\x44\xa3\xd3\x46\xb3\x2c\xf2\xe5\x12\xf3\x47\x8f\x92\xc8\ -\x12\x97\xaf\x5e\xc1\xb0\xf2\x5c\xbd\x72\x8b\x6b\x37\x17\x39\xfb\ -\xf4\x87\x50\x4d\x13\x4f\xc8\x7c\xef\xc7\xe7\xb8\xba\x78\x9b\xcd\ -\x76\x9b\x28\x11\x58\xa5\x32\x01\x31\xba\x61\x61\x18\x46\xca\x69\ -\x97\x65\x92\x24\xc1\x1e\x7a\x78\x5e\x70\xef\xcf\x77\x1f\xea\xc0\ -\xf1\x53\xea\xe6\xee\xac\x0b\x12\x68\x1a\xd2\x2e\x19\x44\x92\xa4\ -\x7b\x39\x55\x9d\x4e\x07\xcf\x75\xd1\x74\x1d\x49\x92\x08\x82\x00\ -\x21\x04\xa6\x69\xd2\xef\x74\x60\x63\x03\x8a\x45\x32\x23\x23\xf7\ -\x66\xee\x4c\x26\x43\x7f\xd0\x4d\x75\xde\x71\x9c\xb6\xe2\xc3\x61\ -\x4a\xcd\x5d\x58\xe0\x91\x5f\xfb\x35\x36\xef\x2c\x70\xfb\xea\x15\ -\x9e\x7c\xf8\x14\x47\xf7\x4c\x90\x95\x62\x26\x0b\x19\x7e\xf9\x83\ -\x8f\x60\x40\x5b\x21\xfe\x3d\x2d\x49\x3e\xab\x88\x18\x05\x81\x94\ -\xc4\xa9\x43\xcd\x2e\xe6\x8b\x48\xa9\xa9\x31\xef\x9a\x49\xde\x35\ -\x28\xb8\x6b\xb8\xff\x7e\xe5\x3b\xff\x5c\x85\x9c\x9e\x34\x3f\xe9\ -\xe4\xf1\x6e\x07\x7d\xcf\x44\x2b\x75\xec\xb8\xe7\x14\x21\x7e\x6a\ -\x6d\x25\x91\x20\x70\xfc\x04\x2f\x14\xfb\x74\x4b\x59\xec\xf9\x24\ -\xdf\x7d\xf1\x0a\x5f\x79\xee\x07\x5c\x59\x5e\xa7\x9d\xc4\x84\x59\ -\x0b\x6b\xac\x8e\xa7\xca\x34\xbd\x21\x74\x5b\x50\x28\x40\xa2\x90\ -\x35\x53\xe2\xa3\xe3\x38\x44\x41\x04\x5e\x98\x7e\x92\x9a\x9e\x02\ -\x5a\x7e\x00\xaa\x8a\x6e\x98\x08\x21\xa1\xca\x12\xba\xaa\x81\x94\ -\xd0\x6c\xee\x90\x48\x02\x21\x29\x08\x91\xda\xb5\x11\x85\xe9\x03\ -\x44\x8c\x96\xcb\xe0\xf7\x7b\xe4\xb3\x59\x2c\x5d\xa1\x60\xea\xf8\ -\xb6\xcd\xef\xfd\x2f\x9f\xa2\xa0\xc3\xd5\x57\x97\xb0\x14\x95\xef\ -\x3c\xff\x1c\x1f\xfb\xc4\xc7\x59\xbc\xb3\xc8\xb9\x97\x5f\x64\x79\ -\x71\x81\xd3\xf7\xdd\x47\x6b\x6b\x9d\xc9\x7a\x9d\xfb\x8f\x9d\x60\ -\xe1\xfa\x75\x5e\x7f\xed\x55\xf2\xf9\x2c\x87\x0e\xcf\x71\x60\xf6\ -\x10\x71\xa4\xd2\xdc\x6e\xb3\xb8\xb8\xc8\xc9\x93\x27\x51\x85\xe0\ -\xfa\x8d\xab\x1c\x98\x99\x21\x9f\xcb\x40\x18\x62\x69\xa9\x11\x81\ -\x2e\x4b\xac\xad\x2c\xb3\xb1\xb2\x42\xb9\x54\xc2\x76\xfb\x54\x46\ -\x2b\x34\x1a\xdb\x14\x0a\x05\x14\x59\x66\x71\x71\x91\xe9\x89\x49\ -\x06\x83\x01\xb6\x6d\x33\x1c\x0e\xa9\x54\x2a\xf4\xed\x21\xb2\x2c\ -\x13\x27\x09\xb9\x42\x9e\x5b\xb7\x6e\x71\xdf\x7d\xf7\xe1\x0c\x86\ -\xc8\xc8\x24\x42\xa0\x68\x2a\xed\x76\x87\xca\x48\x9d\xed\x46\x13\ -\x2b\x9f\xc3\xc8\xe6\x38\x79\xea\x01\xd6\xb7\xb7\xa9\xd4\xea\xfc\ -\xbf\x5f\xfe\x0a\xfd\xe1\x80\x30\x8a\xb8\x7a\xe3\x26\x4f\x3d\xf9\ -\x61\x0e\x1f\x39\x4e\xb9\x3e\x42\xcf\x76\x48\x54\x8d\x9e\x1f\xb2\ -\xb0\xba\xc6\x0b\x2f\xbf\x4c\xab\xd9\x41\x29\x95\x89\x84\x84\x9e\ -\xc9\xe2\x47\x11\xb1\x3d\x4c\xbd\xbc\xbc\x00\x39\x97\x4f\xc5\x31\ -\x41\x80\x6e\x9a\x28\x8a\x42\x1c\xc7\x18\x86\x05\x92\xc0\xf7\x7d\ -\xa2\x28\xc2\xf7\x42\xe2\x30\xb8\x8b\x58\xa5\xb7\x7a\x18\x22\x99\ -\x29\x59\x85\x24\x41\x92\xe5\x7b\xac\xaf\xbb\xf6\x46\x85\x42\x21\ -\xfd\x1c\x06\x83\x7b\x37\x35\x72\xda\xa5\xa5\xb4\x6d\x87\x6c\x36\ -\x8b\xeb\x05\x29\x08\x17\x44\x10\x27\xb4\x6f\xdd\xc4\xac\x94\x98\ -\xae\x55\xd9\x58\xba\xc5\xd9\x07\x8e\x33\x92\x37\xe9\xaf\x2d\xf3\ -\xc0\xd1\x39\x4e\x1d\x3b\xcc\xd1\xf1\x91\x7f\x2e\x91\x3c\xaf\x13\ -\x3f\xaf\x20\xa1\x12\x23\xe2\x28\x85\x8d\x76\xe7\xe4\x08\x41\x84\ -\x74\xaf\x90\xdf\xab\x6a\x96\x00\x29\x26\x35\xc2\xf8\xc5\xce\xc8\ -\x3f\x7d\xbf\xfe\x2c\xfd\xf0\xbb\xe3\xfe\x5d\xab\x17\xb8\xcb\x8c\ -\x49\x11\x3e\x3f\x16\x08\x45\x25\x51\xa5\x76\x2b\x26\xf9\xc1\x9b\ -\x0b\x7c\xf5\x87\x2f\xf2\xe2\xd5\x6b\x0c\x55\x1d\xbd\x56\x47\xca\ -\x15\xd8\xec\xb4\x71\x5c\x1f\x7c\x1f\xa9\x5c\x23\x93\xcd\x93\xd1\ -\x0c\xbc\xfe\x10\xa7\xd1\x24\x71\x03\xb8\x6b\xb2\xa6\x1b\x94\x2a\ -\x65\x12\x29\x65\x85\x99\xd9\x1c\x99\x5c\x0e\x48\x08\xa2\x90\x20\ -\x0c\xe9\xf5\xbb\xe0\xda\xbb\x45\x2b\x48\x84\x40\xd5\x0d\x8c\x6c\ -\x06\x2d\x93\x49\x93\x1f\x6c\x17\x02\x0f\xd3\xb2\xd0\x15\x99\xad\ -\xb5\x35\x4e\x1e\x3f\xc2\xe1\xf9\xfd\x7c\xfd\x4b\xcf\x11\xf5\xfa\ -\x24\x9e\xc3\xc1\x83\xb3\x54\xca\x25\xfa\x76\x8f\x46\xb3\xc1\x48\ -\xbd\x46\xb1\x54\xe4\xf4\xa9\x33\x3c\xf3\xcc\x47\xc9\x66\xaa\x3c\ -\xfb\x8d\xbf\xe1\xe8\xc9\xfb\xf8\xc0\x53\x4f\x71\xe9\xea\x0d\x24\ -\xc3\xe2\xc2\xe5\x6b\x08\x43\xa7\x50\xaf\xa2\xe7\xb3\x7c\xe5\x1b\ -\xdf\xe0\xda\xe2\x02\x6f\x5f\xbb\x46\x2c\x2b\xf4\x3d\x0f\x63\x57\ -\x64\x6f\x5a\x26\x23\xa3\xa3\x8c\x8e\x8d\xa2\xe9\x1a\xb6\x3b\x64\ -\x64\xb4\x8e\x69\x1a\x54\x2b\xa9\x9f\xf5\xd4\xf8\x04\x17\x2f\x5e\ -\x24\x97\xcb\xd1\x6e\xb7\xa9\xd5\x6a\x0c\x9c\x34\xe5\x30\x8c\x22\ -\x82\x28\x44\xd6\x54\x0a\xa5\x22\x51\x10\x72\xf0\xe0\x41\x32\x59\ -\x0b\x33\x93\xc1\x30\x0c\x3c\x3f\x60\x64\x74\x94\xa3\xc7\x8e\x63\ -\x58\x16\x33\x7b\x66\xd8\xd8\xdc\x80\x44\x42\x95\x15\xd6\x56\x56\ -\x21\x4e\x28\x17\x8a\x3c\xf1\xf0\x23\x1c\x9d\x3f\x4c\xad\x52\x22\ -\xa3\xe9\x78\xb6\x4d\xbf\xdb\xa1\x90\xcf\xf1\x9d\x6f\x7f\x17\xd3\ -\xb4\x90\x74\x1d\xc3\x30\x89\x63\xd0\x0c\x13\x45\xb3\x50\xb2\x45\ -\xca\x23\xe3\x44\x8a\x46\xe0\xa6\xbb\xe3\x64\x30\x20\xda\xbd\x4d\ -\xc3\x7e\x9f\x68\x57\x4b\x7d\x77\xee\x8d\x45\x0a\x1c\x29\xba\x4e\ -\x26\x97\x43\xb7\x2c\x84\xa6\x11\xba\x1e\xb2\xa2\x90\x84\x21\xc9\ -\x20\x3d\x60\x74\xcb\xba\xa7\x92\xb3\x6d\x9b\x4a\xa5\x82\x1f\x04\ -\x44\x8e\x43\xae\x52\x41\xd3\x34\xbc\x7e\x1f\xa1\xca\x24\x71\x88\ -\xdf\x6c\x22\x32\x19\x54\xdd\xa4\x3f\x74\x88\x80\x48\xd5\x09\x3b\ -\x5d\x9a\xfd\x1e\xf5\xb1\x31\xae\x5e\xbb\xca\xd8\xd8\x18\x63\xe3\ -\xe3\x7c\xeb\x3b\xdf\xa5\x3e\x36\x86\x62\x1a\x8f\x15\x33\x99\xbf\ -\x2f\x23\x7d\x46\x42\x20\x21\x21\xdf\xbb\xb0\xa4\x77\x5d\x39\xdf\ -\x23\x0d\x7a\xaf\x2f\xd8\x3d\x4d\xb4\xe0\x17\x5f\xc8\xbb\xd3\xce\ -\xbd\x6f\x76\xd7\xf7\x3f\x3d\x65\x48\xb9\xca\xb2\xa2\xa4\x80\x53\ -\x98\xfa\x0c\x0b\x59\x26\x41\xe0\xc5\x21\x41\x22\xe1\x44\x7c\xca\ -\x93\xe5\x7f\x32\x80\x2f\xfe\x87\xaf\xbf\xc0\x0f\x2f\x5e\xe6\xfc\ -\xc2\x12\xda\xe8\x38\xcd\x08\x22\x33\x43\xa7\xd5\x44\xce\x97\x48\ -\xc2\x08\x22\xc1\xde\xe9\x19\xfc\xde\x00\xb7\xdb\x4f\x9d\x1b\x77\ -\x4f\xfc\x5c\xae\x80\x95\xc9\xa3\xe9\x26\x61\x14\xe3\x0c\x6c\x24\ -\x45\x45\xd5\x54\x6c\xc7\xc6\xb5\x07\x84\xcd\x1d\x8c\x4a\x09\xdf\ -\x71\x40\x92\x18\x99\x18\x45\x56\x55\x12\x04\xc5\x52\x99\x84\x84\ -\x41\xbf\x8f\x65\x99\x78\xbb\x74\x4e\x91\x24\xb4\x36\xd6\x09\xdc\ -\x21\x96\xae\xb3\xbc\x78\x87\x9d\xb5\x35\xa2\x4e\x97\xf1\x6a\x95\ -\x62\xa9\xc8\xcb\xe7\x5f\x21\x06\x4e\x3d\x78\x9a\x5b\x8b\x8b\xb8\ -\x7e\xc0\xdb\x17\xde\x61\x7d\xa3\x43\x94\x08\xb6\x1b\x6d\xe6\x0e\ -\x1f\xe3\xb9\x17\x5e\xe4\xc3\x1f\xff\x7b\xdc\xf7\xf0\x29\x72\x13\ -\x53\xc8\xe5\x3c\x4b\x8d\x2d\x7e\xf8\xfa\xab\x34\x5d\x9b\x4c\xbd\ -\x4a\x75\x66\x9a\x9b\x6b\xcb\x5c\x59\xbc\xc5\xc5\x5b\xd7\x59\xdd\ -\xdc\xc4\x23\x06\x25\x25\xaf\xf4\xec\x34\x78\xbc\xd3\x6b\xb1\xb9\ -\xb9\xc1\xe8\xc8\x28\x17\x2e\x5c\x60\x73\x6b\x13\xd3\xb2\x08\x77\ -\xf3\x9e\xe3\xdd\x87\xc4\x34\x4d\x9a\xad\x56\xfa\x77\x71\x84\xe3\ -\x38\x78\xbe\x4f\xb7\xd3\xa1\x50\x2a\xa2\x1b\x06\x6b\x5b\x1b\xd8\ -\x8e\x83\x61\x99\x20\xa5\xa3\x49\xbb\xdd\x61\xd8\xeb\x53\xc8\xe6\ -\x91\x13\xd8\x3f\x35\xc3\xfd\xc7\x4f\x82\x1f\x32\x35\x32\x82\x29\ -\x20\xf6\x6c\x1e\xba\xff\x38\x71\x18\x30\x37\x7b\x80\xa9\xd1\x51\ -\xe6\xe7\xe7\x59\x5a\x5c\xa2\xdb\xe9\x33\x18\x38\x04\x71\x82\x33\ -\x70\x10\x5a\x06\xd7\x76\x18\xda\x01\x89\x24\x63\x1a\x7a\xea\xf0\ -\x19\x04\x68\x96\x45\xa5\x56\x45\x36\x0d\xc2\x30\x22\x74\x5d\x82\ -\x41\x3f\x5d\x0f\xb9\x5e\x0a\x0e\xc9\x12\xf9\x42\x01\xdb\x71\xc8\ -\x58\x19\x84\x10\xe4\x72\xe9\xb6\x42\xcd\x64\x08\xfa\x7d\xfc\x30\ -\xc4\xed\xf5\x88\x92\x04\xdd\x30\xe8\xf5\x7a\x29\x31\x26\x8e\x09\ -\xa3\x88\x7c\x3e\x0f\xb2\x8c\xaa\x2a\xe8\x9a\x82\x9f\x24\x24\xb6\ -\x8d\xeb\x7a\xc4\xaa\x9e\xa6\xb6\xca\x0a\x6a\xbe\x40\x9c\x08\x06\ -\xce\x90\x28\x8a\x68\x34\x76\x68\x34\x9a\x20\xc9\x6c\xb7\x9a\x24\ -\x48\xd4\xaa\x15\xb2\x86\xf6\x31\x3f\x8c\x3f\xa5\x49\xe2\xb3\x49\ -\x98\x10\xfb\x21\xb2\x2c\x91\xb8\x7e\x6a\x67\x84\x40\x12\xd2\xbd\ -\xbb\xf8\xae\xf7\x9c\xf4\x9e\x8d\xce\xcf\xcb\x0c\x7b\x1f\x6e\xe4\ -\xbb\x7c\xac\x64\xf7\x9b\xbb\x6b\x52\x96\x02\x5a\xb2\xa2\x10\xf8\ -\x3e\x7e\xe0\xa3\x69\x26\xb2\xac\xd0\xb7\x6d\x82\x28\x42\x55\x33\ -\x44\x42\x26\x91\xe5\xf6\x8e\xc7\x9f\xbc\xb1\xb0\xc2\xff\xf1\x87\ -\x7f\xcc\x1b\x8b\x77\x98\xb9\xff\x34\x4b\xed\x2e\x41\x18\x11\x5a\ -\x19\x8c\x4a\x05\xd3\xca\x20\x62\x89\x28\x8c\xf0\x7a\x03\x86\xad\ -\x0e\xaa\x90\x88\xe3\x88\x6c\x26\x4b\x36\x93\x23\x8a\x62\x6c\xc7\ -\x25\x0a\xd3\x55\x45\xb8\xbd\x4d\x12\x06\x04\xae\x43\x2c\x4b\xc8\ -\x9a\x82\x5a\xc8\x62\x18\x3a\x6e\xbb\x81\x90\x65\x0c\x3d\xd5\x18\ -\xbb\x9e\x87\xed\xba\xb8\xdd\x1e\x0c\x06\x78\x61\x00\xbd\x36\xc2\ -\xb2\x08\x7d\x8f\x6a\xb9\xc0\x13\x8f\x3d\x86\x2a\x0b\x9e\x78\xec\ -\x51\x46\x4a\x45\x8a\xaa\xc6\x37\xbe\xf6\x35\xbe\xf3\xfc\x77\x68\ -\x74\x5a\x3c\x7e\xf6\x2c\x9b\x3b\x0d\x0a\xc5\x12\x8d\x46\xb4\xfe\ -\xfc\xe6\x00\x00\x20\x00\x49\x44\x41\x54\x1b\xd3\xca\x72\xfa\xc1\ -\x47\xd8\x58\xdf\xe6\xad\x77\x2e\xf1\xce\xa5\x6b\x14\x2a\x75\x56\ -\x37\xb6\x79\xe9\x8d\xb7\xd9\x19\xf6\x68\xb9\x03\xee\x6c\x6e\xb2\ -\xdd\xed\x90\xab\xd5\xe8\x39\x2e\xf7\x3f\xf4\x10\x6f\x5f\xb9\x8c\ -\x1f\xc7\xe4\x0b\x79\x14\x55\xa3\x58\x2e\x51\x1f\x19\xc1\x30\x52\ -\x8f\x6d\x3f\xf0\x91\x88\x51\x65\x89\xb5\xf5\x35\xec\xa1\xcd\xe4\ -\xe4\x24\xfd\x7e\x9f\x28\x8e\x19\x9f\x9c\xa0\xd9\x6c\x92\xcb\xe7\ -\x69\x34\x9b\x68\x86\x4e\xa9\x5a\xa1\xdb\xed\x32\x3d\xb3\x07\xdb\ -\xb1\x51\x0d\x9d\xed\x46\x8b\xed\xc6\x0e\x96\x65\x31\x35\x3d\x4d\ -\xa5\x5e\x43\xd7\x0c\x14\x45\xc1\x32\x33\xd4\xaa\x35\x08\x63\x7c\ -\xdb\x65\xfe\xc0\x1c\xcd\xf5\x2d\x9a\x1b\x5b\x4c\x8f\x8f\x73\x6c\ -\x6e\x96\x52\x3e\xc7\xb5\x8b\x97\xb1\x34\x0d\x77\x38\x60\x75\x75\ -\x15\x43\xd5\xe8\xf5\x7a\x5c\x7c\xe7\x32\x41\x18\x32\x3a\x31\x8d\ -\x95\x2f\x61\xe5\x8b\x24\x8a\x86\x1f\xa7\x0f\x6d\xe8\x3b\xc8\x12\ -\x44\xbe\x4f\x14\x04\x0c\x1d\x1b\xaf\xdf\x47\xd6\x74\xf2\xc5\x22\ -\x72\xc6\xc2\xcc\xe5\x40\xd5\x88\x3c\x0f\x9a\x0d\x6c\xdb\x26\xea\ -\xf7\x89\x55\x15\xb7\xdb\x23\x11\x82\x38\x8e\xd3\xcf\x24\x49\xc8\ -\xe4\x72\xa8\x86\x41\x26\x9b\x65\xd0\xef\x93\x44\x11\x51\x9c\xaa\ -\xad\x12\xdf\x47\x31\x0c\xa2\x28\x42\x37\x34\x0c\x3d\xf5\x0a\x0e\ -\xc2\x28\x6d\x1e\x77\x09\x1f\xc4\x90\xc8\xa9\x84\xb2\x50\xad\x52\ -\x2c\x16\xe9\xf5\x7a\x6c\x6d\xef\x20\x14\x85\xbe\xeb\xf1\xda\xeb\ -\xaf\x43\x18\x33\x31\x35\x33\x6e\x59\xda\xb8\x6d\x87\x9f\x0e\x7c\ -\xf7\x63\x0a\xe2\xb3\xaa\xaa\xc2\xee\xde\x5c\xdc\x2d\x52\x01\x22\ -\x4e\x77\xb0\x0a\xff\x89\xcb\xd5\x2f\xb6\x90\xdf\x6d\xa9\x93\x9f\ -\x18\xe6\xb9\x2b\xef\x92\x64\x64\x49\x46\x92\x64\xa2\x04\xfc\x04\ -\x24\x4d\x47\x56\x75\x22\x60\xdb\x8f\x13\x5f\x16\xbf\xfb\xe3\x8b\ -\xd7\xf9\x57\xff\xf6\xdf\x11\x65\xf3\x14\xa6\xf7\x72\xf5\xad\xb7\ -\x88\xca\x65\xf4\xda\x08\xc9\x2e\x61\xc3\x69\x36\x09\x3d\x1f\x53\ -\x51\x89\x1d\x8f\x72\x3e\x8f\x90\x05\x61\x18\x60\x18\x26\x86\x61\ -\x30\xb4\x1d\x5c\xc7\x21\x8c\x62\x42\xc7\x43\xaf\xd5\x90\x0c\x13\ -\xc5\x32\xa8\xd5\xab\x28\x72\x82\xef\xb9\x24\xa1\x8f\x24\x4b\x24\ -\xbe\x8f\xef\xd9\xd8\x83\x01\x49\x94\xce\x50\x7a\x26\x83\x56\xc8\ -\xa1\xea\x3a\xa1\x24\xa8\xd7\x6a\x24\x61\xc0\xc9\x63\x47\x59\x59\ -\xba\xcd\xf6\xc6\x0a\x19\xc3\x60\xf1\xfa\x75\xae\x5d\xb8\x80\xa2\ -\xa8\x3c\xf4\xc4\xe3\xfc\xf6\x3f\xfa\x87\x64\xcb\x15\x24\x5d\xe3\ -\xc0\xdc\x3c\x7e\x18\x93\xc9\x64\xc9\x17\x8a\xfc\xd5\x97\xbe\xc2\ -\xda\xda\x06\xff\xe8\x7f\xf8\xc7\xfc\xea\x33\x8f\xf3\xe2\x8b\x97\ -\xb8\x7a\xe3\x06\x1b\xcd\x4d\x16\xee\xdc\xa6\xdd\xee\x20\xc9\x2a\ -\xcd\x56\x9b\xee\xd6\x16\x03\x3f\xa4\xdb\xed\x32\xe8\xf6\x89\xa3\ -\x84\xad\xf5\x75\x7a\x9d\x2e\xba\x2c\x11\x87\xa9\xcd\xae\xef\xd8\ -\xb8\xee\x80\x52\xb1\xc4\xca\xea\x1a\x96\x69\x51\x1f\x19\x41\x96\ -\x15\x4a\xa5\x32\x61\x14\xd3\x68\xb6\x28\x16\x4b\x78\x9e\xcf\xc8\ -\xe8\x28\x61\x1c\xa3\xaa\x1a\xd5\x6a\x8d\x6c\x36\x87\xa2\xeb\xf8\ -\x41\x48\x9c\x24\xa8\x9a\x46\x18\x25\x0c\x07\x36\x42\x08\x8a\xc5\ -\x22\xbe\xe3\xa1\x48\x32\x9e\xe3\x51\xce\x17\x58\xb9\xbd\x44\xd6\ -\x34\x91\x92\x84\x47\xce\x9c\x61\x6b\x6d\x19\x77\xd0\xa7\xdd\x68\ -\x50\xc8\x66\xd9\xbf\x7f\x1f\xae\xed\xf0\xc8\x89\x19\x66\x0f\xcd\ -\xb3\xbc\xb6\xc9\xf6\x4e\x93\x18\xc1\xf6\x4e\x93\xc1\xd0\x25\x12\ -\x10\x27\x09\x66\xc6\x40\x53\x24\x14\x45\xc2\xf7\x7d\x90\x24\x14\ -\x55\x23\x4e\x52\x08\xd5\xf3\x3c\x02\xdf\x27\x0e\x23\x84\x94\xa2\ -\xd0\x89\x69\x51\xdc\xf5\x4b\x93\x24\x89\x28\x4e\x52\x89\x69\x18\ -\x12\x04\x01\x89\xe3\x10\xed\x02\x66\x8a\xa2\x90\x24\x09\xc6\x5d\ -\xd9\xa3\x2c\x13\x3b\x0e\x89\xaa\xe2\xb9\x2e\x42\x02\x67\x68\xa3\ -\xa8\x2a\xfe\xae\xa1\x9e\x92\xc9\x22\x29\x32\xb1\xef\xdf\x23\x98\ -\xb8\xbb\x40\x5a\x26\x9b\x8e\x66\x8a\x6e\x20\x6b\x3a\xbd\xc1\x90\ -\x6b\x57\xaf\x71\xfe\xb5\xf3\x3c\xf2\xe8\x07\xa8\xe6\x94\x2f\x19\ -\xba\xf6\x21\x29\x91\x91\xe3\x04\x71\x97\xdc\x74\x77\x57\x8c\x40\ -\x08\xe9\x5e\x4b\x2d\xfd\x54\xdd\xfe\x3c\x85\xac\xbc\x3f\x45\x9c\ -\x1e\x62\xf2\xae\x59\xde\x5d\x96\x14\xa4\x76\xb0\xb2\x92\x06\x87\ -\xfb\x41\x88\x1f\xc7\xa8\xba\x4a\x02\x0c\x62\x5a\x9a\x26\x71\x6e\ -\x61\x9b\xbf\xf8\xfa\x37\x59\xd8\x6c\x90\x9f\x9c\x66\xab\xd1\x44\ -\xda\x33\x83\x51\x28\x22\x19\x16\x81\xed\x10\xb4\xda\xd0\xeb\x22\ -\x0a\x65\xb2\xd9\x2c\x42\xd7\x29\xe6\xb3\x6c\xb5\xb6\x09\xe2\x08\ -\xdb\xf5\x52\x75\x8d\x1f\xa1\x1a\x06\x08\x85\xa0\xdd\x46\xe4\xf3\ -\xc8\x92\x40\x92\xa0\xb9\xb5\x4e\x14\xfa\xc4\x83\x01\x81\x2a\x83\ -\xef\x31\x3a\x52\xc7\xf7\x7d\x84\xac\x12\x09\x05\x37\x08\x76\xc1\ -\x87\xdd\x75\x49\xb3\xc5\x4e\x1c\x93\xb8\x0e\x2f\x9f\x7b\x91\xc8\ -\xb5\x39\x32\x37\xcb\x57\xbe\xf2\x15\xe6\xa7\xf7\x70\xea\xa1\x47\ -\x19\xab\x55\x39\x70\xe4\x10\x5f\xfc\xeb\xbf\xc6\x8d\x62\xb6\x7b\ -\x6d\x6e\xdd\x5c\xa4\x5e\xaf\xf3\x81\x47\x1f\x63\xff\xfe\x29\xa6\ -\xf7\x4c\x72\xe7\xca\x55\x2e\xbe\xfd\x16\x96\xa1\xb1\x74\xeb\x26\ -\xa6\x22\x63\x1a\x19\xbc\xd8\x67\x75\x63\x13\x2f\x88\x29\x14\xcb\ -\xf8\x99\x22\x91\x1f\x11\x06\x30\x36\xb9\x07\xe1\x79\x08\x64\x82\ -\x28\x46\xd5\x33\x54\xaa\x35\x72\x9a\x4a\x66\x74\x94\x8d\x8d\xdb\ -\xe4\xb2\x26\x07\xe7\xe6\xa9\xd5\xaa\xb8\xb6\x4b\x3e\x9f\x47\x96\ -\x14\x2e\x5f\xba\x48\xad\x56\xa7\xdf\xef\x93\xcd\xe5\x31\x4d\x93\ -\xf6\xe6\x16\x27\x4e\x1e\xe7\xce\xf2\x0a\xd3\x7b\x67\x88\xa2\x88\ -\x4a\xb5\x96\xea\xac\x75\xf3\x1e\xcb\xaa\xdf\xef\xb3\xb8\x74\x9b\ -\x5a\xa5\x4e\x2c\x60\xcf\x9e\x3d\xe4\x33\x59\xda\xad\x16\x86\xa1\ -\xd3\x6e\x34\xb9\x75\xe3\x1a\x1b\x1b\x2b\x1c\x39\x7a\x98\x6a\xbd\ -\x4e\x7d\x74\x94\x0b\x97\x2e\x13\xc4\x82\xff\xf0\xf9\x67\x29\x4f\ -\xec\xe1\xe1\xfb\x8e\x63\x3b\x1e\x56\x7d\x9c\xdb\xdb\x0d\x1a\x43\ -\x1f\x4f\x56\xe9\x74\x7a\x38\xb1\xb7\x4b\xaa\xdb\x35\x2b\xb4\x2c\ -\xb2\xd9\x6c\x9a\x8e\x99\x08\x5c\xdf\x4b\xe9\xb1\xc3\x21\x44\xc3\ -\x77\x51\xec\x7c\x1e\xcb\xb2\x52\xe4\x7a\xb7\xa0\x85\x10\x69\xf0\ -\x80\x10\xc4\xbb\xa4\x12\xdf\xf7\x51\xd5\x74\x1b\x11\x04\xa9\xca\ -\xab\xe7\xa4\x33\x39\x49\x42\xe0\x47\x84\xbd\x7e\x6a\x56\x10\x45\ -\x10\x84\x69\x10\x9d\x6a\x30\xd0\xd2\x3d\xb4\x99\xcd\xe2\xac\x2c\ -\xd3\xf4\x3d\xea\x63\xa3\x68\xf9\x32\xcd\x46\x03\x49\x24\x14\x0a\ -\x75\x3c\x9a\xac\x0e\x3c\xbe\xfe\xc3\x97\xf8\xaf\x3f\xfe\xc4\xaf\ -\x6e\x37\x9d\x64\x7f\xc5\x14\x81\x1f\xa3\xc8\x32\x82\x30\x85\xb9\ -\x92\x5d\xf5\x14\x77\x0b\xfa\xfd\x15\x4d\xbc\x0f\xad\xf5\x5d\x05\ -\x48\xfc\x9e\xdb\x58\xdc\x73\x03\x90\x64\x8d\x28\x4e\xf0\x63\x50\ -\x55\x19\xa1\xc8\x0c\x9c\xe8\x75\x37\xe4\x4f\x22\x4d\x98\x3b\xc0\ -\x1f\xfc\xc7\x2f\x73\xfe\xf2\x55\x94\x7c\x99\x61\x2c\x70\x07\x03\ -\xaa\x13\x7b\xe8\xdb\x1e\x5e\xa3\x41\x22\xcb\x10\x86\xc8\xe5\x0a\ -\x23\xb5\x3a\x51\x1c\xe1\x87\x3e\x3d\xbb\x4f\x7f\xd0\x01\x45\x42\ -\xd6\x74\xc2\x24\x26\x12\x12\x99\x6c\x16\x59\xd5\xf0\x1d\x87\x30\ -\x0a\x80\x04\x5d\x4e\x70\xd6\x56\x29\x14\x4b\x14\x0a\x59\x32\x8a\ -\xcc\x70\x6b\x13\xdd\xd0\x21\x0a\xc9\x64\x2c\x64\x59\xa2\x37\x18\ -\xe2\xbb\x4e\xea\xb4\x38\x18\x80\xa6\x52\x28\x17\x91\x45\xc2\x48\ -\xb5\x82\x2c\xa0\xd3\xd8\xe6\x93\xff\xe5\x27\xa8\x14\x4a\x1c\x98\ -\x9d\xa7\xdb\x1f\xf2\xc5\x67\x9f\x65\xe6\xc0\x41\xb6\x3a\x2d\x34\ -\xd3\xe4\xf0\xd1\x23\x0c\xfb\x03\x9a\x3b\x3b\xec\x9f\xd9\x4b\x7f\ -\xa7\x41\xbf\xd7\x66\x6b\x75\x99\x8f\x3c\x79\x96\x61\xa7\xc5\xfa\ -\x9d\x25\x66\x26\xc6\x48\xdc\x80\x72\xb6\xc0\xc9\xc3\xc7\x29\x64\ -\xf2\x3c\x72\xe6\x61\xce\x3d\xf7\x43\x1e\x38\x75\x86\x24\x88\xe9\ -\xb7\x7b\x8c\x54\x2a\xa8\x42\x62\xdf\xe4\x34\x23\xd5\x0a\x81\xed\ -\x62\x18\x3a\xbe\xe7\xe0\x87\x3e\x9a\x6e\x32\x32\x36\x4a\x10\xc6\ -\x29\x1e\x60\xbb\xe8\x9a\xc6\xde\x7d\xb3\x6c\x6d\x6d\x31\x31\x31\ -\x85\x24\x49\x98\x56\x96\xf9\xb9\x39\xda\x9d\x2e\xb5\xfa\x08\xad\ -\x66\x9b\x52\xb9\x4c\xa1\x54\xc2\x71\x7c\xb6\xb6\x77\xb0\x6d\x87\ -\x6c\x2e\xcf\xc8\xe8\x18\x8a\xa6\x62\xbb\x0e\x1b\x9b\x1b\x74\xba\ -\x6d\x3e\xf8\xe4\x07\xb1\x3d\x07\x84\x20\x12\x31\xf5\xb1\x51\x5a\ -\x9d\x2e\x31\x82\x57\xdf\x78\x83\x7c\x3e\xcf\xf8\xc4\x04\xa5\x6a\ -\x99\x43\x87\xe6\x40\x92\x30\x2c\x83\x3d\x7b\x67\x58\xdb\xda\xa0\ -\xdd\xeb\x90\xcd\x67\x40\x61\xf7\x67\x13\xa3\xef\x02\x53\x44\x11\ -\x41\x18\xe2\x7a\x1e\x92\x24\xa3\xc8\x32\x9a\xaa\xa1\x59\x26\x56\ -\xae\x40\x8c\x20\xde\x69\xe0\x86\x11\xbe\xe3\x12\xec\x62\x2e\xec\ -\x0a\x61\x34\x4d\x43\x35\x0c\x62\x21\x10\x72\x4a\x7b\x0c\x6d\x9b\ -\x20\x8e\xf1\x1c\x27\x35\xa3\x88\x63\x14\x55\x45\xd3\x77\xf5\xe7\ -\xb2\x82\xae\x1b\xf8\x5e\x00\xfd\x3e\x51\x14\x93\x28\x12\xba\xaa\ -\x60\xea\x1a\x71\x1c\x11\x6b\x0a\x89\x1b\x30\xf4\x3c\x24\x45\xc3\ -\x8f\x62\x42\x2f\x24\x51\x75\x14\xd3\x24\x92\x04\x97\xae\x5c\x41\ -\xa8\x19\x1e\x39\xbe\x8f\xae\x1d\x7f\x5a\x26\xf9\x9c\x69\xa8\xed\ -\x28\x8e\x52\x1e\xb6\xf4\x1e\xbb\xa0\x7b\x8c\xae\x9f\x94\x55\xfc\ -\xc2\x5a\xeb\x9f\xb4\xae\x4d\x7e\x86\x65\xad\x04\x92\x84\xb4\xbb\ -\xd6\xf1\xa2\xf4\xf0\x53\x55\xe9\xb3\x21\xe2\x63\xeb\x1d\x7f\xfc\ -\x8f\xbe\xfc\x2d\x9e\x7f\xfd\x4d\xa4\x4c\x8e\x00\x41\x79\x74\x8c\ -\x44\xcb\xd0\xbe\x7d\x27\x2d\xe0\x18\x64\x43\x27\x91\x14\x2c\xcb\ -\x20\x8c\x43\x3a\xbd\x2e\x6e\x1c\xe0\x87\x1e\x84\x3e\x56\xad\x46\ -\x26\x9f\x27\xdc\x5d\xc0\x47\x24\x78\xae\x07\x61\x80\x9e\xb1\x20\ -\x0c\xb0\x34\x1d\x4d\x53\xa9\x15\x73\x44\xf6\x10\xa7\xd3\x41\xd3\ -\x55\x4a\x85\x2c\x83\x7e\x97\x76\xbb\x43\x6f\xd0\x23\x89\x22\xac\ -\x5c\x9e\x4c\x2e\x8b\x8f\xc0\xca\xe5\x89\xc2\x80\x62\x3e\xc7\xc6\ -\xea\x0a\x8a\x88\xa9\x14\x0b\xdc\x59\xba\xcd\x43\x67\x1e\xe6\xe1\ -\x33\x33\x7c\xe1\xaf\xbe\x4f\x28\x4b\xbc\xf2\xe6\x9b\x14\xeb\x55\ -\x16\xef\x2c\xb1\xb2\xb2\x42\xa7\xd5\x60\x6e\xdf\x0c\x73\x7b\x67\ -\x28\x99\x3a\x05\x43\x67\xa2\x5a\x62\xef\xc4\x18\x23\xa5\x02\x0f\ -\x9e\x3c\xce\xa9\x07\x4e\x31\x3b\x3b\xcb\x68\x6d\x8c\xf9\xf9\xc3\ -\xcc\x1d\x3a\xcc\xa9\x53\xb3\x0c\x7c\x95\x07\x1f\x7a\x88\x7d\xfb\ -\x67\x29\x57\xca\xcc\x1d\x9a\xc7\x30\x34\x46\xea\x35\xac\x9c\x05\ -\x42\x10\x84\x3e\x42\x86\x5a\xb5\x8a\xa4\xc8\xf4\x7a\xfd\x7b\x3f\ -\x99\xb5\xb5\x55\x2a\x95\x2a\xaa\xa2\xd0\xed\xf6\x98\x9e\x9e\xc6\ -\xf7\x03\x72\xf9\x3c\xdb\xdb\x3b\xe4\x0b\x05\x0c\x5d\x4f\xcd\x0c\ -\x85\x84\x24\x24\xca\x95\x0a\x53\x33\x7b\xa8\xd4\xaa\x44\x22\xa1\ -\x37\x1c\xa0\x99\x06\xb9\x62\x81\x76\xb7\xc3\xcc\xde\xbd\xac\x6e\ -\xac\xf3\xed\xe7\xbe\xcb\xe1\x63\x47\x18\x9b\x9c\xc0\xc8\xe4\xc8\ -\x15\x4b\x6c\xee\x34\x18\x19\x1b\x63\xe8\xb8\x98\x19\x8b\x1b\xd7\ -\xaf\xd3\xea\x76\xb8\x7d\x67\x89\x43\xc7\x8e\x70\xea\xe8\x24\xd7\ -\x97\xd6\x38\xff\xe6\xeb\x74\xbb\xad\x14\x04\x12\x09\xa6\x95\x45\ -\x56\x54\xbc\x5d\x8d\xb1\xa2\x69\x48\x42\xa4\x87\xbf\x93\x1e\xa8\ -\x71\x14\x61\x18\x26\xaa\xa6\xe1\x86\x21\xd9\x72\x19\x21\xcb\xc4\ -\x71\x7c\x6f\x6f\x1c\xc7\x31\xae\x6d\x13\xc5\x31\x71\x10\xa0\xee\ -\x16\xb6\x50\x14\x34\x4d\x23\xda\x5d\x47\x91\x24\x44\x5e\x4a\xeb\ -\x8c\xe3\x98\x4c\x26\x83\xbc\xbb\x8e\x0a\x12\xd2\x9b\x59\x02\x59\ -\x80\xe7\xd8\xc8\x42\xa0\xab\x1a\xbe\x1f\x42\x02\x56\xae\x84\x50\ -\x34\x82\x20\x06\x5d\x23\x92\xa1\xbb\xb6\x86\x9c\xcd\xb0\xb9\xba\ -\xce\xde\x7d\xf3\x54\x8b\x59\x74\x45\x1a\x57\x25\xbe\x44\x12\x21\ -\x64\x81\xd8\x45\xb5\x12\xc1\xbb\xf2\xc7\x9f\x92\x3d\xfd\x3c\x85\ -\xfc\x3e\x10\x42\xee\xfe\x26\xfa\xc9\x00\xac\x44\x90\x24\x31\xb6\ -\xeb\x93\xc9\x5a\x84\x02\xba\x76\xf4\x29\xd5\x94\x3f\x2b\x0b\xb8\ -\x76\x7b\x27\xf9\xeb\x1f\xbf\xcc\xff\xfd\xcd\xef\xa0\x8e\x8e\x23\ -\x6b\x3a\x9a\x6e\xb2\xb1\xd5\x20\x6a\x77\xd9\x73\xe2\x7e\x3a\xc3\ -\x21\x8a\x61\xd2\xec\xb4\x53\xe3\xb6\x38\x48\x87\x0b\x55\x4d\xc5\ -\x1a\x72\xea\x7a\x5e\xaa\x54\x08\x83\x98\x81\x63\x23\x09\x8d\xc8\ -\xb6\xd3\xc8\x4f\x2b\x83\xae\xc8\x44\x8e\x83\x14\x78\x94\x73\x19\ -\x44\xe8\x61\xca\x12\xde\x70\xc0\x91\x63\x87\x38\x76\xff\x71\x96\ -\x37\xd6\xb8\xb3\x9a\x06\x83\x0f\xfc\x80\x44\xd2\x70\x83\x88\x7e\ -\xa7\x4d\xb9\x56\xa7\xb5\x74\x1b\x84\xe0\xf0\xd1\x43\x9c\x3c\x32\ -\xc7\x53\x8f\xdf\x8f\x3b\x8c\xa8\x16\x65\x5e\x7f\x6d\x8d\x2f\x7c\ -\xf1\xaf\x70\x02\x07\x23\x67\x11\xc4\x01\x9a\xa6\x90\xcf\x9a\x2c\ -\xdf\xbc\xce\x4c\xbd\xc6\x27\x3f\xfa\x51\xaa\x56\x86\xc4\xb1\xd9\ -\x33\x36\x86\xd3\xef\xe1\xbb\x1e\x23\x53\x53\xdc\xd9\x6e\xe3\x2b\ -\x1a\x7f\xfa\xef\xff\x23\xaf\x5f\xbe\xc4\x47\x3f\xf1\x49\x1a\xbd\ -\x1e\x8f\x3e\xf9\x14\xff\xfa\xdf\xfc\x21\x99\x4c\x86\x28\x70\xa8\ -\x15\xf2\xd8\xdd\x16\x73\x7b\x26\x39\xb4\x77\x9a\x93\xc7\x8e\xd2\ -\x5a\x5b\xa6\xa2\x0a\xea\xf9\x1c\x8e\xe3\xd0\xef\xf6\xd0\x15\x95\ -\x28\x0c\x59\x59\x5c\xa2\x54\x2a\xe1\xda\x0e\x3b\x3b\x3b\x4c\x4f\ -\x4f\xdf\x33\xb6\xdb\xd8\xd8\x60\x66\x66\x06\xdd\x34\xa8\xd5\x6a\ -\x78\x61\x0a\x06\x09\x59\x22\x4c\x42\xa2\x24\x46\x52\x14\x34\x43\ -\xa7\xdd\x6e\xb3\xb1\xb5\xc9\xed\xc5\x5b\x3c\xf3\xcc\x33\xdc\xba\ -\x71\x13\x5d\xd7\x39\x71\xf4\x18\x2b\xcb\x1b\xd8\xb6\x47\xad\x3a\ -\x42\xb1\x90\xa3\xdf\xef\xe2\xbb\x0e\xbd\x5e\x87\x6c\x21\x4f\xae\ -\x54\xe6\xdc\x6b\xe7\xc9\x56\x2a\x44\xba\xc5\xf3\x2f\xbd\xc4\x30\ -\x81\xd1\x99\xbd\xe8\xd9\x02\x9b\x9d\x21\xd7\x6e\xad\xe1\xc7\xd0\ -\xd8\xde\x06\x21\x28\x56\xca\xe9\x1e\x38\x82\xe1\x70\x98\x6e\x3a\ -\xec\x61\xba\x56\x4c\x12\xe8\xf7\x29\x1e\x38\x90\xae\x90\x3c\x0f\ -\xb1\x2b\x82\x88\xe3\x98\xa8\xdf\x4f\x9f\x0d\xc7\x81\x5d\x2d\xb6\ -\xae\xa7\xc0\xe0\xdd\x71\x41\x96\x65\xdc\x8d\x0d\xd4\x7a\x9d\x20\ -\x08\xc8\x64\x72\xf8\xbe\x9f\xea\x9a\x81\x4e\xa7\x85\x2c\xa7\x64\ -\x21\xa7\xd3\x21\x5f\xab\x31\x74\x5c\x22\xc7\x47\xd2\x4d\x54\xdd\ -\xc0\x73\xfd\xb4\x5b\x23\x22\x33\x59\x21\xab\xc9\x64\x23\x9f\xc1\ -\xf2\x12\xee\xf2\x6d\x9e\xfd\xf3\x3f\x61\x4f\x31\x43\x49\x13\x42\ -\x49\x42\xd2\xc8\x1a\xf1\x9e\x3c\x33\x29\x65\x32\xf2\x93\x59\x66\ -\xbf\xd0\x42\x7e\x37\xb5\x2e\x79\x37\x17\x87\x38\x95\x73\xc5\x31\ -\x89\x50\x11\x92\xc0\x8b\xc1\x97\x53\x45\xc8\x72\x23\x48\xbe\xfc\ -\x37\xdf\xe4\x73\xdf\xfa\x36\x5b\x56\x81\x38\x5f\x24\x9f\xcf\xd3\ -\x6c\xb4\x49\x12\xc1\xd8\xe8\x38\xb1\x00\xc7\xf3\xd1\x0c\x8b\xed\ -\xeb\xd7\x60\xa4\x06\x02\x64\xcb\x4c\x09\x0b\x2b\xcb\x10\x85\x28\ -\x85\x34\x64\xdb\x6b\xb6\x21\x4c\x50\xab\xf5\xdd\x38\x11\x97\xf2\ -\xe8\x38\x78\x1e\xb5\x6c\x86\xad\x3b\x4b\xe4\x34\x89\x9c\x26\xf1\ -\x9b\xcf\x7c\x12\x11\xf9\xec\x9b\xdd\x83\x59\x48\x3f\xcd\xa1\x0b\ -\x57\x17\xb6\x78\xf5\xe2\x65\x2e\xdd\xbc\xc5\xea\x76\x13\x86\x0e\ -\x07\x0e\x1d\x21\x67\x99\xf4\x5a\x3b\x38\xc3\x1e\x27\x4e\x1e\x66\ -\x63\x65\x09\x89\x90\xc5\x6b\xb7\x99\x9a\x3c\xc8\xe8\xe8\x34\x6f\ -\x5c\x7a\x1b\x61\x68\x68\x86\x4a\xa7\xd3\xe4\xa1\xd3\xf7\x51\xcf\ -\x5a\x5c\x3e\xff\x0a\xff\xe2\x9f\xfd\x53\xb4\x30\x64\x63\x69\x91\ -\x77\x5e\x7f\x9d\xa7\xce\x9e\x25\x93\xc9\xb0\xd5\x1d\x70\x79\x75\ -\x87\x57\x2f\x5d\x61\xb5\xd1\x22\x54\x54\xae\x2c\xde\xa6\x50\x1b\ -\xa1\xd3\x6c\x22\x32\x39\x12\xdb\x26\x5f\x29\xa3\x08\x18\xb6\x9b\ -\x14\xb3\x3a\xc5\x7c\x86\xb3\x8f\x3e\xca\xb9\xef\x7f\x97\xbd\x95\ -\x12\x9d\xcd\x4d\xa6\xc7\x27\x78\xe8\xcc\x69\x0a\x86\x41\xaf\xdd\ -\xc2\x10\x12\x85\x7c\x16\xb7\x3f\x64\x69\xf1\x36\xba\xae\xb3\x7f\ -\xff\x7e\xfa\xfd\x3e\x66\xc6\xc2\xb6\x6d\x14\x45\x21\x57\x2c\x21\ -\x84\x20\x8a\xd3\x88\x1d\xc3\xd0\x30\x32\x16\x51\x12\x33\x74\x1c\ -\x5a\x9d\x36\x8d\x46\x03\xdf\xf7\xd1\x74\x05\xd7\xf1\x99\x3d\xb0\ -\x0f\x4d\x35\x18\x0e\x1d\x6a\xf5\x31\x86\x8e\x87\xb4\x6b\x86\x58\ -\x29\x17\x99\x9e\xa8\x71\xe3\xfa\x6d\x56\x56\x57\x09\x93\x98\x3d\ -\x07\x66\xa9\x4c\x4d\x70\x63\x6d\x8b\x2b\x2b\xab\xbc\x7a\xe9\x12\ -\xeb\xad\x1e\x83\x20\xe6\xe0\xa1\xfb\x89\x12\x89\xa5\xa5\x25\x36\ -\xb7\xb6\x88\x3c\x1f\xe2\x18\x35\x5b\x40\xd6\xd4\x7b\x96\xb4\xb9\ -\x5c\xea\x49\xd6\xbc\x75\x0b\x51\x4e\x5d\x4f\x62\xd7\xa5\x32\x3e\ -\x89\xef\xfb\x18\x86\x81\xe3\x38\x28\x8a\x42\xa7\xd1\x48\x49\x23\ -\x71\x04\x41\x80\xc8\xe5\x28\x95\x52\x1d\x77\xd6\xb4\x68\x2c\x2c\ -\x90\x9f\x9c\xc4\x75\x7c\x12\x01\x41\xaf\x87\x9e\x2f\xa0\x1b\x2a\ -\xbd\x56\x03\xc5\x30\x28\x15\x72\xb4\xbb\x5d\xa2\x28\x21\xf1\x3c\ -\xd0\x4d\x14\x45\x23\x4a\xa0\xb8\x9b\xa8\xb1\xb3\xbe\x0c\xbd\x06\ -\x6a\xb5\x48\xd0\x6a\x62\x11\x92\x8f\x43\xb4\x61\x87\x3f\xfa\x3f\ -\xff\x77\x1e\x98\x19\xc1\x04\x61\x12\xa2\xa4\x83\x01\x49\x22\x76\ -\xfd\xd7\x25\x04\xf2\xbb\x34\x91\xe4\x5d\x91\x51\xc2\x4f\xbe\xfe\ -\xe7\x9f\x91\x93\xf7\x2c\x92\x13\x48\x24\x41\x4c\x88\x1f\x87\x24\ -\x22\x4c\x17\xf5\x49\x4c\x22\x64\x86\x5e\xbc\x4f\xd2\x44\xbb\x99\ -\x90\xbc\x7a\x6b\x93\x4f\xff\xe1\x1f\xa3\x8c\x4d\xd1\x8c\x64\xcc\ -\x72\x9d\x76\xb3\x43\x22\x64\xf2\xd5\x11\x22\x29\x75\x93\x70\x7c\ -\x9f\x6e\xa3\x85\x54\x2e\x53\x2c\x96\x09\xc3\x98\xac\x91\xc1\xee\ -\x0f\x91\x24\x95\xa8\xd7\x27\x0e\x52\x3f\x2f\x0c\x03\x25\x5f\x20\ -\x4e\x40\x51\x0d\xe2\x4e\x97\x4a\xad\x46\xd8\xeb\xb3\x7a\xed\x2a\ -\x79\x11\xb3\xb7\x52\xe6\xbf\xf9\xe4\x27\x78\xfc\xbe\x31\xd6\x6f\ -\x2d\x73\x78\x66\x04\x4b\x40\x5e\x82\xcd\xab\x77\x10\x8e\xc7\x89\ -\x93\xc7\xd8\xbb\x6f\x2f\xfd\x7e\x9f\x7a\xb9\xcc\x89\xc9\xbd\x8c\ -\x1b\x19\x1e\xb9\xff\x3e\x96\x16\xaf\xf3\xe6\xc5\xd7\xf0\xc3\x21\ -\x95\x82\x41\xd6\xd0\xf8\x9f\x7e\xe7\x7f\xa4\xdb\x6c\xb3\xb8\xb4\ -\xc4\xf6\x9d\x65\x94\x6c\x9e\x5a\xb5\x4e\xad\x54\xa6\xd7\x68\xf2\ -\xe4\x43\x0f\x82\x63\xd3\xdf\x5e\x63\x6a\xa4\x86\xa6\x48\x4c\x4c\ -\x4f\x62\xbb\x3e\x9f\xff\xea\xd7\xb9\xdd\x1d\x72\x71\x79\x8d\x96\ -\xef\xd3\x09\x43\xe2\x8c\x85\x2f\x29\xc4\xa6\x89\xa6\x9b\x44\xb1\ -\x8c\x2c\x64\x86\x9d\x01\xf5\xfa\x38\x03\x27\x60\xe8\xc7\x2c\x6d\ -\xed\xe0\x49\x06\xaf\x5f\xbe\x41\xa0\x65\xb9\xb2\xb2\x4e\xa1\x3e\ -\x42\x65\x74\x82\x48\xa4\x44\x7c\x5d\x55\xd0\x75\x0d\xc7\x1e\x50\ -\x2c\x16\x98\x99\xd9\x43\xdf\xee\x13\x8b\x84\x90\x04\xdd\x34\xb0\ -\xac\x0c\x3b\x8d\x06\xb5\x5a\x8d\x4e\xbb\x43\xa9\x58\x62\x75\x79\ -\x15\x05\x19\x4b\x33\x58\xb8\x7e\x93\x47\x1f\x7c\x98\x0b\x6f\x5d\ -\xa0\x5c\x28\x72\xec\xc8\x71\x06\xbd\x3e\x19\x23\xcb\xc8\xd8\x28\ -\x8d\x41\x17\x37\xf1\x19\x99\x18\xe7\x0f\xfe\xf8\x8f\x30\x8c\x2c\ -\xc4\x0a\xb5\x42\x99\xf5\x3b\xab\x7c\xfc\x97\xce\xb2\x78\x63\x99\ -\xd5\xe5\x0d\xca\xf5\x11\xd0\x2c\x56\x5a\x5d\xb6\x1d\x0f\xd9\xcc\ -\x72\xf3\xda\x75\x96\x16\x16\xe9\x6d\x6f\x92\x2f\x57\xa8\x8d\x8c\ -\xe0\x27\x29\x79\xc4\xee\x76\xf0\xfa\x36\x5e\x18\x11\x44\x3e\x56\ -\xc6\x64\xe8\xba\xc8\xaa\x8c\x2a\x4b\x28\x86\x4e\x7f\x6b\x1b\x7f\ -\x37\x2b\x2f\xde\x95\x07\xfa\x8e\x4b\xb6\x58\x42\xcd\x66\x11\x66\ -\x6a\x46\xe1\x0c\x87\x84\x43\x1b\x2f\x4e\x50\x33\x59\xdc\xa1\x43\ -\xb5\x52\xc1\xf7\x7d\xb2\xe5\x12\xc3\x7e\x0f\xcf\x4f\xb7\x16\xb1\ -\xed\x90\x28\x1a\x56\x26\x87\xaa\x6a\x20\x2b\x08\x21\x13\xb6\xdb\ -\x48\xba\x4e\xb0\x0b\x88\x92\x84\xe8\x9a\x82\xd7\xe9\x22\xa9\x3a\ -\xa3\x53\x53\xec\xf4\x87\x18\xc5\x12\x37\x17\x97\x78\xfc\xf1\xd3\ -\xa8\x09\x9f\x56\xe2\xf8\x33\x7a\x12\xdd\x6b\xa6\xa5\x28\xb5\xb6\ -\x92\x25\x99\x28\x22\xcd\xc7\x4a\xa5\xcc\xdc\x55\x24\xbc\xf7\x95\ -\xff\x3f\xc2\x95\x78\xbf\x0a\x39\x06\x42\x08\x93\x90\x44\x44\xa4\ -\xda\x87\x98\x44\xa4\x27\x4f\x0a\x1e\x28\x08\x55\xb4\x37\x6c\x92\ -\x6f\xbd\x72\x89\xaf\xfc\xf0\x05\x1c\x23\x83\xab\x5b\x0c\x07\x2e\ -\x6a\xb1\x8c\x50\x75\x34\x2b\x8b\xa4\xa8\x0c\x6c\x07\xd7\xf7\xf1\ -\xfd\x00\x7c\x1f\xc5\xb2\xc8\x64\x32\xf7\xe6\x21\xd7\x76\x88\x7c\ -\x3f\x6d\xaf\x93\x18\xab\x58\x4a\x1f\xfa\x30\x26\x8a\x23\x74\x45\ -\x23\x6c\xb7\x70\x3c\x8f\x68\xd8\x67\x76\x7c\x8c\x93\xb3\xb3\x7c\ -\xe4\x03\x8f\xf2\xc4\xe9\x49\x9a\xeb\x36\xcd\x8d\x65\x26\x47\x6a\ -\x5c\xbc\xf0\x06\xb7\x2e\x5d\x65\x7e\xcf\x3e\xca\x85\x02\xd5\x31\ -\x83\x73\xaf\x5c\xe0\xe9\x27\x9f\xe4\xfc\x8f\x5f\xa2\x7d\x6b\x89\ -\xd9\x91\x51\xae\xbc\xf3\x26\x77\xee\x2c\x70\xfc\xd4\x31\x8e\x1f\ -\x9f\xe7\xc3\x1f\x7c\x82\x07\x8e\x9f\xe4\xb5\x57\xdf\xa4\x6f\x7b\ -\x44\x42\x90\xab\xd7\x51\x54\x03\xc7\x76\x68\x6f\x6d\x71\x78\xef\ -\x34\x4f\x3f\xfc\x20\xfb\x46\xab\x4c\x56\x2b\x48\xa1\xcf\xca\xca\ -\x32\x17\x2f\x5f\x21\x93\xcf\xf3\xf0\xd3\xbf\xc4\x9f\x7f\xf9\xeb\ -\x6c\x0c\x6c\xf2\x23\x75\x22\x4d\x63\xd0\xe9\xa1\x14\xf2\x64\x73\ -\x25\xec\x66\x1b\x59\x35\x90\x63\x09\xdf\xf1\x09\xa3\x18\x37\x0c\ -\x89\x25\x09\x5f\x08\x9a\x3b\x4d\xa6\xe7\x0f\x33\x77\xf4\x28\x9a\ -\x95\xe1\xf2\x95\xab\x4c\x8e\x4f\x30\x36\x52\x23\xf6\x7d\xa4\x24\ -\x15\x28\xc4\x61\xc0\xfe\xd9\x59\xae\x5c\xbd\x82\x61\x59\xd4\x47\ -\xc7\xc8\x17\x0a\xec\xb4\xda\x58\xb9\x2c\xb1\x00\x5d\xd3\x19\x9f\ -\x18\xa7\xdb\xe9\x61\xdb\x36\x53\x93\x93\xf4\xba\x5d\x74\x55\xe3\ -\xad\x37\xdf\x64\x6a\x62\x92\x03\xfb\x66\x59\x5c\x58\xe0\x23\x4f\ -\x3f\x86\xed\x84\x2c\x2c\xdd\x66\x6a\xff\x5e\x76\x5a\x2d\x9a\xed\ -\x36\xcb\xcb\xab\x54\x2a\x75\x1e\x3c\x75\x92\xbf\x79\xf6\x1b\xe4\ -\x33\x39\x62\x1f\xce\x9c\x3e\x88\x6c\x94\xd8\x6a\xb4\xb9\xbd\xb5\ -\x43\x6d\x6a\x1a\x57\x28\x14\xca\x65\x42\x37\xe5\x93\xcb\xba\x4e\ -\xbf\xd5\xa2\x77\xed\x1a\x53\xc7\x8e\xa5\x2d\xb3\xeb\x51\x19\x1d\ -\xc3\x0d\x03\xc2\x4e\x9b\xa1\xeb\x82\x3d\xc4\xc8\xe7\x31\x0d\x03\ -\x21\x49\xa8\xf9\x02\x91\x10\x04\xb6\x43\xe8\x38\xa9\x5a\x2a\x8e\ -\x30\xac\xb4\xab\x08\x93\x18\x55\xd7\xd0\x2c\x8b\x48\x4a\x57\x3f\ -\xe1\xd0\x26\xe9\x0f\x52\xee\xb6\x2c\x63\x65\x32\x29\xff\x50\x08\ -\x62\x3f\x00\xdb\x21\xd2\xf4\x14\x04\xf3\x03\x34\x2d\x9d\xb7\xbd\ -\x5d\xe5\x54\x1c\x86\x69\x3e\x76\x1c\xa2\xc5\x09\xf9\x5d\xa6\xd9\ -\x56\xab\x4d\x14\x46\x0c\xfd\x20\xed\x62\xdc\x90\x33\xc7\x0e\x90\ -\x95\xa4\xcf\x88\x28\x22\xb6\x07\x4f\xcb\xaa\xb6\x88\x90\xf1\x5d\ -\x2f\x2d\x54\x49\x4e\x89\x2e\xe2\x27\xb5\xfa\xc9\x4f\xe9\x0b\xc5\ -\xdf\x66\x1b\x2d\xde\x27\xd4\xfa\x2e\xda\x15\x91\x4a\xc1\x84\x24\ -\x10\xbb\x94\xf0\x08\x18\xfa\xf1\xa7\x7c\x45\x7d\xc0\x17\xfc\x93\ -\x8e\xe0\xc8\x67\xbf\xf0\x55\x96\xdb\x5d\x02\x55\x67\xf5\xd6\x02\ -\xfa\xc4\x14\x8a\x66\xe0\x79\xde\x3d\xf9\x59\xe8\x79\xbb\x3b\x45\ -\x95\x78\x97\x3f\x7b\x17\xd0\xb0\xfb\xfd\xf4\xf8\x95\x24\xcc\x6c\ -\x1e\x23\x9b\xc5\x30\x4c\x7c\xd7\xc3\x1f\xda\xe0\x07\x69\x4b\xef\ -\x38\x18\x9a\xc6\x78\xb9\xc8\x27\x3e\xfa\x77\xf8\xe5\x27\x4f\xb1\ -\x77\xaa\x88\xa1\xc2\xcd\x9b\xb7\xb9\x73\xe7\x26\xa5\x4a\x81\xf1\ -\xf1\x51\x1e\x3c\x71\x8c\x28\x48\x98\x18\xb1\xb8\x78\x7b\x9b\xe7\ -\x7f\xf0\x7d\xbe\xff\x83\xef\xd1\xde\xd8\xe4\xe3\x67\x9f\xe2\xb7\ -\x7e\xfd\x31\x9e\x78\xe4\x24\x67\x1e\x3a\xcb\xe4\xcc\x04\xba\x22\ -\x31\x5a\xaa\xe0\x7b\x21\xf7\x3f\x7c\x92\x9d\x5e\xc0\x4b\x6f\xbc\ -\x01\x8a\xc2\x9d\x95\x25\x86\xbd\x0e\xbf\xfb\xa9\xff\x96\xc7\x1f\ -\x38\x41\xd4\x6d\x31\x59\xce\x72\xe3\xed\x77\x68\x6c\x6d\xf1\xd0\ -\x99\x33\xf8\x7e\x84\x91\xc9\xb1\xda\xe8\x90\x58\x79\xb6\xba\x3d\ -\xb6\x9a\x0d\x42\x24\xf4\x7c\x91\x30\x01\xa7\xd7\x47\xb7\x72\x28\ -\x28\x68\x9a\x9a\x02\x36\x51\x84\xa6\x6b\x68\x86\x86\x6e\x99\xd8\ -\xce\x80\x6e\xab\x81\xaa\xc8\x64\x34\x85\xa9\x7a\x8d\xb3\x8f\x9c\ -\xa1\x64\x59\xa8\x71\x84\xd3\xed\x50\x2d\x96\xe9\x76\x5a\xcc\xcf\ -\xcf\xb3\xb5\xb3\x43\xa5\x56\x67\x6d\x6b\x1b\xc7\xf7\xa9\x8f\x8d\ -\x91\x08\x41\xa7\xd7\xc3\xf7\x43\x4a\x95\x32\x97\xaf\x5c\xe3\xa9\ -\xa7\x1e\xe7\xea\xd5\x1b\x8c\x8e\x8d\x71\xe7\xce\x1d\xf6\xee\xdb\ -\x87\xa6\x69\x98\xa6\xc9\xfc\xa1\x39\xbe\xf3\xbd\x1f\x92\xcd\x66\ -\x78\xe8\x81\xa3\x7c\xef\xdc\xcb\x4c\x4e\x4d\x61\x68\x06\x2f\xbc\ -\xf0\x23\xea\xf5\x11\x2c\x2b\x4b\xa9\x50\xe0\x89\x0f\x3c\x40\xa7\ -\x67\xf3\xdc\xf7\x5f\xe6\x07\x2f\xbe\x48\xcf\xb5\x59\xda\xd8\xc4\ -\x8e\x12\x96\xd7\xd6\x79\xe5\xa5\x97\x08\xfd\x80\x5e\xb3\x89\x95\ -\xcf\x52\xaa\x56\x31\xc7\x26\x58\xbb\xb5\xc0\x70\x6d\x9d\xa9\xc3\ -\xf3\x38\xae\x83\x20\x21\x96\xe5\xf4\x79\x88\xd2\x24\x88\x24\x8e\ -\x09\xc2\xf4\xc2\x50\x35\x0d\x43\x37\x40\x51\x10\x40\xd4\xef\x13\ -\x48\x12\x41\x14\x92\xcd\xe7\x08\xa3\x74\xc7\x2c\x80\x52\xa1\x80\ -\xaa\xa8\x78\xfd\x01\x7e\x10\xe0\x47\x11\xd2\x2e\xc2\xad\xeb\x3a\ -\x92\xa2\x10\x44\x51\xba\xa7\xdf\x45\xc5\xd5\x5d\x95\x95\x2c\xcb\ -\x84\xbe\x8f\xbc\x6b\x54\x20\xc9\xe9\x57\xa7\xb9\x83\x55\x2c\x12\ -\xc4\x09\xb1\xef\xa3\x2a\x1a\x96\xa6\xb0\xbc\x70\x83\xd9\xbd\xfb\ -\x19\xab\x97\x3e\xad\xc9\xca\x67\xc2\x28\x58\x54\x55\x05\x21\xa7\ -\x60\x9e\x10\x12\x42\x16\x29\xbb\x2b\x49\xd9\x90\xd2\x7b\xb8\xd8\ -\x3f\xeb\xeb\x3f\x41\x9a\xdf\x97\xd6\x5a\xbc\x47\x97\x25\xee\x1a\ -\xe9\xa5\x42\x8a\x44\x08\x62\x14\x50\xf5\x37\x1c\xc1\xeb\xb7\x7b\ -\xde\x91\x7f\xf6\xaf\xfe\x0d\xb6\xac\xb1\xd4\x68\xb2\xd6\xee\x60\ -\x8e\x4f\x50\xaa\x8e\xd2\x1f\x0e\x09\x3b\x1d\x92\x38\x46\x31\x0c\ -\x54\x5d\xbf\x87\x24\xa6\x69\x03\x11\xde\x60\x80\xac\x69\x84\x71\ -\x8c\xb1\xbb\xeb\x34\x0c\x03\x55\xd1\x18\xf6\x87\xb8\x83\x21\xc8\ -\x32\xb2\xa6\x11\x79\x2e\x92\x94\x30\x51\x2d\x23\x5c\x87\x33\x27\ -\x0e\x33\x5a\xc9\x72\xf5\x9d\xab\xec\x6c\xee\x30\x31\x5e\xa7\xdb\ -\x6d\x72\xf8\xf0\x3c\xb5\x52\x91\x76\x6f\x40\xa3\xd1\xe2\xfa\xe2\ -\x2a\x8b\xab\x2b\x0c\x9c\x21\x6b\xcb\xcb\x3c\x7c\xf2\x7e\x9e\x7c\ -\xe8\x61\x4c\xd9\x64\xd0\x87\x76\xaf\x4d\x48\x44\xb5\x5c\x21\xa7\ -\x5b\x4c\x4c\x56\x79\xf5\xd2\x1a\x5f\x7b\xfe\x79\x56\x6e\xde\xc0\ -\x93\x04\xc5\x7c\x8e\x7a\x21\xcf\xef\xfc\xe6\xd3\xb8\x2d\x1b\x33\ -\xf2\x59\xbf\xb5\xc0\x78\xb5\xcc\xe1\xb9\x79\x84\xa4\xb0\xb8\xb4\ -\x8c\x66\xe6\xb1\x13\xc1\xd1\x87\x4e\xf0\xed\x17\x5e\xa1\xdf\xe9\ -\x52\x1a\x1d\xa7\xdb\xed\x13\x3b\x1e\x6a\x26\x9f\x8e\x78\x9e\x47\ -\x1c\xc5\x58\x86\x85\xeb\xba\xc4\x24\xd8\x9e\x8b\x50\xe5\x14\xb5\ -\x16\x09\xba\x22\x61\xf7\x7a\x4c\x8d\xd4\xb9\x79\xf9\x22\xe7\x9e\ -\x7f\x8e\xd9\xc9\x71\x74\x49\xa2\x98\xcb\xe1\xda\x0e\x49\x02\x8d\ -\x66\x8b\x91\xc9\x29\x62\x49\xc2\x09\x23\x9c\x20\x40\x33\x32\x14\ -\x8a\x25\xac\x5c\x8e\x9b\xb7\x16\x39\xfb\xc1\x47\x79\xf1\xdc\x79\ -\x0c\xd3\x62\x79\x79\x89\xf9\x43\x87\x20\x49\x98\x9b\x9b\xa3\xdd\ -\x6e\xb3\xb6\xbe\xca\x53\x1f\x7c\x9c\x9d\x66\x9b\x17\x5f\x7a\x9d\ -\x5f\xfa\xc8\x53\xd8\x76\xc8\xe2\xe2\x12\xdf\xfa\xf6\xb7\xb9\xef\ -\xfe\xfb\xe9\x74\xbb\x58\x56\x86\x30\x12\xec\xdb\x3f\xc2\xf4\xcc\ -\x7e\x9c\xd0\xe7\x1b\xdf\x79\x8e\xad\x56\x1b\xd5\x30\x39\xf9\xc0\ -\x29\xce\x7e\xe0\x2c\xa6\x69\x70\xf3\xf2\x15\x8c\x4c\x86\xc3\x47\ -\x0e\xf3\xc8\x23\x8f\x92\xaf\x54\x38\xf2\xe0\x69\xde\xf8\xee\x73\ -\x78\x80\x24\xa7\x9e\xe3\x9a\xa6\xa5\xab\x1b\x04\x61\x14\x12\x45\ -\x31\xa1\xe3\x82\xa2\x62\x19\x29\xe9\x43\x12\x02\xdf\x1e\x22\x74\ -\x9d\x44\x12\xf8\x9d\x36\xb1\x9a\xaa\x9d\x48\x20\xf0\xfc\x54\xf2\ -\x1a\x27\xd4\x27\x26\x18\x76\xbb\x78\x51\x98\x72\x09\x84\xc0\x30\ -\x0c\x84\xa2\x10\xde\x93\x5b\xa6\xe4\x15\x6f\x38\xbc\x87\x94\x17\ -\x0a\x85\x5d\xdf\x36\x85\xa1\xdb\x07\x12\x1c\x3f\x24\x8e\x60\x62\ -\x7a\x06\x5d\x56\xe8\x77\x3b\xe4\x32\x16\x37\x6f\x5c\x43\xb7\x0c\ -\xa6\x26\xc7\x3f\xad\xab\xc6\x67\x82\x38\x44\x24\xa9\x5c\x53\x96\ -\xa5\x34\xcd\x51\xb0\x6b\xb9\xfb\x6e\x66\x99\xf8\xd9\xf5\xfa\x9f\ -\x67\x46\x4e\x80\x90\x68\x57\x91\x1c\x11\x45\x69\x2a\x5f\x12\x27\ -\x24\x42\x25\x92\x14\x7c\xf8\xbf\xde\x5e\xdb\x79\xec\x2b\xdf\xff\ -\x01\xe7\x2e\x5f\xe3\xc2\xb5\xeb\x50\x2c\x23\xac\x0c\xe5\x91\x71\ -\x86\xae\x87\xdd\xe9\x82\x10\x68\x85\x02\xf9\x42\x21\x5d\x33\xb8\ -\x2e\xfe\x60\x40\x94\xa4\x9e\x46\x92\xaa\x52\xae\x54\x90\x65\x39\ -\x8d\x4a\xb5\x6d\xbc\x20\xc0\xe9\x3b\x44\x8e\x07\xaa\x46\xa9\x58\ -\x24\x9b\x31\x09\x86\x7d\xb4\x24\x46\x8f\x23\x24\x7f\xc8\x78\x29\ -\x8f\x21\x12\xf6\x4f\x8d\x33\x35\x51\x67\xbc\x92\xe1\xf6\xd2\x22\ -\x7b\xf6\x4e\xb3\xbc\xb9\xc1\xd2\x9d\x65\xda\xcd\x16\x8a\xa6\x70\ -\xf0\xf0\x21\x0e\x1d\x3a\x44\xaf\xdd\xe2\xef\xff\xda\x33\x0c\xb7\ -\x1a\xe4\xf4\x2c\x9d\x7e\x07\x04\x8c\xef\xa9\xb3\xba\xbe\xc3\x0f\ -\x9e\xff\x21\x9b\x2d\x9b\x37\x6e\x2d\xb2\xb0\xb1\xc1\xf4\xdc\x41\ -\x3a\xad\x16\xa3\x95\x22\x0f\x1c\x39\x44\xd4\xf3\xa0\xdf\x61\x7e\ -\x62\x8c\x7a\x2e\xcb\xbe\x89\x11\xae\x5e\xb9\xce\xe2\xf2\x2a\xe5\ -\xda\x18\x5b\x9d\x1e\x7a\xb9\xca\xb3\x3f\x78\x8d\xe6\xd0\x23\x94\ -\x55\x6c\xd7\x43\x68\x06\xb1\xa4\x12\x3b\x2e\x8a\x61\xa1\x88\x34\ -\x87\x48\xd3\x35\x82\x30\x75\xda\x88\x5d\x9b\x20\x89\x21\x0a\xa8\ -\x94\x4b\x84\xee\x90\x61\xa7\x8d\xf0\x3d\x72\x8a\x42\x56\x91\x79\ -\xf4\xd4\x29\xd4\x38\x46\x15\x12\xb2\x48\x0d\xfd\x85\xa2\xb2\x67\ -\xdf\x2c\xcd\x6e\x9f\x5c\xa5\x86\x95\xcb\xb3\xb0\xb4\xc4\xd4\xde\ -\xbd\x9c\x7f\xfd\x0d\x2a\xb5\x1a\x17\xdf\xb9\x8a\xed\x3a\x28\xaa\ -\xc6\xbe\xfd\xfb\xb8\x79\xf3\x26\x53\x53\x53\xbc\xfc\xca\xcb\x1c\ -\x3e\x72\x84\xa9\xa9\x49\xce\x9d\x7b\x99\xb1\x91\x51\x0e\x1d\x3e\ -\xc2\x8f\x5e\x38\x47\x26\x9b\x65\x72\x6a\x9a\xd7\xdf\x78\x8b\x95\ -\x8d\x4d\x1e\xfb\xc0\xe3\x98\x19\x0b\x2f\x0a\xb8\x7e\x73\x11\x4d\ -\xd7\xb9\xff\xe4\x01\xe6\x8f\x9f\x22\x16\x12\x5f\xfd\xea\x5f\xf3\ -\xe3\x1f\xbd\xc8\xf2\xca\x0a\xae\xe7\x72\xe2\xc1\xd3\x4c\x8e\x4f\ -\x52\x2e\x97\xf9\xfc\x17\xbe\xc0\xe6\xd6\x16\x8e\xeb\xa2\x17\x8b\ -\x84\x51\x4c\x12\x47\x38\xb6\x93\x0a\x1d\x34\x15\xc3\x34\xd0\x0d\ -\x03\x45\x55\x40\x51\x09\xa3\x08\x67\x30\xc4\xb3\x53\x96\x56\x20\ -\x04\x85\x62\x11\x49\x55\x48\x74\x9d\xd8\x75\xf1\xdb\x6d\xa2\xa1\ -\x8d\x6a\x65\xb0\xf4\xb4\x03\x4c\x00\x2d\x9b\x49\xed\x6d\x83\x80\ -\xd0\x73\xf1\x77\x5d\x48\x12\x92\x74\x75\x29\x09\x64\x45\x21\x0a\ -\x83\x94\xb2\x19\xf8\x48\xba\x4e\x4c\x82\xac\x2b\x14\xaa\x05\x86\ -\x3b\xdb\x20\x6b\x94\xaa\x23\x34\xb7\x1b\x90\x80\xae\x6a\x74\xfb\ -\x5d\x96\x57\xef\xb0\xbe\xb9\x81\x91\x33\xd9\x33\x35\xf9\x69\x55\ -\x52\x3e\x13\x44\x01\x2a\x22\xb5\xd9\x25\xde\x5d\x29\x27\xf7\x12\ -\x1f\xc5\x6e\x43\x2d\xee\xf2\x31\xc4\xdf\x8e\x31\x8b\xf7\xcb\x7c\ -\x2f\x20\x5d\x3b\xc9\x22\xf5\xff\x55\x84\x84\x2c\xa7\xa7\x9a\x07\ -\xdc\x19\xf8\xcf\xbd\x76\xe3\x26\xdf\x7a\xe5\x35\xae\xac\xae\x33\ -\x73\xe2\x01\x76\xb6\x9b\xe4\xea\x13\x34\x1a\x4d\xa2\x24\xa5\xc3\ -\xe9\xc5\x22\x96\x65\xdd\x6b\xaf\x1d\xc7\x81\x30\x44\xb5\x2c\x4c\ -\xd3\xbc\xc7\xe4\x19\x0e\x87\x38\xc3\x61\x2a\x61\xd3\x0c\x12\x64\ -\x8c\x42\x81\x4c\x36\x0b\x49\x4c\xe8\xd9\xd8\xdd\x0e\x9a\x88\xf1\ -\xbb\x2d\xf6\x8e\xd5\xf8\xef\x7f\xeb\x13\xcc\x4d\x14\x18\xcd\xaa\ -\x78\x41\x48\x42\x48\xbb\xd9\x60\xe9\xce\x12\xba\x95\xe5\xe0\xdc\ -\x51\x6a\xd5\x1a\x5f\x7b\xf6\x59\xca\xd5\x1a\xab\xab\xcb\x94\x8b\ -\x45\x54\x04\x97\xdf\x7e\x9b\x5c\x3e\x47\x75\x64\x94\xda\x94\x45\ -\xb3\x0f\x2f\x9f\x7f\x83\xfe\xd0\x63\xbb\x37\xe4\xe2\xd2\x1d\x9a\ -\xbd\x2e\x9e\xeb\xe2\x36\xb6\x19\xb4\x5b\xfc\xca\x47\x9e\xe2\xd8\ -\xbe\x3d\x9c\x9e\x1f\x47\x09\x60\xd0\x6a\xf2\xfa\xf9\x37\xa9\x8f\ -\x8e\x31\x3a\x35\x43\x2f\x4a\x68\xba\x1e\x5b\x03\x87\xbf\x7c\xf6\ -\x9b\x6c\x6c\x6c\x93\xaf\x56\x31\xac\x2c\x83\x4e\x1f\x2d\x93\xc3\ -\xcc\x17\x70\xba\x3d\xb2\xc5\x02\x9e\xe3\x22\x64\x09\x59\x95\xd1\ -\x0c\x1d\xd5\x32\x77\x43\x0b\x05\xde\x70\xc0\x70\x7d\x85\x52\x21\ -\x4f\xc1\xd4\xf9\x8d\x4f\xfc\x17\x1c\x9f\x9b\x43\xf6\x03\x32\xba\ -\x41\x6b\xa7\x81\xa2\xc8\x14\x8b\x65\xbc\x30\x42\xcf\xe7\x79\xf5\ -\xcd\x37\xc9\x16\x4b\x44\x92\xcc\xfa\xe6\x16\x7f\xf9\xc5\x2f\x71\ -\xfe\xfc\x6b\x0c\x6c\x9b\x7c\xa9\xc4\x83\x0f\x3e\xc8\xc8\xc8\x28\ -\xfd\x5e\x9f\x93\x27\x8f\x72\xe9\xd2\x15\x1e\x7b\xf4\x11\x16\x16\ -\x16\xe8\x76\x3b\x4c\x4c\x4c\xb0\xbd\xbd\x4d\x36\x93\x65\xfe\xe0\ -\x01\x92\x44\x62\xf1\xf6\x32\xeb\x5b\x9b\x5c\x5b\x58\x40\x35\x4d\ -\xe6\x8f\x1e\xa6\x52\xab\xb0\x77\xdf\x04\x17\x2f\x5f\x65\x73\xab\ -\xc3\xbe\xd9\x49\x12\xa1\x21\x2b\x2a\x08\x19\xc7\xf5\x58\xb8\x79\ -\x83\xd1\xe9\x29\xee\xbf\xff\x14\x09\x09\x67\x3f\x78\x16\x7b\x38\ -\xe4\xea\x9b\x6f\x91\x2b\x97\x89\xc2\x30\xa5\x6d\x22\x88\x07\x03\ -\xe2\x5d\x63\x01\x45\x51\x50\x34\x23\xa5\x00\xcb\x32\xb2\x90\x52\ -\x3e\x75\x02\xf1\x70\x88\xd8\x75\xef\x88\x92\x18\x2d\x63\xa1\xe5\ -\x72\x84\x42\x10\xba\x1e\x5e\xb7\x07\x9e\x4f\xa1\x5a\x05\x29\x95\ -\x6f\x9a\x99\x0c\x61\x92\x10\x47\x51\xaa\x5d\x77\x5d\x24\x5d\x47\ -\x51\xd2\x6e\x40\x35\xd2\xf5\x54\x64\xdb\x04\x8e\x43\x18\xc7\x48\ -\x9a\x82\xed\xbb\x58\x23\x35\xfc\x81\x83\xdb\xee\xa3\xe9\x26\x8a\ -\x50\xe8\xb6\x9a\xa9\xe3\x49\xb9\xc0\xad\x5b\xd7\x69\x0f\xbb\xec\ -\x3d\xb8\x8f\xb1\x7c\xe1\xd3\x86\xac\x7e\x46\x8a\x63\xa4\x24\xdd\ -\xa5\xf3\x5e\x81\xa3\xe0\x6f\xc7\xad\xc5\xdf\xe6\xcc\xf9\x73\x16\ -\x72\xea\x84\x90\xc2\xd6\x0a\x12\x52\x22\x21\x24\x0d\x21\xc9\xb8\ -\x11\xb4\xbc\x24\x79\x6b\xe1\x36\xdf\x7c\xf9\x15\x5e\xbc\x78\x85\ -\xfa\x81\x83\xac\x36\xbb\xa0\x59\x14\x46\xc6\x19\x6e\x36\x50\x33\ -\x59\xa2\x28\xc2\xca\x66\x09\x82\x80\x41\xaf\x97\x72\x6d\xa3\x08\ -\x14\x85\x62\xb1\x88\x24\x49\x24\x49\x42\xbb\xdd\x4e\xc1\x11\xcf\ -\x43\xce\x66\x31\xb3\x59\xcc\x5c\x11\xcd\x30\x88\x45\xc2\x60\xd0\ -\xc3\xe9\xf7\xa0\xd3\xa4\x5e\x29\x52\xc9\xe8\xfc\xcf\xbf\xfd\xdf\ -\x51\x32\x54\xda\xdb\x6d\x24\x21\xd1\x6d\xed\xf0\xfa\xab\xaf\xe0\ -\x79\x0e\x87\x8f\x1e\x63\x7c\x6a\x86\xad\x46\x07\x3f\x08\xf9\xf0\ -\xd3\x4f\xe0\x06\xe9\xfb\x64\xad\x0c\x19\x2b\xcb\xc5\x8b\x97\x69\ -\xf5\x7b\xec\x99\x9f\xc3\x13\xb0\xda\x72\x50\xb2\x39\x46\xa6\xf7\ -\x71\x6b\x6d\x9d\xa6\x3d\x40\xd5\x34\x34\x01\x47\xe6\x0e\xb2\xb7\ -\x5e\xe6\xa3\x67\x1f\x67\x4f\xd9\xc4\x6f\xdb\xdc\x78\xfb\x1d\x54\ -\x49\x62\x72\x72\x9a\xd9\x03\x63\x5c\x5c\xde\xc6\x55\x54\x46\x67\ -\x27\xf9\xd3\x2f\x7c\x95\x8d\xbe\x8d\xd0\x2d\x06\x9e\xcf\xd0\xf1\ -\xc8\x57\xaa\x24\x42\x60\x37\x5b\x98\xa5\x0a\x8e\xe3\x91\xf8\x2e\ -\x51\x3a\x48\xe1\x07\x1e\xd9\x5c\x16\xdf\xf7\x10\x49\x48\x5e\x57\ -\xb1\x4c\x9d\x7d\x13\xe3\x1c\x98\x9e\x42\x0d\x42\xfa\x8d\x1d\x16\ -\xaf\x5d\xe3\xd8\xdc\x3c\xb7\xae\x5f\x27\x6b\x65\xf0\x93\x84\x1b\ -\xb7\x17\xb0\xfd\x90\x50\x96\x59\xde\xd8\xe2\xcb\xcf\x7e\x8d\xb7\ -\xde\x7e\x9b\xb5\x8d\x0d\x4e\x9f\x7a\x90\xfd\xb3\xfb\x39\x71\xe2\ -\x04\x17\x2f\x5d\xe2\xc0\xec\x0c\x9b\x1b\x9b\xb4\x5a\x6d\x66\xf7\ -\xed\x65\x65\x79\x99\xa3\x47\xe7\x68\xec\x34\xa8\x94\xcb\x94\x4b\ -\x05\xd6\xd6\xd6\xe8\xb6\x7a\x28\xaa\x8a\xe3\x07\x64\x0a\x79\xbc\ -\x24\x66\x65\x63\x9d\x47\x9f\x78\x8c\x85\xc5\x05\xec\xa1\xc7\x99\ -\x13\xf3\x08\x45\xe7\xf5\x37\xde\xa1\x5c\xaa\xf2\xf0\xc3\x67\x48\ -\x22\x89\x6b\xd7\x6f\xe0\x6b\x32\xab\x9b\x9b\x9c\xfb\xde\x0f\xe8\ -\x0c\x87\x5c\xba\x7c\x99\x5f\xfd\xe4\x33\xb8\x71\xc2\xf5\xab\xd7\ -\xf0\xc3\x08\x4d\x37\x30\x4c\x0b\x37\x08\x50\xcc\x0c\x91\xe7\xe3\ -\xc7\x09\x51\x94\xe0\x07\x01\xba\xae\x93\xcb\x64\x53\x6e\x75\x9c\ -\x10\x76\x3b\x84\x52\xea\x05\x97\xc9\xe7\x89\xe2\x28\xe5\x61\x27\ -\x09\xf9\x5c\x2a\x40\x09\x6c\x07\x3f\x4e\xdd\x5b\x13\x01\x99\x4c\ -\x66\xd7\xd4\x50\x26\x4c\x12\x18\x0e\x89\x15\x05\xb1\x3b\xde\x19\ -\x86\x91\xe2\x37\x90\xd2\x49\x15\x05\x64\x41\xe8\xdb\xf8\x7e\x80\ -\x90\x75\xf0\x23\x34\xa1\x43\x9c\x50\x28\x94\xb1\x3d\x87\xca\xd8\ -\x08\x5d\x7b\x48\xa3\xdd\x44\x53\x52\x67\xd4\xa2\xaa\x7e\x4e\x4d\ -\xe4\xb6\x72\xd7\x2b\x5b\xda\x95\x1e\x89\xf7\x48\xa1\x92\xf7\x94\ -\xec\xdd\x5c\x57\xf1\xb3\xa7\xdb\xf7\x81\xd9\x15\xdd\x2b\xe6\x24\ -\x08\x11\x11\x08\xa1\xa5\xf3\xd8\x20\x4c\x56\x3b\x03\xfe\xf0\x2f\ -\xfe\x92\xd7\x6f\xdd\x26\xca\xe6\xf1\x15\x03\x61\x58\x44\x5e\xc0\ -\xd0\xf6\xc9\x54\xeb\x44\x49\x44\xe4\xba\xa8\x86\x91\x02\x5a\xbe\ -\x9f\x06\x5c\xef\x0a\xc7\x75\xcb\xba\x97\x7f\x14\xf6\xfb\x48\xa6\ -\x49\x22\xcb\x29\x51\x22\x11\x24\x8a\x4e\x7f\x38\xc0\x73\x6d\x24\ -\x29\x41\x4e\x42\xe2\x7e\x9b\xd9\xbd\xd3\xcc\xcf\x4c\xf2\xf4\xa3\ -\xc7\x90\xfd\x04\x53\xc4\xbc\xf5\xda\x79\x0a\xd9\x2c\x87\xe6\x0f\ -\x62\x18\x26\x8d\x56\x97\xea\xd8\x28\xf9\xac\xc9\x9d\xb5\x16\x7f\ -\xf6\xef\xbf\x40\xb5\x56\x67\xff\xfe\x03\x8c\x4d\x4c\xe0\x7a\x3e\ -\x3f\x3c\xf7\x22\xdb\xfd\x3e\xd9\xea\x08\xff\xcf\x97\xbe\xc6\x85\ -\xeb\x37\x89\x35\x93\x0b\x37\x6e\x71\xfd\xf6\x1d\x5a\xed\x36\x81\ -\x63\x53\x30\x74\xa2\x5e\x97\xd3\x87\xe6\x38\xb1\x6f\x2f\xef\x9c\ -\x7b\x09\x35\x8e\xd8\x3f\x3d\x45\xb1\x54\x44\xd2\x0d\xbe\xf9\xe2\ -\xeb\x64\x46\x27\x18\xdd\x5b\xe2\x0f\xfe\xe2\xeb\x9c\xbb\xf0\x36\ -\xc5\x91\x09\x62\x39\xbd\xa1\xa2\x20\xc2\x8b\x62\xa2\x28\x81\x08\ -\x24\x4d\x25\x8c\x42\x54\xd3\x20\x97\xcb\x22\xa4\xd4\x44\xce\xca\ -\x9a\x78\xae\x83\x22\x20\x71\x86\xcc\x8c\x8d\x50\x2d\xe4\xf8\x9d\ -\x7f\xf0\x0c\x91\xed\x73\x62\x7e\x1e\xc9\xf3\xa9\x96\xf2\xb4\x9a\ -\x4d\x84\x22\x23\x29\x0a\x13\xd3\x7b\xe8\xfb\x1e\xb1\x24\x73\xee\ -\xfc\xab\xac\x6d\x6c\xa1\x69\x3a\x09\x82\x5f\xff\xf5\x5f\x43\xd7\ -\x74\x26\xa7\x26\x90\x25\x41\xaf\x33\xe0\x34\xe5\x4a\x4c\x00\x00\ -\x20\x00\x49\x44\x41\x54\xf0\xa1\xbd\x6c\xac\x6d\x33\x3e\x3e\xca\ -\xca\x9d\x65\x24\x49\x61\x6c\x74\x84\xa5\xa5\x25\xba\xdd\x0e\xfb\ -\xf7\xcf\x22\x23\xd3\xd8\x69\x92\x29\xe4\x98\xde\xbf\x8f\xf5\x9d\ -\x06\xb7\x57\x57\x98\x9a\x9e\x66\xfe\xd0\x3c\xad\x66\x83\xcd\xed\ -\x26\x93\x13\xe3\x14\x0a\x45\x4c\xd3\xe2\xf2\xa5\x1b\x98\x96\x45\ -\xb1\x36\xc2\xd1\x33\x0f\x52\xac\xd7\x19\x9b\x9a\xe6\xe2\x3b\x17\ -\xd1\x2d\x93\x6e\xb7\xc7\x87\x3f\xf2\x34\x8d\x76\x8f\x9d\xf5\x4d\ -\x02\x22\x7c\x37\x20\x71\x5d\xca\xa3\x63\x28\xba\x4e\x92\x08\x82\ -\xe1\x30\x0d\x2c\x88\x22\x42\x2f\x35\x20\x30\x74\x1d\x97\x04\xdd\ -\x34\x89\xa2\x10\xbf\xd7\x25\x4a\x12\x64\x4d\x43\x91\x15\x54\x59\ -\xc1\x77\x3d\x22\xdb\x41\xb3\x2c\x82\xc0\x27\xf2\x7d\xe2\x5d\xae\ -\xb6\xaa\xa6\xbb\x6b\x2f\x08\x50\x0c\x83\xd0\xf3\x52\x83\x7c\x59\ -\x26\x0c\x43\x32\xd9\x2c\x5e\x92\xa0\x19\x06\x51\x12\x91\xb8\x36\ -\x18\x26\x2a\x32\x71\x67\xc0\xd4\xd4\x0c\xad\x9d\x26\x6e\xe0\x83\ -\x2c\x63\x47\x3e\xc5\x6a\x85\x7e\xaf\x43\xb7\xdd\x66\xff\xc4\x04\ -\xb3\x63\x23\xbf\xab\x44\x7c\x46\x15\x12\x09\x51\xca\x35\xbf\x5b\ -\xa7\x42\xfa\xa9\x12\xfd\xe9\x60\xf5\x77\x55\xfe\xc9\x7b\x8c\x3c\ -\x7e\xee\xd6\x5a\xec\xc6\x59\x79\xb6\xb7\x4f\x11\x6a\x1b\x54\xdc\ -\x18\x44\x46\xfa\xdc\x8b\x6f\x2f\xfc\xee\xab\x37\x17\xd8\x1c\xfa\ -\x54\xf7\xec\xa7\x35\x74\x09\xb6\xdb\xa8\xf5\x71\x40\xc6\x30\x0c\ -\xec\x76\x0b\x34\x8d\x60\x30\x40\xe8\x1a\x8a\xa1\xa3\xe9\x3a\x41\ -\x18\xa0\x5a\x66\x9a\xf7\xe3\x79\x44\x24\x18\x85\x7c\x3a\x7b\x75\ -\xbb\x24\x9a\x8a\xac\x6a\x38\xae\x97\xae\xa1\xa2\x80\x7c\x31\x8b\ -\xa9\x42\x18\x7a\x78\xdd\x06\xff\xeb\x3f\xfe\x87\x14\x34\x58\xbe\ -\xb6\xc8\xd6\xea\x0a\x8f\x9e\x79\x98\x8c\x95\xa1\x54\xc8\xd2\x6e\ -\xf5\x09\x85\x4a\x3f\xb4\xb8\xb1\xde\x66\x61\x69\x99\x43\xc7\x8e\ -\x31\x3e\x31\x89\xe7\xfb\x69\x4e\x91\x95\x61\x71\x63\x83\xc5\xad\ -\x2d\x3c\xdd\xe0\xda\xea\x0a\xdb\x03\x9b\x0b\x37\x6e\xb1\xd9\xed\ -\xd3\x1b\xda\x28\x51\xc2\x13\xa7\x1f\xe0\xb7\x7f\xf3\x37\xf8\xf0\ -\x63\x0f\x31\x96\x35\x19\x6c\xae\xb1\x6f\x7c\x94\x7d\x93\x13\x18\ -\x86\xc1\xa5\x1b\xb7\xe8\xb8\x1e\xe3\xf3\x87\xe9\x4b\x0a\xff\xfc\ -\xcf\x3e\xcf\xb9\x4b\xef\x50\x9c\x98\x42\x35\xb2\xb4\xbb\xfd\x94\ -\xdb\x2d\x2b\x30\x74\x40\x55\xc9\x16\x4b\xe9\xf7\x31\x1c\x92\x29\ -\x15\xe8\xb5\x9a\xe8\xa6\x46\x18\x87\x38\xc3\x01\xa6\xa6\x93\x37\ -\x35\x70\x06\xfc\xf6\x3f\xf8\x2d\x0e\xed\xdb\x4b\x35\x97\x63\x7d\ -\x71\x89\x92\x65\x92\x35\x34\xea\x95\x0a\xa1\x1f\x50\x28\x15\x29\ -\x94\xca\x0c\x3d\x8f\xb1\xe9\x3d\x8c\x4e\x4e\x70\x67\x6d\x8d\x7c\ -\xa1\x88\xe3\x38\xa9\xcd\xed\xcb\x2f\x71\xe6\xc1\x07\x79\xfb\xc2\ -\x5b\x9c\x39\x7d\x82\x9d\xad\x26\x86\x6e\x50\xaf\xd6\xb8\x75\xf3\ -\x3a\x27\x8f\x1f\xe7\xce\x9d\x3b\x38\x8e\xcd\xdc\xdc\x1c\x96\x65\ -\x72\xf5\xf2\x55\x88\x62\xca\xd5\x0a\x77\xd6\xd6\x99\x9c\x99\xe4\ -\xd0\x89\x79\x36\xb6\x9b\x7c\xe3\x1b\xdf\xe0\xef\xfc\xf2\x87\x29\ -\xe6\x72\x28\xb2\xc4\x8d\x6b\x37\x18\x0e\x6c\xc6\xc6\x47\x98\xda\ -\x53\x63\x7d\xab\x4d\xb6\x52\x41\x64\xf3\x8c\x4c\x4d\x53\xae\x54\ -\xe8\xdb\x2e\xeb\xeb\x1b\x2c\xaf\x2c\x63\x3b\x01\x87\x8f\x1c\x65\ -\x73\x6b\x9b\x30\x89\x09\x83\x74\x53\xe1\x85\x11\x86\x61\x21\x24\ -\x19\x49\xd3\x50\x55\x05\xbf\xdb\x25\x8c\x93\xd4\xd2\x68\x30\x20\ -\x81\x74\x1c\xcb\xe7\x70\x01\xa1\x2a\xc4\x83\x01\x91\xeb\xa5\x84\ -\x8e\x5c\x1e\xbb\xdb\x25\x53\x28\x20\xa9\x0a\x91\x80\xc0\x75\x89\ -\xc2\x10\xd3\xb2\x48\x92\x94\x1e\xaa\xe8\x3a\xaa\xae\xa3\x6a\x1a\ -\x76\xbb\x8d\xb2\xdb\x5e\x07\xfd\x3e\xb2\xae\x93\xcd\xe5\x71\xa3\ -\xf4\xe7\x26\xdc\x08\x59\x52\x91\x82\x78\xf7\x92\x49\xf0\x42\x3f\ -\xcd\xae\xb2\x0c\x2c\xcb\xa4\xdb\x68\xd2\xdf\xde\xe1\xe4\x91\xe3\ -\xe4\x55\xfd\x88\x42\xf2\x25\x21\x47\x24\xc9\x6e\xb8\x5d\x02\x62\ -\xd7\x56\x37\x09\x42\x84\x2c\xbf\x5b\xc8\xe2\x27\x17\x51\xc9\x4f\ -\x45\x42\xfc\xdc\x5c\xeb\x30\xf2\x18\xf4\xfa\x2d\x5d\x33\x7e\x2f\ -\x4e\x14\x14\x43\xc1\x16\xf0\xd2\xc5\x95\xd6\xbf\xfe\xf3\xcf\x71\ -\x7d\x73\x1b\xa9\x50\xc2\x11\x12\xa1\xa4\x12\x69\x26\x56\x36\x47\ -\xa5\x50\xa6\xd5\x6c\x92\xf4\xba\x60\x9a\x48\xba\x9e\xaa\x9a\xee\ -\x79\x36\xa5\xae\x96\x44\x11\x99\xdd\xf9\xd9\x75\xdd\x34\xf0\x1a\ -\xd0\x0d\x03\xa7\xdb\x4d\x4f\x30\x43\xc7\xc8\x5b\xd8\xbd\x16\x89\ -\x6b\x53\xb1\x34\x2c\x62\x4e\x1f\x3d\xca\x5b\x3f\x7e\x85\x3d\xa3\ -\x23\xdc\x77\x6c\x1e\xcb\x10\xb8\xbe\xa0\x67\xfb\x4c\x4f\x54\xf9\ -\xb3\xbf\x7c\x96\xd1\xd9\x79\xb2\x95\x12\x1b\x3b\x1d\x9e\x7b\xfe\ -\xfb\x8c\x8d\x8d\x53\x2c\x55\xd9\x6e\xb4\x59\xde\xdc\xc4\x91\x04\ -\x17\x6f\x2f\x70\xfe\x9d\x4b\x14\xc7\x26\xf0\x13\x89\x9e\xe3\x11\ -\xeb\x1a\xe5\x62\x99\xb2\xa6\x72\xf6\xe4\x49\x72\x8a\xa0\xbf\xbd\ -\x41\x49\x95\x18\xb6\x76\x98\x19\x1b\xa5\x90\xcb\xf3\xda\x9b\x6f\ -\x33\x33\x37\x8f\x5a\xaa\x72\x7d\x63\x9b\x7f\xfa\x2f\xfe\x25\xd7\ -\xb7\x37\x29\xed\xd9\x83\x27\xc9\x6c\xad\x6e\x60\xe5\x4b\xc4\x89\ -\x20\x0e\x43\xb2\xd5\x3a\xaa\xa2\x32\x6c\x77\x48\xc2\x90\x4c\xb5\ -\x8a\x17\x78\xc4\xdb\x9b\x64\x6a\x55\x44\x14\xa0\x0a\x41\xa5\x90\ -\x67\x7b\x75\x85\xd1\x4c\x86\x8d\xc5\x05\xfe\xee\x47\x9e\xc4\xeb\ -\xd9\x8c\x57\x2a\x88\x28\x20\x76\x1d\x64\x01\xdd\x5e\x97\x4c\xc6\ -\x42\x31\x34\x34\xcb\x60\x7d\x63\x9b\x62\xa5\xc2\xfa\xe6\x26\x07\ -\xe7\x0f\x92\xc4\x11\x42\xc0\x43\xa7\x4e\x73\xf1\x9d\x0b\xd4\xca\ -\x15\xb2\x56\x8e\xb9\xd9\x31\x7e\xfc\xc3\x73\xcc\xcf\xed\xa3\xdb\ -\x6a\xb3\xbd\xb5\xc9\x83\xa7\x8f\x30\x1c\x7a\x74\x3a\x1d\x54\x55\ -\xa1\xd1\x6c\x12\x78\x5e\xea\x24\xb2\x7f\x96\x73\xaf\xbe\x86\x50\ -\x0d\x4e\x9c\x38\xc9\x8f\x7f\xf4\x23\xbe\xf0\xf9\xcf\xf3\xcb\x1f\ -\xfa\x10\xe3\xf5\x22\x95\x72\x0d\xdd\x30\xb9\xb9\xb0\xcc\x4e\xdb\ -\xe1\xd2\xd5\x6b\xfc\xe8\xb5\xd7\x78\xfe\x95\xf3\xbc\xf2\xd6\x05\ -\x2e\x5f\xbd\x4e\x18\xc5\x68\xa6\x85\x6e\x98\x34\x1a\x2d\x16\x6f\ -\xdf\x4e\xa9\xa3\x42\xc1\x1f\xda\x48\xba\x49\x82\x84\xdb\xef\x21\ -\xa9\x69\x96\xb2\x24\x4b\xa0\x28\x28\x42\xc2\xed\xf7\x49\x06\x03\ -\xa4\xdd\x30\xbb\x28\x89\x89\x49\xd2\xe2\x54\x14\xe2\x38\x49\x95\ -\x51\x9e\x4f\x32\xb4\xc9\x57\x2a\xa9\xeb\x88\xa6\xa2\xa8\x2a\x61\ -\x10\xa4\xaa\xa9\xc1\x00\x3c\x0f\xb3\x58\x24\x0c\x43\x4a\xa5\x52\ -\xda\x86\x0f\x06\x04\x8e\x03\x8a\x82\x61\x59\xf8\x41\x80\x91\xcd\ -\xa2\x08\x99\xd0\x76\x89\x3d\x1f\x55\x48\xe8\xba\x86\xa4\xc8\x08\ -\x4d\x25\xe8\x77\xd0\x8b\x79\x64\x59\x21\xf1\x7d\xda\x6b\x1b\x34\ -\xd7\xd6\xf9\xe8\xd9\x07\x3f\xae\xca\xa2\x8d\x90\x76\xb9\xdd\x72\ -\xea\xb6\x13\xa5\x04\x4e\x71\xcf\x0c\xfe\xa7\xd3\x2b\x7e\x76\x21\ -\x4b\xfc\x9c\xbf\x34\x59\xa7\x54\xac\x94\x0d\x33\x87\x64\xea\x38\ -\x02\x5a\x21\xc9\x0f\xde\xb8\x40\xc3\xf5\x08\x55\x03\xc9\xc8\x62\ -\xfb\x31\x9e\xe3\x03\x32\x51\x10\xe2\x79\x0e\x71\x14\x40\x92\xa0\ -\xe9\x3a\x96\x65\xdd\xf3\x5a\x8a\xee\x42\xff\x51\x44\x65\x64\x04\ -\xdf\xf7\xb1\x6d\x9b\x5c\x2e\x97\xca\xec\xda\x6d\x9c\x4e\x07\x91\ -\xcd\x40\xc6\x00\x09\xdc\x76\x9b\x72\x21\xcf\xcc\xd4\x38\xbd\x56\ -\x83\xd9\xe9\x29\x0a\x19\x8b\x5f\xfd\xd8\x93\xec\xdf\x3f\x49\xa7\ -\xe7\xb1\xd1\xf0\xe9\xbb\x11\x37\x56\xb6\xf9\xab\xe7\xdf\x60\xf2\ -\xc0\x11\x42\xa1\xf3\xc7\x7f\xfa\x97\x7c\xee\xcb\x5f\x65\xb5\xd5\ -\xe1\xda\xd2\x2a\xed\xbe\x83\x62\x58\x94\x47\xc7\xd8\x19\x0c\xd9\ -\xb1\x1d\x8a\xe3\xa3\x2c\x5d\xbb\xca\xce\xc6\x06\x53\x93\x93\xec\ -\xdd\xbb\x97\x24\xf4\xa8\x19\x26\x2b\xd7\xae\x50\x90\x05\x8f\x9d\ -\x98\x65\xef\xd8\x18\x7f\xf7\x83\x8f\xf0\xd6\x5b\x6f\xf1\x9d\xef\ -\x7d\x9f\xfa\xc4\x14\x2d\x27\x40\x2f\x0a\xbe\xfe\xc2\x8b\x0c\x24\ -\x99\x99\xa3\x27\xd8\x6c\x36\x69\x0f\x87\x90\xcf\x23\x1b\x1a\x92\ -\xaa\xa4\x71\xaf\x51\x9a\x3a\x88\xbb\x9b\xc9\x4c\x4c\xd0\xed\x90\ -\xdd\xb7\x07\xcf\xb1\x09\x03\x9f\x62\x36\xc3\xea\x9d\x45\x66\x46\ -\x47\x79\xe0\xe8\x51\x2c\x59\x26\x67\xc0\xd5\x8b\xef\x60\x99\x3a\ -\xed\xe6\x0e\x56\xd6\x42\x33\x54\x2c\xcb\x40\xd1\x64\x64\x59\x62\ -\x7c\xb4\x42\xbb\xd9\xa0\x98\x85\xc9\x7a\x9d\xd3\x27\x8e\x52\xcc\ -\x64\xe8\xec\xec\xf0\xc1\xc7\xcf\x50\x2d\x16\x39\x7d\xff\xfd\x5c\ -\xbf\x7c\x09\x53\x81\xb3\x4f\x7c\x80\x4b\xef\x5c\x66\x7a\x7a\x9a\ -\x5c\x2e\xc7\xca\x6a\x0b\xdb\x71\xd8\xda\xde\xe6\xca\xd5\xeb\x9c\ -\x3a\x75\x8a\xb9\xb9\x39\x86\x76\x1f\x45\x81\x53\xf7\x9f\xc4\x77\ -\x5c\xfa\xed\x36\xbf\xff\xff\xb1\xf6\xe6\x41\x96\x9d\xe7\x79\xdf\ -\xef\xec\xdb\xdd\xfb\xf6\x3e\x4b\xf7\xec\x98\x19\x0c\x96\xc1\x60\ -\x21\x09\x90\x82\x44\x91\x22\x45\x8a\xa4\x40\x51\xb2\x44\x6b\x8d\ -\x1c\x2b\xa5\x8a\x5d\x51\x4a\x52\xca\x49\x59\x55\x91\x22\x97\x2b\ -\xa6\x1d\xcb\x16\x4d\xd9\xa4\x24\x8a\xb4\x45\x8a\xe2\x02\x11\x24\ -\x08\x81\xd8\x07\xc0\x00\x98\xc1\xac\x98\x7d\xeb\xbd\x6f\xf7\x5d\ -\xcf\x3d\xfb\x92\x3f\xbe\xd3\x17\x10\xa5\x44\x49\x9c\xa9\x9a\x1a\ -\xd4\x4c\xf7\x45\x77\xdf\xf3\x7d\xef\xfb\x3e\xef\xb3\xfc\xe6\x6f\ -\x33\x3b\x3e\xc9\xbf\xfc\xdf\x7e\x9f\xcf\xfc\xef\xff\x9e\x33\x6f\ -\x9e\x65\x7c\xbc\xcc\x99\x0b\xe7\xf9\xc3\xff\xf8\x39\x9e\x7d\xe5\ -\x25\x22\x44\x18\x9f\xa2\x3b\x0c\x3c\x9f\xae\x3b\xc4\xf5\x7c\xc6\ -\xc6\x27\xc8\x91\x68\x2f\x2c\x12\x86\x31\xee\xfa\x3a\x76\xb5\x8a\ -\x69\x9a\x18\x86\x81\x51\xa9\x10\xb4\x5a\x84\xb1\x68\xa7\xd3\x34\ -\xc5\x34\x4d\x1a\x93\x93\x50\x2a\x91\xb5\xdb\xb4\xd6\xd6\x46\xcf\ -\xd2\xd6\x8e\x58\xb7\x2c\xd0\x34\xd2\x58\x3c\x77\x51\x61\xa9\x2b\ -\x29\x32\x5a\xd1\x0d\x22\x0b\xfe\x3e\x69\x42\x9c\x26\xd8\x25\x87\ -\x4e\xaf\x4b\x14\x06\x94\x9a\x63\x58\x8d\x3a\xb8\x03\x86\x1b\x2d\ -\x34\x55\x15\xd4\x7f\x49\xc6\xd4\x75\x24\x29\xc7\xf3\x07\x0c\xbd\ -\x3e\xb9\x9c\xa3\x19\x1a\x28\x1a\xc3\x20\xa6\x37\xf0\xb1\x4a\x0d\ -\x86\xa9\xcc\x73\xaf\x9f\xe5\xf5\xab\x9b\xd7\x5c\xf8\xd5\x18\xb9\ -\xf0\xf5\x92\x40\x56\x85\x3d\xae\xac\x80\xac\xfe\x5f\x1c\xcf\xec\ -\x07\x7e\xff\xff\x74\x90\xfd\xbe\x0b\xb9\x82\x17\xa5\x0c\x52\x7e\ -\xb5\x03\xf9\xb3\xa7\x2e\xf1\xc4\xcb\x2f\xd3\xce\x72\x4a\xd3\x33\ -\xf4\xc3\x18\x45\xd5\x21\xce\x21\x49\x49\xa3\x98\xcd\x85\x9b\xe8\ -\xa6\x06\x85\x57\x54\x9e\x8b\xfc\xdb\x60\x38\x1c\xe9\x4a\x51\xd5\ -\x91\x8e\x54\xd3\x34\xba\x9d\x0e\xdd\x6e\x17\x4c\x13\xa3\x52\x41\ -\x2e\x2c\x53\x1c\xcb\xa2\x5a\xab\x32\x6c\x77\xb8\xf8\xc2\x0b\xcc\ -\xcd\xce\xa0\xcb\x12\xb3\xe3\x36\xab\xed\x80\x20\x02\xa7\x62\xd0\ -\xea\xba\x9c\xb9\x72\x93\xc4\x70\x88\xec\x2a\x9e\x6a\xf1\x5b\xbf\ -\xf3\xbb\xf4\xa3\x18\xbd\x52\x63\xbd\xef\xf2\xc2\xf1\x57\x99\x9c\ -\x2e\x53\x2a\x97\x79\xf1\xf8\x09\x1e\xff\xee\x93\xcc\xef\xd9\x4b\ -\xaf\xd7\xa3\x3c\x35\xc1\x9e\x5d\xf3\x3c\x72\xff\x7d\x38\x52\x4e\ -\xd4\xdd\x64\xf5\xc6\x15\x7e\xfc\x7d\xef\x63\x7e\xb2\x81\xd7\x0b\ -\xa8\x57\x34\x5e\x3e\x75\x81\x52\xb9\x8a\x51\xaa\xb0\x7d\xbe\x49\ -\xa4\xea\x3c\x77\x72\x09\xac\x12\x47\x1f\x7e\x2f\xbd\x20\x06\xc3\ -\x06\x45\xa3\x31\x31\x4e\x6f\xd0\x07\x49\xa2\x5e\xaf\x33\xf4\x5c\ -\xf2\xa1\x87\x54\x2e\x83\xa6\x30\xbc\x7e\x15\xb2\x04\x5d\x57\xf1\ -\xda\x2d\x1c\xcb\x40\x55\x24\xb2\x7e\x9f\xfb\x8e\x1c\x61\xcf\xec\ -\x36\xfe\x87\x5f\xfb\x6f\xd1\x32\x18\xab\xd5\x18\xab\xab\x84\xa1\ -\x4f\xa9\xe2\xb0\xd9\xdd\x44\x33\x55\x3a\xfd\x0e\xbd\x7e\x07\x24\ -\x88\xc2\x21\x72\x06\x86\x2c\x13\x0f\x43\x66\xc6\xc7\x99\x6e\x36\ -\x90\x73\x98\x1e\x6f\xb2\x7b\xd2\xe4\xc8\xc1\x3b\x38\x77\xf6\x16\ -\x64\x09\x13\xcd\x31\x5a\x6b\x6b\xcc\xcf\xef\xe0\x6b\x5f\xfb\x1a\ -\xb2\x2c\x33\x39\x39\x89\x2c\xcb\x9c\xbf\x70\x01\xcd\xd4\xa8\xd5\ -\x2a\x9c\x7a\xf3\x14\x59\x1a\xf3\xe0\xfe\x59\x06\x9b\x1d\xba\xeb\ -\x1b\xdc\x7b\xe8\x4e\x4c\x49\xc7\x90\x14\xa2\x30\xc4\xf3\xe0\xae\ -\xa3\xf7\xf0\x8b\xff\xf8\x57\xf9\xf4\xaf\xfe\x32\xf3\x07\xf6\x63\ -\x94\xaa\x54\x1a\xe3\x54\x1a\x93\x44\x71\x46\xd8\x73\xe9\xf4\x87\ -\x94\x2a\x55\x9a\x73\xbb\xf0\xfb\x7d\xd4\x4a\x0d\xaf\xdd\x45\xb7\ -\x4c\xaa\xd5\xaa\x78\x26\xa6\xa7\xc8\x7c\x9f\x60\x7d\x9d\x52\xa9\ -\x84\xe3\x38\xe2\xd9\x88\x63\xec\x99\x19\xec\x52\x89\xc1\xe2\x22\ -\x59\x14\xe1\xba\xee\x88\x87\x5d\xab\xd7\xb1\x1c\x07\x0c\x03\xd7\ -\x75\x09\x82\x00\xcf\xf3\x46\xda\xe5\x46\xa3\x81\x51\xaf\x83\xa2\ -\x10\x7a\x1e\xdd\xf5\xf5\x91\x2e\x19\x8a\x94\x8f\x66\x13\x54\x15\ -\xb7\xd5\xc2\xeb\xb9\x64\x71\x46\xa9\x64\x63\x95\x2c\xe2\x2c\xa0\ -\xef\xf7\xf0\xe2\x21\x51\x1a\x41\xb9\x44\x12\xc6\x24\x41\x4c\xae\ -\x9a\x18\xe5\x31\x94\x4a\x83\x3f\xf9\xc6\xe3\x2c\x0e\xf2\xff\x10\ -\xc1\xae\x28\x83\x20\xcf\xc9\x51\x91\x54\x7d\x14\x62\xc8\xff\x0b\ -\x1d\xc4\x7f\x25\x45\x53\x42\xd3\x0c\x40\x26\x40\x66\xa8\xf2\xfa\ -\xed\x01\x7c\xe9\x3b\xdf\xe3\x52\x6b\x13\xdf\x30\x09\x64\x1d\x3f\ -\xcd\x91\x55\x93\x44\x02\xdd\x30\x50\x34\x99\x24\x0e\x51\x0d\x9d\ -\x54\x62\x14\x16\x1e\xc7\x22\x13\x48\xd1\xf5\x91\x63\x45\x9a\xa6\ -\x23\x47\xc4\x2c\x8a\xc4\xdc\x90\xa6\xd8\x95\x0a\xb2\xa2\x90\x45\ -\x29\x61\xbb\x8d\x92\x86\x10\x7a\xdc\x7b\xf7\x21\x6e\x5c\x38\xc7\ -\xbb\xef\xbe\x8b\x3d\x73\x7b\xa9\x3a\x2a\x9d\xb6\xcb\x1b\x67\x2e\ -\xe1\x26\x30\xb5\x67\x37\xff\xe6\x8f\xff\x33\x2f\x9e\x3a\xc7\xf1\ -\x37\xcf\xa2\xdb\x36\xd7\xaf\x5c\xa4\x37\xe8\xf3\xe0\xc3\x0f\x33\ -\x51\x1b\x63\xfb\xcc\x1e\xdc\x81\xcb\xb7\x9e\xf8\x2b\x24\xdb\x60\ -\x61\x75\x89\xb2\xed\x50\xd1\x0d\xfe\xfb\x5f\xfa\x65\xca\x8a\xca\ -\x9f\x7f\xfe\x3f\x72\xe7\xde\xdd\xdc\xb5\x63\x1b\x3f\xfd\xa1\xfb\ -\x30\x34\x90\x93\x8c\x67\x9f\xfe\x3e\x73\xf3\x3b\x39\x78\xe4\x00\ -\xf5\xa9\x19\x3e\xf3\x47\x5f\xe1\xf4\x95\x1b\xac\xba\x21\xdb\xf6\ -\x1f\xe4\x85\xd7\x4f\xb1\x76\xfb\x36\x94\xcb\xd4\x1a\xe3\x74\xd6\ -\x36\x20\x0c\xc5\x7e\xd3\x34\x49\xe3\x14\xb9\xd8\x95\xc6\x71\x04\ -\xaa\xc2\xf8\xdc\x76\x36\x6f\xdf\x80\x2c\xa3\x5a\x29\xb1\x7a\xfb\ -\x26\x15\xc7\xc1\xcc\x72\x92\x6e\x87\x47\x1f\xba\x93\xd3\x6f\xbc\ -\x45\xad\x52\x42\x93\x75\x16\x6e\xdd\xe0\xf0\xa1\xfd\x2c\x2e\xde\ -\x66\x72\x7a\x92\xa1\xe7\x62\xdb\x36\x8d\x7a\x8d\xf6\x66\x97\xd9\ -\x99\x69\x42\x3f\x16\x1e\x5c\x73\xdb\xd1\x24\x89\x6d\xd3\x33\xa8\ -\xc0\xfa\x7a\x9f\xf1\x46\x9d\x4b\x17\x2e\x70\x60\xef\x3c\xd5\x4a\ -\x89\xa7\x9f\x7a\x9a\xc5\x85\x25\x7e\xfa\x53\x9f\xe4\xf8\xcb\xc7\ -\xb9\xe7\x9e\x7b\x30\x1d\x9b\xf5\xb5\x15\xf6\xec\x99\x23\x23\x67\ -\x76\xc7\x0e\x4e\x9d\x7a\x93\x4c\xb1\xb9\xef\xc0\x36\x6e\xdd\x5c\ -\x67\xff\xee\xdd\x3c\xfa\xf0\x7b\x79\xe0\xd8\x7d\x94\xec\x32\xd7\ -\x16\x84\xb5\xf0\xfc\x81\x6d\xac\x0c\x42\xbe\xf4\x8d\xc7\x19\x24\ -\x32\xfd\x81\x87\x62\x58\x98\x4e\x09\xc3\xa9\xd0\x5b\x5d\xc1\x0d\ -\x23\x74\xc3\x24\xce\x21\x0d\x43\xaa\x13\x93\xf4\xda\x6d\x86\x43\ -\x8f\x7a\xa3\xc9\xd0\x0b\xa8\xd4\x6b\xd8\xb5\x1a\xbd\x76\x1b\x77\ -\x71\x89\x5c\x92\xb0\xab\x35\xe4\xc2\x5a\x57\xab\x56\x04\x4b\x2b\ -\x4d\xc8\xe3\x98\x0c\x09\x4d\x51\x88\x83\x10\x55\xd3\x8a\x80\xbb\ -\x98\x3c\xcf\x04\x5f\x21\x17\x29\x9c\x79\x9e\x13\x07\x81\x00\x56\ -\x93\xa4\xa0\x39\x89\x20\xf6\x2d\x33\xc0\x38\x49\x40\x52\xc8\x25\ -\x05\x09\xa1\xb5\xcf\x49\x08\x93\x08\xc5\x50\x50\x2d\x9d\x20\x8d\ -\x46\xa6\x05\x76\xb5\x4a\x1c\x04\x0c\x07\x03\x54\x45\x66\xbd\xdd\ -\x61\xc7\xf6\x19\xf6\x6f\x6b\xbe\x47\x95\x94\xcf\x05\x51\xf2\x15\ -\x5d\x55\xbf\x2a\x01\x51\x92\xa2\x2a\x22\x3c\x41\x96\x8b\x39\x79\ -\xb4\xa6\xca\xde\x61\x79\x29\x21\xff\x1d\xc9\xe2\xff\x1f\x0f\xb3\ -\x4c\x14\xa5\x74\xbd\x30\x8f\x81\x7f\xf7\xa5\x2f\x72\xfc\xe2\x79\ -\x3a\x64\xf8\x9a\x8e\x07\xd4\x26\xa7\x09\x5c\x0f\xf2\x9c\x2c\x4b\ -\x48\xe3\x88\x99\xb9\x1d\x84\xb1\xf0\x14\x0e\xc3\x90\x34\x12\x66\ -\xdf\x52\xc1\xea\x7a\xa7\xac\x2b\xe8\xf5\x88\x83\x80\x52\xad\x26\ -\x42\xbb\xe3\x98\xe1\x70\x88\xae\x6a\x18\x39\xd4\x9c\x32\x61\xbb\ -\x4b\x55\xd3\x49\x87\x3e\x7f\xfc\x87\xff\x9a\x99\x89\x49\x2c\x1d\ -\xfe\xed\xbf\xfd\x23\x1e\xff\xce\x77\xd9\x77\xf8\x4e\xee\x3b\x36\ -\xc7\x77\x8f\xbf\xce\xad\x76\x0f\x7d\x6a\x16\x4f\xb7\x58\xdf\xd8\ -\xe0\xf0\x43\x0f\x50\xdb\x3e\xcb\xf5\xa5\x05\x3e\xf8\xe1\x0f\x31\ -\xb7\x53\xa6\xb5\xd6\x62\xf1\xd6\x22\x9f\xfe\xb9\x9f\xa3\x59\x6f\ -\x30\x5e\x2d\x13\x75\x3b\x74\x6f\xdc\xe0\x4f\x3e\xf3\x19\xf6\x4d\ -\x4d\x12\xae\x2e\xb3\x6b\x6a\x8a\xdb\xb7\x7a\x9c\x3d\xf5\x16\x67\ -\x4e\xbf\xc9\xa3\x8f\xbe\x0f\xd5\xd0\x59\xdd\x1c\x70\x6d\x61\x95\ -\x37\xdf\xba\xc8\x95\x85\x65\x7a\x7e\xcc\x33\x2f\xbd\xca\xea\x46\ -\x17\xbd\x39\x05\xa9\x8c\xeb\xba\xd0\xed\xe0\x4c\x4d\xa2\x68\x2a\ -\xeb\x6b\x6b\xa8\xaa\x08\x39\x8f\xfc\x40\x80\x78\xba\x4a\xeb\xd6\ -\x2d\x48\x33\x14\xcb\xa0\xdb\xde\xc0\xd2\x54\x0e\xee\xdb\x47\x1e\ -\xc7\x1c\xbb\xeb\x2e\xf2\x00\xc6\x2a\x35\xee\x3e\xb4\x9d\x2c\x11\ -\x3b\x56\x49\x01\x2f\xf0\xc8\xc8\x04\x75\x56\xca\xf1\x86\x1e\xa6\ -\xaa\xd2\x5e\xdd\xa0\x66\x59\xc4\xde\x90\x89\x9a\x81\xae\x40\xd0\ -\xef\xb3\x6f\xd7\x2c\x49\xe0\x53\xb1\x0d\x0c\x45\xe6\xbb\x4f\x3c\ -\xc9\xb3\xdf\x7f\x8e\x8f\x7f\xfc\xe3\x94\xcb\x65\x5a\xad\x4d\x0e\ -\x1f\x3e\xcc\xc5\x2b\x97\x99\x9d\x6e\x70\xf7\xbd\xf7\xf2\xc5\x2f\ -\x7d\x89\x66\xad\x4c\xb7\xd7\x66\x7e\x97\x60\x35\xdd\x5e\x72\xb9\ -\xfb\xe0\x7e\x9a\xe5\x06\x04\x31\x5e\xa7\x8f\x9c\x8b\x15\xcf\x30\ -\x0c\xb8\x74\x6b\x83\x33\x57\x2e\x52\xdf\x36\x83\x51\xa9\x80\xac\ -\x89\x84\x8f\x14\xac\x4a\x05\xec\x12\xe4\x12\xdd\x56\x8b\xb4\xd7\ -\xa3\x31\x35\x49\x92\x24\x98\xa5\x12\x20\xd1\x5e\x59\xa1\x52\x11\ -\xa9\x91\xfd\xde\x80\xe6\xe4\x24\xce\xcc\x0c\x78\x9e\x00\xa5\x54\ -\x75\xc4\x49\x30\x0b\xb7\x4d\x64\x99\x34\x08\xe8\x77\xbb\x44\x85\ -\xd7\x77\xad\x56\x43\x35\x0c\x14\x5d\x1f\x99\x10\x74\xda\x6d\x86\ -\x7d\xd1\x21\x55\xab\x55\xea\x93\x93\x10\x45\x24\x83\x81\x58\x3f\ -\x25\x09\x5e\x61\xad\x3b\x3e\x3d\x8d\x65\xd8\x84\x7e\x48\xa7\xdb\ -\x65\xe0\x7b\xa0\xa4\x18\x15\x03\xcd\xd6\xc8\xf2\x98\x3c\x8d\x20\ -\x0c\x31\x0d\x9b\x38\x97\xc9\x0d\x8b\x76\x9c\x10\xd9\x36\x5f\xf8\ -\xda\xd7\x59\xec\xf9\x47\x01\x74\xc3\xf8\xa9\x2d\xfd\x51\x5a\x04\ -\x36\xca\xaa\xfa\xf7\x82\xcd\x5b\xed\xf5\x7f\xbd\xd5\x4f\x94\xa0\ -\x5b\x2a\x15\x53\x91\x5e\x6b\x0d\xf2\x33\xd7\x6f\x10\x39\x36\x61\ -\x90\x82\x6d\x51\x2a\x37\xc8\x65\x15\xb2\x04\x24\xe1\xa1\x94\x4b\ -\x12\xb2\xae\x80\x37\x04\xab\x22\x98\x61\x8a\x8c\x61\x99\x23\xa7\ -\x4d\x92\x98\x24\xd3\xc8\xc2\x10\x7b\xac\x81\xa6\x69\xb8\xae\x4b\ -\x9c\x26\x50\x29\x63\x58\x26\xdd\xf5\x35\x18\x46\xc8\xa6\xc5\xfc\ -\xcc\x2c\x8f\x7d\xe4\x03\xdc\x7b\x60\x82\x31\x03\xda\xeb\x6b\x5c\ -\xbf\x7a\x9b\x5f\xfc\xe5\x5f\xc2\x29\x2b\x74\x43\x78\xea\xe4\x32\ -\xdf\x7b\xe9\x65\x22\xdb\xe1\xd2\xa5\x6b\x38\x33\x33\x18\xa6\xca\ -\x95\x1b\xd7\x99\x99\xdb\xc1\xfb\xdf\xfb\x3e\xf6\x6d\x97\x39\xfe\ -\xf2\x22\xaf\xbf\x7a\x82\xfd\xbb\xf6\xa0\xe6\x12\x4a\x92\xd0\xb4\ -\x1d\x3e\xf0\xc1\xa3\xf4\x16\x17\xf9\xc7\x9f\xfa\x24\x77\x3f\x70\ -\x84\x1c\xf0\xdb\x3d\x16\x6e\xdf\xe4\x8e\xfd\xf3\xd4\x6b\x65\xe2\ -\xd8\xa7\x36\xd6\xe0\xf4\xf9\x4b\x34\x66\x76\xf1\xb3\xbf\xf4\x2b\ -\xdc\xde\x18\xf0\xcd\x67\x5e\xe4\xc6\xa5\xab\x34\xef\x3c\xc2\x30\ -\x0e\x99\x1c\x6b\xb0\xb6\x70\x0b\x9a\x0d\x34\x43\xc5\xf7\x87\x10\ -\xc7\x24\x51\x4c\x96\xa4\xa4\x59\x82\xa6\x69\x4c\x6d\x9f\x66\xe1\ -\xd6\x55\xf6\x1c\xda\x47\x67\x6d\x85\xcd\xab\x57\xd1\x6d\x87\xc0\ -\x1d\x20\xbb\x43\xc2\xc1\x90\x93\xaf\x9d\x26\xcb\x12\xf6\xed\x99\ -\x26\xf0\x5c\xaa\xb5\x32\x7d\xd7\x2d\x92\x0e\x32\x9c\xb2\x08\xa1\ -\xcb\xb2\x84\x92\x23\x56\x57\xe3\xf5\x09\xba\x9b\x1b\x6c\xae\xf5\ -\xd8\x39\x3b\x4b\x38\x74\xb9\xb4\xb6\xc2\x73\x4f\x7f\x9f\xd6\xca\ -\x12\x87\x0e\x1e\xe4\xec\xd9\xb3\x3c\xfa\x43\xef\x65\x30\x10\x7a\ -\xdf\xa9\xa9\x31\xc2\xb8\xc1\x93\x7f\xfd\x14\xd5\x6a\x9d\xf9\xb9\ -\x49\x3e\xf6\x93\x1f\xe3\xc9\x67\x9f\xe1\xce\x7b\x8e\x52\xad\x35\ -\x38\xf9\xc6\x59\xf6\xec\xda\x8f\x21\x41\xb3\xec\xb0\xea\xba\x0c\ -\x86\x2e\x5a\xb5\xc2\x58\x73\x9c\xb3\xa7\x4f\x91\x84\x01\xaf\x9c\ -\x3c\xc9\x8a\x1b\x91\x69\x93\x60\x3a\x44\x5e\x04\x81\x08\xc1\xab\ -\x35\xc7\xc9\xd3\x84\x5e\xbb\x03\xb9\x44\xa7\xdd\x63\x72\x72\x12\ -\xd7\xf7\x50\x0d\x50\x1d\x87\x4e\xab\x85\xa4\x29\x48\x39\xf8\xbe\ -\x8f\x2c\xcb\x38\xb3\xb3\xe4\x69\x46\xb7\xd5\x82\x3c\xc7\x99\x68\ -\x22\xa9\x2a\x69\x9e\x91\x4a\x12\x59\x92\x0a\x8f\xf3\x20\x10\xe4\ -\x8e\x82\x47\x2d\x29\xa2\x9e\x79\x85\xf1\x00\xc9\x96\xaf\x39\x04\ -\x41\x40\x79\x6c\x4c\xe8\x99\xd7\xd6\xf0\x87\x43\xf4\x6a\x95\x58\ -\x51\x44\x31\xd1\x4d\x7c\x4f\x21\x23\x11\xea\xa1\x2c\x22\x96\x12\ -\x34\x43\x9c\x2e\x59\xd1\xc9\xbc\x80\x76\xa7\x8b\xa9\xea\x34\x66\ -\xb7\xd1\x6b\xad\xd2\x49\x63\x3a\xb7\x17\xf9\xc6\xb7\xbf\xc3\xaf\ -\x3c\xf6\xd1\xbc\xa6\xab\x6f\xe3\xd2\xaa\x30\xb5\x57\xa4\x1f\x34\ -\xea\xf8\xdb\xde\x3c\xef\x68\xad\xff\x97\xd1\x5f\xe6\xff\x77\x92\ -\x29\x29\xfb\xdb\x5a\x0c\x09\x50\x64\x7c\x19\x36\x20\xff\x85\xdf\ -\xf8\x2d\xda\x92\xcc\xea\xd0\x47\x76\xaa\xc8\x86\x89\x63\x97\xe9\ -\xdc\xbe\x0d\x9a\x8a\x5d\xab\xa1\x5b\x3a\xb6\x69\xd2\xd9\x6c\x93\ -\x6e\x76\x31\x9a\x4d\x14\x55\x24\xed\xd9\xb6\x2d\x4c\xd4\xa2\x10\ -\x7c\x9f\xdc\x34\xa8\x35\x1a\x24\x49\x44\x9a\x66\x18\x86\x86\xa6\ -\x68\x84\xad\x35\x92\x3c\x43\x57\x54\x26\xea\x75\x1c\x43\xe3\x53\ -\x8f\x7d\x9c\xd0\xeb\xa3\x69\x16\xdf\xfe\xde\xb3\xbc\xfa\xfa\x09\ -\x8e\xbd\xeb\x61\xf4\x8a\x8d\x97\xc3\x7f\xfa\x2f\xdf\xe5\x9b\xdf\ -\x7f\x8e\xd8\x70\x68\x0d\x3c\xa8\xd6\x31\x1d\x0b\x29\x1e\xa2\x49\ -\x29\x91\xef\xd2\x59\x5c\xc2\x96\x6b\x1c\x9c\xdb\x49\xe8\xf6\xf1\ -\xfd\x01\x83\xa0\x4f\x6f\xb3\x45\x7f\x75\x85\x5f\xff\x87\x3f\xcf\ -\xbd\xbb\xf6\x90\x0e\xfa\xd4\xac\x12\x6a\x9e\xd3\x5d\x5d\xe7\xc1\ -\x63\x07\x70\xdd\x10\xc5\x34\x09\x91\xf8\xab\x67\x9e\x67\xc7\xc1\ -\xbb\xb8\xd9\xea\x31\x40\xe3\xcf\xbe\xfe\x2d\x56\xba\x03\xb4\xb1\ -\x26\x7d\xb7\x4f\x73\x6a\x8c\xb5\x9b\xd7\x50\xaa\x0e\x8d\x7a\x8d\ -\xce\xd2\x0a\x59\x2e\xd1\x6c\x4e\x10\x87\x31\x61\x18\x61\x5b\x36\ -\xb2\xaa\xb0\x79\xfb\x16\x48\x39\x71\xe0\xa1\xa5\x31\xcd\x4a\x99\ -\x99\x5a\x89\x87\xee\xbe\x93\xc9\x8a\xc3\x8f\xbe\xe7\x5d\x4c\x8d\ -\xd5\x39\x77\xf6\x34\xbe\x17\x70\xf1\xe2\x05\xfa\xfd\x2e\x9d\x4e\ -\x87\x76\xbb\x4d\xb7\xd3\x65\xbd\xb5\xc1\xcd\x1b\x37\xf1\xbd\x80\ -\xc5\x85\x45\xd6\xd7\x5b\x78\xae\xcb\x6b\xaf\xbf\x86\x61\x18\xb4\ -\xd6\xd6\x39\xf9\xc6\x1b\x1c\x39\x72\x98\x7d\xfb\x76\x31\x70\x7b\ -\x1c\x3e\x74\x07\xaa\x2a\xd3\xda\xdc\x64\xac\xd9\x60\xd7\xfc\x1c\ -\x8f\x3f\xfe\x1d\x0e\x1d\xde\xcb\xce\x1d\xf3\x5c\xb9\x74\x85\x46\ -\x7d\x8c\x28\x89\x08\xc3\x00\xcb\xb4\x91\xf2\x9c\xf1\xc6\x18\x52\ -\x12\xb3\xbc\xb8\x8c\xae\xaa\x74\xba\x9b\x9c\x3a\x7b\x86\x41\x14\ -\x31\xbb\x77\x8e\xef\x1d\x7f\x85\x4d\x3f\xe4\xc4\x6b\x6f\x50\x9f\ -\xdd\x49\x92\xeb\xc8\x9a\x45\x46\x8a\x5d\xaf\x93\x14\xc4\x8d\xe1\ -\x60\x80\xa4\xc8\x18\xa5\x32\xc8\xd0\x77\x87\xc8\xaa\x5a\x78\x64\ -\x67\xe2\x80\xc6\xd1\xc8\x22\xce\x1f\x0c\x88\x3d\x1f\xb3\xe4\x60\ -\x97\x4a\x04\x59\x4a\xec\x0d\x51\x75\x83\x24\x49\xd0\x0a\x86\x96\ -\x69\x98\x82\x37\x6d\x98\xf4\x07\x03\x14\x5d\x13\x56\xba\x9a\x86\ -\xa2\xaa\xc2\x2e\x18\xc8\x3d\x8f\x44\x51\x30\x0c\x31\xf6\x99\xa6\ -\x89\x5a\x80\x65\x91\xeb\x42\xb7\x8b\x52\x2a\xa3\xe9\x06\xc8\x39\ -\x76\xc9\x02\x0d\x52\xdf\x23\x53\x55\x2c\xcb\x21\xcb\x65\xaa\xa5\ -\x2a\x7e\x9c\xc1\x66\x07\xa5\xec\x50\xa9\x54\x48\xc8\x70\xaf\x5f\ -\x67\xdf\xdd\x47\x38\xf1\xe2\xf3\x3c\xf4\xc0\x03\x4c\xd6\xca\x56\ -\x0e\xd7\x75\xe8\xc8\x19\xa8\x32\x24\x69\x22\x52\x1e\xa5\x77\xda\ -\xda\xbf\xed\x8e\x2d\xbd\xc3\xee\x5e\xf9\xe7\xff\xfc\x7f\xde\x4a\ -\x6f\x2d\x7e\x17\x05\xbb\x38\xb7\x72\x9e\x13\x87\x3e\x8a\x2a\x43\ -\x9e\x11\xc7\x91\x98\x21\xd2\x94\x28\x93\xf0\x64\x89\x81\x44\xfe\ -\x9d\x53\x6f\xf1\xad\xe7\x8f\x13\x1a\x0e\xb9\x6a\xa2\xa9\x36\x59\ -\x94\xe2\xbb\x1e\x79\x14\x21\xd7\x2a\xa8\x85\x9f\x52\x18\xc6\x44\ -\xdd\x00\x24\x1d\xbb\x52\x21\xcb\x32\x1a\x63\x63\xf4\xfb\x7d\x92\ -\x2c\x26\xef\xb6\xc1\xb6\x68\xce\x4e\x23\x49\xd0\xef\x75\x84\x2f\ -\x93\xae\xd2\xdb\xd8\x00\xdf\x43\xb1\x6c\xc6\x1b\x35\x5a\xeb\xab\ -\x7c\xe2\x13\x1f\x65\xfb\xdc\x04\x73\xfb\x6b\x1c\x7f\xe3\x2c\x17\ -\x6f\xdf\x64\xb1\xe7\xf2\xe5\x6f\x7d\x9b\xd7\xae\x2e\xf2\xc4\xf1\ -\xb3\xdc\x6a\x0f\x59\x6c\x0f\x88\x15\x93\xfa\xe4\x34\x7e\x14\xa0\ -\xca\x19\x15\x03\xac\x3c\x64\x7f\xa3\xc9\x6f\xfc\xfc\x2f\x70\xdf\ -\xce\x26\x35\x4d\xa2\xdb\xde\xe0\xfe\x63\x47\x58\x59\xbe\xc1\x43\ -\xf7\x1c\xe6\xd7\x7f\xe1\x17\x98\xb2\x55\x6a\x1a\x94\x54\x93\xf3\ -\x6f\x9e\xc2\x44\x61\xd7\xd4\xac\xd0\xc6\x1a\x06\x6d\x1f\x9e\x3a\ -\x71\x86\x6f\xbe\x78\x82\xa8\x34\xc6\x73\xe7\x2f\xf3\x85\xaf\x3f\ -\xce\x50\x91\xa8\x4c\x8c\x93\x69\x90\xa9\x19\x83\x95\x05\xa4\x9a\ -\x43\xa5\x64\x61\x4a\x1a\xee\xca\x2a\x95\x72\x9d\x2c\xcc\x09\x83\ -\x88\x34\xc9\x28\x95\x2a\x28\x8a\x4c\x30\x70\x69\x8c\x35\xf8\xc9\ -\x1f\xff\x00\xa7\x8f\x3f\xcf\xcf\x7c\xf8\x03\x34\x0d\x89\xac\xbf\ -\xc1\xcf\x7e\xec\x23\xd4\x4c\x8d\x37\x4f\xbe\xc6\x07\x3e\xf0\xc3\ -\xcc\xce\x4e\x33\x1c\x0e\xb8\xff\xd8\xfd\x6c\x9b\xdd\xc6\xc2\xed\ -\x45\x8e\xde\x7b\x8c\x6a\xa5\xce\x58\x73\x82\x5d\xf3\xbb\x49\xb2\ -\x9c\xbd\xfb\xf6\xb1\x7d\x7e\x27\x49\x92\xf0\xee\x87\x8e\xd1\x1c\ -\x9b\xa1\x54\xb6\xa9\x54\x1d\xca\x35\x8b\xe5\xd5\xdb\x94\xea\x16\ -\x13\x33\xe3\xbc\x79\xe6\x34\xdb\xe7\xb6\x23\x4b\x2a\x59\x9a\x33\ -\xe8\x0e\x69\x36\x6a\x1c\xd9\x33\xcd\x97\xfe\xf3\x37\x38\x7a\xf4\ -\x1e\x4c\xab\xc4\xf2\xc2\x12\x55\xc7\x46\xca\x62\x1a\x15\x87\xb7\ -\x2e\x9c\xa1\xe7\xb6\x19\x9f\x99\xa2\x3c\x39\xc6\x13\xcf\x3d\x47\ -\x66\x97\x78\xeb\xf6\x12\x6f\x5e\xbe\x8e\x51\x1f\xa7\xef\x25\xc4\ -\x91\x60\xf1\x59\x96\x89\xae\x2a\xc4\x71\x48\xdc\xed\x82\x24\x61\ -\x95\xcb\x58\x96\x43\x92\xa6\xa4\x71\x2a\xfe\xcc\x73\x14\x55\x41\ -\x55\x15\xb1\x56\xca\x72\xa2\x20\x14\x55\x54\xd3\x51\x8a\x03\xa9\ -\xa8\x2a\x99\x24\x13\xb9\x43\xf2\xc2\x39\x34\x89\x13\xbc\x6e\x0f\ -\xa9\x54\x12\xeb\xa6\x30\x24\xf1\x03\x2c\xa7\x44\xe8\x87\x68\x8a\ -\x06\x19\x58\xa6\x45\xe0\x7a\x64\x5e\x40\x94\x89\x95\x90\x6d\xd9\ -\x48\xb9\xd0\x10\x23\x2b\xa4\x61\x44\xae\x0b\xad\xb7\x6e\x19\x84\ -\x51\x24\xcc\x26\xd3\x0c\xbc\x98\x30\x91\x50\x25\x95\x3c\x05\xad\ -\x90\xdf\x2a\x8a\xcc\xd0\x75\x85\x11\xa5\xa6\xe1\xfa\x21\x89\xac\ -\xb0\xb8\xba\xce\x23\xef\x3a\xfa\x9e\xaa\xc4\x3f\x31\x12\xd0\x15\ -\x48\x33\x9f\x5c\x49\x19\x26\x21\x89\x54\x18\xde\x67\x12\x79\x94\ -\x09\xd6\xa3\x04\xb2\xac\x10\xc7\x29\x79\x9e\xff\xcd\x19\x39\xff\ -\x81\x6c\x88\xad\x40\x63\x45\x91\x20\x49\xc8\x93\xf8\xed\xc0\x29\ -\x59\x45\xd6\x64\x22\x99\xaf\xac\x84\xf0\xe5\x6f\x3e\xce\x50\x82\ -\xda\xf8\x34\xe1\x30\x80\x14\x4c\xd5\xc4\x54\x35\x50\x54\xa1\x44\ -\xc9\x63\x82\x28\x24\x49\x84\x9b\x20\xaa\x8e\x22\xa9\x24\x59\x4a\ -\xaf\xd7\x23\x4e\x62\xd1\x66\x3b\x0e\xa8\x42\x69\xb2\xb9\xb1\x86\ -\x55\x29\x63\xd9\x06\xbd\x76\x1b\xd2\x98\xd2\xcc\x2c\xd5\xb2\xc3\ -\xea\xea\x2a\x07\xee\xd8\x4f\x2e\xc1\x7a\xbb\xc7\x9f\x7d\xe5\x69\ -\xfe\xf2\x3b\xdf\xa1\x1d\x85\x78\xaa\x86\x31\x3d\x4b\x0f\x8d\x6b\ -\xb7\x97\x58\xdc\xec\xd1\xd8\x31\x8f\x5a\x2a\x33\xf4\x3d\x6a\xb5\ -\x1a\x71\xe0\xa3\x19\x32\x77\x1e\xbc\x83\xf7\xbf\xfb\x3d\xd8\x71\ -\x8a\x16\x41\x45\x83\x6b\x17\xcf\xe1\x76\xd6\xb9\x73\xdf\x2e\x1e\ -\x3e\x7a\x2f\x15\x4d\x46\x4d\x21\x70\x43\x16\x6f\x5d\xe7\xf0\x81\ -\xfd\x74\x5a\xab\x54\x2a\x2a\x03\x1f\x56\xdb\x31\xa7\xaf\xdc\xe4\ -\xc6\x66\x97\x40\x2f\xf3\xc2\xb9\x2b\x9c\xb8\x74\x1d\x6d\xac\x89\ -\x35\x36\x41\xdb\x75\x91\x34\x9d\xb4\xdf\x47\xa9\xd7\xc9\xfb\x2e\ -\xdd\xcd\x2e\x2b\xb7\x17\x50\x2b\x35\x0c\xc3\x10\xfa\xd9\x34\xa7\ -\x39\x39\x81\xa4\xc8\x04\x41\x00\xb2\x84\x63\xe8\x5c\x3e\x73\x0e\ -\x23\xcf\x20\xf0\xf9\xf4\x27\x7f\x82\xbb\xf7\xed\x66\xb2\x6a\x10\ -\x05\x43\x9a\xe3\x75\x14\x55\x26\x8c\x82\xa2\xdd\x13\xc8\x67\xbd\ -\x3e\x86\x65\x39\x22\x06\x05\x19\xd5\x30\xb1\xcb\x25\x06\xde\x90\ -\x38\x4b\xa9\xd6\x6b\x2c\x2e\x74\x46\x1c\x76\xcd\x50\x41\x81\xb1\ -\xa9\x31\x14\x4d\xc1\x4f\x02\x0e\xde\x75\x88\xb7\xae\x5c\x45\xd2\ -\x60\xf7\x1d\xfb\x58\x6a\x6d\xe2\x85\x39\x17\x6f\xf5\x79\xef\xa3\ -\xef\xe7\xc4\x9b\x6f\x31\x51\x2f\xb1\x73\xd7\x3e\x5e\x7b\xe3\x24\ -\x61\x14\xf1\xf4\xb3\xcf\x30\xbf\x67\x17\x56\xc9\xa1\x31\x35\x81\ -\x6c\x9a\xfc\xd3\xdf\xfe\x75\xee\x3c\x76\x88\x67\x9e\xf8\x1e\x8a\ -\xee\xa0\x99\x55\xe2\x81\x2f\x7c\xb5\xf2\x14\x7f\x38\xc0\x75\xfb\ -\x62\xac\xd2\x75\x81\x1a\x47\x31\x71\x9a\x20\xc9\x0a\x8a\xa1\x23\ -\xab\xea\x28\x33\x79\x14\x25\x13\x04\x62\x55\x59\x24\x3c\x44\x49\ -\x4c\x54\x3c\xa7\xa6\x69\xa2\x98\x26\xb2\xa2\x12\xfa\x81\x90\xb9\ -\x2a\x82\x88\x64\x58\x26\x46\xa5\x0c\xaa\xfa\xf6\xec\x5b\xa0\xd7\ -\x41\x10\x80\x61\xa0\x54\x2a\x82\xf6\x19\x86\xb4\xdb\x6d\x06\x83\ -\x01\x79\x91\xfa\x88\x24\x91\xfa\x3e\x64\x49\x01\x98\xe5\xc8\x92\ -\x8a\xac\x3b\xa0\x98\x90\x2a\x84\x5e\x42\x16\x27\xa4\x71\x02\x12\ -\xa2\xea\x2b\x8a\x60\xee\x21\x23\xe9\x36\x03\x59\xe7\xf4\xcd\x25\ -\xbe\xfc\xf5\xe7\xe9\x86\xe4\xb9\x0c\x24\x31\xaa\x22\x1c\x42\x25\ -\x45\x2a\x4c\x69\x45\x18\x9c\x24\x29\xc8\x45\x0c\xc4\x0f\xb8\xe3\ -\xfd\x7d\x60\x56\x8e\x5c\xc8\xba\xb2\x1c\x14\x55\x27\x97\x64\xb2\ -\x5c\xe8\x8d\xfb\x19\x9f\x7c\xf2\x99\xe3\xbc\xf8\xfa\x49\x9c\xda\ -\x18\x31\x8a\x88\x52\x44\x41\x55\x45\xd6\xb1\xb8\x4d\x72\xd2\x28\ -\x26\x8f\x8a\x6f\x5a\x11\x02\x80\x24\x13\x22\x89\x60\x38\x44\x92\ -\x65\x14\x45\x47\x2b\xd7\xa0\x58\x47\x95\x6a\x0d\xfc\x95\x35\x06\ -\x8b\x8b\x34\x27\x27\xd9\xb9\x77\x2f\x6e\xbf\x4f\x7b\x61\x89\x6a\ -\xb5\x4e\x9a\xe5\xdc\x5c\x58\x24\x88\x12\xce\x9e\xbf\x40\xad\x3e\ -\x46\xa7\x37\xa4\x5c\xaa\x12\x0e\x3c\xd6\xaf\x5e\xa5\x3e\xbb\x1d\ -\xdd\x71\x70\x5d\x17\x49\xca\x85\x6f\x71\x96\x11\xf5\xba\x38\x95\ -\x32\xbf\xf8\x73\x1f\x65\xc7\xdc\x4e\x36\x3b\x6d\x4c\x13\x36\x37\ -\x3d\xf6\xee\x9e\xe7\x8e\x3b\xee\xe0\xd0\xbe\x03\x8c\x95\x6d\xe4\ -\x1c\x82\x20\xe4\xf8\xf1\x97\xd8\x77\x70\x3f\x66\xd9\x62\xd7\xa1\ -\x03\x9c\xbe\xb9\xc4\xb9\xa5\x1b\x5c\x5a\xbf\xcd\xf7\xdf\x38\xce\ -\xf1\x33\x27\x59\xee\x6d\x72\xee\xdc\x19\xfc\x24\xa1\x5c\xae\x12\ -\xfa\x11\xb6\x51\xc1\x5d\x6d\x33\x36\xb5\x1b\x3d\x35\xa9\x37\xb6\ -\x41\x24\x81\x6e\x61\x36\xea\x74\xa3\x10\x37\x0e\xc8\x35\xd0\x6c\ -\x9d\xcd\xee\x26\xbe\xe7\xf2\xd3\x3f\xfb\x33\x94\x4c\x93\x53\xaf\ -\x9d\xe0\xfd\xef\x7b\x94\xc3\x77\x1c\x24\x09\x32\x0c\xd5\x22\x0c\ -\x72\x7a\xbd\x1e\x8e\xe3\x8c\x7c\x9d\xb7\x02\xb7\x07\x83\x01\xf5\ -\x7a\x1d\xcb\x2a\xbc\xad\x24\x09\x4d\x53\xa8\x56\xab\xf4\x7a\x3d\ -\xf2\x3c\x67\x62\x62\x82\x30\x16\x24\x9b\x7b\xef\xbd\x97\x6b\xd7\ -\x6e\x10\xf8\x11\x3b\x77\xec\xe2\xd5\x37\x4e\x61\x99\x55\x90\x0d\ -\xda\x03\x8f\xc5\x8d\x21\x99\x01\xb9\xe9\x70\xfe\xd6\x02\x95\x6d\ -\x15\xa4\x6a\x85\x5e\x02\x6f\x2e\x0d\xf0\x64\x9d\xa1\xac\x73\xe9\ -\xf6\x0a\xf7\x3d\xfc\x28\x4a\xa9\xca\xde\xbb\xee\xe2\x4f\xfe\xfc\ -\x2f\x38\xf5\xd6\x15\xae\xdc\xec\xb2\xb2\x91\x30\x7d\xe7\xbd\xf4\ -\xbd\x10\x77\x18\x30\xbd\x6b\x9f\xd0\x00\xcb\xb2\x88\x39\xf5\x04\ -\x20\xaa\x5a\x16\x6a\xb1\x92\xdc\xf2\xed\x52\x55\x15\xa3\x00\x42\ -\xf3\x34\x25\x8e\x22\xc2\x30\x14\x33\xad\xaa\x8a\x2c\xa9\x82\x87\ -\xb0\x75\xc8\x81\x91\x8e\x5a\xe0\x39\xc2\x46\x68\x4b\x98\x63\x9a\ -\x26\xba\x65\x91\x24\x89\x20\x1a\xf9\x3e\x51\x14\xe1\xf7\xfb\xc2\ -\xfd\xd3\x34\xc5\xe7\xea\x3a\x79\x1c\x93\x46\xd1\xe8\x63\x31\x4d\ -\x14\xcb\x12\x07\xba\xd8\x65\x27\x49\xd1\x0a\x2b\x8a\x00\x1c\x25\ -\x91\x5d\x95\x64\x29\x28\xc2\x14\x52\x92\x0b\x71\x87\x24\x00\xdd\ -\x52\xa9\xc2\xea\xc6\x06\x5f\xfe\xfa\x5f\x72\x65\x71\x83\x44\x86\ -\x30\x13\x47\x53\x46\x42\x95\x84\xbf\x97\x22\x70\x65\x72\x39\xa7\ -\x90\x4d\xfd\x0d\x40\x58\xfe\xbb\x66\xe2\x77\xfe\x65\x14\x45\x20\ -\x09\xe1\xb5\xa4\x2a\x20\x29\x24\x48\xa4\xb2\x84\x07\x5f\x79\xeb\ -\xfa\x2a\x7f\xf2\x97\x5f\xa3\x3a\x31\x4d\x75\x7c\x9a\xc5\xd5\x75\ -\x94\x5a\x03\x59\x35\x21\x57\xc9\x13\x59\xb8\xf6\xa7\x8c\xd2\xe4\ -\x55\x55\x1e\x69\x31\x83\xc0\x2b\x1c\xb6\x05\x7f\x7a\x8b\xeb\x4a\ -\x14\xe1\x7b\x1e\xee\xc2\x02\xd5\x6d\xdb\x29\x6f\xdb\xc6\xc6\xfa\ -\x1a\xeb\x9b\x1b\x4c\xcc\x4c\xa3\x35\x1a\x74\x17\x17\x58\x5e\xdd\ -\xa0\xb5\xd1\xe1\xdb\x4f\x7c\x0f\xc3\x2a\xd1\x77\x7d\xdc\xa1\x70\ -\x18\xc1\x30\xc5\x9b\x20\x81\xa2\x6b\xe8\xa6\x81\xa2\xa9\x0c\x5b\ -\xeb\xf4\x56\x96\x71\x26\xc7\x79\xf0\xa1\x77\xd3\x4d\x60\xc7\xac\ -\xc9\xda\x46\x8b\x24\x85\xb3\x67\xcf\xf2\xe0\x83\x0f\xa2\xab\x0a\ -\xb6\x69\xb0\xb1\xd1\xc5\x1f\xb8\x9c\x7d\xf3\x34\xef\x7e\xf8\x3d\ -\x74\x7b\x3d\x66\x26\x6c\x32\x55\xe6\xe6\xe6\x2a\x2e\x29\x81\x26\ -\x91\x58\x1a\x4a\xd5\xa1\x34\x56\x07\x49\xe4\x4d\x05\xa1\x00\xf9\ -\xbc\x81\x8f\x53\x9f\x24\x0e\x12\x2a\x4e\x83\x34\x91\xb1\x4b\x63\ -\x20\x29\xb8\x83\x01\x71\xaf\x07\x79\x8a\x51\xb6\xe9\xf7\x7b\xa8\ -\x72\xce\xb1\xfb\xee\xe2\x7b\xdf\xf9\x16\xa6\x96\xa3\xe4\x19\x65\ -\xdb\x62\xd7\xf6\x31\xae\x5c\xb8\xc4\xe1\xfd\x87\x30\x75\x89\xe1\ -\x40\x84\xb3\x6d\x3d\x34\x33\x33\x33\x22\x6a\x74\x30\x18\x79\x54\ -\xc7\x45\x7c\x0c\x05\x75\x31\x08\x02\x64\x59\xa6\x56\xab\x71\xfd\ -\xfa\x75\x9a\x4d\x85\x38\x4d\xb8\x79\xfb\x36\xb3\xe3\x13\x78\x71\ -\x8c\x69\x95\x71\xe3\x04\xa3\x5c\xa7\x32\x3e\x45\x2f\xca\x09\x24\ -\x08\x74\x8b\x56\x9c\xb2\x1a\xc0\x46\x92\xf3\xe0\x43\x77\xf0\xe4\ -\xab\x6f\xf0\xed\x97\x5e\xe6\x91\x0f\x3c\x82\x3d\xb5\x8d\x37\x2e\ -\x5f\xc3\x6a\xd6\x59\x1d\xc4\x7c\xf8\xb1\x9f\xe2\x6b\x8f\x3f\xc9\ -\x5b\x37\x6e\xa3\xd9\x2a\xd3\xdb\x77\x32\x18\xfa\x44\xa9\xc4\xca\ -\xed\x05\x90\x84\xae\x17\x55\x2d\x42\xc3\x65\x34\x4d\x1b\x85\xb1\ -\xe5\x45\x02\xc5\x96\xb0\xdf\x30\x0c\xd4\x42\xd8\x9f\x84\x21\xb2\ -\xa6\xa1\x15\x87\xd5\xb2\xac\x91\xd1\xde\x56\x65\xcd\xb2\x4c\x90\ -\x48\x0c\x43\xf8\x78\x01\x91\xe7\x31\xec\xf7\x0b\xf3\x3d\xe1\xa2\ -\x69\x15\xf3\xaf\xa2\x28\x42\x14\xf1\x8e\x75\x53\xb9\x5c\xc6\x70\ -\x1c\x24\x55\x15\x7b\x67\xd7\x45\x2a\x04\x3d\x6a\x71\xb9\x48\x92\ -\x44\x12\x04\xc2\xa9\x33\x49\x30\x0c\x03\xc7\x71\x46\x09\x93\xc8\ -\x45\x87\x55\x58\xf7\x4a\xaa\x8a\x37\xf4\x29\x57\x6a\x54\xea\x4d\ -\x96\x36\xdb\xbc\x7a\xee\x3c\x83\x8c\xd7\x25\x5d\x23\xcf\x24\xe2\ -\x30\xc1\xc8\x15\xf4\x77\x9c\xc8\x5c\xc9\xc9\xe4\xad\x28\x8c\x6c\ -\x14\x00\x27\xff\x3f\x2a\xcc\x12\xe4\xb2\x52\x58\xcd\x42\x26\x0b\ -\x5a\x59\x27\xe0\x93\x4f\xbe\xf4\x32\x97\x16\x56\x18\xdb\xb9\x9b\ -\x5e\x9c\x81\x17\x61\x97\xc7\x50\x35\x93\x24\xc9\xc5\x4e\x3b\x97\ -\x51\x24\x19\x55\xd1\x47\x86\xe1\x69\x9e\x09\xba\x5b\x71\x6b\x9a\ -\xc5\x9b\x90\xa7\x29\x49\x14\x89\x99\x27\xcf\x91\x6b\x75\x91\x53\ -\x14\xc4\x94\xaa\x0d\x2c\xcb\x62\x7d\x7d\x9d\xb8\xd3\x86\x5a\x03\ -\x59\xd1\x58\x58\x5a\xa3\xdb\x1f\xd2\xda\xe8\xe2\x54\xaa\x84\xbd\ -\x01\xaa\xe1\x50\xaa\xd5\x31\x9b\x13\x74\x57\xd6\x46\x6d\x4d\x6f\ -\x75\x05\x34\x0d\x73\x4c\xd0\x3e\xd7\xd7\xd7\x71\xbd\x9c\x57\x4e\ -\x2d\xf0\x9f\x3e\xff\x05\x7e\xef\xf7\x3e\xc3\x47\x3e\xf4\x00\x9a\ -\xa2\x32\x5e\xd2\xd1\x64\x85\x7a\xb9\xc4\xea\xf2\x12\x47\xef\xbb\ -\x07\x59\x96\x99\x9b\x1b\xe7\xc5\xd3\x97\xb9\x70\xe3\x2a\xf7\x3f\ -\x72\x14\xb3\x51\xe7\xf8\xc9\x37\x78\xe1\xd5\x57\xb9\x7a\xe3\x86\ -\x68\xa3\xab\x35\x2c\xa7\x4c\x10\x25\x24\x99\x8c\xac\x5b\xe8\xa6\ -\x43\x98\x48\x6c\xf6\x86\xf4\x87\x31\xb9\x66\x82\x65\x89\x07\xac\ -\x56\x06\x53\x43\x55\x72\x86\x4b\x37\x50\xe5\x84\xbd\x3b\x67\x19\ -\x73\x74\x8e\xdd\x79\x90\xe9\x7a\x85\xf3\x27\x4f\x42\x0c\x52\x96\ -\x53\x2b\x2b\x04\x6e\x3e\x7a\x18\x4d\x53\x61\x63\x63\x83\x66\xb3\ -\x29\x90\xd8\xe2\xa6\x8e\xe3\x0c\x49\x92\xc4\xee\x33\x4e\x47\x0f\ -\x9d\xa2\x28\x28\x9a\x4c\x2e\x65\x78\x21\x44\x69\x42\xad\x51\x27\ -\x00\x4c\xab\x44\x6d\x62\x86\xf3\x97\xaf\x13\x49\x32\x53\xf3\x3b\ -\xf8\xd7\x7f\xf4\x05\xae\xb4\xe0\xaf\xdf\x78\x93\x3f\xfc\xf3\xbf\ -\xe0\xf3\xdf\x7a\x8a\xc7\x8f\x9f\xe0\xf7\xbf\xf2\x2c\xbb\xef\x7d\ -\x80\x4e\xa6\x70\x7a\x29\xc0\x99\x99\xa0\x39\xbf\x9f\x8b\xcb\x7d\ -\xdc\x5c\x23\xd6\xe1\x43\x3f\xf9\xd3\x3c\xfd\xe2\xab\x3c\xf5\xec\ -\x49\x24\xc5\xc4\xb0\x6a\x44\x51\x8a\xe2\x54\x46\x0e\x98\xaa\xae\ -\x83\xa6\x91\xe7\xf9\x68\x73\x21\xcb\x32\xba\xe3\x88\x48\x97\xad\ -\x0a\x8c\x68\x51\x25\x59\x10\x26\xb2\x82\x67\x90\xe7\x39\x4a\xe1\ -\x26\xb3\xf5\xfd\xa7\x45\x97\x12\x86\xa1\x38\x60\x9a\x86\x6e\xdb\ -\x28\x86\x01\x69\x8a\x37\x1c\x8a\x43\x20\xcb\x82\x9b\x5d\x14\x92\ -\xad\x03\xbf\xf5\xb9\x4a\x01\x86\x6d\x19\x01\xe2\x09\xdc\x27\x0c\ -\xc3\xd1\xff\xcf\x2c\x78\xd8\xe4\x12\x84\xf1\xe8\x00\x6b\xaa\x81\ -\xa1\x5b\xc8\x8a\x02\x9e\x47\x26\x81\xe9\xd8\xc2\x86\x38\x08\xf0\ -\xc3\x84\xe6\xe4\x0c\xb5\xd9\x1d\x3c\x73\xf2\x75\xae\xac\xf5\x8e\ -\xc6\x12\xa4\x99\x8c\x86\xaa\xce\x40\x94\x00\x00\x20\x00\x49\x44\ -\x41\x54\x86\x92\x4b\x28\x05\x7a\x95\x91\x91\x6d\x45\x54\xbc\xc3\ -\x17\x48\x92\x24\xd4\x1f\x3c\xc4\x3f\xa8\xb9\x50\x34\xb1\xa1\x4a\ -\xb3\x0c\x64\x85\xa4\x30\x09\x8b\xe1\x47\x2e\xdf\xba\xcd\xf7\x5f\ -\x7d\x9d\xc6\xce\x5d\xf4\xa2\x8c\x56\xbb\x03\xd5\x3a\xa9\xa4\x20\ -\x21\x93\x67\xb1\x90\x36\x2a\x1a\x9a\x66\x88\x78\x97\xe2\x87\x9e\ -\xa5\x29\xc4\x11\x86\x3d\x26\xe0\x7f\x59\xc4\xa2\x8e\xda\x25\x45\ -\x41\xd1\x34\x48\xc5\x8d\x2a\xe5\x62\x15\x10\x06\x09\x92\xaa\x90\ -\x97\x1c\x41\xa5\x93\xd4\xa2\xf5\x0f\x69\x8e\x4f\xb1\xb2\xba\xc8\ -\x8e\x43\x77\xb2\xb0\xb0\x44\xa3\x39\x2e\x4c\xd0\x4b\x65\xd2\x2c\ -\x67\xb8\xba\x0c\x8a\x44\x73\x66\x92\x28\x0a\x08\xa3\x80\x17\x5e\ -\x7a\x91\xcd\x9b\x57\x39\xfd\xdd\xef\xf3\xa9\x47\xdf\xcf\x3f\xfd\ -\xe5\xc7\xf8\xc6\xe3\xc7\xf9\xf1\x8f\xbc\x8b\xdb\xab\x5d\x6e\x2d\ -\xdd\x24\x8a\x22\xee\x3e\x78\x90\x34\x8e\x30\x6c\x87\x08\xf0\x92\ -\x88\xfb\x1e\xb8\x8b\x4e\x0a\xb7\x56\x5a\x2c\xb5\x3a\x68\x66\x99\ -\xb1\x5a\x83\x44\x11\x6f\xde\x60\xe8\x8a\x99\x3f\x8e\xa9\x35\x9a\ -\x0c\x07\x2e\x56\xd9\xa1\x77\x7b\x01\x75\xac\x41\xae\xc8\x94\xab\ -\x35\x06\xfd\x4d\x2c\xdd\xc4\xef\x74\x50\xe4\x1c\x94\x0c\x3d\xf5\ -\xb9\x76\xee\x0d\xee\xbf\xf3\x00\xeb\x0b\xd7\x99\x9f\x9d\x60\xb6\ -\x5e\xa7\xb3\xda\x66\x6e\x7a\x06\x29\x01\x6f\xe0\x42\xe1\xcd\x2c\ -\x49\xb0\xb8\xb8\xc8\xc4\xc4\x04\x8a\x22\x8f\xfc\xcd\xd2\x42\xbb\ -\x9b\xe7\xf9\x88\xae\xb8\x55\xb5\xd2\x2c\x67\x7a\x66\x92\xc5\x95\ -\x16\x3b\xe7\xc6\x39\x74\xe7\x5d\xbc\xf0\xca\x09\xee\x7f\xf0\x7e\ -\xc6\x26\xa6\x68\x5d\x5f\x20\xd1\xe0\xfb\x2f\x5c\xe0\xcd\xeb\xb7\ -\xf8\xdd\xff\xe3\xb3\xdc\x5e\x5d\x25\xca\x53\x2e\x7e\xed\xeb\xcc\ -\x1e\x38\x80\xac\x1a\x44\xa6\xc3\xd7\x3f\xff\x79\x0e\xde\x73\x37\ -\xbd\x8d\x75\x02\x77\xc0\xce\xd9\x19\xe6\xe6\xe6\xf8\xd9\x4f\x7f\ -\x9c\xfb\x1f\x39\xc2\x91\x87\x8f\xf0\x4b\xbf\xf6\x3b\xcc\xdf\x71\ -\x84\xe6\xc4\x24\x5d\x2f\x60\x18\xfa\x10\x86\x64\x9a\x82\x5a\x54\ -\xe0\x34\x4d\x89\x0b\xab\x27\x45\x51\xa8\xd5\x6a\xb8\xae\x4b\xe8\ -\xfb\xc2\x2d\x25\xcb\xde\xc6\x69\x34\x8d\x3c\x08\x85\x97\x75\xf1\ -\x5c\xa9\xaa\x2a\x2a\x7c\xf1\x80\x67\x59\xc6\x70\x30\x10\x6d\x75\ -\x51\x25\x15\x45\x61\xa0\xaa\x84\xc3\x21\xae\xeb\x92\x24\xc9\xe8\ -\x35\xc3\x42\xa2\x28\x49\x12\x49\x2c\x62\x5c\x95\x42\xf9\xb4\x75\ -\x68\x07\x51\x04\x79\x8e\xdb\xeb\xa1\x3b\x16\x7a\x31\x77\x87\x61\ -\x88\x22\xcb\x44\x69\x3a\x6a\xef\x4b\x96\xa0\x1e\x27\xb1\x4e\x90\ -\xa6\xa3\x73\x66\x18\x06\x5e\xa1\x17\x77\x66\xa7\xb0\x9b\x4d\x4e\ -\x5f\xbd\xc2\x8b\x67\xce\x31\x37\xf9\xee\x7c\x4a\x95\x25\x49\x32\ -\xc4\x33\x4e\x46\x2e\xa7\xa3\xc0\x74\xa4\x1c\x85\xbc\x48\x29\x16\ -\x87\xfa\xef\x9d\x91\xb7\x5a\xb2\xb8\x48\xa8\x8b\x72\x76\x85\xf0\ -\xfb\x4b\xdd\xe0\xa9\xa7\x9e\x3f\xce\x8d\x95\x75\xca\xcd\x49\x5a\ -\xae\x0b\x9a\x05\x56\x59\x24\x2c\x86\x09\x8a\xa2\x93\xa6\x39\x32\ -\x0a\x9a\x5c\xbc\x4e\x12\x92\x24\x91\xb0\x07\x32\xc4\x01\x4f\xd2\ -\x9c\x34\xc9\x09\x06\x22\x73\x88\x2c\x03\xd5\x40\xca\xa4\x91\x5f\ -\x52\x9c\x26\x44\x49\x4c\x1c\x25\x58\x76\x09\xb3\x5a\x81\x34\x47\ -\xd6\x74\xba\x03\x97\x24\x83\x95\x5b\xb7\x41\x52\xd9\x68\xf7\x44\ -\x50\x57\x0e\x8a\xa6\x83\x24\x33\x5c\x59\x06\xcb\x64\x72\x7e\x1e\ -\xd7\x75\xe9\xaf\x2e\xa3\x69\x0a\x13\x13\x4d\x5e\x7e\xe2\x09\xee\ -\xbd\xef\x3e\x3e\xf5\x0f\x1e\xc3\x75\x61\x62\xa2\xc9\xe2\x72\x9f\ -\xb5\xd5\x15\xa6\x27\x26\xb9\xf7\xc8\x9d\x34\xca\x25\xa4\x3c\xc7\ -\xf7\x23\x9e\x78\xea\x79\x76\xec\x9a\xc7\x4b\xe1\xcd\xb3\x0b\x3c\ -\xfd\xf4\xcb\xdc\xba\xb5\x86\x3b\x88\xe8\xf7\x7c\x7a\xad\x36\x49\ -\x94\x8a\xbd\x65\x96\x53\xaa\x55\xe8\xf4\xdb\x68\xb6\x46\xaf\xbd\ -\x46\x79\x7e\x96\x5c\xcf\x90\xd5\x9c\xe1\x66\x0b\x7a\x3d\xd4\x61\ -\x1f\x3b\x8d\x90\xdd\x1e\xfb\xa6\x9b\xec\xac\xda\x74\x17\xae\xf1\ -\xd5\xcf\x7f\x96\xf5\x1b\x17\xf9\xd1\xf7\x3c\xc8\x23\xf7\x1f\x65\ -\xe9\xe6\x55\xea\x15\x07\x4b\x03\x4b\x17\x95\x40\x80\x55\xf1\xa8\ -\x0a\x27\x49\xca\x70\x38\x1c\xcd\x94\x5b\x1c\xf6\x2d\xfb\x24\x55\ -\x55\x05\xcf\x38\x8e\xc5\x08\x02\x2c\xad\xf5\x68\x8e\x57\x69\xf7\ -\x87\x2c\x6d\xf6\xa8\x97\x2d\x16\xd7\xbb\x7c\xff\xf8\x45\x2e\x2f\ -\xaf\xa3\xd5\x9a\x9c\xbf\x76\x93\xda\x8e\x79\x94\xb1\x09\x26\xef\ -\xbb\x9f\xa5\xbe\xcb\x42\xbb\xcd\xd3\x2f\xbf\xc2\xfe\x47\xde\xcb\ -\x85\x9b\xb7\x31\x1a\x4d\xe6\x0e\x1e\xe4\xe6\x5a\x8b\xb7\x6e\xde\ -\xe6\x5f\x7d\xf6\xcb\x94\x75\xf8\xce\x53\xa7\xd8\x39\xbf\x9b\xab\ -\xaf\xbd\x86\x84\x2c\x12\x34\xc3\x48\xb4\xd4\x05\x73\x6f\x6b\x0e\ -\x96\x14\x05\x8a\xc3\x19\x45\x11\xb2\x2c\x0b\xfb\x27\x4d\x78\x76\ -\x27\xc5\x81\xd6\x34\x0d\xd9\x32\x41\x53\xc9\xc9\x09\xa3\x10\x3f\ -\x0c\x88\xd3\x04\x59\x55\x30\x6d\x0b\x59\x55\x20\x11\x69\x23\x28\ -\xb2\x08\xb1\x27\x17\xff\x66\x1a\x44\x71\x44\x96\x26\x0c\x7d\x8f\ -\x28\x89\x49\xbd\x21\x92\x25\xc0\x30\xd5\xd0\x49\x92\x98\x24\x4b\ -\x47\xba\x65\x59\x55\x40\x55\xc0\x10\x80\x5c\x14\x89\x75\xe1\x96\ -\xd8\xc1\x30\x0c\x50\x14\xf2\x5c\x22\x8b\x12\x32\x09\x92\x3c\x13\ -\x14\x65\x55\x27\xcd\x33\x7a\x83\x3e\x29\x39\x4e\xa3\x01\x71\xca\ -\xc0\xf3\x71\xb3\x9c\x6e\x06\xcf\xbc\x71\x92\x0b\xb7\xd7\x84\xee\ -\x19\x44\xd5\x2c\xb2\xbe\x84\x04\x44\xf8\xf1\x6c\x55\xe4\xad\xf7\ -\x5c\x7d\xdb\xe0\xfa\xed\xda\x9c\x8d\xca\xb2\xf8\x61\x22\x4b\x20\ -\x4b\x5b\x71\x4e\xf8\x19\xbf\xb9\xb8\xd6\xe2\x99\x97\x5f\x21\x92\ -\x14\x3a\x43\x9f\x5c\xd1\x29\x4d\x4e\xe3\xae\xf7\xc0\x54\x88\xa3\ -\x80\x72\xc5\x66\xd8\x4f\xc8\x95\x7c\x74\x3b\xe6\x71\x4c\x2a\x09\ -\x23\x35\xa5\x00\x34\xc2\x30\x14\xb7\x68\x14\x61\x94\x6b\x44\x92\ -\x24\x92\x14\xa3\x88\x52\xa9\x26\xc0\x99\x34\x15\xa9\x15\xba\x86\ -\xaa\x6b\x90\xcb\x04\x8a\x4c\xaf\xef\xa2\x6a\x06\x7e\x67\x93\xda\ -\xf6\x39\x74\x43\xc6\xf5\x06\xd8\xa6\x45\x18\x25\xf8\xad\xae\x90\ -\x07\x1a\x16\x76\xa5\x22\x5e\x8b\x94\xe6\xce\x6d\x6c\x2c\xdd\x62\ -\xf3\x52\x8b\x03\x0f\x3c\xc8\x8f\xfe\xf0\xa3\x68\xb2\x80\xfe\x8f\ -\x1c\xd9\xc7\x73\xcf\xbf\xc0\xfc\x9e\x39\x76\xcc\x4e\x93\x46\x09\ -\x9d\xcd\x2e\xb6\xe9\x70\x63\x61\x91\xbb\xee\xbe\x07\xd5\xb1\x70\ -\x13\x58\xef\xf9\x5c\xbc\xb5\x8a\x6c\x96\x28\xd5\xab\x68\x95\x12\ -\x9b\xfd\x01\x71\x14\x91\x0e\x86\x94\x9b\x93\xc8\x59\x44\x59\x93\ -\x19\x2c\x5c\x47\xae\x56\x20\xf5\xa8\xda\x2a\xed\xb5\x15\xd4\x24\ -\xa4\x6e\xe8\x6c\xaf\x57\xc1\xd6\xb9\x76\xe1\x3c\xa6\x31\x89\xa3\ -\xab\x04\x59\xc0\xcf\x7d\xfc\xc3\xfc\xfc\xcf\x7e\x0a\x29\xce\xb8\ -\x74\xf6\x2c\x79\x38\xe4\xf2\x85\xb3\x9c\x6c\xf7\x99\x6c\x8e\x31\ -\x36\x33\x39\xe2\xa9\x4f\x4d\x4d\x51\xad\x56\x47\x33\xf2\xfc\xfc\ -\x3c\x9a\x26\x17\x48\x69\x8a\xa6\x29\x64\x19\xa3\x79\x5a\x96\x65\ -\xb6\x6f\xdf\x4e\xbb\xdb\x61\xdb\x78\x83\xe5\x56\x8f\xea\xd8\x38\ -\x86\x5d\xe5\xeb\xcf\xbe\xce\x57\x1f\x7f\x82\x85\x8d\x01\xe5\x89\ -\x59\x28\xd5\x90\x24\x8d\x76\x94\xe0\x49\x05\xde\x21\xcb\xd4\xa7\ -\x66\x30\x14\x95\x2b\x0b\x4b\x4c\xcc\xed\xe4\xfa\xe2\x02\x7b\xe7\ -\x76\x22\xd9\x36\xc3\x38\x61\xf3\xe6\x02\xe7\x57\xe1\xc5\x97\x5f\ -\x41\x36\x6c\x76\xde\x73\x0f\xb7\xae\x5c\x06\x59\xa5\xb2\x6d\x96\ -\x38\x8d\xf0\xfd\x02\xe4\x2a\x52\x21\x46\x95\x11\x18\x74\x3a\x68\ -\x96\x35\x6a\x5d\x87\xc3\xa1\x08\x58\x2b\x1e\xe2\x5a\xad\x36\x9a\ -\x87\x93\x20\x20\x8b\x63\xc2\x34\x1d\x8d\x6a\xb2\x2c\xd4\x51\x14\ -\xd4\x4a\xaf\xdf\x27\x08\x02\x4a\xa5\x92\x30\x0b\x90\xe3\x51\xb7\ -\x22\x17\x01\xea\x4e\xc1\xff\x4f\xd3\x94\xce\xea\x2a\x59\x26\x56\ -\x3e\x23\x10\x2d\x08\x50\xaa\x55\x6c\xdb\x66\xd0\xed\x10\xa7\x29\ -\xa1\xaa\x11\x47\xc2\xb2\x97\x62\xc6\x4f\x0a\x70\x4c\x92\x24\x91\ -\x9b\x5c\x54\xf6\x7c\x38\x2c\x2c\x9e\xab\x78\x03\x17\x3f\x4e\xf1\ -\xb2\x10\xb5\x56\xe3\xdc\x8d\x5b\x5c\x5a\x5c\xe1\xd8\xdc\x24\x72\ -\x0c\x1a\xa2\xe2\xe6\x02\x2a\x23\x27\xff\x5b\x88\xf5\xdf\x66\x76\ -\x49\x39\xe4\xd2\x08\x14\x13\x8e\x85\x08\xbb\x14\xdd\xa4\x9f\x24\ -\xbf\x2f\xab\xea\x5f\x07\x19\x7c\xf1\xcf\xbf\x4a\xdf\x8f\xd8\xbe\ -\x73\x8e\x9b\x83\x3e\xc6\xd4\xb4\x08\x21\x4f\x12\x62\xd7\xc5\x29\ -\x57\x44\x6b\x17\xc7\x8c\x4f\x4e\xb0\x31\xec\x20\xeb\x32\x8a\x61\ -\x90\x47\x09\x95\x4a\x85\xf6\xd2\x12\x66\xa9\x4c\x1e\xc7\xc4\xbe\ -\x8f\xd9\x68\x60\x1a\x26\x69\x92\x93\x49\x31\xc8\x32\xdd\x6e\x1f\ -\xe2\x04\xcd\x36\x31\x4d\xb3\x20\x03\x28\x90\x4a\xa0\x6b\x24\x83\ -\x3e\x56\x63\x1c\x6d\x6c\x82\xa1\xeb\x91\x61\x20\x2b\x1a\xbd\xde\ -\x40\xcc\x2b\xa5\x12\x92\xac\xa1\x29\x0a\x5e\xb7\xcb\xf4\x8e\x59\ -\x3a\xdd\x16\x1b\x4b\x4b\x8c\x8f\x37\xe9\xa5\x3e\xa6\x24\xf1\x9e\ -\xfb\x76\x43\x5f\x74\x32\x37\x16\x96\xa8\xd5\x6a\x42\x97\x1a\xc5\ -\xe4\x71\x84\x94\xc3\xf5\xeb\xd7\x31\x9c\x12\xb3\xe3\x65\x16\x82\ -\x94\xdc\x04\x37\x57\x88\xcd\x0a\x46\xc9\x86\x3c\x23\x4a\x40\x55\ -\x75\xe2\x4e\x4f\x88\x1d\xb2\x88\xc8\x1d\xa2\x49\x12\xba\x92\xa2\ -\x86\x3d\x4a\xb6\x4c\x14\x04\x94\xb3\x80\x77\x1f\x3e\xc4\x3f\xfa\ -\xf4\x47\x68\x98\xb0\xb0\xe8\xa1\x93\x33\x3b\xe9\x90\x67\x70\xe1\ -\xad\x73\xec\xdb\xb3\x1b\xb7\xb5\xc6\xd4\xd8\x38\x5e\xb7\xcd\xbb\ -\x1f\x3c\xc6\x78\xad\xc4\xfa\x62\x9b\x17\x5e\x78\x81\xf5\xde\x26\ -\xa6\x63\x8b\x2e\xa3\xdf\xa7\xdb\xed\xa2\xaa\x2a\x6f\xbd\xf5\x16\ -\xaa\xaa\xb2\x6d\xdb\x36\x86\x43\x91\xef\xbb\xb0\xb0\xc4\x60\x30\ -\xe0\xe6\xcd\x9b\x5c\xbb\x76\x8d\x5a\xad\x46\xb5\x54\xe6\xf4\xb9\ -\xb3\xec\xbe\x63\x3f\x92\xa1\x73\x6b\xad\xc5\x4a\xdf\x23\x55\x4c\ -\x72\xdd\xc6\x8f\xba\xd8\x9a\x89\x62\x97\xa8\xd8\x15\x7a\xad\x65\ -\xb4\x89\x71\xd0\x55\x8c\xa9\x69\x3a\xad\x0d\x2a\x8d\x3a\xd5\xb1\ -\x06\xbd\x7e\x07\xc5\x34\xe8\x07\x1e\xb5\x89\x26\x8e\x65\x53\xb2\ -\x4a\x5c\xba\x72\x15\xd3\x36\x08\x93\x94\x6e\x7b\x03\xf2\x18\xad\ -\x5c\xc1\x1f\x0e\x90\x34\x21\x09\x8c\xe3\x18\xb7\xd7\x43\xd1\x75\ -\xca\xe5\x32\xaa\xaa\x32\xe8\xf7\x45\xc4\x4b\x71\x88\xb2\x2c\x23\ -\x4b\x92\x22\x24\x50\x14\x80\xad\x80\x36\x45\x51\x30\xaa\x55\x92\ -\x24\x21\x0c\xc3\x11\x52\x1f\x79\x1e\x9a\x65\x21\xcb\xb2\xb8\x1c\ -\x0a\xc7\x8f\xad\xd7\xdb\xca\x8e\x8e\xe3\x18\xaf\xdd\x86\xe2\x12\ -\xd9\xea\x62\xec\x7a\x5d\xcc\xc5\x79\x4e\x38\x18\xa0\xda\x36\x28\ -\x0a\x95\x4a\x45\x24\x54\x54\xaa\x78\x9e\xc7\xb0\xd3\x41\x73\x1c\ -\x7a\x6b\x2d\x64\xa7\x4c\x94\xc4\xd8\x95\xb2\xf0\xa3\x4b\x53\xcc\ -\x6a\x59\x54\x72\x59\xa5\x39\xb7\x8b\x8d\xe5\x65\x3a\x99\x44\x3e\ -\x18\x52\xdb\xbb\x8b\xb5\xf5\x45\x1c\xab\xcc\xd2\xe2\x06\x9f\xfd\ -\xe2\x97\xf8\xd4\x7b\xee\xfe\x4a\x2c\xf3\x53\x9a\x24\xc2\x8a\x35\ -\x59\x22\x21\x46\x46\xa1\xef\xf7\x69\x5a\x55\x24\x59\x78\x79\x4b\ -\xd2\x0f\x1c\x64\x29\x2f\x76\xc9\x52\x5e\x28\x2f\x44\xcb\xa3\x68\ -\x26\x6e\x14\xa2\xeb\xc6\x6f\x05\xf0\xba\x9f\xc0\xb7\x9f\x7e\x86\ -\x9d\x87\xef\xe1\xdc\xad\x5b\xec\x3a\x7a\x8c\xa5\xa1\x47\x1a\x05\ -\x02\xf9\x2b\x78\xae\x8a\x22\x43\x2e\xe4\x60\x00\x92\xa2\xa0\xa8\ -\x92\xb0\xa3\x2e\xb4\xc6\xbd\x5e\x17\xad\x88\xbd\xdc\x6a\xa5\x2c\ -\xcb\x22\x4e\x42\x68\xb5\x90\x27\x27\x91\x2d\x0b\x4d\x53\x49\xf2\ -\x8c\x38\x89\x09\x13\x81\x62\x92\x89\x5b\x2e\xcb\x32\x34\x53\x47\ -\x97\xc4\x5c\x18\x25\x21\xa4\x62\x89\x8e\x2c\xe2\x3f\xc8\x32\xe8\ -\x0f\xd8\xd8\xd8\x20\x8e\x7c\x88\x22\xdc\x6e\x97\x99\x7a\x93\x1f\ -\x7e\xf8\x61\xba\x6d\xa8\x90\xb3\xb8\xbc\x42\xa3\x6c\xb1\x7d\xfe\ -\x30\x9e\xdf\xe7\xd4\xeb\xaf\x71\xf4\xde\x7b\x59\x5c\xbe\xcd\x8e\ -\x9d\x73\xc4\x99\xc4\x4a\x37\x64\x6d\xd0\xe3\x96\x1b\xf3\x95\xef\ -\x7e\x0f\x5f\xd3\x08\x92\x94\x6a\xa3\x8e\xef\x0f\x89\xd7\x96\x99\ -\xd9\x35\xcf\xa0\xdd\xc6\x8c\x7c\xea\xa6\xc6\x54\xa3\xce\x58\x7d\ -\x0f\x8a\x04\x9b\xed\x0d\xd6\x5a\x03\x26\xb7\x4d\xf2\x3f\xfd\x37\ -\x1f\xa1\xbf\x96\x13\xf4\x73\x96\xce\x9d\xe1\x87\x1e\x7e\x90\x5e\ -\xab\xcf\xb6\x99\x0a\x6a\x1c\x51\xb5\x0d\x2a\x56\x03\xb2\x84\x5a\ -\xd5\x21\x49\x22\xe2\x24\x27\x88\x03\xf6\xdd\xb1\x8f\x5d\x7b\xf7\ -\x21\x6b\x0a\xcb\xcb\x2b\xc4\x71\xcc\xc4\xc4\xc4\x68\x3e\xde\xb7\ -\x6f\x1f\x8b\x8b\x8b\xac\xad\xad\x8d\x94\x3d\x93\x93\x93\xa3\xd5\ -\x53\xb3\x39\x46\x1c\x44\x78\x61\xc0\xc1\xc3\x87\xd1\x2b\x25\xac\ -\xdb\xcb\x5c\x5b\x6e\x51\x9f\x98\xa1\x39\xb3\x8d\x9e\x6c\x93\xea\ -\x16\x3d\xd7\x47\x2d\x39\x80\x8c\x6e\x99\x0c\x3b\x2d\x41\x0a\x4e\ -\x13\xfa\xeb\x6b\xdc\x75\xec\x18\x13\x8d\x23\x8c\x57\xab\x5c\x79\ -\xeb\x2d\x3e\xf1\x13\x1f\x65\x87\x08\x79\xe4\xdc\xe5\x3e\xb7\x16\ -\x16\x88\x83\x18\xbd\xd6\x40\xaf\x54\xd0\x74\x95\x34\x97\xd0\x4d\ -\x13\x49\x11\xfa\x5b\x3f\x8e\x49\x83\x00\xb7\x90\x1d\x96\x2b\x15\ -\x7c\xdf\x17\x2e\xaa\x05\xe2\x2b\x29\x0a\x72\x31\xe3\xe7\x79\x8e\ -\xe7\x79\x6f\x67\x37\x15\xac\x30\x31\x93\xc6\xf8\xfd\x3e\xba\xe3\ -\x10\x85\x21\x72\xe1\x2a\x13\xc7\x31\xd1\x60\x40\xa2\xaa\x94\x6b\ -\x35\xa2\x20\x64\x94\xb6\x52\xbc\x6e\x92\x24\x23\xed\xbb\xaa\xaa\ -\xc8\xb2\x8c\x61\x59\x02\x34\x2b\xba\x81\xe1\x70\x88\x2c\xcb\xa3\ -\xfc\xa8\x40\x51\x88\xa3\x08\x7c\x1f\xb5\x5c\x46\x37\x8a\x04\xc8\ -\x4a\x65\x54\x95\xb7\xba\x88\x24\x49\x46\xab\x32\x9c\x12\x9d\x6e\ -\x9f\xe9\x1d\x73\xac\x5c\x3c\xc3\xf4\xdc\x1e\x6e\x5d\x7d\x8b\x57\ -\x2e\xaf\x7d\xf2\xe1\x7d\x93\x68\x11\x28\x42\xdc\x28\x56\x50\x05\ -\x38\x9c\x15\xc4\x8f\xad\xe9\x58\xfd\x3b\x73\x8e\xf3\x82\xeb\x25\ -\xe7\xe4\x89\xf8\x26\x25\x5d\xc5\xcd\xc8\x33\x19\xfe\xe0\x73\x5f\ -\xa0\x36\x3e\x4d\x6f\xe8\x51\x75\x1c\xde\x7d\xec\x28\xdf\x7c\xfe\ -\x79\xc2\x8d\x0d\xa8\x4d\x52\x2a\xdb\x44\x3d\x1f\x55\x51\x04\x1b\ -\x2c\x8b\x0b\xf3\x38\x15\x45\x91\xc8\x32\x81\x4c\x92\xa6\x02\xa8\ -\xca\x73\x14\x24\x74\xdd\x00\xc4\x9b\x83\x17\x82\xac\x8d\x56\x26\ -\x79\x71\x53\xa6\x49\x4e\x9e\x26\x82\xbb\x6d\x88\x65\x7f\x96\x25\ -\x22\xd4\x55\x86\x60\x18\x90\x27\x21\xe8\x26\x92\xaa\xd1\xa8\x35\ -\xd8\xdc\xe8\xd0\x6c\xd4\x48\x26\x9a\xc4\xed\x0d\xac\x46\x95\xc9\ -\x6d\x7b\x09\x7a\x2d\x7e\xe6\x27\x7e\x02\xdd\x1b\xa0\x03\x6b\x0b\ -\x0b\x4c\xd6\xca\x6c\xdf\x5e\xc7\x4f\xc0\xb0\x74\xb6\xcf\xed\xe4\ -\xc5\x17\x5f\xe4\xe0\xee\x03\x98\x86\x45\xec\x47\x34\x6b\x3a\x76\ -\x6d\x82\xcf\xfc\xcb\xff\xc0\x20\x4f\xc8\xaa\x65\x1c\xcb\x62\xa3\ -\xd7\x41\x4a\x13\xca\x33\x13\xa8\x79\x8c\x16\xfb\x1c\xdc\xb5\x8f\ -\x7b\xf6\xee\xa3\xac\x29\xfc\xd0\x7b\xf6\x73\xe5\x52\x8b\xf1\xb1\ -\x3a\x97\xae\x5e\xe2\x3d\x0f\x1c\x22\xed\xc2\x36\x47\xa2\xb3\x39\ -\xe0\xe0\xb6\x59\x4a\x32\x18\x25\x87\x93\xaf\x9d\x66\xfb\xf4\x14\ -\x83\x5e\x17\xcb\xb1\x59\x5d\x5d\xa5\x52\xab\x82\x22\x13\xa7\x29\ -\x2b\x6b\xcb\xec\xdc\x3e\x57\xa0\xab\x22\x4b\xb9\xd1\x68\x50\x2a\ -\x99\xe8\x1a\xd8\xb6\x4d\xad\x56\xc2\xb2\xf6\x8e\x1e\xa2\xb1\xb1\ -\x31\x54\x55\x65\x65\x65\x45\x6c\x0e\xd2\x0c\xdb\xd6\xd1\x75\x1d\ -\x45\x56\x45\xbc\x96\x24\x73\xf2\xdc\x39\xcc\xfa\x06\x17\xae\xdf\ -\x40\x2b\x37\xd9\x5c\x5a\x66\xea\xe0\x21\x86\x61\x44\x75\x76\x1b\ -\xbd\x9b\xd7\x91\xc7\xaa\xcc\xcd\xcf\xb3\xbc\xb8\x44\xe8\x07\x9c\ -\x3e\x79\x92\x6d\xb3\x53\x9c\x8b\x42\xa6\xc7\xc7\xd1\x4d\xf0\x72\ -\xb8\x71\x63\x88\xac\x6b\x7c\xf0\xc7\x3f\xc4\xad\x85\x15\xd6\x36\ -\x3b\xc4\x09\x44\x71\x5a\x88\xf8\x45\xe2\x85\xae\xeb\xa2\xf5\xf5\ -\xbc\xd1\x61\x31\x4d\xd1\x85\x0d\x87\x43\xc1\x8f\x96\x65\x94\x77\ -\xc8\x5e\xe3\x38\x26\xf2\x3d\x41\xc0\x28\x0c\x27\x95\x02\xec\xca\ -\x03\x89\x34\x0c\x88\x7c\x0f\xa5\xb0\xd2\x4d\x32\x61\x58\x8f\x6d\ -\x41\x9e\x33\x18\xba\x28\x92\x4c\x16\x06\xc5\x41\x56\x85\x67\xb6\ -\x84\x98\x89\x73\xc1\x39\x50\x64\x19\xd3\xb6\x40\x96\x08\xbb\x5d\ -\xd0\x35\xa2\xa1\x8b\x56\x2a\xa1\xc8\x6a\xa1\x00\x84\x50\x92\x88\ -\xe5\x2d\x3b\x5b\x19\x4d\xd5\xc9\xf2\x14\x45\x13\x6b\x2b\xd2\xac\ -\x00\xb5\x23\xcc\x92\x03\x59\x4e\x9c\x24\x18\xb6\x30\x52\x98\xd9\ -\x7b\x07\xcb\x6f\x9d\x65\x66\x72\x96\x3f\xf8\xe3\x3f\xe5\xae\xff\ -\xf5\x7f\xcc\x75\x1d\x29\x09\x53\x2c\x14\xe4\x1c\x72\x29\xc3\x51\ -\x2c\x52\x64\x72\x72\xd4\xc2\x01\x48\x7e\x9b\xf7\xf1\xce\x25\xf3\ -\xdb\xff\x6d\xe8\x06\x51\x9e\xa0\xa2\x30\xf0\x03\x42\xe0\xaf\x9e\ -\x7c\x8a\x1d\xbb\xf7\xd2\xda\x68\xf3\xd3\x8f\xfd\x24\xef\x3a\x7a\ -\x17\x3b\x26\x27\x60\xe8\xa2\x9b\x1a\xaa\x2c\x11\xc5\x01\x49\x9e\ -\x88\xe4\x09\x09\x14\x43\x1d\x99\xe8\x6d\xc9\x12\x91\x54\x2c\xd3\ -\x1e\xcd\x70\x71\x1c\x8f\x66\x1d\x14\x05\x2a\x15\xb2\xe2\x36\xdb\ -\xfa\x1c\x49\x91\x45\x8b\xa2\x2a\x58\x25\x87\x72\xd9\x29\x58\x39\ -\x2e\x51\x14\x91\x27\x11\x68\x82\x33\x6b\x59\x56\x61\xa4\x67\xd3\ -\xef\xf6\x48\x7b\x7d\xf4\x6a\x8d\x2c\x4d\xe8\x6c\xb6\x38\xbc\xef\ -\x00\x8e\x04\xf7\xec\x3f\xc0\x70\x73\x83\xfb\xee\xda\x81\x94\x26\ -\xb4\x36\x7a\xa4\x59\x8c\x24\x41\x6b\xb3\xc5\xa1\xc3\x87\x59\x5e\ -\x5d\xa1\xdd\xee\x50\x2e\xeb\xb8\x21\xfc\xe9\x57\xbf\x43\x63\x6c\ -\x9c\x99\x9d\xdb\xc8\x02\x97\x41\x77\x13\x92\x80\x3c\xf6\x18\x76\ -\x5b\xf8\xdd\x75\xee\xdd\xb7\x8b\x8f\x3c\xf2\x10\x7b\xc6\x6b\x7c\ -\xf0\x81\xfd\xbc\xfe\xe4\x09\xd4\x7e\x9b\xb7\x8e\x3f\xcf\xb1\xdd\ -\xf3\x38\x09\x48\xc3\x01\xb3\x25\x78\xf3\xd5\x97\xb9\xfb\xe0\x76\ -\x48\x72\x3c\x7f\x88\xaa\xea\x8c\x4f\xcf\x90\x2b\x3a\x61\x0a\x8b\ -\xab\x2d\x4a\x8d\x71\x9c\x4a\x15\xc3\x52\x09\xc2\x98\x52\xb5\x22\ -\x08\x12\x05\x71\x42\x96\x65\x82\x20\xa1\x3f\x48\xe8\x76\xbb\xf4\ -\xfb\x1e\xa5\x92\xd8\xbd\x96\xcb\x65\x4a\x25\x03\x5d\x57\x46\x15\ -\x27\xf4\x7c\x7a\x1d\x17\xd2\x9c\xe1\x50\xac\x02\x67\xb6\x4d\x31\ -\x39\x3b\x4b\xdb\x1d\x50\x9f\x9c\x1e\xc5\xf7\x28\xb2\xc6\x60\x61\ -\x91\x24\x0c\x40\x51\xd1\x93\x8c\x9b\x17\x2f\x52\x36\x6d\x72\x3f\ -\x10\x86\x8b\x81\xc8\x24\x7e\xf3\xcc\x69\x9e\x7a\xe6\x65\x2e\x5f\ -\xeb\xf3\x07\x7f\xf8\x87\xfc\xd1\x1f\x7f\x81\xe7\x5e\x3a\xce\x99\ -\x93\xa7\x58\x5b\x5e\x45\xb3\x4c\xec\x4a\x19\xc3\xb6\xc8\x7c\x1f\ -\xbf\xd0\xa0\x6b\x9a\x26\xf6\xb9\xb2\x4c\x12\xc7\x7f\xa3\xfd\x45\ -\x51\x46\x6b\xa1\xad\xd5\xce\x28\xbc\x7c\x4b\xe6\x5a\x7c\xec\x16\ -\xa0\x47\xc1\x47\xd8\xaa\x84\x5b\x2b\x2a\xdb\xb6\xd1\x74\x1d\xc2\ -\x50\xac\xa8\x7c\x9f\xd8\xf7\x51\x14\x05\xd3\xb6\xdf\x26\xa9\x14\ -\xd5\x79\xab\xd2\x6f\xe5\x2a\x6b\xb6\x0d\xc5\x06\x00\x84\x68\x23\ -\x49\x12\xe1\x9d\x6d\x59\x44\xbe\xcf\xb0\x58\x6d\x6d\x6d\x0d\xb6\ -\xd0\x65\x45\x51\x88\xa2\x48\x00\x91\x9a\x0a\xb2\xc4\xa0\xef\xa2\ -\x2a\x3a\x9e\xe7\x63\x94\xab\xf4\xe3\x98\x37\xae\x5e\xe1\xd9\x53\ -\x17\x88\x81\x54\x55\x05\x9f\x3a\x57\x50\x8a\x2a\x9c\x22\x93\x49\ -\xca\x88\x85\x29\x8f\x02\xd8\x7e\xe0\x97\xbc\x05\xf1\x17\x8b\xf1\ -\x0c\xb0\x1c\x93\xa7\x5f\x3a\x89\x59\x2a\x73\xf6\xf2\x65\xc6\x27\ -\x27\xf8\xf0\x8f\x3c\xc4\x64\x19\x0e\xef\x9a\x87\x92\x81\x6d\xa8\ -\x0c\x07\x5d\xd2\x61\x8f\x28\xf5\x41\x93\xc9\x65\xb1\xc6\x4a\xf2\ -\x84\x20\x4e\x48\x92\x4c\xa0\xea\x86\x41\x18\x86\xd8\xb6\x2d\xe0\ -\xfb\xc1\x80\xa4\x37\xc0\xb0\x1c\x9c\x5a\x0d\x49\x55\x21\xce\x88\ -\x23\x31\x23\xe5\x05\x20\x21\x6b\x1a\x68\x6f\xcb\x1d\xf3\xd0\x27\ -\x1b\x0e\x88\xe3\x10\x45\xd7\x31\x0a\x23\x82\x34\x4d\x31\x0c\x03\ -\xb7\xd5\x22\x0a\x43\x9c\xf1\x71\xd2\x38\x22\xec\xf5\x51\x90\x18\ -\x2b\x97\x99\x70\xca\x48\xc3\x80\x86\xed\xd0\x5a\x1e\x72\x68\xd7\ -\x38\xb2\x0c\x65\x53\xe3\xc2\xc5\xf3\xd8\x8e\xc9\xf8\x44\x93\xbd\ -\x7b\xf7\x33\x1c\x7a\xac\xae\xf6\x78\xed\xc4\x59\x8e\x1d\x7b\x80\ -\xd6\xca\x2a\x4b\xd7\x2f\xd3\x1c\xab\x80\xdf\x47\x49\x03\xca\x52\ -\xc2\xc1\x6d\xd3\xfc\xc3\x8f\x7d\x84\x1f\xbe\xff\x6e\xaa\x2a\x1c\ -\xdd\x3f\x43\x55\x81\x9f\xf9\xb1\xfb\xe9\xaf\xad\x70\xff\x91\xc3\ -\x2c\x5e\xbd\xcc\x1b\x2f\x9f\xa0\x39\x56\xe6\xdb\x7f\xfd\x32\x77\ -\x1c\xdc\x07\x32\x24\xe4\xdc\x5a\x5e\x45\x2b\x95\xd9\xe8\x7b\x58\ -\x95\x12\xc3\x4c\x22\x94\x54\x8c\x52\x85\x20\x83\xbe\x9f\x23\x69\ -\x3a\xb2\xa6\xa3\xe8\xe2\x21\xd5\x75\x5d\x10\x14\x8a\x15\xce\xd6\ -\xcf\xb4\xd7\x13\xc2\x7a\xc1\x3e\x12\x6f\xf5\x16\x51\xa4\x5c\x76\ -\xa8\x94\x4b\x6c\x9b\x99\x15\x2e\x2c\x01\xc8\x3a\xd8\xe5\x0a\x27\ -\x4e\xbd\x49\xab\xdd\xc1\x70\x4a\x50\x2a\xb1\xb4\xb0\x40\x63\xdb\ -\x2c\x99\xe7\x31\xd9\x68\x20\xf9\x1e\x13\x95\x0a\x5e\xbf\x8f\x55\ -\x2e\x93\x17\xf4\xc5\xcd\xd5\x4d\xea\x63\x13\x7c\xf7\xdb\xdf\xe5\ -\x99\x17\x5e\xe0\x77\xff\xc5\x6f\xf0\x81\x0f\x7d\x94\xf9\xbd\x07\ -\x28\xcd\x4c\x53\x9b\x99\x01\xd5\xc0\x8b\x12\x41\xe6\xa8\x94\x41\ -\x92\xf0\x86\x43\x3c\xcf\x1b\xa1\xeb\x52\x71\xe9\xfb\x05\xd7\x40\ -\xb1\xac\xbf\x01\x8e\xc6\xc5\x6a\xc8\xb0\x6d\xc8\x73\xf2\x28\x22\ -\x2b\x8a\x81\xeb\x8a\x4b\x5d\x31\x0c\xd4\x5a\x8d\xb4\x90\x37\x6e\ -\xd1\x36\xb7\xd6\x72\x66\xad\x26\xe6\xed\x24\x81\xe2\xf5\xb6\x12\ -\x1c\x47\x24\x8f\x24\x79\x1b\x4c\x4b\x12\x28\x2e\x02\x8a\x6d\x41\ -\xe0\x79\xc5\xbf\x65\x6f\xd7\xc5\x2c\x23\x0b\x43\xd1\xf6\xcb\xaa\ -\x48\x9e\x70\x9c\x22\xa2\x46\x23\x8d\x12\xa2\x38\x15\xd4\x59\xcb\ -\x82\xe1\x90\x92\xe3\xd0\x5d\xdb\xa0\x3e\x36\x8e\xeb\x7a\xc8\x15\ -\x87\x2f\x3f\xf1\x6d\x7a\x90\xa3\xa8\xa3\xa0\x37\x41\xcf\x94\x09\ -\x93\xa4\xa0\x54\xff\x1d\xad\x75\x9e\xe7\xc5\x4d\x94\x8f\x18\xd7\ -\x41\x18\xa0\x1a\x0e\xed\x28\xcc\x4d\xdd\xe0\x8b\x7f\xf6\x65\x82\ -\x24\xe5\xc0\xa1\x3b\xb9\xef\xbe\xfb\x89\xdd\x94\x4d\xb7\x4f\xd5\ -\xd2\x70\x6c\x13\x29\x8d\x09\xfa\xc2\x7d\x5f\x96\x25\x30\x34\xd2\ -\x3c\x21\x47\x11\x06\xeb\x49\x8e\x5c\xec\xbd\xd4\xc2\x62\xd4\xf3\ -\x3c\x91\x3c\x6f\x9a\xa0\xe7\xa3\xaf\xc5\x34\x4d\xfc\x20\x10\x4c\ -\x24\x05\x90\x25\x81\xdd\x49\x32\x28\x32\x41\x14\xa1\x04\xa9\xa0\ -\xac\x65\xe2\x6b\x36\x2d\x13\x4d\xd7\x08\x93\x50\xac\x38\x50\x29\ -\x8d\x8f\xe3\x6e\x6e\x92\x27\x29\x73\x3b\x76\xb0\xb4\x78\x8b\x5e\ -\x7b\x93\xd9\xc9\x09\x6c\x4d\xc5\x96\x65\x76\x8e\xeb\x94\x54\xb8\ -\xb9\xd4\x25\x95\x13\xce\x5c\xb9\xc4\xd4\xec\x0c\x8d\x6a\x8d\xb2\ -\xaa\x92\xdb\x36\xde\x20\xe0\xcc\x99\xf3\xec\xbe\xeb\x6e\x4a\x33\ -\x36\xc7\xee\x39\xca\xc2\x0b\xc7\x89\xdb\x1b\x54\x95\x0c\x5b\x55\ -\xb9\xfb\xc0\x7e\x7e\xea\x27\x3e\xc2\xb8\x05\xeb\xd7\x97\x98\x9b\ -\x68\xa2\x24\xd0\xeb\xb8\xe8\xcd\x12\x86\xae\x30\x3e\xde\xc4\xb0\ -\x34\x24\x55\xe1\x95\x13\x27\x58\x5e\x5b\xe6\xc1\x47\x1e\xe2\xec\ -\xa5\x05\x6a\xcd\x71\x3a\x81\x4f\x9e\x24\x3c\xfb\xe6\x69\x3e\xf8\ -\xe3\x1f\x66\x61\x75\x03\xbd\x54\x27\xd7\x55\xd6\xd7\x07\x78\xbd\ -\x2e\x4e\xb5\x4e\x10\x46\x44\xa1\x44\x7f\xd0\x1b\xb9\x57\x6c\x01\ -\x43\xf5\x7a\x1d\xd3\x94\x49\x53\x1d\xdb\xb6\xd1\x75\x91\xf1\xbb\ -\x35\xd3\x6d\x6e\x6e\x32\x3d\x31\x41\x1a\xc6\x98\xa6\xc9\x5a\x6b\ -\x03\x6d\x6c\x1c\xc5\x94\x51\x34\x83\x38\x87\xda\x58\x1d\x49\xd7\ -\x70\x2a\x65\x86\x9d\x9e\xf0\x19\xcf\x73\x0c\xa0\xaa\x69\xc4\xbd\ -\x1e\x8d\x89\x19\xfa\x7e\x88\xbd\x6d\x07\x9b\x2f\xbc\x40\xe5\xfe\ -\xfb\xb1\xec\x12\x76\xad\xc1\xe5\xeb\xb7\xf8\xad\x7f\xf6\xef\x50\ -\x54\x15\x59\xd3\x70\xbb\x03\x50\x22\xc8\x3a\x60\xda\x54\xc6\xc6\ -\x04\x27\xa0\x20\x81\x6c\xad\x3b\x55\x55\x25\x0c\x02\x91\xaa\x09\ -\xc8\x45\x8b\x9d\x17\xf6\x3c\x49\xc1\xf4\x52\x55\x15\xab\x24\xd8\ -\x53\xb1\x2c\xe6\xec\x34\x16\x79\x61\x68\x1a\x5a\xb1\x33\x4e\xd3\ -\x94\x3c\x08\x08\x5d\x97\xe8\x1d\x04\x0e\x45\x51\x88\x15\x45\x54\ -\xbc\x62\xdd\x25\xb0\x1d\x65\xb4\x57\xce\x0b\xc3\x81\x28\x0c\x05\ -\xa7\xbb\x98\xa3\x2d\xc7\xa1\x28\xd9\x18\xe5\xf2\xdb\x48\x7b\x71\ -\x41\x64\x59\x46\xe4\xfb\x04\xc5\x08\x60\xda\xe6\xe8\xb2\xd8\x62\ -\x9e\x65\x69\x8a\xa4\xa9\xc8\xb5\x1a\x6e\xaf\x4f\xa9\x3e\x46\xa7\ -\x3b\x40\xab\x37\xc8\x94\x88\x57\xcf\x9f\xe5\xb5\x2b\x57\xf8\x91\ -\xbd\x7b\xc9\xd2\x1c\x39\x13\x4d\xb4\xc8\x58\x96\xb6\xd2\x8b\x85\ -\xb8\xe9\x9d\x40\x97\x94\xff\xa0\x64\x22\xc7\x34\x4c\x24\x24\x74\ -\x5d\xff\x17\xa7\xaf\xde\xe2\xc6\xad\x05\xea\x63\x4d\x3e\xfd\x0b\ -\xbf\xc8\xd1\xa3\x47\xd9\x58\x5f\x41\xcf\x52\x82\x5e\x07\x29\x0e\ -\x09\xfd\x01\x90\xa1\x96\x1d\x64\x4d\x46\xd2\x44\x06\x4f\x1c\x47\ -\x10\x47\xa3\x5b\x4f\x51\x14\x54\xa5\x00\x17\x7a\x3d\x42\xdf\xa3\ -\x54\x2a\x09\x99\x57\xd1\xfa\x19\x05\x03\x27\x7f\xc7\x2e\x71\x6b\ -\x04\x50\x14\x85\x24\x8d\x40\xca\xb1\xab\x15\xf4\x8a\x83\x54\xc0\ -\xed\x5b\x8c\x1c\xb2\x1c\x45\x92\x71\xdb\x1b\x48\x85\x60\x7f\x7d\ -\x75\x0d\x45\x92\xa9\x55\xab\x5c\xbb\x7c\x85\xd9\x71\x9b\xb1\xb2\ -\xce\xda\xd2\x80\x20\x84\x72\xb9\xcc\xf2\xca\x22\xe3\xe3\x63\xa4\ -\x79\x82\xa3\xdb\x9c\xbf\x75\x13\x4d\x53\xf1\xbc\x80\xf9\xf9\xdd\ -\xac\x2e\xaf\x71\xed\xca\x26\xef\x7f\xe4\x01\xee\xd9\xb9\x93\xcd\ -\xd7\x5f\x67\xa7\x6e\xf0\x53\x3f\xf4\x08\x1f\x7d\xf8\xdd\xec\xa9\ -\xc0\x8d\x33\x17\x99\x2a\x3b\xd4\x2d\x85\x2c\x0e\x31\x0c\x9d\x4b\ -\x57\x6f\xb2\xef\xc8\x1d\x78\x52\x8c\xd6\xa8\x21\x95\x4c\x16\x36\ -\xd6\xf8\xf0\x27\x3e\xc6\x73\x2f\xbf\xc2\xe2\xe6\x06\x97\x17\x17\ -\xd8\xf4\x03\xdc\x0c\x4e\x9c\xbb\xc0\xd9\x6b\x37\x78\xf2\x85\x97\ -\xb8\xb1\xd6\xe2\x8d\xf3\xd7\x79\xfd\xcc\x59\x2e\x5c\xbc\xca\xf4\ -\xf6\x39\x14\x4d\xc7\x29\x8b\x15\x4b\xa9\x54\x42\xd7\xc5\xf7\xbe\ -\x95\x03\xdc\xeb\xf9\x85\xcc\x4f\x1a\xfd\x5c\x00\x26\x26\x26\xe8\ -\xf5\x7a\x64\x59\x8e\x63\x6b\x38\x96\x8d\xef\xfb\xc4\x71\xcc\xea\ -\x46\xc8\x8b\xc7\x5f\xc2\x1f\xf4\x59\x6b\x6d\xb2\xbc\xb8\x58\xd0\ -\x1b\x25\xda\xb7\x6e\xf2\xbe\x77\x3d\xc4\xef\xfc\xf6\x2f\xf1\x7b\ -\xff\xec\x9f\x50\xd6\x34\x16\xae\x5c\xa5\xd7\x6a\xd1\x6e\x77\x51\ -\xef\x3c\xc2\xd0\xf3\xe9\xf6\x06\x78\xee\x90\xb1\xe6\x04\xc3\x56\ -\x0b\xcd\x72\xb0\x2a\x75\xe4\x6a\x83\xd2\xe4\x24\x38\x55\x30\x6c\ -\xbc\x28\x26\x4b\xdf\x3e\xbc\x5b\x07\x3a\x2b\xb4\xc0\x5b\x9a\xe0\ -\xad\xc3\xb4\xd5\x32\x2b\xc5\xc7\xc6\x45\xfb\xbd\xd5\x92\xcb\xb2\ -\x3c\x62\x04\xf2\x8e\xef\xb9\x54\x2a\x09\x03\x83\x34\x25\xf7\xfd\ -\x51\xfb\xbd\x05\x68\xc9\xba\x2e\xa8\xbc\x79\x3e\x12\x64\x6c\x11\ -\x67\xb6\x56\x62\x64\x99\xb8\x20\x64\x19\xcf\xf3\x84\xc8\x25\x4d\ -\x47\x97\xc5\x56\x0b\x8e\xa4\x60\x18\xd6\xc8\xd4\x3e\x4b\x13\xe2\ -\x41\x7f\xb4\xb6\x92\x65\x19\xcd\xb2\xc4\xe5\x92\x65\x08\x82\x5a\ -\x8a\xae\x1a\x24\x51\x8a\xae\x8b\x8e\x41\x2d\x95\x18\xa4\x31\xdf\ -\x7a\xea\xbb\x04\xd0\x1e\xfd\x3c\x8a\x73\xaa\xaa\xca\xdb\xbb\x66\ -\x40\x15\x79\x19\x5b\x4c\xae\x4c\x30\xb3\xa5\x0c\x24\x09\x09\x99\ -\x0c\x99\x30\xcb\x08\xe2\xec\x37\x3f\xfb\xd9\xcf\x61\xea\x3a\x8f\ -\xbe\xf7\x11\x52\x7f\xc8\xea\xda\x2a\x77\xcc\xce\x30\xb9\xb3\xc4\ -\x53\x27\x43\xb2\x28\x22\x0a\x7d\x54\xab\x84\x53\x32\x89\xc2\x44\ -\xec\x9f\xe3\x18\x52\x41\xa9\x93\x0d\x19\x53\xb7\xc8\xa2\x90\x54\ -\xca\x60\x18\x82\xa1\x23\xcb\x3a\x81\x27\xe8\x70\x86\x55\x78\x78\ -\x05\x05\xfa\x9c\x24\x68\x8a\x8e\xae\x1b\xb8\xbe\x87\x92\x2b\x68\ -\x8a\x4e\x90\x67\x18\x86\x4e\xc3\x71\x88\xdd\x3e\xbd\x7e\x1b\x18\ -\x8a\x1c\x66\x80\x92\x8d\x8c\x8e\x6e\xda\x18\x99\x82\x94\xc9\xc4\ -\x61\x46\xd9\x32\x49\xa3\x21\x4b\x37\x6e\xd1\xdf\x08\xa8\x97\x4d\ -\xea\xf5\x32\x43\x3f\xe1\xdc\xf9\xd3\xec\x3f\x74\x00\x2f\x0f\xd8\ -\x3e\xb1\x83\x8e\xdb\x67\xdb\xec\x76\x96\x17\x57\x89\x92\x90\xb9\ -\xdd\x3b\x18\xcf\xe1\xc6\x5a\x9b\x37\x9e\x7f\x95\xd5\xf3\xa7\xb9\ -\x7b\xef\x2e\xfe\xc1\x8f\xbd\x9f\x1f\x7e\xd7\x41\x96\xd7\x3d\x36\ -\x17\xda\x4c\x39\x16\x3b\x27\x6a\x04\x6e\x48\xd5\x31\xd8\xdc\xec\ -\xb2\xbc\xb6\xca\xde\xc6\x01\x34\x43\xa7\xeb\x0e\x91\x65\xd8\xb5\ -\x67\x37\x71\x9e\x72\xf7\x7d\xf7\x91\xc9\x2a\x5f\xfe\xea\x37\x98\ -\xd8\xbe\x93\xe7\x8e\x9f\x60\xe7\xbe\xc3\xbc\x76\xee\x0a\x7f\xf9\ -\xf8\xf7\xd8\xbb\x6f\x2f\x86\x24\x91\x0d\x06\x6c\x6b\x8c\xf1\xd1\ -\x0f\xfd\x10\xc4\xe0\x0f\x53\x06\xdd\x9e\x48\x08\x8c\x21\x4b\xc5\ -\x0a\xb1\x54\xae\x20\xc9\x0a\x71\x22\x22\x50\x90\x73\x72\x29\x43\ -\x51\x54\x6a\x25\x85\x6e\xb7\xcd\x70\x38\xc0\xae\x56\xc8\xc8\x08\ -\xd3\x0c\xd5\x31\x70\xfb\x31\x97\x6f\xaf\xd0\xd8\x36\x07\x86\x43\ -\x96\x2b\xd8\x9a\x4c\xbb\xb5\xc2\xf6\xbd\x7b\xa8\x5b\x06\xe1\x10\ -\x6e\x5d\xbb\xcd\xcd\xeb\xd7\x71\xe6\xf7\x61\xd4\x9a\x0c\xba\x3d\ -\x54\x4d\xc6\xdf\xdc\xc4\x9a\x98\x46\xd5\x1d\x56\x5a\x1d\x28\xd5\ -\x70\xbd\x88\xb0\xe7\x81\xaa\x52\xa9\xd4\x70\x57\x37\x40\x51\x51\ -\xcd\x06\x0a\x39\x52\xae\x10\x87\x11\x49\x20\x98\x6a\xe8\xba\xc8\ -\x00\xb3\x6d\xfc\xe1\xf0\x6f\xb0\xd2\x54\x55\x28\xe9\x92\x30\x22\ -\x4d\x62\xfc\x6e\x17\xbd\x52\x41\xd7\x34\x51\xd5\x63\xb1\xb6\xa4\ -\x68\x8b\x35\x4d\x1b\xed\xcc\x4b\xcd\xa6\x58\x4d\xb9\x03\x42\x04\ -\x12\x1d\xc7\xf1\x88\x2f\x1d\x17\x33\xf3\x16\xd0\xb6\x75\x40\x15\ -\x45\x78\x8e\x51\xcc\xe0\xb1\xe7\xa1\x54\x2a\xa4\x69\x4a\xa5\x24\ -\x44\x28\xd9\x60\x20\x54\x7b\x85\x19\x81\xa2\x48\x42\x5f\x6f\x1a\ -\x0c\x3b\x1d\xc1\xe4\x2a\x46\x20\x10\x99\x5e\x14\xe3\x0e\xb9\x30\ -\x3d\x50\x25\x99\x24\x8b\x41\x92\x09\xc8\x71\xea\x4d\x5e\x3a\x71\ -\x12\xff\xd7\xf2\x7a\xaa\x68\xc8\x69\x22\xf8\xe8\x80\x51\xb8\x89\ -\x6c\xc1\x59\xf2\xdb\x98\x57\x01\xfb\xa5\x11\x79\x12\x0b\x10\x20\ -\x81\x14\x99\x38\x91\x7f\xb5\xdd\xf1\xb9\x78\xfe\x12\xf7\x1e\x3a\ -\xc2\x63\x1f\xfa\x20\xfe\xfa\x22\x63\xa6\xca\x78\xb3\x84\xeb\xc2\ -\x95\x8b\x57\x08\x3c\x9f\x2c\x8d\xa8\x8f\x95\x18\x46\x43\xfc\x70\ -\x88\x61\x68\xd0\xee\x61\x4a\x06\x72\x24\x31\xe5\xd4\x49\x86\xa1\ -\x10\x74\xcb\x2a\x24\x12\x0d\xa3\x82\x91\xc8\xe8\x52\xc1\xf4\xca\ -\x20\x97\x14\xc2\xf5\x0d\xe4\x5a\x1d\xd5\x2a\xa1\xa1\xe0\x6e\x74\ -\x69\x5a\x15\xde\x77\xec\x5d\xb8\x8b\xeb\xdc\x7b\xc7\x9d\xdc\x79\ -\xe4\x2e\x7e\xfe\xe7\x3e\xca\xaf\x7c\xf8\x63\xfc\xde\x3f\xfa\xef\ -\xb8\x67\x7a\x9a\x12\x09\x04\x9b\xa8\x63\x36\xb1\x94\xe1\xfb\x21\ -\x52\xa6\xa1\xa6\x1a\xfb\xb6\xef\xe3\x13\x1f\xfe\x04\x55\xdd\x62\ -\x6e\x7a\x06\xaf\xdf\x61\x61\xf1\x26\x8a\x0e\x67\x2f\x9e\x67\x6c\ -\x72\x0a\xcb\x71\xd0\x30\x19\xf6\x03\xaa\x76\x85\x6b\x97\x6f\xd0\ -\x1f\x7a\x6c\x9b\xdf\x01\x4a\x4e\xd9\x81\x1d\x13\x15\xc6\xd4\x94\ -\xfb\xf7\xee\xe4\xde\xf9\x19\xee\xde\x39\x4b\xbf\xe5\xb2\xad\x62\ -\xb3\x71\xfb\x06\x07\x76\xed\x64\xa3\xd5\xc1\x71\x0c\x36\xbb\x2e\ -\x97\xaf\x5d\xe7\x5d\xef\x7e\x10\x55\x52\x09\x87\x21\x8e\x66\x70\ -\xe5\xfc\x5b\xcc\xce\xce\x52\xb2\x75\x74\x45\x25\x8f\xe0\x8e\xdd\ -\x87\x79\xf0\xd8\x3d\xcc\xce\xee\xe5\x95\xd7\xce\xf1\x17\x8f\x7f\ -\x0f\x7b\x76\x9e\x35\x2f\x61\xd5\x0b\xf1\x24\x8d\xab\xb7\x97\xb9\ -\x74\x75\x93\x24\x81\x28\x08\xc8\xe2\x88\x99\x89\x69\xdc\x7e\x40\ -\xbd\x62\x91\x66\x2a\x43\x3f\x45\x56\x75\x52\x49\x42\xb3\x75\x82\ -\x38\xc0\x74\x74\x90\x53\xdc\x30\x26\x4d\x63\x2a\x55\x9b\x84\x08\ -\x2f\xf5\x88\x35\x99\xc4\x84\x13\x17\x6f\x61\x8c\xed\xa4\x1f\x28\ -\x78\xc3\x84\x3c\x08\xe8\x2d\xdc\xc4\x32\x24\x36\xae\x9d\xa7\xb3\ -\x7a\x93\xd6\x7a\x9b\x7b\xee\xdb\x41\x79\x76\x3b\xc3\x8d\x2e\x1e\ -\x32\x92\x53\xc6\xa8\x36\x40\xb7\x68\xad\xb7\x49\x65\x1d\xd5\x28\ -\x61\x56\xc6\x84\x7b\x6a\x94\x60\x2a\x06\xc3\x4e\x0f\xb3\x56\x45\ -\xd2\x74\x82\x7e\x8f\x70\xe8\x92\xc6\xc9\x3b\x6c\x9b\x65\x14\x4d\ -\x1f\xed\x71\x0d\xcb\x22\x4f\x53\x42\xdf\x23\x4a\x13\xf2\x82\x98\ -\x24\xa9\x8a\x10\xfa\xcb\x2a\x29\x12\x41\x18\x43\x9c\x82\x5d\xc2\ -\x6e\x4e\x08\xbd\x71\xbb\x4d\xe8\x79\x48\x45\x3c\x4b\x9e\x24\xa8\ -\x92\x84\x61\x9b\x48\xb2\x44\xd8\xeb\x16\xc1\x80\x42\x9d\x54\x19\ -\x6b\x60\x54\xca\xa4\x81\xcf\xb0\xdf\x23\x4a\x13\x54\x43\xc7\x8f\ -\x42\xf1\xc5\x59\x26\x79\x12\x83\xaa\xd0\xe9\xf7\xd0\x2d\x13\x2f\ -\xf0\x05\x0b\xac\x5e\x13\x1d\xa7\x9c\x93\xe6\x82\x59\x96\x64\x29\ -\x59\x96\xa2\xda\x16\xbd\x9e\xc8\x37\xf3\x3c\x8f\x34\x4d\x69\x8c\ -\x37\x90\x0d\x03\x49\xb7\xa0\xd3\xa7\x6c\x97\x30\x75\x03\xcd\xd2\ -\x44\xa2\x9a\xa2\x30\xbd\x73\x8e\x30\x94\xf9\xe2\x7f\xf9\x26\x1e\ -\xe0\xeb\x2a\xbd\x34\x21\x95\xc1\x48\xc1\xf6\x03\xb4\xf4\x9d\x7a\ -\xe4\xfc\x6d\x26\xd7\xc8\xde\x4b\x82\x54\x92\xf1\xc2\x0c\x55\xe7\ -\x73\xa7\xcf\x9e\x63\xd0\x1f\xf2\xd8\x4f\x7e\x9c\xaa\x25\xb3\x72\ -\xe3\x2a\xbb\xb6\x4f\xa3\xcb\x20\xa7\x50\xb5\x4b\xc2\xb9\x72\x6a\ -\x92\x5e\xaf\x47\x9a\x27\x82\xc6\x26\x2b\x60\x39\xd4\xcb\x55\xaa\ -\x4e\x05\x55\x16\xce\x98\x03\xdf\x63\x18\x0e\xc1\x73\xf1\xfd\x21\ -\x96\x63\x93\xcb\x39\x5e\xe4\x13\x79\x2e\x51\x9e\xc2\xf8\x18\xf5\ -\x66\x9d\xc4\x1d\xd0\xef\xf7\xa9\x57\xaa\xb4\x5b\x1b\xbc\xf6\xca\ -\xab\x10\x46\x5c\xbf\x7a\x8d\x97\x8f\xbf\xc4\xe7\xfe\xfd\x9f\x12\ -\xb4\x37\xb9\x7f\x8f\xc2\xc3\xf7\x1e\xa1\x59\x31\xa9\xcc\xcd\x92\ -\xb4\x56\x41\x53\x71\xaa\x35\xd2\x34\x65\x6d\x6d\x8d\xb3\x17\xce\ -\xf2\xc2\x4b\xcf\x53\xa9\x94\x78\xec\xb1\x1f\x63\xe7\xdc\x34\x59\ -\x96\xf2\xfa\xc9\x53\xec\xdb\xbf\x9f\xfd\x7b\x66\x89\xc2\x14\x55\ -\x52\x29\x59\x26\xab\x4b\x1b\xc4\x51\xca\xfc\xae\x5d\x18\xa6\x41\ -\x9a\x26\xc4\x61\xf6\x7f\x52\xf5\xe6\xc1\x9a\x9d\x77\x9d\xdf\xe7\ -\xec\xeb\xbb\xde\x7d\xef\xee\xdb\xfb\x2e\xf5\x22\x4b\xb2\x16\xcb\ -\xb2\x85\x8d\x6d\xbc\x01\x06\x62\x13\x96\x30\x15\x86\x30\x49\x85\ -\x54\x91\x64\x60\xa0\x6a\x6a\x42\x2a\xc9\x54\x66\x6a\x52\x35\x19\ -\x32\x03\x99\x29\xa0\x02\x18\x8c\xc1\x63\xc0\xb2\x64\x49\xb6\x24\ -\xcb\xad\xb5\xf7\xee\xdb\xf7\x76\xdf\x7d\x79\xf7\xed\xec\xe7\xe4\ -\x8f\xe7\xdc\x57\xcd\x1f\x5d\x5d\xbd\xde\xee\x7b\xcf\x73\x9e\xdf\ -\xf2\xfd\x7e\xbe\xb4\x76\xb7\xb8\x74\xe6\x24\x3f\xf7\xa5\xcf\xf3\ -\x99\xe7\x9e\x65\x77\x75\x05\x47\x96\x79\xe5\x3b\x2f\xf2\xc8\xa9\ -\xd3\xa4\x61\xc2\x58\xb5\x82\xa2\xc0\xda\xfa\x3a\x85\x62\x11\xdf\ -\x4f\x98\x1f\x73\xa9\x14\x4d\x9a\xbb\x35\x34\x45\xa5\x5c\x2a\xd0\ -\x1b\x84\x84\x7e\xc4\xda\xf2\x03\xe6\xa6\xa6\x71\x0d\x98\x9d\x9a\ -\xa6\xe4\x96\xb0\x9d\x02\x49\x9c\x62\xb9\x0e\x29\x19\x3b\xbb\xbb\ -\xcc\xcc\xcc\x70\xfd\xfa\x75\x6e\xdc\xb8\xc3\xee\xee\x0e\xab\xab\ -\xab\x74\x7a\x5d\x32\x64\x92\x0c\xc2\x30\x26\xf0\x23\xb1\xe6\x09\ -\xc3\x7c\x68\xd4\x27\x49\x63\x3c\x5f\x3c\x48\xd3\x93\x93\x24\x51\ -\x4c\xb3\xdd\x22\x96\x32\x24\xc3\xe4\xbd\x9b\x35\xae\xdf\x5b\xa5\ -\xe3\xa7\xc4\x91\x84\xbf\x53\x13\xa1\x7c\x91\xcf\xe1\x85\x69\x62\ -\xbf\x87\x22\x67\x9c\x38\x56\xe5\xad\xf7\x37\x71\x4a\x45\x18\x1d\ -\x23\x49\x85\x84\xb7\x33\xf0\x70\xa7\xe6\x50\x9c\x02\x5e\x10\x32\ -\xf0\x03\x2c\xcb\xc1\xb0\x5d\x14\xdd\x12\xb8\xa1\x38\x41\x4a\x84\ -\x56\x58\xc9\x24\xa2\x20\x24\x0a\x44\x29\xab\x5a\x36\x52\xae\xa8\ -\xda\xb7\x64\x2a\x8a\x82\x6e\x8a\xc8\xd4\x28\x0c\x09\xc2\x50\x94\ -\xbb\xfb\x93\x65\xd3\x20\x69\xf7\x88\xfb\x3d\x64\xc7\x1e\x46\x0f\ -\x65\x59\x86\x39\x3e\x2e\x6e\xd0\xbc\x04\xcf\xb2\x0c\x4d\x15\x06\ -\x9e\xfd\xa8\x96\xc4\xf7\x45\x2c\x6b\x3e\x04\x8b\xa2\x08\xc9\xb2\ -\x90\xf2\x41\x6c\x92\x24\xc4\x9d\x0e\x04\x01\x76\xb9\x8c\x53\xa9\ -\x40\x1c\x93\x76\xbb\xc3\x7e\x5a\x55\x55\xa1\x5f\xcf\x0d\x17\xfb\ -\x53\xf4\x7d\x5b\xe3\x7e\x6b\xb3\x3f\x8d\xf7\x7d\x7f\x38\x88\x15\ -\xed\x63\x4a\xdf\xf7\x88\xd3\x48\x60\x91\x75\x9d\x30\x49\x19\x04\ -\x19\xdd\x20\xe1\xf5\xb7\x3f\xa0\x91\x90\xf9\x70\x48\xd5\x54\xc2\ -\x24\x82\xc8\x17\x67\x2b\xdb\x67\x76\x3d\xb4\x84\xca\x1e\xfa\x96\ -\x48\x39\x08\x4c\xe6\x57\x54\xf8\x77\xaf\xbd\xfe\x03\x4a\xa3\x55\ -\x2e\x3c\x7a\x98\xf7\x6e\x3d\x40\x96\xe1\xc0\xb8\x85\x1f\xc0\xf5\ -\x3b\xf7\x79\xe2\xc2\x05\x56\x6a\x35\xbc\x28\x26\x8b\x62\x4a\xa3\ -\x63\xb4\x36\x77\xf1\xbd\x2e\x74\x07\x74\xca\xe2\x1f\x8f\x37\xc0\ -\x8f\x42\x64\x43\x05\x4b\xa1\x70\x64\x8e\x6e\xb7\x8d\x6c\x24\x04\ -\x69\x84\x6e\x99\xc4\x69\x8f\x34\xea\x83\xa6\xd3\xea\x75\xc0\x31\ -\xc9\x92\x94\x41\x1a\x12\x4a\x09\x0d\xaf\x43\x71\x61\x9a\x7a\xb7\ -\x81\x2a\x25\x58\x9a\xc9\x5f\xfd\xcd\xd7\x19\x2d\xff\x34\x8d\xe6\ -\x2e\x8f\x9d\x3f\xcb\x4b\x37\xaf\xe3\x29\x0a\x59\xa7\xcd\xc8\x68\ -\x89\xd5\x8d\x6d\xc8\x7c\xa6\x8e\xce\x70\xe3\xc1\x35\x0e\xcf\x4e\ -\x62\xb9\x50\x00\xde\xdb\xd8\x60\x6a\x6a\x0a\xc3\x30\x78\xf7\xea\ -\x12\x97\xcf\x1c\x66\x79\xab\x3b\x54\x4b\x09\x3d\x33\x44\x91\xf0\ -\x9d\x76\x3a\x1d\xba\xdd\x2e\xb3\xb3\xb3\x58\x96\x44\x21\x1f\x76\ -\xac\xae\xae\x32\x3b\x3b\xfb\x90\x2b\x06\x6e\xde\x5c\x06\x60\x62\ -\x62\x02\x4d\x53\x58\xda\x68\x60\xdb\x36\x2b\x2b\x2b\x5c\xbc\xf4\ -\x28\x51\x20\xa6\xf1\x8e\xe1\xe0\xf7\xda\x1c\x3e\xbc\x40\x18\xc2\ -\xe9\xc3\x07\xd9\xda\x3b\xc5\xee\x8b\x1b\xa4\xba\xc4\x88\xa5\x32\ -\xbb\x70\x14\xf3\xf0\x41\x7e\xed\xbf\xfc\x2a\x85\x0c\x5c\x0d\xee\ -\xaf\xdc\x63\xaf\xdb\xa0\x54\xdf\x65\x79\x7d\x1d\x09\x8d\x95\x07\ -\x6b\xd8\xa6\x49\xe0\x75\xe9\xf5\x5b\xf4\xfa\x6d\x3a\xad\x26\x7e\ -\xaf\xcf\xa0\xdb\xc3\xd0\x4c\x56\x57\xd7\x09\xfd\x08\x59\xcd\x90\ -\x8b\x15\x5a\xbd\x98\xef\xbd\xfe\x3d\xde\xbd\xbd\x46\x6a\x15\xb0\ -\xcb\x65\x06\xc4\xf4\x7d\x8f\xc3\xf3\x0b\xd4\xeb\x1b\x1c\x38\x7e\ -\x04\xbd\x60\x12\x02\xaf\xfe\xe0\x55\xc2\xc8\x87\x41\x4c\x24\x8b\ -\xd0\xf2\x76\xb3\x4e\x2c\x29\x24\xf5\x3d\x30\x0c\x26\x66\xe7\xf2\ -\x08\x53\x21\xfc\x8f\xa2\x80\x34\xdd\x37\x28\x64\x22\x52\x34\x8e\ -\x48\x25\x09\x39\x0f\xea\x4b\x12\xa1\x13\x4f\xe2\x98\x2c\x77\x31\ -\xe9\xba\x2e\x24\xc7\x9e\x47\x9c\x65\x68\xb9\xdc\x32\xdb\xef\x85\ -\xd3\x08\x89\x3f\xe4\x99\x00\x00\x20\x00\x49\x44\x41\x54\x12\x11\ -\x20\xb8\x2f\xd2\x90\x65\x19\xdb\xb6\x69\x47\x21\x49\x20\x12\x26\ -\x14\x45\x11\x9b\x90\x0f\x8d\x04\xa2\x9b\xcc\x57\xa2\xfb\xeb\xa9\ -\x87\xd7\x9d\xfd\x4e\x27\xcf\x79\x52\x86\xab\x24\xad\x50\x20\xca\ -\xd3\x42\x25\xbb\x30\x1c\x8a\x89\xf5\x98\x32\xe4\x81\x09\x3d\xf8\ -\x43\x1f\x4f\xd3\xf2\x72\x3a\x21\xd0\x15\xf4\xdc\x4f\xe0\xcb\xe0\ -\x05\x1e\x8a\x9a\x61\xa8\x16\xe8\x26\x51\x94\xd2\x8f\x7d\xec\x72\ -\x85\x9b\x2b\xf7\xd9\x69\x0d\x28\x8d\xd8\x87\x80\x65\x29\x93\x45\ -\x61\x9d\x25\x43\x5f\xb3\x9a\x49\xff\x30\xfb\x2d\xcb\x03\xca\x13\ -\x29\x27\x12\x68\xf2\x72\x33\x48\xb3\xf7\xaf\x5d\xe5\xe7\xbe\xf6\ -\x73\xdc\xdf\xa8\xd3\x68\xd4\x98\x5f\x98\x21\x01\xba\xcd\x88\xa8\ -\xef\xf1\xf4\x47\xce\xf1\xad\xd7\x7e\x40\xab\xdb\xc3\x2d\x96\x45\ -\x7f\x1c\xa7\x38\xb3\x0b\xf4\x5b\x6d\xac\xa2\x8b\xd7\x1f\x10\x92\ -\x82\x26\x23\xe9\x32\xa6\xae\xd0\x6d\xee\x41\x1c\x20\x6b\x2e\xf1\ -\xde\x1e\x71\x6c\x81\x2e\x76\x6e\xba\x26\xe1\x68\x1a\x46\x69\x94\ -\xed\xb5\x75\xfa\xeb\x2b\xa8\x13\x13\x24\x59\x8a\x66\xab\x94\x14\ -\x0b\x3a\x6d\x0e\x4e\x8e\xd0\xea\x37\xb8\x71\xfd\x1d\xa6\x0e\x4c\ -\x23\xc5\x3e\x63\x48\x58\xba\xc9\xd6\x6e\x93\xd5\xad\xf7\x90\x6d\ -\x97\xd1\xf9\x71\x6a\xad\x2d\x0e\x9d\x38\x44\x6b\xf3\x3e\x0f\xd6\ -\x6a\xf4\x07\x03\x4e\x9f\x3e\x8d\xae\xeb\xbc\xf7\xde\x7b\x4c\x4c\ -\x4c\xb0\xbc\xd5\xc2\x34\x4d\xd6\xd7\xd7\x29\x14\x0a\x4c\x4c\x4c\ -\x10\x86\xb1\x88\x27\xc9\x39\xc9\xb3\xb3\xb3\xa8\xaa\xc4\xde\x5e\ -\x77\xa8\xe9\xbd\x7e\xfd\x3a\x4f\x3e\xf9\x24\xb7\x6f\xdf\x66\x6e\ -\x6e\x0e\xc7\x71\xf0\x3c\x8f\xc5\xc5\x45\x6c\xdb\x24\x4d\x19\x0e\ -\x72\x8a\xc5\x22\xb6\x6d\x52\xab\xd5\xa8\x54\x2a\xf4\x9a\x2d\x0a\ -\xb6\x8e\x6b\x40\xa3\x9b\x71\x60\x42\xe2\xfc\x91\x05\x8a\xa5\xcf\ -\x72\xe0\xc4\x51\x1c\xc7\xa2\x60\x69\x5c\xff\xe1\x3b\xd8\x32\xd8\ -\x92\x80\xb3\x4d\xcc\x4e\x72\x34\x3c\xc9\xa5\x73\x67\xe8\xf4\xc5\ -\x45\x33\x3e\x39\x4d\xc1\xb1\x70\x6c\x13\xd2\x10\xcf\x13\xd9\x58\ -\x73\x73\x73\x79\x60\x3c\xa8\x8a\xc9\xe1\xa3\x47\xd1\x5c\x0b\x4f\ -\x56\x50\xdb\x31\x2f\x5d\x7b\x80\xe5\xb8\x48\x85\x32\x71\xa6\x80\ -\x61\x52\x2d\x94\xe9\x78\x7d\x26\x67\xa6\x58\x5c\x98\xe3\xc8\xd1\ -\xa3\x34\xda\x29\xb7\x6e\x5f\xa7\x32\x39\x47\xa2\x69\xb4\xeb\x6d\ -\x12\xdb\xc4\xb5\x2c\x0c\x43\x43\x1a\x1f\x13\x8c\x72\x6f\x30\x1c\ -\x1c\xed\xaf\x72\xf6\xd7\x4b\xa2\xef\xcd\xe5\x96\xb9\x5b\x0b\x59\ -\x42\x41\x41\x33\xf4\xe1\xc0\x72\x5f\x7b\xad\xc9\x0a\xb1\xa6\x41\ -\x14\xe3\x0d\x06\x68\x39\x75\x86\x28\x01\xd7\x85\x54\xc4\xbc\x84\ -\x61\x98\x0b\x5c\x84\xfa\x4a\x51\x14\x81\xb3\x7d\x48\xbf\xb0\x7f\ -\x3b\x2b\xba\x25\xb2\x90\x7d\x9f\x38\x0c\xb1\x72\xb1\x49\x10\x08\ -\xb5\x97\x61\x18\x04\xbd\x9e\x38\x80\xf9\x54\x7a\x7f\x9b\xa2\xaa\ -\x2a\x5e\xbf\x4f\x18\x8a\xdd\x79\x26\xbe\xb8\x48\xaa\xb0\x3c\xee\ -\xf7\xf5\xfb\x93\xf0\x34\x4d\xc1\x34\xc5\x5a\x2d\xff\x37\x48\x19\ -\x68\xa9\x30\x60\x64\x52\x8a\x97\xc4\xc8\x89\x01\x86\x45\xe6\x0f\ -\xe8\xc5\x01\x95\x91\x31\xda\xed\x36\xef\xdf\xb8\xcd\xe2\x53\x8f\ -\xfc\xca\x20\x4c\x7e\xa5\xaa\x2b\x3f\x85\x9c\x89\xfd\xbd\x2a\x0e\ -\xb2\x9c\xee\xdf\xbe\xd2\x43\x37\xb2\xb4\x5f\x5a\x43\x08\xdf\xf9\ -\xc1\x0f\xdf\x64\x10\x79\x7c\xe2\x53\x9f\x64\x79\xe5\x1e\xc7\x4f\ -\x1c\xc1\x75\x0c\xee\xdf\xdf\x62\x77\x7d\x9d\xf3\xa7\x4f\x60\x69\ -\xe0\x75\x3b\x94\xec\x22\x41\xcf\xa7\xbf\x53\x43\x1b\x9d\x20\x4a\ -\x32\x08\x23\x6a\xad\x26\xfd\x6e\x93\x7e\xa7\x05\x51\x9f\x24\xf6\ -\x48\x92\x90\xd2\x88\x83\x64\x4a\x04\x83\x26\xf8\x6d\x54\x29\x65\ -\xb4\x54\xc0\x96\x13\xc2\xc6\x2e\x0c\x7a\xec\x2c\x2f\x41\xbf\x03\ -\x9a\xcc\x58\xd9\x45\x57\x33\xba\xed\x1a\x1a\x31\x85\x2c\x66\x44\ -\x97\x79\xfe\x89\xcb\xfc\x57\x5f\xfb\x2c\x5a\x14\x30\xaa\x6a\x3c\ -\xb9\x78\x84\xa7\x0f\x1f\xc3\xe9\x0d\xa8\x48\x19\x27\x0f\x4e\xe3\ -\x6a\x09\x91\xd7\x22\xf4\x5a\xfc\xe6\x7f\xf7\xeb\x14\x5d\x43\x3c\ -\xec\xb9\x7a\xec\xec\xd9\xb3\x44\x51\x44\xb3\xd9\xc4\xf3\x3c\x01\ -\x6b\x33\xcd\x9c\x3c\xa3\x10\x04\xa1\xf0\x42\x47\x11\xd5\x6a\x31\ -\x3f\x90\x05\xca\x65\x93\x7b\xf7\xee\xf1\xdc\x73\xcf\x61\xdb\x36\ -\x17\x2f\x5e\x24\x08\x02\x36\x36\x36\xe8\xf5\x7a\x62\x52\xa9\x09\ -\x6a\xc7\xfc\xdc\x28\xf7\xef\xdf\xe7\xc0\x81\x03\xf4\xfb\x9e\x10\ -\x27\xa8\x32\x37\x6f\x5c\xa3\xe4\xda\x18\x32\x94\x2d\x09\xc5\x07\ -\x06\x4d\x3e\x76\xe9\x1c\x87\xc7\x8a\x4c\xd8\x2a\xca\xa0\xcf\xe1\ -\x99\x71\x0a\x06\x24\x7e\x48\xb3\xd1\x62\xb7\xb1\x47\x63\xd0\xa6\ -\x15\x26\x04\x69\x48\x26\x41\xbf\xdb\x16\xfe\xef\x4c\x42\x45\x26\ -\x09\x13\x0c\xcd\xc4\x1f\x04\x18\x86\x85\x22\x6b\x34\x9b\x1d\xec\ -\x82\x4b\xa2\x2b\xdc\x59\xdf\xe1\xea\x9d\x65\xd6\xb6\x77\x91\x75\ -\x83\x44\x92\x69\xf7\x3a\x30\xe8\x53\x6b\x37\xb1\x4a\x05\x6e\xdf\ -\x5f\xe6\x33\x5f\xf8\x38\x51\x1a\xd1\x6c\xd6\x71\x5d\x9b\x24\xf6\ -\xb1\x54\x19\xfc\x01\xf1\xa0\x47\xc9\x31\xe9\xb7\x5a\x18\x39\xf1\ -\xa3\xbd\xbd\x89\x61\xea\x68\xba\xc0\x42\x21\xa5\x64\x71\x40\x9c\ -\x84\x64\x72\x86\xa2\xab\x62\xd0\x69\x99\x64\x12\x0c\x02\x9f\x38\ -\x15\x25\xa7\xa6\x69\x64\xb9\xe9\x60\x7f\xe0\xe4\x5a\x36\x8a\xa2\ -\x82\xe7\x13\xf5\x07\x64\xb1\xb0\x05\x5a\xa6\x85\x69\x59\xf9\x64\ -\xd9\xcf\xc9\x73\x0c\x35\xd3\x92\xa6\x0d\x85\x23\x9e\x1f\x12\x07\ -\x11\xe4\x4e\x25\x5d\xd7\xc5\xcb\xe4\x21\x10\xc1\xc3\x56\x48\xc5\ -\x34\x85\xaa\xcc\x13\x58\x22\x3d\xcf\xee\x8e\xe3\x98\x42\xa9\x94\ -\xe7\x34\x45\x02\x46\x90\x3b\xb2\x74\x5d\x17\x2f\xa6\xfd\xc3\x9c\ -\x07\x12\xea\x79\x29\xad\x1a\x06\x69\x1c\xe3\x0f\x3c\x82\x5e\x1b\ -\xcd\xd2\xd1\x1d\x03\x48\xf1\x83\x08\x59\xd1\x21\x53\x49\x52\x05\ -\x5f\x56\xe9\xa6\xf0\xad\x97\x5f\xa1\x93\xf2\x93\x51\x10\xff\xa4\ -\x9c\x53\xf6\xd0\xd5\xa1\xc1\x49\x7e\x58\x0a\x92\x4a\xf2\xf0\x17\ -\x32\x31\xb1\x7e\x3e\x06\xbe\xfe\xcd\x6f\x70\xec\xd4\x49\xde\xbf\ -\x7a\x95\xa9\xa9\x09\x26\x2b\x45\x22\x6f\x40\xa7\xb1\x87\x6d\x9b\ -\x8c\x8f\xc1\xf6\xc6\x40\x0c\x6c\x92\x94\xc1\xfa\x06\x66\xa9\x8c\ -\x6d\x58\x1f\xae\x12\x00\xd5\xb6\xb0\x0a\x16\x95\xc9\x51\xc6\x27\ -\x46\x99\x9b\x1c\xe1\xd8\xec\x24\x4e\x12\x42\xbb\xc1\xb1\x23\x8b\ -\x1c\x1b\x1b\x81\xfa\x1e\x72\xa3\xce\xd9\x99\x69\x4e\x4f\x4f\x32\ -\x69\xe9\x1c\x9e\x9a\xa2\xe2\x18\x74\x77\x37\xd1\x92\x00\x47\x85\ -\xb4\xd7\xe1\x53\x4f\x3e\xc1\xc9\xe9\x49\xbe\xf0\xc2\xe3\x68\x11\ -\x3c\x73\xe1\x12\xb3\x85\x12\x5f\x7e\xfe\x19\xe6\x8b\x25\x7e\xf9\ -\xa7\x7f\x8a\x7f\xf3\x7b\xff\x33\xff\xf8\xe7\xbf\xcc\xfc\x48\x89\ -\x67\x1f\x3d\xc7\x42\xa9\x48\x45\x91\xe8\xee\x6c\x33\x52\x2a\xe6\ -\x3b\x57\xa1\xd7\x9d\x9c\x9c\xc4\x34\x4d\xde\x78\xe3\x0d\x5c\xd7\ -\x65\x64\xa4\x44\xaf\x27\x14\x46\x8d\x46\x83\x38\x8e\x99\x9a\x9a\ -\x12\x0a\xaa\x4e\x9f\x28\x8a\xb9\x75\xeb\x3e\x69\x9a\x32\x37\xea\ -\xe4\x15\x94\x10\x1e\xec\xe4\xb1\x25\xad\x56\x8b\x3b\x77\x1e\x10\ -\x45\x11\xbb\x7b\x3d\xda\xed\x36\x96\x65\x51\x2e\xe5\xe5\x64\x98\ -\x90\x44\x31\x93\xe3\xa3\x64\x51\x86\x92\x24\xb4\x77\xb7\xd1\x22\ -\x8f\x8a\x96\xa1\x78\x7d\xe6\x35\x89\xc6\xfa\x2a\x6a\x18\x12\x74\ -\x7d\xfa\xed\x36\xd3\x13\x65\x46\xc7\xc7\x18\x1b\x1f\x27\x21\x13\ -\xfb\x51\x1d\x5a\x8d\x26\xa6\xaa\x51\x2a\xaa\xd8\x86\x49\xe4\x07\ -\xc8\x19\xc4\x71\x8a\xac\x80\x66\xa9\xc8\x86\x89\x64\x43\x0f\xb8\ -\xf6\x60\x83\x57\x7e\xf4\x23\x56\xb7\x77\x51\x0c\x13\xc7\x2d\x52\ -\x1a\xa9\x52\x3a\x78\x08\x64\x58\xdf\xde\xe1\xd0\xe2\x11\xca\x32\ -\xb4\xda\x0d\x26\xc7\x47\x19\x29\xd8\xa8\x51\x84\x92\xf8\x48\x9a\ -\x42\xec\xf5\x88\xfa\x5d\xfc\x6e\x13\x5d\x96\xa8\x56\xcb\x98\xc5\ -\x12\x41\xe0\xe1\x05\x03\x31\xf5\xcd\x65\xb9\xfb\x0f\x7c\xa1\x58\ -\x44\xb7\x4c\x34\x4d\x13\x41\x6d\x41\x40\x10\x47\xa0\xc8\x43\x2e\ -\xd6\x7e\x99\x9a\x25\x29\xaa\x2c\x6e\x3b\x21\x73\x10\xa5\xb0\xa6\ -\x7d\x18\x62\xa0\xd9\x36\xb2\x61\x0c\x6f\xc9\x7d\xc0\xc0\x3e\x54\ -\x3e\x4d\x53\xd2\x28\x12\x37\xa7\xfc\x61\x19\x6e\xd8\x36\x18\x06\ -\x59\xae\xc8\xda\x87\x5f\x04\xbe\x4f\xe2\xfb\xa2\xb4\xd6\xf5\xe1\ -\x6d\xbe\xdf\xbb\xef\xab\xd1\xf6\x15\x67\xfb\x1e\xea\x87\xfb\xe2\ -\xe1\xf3\x9f\xf7\xd3\x43\x1a\x89\x24\x91\xc5\x21\x91\x37\xc0\xd4\ -\x55\x14\x53\x05\x5d\x23\x49\x13\x32\xc1\x31\x46\xd5\x6d\x22\xc5\ -\x20\x54\x35\xae\xde\x59\xe2\xfe\x5a\x1d\xc7\x31\x24\x80\xee\xc0\ -\x43\xd2\xd4\xe1\x78\xeb\x1f\x08\x42\xe4\x0c\xb2\x4c\x16\x8e\x47\ -\x49\x26\x43\x3a\xb4\x57\xaf\xb3\xb6\xb5\xcd\x67\x3f\xff\x05\xd6\ -\xd7\xd7\xb9\x74\xe1\x11\x3a\xdd\x1e\xed\xbd\x1a\xc7\x17\x0e\x31\ -\x3e\x3a\x45\xb3\x2f\x3c\x97\x41\x10\x30\x88\x52\xd0\x74\x26\x47\ -\xc7\xd8\xd8\x6d\xa0\x1b\x16\xb1\x2c\xa1\xa4\x31\x4a\x06\x69\x12\ -\x20\x6b\x16\x8a\x14\xe3\xa8\x26\x46\x73\xc0\x23\x63\xa3\x58\xb6\ -\xcb\x85\x0b\x17\xb8\x79\xf3\x36\x61\x6f\xc0\xd4\xc4\x34\x5f\x7c\ -\xe1\xd3\x14\xdd\x12\xbd\x27\x7b\xec\x36\x1a\xbc\xf6\xc3\x37\xb8\ -\xbb\xb6\x4a\x14\xa5\x18\xa6\x86\xa1\xca\xcc\x96\x0a\x7c\xf2\xe2\ -\x49\xe8\x08\xa9\xec\x5c\x51\x63\xf2\xfc\x31\x56\x77\x7d\x8a\xa6\ -\x85\x53\xac\x12\xf4\x22\x24\x32\x0e\x16\xca\xcc\xce\x8d\xf3\xa9\ -\xcb\x47\x79\xf1\xe5\x37\xf8\xf4\xb3\x8f\x63\x24\x90\x78\x31\x8a\ -\xa2\xd2\xed\x76\x71\x5d\x97\x3b\x77\xee\xf0\xdc\x73\xcf\xb1\xb4\ -\xb4\x84\xeb\xba\x64\x59\x46\xb7\xdb\x05\x60\x7e\x7e\x9e\x4a\x51\ -\xa3\xe7\x89\x1d\xa5\xaa\xaa\xf4\xfb\x7d\x4e\x9d\x3a\xc5\x56\x4b\ -\xdc\x00\xed\x76\x1f\xc7\x71\x38\x77\xee\x1c\xb6\x6d\xd3\xef\xf7\ -\x79\xf0\xe0\x01\x96\x65\xb1\xb2\xb2\xc2\x91\x23\x47\xf2\xb2\x4f\ -\x38\xc4\x36\x37\x36\x38\xb8\x78\x98\x42\xc1\x26\xf6\x62\xfc\x5e\ -\x87\x6e\xb3\xc6\xc1\xe9\x71\x46\x2d\x1d\x4d\x4e\xf1\xe3\x88\xfe\ -\xde\x2e\xa7\x2f\x5e\x62\xb2\x60\xd2\x48\x25\xc2\x10\xee\xdc\xbe\ -\x85\x5d\x2c\x90\xc6\x21\x72\xa6\xe1\x98\x1a\x8a\x94\x61\x5b\x3a\ -\x83\x6e\x8c\x63\xab\xc2\xf0\xae\x6b\xb8\x86\x8e\x1f\x43\x2a\x83\ -\x5d\xae\x72\xf3\x7e\x9b\x86\xac\xb0\xed\x07\x6c\xf5\x07\x44\x32\ -\xb4\x06\x7d\x31\x65\x4e\x62\x74\xc7\x40\xd2\x75\x0a\xb6\xcd\xdc\ -\xc2\x3c\xf5\x04\x5e\x78\xf2\x02\xaf\xbf\xf9\x1e\xbf\xfe\xcb\xbf\ -\xcc\x3f\xff\x5f\xfe\x77\xc6\x67\x26\x49\xe3\x8c\xad\x8d\x2d\x22\ -\xcb\xe0\xa9\xc7\x3f\xc2\xf8\xf4\x34\x3b\x7b\x35\xde\xbf\x7e\x83\ -\x6e\x53\x38\x8a\xd0\x0c\x24\x4b\x17\x25\x68\x92\x88\x61\x68\xae\ -\x29\x08\x72\xd5\xde\xfe\xce\x38\x8e\x63\x64\x49\x42\xcf\xf1\xc8\ -\xfb\x6a\xae\x30\x0c\x21\xcd\x90\x75\xa1\x27\xc8\x92\x14\x49\x4d\ -\x48\xf2\x1b\x5b\xd7\x34\x22\x54\xc2\x7c\x98\x24\x94\x60\x82\x36\ -\x99\x2a\xf9\x21\x96\x25\x50\xb4\xe1\x6a\x29\x93\xe5\xe1\x4a\x28\ -\xc8\xd7\x57\xfb\x6a\xb2\xfd\xfc\x31\xb3\x5c\x16\x6b\xa5\x4e\x87\ -\x30\xcb\xb0\x2b\x15\x94\x9c\x6b\xad\xc9\xf9\x41\x56\x14\x78\xa8\ -\xb7\x06\x50\x73\xf1\xc8\xbe\x4a\x6d\x9f\xed\xe5\x38\x0e\x4a\x2e\ -\x42\x91\xd2\x01\x12\x09\x89\x84\xc8\x31\x8b\x32\x32\x2f\x80\x28\ -\xc5\x2a\x94\x88\xa5\x18\xd5\x2d\xa0\xe9\x1a\x2f\xbf\xfa\x03\x1e\ -\xff\xea\xe7\xc4\x0b\x42\x96\xc4\x1e\x39\xd7\x5a\xab\xff\x80\xd3\ -\x95\x89\x72\x40\x7a\x28\x79\xf5\xee\xd2\x0a\x0b\x07\x0f\x50\x2c\ -\x57\x39\x77\xee\x1c\xe4\x10\xbd\xfa\xd6\x16\x13\xa3\xa3\x48\x06\ -\x78\x01\x94\x46\x5d\x96\x56\x96\x99\x3a\x7e\x8a\x03\x8b\x87\xe8\ -\x35\x1a\x22\x11\x50\x56\x20\x8d\xd0\xd3\x0c\x4b\x93\x91\x25\x85\ -\x09\xd7\xa6\x52\x76\x99\xab\x94\x78\x64\x7a\x9a\x63\xd3\xd3\xec\ -\xd4\xf6\x28\x16\xcb\x38\xbd\x01\x1f\x3d\x7c\x0c\x43\xd5\xd0\xfb\ -\x7d\xe4\x30\xe2\x89\x33\xe3\x74\xc3\x22\x47\xe7\x67\x58\x6b\xd4\ -\xf8\xdb\x57\x5f\xe6\xc6\xca\x12\xe3\x63\xe3\x74\x6a\xbb\xe8\x9c\ -\xa4\xd5\xea\x50\x1d\x2f\xe2\x77\x60\xaf\xdb\x67\xa3\xbe\xc7\x23\ -\x8f\x1d\xe5\xed\x6b\x9b\xbc\xfc\xcd\xbf\x20\x0d\x22\x5c\x5d\xe7\ -\xd2\x13\x1f\xe1\xea\x0f\xef\xf2\xb1\x47\x2e\x13\x34\x7d\x64\x5d\ -\x58\x1c\xeb\xf5\x3e\xc5\x62\x91\x77\xdf\x7d\x97\xc7\x1f\x7f\x9c\ -\x34\x4d\x39\x79\xf2\x24\xaf\xbe\xfa\x2a\x67\xcf\x9e\x65\x7d\x7d\ -\x9d\xb1\xb1\x31\x5c\x57\x63\xa7\xd6\xc7\x75\x1d\x0a\x05\x8b\x1b\ -\x37\xee\xe4\xc3\x2e\x86\xf6\xb8\xc9\x51\x87\xbf\xfc\xeb\x17\x79\ -\xe2\x89\x27\x28\x16\x45\xbf\xf7\xd8\x63\x97\xd8\xd8\xd8\x62\x69\ -\x69\x49\x28\xd6\x3c\x8f\x6a\xb5\x4a\xa9\x32\xca\xcd\x5b\xb7\x79\ -\xfe\xd9\x8f\xe1\x05\x29\xaa\x9c\x3f\x0c\x51\xc8\xf8\xe8\x08\xeb\ -\xab\x0f\x38\x30\xbf\xc0\x76\xbb\x85\xa1\x2a\x58\xba\x41\xad\xe9\ -\x61\x1a\x96\x70\x06\x85\x11\x73\x53\xd3\x68\x28\x6c\xad\x6e\x22\ -\x8f\x4c\x8a\xa8\xd3\x12\xec\x6c\x45\x28\x85\x3c\x18\x2f\x4d\xb1\ -\x8b\x06\x6d\x2f\x25\x4e\x64\x14\xc7\xe6\xed\x9b\xb7\xf8\xff\x5e\ -\x7b\x15\x5f\xb7\x68\x79\x09\x5a\xb9\x8c\x6a\xdb\x44\x51\x0c\xba\ -\x45\xa9\x5a\x62\x6f\xfd\x1e\xe6\xe8\x41\x6e\xdc\xba\x43\xe1\xf3\ -\xcf\x20\x03\x5a\x9c\x71\x6c\xd4\xa1\xa4\xaa\x3c\xb8\x73\x93\xd1\ -\x99\x79\xe2\x91\x32\xa5\x52\x91\x47\x1f\x39\x47\x3f\x08\xd9\xd8\ -\xda\xa4\xdb\xac\x0b\x07\x9a\xae\x61\x17\x0a\x38\x8e\x43\x18\x86\ -\xb4\x9b\x4d\xe2\xc1\x80\x56\x9a\x52\x2c\x56\xc4\x83\x9f\xa6\x43\ -\x32\x47\x14\x45\x68\xb2\xb8\xb9\x3a\x9d\x8e\x18\x46\x05\xe1\x10\ -\x79\x6b\x39\x0e\x69\x9a\x12\xf8\x1e\xa1\x04\xaa\xa1\x0f\x0f\xe6\ -\xfe\x21\x22\xcb\x08\x7d\x1f\x25\xdf\xed\xee\x5b\x11\x91\x65\x81\ -\xcc\x95\x64\x01\xe0\x73\x9c\xe1\x8e\x7a\xdf\x29\x15\xe6\x49\x13\ -\xe8\x02\xd7\xbc\x0f\xd6\xdb\x1f\x56\x0d\xba\x5d\x8c\x3c\xf1\xb1\ -\xd3\xec\x0c\x85\x2b\xfb\xda\xec\x7d\x6d\xb7\x90\x09\x0b\x60\x42\ -\x94\x57\x16\xfb\x07\x59\x55\x55\x94\x0c\x12\x45\x16\x53\xfa\x24\ -\x44\x33\x2c\x32\x29\x25\xee\xf9\x10\x25\xe8\xa6\x4d\xa3\xb9\x83\ -\xa2\x1b\x8c\x8c\x8f\xf1\xdd\xef\xbd\xc2\x7f\xff\xb3\x9f\x3b\x64\ -\x28\x2c\xdb\xb6\x2b\x52\x44\x86\x92\xea\x4c\xcc\xd9\xe4\x4c\x42\ -\x96\x64\x62\x3f\xc0\x50\x54\xfc\x81\xff\x7b\x59\xc6\xa1\xbf\xfe\ -\xeb\x6f\x71\xfc\xc4\x19\x6e\xdc\xba\x89\x6d\xdb\xd8\xba\xc4\xdd\ -\x9b\xb7\x78\xf4\xd4\x29\x4c\x4d\xa7\x1b\xa7\x24\x06\x5c\x5f\x5a\ -\xe6\x89\x67\x9e\x24\x8a\x03\xc2\x41\x0f\x39\xf4\xa8\x5a\x1a\x7a\ -\x34\x80\x46\x0d\x37\x4d\x98\xb4\x0d\x68\xd5\xf9\xfc\x33\x4f\xf3\ -\xc5\x67\x9f\xe5\xfc\xec\x2c\x1f\x3d\xbe\xc8\x94\xa6\x73\xa4\x52\ -\x45\xeb\x74\xf9\xca\xc7\x1f\xe5\xa9\x53\xc7\x59\xbb\xf6\x01\x47\ -\xc7\xc7\x39\x7b\x68\x9c\xa4\x07\x5a\x04\xae\x26\xe1\x75\xea\xf4\ -\x5b\x7b\x9c\x3e\x7a\x90\xc5\x83\xb3\x6c\xed\x6e\xd1\xf5\x85\xf2\ -\x27\x15\x10\x13\xde\xbd\x79\x93\xf2\xc1\x03\xbc\x76\x6b\x8d\x7f\ -\xfd\xa7\xff\x91\x6b\xeb\x2b\x1c\x3e\x7a\x84\x5f\xff\xe5\x9f\x62\ -\xfb\xc6\x12\xc7\xc7\x66\x18\xd1\x15\x4a\x86\x89\x94\x66\x18\x86\ -\x50\xfa\xdc\xbe\x7d\x9b\x13\x27\x4e\x0c\xfb\x24\x5d\x97\x79\xea\ -\xa9\xa7\xd8\xde\xde\x66\x30\x18\x50\x2a\x95\xe8\x76\x43\x8a\x45\ -\x87\x38\x4e\xa8\xd7\xdb\x44\x51\xc4\xf4\xf4\x34\x8a\xc2\xd0\x82\ -\x79\xfd\xf6\x2a\xe7\xcf\x9f\x17\x3a\xef\x5e\x3c\x7c\xe3\xdf\xbd\ -\x7b\x97\xaf\x7c\xe5\xa7\x39\x73\xe6\x14\xa7\x4e\x9d\xc2\x72\x5d\ -\x6e\xdc\xba\x4d\x3f\x88\xd9\xdc\xa9\x13\xc4\x29\xa9\xac\x90\xa9\ -\x2a\x61\x14\x13\x04\x11\x33\x53\xb3\x44\x71\x8a\xd7\x1d\x50\x74\ -\x84\x49\x22\x88\x13\x0c\x0b\x54\xc3\xa4\xdb\xec\x60\xab\x3a\x99\ -\x1f\x31\x35\x36\x4e\xc1\x36\xb0\x74\x83\x28\x10\x65\x5d\x14\x8b\ -\x7c\x60\xc5\xd4\x49\x14\x68\x79\x1e\xa9\x0e\xf5\x41\x9f\xbf\x7b\ -\xed\x35\x62\xcb\x64\x2f\xf0\x31\x47\x2a\x44\x9d\xb6\x10\xe9\x08\ -\xc6\x22\xb5\xda\x2e\xfa\xd4\x14\x9b\xeb\xeb\x48\x59\xc6\xea\xb6\ -\x87\x0a\x4c\x97\x2b\x74\x76\x7d\x7e\xed\x6b\x5f\xe3\x0b\x9f\x7a\ -\x81\x4e\x7d\x17\x57\xd7\x38\x34\x3f\x4b\xb3\xbe\x83\xa6\x29\x18\ -\x86\x8e\x62\x5b\x90\xa5\x14\x46\xaa\xe8\xa6\x49\xab\xd3\xc1\x0b\ -\x02\xa1\xa4\xca\x4d\xfc\xfb\x83\x30\xdd\x71\x84\x89\x21\x08\x70\ -\xf2\x83\xba\x9f\x04\x41\x5e\x0e\xab\x85\x02\xc5\x5c\x4f\xae\x28\ -\x0a\x76\xa1\x00\x71\x84\x94\xa6\xc4\x71\x44\x18\x06\xa8\xaa\x42\ -\xa9\x52\x16\xbf\x96\xa3\x73\x83\x6e\x97\x34\x08\xd1\x2d\x1b\xcb\ -\x71\xc9\x32\x08\xf2\x70\xf3\x7d\x38\xdf\x7e\x25\x60\x3b\x8e\x38\ -\xb0\x9e\x37\x94\x6d\xee\x73\xc2\x2c\xdb\x16\xfd\x76\x1c\x13\xe4\ -\x7d\xb2\x94\xf7\xd7\xba\xe3\x50\xaa\x54\x48\x82\x80\xa0\xd3\x41\ -\x55\xd5\x21\x7c\x2f\x1a\x0c\x30\x4a\x25\x92\x9e\xc8\xe0\x6a\xe6\ -\xee\xb3\xfd\x95\x57\xbf\xd5\xc2\x30\x8c\xa1\xdd\x57\x71\x1c\x08\ -\x22\x14\x45\xe3\xe4\xc9\xd3\x04\xdd\x3e\xf5\x7a\x1d\xc3\x34\x59\ -\xdd\xa8\xdd\xeb\xf6\x03\x52\x32\x3a\x5e\x97\x4c\x16\x9f\x3f\x39\ -\xc7\x01\x13\x07\x01\x44\x31\x32\x0a\x64\x50\xb0\xcd\xdf\x44\x02\ -\x2f\x4c\x79\xeb\xca\xdb\x9c\x39\xf7\x28\x61\x1c\x13\x44\xa2\x07\ -\x93\x33\x19\x5d\xd7\x48\x64\x99\xdd\x7e\x48\x24\x67\xb4\xdb\x4d\ -\xa6\xc7\x47\x91\x02\x8f\xcf\x7d\xe2\x39\x06\x7b\x5b\x58\x49\xc0\ -\xa9\xc5\x05\x9a\x0f\x96\x68\x3c\xb8\xc7\xe9\xd9\x69\xce\x2f\x4c\ -\x63\x87\x3e\x53\xae\x83\x19\x65\xb8\x9a\xc2\x54\xc5\xa5\xb5\xbd\ -\xce\xce\x5a\x97\xcd\x07\x2b\xfc\xd4\xe7\x7f\x02\x5d\x4a\x50\x52\ -\x51\xff\xcb\x12\xfc\xfe\xbf\xfd\xbf\xf8\xab\xaf\xff\x19\xef\xbc\ -\xf5\x26\xa5\xa2\xc3\xd5\x6b\xef\xf2\xb1\x17\x3e\x4e\xa9\x2c\x61\ -\x94\x5c\x7a\x01\x7c\xff\xca\x75\x6e\xaf\xae\xf3\xeb\xbf\xfd\x4f\ -\xf9\xf7\xdf\xfc\x3a\xf1\x48\x01\xcf\x94\x39\x77\xf9\x51\xde\x7f\ -\x67\x99\xc5\xe9\x39\x16\x67\x6c\x94\x0c\xba\x5d\x0f\xdb\x56\xd9\ -\xda\xaa\x73\xef\xde\x3d\x46\x47\x47\x91\x65\x99\x62\x31\xff\x04\ -\xf7\x03\x6a\xb5\x1a\x49\x92\xf0\xe8\xa3\x8f\xb2\xb4\xb4\xc4\xd6\ -\xd6\xd6\x50\xf6\xb8\xb4\xb4\x44\xa5\x52\x41\xd3\x54\x82\x20\x61\ -\x6c\x54\x3c\x80\x6b\x6b\x6b\xc3\xd4\x40\x49\x92\x70\x5d\x8d\xd5\ -\x55\xc1\xd3\x8a\xa2\x98\x24\x11\x93\xcf\x89\x89\x71\x0e\x2c\x1c\ -\xe2\x91\xf3\x17\x08\x93\x94\x17\xbf\xf7\x0a\x3f\xbc\xf2\x0e\x2f\ -\xbf\xf6\x7d\xdc\x62\x19\xc3\x74\xe8\x76\x7a\xf4\xfb\x03\x1a\xb5\ -\x26\xb6\xed\xa2\xc8\xa0\x1b\x26\x61\x0a\xbd\xfe\x00\x53\xd5\x28\ -\x68\x3a\x25\xc7\xa5\x52\xb4\xe8\xb6\xfa\xc4\x61\x44\xbf\x9f\x52\ -\x1d\x75\x48\x25\x90\x14\x99\x98\x8c\xf6\x20\xc6\x29\x3a\xe8\x3a\ -\x54\x46\xc7\x18\xc4\x21\xcd\xc1\x80\xa9\x83\xf3\x74\x07\x7d\xe4\ -\xf1\x11\xe2\x28\x44\xce\x52\x74\x39\x63\xb4\x5a\x21\x6c\xb5\x60\ -\xe0\xd3\xef\x79\x7c\xeb\x1b\x7f\xc3\x1f\xff\xe1\x37\x78\xea\xf4\ -\x01\x7e\xff\xff\xfc\xd7\x48\x7d\x0f\x0b\x89\x5f\xf9\x85\x5f\xe4\ -\x17\xbe\xf6\xb3\x64\x91\xcf\x0f\xdf\x78\x83\x3f\xf8\xf7\xbf\xcf\ -\xf7\xdf\x78\x5d\x4c\x8f\x0b\x05\xba\xbd\x1e\xad\x56\x93\x4c\xe2\ -\xc3\x01\x93\xa2\x40\x2a\x0d\x87\x8a\x92\x24\x89\x07\x58\x51\xe8\ -\x34\x9b\xc4\x71\x4c\xaf\xd3\x11\xe5\xb4\xa6\x0d\xf7\xcb\xfb\xfe\ -\xe4\x61\x2f\x9a\xf7\xc1\x72\x4e\xdf\xdc\x37\x5a\xc4\x71\x8c\xee\ -\x38\x64\x83\x01\xe8\x3a\x5a\x5e\xa6\xef\x3b\x8f\x74\xd3\x24\x8d\ -\x22\x06\xfd\xfe\x10\xc6\x50\x28\x14\xc4\xc7\x4b\x12\x30\x4d\xb1\ -\x2f\xce\x0f\x72\xfa\x10\x8e\x48\x73\x5d\x24\x59\xa6\xd7\x6a\x89\ -\x17\x51\x2e\xb9\x8c\xa2\x08\xc3\x71\x04\xcf\x6b\x6f\x8f\x5e\xaf\ -\x37\x74\x68\xed\x93\x4a\xf6\xbf\x97\x24\x49\x80\x7b\x92\x84\xea\ -\xe4\x14\xdd\xf5\x4d\x0a\x8e\x4b\x3c\x18\x88\xc1\x95\x65\x10\xfa\ -\x03\x7e\xec\xf9\x8f\xf3\xc5\x9f\xfc\x32\xf7\x57\xee\x71\xe2\xe4\ -\x31\xfe\xf2\x1b\xdf\xc0\x76\x0c\x7a\x41\xff\xf7\x6c\xcb\xfe\x70\ -\x93\xf6\x5b\xbf\xf5\x5b\x62\x90\x20\xe5\x76\x35\x55\x25\x0a\x33\ -\x7a\x91\xf4\xfc\x4b\xaf\x5f\xf9\xbf\xff\xe8\x2f\xbf\xc1\x7f\xfb\ -\x9b\xff\x23\x1d\x2f\xe0\xec\xb1\x05\x5e\x7b\xf5\x4d\x0e\xcd\xcf\ -\x61\x48\x0a\xa9\xac\xd2\x90\x15\x1e\xd4\x1a\x8c\x4d\x4e\xf1\xa7\ -\x7f\xf6\x67\x5c\x38\x7f\x9e\x9f\xff\xb9\xff\x82\xed\xf5\x35\x9e\ -\xba\xf0\x28\xbf\xf4\xb3\x9f\xa6\xa4\xdb\x1c\x9a\x1c\xa3\xb9\xb1\ -\xc6\x6f\xfc\xea\x3f\x62\x6b\x79\x89\x85\x89\x31\x8e\xce\x96\xd1\ -\x62\x09\x45\x46\x44\xc6\x38\x16\xb7\x97\x97\xd0\x0d\x9d\xc3\x8b\ -\xa3\xf4\xc3\x0c\xdd\x12\x9a\xd2\xa2\x0d\xd7\x57\xee\xe3\x56\x8a\ -\x7c\xe9\x67\xbe\xcc\x9b\xef\xfc\x90\xc1\xa0\x4f\x1c\x47\xbc\xf1\ -\xc3\xf7\xf8\xfe\x0f\x5e\x47\xb5\x1c\x4e\x3e\x72\x8a\xab\xeb\x1b\ -\xac\x06\x3d\xf6\x88\x68\xa4\x3e\x99\xa6\x10\xb7\xba\x1c\x9e\x98\ -\x24\x69\x75\x38\xb1\x58\xe5\xce\x5a\x9b\x83\xf3\x2e\x7e\x0a\xcd\ -\x7a\x8b\x34\x4d\x99\x98\x98\xc8\xbf\x58\x1a\x8a\x22\x3e\xe9\x9d\ -\x4e\x67\x18\x18\xb6\xb0\xb0\x40\x9a\xa6\xdc\xbb\xb7\x4c\xad\x56\ -\xa3\x5a\xad\x72\xe2\xc8\x2c\x99\x04\xdd\xee\x80\x24\x95\x79\xf7\ -\xdd\x77\xb9\x7c\xf9\xf2\xb0\xd4\x13\x13\x50\x89\x1b\x37\x6e\x73\ -\xf8\xf0\xe1\xa1\x88\xdf\x30\x54\x64\x05\xde\x7d\xf7\x3a\x27\x4f\ -\x1f\xe3\xf0\x4c\x91\xf1\x99\x43\x1c\x3b\x32\xc5\x07\x37\x96\xa8\ -\x8c\x8e\x72\xfd\xe6\x6d\xda\xdd\x2e\xbd\xbe\xc7\x9d\xbb\xcb\x8c\ -\x8d\x4d\x20\x6b\x26\x49\x0a\x9a\xae\x10\x47\x29\x8d\x9d\x1d\xca\ -\xc5\x12\xfd\xb6\x8f\xa6\x98\x74\xdb\x5d\x64\x59\xa1\x5c\x2d\xe3\ -\x16\x24\xea\x2d\x8f\xae\x3f\x40\x32\x54\x52\x59\x46\xb7\x0c\x52\ -\x19\x32\x4c\x5e\x79\xeb\x2d\xb6\xe3\x90\x7e\x92\x90\xc6\x29\x86\ -\xaa\x11\xd6\xea\x18\xb6\x8d\xd7\xed\xe1\xfb\x03\xec\xa2\x43\xd4\ -\xef\x33\x68\xd5\xd9\x5e\x5b\x65\xb0\xb3\x4b\x63\xa3\xc1\xc7\x2e\ -\x5e\xa2\x5a\xa9\xf2\xc8\xd3\xa7\x08\x65\x93\xbd\x7a\x8d\xbf\xf8\ -\xc6\x37\x68\xf7\x7a\x54\xc7\xc7\x50\x4d\x9b\x41\x18\x62\x17\x0a\ -\x84\x9d\x2e\x44\x29\xaa\xe3\xe6\xa6\xff\x58\xc0\x25\x80\xc4\xf3\ -\x30\x6c\x9b\x28\x0c\x3f\x94\x59\xf6\x7a\xa8\xb6\x9d\xc3\x23\x84\ -\xba\x4b\xcb\x51\x3a\x69\x2c\xe0\x8b\xaa\x96\x1f\x86\x2c\xb7\x30\ -\x26\x09\xaa\x22\xc0\xed\x51\x18\x0a\x68\x3c\x90\x85\x21\x52\x0e\ -\xf6\xcb\xc9\x04\x28\xaa\x06\x48\x24\x69\x06\x49\x0c\x41\x80\x9e\ -\x1b\x4b\xfa\x39\x95\x44\x73\x5d\x51\x15\x44\x91\x80\x19\xe4\x7d\ -\xee\x3e\x51\x33\x49\x12\xb2\x7e\x9f\x34\x14\x61\xe7\xfb\x86\x0e\ -\xdb\xb6\x48\x65\x99\xd4\xf7\x45\xf4\x0c\xb9\xa2\x4c\xd7\x89\xa3\ -\x08\x55\xd7\x89\x7c\x1f\x49\x95\x89\x63\xa1\x35\x37\x6c\x0b\x5f\ -\x92\x08\xe3\x0c\xc3\x74\x08\xfd\x81\xa8\x3a\xd2\x84\xc5\xf9\x69\ -\x2e\x9d\x3a\xce\xf6\xdd\xdb\x8c\x3b\x36\xcd\x8d\x55\x3e\xfa\xc4\ -\x63\xff\xa4\x68\xbb\x9f\x48\x89\x73\x2f\x94\x8c\xac\x28\xca\x50\ -\x84\x4e\x92\x23\x42\x64\x09\xd3\xe2\xc5\x30\xcb\xf0\xd3\x94\xb9\ -\xc5\x83\x04\x19\xdc\x5c\xab\x53\x9d\x98\xe0\xc8\xd1\xc3\xec\xed\ -\xd5\xa8\x8c\x8c\xb2\xb2\xba\x4e\x65\x6c\x9c\x2b\x57\xae\x60\x9b\ -\x06\x8b\xf3\x73\x2c\x4e\x69\xcc\x95\x1c\x7e\xec\xa3\x47\x99\x34\ -\xe1\xa9\xb3\xc7\xf8\xda\x17\x3e\xc9\x57\x3f\xff\x69\xb2\x5e\x8b\ -\x63\xb3\xd3\x4c\xba\x36\x71\x2f\x01\x29\x25\x4e\x63\x22\x12\xec\ -\xa2\x4b\x67\xd0\xa5\x32\x56\x65\xb3\xee\x63\xda\x3a\xb6\x09\x49\ -\x9a\xb0\xb2\xd9\xe2\x53\x2f\x7c\x92\xcf\x7d\xfa\x05\x2e\x9d\x3f\ -\xc3\x3f\xfe\xa5\x5f\xe0\xc0\xdc\x14\x0b\x73\x53\x68\xa6\x86\x64\ -\x68\xcc\x1c\x3c\x88\xe9\xc2\x8f\x7f\xe6\xe3\x4c\x4e\x0a\xbe\x33\ -\xbe\x4f\x22\xa7\x7c\x70\xe3\x2a\xfd\x60\xc0\xd1\x13\x8b\xfc\xe1\ -\x1f\x7d\x97\xf2\x68\x89\x7b\x3b\x7d\xee\xde\xbd\x8f\x2c\xcb\x1c\ -\x3d\x7a\x24\xbf\x8d\x6d\xba\xdd\x3e\x8d\x46\x83\x6b\xd7\xae\x21\ -\x49\x12\x93\x93\xe3\x8c\x8f\x8f\x0d\x6f\x82\xd1\xd1\x51\x36\x37\ -\x37\xb1\x6d\x9b\xf5\xed\x36\xfd\x7e\xc4\xc8\x88\x4b\x10\x04\x39\ -\x4f\x5a\xf4\x5f\xc5\xa2\x85\xa2\xc8\x6c\x6d\xd5\x51\x55\x95\x4a\ -\xc5\x19\x3a\x94\xd2\x14\xd6\x1f\x6c\x31\x3e\x36\x82\x04\xec\xb4\ -\xc4\xe7\x61\x75\xab\x8b\x53\x28\x71\xfc\xd4\x61\x1e\x7f\xe2\x49\ -\x66\x66\x17\x18\x1d\x9b\x44\x51\x44\x39\x79\xf7\xd6\x5d\xde\x79\ -\xe7\x1d\xde\x78\xe3\x1d\xde\x78\xe3\x0d\x92\x24\xa3\xd9\xe8\xe6\ -\x7d\x5c\x8a\x66\x98\x14\xaa\x65\xba\xfe\x80\xb5\x9d\x1e\x8d\x6e\ -\x4b\xa8\x85\xf2\xc1\x52\xe8\x67\xf4\x3b\xa0\x2b\x12\xf3\xd3\x33\ -\x14\x2d\x87\xb0\xd7\xc7\xd6\x54\xd4\x34\x81\x5e\x07\x6f\x77\x9b\ -\x91\x52\x81\xb4\xd5\xa2\xdf\x6a\x43\x18\x32\x73\xe0\x20\x5f\xfe\ -\xf2\x4f\x72\xea\xd4\x19\x0e\x1d\x38\xc8\xc7\x9f\x79\x84\x5e\xab\ -\x4d\x1a\xc3\x6b\xaf\x7c\x97\xc1\xa0\xc7\xdc\xdc\x2c\x83\x5e\x6f\ -\x48\xaa\x8c\xf3\xe8\x17\x24\x05\x0c\x23\x77\x35\x85\x84\x71\x34\ -\x9c\x0c\x93\x91\xbb\x86\xd2\x3c\x56\x37\x16\x8a\x25\x91\x50\xf8\ -\x21\x37\x5a\x91\xc5\xff\x43\x92\x88\x92\x3c\xe8\x4f\x96\x86\x07\ -\x34\xdd\x57\x65\xe5\x53\x6a\xb2\x8c\xd4\xf3\x90\x5d\x97\x2c\x8a\ -\x08\xf2\x7c\x64\xc3\x30\x88\xa2\x88\x38\x8e\xb1\x6c\x1b\xd5\x14\ -\xec\x73\xdf\xf7\xe9\xe4\x87\x98\x7c\xcd\x64\xb9\xae\x48\x62\x7c\ -\x88\xa6\xb9\xdf\x07\x67\xf9\xef\x23\xc7\xe5\x9a\xa6\x49\x96\x8a\ -\xff\x43\xa1\x50\x40\x2f\x97\x21\x8a\x44\x1a\x45\xfe\x67\x95\x7d\ -\xd3\x4f\x7e\xe8\x83\x20\x42\x33\x2d\x3a\x83\x80\xea\xe8\x04\x34\ -\x9a\x10\x27\x68\x8a\x4a\x1c\xf9\x68\x0a\xd4\x37\xd6\x99\xad\xea\ -\xfc\xcc\x17\x3f\x0f\x69\xc8\xe1\x13\x47\xb8\xbd\xbc\x54\x01\x18\ -\xf4\x3c\xe4\x4c\x74\xc9\xca\x3f\xfb\x9d\xdf\x46\x92\x32\x11\x06\ -\x25\x09\x5e\x75\x98\x42\xac\xc0\x9b\x57\xef\xfe\xce\x07\xf7\x56\ -\x78\xe1\x0b\x9f\xe1\x3b\xaf\xfd\x00\x55\xd3\xb8\x70\xfe\x38\x24\ -\xb0\x74\xfd\x36\xba\x5b\x24\x2b\x8f\xb2\xdb\xee\xf2\xdd\xbf\xff\ -\x7b\x4e\x1d\x39\xc6\xdc\xf8\x18\x83\x66\x9f\x8f\x5e\x38\x82\xdf\ -\xf0\x91\x82\x04\x47\x81\x92\x25\xa3\x65\x29\x4b\xb7\xae\x72\xf9\ -\xfc\x69\xd2\x30\x40\xd7\x04\x85\x50\xd6\x35\x50\x15\x5e\x7f\xeb\ -\x2d\x26\x67\x67\x40\x95\x29\x14\x0b\x68\xa6\x4c\xa3\xd9\xa7\x54\ -\x36\xb8\xbf\xb2\x86\xa1\x6b\x4c\x4d\x4c\x60\x6a\x32\x25\xc7\xe5\ -\xf8\xa1\xc3\x24\x83\x3e\x97\xcf\x3f\x42\xd1\x29\xf0\xc8\xc9\x59\ -\xba\x5d\x91\xca\x39\x3d\x7b\x9c\xd5\xd5\x55\x5a\xe1\x80\xa0\xd3\ -\xe1\x93\x97\x3f\xc2\x8f\x3f\xfd\x18\x69\xcb\xe3\xd9\xa7\x8e\x72\ -\x7d\x69\x9d\x4c\xca\x68\xd4\xf6\x18\xad\x56\xd1\x75\x9d\x6e\xb7\ -\x4b\xb5\x64\xa2\xa8\xba\x58\xd5\xe4\xbc\xe3\xe9\x8a\xc5\x5e\x53\ -\x78\x7a\x2b\x95\x22\xcb\xcb\x2b\x9c\x3b\x77\x8e\xb5\xb5\x35\x3a\ -\x79\xf9\x17\x45\x19\xb5\x5a\x8d\xc7\x1e\x7b\x94\x95\x95\x0d\xc6\ -\xc6\xca\x74\x3a\x1e\xba\xae\x71\xe7\xce\x5d\xa6\xa6\xa6\xb0\x6d\ -\x17\x59\x96\x72\xce\x92\xc4\xad\x5b\xb7\x38\x30\x3f\x83\xae\xa8\ -\x44\x51\x40\xb9\x62\x72\xed\xfa\x1d\xe6\x17\xe6\x19\xad\x3a\x44\ -\xa9\x44\xa1\x60\x23\x4b\x1a\x83\x81\xc7\xa9\x53\x47\x71\x1c\x97\ -\xc9\xe9\x49\xa6\xa6\x27\x29\x38\x0e\xf5\x5a\x1d\x49\x92\x45\x5c\ -\xe9\xdd\x25\x6e\xde\xb9\xc3\xbd\xd5\xfb\x0c\x7c\x8f\xbd\x46\x8d\ -\xb5\xad\x0d\x76\x6b\x3b\xac\xad\xaf\x22\x4b\x32\x0f\x56\x1e\xb0\ -\xb7\xb3\x47\x63\xbb\xc9\xad\xbb\xf7\x58\x6d\x37\xb1\x0b\x25\x3a\ -\xbb\x7b\xc8\xa1\x08\xe4\x26\x4e\x98\x9e\x9e\x62\x10\x04\x24\x49\ -\x88\x64\x5b\x74\x5b\x0d\xfc\x6e\x97\x23\x33\xb3\x7c\xf6\xf9\xa7\ -\x48\x7a\xb0\xb4\xb2\xc4\xe8\xa1\x39\xf6\x7a\x03\x4e\x9e\x39\xc3\ -\xc5\xcb\x97\x78\xfb\xda\x4d\x1e\x6c\x6d\xa1\x5a\x36\x72\xb1\x48\ -\x4c\x9e\xac\xa0\x6a\xa4\x40\x1c\x25\xe8\x9a\x86\xa9\x8b\x03\x95\ -\x4a\x12\xa9\x1f\xa0\xe7\x3f\x26\xcd\x90\x0c\x83\x64\x30\x20\xcd\ -\x5d\x5d\x69\xde\xab\x4a\xaa\xf0\x29\xa7\x99\x30\x82\x08\x37\x94\ -\x82\xa6\x0a\xcb\x40\x1c\x85\xc4\x71\x5e\x76\x6b\x1a\x92\xaa\x8a\ -\x3e\x34\x8e\x21\xc9\x48\x65\xe5\x43\xb9\xa4\x22\xa3\x29\x2a\x12\ -\x19\x8a\xa6\x11\x75\xbb\xa4\x83\x01\x8a\xe3\x7c\xe8\x6c\xd2\x34\ -\xa2\x7c\x7a\x9d\x24\x89\xc8\x94\xca\x2b\xad\x64\xdf\x92\x68\x98\ -\xa4\x79\xae\xb2\xa6\x69\xf8\xbe\x37\x1c\x74\x85\x9e\x27\xca\x74\ -\xc3\xc0\x75\xdd\x61\x3b\x10\xc6\xb1\x70\x3b\xa4\x90\x04\x11\x86\ -\x5b\x14\xd4\x55\x45\x25\xee\x34\xd1\x6c\x8d\xa4\xd9\xa0\xe8\x1a\ -\x1c\x9f\x9e\xa4\xaa\x18\x28\x5e\x9f\xd1\x82\x4d\x1c\x0d\x28\xd8\ -\x26\xd3\x93\xa3\x3f\x28\x98\xd6\xb2\xc8\xa3\x90\x90\xbd\x28\x20\ -\x22\xcd\x47\xe8\xb9\x57\x32\x85\xbb\xf7\x1b\xd9\xed\x95\x15\xb0\ -\x2c\x96\xd6\x6a\x7c\xfb\xbb\x2f\x33\x7f\xf4\x08\xbd\x08\xc2\x04\ -\x64\xdd\xe0\xc1\xda\x06\xc5\x92\xc5\x77\x5f\x7c\x19\xaf\x33\xe0\ -\xcc\xb1\x13\x78\x8d\x3a\x33\xa5\x22\x56\x0a\x05\x39\xe6\x48\xc5\ -\xc0\x48\x3d\xf0\x3d\xd6\xee\xdd\xe4\xc8\x81\x19\x6a\x3b\x1b\x68\ -\x52\x8a\x6b\xc9\x48\x8a\x4c\x94\xa5\xec\xd6\x6a\x28\xba\xc6\x89\ -\x93\x8b\x34\x1a\x0d\x61\x0e\xf7\x62\x34\x45\x65\xe3\xfe\x0e\xb6\ -\xa2\x70\x61\x7e\x02\x3b\x85\xa8\xde\x65\x06\x38\x52\x1d\x61\x52\ -\x77\xd8\xb8\x79\x87\x8f\x5e\x3a\x47\xb3\x95\xc1\x00\x8a\x09\xe8\ -\xcd\x1e\x1f\x59\x38\x42\xc5\x4b\x71\x82\x18\x47\x02\x5d\x05\xdb\ -\x31\xf0\x43\x28\x17\x5c\x36\xd7\xd7\x38\x70\xe0\x00\x07\x66\xaa\ -\x68\x9a\x42\xb5\x5a\xa6\xde\x0a\xd8\xde\xde\x13\xa0\x3d\xc3\x60\ -\x6e\xa6\xca\xcd\xfb\x3b\xb8\xae\xcb\xfc\x98\xcb\xd6\xd6\xee\x70\ -\x4f\xb8\xb8\xb8\xc8\x81\x03\x07\xd0\x75\x9d\xe5\xe5\x65\xae\x5f\ -\xbf\x4e\x92\x08\xa4\x8e\x18\xc2\x0a\xeb\x63\x96\x65\x8c\x8d\x8d\ -\x31\x18\x78\x0f\xfd\xfc\x00\x5d\x53\x98\x1c\xad\x50\x2e\x68\x8c\ -\x96\x1d\xe4\x4c\x0c\x98\x16\x0e\x8e\xd3\x0b\xa0\xd6\xe8\xa0\xea\ -\xd0\xa8\xb7\xd0\x55\x8d\x24\x82\xa2\xeb\x50\x74\x6c\xa4\x34\x65\ -\x77\x6f\x9b\xa7\x9f\x7b\x9a\x47\x2f\x9f\xe2\xcc\x23\xc7\x38\x73\ -\xf1\x22\x67\x2f\x5d\xe2\xcc\x85\x47\xb8\xf8\xc4\x65\xce\x5f\xbc\ -\xc0\x47\x9e\x78\x9c\xe3\xc7\x8f\xb3\x78\xf0\x10\x67\x4e\x9c\xe0\ -\xc2\x99\x73\x3c\xf1\xc8\x39\xce\x1d\x3d\xc1\xc7\x1e\xff\x28\x33\ -\xa5\x11\x4c\x24\xc6\x6c\x97\xb2\x6e\xf2\xcc\x63\x97\xf9\xaf\x7f\ -\xf9\x17\x49\xfa\x1e\xe3\xd5\x32\xa3\xe3\xe3\x62\x76\xa0\x6b\xec\ -\xd4\x6b\x7c\xe9\x2b\x9f\x20\x48\x18\x1a\x18\x1c\x0d\xce\x9c\x39\ -\xc3\xad\x5b\xb7\x28\x17\xe1\xc2\x85\x47\x20\x4b\xd1\x4c\x03\xc3\ -\x32\xc5\x21\x56\x34\x88\x53\x92\x9e\xb8\x9d\x6c\xd3\x41\x96\x05\ -\x57\x8b\x30\x82\x4e\x77\x78\x88\x0d\xd3\xa4\xe0\xb8\x62\x4f\xfc\ -\x10\x1d\x66\x7f\x4f\xae\x99\x86\x88\x69\x49\x13\xc2\x24\x1a\x82\ -\xf7\x74\x5d\x17\x53\xed\x4e\x87\x30\x17\xe1\x14\x0a\x05\xd2\x34\ -\x15\x43\x2a\xc3\x20\xf5\x3c\x82\xc1\x60\x68\x4d\x0c\xe2\x68\xa8\ -\x3c\x23\x4d\x21\x6f\x85\xf6\xb7\x0f\x51\x14\x51\xa9\x54\x84\xac\ -\x33\x5f\x7f\x0d\x49\x3a\xf9\x1a\xcd\x72\x1c\x92\x76\x9b\x6e\xb7\ -\x3b\x04\x12\xec\x1b\x23\xb4\x7c\x62\x3e\xe4\x74\xe5\xd3\x73\x55\ -\xd3\x1e\x8a\x6f\x05\xb7\x54\x25\x8b\x33\x4c\x45\xc7\x2c\x57\x08\ -\xb6\xb7\x70\xc6\x2b\x90\x86\x48\x81\x47\x63\x6b\x13\x25\x89\xb8\ -\x7c\xf1\x11\xea\x8d\x06\x41\x1a\x63\xeb\xf6\x8b\x6a\x2e\xcf\x04\ -\x90\x55\xcd\x20\x43\x66\x10\xfa\x04\x51\x4c\x94\x88\xa4\x95\x6e\ -\x18\x60\x16\x8b\x58\xc5\x12\xff\xec\xf7\xfe\x05\x2d\xdf\x23\x33\ -\x2c\x2c\x03\xfc\x0c\xb6\x1b\x75\xce\x3e\xfa\x28\xf7\x96\xb6\xd9\ -\xd9\xd8\xc6\x90\x55\x2a\xae\x43\xd5\x71\x51\x63\x1f\x7a\x03\xca\ -\x86\xca\xe6\xd6\x36\xb6\x0a\xf5\xed\x75\xc6\x2a\x05\x5c\x53\xa7\ -\x5c\x72\xd1\x0d\x85\xda\x5e\x13\x55\x56\xd8\xd9\xda\xc5\x1f\x78\ -\x5c\xba\x74\x09\x0d\x28\x38\x2e\x3b\x9b\x5b\xf4\x3b\x5d\x5c\x55\ -\x63\x67\xe5\x01\x97\x4f\x1c\xe2\xee\xcd\x35\x16\x4c\x89\x59\xb3\ -\xc0\xc6\xdd\x0d\x4a\x3e\x14\x06\x01\xc7\xc6\x26\xb8\xfb\xee\x4d\ -\x46\x2c\x89\x11\x15\xaa\x09\x2c\x64\x36\xe7\xdd\x71\xbe\xf6\xcc\ -\x0b\x3c\x7e\xe0\x28\x1f\xbb\x78\x09\x5b\x86\xd1\xb2\x4c\x7d\xb7\ -\x83\x92\x46\x2c\x4c\x4d\x71\xe3\xea\x55\xde\xfe\xe0\x2e\xdb\xdb\ -\xbb\x88\x8a\x4c\x48\xf9\x0a\x85\x02\xa3\xa3\xa3\x34\xdb\x21\x13\ -\x13\x13\x62\xcf\x08\x6c\x6c\x6c\x50\xad\x56\xa9\x56\x2d\x8a\x45\ -\x0b\xc3\x30\x98\x9c\x9c\x1c\xfe\xfe\xf7\xdf\xbf\x4a\x92\x24\xac\ -\xae\x6e\x60\xdb\x1a\x1b\x1b\x1b\xcc\xcd\xcd\x0d\xa1\xf1\xfb\xd8\ -\xd5\x8d\x8d\x0d\xe6\xa6\x67\xe8\x36\xeb\xf4\x9a\x0d\xc2\xd0\x63\ -\xf5\xc1\xba\x50\x42\x01\x51\x0a\x95\x4a\x91\x38\x86\x56\xab\x45\ -\xb5\x5a\x25\x89\x22\x0c\x2d\x0f\x1a\x20\xc6\xf7\x07\xec\xd4\x1a\ -\xd4\xbb\x31\xb5\x56\x48\x75\x44\x23\x93\x25\xda\xfd\x1e\x5b\x7b\ -\x0d\xf6\x5a\x0d\x0c\xc7\x22\x4e\x13\x1c\xcb\x26\x0d\x62\x8a\xa6\ -\x46\x51\x03\x1b\xa8\x18\x36\x53\xa5\x0a\x7e\xa3\xc9\xb8\x5b\xe0\ -\xc0\xf8\x18\xe7\x4f\x1c\xe7\xd2\xd9\x79\x26\xab\x25\x6a\xdb\x5b\ -\x14\x6c\x9b\xbd\xda\x0e\x48\x0a\xa6\x5b\xa0\xeb\x41\x24\xc1\x3b\ -\xd7\xae\x72\xec\xe4\x29\x5e\x7d\xeb\x06\xef\xbf\xff\x3e\xdf\xfe\ -\xdb\x6f\xf1\xad\xbf\x7b\x53\xf0\xd6\xe2\x98\xda\xde\x1e\xad\xad\ -\x5d\xe2\x38\x45\xca\x19\xd0\x24\x19\x24\x02\x8d\xd3\xeb\xf5\x72\ -\x66\x73\x02\x8a\x4a\x32\xf0\xd0\x14\x75\xc8\xe9\x56\x0b\x05\x24\ -\x55\xa5\xd7\xeb\x0d\x65\x9d\xfb\x7e\x00\x39\x17\x8b\xec\xe3\x66\ -\x07\x39\xa5\x03\x45\x19\xae\x88\x22\x3f\x20\x8d\xe2\xa1\xee\x7a\ -\x38\x60\x4b\x62\xbc\x30\x20\xce\x13\x38\xf6\xa9\x22\x98\x26\xd8\ -\x36\x41\xee\x47\xde\x87\xf8\x0f\x45\x1f\x79\xe9\xbc\x3f\x48\xdb\ -\xcf\x9b\xca\xb2\x4c\x20\x85\xa2\xe8\x1f\x88\x49\xf6\xcb\x7c\x0c\ -\x63\x08\xeb\x7b\xd8\x2c\x21\xe5\x53\x7b\x34\x1d\x3f\x4e\x71\x2c\ -\x97\xc4\x0f\x19\xa9\x54\xc1\xeb\x63\x59\x06\x52\x96\x32\x33\x52\ -\xe5\xcc\xe1\x45\xaa\xc5\x02\x53\x13\x15\x46\xc6\x47\xe8\x7b\x7d\ -\xfc\x30\x20\xf0\x83\x87\x6d\x8c\xb9\x32\x44\x96\x30\x74\x95\x4c\ -\x85\x41\xc6\xf3\xef\xdd\xb9\xcd\x7b\xb7\x6e\xd1\xf1\xba\xe8\xaa\ -\x4a\xc1\xb2\xe9\x35\x3b\x34\xfa\xb0\xbb\xd7\x44\xd2\x74\xba\xfd\ -\x3e\x96\xa9\xd3\x6b\xb7\xf8\xfc\x4f\x7c\x16\x4d\x96\x38\x7c\xe8\ -\x00\xfd\x5e\x0f\x53\x37\xd0\x55\x0d\x43\x53\xf0\xfb\x03\xd6\xd7\ -\xd6\xb8\xf0\xe8\xa3\x48\x92\xc4\xfd\xfb\xab\x84\x81\x78\xdb\x45\ -\x51\xc4\xea\xda\x7d\xa6\xa7\x85\xeb\xa7\xde\x18\xb0\x30\x3b\x87\ -\xa5\x1b\xc4\x41\xc8\x07\xef\xbd\xcf\x85\x0b\x17\xe8\xb4\x22\x16\ -\xe7\xe7\xd8\x58\xef\x60\xa9\x70\x6c\x61\x86\xeb\xef\xbe\xcf\x58\ -\xb1\xc2\x85\x93\x87\x18\xaf\x56\xb8\x7d\xf5\x1e\xba\x02\xbd\x06\ -\x4c\x97\x35\xb4\x41\x9f\x42\x10\x72\xa8\x58\x62\xae\x52\x26\xee\ -\x25\xf4\x07\x29\xbb\xf5\x1a\xb2\x2c\x31\x35\x31\xce\x47\x9f\x7c\ -\x12\xc3\x10\x19\xba\xcb\xcb\xeb\xc3\x52\x79\x7e\x7e\x1e\x4d\x03\ -\xc3\xd0\xf1\x3c\x0f\x55\x85\xef\xbd\xfa\x23\xc6\xc7\xc7\x59\x58\ -\x98\xa2\x5e\x1f\xa0\xaa\x88\x28\xd8\x38\xa6\xd7\xeb\x71\xf9\xf2\ -\x65\x4e\x9d\x3a\xc5\xca\xca\x0a\xb5\x5a\x8d\x37\xdf\x7c\x9b\xcd\ -\xcd\x4d\xe6\x67\x47\x88\xa2\x18\xcb\x32\x86\x2f\x8a\x8d\x8d\x0d\ -\xc6\xc6\x47\x70\x6c\x1d\x53\x97\x71\x2c\x93\x28\xf6\x39\x70\x60\ -\x9e\x76\x20\x04\x28\x86\x05\x7e\x08\x5e\x18\x50\x1d\x19\x23\x4a\ -\x32\xfc\x10\x7a\x7d\x8f\x14\x09\xc5\x30\xb1\xab\x65\x70\x54\xee\ -\x6e\xac\xf3\xfe\xf2\x0e\x7f\xf4\x8d\x3f\xe7\xeb\xdf\xfa\x1b\xae\ -\x2d\xdd\xc5\x2a\x56\x08\x92\x94\x30\xce\x28\x96\x2b\x84\x61\x84\ -\x2a\x41\x12\x82\x9a\xa6\x14\xa4\x8c\x27\xcf\x9e\xe6\xd3\x8f\x3f\ -\xce\xa3\x27\x8e\xf2\xa5\xcf\xfc\x38\x8f\x9d\x3b\x42\xaf\x16\xf0\ -\x1b\xbf\xf6\x13\x4c\x8e\x94\x69\xd4\x77\x28\x97\x5d\x92\xd8\xc7\ -\xf3\xbb\xc4\x31\xe8\x26\xf8\x52\xca\xc8\x74\x01\xd7\x76\xa8\x6d\ -\xef\x12\xf4\x03\x5e\x7a\xe9\x25\x3e\xb8\x71\x13\xc9\x2d\x60\x39\ -\x2e\xd5\xe9\x69\x88\x62\x6c\xcd\xc2\x30\x1c\xb1\x1b\x8c\x22\x82\ -\x56\x9b\xb8\xd3\x06\x15\xb4\x52\x01\x6d\xb4\x02\x59\x8c\xa4\x09\ -\xbd\xf5\xc0\xf7\x30\x6c\x4b\xc8\x84\xfb\x3d\x12\xb2\xdc\xd6\x98\ -\x90\x26\x31\xb2\x22\x21\xc9\x02\xd1\xa3\x2a\x0a\xd1\x20\x20\x1e\ -\x04\x98\x96\x43\x61\x7c\x02\xb5\x50\x24\x4d\x12\x3a\xfb\x11\xa6\ -\xb9\x1b\xca\x70\x1c\x50\x35\xe8\xf4\x08\xfb\x3d\x6c\x4d\xc0\xf0\ -\x93\x28\x42\xb7\x2c\x14\xdb\x86\x6e\x97\x38\x5f\x81\xe9\xba\x4e\ -\xb7\xd9\x44\x55\x55\x4a\xa5\x92\x38\x7c\xfd\x3e\xe4\x18\xde\x62\ -\x51\xc8\x74\xc7\xa6\xa7\x51\x2d\x8b\xa0\xd9\x24\xcb\x32\x41\xeb\ -\x0c\x43\xc2\x56\x0b\xdb\x15\x03\xbe\x34\xc7\x0b\xed\xb7\x6b\xba\ -\x66\xe6\x8a\xb0\x84\x5e\xbf\x4d\x14\x07\xe8\x9a\x46\xb3\x56\x87\ -\xea\x18\xb5\xcd\x4d\x24\x45\x45\xb1\x2c\xac\x42\x91\x57\x5e\xfb\ -\x3e\xb5\x5a\x97\xf9\xd9\x59\xe2\x30\x66\xf9\xfe\x4a\x26\xab\xaa\ -\x20\x84\x00\x72\x98\xa4\x28\xc8\xf4\x6a\x7b\x19\x69\x8c\x17\xc6\ -\xf4\x52\xbe\xb3\xd1\xed\x50\xf3\xfb\xc8\x52\x0a\x5e\x97\x0a\x1a\ -\xad\x95\x2d\x46\x2c\x78\xb0\xbc\xc5\x33\x1f\xfb\x18\x4b\xcb\xb7\ -\xf9\xde\x77\xff\x33\x23\x45\x13\x32\x8f\x43\x8b\x0b\x4c\xcc\x8c\ -\xb0\x53\xdb\xc3\x47\x26\xcc\x24\x54\xa3\xc8\x8d\x5b\xf7\x78\xec\ -\xd2\xd3\xc4\xa1\xc2\xcc\xf4\x21\x1a\xb5\x3e\x81\x9f\xb1\x57\x6b\ -\x71\xe7\xce\x1d\x9e\xf9\xe8\xe3\x64\x69\x82\x37\x48\x29\xb9\x36\ -\x9a\x2c\xb3\x30\x3b\xcb\x7b\xef\xbd\xcb\xc4\xec\x34\x66\x51\x01\ -\x53\x23\x50\x41\x2d\x39\xf8\xc0\xab\x6f\xbd\xc3\xd4\xc1\x03\x38\ -\xe3\xa3\xd4\x06\x30\x3e\x3e\x86\xed\xa8\x6c\x37\x6b\xdc\xdd\x5a\ -\x61\xa3\xb3\xcb\xe9\x47\x8f\x72\x70\xb2\xc2\xcf\xfc\xf8\xa7\x28\ -\x66\x60\x29\x0a\x7e\x14\xd0\xf2\xba\x28\xa6\x8e\x6a\x28\x28\xaa\ -\xe8\xc3\xa6\xa6\xa6\xe8\x74\x3a\xac\xae\xae\x32\x31\x31\x7c\xc0\ -\xaf\x88\x00\x00\x20\x00\x49\x44\x41\x54\x91\xdb\xe8\x20\xc8\x2d\ -\x76\x9d\x8e\x48\xc1\x38\x79\x78\x86\x7e\x3f\xc2\xb2\x2c\xfa\xfd\ -\x94\x4a\xa5\xc2\x3b\xef\xbc\xc3\xe2\xe2\x22\x05\x57\x94\x55\x47\ -\x8f\x1e\xe5\xb1\xc7\xce\xd1\x68\x34\x50\x55\x95\x1f\xbd\x7d\x23\ -\xd7\xfd\x8a\x5d\x73\xab\xd5\x62\x72\x72\x52\xac\xef\x92\x44\x84\ -\xd9\x05\x03\xd6\xd6\x1e\x70\xe0\xd0\x02\x9d\x5e\x9b\xb1\xf1\x02\ -\x8d\x6e\x42\x2a\x43\xcf\xf3\x31\x5d\x05\x59\xd7\xf1\x92\x94\x54\ -\x56\x91\x74\x13\x4c\x8b\x58\x97\xd9\xee\x06\xc4\x8e\xc9\x95\xdb\ -\x37\x79\xed\xbd\x77\x28\x4f\x4f\x73\xfe\xf2\x63\x84\xc8\xf4\x06\ -\x29\xaa\x55\xa4\xde\x19\x10\xcb\x32\x61\x92\xa1\x48\xe0\x18\x19\ -\x25\x3d\xe1\xa3\x27\x8e\xf0\x33\x9f\x7c\x8e\xaf\x7e\xe9\x59\x8e\ -\x2e\x54\x18\x2d\xc2\x7b\x6f\xbc\x41\xb7\x06\x8b\x33\x93\x98\x1a\ -\x74\x5a\x7b\x8c\x54\x5d\xe4\xd8\xe7\x3f\xfd\xe1\x7f\x00\x05\xce\ -\x3e\x7e\x01\x2f\x83\xb0\x1f\xb0\x38\x3d\x8f\x65\xd8\xe2\x66\x95\ -\x61\x7c\x7a\x0a\xaf\xdf\xa3\x51\x6b\xe0\xd8\x2e\x51\xbb\x47\xd0\ -\x68\x43\x18\x0b\x84\xae\xa6\x41\xa5\x88\x52\x72\x91\x6c\x95\x28\ -\xee\x43\xc9\x21\x08\x07\x78\x71\x40\xa1\x5a\x62\xe0\x79\x62\x50\ -\x66\x19\x24\x51\x08\x64\xa8\xaa\x4c\x18\xf6\x49\x62\x1f\x53\x07\ -\x59\x95\xf0\x9b\x1d\x14\x4c\x6c\xbb\x84\xae\x98\x24\x49\x96\xcb\ -\x24\x64\x88\x42\xfc\x28\x14\xe5\x38\x29\x71\x14\xe0\xe6\x09\x8c\ -\xf8\x3e\xfd\x76\x8b\x2c\x0a\xc1\xd0\x08\xb3\x84\x4c\x96\x50\x47\ -\x46\x00\x68\xd5\x6a\x24\x61\x44\xa9\x5c\x21\x8b\x13\x06\xdd\x5e\ -\xbe\x16\xb2\x84\xa5\x72\xa8\x00\x4b\xe9\xf5\x3a\x28\x8a\x84\xe4\ -\x58\x78\x83\x01\xad\x56\x4b\x1c\x7a\xdb\x26\x08\x42\xca\xe5\x0a\ -\xc4\x09\xba\x6e\x10\x04\x21\xb5\xdd\x3d\x02\xcf\x47\xad\x94\x50\ -\x46\x8b\x10\xb6\xe9\x74\x6b\x8c\x8c\x55\x08\xfa\x03\x64\x49\x45\ -\x2b\x8c\xb0\xd5\xea\xf2\xe2\xdb\xef\x13\x16\x25\xa6\x17\x8f\xf3\ -\x60\x75\x8b\xd6\x56\x83\x64\x10\xd0\xea\x76\xe8\x04\xbd\x2b\x43\ -\xf8\xde\x7e\xc3\x5f\x9d\x18\x97\x08\x43\x2c\x43\xe5\xc1\xfa\x0e\ -\x5e\x96\xb1\xbc\xbe\x4e\xab\xd5\xe0\xd8\x81\x05\x8e\xce\xcf\xf3\ -\xfc\xd3\xc7\xb9\x75\xb5\xc9\xd4\xe4\x34\x53\x53\x45\xee\xdc\xb9\ -\xc3\xbd\xa5\xdb\x24\x89\xc7\xe2\xa1\x05\x0c\x53\x54\x0b\xaa\x65\ -\x10\xc5\x09\xfd\x41\xc8\x3b\xef\xbe\xcf\xa9\xd3\xe7\x89\x63\xf0\ -\xfc\x98\x62\x41\xc3\x2d\x16\x49\x33\x99\xdb\x77\x97\x38\x7e\xf2\ -\x04\xdd\xae\x60\x76\x19\xaa\x4c\x1c\xc4\x34\xf6\x6a\xdc\xbc\x79\ -\x93\xa7\x9e\x7a\x8a\x9d\xdd\x5d\x76\x76\xbb\xf8\x71\xc4\x20\x8c\ -\xf1\xa2\x90\xfb\xeb\x9b\xc8\xba\x86\x55\x70\xd1\x6c\x8b\x5a\xab\ -\x49\xc5\x55\x28\x16\x0b\xa4\x4a\xca\xf2\xda\x12\x33\x07\xc6\x31\ -\x6d\x95\x85\x99\x29\x26\x4b\x0e\x86\x24\x21\x25\x09\x1f\x5c\xbd\ -\xca\xcc\xec\x2c\xd5\x91\x22\x71\x22\xac\x89\x33\x33\x55\x3c\xcf\ -\x63\x77\x77\x97\xd9\xd9\x59\xd6\xd7\xd7\x69\xb5\x5a\xc3\x54\x86\ -\xe9\x8a\xc9\xda\xda\x1a\x13\x13\x13\x34\xfb\xe9\x10\x8b\x23\xcb\ -\x32\xad\x56\x8b\x72\xb9\x4c\xb5\x5a\xa2\xdb\x4b\x70\x5d\x17\x4d\ -\xd3\xd8\xd9\x69\x33\x3a\x3a\xca\x99\x33\x67\xb0\x2c\x8b\xb7\xdf\ -\x7e\x9b\x2b\x57\x3e\x20\x08\x82\xa1\x4c\xb3\xd1\x68\xe2\x16\x4b\ -\x64\x92\x4a\x14\xa7\xf4\x3d\x7f\x08\xce\x4b\x33\xc8\xe2\x08\x45\ -\x12\xe5\x5d\x14\x8a\xe7\xda\x30\x64\x6c\x57\x63\x73\x67\x17\x59\ -\xd5\xe8\x0c\x62\xec\xa2\x81\xa4\x19\xac\x6e\x6d\xe1\x54\x47\xb8\ -\xb1\xbc\xcc\xbf\xf8\x97\xff\x92\x3f\xf9\xf3\xbf\xc0\x28\xaa\x20\ -\x29\xc8\xb2\x8a\x65\x18\x18\x86\xa0\x99\x7b\xe9\x80\x66\xb7\x46\ -\x41\x83\xb2\x05\x71\x20\x9e\xd1\xef\xff\xe0\x2a\x3b\xdb\xeb\x18\ -\x0a\xfc\xea\x2f\x7d\x96\x13\x87\x0f\x52\xb6\x4c\x5a\x9b\x9b\x54\ -\x74\x93\xb8\xd7\xa7\xa0\x0a\x04\xaf\xac\x42\xa1\x50\xa2\x52\xaa\ -\x32\x3b\x3b\x8f\x65\x3b\x0c\x82\x90\x5a\xb3\x25\xa6\xcf\x9e\x47\ -\x34\xf0\xc9\xc2\x18\x15\x59\xa0\x9d\x54\x4d\xe8\x09\x15\x99\x54\ -\x91\x90\x54\x50\x6c\x13\xc3\x16\x39\x47\x61\xab\x45\xab\xd5\x12\ -\x3d\x6e\xb1\x88\x6a\x58\x10\x45\xf4\x9a\x4d\xe2\x30\xa4\xe0\xb8\ -\x18\xaa\x82\x37\xe8\x92\xb6\xdb\x90\x4a\x48\x92\x02\xc8\x02\x80\ -\x97\xc9\xe8\xa6\x85\x64\x99\xa0\x7e\x98\x5a\x91\x24\x82\xc0\x21\ -\x91\xa1\xca\x12\x12\x10\x0f\xfa\x20\xcb\xe8\xa6\x89\x61\x0a\xe3\ -\x46\x96\x65\x02\xee\x28\x09\xa0\x7d\x12\xc5\xc8\x48\x1f\xda\x26\ -\x83\x60\x28\x16\x51\x35\xc1\x5d\xdb\xdf\x35\x1b\x86\x21\x36\x40\ -\x51\x44\x96\x5b\x1e\x2d\xcb\x12\xfa\xec\x9c\x46\x12\xe7\xab\x28\ -\x72\xcc\x10\x52\x0c\xa6\x82\xee\x98\x6c\xef\x6d\x53\x2a\x14\x49\ -\x83\x18\x09\x15\x59\xb7\xb8\xbd\xbe\xc1\x5b\xd7\xd6\x50\x2c\x97\ -\x7a\xb3\xcd\xec\xd4\x2c\x72\x26\x13\x46\x11\x45\xa7\x74\xf1\x43\ -\x58\x66\x8e\x26\x21\x8a\xf0\xfa\xfd\xdf\x6b\x74\x7a\x59\xbd\xd5\ -\xc6\x75\x5d\xec\x87\x90\xb2\xcf\x3e\xfb\x34\xba\x04\x6b\x6b\x0f\ -\x98\x99\x29\x13\x25\x42\x72\xd6\xef\x74\x79\xfe\x63\xcf\x31\x36\ -\x52\x1a\xd6\xeb\xe5\x62\x89\x5e\xb7\xcb\xc6\xc6\x06\x96\x65\x51\ -\xad\xda\x74\xba\x5d\x2a\x15\x8b\x56\x2b\x66\x71\x71\x91\x2b\x57\ -\xae\x50\x2e\x97\xd1\xf2\x7d\xa0\x98\xe8\x81\xa6\xa9\xc3\xbe\xd2\ -\x75\x1d\x66\x66\x66\xd8\xd8\xd8\xc0\x34\x35\x1c\x47\xf0\x81\x6b\ -\xb5\x1a\x67\xcf\x9e\xc9\xfb\x10\x98\x9a\xaa\xb0\xb9\xd7\xa3\x5a\ -\xad\xb2\xbe\xbe\xce\xc9\x93\x27\x59\x5a\x5a\xa1\xdf\xef\x33\x3b\ -\x59\xa2\x56\x6b\x61\x9b\xb0\xb6\xb6\xc6\xe8\xe8\x28\x73\xb3\x23\ -\x74\xbb\x3e\x9e\xe7\xe5\xbb\x62\xd1\xcf\xec\xf7\xb9\xa5\x52\x89\ -\xdd\xdd\x5d\x6a\x35\x31\xc4\xb8\xb3\x56\xa3\xdd\x6e\x33\x35\x35\ -\x85\x24\x49\x8c\x8f\x17\xa9\x96\x84\xf4\x72\x7b\x7b\x9b\xb1\xb1\ -\xb1\x0f\x23\x68\x01\x55\x95\x58\x59\x59\x61\x7a\x7a\x1a\xc7\x71\ -\x38\x71\xe2\x20\xcf\x3c\xf3\x34\x67\xcf\x9e\xa5\xd5\x6a\x71\xe5\ -\xca\x15\x56\x57\x57\xb9\xb7\xf2\x80\xbd\x5a\x87\x28\xd5\x90\x15\ -\x13\xc7\xad\xe2\x0f\x22\xb2\x28\x25\x0d\x60\xaa\x62\x92\x05\x29\ -\x05\x53\x43\x4e\x33\x74\x19\xa4\x9c\x35\x58\xdf\xde\x66\x7a\x6c\ -\x82\x83\xae\x8a\xdf\x49\x28\x3b\x25\xfa\x7d\x8f\xa5\xfb\x0f\x18\ -\x99\x9d\x61\xbd\x51\x67\xee\xf8\x51\xe2\x14\xbc\xbe\x47\xd2\x0b\ -\x91\x83\x8c\xc8\x4b\x89\xd2\x04\xa9\x60\xa1\x8f\x16\xd8\xa8\x6d\ -\x31\x6a\x40\x2c\xa5\xfc\xf3\xff\xed\x5f\xb1\xba\xb5\xce\x83\xcd\ -\x55\xee\xdd\x5b\xa5\xd3\x81\xc5\xe9\x59\x24\xcf\xe7\xb9\x0b\x97\ -\x19\x37\x6d\xfe\xf9\xff\xf0\xdf\x90\xf5\x61\xb2\xa0\xa2\x01\x33\ -\xb3\x13\x28\x96\x83\x6e\x3b\x84\xa9\x44\xe8\x07\x24\x03\x4f\xac\ -\x66\x52\x86\xbd\xa2\xae\xeb\x18\x9a\x9e\x4f\x98\x25\x48\xc5\x7e\ -\x95\x18\x54\x14\x41\x26\xc8\x24\xd0\x0d\x6c\xd3\x46\x91\x54\xfa\ -\xdd\x01\xb6\xe9\xa0\x9a\x36\x24\xa9\x70\x0b\x79\x21\x7e\x4f\x34\ -\xea\xc6\xe8\x38\xe8\x1a\x68\x02\xca\x18\xa7\x42\xaf\xad\x29\x2a\ -\x86\xaa\x81\xaa\x92\x85\x11\x49\x10\xa2\xe6\xfb\xdf\x20\x0a\x85\ -\x31\x43\xcb\x71\xef\xfb\x70\x00\x45\x11\x13\xf3\x7c\xe2\xac\x28\ -\x0a\x49\x18\x0e\x83\xd3\xf7\x7b\x6d\x34\x6d\x98\x57\xb5\xff\xf5\ -\xde\xe7\x89\x0d\x23\x6a\xf2\x68\xd5\x7d\x05\xda\x3e\x7f\x2e\xcd\ -\x07\x64\xaa\xaa\x42\x3e\xc8\x4b\x92\x04\xd3\x75\x91\x24\x09\xbf\ -\xdf\xcf\xfb\x5c\x15\x49\x91\x71\x0a\x2e\x9e\xef\xb3\xb1\xb1\x81\ -\xeb\xba\xb8\x0f\x41\x13\xae\x5e\xbd\x4a\xa3\xdf\xca\xfe\x41\xd0\ -\xb9\x65\x1a\xa0\x29\x58\x95\xf2\x6f\x3a\xb6\x2b\xb5\xdb\x6d\x52\ -\x32\x76\x77\xb7\x39\x7a\xec\x30\xff\xee\x5f\xfd\xaf\x94\x8a\x2e\ -\x7f\xf2\xa7\xdf\x63\x6b\x6b\x83\x56\x3b\xa4\xd7\x8b\xf0\x03\x8f\ -\x67\x9e\xfe\x28\x8f\x5d\xbc\x80\x94\x42\x1a\x65\x98\x06\xcc\xcf\ -\xcc\xf2\xfe\xfb\xef\xa1\x69\x1a\xc7\x8e\x1d\xa3\xde\x18\x30\x3a\ -\x5a\xa1\xef\xa5\x68\x86\xca\x6e\xad\x26\xe2\x25\x6d\x6b\x38\xe6\ -\xdf\x7f\xab\x6d\x6f\x8b\x09\xf1\xdc\x4c\x95\x56\xab\x4d\xb1\x58\ -\xa4\x50\x28\xf0\xc1\x07\xd7\x49\x53\xd8\xdc\xdc\x64\x76\x76\x16\ -\x49\x12\xfb\x47\x57\x87\xb5\xb5\x3d\xc6\xc7\x5c\xea\xf5\x3a\x92\ -\x24\x51\xad\x56\x19\x19\x19\x61\x79\x79\x99\x56\x7e\x4b\x6e\xed\ -\x74\xd8\xda\xda\x62\x72\x72\x92\xfe\x40\x08\xd8\x0b\x05\x6b\x78\ -\x00\x6f\xdf\xbe\xcd\xc5\x8b\x17\x86\x7b\xc8\xd3\xa7\x4f\xb3\xb9\ -\xb9\x39\xdc\x27\x5f\xbe\x7c\x99\xf1\x82\x9a\x2b\xbe\x12\xbc\x10\ -\x6a\xb5\x1a\x61\x18\x52\xad\x56\x69\xb7\x7b\xd8\xb6\x95\xef\x07\ -\x63\xfa\xfd\x3e\xe3\xe3\xe3\xa8\xaa\xc4\xf6\x76\x8b\x56\xab\x3d\ -\x84\x0a\x7e\xe5\x2b\x5f\x61\x66\x66\x86\x83\x07\x0e\x73\xeb\xce\ -\x03\xae\x5e\x5f\xe2\x9b\xdf\x7a\x11\xdf\x8f\x08\xfc\x10\x53\x33\ -\x09\x06\x1e\x9d\x56\x40\x7d\x6b\x83\xf9\xc9\x09\x2c\x4d\xc2\xd2\ -\x20\x1c\xf8\x74\x9a\xc2\x41\x35\x52\x29\xd2\x4b\x40\x97\x14\x2c\ -\x5d\xe5\x53\x3f\xf6\x59\x16\x16\x8f\xf0\xea\x0f\xdf\x62\xec\xd0\ -\x41\x2e\x3e\x7e\x06\x34\x30\x4d\x9b\x11\xb7\x48\xc1\x10\x6c\xa8\ -\x5e\xe0\xd1\x57\x33\xe4\x82\x85\x65\x99\x34\xfc\x04\xd3\x90\x19\ -\x9b\x1c\xe7\xbd\xeb\xef\xd2\xf5\x7b\xc4\x59\x4c\xab\xde\xe5\xbd\ -\x2b\x6f\xe3\xc8\x1a\x27\x0f\x1d\xe1\xa7\x7f\xe2\xcb\xec\x6d\x0c\ -\x90\x62\xe8\xf7\xa0\xe3\xc1\x95\x6b\x4b\x7c\xe7\xd5\xd7\x78\xff\ -\xc6\x1d\x7a\x7e\x80\x5b\x19\x43\x2d\x95\x91\x9d\x02\x78\x1e\x92\ -\xa2\x0e\xad\x7d\xc3\xb8\xd7\x24\x15\x58\x9c\x20\x24\x0d\x22\xe4\ -\x24\x13\x43\x2f\x14\x74\x45\x47\x97\x14\x4c\x55\x44\xec\x66\x51\ -\x8c\xa1\x99\x90\x49\x64\x5e\x40\x18\xc6\xe2\xb1\x55\x75\x1c\xa7\ -\x80\x55\x70\xc5\xe6\x23\x4d\x84\x69\x41\x12\x7b\xde\x34\x4e\x84\ -\xce\xff\xa1\x43\x95\xc9\x22\x42\x26\x09\x03\x34\x43\x47\x2e\xb8\ -\x43\xb9\x65\xe0\xf9\x48\x69\x86\x9a\x3b\x94\xa4\x87\xb2\x9a\x22\ -\xdf\x27\xf4\x7d\x50\x64\xec\x52\x09\x35\x0f\x0a\x48\xba\xdd\xe1\ -\x8b\x4a\x7e\xc8\x18\x91\x0b\xef\x49\xd3\x74\x38\xe0\x1a\xee\xb7\ -\x73\xae\x35\x79\xc2\x28\x69\x8a\xae\x6a\x04\x41\x80\x69\x5a\x34\ -\xea\xf5\x61\x7f\x6e\x9a\x26\x81\xe7\xb1\xb6\xbe\x89\x66\xe8\x9c\ -\x3c\x75\x82\x30\x4e\x39\x7a\xe2\x24\x96\xeb\x50\x74\xca\xc3\x10\ -\x28\x39\x21\x11\xf1\x96\x69\x42\xe8\x0d\xd0\x54\x78\xb0\xba\x3a\ -\xdc\x79\xfd\xd8\x27\x9e\xa7\x9f\x40\xa7\x55\xa7\xe0\x9a\x5c\xba\ -\x7c\x81\x3b\x77\x6e\x61\xbb\x1a\x0b\x0b\x0b\x7c\xe6\x85\x4f\xd1\ -\xae\x35\x50\x11\x22\x03\x25\x13\xeb\x95\xdd\xdd\x5d\xaa\xd5\x2a\ -\x71\x9c\xe2\x38\x36\x51\x92\x61\x18\x32\xf7\x57\xd7\xf1\xc3\x80\ -\xf3\x8f\x9e\xa3\x5e\xaf\x0f\x71\x28\xb2\x2c\x53\xaf\x8b\x1e\xf5\ -\xe8\xd1\x45\xd6\x36\x1a\x43\x99\xe3\xc1\x83\x33\x74\xbb\x5d\x5e\ -\x7f\xfd\x47\x1c\x3c\x78\x90\x91\x91\x2a\xfd\xbe\xc7\xe8\x68\x89\ -\xcd\x5a\x9f\x6a\xb5\x4a\x10\xc2\xca\xca\x0a\x97\x2f\x3f\x32\x34\ -\x85\x1f\x3c\x78\x90\xb7\xde\x7a\x0b\xd7\x55\x59\x59\x59\xe1\xfc\ -\xf9\xf3\xb8\xae\xc8\x49\x2a\x14\x1c\x82\x20\x41\xd7\x25\xee\xdf\ -\xbf\x4f\xa9\x54\x42\xd3\xa0\xd9\x6c\x32\x31\x51\xc2\xb6\x65\xc6\ -\xc7\xc7\x87\x61\x62\x9e\xe7\xf1\x60\xb7\x3b\xd4\x06\x77\x3a\x42\ -\xda\x37\x35\x35\x85\x69\x0a\x09\x9f\x65\x0a\xd1\xc5\xf6\xf6\x36\ -\xe3\xe3\xe3\x68\x9a\x84\xef\x47\x14\x8b\x45\xe6\x26\x85\x77\x75\ -\x63\x63\x03\x3b\xcf\x3a\x9a\x98\x70\x99\x98\x39\xc0\xe1\x63\x67\ -\xa8\x54\xa7\x38\x7d\xfa\x02\xbb\xdb\x7b\x5c\xf9\xd1\x8f\xb8\xf6\ -\xde\x7b\x6c\xdc\x5f\xe1\x3b\xdf\xfa\x16\xe1\xa0\x4f\x73\xaf\x86\ -\x22\x83\xe3\x88\x54\x06\xdb\x2d\x20\xab\xd0\xed\x81\x65\x42\x16\ -\xc3\xcb\x2f\x7d\x1f\xd3\x2c\x71\xfe\xd2\x13\x54\xe7\xe6\x79\xe9\ -\xdd\x3b\xec\xf5\x20\x8a\x53\xe4\x54\xc2\x04\x6c\x5d\x13\x2a\x23\ -\x55\x25\xb3\x74\x1a\xdb\xdb\xc4\x9d\x1e\x2e\x30\x33\x31\x8e\xef\ -\x0f\x38\x7b\xf6\x0c\x69\x16\xf3\x07\x7f\xf0\x07\x7c\xf9\xf3\x5f\ -\xe4\x97\xbe\xfa\x0b\x1c\x3b\x70\x98\x6f\x7f\xf3\x3f\x13\x84\x09\ -\x6f\x5f\x5f\xe6\xaf\xbe\xfb\x2a\xff\xc7\xbf\xfd\x03\x8e\x3c\x72\ -\x18\xbd\x5c\xa1\x17\x27\x78\x31\xf8\x71\x42\x9c\x64\x18\xa6\x0d\ -\x23\xa3\xf9\x81\x50\x87\x53\x67\x81\x2d\x16\xa0\x77\xa2\x04\xe2\ -\x04\x47\xb7\x31\x75\x0b\x09\x89\xb0\xdd\xa1\xbe\xd7\x40\xca\x64\ -\x2a\xa5\x2a\xbd\x4e\x3f\xaf\x18\x13\x88\x12\x2c\xd3\xa6\x5c\x1d\ -\x45\x51\x75\x1a\xb5\x3a\x8a\xa1\x13\x65\x11\x69\x1c\x90\xc9\x19\ -\x92\x94\x11\x86\x42\x07\xad\xab\x1a\xaa\x6e\x0c\x81\x78\xbe\xef\ -\x0b\x34\x8e\xae\xa1\xda\x22\x71\x11\x45\x25\xf5\x02\x62\xcf\x47\ -\xce\x6f\xe3\x7d\x6a\xa7\xaa\xaa\xa4\x49\x9c\x13\x4e\x32\xa4\x9c\ -\xe2\xa9\xe7\x59\xce\xa8\x0a\x71\x9e\x31\x25\x49\x92\xf0\x33\x47\ -\x91\x90\x94\xe6\xd0\xbf\x20\x8f\xb4\xc9\xb2\x0c\xcb\xb2\xc4\xdf\ -\xd9\xed\xa2\xe4\x92\x51\x2d\x47\x0a\x09\xed\xb5\x0d\x83\x01\x71\ -\x9e\x3e\x11\x44\x09\x86\xe3\xb0\xbc\xbc\x8c\x5b\x2c\x90\x02\x51\ -\x12\xb3\xb5\xb5\x85\x61\x58\xbc\xf3\xfe\x3b\xc3\x1b\x59\xf9\xed\ -\xdf\xf9\x5d\x74\x55\x26\x0b\x06\x87\x34\xc7\x6d\x76\x53\xe5\xd0\ -\x6a\xa3\xf3\x4f\xba\xc8\xe8\xb6\xc5\x57\xbe\xf4\x39\x06\xdd\x2e\ -\x52\x94\x72\xf8\xd0\x61\xbc\x41\x48\xaf\xdf\xc5\x34\x64\xee\xdc\ -\xbd\xcb\xe4\xd4\x14\x9a\xaa\x52\x74\x6d\x2c\x1d\xf6\xb6\x1b\x6c\ -\x6f\x6e\x71\x74\x71\x91\xdd\x9d\x1d\x26\x26\x27\x51\x65\x89\x6e\ -\xb7\x8f\x5d\xd0\x79\xed\xfb\x6f\x72\xe9\x23\x17\x51\x75\x03\x59\ -\x51\x58\x5e\x5a\x62\x76\x76\x1a\x55\x95\xf8\xe0\x83\x6b\x2c\x2c\ -\x2c\xe0\xba\x0e\x62\xaa\xaf\x21\x49\x32\x96\x29\xd3\xed\x89\x52\ -\x78\x6c\x6c\x4c\x98\xcb\x01\xdb\x56\xc8\x32\xa1\x4a\x7b\xe3\x8d\ -\x37\xb9\x78\xf1\x22\xfd\xbe\x28\x63\x2a\x45\x8d\x0c\xb1\x42\xb8\ -\x76\xed\x16\xba\xae\x73\xe8\xd0\x0c\xb6\x06\x99\xa4\x13\xc7\xc2\ -\xc3\xba\xba\xba\x2e\x76\x85\x92\x44\xb1\x58\xa0\x50\xb0\xd9\xdd\ -\x6d\x31\x5a\x30\x69\xf7\x02\x5a\xad\x16\x47\x8e\x1c\x61\x69\x69\ -\x89\x56\xab\x35\xdc\x4d\xd6\x6a\x35\x4c\xd3\x64\x7a\x7a\x1a\xc1\ -\x2d\x57\x48\x52\x19\x45\x81\x1b\x37\x6e\x72\xe0\xc0\x01\x64\x59\ -\xec\x8b\x35\x4d\xc3\x0f\x33\xf6\xf6\xf6\xa8\x56\xab\x4c\x4d\x55\ -\xd0\x34\x83\x7a\x63\xc0\xcc\xac\x4b\x7f\x00\xeb\x9b\xdb\x9c\x3e\ -\x35\x4f\xa1\x58\x61\x6a\x62\x8c\xc9\xd1\x11\xca\xc5\x02\x52\x96\ -\x72\xea\xe4\x09\x6e\x5c\xbf\xc9\xcd\x3b\xcb\xdc\xbd\xbf\xca\x76\ -\xa3\xc9\x83\xad\x3d\xca\xe3\xf3\xac\x6e\x37\xd1\x4c\x9b\xab\x57\ -\xef\xf3\x89\x4f\x3d\xce\x95\x6b\x4b\xdc\x5a\x7d\xc0\x5a\x7d\x8f\ -\xab\x37\x6e\xf0\xf8\x85\xc7\xc0\xf3\xd1\xfa\x01\x46\x26\x76\x57\ -\xb1\x06\x03\x5d\x26\x22\x46\xa9\xf5\x99\xae\x4c\x60\xd8\x2a\x72\ -\xb1\xc2\xad\xbb\xcb\xfc\xf0\xed\xb7\x19\x78\x21\x87\x8e\x1c\xe3\ -\x87\x6f\xbf\x8d\x63\xd9\x8c\x8f\x8c\x51\x2c\x96\x99\x9e\x9d\xe5\ -\xda\xf2\x32\x7f\x7f\xe5\x4d\x6a\x51\xc8\xd5\xbb\x9b\xbc\xf9\xfe\ -\x35\x1a\xcd\x26\xa5\xa9\x19\x21\x6d\x94\x35\x31\x74\x0a\x62\xb2\ -\x44\x42\x91\x65\x14\x24\xd2\x2c\x16\x96\x7f\x39\x23\x95\x84\x88\ -\x43\x43\xc1\x54\x85\x00\x43\x91\x15\x92\x54\x12\x91\x40\xb2\x20\ -\x57\x26\xbe\x8f\x66\x5a\x22\x3a\x35\x83\x04\x09\x45\x55\x50\x55\ -\x8d\x4c\x91\xc9\x54\x51\x02\x93\xe5\xee\xa9\x5c\x17\xad\xca\x32\ -\x96\x69\xa2\xe4\xc9\x93\x99\x37\x10\xa5\xbc\x65\x60\x14\x5c\x64\ -\x4d\xcd\xd5\x61\xca\xd0\xb2\x28\xe7\x87\x34\x49\x12\xe2\x50\xf8\ -\xa2\xb3\x7d\x2a\xa7\xae\x23\xa9\x0a\xf1\x3e\x4f\x4c\x55\x30\x6c\ -\x87\xd8\xf3\x50\xd4\x3c\xfa\x77\x3f\x88\x3d\x27\x70\xee\x8b\x46\ -\xd4\xbc\xe4\x56\x55\x55\x88\x49\xda\x6d\xf4\x52\x89\x38\xf0\xb1\ -\x0a\x36\x7e\xdf\xa3\x6c\x15\x89\x82\x80\x30\x8e\x49\x82\x80\xe2\ -\xd8\x28\x9d\x56\x83\xb2\x6d\xb1\xb7\xbe\xc6\xcf\x7f\xf9\x73\x68\ -\x09\x1c\x9b\x9f\x63\xe9\xce\x2d\x3e\xf1\xc9\x8f\xd3\x6a\x36\x99\ -\x9d\x9c\xfc\x5d\x05\x09\xb5\xef\x77\x0f\x15\x4d\x73\xd9\xf3\xbc\ -\x7b\xae\x5d\x94\xae\xdf\x5c\xba\x97\x21\xf3\x17\xdf\xf8\x73\x26\ -\xe6\x66\xf0\x7c\x9f\xa9\x52\x81\x3f\x7e\xf1\xff\xe5\x57\x7e\xf1\ -\x57\x89\x2b\x12\x3f\x78\xfd\x15\x34\xd9\xe3\xa7\x7f\xfa\x4b\xfc\ -\xf1\x9f\xfc\x05\x5f\xf9\xca\x17\x09\xfc\x14\x59\x91\xd9\xda\xd8\ -\xc4\x75\x1c\x0e\x1e\x9c\xe1\xe5\x97\x56\x70\x1d\x99\xd5\xb5\x1a\ -\x53\x53\xa3\x7c\xf0\xc1\x1d\x8e\x1e\x3d\x9a\x3b\x85\x52\xe6\xe6\ -\xc6\x78\xb0\xbc\xcc\xf6\xf6\xee\x90\x0a\x31\x3f\x3f\x46\xb3\xe9\ -\x33\x51\xb5\xd8\x6b\x89\xb7\xdd\xd6\xb6\x08\xa3\xbe\x74\xe9\x12\ -\x2f\xbf\xfc\x32\xcf\x3e\xfb\xec\x30\x95\xc0\x34\x4d\x5a\xb9\x7b\ -\xa4\xdb\xed\x32\x3f\x55\x66\xa7\xe1\xd1\xee\x89\x41\xc7\xf1\x63\ -\xf3\xdc\xbe\x7d\x9b\xa9\xa9\x29\x3e\xf8\xe0\x36\x33\x33\x33\x94\ -\x4a\x2e\x71\x2c\xd4\x38\x41\x10\x50\x28\x14\x98\x9f\x17\x07\xd2\ -\x30\x60\x64\xa4\xcc\xdd\xd5\x3d\x82\x20\xa0\x5c\x2e\x73\x78\xa6\ -\x2a\xb0\x2f\x41\x40\xbd\x5e\xa7\xdf\xef\xb3\xb3\xb3\xc3\xf1\xe3\ -\xc7\x91\x65\xf0\xfd\x30\x57\xf5\xf8\x44\x51\x34\x24\x49\x88\xbc\ -\xa5\x22\xba\x0a\xdb\xbb\x5d\x36\x37\x37\x39\x76\xec\x18\x83\x41\ -\x3a\xac\x42\x82\x10\x6a\xb5\x36\x27\x8e\x1f\x45\x51\x41\xf2\x13\ -\xb2\x2c\xc1\xb1\x75\x74\x45\x21\xcd\x22\x0c\x43\x63\xf1\xf8\x71\ -\x24\xdd\x44\x2d\x9a\xf4\x63\x78\xf0\xd2\xeb\xec\x78\x21\xff\xe6\ -\x3f\xfd\x47\x6a\x7b\x4d\xe4\x08\x7e\x2e\xfc\x2a\x57\xae\xbc\xc7\ -\xb3\x3f\xf1\x69\xfe\xf6\xa5\x6f\x83\x2a\xf3\xda\x8f\xde\xe2\x90\ -\xe1\xd2\xf7\x33\xba\x3b\xbb\x68\x66\x46\x47\x09\x69\x55\x24\xd2\ -\x20\xa2\xfe\xea\x0d\x5a\x0f\x1a\x6c\xa8\x31\xc5\xc5\x05\xf6\x76\ -\x9b\x1c\x58\x3c\xca\xf1\xb3\x8f\x70\xee\xd1\x0b\x7c\xb2\x0a\xaf\ -\x7d\xef\x06\xb1\x69\x73\xe9\xf9\x93\xfc\x87\xff\xe7\xdb\xac\x35\ -\x76\xd9\x75\x4c\xb6\x36\x37\x99\x90\x2d\x52\xcd\x00\xd3\x22\x53\ -\x74\x3a\x83\x00\x55\x13\x19\x5e\xaa\xe3\x10\x37\xba\xc4\xb2\x42\ -\x2c\x89\xf4\x12\x45\x51\x04\x56\x2a\x13\x30\x85\x4c\x96\x09\x72\ -\x38\x9e\x6d\xdb\x28\x9a\x41\xa7\xdd\x26\x08\x84\x88\x48\x72\x0a\ -\x28\xaa\x8a\xed\x38\xf4\x55\x85\xa8\xdd\xa6\x9f\xc4\xb8\xd5\x2a\ -\x25\xb7\x40\xa3\xd7\x02\x53\x83\x44\x26\x8d\x43\xc2\x44\x42\x57\ -\x54\x34\x45\x26\x8d\x23\xe2\x30\x12\x2f\x88\xfc\xee\x52\x0c\x13\ -\x49\x51\x08\xa2\x90\x8c\x0c\x45\x96\x51\x91\x08\xa2\x98\xd8\x0f\ -\x88\x15\x35\x8f\x40\x95\x73\xff\xb2\xe8\xe9\xf7\xb9\x5c\x69\x9a\ -\x8a\x3f\x87\x80\x08\x90\xef\x8c\xd3\xdc\x8a\x29\xe7\x2d\x44\x9a\ -\xa6\x43\x8d\x76\xe0\x79\x38\x85\x02\x41\x9e\xeb\x4c\x0e\xdb\x47\ -\x96\xf1\x3c\x11\x8e\xbe\xcf\x0c\xd3\x6c\x87\xa8\xd7\x16\x11\x40\ -\x8a\x8a\xed\xba\x0c\x74\x8d\x8d\xad\x3d\x0a\xa3\x55\xac\xa2\xc2\ -\xbd\x95\x65\x2e\xf7\x1e\xe1\xea\xd5\xab\x3c\x7e\xee\xbc\x78\x59\ -\x38\xa6\xb5\x9c\x91\xe2\x8e\x54\xa5\x6e\xaf\x4b\xa7\xd7\x23\x4c\ -\x33\xda\xed\x2e\x4f\x3e\x7f\x1c\xc7\x34\xf9\xce\x4b\x2f\xf3\x4b\ -\x3f\xff\x55\x96\xef\xdd\xe6\xc8\xc9\x13\xdc\xbc\x79\x93\xe7\x9e\ -\xfb\x08\xbb\xb5\x26\x6b\xab\xf7\xe9\x36\x7b\xe8\xaa\x46\x24\xe9\ -\x78\x83\x01\xcf\x5d\x3a\xcd\x9b\xef\xdd\xe6\xe4\xc9\x93\xac\xdc\ -\xdf\x61\x6a\x6a\x82\x7a\xbd\x83\xe7\xfb\x9c\x39\x7e\x94\x2c\x97\ -\x74\xb7\xda\x01\xcf\x3d\xfb\x18\x7f\xf5\xd7\x2f\x52\x2a\x95\xf8\ -\xc8\x47\x2e\xb1\xb6\x56\x63\x76\x76\x94\xb5\xed\x36\x13\x13\x25\ -\x7a\xbd\x98\xd5\xd5\x55\x4e\x9d\x3a\x45\xab\xd5\xe2\xd4\xa9\x53\ -\xec\xec\xec\x30\x37\x27\x28\x1d\x61\x18\x72\xed\xda\x35\x5e\x78\ -\xe1\x69\x6a\xb5\x3e\xfd\x50\xf4\x48\x86\x61\x20\x49\x12\xdf\xfe\ -\xdb\x57\xf8\xc4\x27\x3e\x41\xa7\xd3\x21\x4d\x53\x76\x76\x76\x28\ -\x95\x5c\x0c\x43\xe3\xea\xd5\xeb\x4c\x4c\x4c\x30\x36\x56\xa5\xd7\ -\xf3\xa9\x54\x4c\xf6\xf6\x7a\x8c\x8d\x09\x59\x60\xbd\x5e\xe7\xf2\ -\xe5\x73\xac\x6c\xb7\x19\x1b\x2b\x01\xa2\x77\x99\x9a\x9a\xa2\x5e\ -\xaf\xf3\xe0\xc1\x03\xc6\xc6\xc6\x86\x5f\x38\x5d\xd7\xd9\xda\xda\ -\x62\x66\x66\x86\x34\x4d\x71\x5d\x85\x5a\xad\x4f\xa1\xe0\x0c\x07\ -\x1f\x62\x90\x22\xd3\x6e\x77\x98\x9a\x28\xd2\xef\xc3\xfa\xea\x7d\ -\x2e\x5e\x3a\x47\xab\xe1\x63\x5b\x2a\xa6\x65\x10\xf9\x03\x6a\xad\ -\x3a\xaa\xa6\x91\xc8\x50\x9d\x2c\xd3\x8b\xa0\x97\xc2\xdd\xad\x26\ -\xdf\xfc\xee\x2b\x2c\xac\x6f\xd3\x93\x25\xe4\xa2\xcd\x89\xd9\x23\ -\xe8\xa6\xcd\xaf\xfe\xa3\x5f\xa5\x7a\x70\x96\x57\xde\x7f\x07\xd3\ -\x36\xf8\xe0\xce\x5d\xe6\x2f\x7c\x84\xf9\xb9\x59\x16\x8a\x2e\xa6\ -\x0e\x8d\xb8\x47\xbb\x24\x61\xaa\x26\x2b\x5b\x32\xcf\x3d\xfb\x18\ -\x35\x17\xee\xf5\xe1\x7f\xfa\xdd\xdf\xe6\xd7\x7e\xe3\x9f\x72\xf7\ -\xeb\xdf\xe0\x7e\xbd\xc3\xd2\xfd\xfb\x78\x83\x80\xdb\x4b\x6b\x54\ -\xcb\x25\xfe\xee\x87\x3f\x42\x1f\x29\x11\x8f\x5a\xff\x3f\x55\x6f\ -\x16\x63\x67\x9a\x9f\xf7\xfd\xbe\x7d\x3b\xfb\x39\x75\xea\xd4\x4e\ -\xb2\xc8\xe2\xce\xee\x26\x9b\xbd\x4d\x7b\x46\xb3\x4f\x24\x79\xa2\ -\x08\x91\x1d\x49\x41\x60\x05\xb0\x92\x5c\xd8\x86\x01\x09\x76\xa0\ -\x20\x12\x62\x04\xf0\x45\x90\x40\xb9\x70\x6c\x27\x8a\x63\x1b\xb6\ -\x2c\x69\x14\x44\x1e\x69\xe4\x48\x9a\xcc\xa8\x7b\x66\x7a\x99\xde\ -\xb8\x34\xd7\x22\x59\x55\xac\xbd\xce\xfe\x9d\x6f\xdf\x72\xf1\x9e\ -\xaa\x1e\x5d\x11\x28\xd6\xc2\xc3\x3a\xef\xfb\xbd\xef\xf3\x7f\x9e\ -\xdf\x43\xf3\xda\x0b\x0c\xb7\xba\x38\x4e\x09\xfc\x80\x30\xcd\xc8\ -\xbd\x10\xa5\x55\x82\x24\x47\x56\x25\xd2\x3c\x27\x9b\x92\x1e\x91\ -\x24\x64\xb9\x40\x92\x14\xa4\x58\xf8\xaa\x13\x45\xc2\xd0\x25\x61\ -\xf2\x90\x65\x3c\x6f\x02\xa3\x21\xd4\xeb\x98\x8d\x06\x59\x91\x13\ -\x84\x1e\xb2\xc2\x14\xa6\x97\x40\x21\xaa\x53\x83\xc8\xa7\x50\x24\ -\x31\x73\x4e\x33\xe2\xe1\x08\xb2\x1c\xd9\x11\xf9\xe4\x38\x8c\x08\ -\x3d\x0f\xa3\xe4\x80\xe3\x90\x15\xf9\xc9\x11\x98\x3c\x41\xb3\x6c\ -\x92\x20\xc4\x54\xa7\x4e\xab\x30\x24\x52\x55\x4c\x47\xf4\x91\xa5\ -\x61\x28\x44\xbb\x2c\xa3\x48\x13\xc1\xe3\x32\xf4\x93\xc8\xa3\xe7\ -\x79\xc2\xbf\x3e\xf1\x04\xbc\x7e\xba\x81\x1f\x1f\xb5\x8f\x91\x41\ -\x41\xbf\x8f\x34\x6d\x96\x94\x65\x59\xf8\xbf\xa7\xea\x78\x3e\x1a\ -\x63\xb5\x1a\x8c\xfb\x63\xca\x96\x4d\x1c\xa7\x48\x8e\x83\x3b\x72\ -\xa9\xd4\x6c\x76\xf7\xf7\x50\x0b\x89\xb7\x7f\xf8\x0e\x2f\xfc\xe2\ -\x37\x19\x8e\x12\x90\x15\xfa\xbd\x21\x41\x9c\x4c\x65\xae\x29\x0e\ -\xd7\x0b\xfd\x93\x64\x48\x6f\x34\xe6\xe3\x5b\xb7\xe9\xcc\x2f\x32\ -\x18\x0c\xc4\x6a\x57\x24\xe6\x67\xaa\x74\x0f\xf7\x99\x8c\x63\x82\ -\x28\x64\x7e\x61\x89\x52\xb5\xc2\x6b\xaf\xdc\x44\x01\x2a\x65\x83\ -\xbf\xfc\xee\x77\x79\xe5\xc6\x0d\xf6\x87\x11\x2b\xcb\xa7\x68\x35\ -\x1b\x6c\x6d\x3e\x27\x4b\xe1\xfe\x83\x87\x5c\xbc\x78\x09\x55\x15\ -\x24\x8f\x30\x0a\xd0\x74\x71\x14\x3a\x4e\x09\x95\x75\x01\x06\x8f\ -\x63\x01\xa7\x1b\x8d\x22\xc6\xe3\xf1\x14\x91\x22\xb3\x30\x5f\x3f\ -\x59\xa0\xeb\xeb\x02\xaf\xf3\xce\x3b\xef\xf0\xb9\xcf\x7d\xee\x44\ -\xb4\x72\x74\x28\x95\x4a\xa8\xaa\xcc\xc6\xc6\x06\x8b\x8b\x8b\xd3\ -\xf2\xbd\x82\xd5\xd5\x53\xa8\xaa\xca\x0f\x7e\x20\xc2\x06\x82\xce\ -\x22\x63\xea\x22\x6f\x3a\x1a\xc5\x94\xcb\x25\x5c\x37\x65\x30\x18\ -\xb0\xb8\xb8\xc8\x64\x22\xee\xb8\x61\x98\xe3\xfb\x29\xa5\x52\x89\ -\x7e\xbf\x4f\xbb\xdd\xe6\xb5\xd7\x5e\xe3\xf1\xe3\xc7\xdc\xba\x75\ -\x0b\xdf\xf7\xb1\x2c\x99\xc3\xc3\x43\x66\x67\xdb\xe2\xd8\x06\x54\ -\xab\x0e\x93\x89\x4f\xb7\xdb\x65\x6e\x6e\x6e\x9a\xb3\xcd\xa9\xd7\ -\x2b\x4c\x7c\x88\xa2\x0c\x55\xc9\xd1\x35\xe8\xb4\x4c\xdc\xc9\x00\ -\x3f\x70\xb1\x1c\x93\x7b\x8f\xee\xf3\xd2\x2b\xd7\x29\x54\x95\xde\ -\x24\x22\x37\x60\x94\xc0\xde\xd8\x63\x7b\x38\xe6\xce\xe6\x16\xae\ -\x02\xa1\x21\xf3\x85\xaf\x7f\x85\xd3\xab\x8b\x2c\xcc\xcd\xb3\xba\ -\xac\xf3\x73\xdf\xfc\x39\xd2\x1c\xf6\x06\x23\xbe\xfd\xdd\xef\xa2\ -\x55\x4b\x4c\x92\x0c\xc5\x80\x66\xb3\x84\x92\x80\x94\x4a\x98\xf5\ -\x36\xdb\x2e\x3c\xd8\x4d\x79\xff\xfe\x33\xfe\xc3\x8f\x3e\xc6\x99\ -\x5b\x44\xae\x35\xf9\xfe\x8f\x3f\x26\xd6\x6c\x86\x69\xce\xa1\x1f\ -\xf2\xbd\xf7\x3f\x22\xb5\xcb\x64\xb6\x43\x6c\x3a\xf4\x0e\x0e\x51\ -\x2b\x55\x0a\xcd\xc0\x6a\xcd\x10\x74\x7b\xe8\x95\x0a\x81\xeb\x92\ -\xa5\x29\x72\x01\x4a\xc5\xa1\x48\xa2\xcf\xbc\xcb\x89\x78\x4a\x9a\ -\x86\x81\x66\x59\x14\x81\x4f\x0a\xf8\x71\x4c\x7f\x38\x24\xf3\xc6\ -\x18\x0b\x1d\x24\x55\x22\xc9\x62\x51\x03\x64\xea\x98\xa6\x8e\xeb\ -\x8e\x28\x97\x45\x6e\x59\x95\x21\xcb\x53\x54\x4d\x21\xf2\x27\xc4\ -\x9e\x8b\x5d\xaf\x81\xae\x12\x8e\x86\x14\xe4\x84\x9e\x0b\x45\x86\ -\x6e\x88\x79\xbd\xe5\x38\xa4\xdd\x2e\x96\x6d\x0b\x1e\x76\x9a\x63\ -\x99\x82\xd0\xaa\x68\x1a\x6a\xa5\x42\x2e\x81\x37\x1a\x89\x45\x6c\ -\x9a\x68\x86\x81\xdd\xa8\x0b\xf1\x6a\x32\x11\x2d\x0f\xb2\x42\x31\ -\x7d\x3d\xea\x74\x03\x62\x5a\xd2\x76\x6c\xc9\x3c\x7e\x6f\x05\xbe\ -\x8f\xd5\xe9\x30\x39\x38\x80\x28\x22\x4f\x53\xca\xe5\xf2\x09\xc4\ -\x8f\x38\x26\xf4\x7c\xd1\xfd\xb4\xf5\x9c\x7a\xbd\x4e\xad\x5e\x87\ -\x34\x21\x8c\x23\x6a\xcd\x06\xbe\x3b\xa6\x5a\x6b\xf0\xf4\xd9\x3e\ -\xba\xa1\x71\x76\xed\x3c\xf7\x1f\x3d\x66\x34\x1c\x9f\x08\x69\x72\ -\x41\x81\x63\x3a\xf4\x0e\xbb\x85\xed\x54\xf8\xf1\x07\x1f\x71\xe1\ -\xd2\x55\x24\x59\x43\x42\xe1\xf9\xd6\x73\x6c\xcb\x20\x07\xca\x8e\ -\x4d\xad\x3e\xad\xd6\x88\x13\x76\x77\xf6\xb8\xb0\x76\x8e\x4f\xef\ -\xdc\xe2\xa3\x0f\x3e\x16\x16\x4b\x55\xa8\x7e\xcd\x86\xc1\xf3\xe7\ -\xbb\xcc\xcd\xcd\xf1\xad\x6f\x7d\x8b\x97\x5f\x7e\x99\x38\x8e\x09\ -\x26\x31\xbb\x7b\x03\x66\x9a\x25\x74\x55\xe1\xbd\x0f\x3e\xe5\xe5\ -\x97\x5f\x46\xd7\x75\x1e\x6d\x1e\x52\x2a\x95\x08\x82\x08\x55\x15\ -\x3b\xe7\xf6\xf6\x36\x17\x2e\x5c\x20\x08\x42\xf6\x0f\xc6\xcc\xcf\ -\xd5\x98\x9b\xeb\xb0\xb7\xb7\xc7\x9d\x3b\x77\x78\xf3\xcd\x37\x51\ -\x55\x85\x8d\x8d\x03\x96\xe7\xeb\xac\x6f\x1e\x4e\x3d\xb1\x70\x78\ -\x78\xc8\xd2\xd2\x12\xbd\x7e\x30\x7d\x12\x42\xab\xd5\xe2\xcc\x99\ -\x33\xdc\xbd\x7b\x97\x2c\xcb\x68\xb7\x1b\x0c\xc7\x09\x96\xa5\x4c\ -\x63\x6a\x7f\xb5\xed\x4f\x8c\x4e\xa4\x93\xa2\x6c\x45\x81\x07\x0f\ -\x1e\xf0\xe2\x8b\x17\x09\x82\x80\xcb\x97\x2f\xd3\x6a\xb5\x58\x5f\ -\x5f\xe7\x0f\xff\xf0\x8f\xa7\xa3\x06\x98\x6d\x97\x79\xfa\x74\x8f\ -\xf1\xd8\x67\xb1\x69\x73\x70\x70\x80\xae\xeb\x38\x8e\xc5\x70\x38\ -\x24\x4d\x0b\x14\x59\x8c\x54\x55\x25\xc5\x9f\x8c\xe9\x0d\x3d\x2a\ -\x8e\x83\xe3\x58\x44\x49\x4c\x6f\xd0\x27\xcb\x21\x2e\x72\xdc\x20\ -\x24\x96\xc0\xac\x80\x59\xa9\x72\xe6\xe2\x65\x52\x59\x46\x75\x74\ -\x0a\x4d\x61\xe8\x8d\xb0\x4a\xf0\xf0\xe1\x43\x6c\x09\xee\xdf\xbd\ -\x8f\x65\xd9\x24\x05\xec\x8f\x86\x6c\x0d\x46\xe8\x4d\x85\xc3\x71\ -\x4e\x10\x42\xd5\x71\x50\x54\x99\x2d\xd7\xe3\xdf\xbf\x77\x8b\xff\ -\xe9\x5f\xfd\x1b\x7e\xe7\x8f\xfe\x3d\x3f\xbc\x7b\x9f\x43\x2f\xc2\ -\xcb\x40\x2b\xd7\x99\xe4\x12\xa9\x6e\xd1\x75\x7d\x72\xdd\x84\x28\ -\x23\x29\x54\x28\x74\xb0\x6a\x78\x13\x0f\x37\xf0\x09\x92\x74\xfa\ -\xc4\x55\x50\x35\x1d\x63\xfa\x3e\xc8\xa6\xf9\xde\xb4\x10\x7e\x69\ -\x59\x16\xdd\x45\x49\x92\x90\x84\x21\x14\x12\xc1\xde\x1e\x24\x09\ -\x76\xb5\x44\x6d\x69\x91\x28\x8d\x29\xe2\x48\xc0\xfd\x4c\x0d\x43\ -\x57\xe8\x1d\xec\x62\xe8\x0a\x9d\x99\x26\xf3\x2b\xcb\x04\x7b\x3b\ -\x38\x86\x0e\x79\xc1\x4c\x7b\x96\x4a\xa3\x89\x3f\x99\x88\x19\xad\ -\x2c\xe3\x6e\x6f\x63\xd7\xaa\xd8\xd5\xea\x34\xec\x52\x27\x18\x8d\ -\x90\xea\x75\x82\x5e\x4f\xdc\x6b\xa7\x6e\xab\xe3\x90\x7f\x51\x14\ -\x14\xc7\x1d\x4f\xd3\xa4\x94\xa4\x2a\x9f\xd9\x3f\x75\x5d\xf4\x47\ -\xc5\x31\x96\x65\xa3\x20\xe1\x4f\xdd\x63\x98\xe6\x67\x9d\x4e\xc7\ -\xa3\xaa\x69\x82\x2b\x8a\x22\xa4\x69\x92\x4a\x9f\xd6\xc4\x9a\xa6\ -\x49\x91\x66\x48\xd5\xda\x49\x60\x47\xab\xd7\xa7\x35\x36\x12\x6a\ -\xb9\x4c\xec\x87\x8c\xc6\x13\xea\x9d\x79\x90\x15\x86\x23\x97\x1f\ -\xbe\xfb\x21\x6f\xbc\xf9\x79\x2a\xd5\x3a\xe7\x2f\x5e\xe0\xd6\xad\ -\x5b\x85\xeb\xba\x42\xb5\x06\x89\xe6\xcc\xac\x94\x15\x10\x44\x29\ -\x71\x52\x60\x5a\x0e\xbb\xbb\xfb\x82\xd3\x75\xf3\x26\x9e\xeb\xe3\ -\x7b\x1e\x6f\x7d\xef\x5d\xca\xa5\x2a\xb2\xaa\x63\xda\x0e\x67\x97\ -\x3a\xf4\xbb\x47\xa8\xb2\x84\x69\x68\xf8\xae\x87\xa5\xab\x0c\x86\ -\x09\xa7\x4f\xcf\x33\x18\x0c\x98\x9b\x9b\x43\x91\x24\xe6\x5b\x22\ -\x63\x3a\xdb\xaa\xa3\x03\xc3\xde\xf0\x24\x02\xf6\xd2\x4b\x97\xf9\ -\xd1\x8f\x7e\x44\xc9\x62\x5a\x3d\x99\xb1\xb5\xb5\xc5\xea\xea\xaa\ -\x80\xd3\xd7\x05\xa4\x6d\x30\x14\x0e\xa9\xc5\xc5\xc5\x93\xfb\x6a\ -\x92\xa4\x2c\x2f\xcf\xe2\x06\x62\x28\x5f\xad\x1a\x7c\xf2\xc9\x2d\ -\x16\x17\x17\x85\xc2\x6b\x5b\x2c\x34\xed\x13\x47\x56\xb5\x5a\x25\ -\x8e\x63\x7a\xbd\x1e\xbb\xbb\x87\xa4\x69\xca\xfe\x7e\x9f\x7a\xcd\ -\x60\x3c\xf6\xf9\xf6\xb7\xbf\xcd\xe2\xe2\x22\xa7\xe6\x6a\x53\x1a\ -\x63\x8e\x24\x89\xa3\xdd\x83\x07\x8f\x59\x58\x58\xa0\x28\xc4\xe9\ -\xc1\xb1\xe0\xc2\xb9\x45\x5e\x7a\xe9\x25\xce\x9d\x3b\x47\xb3\xd9\ -\xe4\x0f\xff\xf0\x4f\xf8\xe0\xc3\x7b\x27\xc7\xf9\xa3\x49\x46\xaf\ -\xd7\x13\xdd\x56\x06\xb4\x5a\x0d\x64\x59\xe2\xe8\xa8\x4b\xaf\x7b\ -\x40\x7b\xa6\x41\x7b\xb6\x82\x2a\x43\x92\x27\x78\x61\x40\x94\x26\ -\x2c\x2c\x2f\x91\x90\xa3\x6a\x32\xb3\x9d\x2a\xc3\xb1\x80\x2c\x1c\ -\x1c\xec\xf3\xe9\xbd\x3b\xd8\xb6\xc9\xa0\xd7\x43\x22\x63\x65\x65\ -\x91\xf1\x18\xf2\x3c\xe5\xef\xfc\xda\x6f\xb3\xb1\xfe\x04\x7f\xe4\ -\x61\x9a\x16\x29\x12\xb7\xd7\xd7\xb9\xfb\x6c\x80\x5c\x92\x89\x65\ -\x01\xdd\xf8\xe0\xd6\x63\xfe\xe8\xfd\xf7\x79\xff\x68\x8f\x67\x49\ -\xc4\xd8\x30\xf1\x0c\x0b\xb5\xd1\x04\x49\x25\x55\x54\xa2\x1c\x74\ -\xbb\x44\x94\xe5\xb4\x5a\xb3\x28\x66\x19\x2d\x2e\x90\xbc\x04\xa2\ -\x1c\x45\x33\x51\xb4\x29\x75\x52\xd7\x21\x17\xcd\xbd\x69\x12\x13\ -\x4e\x5c\x9a\xad\x06\x46\xa5\x44\x56\xa4\x8c\xdc\x21\xbe\x3b\x26\ -\x9a\x4c\x88\x7c\x7f\x5a\xb6\xa6\x42\xb3\x41\xb5\x33\x83\x3f\x99\ -\x90\x24\x31\x95\x4a\x89\xd6\xfc\x0c\x04\x2e\xe3\xc3\x5d\xa4\x2c\ -\x64\x61\x7e\x86\xaa\xad\xf1\x2b\xbf\xfc\x15\xbc\xc1\x21\xe8\x12\ -\xa9\x3f\x41\x29\x72\xdc\xd1\x90\x30\xf0\x60\x32\x9e\xba\xc0\x32\ -\x70\x5d\x0c\xd3\xc4\x72\x6c\x91\x94\xd2\xc4\xec\xd7\xd2\x0d\x88\ -\x62\x51\x91\x54\x70\x12\x87\x3c\x06\xf1\x31\xdd\x78\x24\x59\xc4\ -\x26\x15\x45\x21\x4f\x12\x51\x44\xa7\xeb\xe0\x07\x64\x51\x8c\xa1\ -\x6a\x82\x8e\xe9\x07\x7f\x05\xa8\x97\x4f\xfd\xdf\xc7\x23\x29\x7d\ -\xda\x29\xa5\xaa\x2a\x4c\xf3\xd6\xc7\x71\xd8\x3c\xcf\xb1\x2c\x8b\ -\x3c\xcd\xc8\xbb\x3d\x2c\xcb\xc2\xf7\x45\xa3\x86\x61\x59\x10\x45\ -\x44\xee\x58\x28\xd8\x69\xc2\x51\xbf\x47\x96\xc3\x51\xb7\xcf\xa9\ -\xd5\x55\x9e\x3c\xdd\xc0\x0b\x03\x51\x03\x2b\x1d\x47\x9e\x90\x18\ -\xba\xde\x07\x33\xed\x79\x5a\x33\x1d\xe2\x38\x67\x73\x73\x0b\x77\ -\x34\xa6\x22\xa9\xe8\x8a\x4a\xad\x2c\x66\xba\x97\x2f\x5f\x66\xa6\ -\x22\xd1\x6c\xd5\xd9\xdc\xef\x61\xd9\x06\x4b\x4b\x4b\x54\x2a\x36\ -\x96\x65\xa0\xaa\xc2\x24\xee\xba\x62\x77\x9a\x9b\x9b\x63\x6f\x6f\ -\x9f\xee\x30\xa1\x56\x35\x89\xa2\x8c\xc3\xae\x00\xd2\xcd\xcf\xcf\ -\x63\x9a\x26\x92\x04\x97\x2f\x5f\xe6\xd6\xdd\x27\x58\x96\xca\x60\ -\x30\x20\xcf\x73\xea\x75\x87\x7a\xbd\x46\x1c\x83\xe3\x08\x4e\x95\ -\xae\x8a\x79\xf2\x6b\xaf\xbd\xc6\xd6\xd6\xd6\x5f\xf9\x59\x96\x65\ -\x51\x14\xb0\xb1\xb1\xc1\xd5\xb3\x0b\x98\x26\x74\xbb\x3d\x9e\xec\ -\xf4\x85\xa1\x1f\xb8\x7d\xfb\x36\x57\xaf\x5e\xe5\x9b\x3f\xfd\x45\ -\x82\x20\xe0\xfe\xfd\xfb\x84\x61\xc8\x51\x57\x8c\x3a\x6e\xde\xbc\ -\x89\xa2\x28\xf4\x26\xd9\x09\x67\x29\x49\x44\x06\xb5\xd7\xeb\x71\ -\xe1\xc2\x79\x46\xa3\x00\x5d\x57\x78\xfc\x64\x17\x2f\x84\xad\xad\ -\x2d\x74\x5d\xe7\xfa\xf5\x2b\x7c\xe9\x4b\x5f\xe2\xea\xd5\x4b\x18\ -\x86\xc1\xfa\xfa\x3a\xdf\xf9\xce\x77\x58\x5e\x5e\x46\xd7\x35\x1e\ -\x6f\x1d\x11\x04\x11\x59\x96\x33\x33\xd3\xe2\xf0\xf0\x50\x78\x73\ -\x13\xf1\x66\x33\x0c\x0b\xdb\x29\xd3\xed\x0d\xc8\x72\x11\xfb\x1b\ -\x0e\x3d\xba\x7d\x9f\x76\x05\x5c\x17\xbe\xf7\x67\x7f\xca\x52\xbb\ -\x89\x59\xa4\x94\xa5\x9c\xd3\x33\x0d\xdc\x61\x97\xbc\x48\xb1\x1c\ -\x13\xdd\xd0\x98\x99\xe6\x9c\xc9\x20\x2f\x24\xfe\xe2\xad\xb7\xf8\ -\x5f\xfe\xf9\x3f\xe5\xd0\xcf\x19\xc6\xa0\x1a\x30\xca\x0b\x7e\xf8\ -\xf0\x3e\x87\x48\xd0\x68\x91\x2a\x2a\xdd\xe1\x98\x5c\x16\xce\x26\ -\x49\xd5\x48\xa7\xe3\xa3\xbc\x10\x6f\xcc\xb2\x65\x93\x79\x21\x56\ -\x0a\x5a\x2e\x91\x25\x11\x71\x96\x92\x65\x89\xa0\xc0\x25\x19\x86\ -\xac\x62\xaa\x1a\xaa\x22\xe3\x4d\x5c\x22\xdf\x27\x77\x5d\x0a\xdf\ -\x03\x49\x42\x2b\x39\x94\x6a\x35\x9c\xd9\x59\xe4\x52\x09\xc2\x90\ -\xc9\x64\x22\x3a\xbf\xb2\x84\xc9\x70\x40\x30\x71\xb1\xaa\x65\x4a\ -\x55\x07\x29\x8d\x89\xc6\x23\xfe\x9b\x5f\xf9\x25\xbe\xff\xff\xbe\ -\xcf\x5c\xad\xcc\x5c\xad\x46\xec\x8e\xb1\x35\x99\x70\x6f\x9f\xb8\ -\xdb\x07\xdd\x10\xca\xb4\xaa\xc2\x6c\x5b\x6c\x88\x71\x8c\xa4\x2a\ -\x8c\xc7\x63\xac\x5a\x8d\x30\x08\x90\x9c\x12\xa9\x1f\xa2\x2b\xea\ -\x89\xf3\x2b\x0c\x43\xe1\x5b\x56\x45\x67\x71\x91\x67\x27\x74\x4e\ -\x79\x6a\x10\x51\x25\xf9\x24\x04\x11\xf8\x3e\x71\x10\x9e\x50\x3f\ -\x14\x45\x11\x4f\xe6\x69\xb9\xdc\xb1\xaf\xfa\xf8\xe9\x9c\x84\x21\ -\x46\xb5\x4a\xee\xba\xe8\xba\xfe\x59\xa8\x62\x8a\xed\x15\xdc\xec\ -\x04\x45\x56\x91\x8e\x2d\xa6\x4e\x09\x74\x93\x34\x2b\xf8\xfe\x5f\ -\xbe\xcd\x7f\xf6\x33\xaf\xf1\xa3\x77\xdf\x67\x71\x71\x16\x4d\x37\ -\xe9\x76\xfb\x58\xa6\xd0\x6d\x64\x05\x85\x1c\xc1\xfb\x7d\xf2\x74\ -\xeb\xc6\xc5\x4b\xd7\xa8\xd4\x5a\x20\x6b\x4c\x5c\x9f\x57\x5f\x7d\ -\x9d\xc3\xf1\x48\x64\x87\xa3\x90\x0b\x6b\x17\x39\x3a\xea\x31\x0c\ -\x21\x08\x84\x10\xb5\xbc\xb0\xc0\xc6\xd3\x75\xca\x8a\xf8\x47\x4d\ -\x26\x09\x9d\x4e\x8d\x7b\xf7\xee\x71\xe1\xc2\x25\x11\x7e\xef\xf5\ -\x48\xa2\x08\xdf\x4d\x48\x93\x84\xed\xcd\x0d\x3a\xb3\x33\xe2\x8e\ -\x6a\xaa\x8c\x46\x21\x2f\x5e\x3b\xc7\x64\x32\xe1\xa3\x8f\xee\x60\ -\x18\x06\xa7\x4e\x9d\x02\x60\x3c\x76\xa7\xa1\x96\x82\x99\x99\x1a\ -\xf7\x1e\x6c\xd2\x6e\xb7\x29\x95\x4a\x5c\xba\x74\x89\xdd\xdd\x5d\ -\xd6\xd7\xd7\xf1\x3c\x0f\xc3\xd0\xf9\xc1\x0f\x7e\xcc\x17\xbe\xf0\ -\x05\xc6\x09\x78\x5e\x46\xad\x56\x63\x66\xa6\xc1\xe9\x4e\xf5\xc4\ -\x94\x91\xa6\x29\x4f\xb7\x8e\x98\x9d\x9d\x65\x69\x69\x09\xd3\x34\ -\x79\xfc\xf8\x31\x8f\x1e\x3d\xe2\xfc\xda\x12\xf5\xba\x79\xc2\x45\ -\x76\x1c\x71\xc7\x7a\xfa\xf4\x29\xe7\xce\x9d\xc3\xf7\x03\xaa\x55\ -\x8b\x38\xce\x68\x34\x1a\xd8\xa6\x60\x56\x57\xab\x55\x7c\x3f\x3d\ -\x09\xbb\x9f\x3a\x75\x6a\xaa\xd2\x2b\xd4\x6a\x35\xee\xde\xfd\x94\ -\x3b\x77\xee\xb0\xbe\xbe\x4e\xb7\xdb\xa5\x28\x20\x88\x42\x6a\xf5\ -\x26\x71\x0a\x79\xa1\x70\x34\x18\xe1\x05\x31\x93\x20\xe4\xec\xea\ -\x79\x1a\x8d\x1a\x8e\x65\xd3\x2a\xdb\xec\x6d\xf7\xa9\xea\xb0\xda\ -\x69\x50\x57\x72\xbe\xf1\xfa\xcb\xfc\xce\xff\xf8\x5b\xfc\x0f\x7f\ -\xf7\x6f\xf3\xea\x85\x59\xee\xdf\xbf\xc3\xbf\xfb\xc3\xdf\x23\x91\ -\x32\xf6\xf6\xf6\xb0\x0d\x93\x70\xe2\x91\xa7\x39\x23\xcf\x47\x2b\ -\x57\x48\x2c\x99\x89\x0a\x23\xa0\x97\x24\x90\x15\xec\xb8\x1e\x03\ -\xd7\x07\x37\x00\x2f\x46\x2f\x14\xc8\x65\xf2\x48\x84\x2c\xe2\x38\ -\x24\xc9\x13\x46\xa3\x01\x9a\x54\x90\x7a\x3e\x25\x24\xaa\x9a\x8e\ -\xa9\xa9\xe8\x8a\x2c\x58\xd2\x45\x46\x38\x1c\x10\x4f\x26\x44\x93\ -\x09\x81\x3b\x26\x1c\x8f\x44\x23\x82\xae\x82\x63\x61\xd7\x2a\x98\ -\x8e\x45\x31\x4d\x82\xe5\x61\x24\x6c\x9b\x69\x46\xc5\x76\x90\xf2\ -\x0c\x53\x55\xc8\x03\x1f\x53\x86\xc9\xc1\x1e\xe1\xb0\xc7\x7f\xf1\ -\x0b\x3f\xcf\x52\x13\x7e\xe6\x0b\xaf\x70\x69\x79\x09\xc9\x9f\x60\ -\x65\x31\xe1\x60\x28\xd0\x3b\xa6\x8e\x53\x76\x30\x1d\x07\xb3\x54\ -\xa2\x34\xd3\x24\x1e\xf5\xf1\x23\x61\x85\x4c\xa2\x48\x3c\xfd\x92\ -\x14\xdb\x30\x21\x8c\x29\xd2\x4c\x64\xc1\xe3\x88\x24\xf0\x91\x14\ -\x05\xb5\x5c\x66\x6a\x0c\x20\x4e\xe2\xcf\xd4\x74\x84\x0b\xcb\xae\ -\x54\xd0\x64\x85\xa8\x3f\x80\x20\xc0\x98\xba\xb2\x4e\x0a\xcd\x75\ -\xfd\x04\x30\x70\x0c\x12\x3c\xd6\x4b\xe4\xe9\x5d\x3a\xff\x09\x16\ -\x98\x34\x05\x0d\xe8\xad\x16\x51\x10\x9c\x58\x7c\xc3\x38\xa2\x5c\ -\xaf\x0b\xc6\x88\x2c\x51\xaf\xd7\x79\xb8\x97\xf2\xb9\xbf\xf6\x26\ -\xaa\x0e\x13\xdf\xe3\xa7\xbe\xfc\x25\xd1\x29\x75\xec\xec\xca\x91\ -\x31\x2d\x87\xa3\xa3\x1e\x7e\x14\xb1\xb9\xb5\xcd\xc4\xf5\x29\x55\ -\xaa\x9c\x6e\x54\xb0\x0c\x83\xd0\x13\x19\xcb\xbb\x77\xef\x72\x70\ -\x70\xc0\x24\xc8\xd1\x4d\x15\xcf\x77\x39\x75\xea\x14\xae\xeb\xb2\ -\x37\x18\x4f\x93\x42\x32\xcf\x9f\x8b\x45\x32\x99\x4c\xb8\x76\x6d\ -\x15\x69\x3a\xcf\x03\x48\xa3\x18\x45\x51\x58\x9c\x9b\xa7\x52\x2e\ -\x4d\xd9\x59\x26\xdd\x7e\xc0\xdc\xdc\x1c\xc3\xe1\x90\xf1\x78\x4c\ -\xad\x56\xc5\x75\x23\x16\xda\x65\x06\x83\x80\x5e\xaf\x87\xa2\x20\ -\xba\x7d\xe7\xe6\x84\x3b\xcb\x11\xb9\xd3\x99\x99\x19\x86\xc3\x21\ -\xdb\xdb\x3b\x38\x8e\xc3\x99\xb9\x1a\x83\x81\xa8\x7d\xb1\x2c\x85\ -\x2c\x83\x3b\xeb\x3b\x7c\xf4\xd1\x47\xbc\xfa\xea\xab\x2c\x36\x6d\ -\x9a\xcd\x26\x86\x61\x70\x7e\x79\x06\xcb\xb2\x70\x1c\x47\xa4\x96\ -\xde\xbb\x4d\xb7\xeb\x51\xab\xd9\x18\x86\x72\xe2\xb9\xee\xf7\xfb\ -\xd4\x6a\x35\x2c\xcb\x22\x08\x32\x0c\x43\xa1\x51\x37\x79\xf2\x6c\ -\x9f\x83\x83\x03\x1c\xc7\xc1\x34\x55\x74\x5d\x63\x3c\xf6\xd0\x34\ -\x61\x44\xb8\x74\xe9\x12\xf5\x7a\x9d\xf9\xf9\x79\xbe\xf1\x8d\x2f\ -\xd1\xe9\x74\x18\x0c\x06\xfc\x7f\xdf\xfb\x3e\xf7\x1e\x3c\xe6\xa8\ -\x37\x24\x4e\x52\x4c\x5b\x45\x51\x4d\x06\xc3\x09\x47\x87\x7d\x74\ -\xdd\x64\xd8\x77\x29\x92\x98\x34\x08\x39\xd5\x6e\x60\x17\x05\x57\ -\x56\xe6\xf8\x67\xff\xf8\x1f\xf2\xcb\x5f\xad\x12\xb4\x1e\x00\x00\ -\x20\x00\x49\x44\x41\x54\x79\x85\x66\x06\x79\x37\x42\x03\x4c\x4b\ -\xe5\xe7\xff\xe6\x7f\xca\xea\xa5\x0b\x9c\xbf\x74\x11\x55\x56\x70\ -\x0c\x07\x29\x85\x7a\xad\xc9\xdf\xfa\xd5\x5f\x45\xad\x40\x62\xc1\ -\xfd\x23\x8f\xbb\xcf\x36\xa0\x51\xc7\x9d\x78\x68\xaa\x8e\x5c\x6f\ -\x51\xa9\xb6\xd0\x52\x09\xa2\x94\x22\x4a\x90\xc8\x29\x8a\x0c\xbb\ -\x6c\x22\x29\x05\xb6\x6d\xa2\x4a\x39\xc1\x78\x40\x30\xea\x43\x26\ -\xc6\x26\x52\x3e\xed\xa8\x76\xc7\x44\xa1\x4f\x16\x85\x10\x27\x94\ -\x6a\x35\x2a\xcd\x3a\x4a\xb9\x24\xba\x8f\x0a\x61\x6d\x3c\x8e\xf5\ -\x91\xe7\xd4\xea\x55\x28\x72\xfa\xdd\x23\x42\xd7\xa5\x56\xb2\xd1\ -\x64\x89\x22\x08\x58\x9e\x9f\xe3\x1b\x5f\xfc\x02\xe7\x57\x9a\xcc\ -\x4a\x50\x78\x11\xef\x7c\xf7\x2f\x38\xbf\xd0\x41\x0e\x43\x82\xa7\ -\xcf\xa8\xd7\x6a\x38\xa6\x45\x1c\x46\x18\xd3\x18\x61\x21\x01\xd3\ -\xb4\x54\x9c\x26\xe8\xa6\x49\x1c\x84\x38\x96\x4d\x16\x25\xa2\xa9\ -\x72\xe2\x9f\x10\x37\x45\xf0\x40\xc5\xb0\x2d\x34\x4b\xcc\xad\x49\ -\x53\x8a\xa9\x61\x69\x4a\x9e\xc5\xd4\x74\xd1\x1d\x15\xc5\x82\xe6\ -\x31\x8d\x3b\x1e\x47\x2d\x35\x4d\x43\x9a\x6e\x52\xc7\xde\x6a\xe2\ -\x58\xe0\x93\x82\x00\xbd\x56\x3b\xe9\x7d\x3e\xfe\x1c\x51\x74\x50\ -\x3b\x61\x75\xa7\xd3\x59\x72\x5e\x48\xa0\xea\xf4\x0e\x8f\x30\x2c\ -\x9b\x7a\x5d\xa0\x97\xef\xdc\x79\xca\xf9\xd5\xe5\x93\xea\xa2\x3c\ -\xcf\x91\xc3\x24\x44\x46\x26\x8e\x53\xda\xb3\x1d\xde\x7a\xfb\x87\ -\x04\x41\xc4\xd1\xd1\x11\xf5\x5a\x93\x8d\xae\x8b\xaa\xe8\x1c\x1e\ -\x1e\x72\xed\xf2\x15\xba\xdd\x2e\xe7\xce\xad\x31\x53\x97\x11\x95\ -\xaf\x21\x8e\xe3\x70\xe5\xca\x15\xf6\xf6\xf6\xa8\x35\x1b\x14\xb2\ -\x00\xd3\xb5\x5a\x2d\xc6\x83\x21\xb6\x0c\x2b\x2b\x2b\x3c\x79\xf2\ -\x84\x3c\xcd\x78\xf6\xe4\x29\x73\x9d\x0e\xde\x64\x32\xd5\x10\x74\ -\xa2\x48\xbc\xa0\x6e\xb7\xcb\x0b\x2f\xbc\x40\xb7\xdb\x65\x3c\x76\ -\x31\x4d\x83\x64\xfa\xf1\xb5\xa5\x16\x7f\xf0\x07\xdf\xe6\xdc\xb9\ -\x73\xb4\xea\x02\xc6\xb6\xb1\x75\xc4\xc5\x73\x8b\x22\x66\x36\x05\ -\xe2\x5d\xbb\x76\x89\xa7\x7b\x43\xaa\xd5\x32\xcd\x66\x95\x30\x14\ -\x3b\x64\x18\x86\x9c\x3b\x77\x0e\x4d\xd3\xd8\x38\x18\x9f\xcc\xee\ -\x9e\xed\x8f\x4e\xba\x82\x6e\xdc\xb8\xc1\xdc\xdc\x1c\x77\xef\xde\ -\x65\x77\xb7\x4b\xb7\x3b\xc4\xf7\xe3\x93\xcd\xc3\xf7\x7d\xaa\x96\ -\x88\x2f\xaa\x2a\xf4\xfa\x01\xbe\xef\x73\xf3\xe6\xcd\x29\x7f\x39\ -\x43\xf4\x79\x69\x6c\x6c\xec\x70\x74\x24\x36\xb4\x63\xcb\x9d\x30\ -\xba\x18\x9c\x3f\x7f\x9e\x4b\x97\x2e\xf1\xa5\x2f\x7f\x9d\xbc\x50\ -\xf8\xe0\x93\x3b\xfc\xd9\x77\xdf\x61\x6f\xff\x88\xc3\xa3\x3e\x61\ -\x94\x11\x45\x09\xba\xaa\x62\xeb\x06\xcd\x92\x49\x3c\x1e\xa2\x04\ -\x1e\x73\x8e\x49\x3c\x1c\x63\xa6\x60\x8c\x7c\xce\x54\x0c\x22\x17\ -\x34\x45\xe6\xf6\x83\xbb\xfc\xe8\xc3\x77\x79\xb6\xb1\x81\xa6\x28\ -\x54\x0c\x0b\x5d\x56\x04\xc0\x6f\xec\xf2\x2f\xbf\xf5\x3d\xfe\xcf\ -\xdf\xff\x0e\xff\xe2\xff\xf9\x16\x3f\x7e\xf0\x29\xa5\x7a\x0b\x39\ -\xc8\xb0\x72\x15\x65\x92\xc0\xc8\x27\xeb\xbb\xa8\x39\x68\x79\x4e\ -\x9e\xa6\x14\x24\xa4\x52\x42\x22\xc5\xf8\xa9\x87\x61\xab\xb8\xe3\ -\x3e\x61\xe8\x13\x76\x0f\x89\xdd\x11\x59\x12\xa1\xa8\x32\x28\x12\ -\xd5\xb2\x43\x7b\xa6\x49\x7b\xb6\x4d\x91\x25\x62\x66\x9c\xc6\x10\ -\xf9\xc4\x69\x22\x20\x7c\xa6\x49\xad\x56\xa3\x5a\x6f\x30\xea\x0d\ -\xc8\xb6\x77\x91\xb2\x94\x8b\xe7\xce\x52\xb5\x2d\x1c\x4d\xe5\xcc\ -\xe2\x12\xcd\x52\x89\x70\x38\xe0\xb4\x03\x1f\x7c\xb2\xcd\xa4\xd7\ -\xe5\xec\xe2\x02\xdf\xff\xce\x77\x58\x68\x34\xb1\x3a\xb3\x78\xc3\ -\x21\x45\x2a\x98\x5d\x71\x1c\x12\x25\xa1\xf0\x53\x97\xcb\x27\x24\ -\x4c\x6d\xea\x19\x50\x65\x05\xa9\x28\xc4\xc8\x29\x4d\xf1\x3d\x0f\ -\x74\x1d\xd9\xb6\x4f\x16\x91\xaa\x6b\x22\x38\x21\x3a\x4f\x4f\x38\ -\xd7\x3f\x09\x0d\xc0\xb2\x41\xd5\x88\xc3\xe8\xe4\xef\x7e\x12\x02\ -\x08\x10\xf9\xbe\xe0\x75\x4f\x8f\xe6\xc7\x7a\xd0\x4f\xd6\xcf\x1c\ -\x7f\x7d\x92\x24\x58\xe5\x32\xe3\xf1\x58\x88\x63\x86\x81\x37\x1a\ -\x42\x96\x52\x6d\x36\xe9\x76\xbb\x48\x2a\xc8\xaa\xc2\xd3\x8d\x0d\ -\xa2\x54\x5c\x2f\x5d\xd7\x15\x66\x13\x47\xb3\x49\xf2\x14\x59\x53\ -\xe9\x8f\x47\xd3\x6a\x8f\x98\xc5\xb9\x16\x69\x16\xd0\x69\x95\x09\ -\xc2\x90\x27\x9b\x5b\x5c\x7f\xa9\x83\x5d\xb2\x88\x76\x76\x18\x79\ -\xf0\xd1\xfb\x1f\xb0\x76\x6a\x55\x20\x48\xab\x75\x3e\xbd\xfb\x90\ -\x56\x7b\x9e\x9d\x9d\x3d\x2e\x5f\xbe\x4c\x18\x86\xdc\xb8\x76\x8a\ -\x67\x3b\x43\x66\x67\x6b\x9c\x3a\xb5\xc2\xf7\xfe\xf2\xfb\x5c\xbd\ -\x7a\x95\x02\x70\x4a\x25\x0e\x0e\x7a\x2c\x2c\x36\x09\x02\xe5\xe4\ -\x05\x05\x41\xc0\xc5\x8b\x17\x79\xfe\xfc\xf9\xf4\x63\x16\x67\xcf\ -\x2e\xb1\x79\xe8\xd2\x6e\xb7\x05\x2b\x6b\x6f\xc8\xfc\x5c\x8d\x24\ -\x49\xf0\x63\x7e\x62\x11\x5f\xe3\xed\xb7\xdf\xe1\x85\x17\x5e\x20\ -\xcf\x21\x8a\x84\xa1\x22\xcf\x73\x9e\x3e\x7d\xca\xcf\x7f\xf3\xab\ -\x1c\x0d\xc2\x93\x2c\x69\x10\x04\x2c\x76\xaa\x7c\x7c\x47\x1c\xcd\ -\x6f\xdc\x78\x01\xcf\x8b\xb8\x71\xe3\x06\x7b\x7b\x7b\xec\xef\xef\ -\xf3\xf2\xcb\x2f\xf3\xec\xd9\x33\xde\x78\xe3\x0d\x8a\xa2\x60\xe7\ -\x68\x42\xa7\x53\xc7\x75\x13\x6c\xdb\x62\x67\x67\x87\xb5\xb5\x33\ -\x8c\x46\x1e\x95\x8a\xc9\x64\x12\x53\x2a\xe9\x18\xc6\x02\xf7\xef\ -\x3f\x98\x06\x2e\x3a\x34\x1a\x16\xe3\x71\x42\xb9\x5c\x22\x8e\x13\ -\xee\xdf\xbf\xcf\xe7\x7f\xea\x0b\xe4\x05\x94\x1a\x0d\x82\xc0\x63\ -\x79\xde\xe1\xa3\x5b\xeb\xf4\x8e\x7a\x3c\x7e\xb8\x0e\x69\x82\x37\ -\x12\xb4\xc6\xb5\xb5\xb3\x94\xaa\x15\xe4\x2c\xa1\xe5\x38\x6c\x6f\ -\x6d\x70\xaa\xbd\x44\x18\xa5\x28\x59\xcc\xed\xf7\xde\xc2\x1b\x8d\ -\xf8\xaf\x7f\xe9\x17\xb0\xad\x1a\x67\x57\x3a\x0c\xf7\x62\x1c\x4b\ -\x27\x49\xa0\x39\x07\xef\xde\x2d\x78\xff\xfe\x3d\xfa\xd1\x84\x5a\ -\xbd\x8d\x77\x18\x93\xc5\x29\xa5\x7a\x95\x3c\xcd\xb0\x2c\x1b\xcb\ -\x76\x18\x51\x30\x38\xdc\xc3\xb0\x17\x20\xf2\x89\xa2\x80\x28\x89\ -\xf1\xfc\x10\x7d\x7a\xe4\xab\x36\xea\xb8\x71\x8a\x66\x99\xa8\x28\ -\x48\x45\xce\x68\xe4\x93\xcb\x0a\x51\x2e\x09\x17\x54\x56\xe0\xa8\ -\x26\xa6\x0e\x61\x21\xa3\xa9\x3a\x79\x26\x91\x46\x21\x69\x9c\x61\ -\x28\x2a\xb5\x4a\x99\x48\xce\x69\xda\x16\x5f\x7b\xe5\x35\x4a\xba\ -\xcc\xc1\xee\x73\x02\x6f\xcc\xed\x5b\x1f\xf3\x68\xe7\x19\xff\xfa\ -\xf7\x75\xa4\x2c\xe5\xfa\x95\xab\xbc\xf9\xd2\x55\xbe\xf1\xda\x0d\ -\x72\xd5\x64\xdd\x75\xf9\xbd\x3f\xfe\x53\x2a\x8d\x06\xad\xce\x02\ -\x5b\xfb\xfb\x14\x92\x84\x59\xaa\x50\x94\x2b\xb8\x87\x5d\x30\x4c\ -\x31\x0e\x93\x65\x92\x34\xc6\x34\x0d\xb1\x80\x64\x09\x26\x13\xb4\ -\xf6\x0c\x9a\x69\xe1\x7b\x2e\x51\x9a\x63\x39\x16\x9a\xa2\x12\xe5\ -\x05\x28\x12\xc9\xc4\x43\x2b\x97\x45\x19\x41\xaf\x0f\x8a\x8a\x53\ -\xad\x08\x61\xca\xf7\xd0\xab\x15\x8c\x63\x98\x40\x21\x10\x42\x45\ -\x52\x90\x04\x01\xa8\x2a\xa5\x5a\x85\x38\x8c\xa9\x94\x1c\xa2\x28\ -\x12\xe2\xd5\xa0\x87\x5c\xab\x09\x71\x50\xd5\x08\xa2\x88\xf6\x4c\ -\x8b\xed\x67\xcf\x50\x4d\x95\x46\xad\x46\xef\xd9\x11\xd5\x76\x9b\ -\xbc\x7f\x84\x9f\x26\x0c\x3c\x50\x4d\x83\xce\x4c\x95\x51\x7f\xc4\ -\xe2\xec\x1c\xcf\xee\xde\x26\x49\x73\xd4\x22\x4e\x30\x74\x0d\x3f\ -\x87\xb7\x3f\x78\x8f\xff\xf2\x6f\xff\xe7\xfc\xe3\x7f\xf2\x4f\x28\ -\xa2\x11\xbf\xfe\xeb\x7f\x9f\xdb\xf7\x1e\xb2\xba\xbc\x88\x56\x29\ -\x13\x2b\xb0\x76\x69\x95\x7f\xf7\x7f\xff\x01\x45\xf6\xcb\x84\xa1\ -\xcf\xf9\xb5\x97\xf1\x82\x82\x34\x53\x38\x7f\xf1\x0a\x4f\x1e\x3d\ -\x65\x38\x1c\x72\xed\xf2\x1a\x61\x58\xb0\xdf\x8f\x68\xb7\x6b\x84\ -\x89\xe8\xb4\xd5\x6d\x0b\xab\x62\x93\x49\x10\x66\x09\x8d\x66\x93\ -\xf1\x58\x38\x7b\xba\xdd\x2e\xad\x56\x8b\xf9\xf9\x59\xd2\xb4\xa0\ -\x5a\xad\xb2\xb3\xb3\xc3\xf2\xf2\x32\x41\x10\x08\x27\xcb\xeb\xaf\ -\x33\x1a\x8d\xc4\xf7\x8c\x98\x9a\x31\xc4\x09\xa9\x3e\x6d\x00\x78\ -\xed\xb5\xd7\xf8\xe0\x83\x0f\x58\x59\x59\xa1\xd9\x6c\x62\x19\xf0\ -\xe9\xa7\x8f\x39\x7b\xf6\x2c\x61\xca\xc9\x8e\x99\x65\x99\x98\x5b\ -\xe7\xb0\xb9\xb9\xc9\x37\x7f\xf6\xcb\x1c\x1c\x4d\x68\x34\x4a\xc4\ -\xb1\x40\xf6\xcc\xcd\xcd\xf1\xe7\x7f\xfe\xe7\x62\x74\x16\x88\x31\ -\x96\xe3\x38\x84\x61\x81\x69\x6a\x3c\x7d\xba\xc9\xe2\xe2\x22\x9e\ -\x17\x21\xcb\x32\x61\x98\x63\xdb\x3a\xb2\x0c\x1b\x1b\x9b\x27\xa9\ -\x95\x38\x4e\xf0\xbc\x64\x4a\x60\xcc\xb1\x2c\x8d\x5c\x82\x30\x17\ -\x79\x01\xcb\x01\x4d\x73\x70\x3d\x08\xdd\x80\xaf\x7d\xfe\xab\x38\ -\xb6\x89\xad\x89\x60\x7c\x1c\xc7\xf4\xfb\x5d\x9e\xac\x3f\x63\x77\ -\x67\x8f\xf7\xde\x7b\x1f\x14\x89\x07\x4f\xee\x23\xc9\x32\xef\x7d\ -\xf2\x21\xb3\x4e\x85\xaf\xfe\xf4\x17\x49\xb2\x09\x83\xad\x23\x96\ -\x4f\x75\xe8\x34\x75\x86\x1e\xec\x8c\x27\x7c\x3a\x4c\xd9\xdc\x3b\ -\xa0\x77\x34\x02\x5b\x65\x70\xd8\x83\x40\x03\xd9\xa4\x7f\xb0\x03\ -\x59\xc6\xc1\xb0\x27\xd0\x3c\x61\x0a\x9e\x8f\x91\x42\x92\xc9\xe8\ -\xcd\x59\x0a\x29\x47\x55\x24\xf2\x38\x82\x3c\xa3\x40\xcc\x50\x35\ -\xa3\xc4\xa8\x37\xc0\x2a\x3b\x50\x6b\xe0\xa6\x39\x96\x26\xa3\x68\ -\x26\x52\x0a\xbe\x97\xa0\xab\x26\x85\xa2\x11\x0d\x5c\x2a\xb3\x1d\ -\xc6\xf1\x18\xc3\xb4\xa9\x38\x1a\xc3\x83\x5d\xcc\x38\x22\x0f\x26\ -\xdc\x5c\xa8\x53\xb7\xc1\x3e\x57\xe5\x7f\xff\x3f\x7e\x1f\x27\xf2\ -\x70\xbd\x11\x8f\x6e\x7f\xc8\xd7\xbf\xfc\x45\x6e\x5c\x59\x22\x59\ -\x6a\x51\xd7\x4d\x72\x24\x3c\x05\xbe\x70\x69\x85\xbd\x81\x8b\x56\ -\xaa\xf2\xcf\xfe\xd5\xef\xd2\x0f\x13\x4a\x95\x1a\x3d\x77\x82\x6e\ -\x97\x89\x27\x13\x42\x45\x61\x66\x76\x96\xee\xd1\x01\xa1\x9f\x22\ -\x53\xe0\x34\x4a\xf8\x49\x41\x12\x27\x24\x49\x81\x69\x5a\x28\x92\ -\x4a\x1a\x09\x5a\xa7\xa6\xdb\x24\x9e\x87\x51\x2e\x93\x46\x31\xb1\ -\x37\x01\x59\xc6\xaa\x94\x28\x24\x49\xf4\x2f\x4d\xd3\x5c\x49\x56\ -\x08\xf8\xa1\xa4\x61\xa9\x16\xaa\x2c\x33\xca\x02\x48\x52\xea\xb3\ -\x25\x0e\xc6\xfb\x58\x25\x87\x20\xf0\xd0\x4d\x8d\x48\xce\x88\x63\ -\x0f\x24\x95\x3c\x8c\x29\xcd\xcd\xb1\x7d\xb4\x0b\x8e\x41\x96\x47\ -\x8c\x7b\x87\xa0\xc9\xf8\xe3\x21\x0b\xed\x16\x1b\x3f\x7e\x97\x61\ -\x92\x20\x5b\x2a\x69\x96\x10\x0c\xfa\x58\x92\x44\xbb\x3d\xcb\xc6\ -\xf6\x6e\xa1\x2a\x28\xe4\xa9\x80\x37\xc4\x69\x82\xa6\xcb\xec\x6d\ -\x3f\xe5\x1b\xdf\xfc\x26\x4b\x9d\x26\xb7\x7f\xbc\xc1\xb3\x34\xe3\ -\xdc\xda\x05\x1e\x3c\x7a\xc4\xd2\xca\x69\xea\x8d\x32\xf7\xef\xdf\ -\xe7\xe5\xeb\xd7\xd9\x3f\x9c\x70\xba\x53\x62\x7b\xc7\xe7\xdc\x72\ -\x93\x1f\xbc\xf5\x16\xaf\xbf\xfe\x3a\x93\x49\x82\x69\x6a\x24\x09\ -\xc4\x71\x41\x4e\xc1\xfe\xfe\x3e\x97\x2e\x5f\x60\xfd\xe9\x53\xae\ -\x5e\xbd\x4a\x0e\xc4\x41\x40\xa5\x62\xd1\xed\x76\x4f\x90\xb3\x93\ -\x89\x20\x1e\xce\xcc\xb4\x3e\x53\x14\x8b\x82\x46\xa3\x81\xa6\x49\ -\xd4\xeb\x35\xa2\xa8\x38\x61\x21\x19\x06\xbc\xf3\xce\x87\xdc\xb8\ -\x71\x03\xd3\xd4\x08\xc3\xe4\x24\xbd\xe4\xfb\xfe\x09\x01\x64\x6d\ -\xed\x34\x96\x0a\xcf\x8f\x8e\x58\x58\xe8\x20\x49\x0a\x59\x96\xb3\ -\xbe\xbe\xcd\xca\xca\x0a\xc3\x71\x82\xe3\x38\xb8\x6e\x44\xa9\x24\ -\xf8\x4b\xc7\x5e\x6b\xdb\xb6\xd9\xdd\xdd\xe5\xf0\xf0\x90\xd5\xd5\ -\x55\x66\x66\x66\x48\x53\xa1\x62\x2f\x2f\x2f\x63\x9a\x86\x00\x9f\ -\x47\x11\x41\x20\x76\xff\xd1\x68\xc4\x95\x2b\x57\x44\x42\xaa\xa2\ -\x31\x70\x25\x1c\x47\x25\x08\x72\xf6\xf7\xbb\xd3\xce\x29\x88\xa6\ -\x4e\xc0\x38\xcd\xd0\x74\x85\x28\x0c\x45\x79\x9c\xaa\x80\x02\x9a\ -\xac\xa1\x19\x1a\x8a\xa1\x93\xab\x32\x66\xa5\xc2\x99\xb3\xab\xe4\ -\x52\x4a\x10\x4e\xa8\xd5\xab\xdc\x7c\xf3\x75\xfe\xf2\xed\xb7\x39\ -\xdd\xe9\xd0\xee\x2c\xa1\xa8\x32\xbf\xf3\x2f\xff\x08\xd5\xa8\x71\ -\xe8\x86\xdc\x79\xba\xc5\x30\x4b\xd8\x3e\xda\x87\xba\x83\xd9\x69\ -\x92\xa5\x12\x69\x3f\x44\xd7\x6c\x64\xc7\x24\x9e\x2a\xb5\x8e\xaa\ -\xa3\x04\x09\x63\x19\x94\x02\x74\x59\x43\x41\x21\x96\x20\x41\x26\ -\x95\x14\x90\x54\xe2\x34\x47\x55\x35\x01\x2a\x34\x0c\x92\xbc\x00\ -\xd3\x80\xc9\x84\xcc\x16\x0f\x3c\x4d\x37\xc9\x93\x14\x29\x17\xc9\ -\x2b\xb2\x62\x3a\x7b\x15\xa1\x82\x6e\xee\x91\xa6\x3e\xad\xb2\xcd\ -\x95\xd9\x65\x2a\x1a\x94\x0b\x88\xfb\x19\x5f\x7a\xf9\x3a\x33\x35\ -\x9b\xee\x78\x9e\xaf\x7d\xe3\xab\x84\x81\x47\x3e\x09\x99\x2d\x5b\ -\xe8\x71\x4e\x1c\x47\x20\x69\x9c\x9a\xa9\xb3\xbf\xf5\x9c\xb5\x8b\ -\x67\xf9\x8d\x5f\xfb\xbb\xfc\xaf\xbf\xf3\x6f\xd9\x1d\x7b\xc8\x19\ -\x38\x65\x9b\x38\xc9\x20\x0e\xe8\x0d\x07\xa2\xb2\x46\x2e\xa6\xe8\ -\x25\xa6\x30\x3d\x91\x42\xca\x92\x1c\x45\xc9\x51\x50\xa6\x0d\x30\ -\x12\xa9\xa6\x93\xc6\x09\x39\x99\xf0\x5b\x2b\x0a\x59\x9e\x8b\x8e\ -\x34\x43\x87\x2c\x21\x4e\x23\x52\x25\x47\x53\x54\xf2\x42\xc6\x0d\ -\x7c\x8a\x24\x13\x48\xdf\x24\x61\xf7\xe0\x90\xd3\xa7\x57\x78\xb6\ -\xf1\x14\xdd\x52\xe9\xcc\xcf\x92\x4b\x29\xde\xf6\x36\xf6\x99\x4b\ -\x04\x61\x84\xe7\x79\xac\x9e\x5b\xc5\x1d\xf4\x39\x7c\xf6\x84\xa4\ -\xe4\x50\x2a\x95\xb0\x0c\x9d\x91\x37\xa1\xb1\xb4\xc4\x83\xa7\xeb\ -\xbc\x72\xfa\x14\xf3\xba\xc2\xc3\x77\x7e\x48\xcd\x76\x70\x75\x8b\ -\x30\x4e\x91\x25\x4d\x26\xcd\xc4\xfd\xd4\xb1\x2d\x31\x03\x0c\x23\ -\x3e\xff\xda\x1b\x94\x34\x0d\x1d\x99\x70\x3c\x21\x8f\x13\x3e\xfd\ -\xe4\x36\x8d\x6a\x8d\xd7\x5f\x7d\x8d\xad\x8d\x4d\x0c\x5d\xcc\xbd\ -\x06\x13\xa8\xd4\x2a\xec\x8f\x32\xe1\x29\x9d\x2a\x76\x79\xce\x89\ -\x7d\x71\x34\x1a\x9d\xc4\xd9\x16\x17\x17\x85\x60\x36\x05\x78\x67\ -\x99\xb8\x03\x0b\x21\x89\x9f\xe0\x2c\x41\xad\x56\x3b\x11\xd9\x66\ -\x67\x67\x29\x69\x30\x1c\x8e\xd0\x34\x69\x0a\x47\x2b\xf1\xf4\xe9\ -\xae\xc8\xbb\x1a\x62\x11\xdb\xb6\x86\xe3\x58\xcc\xce\xce\x22\x49\ -\x12\x0f\x1f\x3e\xa4\x56\xab\xd1\xeb\x8d\xd9\x3e\x18\x73\xea\x54\ -\x87\x38\xce\x18\x0e\x47\x27\xed\x8b\xa7\x4f\x9f\x9e\x3a\xcc\x8e\ -\x55\xc5\x69\xbb\xc0\x14\x3e\xde\x68\x34\xb8\x70\x61\x95\x0b\x17\ -\x2e\xb0\xbb\xbb\xcb\x5b\x6f\xbd\xc5\x3b\xef\xbc\x43\x7b\x0a\xa7\ -\xf3\xfd\xcf\x2a\x3d\x45\x13\x45\x7a\x02\x44\x1f\x8f\xc7\xf4\xc7\ -\xc9\x34\x02\x29\xc6\x58\x9b\x9b\x9b\xac\xac\x2c\x23\x17\x20\x17\ -\x19\x2a\x82\xc3\xa5\x29\x10\xc6\x1e\x86\x2d\x16\xb1\xeb\x27\x4c\ -\xe2\x0c\x3f\x2d\xc8\x55\x85\x91\x17\x50\xaa\x35\x84\x30\xa6\x98\ -\x98\x66\x03\x07\x8d\x20\xd5\xb0\x9b\x8b\x54\x16\x57\x18\x4a\x32\ -\x1b\x5e\x41\xfb\xea\x55\xfe\xf4\xe3\x8f\x79\x77\xfd\x09\x4f\xfa\ -\x3d\x7c\x49\xa1\xb2\xb4\x48\x6b\x61\x19\x5d\x36\x29\x92\x94\xc2\ -\x0f\x21\x4d\x90\xc9\x41\xca\x91\xe4\x69\x47\xf0\x14\x3d\x9b\x49\ -\x12\x92\xa6\x09\x56\x33\x0a\x99\xa4\x88\x30\x4a\xa1\x91\xc4\x82\ -\x87\x9e\x84\x01\x9a\x2a\x93\x67\x09\x86\xae\x42\x18\x50\x24\x31\ -\x45\x9e\xa2\xc8\x08\x4a\xab\x54\x60\x68\x0a\x18\x2a\x69\x30\xc1\ -\xd6\x55\xd2\xc4\xa3\x36\xdb\xc0\x9a\xa9\x91\xeb\x12\x98\x32\xef\ -\x7f\x7c\x8b\x3b\x77\x1f\xf0\xe0\xe1\x1d\x4e\x2d\x75\xf8\xd5\x5f\ -\xfc\x59\x7e\xf1\x3f\xf9\x8f\xb9\xbc\x32\xcb\xe4\xa0\x47\xe2\x45\ -\x54\x14\x90\x52\x99\x38\xce\xd1\x2d\x05\xa7\xa4\x53\x69\xcd\xe0\ -\x47\x05\xb5\x1a\x0c\x5c\x97\xb1\x3b\xc1\x2a\x57\xc8\x99\xce\x90\ -\x25\x85\x7c\x34\x46\x9d\x8a\x61\x22\x52\x29\xee\xad\x4c\xa3\x95\ -\x69\x9a\x92\xe5\x09\x92\x5c\x9c\xd8\x2b\x75\x5d\x25\x4b\x22\x8a\ -\x24\x41\x99\x1a\x47\x84\x3b\x2f\x45\xd3\x35\xa1\xc6\xe7\x21\x79\ -\x12\x90\xa9\x39\x91\x9c\x10\x25\x1e\xb1\x94\x40\xd5\x22\x2f\x19\ -\x14\x15\x8b\xf5\x67\x4f\x90\xab\x25\x66\x4f\x9f\xe2\xf1\x83\x87\ -\x78\x59\x0e\xba\x49\x16\x7a\xa8\x49\x88\x5e\x24\x6c\xaf\xaf\x13\ -\x79\x13\xcc\x46\x03\xba\x3d\x74\xd3\x22\x49\x0b\xfc\x20\xc2\xb2\ -\x2b\xfc\xe0\x9d\x1f\x53\x6f\xd9\x68\xa6\xc1\x7e\xb7\x8b\x6a\x19\ -\xd4\x9b\x0d\xe2\x38\x16\x25\x6e\x9a\xa6\x31\x8a\x92\x33\x4b\xf3\ -\x0b\x58\x9a\xce\x85\xb3\x67\x59\xee\xb4\x88\xc2\x02\xa2\x94\x8b\ -\x97\x2e\xd2\x28\xd7\x58\x59\x5c\xc2\x54\xe1\xd4\xf2\x69\x36\x76\ -\xf7\xb0\x6d\x05\x53\x6a\x30\x1a\x8d\x58\x58\xa8\xf2\xce\x0f\xef\ -\x72\xf5\x85\x6b\xec\xed\xec\x32\x3b\x33\x23\xe4\x78\x49\x42\x55\ -\x65\x8e\xf6\x0f\x98\x5b\x5c\x20\xcb\x12\x4e\x2f\xcd\xb2\xfe\x74\ -\x9b\xc3\xfd\x7d\xce\x9c\x3e\xcb\xfe\xfe\x21\x45\x51\xb0\xb4\xd4\ -\x66\x34\x12\xb5\x2b\x9a\x26\x33\x99\x24\xd4\x6a\x0e\x77\xef\x8a\ -\x54\x54\xaf\xd7\x43\xd7\x75\x16\x3a\x55\x36\xb7\x7b\x2c\x2c\x34\ -\xf1\xbc\x8c\xed\xed\x6d\x6e\xdc\xb8\x81\xef\x87\xd3\x46\x00\x81\ -\x8f\xed\xcc\x94\x28\x97\x4b\xdc\xbe\x7d\x9b\xf1\x78\x2c\x9a\x0f\ -\x14\x05\xcf\xcb\x18\x0c\x06\x2c\x2d\xb5\xb8\x7f\x7f\x83\x72\xb9\ -\x8c\xaa\x2a\x80\x4e\x1c\x8b\x9c\xb2\x88\x38\x2a\x7c\xf0\xc1\xa7\ -\x34\x1a\x8d\x13\x82\xe2\xd2\x7c\x9d\xd9\xd9\x3a\x41\x90\x71\xef\ -\xde\x3d\x3e\xfa\xe8\x23\x92\x24\xa1\xd9\x6c\x9e\x84\xc8\x65\x59\ -\xe6\xe8\xe8\x88\xb9\xb9\x39\x1a\x75\x93\x46\xdd\x64\xe2\xe5\xd4\ -\x2b\x1a\x43\x37\x3d\x29\x00\x6b\xb7\x6a\xb8\x5e\x40\x41\x86\xa4\ -\xd8\x68\x4a\x8e\x24\x4a\xb8\x50\x75\xf0\xfd\x8c\x5c\x97\x90\x25\ -\x85\x4c\x12\x4f\x88\x81\xeb\xd3\x9c\x5b\x20\xcd\x61\xe2\xe5\x98\ -\xba\xcc\xc3\xe7\x13\xca\xed\x12\x6f\xbd\xf3\x21\x9f\x3c\xdb\xe6\ -\xf1\xce\x0e\x97\x5f\x7e\x9d\x67\xbb\x5d\x86\xaa\x42\x94\x43\x64\ -\x59\x94\x6a\x35\x72\x52\xdc\x89\x4f\x14\x07\xd4\x2a\x55\x86\x8c\ -\x91\x25\x81\xff\x51\x81\x54\x96\x51\x74\x05\x55\x52\x50\x1d\x8b\ -\x28\x4b\x91\x4d\x9d\x54\x2a\xc8\x10\xb5\x42\x12\x0a\x85\x6a\x92\ -\xc5\x19\xb9\x95\x91\x26\x21\xaa\xa4\xa1\xcb\x32\x45\x1a\x83\x5c\ -\x90\x84\x01\x86\x53\x22\x27\xa1\x20\x45\x92\x25\x74\x55\xc6\x91\ -\x0d\xbc\x7e\x1f\x5d\x93\xc0\x8d\xe8\x3e\xfe\x14\x1c\x83\x68\x34\ -\xa2\xad\xe4\xf4\xab\x36\x3f\xfd\xd7\xbf\x42\x53\x17\x41\x93\xa3\ -\xee\x84\xb9\x66\x99\x89\x57\xe0\xd8\x36\xb2\xa4\xb2\x7b\x14\x23\ -\x27\x09\x95\x96\xc3\xf3\x51\x8e\x27\xc1\xd2\xb9\x15\x1e\x3d\x1f\ -\xb2\x79\x7f\x00\x8a\x81\x6e\xcb\xf8\x51\x8c\x17\x4f\xc7\x5b\x9a\ -\x06\xfe\x04\xd3\xb6\x28\xb2\x54\xb0\xcb\x8a\x02\x05\x09\x45\x92\ -\xc9\x24\x89\x22\xcf\x11\x71\x62\xe9\xd8\x6d\xc9\x71\x37\xe9\xb1\ -\xb2\x5d\x80\xa8\x69\x29\x24\x24\xb9\x40\x93\x20\x89\x0b\xc8\x63\ -\xd2\x54\x15\x45\xe7\x6a\x01\xb2\x24\x36\xa7\xa4\x20\x4f\x63\xd4\ -\x56\x83\x3c\x4f\xd9\xde\xdd\xc3\x6e\xb6\x08\xfd\x80\xf2\xdc\x1c\ -\x6e\xb7\x87\x26\x41\xa7\xb1\xc8\x17\x7f\xee\xaf\xf3\xf6\x0f\x7f\ -\xc0\xc0\x9d\xb0\xdf\x68\x30\x1e\x4f\xc4\x83\xa1\x31\x43\xee\x4f\ -\x78\xf6\x7c\x17\x49\x82\x49\x92\xb3\xb4\xba\x8a\x55\x76\xa8\x38\ -\x95\xa9\x45\xb3\x48\xc5\x9b\x67\x4a\xc8\x30\x14\x95\xb5\x95\x33\ -\x98\x12\x18\x48\xa8\x39\x64\x7e\x84\x26\x49\x5c\x58\x3d\x27\x8e\ -\xe1\x28\x38\x76\x99\x49\x90\x53\xab\xa9\x54\x6a\x55\x36\xb6\x7a\ -\x94\xab\x55\x9a\xcd\x26\xb3\xb3\xb3\x6c\x6f\x6f\x0b\x0b\x6a\x01\ -\x87\x87\xdd\x93\x7e\xdb\xd9\x56\x83\x5e\x6f\xc2\xea\xe9\x45\x64\ -\x59\x66\x7b\x7b\x9b\xc3\xc3\x43\xe6\xe7\xe7\x8f\xff\xaf\xa6\x49\ -\x13\xf1\xe7\xee\xee\x11\xd5\x6a\x95\x8b\x17\x4f\x9d\x04\x19\xc2\ -\x44\x78\xb1\xb3\x0c\xee\xdd\xbb\xc7\xdc\xdc\x1c\x86\xa1\x50\x2e\ -\x9b\xd4\xeb\x36\xfd\xfe\x00\xcb\xb2\x70\xfd\x82\x4f\x3e\xb9\xc5\ -\xd7\xbf\xfe\x75\x3a\x9d\x0e\x79\x9e\x33\x1e\x0b\xc0\xc0\xe2\x62\ -\x8b\xc1\x20\x64\x77\x77\x97\x76\xbb\x4d\x1c\x7f\x36\xc4\x57\x14\ -\x71\x2a\x08\x02\x31\x26\x7b\xe9\xea\x59\xda\x2d\x07\xcf\xf3\x18\ -\x8c\x13\xc2\x30\xc7\x30\x14\xba\xdd\x2e\xdf\xf8\xc6\x37\xa6\x0a\ -\xf5\x06\x9f\x7c\xf2\x09\xcf\x9f\x3f\xc7\xf7\x7d\x7a\x3d\xe1\xd4\ -\xd9\x7a\xde\xc5\xf3\x05\x4c\x2f\x88\xc5\x51\xee\xe8\x48\xbc\xa6\ -\xa2\x00\xb9\x48\x30\x28\xa0\xc8\x50\x15\x09\xd7\x1d\x63\x96\x74\ -\x52\x49\x50\x3b\x0a\x59\xac\xb0\x42\x15\x7d\xd5\x49\x01\xa6\xed\ -\x20\xc9\x88\xe4\x8e\x04\x8b\xf3\x25\xb2\x14\x2a\x95\x36\x1f\xdf\ -\x5b\x67\x52\x28\xfc\xee\x9f\xfc\x07\xde\x7d\xf4\x88\x2e\x30\x92\ -\x20\xd7\x35\xdc\x3c\x67\x1c\xc4\x44\x71\x0e\x89\x84\xa3\xdb\xc8\ -\x8a\x8e\xcc\x34\xd9\x33\xed\xc8\xce\x64\x40\x13\x7a\x46\x94\xc4\ -\x20\x4b\x64\xf9\x14\x01\x5b\xc8\x28\x92\x8a\xa6\x0a\xaa\x24\x45\ -\x86\x22\x15\x64\x69\x8c\x69\x68\x42\x9d\xb6\x4d\x48\x22\x90\x72\ -\x20\x27\x27\x23\x4a\x43\xa2\x34\x24\x2f\x12\x48\x02\xa2\xd0\x05\ -\x44\xac\x90\x3c\xe5\xa5\xab\x57\xf8\x6f\xff\xe1\x7f\xc5\x1b\xaf\ -\xde\xe0\xdd\x1f\xbc\xc3\x70\xe8\x73\xaa\x5d\x46\x95\x0a\x74\x05\ -\x4c\x53\x62\xed\xe2\x25\x06\x7e\x88\x27\x2b\x04\x86\x49\xac\x43\ -\xa9\x2a\xa3\x57\x64\xfa\x1e\x7c\xf4\xe9\x3d\xfe\xf8\x2f\xbe\x4b\ -\x22\xc9\x68\x76\x19\xef\xe0\x40\xe4\x98\x65\x15\xd9\x34\x40\x53\ -\xc9\x8a\xe9\x89\xeb\xb8\x3e\xf8\x78\x31\x2b\x12\x12\x39\x79\x2a\ -\x52\x59\xc9\x54\x97\x48\xf3\x4c\xf4\x3d\xa9\x2a\x59\x92\x10\x27\ -\x11\xb2\x2c\x9d\xf0\xad\x4d\x49\x41\x55\xa6\x44\xcc\xc0\x87\x3c\ -\x06\x4b\x03\x5b\x27\x2f\x12\xf4\x56\x0d\xb2\x58\xd0\x33\x55\x8d\ -\xd4\x0f\xf1\xbb\x03\xf2\x91\x87\xe2\x85\xe4\x47\xfb\xfc\xfc\x57\ -\xbe\xc8\xe1\xb3\xc7\x18\x49\x44\xcd\x34\xd8\xbf\x75\x0b\xc7\xb4\ -\x90\xf2\x82\x02\x99\x02\x85\x20\x2b\xe8\xbb\x01\xcf\xfb\x90\xc9\ -\x32\x8d\xf9\x45\x86\x5e\x40\xab\xdd\x16\x66\x94\x2c\xcf\xc9\xc9\ -\x31\x74\xf5\x69\x10\x78\x0c\x87\x7d\x46\xc3\x21\x81\x97\x11\xb8\ -\x3e\xf5\x72\x85\x07\x77\xef\x11\xfb\x31\xf5\x4a\x9d\x20\x48\x70\ -\x7d\x8f\x34\xcf\xd8\xd9\xdd\x25\xce\x41\x56\x61\x6b\xfb\x39\xf3\ -\x8b\x0b\xa0\xc8\x74\xe6\xe7\x18\x8e\xc7\xf4\xfb\xa2\x8a\xe5\xde\ -\xdd\x4f\x59\x59\x59\x99\x8a\x41\x09\xa6\xa6\x13\x7a\x29\xe7\xcf\ -\xad\xb1\xb9\xb9\x49\x51\x14\xb4\xdb\x2d\x0e\x0e\x06\xd4\xab\x82\ -\xfa\x1f\x45\x09\xba\xae\x9e\x88\x5d\xae\x9b\x9e\x58\x20\xdf\x7b\ -\xef\x43\x2c\x4b\x63\x38\xf4\x4e\x4a\xd4\x26\x93\x70\xaa\x70\x8b\ -\xd0\x84\x2c\x0b\x93\x86\xe8\xd0\xd5\x28\x95\x4a\x2c\x2c\xcc\x31\ -\x3f\x2f\x6c\xa3\xf7\xee\x3d\x65\x7f\x7f\x1f\xdb\xb6\xa9\xd5\x1c\ -\x4c\x53\x98\x3e\x4a\xb6\xc4\x64\x22\xae\x06\xc7\x10\x00\x37\x80\ -\xde\x20\x14\xe3\x92\x8a\xc6\x70\x38\x64\x77\xf7\x90\x7a\xbd\x8e\ -\xe3\x88\x34\xd4\xcd\x9b\xd7\xb8\x7e\xfd\x3a\x33\x33\x33\x1c\x1c\ -\x1c\xb0\xb7\xb7\xc7\x68\x34\x3a\x89\xbe\x55\x2a\x15\x92\x24\xa7\ -\x62\x4b\x1c\x1c\x1c\x30\x3f\x3f\x8f\x3f\xf1\xb1\x74\x03\xd3\x30\ -\x4e\x18\xce\xfb\xfb\xbb\x34\x5a\x4d\xb2\x7c\x9a\x1e\x2a\x84\x4f\ -\x39\xcf\x21\x08\x62\x11\x44\x40\x30\xb6\xa4\x69\x2f\x56\x1a\x09\ -\x72\xcd\xf2\xe2\x0a\xff\xe0\xd7\xfe\x1e\xaf\xbf\xf6\x39\x0c\xc7\ -\x06\x43\x27\x57\x24\x30\x0d\xe4\x46\x1d\xd5\xb6\xd1\x2c\x87\xf6\ -\xec\x3c\x86\xe5\x30\xec\xbb\x48\x92\x42\x14\xa7\x04\x51\x4c\x92\ -\xe6\xe4\x59\x8a\x1f\x44\xa2\xea\x54\x95\xc5\x37\x57\x24\xf2\x5c\ -\x04\xec\x55\x0a\x34\x49\xc6\x56\x15\x48\x13\x54\x45\x9a\x22\xd1\ -\x0b\x54\x09\xa4\xbc\xc0\xb6\x6c\xc8\x53\xd2\x34\xa6\x90\x72\x0a\ -\x49\x24\x98\x3c\x6f\x4c\x10\x7a\x50\xa4\x78\xe3\x01\xb2\xaa\x00\ -\x0a\x86\x6a\x40\x9c\xa2\x66\x50\x71\x1c\xda\x8d\x3a\xed\x9a\xcd\ -\x41\x6f\x8c\x61\x18\xec\x1e\x0e\x89\x81\x48\x93\xf8\xf1\xfa\x3a\ -\x81\xa3\x30\x71\x14\xb6\x13\xf8\x78\x27\x60\x6f\x04\x7f\xf4\x67\ -\xdf\xe3\x87\x1f\xde\x62\xe3\xc9\x33\x76\x77\x77\x09\xb3\x29\xd7\ -\xd9\x14\x55\x30\xca\x14\x5f\x1b\x78\x1e\x71\x9a\x9c\x24\xb2\x8a\ -\x4c\xcc\x7f\x8f\x4f\x8f\x3f\x39\xff\x4d\xf3\x4c\xd8\x2b\x0d\x1d\ -\xc5\x10\x29\xa8\x7c\x7a\x32\x93\x14\x19\x29\x2f\x90\xd3\x1c\x23\ -\x57\x21\x47\x20\x4f\x93\x0c\x45\xd3\x91\x54\x19\xf2\x94\x22\x09\ -\xa9\x74\x66\x29\x36\x37\x28\x26\x13\x7e\xe1\xab\x5f\x63\xce\xb4\ -\x59\xb6\x4a\xbc\x72\xe6\x0c\x37\x2f\x9d\x27\x1f\x1d\xd1\xb6\x75\ -\x26\x87\xbb\xfc\xca\xdf\xfc\x19\x94\x92\x8d\x92\xe5\x24\xfd\x01\ -\xaa\xac\xd1\xed\x0f\x08\x93\x9c\x18\x89\x0f\xef\x7c\x8a\x62\x43\ -\x6f\xec\xb3\xd7\x1b\x00\x82\x4c\xa2\x2a\xd3\xca\xc7\x02\x48\xf2\ -\x8c\x9d\x9d\x1d\xf6\xf6\xf6\x48\xa2\x98\xfd\x1d\x51\x2c\x95\x35\ -\x52\x6c\x5b\xa7\xd6\xd4\x79\xe7\xe3\x67\xf4\x07\x43\xb0\x4c\x36\ -\xb7\x9f\xb3\x32\xdf\x11\xe7\xfc\x69\x4c\x4f\x00\xc5\xa4\x13\x88\ -\x5d\x32\x33\x83\x6d\xdb\x38\x96\x4e\x51\xc0\xd1\x60\xc4\xca\x62\ -\x8b\x8d\xed\x2e\xf5\x56\x93\x72\xb9\x4c\xb9\x5c\x66\x38\x1c\x0b\ -\xb3\x48\xce\x09\x36\xe5\xe0\xe0\x88\x66\xb3\x89\xef\xfb\x38\x8e\ -\x8d\x60\x90\xeb\xb4\xdb\x6d\xee\xdd\x7b\x84\x61\x18\x2c\x2e\x2e\ -\x12\x45\x11\x8e\x63\x33\x18\x08\x30\xf9\x4c\xd3\xa6\x3f\x8c\x18\ -\x8d\x46\xd4\x6a\x35\x24\x49\xa2\x59\x33\xd8\x3f\x12\x77\xf2\xcb\ -\x97\x2f\xf3\xf8\xf1\x63\x9e\x3d\x7b\xc6\x85\x0b\x17\x18\x0c\x44\ -\xcd\x89\x61\x18\x64\x05\x27\x45\x5f\xdd\x6e\x97\x97\x5f\x7e\x99\ -\x92\x05\x59\xa6\x4d\x9d\x5e\x26\xf5\x7a\x9d\xfd\xfd\x7d\x4e\x9f\ -\x3e\x4d\x92\x08\xf5\xbb\xdb\xf5\xd1\x75\x9d\x6a\xb5\x4a\xbf\xdf\ -\x67\x6d\x6d\x0d\xc7\x71\x78\xfc\xf8\x31\xaa\xaa\x9e\xa8\xd7\x03\ -\xdb\xc6\xf7\x7d\x9a\xcd\x26\x65\x47\xc6\x1d\x86\xc8\xba\xc0\xbf\ -\x98\xb6\xc1\xd1\x51\x8f\x0b\x57\x2f\x8b\x51\x86\xac\xa2\x1b\xaa\ -\x08\xe6\x4b\x10\xba\x11\x25\x4b\xc7\x90\x40\x4e\xc1\x56\x41\x4a\ -\xc0\x77\x13\xdc\x3c\xe6\xc5\x0b\x6b\xc4\x09\x7c\xfe\x95\x0b\x60\ -\xda\xfc\x6f\xbf\xfb\x7b\x34\x3b\x8b\xf4\x46\x01\x79\x96\xe1\x47\ -\x31\xb9\xeb\x91\x9a\x16\x92\xac\x92\xa5\x29\xa6\x25\x7c\xd4\x28\ -\x3a\xba\x6d\x8a\x37\x39\x05\x99\x24\xc0\x0e\x41\x9e\x0a\x61\x36\ -\x4b\x29\x00\x2d\xcf\xd0\xf2\x02\xb3\xc8\xf1\xa2\x08\x55\x82\x82\ -\x0c\x43\x37\x09\x83\x60\x3a\xa7\x15\x5e\xa3\xd0\x0f\x91\x75\xfd\ -\x04\xd9\x8a\x24\x83\x26\x43\xa5\x0c\x13\x8f\x72\xb3\x4e\x9e\xa7\ -\xc8\x91\x4f\x78\x34\x20\x1e\x14\xe8\x51\xcc\x64\x38\x61\x63\xf3\ -\x88\xd9\xf9\x19\xc6\x69\x8e\xdd\xac\x71\x14\xc1\xc3\xed\x3d\xfe\ -\xf4\xc3\x0f\xf9\xcb\xf5\x67\x44\x89\x40\xfe\x8c\xfa\x23\xda\xed\ -\x0e\x0f\x9e\x3e\x25\x91\x14\xa8\x36\x00\x85\xa4\x28\x50\x1a\x75\ -\x64\x45\x98\x43\xf2\x2c\x17\x74\xc1\x89\x0b\x96\x3e\x75\x56\x49\ -\x80\x82\xaa\x48\x14\x85\x2a\x60\x02\x59\x26\x14\x69\x85\xe9\xe9\ -\x4c\x43\x9e\xa2\x78\x33\x45\x80\xec\xd3\x34\x45\x53\x64\x74\x49\ -\x43\x49\x72\xa4\x58\x46\x4b\x55\x92\x1c\x48\x25\x94\x38\x43\x51\ -\xc5\x43\x3a\xd9\xde\xa1\x31\x3f\x8f\xb9\x34\x47\xd4\x1b\x72\x65\ -\x66\x86\x5f\xf8\x07\xbf\xca\xfa\xed\x3d\xae\x5d\x9d\x43\xd2\xe0\ -\xef\xfc\xbd\xbf\x8f\xe9\x94\xa8\x69\x32\xc9\x28\xe6\xc5\xf3\x17\ -\xd9\xec\x0d\xc0\x30\xd1\x64\x05\x45\xd1\xc9\xb3\x98\xfa\x4c\x9b\ -\x4f\x1f\xad\xf3\xb5\x37\x2e\x73\x34\x9e\x50\x2a\x55\x38\xea\x75\ -\x51\x92\x18\x39\x43\x6c\x26\xfd\xc0\x2b\xcc\x92\x43\x6f\x24\xfa\ -\x7a\x2c\xc7\x62\x34\x71\x69\xb4\x9a\x9c\x3a\x75\x8a\xdb\x77\xef\ -\x33\xf6\xe0\xe9\xf3\x4d\x0c\xcb\x24\x4a\x62\xfe\xf8\x3b\x7f\x42\ -\x10\x04\xf8\x53\x6b\x99\xa2\xc9\xf8\xbe\x8f\xa4\xc2\x99\xd3\x6d\ -\x5c\xcf\xe3\xf9\xf3\xe7\xbc\xf1\xc6\x4d\xba\xdd\x21\x45\x21\xd2\ -\x47\x07\xdd\x09\xa7\x16\x5b\x7c\xf2\xc9\x27\xac\x4d\x15\xe1\xcd\ -\xcd\x4d\x66\x67\xeb\x1c\x1c\x0c\x71\x1c\x01\x19\x78\xf4\xe8\x11\ -\xb6\x6d\x73\x7a\xa9\x45\x14\x09\x4e\x58\x9e\xe7\xac\xad\x2d\x51\ -\x2a\x95\xb8\x77\xef\x1e\xb6\x6d\x8b\x85\x2c\xc2\x27\x94\x4a\x36\ -\xe3\x89\x30\xa5\x6f\x6e\x6e\xd2\xe9\x74\x50\x55\xd8\xd9\x1f\x61\ -\xdb\x36\xd5\xaa\x68\xfe\x3b\x7d\xfa\x34\xb5\x5a\x8d\x28\x8a\x58\ -\x5f\x5f\x9f\xa6\x93\x64\xfa\x7d\xb1\x20\x8f\x7d\xb2\xba\x2e\xd1\ -\x1f\x89\x23\xb6\xe8\x0d\x12\x14\xcd\xcd\xcd\x4d\xea\xf5\x2a\xe3\ -\xf1\x98\x72\x59\xc7\xb6\x6d\xca\x65\x03\x45\x11\xc5\x6f\xf3\xf3\ -\xf3\x54\x2a\x15\xbe\xf2\xa5\xd7\xb9\x76\xed\x1a\xe5\x72\x99\x4a\ -\xa5\xc2\xed\xdb\xb7\xd9\xdb\xdb\xe3\xf6\xed\xdb\xac\x3f\xd9\x65\ -\xec\xfa\x84\x41\x4a\x12\x17\x68\x9a\x08\x9a\x37\x6b\xb5\x29\x64\ -\x2d\x23\x8b\x23\xf2\x38\x25\x8f\x73\x92\x20\xc0\x94\x41\xc9\x73\ -\xa4\x14\x74\xa0\x6c\x42\xcd\xd1\x88\xc7\x3d\xdc\xc3\x1d\x96\xcb\ -\xa0\x06\x70\xf3\xfc\x32\x2f\x9f\x3f\x87\x1e\x45\xd0\x3d\x82\x38\ -\xa1\x56\x2e\x21\x5b\x06\x49\x9e\x09\x66\x5a\xa9\x44\x92\xcb\xa4\ -\x49\x41\x9a\x16\xe4\x85\x22\xd8\x58\x61\x4c\x1c\x06\xe2\x98\x9c\ -\x27\xa8\x52\x8e\x4e\x82\x5e\xc4\xe8\x79\x8c\x91\xc7\xe8\x45\x82\ -\x94\x06\xa8\x14\x64\x89\xc0\xea\xf8\x13\x0f\x5d\x56\x48\xe3\x4c\ -\x70\xb9\xbc\x80\x3c\x08\xc5\x95\x49\xd3\x91\x4a\x36\x76\xb5\x46\ -\xb9\xd5\x84\xa2\xa0\x64\x95\xc8\x83\x84\x92\xea\xa0\xcb\x3a\xba\ -\x2a\x31\x37\x57\xe2\xdc\xda\x25\x86\x13\x9f\x20\x05\x3f\x93\x88\ -\x14\xf8\xed\x7f\xf1\xaf\xf9\xa7\xbf\xf7\x2d\x0e\x52\x78\x67\xfd\ -\x29\xb7\x0f\xfb\xac\x0f\x5c\x72\xbb\xc2\x47\xf7\x1f\x11\x4b\x1a\ -\x7e\x52\x40\x0a\x4a\xb9\x42\x9c\x64\xe4\x85\x98\x96\x1c\xdb\x24\ -\x2d\xcb\x9a\xb2\xed\x74\x24\x94\x93\xf6\x87\x63\xc8\xc3\x49\xb9\ -\x39\xd3\xf4\x9b\xae\xa1\xe8\x53\xa0\x9e\x2c\x09\x1f\xb6\x24\x89\ -\xc5\x9e\x89\xea\xdd\x22\x81\x22\x91\x91\x73\x05\x59\xd2\x21\x97\ -\xc8\xc2\x18\xe2\x14\x4b\x2a\x68\xb5\x1b\xc4\x83\x23\xe2\xee\x01\ -\xff\xd1\xeb\xaf\x30\x7e\xf6\x98\x56\x0e\x7f\xe3\x0b\x73\x2c\x18\ -\x90\xf6\x47\xfc\xcf\xff\xe8\x37\xb9\x74\x6a\x89\x95\x76\x93\xd1\ -\xde\x2e\xff\xfd\xaf\xff\x12\x45\x10\x50\x36\x0c\x46\xbd\x3e\xb6\ -\x61\x12\xf7\x47\x98\x96\xc3\xc3\x27\x4f\x79\xb4\xd1\xa3\x37\xf1\ -\xb0\x2b\x55\x0e\xbb\x3d\xc2\x30\x44\xf9\x8d\xdf\xfa\x4d\x12\xe0\ -\x93\x87\xf7\x7f\xab\x3b\x1a\x13\x64\x39\x76\xb5\x4a\x92\x64\x78\ -\x7e\xc0\xc2\xc2\x3c\x4b\x73\x65\x7e\x7c\xeb\x1e\x95\x46\x13\xd9\ -\xd0\xa8\xcc\xb4\xf8\xee\xdb\x6f\x53\x14\x39\x8e\xa1\xe3\x8d\x47\ -\x7c\xf1\xd5\xab\x6c\xef\xf7\x29\x97\x1c\x6c\x5b\xe6\x60\x6f\x8c\ -\x6d\xdb\xec\x3c\x7f\xce\xdc\xdc\xc2\xf4\x78\xab\x32\x1c\xba\x54\ -\xab\x82\x3f\xf4\xd1\x27\xb7\xb9\x76\xed\x32\x69\x9a\xb3\xb4\xb4\ -\xc4\xa3\x47\x4f\xa6\x35\xa5\x1a\x07\x07\x22\x4c\x30\x37\x37\x47\ -\x7f\x38\x99\x7e\xbd\x46\x14\x65\xa4\xa9\x38\x9e\x8a\xcc\xb2\x58\ -\xa0\x9a\x61\x8b\x81\x7f\x92\x62\x9a\x1a\xf7\xee\xdd\xa7\xd3\xe9\ -\x30\x33\xd3\x20\x49\xf2\x69\xfe\x53\x47\x51\x20\x0c\x53\xee\xdf\ -\xbf\xcf\xca\xca\x0a\xab\xab\xcb\x98\xa6\xcd\x70\x38\xe4\xc9\x93\ -\x67\x98\x53\x4c\xcb\xee\xee\x2e\x2b\x2b\x2b\x14\x85\x8c\x69\xea\ -\x84\x61\x84\x61\xa8\x04\x41\xc8\xf3\xe7\xcf\x99\x9b\x9b\xc3\x9a\ -\xd6\x5a\x4a\x92\xa0\x7b\x2a\x8a\x10\xd9\xf6\xf7\xf7\xe9\x74\x3a\ -\x58\x96\x49\x10\x66\xe8\xba\x80\xce\xd5\xeb\x15\x5a\xad\x36\x41\ -\x10\xb0\xba\xba\x4a\xaf\xd7\x67\x30\x98\xb0\xb1\xb9\xcb\x60\x38\ -\x22\x2f\x14\x9e\x6e\x6e\x32\x37\xb7\x48\x91\xe5\x58\xa6\x81\xef\ -\x79\x38\xa6\x49\xd9\x54\x38\xda\x3f\xc0\xd1\x35\x6c\x5d\xc3\xd6\ -\x34\xd2\xd0\xa7\x28\x72\x14\x39\xc5\xf3\x06\xf8\xee\x80\xa5\x85\ -\x79\xc2\x89\x8f\xa5\x69\xcc\xcd\x2c\xf0\xe3\xf7\x3e\x60\xe4\x45\ -\x48\x8a\x42\x9e\x09\xe2\x73\x14\x47\xa4\x49\x0c\x05\x18\xaa\x43\ -\xd4\x1f\x63\x2f\xcc\x93\x48\x39\x45\x2c\xee\xc4\xb6\xaa\x12\xbb\ -\x2e\x92\x5c\x20\xe7\x09\x8a\x9c\xd3\xa8\x96\xb9\x7e\x71\x8d\xaf\ -\xbd\xf9\x06\x47\x4f\x9f\xd0\x3b\x3c\xa0\xd4\x9e\x61\x74\xb0\x4f\ -\x98\x64\x14\x61\x4c\x74\xd0\xc5\x28\x57\x40\x33\xc8\xa3\x88\xf2\ -\xf2\x12\x71\x91\x23\x4f\x45\xa6\x42\x92\xa7\xbf\xa7\x8c\x2c\xc9\ -\x31\x35\x1d\x53\x56\x38\xb3\xb4\xc8\xcd\x97\xce\x40\x06\x59\xa1\ -\xb2\xbe\xb9\xc9\xdc\x6a\x07\xc5\x90\xf8\xed\xff\xeb\xdb\xdc\xde\ -\xd8\xa6\x1b\x26\x28\xd5\x26\x7e\x06\x79\x94\x93\x5a\x25\xc6\x83\ -\x11\x69\x0e\xb9\xa4\x52\xa8\x3a\xcd\xa5\x25\xbc\xd1\x08\x8a\x02\ -\xa3\x5c\x21\x89\x63\x4a\xe5\x32\xf1\x60\x80\xe1\xd8\x28\x86\x4e\ -\x74\xb0\x8f\x55\xad\x92\x65\x05\x25\xa7\xcc\x78\xec\x12\x86\x3e\ -\x85\x37\x41\x2e\xd9\x14\xd3\xf4\x51\xc1\xb4\xa0\x20\x0a\x4f\xbc\ -\x07\xba\xa9\x93\x8e\x47\x14\xaa\x82\xa9\x5b\xc4\x7e\x4e\x91\xcb\ -\x28\xa6\x45\xa9\x5a\x23\x4c\x63\xf2\x34\x11\xf5\xb7\x72\x8e\x45\ -\x86\x9e\x86\xbc\x71\xf9\x22\x5f\xbd\x79\x1d\x3b\x0e\xa8\x2b\x3a\ -\x0b\x55\x13\x42\x50\x75\x99\x85\x59\x07\x45\xd6\x90\x8a\x82\xd9\ -\xf6\x2c\xf5\x9a\x81\x6c\x34\xb8\xf7\xe0\x21\x51\x9a\x10\x46\x11\ -\x92\xae\xa2\x49\x30\x53\xab\xd0\xae\xd7\xa9\x58\x16\x17\x4e\x9f\ -\xe2\x7b\x7f\xf2\x47\xcc\xd6\x6b\xc8\x31\x09\x05\x32\x61\x14\x23\ -\xab\x3a\x85\xac\xb0\x76\xe9\x12\xdb\x07\x07\x34\x67\x67\x88\x8b\ -\x8c\xad\x23\x8f\xf9\xc5\x05\xee\x3d\xf8\x94\xf6\x5c\x87\x73\xe7\ -\xe6\xb0\x2c\x83\xfe\x70\xc8\xce\xf3\x2d\xc2\x20\x60\x14\xc1\xc2\ -\x5c\x03\xdb\x56\xd9\xdf\x19\xd0\xe9\x54\x78\xbe\xb9\xc9\xea\xea\ -\x2a\xdb\xdb\xdb\x54\x2a\x06\x4f\x9e\xec\xb2\x38\x53\xc6\x0f\x22\ -\xde\x7a\xeb\x1d\x3e\xff\xf9\xcf\x93\xa4\x9c\xf4\xd2\x36\x1a\x0d\ -\xee\xdd\xbb\x87\xef\x87\x6c\x6d\x6d\x71\xea\xd4\x32\xae\xeb\xd2\ -\x6c\x96\xa8\x94\x55\xf6\xf7\x07\x58\x96\x71\x62\xce\x58\x59\x59\ -\x61\x6d\x6d\x8d\xc3\xc3\x43\x1e\x3e\x7c\x74\x72\xcf\xf1\xfd\xe8\ -\xe4\xa8\x7f\x2c\x9e\x55\x2a\x36\x61\x18\x33\x1a\x09\x65\xdb\xf3\ -\x3c\xe6\xe7\x67\xf0\xbc\x98\xce\x6c\x85\xe5\xe5\x65\x96\x97\x97\ -\xe9\x76\xbb\xdc\xba\x75\x8b\x9d\x9d\x1d\x2a\x95\xf2\xf4\x5e\x1f\ -\x4f\xef\x4f\x9c\xc0\xd7\x6c\xdb\x3e\x69\x38\x14\x5e\x78\x71\x7e\ -\xf4\x7d\xff\x24\x38\x9e\x65\xf9\xb4\x27\x8a\xe9\xd8\x02\x0e\x0e\ -\x0e\x58\x5d\x5d\xa5\x5a\xad\xb2\xb6\x76\x9e\x6b\x2f\x5d\xe4\xa5\ -\x9b\x37\x38\x77\xe1\x0a\x69\x2e\x93\xc4\x05\x9b\x9b\x5b\xdc\xbd\ -\x7b\x8f\xf7\xdf\x79\x97\xc9\x60\xc4\xb8\xdf\xa3\x7b\xd8\xe7\xe8\ -\x70\x1f\x4d\x53\x28\x95\x6c\x6c\x5b\x46\x56\x25\x34\x43\x22\x57\ -\x13\x2a\x25\x1d\x47\x97\x29\xfc\x90\x96\x66\x50\x2e\xe0\x6c\xab\ -\xcc\x99\x56\x8b\x96\x65\x62\x17\x12\x72\x9a\x92\xa5\x09\x9a\x22\ -\xa3\xe9\x82\x75\x66\xdb\x22\x27\xeb\x8f\xc6\x98\x8a\x86\x53\x29\ -\x8b\x2a\x8a\x38\x64\xa6\x56\x21\x1d\xf4\x68\x57\x1c\x82\x41\x97\ -\xf9\x46\x95\x9f\x7a\xfd\x15\x46\xdd\x7d\xe6\x67\xea\xcc\xcf\xd4\ -\xd9\xbe\xf3\x09\x64\x09\x8d\xb2\xc3\xa9\xe5\x25\x5a\x0b\x4b\x94\ -\x0d\x0b\x5d\x52\xa0\x54\xc6\xed\x0d\xc5\xbd\x4d\x11\xdc\xab\x42\ -\x92\x89\xc2\x04\x72\x49\x04\x1a\x64\x85\xbe\xeb\xb2\x7d\x74\xc4\ -\xde\x08\x24\x13\xf4\x86\x44\xea\x54\xd8\x1e\xc3\xf7\x6f\xed\xb1\ -\x37\xf4\x08\xd1\x30\xcb\x4d\xfc\xb0\x10\x9f\xe4\x27\x64\x6e\x88\ -\xe6\x54\xa9\x34\xdb\x60\x58\x54\x5a\x2d\x86\xae\x8b\x54\x2a\x7f\ -\x86\xab\x2d\x0a\x26\xe3\x11\xda\xd4\xc2\x9b\x25\x19\x28\x3a\xe3\ -\xa1\x98\x62\x8c\xc7\x22\x9c\x4f\x51\x60\x34\x1b\x53\x7c\x8f\x4a\ -\xe8\x7b\x82\xa0\x39\x2d\x1f\x3f\xf6\x52\x4b\x92\x40\xf6\x16\x89\ -\x68\x17\x89\x24\x28\x2c\x9b\xc9\xd8\xc5\xaa\x56\x51\x34\x15\x7c\ -\x8f\x66\xa3\x82\xa9\xc9\x84\xde\x90\x46\xc9\xe4\xca\xf9\xd3\x90\ -\x78\xcc\x35\x1c\x16\xda\x15\xb2\x10\xdc\x41\x8f\x66\x59\xa7\x7b\ -\x34\xe6\x74\x67\x96\xde\xce\x73\xce\x2d\x57\xc8\x7c\xf8\xca\xe7\ -\x2e\xd0\xb0\x74\xa4\x38\x80\x51\x8f\x66\xb5\x4c\xa5\xec\x70\x74\ -\x74\x44\x9c\x26\xd4\x5a\x2d\x0a\x45\xa5\x56\x6f\x1e\xb7\x31\xfe\ -\x23\x72\xe0\xfe\xe6\xc6\x6f\x65\x92\xc2\x8d\xd7\x5f\xe7\xad\x1f\ -\xfe\x88\x72\xb5\xca\xea\xea\x2a\x73\xed\x32\xb9\xa4\x60\xda\x16\ -\x4f\x9e\x3d\xe3\xd2\xb5\xf3\x94\x24\xe8\xc7\x19\xfe\x64\x42\x38\ -\x1a\xf1\x95\x2f\xfc\x14\xa3\x91\x4b\xab\x59\xa1\xc8\x21\xf0\x23\ -\xc6\x23\x9f\x34\x49\x38\xbb\xba\x8a\xe7\x79\x1c\x76\xfb\xcc\xcd\ -\xcf\x23\x69\x32\xdb\xdb\x7b\xf8\xbe\xcf\xf9\xf3\x2b\x74\xfb\x63\ -\x9a\x35\x83\x91\x1b\x9c\x34\xb8\x3f\x79\xf2\x84\xc5\xc5\x45\xea\ -\xf5\x0a\xaa\xaa\x33\x1e\xfb\x24\x09\x38\x8e\x03\x88\x16\xc3\x76\ -\xbb\xcd\xec\x6c\x03\x90\xa7\xd1\x45\x61\x38\xc9\xf3\x9c\xc1\x60\ -\x40\xa5\x52\x61\x65\xa5\xc3\x68\xe4\x4f\xe1\xe1\x0a\xbe\x2f\x12\ -\x30\x07\x07\x07\x64\x59\xc6\xd2\xd2\x2c\x41\x90\x90\xa4\xe2\x17\ -\xd5\x99\xad\x70\x6a\xbe\x8d\x17\xa6\x8c\x46\x23\xf6\xf7\xf7\x4f\ -\x8a\xb9\x66\x1b\x16\x9a\x06\xdd\xde\x98\xfd\xfd\x7d\x51\x9d\x39\ -\x1d\x67\x65\xd9\x71\xda\x45\x66\x6f\x6f\x8f\x56\xab\x85\x69\x9a\ -\x58\x96\x46\x1c\xa7\x14\x53\xb2\x68\x18\x86\xdc\xbe\x7d\x9b\x2b\ -\x57\x2e\xe3\x79\x3e\x4e\x59\x67\xe2\x89\x13\x9b\x65\xc9\x8c\x47\ -\x21\xd5\x5a\x95\xf3\xe7\xcf\x32\x37\x3b\xcb\xc2\x7c\x87\x7e\xbf\ -\xcf\xee\xce\x36\x47\xdd\x23\x76\x77\x76\xb1\x9c\x32\x9f\x3e\x78\ -\xc0\xc6\xf3\x3d\xfc\x34\xa4\x37\x19\x70\x34\xec\xd2\x1f\x0e\x19\ -\x8f\x5d\xc8\x25\x74\xdd\x24\x8a\x73\xec\xb2\xca\xfa\x66\x8f\xc3\ -\xc1\x88\x38\x2b\x48\x81\x38\x89\x50\x34\x99\x3c\x8b\x49\x5c\x0f\ -\xcf\x3d\x26\x4b\x2a\x24\x07\x3b\x24\xc1\x18\x85\x1c\x35\x8c\xe8\ -\xed\x6c\x42\x1c\x92\x26\x21\x8a\x5c\xe0\xbb\x23\xae\xbf\x70\x8d\ -\x33\x0b\x8b\xbc\x79\x73\x8d\x17\xae\xdd\xe4\xd3\xcd\x67\xcc\x2e\ -\x2d\xe2\xf5\x07\x64\x41\x04\x51\x82\x8c\x8c\xeb\x09\xef\x01\x86\ -\x8e\x5e\x2a\x91\xa6\xe2\x12\xa7\x22\x93\x4f\x41\x7b\x79\x92\xe0\ -\xd4\x2a\x68\xa6\x86\x1f\xb8\xf4\x87\x03\xbc\x54\x25\xc2\xe4\xf6\ -\xa3\x47\xfc\xe8\xe3\xdb\x3c\x7a\xbe\xcf\xd6\xd1\x80\xb1\x17\x83\ -\x66\xe3\xf6\x27\x20\x1b\xa2\x69\x50\x37\xd1\x35\x4d\x40\xf2\x24\ -\x19\xd5\xd0\x09\xbc\x00\x45\xd7\x28\x44\xff\x29\xb5\x66\x83\x70\ -\x30\xc0\x98\x9a\x33\x34\x55\xc5\xa9\x54\x08\x07\x43\xd0\x44\x57\ -\xb1\x18\x76\x0b\x67\x60\x14\x45\x20\xcb\x14\x61\x40\xa1\x6b\x27\ -\x9d\xc8\x45\x26\xea\x69\x44\x84\x1e\xaa\x00\x00\x20\x00\x49\x44\ -\x41\x54\xd2\x44\xa4\xdb\xb2\x28\xa2\x08\x42\x8a\x4c\xa2\xb4\x38\ -\x8f\x56\x29\xd1\xdd\xd9\xa4\x73\x66\x09\x77\xeb\x09\x92\xa9\x21\ -\xa5\x21\xc1\xa8\xcb\x97\x3f\xf7\x2a\x2f\x9c\x3b\xc5\xda\xca\x1c\ -\xf5\x92\xc1\xdd\xdb\x1f\x32\x3b\xd3\xc4\x29\x9b\x84\x69\x0e\x85\ -\xc4\xb0\xdf\xa7\xdf\xeb\x72\xe6\xf4\x59\x6a\x36\x0c\x3d\x30\x4c\ -\x9b\xc3\xa3\x03\xfa\xc3\x3e\xf5\x46\x9d\xc8\x9b\xd0\x28\xd9\x3c\ -\x7d\xf8\x88\xbf\xf1\xf3\x5f\x42\x8e\x0a\xd2\xfe\x11\x35\xdb\x44\ -\x3e\x56\xef\x74\x45\xc7\x1d\x4d\x30\x0d\x83\xdb\x77\xef\x90\x15\ -\x39\x43\x77\x8c\x17\x83\x66\x28\xec\xed\xed\x31\xbf\x30\x47\xef\ -\x68\xc0\xde\x28\xe4\xc5\x2b\x97\xb9\xb8\x76\x8e\x24\x8c\x38\xb5\ -\xbc\x30\xad\xc1\x80\x51\x7f\xc2\xec\x4c\x8d\xf5\x47\x8f\x38\x73\ -\xe6\x0c\xba\xae\xd0\xee\xcc\x72\x78\x78\x88\x61\xa8\x74\xbb\x63\ -\xbc\x30\x60\xed\xe2\x05\xba\x43\xb1\xc8\x26\x01\x53\x43\x87\x21\ -\x48\x0e\x41\x40\xbd\x5e\x67\x73\x73\x07\xd3\x94\x4e\x0a\xc7\x1b\ -\xb6\xc4\x78\x3c\x66\x34\x1a\xb1\xb4\x24\x16\xa9\x61\x88\xa7\xe1\ -\xc5\x55\x91\x6b\xde\xdc\xdc\x64\x7d\x7d\x9d\x85\x85\x36\xa3\x51\ -\x78\x62\x42\x09\xc3\xcf\x4c\x26\xcf\x9f\x3f\x67\x6d\x6d\x8d\xe1\ -\x30\xc4\x71\x4c\x54\x55\xa5\x51\x33\x70\x27\x19\x8f\x36\x0e\xd8\ -\xd8\xd8\xe0\xfa\xf5\xeb\xbc\xf9\xe6\xab\x44\x51\xc4\xf6\xf6\x36\ -\x77\x1e\x6c\xf2\x7c\x77\xc0\x78\x3c\x66\x69\x69\x89\xe6\xf1\xee\ -\x7d\xdc\x9d\x35\xad\x11\x71\x5d\x97\x72\xb9\x3c\x35\xd2\x73\x72\ -\x32\x30\x0c\x71\x17\x33\x0c\x03\x6b\x8a\xcf\x4d\x12\x11\x6f\x3d\ -\x2e\x60\x70\x5d\x97\xd9\xd9\x19\xd4\xe9\x68\x49\x51\x34\x4e\x9f\ -\x3e\xcd\x2b\xaf\xbd\xc1\x8b\x2f\xdf\xc4\x6e\xb4\x98\x3d\x7d\x86\ -\xcb\xaf\xbc\xc6\xb9\xeb\x2f\xa1\x35\x67\xf0\x4d\x93\xc8\x2a\xb1\ -\xef\x05\x84\x92\xca\xd6\xe1\x11\x8f\x9e\x6e\x70\xfb\xd3\x87\xfc\ -\xe0\xdd\x07\x3c\xdd\xd8\xe0\xc9\xc6\x33\xfa\x7b\xdb\x04\xfd\x2e\ -\x4c\xc6\xa4\x61\x20\x48\x18\x81\x87\x14\x4f\x20\x8f\x70\xe4\x1c\ -\xab\x5e\xa2\x64\x1b\x30\x19\xd2\xb2\x34\x3e\x7f\xfd\x45\x6e\x5c\ -\xba\x88\xdf\xed\xb2\xd0\x6a\xa2\x49\xf0\xe4\xd1\x63\x61\x87\x35\ -\x60\x76\x56\xe5\xa5\x2b\x17\xf9\x6b\x37\x5e\x60\xa1\x51\xa6\x2c\ -\x15\xcc\x94\x2c\xe6\xeb\x15\x3a\x95\x32\xb6\x65\x42\x9a\x60\x28\ -\x32\xa4\xe2\x28\xaf\x6b\x2a\xba\xac\x60\xc8\x32\x4c\x5c\x7a\x07\ -\xbb\x24\x69\xc8\x70\xe2\xf2\xe1\xbd\x3b\x7c\xf4\xe0\x1e\x8f\x0e\ -\xf6\x39\x08\x42\xee\x6e\xed\x70\xe7\xd9\x26\x03\x2f\x22\x55\x0c\ -\xe2\x48\xb0\xaf\x4d\xd5\x44\x29\x55\xa1\x00\x4d\x33\x98\x78\x3e\ -\xaa\x6e\x12\xf8\x11\x86\x6d\x93\xf9\x01\x8a\x61\x88\xee\x62\x59\ -\x16\x99\xe1\x22\x27\x0a\x43\x8a\x34\xc3\x30\x4c\x90\x14\x62\xd7\ -\x03\x45\x11\xcd\x91\xa6\x49\x98\xc4\x82\x62\xa2\x28\x53\xc6\x70\ -\xf1\x57\x20\x00\x52\x51\x10\x87\x21\x32\x53\x36\x77\x96\xa1\xcf\ -\x36\x18\x4c\xfa\x78\xd1\x84\xf2\xfc\x0c\xbb\x5b\x1b\xcc\x9c\x3f\ -\x87\xbb\xbd\x81\x92\x44\xbc\x76\xf5\x0a\x2f\x9c\x5f\x43\xca\x53\ -\x2c\x03\x66\x6a\x16\xb2\x5a\x30\xf0\x87\x60\x28\xb8\xbe\x87\xae\ -\x69\x0c\x07\x03\x4e\x2f\x2e\x52\x84\x21\x5b\x1b\x47\x2c\x54\xe1\ -\x8b\xaf\x5d\xe1\xb5\x6b\x97\xd0\xc8\xd0\xf3\x04\x43\x91\x38\x3a\ -\xdc\xa7\xd9\x6c\xf2\x6f\xff\xcd\x9f\x52\xa9\xc9\x9f\x71\xe0\xfe\ -\xbb\xdf\xf8\x4d\x54\x45\x62\x3c\x89\x7f\x6b\xef\xa8\xc7\xf6\xde\ -\x21\xd6\x54\x2c\x90\x65\x89\x6a\xa5\x02\x79\xc1\xa7\xb7\x6f\x73\ -\xfd\xc5\x17\x79\xf4\xe8\x11\xed\xce\x2c\x8d\xaa\xc9\xfe\xce\x01\ -\xb1\xef\x71\xed\xd2\x35\x7c\xcf\xc7\x32\x4c\x64\x59\x22\xf0\x45\ -\x39\x74\xb3\xd9\x44\xd5\x14\x91\xac\x6a\xb7\x79\xf4\xe4\x09\x8a\ -\x26\x4a\xab\x0d\xd3\xc0\x30\x0c\x1c\xdb\x9e\x82\xe8\x1d\x1c\x13\ -\xde\x7d\xef\x23\x5e\x7a\xe9\x25\xf6\xf7\xf7\x05\x68\x3c\x97\x98\ -\x6b\x97\xd1\x0c\x1b\x2f\xca\xd9\xde\xde\xa6\xdd\x6e\x53\xaf\x97\ -\x19\x8f\x3d\x9a\x15\x93\x89\x9f\xe0\xfa\xe2\xe7\x75\x3a\x1d\x1e\ -\x3e\x7c\xc8\xde\xde\x21\x33\x33\x33\x54\xab\x16\x59\x26\x16\x8e\ -\x6d\xeb\xec\xee\x1e\x31\x18\x0c\xb8\x7c\xf1\x14\x41\x98\x62\xdb\ -\x2a\xfd\xfe\x88\x30\xca\x31\x4d\x03\xcf\xf3\xe9\x74\x3a\x9c\x9e\ -\xab\xb1\xb5\xdb\xa3\x5e\xaf\x9f\x38\xd3\xc2\x30\x64\x73\x73\x93\ -\x46\xa3\x71\x52\x3c\x9e\xa6\xe9\xb4\xd6\x53\x25\x8e\xc5\x42\x9e\ -\x9f\x9f\x23\x8e\x13\x40\x3d\x21\x42\xe4\xb9\xc4\x68\x34\x12\x03\ -\xfe\x6a\x1d\x49\x92\xa7\x0a\xb9\x84\x3b\x89\x49\x62\x78\xf6\x6c\ -\x9d\xb3\x67\x96\x91\x25\x31\xee\x51\x34\x15\x59\x51\x88\xf2\x02\ -\x3f\xcd\xd9\xee\xf5\x39\x75\xe1\x34\x85\xa9\x52\x98\x2a\xb1\xe9\ -\x10\x9b\x25\x4a\x33\x33\xf4\xdd\x84\xb5\xab\xd7\x59\x38\xb5\x44\ -\xa5\xd3\x66\x66\xa5\x43\x6a\xb5\xf8\xe0\xd1\x3a\x87\xbe\x0f\x95\ -\x2a\xf6\x4c\x0b\xcd\xb1\xb0\x0d\x0d\x53\x92\xb0\x75\x9d\x0a\x12\ -\x86\x5c\xa0\xca\x29\x45\x32\xa1\xac\xc2\x99\x4e\x9b\x5f\xfa\xe6\ -\xcf\xf2\xb7\x7e\xf6\x15\x2e\x5c\x78\x91\xf5\x47\x0f\xd9\xdd\x3f\ -\x40\x92\x55\x0e\xbb\x3d\x1e\x3c\x7c\x0c\x6a\x9d\xc5\xa5\x0a\x71\ -\x98\xf3\xb3\xaf\xae\x71\xf5\xf2\x4b\x34\x2c\x87\x68\x3c\x61\xdc\ -\xef\x93\x26\x09\xba\xa9\xe1\x1e\xec\xa3\x56\x6c\x72\x40\x53\x15\ -\xd4\x22\x23\xf5\x7d\xb4\x3c\x23\x0e\x7d\x66\x1a\x15\x4c\x45\x46\ -\x57\x24\x5e\x7a\xe1\x0a\x2f\xde\x78\x09\x45\xd7\xf9\xe0\xee\x1d\ -\x1e\xde\xba\x8b\x27\x6b\xa4\xb2\x26\x42\x10\xc8\x94\xcb\x55\x54\ -\x59\x46\x53\x25\xa2\xc3\x43\x2a\xb3\x6d\x82\x30\x44\x9b\x42\xef\ -\x54\x55\x16\x56\x63\x55\x21\x0b\x43\x02\xdf\xc3\x72\x6c\x91\xf1\ -\xf5\x7c\x12\xd7\xc5\x0f\x23\xa1\x58\x67\x19\x98\x3a\x9a\xae\x63\ -\x98\x26\xee\x78\x8c\xa2\x0b\x90\xbd\xaa\xeb\xe4\xbe\x0f\x8a\x84\ -\xa6\xa9\x64\x69\x26\x0c\x23\x9e\x8f\xa2\x6a\x14\x79\x46\xa1\x2a\ -\x94\x1b\x35\xc2\x51\x8f\x22\x9c\xa0\x92\x51\x92\x0b\x66\x4a\x06\ -\xee\x51\x97\x37\x5f\x78\x81\xeb\x17\xcf\x71\x6e\x61\x9e\xb3\xf3\ -\x75\xfc\xe1\x84\x24\x49\x99\x9d\x9d\xe1\xe9\xd6\x06\xb3\x9d\x39\ -\xfe\x7f\xaa\xde\x2c\xc6\xae\x3b\xcf\xef\xfb\x9c\x7d\xbb\xfb\x5a\ -\xfb\x5e\x24\xab\xb8\x89\xa2\xa8\x16\xb5\x77\x6b\xeb\x99\x1e\xcf\ -\xd8\x93\x19\x7b\x36\x64\x0c\x67\x82\x20\x4f\xc9\x4b\x80\x00\x36\ -\x26\xea\x38\x0f\x09\x9c\xc5\x06\xf2\x60\x24\x41\x9c\x78\x9c\xf1\ -\x64\xa6\xed\x1e\xcf\xa6\xe9\x45\x5b\x77\x4b\xa2\x24\x4a\x24\x45\ -\x91\x2c\xb2\x8a\xac\x62\xb1\xf6\x7b\xeb\xee\xe7\x9e\xfd\x9c\x3c\ -\x9c\xab\x02\xf2\x4a\xa0\x88\xaa\x42\x9d\x7b\xfe\xff\xdf\xef\xfb\ -\xfd\x7c\x24\x29\xa5\xd9\x9c\x5a\x58\x64\x76\x66\x8a\x2f\x3f\xff\ -\x8c\xa5\xa5\x05\x44\x59\xc2\xd2\xe0\xa8\xd5\x47\x51\x65\xf6\x76\ -\x77\x31\x74\x05\x21\x8c\x98\x9f\x9e\xe1\xe3\x0f\x3f\xe4\xcd\x97\ -\x5f\x63\xe3\x8b\x4f\x29\x65\x4c\x64\x43\x16\x89\x00\xa7\x67\x93\ -\x31\x4c\x1a\xbd\x3e\x95\x52\x19\xc7\x0f\x18\x3a\x0e\xb5\x52\x86\ -\x46\xa3\x8d\x95\x31\x30\x75\x95\x4e\xb3\xc9\x44\x46\xe5\xc8\x8e\ -\x31\x65\x99\xe7\x2e\x5f\x21\x97\x53\x98\x9a\x98\xe0\xfe\xfd\xfb\ -\xbc\xf4\xc2\xd3\x7c\xf0\xc1\x35\x9e\xba\x70\x61\xc4\xbd\x4a\xd7\ -\x39\xd5\xb1\x1c\xcd\x76\x86\xf5\x87\x1b\x8c\x4d\x4c\x20\x48\x12\ -\xaa\xae\x40\xc4\x88\x90\x11\x93\x24\xe2\xe8\x6d\x9c\x3d\x21\x61\ -\x1e\x1d\x1d\xd1\xeb\xf5\x58\x5a\x9a\xa5\xd3\xe9\xd3\x6a\xb5\x58\ -\x5a\x5a\xc2\xf3\x12\xca\xe5\x02\xdb\xfb\x1d\xaa\xd5\x42\x9a\x78\ -\x19\xf8\xdc\xba\x75\x8b\xd7\x5e\x7b\x8d\x30\x0c\xd9\xdc\xdc\xc4\ -\x71\xea\xf8\xbe\x4f\xb9\x5c\x26\x9f\x49\x9b\x4a\x4b\x4b\x4b\x0c\ -\x86\xe9\x7e\xf9\x1b\xd0\x9f\xe3\x38\xc4\x71\xc2\xfa\xfa\x3a\xe7\ -\xce\x9d\xc3\x25\xfd\xbe\x32\x19\x8d\x7c\x7e\x9c\x7a\xbd\x4e\xb3\ -\xd9\xe4\xe1\xc3\x87\x1c\x1d\x1d\xd1\xed\x76\x29\x16\x8b\x27\xf6\ -\x3d\xd3\x34\xe9\x76\xbb\xa3\x87\x9c\x13\xc4\xcb\x37\x7e\x5f\xc7\ -\x71\x46\x41\x94\x29\xba\xdd\x3e\xa6\x69\xe2\x47\x11\xe5\xa2\x44\ -\xcf\xd6\x90\x44\x50\xa4\x18\x43\x97\x70\xdd\xb4\xd0\x1e\x44\x21\ -\x99\x82\x49\xe3\xb0\x43\x20\x6a\x28\x85\x0a\x37\x36\x9b\x7c\xf4\ -\xd9\x75\x22\x49\x62\xe9\xcc\x0a\x46\x3e\x4b\x3e\xcc\xf1\xb0\xe3\ -\x50\x4d\xc0\x17\xa0\x37\x00\x25\x0b\xdb\x7d\x9b\x86\xe7\xe3\x2b\ -\x2a\xb1\x9a\x96\x34\xa2\x30\xc0\xeb\x0f\xd1\x85\x84\x85\xfa\x04\ -\xce\x61\x83\x24\x09\x89\xe5\x98\x6c\xbe\xc0\xd3\x97\xce\x73\x79\ -\xf5\x2c\x97\xa7\xb2\xd8\x21\x54\x0c\x91\xa9\x5a\x0d\x0c\x9d\xe6\ -\xd0\xc6\x0d\x23\x0e\x3b\x3d\x7e\xf8\xce\x8f\x39\x77\xee\x1f\x21\ -\x85\x1e\xbd\x41\xcc\x54\x51\x64\xfa\xd5\xb3\xfc\xdd\xd7\xce\xb2\ -\x7d\x00\xbf\xb8\x79\x97\x77\x3f\xff\x0c\x08\x91\xa2\x00\x53\xd7\ -\x70\x5d\x07\x7b\x38\x44\x8b\x05\xea\xd5\x1a\xe7\x17\xe6\x98\xae\ -\x55\x98\x99\x9d\xe4\xb0\x79\xc8\xd0\xb5\xf9\xe0\xfd\xf7\x69\xb4\ -\x3b\x3c\xde\xd9\x05\xd3\x40\xb0\x2c\x90\x75\x62\x59\xc2\x0b\x3c\ -\x54\x19\x7c\xd7\xc1\xd0\x34\x10\x22\xda\xed\xe3\xd1\x89\xcb\x25\ -\x93\xc9\xd0\x1f\x74\xc9\x8e\xd0\xb3\x92\x65\x11\xf5\xfb\x28\xb9\ -\x3c\xce\xc0\x4e\x03\x2d\x82\x48\x12\xc7\x18\x56\x16\xa7\xdd\x82\ -\x51\x94\x56\xd7\x75\x48\x52\x08\xdf\x37\xd2\x84\x54\x3d\x39\x5a\ -\x4b\xc5\x31\x61\x94\x7e\xbd\x10\x27\x68\x8a\x0a\xa2\x40\x67\x6f\ -\x0b\x45\x57\x79\xee\xca\x33\xdc\xbf\x75\x13\xc9\x73\xe9\x6f\x1d\ -\xf3\xbb\xdf\xfd\x25\x2a\x19\x9d\x71\x3d\xcb\x64\xc6\x20\x03\xe8\ -\x56\x86\xc0\x71\x09\xe3\x90\x28\x4e\x18\x78\x1e\xad\x66\x1f\x51\ -\x94\x29\x95\x0a\x48\x62\xea\xfb\xaa\xe6\x54\x36\x76\x9b\x84\x9a\ -\x46\x2d\x6f\xf1\xfb\xbf\xf5\x9b\xfc\xe3\xff\xf6\x9f\x12\xd8\x36\ -\x86\x22\xe3\x0c\xfa\xd4\xeb\xe3\x1c\x1c\x35\xe9\x76\xfb\xb8\xae\ -\x8b\x3c\x02\x3b\x10\xfb\x11\x89\x1f\x53\xab\xd4\xb9\xf3\x70\x83\ -\x62\xb5\x82\xa6\xaa\x0c\xdd\x84\x83\xbd\x7d\xa6\x27\x26\xd3\x58\ -\x99\x65\xb1\xbd\xd7\xa2\xd5\xed\x52\x29\x14\x59\x98\x99\x23\xf4\ -\xc1\xd0\x74\x42\x3f\xe0\x60\xaf\x85\x3a\xca\xa9\x6a\x9a\x4c\x18\ -\x82\x61\x18\x1c\x1f\x0f\x99\x9c\x9c\x64\xed\xc1\xbd\x91\x1e\x43\ -\x67\x38\xf4\x48\xc2\x84\x62\x51\xa7\xd5\x72\xd8\xd9\x69\xb0\xba\ -\xba\x4a\xbf\xef\x30\x39\x51\x24\x4e\xc0\x71\xb2\x3c\x7a\xf4\xe8\ -\xc4\x00\x50\xa9\x54\x08\xc3\x34\xaf\x9c\x31\x95\x13\xb4\x4f\xbb\ -\x3d\x60\x38\x1c\x9e\x4c\x8b\x8f\x8e\x1a\x3c\xfb\xec\x79\x6e\xdf\ -\xde\x38\x21\x34\xb8\xae\x85\xa2\x28\x54\xab\x15\xc2\x30\x1a\xc5\ -\x2e\x15\x4c\x53\x26\x8a\x54\x1a\x8d\xc6\xc9\xdd\xb7\xdb\x4d\x73\ -\xd3\x61\x08\xb6\xed\x9f\x54\x1e\xcf\x9f\x3f\x4f\xa9\x94\x4a\xdf\ -\x6c\xdb\x3e\x21\x3d\xd8\xb6\xcd\xc3\x87\x0f\x59\x59\x59\xc1\xb6\ -\x3d\x0c\x43\x23\x8a\x12\x4c\x53\x26\x49\x64\xe2\x58\x63\x38\x1c\ -\x8e\xb0\x45\xa9\x9c\xdb\xd4\x24\x3a\x03\x0f\xcf\xf3\x30\x74\x15\ -\x3f\x18\x12\x04\x01\xb2\x2c\x22\xcb\x3a\x7e\x9c\x30\x70\x13\x0a\ -\xd5\x22\x81\x08\x8d\x0d\x97\x2f\xbf\xfc\x9a\xcf\xbe\xbe\x83\x97\ -\x40\x7e\xe3\x09\x5d\x3b\x9d\x2d\xb4\xf7\x0f\xf8\xec\xde\x63\x4a\ -\xd9\x3c\x6e\xe0\x53\xa8\xd6\x79\xd2\x6a\xf2\xb8\x6f\x8f\x98\xce\ -\x09\x81\x08\x96\x61\x20\x0a\xb0\x34\x31\xc1\xdf\xfb\xce\x6b\x4c\ -\x64\x0d\x3e\x7c\xf7\xc7\x6c\x1e\xec\x70\xea\xcc\x32\xcf\x5e\x3a\ -\x4f\x2d\x6b\xa1\x03\xed\x4e\x4c\x84\xc8\xb9\x33\x2b\x9c\xaf\x94\ -\xf8\xd3\xbf\x7e\x87\xa3\x76\x8f\xda\xd8\x24\xbb\xbb\x4d\xee\x3e\ -\x68\x90\x37\x55\x7a\x87\x3b\xcc\x65\x66\xf0\x12\x88\x86\x60\x49\ -\xf0\xfa\x8b\xab\x5c\x7c\x76\x95\xff\xf2\xed\xff\x1e\x31\xf4\x91\ -\x12\x05\x27\xf0\x50\x45\x18\x2b\x97\x39\x35\x37\xc3\x95\xd5\xb3\ -\x9c\x1a\xcf\x12\x78\xf0\xe9\x8f\x7e\xc4\xd7\x8f\xd6\x68\x1d\x1f\ -\x53\x3b\x73\x8a\x6c\xbe\x88\x1d\xc5\x24\xb2\x44\xa2\x6a\xf4\x43\ -\x0f\x41\x15\xe8\xb8\x7d\x48\x42\x54\x55\x81\x52\x86\xb0\xdf\xa3\ -\x38\xb7\x30\xea\x82\x7b\xc4\x7e\x80\x92\x95\x88\x46\xdd\xe0\x48\ -\x96\x19\xda\x03\x42\xdb\x41\xd0\x34\xcc\x5c\x71\x34\x80\x94\x70\ -\x14\x25\x2d\x4b\x44\x21\x43\xcf\x41\x36\x8d\xb4\xa3\x2e\xa4\x46\ -\x07\xb2\x59\x08\x3c\x7c\xc7\x41\x94\x24\x92\x38\xc6\xca\x98\x08\ -\x09\x28\xa2\x4a\x1c\x05\xb8\xae\x43\x4e\x13\x79\xed\xf2\x25\xde\ -\x3a\xbf\xca\xff\xfe\x2f\xfe\x39\x6f\x5c\x7d\x9e\xbf\xf3\xc2\xf3\ -\x3c\x59\x5f\xa7\x2c\x29\x14\x80\xa3\x47\x6d\x6a\xf5\x22\xb5\x9c\ -\xce\x5e\x3b\x61\x7a\x6a\x9e\xb5\x7b\x1b\x0c\xfa\x0e\x2f\x5c\x7d\ -\x16\xdb\x76\xb0\x7b\x6d\xde\x78\xed\x55\x7e\xf4\xb7\x3f\xe1\xe5\ -\x37\xde\xe0\x83\xcf\xae\x33\x77\xea\x0c\xe5\x92\xcc\xcb\x57\xbf\ -\xc5\xa3\xc7\x3b\x7c\xfc\x8b\x4f\xf9\x8d\x5f\xfb\x7b\xfc\xcd\x9f\ -\xff\x05\xaa\xaa\x32\x33\x33\x83\x65\x59\x48\x6f\xff\xe1\xdb\x88\ -\x12\x94\x2a\x63\x7f\xb4\xb9\xbb\xf3\x5f\xc8\xba\x81\x91\xcd\xd3\ -\xe9\xdb\x9c\x5a\x3d\xc7\xd6\xd6\x0e\x47\xcd\x0e\x17\x2e\x9c\xa3\ -\x60\x29\x64\xb2\x65\xee\xde\xfe\x0a\x45\x14\x58\x5e\x9c\x47\x51\ -\x55\x3e\xbe\x76\x8d\x42\xb1\xc4\xe4\xe4\x38\x3f\xfe\xe9\x4f\xb9\ -\x7a\xf5\x2a\x92\x2c\x13\x84\x11\xae\xef\x63\x65\x35\x92\x44\x60\ -\xeb\xf1\x63\xa6\xa7\xa7\x88\x47\x05\x6e\x49\x92\x20\x01\x49\x52\ -\x80\xb4\x4f\xbc\xb4\xb4\x44\x26\xa3\xb1\xbb\xdb\x1c\x4d\x86\x45\ -\x4e\x9f\x9e\xe5\xee\xdd\x07\x1c\x1e\x1e\xf2\xc2\xd5\xa7\x70\xdc\ -\x30\x2d\x7b\x0b\x2a\xaa\x9a\xd6\x18\x2d\x4b\xe5\xee\xdd\x35\x72\ -\xb9\x1c\xe3\xb5\x2c\xaa\x66\xd1\x6a\xf5\xa9\x8e\x02\x29\x7b\x7b\ -\x7b\x6c\x6d\xa5\x1e\x66\x49\x92\xa8\x14\x34\x8e\xdb\x03\x4c\xd3\ -\x24\x49\x52\x3b\xdf\xdd\xbb\x77\xb9\x78\xf1\x22\xba\x9e\x9a\x28\ -\x52\x27\x6f\x3a\xfd\xd4\xf5\x34\x00\x53\xaf\xd6\xd0\x4c\x83\x6c\ -\x2e\x83\x6e\x9a\xa9\x8c\x2c\x49\xe8\x74\x3a\xdc\xb9\x73\x87\xa9\ -\xa9\x29\x86\xc3\x21\xa6\x69\xe1\xfb\x3e\xae\x1b\x90\x24\x22\xb2\ -\x2c\x72\xe7\xce\x3d\xe6\xe7\xe7\x91\x65\x29\xed\xa5\x6a\x32\x81\ -\xe7\xa1\xca\x22\x19\xd3\xe4\xd1\xa3\x87\xd4\xea\x63\x69\x0a\x49\ -\x96\x18\x7a\x1e\x66\x46\xa5\xd9\xf3\x68\xda\x11\xfb\x9d\x2e\x4d\ -\xc7\xa3\xe9\x78\x0c\x62\x01\x5f\xd1\x70\x45\x99\x9e\x17\xe1\x07\ -\x31\x4e\x9c\xb0\xd7\x6c\xf3\x68\xef\x80\x9d\x76\x87\xad\xc6\x31\ -\x58\x16\xa1\x28\xa4\x7b\x50\x31\x41\x89\x22\x04\xdf\x65\xb1\x3e\ -\xce\xaf\x7e\x67\x15\x33\x11\x19\x2b\xe4\x78\xe6\xd2\x79\x9e\x7b\ -\x7a\x85\x79\x4b\x45\x04\xba\xcd\x21\x7f\xfb\x97\x7f\x49\xb3\xd1\ -\xa0\x50\x2a\x71\xea\xcc\x12\xba\x91\xc1\xb6\x3d\xda\xad\x0e\x9a\ -\xa2\x71\xe7\xd6\x0d\x8e\xb6\x37\xf9\xec\x93\x4f\xc8\x14\xc7\x91\ -\xf5\x22\xa5\xbc\x00\x5a\x7a\xe7\xb7\x87\xf0\xe3\x9f\xfe\x94\x30\ -\xf0\xd1\x0d\x15\x45\x16\x18\x2b\x16\x59\x9c\x9e\x62\xaa\x54\xe1\ -\xf4\xd4\x04\x3f\xfb\x9b\x9f\x22\x04\x1e\xbd\x41\x97\xf9\xc5\x05\ -\x7c\x51\x42\xd0\x34\x7a\xbe\x4f\xae\x5c\xc5\x39\x6a\x10\x9b\x06\ -\x24\x31\xe5\x72\x19\xdf\x1b\xa0\x49\x02\x0a\x09\x52\x94\xee\xab\ -\x4f\xcf\xcd\x31\x5e\xab\xb2\xbb\xb3\x83\x28\xcb\x84\x51\x88\xa8\ -\x28\x38\xb6\x0d\x83\x61\x3a\x74\x53\x54\x74\xc3\x48\x7d\xc9\x51\ -\x88\x17\x45\x28\x96\x41\x14\x47\x69\x72\x2d\xf2\xc9\xe4\xb2\x38\ -\xce\x10\x41\x88\x11\xe2\x88\x7a\xa9\x88\xdd\xeb\x80\x6b\xa3\x89\ -\x02\x72\x1c\x51\xca\x65\x20\x0a\x50\x64\x91\x24\x18\xa2\x85\x2e\ -\x17\x17\xe7\xb9\x7a\xe9\x1c\x96\x28\xf3\xeb\xdf\x7d\x85\xe7\x2f\ -\xcf\xb3\xf6\xe5\x03\xae\x3e\x7d\x8a\xfb\xb7\xd7\x98\x9f\x9a\x64\ -\x76\xcc\xe0\xf0\xb0\x4b\x90\x48\xa8\x86\x86\x28\xab\x6c\x6e\x6f\ -\x93\xcf\x17\x50\x65\x8d\xc9\x9a\x05\x48\x38\x43\x9b\x6e\xbf\x9f\ -\x06\x50\xe2\x84\x72\xa5\x8c\xa2\x29\xe4\xf3\x15\xda\xcd\x16\x76\ -\xbb\xcd\xd9\x53\x4b\x88\x81\xcf\x64\x21\xc7\xf9\xd9\x49\x72\xa6\ -\x82\xf4\xf6\x3f\xf9\x6f\x40\x12\x10\x55\xda\x1b\x5b\xdb\x6f\xf7\ -\x6c\x07\x2f\x12\x10\x94\x0c\xa7\xce\x2d\xf0\xc7\xff\xfe\x3d\xca\ -\x13\xb3\x94\xea\x15\x06\x3e\x08\x24\x88\x49\x40\xfb\xe0\x09\x67\ -\xcf\x9c\xc2\x8b\x62\xd6\x1f\x6f\xf1\xf0\xf1\x26\x73\x8b\x73\xb4\ -\x7b\x1d\x6c\x67\x48\x75\xac\x86\x61\xca\x78\x41\x84\xae\xc9\x38\ -\x8e\xcf\xda\xda\x1a\x4b\x8b\xcb\xcc\x4c\x55\xd8\x7e\xbc\x8f\xdd\ -\xb7\x29\x16\x8b\x68\x9a\xc4\xc6\xc6\x23\x8a\xc5\x22\xf9\x7c\x9e\ -\x27\x4f\xf6\x58\x98\x1f\xc3\x1e\x86\xa3\x41\xd7\x90\xa9\xa9\x29\ -\x1e\x3e\x7c\x48\xb7\x37\x64\x7c\x7c\x7c\xb4\xfa\x51\x70\x47\x84\ -\x05\xcf\x4b\x8d\xf1\x33\x33\x33\x34\x8f\xd3\xd5\x42\x26\xa3\x23\ -\xa4\x2d\x04\xaa\xd5\x2a\x0f\x1f\x3e\x3c\x19\x50\xc5\xa4\xbd\x62\ -\x59\x12\x89\xc2\x54\xb9\xb9\x3b\x12\xc4\x41\x7a\x9f\xad\x94\x0c\ -\x86\x7e\x84\x20\x89\xe8\x86\xc4\xc3\xcd\xc7\xcc\xce\xcd\xf1\xee\ -\xfb\xef\xa5\x1d\xd4\x30\x4c\x85\x71\xc5\x1c\xae\xeb\x33\x37\x37\ -\x37\xda\x81\x1f\xf2\xf8\xf1\x63\x3a\x9d\xce\x28\x53\x9d\xb0\xb7\ -\x77\x30\x82\xdb\xd7\x46\x06\x12\x99\x7e\x6f\x80\x22\x8a\xe8\xaa\ -\x4e\x18\xc6\x1c\xb5\x8e\x29\xd7\xea\xc4\x62\x82\xa0\xc8\x44\x71\ -\x84\xae\x2a\x0c\xc3\x90\x07\x1b\x8f\x58\x5a\x5d\x61\x73\xaf\xc1\ -\xdd\xc7\x4f\x88\x94\x0c\xa2\x95\xa3\x1f\xb8\x24\x42\x02\x61\x82\ -\x92\x2b\x30\x0c\x12\x04\xcd\x24\x14\x65\x42\x49\x22\x51\x44\xa2\ -\xce\x31\xa8\x02\xa6\xa1\x81\xdd\x27\x2f\xc2\xe5\xd3\xa7\x99\x2d\ -\x4d\x30\x96\x11\xd8\x7e\xb0\xc9\xc5\xd3\xb3\x0c\x1a\x5d\x92\x30\ -\xa6\x64\x2a\x14\x0c\x85\x8d\xfb\xf7\x11\x08\x29\xe5\xf2\xcc\x4c\ -\xd6\x38\x35\x5f\x65\x65\xe9\x1c\x7e\x7f\xc8\xde\xe3\x6d\x2c\xcd\ -\x80\x44\xe1\xee\xc3\x1d\x1a\x61\xc4\x17\xeb\x1b\x6c\xb6\x5d\x24\ -\xb3\x8c\x88\x44\x46\x87\x6b\x1f\x7c\x82\x26\xa5\x85\x09\xcf\x19\ -\x10\x0c\x87\x54\xb2\x79\x4e\x4d\x4e\x53\xc9\x66\x58\x98\x1a\xa7\ -\x58\xca\x62\xe5\x73\x78\x24\x6c\x1e\x1e\x72\xec\x38\x48\x96\x45\ -\xd7\x71\x30\xc7\xc6\x09\x1a\x87\xa8\xd9\x1c\x5e\xb7\x4d\x5e\x96\ -\xc1\x1e\x22\x7b\x3e\x73\xa5\x02\xaf\x5f\xba\xc4\x2f\xbf\x7c\x95\ -\x9b\xd7\xaf\x13\xc5\x11\xb2\x66\xd0\xed\xdb\x04\x51\x92\x4e\xb7\ -\x7b\x7d\xc8\xe4\xa9\x57\x6b\x84\x61\x84\xe3\x7b\x08\xba\x4a\xa8\ -\x48\x88\x86\x42\x1c\x38\x20\xc4\x68\xa6\xc6\xb0\xd7\x21\x57\xcc\ -\xe0\xf6\x3b\x24\x83\x1e\xdf\xfd\xf6\xcb\x5c\x3d\xbb\xc2\x4c\xa9\ -\xc4\xa9\xf1\x3a\x6a\xe8\x33\xec\x35\x51\xe5\x90\xa1\xdb\x41\x8e\ -\x1c\x26\x0d\x83\xd5\xe9\x69\x8a\x99\x2c\x92\x90\x50\x2a\x6b\xdc\ -\xf8\x72\x9b\x4b\x97\x16\x70\x86\x20\xc4\x11\x81\xe7\x13\xa1\x20\ -\x4a\x02\x5a\x46\xc7\x8d\x23\x64\x4b\xe6\xe3\x4f\xbf\xe0\xec\xf2\ -\x32\xe5\x7c\xda\x1b\x50\x35\x95\x5c\x4e\xe7\xc1\xfd\x2d\x8e\x5b\ -\x1d\x2e\x5e\xba\x7c\x62\x2c\x91\xc2\x18\xbb\xd9\xa0\xf1\xf8\x31\ -\xdf\x3a\x7b\x96\x7a\xc6\xc2\x88\x7c\xea\x79\x1d\x4d\x12\x90\xde\ -\xfe\xfe\xdb\xe9\x51\x22\x81\xcf\x6e\xdc\x7a\xfb\xb5\xef\xbe\x49\ -\xa3\xe3\xd0\x76\x43\xbe\xbc\xf3\x98\x5f\x7c\xfa\x25\x67\x2e\x5c\ -\x62\x6a\xa6\x40\xc1\x82\x24\x96\xc9\x69\x32\x8d\x9d\x4d\x32\x19\ -\x03\x34\x83\xa9\xf9\x79\x1e\x6e\x6c\x50\xa9\x56\x51\x35\x8d\x30\ -\x0c\x90\x15\x19\xcf\x0b\xa8\x96\x33\xb4\x3a\x43\x1e\x6f\x6d\x31\ -\x37\x37\x87\x69\x18\xb8\x6e\xfa\x00\x24\xa3\x12\x83\xeb\xa6\xf9\ -\xd5\x5c\x2e\x47\xaf\xd7\xe3\xec\xc2\x38\x47\x6d\x17\x5d\x57\x89\ -\xe3\x84\x89\xa2\xce\x8f\xde\xfb\x19\x97\x2e\x5d\xa2\x50\x28\x70\ -\xe7\xce\x1d\xa6\xa7\xa7\x01\x01\xc3\x90\x09\x82\xe8\x84\x26\x52\ -\x2c\x16\x31\x0c\x03\x5d\x17\x71\xdd\x08\xdf\x0f\x18\x2f\x68\x6c\ -\xed\x1c\x62\x9a\x26\x8b\x8b\x8b\x78\x9e\xc7\xbd\x7b\xf7\x4e\x14\ -\x9a\x49\x18\xb1\xb1\xb1\x41\x26\x97\xa5\x5e\x4f\xef\xb8\xb2\xa2\ -\x61\x0f\x7d\xa2\xd1\xd1\xf9\xb0\x71\x4c\x92\x24\xcc\x4d\xd7\xc8\ -\x17\x2b\x4c\x4c\x8c\xa7\xbb\xe1\x28\x22\xf4\xd3\x68\x6b\xa1\x50\ -\x60\x72\xb2\x46\xb5\x3a\x46\xbd\x5e\xa7\x54\x2a\x9d\x40\x01\xf7\ -\xf6\xf6\x46\x5a\x1c\x0d\xdf\x0f\x51\x14\x95\x42\x4e\x25\xf2\x12\ -\xe2\x30\xa4\xd1\x38\x26\x42\xa0\x3a\x56\x4f\x0d\x04\x71\x42\x1c\ -\x47\xc4\x88\xd8\xb6\xc3\xd6\x93\x7d\xa6\x16\x26\xb9\xfb\x68\x8f\ -\xfb\xdb\xfb\x74\x9c\x20\xcd\x13\x7f\x63\x37\xf4\x42\x14\xdd\xc2\ -\xf7\x42\xe2\xf4\xb9\x26\x08\x03\x64\x45\x22\xf2\x5d\xac\x9c\x05\ -\x83\x3e\x79\x31\xc1\x88\x22\xe8\x76\xf9\xf6\xb3\x97\x31\x12\x48\ -\x9c\x01\x4e\xcf\xe6\xfc\x6c\x0d\xcf\x07\x59\x90\xd8\xdb\x6f\x90\ -\x2b\x96\x08\x92\xf4\x77\x51\x2a\x96\xb1\x34\x81\x8c\x0e\x17\xcf\ -\xce\xf1\xd4\xca\x39\x32\x86\x4e\xaf\x67\xb3\xd7\x3c\x26\xd4\x64\ -\x9a\x83\x1e\x11\x11\xfb\x7b\x3b\x48\x41\xc2\x85\x85\x32\xe3\xb5\ -\x79\x3e\xfc\xe0\x3d\x1a\xad\x26\x8a\xa6\x61\x19\x29\x7a\xe8\x5b\ -\x4f\x5d\x66\xa2\xa8\x70\xbc\xb7\x8f\x6b\xf7\x29\x95\x2b\x84\x09\ -\x48\x9a\xc1\xd1\x71\x8b\x44\x94\x70\x87\x2e\x44\x31\x71\xb7\x47\ -\x29\x5f\x40\x74\x1c\xaa\xba\x81\xe4\x0c\x99\xce\x17\x79\xe5\xd2\ -\x25\x5e\xff\xd6\x45\xdc\xde\x80\xe9\x99\x69\xde\xff\xf9\xcf\x39\ -\xee\xf7\x91\xb3\x19\xe2\x94\x20\x81\x68\xa4\x80\xfc\x20\x08\x40\ -\x10\x50\x4d\x03\xc9\xd0\x08\xc2\x80\x38\x8e\x60\x60\x43\xaf\x43\ -\xa2\x28\xe4\x0a\x39\x86\x9d\x2e\xc5\x5c\x16\x8d\x98\xac\x24\xf3\ -\x2b\xaf\x5c\x66\x2c\x53\xe4\x85\xa7\x97\xc0\x0b\xe8\x35\x0f\x38\ -\xbd\x3c\x4b\xbd\x9c\xe3\xec\xe2\x02\x2f\x9d\x7f\x8a\x73\x4b\xcb\ -\x04\x41\xc0\x9f\xfe\xd9\x0f\x88\x45\x8b\xb9\x85\x45\x06\xc3\x88\ -\x76\xa7\xcd\xf4\xcc\x38\xbb\x7b\xbb\xd4\x6b\x15\x26\x4b\x2a\x9b\ -\x7b\x0d\x24\x45\xe6\x8b\x9b\xb7\x79\xe3\x8d\x57\xb9\xf1\xe9\xe7\ -\x4c\x8e\xd7\xd1\x64\x05\xc7\x71\xe8\x75\x5d\x8a\xa5\x32\x7b\xfb\ -\xfb\x5c\x38\xbb\xc0\x71\xc7\x46\x91\x14\xca\x39\x95\x41\x77\x40\ -\xd9\xb2\xf8\xce\x0b\xcf\xe3\x76\x7a\x14\x0c\x8d\xb1\x72\x96\x38\ -\xf4\x90\xe3\x28\xc2\xf1\x03\x7c\x49\x5a\x28\x94\x8a\x0c\xdc\x90\ -\x56\xbf\x8b\xa8\x1a\xfc\xf5\x9f\xff\x25\x6d\xdb\xe7\x07\xff\xe1\ -\x87\xb4\x8f\x9f\xe7\xcc\xec\x04\xdf\x79\x7a\x8a\x2f\x6e\xac\x53\ -\x2c\x16\x51\x25\x19\x5d\x37\x68\xf4\x6d\x5e\xb8\x7a\x95\xad\xad\ -\x2d\x96\x96\x96\x18\x2b\x65\xf8\xf2\xab\xfb\x2c\xce\x2f\x90\x8c\ -\x96\xe9\x47\x47\x47\x5c\xb8\xb0\x42\x1c\x41\xbb\xdd\x65\x7a\x2c\ -\x4f\x18\xe6\xd8\xdb\xdf\x27\x49\x52\xc1\xd9\xf4\xf4\x34\x83\xc1\ -\x80\x6f\xaa\x95\xfd\x7e\x0a\xf2\xde\xd8\x6d\x31\x3f\x3f\x8f\x28\ -\x8a\xe4\xf3\x79\x56\x57\x57\xb9\x7e\xfd\x3a\xab\xab\xab\xe4\xf3\ -\x16\xed\x76\xba\x16\x3a\x73\xe6\xcc\x49\x71\xdf\x71\x62\x64\x59\ -\x22\x08\x02\x1e\xed\x77\xd8\xdf\xdf\xe7\x5b\xdf\xba\x4c\xaf\x37\ -\xa4\x5e\xaf\x93\xcd\x66\x19\x0e\x87\x27\x5e\xa8\xa1\xe7\xf2\xec\ -\x53\xab\xf4\xfa\xee\xe8\xae\x5d\x4a\x1f\xba\x28\x41\x51\x04\xd6\ -\xd7\x1b\x23\x3d\x6b\x77\xe4\xd2\x4d\x3d\xbc\x92\x94\xa6\xbd\x1c\ -\xc7\x39\xe9\x56\x8b\xa2\x70\x02\x1b\xbc\x7c\xf9\x29\x6c\x3b\x6d\ -\x59\x29\x8a\xc2\xfa\xfa\x3a\x83\x41\x9a\x09\xcf\x66\x4c\xa6\x6a\ -\x63\xc8\x22\x3c\xde\x7e\xc2\xfc\xf2\x12\x8a\x90\x9e\x18\x5c\x3f\ -\x44\x93\x54\x7c\x2f\xc4\xd0\xd2\x55\x88\x21\xa7\x27\x0f\x45\x51\ -\xd0\x15\x05\x2b\x57\xc4\xed\xf6\x48\x22\x09\x27\x0a\xc9\x24\x2a\ -\x92\x98\xae\xd9\x12\x09\x82\x38\xc1\xde\x3f\x44\x52\x05\x84\x76\ -\x97\x78\xd0\x63\x69\x69\x91\x97\x2f\x3f\xc5\x98\x95\xa1\xa8\x41\ -\x41\x81\xec\xec\x04\x3f\xfb\xf8\x53\x66\x67\xa7\x71\xc3\x04\x4b\ -\x85\xa1\x60\x22\x65\x4d\xbe\xfa\xf9\x97\x3c\xfb\xec\xb3\x0c\x1c\ -\x1f\x49\xd5\x29\x98\x23\x07\xf6\x54\x96\x97\x16\x2e\xf3\xe5\xa5\ -\xf3\xd4\xea\x45\x6e\x6d\xdc\xa5\xd5\x6d\xf1\xec\xb9\xd7\x11\x7d\ -\x9f\xb5\x9b\x5f\x22\xf4\x53\x30\xe3\xea\xd2\x12\xcd\xd0\xe3\xb0\ -\x3f\x20\x89\xe0\xce\x9d\x7b\x6c\xac\x6c\x31\x53\x3c\x4d\x39\x93\ -\xc7\xed\x77\x59\x9e\xc8\x23\x0b\x32\x59\x2b\xc7\xce\xa3\x2d\x5a\ -\xb6\x43\xe4\x87\xd4\x4b\x16\x5b\xd1\x11\xf3\xa6\xc5\x6f\xfe\xd6\ -\xef\x50\xd0\x65\xde\xff\x9b\x1f\xb1\xba\x74\x8a\x8b\x67\xe7\xb1\ -\x74\x78\xb0\xb6\xcf\xf8\xe9\x65\x4a\xb9\x2c\x9d\xbd\x03\x8c\xfa\ -\x18\x7d\x37\x44\x92\x45\xb2\xd9\x0c\x9d\xdd\x1e\xfe\x30\x40\xce\ -\x9a\x68\x8a\x41\x18\x27\xe0\xa7\x0f\x7a\xb9\x32\x86\xd3\xb7\x48\ -\xa2\x88\xee\xa3\x5d\x96\xcf\xad\xb0\xb7\xbd\xc5\x78\x3e\xc7\x7f\ -\xf4\xdd\x37\x91\x3c\x78\x7a\x31\xc3\x57\x37\x77\xf9\xbb\xaf\x5e\ -\xe6\x95\xa7\x2f\x90\x2b\x2b\x1c\xb5\xfa\x14\x73\x59\xf4\x04\xd6\ -\x1f\x1c\xb0\xfd\x78\x87\xfd\x46\x8b\x8d\x27\x3b\x58\xd5\x2a\x9f\ -\x5f\xbb\xc6\xc6\x9d\xdb\x5c\x58\x98\x63\xb6\x5a\x62\x7a\x76\x0a\ -\xc1\xd6\x39\x3d\x53\xe5\xdd\x8f\xbe\x60\x7e\x7c\x02\x13\xc8\x65\ -\xcc\xf4\x0a\x39\x72\x33\x67\x32\x19\x3e\xbf\x7e\x3d\x4d\x17\x1e\ -\xf5\xc9\xe6\xb2\x84\x02\x34\x8e\x87\xec\xed\xed\xf1\xbd\xef\x7d\ -\x0f\x29\x81\xe5\xe5\x45\xd6\xbf\xbe\x85\x28\x56\xf0\xc2\x10\xe9\ -\xfb\xdf\xff\x3e\x92\x2c\x23\x28\x52\xfb\xab\xfb\xeb\x6f\x9b\xa5\ -\x0a\x9f\x7e\x7d\x87\x5c\x7d\x92\xeb\x77\xee\x11\x89\x12\x8d\xe3\ -\x16\xae\xe7\x40\xe8\xb2\x3c\xb7\xcc\xd1\xce\x36\x17\xcf\x9c\xe2\ -\xee\xdd\x7b\xd4\x26\x67\x88\xe2\x84\x6c\x26\xc3\x93\xed\x6d\xa6\ -\xa7\xa6\x70\xdd\x88\x38\x8a\xd9\xdd\xdd\x25\x49\xa4\x14\xae\xe7\ -\xba\xe4\x72\x05\x74\x4d\x22\x08\x62\x90\x14\x44\x51\xc2\xb2\x2c\ -\xf6\xf7\xf7\x4f\x76\xc7\xd5\x6a\x86\xe3\xae\x9f\xf2\x91\x6c\x9b\ -\x5c\xce\xe4\xc6\x8d\x5b\x94\xcb\x65\x96\xa7\x2b\x0c\xfd\x74\x02\ -\x7c\xe1\xec\x02\x9f\x7d\x7e\x13\xdb\x4e\xc1\x68\xdf\x48\xc5\x83\ -\x20\xc6\xb2\x44\xc2\x50\xc0\x75\xbd\x93\xcc\xb4\xe3\x38\x98\x66\ -\x06\x4d\xd3\xc8\x65\x24\x24\x59\x45\x14\x25\x8a\xa5\x12\x8f\x36\ -\x37\x79\xb2\xb3\x43\xbd\x9e\xde\x9f\xeb\xb5\x2c\x09\x70\x78\xd8\ -\x22\x8c\x22\x92\x44\xa0\xd1\x68\xb0\xb8\xb8\x88\xae\xeb\xa3\xdd\ -\xb0\x48\x12\x46\x44\x51\x7a\x87\xee\xf7\xfb\x4c\x4e\x4e\x22\x08\ -\x22\x71\x9c\xa0\x69\x32\x8a\x92\x9e\x28\x7c\xdf\xa7\xd1\x68\xf0\ -\xd2\x0b\x4f\x33\x3e\x31\xc9\xf2\xf2\x3c\xd5\xea\x18\xf9\x7c\x0e\ -\xfc\x90\x30\x0a\xb8\x71\xeb\x2b\xb2\x99\x0c\xbb\x7b\x07\xb8\xb6\ -\x4b\xe0\x7b\x98\xba\x01\x89\x40\x31\xa7\x71\x70\x3c\x24\x5b\x2b\ -\xf3\xe3\x9f\x5f\xe7\x49\xb3\x85\x8b\x88\xac\xa8\x08\xfd\x00\xd1\ -\x09\x09\x5c\x1f\xcb\x34\xd3\x2a\xa6\x24\x20\x4b\x22\x42\x1c\x50\ -\xc8\x98\xf8\x9d\x16\x59\x31\xe1\x3f\xfb\xed\xdf\xe2\xad\x17\xaf\ -\xb2\x3a\x3d\xc1\xd9\x99\x02\x6e\xcf\xc5\xef\xb5\xd1\x54\x85\x27\ -\x4f\x9e\x50\xaa\x8e\xa1\x99\x3a\x8d\x01\x3c\xd8\xda\xe1\x47\x3f\ -\x7d\x9f\x7b\x1b\x1b\xcc\xcf\xcf\x33\xb4\x7b\xe4\x2d\x83\x92\xa5\ -\xd2\x6f\x77\xb8\xf3\xe5\xa7\x34\xda\x7d\xda\xbd\x3e\x7b\x07\x7b\ -\x94\x2b\x39\x7a\xed\x26\xa7\xe6\xa6\xf9\xde\x2b\x57\x78\xe6\xec\ -\x39\x2e\xaf\x4c\xd0\xed\xfa\xbc\xf8\xe2\x4b\xac\x5c\xbc\xc8\x61\ -\x23\x35\x3c\x54\x4a\x15\x24\x41\xe6\xc7\x7f\xf1\x0e\x25\x55\x26\ -\xb4\xfb\xe4\xf3\x35\x4a\x45\x83\x9c\x65\xa1\x4b\x69\xbc\x33\xa7\ -\x28\x18\x11\x24\x83\x1e\xcf\x9e\x5d\xe5\xcd\xe7\xe7\xa9\x9b\x70\ -\x71\x79\x89\x85\xb1\x22\xc7\xfb\x2d\x1a\xfb\x4d\x82\xc8\xe7\xa8\ -\xd5\xc3\x2a\x95\xd8\x6a\x1e\x23\xe8\x3a\xa1\x00\x82\x24\x22\x49\ -\x22\xbe\x63\x83\x28\xa4\x31\x55\x01\x82\x28\x20\x8e\x42\x34\xd5\ -\xc0\x92\x0d\x7a\xcd\x2e\x7e\xbb\x43\x71\x62\x8a\xdd\x8d\x87\x04\ -\x8e\xc3\xa0\xd5\xc6\x54\x14\x5e\xbe\x3c\x8d\xef\xc2\xf6\x83\x2d\ -\x26\x2a\x75\x72\x86\x44\xef\xb8\xcd\xb9\x5a\x9e\x56\xd7\x21\x6b\ -\x2a\xd4\xea\x19\xfe\xf9\xbf\xfc\xe3\x34\x5d\x58\xae\xf2\x8b\xeb\ -\x5f\xb0\xb5\xbf\x87\xa8\xa9\x1c\x1c\xed\xf3\x7b\xbf\xf7\xbb\x6c\ -\x3d\x5c\xa7\x54\xc8\x33\xe8\xb9\x24\x9e\xcf\x99\xc5\x39\x3c\xdb\ -\x23\x8c\xa2\xb4\x14\x64\xa4\x1d\x80\xc0\x0f\x68\x36\x9b\xd4\xc7\ -\xc6\x70\x7d\x8f\xb9\xb1\x3c\xbb\x47\x2d\x86\x8e\xc3\xda\xda\x1a\ -\x67\xcf\xac\x60\x19\x32\xf7\xbe\x5e\x23\xf6\x3d\x0c\x25\x65\x8b\ -\x4b\x6f\xbf\xfd\x87\xe9\x7f\x00\xfc\x6f\xff\xfa\xdf\xbc\xfd\xca\ -\x77\xdf\xe2\xbd\xcf\xbe\xa0\x13\xc6\x1c\xf6\xfb\x34\xba\x3d\x8c\ -\x6c\x06\xd7\x75\xf8\x47\xbf\xff\x7b\xb8\xbd\x0e\xf3\x93\x75\xea\ -\xa5\x22\x87\x07\x07\xf8\x71\x42\xb1\x5c\xa1\xd9\x68\x22\x00\x93\ -\x13\x55\x7c\xc7\xa7\x54\x2c\xd2\xeb\x76\x71\x1d\x07\xbb\x3f\x60\ -\x6e\x6e\x6e\x34\x91\x4d\xf7\x7d\x8e\xe3\x8e\xc8\x92\x12\x6b\x6b\ -\xeb\x27\x48\x5d\x5d\xcf\x9c\x54\xc9\x4a\xa5\x1c\x71\x0c\x1b\x1b\ -\x0f\x39\x77\xee\x1c\xc7\x5d\x1b\x4d\xd3\x18\x2b\xea\x6c\xee\x1c\ -\xb3\xb8\xb8\x98\x26\x9f\xf6\xf6\x4e\x8a\xfd\x9a\x26\x93\x9e\x1c\ -\xfb\x14\x0a\x16\x41\x10\xb1\xb9\xb9\x39\xd2\x9c\xa6\x6a\xcb\x20\ -\x04\x55\x15\x68\xb7\x7b\x8c\x8d\xe5\xd9\x3d\x68\x72\xfa\xcc\x19\ -\xba\xbd\x1e\x5f\xdf\xb9\x83\xed\x04\x04\x11\x2c\x4d\x96\x51\x34\ -\x8d\x56\xb3\x4d\xbb\xd5\x62\xac\x56\x27\x63\xca\x84\x41\x6a\xf1\ -\x73\x1c\xf7\x04\x07\x24\x08\x02\xb5\x5a\x85\x78\x34\xfc\x52\x14\ -\x11\x59\x16\x50\x14\x01\xdb\x76\x39\x3c\x3c\x64\x6a\x7a\x06\xdb\ -\x76\xb1\x4c\x99\x04\x19\xdf\xf7\x90\x13\x01\xd3\x32\x18\x0c\x6c\ -\x2e\x3e\xf5\x14\xaa\xac\xa2\xab\x2a\xad\xc6\x31\x47\xfb\x87\xdc\ -\xb9\x7d\x87\x56\x77\xc8\xd7\xf7\x1e\xb0\x7b\x3c\xe4\xbd\x6b\xd7\ -\x19\xc6\x22\x89\x91\x21\x09\xc1\x0a\x25\xc4\x50\xc0\x0f\x23\xac\ -\x6c\x86\x90\x38\x6d\x18\x89\x09\x44\x1e\xd1\xd0\x26\x1e\x74\x39\ -\x3b\x3b\xc5\xdf\xff\x95\xef\x30\x95\x97\x91\x47\x98\x69\x53\x95\ -\x51\x05\x01\x4d\xd3\xe8\x76\x6d\x66\x17\xa7\xf0\x81\xdd\x83\x0e\ -\x5e\x18\x72\xff\xc1\x3a\x8f\x1e\xae\xb3\xb4\x38\x87\x10\xf9\x28\ -\x84\xdc\xbd\x75\x03\x39\xf2\x99\x19\xab\xa0\x6a\x0a\x95\xb1\x31\ -\x64\x5d\xe1\x57\xde\x7a\x05\xa7\xd7\xe7\xeb\xeb\x9f\xb1\x3c\xbd\ -\xc0\x44\x3e\x87\x67\x43\xbd\xac\x73\xff\xfe\x26\xbd\x41\x9f\xa7\ -\x9f\xb9\x82\xe7\x07\xf8\x5e\xc0\xc5\xf3\x4f\xf1\xcb\xaf\xbf\xca\ -\xf2\xc4\x18\xe3\x95\x22\x87\x87\xfb\x64\xcc\x1c\xbd\x4e\x9f\x8b\ -\xab\x53\xcc\x8d\xcf\xf2\xfa\x4b\xcf\xf0\xd4\x99\x15\x72\xb2\xc4\ -\x6c\xb5\xcc\x44\xae\x86\x1c\x42\x2d\x07\x7f\xf2\x7f\xff\x80\x0f\ -\xdf\xfd\x31\xa7\x17\xe7\x59\x3a\x75\x8a\xad\xbd\x3d\xcc\x42\x81\ -\xcd\xfd\x03\x6c\xdf\x43\xd2\x0d\xfc\x28\x05\x1a\x84\x49\x84\x24\ -\xcb\x44\x61\x40\x32\x22\x6a\x46\x88\x48\x82\x84\x26\xa8\x78\xae\ -\x8f\x55\x2a\xd3\x6d\x36\x18\x9b\x9b\x46\xd7\x74\x0a\xb9\x2c\x1b\ -\xf7\xd7\x18\x0e\x62\x26\x6b\x13\x14\xb3\x16\x9e\x63\x53\x2d\x9b\ -\x58\x9a\xce\x51\x2b\x3d\x82\xef\x3c\xb1\xb9\x75\xef\x00\xad\x50\ -\x66\xbb\xdf\x67\xaf\x3f\x20\x3f\x31\xc5\x7e\xbb\x45\xbe\x5a\x46\ -\x55\x55\xbe\xfb\xe6\xf3\xb4\x8f\x5a\x18\xb2\x4c\xfb\xe0\x80\x0b\ -\x2b\x67\x70\x3b\x5d\x4a\x05\x0b\x49\x56\xf9\xfa\xee\x5d\x96\x17\ -\x17\x70\x1c\x97\xcf\x3f\xbb\xce\x1b\xaf\x5f\xc5\xf1\x62\x8e\xdb\ -\x6d\xd0\x2c\xa6\xeb\x39\x3e\xfa\xec\x0b\x5e\x7a\xfe\x79\x8e\x0e\ -\x0e\x10\x63\x91\xbd\x9d\x27\x68\xb2\x44\xa7\x79\x40\x31\x97\x41\ -\x4e\x82\x90\x50\x14\x09\x12\x91\x4c\x36\xcb\xcd\x3b\x6b\x94\x6b\ -\x75\x3e\xbc\xfd\x35\x5d\x2f\x64\x30\xda\xa9\x55\x4a\x45\x62\x45\ -\xe5\xf6\xcd\xfb\x64\x57\x16\xf0\x0b\x39\x2e\x3d\x73\x85\xf7\x7e\ -\x71\x8d\x4a\x7d\x92\x9d\xad\xc7\xcc\xcd\xcf\x63\x48\x20\x17\xd2\ -\x95\xd0\xd2\xd2\x12\xeb\xeb\xeb\x6c\x6f\x6f\xb3\xbc\xbc\x38\x22\ -\xf4\xbb\x27\x4d\xa2\x28\x8a\xd8\x7a\xbc\x93\x8a\xd6\x46\xd9\xe5\ -\x66\xb3\x89\xaa\xaa\xd4\x6a\x25\x0c\x05\xae\xdf\xbc\xcf\xc2\xc2\ -\x02\x51\x14\x91\xcb\x59\x34\x1a\x2d\xf4\x89\xd2\x68\x5f\x2b\x60\ -\x59\x16\x51\x14\x71\x74\x74\x84\x61\x18\x8c\x8f\x8f\x9f\xac\xaa\ -\x46\x9c\x78\x76\x76\x76\xb8\x70\xe1\x2c\xb2\x0c\xed\x76\xba\xe2\ -\x99\x1f\xcb\xa3\x69\x1a\x8f\x77\x9a\x0c\x06\x03\x5e\x7e\xf6\x02\ -\x1d\x37\x6d\x67\x09\x82\xc0\x9d\x3b\x77\x68\x36\x9b\x9c\x5e\x5a\ -\xa6\xdd\x6e\x9f\x20\x87\x3c\x4f\xa1\xdf\xeb\x91\xc9\x64\x10\x00\ -\xc3\x90\x4f\x86\x5a\x41\x10\x9d\xf4\x8f\xfb\xfd\xb4\x71\x53\xab\ -\xa4\xd8\x9f\x6a\xb5\x8a\xeb\x06\x74\xbb\x5d\x34\x4d\x43\xd3\x04\ -\x72\xb9\x1c\xb5\xba\x48\xcb\x0e\xb1\xb2\x19\x82\x20\xc0\x34\x4d\ -\x8a\xc5\x0c\xc5\x7c\x81\x38\x8e\x39\x73\x66\x85\x9e\x1b\x70\xd0\ -\x77\xb8\xf1\xf8\x71\x4a\x20\xc9\x99\x69\xc7\xb7\xd3\x21\x70\x64\ -\x22\xc7\x23\x71\xfa\xec\xeb\x22\x44\x4e\x5a\x52\xc6\x07\xd7\xc6\ -\xd2\x54\x2a\xf9\x0c\xab\x0b\x73\x3c\xb9\xff\x88\xc7\xc3\x3e\xba\ -\x14\xf3\xe9\x47\x3f\x67\x61\x7a\x8a\x8c\xa2\x63\x9a\x19\x3e\xfa\ -\xf8\x53\x5a\x6e\x88\x1f\x27\x4c\xcd\x2f\xb2\x34\x33\xc9\xe6\xdc\ -\x04\x6b\xb7\x3f\x47\x08\x5d\x3a\xcd\x16\xcf\x5f\x3e\xc7\xd2\xcc\ -\x18\xb5\x62\x9e\x24\xf6\xe9\xbb\x01\x7d\x41\x66\x6a\xac\xca\xc1\ -\xee\x3e\x65\x4b\xe3\xf9\xa7\x2e\xb2\x3c\x39\x81\x14\x24\xe4\x4d\ -\x01\x2f\x84\xd3\xb3\xd3\xdc\xdf\xdb\xa3\x9a\xd1\xf0\x3b\x1d\xb6\ -\x1e\xac\x51\xcd\x64\xf9\x3b\x57\xea\x38\x4d\x99\x6c\x2e\xcb\xda\ -\xc3\x07\x2c\x1b\x8b\x74\xba\x1e\x59\x05\x44\x6f\x40\xd8\x09\x29\ -\x6b\x3a\xbf\xfb\xab\xaf\x70\xe3\x8b\x7b\x14\x34\x08\xbc\x90\x4f\ -\xde\xbf\x45\xce\x90\xf8\xcf\xff\xe0\x3f\x46\xd6\x2d\x26\xea\x12\ -\xa7\x9d\x39\xde\xb9\xf6\x39\xde\xb0\x4f\x22\xca\xc8\x52\x82\x14\ -\x83\x28\x8b\x48\x9a\x9c\x02\x06\x5c\x1f\x64\x19\x43\xd7\x48\x1c\ -\x17\xcf\x71\x38\xea\x76\xc8\xd7\xea\x74\x1f\x3d\x00\x09\x8e\xda\ -\x5d\xa6\x27\xaa\x34\xf6\xb6\x19\x1f\xab\xf1\xe1\x97\xd7\xb9\x73\ -\xe7\x2b\x26\x4b\x59\x2c\x59\xe4\xf2\x53\x67\x91\x49\x58\x3d\x73\ -\x3a\x05\x48\x22\x32\xb9\x38\xc3\xbf\x7d\xf7\x7d\x7a\x41\x42\x7e\ -\x7a\x92\xdd\x76\x97\xfc\xf8\x14\x9e\x98\xd0\x6e\x1f\xf2\x60\xb3\ -\xc5\xd2\xdc\x12\xb7\x3f\xfd\x98\x37\x9f\xbb\x82\xef\x0e\xc9\x9a\ -\x06\x83\x4e\x9f\x89\x4a\x4a\xe7\x6c\xb5\x3b\xf8\x9e\x97\xe6\x0b\ -\x46\x9d\x7a\x7b\xf3\x11\x41\x10\xb0\x7d\xd8\x65\xbc\x56\xa7\x54\ -\x2a\xf2\x68\x7d\x83\xe9\xb1\x09\x04\x21\xc5\x0e\xaf\x6d\xdc\xe6\ -\xe2\xea\x29\xa4\xb7\xbf\xff\x7d\xa2\x38\x46\x90\x65\x3c\x59\x79\ -\xfb\x27\x1f\x5f\xe3\xb9\x37\xde\xe4\x87\x3f\x79\x8f\x48\xd5\x70\ -\x10\xa9\x8c\x8d\xf1\xdd\xb7\xde\xe4\x4f\xfe\xcd\x1f\x31\xec\xb4\ -\x98\x9b\x9c\x60\xa2\x5c\x26\xf4\x7d\xda\xdd\x2e\x9a\x6e\xb0\xf3\ -\x78\x9b\xd3\x67\xce\x20\x22\xf0\x68\x73\x87\x62\x21\x47\xb3\xd9\ -\xa2\xdb\xed\x22\xcb\xe9\x31\x33\x9b\x31\x89\xe2\x64\x24\x29\x97\ -\xe9\x0f\x1c\x1e\x3e\x7c\xc8\xf9\xf3\x29\xa0\x2e\x97\xcb\x11\xc7\ -\x31\xad\x56\x8b\x6a\xb5\x44\xb3\x65\x73\xeb\xd6\x2d\xde\x78\xf1\ -\x32\xed\x7e\x5a\x87\x2b\x16\x33\xd8\x76\x70\xd2\x27\xbd\x7d\xfb\ -\x36\x57\xae\x5c\xc1\x30\x52\x80\x5f\x4a\xd8\xac\x8c\x76\xc9\x6d\ -\x5a\xad\x16\xab\xab\xab\x48\x92\x82\x6d\xbb\x64\xb3\x06\xbe\x1f\ -\xd2\xe8\x0c\x28\x55\xf3\x38\x9e\x8f\xac\xc8\xa8\x56\x9e\x5e\xbf\ -\x87\x61\x1a\x68\x7a\x7a\x27\xd5\x75\x9d\xc7\x5b\x5b\x1c\x1c\x1c\ -\x30\x37\x3b\x4b\x2e\x9b\x45\x92\x04\x54\x49\xc1\x32\x14\x44\x49\ -\x21\x8a\x53\xa9\xdb\xfc\xfc\xfc\xc9\x09\x43\x51\x24\x44\x51\xc6\ -\x34\x55\x9a\xc7\x7d\xb6\xb7\xb7\x99\x9a\x9a\xa2\x5a\x36\x51\x54\ -\x2b\xe5\x19\xfb\x11\xf6\xa0\x4f\x10\x8b\x3c\xd9\xd9\x4e\x57\x0d\ -\xb5\x3a\x96\x65\xa6\x9e\xe4\x44\xc2\x30\xd2\x7d\xfc\xde\x61\x93\ -\x61\x14\xf1\xf1\x8d\x5b\xec\x0f\x06\x04\xaa\x0a\xa6\x49\x1c\x0b\ -\x94\x0a\x15\x64\x4d\xc7\xd3\x24\x8c\xf1\x32\xa1\x25\x41\xce\x40\ -\x34\x15\x24\x55\x20\xaf\xc9\x18\x62\xcc\x9b\x2f\x3e\xc7\xb7\x2e\ -\x2e\x52\x2b\x94\x18\xab\x97\xd9\xdd\xdb\xe1\xcc\xea\x0a\xcf\x3c\ -\xf7\x02\x67\x4f\xcd\xe2\x0a\x3a\x97\x9f\xb9\x4c\xa9\x94\x67\x61\ -\x22\x87\x20\x26\xec\x3f\x49\x41\xe8\xaf\xbd\xfa\x22\x8e\xdd\xe7\ -\xe9\x73\xa7\x40\xd1\x69\x76\xfa\x34\xbb\x43\x8a\xa5\x02\xb1\x22\ -\x63\x58\x26\x3f\xfe\xdb\x77\xa8\x97\x4a\x3c\x75\x66\x95\xbc\xaa\ -\xe3\xb4\xda\x54\x8a\x26\x81\x03\x42\x12\xb3\x76\x7f\x8d\x33\x67\ -\xa6\x99\x9a\x98\xa5\x71\xb0\xc7\xc6\xfa\x1a\xe5\xea\x0c\x33\x53\ -\x79\x14\x15\xd6\x37\xb7\x98\x98\x9a\x44\xd5\x52\xc3\xa1\x2a\x2b\ -\xe4\x33\x26\x85\x8c\x44\x55\x83\x9f\xfd\xe2\x13\x8e\x9b\x87\x94\ -\x4a\x59\x0c\x4b\xe5\xea\xd5\x67\x53\x8f\x57\xce\x22\x14\x40\xc9\ -\x68\xbc\xff\xc9\xe7\x3c\x39\x6a\x20\xa8\x1a\x82\x92\xe2\x89\x24\ -\x49\x22\x4a\x42\x84\x24\x49\xa1\x00\xa2\x88\x2a\xab\xf8\xae\x47\ -\xec\x85\x88\xb9\x02\x6e\xb7\x8d\x3e\x33\x85\x58\x2a\x10\x86\x1e\ -\xdd\xa3\x43\xcc\x7a\x85\xe3\x41\x17\x23\x9b\xa1\xd1\x6f\xd1\xf7\ -\x7d\xd6\x36\x37\xf8\xf6\x9b\xbf\xc4\x5f\xfc\xf8\x47\xf4\x1c\x17\ -\x17\x1d\x31\x53\xe0\x9d\x9f\x5f\xe3\xc6\xc3\x87\xc4\xba\x81\x27\ -\x2a\x04\x08\xe8\x66\x86\xe3\xbd\x3d\xe6\xa7\x26\xf9\xd5\x37\xbf\ -\x85\xd7\x75\xe8\xec\xef\x32\x53\xaf\xa1\x90\x50\xcc\x9b\xf4\x6d\ -\x9b\x50\x4e\x05\x89\xbb\x3b\x7b\x04\x5e\xc0\x85\xf3\xe7\x69\xb7\ -\x7b\x54\xaa\x16\x7e\x08\x8e\xeb\xd0\xb3\xfb\x68\x9a\x8a\x22\xcb\ -\xb8\x03\x9b\xe3\xa3\x23\x9e\xba\x70\x81\x87\xf7\xd7\x68\x1f\xed\ -\xf3\xea\x2b\x2f\xfd\x0f\xe2\x89\xca\x02\xe8\x0f\x6c\x7a\x83\x3e\ -\x53\x93\x79\xf6\x0e\xf7\x71\xa2\x08\x35\x93\xa1\xd9\xed\x53\x9d\ -\x9a\xe6\xeb\xbb\xf7\xa8\x4f\xcd\x52\xac\x8f\xd1\x75\x3c\x8c\xac\ -\xce\x85\x8b\x97\x78\xe7\xaf\xfe\x9a\x97\x5f\x7e\x19\x59\x10\x71\ -\xdd\x90\xf9\x99\x29\xc2\x10\xca\xe5\x12\xbd\x5e\x8f\xd5\xd5\x55\ -\x76\x77\x77\x69\xb7\x7b\xe8\xba\x32\x02\x10\xa4\x70\xfb\x6c\x36\ -\x8b\xeb\x68\xd5\xc5\x24\x00\x00\x20\x00\x49\x44\x41\x54\x7a\xd4\ -\xeb\x39\x24\x49\xa2\x58\x2c\x22\xcb\x32\x1b\x1b\x8f\x4f\x98\xd2\ -\x8f\x8f\xfa\x58\x96\x89\x61\x28\xa8\x72\xda\x30\x52\x14\x05\x4d\ -\x13\x71\x5d\x97\x52\x31\xbd\xb7\x5e\xbe\x7c\x16\xd3\x34\xf9\xfa\ -\xeb\xbb\xec\xee\xee\x93\xcf\xe7\xd3\x69\x74\xc6\xc0\xf7\x7d\xf2\ -\x79\x7d\xe4\x41\xce\x8c\xd2\x5c\x21\x1b\x1b\x1b\x14\xcb\x25\xc2\ -\x30\x24\x97\xcb\xa5\x98\xda\x38\x66\x76\x76\x9a\xd9\xd9\x09\xc6\ -\xc7\xc7\x49\x92\x84\xfd\xfd\x7d\x3e\xfb\xec\x33\x6e\x5c\xbf\xc1\ -\x60\x30\x20\x08\x52\x1d\x6c\x14\xa6\x3b\xed\x7c\xde\x1c\x85\x12\ -\x62\x06\x83\xd4\x65\x14\x45\x50\x2e\xa7\x29\x23\x51\x14\xe9\xdb\ -\x31\x51\x14\xa5\xc5\x74\x45\x26\x9b\xcf\x11\x46\x11\x7e\x1c\x51\ -\x9b\x98\x44\xcf\x68\xc4\x12\x34\x8e\x07\xb4\xfb\x7d\x04\x09\xba\ -\x03\x0f\xdb\x19\x32\x35\x3b\x43\xa5\x56\x66\x7a\x7a\x12\xd3\xd4\ -\x51\x55\x19\x39\x63\xe0\x27\x21\x2e\x01\x10\xe2\x89\x61\x7a\xa4\ -\x96\x42\x12\x29\x06\x21\x82\x24\xa4\x5e\x2e\x90\x35\x0c\x86\x7d\ -\x9f\xb5\x3b\x5f\x53\xb2\x0c\x7e\xe7\xb7\xfe\x3e\xab\x2b\xe7\x70\ -\x43\xd8\x1f\x80\x17\xc5\xc8\x2a\x54\x2a\x16\xcd\xae\x83\x24\x26\ -\x7c\xfb\xd5\x97\xf8\xa5\xef\xbe\x4e\xb1\x90\xc3\xf7\x7d\x22\xa0\ -\xd3\xf7\xb0\x0a\x59\x44\xa3\xc8\x5f\x7f\x70\x9d\x9f\xfe\xec\x13\ -\x7e\xf0\xef\x7e\xc8\xfb\xef\xbe\xc7\xb9\xe5\x15\x66\xea\xe3\x18\ -\x8a\xcc\xc2\x4c\x85\xfd\x27\x4d\xf2\x16\x18\xb2\x40\x86\x08\xd5\ -\x85\x53\x75\x85\x3f\xf8\x9d\xdf\xe4\x3f\xf9\x9d\xdf\x24\xa3\x09\ -\x20\x81\x13\x83\x6a\xa8\xc8\xaa\xc8\x54\x59\x63\xd8\x1b\xa0\x2b\ -\x02\x42\xe0\xf1\xc5\xb5\xcf\xf9\xa3\x3f\xfb\x4b\x56\x4f\x2d\x31\ -\x3b\x35\x8e\x69\xa9\xcc\xce\x4d\x13\xe0\x93\x28\x31\x92\x96\xb2\ -\xcb\x24\x09\x6a\xd5\x32\x86\xaa\x21\x0a\x09\x51\x18\x12\x78\x3e\ -\x41\x98\xca\xc5\xe5\xd1\x6e\x1e\xcf\xa7\xdf\xeb\x11\x0e\x86\x90\ -\x40\xec\xda\xe4\xe7\x66\xf1\xe2\x10\xbf\xd7\x81\x24\x41\xa8\x55\ -\x71\x13\x01\xd1\xca\xd1\x0e\x23\x02\x33\xcb\x61\x10\x61\x4d\xcf\ -\xf3\x4f\xff\xd7\x7f\x89\x5a\x99\xe2\x27\x9f\xdd\xa2\xba\x3c\xc1\ -\x7f\xf8\xe0\x43\x3e\xf8\xf2\x0b\x8c\x4a\x05\x57\x10\xf1\x13\xc8\ -\xe4\xcb\x0c\x6d\x8f\x5c\xae\xc4\x58\x65\x02\xb7\x0f\xed\xa3\x63\ -\xf2\xf9\x22\xaa\xa1\x93\x29\x64\x69\xdb\x43\xcc\x5c\x96\x4e\xaf\ -\xcb\xd9\xe5\x99\x93\x3e\x41\x1c\xc7\xcc\x4e\xe4\xd9\xdd\x6d\x91\ -\xcf\xe7\xd9\xdb\xdb\xa3\x79\xd4\x60\x76\x76\xf6\x24\x3d\x38\x1c\ -\x0e\x4f\xb8\x6f\x82\x20\x90\xb3\x32\xff\xb5\x4c\x1c\x23\x49\x32\ -\x11\x90\x2f\x16\xa8\x8f\x8d\xf1\xaf\xfe\xf8\x2f\xa8\x4d\x4e\x73\ -\xb4\xbb\x4b\xe1\xcc\x79\x24\x51\xe1\xbd\x9f\x7d\x04\xb2\xca\x67\ -\xb7\x6e\xf3\xfb\xbf\xf1\x26\x62\x08\x03\x0f\xc2\x30\xe0\xd4\xa9\ -\x53\xbc\xf7\xde\x7b\xfc\xd2\x2f\xbd\x81\x28\xca\x7c\xf1\xc5\x4d\ -\x2e\x3f\xfb\x14\x8e\x13\x9e\xac\x78\xce\x9c\x39\xc3\xfa\xfa\x3a\ -\x09\x33\xa8\xaa\x4a\xc1\xd2\x4f\x78\x59\xa6\xa9\x61\xdb\x69\x83\ -\x28\x93\x91\x58\x58\x98\xe3\xde\xbd\xfb\xec\xee\xee\xf2\x9d\xef\ -\x7c\x07\x59\x86\x4e\x67\x40\xa1\x90\xa1\xd9\x72\xc8\x66\xb3\x88\ -\x22\xdc\xb8\xf1\x35\x57\xaf\x5e\x65\xe8\x30\xba\x77\x27\x4c\x4f\ -\x4f\xd3\xeb\xf5\x38\x3e\x3e\xe6\x9d\x77\xde\xe1\xf5\xd7\x5f\xa7\ -\xd7\x4b\xa7\xdf\x8e\x13\x33\x1c\x0e\x99\x28\xea\x1c\x0f\x87\x98\ -\xd9\x54\x68\x5e\x2e\xe7\x11\xd3\xb2\x0c\xfd\xbe\x43\x36\x6b\x10\ -\xfa\x09\xc3\xa1\x47\xbf\xdf\xe7\xca\x95\x2b\xa8\x23\xf2\xe2\xa0\ -\xdb\x63\x73\x73\x33\x25\x6e\x6a\x29\x69\xe2\xf4\xe9\xd3\x84\x21\ -\x23\xd3\x80\x80\x69\xea\xb4\x5a\x1d\x82\x20\x44\x55\xe5\x93\xd8\ -\x69\x14\xc1\x60\x30\xa0\x54\xca\xe1\xfb\x31\x51\x1c\x60\x64\x0d\ -\xd6\x1e\xae\xf3\xe6\x5b\xa7\xb0\xbd\x80\x44\x10\x31\x0b\x19\x42\ -\x37\x66\xe0\x82\xa2\xa9\x1c\xb7\x5b\x5c\x58\x59\xe2\xa5\x17\x5e\ -\xe0\xeb\x7f\xf7\xc3\x14\xcd\x93\xc4\xe8\x56\x89\x5e\xb7\x0f\x7e\ -\x04\xc5\x1c\x71\xe8\x81\x14\x41\x14\x90\x04\x0e\x95\x7c\x06\x1a\ -\xc7\x8c\x17\xcb\x88\xbe\x4f\x5e\x53\x79\xf5\xb9\xa7\x19\x0e\x03\ -\xfc\x30\xc0\xca\x9a\x88\x22\x68\x66\x8a\x8d\x75\x83\x98\x76\xcf\ -\xa6\x50\xc8\xe2\xf9\x01\xc8\x0a\xa2\xa8\x23\x29\x02\x6a\xae\xc8\ -\x6e\x37\xa0\x50\xd4\xe8\x3b\xf0\xe4\xa0\xc9\xbf\xfd\xc1\x9f\x83\ -\x92\x60\x1a\x2a\x85\x6c\x89\xd9\xb1\x32\x4e\x3f\xc4\x1e\xf4\x30\ -\x2b\x25\xea\x63\x65\x3a\xed\x1e\xb2\xaa\x31\x37\x5e\x23\xe9\x77\ -\x19\x0c\x45\x96\x6a\x59\x4c\x65\x0a\x2f\x0a\x89\x43\xb8\x71\xe3\ -\x06\x49\x12\xf1\xbf\xfc\xcf\xff\x13\x05\x2b\xcb\x85\xd5\x15\x4c\ -\x4d\x43\x4c\xe0\xb9\x2b\x97\x49\xa2\x00\x59\x55\xf9\xf0\xc3\x0f\ -\x39\x7b\x76\x99\xee\x70\x48\x22\xa4\x2b\x36\xcf\xf6\xd0\x73\x5a\ -\x8a\xea\xfd\x46\x3e\x6e\x98\x04\x71\x82\x22\x4a\x44\x51\x94\x26\ -\xf4\xfc\x00\xd5\x34\xf1\xbb\x0d\x92\xee\x80\xfc\xcc\x1c\x7e\x9c\ -\x10\x48\x0a\x8e\xdd\x23\xf1\x3c\xc4\x5c\x86\xb8\xdf\x25\x89\x22\ -\xbc\x20\x42\xd2\x15\x12\x51\x45\x55\x54\x54\x2d\x4b\x2f\x4e\x68\ -\xf5\xf6\xf9\xd9\xed\x75\xca\xf9\x02\x6f\xff\x8b\x3f\xa6\xeb\xb8\ -\x38\x86\x46\xbf\xdb\x65\x6c\x66\x9e\x83\x8d\x4d\xc8\x96\x08\x3a\ -\x7d\x6a\xa5\x1c\x49\xdf\xa1\x77\xd0\xe1\xcc\xfc\x2c\xb2\x57\xe1\ -\xb0\x71\x44\x2e\x33\x45\xd7\xb7\xa9\xe4\xaa\x98\x42\x96\xb5\x47\ -\xfb\x6c\x6d\x6d\xf1\xd2\x0b\x2f\xa6\x7f\x43\xa4\x78\x64\xcb\xd4\ -\x09\x43\x9f\x67\x9f\xfb\x16\xa1\xef\x91\xcf\xea\x1c\x1e\xec\xf1\ -\xdc\x33\x57\x50\x25\x91\x24\x0e\x19\x1b\x1b\xc3\x0b\x03\x44\x44\ -\x11\x3f\xf0\x11\x49\xdf\x90\xa6\x69\xb2\xb1\xb1\x81\xae\x1b\x20\ -\x29\x04\x61\xcc\xc0\xf3\x58\x7b\xf4\x08\x31\x5f\x62\xbf\xd9\xa2\ -\x39\x48\x68\x0e\x5d\xfc\x94\xa5\x40\x44\xc2\xf2\xf2\x32\x07\x8d\ -\x16\xfd\xbe\xcd\xc4\xf4\x14\xed\xf6\x80\x9d\x9d\x1d\xa6\xa7\xa7\ -\x49\x92\x04\xc3\xd0\x28\x14\x0a\x27\x9f\x3a\x7e\x02\x07\x07\x07\ -\xd4\x6a\x35\xa2\x08\x72\x96\x38\x42\xd3\xba\x88\x22\x4c\x4e\x4e\ -\x22\x8a\x22\x5f\x7d\xf5\x15\x87\x87\xa9\x92\xb4\xdb\xb5\x99\x28\ -\x19\x04\x41\x80\x28\xc2\xee\xee\xee\x68\x82\xcc\xc9\xbd\x58\x92\ -\x52\x25\x4b\xbd\x5e\x27\x8a\x22\x3e\xff\xfc\x73\x8e\x8f\x8f\x31\ -\xcd\xb4\x4b\x3a\x35\x59\x62\xb7\xe5\x60\x8e\x90\x3b\x51\x14\x71\ -\xb0\xd7\xa0\xd5\xea\x8f\xa0\x04\xa9\x19\x52\x14\x53\xdc\xee\x37\ -\x6e\x9e\x6f\x22\xa7\xe5\x5a\x89\x95\x95\x15\xce\x9f\x3f\xcf\xc2\ -\xc2\x02\x3b\xbb\xbb\xec\xee\xee\x72\xef\xde\x1a\x7b\x7b\x7b\x48\ -\x12\xe4\x34\x4e\x4c\x16\xb6\x1d\xa2\x28\x0a\xb6\xed\x11\x86\x11\ -\xda\xc8\xe6\x97\x24\x09\x9e\x1b\x20\xca\x60\x5a\x59\x14\x0d\x64\ -\x5d\x41\x92\x47\xc4\x4c\x45\x44\x31\xc0\x0b\x02\x44\x45\x64\x38\ -\xf4\xe8\xb4\x1b\xb8\x76\x8f\x6a\xd6\xa2\x6c\x19\x88\xa1\xc3\xcc\ -\x44\x0d\x49\x49\xa0\x7b\x0c\x8e\x4d\xc1\x32\x28\x98\x1a\xa2\x3d\ -\x60\x78\xd8\x64\xb6\x5a\xe3\xd4\xcc\x0c\x33\x63\x13\x88\x11\xf4\ -\x7b\x09\x42\xac\x60\xaa\x26\xbe\x13\x93\x44\x01\x9d\xee\x90\x4e\ -\xaf\xcd\x30\x0c\x49\x8c\x0c\xa1\x04\x9e\xa2\x10\xe8\x32\x7d\x51\ -\xe0\x89\x0d\x76\xac\x90\xcd\x2b\x34\x7b\xe0\x7a\x50\xaf\xd5\xf8\ -\x1f\xff\xd9\x7f\xc7\x6f\xff\xf6\xef\xb2\xba\x72\x9e\x38\x10\xd8\ -\xde\x69\x93\xcb\xc8\x8c\xd7\x4a\x20\xc2\x93\xbd\x5d\x14\x4d\x41\ -\x91\x05\x32\xaa\xc8\xa0\x7d\x84\xe0\xda\x04\x5e\x42\x5e\x93\x99\ -\xc8\xeb\x74\x8f\x9b\xf8\x43\x87\xc8\x0d\xd1\x25\x85\x2b\x17\x2f\ -\xf2\xf4\xb9\xf3\x5c\x5a\x5d\xe5\xca\x53\x17\xd1\x04\x81\x24\x88\ -\x38\xdc\x4d\x3f\xf4\xd7\xd6\x36\xc8\x98\x26\xb2\xa4\xa2\x59\x26\ -\x99\x9c\x46\x6b\x08\xfb\xbd\x84\xe9\xd9\x39\x7a\xf6\x80\x20\x88\ -\x4e\x70\xb6\xa2\x20\xe3\x3a\x0e\xa1\x6d\xe3\xf7\xfb\x29\x4d\x53\ -\xd7\xd1\x14\x15\x39\x11\x48\xbc\x21\x62\xe4\x93\xcb\x18\x88\x9e\ -\x0f\x89\x00\xbd\x21\x08\x12\xaa\xa8\xa1\x6a\x59\xbc\x40\xc2\x89\ -\x15\x5a\xfd\x00\xe4\x0c\x43\x07\xfa\x81\x42\xdb\x49\x38\xb4\x87\ -\x24\x96\x85\x59\x2e\x73\x70\xb8\x0f\x8e\x83\x10\x85\x94\x72\x39\ -\x1a\x8f\xb7\xd9\xdb\x58\xa7\xa0\x19\xd4\xf2\xa9\xd2\x67\x6f\x6f\ -\x8f\x50\x48\xd0\x0b\x59\x0e\xbb\x6d\x10\x65\xb6\xb7\xb7\x79\xeb\ -\xad\xb7\xd8\xda\xda\x42\x55\x25\x1e\xee\xb4\xa9\x55\x4b\xc4\x71\ -\xcc\xe7\x9f\x7f\x8e\xaa\xaa\x54\xb2\x3a\xfd\xbe\x47\xbd\x5e\x47\ -\x92\xa4\x13\x38\x85\x61\x18\xe9\x10\x37\xad\x6d\x86\x08\x8a\x8a\ -\x61\x18\xb8\xae\xcf\xd6\xd6\x36\xc6\xd4\x22\x68\x06\x76\xb7\xcf\ -\xd8\xdc\x22\xc7\xfb\xfb\x24\xb2\xcc\xd0\x8f\xd8\x3c\x3c\xe2\xea\ -\x6a\x9d\x81\x0d\x7e\xb7\x43\xbe\x50\x60\xe9\xf4\x1c\xb7\xbe\x5a\ -\xa3\x5c\x2a\xe1\xf9\x3e\xba\x61\x70\xd4\x68\x70\xee\xdc\x39\x0c\ -\x53\xc1\xf7\x13\x32\xd9\x2c\xb2\x24\xd1\x38\x3a\x62\x7f\x2f\xe4\ -\xe2\x85\x0b\x84\x61\xc8\x70\x38\x44\x96\xf3\x14\x8b\x59\x6c\xdb\ -\xa3\xdb\xb5\x39\x3e\x3e\x66\x61\x61\x81\x7a\xbd\xce\xbd\x7b\xf7\ -\xa8\x54\xca\x54\x2a\x16\x5f\x3d\x78\xc2\xdc\xdc\x34\xcd\x66\x87\ -\xc5\xc5\x45\x64\x59\xc6\xf3\xc2\x13\xce\x56\x92\x88\x29\xa3\xab\ -\x6c\xb2\xb2\xb2\x72\xf2\x40\x7f\xf0\xc1\x27\x0c\x06\x03\xbe\xfd\ -\xed\x6f\x9f\x64\xbd\x8f\xf6\x0f\x78\xe6\xe9\xcb\x64\x32\x2a\x92\ -\x08\x8e\x9b\x66\xa6\x3b\x2d\x8f\x6a\xb5\x44\x26\x93\x39\x79\xd8\ -\x13\xc0\x1f\x91\x46\x14\x5d\x43\x55\x05\xe2\x3e\x94\x4a\x25\x2e\ -\x8c\x7e\x8e\x6f\x2a\x94\xe9\xd1\x7c\x96\x53\xa7\x16\x78\xfc\x78\ -\x97\x6a\xb5\x8a\xae\x6b\x29\x91\x75\x98\xd0\x1f\x75\xaf\xb3\xd9\ -\x0c\xed\xb6\x4d\x14\x45\xf4\x06\x3e\x89\x20\x10\x22\x90\x44\x31\ -\x22\x31\x8a\xa2\xd3\xb7\x7b\xe4\x72\x19\xc4\x38\x62\x6e\x62\x9c\ -\xaa\x65\x30\xb9\x34\xcf\xed\xad\x1d\x3a\xc7\x2d\x3a\x3d\x17\x39\ -\x08\x50\x14\x01\x25\x89\xd0\xfa\x7d\x12\x7f\xc8\xb4\x9e\xe1\xa9\ -\xe5\x25\xae\x9e\x3d\x8b\x19\x44\x78\x03\x97\x44\x55\x91\x48\xe3\ -\xa8\x22\x10\x07\x22\xba\x29\x12\x0a\x21\x66\x3e\x8b\x94\x55\x71\ -\x62\x38\x4c\xa0\x39\x00\xd5\x84\x66\x23\xe2\xf1\xe6\x43\xfe\x9f\ -\xff\xeb\x4f\x10\xb4\x2c\xcf\x5f\x9e\xa7\x20\x81\x81\xc0\xe3\xa6\ -\xc3\xab\xcf\xae\xf2\xec\xa5\x55\xdc\x37\x7f\x99\xde\xc1\x01\x1b\ -\x7d\x87\xd3\xcb\x13\xd8\x8e\x4b\xa9\x5a\x41\x33\x75\xdc\xc1\x00\ -\x51\x84\xd8\xf1\x59\x98\x19\x63\x18\x26\x6c\x3c\x5c\x67\x63\xeb\ -\x31\x86\x9e\xc3\x42\x66\x6a\x7a\x02\xc5\x0b\xb8\x7c\xfe\x22\xc5\ -\xac\x4e\xe8\x86\x64\x4c\x19\x7b\xe8\x53\x29\x59\xd4\x4a\x16\xb7\ -\x1f\x80\x6a\xa6\xb9\x7d\x14\x89\xa1\xed\x83\x69\x22\x58\xe0\x0f\ -\x04\xdc\x58\x20\x8a\x05\x1c\x2f\x44\xb7\x24\x7c\xc7\x25\x16\xa5\ -\xf4\xc4\x22\x29\xe9\x2b\xdc\x34\xc0\x49\x85\x07\x02\x31\x79\xc3\ -\xa0\xd3\xef\xa2\x5b\x59\x2c\x41\x44\x34\x33\xb4\xb7\xb7\x41\x90\ -\x31\xcc\x3c\x71\x22\xe0\xba\x43\x04\x5d\x81\x58\x82\xdc\x18\xf4\ -\xfa\x84\xa1\x4a\x40\x8c\x9a\x2b\x30\xf0\x3c\x14\xcd\x02\x55\x83\ -\x4a\x89\x7e\xa3\x41\xdd\x32\xd1\x49\x98\x28\x97\x18\x2b\x6a\x84\ -\x3e\x54\xcb\x06\xb7\x43\x8f\xde\xd0\xc6\xcc\x98\x68\x96\xc5\xe7\ -\x9f\x5f\x67\x79\x79\x19\xc3\xd0\x47\xdc\x73\x77\xd4\x73\x87\x9b\ -\x37\x6f\xf2\xf4\x53\x4f\xd1\x6a\x1e\x13\x15\xb2\x10\x87\x74\xdb\ -\xc7\x2c\xbc\xfa\x32\xee\xc0\x61\xed\xee\x5d\x96\x67\x27\xbe\x79\ -\x90\x13\x4c\x43\xa7\x0f\x4c\x4d\x4c\x72\xf8\xb7\xef\x13\x0c\x5d\ -\xb4\x20\x7d\xb8\x93\xa1\x87\x2c\xa5\x83\x9d\xc4\x0d\xa8\x4e\x4e\ -\xf1\xe1\xa7\xd7\x58\x3d\xfd\x6b\xe4\x74\xd8\x78\xfc\x98\x17\xae\ -\x5c\xa6\x37\x0c\x18\x9b\x9c\x60\x63\x63\x83\x24\x4c\x55\xa6\x96\ -\x65\x9d\x90\x35\x82\x20\xb5\x38\x98\x86\xcc\xc1\x41\x2a\x50\x7f\ -\xee\xb9\xe7\xd2\xf2\xc3\xe8\x6d\x5b\x2a\x59\x58\x96\x46\xaf\x97\ -\x26\xa5\x5e\x7c\xf1\x79\x86\x43\x97\xa9\xa9\x29\xbe\xfc\xf2\x06\ -\xba\xae\xf3\xec\xd3\x2b\x34\x3b\x1e\xfb\xfb\xfb\x94\x4a\x25\x0c\ -\x43\x64\x38\x6a\x32\xe9\xba\x8c\xef\xa7\x95\xc3\xbd\x3d\x9b\x5a\ -\xad\xc6\x44\x3d\xc7\x41\x63\xc0\xe5\xcb\x97\xa9\xe4\x55\xde\xf9\ -\xe9\x47\x14\x8b\x45\x8a\xc5\x02\xcd\x66\x93\x72\xb9\xcc\x60\x30\ -\x20\x9b\xcd\xa6\x85\x8a\xb2\xc5\xd0\xb5\x00\xd8\xdc\xdc\xa4\x50\ -\x28\x8c\xc0\x79\x69\xa6\x7b\x30\xf0\x52\xb0\x9b\xac\x93\x90\xd2\ -\x4d\x32\x19\x0b\xd7\xf5\x38\x7d\xfa\x34\xd9\xac\x46\xbb\x6d\xd3\ -\x68\x34\xf8\xf8\xe3\xcf\x78\xf4\xe8\x11\xa7\x4e\x9d\xe2\xf8\xb8\ -\x45\xad\x56\x42\x55\x53\xc0\xc0\x09\x3b\x39\x8e\x29\x15\xca\x28\ -\xa2\x8c\xa8\xa5\x41\x0e\xdf\x4f\xff\x5d\x94\xa1\x3e\x56\xe1\xc1\ -\xfa\x7d\x2e\x5c\x3c\xc3\xc0\xf5\xf8\x67\xdf\xff\xaf\xe8\xc6\xd0\ -\xb0\xe1\x2f\x7e\xf4\x21\x37\xbe\xfc\x1a\x4b\x4f\xc7\xf3\x4e\xbf\ -\x4f\xd0\x0b\xc8\xe9\x1a\x57\xce\x9f\xe5\x1f\xfc\xea\xf7\xa8\x98\ -\xf0\x78\xfd\x18\xd7\x0b\x70\x52\xca\x2d\x12\xe0\x46\xd0\x75\x23\ -\x1e\xae\xdf\x21\x56\xe0\xfe\xee\x01\xcd\x44\xe3\xd1\x7e\x93\xbd\ -\xf6\x80\x27\x87\x6d\x14\xdd\xa0\xd5\x3c\xa6\x73\x74\x44\xce\xcc\ -\x73\xf3\xeb\x7b\x9c\x3f\x35\x4f\x36\x07\xad\x41\x80\x29\x8b\x74\ -\x7a\x09\x92\x24\x70\xb4\xb3\x47\x56\x92\x58\x5e\x98\x60\x7f\xff\ -\x98\xda\x64\x99\x30\x89\xe9\x0c\x6d\xa4\x24\x46\x90\x15\xae\x5d\ -\xfb\x90\xfb\xeb\x1b\xc4\xb2\xc8\xcc\xea\x19\x5e\x7b\xed\x75\x14\ -\x11\x92\x10\x74\x15\x2c\x59\x63\xd0\xeb\x21\x25\x09\xbe\xe7\x11\ -\x61\xd1\xe9\x74\x11\xb5\x2a\xcd\xce\x80\x50\x94\xd9\x3b\x68\x70\ -\x6a\xf5\x0c\x48\x29\x49\xb7\x15\x41\xd7\x85\xf7\x3e\xba\xc6\x4f\ -\x7f\x76\x0d\x23\x53\x20\x08\x63\x18\xa4\x77\xfa\x24\xf0\x41\x56\ -\xc8\xe5\x0b\xb8\xc3\x21\x52\x0c\x4e\x7f\x88\x6d\x3b\x08\x42\x82\ -\xa1\x18\x28\xa2\x40\xe4\x39\xc8\xa2\x82\xaa\x4a\x48\x66\x06\x21\ -\x08\xb1\x9b\x6d\x46\xc4\x47\xa2\x28\x41\xb3\x72\xc8\x88\xd8\x41\ -\x88\x17\x86\x88\xa2\x4c\x26\x9b\xa1\x75\xb4\x4b\x10\x90\xea\x88\ -\x35\x9f\xde\xe1\x06\x6e\x12\x50\xcc\x59\x9c\x3b\xbd\x88\x2a\x81\ -\xa9\x42\xfb\x78\xc0\xd3\x97\x2e\xb2\xb1\xb1\xc1\xa9\xb3\x2b\xf8\ -\x8e\x9f\x52\x60\x27\x4b\x38\xfd\x88\x56\xa7\x4d\xa9\xa4\xe3\xf9\ -\xb0\xbf\x7f\x4c\xb7\xdb\xe5\x7b\xbf\xf2\x06\x1f\xfe\xe2\x33\xce\ -\xac\x9c\xa2\x79\x78\x84\x6d\xdb\xc8\x32\x24\x61\xaa\xf9\x7d\xe6\ -\xfc\x99\x74\x06\x10\x86\x21\xd2\x88\x47\x54\x2a\x16\x19\xda\x76\ -\x5a\xc6\x0e\x63\xe4\x44\x22\x30\xb3\xec\x3c\x7a\x84\x9e\xc9\x82\ -\x20\x92\x2d\x57\xf8\xe8\x8b\x2f\x29\x66\x4d\xfe\xd3\xdf\x78\x83\ -\x61\xe8\x13\x25\x09\xba\x99\x3a\x5d\x6b\x63\x75\x3e\xfe\xc5\x47\ -\x2c\x9f\x39\x8d\x66\x1a\x08\xb2\x44\x77\x60\x63\xe9\x06\xaa\x2a\ -\xe2\x79\x31\x95\x4a\x05\xdb\xb6\xf9\xe2\x8b\x2f\x78\xe9\xe5\x17\ -\x46\x4c\x33\x83\x4e\xc7\xc1\xb2\xd2\xa3\x42\x7a\xe4\x4e\x30\x8c\ -\x14\xf0\x6e\x9a\x26\x8d\x46\x83\xcf\xbe\xbc\xc7\xe2\xe2\x22\x0f\ -\x1e\x3c\xe0\xad\xb7\xde\x62\x30\x08\x4e\x70\x3e\x69\x99\x3f\xd5\ -\xac\x7e\xf5\xd5\x57\xbc\xf8\xe2\x8b\x27\x40\xf8\xe1\x70\x48\x92\ -\x4f\xdb\x22\xa5\x52\x89\x0f\x3f\xfc\x19\x4f\x9e\x3c\xe1\x95\x57\ -\x9e\x23\x8e\x19\xc9\xd9\x63\x5c\x47\x24\xf0\x3c\x44\x4d\x23\x0e\ -\x42\xaa\x13\xe3\x24\xa2\x80\x1b\x8c\xd8\x6b\x72\xda\x82\x09\x47\ -\xc3\xba\xb4\x78\x0e\x99\x8c\x36\x1a\x80\xa5\xc7\xfc\x85\x85\x39\ -\x66\x67\x67\x91\x65\x99\x5a\xad\xc6\xfd\xfb\xf7\x59\x5f\x4f\x69\ -\x26\xdf\xd8\x36\x14\x59\xc6\x6e\xf5\xc9\x28\x1a\x81\xeb\x21\x09\ -\x06\x82\x02\x71\x9c\x10\xfa\x3e\xfd\x50\x44\x8a\x52\x5f\x70\xbf\ -\x39\x60\x71\xb2\x48\x73\x08\x15\x2b\x65\x4f\xbf\xf1\xec\x15\x6e\ -\x5e\xbb\xc6\xec\xc2\x3c\x2f\x5e\x79\x8e\x8b\x2b\x33\x8c\x65\xd3\ -\x0f\x02\xa7\x9f\x50\xcf\x40\xb7\x0b\x5a\xd6\x42\x94\x65\x1e\x77\ -\x1c\x76\xf7\x1b\xd8\xb6\x43\xb3\x79\xcc\xbd\xfb\x77\x78\xf4\x78\ -\x0d\xa3\x98\xa1\x35\x70\xc9\xd7\xa7\xe8\x78\x31\x82\x9a\xa1\xe7\ -\xf8\x98\x66\x88\xae\x99\xd4\xa6\xa6\xe9\xec\x6c\x91\x88\x02\x95\ -\x02\x0c\xfb\x09\xf5\x9c\xc2\xd1\x51\x9f\xa9\x9a\x86\x04\x94\x97\ -\x16\xf8\xe8\xfd\x0f\x39\x3b\x3f\x43\xbd\x5a\x66\x63\x7b\x9b\x7b\ -\xeb\x6b\x48\xb2\x48\x46\xd5\x99\x29\x8f\xb1\x72\xf6\x02\xdf\x7a\ -\xee\x0a\x89\x92\x3e\x80\x9d\x81\x8b\x26\xea\x38\xb6\x4b\xe8\xb9\ -\x48\x9a\xc2\xc3\xcd\x47\x5c\x7d\xfe\x69\xf4\xd8\x20\x16\x60\x3a\ -\x57\x65\xe3\xa0\x87\x96\xcb\x51\xaf\x67\x78\xf4\x65\x9f\x9f\xdf\ -\xbc\x8b\xa4\xe9\x7c\xb5\xbe\x86\x56\xcb\x73\xd0\xee\x70\xf3\xf6\ -\x3a\x5d\x2f\xc0\xca\x17\x69\xec\x1e\x11\x74\x1d\xcc\xd9\x59\x86\ -\xbe\x87\x28\x89\x48\x92\x9c\xbe\x90\x84\x04\x64\x39\x55\x09\xe9\ -\x3a\x3d\xa7\x4f\xa6\x98\x25\x74\x3d\xe2\x20\xa2\xd7\x6d\x53\xce\ -\xe7\xe9\x0d\x06\xb8\xad\x63\xc8\x5a\xa0\xaa\x69\xcc\x35\x9f\xc7\ -\xb1\x5d\x04\x5d\x4d\x5f\x76\x9a\x89\xd3\xb3\x91\xf5\xd4\x0d\xe5\ -\x3a\x36\x7e\xb7\x07\x86\x84\x1f\xd8\xa0\x89\x88\x52\x48\x2e\x0f\ -\xf6\x20\xed\x1c\x28\xaa\x46\x12\x26\x6c\x6e\x6c\xa2\x48\x2a\x2f\ -\x3e\x7f\x35\x95\x32\x28\x2a\xf5\x7a\x9d\xfd\xfd\x2e\xf5\xb1\x3c\ -\x77\xee\xdc\xe1\xd5\x57\x5f\xa5\x3f\x70\x71\xbd\xb4\x35\x77\xed\ -\xa3\x8f\x39\xb5\xb4\xc8\xd6\xa3\x6d\x8e\x0f\x8e\x38\x7d\xfa\xf4\ -\xc9\xa6\x47\x16\x45\x91\x98\x94\xc8\x98\x62\x63\x8b\x88\xc9\x2e\ -\xe2\xc8\xd5\x93\xaf\xe6\xe8\xee\x1d\x90\x9f\x9c\xc1\x3d\x3e\xe2\ -\xb8\xdb\x43\xb1\x2c\xde\xf9\xe0\x7d\xbe\xf3\xe2\xb3\x94\xeb\x35\ -\x8e\x5a\xc7\x2c\x4c\x54\x10\x65\x89\xfa\xf8\x18\x95\x5a\x95\x9d\ -\xbd\x5d\x32\xa6\x85\x24\x49\x29\xbd\x30\x01\xdf\x8f\x11\x05\x61\ -\x84\xb7\xb5\xc8\x66\xb3\x34\x1a\x2d\x5a\xad\x16\x2b\x2b\x4b\xc8\ -\x72\x7a\xb4\xbf\x7f\xff\x3e\x8b\x8b\x8b\xf8\xbe\x4f\x1c\xc7\x34\ -\x1a\x36\x8b\xd3\x15\x64\x79\x9c\x76\xbb\xcd\x3b\xef\xbc\xc3\x6f\ -\xff\xd6\xaf\x11\x46\x30\x1c\x86\x69\x8b\x28\x88\xe9\x76\xed\x93\ -\xb2\x44\xda\x11\xd6\x90\x24\xe8\xf5\x42\xea\xf5\x02\xe1\xe8\x0d\ -\x6a\x59\x16\x95\x4a\x85\xc5\xc5\x45\x7e\xf2\xe3\x0f\xa9\x56\xab\ -\x29\x9e\x36\x97\x23\x9b\x35\x48\x12\x95\xc1\x60\x40\xb7\xdb\x65\ -\xf9\xcc\x29\x86\x43\x67\xd4\x68\x32\x4f\x86\x77\xbe\x1f\xb0\xb3\ -\x9f\xde\xdb\x86\x43\xff\xa4\x77\x9c\x92\x4e\x54\xa2\x28\xa1\xd7\ -\x4b\x11\xbf\xe3\xe3\xe3\xa9\xc7\xc7\x48\xef\xf7\x9d\x4e\x1a\x19\ -\xed\x34\x8f\x69\x1f\x36\x28\x56\xca\x48\x8a\x8e\x91\xcf\x62\x16\ -\x0a\x28\xba\x48\x26\xa7\xa3\x00\xc7\x07\x4d\xa4\x24\x66\xac\x94\ -\x49\xbb\xf0\x0a\xec\xed\x0f\x19\xab\x9a\x14\x67\x4d\x5e\x7d\xf9\ -\x2a\x13\xd3\x53\x3c\x73\x76\x26\xdd\xb3\xda\x20\x85\x60\x49\x02\ -\x49\x04\x7a\x06\x6e\x6f\x1d\xf0\xe5\x9d\x7b\xac\x3f\xde\xe1\xe0\ -\xb0\x89\x28\x69\x64\x32\xd9\x34\x05\x36\x3e\x8f\x2b\x89\x0c\x82\ -\x2e\x9e\x07\xb1\x64\x90\xc9\x14\x90\x45\x07\x41\x12\xe9\x74\x5a\ -\x64\x15\x11\xc3\xd0\xb9\x7e\xfd\x33\xde\x19\xaf\xf0\xfa\xd5\x2b\ -\x1c\x1c\xf4\x99\x1a\xcb\xb2\xd7\x74\x91\x45\x89\x3b\x9f\x7e\xce\ -\xee\xc3\x75\xee\x55\x8a\x3c\xd8\x79\xc4\xb7\x5e\x7b\x89\x57\xdf\ -\x78\x9d\x30\x0a\x89\xfd\x00\x3d\x10\x69\x36\xfb\x7c\xf9\xd5\x7d\ -\x8a\xe3\xe3\x24\x96\x81\x6c\xe8\x44\x31\x14\xea\x3a\x51\xa8\x93\ -\x51\xe0\xe6\x7d\x17\x3b\x01\x37\x08\x71\x5c\x97\x5d\x49\x84\x8c\ -\x85\x66\xc2\x56\x3f\x66\xe1\xe9\x65\xfe\xf1\xdb\xff\x9c\xbd\xfd\ -\x06\x46\x29\x4f\x5f\x70\x71\xe3\x18\x67\x18\x33\x35\xb5\xc4\xc1\ -\x61\x97\xfc\xd4\x34\xdd\x9e\x03\xb1\x80\x61\x58\xf8\x91\x4f\xb7\ -\xdb\x47\x88\x23\x54\x51\x42\xcf\xe6\x71\xbb\x03\x62\x49\x20\x51\ -\x45\xfa\xb1\x4f\x92\x84\x94\x8b\x79\x7c\xd7\xa3\x3b\xe8\xe2\xd9\ -\x36\x6a\x2e\x43\xa2\xab\x28\x86\xce\xd0\x75\x52\xb5\x2c\x2e\x92\ -\x96\x92\x32\x25\xc5\x4c\xc5\xe9\x86\x4e\xdf\x0d\x88\x7d\x1f\xfc\ -\x21\x5a\x46\xc7\x69\x1c\x50\x9e\x9e\x65\x72\xa6\x8e\x0c\x0c\xbd\ -\x21\xe5\x72\x96\xa1\xed\x31\xec\x0f\x08\xbc\x90\x73\xe7\x2e\xa0\ -\xca\xa4\x59\x0d\x4d\x65\x65\x65\x85\xcf\x3e\xb9\xc6\xe2\xd2\x12\ -\x85\x42\x81\x6a\x46\xe1\xd1\x61\x6f\xd4\xde\xdb\x67\x7c\x7c\x9c\ -\x5a\xa1\x80\xef\xfb\x6c\x6f\x6f\xa3\x4a\x42\x9a\x0e\x04\xa4\xef\ -\x7f\xff\x6d\xc2\x24\x22\x11\x24\x7c\x41\x78\xfb\xf6\x83\x2d\xd6\ -\xb6\x76\x08\x44\x0d\x3b\x04\xb3\x50\xc6\x11\x04\x24\x59\xc6\x0b\ -\x3d\xe2\x38\xa0\x54\xcc\xe2\x7b\x0e\x04\x1e\xcf\xac\xae\x50\xcc\ -\x5a\x74\x07\x2e\x53\x45\x8b\xed\xc3\x26\xa7\x4e\x9d\xe2\xc6\xcd\ -\x9b\xa3\xb7\x4e\x4a\xbf\x8c\x82\x14\x4b\xaa\x2a\x32\x0f\x1e\x3c\ -\xa0\x50\x28\x70\xfe\xcc\x2c\x3b\xfb\x0d\x3a\x9d\x0e\xb2\xac\x51\ -\x28\x18\x1c\x1d\xb5\x78\xf2\xe4\x09\x73\x73\x73\xe8\xba\x86\x65\ -\x29\xe8\xba\x89\xed\xa6\x52\xe9\xf1\x6a\x86\xc7\x4f\x0e\xd8\xd9\ -\x3d\xe4\xf0\xb0\x39\xba\xfc\x8b\xa8\xaa\x40\x10\xa4\x93\xef\xfd\ -\xfd\x43\x14\x45\x21\x9b\xcd\xd1\xed\x0e\xc8\xe5\x32\x04\x41\xc2\ -\xf1\x71\x8f\x5a\xad\x40\x10\xc4\xdc\xbf\x7f\x9f\xa7\x9f\x3e\xc7\ -\xf8\xf8\x14\xa6\xa6\xb3\xbf\xb7\x87\x1f\xf8\x48\x52\xba\x1e\xeb\ -\xf7\xfb\xe9\x84\x7b\x6a\x0c\x51\x94\x11\x65\x09\x55\x4b\x25\xd6\ -\xba\x2e\x10\x44\xf0\x68\x73\x93\xd5\xd5\x15\x02\xcf\xff\xff\x09\ -\xaf\x2d\x4b\x02\x04\x82\x20\xbd\x22\xcc\xcd\xcd\x92\xc9\xe8\x14\ -\x2c\x19\x51\x51\xc9\x64\x52\x34\x6e\x3e\x9b\xc3\xeb\x0e\x58\x9e\ -\x5f\x44\xd1\x74\x3a\xdd\x0e\xbb\x7b\xfb\x6c\x6e\x6e\xf2\xe8\xe1\ -\x16\xf7\xef\xad\x21\x45\x01\xbb\xdb\xdb\xd8\x9d\x1e\x9a\x62\x91\ -\x84\x30\x53\x37\xf1\x7d\xd8\x3d\x74\xf8\x3f\xfe\xdf\x7f\x8d\xa4\ -\x4b\x9c\x5d\x3a\x43\x59\x4d\x37\x4e\x19\x23\x25\x36\xef\x1d\xdb\ -\xfc\xab\x3f\xfb\x21\x7f\xfb\xc9\x47\x7c\xf1\xe8\x11\x03\x45\x42\ -\x2a\x96\xb0\x25\x99\x3e\x02\x91\x95\xa7\x1d\xa9\x34\x03\x89\xd0\ -\x8b\xf0\x24\x8d\x50\x94\x11\x65\x91\xc0\x1d\x62\x28\x10\xf6\x3b\ -\xcc\xd4\x4a\x1c\xef\x6c\xd1\xd8\x79\xcc\xdc\xc4\x04\x44\x31\xdd\ -\x76\x97\x07\x1b\x5b\x6c\x3f\x7a\x84\x1a\x85\x3c\x7f\xe9\x12\xde\ -\xa0\xcf\x95\x2b\x4f\x73\x6a\xf5\x0c\x83\xd8\xa5\xeb\x0d\x11\x14\ -\x15\x41\x50\xc8\x9b\x1a\xaa\x96\xc3\xf1\x62\x26\x17\xaa\x78\xb2\ -\x44\x24\xc3\xfa\xd6\x01\xd9\x72\x06\x5f\x04\x47\x80\x9b\x6b\x6b\ -\xd4\x67\x67\x49\x74\x19\xc5\x52\x31\x75\x85\x27\xae\x8b\xa3\x2a\ -\x68\x9a\xc0\xff\xf9\xe7\xef\x72\x63\xfd\x21\x7a\xb9\x42\x2f\x89\ -\x50\xf2\x16\x82\xa2\x31\x1c\xa6\xb3\x15\x04\x95\x8b\x17\x2f\xe3\ -\x47\x69\xda\x2d\x19\xcd\x04\xc2\xc0\x43\x55\x35\x82\x20\xc2\x34\ -\x0c\xbc\x4e\x0f\xb5\x90\x25\xca\xc8\x04\xbe\x4d\x1c\x45\x24\xb2\ -\x4c\x9c\xc4\x78\x76\x1f\x84\x04\x25\x9f\x41\x50\x45\x44\x5d\x26\ -\x10\x63\x82\xc4\x47\xd1\x15\x90\x12\xe2\x28\x00\x51\x40\x17\x14\ -\x42\x27\x20\x0e\x82\x94\x5c\xa2\xcb\xa8\x12\xf8\xbd\x23\xbe\xfd\ -\xea\x0b\x7c\xfb\xf9\xcb\x44\x61\x44\x35\xab\xd3\xeb\xf4\x31\x35\ -\x9d\x2f\x3f\xfd\x82\x73\xab\xe7\x99\x1c\x2f\x72\x78\x90\x52\x63\ -\x4a\x19\x99\x76\x77\xc8\xa0\x9f\xe6\x0e\x5e\x7d\xf5\x05\x1a\xdd\ -\x21\xd9\x5c\x96\x27\xbb\x3b\xb4\x9b\x0d\xce\x9d\x5d\xc5\x77\x3d\ -\x8e\x1b\x4d\x2c\x4d\xe3\xee\xd7\xb7\x79\xfd\xdb\xaf\x2c\x2a\x8a\ -\xdc\x96\x49\x20\xf1\x43\x22\x4d\xc1\x10\x79\x43\xd5\xb5\x9f\x18\ -\x86\xce\x4e\xbf\x87\x68\x14\x10\x92\x04\x51\x90\xe9\xdd\x5d\xc3\ -\x58\x9c\xc5\xd2\x05\x76\x8f\x76\x99\x9b\x9a\xe4\x93\x5b\xb7\xf9\ -\xbd\x5f\xff\x55\xfa\x5e\x4c\xb9\xa4\xb1\x37\x8c\x99\x99\xac\x71\ -\x74\xd8\x66\xb2\x52\x47\x4a\x62\x02\xcf\xa1\xd3\x49\x52\x9e\xb4\ -\xac\xa5\x20\x7a\x41\x60\x7a\x7a\x8a\x27\x07\x5d\x66\x67\x67\x58\ -\x58\x98\xe1\xfa\xf5\x9b\x24\x49\x92\xa6\xa9\x4e\x9f\xc6\x34\x53\ -\xa0\xfd\xd6\xd6\x3e\xa7\x16\xc6\x39\x68\xa6\xfc\x2d\x5b\x54\x89\ -\xa2\x88\x2b\x57\xae\xd0\xe9\x74\xb8\x76\xed\x1a\x96\x65\xb1\xb2\ -\xb2\x42\xb1\xa8\xe3\x38\x70\xeb\xd6\x2d\xce\x9f\x3f\x8f\x61\x28\ -\x18\x46\x1e\xd7\x4d\x29\x10\xf5\x7a\x9e\x5e\xcf\x47\x14\xc5\xd1\ -\xbd\xdc\x49\x91\x44\xd5\x3c\x49\x32\x4d\x10\x47\x6c\x6d\x6d\xe1\ -\x38\x0e\xd9\x5c\x8e\xb3\x67\xcf\xd2\x68\xb4\xd3\xb7\xa9\xae\xa4\ -\x32\x81\xa1\x8b\x28\xea\x24\x49\xfa\xc1\xa4\xab\xd0\xeb\x7c\x13\ -\x34\x49\xb9\x5b\x8a\x92\xc7\xf7\x03\x82\x20\xa4\x54\x2a\x13\x26\ -\xd0\x6d\xf5\xe9\xaa\x32\x71\x10\x52\x28\x67\xd1\x34\x05\x21\x4a\ -\x11\x34\xe3\xe3\x63\x44\x2a\x58\xc3\x2c\x76\xe0\x21\x2a\x32\x19\ -\xd3\x40\x4c\x42\x7a\x8d\x06\xde\xd0\x61\x71\x79\x85\xdb\x77\xd7\ -\x90\xcc\x3c\xdb\x9f\x34\x10\xf5\x2c\x1f\xdd\xb9\xcd\x41\xbb\xcb\ -\xce\x5f\xfd\x2d\x1f\xfd\xe2\x73\xd4\x20\xa1\xa0\xeb\x5c\xbe\xf4\ -\x34\x92\xac\x72\xeb\xde\x1d\x6e\xaf\xdd\x85\x9c\x05\x9a\xce\xf0\ -\xb8\x0b\x8a\x07\xc8\x10\x49\xf4\xed\x08\x44\x15\xbc\x10\xd0\x41\ -\xd4\x88\xfd\x90\xee\x61\x03\xec\x1e\x52\xb9\x80\xdd\xef\xb1\xb1\ -\xd6\x66\xa6\x5a\x61\xb2\x98\xe3\x37\xff\xc1\xaf\x93\x33\x20\xb4\ -\xa1\x98\x49\x0d\x29\x81\x3d\x04\x15\x9c\x28\xc0\x89\x02\x34\xd3\ -\xc0\x8c\xd3\xa6\x93\x2c\x49\x74\xbb\x0e\x4d\x1b\x02\x14\x0e\x06\ -\x2e\x71\x23\xe6\xaf\x7e\xf6\x33\x3e\xff\xea\x2b\x86\xde\x90\xe7\ -\x9f\x7f\x1e\x4d\x57\xd0\x34\x85\xb5\xed\x43\xc4\xaf\x1f\xd0\xee\ -\x76\x70\x7c\x9f\x5b\x5f\xdf\x46\xcf\xe4\xe9\x0e\x5c\x0e\x8e\x9b\ -\x64\x8a\x15\xda\x4e\xc0\x50\x89\xf0\x13\x48\x0e\x3b\xcc\x9f\x3d\ -\xcb\xc2\xe2\x05\x1e\xdd\x7b\x44\x3d\x5f\xe5\x78\xe7\x31\x47\xeb\ -\xeb\xcc\xae\x9c\xe6\x49\xf3\x10\x3d\x97\x01\x53\x26\x93\xb1\xe8\ -\x34\x5b\x08\x42\x3a\x00\x33\x64\x93\xb6\xd3\x07\x33\x8b\xa0\x25\ -\xd8\x9b\x8f\x21\x9b\x47\xaf\x57\x90\x65\x99\xc1\xee\x13\x28\x96\ -\x90\xc4\x18\x49\x14\x88\x9c\x21\xe6\xd8\x18\x76\xaf\x0f\x0a\x04\ -\xc3\x3e\x91\x18\x23\x44\xa0\x68\x32\x6e\xbf\x47\xb1\x94\xc1\x54\ -\x44\x3c\x4d\x63\xb2\x56\x25\xf4\x03\xca\x96\x42\xb3\xd5\x65\xb6\ -\x94\xe7\xdd\x9f\x7e\xc8\xc5\x0b\x17\x90\x13\x81\xd6\xd1\x00\xd3\ -\x30\x30\x4d\x95\xe3\x41\xca\xdd\x56\x35\x8d\xc5\xe5\x25\x7a\x7d\ -\x8f\x6c\xd6\xa4\xd5\xe9\xe1\x0c\x6c\x2a\xa5\x32\xde\xd0\xa1\x58\ -\x28\xf0\xe7\x7f\xfa\x03\xfe\xe0\x1f\xfe\x43\xee\xdd\xba\x85\xa5\ -\xa9\x8f\x04\x40\x7a\xfb\x9f\xfc\x21\xe2\xe8\x92\xd8\x87\x87\xa5\ -\x99\x39\xfe\xfd\x8f\x7f\xc2\x50\x14\xf1\x25\x19\x2b\x5f\x41\x94\ -\x55\xbc\x18\x72\xd5\x2a\xae\xe7\xa0\x59\x26\x41\x12\xb3\xf7\x70\ -\x8b\xbf\x7c\xef\x13\xbe\x75\xf5\x55\x32\x59\x01\x6f\x20\x90\xd7\ -\xc0\x3d\xb6\x51\xe2\x98\xa9\x7a\x8d\x7b\x6b\x77\x31\xb3\x19\x34\ -\xcb\xc4\xf5\x42\x76\xf7\xf6\x28\x96\x4a\x68\xb2\x86\xa9\x1b\x08\ -\x62\x3a\xf4\x31\x4d\x8b\x5e\xaf\xc7\xfd\xfb\xf7\xb9\x70\xe1\x42\ -\x4a\x65\x11\x84\x94\xcd\x35\x02\xd3\x1b\x86\xce\x8d\x1b\x37\x99\ -\x9e\x9e\x66\x6e\xbc\x80\xa4\x19\x14\x0a\x69\x80\xe4\xfe\xfd\xfb\ -\xe4\x72\x25\x74\x5d\xc1\xb6\x53\x2d\x6b\x3e\x9f\x21\x8e\x21\x0c\ -\xa3\x91\xe1\x51\x41\xd3\x24\xee\xde\x4d\x29\x9c\x96\x65\x51\x2c\ -\x9a\x69\x52\x2c\x49\x28\x95\x0b\x54\xaa\x35\x4a\xe5\x32\xef\xbe\ -\xfb\x6e\xda\xc4\x1a\x61\x5d\x0c\xdd\x40\x10\x21\x0e\x22\xba\xdd\ -\x3e\xce\xd0\xa1\x5a\x4a\x7d\xcc\x59\xcb\x42\x91\x05\x92\x24\xdd\ -\x21\x3b\x8e\x87\xa4\xa8\x7c\x75\xfb\x0e\xa7\xcf\xac\xa0\xea\x22\ -\x92\xa4\x8d\xde\xe8\x12\xb6\xe3\x22\x8a\x0a\x82\x90\xb0\xfb\x64\ -\x97\xa9\x99\x69\xfc\x38\x42\x36\x14\xb4\xac\xc6\x70\xd8\x47\x53\ -\x45\x44\x20\x09\x13\xba\x5d\x87\x42\x75\x8c\xf1\x85\x39\xc4\x4a\ -\x85\xea\x99\x59\xee\xb5\x86\xfc\x62\xed\x01\x62\xb6\xc4\x50\xd0\ -\x51\x0b\x63\x04\x7a\x8e\x30\x57\xe5\x7e\x73\xc0\x46\xbb\xc7\x40\ -\x31\x91\x2a\x75\x7c\xd9\x04\x2b\x87\x56\xac\x22\x98\xf9\xff\x8f\ -\xaf\xf7\x8a\xb5\x2c\x3b\xef\xfc\x7e\x6b\xed\xbc\xf7\xc9\xe7\xdc\ -\x54\xb7\x72\xea\xea\xea\xea\x6e\xb2\x9b\x6c\x76\x71\x9a\x41\x0c\ -\x22\x15\x28\xd9\x23\x0f\x04\x18\xf0\xc0\x01\x18\x07\xc0\xb0\xdf\ -\xfc\x20\x4b\x6a\x3e\x8d\xf5\x64\xc0\x30\xe0\x34\xb6\x07\xd2\xcc\ -\x40\x23\x59\x33\x12\x49\x89\x94\xd9\x0c\x92\xd8\x64\x07\x56\x75\ -\xa8\x9c\x6e\x55\xdd\x9c\x4f\xdc\x67\xc7\xb5\x97\x1f\xd6\xa9\xcb\ -\xd1\x8b\x6f\x61\xe3\x5e\x54\xdd\x54\xe7\x9c\xb5\xd7\xb7\xbe\xef\ -\xff\xff\xfd\xd1\x41\x1d\xd9\xec\x80\x1f\x21\x6d\x17\xb7\x5e\x47\ -\xc5\x53\x82\x4e\x17\x29\x2c\xdc\x20\xa0\xd6\x6c\xe3\x48\x8b\xa5\ -\xf9\x05\xd2\xe9\x94\xd0\xf7\xf9\xad\x7f\xf8\xef\xd1\x69\xb5\xe8\ -\xd4\x24\xd2\x86\xb4\x80\xca\x05\xed\x3b\xc4\x15\x54\xbe\x4d\x3f\ -\x1e\x53\xab\xd7\x68\xf8\x01\x79\x7f\x82\xaf\x1c\x5c\x65\x11\xfa\ -\x36\x7b\x93\x8a\x9d\x5c\xf1\xcf\xbf\xf3\x5d\x7e\x78\xeb\x0e\xb1\ -\x17\x92\x38\x35\x6e\xaf\xef\xf2\x60\x63\x9f\x9b\x4f\xb6\xd9\x18\ -\xa4\xbc\xf5\xb3\x0f\xd9\x8b\x35\x37\x1e\x6e\x12\x2b\x8f\x7e\x0a\ -\x71\x21\x19\xa7\x30\x18\x26\xa0\x2c\x54\xae\x99\x3b\x73\x81\xa9\ -\x92\xc4\x85\xe6\x37\xbe\xf4\x35\xd2\xdd\x7d\xa2\x3c\xe5\xb3\x97\ -\x2f\xd2\x89\x2c\x8e\x2f\xd5\xd9\x1f\x6d\x31\x9c\xec\x22\x23\x07\ -\x61\x0b\xd2\xd1\x94\x5a\xd0\x00\xe5\x30\xed\x8f\x71\x1d\x07\x75\ -\x70\x08\x79\x01\xdd\x1e\x38\x0e\xa5\x84\x5c\x29\x83\xce\x71\x7c\ -\xea\x41\x84\x4a\x0b\x5c\xc7\x27\x9d\xe6\xa8\xb4\xc0\xaa\x35\x4d\ -\xa0\x5b\x51\x80\x63\x53\x56\x25\x67\x4e\x2e\xb3\xb3\xfa\x98\x9e\ -\xef\x51\x17\x9a\x9a\x86\x2f\x7f\xfa\x05\xc6\xe3\x82\x9a\xeb\x71\ -\xed\xe7\x1f\xf1\xdc\xc5\x8b\x9c\x3c\x7e\x9c\x6b\xd7\x7f\xce\xf3\ -\x97\x2e\x92\x67\x19\xad\x9a\xc3\xe6\xce\x21\xfd\xe1\x80\xbf\x7b\ -\xfb\xa7\xfc\xfa\xaf\x7f\x89\x4c\x19\x0c\x73\xbb\x15\xf1\xe0\xfe\ -\x0a\x2f\xbd\xf0\x22\xcb\x8b\x1d\x92\x71\xc2\xe8\xb0\xcf\xd2\xc2\ -\x02\xcf\x9d\x3b\x4b\xbb\x5e\xff\xa6\xd4\x25\x12\x04\x72\x56\x7e\ -\xf8\xf0\x55\x3f\xf4\xa8\x50\xf4\x7a\x5d\xb4\x56\x64\x49\x8c\x1f\ -\xb8\xa0\x35\xc3\xe1\x90\xac\x54\x64\xaa\x22\xc3\xc6\x39\x76\x82\ -\xc2\xa9\xf1\x4f\xff\xa7\xff\x85\x71\x01\xb6\x6f\xf4\xfa\x6b\x2b\ -\x4f\x68\xd5\xea\xd4\x3c\x8f\xaf\xbe\xf1\x19\xee\xdc\xba\xc5\x60\ -\x30\xc6\x8f\x6c\xca\x4a\xd3\xee\xf4\x8e\xc0\x75\x61\x00\xbb\xbb\ -\x07\x84\x61\xc8\x95\xe7\x4e\x9a\xc4\xc1\x7e\x1f\x21\x8c\x7b\xe9\ -\xf0\x70\x4c\x10\x38\x06\x42\xef\x98\xd2\xb5\xdd\x6e\x33\xca\x8c\ -\x1d\x32\x4d\x53\x4e\x9d\x5a\xe6\xea\xd5\xd7\x79\xff\xfd\xf7\xf9\ -\xde\xf7\xbe\x7f\xf4\x39\xd3\x69\x31\xb3\x42\x3a\x2c\x77\x02\x92\ -\x24\x65\x38\x8c\x89\xe3\x98\x4e\xa7\x83\xef\xbb\xf4\xfb\x53\x82\ -\xc0\xa1\x37\x57\x23\xcf\x15\xfb\xfb\xfb\xec\xed\x19\xe4\xd0\x2f\ -\xfd\xd2\x1b\xb4\x5a\x2d\xd6\xd7\xd7\xb9\x76\xed\x3a\x07\xbb\x87\ -\x44\x91\x47\xb3\x56\x67\x70\x60\xe4\xa7\xae\xed\x30\x4d\x26\xec\ -\xed\x0d\xd8\xdb\xdb\x65\x32\x49\x0d\x54\x30\x82\x30\xac\xb1\xbf\ -\x7f\xc8\xf6\xb6\x11\x87\x80\x99\x9d\x1f\x6f\x1b\x20\x7e\xad\xe6\ -\x50\x49\xc1\x38\x49\x48\xf2\x8c\x52\x97\x68\xad\x70\x1c\xa3\x45\ -\x17\x96\xcd\xe6\xee\x1e\x76\x58\x23\xe8\xf8\xe4\x3e\xc4\x36\x3c\ -\x3a\x84\xef\xbd\xfb\x3e\x1b\x71\x42\x2e\x3d\x90\x3e\xb9\x15\x32\ -\x75\x6a\x8c\xed\x88\x91\x63\xae\xb1\xe5\x93\xc9\x00\xa4\x0f\xb8\ -\x68\x5c\x34\x16\x60\xcf\xde\x0b\x10\x1a\x89\x32\xe9\x81\x95\xa2\ -\x92\x02\x8d\xa4\x10\x92\x42\xda\xec\x8d\xa7\x74\x8e\x9f\x22\x77\ -\x7d\xfe\xf8\xdb\xdf\xe5\x5f\x7d\xfb\x3b\x3c\x1e\x69\xb4\x0d\x7b\ -\x85\x62\x27\x83\xad\xa9\x62\xe2\x43\xd5\x6c\xb3\x11\x8f\xd9\x1a\ -\x8e\x98\xe6\x8a\xa5\x5e\x83\xba\x2f\xf1\x6c\x0b\x05\x54\x96\xc3\ -\x8f\xdf\x7b\x8f\xc7\xbb\xfb\x38\xed\x2e\x2a\xaa\x91\x39\x11\xa9\ -\x1d\x12\xdb\x21\xb1\x0c\x98\xe0\xa3\x45\xc0\xa8\xb4\x99\x6a\xb3\ -\x88\xf7\x47\x39\x07\x93\x92\x12\x8f\xa0\xbd\x80\xdb\x5b\x82\x20\ -\x62\x34\x4d\x01\x1b\xcb\x0a\xf8\xe7\x7f\xf8\xaf\xa8\xd5\x6a\x7c\ -\xe3\x57\xbe\x46\xcb\x77\xf8\xc6\x57\x3e\xc7\x6f\x7d\xed\x97\x78\ -\xe9\xcc\x32\xe7\x96\x0d\x14\x20\x3e\xdc\xa3\xd1\x88\xc8\xa6\x31\ -\x45\x99\xa1\xb2\x29\x3a\xc9\x67\x1d\x22\x0b\x94\x9e\xa1\x4f\x1d\ -\x90\x16\xd8\x2e\x94\x8a\x2a\x57\x58\xa5\xc0\x15\x0e\x81\xed\x23\ -\x2c\x17\x95\x97\x30\x4d\xcc\x28\xcb\x92\x74\xbb\x6d\x9e\x3e\x7e\ -\xc4\x89\x85\x39\x48\x53\xbe\x74\xf5\xb3\xbc\xf2\xc2\x15\x6c\xc0\ -\xaa\x60\xe5\xc1\x0a\xcb\xcb\xcb\x34\x9b\x6d\xfa\x83\x01\x51\x14\ -\x91\xe7\x05\x69\x9a\x32\xcd\x60\x71\xb1\x47\x92\xa6\xfc\xca\xaf\ -\xfd\x2a\x3f\x7a\xfb\x3a\x69\x91\x23\x1d\x87\x9d\x9d\x01\x4f\x9f\ -\xae\x11\x06\x01\xfd\x83\x09\xa8\x8a\x5e\xa7\x8b\x63\x59\x26\x73\ -\x4b\x82\x44\x60\x23\x30\x74\x40\x6d\x9e\xd7\xc0\x81\x9a\x1f\xa0\ -\x3d\x9f\x2a\x1f\x32\x1c\x0c\x98\x8b\x9a\x86\x6d\x94\xe7\x84\x0d\ -\x1f\x21\x0b\xb3\x5b\x29\x45\xe4\x07\xc4\x69\x42\x56\xc0\x62\x08\ -\x4f\xd6\x63\x0a\x2a\x1a\xad\x16\x93\x24\x65\x90\xc1\x6b\xaf\xbd\ -\xc6\x9d\x47\x8f\x68\x75\xae\xb0\xb6\xf6\x94\xa5\x85\x79\x9a\xad\ -\x06\x79\xaa\xd9\xdd\x9b\xb0\xb8\xd8\x25\xcb\x2a\x7e\xfc\xf6\x75\ -\xae\x5e\xbd\xca\xe6\xe6\x26\x3b\x3b\x3b\x5c\xba\x74\x89\xc5\x79\ -\x93\x4a\x71\x78\x38\x9a\xb1\xa3\x85\x11\x96\xe7\x46\x52\xd9\x0d\ -\x05\x9b\x7d\x13\x65\x7a\xf5\xea\x55\xde\x7e\xfb\x6d\xb2\x2c\xa3\ -\xdb\x74\x19\x4c\x14\xbd\x5e\xc4\xd3\xa7\xbb\xc4\x8d\x06\x07\x07\ -\x07\x47\x3b\xb1\xe7\xb9\x4c\xa7\x29\xb5\x5a\xc8\x70\x18\x23\xa5\ -\xc4\xf7\x7d\xce\x9e\xe8\xf1\xe0\xc9\x0e\xbd\x5e\x8f\x3c\x37\xe1\ -\xea\x73\x73\x73\xf4\xfb\x7d\xb6\xb6\xb6\xb8\x7d\xfb\xf6\x51\xd3\ -\xea\x95\x57\x3f\x61\x7c\xc5\xf5\x3a\x61\x4b\x90\x63\x9e\xdb\xb2\ -\x54\x0c\xfb\x15\x83\xc3\x7d\x3e\xf1\xe2\x73\xd8\x9e\x09\x27\x2c\ -\x4a\x58\x9c\x9b\xe7\x60\xaa\xf1\x1d\x97\x0f\x3f\xba\xcf\xf2\x89\ -\x13\xf8\x61\x40\xa1\x8d\x8f\xb8\x2c\x2b\x84\xb0\xa8\x94\x60\x14\ -\x67\x3c\xde\xda\xe5\x6b\xbf\xfc\x39\x56\xfb\xf0\x67\xdf\xfb\x01\ -\x3f\xba\x7e\x83\xa1\x86\xfd\x24\xe1\xf4\x73\xcf\x73\x78\x78\x08\ -\x1a\xa4\x10\x88\x0a\x84\xd6\x30\xd3\xb3\x6b\xa9\x8f\x52\x41\xc1\ -\x24\x63\x8a\xd9\x7b\x34\x26\x91\x50\x18\xd3\x0c\xae\x26\x23\x05\ -\xc7\xa6\x42\x40\xa5\xb1\x5d\x07\x2f\x70\x59\x1b\xf5\x51\x93\x18\ -\x8a\x84\xfd\x9b\xf7\x79\xf7\xc1\xff\xc8\xe9\xe3\xc7\x38\x73\xea\ -\x34\x93\xc1\x90\x9d\x8d\x75\x7a\xdd\x26\xc7\x7a\x5d\x5a\xa1\xc3\ -\x4b\x9f\x7c\x89\x49\x0e\x07\xfb\x31\xa1\x13\x90\x67\x15\x56\x64\ -\x13\xb4\x61\x61\x79\x89\xfc\xe1\x7d\x72\x59\x31\x3c\xd8\xa7\x7d\ -\xec\x94\x19\x13\x01\x95\x52\xe4\xa5\x69\xfd\x0f\x46\x23\x74\x9e\ -\xe3\x84\x21\x7a\x06\x87\x97\x52\x1a\xf4\xab\x65\x91\x4f\x63\xb2\ -\xf1\x04\xa7\xdb\x26\xdd\xda\xa2\x33\xd7\xe5\xda\xed\x5b\x9c\x5c\ -\x9a\xe3\x37\xbf\xfc\x02\xbb\xeb\x29\x2a\x57\xfc\xe3\x5f\xff\x2d\ -\xfe\xb7\x3f\xfa\x23\xfa\x87\x7b\xd4\x1b\x2d\x02\xdf\x65\x6b\xd4\ -\xc7\x6b\x05\x14\xe3\x98\xbc\xb0\xf1\x6b\x11\xca\x12\x14\xaa\x44\ -\x58\x16\x42\x4b\x03\x1d\x70\x7c\x98\xa6\x94\x45\x65\x32\xa0\xb0\ -\x28\x0b\x85\xce\x4b\xb0\x84\xc9\xb2\x6a\xb6\xa0\x28\xc8\xd2\x29\ -\x17\xce\x9f\xe3\xde\x7b\x3f\xe5\xd7\xbe\xfc\x45\xbe\xfe\x95\xcf\ -\xb1\xf7\x64\x95\xb5\xa7\xfb\xf8\x54\xe4\x69\xc2\xd2\xfc\x05\x83\ -\xd0\xb6\x1d\x1a\xcd\xb6\xa1\x7f\x3a\x0e\x65\xa9\x78\xef\xda\x75\ -\xce\x9d\x3f\x4f\x51\x94\x84\x61\x38\x23\xcc\x0a\x1e\xde\xdb\x22\ -\xf4\x7c\xc3\xbf\xd3\x2e\xd7\xae\x5f\x27\x8a\x22\x1e\x3d\x7a\xc4\ -\xe5\xf3\x67\x8d\x12\x4c\x08\xac\x37\x7f\xef\xf7\x11\x52\xa0\xb0\ -\xc8\x24\xff\x24\x87\x37\x3e\xbc\xb7\xc2\xe3\x8d\x1d\x26\x59\x89\ -\xe3\xd7\x90\x8e\x4b\x16\x4f\x21\xf0\x70\x5c\x1b\xdb\xb6\x48\xb3\ -\x29\x7a\x12\x73\xf1\xd2\x0b\x6c\x3e\x79\xca\x4f\x7f\xf4\x53\x5c\ -\x19\xd2\xf0\x1c\x44\x55\x72\xfe\xcc\x31\x82\xc8\x61\x9a\x17\x20\ -\x2d\xc2\x7a\x9d\x77\xde\xbd\x46\x3d\xaa\x71\xf1\xc2\x19\x44\x05\ -\x79\x51\x52\xab\x07\x24\x89\x71\x0a\x39\x8e\x43\xbf\xdf\xe7\xd4\ -\xa9\x53\xcc\xcf\xcf\xf3\xf4\xe9\x53\xa4\x65\xc6\x3a\xbe\x6f\x24\ -\x9d\x9d\x4e\x87\x56\xab\x81\x52\x95\x31\x58\x8c\x12\x94\x52\x74\ -\xbb\x21\xae\x6b\x71\x78\x38\xe2\xe2\xc5\x8b\xfc\xe9\x9f\xfd\x05\ -\x87\x87\x87\x2c\x2e\x1e\xc7\xf3\x3c\x96\x5a\x1e\x73\x9d\x06\xeb\ -\x5b\xfb\x33\xa5\x97\x71\x19\x19\x95\x95\xe9\x44\x17\x45\x41\x59\ -\x59\xdc\xb9\x73\x87\xf9\xf9\x79\x1a\x0d\xc3\x0c\xf3\x7d\x89\x94\ -\x0e\xf5\x7a\x9d\xe3\xc7\x8f\xd3\xeb\xf5\xb8\x7b\xf7\x2e\xdb\xdb\ -\x5b\xec\xef\xed\x72\x78\xd0\xa7\xd4\xc6\x67\x9d\x65\x39\xb6\xed\ -\xa0\x94\x99\x67\xb7\x5b\x73\x38\xb6\x24\x4b\xd4\x2c\xed\xd1\x65\ -\x32\x99\xd2\x6e\x47\x3c\x7c\xf8\x98\xb3\x67\xcf\xe1\x7a\x16\x1a\ -\x01\x02\xca\x5c\x21\x30\x19\xc5\x93\xb4\x64\x65\x63\x8b\xb9\x33\ -\x27\xf9\x83\xff\xf9\xff\xe6\xa3\x95\xc7\x94\x61\x1d\xaf\xd5\x25\ -\xec\xcc\xb1\x76\xff\x11\x4e\x18\x1a\x31\x4c\x54\xa3\xac\x0c\x93\ -\x59\x55\x1a\x21\x40\x54\x15\x52\x6b\xd4\x2c\x1a\xd5\xb5\x5d\x40\ -\x50\x21\x91\xc2\x42\xa3\x41\x17\x48\xcb\x64\xf8\x52\x55\xe0\xb9\ -\x68\x29\xd1\x5a\xa1\x6d\x07\x6d\xd9\x08\xc7\xc5\x8b\xea\x28\xc7\ -\x25\xea\x74\xd9\x1b\x4f\xe9\x27\x19\x83\xa4\xe4\xc9\xfa\x16\x8f\ -\xd7\xb7\x19\x4c\x53\x56\x77\x76\x78\xf4\x74\x8d\xe7\x5f\xfe\x14\ -\x7e\xcd\xec\x68\xc2\x11\x94\xb6\x44\x44\x90\x68\x68\x2e\x1d\xe3\ -\xad\x9f\xbc\x8d\x76\x1d\xea\xdd\x39\x26\x69\x41\x51\x56\x94\x4a\ -\x19\x7e\x56\x59\xce\x68\x97\x66\xa1\x84\x51\x84\x6d\xdb\x44\x51\ -\x64\x48\x36\xb3\xa4\xc4\xaa\x2c\xc0\x35\x47\x15\x3c\x97\x30\xf4\ -\x18\x0c\xfa\xac\xad\x3d\xa5\x56\x5b\x60\x79\xb1\xc7\xe3\xec\x00\ -\xca\x81\x00\x00\x20\x00\x49\x44\x41\x54\x7b\x2b\xbc\x7e\xb1\xcb\ -\xd5\x4f\xbd\x4c\x3b\x58\xe0\xda\x3b\xef\xb2\xb5\xb3\x89\x70\x20\ -\xb7\x15\xfe\x42\x9b\x72\x14\xd3\x68\x76\x70\x7d\xcf\x54\x4d\x12\ -\x2a\xad\x41\x29\x83\xbd\x8d\x13\x2c\xc7\xc1\xb1\x5c\x8a\xa2\x64\ -\x3a\x99\x40\x9e\x81\xe3\x60\xd7\xeb\x54\x69\x8e\x1b\x06\x48\x55\ -\x92\x8d\x46\x9c\x3b\x79\x8c\x6f\x7c\xf9\x97\x38\xbb\x14\x52\xc6\ -\x19\x4f\x1f\xdc\xa1\xe1\x79\x5c\x3c\x7f\x1e\xd7\xb6\x88\x63\xa3\ -\xcb\x9f\xa6\x05\xc3\xd1\x88\x5e\xa7\xc7\xee\xee\x0e\xd2\xb2\x39\ -\xb6\xbc\x8c\x1b\x04\xb3\x6c\xed\x79\x7e\xf6\xb3\x6b\x74\x5b\x2d\ -\x02\xcf\x65\x6e\x6e\x9e\x24\x8e\x59\x79\xf8\x10\xd7\xb6\x39\xd8\ -\xdd\xe1\x85\xe7\x2f\x51\x0f\xfd\x6f\x5a\x02\xac\x37\x7f\xe7\xbf\ -\x37\x62\x72\x4b\x50\xc0\x4a\x05\xff\xcd\x50\x49\xfe\xfa\x47\x3f\ -\xc6\x0a\x22\x1a\xdd\x39\xd2\xdc\xc4\x55\xfb\x41\x48\x32\x1e\xa2\ -\x2d\xf0\x1d\xc7\xa8\x90\x8a\x92\xc0\x76\x39\x36\xd7\xe3\xf2\xf9\ -\xb3\x9c\x5c\xe8\x91\x8c\x87\xb4\x1a\x2d\x86\xc3\x09\x61\x54\x43\ -\x58\x92\xa2\x54\xf8\x9e\xcf\x74\x12\xb3\x30\xbf\x48\x32\x4d\xe8\ -\x75\x7c\xf6\xf6\x47\x34\x1a\x21\x96\x65\x73\xed\xda\x35\xbe\xfa\ -\xc6\xab\x24\xa5\x31\x72\x4c\x26\x13\xf6\xf6\xf6\xb0\x6d\x9b\xc5\ -\xb9\x1a\x1f\xdf\xb8\xcb\xa9\x53\xa7\x28\x4b\x45\xbd\xee\x91\xe7\ -\x66\xf1\x37\x9b\x01\x87\x87\x31\xd3\x69\xce\xd3\xa7\x4f\xb9\x70\ -\xe1\x3c\xaf\xbe\x7a\x99\xd3\xa7\x4f\xf1\x83\x1f\xfc\x98\x34\x4d\ -\xd9\x3e\x18\xa2\x70\x78\xf4\xe8\x11\xaf\xbc\xf2\x0a\x51\x64\x6c\ -\x93\xa3\x51\x4c\x18\xfa\x34\x02\xc1\x34\x55\x0c\x87\x43\x76\x77\ -\x77\x39\x73\xe6\xcc\x0c\x4c\x3e\x0b\xf4\xb2\x2c\xa2\xc8\xa5\x2c\ -\xf5\x51\x52\xc5\xe7\x3f\xff\x39\x8e\x2d\x2f\x11\x4f\xa7\xac\xae\ -\xad\x33\x18\x0e\xa8\x45\x35\xe6\x7a\x11\xe3\x51\xca\xee\xce\x2e\ -\xc7\x8f\x2f\x23\x10\x34\x22\x89\xeb\x59\xec\xef\x0e\x58\x5a\x6c\ -\xb0\xbd\x33\x20\x8e\x63\x5a\xbd\x2e\x45\xa5\x29\xf3\x02\x5d\x6a\ -\x44\x65\xf2\x85\x5c\x07\x94\xed\xb0\x3d\x4e\x19\x6b\x97\x3f\xfb\ -\xfe\x0f\xd1\xb5\x06\xc3\x42\xb3\x37\x49\xe8\x2e\x2e\xe3\x35\x9a\ -\xa4\xf1\x98\x32\x2f\xf0\xc3\x1a\xa5\xaa\x90\xd2\x42\x57\x46\xab\ -\x0b\x1a\xf1\x6c\x21\x0b\x81\xeb\xb8\x26\x69\x50\x9b\x85\x6c\x04\ -\xb6\x19\x52\xcc\x16\x51\x56\x60\x85\x21\x5a\x5a\xc6\xf6\xe7\xf9\ -\xa8\xc9\x94\x4a\x58\x94\x69\x0e\xbb\x87\xe4\x8d\x36\x41\xb3\x83\ -\x76\x23\x76\x0f\x47\x84\xcd\x39\x70\x43\xfc\x66\x9b\x71\x56\xb0\ -\xf1\xe8\x11\xa9\xe3\xb2\xba\xd5\xe7\xc1\xd3\x75\x6e\xdc\x5f\x61\ -\x77\x92\x40\xd8\x21\xb3\x04\xa3\x4c\xf3\xad\xbf\xfe\x6b\x92\xb2\ -\x24\x57\x15\x79\x5a\xa2\xab\xca\x64\x2d\x1b\x6d\x2c\xd2\xf7\xd1\ -\x42\x10\xd4\x22\xf4\xec\x8f\xeb\xb9\x47\x3e\x75\x69\x5b\x54\xb3\ -\x49\x4a\xa5\x2b\x6c\x4b\x32\x39\x3c\xe0\xd4\xb9\xb3\xec\x1d\x1e\ -\x72\xe3\xa3\x8f\xb9\x78\xe6\x22\xc7\x9a\x5d\x6a\x96\x43\xb1\x0f\ -\xc7\xda\x5d\x1c\x29\xd9\xda\xdd\xa0\x77\x7c\x8e\x58\x4e\x49\xc7\ -\x03\x88\x0b\xa2\x5a\x0b\xdb\x71\x29\xcb\xc2\x54\xa6\x15\xa0\x05\ -\x81\x17\x50\x4c\x53\xe3\x0e\xc4\xa2\x28\x72\x2a\xa5\xc0\xb2\x90\ -\x8e\x43\xe0\xf9\xe4\xe3\x18\x55\x96\x26\xf0\x7c\x3c\xe4\x33\x2f\ -\x5e\xe6\x57\x3f\x7f\x19\xab\x04\x99\xe7\xf4\x77\xb6\x38\xb9\xb4\ -\xc8\xf9\x85\x16\x83\x38\x45\x29\xe3\x87\xd6\xc2\xe1\xee\x9d\x7b\ -\xd4\xea\x11\xa3\xe1\x80\x4b\xcf\x5f\xa4\xaa\xc0\x71\x05\x37\x6f\ -\xde\xa6\xd5\xea\x30\x18\x0c\xb8\x7c\xe9\x12\xba\x52\xf4\x0f\x0e\ -\x79\xba\xb2\xc2\xf1\xa5\x25\xf6\xf7\xf6\xe8\x75\xda\x9c\x3b\x7b\ -\xea\x0f\x02\xd7\x79\x4b\x02\xd6\x9b\xbf\xf3\x3b\x60\x99\x07\x26\ -\xd5\xfc\x23\x25\xf8\x86\x0c\xea\xfc\xc9\xb7\xfe\x12\x65\x79\x60\ -\xbb\x86\xe4\xef\x87\x34\xda\x4d\xa6\xe3\x11\xaa\x32\x41\xac\xd6\ -\x2c\x18\x4c\x97\x15\x81\x63\xb1\xdc\xeb\xb0\xbb\xb9\xca\xe7\x5e\ -\xff\x34\xcd\xba\x45\xa9\x98\x41\xec\x22\xa4\xe3\xf2\xf0\xc1\x0a\ -\x57\xae\x5c\xe1\xfd\xf7\xde\xa3\xdb\xe9\xe0\x07\x3e\xd3\xc4\xa0\ -\x63\x1f\x3c\x78\x84\xeb\xba\x38\x41\xc3\xc0\xc4\xd3\x94\x6e\xb7\ -\x4b\x10\x04\xf4\xfb\x7d\xc6\x93\x8c\xfd\xfd\x7d\x5e\x7e\xe9\x02\ -\x93\x49\x66\x6c\x5d\x8e\x35\x73\x40\x55\x78\x9e\xc7\xc7\x1f\x7f\ -\xcc\x2b\xaf\xbc\x42\xbd\x66\x73\xe3\xc6\x43\x16\x16\x3a\x9c\x3d\ -\x7b\x86\x30\xac\xb1\xba\xba\x8a\x10\x82\xfd\xfd\x7d\x5e\x7a\xe1\ -\x2c\xc3\x51\x42\x51\x98\x9d\x7c\x34\x4a\x48\xb2\x8a\x46\xc3\x43\ -\x08\xc3\x35\xae\xd5\x6a\x33\xd3\x83\x8b\x52\x15\x71\x3c\x45\x6b\ -\x49\x18\x3a\x47\xd1\x33\xf5\x7a\x83\x2c\xcf\x58\x5c\x9c\xe7\xf8\ -\xf1\xe3\xb8\xae\xcb\xfa\xda\x3a\xb7\xef\x3c\xe0\xde\xdd\xbb\x84\ -\x61\xc4\xd2\xfc\x02\x49\x9c\x30\x1a\xa5\xa8\xd2\x40\x04\x6c\x5b\ -\xe0\x7a\x3e\xf7\xee\x3f\xe0\xcc\xd9\x33\x06\x42\x20\x2d\x63\x5c\ -\x92\x12\x29\x05\xa9\x32\xe3\x98\xbf\xbb\x76\x83\x6b\x0f\x57\xd8\ -\x18\x4d\x50\x41\x8d\x7e\x56\x62\xf9\x11\x83\xf1\x94\xf1\x68\x84\ -\xd0\x15\x55\x31\xdb\x91\x55\x85\xb4\x6c\x34\xc6\xbc\xc1\x6c\x47\ -\x2e\x0b\x33\xe7\x76\x5c\x17\x61\xf0\x89\x20\x2d\x84\x56\xd8\x55\ -\x89\x23\x2a\xa8\x24\x6a\x3c\xc1\xab\x37\x91\x08\x54\x56\xe2\x78\ -\x3e\x5e\x50\x43\x4a\x17\x25\x6d\x70\x0c\x0d\xb5\x48\x0b\x94\xb0\ -\x09\xa2\x06\x25\x16\xe3\xe1\x90\x71\x9e\xe3\xd5\x1a\x64\x55\xc9\ -\x38\x2f\xb9\xf7\xe8\x21\xef\x7d\xf8\x21\x7b\xc3\x31\x1f\xdf\xbb\ -\xc7\x87\xb7\xef\xf2\xf1\xfd\x15\xfe\xf8\xcf\xff\x82\x78\x6f\x8f\ -\x60\x6e\x8e\x4c\x0b\xb0\x3d\xa3\x9e\xb2\x6d\x2c\xc7\x41\x0a\x89\ -\xeb\xb9\x94\x49\x82\xeb\x99\x40\xbd\x67\xee\xb1\xaa\xaa\x10\x96\ -\x3c\x3a\xda\xa8\xd1\x08\x37\x0c\x29\x8a\x1c\xaf\x5e\xa3\xd0\x15\ -\xae\xeb\x11\x04\x01\xf7\x3e\xba\x49\x28\x1c\xec\x44\x52\xc5\x29\ -\x55\x9a\xf2\xfc\xa5\x0b\x7c\xee\x4b\x6f\xd0\x98\xaf\x73\xfd\xf6\ -\x35\x9c\x30\xa4\x1c\x9a\x79\xb0\x94\x02\xa5\x95\x49\x8e\x94\x02\ -\x5b\x3a\xd8\x96\x43\x91\x15\x90\xa5\x94\xe6\x1f\xf0\x42\x9f\xa0\ -\x16\xa1\x8a\x12\x55\x55\xf8\x51\x9d\xe2\xe0\x80\x66\xb3\x46\x20\ -\x15\xcb\xad\x06\x2f\x9c\xbd\x40\x3a\x1c\xa0\x26\x23\x42\x1b\x96\ -\x7a\x1d\x2c\xc7\x23\xcf\x32\xa2\x7a\x8d\xd1\x24\xa7\xde\xf0\xb8\ -\x7d\xfb\x21\xf5\x28\xa4\x3b\xd7\x21\xcb\x15\xbe\xef\x32\x1c\x4f\ -\x19\x0c\x06\x0c\x87\x43\x5e\xff\xf4\x27\x91\x02\x3c\xc7\xe5\x83\ -\x6b\x3f\x27\xf4\x5d\x24\x9a\x83\xdd\x6d\x4e\x9f\x58\xe6\xfc\xa9\ -\xe3\x9f\xb3\x66\xc7\x25\x89\x6d\x81\x36\x8b\x51\x56\xd5\x5b\x00\ -\xbd\x76\x8d\xd3\x4b\x8b\x14\xf1\x98\x32\x8d\xa1\xcc\x29\x4b\x33\ -\xb6\x09\xda\x6d\x84\xed\x51\x8c\x26\xe8\x4a\x50\xab\xb7\xe9\xcc\ -\xcd\x51\x6b\x36\x79\xe3\xcb\xaf\xe2\x44\x11\xdb\x87\x03\xee\xad\ -\x6c\xd2\x6c\xf9\x44\x8d\x3a\xd3\x1c\x86\x03\x03\xa0\x13\x42\xf0\ -\x85\x2f\x5c\xe5\xe1\xc3\x87\xac\xae\x6d\xd3\x6e\x37\x18\x8f\x4d\ -\x97\x39\x0c\x43\x7c\xdf\x27\x4d\x53\x7a\xbd\x88\x66\xcd\xa2\xd1\ -\x68\xe0\xfb\x3e\x4f\x9e\x3c\x61\x61\x61\x81\x4a\x1b\x70\xfc\x68\ -\x34\x25\x8e\x33\xf2\xdc\x00\xf0\x47\xa3\x11\xd3\xa9\x89\xa0\xc9\ -\x0b\x78\xed\xc5\xf3\xec\xec\x0c\x18\x8d\xa6\x04\x41\xc0\x4b\x2f\ -\xbd\x84\xe7\x79\x4c\x26\x13\xfe\xe6\x27\xd7\xd8\xdc\xdc\x64\xb1\ -\xed\xa3\x35\x47\xb9\xce\x65\x69\x64\x99\xcf\xf2\x7e\xe6\x3a\x01\ -\x96\x05\x61\x28\x71\x5d\x97\x24\x49\x48\x53\xc5\x78\x3c\xa6\xdd\ -\x6e\x33\x1e\x8f\xc9\x8a\x82\x24\x2b\x49\x12\x73\xe3\xb9\xfa\xfa\ -\xcb\x5c\xbd\x7a\x95\xe5\xa5\x25\x4e\x2c\x2f\x71\xef\xee\x6d\x1e\ -\x3d\xbc\xcf\x9d\xdb\x37\x79\xfa\x64\x05\x29\x25\x4f\x9e\x6c\xd3\ -\xf1\x20\x99\x4e\x49\xf3\x04\x21\xc0\xb6\x05\x42\x6b\x5c\x29\xa9\ -\x4a\x18\x8d\x4b\xb2\x12\xde\xbf\x71\x93\xeb\x77\xee\x92\xda\x92\ -\x83\x64\x8a\x12\x82\xb0\xdd\x26\x8c\xea\xd4\xeb\xad\xa3\x00\xb2\ -\x67\x6f\x7a\xf6\xb1\x44\x1c\xa9\xdd\xd0\xc6\xdd\x28\xfe\xdd\x6b\ -\xa6\xb7\x76\x14\x78\x25\x44\xda\x82\xac\x24\xaa\x04\x81\x12\x90\ -\x57\x04\xa5\x20\x59\xdd\xc0\x2e\x15\xed\xa0\x06\x96\x0b\x3b\x87\ -\xa0\x34\xbe\xb4\xd1\x45\x45\x59\x80\x88\x5a\x60\x07\x94\xb6\x03\ -\x7e\x83\xdd\xc1\x88\x2a\x6a\x52\x5f\x3e\xc9\xa3\x83\x3e\x0f\xd7\ -\xb6\xb9\xbe\xf2\x94\x9b\x4f\xd6\x19\x0c\xa7\xd8\x4b\xa7\xb0\xdc\ -\x1a\xba\xd4\x58\x5e\x80\xe3\xfb\xd8\xae\x6b\x92\x35\x9e\x45\x9c\ -\x26\x53\xd2\x3c\xc3\x71\x4c\x92\xa5\xd6\xfa\xe8\xff\x66\xcd\x90\ -\x3d\x4c\xa7\x14\x49\xc2\xf1\x85\x25\x2a\x05\xa3\x83\x3e\x49\x51\ -\x62\xf9\x21\x1b\x07\x03\xfe\xec\x3b\xdf\xe5\xf1\xc6\x16\x67\x2f\ -\xf6\xb8\xfa\x6a\x87\xb3\x27\x2c\xda\xbe\xc5\x4b\xe7\x4e\xf0\x5f\ -\xff\xc7\xff\x21\xe7\x97\xba\x78\xa1\x4b\x96\x4e\xc9\x92\x29\xf6\ -\xac\x0d\xe8\x20\x67\x61\x80\x53\xf3\xe0\xcd\x62\x61\xa5\x6b\xf4\ -\x04\xe6\xf5\x52\x61\x55\xe6\xf3\xed\x30\xa2\xee\x79\x1c\xee\xee\ -\xf2\xc9\x17\xaf\xb0\xfe\xf4\x09\xe3\x83\x3d\xe6\x9a\x75\x1a\xbe\ -\x4f\x16\xc7\x4c\xc6\x23\x2c\xcb\xc2\x40\x5c\x25\xfd\xa1\xc2\x71\ -\x7d\x1a\xad\x26\xb5\x5a\x83\x76\xbb\x46\x51\x28\x16\xbb\x21\x71\ -\x1c\x93\xa6\x09\x93\x49\x4a\x92\xe4\x44\x61\xc0\x78\x38\xe4\xd2\ -\x85\x8b\xac\x3d\x5d\xc5\xb2\xac\x23\x53\xce\xb3\x37\x89\x94\xa8\ -\xb2\x44\x48\x8d\x6f\xc9\x15\x07\xfa\x35\x1b\x2e\x9c\x3a\x01\x45\ -\xca\xd2\x7c\x97\xb0\x1e\x42\x3c\x64\x3c\x1e\x19\x21\x43\xad\x0e\ -\xa5\xc6\xf7\x43\xb6\xb7\x77\x49\x95\xe2\xf6\xfd\x07\xfc\xec\xbd\ -\xfb\x34\x3a\x5d\x0e\xc6\x63\xa2\x76\x9b\xed\xc3\x29\x8d\x86\xc7\ -\x34\x4e\x51\x79\xc1\xe9\x53\xa7\x08\x03\x9b\xe1\x30\xe1\xf9\x2b\ -\x2f\xcc\x34\xd1\x3b\x47\x9d\x6a\x03\x87\x87\x4e\x27\x64\x77\x77\ -\xcc\x7e\x3f\x25\x4d\x53\x5e\x38\xbf\x8c\x65\x59\x1c\x1e\x1e\xf2\ -\x9d\xef\xbc\x45\x9a\x9a\xce\x70\x10\x78\x54\x95\x9e\x8d\x9a\x1a\ -\x74\x3a\x1d\x94\x52\x4c\xa7\x39\xbb\xe3\x72\xf6\x39\x01\x96\x25\ -\xa8\xd7\x7d\xe2\x38\xe6\xd5\x57\x5f\xe5\xe2\xc5\x8b\x08\x21\xf8\ -\xcb\xb7\xde\xe6\xbd\xf7\x3e\x06\xa0\xd1\xf0\x99\x4c\x12\x76\x77\ -\x77\x39\x7f\xfe\x3c\xad\xa6\xcb\xd3\xf5\x03\x03\x00\x88\x4d\xfe\ -\x4f\xb7\x5b\xc7\xf3\x2c\x36\x36\x36\x66\x32\xd2\xc6\x8c\xf6\x61\ -\xa3\x94\x22\x4d\x53\x8a\x92\xa3\xa6\xdc\xf2\xf2\x32\x57\xae\x5c\ -\xe1\xf2\xe5\xcb\xbc\xfe\xfa\xeb\x9c\x3c\x7d\x8a\x1b\x37\x6e\xf0\ -\xe4\xc9\x13\xbe\xf3\xd6\xcf\x78\xba\xba\xca\xca\xca\x0a\x5b\xbb\ -\x5b\x0c\x06\xc6\x67\x3a\xdb\x2c\xa9\x84\xc0\x09\xa0\xb0\x1d\x32\ -\x01\x83\x34\xc3\x69\xd4\xa8\xf7\xba\x0c\xf6\xf6\x98\x4e\xa7\x06\ -\xa6\xae\xf5\xdf\x5b\xc8\xcf\xe4\xaa\xcf\xec\x70\xff\x7f\x6f\x42\ -\x9b\xd4\x04\x4b\x4b\x6c\x2d\x8c\x2c\xb7\x62\x76\x55\x38\x1a\x5a\ -\xdd\x2e\xd5\x74\xca\x78\x6f\x87\x86\x6b\x43\xe0\x12\x58\x36\x3a\ -\x49\x28\x92\x29\x69\x3c\x36\x8e\x2e\xa5\x89\x47\x89\x49\xaa\x1f\ -\x25\x1c\x8e\x13\x76\x9e\x6e\x12\x2d\x2c\x13\x9e\x3c\x4b\xfb\xf8\ -\x69\xc6\x4a\xd2\x38\x71\x96\x12\x97\xc9\xa4\x64\x6e\xe9\x34\xaa\ -\x28\x28\x54\x79\x04\xfa\xd7\x52\x98\xec\xa5\x67\x29\x1d\xfc\x62\ -\xf1\x3e\x3b\x23\x6b\xad\xcd\xcf\x8c\x22\xea\x7e\xc8\xc1\xee\x1e\ -\x55\x5e\x20\x1c\x9f\x7c\x63\x87\xad\xad\x5d\xac\xb0\x46\xf7\xd4\ -\x29\xfe\xe4\x7b\xdf\x65\x3f\x85\x83\x02\xf6\x06\xb0\x5c\x17\x9c\ -\x8c\x42\x3e\x7b\xf2\x22\x0b\xbe\x43\xa7\x1e\x40\x99\x50\x66\x13\ -\x2c\x5d\x62\x63\x0c\x2b\x5a\x15\xe8\x59\x43\x17\xcb\xc2\x8d\x42\ -\x84\x63\x93\xe4\x19\xd3\x69\x8c\xae\x2a\x6a\x91\x8f\x28\x4a\xca\ -\xfe\x3e\x9b\x4f\x1f\xf3\xf9\xd7\x3f\x4d\x32\xea\x73\xfa\xd8\x12\ -\x97\xce\x9f\xe3\xc4\x7c\x07\x0b\x98\x8c\x86\xb4\x1a\x4d\x1c\x4b\ -\x32\x19\x67\xb8\xbe\xcd\xa3\x47\x8f\xa8\xd0\x34\x9b\x4d\x93\x49\ -\x66\x1b\x0d\xc2\xce\x61\xc2\x64\x32\xe1\xe2\xc5\x8b\x74\xda\x3e\ -\x41\xe0\x32\x99\x8c\xf1\x7d\x97\x7a\xa3\x46\x54\x0b\x68\x35\xeb\ -\x9c\x3b\x7b\x5a\x94\xd5\x2f\x9e\x4b\xeb\xcd\xdf\xff\x3d\xa4\x6d\ -\xa3\x35\x28\x21\x91\x82\x3f\x98\xe4\xfa\xcd\x9d\xc3\x01\xf7\x9f\ -\x3c\x25\x13\x92\x66\x6f\x9e\xc1\xfe\x01\xb5\xf9\x79\x92\x34\x43\ -\x95\x8a\x52\x08\xb2\xe1\x08\x84\x4d\xa7\xd3\xa1\x52\x39\x9b\xab\ -\x4f\xb8\xf2\xdc\x39\x5e\xb8\x74\x9a\x9d\x8d\x4d\xd2\x24\x66\xb1\ -\xdb\x62\x34\x4e\xc8\xf3\x82\x20\x0c\x99\x4e\x53\x9a\x4d\x63\xe0\ -\x0f\xa3\x88\xdd\x9d\x5d\xaa\xaa\x62\x67\x67\x87\x2b\x57\x2e\x31\ -\x1a\x25\x48\xe9\x1c\xa5\x31\xcc\xb5\x7d\x9e\x6e\xf6\x19\x0e\x87\ -\xbc\xf6\xda\x6b\x9c\x39\x73\x86\xc7\x8f\x1f\xb3\xb6\xb6\x46\xb7\ -\xdb\x9b\xc9\x22\x1d\x6e\xde\x34\x70\x78\xcb\xb2\xb0\x6d\x9b\x56\ -\xdd\xdc\x5b\x3d\x4f\x30\x1e\x27\x38\x8e\xc3\xad\x5b\x77\x8e\xc8\ -\xfc\xbd\x5e\x87\x46\xa3\x49\x51\x14\xac\xaf\xaf\x1f\x19\x3b\x9e\ -\xc1\x0e\xa6\x49\xc1\xc2\x42\x93\xa2\xd0\x47\x69\x8e\x83\x41\x4c\ -\x51\x28\x26\x93\x09\x73\x73\x73\x08\xe1\x50\x69\xd3\x9b\x09\x3c\ -\x8f\xaa\x82\x3c\x2f\x69\xd6\x7c\x6e\xdf\xbc\xc3\x73\x17\xcf\x12\ -\xc7\x53\x86\xc3\x01\x96\xe3\x10\xc7\x31\x17\xce\x9f\x61\xe1\xd8\ -\x71\xba\xbd\x79\x4a\x2a\x5e\x7d\xed\x93\x26\xc6\x75\x6d\x03\x21\ -\x2d\xee\xde\x5f\xe1\xe3\x3b\x0f\x19\x97\x8a\x7e\x21\xb9\xb3\xba\ -\xca\x48\x29\xa6\x40\x89\x44\x0b\x0b\x2d\xa4\x71\x48\xe9\x0a\xaa\ -\x12\x6d\x09\x84\xb4\x51\x95\x46\x55\xfa\xe8\xbc\xe7\x3a\x36\x95\ -\x2a\x29\x8b\x1c\x29\x04\x8e\xed\x60\xd6\xbd\x30\xa2\x08\xad\xb1\ -\x55\x65\x9e\x7b\xad\x49\x95\xc6\xb2\x1d\x54\x51\xe0\x07\x3e\x45\ -\x96\x20\xa8\xd0\x65\x8e\x25\x34\x79\x3a\x41\x0d\x0f\x91\x36\x14\ -\x69\x8c\xa4\xa2\x4a\x33\xca\x49\x6c\x12\x1d\x75\x85\x5d\x0b\x0d\ -\x7c\xb0\xde\xc0\x6d\x75\x49\x8a\x12\xe1\x06\xc4\x79\x49\x58\x6f\ -\x93\x96\x1a\x69\xf9\x54\x85\x46\xdb\x2e\xd2\x35\x21\x03\x65\x51\ -\xe0\xba\x2e\x45\x9e\xe3\x58\x36\x45\x55\xa1\xa7\x53\x9c\x30\xc4\ -\x76\x1c\x92\x34\xa5\xd1\x30\xf0\x09\x61\x5b\x4c\x46\x23\x73\x96\ -\xad\x34\xba\x28\x29\x0a\x83\xb6\xad\x9f\x38\x89\x46\xe2\x38\x1e\ -\x96\x6b\x13\xa7\x53\x26\x59\xc6\xb9\xe7\xce\xe0\xfa\xa0\x2d\x43\ -\x22\x8d\x6c\x41\xaf\xd1\xe6\xa7\xef\x7e\xc4\x28\x36\xe8\x1d\x2d\ -\xb4\x51\x13\xd6\xeb\x0c\x6e\xdd\x84\xf9\x39\x82\x56\x9b\x52\x95\ -\x28\x55\x22\x5d\x07\xd7\xb6\x91\x96\xc4\x73\x4c\xb6\x54\x95\x4d\ -\x59\xe8\xb6\x49\x87\x87\x9c\x9c\xeb\xf0\x1f\xfd\xd6\x97\x68\x05\ -\x36\x32\x2f\x49\x46\x23\xaa\x22\xe3\xc9\xa3\x15\x96\x97\x96\x41\ -\x4a\x2a\x2c\x6e\xde\xbc\xc3\xe5\x2b\xcf\x33\x37\xb7\xc0\x9d\x5b\ -\x1f\x73\xe9\xfc\x32\x59\x09\x07\x07\x7d\xa4\x65\xb1\xb3\xb3\x43\ -\x3d\x0c\xf1\xfc\x1a\x9e\x6b\x71\xff\xee\x3d\xb2\x38\xe6\x33\xaf\ -\x5c\xe1\xc9\xca\x53\xea\xf5\x1a\x17\xcf\x9c\xfa\xa6\x23\xa0\x52\ -\x95\x69\x2d\x30\x2b\xbf\x8a\xa2\xc0\x11\x06\xf7\x14\xd8\x82\x97\ -\x2e\x5d\x44\xa5\x31\x45\x12\x53\x64\x53\xf0\x1d\x06\xfb\x3b\x78\ -\xcf\x4a\x8b\xb4\xc0\x6b\xb4\x89\xda\x6d\x9e\xae\x6f\x10\xd4\xea\ -\x1c\x4e\x26\xdc\x7a\xf8\x90\x49\x5e\xd1\xe8\xf5\xa8\xa4\xe4\xde\ -\xca\x16\xa7\xe6\xeb\xbc\xfb\xee\xbb\x54\x45\xc9\xa5\xe3\xdd\x59\ -\x49\x5a\xe2\xfa\x1e\xe7\x9f\xbb\xc8\xce\xce\x8e\x39\x73\x3a\xbf\ -\x30\x3f\x2c\xcd\xd5\xf0\x7d\x8f\xc3\x51\xc1\xf2\xb1\x36\xdb\xdb\ -\xdb\x4c\xa7\x53\x7c\x5f\x70\xfe\xfc\x79\xea\xf5\x3a\x6b\x6b\x6b\ -\x33\x9b\x61\x75\x14\x0b\xd3\x6a\x19\x92\xe4\xe6\x8e\x29\xb5\xc7\ -\xe3\x8c\xb2\x2c\x71\xdd\x67\x33\x68\x93\x79\xac\x94\xa6\xd7\x6b\ -\x72\xfe\xfc\x79\x9e\x7b\xee\x39\x84\x10\x5c\xbf\x7e\x9d\xfd\xfd\ -\x7d\x5a\xad\x1a\xf5\x7a\xc4\xea\xea\x2e\x49\x92\xcc\x76\x01\xb3\ -\x2b\x0c\x87\x43\x63\xfb\x14\x02\xc7\x9f\x55\xae\xc2\xf4\x69\x2c\ -\xcb\xc2\xb5\x6c\xd2\x54\x51\xaf\x1b\x90\x40\xbd\x1e\x31\x8e\x27\ -\xd4\xeb\x01\x51\xbd\x8e\x70\x67\xaf\x3f\x29\x18\x4e\xc6\xa6\xab\ -\x6f\x3b\xbc\xf6\xc6\x1b\x74\x16\x16\x38\x77\xf9\x0a\x5f\xfe\xc6\ -\x17\x38\xff\xd2\x79\x1e\x6d\x6c\x71\xf3\xfe\x43\x36\xb6\x76\x29\ -\x0f\x87\xa8\xfe\x90\x6c\x77\x8f\x6a\xff\x00\x3d\x1c\x90\x8e\x87\ -\x94\x69\x8c\x4e\x53\xd2\x2c\x45\x25\x09\x55\x9a\x90\xc6\x31\xc5\ -\x78\xcc\x78\x3c\x36\x99\xd1\xcf\xa0\xfc\xb3\xd4\x8c\x2c\x4d\xc9\ -\xe2\x98\x6c\x1c\x33\x1a\x0e\xe9\x0f\xc7\x0c\x86\x23\x18\x0e\x18\ -\x0d\xfb\x8c\x87\x7d\x06\x83\x03\x26\xc3\x7d\x86\xa3\x43\xa6\xe3\ -\x3e\xd3\xb8\x4f\x9e\x8d\x41\xc5\x08\x59\x60\xd9\x0a\xdb\xd1\x04\ -\x8d\x00\xbf\x59\x23\xa8\x05\x78\x9e\x8b\x27\x6d\xf3\x80\x60\x81\ -\xb0\xd1\x96\x87\xb6\x5d\xb4\x15\xa0\xa4\x8b\xc2\x45\xe1\x00\x0e\ -\xba\x92\x14\x79\x4e\x9a\x24\xe8\xbc\x20\x9d\x26\x88\x4a\xa3\xab\ -\x0a\xdb\xf5\x60\x16\xb3\xfb\xac\xc2\x49\x92\x84\xb4\x30\xd9\xd8\ -\x48\x89\x70\x1c\xb2\xf1\x18\xa1\xc1\xb7\x1d\x84\x17\x18\x40\x3b\ -\x92\xb4\x52\x8c\x54\x49\x5e\xf7\xf9\xf9\xd3\x15\xbe\xfd\xd3\x0f\ -\xb9\xfe\x68\x8b\x69\x0e\x64\x15\x0b\x48\x96\xfc\x1a\xaf\x5c\x3c\ -\x83\x55\x4e\xa8\xb9\xd0\x70\x25\xbb\xb7\x6f\xb0\xf1\xf0\x3e\xe1\ -\xd9\x33\x34\xeb\x35\x92\xd1\x00\xbb\x59\x03\x95\x53\xaa\x1c\x2c\ -\x41\x32\x1e\x52\xa9\x02\x57\x6a\x02\x51\x11\x1f\xec\x70\xe9\xcc\ -\x49\xfe\xdb\xff\xea\x1f\x41\x01\xbe\x80\xc0\x71\xb8\x75\xf3\x26\ -\xbd\x9e\x51\x89\xf9\xbe\x8f\x14\x82\x5b\x1f\xdf\xe0\xf4\xc9\x93\ -\xd8\x96\x91\x8d\x86\x61\xc8\xee\xc1\x94\xb2\x34\x9e\xf7\xdb\xb7\ -\x6f\x23\xa5\xe4\x53\x2f\x9c\x45\x0a\xcd\xde\xf6\x3e\xae\x6b\xb3\ -\x74\x6c\x91\xbf\x7b\xfb\x5d\xee\xdc\xb9\xc5\x7c\xb7\x43\x9a\x15\ -\x28\xad\x41\x54\xcf\x76\xe4\x6f\x02\x82\x3c\x4f\x70\x5d\x0f\x0d\ -\x28\xf8\x46\x7b\xae\x75\xec\x5f\xfe\x9b\x6f\x33\x29\x2a\x64\x18\ -\x51\x5a\x36\x6a\x34\x26\xec\xcc\x19\xc4\xeb\x70\x48\x7b\x7e\x81\ -\xb4\x28\x51\xc9\x14\xe9\x4a\x50\x05\xd3\x71\x9f\xff\xe0\xab\xaf\ -\x53\x94\x82\x66\x14\xd2\xdf\x3b\x20\x57\x92\x3c\xcd\x38\x75\xf2\ -\x14\x7e\xe8\x50\x09\x07\x55\x19\x57\x52\x91\x17\xec\xef\x19\xbd\ -\xf5\xfa\xf6\x3e\xad\x56\xcb\x10\x36\x06\x53\x46\x23\x93\x18\xf1\ -\x93\xb7\xdf\xe5\x57\x7e\xe5\xcb\x94\xa5\x66\x34\x32\x24\xcd\x5e\ -\xaf\x8b\x10\x82\xf5\xf5\xf5\xa3\x05\xbd\xbc\xbc\x8c\x3d\x1b\xb1\ -\xb4\x5a\x01\x41\x60\xac\x8d\x42\x38\x28\x25\xb8\x77\xef\x1e\x17\ -\x2e\x9c\x63\x38\x1c\x53\x14\x05\xf5\xba\x8b\x10\x90\x24\x19\xad\ -\x56\x0b\xdf\x37\xcd\x95\x1b\x37\x6e\xb1\xb6\xb6\xce\xc2\xc2\x02\ -\x73\x73\x2d\x94\xd2\x68\x2d\x08\x02\x87\xb2\xac\xa8\xd7\x8d\x56\ -\x7a\x3c\x99\x3d\x66\x1a\xb4\x32\xd0\x3d\xad\x0a\x0e\x0f\x0f\x80\ -\x8a\x7a\xa3\x8e\xe5\xd8\x2c\x2d\x75\xd9\xd9\x1b\x72\xf7\xfe\x3d\ -\xee\x3d\x78\x4a\x50\x8b\x58\xdb\xdc\xe2\xa5\x57\x3e\xc9\xc1\x70\ -\x80\x17\x45\x74\xe7\x5a\x58\xa1\x87\x0c\x1d\xa6\x02\x3e\x7c\xb8\ -\xcd\x5b\xef\xbc\xc7\xe6\x60\x84\x5b\x6f\xe2\xb5\xbb\x58\x51\x0d\ -\xe1\xf8\xc8\x20\xc0\xab\xd7\xa8\xd5\x6b\xa4\xb9\x79\x51\xdb\x7e\ -\x48\x25\xed\x67\x59\xae\x50\x19\x91\x47\xde\xef\xc3\x70\x88\xce\ -\x33\x0a\x21\xcc\x68\x45\x48\x23\x76\xb0\x2d\xec\x66\x1d\xbb\x11\ -\x21\xa2\x90\xca\xb1\x71\x7a\x6d\xec\x28\xc4\x6f\xd6\x90\xa1\x8b\ -\x13\x3a\xe0\xdb\xb8\xa1\x8b\xed\xdb\x94\x42\x11\xb6\x6b\x08\x47\ -\xe0\x47\x3e\x8e\xe3\xe1\xd8\x36\x9e\x6d\x21\xd1\x08\x0d\x59\x3c\ -\xc5\x09\x02\xa4\xed\xa0\x2a\x01\xb6\x63\x7e\x1d\xc7\x74\xfd\xcd\ -\xb6\xa8\x10\xae\x4d\x18\xfa\x26\x81\xc1\x71\xa9\x4a\x93\x3d\x5c\ -\xa4\x19\xaa\x28\x60\x12\x53\x6b\xb7\xb1\xa4\x85\xed\x18\xfb\x67\ -\x59\x16\xa8\x67\x25\x6f\x59\x42\x9a\x11\x36\x1a\x78\xae\x87\xeb\ -\xfa\x94\x4a\x63\xbb\x86\x78\x83\x67\x91\x1c\xee\x33\x54\x29\x0f\ -\x56\x1e\xf0\xf3\xf7\xdf\xc3\xb7\x3d\x5e\x38\x7f\x1a\x9d\x42\xb3\ -\x16\x70\xe1\x85\xcb\x9c\xbb\x70\x8e\xd5\xc7\x8f\xd8\xdb\xdc\xe2\ -\xec\x73\x97\xa8\xd7\xeb\xc4\xf1\x94\x56\xb7\xc3\x68\x32\xc6\x72\ -\x6c\xaa\xc9\x18\x2b\x8a\x90\x95\x79\xbd\xb7\xeb\x75\xd2\xd1\x90\ -\x90\x92\x2b\xe7\xce\xf0\xe2\x73\xe7\xb8\x74\xea\x38\x8b\x1e\x3c\ -\x7c\xb0\x41\x33\x0a\x39\xb5\x7c\x1c\x4b\x08\x94\xd2\x24\x59\xca\ -\x68\x38\x01\x21\x38\x79\x72\x99\x24\x2d\x89\xc2\x80\x3b\xb7\x6f\ -\xf1\xc2\x0b\x17\x98\x4e\x73\xae\x5d\xbb\xce\x97\xbf\xfa\x06\xeb\ -\xeb\xdb\x2c\x1c\x3b\x81\x2a\x4b\xee\xde\xbe\x43\xb3\x51\x63\x63\ -\x6d\x8d\x5e\xa7\x43\x55\x14\xb4\x9a\x0d\xce\x9c\x58\xfe\x66\x55\ -\x2a\x93\x04\x24\x04\xd6\x9b\xbf\xff\xa6\x39\x2c\x6b\x4d\x55\x99\ -\x26\x4f\x51\xb1\x62\x49\xfe\xf1\xdf\x5e\xff\x90\x95\xcd\x6d\xbc\ -\x46\x8b\x5c\x4a\x94\x13\x20\x6d\x97\x34\xcd\xa8\xca\x8a\xb0\xd1\ -\x64\x9c\x24\x60\x09\x5a\xad\x3a\xbb\xf7\x6e\x71\xe1\xd2\x05\x5e\ -\x7c\xe9\x25\x22\xc7\xc2\xb7\x6c\xe6\x9a\x2d\xde\xff\xd9\x3b\x9c\ -\x3d\x7d\x9a\xc5\x85\x0e\x6b\x1b\x7b\x74\x7b\x35\x26\xb1\xa1\x69\ -\xfa\x9e\xc3\xce\xd6\x0e\x57\xaf\x5e\xc5\xf3\x3c\x0e\x0f\x0f\x49\ -\xd3\x8c\xe3\xcb\x1d\x82\xc0\xcc\x71\xc7\xe3\x31\x79\xae\x68\x36\ -\x9b\xf8\xbe\x4f\x18\x0a\x4c\xec\xad\xc7\xe9\xd3\x0b\xd8\xb6\xcf\ -\xbd\x7b\xf7\xd8\xdb\xdb\x63\x61\x61\x01\x21\x04\x7b\x7b\x87\xb8\ -\x6e\x38\x6b\x88\xe5\xec\xef\xef\xe3\xfb\x3e\xe7\x97\x7b\x64\x4a\ -\xce\x12\xfc\x14\xfb\xfb\xfd\xa3\x3c\xe3\x3b\x77\xee\x98\xf3\xec\ -\xcb\x17\x99\x3f\x76\x8a\x27\x4f\x9e\xb0\xb5\xb5\x73\x04\x94\x2f\ -\xcb\x8a\xfb\xf7\xef\x23\xa5\xa4\xd3\x69\x53\xab\x3b\x64\xf9\x6c\ -\x06\x3a\x23\x89\x88\x19\x6c\x7f\x6e\x6e\x8e\x30\x8a\x98\x4c\x26\ -\xa4\x45\x49\x6f\xae\x8e\xe5\x85\x7c\xe2\xa5\xf3\xdc\x7d\xbc\xc6\ -\xed\xbb\xf7\xf8\xc4\xab\xcf\x73\xf3\xd1\x3a\xaf\x5c\x3a\xc3\x87\ -\x4f\x0e\xa8\xfc\x90\xad\x51\xc5\xdb\x1f\x3d\xe0\x2f\x7e\xf8\x23\ -\x3e\xba\xb7\x42\x26\x2c\xa4\x17\x61\xb9\x66\x9e\x5e\x64\x05\xd5\ -\x4c\xf0\x51\xce\x48\x29\xc2\xb6\x09\xc3\x1a\xc2\x76\x90\x8e\x8b\ -\xe3\x7a\x28\x34\x8e\xe7\xe0\x05\x01\xa5\x6d\x21\x42\x9f\xb0\x56\ -\x47\xda\x0e\xd8\x2e\x96\xed\x50\x49\x23\x7c\x50\xc2\xdc\x84\x48\ -\x12\x2a\xd7\x45\x55\x25\x0a\x4d\xa9\x0a\x82\x28\x04\xa9\x91\xb6\ -\x40\x51\xa1\xb2\x29\x22\xf0\xcd\xee\x24\x2c\xca\x4a\xa3\x31\xcd\ -\x28\x55\x2a\xaa\x52\x51\xc4\x09\x4e\x54\xc3\xb2\x5d\xb2\x22\x47\ -\x58\x0e\xda\x6c\x39\xe8\x62\xd6\x9c\x2b\x0a\xa4\x65\x51\xaa\x1c\ -\x55\x64\xf8\x8e\x8b\x56\x15\x8d\xb0\x86\xae\x8c\xbf\xbc\xa8\x2a\ -\xb2\x24\x31\xb9\xc6\x42\x50\x26\x09\x76\x10\x50\x49\x49\xd8\x6a\ -\x61\x07\x3e\xe5\x74\x4a\x58\x6b\xa0\xa5\x85\x25\x25\x93\x69\x82\ -\x1f\x84\x94\x96\x46\xd8\x92\xf6\xf1\x63\x4c\x77\x36\x89\x7a\x1d\ -\x3c\xc7\x66\x77\x6d\x83\xaf\x7f\xe1\x75\x3c\xa0\xcc\xe0\xe3\x5b\ -\x1f\x93\xa5\x13\x5e\x78\xee\x02\x5f\xfe\xc2\x2f\xf1\xf1\x07\x1f\ -\xb2\xb1\xbe\x41\xb3\xdd\x61\xfd\xf1\x53\x5a\x0b\x73\x4c\x07\x43\ -\x03\x63\x8c\x6a\xa8\x74\x4a\xe0\x38\x34\x7c\x8f\xc3\xcd\x75\x1a\ -\x42\xf1\xdb\xbf\xf1\xab\x34\x7d\x8f\x5e\xb3\xcd\x64\x9c\x72\xf9\ -\x44\x87\x9a\x23\x19\x4d\x52\x3c\xdb\x45\x95\x25\x77\xee\xdc\x25\ -\x08\x23\x5e\xb8\x7c\x89\xc9\x38\x21\xf0\x3d\x6c\x1b\x76\x77\x76\ -\xa8\xd5\x9a\xac\xac\x3c\xe6\xa5\x97\x5e\x02\x69\x13\x86\x11\x77\ -\x6f\xdf\x61\x3a\x8d\xe9\x75\xdb\xb8\x8e\x4d\x3d\x8a\x38\xd8\xdb\ -\x66\xf5\xf1\x0a\xbf\xfc\x95\x2f\xe3\xda\xf6\x37\x8d\x10\xc8\x2c\ -\x64\x5b\xcf\xfc\x21\x96\xeb\x32\x1d\x8f\x09\xdc\x26\x8e\xe0\xad\ -\x02\xfa\x5f\xfa\xfc\xe7\xda\x3f\xfc\xe8\x0e\xaa\x48\xc9\x8a\x9c\ -\xf9\xb3\xcf\xb1\xbb\x7b\x08\x45\x85\x1b\xd6\x4c\x89\x83\xa4\xb7\ -\x74\x8c\xed\x27\x0f\xb0\xe6\xe7\x78\xb2\xbe\xc1\xf6\xfe\x00\x59\ -\x0b\xb0\x6d\xc9\x62\xcd\x61\x7e\x7e\x9e\x87\x0f\x1f\xd2\x6c\x36\ -\x59\x58\x98\x23\x49\x67\xe5\xa8\x25\x51\x0a\x0e\x0e\x0e\x10\x02\ -\xba\xdd\x2e\x65\x59\x1e\x75\xb7\x3b\x9d\xce\x51\x49\x68\x46\x51\ -\x82\x83\x83\x98\xd1\x48\xcd\x3a\xdc\x36\xbb\xbb\x63\xfa\xfd\x3e\ -\x6f\xbc\xf1\x06\x5a\x6b\x23\x22\x99\xf9\x99\xd3\x34\x3d\x0a\x82\ -\x7e\xf8\xf0\x21\x97\x2e\x5d\x62\x54\x40\x96\x65\x2c\xcd\xd5\xd8\ -\xeb\x17\x9c\x3a\xd1\x23\x2f\x21\xcf\x35\xad\x56\x0b\xcb\xb2\xb8\ -\xbf\x66\x02\xe4\x5e\x7e\xf9\x32\x93\xd9\xd8\xcb\xfc\x8e\x82\x34\ -\x4d\x67\x99\xc9\x9a\xfd\x03\x23\xec\xa8\xb4\xa4\xca\x1d\xa4\x04\ -\x95\xe5\xc4\x71\x4c\x6f\xae\x43\x3c\x1d\xd3\xed\xb6\x98\x16\x15\ -\xfd\x51\xc6\xd2\x62\x93\x47\x9b\x7d\x4e\x9d\x3f\xcb\xc6\xce\x2e\ -\x71\x09\x4b\xa7\x2e\xb0\x0d\xfc\x9f\x7f\xf2\xe7\xac\xed\xed\x92\ -\x62\xa1\xbd\x80\xe1\x34\x25\xf7\x23\x82\x5a\x93\x20\x6c\x20\x6c\ -\x07\xaa\x1c\xe1\xdb\x06\xf2\x20\x05\x55\x91\x53\xe4\x31\x68\x4d\ -\x51\x29\xca\x67\x35\xbe\x51\x01\xa3\xd0\x78\x8e\x8d\x74\x6c\x6c\ -\x29\xb0\x5d\x07\x51\x69\xc0\x42\x58\xae\xb9\x79\x53\x81\x25\xa9\ -\x74\x49\xe5\xba\xd8\xae\x6b\x64\xa2\xae\x8d\x52\x92\x34\xcf\xcc\ -\xc4\x02\x41\xa5\x2b\xd0\x02\x25\x24\xa5\x74\x90\x96\xa4\xc8\x2b\ -\x6c\x14\x8e\x90\x46\xc7\xa1\x4d\x3f\x5c\xe8\x59\xf7\xf9\x59\xf9\ -\x37\x83\x28\x08\x51\x61\x5b\x82\x42\x28\xa4\x56\x58\x02\xaa\xca\ -\x28\xc9\x54\x31\x03\xe6\x65\x66\x42\x72\xd4\x80\xb0\x66\x6d\x3b\ -\x69\x6e\xc0\x96\x6d\x63\x7b\x2e\x2a\x37\x31\x30\x49\x99\x23\xb0\ -\xb0\x5c\xc7\xb8\x98\x66\x48\xe2\x22\xc9\x51\xba\x00\xc7\x23\x2d\ -\x35\xae\x70\xc9\x85\xe6\x4f\xbf\xfb\x0e\x67\x5a\x1d\x4e\x2c\xb6\ -\x79\xe9\xf9\xf3\x24\x79\xca\x9d\xbb\x8f\xb8\xfa\xea\x65\xd4\x6f\ -\xfc\x1a\xdf\xf9\xe1\xdf\xb2\x7a\x38\xe2\x13\x57\x9e\x67\x7d\x30\ -\x32\x6a\x38\xdf\x27\x19\x0e\x08\x2c\x81\x27\x25\xfb\x6b\x1b\x2c\ -\xd6\xeb\xbc\x7a\xf1\x24\x57\x2e\x9c\x60\xb0\x3f\xc0\x97\x60\xb9\ -\x1e\x39\xb0\x77\x90\x50\x0f\x23\xca\xa2\x64\x30\x8c\x51\x95\x09\ -\x51\xa8\x2a\x4d\x9e\x25\x74\xbb\x01\xfd\x7e\x42\xa3\xd1\xe0\xc9\ -\x93\x27\xd8\x8e\xcb\x72\xc7\xe7\xde\x0c\xba\x77\x7d\x6f\x0f\x4b\ -\xce\x71\xf2\xf8\x31\x1e\xdc\xbd\x43\xc3\xf3\x69\xd6\x4d\xa3\xb9\ -\xd5\xa8\x0b\x89\x29\xbe\x2a\x65\xa4\xbf\xd6\xef\xfe\xee\xef\x9a\ -\x04\x76\x01\x45\x9e\xe3\xba\x3e\x5a\xc2\x54\xf3\x3f\xd4\xe7\x16\ -\xf8\xf3\xff\xf7\xfb\x54\x7e\x48\x16\x4f\xe9\x9e\x3a\xcd\xf0\x70\ -\x08\x85\xc2\x0b\x6b\x28\x05\x41\xb3\xc5\x60\x38\x40\x3a\x92\x6a\ -\x3a\xa4\x16\x79\xa8\x34\xe6\xcb\x9f\x7e\x81\x32\xd7\x54\x85\xc0\ -\x9a\x75\x56\x8b\xa2\xc0\xf1\x3c\x90\x9a\xb0\x16\xa0\x54\x89\x2a\ -\x2a\xb2\x24\x3d\xe2\x5c\x9f\x5d\xee\x10\x35\xbb\xec\xed\xed\x19\ -\xc1\x44\xab\xc5\xbb\xef\xbe\xcb\x3f\xf8\xd4\x0b\xf4\xc7\xc5\xec\ -\x1c\x1c\xe1\xfb\x92\xdd\xdd\xc1\x51\x9a\x7c\xb3\xd9\xc4\x71\x1c\ -\x4e\x9e\x5c\xc2\xf7\x23\x9e\x3e\x7d\xca\xe6\xe6\xe6\x11\xd3\x68\ -\x75\x75\x95\x4b\x97\xce\x70\x70\x30\x22\xcf\x73\xda\x8d\x90\x24\ -\xaf\x48\xd2\x92\x38\x4e\xe9\xf7\xfb\x1c\x1c\x1c\x70\xec\xd8\x31\ -\x3c\xcf\xa3\x5e\x37\x07\xe0\xb2\x34\x04\x93\x76\xbb\x4d\x9a\xa6\ -\xac\xad\xad\xa1\x94\x62\x30\x18\x70\x38\xe8\xa3\xb5\x45\x51\x9a\ -\x24\x7b\xcb\x32\x02\x85\xc3\x83\x03\xda\xed\x16\xae\xeb\x32\x49\ -\x72\x34\x9a\xa8\xe1\xb3\xba\x73\x40\xbb\xdb\x21\x2b\x0a\x72\x05\ -\x76\xd4\xc0\x8e\x2c\xfe\xf5\xb7\x7f\xc6\xa3\xed\x1d\x36\xc7\x53\ -\x9c\x6e\x0f\xd9\x68\x31\xa9\xa0\x9c\xa4\x88\xa0\x49\x59\x09\x8a\ -\xbc\x22\x2f\x4a\xa3\xab\x94\x92\xbc\xaa\x50\x45\x0a\x55\x01\x5a\ -\x23\x3d\xdf\x48\x2b\xa5\x31\xd1\x2b\x55\x62\x59\x92\x74\x3c\x42\ -\xc7\x31\x4a\x15\x54\xd2\xa2\xd2\x1a\x2d\x24\xd2\xb2\x4d\x10\x5d\ -\x96\x81\x2a\xa9\x8a\x12\xe2\x29\xda\x75\x4c\x03\x45\x43\x99\x9b\ -\xce\x3f\xda\x44\x94\x0a\x2c\xaa\x5c\xe1\x84\x75\x04\x16\xb6\x13\ -\x50\x0a\x8b\xca\xb2\x8c\xda\x57\x0b\x2c\xcb\xa6\x48\x53\xdc\x28\ -\x04\x4b\x92\x97\xcf\x66\xf1\x39\x96\x23\x11\xaa\xc4\x96\x15\x65\ -\x96\x60\x0b\x4d\xbd\x16\x61\x09\x89\x2a\x4a\xd2\xa9\xd9\x7d\x55\ -\x96\x51\x16\x05\xe4\x39\x5e\xb3\x89\x17\x06\xf8\x9e\x47\x65\x49\ -\x10\x82\x52\x57\x14\xaa\x24\x9b\x4e\x41\x55\x94\x80\xed\x79\x33\ -\xa1\x85\x34\x0b\x9a\x8a\x2a\x4b\x88\x1a\x4d\xf2\xf1\x08\xdb\x71\ -\x91\x95\x20\x8d\x53\x0e\x76\x0f\xf8\x27\xff\xc9\xd7\xd0\x44\xcc\ -\xb7\x1c\x96\xc2\x80\x95\x47\x0f\xa9\x47\x5d\x4e\x9f\x9c\xe7\xf3\ -\x9f\x7b\x89\x8a\x3a\x3f\xfc\x9b\xbf\xa3\xac\x14\xad\x76\x07\x21\ -\x20\xdf\xdc\x22\xaa\x45\x90\x66\x8c\xb7\x77\xf8\xfa\x17\x3f\xcf\ -\x6f\x7e\xe5\x0b\x2c\x77\x5d\x74\xa9\x59\x7d\xb4\x42\xa3\x16\x32\ -\x1c\xa4\x94\x59\xce\x5c\x37\xe0\xd1\xc3\xa7\x47\x41\x6c\x8b\x0b\ -\xf3\x64\x49\x4a\xb7\xd3\x62\x32\x9e\x10\x04\x01\xd7\xaf\x7d\x48\ -\xb7\xd7\xe3\xd2\xa5\xe7\xd8\xdc\x1d\x70\x62\xb9\xcd\x38\xce\xb8\ -\x75\xf3\x26\x2f\x5e\x79\x81\x28\x0c\xb8\xf9\xf1\x47\x88\x4a\x71\ -\xe1\xdc\x39\x16\xba\x5d\x1a\x8d\xda\xdb\xbe\xe3\xac\x08\x9e\xdd\ -\x1c\x05\x52\x5a\x96\x69\xf1\x6b\x08\x7c\x17\xb4\xc2\x02\x3c\xc1\ -\x7f\xbe\xd0\x0a\x39\x7f\xee\x8c\xf9\x7b\xcb\xe0\x3a\xbd\x28\x02\ -\xc7\x21\x89\xa7\xb3\xa6\x91\x32\x34\xc9\x3c\x23\x68\x75\x18\x0c\ -\x87\x3c\x5d\x5b\x65\xfd\x60\x4a\xad\x66\x33\x49\xa6\x6c\x6e\x6f\ -\xf1\xa9\x57\xae\x10\x05\x21\x1b\xab\xe6\x3c\x5b\x14\x8a\xac\x2c\ -\xd8\xd9\x31\xe3\xa7\x5e\xaf\x49\xaf\x17\xf1\x70\x6d\x1f\xcb\xb2\ -\x8e\xa0\xf4\x3f\xf8\xc1\x0f\xf8\xec\x67\x3f\xcb\xea\xce\x88\x76\ -\xc3\x99\x65\x42\xa5\x8c\xc7\x05\x27\x97\x5a\x48\x29\xb9\x7b\xf7\ -\xee\x11\xb3\x6b\x6f\x6f\x80\xe3\x38\x7c\xfa\xd3\x57\xf8\xd4\xa7\ -\x3e\xc5\xca\xca\x0a\x4f\x9e\x3c\x21\x8e\x63\xa6\x53\x45\xad\x56\ -\x63\x7e\xbe\x4b\x52\x9a\x99\x6b\xbd\xee\x11\x45\x11\x41\x10\xcc\ -\x32\xa1\x6c\x3c\xcf\x21\x49\x4a\x36\x37\xf7\xf0\x66\x9c\x65\x03\ -\xdf\xf3\xb8\x7c\xf9\x32\x2f\xbf\xfc\x32\xc7\x8f\x1f\xa7\x56\xab\ -\xb1\xbe\xbe\xce\xd6\xd6\xd6\x91\x3e\xbc\xdf\xef\x9b\x19\x27\xd0\ -\x6e\x45\x04\x81\x87\xeb\xfb\x6c\xed\x1c\x32\xbf\xd8\xa5\xe6\x42\ -\x51\x29\x36\xf7\x76\xc0\xb6\x78\xe7\xfa\x2a\x3f\xf8\xc9\x7b\x1c\ -\xa6\x0a\xa2\x26\x79\x50\xa3\x5f\x09\x0a\x2c\x33\xb7\x75\x42\x10\ -\x2e\x68\x0b\xcf\x0e\x70\x83\x10\xcb\xf1\x10\x96\x63\x18\x51\xb6\ -\x0b\x8e\x69\x68\x1d\xcd\x60\x2d\x73\x49\xcb\xa2\xde\xed\x62\xb7\ -\x5a\xb8\xf5\x3a\x41\x10\x60\xdb\xb6\xe1\x6a\x17\x05\x45\x9e\x13\ -\x4a\x49\x1d\x73\xa1\x05\xb5\xca\x22\xd4\xe6\x0a\xb0\xb1\x32\xb0\ -\x0a\x01\x85\x44\xe7\x02\x52\x4d\x99\x6a\xca\xa4\x22\x49\x95\x69\ -\x64\x49\x87\x52\x4a\x4a\xcb\x02\xcb\x06\x69\xa3\x31\xaf\x0d\xd3\ -\xbc\xac\xcc\x55\x15\x68\x95\x42\x99\x42\x31\xa1\xcc\x63\xf6\x76\ -\x76\x18\x0d\x86\x8c\x87\x23\x33\xfb\xd6\x10\xd5\xea\x44\x51\x8d\ -\xb0\xd3\x21\x1b\x0e\x8f\x1a\x5e\xb6\x6d\x53\x96\xe6\xe6\xe2\xba\ -\x2e\x41\xbd\x0e\x61\x04\x08\xa4\x6b\x0c\x28\x76\xe0\x51\xa8\x12\ -\xdf\x71\x11\x96\xc7\x78\xbf\x4f\xb3\xb7\x4c\x7a\x38\xa6\x7f\xef\ -\x21\xd2\x0d\x48\xb0\xb8\xb3\x0b\x99\x05\x45\x92\xd0\xdf\xdb\x60\ -\x21\x0c\xe9\x85\x01\x91\x80\x83\xb5\x9c\x4f\x5f\xb9\xc4\x3f\xfd\ -\xfd\xff\x0e\x4f\x48\x44\x51\xa0\xd3\xd4\x18\x4b\xd2\x1c\x47\x0b\ -\x5e\xbe\xfc\x22\x5f\xfc\xec\x67\x39\x77\x22\xa2\x9c\x42\x99\x24\ -\x6c\x6f\xae\xf3\x2f\xfe\xf0\x8f\x38\xb9\xdc\x60\x69\xb9\xc3\x8f\ -\xff\xf6\x3a\x85\xaa\x98\x5b\x58\xc4\x75\x7d\x46\x23\xb3\x78\x6d\ -\x09\x65\x96\x91\x26\xb1\x31\x0e\x45\x35\x3c\x0f\x16\x17\x5b\x6c\ -\xed\x8d\x71\x1c\x63\x12\x0a\xc3\x90\xa5\x66\x88\x23\x2d\xae\x5e\ -\xbd\xca\x07\x1f\x5c\xa3\xd2\x8a\x5a\x10\xbe\x35\x8e\xc7\xe4\x65\ -\xfa\x8b\xf1\xd3\xef\xbf\xf9\xa6\x31\xc1\xa0\x11\x96\xc9\xeb\x45\ -\x0a\xa4\x94\xd7\xd2\x8a\x37\x6f\x3d\x5a\xe3\x70\x12\x73\x58\x6a\ -\x12\xa5\x68\xf5\xe6\xc8\xb2\x12\xdd\x1f\x51\x6f\xb7\xc8\x74\x8e\ -\x3f\x23\x71\x24\xbb\xdb\xb4\x7a\x1d\x36\x37\x36\x58\x5e\x3a\xc6\ -\xe9\x53\x8b\xd4\x7c\x97\x5b\x37\xee\x70\xfc\xf8\x29\x1a\xf5\x1a\ -\xd2\x91\x6c\x6e\x6e\x90\xe6\x09\x51\x10\x32\x9d\x24\xf4\xba\x5d\ -\x4c\xd3\xd9\x2c\x9a\x5a\xcd\x21\x4d\x0b\x16\x17\xe7\x48\x92\x94\ -\xd5\xd5\x55\x53\x76\x2b\x49\x10\xb8\x38\x8e\x8d\x52\x15\x69\x6e\ -\xe6\x89\x1b\x1b\x1b\x9c\x3d\x7b\x96\x5a\x24\xd1\x98\x4c\x63\xa5\ -\xcc\x2e\x72\xfa\xf4\x71\xb4\x16\xac\xad\xad\x31\x1a\x8d\x66\xc2\ -\x93\x88\xe1\x70\xf6\xa0\xda\x26\x3a\xe6\xe0\xe0\x60\x66\x95\x34\ -\x9c\xed\x20\xf0\x68\x34\x22\x92\x24\x3f\xea\xa4\x6f\x6f\x6f\x53\ -\xce\xa2\x54\x7d\xdf\xa3\xd1\x6a\x31\x37\xbf\x40\xaf\xd7\x25\x2f\ -\x72\xb2\x6c\x4a\x7f\x7f\x97\xf5\xb5\x27\x46\x93\xab\x8d\x45\xd3\ -\xb2\x2d\x9a\xed\x1a\xfd\x51\x4a\x5c\x08\xbc\xc0\x63\x9c\x96\xfc\ -\xb3\x3f\xfc\x53\x7e\x74\xfd\x06\xa2\xd6\x22\xb7\x5c\x32\xcb\x22\ -\x2e\x15\x4a\x4a\xa3\xbd\x56\x02\xcb\xf5\xd1\x4a\x21\x91\x33\x31\ -\x82\x24\xaf\x14\xa5\x2a\xa1\x2a\x8d\xee\xb7\xd2\x58\x96\x71\x96\ -\x55\xca\x94\xd5\x3a\x2f\xd0\x68\x54\x9e\x53\x26\xc9\xcc\xd8\x63\ -\x81\x10\x08\x21\xb1\x1c\x17\x47\x5a\x90\xa5\x58\xba\x42\x2b\x45\ -\x9e\xa4\x38\x9e\x87\xd0\x46\xab\xad\x95\xb1\x7e\x56\x95\xc6\x16\ -\x16\x42\x48\xca\xa2\x24\xaa\x35\xb0\xa4\x65\xf4\xc9\xaa\x32\x25\ -\xb0\xd2\x48\xa5\xb1\x84\xa0\x98\x26\xd8\x9e\x83\xae\x2a\x2a\x14\ -\xb6\x2d\x8d\xba\x0c\x4d\x35\xfb\x7d\xab\x38\x46\x2b\x53\xaa\x5b\ -\x9e\x87\x10\x36\xf5\xa6\xc9\xdc\xf2\xa3\x90\xbc\x2c\xa9\xb4\x46\ -\x65\x19\x61\xbd\x8e\xb4\x2c\x6c\xdb\x22\x89\x63\x2c\xc7\x38\xe7\ -\x0c\x8f\x5d\x53\xa5\x19\xb6\xef\x93\xcf\x12\x16\xf3\x74\x4a\x30\ -\x4b\x2e\x29\xb3\x94\x6c\x30\x80\xb2\xc4\x5f\x58\x22\xaa\xd5\x11\ -\xb6\xc3\xcf\x3f\xbe\xc3\x41\xbf\x4f\x55\xc6\x5c\x3c\x7f\x01\xcf\ -\xab\xf1\xf8\xd1\x1a\xf3\xad\x1e\x91\x67\x51\xaf\xc1\xe1\xa8\xe2\ -\xf6\x83\x3b\x6c\xee\x6f\x90\x95\x53\xc2\x66\x48\x39\x1e\xb3\x50\ -\xaf\xf1\x0f\xbf\xf2\x55\x3e\xfb\x52\x9b\x3c\x99\xdd\xbb\xa2\x80\ -\x3f\xfd\xd6\xb7\xd8\xde\xdd\x65\x3a\x29\xa9\x52\xcd\x8b\x97\x2f\ -\xb3\xb8\xd0\x41\x5a\x16\x1b\xbb\xdb\xb4\xbb\x6d\x9a\xcd\x88\xd5\ -\xd5\x55\xce\x9c\x58\xe2\xbd\x6b\x1f\x10\x36\x1a\x2c\x2c\x2c\xd2\ -\xa8\xfb\x0c\x06\x29\x1a\xe8\xef\x1f\x30\x9e\x0c\x39\x7f\xe6\x14\ -\xfd\x41\xcc\xbd\x3b\xb7\x39\xb5\x7c\x9c\x9d\xad\x0d\xbe\xfa\xf9\ -\xcf\x8b\xb2\x2a\x08\x3c\x07\x57\xda\xe8\x99\x84\x58\x9a\x7b\xa5\ -\x20\xd7\x90\x95\xe6\x45\x2b\xf3\x02\x27\xab\xe8\x54\x88\xdf\xb8\ -\xfa\x59\xc6\x9b\x1b\xd8\x94\xb0\xb7\xce\x34\x1d\x51\x6f\x47\x50\ -\x95\xf4\x77\x37\x69\x35\x2c\x92\x78\x97\x64\x74\x80\x6c\x75\x11\ -\x5e\x97\xc2\xee\xf2\x6f\xbf\xff\x2e\x6b\x43\xc8\x24\xc4\x96\x45\ -\xe9\x49\x52\x32\x16\x16\x3b\x9c\x3d\xb9\x4c\xdb\x8f\x78\x74\xfb\ -\x1e\xa3\xfe\x80\x30\x0c\x67\xee\x16\xfe\x1e\x69\x23\x8e\x8d\x20\ -\xe4\x13\x9f\xf8\xc4\xbf\x93\x39\x3c\x26\xcb\x0a\x9a\x0d\xe3\x82\ -\xd9\xdf\xdf\x67\x79\x79\x99\x3c\xcf\x19\x8e\x8a\xa3\x5d\xa9\x15\ -\x49\xb4\xd6\xc4\x71\xc6\xe6\xe6\x26\xaf\xbe\xfa\x2a\x2f\xbf\xfc\ -\x32\xe3\xf1\x98\x0f\x3e\xf8\x80\xd1\x68\x84\xd6\x9a\xf1\x78\x46\ -\xd4\xdc\xdd\xa5\xd7\xeb\x11\x45\x36\x41\x10\xa0\x94\xf9\x5a\xad\ -\xf5\xac\xd1\x65\xba\xec\xf5\x7a\x7d\xf6\x7d\xa7\x38\x0e\xc4\x69\ -\x8c\xa2\xe4\xfc\xd9\x63\xcc\xf5\x5a\x5c\xbc\x70\x9a\xe5\xf9\x0e\ -\xe7\x4f\x2d\x93\xc7\x63\x76\x36\x37\xf9\xdb\x1f\xfe\x88\xeb\xef\ -\xdf\x60\xf5\xf1\x3a\xfd\xc3\x09\x95\x86\x1f\xfc\xf0\x1d\x56\x77\ -\x87\xa8\xa8\x45\x1f\x49\x66\xd9\x38\xae\x8f\x27\x6d\x82\x0a\x7c\ -\x61\x99\x67\xa6\x4c\x70\x1d\x03\x9d\xcf\x8b\x98\xa2\xc8\xd0\x45\ -\x8e\x28\x0a\x3c\x61\x43\x5c\x50\xf3\x6a\xf8\xc2\xc1\x03\x3c\x4b\ -\xe2\x68\x8d\x67\xdb\x84\x96\x85\x27\x6d\x84\xb0\x71\xb0\xb0\xb5\ -\x9c\x29\xbb\x14\x54\x39\x95\xca\xa8\xa4\x42\xb8\x16\x99\x50\xe0\ -\xd9\x64\x2a\x47\x3b\x86\xe6\x89\xed\x50\xa1\x50\xaa\xc0\xb2\x04\ -\xb6\xd0\xa0\x0a\xd2\x78\x88\x67\xc3\x74\x7f\x97\xae\xe3\x10\x6a\ -\x88\x24\x58\x55\x81\x28\x32\xdc\xd0\x25\xe9\x1f\x22\xca\x92\x6a\ -\x12\x93\x1e\x0e\x61\x9c\xa0\xf6\xfa\x90\x94\x94\x5a\x22\x5a\x3d\ -\xf0\x02\x3a\xc7\x4f\x62\x05\x01\x61\xab\xc5\xa4\x2c\x71\x5b\x4d\ -\xfa\xd3\x18\xe5\x48\xaa\x59\x86\x95\xa6\x22\x9d\x4c\x28\xd2\x84\ -\x7a\xad\x46\x91\x4c\xf1\x2c\x89\x50\x05\x65\x92\x82\x84\x24\x1e\ -\x23\x85\x46\xcc\xac\x5d\xc3\xfd\x1d\xd2\xe9\x18\x2c\x0b\xaf\xd7\ -\x33\xdb\x56\x10\x92\x58\x2e\xa9\xeb\xb3\x97\x16\x7c\xe7\xe7\x1f\ -\xf2\xbf\xfe\xe0\x1d\xfe\xc5\x3b\xb7\x39\x90\x4d\xa4\xdb\x21\x14\ -\x40\x1f\x4e\x79\xe0\x27\x03\x54\xbc\x85\xe3\x8c\x11\xee\x88\x34\ -\xdf\x65\x61\xde\xe5\x37\xbf\xfa\x06\xbf\xfa\xda\x71\xd4\x81\xb1\ -\x29\x4c\x80\xff\xeb\xdb\xdf\xe5\xbd\xd5\x55\x56\xc7\x63\x72\x29\ -\x38\x71\x6c\x99\x85\x86\x20\x49\x32\xec\x00\x52\x14\xa5\x6b\x51\ -\x59\x20\x5c\x8f\x9f\x5c\xfb\x98\xe7\xaf\xbc\x48\x59\x29\xdc\xc0\ -\xe5\x70\x30\x25\xaa\xf9\xf8\xae\xcd\xfe\xc1\x2e\x0e\x92\x22\xcb\ -\xd9\xdd\xde\xc6\x16\x92\x30\x08\x58\x5e\x3a\x46\xa5\xc1\x97\x0e\ -\xd3\xe1\xd8\xa8\xf3\xa4\xfc\x85\xf8\x47\x83\xc1\x86\x5a\x12\x2c\ -\xb0\x10\x38\xaa\xc2\x53\x70\xe9\xf8\x71\x4e\x75\xbb\x9c\x3f\x7e\ -\xcc\xdc\xe1\x54\x4e\x1c\x8f\xc1\xb5\xe9\x74\x5b\xec\xae\xaf\x62\ -\x5b\x1a\xbf\xd1\xa0\x52\x15\x49\x0e\x7e\xa3\xc7\xc1\x24\xe7\x5f\ -\x7f\xeb\x87\xfc\x3f\x6f\x7d\xc0\x8b\x9f\xf9\x0c\xca\x82\x69\x99\ -\x33\x1a\x4f\x08\xc3\x80\x46\xad\xce\xb1\xf9\x25\x36\x37\x36\x50\ -\x4a\x99\x24\x03\xa5\x89\xe3\x98\x7e\x7f\x61\x9b\x27\x6a\x00\x00\ -\x20\x00\x49\x44\x41\x54\x4a\xad\xe6\x13\x86\x3e\x3b\x3b\x3b\x34\ -\x9b\x0d\x5e\x7d\xf5\x32\xed\x76\x9b\x1b\x37\x6e\xe0\xba\x0e\x4f\ -\x9e\x1a\x21\xc9\x70\x38\xa4\xd5\x6a\xd1\x6e\x07\x74\x1a\x0e\x59\ -\x96\x31\x9d\x4e\xd9\x39\x4c\x48\x92\x84\x5e\xcb\xc3\x71\x4c\xa8\ -\x79\xbb\xe9\x72\xfe\xfc\x79\x96\x97\x97\x19\x0c\x06\xfc\xe4\x27\ -\x3f\x39\x92\xfd\x19\x55\x99\x4b\x96\x71\x44\xf0\x6f\x36\xcd\xd7\ -\xda\x36\x47\x2c\xe1\x67\x67\x79\x73\xac\x00\xdf\xf5\x08\x7d\xdb\ -\x64\x3e\x37\x5b\x8c\x06\x43\x8e\x1d\x3b\x46\xa7\xd9\xe2\xc4\x89\ -\x13\xf4\x7a\x3d\xbe\xf8\xa5\xaf\x70\xe6\xfc\x45\xfc\x5a\x93\x58\ -\x49\x7e\x7e\x63\x93\xbb\x2b\xeb\xec\x8c\x12\x0e\xd3\x8c\x51\x9a\ -\x32\x9e\x26\xc4\xd3\x94\x22\x49\x29\xd3\x0c\x95\x24\x90\xa5\xe8\ -\xaa\xa0\xd2\x05\x5a\x2b\x90\x1a\x21\xb5\xb9\xe1\x59\x36\xae\x6d\ -\x83\x02\x0a\xb3\xa3\x96\x79\x81\xca\x52\xf2\x2c\x21\x4f\xa7\x24\ -\x49\x42\x9e\x66\xe8\x2c\xa3\xcc\x9f\xb9\x86\x0c\x64\x41\x30\x4b\ -\xa2\x90\x82\xca\x9a\xb5\x3f\x2d\xd0\x96\x78\xd6\x0a\x05\x29\x8e\ -\x9a\x92\x9a\xca\x18\x31\x74\x85\x63\x09\x6c\x14\x9e\x63\x91\x4c\ -\x26\x14\x71\x4c\x91\x24\xe4\x69\x42\x92\xc6\xe4\xc9\x04\x92\x09\ -\x49\x1a\x1b\x17\x91\xb4\xf0\xa2\x1a\x6e\xab\x83\xd7\x6a\xe3\x87\ -\x11\x5a\x08\x28\x4b\xb2\x22\xa7\x50\x9a\x82\x8a\xca\x12\x28\x61\ -\x50\x9f\xc2\xb6\xb0\xec\xd9\x38\x0d\x66\x51\x3d\xb3\xa6\x9d\xb4\ -\x8e\xe4\xa8\x51\x2d\xc2\x72\x5c\x50\x8a\x2c\x4d\xc9\xb3\x8c\x59\ -\xb6\x2d\xd8\x36\xb6\xef\x61\x7b\x2e\xd4\xea\x64\x55\xc5\x28\x8e\ -\xd9\x39\x38\x24\x45\x50\x9b\x3b\xc6\x83\x8d\x7d\xfe\xe6\xce\x0a\ -\x45\x08\x4f\x0f\x27\x3c\x58\xcd\x58\x5c\x82\xad\x7d\x28\x8b\x29\ -\xbf\xfa\xb5\x2f\x12\xd8\x15\x67\x8f\x2f\xd1\x69\x78\x34\x03\x87\ -\xaf\x7f\xfe\x0a\xf1\x00\xea\x35\xc8\x2a\xf8\xe3\xef\xbc\xcd\x5f\ -\xfd\xec\x1d\x82\x85\x79\xb6\x07\x03\x96\xcf\x9c\x61\xa1\x17\xb0\ -\xb5\x39\x61\xa1\xed\xb1\xbe\xb9\x87\xe5\xdb\xd8\x81\xc7\xe3\xf5\ -\x6d\xb6\x77\xf7\x38\x76\xfc\x24\xcd\x56\x44\xb7\xdb\x26\x9e\x9a\ -\x72\x7a\x7d\x7d\x83\x0f\x3e\xf8\x80\xb3\xa7\xcf\xd0\x6e\xb7\xf1\ -\x5d\x8f\xc7\x8f\x1f\x19\x78\xe3\xed\x3b\x2c\x2f\x2e\x61\x01\xaa\ -\x2c\x68\x36\x9b\x7f\x4f\xd1\x67\x3f\x93\xf1\x55\x68\x84\x94\x08\ -\x66\x7d\x6c\x25\x90\x02\x96\x3b\xae\xb8\xfa\xc9\x57\xf4\x77\x6e\ -\xdd\x01\xcf\x33\xa2\x83\x4c\x63\x45\x01\x4e\xe0\x43\x3f\x45\xeb\ -\x3a\x52\x08\x50\x50\x56\x8a\x66\x14\x31\x8a\x87\xfc\xe4\x9d\x77\ -\x18\x9c\x3d\xc6\xf2\x7c\x1d\x5b\x2d\x70\xb2\xd7\x30\x6d\xff\x38\ -\x47\xa9\x92\xa5\xc5\x63\xb8\x77\xee\xb2\xbe\xbe\xce\x99\x33\x67\ -\x70\x1c\x93\x0f\x6b\x59\x70\x70\x30\xa4\xd5\x6a\xf2\xdc\x73\xcf\ -\x31\x9d\x26\xa4\xa9\xe4\xe4\xc9\x79\x7c\xdf\xe7\xed\xb7\x7f\x4a\ -\xbb\xdd\x66\x69\x69\xfe\x68\xe4\x94\xa6\x50\x98\xe7\x97\x63\x0b\ -\x0d\x26\x89\xd1\x60\xf7\xc7\x25\x07\x07\x07\x2c\x2e\x2e\x32\x1c\ -\x1b\x21\xc7\xd2\xd2\x02\xcb\xcb\x0b\x64\x99\xe2\x83\x0f\x3e\x20\ -\xcf\x8d\xc8\xe0\xc4\x89\x13\x34\x9b\x3e\x55\x15\xa0\x94\x62\x3c\ -\xae\x66\x0b\xd8\x28\xbe\x86\xc3\x21\x57\xae\x3c\x8f\x65\x41\x59\ -\x3a\x64\x69\x61\x04\xfd\x0a\xb2\x34\xa1\x19\xf9\x26\xe1\x71\x6e\ -\x0e\x27\xa8\x21\x1c\x87\x56\xd8\xc0\x71\x21\xf5\x2d\xda\xf5\x39\ -\x3e\xba\xbf\xcf\x77\x7f\xfa\x33\xb6\x92\x9c\xfa\xd2\x31\xb6\xd2\ -\x1c\xb4\xa6\xb2\x24\x95\x34\xb3\xf8\xd2\xb2\xa0\x54\x90\x26\xa8\ -\x5a\x84\x55\x55\xe8\xca\x3c\x47\x55\x55\xcd\xae\x59\xb7\x57\x4a\ -\x84\x6d\x21\x6d\x1b\xd7\x12\x08\xdb\x94\xcf\xe8\x59\xd2\x42\x66\ -\x2c\xa2\xb6\x94\x58\x8e\x83\xd2\x95\xe9\x54\x6b\x6d\xba\xd0\xb3\ -\xef\xa7\xb5\xe9\x10\x6b\xad\x29\x75\x65\xf4\xd9\x52\x92\x8e\x06\ -\xa0\x21\xd3\x95\x61\xe9\x8e\x86\x24\xb6\xa0\xc8\x52\x4a\x55\x19\ -\x66\x34\x20\x5d\xcf\x28\xcc\x8c\x82\x1b\x2a\x1f\x2f\x0a\x0d\xe1\ -\xd1\x75\x4c\x55\xa3\x2b\x84\x94\x68\x29\x10\xae\x83\x9e\x09\x3e\ -\x8c\x24\xb2\x04\x4c\xfa\xc6\x33\x6d\xe9\xb3\x9b\x6c\x51\x14\x58\ -\xc2\xc2\xb2\x0c\x6e\x49\x5a\x8e\x51\xb7\x09\x4d\x96\xe6\xe6\xa6\ -\x57\xe4\xe0\x1a\xf8\x3c\x8e\x83\x74\x6c\x1c\xc7\xfc\xdc\xa2\x28\ -\xc0\xb2\xd0\x4a\x11\xd5\x4c\x2e\xf6\x33\x81\x49\x6b\x7e\x91\x8f\ -\x6f\xdc\xe4\x5b\xbd\x63\xbc\x72\xe1\x02\x93\xc0\xe1\xc7\xf7\x0e\ -\xc9\xc9\x58\x38\x7d\x9c\x97\x4f\x2c\xf0\x37\xef\xff\x9c\xbb\xf7\ -\x1f\xf1\xca\x8b\x9f\x64\xce\xab\xe3\x02\x3a\x84\x41\x02\xdf\x79\ -\xfb\x03\xae\xdd\xba\x49\x92\x17\xa4\x07\x09\x97\x2e\x5f\x9e\x4d\ -\x35\xc0\xf7\x43\x26\x29\x86\x9a\x7a\x6c\x99\xad\x8d\x4d\xca\xf1\ -\x94\x76\xb3\xc9\xf2\x42\x8b\x9d\x83\x09\xb6\x6d\xb3\xb2\xb2\xc2\ -\xe7\x3e\xfb\x3a\x3b\x3b\x3b\x7c\xe6\xd3\xaf\x71\xe3\xc6\x0d\x2e\ -\x3f\x7f\x91\x0f\xae\x7f\xc0\xe5\x4b\xcf\x33\xee\x1f\xf0\xf8\xe1\ -\x03\x5e\xfb\xe4\x8b\x7f\x20\x05\x58\xb6\x03\x18\x71\x8f\xed\x78\ -\x33\x41\xc8\x9b\x6f\xce\x86\x15\xda\xa8\x5a\x85\x21\x0c\x48\x24\ -\x15\x82\xca\x02\xbf\xbd\xf0\xe6\xff\xf1\x47\xff\x12\xa7\xde\x44\ -\x3a\x1e\x65\xa1\xb1\x5d\x13\x3e\x65\xd7\x43\xc3\xa7\x8a\x33\x90\ -\x36\x6e\x10\x60\x59\xb6\x21\x17\x48\xcd\xee\xd6\x1a\xc3\xc3\x03\ -\xfe\xc1\xd5\xd7\x09\x5c\x49\x32\xce\xa8\x07\x1e\xa1\xe7\x70\x70\ -\x30\x62\x67\x7f\x97\xc5\xc5\x45\xb6\xb7\xb7\x71\x1c\x0f\xcf\xf3\ -\x98\x4e\x13\x6a\xb5\x1a\x0f\x1e\x3c\x60\x3a\x9d\x72\xfa\xf4\x71\ -\xca\xd2\x50\x32\x4f\x2f\x34\x38\x7e\xe6\x04\x73\x73\x73\xfc\xe5\ -\x5f\x7e\x8f\xc1\xc0\x80\xea\xeb\x75\x97\xf1\xd8\xe0\x69\xfd\xd0\ -\xa5\x34\x5d\x79\x92\xc4\xec\xcc\x2f\x3f\x7f\x1a\xc7\x33\x38\xde\ -\x62\x26\xe9\x2b\x8a\x82\x97\x2f\x9d\x22\xce\x14\xa3\x91\x01\x17\ -\x0c\x87\x13\x83\x4a\xf5\x3c\xc2\xd0\x03\x04\xb5\x9a\x85\xeb\x7a\ -\xac\xae\xae\xd3\xeb\xcd\x71\x70\x30\xc0\xf7\x03\x82\xc0\x22\x74\ -\x5d\x6c\x2c\xea\xa1\x47\xa5\x04\xfd\xc3\x01\xb6\xe3\x10\xd4\xea\ -\x0c\xe3\x84\xd2\x72\x58\x1f\xa6\x4c\xa5\xc3\x7e\x02\xff\xf6\xfb\ -\x3f\xe6\xc7\xd7\x3f\x80\xa8\x81\xa8\xd5\xa9\x1c\x97\xd2\xb6\xb1\ -\x5c\xc7\x48\x65\x31\x9e\x62\xad\x81\x3c\x47\x97\x25\x65\xa5\x28\ -\xd3\x1c\x95\x26\x14\x79\x81\x4a\xa6\x54\xf1\x94\x22\x4b\x61\x67\ -\x8f\xbc\x52\x64\x79\x46\x11\x4f\x28\xb2\x94\x22\x4d\x29\xa6\x53\ -\xa3\xf6\xaa\x2a\xaa\x19\x64\x5f\x69\x4d\x9e\x67\x54\x45\x8e\x2a\ -\x0b\xaa\x2c\xa3\x8a\xa7\xe4\x65\x4e\x35\x99\x42\x3c\x41\xcf\xf2\ -\xac\x54\x9a\x53\x66\x99\xa9\x1d\x1d\xc7\xc8\x39\x1d\x9b\x2a\x4d\ -\x11\xb5\x08\xdb\x92\x58\x9e\x87\x32\x92\xb6\x99\x00\xc4\xc6\xf1\ -\x8c\xd0\xa4\x92\x82\xb0\x51\x3f\xd2\x4e\x6b\xa0\x54\x8a\x52\x57\ -\x68\x31\xf3\xfc\x6a\x8d\x00\x6c\x29\x11\xb6\x30\xee\xc1\x99\xb6\ -\x5a\x57\xda\x58\x06\x67\xfd\x09\x69\x59\x08\x29\xc9\xcb\x82\xb4\ -\x2c\x50\x95\xa2\xcc\xcb\x19\xb9\x32\x37\x12\x51\xdf\xc3\x0d\x43\ -\x3c\xdf\xc7\x72\xec\xa3\x23\x5a\x59\x96\xe6\xbb\x66\x19\xf5\xa6\ -\x19\x31\x5a\xd2\x62\x1a\x4f\x08\x7c\xd7\x28\xf6\x46\x23\x36\xf7\ -\x76\xf8\xf3\xef\xfd\x25\xef\xdd\xfe\x18\xb7\x55\xa7\xb3\xb8\x48\ -\xaf\xed\x10\xd5\x7a\xa4\xc3\x98\x5f\xff\xd2\xd7\x99\x6f\xcd\xd1\ -\xa8\xb7\x88\x42\xf8\xc9\xf5\xc7\xfc\xb3\x3f\xf9\x13\xec\x56\x1d\ -\xb7\x55\x67\xb8\xb5\xc1\xd5\x57\x3e\xcd\xe7\x3f\xf9\x49\xbc\x0c\ -\x1a\x91\xa0\x3f\x8a\x99\x9b\xaf\x93\x2b\xcd\x3b\x3f\xfd\x19\x17\ -\x4e\x9f\xe5\xc4\xb1\x65\x90\x82\xbd\x83\x43\x8e\x9d\x58\xe6\xe9\ -\xd3\xa7\x1c\xec\xf5\xe9\xf5\x7a\x04\x7e\xc0\xea\x93\x15\x7c\xd7\ -\xa3\xaa\x4a\x5e\x7e\xe1\x79\x7e\xf8\xd6\x0f\xe8\x75\xda\x5c\xb9\ -\xfc\xfc\xe7\xec\x59\x19\x3d\x1e\x0d\x09\xa3\xc8\x4c\xf7\x84\x30\ -\x49\x13\x92\xca\x28\x61\xd0\x66\x84\x61\x99\x91\x91\xac\x40\x17\ -\xf0\xd2\xc9\xf6\xb5\x0b\x73\xf3\xaf\xae\xa6\x05\x4e\xc7\x67\xbf\ -\x2a\x29\xe2\x09\xd2\x77\x69\xd5\x1a\x64\xfb\xfb\x26\xb2\x32\xf2\ -\x11\x42\x90\x15\x39\xbe\x1f\xe0\xd7\x5c\xd6\x0e\x36\x78\xef\xe6\ -\x6d\x7e\x7e\xf3\x0e\x5f\xfc\xd4\x15\x2c\x6c\x0e\x47\x39\x2d\xcf\ -\x25\x2f\x14\x27\x8e\x9b\x2c\xa8\xd3\xa7\x4f\xf3\xe8\xd1\x23\x82\ -\x20\xe0\xf2\xe5\xb3\x4c\x26\xe5\x51\x49\x9c\xa6\x25\x8d\x86\x8b\ -\x6d\xdb\x7c\x74\x7f\x8d\xb9\xb9\x39\xf2\x3c\xe7\xb7\xff\xfd\xaf\ -\xf3\x57\x6f\xbd\xcd\x83\x07\x0f\x66\xfc\xad\x36\xa7\x4f\xf4\xd8\ -\x3b\x4c\xc8\xf3\x9c\xf9\xf9\x26\x7b\x7b\x31\x00\x7b\xc3\x9c\x34\ -\x35\x5d\xbe\x4e\xa7\x31\xc3\x06\xb9\xec\x0e\x73\xf2\x3c\xe7\xf9\ -\xe7\x9f\xa7\xd5\x6a\xd1\xef\xf7\xd9\xdd\xdd\x65\x67\x67\x07\xad\ -\x35\x4b\x4b\x4b\x06\xbb\x23\x04\x41\x10\xd0\x9d\x95\xea\xae\x2b\ -\x88\xc7\x05\xae\xe5\x50\x95\xcc\x4a\x1e\x28\x0b\x4d\x10\x36\x90\ -\xae\x8b\x2d\x6c\x0a\x5b\xe2\x34\x02\x26\x12\x7e\xfc\xb3\x8f\xf9\ -\xe9\xcd\x5b\x64\xd2\x81\x5a\x83\x71\x92\xd0\xec\xf6\xa0\x2c\xb0\ -\xe5\x4c\x54\x51\x98\x68\x9b\xca\x29\xc9\x54\x89\xdf\x30\xb6\xce\ -\x4a\x99\xb1\x8b\x25\x1d\xca\x4a\xa1\x94\xc6\xb5\x2d\x92\x0a\x6a\ -\xad\x06\xd8\x16\x49\x69\x7c\xc7\x0a\x0d\xe5\xac\xfc\x8f\x67\xbb\ -\x95\xb4\x50\x9e\x3b\x63\xc3\x58\x66\x77\xd5\x1a\xaf\x56\xc7\x73\ -\x2c\x53\x5d\xa4\x09\x96\xe7\xe3\x7a\x9e\x99\x05\x0b\x41\x96\x25\ -\x38\xb6\x8d\x72\x1d\xd3\x6d\x9d\x1d\x41\x6c\x5b\x62\x7b\x3e\xba\ -\x82\x42\x6b\xa4\xe3\x52\x29\x65\x98\xdc\xba\x82\x3c\x67\x9a\x24\ -\x47\x01\x6a\xf6\x6c\xf6\x0b\xa6\x6a\xa3\x2c\xa1\x28\xd0\xb6\xc4\ -\x76\x1c\xd3\x84\xb3\x2c\xf2\xb2\xc4\xb2\x2d\xaa\x52\xa1\xa9\xf0\ -\x3c\x9f\x34\x9e\x62\x0b\x9b\xb2\x50\x24\x69\x62\xdc\x7a\x33\x9b\ -\x66\xd4\x68\x91\xda\x8e\xd1\x42\x7b\xae\xd9\x85\x2d\x8b\xac\xfc\ -\x85\xb4\xd3\xf7\x7d\x2c\x5f\x30\x1e\x0c\x38\x3c\x3c\xc4\xf3\x3c\ -\x7c\xd7\xc3\xf7\x43\xb2\x2c\x65\x32\x9a\x30\x49\x33\x1e\xed\x6c\ -\xa0\x0e\x0f\x78\xe1\xd5\x4f\xf2\x57\xd7\xde\xe7\xdf\xbc\xf5\x16\ -\xbf\xf9\xb5\xaf\xd1\x8e\xea\xfc\x67\xbf\xfd\x9f\xb2\xd4\x93\xdc\ -\xbb\xd7\x67\x7b\x27\xe1\x83\xad\x1d\xbe\xff\xf6\xdb\x0c\x51\x14\ -\x59\x82\x16\x92\xc6\xf1\x53\xec\xef\x1f\xd2\x6a\x40\x94\xc1\x74\ -\xa8\xa9\x05\x11\xa3\x51\xce\xe1\xe1\x01\xe9\x24\xe6\xc4\xd2\x31\ -\xaa\xa2\xe4\x20\x4e\x39\x7e\x72\x11\x01\x0c\xfa\x23\x3c\xdb\xe3\ -\xc4\x89\x13\x6c\x6f\x6e\x10\x86\x21\xb7\x6f\xde\xe2\xeb\xbf\xfc\ -\x15\xee\xdf\x7d\xc0\xfd\x3b\x77\xf9\xda\x7f\xf9\x5f\xe0\x4a\x81\ -\x52\x15\x96\x25\x8f\x4c\x26\xbf\x30\x4d\xbc\xf9\x7b\xa6\xa4\x31\ -\x05\xd7\xcc\x6d\x22\x10\xda\x94\x49\xb6\x99\xef\xff\xef\x4e\xd8\ -\x7d\xf3\xed\xf7\xde\xa7\xde\xe9\x51\x59\x0e\xc9\xe1\x01\xfe\xc2\ -\x02\x79\x9a\x61\x4b\x13\x1e\x8e\xe5\x80\x90\x28\x2a\xb0\x20\x4e\ -\x62\x82\xc0\xa3\x54\x05\x77\x6e\xdd\xe0\xd2\x85\x4b\x9c\x39\xd6\ -\x22\x89\x15\x79\x52\x52\x64\x19\x41\xe8\xb3\x7c\xbc\x4b\x55\x49\ -\xda\xed\x36\x00\x2b\x2b\xab\xd4\xeb\xf5\xa3\xdc\xe1\x30\x0c\x8d\ -\x0f\xb6\x28\x99\x9b\x6b\x53\x8f\x6c\x4a\x25\xf8\xe0\xe3\xdb\xf8\ -\xbe\xcf\xb9\x73\xe7\xf0\x3c\x8f\x5b\xb7\x6e\xa1\xb4\x45\xab\xd5\ -\xa2\xd1\x08\xe8\xf7\x63\xb6\xb6\xb6\x58\x58\x58\xa0\xd3\x69\x10\ -\x45\x1e\xb6\x6d\x14\x35\xc3\x61\xca\xc1\x81\x99\x43\xef\xee\xee\ -\x1a\x70\x7d\xd3\x25\x88\x6a\x74\xbb\xff\x1f\x63\xef\x15\x64\xe9\ -\x99\xde\xf7\xfd\xde\xf0\xa5\x93\x3b\xa7\xc9\x09\xc0\x20\x2e\x30\ -\x48\x04\x96\x0b\x72\x97\xb4\x18\x44\x4a\x22\xb5\x2c\xd9\x32\x25\ -\xd9\x65\xda\x0a\xb6\xca\x17\x2c\xf1\xc2\x36\xc9\x2a\x5f\x98\x37\ -\xbe\xb1\xaf\x54\x72\x95\xaf\x6c\x97\x28\x53\x45\xd3\x14\xc5\x8d\ -\x4c\xc0\x2e\xc2\x22\xcc\x2c\x80\x49\x18\x4c\x9e\x8e\xa7\xfb\xc4\ -\x2f\xbe\xef\xeb\x8b\xf7\xeb\x33\x83\x25\x8b\x72\x57\x9d\xea\x9e\ -\x9a\x0e\xa7\x4f\xbf\xe1\x79\xfe\xcf\x3f\x2c\x32\x3f\xef\x23\x63\ -\x26\x93\x09\x07\x07\x07\xb3\xf9\x71\xa7\xbb\x58\x0b\x33\x24\x45\ -\x6e\xa8\x32\x43\xa0\x14\xe9\x38\x43\x28\xc1\xad\x5b\x37\x39\x7e\ -\xea\x24\xa5\x71\xe8\xa6\x22\x97\x50\x6a\xf8\xf0\xca\x26\x7f\xfc\ -\xe6\xf7\x19\x18\x47\xa6\x02\x8c\xd4\x24\xf3\x0b\x14\x55\x81\xa9\ -\x1e\x4a\x11\x9d\xad\x47\x36\xce\x9b\xd4\x57\xce\x61\x81\xca\x78\ -\x06\xd9\xe1\x1c\xd5\x5a\xe7\x35\xb4\xd3\x14\x15\x45\x48\x25\x31\ -\xce\xcf\x14\x91\x62\x56\x1a\x87\x51\x84\x01\x64\x1c\xd3\x68\x36\ -\x09\xc2\x00\x19\x04\x04\x71\x84\x0a\x3c\x1d\x12\xe1\xdd\x5a\x28\ -\x0b\x9c\x90\x58\x29\x30\xd6\x61\x71\x38\x63\x10\x52\xa2\xa4\x24\ -\x2f\x72\x90\x12\x53\x96\x28\xe5\x67\xd1\x56\x6b\x4c\xdd\x96\x39\ -\x6b\xbd\xdb\x8c\x35\xbe\x9a\x08\x03\xc2\xba\xbc\x75\xce\x61\x6b\ -\xa2\x86\xb1\xde\xf9\x40\x48\xed\xb5\xd4\x51\x84\xa8\xc7\x66\x45\ -\x59\x12\x46\x91\xd7\xb9\x5b\x8b\x29\x2b\xdc\xc1\x01\x56\x07\x9e\ -\x40\x54\x55\x10\xc6\x7e\xf4\x16\x84\x24\x71\xe4\x67\xc9\x35\x11\ -\xc4\xd5\x25\xb9\xb1\x16\x6b\x4c\x8d\x76\x6b\x84\x83\x62\x32\xc1\ -\xd5\x72\xd9\x3c\xcb\x98\x66\x53\xaf\x31\x6e\x37\xc8\xad\x25\x99\ -\xef\x51\x8e\x0e\xd8\x29\x72\x5c\x10\xd2\xed\xf6\xb8\xf8\x83\x8f\ -\x90\x95\xe0\xcb\xaf\x9c\x67\x2d\x82\x3b\x3b\x96\x3f\xf8\xc6\xb7\ -\x78\xf3\xbd\x77\xb9\xb6\x79\x9f\xb9\x93\xc7\xd8\xcf\x33\x74\x1c\ -\xd2\x8e\x62\x8e\xcd\x2d\xf0\xe4\xb1\xc7\x59\x6b\x0a\x4c\x2e\x18\ -\x97\x29\x77\xef\xdf\xa5\xd5\x6a\x92\x4e\xa6\x3c\x79\xf6\x14\x59\ -\x56\x52\x39\x4b\xab\x11\xf1\xe9\x95\xcf\xf9\xfc\xf3\xcf\xf9\x89\ -\x37\xde\xa0\x99\x28\x96\x7b\x1d\xbe\xf7\xbd\x77\x39\x79\xec\x08\ -\xf3\x73\x3d\xae\x5f\xb9\xcc\x5c\xb7\xc3\x6b\xaf\xbe\x22\x04\x02\ -\xe1\xbc\xa3\x67\x12\xc7\x14\x79\x8e\x54\xfa\x10\xec\xb2\xb3\xc2\ -\xda\xe2\x87\xeb\x16\x87\xab\xd7\x83\x76\xa0\x72\xf8\xf9\xd7\x9f\ -\x67\x29\x08\xc8\xf7\xf6\x88\x15\x10\x05\x14\x55\xc9\x64\x92\xd2\ -\x68\x74\xd0\x51\x04\xb5\x24\xad\xc2\x61\x85\x64\x5a\x95\x0c\xf3\ -\x9c\xe5\xe3\xa7\xe8\x67\x25\xff\xf7\x1f\xfd\x31\x37\x37\x33\xba\ -\x8b\x21\xad\x4e\xc4\xdd\xfb\x9b\x08\x25\xb9\x73\x67\x87\x46\x43\ -\xd2\x68\x84\x34\x6b\x6b\x97\x2b\x57\xae\x70\xf7\xee\xdd\xda\x68\ -\xde\xf3\x55\xa7\xd3\x29\xcd\x00\x6e\xdf\xdd\xa3\xdb\x0d\x19\x8d\ -\x46\x3c\xfd\xf4\x53\x74\xbb\x4d\x16\x17\xe7\x78\xf5\xd5\x57\x91\ -\x52\xf2\xd6\x5b\x6f\xf1\xde\x7b\x1f\xd1\xe9\x34\x99\x4c\x26\xac\ -\xae\x2e\x53\x14\x96\x2c\xb3\xec\xef\xef\x33\x9d\xfa\xb0\xb6\xa3\ -\x47\x17\x67\xf1\x94\x79\x9e\x33\x18\x1b\xf2\xbc\xa2\xd1\x50\xb4\ -\xdb\x09\x41\x10\x70\xe6\xcc\x29\x4e\x9c\x38\x41\xab\xd5\xa2\xd1\ -\x68\xf0\xce\x3b\xef\xf0\xfe\xfb\xef\x73\xe7\xce\x66\x6d\xbe\x1f\ -\xd2\xe9\x42\xbb\x17\x23\x25\xb5\x89\x3d\x4c\xb2\x94\x69\xea\x18\ -\x4e\x2c\x9f\x5e\xde\xe4\xf7\xff\xf0\xdf\xf1\xf9\x9d\xbb\x34\xda\ -\x1d\x98\x4c\xc1\x39\x9c\xd2\xde\xe6\xa6\x2a\x29\xaa\x8a\xa2\xaa\ -\x28\x8d\x7f\x14\x55\xe5\x81\xa2\x3a\x05\xf2\x47\x1f\xba\x7e\x4f\ -\x5d\x7a\x1b\x57\x0b\xfe\x94\x44\x05\xfe\xf6\x8b\xa2\xc8\x8f\x68\ -\xa4\x97\x03\x1a\x67\x29\x8c\x07\x98\xb2\x2c\x23\xcf\x52\x74\xf8\ -\xf0\x7b\x12\x04\x5f\xf8\x79\x3a\x08\x50\x61\x80\xd0\x8a\x46\xcb\ -\xc7\xe8\xb4\x5a\x2d\x70\x16\xa9\xd5\x43\xc6\x55\x1d\x15\xeb\x9d\ -\x4a\x25\x81\x0e\x40\x69\xb4\x54\x04\x5a\x23\x85\xc0\x1a\x83\x29\ -\x4a\x4c\x51\x22\x8d\x23\x92\x9a\x46\x12\x43\x91\x23\x9d\xc5\x9a\ -\x12\x5b\x95\xb8\x3c\xc5\x54\x05\x55\x51\x60\xd3\xcc\xdf\x3c\x85\ -\xaf\x28\x54\x10\x42\x10\x11\x35\x5a\x44\x8d\x26\x71\xe2\xe3\x72\ -\xab\xfa\xb5\xf2\xd1\x2e\x75\xcf\x2e\x25\x4a\xeb\xba\xaa\xc8\x7d\ -\x35\x96\x24\x33\xef\xaf\x6c\x34\x82\xca\x52\xec\xf5\x89\x93\x36\ -\x38\x49\xa1\x14\x2c\x2f\xa3\x16\x16\xd1\x9d\x1e\xf7\xf7\x87\x2c\ -\x6c\x1c\x23\xee\xcc\xf3\xf6\x07\xf7\xb8\x7e\x00\x77\x76\xfa\xfc\ -\xc9\xf7\xde\xe1\xc1\x68\x82\x6b\x34\x29\xb4\x42\xb7\x9a\x44\x0d\ -\x6f\x6d\x7c\xe1\xd9\x2f\x31\x39\x18\xb2\xbf\x0f\xc6\x58\x0e\x0e\ -\xfa\x48\xad\x58\x5f\x5d\xa6\x99\x34\xc8\x33\x43\xbb\x15\x83\x93\ -\xdc\x7d\xb0\x0f\xc0\xc6\xda\x9a\x1f\xc9\x59\xb8\xf6\xf9\x5d\xca\ -\xb2\xe4\xb1\xc7\x1e\xa3\xcc\x72\x06\x07\x07\xfc\x9d\xbf\xfd\xb7\ -\x7f\x57\x2b\x2f\x39\x15\x7e\x3b\xcf\xda\x86\x19\xd8\x75\x48\xe7\ -\x13\x33\x53\x15\x6a\x45\xa6\xa7\x51\xba\xd2\x11\x20\xe8\x84\x88\ -\xf5\x4e\xcb\xdd\xb9\x77\x8f\xde\xdc\x3c\xba\xd7\xa6\x1c\x0d\x90\ -\xaa\x41\xa0\xbd\x73\x04\x55\x35\xd3\x91\xaa\x28\x24\x96\x1d\xb2\ -\xf1\x88\xad\x83\x01\xc7\xcf\x3d\xc1\xed\xed\x3e\x77\x77\xf7\x89\ -\x58\x66\x29\x52\xb4\x3a\x5d\xca\xd2\x30\x3f\x3f\x47\x59\xc2\x68\ -\x34\xa5\xdd\x6e\x70\xfe\xfc\x19\xc6\xe3\x82\xdf\xfb\xbd\xdf\x23\ -\xcf\x73\xee\xdf\xf7\x0c\xaf\xf9\xf9\x2e\x83\xd4\x07\xa7\x6d\x6e\ -\x0e\x38\x7e\xfc\x38\x77\xef\xde\xe3\xc8\x91\x0d\xaa\xba\x94\x5c\ -\x5c\x5c\xe4\xc4\x89\x75\x6e\xdc\xb8\xcb\x5b\x6f\xbd\xcd\xbd\x7b\ -\xf7\x70\xee\xa5\x9a\x5a\xd9\xc0\x98\x16\x51\xa4\x99\x4c\x32\xf2\ -\xdc\x27\x2e\x2a\xa5\x98\x9f\x6f\x51\x55\x30\x18\x8c\xd0\xba\x4d\ -\x10\x50\x6b\x99\x3d\xa5\xb3\x2c\x4b\x2e\x5c\xb8\xc0\x64\x32\xa9\ -\x11\xc6\xbb\x5c\xbd\x72\x85\x85\xee\x22\xbd\x6e\x97\xe5\xe5\x45\ -\x76\x76\xb6\x99\x5b\x98\xc3\x0a\x4b\xa7\xd3\x82\x08\x26\x99\x60\ -\x3c\x19\xb2\xb9\xb9\x89\x74\x3e\xe6\x13\x21\x98\x5b\xdf\x60\xff\ -\xc1\x26\x71\xaf\x8b\x51\x0f\xb5\xc3\x4e\xf8\xd7\x0f\xeb\xb0\xb5\ -\xae\x58\x08\x81\x75\xcc\x80\x28\x63\x7c\x69\x8d\xb0\xde\x3b\xaa\ -\x2e\x5d\xab\xca\xc1\xa1\x08\xdf\x5a\x2c\x1e\x75\x46\x88\xd9\x58\ -\x4e\x0b\x3f\x7b\x15\x5a\xe1\xb0\xb8\xd2\xdf\x64\xc6\x79\x00\xcc\ -\x38\x8b\x72\x7e\x25\x08\x7b\xf8\xb3\x0c\x24\x31\xae\xc8\x11\x8d\ -\x06\x64\x19\x55\x12\x61\x44\x81\x4e\x5a\xe4\x08\xa8\x3d\xd4\x9c\ -\x54\xb8\xca\x6f\xaa\x2a\xcf\xb1\xb5\x1c\x35\x08\x02\xcf\xa7\x76\ -\xce\x5b\xf6\x54\x15\xb6\xb0\x60\x2c\x0e\x83\xb5\xde\xc4\x92\x2c\ -\xa3\x08\x03\xef\x62\x98\x17\xb4\xd7\x36\x18\x0d\x47\x34\x9b\x4d\ -\x82\x28\xa4\xa8\x45\xb8\x65\x59\xe2\x4c\x45\x24\xfc\x8d\xeb\x84\ -\xd7\x32\x07\xf5\xeb\x51\x39\xfb\x05\x33\x02\x51\xf7\xf2\xa6\xdf\ -\xe7\x20\xcb\xa0\x2c\xd9\x38\x7b\x96\xd1\x64\xcc\xfe\x60\x4c\x6b\ -\x71\x99\xf1\xde\xa6\xff\x99\x1b\x73\xf4\xaf\x5c\x61\x7e\x65\x83\ -\x0c\xc5\xed\xdd\x3d\x3e\xbc\x74\x99\x3f\xfc\x56\x9b\xc1\x78\x4c\ -\xe6\x1c\x8b\x2b\x2b\x98\x48\xb3\x39\x19\x12\x34\x42\xf6\xf7\xf7\ -\x79\xf2\x89\xf3\xcc\x75\xba\x6c\xac\x74\x19\x6d\x8f\x18\xec\x6e\ -\xb2\x78\x7c\x85\x56\x24\x08\x24\x4c\x46\x23\x4c\x59\xa1\x62\xaf\ -\xa2\x2b\x9c\xe1\xe8\xd1\xa3\xdc\xb8\x7e\x9d\x24\x89\x98\x8e\x53\ -\xae\x5e\xbe\xc2\x91\x8d\x35\x4c\x55\x32\x1a\x0d\x78\xff\xdd\x77\ -\xf8\x4f\x7e\xe9\x17\xbf\x9e\xe7\xc5\xa9\x76\x14\xde\xb0\x55\x05\ -\x4e\x30\xa8\xc3\x13\x0f\xf7\xb2\x04\x4f\x06\x51\x9e\x74\x47\x40\ -\x80\x44\xfa\x52\x47\x3a\x6c\x95\x13\x84\x10\x56\xf0\xdf\xfe\x17\ -\xff\x39\xe9\xf6\x16\xed\x40\x12\x3a\x03\x65\x41\x18\x04\x6c\x6d\ -\x6d\xf9\x79\x56\xa3\x41\xab\xd5\xc4\xa4\x29\xc3\xc1\x01\x4e\x28\ -\x88\x13\x0a\x19\x32\x2c\x0c\xd3\x0a\xde\xfc\xc1\x07\xdc\xb8\x7b\ -\x8f\x9b\x0f\xf6\xb8\xbf\xbd\xcd\xea\xaa\x57\x31\x69\xed\x37\x4c\ -\x51\x98\x1a\x74\x75\x2c\x2f\x2f\xcf\x58\x59\x3e\x67\xc9\x4f\x23\ -\xa6\xd3\xe9\x0c\x0c\xdb\xd8\xd8\xa8\xcb\x4c\x39\x9b\xf9\x46\xca\ -\x6f\xc2\x0b\x17\x2e\xd0\xe9\x74\xf8\xce\x77\xbe\xcb\xfd\xfb\xf7\ -\x19\x0e\xf3\xfa\x84\xae\x48\x92\x98\x30\xf4\xf9\xc6\x9e\xe6\xe9\ -\x75\xaa\x66\xc6\xd5\xf5\x23\xa7\x40\x43\xaf\xd7\x63\x34\x1a\xe1\ -\x9c\xa3\xdb\x6d\xd1\xe9\xf8\xd8\xd6\x1f\xff\xca\x57\x58\xd9\x58\ -\x66\x38\x3e\xe0\xd2\xc7\x1f\xf1\xe9\xd5\x1f\x72\x6f\xf3\x36\xe0\ -\x6f\xd9\xd1\x38\xa7\x19\xc3\xb1\x23\x1b\x3c\xfb\xe4\x79\x1a\xa1\ -\x22\x1f\x8f\x40\x2b\xf6\x6f\xdf\x66\x6e\x65\x85\x22\x4f\x67\x62\ -\xf9\x43\xe6\x52\xa3\xd1\xf0\x14\xc5\x7a\x21\xfe\xe8\x82\x54\xca\ -\x8f\x66\x42\xaf\xcd\xfc\x82\xa1\xc0\xa3\xc6\x02\xb3\xaf\x7b\xe4\ -\x7b\x3c\x44\xbd\xfd\x63\xe6\x22\x52\xd3\xfd\xb0\x0f\xc3\xd8\x0f\ -\xe5\x9a\x42\x08\xc6\xe3\x31\xba\xd9\x9c\xc5\xcc\x0a\x21\x90\x0e\ -\x26\x23\x6f\xd1\xaa\x85\xa4\x15\x25\x44\x4a\x13\x4a\x85\x8a\x1b\ -\x90\x97\xcc\x77\x7a\x68\x24\xca\x09\x84\x71\xa4\x93\x29\xa6\xac\ -\x08\x85\xa2\xca\x3d\x50\x35\xec\xf7\x49\xc7\x63\x8a\xc9\xc4\xa3\ -\xce\x42\x10\xf6\x7a\xc4\x2b\x2b\xfe\xe0\x9c\x9b\x63\x3c\x1c\x32\ -\x99\x4c\xbc\xf5\x4f\x9a\x7e\xa1\x3f\x6c\xb5\x5a\x44\x51\x84\xdd\ -\xdf\x9f\x8d\x09\xf3\x3c\x9f\x3d\x4f\x93\xe7\x94\x93\x89\x07\xce\ -\xca\x92\xa8\xd5\xa2\xb7\xbe\xce\xd6\xce\x36\x69\x5e\x92\x34\x5a\ -\x8c\x87\x53\x08\x9a\x90\xf4\x38\xb8\xb5\x49\xb4\xb0\x46\x51\x3a\ -\x86\x65\xc5\xbd\xd1\x98\x3d\x5b\x71\xf1\xe6\x67\xdc\xea\xef\xd0\ -\x3e\xba\xc1\xc4\x38\xf6\x46\x23\xe2\x66\xd3\xaf\x99\xb2\xe4\xec\ -\xb1\x63\xe8\xb2\xe2\xc1\xad\x5d\xfa\x7b\xbb\x3c\xf1\xd4\x59\x4a\ -\x5b\xd1\x9d\x6b\x33\x9c\x14\x1c\x59\xdf\x20\x54\x9a\xfe\xce\x98\ -\xfb\xf7\x1f\xf8\x28\x25\xa0\xdb\xed\xa2\x14\x7c\xfc\xf1\xc7\x3c\ -\xf1\xc4\x13\x14\x69\x06\xc6\xf2\xfd\xb7\xbe\xc7\xaf\x7c\xfd\xeb\ -\x0c\x86\x63\xd7\x8c\xc2\x1b\xee\x91\xb9\x71\xb7\x3b\x0f\x35\x9f\ -\xbd\x06\xbb\xec\xcc\x1a\x46\x01\xe6\xe1\xdd\xe0\xaf\xec\x66\x88\ -\xcb\x4a\xb4\x0c\x78\xed\x4b\x27\xc4\xd3\x67\x4e\xba\xcb\x1f\x5f\ -\x64\xe1\xa9\x67\x99\x66\xa3\x7a\x74\x05\xb6\xaa\x70\x65\x89\x6b\ -\x25\xf5\x50\x4b\x90\xa7\x39\x64\x05\xad\x23\x1b\x38\x2c\x13\x03\ -\x9f\xdf\xdd\xe4\xf5\x2f\xbd\x48\xbb\xd7\xe3\xd6\xd5\xcb\x18\x07\ -\xc3\xe1\x10\x29\x7b\xac\xad\x79\xd8\x7e\x6f\x6f\xcc\x78\x3c\xe6\ -\xc4\x89\x13\x9c\x3e\x7d\x8a\x7b\xf7\xee\x73\xf9\xf2\x65\x92\x24\ -\xe1\xec\xd9\xb3\x2c\x2e\x36\x29\x0a\x1f\xa2\x76\x58\xce\x79\x43\ -\x80\x98\xcd\xcd\x3d\x8a\x22\x61\x7d\x7d\x81\xef\x7f\xff\x03\x5e\ -\x7b\xed\x35\x16\xe6\x13\x3e\xbb\xf1\x80\x77\xdf\x7d\x97\xd3\xa7\ -\x4f\x73\xfa\xd4\x1a\x45\xe9\x4d\x00\x8a\xa2\x20\x8e\x63\xcf\x1b\ -\x4f\x02\xe2\xb8\x87\x73\x9e\x63\x5d\x96\x25\x77\xee\x8e\x69\xb5\ -\x5a\x2c\x2d\x2d\x11\x45\x92\xe1\x30\x9d\x6d\x92\x20\x80\x93\xc7\ -\x96\x58\x5b\x5b\x22\xcf\x73\x3e\xbe\xf4\x11\x59\x96\xf1\xc9\xa7\ -\x3f\xa4\x3f\x1c\x91\x3b\xc7\xc6\x99\xc7\xd0\xcd\x2e\x47\xd6\x56\ -\xb9\x76\xf7\x01\x9a\x90\xcc\x08\x0a\xa9\x19\xf6\xf7\x10\xca\x0b\ -\x0b\x0e\xe9\x8c\xb6\xf2\xcf\x89\xa2\xf0\xa5\x75\x5d\x0a\x1e\x8a\ -\xff\x85\xf5\xb7\xa6\xad\x9c\xa7\x82\xd6\x1b\x4f\x18\x59\x97\x95\ -\xb2\x96\x55\x5a\x84\x90\x04\x42\x52\xd4\xb7\xb1\x94\xd2\xa3\xe2\ -\x87\x3d\x2d\xe0\xea\x52\x54\xf8\x55\x82\x94\x5e\x6f\xae\x85\x1f\ -\x63\x99\xaa\xa8\x4b\x55\x81\x44\x11\x28\x45\x16\xf9\xe9\x82\xd2\ -\x21\xda\x7a\x63\x45\x6b\x0c\x59\x99\x22\x1d\x7e\x56\x5d\x99\x7a\ -\x0d\xa4\x94\xb9\x97\x25\x0a\x21\x30\x69\x86\x91\x92\x4a\x6b\x4f\ -\x7b\x14\x02\x64\x80\x0a\x43\x9c\xf2\x6d\x80\xd4\x1a\xad\x7c\x5f\ -\x3b\x3b\x68\xea\x03\x4c\xd6\x88\xb8\x0e\x43\x4c\x09\xd9\x70\x80\ -\xb4\x4d\x4a\x53\xd5\x3c\x73\x55\x2b\xa7\xfc\xef\x55\x65\x99\x3f\ -\xa0\x82\x80\x28\x8a\xc8\x6b\xee\xfd\xe1\xa1\x16\x45\x9a\x20\x88\ -\x88\xeb\x03\xb1\x74\x02\x53\x5a\x4c\x09\xc6\x96\x98\x20\x20\x9d\ -\x8c\x40\x4a\x92\xe3\x1b\x08\x23\x98\xa4\x29\x51\x59\xd1\x9a\xeb\ -\x51\x05\x8e\xf4\x60\x87\xd8\x09\xce\x9f\x3c\x8d\x7e\xb0\xc3\x41\ -\xbf\xcf\x4b\x4f\x3e\xc1\x74\x9a\x71\x72\x7d\x9e\xdb\xc3\x21\xcb\ -\x9d\x0e\xa3\xd1\x80\xcd\xfb\x5b\xec\xec\xf9\x58\xa5\xc5\x95\x36\ -\xdf\xf9\xce\x5b\xbc\xf2\xd2\x05\x1e\x3c\xf0\xbc\x88\xa3\x47\xd6\ -\xb9\x7e\xf9\x13\xee\xdc\xba\xc9\x74\x32\x62\x7d\x65\x99\x76\xab\ -\x29\x0e\x77\xa5\x67\xb3\x79\x0b\x6b\x21\xc4\x0c\xd5\xd7\xb3\xd3\ -\x1c\x50\x4e\x72\xa8\x9d\x41\x08\x9c\x30\x08\x6b\x10\xa1\x83\xa2\ -\x40\x13\xf2\xab\xbf\xf2\x4b\xfc\xfa\xff\xfc\xbf\x52\xec\xf7\x51\ -\x04\x7e\x56\xa9\x05\x65\x59\x40\x91\x21\x4c\x45\x12\x85\x94\x0e\ -\xaa\x3c\x85\xd2\x20\x55\x40\x96\xe7\x04\x49\x8b\x9d\x81\x5f\xe0\ -\x71\x47\x91\x63\xb9\xf6\xd9\x4d\x96\xe7\x7b\x44\x91\xc0\x5a\xe8\ -\xf7\xc7\x33\x21\x84\xf7\xef\xca\x39\x75\x6a\x9d\xb5\xb5\x35\x6e\ -\xdc\xb8\xc1\xad\x5b\xb7\x66\xde\xd4\xab\xab\xab\x04\x81\x64\x38\ -\xf4\x9c\xd5\xb5\xb9\x98\xd5\xd5\x05\xf6\xf7\xc7\xf5\xf7\xea\xd3\ -\x6a\x25\x7c\x7e\x73\x8b\xe5\xe5\x65\x4e\x9d\x5a\xe3\x83\x0f\x2e\ -\xf3\xff\xfc\xc1\xc7\x1c\x3f\x7e\x9c\x63\xc7\x8e\x31\x1a\x8d\x58\ -\x5d\x5d\x45\x4a\x1f\x32\x77\x18\xc6\xa6\xb5\xaa\x73\x96\x17\x98\ -\x4e\x3d\xb9\x62\x7f\xdf\xcf\xfd\xe6\xe6\x62\xf2\x3c\x26\xcf\x2d\ -\x77\xef\x79\x53\x84\x5e\xa7\x4d\x10\x47\x9c\x3e\x7d\x9a\x30\x89\ -\x30\xd6\x11\x34\xdb\x7c\x70\xf9\x1a\xb6\x82\xdd\xcd\x07\x5c\xfe\ -\xf8\x13\x6c\xd4\x04\x11\x12\xac\x6c\x10\x28\x4d\x56\x79\x23\x43\ -\x21\x1c\x12\xd0\x3a\x20\xd4\x01\x69\x14\x21\x93\x04\x7d\xc8\x9f\ -\x46\x70\x78\x22\x4b\xe7\x3d\xab\x3d\xaf\x5a\x11\x28\xbf\xf0\x6d\ -\x5d\x46\x3b\xe9\xf9\xcd\x42\x08\x4c\x59\x79\x93\x75\x49\x8d\x04\ -\x7b\xc3\x2e\x2b\xc0\x39\x8b\xa8\x0c\x95\xc0\x1f\x02\x55\x85\x15\ -\x25\x95\x92\xb3\xaf\x17\xf5\x02\x37\xc6\x61\x4c\xe9\xc7\x4d\x93\ -\x29\xd3\x30\x40\xaa\x82\xca\x08\x64\x10\x10\xe9\x80\x20\x88\xc0\ -\x3a\x72\x93\xfa\xd1\xd5\x78\xc2\xa8\x32\x50\x96\x10\x86\xe8\xc8\ -\xab\xab\xa2\x28\x22\x88\x22\xaa\x46\x83\xf1\xee\x0e\x32\x8c\x88\ -\xe2\x06\x56\x09\xaa\xda\x4d\xd3\x38\xff\x7a\xcc\x54\x50\xa6\xc2\ -\x99\x0a\xa9\x25\xc2\x19\x6c\x8d\x4a\x47\xcd\x26\xa1\x0e\xa9\x32\ -\xdf\xb2\x64\x59\xe6\xab\x86\xca\xa7\x87\x10\x04\xfe\x35\x0a\xfc\ -\x98\x89\x20\x98\x55\x23\x52\xca\x5a\x66\x29\xa1\x32\x68\xa9\x70\ -\x06\x4c\xe9\x70\xd2\x60\x9c\xf1\xb3\xf2\x24\x46\x87\x31\x95\x70\ -\x54\x59\x89\x93\x92\xd2\x81\x9c\xa6\x24\x61\x0c\x65\xc1\x73\xe7\ -\x9f\x64\xfb\xb3\xcf\x59\x9a\xe4\xbc\x72\xee\x0c\x26\xcf\x98\x5b\ -\x69\xb2\x39\x4d\x91\x5a\x53\x5a\x5f\x65\x3e\x78\xf0\x80\xa3\x47\ -\x8f\xd1\x6c\xb6\x19\x8e\xfc\x1a\xdf\xdd\xdd\xe5\xa0\xbf\xc7\x53\ -\xe7\x9f\x64\x74\x30\x60\x34\x1c\x52\x76\xdb\x3c\x7e\xee\x0c\x6b\ -\xab\x2b\x22\x94\xbe\x2b\x76\xd6\x78\x97\xd4\xfa\x10\x52\x35\x59\ -\x06\x3c\x96\xe5\xb3\x26\xac\x44\xd9\x3a\xa6\x44\xf8\x4c\x67\x8f\ -\x62\x97\x68\xed\x4f\xe2\xfe\x28\xfd\xda\xdf\xfa\x1b\x5f\xe1\xf7\ -\xbe\xfd\x27\x5c\xda\x1f\x61\xd0\xc8\xf9\x75\x82\x28\x00\x1c\x65\ -\x0d\x58\x84\x91\x7f\xd1\xc6\xa5\x02\xa9\x19\x1e\x8c\xd1\xd2\xb1\ -\xd6\xe9\xa1\xc6\x43\x1e\xec\xf5\x31\xe7\x96\x69\xf7\xe6\x68\x75\ -\xba\x1c\x1c\x1c\x30\x1a\x8d\x38\x79\xf2\x28\xcd\x66\x13\x6b\x2d\ -\x07\x07\x07\xac\xad\xad\x91\x24\x11\xbb\xbb\x63\xc2\x30\xe4\xf4\ -\xe9\xd3\x0c\x06\x03\xae\x5c\xb9\xe2\x59\x5b\x8b\x8b\x94\xa5\x65\ -\x7e\xbe\x89\x10\x70\xed\xce\x2e\xad\x56\x8b\x6e\xb7\x45\x9e\x5b\ -\x96\x96\x96\xd8\xdc\xdc\xe1\xd8\xb1\x15\x8c\x81\xcd\xcd\x01\x67\ -\xcf\x9e\xe5\xd9\x67\x1f\xe7\xce\x9d\x6d\xde\x7b\xef\x3d\xee\xdc\ -\xb9\xc3\xd7\xbe\xf6\xb5\x1a\x2b\xa9\x66\x66\x6f\x5a\x43\x9a\x5a\ -\xc6\xe3\x31\x69\x9a\xb2\xb0\xb0\x50\x1b\xa4\xf9\xb0\xf2\xb2\x2c\ -\x29\x8a\x82\xb5\xd5\x35\x84\xf4\x3d\xca\x78\x3c\xa6\xd9\x6c\x62\ -\x70\x14\x65\x0e\x65\xc9\xb3\x4f\x9d\x65\xbf\x82\xa3\xb7\x8e\x72\ -\xec\xd8\x51\x72\x9d\xf0\x60\x77\x40\x39\x9d\x52\x56\xfe\x16\x41\ -\x40\x85\xa3\x0a\x02\x28\x0b\x46\x80\x1d\x8f\xb1\x75\xe9\x15\x38\ -\x87\xb3\x1e\x95\x96\x78\xb3\xc4\x43\x13\x3d\xca\x0a\x5b\x55\x54\ -\x52\x50\xd9\xea\xe1\x46\x36\x3e\xf9\x52\x39\x66\xa7\xb6\x07\x4a\ -\x6a\x9b\x5c\xe1\x27\x13\x61\x14\x11\x05\x0a\x61\x05\x69\x55\xf9\ -\x59\xb0\x54\x1e\xf3\x00\xa4\xd6\xb3\xaf\x51\xc2\x1b\x07\x94\x75\ -\x95\xa0\xa4\xc4\x3a\x41\x95\x17\x54\x83\x51\x1d\xec\x2c\xea\xfc\ -\x59\x01\xad\x26\xdd\x85\xf9\x19\x00\x75\x58\xbd\x39\xe9\xcd\xe0\ -\xad\xb3\xa0\x7d\x4f\x2b\xa5\xf4\x7d\xae\x73\x1e\xb1\xc6\xa2\xea\ -\xe7\xed\x6a\x9f\x69\x5b\x19\x5c\x58\xfb\xd5\x3a\x03\xb6\x22\x0a\ -\x7d\x42\x66\x55\x55\x50\x55\xbe\x84\xae\x39\xe5\x08\x41\x90\x24\ -\xbe\x6d\x91\xca\x57\x3a\xd6\x92\xe7\xb9\x67\xc6\x85\xbe\xe7\x76\ -\xc6\xa3\xe3\x12\x8b\x2d\x4a\xc8\x0b\x4c\xdd\x5a\x12\x05\x10\x05\ -\x9e\xb0\x53\x55\x50\x1f\xbc\x87\xc2\x98\xc1\xee\x16\x6b\xf3\x0b\ -\x74\xa4\xa6\xa3\x24\xcb\xad\x16\xb2\xa8\x58\x3b\xd6\xe6\xa0\x28\ -\x19\x65\x43\xba\x4b\x0b\xec\xec\x7a\x35\xdf\xb1\x8d\x35\x4e\x9d\ -\x5a\xe2\xee\xbe\x61\x5a\xa6\x74\x3a\x5d\x2e\x5f\xbe\xcc\x13\x67\ -\xce\xb1\x36\xd7\xe4\xdb\x7f\xfa\x26\x91\xf6\x1b\xf4\xd5\x97\x5f\ -\x26\x50\x7e\x4f\x1e\xca\x15\x1f\x25\xca\xf0\x48\x5b\x24\x2d\xbe\ -\xc4\xc2\x79\x00\x5b\x58\xff\xfc\x0f\xa7\xca\x28\xc9\x60\xb2\x0f\ -\xc2\xd0\x6c\x85\xdf\xea\x68\xc4\xdf\xfd\xf9\x9f\xa1\x83\x17\xa2\ -\x9b\xaa\xf0\x49\x85\xa1\xff\xe3\x99\x3c\xc3\x95\x05\x5a\x48\x74\ -\x10\xfa\x51\x41\x9a\x52\x19\x41\x56\x56\x38\xa5\xf9\xec\xd6\x6d\ -\x0e\xc6\xd0\x9a\xeb\xb2\xb1\x31\x47\xbb\xdd\x66\x34\x1a\xb1\xbd\ -\xdd\xa7\x2c\x4b\x3a\x2d\x35\x3b\x35\xd3\x34\xaf\x91\xeb\x90\xe9\ -\x74\x5a\x23\xc9\x67\x08\x82\x80\x9d\x9d\x1d\xb6\xb6\xb6\xd8\xde\ -\x1e\x50\x55\x1e\x31\x6e\x36\x63\xf2\xdc\xb3\xb9\x9c\x73\xcc\xcd\ -\xcd\x1d\x62\x70\x2c\x2e\x76\x89\x63\x55\xc7\xc4\x24\xfc\xe4\x4f\ -\xbe\xc6\xc2\xc2\x02\x5b\x5b\x5b\xbc\xf9\xe6\x9b\x3c\x78\xf0\x60\ -\xc6\xf8\x19\x8d\x32\x3a\x9d\x78\xe6\xbc\xa9\x6b\x5f\xb3\x2c\xcb\ -\xe8\xf7\xfb\x33\x35\x8e\x31\x50\xa4\x86\xc9\x24\x67\xb4\x3f\x41\ -\x08\x85\x92\x01\x3a\x8a\x09\xa2\x80\x9b\x77\xb6\xd9\xdb\x9f\x32\ -\x2d\x4a\x74\x18\x22\xc3\x88\xb0\xd3\x46\x75\x5a\xe8\x76\x1b\x91\ -\x24\xc8\xa4\xe1\x63\x4a\xa8\xc7\x4e\x59\x06\xa3\x31\x94\x15\xd5\ -\x34\x25\xcb\x32\xb2\x34\xa5\xca\xb2\x9a\x76\x99\xcd\x3e\x46\x48\ -\x64\x1d\xfb\xa3\x10\x28\x29\x51\xf8\xf4\x01\xf9\xc8\x6d\xae\xe5\ -\x23\x9f\x57\x7f\xac\xa5\xa4\xcc\xf2\x87\xa8\x6e\x9e\x63\xf3\x9c\ -\x22\xcf\x29\x32\xff\xc8\x36\x37\x49\xb7\xb6\x48\x77\x76\xc9\xfa\ -\xfb\xa4\xc3\x21\x4c\x26\x14\x69\x46\x9e\xe7\x54\x93\x09\x08\x88\ -\x7b\x5d\xda\x6b\x6b\x74\xd6\xd7\x68\xcd\xcf\x53\x83\x1e\x35\x49\ -\x24\x9a\x91\x44\x44\xa0\xb0\x4a\x50\x38\x83\x91\x1e\x65\x77\x08\ -\xcf\x34\x35\xd6\xdb\xd7\xe0\x85\x1d\x02\x59\x8f\xb9\x3c\xb7\x41\ -\xc8\x87\xec\x51\x2d\x05\x4a\x48\x86\x7b\x7b\x5e\x71\x36\x9d\xfa\ -\x43\xd1\x5a\xc2\x46\x83\xa4\xd7\xa3\xb5\xb0\x30\x2b\x47\x85\x10\ -\xfe\x40\xd1\x1a\x6a\x1c\x24\x50\x9a\x66\x12\x11\x6a\x59\x8f\x60\ -\x8d\x9f\x71\xdb\x3a\xfb\x42\x29\x9a\xed\x36\x4c\xa7\xd8\xf1\x98\ -\x66\xd2\xa0\xd1\xed\xd5\x6c\xb8\x8a\x5e\xa7\x8d\x4b\x33\xd2\xed\ -\x6d\x1e\xdf\x38\xc2\x4f\xbe\x74\x86\x23\xf3\x0b\x0c\xf7\xb6\x09\ -\x34\x94\x65\xce\xfa\xd2\x0a\xdb\xfb\xbb\x4c\x33\x6f\xaa\x77\xf4\ -\xe8\x51\x46\x07\x96\x28\xf2\x00\xeb\xa5\x4b\x97\x38\x79\xf2\x24\ -\xa7\x4e\x1d\x61\x77\x9c\xd1\xdf\xdb\x63\x79\x69\x81\x22\x9b\xd2\ -\x6b\x34\x84\xb1\x87\x83\x61\xdf\xfe\x7a\x34\xda\xfd\x25\x23\x45\ -\xed\x0e\x0b\x6b\x27\x0e\xdb\xe5\xd9\x9b\xa9\x73\x09\x74\x33\xa6\ -\xb0\x29\x5a\x36\x99\x18\xf5\xb5\x1f\x7f\xe9\x02\xff\xcb\xff\xfe\ -\x7f\xb0\xd4\x6a\xb3\x3b\x99\x10\x86\x31\x91\x52\x20\xc1\x54\x15\ -\x79\x96\x12\xab\x80\x40\x48\x7f\xcb\xd4\x8e\x14\xbb\xfd\x03\x2a\ -\xe9\xb8\xf3\xe0\x3e\x9f\xdf\x7f\xc0\x72\x14\x32\x9e\xc2\xd1\x23\ -\x0b\xb4\x5a\x2d\x36\x37\x37\xd9\xd9\xd9\xa1\x3a\x7a\x94\x3c\xcf\ -\x09\xc3\x90\x6e\x37\x62\x34\x2a\x01\x4d\xab\xd5\x20\x8a\x60\x54\ -\x87\x97\x3f\xfd\xf4\xd3\x0c\x06\x03\x86\xc3\x21\xfd\x7e\x9f\x8d\ -\x8d\x8d\xba\x92\xd2\x48\xb9\xc0\xfb\xef\xbf\xcf\xcb\x2f\x3f\xcb\ -\xce\xce\xa8\x26\x31\x68\x06\x83\x41\x1d\x69\xaa\xd9\xdb\xcf\x38\ -\x38\x38\xe0\x17\x7e\xe1\xa7\x48\x53\xb8\x74\xe9\x12\x6f\xbe\xf9\ -\x26\x2b\x2b\x2b\x2c\x2c\x2c\x90\xe7\x39\xf3\xf3\x5d\xd2\xd4\x0b\ -\xc0\x0f\x7d\xbb\xa4\x94\x34\x1a\x8d\x7a\xde\x0e\x61\x6d\x08\x97\ -\x24\x4d\x9c\x55\x58\x61\x71\x56\x21\x24\xac\x1f\x59\x26\x12\xf0\ -\xe1\xd2\x22\x25\x82\xfb\xdb\x5b\x88\x56\x0f\x1d\xc5\xe8\x38\x06\ -\xe3\x4b\xa4\x22\xf7\xbd\xa9\x8d\x7c\xe9\x57\xc4\x31\xcd\x6e\x97\ -\xc9\x78\x8c\x96\x0a\x63\xc1\x5a\x83\xa8\x11\x69\x8c\x1f\x11\xd2\ -\xef\x33\x71\xc6\xd3\x13\x6d\xf5\x70\x24\x64\xad\xb7\xf4\xc9\x4b\ -\x98\x4c\x28\x95\xa2\x6c\x34\xfc\x02\x15\x75\xc6\x11\x16\x74\x48\ -\x55\x6a\x5c\x5e\x42\x96\x83\x13\x38\x29\xfd\xc1\x2e\x25\xa2\xd7\ -\x43\x21\xd0\xca\xa7\x4f\x68\xa9\x98\x54\x25\xdd\x76\x07\x15\x84\ -\xb8\x39\x3f\xa7\x2e\xcb\x92\x34\xcb\x66\xf9\xd1\xcd\x4e\x9b\x32\ -\x89\x19\xa5\x1e\xe5\x2f\x8c\x67\x57\x25\x51\x82\x94\x02\xe7\x14\ -\xa1\x0e\x28\x46\x53\x2c\x02\x53\x39\x9c\xf4\x0e\x35\x52\x29\xb4\ -\xf0\xe3\x96\x40\xfb\x04\xcb\x52\x64\xb8\xca\x90\xa7\x99\x9f\x67\ -\x87\x7a\x86\x23\x08\x1d\xe0\xc2\x10\x74\xe2\x9d\x47\x6a\x0f\x6c\ -\xe7\x9c\x0f\xad\xd7\x3e\x60\x5c\x08\xe1\x93\x39\xea\x80\x7a\xaf\ -\x37\xf7\x37\x5d\x59\x14\x28\xad\x7d\x35\xa3\x15\x2a\x0a\x51\x51\ -\xe8\x7b\x7d\xe9\x2f\x29\x57\x9a\xda\xe8\x40\x43\x59\x70\xd0\xdf\ -\x45\xe6\x25\x4f\x3e\x7e\x86\x37\x5e\x7a\x96\xc4\x41\x10\x06\x0c\ -\x9d\x63\x7b\x73\x48\x63\xa1\xc1\x9d\xd1\x0e\x3b\xfd\x1d\xd6\x3a\ -\x8b\x6c\x1c\x3d\xc2\x68\x34\x22\x89\x9a\x14\x4e\xb1\xb7\x3b\x60\ -\x32\x99\x70\xfe\xb1\x93\x60\xa9\x4d\x20\x0d\x79\x9e\x73\x6c\x7d\ -\xed\x21\xd9\x03\x89\x54\xbe\xed\xc5\xfd\xd5\x8e\xa8\x1a\x1e\x7a\ -\x1f\xcf\x1e\xc2\xdf\xca\x4e\xc0\xd8\x4c\xff\xa7\x96\x8a\x7e\x23\ -\xaf\xa6\xe8\x40\xa2\x64\xf0\xad\x95\xb6\xfc\x9d\xd7\x2f\x5c\xf8\ -\x17\xdf\xf8\xf4\x33\xdc\x78\x44\xde\x6a\x13\xc4\x1a\x02\xe5\x49\ -\x0a\x65\xe5\xe7\x80\x4a\xf9\x75\x13\xc7\x08\x0b\x0e\x49\x5e\xe6\ -\x1c\x8c\xc6\x7c\x72\xf5\x0a\xab\xcf\x3f\xed\x95\x44\x53\x88\xe3\ -\x88\xb5\xb5\x35\xfa\xfd\xfe\xac\x17\x7e\xf9\xe5\x17\x48\x53\x5f\ -\x06\x96\x65\xc9\xce\xce\x01\x73\x73\x73\xcc\x75\x82\x19\xe2\xbc\ -\xb0\xb0\x40\x10\x04\xec\xed\xed\x71\xe9\xd2\x25\x1a\x8d\x06\xcf\ -\x3f\xff\x04\x4a\xf9\x51\x54\xbf\x3f\x65\x75\xb9\xcd\x70\x6c\x3c\ -\x9f\x7a\x63\x1e\x07\x6c\x6e\x7b\xa0\xee\xe5\x97\x5f\x66\x67\x67\ -\xcc\x64\x32\xe1\xb9\xe7\x9e\x26\x0a\xe1\xde\xfd\x7d\xae\x5e\xbd\ -\x4a\x92\x24\x6c\x6d\x79\xe1\xc6\xfa\xfa\x3a\x61\x08\xe3\x71\x45\ -\x9a\xa6\x9e\x4f\x5b\x79\x63\xf7\xaa\x0e\x49\x50\x22\x20\x4b\x4b\ -\x54\xa8\x28\x4c\x85\x49\x03\xf6\x8a\x8a\xb8\xab\x79\xb0\xb3\x8b\ -\x95\x0a\x17\x04\x74\x16\x16\x98\x22\x70\x41\x40\x3a\xea\x13\xe8\ -\x00\x53\x14\x88\x30\xf4\x7f\x0d\xeb\x66\x29\x90\x55\x18\x11\x44\ -\x21\x46\x79\x46\x94\xd6\x21\x65\x3d\x7e\x8a\x43\x4d\xba\xb8\x48\ -\xb7\xd7\x45\x46\x01\xb9\xa9\x10\x4a\xfa\xb2\xcf\xf8\x1e\x50\x23\ -\x49\x27\x13\xb4\x54\xc4\x8d\x04\xe3\x1c\xf6\xf0\x26\x74\x96\x62\ -\x9a\x12\x86\x9a\x5c\x97\x94\x5a\xa3\xa3\x98\x38\x8e\x11\xc2\x63\ -\x04\x45\xe1\xd9\x70\x52\xf8\x1e\x5b\x58\x5f\xe6\x96\x65\x49\x09\ -\x4c\xf7\x07\x10\x27\x84\x61\x88\xac\x69\x91\xa5\x35\xbe\xc4\x1d\ -\x0c\x68\x9d\x3c\x89\x0e\x02\x2f\xe6\xa8\x4a\x2a\xe1\xdb\x12\x5b\ -\xe4\x14\x41\x58\xf7\xc3\x7e\x36\x2a\x84\x42\x4a\x4f\xc5\xb4\xa6\ -\xc2\x14\xa5\x4f\xc6\xa8\x0c\xae\x2a\x28\xb1\xb8\x0a\x5f\xde\xca\ -\xa8\x76\xed\x6c\xd2\x88\x1b\x54\xd6\xe0\xa4\x20\xed\xf7\x29\x8a\ -\x62\x66\xa3\xfb\xa3\x88\x7e\x10\x04\x14\xd3\x29\x79\xee\x27\x18\ -\xb6\xc8\x0f\xad\x36\x10\x61\x84\x08\x04\x8e\x0a\x02\x5f\x09\x98\ -\xbc\xa0\x95\x34\x91\x0e\xd2\xf1\x94\xaa\xcc\x3d\x1d\xd4\x3a\x26\ -\x3b\xbb\x34\x03\xc7\x7f\xf6\xf7\xfe\x63\x9a\x02\x26\xbb\xb0\xde\ -\x4e\xf8\xec\xc3\xfb\x9c\x7c\xec\x28\x0f\xfa\xbb\x5c\xdb\xb9\xc9\ -\xe2\xfa\x2a\xcd\x76\x8b\x5e\xaf\xe7\xcd\x32\x3a\x73\xdc\xd9\xde\ -\x61\x77\x78\xc0\xc9\x93\x27\xc9\x72\xd8\xdd\xda\x66\x38\xf0\x59\ -\xc9\xe3\xf1\x98\x73\x67\xce\xfe\x8e\xe0\x61\x75\x0c\x75\x5f\x2f\ -\x34\x52\xa9\x5a\xae\xfa\x88\xaf\xb5\x60\xb6\x95\x1f\xa2\x5e\x8f\ -\x7c\xd8\x52\xad\xdf\x98\x9a\xec\x5f\x27\x61\xcb\x5b\xa8\x5a\x43\ -\x08\xbf\xf1\x4f\x7e\xf5\xef\x53\xee\x6c\x41\x3a\x42\x64\x63\x22\ -\x6b\xd0\x3a\x20\x08\x42\x1c\x82\xb2\x1e\x61\x60\x0c\xd2\x56\xb8\ -\x2a\xa5\xd7\x6d\x12\xc7\x21\xb9\xad\xb8\x76\xfb\x0e\xc4\x09\xb9\ -\xad\x30\x18\x9c\xf4\x80\xcb\xca\xca\x0a\x27\x4e\x9c\x20\x0c\x43\ -\x6e\xdf\xbe\x0f\xce\x51\x14\x05\xcd\x66\xc8\xd1\xa3\xcb\xe8\x28\ -\xe0\xe6\xfd\x3e\x0f\xb6\xb7\xd8\xd8\x98\xaf\xe7\xbf\x15\x47\x8e\ -\xac\x73\xf6\xec\x59\x3a\x9d\x0e\xdf\xfb\xde\x87\xfc\xab\x7f\xf5\ -\xbf\xf1\xd2\x4b\x2f\xd0\x6a\x35\x38\x18\xfa\x3e\xbf\xd7\x6b\xb1\ -\x3f\x28\x38\x18\x78\x0a\xa9\x73\x8e\xcd\xcd\x4d\xba\xdd\x16\x27\ -\x4e\xac\x50\x96\x96\x9d\xdd\x09\x8b\x8b\x73\x3c\xf9\xe4\x93\x3c\ -\xf5\xd4\x53\x74\xbb\x5d\x76\x76\x76\x78\xfb\xed\xb7\xf9\xe6\x37\ -\xff\x82\xcb\x97\x2f\x63\x8c\x21\x49\xa8\x9f\x97\xcf\xf3\xaa\xca\ -\x0a\x25\x34\x4a\x4a\x5a\x2d\x2f\x85\x74\x0a\xda\x5d\xcd\x6e\x06\ -\x57\x6f\xdf\x65\x62\x8d\x07\x5f\xa4\xa6\x1c\x4f\xfd\xeb\xa3\x43\ -\x82\x30\x44\xd5\x1b\x41\xe9\xd0\xbf\xce\x42\x22\x75\x2d\x0e\x40\ -\x62\x0f\x05\x11\x5a\x79\xa6\xff\x31\x22\x00\x00\x20\x00\x49\x44\ -\x41\x54\x12\x47\x14\xfa\xf1\x93\x31\x14\xce\x50\x3a\x4b\x65\x0d\ -\x85\x35\x18\x6b\x29\xac\xa1\xb4\x86\xac\xf0\xa5\x72\x56\xe4\xa4\ -\xf5\xfb\x69\x9e\x91\xe5\x39\x59\x5e\x60\xa5\x00\xa1\xea\xf6\x8a\ -\x5a\xcb\x6d\x1e\x12\x54\x9c\xa5\xc2\xd5\x9c\x6a\x8d\xd3\xde\xb8\ -\x4f\x87\x11\x61\x10\x13\xb6\xdb\x75\x52\xa6\x0f\x81\x97\xca\x27\ -\x49\x86\xad\x16\xd4\x0b\x37\x3b\x54\x25\x95\xe5\x8c\xb4\x82\xf6\ -\xe8\x32\x4a\x11\x88\xba\x48\xa8\x5b\x02\x61\xfd\xdf\xbc\x4a\x53\ -\xd2\x83\x7d\xb2\xd1\xd0\x33\xc5\x9c\xbf\x7d\x45\x23\xa1\xdd\xeb\ -\xd1\x59\x5e\xc2\x13\x39\xfd\x68\x4d\x58\x07\x65\x85\x14\x82\x24\ -\x8c\x68\x37\x5b\x44\x61\x44\xa4\x83\xd9\x44\xa0\x72\xd6\x3f\x8f\ -\xa2\xc0\x16\x05\x41\x94\x90\xc4\x0d\xc2\x66\x93\x46\xab\x49\xd4\ -\x88\x7c\x30\xa3\x29\xc8\x32\xdf\x82\x99\xac\xa4\x98\xe6\x34\x74\ -\x48\xa2\x02\xc8\x52\xb0\x05\x9d\xb9\x36\xcf\x9d\x3e\x85\x98\x0c\ -\x58\x68\x41\xcd\xf3\x40\x35\x22\xfa\xc3\x01\x0f\x1e\x6c\x72\x7c\ -\xfd\x18\x47\x96\x36\x68\x45\x0d\xee\xde\xbd\xcb\xda\x91\x0d\x76\ -\x07\x7d\x8a\x32\xe3\xec\x99\x13\x84\x4a\xf9\x64\xcf\x83\x3e\x5b\ -\xf7\x1f\xd0\x6d\x35\xe9\xb6\x3b\x34\xc3\xe0\x37\x2c\x0e\x6c\x3d\ -\x47\x72\x6e\x56\x3d\x1c\xee\x5c\xf3\x48\x89\xed\x05\x61\x0e\x2f\ -\x69\x0b\x1e\x79\x50\xa0\x70\x48\x24\x1d\x35\xf7\xf5\x69\x6e\x19\ -\xec\x67\x7d\x61\x7c\x08\xe5\x9c\xaa\xf8\xc5\xd7\x9e\xe7\x78\x5b\ -\xb1\x68\x27\xec\x5d\xf9\x98\x50\x08\xa2\x56\x17\x23\x43\x8a\xca\ -\x33\x5b\xc2\x56\x88\xe9\xdf\x27\x34\x63\x62\x99\x71\xe1\xa5\xa7\ -\x21\x52\x5c\x79\xb0\xc5\x76\x56\x10\xb4\x03\x72\x93\x63\xa8\x48\ -\x5a\x09\xbb\x7b\xdb\xcc\x2f\xb4\xe8\xb4\x9b\x28\x09\x1f\xbd\xff\ -\x01\xce\x5a\xf2\xa2\x62\x92\x55\x84\x11\xa8\x48\x31\xb7\x34\xc7\ -\x9d\xed\x3e\xa5\x85\xf9\x85\x26\x95\xa9\x48\x1a\x11\xc7\x8f\x6f\ -\x70\xfe\xfc\x79\x1e\x7f\xfc\x71\xfe\xec\xcf\xde\x64\x73\x73\x07\ -\x51\xfb\x49\x4d\x26\x1e\x8c\x69\x34\x42\x92\x44\x03\x82\x66\xb3\ -\xc9\x78\x9c\x32\x1c\x96\x68\x2d\x69\xb5\x9a\x94\xa5\x3f\xfd\x9a\ -\x4d\x4f\x1b\x5d\x5f\x5f\xe7\xab\x5f\xfd\x2a\xaf\xbe\xfa\x2a\xa7\ -\x4e\x9d\x62\x7f\x7f\x9f\xb7\xde\xfa\x80\x8f\x2e\x7e\xc8\xe7\x37\ -\xee\x53\x56\x39\x77\x6f\x5e\xe7\xec\xc9\x63\xf4\x9a\x01\xbb\x5b\ -\x53\x84\x04\xa7\xa1\x9f\xc1\x9b\x1f\x5c\x66\x3f\xcf\xb1\x41\x08\ -\x45\x45\x55\x59\x5a\xad\x9e\xcf\x57\x72\x96\x69\x55\x41\x10\x52\ -\x19\x8b\xd0\xda\x07\x93\x25\x0d\xd2\xfa\xd6\xcb\x84\xa3\x52\x8a\ -\x42\x49\x52\x53\x92\x3b\x83\x11\x96\x51\x91\x41\x23\xc2\x6a\x4d\ -\x01\xde\x20\x51\x29\x4a\x21\x30\x52\x62\x6b\x0a\x25\xfa\xe1\x7b\ -\x74\x00\x3a\xc0\x05\xfe\x61\xb5\x22\xf7\x77\x90\xaf\x04\xa4\xc6\ -\x38\x81\x71\x96\xcc\x94\x88\x28\xa2\x12\x40\x23\x21\x33\x25\xa5\ -\xd2\x10\x27\x0c\xd3\x12\x54\x40\x18\x46\x48\x21\x28\x8b\x82\xa2\ -\xb6\xe8\x11\xd6\xf9\x9b\xc4\xfa\xd4\x49\x8d\x20\xd2\x01\x5a\x87\ -\x7e\xb3\x55\xc6\xe3\x55\x95\x21\x52\x8a\x72\x3c\x46\x64\x39\xc5\ -\x70\x44\xb6\xbd\x4d\xd6\xdf\xc3\x0d\x86\x50\x96\xe8\x6e\x0f\xba\ -\x1d\xe8\xb4\x21\x0c\x51\xcd\x06\x41\xb3\xc5\xa4\x2c\x49\xcb\x0a\ -\x17\x68\x72\x2c\xa5\x35\x75\xca\xa4\x20\xb0\x82\xd0\x49\x22\xa1\ -\xb0\x45\x49\xa0\x35\xa3\xe1\x10\x1d\x86\xe4\x45\x01\xa6\x42\xc4\ -\x11\xcd\xee\x1c\x61\xd0\x42\x05\x31\x41\x1c\x33\x9a\x8e\x28\x4d\ -\x06\x91\x83\x6c\x44\xb3\xd3\xc4\x55\x86\x46\xdc\x24\x10\x9a\xc1\ -\x4e\x9f\x7c\x3c\x45\x4a\x47\xd4\x90\xf4\x12\xc1\x4b\xe7\x8e\x73\ -\xbc\x9d\x90\x00\x93\x3c\x67\xe0\x4a\xee\x8e\xf7\xf9\x6c\x6b\x8b\ -\x63\x27\xce\x70\x66\x69\x1d\x86\x39\xe5\x28\x43\xa2\x98\x9a\x8c\ -\x1b\x77\x6f\xf1\xc4\xf9\xa3\x28\x0c\x5a\x18\xca\xdc\xdb\x4e\x2f\ -\x74\xdb\x5c\xbe\x78\x91\x0b\x4f\x3f\x8d\x02\x5c\x51\x11\xd5\x82\ -\x15\xe1\x24\xa1\x8e\x1e\xd2\xb6\x04\x08\xf9\x08\xd8\x85\x93\x33\ -\xd8\x0b\x65\xfc\x43\xf8\x66\x5f\x39\x08\x08\x48\xb3\x1c\x61\x43\ -\x16\xe6\x16\xe6\x15\x82\xd1\x30\xfb\xd7\xf3\xb1\x16\xff\xf5\x3f\ -\xfa\x4f\x19\xdc\xfe\x0c\x31\xea\xf3\xf4\x53\x4f\x30\xdd\xdf\xa7\ -\x7f\xff\x3e\x8b\xeb\x47\x68\xcc\xcf\x43\x65\x31\xa6\x04\x0c\xed\ -\x46\x40\x3e\x19\xf2\xc9\x27\x3f\xe4\x60\x3c\xc4\xc5\x21\x57\xee\ -\xdc\x21\x17\xd0\x6d\x37\xd9\x3d\x18\x90\x9b\x92\xb3\x47\x57\xb8\ -\x76\xed\x73\xb4\xd6\x2c\xcd\x2f\xf0\xca\x2b\x2f\xf0\xc9\xa5\x8b\ -\xdc\xb9\x73\xc7\x4b\xbe\x3e\xbf\xcb\xf2\x42\x97\x1b\xb7\x6e\x70\ -\x6a\x79\x9e\xdd\xdd\x3d\xa6\x53\x2f\x33\x94\x52\x12\x06\xcc\xc4\ -\x11\xcf\x3e\xfb\x2c\xd3\xe9\x94\xcb\x97\x2f\x33\x99\x4c\xbc\xa7\ -\x73\x5e\x52\x55\x70\xe7\xce\x36\xe3\xf1\x98\x28\x8a\xd1\xda\xbb\ -\x8a\x94\xa5\xa9\xc1\x56\x49\x14\x45\x64\x99\x07\x4a\x3c\xdf\x5b\ -\x13\x45\x8a\xb9\xb9\x6e\x8d\x7c\x3f\xcb\x33\xcf\x3c\xc3\x24\x1d\ -\xf1\xce\x0f\xbe\xcf\xf5\x1b\xd7\x78\xf0\xe0\x3e\x4a\xc1\xc6\x7a\ -\x83\xe1\xc4\x6b\xb3\x65\x08\x77\xb7\xb6\xb9\x75\xef\x3e\xe3\x2c\ -\x07\x15\x62\xcb\x8a\x2a\xcb\x09\x44\xad\x16\x0b\x03\x6f\xbf\x93\ -\x97\x14\x69\x41\x96\x15\x7e\xc3\x97\x75\x3f\x26\x3c\x1d\x52\x68\ -\x6f\x30\x17\xc4\x11\x3a\xf4\x68\x2f\x4a\xf9\x28\x50\xed\x67\xac\ -\xa2\x7e\x48\xa5\x66\xfd\x3c\xf5\x7b\xa1\x14\x42\xc9\x2f\x58\x02\ -\x39\x3c\xe7\x59\xe8\xc0\xbb\x5c\xd6\xcc\x3c\x59\xdf\xae\x42\x2b\ -\x44\x14\xfa\x39\x6d\x14\x53\xe4\x7e\x03\x33\xcd\xc8\xb2\x82\xf1\ -\x60\x48\x9e\xe7\xb3\xc8\x9f\x76\xa3\xe9\xb3\xaf\x8b\x12\x26\x53\ -\xd2\xb1\xbf\x91\xab\xbc\xf0\xf3\x6e\xeb\x11\x64\x5d\x33\xbd\xf2\ -\xc9\x04\xd2\x94\xb2\xf2\xf9\x4e\x22\x8c\x88\x1a\x4d\x54\xbb\x4d\ -\xd0\xed\x7a\x1e\xb7\x92\x1e\x03\x08\x82\x3a\xc7\xd9\x61\x4b\x43\ -\x55\x19\x1a\xcd\xa6\x9f\x2d\xd7\xe0\x28\x41\x8d\xcd\x64\x39\xc3\ -\xfe\x3e\xce\xd8\xd9\x5c\xbe\xca\xb2\x5a\x29\xe5\xea\xc9\x84\xae\ -\x6f\x36\xdf\x2b\xbb\xca\x78\x63\x02\xad\x40\xb8\x99\x81\x44\xbf\ -\x7f\xc0\x68\xa7\x4f\xbb\xdd\xe6\xf8\xb1\x23\x28\x0c\xe4\x53\x4e\ -\xae\x2d\xf3\x0b\x3f\xf5\xe3\xac\xb4\x43\xf2\x09\xb4\xbb\x11\x19\ -\x25\x85\x12\x3c\xf5\xdc\xd3\x48\x15\x70\xb0\x37\xe6\x48\xa7\x45\ -\x28\x02\x8c\x31\xbc\x7f\xf1\x23\x9e\x78\xe6\x3c\x65\x09\x83\xfe\ -\x1e\x93\xd1\x90\xe1\xfe\x3e\x5f\x7e\xf9\x05\xde\x79\xfb\x7b\xbc\ -\xf0\xfc\xf3\xcc\xf5\xba\x7e\x6e\x6c\x1e\x99\x4e\x3c\xf2\x56\x0f\ -\x14\x66\xc8\x79\xed\x6b\xfd\x9b\x75\x11\x2d\xea\xb2\x5a\xcc\x66\ -\x96\xbe\xb7\x90\x58\x9c\xcf\x87\x95\xd2\x8f\x25\x1c\xbf\xdb\x88\ -\x25\x41\xa2\xdf\xdc\xab\xf8\xd5\x3f\xf9\x8b\x37\x39\x72\xfc\x14\ -\xa5\x94\x4c\xef\x3d\x20\x5c\x5e\xa5\xd1\x6e\x33\xe9\xf7\xfd\xf7\ -\x19\x8f\x88\x7b\x1d\xa2\x28\xa1\x95\xb4\x98\x9f\x5f\x20\x2b\x0a\ -\x2e\xbe\xf7\x03\x48\x53\xce\x9c\x3d\x8b\x0e\x62\xf2\xa2\x64\x9c\ -\x56\x1c\x3b\xb2\xc4\xa7\x1f\x5f\xe1\xa9\xf3\x8f\x31\x38\x18\x71\ -\xf4\xf8\x11\xd2\xc9\x84\x8f\x3e\xfc\x80\xe7\x2f\x3c\xcb\x3b\xef\ -\xbd\xcf\x6b\x3f\xf6\x3a\x77\xb7\x77\xd9\x58\x5b\x46\x20\x89\xe3\ -\x08\x29\x15\xc3\x61\x46\xa3\xe1\x4d\xea\x7d\xe0\x78\x8b\xd5\xd5\ -\x55\x3e\xfd\xf4\x53\x26\x93\x09\x65\x59\x11\x04\x21\x67\x8f\xf4\ -\xf8\xf8\xea\xe7\x2c\x2c\x2c\xb0\xb8\xd8\xc1\x39\x49\x9a\xa6\x3e\ -\xac\x0d\x4d\x9a\xa6\x54\x95\x4f\x95\x98\x4e\xa7\x2c\x2c\x2c\x93\ -\xa6\x39\x20\x6a\x4f\x25\x89\x73\x8a\xce\x5c\x97\x63\xc7\x8f\xa3\ -\xb5\xe6\xce\xbd\xfb\x7c\x72\xf9\x3a\x9f\xdf\xdb\x61\x6f\x38\x66\ -\x62\x61\x6f\x62\x79\xfb\xc3\x8f\xd8\x1d\x4c\xbc\x61\x21\x1a\xad\ -\x63\xac\xf1\xe6\x00\x69\x9e\x7a\x4b\x1d\xeb\x4b\xc3\x28\x08\xd1\ -\x42\x51\x21\xe8\xcd\xf5\x3c\xbb\xea\x11\xd1\x81\x74\x40\x65\x3d\ -\xc9\x62\x92\x42\x3d\x32\x12\x0e\x2f\x56\xb0\x0e\x67\xbc\xd1\x80\ -\x3a\x24\x67\xa4\x19\xce\xfa\x80\x38\x77\x28\x5a\xc0\x93\x46\x94\ -\xf0\x82\x7d\x71\x58\xa6\x19\x4b\xa8\x75\x1d\x26\x27\xd1\x35\x67\ -\xda\x55\x86\x66\xdc\x00\x63\x69\x37\x9a\x64\x59\x41\xa7\xdd\x21\ -\x88\xbc\xda\xa8\xaa\x2a\x4f\x65\x2d\x0a\xcf\xb0\x13\x82\x4a\x29\ -\x7a\x73\x73\xc4\x35\x09\xa3\x34\x9e\xb6\x69\x46\x23\xec\xc1\x3e\ -\xc5\x60\xe0\x99\x5c\xa6\x42\x24\x31\x2a\x0c\x7c\xeb\x10\xf9\xde\ -\x59\x68\xe5\x37\xbe\x90\x18\xe3\xe9\x9c\x12\x81\x76\x9e\x55\x16\ -\x28\x4d\xba\xdf\xc7\x48\x49\x23\x8a\xd1\x52\x91\x0f\x87\x94\xc6\ -\x87\xfa\x35\x5b\x4d\xc6\xa3\x11\x15\xde\x7e\x17\xa5\x66\x46\x05\ -\x3a\x8a\x49\xe2\x06\x45\x65\x30\x3e\x86\x1d\x87\x25\x8e\x42\xac\ -\x01\x37\xcd\xb1\x32\xc2\x0c\x27\xe8\x38\x21\x8c\x13\x1a\x51\xc0\ -\xbd\x1b\xd7\x98\xeb\x34\x90\x26\xe7\xd7\xff\xcb\x5f\x63\x29\x50\ -\x34\x15\x14\x45\xc9\xa5\x8b\x97\xa8\xf2\x1c\x29\x04\x6b\x6b\xeb\ -\xa4\x69\xca\xfc\x7c\x9b\x69\x6e\x19\x0e\x87\xdc\xbc\x79\x93\x17\ -\x5f\x7c\x91\xe9\x74\x4a\xb7\xdb\xe0\x93\x8f\x2f\xd3\x88\x43\x1e\ -\x3b\x77\x8e\x1b\x9f\xdd\x20\x0a\x02\x7e\xf2\x8d\x37\x7e\x57\x4b\ -\xf1\xbb\x91\x92\x84\x35\xe6\xf0\x97\x5a\xdf\x7a\x9f\x3a\x31\x93\ -\x6e\xa3\x41\xce\xdc\xea\x1d\x35\x21\xc4\x23\x53\x1e\xb8\xa8\x4a\ -\x62\x1d\x62\xf0\x12\x2a\x1c\x34\x1b\x7e\xb6\xb8\xb9\xb5\xff\xcd\ -\x7f\xfc\x0f\xff\x2e\x7f\xf0\xa7\x7f\xc6\xbd\x9b\x9f\xb1\x7e\xea\ -\x71\x76\xf7\x27\x1c\xdc\xbd\x43\xb2\xba\x86\x68\xb5\x51\xc2\x52\ -\xd9\x39\x84\x0c\x99\xa4\x53\x86\x83\x11\xbd\x6e\x97\x40\x47\xc8\ -\x56\x9b\x9d\x51\xc6\x07\x97\x3f\xe7\xd8\xfa\x1a\xa7\x16\x12\x06\ -\x23\xc3\x27\x57\x6f\xf3\xda\xeb\x3f\xce\xc1\xc1\x98\xb9\xb9\x36\ -\x93\xc9\x84\x93\xc7\x7d\xdf\xfc\xc1\x3b\x1f\xf0\xe1\x87\x1f\xf0\ -\xf4\x53\xcf\xb2\xba\xbc\x42\x9a\x7a\xff\xa2\xbd\x3d\x4f\xcf\x9b\ -\x9f\xeb\x30\x9d\x56\xdc\xbe\x7d\x9b\x53\xa7\x4e\xd2\x8a\x61\x30\ -\x71\x3c\xfb\xec\xb3\x44\x91\xe4\xda\xb5\xdb\x5c\xba\x74\x89\x1b\ -\xcd\x26\xdb\xdb\xdb\x3c\xf6\xd8\x63\x68\x05\x5a\x4b\x3a\x9d\x16\ -\xce\xf9\x5e\x27\x08\xba\x00\x33\xd9\xdb\xe1\x4d\x75\x48\x18\xc9\ -\x32\x45\x56\x16\x04\x81\xa2\xdd\xd4\x8c\xf2\x94\x67\x5e\x78\x96\ -\xf5\xb5\x25\xd2\x12\x76\x26\x15\xff\xfe\x2f\xfe\x9c\x3f\x7a\xeb\ -\x7b\x5c\xba\x7e\x13\x7a\x8b\x88\x66\x89\x9b\x16\x14\x3d\x50\xf5\ -\x66\x6e\xb4\xe2\x1a\x94\x12\x94\xa2\x40\x3b\xc1\x34\x2f\x70\x07\ -\x03\xf6\xa5\x24\x6c\xc4\x58\xeb\xcb\x29\xe9\xbc\xe2\x49\x08\x81\ -\x34\x5e\xaf\x2b\x54\x40\xa4\x02\xa4\x56\x48\x2b\xbd\x42\x08\x07\ -\xc6\x12\x28\x0d\x48\xa6\xda\x13\x77\x62\x15\x60\x0e\xe7\xc1\xd2\ -\x9b\x2e\xa6\x93\x29\x32\xac\x65\x8f\x16\xca\xf1\x94\x52\x78\xe1\ -\x85\x13\x90\xe6\x39\xae\xe6\x61\x4f\xf3\x12\x61\x2c\x59\x61\x20\ -\xcd\x98\x8e\xc6\xe4\x94\xbe\x4a\xa8\x03\xc8\xa5\xf3\xb7\x5b\x3e\ -\x99\xc0\x64\xc2\xc1\xce\x8e\xb7\xd2\xd0\xda\xa3\xc1\x49\x82\x6c\ -\x36\x40\x7a\x53\xfa\x74\x3c\xc1\x98\x0a\x11\x79\x55\x96\x75\x16\ -\x83\xb7\xf7\x95\x38\x74\x9d\x03\x45\x59\x42\x51\xe2\x90\xa8\x30\ -\x22\x52\x01\x42\x69\xa2\xd5\x35\x26\xe9\xd4\xbb\xba\x54\x16\xc2\ -\x70\x16\xb8\x37\xda\xd9\x46\x74\x3b\x1e\x1c\xaa\xfb\x78\x25\x25\ -\x69\x1d\x63\x9b\xe6\x99\x9f\xcc\x28\x50\x52\x23\x8c\x9f\xd3\xbb\ -\xd2\x42\x56\x61\xc2\x02\x82\x10\xeb\x04\x85\x29\x68\x34\xe6\x58\ -\x5b\x5d\xe6\xc8\x52\x97\x86\x5a\xa1\x17\x06\x8c\xfa\xfb\x44\x8d\ -\x98\xcf\xae\x5e\xe3\xc4\xd1\x63\x74\xbb\x5d\x2e\x5e\xbc\xc8\xab\ -\xaf\xbe\xc8\xdc\x5c\x7b\x96\xfd\xbd\xb7\xb7\x47\x10\x04\xb4\x5a\ -\x2d\x9a\xcd\x26\x79\x0e\xd7\xae\x5d\xe3\xe7\x7e\xe6\xa7\xe8\xb4\ -\x9b\xfc\x9b\x3f\xf9\x53\xfe\xe9\x3f\xf9\xaf\x7e\xa7\x21\xf9\x8d\ -\x3c\x2f\x4e\x55\xc6\xde\x08\x95\xfc\x4b\xb7\xf1\x21\x0b\xcf\x1d\ -\x02\x61\x82\x87\xc6\x02\xb5\xf5\x1e\xae\xfe\x2a\x27\xfc\xbf\xc1\ -\xd3\xe2\x04\x02\x6b\x2c\x81\x52\xbe\x5f\x2d\x0d\x91\x56\xc4\xad\ -\xe4\xb7\xa7\x96\xdf\xea\x2c\x2e\xf2\xee\xbb\x1f\x90\x15\x86\xee\ -\xd2\x2a\xc3\xe1\x88\xaa\x30\xb4\x16\xe6\xbd\x9b\xe2\x74\xca\xb4\ -\x7f\x80\x91\x8a\xf9\xb9\x05\xe2\x38\x66\x38\x1a\x53\x15\x25\xab\ -\xcb\x2b\x9c\x3b\xf7\x04\x9f\xdf\xbe\xc7\xc1\xa4\x64\x75\xb9\xc3\ -\xbd\x7b\x5b\x8c\x06\x07\xac\xae\x2c\xa3\xb0\x48\x29\x28\xf2\x9c\ -\xa5\xc5\x05\x4f\x5f\x11\x92\x1b\x9f\xdd\x60\x75\x75\xcd\x9b\xdc\ -\x21\x58\x5d\x68\xd3\x6a\x44\xdc\xbe\xbb\x43\x1c\xc7\x8c\xc7\x63\ -\x82\x20\x60\x92\x56\x0f\xe9\x89\x4e\xd0\x68\x34\x39\x77\xee\x28\ -\xad\xd6\x1c\xef\xbe\xfb\x8e\x27\xae\x8c\x33\xd2\x34\x43\xeb\x80\ -\x34\xcd\x28\x8d\xa0\xaa\x0c\xad\x96\xe2\xc1\x83\x5d\xa2\x28\xaa\ -\x9d\x4b\xbc\x7c\xb1\xaa\xed\x72\x74\x10\x30\xce\x26\x4c\x8a\x8a\ -\x6b\xd7\xaf\x73\xf2\xd4\x29\x84\x0a\xd8\xda\xdd\x67\x7e\xa5\xc9\ -\xd1\xd3\x27\xd9\x19\xa6\x0c\xf2\x9c\x85\x95\x0d\x84\x8e\x48\x4b\ -\x83\x8a\x12\x4c\x09\x76\x32\xa1\x1c\xf4\x29\xa6\x23\xb2\x2c\xc7\ -\x14\x05\x91\x52\x48\x3c\x41\x64\x6e\xbe\xc7\x64\x3a\xc1\x38\x2f\ -\x73\x14\x12\x22\xad\x89\x83\x80\x50\x4a\xdf\x9b\x8e\xc7\x48\xe5\ -\x8d\xe6\xcb\xaa\xc0\x58\xcf\x7a\xb2\x65\x89\xb0\x16\x5b\x14\x94\ -\xd3\x29\xae\xaa\xbc\xc4\xd0\x94\x94\x95\xb7\x0e\xaa\x4c\x49\x1c\ -\x04\x44\x5a\xfb\xa8\xa0\x38\x22\x9d\x4c\x68\xb7\x5a\x44\xa1\xf7\ -\xad\x8e\x1b\xf1\xcc\x52\xc7\x9a\x8a\x76\xa3\x41\x99\x65\x58\x63\ -\xd1\x81\x9f\x11\x57\xce\x52\x4c\x26\x54\x83\x01\xe5\x78\xec\x4b\ -\xe8\x20\x40\x37\x9b\xd8\x28\x22\xe9\xf5\x88\x1a\x0d\x9c\xf6\x02\ -\x07\x8b\xa3\xaa\xea\xf0\x36\x81\xb7\x34\x0a\x03\x44\xe0\x73\x95\ -\xa4\x92\x18\x6b\x51\x52\x79\xf0\x0b\xa8\xd2\x1c\xca\x8a\x30\x8c\ -\xbc\x43\xa6\xf1\xb4\xd6\xe1\xe0\x00\x27\x25\x9d\x56\x0b\x5b\x56\ -\xd8\xc1\x80\x6a\x32\x41\x36\x12\xe2\x6e\x97\xb8\x99\xa0\x02\xed\ -\x01\xc5\xba\xc5\x30\x55\x85\x4d\x33\x8c\x00\xab\x25\x42\x7a\xc0\ -\xd2\x96\x06\x8c\xa5\xcc\x2a\x9f\x15\xdd\x9e\x23\x68\xb5\x69\x34\ -\x9b\x5e\x6c\x5e\x66\x34\xa5\xa5\xd8\xdf\xe3\x6f\x7d\xed\x0d\x5e\ -\x38\x35\x0f\x79\xc9\xad\xeb\xd7\x38\x75\xe2\x04\x47\xd7\xe6\xd8\ -\x3b\x18\xe2\xb0\xac\xaf\xad\x53\x14\x06\xad\x34\x6f\xbf\xfd\x0e\ -\x41\x10\x32\x3f\xbf\xc0\xea\xea\x02\x7b\x7b\x03\x2e\x7e\xf0\x21\ -\xab\x2b\xcb\x1c\x5d\x5b\xe1\x07\xef\xbc\xc3\xf1\xa3\xc7\x38\xb6\ -\xb1\xf1\xdb\x52\x70\x23\xd2\x6a\x5f\x38\x47\x51\x64\xfe\x30\x16\ -\xf6\xe1\x8e\x15\x5f\x44\xa5\x0f\x39\x21\xde\x45\xb3\xd6\x3f\x21\ -\x1e\x35\x38\x7f\xc8\x22\x91\x42\x52\xd5\xbc\x5f\xa5\x24\xd6\x78\ -\x00\x01\xa0\x10\xfc\xd6\xfa\xf1\x0d\xbe\xf7\xfd\xf7\xb8\x75\xef\ -\x1e\x61\xd2\x66\x94\x97\x24\x73\x8b\x4c\xb3\x02\x93\x97\x04\xed\ -\x36\x4e\x07\x48\x29\x18\xee\xf5\xd9\xdf\xda\xc1\x2a\xc9\x97\x9e\ -\x7d\x9e\x07\x9b\x5b\x7c\x7a\xed\x3a\x5a\x87\xac\xac\xae\xf2\xc3\ -\x1f\x5e\x65\x79\x61\x91\x24\xd2\x2c\xce\x75\x29\xb2\x14\x8d\x20\ -\x9b\x4e\x69\x26\x09\xed\x4e\x9b\xed\xed\x1d\x5e\x7c\xf1\x65\xbe\ -\xf5\xad\x6f\xcd\x0c\x05\xf2\xd2\xdf\x14\xed\x56\x87\x6e\x4b\x71\ -\xf1\x87\x97\x39\x79\xf2\x24\xcb\x8b\x4d\x9a\xb1\xa2\x7f\x30\x61\ -\xad\x17\x82\x96\xdc\xba\xb5\x45\xbb\xdd\xa6\xaa\x4a\xbe\xf4\xa5\ -\x2f\x31\x1e\x8f\xb9\x77\xef\x5e\x1d\x08\x17\xd2\x6e\x37\x29\xcb\ -\x8a\xc9\xa4\x60\x7f\x7f\x9f\xb9\xb9\x39\x8f\x42\xd7\x64\x85\xa2\ -\x2e\x1f\xa3\x24\x60\xb9\x15\x93\x1a\xc7\x74\x32\x61\x6d\x7d\x03\ -\x21\x05\x51\x23\x21\x2d\xc1\x6a\xd0\x49\x87\x8f\x3e\xfe\x94\x69\ -\x65\x98\xa6\x05\x95\xd4\xb4\xba\x73\xc4\x49\x1b\xdd\x48\x48\xe6\ -\xbb\x04\x8d\x06\x4a\x2a\xca\xa2\xa0\x2a\x4a\xb2\xe1\x10\xd7\xef\ -\x93\xda\x43\x05\x8f\xf5\x8f\x5a\x89\x54\x55\xde\xc8\xbd\xc8\x0b\ -\xa4\x90\x24\x71\xe2\x29\xa5\x52\xd6\x59\x4f\x12\x25\xbc\x9c\x50\ -\xd5\x44\x88\x50\x07\xc4\x51\x34\x9b\xd3\x1e\xde\xa0\x55\x51\x7a\ -\x17\x8d\xa2\xf4\x94\xd1\xbd\x3e\x41\xb3\x81\x37\x28\x29\x99\x0c\ -\x87\x98\xd1\x90\xdc\x39\xcc\xfe\x01\x95\x83\xa2\xbf\x8f\xcb\x72\ -\x2a\xeb\x28\xc7\x23\x9c\x80\xa0\xd9\xa4\xd1\xeb\x11\xb7\xdb\x08\ -\xad\xfd\x66\xc9\x73\xb0\x96\x20\xf1\x55\x87\x3d\x24\x67\xd4\xfe\ -\xd4\x87\x07\xac\xcd\x32\x08\x02\x84\xd6\x33\x7a\xb0\xa9\x2a\xa4\ -\xf0\x3c\xf4\x59\x0e\xb7\xf3\x59\xc1\x0a\x0f\xae\xa5\x59\xe6\x2f\ -\x9f\xe1\x90\x7c\x32\xc5\xa6\x19\x41\xa7\x43\x6b\x61\x9e\x5e\xaf\ -\xe7\xf5\xdb\x52\x90\x57\xfe\x77\x2c\x4c\xe5\x2d\x77\xf1\x13\x92\ -\xa4\xd9\xa4\x70\xde\x6d\x14\x63\x29\xd3\x0c\x69\x84\x6f\x4d\x44\ -\x40\x77\x71\x99\xaa\xac\x98\x4e\x47\x04\xca\x11\x51\x71\x7a\x65\ -\x89\x7f\xf6\x0f\x7e\x95\xf1\xbd\x3b\x8c\xb6\xf7\x89\x30\x3c\xf9\ -\xf8\x39\x8a\x22\x47\xa8\x88\xdd\x9d\x5d\x10\xb0\xb1\xbe\xc8\xa5\ -\x4b\x97\xb9\x7f\xef\x1e\x17\x2e\x5c\x60\x6f\x6f\x8f\x5e\xaf\xc7\ -\x78\x9c\x72\xe7\xe6\x2d\xce\x9f\x3f\xcf\x68\xb0\x8f\xad\x4a\x3e\ -\xfd\xf8\x22\x7f\xf3\x67\x7e\xe6\x77\x94\xe4\x5f\x0a\xe7\xa8\xaa\ -\x82\x38\xf0\x2e\xa4\x4a\x1d\xb2\xf1\xfe\xfa\x8d\xac\xed\x17\x1a\ -\x68\x31\xc3\xc0\x0e\xbb\xe4\xb2\xcc\x50\x91\xcf\xf5\xa9\x4a\x9f\ -\x57\x9b\x44\x21\x58\xc7\x60\x38\x78\xaf\xd3\xeb\x89\x12\xdc\x7f\ -\xf4\xfa\x2b\xdc\xdd\xfc\x03\xa6\xc3\x3e\xa2\x84\x5e\x33\x26\xdd\ -\xda\x05\x24\xa5\x0e\x10\x42\x33\xbf\xb4\x42\xd5\x1a\x53\x64\x63\ -\x26\xc3\x21\x3f\xf8\xe8\x22\x71\x18\x7b\x6f\xe1\xe1\x84\xde\xfc\ -\x02\x2f\x3e\xf9\x0c\x97\xde\x79\x8b\x2f\x3f\xff\x0c\x46\x08\x8c\ -\x83\x66\x3b\xc1\x5a\xdf\x67\x14\x95\x63\x32\x1a\xd3\xdf\xd9\xe5\ -\xe7\x7e\xe6\xe7\x18\x8c\x06\xbc\xf9\xe6\x9b\x68\xad\xb9\x70\xe1\ -\x02\x79\x36\x21\xcf\x3d\x68\xb3\x3c\x17\xb3\x73\x50\x30\x1a\x8d\ -\xe8\xf5\x7a\x5c\xbb\xdb\xa7\xd3\xe9\xf1\xd4\xe9\x15\x6e\x3c\x18\ -\x51\x55\xd5\x8c\x6b\xbd\xba\xba\x4a\x9a\xa6\x5c\xb9\x72\x05\xe7\ -\x7c\xea\xc4\xfa\xfa\x7a\x4d\x1d\x3d\x49\x92\x48\x6a\xe1\x0f\x71\ -\x1c\xfb\x1b\x59\xc0\xce\xa8\x24\x9d\xa4\x4c\x46\x53\x86\x07\x03\ -\xa4\x56\x74\xe6\xdb\x34\x25\xec\xa6\x10\x48\x45\xbb\xd9\xa0\xd3\ -\xea\x51\x6d\xf7\x19\xf6\xc7\x64\x65\x8e\x0a\x14\xa5\x33\xa8\x4a\ -\xe0\x30\x75\x46\xb2\xae\x5d\x2f\x05\x25\xd0\xec\x75\x99\x16\xb9\ -\x1f\xf9\x00\x58\x83\xcd\x2b\xcf\xdb\x29\x0d\x94\x15\x6e\x38\x62\ -\x98\x67\xbe\xf7\x73\xc6\x8f\x76\x9c\x5f\x98\x99\x0e\x3c\x42\x3c\ -\x9e\x60\xa4\x22\x6b\x24\xcc\x58\x05\x5a\x3d\xcc\xfe\x75\x3e\x54\ -\xba\x6a\x55\x70\xb0\xcf\xb8\xd5\xf4\x83\xc9\xb2\x80\x46\x0c\x51\ -\xe4\xcb\xd3\x76\xcb\x9b\x0c\x74\xda\x98\xac\xa0\x33\xd7\x23\xb3\ -\x15\x4e\xcb\x99\x37\xd6\x61\xaf\xdd\x6a\xb5\xd0\x5a\xb3\xff\xe0\ -\xc1\x8c\x52\x78\x48\xd2\xb0\x16\x4c\x4d\x39\x4c\x9a\x4d\xef\x51\ -\x36\x53\xd9\x52\x13\x5e\x2c\x56\x58\x04\x7e\xc3\xab\x40\x63\xea\ -\xf1\x99\x51\xbe\x22\x92\x5a\x61\x14\xd0\xed\xd1\xed\x74\x98\x1c\ -\x0c\x7d\x52\xc5\xee\xae\x97\x4b\x0a\x7f\x99\x95\x45\x81\x0e\x02\ -\xac\x35\x58\xe1\x85\x15\xd4\x96\xbf\x94\x39\x4e\x0a\x2a\xa7\x67\ -\xc8\xb0\x74\x01\x59\xe1\x09\x28\x55\xe9\x53\x2d\xe7\x3b\x31\x62\ -\x74\x40\x27\x0a\x38\xbd\x26\xb9\xfa\xdd\x4d\xbe\xfc\xc6\x6b\xf4\ -\xda\x21\x5a\x42\x23\x0e\x67\x19\xe2\xad\x46\x93\xf7\xde\xf3\x7c\ -\x7e\x6b\x0c\x83\xc1\x80\x38\x08\x59\x9c\x9b\xe7\xbd\xf7\xde\xe3\ -\x95\x97\x5e\xe6\x4f\xff\xec\xbb\x5c\x78\xee\x59\x6e\x5d\xbb\xca\ -\xb3\xe7\x9f\xc2\x59\x7b\x2a\x0e\x34\xce\x09\xf2\xdc\x8f\x86\xa2\ -\x30\x02\x67\xea\xc3\xed\xaf\x8f\xc8\x55\xff\x43\xed\xd9\xf5\x23\ -\x55\xb8\x8f\xfe\xa8\xfd\xbb\x54\x6d\x07\xab\x6b\xa1\x76\x59\x14\ -\x08\x01\x49\x23\xf9\x97\x07\xd3\xb1\x6b\x04\xd1\xef\x9c\x3c\x7b\ -\xfa\xf5\x6f\x7d\xf7\xcf\x91\x41\xc8\x68\x9a\x83\xd2\xc8\xb8\x49\ -\xa9\x35\x2a\x08\xb1\xc6\x2b\x6e\x06\xbb\xbb\x08\xa5\x11\x38\xf2\ -\x83\x21\xcb\xc7\x4f\x13\x35\x3b\x6c\x6d\x6f\x73\xef\xde\x5d\x16\ -\x7a\x5d\xce\x9d\x39\xc5\x0f\x3f\xfc\x80\xdd\xed\x2d\x56\x56\x96\ -\x31\x95\xbf\x29\xa5\xd6\x24\x49\x83\xf1\x64\xca\xe2\xe2\x32\xc6\ -\xf9\xa4\x82\xd3\x67\x4e\xd2\x68\xb4\xb8\x7d\xfb\x36\xf7\xee\xde\ -\x67\x7d\x7d\x9d\xcd\xcd\x4d\x96\x56\x8e\xcc\xa4\x87\xaa\x4e\xba\ -\x17\x42\x30\x98\x56\x35\xb9\xbe\xe0\xe8\xd1\x23\x33\x45\x49\xb7\ -\x1b\xb3\xb8\xb8\xc2\xd1\xa3\x47\x28\x8a\x92\x5b\xb7\x6e\x71\xf5\ -\xea\x55\x8e\x1c\x39\x52\xdb\xc2\x14\xb8\xda\x79\xe3\x10\xe5\x6e\ -\xc7\x01\xed\x24\xe6\xf3\xcf\x6f\xf1\xf2\xb3\xe7\xd0\x71\xc4\xd6\ -\x76\x9f\x4e\x2b\x61\x54\x58\xfe\xcd\xbf\xfd\xb7\xdc\xdb\xda\xe6\ -\xdc\x13\x4f\x32\x4c\x33\x76\x76\x76\x21\x8e\x7d\x8e\x90\x10\xe4\ -\xf9\x04\xe7\x40\xd7\x3e\x52\x49\x92\xf8\xf0\x35\x53\x91\xb4\x5b\ -\xc8\x40\x11\xc6\x31\x2a\x0a\x71\xda\x83\x35\x4a\x07\xa8\x28\xf4\ -\x3d\xa5\xd6\xc4\xdd\x2e\x41\x23\xc1\xc5\x11\xba\xd1\x40\xc6\x31\ -\x22\x8e\x89\x1b\x0d\x82\x28\xa6\xd2\x0a\xdd\x68\xd0\xe8\xb4\xd1\ -\x49\x82\x6c\xc4\x04\x4d\xff\x79\x3a\x49\xbc\x29\x84\xd2\x74\x7b\ -\x3d\x6f\x48\xb7\xba\x4a\x18\xc7\xd8\x50\x7b\xcb\xa2\x66\x03\xa1\ -\x24\x8d\xa4\xe1\xd3\x48\x82\x90\x2a\xcb\x68\x75\x3a\xde\x50\x4f\ -\xc9\x87\x08\x79\x4d\xe8\x3f\x94\x4e\x16\xa3\x11\x32\xf1\xe1\x78\ -\x55\x2d\x54\x10\x35\xaf\x5a\xd6\xea\xac\x72\x34\x06\xa9\xbc\xe2\ -\x49\x4a\x94\xf4\x73\xed\x30\xf4\x79\x50\x41\x10\x50\x56\x25\x76\ -\x3c\xc6\x15\x05\x06\x50\x51\x48\xd2\x6a\x22\xb4\x4f\xcf\x88\x94\ -\xae\x93\x52\x42\x9c\xf0\xea\xa8\x69\x9a\xd2\x6a\xb7\xa9\x9c\x25\ -\x4c\x62\x3f\xab\x96\x3e\xd5\xc2\xec\xf5\x3d\x12\x6f\x2b\x4f\x54\ -\x96\x21\xb1\x0e\xe9\x24\x6d\xb0\x82\x6c\x3c\xc6\x00\x71\xa4\x90\ -\xae\x20\x1d\xec\x72\x7a\x65\x89\x5f\xff\xb5\x5f\xe4\xd2\x5f\x7c\ -\x4a\x52\x95\x3c\x7f\xfe\x1c\x55\x91\x22\x95\xc0\x39\xdf\x9a\x7c\ -\xf0\xe1\x45\xc2\x30\xa4\xd3\xf1\xc9\x27\xbd\x5e\x97\x46\x23\xe6\ -\xea\xe5\xab\xd8\xca\x30\x3f\x37\x4f\x55\xe6\x24\x71\xc2\xb5\xcb\ -\x9f\xa0\xb0\xbc\xf2\xd2\x0b\xfb\x91\xd6\x17\xac\xb5\xb8\xaa\xa4\ -\x95\x24\x14\x79\x86\xc3\xa1\x66\x23\x26\xf1\x97\xf6\xe8\xa3\x37\ -\xb2\xb4\x35\x15\xd3\xfd\x08\xfb\xcb\x57\xd9\xb5\xf5\xa8\x13\x44\ -\x61\x58\x2f\x78\x4b\x10\x28\xa4\x00\xe1\x2a\xe6\x1b\x6d\x11\xc0\ -\x6f\xb4\x24\xfc\x8b\x7f\xfa\x6b\xa4\x7b\x9b\x2c\x25\x01\x07\xb7\ -\x3e\xe3\xd8\xca\x02\xb2\xaa\x30\x3b\xbb\x60\x2d\x95\x05\xdd\x6c\ -\x11\x46\x09\x8d\x56\x1b\xc2\x88\xbb\xbb\xfb\x8c\x2b\x07\x71\x8b\ -\x42\x86\xfc\xfe\x37\xbe\xc3\xff\xfb\xad\x3f\xe1\xa5\xaf\x7c\x85\ -\x27\x5f\x78\x91\x8f\xaf\x5d\xe7\xe6\xfd\x2d\x32\x03\xc6\x29\xc6\ -\x69\x46\x51\x9a\x59\x0e\x72\x96\x65\xe4\xb9\x77\xfc\x38\x7f\xfe\ -\x3c\xaf\xbf\xfe\x12\xdf\xfe\xf6\xb7\xd9\xd9\xd9\xf1\x0c\x22\x6b\ -\x89\x23\x66\x3a\xe7\x43\xa3\x80\x5e\xaf\x57\x1f\x4e\x30\x18\x0c\ -\x66\x94\xbd\xb2\x2c\x19\x8d\xc6\xac\xaf\xaf\xf2\xd2\x4b\x5f\x62\ -\x63\x63\x83\x7b\xf7\xee\xf1\x8d\x6f\x7c\x93\x8b\x17\x2f\xb2\xbb\ -\xbb\x4b\x10\x40\x18\x7a\x64\xb7\xa9\xe1\xc1\xcd\x4d\xd6\x17\x97\ -\x99\xa6\x30\x19\x4c\xe9\x75\xba\x14\x06\xda\x89\xe4\x57\x7e\xe9\ -\xef\xf0\xf7\xbe\xfe\x4b\xbc\xfd\xfd\x37\xf9\xe4\xd2\x87\xc4\x9d\ -\x06\x71\xa2\x19\x65\x23\x5f\x0f\x09\x50\x71\xe0\xed\x91\xb4\x20\ -\xad\x72\x64\xa4\xa1\x48\xd1\x91\x06\x25\xb0\xc2\x79\xc3\x01\x25\ -\xd0\xa1\x46\xc5\x01\x68\x89\x91\xde\x5c\xc0\x0a\x8b\xab\x3f\xc7\ -\x60\x31\xd2\x61\x84\xf3\xff\xaf\x05\x68\x81\xd3\x9e\xaf\x8c\xc2\ -\xbf\xaf\x59\x98\xc6\x19\x64\xa4\x09\x1b\x11\x79\x95\x43\xbb\x49\ -\x66\x0a\x72\x53\x50\x39\x83\x8e\x02\x2a\x5b\xe1\x14\xa4\x55\x4e\ -\xd0\x88\x70\xca\x5b\xd6\x16\x55\xe1\x2d\x73\x6b\x19\xe6\xe1\x6b\ -\x78\xa8\xca\x31\x87\xb6\xb4\x8f\xb8\x59\x1c\x8e\xb6\x66\x11\xb4\ -\xc3\x31\x71\xb3\x03\x69\x41\x24\x14\xa2\xa8\x7c\x68\xb9\x75\x14\ -\x69\x46\x39\x1a\x32\x1a\x1c\x50\x65\xa9\xa7\x94\xce\x75\x69\xaf\ -\x2e\xe1\x42\x85\xd5\xde\x1a\xe8\xb0\x1a\x88\x6a\x79\xa5\xa9\x15\ -\x50\x3a\x0c\x98\xe6\xd9\x8c\x67\x7d\xa8\xe5\x2e\xf2\xdc\xc7\xec\ -\x24\x09\xf1\xf2\x02\xb2\xd5\xa2\xdd\x6e\x53\x96\x25\x07\x07\x07\ -\x44\x61\x08\x93\x29\xab\x8b\x0b\x88\xb2\x20\xa6\x42\x17\x29\xcf\ -\x3d\x76\x8a\xcb\x1f\xdd\xe2\xc7\x5f\x7d\x82\xb9\x66\x4c\x24\x20\ -\x0c\xd4\xec\xa2\xcb\xf3\x9c\xe3\xc7\x8f\x73\xfd\xfa\x75\xce\x9c\ -\x5e\x3f\x2c\xa2\x70\x16\x0e\x0e\x0e\x28\x8a\x82\x4e\xbb\xc9\xe9\ -\xe3\xcb\xfc\xd9\x77\xbe\xcd\x99\x13\x27\x38\x79\xf4\x08\xc2\xd8\ -\x1b\x89\x96\x34\xea\xc8\x62\x80\x38\x8a\x09\x6b\x05\x9e\x7f\x3c\ -\x04\x5b\x1f\xdd\xd4\x87\x3a\x73\xf5\xdf\xd7\x37\xf2\x8f\xee\x7b\ -\xf1\x08\xd6\x2d\xea\x24\x8a\x2f\xf4\xcf\xc2\xd5\xce\x88\x25\x5a\ -\x6a\x34\xfc\x76\xdc\x6a\xff\xd6\x67\x37\x6f\xb2\xb9\xbb\x87\x53\ -\x9a\x9d\xfd\x7d\x4e\x9e\x3d\x47\x7f\x32\x81\x83\x21\xb2\xd3\x9e\ -\x51\x2b\xab\xb2\xa0\xb2\xe0\x64\x80\x8c\x63\xa2\x30\x40\x2b\xc1\ -\xd6\xe6\x03\xf6\x76\x77\x59\x59\x5a\xe4\xd8\xb1\x65\xda\xed\x05\ -\x84\x70\xbc\xff\xfe\x07\x34\xda\x2d\x96\x96\xbb\xfc\xe0\x07\x97\ -\x58\x5c\x5a\x22\x0c\xbd\x47\xd8\x72\x2b\x40\x46\x21\x9b\x9b\xdb\ -\x44\x61\x93\xe7\x9e\x39\xcb\xd6\x76\xbf\x4e\x97\x18\x11\xc7\x6d\ -\xb2\x2c\x23\x8a\xe2\x3a\xcb\x29\x64\x3a\xcd\x99\x4c\xc6\xcc\xcf\ -\x2f\xd2\xed\xc6\x80\x62\x34\x4a\xd1\xda\xb3\xb2\x7c\x8f\x9c\xb2\ -\xb3\xb3\xc3\xeb\xaf\xbf\xc8\xd3\x8f\x9f\xa6\xd1\x9e\xe3\xda\xb5\ -\x6b\xfc\xf0\x87\x9f\x72\xeb\xd6\x6d\x46\x07\x03\x9a\xba\xcd\xfe\ -\xce\xae\x97\x3c\x2e\x2d\x60\x8c\x41\x29\x7f\xeb\x94\xc6\xb2\xd1\ -\x09\x11\xcd\x1e\x7f\xe3\x67\x5f\xe7\xdd\x0f\x3e\x85\x20\x20\x77\ -\x0e\x15\x04\x88\x20\xa0\x92\x10\x06\x81\x1f\x1b\xd5\x0c\x1e\x63\ -\x2d\xd5\x68\x08\x8d\x06\x69\x9e\x7a\x2b\x1f\x6b\x7c\x69\x58\xfb\ -\x52\x59\xeb\x3d\xad\x40\xf8\xf1\x4e\xe0\x79\xc2\x3a\x0c\x66\xb3\ -\x62\xad\xfd\xec\xd2\x14\x7e\xc3\xe9\x40\x7b\xdf\x2c\x51\x03\x9a\ -\xc2\x93\x76\x38\x5c\xe8\x75\x32\x43\x90\x24\x7e\xf4\x53\xd3\x3d\ -\x8d\x33\x58\x21\xbc\x76\xd9\xf9\x0d\xea\xb2\x1c\x11\xe8\x19\xae\ -\x72\xb8\xc8\x94\xa8\x0d\xd3\x85\x7f\x0e\x45\x9e\x13\xd4\x16\x3b\ -\x87\x37\xb2\x13\x60\xac\x9f\x91\xb6\x82\x08\x2d\x24\xd9\x68\xec\ -\x2b\xfc\xf1\xd8\x07\x88\xa7\x29\x2e\x4d\xa1\xd9\x40\xc4\x11\x22\ -\x0c\xbc\x9d\x4f\x14\x22\x02\x4d\x65\x0c\x41\x18\x12\xea\xc0\x5b\ -\x31\x3b\xe7\xfb\x6a\x07\x45\x9a\x92\xb4\x5a\x84\x71\x44\x65\x4d\ -\x2d\xd9\x74\x94\xe3\x89\x37\x2f\x98\xa6\x10\x04\x6c\x9c\x38\xce\ -\x70\x3a\xf2\xaf\x51\x6e\x08\x83\x18\x89\xa4\xdd\x6e\x31\xd8\xdd\ -\xc1\x69\x87\xb2\x19\x81\x4d\xf9\xf2\x97\x9e\xe6\x6b\xaf\xbe\xc8\ -\xe3\x47\x16\x10\xa9\x25\xdd\xdb\xa3\xd3\x6a\xd1\xea\x36\x08\x42\ -\x85\xd6\x21\x7f\xf4\xc7\xdf\x64\x7f\xff\x80\x17\x5e\x78\x01\x84\ -\x3f\x54\xe2\x48\x70\xe3\xfa\x4d\x76\xb6\xb6\xf8\x89\x37\x7e\x8c\ -\x76\x33\xe1\xdf\xfd\xe1\xbf\xe7\x4b\x4f\x3f\x4d\x12\x68\xd6\x16\ -\x97\x98\x6b\xb5\x36\x74\xdd\x0b\x0b\xfc\xb8\x4d\xf0\x57\x18\x3f\ -\x7c\x61\xa7\x7e\x71\xbf\xd6\xde\x7a\xff\xe1\x37\xf7\x57\x5d\xee\ -\x0e\x62\x1d\xb3\x37\x1c\xd2\xea\x74\x08\x5d\xc5\x3f\xfb\x87\x7f\ -\x9f\xff\xe6\x37\xff\x47\xaf\x7f\x35\x39\x77\xaf\x5f\xa1\xd9\x9e\ -\x63\x32\x4d\xa9\xf2\x82\xc2\x96\x34\x92\x98\x30\x4a\xc8\x32\x2f\ -\x09\x9b\x0e\x0e\xc8\xb5\x24\x6c\xc6\x34\xe7\x16\x90\xae\xe0\xe6\ -\x56\x9f\x97\x04\xac\xce\x07\x1c\xa8\x79\x9e\x79\xe5\x35\xb6\xee\ -\xdc\x61\x38\x49\x59\x3b\x76\x84\xb8\xdd\x24\x8c\x02\x84\x80\x8b\ -\xd7\x6f\x93\x24\x09\xc7\x8e\xae\x50\x55\xcc\xc4\x10\xbf\xfc\x4b\ -\x3f\xcb\xf6\xce\x84\xc1\x60\xc0\x83\x07\x0f\x78\xea\xa9\xa7\x88\ -\x63\xef\x03\x7c\xf5\xea\x55\x16\x17\xe7\xd9\xda\xda\x66\x7d\x7d\ -\x99\xb2\xf4\x27\x6a\xab\x95\x10\x87\x30\xcd\x34\x61\xa8\x6b\x8e\ -\xf7\x10\x21\x04\x61\x18\xf2\xe2\x8b\x2f\xd2\x49\xe0\x60\x62\x19\ -\xec\xf4\xb9\x73\xeb\x2e\x77\x6f\xdf\x21\x6a\x46\x2c\x2c\x2d\x10\ -\xb7\x13\x92\x48\x33\xca\x4b\x0e\xf6\xf7\xe9\x87\x11\xbb\xfb\x43\ -\xce\xb7\x8f\x72\x64\x69\x9e\x4b\x37\xef\x12\x37\xbb\x0c\xb3\x11\ -\xa6\x48\x21\x88\xc8\x2b\x6f\x93\x14\x08\xe9\xc7\x2d\x00\xcd\x26\ -\x2a\x0c\xe8\xb6\x9b\x38\xe5\x9d\x31\xcb\xaa\xf2\x82\x72\xeb\x30\ -\xae\xf2\xce\xa7\x55\x49\x5e\x95\x08\x27\x29\x9d\x37\x9e\x77\x75\ -\x8f\x8c\xf5\x11\x2e\x87\x1b\x8d\xda\x98\xcf\x5b\xee\x7a\x93\x01\ -\x15\x68\xa4\x90\x18\xf0\xf4\xc5\xfa\x66\xf5\x36\xe5\x8e\x20\xd0\ -\x54\xc2\x03\x4e\x46\x08\x94\xf0\xa5\xac\x51\x3e\xc2\xc6\x58\x1f\ -\xc7\x2b\x66\x92\xc3\x43\x6a\xb0\xfb\x4b\x3c\xe7\xc3\x1b\xc4\xd6\ -\x56\xb7\xd6\x09\x0e\x06\x43\x2f\xb5\x1c\x8d\x31\x91\x37\xd4\x8b\ -\x1b\x09\x4e\x7b\x55\x5e\x69\xcd\xcc\x9f\x3a\x0b\xfc\x66\x2e\xab\ -\x0a\xe7\xac\x67\x9f\xa5\x1e\x0c\x0d\x95\xb7\x3b\x0a\x94\x27\xc9\ -\x58\x6b\x31\xb5\x87\x9c\xcd\x52\x7f\x08\x84\x21\xbd\xc5\x15\x5c\ -\x51\x31\x78\xb0\xc9\xbd\x3b\x77\xd1\x8d\x90\x50\x05\x94\xa6\x22\ -\x68\x86\xe4\x55\x4e\x61\x0a\x08\x1c\xc5\x64\x1f\x33\x39\x60\xed\ -\xc8\x22\x3f\xfd\x63\x2f\x71\x6a\x39\xa4\x65\x61\xf3\xf6\x03\x16\ -\x97\x17\x48\x9a\x31\xc3\xd1\x84\xed\xdd\x2d\xee\xde\xbd\xcf\x4f\ -\xff\xf4\x4f\xf3\xd6\x5b\xdf\xa7\xd3\x9d\x23\xcf\x7d\x99\xbf\xb5\ -\x35\xe4\xcd\x37\xff\x82\xaf\xfd\xc4\x1b\x38\xe3\xb8\x7d\xf3\x26\ -\x9b\x77\xef\xf2\xc2\x93\xe7\xd9\x79\x70\x9f\xe7\xce\x9d\xf5\xe7\ -\x61\xbd\x9f\xb4\x94\xff\xa1\x76\x98\x47\x5c\xab\x1f\xed\x91\x7f\ -\xf3\x0b\xf7\xef\x5f\x41\xb9\x9e\x5d\xe7\x62\x06\x88\x3d\xfa\x47\ -\x52\x68\xa9\xa9\x8c\x23\x89\x83\xdf\x6e\xb7\x92\x7f\x1e\x35\x9a\ -\xc9\x9f\x7f\xef\x7b\x84\x71\x42\x7f\x30\x64\x69\x75\x8d\x51\x5e\ -\xe1\x94\xcf\x1a\x92\xa1\x77\x7d\x2c\xca\x02\x91\x24\xb5\x68\xbc\ -\x2e\xcb\x84\x57\x6b\xdc\xbe\x73\x87\xc9\xa4\xa2\x39\xbf\xc6\xc2\ -\xa2\xa2\x11\x09\xc2\xb8\xc7\xe6\xe6\x16\xef\xbd\xff\x1e\x67\x4f\ -\x9f\xf5\x76\x44\x0e\xe6\x17\x7a\x2c\xf5\x9a\xec\x0f\x33\xf6\xfb\ -\x43\x5a\xad\x16\xc6\x18\x7a\xbd\x25\xaa\xca\xd0\xe9\x74\x00\xb8\ -\x7d\xfb\x36\x37\x6f\xde\x26\x8e\xbd\x29\xdf\xcb\xcf\x9c\x46\xc7\ -\x4d\xe2\xc8\xcf\xd0\xbd\xec\xd5\x32\x99\x16\x54\x95\x21\x8e\x35\ -\x5b\x5b\xbb\x9c\x3b\x77\x92\x5e\x3b\x22\x8c\x34\x93\x49\x4e\x56\ -\xf8\x3e\xb0\xd5\x6c\x32\xd7\xee\x12\x05\x31\xdd\xb9\x1e\x07\xa3\ -\x03\x7e\xf0\xd1\x07\x5c\xbd\x7e\x8d\xfd\xc1\x3e\xc6\xf8\xf1\x5a\ -\xbb\xd5\xa6\x40\x79\x3f\xf0\x28\x66\xff\xe0\x80\x38\x49\x10\x4a\ -\x11\x26\x0d\xb4\x0a\x50\xce\xc3\x3d\xaa\x36\x8b\xb3\x45\x81\x15\ -\x82\x74\xea\x8d\x01\xcb\xdc\x8f\xa7\x6c\xe5\x6f\x65\x6b\xac\x07\ -\xb2\x8c\x23\x8a\xe3\x99\x77\xb4\x52\x0a\x21\xbd\x08\x41\x2b\xed\ -\xe3\x4a\x8b\x12\x21\xa5\xe7\x36\x1f\xfa\x71\xd5\x2e\x27\xd4\x36\ -\x49\x58\x8b\xc2\xdb\xe2\xe8\xba\x4f\x77\xce\xe3\x1a\x95\xad\xfd\ -\xa5\x8d\x45\x58\xb0\x65\x85\x4b\x33\x54\x10\xd0\x68\x36\xbd\xd9\ -\x5f\xad\x29\x96\x87\xda\xe7\x7a\x05\x55\xa3\x11\x36\xd0\xb3\x2a\ -\xcc\x1c\x32\xb0\xaa\xd2\x8f\xb0\xa4\x37\x46\xa8\xac\xa1\x31\xd7\ -\x23\x8a\x63\xa2\x38\xf6\xb1\xb1\xd6\x3e\xd4\xf1\xd4\x96\x3d\x38\ -\x87\xa8\x11\x5d\x1c\x9e\x0e\x7a\x58\x09\xd4\x07\x45\x31\x1a\x61\ -\xb4\xf2\x63\x36\x80\xd0\xf3\xb3\x0f\xfd\xb2\xb3\x69\x8a\x2b\x0a\ -\xba\xbd\x1e\x52\x09\x94\xd6\x48\xe9\x81\xa6\xb2\x2a\x98\x8c\x86\ -\xb8\x2a\xa7\xa1\x1d\x89\x4b\x79\xfd\x4b\x4f\xf2\x93\x17\x9e\x21\ -\xb6\x50\x8d\xa7\x98\x22\x27\xd2\x1a\xa9\x25\x45\x55\x70\xf5\xb3\ -\x6b\x3c\xf3\xcc\x73\x54\xd6\xb1\xb5\xb5\xcb\xc9\x93\xc7\x98\x4c\ -\x52\x86\xc3\x21\xdb\x5b\xdb\x1c\xdb\xd8\x60\x75\x71\x91\xcd\x3b\ -\xb7\xd9\xdd\xda\xe2\xcc\xc9\x13\x5c\xfe\xe1\x25\xbe\xfa\xc6\x57\ -\x7e\xaa\x11\xe9\x1b\xae\xd6\x44\x0b\xfc\xef\xe2\x9c\xf9\x82\x1b\ -\x08\xfc\x35\x62\x08\x1e\x71\x08\x39\x44\xa8\xe5\xa3\xfc\xaf\x2f\ -\x18\xfe\x7c\x71\x63\xbb\x47\x04\x53\xe9\x38\xa5\xd1\x4c\x08\x04\ -\x4c\x4c\x45\xa0\xd4\xd7\x7f\xfe\x27\x5e\xff\xe6\xbb\x1f\x7d\xc4\ -\xff\xf5\xc7\xdf\xe5\xdc\x73\xaf\x92\x55\x39\x14\x53\x82\x56\x0b\ -\x5a\xbe\x17\x29\xb2\xca\x93\xf5\xd3\x09\x8d\xb9\x39\x22\xa5\xc8\ -\xc7\x63\x06\xd3\x9c\x50\x58\xd2\x5b\xb7\xf8\x2e\xb0\xbd\xbb\xc7\ -\x2f\xff\xcd\x9f\x65\xad\x1b\xb0\xd0\x81\xd7\x5e\x38\xc7\xfe\x60\ -\xc0\xe5\xcf\xae\x21\xaa\x8a\x33\xa7\x4f\xa1\x84\xd7\x1d\x37\x1a\ -\x31\x71\x14\xf3\xf1\xc7\x9f\x12\x04\x41\x6d\xff\x93\x30\x1e\x67\ -\x9c\x3e\x7d\x84\xf3\xe7\x8e\xb0\x3f\x72\x7c\xfa\xe9\xa7\x7c\xe3\ -\x1b\xdf\xa0\xd5\x6a\x30\x3f\x3f\xcf\x40\xc0\xdc\x5c\x87\xa5\xb9\ -\x98\xcc\xdb\x2d\x93\x65\x19\xb7\x6e\xdd\xa7\xdb\xed\x32\x1a\x65\ -\x6c\xa7\xe9\x4c\x1c\x10\x04\x92\xa2\x30\x9e\x29\x15\x84\xe4\xce\ -\x30\x37\x37\xcf\xfa\xe2\x31\x1e\x7b\xee\x71\xb4\x86\xd1\x24\x65\ -\xa7\xbf\xc7\xd5\x8f\x2f\xa2\xa3\x16\xa3\xc2\xb2\x77\xfb\x26\x67\ -\x56\x56\x79\xf7\xed\x77\x68\xad\xae\x33\xce\x0b\xd2\xcc\x60\x51\ -\x50\x59\x02\xe9\x0f\x45\x9b\x97\x04\x51\x52\x8f\xfb\x02\x9c\xaa\ -\xcb\xd1\xda\x50\xe0\x30\xab\xd8\xe7\xb5\x79\x59\xa3\x14\xc2\x4b\ -\x1c\x8d\xf5\xa7\xbb\x75\x48\xe1\xff\xed\xa9\x7e\x7e\xac\x52\xaf\ -\x76\x84\xf4\x5e\x5e\xa6\x2c\xd1\x3e\x14\x15\xa5\x15\xb9\xf6\x6e\ -\x1f\x48\x41\xe9\x2c\x52\xfa\xdb\x4d\x09\x85\x91\xf8\x1c\x64\x69\ -\x31\x52\x11\x48\xef\x8f\x75\x58\xba\x1e\x56\x02\xd6\xda\x3a\xa0\ -\xcd\x3b\xcb\xd8\xda\x93\x8c\x99\xc1\x80\x2f\x85\x71\x10\x36\x1a\ -\x48\xeb\x20\xf3\xbf\xa7\x15\x0e\xe7\xbc\xba\xaa\x28\x4b\xc2\xc4\ -\xa7\x51\x88\x43\xe8\xd6\x41\x24\x35\x46\x7a\x66\x5a\xb7\xdb\xa5\ -\x28\x0a\xaf\x8f\x9e\xa6\xf5\xa2\x4c\x71\xad\x26\x2a\xf2\xc9\x1a\ -\xba\xf6\xbb\x2e\xc8\x1f\x56\x07\xf5\xeb\x28\x91\xe4\x45\x89\x13\ -\x8a\xe9\x78\x88\x4e\x12\x4c\xff\x00\x5c\x49\xa8\x14\x3f\xf6\xfc\ -\x33\xfc\xd4\xcb\x17\xe8\x4a\x68\x2a\x30\x5a\x10\x74\x5a\x5c\xbd\ -\x7e\x83\xc6\xa8\x41\x33\x89\x78\xe3\x27\xde\xc0\x39\x18\x8e\x33\ -\x46\xd3\x09\x85\x81\xcf\x6f\xdd\xa1\xdd\x6c\x72\xfa\xf4\x69\x3e\ -\xbd\x74\x89\xa2\xcc\x18\x1c\xec\x13\x28\xc1\xe7\xd7\x2e\xf3\xd3\ -\x5f\xfd\x2a\xdd\x46\xf4\x2d\x8c\xbf\x14\x24\xfe\x30\x3a\x14\xae\ -\x38\x21\x50\xea\xd1\x5d\xf7\xd7\xd7\xcd\x5a\xd6\xb2\x65\xf9\x1f\ -\xfc\xe4\xc3\x26\xdb\x7a\x94\x44\xf8\x24\xbd\x46\x33\xa4\xc8\x2c\ -\x61\x22\x71\x45\x41\x33\x69\x7c\x6b\x52\x4c\xf9\xe7\xbf\xf6\x8f\ -\xf8\xe4\xc6\xe7\xdc\xda\xb9\xcf\x48\x34\x09\x9a\x73\x98\xb2\x40\ -\x45\x09\xb2\x8e\xfe\x70\x45\x06\xe9\x84\x60\x71\x0e\x29\x41\x06\ -\x1a\x11\x6a\x3a\xdd\x0e\xe9\x70\x48\x26\x34\x37\x1e\x6c\xf3\x7f\ -\xfe\xde\xef\xf3\x8f\xff\xc1\x2f\x93\x01\xdf\xbf\xbe\x43\xa3\xdd\ -\xe1\x85\xe7\x1f\x23\x1f\xa6\x7c\x7e\xfd\x3a\xa1\x96\x14\x45\x41\ -\x92\x24\xcc\xf5\xe6\xd8\xdb\xdb\xe3\x95\x57\x5e\x21\x08\x34\x45\ -\xe1\xf5\xbe\x79\x0e\xdb\x83\x01\xad\x56\x87\xe7\x9f\x3f\x4f\xbf\ -\xdf\x27\x49\x12\xee\xdf\xbf\x4f\x55\x95\x0c\x87\x73\xb4\x5a\x2d\ -\xc2\x30\x64\x69\xa1\x41\x1c\xc7\x6c\x6e\x7a\x3f\xaf\xa4\x9e\x83\ -\x36\x9b\xa1\x27\x18\x15\x35\x21\x24\x56\xde\x36\x47\x4b\x64\x1c\ -\x32\xc9\x3d\xa7\x38\x08\x14\x51\xa0\x39\xba\xb6\xc6\xea\xe2\x12\ -\x61\x14\x71\x30\x31\x08\x14\xab\xe7\x1e\xa7\xd9\x68\xf3\xe6\x47\ -\x17\xb9\xfb\xc9\x15\x6c\x90\x83\xf2\x86\xf0\x46\x05\x94\xca\x62\ -\xa7\x29\x71\xaf\x87\x74\x02\xa5\xeb\x05\x8e\xa3\x34\xe6\xe1\xa1\ -\xeb\x3c\x52\x6a\x2d\x28\xeb\x6b\x2d\x69\xfd\x48\xc5\xe2\x70\xf5\ -\x46\x46\x48\xa4\xa8\xe7\xca\x48\xac\x73\xfe\xc6\x76\x5e\x69\x14\ -\xa8\x80\x50\x69\xac\x33\x28\x7f\x5a\x60\xcb\xca\x97\xf2\xa6\x42\ -\x3b\xe7\x6f\x52\xa5\xc0\x5a\x24\xd2\x07\x8c\x17\x25\x65\x5e\xd4\ -\x5e\xd7\x8f\xc0\xa7\x3f\x5a\x5a\x47\x11\x3a\x8a\xd0\x5a\x53\x58\ -\x5d\xf3\xc3\x0f\xdd\x4e\x84\xb7\xd2\xc1\x82\xad\x48\xab\xc2\x6b\ -\x96\xb5\x22\x8c\x22\x54\xe4\x13\x23\x6d\x59\xa1\x85\xa4\x92\x3e\ -\x4a\x27\x44\x62\xa5\x26\xcf\x73\x86\xfb\x07\x98\xda\x3d\x04\x63\ -\x10\x4a\xcf\x88\x27\x52\x6b\x1f\xf8\x5e\x1b\x09\x08\x21\x68\xb7\ -\xdb\x98\x20\xa2\x3f\x9e\x32\x1e\x8c\x88\x9b\x09\x69\x9e\x79\x1d\ -\x72\x9e\xa3\xe6\xda\x54\x71\x00\xe3\x11\xcb\xf3\x6b\x7c\xf9\xa5\ -\xe7\x79\xea\xc4\x1a\x89\xa9\x88\x8c\x63\x98\x4e\xd8\xdc\xdc\x61\ -\x7f\x34\x60\x65\x63\x8d\x4e\xa3\x41\x5e\x7a\x36\xdb\x74\x9a\x71\ -\xea\xf4\x19\xde\x7c\xeb\x2d\x9e\x79\xea\x59\x44\xad\xae\x8b\xa3\ -\x88\x6b\x57\xae\xf2\xd8\xc9\x13\x7c\xf4\xfe\x3b\x3c\xf3\xe4\x93\ -\x34\x42\xf5\xbb\xd6\x54\x28\xe7\x2b\x92\x99\x29\x57\x1d\x15\xe1\ -\x49\x20\x8a\xff\xbf\x6f\xea\x37\x7f\xeb\xbf\xab\x17\x87\x78\x94\ -\xc8\xf9\x23\x5a\xce\x47\xaf\xe5\x5a\xd0\x8e\x2f\x81\x05\x12\x29\ -\x05\xfb\xfd\x7d\x7a\xdd\x16\x65\x95\x82\x96\x0f\x5a\x51\xb2\xbe\ -\x70\xec\xd8\xfa\x9f\xbe\xfd\x2e\x83\xb4\x64\x69\xfd\x28\xa3\x83\ -\x31\x56\x2a\xe2\x46\x13\x1d\xfa\x71\x01\xb6\x44\x45\x21\x93\xc9\ -\x98\x30\x0a\x28\x8a\x0a\xfd\xff\xb1\xf7\xa6\x41\x76\xa5\xe7\x7d\ -\xdf\xef\x3d\xfb\x39\x77\x5f\x7a\xef\x46\x63\xc7\x00\x18\x60\xf6\ -\x19\xcd\x88\xdb\x90\x1c\x49\x94\x44\x52\x22\x45\x2b\xa1\x15\xd9\ -\x8a\x62\xb9\x54\x96\x93\x52\xf2\xc5\xae\x7c\x91\xaa\x52\x71\x9c\ -\x54\xec\x2f\x4e\x25\xa2\x1d\x51\x49\x6c\x4b\xa6\x62\xc7\xb4\x2c\ -\x52\x12\x25\x52\x5c\x87\x9c\x1d\xb3\x00\x03\x0c\x96\x06\xba\xd1\ -\xfb\x72\xab\x95\x75\x81\x00\x00\x20\x00\x49\x44\x41\x54\xd7\xb3\ -\xbe\xe7\x3d\xf9\xf0\x9e\xbe\x83\xa1\x48\x29\x8e\x64\x93\x2e\xfb\ -\x56\x01\x33\x85\xee\xae\xea\xba\xf7\x3c\xef\xf2\x3c\xff\xff\xef\ -\x6f\x5b\xc4\xfd\x21\xb9\x21\xd8\xd9\xd8\xc4\x72\x6c\x3e\xff\xb9\ -\x3f\xc0\xb6\x02\x3e\xf8\xd8\x49\x56\xd6\x77\x30\x31\x31\x0d\x38\ -\x7b\xea\x08\x52\x16\x9a\x9c\x91\xa6\x54\x2a\x35\x56\x57\x57\x39\ -\x7d\xfa\x18\x71\xac\x29\x1e\x20\xb0\x2c\x41\xb7\xe9\x31\x8e\x72\ -\x92\x24\xe7\xf6\xed\xdb\x3c\xf8\xe0\xfd\x74\xbb\x5d\x5c\xd7\xa5\ -\xd7\xeb\xb1\xb9\xb9\xc9\x70\x38\x24\x93\x90\x24\xfa\xc3\x4f\xd3\ -\x94\x66\xb3\x55\xc6\x78\x5a\x13\xd6\x93\x94\x92\x5c\x19\x98\x96\ -\xe0\xd6\xea\x26\x5e\x3d\xc0\xa9\xb8\x54\xeb\x01\xb6\x63\x93\x44\ -\x63\xe2\xf1\x08\xb2\x9c\x42\x82\x90\x8a\x83\xfd\x3e\x47\x8f\x76\ -\x39\x7f\x74\x0a\x65\xd6\xb9\x71\xfb\x0e\x46\xb5\x8e\x08\x2a\x1a\ -\x7c\x60\x08\x8a\x34\x23\xdf\xdd\x21\xb7\x2c\x92\x70\x4c\xb2\xb9\ -\x49\x32\xe8\x93\x8e\x86\xe4\xe3\x31\x32\x4d\x34\x43\x3a\xcb\x28\ -\xb2\x0c\x13\xf0\x1c\x07\xc3\xd4\x98\x5b\xd3\x10\xfa\x88\x56\x14\ -\xd8\xa6\xa9\x09\x92\x51\x84\x50\x0a\xcb\x10\xda\xe7\x2b\xa5\x0e\ -\x02\x97\x12\xa1\x34\xfe\x56\x26\x09\x45\x96\x91\x0d\x06\x60\x08\ -\x5d\xbc\x59\x8a\x4c\x13\x88\x42\x8a\x2c\xa5\x88\x63\xf2\x34\x43\ -\x45\x11\x0c\x87\xe4\x42\xe0\xd4\xeb\xe0\x3a\xba\x58\x5d\x17\xdb\ -\x71\xb1\x3d\x0f\xc7\xf5\xb0\x5c\x17\x79\xc8\xd5\x2a\xc7\x42\xb6\ -\x6d\x6b\xde\xb4\x61\x60\x5a\x26\xb6\xa3\x9b\x57\x59\x96\x22\x02\ -\x0f\x54\xae\xb1\x47\x85\x6e\xe6\xd9\x96\x7e\x4e\x5c\xcb\x26\x4f\ -\x32\x8a\x50\x9b\x63\x8a\x2c\x27\x4d\x12\xf2\x38\xd2\x10\x7d\xd3\ -\xc2\x71\x5c\x7c\xdf\xd7\x3b\x79\x10\xe8\xe7\xd4\x10\x78\xbe\x87\ -\x6d\xdb\x24\xe3\x31\xe1\x68\x4c\x34\x1c\x81\x2a\x98\x99\x9e\xd1\ -\xb9\xcc\xc2\xd0\xeb\x8e\x6f\x53\x58\x06\xb6\x6f\x91\xc7\x23\x3e\ -\xf2\x81\xf7\xf0\xae\x0b\x67\xa9\x53\xe0\xcb\x8c\xed\xbb\x77\x48\ -\x93\x84\x5b\x6b\xab\x4c\x2d\x1d\x61\xe9\xf8\x11\xda\x81\xcb\xd6\ -\xf6\x1e\x96\xe5\x70\xed\xad\xeb\x5c\xbf\x7e\x9d\x1f\xfc\xc1\x77\ -\x53\xad\xf8\x2c\xb4\x1c\x2e\x5f\xb9\x41\x1a\x87\x3c\x7c\xe1\x3c\ -\x69\x38\xc2\x35\xe0\x07\x1f\x7f\x54\x54\x7d\xf7\xb7\x07\xfd\x1e\ -\x81\xe7\x95\xfd\x0b\x0d\x83\x38\x8c\x0c\x32\xc4\x24\x85\xed\x3b\ -\xb6\xa1\xbf\xfd\x7f\xad\xef\x2c\xe4\xfc\xd3\xae\xdb\x46\xb9\x6a\ -\x68\x84\x4c\x18\xa5\x04\x81\x43\xbb\xd3\x22\x8a\x87\x9a\x48\x59\ -\xa8\x4f\x1d\xc8\xf8\xd7\xde\x75\xff\x7d\xfc\x95\x8f\x7d\x94\x7f\ -\xf2\xbb\x7f\x84\x50\x29\xa4\x23\xfc\x56\x1d\x55\xa4\xc8\x42\x60\ -\x55\x7c\xe4\xde\x0e\xa1\x1f\x01\x05\x8d\x46\x8b\x24\x93\x44\x99\ -\x04\xdf\xa7\xda\x9d\x62\x2c\x60\xbd\xd7\xa3\x1b\x54\xf8\xec\x17\ -\xbe\xc8\x0b\x2f\xbc\xc0\x62\xb7\xc5\x89\x33\x67\x68\xd4\x0d\xf6\ -\x46\x19\xad\xce\x14\x53\x33\x33\x5c\xbf\x7e\x93\xd7\x5e\x7b\x8d\ -\xdb\xb7\x6f\x33\xe8\x3f\x82\x69\x9a\x64\x49\x86\x17\xd8\x0c\x06\ -\x21\x10\xb0\xbd\xbb\xcb\x89\x13\xb3\xf8\xb5\x3a\xa3\x50\xeb\xb4\ -\x5b\xad\x26\x9e\xe7\x4d\xee\x25\xab\xab\xab\xdc\xb8\x71\x83\x6a\ -\xb5\x3a\xb9\xa7\x68\xac\x8f\xf6\xea\x7a\x9e\x8d\x69\xba\x08\x01\ -\x1b\x7b\x03\xc2\x3c\xa6\x5a\xaf\xe0\x78\x16\x49\x9c\x12\x85\x23\ -\x3c\xc3\x64\xa6\x3b\x45\x16\x49\xa2\x28\xa1\xdd\xac\xb0\xb5\xba\ -\xca\xe9\x0b\x67\xd8\x4b\xe1\xfd\x8f\x1c\xe1\xb9\x57\x96\xf9\xd6\ -\x8d\x35\x6c\xab\xc0\x36\xf5\x9c\x58\x79\x1e\x89\x1b\xd0\x68\xb5\ -\xc9\x72\x85\x39\x33\xa7\x1d\x3a\x85\x2a\x59\xce\x8a\x42\xe5\xa8\ -\x2c\xd3\xb4\xc7\x7e\x9f\x7e\x5a\x92\x41\x54\xae\x85\x1e\xe5\x56\ -\x1d\x9b\xb6\x6e\x7a\x8d\x42\xa4\x61\x32\xcc\xd5\xdb\x17\xa6\x43\ -\x41\x88\xca\x88\x2d\x0b\x52\x09\xc2\x82\x38\x23\x0f\xc0\xb0\x35\ -\x64\xde\xaf\x54\x48\xf3\xb4\x04\x22\x6a\x8c\x6d\x2e\x25\x91\x30\ -\x09\x1a\x35\x0d\x8f\x30\xee\x41\xf1\x7e\x3b\x57\x4a\x4a\x64\xaa\ -\x8f\xd6\x52\xe9\x93\x0c\x66\x19\x82\x6e\xea\xdd\xdd\x28\x05\x1a\ -\x96\x61\x22\xcd\x02\xd3\xd0\x63\x17\x13\xad\xf0\x2a\x64\x4e\x61\ -\xeb\x9d\x95\x68\x4c\x24\xd0\xf4\x93\x2c\xa5\xb1\xb8\x40\x8e\xce\ -\x66\xce\x33\x39\xe9\xe7\x18\x86\x6e\xc6\x65\x52\x6b\x06\x84\xd0\ -\x90\xc0\x56\xad\x8e\x8c\x12\xfa\xb7\x57\xd9\x58\x59\x01\xc7\xa2\ -\xde\xed\x90\x2b\x89\x53\xf1\x88\x07\x3d\xea\xad\x1a\xd2\xf3\x78\ -\xfa\x89\xc7\x59\xae\xc1\xc1\xc6\x36\xb6\x63\x71\x67\x75\x85\xe3\ -\xa7\xcf\x10\x54\x03\xce\x9c\x38\xce\x70\x10\xa2\x6c\x87\xf6\x74\ -\x87\xbd\xed\x1e\x71\x1c\xf3\xe8\x23\x8f\xe0\x3a\x16\xe1\x68\xcc\ -\x9e\xf2\x59\xbf\x7b\x87\x67\x9e\x7e\x0f\xbe\xe7\xf2\xa5\x6f\x3d\ -\xcb\x2f\xfc\xec\x5f\x16\x02\x38\xd8\xdb\xa3\xdd\xee\x50\x48\x4d\ -\x3b\x2d\x0a\x49\x96\xe7\x58\xf6\x61\xb3\xeb\xde\x3a\xfb\x0e\xc7\ -\x6b\xf1\xce\xcb\xaf\x65\x4c\xb6\x6f\xe3\xbb\x74\xba\xbe\xd3\x21\ -\xdb\x9c\xfc\x88\x1f\x38\xda\x21\x59\xe4\x38\xae\xab\xd5\x4a\x42\ -\xd0\xb0\x2c\x91\xc0\x67\x3e\xf9\xc1\xf7\x7e\xe2\xf9\xaf\x7d\x83\ -\x3b\xbd\x0d\xe6\x2b\x3e\xeb\x7b\xeb\xf8\xf3\xf3\xc8\x1c\x8d\x50\ -\xa9\xb5\xe0\x20\xc4\x9e\xea\xb2\xb1\xb9\x43\x61\x08\x82\xc0\x27\ -\x91\x19\xfb\xc3\x7d\xec\x8a\x47\xd5\xab\xb3\xba\x75\x97\xf9\x76\ -\x8b\x95\xfe\x90\x2b\xab\xab\x3c\xf5\x23\x3f\x46\xbd\x5e\x61\x10\ -\xa6\x2c\x75\x2a\x38\x26\x74\xa7\xa6\x39\x79\xec\x38\x77\xd7\xd6\ -\x58\xbb\xbd\x52\x66\x37\x2d\xe0\xba\x4d\x5a\xad\x80\x54\x42\xa3\ -\xd9\x65\x6f\x08\xb9\x61\xa3\x2c\x6d\x22\x10\xa5\x33\x48\x17\x6b\ -\xce\xe2\xc2\x02\x73\xb3\xb3\x6c\x6c\x6c\x70\xf3\xe6\x4d\xd2\xd2\ -\xa6\x37\x33\x33\xa3\x93\x1f\x23\x8d\x88\xb5\x7d\x87\xf6\x4c\x1d\ -\x79\x33\x25\x47\x91\x8c\x23\x2c\xc3\xa4\xe6\x54\x08\x2c\x97\x71\ -\x2f\x25\xcb\x32\x2a\xf5\x0a\x51\x02\x5e\xc5\x03\x05\xdd\x3a\x84\ -\x12\xe6\xab\x2e\x6e\x3c\xc6\xaf\x68\xd5\xd1\x28\x4e\xa8\x34\xda\ -\xf4\xea\x35\xac\xa0\x4e\xbf\xd7\xc7\x90\xa2\x1c\xd9\x49\xb2\x54\ -\x62\x0b\x87\x46\xe0\x23\x5c\xc9\x60\x34\x24\x2e\x0a\xaa\xd3\x53\ -\x9a\x90\x51\xe8\xfc\x24\xa5\xc0\x72\x6c\x64\xa6\x48\xa3\x08\xaa\ -\x4d\x7d\xb7\x2e\x47\x5d\xb6\x6d\xa3\x94\x24\x92\x31\x45\xa0\xef\ -\xdb\xbe\x19\xa0\x12\x45\x52\xb8\x34\xda\x73\x64\x49\x4a\x18\x86\ -\x90\x5b\x14\x32\xc3\xaf\x04\x58\xb6\x20\x89\x62\xc2\x34\xa4\x10\ -\x85\x8e\x96\x31\x74\x20\xdb\xe4\x9e\x7e\x98\x82\x90\x97\x45\x5b\ -\xe6\x66\xb9\xae\x4b\x9e\xc4\x65\x81\xe9\x69\x80\x6f\xd9\x64\x42\ -\xe2\x1a\x26\xa1\xed\x90\x0d\x86\x54\xeb\x0d\x94\x80\x38\x4a\xb1\ -\x5c\x97\xf1\xfe\x01\x14\x05\xa3\x2c\x2d\x17\x20\xf0\xda\x35\x8a\ -\x22\xc7\xb0\xea\xf4\xc7\x03\x84\x30\x71\x4d\x6b\xc2\x29\xa3\x04\ -\xfc\x17\x32\xd7\xbf\x53\xc9\xec\x4a\xe2\xb4\xe4\x7b\xc5\x40\x41\ -\x65\xaa\x8b\xe9\x1b\x8c\xe3\x21\x38\x0e\x85\x92\xb4\xeb\x0d\x44\ -\x7f\xc8\xa9\xe6\x0c\x27\x6a\xb0\x72\x73\x07\x23\xe9\x33\x28\x22\ -\x2e\xfe\xc0\x63\x74\x83\x26\xaf\x5d\xbb\x4e\xb8\x7f\x40\xab\xd1\ -\xe1\x20\x8e\xc9\x94\xe0\xca\xf5\xeb\xb8\xb6\x26\xbd\x14\x59\x44\ -\xb3\xe6\xf1\xcf\xff\xef\xdf\xe2\x83\xef\x7b\x2f\x32\x0b\xf9\xd2\ -\xb3\x5f\xe1\x99\x67\xde\xaf\xe1\x96\x52\xd1\x6e\x76\x41\xea\x66\ -\x22\xa2\x40\x08\x6b\xe2\x76\x7a\x67\xe9\x19\xdf\xfd\x84\x7c\xcf\ -\x77\x99\xbf\xf2\x2b\xbf\xfa\x67\xeb\xbf\xfe\xcc\xc1\x94\x9a\x1c\ -\xb7\x8b\x89\x87\x0a\x0c\x21\x7e\xdb\x36\x8d\xff\x6a\x7a\x7a\xc6\ -\xff\xd7\x9f\xfb\x3c\x92\x82\x54\x08\x92\x34\xa5\x32\x3b\x43\x36\ -\x0e\xf1\xbc\x1a\x52\xe6\x98\x96\x45\x5e\xe4\xba\x1b\x69\x19\xe4\ -\x59\x02\x14\xb8\x55\x9f\x30\x8e\x71\x3d\x97\xde\x60\x88\xe5\xfa\ -\x0c\xc2\x98\xdb\x1b\x9b\xcc\xcc\x9f\xe4\xc2\x42\x95\xd5\x8d\x03\ -\xaa\x75\x1f\x43\x38\x1a\xa0\x88\xe0\xd8\xf2\x32\xae\xeb\x72\xeb\ -\xd6\x4d\xfa\xbd\x3e\x51\x92\x13\x54\xaa\xd8\x8e\x46\xf3\xac\x6f\ -\x6c\x72\x74\x79\x16\xcb\xd0\x40\xba\x3c\xcf\x71\x1c\xed\x39\xd6\ -\xac\x63\x87\x38\xd6\x41\xe7\x27\x4e\x9c\x20\x08\x02\x76\x77\x77\ -\xb9\x7e\xfd\x3a\xb7\x6f\xdf\xd6\x1e\x57\xc3\x44\x19\xb0\xba\xb6\ -\xca\xe2\xe2\x02\xb6\x61\x62\x63\x20\xf2\x02\xd3\xb0\x50\x52\x87\ -\xae\xc5\x59\x8e\x2c\x0c\xb6\xf7\xf7\x98\x5b\x98\x63\x30\x18\x53\ -\xaf\x3a\x04\xf5\x16\x51\x2a\xe9\x0d\xfa\x1c\xf4\x7a\xba\x7b\xea\ -\x58\x8c\x6e\x5c\x27\xa9\xd7\x68\xcf\xcd\x31\x8a\x23\x4c\xc7\x45\ -\x98\x16\x9e\xe7\x6a\xc4\x4e\x26\x09\xe3\x44\xef\xd4\x32\x81\x8a\ -\x47\x96\x17\x48\x51\x50\x08\x53\x43\x02\x84\x45\x5e\x14\x78\xd5\ -\x2a\x4a\x08\x1d\x25\xe3\x3a\x08\x43\x0b\x39\x0a\x55\x60\x38\x02\ -\x59\x24\x90\x26\x28\x2c\x90\x02\x35\x8c\x31\x2b\x35\x1c\x37\xa0\ -\xd6\xa8\x63\xd8\x06\x51\x1a\x93\xaa\x94\x30\x0e\x91\xb9\xe4\x30\ -\x68\xc8\x76\xb5\x21\x5f\x58\x3a\x1a\xc6\xb4\xac\x09\xbe\xd7\x2c\ -\xf9\xd8\x59\x18\x52\x18\x06\x8e\xeb\x68\x1b\x66\xf9\xb5\x54\x66\ -\x58\xa6\x51\xc6\x21\x14\x24\xe3\x10\xc2\x88\xb4\xd4\x3c\x17\x71\ -\x8c\x54\x4a\x47\xd6\x98\x26\x86\x63\x6b\x5d\x75\x96\x62\x54\x03\ -\x72\x24\x85\x69\x50\xad\x35\x26\xd1\x30\x79\x26\xc9\x65\x8e\x1c\ -\xea\xc2\xd4\x37\xce\x02\x99\x49\x7d\x45\x08\x43\xbd\x7f\x29\xad\ -\x89\x68\xb4\x5b\xf4\xc7\x07\xd4\x9a\x35\x84\xa9\x67\xd9\xd1\xce\ -\x2e\x8f\x9e\x3c\xcd\x91\x4a\x85\x33\x73\xc7\x48\x0e\x76\xe8\x36\ -\x2a\x2c\x1f\x5f\xa2\x37\xea\xb3\xb6\xbb\x4d\x12\xa5\x2c\xcf\x2f\ -\xd3\xeb\x0d\xd9\x8f\x63\xae\xdd\x5a\xe1\x5d\x4f\x3e\xc8\x78\x10\ -\xb2\xbc\x38\x4f\xd5\x73\x78\xe3\xb5\x4b\x14\x32\xa5\x51\xab\xf2\ -\xe6\xeb\xaf\x72\xf1\xfc\x79\x8e\x2c\xcc\x0b\xc7\x30\x31\x14\xc8\ -\x30\xd6\x6a\x3d\x74\x36\xf5\x3b\xe7\xc5\x7f\xca\x2e\xca\x77\x65\ -\x76\xfd\xc5\xbc\xf4\x38\x43\xaf\x1f\xfa\x9a\xae\x63\x32\x7d\x68\ -\x5f\xbc\xef\x4c\xf1\x91\x1f\xf9\x11\xfe\xd5\xd7\xbe\x49\x36\xec\ -\xe3\x04\x01\xe3\x9d\x6d\x88\x52\xcc\x9a\x0d\x46\x8e\x69\xe6\x08\ -\x43\x90\xca\x8c\x74\x3c\xd2\xad\x63\x4b\xe0\x38\x01\x32\x91\x54\ -\x6b\x2d\xe2\x48\x12\x2b\x8b\x04\x9b\x4b\x97\x2e\xf3\xbb\x9d\x2e\ -\xdd\x1f\xfd\x20\x27\x17\x5a\x6c\x1d\xa4\x58\x02\x6a\xbe\xc3\xf6\ -\xc1\x1e\xf3\x0b\xb3\x18\x26\x5c\x7c\xe0\x7e\xb6\xb6\xb6\xe8\xed\ -\xed\x68\xf7\x4e\xbd\x81\x13\x54\x30\x91\x64\x51\x86\xe3\xda\x98\ -\xa6\x3e\x3a\xa7\xa9\x9c\x40\xef\xed\x92\x7f\xbc\xb4\xb4\xc4\xfc\ -\x6c\x83\x30\x86\x4a\xa5\x42\xa5\x12\x50\x14\xda\xde\xb8\xba\xba\ -\xc6\x28\x8b\x79\xeb\xea\x75\x8e\x2e\x2e\x53\x0f\xaa\x04\xae\x87\ -\x2d\x0c\x3c\x17\x0c\xc7\xc6\x30\x20\x8e\x24\x86\x51\x60\x59\x06\ -\x42\x14\xe4\x59\x82\x43\x85\x93\x47\x3a\x3c\xf9\xd4\xc3\x38\xed\ -\x2a\x97\xae\xbc\xc5\x4e\x7f\x88\xe3\x03\xd3\x55\xdc\x40\xb0\xdb\ -\xdf\x02\xdb\x20\x26\x05\x95\x53\xa9\xd7\xc9\x64\x4c\x5e\x68\x4c\ -\xb1\x1d\xf8\x40\x8c\xe1\x39\x18\x52\x77\xa4\x0d\xd3\xd6\x41\x67\ -\xb6\x09\x39\x44\xc3\x03\x0d\xd5\xb3\x4d\xf0\x6a\x18\xa6\x45\x4a\ -\x4e\x26\x73\x3c\x61\xd2\x76\x7d\xd2\x42\xe0\x58\x16\x4a\x98\xf4\ -\x2c\x41\x2a\x13\x46\x49\x04\xe4\x58\x15\x87\xdc\x52\x58\x9e\x8d\ -\x89\xa9\x1f\xad\x2c\x47\x86\x19\xd1\x68\xa4\x63\x82\xca\xc5\x10\ -\xd0\x63\xb4\x72\x1c\xa4\x73\xa7\xde\x06\xe1\x4d\xe0\xea\xe5\xb1\ -\x5b\x4a\x89\x4c\x25\xa6\x28\xa3\x2c\x0b\x55\x42\xf2\x35\xdd\xc4\ -\xf5\x3c\xbd\x49\x14\x05\xa2\x7c\xef\xa4\xa1\x95\x54\x79\xc9\x89\ -\x1e\xf4\x7a\x60\x98\x78\x56\x99\x57\x65\x68\x80\xfe\x61\x8c\x8c\ -\x0c\xcb\x84\x09\xdb\x02\xd7\xc5\x0d\x02\x54\x92\x91\xa5\x1a\x67\ -\x1c\x78\x15\x0c\x25\x48\xc3\x98\x7a\x25\x20\x70\x3c\x1e\x3a\x7f\ -\x16\x63\x6b\x93\xa8\xdf\xe3\xd4\x91\x23\x14\x6a\x84\x69\x18\xcc\ -\xb7\xe7\xb9\x95\xae\xd1\xef\x8d\x98\x6e\xb8\x5c\xbd\xb1\x86\xaa\ -\x05\x5c\x7c\xf8\x7e\x3e\xff\x85\xaf\x61\xa4\x29\x4b\x73\x73\xbc\ -\xfc\xfc\x73\x74\x9b\x0d\xee\x3b\x71\x8a\xd5\x95\x15\xb2\x34\xe5\ -\xcc\xa9\xd3\xc2\x9d\x04\x7a\x28\x32\x95\x61\x0b\xff\xbb\xc2\xf4\ -\xfe\x4d\x5f\x7f\x41\x85\x7c\x58\xbe\x87\x51\x22\x3a\x10\xce\x44\ -\x33\x79\xf3\x28\xe2\x97\xfe\xf3\xbf\xc4\xed\xad\x5d\x06\x97\xaf\ -\x11\x87\x63\x4c\xa5\xb0\x2b\x35\xc2\xfe\x2e\xe4\x39\x96\xe1\xe1\ -\x78\x1e\xa3\x44\x91\x86\xb1\xfe\x50\x73\x93\x70\x1c\xe3\x79\x55\ -\x72\x65\xd0\x9a\x9a\xa3\xbf\xbb\x0f\xa6\x43\x65\xf1\x18\x7f\xfc\ -\xdc\x8b\xdc\xbd\x76\x99\xbf\xfd\x4b\xbf\xc0\xd2\x5c\x83\xaa\xa1\ -\x9f\x2b\x1c\xdd\xe9\x3d\xd2\xe9\xd0\x0b\x13\x8e\x1f\x5d\x66\xd4\ -\x0d\xd9\xde\xd9\xe3\xe6\x8d\xeb\xba\xb9\xb5\xbd\x49\x3c\x3a\x06\ -\x99\x1e\x4d\x68\x33\x84\x8b\xe3\x54\x27\x26\xb0\x28\xf2\xb9\x7e\ -\xfd\x7a\x99\x01\x65\x4e\x24\x88\xbe\x0f\x33\x33\x6d\x6c\xc7\xa1\ -\x39\x55\x45\xc9\x1c\xcf\x71\xd9\xda\xda\x22\x09\x23\x44\x19\x03\ -\x62\x09\x83\x63\x27\x8e\x61\x79\xae\xbe\x7e\xc6\x31\x42\x15\x54\ -\x7c\xed\x2e\x1a\x0d\x63\x1e\x3a\x3e\xcd\xd9\xe3\xd3\x3c\xf9\xe4\ -\x23\x7c\xfe\x8b\x5f\xe1\xf5\xb7\x6e\xc2\x70\x0f\x93\x59\x5c\xcb\ -\x26\x13\xa0\x8a\x04\xe2\x88\xd8\xb3\x41\x48\x84\xe7\x81\x84\x4c\ -\xa5\x90\x67\xe4\x4a\x87\x97\x69\xec\xab\x0e\x4b\xcf\x45\x99\xa4\ -\x50\xaf\x90\xd8\x06\xc8\x14\x99\x44\x98\xb6\x89\x2d\x0a\xb0\x0a\ -\xac\x3c\x21\xdf\x1b\x63\xca\x1c\xc3\x2b\x50\x85\x0d\x2a\x23\x08\ -\x2c\xac\x02\xa2\x3c\xc3\xf2\x4d\x94\xed\x62\xb9\x26\x49\x14\x52\ -\x24\x29\x42\x19\x60\x1b\xf8\xbe\xd6\x8b\x17\x86\xbe\xcf\x16\x45\ -\x81\xc8\xd5\xa4\x90\xcd\x43\xbe\x74\xa6\x61\xf2\xb2\xd0\x59\xc5\ -\xa6\xa5\x09\x98\x52\x00\xb1\x4e\x6d\xc4\x30\xc0\xf7\xa9\xd5\x6a\ -\x25\x84\x40\xc3\xdb\x87\xc3\xfe\xb7\x99\x7e\xee\xc1\xdb\x14\x68\ -\xc4\xb0\x61\x62\x19\x26\x42\xea\x1e\x06\x71\x4c\x24\x84\x7e\x86\ -\x02\x4f\xeb\xd3\x1d\x1b\x13\x1d\x8d\x9b\x15\x82\xac\x6c\x64\x16\ -\x45\x8e\x65\xdb\x08\xa9\x48\x92\x31\x55\xdb\xa2\x48\x63\x1a\xbe\ -\xcb\x7d\x27\x3a\x64\xbd\x88\x5a\x35\x60\x77\x6b\x17\xbb\x1a\x90\ -\xc4\x92\x76\x77\x96\x7f\xf6\x2f\xff\x98\x8b\x8f\x3e\x41\x63\xd1\ -\xe7\xeb\x2f\x5f\xe3\x6b\xdf\x78\x96\x0f\xbd\xff\x7d\xec\xec\xec\ -\x70\xe6\xd4\x69\x46\x7b\x7b\x64\x49\xca\xc1\xf6\x2e\x4f\xbf\xef\ -\xdd\xd8\xe8\xf1\xa1\x23\x0c\xd2\x5c\x93\x4d\xfe\x22\x5f\xa5\x1f\ -\xf9\xcf\xb7\x13\x1f\xc6\x80\x8a\xc3\x19\x65\x39\xef\x13\x85\x81\ -\x2a\x0c\x2a\x9e\xfd\xab\x36\x9c\x17\x6e\xf5\xbc\x54\xf0\xea\x6b\ -\x97\x98\x6e\xb7\x99\x9e\xea\x32\x1c\x0f\xc8\x0b\x49\x41\x81\x57\ -\x52\x1e\x0a\x21\xc8\x0d\x13\xe2\x14\x95\x66\x18\x5e\xc0\x78\x14\ -\xe1\xf9\x55\xad\x81\x10\x06\x41\xbd\x45\xb8\xb7\x43\xab\x55\x67\ -\xe5\xce\x2d\x16\x8f\x9d\xc2\xf4\x1d\xc2\x48\xb2\x7c\x74\x91\xab\ -\x6f\x5e\x65\x18\xc7\xd4\xaa\x15\x54\x26\x49\xd3\x84\x20\xf0\x98\ -\x99\xea\x32\xdd\x6d\xb3\x7a\xfb\x36\xa2\xd0\xa3\xb7\x43\xdd\xb6\ -\xe3\x58\xe4\x79\x41\x9a\x4a\x94\xd2\xc0\x79\xdf\xf7\x39\x7a\x64\ -\x8a\xc0\xb7\x50\x85\x45\x92\xa4\x8c\xc7\x09\x60\xe2\xfb\x1e\x07\ -\x7b\x43\xee\xae\xae\x71\xdf\xe9\x33\x4c\xcd\xcc\x30\x3f\x3b\x47\ -\x50\xaf\x61\x58\x16\xa3\x28\xe2\xa5\x4b\xaf\xb0\xb1\xb9\xc1\x60\ -\x34\xe2\xf5\x37\x5e\xe7\xe8\xf2\x32\xd5\x6a\x85\xba\xa5\x41\xee\ -\x7b\x83\x3e\xc2\xb4\xe8\x54\x5c\x16\xe6\x66\x68\xb5\x9b\x5c\x5f\ -\x5b\x45\x20\xc8\xb2\x08\xdf\x75\xf1\x5d\x07\x65\x99\x58\xa6\x81\ -\xcc\x33\x5c\xdb\x40\xca\x0c\xd2\x04\xb2\x18\xcf\xb1\x30\xf2\x1c\ -\xcb\x04\xc7\x30\x40\x66\x38\x02\x6c\x0a\xe2\x7e\x0f\xb2\x04\xf2\ -\x14\x4b\x26\xf8\xa6\xa0\x66\x5b\x98\x59\x42\xda\xdf\x67\xb9\x5e\ -\x63\xba\x52\xa5\xe5\x07\x84\xa3\x11\xa3\x8d\x75\x94\xeb\x22\x5c\ -\x03\x61\x15\x24\x32\xa4\xc8\x42\x94\x28\x00\x89\xc8\xcb\x99\x57\ -\x9c\x92\x17\xda\xbd\x24\x0c\x6d\x80\x57\x4a\xa1\xa4\xb6\x59\xe6\ -\x65\x76\x94\x92\x52\x73\xcd\x2d\x13\xa5\x72\x48\x12\x8a\xc3\x2e\ -\x2d\x60\x58\x36\x8e\x63\x23\xcb\x71\x95\xe3\x6a\xff\x73\x92\x66\ -\xe5\xee\x5d\x26\x5e\x94\xd4\x4f\x15\xc7\x58\x81\x57\x02\xdb\x05\ -\x96\xed\x22\x65\x4e\x1a\xc7\x24\xe3\x50\x5f\x79\xc6\x63\x8c\x5a\ -\x0d\x3b\xf0\xa9\x34\xea\x7a\xe1\x10\x42\xf3\xc4\x84\xd0\xa8\xa5\ -\x24\x25\xa8\xd6\x08\x07\x03\xbc\x4a\x45\x27\x62\x0e\x07\x3c\x7a\ -\xee\x2c\x4f\x5d\x38\x47\xa3\x90\x2c\x77\x5a\x54\x2c\x7d\x62\x6b\ -\x34\xeb\x6c\xef\xf7\x88\x53\xc5\xd5\x6b\x37\xf9\xcb\x3f\xf9\x41\ -\x06\xa9\xcd\xea\x60\xc4\x67\x3f\xf7\x3b\x5c\xbd\x72\x85\x77\x3f\ -\xf9\x14\xf7\x9f\x39\xcd\x62\xb7\xca\xef\x7f\xfe\x0f\x98\x6a\x35\ -\x69\xd7\xeb\x3c\x7a\xf1\x7e\x11\x45\x09\x9e\x6d\xa3\xe1\x4a\x1a\ -\xfc\x9f\x67\x69\x79\x47\xfe\x6e\x47\x6b\xbe\x47\x47\x6b\xde\x56\ -\x7e\x99\x65\x96\xab\x2a\xc0\x35\x4c\x76\x07\xd9\x27\x9e\x7e\xec\ -\x2c\x5e\xb5\xc6\xcd\x5b\xd7\xb9\x72\xe7\x06\x15\xdf\xa1\x53\x0b\ -\x38\x88\x62\xe2\xf1\x90\xd0\x72\x08\x2a\x55\x2a\x7e\x80\x95\xc3\ -\xb8\x37\x02\xcf\x26\x89\x33\x8a\x54\x72\xd0\x1f\xea\x9d\xce\x77\ -\xe9\xdf\x5d\xa7\x7e\x64\x99\x83\x78\xc0\xda\xab\x57\xd8\x1c\x7c\ -\x9a\x27\x1f\x7c\x80\x07\xcf\x9c\xe4\xc1\x13\x73\x8c\x92\x8c\x63\ -\xf5\x36\xb9\x30\x30\x84\xa2\x52\xa9\x50\xf3\x6d\xc2\x24\x67\x3c\ -\x1e\x53\x09\x3c\xce\x9c\x3e\xc9\xee\x5e\x9f\x3b\x77\xee\xb0\xbb\ -\xbb\x4b\xa7\xd3\xe1\xe8\xd1\xa3\x4c\x4f\x37\xf4\xb3\x1a\xc7\x0c\ -\x06\x03\xd6\x37\xfb\x93\x86\x4d\xbb\xe5\x69\xe9\x60\xa6\x47\x54\ -\xd3\xed\x1a\xb5\x4a\x15\x53\x18\xba\xa3\x6c\x19\x54\xaa\x55\x1a\ -\xcd\x2a\xb5\x66\x83\xb3\x17\x4e\x12\x45\x1a\x0c\x77\xf5\xea\x55\ -\xf6\x77\xf7\xb8\x7a\xe5\x4d\xcd\xb0\x32\x14\x47\x4f\x1d\xa3\xb7\ -\xb5\x81\xdf\x68\x71\x7c\x66\x86\x63\x8f\x9c\x67\xb4\xb5\xcb\xd5\ -\xd5\xbb\xbc\x7a\xfd\x26\x49\x18\xe2\x78\x15\x2a\x6e\x40\x34\xea\ -\xe3\x22\x28\xe2\x11\x2e\x06\x4a\xea\x3e\x42\x35\xd7\x79\x51\x46\ -\x66\x21\xac\x94\x22\x49\xf0\x1d\x0f\xd3\x10\x58\x4a\x62\x52\x90\ -\xcb\x14\xd7\xb6\x38\xde\xed\x70\xe1\xfc\x59\xe6\xe6\x66\x70\x01\ -\x37\x89\x69\x54\x6b\x28\xcb\xe3\xd2\x5b\x37\xf9\xdd\x2f\x7e\x99\ -\x50\x28\x46\xe1\x01\x85\x29\x74\x43\x31\x8e\xb1\xb2\x1c\xc7\x72\ -\xb1\x7c\x97\x3c\x91\x8c\xa2\x18\x53\xc0\xa8\x77\x30\xb1\x4d\xea\ -\x8f\xdf\x78\x7b\x8e\x5c\x14\x98\xae\x4b\x1e\x45\xfa\xb4\x60\x99\ -\xe4\x4a\x61\xbb\xae\xd6\x72\x17\x0a\x47\x98\x18\xa2\xd0\x9c\xb2\ -\x3c\x27\x4d\xd3\x89\xc9\x41\xe7\x6b\x69\x9e\x99\xa6\xac\x52\xc2\ -\xe1\x95\xbe\x3e\x18\x20\x47\xfb\x4c\x7c\x7e\x0a\x2c\xc7\x45\xfa\ -\x3e\xd5\x6a\x15\xdb\x75\x26\xb3\xe9\x43\xb3\xc6\xc4\xc0\x71\x68\ -\xf2\xb0\x1d\xc6\xe3\x08\x25\xb5\x74\x78\x6e\xaa\x43\xc5\x2b\xef\ -\xe3\x0a\x92\x34\xa2\x48\x32\xd6\xd6\x76\xc8\x0c\x83\x2f\x7f\xed\ -\x79\x3e\xfa\x91\x4f\x70\xe7\x00\x2c\x0f\x3e\xfb\x4f\xff\x35\xaf\ -\xbd\xfe\x3a\x8b\xb3\xb3\x3c\xfc\xf0\xfd\x8c\xf6\x47\x7c\xf5\xf3\ -\x5f\xe7\xec\xc9\xd3\xb8\xa6\xc5\x23\x0f\x3f\x22\xc2\x28\xc1\x36\ -\x4c\x4c\x74\xce\x59\xb3\xde\x28\x11\x1f\x5a\xe8\x23\xbe\x2f\x8e\ -\xd6\xdf\x26\xfd\x32\x0e\x8f\x58\xf7\xe0\x4d\x15\x50\xb7\x8d\xbf\ -\x6b\x0b\xfe\xd6\x23\xa7\x16\x8b\xbf\xfe\xd3\x9f\xe0\x1f\xfc\xfa\ -\xaf\xb3\xb9\x76\x1b\x6b\x61\x59\xab\xb0\xcc\x8c\x2c\x4b\x88\x22\ -\x1b\xd3\x36\x70\x1d\x9f\xb1\xe9\x60\xf8\x55\x54\xa6\x10\x96\x4b\ -\x51\x8e\x12\xfc\xc0\x25\x4c\x13\x9c\xa0\x42\x6f\x74\xc0\xfd\x8f\ -\x3f\xc5\xdd\x9b\x37\x78\xf5\xe6\x2a\xbb\x07\x3d\x56\x56\xa6\x51\ -\xa3\x1e\x4f\x3c\xf1\x30\x81\x01\xe3\x61\x44\xaf\xb7\x47\xe4\x07\ -\x65\xe4\x8a\x4e\x5a\x50\x4a\x31\x3f\x3f\xcf\x89\x53\x0b\x64\x12\ -\xf6\xf6\x34\x57\xe9\xca\x95\x90\x4e\x99\x52\xd0\x68\x34\x98\x99\ -\xd1\xd8\x9f\x28\x2a\x18\x8e\xf2\x09\xe8\xcf\x12\x26\xfd\x30\x23\ -\x19\xc7\x65\xa7\xd8\xc0\x30\x75\x3c\x68\x61\x81\xb0\x4c\xc6\x91\ -\xfe\xfe\x6a\xe0\xd1\x6c\xd6\x39\x75\xe2\x18\xcb\x0b\xf3\x98\x08\ -\xea\x0d\x9f\x5b\xd7\x6f\xe2\x63\x13\x1f\x0c\xb8\xb3\xba\xc9\x50\ -\x16\x44\xb7\x56\x38\x56\xab\x53\x59\x3e\xc2\xda\xce\x1e\xfb\x83\ -\x01\x45\x18\x51\xc4\x29\x53\xb3\x33\x3a\x70\xbd\x56\xa7\xc8\x7d\ -\x44\x96\x11\x38\x36\x7d\x99\x92\xa5\x09\x2a\x51\xfa\x3d\x72\x73\ -\x6c\xc7\xa4\xa1\x32\xe6\x66\xa7\x39\x75\xf2\x04\xa7\x8e\x1f\xe3\ -\xf8\x91\x19\xba\x0d\xfd\x71\x25\x29\xa8\x44\xf7\x85\x3c\x17\x3a\ -\xcd\xd3\xa4\x61\x9f\xdb\x5b\x9b\xdc\xde\xdc\x24\x94\x29\xe9\xb0\ -\x87\xd5\xdf\xd7\xa1\x69\x86\xc9\x38\xca\x28\x86\x63\x48\x15\xb2\ -\x3b\x03\x7e\x55\x17\xb2\x36\x54\xe3\xd8\x3a\x08\xa0\x28\x47\x75\ -\x8e\xe3\x30\x0a\x43\x3d\x27\x77\x1d\xc2\xb2\x38\x0d\xdb\x42\xc9\ -\x0c\x99\x6b\x5f\xf7\xe1\xb1\xd9\xb0\xb4\x1d\xd2\x16\x06\x8e\xe3\ -\x90\x65\x89\x2e\x3c\x55\xe8\xdd\x3d\xcf\x51\x99\x2c\x17\x0e\x55\ -\xa6\x37\x1a\x38\xa6\x85\xa9\xc0\x14\xc6\x24\xb9\xb1\x08\xc7\x14\ -\x96\x31\xc9\x79\x7e\x47\xe2\x84\x94\x3a\x52\xd7\x71\xc9\x55\x8e\ -\xeb\x7b\xd8\x69\xc8\xb7\x9e\xfd\x2a\xf3\x56\xce\x7d\x8d\x1a\xed\ -\x3a\x44\xa1\xcf\xea\xc6\x36\xfb\xa3\x11\xcd\xb9\x05\xa6\x8f\x1c\ -\x45\x39\x82\xa9\x0a\xfc\xf6\xef\xbf\xc2\x17\xbf\xfc\xc7\xdc\x7f\ -\xf1\x1c\x3f\xf3\xb1\x8f\x93\xa6\x8a\x34\x8e\x49\xe3\x98\x76\xbd\ -\xc1\xd9\xd3\x27\x4f\x54\x5c\xc1\x60\x98\xe3\xd7\x5c\x0c\xc0\xb1\ -\xec\x89\xe7\xda\x34\xcd\x3f\xc1\xdf\xfe\x9e\xef\xc8\x1c\xc6\xce\ -\xbc\x23\xae\xa2\x14\xf8\x67\x39\x0d\xd7\xfe\x5b\x51\x0e\x5d\x9b\ -\xbf\xfe\xa3\x4f\xde\xff\x6b\x79\xf4\x53\xfc\x0f\xff\xe8\xd3\xec\ -\xee\x6c\x61\x4f\xcd\x12\xf8\x1e\x85\xb0\x88\xc6\x21\xc2\x90\x34\ -\x5a\x2e\xb8\x1e\xb6\x69\x91\xc8\x18\xcb\xd6\x91\x2a\xf1\xc6\x3a\ -\xf6\xc2\x1c\xc6\x54\x87\xfd\xfd\x7d\x0c\x37\xe0\xfa\xe6\x2e\x49\ -\x56\x70\x7b\xfb\x80\xfd\xdd\x5d\x2e\x9e\x3b\xcb\x76\xaf\xc7\x37\ -\x5f\xbe\xcc\x7c\xb3\xc6\xf2\xcc\x34\x0b\x0b\xb3\x18\x40\xbf\xaf\ -\xf5\xba\xb6\xeb\x61\x59\x3a\xaf\x77\x30\xd4\x74\xff\x20\x08\x38\ -\x7f\xfe\xbc\x0e\x3d\xef\xf7\xb9\x7e\xfd\x3a\x07\x07\x07\x58\x96\ -\x45\xb3\xd9\x44\x08\x81\xe7\x79\x54\x2a\x15\x4c\x13\xf2\xb4\xc0\ -\x36\x05\xae\xe3\x6b\xe5\x91\x2c\x90\xa9\x22\x2b\x72\xdc\xc0\xa1\ -\x10\xe0\xba\x26\x86\x11\x60\xdb\xfa\x01\xb2\x2c\x13\xaf\x12\x10\ -\x85\x21\x51\x3f\xe4\xf4\xd2\x51\xa4\x94\xa4\xaa\x20\xcc\x14\xa6\ -\xef\xd3\xa9\x34\x99\x3b\x7a\x94\xdc\x82\x17\x5f\x7b\x93\x17\x2f\ -\xbd\xca\x7e\x6f\xc8\x38\x8e\x78\xe0\xc2\x59\xb2\x5c\xd2\xed\x76\ -\x51\x89\x0e\x0e\x37\x11\x6c\x6d\xed\x30\x1a\x8d\x88\xe3\x98\xf1\ -\x78\x8c\xef\xea\xb8\x9b\xa3\x47\x16\xb1\x2d\x03\xdf\x36\x50\x3b\ -\x1b\xdc\xde\xdd\x60\x25\x97\x3a\x4a\xd7\x14\x04\x35\x97\xdd\xde\ -\x01\x96\x57\x43\x38\x1e\xe9\xee\x5d\xb2\xed\x2d\xa2\xdb\x2b\x44\ -\x71\xcc\xf2\xb1\xa3\x9c\x3b\x7e\x94\x0b\x17\x1f\xa4\xd9\x9d\x62\ -\x65\x7d\x83\x17\x5e\x7e\x8d\x9b\x6b\x77\xf1\xeb\x15\x32\xc7\x27\ -\x94\x5a\xf7\x7d\x48\x1e\x31\x0c\x03\x99\xeb\xfb\xb0\xeb\xba\xf7\ -\x38\x29\xca\x46\x4f\x96\x81\xca\xc9\x92\x58\x37\xc9\x6c\x73\xb2\ -\x10\x58\x25\x79\xa6\x28\xf4\x11\x3d\x4d\xd3\xd2\x05\xa4\x53\x4c\ -\x28\x03\xd5\x0f\x17\x0f\xd3\xb6\xcb\xb1\xb9\xd2\x33\xd9\xd2\x34\ -\xe1\xfb\x1a\xf1\x93\x96\xc6\xfc\x3c\xcf\xc9\xa2\x88\x54\x08\xbd\ -\x82\x09\x81\xed\xfa\xfa\x2a\x67\x14\xf8\x4e\x41\xa5\x62\x61\x85\ -\x7d\x1e\x7d\xec\x21\x82\x61\x9f\xaf\xbf\x70\x05\xd7\x12\x98\xae\ -\xc5\xf2\x99\xb3\x7c\xf5\xb9\xe7\x39\xfb\xc0\xa3\x0c\x62\x78\x79\ -\x3b\xe5\xab\xcf\x7e\x93\x5a\xad\xc6\x03\x17\xef\x67\xf9\xc8\x02\ -\x6f\xbc\xf8\x12\xc3\xf5\x2d\xa6\xdb\x2d\x1e\xba\x78\x5a\xd8\x02\ -\x92\x48\xd2\xac\x05\x00\x8c\xc7\x11\xd5\x4a\x30\x91\x9c\x5a\xa5\ -\xf6\xfd\xfb\xae\x90\xdf\x36\x57\x98\xf7\x48\xf5\xa0\xc8\x92\x89\ -\x53\xa9\x1f\x2b\xea\x9e\x21\xde\xfb\xe8\x83\xc5\x8d\xf5\x1f\xe2\ -\xef\xfd\x8b\xdf\x85\x6a\x1d\x61\x68\xae\xf3\xec\xcc\x22\xc3\x51\ -\xcc\xc1\xf6\x0e\x41\xa3\x49\x38\x18\xd2\xe8\x74\x70\x1c\x8b\x83\ -\xde\x1e\x7e\xbb\xc9\xf8\x60\x07\x75\xb0\x4b\xeb\xd4\x69\x22\x65\ -\x10\xe7\x39\x66\x50\x23\x33\x60\x73\x7f\x9b\x2f\x7d\xed\x5b\xbc\ -\xff\x89\x47\x38\x7d\xf6\x3e\xd6\xae\x5d\x25\x0d\x6f\xb3\x57\xad\ -\x51\xf3\x3d\x66\xba\x2d\xc2\x50\x12\xc5\x19\x86\xe9\x60\xd8\x06\ -\x86\x44\xcf\x39\xcb\xe3\x9c\xef\xeb\xe4\x04\xc7\x71\xb8\x75\xeb\ -\x16\x61\x18\xb2\xb1\xb1\x01\xc0\xec\xec\x2c\x8d\x46\x83\x4a\xa5\ -\xa2\xc5\xfa\x86\x9e\x99\xda\x96\x6e\xbc\x0a\xa1\xbd\xdb\x87\x00\ -\x02\x29\x35\xc8\xde\x14\xba\xa3\x2a\x53\x49\x26\x35\x7a\xc7\x31\ -\x4c\x64\x06\x79\xa6\x05\xec\x15\xdb\x23\x95\x05\xf9\x70\x84\x9f\ -\x17\xa4\x32\xe7\x99\xc7\xee\xe3\x83\x8f\xdf\x47\x9a\xc1\x38\x2e\ -\xf0\x3c\x3d\x1d\x18\x8d\x62\xea\x55\x8f\xd7\x5f\x7b\x8b\xb3\x67\ -\x4f\x51\x36\x88\x09\x43\xdd\x8c\xb3\x74\x36\x1c\x69\x04\xeb\x77\ -\xd7\x71\x2c\x98\x9b\x99\xc6\x35\x35\xfd\xc5\xb3\x4d\x32\x0a\xa4\ -\xad\x18\x26\x11\x86\xe9\xe3\x3a\x26\x22\x1a\xf3\xb3\x3f\xf1\x11\ -\x92\x30\x62\xe3\xee\x3a\x8b\x0b\x0b\xd4\x9a\x01\xc3\xb4\xc0\xf0\ -\x05\x6e\x92\xf0\xee\x9f\xff\x39\x7e\xe5\x7f\xfc\x9f\xb0\x02\x97\ -\xdd\x44\x2b\xde\x4c\xa7\xc4\xef\x8a\x77\x76\xa9\xa3\x28\x82\xd2\ -\x50\x71\x88\x52\x12\x86\x41\x52\x66\x67\xe9\xd1\x9f\x9c\xe8\xb0\ -\xa5\xd4\x71\x40\x87\xe9\x22\x59\x18\xea\xaf\x59\x66\xd9\xdd\xb2\ -\xf4\xe2\xe0\xda\x38\x7e\xc0\x38\x96\x6f\xc7\xbe\x9a\x87\x88\x5b\ -\xad\xbc\x3b\x4c\xb6\x50\x69\xaa\xdf\x8c\xe1\x08\xd1\x6a\x51\x6b\ -\xb7\x19\x84\x77\xb1\x2c\x8b\x61\x2a\x71\x2b\xb6\x8e\x08\x2e\x12\ -\x3c\xe0\xcd\xb7\xde\xe4\x89\x63\x47\xd9\x89\x43\x16\xe7\xa6\x69\ -\xcf\xce\x92\x38\x36\xed\xc5\x25\xb6\x7b\x43\x54\x36\xe0\xd7\xff\ -\xd7\xdf\x20\xcf\x62\x3e\xf8\xfe\xf7\x71\xe1\xec\x69\xae\xbc\x76\ -\x89\xd5\x1b\x37\x78\xf8\xc4\x69\x9e\x7a\xe8\x81\x17\x45\x29\x6b\ -\xf7\x5d\x9d\x5c\x2c\x0c\xa8\x56\x7c\x0a\xde\x2e\xe0\x82\xe2\xbb\ -\x18\x23\xbe\xd7\x3b\xf2\x77\x6c\x68\x1b\xd8\x86\x1e\xd0\x0b\x55\ -\x40\x1a\xe1\x7a\x15\x96\xea\x81\xf8\xc9\x1f\x7e\xa6\xd8\x2c\x2c\ -\xfe\xe0\xc5\xd7\x48\x92\x18\x99\x0b\x36\x56\x6e\x72\xe2\xcc\xfd\ -\x8c\xfa\x23\xe2\x71\x08\x4a\x32\x1c\xf6\x71\x1d\x0b\x91\x67\x54\ -\xaa\x35\x6a\x5e\x83\x9d\x34\x24\x1e\x0d\x89\x93\x02\xb7\x33\x45\ -\xbd\x56\xc5\x08\x47\x54\xa7\xa6\xd9\xde\xdd\x67\x7b\x7b\x07\x3f\ -\xb8\x8f\x73\xe7\xce\x10\xf5\x86\x6c\xad\xae\xb2\x3e\x1e\x13\x8e\ -\x97\x58\x58\x98\xa5\xde\x6c\xa3\x30\x88\x47\x31\x05\xfa\x01\xf3\ -\x7d\xf7\x90\x96\x4a\xaf\x97\xb0\xbf\xbf\x4f\xb7\xdb\xe5\xd4\xa9\ -\xa3\xda\x1e\xb9\xb7\xcf\xc1\xc1\x01\xeb\xeb\xeb\x98\xa6\x49\xe0\ -\xfa\x1c\x59\x5c\x26\x8e\x43\x72\x05\xa6\xa9\x1f\x26\x2c\x90\x45\ -\x99\x3c\x58\x76\x71\x1d\x4b\x13\x4a\x7c\xdf\x42\xc6\x3a\x2a\x34\ -\x93\x9a\xda\xe8\x56\xf5\xfc\x3b\xca\x60\x7c\x30\x62\x30\xe8\xe1\ -\x98\x05\xdd\xba\xc5\xfa\xf6\x18\xc7\xd3\xf4\xc7\xb6\x6b\xe2\x96\ -\xd9\xe6\xbe\x67\x10\x8e\xfa\x98\xf9\x18\x33\xcf\xb0\x0d\x1b\xd7\ -\x02\xc3\xd6\x1f\xaa\x4c\x41\x66\x09\xb5\xc0\xa5\xe6\x09\x1c\xd3\ -\xa4\xe2\x80\x59\x28\xd2\x24\x22\x4d\x0b\xc2\x3c\xc6\x6a\xf8\x98\ -\x06\xd8\x96\xc2\x54\x26\x46\x38\xc4\x4f\x22\x16\x1b\x15\x8e\x57\ -\x4e\xe9\x9f\xf1\x60\x20\x04\xd7\x56\xf7\x78\xe2\xec\x71\xb6\x63\ -\xb8\xff\xcc\x29\xbe\xf0\xad\x17\x71\xe7\x8e\xa2\xc8\x51\xaa\x54\ -\x5e\x19\xba\x71\x78\x68\xf2\x1f\x0e\x87\x13\x5a\x88\xb8\x27\xa8\ -\xdd\xa2\xc0\x2e\xd9\x62\x4a\x42\x2a\x52\x28\xcd\xf9\x45\x51\x40\ -\xac\x45\x37\x5e\xb3\x5e\xca\x63\x35\x12\x29\x2b\xa3\x5e\xf2\x72\ -\xc7\x37\x0c\x8d\xca\x3d\x3c\x7e\xe7\x79\x3e\x59\x14\x0c\xc3\x40\ -\x85\x23\x28\x67\xdd\x85\x59\x7a\xcd\xd3\x0c\x0c\x43\xdb\x56\x9b\ -\x2d\x06\xbb\x5b\x98\xae\xa2\x52\xaf\x32\xde\x5e\xe5\xd7\x7f\xe3\ -\xd3\xd8\x1f\xff\x18\x3f\xf2\xee\xa7\xa8\xba\xb0\x39\x8c\xc9\xb0\ -\x19\x44\x09\xe3\x28\xe4\xc5\x6f\xbe\x88\x54\x19\x53\xed\x26\xbe\ -\x69\x90\xf4\x7b\x04\x86\xe0\xfc\xa9\xe3\x9c\x3e\xb6\x4c\xcd\xe7\ -\x51\x91\x94\x96\x04\xfe\xdd\xbc\xfe\xfc\x85\x2c\xd4\xb7\x5d\x97\ -\x8d\xb7\xa7\x04\xda\x01\xaf\xad\x6d\xaa\xc0\xb4\x0c\xaa\xae\xf3\ -\xa9\x42\x29\x1c\xc3\xe0\xd4\x54\xf3\xe0\xe7\x3e\xfe\x93\x2d\x2c\ -\x87\x6f\x7c\xf3\x25\x0e\xd2\x84\x99\xa9\x2e\xb7\xaf\xbd\xc9\xf2\ -\xb1\x13\x84\x99\x62\x67\x75\x1d\xc3\xf7\x69\x35\xea\x64\x99\x4d\ -\x16\x47\xc8\x34\xa2\x48\x62\xa2\xdd\x0c\x7b\xee\x28\xc9\xfa\x3a\ -\xdb\xae\x85\x47\x4e\x20\x63\xc6\xd1\x10\x99\x24\xa4\x91\xce\xfa\ -\x9a\x9a\xaa\x31\xd7\x39\x47\x21\xe1\xad\xb7\x56\xf8\xda\x37\x9e\ -\xe3\xc6\xf5\x5b\x9c\x3a\x73\x9a\xd9\x8e\x47\xac\x20\x49\x20\x8a\ -\x92\x32\xfc\xda\xc5\xf3\x3c\x3a\x9d\x0e\xeb\xeb\xeb\xf4\x7a\xe3\ -\x32\x17\xb9\xc5\xc2\x42\x9b\x38\x3e\x41\x14\xc5\x84\x61\xc8\xdd\ -\x8d\x35\x6e\xdf\xbd\xcd\xad\x95\x5b\xe4\x02\x1c\xdf\xa3\x52\xad\ -\xe2\x05\x3e\x66\x49\x11\xc9\x8b\x02\x99\x42\x12\x26\x44\x23\x0d\ -\xce\x33\xcb\xfb\x5a\x9c\x4b\xc8\xf4\xc3\xed\xfa\x16\x95\x4e\x95\ -\x7a\xb7\x4d\x56\x48\x36\x76\x13\x9a\x9d\x1a\x96\x09\x61\x94\x60\ -\x99\x10\x47\x19\x4a\xe5\x38\xb6\xcd\xee\xea\x3a\xb5\xba\x87\x61\ -\x29\x52\x19\x22\x4c\x1f\x25\x32\xed\xf6\xf1\x00\xe5\x32\x18\x84\ -\x8c\x93\x11\xb9\x6b\x93\x52\xd5\xf3\x56\xc3\xc2\x32\x04\xa2\x30\ -\xc9\x0c\x85\x48\x25\x05\x19\x42\x14\x34\x7d\x8f\xa6\x6b\x51\x15\ -\x50\x64\x19\x72\x94\x82\xe5\x30\x1e\x0d\x38\x3d\xdf\x61\x5b\xc2\ -\x54\x03\xe2\xd1\x90\xc5\x85\x05\x8a\x56\x87\xb1\x12\xe4\x69\xa6\ -\x19\xdc\x65\x81\x65\x65\x71\x99\xa6\xa9\xa1\x04\x85\xf6\x20\xa7\ -\x69\x8a\x91\xe7\xe4\xb9\xd4\x51\xa5\xc3\x91\x66\x8d\xa5\x52\xe3\ -\x5b\x82\x40\x13\x3a\x5c\xbf\x24\x89\x88\x49\xb6\x51\x51\x40\x86\ -\x7e\x96\x54\x79\x57\x36\x1d\x7f\x12\xec\x2e\xa5\xd4\xae\xab\x44\ -\x27\x4c\xea\xd8\x46\x8b\x6a\xb5\x4a\x94\x26\x14\xa6\xce\x16\x8e\ -\x46\x23\xec\x5a\x0d\xcf\xf3\xe8\xf5\xfb\x98\x95\x0a\x86\x1a\xb3\ -\x7a\xe9\x65\x5c\xdf\xe4\xfc\xdc\x0c\x8f\xfc\xc0\xe3\x98\xae\x4e\ -\x0a\x51\x8e\xc7\x56\x6f\xc4\xad\xf5\x4d\xee\xdc\x5e\xa3\x3f\xd0\ -\xd0\xbc\x8f\x7f\xf4\xc3\x08\xd5\xa3\x6e\x1a\x34\x83\x80\xd9\x56\ -\x9b\xc5\x4e\x53\xd8\x65\x19\x94\x9e\x8d\x89\x9b\xbf\xb8\xc7\x9e\ -\xf4\x9d\x3c\xc5\xdf\x17\x3b\x72\xf1\x6d\xb7\x63\xf3\xb0\x01\x56\ -\xbe\x99\x94\x44\x43\xd7\xb1\x91\x45\xce\x30\x1e\x1f\x97\x86\xd3\ -\x5a\x08\x6c\x7e\xfe\x27\x7e\x8c\x9b\xaf\xbc\x8c\x95\x1b\xec\x6e\ -\xae\x63\x09\x87\xe1\xc1\x2e\x41\xa3\x8b\x5d\xaf\x92\x8d\x06\xac\ -\xc7\x63\x1c\xcf\xa1\x16\xb8\x74\x66\x66\xa8\x05\x0e\x1b\x6b\x9b\ -\xa8\x38\x21\xe8\x74\x09\xd7\x57\x31\x03\x9b\x73\x27\x4f\xd0\x5f\ -\xbb\xc5\xea\x8d\x1b\xe4\xc9\x7b\x50\xd2\x00\xd7\x62\x38\x0c\xb1\ -\x4c\x93\xa5\x85\x79\x1e\xbc\xff\x28\x9f\xcf\x73\xbe\xfe\xf5\xaf\ -\x53\xf1\x3d\x9a\xad\x06\xf3\xf3\xf3\x65\xe2\xa2\x5e\x8e\x0e\xef\ -\x9a\xd5\x6a\x95\x5a\xad\x32\x09\xfb\x8e\x63\x88\xa2\x58\x53\x34\ -\x5d\x97\x93\xa7\x4f\xb3\x7a\xf7\x2e\xb5\x46\x83\xdd\xfd\x3d\x7a\ -\xdb\xdb\x64\xeb\xeb\x13\xb4\x4d\xa7\xdb\xc6\x32\x4c\xe6\xa6\x67\ -\x70\x6c\x9b\x6a\xd5\x22\xb5\x2c\x72\x99\x93\xe6\x39\xb5\x8e\x4b\ -\x6e\xe8\x2e\xf8\x28\xd1\x40\xfc\xbd\x83\x5d\x30\x4f\xd2\x6e\xd4\ -\x48\x92\x0c\xa5\x0c\xe2\x68\x8c\x21\x7c\xa2\x70\x8c\x69\x9a\x54\ -\x2b\x3e\x83\x61\x8f\x63\xc7\x4f\x51\x0b\x5c\x06\x61\x48\x81\xc6\ -\xdc\xe6\xb9\xe6\x5f\x03\x54\x6b\x01\xbd\xbe\x8b\x65\x8a\x32\x30\ -\x4d\xc3\x09\x34\xa4\x0f\x6c\x61\x23\x29\x30\x15\x88\x42\xe1\x39\ -\x1a\x56\xaf\xd2\x1c\x99\xc6\xb4\xaa\x35\x36\xb7\x76\x38\xba\x34\ -\xc5\xc8\x02\x52\x18\x0d\x34\x98\xc1\xe8\xcc\xb2\x71\xf7\x2e\xd8\ -\x1e\x46\x69\xec\x77\x4a\x45\x17\xe6\x61\x52\xc3\x18\x0e\xef\xba\ -\x42\xb7\xfb\x73\x43\xeb\xc2\x95\x69\x40\x25\x28\xef\x24\xfa\xde\ -\x7a\x78\xac\x56\x85\x9a\xbc\x87\x4a\xa9\xd2\x14\xf2\x27\xf4\x89\ -\xc4\x71\x4c\xa1\x0e\x41\x0a\x6a\x32\x02\x9d\x8c\x46\x6d\x7d\x3a\ -\x08\x4b\x79\xa8\x10\x02\xe2\x98\xca\x8c\xee\x79\xd8\x8e\x43\xb6\ -\x7d\x97\xdc\x83\xc6\xb1\x63\x54\xb2\x31\x52\x2a\xd2\x4c\x91\x01\ -\xb9\x09\x57\xaf\xad\xb0\xb2\xbf\xcf\x17\xbe\xf8\x25\x0c\x0c\xbc\ -\x42\xf0\x43\x1f\x7c\x9a\xf5\xdb\x37\xb8\xff\xe4\x3c\x0d\xdb\x64\ -\xb1\xd3\x61\xb6\xdd\x10\x5e\xb9\xb7\xbd\x9d\x41\x5e\x68\x4e\xfc\ -\x3d\x15\xfb\xa7\xa5\x2a\x7e\x8f\x0b\xf9\xed\x95\xa6\x98\x98\xb1\ -\x4a\x15\xb7\xa1\x09\xe0\x45\x96\x90\xc6\x63\xdc\x4a\x80\x29\x04\ -\x15\xcf\xbd\x69\x63\x09\x1b\x5e\xa8\xf9\x3c\xf2\xdf\xfc\xd5\x4f\ -\xf2\xdf\xfd\xfd\x7f\x80\x34\x6d\x06\x85\x44\x86\x63\xb6\xa2\x98\ -\x6a\x67\x86\x83\x42\x77\x19\x53\xa9\x18\x0c\xf5\x28\xc3\x77\xaa\ -\x78\xd5\x3a\x42\x49\xda\xae\x4d\xd0\x6a\xd0\xad\x38\xf4\x37\xee\ -\xf2\xf0\xd9\xd3\x5c\x3c\x7e\x84\xf9\xa6\xc3\xe8\x20\x24\x4a\xc6\ -\x04\x9e\xc7\x74\xd5\xe5\xee\x7e\xc8\xed\xb5\x21\xb5\x5a\x8d\x27\ -\x9e\x78\x02\x53\xc0\xf6\xce\x16\x77\xef\xde\x65\x7d\x7d\x9d\x56\ -\xab\xc5\xec\xec\x6c\x89\xc4\xcd\xca\x2c\xe4\x12\x41\x9b\x65\x1a\ -\x02\x68\x18\x78\x9e\x83\x6d\xc3\x68\x2c\x71\x3c\x87\x99\xb9\x36\ -\x9d\xd9\xb6\x36\xde\x0b\x90\xa5\x38\x61\x70\xd0\xa7\xd7\xeb\x71\ -\xfb\xd6\x6d\x5e\x7a\xfe\x45\xaa\x7e\x45\x43\xd9\xea\x0d\xbc\x6a\ -\x85\xad\x61\x0f\x3b\xf0\x08\x82\x80\xa0\x6a\xe1\xfa\x0d\x1a\xed\ -\x26\xa6\x69\x12\x45\x19\x85\x92\x08\xcb\xd2\x29\x1d\x9e\xaf\xe9\ -\x1a\x4a\x21\x73\xe8\x1d\x68\x93\x8a\x83\xc6\xc4\xba\xb6\x45\x2c\ -\x14\x4a\x41\x18\x46\x48\x29\xf1\x1c\x97\x24\xc9\x28\x4c\x0b\x29\ -\xb5\x73\xad\x90\x0a\xa9\xb4\xc9\xc0\xb5\x04\x9e\xb0\xb1\x1c\x8f\ -\x51\x18\x11\xc6\x92\xfd\xc1\x10\xa7\xdd\xa5\xde\xad\xb1\xb3\x35\ -\x60\x90\xa5\xd8\x31\x0c\x54\x81\xb2\x05\xd5\x2a\x34\xbb\xd3\xec\ -\xe7\x8a\x56\xbb\x4b\x66\x3a\x18\x25\x02\x48\xcf\xec\x53\x64\xa2\ -\xc7\x49\xe4\x7a\x76\xac\x3c\xb7\x8c\x62\x11\x1a\x0c\x80\x85\x61\ -\x99\x04\x9e\x47\x9e\x67\x44\x42\xdb\x24\x0f\x99\x55\x87\x45\xec\ -\x38\xee\xe4\x0e\x7c\xf8\x6f\x87\xe3\x2d\xa5\x14\xc5\x28\xd2\x09\ -\x66\xa6\x55\x46\x06\x39\x44\x9e\x37\x69\x76\x0d\xc3\x91\x6e\xae\ -\x95\x30\x3f\xd7\x71\x08\xcb\xd1\xd3\xb0\x37\x80\x30\xc4\x9a\xee\ -\x32\xdd\xf6\xc9\x47\x7b\xf4\xb7\xd6\xf8\xe1\x1f\x7e\x86\x99\x96\ -\xc3\xcb\xaf\xac\x90\xe6\x8a\xf6\xdc\x1c\x5f\xfc\x17\x9f\x65\x6d\ -\x75\x83\xe5\xc5\x05\xba\xad\x26\x4b\x53\x1d\xd2\xdd\x2d\xc2\xdd\ -\x1d\xe6\x97\x66\x99\x6f\x36\x84\x5f\xea\xa8\x4d\x0d\xb4\x23\x4d\ -\x13\x6c\x47\x37\x3d\x8b\x3f\xe1\x68\x10\xdf\x4f\x85\xac\xbe\xeb\ -\xae\x7c\xe8\xdd\xa0\x54\xf2\x08\xc7\xc6\xa2\xe4\x2a\x59\x16\x06\ -\x06\x0e\x0a\xa1\xb2\x47\xab\x86\xcb\x13\x27\x97\x8a\xff\xf6\x97\ -\xfe\x1a\x7f\xef\xd3\xbf\x49\x78\x30\x26\x1c\x15\xd8\x8d\x2e\x07\ -\x7b\x3b\x58\xd5\x3a\xd5\xce\x14\x96\x65\xb1\x7b\x77\x8d\x9d\x95\ -\x75\xac\xaa\x8f\x4c\x13\x5a\x8e\x4f\xc7\x77\xf1\xbd\x29\x7e\xfe\ -\x67\x7e\x8a\xc5\x26\x5c\x7b\xe5\x4d\x2e\x3f\xff\x2d\xde\xf3\xc0\ -\x7d\xcc\x34\x02\xf2\x34\x23\x09\x23\x56\xb7\xc7\x38\xae\xcf\x99\ -\xc5\x0e\x86\x30\x79\xed\xd2\x2b\x9c\x3a\x7d\x92\x6e\xb7\xcb\xec\ -\xec\x6c\x29\xbb\x5c\x65\x75\x75\x95\x20\x08\x26\x90\x38\xdd\x6d\ -\xd6\x5a\xe7\xc0\xd3\xa7\xc0\x38\xce\x19\x0c\xb5\x8f\x35\x92\x29\ -\x51\xaa\x0b\xb7\x14\x31\xea\x5d\x4f\x29\xa6\x5a\x6d\x5a\xb5\x3a\ -\xbe\xef\xb0\xb7\xb3\xc3\xb9\x73\xe7\xe8\xf5\x7a\x44\x51\xc4\xce\ -\xde\x2e\xc2\xb3\x38\xd8\x5c\x67\x30\xec\x69\xfa\x62\xa5\xca\xda\ -\xca\x2d\x5a\xb5\x2a\x79\x26\x39\x76\xec\x18\x32\xc9\xf5\xb1\x52\ -\x82\xca\x04\xb6\x1d\x50\x48\x83\xc0\xad\x31\xee\x8f\xb1\x85\xcd\ -\x68\x14\x22\x6a\x35\x8a\x02\x6c\xcb\xc2\xf6\x7c\x2c\x0b\x7a\xbd\ -\x10\x43\x1a\xd8\x8e\x43\xe0\x06\x38\xa6\x4e\x25\xd5\xc8\x9d\x04\ -\x0f\x1d\x91\x62\x22\xb0\x0d\x97\x7a\xab\x8b\x11\x54\x88\x44\x81\ -\x4a\x05\x95\xd9\x3a\xd5\xb9\x3a\x9b\x7b\x29\xc1\x94\xc3\x66\x1f\ -\xbe\xf9\xfc\x0a\x83\x71\x42\x4f\x2a\xb2\x83\x35\x9d\x4f\x85\x28\ -\x41\x7b\xe5\x09\xcc\xb4\xf4\x0c\x59\x4a\xcd\xb6\x2e\x67\xc7\x79\ -\xae\x75\xf5\xb2\x50\x58\x96\xa9\x77\xd4\x72\xa1\x3e\xdc\x91\x2d\ -\xcb\xc2\x12\xd6\x3b\xa0\x73\x87\x80\x3f\xb2\x8c\x24\x49\xc8\x93\ -\x58\xef\xc2\x8e\x03\xa6\x46\xfc\x98\x0a\x4d\x45\x39\xdc\x79\xd1\ -\xca\xaf\x34\x4d\x51\x79\x4e\x98\x8e\x51\xe5\xc2\x92\xe7\x39\xa4\ -\x19\xde\xf4\x0c\x45\x91\x71\xb0\xb3\x4d\xc5\xc8\x51\x69\x4e\xe0\ -\xf9\x1c\x84\xd0\xec\x74\x19\x0c\x43\x7e\xff\x0b\x5f\x64\xe5\xf6\ -\x5d\xce\x9f\xbf\xc0\xd6\x9d\x15\x3e\xf0\xe1\x8f\x62\x2a\xc9\x5c\ -\xbb\xc9\x7c\xc3\xe6\xc8\x54\x97\xc0\xd0\xa7\xd0\x28\x1a\x61\x7b\ -\x0e\x58\x16\xa6\x29\x28\xc4\x61\x4c\xb9\x39\xa9\x18\xf3\xcf\x62\ -\x68\x7d\x2f\x8f\xd6\x6f\x1b\xe4\x8c\x77\xec\xd1\xaa\x50\xe5\x2f\ -\xae\x45\xfb\x79\x9e\x93\x15\x99\x4e\xda\x91\x92\x20\x4f\x8f\x27\ -\xb2\xf7\x99\x6e\xb5\x2d\xde\x7d\xf1\x6c\x71\xf0\x97\x3e\xca\xdf\ -\xf9\x47\xff\x18\xe5\x38\x44\xe4\x3a\x7f\xb8\x37\xa0\x77\x30\xa0\ -\x32\xb7\x48\x67\x7e\x89\x68\x38\x40\xa5\x09\xb2\x37\xa4\x7b\xa4\ -\xc6\x8f\xbf\xff\xdd\x9c\x39\xd2\x66\xa9\xa1\xe7\xa2\xef\x7b\xf4\ -\x3e\x3a\x64\x7c\xf9\xf7\x3f\xc7\xb9\x53\xc7\xf1\x6d\x8b\x90\xf9\ -\x2c\x08\x00\x00\x20\x00\x49\x44\x41\x54\x13\xc7\x4f\x61\xb9\x75\ -\x06\xc3\x90\x6b\x2b\x6b\xe4\x85\xc9\xd2\x91\x45\x3a\x9d\x3a\xa3\ -\x51\x42\x18\x86\xd4\x6a\x35\x1e\x7a\xe8\x41\x84\x80\xed\xed\x5d\ -\x6e\xdc\xb8\xc1\xc6\xc6\x86\x16\x82\xb4\xdb\x58\x96\x45\x14\x69\ -\x14\x8f\xef\xfb\xd4\xeb\x15\x0a\x0b\x82\xaa\x8f\xe5\x18\xa8\x58\ -\xb3\xa4\x2c\xc3\xc4\x32\x1d\x84\x00\x99\xe6\xba\xe1\x55\x80\x65\ -\x3a\x54\x02\x07\xc3\x9a\x2e\x49\x2b\x8a\x34\x8b\x38\xbe\x38\x8b\ -\x5d\x3a\xaf\x7a\x7b\x3d\xd6\xaf\xdf\xc0\x92\x12\xd7\xb4\x79\xed\ -\x85\x97\x08\x43\x9d\x82\xe1\x38\x0e\x52\x41\xa3\xd1\xa2\x00\x0e\ -\xb6\xfb\x24\xd3\x31\x63\xd9\x67\xd8\x1b\xa2\xc6\x19\x79\xa1\x85\ -\x2b\x8e\xeb\x63\x55\x6c\x6a\x4e\xc0\xd0\xf4\xb1\x72\x8b\x22\x82\ -\xa4\x28\x48\xa2\x50\x8b\x2a\x92\x94\x9d\xdd\x0d\xcd\x8a\x76\x1d\ -\x42\xa5\xb8\xbb\xb7\x47\x54\x40\x96\x25\x24\xe3\x90\x7a\x10\xa0\ -\x94\x06\xd0\x0f\xd7\x0a\xf6\xa5\xe0\x7f\xf9\xd4\xff\xce\xfe\x68\ -\x8c\x31\xbb\x40\xe3\xc8\x22\x99\xd0\x19\x4d\x7a\x3e\xab\x3b\xff\ -\x87\x5a\xeb\x34\x4d\x49\x8b\x42\x47\xc0\x9a\xc6\xdb\xe2\xa1\xf2\ -\xfb\x3d\xd7\x25\xcf\x33\xf2\x54\x4e\xa2\x43\xf3\x3c\x47\x26\xb2\ -\x24\x72\xea\xee\xb5\x21\xd0\x81\x80\x59\x79\x35\x10\x42\x8f\xbb\ -\xfc\x80\xa2\xc4\xea\x16\xa9\x7c\x87\xd8\xa3\x28\x49\xb0\x71\x14\ -\xe9\x62\x19\x8f\x89\xcb\xb1\x95\xe3\x38\x50\xaf\x63\x09\x13\xcf\ -\x73\x88\xc7\x11\xf1\x70\x80\xe7\xb8\xa4\x51\xca\xad\xeb\xeb\x9c\ -\x3d\x3d\xcf\xd4\x4c\x95\xff\xfe\x7f\x7e\x96\x24\xcd\xb8\x7d\x6b\ -\x85\x5f\xfc\x2b\x3f\xcb\x74\xb3\xc1\xe0\xe6\x2d\xec\x9a\xc7\xc3\ -\xf7\x5d\x14\x35\xcf\x28\x25\xc5\x19\xae\x69\x4c\xba\xec\xa6\xa5\ -\xe7\xc4\x1a\x57\xa4\x2b\xc2\xfc\xfe\x6c\x76\x19\x93\x92\x3d\xdc\ -\x81\xc5\x3d\x5f\x11\x80\x5d\xae\x88\x45\xae\xca\xd1\x00\x58\xc2\ -\xa0\x40\xcf\xef\x84\xe9\xde\x34\xd3\x0c\x93\x02\x1f\xc4\x33\x4f\ -\x3e\x52\x98\x5e\x8d\xbf\xf3\xa9\x4f\x63\x17\x36\x0b\x0b\x47\xd8\ -\x1a\x8e\xe9\xef\xf4\xc8\xc2\x21\x8e\x51\xd5\x0b\xb1\x57\xc5\x98\ -\x9e\xe2\xad\x97\x9e\xe3\xe0\x07\x2e\x62\x2d\xb7\x89\x12\xa8\x2a\ -\x28\x24\x4c\x35\x1a\xb4\x4e\x9f\x61\xa6\xd5\xe0\xee\xfa\x2a\x6f\ -\xbc\xf1\x06\x4a\x18\x1c\x3d\x76\x82\xf9\x85\x05\x46\xe3\x84\x17\ -\x5f\x79\x99\x7a\xbd\x8e\xeb\xba\x34\x9b\x2e\x79\x0e\xe3\x71\x56\ -\x7a\x8e\x3d\x96\x97\x97\x69\xb5\x5a\xd8\xb6\xcd\x8d\x1b\x37\x48\ -\xd3\x94\xe9\xe9\x69\x9a\xcd\x66\xb9\x53\xc3\x38\x0a\x89\xc3\x08\ -\xa5\x34\xa0\xce\x28\x45\x31\xb9\xd4\x05\xec\x38\xf6\xe4\x48\x98\ -\xab\x8c\x4c\x1d\x4a\x13\xb5\x78\xc1\x34\x1c\x8a\x3c\x23\x8d\x62\ -\x2c\xc3\xa4\x59\x6f\xb0\xbc\x74\x84\xe3\x47\x8f\x21\x84\xc9\x99\ -\x53\xc7\x18\x0c\x12\xed\x7c\x92\x10\x96\xc6\xfa\xcd\xed\x5d\x6a\ -\x41\x4d\xbf\xfd\x4a\x50\xe4\x05\x69\x9c\x30\x1c\x8e\x89\xe2\x98\ -\x24\xc9\x30\x6c\x0b\x4b\x18\xdc\xb9\x73\x07\x21\x04\xd3\xdd\x29\ -\x2c\x5b\x8b\x61\x5c\xd7\xc5\x2a\x04\x4b\x33\x73\x78\x05\xe0\x79\ -\x18\xe3\x21\xee\x48\x87\x6d\x37\x9b\x75\xec\x79\x93\x38\x4c\x98\ -\x9e\x9d\x21\x92\x05\xd5\xc2\xe0\xb9\x2f\x7d\x85\x13\xa7\x8e\xb3\ -\x7f\xe9\x35\x4e\x1c\x3d\xca\x5b\xeb\x1b\xe0\xf8\x65\x24\x8b\x55\ -\xfa\xa2\x45\x79\x3a\x13\x64\x59\x0e\x99\xa2\xc8\x0e\x4f\x2b\x05\ -\x86\x29\xb4\x54\xd1\x10\xc8\xb4\x14\x7c\xc8\xfc\x9d\x63\x4c\x53\ -\xff\x37\x8d\x62\xc8\xa4\x26\x94\x94\x3c\x63\xcf\x0d\x50\xae\x8f\ -\xeb\x7b\x0c\x93\x94\x42\x28\x6d\xe1\x54\x4a\x53\x4e\x00\xdb\x34\ -\xb1\x6c\x87\x70\x77\x1b\x54\x8e\xd5\xea\x20\x5d\x89\xe7\x55\x88\ -\x2b\x01\x96\xa3\x39\xd7\x2a\x1c\xe3\x5b\x3e\xf1\x78\x8c\x99\xa5\ -\x7c\xe4\x43\x3f\xc6\x27\x3e\xf2\x24\xfd\xbd\x02\xc3\x83\x95\x3b\ -\x23\xd2\x7c\x8c\x67\x2a\x9e\x7a\xe8\x01\xde\xfd\xf0\xfd\x7c\xeb\ -\x0b\x5f\xe4\x3f\x7d\xe6\xfd\xf8\x59\x46\xd5\xb3\xc8\x93\x18\x25\ -\x73\xec\xc0\xc5\xf0\x74\x86\x78\x12\x85\xb8\x41\xf0\x27\xcc\x88\ -\xc6\xff\x7f\x83\xd3\xbf\xed\x1d\xd9\x98\xfc\x3e\xe6\x77\x80\x93\ -\x88\xf2\x6e\xf2\xed\xfb\x77\x81\x81\x30\x5d\x90\x19\x76\x7d\xea\ -\xd1\x54\x15\xa4\x49\xf4\x99\x86\xef\x3f\xf3\xcc\x43\xa7\xbf\x90\ -\xfc\xf4\xc7\xf9\x27\xbf\xf3\x39\xae\xbd\xfa\x2c\xed\xd9\x45\x3a\ -\x73\x2d\x56\xb6\x36\xc8\xcd\x59\x1a\xf5\x06\xc3\x28\x25\x03\xac\ -\x76\x9d\xe7\x5f\xf8\x06\xa7\x16\xa7\xe8\x2c\xcf\x52\xf7\xa1\xbf\ -\x3e\x62\x71\x66\x81\xcb\x97\x5e\xa2\x75\xfc\x24\xb5\x66\x87\x5c\ -\x29\x6e\xdc\xbe\xcd\xf3\x97\x5e\xa5\xd9\xee\x72\xe2\xd4\x49\x94\ -\xa1\x05\x0c\x9a\x67\x5c\x10\x04\x2e\xb6\xad\xb5\xbf\x42\x68\xde\ -\xb5\xe7\x79\x74\xbb\x5d\x96\x96\xe6\xd9\xde\xde\x23\x4d\xb5\xa7\ -\xf5\xd6\xad\x5b\x38\x8e\x43\xa5\x5a\x45\x48\x48\xc7\x89\xa6\x60\ -\x94\x4e\x9d\x24\x4f\x68\xd6\x5c\xc2\x30\xc7\xb4\x4d\xc6\x51\x4c\ -\x61\x50\x46\xb7\x0a\x94\x84\x38\xd3\xfa\xef\xb4\x14\x32\x98\xa6\ -\x45\x18\x86\x24\xa9\x44\xe6\x05\x4a\x49\x84\xe1\x60\x39\x36\x85\ -\x80\x34\x4f\xf1\x2a\x0e\x96\x65\x70\xc4\x9f\x65\xe5\xf6\x35\x96\ -\x8e\x2f\xe3\x79\xe0\xd5\xab\xd4\x6a\x3e\x7a\x24\xab\x77\x36\xdb\ -\xb5\xc9\x92\x8c\xf6\x54\x13\xdb\xb6\x99\x99\x99\x29\x01\x01\xaa\ -\x1c\xdb\xe4\x58\xc2\x24\xcd\x73\x5c\xd7\xa4\x41\x85\x5e\x7f\x9b\ -\xa3\xd3\x6d\x82\x20\xd0\xcd\xa0\x05\x83\xad\x83\x90\x1c\x83\x4e\ -\xd7\xe6\xe9\x0f\xbc\x07\x51\xf3\x79\xfe\x8d\x57\xc8\xc2\x1e\x2d\ -\xdf\x23\xcc\x15\x8e\x65\x12\x4b\x89\xe9\xfa\x28\x59\xe0\xd8\x1e\ -\xe3\xd1\x88\x5a\xa5\xce\x60\xb0\x45\x1a\x26\xd4\x1a\x7a\xde\x9c\ -\x8a\x8c\x3c\x8f\xb1\x6d\x0f\x15\x67\x38\xa6\x43\x96\xa5\x50\xe8\ -\x58\x17\xd2\x54\x0f\xc3\x6d\x17\x61\x9a\xd4\x1b\x4d\x92\x48\x47\ -\xe5\xc6\xa9\xc4\xb4\x5c\x54\x2e\x19\xc7\x19\x96\xef\xa0\x04\x58\ -\x4a\x10\xed\xf7\x08\xbc\x0a\xc2\x71\x19\x0f\x43\x54\x3e\xc4\xf2\ -\x2b\xd8\xbe\x8b\xe5\x78\x48\xdb\x26\x1a\x8e\xa1\x52\x63\x77\x6f\ -\x9f\x86\x67\x53\xc9\x63\xa2\x3b\xeb\x78\x22\xe7\xe8\xd1\x45\x7e\ -\xe8\xe9\x27\x19\x4b\xa8\x77\x04\x97\xef\xec\xf0\xa9\x4f\xfd\x6f\ -\x4c\xcd\xd4\xe8\xd4\x2a\x3c\x7a\x7a\x91\x8d\xd7\x2f\x71\xb2\x55\ -\x81\xc1\x80\x99\xd9\xba\x28\x14\x98\xb6\x8b\xe9\x94\xb1\x16\x7a\ -\xc6\x86\x1b\xd4\xde\xb1\xa1\xbd\xad\x7b\xfc\xff\x84\xe0\xfa\x1e\ -\x0b\x42\xfe\x0d\x8a\x7f\xb2\x4e\x99\xba\x99\x21\x93\x04\x23\x53\ -\x7f\xe8\x78\xfc\x61\x53\x20\xde\xf3\xe0\x7d\x45\xa7\x1e\xf0\x0f\ -\xff\xe9\x67\xb8\xb5\xbb\x43\x32\x1a\xe2\xe5\x06\x79\x7f\x8f\xed\ -\xb5\x55\x9c\xe9\x79\x16\xe7\xa6\x89\x44\x9f\xb5\xd5\xdb\x54\x5c\ -\x97\x57\x5e\x78\x95\x93\x53\x33\x5c\x3c\x39\x83\x0c\x15\x9b\x1b\ -\xdb\xc8\x07\x04\x79\x51\x10\x65\x19\x67\xcf\x9f\x23\xc9\x0a\xde\ -\xbc\x76\x95\x17\x5f\xbe\xc4\xea\xea\x2a\x17\xce\x9d\xc7\xf7\x3c\ -\x1c\xc7\xc4\xb2\x20\x8a\x52\xdd\x24\xf2\xb4\x32\x6a\x75\x75\x95\ -\x99\x99\x19\xd2\x54\xd3\x38\x0f\x8b\xbc\xd7\xd3\x88\xdc\xbd\xbd\ -\x3d\x36\xd6\xd7\x79\xf5\xd2\x25\xaa\xd5\x2a\xad\x56\x8b\xa9\xa9\ -\x29\x8a\xa2\xa0\x37\xd4\x99\xbf\xae\x63\xe3\x5a\x5a\x11\xe6\x7a\ -\xda\xf8\xaf\xdf\x30\x87\xa2\x10\x7a\x37\x11\x06\x4a\x18\xfa\xbe\ -\x69\xea\xbc\x62\xa1\x14\x51\x39\xd6\xb1\x6d\x5b\x87\x8d\x95\xa1\ -\x63\xb6\x63\x50\x6f\xd4\x18\x8e\x46\x18\x66\x15\x55\x14\xc8\x1c\ -\x9d\x77\x04\x28\xf4\x38\x46\x94\x30\x7a\x0c\x10\xa6\x40\xdc\xc3\ -\x91\x50\x80\xb2\xa1\xc8\x34\x20\x20\x4f\x25\x79\x16\x63\x15\x0a\ -\x53\x65\xe4\x0a\x72\xc3\x63\xb6\x13\xd0\x97\x30\x4e\xa0\x53\x37\ -\xf9\xe0\x7b\x7f\x80\x57\x5f\x7d\x95\xb5\xdd\x3d\xea\xd5\x2e\x9e\ -\x6d\x31\x4a\x63\xad\xbc\xeb\x1d\x60\x56\x1b\xa4\xb9\x16\x76\xe4\ -\xb2\x40\xb8\x2e\xbe\xe3\x92\x25\xa9\xb6\x89\xda\x0a\xf2\x88\x38\ -\x4b\x21\x2c\x50\x86\xd4\x56\x4b\xd7\x06\xd7\x05\xdb\xc6\x0c\x02\ -\x5c\xdb\x26\x1a\x8c\xb5\xb8\xa4\xd0\xd1\xb2\x18\x16\x42\x68\xe1\ -\x89\x21\x72\xd2\x41\x0f\x3c\x1b\xd7\x0e\xc0\x30\x08\xf7\xf7\x20\ -\x95\xd8\xb5\x26\x6e\xbd\x42\xa5\x5a\x65\xfb\x60\x4f\x77\xc3\x95\ -\x82\xfe\x3e\x4e\xa7\xcb\xd4\x4c\x97\xdd\x5b\x37\xe8\x5a\x05\x99\ -\x8c\xf8\xe5\x5f\xfe\x65\x2e\x5f\x79\x95\x6e\x45\xcf\x7f\x9f\x7d\ -\xfe\x75\x3e\xf7\xbb\xff\x8a\x8d\xbb\x2b\xcc\xb4\x1b\x9c\x98\x3f\ -\xca\x68\x73\x8d\x46\xab\xc1\x33\xef\x7d\x42\x38\x39\xa8\xa4\xc0\ -\xb0\x85\x9e\x17\x0b\xee\x69\xf8\xde\x8b\xe8\xf9\x77\x33\x4b\xb6\ -\xf8\x5e\xbe\x0e\x29\x90\x32\xc7\x36\x04\x56\xe0\x7c\x4a\x08\xc8\ -\x80\x85\x66\xf5\x44\xfb\xe1\x73\x37\xaa\x8d\xbf\xc6\x3f\xfc\xc7\ -\x9f\xe1\xc8\xb9\x8b\x6c\x0e\x23\xfe\xf0\xeb\xcf\x31\x7f\x6c\x99\ -\xbb\x3b\x7b\xec\xde\xdc\x67\xb1\xeb\xb3\xbb\xbd\xc6\xb1\x23\x2d\ -\xce\xcc\xb4\xd8\x59\xb9\xcb\x37\x9e\x7d\x05\x5f\x18\xb4\x3a\x6d\ -\xcd\x6c\x72\x03\xd2\x50\x6b\xa0\xa3\x24\xe6\xc2\xfd\xf7\x01\xb0\ -\xb7\xbd\xcb\xa5\x57\x5e\x99\x14\x6d\xa7\xd3\xa1\x5e\xaf\x53\xab\ -\x55\xf0\x5d\x88\xe3\x80\x34\x4d\x69\x37\x5d\x46\x61\x81\x65\x99\ -\xa4\xa9\x76\xd0\xd8\xb6\x8d\xef\xfb\xd8\xb6\xcd\x7d\xf7\xdd\xc7\ -\x85\x0b\x17\x88\xe3\x98\x3b\x77\xee\xb0\xb6\xb6\xa6\x3b\xa8\xe5\ -\x0e\x5d\xaf\xd7\xf1\x7d\x9f\xfd\xfd\x7d\x86\xc3\x50\x6b\x89\x4b\ -\xbf\xb3\xeb\x9a\x28\x65\x95\x42\x09\x26\x23\x92\xc3\x66\x4d\x10\ -\xd8\x24\x89\x0e\xcf\xcb\x73\x3d\x5e\x39\x3c\x5e\x1f\x92\x42\x5b\ -\xad\x2a\xae\xeb\x62\xdb\xa0\x94\x81\x65\x09\x2c\x4b\x57\x6c\x5a\ -\x62\x76\x0e\xff\x1c\x76\xbd\x0f\x1b\x48\x52\x52\x36\x92\x8a\x49\ -\x38\x9d\xe3\xba\xf8\xbe\x47\x9c\xa6\x84\xe1\x08\xcf\xd0\xa7\x0e\ -\x5b\x23\x65\xa8\xfb\xf0\x9e\x8b\x0f\x80\x57\xe5\x73\x5f\x7e\x96\ -\x3c\x4d\x90\x51\x48\xad\xd5\x26\x75\x5d\xfc\x6a\x85\xf1\x38\xc1\ -\xb4\x6d\xc6\xdb\x7b\x90\xa5\x48\xc7\x22\xcd\x13\xf2\x3c\x84\xaa\ -\xab\x3b\xcd\x0a\x44\xd9\xf8\xd4\xf8\x12\x07\xdb\xf3\xc8\xa4\x9c\ -\xfc\x7e\x87\x31\x45\x13\x8d\x74\x99\x06\xa2\xd0\x6c\x6f\xdb\x75\ -\xc9\x46\x3d\xc6\xb1\xb6\xb7\x52\x40\x63\x66\x1a\xd3\x76\xf4\xe8\ -\x2b\x2c\x38\xb2\xb8\xc0\xca\xeb\xaf\x32\x7f\xf2\x04\x61\x34\x86\ -\xc8\x61\xfb\xc6\x1e\x81\x92\x14\x99\xe4\x6f\xfe\xc2\x7f\x41\x2b\ -\xf0\xf8\xc1\x47\x1f\x26\x0f\xe1\xf2\x95\x37\xb9\xfc\xdc\x0b\xa8\ -\xfe\x90\x8e\xeb\xf3\x9e\x87\x1f\xe3\xbe\xa3\x47\x98\xab\xd5\x39\ -\x3d\xbf\xa4\xd7\xc5\x12\xb2\xcf\xbf\xb5\x5b\xef\xbf\x4f\x85\x5c\ -\x02\xd6\x85\xd0\x90\xb5\x43\xba\xa2\x94\x92\x42\x18\xc7\x1d\xcb\ -\xfa\xbb\x8f\x9f\x58\x38\xde\xfd\x2f\x7f\xf1\x13\x5f\xfc\xe6\xf3\ -\x3c\xfe\xf0\x43\xcc\x76\x9a\x5c\xbf\xbd\x4e\xa0\x52\xb6\x77\x36\ -\xb9\xf6\xd2\x65\x4e\x2d\x2d\x72\xf3\x8d\x35\xde\x75\x61\x91\xda\ -\xf2\x02\xe6\xc2\x3c\xe1\xa0\xcf\xd7\xbe\xfa\x15\xbe\xf0\xa5\x3f\ -\xe6\xe9\x0f\xbc\x8f\x24\xcb\x10\xa9\xc4\xb1\x3d\xa2\x48\x91\xc6\ -\x29\x8f\x3f\xfa\x18\xe3\x70\x44\xab\xd5\x9a\x1c\x99\xd7\xd6\xd6\ -\x70\x1c\x87\x63\xc7\x8e\x51\xad\x56\xe9\xf5\x7a\xc8\xd2\xd2\x58\ -\xaf\xd7\xf4\x83\x5e\x0a\xf0\x6d\x1b\x92\x44\x3f\x60\x4a\x29\xa6\ -\xa7\xeb\x34\x1a\xf7\x97\x7c\xec\x5c\xab\x9a\xca\x07\xef\xe0\xe0\ -\x80\xeb\xd7\xaf\xd3\x68\x34\xf0\x3c\x8f\x76\xbb\x5d\x12\x3a\xdb\ -\x13\xb3\x7d\x9e\x97\xb2\xc4\xb2\x33\xab\x95\x4b\x7a\x31\x39\x4c\ -\x2e\xd4\x70\x02\x81\xeb\x3a\xcc\xce\xce\xb2\xbb\xbb\x4b\xbd\x5e\ -\x9f\x14\xa7\x4e\xd4\x70\x27\x5d\xde\xc3\xd4\xc5\xc3\x6c\x26\x2d\ -\xb0\x30\xb5\xa4\x11\x03\xd3\x82\xa2\x30\x27\x4c\x68\x59\xce\x6f\ -\x93\x2c\x63\x34\x1a\xe1\xd8\x9e\xf6\x87\x0b\x41\xcd\x77\x19\xc5\ -\x90\x45\x70\xa4\xde\xe4\xb1\xa7\xce\xf0\xd4\x63\xe7\xf9\xe6\xe5\ -\x0d\xbe\xf2\xc2\x73\xac\x6c\xef\x90\x64\xb0\x17\x86\xa8\x34\xd7\ -\x0c\xb0\x22\x83\x5c\x92\xa9\x5c\xdb\x17\x2d\x07\xdb\xf6\x90\x86\ -\xc4\x14\x16\xae\x6d\x60\xe4\x82\x34\x4d\x30\x4b\x59\xac\x54\x7a\ -\x02\x50\xe4\x39\x6e\x99\xc2\x71\x28\xdf\x44\x69\x53\x88\x9e\x0c\ -\xa4\x28\x2b\x03\x61\x60\x57\x2b\x04\x6e\x95\xfe\xdd\x4d\xf2\xa2\ -\xc0\x77\x9c\x92\x75\x56\xb0\xf2\xd6\x35\x66\x8e\x2e\xb1\x7e\xf3\ -\x2d\x82\x46\x95\xb4\xb7\x87\x55\x28\x7e\xf8\xe9\xf7\xf1\x33\x1f\ -\x7e\x3f\x75\x17\x9e\xfd\xda\x25\x1e\xb8\x78\x3f\xaf\x3d\xfb\x1c\ -\xf3\x73\xb3\x58\x61\xc4\x2b\x5f\xff\x1a\x3f\xf7\x57\xff\x33\x3e\ -\xf0\xf8\xe3\x2c\x74\x3b\x1c\x69\x35\x45\x0d\xd8\xdb\xdc\xa3\x53\ -\xa9\xe1\x04\x4e\xd9\xc4\x12\xff\x81\x17\xb2\x50\x60\x1b\x1a\xf6\ -\x27\x25\x59\x92\xa1\x0c\x81\x6f\x3b\x60\x9a\x7f\x98\xc1\x1f\xf6\ -\xe2\xb4\x38\xd5\xf2\x9e\xe9\x7e\xe8\xdd\x5f\xf8\xe6\x2b\x57\x99\ -\xb5\x61\xf6\xec\x31\xce\xfd\xf4\xc7\xf8\x8d\xff\xf3\xff\x20\x9a\ -\xed\x72\xf2\xc4\x31\xde\x7c\xe9\x65\x2e\x2c\x2d\x52\xa4\x29\x33\ -\x1d\x87\x8a\xdf\xe4\x43\x3f\xfe\x63\xfc\xde\x17\x7e\x8f\x6f\x3e\ -\xf7\x02\x8d\x56\x93\xa5\xa5\x25\x06\xfd\x11\x0b\x73\xb3\xb4\x3a\ -\x1e\x2b\x77\xb4\xb8\xc2\xf3\xf4\x1c\xb7\xd9\xd4\xdf\x33\x1c\x0e\ -\xd9\xdb\xdb\xe3\x8d\x37\xde\xe0\xe0\xe0\x80\x30\x3c\x1c\x3f\x41\ -\x18\xe6\x44\x51\x8c\x69\x9a\x14\x85\x31\x71\xf8\x68\xe2\x26\xc4\ -\xb1\x6e\xde\xd4\x6a\x3e\x8e\xd3\x64\x30\x18\x53\xa9\x54\x68\x34\ -\x1a\x5c\xb8\x70\x81\x73\xe7\xce\x31\x1e\x8f\x19\x0e\x87\x6c\x6f\ -\x6f\x73\xe9\xd2\x25\x2d\xdc\xa8\x56\x69\xb7\xdb\x93\x22\xac\x54\ -\x5c\x2c\xcb\x2d\x77\x4c\x67\x52\xa8\x3a\x27\xad\xc0\x30\xa0\x56\ -\xab\xb1\xbb\xb7\x37\x31\x1a\xd8\xb6\x81\x94\x16\xb6\x7d\x98\xbd\ -\x64\x6a\x43\xbf\x94\x93\x42\x50\xca\x98\x40\x08\x32\x95\x93\xa4\ -\x46\x39\x7f\x35\x11\x96\x89\xe3\xb9\x78\x95\x80\xc0\x85\xa2\x08\ -\xb0\x2c\x07\xc7\xd6\x9a\xf1\x2c\x87\x8a\x02\xcb\x81\x5a\xae\xc8\ -\xf6\xa0\x88\x24\x2d\x14\xb3\x81\xcf\xf3\xb7\x6f\x21\x6a\x75\x54\ -\xae\x70\xba\xb3\x64\x39\x78\x7e\x93\xa8\xd7\xc7\xb2\x6d\x1c\xd7\ -\x47\x0a\x45\x61\x42\x8e\xc0\xb2\x6c\xed\x6f\x2e\xb4\xd6\xdc\x10\ -\xd6\x64\xd1\x11\xa5\x83\x2e\xcb\x32\x72\x95\xe9\x48\xd9\x2c\xd6\ -\x9a\x04\xa5\x34\x1a\x0a\x03\xcf\xb4\x11\xe4\xb8\x96\x8b\x6b\x5b\ -\xf4\xcb\x39\x74\x9c\x26\x8c\xc2\x10\xd7\x73\xc0\x54\x6c\xdd\xb8\ -\xc6\xd4\x54\x97\xbd\x3b\x2b\x1c\xe9\xb6\xf8\xf0\x33\x1f\xe4\x07\ -\x1f\x7a\x90\xfe\xe6\x0e\xad\xf9\x29\x56\xae\xbc\xc6\xd9\xe5\x79\ -\xde\xff\xd8\xe3\xfc\xb3\xdf\xfc\xbf\xb8\xf9\xd2\x8b\x7c\xf9\xb3\ -\x9f\xe5\xfa\xb5\x37\x99\xab\xd6\x38\xd9\x6a\x8a\x28\x8c\xc0\xf5\ -\x99\x9b\xe9\x90\x1c\x0c\xa0\xd0\x93\x89\xe2\x3f\xee\xc8\xdf\x4e\ -\x14\x2b\x70\x0c\x9d\x39\x04\x39\x32\x53\x54\x2d\x21\x0c\xc0\xcf\ -\x14\xef\xba\xff\x0c\xf9\x70\x48\xad\xd5\xe2\x8f\xff\x9f\xdf\xe2\ -\x17\xff\x93\x9f\x22\x8c\x52\xe6\xe6\xa6\x78\xe1\xd9\x17\xb9\xf4\ -\xfc\x4b\xf8\x8e\xc1\xc2\xbb\x1f\x64\xb7\x37\xc6\xab\x04\x5c\x78\ -\xe0\x22\x85\x10\x0c\x87\x43\xde\xbc\x76\x9d\x99\xee\x34\x45\x01\ -\x6b\x6b\x03\x50\x05\xb7\x6f\xae\x50\xaf\xd7\x69\xb5\xaa\xc8\x12\ -\x83\x6b\x59\x16\xcb\xcb\xcb\x9c\x3a\x75\x8c\x9d\x9d\x1d\x2e\x5f\ -\xbe\x4c\xaf\xd7\x63\x7e\x7e\x9e\x56\xab\xc5\xcc\x4c\x9b\x2c\x83\ -\x5e\x6f\x34\x09\x40\xdf\xde\xde\xa6\xd9\x6c\xd2\x6a\x35\x28\x0a\ -\x3d\x16\x1d\x8d\x46\xd4\x6a\xd5\x52\x81\xf4\xb6\xfc\xd3\xf7\x7d\ -\xa6\xa7\xa7\xc8\x32\x49\xb5\x6a\x31\x1e\x6b\xab\x63\x14\x45\x6c\ -\x6d\x6d\x71\xf9\xf2\x65\x54\xb9\xf3\x54\x2a\x95\xc9\x6e\x6c\xdb\ -\x36\xed\x76\xbb\x44\xf4\x36\x27\x47\xe1\xc3\x42\x35\x8c\x72\xbc\ -\x57\x36\xd4\x8a\x72\xec\xe3\x38\xda\x5a\xa8\x77\x67\x90\x52\x23\ -\x8c\x8d\xdc\xc0\xf5\x0d\xca\x08\x29\x64\x22\x88\xc2\x84\xed\xdd\ -\x2d\x6d\x07\x1c\x0f\xd8\xde\xd8\xd6\x86\x92\x4c\x51\x28\x41\x96\ -\x49\x3c\xc7\xe7\xf5\xe7\x5e\x26\x1a\x0e\x99\x3b\x71\x8a\x87\x8e\ -\x2f\xb0\x30\x3f\xcd\xf6\xee\x16\x3d\x61\xb0\xb2\xb3\x87\xe7\x3b\ -\xec\xf7\x47\x08\xc7\xd5\xa9\x15\x86\x40\x98\x36\x26\xb9\xa6\x97\ -\xc8\x4c\x07\xd8\x61\x92\x17\x72\x92\xe2\x98\xe7\x3a\xca\xf4\x30\ -\x3d\x22\x8b\x63\x90\x4a\x1b\xf0\x33\x89\x19\x78\x18\x96\x85\x17\ -\xf8\xa8\xdc\xa2\xe6\x16\xc4\xd1\x98\x24\x8a\xb5\xa7\xd9\xd1\x09\ -\x1e\xe3\x28\x42\xee\xee\x50\x74\x3b\x04\xbe\x87\xcc\x33\x76\x6e\ -\xbe\xc5\xbb\x1e\x7b\x08\x3b\x0e\x79\xcf\x03\xe7\xf0\x54\xcc\xee\ -\xb8\xc7\xbf\xfc\xed\x2f\xf1\x5f\xff\x8d\x9f\x21\x0d\xc1\x90\x39\ -\xfd\xbb\xeb\xfc\xed\xbf\xf9\x37\xf8\xd2\x67\x3f\xcb\x8f\xfe\xe8\ -\x87\x98\xef\x76\x0e\x4c\xc0\x46\x61\x93\xeb\x50\xc3\xaa\xaf\xc7\ -\x23\xc2\xf8\x8f\x47\x6b\x0a\x43\x8f\x1d\x4c\x3d\x8f\xb1\xbd\xb2\ -\x6b\x50\xe8\xfc\xdc\x3c\x49\x09\x82\x0a\xa3\x30\xa4\x1d\x04\xa2\ -\x17\xa5\xc5\x7b\x1f\xba\xc8\xef\xff\xc1\x17\x78\xfa\xe1\x0b\xbc\ -\xf0\x47\x7f\xc0\xb1\x53\xf7\xb3\x97\xe6\x9c\x3f\x7e\x8c\x34\x8e\ -\x08\x7c\x97\x6f\x3e\x7b\x89\xd1\x68\xc8\xc5\x47\x1e\xa0\xd5\xe9\ -\xf0\xfa\xe5\x37\x78\xea\xa9\xc7\xb0\x81\xab\x57\x57\x79\xf1\xf9\ -\x17\xc9\x93\x9c\xb9\xb9\x19\xed\x9d\x2d\x0a\xd2\xb4\xc0\xb6\x05\ -\xdd\xb6\x4f\x2a\x7d\x92\x44\x71\x70\x30\xe4\xf8\xf1\xe3\x2c\x2f\ -\x2f\x53\xab\xd5\xe8\xf7\xfb\x5c\xb9\x72\x85\x57\x5f\x8d\x69\x34\ -\x1a\xb4\x5a\x2d\x94\x52\x74\x3a\x1d\xa6\xa6\xa6\xf0\x3c\x1b\xdb\ -\x86\xdd\xdd\x91\xce\xc9\xad\x56\x49\x92\xb4\x4c\xa7\xb0\x71\xcb\ -\xa0\xf1\xc3\x48\xd6\x34\x4d\x89\x22\x73\x62\xf7\xab\x56\x2b\xd4\ -\x6a\x35\xd2\x34\xe5\x91\x47\x1e\x42\x29\x26\xc7\xea\x43\xc9\xa8\ -\x65\x59\x0c\x87\x43\x36\x37\x37\x19\x0c\x06\x5c\xbf\x71\x83\xfd\ -\xfd\x7d\x94\x52\xf8\xbe\x4f\x14\x45\x13\x99\xe3\xe1\x1c\x77\x7d\ -\x7d\x7d\x42\x01\x3d\x64\x72\x1f\x76\xad\x8b\x5c\x94\x8e\x2f\x17\ -\x61\x0a\xae\x5e\xbd\x8a\xe5\x19\x34\xaa\x35\x40\x71\xfa\xec\x69\ -\x0a\xa5\xa3\x6c\x02\xaf\x42\x1a\xeb\xa4\xc4\x3c\x4e\x79\xd7\x7b\ -\x1e\x65\x7d\x27\xa1\x5a\x83\xa0\x66\xf3\xf0\xd9\xd3\xdc\xec\xf5\ -\xd8\xd8\xdb\x25\x8d\xc7\x34\x1a\x35\xfa\xbb\x7d\xc8\xf5\x9d\x57\ -\x4a\x89\x54\x39\x86\x6b\x62\x0a\x1b\x55\x72\xb7\x28\xc7\x4f\xb9\ -\x94\xa4\x71\x02\x51\x84\x32\x2c\x0a\xdb\xc6\xb2\x1d\x64\x91\x61\ -\x99\x26\x99\x61\xe0\xb8\x16\x0a\xb0\x2c\xdd\x1c\xec\xf7\x0f\xa8\ -\x04\x3e\xae\xe3\xb0\xbb\x77\x00\x69\xce\x70\xef\x00\x51\xab\x40\ -\x77\x0a\x61\x82\x92\x29\xcb\xf3\x33\x6c\x8d\x0f\x58\xea\xb4\xf9\ -\xe8\xd3\x3f\xc1\xca\xab\x97\xb8\x78\xf6\x24\xf7\x1d\x5d\x24\xed\ -\xef\xb2\xb5\xba\x83\x2f\x0c\xfe\xf9\x6f\xfd\x26\x9f\xfc\xc9\x0f\ -\xd3\xdf\xdb\xe3\x23\x1f\x7c\x3f\x4b\xb3\x5d\x11\xd8\x26\xe3\x38\ -\xa2\x19\xf8\x98\x28\x0e\xb6\xb7\x69\x75\xa6\xa0\x38\x84\x4e\x9a\ -\xff\xa1\x1f\xad\x01\xcb\x86\x43\x7f\x29\x3a\xd6\xe4\x70\x3c\x52\ -\xad\x56\x89\xc2\x90\x46\x50\x65\x1c\x27\xb4\x3d\x57\x14\x02\x7e\ -\xf6\x63\x3f\xc6\xf6\xc1\xb8\x78\xfd\x85\x17\x99\x0e\x5c\x0a\x25\ -\xc9\x86\x31\x6f\x5e\xb9\xc2\xc7\x3e\xfe\x21\x1a\xb5\x80\xc2\x82\ -\x97\x5e\xbd\x04\x96\xc9\x6e\x6f\x9f\x02\xd8\x1f\xea\x39\xf0\xf9\ -\x33\x4b\x6c\xaf\x8f\x51\x4a\xf2\x47\x5f\xfe\x12\x5e\xc5\xa7\xd3\ -\xe9\x4c\x76\xcb\x43\x1a\x48\xbd\x5e\x63\x6a\x6a\x8a\xfd\xfd\x7d\ -\x4c\xd3\xa4\x5e\xaf\xf3\xc4\x13\x4f\x60\x18\x82\xc1\x60\xc8\xce\ -\xce\x0e\xb7\x6e\xdd\x62\x7b\x7b\x1b\xc7\xd1\x77\xd6\x0b\x17\xce\ -\xd0\x68\x54\xc9\xb2\xb7\xad\x7c\x86\x21\xc8\x73\x7d\x67\x4d\xd3\ -\x12\xa5\x6b\xdb\xa5\x7a\x8c\x7b\xc8\x15\x45\xb9\xa3\x66\x24\x49\ -\x36\xb9\x7b\x07\x41\x30\x89\xab\xa9\xd7\xf5\xef\x58\x14\x05\xfd\ -\x7e\x9f\xf9\x85\x05\x16\x16\x16\x90\x52\x12\x04\x0e\x71\x2c\x27\ -\xcd\x21\xcb\x32\xc8\xf3\x82\xbb\x77\xef\xde\x53\xc8\xda\x39\x64\ -\x18\x06\xb9\x94\x04\xae\x45\x92\x28\x2c\xcb\x20\x53\x0a\xdb\x31\ -\x39\x7e\xe2\x24\x41\xcd\xc7\x34\x05\x32\xd5\x76\x43\xa1\xb4\x00\ -\xc3\x33\x0c\x2c\xc3\xc4\xb0\xa1\xdf\x8f\x69\xd7\x3c\x54\x0e\x15\ -\x07\xde\xf7\xe4\xe3\x4c\x6d\x6d\x73\x75\x75\x8d\x1b\x77\xb7\x68\ -\x2e\x04\xda\xa3\xe9\xea\x8e\x7d\x9c\x26\xc8\x54\xe2\xba\x0e\x86\ -\xa1\x25\xa2\x49\x9c\x91\x6b\xdc\x0a\x38\x16\x99\x65\x96\xba\x7c\ -\x7d\xcc\xae\x55\x02\xb2\x48\xfb\x96\x65\x9a\x95\x9d\x70\x2d\xfc\ -\x90\x52\xe2\x78\x01\x99\x94\x8c\xe2\x11\xf9\xfe\x00\xa6\x66\xb0\ -\x5d\x0f\x3f\x08\x34\xdd\x43\xa6\x34\xaa\x15\xf6\xb7\xb7\x78\xec\ -\xc1\x8b\x5c\x38\x75\x02\x5b\x26\x7c\xe4\x03\x4f\xb2\xb1\xba\xc9\ -\x5b\x97\x5f\x65\x69\xa6\xcd\xda\xad\x6b\xcc\xb7\xbb\x74\x6a\x3e\ -\x35\xdb\xe0\xf1\xf7\xbe\x5b\x78\x8e\xfe\x4c\xfa\xfd\x1e\xf5\x46\ -\x95\x2c\x8d\x48\x55\x4e\x6b\xba\x4b\x91\xa6\x88\x12\x12\xf0\xfd\ -\xf0\xfa\x73\x33\xbb\xfe\x62\x9a\xd7\x5a\xde\x57\x60\xe8\xd1\x82\ -\x69\x22\x0c\x13\x30\xb0\x6d\x07\x28\x74\xac\x46\xb9\xf6\x09\x20\ -\x70\x9d\x5f\x7d\xfc\xd1\x87\x7e\x35\xcf\xf8\x95\x2c\x4d\x98\xee\ -\xb4\x49\xc2\x31\x6b\xab\x6b\x54\x2b\x01\x9d\x4e\x8b\xb9\x85\x39\ -\x5a\x53\x6d\x6e\x5c\xbf\xc9\x95\xab\xd7\x39\x75\xf2\x24\xf5\x8a\ -\xa3\x9f\x2d\xc3\xa1\x12\x78\x2c\x2c\x1f\x61\xef\x40\xc7\xc7\x5c\ -\xb9\x72\x45\xab\x88\x0c\x03\xcf\xf3\xb0\x6d\x93\x3b\x77\xd6\xa8\ -\x54\x2a\xf7\xec\xaa\x06\x59\xa6\x0b\xa1\xd9\x6c\x4e\x9a\x57\xf5\ -\x7a\x9d\x24\x49\xb8\x7a\xf5\x3a\x2b\x2b\xb7\xd9\xde\xde\x66\x34\ -\x1a\x61\x9a\x26\x9d\x76\xc0\xfe\xc1\x90\x28\x8a\xe8\x74\x3a\x3a\ -\xbb\xb7\x94\xf0\xc5\x71\x3a\xe1\x69\x1f\xee\xd6\x9b\x9b\x9b\x2c\ -\x2d\x2d\x95\xa3\x2e\x31\x39\x3e\x3b\x8e\x43\x9e\x0b\x1c\x47\xab\ -\xbc\xc2\x30\x64\x30\x18\xd0\x68\x68\x82\x89\x65\x99\x1a\x2d\x7c\ -\x68\x3c\x50\xfa\xe7\x7a\xbd\x1e\x42\x08\x82\x52\xa0\x70\x78\x47\ -\x2e\x8a\x02\x13\x83\x42\x2a\x94\x2a\x48\x93\x84\x1b\x2b\x37\x39\ -\x7a\xe2\x38\xc2\x14\x38\x8e\xab\x73\x95\x05\xa4\x2a\xd3\x73\x70\ -\x95\x83\x01\x77\xb7\x36\x99\x5f\x98\x23\x0f\x63\x82\x8a\xc3\xfa\ -\x6e\x44\x7d\xca\xa6\xdb\xad\x72\xf9\xce\x0e\xc3\x24\x23\x91\x39\ -\x59\x94\xe2\x55\xeb\x84\xe3\x90\xbc\x5c\xa0\x93\xd1\x10\x15\x87\ -\x14\xc3\x11\x79\xa6\x21\xec\x45\x49\xb9\xac\x36\xea\x14\xb6\x83\ -\x92\xba\x23\x9d\x67\x12\xcb\x30\xc8\xd2\xb4\xcc\x83\x4a\xb1\x1c\ -\x9b\xbc\xc8\x49\xb3\x8c\x38\x0a\x89\xf7\x7b\xd8\xb5\x96\xe6\x70\ -\xb5\xba\xa8\x42\x37\x4f\x6d\xc3\xc0\x2c\x24\xe9\xa8\xcf\x7c\xb3\ -\xc1\x27\x7f\xe2\xc3\x9c\x5d\x9c\xe7\xf4\x5c\x85\x78\x67\x4c\xb3\ -\xe6\xf3\xda\x6b\x2f\xd3\x6c\x04\x1c\x99\x9d\xc5\x2c\x14\x0f\x9c\ -\xbb\x8f\x73\xa7\x8e\x0b\xd7\x82\xd1\x68\x8c\x63\x6b\xe5\x57\x21\ -\xc0\x30\x0d\x2c\x4b\x37\x06\x45\xe9\x0a\xd2\x17\x3f\x71\x8f\x1f\ -\x9f\x3f\x37\x7f\xeb\xdf\xcb\x3b\xf2\xbd\x82\xf2\xb2\xe7\x71\x4f\ -\xa2\xdf\xa1\xdd\xab\x84\xf9\xdd\xe3\xac\x32\xca\x98\x3e\xcf\x86\ -\xb9\x4e\x93\xaf\x7e\xf5\x2b\x9c\x3a\x75\x8a\x28\x8d\xb0\x8d\x82\ -\xbb\xab\x77\xa8\x77\xbb\x84\xe3\x11\x9f\xfc\xc9\x1f\xe7\x33\xbf\ -\xf3\x7b\x5c\xbd\x7a\x95\xed\xbb\x1b\x3c\xf9\xd8\x13\xcc\x34\x6b\ -\x84\xa1\x96\x54\x26\x49\xc2\xd1\xa3\x4b\xd4\x6a\x7a\x88\x7f\xe3\ -\xc6\x0d\xae\x5d\xbb\x46\xb5\x5a\x65\x61\x61\x61\x72\x6c\x1d\x8d\ -\x46\xd4\x2b\x75\xa4\x34\x18\x8d\x62\x5a\xad\x3a\x9e\x67\x31\x18\ -\x0c\xd8\xda\xda\x62\x71\x71\x91\x53\xa7\x4e\x51\xab\xb9\x0c\x06\ -\xda\xe6\x78\xe7\xce\x1d\x5e\x7c\xf1\x45\x9a\xcd\x26\xb7\x6f\xdf\ -\xe6\xe0\xe0\x80\x87\x1e\x7a\x88\xc1\x60\xa0\xef\xca\x4d\x97\x9d\ -\xbe\x4e\xeb\x18\x8d\x62\x3c\xcf\x9b\x1c\x89\x47\xa3\x11\x0b\x0b\ -\x1d\x8a\x02\xa2\x48\x94\x0d\xac\x7c\xf2\xb0\x1c\x62\x7b\x2d\xcb\ -\x9a\x50\x34\xee\x25\x71\x1c\x7a\x72\xef\x1d\x69\x89\x6f\x03\xbd\ -\x25\xe5\xdc\xbc\xde\x08\xa8\x35\x02\x1a\x8d\x46\x19\x49\xaa\x08\ -\x7c\x97\x7e\x98\x60\x9a\x02\x85\x86\xcf\x27\x79\x4a\x22\x33\x06\ -\xc9\x88\x71\x12\xb3\xd0\xaa\x93\x4a\x68\x37\x7c\xb6\x86\x70\x75\ -\x67\x8f\xcb\xaf\xbf\x8a\xf0\x6b\x8c\x57\xd7\x40\x0a\x62\x61\xe9\ -\xd9\x9f\xed\x62\x7b\x2e\x38\x0e\x86\xa7\xc3\xdb\xcc\x58\x22\x54\ -\x41\x9c\x67\x93\x7b\xfc\x21\xd1\xc3\x30\x0c\x6a\x41\xc0\xb8\x3f\ -\x98\xa0\x77\xcd\x20\xc0\x44\xe8\x9e\xc3\x78\x04\x95\x0a\xb3\xf7\ -\x9d\x67\xd8\x1b\x42\xb9\xd8\xe6\x69\x46\xd5\x75\x89\xc7\x03\x06\ -\xbb\xdb\x4c\x57\x3d\xde\xfb\xc4\x63\x3c\x70\xb2\x81\x1f\x43\xcb\ -\x80\x2f\xbe\xf6\x0a\x9d\x66\x95\x77\xfd\xc0\x63\xac\x6f\xad\xb1\ -\xbd\x79\x97\x33\x47\x8f\xb3\x3c\x3b\x2b\x84\x02\x99\x65\x1a\xdc\ -\x58\xc8\xf2\xf9\x54\x93\xbf\x27\x1a\x08\xc1\xf7\x47\xa7\xeb\x7b\ -\x5d\xc8\x87\x26\x8b\xe2\x1d\x7e\xe6\x7b\x0a\xb8\x7c\xa3\xbe\xb3\ -\x7b\x04\x4c\x01\xcb\xf3\x2d\xd1\x1f\xc9\x5f\x38\x7f\xea\xf8\xaf\ -\xbd\xf2\xda\xcb\x3c\xf2\xd8\xe3\xbc\xf8\xad\x6f\x31\xb3\xb4\xc0\ -\xd6\xce\x36\xef\x7a\xf2\x51\xae\xac\x6d\xb2\x7c\x74\x89\xd9\xa9\ -\x39\x8e\x2e\x2c\x71\x7b\x65\x85\xf5\x55\x93\xe5\xe5\x65\x3c\xcf\ -\x2b\x67\x95\x9a\x5b\xdd\xa9\xdb\x4c\x4d\x3d\x42\x18\x66\x8c\xc7\ -\x63\x6e\xde\xbc\xc9\xcb\x2f\xbf\xcc\x27\x3f\xf9\x49\x3a\x9d\x3a\ -\x1b\xdb\x43\x4c\xd3\x64\x7e\xa6\xce\x5e\x4f\x0b\x3e\x5a\xad\x16\ -\xbd\x5e\x8f\xd9\xd9\x2e\xa3\x51\x4c\x92\x14\x13\x51\xc9\xd3\x4f\ -\x3e\xc8\xda\xee\x98\xd9\x6e\x85\x2f\x7d\x55\xc3\x05\x76\x77\x77\ -\x59\x5b\x5b\x9b\x74\xbc\xf7\xf6\xf6\x58\x5a\x5a\xc2\xf3\x3c\x1a\ -\x8d\x46\x89\x14\xd2\x6c\xe6\x7e\x3f\x99\xdc\x67\x0f\xef\xd8\x87\ -\xb8\x5e\xdb\xb6\xbf\x2d\x7b\xf8\xed\x54\xc4\xc3\x7f\x3f\x34\x7e\ -\x7c\xb7\x82\x6e\x34\x1d\xb2\xcc\x21\xcb\x14\x3b\xfb\x03\xfa\x07\ -\x3d\x2a\x7e\x80\x54\x39\x7b\xfd\x11\xae\xe7\x61\x3b\x66\xb9\xc2\ -\x82\x44\x20\x54\x81\x1d\x54\xf0\x6b\x55\x6e\xad\x6d\x72\xe3\xd6\ -\x0a\xb2\x5a\x63\xbf\x28\x58\x8d\x62\x1c\xcb\x66\xa7\xff\xff\xb6\ -\x77\xa6\x3f\x76\x9d\xf7\x7d\xff\x9c\xfd\x9c\x7b\xce\xdd\x67\xe5\ -\x2c\x24\x87\xeb\x70\x19\x92\x12\x45\xc9\x92\x2c\x35\x32\x9d\xc2\ -\xcd\x82\xa4\x41\x0a\xd8\x29\xe0\xa6\x40\xed\xa2\xef\x0a\xb4\xb0\ -\x5f\xf4\x45\x02\x14\x68\xfc\x07\x04\x45\x89\xa2\x1b\x90\x20\x95\ -\x9d\xb5\x4e\xe0\xd8\x52\x1a\xad\x16\xa9\x8d\x14\x49\x71\x5f\x34\ -\x9c\xfd\xce\xdc\xb9\xfb\x3d\xfb\xd3\x17\xcf\x99\xcb\x21\x25\x5b\ -\x09\x02\x34\xb2\xc2\x0b\x10\x97\xe4\xdc\x33\x83\x3b\xe7\xfe\x9e\ -\xdf\xf6\x5d\x5a\x68\xe5\x0a\x49\xb3\x8f\x69\xd9\xb2\x9c\x57\x74\ -\x14\x45\x80\x22\x33\xb3\xa1\xa9\x98\x98\x24\x7e\x88\x92\xa4\x99\ -\xb5\x69\xe6\xea\x28\xa4\x99\x5c\xd3\xdf\x94\x30\x4d\x21\xd5\x41\ -\xb6\xfc\xb8\x34\x5d\xc3\xa8\x56\x71\x3c\x8f\x95\xeb\xd7\xc9\xef\ -\x98\x84\x38\xa6\xb9\xbe\xca\xf4\xc4\x04\xf3\xd7\xaf\x40\xbf\xcb\ -\xd4\xce\x31\xc2\x46\x9d\x9f\x7f\xe6\x28\x7e\x13\x16\x6e\xdd\xe4\ -\xea\xe6\x06\x7e\x63\x93\x83\xbb\x27\x39\xfb\xe3\x37\x18\x9b\x18\ -\xe5\xc8\x81\x43\x4c\x54\x47\x14\x15\xe8\x74\x5a\x28\x02\xf2\xa6\ -\xb4\xaa\x4d\x95\xed\x9f\x4d\x35\xc3\x25\xf2\x00\xe8\xe3\xd1\xd4\ -\xfa\x21\xf8\x8b\x2a\x1e\x0c\x74\xb6\xb6\x13\xdb\x3e\x9c\xf7\x2f\ -\x11\x44\x31\xe4\x6c\xfd\xcc\xe3\x8f\xcd\x9e\x99\x3b\x3a\xcb\x7f\ -\xfb\x1f\xff\x53\x78\xa5\x22\x8d\xb5\x35\xf6\xcf\x1d\xe5\xfb\x3f\ -\x7c\x19\xaf\x52\x66\xcf\xde\xbd\xbc\x79\xf6\x1c\xa7\x9f\xff\x12\ -\xc5\xc3\x87\xa9\xad\xac\x72\xfe\xfc\x79\xca\x43\x55\x34\x4d\xa3\ -\xd1\xe8\x60\x59\x16\x0b\xab\x2d\x84\x10\x94\xcb\x45\x34\xad\xc0\ -\x89\x13\x27\x48\x92\x84\x2b\x57\xae\xd0\xed\x76\x51\x55\x95\x5c\ -\x2e\x87\xbf\x73\x27\x3b\x76\x54\x08\x43\x48\x53\x83\xcd\xcd\x4d\ -\x82\x20\xc9\x70\xda\x0a\x9a\xe6\x61\x9a\x70\x77\xa5\x49\x2e\x97\ -\xa3\xd5\x93\xc1\x7d\xea\xe4\x61\xda\x5d\x29\x7c\xbf\xd5\x3f\x07\ -\x41\x38\xc8\xa2\x57\xaf\x5e\xe5\xc2\x85\x0b\x03\xda\xe4\x96\xd7\ -\x73\xb7\xdb\x1d\x80\x50\xaa\xd5\x2a\x23\x23\x23\x99\xcb\x64\xb0\ -\x4d\xd7\x4a\xee\xa1\xb7\x06\x5d\x5b\x59\x7b\xeb\x6b\xdb\xf9\xbd\ -\x20\x25\x8a\xd6\x37\xfc\x41\x56\x37\x4d\x13\xd7\x75\xc9\x99\xb0\ -\x56\xef\xb3\xb2\xb4\xc8\xca\xda\xaa\xdc\xef\xc7\x02\x55\x97\x84\ -\x11\xd5\xd0\xb9\x74\xe9\x12\x9a\x50\x99\x2c\x0e\xb1\xf7\xc0\x41\ -\xec\xf1\x12\x1b\x09\xec\xb3\xe1\xf0\x33\x27\xf9\x0f\xff\xe9\x77\ -\x49\xfd\x04\x91\x73\x29\xba\x1e\x71\x94\x48\xf4\x98\x02\x51\x94\ -\x0e\x0e\x92\x38\x8e\x89\x33\xdb\xd5\xad\xf7\x19\xc5\xd2\xdb\x36\ -\x50\x32\xa2\x76\x10\x82\xa2\x0e\x3c\xa5\x13\x91\x4a\x36\x57\x5e\ -\xea\x6a\xe7\xa6\xa6\x68\xaf\xad\xe1\x54\x4b\xd0\x0f\x59\xb8\x7e\ -\x85\xa9\x91\x21\x3c\xbd\x8c\x4d\x42\x69\x6a\x94\xbc\x02\x4b\x77\ -\xee\x50\xb1\x4d\x94\x42\x1e\x3f\x09\x38\xff\xce\xdb\x3c\xfe\xf8\ -\x1c\x13\x93\xe3\x0c\xe5\x4a\x4a\x9a\x44\x44\x91\x14\x36\x44\x49\ -\xe9\xf7\xfb\x98\xb6\x95\x25\x1c\x29\x91\xa4\x6c\xd7\x70\x1f\x78\ -\x63\xfe\x03\x0f\x64\x25\xcb\xb0\x83\x80\x15\x0f\xfa\x41\x2a\x59\ -\xa9\x8d\x48\x07\x7c\x2f\xb1\xad\xec\x56\x10\x20\xa4\x43\x85\x40\ -\x87\x34\xe2\x9b\xff\xea\xeb\xca\x8b\xdf\xfb\x63\xf1\xfe\xf9\x77\ -\x38\x76\x62\x8e\x83\x7b\xf7\x30\x39\xb3\x8b\xbf\xf8\xe1\x4b\x74\ -\x1b\x2d\x6e\xdd\xba\xc1\xbe\x99\x7d\x8c\x8d\x8d\x50\xae\x96\x68\ -\x34\xdb\xb4\x17\xba\xbc\xf5\xd6\x5b\x9c\x3e\x7d\x1a\xcf\x33\x08\ -\x43\x09\x34\xea\xf7\xfb\x24\x49\xc2\xcc\xcc\x0c\x2b\x2b\x2b\x1c\ -\x3b\x76\x0c\xcf\xd3\x58\x5c\xac\x67\x6a\x9b\x32\xb8\xc7\xc6\xc6\ -\x68\x34\x1a\x08\x21\xf0\x3c\x29\x42\xd0\x6e\x77\x89\xe3\x98\xa1\ -\xa1\x22\x8a\x02\x8b\x8b\x35\x84\x10\x2c\x2e\x37\x28\x95\x4a\x19\ -\xb3\x07\x1a\x8d\xf6\x40\x00\xdf\xb2\x14\x0e\x1c\x38\x40\xbd\x5e\ -\xe7\xf9\xe7\x9f\x22\x8a\xa0\xd9\x6c\x0f\xca\x6d\x5d\xd7\xe8\x76\ -\x7b\xd4\xeb\x75\x6e\xdc\xb8\xc1\x9d\x3b\x77\xe8\x66\x7d\xf2\xd6\ -\x6a\xcb\xf7\xfd\x01\x67\x7a\x2b\x78\x17\x16\x16\x3e\x36\xb5\xde\ -\xa2\x67\x7a\xf9\x1c\x8d\xfa\x26\xaa\x2a\xcb\xda\xb3\x67\xdf\xc6\ -\xf7\x43\x9c\x5c\x8e\x89\x89\x09\xf6\x9d\xda\x8b\x50\x15\xa2\x38\ -\xc1\xb0\x8d\xcc\x7c\x4d\xa3\x98\x2b\xf0\xd8\xf1\xe3\xe4\x34\x85\ -\x30\x85\x46\x02\x98\xe0\x47\x70\xeb\xce\x1a\xfd\xae\x8f\x97\x2f\ -\xb3\xd1\xde\xc8\x4c\xdc\x40\x55\xb5\xcc\x70\x5d\x47\x37\xa4\xbd\ -\x4c\xab\xb6\x09\x61\x0a\xa6\x2e\xf7\xc6\x7e\x24\x77\x77\xba\xd4\ -\xdf\x72\x3d\x8f\xd6\x66\x03\x11\x48\x23\x39\x2b\x67\x11\xc5\x31\ -\xfd\xa0\x4f\x3f\x0c\x48\x7b\x1d\xb4\x4a\x05\x56\x97\x49\x76\x8c\ -\x33\xe2\xb9\x6c\x36\x03\x0a\x69\x80\x15\x26\x54\x72\x26\xff\xe4\ -\x99\x27\x59\xbe\x7e\x9b\x43\xbb\x27\xd1\x7a\x7d\xde\x3c\xff\x36\ -\xf5\xa5\x25\x7e\xe5\x17\xbf\xc2\x81\xfd\x7b\x15\xd9\x62\xf4\x50\ -\x92\x14\xc7\xb2\x07\x1b\x15\xc7\x71\x89\xc4\x56\x53\x71\x9f\xd3\ -\xa7\x64\xe1\xfc\xff\x0f\x80\xf9\x33\x90\x91\x65\xf7\x25\x06\x18\ -\xd5\x07\x43\x5c\x41\x88\x34\x73\x70\xdf\x66\x46\x33\x70\x8c\x4c\ -\x11\x24\x18\xaa\x4e\x1a\x07\x34\x5b\xcd\xba\x6d\xdb\x95\x5f\xf9\ -\xc5\x5f\x50\x9e\x78\xe2\x09\xf1\xbd\x3f\xfb\x53\x8e\x9e\x7a\x82\ -\x42\xa9\xc8\x0b\xcf\x3d\x47\xaf\xef\xf3\xfb\xbf\xff\x07\xf4\x3a\ -\x1d\xf6\xed\xd9\xcb\xc4\x50\x41\x7a\x35\x2b\xb0\xbc\xbc\xcc\x7b\ -\xef\xbd\x47\x10\x04\xe4\xf3\x79\xf6\xef\xdf\xcf\xf0\x90\x4b\xb7\ -\x27\x08\x32\xe9\x18\x4d\xd3\x68\x36\x43\x3c\xcf\xe3\xd4\xa9\xc7\ -\x10\x02\x6c\x13\x3a\x3d\x41\xad\x56\xe3\xe5\x97\x5f\xc6\xb2\x2c\ -\xc6\xc7\xc7\x99\x9e\x9e\x66\xf7\x58\x91\xb5\xb6\xa4\xe5\x8d\x8f\ -\x0f\x33\x31\x31\xcc\x6b\xaf\x9d\xe5\xd9\x67\x9f\xa4\xd1\xe8\x62\ -\x9a\x26\xe5\x72\x5e\x7e\x6e\x75\x68\x36\xfb\x54\x2b\x0e\xba\xae\ -\x4b\xc5\x90\x4e\x8f\x5c\x2e\x87\xa6\x69\x83\x9d\xb1\xaa\xaa\x54\ -\xab\x55\x46\x47\x47\x19\x1a\x1a\xa2\xd5\x6e\xb3\x6b\xd7\xae\x81\ -\xb0\x5d\xbf\xdf\x1f\x68\x41\x6f\x05\x72\xa9\x54\x42\xd7\xf5\x41\ -\x16\xdf\x0e\x08\x11\x4a\xca\xe8\xc4\x0e\xf2\x6e\x01\xcf\x91\xe4\ -\xfc\xc3\x87\x0f\x23\xe2\x84\x7c\x3e\x47\xaf\x27\xd7\x5f\x06\x0a\ -\x0e\x10\x2b\x1a\x71\x22\x88\x7a\x01\xed\x46\x9b\xc8\xf6\x08\x84\ -\xa0\xa7\x6b\x34\x23\xb8\x7a\x6f\x99\xef\x7e\xf7\x4f\x28\x97\xcb\ -\x6c\xb6\xfb\x72\xcf\x2a\x12\xd2\x58\x1a\xfd\xc5\xa9\x42\x18\xf6\ -\x08\x93\x40\x22\xb6\xa2\x08\x62\x81\xe6\x58\xd2\xac\x2e\x0e\x49\ -\x75\x1d\x2b\x67\x61\xe9\x86\x1c\x7a\x69\x3a\xd8\xb2\x35\x88\xa2\ -\x88\xbe\xef\x13\x47\x91\x04\x13\xb9\x36\xc9\xf2\x02\xde\xec\x3e\ -\x8a\xaa\x46\xb4\x51\xe3\xd0\xae\x49\x76\x8f\x54\x58\xbe\x7d\x83\ -\x7f\xfd\xd5\xaf\x71\x68\xcf\x10\x61\x3b\x62\x73\x6d\x91\xf7\xdf\ -\x7c\x8b\xe9\x91\x21\xbe\xf9\xb5\x5f\x93\xae\x88\xf5\x8d\xdf\x31\ -\x4d\xf3\xdb\x9e\x9d\x93\xcc\x25\x01\x89\x1f\xa0\xea\x1a\x8a\xa1\ -\x6f\xd3\x6b\x67\x5b\x10\x6f\x47\x81\x88\x47\x81\x2c\x25\x36\xd3\ -\x6d\xa5\x4a\x16\xa0\xdb\x0c\x99\xa5\x2a\x76\xc6\x32\xc8\x5c\x07\ -\xe4\xe4\x4b\x06\xb2\xa6\xcb\x7f\x47\x51\xc0\xe8\x70\xa5\x22\x84\ -\x42\x1c\xa7\xec\xde\x39\xa9\xfc\xcb\xdf\xfc\xcd\x77\x5e\x79\xf3\ -\xc7\x8f\x9f\xf9\xdd\xff\xcc\x17\x4f\x9f\x66\x6a\xd7\x4e\x8e\x1f\ -\x9f\x63\x78\xb8\xca\xf5\xeb\x57\x39\x7f\xde\xe7\xf0\x91\x39\x2c\ -\xcb\xe2\xc4\x89\x13\x08\x21\x18\x1e\x1e\x26\x0c\x43\xae\x5c\xb9\ -\xc2\xfc\xfc\x3c\xbb\x76\xed\x62\xf7\xee\xdd\x28\x8a\xc2\xe6\xe6\ -\x26\x7b\x76\x94\x69\xc7\xb0\xb4\x54\x63\x6a\x6a\x98\x66\x3b\xa6\ -\xdf\xef\x33\x33\x33\x83\xef\xfb\xec\xdf\xbf\x7f\xb0\x6f\x7e\x69\ -\x71\x91\xe9\xe9\x69\x3c\xcf\x63\x78\x78\x98\xb1\xd1\x02\xf5\x7a\ -\x9d\xcd\xcd\x0e\x85\x82\x37\x30\x2a\x0f\x82\x80\x34\x95\xd8\xeb\ -\x30\x82\xa9\xa9\x29\x96\x96\x56\x28\x14\x0a\x84\x61\x38\xc8\xb0\ -\xa6\xa9\x63\x64\x8e\x7d\x9a\x86\xdc\x1b\x67\x19\x58\x4a\x0f\x29\ -\x08\x61\xa3\xeb\x1a\x69\x06\x6b\xdc\x02\x85\x6c\x09\xe2\x6d\xa9\ -\x59\x6a\x9a\x8a\x96\xa6\xd8\x39\x95\x18\x88\xc3\x94\xd5\xf5\x4d\ -\x9a\xad\x16\x45\xcf\x82\x18\xc2\x5e\x82\x9e\xa8\xe8\x4a\xf6\x33\ -\x13\xa9\xca\xa3\x8a\x14\x23\x56\x30\x14\xe9\x73\x3c\x96\x87\xbb\ -\x21\xfc\xaf\xff\xfa\x7b\x5c\xbe\xb7\xcc\x5a\xab\xcb\xee\xd9\x23\ -\x2c\x2e\xd5\x30\x75\x07\x0d\x85\x28\x8e\x88\x63\x41\xa2\x29\x52\ -\xd9\x80\x08\x12\x50\x4c\x13\x91\x09\x37\x98\xa6\x49\xa2\x08\x92\ -\x4c\xfb\x5a\x41\xa1\xb5\xb9\x89\x82\x8a\x99\x4d\xf6\xc3\x50\x0e\ -\xe7\x74\xc3\xc0\xf0\x1c\xfa\xdd\x36\x78\x36\x8a\x88\x49\xfc\x1e\ -\x22\xe8\x41\x5f\xe5\xd9\xc7\x9e\x67\xa3\x9a\x63\x76\x72\x88\x3b\ -\x97\xae\x71\xf9\xfc\x7b\xb4\x37\x6a\x7c\xfd\x37\xbe\x46\xd1\xc9\ -\x7d\xc7\xf7\x03\x88\x23\x86\xca\xd5\x6f\x4b\xa3\x75\x25\xb3\x96\ -\x55\xd0\x4c\x0b\x48\x09\xfa\x3e\x9a\x63\x3f\x90\x7b\x07\x15\xa3\ -\x78\xa8\x6a\xfc\x87\xbd\x7e\x12\xdb\xfe\x6c\xfb\x75\x0d\x82\x95\ -\x07\xc4\xcb\x40\xc8\x71\xbf\xb2\xf5\x3a\xa9\x6c\xd1\x0b\x3a\x78\ -\xb6\x3b\xb0\x3f\xd5\x34\x0d\xbf\x1f\xe2\xb9\xce\x99\xdd\x33\x33\ -\xbf\x3d\x3e\x31\xf1\x5b\x6f\xbd\xf9\x26\xf7\xe6\x17\x98\x1c\xdf\ -\x41\x1c\x4b\x49\x9a\x93\x27\x4f\xb1\xb0\xb4\xc4\xcd\xdb\x77\x30\ -\x0d\x83\x5a\xad\x96\xad\x7d\x64\xaf\xf8\xf4\x93\x73\x18\xa6\xcb\ -\xe5\xcb\x97\x59\x58\x58\xa0\xd7\xeb\xa1\x18\x72\xa7\xeb\x98\x36\ -\xcd\x56\x0f\xd7\xb5\xd1\x34\x03\xcf\xf3\x58\x59\x59\x61\x64\x64\ -\x04\x5d\xd7\x99\x9e\x9e\xe2\xd0\xe1\x03\x58\xa6\x43\xa1\x58\xe4\ -\xdd\x77\xde\xe1\xd6\x9d\x7b\xac\xd7\x6a\x74\x7b\x3d\xf6\xec\x99\ -\x66\xb3\xd1\x46\xcb\x24\x6a\x24\xb9\xc2\x66\x7d\xbd\xc9\xc8\xc8\ -\x08\xd7\xae\x5d\x63\xe7\xce\x9d\x68\x9a\x86\x61\xc8\xc0\x14\x42\ -\x02\x44\xa2\x28\x26\x49\x04\xed\x76\x9b\x76\xa7\x43\xa1\x50\xc8\ -\xd6\x57\x3a\x51\x14\x0f\xbe\xdf\xd6\x94\xbb\xd9\x6c\xa2\xaa\x2a\ -\xae\xeb\x0e\xd6\x59\x8a\x22\x71\xed\x41\x9c\x12\x47\x92\x86\x68\ -\x99\x0e\x2b\xcb\xcb\x8c\x0c\x8d\x13\x05\x71\x26\xa6\xae\x48\xa5\ -\x8b\x4c\x15\xb4\xef\x07\x08\x01\xeb\xeb\xeb\x4c\xed\x99\x26\xd4\ -\x60\xa1\x0b\x1f\x7e\xb4\xc2\x5f\xbe\xf6\x16\x9d\x14\xd4\x5c\x9e\ -\xf9\x4b\x57\xb1\xaa\xa3\x84\xed\x3e\x89\xa2\xd3\xf7\x7d\x52\x45\ -\xa0\x9b\x1a\x98\x1a\x86\xe7\x61\xd8\x36\xba\x90\x2b\x33\xd3\x32\ -\x30\x6d\x93\x24\x89\x51\x44\x8a\xae\xa8\x44\x7e\x28\x33\x6f\x18\ -\x92\xf4\xbb\x44\x49\x8c\x66\x6a\x38\xae\x83\x6e\x19\x20\x62\x34\ -\x5d\x90\xfa\x3d\x5c\x91\xd0\x59\x5e\xe0\x3f\xfe\xfb\x7f\xcb\x57\ -\x7f\xf9\x05\x6a\xb7\x6f\x73\xea\xf0\x01\xae\x5f\x78\x8f\xbf\xf8\ -\xa3\x3f\xe4\x85\x67\x9e\xe2\x37\x7e\xfd\xd7\x14\x5d\x11\xcb\xae\ -\x6d\x7f\x47\x49\x63\xdc\x9c\x4b\xd8\xef\xe2\x77\x7b\x92\x2f\x6f\ -\xd9\xd2\x74\x2e\x92\xf2\xb9\xfa\x16\xfd\x56\xb9\x4f\xd3\x55\xf9\ -\x04\xcd\x2d\x85\xbf\xb7\xb5\xd3\x67\x24\x23\x6f\x05\xa5\xfa\x13\ -\xdb\x0d\x45\x55\xb3\x8e\xe4\xbe\x88\xc1\x96\x50\xb0\xec\x5c\x12\ -\xf2\x96\x14\x00\x37\x2d\x6b\x70\x9d\xe3\x58\xa4\x80\xa9\xc0\xdc\ -\xde\x19\x65\xe7\xc4\xbf\xa8\x37\x3a\xdd\xf2\xd9\xb7\xde\xa6\x5e\ -\xaf\x53\x19\x1a\x22\xe8\xf6\x98\x9c\x9c\x66\x78\x72\x8a\x7b\x77\ -\xef\xb2\x56\xab\x71\xf6\xdc\x39\x4e\x9e\x3c\x89\x97\xcf\xb3\xb4\ -\xd6\xc6\x32\x75\xbe\xf8\xc5\x27\x69\x37\xba\x9c\x3b\x77\x8e\x95\ -\xc5\x05\x2e\xbc\xf7\x2e\xe5\x52\x89\x62\xa9\x42\x18\x56\x19\x19\ -\xad\x60\x5a\x26\x77\xee\xde\xe5\x89\x53\xc7\x69\xb5\x62\x3a\xdd\ -\x1e\x8e\x97\xc3\xb2\x6d\x34\xd3\xe0\x89\x27\x4f\x52\xaa\x78\xfc\ -\xf8\x8d\xb7\x99\xda\xb9\x93\x73\xef\x9e\x97\x2b\x28\xd3\x21\x08\ -\x02\xa2\x28\x22\x97\xcb\x31\x3c\x3c\x4c\x14\xc7\x18\xa6\x49\xa3\ -\xd9\x94\x1a\xdb\x96\x89\xdf\x09\x06\x93\xab\xb9\x11\x4d\x00\x00\ -\x15\xd8\x49\x44\x41\x54\x67\xc9\x50\x32\xb0\x6c\x1b\x55\x51\x70\ -\x73\x16\x51\x94\x12\x85\x31\x69\x92\xa0\x9a\x26\x02\xa9\xae\xa1\ -\x20\xa5\x7f\xa4\x77\x31\x68\xaa\x82\xa6\x6a\x92\xd8\x11\x84\x98\ -\x59\x4f\xd8\xd9\xe8\x30\x34\xe4\x11\x05\x11\xa6\xad\xe3\xfb\x29\ -\xad\x28\xc4\xb2\x4c\x52\x15\xe2\x14\x5c\x17\x5a\x2d\x9f\x9d\x13\ -\x45\xba\x69\xc4\xc2\x7a\x9b\xf5\x48\xe1\xe6\xea\x06\xff\xfb\xff\ -\x7c\x9f\x5b\x1b\x4d\x12\xc7\xc5\x2e\x39\x30\x35\x83\x59\x28\x13\ -\xf8\x02\xc3\x2b\xe0\x95\x4d\xba\xbd\x26\x31\x29\xae\x93\x23\x51\ -\x15\xc9\x4e\x8a\x62\xd0\x53\x4a\x95\x92\x34\x72\x8f\x22\x82\xda\ -\x06\xa1\x93\x43\xf4\x7a\xa0\x2a\x18\xae\x43\xae\x52\x90\x84\x29\ -\x55\x48\xff\xe4\xb0\x47\xd2\x6d\xe3\x45\x01\x6c\xd4\x71\xbc\x1c\ -\xdf\xfa\x37\xdf\x60\x76\xb4\xca\x8d\x77\xde\xc5\x4e\xfa\xdc\xbd\ -\xf2\x01\x63\xc5\x02\xbf\xf5\xad\x7f\xc7\x68\xb5\x22\x8b\x64\xd3\ -\x38\x63\x6a\x1a\x68\x0e\xdd\xc0\xc7\xcd\xb9\x98\xce\x83\x86\x6a\ -\xaa\x75\x3f\x80\x55\x7e\x82\x5d\xf8\xb6\xd5\x8a\xf2\xa8\xb4\x7e\ -\x78\xa1\xf4\x69\xaf\xf9\x09\x3a\x0b\x9f\xa0\x7b\xb4\x5d\xa9\x24\ -\x8c\x53\x4a\x8e\x59\x49\xc2\x48\x3c\xf7\xd4\x93\xbc\x77\xfe\x03\ -\x7c\xdf\xe7\x95\x97\x5f\x62\xc7\xde\x7d\xcc\xce\x1d\x65\x6a\x6a\ -\x8a\xf1\x1d\xa3\x5c\x78\xff\x03\xce\x9d\x3d\x8b\x61\x18\x9c\x3a\ -\x75\x8a\x76\xbb\x49\xb7\xc5\x60\xf5\x33\xb3\x7b\x37\x4f\x9e\x3a\ -\x4e\x10\x08\x96\x57\x56\xb8\x76\xf5\x3a\x97\x2e\xc7\xe4\x3d\x57\ -\xee\x9a\xdb\x99\x58\x40\x18\xd3\xef\xf4\x28\x95\x72\x04\x81\x20\ -\x97\xcb\x11\xfa\x29\x8d\x46\x83\x67\x9e\x79\x82\x91\x91\x11\x7c\ -\xdf\xc7\x50\x8d\x01\x0a\xab\xdd\xee\xd2\xeb\xf5\xf8\xe8\xa3\x8f\ -\xb8\x76\xed\x1a\xcd\x66\x73\xe0\x6e\x61\x59\x96\x94\x78\xcd\x08\ -\x16\x12\xb0\x62\x10\x86\x21\xdd\xae\x64\x03\xb9\xae\x3d\x00\x97\ -\xf4\x7a\xbd\xec\xfb\xea\x72\x5d\xa3\x49\x7d\xac\x30\x94\x43\x30\ -\xd3\x34\x65\xb6\x47\x91\x92\x44\x9a\x49\x12\x4a\xd1\xc0\x7a\xbd\ -\x43\xbb\x2b\x5d\x2b\x1a\xad\x16\xbe\xef\xe3\x87\x01\xb6\x6d\x13\ -\x25\x31\x7f\xf5\xea\x1a\xf9\x52\x91\xcb\x57\xaf\x30\xf3\xd8\x29\ -\xee\x9c\x7b\x1f\xd3\x71\xd9\xb3\xf7\x20\xd7\x17\xef\x61\x3a\x39\ -\x9c\xa2\xcb\xe6\xe5\x2b\xb8\x7b\xf6\x13\x87\x11\x71\xe8\x63\x38\ -\x39\x72\xa6\x4a\x9c\x06\x04\xbe\x0f\x49\x84\x66\x98\x24\xfd\x36\ -\xcb\x97\x2f\x43\xa9\x04\x41\x48\x65\x6a\x0a\x55\x40\xe0\x79\xb4\ -\x37\xeb\xb8\xae\x9b\xed\xeb\x1b\xf4\x5a\x0d\xa9\xe7\xa4\x69\x28\ -\x71\x88\x9d\x44\x1c\xd9\x39\xc1\xd7\xbf\xfa\x55\x0e\xee\x9a\xe4\ -\x87\x7f\xfa\x47\x1c\x9f\xdd\x8f\x69\x2a\x5c\x79\xef\x2a\xbf\xf4\ -\xcf\x7f\xe3\x3b\x65\x2f\xf7\x6d\x95\x74\xab\xa6\x43\x64\x4c\x2c\ -\x5d\xd7\x33\x5f\xa8\xbf\xd1\x42\xe5\x6f\xf0\x9f\x7f\x8f\xb3\x26\ -\x21\x04\x3f\xbb\x8f\xac\xc7\x1e\x0c\xbf\xd8\x06\x62\x57\x11\x40\ -\x98\xc8\x7e\x32\x4c\xc9\x80\x06\x10\xc6\xc9\xef\xdc\xbd\x7b\xf7\ -\x5b\x77\xee\x2d\xb0\xd6\xe9\xa0\xdb\x0e\xd3\xd3\xd3\x98\xa6\xce\ -\xd0\xf0\x28\xf3\xf3\xf3\x54\x2a\x15\x6e\xdc\xb8\x81\xaa\xaa\x8c\ -\x8f\x8d\x31\x33\xb3\x8b\x1b\x37\xa4\xdc\xcf\x9e\x3d\x7b\x08\x43\ -\x39\xf4\xf2\x83\x98\x62\x51\x67\x71\xb1\xc1\xc5\xcb\x97\xe9\x75\ -\x3a\x94\xab\x55\x5c\x2f\xc7\xd1\xa3\x87\xd8\xd8\x68\xe0\x79\x92\ -\x38\xd1\x6a\xb5\xb8\x79\xf3\x26\x4f\x3d\x75\x8a\xf5\xf5\x3a\x3b\ -\x76\x54\x68\x34\xa5\xe0\xba\xe3\x98\xf8\xbe\x64\x2a\xc9\x3e\x7a\ -\x93\xe3\xc7\x8f\x90\xa6\xb0\xb9\x29\x95\x4a\x7a\x99\x87\x92\xa2\ -\x28\x5c\xb8\x70\x81\x95\x95\x15\xf2\x59\xff\x5d\xaf\xd7\x07\x1c\ -\xe7\xad\xdd\x71\xa1\x50\xa0\xdd\x6e\xb3\xbe\xbe\x8e\x65\x59\x0c\ -\x0d\x0d\x49\x52\x42\x86\xb5\x8e\xe3\x98\xb0\x17\x0d\x14\x5c\x5c\ -\xd7\xe5\xf2\xd5\x2b\x3c\xf5\xd4\x53\x28\x9a\x0c\xf8\x52\xa5\x42\ -\x3e\xef\x92\x64\x63\x89\x42\x0e\x16\x6b\x72\xbf\x7e\xe2\xc9\xa3\ -\x2c\x36\xe0\xbf\xff\xc1\x9f\x70\xf6\xd2\x87\x38\x63\xa3\xac\xf9\ -\x01\xdd\x54\x10\xaa\x26\x28\x3a\x05\xaf\x48\xe8\xfb\xc4\x7e\x88\ -\xa2\x48\x99\x9f\x48\x04\xa4\x61\x20\xa7\xd3\x81\x82\x5d\x28\x61\ -\x39\x36\xf9\x7c\x9e\xd5\x5a\x0d\x3b\x27\x31\xe3\x71\xe0\x43\xe0\ -\x4b\xb5\x7d\x12\x9c\x5c\x8e\x7c\xce\x44\x23\x25\x0e\x42\xf4\xa0\ -\xc7\x73\x87\x0e\xf0\xeb\xff\xf8\xe7\xf9\xf0\x83\x0b\xd8\x08\x8c\ -\x34\x64\x66\x62\x94\xe3\x07\x0f\x32\x9a\x37\x15\x3d\x2b\x89\xd3\ -\x44\x22\xf6\xd2\x24\x03\x9b\xe8\x06\xaa\xa6\x7c\xd6\xe2\xf1\x73\ -\xb0\x47\xfe\xbb\xec\xb0\x84\xf2\x13\xb3\xbb\x96\xa9\x35\x84\x7d\ -\x1f\xcb\xb2\xe9\xf9\xbd\x17\x8b\xf9\xdc\x3f\x3b\x3a\xbb\xe7\xdb\ -\xfb\xf6\xed\xe1\x87\xaf\xbe\x21\x34\xcb\xa4\xdf\xdc\x04\x37\xc7\ -\x85\x77\xce\xa2\xea\x26\x73\x87\x0f\x30\x52\xad\xa0\xaa\x1a\xd7\ -\xaf\xdf\xe0\xa5\x97\xfe\x8a\xd1\xd1\x51\xfa\xfd\x3e\xb6\x2d\x59\ -\x46\x8e\x0d\xeb\x1b\x6d\xe2\xd8\xa1\x52\x29\xf1\x95\x9f\x7f\x86\ -\x1f\xfc\xe5\xeb\xec\xdf\xbb\x17\xdf\xef\xf3\xd7\x2f\xbf\x42\xb5\ -\x5a\x65\x73\x73\x93\xd9\x03\x07\x29\x57\x2b\x54\xf2\x45\x96\xee\ -\x2d\xb1\x63\x6c\x9c\xb0\x2f\xcb\x5e\x01\xc4\xb1\xa0\x50\x30\xf0\ -\x7d\x83\x34\x2d\x51\xab\xd5\xe8\x76\xa5\x56\x57\x3e\x9f\xc7\x71\ -\x54\x6c\xdb\xca\x80\x20\x30\x37\x37\xc7\xec\xec\x2c\x0b\xf7\xee\ -\xb1\x7f\xff\x7e\x14\x45\x21\x9f\x37\x33\x50\x88\x54\xf9\x54\x55\ -\x95\x5e\xaf\x47\xad\x56\xc3\x71\x9c\x6c\xfd\xc4\x60\x58\x16\xc7\ -\x60\x65\x22\xea\xfd\xbe\x3c\x68\x14\x5d\x63\x62\x62\x02\xcd\x90\ -\x10\x52\xc3\x92\xd6\x4c\x7e\x0c\xf5\x7a\x17\x70\xe9\x74\x3a\x32\ -\xe3\x27\x30\xe2\x81\x16\xf6\x70\x88\x70\x44\x4c\xd1\x36\x70\x0c\ -\x8b\x46\x18\xd2\x5b\x5d\xa7\xd5\xef\xa1\xb9\x1e\x9a\xae\x10\xb6\ -\x5b\x12\x7b\xed\xe6\xa4\x12\x08\x0a\xb6\xe5\x65\x42\x7b\x21\xcd\ -\xfa\x3d\xf2\x43\x55\x30\x14\x8a\x6e\x99\x56\xa3\x4e\xac\x27\x08\ -\x3f\x21\x6f\xda\x0c\xe7\x5d\x94\xc0\xa7\x53\x5f\xa7\xec\xb8\xec\ -\x99\x9c\xe2\xc9\xfd\x07\x49\x9a\x4d\x0e\xed\x9c\x62\x7d\xe9\x1e\ -\xa7\xe6\x9e\x60\xef\x44\x49\x31\x81\x24\x4c\x30\x35\x8d\x30\xe8\ -\xa3\x88\x14\xd5\xb2\x50\x55\xd9\x66\xa0\x7c\x5e\x42\xf8\x33\x84\ -\xb5\xfe\x3b\xa3\x48\x06\x37\x46\xbd\x3f\x57\xcc\x06\x14\xaa\xaa\ -\x20\x52\xe9\xc1\xd3\xed\xf5\x29\x78\xb9\xef\x76\xdb\xfd\x19\xdb\ -\x32\x36\x55\x15\xf6\xed\x9e\xfe\x6d\x14\xe3\xb7\xee\xdc\xbc\x45\ -\x39\x5f\x60\x74\x78\x98\x0f\xde\x3f\xcf\x47\xb7\xef\x48\x70\x3f\ -\x0a\x43\x43\x15\x8a\xc5\x22\x23\xc3\x43\x5c\xbf\x71\x93\x2b\x57\ -\xae\xd2\x6e\xb7\xa9\x6f\xb6\x29\x17\xcb\x4c\x0c\xe7\x68\xb4\x02\ -\xa2\x48\x61\x75\x65\x95\xe9\xa9\x69\x2a\xe5\x12\x27\x0e\xed\x42\ -\xd1\x72\x8c\x8d\x8e\xd1\xa8\x6f\x72\xed\xda\x75\x14\x01\xaf\xbc\ -\xf2\x0a\x9a\x22\xd7\x40\xb6\x2b\x09\x10\x5b\x90\xcd\x4e\xa7\x27\ -\xd1\x5f\xb5\x1a\xe3\xe3\xe3\x84\x61\x88\x65\x19\xf4\xfb\x91\x9c\ -\xe1\x27\x29\xbd\x6e\x40\xce\x71\x06\x59\x7e\x7a\x7a\x0c\x45\xd1\ -\xf0\xfd\x98\x76\xbb\x37\x38\xd0\x84\x10\x54\xca\x36\x7e\x70\xdf\ -\xa2\x34\x8e\x13\xe2\x58\x8a\xd8\xf7\xfb\x7d\x48\x35\xe2\x04\xa2\ -\x38\x64\x63\x63\x1d\x4d\xd7\x28\x95\x8a\xd8\x8e\x86\x65\x41\xb7\ -\x9f\xb2\x5a\xdb\xc4\x30\xac\x4c\xe9\x56\xe7\xe2\x07\x1f\xf0\x4b\ -\x2f\x7c\x81\x95\x5a\x07\xc7\x34\x39\x76\xf4\x28\xc3\xa3\x23\x5c\ -\xb9\x7e\x95\xcd\x56\x83\xae\xdf\xa3\xb3\xb4\x22\xd1\x3d\x9a\x8a\ -\x62\x9a\x68\xa6\x86\xd0\x14\xb0\x4c\x9c\x5c\x0e\xc3\x34\x50\xd1\ -\x09\x36\xda\x78\xf9\x12\x23\xe3\xa3\x84\x69\x4a\xd7\xef\x10\xce\ -\x7f\x44\xbf\x51\x27\xed\x34\x50\x2d\x83\xbc\xa9\x50\x30\x54\x44\ -\xa7\x49\x5c\xdf\x60\xaa\x90\xe7\x97\xbf\xf8\x3c\x5f\xff\xe5\x5f\ -\xa0\x6a\xe9\x2c\xde\xba\xce\xee\xf1\x51\x1e\x9b\x3d\xc4\xe4\xb0\ -\xa3\x74\x37\xfb\x68\x49\x8a\x67\x1b\x28\xd9\xce\x5c\x33\xcc\xec\ -\x33\xa2\x0c\x18\x76\x42\x7c\x66\x58\x88\x8f\x32\xb2\x74\x80\xfc\ -\x29\xc5\x77\x2a\x11\x4c\xaa\xa2\x91\xcf\x39\x99\xb5\xa5\x72\x3b\ -\xe8\x49\xe7\x03\xcb\x31\x99\x1e\x19\x52\xf6\xfd\xca\x57\x78\xfd\ -\xcd\x73\xe2\xfd\xcb\x97\xa8\x16\x3c\xe6\x8e\x1f\xe7\xbb\x7f\xf8\ -\x3d\x86\x86\x86\x38\xf1\xc4\x13\xec\xdc\xbd\x8b\x28\x11\x1c\x39\ -\x74\x98\xb5\xf5\x1a\x47\x8e\x1c\x61\x71\x71\x91\x9b\x37\x6f\xf2\ -\xd6\x5b\xeb\xe4\xf3\x05\x4e\x9e\x3c\x49\x3e\x9f\xa7\xd5\x6a\xa1\ -\xeb\x15\xae\xdd\xd9\xa0\x5c\x2e\xa3\x29\x2a\xe3\x47\xf3\x1c\x4a\ -\x66\x32\x0f\xa9\x0d\x8e\x1f\x3f\xce\xa5\x0f\x2f\xb3\xb2\xb6\x82\ -\x66\x1a\xd2\x87\x79\xa9\x44\xb7\xdb\x65\x64\x64\x24\x13\x34\xe8\ -\xe1\xfb\x3e\x51\xa6\xd6\x51\xad\x56\x71\x5d\x03\x55\xb5\xb1\x2c\ -\x85\x56\x2b\x64\x71\x71\x91\xdd\xbb\x77\xe3\x38\x76\xb6\x9a\xb2\ -\x71\x5d\x5d\x0a\x01\x44\x29\xf3\xf7\xd6\x59\x5d\x5d\xc5\x71\x1c\ -\x4a\xa5\x12\xb9\x9c\xf4\x99\x92\xaa\xb0\x0a\x9a\xa2\x65\x0c\x2c\ -\x8b\x38\x8e\x29\x95\x4a\x24\x49\x42\xbf\x0f\xdd\x6e\x9a\x01\x51\ -\x74\x34\x4d\x45\x4f\x35\x9a\xcd\x26\xcd\x66\x93\x6b\xf7\xd6\xf9\ -\xe8\xee\x5d\x88\x04\x61\x2a\xd8\xbf\x7f\x3f\x4f\x1f\x9f\xe3\xc5\ -\x97\x5f\x22\x48\x15\x0a\x3b\x46\x68\xc5\x29\x85\x72\x95\x5e\x90\ -\x20\x48\x28\x96\xcb\x18\x9a\x46\xb7\xdb\xa5\xdb\x6a\x42\x90\xa0\ -\x3b\x16\xbd\x6e\x93\xd6\xdb\xb7\xa1\xe0\xa1\x38\x26\xa5\x7d\xbb\ -\xe8\xb4\x36\x31\x94\x14\x53\xa4\x28\xfd\x0e\x69\x18\x31\x55\x2d\ -\xf1\xec\xd3\x5f\xe2\xb1\x7d\xfb\x10\x1d\x9f\xb3\x3f\xf8\x01\x65\ -\xd7\xe4\x6b\xbf\xfa\x82\x92\x26\xcc\xa4\x21\xa7\x1d\xc0\x2b\x3b\ -\x52\xd2\x35\xc9\x5a\x2f\x2d\xfb\x98\x27\x09\xa4\x09\x18\xd2\xf8\ -\x5c\xa4\x82\xcf\x4b\x71\xfd\x33\xde\x23\x7f\xca\x66\x0b\x09\x7e\ -\xdf\xe2\xf0\xe6\x8b\x05\xfa\xdd\x1e\x8e\x9b\x23\x8a\x12\x0c\x43\ -\x63\x61\x71\x55\x8c\x4f\x8c\x2a\xad\x56\x7f\xc6\x2b\x38\xb7\x05\ -\xd0\xee\x45\xdf\x78\xf5\xf5\x37\xfe\x4b\xb1\x5a\x61\x7e\x7e\x1e\ -\xcb\xf5\xd0\x0d\x13\x45\xd7\x50\x75\x83\x6e\xbf\xcf\x9e\x3d\x7b\ -\x88\x92\x98\xc9\xc9\x49\xc2\x28\x61\x73\xb3\x49\xbb\xdd\x1e\x08\ -\xdc\x1f\x3c\x78\x90\xd9\xd9\x59\xa9\x3e\x62\xc3\xfa\x7a\x6f\xc0\ -\x7e\x7a\xfd\xf5\xd7\x39\x71\xe2\x84\x9c\xb4\xdb\x26\x9a\x29\x01\ -\x1c\x5b\x81\xdb\x6c\x36\xb9\x78\xf1\x22\x43\x43\x43\xb8\xae\x9b\ -\xb1\x9e\xa4\xf5\x6b\xa7\xd3\x21\x49\x12\x8a\xc5\x22\x9e\xe7\xf1\ -\xea\xab\xaf\x32\x37\x37\x37\x80\x61\x6a\x9a\xc6\xc8\xc8\x08\x9e\ -\xe7\x91\xcb\x49\x0b\xcf\xd5\xd5\x55\x4c\xd3\x1c\xf4\xc8\x5b\x3f\ -\xa7\xdd\x6e\xd3\x6b\x77\x07\x90\xce\x2b\x57\xae\xb0\x67\xdf\xbe\ -\xc1\x0a\x2f\x4a\xe2\x01\x8f\x3a\x88\xa3\x01\xc8\x64\x6d\x6d\x8d\ -\xd1\xd1\x51\x8e\xcc\x1e\xc2\x14\xd0\x0b\x02\x9c\x61\x8f\xf5\x10\ -\x5a\x3a\xfc\xde\xf7\xff\x9a\x17\xbf\xff\x7d\xf0\x8a\x54\x27\x77\ -\xd3\xea\xf9\xc4\x89\xc0\xb6\x2c\x34\x34\x3a\xed\x36\xb4\x3b\x52\ -\x72\x44\x37\x19\xaa\x54\x81\x94\x42\xd1\xa3\xdd\x6e\xd0\xef\xb5\ -\xe8\xd4\x56\x29\x15\x1c\xfc\x66\x9d\xa3\xbb\x77\x72\x70\x72\x92\ -\xaa\x69\x31\x9c\xb3\x38\x38\x35\xc5\x81\xe9\xdd\x0c\x17\xdd\x77\ -\xf3\x39\x4e\xfa\xbe\xc0\xb5\x15\xc2\x7e\x4a\xec\xf7\x29\x95\x5c\ -\x9a\xeb\x1b\x14\x2b\x65\x09\x38\xd1\x95\x8c\xfb\x1e\x23\x54\x4d\ -\xd2\x0f\x1f\x58\x0a\x3f\xca\xc8\x9f\xfd\x37\x98\x01\xed\xf3\x85\ -\x02\x7e\xaf\x8f\x93\xcb\x49\x0d\x62\x5d\x23\x8d\x13\x26\xc6\x86\ -\x95\x30\x88\x28\xe5\x9d\xdb\x42\x40\x10\xa7\x14\x73\xc6\x99\xd3\ -\x3f\xf7\xdc\x19\xd5\x50\x99\xd9\xbd\x53\xbc\x7f\xfe\x03\x3e\x9a\ -\x9f\xe7\xc9\x67\xbe\x40\xa3\xd5\x26\x08\xfa\x9c\xfd\xf1\x1b\xec\ -\xdd\x7f\x90\x66\x3e\x4f\x9c\x08\x4a\xa5\x02\xae\xeb\x30\x3e\x3e\ -\x8a\xe3\x58\x83\x61\x59\xbb\x2d\xe9\x8b\x9e\x97\xe7\xc0\x81\x03\ -\x24\x22\x25\x5f\x2c\x90\x22\x28\x14\xe4\x10\x2c\x88\x63\x1c\x47\ -\xa7\xd1\x08\x99\x9e\xac\xd2\x2c\x16\xa5\xfa\xa6\x65\x31\x3a\x3a\ -\x9a\x29\x8d\xe4\x07\xf4\x47\xcb\x52\xd9\xd8\x68\xa1\xeb\x3a\x5f\ -\xf8\xc2\x17\x38\x74\xe8\xd0\x40\xa8\xae\xdd\x6e\xd3\x6e\xb7\x59\ -\x5a\x5a\x22\x0c\x25\x45\x72\x65\x65\x05\x55\x55\xd9\xd8\xd8\x18\ -\x04\x66\xa1\x50\xc0\xf3\x3c\x46\x8e\x0c\x0f\x78\xcf\xaa\xaa\x72\ -\x64\x6e\x2e\x9b\x6a\xcb\x32\x3c\x8c\x23\x6c\xdb\xc6\xf7\x7d\x6c\ -\xd7\x46\xd7\xe1\x7b\xdf\xfb\x33\x4e\x9c\x38\x86\xa1\x80\x11\x83\ -\xeb\x1a\xf4\x13\x08\xdb\x01\xd5\x61\x0b\x2d\x89\xa0\xd9\x62\x72\ -\xff\x21\x16\x96\x97\x50\x9c\x1c\x22\x55\xe8\x37\x1b\xd2\xa6\xd2\ -\xb2\xd0\x73\x39\x34\x91\x52\x74\x1c\x34\xe1\xa3\x00\x6b\x1f\x5d\ -\x27\x67\xea\x74\x16\xe7\x29\xd9\x06\x93\x96\xc7\x57\xfe\xe9\xaf\ -\x62\xc4\x01\x13\xe5\x02\xc7\xf7\xef\xe7\xc0\xe4\xd0\x37\x6d\x38\ -\xa3\x01\x69\x24\x30\x51\xe8\x07\x7d\x34\x33\x87\xdf\x69\x31\x34\ -\x54\xc2\xef\x76\x29\x56\xcb\x24\x41\x80\x66\x6f\xe3\xbb\xdb\xe6\ -\x03\xe0\x4a\xf1\xf9\x89\xe3\x9f\xfd\x8c\x2c\x3e\x75\x1b\x90\x3e\ -\xf8\xc2\x4f\x5b\x81\x29\xf7\x59\x59\x49\x76\x59\x0c\xdc\x9e\x5f\ -\x14\xef\x9e\xbf\x40\xdf\x0f\x99\xda\x29\xd1\x5a\x9b\xed\x36\xed\ -\x7e\x8f\x9c\x97\xc7\xf7\xa5\xb2\xe5\x50\x06\x08\x89\xa2\x84\x7c\ -\x3e\x4f\xa1\x50\x40\x51\x14\xba\xdd\x3e\x77\xef\xde\x45\xd7\x75\ -\x6a\xb5\x1a\x8b\x8b\x8b\x4c\x4c\x4c\xf0\xf8\xf1\x13\xf8\xbe\x4f\ -\x1c\xc7\xec\x9d\x19\x63\x71\xb9\x99\x11\x36\xe0\xdc\xb9\xf7\x39\ -\x76\xec\xd8\x20\x13\x4a\xfc\x74\xd6\xe2\x65\x3d\xde\x4b\xff\xf7\ -\xaf\xf8\xf2\x97\x5f\x20\x0c\x93\x81\x40\xc1\x16\x11\xc3\xb2\x4c\ -\xe2\x38\x61\x61\x61\x01\x45\x51\x18\x1e\x1e\x1e\x18\x91\x6b\x9a\ -\x4a\x98\x99\xa4\x0b\x21\x30\x1d\x83\x57\x5f\x7d\x23\x13\x4e\x50\ -\x33\xe3\x77\x87\x28\x8a\xb3\x15\x8d\x32\x78\x8f\x8b\x8b\x8b\x54\ -\x2a\x15\xf2\x9e\x47\xc9\x32\x59\xdb\x68\xe0\x0b\x68\x26\x29\xf3\ -\x9b\x0d\x5e\xfc\xd1\x8f\x78\xf5\xd5\x37\xc9\xef\x3f\x48\xbb\xdf\ -\xc7\x2c\x56\x29\x96\x2b\xf8\xfd\x00\xbf\xd3\x27\xea\x74\x71\x72\ -\x2e\x79\xc7\x22\xf4\x9b\x34\x37\x56\xa8\xb8\x79\x0c\x52\xfc\xfa\ -\x06\x47\xf7\xec\xe1\xc9\xa3\x87\xd0\xc2\x3e\x15\xd3\xe4\x89\xb9\ -\x43\xcc\x1d\xdc\xfd\x4d\x27\x0b\x60\xc9\x49\x4f\x09\xe3\x10\x53\ -\x33\x41\xa8\x19\x02\x90\xfb\xcf\x22\xbb\xef\xda\x83\x2b\x4b\xf1\ -\xd0\x40\xf4\xd1\xd4\xfa\x67\x74\x2e\x76\x3f\xa0\xd3\x6d\x3d\x76\ -\xba\xed\xeb\x32\x58\xb6\x6e\x77\x2f\x4a\x30\x0d\x8d\x7d\xd3\x13\ -\xca\xee\xe9\x09\x9a\x9d\xbe\xd8\x68\x6c\x72\xfb\xf6\x5d\x6e\xdd\ -\xb9\xcd\xf8\xd4\x34\x96\xa9\x71\x68\x76\x0e\x05\x59\x9e\xae\xd6\ -\xd6\x32\x66\x52\xc4\xe4\xe4\x24\x4f\x3e\x76\x14\x2f\xe7\x61\xda\ -\xfb\xb0\x4c\x8b\x99\x60\x0f\x1f\x7e\xf8\x21\x27\x4e\x1c\xe3\xec\ -\x1b\x6f\x51\x2e\x97\x07\xb0\xce\x52\xa9\x44\xa3\xd1\x60\xff\xfe\ -\xfd\xcc\xcf\xcf\xb3\x77\xef\xde\x01\xbb\x69\x0b\x6a\x29\xd1\x5e\ -\x06\x96\xa5\x65\x38\x6a\xa9\xc3\x95\x64\x56\x29\xda\x7d\x2b\x40\ -\x7c\xdf\x1f\x50\x20\x4d\xd3\xcc\x50\x62\x0c\x94\x3e\x0b\x05\x5b\ -\xfe\x1d\x28\x16\x8b\xac\xac\xac\x90\xcb\xe5\x06\xdc\xec\x2d\x55\ -\xce\x95\xd5\x55\x6c\xdb\xe6\xea\xd5\xab\x4c\x4d\x4d\x71\xed\xda\ -\x35\xfc\x7e\x9f\xb2\xeb\xa2\x6a\x06\x86\xeb\x91\x18\x16\x87\xf6\ -\xce\x30\x73\x71\x07\xea\x97\x5e\xe0\xc6\xe2\x12\xa5\xd1\x11\x22\ -\x45\xa3\x57\xaf\x51\xf0\x8a\xe8\x5a\x8a\x59\x70\x69\xd5\x9b\x74\ -\x1b\x21\xe3\x13\x25\x0a\xc2\x65\xa4\x54\x64\xb2\x52\x66\x22\x7f\ -\x9c\x67\x8e\x1d\xe3\x89\xd9\x3d\x18\x51\x4a\xd4\x6c\x32\x5a\xc9\ -\x2b\x1e\x90\x8a\x98\x38\x0a\xc0\xd0\x50\x15\x05\x5b\x57\xa4\x7d\ -\xcc\x36\x0f\x32\x91\xd9\xfc\x6e\x2d\x32\xd4\x6d\xb7\x3c\xfd\xc4\ -\xad\xc6\xa3\x8c\xfc\x99\xca\xc8\x9f\x1c\xb7\xe9\xa7\xec\xa0\x3f\ -\xe9\x42\x75\xb0\x83\xde\xe2\x5c\x85\x71\x8c\x1f\xc6\xa7\x53\xc4\ -\x69\x4d\x37\xce\x68\xa6\x7e\x5b\xcf\x32\xf6\x85\x6b\xd7\xc5\x8d\ -\xdb\x77\x88\xe3\x98\xd1\xb1\x1d\x8c\x8c\x8c\x50\x19\x1e\xa2\xd7\ -\xeb\x71\xf5\xda\x75\x4c\xd3\xa4\xb6\x51\xa7\xdf\xef\x23\x14\x85\ -\x9f\xfb\xb9\x2f\xb1\xbc\xbc\xcc\x7a\x7d\x83\x1d\x3b\x76\x30\x5a\ -\x19\xc1\xf3\x74\x92\x04\x5a\xad\x3e\xc3\x55\x87\x8d\xcd\x80\x8b\ -\x17\x2f\xb2\xb8\xb8\xc8\xec\xec\xac\x94\x07\xce\xb2\x72\x18\x86\ -\xf4\x7a\xbd\xc1\x2e\xf8\xfc\xc5\x0f\x98\x9b\x9b\x1b\x50\x11\x75\ -\x5d\x1f\xc8\x02\x39\x8e\x33\x80\x8e\x6a\x9a\x46\xb1\x58\x1c\x5c\ -\x1f\x45\xd1\xe0\xb9\xd9\x6c\x12\xc7\x31\xbd\x5e\x6f\xa0\x3f\x16\ -\x86\x21\xf3\xf3\xf3\x4c\x4f\x4f\x63\x18\x06\xae\xeb\xd2\xef\xf7\ -\xb9\x78\xf1\x22\xcf\x3c\xf3\x4c\xa6\x01\x6e\xd3\x6b\x87\x38\x8e\ -\x09\x3a\x2c\xae\xb6\x71\xab\x79\x2e\x5c\xfd\x08\xa3\x58\xe2\xd2\ -\xed\xdb\xbc\xf5\xc1\x45\xae\xdd\xb9\x43\xbb\xd5\xc1\xaf\xd7\x29\ -\x8d\x8e\x21\xc2\x98\x9d\xe3\x53\xb8\x8e\xce\xb1\x13\x7b\x71\x4c\ -\x85\x89\x72\x85\x89\x52\x85\x31\xd7\x63\xd7\x50\x95\x61\x13\x25\ -\x69\x87\x14\x3c\x33\xab\x81\xe3\x41\x9d\x24\x54\x91\x55\x4b\x02\ -\x0d\xf3\x63\x59\x55\x6c\x3b\xaa\x15\xb4\x07\x70\x05\x0f\x9f\xeb\ -\x8f\x02\xf9\x33\x1f\xc8\xe9\xc7\x7a\xa1\x07\x7b\xa2\x4f\x28\xb9\ -\x95\x07\xcb\xec\x2d\xe3\xf6\xf4\xa1\x0f\x47\x0a\x04\x51\x48\x8a\ -\x32\x23\x34\x6d\x26\x88\xa2\x1f\xdd\xbd\x3b\x4f\xad\x56\xc3\xb4\ -\x2d\xa2\x58\x2a\x60\xe6\xf2\x05\x4c\xcb\x62\x7a\xf7\x6e\x4a\xae\ -\x45\x20\xe0\x95\xd7\x7e\x4c\xa1\x50\x60\xb3\xd9\xa4\x5e\x6f\x60\ -\xe9\xd6\xa0\x7c\xbe\x73\xe7\x0e\xa7\xff\xd1\x29\xee\x2d\x37\x99\ -\x18\x2f\xf2\x83\x1f\xbe\xce\xd1\xa3\x47\xa5\x43\x85\x25\x83\x7d\ -\x8b\x6f\xac\xeb\x3a\xaa\x0a\x1f\x5c\xfe\x90\xc9\xc9\x49\x72\xb9\ -\xdc\x20\x18\xb7\xd8\x5a\x5b\xe0\x92\x5a\xad\x86\x6d\xdb\x8c\x8d\ -\x8d\x49\x6b\x51\xcb\x1a\xe0\xae\x47\x46\x2a\x74\x3a\xfe\xc0\xdf\ -\xaa\x58\x2c\x52\xa9\x54\x32\x31\xfb\x94\x4a\xd9\xe6\xde\xc2\x06\ -\xa5\x92\x84\x50\x5e\xba\x74\x89\x63\xc7\x8e\x65\x5b\x3f\x85\xf5\ -\xf5\x35\x9c\x9c\x87\xa1\x19\x5c\xbf\x79\x8b\xf7\xce\x7f\xc0\x8e\ -\x5d\xbb\x88\x35\x1d\xab\x54\x44\x73\x5d\xae\x5c\xbf\xc1\x1b\x6f\ -\xfd\x18\xcf\xc9\xa1\xa4\x82\x13\x47\xe6\xd8\x31\x34\xc2\x81\x7d\ -\xbb\xb9\x75\xe7\x12\x13\xa3\xc3\x4c\x8e\x8c\x30\x9a\xf7\xa8\x6a\ -\xca\x37\x5d\x38\x63\x6f\x41\xf0\xc3\x50\xee\x9e\x55\xc0\xd6\x07\ -\x37\x30\x22\x26\xcd\xfc\x9d\xb7\x4f\x9e\xc5\xc7\x8e\xef\xfb\x81\ -\xac\x7c\x42\x33\xf5\xa8\x47\xfe\xcc\x04\x72\xfa\xa9\xaf\xd9\x86\ -\xd0\xfe\x58\x71\xa5\xfc\x94\xeb\x05\x03\x6d\x74\x62\x91\x4a\xfb\ -\x93\xcc\x65\x62\x3b\xa9\x3c\x05\x7a\x7e\x44\x10\x85\xf5\x62\xde\ -\xad\x74\xc2\xe4\x77\x96\x97\x97\xbf\x15\x09\x78\xed\xf5\xd7\x49\ -\x04\xcc\x1e\x39\x4c\x92\x0a\xca\x43\x55\xa9\xf1\x55\x2c\xf2\xda\ -\x6b\x6f\xf0\xd4\x17\x9e\xe1\xce\x9d\x8f\x88\xa2\x88\x62\xb1\xc8\ -\xad\x5b\xb7\x30\x0c\x83\x6e\xb7\xcb\xe3\x8f\x3f\xce\x85\x0b\x17\ -\x98\x99\x99\x61\x7c\x7c\x7c\x40\xbe\x97\x2c\x26\xf0\xfd\x90\x9b\ -\x77\x6e\x93\xcf\xe7\xd9\xb1\x63\x07\x86\xa1\x90\x24\x03\x9f\x6f\ -\xa2\x28\xc2\x71\x0c\x96\x96\xd6\x24\x4a\xab\x54\x1a\x88\x0a\xd8\ -\xb6\x95\xbd\x4e\x12\xe8\xcb\x65\x97\xd7\x5e\x3b\xcb\xd1\xa3\x47\ -\x07\x28\xb2\x91\xaa\x87\x02\x6c\xd4\x7b\x74\x3a\x1d\x6c\xdb\xe6\ -\xcf\xff\xfc\xcf\x79\xf6\xd9\x67\xb9\x7b\xf7\x2e\x86\x6d\xe1\xb8\ -\x76\x66\x5e\xa7\x51\x29\x14\xf9\xe8\xce\x3c\xcf\x3d\xff\x24\x1b\ -\xcd\x08\x3d\x67\x70\x6d\x7e\x81\xb7\xdf\x7b\x97\x46\xa3\x81\xaa\ -\x08\x9e\x7f\xfa\x59\x8a\x8e\xcb\xae\x1d\xe3\x68\x0a\x98\x16\xb8\ -\x2a\xef\xea\xf0\x6d\x00\x53\xf0\x92\x08\x22\xb4\x38\x24\x67\x1a\ -\x72\x75\x94\xc6\x90\x26\x08\x55\x21\xd5\x14\x52\x21\x24\x44\x13\ -\x45\x02\x7e\xb6\x01\xfb\x44\x76\xf0\xde\x3f\xc0\xb5\x41\xc0\x3e\ -\x80\x9b\x16\x9f\xaf\x48\xfe\x99\x87\x68\x3e\x18\xc8\xea\x27\x8d\ -\xb9\x3e\x31\x40\xef\x63\xc1\xd2\x9f\x7a\x3f\xd3\x6d\x3e\x3e\x4a\ -\xb6\x97\x56\x54\xa9\xf6\xd1\xef\x05\xd8\xa6\x43\xbf\x1f\x9c\xce\ -\x17\x0b\x2f\x29\x72\xc3\x41\xa2\x48\x56\xdc\xfa\x46\x43\x98\xae\ -\xc3\xd2\xf2\x2a\x97\xae\x7c\xc8\xe4\xd4\x4e\xfc\x30\x20\x88\x62\ -\x1a\xad\x26\x39\xaf\xc0\x66\xb3\xc5\xcc\x9e\x7d\x8c\x8c\x8c\xe0\ -\xba\x36\xad\xcc\xeb\x28\x9f\xf7\x38\x7b\xf6\x1c\x41\x10\x50\xad\ -\x56\x51\x14\x85\x5a\xad\x46\xbf\xdf\xa7\x58\x2c\x0e\x04\xf7\x12\ -\x24\xb0\x63\x6a\x6a\x4a\x4e\xc0\x33\x3c\xb6\x69\x9a\x92\x84\x20\ -\x04\x6b\x6b\x6b\x18\x86\xc1\xf0\xf0\xf0\x36\x1a\xa3\xe4\x38\x3b\ -\x8e\x25\x1d\x25\x4c\x93\xd7\x5f\x7f\x9d\x67\x9f\x7d\x96\x4e\xa7\ -\x33\x50\xde\x0c\xfb\x52\xfa\xd7\x71\x1c\x5a\xad\x16\xeb\xeb\xeb\ -\x3c\xfd\xf4\xd3\x14\x0a\x05\xdc\x82\xcd\xfc\xb2\x34\x87\xef\x6d\ -\x36\x31\x84\xc2\x85\x73\xef\x13\x06\x01\xa3\x63\x63\xa8\x96\x81\ -\x9e\xb3\xe9\x07\x3d\x3a\xfd\x1e\x47\x0f\x1d\xa2\xec\xe6\x19\x76\ -\x2d\x45\x24\x60\x6a\xb2\x3d\xd1\x80\x28\x4e\x51\x85\x20\x67\x68\ -\x59\xc0\x3d\xe4\xbd\x9d\x49\x00\xc5\xa9\xbc\xe3\x9a\xae\xa3\xa2\ -\xa0\x8a\x64\xf0\x5a\x29\x09\xf5\x60\x20\xab\x03\x53\xdf\x6d\xac\ -\xa5\x87\xab\x30\xe5\x51\x20\x7f\x46\x02\x59\xfc\x94\xfc\xaa\x0e\ -\x4a\xe4\x87\x33\xb4\x34\xfe\x4c\x3f\xe1\x08\xd8\x7e\x9f\x33\xe9\ -\x35\x91\x12\x87\x11\xa0\x60\x5a\xdb\xdc\x25\x13\x4d\xca\x62\x18\ -\x3a\xe8\x1a\x49\x10\xc9\x95\x47\x36\xed\xde\xd2\x7b\x6a\xfa\xd1\ -\x3b\xcd\x56\xe7\xf1\xf2\x50\xf9\x3b\x8d\x66\xf7\x5b\xa6\x6d\xb1\ -\x5e\xdf\xe4\xda\xad\xbb\xd4\xd6\xeb\xf8\xbe\xcf\xd8\xd8\x18\xad\ -\x56\x8b\xe7\x9e\x7b\x8e\x7a\xbd\x8e\xae\xeb\x2c\x2e\x2e\x32\x3c\ -\x3c\xcc\xe8\xe8\x28\x8e\x23\x67\x93\x61\x28\xe8\x74\x24\xb1\x61\ -\x69\x75\x85\xd5\xd5\x55\x76\xed\xda\x85\x10\x82\x28\x92\x92\xb1\ -\x9e\xe7\x49\x19\x9d\x38\x66\x75\x75\x15\xcb\xb2\x18\x1b\x1b\x43\ -\xd3\xb4\x81\x07\x71\xaf\xd7\x03\xa4\xb0\x60\x14\x45\x2c\x2e\x2e\ -\xca\x15\x59\x92\x30\x3d\x31\x39\x38\x0c\xb6\x64\x79\xce\x9f\x3f\ -\xcf\xec\xec\x2c\xed\x76\x1b\x21\x04\x0b\xcb\x0b\xa4\x86\xa0\xb6\ -\xb6\x46\x63\x79\x8d\x3d\x3b\xa6\x98\xdb\xbb\x8f\x6a\xb1\xcc\xe8\ -\x48\x41\x69\x76\x82\x17\x15\x53\xbf\x9d\x92\x9c\x76\x4c\xf3\xa4\ -\x82\xf4\x8f\x0a\xfc\x0e\xae\x6e\x4a\x3e\x32\x06\x71\xc6\x33\xd7\ -\x0c\x55\x3a\x69\x00\x61\x1a\x12\x46\x91\x9c\xc8\x5a\x36\xda\x56\ -\x89\x2c\x1e\x3c\x91\x4d\x75\x8b\xd3\xae\x0e\x02\x72\x7b\x4b\x34\ -\x28\xa1\xb7\x07\xb0\xd8\x76\x9a\xab\x8f\x02\xf9\x33\x98\x91\xb7\ -\x07\xaa\xfa\xd0\x57\xd4\x4f\xec\xa9\xb7\x84\x0b\xd4\x87\x69\x92\ -\xd9\x73\x92\x64\x86\xdb\x8a\x2a\xdd\x0e\x80\x24\x96\x9c\x59\x55\ -\xd1\x48\xfa\x11\x9a\x93\x03\xa1\x20\xa2\x10\xc5\xb6\x48\xc2\x98\ -\x5e\xe0\x93\x2f\x78\xc4\x29\x74\x03\xe9\x6b\x64\xe8\x52\x16\x27\ -\x0c\xe3\x6f\x38\xb6\x7e\x66\xbd\xd9\x13\xa5\x62\x4e\xb9\xbb\xb4\ -\x29\xa4\x78\xdf\x18\x61\x18\x52\xab\x6f\x50\xab\xd5\xb0\x2c\x8b\ -\x8d\x8d\x0d\xfc\x30\x40\x08\xc9\xa0\xca\x39\x5e\xe6\x19\xe5\x60\ -\xbb\x39\x5a\x9d\x36\xf7\x16\x16\x98\x3d\x70\x08\x55\x97\xa5\x80\ -\x6e\x6a\x94\x8b\x15\xc2\x38\x40\x11\x2a\x4b\x2b\x8b\x18\x9a\xc9\ -\xd0\x48\x15\x4d\xd1\x89\x92\x90\x38\x4c\x68\x77\xa5\x44\x90\x69\ -\xe9\xdc\xbc\x79\x93\x7c\x3e\x4f\xb5\x5a\xa5\xd7\xe9\x32\x3e\x3e\ -\xce\xa5\x0f\x2e\xd2\x68\x34\x28\x95\x0b\xb4\x9a\x1d\x7a\x9d\x16\ -\x87\x0f\x1f\xa6\xdb\xed\x92\xcf\xe7\x19\x1e\x1b\x41\x37\x35\x7a\ -\xdd\x36\x63\xa5\x2a\xae\x6e\xe2\x69\xba\xe2\x5a\x1a\xdd\xb6\x8f\ -\x9b\xb7\x89\x85\x8c\xa2\x30\x8d\x31\x55\x15\x92\x48\x2a\x7e\x24\ -\x49\x56\x0f\x9b\x0f\x64\x45\xdf\xef\x93\xaa\x60\x6d\xd3\xca\xda\ -\x8a\xb9\x28\x11\x90\x08\x74\x5d\x45\x93\xba\x12\xe8\xea\xb6\xda\ -\x4b\xd9\x1e\xe3\x0f\x89\xf1\x88\x8f\x1f\x02\x9f\x27\x50\xc8\xe7\ -\x00\xd9\x95\xfe\x84\xd2\x59\xfd\x5b\x88\xb0\xa4\xdb\x44\xd5\x1e\ -\x7e\xfe\xb4\x26\x5d\xfd\xe9\xeb\xae\x87\x06\x65\x1f\xbb\x3c\xdb\ -\x07\xa7\x59\xd9\x2e\x3f\xab\x82\x14\x31\x23\x84\x98\x59\x5b\xaf\ -\xff\xa8\xdb\xef\x81\xa6\xca\x72\x5a\xd1\xd8\xdc\xdc\xa4\xdb\xed\ -\xa2\xa8\x1a\xcd\x4e\x97\x4e\xaf\x8b\xae\x18\x14\x2b\x05\x74\xc5\ -\xa0\xd1\xde\x24\xe8\x85\x68\xa6\x4a\xa7\xd9\xa5\x17\x74\x21\x51\ -\xc8\xe5\x1d\x5c\xdb\x43\x35\x14\x0c\xd5\xc4\xca\x99\xe4\xf2\x39\ -\x16\x16\x17\xe9\x75\x3b\x54\x2a\x15\xca\x05\xa9\xe2\x69\x99\x3a\ -\xe5\x42\x91\x52\xa1\xc8\xca\xea\x12\xbd\x4e\x9f\x4a\xb1\x40\xa5\ -\x5c\x46\x55\xd5\x77\x35\x94\x33\xa6\xa9\x9f\x31\xb6\x51\xc9\xf5\ -\x4f\x48\x70\xe2\xd3\x66\x12\x0f\xff\xfe\x94\x8f\x5f\x97\xfe\x84\ -\x8a\xe9\x6f\xdd\xef\x8a\x9f\x7e\x9f\x1e\x05\xf2\xa3\xc7\xdf\xed\ -\x1c\xca\xb2\x83\xb8\xef\x67\x76\x1f\x8c\x22\xa0\xe7\xf7\x5f\x14\ -\xa8\x33\xb6\x6b\x9d\x54\x81\xae\x1f\xd5\x83\x20\x28\xa3\xe9\xc4\ -\x51\x4a\x3f\x90\x54\x48\xcf\xf3\xd0\x75\x7d\x80\xcf\xd6\x34\x8d\ -\x56\xab\x35\xe8\x9b\x5d\xd7\x1d\x08\xfd\x49\x69\x1d\x9d\x54\x93\ -\x6a\x1f\xbe\xef\x53\x70\x3d\xe9\x62\x91\xc6\x68\x8a\x8a\xeb\x58\ -\x5f\xb6\x55\xf5\xa5\x4e\xb7\xff\x4e\x18\x04\x8f\xe7\x72\xce\x97\ -\x1d\xcb\x7a\x69\xcb\xcf\x5b\xd7\x64\xeb\xa1\x6c\xc9\xde\x7c\xce\ -\x18\x45\x8f\x02\xf9\xd1\xe3\x6f\x33\x76\xff\x58\x86\x78\x58\xef\ -\x3b\x46\x66\x6a\x35\x63\x74\x6d\x87\x40\xa8\xd9\xd7\x85\x90\x90\ -\xe2\x87\x71\x2f\x51\x0a\x41\x10\xd6\x85\x10\x65\xd3\x34\xbf\xac\ -\xeb\xca\x4b\x5b\xb7\x5c\xcd\x5e\x9c\xc8\xef\xff\x0d\x53\xe1\x8c\ -\xba\xed\x7c\xd1\x1f\xea\x31\xb7\x7e\xbe\x40\x12\x9b\xa4\x22\xd3\ -\xfd\x37\xf0\x28\x90\xff\xfe\x1e\xff\x0f\x7c\xda\x6f\xe0\xe9\x28\ -\x97\x5f\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\ -\x00\x00\x01\x4e\ -\x89\ -\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ -\x00\x00\x08\x00\x00\x00\x0c\x08\x06\x00\x00\x00\x5f\x9e\xfc\x9d\ -\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\ -\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x01\x23\x00\x00\x01\x23\ -\x01\x72\x41\x77\xde\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\ -\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\ -\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x00\xcb\x49\x44\ -\x41\x54\x18\x57\x7d\x90\x49\x0a\x02\x31\x10\x45\xb3\x4b\x15\x24\ -\xd1\xbd\x20\x2e\xbc\x42\x12\xd0\x8d\x08\xde\x46\x70\xeb\xd2\x03\ -\x08\x9e\x40\x57\x6e\x14\xc4\x09\x6d\x71\xc4\x09\xa7\x43\xb5\xdf\ -\x01\x69\xa1\x75\xf1\x29\x52\xf5\xa8\xff\x53\xc2\x2b\xaa\x16\x84\ -\xa0\x30\x0c\x45\x9c\x84\xd7\xb4\xb5\x9a\x9a\xb9\x24\xa5\x63\x01\ -\xa7\x69\x07\x68\x89\x3a\xf0\x09\x59\x8c\x03\xf6\xd0\x0a\x5b\x66\ -\x4e\xd1\xc8\x1b\x2e\x67\x85\x90\x51\xe0\x00\xad\xa1\x99\x55\x34\ -\x76\x9a\x7b\x4e\x71\xdd\x33\xa7\x9e\x80\x55\xf2\x88\xe1\x06\x9a\ -\x3b\x43\x13\xd8\xf5\x01\x75\x50\x9b\xe8\xe5\x85\x33\xf2\xf4\x08\ -\x8a\xc7\x02\x9a\x3e\xb2\x58\xcd\x5d\xd8\xb5\x5e\x80\xe6\x73\x24\ -\x68\x80\xc1\xd0\x1a\x6e\x7c\x2c\x00\x5c\xa2\x41\xbd\xe6\xca\x57\ -\x48\xac\xbb\xbe\x83\x06\xd6\xc8\x52\xdc\x37\x6f\x4e\xcb\xb6\x4b\ -\x50\xe6\xd7\xa1\x6a\xff\x4e\x7d\x07\x92\x57\x9f\x99\x89\xc4\x79\ -\xa9\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\ -\x00\x00\x50\x2b\ -\x2f\ -\x2a\x20\x58\x50\x4d\x20\x2a\x2f\x0a\x73\x74\x61\x74\x69\x63\x20\ -\x63\x68\x61\x72\x20\x2a\x20\x43\x3a\x5c\x55\x73\x65\x72\x73\x5c\ -\x62\x72\x61\x64\x79\x7a\x70\x5c\x4f\x6e\x65\x44\x72\x69\x76\x65\ -\x5c\x44\x6f\x63\x75\x6d\x65\x6e\x74\x73\x5c\x44\x47\x53\x49\x63\ -\x6f\x6e\x5f\x78\x70\x6d\x5b\x5d\x20\x3d\x20\x7b\x0a\x22\x34\x38\ -\x20\x34\x38\x20\x39\x37\x37\x20\x32\x22\x2c\x0a\x22\x20\x20\x09\ -\x63\x20\x4e\x6f\x6e\x65\x22\x2c\x0a\x22\x2e\x20\x09\x63\x20\x23\ -\x44\x31\x43\x44\x44\x39\x22\x2c\x0a\x22\x2b\x20\x09\x63\x20\x23\ -\x42\x38\x42\x33\x43\x36\x22\x2c\x0a\x22\x40\x20\x09\x63\x20\x23\ -\x41\x32\x39\x42\x42\x35\x22\x2c\x0a\x22\x23\x20\x09\x63\x20\x23\ -\x39\x34\x38\x43\x41\x39\x22\x2c\x0a\x22\x24\x20\x09\x63\x20\x23\ -\x38\x44\x38\x34\x41\x34\x22\x2c\x0a\x22\x25\x20\x09\x63\x20\x23\ -\x39\x32\x38\x41\x41\x38\x22\x2c\x0a\x22\x26\x20\x09\x63\x20\x23\ -\x41\x30\x39\x38\x42\x33\x22\x2c\x0a\x22\x2a\x20\x09\x63\x20\x23\ -\x42\x33\x41\x45\x43\x32\x22\x2c\x0a\x22\x3d\x20\x09\x63\x20\x23\ -\x43\x42\x43\x38\x44\x35\x22\x2c\x0a\x22\x2d\x20\x09\x63\x20\x23\ -\x45\x34\x45\x32\x45\x39\x22\x2c\x0a\x22\x3b\x20\x09\x63\x20\x23\ -\x41\x46\x41\x42\x43\x30\x22\x2c\x0a\x22\x3e\x20\x09\x63\x20\x23\ -\x37\x45\x37\x36\x39\x41\x22\x2c\x0a\x22\x2c\x20\x09\x63\x20\x23\ -\x35\x44\x35\x32\x37\x45\x22\x2c\x0a\x22\x27\x20\x09\x63\x20\x23\ -\x34\x37\x33\x41\x36\x44\x22\x2c\x0a\x22\x29\x20\x09\x63\x20\x23\ -\x33\x46\x33\x31\x36\x37\x22\x2c\x0a\x22\x21\x20\x09\x63\x20\x23\ -\x33\x39\x32\x42\x36\x33\x22\x2c\x0a\x22\x7e\x20\x09\x63\x20\x23\ -\x33\x32\x32\x34\x36\x30\x22\x2c\x0a\x22\x7b\x20\x09\x63\x20\x23\ -\x32\x44\x32\x30\x35\x44\x22\x2c\x0a\x22\x5d\x20\x09\x63\x20\x23\ -\x32\x46\x32\x31\x35\x46\x22\x2c\x0a\x22\x5e\x20\x09\x63\x20\x23\ -\x32\x46\x32\x31\x35\x45\x22\x2c\x0a\x22\x2f\x20\x09\x63\x20\x23\ -\x32\x44\x31\x46\x35\x45\x22\x2c\x0a\x22\x28\x20\x09\x63\x20\x23\ -\x33\x31\x32\x35\x36\x33\x22\x2c\x0a\x22\x5f\x20\x09\x63\x20\x23\ -\x34\x32\x33\x37\x37\x30\x22\x2c\x0a\x22\x3a\x20\x09\x63\x20\x23\ -\x36\x45\x36\x36\x39\x31\x22\x2c\x0a\x22\x3c\x20\x09\x63\x20\x23\ -\x41\x35\x41\x30\x42\x39\x22\x2c\x0a\x22\x5b\x20\x09\x63\x20\x23\ -\x45\x31\x44\x46\x45\x35\x22\x2c\x0a\x22\x7d\x20\x09\x63\x20\x23\ -\x46\x45\x46\x45\x46\x44\x22\x2c\x0a\x22\x7c\x20\x09\x63\x20\x23\ -\x44\x41\x45\x34\x45\x38\x22\x2c\x0a\x22\x31\x20\x09\x63\x20\x23\ -\x38\x34\x41\x34\x42\x41\x22\x2c\x0a\x22\x32\x20\x09\x63\x20\x23\ -\x33\x34\x36\x41\x39\x31\x22\x2c\x0a\x22\x33\x20\x09\x63\x20\x23\ -\x33\x36\x36\x43\x39\x34\x22\x2c\x0a\x22\x34\x20\x09\x63\x20\x23\ -\x36\x34\x38\x45\x41\x44\x22\x2c\x0a\x22\x35\x20\x09\x63\x20\x23\ -\x36\x36\x38\x46\x41\x44\x22\x2c\x0a\x22\x36\x20\x09\x63\x20\x23\ -\x39\x45\x39\x38\x42\x33\x22\x2c\x0a\x22\x37\x20\x09\x63\x20\x23\ -\x35\x39\x34\x46\x37\x46\x22\x2c\x0a\x22\x38\x20\x09\x63\x20\x23\ -\x32\x38\x31\x44\x35\x44\x22\x2c\x0a\x22\x39\x20\x09\x63\x20\x23\ -\x32\x38\x31\x42\x35\x43\x22\x2c\x0a\x22\x30\x20\x09\x63\x20\x23\ -\x33\x42\x32\x44\x36\x34\x22\x2c\x0a\x22\x61\x20\x09\x63\x20\x23\ -\x33\x45\x32\x46\x36\x35\x22\x2c\x0a\x22\x62\x20\x09\x63\x20\x23\ -\x33\x33\x32\x35\x36\x30\x22\x2c\x0a\x22\x63\x20\x09\x63\x20\x23\ -\x32\x38\x31\x42\x35\x42\x22\x2c\x0a\x22\x64\x20\x09\x63\x20\x23\ -\x32\x32\x31\x36\x35\x39\x22\x2c\x0a\x22\x65\x20\x09\x63\x20\x23\ -\x32\x31\x31\x35\x35\x39\x22\x2c\x0a\x22\x66\x20\x09\x63\x20\x23\ -\x32\x32\x31\x35\x35\x39\x22\x2c\x0a\x22\x67\x20\x09\x63\x20\x23\ -\x32\x32\x31\x35\x35\x41\x22\x2c\x0a\x22\x68\x20\x09\x63\x20\x23\ -\x32\x31\x31\x34\x35\x39\x22\x2c\x0a\x22\x69\x20\x09\x63\x20\x23\ -\x32\x30\x31\x33\x35\x38\x22\x2c\x0a\x22\x6a\x20\x09\x63\x20\x23\ -\x32\x33\x31\x36\x35\x39\x22\x2c\x0a\x22\x6b\x20\x09\x63\x20\x23\ -\x34\x41\x34\x30\x37\x34\x22\x2c\x0a\x22\x6c\x20\x09\x63\x20\x23\ -\x39\x30\x38\x41\x41\x38\x22\x2c\x0a\x22\x6d\x20\x09\x63\x20\x23\ -\x39\x32\x41\x35\x42\x44\x22\x2c\x0a\x22\x6e\x20\x09\x63\x20\x23\ -\x34\x30\x37\x34\x39\x38\x22\x2c\x0a\x22\x6f\x20\x09\x63\x20\x23\ -\x34\x32\x37\x35\x39\x38\x22\x2c\x0a\x22\x70\x20\x09\x63\x20\x23\ -\x39\x35\x42\x31\x43\x34\x22\x2c\x0a\x22\x71\x20\x09\x63\x20\x23\ -\x45\x31\x45\x38\x45\x44\x22\x2c\x0a\x22\x72\x20\x09\x63\x20\x23\ -\x46\x43\x46\x43\x46\x43\x22\x2c\x0a\x22\x73\x20\x09\x63\x20\x23\ -\x45\x46\x46\x34\x46\x36\x22\x2c\x0a\x22\x74\x20\x09\x63\x20\x23\ -\x33\x45\x37\x31\x39\x37\x22\x2c\x0a\x22\x75\x20\x09\x63\x20\x23\ -\x36\x33\x35\x38\x38\x35\x22\x2c\x0a\x22\x76\x20\x09\x63\x20\x23\ -\x32\x38\x31\x43\x35\x43\x22\x2c\x0a\x22\x77\x20\x09\x63\x20\x23\ -\x32\x42\x31\x45\x35\x44\x22\x2c\x0a\x22\x78\x20\x09\x63\x20\x23\ -\x32\x46\x32\x32\x35\x46\x22\x2c\x0a\x22\x79\x20\x09\x63\x20\x23\ -\x32\x34\x31\x37\x35\x41\x22\x2c\x0a\x22\x7a\x20\x09\x63\x20\x23\ -\x32\x37\x31\x41\x35\x42\x22\x2c\x0a\x22\x41\x20\x09\x63\x20\x23\ -\x32\x45\x32\x31\x35\x44\x22\x2c\x0a\x22\x42\x20\x09\x63\x20\x23\ -\x32\x36\x31\x41\x35\x43\x22\x2c\x0a\x22\x43\x20\x09\x63\x20\x23\ -\x31\x46\x31\x33\x35\x37\x22\x2c\x0a\x22\x44\x20\x09\x63\x20\x23\ -\x32\x32\x31\x35\x35\x38\x22\x2c\x0a\x22\x45\x20\x09\x63\x20\x23\ -\x32\x33\x31\x37\x35\x42\x22\x2c\x0a\x22\x46\x20\x09\x63\x20\x23\ -\x32\x41\x31\x45\x35\x44\x22\x2c\x0a\x22\x47\x20\x09\x63\x20\x23\ -\x33\x33\x32\x36\x36\x30\x22\x2c\x0a\x22\x48\x20\x09\x63\x20\x23\ -\x32\x46\x32\x35\x36\x30\x22\x2c\x0a\x22\x49\x20\x09\x63\x20\x23\ -\x32\x33\x32\x39\x36\x35\x22\x2c\x0a\x22\x4a\x20\x09\x63\x20\x23\ -\x34\x37\x35\x39\x38\x37\x22\x2c\x0a\x22\x4b\x20\x09\x63\x20\x23\ -\x44\x33\x44\x41\x45\x31\x22\x2c\x0a\x22\x4c\x20\x09\x63\x20\x23\ -\x46\x44\x46\x45\x46\x44\x22\x2c\x0a\x22\x4d\x20\x09\x63\x20\x23\ -\x46\x45\x46\x45\x46\x45\x22\x2c\x0a\x22\x4e\x20\x09\x63\x20\x23\ -\x45\x36\x45\x44\x46\x30\x22\x2c\x0a\x22\x4f\x20\x09\x63\x20\x23\ -\x33\x35\x36\x42\x39\x32\x22\x2c\x0a\x22\x50\x20\x09\x63\x20\x23\ -\x39\x32\x38\x41\x41\x37\x22\x2c\x0a\x22\x51\x20\x09\x63\x20\x23\ -\x33\x32\x32\x36\x36\x31\x22\x2c\x0a\x22\x52\x20\x09\x63\x20\x23\ -\x32\x43\x31\x46\x35\x45\x22\x2c\x0a\x22\x53\x20\x09\x63\x20\x23\ -\x32\x32\x31\x36\x35\x38\x22\x2c\x0a\x22\x54\x20\x09\x63\x20\x23\ -\x33\x30\x32\x33\x35\x46\x22\x2c\x0a\x22\x55\x20\x09\x63\x20\x23\ -\x32\x34\x31\x37\x35\x39\x22\x2c\x0a\x22\x56\x20\x09\x63\x20\x23\ -\x32\x35\x31\x38\x35\x41\x22\x2c\x0a\x22\x57\x20\x09\x63\x20\x23\ -\x32\x43\x31\x46\x35\x43\x22\x2c\x0a\x22\x58\x20\x09\x63\x20\x23\ -\x33\x31\x32\x34\x35\x46\x22\x2c\x0a\x22\x59\x20\x09\x63\x20\x23\ -\x32\x46\x32\x32\x36\x30\x22\x2c\x0a\x22\x5a\x20\x09\x63\x20\x23\ -\x32\x30\x31\x33\x35\x37\x22\x2c\x0a\x22\x60\x20\x09\x63\x20\x23\ -\x32\x36\x31\x39\x35\x42\x22\x2c\x0a\x22\x20\x2e\x09\x63\x20\x23\ -\x32\x46\x32\x32\x35\x45\x22\x2c\x0a\x22\x2e\x2e\x09\x63\x20\x23\ -\x33\x31\x32\x34\x36\x31\x22\x2c\x0a\x22\x2b\x2e\x09\x63\x20\x23\ -\x32\x44\x32\x30\x35\x45\x22\x2c\x0a\x22\x40\x2e\x09\x63\x20\x23\ -\x33\x33\x32\x38\x36\x32\x22\x2c\x0a\x22\x23\x2e\x09\x63\x20\x23\ -\x32\x46\x32\x34\x36\x30\x22\x2c\x0a\x22\x24\x2e\x09\x63\x20\x23\ -\x32\x32\x31\x38\x35\x41\x22\x2c\x0a\x22\x25\x2e\x09\x63\x20\x23\ -\x37\x36\x36\x46\x39\x37\x22\x2c\x0a\x22\x26\x2e\x09\x63\x20\x23\ -\x44\x35\x44\x33\x44\x45\x22\x2c\x0a\x22\x2a\x2e\x09\x63\x20\x23\ -\x42\x37\x43\x41\x44\x36\x22\x2c\x0a\x22\x3d\x2e\x09\x63\x20\x23\ -\x32\x39\x36\x31\x38\x42\x22\x2c\x0a\x22\x2d\x2e\x09\x63\x20\x23\ -\x43\x46\x44\x42\x45\x33\x22\x2c\x0a\x22\x3b\x2e\x09\x63\x20\x23\ -\x44\x39\x44\x36\x44\x45\x22\x2c\x0a\x22\x3e\x2e\x09\x63\x20\x23\ -\x38\x32\x37\x38\x39\x42\x22\x2c\x0a\x22\x2c\x2e\x09\x63\x20\x23\ -\x32\x34\x31\x38\x35\x39\x22\x2c\x0a\x22\x27\x2e\x09\x63\x20\x23\ -\x32\x39\x31\x44\x35\x43\x22\x2c\x0a\x22\x29\x2e\x09\x63\x20\x23\ -\x32\x30\x31\x34\x35\x38\x22\x2c\x0a\x22\x21\x2e\x09\x63\x20\x23\ -\x33\x32\x32\x34\x35\x46\x22\x2c\x0a\x22\x7e\x2e\x09\x63\x20\x23\ -\x33\x34\x32\x36\x36\x30\x22\x2c\x0a\x22\x7b\x2e\x09\x63\x20\x23\ -\x32\x44\x32\x30\x35\x43\x22\x2c\x0a\x22\x5d\x2e\x09\x63\x20\x23\ -\x32\x32\x31\x36\x35\x41\x22\x2c\x0a\x22\x5e\x2e\x09\x63\x20\x23\ -\x32\x36\x31\x39\x35\x41\x22\x2c\x0a\x22\x2f\x2e\x09\x63\x20\x23\ -\x33\x34\x32\x36\x36\x31\x22\x2c\x0a\x22\x28\x2e\x09\x63\x20\x23\ -\x32\x39\x31\x43\x35\x43\x22\x2c\x0a\x22\x5f\x2e\x09\x63\x20\x23\ -\x33\x36\x32\x39\x36\x31\x22\x2c\x0a\x22\x3a\x2e\x09\x63\x20\x23\ -\x33\x37\x32\x41\x36\x32\x22\x2c\x0a\x22\x3c\x2e\x09\x63\x20\x23\ -\x33\x34\x32\x38\x36\x32\x22\x2c\x0a\x22\x5b\x2e\x09\x63\x20\x23\ -\x32\x44\x32\x32\x35\x46\x22\x2c\x0a\x22\x7d\x2e\x09\x63\x20\x23\ -\x32\x35\x31\x39\x35\x42\x22\x2c\x0a\x22\x7c\x2e\x09\x63\x20\x23\ -\x32\x31\x31\x35\x35\x41\x22\x2c\x0a\x22\x31\x2e\x09\x63\x20\x23\ -\x35\x41\x35\x30\x38\x31\x22\x2c\x0a\x22\x32\x2e\x09\x63\x20\x23\ -\x43\x36\x43\x33\x44\x33\x22\x2c\x0a\x22\x33\x2e\x09\x63\x20\x23\ -\x46\x44\x46\x44\x46\x44\x22\x2c\x0a\x22\x34\x2e\x09\x63\x20\x23\ -\x37\x34\x39\x38\x42\x33\x22\x2c\x0a\x22\x35\x2e\x09\x63\x20\x23\ -\x35\x37\x38\x33\x41\x33\x22\x2c\x0a\x22\x36\x2e\x09\x63\x20\x23\ -\x46\x35\x46\x37\x46\x38\x22\x2c\x0a\x22\x37\x2e\x09\x63\x20\x23\ -\x37\x34\x36\x41\x38\x45\x22\x2c\x0a\x22\x38\x2e\x09\x63\x20\x23\ -\x33\x43\x32\x45\x36\x35\x22\x2c\x0a\x22\x39\x2e\x09\x63\x20\x23\ -\x32\x44\x31\x46\x35\x44\x22\x2c\x0a\x22\x30\x2e\x09\x63\x20\x23\ -\x32\x33\x31\x35\x35\x38\x22\x2c\x0a\x22\x61\x2e\x09\x63\x20\x23\ -\x31\x45\x31\x33\x35\x36\x22\x2c\x0a\x22\x62\x2e\x09\x63\x20\x23\ -\x32\x43\x31\x46\x35\x44\x22\x2c\x0a\x22\x63\x2e\x09\x63\x20\x23\ -\x33\x34\x32\x37\x36\x30\x22\x2c\x0a\x22\x64\x2e\x09\x63\x20\x23\ -\x33\x30\x32\x32\x35\x45\x22\x2c\x0a\x22\x65\x2e\x09\x63\x20\x23\ -\x33\x38\x32\x42\x36\x32\x22\x2c\x0a\x22\x66\x2e\x09\x63\x20\x23\ -\x32\x44\x32\x34\x35\x46\x22\x2c\x0a\x22\x67\x2e\x09\x63\x20\x23\ -\x32\x34\x31\x41\x35\x42\x22\x2c\x0a\x22\x68\x2e\x09\x63\x20\x23\ -\x32\x33\x31\x36\x35\x41\x22\x2c\x0a\x22\x69\x2e\x09\x63\x20\x23\ -\x35\x37\x34\x45\x38\x31\x22\x2c\x0a\x22\x6a\x2e\x09\x63\x20\x23\ -\x39\x41\x41\x34\x42\x43\x22\x2c\x0a\x22\x6b\x2e\x09\x63\x20\x23\ -\x32\x44\x36\x35\x38\x45\x22\x2c\x0a\x22\x6c\x2e\x09\x63\x20\x23\ -\x39\x46\x42\x38\x43\x39\x22\x2c\x0a\x22\x6d\x2e\x09\x63\x20\x23\ -\x37\x37\x36\x45\x39\x35\x22\x2c\x0a\x22\x6e\x2e\x09\x63\x20\x23\ -\x33\x42\x32\x42\x36\x33\x22\x2c\x0a\x22\x6f\x2e\x09\x63\x20\x23\ -\x32\x41\x31\x44\x35\x43\x22\x2c\x0a\x22\x70\x2e\x09\x63\x20\x23\ -\x32\x33\x31\x36\x35\x42\x22\x2c\x0a\x22\x71\x2e\x09\x63\x20\x23\ -\x32\x31\x31\x35\x35\x38\x22\x2c\x0a\x22\x72\x2e\x09\x63\x20\x23\ -\x33\x38\x32\x41\x36\x32\x22\x2c\x0a\x22\x73\x2e\x09\x63\x20\x23\ -\x33\x35\x32\x41\x36\x33\x22\x2c\x0a\x22\x74\x2e\x09\x63\x20\x23\ -\x32\x35\x31\x42\x35\x43\x22\x2c\x0a\x22\x75\x2e\x09\x63\x20\x23\ -\x32\x30\x31\x34\x35\x37\x22\x2c\x0a\x22\x76\x2e\x09\x63\x20\x23\ -\x32\x38\x34\x38\x37\x42\x22\x2c\x0a\x22\x77\x2e\x09\x63\x20\x23\ -\x34\x36\x37\x37\x39\x41\x22\x2c\x0a\x22\x78\x2e\x09\x63\x20\x23\ -\x45\x39\x45\x45\x46\x31\x22\x2c\x0a\x22\x79\x2e\x09\x63\x20\x23\ -\x43\x38\x44\x36\x44\x46\x22\x2c\x0a\x22\x7a\x2e\x09\x63\x20\x23\ -\x38\x42\x38\x33\x41\x32\x22\x2c\x0a\x22\x41\x2e\x09\x63\x20\x23\ -\x32\x42\x31\x45\x35\x45\x22\x2c\x0a\x22\x42\x2e\x09\x63\x20\x23\ -\x32\x31\x31\x34\x35\x38\x22\x2c\x0a\x22\x43\x2e\x09\x63\x20\x23\ -\x32\x41\x32\x30\x35\x45\x22\x2c\x0a\x22\x44\x2e\x09\x63\x20\x23\ -\x32\x36\x31\x43\x35\x43\x22\x2c\x0a\x22\x45\x2e\x09\x63\x20\x23\ -\x31\x42\x32\x33\x36\x31\x22\x2c\x0a\x22\x46\x2e\x09\x63\x20\x23\ -\x30\x43\x34\x34\x37\x37\x22\x2c\x0a\x22\x47\x2e\x09\x63\x20\x23\ -\x35\x30\x36\x35\x38\x46\x22\x2c\x0a\x22\x48\x2e\x09\x63\x20\x23\ -\x45\x42\x45\x41\x45\x46\x22\x2c\x0a\x22\x49\x2e\x09\x63\x20\x23\ -\x44\x35\x44\x46\x45\x35\x22\x2c\x0a\x22\x4a\x2e\x09\x63\x20\x23\ -\x37\x46\x41\x31\x42\x38\x22\x2c\x0a\x22\x4b\x2e\x09\x63\x20\x23\ -\x38\x32\x41\x34\x42\x39\x22\x2c\x0a\x22\x4c\x2e\x09\x63\x20\x23\ -\x41\x45\x41\x39\x42\x45\x22\x2c\x0a\x22\x4d\x2e\x09\x63\x20\x23\ -\x32\x46\x32\x31\x35\x44\x22\x2c\x0a\x22\x4e\x2e\x09\x63\x20\x23\ -\x32\x34\x31\x38\x35\x41\x22\x2c\x0a\x22\x4f\x2e\x09\x63\x20\x23\ -\x32\x31\x31\x36\x35\x41\x22\x2c\x0a\x22\x50\x2e\x09\x63\x20\x23\ -\x32\x30\x31\x37\x35\x41\x22\x2c\x0a\x22\x51\x2e\x09\x63\x20\x23\ -\x31\x31\x33\x37\x36\x46\x22\x2c\x0a\x22\x52\x2e\x09\x63\x20\x23\ -\x31\x30\x33\x37\x37\x30\x22\x2c\x0a\x22\x53\x2e\x09\x63\x20\x23\ -\x32\x30\x31\x37\x35\x42\x22\x2c\x0a\x22\x54\x2e\x09\x63\x20\x23\ -\x39\x30\x38\x41\x41\x41\x22\x2c\x0a\x22\x55\x2e\x09\x63\x20\x23\ -\x43\x45\x44\x41\x45\x32\x22\x2c\x0a\x22\x56\x2e\x09\x63\x20\x23\ -\x39\x44\x42\x36\x43\x37\x22\x2c\x0a\x22\x57\x2e\x09\x63\x20\x23\ -\x38\x46\x41\x43\x43\x30\x22\x2c\x0a\x22\x58\x2e\x09\x63\x20\x23\ -\x42\x46\x43\x45\x44\x39\x22\x2c\x0a\x22\x59\x2e\x09\x63\x20\x23\ -\x43\x43\x44\x39\x45\x31\x22\x2c\x0a\x22\x5a\x2e\x09\x63\x20\x23\ -\x36\x33\x35\x38\x38\x33\x22\x2c\x0a\x22\x60\x2e\x09\x63\x20\x23\ -\x33\x35\x32\x36\x36\x31\x22\x2c\x0a\x22\x20\x2b\x09\x63\x20\x23\ -\x33\x34\x32\x35\x36\x31\x22\x2c\x0a\x22\x2e\x2b\x09\x63\x20\x23\ -\x32\x43\x31\x45\x35\x44\x22\x2c\x0a\x22\x2b\x2b\x09\x63\x20\x23\ -\x32\x35\x31\x41\x35\x43\x22\x2c\x0a\x22\x40\x2b\x09\x63\x20\x23\ -\x32\x33\x31\x38\x35\x42\x22\x2c\x0a\x22\x23\x2b\x09\x63\x20\x23\ -\x32\x30\x31\x34\x35\x39\x22\x2c\x0a\x22\x24\x2b\x09\x63\x20\x23\ -\x31\x38\x32\x43\x36\x38\x22\x2c\x0a\x22\x25\x2b\x09\x63\x20\x23\ -\x30\x43\x34\x34\x37\x39\x22\x2c\x0a\x22\x26\x2b\x09\x63\x20\x23\ -\x31\x41\x32\x34\x36\x33\x22\x2c\x0a\x22\x2a\x2b\x09\x63\x20\x23\ -\x33\x39\x32\x46\x36\x39\x22\x2c\x0a\x22\x3d\x2b\x09\x63\x20\x23\ -\x41\x32\x41\x38\x42\x45\x22\x2c\x0a\x22\x2d\x2b\x09\x63\x20\x23\ -\x38\x44\x41\x42\x42\x46\x22\x2c\x0a\x22\x3b\x2b\x09\x63\x20\x23\ -\x41\x39\x42\x46\x43\x45\x22\x2c\x0a\x22\x3e\x2b\x09\x63\x20\x23\ -\x39\x37\x42\x31\x43\x33\x22\x2c\x0a\x22\x2c\x2b\x09\x63\x20\x23\ -\x39\x39\x39\x32\x41\x45\x22\x2c\x0a\x22\x27\x2b\x09\x63\x20\x23\ -\x33\x37\x32\x38\x36\x31\x22\x2c\x0a\x22\x29\x2b\x09\x63\x20\x23\ -\x33\x36\x32\x38\x36\x32\x22\x2c\x0a\x22\x21\x2b\x09\x63\x20\x23\ -\x32\x37\x31\x42\x35\x42\x22\x2c\x0a\x22\x7e\x2b\x09\x63\x20\x23\ -\x32\x35\x31\x39\x35\x41\x22\x2c\x0a\x22\x7b\x2b\x09\x63\x20\x23\ -\x32\x30\x31\x35\x35\x38\x22\x2c\x0a\x22\x5d\x2b\x09\x63\x20\x23\ -\x32\x39\x31\x44\x35\x44\x22\x2c\x0a\x22\x5e\x2b\x09\x63\x20\x23\ -\x32\x45\x32\x32\x35\x46\x22\x2c\x0a\x22\x2f\x2b\x09\x63\x20\x23\ -\x33\x30\x32\x34\x35\x46\x22\x2c\x0a\x22\x28\x2b\x09\x63\x20\x23\ -\x33\x33\x32\x37\x36\x32\x22\x2c\x0a\x22\x5f\x2b\x09\x63\x20\x23\ -\x33\x34\x32\x38\x36\x31\x22\x2c\x0a\x22\x3a\x2b\x09\x63\x20\x23\ -\x32\x46\x32\x33\x35\x46\x22\x2c\x0a\x22\x3c\x2b\x09\x63\x20\x23\ -\x32\x34\x31\x38\x35\x43\x22\x2c\x0a\x22\x5b\x2b\x09\x63\x20\x23\ -\x31\x46\x31\x32\x35\x36\x22\x2c\x0a\x22\x7d\x2b\x09\x63\x20\x23\ -\x31\x45\x31\x32\x35\x36\x22\x2c\x0a\x22\x7c\x2b\x09\x63\x20\x23\ -\x31\x42\x31\x46\x35\x46\x22\x2c\x0a\x22\x31\x2b\x09\x63\x20\x23\ -\x30\x46\x34\x33\x37\x37\x22\x2c\x0a\x22\x32\x2b\x09\x63\x20\x23\ -\x31\x35\x33\x31\x36\x43\x22\x2c\x0a\x22\x33\x2b\x09\x63\x20\x23\ -\x37\x37\x36\x46\x39\x37\x22\x2c\x0a\x22\x34\x2b\x09\x63\x20\x23\ -\x43\x45\x44\x39\x45\x31\x22\x2c\x0a\x22\x35\x2b\x09\x63\x20\x23\ -\x36\x44\x39\x34\x41\x45\x22\x2c\x0a\x22\x36\x2b\x09\x63\x20\x23\ -\x34\x32\x37\x34\x39\x38\x22\x2c\x0a\x22\x37\x2b\x09\x63\x20\x23\ -\x34\x45\x37\x44\x39\x44\x22\x2c\x0a\x22\x38\x2b\x09\x63\x20\x23\ -\x43\x31\x44\x30\x44\x39\x22\x2c\x0a\x22\x39\x2b\x09\x63\x20\x23\ -\x35\x34\x34\x39\x37\x41\x22\x2c\x0a\x22\x30\x2b\x09\x63\x20\x23\ -\x33\x35\x32\x38\x36\x31\x22\x2c\x0a\x22\x61\x2b\x09\x63\x20\x23\ -\x33\x33\x32\x36\x36\x31\x22\x2c\x0a\x22\x62\x2b\x09\x63\x20\x23\ -\x33\x37\x32\x39\x36\x32\x22\x2c\x0a\x22\x63\x2b\x09\x63\x20\x23\ -\x32\x33\x31\x37\x35\x41\x22\x2c\x0a\x22\x64\x2b\x09\x63\x20\x23\ -\x32\x45\x32\x31\x35\x45\x22\x2c\x0a\x22\x65\x2b\x09\x63\x20\x23\ -\x32\x37\x31\x45\x35\x45\x22\x2c\x0a\x22\x66\x2b\x09\x63\x20\x23\ -\x33\x35\x32\x37\x36\x31\x22\x2c\x0a\x22\x67\x2b\x09\x63\x20\x23\ -\x32\x42\x31\x46\x35\x44\x22\x2c\x0a\x22\x68\x2b\x09\x63\x20\x23\ -\x32\x33\x31\x37\x35\x38\x22\x2c\x0a\x22\x69\x2b\x09\x63\x20\x23\ -\x31\x46\x31\x36\x35\x39\x22\x2c\x0a\x22\x6a\x2b\x09\x63\x20\x23\ -\x31\x32\x33\x36\x36\x46\x22\x2c\x0a\x22\x6b\x2b\x09\x63\x20\x23\ -\x31\x30\x33\x43\x37\x33\x22\x2c\x0a\x22\x6c\x2b\x09\x63\x20\x23\ -\x32\x30\x31\x42\x35\x44\x22\x2c\x0a\x22\x6d\x2b\x09\x63\x20\x23\ -\x33\x35\x32\x39\x36\x37\x22\x2c\x0a\x22\x6e\x2b\x09\x63\x20\x23\ -\x43\x35\x43\x33\x44\x31\x22\x2c\x0a\x22\x6f\x2b\x09\x63\x20\x23\ -\x44\x39\x45\x32\x45\x37\x22\x2c\x0a\x22\x70\x2b\x09\x63\x20\x23\ -\x37\x46\x41\x30\x42\x38\x22\x2c\x0a\x22\x71\x2b\x09\x63\x20\x23\ -\x33\x46\x37\x30\x39\x34\x22\x2c\x0a\x22\x72\x2b\x09\x63\x20\x23\ -\x39\x43\x42\x35\x43\x36\x22\x2c\x0a\x22\x73\x2b\x09\x63\x20\x23\ -\x41\x42\x41\x35\x42\x42\x22\x2c\x0a\x22\x74\x2b\x09\x63\x20\x23\ -\x33\x32\x32\x33\x35\x46\x22\x2c\x0a\x22\x75\x2b\x09\x63\x20\x23\ -\x33\x34\x32\x37\x36\x31\x22\x2c\x0a\x22\x76\x2b\x09\x63\x20\x23\ -\x32\x34\x31\x38\x35\x42\x22\x2c\x0a\x22\x77\x2b\x09\x63\x20\x23\ -\x32\x32\x31\x37\x35\x42\x22\x2c\x0a\x22\x78\x2b\x09\x63\x20\x23\ -\x32\x41\x31\x45\x35\x43\x22\x2c\x0a\x22\x79\x2b\x09\x63\x20\x23\ -\x35\x45\x35\x35\x38\x33\x22\x2c\x0a\x22\x7a\x2b\x09\x63\x20\x23\ -\x38\x34\x37\x44\x39\x45\x22\x2c\x0a\x22\x41\x2b\x09\x63\x20\x23\ -\x35\x39\x34\x45\x37\x43\x22\x2c\x0a\x22\x42\x2b\x09\x63\x20\x23\ -\x33\x35\x32\x38\x36\x32\x22\x2c\x0a\x22\x43\x2b\x09\x63\x20\x23\ -\x33\x32\x32\x35\x36\x31\x22\x2c\x0a\x22\x44\x2b\x09\x63\x20\x23\ -\x33\x30\x32\x33\x36\x30\x22\x2c\x0a\x22\x45\x2b\x09\x63\x20\x23\ -\x33\x35\x32\x39\x36\x34\x22\x2c\x0a\x22\x46\x2b\x09\x63\x20\x23\ -\x31\x41\x33\x31\x36\x42\x22\x2c\x0a\x22\x47\x2b\x09\x63\x20\x23\ -\x31\x30\x34\x37\x37\x41\x22\x2c\x0a\x22\x48\x2b\x09\x63\x20\x23\ -\x32\x30\x32\x41\x36\x36\x22\x2c\x0a\x22\x49\x2b\x09\x63\x20\x23\ -\x31\x46\x31\x32\x35\x37\x22\x2c\x0a\x22\x4a\x2b\x09\x63\x20\x23\ -\x32\x34\x31\x37\x35\x42\x22\x2c\x0a\x22\x4b\x2b\x09\x63\x20\x23\ -\x32\x34\x31\x37\x35\x43\x22\x2c\x0a\x22\x4c\x2b\x09\x63\x20\x23\ -\x38\x34\x37\x45\x41\x31\x22\x2c\x0a\x22\x4d\x2b\x09\x63\x20\x23\ -\x36\x39\x38\x46\x41\x41\x22\x2c\x0a\x22\x4e\x2b\x09\x63\x20\x23\ -\x41\x33\x42\x41\x43\x42\x22\x2c\x0a\x22\x4f\x2b\x09\x63\x20\x23\ -\x44\x31\x44\x44\x45\x34\x22\x2c\x0a\x22\x50\x2b\x09\x63\x20\x23\ -\x42\x36\x43\x39\x44\x35\x22\x2c\x0a\x22\x51\x2b\x09\x63\x20\x23\ -\x37\x39\x36\x46\x39\x33\x22\x2c\x0a\x22\x52\x2b\x09\x63\x20\x23\ -\x34\x30\x33\x33\x36\x41\x22\x2c\x0a\x22\x53\x2b\x09\x63\x20\x23\ -\x39\x39\x39\x33\x41\x45\x22\x2c\x0a\x22\x54\x2b\x09\x63\x20\x23\ -\x41\x44\x41\x39\x42\x45\x22\x2c\x0a\x22\x55\x2b\x09\x63\x20\x23\ -\x41\x41\x41\x36\x42\x44\x22\x2c\x0a\x22\x56\x2b\x09\x63\x20\x23\ -\x41\x39\x41\x35\x42\x44\x22\x2c\x0a\x22\x57\x2b\x09\x63\x20\x23\ -\x41\x31\x39\x43\x42\x37\x22\x2c\x0a\x22\x58\x2b\x09\x63\x20\x23\ -\x38\x43\x38\x37\x41\x38\x22\x2c\x0a\x22\x59\x2b\x09\x63\x20\x23\ -\x36\x31\x35\x39\x38\x38\x22\x2c\x0a\x22\x5a\x2b\x09\x63\x20\x23\ -\x32\x39\x31\x45\x35\x46\x22\x2c\x0a\x22\x60\x2b\x09\x63\x20\x23\ -\x32\x39\x31\x44\x35\x42\x22\x2c\x0a\x22\x20\x40\x09\x63\x20\x23\ -\x33\x35\x32\x41\x36\x37\x22\x2c\x0a\x22\x2e\x40\x09\x63\x20\x23\ -\x34\x39\x33\x46\x37\x36\x22\x2c\x0a\x22\x2b\x40\x09\x63\x20\x23\ -\x35\x33\x34\x39\x37\x45\x22\x2c\x0a\x22\x40\x40\x09\x63\x20\x23\ -\x34\x42\x34\x30\x37\x35\x22\x2c\x0a\x22\x23\x40\x09\x63\x20\x23\ -\x36\x30\x35\x36\x38\x32\x22\x2c\x0a\x22\x24\x40\x09\x63\x20\x23\ -\x44\x44\x44\x43\x45\x32\x22\x2c\x0a\x22\x25\x40\x09\x63\x20\x23\ -\x46\x36\x46\x35\x46\x36\x22\x2c\x0a\x22\x26\x40\x09\x63\x20\x23\ -\x38\x31\x37\x42\x39\x46\x22\x2c\x0a\x22\x2a\x40\x09\x63\x20\x23\ -\x32\x41\x31\x44\x35\x45\x22\x2c\x0a\x22\x3d\x40\x09\x63\x20\x23\ -\x36\x45\x36\x34\x38\x43\x22\x2c\x0a\x22\x2d\x40\x09\x63\x20\x23\ -\x41\x38\x41\x32\x42\x38\x22\x2c\x0a\x22\x3b\x40\x09\x63\x20\x23\ -\x38\x34\x39\x33\x41\x43\x22\x2c\x0a\x22\x3e\x40\x09\x63\x20\x23\ -\x31\x46\x35\x37\x38\x33\x22\x2c\x0a\x22\x2c\x40\x09\x63\x20\x23\ -\x37\x30\x38\x44\x41\x39\x22\x2c\x0a\x22\x27\x40\x09\x63\x20\x23\ -\x38\x31\x37\x39\x39\x42\x22\x2c\x0a\x22\x29\x40\x09\x63\x20\x23\ -\x33\x42\x32\x46\x36\x37\x22\x2c\x0a\x22\x21\x40\x09\x63\x20\x23\ -\x34\x41\x34\x31\x37\x36\x22\x2c\x0a\x22\x7e\x40\x09\x63\x20\x23\ -\x44\x43\x44\x46\x45\x35\x22\x2c\x0a\x22\x7b\x40\x09\x63\x20\x23\ -\x41\x37\x42\x43\x43\x42\x22\x2c\x0a\x22\x5d\x40\x09\x63\x20\x23\ -\x44\x33\x44\x45\x45\x33\x22\x2c\x0a\x22\x5e\x40\x09\x63\x20\x23\ -\x43\x33\x44\x32\x44\x42\x22\x2c\x0a\x22\x2f\x40\x09\x63\x20\x23\ -\x38\x33\x41\x33\x42\x38\x22\x2c\x0a\x22\x28\x40\x09\x63\x20\x23\ -\x35\x31\x34\x34\x37\x34\x22\x2c\x0a\x22\x5f\x40\x09\x63\x20\x23\ -\x33\x36\x32\x38\x36\x31\x22\x2c\x0a\x22\x3a\x40\x09\x63\x20\x23\ -\x34\x35\x33\x38\x36\x45\x22\x2c\x0a\x22\x3c\x40\x09\x63\x20\x23\ -\x44\x46\x44\x44\x45\x35\x22\x2c\x0a\x22\x5b\x40\x09\x63\x20\x23\ -\x46\x45\x46\x46\x46\x45\x22\x2c\x0a\x22\x7d\x40\x09\x63\x20\x23\ -\x46\x36\x46\x35\x46\x38\x22\x2c\x0a\x22\x7c\x40\x09\x63\x20\x23\ -\x33\x44\x33\x33\x36\x43\x22\x2c\x0a\x22\x31\x40\x09\x63\x20\x23\ -\x32\x36\x31\x41\x35\x42\x22\x2c\x0a\x22\x32\x40\x09\x63\x20\x23\ -\x33\x35\x32\x38\x36\x30\x22\x2c\x0a\x22\x33\x40\x09\x63\x20\x23\ -\x33\x33\x32\x39\x36\x31\x22\x2c\x0a\x22\x34\x40\x09\x63\x20\x23\ -\x38\x34\x38\x30\x41\x32\x22\x2c\x0a\x22\x35\x40\x09\x63\x20\x23\ -\x43\x44\x43\x43\x44\x38\x22\x2c\x0a\x22\x36\x40\x09\x63\x20\x23\ -\x45\x42\x45\x41\x45\x45\x22\x2c\x0a\x22\x37\x40\x09\x63\x20\x23\ -\x45\x44\x45\x43\x46\x30\x22\x2c\x0a\x22\x38\x40\x09\x63\x20\x23\ -\x45\x41\x45\x38\x45\x44\x22\x2c\x0a\x22\x39\x40\x09\x63\x20\x23\ -\x44\x44\x44\x42\x45\x32\x22\x2c\x0a\x22\x30\x40\x09\x63\x20\x23\ -\x44\x46\x44\x44\x45\x34\x22\x2c\x0a\x22\x61\x40\x09\x63\x20\x23\ -\x37\x45\x37\x34\x39\x38\x22\x2c\x0a\x22\x62\x40\x09\x63\x20\x23\ -\x34\x38\x33\x43\x37\x30\x22\x2c\x0a\x22\x63\x40\x09\x63\x20\x23\ -\x37\x34\x36\x43\x39\x33\x22\x2c\x0a\x22\x64\x40\x09\x63\x20\x23\ -\x45\x32\x45\x30\x45\x36\x22\x2c\x0a\x22\x65\x40\x09\x63\x20\x23\ -\x44\x38\x45\x32\x45\x38\x22\x2c\x0a\x22\x66\x40\x09\x63\x20\x23\ -\x34\x44\x37\x45\x41\x30\x22\x2c\x0a\x22\x67\x40\x09\x63\x20\x23\ -\x36\x38\x39\x30\x41\x43\x22\x2c\x0a\x22\x68\x40\x09\x63\x20\x23\ -\x46\x33\x46\x36\x46\x36\x22\x2c\x0a\x22\x69\x40\x09\x63\x20\x23\ -\x46\x42\x46\x42\x46\x42\x22\x2c\x0a\x22\x6a\x40\x09\x63\x20\x23\ -\x41\x45\x41\x38\x42\x44\x22\x2c\x0a\x22\x6b\x40\x09\x63\x20\x23\ -\x33\x45\x33\x32\x36\x37\x22\x2c\x0a\x22\x6c\x40\x09\x63\x20\x23\ -\x32\x43\x32\x30\x36\x31\x22\x2c\x0a\x22\x6d\x40\x09\x63\x20\x23\ -\x43\x33\x43\x30\x44\x30\x22\x2c\x0a\x22\x6e\x40\x09\x63\x20\x23\ -\x38\x46\x41\x44\x43\x30\x22\x2c\x0a\x22\x6f\x40\x09\x63\x20\x23\ -\x37\x32\x39\x38\x42\x31\x22\x2c\x0a\x22\x70\x40\x09\x63\x20\x23\ -\x36\x38\x38\x46\x41\x39\x22\x2c\x0a\x22\x71\x40\x09\x63\x20\x23\ -\x37\x46\x39\x46\x42\x36\x22\x2c\x0a\x22\x72\x40\x09\x63\x20\x23\ -\x42\x46\x42\x43\x43\x42\x22\x2c\x0a\x22\x73\x40\x09\x63\x20\x23\ -\x34\x30\x33\x32\x36\x37\x22\x2c\x0a\x22\x74\x40\x09\x63\x20\x23\ -\x34\x34\x33\x37\x36\x44\x22\x2c\x0a\x22\x75\x40\x09\x63\x20\x23\ -\x45\x30\x44\x44\x45\x35\x22\x2c\x0a\x22\x76\x40\x09\x63\x20\x23\ -\x46\x46\x46\x46\x46\x46\x22\x2c\x0a\x22\x77\x40\x09\x63\x20\x23\ -\x45\x41\x45\x39\x45\x44\x22\x2c\x0a\x22\x78\x40\x09\x63\x20\x23\ -\x41\x31\x39\x43\x42\x35\x22\x2c\x0a\x22\x79\x40\x09\x63\x20\x23\ -\x41\x38\x41\x33\x42\x42\x22\x2c\x0a\x22\x7a\x40\x09\x63\x20\x23\ -\x44\x35\x44\x32\x44\x44\x22\x2c\x0a\x22\x41\x40\x09\x63\x20\x23\ -\x32\x41\x31\x46\x35\x46\x22\x2c\x0a\x22\x42\x40\x09\x63\x20\x23\ -\x32\x44\x32\x34\x36\x30\x22\x2c\x0a\x22\x43\x40\x09\x63\x20\x23\ -\x37\x41\x37\x37\x39\x41\x22\x2c\x0a\x22\x44\x40\x09\x63\x20\x23\ -\x46\x32\x46\x34\x46\x37\x22\x2c\x0a\x22\x45\x40\x09\x63\x20\x23\ -\x41\x33\x39\x44\x42\x35\x22\x2c\x0a\x22\x46\x40\x09\x63\x20\x23\ -\x37\x36\x36\x45\x39\x35\x22\x2c\x0a\x22\x47\x40\x09\x63\x20\x23\ -\x45\x38\x45\x36\x45\x42\x22\x2c\x0a\x22\x48\x40\x09\x63\x20\x23\ -\x36\x32\x35\x38\x38\x34\x22\x2c\x0a\x22\x49\x40\x09\x63\x20\x23\ -\x34\x36\x33\x39\x36\x45\x22\x2c\x0a\x22\x4a\x40\x09\x63\x20\x23\ -\x43\x46\x43\x43\x44\x38\x22\x2c\x0a\x22\x4b\x40\x09\x63\x20\x23\ -\x36\x42\x39\x32\x41\x45\x22\x2c\x0a\x22\x4c\x40\x09\x63\x20\x23\ -\x31\x36\x34\x34\x37\x38\x22\x2c\x0a\x22\x4d\x40\x09\x63\x20\x23\ -\x36\x30\x36\x33\x38\x45\x22\x2c\x0a\x22\x4e\x40\x09\x63\x20\x23\ -\x42\x34\x42\x30\x43\x34\x22\x2c\x0a\x22\x4f\x40\x09\x63\x20\x23\ -\x46\x38\x46\x37\x46\x37\x22\x2c\x0a\x22\x50\x40\x09\x63\x20\x23\ -\x37\x36\x36\x43\x39\x31\x22\x2c\x0a\x22\x51\x40\x09\x63\x20\x23\ -\x33\x32\x32\x35\x35\x46\x22\x2c\x0a\x22\x52\x40\x09\x63\x20\x23\ -\x39\x42\x39\x35\x42\x32\x22\x2c\x0a\x22\x53\x40\x09\x63\x20\x23\ -\x43\x35\x44\x33\x44\x43\x22\x2c\x0a\x22\x54\x40\x09\x63\x20\x23\ -\x39\x45\x42\x36\x43\x36\x22\x2c\x0a\x22\x55\x40\x09\x63\x20\x23\ -\x44\x44\x45\x34\x45\x39\x22\x2c\x0a\x22\x56\x40\x09\x63\x20\x23\ -\x46\x31\x46\x34\x46\x35\x22\x2c\x0a\x22\x57\x40\x09\x63\x20\x23\ -\x46\x32\x46\x34\x46\x36\x22\x2c\x0a\x22\x58\x40\x09\x63\x20\x23\ -\x39\x44\x39\x37\x42\x31\x22\x2c\x0a\x22\x59\x40\x09\x63\x20\x23\ -\x33\x38\x32\x41\x36\x31\x22\x2c\x0a\x22\x5a\x40\x09\x63\x20\x23\ -\x34\x31\x33\x35\x36\x44\x22\x2c\x0a\x22\x60\x40\x09\x63\x20\x23\ -\x44\x46\x44\x44\x45\x36\x22\x2c\x0a\x22\x20\x23\x09\x63\x20\x23\ -\x43\x45\x43\x43\x44\x39\x22\x2c\x0a\x22\x2e\x23\x09\x63\x20\x23\ -\x32\x44\x32\x32\x36\x32\x22\x2c\x0a\x22\x2b\x23\x09\x63\x20\x23\ -\x34\x44\x34\x33\x37\x38\x22\x2c\x0a\x22\x40\x23\x09\x63\x20\x23\ -\x43\x34\x43\x31\x44\x31\x22\x2c\x0a\x22\x23\x23\x09\x63\x20\x23\ -\x46\x35\x46\x35\x46\x37\x22\x2c\x0a\x22\x24\x23\x09\x63\x20\x23\ -\x36\x37\x36\x31\x38\x45\x22\x2c\x0a\x22\x25\x23\x09\x63\x20\x23\ -\x32\x36\x31\x44\x35\x44\x22\x2c\x0a\x22\x26\x23\x09\x63\x20\x23\ -\x39\x43\x39\x42\x42\x34\x22\x2c\x0a\x22\x2a\x23\x09\x63\x20\x23\ -\x45\x34\x45\x33\x45\x39\x22\x2c\x0a\x22\x3d\x23\x09\x63\x20\x23\ -\x34\x44\x34\x32\x37\x33\x22\x2c\x0a\x22\x2d\x23\x09\x63\x20\x23\ -\x32\x46\x32\x31\x36\x30\x22\x2c\x0a\x22\x3b\x23\x09\x63\x20\x23\ -\x36\x37\x35\x44\x38\x37\x22\x2c\x0a\x22\x3e\x23\x09\x63\x20\x23\ -\x46\x32\x46\x31\x46\x34\x22\x2c\x0a\x22\x2c\x23\x09\x63\x20\x23\ -\x38\x34\x37\x43\x39\x44\x22\x2c\x0a\x22\x27\x23\x09\x63\x20\x23\ -\x35\x42\x35\x30\x37\x46\x22\x2c\x0a\x22\x29\x23\x09\x63\x20\x23\ -\x46\x31\x46\x30\x46\x32\x22\x2c\x0a\x22\x21\x23\x09\x63\x20\x23\ -\x38\x35\x41\x36\x42\x43\x22\x2c\x0a\x22\x7e\x23\x09\x63\x20\x23\ -\x31\x37\x34\x44\x37\x44\x22\x2c\x0a\x22\x7b\x23\x09\x63\x20\x23\ -\x32\x42\x33\x35\x36\x43\x22\x2c\x0a\x22\x5d\x23\x09\x63\x20\x23\ -\x34\x34\x33\x39\x37\x30\x22\x2c\x0a\x22\x5e\x23\x09\x63\x20\x23\ -\x38\x39\x38\x33\x41\x35\x22\x2c\x0a\x22\x2f\x23\x09\x63\x20\x23\ -\x37\x37\x36\x46\x39\x35\x22\x2c\x0a\x22\x28\x23\x09\x63\x20\x23\ -\x34\x38\x33\x43\x36\x46\x22\x2c\x0a\x22\x5f\x23\x09\x63\x20\x23\ -\x33\x38\x32\x42\x36\x33\x22\x2c\x0a\x22\x3a\x23\x09\x63\x20\x23\ -\x37\x39\x37\x31\x39\x38\x22\x2c\x0a\x22\x3c\x23\x09\x63\x20\x23\ -\x44\x30\x44\x42\x45\x32\x22\x2c\x0a\x22\x5b\x23\x09\x63\x20\x23\ -\x37\x32\x39\x35\x41\x46\x22\x2c\x0a\x22\x7d\x23\x09\x63\x20\x23\ -\x39\x31\x41\x43\x42\x46\x22\x2c\x0a\x22\x7c\x23\x09\x63\x20\x23\ -\x38\x37\x41\x35\x42\x41\x22\x2c\x0a\x22\x31\x23\x09\x63\x20\x23\ -\x42\x44\x43\x44\x44\x38\x22\x2c\x0a\x22\x32\x23\x09\x63\x20\x23\ -\x38\x31\x37\x41\x39\x45\x22\x2c\x0a\x22\x33\x23\x09\x63\x20\x23\ -\x33\x44\x33\x31\x36\x42\x22\x2c\x0a\x22\x34\x23\x09\x63\x20\x23\ -\x44\x45\x44\x43\x45\x35\x22\x2c\x0a\x22\x35\x23\x09\x63\x20\x23\ -\x43\x46\x43\x44\x44\x41\x22\x2c\x0a\x22\x36\x23\x09\x63\x20\x23\ -\x32\x44\x32\x33\x36\x32\x22\x2c\x0a\x22\x37\x23\x09\x63\x20\x23\ -\x37\x38\x37\x31\x39\x38\x22\x2c\x0a\x22\x38\x23\x09\x63\x20\x23\ -\x46\x42\x46\x41\x46\x41\x22\x2c\x0a\x22\x39\x23\x09\x63\x20\x23\ -\x39\x45\x39\x43\x42\x38\x22\x2c\x0a\x22\x30\x23\x09\x63\x20\x23\ -\x38\x35\x37\x45\x39\x46\x22\x2c\x0a\x22\x61\x23\x09\x63\x20\x23\ -\x46\x36\x46\x36\x46\x37\x22\x2c\x0a\x22\x62\x23\x09\x63\x20\x23\ -\x38\x45\x38\x37\x41\x35\x22\x2c\x0a\x22\x63\x23\x09\x63\x20\x23\ -\x35\x35\x34\x41\x37\x43\x22\x2c\x0a\x22\x64\x23\x09\x63\x20\x23\ -\x46\x38\x46\x37\x46\x38\x22\x2c\x0a\x22\x65\x23\x09\x63\x20\x23\ -\x37\x33\x36\x39\x38\x46\x22\x2c\x0a\x22\x66\x23\x09\x63\x20\x23\ -\x39\x31\x41\x42\x42\x46\x22\x2c\x0a\x22\x67\x23\x09\x63\x20\x23\ -\x32\x33\x35\x45\x38\x39\x22\x2c\x0a\x22\x68\x23\x09\x63\x20\x23\ -\x38\x46\x41\x38\x42\x44\x22\x2c\x0a\x22\x69\x23\x09\x63\x20\x23\ -\x41\x33\x39\x43\x42\x35\x22\x2c\x0a\x22\x6a\x23\x09\x63\x20\x23\ -\x37\x43\x37\x32\x39\x35\x22\x2c\x0a\x22\x6b\x23\x09\x63\x20\x23\ -\x34\x46\x34\x34\x37\x36\x22\x2c\x0a\x22\x6c\x23\x09\x63\x20\x23\ -\x32\x43\x32\x30\x35\x46\x22\x2c\x0a\x22\x6d\x23\x09\x63\x20\x23\ -\x35\x45\x35\x35\x38\x34\x22\x2c\x0a\x22\x6e\x23\x09\x63\x20\x23\ -\x45\x31\x45\x35\x45\x39\x22\x2c\x0a\x22\x6f\x23\x09\x63\x20\x23\ -\x39\x38\x42\x31\x43\x34\x22\x2c\x0a\x22\x70\x23\x09\x63\x20\x23\ -\x44\x43\x45\x34\x45\x39\x22\x2c\x0a\x22\x71\x23\x09\x63\x20\x23\ -\x44\x46\x45\x36\x45\x42\x22\x2c\x0a\x22\x72\x23\x09\x63\x20\x23\ -\x46\x38\x46\x39\x46\x41\x22\x2c\x0a\x22\x73\x23\x09\x63\x20\x23\ -\x36\x45\x36\x36\x39\x30\x22\x2c\x0a\x22\x74\x23\x09\x63\x20\x23\ -\x33\x38\x32\x41\x36\x33\x22\x2c\x0a\x22\x75\x23\x09\x63\x20\x23\ -\x33\x46\x33\x34\x36\x43\x22\x2c\x0a\x22\x76\x23\x09\x63\x20\x23\ -\x44\x43\x44\x42\x45\x34\x22\x2c\x0a\x22\x77\x23\x09\x63\x20\x23\ -\x44\x32\x43\x46\x44\x43\x22\x2c\x0a\x22\x78\x23\x09\x63\x20\x23\ -\x33\x31\x32\x36\x36\x34\x22\x2c\x0a\x22\x79\x23\x09\x63\x20\x23\ -\x34\x37\x33\x44\x37\x34\x22\x2c\x0a\x22\x7a\x23\x09\x63\x20\x23\ -\x45\x39\x45\x39\x45\x44\x22\x2c\x0a\x22\x41\x23\x09\x63\x20\x23\ -\x43\x32\x43\x30\x44\x30\x22\x2c\x0a\x22\x42\x23\x09\x63\x20\x23\ -\x32\x44\x32\x31\x36\x31\x22\x2c\x0a\x22\x43\x23\x09\x63\x20\x23\ -\x33\x43\x32\x46\x36\x36\x22\x2c\x0a\x22\x44\x23\x09\x63\x20\x23\ -\x42\x42\x42\x36\x43\x37\x22\x2c\x0a\x22\x45\x23\x09\x63\x20\x23\ -\x46\x43\x46\x42\x46\x43\x22\x2c\x0a\x22\x46\x23\x09\x63\x20\x23\ -\x46\x33\x46\x32\x46\x35\x22\x2c\x0a\x22\x47\x23\x09\x63\x20\x23\ -\x45\x39\x45\x38\x45\x44\x22\x2c\x0a\x22\x48\x23\x09\x63\x20\x23\ -\x46\x38\x46\x38\x46\x39\x22\x2c\x0a\x22\x49\x23\x09\x63\x20\x23\ -\x45\x33\x45\x31\x45\x38\x22\x2c\x0a\x22\x4a\x23\x09\x63\x20\x23\ -\x39\x37\x39\x30\x41\x42\x22\x2c\x0a\x22\x4b\x23\x09\x63\x20\x23\ -\x33\x39\x32\x42\x36\x32\x22\x2c\x0a\x22\x4c\x23\x09\x63\x20\x23\ -\x32\x44\x33\x38\x36\x44\x22\x2c\x0a\x22\x4d\x23\x09\x63\x20\x23\ -\x32\x30\x35\x37\x38\x34\x22\x2c\x0a\x22\x4e\x23\x09\x63\x20\x23\ -\x38\x33\x41\x34\x42\x42\x22\x2c\x0a\x22\x4f\x23\x09\x63\x20\x23\ -\x46\x41\x46\x39\x46\x41\x22\x2c\x0a\x22\x50\x23\x09\x63\x20\x23\ -\x42\x34\x41\x46\x43\x34\x22\x2c\x0a\x22\x51\x23\x09\x63\x20\x23\ -\x36\x37\x35\x46\x38\x43\x22\x2c\x0a\x22\x52\x23\x09\x63\x20\x23\ -\x33\x37\x32\x41\x36\x31\x22\x2c\x0a\x22\x53\x23\x09\x63\x20\x23\ -\x35\x31\x34\x38\x37\x43\x22\x2c\x0a\x22\x54\x23\x09\x63\x20\x23\ -\x46\x30\x46\x30\x46\x32\x22\x2c\x0a\x22\x55\x23\x09\x63\x20\x23\ -\x41\x46\x43\x34\x44\x30\x22\x2c\x0a\x22\x56\x23\x09\x63\x20\x23\ -\x43\x32\x44\x32\x44\x42\x22\x2c\x0a\x22\x57\x23\x09\x63\x20\x23\ -\x38\x36\x41\x35\x42\x41\x22\x2c\x0a\x22\x58\x23\x09\x63\x20\x23\ -\x38\x45\x41\x42\x42\x46\x22\x2c\x0a\x22\x59\x23\x09\x63\x20\x23\ -\x36\x35\x35\x43\x38\x41\x22\x2c\x0a\x22\x5a\x23\x09\x63\x20\x23\ -\x34\x37\x33\x41\x37\x30\x22\x2c\x0a\x22\x60\x23\x09\x63\x20\x23\ -\x44\x44\x44\x42\x45\x34\x22\x2c\x0a\x22\x20\x24\x09\x63\x20\x23\ -\x44\x33\x44\x30\x44\x43\x22\x2c\x0a\x22\x2e\x24\x09\x63\x20\x23\ -\x33\x34\x32\x38\x36\x35\x22\x2c\x0a\x22\x2b\x24\x09\x63\x20\x23\ -\x33\x44\x33\x37\x37\x30\x22\x2c\x0a\x22\x40\x24\x09\x63\x20\x23\ -\x45\x32\x45\x33\x45\x41\x22\x2c\x0a\x22\x23\x24\x09\x63\x20\x23\ -\x43\x38\x43\x35\x44\x33\x22\x2c\x0a\x22\x24\x24\x09\x63\x20\x23\ -\x32\x41\x31\x45\x35\x45\x22\x2c\x0a\x22\x25\x24\x09\x63\x20\x23\ -\x37\x38\x37\x31\x39\x36\x22\x2c\x0a\x22\x26\x24\x09\x63\x20\x23\ -\x43\x36\x43\x33\x44\x32\x22\x2c\x0a\x22\x2a\x24\x09\x63\x20\x23\ -\x36\x42\x36\x33\x38\x46\x22\x2c\x0a\x22\x3d\x24\x09\x63\x20\x23\ -\x37\x31\x36\x38\x39\x32\x22\x2c\x0a\x22\x2d\x24\x09\x63\x20\x23\ -\x36\x44\x36\x33\x38\x43\x22\x2c\x0a\x22\x3b\x24\x09\x63\x20\x23\ -\x34\x43\x34\x30\x37\x34\x22\x2c\x0a\x22\x3e\x24\x09\x63\x20\x23\ -\x33\x30\x32\x32\x35\x46\x22\x2c\x0a\x22\x2c\x24\x09\x63\x20\x23\ -\x33\x33\x32\x34\x36\x31\x22\x2c\x0a\x22\x27\x24\x09\x63\x20\x23\ -\x32\x41\x33\x31\x36\x38\x22\x2c\x0a\x22\x29\x24\x09\x63\x20\x23\ -\x31\x34\x34\x35\x37\x37\x22\x2c\x0a\x22\x21\x24\x09\x63\x20\x23\ -\x33\x35\x35\x36\x38\x34\x22\x2c\x0a\x22\x7e\x24\x09\x63\x20\x23\ -\x42\x43\x42\x39\x43\x41\x22\x2c\x0a\x22\x7b\x24\x09\x63\x20\x23\ -\x45\x31\x44\x46\x45\x36\x22\x2c\x0a\x22\x5d\x24\x09\x63\x20\x23\ -\x36\x41\x36\x32\x38\x43\x22\x2c\x0a\x22\x5e\x24\x09\x63\x20\x23\ -\x32\x38\x31\x42\x35\x44\x22\x2c\x0a\x22\x2f\x24\x09\x63\x20\x23\ -\x34\x37\x33\x45\x37\x33\x22\x2c\x0a\x22\x28\x24\x09\x63\x20\x23\ -\x45\x32\x45\x33\x45\x38\x22\x2c\x0a\x22\x5f\x24\x09\x63\x20\x23\ -\x39\x35\x42\x30\x43\x32\x22\x2c\x0a\x22\x3a\x24\x09\x63\x20\x23\ -\x38\x30\x41\x31\x42\x37\x22\x2c\x0a\x22\x3c\x24\x09\x63\x20\x23\ -\x42\x34\x43\x38\x44\x34\x22\x2c\x0a\x22\x5b\x24\x09\x63\x20\x23\ -\x37\x45\x41\x31\x42\x38\x22\x2c\x0a\x22\x7d\x24\x09\x63\x20\x23\ -\x36\x36\x35\x44\x38\x41\x22\x2c\x0a\x22\x7c\x24\x09\x63\x20\x23\ -\x32\x45\x32\x30\x35\x45\x22\x2c\x0a\x22\x31\x24\x09\x63\x20\x23\ -\x34\x41\x33\x45\x37\x31\x22\x2c\x0a\x22\x32\x24\x09\x63\x20\x23\ -\x44\x34\x44\x31\x44\x43\x22\x2c\x0a\x22\x33\x24\x09\x63\x20\x23\ -\x33\x38\x32\x43\x36\x37\x22\x2c\x0a\x22\x34\x24\x09\x63\x20\x23\ -\x35\x32\x34\x46\x38\x31\x22\x2c\x0a\x22\x35\x24\x09\x63\x20\x23\ -\x45\x44\x46\x30\x46\x33\x22\x2c\x0a\x22\x36\x24\x09\x63\x20\x23\ -\x42\x36\x42\x32\x43\x37\x22\x2c\x0a\x22\x37\x24\x09\x63\x20\x23\ -\x33\x30\x32\x35\x36\x33\x22\x2c\x0a\x22\x38\x24\x09\x63\x20\x23\ -\x42\x43\x42\x38\x43\x41\x22\x2c\x0a\x22\x39\x24\x09\x63\x20\x23\ -\x44\x37\x44\x36\x44\x46\x22\x2c\x0a\x22\x30\x24\x09\x63\x20\x23\ -\x38\x35\x37\x45\x41\x31\x22\x2c\x0a\x22\x61\x24\x09\x63\x20\x23\ -\x36\x45\x36\x35\x39\x30\x22\x2c\x0a\x22\x62\x24\x09\x63\x20\x23\ -\x36\x45\x36\x35\x38\x44\x22\x2c\x0a\x22\x63\x24\x09\x63\x20\x23\ -\x36\x37\x35\x45\x38\x37\x22\x2c\x0a\x22\x64\x24\x09\x63\x20\x23\ -\x35\x33\x34\x38\x37\x39\x22\x2c\x0a\x22\x65\x24\x09\x63\x20\x23\ -\x32\x39\x32\x41\x36\x35\x22\x2c\x0a\x22\x66\x24\x09\x63\x20\x23\ -\x31\x32\x33\x46\x37\x34\x22\x2c\x0a\x22\x67\x24\x09\x63\x20\x23\ -\x31\x35\x33\x42\x37\x31\x22\x2c\x0a\x22\x68\x24\x09\x63\x20\x23\ -\x32\x42\x32\x35\x36\x32\x22\x2c\x0a\x22\x69\x24\x09\x63\x20\x23\ -\x33\x44\x33\x30\x36\x39\x22\x2c\x0a\x22\x6a\x24\x09\x63\x20\x23\ -\x39\x42\x39\x35\x41\x45\x22\x2c\x0a\x22\x6b\x24\x09\x63\x20\x23\ -\x43\x30\x42\x43\x43\x43\x22\x2c\x0a\x22\x6c\x24\x09\x63\x20\x23\ -\x45\x37\x45\x36\x45\x42\x22\x2c\x0a\x22\x6d\x24\x09\x63\x20\x23\ -\x42\x31\x41\x44\x43\x32\x22\x2c\x0a\x22\x6e\x24\x09\x63\x20\x23\ -\x33\x39\x32\x43\x36\x34\x22\x2c\x0a\x22\x6f\x24\x09\x63\x20\x23\ -\x32\x37\x31\x42\x35\x43\x22\x2c\x0a\x22\x70\x24\x09\x63\x20\x23\ -\x34\x43\x34\x33\x37\x38\x22\x2c\x0a\x22\x71\x24\x09\x63\x20\x23\ -\x45\x45\x45\x45\x46\x30\x22\x2c\x0a\x22\x72\x24\x09\x63\x20\x23\ -\x39\x46\x42\x38\x43\x38\x22\x2c\x0a\x22\x73\x24\x09\x63\x20\x23\ -\x41\x43\x43\x32\x44\x30\x22\x2c\x0a\x22\x74\x24\x09\x63\x20\x23\ -\x45\x39\x45\x46\x46\x31\x22\x2c\x0a\x22\x75\x24\x09\x63\x20\x23\ -\x43\x31\x44\x32\x44\x44\x22\x2c\x0a\x22\x76\x24\x09\x63\x20\x23\ -\x37\x31\x36\x39\x39\x33\x22\x2c\x0a\x22\x77\x24\x09\x63\x20\x23\ -\x32\x45\x32\x31\x36\x30\x22\x2c\x0a\x22\x78\x24\x09\x63\x20\x23\ -\x33\x39\x32\x44\x36\x38\x22\x2c\x0a\x22\x79\x24\x09\x63\x20\x23\ -\x39\x31\x38\x46\x41\x46\x22\x2c\x0a\x22\x7a\x24\x09\x63\x20\x23\ -\x38\x39\x38\x32\x41\x35\x22\x2c\x0a\x22\x41\x24\x09\x63\x20\x23\ -\x39\x35\x38\x46\x41\x45\x22\x2c\x0a\x22\x42\x24\x09\x63\x20\x23\ -\x46\x45\x46\x44\x46\x43\x22\x2c\x0a\x22\x43\x24\x09\x63\x20\x23\ -\x46\x39\x46\x39\x46\x41\x22\x2c\x0a\x22\x44\x24\x09\x63\x20\x23\ -\x46\x37\x46\x36\x46\x38\x22\x2c\x0a\x22\x45\x24\x09\x63\x20\x23\ -\x43\x39\x44\x31\x44\x42\x22\x2c\x0a\x22\x46\x24\x09\x63\x20\x23\ -\x33\x43\x36\x37\x38\x46\x22\x2c\x0a\x22\x47\x24\x09\x63\x20\x23\ -\x31\x30\x33\x41\x37\x32\x22\x2c\x0a\x22\x48\x24\x09\x63\x20\x23\ -\x33\x34\x33\x35\x36\x44\x22\x2c\x0a\x22\x49\x24\x09\x63\x20\x23\ -\x35\x38\x34\x46\x37\x45\x22\x2c\x0a\x22\x4a\x24\x09\x63\x20\x23\ -\x36\x37\x35\x45\x38\x39\x22\x2c\x0a\x22\x4b\x24\x09\x63\x20\x23\ -\x32\x43\x31\x46\x35\x46\x22\x2c\x0a\x22\x4c\x24\x09\x63\x20\x23\ -\x36\x34\x35\x43\x38\x39\x22\x2c\x0a\x22\x4d\x24\x09\x63\x20\x23\ -\x45\x36\x45\x35\x45\x42\x22\x2c\x0a\x22\x4e\x24\x09\x63\x20\x23\ -\x44\x32\x43\x46\x44\x42\x22\x2c\x0a\x22\x4f\x24\x09\x63\x20\x23\ -\x34\x31\x33\x35\x36\x41\x22\x2c\x0a\x22\x50\x24\x09\x63\x20\x23\ -\x32\x35\x31\x38\x35\x42\x22\x2c\x0a\x22\x51\x24\x09\x63\x20\x23\ -\x35\x35\x34\x44\x37\x45\x22\x2c\x0a\x22\x52\x24\x09\x63\x20\x23\ -\x46\x32\x46\x32\x46\x34\x22\x2c\x0a\x22\x53\x24\x09\x63\x20\x23\ -\x41\x42\x43\x30\x43\x45\x22\x2c\x0a\x22\x54\x24\x09\x63\x20\x23\ -\x39\x36\x42\x32\x43\x33\x22\x2c\x0a\x22\x55\x24\x09\x63\x20\x23\ -\x45\x35\x45\x43\x45\x46\x22\x2c\x0a\x22\x56\x24\x09\x63\x20\x23\ -\x46\x31\x46\x35\x46\x35\x22\x2c\x0a\x22\x57\x24\x09\x63\x20\x23\ -\x38\x42\x38\x34\x41\x35\x22\x2c\x0a\x22\x58\x24\x09\x63\x20\x23\ -\x32\x35\x31\x38\x35\x39\x22\x2c\x0a\x22\x59\x24\x09\x63\x20\x23\ -\x33\x31\x32\x33\x35\x46\x22\x2c\x0a\x22\x5a\x24\x09\x63\x20\x23\ -\x44\x44\x44\x42\x45\x35\x22\x2c\x0a\x22\x60\x24\x09\x63\x20\x23\ -\x35\x30\x34\x35\x37\x39\x22\x2c\x0a\x22\x20\x25\x09\x63\x20\x23\ -\x33\x43\x33\x32\x36\x44\x22\x2c\x0a\x22\x2e\x25\x09\x63\x20\x23\ -\x37\x41\x37\x36\x39\x44\x22\x2c\x0a\x22\x2b\x25\x09\x63\x20\x23\ -\x45\x34\x45\x37\x45\x43\x22\x2c\x0a\x22\x40\x25\x09\x63\x20\x23\ -\x44\x41\x44\x38\x45\x31\x22\x2c\x0a\x22\x23\x25\x09\x63\x20\x23\ -\x34\x43\x34\x31\x37\x37\x22\x2c\x0a\x22\x24\x25\x09\x63\x20\x23\ -\x38\x38\x38\x31\x41\x34\x22\x2c\x0a\x22\x25\x25\x09\x63\x20\x23\ -\x45\x44\x45\x43\x45\x46\x22\x2c\x0a\x22\x26\x25\x09\x63\x20\x23\ -\x44\x34\x44\x32\x44\x44\x22\x2c\x0a\x22\x2a\x25\x09\x63\x20\x23\ -\x43\x42\x43\x38\x44\x36\x22\x2c\x0a\x22\x3d\x25\x09\x63\x20\x23\ -\x44\x30\x43\x44\x44\x39\x22\x2c\x0a\x22\x2d\x25\x09\x63\x20\x23\ -\x44\x37\x44\x35\x44\x46\x22\x2c\x0a\x22\x3b\x25\x09\x63\x20\x23\ -\x43\x46\x44\x36\x44\x46\x22\x2c\x0a\x22\x3e\x25\x09\x63\x20\x23\ -\x36\x33\x38\x44\x41\x41\x22\x2c\x0a\x22\x2c\x25\x09\x63\x20\x23\ -\x34\x33\x37\x34\x39\x38\x22\x2c\x0a\x22\x27\x25\x09\x63\x20\x23\ -\x35\x30\x35\x36\x38\x34\x22\x2c\x0a\x22\x29\x25\x09\x63\x20\x23\ -\x39\x35\x38\x46\x41\x42\x22\x2c\x0a\x22\x21\x25\x09\x63\x20\x23\ -\x46\x30\x45\x46\x46\x32\x22\x2c\x0a\x22\x7e\x25\x09\x63\x20\x23\ -\x45\x46\x45\x46\x46\x32\x22\x2c\x0a\x22\x7b\x25\x09\x63\x20\x23\ -\x37\x37\x37\x30\x39\x37\x22\x2c\x0a\x22\x5d\x25\x09\x63\x20\x23\ -\x32\x45\x32\x31\x36\x31\x22\x2c\x0a\x22\x5e\x25\x09\x63\x20\x23\ -\x36\x33\x35\x42\x38\x39\x22\x2c\x0a\x22\x2f\x25\x09\x63\x20\x23\ -\x45\x38\x45\x37\x45\x44\x22\x2c\x0a\x22\x28\x25\x09\x63\x20\x23\ -\x42\x35\x42\x31\x43\x35\x22\x2c\x0a\x22\x5f\x25\x09\x63\x20\x23\ -\x36\x37\x36\x30\x38\x42\x22\x2c\x0a\x22\x3a\x25\x09\x63\x20\x23\ -\x46\x39\x46\x39\x46\x39\x22\x2c\x0a\x22\x3c\x25\x09\x63\x20\x23\ -\x43\x41\x44\x37\x44\x46\x22\x2c\x0a\x22\x5b\x25\x09\x63\x20\x23\ -\x36\x30\x38\x41\x41\x37\x22\x2c\x0a\x22\x7d\x25\x09\x63\x20\x23\ -\x37\x41\x39\x44\x42\x35\x22\x2c\x0a\x22\x7c\x25\x09\x63\x20\x23\ -\x41\x37\x42\x45\x43\x43\x22\x2c\x0a\x22\x31\x25\x09\x63\x20\x23\ -\x41\x44\x41\x38\x42\x45\x22\x2c\x0a\x22\x32\x25\x09\x63\x20\x23\ -\x32\x38\x31\x43\x35\x44\x22\x2c\x0a\x22\x33\x25\x09\x63\x20\x23\ -\x32\x45\x32\x31\x35\x46\x22\x2c\x0a\x22\x34\x25\x09\x63\x20\x23\ -\x33\x33\x32\x35\x36\x31\x22\x2c\x0a\x22\x35\x25\x09\x63\x20\x23\ -\x34\x33\x33\x37\x36\x45\x22\x2c\x0a\x22\x36\x25\x09\x63\x20\x23\ -\x45\x31\x44\x46\x45\x38\x22\x2c\x0a\x22\x37\x25\x09\x63\x20\x23\ -\x45\x30\x44\x46\x45\x38\x22\x2c\x0a\x22\x38\x25\x09\x63\x20\x23\ -\x46\x32\x46\x31\x46\x33\x22\x2c\x0a\x22\x39\x25\x09\x63\x20\x23\ -\x37\x46\x37\x38\x39\x45\x22\x2c\x0a\x22\x30\x25\x09\x63\x20\x23\ -\x35\x33\x34\x39\x37\x44\x22\x2c\x0a\x22\x61\x25\x09\x63\x20\x23\ -\x46\x30\x45\x46\x46\x33\x22\x2c\x0a\x22\x62\x25\x09\x63\x20\x23\ -\x45\x38\x45\x36\x45\x43\x22\x2c\x0a\x22\x63\x25\x09\x63\x20\x23\ -\x36\x35\x35\x44\x38\x39\x22\x2c\x0a\x22\x64\x25\x09\x63\x20\x23\ -\x32\x46\x32\x34\x36\x31\x22\x2c\x0a\x22\x65\x25\x09\x63\x20\x23\ -\x33\x33\x32\x39\x36\x34\x22\x2c\x0a\x22\x66\x25\x09\x63\x20\x23\ -\x33\x34\x33\x32\x36\x42\x22\x2c\x0a\x22\x67\x25\x09\x63\x20\x23\ -\x32\x43\x35\x32\x38\x32\x22\x2c\x0a\x22\x68\x25\x09\x63\x20\x23\ -\x34\x35\x37\x38\x39\x43\x22\x2c\x0a\x22\x69\x25\x09\x63\x20\x23\ -\x42\x44\x43\x43\x44\x37\x22\x2c\x0a\x22\x6a\x25\x09\x63\x20\x23\ -\x36\x42\x36\x32\x38\x44\x22\x2c\x0a\x22\x6b\x25\x09\x63\x20\x23\ -\x36\x43\x36\x34\x38\x46\x22\x2c\x0a\x22\x6c\x25\x09\x63\x20\x23\ -\x43\x43\x43\x39\x44\x37\x22\x2c\x0a\x22\x6d\x25\x09\x63\x20\x23\ -\x45\x35\x45\x34\x45\x41\x22\x2c\x0a\x22\x6e\x25\x09\x63\x20\x23\ -\x37\x42\x37\x32\x39\x36\x22\x2c\x0a\x22\x6f\x25\x09\x63\x20\x23\ -\x33\x33\x32\x35\x35\x46\x22\x2c\x0a\x22\x70\x25\x09\x63\x20\x23\ -\x38\x37\x38\x31\x41\x33\x22\x2c\x0a\x22\x71\x25\x09\x63\x20\x23\ -\x46\x32\x46\x35\x46\x35\x22\x2c\x0a\x22\x72\x25\x09\x63\x20\x23\ -\x41\x46\x43\x32\x43\x46\x22\x2c\x0a\x22\x73\x25\x09\x63\x20\x23\ -\x45\x46\x46\x33\x46\x34\x22\x2c\x0a\x22\x74\x25\x09\x63\x20\x23\ -\x46\x33\x46\x36\x46\x37\x22\x2c\x0a\x22\x75\x25\x09\x63\x20\x23\ -\x44\x30\x43\x44\x44\x38\x22\x2c\x0a\x22\x76\x25\x09\x63\x20\x23\ -\x33\x42\x32\x46\x36\x39\x22\x2c\x0a\x22\x77\x25\x09\x63\x20\x23\ -\x32\x39\x31\x42\x35\x42\x22\x2c\x0a\x22\x78\x25\x09\x63\x20\x23\ -\x33\x44\x33\x31\x36\x41\x22\x2c\x0a\x22\x79\x25\x09\x63\x20\x23\ -\x46\x37\x46\x37\x46\x38\x22\x2c\x0a\x22\x7a\x25\x09\x63\x20\x23\ -\x45\x45\x45\x44\x46\x31\x22\x2c\x0a\x22\x41\x25\x09\x63\x20\x23\ -\x43\x32\x42\x46\x43\x44\x22\x2c\x0a\x22\x42\x25\x09\x63\x20\x23\ -\x37\x33\x36\x43\x39\x34\x22\x2c\x0a\x22\x43\x25\x09\x63\x20\x23\ -\x44\x45\x44\x43\x45\x33\x22\x2c\x0a\x22\x44\x25\x09\x63\x20\x23\ -\x44\x30\x43\x45\x44\x41\x22\x2c\x0a\x22\x45\x25\x09\x63\x20\x23\ -\x42\x33\x41\x46\x43\x34\x22\x2c\x0a\x22\x46\x25\x09\x63\x20\x23\ -\x39\x32\x39\x34\x41\x44\x22\x2c\x0a\x22\x47\x25\x09\x63\x20\x23\ -\x33\x31\x35\x36\x38\x32\x22\x2c\x0a\x22\x48\x25\x09\x63\x20\x23\ -\x34\x31\x37\x36\x39\x43\x22\x2c\x0a\x22\x49\x25\x09\x63\x20\x23\ -\x42\x43\x43\x46\x44\x41\x22\x2c\x0a\x22\x4a\x25\x09\x63\x20\x23\ -\x42\x39\x42\x36\x43\x38\x22\x2c\x0a\x22\x4b\x25\x09\x63\x20\x23\ -\x33\x39\x32\x45\x36\x41\x22\x2c\x0a\x22\x4c\x25\x09\x63\x20\x23\ -\x37\x39\x37\x32\x39\x38\x22\x2c\x0a\x22\x4d\x25\x09\x63\x20\x23\ -\x44\x30\x43\x45\x44\x39\x22\x2c\x0a\x22\x4e\x25\x09\x63\x20\x23\ -\x46\x41\x46\x41\x46\x41\x22\x2c\x0a\x22\x4f\x25\x09\x63\x20\x23\ -\x44\x42\x44\x39\x45\x31\x22\x2c\x0a\x22\x50\x25\x09\x63\x20\x23\ -\x38\x44\x38\x36\x41\x34\x22\x2c\x0a\x22\x51\x25\x09\x63\x20\x23\ -\x41\x44\x41\x39\x43\x30\x22\x2c\x0a\x22\x52\x25\x09\x63\x20\x23\ -\x44\x44\x45\x36\x45\x41\x22\x2c\x0a\x22\x53\x25\x09\x63\x20\x23\ -\x42\x32\x43\x36\x44\x32\x22\x2c\x0a\x22\x54\x25\x09\x63\x20\x23\ -\x38\x46\x41\x43\x42\x46\x22\x2c\x0a\x22\x55\x25\x09\x63\x20\x23\ -\x43\x37\x44\x36\x44\x45\x22\x2c\x0a\x22\x56\x25\x09\x63\x20\x23\ -\x35\x45\x35\x33\x38\x30\x22\x2c\x0a\x22\x57\x25\x09\x63\x20\x23\ -\x32\x46\x32\x33\x36\x30\x22\x2c\x0a\x22\x58\x25\x09\x63\x20\x23\ -\x32\x33\x31\x37\x35\x39\x22\x2c\x0a\x22\x59\x25\x09\x63\x20\x23\ -\x36\x32\x35\x39\x38\x34\x22\x2c\x0a\x22\x5a\x25\x09\x63\x20\x23\ -\x36\x39\x36\x31\x38\x41\x22\x2c\x0a\x22\x60\x25\x09\x63\x20\x23\ -\x35\x45\x35\x38\x38\x36\x22\x2c\x0a\x22\x20\x26\x09\x63\x20\x23\ -\x35\x41\x35\x32\x38\x34\x22\x2c\x0a\x22\x2e\x26\x09\x63\x20\x23\ -\x35\x41\x35\x31\x38\x33\x22\x2c\x0a\x22\x2b\x26\x09\x63\x20\x23\ -\x34\x44\x34\x33\x37\x39\x22\x2c\x0a\x22\x40\x26\x09\x63\x20\x23\ -\x33\x30\x32\x35\x36\x32\x22\x2c\x0a\x22\x23\x26\x09\x63\x20\x23\ -\x36\x35\x35\x43\x38\x39\x22\x2c\x0a\x22\x24\x26\x09\x63\x20\x23\ -\x41\x42\x41\x36\x42\x45\x22\x2c\x0a\x22\x25\x26\x09\x63\x20\x23\ -\x43\x45\x44\x34\x44\x45\x22\x2c\x0a\x22\x26\x26\x09\x63\x20\x23\ -\x36\x36\x38\x46\x41\x43\x22\x2c\x0a\x22\x2a\x26\x09\x63\x20\x23\ -\x32\x39\x35\x42\x38\x38\x22\x2c\x0a\x22\x3d\x26\x09\x63\x20\x23\ -\x38\x32\x39\x31\x41\x44\x22\x2c\x0a\x22\x2d\x26\x09\x63\x20\x23\ -\x39\x34\x38\x45\x41\x41\x22\x2c\x0a\x22\x3b\x26\x09\x63\x20\x23\ -\x34\x44\x34\x33\x37\x35\x22\x2c\x0a\x22\x3e\x26\x09\x63\x20\x23\ -\x33\x45\x33\x33\x36\x44\x22\x2c\x0a\x22\x2c\x26\x09\x63\x20\x23\ -\x36\x44\x36\x34\x38\x44\x22\x2c\x0a\x22\x27\x26\x09\x63\x20\x23\ -\x38\x38\x38\x30\x41\x30\x22\x2c\x0a\x22\x29\x26\x09\x63\x20\x23\ -\x38\x39\x38\x31\x41\x31\x22\x2c\x0a\x22\x21\x26\x09\x63\x20\x23\ -\x37\x37\x36\x45\x39\x33\x22\x2c\x0a\x22\x7e\x26\x09\x63\x20\x23\ -\x35\x34\x34\x38\x37\x37\x22\x2c\x0a\x22\x7b\x26\x09\x63\x20\x23\ -\x33\x37\x32\x44\x36\x38\x22\x2c\x0a\x22\x5d\x26\x09\x63\x20\x23\ -\x44\x37\x44\x35\x45\x30\x22\x2c\x0a\x22\x5e\x26\x09\x63\x20\x23\ -\x44\x30\x44\x43\x45\x33\x22\x2c\x0a\x22\x2f\x26\x09\x63\x20\x23\ -\x36\x46\x39\x35\x41\x46\x22\x2c\x0a\x22\x28\x26\x09\x63\x20\x23\ -\x39\x34\x42\x30\x43\x33\x22\x2c\x0a\x22\x5f\x26\x09\x63\x20\x23\ -\x39\x38\x42\x33\x43\x34\x22\x2c\x0a\x22\x3a\x26\x09\x63\x20\x23\ -\x38\x38\x38\x31\x41\x32\x22\x2c\x0a\x22\x3c\x26\x09\x63\x20\x23\ -\x33\x30\x32\x33\x35\x45\x22\x2c\x0a\x22\x5b\x26\x09\x63\x20\x23\ -\x32\x32\x31\x36\x35\x42\x22\x2c\x0a\x22\x7d\x26\x09\x63\x20\x23\ -\x32\x41\x31\x44\x35\x44\x22\x2c\x0a\x22\x7c\x26\x09\x63\x20\x23\ -\x33\x44\x33\x42\x36\x45\x22\x2c\x0a\x22\x31\x26\x09\x63\x20\x23\ -\x32\x44\x35\x34\x38\x31\x22\x2c\x0a\x22\x32\x26\x09\x63\x20\x23\ -\x30\x46\x34\x31\x37\x35\x22\x2c\x0a\x22\x33\x26\x09\x63\x20\x23\ -\x32\x34\x32\x44\x36\x38\x22\x2c\x0a\x22\x34\x26\x09\x63\x20\x23\ -\x33\x38\x32\x43\x36\x35\x22\x2c\x0a\x22\x35\x26\x09\x63\x20\x23\ -\x32\x36\x31\x41\x35\x41\x22\x2c\x0a\x22\x36\x26\x09\x63\x20\x23\ -\x33\x36\x32\x39\x36\x32\x22\x2c\x0a\x22\x37\x26\x09\x63\x20\x23\ -\x45\x34\x45\x41\x45\x45\x22\x2c\x0a\x22\x38\x26\x09\x63\x20\x23\ -\x42\x44\x43\x45\x44\x38\x22\x2c\x0a\x22\x39\x26\x09\x63\x20\x23\ -\x42\x46\x42\x43\x43\x44\x22\x2c\x0a\x22\x30\x26\x09\x63\x20\x23\ -\x32\x46\x32\x34\x36\x32\x22\x2c\x0a\x22\x61\x26\x09\x63\x20\x23\ -\x32\x43\x31\x45\x35\x45\x22\x2c\x0a\x22\x62\x26\x09\x63\x20\x23\ -\x32\x42\x32\x43\x36\x33\x22\x2c\x0a\x22\x63\x26\x09\x63\x20\x23\ -\x31\x39\x34\x30\x37\x33\x22\x2c\x0a\x22\x64\x26\x09\x63\x20\x23\ -\x31\x34\x34\x31\x37\x36\x22\x2c\x0a\x22\x65\x26\x09\x63\x20\x23\ -\x32\x36\x32\x44\x36\x35\x22\x2c\x0a\x22\x66\x26\x09\x63\x20\x23\ -\x41\x34\x39\x46\x42\x38\x22\x2c\x0a\x22\x67\x26\x09\x63\x20\x23\ -\x46\x43\x46\x44\x46\x43\x22\x2c\x0a\x22\x68\x26\x09\x63\x20\x23\ -\x45\x35\x45\x42\x45\x46\x22\x2c\x0a\x22\x69\x26\x09\x63\x20\x23\ -\x36\x41\x36\x32\x38\x44\x22\x2c\x0a\x22\x6a\x26\x09\x63\x20\x23\ -\x32\x35\x32\x41\x36\x35\x22\x2c\x0a\x22\x6b\x26\x09\x63\x20\x23\ -\x31\x34\x34\x30\x37\x33\x22\x2c\x0a\x22\x6c\x26\x09\x63\x20\x23\ -\x32\x32\x32\x37\x36\x34\x22\x2c\x0a\x22\x6d\x26\x09\x63\x20\x23\ -\x32\x45\x32\x30\x35\x43\x22\x2c\x0a\x22\x6e\x26\x09\x63\x20\x23\ -\x35\x32\x34\x39\x37\x44\x22\x2c\x0a\x22\x6f\x26\x09\x63\x20\x23\ -\x45\x34\x45\x42\x45\x45\x22\x2c\x0a\x22\x70\x26\x09\x63\x20\x23\ -\x39\x38\x42\x32\x43\x33\x22\x2c\x0a\x22\x71\x26\x09\x63\x20\x23\ -\x46\x30\x46\x34\x46\x35\x22\x2c\x0a\x22\x72\x26\x09\x63\x20\x23\ -\x42\x34\x42\x31\x43\x35\x22\x2c\x0a\x22\x73\x26\x09\x63\x20\x23\ -\x32\x43\x32\x30\x36\x30\x22\x2c\x0a\x22\x74\x26\x09\x63\x20\x23\ -\x32\x38\x31\x46\x35\x45\x22\x2c\x0a\x22\x75\x26\x09\x63\x20\x23\ -\x32\x34\x32\x32\x36\x30\x22\x2c\x0a\x22\x76\x26\x09\x63\x20\x23\ -\x32\x41\x33\x30\x36\x37\x22\x2c\x0a\x22\x77\x26\x09\x63\x20\x23\ -\x31\x43\x33\x31\x36\x41\x22\x2c\x0a\x22\x78\x26\x09\x63\x20\x23\ -\x31\x30\x33\x46\x37\x34\x22\x2c\x0a\x22\x79\x26\x09\x63\x20\x23\ -\x31\x39\x33\x46\x37\x34\x22\x2c\x0a\x22\x7a\x26\x09\x63\x20\x23\ -\x32\x44\x32\x45\x36\x37\x22\x2c\x0a\x22\x41\x26\x09\x63\x20\x23\ -\x33\x37\x32\x39\x36\x31\x22\x2c\x0a\x22\x42\x26\x09\x63\x20\x23\ -\x32\x42\x31\x45\x35\x43\x22\x2c\x0a\x22\x43\x26\x09\x63\x20\x23\ -\x39\x44\x39\x38\x42\x34\x22\x2c\x0a\x22\x44\x26\x09\x63\x20\x23\ -\x43\x39\x44\x37\x44\x46\x22\x2c\x0a\x22\x45\x26\x09\x63\x20\x23\ -\x36\x35\x38\x44\x41\x39\x22\x2c\x0a\x22\x46\x26\x09\x63\x20\x23\ -\x39\x30\x41\x44\x43\x32\x22\x2c\x0a\x22\x47\x26\x09\x63\x20\x23\ -\x37\x36\x36\x45\x39\x36\x22\x2c\x0a\x22\x48\x26\x09\x63\x20\x23\ -\x32\x32\x31\x37\x35\x41\x22\x2c\x0a\x22\x49\x26\x09\x63\x20\x23\ -\x31\x39\x32\x37\x36\x34\x22\x2c\x0a\x22\x4a\x26\x09\x63\x20\x23\ -\x31\x32\x33\x37\x36\x46\x22\x2c\x0a\x22\x4b\x26\x09\x63\x20\x23\ -\x31\x30\x34\x32\x37\x35\x22\x2c\x0a\x22\x4c\x26\x09\x63\x20\x23\ -\x30\x42\x34\x35\x37\x38\x22\x2c\x0a\x22\x4d\x26\x09\x63\x20\x23\ -\x30\x43\x34\x42\x37\x43\x22\x2c\x0a\x22\x4e\x26\x09\x63\x20\x23\ -\x30\x39\x34\x43\x37\x44\x22\x2c\x0a\x22\x4f\x26\x09\x63\x20\x23\ -\x31\x42\x33\x44\x37\x32\x22\x2c\x0a\x22\x50\x26\x09\x63\x20\x23\ -\x32\x44\x32\x38\x36\x33\x22\x2c\x0a\x22\x51\x26\x09\x63\x20\x23\ -\x33\x31\x32\x33\x36\x30\x22\x2c\x0a\x22\x52\x26\x09\x63\x20\x23\ -\x36\x34\x35\x43\x38\x41\x22\x2c\x0a\x22\x53\x26\x09\x63\x20\x23\ -\x44\x35\x44\x46\x45\x36\x22\x2c\x0a\x22\x54\x26\x09\x63\x20\x23\ -\x41\x45\x43\x32\x43\x46\x22\x2c\x0a\x22\x55\x26\x09\x63\x20\x23\ -\x42\x36\x43\x38\x44\x35\x22\x2c\x0a\x22\x56\x26\x09\x63\x20\x23\ -\x41\x38\x42\x45\x43\x45\x22\x2c\x0a\x22\x57\x26\x09\x63\x20\x23\ -\x39\x43\x41\x36\x42\x44\x22\x2c\x0a\x22\x58\x26\x09\x63\x20\x23\ -\x32\x34\x32\x36\x36\x35\x22\x2c\x0a\x22\x59\x26\x09\x63\x20\x23\ -\x32\x30\x31\x35\x35\x39\x22\x2c\x0a\x22\x5a\x26\x09\x63\x20\x23\ -\x31\x42\x32\x38\x36\x36\x22\x2c\x0a\x22\x60\x26\x09\x63\x20\x23\ -\x30\x45\x34\x35\x37\x41\x22\x2c\x0a\x22\x20\x2a\x09\x63\x20\x23\ -\x30\x38\x34\x42\x37\x45\x22\x2c\x0a\x22\x2e\x2a\x09\x63\x20\x23\ -\x30\x38\x34\x42\x37\x44\x22\x2c\x0a\x22\x2b\x2a\x09\x63\x20\x23\ -\x30\x38\x34\x41\x37\x45\x22\x2c\x0a\x22\x40\x2a\x09\x63\x20\x23\ -\x30\x46\x34\x36\x37\x38\x22\x2c\x0a\x22\x23\x2a\x09\x63\x20\x23\ -\x33\x31\x33\x30\x36\x38\x22\x2c\x0a\x22\x24\x2a\x09\x63\x20\x23\ -\x33\x38\x32\x39\x36\x31\x22\x2c\x0a\x22\x25\x2a\x09\x63\x20\x23\ -\x33\x38\x32\x39\x36\x32\x22\x2c\x0a\x22\x26\x2a\x09\x63\x20\x23\ -\x32\x37\x31\x41\x35\x44\x22\x2c\x0a\x22\x2a\x2a\x09\x63\x20\x23\ -\x33\x43\x33\x32\x36\x43\x22\x2c\x0a\x22\x3d\x2a\x09\x63\x20\x23\ -\x42\x42\x42\x38\x43\x41\x22\x2c\x0a\x22\x2d\x2a\x09\x63\x20\x23\ -\x38\x39\x41\x36\x42\x42\x22\x2c\x0a\x22\x3b\x2a\x09\x63\x20\x23\ -\x43\x39\x44\x38\x45\x30\x22\x2c\x0a\x22\x3e\x2a\x09\x63\x20\x23\ -\x46\x42\x46\x43\x46\x43\x22\x2c\x0a\x22\x2c\x2a\x09\x63\x20\x23\ -\x36\x44\x39\x34\x42\x30\x22\x2c\x0a\x22\x27\x2a\x09\x63\x20\x23\ -\x33\x38\x35\x34\x38\x33\x22\x2c\x0a\x22\x29\x2a\x09\x63\x20\x23\ -\x33\x33\x32\x39\x36\x37\x22\x2c\x0a\x22\x21\x2a\x09\x63\x20\x23\ -\x31\x46\x31\x33\x35\x38\x22\x2c\x0a\x22\x7e\x2a\x09\x63\x20\x23\ -\x32\x36\x31\x39\x35\x43\x22\x2c\x0a\x22\x7b\x2a\x09\x63\x20\x23\ -\x31\x43\x33\x39\x37\x30\x22\x2c\x0a\x22\x5d\x2a\x09\x63\x20\x23\ -\x30\x38\x34\x41\x37\x43\x22\x2c\x0a\x22\x5e\x2a\x09\x63\x20\x23\ -\x30\x41\x34\x44\x37\x46\x22\x2c\x0a\x22\x2f\x2a\x09\x63\x20\x23\ -\x31\x42\x33\x45\x37\x32\x22\x2c\x0a\x22\x28\x2a\x09\x63\x20\x23\ -\x33\x33\x32\x34\x36\x30\x22\x2c\x0a\x22\x5f\x2a\x09\x63\x20\x23\ -\x33\x32\x32\x34\x36\x31\x22\x2c\x0a\x22\x3a\x2a\x09\x63\x20\x23\ -\x33\x31\x32\x34\x36\x30\x22\x2c\x0a\x22\x3c\x2a\x09\x63\x20\x23\ -\x32\x31\x31\x36\x35\x39\x22\x2c\x0a\x22\x5b\x2a\x09\x63\x20\x23\ -\x39\x41\x39\x35\x42\x31\x22\x2c\x0a\x22\x7d\x2a\x09\x63\x20\x23\ -\x43\x35\x44\x34\x44\x45\x22\x2c\x0a\x22\x7c\x2a\x09\x63\x20\x23\ -\x37\x45\x39\x45\x42\x36\x22\x2c\x0a\x22\x31\x2a\x09\x63\x20\x23\ -\x39\x36\x42\x32\x43\x34\x22\x2c\x0a\x22\x32\x2a\x09\x63\x20\x23\ -\x41\x39\x43\x30\x43\x46\x22\x2c\x0a\x22\x33\x2a\x09\x63\x20\x23\ -\x33\x34\x36\x42\x39\x32\x22\x2c\x0a\x22\x34\x2a\x09\x63\x20\x23\ -\x39\x44\x42\x36\x43\x38\x22\x2c\x0a\x22\x35\x2a\x09\x63\x20\x23\ -\x39\x43\x39\x37\x42\x33\x22\x2c\x0a\x22\x36\x2a\x09\x63\x20\x23\ -\x32\x39\x31\x45\x35\x44\x22\x2c\x0a\x22\x37\x2a\x09\x63\x20\x23\ -\x31\x46\x31\x36\x35\x41\x22\x2c\x0a\x22\x38\x2a\x09\x63\x20\x23\ -\x31\x39\x32\x42\x36\x37\x22\x2c\x0a\x22\x39\x2a\x09\x63\x20\x23\ -\x31\x30\x34\x33\x37\x36\x22\x2c\x0a\x22\x30\x2a\x09\x63\x20\x23\ -\x30\x44\x34\x32\x37\x37\x22\x2c\x0a\x22\x61\x2a\x09\x63\x20\x23\ -\x30\x41\x34\x42\x37\x44\x22\x2c\x0a\x22\x62\x2a\x09\x63\x20\x23\ -\x32\x36\x33\x33\x36\x41\x22\x2c\x0a\x22\x63\x2a\x09\x63\x20\x23\ -\x33\x35\x32\x36\x36\x30\x22\x2c\x0a\x22\x64\x2a\x09\x63\x20\x23\ -\x33\x30\x32\x31\x35\x45\x22\x2c\x0a\x22\x65\x2a\x09\x63\x20\x23\ -\x38\x46\x38\x38\x41\x41\x22\x2c\x0a\x22\x66\x2a\x09\x63\x20\x23\ -\x46\x45\x46\x44\x46\x44\x22\x2c\x0a\x22\x67\x2a\x09\x63\x20\x23\ -\x41\x35\x42\x42\x43\x41\x22\x2c\x0a\x22\x68\x2a\x09\x63\x20\x23\ -\x42\x45\x43\x46\x44\x39\x22\x2c\x0a\x22\x69\x2a\x09\x63\x20\x23\ -\x45\x39\x45\x46\x46\x30\x22\x2c\x0a\x22\x6a\x2a\x09\x63\x20\x23\ -\x41\x32\x42\x42\x43\x41\x22\x2c\x0a\x22\x6b\x2a\x09\x63\x20\x23\ -\x32\x41\x36\x34\x38\x44\x22\x2c\x0a\x22\x6c\x2a\x09\x63\x20\x23\ -\x43\x45\x44\x41\x45\x34\x22\x2c\x0a\x22\x6d\x2a\x09\x63\x20\x23\ -\x46\x44\x46\x44\x46\x43\x22\x2c\x0a\x22\x6e\x2a\x09\x63\x20\x23\ -\x39\x39\x39\x34\x42\x30\x22\x2c\x0a\x22\x6f\x2a\x09\x63\x20\x23\ -\x33\x32\x32\x36\x36\x35\x22\x2c\x0a\x22\x70\x2a\x09\x63\x20\x23\ -\x31\x42\x32\x32\x36\x31\x22\x2c\x0a\x22\x71\x2a\x09\x63\x20\x23\ -\x31\x30\x33\x36\x36\x46\x22\x2c\x0a\x22\x72\x2a\x09\x63\x20\x23\ -\x30\x43\x34\x35\x37\x38\x22\x2c\x0a\x22\x73\x2a\x09\x63\x20\x23\ -\x31\x39\x33\x35\x36\x45\x22\x2c\x0a\x22\x74\x2a\x09\x63\x20\x23\ -\x32\x32\x32\x30\x35\x46\x22\x2c\x0a\x22\x75\x2a\x09\x63\x20\x23\ -\x31\x36\x33\x35\x36\x45\x22\x2c\x0a\x22\x76\x2a\x09\x63\x20\x23\ -\x31\x30\x34\x34\x37\x37\x22\x2c\x0a\x22\x77\x2a\x09\x63\x20\x23\ -\x32\x44\x32\x37\x36\x32\x22\x2c\x0a\x22\x78\x2a\x09\x63\x20\x23\ -\x33\x31\x32\x32\x35\x46\x22\x2c\x0a\x22\x79\x2a\x09\x63\x20\x23\ -\x38\x42\x38\x35\x41\x36\x22\x2c\x0a\x22\x7a\x2a\x09\x63\x20\x23\ -\x41\x46\x43\x33\x44\x30\x22\x2c\x0a\x22\x41\x2a\x09\x63\x20\x23\ -\x39\x37\x42\x32\x43\x34\x22\x2c\x0a\x22\x42\x2a\x09\x63\x20\x23\ -\x39\x36\x42\x31\x43\x33\x22\x2c\x0a\x22\x43\x2a\x09\x63\x20\x23\ -\x39\x44\x42\x37\x43\x38\x22\x2c\x0a\x22\x44\x2a\x09\x63\x20\x23\ -\x32\x39\x36\x33\x38\x42\x22\x2c\x0a\x22\x45\x2a\x09\x63\x20\x23\ -\x42\x41\x43\x44\x44\x38\x22\x2c\x0a\x22\x46\x2a\x09\x63\x20\x23\ -\x45\x42\x46\x30\x46\x32\x22\x2c\x0a\x22\x47\x2a\x09\x63\x20\x23\ -\x34\x36\x36\x37\x39\x30\x22\x2c\x0a\x22\x48\x2a\x09\x63\x20\x23\ -\x31\x31\x34\x38\x37\x42\x22\x2c\x0a\x22\x49\x2a\x09\x63\x20\x23\ -\x30\x46\x33\x41\x37\x31\x22\x2c\x0a\x22\x4a\x2a\x09\x63\x20\x23\ -\x31\x41\x32\x36\x36\x35\x22\x2c\x0a\x22\x4b\x2a\x09\x63\x20\x23\ -\x32\x36\x32\x31\x35\x46\x22\x2c\x0a\x22\x4c\x2a\x09\x63\x20\x23\ -\x32\x30\x32\x41\x36\x35\x22\x2c\x0a\x22\x4d\x2a\x09\x63\x20\x23\ -\x32\x43\x32\x30\x35\x45\x22\x2c\x0a\x22\x4e\x2a\x09\x63\x20\x23\ -\x39\x36\x39\x30\x41\x45\x22\x2c\x0a\x22\x4f\x2a\x09\x63\x20\x23\ -\x45\x42\x46\x30\x46\x31\x22\x2c\x0a\x22\x50\x2a\x09\x63\x20\x23\ -\x42\x35\x43\x38\x44\x33\x22\x2c\x0a\x22\x51\x2a\x09\x63\x20\x23\ -\x41\x32\x42\x41\x43\x39\x22\x2c\x0a\x22\x52\x2a\x09\x63\x20\x23\ -\x39\x32\x41\x45\x43\x31\x22\x2c\x0a\x22\x53\x2a\x09\x63\x20\x23\ -\x46\x30\x46\x33\x46\x34\x22\x2c\x0a\x22\x54\x2a\x09\x63\x20\x23\ -\x42\x36\x43\x41\x44\x36\x22\x2c\x0a\x22\x55\x2a\x09\x63\x20\x23\ -\x33\x32\x36\x38\x39\x30\x22\x2c\x0a\x22\x56\x2a\x09\x63\x20\x23\ -\x33\x38\x36\x44\x39\x33\x22\x2c\x0a\x22\x57\x2a\x09\x63\x20\x23\ -\x32\x39\x36\x32\x38\x42\x22\x2c\x0a\x22\x58\x2a\x09\x63\x20\x23\ -\x35\x31\x37\x46\x41\x30\x22\x2c\x0a\x22\x59\x2a\x09\x63\x20\x23\ -\x38\x36\x39\x44\x42\x36\x22\x2c\x0a\x22\x5a\x2a\x09\x63\x20\x23\ -\x36\x35\x36\x32\x38\x44\x22\x2c\x0a\x22\x60\x2a\x09\x63\x20\x23\ -\x33\x30\x32\x34\x36\x30\x22\x2c\x0a\x22\x20\x3d\x09\x63\x20\x23\ -\x35\x41\x35\x31\x38\x30\x22\x2c\x0a\x22\x2e\x3d\x09\x63\x20\x23\ -\x44\x45\x45\x36\x45\x41\x22\x2c\x0a\x22\x2b\x3d\x09\x63\x20\x23\ -\x41\x46\x43\x35\x44\x32\x22\x2c\x0a\x22\x40\x3d\x09\x63\x20\x23\ -\x38\x46\x41\x41\x42\x44\x22\x2c\x0a\x22\x23\x3d\x09\x63\x20\x23\ -\x33\x44\x36\x46\x39\x33\x22\x2c\x0a\x22\x24\x3d\x09\x63\x20\x23\ -\x42\x33\x43\x37\x44\x34\x22\x2c\x0a\x22\x25\x3d\x09\x63\x20\x23\ -\x41\x31\x42\x39\x43\x41\x22\x2c\x0a\x22\x26\x3d\x09\x63\x20\x23\ -\x43\x33\x44\x33\x44\x44\x22\x2c\x0a\x22\x2a\x3d\x09\x63\x20\x23\ -\x46\x30\x46\x33\x46\x35\x22\x2c\x0a\x22\x3d\x3d\x09\x63\x20\x23\ -\x44\x45\x45\x31\x45\x36\x22\x2c\x0a\x22\x2d\x3d\x09\x63\x20\x23\ -\x39\x43\x39\x36\x42\x32\x22\x2c\x0a\x22\x3b\x3d\x09\x63\x20\x23\ -\x34\x46\x34\x35\x37\x41\x22\x2c\x0a\x22\x3e\x3d\x09\x63\x20\x23\ -\x34\x30\x33\x35\x36\x45\x22\x2c\x0a\x22\x2c\x3d\x09\x63\x20\x23\ -\x38\x45\x38\x38\x41\x38\x22\x2c\x0a\x22\x27\x3d\x09\x63\x20\x23\ -\x45\x30\x44\x46\x45\x35\x22\x2c\x0a\x22\x29\x3d\x09\x63\x20\x23\ -\x46\x41\x46\x42\x46\x41\x22\x2c\x0a\x22\x21\x3d\x09\x63\x20\x23\ -\x46\x32\x46\x36\x46\x36\x22\x2c\x0a\x22\x7e\x3d\x09\x63\x20\x23\ -\x37\x43\x39\x46\x42\x37\x22\x2c\x0a\x22\x7b\x3d\x09\x63\x20\x23\ -\x42\x42\x43\x44\x44\x37\x22\x2c\x0a\x22\x5d\x3d\x09\x63\x20\x23\ -\x43\x32\x44\x31\x44\x42\x22\x2c\x0a\x22\x5e\x3d\x09\x63\x20\x23\ -\x41\x34\x42\x43\x43\x43\x22\x2c\x0a\x22\x2f\x3d\x09\x63\x20\x23\ -\x38\x34\x41\x33\x42\x39\x22\x2c\x0a\x22\x28\x3d\x09\x63\x20\x23\ -\x43\x31\x44\x32\x44\x43\x22\x2c\x0a\x22\x5f\x3d\x09\x63\x20\x23\ -\x44\x45\x44\x44\x45\x35\x22\x2c\x0a\x22\x3a\x3d\x09\x63\x20\x23\ -\x39\x44\x39\x38\x42\x33\x22\x2c\x0a\x22\x3c\x3d\x09\x63\x20\x23\ -\x35\x44\x35\x34\x38\x33\x22\x2c\x0a\x22\x5b\x3d\x09\x63\x20\x23\ -\x33\x35\x32\x39\x36\x33\x22\x2c\x0a\x22\x7d\x3d\x09\x63\x20\x23\ -\x33\x36\x32\x37\x36\x31\x22\x2c\x0a\x22\x7c\x3d\x09\x63\x20\x23\ -\x35\x30\x34\x36\x37\x39\x22\x2c\x0a\x22\x31\x3d\x09\x63\x20\x23\ -\x39\x32\x38\x44\x41\x42\x22\x2c\x0a\x22\x32\x3d\x09\x63\x20\x23\ -\x44\x35\x44\x33\x44\x44\x22\x2c\x0a\x22\x33\x3d\x09\x63\x20\x23\ -\x44\x38\x45\x33\x45\x38\x22\x2c\x0a\x22\x34\x3d\x09\x63\x20\x23\ -\x39\x31\x41\x45\x43\x31\x22\x2c\x0a\x22\x35\x3d\x09\x63\x20\x23\ -\x38\x37\x41\x36\x42\x41\x22\x2c\x0a\x22\x36\x3d\x09\x63\x20\x23\ -\x44\x46\x45\x36\x45\x39\x22\x2c\x0a\x22\x37\x3d\x09\x63\x20\x23\ -\x37\x32\x39\x36\x42\x30\x22\x2c\x0a\x22\x38\x3d\x09\x63\x20\x23\ -\x37\x34\x39\x37\x42\x30\x22\x2c\x0a\x22\x39\x3d\x09\x63\x20\x23\ -\x39\x42\x42\x34\x43\x34\x22\x2c\x0a\x22\x30\x3d\x09\x63\x20\x23\ -\x39\x34\x42\x30\x43\x32\x22\x2c\x0a\x22\x61\x3d\x09\x63\x20\x23\ -\x42\x39\x43\x41\x44\x35\x22\x2c\x0a\x22\x62\x3d\x09\x63\x20\x23\ -\x39\x32\x41\x45\x43\x32\x22\x2c\x0a\x22\x63\x3d\x09\x63\x20\x23\ -\x42\x34\x43\x37\x44\x33\x22\x2c\x0a\x22\x64\x3d\x09\x63\x20\x23\ -\x46\x36\x46\x38\x46\x37\x22\x2c\x0a\x22\x65\x3d\x09\x63\x20\x23\ -\x45\x35\x45\x38\x45\x42\x22\x2c\x0a\x22\x66\x3d\x09\x63\x20\x23\ -\x43\x37\x43\x34\x44\x33\x22\x2c\x0a\x22\x67\x3d\x09\x63\x20\x23\ -\x37\x30\x36\x39\x39\x32\x22\x2c\x0a\x22\x68\x3d\x09\x63\x20\x23\ -\x35\x31\x34\x37\x37\x41\x22\x2c\x0a\x22\x69\x3d\x09\x63\x20\x23\ -\x33\x37\x32\x43\x36\x38\x22\x2c\x0a\x22\x6a\x3d\x09\x63\x20\x23\ -\x33\x34\x32\x39\x36\x37\x22\x2c\x0a\x22\x6b\x3d\x09\x63\x20\x23\ -\x33\x44\x33\x32\x36\x44\x22\x2c\x0a\x22\x6c\x3d\x09\x63\x20\x23\ -\x34\x43\x34\x32\x37\x38\x22\x2c\x0a\x22\x6d\x3d\x09\x63\x20\x23\ -\x36\x37\x35\x46\x38\x42\x22\x2c\x0a\x22\x6e\x3d\x09\x63\x20\x23\ -\x39\x34\x38\x44\x41\x45\x22\x2c\x0a\x22\x6f\x3d\x09\x63\x20\x23\ -\x43\x32\x42\x46\x43\x46\x22\x2c\x0a\x22\x70\x3d\x09\x63\x20\x23\ -\x45\x42\x45\x42\x45\x45\x22\x2c\x0a\x22\x71\x3d\x09\x63\x20\x23\ -\x43\x45\x44\x41\x45\x31\x22\x2c\x0a\x22\x72\x3d\x09\x63\x20\x23\ -\x41\x44\x43\x32\x44\x30\x22\x2c\x0a\x22\x73\x3d\x09\x63\x20\x23\ -\x41\x35\x42\x43\x43\x41\x22\x2c\x0a\x22\x74\x3d\x09\x63\x20\x23\ -\x36\x41\x39\x30\x41\x42\x22\x2c\x0a\x22\x75\x3d\x09\x63\x20\x23\ -\x37\x38\x39\x42\x42\x33\x22\x2c\x0a\x22\x76\x3d\x09\x63\x20\x23\ -\x42\x38\x43\x39\x44\x34\x22\x2c\x0a\x22\x77\x3d\x09\x63\x20\x23\ -\x41\x42\x43\x30\x43\x46\x22\x2c\x0a\x22\x78\x3d\x09\x63\x20\x23\ -\x39\x32\x42\x30\x43\x33\x22\x2c\x0a\x22\x79\x3d\x09\x63\x20\x23\ -\x39\x45\x42\x37\x43\x37\x22\x2c\x0a\x22\x7a\x3d\x09\x63\x20\x23\ -\x41\x35\x42\x43\x43\x42\x22\x2c\x0a\x22\x41\x3d\x09\x63\x20\x23\ -\x38\x42\x41\x39\x42\x46\x22\x2c\x0a\x22\x42\x3d\x09\x63\x20\x23\ -\x41\x44\x43\x31\x43\x45\x22\x2c\x0a\x22\x43\x3d\x09\x63\x20\x23\ -\x41\x36\x42\x44\x43\x43\x22\x2c\x0a\x22\x44\x3d\x09\x63\x20\x23\ -\x46\x34\x46\x37\x46\x37\x22\x2c\x0a\x22\x45\x3d\x09\x63\x20\x23\ -\x45\x31\x45\x37\x45\x42\x22\x2c\x0a\x22\x46\x3d\x09\x63\x20\x23\ -\x45\x45\x45\x45\x46\x31\x22\x2c\x0a\x22\x47\x3d\x09\x63\x20\x23\ -\x45\x30\x45\x30\x45\x38\x22\x2c\x0a\x22\x48\x3d\x09\x63\x20\x23\ -\x44\x42\x44\x39\x45\x33\x22\x2c\x0a\x22\x49\x3d\x09\x63\x20\x23\ -\x44\x39\x44\x37\x45\x31\x22\x2c\x0a\x22\x4a\x3d\x09\x63\x20\x23\ -\x44\x41\x44\x38\x45\x32\x22\x2c\x0a\x22\x4b\x3d\x09\x63\x20\x23\ -\x45\x31\x45\x30\x45\x38\x22\x2c\x0a\x22\x4c\x3d\x09\x63\x20\x23\ -\x45\x43\x45\x43\x46\x30\x22\x2c\x0a\x22\x4d\x3d\x09\x63\x20\x23\ -\x46\x38\x46\x38\x46\x38\x22\x2c\x0a\x22\x4e\x3d\x09\x63\x20\x23\ -\x44\x36\x45\x32\x45\x38\x22\x2c\x0a\x22\x4f\x3d\x09\x63\x20\x23\ -\x46\x37\x46\x39\x46\x39\x22\x2c\x0a\x22\x50\x3d\x09\x63\x20\x23\ -\x39\x30\x41\x44\x43\x30\x22\x2c\x0a\x22\x51\x3d\x09\x63\x20\x23\ -\x42\x36\x43\x39\x44\x36\x22\x2c\x0a\x22\x52\x3d\x09\x63\x20\x23\ -\x44\x36\x45\x31\x45\x37\x22\x2c\x0a\x22\x53\x3d\x09\x63\x20\x23\ -\x38\x35\x41\x35\x42\x42\x22\x2c\x0a\x22\x54\x3d\x09\x63\x20\x23\ -\x39\x38\x42\x33\x43\x33\x22\x2c\x0a\x22\x55\x3d\x09\x63\x20\x23\ -\x43\x46\x44\x42\x45\x31\x22\x2c\x0a\x22\x56\x3d\x09\x63\x20\x23\ -\x39\x37\x42\x32\x43\x35\x22\x2c\x0a\x22\x57\x3d\x09\x63\x20\x23\ -\x37\x35\x39\x39\x42\x33\x22\x2c\x0a\x22\x58\x3d\x09\x63\x20\x23\ -\x39\x30\x41\x44\x43\x31\x22\x2c\x0a\x22\x59\x3d\x09\x63\x20\x23\ -\x43\x36\x44\x35\x44\x44\x22\x2c\x0a\x22\x5a\x3d\x09\x63\x20\x23\ -\x34\x46\x37\x45\x39\x45\x22\x2c\x0a\x22\x60\x3d\x09\x63\x20\x23\ -\x41\x34\x42\x43\x43\x42\x22\x2c\x0a\x22\x20\x2d\x09\x63\x20\x23\ -\x44\x34\x44\x46\x45\x35\x22\x2c\x0a\x22\x2e\x2d\x09\x63\x20\x23\ -\x39\x43\x42\x36\x43\x38\x22\x2c\x0a\x22\x2b\x2d\x09\x63\x20\x23\ -\x42\x35\x43\x38\x44\x35\x22\x2c\x0a\x22\x40\x2d\x09\x63\x20\x23\ -\x42\x34\x43\x37\x44\x35\x22\x2c\x0a\x22\x23\x2d\x09\x63\x20\x23\ -\x42\x36\x43\x39\x44\x34\x22\x2c\x0a\x22\x24\x2d\x09\x63\x20\x23\ -\x42\x46\x44\x31\x44\x42\x22\x2c\x0a\x22\x25\x2d\x09\x63\x20\x23\ -\x38\x36\x41\x36\x42\x43\x22\x2c\x0a\x22\x26\x2d\x09\x63\x20\x23\ -\x39\x41\x42\x34\x43\x35\x22\x2c\x0a\x22\x2a\x2d\x09\x63\x20\x23\ -\x45\x33\x45\x41\x45\x44\x22\x2c\x0a\x22\x3d\x2d\x09\x63\x20\x23\ -\x41\x36\x42\x43\x43\x41\x22\x2c\x0a\x22\x2d\x2d\x09\x63\x20\x23\ -\x37\x31\x39\x36\x42\x30\x22\x2c\x0a\x22\x3b\x2d\x09\x63\x20\x23\ -\x41\x37\x42\x45\x43\x44\x22\x2c\x0a\x22\x3e\x2d\x09\x63\x20\x23\ -\x41\x46\x43\x34\x44\x31\x22\x2c\x0a\x22\x2c\x2d\x09\x63\x20\x23\ -\x45\x38\x45\x45\x46\x30\x22\x2c\x0a\x22\x27\x2d\x09\x63\x20\x23\ -\x39\x36\x42\x30\x43\x32\x22\x2c\x0a\x22\x29\x2d\x09\x63\x20\x23\ -\x46\x31\x46\x34\x46\x34\x22\x2c\x0a\x22\x21\x2d\x09\x63\x20\x23\ -\x42\x30\x43\x35\x44\x32\x22\x2c\x0a\x22\x7e\x2d\x09\x63\x20\x23\ -\x36\x36\x38\x45\x41\x39\x22\x2c\x0a\x22\x7b\x2d\x09\x63\x20\x23\ -\x35\x37\x38\x33\x41\x32\x22\x2c\x0a\x22\x5d\x2d\x09\x63\x20\x23\ -\x42\x37\x43\x41\x44\x35\x22\x2c\x0a\x22\x5e\x2d\x09\x63\x20\x23\ -\x39\x30\x41\x43\x43\x31\x22\x2c\x0a\x22\x2f\x2d\x09\x63\x20\x23\ -\x35\x34\x38\x31\x41\x31\x22\x2c\x0a\x22\x28\x2d\x09\x63\x20\x23\ -\x44\x38\x45\x31\x45\x37\x22\x2c\x0a\x22\x5f\x2d\x09\x63\x20\x23\ -\x35\x33\x38\x30\x41\x30\x22\x2c\x0a\x22\x3a\x2d\x09\x63\x20\x23\ -\x39\x35\x42\x31\x43\x33\x22\x2c\x0a\x22\x3c\x2d\x09\x63\x20\x23\ -\x35\x30\x37\x45\x39\x46\x22\x2c\x0a\x22\x5b\x2d\x09\x63\x20\x23\ -\x39\x38\x42\x32\x43\x34\x22\x2c\x0a\x22\x7d\x2d\x09\x63\x20\x23\ -\x38\x32\x41\x31\x42\x39\x22\x2c\x0a\x22\x7c\x2d\x09\x63\x20\x23\ -\x46\x42\x46\x43\x46\x42\x22\x2c\x0a\x22\x31\x2d\x09\x63\x20\x23\ -\x42\x41\x43\x43\x44\x38\x22\x2c\x0a\x22\x32\x2d\x09\x63\x20\x23\ -\x38\x34\x41\x33\x42\x38\x22\x2c\x0a\x22\x33\x2d\x09\x63\x20\x23\ -\x37\x46\x41\x31\x42\x37\x22\x2c\x0a\x22\x34\x2d\x09\x63\x20\x23\ -\x44\x46\x45\x37\x45\x42\x22\x2c\x0a\x22\x35\x2d\x09\x63\x20\x23\ -\x35\x37\x38\x32\x41\x32\x22\x2c\x0a\x22\x36\x2d\x09\x63\x20\x23\ -\x42\x39\x43\x42\x44\x36\x22\x2c\x0a\x22\x37\x2d\x09\x63\x20\x23\ -\x36\x31\x38\x41\x41\x38\x22\x2c\x0a\x22\x38\x2d\x09\x63\x20\x23\ -\x35\x38\x38\x34\x41\x33\x22\x2c\x0a\x22\x39\x2d\x09\x63\x20\x23\ -\x42\x41\x43\x42\x44\x37\x22\x2c\x0a\x22\x30\x2d\x09\x63\x20\x23\ -\x35\x44\x38\x37\x41\x35\x22\x2c\x0a\x22\x61\x2d\x09\x63\x20\x23\ -\x34\x44\x37\x43\x39\x44\x22\x2c\x0a\x22\x62\x2d\x09\x63\x20\x23\ -\x35\x31\x37\x45\x39\x46\x22\x2c\x0a\x22\x63\x2d\x09\x63\x20\x23\ -\x41\x39\x42\x46\x43\x46\x22\x2c\x0a\x22\x64\x2d\x09\x63\x20\x23\ -\x39\x42\x42\x35\x43\x37\x22\x2c\x0a\x22\x65\x2d\x09\x63\x20\x23\ -\x42\x35\x43\x39\x44\x35\x22\x2c\x0a\x22\x66\x2d\x09\x63\x20\x23\ -\x44\x32\x44\x44\x45\x34\x22\x2c\x0a\x22\x67\x2d\x09\x63\x20\x23\ -\x43\x32\x44\x32\x44\x44\x22\x2c\x0a\x22\x68\x2d\x09\x63\x20\x23\ -\x42\x37\x43\x39\x44\x36\x22\x2c\x0a\x22\x69\x2d\x09\x63\x20\x23\ -\x41\x42\x43\x31\x43\x46\x22\x2c\x0a\x22\x6a\x2d\x09\x63\x20\x23\ -\x41\x39\x42\x46\x43\x44\x22\x2c\x0a\x22\x6b\x2d\x09\x63\x20\x23\ -\x39\x36\x42\x30\x43\x33\x22\x2c\x0a\x22\x6c\x2d\x09\x63\x20\x23\ -\x39\x45\x42\x37\x43\x38\x22\x2c\x0a\x22\x6d\x2d\x09\x63\x20\x23\ -\x39\x36\x42\x31\x43\x34\x22\x2c\x0a\x22\x6e\x2d\x09\x63\x20\x23\ -\x42\x35\x43\x38\x44\x34\x22\x2c\x0a\x22\x6f\x2d\x09\x63\x20\x23\ -\x45\x45\x46\x32\x46\x33\x22\x2c\x0a\x22\x70\x2d\x09\x63\x20\x23\ -\x44\x42\x45\x34\x45\x39\x22\x2c\x0a\x22\x71\x2d\x09\x63\x20\x23\ -\x45\x31\x45\x38\x45\x42\x22\x2c\x0a\x22\x72\x2d\x09\x63\x20\x23\ -\x46\x43\x46\x43\x46\x42\x22\x2c\x0a\x22\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22\x2c\x0a\x22\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x2e\x20\x2b\x20\x40\x20\x23\x20\x24\x20\x25\x20\x26\x20\x2a\x20\ -\x3d\x20\x2d\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22\x2c\ -\x0a\x22\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3b\x20\ -\x3e\x20\x2c\x20\x27\x20\x29\x20\x21\x20\x7e\x20\x7b\x20\x5d\x20\ -\x5e\x20\x2f\x20\x28\x20\x5f\x20\x3a\x20\x3c\x20\x5b\x20\x7d\x20\ -\x7d\x20\x7c\x20\x31\x20\x32\x20\x33\x20\x34\x20\x35\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x22\x2c\x0a\x22\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x36\x20\ -\x37\x20\x38\x20\x39\x20\x30\x20\x61\x20\x62\x20\x63\x20\x64\x20\ -\x65\x20\x66\x20\x66\x20\x67\x20\x65\x20\x68\x20\x69\x20\x6a\x20\ -\x6b\x20\x6c\x20\x6d\x20\x6e\x20\x6f\x20\x70\x20\x71\x20\x72\x20\ -\x73\x20\x74\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x22\x2c\x0a\x22\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x3b\x20\ -\x75\x20\x76\x20\x77\x20\x78\x20\x79\x20\x5e\x20\x7e\x20\x7a\x20\ -\x78\x20\x41\x20\x42\x20\x43\x20\x66\x20\x66\x20\x44\x20\x45\x20\ -\x69\x20\x46\x20\x47\x20\x48\x20\x49\x20\x4a\x20\x4b\x20\x4c\x20\ -\x4d\x20\x4d\x20\x4e\x20\x4f\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22\x2c\x0a\x22\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x50\x20\x51\x20\x52\x20\x66\x20\x53\x20\x54\x20\x78\x20\x55\x20\ -\x56\x20\x57\x20\x41\x20\x58\x20\x59\x20\x5a\x20\x66\x20\x60\x20\ -\x20\x2e\x2e\x2e\x2b\x2e\x40\x2e\x23\x2e\x24\x2e\x65\x20\x64\x20\ -\x25\x2e\x26\x2e\x4d\x20\x4d\x20\x2a\x2e\x3d\x2e\x2d\x2e\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22\x2c\ -\x0a\x22\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x3b\x2e\x3e\x2e\x62\x20\x2c\x2e\x27\x2e\x68\x20\x29\x2e\x60\x20\ -\x21\x2e\x7e\x2e\x62\x20\x7b\x2e\x5d\x2e\x5e\x2e\x2f\x2e\x28\x2e\ -\x65\x20\x28\x2e\x5f\x2e\x3a\x2e\x3c\x2e\x5b\x2e\x7d\x2e\x43\x20\ -\x29\x2e\x5d\x2e\x7c\x2e\x31\x2e\x32\x2e\x33\x2e\x34\x2e\x35\x2e\ -\x36\x2e\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x22\x2c\x0a\x22\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x3b\x2e\x37\x2e\x38\x2e\x46\x20\x28\x2e\x5e\x2e\x67\x20\ -\x68\x20\x65\x20\x56\x20\x39\x2e\x2b\x2e\x30\x2e\x5d\x2e\x61\x2e\ -\x62\x2e\x63\x2e\x57\x20\x64\x2e\x65\x2e\x66\x2e\x67\x2e\x5d\x2e\ -\x68\x2e\x29\x2e\x68\x20\x65\x20\x65\x20\x5d\x2e\x69\x2e\x6a\x2e\ -\x6b\x2e\x6c\x2e\x4d\x20\x4d\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x22\x2c\x0a\x22\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x6d\x2e\x6e\x2e\x62\x20\x6a\x20\x6f\x2e\ -\x66\x20\x65\x20\x65\x20\x65\x20\x67\x20\x45\x20\x70\x2e\x5a\x20\ -\x68\x2e\x43\x20\x71\x2e\x62\x2e\x5f\x2e\x72\x2e\x73\x2e\x74\x2e\ -\x69\x20\x65\x20\x70\x2e\x69\x20\x5d\x2e\x29\x2e\x68\x20\x5d\x2e\ -\x75\x2e\x76\x2e\x77\x2e\x78\x2e\x4d\x20\x7d\x20\x79\x2e\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22\x2c\x0a\x22\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x7a\x2e\x62\x2e\x62\x20\x41\x2e\ -\x63\x20\x76\x20\x5d\x2e\x71\x2e\x65\x20\x68\x20\x68\x20\x65\x20\ -\x68\x20\x66\x20\x42\x2e\x66\x20\x65\x20\x71\x2e\x38\x20\x43\x2e\ -\x44\x2e\x29\x2e\x69\x20\x65\x20\x65\x20\x68\x20\x66\x20\x68\x20\ -\x65\x20\x65\x20\x45\x2e\x46\x2e\x47\x2e\x48\x2e\x4c\x20\x49\x2e\ -\x4a\x2e\x4b\x2e\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22\x2c\ -\x0a\x22\x20\x20\x20\x20\x20\x20\x20\x20\x4c\x2e\x38\x2e\x21\x2e\ -\x4d\x2e\x7d\x2e\x2b\x2e\x4e\x2e\x65\x20\x68\x20\x65\x20\x65\x20\ -\x65\x20\x5d\x2e\x66\x20\x66\x20\x29\x2e\x29\x2e\x65\x20\x67\x20\ -\x4f\x2e\x7c\x2e\x68\x20\x5d\x2e\x68\x20\x65\x20\x68\x20\x5d\x2e\ -\x66\x20\x67\x20\x67\x20\x50\x2e\x51\x2e\x52\x2e\x53\x2e\x54\x2e\ -\x55\x2e\x56\x2e\x57\x2e\x58\x2e\x59\x2e\x20\x20\x20\x20\x20\x20\ -\x20\x20\x22\x2c\x0a\x22\x20\x20\x20\x20\x20\x20\x20\x20\x5a\x2e\ -\x60\x2e\x20\x2b\x2e\x2b\x2f\x20\x2b\x2e\x65\x20\x65\x20\x42\x2e\ -\x29\x2e\x66\x20\x68\x20\x67\x20\x67\x20\x66\x20\x64\x20\x4e\x2e\ -\x2b\x2b\x40\x2b\x4f\x2e\x7c\x2e\x42\x2e\x29\x2e\x67\x20\x68\x20\ -\x67\x20\x23\x2b\x5d\x2e\x42\x2e\x7c\x2e\x24\x2b\x25\x2b\x26\x2b\ -\x68\x2e\x2a\x2b\x3d\x2b\x57\x2e\x2d\x2b\x3b\x2b\x3e\x2b\x20\x20\ -\x20\x20\x20\x20\x20\x20\x22\x2c\x0a\x22\x20\x20\x20\x20\x20\x20\ -\x2c\x2b\x27\x2b\x62\x20\x29\x2b\x21\x2b\x54\x20\x7e\x2b\x65\x20\ -\x66\x20\x7b\x2b\x71\x2e\x68\x20\x65\x20\x64\x20\x5d\x2b\x5e\x2b\ -\x2f\x2b\x28\x2b\x5f\x2b\x3c\x2e\x3a\x2b\x52\x20\x60\x20\x5a\x20\ -\x3c\x2b\x5b\x2b\x3c\x2b\x7d\x2b\x45\x20\x29\x2e\x7c\x2b\x31\x2b\ -\x32\x2b\x29\x2e\x5d\x2e\x5a\x20\x33\x2b\x34\x2b\x35\x2b\x36\x2b\ -\x37\x2b\x38\x2b\x20\x20\x20\x20\x20\x20\x22\x2c\x0a\x22\x20\x20\ -\x20\x20\x20\x20\x39\x2b\x30\x2b\x61\x2b\x62\x2b\x77\x20\x62\x2e\ -\x5d\x2e\x68\x20\x65\x20\x69\x20\x64\x20\x68\x20\x63\x2b\x64\x2b\ -\x2f\x2e\x7b\x20\x46\x20\x65\x2b\x38\x20\x77\x20\x20\x2e\x21\x2e\ -\x66\x2b\x2f\x2b\x67\x2b\x68\x2b\x63\x2b\x43\x20\x66\x20\x69\x2b\ -\x6a\x2b\x6b\x2b\x6c\x2b\x43\x20\x68\x2e\x5a\x20\x6d\x2b\x6e\x2b\ -\x6f\x2b\x70\x2b\x71\x2b\x72\x2b\x20\x20\x20\x20\x20\x20\x22\x2c\ -\x0a\x22\x20\x20\x20\x20\x73\x2b\x74\x2b\x7e\x2e\x7e\x20\x75\x2b\ -\x5e\x2b\x76\x20\x76\x2b\x71\x2e\x77\x2b\x29\x2e\x71\x2e\x42\x2e\ -\x78\x2b\x62\x2b\x63\x20\x5a\x20\x65\x20\x67\x20\x67\x20\x68\x20\ -\x64\x20\x79\x2b\x7a\x2b\x41\x2b\x72\x2e\x42\x2b\x43\x2b\x44\x2b\ -\x45\x2b\x46\x2b\x47\x2b\x48\x2b\x76\x2b\x49\x2b\x4a\x2b\x7d\x2b\ -\x4b\x2b\x4c\x2b\x2d\x2e\x4d\x2b\x4e\x2b\x4f\x2b\x50\x2b\x20\x20\ -\x20\x20\x22\x2c\x0a\x22\x20\x20\x20\x20\x51\x2b\x62\x20\x30\x2b\ -\x52\x2b\x53\x2b\x54\x2b\x55\x2b\x56\x2b\x57\x2b\x58\x2b\x59\x2b\ -\x5a\x2b\x65\x20\x60\x2b\x5f\x2e\x76\x20\x40\x2b\x20\x40\x2e\x40\ -\x2b\x40\x40\x40\x23\x40\x24\x40\x25\x40\x26\x40\x2a\x40\x41\x20\ -\x3d\x40\x2d\x40\x3b\x40\x3e\x40\x2c\x40\x27\x40\x29\x40\x21\x2b\ -\x5d\x2e\x43\x20\x5d\x2e\x21\x40\x7e\x40\x7b\x40\x5d\x40\x5e\x40\ -\x2f\x40\x20\x20\x20\x20\x22\x2c\x0a\x22\x20\x20\x20\x20\x28\x40\ -\x47\x20\x5f\x40\x3a\x40\x3c\x40\x5b\x40\x4d\x20\x4d\x20\x4d\x20\ -\x4d\x20\x7d\x40\x3c\x20\x7c\x40\x31\x40\x32\x40\x33\x40\x34\x40\ -\x35\x40\x36\x40\x37\x40\x38\x40\x39\x40\x30\x40\x61\x40\x62\x40\ -\x52\x20\x63\x40\x64\x40\x65\x40\x66\x40\x67\x40\x68\x40\x69\x40\ -\x6a\x40\x6b\x40\x21\x2b\x68\x20\x42\x2e\x6c\x40\x6d\x40\x6e\x40\ -\x6f\x40\x70\x40\x71\x40\x20\x20\x20\x20\x22\x2c\x0a\x22\x20\x20\ -\x72\x40\x73\x40\x75\x2b\x62\x2b\x74\x40\x75\x40\x76\x40\x77\x40\ -\x78\x40\x79\x40\x7a\x40\x4d\x20\x7d\x20\x3c\x20\x41\x40\x42\x40\ -\x43\x40\x44\x40\x7d\x20\x45\x40\x46\x40\x3b\x20\x7d\x20\x47\x40\ -\x48\x40\x2f\x2e\x49\x40\x4a\x40\x36\x2e\x4b\x40\x4c\x40\x4d\x40\ -\x4e\x40\x7d\x20\x4f\x40\x50\x40\x51\x40\x76\x2b\x42\x2e\x66\x20\ -\x52\x40\x53\x40\x54\x40\x55\x40\x56\x40\x57\x40\x20\x20\x22\x2c\ -\x0a\x22\x20\x20\x58\x40\x59\x40\x66\x2b\x66\x2b\x5a\x40\x60\x40\ -\x76\x40\x20\x23\x2e\x23\x5d\x2e\x2b\x23\x40\x23\x4d\x20\x23\x23\ -\x24\x23\x25\x23\x26\x23\x4d\x20\x2a\x23\x3d\x23\x2d\x23\x3b\x23\ -\x3e\x23\x7d\x20\x2c\x23\x47\x20\x27\x23\x29\x23\x21\x23\x7e\x23\ -\x7b\x23\x54\x20\x5d\x23\x5e\x23\x2f\x23\x28\x23\x5f\x23\x6f\x2e\ -\x68\x20\x68\x2e\x3a\x23\x3c\x23\x5b\x23\x7d\x23\x7c\x23\x31\x23\ -\x20\x20\x22\x2c\x0a\x22\x20\x20\x32\x23\x66\x2b\x29\x2b\x66\x2b\ -\x33\x23\x34\x23\x76\x40\x35\x23\x36\x23\x5d\x2e\x29\x2e\x37\x23\ -\x38\x23\x4d\x20\x39\x23\x7d\x2e\x30\x23\x33\x2e\x61\x23\x62\x23\ -\x63\x23\x58\x40\x4d\x20\x64\x23\x65\x23\x72\x2e\x23\x40\x66\x23\ -\x67\x23\x68\x23\x69\x23\x6a\x23\x6b\x23\x6c\x23\x6a\x20\x58\x20\ -\x65\x2e\x20\x2e\x67\x20\x65\x20\x6d\x23\x6e\x23\x6f\x23\x70\x23\ -\x71\x23\x72\x23\x20\x20\x22\x2c\x0a\x22\x20\x20\x73\x23\x7e\x20\ -\x66\x2b\x74\x23\x75\x23\x76\x23\x76\x40\x77\x23\x78\x23\x71\x2e\ -\x65\x20\x79\x23\x7a\x23\x4d\x20\x41\x23\x42\x23\x43\x23\x44\x23\ -\x45\x23\x46\x23\x47\x23\x48\x23\x49\x23\x4a\x23\x4b\x23\x21\x20\ -\x4c\x23\x4d\x23\x4e\x23\x33\x2e\x4d\x20\x4f\x23\x47\x23\x50\x23\ -\x51\x23\x6f\x2e\x52\x23\x7e\x2e\x76\x2b\x29\x2e\x53\x23\x54\x23\ -\x55\x23\x56\x23\x57\x23\x58\x23\x20\x20\x22\x2c\x0a\x22\x20\x20\ -\x59\x23\x5e\x20\x5d\x20\x72\x2e\x5a\x23\x60\x23\x76\x40\x20\x24\ -\x2e\x24\x65\x20\x67\x20\x2b\x24\x40\x24\x4d\x20\x23\x24\x24\x24\ -\x25\x24\x39\x40\x26\x24\x2a\x24\x3d\x24\x2d\x24\x3b\x24\x3e\x24\ -\x2c\x24\x27\x24\x29\x24\x21\x24\x7e\x24\x61\x23\x4d\x20\x4d\x20\ -\x4d\x20\x4d\x20\x7b\x24\x5d\x24\x32\x40\x5f\x40\x5e\x24\x29\x2e\ -\x2f\x24\x28\x24\x5f\x24\x3a\x24\x3c\x24\x5b\x24\x20\x20\x22\x2c\ -\x0a\x22\x20\x20\x7d\x24\x7c\x24\x77\x20\x62\x2b\x31\x24\x34\x23\ -\x76\x40\x32\x24\x33\x24\x66\x20\x43\x20\x34\x24\x35\x24\x4d\x20\ -\x36\x24\x37\x24\x38\x24\x4d\x20\x39\x24\x30\x24\x61\x24\x62\x24\ -\x63\x24\x64\x24\x65\x24\x66\x24\x67\x24\x68\x24\x69\x24\x3d\x40\ -\x6a\x24\x6b\x24\x6c\x24\x4d\x20\x4d\x20\x6d\x24\x6e\x24\x62\x2b\ -\x6f\x24\x29\x2e\x70\x24\x71\x24\x72\x24\x73\x24\x74\x24\x75\x24\ -\x20\x20\x22\x2c\x0a\x22\x20\x20\x76\x24\x52\x20\x77\x24\x2f\x2e\ -\x28\x23\x60\x23\x76\x40\x32\x24\x78\x24\x71\x2e\x66\x20\x79\x24\ -\x4d\x20\x4d\x20\x7a\x24\x65\x20\x41\x24\x42\x24\x4d\x20\x33\x2e\ -\x69\x40\x43\x24\x44\x24\x45\x24\x46\x24\x47\x24\x48\x24\x49\x24\ -\x4a\x24\x2a\x40\x5e\x2e\x4b\x24\x4c\x24\x4d\x24\x4d\x20\x4e\x24\ -\x4f\x24\x63\x2e\x50\x24\x42\x2e\x51\x24\x52\x24\x53\x24\x54\x24\ -\x55\x24\x56\x24\x20\x20\x22\x2c\x0a\x22\x20\x20\x57\x24\x58\x24\ -\x3e\x24\x59\x24\x3a\x40\x5a\x24\x76\x40\x32\x24\x60\x24\x20\x25\ -\x2e\x25\x2b\x25\x4d\x20\x40\x25\x23\x25\x68\x20\x24\x25\x25\x25\ -\x26\x25\x2a\x25\x3d\x25\x2d\x25\x3b\x25\x3e\x25\x2c\x25\x27\x25\ -\x29\x25\x21\x25\x7e\x25\x7b\x25\x5d\x25\x24\x24\x5e\x25\x2f\x25\ -\x4d\x20\x28\x25\x6e\x24\x20\x2e\x79\x20\x29\x2e\x5f\x25\x3a\x25\ -\x3c\x25\x5b\x25\x7d\x25\x7c\x25\x20\x20\x22\x2c\x0a\x22\x20\x20\ -\x31\x25\x32\x25\x33\x25\x34\x25\x35\x25\x60\x23\x76\x40\x33\x2e\ -\x36\x25\x37\x25\x48\x23\x4d\x20\x38\x25\x39\x25\x29\x2e\x30\x25\ -\x61\x25\x62\x25\x63\x25\x64\x25\x65\x25\x66\x25\x67\x25\x68\x25\ -\x69\x25\x6a\x25\x6b\x25\x77\x40\x4d\x20\x52\x24\x6c\x25\x26\x24\ -\x6d\x25\x4d\x20\x52\x24\x6e\x25\x6f\x25\x31\x40\x5d\x2e\x29\x2e\ -\x70\x25\x71\x25\x72\x25\x53\x40\x73\x25\x74\x25\x20\x20\x22\x2c\ -\x0a\x22\x20\x20\x75\x25\x76\x25\x76\x2b\x77\x25\x78\x25\x26\x25\ -\x79\x25\x61\x23\x23\x23\x7d\x40\x7a\x25\x41\x25\x42\x25\x5d\x2e\ -\x69\x20\x2b\x23\x43\x25\x7d\x20\x44\x25\x45\x25\x46\x25\x47\x25\ -\x48\x25\x49\x25\x4a\x25\x4b\x25\x67\x20\x4c\x25\x4d\x25\x3a\x25\ -\x7d\x20\x4d\x20\x4e\x25\x4f\x25\x50\x25\x61\x2b\x39\x20\x68\x20\ -\x67\x20\x50\x24\x51\x25\x52\x25\x53\x25\x5f\x24\x54\x25\x55\x25\ -\x20\x20\x22\x2c\x0a\x22\x20\x20\x20\x20\x56\x25\x57\x25\x58\x25\ -\x64\x20\x59\x25\x5a\x25\x60\x25\x20\x26\x2e\x26\x2b\x26\x40\x26\ -\x65\x20\x66\x20\x56\x20\x68\x2e\x23\x26\x24\x26\x20\x24\x25\x26\ -\x26\x26\x2a\x26\x3d\x26\x2d\x26\x3b\x26\x31\x40\x45\x20\x69\x20\ -\x3e\x26\x2c\x26\x27\x26\x29\x26\x21\x26\x7e\x26\x20\x2e\x42\x20\ -\x23\x2b\x65\x20\x66\x20\x7b\x26\x5d\x26\x5e\x26\x2f\x26\x28\x26\ -\x5f\x26\x20\x20\x20\x20\x22\x2c\x0a\x22\x20\x20\x20\x20\x3a\x26\ -\x2f\x2b\x54\x20\x52\x20\x3c\x26\x24\x24\x65\x20\x66\x20\x68\x20\ -\x5b\x26\x29\x2e\x5d\x2e\x62\x2e\x63\x2e\x64\x2b\x7d\x26\x61\x2b\ -\x7c\x26\x31\x26\x32\x26\x33\x26\x34\x26\x58\x20\x21\x2e\x75\x2b\ -\x2b\x2e\x5b\x2b\x3c\x2b\x35\x26\x36\x26\x21\x20\x5f\x40\x62\x2e\ -\x66\x20\x67\x20\x29\x2e\x68\x2e\x42\x2e\x51\x23\x44\x24\x7d\x20\ -\x2d\x2e\x37\x26\x38\x26\x20\x20\x20\x20\x22\x2c\x0a\x22\x20\x20\ -\x20\x20\x39\x26\x30\x26\x63\x20\x7a\x20\x4e\x2e\x7c\x2e\x5d\x2e\ -\x67\x20\x43\x20\x70\x2e\x29\x2e\x68\x2e\x61\x26\x6f\x2e\x77\x20\ -\x33\x25\x62\x26\x63\x26\x64\x26\x65\x26\x59\x24\x7e\x20\x62\x20\ -\x7c\x24\x7b\x2e\x30\x2b\x78\x2b\x68\x2e\x43\x20\x39\x2e\x7e\x20\ -\x27\x2e\x65\x20\x65\x20\x67\x20\x68\x20\x5d\x2e\x64\x20\x66\x26\ -\x67\x26\x68\x26\x4d\x20\x4d\x20\x20\x20\x20\x20\x20\x20\x22\x2c\ -\x0a\x22\x20\x20\x20\x20\x20\x20\x69\x26\x42\x2e\x66\x20\x5d\x2e\ -\x29\x2e\x70\x2e\x66\x20\x71\x2e\x67\x20\x65\x20\x60\x20\x6f\x24\ -\x59\x24\x59\x24\x6a\x26\x6b\x26\x64\x26\x6c\x26\x78\x2b\x27\x2e\ -\x60\x20\x41\x2e\x62\x20\x6d\x26\x64\x2b\x54\x20\x63\x20\x65\x20\ -\x29\x2e\x4a\x2b\x65\x20\x68\x20\x45\x20\x29\x2e\x45\x20\x42\x2e\ -\x6e\x26\x6d\x25\x6f\x26\x70\x26\x71\x26\x4d\x20\x20\x20\x20\x20\ -\x20\x20\x22\x2c\x0a\x22\x20\x20\x20\x20\x20\x20\x72\x26\x73\x26\ -\x71\x2e\x65\x20\x64\x20\x71\x2e\x65\x20\x66\x20\x42\x2e\x65\x20\ -\x74\x26\x75\x26\x76\x26\x77\x26\x78\x26\x79\x26\x7a\x26\x7e\x2e\ -\x72\x2e\x41\x26\x54\x20\x5d\x2b\x5e\x24\x52\x20\x2f\x2e\x5d\x20\ -\x42\x26\x66\x20\x42\x2e\x65\x20\x65\x20\x23\x2b\x65\x20\x42\x2e\ -\x5d\x2e\x66\x20\x43\x26\x33\x2e\x44\x26\x45\x26\x46\x26\x20\x20\ -\x20\x20\x20\x20\x20\x20\x22\x2c\x0a\x22\x20\x20\x20\x20\x20\x20\ -\x3a\x25\x47\x26\x29\x2e\x42\x2e\x65\x20\x67\x20\x68\x20\x48\x26\ -\x49\x26\x4a\x26\x4b\x26\x4c\x26\x4d\x26\x4e\x26\x4f\x26\x50\x26\ -\x7e\x20\x62\x2b\x74\x23\x74\x23\x72\x2e\x62\x2b\x59\x20\x76\x2b\ -\x51\x26\x3e\x24\x46\x20\x63\x2b\x65\x20\x65\x20\x68\x20\x68\x20\ -\x65\x20\x42\x2e\x66\x20\x52\x26\x36\x40\x53\x26\x54\x26\x55\x26\ -\x56\x26\x20\x20\x20\x20\x20\x20\x20\x20\x22\x2c\x0a\x22\x20\x20\ -\x20\x20\x20\x20\x4d\x20\x57\x26\x58\x26\x5d\x2e\x68\x20\x59\x26\ -\x4f\x2e\x42\x2e\x5a\x26\x60\x26\x20\x2a\x2e\x2a\x2b\x2a\x40\x2a\ -\x23\x2a\x24\x2a\x41\x26\x41\x26\x72\x2e\x74\x23\x62\x2b\x25\x2a\ -\x2c\x24\x26\x2a\x34\x25\x54\x20\x78\x2b\x65\x20\x29\x2e\x65\x20\ -\x68\x20\x29\x2e\x65\x20\x42\x2e\x2a\x2a\x3d\x2a\x68\x40\x2d\x2a\ -\x3b\x2a\x4d\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22\x2c\ -\x0a\x22\x20\x20\x20\x20\x20\x20\x3e\x2a\x2c\x2a\x27\x2a\x29\x2a\ -\x65\x20\x21\x2a\x70\x2e\x23\x2b\x7e\x2a\x7b\x2a\x5d\x2a\x2e\x2a\ -\x5e\x2a\x2f\x2a\x5f\x23\x24\x2a\x41\x26\x74\x23\x72\x2e\x41\x26\ -\x28\x2a\x2f\x2e\x34\x25\x5f\x2a\x3a\x2a\x20\x2e\x2b\x2e\x23\x2b\ -\x65\x20\x65\x20\x68\x20\x3c\x2a\x66\x20\x53\x20\x5b\x2a\x33\x2e\ -\x7d\x2a\x7c\x2a\x31\x2a\x32\x2a\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x22\x2c\x0a\x22\x20\x20\x20\x20\x20\x20\x20\x20\x33\x2a\ -\x34\x2a\x35\x2a\x36\x2a\x29\x2e\x5d\x2e\x37\x2a\x38\x2a\x39\x2a\ -\x30\x2a\x4e\x26\x61\x2a\x62\x2a\x72\x2e\x3a\x2e\x3a\x2e\x72\x2e\ -\x63\x2a\x57\x20\x20\x2e\x64\x2a\x7b\x20\x51\x26\x43\x2b\x29\x2b\ -\x39\x20\x43\x20\x5d\x2e\x42\x2e\x66\x20\x5d\x2e\x29\x2e\x65\x2a\ -\x66\x2a\x4f\x2b\x67\x2a\x68\x2a\x69\x2a\x6a\x2a\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x22\x2c\x0a\x22\x20\x20\x20\x20\x20\x20\ -\x20\x20\x6b\x2a\x6c\x2a\x6d\x2a\x6e\x2a\x6f\x2a\x70\x2a\x71\x2a\ -\x72\x2a\x73\x2a\x74\x2a\x75\x2a\x76\x2a\x77\x2a\x59\x24\x21\x2e\ -\x63\x2a\x78\x2a\x2b\x2e\x42\x26\x2e\x2b\x6f\x2e\x3c\x26\x3a\x2e\ -\x75\x2b\x52\x20\x67\x20\x29\x2e\x65\x20\x65\x20\x65\x20\x53\x20\ -\x79\x2a\x43\x24\x33\x2e\x7a\x2a\x41\x2a\x42\x2a\x43\x2a\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22\x2c\x0a\x22\x20\x20\ -\x20\x20\x20\x20\x20\x20\x44\x2a\x45\x2a\x46\x2a\x38\x2b\x47\x2a\ -\x48\x2a\x49\x2a\x4a\x2a\x28\x2e\x3a\x2a\x4b\x2a\x4c\x2a\x2f\x2e\ -\x75\x2b\x62\x20\x60\x2e\x51\x26\x2e\x2b\x63\x20\x4d\x2a\x36\x26\ -\x5f\x40\x77\x20\x4e\x2e\x42\x2e\x7c\x2e\x68\x20\x65\x20\x66\x20\ -\x6d\x2b\x4e\x2a\x33\x2e\x4f\x2a\x50\x2a\x51\x2a\x52\x2a\x53\x2a\ -\x54\x2a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22\x2c\ -\x0a\x22\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x55\x2a\x56\x2a\ -\x57\x2a\x58\x2a\x59\x2a\x5a\x2a\x68\x2e\x44\x20\x64\x2e\x36\x26\ -\x60\x2a\x52\x20\x28\x2e\x21\x2b\x39\x20\x21\x2b\x52\x20\x61\x2b\ -\x5f\x23\x72\x2e\x62\x2e\x29\x2e\x68\x20\x29\x2e\x67\x20\x42\x2e\ -\x71\x2e\x20\x3d\x28\x25\x7d\x20\x2e\x3d\x2b\x3d\x53\x25\x40\x3d\ -\x23\x3d\x24\x3d\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x22\x2c\x0a\x22\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x25\x3d\x26\x3d\x2a\x3d\x6d\x2a\x3d\x3d\x2d\x3d\x3b\x3d\ -\x50\x24\x64\x2b\x72\x2e\x74\x23\x66\x2b\x7e\x2e\x30\x2b\x5f\x40\ -\x59\x40\x4b\x23\x75\x2b\x62\x2e\x66\x20\x69\x20\x45\x20\x69\x20\ -\x70\x2e\x3e\x3d\x2c\x3d\x27\x3d\x29\x3d\x21\x3d\x3c\x23\x36\x2b\ -\x7e\x3d\x7b\x3d\x5d\x3d\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x22\x2c\x0a\x22\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x4d\x20\x7d\x20\x5e\x3d\x2f\x3d\ -\x28\x3d\x5f\x3d\x3a\x3d\x3c\x3d\x5b\x3d\x20\x2e\x47\x20\x7d\x3d\ -\x63\x2e\x6f\x25\x54\x20\x42\x26\x58\x25\x42\x2e\x66\x20\x68\x20\ -\x73\x26\x7c\x3d\x31\x3d\x32\x3d\x4c\x20\x33\x3d\x34\x3d\x35\x3d\ -\x36\x3d\x37\x3d\x38\x3d\x39\x3d\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22\x2c\x0a\x22\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x6f\x26\ -\x30\x3d\x61\x3d\x62\x3d\x63\x3d\x64\x3d\x65\x3d\x66\x3d\x6e\x2a\ -\x67\x3d\x68\x3d\x5f\x20\x69\x3d\x20\x40\x6a\x3d\x6b\x3d\x6c\x3d\ -\x6d\x3d\x6e\x3d\x6f\x3d\x70\x3d\x7d\x20\x71\x3d\x72\x3d\x73\x3d\ -\x74\x3d\x75\x3d\x76\x3d\x77\x3d\x7a\x2a\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22\x2c\ -\x0a\x22\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x78\x3d\x79\x3d\x7a\x3d\x41\x3d\x57\x2e\x42\x3d\ -\x43\x3d\x44\x3d\x45\x3d\x46\x3d\x47\x3d\x48\x3d\x49\x3d\x4a\x3d\ -\x4b\x3d\x4c\x3d\x4d\x3d\x55\x24\x4e\x3d\x33\x2e\x4f\x3d\x50\x3d\ -\x51\x3d\x52\x3d\x53\x3d\x2f\x26\x54\x3d\x55\x3d\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x22\x2c\x0a\x22\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x56\x3d\x4f\x3d\x57\x3d\ -\x58\x3d\x59\x3d\x5a\x3d\x60\x3d\x53\x24\x20\x2d\x2e\x2d\x2a\x3d\ -\x2b\x2d\x36\x2e\x40\x2d\x23\x2d\x24\x2d\x25\x2d\x26\x2d\x2a\x2d\ -\x3e\x2a\x6e\x40\x3d\x2d\x2d\x2d\x3b\x2d\x3e\x2d\x2c\x2d\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x22\x2c\x0a\x22\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x27\x2d\x29\x2d\x21\x2d\x7e\x2d\x7b\x2d\x5d\x2d\x5e\x2d\ -\x2f\x2d\x28\x2d\x5f\x2d\x3a\x2d\x3c\x2d\x5b\x2d\x56\x3d\x7d\x2d\ -\x7c\x2d\x4c\x20\x4d\x20\x31\x2d\x32\x2d\x33\x2d\x34\x2d\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22\x2c\x0a\x22\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x53\x25\x50\x2b\x35\x2d\ -\x36\x2d\x37\x2d\x38\x2d\x39\x2d\x30\x2d\x61\x2d\x62\x2d\x63\x2d\ -\x64\x2d\x2d\x2b\x65\x2d\x66\x2d\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x22\x2c\ -\x0a\x22\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x67\x2d\x53\x40\x68\x2d\x69\x2d\x6a\x2d\x6b\x2d\x6c\x2d\ -\x6d\x2d\x31\x2d\x6e\x2d\x26\x3d\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x22\x2c\x0a\x22\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x7c\x2d\x6f\x2d\ -\x70\x2d\x53\x2a\x71\x2d\x72\x2d\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\ -\x20\x20\x20\x20\x20\x20\x22\x7d\x3b\x0a\ -\x00\x00\x03\xcd\ -\x89\ -\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ -\x00\x00\x32\x00\x00\x00\x32\x08\x06\x00\x00\x00\x1e\x3f\x88\xb1\ -\x00\x00\x03\x94\x49\x44\x41\x54\x68\x43\xed\x99\xfd\x95\x0d\x41\ -\x10\xc5\xef\x46\x80\x08\x10\x01\x22\x40\x04\x88\x00\x11\x20\x02\ -\x44\x80\x08\xec\x46\x80\x08\x10\x01\x22\x60\x23\xb0\x22\xe0\xfc\ -\xe8\x72\x6a\xe7\xcd\x74\x57\xf5\xf4\xec\x1f\xef\xbc\x3e\x67\xcf\ -\xdb\xdd\x57\x5d\x5d\xb7\x3e\x6f\xcf\x1c\x69\x4f\xd6\xd1\x9e\xe0\ -\xd0\x01\x48\x22\x92\x5f\x24\x9d\x49\xba\x9b\xd8\x93\x16\xdd\x3a\ -\x22\x77\x24\x7d\x2c\x56\x6d\x7a\xd6\xa6\xca\x25\x1d\x4b\x7a\x28\ -\xe9\x99\xa4\xd7\x69\x37\x27\x36\x6c\x09\xe4\xb2\xa4\xef\x92\xf8\ -\xbc\x52\xd2\x8b\x34\x63\x91\x66\xa4\xdb\xb0\xb5\x25\x90\x47\x92\ -\xde\x4e\xd2\xea\x77\xf9\xfb\x87\xa4\x07\x92\xbe\x8e\x42\xb2\x25\ -\x10\xa2\x71\xad\x18\x7a\xab\x18\xfd\x49\xd2\xed\xf2\x3f\x6b\x00\ -\x43\xc0\x6c\x05\xc4\x47\x03\xbb\xf1\xfe\x7b\x57\x33\x16\x88\x61\ -\x60\xb6\x02\xe2\xa3\x81\xd1\x2f\x25\xbd\x28\x3f\xcf\x27\xe9\x04\ -\x18\x22\x46\xba\x75\xaf\x2d\x80\x4c\xa3\x81\x71\x6f\x24\x3d\x95\ -\x34\xf7\x1d\xdf\x93\x5e\xab\x1a\xc0\x68\x20\x74\x28\x3a\x93\xd5\ -\x86\x79\xf8\xb3\x24\x66\x8a\x9f\x2b\x53\xef\x53\x3f\xdd\x43\x73\ -\x34\x10\xd2\x67\x9a\x3a\x18\x1c\x01\xe2\x23\x97\x4e\xb1\x91\x40\ -\x6e\x96\x68\xcc\x19\x41\xea\x50\x07\x44\x8a\xfa\xa9\x2d\x6b\x0c\ -\x29\x30\x23\x81\x90\x52\x80\x59\x5a\x76\x96\xcd\x92\x25\xb9\xae\ -\xe2\x1f\x05\x04\xfa\xf1\xa4\xe1\xc2\x28\x10\xd4\xa4\xeb\x65\x04\ -\x90\xfb\x92\xde\x35\x40\xfc\x2a\x54\x05\xb1\x56\x44\x4c\x55\x2a\ -\xc5\xd6\x02\x21\x95\x60\xb7\x74\xab\xda\x8a\x16\xbb\xd7\x41\x8a\ -\x5d\x8f\x72\xb2\x35\x40\x30\x1e\x10\xb5\xba\xc8\xb4\xdf\x39\x47\ -\xd8\x20\x6d\x16\x7e\x2f\x90\x0c\x88\x4c\xfb\x9d\x1a\x1c\x8e\x4a\ -\x0f\x10\x40\x50\x13\x0c\xb7\xe8\x32\xcf\x32\xdd\x5f\x45\x37\x15\ -\xb9\x50\x54\xb2\x40\xb2\x91\x30\x9b\xed\x62\xb5\x34\x30\x6b\xd8\ -\xe0\x60\xd4\x4a\x75\x65\x80\xf4\x82\xc0\x00\xa8\x07\x2d\xd5\xd3\ -\xf8\x96\x6d\xfe\xfb\x66\x07\x8b\x02\x61\x22\x93\x4e\x91\xc2\x9e\ -\x1a\xe8\x5b\xef\xcf\x40\x87\x9b\x03\xf8\x41\x12\x6d\x7e\x71\x45\ -\x80\x50\x0b\x80\x68\xb5\xd8\xa5\x43\xcc\x88\x1a\x85\x89\x44\xa7\ -\x6a\x6b\x0b\x08\x04\x90\xbc\x5e\xb3\x1e\x97\x0b\x55\x64\xfa\xd7\ -\xce\xb1\xf4\x9c\x95\xa9\x01\x69\x71\xa7\x08\xb8\x53\x47\xe9\xa7\ -\x97\xad\xc8\x7e\x2f\x53\xed\x5e\x35\x20\x30\xd6\x1b\xd9\xd3\x26\ -\xf2\x16\x8d\xa5\x0b\x55\x46\xbd\xb1\x83\x74\x44\xd8\x40\x5e\x63\ -\x04\x85\x76\x35\x73\x6a\x91\x35\x47\xad\x8d\x06\xea\xaa\x6d\xb8\ -\x55\x23\xde\xf6\x1e\x50\xf6\x3c\x6b\x44\x74\xb1\x65\xd1\xde\x0c\ -\x90\x1e\x50\xfe\x09\x23\x8e\xb0\xeb\x2e\x9f\x97\x56\x44\x78\x67\ -\x6b\x2f\x90\x0e\x1b\xb6\xdd\xb2\xd7\x40\x08\x3b\xc4\xae\x67\x8a\ -\x6f\xeb\xf6\xf3\xda\x99\x4b\xa4\xee\xdf\x35\x17\x91\x5e\x1a\x71\ -\x91\x20\x76\xec\x9f\x03\xc2\x1d\xa0\xa7\x10\x2f\x1a\xc8\xb9\xb9\ -\x32\x07\x84\x67\xb4\xf7\x2e\xda\xaa\xe4\x79\xdf\x4a\x07\xfc\xff\ -\x6a\x62\x0e\xc8\x5a\x72\x97\xb4\x29\x2d\xbe\x03\xa2\x36\x60\x46\ -\x50\x8a\xb4\x85\x81\x0d\x30\x69\x6c\xdb\x79\x49\x54\x6b\xbf\xd0\ -\x12\xa8\x3b\xd4\x80\x4e\xc6\x35\x75\xa9\x76\x20\x87\xb0\xe4\x88\ -\x2c\xf7\x13\x3a\x0e\x97\x2c\xee\x39\xec\x5b\xa2\x3f\x5e\x16\x5b\ -\x48\xfb\x2e\xae\xe5\x37\xa1\x08\x30\x80\xe2\x65\x0d\x87\x40\x3d\ -\xec\xbd\x87\xf7\x12\xb2\xc6\xd1\xac\x8d\x47\x65\x71\x16\x85\x0c\ -\x50\x00\x87\x5e\xd1\xb5\x06\x22\x2f\x32\x31\x08\x0a\x8d\xe2\xda\ -\xca\xc8\x12\x6d\x9e\x4c\xf2\xb2\xf4\xa4\xa1\x17\xc7\x71\x2f\xaa\ -\xca\x02\x04\xef\x11\x62\x3c\xc6\xef\x50\x77\xbc\x88\xf7\xfd\xeb\ -\x01\x80\xa0\x8c\xf4\xc1\x63\x5e\x16\xb0\x7e\x80\xa2\x0b\x59\x3e\ -\x91\x65\x11\x45\x23\x9e\x4b\xb2\x14\x32\x11\x40\x96\xb3\xd1\xeb\ -\x9f\xd6\x78\xbd\x5e\xf6\x14\x20\x35\x8a\x4d\xee\x93\x3a\x28\x6c\ -\xcd\x96\x8c\x2c\x69\x09\xd0\xc8\xf5\x20\x22\x7b\x06\x10\xf2\x10\ -\xd4\x44\xc2\xf2\x1e\xaf\x03\xc0\x8a\x0b\xef\x73\x28\x72\x78\xca\ -\x5e\x68\xe2\xed\xac\x2c\x91\x45\xaf\xe5\x3e\x7a\xf9\x99\xd3\x5b\ -\x93\x25\xaa\x56\x4f\xc7\x87\x1a\x39\xd4\xc8\xbf\xc2\x8f\xe4\xbd\ -\x35\xb3\x88\xec\xfe\xd4\xc8\x1f\x77\x50\x0b\x20\xa9\x40\x9b\x34\ -\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\ -\x00\x00\x01\x5a\ -\x89\ -\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ -\x00\x00\x0c\x00\x00\x00\x08\x08\x06\x00\x00\x00\xcd\xe4\x1e\xf1\ -\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\ -\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x01\x23\x00\x00\x01\x23\ -\x01\x72\x41\x77\xde\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\ -\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\ -\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x00\xd7\x49\x44\ -\x41\x54\x18\x19\x05\xc1\x31\x4a\x5c\x51\x18\x06\xd0\xf3\xdf\x20\ -\x51\x82\xae\x21\x6b\x48\x61\x65\xe1\x7e\xb2\x05\x1b\xfb\xa0\x90\ -\x4a\x49\xf6\x21\x44\x70\x1a\x85\xe8\x16\x04\x35\xf6\x83\x13\x67\ -\xf0\x3d\xef\x23\xef\xcb\x39\xb5\xbf\xb7\x73\x2e\xf9\x12\x95\x22\ -\x88\x9a\x93\xd9\x5c\x55\x41\x90\x22\xe2\xa2\x0e\xd9\x7e\xdb\xfd\ -\xf8\x93\xfa\x8c\x20\x45\xc2\x8c\x20\x45\x66\xfe\x7c\x5a\x8f\x5f\ -\xdb\x22\x19\xb5\x3a\xc2\x1a\xbd\xe8\xa1\x63\x42\x0f\x53\xd8\x6c\ -\x7d\x70\xbc\x48\xc6\x06\xb7\xab\xe1\x29\x95\x93\x30\x85\x09\x93\ -\x32\x25\xa6\x8a\x5e\x2d\xdf\x6f\x5e\x86\x67\x68\x00\x77\x7f\xc7\ -\xcb\xa6\x2e\x44\x47\xaf\xe8\x55\xd5\xab\xd5\xaf\xdf\xab\xf1\x0a\ -\xa0\x01\xc0\x72\x3d\x9c\xa5\xd5\x43\x54\x8f\xea\xe2\x71\xf9\x3a\ -\xfc\x00\x80\x06\x00\xf7\xc9\x7b\x9b\x7c\xab\x64\x53\xb2\xa9\x7f\ -\x4e\xef\x93\x77\x00\xa8\x24\x00\x00\xf6\x77\x77\x0e\xe0\x6e\x3d\ -\x5c\x03\x00\xfc\x07\x0d\x05\x7c\xd8\x7c\x63\x5f\x7c\x00\x00\x00\ -\x00\x49\x45\x4e\x44\xae\x42\x60\x82\ -" - -qt_resource_name = b"\ -\x00\x06\ -\x07\x03\x7d\xc3\ -\x00\x69\ -\x00\x6d\x00\x61\x00\x67\x00\x65\x00\x73\ -\x00\x06\ -\x06\x8a\x9c\xb3\ -\x00\x61\ -\x00\x73\x00\x73\x00\x65\x00\x74\x00\x73\ -\x00\x0f\ -\x0a\x1f\xa8\x07\ -\x00\x66\ -\x00\x6c\x00\x69\x00\x67\x00\x68\x00\x74\x00\x5f\x00\x69\x00\x63\x00\x6f\x00\x6e\x00\x2e\x00\x70\x00\x6e\x00\x67\ -\x00\x0e\ -\x03\x1e\x07\xc7\ -\x00\x67\ -\x00\x65\x00\x6f\x00\x69\x00\x64\x00\x5f\x00\x69\x00\x63\x00\x6f\x00\x6e\x00\x2e\x00\x70\x00\x6e\x00\x67\ -\x00\x11\ -\x0b\x76\x30\xa7\ -\x00\x62\ -\x00\x72\x00\x61\x00\x6e\x00\x63\x00\x68\x00\x2d\x00\x63\x00\x6c\x00\x6f\x00\x73\x00\x65\x00\x64\x00\x2e\x00\x70\x00\x6e\x00\x67\ -\ -\x00\x0c\ -\x07\x3c\x74\x8d\ -\x00\x64\ -\x00\x67\x00\x73\x00\x5f\x00\x69\x00\x63\x00\x6f\x00\x6e\x00\x2e\x00\x78\x00\x70\x00\x6d\ -\x00\x0d\ -\x0d\x10\x1d\x07\ -\x00\x62\ -\x00\x6f\x00\x61\x00\x74\x00\x5f\x00\x69\x00\x63\x00\x6f\x00\x6e\x00\x2e\x00\x70\x00\x6e\x00\x67\ -\x00\x0f\ -\x06\x53\x91\xa7\ -\x00\x62\ -\x00\x72\x00\x61\x00\x6e\x00\x63\x00\x68\x00\x2d\x00\x6f\x00\x70\x00\x65\x00\x6e\x00\x2e\x00\x70\x00\x6e\x00\x67\ -" - -qt_resource_struct_v1 = b"\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ -\x00\x00\x00\x12\x00\x02\x00\x00\x00\x06\x00\x00\x00\x03\ -\x00\x00\x00\x48\x00\x00\x00\x00\x00\x01\x00\x00\x01\xe2\ -\x00\x00\x00\xd0\x00\x00\x00\x00\x00\x01\x00\x02\x4e\x37\ -\x00\x00\x00\x92\x00\x00\x00\x00\x00\x01\x00\x01\xfa\x37\ -\x00\x00\x00\x24\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x00\x6a\x00\x00\x00\x00\x00\x01\x00\x01\xf8\xe5\ -\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x01\x00\x02\x4a\x66\ -" - -qt_resource_struct_v2 = b"\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ -\x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x02\ -\x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x12\x00\x02\x00\x00\x00\x06\x00\x00\x00\x03\ -\x00\x00\x00\x00\x00\x00\x00\x00\ -\x00\x00\x00\x48\x00\x00\x00\x00\x00\x01\x00\x00\x01\xe2\ -\x00\x00\x01\x5e\x3f\x2e\x79\xa0\ -\x00\x00\x00\xd0\x00\x00\x00\x00\x00\x01\x00\x02\x4e\x37\ -\x00\x00\x01\x5e\x4f\x8e\x65\xbf\ -\x00\x00\x00\x92\x00\x00\x00\x00\x00\x01\x00\x01\xfa\x37\ -\x00\x00\x01\x5e\x34\xe1\x4c\x70\ -\x00\x00\x00\x24\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x01\x5e\x3f\x18\x3e\x38\ -\x00\x00\x00\x6a\x00\x00\x00\x00\x00\x01\x00\x01\xf8\xe5\ -\x00\x00\x01\x5e\x4f\x8e\x4c\xff\ -\x00\x00\x00\xb0\x00\x00\x00\x00\x00\x01\x00\x02\x4a\x66\ -\x00\x00\x01\x5e\x3f\x23\x04\x08\ -" - -qt_version = QtCore.qVersion().split('.') -if qt_version < ['5', '8', '0']: - rcc_version = 1 - qt_resource_struct = qt_resource_struct_v1 -else: - rcc_version = 2 - qt_resource_struct = qt_resource_struct_v2 - -def qInitResources(): - QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data) - -def qCleanupResources(): - QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data) - -qInitResources() diff --git a/docs/README.rst b/docs/README.rst new file mode 100644 index 0000000..d43dcce --- /dev/null +++ b/docs/README.rst @@ -0,0 +1,4 @@ +DGP Documentation README +~~~~~~~~~~~~~~~~~~~~~~~~ + + diff --git a/docs/project.py UML Diagram.vsdx b/docs/project.py UML Diagram.vsdx new file mode 100644 index 0000000..a9b8140 Binary files /dev/null and b/docs/project.py UML Diagram.vsdx differ diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..798c2f2 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,12 @@ +# Documentation Requirements +Sphinx==1.7.5 +sphinx_rtd_theme==0.4.0 + +# Project Requirements +matplotlib>=2.0.2 +numpy>=1.13.1 +pandas==0.23.3 +PyQt5==5.11.2 +pyqtgraph==0.10.0 +tables==3.4.4 +scipy==1.1.0 diff --git a/docs/source/conf.py b/docs/source/conf.py index 13af83d..03c3e29 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -19,10 +19,10 @@ # import os import sys + sys.path.insert(0, os.path.abspath('.')) sys.path.insert(0, os.path.abspath('../..')) - # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. @@ -33,16 +33,41 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = ['sphinx.ext.autodoc', - 'sphinx.ext.doctest', - 'sphinx.ext.todo', - 'sphinx.ext.mathjax', - 'sphinx.ext.viewcode', - 'sphinx.ext.napoleon'] + 'sphinx.ext.coverage', + 'sphinx.ext.doctest', + 'sphinx.ext.extlinks', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'sphinx.ext.mathjax', + 'sphinx.ext.viewcode', + 'sphinx.ext.napoleon'] napoleon_google_docstring = False +napoleon_numpy_docstring = True +napoleon_include_private_with_doc = True napoleon_use_param = False napoleon_use_ivar = True +# Link shortcuts - see: http://www.sphinx-doc.org/en/stable/ext/extlinks.html +extlinks = {} + +# Intersphinx Mapping to link to external sphinx documentation +intersphinx_mapping = { + 'python': ('https://docs.python.org/3.6', None), + 'numpy': ('https://docs.scipy.org/doc/numpy-1.13.0/', None), + 'pyqtgraph': ('http://pyqtgraph.org/documentation', None), + 'pytables': ('https://www.pytables.org', None), + 'pyqt': ('http://pyqt.sourceforge.net/Docs/PyQt5', None), + 'pandas': ('https://pandas.pydata.org/pandas-docs/stable/', None) +} +# Note: the pyqt interlink won't work correctly as the namespaces are all +# under :sip: in the objects.inv from the documentation site. +# See: https://github.com/MSLNZ/msl-qt/blob/master/docs/create_pyqt_objects.py +# for a possible solution + +# Set whether module paths are prepended to class objects in doc. +add_module_names = False + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -57,8 +82,8 @@ # General information about the project. project = 'Dynamic Gravity Processor' -copyright = '2017, Zachery Brady, Daniel Aliod, Nigel Brady, Chris Bertinato' -author = 'Zachery Brady, Daniel Aliod, Nigel Brady, Chris Bertinato' +author = 'Zachery Brady, Daniel Aliod, Chris Bertinato' +copyright = '2017, 2018, ' + author # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -67,7 +92,7 @@ # The short X.Y version. version = '0.1' # The full version, including alpha/beta/rc tags. -release = '0.1' +release = '0.1a' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -87,7 +112,6 @@ # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = True - # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for @@ -99,7 +123,9 @@ # further. For a list of options available for each theme, see the # documentation. # -# html_theme_options = {} +html_theme_options = { + 'navigation_depth': 4 +} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -121,13 +147,15 @@ ] } +html_logo = "" + +html_show_sourcelink = True # -- Options for HTMLHelp output ------------------------------------------ # Output file base name for HTML help builder. htmlhelp_basename = 'DynamicGravityProcessordoc' - # -- Options for LaTeX output --------------------------------------------- latex_elements = { @@ -153,10 +181,9 @@ # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'DynamicGravityProcessor.tex', 'Dynamic Gravity Processor Documentation', - 'Zachery Brady, Daniel Aliod, Nigel Brady, Chris Bertinato', 'manual'), + 'Daniel Aliod, Chris Bertinato, Zachery Brady', 'manual'), ] - # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples @@ -166,7 +193,6 @@ [author], 1) ] - # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples @@ -177,3 +203,15 @@ author, 'DynamicGravityProcessor', 'One line description of project.', 'Miscellaneous'), ] + +# -- Options for Autodoc plugin ------------------------------------------- + +# Set sort type for auto documented members, select from 'alphabetical', +# 'groupwise', or 'bysource' +autodoc_member_order = 'bysource' + +# Autodoc directives automatically applied +autodoc_default_flags = ['members'] + +# -- Options for Doc Coverage extension ----------------------------------- +coverage_skip_undoc_in_source = False diff --git a/docs/source/contributing.rst b/docs/source/contributing.rst new file mode 100644 index 0000000..033c490 --- /dev/null +++ b/docs/source/contributing.rst @@ -0,0 +1,218 @@ +############ +Contributing +############ + +Creating a branch +----------------- +This project uses the GitFlow_ branching model. The ``master`` branch reflects the current +production-ready state. The ``develop`` branch is a perpetual development branch. + +.. _GitFlow: http://nvie.com/posts/a-successful-git-branching-model/ + +New development is done in feature branches which are merged back +into the ``develop`` branch once development is completed. Prior to a release, +a release branch is created off of ``develop``. When the +release is ready, the release branch is merged into ``master`` and ``develop``. + +Development branches are named with a prefix according to their purpose: + +- ``feature/``: An added feature or improved functionality. +- ``bug/``: Bug fix. +- ``doc/``: Addition or cleaning of documentation. +- ``clean/``: Code clean-up. + +When starting a new branch, be sure to branch from develop:: + + $ git checkout -b my_feature develop + +Keep any changes in this branch specific to one bug or feature. If the develop +branch has advanced since your branch was first created, then you can update +your branch by retrieving those changes from the develop branch:: + + $ git fetch origin + $ git rebase origin/develop + +This will replay your commits on top of the latest version of the develop branch. +If there are merge conflicts, then you must resolve them. + +Committing your code +-------------------- +When committing to your changes, we recommend structuring the commit message +in the following way: + +- subject line with less than < 80 chars +- one blank line +- optionally, a commit message body + +Please reference the relevant GitHub issues in your commit message using +GH1234 or #1234. + +For the subject line, this project uses the same convention for commit message +prefix and layout as the Pandas project. Here are some common prefixes and +guidelines for when to use them: + +- ENH: Enhancement, new functionality +- BUG: Bug fix +- DOC: Additions/updates to documentation +- TST: Additions/updates to tests +- BLD: Updates to the build process/scripts +- PERF: Performance improvement +- CLN: Code cleanup + +Combining commits ++++++++++++++++++ +When you're ready to make a pull request and if you have made multiple commits, +then you may want to combine, or "squash", those commits. Squashing commits +helps to maintain a compact commit history, especially if a number of commits +were made to fix errors or bugs along the way. To squash your commits:: + + git rebase -i HEAD-# + +where # is the number of commits you want to combine. If you want to squash +all commits on the branch:: + + git rebase -i --root + +Then you will need to push the branch forcefully to replace the current commits +with the new ones:: + + git push origin new-feature -f + +Incorporating a finished feature on develop ++++++++++++++++++++++++++++++++++++++++++++ +Finished features should be added to the develop branch to be included in the +next release:: + + $ git checkout develop + Switched to branch 'develop' + $ git merge --no-ff myfeature + Updating ea1b82a..05e9557 + (summary of changes) + $ git branch -d myfeature + Deleted branch myfeature (was 05e9557). + $ git push origin develop + +The ``--no-ff`` flag causes the merge to always create a commit, even if it can +be done with a fast-forward. This way we record the existence of the feature +branch even after it has been deleted, and it groups all of the relevant +commits for this feature. + +Note that pull-requests into develop require passing Continuous Integration +(CI) builds on Travis.ci and AppVeyor, and at least one approved review. + +Code standards +-------------- +*DGP* uses the PEP8_ standard. In particular, that means: + +- we restrict line-length to 79 characters to promote readability +- passing arguments should have spaces after commas, *e.g.*, + ``foo(arg1, arg2, kw1='bar')`` + +Continuous integration will run the flake8 tool to check for conformance with +PEP8. Therefore, it is beneficial to run the check yourself before submitting +a pull request:: + + git diff master --name-only -- '*.py' | flake8 --diff + +.. _PEP8: http://www.python.org/dev/peps/pep-0008/ + +Test-driven development +----------------------- +All new features and added functionality will require new tests or amendments +to existing tests, so we highly recommend that all contributors embrace +`test-driven development (TDD)`_. + +.. _`test-driven development (TDD)`: http://en.wikipedia.org/wiki/Test-driven_development + +All tests should go to the ``tests`` subdirectory. We suggest looking to any of +the examples in that directory to get ideas on how to write tests for the +code that you are adding or modifying. + +*DGP* uses the pytest_ framework for unit testing and coverage.py_ to gauge the +effectiveness of tests by showing which parts of the code are being executed +by tests, and which are not. The pytest-cov_ extension is used in conjunction +with Py.Test and coverage.py to generate coverage reports after executing the +test suite. + +Continuous integration will also run the test-suite with coverage, and report +the coverage statistics to `Coveralls `__ + +.. _pytest: https://docs.pytest.org/ +.. _pytest-cov: https://pytest-cov.readthedocs.io/ +.. _unittest: https://docs.python.org/3/library/unittest.html +.. _coverage.py: https://coverage.readthedocs.io/en/coverage-4.4.1/ + +Running the test suite +++++++++++++++++++++++ +The test suite can be run from the repository root:: + + pytest --cov=dgp tests + # or + coverage run --source=dgp -m unittest discover + +Add the following parameter to display lines missing coverage when using the +pytest-cov extension:: + + --cov-report term-missing + + +Use ``coverage report`` to report the results on test coverage:: + + $ coverage report -m + Name Stmts Miss Cover Missing + -------------------------------------------------------------- + dgp/__init__.py 0 0 100% + dgp/lib/__init__.py 0 0 100% + dgp/lib/etc.py 6 0 100% + dgp/lib/gravity_ingestor.py 94 0 100% + dgp/lib/time_utils.py 52 3 94% 131-136 + dgp/lib/trajectory_ingestor.py 50 8 84% 62-65, 93-94, 100-101, 106 + -------------------------------------------------------------- + TOTAL 202 11 95% + +Documentation +------------- +The documentation is written in reStructuredText and built using Sphinx. Some +other things to know about the docs: + +- It consists of two parts: the docstrings in the code and the docs in this folder. + + Docstrings provide a clear explanation of the usage of the individual functions, + while the documentation in this folder consists of tutorials, planning, and + technical documents related data formats, sensors, and processing techniques. + +- The docstrings in this project follow the `NumPydoc docstring standard`_. + This standard specifies the format of the different sections of the docstring. + See `this document`_ for a detailed explanation and examples. + +- See `Quick reStructuredText `__ + for a quick-reference on reStructuredText syntax and markup. + +- Documentation can also contain cross-references to other + classes/objects/modules using the `Sphinx Domain Reference Syntax `__ + +- Documentation is automatically built on push for designated branches + (typically master and develop) and hosted on `Read the Docs `__ + +.. _`NumPydoc docstring standard`: https://numpydoc.readthedocs.io/en/latest/ +.. _`this document`: http://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_numpy.html + +Building the documentation +++++++++++++++++++++++++++ +Navigate to the ``dgp/docs`` directory in the console. On Linux and MacOS X run:: + + make html + +or on Windows run:: + + make.bat + +If the build completes without errors, then you will find the HTML output in +``dgp/docs/build/html``. + +Alternately, documentation can be built by calling the sphinx python module +e.g.:: + + python -m sphinx -M html source build + diff --git a/docs/source/core/controllers.rst b/docs/source/core/controllers.rst new file mode 100644 index 0000000..e40467b --- /dev/null +++ b/docs/source/core/controllers.rst @@ -0,0 +1,158 @@ +dgp.core.controllers package +============================ + +The Controllers package contains the various controller classes which are +layered on top of the core 'data models' (see the :doc:`models`) which +themselves store the raw project data. + +The function of the controller classes is to provide an interaction +layer on top of the data layer - without complicating the underlying +data classes, especially as the data classes must undergo serialization +and de-serialization. + +The controllers provide various functionality related to creating, +traversing, and mutating the project tree-hierarchy. The controllers +also interact in minor ways with the UI, and more importantly, are the +layer by which the UI interacts with the underlying project data. + + +TODO: Add Controller Hierarchy like in models.rst + + +Controller Development Principles +--------------------------------- + +.. py:currentmodule:: dgp.core.controllers + +Controllers typically should match 1:1 a model class, though there are cases +for creating controllers such as the :class:`~.project_containers.ProjectFolder` +which is a utility class for grouping items visually in the project's tree view. + +Controllers should at minimum subclass +:class:`~.controller_interfaces.VirtualBaseController` which configures inheritance +for :class:`QStandardItem` and :class:`~.controller_mixins.AttributeProxy`. +For more complex and widely used controllers, a dedicated interface should be +created following the same naming scheme - particularly where circular +dependencies may be introduced. + + +Context Menu Declarations +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Due to the nature of :class:`QMenu`, the menu cannot be instantiated directly +ahead of time as it requires a parent :class:`QWidget` to bind to. This has +led to the current solution which lets each controller declaratively define +their context menu items and actions (with some common actions mixed in by +the view at runtime). +The declaration syntax at present is simply a list of tuples which is queried +by the view when a context menu is requested. + +Following is an example declaring a single menu item to be displayed when +right-clicking on the controller's representation in the UI + +.. code-block:: python + + bindings = [ + ('addAction', ('Properties', lambda: self._show_properties())), + ] + +The menu is built by iterating through the bindings list, each 2-tuple is a +tuple of the QMenu function to call ('addAction'), and the positional +arguments supplied to the function - in this case the name 'Properties', and +the lambda functor to call when activated. + +.. contents:: + :depth: 2 + + +Interfaces +---------- + +The following interfaces provide interface definitions for the various +controllers used within the overall project model. + +The interfaces, while perhaps not exactly Pythonic, provide great utility +in terms of type safety in the interaction of the various controllers. +In most cases the concrete subclasses of these interfaces cannot be +directly imported into other controllers as this would cause circular +import loops + + +e.g. the :class:`~.flight_controller.FlightController` +is a child of an :class:`~.project_controllers.AirborneProjectController`, +but the FlightController also stores a typed reference to its parent +(creating a circular reference), the interfaces are designed to allow proper +type hinting within the development environment in such cases. + + +.. py:module:: dgp.core.controllers.controller_interfaces + +.. autoclass:: VirtualBaseController + :show-inheritance: + :undoc-members: + +.. autoclass:: IAirborneController + :show-inheritance: + :undoc-members: + +.. autoclass:: IFlightController + :show-inheritance: + :undoc-members: + +.. autoclass:: IMeterController + :show-inheritance: + :undoc-members: + +.. autoclass:: IDataSetController + :show-inheritance: + :undoc-members: + + +Controllers +----------- + +**Concrete controller implementations** + +.. py:module:: dgp.core.controllers.project_controllers +.. autoclass:: AirborneProjectController + :undoc-members: + :show-inheritance: + +.. py:module:: dgp.core.controllers.flight_controller +.. autoclass:: FlightController + :undoc-members: + :show-inheritance: + +.. py:module:: dgp.core.controllers.gravimeter_controller +.. autoclass:: GravimeterController + :undoc-members: + :show-inheritance: + +.. py:module:: dgp.core.controllers.dataset_controller +.. autoclass:: DataSetController + :undoc-members: + :show-inheritance: + +.. py:module:: dgp.core.controllers.datafile_controller +.. autoclass:: DataFileController + :undoc-members: + :show-inheritance: + +Containers +---------- + +.. py:module:: dgp.core.controllers.project_containers +.. autoclass:: ProjectFolder + :undoc-members: + :show-inheritance: + + +Utility/Helper Modules +---------------------- + +.. autoclass:: dgp.core.controllers.controller_mixins.AttributeProxy + :undoc-members: + +.. automodule:: dgp.core.controllers.controller_helpers + :undoc-members: + diff --git a/docs/source/core/data-management.rst b/docs/source/core/data-management.rst new file mode 100644 index 0000000..cb6358d --- /dev/null +++ b/docs/source/core/data-management.rst @@ -0,0 +1,28 @@ +Data Management in DGP +====================== + +DGP manages and interacts with a variety of forms of Data. +Imported raw data (GPS or Gravity) is ingested and maintained internally as a +:class:`pandas.DataFrame` or :class:`pandas.Series` from their raw +representation in comma separated value (CSV) files. +The ingestion process performs type-casts, filling/interpolation of missing +values, and time index creation/conversion functions to result in a +ready-to-process DataFrame. + +These DataFrames are then stored in the project's HDF5_ data-file, which +natively supports (with PyTables_ and Pandas) the storage and retrieval of +DataFrames and Series. + +.. _HDF5: https://portal.hdfgroup.org/display/support +.. _PyTables: https://www.pytables.org/ + +To facilitate storage and retrieval of data within the project, the +:class:`~dgp.core.hdf5_manager.HDF5Manager` class provides an easy to use +wrapper around the :class:`pandas.HDFStore` and provides utility methods +for getting/setting meta-data attributes on nodes. + +.. py:module:: dgp.core.hdf5_manager + +.. autoclass:: HDF5Manager + :undoc-members: + :private-members: diff --git a/docs/source/core/index.rst b/docs/source/core/index.rst new file mode 100644 index 0000000..daa1917 --- /dev/null +++ b/docs/source/core/index.rst @@ -0,0 +1,36 @@ +***************** +dgp\.core package +***************** + +Core modules and packages defining the project data-layer +and controllers for interfacing with the data-layer via the +user interface. + + +.. toctree:: + :caption: Sub Packages + :maxdepth: 1 + + models.rst + controllers.rst + types.rst + + +Sub Modules +=========== + +dgp.core.file_loader module +--------------------------- + +.. automodule:: dgp.core.file_loader + :members: + :undoc-members: + + +dgp.core.oid module +------------------- + +.. automodule:: dgp.core.oid + :members: + :undoc-members: + diff --git a/docs/source/core/models.rst b/docs/source/core/models.rst new file mode 100644 index 0000000..07684be --- /dev/null +++ b/docs/source/core/models.rst @@ -0,0 +1,118 @@ +dgp.core.models package +======================= + +The models package contains and defines the various data classes that define +the logical structure of a 'Gravity Project' + +Currently we are focused exclusively on providing functionality for +representing and processing an Airborne gravity survey/campaign. +In future support will be added for processing and managing Marine gravity +survey's/campaigns. + +The following generally describes the class hierarchy of a typical Airborne project: + +.. py:module:: dgp.core.models + + +| :obj:`~.project.AirborneProject` +| ├── :obj:`~.flight.Flight` +| │ ├── :obj:`~.dataset.DataSet` +| │ │ ├── :obj:`~.datafile.DataFile` -- Gravity +| │ │ ├── :obj:`~.datafile.DataFile` -- Trajectory +| │ │ └── :obj:`~.dataset.DataSegment` -- Container (Multiple) +| │ └── :obj:`~.meter.Gravimeter` -- Link +| └── :obj:`~.meter.Gravimeter` + +----------------------------------------- + +The project can have multiple :obj:`~.flight.Flight`, and each Flight can have +0 or more :obj:`~.flight.FlightLine`, :obj:`~.datafile.DataFile`, and linked +:obj:`~.meter.Gravimeter`. +The project can also define multiple Gravimeters, of varying type with specific +configuration files assigned to each. + +Model Development Principles +---------------------------- + +- Classes in the core models should be kept as simple as possible. +- :class:`@properties` (getter/setter) are encouraged where state updates must + accompany a value change +- Otherwise, simple attributes/fields are preferred +- Models may contain back-references (upwards in the hierarchy) only to their + parent (using the 'magic' parent attribute) - otherwise the JSON serializer + will complain. +- Any complex functions/transformations should be handled by the model's + controller +- Data validation should be handled by the controller, not the model. +- A limited set of complex objects can be used and serialized in the model, + support may be added as the need arises in the JSON serializer. +- Any field defined in a model's :attr:`__dict__` or :attr:`__slots__` is + serialization by the ProjectEncoder, and consequently must be accepted + by name (keyword argument) in the model constructor for de-serialization + +Supported Complex Types +^^^^^^^^^^^^^^^^^^^^^^^ + +- :class:`pathlib.Path` +- :class:`datetime.datetime` +- :class:`datetime.date` +- :class:`dgp.core.oid.OID` +- All classes in :mod:`dgp.core.models` + +See :class:`~dgp.core.models.project.ProjectDecoder` and +:class:`~dgp.core.models.project.ProjectEncoder` for implementation details. + + +.. contents:: + :depth: 2 + + +dgp.core.models.project module +------------------------------ + +.. autoclass:: dgp.core.models.project.GravityProject + :undoc-members: + +.. autoclass:: dgp.core.models.project.AirborneProject + :undoc-members: + :show-inheritance: + +Project Serialization/De-Serialization Classes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: dgp.core.models.project.ProjectEncoder + :show-inheritance: + +.. autoclass:: dgp.core.models.project.ProjectDecoder + :show-inheritance: + + +dgp.core.models.meter module +---------------------------- + +.. versionadded:: 0.1.0 +.. automodule:: dgp.core.models.meter + :undoc-members: + +dgp.core.models.flight module +----------------------------- + +.. automodule:: dgp.core.models.flight + :undoc-members: + +dgp.core.models.datafile module +------------------------------- + +.. automodule:: dgp.core.models.datafile + :members: + :undoc-members: + +dgp.core.models.dataset module +------------------------------ + +.. versionadded:: 0.1.0 +.. automodule:: dgp.core.models.dataset + :members: + :undoc-members: + + diff --git a/docs/source/core/types.rst b/docs/source/core/types.rst new file mode 100644 index 0000000..e638f72 --- /dev/null +++ b/docs/source/core/types.rst @@ -0,0 +1,6 @@ +dgp.core.types package +====================== + + +Stuff about types + diff --git a/docs/source/dgp.rst b/docs/source/dgp.rst deleted file mode 100644 index 8d7af74..0000000 --- a/docs/source/dgp.rst +++ /dev/null @@ -1,17 +0,0 @@ -dgp package -=========== - -Subpackages ------------ - -.. toctree:: - - dgp.lib - -Module contents ---------------- - -.. automodule:: dgp - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/gui/index.rst b/docs/source/gui/index.rst new file mode 100644 index 0000000..b4dc2a5 --- /dev/null +++ b/docs/source/gui/index.rst @@ -0,0 +1,30 @@ +dgp.gui package +=============== + +This package contains modules and sub-packages related to the +Graphical User Interface (GUI) presentation layer of DGP. + +DGP's User Interface is built on the Qt 5 C++ library, using the +PyQt Python bindings. + +Custom Qt Views, Widgets, and Dialogs are contained here, as well +as plotting interfaces. + +Qt Interfaces and Widgets created with Qt Creator generate .ui XML +files, which are then compiled into a Python source files which define +individual UI components. +The .ui source files are contained within the ui directory. + +.. toctree:: + :caption: Sub Packages + :maxdepth: 1 + + plotting.rst + workspaces.rst + + +.. seealso:: + + `Qt 5 Documentation `__ + + `PyQt5 Documentation `__ diff --git a/docs/source/gui/plotting.rst b/docs/source/gui/plotting.rst new file mode 100644 index 0000000..d5086cb --- /dev/null +++ b/docs/source/gui/plotting.rst @@ -0,0 +1,97 @@ +dgp.gui.plotting package +======================== + +The plotting package contains the backend wrappers and classes used by the DGP +application to interactively plot data within the GUI. + +The interactive plotting framework that we utilize here is based on the +`PyQtGraph `__ python +package, which itself utilizes the +`Qt Graphics View Framework `__ to +provide a highly performant interactive plotting interface. + + +The modules within the plotting package are separated into the :ref:`bases`, +:ref:`plotters` and :ref:`helpers` modules, which provide the base plot +wrappers, task/application specific plot widgets, and plot utility functions/ +classes respectively. + +The :ref:`bases` module defines the base plot wrappers which wrap some of +PyQtGraph's plotting functionality to ease the plotting and management of +Pandas Series data within a plot surface. + +The :ref:`plotters` module provides task specific plot widgets that can be +directly incorporated into a QtWidget application's layout. These classes add +specific functionality to the base 'backend' plots, for example to enable +graphical click-drag selection of data segments by the user. + + +Types/Consts/Enums +------------------ + +.. py:module:: dgp.gui.plotting + +.. py:data:: backends.MaybePlot + :annotation: = Union[ DgpPlotItem, None ] + + Typedef for a function which returns a :class:`DgpPlotItem` or :const:`None` + +.. py:data:: backends.MaybeSeries + :annotation: = Union[ pandas.Series, None ] + + Typedef for a function which returns a :class:`pandas.Series` or :const:`None` + +.. py:data:: backends.SeriesIndex + :annotation: = Tuple[ str, int, int, Axis ] + + Typedef for a tuple representing the unique index of a series on a plot + within a :class:`GridPlotWidget` + +.. autoclass:: dgp.gui.plotting.backends.Axis + :undoc-members: + +.. autoclass:: dgp.gui.plotting.backends.AxisFormatter + :undoc-members: + + +.. _bases: + +Bases +----- + +.. autoclass:: dgp.gui.plotting.backends.GridPlotWidget + :undoc-members: + :show-inheritance: + +.. autoclass:: dgp.gui.plotting.backends.DgpPlotItem + :show-inheritance: + +.. autoclass:: dgp.gui.plotting.backends.LinkedPlotItem + :show-inheritance: + +.. _plotters: + +Plotters +-------- + +.. autoclass:: dgp.gui.plotting.plotters.LineSelectPlot + :undoc-members: + :show-inheritance: + +.. _helpers: + +Helpers +------- + +.. autoclass:: dgp.gui.plotting.helpers.PolyAxis + :undoc-members: + :show-inheritance: + +.. autoclass:: dgp.gui.plotting.helpers.LinearSegment + :undoc-members: + :show-inheritance: + +.. autoclass:: dgp.gui.plotting.helpers.LinearSegmentGroup + :undoc-members: + :show-inheritance: + diff --git a/docs/source/gui/workspaces.rst b/docs/source/gui/workspaces.rst new file mode 100644 index 0000000..f41dc98 --- /dev/null +++ b/docs/source/gui/workspaces.rst @@ -0,0 +1,82 @@ +dgp.gui.workspaces package +========================== + + +The Workspaces sub-package defines GUI widgets for various controller +contexts in the DGP application. +The idea being that there are naturally different standard ways in which the +user will interact with different project objects/controllers, depending on the +type of the object. + +The workspaces are intended to be displayed within a QTabWidget within the +application so that the user may easily navigate between multiple open +workspaces. + +Each workspace defines its own custom widget(s) for interacting & manipulating +data associated with its underlying controller (:class:`VirtualBaseController`). + +Workspaces may also contain sub-tabs, for example the :class:`DataSetTab` +defines sub-tabs for viewing raw-data and selecting segments, and a tab for +executing transform graphs on the data. + +.. contents:: + :depth: 3 + + +Base Interfaces +--------------- + +.. versionadded:: 0.1.0 + +.. automodule:: dgp.gui.workspaces.base + + +Workspaces +---------- + +Project Workspace +^^^^^^^^^^^^^^^^^ + +.. warning:: Not yet implemented + +.. note:: + + Future Planning: Project Workspace may display a map interface which can + overlay each flight's trajectory path from the flights within the project. + Some interface to allow comparison of flight data may also be integrated into + this workspace. + +.. automodule:: dgp.gui.workspaces.project + +Flight Workspace +^^^^^^^^^^^^^^^^ +.. warning:: Not yet implemented + +.. note:: + + Future Planning: Similar to the project workspace, the flight workspace may + be used to display a map of the selected flight. + A dashboard type widget may be implemented to show details of the flight, + and to allow users to view/configure flight specific parameters. + +.. automodule:: dgp.gui.workspaces.flight + + +DataSet Workspace +^^^^^^^^^^^^^^^^^ +.. versionadded:: 0.1.0 + +.. automodule:: dgp.gui.workspaces.dataset + + + +DataFile Workspace +^^^^^^^^^^^^^^^^^^ +.. warning:: Not yet implemented + +.. note:: + + Future Planning: The DataFile workspace may be used to allow users to view + and possibly edit raw data within the interface in a spreadsheet style + view/control. + diff --git a/docs/source/index.rst b/docs/source/index.rst index 83ef737..7251bdb 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,19 +1,57 @@ -.. Dynamic Gravity Processor documentation master file, created by - sphinx-quickstart on Mon Aug 14 09:16:37 2017. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - Welcome to Dynamic Gravity Processor's documentation! ===================================================== +What is DGP? +^^^^^^^^^^^^ + +**DGP** is a library as well a graphical desktop application for processing +gravity data collected with dynamic gravity systems, such as those run on +ships and aircraft. + +The library can be used to automate the processing workflow and experiment with +new techniques. The application was written to fulfill the needs of of gravity +processing in production environments. + +The project aims to bring all gravity data processing under a single umbrella by: + +- accommodating various sensor types, data formats, and processing techniques +- providing a flexible framework to allow for experimentation with the workflow +- providing a robust and efficient system for production-level processing + +Core Dependencies ++++++++++++++++++ + +(Subject to change) + +- Python >= 3.6 +- numpy >= 1.13.1 +- pandas == 0.20.3 +- scipy == 1.1.0 +- pyqtgraph >= 0.10.0 +- PyQt5 >= 5.10 +- PyTables >= 3.4.2 + .. toctree:: - :maxdepth: 2 - :caption: Contents: - - modules - dgp.lib + :caption: Getting Started + :maxdepth: 1 + install.rst + userguide.rst + +.. toctree:: + :caption: API Documentation + + core/index.rst + lib/index.rst + gui/index.rst + core/data-management.rst + +.. toctree:: + :caption: Development + contributing.rst + requirements-specification-include.rst + todo.rst Indices and tables ================== diff --git a/docs/source/install.rst b/docs/source/install.rst new file mode 100644 index 0000000..a8a5472 --- /dev/null +++ b/docs/source/install.rst @@ -0,0 +1,5 @@ +============ +Installation +============ + +TODO: All diff --git a/docs/source/dgp.lib.rst b/docs/source/lib/index.rst similarity index 73% rename from docs/source/dgp.lib.rst rename to docs/source/lib/index.rst index 2041492..05eda87 100644 --- a/docs/source/dgp.lib.rst +++ b/docs/source/lib/index.rst @@ -1,14 +1,15 @@ dgp\.lib package ================ -Submodules ----------- + +This package contains library functions and utilities for loading, +processing, and transforming gravity and trajectory data. + dgp\.lib\.gravity\_ingestor module ---------------------------------- .. automodule:: dgp.lib.gravity_ingestor - :members: :undoc-members: :show-inheritance: @@ -16,7 +17,6 @@ dgp\.lib\.time\_utils module ---------------------------- .. automodule:: dgp.lib.time_utils - :members: :undoc-members: :show-inheritance: @@ -24,15 +24,6 @@ dgp\.lib\.trajectory\_ingestor module ------------------------------------- .. automodule:: dgp.lib.trajectory_ingestor - :members: :undoc-members: :show-inheritance: - -Module contents ---------------- - -.. automodule:: dgp.lib - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/modules.rst b/docs/source/modules.rst deleted file mode 100644 index 7ea1b01..0000000 --- a/docs/source/modules.rst +++ /dev/null @@ -1,7 +0,0 @@ -dgp -=== - -.. toctree:: - :maxdepth: 4 - - dgp diff --git a/docs/source/requirements-specification-include.rst b/docs/source/requirements-specification-include.rst new file mode 100644 index 0000000..41ed175 --- /dev/null +++ b/docs/source/requirements-specification-include.rst @@ -0,0 +1 @@ +.. include:: ../../requirements-specification.rst diff --git a/docs/source/todo.rst b/docs/source/todo.rst new file mode 100644 index 0000000..e5c7dc4 --- /dev/null +++ b/docs/source/todo.rst @@ -0,0 +1,4 @@ +Documentation ToDo's +==================== + +.. todolist:: diff --git a/docs/source/userguide.rst b/docs/source/userguide.rst new file mode 100644 index 0000000..f9d8727 --- /dev/null +++ b/docs/source/userguide.rst @@ -0,0 +1,59 @@ +User Guide +========== + +.. todo:: Write documentation/tutorial on how to use the application, + targeted at actual users, not developers. + +Creating a new project +---------------------- + + +Project Structure (Airborne) +++++++++++++++++++++++++++++ + +An Airborne gravity project in DGP is centered primarily around the +:obj:`Flight` construct as a representation of an actual survey flight. A +flight has at least one :obj:`DataSet` containing Trajectory (GPS) and Gravity +data files, and at least one associated :obj:`Gravimeter`. + +A :obj:`Flight` may potentially have more than one :obj:`DataSet` associated +with it, and more than one :obj:`Gravimeter`. + +Each DataSet has exactly one Trajectory and one Gravity DataFile contained +within it, and the :obj:`DataSet` may define :obj:`DataSegments` which are +directly associated with the encapsulated files. + +DataSegments are used to select areas of data which are of interest for +processing, typically this means they are used to select the individual +Flight Lines out of a continuous data file, i.e. the segments between course +changes of the aircraft. + + + + +Creating Flights/Survey's +------------------------- + + +Importing Gravimeter (Sensor) Configurations +-------------------------------------------- + + +Importing Gravity/Trajectory (GPS) Data +--------------------------------------- + + + +Data Processing Workflow +------------------------ + +Selecting Survey Lines +++++++++++++++++++++++ + + +Selecting/Applying Transformation Graphs +++++++++++++++++++++++++++++++++++++++++ + + +Viewing Line Repeats +++++++++++++++++++++ diff --git a/examples/daniels_processing_workflow.py b/examples/daniels_processing_workflow.py new file mode 100644 index 0000000..4bcf3df --- /dev/null +++ b/examples/daniels_processing_workflow.py @@ -0,0 +1,206 @@ +import numpy as np +import matplotlib.pyplot as plt +from scipy import signal +from scipy.signal import correlate, filtfilt, firwin, freqz +import easygui +from tempfile import TemporaryFile +import os + +from ..dgp.lib.eotvos import calc_eotvos +from ..dgp.lib.timesync import find_time_delay, time_Shift_array +from lib.trajectory_ingestor import import_trajectory +from lib.gravity_ingestor import read_at1a + +os.getcwd() + +MeterGain = 1.0 + +plt.interactive(True) +# was sept7.dat +path = easygui.fileopenbox() +# meter=read_at1a('tests\january10vant2st.dat') +meter = read_at1a(path) +fields = ['mdy', 'hms', 'lat', 'long', 'ortho_ht', 'ell_ht', 'num_sats', 'pdop'] +# was Possept7.txt +path = easygui.fileopenbox() +gpsdata = import_trajectory(path, columns=fields, skiprows=1, timeformat='hms') + + +def find_nearest(array, value): + idx = (np.abs(array - value)).argmin() + return idx + + +# newindex = meter.index.union(gpsdata.index) +# meter= meter.reindex(newindex) +# gpsdata = gpsdata.reindex(newindex) + +if meter.index[0] >= gpsdata.index[0]: + start = meter.index[0] +else: + start = gpsdata.index[0] + +if meter.index[-1] >= gpsdata.index[-1]: + end = gpsdata.index[-1] +else: + end = meter.index[-1] + +meter = meter[start: end] +gpsdata = gpsdata[start: end] +Eotvos = calc_eotvos(gpsdata.lat.values, gpsdata.long.values, + gpsdata.ell_ht.values, 10) + +# filter design for time sync +fs = 10 # sampling frequency +nyq_rate = fs / 2 +numtaps = 2001 +fc = 0.01 # frequecy stop +Nfc = fc / nyq_rate # normaliced cutt of frequency +a = 1.0 +b = signal.firwin(numtaps, Nfc, window='blackman') +fgv = signal.filtfilt(b, a, meter.gravity) +fet = signal.filtfilt(b, a, Eotvos) +timef = find_time_delay(fet, -fgv, 10) +print('time shift filtered', timef) +# + + +# Use this for big lag determination +# corr = correlate(ref, target) +# lag = len(ref) - 1 - np.argmax(corr) + +time = find_time_delay(Eotvos, -meter.gravity, 10) +print('time shift', time) +# time= 0.763 # overwrite here +gravitys = time_Shift_array(meter.gravity, -time, 10) +time = find_time_delay(Eotvos, -gravitys, 10) +print('time shift fixed', time) +Total = MeterGain * gravitys + Eotvos + +# select the lines using eotvos no vertical acce +h = np.zeros(len(gpsdata.ell_ht)) +Eot_simple = calc_eotvos(gpsdata.lat.values, gpsdata.long.values, h, 10) +plt.figure(figsize=(14, 9)) +# plt.figure() +plt.title('Eotvos_simple') +plt.plot(Eot_simple) +plt.show() + +# easygui.msgbox('continue') +nlines = int(easygui.enterbox('Select numbe of lines')) +clicks = 2 * nlines + +x = plt.ginput(clicks, timeout=100) +print("clicked", x) +np.save('lines', x) + +# filter design +fs = 10 # sampling frequency +nyq_rate = fs / 2 +numtaps = 2001 +fc = 0.008 # frequecy stop +Nfc = fc / nyq_rate # normaliced cutt of frequency +a = 1.0 +b = signal.firwin(numtaps, Nfc, window='blackman') + +""" +w, h = freqz(b,worN=8000) +plt.plot((w/np.pi)*nyq_rate, np.absolute(h), linewidth=1) +plt.xlabel('Frequency (Hz)') +plt.ylabel('Gain') +plt.title('Frequency Response') +plt.ylim(-0.1,1.1) +plt.xlim(0,0.1) +plt.grid(True) +""" + +fGrav = signal.filtfilt(b, a, Total) +# fGrav=signal.filtfilt(b,a,fGrav1) +flong = signal.filtfilt(b, a, gpsdata.long) +flat = signal.filtfilt(b, a, gpsdata.lat) + +# cut the data in lines +# llong = {} +# lgrav = {} +plt.interactive(False) +plt.figure() +plt.title('Corrected Gravity stack') + +longmin = 10000 +longmax = -10000 + +for n in range(0, nlines): + a = int(x[2 * n][0]) + b = int(x[2 * n + 1][0]) + plt.plot(flong[a:b], fGrav[a:b], label=n) + minl = min(flong[a:b]) + maxl = max(flong[a:b]) + if minl < longmin: + longmin = minl + if maxl > longmax: + longmax = maxl +plt.legend() +plt.show() + +# calculate repeats +a = int(x[0][0]) +b = int(x[1][0]) + +longrange = flong[a + 1000:b - 1000] +latrange = flat[a + 100:b - 100] + +# longrange=np.linspace(longmin,longmax,len(flong)) + + +# built the lonfitude to generate the test points + +Avg = [] +Inter = [] +foravgg = [] +foravglo = [] + +plt.figure() + +sumg = 0 +for l in range(0, nlines): + a = int(x[2 * l][0]) + b = int(x[2 * l + 1][0]) + lo = flong[a:b] + la = flat[a:b] + g = fGrav[a:b] + Inter = [] + dr = 0.001 + for n in range(0, len(longrange), 10): + indices = np.where( + np.logical_and(lo >= longrange[n] - dr, lo <= longrange[n] + dr)) + point = np.array(indices) + Inter.append(point.item(0)) + + # plt.plot(lo[point.item(0)],g[point.item(0)]) + print('number of intersections', len(Inter)) + plt.plot(lo[Inter], g[Inter]) + foravglo.append(lo[Inter]) + foravgg.append(g[Inter]) +# find average line +avg = np.sum(foravgg, axis=0) +avg = avg / nlines +plt.plot(lo[Inter], avg, 'r--') +plt.show() + +# calculate sigma mean error +meanerror = [] +meanabs = 0 +plt.figure() +plt.title('Error to to the mean') +for l in range(0, nlines): + error = foravgg[l] - avg + meanabs = meanabs + np.mean(np.absolute(error)) + meanerror.append(error) + plt.plot(error) + +meanabserror = meanabs / nlines +print('mean absolute error', meanabserror) + +print(np.std(meanerror, axis=1)) +stdev = np.std(meanerror, axis=1) +print(np.sum(stdev, axis=0) / nlines) diff --git a/examples/plot2_prototype.py b/examples/plot2_prototype.py new file mode 100644 index 0000000..9d3d35b --- /dev/null +++ b/examples/plot2_prototype.py @@ -0,0 +1,130 @@ +import os +import sys +import uuid +import logging +import datetime +import traceback + +from PyQt5 import QtCore +import PyQt5.QtWidgets as QtWidgets +import PyQt5.Qt as Qt +import numpy as np +from pandas import Series, DatetimeIndex +from matplotlib.axes import Axes +from matplotlib.patches import Rectangle +from matplotlib.dates import date2num + +os.chdir('..') +import dgp.lib.project as project +# from dgp.gui.plotting.plotter2 import FlightLinePlot + + +class MockDataChannel: + def __init__(self, series, label): + self._series = series + self.label = label + self.uid = uuid.uuid4().__str__() + + def series(self): + return self._series + + def plot(self, *args): + pass + + +class PlotExample(QtWidgets.QMainWindow): + def __init__(self): + super().__init__() + self.setWindowTitle('Plotter Testing') + self.setBaseSize(Qt.QSize(600, 600)) + self._flight = project.Flight(None, 'test') + + self._plot = FlightLinePlot(self._flight, parent=self) + self._plot.set_mode(grab=True) + print("Plot: ", self._plot) + # self.plot.figure.canvas.mpl_connect('pick_event', lambda x: print( + # "Pick event handled")) + # self.plot.mgr = StackedAxesManager(self.plot.figure, rows=2) + # self._toolbar = NavToolbar(self.plot, parent=self) + # self._toolbar.actions()[0] = QtWidgets.QAction("Reset View") + # self._toolbar.actions()[0].triggered.connect(lambda x: print( + # "Action 0 triggered")) + + self.tb = self._plot.get_toolbar() + + plot_layout = QtWidgets.QVBoxLayout() + plot_layout.addWidget(self._plot) + plot_layout.addWidget(self.tb) + c_widget = QtWidgets.QWidget() + c_widget.setLayout(plot_layout) + + self.setCentralWidget(c_widget) + + plot_layout.addWidget(QtWidgets.QPushButton("Reset")) + + # toolbar = self.plot.get_toolbar(self) + self.show() + + def plot_sin(self): + idx = DatetimeIndex(freq='5S', start=datetime.datetime.now(), + periods=1000) + ser = Series([np.sin(x)*3 for x in np.arange(0, 100, 0.1)], index=idx) + self.plot.mgr.add_series(ser) + self.plot.mgr.add_series(-ser) + ins_0 = self.plot.mgr.add_inset_axes(0) # type: Axes + ins_0.plot(ser.index, ser.values) + x0, x1 = ins_0.get_xlim() + width = (x1 - x0) * .5 + y0, y1 = ins_0.get_ylim() + height = (y1 - y0) * .5 + # Draw rectangle patch on inset axes - proof of concept to add inset + # locator when zoomed in on large data set. + ax0 = self.plot.mgr[0][0] # type: Axes + rect = Rectangle((date2num(idx[0]), 0), width, height, + edgecolor='black', + linewidth=2, alpha=.5, fill='red') + rect.set_picker(True) + patch = ins_0.add_patch(rect) # type: Rectangle + # Future idea: Add click+drag to view patch to pan in main plot + def update_rect(ax: Axes): + x0, x1 = ax.get_xlim() + y0, y1 = ax.get_ylim() + patch.set_x(x0) + patch.set_y(y0) + height = y1 - y0 + width = x1 - x0 + patch.set_width(width) + patch.set_height(height) + ax.draw_artist(patch) + self.plot.draw() + + ax0.callbacks.connect('xlim_changed', update_rect) + ax0.callbacks.connect('ylim_changed', update_rect) + + self.plot.draw() + ins_1 = self.plot.mgr.add_inset_axes(1) + + +def excepthook(type_, value, traceback_): + """This allows IDE to properly display unhandled exceptions which are + otherwise silently ignored as the application is terminated. + Override default excepthook with + >>> sys.excepthook = excepthook + + See: http://pyqt.sourceforge.net/Docs/PyQt5/incompatibilities.html + """ + traceback.print_exception(type_, value, traceback_) + QtCore.qFatal('') + + +if __name__ == '__main__': + sys.excepthook = excepthook + app = QtWidgets.QApplication(sys.argv) + _log = logging.getLogger() + _log.addHandler(logging.StreamHandler(sys.stdout)) + _log.setLevel(logging.DEBUG) + + window = PlotExample() + # window.plot_sin() + sys.exit(app.exec_()) + diff --git a/examples/plot_example.py b/examples/plot_example.py index 3aa75a9..0bcc716 100644 --- a/examples/plot_example.py +++ b/examples/plot_example.py @@ -1,13 +1,63 @@ import os import sys -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) -# import dgp +import uuid +import logging +import datetime +# sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), +# '../dgp'))) -from dgp.gui import plotting as plots -from dgp.lib import gravity_ingestor as gi +import PyQt5.QtWidgets as QtWidgets +import PyQt5.Qt as Qt + +import numpy as np +from pandas import Series, DatetimeIndex + +os.chdir('..') +import dgp.lib.project as project +import dgp.gui.plotting.plotter as plotter + + +class MockDataChannel: + def __init__(self, series, label): + self._series = series + self.label = label + self.uid = uuid.uuid4().__str__() + + def series(self): + return self._series + + def plot(self, *args): + pass + + +class PlotExample(QtWidgets.QMainWindow): + def __init__(self): + super().__init__() + self.setWindowTitle('Plotter Testing') + self.setBaseSize(Qt.QSize(600, 600)) + self._flight = project.Flight(None, 'test') + self.plot = plotter.LineGrabPlot(self._flight, 2) + self.setCentralWidget(self.plot) + # toolbar = self.plot.get_toolbar(self) + self.show() + + def plot_sin(self): + idx = DatetimeIndex(freq='1S', start=datetime.datetime.now(), + periods=1000) + ser = Series([np.sin(x) for x in np.arange(0, 100, 0.1)], index=idx) + dc = MockDataChannel(ser, 'SinPlot') + dc2 = MockDataChannel(-ser, '-SinPlot') + self.plot.add_series(dc) + self.plot.add_series(dc2) + + +if __name__ == '__main__': + app = QtWidgets.QApplication(sys.argv) + _log = logging.getLogger() + _log.addHandler(logging.StreamHandler(sys.stdout)) + _log.setLevel(logging.DEBUG) + + window = PlotExample() + window.plot_sin() + sys.exit(app.exec_()) -os.chdir('../tests') -df = gi.read_at1m(os.path.abspath('./test_data.csv')) -plt = plots.Plots() -plt.generate_subplots(df.index, df['gravity'], df['pressure'], df['temp']) -# plt.generate_subplots(df.index, df['gravity']) diff --git a/examples/process_example_2.py b/examples/process_example_2.py new file mode 100644 index 0000000..044ebd9 --- /dev/null +++ b/examples/process_example_2.py @@ -0,0 +1,92 @@ +from datetime import datetime +import numpy as np +import pandas as pd + +from dgp.lib.gravity_ingestor import read_at1a +from dgp.lib.trajectory_ingestor import import_trajectory +from dgp.lib.etc import align_frames +from dgp.lib.transform.transform_graphs import AirbornePost +from dgp.lib.transform.filters import detrend + + +def compute_static(begin, end): + return gravity[(begin < gravity.index) & (gravity.index < end)][ + 'gravity'].mean() + + +if __name__ == "__main__": + # import gravity + print('Importing gravity') + gravity_filepath = '/Users/cbertinato/Documents/Git/dgp_example/data/AN04_F1001_20171103_2127.dat' + gravity = read_at1a(gravity_filepath, interp=True) + + # import trajectory + print('Importing trajectory') + trajectory_filepath = '/Users/cbertinato/Documents/Git/dgp_example/data/AN04_F1001_20171103_DGS-INS_FINAL_DGS.txt' + gps_fields = ['mdy', 'hms', 'lat', 'long', 'ortho_ht', 'ell_ht', + 'num_stats', 'pdop'] + trajectory = import_trajectory(trajectory_filepath, + columns=gps_fields, skiprows=1, + timeformat='hms') + + # ROSETTA 3, F1001 + # 11/3/2017 + k_factor = 1.0737027 + first_static = 14555.4 + second_static = 14554.9 + tie_gravity = 980352 + + # L650 + begin_line = datetime(2017, 11, 4, 0, 39) + end_line = datetime(2017, 11, 4, 1, 45) + + # pre-processing prep + gravity = gravity[ + (begin_line <= gravity.index) & (gravity.index <= end_line)] + trajectory = trajectory[ + (begin_line <= trajectory.index) & (trajectory.index <= end_line)] + + # align gravity and trajectory frames + gravity, trajectory = align_frames(gravity, trajectory) + + # adjust for crossing the prime meridian + trajectory['long'] = trajectory['long'].where(trajectory['long'] > 0, + trajectory['long'] + 360) + + # dedrift + gravity['gravity'] = detrend(gravity['gravity'], first_static, + second_static) + + # adjust to absolute + offset = tie_gravity - k_factor * first_static + gravity['gravity'] += offset + + # begin_first_static = datetime(2016, 8, 10, 19, 57) + # end_first_static = datetime(2016, 8, 10, 20, 8) + # first_static = compute_static(begin_first_static, end_first_static) + # + # begin_second_static = datetime(2016, 8, 10, 21, 7) + # end_second_static = datetime(2016, 8, 10, 21, 17) + # second_static = compute_static(begin_second_static, end_second_static) + + print('Processing') + g = AirbornePost(trajectory, gravity, begin_static=first_static, + end_static=second_static) + results = g.execute() + + trajectory = results['shifted_trajectory'] + time = pd.Series(trajectory.index.astype(np.int64) / 10 ** 9, + index=trajectory.index, name='unix_time') + output_frame = pd.concat([time, trajectory[['lat', 'long', 'ell_ht']], + results['aligned_eotvos'], + results['aligned_kin_accel'], results['lat_corr'], + results['fac'], results['total_corr'], + results['abs_grav'], results['corrected_grav']], + axis=1) + output_frame.columns = ['unix_time', 'lat', 'lon', 'ell_ht', 'eotvos', + 'kin_accel', 'lat_corr', 'fac', 'total_corr', + 'vert_accel', 'gravity'] + output_frame = output_frame.iloc[15:-15] + output_frame.to_csv( + '/Users/cbertinato/Documents/Git/dgp_example/data/L650.csv', + index=False) diff --git a/examples/process_script.py b/examples/process_script.py new file mode 100755 index 0000000..f800904 --- /dev/null +++ b/examples/process_script.py @@ -0,0 +1,142 @@ +import os +from datetime import datetime + +from dgp.lib.gravity_ingestor import read_at1a +from dgp.lib.trajectory_ingestor import import_trajectory +from dgp.lib.etc import align_frames +from dgp.lib.transform.transform_graphs import AirbornePost +from dgp.lib.transform.filters import detrend +from dgp.lib.plots import timeseries_gravity_diagnostic, mapplot_line, read_meterconfig + +# Runtime Option +campaign = 'OIB' # 'ROSETTA' + +# Set paths +if campaign == 'ROSETTA': + print('ROSETTA') + basedir = '/Users/dporter/Documents/Research/Projects/DGP_test/' + gravity_directory = 'DGP_data' + gravity_file = 'AN04_F1001_20171103_2127.dat' + trajectory_directory = gravity_directory + trajectory_file = 'AN04_F1001_20171103_DGS-INS_FINAL_DGS.txt' + # L650 + begin_line = datetime(2017, 11, 4, 0, 27) + end_line = datetime(2017, 11, 4, 1, 45) + gps_fields = ['mdy', 'hms', 'lat', 'long', 'ortho_ht', 'ell_ht', 'num_stats', 'pdop'] +elif campaign == 'OIB': + print('OIB') + basedir = '/Users/dporter/Documents/Research/Projects/OIB-grav/data/P3_2017' + gravity_directory = 'gravity/dgs/raw/F2004' + gravity_file = 'OIB-P3_20170327_F2004_DGS_0938.dat' + trajectory_directory = 'pnt/dgs-ins/F2004/txt' + trajectory_file = 'OIB-P3_20170327_F2004_DGS-INS_RAPID_DGS.txt' + # NW Coast Parallel + begin_line = datetime(2017, 3, 27, 15, 35) + end_line = datetime(2017, 3, 27, 16, 50) + gps_fields = ['mdy', 'hms', 'lat', 'long', 'ortho_ht', 'ell_ht', 'num_stats', 'pdop'] + +else: + print('Scotia?') + +# Load Data Files +print('\nImporting gravity') +gravity = read_at1a(os.path.join(basedir, gravity_directory, gravity_file), interp=True) +print('\nImporting trajectory') +trajectory = import_trajectory(os.path.join(basedir, trajectory_directory, trajectory_file), + columns=gps_fields, skiprows=1, timeformat='hms') + +# Read MeterProcessing file in Data Directory +config_file = os.path.join(basedir, gravity_directory, "MeterProcessing.ini") +k_factor = read_meterconfig(config_file, 'kfactor') +tie_gravity = read_meterconfig(config_file, 'TieGravity') +print('{0} {1}'.format(k_factor, tie_gravity)) +flight = gravity_file[4:11] + +# statics +# TODO: Semi-automate or create GUI to get statics +first_static = read_meterconfig(config_file, 'PreStill') +second_static = read_meterconfig(config_file, 'PostStill') +# def compute_static(begin, end): +# return gravity[(begin < gravity.index) & (gravity.index < end)]['gravity'].mean() +# +# begin_first_static = datetime(2016, 8, 10, 19, 57) +# end_first_static = datetime(2016, 8, 10, 20, 8) +# first_static = compute_static(begin_first_static, end_first_static) +# +# begin_second_static = datetime(2016, 8, 10, 21, 7) +# end_second_static = datetime(2016, 8, 10, 21, 17) +# second_static = compute_static(begin_second_static, end_second_static) + +# pre-processing prep +trajectory_full = trajectory[['long', 'lat']] +gravity = gravity[(begin_line <= gravity.index) & (gravity.index <= end_line)] +trajectory = trajectory[(begin_line <= trajectory.index) & (trajectory.index <= end_line)] + +# align gravity and trajectory frames +gravity, trajectory = align_frames(gravity, trajectory) + +# adjust for crossing the prime meridian +trajectory['long'] = trajectory['long'].where(trajectory['long'] > 0, trajectory['long'] + 360) + +# de-drift +gravity['gravity'] = detrend(gravity['gravity'], first_static, second_static) + +# adjust to absolute +offset = tie_gravity - k_factor * first_static +gravity['gravity'] += offset + +# print('\nProcessing') +# g = AirbornePost(trajectory, gravity, begin_static=first_static, end_static=second_static) +# results = g.execute() + +########### +# Real plots +print('\nPlotting') +if 'results' in locals(): + # Time-series Plot + variables = ['ell_ht', 'lat', 'long'] + variable_units = ['m', 'degrees', 'degrees'] + plot_title = campaign + ' ' + flight + ': PNT' + plot_name = os.path.join(basedir, campaign + '_' + flight + '_DGP_TS_pnt.png') + timeseries_gravity_diagnostic(results['shifted_trajectory'], variables, variable_units, begin_line, end_line, + plot_title, plot_name) + + # Time-series Plot + variables = ['eotvos', 'lat_corr', 'fac', 'total_corr'] + variable_units = ['mGal', 'mGal', 'mGal', 'mGal'] + plot_title = campaign + ' ' + flight + ': Corrections' + plot_name = os.path.join(basedir, campaign + '_' + flight + '_DGP_TS_corrections.png') + timeseries_gravity_diagnostic(results, variables, variable_units, begin_line, end_line, + plot_title, plot_name) + + # Time-series Plot + variables = ['filtered_grav', 'corrected_grav', 'abs_grav'] + variable_units = ['mGal', 'mGal', 'mGal', 'mGal'] + plot_title = campaign + ' ' + flight + ': Gravity' + plot_name = os.path.join(basedir, campaign + '_' + flight + '_DGP_TS_gravity.png') + timeseries_gravity_diagnostic(results, variables, variable_units, begin_line, end_line, + plot_title, plot_name) + + # Map Plot + plot_title = campaign + ' ' + flight + ': Gravity' + plot_name = os.path.join(basedir, campaign + '_' + flight + '_DGP_mapplot_gravity.png') + mapplot_line(trajectory_full, trajectory, results, 'filtered_grav', 'mGal', plot_title, plot_name) +else: + # Temporary plots for when graph is commented out (currently OIB_P3) + variables = ['gravity', 'cross_accel', 'beam', 'temp'] + variable_units = ['mGal', 'mGal', 'mGal', 'C'] + plot_title = campaign + ' ' + flight + ': QC' + plot_name = os.path.join(basedir, campaign + '_' + flight + '_DGP_TS_QC.png') + timeseries_gravity_diagnostic(gravity, variables, variable_units, begin_line, end_line, + plot_title, plot_name) + + variables = ['ell_ht', 'ortho_ht', 'lat', 'long'] + variable_units = ['m', 'm', 'degrees', 'degrees'] + plot_title = campaign + ' ' + flight + ': PNT' + plot_name = os.path.join(basedir, campaign + '_' + flight + '_DGP_TS_pnt.png') + timeseries_gravity_diagnostic(trajectory, variables, variable_units, begin_line, end_line, + plot_title, plot_name) + + plot_title = campaign + ' ' + flight + ': Gravity' + plot_name = os.path.join(basedir, campaign + '_' + flight + '_DGP_mapplot_gravity.png') + mapplot_line(trajectory_full, trajectory, gravity, 'gravity', 'mGal', plot_title, plot_name) diff --git a/examples/pyqtgraph_line_selection_plot.py b/examples/pyqtgraph_line_selection_plot.py new file mode 100644 index 0000000..aa6d92d --- /dev/null +++ b/examples/pyqtgraph_line_selection_plot.py @@ -0,0 +1,78 @@ +import os +import sys +import uuid +import logging +import datetime +import traceback + +from PyQt5 import QtCore +import PyQt5.QtWidgets as QtWidgets +import PyQt5.Qt as Qt +import numpy as np +from pandas import Series, DatetimeIndex + +os.chdir('..') +import dgp.lib.project as project +from dgp.gui.plotting.plotters import PqtLineSelectPlot as LineSelectPlot + + +class MockDataChannel: + def __init__(self, series, label): + self._series = series + self.label = label + self.uid = uuid.uuid4().__str__() + + def series(self): + return self._series + + def plot(self, *args): + pass + + +class PlotExample(QtWidgets.QMainWindow): + def __init__(self): + super().__init__() + self.setWindowTitle('Plotter Testing') + self.setBaseSize(Qt.QSize(600, 600)) + self._flight = project.Flight(None, 'test') + + self._plot = LineSelectPlot(flight=self._flight, rows=3) + self._plot.line_changed.connect(lambda upd: print(upd)) + self.setCentralWidget(self._plot.widget) + + self.show() + + idx = DatetimeIndex(freq='5S', start=datetime.datetime.now(), + periods=1000) + ser = Series([np.sin(x)*3 for x in np.arange(0, 100, 0.1)], index=idx) + p0 = self._plot.plots[0] + p0.add_series(ser) + print("new xlim: ", p0.get_xlim()) + x0, x1 = p0.get_xlim() + xrng = x1 - x0 + tenpct = xrng * .1 + + +def excepthook(type_, value, traceback_): + """This allows IDE to properly display unhandled exceptions which are + otherwise silently ignored as the application is terminated. + Override default excepthook with + >>> sys.excepthook = excepthook + + See: http://pyqt.sourceforge.net/Docs/PyQt5/incompatibilities.html + """ + traceback.print_exception(type_, value, traceback_) + QtCore.qFatal('') + + +if __name__ == '__main__': + sys.excepthook = excepthook + app = QtWidgets.QApplication(sys.argv) + _log = logging.getLogger() + _log.addHandler(logging.StreamHandler(sys.stdout)) + _log.setLevel(logging.DEBUG) + + window = PlotExample() + # window.plot_sin() + sys.exit(app.exec_()) + diff --git a/examples/treemodel_integration_test.py b/examples/treemodel_integration_test.py new file mode 100644 index 0000000..962a3c9 --- /dev/null +++ b/examples/treemodel_integration_test.py @@ -0,0 +1,117 @@ +# -*- coding: utf-8 -*- +import datetime +import sys +import traceback +from itertools import count +from pathlib import Path +from pprint import pprint + +from PyQt5 import QtCore + +from dgp.core.models.dataset import DataSet +from dgp.core.oid import OID +from dgp.core.controllers.flight_controller import FlightController +from dgp.core.controllers.project_controllers import AirborneProjectController +from core.controllers.project_treemodel import ProjectTreeModel +from dgp.core.models.flight import Flight, FlightLine, DataFile +from dgp.core.models.meter import Gravimeter +from dgp.core.models.project import AirborneProject + +from PyQt5.uic import loadUiType +from PyQt5.QtWidgets import QDialog, QApplication + +from gui.views import ProjectTreeView + +tree_dialog, _ = loadUiType('treeview.ui') + + +def excepthook(type_, value, traceback_): + """This allows IDE to properly display unhandled exceptions which are + otherwise silently ignored as the application is terminated. + Override default excepthook with + >>> sys.excepthook = excepthook + + See: http://pyqt.sourceforge.net/Docs/PyQt5/incompatibilities.html + """ + traceback.print_exception(type_, value, traceback_) + QtCore.qFatal('') + + +class TreeTestDialog(QDialog, tree_dialog): + """ + Tree GUI Members: + treeViewTop : QTreeView + treeViewBtm : QTreeView + button_add : QPushButton + button_delete : QPushButton + """ + + def __init__(self, model): + super().__init__(parent=None) + self.setupUi(self) + + self.treeView: ProjectTreeView + + self.treeView.setModel(model) + model.flight_changed.connect(self._flight_changed) + self.treeView.expandAll() + + def _flight_changed(self, flight: FlightController): + print("Setting fl model") + self.cb_flight_lines.setModel(flight.lines_model) + + +if __name__ == "__main__": + sys.excepthook = excepthook + + # Mock up a base project + project = AirborneProject(name="Test Project", path=Path('.'), create_date=datetime.datetime(2018, 5, 12)) + flt = Flight('Test Flight', datetime.datetime(2018, 3, 9), uid=OID(base_uuid='0a193af02d1f46c6b8bad4dad028b3bc')) + flt.add_child(FlightLine(datetime.datetime.now().timestamp(), datetime.datetime.now().timestamp() + 3600, 1)) + flt.add_child(DataSet()) + # first one is real reference in HDF5 + # flt.add_child(DataFile('gravity', datetime.datetime.today(), + # source_path=Path('C:\\RealSample.txt'), + # uid=OID(base_uuid='4458f26f6d7b4eb09097093dd2b85c61'))) + # flt.add_child(DataFile('gravity', datetime.datetime.today(), source_path=Path('C:\\data2.csv'))) + # flt.add_child(DataFile('trajectory', datetime.datetime.today(), + # source_path=Path('C:\\trajectory1.dat'))) + at1a6 = Gravimeter('AT1A-6') + at1a10 = Gravimeter('AT1A-10') + project.add_child(at1a6) + # project.add_child(flt) + + app = QApplication([]) + + prj_ctrl = AirborneProjectController(project) + model = ProjectTreeModel(prj_ctrl) + # proxy_model = ProjectTreeProxyModel() + # proxy_model.setSourceModel(model) + # proxy_model.setFilterRole(Qt.UserRole) + # proxy_model.setFilterType(Flight) + + dlg = TreeTestDialog(model) + # dlg.qlv_proxy.setModel(proxy_model) + prj_ctrl.set_parent_widget(dlg) + fc = prj_ctrl.add_child(flt) + dlg.qlv_0.setModel(fc.data_model) + dlg.qlv_1.setModel(fc.data_model) + + counter = count(2) + + def add_line(): + for fc in prj_ctrl.flights.items(): + fc.add_child(FlightLine(datetime.datetime.now().timestamp(), datetime.datetime.now().timestamp() + 2400, + next(counter))) + + # cn_select_dlg = ChannelSelectDialog(fc.data_model, plots=1) + + dlg.btn.clicked.connect(add_line) + dlg.btn_export.clicked.connect(lambda: pprint(project.to_json(indent=4))) + dlg.btn_flight.clicked.connect(lambda: prj_ctrl.add_flight()) + dlg.btn_gravimeter.clicked.connect(lambda: prj_ctrl.add_gravimeter()) + dlg.btn_importdata.clicked.connect(lambda: prj_ctrl.load_file_dlg()) + dlg.qpb_properties.clicked.connect(lambda: prj_ctrl.properties_dlg()) + dlg.show() + prj_ctrl.add_child(at1a10) + sys.exit(app.exec_()) diff --git a/examples/treeview.ui b/examples/treeview.ui new file mode 100644 index 0000000..e813c38 --- /dev/null +++ b/examples/treeview.ui @@ -0,0 +1,112 @@ + + + Dialog + + + + 0 + 0 + 580 + 650 + + + + Dialog + + + + + + + + + 15 + 15 + + + + false + + + false + + + + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + + Add Line + + + + + + + Add Gravimeter + + + + + + + Import Data + + + + + + + Add Flight + + + + + + + Project Properties + + + + + + + Export JSON + + + + + + + + ProjectTreeView + QTreeView +
dgp.gui.views.ProjectTreeView
+
+
+ + + + +
diff --git a/examples/treeview_testing.ui b/examples/treeview_testing.ui new file mode 100644 index 0000000..424d4b9 --- /dev/null +++ b/examples/treeview_testing.ui @@ -0,0 +1,57 @@ + + + Dialog + + + + 0 + 0 + 522 + 497 + + + + Dialog + + + + + + + + + + + + Tree Controls + + + + + + Add Flight + + + + + + + Delete Last Flight + + + + + + + PushButton + + + + + + + + + + + diff --git a/requirements-specification.rst b/requirements-specification.rst index 50b4734..3d46455 100644 --- a/requirements-specification.rst +++ b/requirements-specification.rst @@ -1,9 +1,6 @@ -====================================== -Gravity Processing and Analysis System -====================================== ------------------------------------ +=================================== Software Requirements Specification ------------------------------------ +=================================== Overall Description =================== @@ -29,114 +26,133 @@ Functional Requirements ======================= 1. FR1 + - Description: The user shall be able to import gravity data. The user shall be able to choose file type and define the format. - Priority: High - Rationale: Required to process gravity data. Allowing the user to define the type and format reduces future work to incorporate other sensors or changes to file types and formats. - Dependencies: None 2. FR2 + - Description: The user shall be able to import position and attitude data. The user shall be able to choose file type and define the format. - Priority: High - Rationale: Required to process gravity data. Allowing the user to define the type and format reduces future work to incorporate other sensors or changes to file types and formats. - Dependencies: None 4. FR4 + - Description: The user shall be able to organize data by project and flight. - Priority: High - Rationale: This is a standard organizing principle. - Dependencies: None 5. FR5 + - Description: The user shall be able to import and compare multiple trajectories for a flight. - Priority: Medium - Rationale: For comparison of INS hardware and post-processing methods. - Dependencies: None 6. FR6 + - Description: The user shall be able to combine and analyze data across projects and flights. - Priority: Medium - Rationale: For comparison of line reflown, or to produce a grid of lines flown for a survey, for example. - Dependencies: None 7. FR7 + - Description: The user shall be able to select sections of a flight for processing. - Priority: High - Rationale: Necessary to properly process gravity. - Dependencies: None 8. FR8 + - Description: The user shall be able to plot all corrections. - Priority: High - Rationale: For troubleshooting, for example. - Dependencies: None 9. FR9 + - Description: The user shall be able to choose to plot any channel. - Priority: High - Rationale: For quality control of data, diagnostics, and performance assessment. - Dependencies: None 10. FR10 + - Description: The user shall be able to compare with lines and grids processed externally. - Priority: Medium - Rationale: For quality control of data, diagnostics, and performance assessment. - Dependencies: None 11. FR11 + - Description: The user shall be able to export data. The user shall be able to choose file type and define the format. - Priority: High - Rationale: For further processing or use in another system. - Dependencies: None 12. FR12 + - Description: The user shall be able to specify sensor-specific parameters. - Priority: High - Rationale: Required to process gravity data. - Dependencies: None 13. FR13 + - Description: The user shall be able to plot flight track on a map. - Priority: High - Rationale: To facilitate selection of sections for processing. - Dependencies: FR2 14. FR14 + - Description: The user shall be able to import a background image or data set as the background for the map. - Priority: Low - Rationale: To facilitate selection of sections for processing. - Dependencies: FR13 15. FR15 + - Description: The user shall be able to choose the method used to filter data and any associated parameters. - Priority: High - Rationale: To facilitate comparison of processing methods. - Dependencies: None 16. FR16 + - Description: The user shall be able to compute statistics for any channel. - Priority: High - Rationale: For quality control of data, diagnostics, and performance assessment. - Dependencies: 17. FR17 + - Description: The user shall be able to perform cross-over analysis. - Priority: Medium - Rationale: For quality control at the level of a whole survey. - Dependencies: 18. FR18 + - Description: The user shall be able to perform upward continuation. - Priority: Low - Rationale: For quality control at the level of a whole survey. - Dependencies: 19. FR19 + - Description: The user shall ble able to flag bad data within lines and choose whether to exclude from processing. - Priority: High - Rationale: For quality control of data, diagnostics, and performance assessment. - Dependencies: 20. FR20 + - Description: The user shall be able to import outside data sets (e.g., SRTM, geoid) for comparison with flown gravity. - Priority: High - Rationale: For quality control of data, diagnostics, and performance assessment. diff --git a/requirements.txt b/requirements.txt index b1bb300..aff020d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,30 +1,8 @@ -alabaster==0.7.10 -Babel==2.5.0 -certifi==2017.7.27.1 -chardet==3.0.4 -coverage==4.4.1 -cycler==0.10.0 -docutils==0.14 -idna==2.6 -imagesize==0.7.1 -Jinja2==2.9.6 -MarkupSafe==1.0 -matplotlib==2.0.2 -numexpr==2.6.2 -numpy==1.13.1 -pandas==0.20.3 -Pygments==2.2.0 -pyparsing==2.2.0 -PyQt5==5.9 -python-dateutil==2.6.1 -pytz==2017.2 -requests==2.18.4 -scipy==0.19.1 -sip==4.19.3 -six==1.10.0 -snowballstemmer==1.2.1 -Sphinx==1.6.3 -sphinx-rtd-theme==0.2.4 -sphinxcontrib-websupport==1.0.1 -tables==3.4.2 -urllib3==1.22 +# Project Requirements +matplotlib>=2.0.2 +numpy>=1.13.1 +pandas==0.23.3 +PyQt5==5.11.2 +pyqtgraph==0.10.0 +tables==3.4.4 +scipy==1.1.0 diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 0000000..e529836 --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,5 @@ +pytest>=3.6.1 +coverage>=4.4.1 +pytest-cov>=2.5.1 +pytest-faulthandler==1.5.0 +coveralls diff --git a/tests/__init__.py b/tests/__init__.py index e69de29..f11a9e7 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -0,0 +1,3 @@ +import pathlib + +sample_dir = pathlib.Path('tests/sample_data') diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..464ed94 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,164 @@ +# -*- coding: utf-8 -*- +import os +import sys +import traceback +from datetime import datetime +from pathlib import Path + +import pandas as pd +import pytest +from PyQt5 import QtCore +from PyQt5.QtCore import QSettings +from PyQt5.QtWidgets import QApplication + +from dgp.gui.settings import set_settings +from dgp.core import DataType +from dgp.core.controllers.project_controllers import AirborneProjectController +from dgp.core.hdf5_manager import HDF5_NAME +from dgp.core.models.datafile import DataFile +from dgp.core.models.dataset import DataSegment, DataSet +from dgp.core.models.flight import Flight +from dgp.core.models.meter import Gravimeter +from dgp.core.models.project import AirborneProject +from dgp.core.oid import OID +from dgp.lib.gravity_ingestor import read_at1a +from dgp.lib.trajectory_ingestor import import_trajectory + +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) + +"""Global pytest configuration file for DGP test suite. + +This takes care of configuring a QApplication instance for executing tests +against UI code which requires an event loop (signals etc). +If a handle to the QApplication is required, e.g. to use as the parent to a test +object, the qt_app fixture can be used. + +The sys.excepthook is also replaced to enable catching of some critical errors +raised within the Qt domain that would otherwise not be printed. + +""" + + +@pytest.fixture(scope='session', autouse=True) +def shim_settings(): + """Override DGP Application settings object so as not to pollute the regular + settings when testing. + + This fixture will be automatically called, and will delete the settings ini + file at the conclusion of the test session. + """ + settings = QSettings(QSettings.IniFormat, QSettings.UserScope, "DgS", "DGP") + set_settings(settings) + yield + if os.path.exists(settings.fileName()): + os.unlink(settings.fileName()) + + +def qt_msg_handler(type_, context, message: str): + level = { + QtCore.QtDebugMsg: "QtDebug", + QtCore.QtWarningMsg: "QtWarning", + QtCore.QtCriticalMsg: "QtCritical", + QtCore.QtFatalMsg: "QtFatal", + QtCore.QtInfoMsg: "QtInfo" + }.get(type_, "QtDebug") + if type_ >= QtCore.QtCriticalMsg: + print(f'QtMessage: {level} {message}', file=sys.stderr) + + +QtCore.qInstallMessageHandler(qt_msg_handler) + + +def excepthook(type_, value, traceback_): + """This allows IDE to properly display unhandled exceptions which are + otherwise silently ignored as the application is terminated. + Override default excepthook with + >>> sys.excepthook = excepthook + + See Also + -------- + + http://pyqt.sourceforge.net/Docs/PyQt5/incompatibilities.html + """ + traceback.print_exception(type_, value, traceback_) + QtCore.qFatal('') + + +sys.excepthook = excepthook +APP = QApplication([]) + + +def get_ts(offset=0): + return datetime.now().timestamp() + offset + + +@pytest.fixture(scope='module') +def qt_app(): + return APP + + +@pytest.fixture() +def project_factory(): + def _factory(name, path, flights=2, dataset=True): + base_dir = Path(path) + prj = AirborneProject(name=name, path=base_dir.joinpath(''.join(name.split(' '))), + description=f"Description of {name}") + prj.path.mkdir() + + flt1 = Flight("Flt1", sequence=0, duration=4) + flt2 = Flight("Flt2", sequence=1, duration=6) + + mtr = Gravimeter.from_ini(Path('tests').joinpath('at1m.ini'), name="AT1A-X") + + grav1 = DataFile(DataType.GRAVITY, datetime.now(), base_dir.joinpath('gravity1.dat')) + traj1 = DataFile(DataType.TRAJECTORY, datetime.now(), base_dir.joinpath('gps1.dat')) + seg1 = DataSegment(OID(), get_ts(0), get_ts(1500), 0, "seg1") + seg2 = DataSegment(OID(), get_ts(1501), get_ts(3000), 1, "seg2") + + if dataset: + dataset1 = DataSet(grav1, traj1, [seg1, seg2]) + flt1.datasets.append(dataset1) + + prj.add_child(mtr) + prj.add_child(flt1) + prj.add_child(flt2) + return prj + return _factory + + + +@pytest.fixture() +def project(project_factory, tmpdir): + """This fixture constructs a project model with a flight, gravimeter, + DataSet (and its children - DataFile/DataSegment) for testing the serialization + and de-serialization of a fleshed out project. + """ + return project_factory("TestProject", tmpdir) + + +@pytest.fixture() +def prj_ctrl(project): + return AirborneProjectController(project) + + +@pytest.fixture +def flt_ctrl(prj_ctrl: AirborneProjectController): + return prj_ctrl.get_child(prj_ctrl.datamodel.flights[0].uid) + + +@pytest.fixture(scope='module') +def hdf5file(tmpdir_factory) -> Path: + file = Path(tmpdir_factory.mktemp("dgp")).joinpath(HDF5_NAME) + file.touch(exist_ok=True) + return file + + +@pytest.fixture(scope='session') +def gravdata() -> pd.DataFrame: + return read_at1a('tests/sample_gravity.csv') + + +@pytest.fixture(scope='session') +def gpsdata() -> pd.DataFrame: + return import_trajectory('tests/sample_trajectory.txt', timeformat='hms', + skiprows=1) diff --git a/tests/context.py b/tests/context.py deleted file mode 100644 index 9d9a87a..0000000 --- a/tests/context.py +++ /dev/null @@ -1,10 +0,0 @@ -# coding: utf-8 - -import os -import sys -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) - -# Import dgp making the project available to test suite by relative import of this file -# e.g. from .context import dgp - -import dgp diff --git a/tests/sample.csv b/tests/sample.csv deleted file mode 100644 index bbd5ff8..0000000 --- a/tests/sample.csv +++ /dev/null @@ -1,9 +0,0 @@ -10062.261052, -0.084221, -0.115037, -0.093792, 62.251979, 21061, 39.690004, 52.294525,1959,219697.300 -10061.914332, -0.107825, -0.141799, -0.093793, 62.251979, 21061, 39.690004, 52.288713,1959,219697.400 -10061.270423, -0.062048, -0.135839, -0.093797, 62.252648, 21061, 39.690004, 52.273600,1959,219697.600 -10061.121829, -0.043094, -0.082552, -0.093799, 62.253318, 21061, 39.690004, 52.259650,1959,219697.700 -10061.171360, -0.026226, -0.094891, -0.093803, 62.253987, 21061, 39.690004, 52.263138,1959,219697.800 -10061.270423, -0.019431, -0.144064, -0.093807, 62.253987, 21061, 39.690004, 52.277088,1959,219697.900 -10061.419017, -0.020802, -0.138521, -0.093814, 62.252648, 21061, 39.690004, 52.295687,1959,219698.000 -10061.567612, -0.020802, -0.100315, -0.093822, 62.253318, 21061, 39.690004, 52.293363,1959,219698.100 -10061.617143, -0.019670, -0.104725, -0.093831, 62.253318, 21061, 39.690004, 52.286388,1959,219698.200 diff --git a/tests/sample_data/eotvos_short_input.txt b/tests/sample_data/eotvos_short_input.txt new file mode 100644 index 0000000..1e7eb04 --- /dev/null +++ b/tests/sample_data/eotvos_short_input.txt @@ -0,0 +1,101 @@ +GPS Date,GPS Time, Lattitude, Longitude, Orthometric Heigth,Elipsoidal Height,Num of satelites,PDOP + 9/14/2017,15:38:39.00, 39.9148595446,-105.057988972, 1615.999, 1599.197, 0, 0.00 + 9/14/2017,15:38:39.10, 39.9148599142,-105.057988301, 1615.991, 1599.190, 0, 0.00 + 9/14/2017,15:38:39.20, 39.9148607753,-105.057986737, 1615.973, 1599.172, 0, 0.00 + 9/14/2017,15:38:39.30, 39.9148614843,-105.057985449, 1615.958, 1599.157, 0, 0.00 + 9/14/2017,15:38:39.40, 39.9148617500,-105.057984967, 1615.953, 1599.152, 0, 0.00 + 9/14/2017,15:38:39.50, 39.9148617748,-105.057984922, 1615.953, 1599.151, 0, 0.00 + 9/14/2017,15:38:39.60, 39.9148617748,-105.057984922, 1615.953, 1599.151, 0, 0.00 + 9/14/2017,15:38:39.70, 39.9148617748,-105.057984922, 1615.953, 1599.151, 0, 0.00 + 9/14/2017,15:38:39.80, 39.9148618286,-105.057984811, 1615.952, 1599.151, 0, 0.00 + 9/14/2017,15:38:39.90, 39.9148619529,-105.057984553, 1615.951, 1599.150, 0, 0.00 + 9/14/2017,15:38:40.00, 39.9148620900,-105.057984268, 1615.951, 1599.149, 0, 0.00 + 9/14/2017,15:38:40.10, 39.9148622338,-105.057983967, 1615.950, 1599.148, 0, 0.00 + 9/14/2017,15:38:40.20, 39.9148623765,-105.057983668, 1615.949, 1599.148, 0, 0.00 + 9/14/2017,15:38:40.30, 39.9148624276,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:40.40, 39.9148624276,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:40.50, 39.9148624276,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:40.60, 39.9148624276,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:40.70, 39.9148624277,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:40.80, 39.9148624277,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:40.90, 39.9148624277,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:41.00, 39.9148624277,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:41.10, 39.9148624277,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:41.20, 39.9148624276,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:41.30, 39.9148624276,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:41.40, 39.9148624276,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:41.50, 39.9148624276,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:41.60, 39.9148624276,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:41.70, 39.9148624276,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:41.80, 39.9148624277,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:41.90, 39.9148624277,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:42.00, 39.9148624276,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:42.10, 39.9148624276,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:42.20, 39.9148624276,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:42.30, 39.9148624275,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:42.40, 39.9148624275,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:42.50, 39.9148624275,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:42.60, 39.9148624275,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:42.70, 39.9148624276,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:42.80, 39.9148624276,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:42.90, 39.9148624276,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:43.00, 39.9148624276,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:43.10, 39.9148624276,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:43.20, 39.9148624275,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:43.30, 39.9148624275,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:43.40, 39.9148624275,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:43.50, 39.9148624275,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:43.60, 39.9148624275,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:43.70, 39.9148624275,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:43.80, 39.9148624275,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:43.90, 39.9148624276,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:44.00, 39.9148624275,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:44.10, 39.9148624275,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:44.20, 39.9148624275,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:44.30, 39.9148624274,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:44.40, 39.9148624274,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:44.50, 39.9148624274,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:44.60, 39.9148624274,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:44.70, 39.9148624275,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:44.80, 39.9148624275,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:44.90, 39.9148624275,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:45.00, 39.9148624275,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:45.10, 39.9148624274,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:45.20, 39.9148624274,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:45.30, 39.9148624274,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:45.40, 39.9148624273,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:45.50, 39.9148624274,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:45.60, 39.9148624274,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:45.70, 39.9148624274,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:45.80, 39.9148624274,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:45.90, 39.9148624274,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:46.00, 39.9148624274,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:46.10, 39.9148624274,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:46.20, 39.9148624273,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:46.30, 39.9148624273,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:46.40, 39.9148624273,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:46.50, 39.9148624273,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:46.60, 39.9148624273,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:46.70, 39.9148624274,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:46.80, 39.9148624274,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:46.90, 39.9148624274,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:47.00, 39.9148624274,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:47.10, 39.9148624273,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:47.20, 39.9148624273,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:47.30, 39.9148624273,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:47.40, 39.9148624272,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:47.50, 39.9148624272,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:47.60, 39.9148624273,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:47.70, 39.9148624273,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:47.80, 39.9148624273,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:47.90, 39.9148624273,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:48.00, 39.9148624273,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:48.10, 39.9148624273,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:48.20, 39.9148624272,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:48.30, 39.9148624272,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:48.40, 39.9148624272,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:48.50, 39.9148624272,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:48.60, 39.9148624272,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:48.70, 39.9148624272,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:48.80, 39.9148624273,-105.057983561, 1615.949, 1599.147, 0, 0.00 + 9/14/2017,15:38:48.90, 39.9148624273,-105.057983561, 1615.949, 1599.147, 0, 0.00 \ No newline at end of file diff --git a/tests/sample_data/eotvos_short_result.csv b/tests/sample_data/eotvos_short_result.csv new file mode 100644 index 0000000..d3ab8d7 --- /dev/null +++ b/tests/sample_data/eotvos_short_result.csv @@ -0,0 +1,101 @@ +Longitude,latitude,Elipsoidal h,Eotvos_full +-105.057989,39.91485954,1599.197,110015.3395 +-105.0579883,39.91485991,1599.19,110015.3395 +-105.0579867,39.91486078,1599.172,-29987.75511 +-105.0579855,39.91486148,1599.157,-99995.6938 +-105.057985,39.91486175,1599.152,-39999.7461 +-105.0579849,39.91486177,1599.151,-10000.01824 +-105.0579849,39.91486177,1599.151,0 +-105.0579849,39.91486177,1599.151,1.03750397 +-105.0579848,39.91486183,1599.151,10002.42929 +-105.0579846,39.91486195,1599.15,2.71896098 +-105.0579843,39.91486209,1599.149,2.86739311 +-105.057984,39.91486223,1599.148,-9997.139013 +-105.0579837,39.91486238,1599.148,10001.08023 +-105.0579836,39.91486243,1599.147,-9999.969253 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0.00094152 +-105.0579836,39.91486243,1599.147,-0.00094152 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,-0.00094152 +-105.0579836,39.91486243,1599.147,0.00094152 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0.00094152 +-105.0579836,39.91486243,1599.147,-0.00094152 +-105.0579836,39.91486243,1599.147,-0.00094152 +-105.0579836,39.91486243,1599.147,0.00094152 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,-0.00094152 +-105.0579836,39.91486243,1599.147,0.00094152 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0.00094152 +-105.0579836,39.91486243,1599.147,-0.00094152 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,-0.00094152 +-105.0579836,39.91486243,1599.147,0.00094152 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0.00094152 +-105.0579836,39.91486243,1599.147,-0.00188303 +-105.0579836,39.91486243,1599.147,0.00094152 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,-0.00094146 +-105.0579836,39.91486243,1599.147,0.00094146 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0.00094146 +-105.0579836,39.91486243,1599.147,-0.00094146 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,-0.00094146 +-105.0579836,39.91486243,1599.147,0.00094146 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,-0.00094146 +-105.0579836,39.91486243,1599.147,0.00188291 +-105.0579836,39.91486243,1599.147,-0.00094146 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,-0.00094146 +-105.0579836,39.91486243,1599.147,0.00094146 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0.00094146 +-105.0579836,39.91486243,1599.147,-0.00094146 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,-0.00094146 +-105.0579836,39.91486243,1599.147,0.00094146 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,-0.00094152 +-105.0579836,39.91486243,1599.147,0.00094152 +-105.0579836,39.91486243,1599.147,0.00094152 +-105.0579836,39.91486243,1599.147,-0.00094152 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,-0.00094152 +-105.0579836,39.91486243,1599.147,0.00094152 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0 +-105.0579836,39.91486243,1599.147,0.00094152 +-105.0579836,39.91486243,1599.147,-0.00094152 +-105.0579836,39.91486243,1599.147,0 diff --git a/tests/test_data.csv b/tests/sample_data/test_data.csv similarity index 100% rename from tests/test_data.csv rename to tests/sample_data/test_data.csv diff --git a/tests/test_controller_observers.py b/tests/test_controller_observers.py new file mode 100644 index 0000000..43afd04 --- /dev/null +++ b/tests/test_controller_observers.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +import weakref + +import pytest + +from dgp.core import StateAction +from dgp.core.models.flight import Flight +from dgp.core.controllers.controller_interfaces import VirtualBaseController + + +@pytest.fixture +def mock_model(): + return Flight("TestFlt") + + +class Observer: + def __init__(self, control: VirtualBaseController): + control.register_observer(self, self.on_update, StateAction.UPDATE) + control.register_observer(self, self.on_delete, StateAction.DELETE) + self.control = weakref.ref(control) + self.updated = False + self.deleted = False + + def on_update(self): + self.updated = True + + def on_delete(self): + self.deleted = True + + +# noinspection PyAbstractClass +class ClonedControl(VirtualBaseController): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.updated = False + + def update(self): + self.updated = True + + +def test_observer_notify(mock_model): + abc = VirtualBaseController(mock_model, project=None) + + assert not abc.is_active + observer = Observer(abc) + assert abc.is_active + + assert not observer.updated + assert not observer.deleted + + abc.update() + assert observer.updated + abc.delete() + assert observer.deleted + + +def test_controller_clone(mock_model): + abc = VirtualBaseController(mock_model, project=None) + assert not abc.is_clone + + # VirtualBaseController doesn't implement clone, so create our own adhoc clone + clone = ClonedControl(mock_model, None) + abc.register_clone(clone) + + assert clone.is_clone + assert not clone.updated + abc.update() + assert clone.updated diff --git a/tests/test_controllers.py b/tests/test_controllers.py new file mode 100644 index 0000000..6b6f98a --- /dev/null +++ b/tests/test_controllers.py @@ -0,0 +1,198 @@ +# -*- coding: utf-8 -*- +from datetime import datetime +from pathlib import Path + +import pytest +import pandas as pd +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QStandardItemModel, QStandardItem +from PyQt5.QtWidgets import QWidget, QMenu +from pandas import DataFrame, Timedelta, Timestamp + +from dgp.core import DataType +from dgp.core.oid import OID +from dgp.core.hdf5_manager import HDF5Manager +from dgp.core.models.dataset import DataSet, DataSegment +from dgp.core.controllers.project_controllers import AirborneProjectController +from dgp.core.models.project import AirborneProject +from dgp.core.controllers.controller_mixins import AttributeProxy +from dgp.core.controllers.controller_interfaces import IMeterController, VirtualBaseController +from dgp.core.controllers.gravimeter_controller import GravimeterController +from dgp.core.controllers.dataset_controller import (DataSetController, + DataSegmentController) +from dgp.core.models.meter import Gravimeter +from dgp.core.models.datafile import DataFile +from dgp.core.controllers.flight_controller import FlightController +from dgp.core.models.flight import Flight + + +def test_attribute_proxy(tmpdir): + _name = "TestPrj" + _path = Path(tmpdir) + prj = AirborneProject(name=_name, path=_path) + prj_ctrl = AirborneProjectController(prj) + + assert _name == prj_ctrl.get_attr('name') + + # Test get_attr on non existent attribute + with pytest.raises(AttributeError): + prj_ctrl.get_attr('not_an_attr') + + # Test attribute write protect + with pytest.raises(AttributeError): + prj_ctrl.set_attr('path', Path('.')) + + # Test attribute validation + with pytest.raises(ValueError): + prj_ctrl.set_attr('name', '1prj') + + prj_ctrl.set_attr('name', 'ValidPrjName') + + +def test_gravimeter_controller(tmpdir): + prj = AirborneProjectController(AirborneProject(name="TestPrj", path=Path(tmpdir))) + meter = Gravimeter('AT1A-Test') + meter_ctrl = GravimeterController(meter, prj) + + assert isinstance(meter_ctrl, VirtualBaseController) + assert isinstance(meter_ctrl, IMeterController) + assert isinstance(meter_ctrl, AttributeProxy) + + assert meter == meter_ctrl.data(Qt.UserRole) + + with pytest.raises(AttributeError): + meter_ctrl.set_attr('invalid_attr', 1234) + + assert 'AT1A-Test' == meter_ctrl.get_attr('name') + assert meter_ctrl.get_parent() is None + meter_ctrl.set_parent(prj) + assert prj == meter_ctrl.get_parent() + + assert hash(meter_ctrl) + + meter_ctrl_clone = meter_ctrl.clone() + assert meter == meter_ctrl_clone.entity + + assert "AT1A-Test" == meter_ctrl.data(Qt.DisplayRole) + meter_ctrl.set_attr('name', "AT1A-New") + assert "AT1A-New" == meter_ctrl.data(Qt.DisplayRole) + + +def test_flight_controller(project: AirborneProject): + prj_ctrl = AirborneProjectController(project) + flight = Flight('Test-Flt-1') + data0 = DataFile(DataType.TRAJECTORY, datetime(2018, 5, 10), Path('./data0.dat')) + data1 = DataFile(DataType.GRAVITY, datetime(2018, 5, 15), Path('./data1.dat')) + dataset = DataSet(data1, data0) + # dataset.set_active(True) + flight.datasets.append(dataset) + + _traj_data = [0, 1, 5, 9] + _grav_data = [2, 8, 1, 0] + # Load test data into temporary project HDFStore + HDF5Manager.save_data(DataFrame(_traj_data), data0, path=prj_ctrl.hdfpath) + HDF5Manager.save_data(DataFrame(_grav_data), data1, path=prj_ctrl.hdfpath) + + fc = prj_ctrl.add_child(flight) + assert hash(fc) + assert str(fc) == str(flight) + assert flight.uid == fc.uid + assert flight.name == fc.data(Qt.DisplayRole) + + dsc = fc.get_child(dataset.uid) + assert isinstance(dsc, DataSetController) + + dataset2 = DataSet() + dsc2 = fc.add_child(dataset2) + assert isinstance(dsc2, DataSetController) + + with pytest.raises(TypeError): + fc.add_child({1: "invalid child"}) + + # fc.set_parent(None) + + with pytest.raises(KeyError): + fc.remove_child("Not a real child", confirm=False) + + assert dsc2 == fc.get_child(dsc2.uid) + assert fc.remove_child(dataset2.uid, confirm=False) + assert fc.get_child(dataset2.uid) is None + + fc.remove_child(dsc.uid, confirm=False) + assert 0 == len(fc.entity.datasets) + + +def test_FlightController_bindings(project: AirborneProject): + prj_ctrl = AirborneProjectController(project) + fc0 = prj_ctrl.get_child(project.flights[0].uid) + + assert isinstance(fc0, FlightController) + + # Validate menu bindings + for binding in fc0.menu: + assert 2 == len(binding) + assert hasattr(QMenu, binding[0]) + + assert fc0 == prj_ctrl.get_child(fc0.uid) + fc0._action_delete_self(confirm=False) + assert prj_ctrl.get_child(fc0.uid) is None + + +def test_airborne_project_controller(project): + flt0 = Flight("Flt0") + mtr0 = Gravimeter("AT1A-X") + project.add_child(flt0) + project.add_child(mtr0) + + assert 3 == len(project.flights) + assert 2 == len(project.gravimeters) + + project_ctrl = AirborneProjectController(project) + assert project == project_ctrl.entity + assert project_ctrl.path == project.path + # Need a model to have a parent + assert project_ctrl.parent_widget is None + + flight = Flight("Flt1") + flight2 = Flight("Flt2") + meter = Gravimeter("AT1A-10") + + fc = project_ctrl.add_child(flight) + assert isinstance(fc, FlightController) + assert flight in project.flights + mc = project_ctrl.add_child(meter) + assert isinstance(mc, GravimeterController) + assert meter in project.gravimeters + + with pytest.raises(ValueError): + project_ctrl.add_child("Invalid Child Object (Str)") + + assert project == project_ctrl.data(Qt.UserRole) + assert project.name == project_ctrl.data(Qt.DisplayRole) + assert str(project.path) == project_ctrl.data(Qt.ToolTipRole) + assert project.uid == project_ctrl.uid + + assert isinstance(project_ctrl.meter_model, QStandardItemModel) + assert isinstance(project_ctrl.flight_model, QStandardItemModel) + + project_ctrl.add_child(flight2) + + fc2 = project_ctrl.get_child(flight2.uid) + assert isinstance(fc2, FlightController) + assert flight2 == fc2.entity + + assert 5 == project_ctrl.flights.rowCount() + project_ctrl.remove_child(flight2.uid, confirm=False) + assert 4 == project_ctrl.flights.rowCount() + assert project_ctrl.get_child(fc2.uid) is None + + assert 3 == project_ctrl.meters.rowCount() + project_ctrl.remove_child(meter.uid, confirm=False) + assert 2 == project_ctrl.meters.rowCount() + + with pytest.raises(KeyError): + project_ctrl.remove_child("Not a child") + + jsons = project_ctrl.save(to_file=False) + assert isinstance(jsons, str) + diff --git a/tests/test_dataset_controller.py b/tests/test_dataset_controller.py new file mode 100644 index 0000000..d126c3d --- /dev/null +++ b/tests/test_dataset_controller.py @@ -0,0 +1,166 @@ +# -*- coding: utf-8 -*- +from datetime import datetime +from pathlib import Path + +import pytest +import pandas as pd +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QStandardItemModel, QStandardItem +from pandas import Timestamp, Timedelta, DataFrame + +from dgp.core import OID, DataType, StateAction +from dgp.core.hdf5_manager import HDF5Manager +from dgp.core.models.datafile import DataFile +from dgp.core.models.dataset import DataSet, DataSegment +from dgp.core.models.flight import Flight +from dgp.core.models.project import AirborneProject +from dgp.core.controllers.project_controllers import AirborneProjectController +from dgp.core.controllers.dataset_controller import DataSetController, DataSegmentController +from dgp.gui.plotting.helpers import LineUpdate + + +def test_dataset_controller(tmpdir): + """Test DataSet controls + Load data from HDF5 Store + Behavior when incomplete (no grav or traj) + """ + hdf = Path(tmpdir).joinpath('test.hdf5') + prj = AirborneProject(name="TestPrj", path=Path(tmpdir)) + flt = Flight("TestFlt") + grav_file = DataFile(DataType.GRAVITY, datetime.now(), Path(tmpdir).joinpath('gravity.dat')) + traj_file = DataFile(DataType.TRAJECTORY, datetime.now(), Path(tmpdir).joinpath('trajectory.txt')) + ds = DataSet(grav_file, traj_file) + seg0 = DataSegment(OID(), Timestamp.now(), Timestamp.now() + Timedelta(minutes=30), 0) + ds.segments.append(seg0) + + flt.datasets.append(ds) + prj.add_child(flt) + + prj_ctrl = AirborneProjectController(prj) + fc0 = prj_ctrl.get_child(flt.uid) + dsc: DataSetController = fc0.get_child(ds.uid) + assert 1 == dsc._segments.rowCount() + + assert isinstance(dsc, DataSetController) + assert fc0 == dsc.get_parent() + assert grav_file == dsc.get_datafile(grav_file.group).entity + assert traj_file == dsc.get_datafile(traj_file.group).entity + + grav1_file = DataFile(DataType.GRAVITY, datetime.now(), Path(tmpdir).joinpath('gravity2.dat')) + dsc.add_datafile(grav1_file) + assert grav1_file == dsc.get_datafile(grav1_file.group).entity + + traj1_file = DataFile(DataType.TRAJECTORY, datetime.now(), Path(tmpdir).joinpath('traj2.txt')) + dsc.add_datafile(traj1_file) + assert traj1_file == dsc.get_datafile(traj1_file.group).entity + + invl_file = DataFile('marine', datetime.now(), Path(tmpdir)) + with pytest.raises(TypeError): + dsc.add_datafile(invl_file) + + with pytest.raises(KeyError): + dsc.get_datafile('marine') + + # Test Data Segment Features + _seg_oid = OID(tag="seg1") + _seg1_start = Timestamp.now() + _seg1_stop = Timestamp.now() + Timedelta(hours=1) + update = LineUpdate(StateAction.CREATE, _seg_oid, _seg1_start, _seg1_stop, "seg1") + seg1_ctrl = dsc.add_child(update) + seg1: DataSegment = seg1_ctrl.entity + assert _seg1_start == seg1.start + assert _seg1_stop == seg1.stop + assert "seg1" == seg1.label + + assert seg1_ctrl == dsc.get_child(_seg_oid) + assert isinstance(seg1_ctrl, DataSegmentController) + assert "seg1" == seg1_ctrl.get_attr('label') + assert _seg_oid == seg1_ctrl.uid + + assert 2 == len(ds.segments) + assert ds.segments[1] == seg1_ctrl.entity + assert ds.segments[1] == seg1_ctrl.data(Qt.UserRole) + + # Segment updates + _new_start = Timestamp.now() + Timedelta(hours=2) + _new_stop = Timestamp.now() + Timedelta(hours=3) + seg = dsc.get_child(seg1.uid) + seg.set_attr("start", _new_start) + seg.set_attr("stop", _new_stop) + assert _new_start == seg1.start + assert _new_stop == seg1.stop + assert "seg1" == seg1.label + + seg.set_attr("label", "seg1label") + assert "seg1label" == seg1.label + + invalid_uid = OID() + assert dsc.get_child(invalid_uid) is None + with pytest.raises(KeyError): + dsc.remove_child(invalid_uid) + + assert 2 == len(ds.segments) + dsc.remove_child(seg1.uid) + assert 1 == len(ds.segments) + assert 1 == dsc._segments.rowCount() + + +def test_dataset_datafiles(project: AirborneProject): + prj_ctrl = AirborneProjectController(project) + flt_ctrl = prj_ctrl.get_child(project.flights[0].uid) + ds_ctrl = flt_ctrl.get_child(flt_ctrl.entity.datasets[0].uid) + + grav_file = ds_ctrl.entity.gravity + grav_file_ctrl = ds_ctrl.get_datafile(DataType.GRAVITY) + gps_file = ds_ctrl.entity.trajectory + gps_file_ctrl = ds_ctrl.get_datafile(DataType.TRAJECTORY) + + assert grav_file.uid == grav_file_ctrl.uid + assert ds_ctrl == grav_file_ctrl.get_parent() + assert grav_file.group == grav_file_ctrl.group + + assert gps_file.uid == gps_file_ctrl.uid + assert ds_ctrl == gps_file_ctrl.get_parent() + assert gps_file.group == gps_file_ctrl.group + + +def test_dataset_data_api(project: AirborneProject, hdf5file, gravdata, gpsdata): + prj_ctrl = AirborneProjectController(project) + flt_ctrl = prj_ctrl.get_child(project.flights[0].uid) + + gravfile = DataFile(DataType.GRAVITY, datetime.now(), + Path('tests/sample_gravity.csv')) + gpsfile = DataFile(DataType.TRAJECTORY, datetime.now(), + Path('tests/sample_trajectory.txt'), column_format='hms') + + dataset = DataSet(gravfile, gpsfile) + + HDF5Manager.save_data(gravdata, gravfile, hdf5file) + HDF5Manager.save_data(gpsdata, gpsfile, hdf5file) + + dataset_ctrl = DataSetController(dataset, prj_ctrl, flt_ctrl) + + gravity_frame = HDF5Manager.load_data(gravfile, hdf5file) + assert gravity_frame.equals(dataset_ctrl.gravity) + + trajectory_frame = HDF5Manager.load_data(gpsfile, hdf5file) + assert trajectory_frame.equals(dataset_ctrl.trajectory) + + assert dataset_ctrl.dataframe() is not None + expected: DataFrame = pd.concat([gravdata, gpsdata], axis=1, sort=True) + expected_cols = [col for col in expected] + + assert expected.equals(dataset_ctrl.dataframe()) + assert set(expected_cols) == set(dataset_ctrl.columns) + + series_model = dataset_ctrl.series_model + assert isinstance(series_model, QStandardItemModel) + assert len(expected_cols) == series_model.rowCount() + + for i in range(series_model.rowCount()): + item: QStandardItem = series_model.item(i, 0) + col = item.data(Qt.DisplayRole) + series = item.data(Qt.UserRole) + + assert expected[col].equals(series) + diff --git a/tests/test_dialogs.py b/tests/test_dialogs.py new file mode 100644 index 0000000..1b3c42d --- /dev/null +++ b/tests/test_dialogs.py @@ -0,0 +1,383 @@ +# -*- coding: utf-8 -*- +from datetime import datetime, date +from pathlib import Path + +import pytest + + +import PyQt5.QtTest as QtTest +from PyQt5.QtCore import Qt, QRegExp +from PyQt5.QtGui import QValidator, QRegExpValidator, QIntValidator +from PyQt5.QtTest import QTest +from PyQt5.QtWidgets import (QDialogButtonBox, QDialog, QFormLayout, QLineEdit, QLabel, QVBoxLayout, QDateTimeEdit, + QHBoxLayout, QPushButton) + +from dgp.core.models.dataset import DataSet +from dgp.core.controllers.flight_controller import FlightController +from dgp.core.models.flight import Flight +from dgp.core.controllers.project_controllers import AirborneProjectController +from dgp.core.models.project import AirborneProject +from dgp.core.types.enumerations import DataType +from dgp.gui.dialogs.add_gravimeter_dialog import AddGravimeterDialog +from dgp.gui.dialogs.add_flight_dialog import AddFlightDialog +from dgp.gui.dialogs.data_import_dialog import DataImportDialog +from dgp.gui.dialogs.create_project_dialog import CreateProjectDialog +from dgp.gui.dialogs.dialog_mixins import FormValidator +from dgp.gui.dialogs.custom_validators import FileExistsValidator, DirectoryValidator + + +@pytest.fixture +def airborne_prj(tmpdir): + project = AirborneProject(name="AirborneProject", path=Path(tmpdir)) + prj_ctrl = AirborneProjectController(project) + return project, prj_ctrl + + +class TestDialogs: + def test_create_project_dialog(self, tmpdir): + dlg = CreateProjectDialog() + accept_spy = QtTest.QSignalSpy(dlg.accepted) + _name = "Test Project" + _notes = "Notes on the Test Project" + _path = Path(tmpdir) + + # Test field validation + assert str(Path().home().joinpath('Desktop')) == dlg.prj_dir.text() + _invld_style = 'QLabel { color: red; }' + assert not dlg.validate() + assert dlg.accept() is None + assert _invld_style == dlg.label_name.styleSheet() + dlg.prj_name.setText("TestProject") + + dlg.prj_name.setText("") + QTest.keyClicks(dlg.prj_name, _name) + assert _name == dlg.prj_name.text() + + dlg.prj_dir.setText(str(_path.absolute())) + assert str(_path) == dlg.prj_dir.text() + + QTest.keyClicks(dlg.qpte_notes, _notes) + assert _notes == dlg.qpte_notes.toPlainText() + + # QTest.mouseClick(dlg.btn_create, Qt.LeftButton) + dlg.accept() + assert 1 == len(accept_spy) + + assert isinstance(dlg.project, AirborneProject) + assert _path.joinpath("TestProject") == dlg.project.path + assert dlg.project.name == "".join(_name.split(' ')) + assert dlg.project.description == _notes + + def test_add_flight_dialog(self, airborne_prj): + project, project_ctrl = airborne_prj + dlg = AddFlightDialog(project_ctrl) + spy = QtTest.QSignalSpy(dlg.accepted) + assert spy.isValid() + assert 0 == len(spy) + assert dlg.accept() is None + + _name = "Flight-1" + _notes = "Notes for Flight-1" + + assert datetime.today() == dlg.qde_flight_date.date() + QTest.keyClicks(dlg.qle_flight_name, _name) + QTest.keyClicks(dlg.qte_notes, _notes) + + assert _name == dlg.qle_flight_name.text() + assert _notes == dlg.qte_notes.toPlainText() + + QTest.mouseClick(dlg.qdbb_dialog_btns.button(QDialogButtonBox.Ok), Qt.LeftButton) + # dlg.accept() + + assert 1 == len(spy) + assert 1 == len(project.flights) + assert isinstance(project.flights[0], Flight) + assert _name == project.flights[0].name + assert _notes == project.flights[0].notes + assert date.today() == project.flights[0].date + + def test_edit_flight_dialog(self, airborne_prj): + """Test Flight Dialog to edit an existing flight""" + project, project_ctrl = airborne_prj # type: AirborneProject, AirborneProjectController + + _name = "Flt-1" + _date = datetime(2018, 5, 15) + _notes = "Notes on flight 1" + flt = Flight(_name, date=_date, notes=_notes, sequence=0, duration=6) + + flt_ctrl = project_ctrl.add_child(flt) + + dlg = AddFlightDialog.from_existing(flt_ctrl, project_ctrl) + + assert _name == dlg.qle_flight_name.text() + assert _date == dlg.qde_flight_date.date() + assert _notes == dlg.qte_notes.toPlainText() + + # Test renaming flight through dialog + dlg.qle_flight_name.clear() + QTest.keyClicks(dlg.qle_flight_name, "Flt-2") + QTest.mouseClick(dlg.qdbb_dialog_btns.button(QDialogButtonBox.Ok), Qt.LeftButton) + # Note: use dlg.accept() for debugging as it will correctly generate a stack trace + # dlg.accept() + assert "Flt-2" == flt.name + + def test_import_data_dialog(self, airborne_prj, tmpdir): + _path = Path(tmpdir).joinpath('source') + _path.mkdir() + project, project_ctrl = airborne_prj # type: AirborneProject, AirborneProjectController + _f1_date = datetime(2018, 3, 15) + flt1 = Flight("Flight1", _f1_date) + flt1.datasets.append(DataSet()) + flt2 = Flight("Flight2") + fc1 = project_ctrl.add_child(flt1) # type: FlightController + fc2 = project_ctrl.add_child(flt2) + + dlg = DataImportDialog(project_ctrl, datatype=DataType.GRAVITY) + load_spy = QtTest.QSignalSpy(dlg.load) + + # test set_initial_flight + dlg.set_initial_flight(fc1) + assert flt1.name == dlg.qcb_flight.currentText() + + fc_clone = dlg.qcb_flight.model().item(dlg.qcb_flight.currentIndex()) + assert isinstance(fc_clone, FlightController) + assert fc1 != fc_clone + assert fc1 == dlg.flight + + assert dlg.file_path is None + _srcpath = _path.joinpath('testfile.dat') + QTest.keyClicks(dlg.qle_filepath, str(_srcpath)) + assert _srcpath == dlg.file_path + + dlg.qchb_grav_interp.setChecked(True) + assert dlg.qchb_grav_interp.isChecked() + _grav_map = dlg._params_map[DataType.GRAVITY] + assert _grav_map['columns']() is None + assert _grav_map['interp']() + assert not _grav_map['skiprows']() + + _traj_map = dlg._params_map[DataType.TRAJECTORY] + _time_col_map = { + 'hms': ['mdy', 'hms', 'lat', 'long', 'ell_ht'], + 'sow': ['week', 'sow', 'lat', 'long', 'ell_ht'], + 'serial': ['datenum', 'lat', 'long', 'ell_ht'] + } + for i, expected in enumerate(['hms', 'sow', 'serial']): + dlg.qcb_traj_timeformat.setCurrentIndex(i) + assert expected == _traj_map['timeformat']() + assert _time_col_map[expected] == _traj_map['columns']() + + assert not dlg.qchb_traj_hasheader.isChecked() + assert 0 == _traj_map['skiprows']() + dlg.qchb_traj_hasheader.setChecked(True) + assert 1 == _traj_map['skiprows']() + assert dlg.qchb_traj_isutc.isChecked() + assert _traj_map['is_utc']() + dlg.qchb_traj_isutc.setChecked(False) + assert not _traj_map['is_utc']() + + # Test emission of DataFile on _load_file + # TODO: Fix this, need an actual file to test loading + # assert dlg.datatype == DataType.GRAVITY + # dlg.qcb_flight.setCurrentIndex(0) + # dlg.qcb_dataset.setCurrentIndex(0) + # dlg.accept() + # assert 1 == len(load_spy) + # # assert 1 == len(flt1.data_files) + # # assert _srcpath == flt1.data_files[0].source_path + # + # load_args = load_spy[0] + # assert isinstance(load_args, list) + # file = load_args[0] + # params = load_args[1] + # assert isinstance(file, DataFile) + # assert isinstance(params, dict) + + # Test date setting from flight + assert datetime.today() == dlg.qde_date.date() + dlg._set_date() + assert _f1_date == dlg.qde_date.date() + + # Create the test DataFile to permit accept() + _srcpath.touch() + dlg.qchb_copy_file.setChecked(True) + QTest.mouseClick(dlg.qdbb_buttons.button(QDialogButtonBox.Ok), Qt.LeftButton) + # dlg.accept() + assert 1 == len(load_spy) + assert project_ctrl.path.joinpath('testfile.dat').exists() + + def test_add_gravimeter_dialog(self, airborne_prj): + project, project_ctrl = airborne_prj # type: AirborneProject, AirborneProjectController + _basepath = project_ctrl.path.joinpath('source').resolve() + _basepath.mkdir() + + dlg = AddGravimeterDialog(project_ctrl) + assert dlg.config_path is None + assert dlg.accept() is None + + _ini_path = Path('tests/at1m.ini').resolve() + QTest.keyClicks(dlg.qle_config_path, str(_ini_path)) + assert _ini_path == dlg.config_path + + # Test exclusion of invalid file extensions + _bad_ini = _basepath.joinpath("meter.bad").resolve() + _bad_ini.touch() + dlg.qle_config_path.setText(str(_bad_ini)) + assert dlg.config_path is None + assert dlg._preview_config() is None + + _name = "AT1A-11" + assert "AT1A" == dlg.get_sensor_type() + QTest.keyClicks(dlg.qle_serial, str(11)) + assert _name == dlg.qle_name.text() + + assert 0 == len(project.gravimeters) + dlg.qle_config_path.setText(str(_ini_path.resolve())) + dlg.accept() + assert 1 == len(project.gravimeters) + assert _name == project.gravimeters[0].name + + dlg2 = AddGravimeterDialog(project_ctrl) + dlg2.qle_serial.setText(str(12)) + dlg2.accept() + assert 2 == len(project.gravimeters) + assert "AT1A-12" == project.gravimeters[1].name + + +class ValidatedDialog(QDialog, FormValidator): + def __init__(self, parent=None): + super().__init__(parent=parent, flags=Qt.Dialog) + self._form1 = QFormLayout() + self._form2 = QFormLayout() + self.vlayout = QVBoxLayout() + self.vlayout.addChildLayout(self._form1) + self.vlayout.addChildLayout(self._form2) + self.setLayout(self.vlayout) + + # Form 1 Validated Input + exp = QRegExp(".{5,35}") + self.validator1 = QRegExpValidator(exp) + self.label1 = QLabel("Row0") + self.lineedit1 = QLineEdit() + self.lineedit1.setValidator(self.validator1) + self._form1.addRow(self.label1, self.lineedit1) + + # Form 2 Validated and Unvalidated Input Lines + self.validator2 = QRegExpValidator(exp) + self.label2 = QLabel("Row1") + self.lineedit2 = QLineEdit() + self.lineedit2.setValidator(self.validator2) + self._form2.addRow(self.label2, self.lineedit2) + + # Form 2 Unvalidated Line Edit + self.label3 = QLabel("Row2 (Not validated)") + self.lineedit3 = QLineEdit() + self._form2.addRow(self.label3, self.lineedit3) + + # DateTime Edit widget + self.label4 = QLabel("Date") + self.datetimeedit = QDateTimeEdit(datetime.today()) + + # Nested layout widget + self.nested_label = QLabel("Nested input") + self.nested_hbox = QHBoxLayout() + self.nested_lineedit = QLineEdit() + self.nested_validator = QRegExpValidator(exp) + self.nested_button = QPushButton("Button") + self.nested_hbox.addWidget(self.nested_lineedit) + self.nested_hbox.addWidget(self.nested_button) + self._form2.addRow(self.nested_label, self.nested_hbox) + + self.nested_vbox = QVBoxLayout() + self.nested_label2 = QLabel("Nested v input") + self.nested_lineedit2 = QLineEdit() + self.nested_validator2 = QRegExpValidator(exp) + self.nested_lineedit2.setValidator(self.nested_validator2) + self.nested_button2 = QPushButton("Button2") + self.nested_vbox.addWidget(self.nested_button2) + self.nested_vbox.addWidget(self.nested_lineedit2) + + @property + def validation_targets(self): + return [self._form1, self._form2] + + +class TestDialogMixins: + def test_dialog_form_validator(self): + """Test the FormValidator mixin class, which scans QFormLayout label/field pairs + and ensures that any set QValidators pass. + + Labels should be set to RED if their corresponding field is invalid + """ + dlg = ValidatedDialog() + assert issubclass(ValidatedDialog, FormValidator) + assert isinstance(dlg.validation_targets[0], QFormLayout) + + assert not dlg.lineedit1.hasAcceptableInput() + dlg.lineedit1.setText("Has 5 characters or more") + assert dlg.lineedit1.hasAcceptableInput() + dlg.lineedit1.setText("x"*36) + assert not dlg.lineedit1.hasAcceptableInput() + + assert not dlg.validate() + assert FormValidator.ERR_STYLE == dlg.label1.styleSheet() + + dlg.lineedit1.setText("This is acceptable") + dlg.lineedit2.setText("This is also OK") + assert dlg.lineedit1.hasAcceptableInput() + assert dlg.validate() + assert "" == dlg.label1.styleSheet() + + dlg.lineedit1.setText("") + assert not dlg.validate() + + # Test adding an input mask to lineedit3 + dlg.lineedit1.setText("Something valid") + dlg.lineedit3.setText("") + dlg.lineedit3.setInputMask("AAA-AAA") # Require 6 alphabetical chars separated by '-' + assert not dlg.validate() + assert dlg.label3.toolTip() == "Invalid Input: input must conform to mask: AAA-AAA" + + QTest.keyClicks(dlg.lineedit3, "ABCDEF") + assert dlg.validate() + + # What about nested layouts (e.g. where a QHboxLayout is used within a form field) + dlg.nested_lineedit.setValidator(dlg.nested_validator) + assert not dlg.validate() + dlg.nested_lineedit.setText("Valid String") + assert dlg.validate() + + dlg._form2.addRow(dlg.nested_label2, dlg.nested_vbox) + assert not dlg.validate() + + dlg.nested_lineedit2.setText("Valid String") + assert dlg.validate() + + int_validator = QIntValidator(25, 100) + dlg.nested_lineedit2.setValidator(int_validator) + assert not dlg.validate() + dlg.nested_lineedit2.setText("26") + assert dlg.validate() + + def test_file_exists_validator(self): + line_edit = QLineEdit() + validator = FileExistsValidator() + line_edit.setValidator(validator) + + assert (QValidator.Acceptable, "tests/at1m.ini", 0) == validator.validate("tests/at1m.ini", 0) + assert (QValidator.Intermediate, "tests", 0) == validator.validate("tests", 0) + assert (QValidator.Invalid, 123, 0) == validator.validate(123, 0) + + def test_directory_validator(self): + exist_validator = DirectoryValidator(exist_ok=True) + noexist_validator = DirectoryValidator(exist_ok=False) + + _valid_path = "tests" + _invalid_path = "tests/at1m.ini" + assert QValidator.Acceptable == exist_validator.validate(_valid_path, 0)[0] + assert QValidator.Invalid == exist_validator.validate(123, 0)[0] + assert QValidator.Invalid == exist_validator.validate(_invalid_path, 0)[0] + assert QValidator.Intermediate == noexist_validator.validate(_valid_path, 0)[0] + assert QValidator.Intermediate == exist_validator.validate(_valid_path + "/nonexistent", 0)[0] + + diff --git a/tests/test_eotvos.py b/tests/test_eotvos.py deleted file mode 100644 index 6f48bdd..0000000 --- a/tests/test_eotvos.py +++ /dev/null @@ -1,16 +0,0 @@ -# coding: utf-8 - -import os -import unittest -import numpy as np - -from .context import dgp -import dgp.lib.eotvos as eotvos - - -class TestEotvos(unittest.TestCase): - def setUp(self): - pass - - def test_derivative(self): - pass diff --git a/tests/test_etc.py b/tests/test_etc.py new file mode 100644 index 0000000..cf8f0cd --- /dev/null +++ b/tests/test_etc.py @@ -0,0 +1,135 @@ +import unittest +import numpy as np +import pandas as pd + +from dgp.lib.etc import align_frames + + +class TestAlignOps(unittest.TestCase): + # TODO: Test with another DatetimeIndex + # TODO: Test with other interpolation methods + # TODO: Tests for interp_only + + def test_align_args(self): + frame1 = pd.Series(np.arange(10)) + index1 = pd.Timestamp('2018-01-29 15:19:28.000') + \ + pd.to_timedelta(np.arange(10), unit='s') + frame1.index = index1 + + frame2 = pd.Series(np.arange(10, 20)) + index2 = pd.Timestamp('2018-01-29 15:00:28.002') + \ + pd.to_timedelta(np.arange(10), unit='s') + frame2.index = index2 + + msg = 'Invalid value for align_to parameter: invalid' + with self.assertRaises(ValueError, msg=msg): + align_frames(frame1, frame2, align_to='invalid') + + msg = 'Frames do not overlap' + with self.assertRaises(ValueError, msg=msg): + align_frames(frame1, frame2) + + frame1 = pd.Series(np.arange(10)) + index1 = pd.Timestamp('2018-01-29 15:00:28.000') + \ + pd.to_timedelta(np.arange(10), unit='s') + frame1.index = index1 + + frame2 = pd.Series(np.arange(10, 20)) + index2 = pd.Timestamp('2018-01-29 15:19:28.002') + \ + pd.to_timedelta(np.arange(10), unit='s') + frame2.index = index2 + + msg = 'Frames do not overlap' + with self.assertRaises(ValueError, msg=msg): + align_frames(frame1, frame2) + + def test_align_crop(self): + frame1 = pd.Series(np.arange(10)) + index1 = pd.Timestamp('2018-01-29 15:19:30.000') + \ + pd.to_timedelta(np.arange(10), unit='s') + frame1.index = index1 + + frame2 = pd.Series(np.arange(10, 20)) + index2 = pd.Timestamp('2018-01-29 15:19:28.002') + \ + pd.to_timedelta(np.arange(10), unit='s') + frame2.index = index2 + + # align left + aframe1, aframe2 = align_frames(frame1, frame2, align_to='left') + self.assertTrue(aframe1.index.equals(aframe2.index)) + + # align right + aframe1, aframe2 = align_frames(frame1, frame2, align_to='right') + self.assertTrue(aframe1.index.equals(aframe2.index)) + + def test_align_and_crop_series(self): + frame1 = pd.Series(np.arange(10)) + index1 = pd.Timestamp('2018-01-29 15:19:28.000') + \ + pd.to_timedelta(np.arange(10), unit='s') + frame1.index = index1 + + frame2 = pd.Series(np.arange(10, 20)) + index2 = pd.Timestamp('2018-01-29 15:19:28.002') + \ + pd.to_timedelta(np.arange(10), unit='s') + frame2.index = index2 + + # align left + aframe1, aframe2 = align_frames(frame1, frame2, align_to='left') + self.assertTrue(aframe1.index.equals(aframe2.index)) + + # align right + aframe1, aframe2 = align_frames(frame1, frame2, align_to='right') + self.assertTrue(aframe1.index.equals(aframe2.index)) + + def test_align_and_crop_df(self): + frame1 = pd.DataFrame(np.array([np.arange(10), np.arange(10, 20)]).T) + index1 = pd.Timestamp('2018-01-29 15:19:28.000') + \ + pd.to_timedelta(np.arange(10), unit='s') + frame1.index = index1 + + frame2 = pd.DataFrame(np.array([np.arange(20,30), np.arange(30, 40)]).T) + index2 = pd.Timestamp('2018-01-29 15:19:28.002') + \ + pd.to_timedelta(np.arange(10), unit='s') + frame2.index = index2 + + # align left + aframe1, aframe2 = align_frames(frame1, frame2, align_to='left') + self.assertFalse(aframe1.index.empty) + self.assertFalse(aframe2.index.empty) + self.assertTrue(aframe1.index.equals(aframe2.index)) + + # align right + aframe1, aframe2 = align_frames(frame1, frame2, align_to='right') + self.assertFalse(aframe1.index.empty) + self.assertFalse(aframe2.index.empty) + self.assertTrue(aframe1.index.equals(aframe2.index)) + + def test_align_and_crop_df_fill(self): + frame1 = pd.DataFrame(np.array([np.arange(10), np.arange(10, 20)]).T) + frame1.columns = ['A', 'B'] + index1 = pd.Timestamp('2018-01-29 15:19:28.000') + \ + pd.to_timedelta(np.arange(10), unit='s') + frame1.index = index1 + + frame2 = pd.DataFrame(np.array([np.arange(20, 30), np.arange(30, 40)]).T) + frame2.columns = ['C', 'D'] + index2 = pd.Timestamp('2018-01-29 15:19:28.002') + \ + pd.to_timedelta(np.arange(10), unit='s') + frame2.index = index2 + + aframe1, aframe2 = align_frames(frame1, frame2, fill={'B': 'bfill'}) + self.assertTrue(aframe1['B'].equals(frame1['B'].iloc[1:].astype(float))) + + left, right = frame1.align(frame2, axis=0, copy=True) + left = left.fillna(method='bfill') + left = left.reindex(frame2.index).dropna() + aframe1, aframe2 = align_frames(frame1, frame2, align_to='right', + fill={'B': 'bfill'}) + self.assertTrue(aframe1['B'].equals(left['B'])) + + left, right = frame1.align(frame2, axis=0, copy=True) + left = left.fillna(value=0) + left = left.reindex(frame2.index).dropna() + aframe1, aframe2 = align_frames(frame1, frame2, align_to='right', + fill={'B': 0}) + self.assertTrue(aframe1['B'].equals(left['B'])) diff --git a/tests/test_gravity_ingestor.py b/tests/test_gravity_ingestor.py index a9abd60..7fe6a44 100644 --- a/tests/test_gravity_ingestor.py +++ b/tests/test_gravity_ingestor.py @@ -6,7 +6,6 @@ import numpy as np import datetime -from .context import dgp from dgp.lib import gravity_ingestor as gi @@ -27,7 +26,7 @@ def test_read_bitfield_options(self): # test num columns specified less than num bits columns = ['test1', 'test2', 'test3', 'test4'] unpacked = gi._extract_bits(status, columns=columns, as_bool=True) - array = np.array([[1, 0, 1, 0],]*5) + array = np.array([[1, 0, 1, 0],] * 5) expect = pd.DataFrame(data=array, columns=columns).astype(np.bool_) self.assertTrue(unpacked.equals(expect)) @@ -59,31 +58,31 @@ def test_import_at1a_no_fill_nans(self): df = gi.read_at1a(os.path.abspath('tests/sample_gravity.csv'), fill_with_nans=False) self.assertEqual(df.shape, (9, 26)) - fields = ['gravity', 'long', 'cross', 'beam', 'temp', 'status', 'pressure', 'Etemp', 'GPSweek', 'GPSweekseconds'] + fields = ['gravity', 'long_accel', 'cross_accel', 'beam', 'temp', 'status', 'pressure', 'Etemp', 'GPSweek', 'GPSweekseconds'] # Test and verify an arbitrary line of data against the same line in the pandas DataFrame line5 = [10061.171360, -0.026226, -0.094891, -0.093803, 62.253987, 21061, 39.690004, 52.263138, 1959, 219697.800] sample_line = dict(zip(fields, line5)) self.assertEqual(df.gravity[4], sample_line['gravity']) - self.assertEqual(df.long[4], sample_line['long']) + self.assertEqual(df.long_accel[4], sample_line['long_accel']) self.assertFalse(df.gps_sync[8]) def test_import_at1a_fill_nans(self): df = gi.read_at1a(os.path.abspath('tests/sample_gravity.csv')) - self.assertEqual(df.shape, (9, 26)) + self.assertEqual(df.shape, (10, 26)) - fields = ['gravity', 'long', 'cross', 'beam', 'temp', 'status', 'pressure', 'Etemp', 'GPSweek', 'GPSweekseconds'] + fields = ['gravity', 'long_accel', 'cross', 'beam', 'temp', 'status', 'pressure', 'Etemp', 'GPSweek', 'GPSweekseconds'] # Test and verify an arbitrary line of data against the same line in the pandas DataFrame line5 = [10061.171360, -0.026226, -0.094891, -0.093803, 62.253987, 21061, 39.690004, 52.263138, 1959, 219697.800] sample_line = dict(zip(fields, line5)) self.assertEqual(df.gravity[5], sample_line['gravity']) - self.assertEqual(df.long[5], sample_line['long']) + self.assertEqual(df.long_accel[5], sample_line['long_accel']) self.assertTrue(df.iloc[[2]].isnull().values.all()) def test_import_at1a_interp(self): df = gi.read_at1a(os.path.abspath('tests/sample_gravity.csv'), interp=True) - self.assertEqual(df.shape, (9, 26)) + self.assertEqual(df.shape, (10, 26)) # check whether NaNs were interpolated for numeric type fields self.assertTrue(df.iloc[[2]].notnull().values.any()) diff --git a/tests/test_gui_main.py b/tests/test_gui_main.py new file mode 100644 index 0000000..845a503 --- /dev/null +++ b/tests/test_gui_main.py @@ -0,0 +1,184 @@ +# -*- coding: utf-8 -*- + +# Test gui/main.py +import logging +from pathlib import Path + +import pytest +from PyQt5.QtCore import Qt +from PyQt5.QtTest import QSignalSpy, QTest +from PyQt5.QtWidgets import QMainWindow, QProgressDialog, QPushButton + +from dgp.core.oid import OID +from dgp.core.models.project import AirborneProject +from dgp.core.controllers.project_treemodel import ProjectTreeModel +from dgp.core.controllers.flight_controller import FlightController +from dgp.core.controllers.project_controllers import AirborneProjectController +from dgp.gui.main import MainWindow +from dgp.gui.dialogs.create_project_dialog import CreateProjectDialog +from dgp.gui.utils import ProgressEvent + + +@pytest.fixture +def window(project) -> MainWindow: + window = MainWindow() + window.add_project(project) + yield window + window.close() + + +def test_MainWindow_load(window, project): + assert isinstance(window, QMainWindow) + assert not window.isVisible() + + window.load(project) + assert window.isVisible() + assert not window.isWindowModified() + + window.close() + assert not window.isVisible() + + +def test_MainWindow_tab_open_requested(project, window): + assert isinstance(window.model, ProjectTreeModel) + + tab_open_spy = QSignalSpy(window.model.tabOpenRequested) + assert 0 == len(tab_open_spy) + assert 0 == window.workspace.count() + + flt_ctrl = window.model.active_project.get_child(project.flights[0].uid) + + assert isinstance(flt_ctrl, FlightController) + assert window.workspace.get_tab(flt_ctrl.uid) is None + + window.model.item_activated(flt_ctrl.index()) + assert 1 == len(tab_open_spy) + assert 1 == window.workspace.count() + + window.model.item_activated(flt_ctrl.index()) + assert 2 == len(tab_open_spy) + assert 1 == window.workspace.count() + + +def test_MainWindow_project_mutated(window: MainWindow): + assert not window.isWindowModified() + window.model.projectMutated.emit() + assert window.isWindowModified() + window.save_projects() + assert not window.isWindowModified() + + +def test_MainWindow_set_logging_level(window: MainWindow): + # Test UI combo-box widget to change/set logging level + assert logging.DEBUG == window.log.level + + index_level_map = {0: logging.DEBUG, + 1: logging.INFO, + 2: logging.WARNING, + 3: logging.ERROR, + 4: logging.CRITICAL} + + for index, level in index_level_map.items(): + window.combo_console_verbosity.setCurrentIndex(index) + assert level == window.log.level + + +def test_MainWindow_new_project_dialog(window: MainWindow, tmpdir): + assert 1 == window.model.rowCount() + dest = Path(tmpdir) + dest_str = str(dest.absolute().resolve()) + + dlg: CreateProjectDialog = window.new_project_dialog() + projectCreated_spy = QSignalSpy(dlg.sigProjectCreated) + dlg.prj_name.setText("TestNewProject") + dlg.prj_dir.setText(dest_str) + dlg.accept() + + assert 1 == len(projectCreated_spy) + assert 2 == window.model.rowCount() + + prj_dir = dest.joinpath(dlg.project.name) + assert prj_dir.exists() + + +def test_MainWindow_open_project_dialog(window: MainWindow, project_factory, tmpdir): + prj2: AirborneProject = project_factory("Proj2", tmpdir, dataset=False) + prj2_ctrl = AirborneProjectController(prj2) + prj2_ctrl.save() + prj2_ctrl.hdfpath.touch(exist_ok=True) + + assert window.model.active_project.path != prj2_ctrl.path + assert 1 == window.model.rowCount() + + window.open_project(path=prj2.path, prompt=False) + assert 2 == window.model.rowCount() + + # Try to open an already open project + window.open_project(path=prj2.path, prompt=False) + assert 2 == window.model.rowCount() + + with pytest.raises(FileNotFoundError): + window.open_project(path=Path(tmpdir), prompt=False) + assert 2 == window.model.rowCount() + + +def test_MainWindow_progress_event_handler(project, window): + model: ProjectTreeModel = window.model + progressEventRequested_spy = QSignalSpy(model.progressNotificationRequested) + + flt_ctrl = window.model.active_project.get_child(project.flights[0].uid) + + prog_event = ProgressEvent(flt_ctrl.uid, label="Loading Data Set") + assert flt_ctrl.uid == prog_event.uid + assert not prog_event.completed + assert 0 == prog_event.value + + model.progressNotificationRequested.emit(prog_event) + assert 1 == len(progressEventRequested_spy) + assert 1 == len(window._progress_events) + assert flt_ctrl.uid in window._progress_events + dlg = window._progress_events[flt_ctrl.uid] + assert isinstance(dlg, QProgressDialog) + assert dlg.isVisible() + assert prog_event.label == dlg.labelText() + assert 1 == dlg.value() + + prog_event2 = ProgressEvent(flt_ctrl.uid, label="Loading Data Set 2", + start=0, stop=100) + prog_event2.value = 35 + model.progressNotificationRequested.emit(prog_event2) + assert 2 == len(progressEventRequested_spy) + + assert dlg == window._progress_events[flt_ctrl.uid] + assert prog_event2.label == dlg.labelText() + assert prog_event2.value == dlg.value() + + prog_event2.value = 100 + assert prog_event2.completed + model.progressNotificationRequested.emit(prog_event2) + assert not dlg.isVisible() + + assert 0 == len(window._progress_events) + + model.progressNotificationRequested.emit(prog_event) + assert 1 == len(window._progress_events) + + # Test progress bar with cancellation callback slot + received = False + + def _receiver(): + nonlocal received + received = True + + _uid = OID() + prog_event_callback = ProgressEvent(_uid, "Testing Callback", receiver=_receiver) + model.progressNotificationRequested.emit(prog_event_callback) + + dlg: QProgressDialog = window._progress_events[_uid] + cancel = QPushButton("Cancel") + dlg.setCancelButton(cancel) + assert dlg.isVisible() + QTest.mouseClick(cancel, Qt.LeftButton) + + assert received + diff --git a/tests/test_gui_utils.py b/tests/test_gui_utils.py new file mode 100644 index 0000000..cd3cedb --- /dev/null +++ b/tests/test_gui_utils.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +from pathlib import Path + +import dgp.gui.utils as utils + + diff --git a/tests/test_hdf5store.py b/tests/test_hdf5store.py new file mode 100644 index 0000000..351e937 --- /dev/null +++ b/tests/test_hdf5store.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- + +from datetime import datetime +from pathlib import Path + +import pytest +from pandas import DataFrame + +from dgp.core import DataType +from dgp.core.models.flight import Flight +from dgp.core.models.datafile import DataFile +from dgp.core.hdf5_manager import HDF5Manager + +HDF5_FILE = "test.hdf5" + + +def test_datastore_save_load(gravdata: DataFrame, hdf5file: Path): + flt = Flight('Test-Flight') + datafile = DataFile(DataType.GRAVITY, datetime.now(), Path('tests/test.dat')) + assert HDF5Manager.save_data(gravdata, datafile, path=hdf5file) + loaded = HDF5Manager.load_data(datafile, path=hdf5file) + assert gravdata.equals(loaded) + + # Test loading from file (clear cache) + HDF5Manager.clear_cache() + loaded_nocache = HDF5Manager.load_data(datafile, path=hdf5file) + assert gravdata.equals(loaded_nocache) + + HDF5Manager.clear_cache() + with pytest.raises(FileNotFoundError): + HDF5Manager.load_data(datafile, path=Path('.nonexistent.hdf5')) + + empty_datafile = DataFile(DataType.TRAJECTORY, datetime.now(), + Path('tests/test.dat')) + with pytest.raises(KeyError): + HDF5Manager.load_data(empty_datafile, path=hdf5file) + + +def test_ds_metadata(gravdata: DataFrame, hdf5file: Path): + flt = Flight('TestMetadataFlight') + datafile = DataFile(DataType.GRAVITY, datetime.now(), source_path=Path('./test.dat')) + empty_datafile = DataFile(DataType.TRAJECTORY, datetime.now(), + Path('tests/test.dat')) + HDF5Manager.save_data(gravdata, datafile, path=hdf5file) + + attr_key = 'test_attr' + attr_value = {'a': 'complex', 'v': 'value'} + + # Assert True result first + assert HDF5Manager._set_node_attr(datafile.nodepath, attr_key, attr_value, hdf5file) + # Validate value was stored, and can be retrieved + result = HDF5Manager._get_node_attr(datafile.nodepath, attr_key, hdf5file) + assert attr_value == result + + # Test retrieval of keys for a specified node + assert attr_key in HDF5Manager.list_node_attrs(datafile.nodepath, hdf5file) + + with pytest.raises(KeyError): + HDF5Manager._set_node_attr('/invalid/node/path', attr_key, attr_value, + hdf5file) + + with pytest.raises(KeyError): + HDF5Manager.list_node_attrs(empty_datafile.nodepath, hdf5file) + + assert HDF5Manager._get_node_attr(empty_datafile.nodepath, 'test_attr', + hdf5file) is None diff --git a/tests/test_loader.py b/tests/test_loader.py new file mode 100644 index 0000000..3e8b245 --- /dev/null +++ b/tests/test_loader.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- + +# TODO: Tests for new file loader method in core/controllers/project_controller::FileLoader +from pathlib import Path + +import pytest +from PyQt5.QtTest import QSignalSpy +from pandas import DataFrame + + +from dgp.core.file_loader import FileLoader + +TEST_FILE_GRAV = 'tests/sample_gravity.csv' + + +def mock_loader(*args, **kwargs): + # return args, kwargs + return DataFrame() + + +def mock_failing_loader(*args, **kwargs): + raise FileNotFoundError + + +def test_load_mock(qt_app): + loader = FileLoader(Path(TEST_FILE_GRAV), mock_loader, qt_app) + spy_complete = QSignalSpy(loader.loaded) + spy_error = QSignalSpy(loader.error) + + assert 0 == len(spy_complete) + assert 0 == len(spy_error) + assert not loader.isRunning() + + loader.run() + + assert 1 == len(spy_complete) + assert 0 == len(spy_error) + + +def test_load_failure(qt_app): + called = False + + def _error_handler(exception: Exception): + assert isinstance(exception, Exception) + nonlocal called + called = True + + loader = FileLoader(Path(), mock_failing_loader, qt_app) + loader.error.connect(_error_handler) + spy_err = QSignalSpy(loader.error) + assert 0 == len(spy_err) + + loader.run() + assert 1 == len(spy_err) + assert called diff --git a/tests/test_models.py b/tests/test_models.py new file mode 100644 index 0000000..fd6ea74 --- /dev/null +++ b/tests/test_models.py @@ -0,0 +1,132 @@ +# -*- coding: utf-8 -*- + +""" +Unit tests for new Project/Flight data classes, including JSON +serialization/de-serialization +""" +import time +from datetime import datetime +from typing import Tuple +from uuid import uuid4 +from pathlib import Path + +import pytest +import pandas as pd + +from dgp.core import DataType +from dgp.core.models.project import AirborneProject +from dgp.core.hdf5_manager import HDF5Manager +from dgp.core.models.datafile import DataFile +from dgp.core.models.dataset import DataSet +from dgp.core.models import flight +from dgp.core.models.meter import Gravimeter + + +@pytest.fixture() +def make_flight(): + def _factory() -> Tuple[str, flight.Flight]: + name = str(uuid4().hex)[:12] + return name, flight.Flight(name) + + return _factory + + +def test_flight_actions(make_flight): + # TODO: Test adding/setting gravimeter + flt = flight.Flight('test_flight') + assert 'test_flight' == flt.name + + f1_name, f1 = make_flight() # type: flight.Flight + f2_name, f2 = make_flight() # type: flight.Flight + + assert f1_name == f1.name + assert f2_name == f2.name + + assert not f1.uid == f2.uid + + assert '' % (f1_name, f1.uid) == repr(f1) + + +def test_project_path(project: AirborneProject, tmpdir): + assert isinstance(project.path, Path) + new_path = Path(tmpdir).joinpath("new_prj_path") + project.path = new_path + assert new_path == project.path + + +def test_project_add_child(project: AirborneProject): + with pytest.raises(TypeError): + project.add_child(None) + + +def test_project_get_child(make_flight): + prj = AirborneProject(name="Project-2", path=Path('.')) + f1_name, f1 = make_flight() + f2_name, f2 = make_flight() + f3_name, f3 = make_flight() + prj.add_child(f1) + prj.add_child(f2) + prj.add_child(f3) + + assert f1 == prj.get_child(f1.uid) + assert f3 == prj.get_child(f3.uid) + assert not f2 == prj.get_child(f1.uid) + + with pytest.raises(IndexError): + fx = prj.get_child(str(uuid4().hex)) + + +def test_project_remove_child(make_flight): + prj = AirborneProject(name="Project-3", path=Path('.')) + f1_name, f1 = make_flight() + f2_name, f2 = make_flight() + f3_name, f3 = make_flight() + + prj.add_child(f1) + prj.add_child(f2) + + assert 2 == len(prj.flights) + assert f1 in prj.flights + assert f2 in prj.flights + assert f3 not in prj.flights + + assert not prj.remove_child(f3.uid) + assert prj.remove_child(f1.uid) + + assert f1 not in prj.flights + assert 1 == len(prj.flights) + + +def test_gravimeter(): + meter = Gravimeter("AT1A-13") + assert "AT1A" == meter.type + assert "AT1A-13" == meter.name + assert meter.config is None + config = meter.read_config(Path("tests/at1m.ini")) + assert isinstance(config, dict) + + with pytest.raises(FileNotFoundError): + config = meter.read_config(Path("tests/at1a-fake.ini")) + + assert {} == meter.read_config(Path("tests/sample_gravity.csv")) + + +def test_dataset(tmpdir): + path = Path(tmpdir).joinpath("test.hdf5") + df_grav = DataFile(DataType.GRAVITY, datetime.utcnow(), Path('gravity.dat')) + df_traj = DataFile(DataType.TRAJECTORY, datetime.utcnow(), Path('gps.dat')) + dataset = DataSet(df_grav, df_traj) + + assert df_grav == dataset.gravity + assert df_traj == dataset.trajectory + + frame_grav = pd.DataFrame([0, 1, 2]) + frame_traj = pd.DataFrame([7, 8, 9]) + + HDF5Manager.save_data(frame_grav, df_grav, path) + HDF5Manager.save_data(frame_traj, df_traj, path) + + expected_concat: pd.DataFrame = pd.concat([frame_grav, frame_traj]) + # assert expected_concat.equals(dataset.dataframe) + + diff --git a/tests/test_oid.py b/tests/test_oid.py new file mode 100644 index 0000000..188c8ef --- /dev/null +++ b/tests/test_oid.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +import pytest + +from dgp.core.oid import OID + + +def test_oid_equivalence(): + oid1 = OID('flt') + oid2 = OID('flt') + + assert not oid1 == oid2 + + oid2_clone = OID(tag="test", base_uuid=oid2.base_uuid) + assert oid2 == oid2_clone + assert "oid" == oid2_clone.group + assert "test" == oid2_clone.tag + + assert str(oid2.base_uuid) == oid2_clone + + assert not oid2 == dict(expect="Failure") diff --git a/tests/test_plots.py b/tests/test_plots.py new file mode 100644 index 0000000..44bf83d --- /dev/null +++ b/tests/test_plots.py @@ -0,0 +1,453 @@ +# -*- coding: utf-8 -*- +from datetime import datetime + +import pytest +import numpy as np +import pandas as pd +from PyQt5.QtCore import QObject +from PyQt5.QtTest import QSignalSpy +from PyQt5.QtWidgets import QWidget +from pyqtgraph import GraphicsLayout, PlotItem, PlotDataItem, LegendItem + +from dgp.core.oid import OID +from dgp.gui.plotting.backends import GridPlotWidget, Axis, AxisFormatter +from dgp.gui.plotting.plotters import LineSelectPlot +from dgp.gui.plotting.helpers import PolyAxis, LinearSegment, LinearSegmentGroup, LineUpdate + +"""Test/Develop Plots using PyQtGraph for high-performance user-interactive +plots within the application. + +""" + + +@pytest.fixture +def gravity(gravdata) -> pd.Series: + return gravdata['gravity'] + + +def test_GridPlotWidget_init(): + gpw = GridPlotWidget(rows=2) + assert isinstance(gpw, QWidget) + assert isinstance(gpw, QObject) + + assert isinstance(gpw.centralWidget, GraphicsLayout) + + assert 2 == gpw.rows + assert 1 == gpw.cols + + assert isinstance(gpw.get_plot(row=0), PlotItem) + assert isinstance(gpw.get_plot(row=1), PlotItem) + assert gpw.get_plot(row=2) is None + + p0 = gpw.get_plot(row=0) + assert isinstance(p0.legend, LegendItem) + + +def test_GridPlotWidget_make_index(gravdata): + assert ('gravity', 0, 1, Axis.LEFT) == GridPlotWidget.make_index(gravdata['gravity'].name, 0, 1) + + unnamed_ser = pd.Series(np.zeros(14), name='') + with pytest.raises(ValueError): + GridPlotWidget.make_index(unnamed_ser.name, 1, 1) + + upper_ser = pd.Series(np.zeros(14), name='GraVitY') + assert ('gravity', 2, 0, Axis.LEFT) == GridPlotWidget.make_index(upper_ser.name, 2, 0) + + assert ('long_acc', 3, 1, Axis.LEFT) == GridPlotWidget.make_index('long_acc', 3, 1, 'sideways') + + +def test_GridPlotWidget_add_series(gravity): + gpw = GridPlotWidget(rows=2) + p0: PlotItem = gpw.get_plot(row=0) + p1: PlotItem = gpw.get_plot(row=1) + + assert 0 == len(p0.dataItems) == len(p1.dataItems) + + assert 'gravity' == gravity.name + assert isinstance(gravity, pd.Series) + + # Plotting an item should return a reference to the PlotDataItem + _grav_item0 = gpw.add_series(gravity, row=0) + assert 1 == len(p0.items) + assert gravity.equals(gpw.get_series(gravity.name, row=0)) + assert isinstance(_grav_item0, PlotDataItem) + assert gravity.name in [label.text for _, label in p0.legend.items] + + # Re-plotting an existing series on the same plot should do nothing + _items_len = len(list(gpw._items.values())) + gpw.add_series(gravity, row=0) + assert 1 == len(p0.dataItems) + assert _items_len == len(list(gpw._items.values())) + + # Allow plotting of a duplicate series to a second plot + _items_len = len(list(gpw._items.values())) + gpw.add_series(gravity, row=1) + assert 1 == len(p1.dataItems) + assert _items_len + 1 == len(list(gpw._items.values())) + + # Remove series only by name (assuming it can only ever be plotted once) + # or specify which plot to remove it from? + gpw.remove_series(gravity.name, row=0) + assert 0 == len(p0.dataItems) + key = 0, 0, gravity.name + assert gpw._series.get(key, None) is None + assert gpw._items.get(key, None) is None + assert 'gravity' not in [label.text for _, label in p0.legend.items] + + with pytest.raises(KeyError): + gpw.remove_series('eotvos', 0, 0) + + +def test_GridPlotWidget_remove_series(gravity): + gpw = GridPlotWidget(rows=3, multiy=True) + p0 = gpw.get_plot(row=0) + p0right = gpw.get_plot(row=0, axis=Axis.RIGHT) + p1 = gpw.get_plot(row=1) + p2 = gpw.get_plot(row=2) + + assert 0 == len(p0.dataItems) == len(p1.dataItems) == len(p2.dataItems) + _grav0 = gpw.add_series(gravity, row=0, axis=Axis.LEFT) + _grav1 = gpw.add_series(gravity, row=0, axis=Axis.RIGHT) + + assert 1 == len(p0.dataItems) == len(p0right.dataItems) + + gpw.remove_series(gravity.name, 0, axis=Axis.LEFT) + assert 0 == len(p0.dataItems) + assert 1 == len(p0right.dataItems) + gpw.remove_series(gravity.name, 0, axis=Axis.RIGHT) + assert 0 == len(p0right.dataItems) + + +def test_GridPlotWidget_remove_plotitem(gravity): + gpw = GridPlotWidget(rows=2) + p0 = gpw.get_plot(0) + p1 = gpw.get_plot(1) + + _grav_item0 = gpw.add_series(gravity, 0) + _grav_item1 = gpw.add_series(gravity, 1) + assert 1 == len(p0.dataItems) == len(p1.dataItems) + assert _grav_item0 in p0.dataItems + assert _grav_item0 in gpw._items.values() + + gpw.remove_plotitem(_grav_item0) + assert 0 == len(p0.dataItems) + assert 1 == len(p1.dataItems) + assert _grav_item0 not in gpw._items.items() + assert _grav_item0 not in p0.dataItems + assert gpw._series.get((0, 0, 'gravity'), None) is None + + assert 'gravity' not in [label.text for _, label in p0.legend.items] + + +def test_GridPlotWidget_find_series(gravity): + """Test function to find & return all keys for a series identified by name + e.g. if 'gravity' channel is plotted on plot rows 0 and 1, find_series + should return a list of key tuples (row, col, name) where the series is + plotted. + """ + gpw = GridPlotWidget(rows=3) + assert 3 == gpw.rows + + gpw.add_series(gravity, 0) + gpw.add_series(gravity, 2) + + expected = [(gravity.name, 0, 0, Axis.LEFT), (gravity.name, 2, 0, Axis.LEFT)] + result = gpw.find_series(gravity.name) + assert expected == result + + _grav_series0 = gpw.get_series(*result[0]) + assert gravity.equals(_grav_series0) + + +def test_GridPlotWidget_set_xaxis_formatter(gravity): + """Test that appropriate axis formatters are automatically added based on + the series index type (numeric or DateTime) + """ + gpw = GridPlotWidget(rows=2) + gpw.add_series(gravity, 1) + + p0 = gpw.get_plot(0) + btm_axis_p0 = p0.getAxis('bottom') + gpw.set_xaxis_formatter(formatter=AxisFormatter.DATETIME, row=0) + assert isinstance(btm_axis_p0, PolyAxis) + assert btm_axis_p0.timeaxis + + p1 = gpw.get_plot(1) + btm_axis_p1 = p1.getAxis('bottom') + assert isinstance(btm_axis_p1, PolyAxis) + assert not btm_axis_p1.timeaxis + + gpw.set_xaxis_formatter(formatter=AxisFormatter.SCALAR, row=0) + assert not p0.getAxis('bottom').timeaxis + + +def test_GridPlotWidget_sharex(gravity): + """Test linked vs unlinked x-axis scales""" + gpw_unlinked = GridPlotWidget(rows=2, sharex=False) + + gpw_unlinked.add_series(gravity, 0, autorange=False) + up0_xlim = gpw_unlinked.get_xlim(row=0) + up1_xlim = gpw_unlinked.get_xlim(row=1) + + assert up1_xlim == [0, 1] + assert up0_xlim != up1_xlim + gpw_unlinked.set_xlink(True) + assert gpw_unlinked.get_xlim(row=0) == gpw_unlinked.get_xlim(row=1) + gpw_unlinked.set_xlink(False, autorange=True) + gpw_unlinked.add_series(pd.Series(np.random.rand(len(gravity)), + name='rand'), 1) + assert gpw_unlinked.get_xlim(row=0) != gpw_unlinked.get_xlim(row=1) + + gpw_linked = GridPlotWidget(rows=2, sharex=True) + gpw_linked.add_series(gravity, 0) + assert gpw_linked.get_xlim(row=0) == gpw_linked.get_xlim(row=1) + + +def test_GridPlotWidget_iterator(): + """Test plots generator property for iterating through all plots""" + gpw = GridPlotWidget(rows=5) + count = 0 + for i, plot in enumerate(gpw.plots): + assert isinstance(plot, PlotItem) + plot_i = gpw.get_plot(i, 0) + assert plot_i == plot + count += 1 + + assert gpw.rows == count + + +def test_GridPlotWidget_clear(gravdata): + """Test clearing all series from all plots, or selectively""" + gpw = GridPlotWidget(rows=3) + gpw.add_series(gravdata['gravity'], 0) + gpw.add_series(gravdata['long_accel'], 1) + gpw.add_series(gravdata['cross_accel'], 2) + + assert 3 == len(gpw._items) + p0 = gpw.get_plot(0, 0) + assert 1 == len(p0.dataItems) + + gpw.clear() + + assert 0 == len(gpw._items) + assert 0 == len(p0.dataItems) + + # TODO: Selective clear not yet implemented + + +def test_GridPlotWidget_multi_y(gravdata): + _gravity = gravdata['gravity'] + _longacc = gravdata['long_accel'] + gpw = GridPlotWidget(rows=1, multiy=True) + + p0 = gpw.get_plot(0) + gpw.add_series(_gravity, 0) + gpw.add_series(_longacc, 0, axis=Axis.RIGHT) + + # Legend entry for right axis should appear on p0 legend + assert _gravity.name in [label.text for _, label in p0.legend.items] + assert _longacc.name in [label.text for _, label in p0.legend.items] + + assert 1 == len(gpw.get_plot(0).dataItems) + assert 1 == len(gpw.get_plot(0, axis=Axis.RIGHT).dataItems) + + assert gpw.get_xlim(0) == gpw.get_plot(0, axis=Axis.RIGHT).vb.viewRange()[0] + + +@pytest.mark.skip +@pytest.mark.parametrize("delta,expected", [ + (pd.Timedelta(seconds=1), [(pd.Timedelta(milliseconds=100).value, 0)]), + (pd.Timedelta(seconds=2), [(pd.Timedelta(milliseconds=333).value, 0)]), + (pd.Timedelta(seconds=60), [(pd.Timedelta(seconds=10).value, 0)]), + (pd.Timedelta(seconds=1200), [(pd.Timedelta(seconds=15*60).value, 0)]), +]) +def test_PolyAxis_dateTickSpacing_major(delta, expected): + """Test generation of tick spacing tuples for a PolyAxis in date mode. + + The tickSpacing method accepts a minVal, maxVal and size parameter + + size is the pixel length/width of the axis where the ticks will be displayed + + """ + axis = PolyAxis(orientation='bottom', timeaxis=True) + assert axis.timeaxis + + _size = 600 + + t0: pd.Timestamp = pd.Timestamp.now() + t1: pd.Timestamp = t0 + delta + + assert expected == axis.dateTickSpacing(t0.value, t1.value, _size) + + +@pytest.mark.skip +def test_PolyAxis_tickStrings(): + axis = PolyAxis(orientation='bottom') + axis.timeaxis = True + _scale = 1.0 + _spacing = pd.Timedelta(seconds=1).value + + _HOUR_SEC = 3600 + _DAY_SEC = 86400 + + dt_index = pd.DatetimeIndex(start=datetime(2018, 6, 15, 12, 0, 0), freq='s', + periods=8 * _DAY_SEC) + dt_list = pd.to_numeric(dt_index).tolist() + + # Test with no values passed + assert [] == axis.tickStrings([], _scale, 1) + + # If the plot range is <= 60 seconds, ticks should be formatted as %M:%S + _minute = 61 + expected = [pd.to_datetime(dt_list[i]).strftime('%M:%S') for i in range(_minute)] + assert expected[1:] == axis.tickStrings(dt_list[:_minute], _scale, _spacing)[1:] + + # If 1 minute < plot range <= 1 hour, ticks should be formatted as %H:%M + _hour = 60 * 60 + 1 + expected = [pd.to_datetime(dt_list[i]).strftime('%H:%M') for i in range(0, _hour, 5)] + assert expected[1:] == axis.tickStrings(dt_list[:_hour:5], _scale, _spacing)[1:] + + # If 1 hour < plot range <= 1 day, ticks should be formatted as %d %H:%M + tick_values = [dt_list[i] for i in range(0, 23 * _HOUR_SEC, _HOUR_SEC)] + expected = [pd.to_datetime(v).strftime('%d %H:%M') for v in tick_values] + assert expected == axis.tickStrings(tick_values, _scale, _HOUR_SEC) + + # If 1 day < plot range <= 1 week, ticks should be formatted as %m-%d %H + + tick_values = [dt_list[i] for i in range(0, 3 * _DAY_SEC, _DAY_SEC)] + expected = [pd.to_datetime(v).strftime('%m-%d %H') for v in tick_values] + assert expected == axis.tickStrings(tick_values, _scale, _DAY_SEC) + + +def test_LineSelectPlot_init(): + plot = LineSelectPlot(rows=2) + + assert isinstance(plot, QObject) + assert isinstance(plot, QWidget) + + assert 2 == plot.rows + + +def test_LineSelectPlot_selection_mode(): + plot = LineSelectPlot(rows=3) + assert not plot.selection_mode + plot.set_select_mode(True) + assert plot.selection_mode + + plot.add_segment(datetime.now().timestamp(), + datetime.now().timestamp() + 1000) + + assert 1 == len(plot._segments) + + for lfr_grp in plot._segments.values(): # type: LinearSegmentGroup + assert lfr_grp.movable + + plot.set_select_mode(False) + for lfr_grp in plot._segments.values(): + assert not lfr_grp.movable + + +def test_LineSelectPlot_add_segment(): + _rows = 2 + plot = LineSelectPlot(rows=_rows) + update_spy = QSignalSpy(plot.sigSegmentChanged) + + ts_oid = OID(tag='datetime_timestamp') + ts_start = datetime.now().timestamp() - 1000 + ts_stop = ts_start + 200 + + pd_oid = OID(tag='pandas_timestamp') + pd_start = pd.Timestamp.now() + pd_stop = pd_start + pd.Timedelta(seconds=1000) + + assert 0 == len(plot._segments) + + plot.add_segment(ts_start, ts_stop, uid=ts_oid) + assert 1 == len(update_spy) + assert 1 == len(plot._segments) + lfr_grp = plot._segments[ts_oid] + assert _rows == len(lfr_grp._segments) + + # Test adding segment using pandas.Timestamp values + plot.add_segment(pd_start, pd_stop, uid=pd_oid) + assert 2 == len(update_spy) + assert 2 == len(plot._segments) + lfr_grp = plot._segments[pd_oid] + assert _rows == len(lfr_grp._segments) + + # Test adding segment with no signal emission + plot.add_segment(ts_start + 2000, ts_stop + 2000, emit=False) + assert 2 == len(update_spy) + + +def test_LineSelectPlot_remove_segment(): + _rows = 2 + plot = LineSelectPlot(rows=_rows) + update_spy = QSignalSpy(plot.sigSegmentChanged) + + lfr_oid = OID(tag='segment selection') + lfr_start = datetime.now().timestamp() + lfr_end = lfr_start + 300 + + plot.add_segment(lfr_start, lfr_end, uid=lfr_oid) + assert 1 == len(update_spy) + assert isinstance(update_spy[0][0], LineUpdate) + + assert 1 == len(plot._segments) + group = plot._segments[lfr_oid] + assert group._segments[0] in plot.get_plot(row=0).items + assert group._segments[1] in plot.get_plot(row=1).items + + group.delete() + assert 0 == len(plot._segments) + + +def test_LineSelectPlot_set_label(gravity: pd.Series): + plot = LineSelectPlot(rows=2) + update_spy = QSignalSpy(plot.sigSegmentChanged) + plot.add_series(gravity, 0) + + uid = OID() + plot.add_segment(2, 4, uid=uid) + assert 1 == len(update_spy) + + segment_grp = plot._segments[uid] + segment0 = segment_grp._segments[0] + segment1 = segment_grp._segments[1] + + assert isinstance(segment0, LinearSegment) + assert '' == segment0._label.textItem.toPlainText() + assert '' == segment0.label_text + + _label = 'Flight-1' + segment_grp._update_label(_label) + assert 2 == len(update_spy) + update = update_spy[1][0] + assert _label == update.label + assert _label == segment0._label.textItem.toPlainText() + assert _label == segment1._label.textItem.toPlainText() + + +def test_LineSelectPlot_check_proximity(gravdata): + _rows = 2 + plot = LineSelectPlot(rows=_rows) + p0 = plot.get_plot(0) + plot.add_series(gravdata['gravity'], 0) + + lfr_start = gravdata.index[0] + lfr_end = gravdata.index[2] + p0xlim = plot.get_xlim(0) + span = p0xlim[1] - p0xlim[0] + + xpos = gravdata.index[3].value + assert plot._check_proximity(xpos, span) + + plot.add_segment(lfr_start, lfr_end) + + assert not plot._check_proximity(xpos, span, proximity=0.2) + xpos = gravdata.index[4].value + assert plot._check_proximity(xpos, span, proximity=0.2) + + +def test_LineSelectPlot_clear(): + pass diff --git a/tests/test_project.py b/tests/test_project.py deleted file mode 100644 index 77aca45..0000000 --- a/tests/test_project.py +++ /dev/null @@ -1,178 +0,0 @@ -# coding: utf-8 - -import unittest -import random -import tempfile -from pathlib import Path - -from .context import dgp -from dgp.lib.gravity_ingestor import read_at1a -from dgp.lib.project import * -from dgp.lib.meterconfig import * - - -class TestProject(unittest.TestCase): - - def setUp(self): - """Set up some dummy classes for testing use""" - self.todelete = [] - self.project = AirborneProject(path='tests', name='Test Airborne Project') - - # Sample values for testing meter configs - self.meter_vals = { - 'gravcal': random.randint(200000, 300000), - 'longcal': random.uniform(150.0, 250.0), - 'crosscal': random.uniform(150.0, 250.0), - 'cross_lead': random.random() - } - self.at1a5 = MeterConfig(name="AT1A-5", **self.meter_vals) - self.project.add_meter(self.at1a5) - - def test_project_directory(self): - """ - Test the handling of the directory specifications within a project - Project should take an existing directory as a path, raising FileNotFoundError if it doesnt exist. - If the path exists but is a file, Project should automatically strip the leaf and use the parent path. - """ - with self.assertRaises(FileNotFoundError): - project = GravityProject(path=Path('tests/invalid_dir')) - - with tempfile.TemporaryDirectory() as td: - project_dir = Path(td) - project = GravityProject(path=project_dir) - self.assertEqual(project.projectdir, project_dir) - - # Test exception given a file instead of directory - with tempfile.NamedTemporaryFile() as tf: - tf.write(b"This is not a directory") - with self.assertRaises(NotADirectoryError): - project = GravityProject(path=Path(str(tf.name))) - - def test_pickle_project(self): - # TODO: Add further complexity to testing of project pickling - flight = Flight(None, 'test_flight', self.at1a5) - flight.add_line(100, 250.5) - self.project.add_flight(flight) - - with tempfile.TemporaryDirectory() as td: - save_loc = Path(td, 'project.d2p') - self.project.save(save_loc) - - loaded_project = AirborneProject.load(save_loc) - self.assertIsInstance(loaded_project, AirborneProject) - self.assertEqual(len(loaded_project.flights), 1) - self.assertEqual(loaded_project.flights[flight.uid].uid, flight.uid) - self.assertEqual(loaded_project.flights[flight.uid].meter.name, 'AT1A-5') - - def test_flight_iteration(self): - test_flight = Flight(None, 'test_flight', self.at1a5) - line0 = test_flight.add_line(100.1, 200.2) - line1 = test_flight.add_line(210, 350.3) - lines = [line0, line1] - - for line in test_flight: - print(line) - self.assertTrue(line in lines) - - # TODO: Fix ImportWarning generated by pytables? - @unittest.skip('New add_data test not implemented') - def test_associate_flight_data(self): - """Test adding a data file and associating it with a specific flight""" - self.todelete.append('tests/prjdata.h5') # Cleanup when done - - flt = Flight(self.at1a5) - self.project.add_flight(flt) - - data1 = 'tests/test_data.csv' - self.project.add_data(data1, flight=flt) - - data1path = os.path.abspath(data1) - self.assertTrue(data1path in self.project.data_sources.values()) - - test_df = read_at1m(data1) - grav_data, gps_data = self.project.get_data(flt) - self.assertTrue(test_df.equals(grav_data)) - self.assertIsNone(gps_data) - - -class TestFlight(unittest.TestCase): - def setUp(self): - pass - - -class TestMeterconfig(unittest.TestCase): - def setUp(self): - self.ini_path = os.path.abspath('tests/at1m.ini') - self.config = { - 'g0': 10000.0, - 'GravCal': 227626.0, - 'LongCal': 200.0, - 'CrossCal': 200.1, - 'vcc': 0.0, - 've': 0.0, - 'Cross_Damping': 550.0, - 'Long_Damping': 550.0, - 'at1_invalid': 12345.8 - } - - def test_MeterConfig(self): - mc = MeterConfig(name='Test-1', **self.config) - self.assertEqual(mc.name, 'Test-1') - - # Test get, set and len methods of the MeterConfig class - self.assertEqual(len(mc), len(self.config)) - - for k in self.config.keys(): - self.assertEqual(mc[k], self.config[k]) - # Test case-insensitive handling - self.assertEqual(mc[k.lower()], self.config[k]) - - mc['g0'] = 500.01 - self.assertEqual(mc['g0'], 500.01) - self.assertIsInstance(mc['g0'], float) - # Test the setting of non-float types - mc['monitor'] = True - self.assertTrue(mc['monitor']) - - mc['str_val'] = 'a string' - self.assertEqual(mc['str_val'], 'a string') - - # Test the class handling of invalid requests/types - with self.assertRaises(NotImplementedError): - mc[0: 3] - - with self.assertRaises(NotImplementedError): - MeterConfig.from_ini(self.ini_path) - - def test_AT1Meter_config(self): - at1 = AT1Meter('AT1M-5', **self.config) - - self.assertEqual(at1.name, 'AT1M-5') - - # Test that invalid field was not set - self.assertIsNone(at1['at1_invalid']) - valid_fields = {k: v for k, v in self.config.items() if k != 'at1_invalid'} - for k in valid_fields.keys(): - # Check all valid fields were set - self.assertEqual(at1[k], valid_fields[k]) - - def test_AT1Meter_from_ini(self): - at1 = AT1Meter.from_ini(self.ini_path) - - # Check type inheritance - self.assertIsInstance(at1, AT1Meter) - self.assertIsInstance(at1, MeterConfig) - - self.assertEqual(at1.name, 'AT1M-1U') - - cfp = configparser.ConfigParser(strict=False) # strict=False to allow for duplicate keys in config - cfp.read(self.ini_path) - - skip_fields = ['meter', '00gravcal'] - for k, v in cfp['Sensor'].items(): - if k in skip_fields: - continue - self.assertEqual(float(cfp['Sensor'][k]), at1[k]) - - - diff --git a/tests/test_project_treemodel.py b/tests/test_project_treemodel.py new file mode 100644 index 0000000..8267446 --- /dev/null +++ b/tests/test_project_treemodel.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +from PyQt5.QtTest import QSignalSpy + +from dgp.core.oid import OID +from dgp.core.models.project import AirborneProject +from dgp.core.controllers.flight_controller import FlightController +from dgp.core.controllers.project_controllers import AirborneProjectController +from dgp.core.controllers.project_treemodel import ProjectTreeModel + + +def test_ProjectTreeModel_init(project: AirborneProject, + prj_ctrl: AirborneProjectController): + + model = ProjectTreeModel(prj_ctrl) + assert 1 == model.rowCount() + assert prj_ctrl == model.active_project + + +def test_ProjectTreeModel_multiple_projects(project: AirborneProject, + prj_ctrl: AirborneProjectController): + prj_ctrl2 = AirborneProjectController(project) + assert prj_ctrl is not prj_ctrl2 + + model = ProjectTreeModel(prj_ctrl) + assert 1 == model.rowCount() + assert prj_ctrl == model.active_project + + model.add_project(prj_ctrl2) + assert 2 == model.rowCount() + assert prj_ctrl == model.active_project + model.item_activated(model.index(prj_ctrl2.row(), 0)) + assert prj_ctrl2 == model.active_project + + assert prj_ctrl in model.projects + assert prj_ctrl2 in model.projects + diff --git a/tests/test_serialization.py b/tests/test_serialization.py new file mode 100644 index 0000000..a0a5bf0 --- /dev/null +++ b/tests/test_serialization.py @@ -0,0 +1,156 @@ +# -*- coding: utf-8 -*- +import json +import time +from datetime import datetime, date +from pathlib import Path +from pprint import pprint + +import pandas as pd +import pytest + +from dgp.core.types.reference import Reference +from dgp.core.models.meter import Gravimeter +from dgp.core.models.dataset import DataSet +from dgp.core.models.datafile import DataFile +from dgp.core.models.flight import Flight +from dgp.core.models.project import AirborneProject, ProjectEncoder, ProjectDecoder, PROJECT_FILE_NAME + + +"""Test Project is created as a global fixture in conftest.py""" + + +def test_project_serialize(project: AirborneProject, tmpdir): + _description = "Description for project that will be serialized." + project.description = _description + + encoded = project.to_json(indent=4) + decoded_dict = json.loads(encoded) + + assert project.name == decoded_dict['name'] + assert {'_type': 'Path', '_module': 'pathlib', 'path': str(project.path.resolve())} == decoded_dict['path'] + for flight_obj in decoded_dict['flights']: + assert '_type' in flight_obj and flight_obj['_type'] == 'Flight' + + _date = date.today() + enc_date = json.dumps(_date, cls=ProjectEncoder) + assert _date == json.loads(enc_date, cls=ProjectDecoder, klass=None) + with pytest.raises(TypeError): + json.dumps(pd.DataFrame([0, 1]), cls=ProjectEncoder) + + # Test serialize to file + project.to_json(to_file=True) + assert project.path.joinpath(PROJECT_FILE_NAME).exists() + + +def test_project_deserialize(project: AirborneProject): + flt1 = project.flights[0] + flt2 = project.flights[1] + + serialized = project.to_json(indent=4) + time.sleep(0.20) # Fuzz for modification date + prj_deserialized = AirborneProject.from_json(serialized) + re_serialized = prj_deserialized.to_json(indent=4) + assert serialized == re_serialized + + assert project.create_date == prj_deserialized.create_date + + flt_names = [flt.name for flt in prj_deserialized.flights] + assert flt1.name in flt_names + assert flt2.name in flt_names + assert flt1.parent is project + + f1_reconstructed = prj_deserialized.get_child(flt1.uid) + assert flt1.uid in [flt.uid for flt in prj_deserialized.flights] + assert 2 == len(prj_deserialized.flights) + prj_deserialized.remove_child(f1_reconstructed.uid) + assert 1 == len(prj_deserialized.flights) + assert flt1.uid not in [flt.uid for flt in prj_deserialized.flights] + assert f1_reconstructed.name == flt1.name + assert f1_reconstructed.uid == flt1.uid + assert f1_reconstructed.parent is prj_deserialized + + assert flt2.uid in [flt.uid for flt in prj_deserialized.flights] + + +def test_parent_child_serialization(): + """Test that an object _parent reference is correctly serialized and deserialized + i.e. when a child say FlightLine or DataFile is added to a flight, it should + have a reference to its parent Flight. + When de-serializing, check to see that this reference has been correctly assembled + """ + prj = AirborneProject(name="Parent-Child-Test", path=Path('.')) + flt = Flight('Flight-1') + data1 = DataFile('gravity', datetime.now(), Path('./data1.dat')) + + # flt.add_child(data1) + # assert flt == data1.parent + + prj.add_child(flt) + assert flt in prj.flights + + encoded = prj.to_json(indent=2) + # pprint(encoded) + + decoded = AirborneProject.from_json(encoded) + + assert 1 == len(decoded.flights) + flt_ = decoded.flights[0] + + +def test_Reference(): + project = AirborneProject(name='Reference-Test', path=Path('.')) + flt = Flight('Flight-1') + + ref = Reference(flt, 'parent', project) + assert not ref.isnull + expected = { + '_type': Reference.__name__, + 'parent': flt.uid, + 'attr': 'parent', + 'ref': project.uid + } + assert expected == ref.serialize() + + nullref = Reference(flt, 'parent') + assert nullref.isnull + assert nullref.serialize() is None + + +def test_reference_serialization(): + """Project objects should be able to use a Reference wrapper to serialize a + reference to a object higher in the project graph. + The referred object should be set as an attribute on the object when + de-serialization is completed. + + """ + sensor = Gravimeter('AT1A-12') + ds = DataSet(sensor=sensor) + ds_a = DataSet(sensor=sensor) + flt = Flight(name='Flight-1', datasets=[ds, ds_a]) + prj = AirborneProject(name="Reference-Serialization-Test", path=Path('.'), + flights=[flt]) + prj.add_child(sensor) + assert flt.parent is prj + assert sensor is ds.sensor + + serialized0 = prj.to_json(indent=2) + + prj1 = prj.from_json(serialized0) + sensor1 = prj1.gravimeters[0] + flt1 = prj1.flights[0] + ds1 = flt1.datasets[0] + ds2 = flt1.datasets[1] + + assert flt1.parent is prj1 + + assert sensor.name == sensor1.name + assert sensor.uid == sensor1.uid + + assert flt.uid == flt1.uid + assert ds.uid == ds1.uid + + assert ds.sensor.uid == ds1.sensor.uid + assert isinstance(ds1.sensor, Gravimeter) + + assert ds1.sensor is sensor1 + assert ds2.sensor is sensor1 diff --git a/tests/test_time_utils.py b/tests/test_time_utils.py index 80d8246..bb513e3 100644 --- a/tests/test_time_utils.py +++ b/tests/test_time_utils.py @@ -1,67 +1,76 @@ # coding: utf-8 -import os -import unittest +import pytest from datetime import datetime import pandas as pd -from .context import dgp from dgp.lib import time_utils as tu -class TestTimeUtils(unittest.TestCase): - def test_leap_seconds(self): - # TO DO: Test edge cases - gpsweek = 1959 - gpsweeksecond = 219698.000 - unixtime = 1500987698 # 2017-07-25 13:01:38+00:00 - dt = datetime.strptime('2017-07-25 13:01:38', '%Y-%m-%d %H:%M:%S') - expected1 = 18 - date1 = '08-07-2015' - date2 = '08/07/2015' - date3 = '08/07-2015' - expected2 = 17 +def test_leap_seconds(): + # TO DO: Test edge cases + gpsweek = 1959 + gpsweeksecond = 219698.000 + unixtime = 1500987698 # 2017-07-25 13:01:38+00:00 + dt = datetime.strptime('2017-07-25 13:01:38', '%Y-%m-%d %H:%M:%S') + expected1 = 18 - res_gps = tu.leap_seconds(week=gpsweek, seconds=gpsweeksecond) - res_unix = tu.leap_seconds(seconds=unixtime) - res_datetime = tu.leap_seconds(datetime=dt) - res_date1 = tu.leap_seconds(date=date1) - res_date2 = tu.leap_seconds(date=date2) + date1 = '08-07-2015' + date2 = '08/07/2015' + date3 = '08/07-2015' + expected2 = 17 - self.assertEqual(expected1, res_gps) - self.assertEqual(expected1, res_unix) - self.assertEqual(expected1, res_datetime) - self.assertEqual(expected2, res_date1) - self.assertEqual(expected2, res_date2) + res_gps = tu.leap_seconds(week=gpsweek, seconds=gpsweeksecond) + res_unix = tu.leap_seconds(seconds=unixtime) + res_datetime = tu.leap_seconds(datetime=dt) + res_date1 = tu.leap_seconds(date=date1) + res_date2 = tu.leap_seconds(date=date2, dateformat='%m/%d/%Y') - with self.assertRaises(ValueError): - res_date3 = tu.leap_seconds(date=date3) + assert expected1 == res_gps + assert expected1 == res_unix + assert expected1 == res_datetime + assert expected2 == res_date1 + assert expected2 == res_date2 - with self.assertRaises(ValueError): - res = tu.leap_seconds(minutes=dt) + with pytest.raises(ValueError): + tu.leap_seconds(date=date3) - def test_convert_gps_time(self): - gpsweek = 1959 - gpsweeksecond = 219698.000 - result = 1500987698 # 2017-07-25 13:01:38+00:00 - test_res = tu.convert_gps_time(gpsweek, gpsweeksecond) - self.assertEqual(result, test_res) + with pytest.raises(ValueError): + tu.leap_seconds(minutes=dt) - def test_datetime_to_sow(self): - # test single input - dt = datetime(2017, 9, 7, hour=13) - expected = (1965, 392400) - given = tu.datetime_to_sow(dt) - self.assertEqual(expected, given) - # test iterable input - dt_series = pd.Series([dt]*20) - expected_iter = [expected]*20 - given_iter = tu.datetime_to_sow(dt_series) - self.assertEqual(expected_iter, given_iter) +def test_convert_gps_time(): + gpsweek = 1959 + gpsweeksecond = 219698.000 + result = 1500987698 # 2017-07-25 13:01:38+00:00 + test_res = tu.convert_gps_time(gpsweek, gpsweeksecond) + assert result == test_res - def test_datenum_to_datetime(self): - pass - # datenum = 736945.5416667824 - # given = tu.datenum_to_datetime(datenum) - # expected = datetime(2017, 9, 7, hour=13, microsecond=10000) - # self.assertEqual(expected, given) + +@pytest.mark.parametrize( + 'given_sow, expected_dt', [ + (312030.8, datetime(2017, 3, 22, 14, 40, 30, 800000)), + (312030.08, datetime(2017, 3, 22, 14, 40, 30, 80000)), + (312030.008, datetime(2017, 3, 22, 14, 40, 30, 8000)), + (312030.0008, datetime(2017, 3, 22, 14, 40, 30, 800)) + ] +) +def test_convert_gps_time_datetime(given_sow, expected_dt): + gpsweek = pd.Series([1941]) + gpsweeksecond = pd.Series([given_sow]) + result = pd.Series([expected_dt]) + test_res = tu.convert_gps_time(gpsweek, gpsweeksecond, format='datetime') + assert result.equals(test_res) + + +def test_datetime_to_sow(): + # test single input + dt = datetime(2017, 9, 7, hour=13) + expected = (1965, 392400) + given = tu.datetime_to_sow(dt) + assert expected == given + + # test iterable input + dt_series = pd.Series([dt]*20) + expected_iter = [expected]*20 + given_iter = tu.datetime_to_sow(dt_series) + assert expected_iter == given_iter diff --git a/tests/test_timesync.py b/tests/test_timesync.py new file mode 100644 index 0000000..2d13183 --- /dev/null +++ b/tests/test_timesync.py @@ -0,0 +1,117 @@ +# coding: utf-8 +import os + +import unittest +import numpy as np +import pandas as pd + +from dgp.lib.timesync import find_time_delay, shift_frame + + +@unittest.skipIf(os.getenv("development", False), "Skip slow unit-tests in dev env") +class TestTimesync(unittest.TestCase): + def test_timedelay_array(self): + rnd_offset = 1.1 + t1 = np.arange(0, 5000, 0.1, dtype=np.float64) + t2 = t1 + rnd_offset + s1 = np.sin(0.8 * t1) + np.sin(0.2 * t1) + s2 = np.sin(0.8 * t2) + np.sin(0.2 * t2) + time = find_time_delay(s1, s2, 10) + self.assertAlmostEqual(rnd_offset, -time, places=2) + + def test_timedelay_timelike_index(self): + rnd_offset = 1.1 + now = pd.Timestamp.now() + t1 = np.arange(0, 5000, 0.1, dtype=np.float64) + index1 = pd.to_timedelta(t1, unit='s') + now + t2 = t1 + rnd_offset + index2 = pd.to_timedelta(t2, unit='s') + now + s1 = np.sin(0.8 * t1) + np.sin(0.2 * t1) + frame1 = pd.Series(s1, index=index1) + s2 = np.sin(0.8 * t2) + np.sin(0.2 * t2) + frame2 = pd.Series(s2, index=index2) + + time = find_time_delay(frame1, frame2) + self.assertAlmostEqual(rnd_offset, -time, places=2) + + def test_timedelay_warning(self): + rnd_offset = 1.1 + + t1 = np.arange(0, 5000, 0.1, dtype=np.float64) + t2 = t1 + rnd_offset + + s1 = np.sin(0.8 * t1) + np.sin(0.2 * t1) + index = pd.Timestamp.now() + pd.to_timedelta(t1, unit='s') + frame = pd.Series(s1, index=index) + s2 = np.sin(0.8 * t2) + np.sin(0.2 * t2) + + with self.assertWarns(UserWarning): + find_time_delay(frame, s2) + + def test_timedelay_ignore_indexes(self): + rnd_offset = 1.1 + t1 = np.arange(0, 5000, 0.1, dtype=np.float64) + t2 = t1 + rnd_offset + s1 = np.sin(0.8 * t1) + np.sin(0.2 * t1) + s2 = np.sin(0.8 * t2) + np.sin(0.2 * t2) + now = pd.Timestamp.now() + index1 = now + pd.to_timedelta(t1, unit='s') + frame1 = pd.Series(s1, index=index1) + frame2 = s2 + + msg_expected = 's2 has no index. Ignoring index for s1.' + with self.assertWarns(UserWarning, msg=msg_expected): + find_time_delay(frame1, frame2) + + frame1 = s1 + index2 = now + pd.to_timedelta(t2, unit='s') + frame2 = pd.Series(s2, index=index2) + + msg_expected = 's1 has no index. Ignoring index for s2.' + with self.assertWarns(UserWarning, msg=msg_expected): + find_time_delay(frame1, frame2) + + frame1 = pd.Series(s1, index=index1) + index2 = now + pd.to_timedelta(t2, unit='s') + frame2 = pd.Series(s2) + + msg_expected = ('Index of s2 is not a DateTimeIndex. Ignoring both ' + 'indexes.') + with self.assertWarns(UserWarning, msg=msg_expected): + find_time_delay(frame1, frame2) + + frame1 = pd.Series(s1) + index2 = now + pd.to_timedelta(t2, unit='s') + frame2 = pd.Series(s2, index=index2) + + msg_expected = ('Index of s1 is not a DateTimeIndex. Ignoring both ' + 'indexes.') + with self.assertWarns(UserWarning, msg=msg_expected): + find_time_delay(frame1, frame2) + + def test_timedelay_exceptions(self): + rnd_offset = 1.1 + now = pd.Timestamp.now() + t1 = np.arange(0, 5000, 0.1, dtype=np.float64) + index1 = pd.to_timedelta(t1, unit='s') + now + t2 = np.arange(0, 5000, 0.12, dtype=np.float64) + rnd_offset + index2 = pd.to_timedelta(t2, unit='s') + now + s1 = np.sin(0.8 * t1) + np.sin(0.2 * t1) + frame1 = pd.Series(s1, index=index1) + s2 = np.sin(0.8 * t2) + np.sin(0.2 * t2) + frame2 = pd.Series(s2, index=index2) + + msg_expected = 'Indexes have different frequencies' + with self.assertRaises(ValueError, msg=msg_expected): + find_time_delay(frame1, frame2) + + def test_shift_frame(self): + test_input = pd.Series(np.arange(10)) + index = pd.Timestamp.now() + pd.to_timedelta(np.arange(10), unit='s') + test_input.index = index + shifted_index = index.shift(110, freq='L') + expected = test_input.copy() + expected.index = shifted_index + + res = shift_frame(test_input, 0.11) + self.assertTrue(res.equals(expected)) diff --git a/tests/test_trajectory_ingestor.py b/tests/test_trajectory_ingestor.py index 54e55c5..c8e396d 100644 --- a/tests/test_trajectory_ingestor.py +++ b/tests/test_trajectory_ingestor.py @@ -5,7 +5,6 @@ import pandas as pd import numpy as np -from .context import dgp from dgp.lib import trajectory_ingestor as ti diff --git a/tests/test_transform.py b/tests/test_transform.py new file mode 100644 index 0000000..ce8500f --- /dev/null +++ b/tests/test_transform.py @@ -0,0 +1,227 @@ +# coding: utf-8 +import pytest +import pandas as pd +import numpy as np +from pandas.testing import assert_series_equal +from functools import partial + +from dgp.lib.transform.graph import Graph, TransformGraph, GraphError +from dgp.lib.transform.gravity import eotvos_correction, latitude_correction, free_air_correction +import dgp.lib.trajectory_ingestor as ti + +from tests import sample_dir +import csv + + +class TestGraph: + @pytest.mark.parametrize('test_input', ['some_string', + [[1, 2], [3], "hello"], + {'a': [1, 2], 'b': 3}, + {'a': [1, 2], 'b': "hello"}, + ]) + def test_init_raises(self, test_input): + pytest.raises(TypeError, Graph(test_input)) + + def test_topo_sort_raises(self): + test_input = {'a': [], + 'b': ['c'], + 'c': ['a', 'b'], + 'd': ['a', 'b', 'c']} + + g = Graph(test_input) + with pytest.raises(GraphError, message='Cycle detected'): + g.topo_sort() + + +def add(a, b): + return a + b + + +class TestTransformGraph: + @pytest.fixture + def test_input(self): + graph = {'a': 1, + 'b': 2, + 'c': (add, 'a', 'b'), + 'd': (sum, ['a', 'b', 'c']) + } + return graph + + def test_init(self, test_input): + g = TransformGraph(graph=test_input) + assert g.order == ['d', 'c', 'b', 'a'] + + def test_execute(self, test_input): + g = TransformGraph(graph=test_input) + res = g.execute() + expected = {'a': 1, 'b': 2, 'c': 3, 'd': 6} + assert res == expected + + def test_graph_setter(self, test_input): + g = TransformGraph(graph=test_input) + g.execute() + new_graph = {'a': 1, + 'b': 2, + 'c': (add, 'a', 'b'), + 'd': (sum, ['a', 'b', 'c']), + 'e': (add, 'd', 'b') + } + g.graph = new_graph + res = g.execute() + expected = {'a': 1, 'b': 2, 'c': 3, 'd': 6, 'e': 8} + + assert res == expected + + def test_subclass_noargs(self, test_input): + class NewTransformGraph(TransformGraph): + transform_graph = test_input + + g = NewTransformGraph() + res = g.execute() + expected = {'a': 1, 'b': 2, 'c': 3, 'd': 6} + assert res == expected + + def test_subclass_args(self): + class NewTransformGraph(TransformGraph): + def __init__(self, in1, in2): + self.transform_graph = {'a': in1, + 'b': in2, + 'c': (add, 'a', 'b'), + 'd': (sum, ['a', 'b', 'c']) + } + super().__init__() + + g = NewTransformGraph(1, 2) + res = g.execute() + expected = {'a': 1, 'b': 2, 'c': 3, 'd': 6} + assert res == expected + + +class TestCorrections: + @pytest.fixture + def trajectory_data(self): + # Ensure gps_fields are ordered correctly relative to test file + gps_fields = ['mdy', 'hms', 'lat', 'long', 'ortho_ht', 'ell_ht', + 'num_stats', 'pdop'] + data = ti.import_trajectory( + 'tests/sample_data/eotvos_short_input.txt', + columns=gps_fields, + skiprows=1, + timeformat='hms' + ) + + return data + + def test_eotvos(self, trajectory_data): + # TODO: More complete test that spans the range of possible inputs + result_eotvos = [] + with sample_dir.joinpath('eotvos_short_result.csv').open() as fd: + test_data = csv.DictReader(fd) + for line in test_data: + result_eotvos.append(float(line['Eotvos_full'])) + + transform_graph = {'trajectory': trajectory_data, + 'eotvos': (eotvos_correction, 'trajectory'), + } + g = TransformGraph(graph=transform_graph) + eotvos_a = g.execute() + + for i, value in enumerate(eotvos_a['eotvos']): + if 1 < i < len(result_eotvos) - 2: + try: + assert value == pytest.approx(result_eotvos[i], rel=1e-2) + except AssertionError: + print("Invalid assertion at data line: {}".format(i)) + raise AssertionError + + @pytest.mark.skip(reason="Error on my workstation") + def test_free_air_correction(self, trajectory_data): + # TODO: More complete test that spans the range of possible inputs + s1 = pd.Series([39.9148595446, 39.9148624273], name='lat') + s2 = pd.Series([1599.197, 1599.147], name='ell_ht') + test_input = pd.concat([s1, s2], axis=1) + test_input.index = pd.Index([trajectory_data.index[0], trajectory_data.index[-1]]) + + expected = pd.Series([-493.308594971815, -493.293177069581], + index=pd.Index([trajectory_data.index[0], + trajectory_data.index[-1]]), + name='fac' + ) + + transform_graph = {'trajectory': test_input, + 'fac': (free_air_correction, 'trajectory'), + } + g = TransformGraph(graph=transform_graph) + res = g.execute() + + assert_series_equal(expected, res['fac']) + # assert expected == pytest.approx(res['fac'], rel=1e-8) + + # check that the indices are equal + assert test_input.index.identical(res['fac'].index) + + def test_latitude_correction(self, trajectory_data): + test_input = pd.DataFrame([39.9148595446, 39.9148624273]) + test_input.columns = ['lat'] + test_input.index = pd.Index([trajectory_data.index[0], trajectory_data.index[-1]]) + + expected = pd.Series([-980162.105035777, -980162.105292394], + index=pd.Index([trajectory_data.index[0], + trajectory_data.index[-1]]), + name='lat_corr' + ) + + transform_graph = {'trajectory': test_input, + 'lat_corr': (latitude_correction, 'trajectory'), + } + g = TransformGraph(graph=transform_graph) + res = g.execute() + + assert_series_equal(expected, res['lat_corr'], check_less_precise=8) + # assert expected == pytest.approx(res['lat_corr'], rel=1e-8) + + # check that the indexes are equal + assert test_input.index.identical(res['lat_corr'].index) + + def test_partial(self): + input_A = pd.Series(np.arange(0, 5), index=['A', 'B', 'C', 'D', 'E']) + input_B = pd.Series(np.arange(2, 7), index=['A', 'B', 'C', 'D', 'E']) + expected = pd.concat([input_A, input_B], axis=1) + + concat = partial(pd.concat, join='outer', axis=1) + + transform_graph = {'input_a': input_A, + 'input_b': input_B, + 'result': (concat, ['input_a', 'input_b']) + } + g = TransformGraph(graph=transform_graph) + result = g.execute() + res = result['result'] + + assert res.equals(expected) + + # check that the indexes are equal + assert input_A.index.identical(res.index) + assert input_B.index.identical(res.index) + + def test_graph_chaining(self): + + class Graph1(TransformGraph): + def __init__(self, in1, in2): + self.transform_graph = {'a': in1, + 'b': in2, + 'c': (add, 'a', 'b'), + } + super().__init__() + + graph2 = {'a': 1, + 'b': 2, + 'c': (Graph1.run(item='c'), 'a', 'b'), + 'd': (sum, ['a', 'b', 'c']) + } + g = TransformGraph(graph=graph2) + result = g.execute() + expected = {'a': 1, 'b': 2, 'c': 3, 'd': 6} + + assert result == expected + diff --git a/tests/test_workspaces.py b/tests/test_workspaces.py new file mode 100644 index 0000000..d7e238a --- /dev/null +++ b/tests/test_workspaces.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- + +# Tests for gui workspace widgets in gui/workspaces + +# TODO: Reimplement these diff --git a/utils/build_uic.py b/utils/build_uic.py new file mode 100644 index 0000000..1ba93e4 --- /dev/null +++ b/utils/build_uic.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +from pathlib import Path + +from PyQt5.uic import compileUiDir +from PyQt5.pyrcc_main import processResourceFile + + +""" +Utility script to build python compiled UI and resource files from Qt .ui and +.qrc files. + +See Also +-------- + +`Qt 5 Resource System `__ + +`Qt 5 Resource Compiler (RCC) `__ + +`PyQt5 Resource System `__ + + +""" +BASE_DIR = Path(Path(__file__).parent).joinpath('../dgp').absolute() +RES_FILES = [ + str(BASE_DIR.joinpath('gui/ui/resources/resources.qrc')) +] +RES_DEST = str(BASE_DIR.joinpath('resources_rc.py')) +UI_DIR = str(BASE_DIR.joinpath('gui/ui')) + + +def compile_ui(ui_directory, resource_files, resource_dest, base_module='dgp', + resource_suffix='_rc') -> None: + """Compile Qt .ui and .qrc files into .py files for direct import. + + Parameters + ---------- + ui_directory : str + String path to directory containing .ui files to compile + resource_files : List of str + List of string paths to Qt resource .qrc files to compile + resource_dest : str + Destination path/name for the compiled resource file + base_module : str, optional + Module name which .ui files will import the compiled resources_rc.py + file from. Default is to import from the root 'dgp' module + resource_suffix : str, optional + Optional suffix used by ui files to load resources. Default is '_rc' + + Notes + ----- + Compiled .ui files are output to the same directory as their source + + """ + processResourceFile(resource_files, resource_dest, None) + compileUiDir(ui_directory, from_imports=True, import_from=base_module, + resource_suffix=resource_suffix) + + +if __name__ == '__main__': + compile_ui(UI_DIR, RES_FILES, RES_DEST)