diff --git a/carte-orientation.py b/carte-orientation.py deleted file mode 100644 index 0933dcf..0000000 --- a/carte-orientation.py +++ /dev/null @@ -1,119 +0,0 @@ -# 🄯 Association Linux-Alpes -# Contributeurs : Jean-Christophe Becquet (APITUX), Jacky Volpes, Arnaud Champollion -# mercredi 13 janvier 2021 -# licence GPL version 3 ou supérieure -# ce script fait partie du projet CaliÉc -# voir http://www.linux-alpes.org/caliec/ - -import shutil -import tempfile - -from pathlib import Path - -from processing.tools import dataobjects - -def main(): - # Paramètres du projet - tempdir = tempfile.TemporaryDirectory() - styles_url = 'https://forge.chapril.org/linux_alpes/caliec/raw/branch/master/styles/' - lambert93 = QgsCoordinateReferenceSystem("EPSG:2154") - wgs = QgsCoordinateReferenceSystem("EPSG:4326") - wgspm = QgsCoordinateReferenceSystem("EPSG:3857") - scr = wgspm - project = QgsProject.instance() - project.setCrs(scr) - options = QgsVectorFileWriter.SaveVectorOptions() - options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteFile - options.driverName = "GPKG" - context = dataobjects.createContext() - context.setInvalidGeometryCheck(QgsFeatureRequest.GeometryNoCheck) - - # Correspondances des noms des couches et des styles: - # "NOM_DE_LA_COUCHE_OSM": ("nom_du_style", "nom_du_layer") - # Commenter les couches non désirées - # L'ordre impacte directement l'ordre final des couches - names = { - #"OUTPUT_OTHER_RELATIONS": (None, "Autres"), - "OUTPUT_MULTIPOLYGONS": ("multipolygon", "Surfaces"), - #"OUTPUT_MULTILINESTRINGS": (None, "Multilignes"), - "OUTPUT_LINES": ("linestring", "Lignes"), - "OUTPUT_POINTS": ("point", "Points"), - } - - # Vérif de l'échelle - if iface.mapCanvas().scale() > 10000: - if QMessageBox.warning(iface.mainWindow(), "Zone étendue", - "La zone est étendue et le téléchargement risque de prendre longtemps", - QMessageBox.Ok | QMessageBox.Cancel) == QMessageBox.Cancel: - return - - # Paramétrage du dossier de travail - settings = QSettings() - dir = QFileDialog.getExistingDirectory(iface.mainWindow(), - "Sélectionnez un dossier de travail", - settings.value("caliec/workingDir")) - if dir == "": - return - settings.setValue("caliec/workingDir", dir) - workDir = Path(dir) - - # Construction de la requête overpass - try: - url = processing.run("quickosm:buildqueryextent", {"EXTENT": iface.mapCanvas().extent()})["OUTPUT_URL"] - except QgsProcessingException: - QMessageBox.warning(iface.mainWindow(), "Attention", "Vous n'avez pas installé l'extension QuickOSM") - return - - # Barre de chargement animée - qApp.setOverrideCursor(Qt.WaitCursor) - message_bar = iface.messageBar() - progress_bar = QProgressBar() - progress_bar.setMaximum(0) - widget = message_bar.createMessage("Chargement", "Récupération des data en ligne") - widget.layout().addWidget(progress_bar) - message_bar.pushWidget(widget) - - # Téléchargement du fichier osm et création des couches - osmfile = str(Path(tempdir.name) / "osm.xml") - processing.run("native:filedownloader", {"URL": url, "OUTPUT": osmfile}) - layers = processing.run("quickosm:openosmfile", {"FILE": osmfile}) - - for osm_name, style_layer_names in names.items(): - style_name, layer_name = style_layer_names - - # On explose les champs - layer = processing.run("native:explodehstorefield", parameters={"INPUT": layers[osm_name], "FIELD": "other_tags", "OUTPUT": "memory:"}, context=context)["OUTPUT"] - - # On enregistre le layer dans le gpkg - options.layerName = layer_name - code, error = QgsVectorFileWriter.writeAsVectorFormat(layer, str(workDir / "data.gpkg"), options) - if code != 0: - QMessageBox.warning(None, 'Erreur', f"Erreur à l'export de la couche {layer_name} : \n\n{error}") - return - new_layer = QgsVectorLayer(str(workDir / f"data.gpkg|layername={layer_name}"), layer_name) - - # Les layers suivants seront enregistrés dans le gpkg déjà existant - options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer - - # On charge le style - if style_name is not None: - stylefile = str((Path(tempdir.name) / style_name).with_suffix('.qml')) - processing.run("native:filedownloader", {"URL": styles_url + f"{style_name}.qml", "OUTPUT": stylefile}) - new_layer.loadNamedStyle(stylefile) - - # On charge le nouveau layer - project.addMapLayer(new_layer) - - try: - project.removeMapLayer(project.mapLayersByName("OpenStreetMap")[0]) - except IndexError: - pass - iface.mapCanvas().refreshAllLayers() - project.write(str(workDir / 'orient.qgs')) - - -try: - main() -finally: - iface.messageBar().popWidget() - qApp.restoreOverrideCursor() diff --git a/orientation/__init__.py b/orientation/__init__.py new file mode 100644 index 0000000..f223cad --- /dev/null +++ b/orientation/__init__.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +""" +/*************************************************************************** + Orientation + A QGIS plugin + Réaliser des cartes d’orientation + Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/ + ------------------- + begin : 2021-03-01 + copyright : (C) 2021 by Association Linux-Alpes + email : caliec@linux-alpes.org + git sha : $Format:%H$ + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + This script initializes the plugin, making it known to QGIS. +""" + + +# noinspection PyPep8Naming +def classFactory(iface): # pylint: disable=invalid-name + """Load Orientation class from file Orientation. + + :param iface: A QGIS interface instance. + :type iface: QgsInterface + """ + # + from .orientation import Orientation + return Orientation(iface) diff --git a/orientation/i18n/fr.ts b/orientation/i18n/fr.ts new file mode 100644 index 0000000..739632b --- /dev/null +++ b/orientation/i18n/fr.ts @@ -0,0 +1,11 @@ + + + + @default + + + Good morning + Bonjour + + + diff --git a/orientation/icon.png b/orientation/icon.png new file mode 100644 index 0000000..c30804a Binary files /dev/null and b/orientation/icon.png differ diff --git a/orientation/metadata.txt b/orientation/metadata.txt new file mode 100644 index 0000000..263ec5d --- /dev/null +++ b/orientation/metadata.txt @@ -0,0 +1,46 @@ +# This file contains metadata for your plugin. + +# This file should be included when you package your plugin.# Mandatory items: + +[general] +name=CaLiÉc +qgisMinimumVersion=3.0 +description=Réaliser des cartes d’orientation +version=1.0 +author=Association Linux-Alpes +email=caliec@linux-alpes.org + +about=Permettre la production de supports pour l’enseignement en géographie et EPS (course d’orientation) à l’école primaire. En effet la représentation de l’espace y est travaillée sur des zones peu étendues, et la symbologie doit être adaptée à l’âge des élèves. + +tracker=https://forge.chapril.org/linux_alpes/caliec/issues +repository=https://forge.chapril.org/linux_alpes/caliec/ +# End of mandatory metadata + +# Recommended items: + +hasProcessingProvider=no +# Uncomment the following line and add your changelog: +# changelog= + +# Tags are comma separated with spaces allowed +tags=python, osm + +homepage=http://www.linux-alpes.org/caliec/ +category=Plugins +icon=icon.png +# experimental flag +experimental=False + +# deprecated flag (applies to the whole plugin, not just a single version) +deprecated=False + +# Since QGIS 3.8, a comma separated list of plugins to be installed +# (or upgraded) can be specified. +plugin_dependencies=QuickOSM + +Category of the plugin: Raster, Vector, Database or Web +# category= + +# If the plugin can run on QGIS Server. +server=False + diff --git a/orientation/orientation.py b/orientation/orientation.py new file mode 100644 index 0000000..4dd2449 --- /dev/null +++ b/orientation/orientation.py @@ -0,0 +1,302 @@ +# -*- coding: utf-8 -*- +""" +/*************************************************************************** + Orientation + A QGIS plugin + Réaliser des cartes d’orientation + Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/ + ------------------- + begin : 2021-03-01 + git sha : $Format:%H$ + copyright : (C) 2021 by Association Linux-Alpes + email : caliec@linux-alpes.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +""" +from qgis.PyQt.QtCore import Qt, QSettings, QTranslator, QCoreApplication +from qgis.PyQt.QtGui import QIcon +from qgis.PyQt.QtWidgets import QAction, qApp, QFileDialog, QProgressBar, QMessageBox + +from qgis.core import QgsCoordinateReferenceSystem, QgsProject, QgsVectorFileWriter, QgsVectorLayer, QgsFeatureRequest +from processing import QgsProcessingException + + +# Initialize Qt resources from file resources.py +from .resources import * + +import processing +import os.path +import shutil +import tempfile + +from pathlib import Path + +from processing.tools import dataobjects + +class Orientation: + """QGIS Plugin Implementation.""" + + def __init__(self, iface): + """Constructor. + + :param iface: An interface instance that will be passed to this class + which provides the hook by which you can manipulate the QGIS + application at run time. + :type iface: QgsInterface + """ + # Save reference to the QGIS interface + self.iface = iface + # initialize plugin directory + self.plugin_dir = os.path.dirname(__file__) + # initialize locale + locale = QSettings().value('locale/userLocale')[0:2] + locale_path = os.path.join( + self.plugin_dir, + 'i18n', + 'Orientation_{}.qm'.format(locale)) + + if os.path.exists(locale_path): + self.translator = QTranslator() + self.translator.load(locale_path) + QCoreApplication.installTranslator(self.translator) + + # Declare instance attributes + self.actions = [] + self.menu = self.tr(u'&CaLiÉc') + + # Check if plugin was started the first time in current QGIS session + # Must be set in initGui() to survive plugin reloads + self.first_start = None + + # noinspection PyMethodMayBeStatic + def tr(self, message): + """Get the translation for a string using Qt translation API. + + We implement this ourselves since we do not inherit QObject. + + :param message: String for translation. + :type message: str, QString + + :returns: Translated version of message. + :rtype: QString + """ + # noinspection PyTypeChecker,PyArgumentList,PyCallByClass + return QCoreApplication.translate('Orientation', message) + + + def add_action( + self, + icon_path, + text, + callback, + enabled_flag=True, + add_to_menu=True, + add_to_toolbar=True, + status_tip=None, + whats_this=None, + parent=None): + """Add a toolbar icon to the toolbar. + + :param icon_path: Path to the icon for this action. Can be a resource + path (e.g. ':/plugins/foo/bar.png') or a normal file system path. + :type icon_path: str + + :param text: Text that should be shown in menu items for this action. + :type text: str + + :param callback: Function to be called when the action is triggered. + :type callback: function + + :param enabled_flag: A flag indicating if the action should be enabled + by default. Defaults to True. + :type enabled_flag: bool + + :param add_to_menu: Flag indicating whether the action should also + be added to the menu. Defaults to True. + :type add_to_menu: bool + + :param add_to_toolbar: Flag indicating whether the action should also + be added to the toolbar. Defaults to True. + :type add_to_toolbar: bool + + :param status_tip: Optional text to show in a popup when mouse pointer + hovers over the action. + :type status_tip: str + + :param parent: Parent widget for the new action. Defaults None. + :type parent: QWidget + + :param whats_this: Optional text to show in the status bar when the + mouse pointer hovers over the action. + + :returns: The action that was created. Note that the action is also + added to self.actions list. + :rtype: QAction + """ + + icon = QIcon(icon_path) + action = QAction(icon, text, parent) + action.triggered.connect(callback) + action.setEnabled(enabled_flag) + + if status_tip is not None: + action.setStatusTip(status_tip) + + if whats_this is not None: + action.setWhatsThis(whats_this) + + if add_to_toolbar: + # Adds plugin icon to Plugins toolbar + self.iface.addToolBarIcon(action) + + if add_to_menu: + self.iface.addPluginToMenu( + self.menu, + action) + + self.actions.append(action) + + return action + + def initGui(self): + """Create the menu entries and toolbar icons inside the QGIS GUI.""" + + icon_path = ':/plugins/caliec/icon.png' + self.add_action( + icon_path, + text=self.tr(u'Créer le projet'), + callback=self.run, + parent=self.iface.mainWindow()) + + # will be set False in run() + self.first_start = True + + + def unload(self): + """Removes the plugin menu item and icon from QGIS GUI.""" + for action in self.actions: + self.iface.removePluginMenu( + self.tr(u'&CaLiÉc'), + action) + self.iface.removeToolBarIcon(action) + + + def run(self): + try: + self.main() + finally: + self.iface.messageBar().popWidget() + qApp.restoreOverrideCursor() + + def main(self): + # Paramètres du projet + tempdir = tempfile.TemporaryDirectory() + styles_url = 'https://forge.chapril.org/linux_alpes/caliec/raw/branch/master/styles/' + lambert93 = QgsCoordinateReferenceSystem("EPSG:2154") + wgs = QgsCoordinateReferenceSystem("EPSG:4326") + wgspm = QgsCoordinateReferenceSystem("EPSG:3857") + scr = wgspm + project = QgsProject.instance() + project.setCrs(scr) + options = QgsVectorFileWriter.SaveVectorOptions() + options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteFile + options.driverName = "GPKG" + context = dataobjects.createContext() + context.setInvalidGeometryCheck(QgsFeatureRequest.GeometryNoCheck) + + # Correspondances des noms des couches et des styles: + # "NOM_DE_LA_COUCHE_OSM": ("nom_du_style", "nom_du_layer") + # Commenter les couches non désirées + # L'ordre impacte directement l'ordre final des couches + names = { + #"OUTPUT_OTHER_RELATIONS": (None, "Autres"), + "OUTPUT_MULTIPOLYGONS": ("multipolygon", "Surfaces"), + #"OUTPUT_MULTILINESTRINGS": (None, "Multilignes"), + "OUTPUT_LINES": ("linestring", "Lignes"), + "OUTPUT_POINTS": ("point", "Points"), + } + + # Vérif de l'échelle + if self.iface.mapCanvas().scale() > 10000: + if QMessageBox.warning(self.iface.mainWindow(), "Zone étendue", + "La zone est étendue et le téléchargement risque de prendre longtemps", + QMessageBox.Ok | QMessageBox.Cancel) == QMessageBox.Cancel: + return + + # Paramétrage du dossier de travail + settings = QSettings() + dir = QFileDialog.getExistingDirectory(self.iface.mainWindow(), + "Sélectionnez un dossier de travail", + settings.value("caliec/workingDir")) + if dir == "": + return + settings.setValue("caliec/workingDir", dir) + workDir = Path(dir) + + # Construction de la requête overpass + try: + url = processing.run("quickosm:buildqueryextent", + parameters={"EXTENT": self.iface.mapCanvas().extent()})["OUTPUT_URL"] + except QgsProcessingException: + QMessageBox.warning(self.iface.mainWindow(), "Attention", "Vous n'avez pas installé l'extension QuickOSM") + return + + # Barre de chargement animée + qApp.setOverrideCursor(Qt.WaitCursor) + message_bar = self.iface.messageBar() + progress_bar = QProgressBar() + progress_bar.setMaximum(0) + widget = message_bar.createMessage("Chargement", "Récupération des data en ligne") + widget.layout().addWidget(progress_bar) + message_bar.pushWidget(widget) + + # Téléchargement du fichier osm et création des couches + osmfile = str(Path(tempdir.name) / "osm.xml") + processing.run("native:filedownloader", {"URL": url, "OUTPUT": osmfile}) + layers = processing.run("quickosm:openosmfile", {"FILE": osmfile}) + + for osm_name, style_layer_names in names.items(): + style_name, layer_name = style_layer_names + + # On explose les champs + layer = processing.run("native:explodehstorefield", + parameters={"INPUT": layers[osm_name], + "FIELD": "other_tags", "OUTPUT": "memory:"}, + context=context)["OUTPUT"] + + # On enregistre le layer dans le gpkg + options.layerName = layer_name + code, error = QgsVectorFileWriter.writeAsVectorFormat(layer, str(workDir / "data.gpkg"), options) + if code != 0: + QMessageBox.warning(None, 'Erreur', f"Erreur à l'export de la couche {layer_name} : \n\n{error}") + return + new_layer = QgsVectorLayer(str(workDir / f"data.gpkg|layername={layer_name}"), layer_name) + + # Les layers suivants seront enregistrés dans le gpkg déjà existant + options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer + + # On charge le style + if style_name is not None: + stylefile = str((Path(tempdir.name) / style_name).with_suffix('.qml')) + processing.run("native:filedownloader", + parameters={"URL": styles_url + f"{style_name}.qml", "OUTPUT": stylefile}) + new_layer.loadNamedStyle(stylefile) + + # On charge le nouveau layer + project.addMapLayer(new_layer) + + try: + project.removeMapLayer(project.mapLayersByName("OpenStreetMap")[0]) + except IndexError: + pass + self.iface.mapCanvas().refreshAllLayers() + project.write(str(workDir / 'orient.qgs')) + diff --git a/orientation/resources.py b/orientation/resources.py new file mode 100644 index 0000000..3acbabb --- /dev/null +++ b/orientation/resources.py @@ -0,0 +1,774 @@ +# -*- coding: utf-8 -*- + +# Resource object code +# +# Created by: The Resource Compiler for PyQt5 (Qt v5.15.2) +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore + +qt_resource_data = b"\ +\x00\x00\x2c\x6f\ +\x89\ +\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\ +\x00\x00\x68\x00\x00\x00\x75\x08\x06\x00\x00\x00\xa2\x54\xa4\xe4\ +\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\x13\x00\x00\ +\x0b\x13\x01\x00\x9a\x9c\x18\x00\x00\x00\x07\x74\x49\x4d\x45\x07\ +\xe5\x03\x01\x0c\x25\x29\xd6\x1a\x8c\xcb\x00\x00\x20\x00\x49\x44\ +\x41\x54\x78\xda\xed\x5d\x77\x78\x14\xc5\xdf\xff\xcc\x5e\xca\xa5\ +\x57\x08\x09\xa1\x06\x88\x04\x41\x08\x45\x3a\x0a\x88\x20\xd5\x50\ +\x14\x44\x40\xf9\x59\x29\x22\x22\x22\x8a\xa2\x40\x00\x51\x10\x50\ +\xa9\x2a\x88\x8a\x09\x22\x55\x40\x42\x8d\x84\x00\x09\xcd\x84\x12\ +\x20\x60\x20\x80\x94\x40\x48\xcf\x25\x77\xf3\xfe\x71\x5b\x66\xf7\ +\x76\xf7\xf6\x02\xfe\x5e\xdf\xf7\x71\xf3\xdc\x93\xdd\xd9\x99\xd9\ +\xa9\xdf\xfa\x99\x19\x42\x29\xc5\xbf\xd7\x3f\xf7\xe2\xfe\x6d\x82\ +\x7f\x78\x07\x09\x33\x48\xef\xbf\x91\x38\xc2\x65\x34\x6e\x55\xd3\ +\xb8\x92\xaf\xab\xf9\xff\x9d\xe5\x56\x4b\xa3\x57\x1f\xe1\x9e\xfc\ +\xb7\x49\x1c\xa5\x14\x84\x90\xff\x77\xdf\xfa\xbb\x2e\xf2\x2f\x0f\ +\xfa\x67\x5f\x6e\xca\x51\x26\x3c\xeb\x75\x9c\x32\xbe\xda\x7b\x65\ +\x38\x1b\x66\x34\x7f\xa3\xf1\x8d\xc6\xd1\xca\x5f\x99\x87\x32\x2f\ +\x67\xcf\xae\x96\x45\xeb\x3b\xaa\x71\x6d\x36\x9b\x4b\x95\x73\xb5\ +\x11\x5d\x69\x5c\xbd\xb8\xae\x54\xca\x48\xd9\x1f\x64\x87\xff\x9d\ +\xdf\xf9\x97\xc4\xfd\x5f\x12\xb3\xf5\x24\x14\x23\xef\xb5\xf2\xd2\ +\x4b\xaf\xc7\xe0\x5d\x7d\xef\xca\x60\x63\x25\x28\x23\xf9\xdf\xef\ +\xf7\xaa\x5a\x16\x37\x23\xb4\xd9\x15\x69\x49\xed\x5e\xf8\xaf\x75\ +\xaf\x97\x2e\x25\x25\x85\x26\x27\x27\x6b\x7e\x3b\x3a\x3a\x1a\x71\ +\x71\x71\x44\x29\xad\x09\x79\x7c\xfb\xed\xb7\xf4\xfa\xf5\xeb\xaa\ +\x69\x9b\x36\x6d\x8a\xbe\x7d\xfb\x12\x35\x69\x4f\x59\x3e\xb5\xbc\ +\x95\x64\x57\x8f\x97\xeb\xd5\x57\xd9\xf6\xb2\x7e\x60\xe5\xf1\x7f\ +\xe2\x6f\xfa\xf4\xe9\x14\x00\xf5\xf3\xf3\xa3\x01\x01\x01\xb2\x9f\ +\x9f\x9f\x1f\xf5\xf6\xf6\xa6\x19\x19\x19\x54\x2b\x7d\x6c\x6c\x2c\ +\xe5\x38\x4e\x96\xce\xdf\xdf\x9f\x12\x42\xe8\xf0\xe1\xc3\xe9\x3f\ +\xbd\xfe\x6e\x7a\xd2\xcc\x83\x60\x86\x6a\x12\x50\x55\x66\x69\xf2\ +\xfe\x64\xd4\xa9\x53\x47\x16\x66\xb1\x58\xd0\xa7\x6f\x1f\xf4\xec\ +\xd9\x13\x07\x0e\x1c\xa0\x75\xea\xd4\x21\x6a\x65\x89\x89\x89\xc1\ +\xde\x3d\x7b\x61\x32\x99\x00\x00\xf9\xf9\xf9\x68\xd5\xba\x95\x4b\ +\x52\xa8\xd1\x70\xe5\xbd\x2b\x75\x55\xcb\x9f\xd3\xa3\xad\xf7\xab\ +\xe4\xa9\x7d\x50\x18\x19\xce\xf2\x56\xbe\xf7\xf7\xf7\x47\x60\x60\ +\x20\x02\x83\xec\xbf\xa0\xa0\x20\x54\x0f\xab\x8e\x29\xef\x4c\xc1\ +\xd5\xab\x57\xb1\x78\xf1\x62\xcd\xb2\x9b\x4c\x26\x04\x05\x05\x89\ +\x69\x03\x02\x02\xc0\x11\xce\xb0\x82\xeb\xac\xa1\xd5\x78\xab\xb3\ +\x34\x02\x89\xd4\xca\x47\x78\xcf\x09\x91\xd8\x04\x6a\x3c\x42\xed\ +\xbd\x1a\x5f\x71\x96\x5e\x2f\x1f\x36\x5c\xad\x93\x08\x21\x10\xfe\ +\x28\xa5\x20\x20\x18\x30\x60\x00\x06\x0d\x1a\x84\xa5\x4b\x97\x22\ +\x33\x33\x93\xea\xa6\xe7\xff\xd4\x06\x82\xd6\xf7\xf5\xea\xe7\x2c\ +\x4c\xaf\xfd\xb4\xbe\xaf\x4c\xcf\x29\x6d\x43\x42\x81\x9c\xd9\xc1\ +\xd8\x9f\x5a\x1a\xf6\x9e\x7d\xef\xec\xa7\x66\xa7\x12\x47\x18\xf3\ +\xb7\x6a\xf5\x2a\xdc\xb9\x73\x07\x9c\x89\xc3\x9a\xef\xd6\xa0\x49\ +\x93\x26\x18\x3b\x76\x2c\x2a\x2a\x2a\x74\xd3\xeb\xd9\xe9\xb4\xca\ +\xaa\x55\x3f\xbd\x30\x23\xed\xa7\x65\x9b\x63\xdf\x73\x0f\x42\x74\ +\xbc\x5f\x91\xd9\xf8\x87\xa4\xff\x3b\x76\xec\xc0\xaa\xd5\xab\x00\ +\x0a\x78\x9a\x3d\x31\x7e\xdc\x78\x1c\x3e\x7c\x18\x9f\x7d\xf6\x19\ +\xd5\xcf\xe2\xef\x15\xdf\x1f\x64\xbb\x89\x1d\x64\x84\xf4\x18\x25\ +\x51\xce\xe2\xe9\x3d\xeb\x91\x02\x19\x89\x23\x04\x15\x96\x0a\xcc\ +\x98\x31\x03\xe7\xce\x9f\x03\x00\x0c\x1b\x36\x0c\x4f\x74\x7f\x02\ +\x33\x66\xcc\x40\x7a\x7a\x3a\x55\xa3\xf1\x7a\xbc\xc0\x08\x29\xbf\ +\xdf\x5f\x55\xf2\xe7\x9c\x49\x6c\x46\x94\x4b\x3d\xa5\x4e\xad\x91\ +\xb5\x98\xa9\xf2\x9d\x33\x12\x95\x9f\x9f\x8f\x99\x33\x67\x02\x14\ +\x20\x1c\x41\x7c\x7c\x3c\x00\x60\xda\xb4\x69\xea\xd2\x16\x88\xcb\ +\xba\x9c\x11\x65\x5d\x4d\xd9\xd4\x12\x1c\xf4\x4c\x63\x6a\x69\x38\ +\x67\x3c\xc6\x19\xfd\x74\x96\xc6\x15\x5e\xe3\x74\xca\x53\x9e\x0f\ +\x31\xf1\x12\x12\x12\x70\xf0\xe0\x41\x80\x02\x4d\x9a\x34\xc1\xf2\ +\xe5\xcb\xb1\x77\xef\x5e\xec\xdc\xb9\x93\xaa\x76\x30\xd5\xd6\xe2\ +\x9d\xf9\x9b\x9c\xdd\xbb\xda\x56\x46\xda\x9a\xd3\x1b\xe5\x5a\xa2\ +\xaf\x2b\xf1\xb5\x24\x16\xad\xb8\xae\x88\xf8\xd5\xaa\x55\x43\xcb\ +\x96\x2d\xd1\xbb\x4f\x6f\x9c\x3e\x7d\x1a\x84\x23\x18\x36\x74\x18\ +\xfa\xf6\xed\x8b\xe7\x9f\x7f\x1e\x07\x0f\x1e\xa4\x46\x49\x9c\x1a\ +\xb9\x73\x26\xfa\xab\x91\x2d\x3d\x31\x5a\xab\x1d\xb4\xda\x09\x80\ +\xa3\x98\x6d\x44\x04\x66\xc5\x4e\xbd\xf4\x5a\x8d\xa0\x25\x56\x1a\ +\xe2\x41\x54\x7a\xef\xee\xee\x8e\x89\x13\x27\xe2\xde\xbd\x7b\xf8\ +\xea\xab\xaf\x00\x0a\x70\x1c\x87\x49\x6f\x4d\x42\x5e\x5e\x1e\x3e\ +\xff\xfc\x73\x47\x31\xbb\x8a\x8d\xef\x6a\x3d\xd5\x78\x9c\x96\xfa\ +\xa1\x36\x48\x45\x1e\x54\x55\x05\xf4\x7e\xde\xdf\x97\x14\x47\x20\ +\x23\x53\x3d\x7b\xf6\xc4\xf8\xf1\xe3\xb1\xf2\xeb\x95\x22\xa9\x7b\ +\xf4\xd1\x47\x31\x76\xec\x58\x6c\xdc\xb8\x11\x67\xcf\x9e\x75\x94\ +\x02\xff\x6e\x2f\xe8\x7d\xb6\x8f\x6c\x06\x69\xe9\x1d\x6a\x74\xd5\ +\x08\xbf\x71\x46\x8b\xf5\x78\x8f\x11\x3d\x48\xe0\x43\x6c\x65\x3e\ +\xfd\xf4\x53\xb4\x6d\xdb\x16\x13\xde\x9c\x00\x4b\x85\x05\x00\xf0\ +\xc9\xdc\x4f\xf0\xd4\x53\x4f\xa1\xa4\xa4\xc4\x10\x0f\x32\xc2\x3f\ +\xb5\xd2\x68\x59\xfe\x8d\xf0\x1d\x67\xdf\xe0\xd4\xa4\x29\x35\x89\ +\x4a\x4d\x0a\xd1\xb2\x00\x3b\x93\xde\xb4\x68\xbd\xde\xf4\x17\xa5\ +\x30\xe2\x18\xee\xee\xee\x8e\xc9\x93\x27\x23\x23\x23\x03\x53\xde\ +\x9d\x02\x4a\x29\x3c\x3d\x3c\x31\xe5\x9d\x29\x70\x73\x73\x73\x48\ +\xaf\xc7\x83\x5c\xe5\x2f\x6a\xe4\x5f\x49\xda\xd4\x2c\x11\xce\xc8\ +\xb9\x10\xe6\x66\x84\x79\xeb\x3d\x6b\xd9\xad\xb4\xf2\x35\x9a\x5e\ +\x93\x0c\x30\x33\xa0\xa0\xa0\x00\xef\xbd\xf7\x1e\x2c\x16\x0b\x8a\ +\x8b\x8b\xe1\xe1\xe1\x81\x2f\xbe\xf8\x02\x7d\xfb\xf4\xc5\xe3\x8f\ +\x3d\x8e\x76\x6d\xdb\x61\xec\x98\xb1\xd8\xbb\x6f\xaf\x26\x99\x53\ +\x36\x9e\xd1\x72\x6b\xb9\x24\x8c\xb4\xa1\x2b\xed\xe4\xa6\xa7\xd3\ +\x38\xb3\x52\x1b\xd1\x88\x8d\xc4\xd3\xd2\x9b\x1c\xa6\xbd\xa2\x75\ +\x8b\x8a\x8a\xb0\x68\xd1\x22\x69\x7e\x10\x80\x52\x60\xfe\x82\xf9\ +\x78\xec\xb1\xc7\x00\x00\xaf\xbf\xfe\x3a\x8e\x1d\x3b\xa6\x6b\x45\ +\xb8\xdf\x3a\xaa\x51\x8d\x07\x81\xed\x00\x00\x37\xb5\x4c\x5d\x75\ +\x5c\x19\x0d\xd7\x9a\x41\xca\xf0\xdb\xb7\x6f\xcf\xd9\xb6\x6d\xdb\ +\x3b\xbb\x76\xed\xc2\xb6\x6d\xdb\xe4\x69\x99\x7a\xf8\x06\x04\x63\ +\xdc\x47\x2b\xe0\x1f\x18\x02\x4f\x2f\x6f\x98\xbd\x7d\x71\x29\xeb\ +\x24\x3e\x7f\x77\x24\x12\x12\x12\x30\x64\xc8\x10\x34\x68\xd8\x00\ +\xab\x56\xad\x92\x66\x09\x93\x7e\xe3\xc6\x8d\x18\x34\x68\x10\xed\ +\xd6\xad\x1b\xfa\xf7\xef\x8f\x88\x88\x08\xa2\x55\x1f\x23\xb3\x5f\ +\x2d\xdc\x88\xc0\xa4\x96\x8f\x18\x26\x8c\x52\x9b\xcd\x06\x9b\xcd\ +\x26\x7b\x56\xbb\xaf\xca\x7b\xad\x34\xc2\xb3\xf0\xff\xf8\xf1\xe3\ +\x74\xe0\xc0\x81\x34\x24\x24\x84\xf2\xc4\x88\x9a\x4c\x6e\x14\x00\ +\xcd\xbe\x90\x4d\xa9\x8d\x52\x6a\xa5\x94\xda\x28\x7d\x7a\xc0\xd3\ +\x34\xb8\x7a\x04\x4d\x4c\x2b\xa4\x9b\x4f\xd9\xe8\xe6\x4c\x1b\xdd\ +\x72\x8a\xd2\xcd\x99\x36\xda\xb1\xe7\x10\xea\xef\xef\x4f\x53\x52\ +\x52\x28\xb5\x52\x6a\xb3\xda\xc4\x74\xd4\x4a\x69\xde\xed\x3c\x1a\ +\x1a\x12\x2a\xe6\x2d\x38\x04\x7b\xf6\xec\x49\x93\x92\x92\xa8\xd1\ +\x3a\x2a\xeb\xa6\x8c\xa3\x97\x5e\xed\x59\x2d\x3e\xe7\x4c\xa9\x74\ +\x85\x86\xba\x4a\x77\x09\x21\xb0\x5a\xad\x38\x76\xec\x18\x9d\x34\ +\x69\x12\xed\xdc\xb9\x33\xd6\xaf\x5f\x0f\xb8\x79\xa1\xef\xf0\xf1\ +\x98\xf6\xe5\x66\xc4\xbd\xf8\xb6\xd2\x5e\xa3\x62\xc2\xb1\xe7\x57\ +\x78\xef\x0e\x8a\xee\xdd\xc5\x90\x97\xa6\xa2\xb4\xcc\x82\x59\xb3\ +\x66\xc1\x6a\xb3\xda\xbf\xab\x92\xae\xc3\x93\x83\x31\xeb\x9b\x3d\ +\x18\xfc\xf2\x54\xf8\x06\x85\xe1\xb7\xdf\x76\xa2\x4f\x9f\x3e\x18\ +\x35\x6a\x14\x3d\x70\xe0\x00\xad\xac\xac\x74\x49\x34\xd6\xe3\xd7\ +\xce\x78\xb9\x56\xfb\xbb\x29\x7d\xea\x6a\xff\x9d\x39\xe4\xb4\x70\ +\x63\x7a\x95\xb2\xd9\x6c\x38\x74\xe8\x10\x9d\x3d\x7b\x36\xb6\x6f\ +\xdf\x0e\x80\xa0\x6d\xf7\xa7\xd1\x63\xe0\x68\xc4\xb4\xe8\x08\x4f\ +\x6f\x1f\x00\x14\xd9\xa7\xed\xfc\xe3\xfd\x69\xef\xc3\xcf\xcf\x4f\ +\x4c\x7f\xfc\xc4\x71\x59\x17\x65\xa4\xed\xc7\xac\x71\x03\x40\xa9\ +\x0d\x53\x17\x6d\xc0\x90\x57\xa6\x22\x61\xe9\x4c\x3c\x37\xfc\x39\ +\x04\x04\x04\xc8\xbe\x5d\x5e\x5e\x8e\xa2\xe2\x22\x98\x4c\x26\x34\ +\x7d\xf4\x71\x34\x7b\xf4\x71\x0c\x7d\xed\x03\x9c\xcf\x4c\xc7\xee\ +\x4d\xab\xf0\x53\xe2\x8f\xf8\xee\xbb\xef\xd0\xbe\x7d\x7b\x1a\x1f\ +\x1f\x8f\x76\xed\xda\x11\x77\x77\x77\x55\xfe\xe2\xac\xad\x8c\xb4\ +\xad\x96\x0d\x50\xc6\x83\x9c\xfd\x77\xc6\xe8\x8c\x9a\x7f\x00\xa0\ +\xa2\xa2\x02\xb3\x66\xcd\xa2\x33\x67\xce\x84\xcd\x66\x43\xdd\xe8\ +\x47\x30\x7c\xdc\x0c\xb4\xee\xfc\x14\x08\xc7\x31\xfa\x28\x81\xc9\ +\xcd\x1d\x9e\x66\x6f\xfc\xb2\x61\x93\x43\x3e\xc1\xd5\xc2\xed\xf1\ +\x28\xc5\xf6\x84\x25\x28\x2e\xcc\x07\x00\x6c\xf9\x7e\x11\xa6\x7e\ +\xbe\x1e\xd9\xa7\x8f\x61\xe3\xa6\x2d\x9a\x86\x7c\x37\x0f\x4f\x3e\ +\x3d\xe0\xee\xe1\x89\x98\xd8\x0e\x68\xdc\xa2\x3d\x7a\x0e\x7e\x05\ +\x2b\xe6\xbc\x81\xd4\xd4\x43\xe8\xd6\xad\x1b\x46\x8c\x18\x41\x17\ +\x2e\x5c\x48\x7c\x7d\x7d\xab\xd4\x56\x46\xe3\xab\x52\x9d\xbf\x1b\ +\x17\xa7\xd4\xa9\x36\x6f\xde\x4c\xe7\xcd\x9b\x87\x94\x94\x83\xa8\ +\x59\xb7\x21\x86\xbc\xf2\x3e\x1e\xeb\x3d\x0c\x1c\x67\x92\xc8\x10\ +\x65\x71\x07\xa5\x28\x2f\x2b\x55\x6f\x62\x8e\x83\xb7\x6f\x00\xce\ +\x9f\x4a\xc7\xd4\x51\x8f\xa3\xbc\xb4\xd8\x3e\xea\xdc\x3d\xb0\xe8\ +\x97\x13\x08\xab\x59\x0f\xe5\x65\x25\x9a\x65\x73\xf7\xf0\x84\xd9\ +\xec\x0d\x08\x0d\x43\x25\x12\x4a\xa9\x0d\xc7\x52\x76\xe2\x9b\x79\ +\x93\x70\x25\xfb\x0c\xa2\xa3\x1b\xe1\x93\x4f\x3e\x41\xaf\x5e\xbd\ +\x08\xab\x5b\xb9\x22\x20\x55\xc9\x2a\xa1\xf4\x1a\x1a\x01\x43\xb8\ +\x02\x1a\x61\xc9\xca\xd4\xa9\x53\xe9\xa2\x45\x8b\x60\xf6\xf6\xc3\ +\xa8\xb7\xe6\xe2\xf1\xbe\xcf\xc3\xd3\x6c\x16\x5b\x85\x82\xf2\x2e\ +\x01\xd6\xa6\x43\x44\x01\xd9\xf1\x1d\x50\x59\x51\x81\xd7\xfb\x35\ +\xc1\xf5\xcb\x17\x64\xdf\x6b\xdb\x6d\x00\xde\x9c\xbd\x1a\xde\x3e\ +\x7e\x50\xf6\xbc\x3c\x2f\x75\x6b\x92\x70\x95\x95\x96\xe0\x58\xca\ +\x6f\x58\x31\x67\x02\xf2\xfe\xca\xc5\xe0\xc1\x83\xb1\x6c\xd9\x32\ +\x12\x10\x10\xa0\x2b\xd5\x19\x51\xf6\x9d\xb5\xa1\x68\x8b\x33\xe2\ +\x6b\xd7\x73\x30\x39\x73\x3e\x5d\xbb\x76\x8d\x4e\x9e\x3c\x99\x2e\ +\x5e\xbc\x18\x61\x91\x51\x78\x79\xea\x22\x3c\x39\xe8\x25\x78\x9a\ +\xbd\x00\xca\x88\xbe\xe2\x3d\x91\xd8\x3f\x05\x28\xb5\x1b\x49\xed\ +\xf2\x16\x91\xe2\x82\xe0\xf4\xf1\x14\x87\xce\x01\x80\xb4\xfd\x5b\ +\x71\xea\xe8\xef\x4c\x7c\x7b\x3e\x94\x32\xb8\x04\x4a\x00\x3e\x4c\ +\xb8\x27\xc2\x3d\xec\xe1\x9e\x66\x1f\xb4\xef\x1e\x87\x09\x33\xbf\ +\x45\x58\x64\x3d\x24\x26\x26\x62\xe2\xc4\x89\x34\x27\x27\x87\x1a\ +\x15\x9c\x5c\x31\x44\x3b\x84\x39\xac\x47\xd1\x00\xd8\x39\x93\xf9\ +\xb5\xde\x9f\x39\x73\x86\xf6\xeb\xd7\x0f\x17\x2e\x5c\xc0\xe3\x7d\ +\x87\xe3\xe5\xa9\x8b\xe1\xeb\x17\x68\x1f\xa9\x02\x03\x60\x47\x38\ +\x91\x00\x21\x8e\x36\x52\xf9\x0c\xb3\xd9\xac\xf8\xf0\x95\x9e\x38\ +\x91\xba\x4b\x75\xd6\x3e\xd4\xbc\x1d\xe6\xae\x39\x00\x42\x38\xd9\ +\x1c\x22\x2a\x79\x4a\xff\xf9\x70\x02\x10\x2a\xa5\xa0\xa0\x28\x2b\ +\x29\x42\xe2\xf2\x78\xfc\xf2\xcd\x3c\x84\x86\x86\x20\x31\x31\x11\ +\x5d\xba\x74\x21\x46\x49\x9b\xb3\x38\x6a\x6d\x49\x6c\x36\x9b\x4b\ +\xb0\x29\x57\xae\xf3\xe7\xcf\xd3\xae\x5d\xbb\xe2\xaf\x1b\x37\x11\ +\xf7\xe2\xdb\x18\x3e\xf6\x63\x70\x26\x4e\x9b\x9e\xa8\x0a\xd0\x14\ +\x94\x4a\x6c\x82\x4d\x77\x3e\xf3\x28\x26\x0d\x6d\x0b\x9b\xcd\xaa\ +\x99\xc3\xdc\x35\x07\x10\x13\xdb\x5e\xce\xdb\x78\x8b\x03\xa0\xc8\ +\x57\xef\xfb\x4c\xba\x2d\x3f\x2c\xc6\xd7\x73\x27\xc2\xdb\xdb\x0b\ +\xfb\xf7\xef\x47\x8b\x16\x2d\xc8\xdf\xd1\x7e\xa2\xcb\xdb\xa8\xdf\ +\xc7\x15\xb2\x76\xe0\xc0\x01\xda\xa1\x43\x07\xdc\xb8\x79\x0b\x2f\ +\xbf\xbb\x10\xcf\x8f\x9b\x01\xc2\x99\xec\xe4\x84\x27\x1f\x94\x27\ +\x33\x2c\x89\xa1\x90\x9e\xed\xfc\x91\x6f\x26\x26\x1e\x05\x81\xb5\ +\xb2\x12\x3b\xd7\xaf\x94\x3a\x87\x98\xa4\x8a\xb9\x79\x8a\xf7\xdb\ +\x13\x97\xc2\x8e\xa0\x15\x35\x26\x86\xcc\x49\x24\x4e\x8c\x23\x3e\ +\x0b\xdf\xe7\xe3\x11\x22\x76\x6a\xef\x67\x5f\xc3\xdb\x9f\xae\x85\ +\x0d\x1c\x7a\xf7\xee\x8d\x9f\x7e\xfa\x89\xea\x19\x41\x9d\xf9\xbe\ +\xb4\xde\x8b\xd6\x6c\x35\x32\x67\xc4\x56\xa5\x05\x4a\x3c\x71\xe2\ +\x04\x1d\x34\x68\x10\x0a\x8b\x4b\xf1\x66\xfc\x6a\xf4\x7a\xe6\x55\ +\x80\xb3\xdb\xca\x08\x11\x95\x77\xfb\xe8\x25\xfc\x28\x26\x14\x20\ +\x14\x84\x0f\xa7\x44\x78\x6f\x8f\x40\x08\xb5\xa7\xe5\x7f\x7b\x36\ +\xaf\xc1\x9e\x4d\xdf\xf1\xe2\x9c\x19\x08\xef\x21\x96\x23\xac\xd5\ +\x50\xb1\x93\x0e\xee\x5c\x8f\xac\x3f\x0e\x09\x22\x91\x9d\x74\x31\ +\xdf\xa5\xfc\xb7\x89\x60\x25\x27\x10\xcb\x69\x6f\x30\xa1\xcc\x10\ +\xe3\x98\xdc\xdc\xd1\xf1\xc9\xc1\xf8\xe0\xab\xad\x28\x2a\xb5\xe0\ +\x85\x17\x5e\x80\x60\x81\x50\x7a\x05\xd4\xdc\x0d\xca\x38\x5a\xef\ +\x65\x33\xc8\x99\x95\x55\x4d\xc2\x50\x93\xe3\x2f\x5d\xba\x44\xc7\ +\x8c\x19\x83\xbc\xbc\x3b\x18\xf7\xf1\x0a\x74\xea\xf5\x2c\x6f\x53\ +\xe2\x47\x29\xc3\xe0\xed\xa3\x59\x12\x10\xa4\x11\x0c\x10\x7e\xa6\ +\x40\xe8\x4f\x30\x23\xdb\x46\xb1\x73\xfd\xd7\xb0\x94\xf3\xe2\x77\ +\x64\x5f\x20\xa0\x89\x58\x0e\x73\x68\x3d\x04\x3d\xd4\xcd\x2e\xa6\ +\x97\x97\x62\xc5\xec\x09\xb0\x59\x2b\x79\x61\x03\xe2\x6c\x11\x66\ +\x27\x71\x98\x45\x6c\x79\x20\x96\x93\x32\x61\x94\x02\x31\xb1\x9d\ +\x30\xfa\xed\x4f\x61\x72\x37\xe3\xd5\x57\x5f\xc5\xb5\x6b\xd7\xa8\ +\x96\x4b\x45\xcd\xa5\xaf\x25\x8c\xb1\x6d\xcf\x19\x75\x50\x39\x73\ +\xec\x51\x4a\x71\xeb\xd6\xad\xc4\x7e\xfd\xfa\x21\x35\x35\x15\x23\ +\x27\xce\x41\xe7\x5e\xcf\x0a\x91\x20\xb5\x34\xe1\x85\x66\xca\x77\ +\x0e\x9f\xa7\x20\x20\x08\xef\xf8\x74\x44\x80\x2a\x32\x79\x9c\x4a\ +\x4f\xc6\xb9\x8c\xc3\xbc\x32\xe3\x0f\x3c\x12\x2f\x67\x66\x84\xa0\ +\x7e\xff\x78\x78\x04\xd6\x04\x00\x9c\xcb\x38\x82\xe3\x07\x93\x18\ +\x71\x5d\xe0\x3d\x54\x51\x36\xca\x0b\x08\x94\x17\x1a\xa8\x58\x3e\ +\x71\xc6\x8b\x82\x85\xfd\xae\xfb\x80\x51\x98\x10\xbf\x0a\x39\x97\ +\x2f\xa3\x6d\xdb\xb6\x38\x77\xee\x1c\x55\x03\x3f\x2a\x85\x00\xa3\ +\x3f\xce\x99\x98\xe8\x0c\xa7\xcc\x7e\x70\xdc\xb8\x71\x83\x4f\x9d\ +\x3a\x85\x3e\xcf\x8d\xc3\x80\x11\x6f\xca\xb5\x1b\x81\xb4\x30\x0c\ +\x9f\x30\xe4\x46\xe0\xc0\x22\xa9\x11\x1b\x4b\x22\x3b\xe0\x21\xbf\ +\x3f\x7f\x3d\x17\x36\x2b\xcf\x7b\xa2\x46\x03\x1e\x41\x4a\xda\x0b\ +\xdf\xc8\x66\x88\x7c\x6c\xac\x84\xfe\x59\x3a\x93\xff\x26\x15\xfb\ +\x92\x10\xa9\x5b\x84\xb2\x50\xc6\x75\x21\x06\x12\x69\x9c\x11\x9e\ +\x1c\x52\x46\x8e\x68\xd7\x6d\x00\xfe\xf3\xce\x02\xe4\xe6\xe6\x62\ +\xc4\x88\x11\xb0\x58\x2c\x9a\xa0\x11\x67\xfe\x33\xe5\x8c\xe2\xf4\ +\x3c\x84\xce\x18\x1f\x1b\x27\x29\x29\x89\x6e\xda\xb4\x09\xad\x3a\ +\xf7\xc6\xc0\x17\x27\x83\x70\x1c\xe4\x68\x68\x5e\xcf\xe0\xc9\x19\ +\xab\x8b\x10\x2a\xb0\x6c\x22\xea\x42\x84\xef\x39\xc2\x93\x3b\x41\ +\xb5\xbc\x71\xf5\x92\x5d\xbf\x01\x00\xce\x03\x88\xec\xaf\x21\x8a\ +\x11\x54\x6b\x39\x44\xe4\x45\xd9\x67\x8e\x21\xe7\x42\xa6\xa8\x5b\ +\x89\xdf\x26\x52\x99\xec\xcf\x50\xe8\x5b\x52\x2d\x64\xf1\x14\xe5\ +\xed\xda\x6f\x04\x5a\xb4\xef\x81\xf4\xf4\x74\x24\x24\x24\x50\x35\ +\x67\xa0\x91\x7b\x55\x4c\xc2\xfd\x5e\xbb\x77\xef\xa6\xfd\xfb\xf7\ +\x47\x40\x68\x38\xc6\xcf\x58\x89\xe0\xb0\x9a\x62\x1d\x29\x91\xeb\ +\x9f\x6c\x18\xd4\xc2\x98\xf8\xb2\x30\x00\x16\x4b\x19\x16\x4d\x1b\ +\x2d\x9a\x74\x50\xb3\x0f\x10\xf0\xb0\x26\x18\xc4\x2b\xb4\x3e\xc2\ +\xdb\x8d\xb2\xdb\xff\x2c\xe5\xf8\x79\xc5\x1c\x54\x56\x56\x40\xa6\ +\xa7\xea\x95\x53\x11\x07\x44\xc6\x3e\x65\x61\xde\x7e\x01\x78\x6f\ +\xf1\x06\x34\x68\xd2\x0a\xe3\xc7\x8f\xc7\x9a\x35\x6b\xe8\x83\x30\ +\xf9\x70\x46\xa4\x35\xbd\xab\xb2\xb2\x12\x1f\x7e\xf8\x21\xca\xcb\ +\x2d\x18\xf9\xe6\x6c\x04\x85\xd6\x80\x20\x0d\x08\x02\x1b\x61\xc1\ +\x1a\x22\xb9\xa7\x8c\x80\xa0\x1d\x87\x0d\x3b\x76\x60\x07\x32\xd3\ +\xf6\x4b\xbc\x27\xea\x45\xa7\x0a\x55\x44\xe7\xd7\x01\x7e\xa9\x49\ +\xea\xae\x0d\x48\xf9\x6d\x9d\x44\xae\xc4\x6f\x4b\xdf\x92\x87\xc9\ +\xff\xb3\xec\x8a\x32\x61\xc2\x97\x3d\x3d\xbd\xf1\xca\x7b\x5f\xa0\ +\xa0\xb0\x10\x53\xa6\x4c\x41\x59\x59\x99\x4b\x1e\x5c\xa7\x1d\xe4\ +\x6a\x8f\x53\x4a\xb1\x6d\xdb\x36\x9a\x9a\x9a\x8a\x87\x5b\x77\x46\ +\xbb\x6e\x4f\x8b\xc4\x5d\x26\x42\x0b\x34\x1d\xac\x88\x4b\x64\x16\ +\x1d\x30\x80\x0e\x91\xf4\x13\x29\x1d\xb5\x59\xb1\x2d\x61\x89\xf4\ +\xf1\xa8\x97\x80\x90\x36\xda\xda\x26\xdf\x90\x3e\x11\x31\xa8\xf1\ +\xe8\x08\x51\xa2\xdb\xb4\x66\x21\xec\x2b\xdb\x15\x49\xf9\x6f\x29\ +\x2d\x4d\xca\xff\x02\x0f\x23\x0a\x3e\x26\x58\x1f\xa2\x62\x62\xd1\ +\xb9\xd7\xb3\xb8\x76\xed\x1a\x96\x2c\x59\x42\xb5\xec\x6e\x46\x3b\ +\x8c\x33\xda\xc3\x6a\x61\x37\x6f\xde\xbc\x33\x71\xe2\x44\x84\xd7\ +\x6e\x88\xf7\x16\x6d\x80\xc9\xdd\x5d\x66\x4a\x51\x4e\x08\x09\x17\ +\x40\x55\xa1\x6e\x4a\x63\x36\x1b\xf3\xd4\xb1\xdf\x71\x32\x75\xb7\ +\xfd\xc1\x23\x18\x68\xf0\x12\xaf\x9c\x12\x95\x09\xc4\x18\x27\x39\ +\x37\x34\x18\xb2\x10\x9e\x81\x91\x76\xeb\x46\x46\x1a\xd2\xf6\x6f\ +\x55\xc5\x90\xa8\xcd\x43\x47\x28\x1e\x71\xa8\x9b\xac\xf1\x39\x0e\ +\x23\x26\xc4\xe3\xa1\xe6\xed\x31\x6b\xd6\x2c\xa8\xd9\xec\x5c\xe9\ +\x30\x4e\x4d\xd1\x54\x53\xa4\x94\xe2\x21\x00\xcc\x9a\x35\x2b\x28\ +\x3b\x3b\x1b\x3d\x06\xfd\x07\x3e\x7e\x41\x3c\xd3\xa4\xbc\x78\x0c\ +\x10\xe1\x9e\x52\x89\xdc\xf1\xba\x08\xc4\x30\x86\x66\x88\xe1\xf2\ +\x74\x94\x52\xec\xff\xf5\x47\xc9\x6a\x10\xd6\x15\xf0\x0c\x85\x48\ +\x47\x89\x16\xfc\xc7\x9e\xa7\x9b\xd9\x1f\xa1\xcd\xfb\x8b\xe1\x7b\ +\xb7\x7c\x2f\xd5\x83\x4a\x92\x1f\xd8\x30\x56\x59\x02\x43\x72\x99\ +\xb2\x52\x5e\x0d\x00\x43\xca\x09\x28\x42\x6b\xd4\xc2\xc0\xd1\x6f\ +\x23\x2f\x2f\x0f\x4b\x97\x2e\x75\x09\x53\xe8\xb0\x04\x52\x4f\xcb\ +\x55\x7b\x16\xae\x8b\x17\x2f\xd2\x6f\xbf\xfd\x16\x61\x91\xf5\xd1\ +\xeb\x99\x57\x45\xc7\x99\x38\xaa\xa8\x24\xc2\x52\x71\xee\x50\x85\ +\xf1\x9a\x8a\x4a\x20\x11\x63\xf0\x0a\x2a\x23\xa4\x9f\x3d\x71\x10\ +\xbb\x37\xae\x96\x24\xb7\xe8\x71\x72\x4e\x4d\x35\x87\xa6\xd8\x29\ +\x91\xdd\xde\x02\xe7\xe1\x03\x00\x38\xb2\x77\x33\x2e\x9e\x3d\x21\ +\xcd\x69\xd6\x1d\x00\x07\xb3\x1d\xa3\x83\xa9\xcc\x52\x2a\x95\x9c\ +\x32\xd2\x44\x9b\xc7\xfa\x22\xa6\x65\x27\xcc\x9d\x3b\x17\xa9\xa9\ +\xa9\xd4\x48\x9b\xaa\x02\x17\xd5\xb4\x5a\x2d\xd1\x8f\xfd\x7d\xf3\ +\xcd\x37\x28\x2a\x2a\x42\x8f\x81\xa3\xe1\xe5\xe5\xcb\x00\x0a\x89\ +\x64\x32\x11\xf5\x0b\x29\x5c\x14\x4f\x09\x23\x80\x13\xe9\x99\x10\ +\x39\x5f\xb0\x5a\x2b\xf1\xd5\xc7\xaf\xa1\x92\x47\x8c\xa2\xc6\x13\ +\x76\xab\x81\xc8\xb5\xd5\xe8\x12\xab\x6c\xd9\xf3\x31\x87\xd4\x45\ +\xf5\xd8\xc1\xa2\x44\xb7\x64\xc6\xeb\xb0\x5a\x2b\xe5\x65\x13\xef\ +\xa5\xb5\x48\x90\x85\x13\x49\x75\x50\xb3\xb7\x89\xf5\x01\x08\x31\ +\xa1\xef\x73\xe3\x00\x00\x0b\x17\x2e\xac\xd2\xda\x2a\x42\x88\x64\ +\x8b\x73\xe5\x57\x56\x56\x86\xb5\x6b\xd7\xc2\xcb\xc7\x0f\x5d\x7a\ +\x0f\xe5\x21\xb5\x8c\xb6\x4f\x25\xeb\x00\xd5\xb8\x67\xe3\x53\x9d\ +\xfb\x33\xc7\x53\x70\x39\xfb\x0c\x2f\xb9\x05\x02\xcd\x3e\x82\x23\ +\x87\x97\xf7\x12\x85\x82\x44\xf1\x24\xb7\x46\xbb\x91\x70\xf3\x0a\ +\x04\x00\x64\x9d\x3c\x84\xa3\xc9\xdb\xa4\x39\xae\x52\x06\xaa\x28\ +\x8f\x20\x79\x8a\x96\x0d\x26\x8e\x78\x0f\x2a\x5a\x40\x9a\xb7\xeb\ +\x8e\x90\xb0\x9a\x48\x4a\x4a\xc2\xd5\xab\x57\xa9\xd1\xa5\x39\x4e\ +\x97\x9f\x38\xbb\x92\x92\x92\xe8\xc5\x8b\x17\xf1\xf2\xd4\x45\xa8\ +\x1e\x51\x57\x26\xb1\x29\xef\xd5\x9e\xf5\xc2\xc0\xdc\x53\x6a\xc3\ +\xba\x15\x73\x60\xb3\xf2\xe8\x9a\xa8\x17\x01\x9f\xba\x72\x0e\xad\ +\xee\x18\x15\xf3\x62\x7f\x01\x0d\x3a\xa3\x4e\xef\x0f\xc4\x28\x89\ +\xcb\xe3\x51\x59\x51\x29\xfb\x2e\x55\x29\x97\x20\x4d\x52\x22\x59\ +\x12\xf4\xea\x2c\x50\x5e\x5f\xff\x40\x3c\xfb\xda\x07\xb8\x7b\xf7\ +\x2e\x12\x12\x12\xaa\x04\xf2\xe4\x5c\x9d\x72\x56\xab\x15\x5b\xb6\ +\x6c\x81\x97\x8f\x1f\x5a\x76\xe8\xc9\xaf\xb8\x96\x7b\x26\xd9\xff\ +\x5a\xf7\x4a\x37\x83\xf0\x4c\x98\xe7\xbf\xae\x5c\xc4\x89\x83\x3b\ +\x79\xde\xe3\x09\xd4\x1d\x2a\x58\x37\x21\x57\xb4\x8c\xf5\x10\x21\ +\x1c\x6a\xb4\x1b\x05\xce\xdd\xcb\x2e\xd1\x9d\x4a\xc7\xf9\x53\x69\ +\x9a\x65\xa1\x32\x23\xaa\xbc\x6c\x6a\xf1\xa1\xe2\x99\xed\x31\xf0\ +\x3f\x08\xae\x5e\xd3\x01\x80\x69\xd4\x85\xc3\x19\x5d\x95\x2c\x5c\ +\x47\x8e\x1c\xa1\x09\x09\x09\x88\x89\xed\x88\xc0\xd0\x30\xd9\x88\ +\x97\x46\x22\x15\xd5\x1a\xc9\x9c\xc5\xba\x0b\xd8\x78\xd4\x2e\x2c\ +\xc8\xee\xed\x3a\xcb\x86\x55\x9f\x4a\xdf\x8e\xe8\x05\xf8\xd4\x73\ +\x64\x38\x54\x03\x2c\x47\xa9\xa3\xc2\x4b\x00\x37\xaf\x40\x84\xb7\ +\x7f\x91\xd7\xad\x6c\xd8\xbc\x66\x21\x2c\x96\x32\xd1\xe5\x41\x40\ +\x15\xb3\x9b\x2a\x5c\x1d\xd2\x2c\xa3\x4c\x79\xa5\x77\x54\x74\x61\ +\x50\x42\xc1\x71\x1c\xda\x3f\x11\x87\x94\x94\x14\x64\x65\x65\x51\ +\x2d\x12\xa7\x29\x66\x6b\x39\x8a\xd4\xa6\x1e\xa5\x14\xeb\xd6\xad\ +\x43\x41\x41\x01\xba\xf4\x1e\xa6\xb2\xfa\x40\xa1\xc5\xb0\x23\x9b\ +\x10\xb0\x0e\x64\x56\xeb\x90\x44\x07\x22\xe6\xf1\xfb\x6f\x89\x48\ +\x5a\xff\x8d\xe4\x8c\x6b\x3c\x51\x52\xeb\x1d\x9d\x9e\x8e\x12\x96\ +\x6c\xd0\x88\xfe\x6b\x10\x02\x44\x76\x7b\x13\x26\x4f\x5f\xd1\xba\ +\xb0\xed\xa7\xaf\x14\x95\xa0\x0a\x39\x8e\xfd\x51\x99\x26\x44\x14\ +\x75\x27\x62\xfd\x24\x60\x4a\x97\xde\x43\x51\x5e\x5e\x8e\x29\x53\ +\xa6\x68\xba\x6c\xb4\x3a\x8b\x53\x43\x9d\x68\x2d\x0f\xa1\x94\xe2\ +\xe8\xd1\xa3\xe0\x4c\x26\x44\x3f\xd2\x56\x43\x1b\x25\x8e\x46\x34\ +\x71\x34\x13\x47\xc3\x17\x25\x72\x8f\x04\x08\xac\x56\x1b\x92\x7f\ +\x5d\x0b\xab\xc0\x7b\x6a\x0d\x04\xfc\x63\xf4\xb0\x49\x2a\x2a\x10\ +\x61\xbd\x08\x32\xb0\x89\x39\xa4\x1e\x02\x1b\xd9\xc1\xf5\xd6\xca\ +\x0a\xec\xdb\xfa\x03\xac\x95\x95\x2a\xa4\x4a\x4d\xd3\x56\x01\x98\ +\x50\xaa\x6b\x50\x8c\xac\xd7\x18\x7e\x81\xa1\x48\x4f\x4f\x47\x65\ +\x65\xa5\x21\xcf\xaa\xd8\x41\xae\x2c\x3e\xca\xcf\xcf\xef\x7e\xe2\ +\xc4\x09\x54\x8f\xa8\x83\xf0\x5a\x51\x8c\x92\xc8\x90\x29\xc1\x73\ +\x29\x69\x6f\x7c\x3f\x51\xd1\x73\x49\x21\x91\x34\x41\xb7\x25\x4c\ +\xfa\xb3\x27\x53\x25\x20\x88\x47\x10\xd0\xf4\x43\x55\xcc\x9c\x13\ +\x40\x99\xe3\x8f\x57\xb8\x08\xc7\x21\x7a\xf8\x4a\xd1\xba\x70\xf1\ +\xcc\x71\x1c\xd9\xb7\x45\x2c\x9f\x40\xaa\x64\xf5\x21\x6c\x7d\x28\ +\x53\x07\x61\x5c\x31\x64\x9a\xca\xeb\xe7\xe3\x17\x80\xa8\x98\x58\ +\xdc\xb8\x71\x03\x67\xce\x9c\xa1\x46\x36\xb4\x10\xa5\x38\x67\xbe\ +\x72\xf6\x39\x2b\x2b\x2b\xa9\xb0\xb0\x10\x0d\x1f\x6e\x2d\x99\xda\ +\x19\x97\x01\x3b\x6a\x08\xe3\x31\x15\x31\x00\x82\xb7\x94\xc8\xb1\ +\x00\x84\xc5\x26\x00\xd8\xf9\xf3\x0a\xc9\x6a\x10\xd1\x0b\x30\x87\ +\x49\xc4\x44\xb3\xa3\x88\x73\x31\x8e\x89\xe3\xe1\x1f\x86\xb0\x47\ +\x9f\x17\x1b\xe2\xb7\x75\xcb\x41\x6d\x54\x3e\xe3\xa8\x04\xfb\x82\ +\x5a\xfd\x04\xd7\x88\xc2\x24\xcf\x0a\x4e\x02\x55\x68\xf4\x70\x6b\ +\x54\x56\x56\xe2\xc4\x89\x13\x86\xb6\x9f\x11\x5d\xde\xae\xe8\x3f\ +\xa9\xa9\xa9\xe0\x38\x0e\x31\xb1\x1d\x15\xa3\x92\x91\xa8\xa0\xf4\ +\x50\x0a\x8c\x57\xc2\x1c\x08\xfc\x49\xed\xdd\x5f\xb9\x97\x90\xb2\ +\xf3\x67\x01\xfd\x61\x37\x8a\xca\x34\x77\x01\x13\x05\xb9\xd7\x4c\ +\x4d\xcb\x07\xd5\xf8\xd9\xdf\x85\x77\x7c\x09\x26\xb3\x1d\xef\x7d\ +\xf2\xf0\x1e\x64\x9f\x39\x2e\xd6\x83\x30\x75\x12\x85\x04\x28\xea\ +\xa9\xbc\x67\xe2\x10\xc5\x7d\xe3\x16\x76\x64\x51\x6a\x6a\xaa\x6b\ +\x1e\x55\x57\x76\xca\xc8\xc8\xc8\x40\x60\x68\x0d\x34\x89\xed\xe4\ +\xa8\xb4\x38\x53\x76\xf4\xe2\xf3\xcf\x96\xf2\x32\x7c\xf6\xce\x70\ +\x94\x97\xf2\x70\xdd\x88\x9e\x40\x60\x53\x15\x1b\xa8\xd2\x35\x41\ +\x35\x4c\x71\xfa\xce\x26\x73\x48\x5d\xd1\xd2\x5d\x59\x61\xc1\xfc\ +\x77\x47\xa0\xb4\xb8\x48\xbf\xbc\x30\x52\x3f\x38\xa4\xad\xdd\xa0\ +\x09\xdc\xdc\x3d\x90\x91\x91\xe1\xba\x25\x41\x49\x03\xb5\xfe\xe7\ +\xe6\xe6\x22\x20\xa8\x1a\x6a\xd4\xaa\x2f\xf1\x2c\xd6\xa9\x23\xf3\ +\xe1\x48\xfe\x7e\x56\x13\x67\x9f\xa9\xcc\x20\x49\x71\xfe\x54\x3a\ +\x83\x35\x08\x04\xea\x3e\x27\xa7\x4c\x5a\x54\x4b\x55\xd1\x56\x9b\ +\x45\x4c\x38\xb1\x4b\x5c\xd5\x5b\x0f\x85\xbb\x5f\x75\x00\xc0\x95\ +\xec\xd3\x38\x76\x70\xa7\xc2\x28\x4a\xe5\xcf\xb2\x01\x22\x0d\x14\ +\xaa\xf1\x2c\x24\x09\x08\xae\x0e\x4f\xb3\x37\x6e\xde\xbc\x09\x8b\ +\xc5\xa2\x89\xea\x51\x9d\x41\xce\xd6\xad\x08\x57\x56\x56\x16\x6a\ +\xd4\x8e\x82\xd9\xc7\x4f\x66\x2f\x53\x2c\xd4\x61\x3c\x96\x92\x0d\ +\x8b\xf2\xcf\x14\x4a\x9b\x9d\x84\x39\x5b\xb7\x62\xb6\x84\x35\xa8\ +\x3f\xd2\x6e\x77\xd3\xed\x1d\xe8\x20\x1f\x05\xd1\x9a\xa8\x3c\x4b\ +\xe1\xfe\xf5\xdb\xa1\x4e\xaf\xf7\xc4\x54\xeb\x57\xce\x41\x45\x65\ +\x05\xe4\x8a\x9c\xdc\x5f\xe5\x28\x5f\x53\xd9\xc4\x61\x50\xcb\xa2\ +\x50\xe4\xe1\x69\x46\x4c\xcb\x8e\xb8\x76\xed\x1a\x8a\x8a\x8a\x5e\ +\xd6\x82\x14\x28\xf9\x3f\x67\xa4\x63\x00\xe0\xd6\xad\x5b\xe9\xb7\ +\x6f\xdf\x46\x78\xad\x28\x9e\xd4\x12\x99\x77\x91\xf5\xe1\x8b\x8c\ +\x94\x3a\x3e\x13\x07\xf1\xd7\x9e\xfe\x4a\xf6\x69\x1c\xfd\x7d\xbb\ +\x3d\x0f\x93\x17\x50\x7f\x94\xe3\xcc\x74\xb0\xb1\xb1\x33\x95\x28\ +\x8c\xa5\x6c\xa3\x2a\x5a\x8f\x69\x4d\x02\x0e\x35\xda\x8e\x82\x9b\ +\x4f\x88\xdd\xba\x90\x99\x6e\xf7\xda\x2a\xfc\xdd\x54\xf1\x5f\xf6\ +\x1e\x8e\xfe\x71\xb6\xae\xc2\xff\x16\xed\x7b\xa0\xb8\xb8\x18\x57\ +\xae\x5c\x59\x66\x74\x69\x0f\x67\xd4\x39\x77\xeb\xd6\xad\x96\x56\ +\xab\x15\xfe\x41\xa1\x72\x85\x4e\xd9\x06\x50\x1b\xe4\xea\x23\x0c\ +\x4c\x1b\x6e\x4f\x5c\x26\xa5\xaf\xd1\x1d\xf0\xae\xc5\x98\xf3\x21\ +\xb7\x5e\xeb\x4a\x73\x0a\x3e\x45\x15\xd6\x05\xa5\x2f\x81\x50\x98\ +\xcc\x7e\x08\x6b\xf3\x9c\x18\x6d\xc7\xba\x65\xa0\xb0\x39\x96\x57\ +\xc5\x6a\xe2\x30\xc1\xa1\xfd\x3e\x34\x2c\x52\x70\x74\x1a\x77\x79\ +\x1b\x5d\xbe\x78\xf7\xee\x5d\xd8\x6c\x36\x78\xf9\xf8\x49\x75\x15\ +\x49\x97\x9c\x2f\xcb\x58\x13\x91\x80\x7f\x20\x0a\xbe\xce\xeb\x40\ +\x47\x92\xb7\x4a\xfe\x1e\x62\x02\x1a\xbf\xa5\xde\x11\x1a\xd6\x6b\ +\x85\x04\x2d\x75\xac\x43\xa3\x29\xc8\x14\x95\x90\x3d\xb5\xba\xbd\ +\x09\x93\xd9\x1f\x00\x70\x68\xd7\x46\x1c\xd8\xb1\x4e\x06\x00\x22\ +\x6a\xb2\x89\x92\xb3\x31\x14\x54\xe6\x07\xe4\xbf\x29\xb4\xdd\x9d\ +\x3b\x77\x5c\xc3\x24\x18\xd9\x2f\xbb\xa0\xa0\x00\x94\x52\x98\xcd\ +\x3e\x12\xbe\x4c\x1c\x84\x54\x74\x06\x2b\x59\x13\x15\xbc\xa4\x44\ +\xee\xaa\x11\xd2\x53\x6a\xc5\xa6\xd5\x0b\x50\x5a\x5c\x60\x8f\x10\ +\xda\x0e\x08\x88\x61\x1a\x97\xca\x05\x01\x55\xf6\x43\xf4\xad\x0b\ +\x44\x21\x38\xa8\xb0\x2f\x73\x48\x5d\x84\x34\xed\x0d\x00\xb0\xd9\ +\xac\x58\xfb\xd5\x47\xa8\xa8\xb0\xc8\xa8\x03\x25\x94\x31\xe9\x30\ +\x20\x13\x38\x4a\xfd\x84\x01\xfd\x8b\xa0\x12\x2f\x6f\x00\x10\xdb\ +\xd2\x08\xe5\xe2\xf4\xe0\xbe\x6c\x58\x7e\x7e\x3e\x6c\x36\x1b\xcc\ +\xde\x3e\xfc\xc8\x22\x8c\x05\x47\xb2\x3e\x39\x68\x1c\x44\x7a\x2f\ +\x23\xd7\x7c\xdc\x73\x7f\x1c\x41\x46\xda\x3e\x49\x72\x6b\xb5\xd8\ +\x3e\x8b\x1c\x86\x28\xd5\x46\xfc\xa8\x7a\x3b\x89\x86\x85\x5b\x3b\ +\xa8\xd1\xb3\x5f\xc2\x33\xa8\x36\x00\x20\xf7\xd2\x59\x1c\xde\xb3\ +\x49\x51\x0c\xc2\xe0\x4f\x89\x28\x00\x50\x85\xcd\x56\x8c\xc3\xbc\ +\x07\x00\x2f\x6f\x5f\x91\x1a\x19\xa5\x5c\x9c\xde\xac\x51\x35\x41\ +\x48\x70\x4c\x69\xc6\x50\x01\x7f\x00\x05\xfe\x80\x4a\xf1\xa8\x04\ +\xe5\x25\x42\x3c\xd8\x25\x37\x2a\x2c\x81\xa9\x3b\x4c\xe2\x3d\x44\ +\x21\x0e\x81\x38\x2a\xa6\x84\x81\xd5\xa8\x5a\xb9\x59\xda\xa3\x30\ +\xaa\x51\x85\x5a\x40\xed\x96\xee\x5a\xdd\xdf\x12\xeb\xbb\xfe\x9b\ +\x4f\x60\xad\xac\xe0\x27\x24\x5b\x57\x86\x32\xf0\xb6\x38\xc2\x08\ +\x2d\x6c\xfd\xec\x02\x03\x65\x56\x57\x40\x77\x7f\x1f\xe5\x8c\xe2\ +\xf4\x66\x0d\xfb\xdf\xcf\xcf\x0f\x1c\xc7\xc1\x52\x56\xca\x80\xf7\ +\x58\x22\x4d\x24\xd1\x5a\x34\xc7\x0b\xbb\x7f\x10\xde\x44\x2f\x2c\ +\x1f\xb1\xc7\xbf\x71\xf5\x92\x34\x7b\x40\x80\xda\x83\xe5\x8d\xa7\ +\x89\xf1\xa1\xba\x4a\xaa\x43\x90\x03\x42\x51\x83\xce\x81\x20\xf4\ +\x91\xfe\x30\x99\xed\xab\xc2\x2f\x9d\x39\x81\x3f\xb3\xfe\x10\x21\ +\xc8\xac\x70\x28\x50\x06\xc8\x56\x60\x40\x34\x57\x51\x66\xb9\x8a\ +\x40\xe7\x84\xf5\xb2\xfe\xfe\xfe\x86\xb6\x9b\xd1\xf4\x07\xa9\xcd\ +\x9e\xa0\xa0\x20\x70\x1c\x87\x92\xe2\x02\x66\x96\xf0\x30\x0f\x7e\ +\x43\x0c\xbb\xaa\x21\xc9\xce\xc4\x01\xe1\x23\xd1\xe7\xf2\xb2\x52\ +\x7c\xf2\xd6\xb3\x28\x2d\x2e\xe4\x51\xa2\xbd\xed\x56\x03\x96\xd7\ +\xa8\x69\xed\x72\x70\x9d\x36\x2e\x8e\x35\x43\xc9\x10\x88\x4a\x67\ +\x1f\x64\x46\x50\xcf\xe0\xda\x08\xef\x30\xda\x6e\xe9\xb6\x56\xe2\ +\xc7\x2f\xa7\xa3\xf0\xde\x1d\x86\x8f\xb2\x94\x82\xca\x28\x85\x40\ +\x21\xc4\x59\x24\xe8\x47\x7c\x1b\x08\x75\x0d\x0e\x0e\x76\xba\x3b\ +\xb0\xaa\xa9\x47\xcf\x80\x17\x10\x10\x00\x8e\xe3\x50\x5e\x52\x22\ +\x71\x3e\x95\xb8\x54\xd5\x9f\xad\x90\xa0\x08\x41\x66\xfa\x7e\x9c\ +\xcb\x38\x22\x8d\xe2\xa8\xd1\x8e\x0d\x4e\xb4\xd8\x87\xdc\x3a\xad\ +\x6e\x45\x70\xd6\xb1\x6a\x1d\x6c\xaf\x4f\x44\xa7\x57\x40\x38\xfb\ +\x4a\xee\xb4\xfd\x5b\x71\xe0\xb7\x75\x72\x1d\x4a\x09\xac\x77\x08\ +\x23\x0a\xc1\xc6\xfe\x5f\x80\x2c\x0b\x0b\x90\x8d\x6c\x74\xc8\x19\ +\xdd\x2f\x2d\x34\x34\x14\x26\x93\x09\x85\x05\x79\xe2\xca\x37\x01\ +\x1b\x06\x76\x8f\x69\x51\x8f\x64\x71\x66\x8e\xf9\x6f\xfd\x61\x31\ +\x83\x12\x7d\x11\x08\x79\x54\x85\x92\x29\x78\x86\xaa\x17\x55\x0b\ +\x76\x45\x1d\x95\x5b\xc0\xd1\x8c\xa3\x02\x30\xf1\xaa\xde\x10\x75\ +\xfb\x4c\x97\xf4\xa2\xc4\x65\xa8\xb0\x94\x31\x58\x3a\xca\xc0\x97\ +\xa9\x43\x5d\x55\xeb\x4d\x81\xbb\xb7\xff\x02\x60\xdf\xca\xd3\xe8\ +\x7e\x72\x9c\x11\x93\x37\x21\x04\xe1\xe1\xe1\x24\x24\x24\x04\x57\ +\xff\x3c\x2f\x5b\xe0\x4b\x20\x87\x2a\x49\x03\x46\x6e\xce\x11\xfd\ +\xa5\x14\xc8\xfa\xe3\x30\x8e\x1e\xd8\x21\x61\xac\x1f\x9a\x68\xc7\ +\x1c\xb0\x30\x2a\xd6\x41\x06\x69\x79\x8a\xc3\x6c\xa2\x5a\x52\x9b\ +\x7c\xc6\xaa\xce\x22\xe2\x80\x35\x16\xa9\x42\x64\xd7\x37\xe0\x55\ +\xad\x81\xe8\x2f\x3a\xbc\x67\x13\x03\x45\x66\x2d\x11\xd2\xea\x0d\ +\xc2\x68\xb1\x72\x2f\xb1\xbd\x2c\xe9\xbf\x6f\x87\x8f\x8f\x0f\xea\ +\xd6\xad\x3b\xd7\xe8\x7e\x72\x9c\xd1\x1d\xd5\x01\x20\x32\x32\x12\ +\x79\x37\x72\x61\xb5\x55\x3a\x0a\xd4\x0a\xe4\x25\x81\x72\xa4\x52\ +\x11\xe0\xb7\x7f\xeb\x0f\x92\xe4\x56\xbd\x0b\x60\xae\x21\x5f\x38\ +\x44\x95\xca\x14\xdb\x09\xce\x18\xbd\x51\x97\x83\xfe\xcf\xe4\xe9\ +\x83\xd0\xe6\x4f\x8b\xb9\xed\xdd\xb2\x86\x41\xa2\xb2\xc2\xb5\x04\ +\xcb\x54\x2e\x06\x63\x7f\x36\x9b\x15\x17\x32\xd3\x11\x1c\x1c\x0c\ +\x6f\x6f\xef\x29\xce\xa8\x96\x83\xc3\xce\x19\xe2\x84\x10\x82\xe8\ +\xe8\x68\xdc\xfe\xeb\x0a\xae\x64\x9f\xe1\xad\x08\x44\xd2\x89\x58\ +\x6f\xbc\x8c\xb1\x83\x89\x4b\x70\x64\xef\x16\xec\xd9\xfc\x9d\xe4\ +\xef\x79\x68\x02\x83\x42\xa7\x72\x05\x95\xb2\x18\x01\xa2\x62\x56\ +\x61\xe3\x4b\xab\xd5\xa9\xad\xd2\xa0\x91\x95\x68\xd9\xa6\x00\x10\ +\x44\x3e\xfe\x06\xdc\xbc\xec\x12\x5d\x7a\xf2\x36\x9c\x39\x9e\x22\ +\xce\x3e\xa2\x10\x62\x88\xda\x4c\x25\x52\xbb\xdc\xb9\x79\x1d\x05\ +\xf9\xb7\x51\xab\x56\x2d\x78\x79\x79\xc1\xe8\x66\xbe\x1c\x8b\xc7\ +\x66\xd7\x50\xaa\xc9\xe7\xd1\xd1\xd1\xb8\x7b\xeb\x2f\x7e\x51\x2e\ +\x15\x77\x15\x90\x3b\xb4\xd8\x31\x2c\x2c\x16\x14\x46\x91\x0d\x6b\ +\x97\x7c\x84\x92\x22\xde\x6a\x10\x39\x00\x08\x6c\x06\xa8\x5a\xc6\ +\x09\xe3\x72\x26\x2a\xa0\x0e\x3e\xdc\x66\x01\x32\x3e\x06\x2e\xac\ +\x14\xa3\x5c\xff\x7d\x39\x2e\x6d\xfd\x10\x95\x25\xf9\x8e\xfc\x46\ +\x6b\xa2\x39\x2a\x4f\xf0\x0c\xaa\x89\xea\xad\x87\x8a\x6d\x30\xff\ +\xdd\x11\x28\x29\x2e\x10\x17\x52\x52\xc2\xa8\xa1\x02\x76\x5d\x14\ +\x94\xa8\xcc\xf5\x7e\x35\xe7\x1c\x2a\x2c\xe5\x88\x8e\x8e\xd6\xdd\ +\x80\x49\x39\xa3\x38\x67\x1b\xf8\xb1\xf7\xb1\xb1\xb1\xb0\xd9\xac\ +\x38\x97\x91\xc6\xec\xc6\x41\x65\xee\x6a\x02\x22\xe3\xed\xe2\xaa\ +\x34\x10\x9c\xcf\x4c\xb3\x7b\x2d\x01\xc0\x3d\x00\x68\x3a\x4d\x5c\ +\xbb\xe3\x60\xc8\x54\xb3\xb7\x81\x31\xe2\x59\xf2\x81\xdc\x4d\xc0\ +\xee\x27\x80\xac\x85\x40\xf9\x2d\x69\xcd\x52\x69\x3e\x72\x7e\x9d\ +\x81\xf4\xd9\xad\x70\x3d\xe5\x6b\x54\x96\xde\x53\xe8\xab\xda\xcb\ +\x55\xe4\x33\x89\x22\xa2\xf3\x6b\xf0\xaa\x16\x05\x00\xb8\x91\x7b\ +\x09\x69\xc9\xbf\x32\x40\x11\x88\x7c\x55\xdc\x7c\x83\x51\xd4\x29\ +\x95\xda\xe3\xc2\xa9\x74\xb1\x0d\x9d\xed\x03\x2b\xdb\x96\xd9\x95\ +\xdd\xe6\x5b\xb5\x6a\xf5\x8a\xaf\xaf\x2f\x32\x8e\xec\x15\x69\x30\ +\x81\x1c\x4f\x46\x19\x37\xb6\x48\xa9\x08\x05\x60\x43\xe2\xb2\x59\ +\x52\x47\xd4\x1b\x0e\x78\xd5\x74\x5c\x41\xa0\xe4\x5d\x0a\x6d\x1f\ +\x96\xbb\xc0\xd9\xcf\x81\x9d\x1d\x80\x43\x2f\x02\xf7\x32\xc5\xca\ +\x36\x6e\xd1\x01\x8f\xb4\xed\x66\xdf\x98\x09\x14\x65\xb7\x2f\x22\ +\xeb\xfb\x97\x70\x78\x7a\x34\x2e\x6e\x78\x07\xe5\xf7\xae\xca\x75\ +\x1f\x19\x44\x0c\x8e\xab\xb4\x00\xf8\xd6\x6c\x8a\x5a\x4f\x4c\x16\ +\xbf\xb1\x6e\xc5\x6c\x58\x2b\x2d\x00\x03\x11\x93\xb7\x83\x84\x91\ +\x23\x8c\x24\x99\x71\x64\x1f\xdc\xdc\xdc\xd0\xa9\x53\x27\x55\x00\ +\xbd\x56\xfb\xbb\xe4\xf2\x0e\x0c\x0c\x5c\xde\xa8\x51\x23\xdc\xbc\ +\x96\x83\xfc\xbc\x9b\x92\x79\x94\x4a\xb4\x96\x30\x1b\x55\x88\x3c\ +\x89\x12\x5c\xbf\x9c\x8d\x13\xa9\x49\x92\x85\xa9\xde\x08\xb9\x54\ +\x25\x73\xa4\x29\xf5\x21\x02\x50\x0b\x90\xb3\x16\xd8\xd1\x0a\xc8\ +\x9c\x01\x94\xfd\x25\x36\x9a\x6f\x40\x30\x5e\x98\x34\x0f\xb3\x57\ +\xed\xc5\xc7\x2b\x7e\xc3\x84\xf8\x55\xbc\x5b\xc4\x9e\xbe\xa2\xf0\ +\x26\xae\x24\xcd\x43\xfa\xac\x16\xc8\xd9\x31\x17\x56\x4b\x89\x8a\ +\xff\x00\x9a\xfe\x84\x6a\xb1\x03\xe1\xee\x6b\x77\xb3\xe4\x9c\xcb\ +\xc0\xe9\xe3\x29\x92\x6d\x4e\xac\x27\xd3\x0e\x54\x1e\x5e\x5e\x56\ +\x82\x9c\xf3\x99\xf0\xf7\xf7\x47\xa3\x46\x8d\x88\x51\x9e\xaf\x09\ +\x1a\xd1\xd2\x85\x38\x8e\x43\xc7\x8e\x1d\x61\xad\xac\xc0\x1f\x87\ +\xf7\x48\xe0\x08\x96\x07\x89\xc8\x4c\x29\xbc\xb2\xa2\x1c\x6b\x97\ +\x7c\x0c\x4b\x79\x99\x84\x35\xf0\x8d\x52\xe1\x2d\x2a\x9a\xa9\xe5\ +\x2e\x70\xe1\x6b\x60\xcf\x93\x40\xfa\x58\xa0\xe2\x9e\xe4\x36\x8a\ +\xac\x8f\x57\xa6\x2e\xc6\x37\xbb\x72\x10\xf7\xc2\x5b\x30\xb9\xb9\ +\x81\x10\x0e\x8f\xf7\x1d\x8e\xe5\xdb\xcf\x63\xd2\x27\xdf\xa3\x6e\ +\xa3\x66\x62\xfc\x8a\xa2\x5b\xb8\xb4\xe9\x5d\xa4\xcd\x68\x86\x2b\ +\xbb\xe6\xa3\xec\xee\x15\xa8\x7a\x0f\x15\xd2\x98\xbb\x4f\x30\x6a\ +\xb4\x7b\x41\xcc\x67\xe3\xea\xf9\xa0\xd4\xea\x58\x7f\xfe\x3f\x85\ +\xfc\x39\xe7\xfc\x29\xe4\xdd\xb8\x8a\x0e\x1d\x3a\xc0\x6c\x36\xbb\ +\x04\x1a\x91\x1d\x74\xab\x75\x6a\x21\x1b\x76\xe0\xc0\x01\xda\xab\ +\x57\x2f\x34\x6e\xd9\x05\xd3\xbe\xdc\x22\x4a\x5f\x44\xdc\xe3\x40\ +\xf2\x2b\x08\x61\xbf\x6f\x4f\xc4\xbc\x49\xcf\x4a\x7a\x4f\xc7\x75\ +\x40\x48\x2b\x4d\x03\x00\x00\xa0\x38\x07\xb8\xf2\x8b\x9d\xf9\x33\ +\xb3\x05\xb0\x6f\x92\xf4\xcc\xab\xd3\x10\x13\xdb\x91\xf7\xb1\x50\ +\xc9\xff\xa3\x70\xca\x54\x58\xca\x70\xea\xe8\xef\xd8\xf2\xfd\x62\ +\xa4\xed\xff\x55\xc6\xe4\xdc\xbc\x02\x51\xa3\xfd\x0b\x08\x6b\x33\ +\x1c\x7e\xb5\x63\xe5\xcb\x56\xc4\x7b\x7b\x7e\x96\x82\xbf\x70\x68\ +\x5a\x03\xd8\x2c\xc5\x30\xb9\xb9\x63\xd4\xc4\xb9\xe8\x3f\x72\x82\ +\xc4\x77\x1d\x90\xfc\xd2\xca\xbf\x95\x73\xde\xc4\x6f\x89\x4b\x70\ +\xec\xd8\x31\x34\x6e\xdc\x98\x18\x39\x1d\x52\xf8\xcf\x19\xd9\x6c\ +\x9b\x0d\x6b\xd6\xac\x19\xe9\xda\xb5\x2b\xce\x67\xa6\xa3\xb8\xf0\ +\x9e\xc8\xb4\x1d\xdc\xde\x8c\xb0\xb0\x6f\xcb\xf7\x52\xeb\xd6\x79\ +\x56\x42\xea\xc8\xf8\x0c\x5f\x3f\x6b\x39\x90\xbb\x05\x48\x1d\x05\ +\x64\xce\x94\x75\x4e\x58\xcd\x7a\x18\xf2\xf2\x7b\x78\x67\x7e\x22\ +\x5a\x75\xea\x05\x2f\x6f\x3f\x99\x47\x8c\xa8\x20\x49\x3d\x3c\xbd\ +\xd0\xbc\x5d\x0f\x4c\x9c\xf3\x1d\x9e\x1b\x3b\x1d\x75\x1a\x3e\x2c\ +\x13\x26\x72\x77\x2f\x40\xe6\xb2\x38\x5c\x4d\x5e\x82\xca\xb2\x02\ +\xc6\x50\x2b\x5f\x0a\xee\xee\x17\x26\x7a\x5d\xad\x95\x15\xd8\xb5\ +\xe1\x5b\x54\x94\x97\x29\x70\x74\x8c\x13\x50\x14\xf9\x6d\x38\x79\ +\x78\x37\x1e\x7e\xf8\x61\x19\x79\x33\xb2\xa1\xba\x0c\x59\xea\xcc\ +\xf4\x2d\x84\xf9\xfb\xfb\xe3\x85\x17\x5e\x40\x7e\xde\x0d\x69\xad\ +\x27\xb3\x24\x83\x5d\x1f\x47\x88\x7d\x97\x8f\x63\x29\xbc\xd5\xc0\ +\xe4\x03\x44\xbf\x01\x98\x3c\x14\xfc\x07\x40\x65\x21\x70\x76\x21\ +\x90\xd4\x09\x38\x34\x0a\xc8\xff\x43\xfc\x6e\xbd\xe8\x47\xf0\xca\ +\x7b\x5f\x60\xd1\x2f\xc7\xf1\xfc\xf8\x99\x08\xad\x5e\x53\x6e\x16\ +\x63\x8d\x07\x84\x88\xd8\x68\x76\x73\x0c\x5f\xff\x20\x3c\xf3\xea\ +\x34\xcc\x4f\x48\xc3\xa4\x4f\x7e\x44\xc3\xa6\x6d\x40\x78\x09\xb2\ +\xfc\x4e\x0e\xce\xaf\x7d\x1d\x47\xa6\x37\xc6\x85\xf5\x6f\xa1\x2c\ +\xff\x8a\x83\x1e\x46\x40\x10\x35\xf0\x53\x78\x55\x6f\x64\xe7\x45\ +\xe7\x33\x90\xba\x6b\x23\x83\xd7\x96\x9b\xea\x84\x76\xd9\xbd\x71\ +\x15\x72\xce\x65\xe2\x99\x67\x9e\x81\x72\xa7\x46\x23\x6d\x5f\xa5\ +\x2d\x31\x4b\x4a\x4a\x50\xb7\x6e\x5d\x5a\x5c\x52\x8e\x95\x49\x97\ +\xe0\xe7\x1f\xac\xea\xa2\xa6\xa0\xf8\xec\x9d\xe1\xd8\xff\xeb\x8f\ +\x7c\x4b\x3f\x0f\xc4\x7e\x2e\x77\x63\xdb\x2c\xc0\xf9\x2f\x81\x0b\ +\x2b\x80\xb2\x1b\xb2\xef\xf8\xf8\x05\x62\xfc\x8c\x95\x78\xb4\x6b\ +\x7f\x98\x4c\x6e\xea\xbe\x39\x25\x78\x9e\x18\x8b\x63\xb3\x5a\x91\ +\x95\x71\x04\x9f\x4d\x7e\x0e\x37\xae\x5e\x92\x3b\xc9\x3c\x7c\x10\ +\xd6\xfa\x3c\x22\x3b\xa4\x00\x00\x0b\xf0\x49\x44\x41\x54\x59\x44\ +\xc5\x7d\x0a\x37\xef\x40\xd9\xbb\x2b\xbb\x17\x20\xfb\xe7\x89\x00\ +\x80\x06\x4d\x5a\x62\x7e\x42\x9a\xfc\xe0\x28\xc6\xe5\x5d\x61\x29\ +\xc3\x98\x7e\x4d\x70\x2f\xef\x3a\x32\x32\x32\x10\x15\x15\xe5\xf2\ +\xc6\x09\x9a\x1b\x59\xe8\x1d\xba\xe4\xe5\xe5\x85\x61\xc3\x86\xa1\ +\xa4\xb8\x00\xfb\xb6\xfe\x20\x07\xb8\x30\x05\xbd\xfa\x67\x16\xd2\ +\x93\xb7\x49\x56\x83\xba\xc3\xa5\xf7\x96\x7b\x40\xce\x0f\xc0\xbe\ +\xde\x3c\x29\x93\x3a\xa7\x7a\x44\x1d\xbc\x3c\x75\x21\x16\x6f\x38\ +\x89\x76\x4f\xc4\x81\x33\xb9\x31\xae\x1d\x06\x1f\xad\xb0\x97\x52\ +\x15\xc3\x00\x85\xe4\x0a\x91\xad\x59\xe0\x4c\x78\xe8\x91\xb6\x98\ +\x9f\x78\x04\x93\xe6\xfd\x88\xfa\x0f\x35\x17\xbf\x61\xb3\x14\xe3\ +\x7a\xca\xd7\x48\x8f\x8f\x45\xee\xde\x45\x28\xcb\xcb\x91\xc8\x6c\ +\xab\xa1\x30\xf1\xd6\x85\x8b\x67\x4f\x20\xeb\xe4\x21\x07\xe7\xaf\ +\xd0\x5f\x27\x0f\xef\xc6\x8d\xab\x7f\xa2\x6b\xd7\xae\xa8\x57\xaf\ +\x1e\x31\x7c\x90\x95\xcc\x6b\x52\xc5\x0d\xe7\x2e\x5c\xb8\x40\x9b\ +\x37\x6f\x0e\xff\x90\x70\x2c\xfa\xe5\x04\xcc\x66\x1f\x09\x07\x46\ +\xed\x58\x83\x09\x83\x5b\xe1\x92\xb0\x58\x37\xbc\x27\xd0\x7e\x0d\ +\x50\x9e\x07\x5c\x5e\x07\x9c\xfb\xd2\x81\xf9\x37\x7c\xb8\x35\xfa\ +\x3c\x37\x0e\x6d\xbb\x0d\x80\xb7\x8f\x9f\x7c\x23\x3f\xaa\xc0\x8e\ +\x50\xc7\x45\x76\xac\xb5\x48\xeb\x59\xc9\xcb\x85\xf0\x0a\x4b\x39\ +\x4e\x1e\xde\x83\x6d\x6b\xbf\xe2\x95\x51\xa9\x5d\x4c\x66\x3f\xd4\ +\x68\x3b\x12\xb5\x7b\xbc\x03\xcf\xa0\x48\x64\xff\x32\x19\x57\x92\ +\xe6\xd9\xad\x2b\xcd\xda\x62\xda\x97\x9b\x11\x10\x5c\x4d\x26\x57\ +\xd8\xa8\x0d\xef\x8f\xee\x8e\x8c\x23\x7b\x91\x9c\x9c\x8c\x4e\x9d\ +\x3a\x55\x69\xdb\x11\xd5\x1d\x17\x8d\x9c\x29\x60\xb3\xd9\xd0\xab\ +\x57\x2f\xba\x7b\xf7\x1e\xbc\xff\xc5\x46\xb4\xea\xd2\x5b\x36\xd5\ +\xcf\x65\xa6\x61\xd2\xd0\xb6\x76\xa3\xa8\x9b\x9f\xbd\x73\x04\x3e\ +\x73\xf7\x04\x40\xa5\x4d\xc3\x83\xab\x45\xa0\x5d\xf7\xa7\x11\xf7\ +\xe2\x64\x54\x0b\xaf\xa5\xda\x90\xf2\x0d\x8d\x88\x8c\x8c\xea\xc5\ +\xb7\x0b\x78\x92\x10\x41\x59\x90\x21\xdb\xf1\xbc\x98\x5f\x74\xef\ +\x0e\x76\x24\x2e\xc3\xee\x8d\xab\x70\xf5\xcf\x73\x72\x92\x1b\xd1\ +\x14\xe1\x1d\xff\x03\x9f\x9a\xcd\x90\xb9\xa4\x1f\xac\x65\x76\x07\ +\xdc\xc4\x39\x6b\xf0\x78\xdf\xe7\x64\x92\x5b\xce\x85\x53\x78\x73\ +\x70\x4b\x74\xea\xd8\x01\xdb\xb7\x6f\x97\xed\xbb\xed\x4a\x7b\xdf\ +\xd7\xb6\xcc\xd7\xaf\x5f\xa7\xed\xdb\xb7\x87\xd5\xe4\x8d\x4f\xd7\ +\xa6\xc2\xcb\xc7\x5f\x5c\xb6\x1e\xff\x46\x1c\x0e\xed\xde\xc8\xd3\ +\xc4\x08\xc0\x23\x10\xb8\x77\x46\xc6\x0c\xc2\x6b\x37\x40\x9f\x61\ +\x63\xd1\x6d\xc0\x28\x78\xfb\xfa\x8b\x08\x54\x56\x5a\x56\x6e\x87\ +\x49\xe1\x08\x10\x55\xdb\x0c\x83\x95\x94\xd9\x91\x2d\xe2\xee\xe5\ +\x52\xb4\x43\x1e\x96\xf2\x32\xa4\xed\xdb\x8a\x84\x65\x33\xf1\xe7\ +\xb9\x0c\x50\x2a\x0d\x64\xcf\xe0\xda\xe0\x4c\x1e\x28\xbd\x65\xdf\ +\xcc\x36\xb2\xde\x43\xf8\x62\x53\x06\x38\x93\x1b\x08\x80\xbc\x1b\ +\x57\x31\x6f\xf2\x30\x5c\xbd\xf0\x07\x8e\x1e\x3d\x8a\x7a\xf5\xea\ +\x91\xaa\xee\xdb\xc3\xb9\xc2\x7b\x94\xef\xc2\xc3\xc3\xc9\x07\x1f\ +\x7c\x80\x2b\xd9\xa7\xb1\xe0\xdd\x91\xa2\x82\x97\x7b\xe9\x2c\xd2\ +\xf7\xff\x2a\x25\x2c\xbd\x06\xdc\x3b\x2d\x76\x8e\x97\x8f\x1f\x26\ +\x7d\xf2\x23\x96\xfd\x9a\x85\x7e\xcf\xbf\x01\x1f\x3f\x7f\xd1\x66\ +\x25\x43\x52\x51\x2a\xc2\xb3\xc4\xbd\x43\x55\x7a\x43\x82\x40\x51\ +\x99\x4f\x8e\xb0\xb0\x5c\xca\x98\x5f\x64\x9e\x59\x30\x52\x98\x24\ +\x8d\x79\x78\x9a\xd1\xbe\xc7\x20\x2c\x5c\x7f\x1c\xf3\xd6\x1e\x44\ +\x8d\xc8\xfa\x62\xaa\xf2\x3b\x97\xc5\xce\x11\x10\x40\xe9\xc9\xdb\ +\x78\xa8\x15\xc5\x2f\xdf\xce\xc3\xa9\xf4\x64\xbc\xf6\xda\x6b\xa8\ +\x5f\xbf\x3e\x51\x9b\x21\x46\x4e\x53\x71\xd8\x2f\x4e\x0b\x40\xa2\ +\xf7\x6e\xe0\xc0\x81\xa4\x71\xe3\xc6\x48\x4f\xde\x86\xcc\xf4\xfd\ +\xb0\xd9\x28\x92\x7e\xf9\xc6\xbe\xab\x94\xe2\x0a\x09\x8b\xc4\x8b\ +\x6f\xcf\xc3\xc2\xf5\xc7\xd1\xf9\xa9\x67\xf9\x2d\xcb\x18\x90\xa1\ +\x12\x08\xea\x60\x86\x11\x48\x11\x95\x91\x3c\x29\x3d\x91\x66\x06\ +\xd3\xd3\x54\xe1\xd6\x96\x6d\x5b\xa1\xe1\x9d\xa5\x90\x56\x78\x47\ +\x37\x7d\x14\xf3\x13\xd3\xf0\xda\xb4\xaf\x10\x15\x13\xab\xda\xa8\ +\x3b\x12\x97\xc1\x66\xa3\xb8\x76\xf9\x3c\xf6\x6c\xfa\x0e\xc1\xc1\ +\xc1\x18\x33\x66\x0c\x5c\x69\x5f\x55\xbc\xb6\x72\x5d\xa4\xde\x39\ +\x0c\x5a\x5b\x30\x27\x25\x25\xd1\x7e\xfd\xfa\x21\x30\x34\x02\xaf\ +\xbc\xff\x05\x16\x4f\xfb\x0f\xee\xdc\xba\xc6\xa7\xe7\xd0\xa8\x59\ +\x1b\x74\x1f\x30\x0a\x5d\x7a\x0f\x13\xb1\x61\x50\x57\xd8\x19\x92\ +\xa6\xdc\xf1\x97\x35\x2e\xda\x5d\x1c\x54\xd8\xdf\x4d\x3c\x3a\x4d\ +\xda\x0c\x50\xce\xaf\xd4\x9f\x59\xc9\xc1\x9e\x17\x65\xbe\x23\xb7\ +\x3e\x09\x75\xb6\x56\x56\xe0\xf0\xde\x2d\xd8\xb5\xf1\x5b\x1c\x4f\ +\xd9\x29\x6e\xb0\xe1\xe1\x69\xc6\xe7\x3f\x1f\xc3\xa2\xf7\x47\xe3\ +\xaf\x9c\x33\x58\xb0\x60\x01\x46\x8e\x1c\x49\xaa\x72\xae\x05\x3b\ +\x8b\x4c\xd3\xa7\x4f\xd7\x75\x1a\x19\x39\x18\x22\x2a\x2a\xea\x23\ +\xab\xd5\x3a\x7d\xeb\xe6\x0d\xa8\x28\x2f\x43\xe1\xbd\x3c\x14\xdd\ +\xbb\x0b\xbf\x80\x60\x3c\x39\xf8\x25\x4c\x9c\xb3\x06\xd1\x8f\xb4\ +\x85\xbb\x87\xa7\xdd\x6f\xc2\xba\x86\x15\x40\x0e\x22\x3a\xb9\xa8\ +\x08\xcb\xa5\x0c\xf7\x27\xbc\x9f\x88\x30\x07\x3a\xc9\x5c\xd6\x7c\ +\x27\x50\x30\x5b\x28\xb2\xab\x29\xa8\xdc\x81\x08\xb6\xc3\xc1\x3a\ +\x0d\xf9\xef\xf0\x1b\x68\x8b\xbb\x40\x12\x13\x6a\x45\x35\x46\x97\ +\xa7\x86\x22\x20\xa4\x3a\x2e\x9e\x3d\x8e\xd2\xe2\x42\x04\x84\x54\ +\x47\x85\xa5\x1c\x29\x3b\xd7\x61\xec\xd8\xb1\x98\x3c\x79\x32\xd1\ +\x73\xca\x39\x9b\x14\xe2\x4f\xed\x68\x00\x67\xb6\x39\x65\x4f\x13\ +\x42\x50\x51\x51\x81\x21\x43\x86\xd0\x2d\x5b\xb7\xa2\xf3\x53\x43\ +\xd1\xbe\x7b\x1c\x1e\x6e\xd5\x19\x3e\xfe\x41\x8c\x74\xe7\x6c\x3f\ +\x29\xc7\xed\xc7\xa5\xed\xc6\x01\xa8\x1c\x0d\xc0\x36\xb2\x73\x0d\ +\x55\x1e\xae\x8a\x3f\x25\xda\x80\x7c\x76\x5d\xba\x90\xbe\xac\xb4\ +\x18\xb9\x17\xcf\xe0\xd0\x9e\x4d\x58\xb7\x62\x36\x5a\x34\x6f\x8e\ +\x7d\xfb\xf6\x89\x07\x71\x68\x91\x30\xa3\xc2\x19\xe7\x8a\x1d\x4e\ +\x8f\x2f\xb9\xbb\xbb\x63\xc9\x92\x25\x88\x08\x0f\xc7\xfe\xad\x3f\ +\xa2\xf0\xde\x1d\xf8\x04\x04\x3b\x80\x37\xa8\x83\x22\xc9\xb8\xcd\ +\x45\x96\xa0\x58\x32\x41\x18\xd4\x37\x51\xb8\xd1\x85\x19\xa1\x70\ +\x41\x4b\x70\x63\xf6\x99\x48\x9b\x3b\x29\xc0\x23\x72\xb7\xbd\x34\ +\xc3\xa8\xca\x2a\x3b\x4a\x24\xf8\xaf\x97\xb7\x2f\xca\x4a\x8a\xf1\ +\xcb\x37\xf3\xe0\xed\xe5\x85\xef\xbe\xfb\x0e\x7e\x7e\x7e\x0f\xe4\ +\x1c\xf4\x2a\xef\xd5\xa3\xe5\x92\x08\x0b\x0b\x23\xf3\xe7\xcf\x47\ +\x78\x78\x0d\x7c\xbf\x68\x1a\xae\x64\x9f\x96\x76\xce\x95\x81\x49\ +\x04\xa9\x8c\x97\xd2\x44\x48\x30\x65\x9c\x5c\x8c\xd9\x9e\x2a\xdc\ +\x19\x80\x43\x18\xa1\x2c\x26\x97\x07\x16\x12\x16\x48\x28\xad\x35\ +\x25\x32\x74\xb8\x54\x0e\x36\x9c\xf0\xab\xb5\xd9\xf2\x08\x52\x1a\ +\xdb\x8d\xd9\x67\x8e\x63\xc5\x9c\x09\xf0\xf6\x32\x63\xd5\xaa\x55\ +\x88\x89\x89\x21\x5a\xee\x9a\xaa\xfc\x44\x77\x83\x9e\x62\xaa\x77\ +\xce\x9d\xda\x29\x1f\xc7\x8f\x1f\xa7\x4f\x3e\xf9\x24\x0a\x8b\x4a\ +\x30\x21\x7e\x15\x3a\xf4\x18\xc4\xc0\x84\xa9\xe2\x9e\x71\x35\xb3\ +\x67\x39\x10\xa8\xc4\x17\xb5\x4d\x05\x39\xaa\x42\x7c\x99\xa8\xad\ +\x2c\x8f\xca\xe2\x23\x36\x0e\x9f\xfe\xec\x89\x14\xcc\x18\xd3\x0f\ +\x96\xb2\x62\x6c\xd8\xb0\x01\x3d\x7b\xf6\x24\xca\x36\x73\x26\x60\ +\x39\x6b\x6f\xcd\x83\x6e\x95\x7c\xc6\xe8\x01\xe1\x00\xd0\xa2\x45\ +\x0b\xb2\x60\xc1\x02\x58\xca\x4b\x31\x7f\xca\xf3\xc8\x3a\xc9\x83\ +\x4c\x88\x62\x17\x12\x66\x55\x22\x51\xec\x43\x20\xdf\xac\x8f\x71\ +\x80\x41\xc5\xe9\x2a\x5b\x51\x2d\xdf\x76\x46\x2b\xbe\xe4\x50\x03\ +\xb3\xd2\x9c\xd1\x84\x89\x7c\x71\x1a\x91\x2d\x73\xa4\xb8\x71\xf5\ +\x22\x66\x8e\x7b\x1a\x85\xf7\xee\x60\xca\x94\x29\xb2\xce\xd1\x83\ +\x50\xbb\xda\xde\x44\xb9\xe9\xb6\x9e\xd8\xe7\xec\x3d\xdb\xfb\x36\ +\x9b\x0d\xeb\xd6\xad\xa3\x6f\xbc\xf1\x06\xca\x2a\x28\x46\xbe\x39\ +\x1b\xdd\xfa\x8f\x04\x67\x32\x39\x0c\x4e\x46\xb8\x85\xfe\x69\x1b\ +\x2a\xef\x65\x72\x03\x33\x03\x54\x8f\x3b\xa1\xec\xc2\x51\x1d\x88\ +\x0f\xd1\xfc\x3e\x05\x70\xe0\xb7\x75\x58\x31\x7b\x02\x2c\xa5\x05\ +\x58\xb9\x72\x25\xe2\xe2\xe2\x88\x87\x87\x87\xa1\x83\xe2\x5d\x6d\ +\x67\xdd\xd3\x4f\x1e\xc4\x95\x91\x91\x41\xfb\xf7\xef\x8f\x9c\x9c\ +\xcb\xe8\x36\x60\x24\x5e\x9a\xf2\xb9\xb8\xd2\x4c\xb9\x8c\x91\x10\ +\xe5\x4e\x87\x0a\xca\xe7\x2c\x8e\x0a\xc5\x72\x10\xf8\xd4\xa8\xa0\ +\x32\x7f\x8d\x6f\x95\x97\x95\x62\xdd\x8a\x39\xf8\x79\xe5\x1c\x04\ +\xf8\xfb\xe1\xa7\x9f\x7e\x42\xf7\xee\xdd\xc9\xdf\xd9\x7e\x9c\x2b\ +\x27\x3f\x6a\xd1\x49\xbd\x74\x4d\x9b\x36\x25\x4b\x96\x2c\x41\xc3\ +\x86\x0d\xb0\x6b\xc3\xb7\x58\x3e\xfb\x0d\xd1\xff\x42\x18\x93\x8c\ +\x68\xea\xa1\x44\x75\x0f\x20\x89\xa6\x2b\xd6\xe8\xf0\x9b\x9f\xcb\ +\xac\x00\xac\xc9\x48\xdc\x84\x1c\x8a\xfd\x9d\xe4\x0b\x7c\x09\x18\ +\x4b\x84\x28\x0a\x43\x84\x56\x15\xe6\xdf\xc1\xd2\x99\x63\xb1\x6e\ +\x79\x3c\xea\xd4\xae\x85\x2f\xbf\xfc\x52\xec\x1c\x23\x67\xc6\x56\ +\xe5\x24\x4d\xd9\x0c\xd2\x3b\x45\x57\x6b\x8f\x4d\x3d\xf9\x5e\x79\ +\x5f\x5c\x5c\x8c\xc9\x93\x27\xd3\xa5\x4b\x97\xda\x51\x38\x6f\x7d\ +\x82\x2e\xbd\x87\xd9\x95\x57\xca\x9f\x4a\xe2\xe0\xd3\xa7\x8c\x25\ +\x88\x48\x67\x26\x50\xc6\x3a\xa0\xa4\x66\x4a\xd8\xb0\x08\xcd\x25\ +\xe2\x52\x4d\x87\x77\xec\xf9\x40\x90\x77\x6e\x79\x79\x09\x4e\xa4\ +\xee\xc2\xca\xb9\x6f\xe2\x46\xee\x25\xf4\xef\xdf\x1f\xcb\x97\x2f\ +\x5f\x57\xad\x5a\xb5\x21\x5a\x75\x75\x76\xef\xec\x9d\x83\x35\x5b\ +\xef\xe4\x2d\x2d\xfa\xa8\x25\xcd\xe9\x9d\xe3\x46\x29\xc5\x0f\x3f\ +\xfc\x40\x27\x4d\x9a\x84\x9b\xb7\x6e\xa1\x76\xfd\xc6\x98\x10\xbf\ +\x1a\x0d\x9a\xb4\x94\xcd\x10\x61\xbd\x91\xba\x24\x04\x11\x30\x29\ +\x8c\x72\x42\x94\x65\x70\x3c\x37\x50\x3a\xd9\x97\xf5\x15\xa9\x7d\ +\x03\xa2\xc9\xe7\xc6\xd5\x3f\x31\xfb\x8d\x81\xb8\x94\x75\x12\x6e\ +\x6e\x26\xac\x5e\xbd\x5a\xc6\x6f\xf4\x4e\x29\xd3\x6b\x3f\x67\x6d\ +\x2b\x0b\xfb\xbb\x4f\x81\x54\x63\x82\xd9\xd9\xd9\x74\xc2\x84\x09\ +\xd8\xbe\x7d\x3b\xbc\x7c\xfc\xd1\x77\xf8\x78\x74\x7c\x72\x30\x6a\ +\x37\x68\x52\xa5\x13\x14\xa9\x2e\x5b\x77\x72\xc8\x97\xc3\x16\x0b\ +\x14\xb7\xae\x5f\xc6\x81\x1d\x89\xd8\xfc\xfd\x42\xdc\xcb\xbb\x81\ +\x36\x6d\xda\x60\xc1\x82\x05\x68\xdd\xba\x35\x79\x90\x27\x3c\x1a\ +\x76\xd8\x55\xa9\x51\x0c\x8e\x02\xad\xb4\x56\xab\x15\x07\x0f\x1e\ +\xa4\xf1\xf1\xf1\xd8\xb9\x73\x27\xdc\xdc\x3d\xd0\xee\x89\x38\xf4\ +\x88\x1b\x8d\x98\xd8\x8e\x76\xd2\xe7\xd0\x88\x54\x8d\x0e\x89\x16\ +\x6a\xe2\xe0\x30\x52\xef\x0c\xb5\xb7\x56\x6b\x25\x2e\x9c\x4a\xc7\ +\xee\x8d\xab\xb1\xff\xd7\x1f\x51\x52\x54\x80\x36\x6d\xda\x20\x3e\ +\x3e\x1e\x1d\x3b\x76\x24\x9e\x9e\x9e\x2e\xd5\x5d\x4b\xdf\x71\xb5\ +\xcd\xfe\xeb\x33\x48\x59\x28\xab\xd5\x8a\xb5\x6b\xd7\xd2\x39\x73\ +\xe6\xe0\xd4\xa9\x53\x00\x21\xa8\xdb\xa8\x29\x46\x4f\xfe\x0c\x0d\ +\x9b\xb4\x86\xb7\xaf\xbf\x8e\xfd\xae\xca\x25\x10\xc5\xbb\xf2\xd2\ +\x62\x5c\xce\x3e\x8d\x55\xf3\xdf\x41\x66\x7a\x32\xa8\xcd\x86\x5a\ +\xb5\x6a\x61\xe2\xc4\x89\x18\x33\x66\x8c\xae\x27\xf4\xbf\x3e\x83\ +\x8c\x30\x37\x35\x29\xc4\x08\x23\x54\xcb\x97\x4d\x6b\xb1\x58\xb0\ +\x7e\xfd\x7a\x9a\x90\x90\x80\xe4\xe4\x64\xe4\xe7\xe7\xc3\x2f\x20\ +\x18\x2d\x3a\xf4\x40\x4c\x6c\x27\x34\x68\xd2\x12\x75\x1a\x3e\x0c\ +\xb3\x97\x8f\x6c\xce\xc8\x4f\x71\x54\x18\x43\x45\xcb\xb6\xe4\x8c\ +\xab\xb0\x58\x70\xe5\xe2\x19\x64\x9d\x3c\x84\x73\x99\x69\x38\x7e\ +\xe0\x37\xe4\xdd\xbc\x0a\x6f\x6f\x6f\xb4\x6f\xdf\x1e\x71\x71\x71\ +\x18\x3e\x7c\x38\xf1\xf5\xf5\x75\xda\x2e\x6a\xef\x5c\x39\x0a\xda\ +\x90\x00\xf1\xbf\x31\x83\x9c\xcd\xae\x5b\xb7\x6e\xa5\x6f\xd9\xb2\ +\xa5\x65\x52\x52\x12\xb6\x6f\xdf\x8e\x82\x82\x02\x10\x8e\x43\x40\ +\x50\x35\x84\x45\xd6\x43\x78\xed\x06\x88\xac\x17\x8d\x6a\x35\x6a\ +\x23\xb8\x7a\x04\xbc\x7c\xfc\x60\xf6\xf6\x15\xdd\xe6\xa5\xc5\x85\ +\x28\x29\x2a\x40\x79\x69\x09\xee\xde\xfe\x0b\x37\x72\x2f\xe2\x7a\ +\xee\x45\xe4\x5e\x3c\x83\x5b\xd7\x2e\xe3\x6e\xde\x0d\xd8\xac\x95\ +\xf0\xf2\xf2\x42\xb7\x6e\xdd\xd0\xbd\x7b\x77\xc4\xc5\xc5\xa1\x66\ +\xcd\x9a\x84\xe3\x38\x97\x49\xf6\x83\xa6\x2a\x9a\x52\x9c\x1a\xad\ +\xd4\x92\x50\xb4\xc4\x6f\x67\x52\x8c\xd6\x48\x54\x8b\x53\x56\x56\ +\x86\xb4\xb4\x34\x7a\xf0\xe0\x41\x1c\x39\x72\x04\x69\x69\x69\xb8\ +\x7d\xfb\x36\x4a\x4b\xa5\xa3\xa3\xcd\x5e\x3e\xf0\xf4\xf2\x81\xa7\ +\xd9\x1b\x66\x6f\x1f\x7b\xba\xd2\x62\x94\x95\x14\xc3\x52\x5e\x8a\ +\xb2\x92\x22\x31\x4f\xb3\xd9\x8c\xa0\xa0\x20\xb4\x68\xd1\x02\x1d\ +\x3b\x76\x44\xab\x56\xad\xd0\xb6\x6d\x5b\xd9\x19\xdd\x7a\x87\xc7\ +\x3b\xe3\x21\x55\x89\xa3\xd7\x76\x55\x96\xe2\x1e\xc4\xa1\xae\x55\ +\x49\x53\x52\x52\x82\x3b\x77\xee\xd0\x6b\xd7\xae\x21\x2b\x2b\x0b\ +\x97\x2f\x5f\x46\x6e\x6e\x2e\x0a\x0a\x0a\x50\x58\x58\x28\xee\x86\ +\x12\x10\x10\x80\xc0\xc0\x40\xf8\xf8\xf8\x20\x22\x22\x02\xf5\xeb\ +\xd7\x47\xfd\xfa\xf5\x51\xa7\x4e\x1d\x04\x06\x06\x12\x3f\x3f\x3f\ +\xfc\x5f\xb8\x34\x3b\xc8\x88\x44\x52\x55\x79\xff\x41\xd9\xfd\x5c\ +\x71\x7a\x19\x91\xa6\x8c\x94\xdb\x48\xf9\x1e\x74\xfe\xff\x38\x1e\ +\xf4\xef\xa5\xb0\xc5\x69\x1d\x56\xab\xd7\xbb\xce\x40\xf6\x46\xc0\ +\x10\x7a\xe9\x8d\x40\x92\x8c\xa6\x77\x56\x3f\x67\xe5\x77\xb5\x7d\ +\x8c\xd4\xdf\x95\xef\xff\x3b\x83\xfe\xe1\x97\xdb\xbf\x1d\xf4\xcf\ +\xbe\xfe\x96\x19\xf4\xdf\xd4\x1f\xfe\xbf\x7f\x9f\x38\xa3\xa9\x46\ +\x80\x8c\x55\xb5\x26\xe8\x69\xe7\x46\x74\x12\x57\xca\xab\xa7\x7b\ +\x3c\xc8\xfc\xd5\x0e\x26\x71\x35\x7f\xb6\x8c\xaa\x3b\x2e\xea\x89\ +\xd8\x46\x3e\xe2\x8a\xd8\xeb\x4c\x91\x75\x96\xde\xe8\xce\x85\xce\ +\x44\x60\x36\xdc\xc8\xa9\xcc\x7a\xdf\xd6\x7a\x6f\x34\x7f\x59\x5e\ +\x7f\xb7\xcb\xfb\xdf\xeb\xfe\xae\xff\x01\x23\xea\xed\xde\xc5\xed\ +\x5c\x00\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\ +" + +qt_resource_name = b"\ +\x00\x07\ +\x07\x3b\xe0\xb3\ +\x00\x70\ +\x00\x6c\x00\x75\x00\x67\x00\x69\x00\x6e\x00\x73\ +\x00\x06\ +\x06\x98\x2f\xb3\ +\x00\x63\ +\x00\x61\x00\x6c\x00\x69\x00\x65\x00\x63\ +\x00\x08\ +\x0a\x61\x5a\xa7\ +\x00\x69\ +\x00\x63\x00\x6f\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\x14\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\ +\x00\x00\x00\x26\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ +" + +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\x14\x00\x02\x00\x00\x00\x01\x00\x00\x00\x03\ +\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x26\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ +\x00\x00\x01\x77\xed\xcb\x53\xaa\ +" + +qt_version = [int(v) for v in 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/orientation/resources.qrc b/orientation/resources.qrc new file mode 100644 index 0000000..e63f8a6 --- /dev/null +++ b/orientation/resources.qrc @@ -0,0 +1,5 @@ + + + icon.png + + diff --git a/pb_tool.cfg b/pb_tool.cfg new file mode 100644 index 0000000..5be82bb --- /dev/null +++ b/pb_tool.cfg @@ -0,0 +1,80 @@ +#/*************************************************************************** +# Orientation +# +# Configuration file for plugin builder tool (pb_tool) +# Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/ +# ------------------- +# begin : 2021-03-01 +# copyright : (C) 2021 by Association Linux-Alpes +# email : caliec@linux-alpes.org +# ***************************************************************************/ +# +#/*************************************************************************** +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU General Public License as published by * +# * the Free Software Foundation; either version 2 of the License, or * +# * (at your option) any later version. * +# * * +# ***************************************************************************/ +# +# +# You can install pb_tool using: +# pip install http://geoapt.net/files/pb_tool.zip +# +# Consider doing your development (and install of pb_tool) in a virtualenv. +# +# For details on setting up and using pb_tool, see: +# http://g-sherman.github.io/plugin_build_tool/ +# +# Issues and pull requests here: +# https://github.com/g-sherman/plugin_build_tool: +# +# Sane defaults for your plugin generated by the Plugin Builder are +# already set below. +# +# As you add Python source files and UI files to your plugin, add +# them to the appropriate [files] section below. + +[plugin] +# Name of the plugin. This is the name of the directory that will +# be created +name: caliec + +# Full path to where you want your plugin directory copied. If empty, +# the QGIS default path will be used. Don't include the plugin name in +# the path. +plugin_path: + +[files] +# Python files that should be deployed with the plugin +python_files: __init__.py caliec.py + +# The main dialog file that is loaded (not compiled) +main_dialog: + +# Other ui files for dialogs you create (these will be compiled) +compiled_ui_files: + +# Resource file(s) that will be compiled +resource_files: resources.qrc + +# Other files required for the plugin +extras: metadata.txt icon.png + +# Other directories to be deployed with the plugin. +# These must be subdirectories under the plugin directory +extra_dirs: + +# ISO code(s) for any locales (translations), separated by spaces. +# Corresponding .ts files must exist in the i18n directory +locales: + +[help] +# the built help directory that should be deployed with the plugin +dir: help/build/html +# the name of the directory to target in the deployed plugin +target: help + + + diff --git a/plugin_upload.py b/plugin_upload.py new file mode 100755 index 0000000..a88ea2b --- /dev/null +++ b/plugin_upload.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python +# coding=utf-8 +"""This script uploads a plugin package to the plugin repository. + Authors: A. Pasotti, V. Picavet + git sha : $TemplateVCSFormat +""" + +import sys +import getpass +import xmlrpc.client +from optparse import OptionParser + +standard_library.install_aliases() + +# Configuration +PROTOCOL = 'https' +SERVER = 'plugins.qgis.org' +PORT = '443' +ENDPOINT = '/plugins/RPC2/' +VERBOSE = False + + +def main(parameters, arguments): + """Main entry point. + + :param parameters: Command line parameters. + :param arguments: Command line arguments. + """ + address = "{protocol}://{username}:{password}@{server}:{port}{endpoint}".format( + protocol=PROTOCOL, + username=parameters.username, + password=parameters.password, + server=parameters.server, + port=parameters.port, + endpoint=ENDPOINT) + print("Connecting to: %s" % hide_password(address)) + + server = xmlrpc.client.ServerProxy(address, verbose=VERBOSE) + + try: + with open(arguments[0], 'rb') as handle: + plugin_id, version_id = server.plugin.upload( + xmlrpc.client.Binary(handle.read())) + print("Plugin ID: %s" % plugin_id) + print("Version ID: %s" % version_id) + except xmlrpc.client.ProtocolError as err: + print("A protocol error occurred") + print("URL: %s" % hide_password(err.url, 0)) + print("HTTP/HTTPS headers: %s" % err.headers) + print("Error code: %d" % err.errcode) + print("Error message: %s" % err.errmsg) + except xmlrpc.client.Fault as err: + print("A fault occurred") + print("Fault code: %d" % err.faultCode) + print("Fault string: %s" % err.faultString) + + +def hide_password(url, start=6): + """Returns the http url with password part replaced with '*'. + + :param url: URL to upload the plugin to. + :type url: str + + :param start: Position of start of password. + :type start: int + """ + start_position = url.find(':', start) + 1 + end_position = url.find('@') + return "%s%s%s" % ( + url[:start_position], + '*' * (end_position - start_position), + url[end_position:]) + + +if __name__ == "__main__": + parser = OptionParser(usage="%prog [options] plugin.zip") + parser.add_option( + "-w", "--password", dest="password", + help="Password for plugin site", metavar="******") + parser.add_option( + "-u", "--username", dest="username", + help="Username of plugin site", metavar="user") + parser.add_option( + "-p", "--port", dest="port", + help="Server port to connect to", metavar="80") + parser.add_option( + "-s", "--server", dest="server", + help="Specify server name", metavar="plugins.qgis.org") + options, args = parser.parse_args() + if len(args) != 1: + print("Please specify zip file.\n") + parser.print_help() + sys.exit(1) + if not options.server: + options.server = SERVER + if not options.port: + options.port = PORT + if not options.username: + # interactive mode + username = getpass.getuser() + print("Please enter user name [%s] :" % username, end=' ') + + res = input() + if res != "": + options.username = res + else: + options.username = username + if not options.password: + # interactive mode + options.password = getpass.getpass() + main(options, args) diff --git a/pylintrc b/pylintrc new file mode 100644 index 0000000..7e168f6 --- /dev/null +++ b/pylintrc @@ -0,0 +1,281 @@ +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Profiled execution. +profile=no + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS + +# Pickle collected data for later comparisons. +persistent=yes + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + + +[MESSAGES CONTROL] + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time. See also the "--disable" option for examples. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +# see http://stackoverflow.com/questions/21487025/pylint-locally-defined-disables-still-give-warnings-how-to-suppress-them +disable=locally-disabled,C0103 + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html. You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=no + +# Tells whether to display a full report or only the messages +reports=yes + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Add a comment according to your evaluation note. This is used by the global +# evaluation report (RP0004). +comment=no + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + + +[BASIC] + +# Required attributes for module, separated by a comma +required-attributes= + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter,apply,input + +# Regular expression which should only match correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression which should only match correct module level names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression which should only match correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression which should only match correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct method names +method-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct instance attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct variable names +variable-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match correct attribute names in class +# bodies +class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Regular expression which should only match correct list comprehension / +# generator expression variable names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=__.*__ + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). +ignored-classes=SQLObject + +# When zope mode is activated, add a predefined set of Zope acquired attributes +# to generated-members. +zope=no + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E0201 when accessed. Python regular +# expressions are accepted. +generated-members=REQUEST,acl_users,aq_parent + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the beginning of the name of dummy variables +# (i.e. not used). +dummy-variables-rgx=_$|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=80 + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + +# List of optional constructs for which whitespace checking is disabled +no-space-check=trailing-comma,dict-separator + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,TERMIOS,Bastion,rexec + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=5 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branches=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + + +[CLASSES] + +# List of interface methods to ignore, separated by a comma. This is used for +# instance to not check methods defines in Zope's Interface base class. +ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..8feeb0b --- /dev/null +++ b/test/__init__.py @@ -0,0 +1,2 @@ +# import qgis libs so that ve set the correct sip api version +import qgis # pylint: disable=W0611 # NOQA \ No newline at end of file diff --git a/test/__init__.pyc b/test/__init__.pyc new file mode 100644 index 0000000..72398f3 Binary files /dev/null and b/test/__init__.pyc differ diff --git a/test/__pycache__/__init__.cpython-36.pyc b/test/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000..7bf087e Binary files /dev/null and b/test/__pycache__/__init__.cpython-36.pyc differ diff --git a/test/__pycache__/qgis_interface.cpython-36.pyc b/test/__pycache__/qgis_interface.cpython-36.pyc new file mode 100644 index 0000000..23e2451 Binary files /dev/null and b/test/__pycache__/qgis_interface.cpython-36.pyc differ diff --git a/test/__pycache__/test_init.cpython-36.pyc b/test/__pycache__/test_init.cpython-36.pyc new file mode 100644 index 0000000..9b76c67 Binary files /dev/null and b/test/__pycache__/test_init.cpython-36.pyc differ diff --git a/test/__pycache__/test_qgis_environment.cpython-36.pyc b/test/__pycache__/test_qgis_environment.cpython-36.pyc new file mode 100644 index 0000000..caaf5df Binary files /dev/null and b/test/__pycache__/test_qgis_environment.cpython-36.pyc differ diff --git a/test/__pycache__/test_resources.cpython-36.pyc b/test/__pycache__/test_resources.cpython-36.pyc new file mode 100644 index 0000000..eeb8531 Binary files /dev/null and b/test/__pycache__/test_resources.cpython-36.pyc differ diff --git a/test/__pycache__/test_translations.cpython-36.pyc b/test/__pycache__/test_translations.cpython-36.pyc new file mode 100644 index 0000000..f583d27 Binary files /dev/null and b/test/__pycache__/test_translations.cpython-36.pyc differ diff --git a/test/__pycache__/utilities.cpython-36.pyc b/test/__pycache__/utilities.cpython-36.pyc new file mode 100644 index 0000000..67d11d7 Binary files /dev/null and b/test/__pycache__/utilities.cpython-36.pyc differ diff --git a/test/qgis_interface.py b/test/qgis_interface.py new file mode 100644 index 0000000..a407052 --- /dev/null +++ b/test/qgis_interface.py @@ -0,0 +1,205 @@ +# coding=utf-8 +"""QGIS plugin implementation. + +.. note:: This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + +.. note:: This source code was copied from the 'postgis viewer' application + with original authors: + Copyright (c) 2010 by Ivan Mincik, ivan.mincik@gista.sk + Copyright (c) 2011 German Carrillo, geotux_tuxman@linuxmail.org + Copyright (c) 2014 Tim Sutton, tim@linfiniti.com + +""" + +__author__ = 'tim@linfiniti.com' +__revision__ = '$Format:%H$' +__date__ = '10/01/2011' +__copyright__ = ( + 'Copyright (c) 2010 by Ivan Mincik, ivan.mincik@gista.sk and ' + 'Copyright (c) 2011 German Carrillo, geotux_tuxman@linuxmail.org' + 'Copyright (c) 2014 Tim Sutton, tim@linfiniti.com' +) + +import logging +from qgis.PyQt.QtCore import QObject, pyqtSlot, pyqtSignal +from qgis.core import QgsMapLayerRegistry +from qgis.gui import QgsMapCanvasLayer +LOGGER = logging.getLogger('QGIS') + + +#noinspection PyMethodMayBeStatic,PyPep8Naming +class QgisInterface(QObject): + """Class to expose QGIS objects and functions to plugins. + + This class is here for enabling us to run unit tests only, + so most methods are simply stubs. + """ + currentLayerChanged = pyqtSignal(QgsMapCanvasLayer) + + def __init__(self, canvas): + """Constructor + :param canvas: + """ + QObject.__init__(self) + self.canvas = canvas + # Set up slots so we can mimic the behaviour of QGIS when layers + # are added. + LOGGER.debug('Initialising canvas...') + # noinspection PyArgumentList + QgsMapLayerRegistry.instance().layersAdded.connect(self.addLayers) + # noinspection PyArgumentList + QgsMapLayerRegistry.instance().layerWasAdded.connect(self.addLayer) + # noinspection PyArgumentList + QgsMapLayerRegistry.instance().removeAll.connect(self.removeAllLayers) + + # For processing module + self.destCrs = None + + @pyqtSlot('QStringList') + def addLayers(self, layers): + """Handle layers being added to the registry so they show up in canvas. + + :param layers: list list of map layers that were added + + .. note:: The QgsInterface api does not include this method, + it is added here as a helper to facilitate testing. + """ + #LOGGER.debug('addLayers called on qgis_interface') + #LOGGER.debug('Number of layers being added: %s' % len(layers)) + #LOGGER.debug('Layer Count Before: %s' % len(self.canvas.layers())) + current_layers = self.canvas.layers() + final_layers = [] + for layer in current_layers: + final_layers.append(QgsMapCanvasLayer(layer)) + for layer in layers: + final_layers.append(QgsMapCanvasLayer(layer)) + + self.canvas.setLayerSet(final_layers) + #LOGGER.debug('Layer Count After: %s' % len(self.canvas.layers())) + + @pyqtSlot('QgsMapLayer') + def addLayer(self, layer): + """Handle a layer being added to the registry so it shows up in canvas. + + :param layer: list list of map layers that were added + + .. note: The QgsInterface api does not include this method, it is added + here as a helper to facilitate testing. + + .. note: The addLayer method was deprecated in QGIS 1.8 so you should + not need this method much. + """ + pass + + @pyqtSlot() + def removeAllLayers(self): + """Remove layers from the canvas before they get deleted.""" + self.canvas.setLayerSet([]) + + def newProject(self): + """Create new project.""" + # noinspection PyArgumentList + QgsMapLayerRegistry.instance().removeAllMapLayers() + + # ---------------- API Mock for QgsInterface follows ------------------- + + def zoomFull(self): + """Zoom to the map full extent.""" + pass + + def zoomToPrevious(self): + """Zoom to previous view extent.""" + pass + + def zoomToNext(self): + """Zoom to next view extent.""" + pass + + def zoomToActiveLayer(self): + """Zoom to extent of active layer.""" + pass + + def addVectorLayer(self, path, base_name, provider_key): + """Add a vector layer. + + :param path: Path to layer. + :type path: str + + :param base_name: Base name for layer. + :type base_name: str + + :param provider_key: Provider key e.g. 'ogr' + :type provider_key: str + """ + pass + + def addRasterLayer(self, path, base_name): + """Add a raster layer given a raster layer file name + + :param path: Path to layer. + :type path: str + + :param base_name: Base name for layer. + :type base_name: str + """ + pass + + def activeLayer(self): + """Get pointer to the active layer (layer selected in the legend).""" + # noinspection PyArgumentList + layers = QgsMapLayerRegistry.instance().mapLayers() + for item in layers: + return layers[item] + + def addToolBarIcon(self, action): + """Add an icon to the plugins toolbar. + + :param action: Action to add to the toolbar. + :type action: QAction + """ + pass + + def removeToolBarIcon(self, action): + """Remove an action (icon) from the plugin toolbar. + + :param action: Action to add to the toolbar. + :type action: QAction + """ + pass + + def addToolBar(self, name): + """Add toolbar with specified name. + + :param name: Name for the toolbar. + :type name: str + """ + pass + + def mapCanvas(self): + """Return a pointer to the map canvas.""" + return self.canvas + + def mainWindow(self): + """Return a pointer to the main window. + + In case of QGIS it returns an instance of QgisApp. + """ + pass + + def addDockWidget(self, area, dock_widget): + """Add a dock widget to the main window. + + :param area: Where in the ui the dock should be placed. + :type area: + + :param dock_widget: A dock widget to add to the UI. + :type dock_widget: QDockWidget + """ + pass + + def legendInterface(self): + """Get the legend.""" + return self.canvas diff --git a/test/test_init.py b/test/test_init.py new file mode 100644 index 0000000..a11ca44 --- /dev/null +++ b/test/test_init.py @@ -0,0 +1,64 @@ +# coding=utf-8 +"""Tests QGIS plugin init.""" + +__author__ = 'Tim Sutton ' +__revision__ = '$Format:%H$' +__date__ = '17/10/2010' +__license__ = "GPL" +__copyright__ = 'Copyright 2012, Australia Indonesia Facility for ' +__copyright__ += 'Disaster Reduction' + +import os +import unittest +import logging +import configparser + +LOGGER = logging.getLogger('QGIS') + + +class TestInit(unittest.TestCase): + """Test that the plugin init is usable for QGIS. + + Based heavily on the validator class by Alessandro + Passoti available here: + + http://github.com/qgis/qgis-django/blob/master/qgis-app/ + plugins/validator.py + + """ + + def test_read_init(self): + """Test that the plugin __init__ will validate on plugins.qgis.org.""" + + # You should update this list according to the latest in + # https://github.com/qgis/qgis-django/blob/master/qgis-app/ + # plugins/validator.py + + required_metadata = [ + 'name', + 'description', + 'version', + 'qgisMinimumVersion', + 'email', + 'author'] + + file_path = os.path.abspath(os.path.join( + os.path.dirname(__file__), os.pardir, + 'metadata.txt')) + LOGGER.info(file_path) + metadata = [] + parser = configparser.ConfigParser() + parser.optionxform = str + parser.read(file_path) + message = 'Cannot find a section named "general" in %s' % file_path + assert parser.has_section('general'), message + metadata.extend(parser.items('general')) + + for expectation in required_metadata: + message = ('Cannot find metadata "%s" in metadata source (%s).' % ( + expectation, file_path)) + + self.assertIn(expectation, dict(metadata), message) + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_qgis_environment.py b/test/test_qgis_environment.py new file mode 100644 index 0000000..1becb30 --- /dev/null +++ b/test/test_qgis_environment.py @@ -0,0 +1,60 @@ +# coding=utf-8 +"""Tests for QGIS functionality. + + +.. note:: This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + +""" +__author__ = 'tim@linfiniti.com' +__date__ = '20/01/2011' +__copyright__ = ('Copyright 2012, Australia Indonesia Facility for ' + 'Disaster Reduction') + +import os +import unittest +from qgis.core import ( + QgsProviderRegistry, + QgsCoordinateReferenceSystem, + QgsRasterLayer) + +from .utilities import get_qgis_app +QGIS_APP = get_qgis_app() + + +class QGISTest(unittest.TestCase): + """Test the QGIS Environment""" + + def test_qgis_environment(self): + """QGIS environment has the expected providers""" + + r = QgsProviderRegistry.instance() + self.assertIn('gdal', r.providerList()) + self.assertIn('ogr', r.providerList()) + self.assertIn('postgres', r.providerList()) + + def test_projection(self): + """Test that QGIS properly parses a wkt string. + """ + crs = QgsCoordinateReferenceSystem() + wkt = ( + 'GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",' + 'SPHEROID["WGS_1984",6378137.0,298.257223563]],' + 'PRIMEM["Greenwich",0.0],UNIT["Degree",' + '0.0174532925199433]]') + crs.createFromWkt(wkt) + auth_id = crs.authid() + expected_auth_id = 'EPSG:4326' + self.assertEqual(auth_id, expected_auth_id) + + # now test for a loaded layer + path = os.path.join(os.path.dirname(__file__), 'tenbytenraster.asc') + title = 'TestRaster' + layer = QgsRasterLayer(path, title) + auth_id = layer.crs().authid() + self.assertEqual(auth_id, expected_auth_id) + +if __name__ == '__main__': + unittest.main() diff --git a/test/test_resources.py b/test/test_resources.py new file mode 100644 index 0000000..b37f18c --- /dev/null +++ b/test/test_resources.py @@ -0,0 +1,44 @@ +# coding=utf-8 +"""Resources test. + +.. note:: This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + +""" + +__author__ = 'caliec@linux-alpes.org' +__date__ = '2021-03-01' +__copyright__ = 'Copyright 2021, Association Linux-Alpes' + +import unittest + +from qgis.PyQt.QtGui import QIcon + + + +class OrientationDialogTest(unittest.TestCase): + """Test rerources work.""" + + def setUp(self): + """Runs before each test.""" + pass + + def tearDown(self): + """Runs after each test.""" + pass + + def test_icon_png(self): + """Test we can click OK.""" + path = ':/plugins/Orientation/icon.png' + icon = QIcon(path) + self.assertFalse(icon.isNull()) + +if __name__ == "__main__": + suite = unittest.makeSuite(OrientationResourcesTest) + runner = unittest.TextTestRunner(verbosity=2) + runner.run(suite) + + + diff --git a/test/test_translations.py b/test/test_translations.py new file mode 100644 index 0000000..e81cc44 --- /dev/null +++ b/test/test_translations.py @@ -0,0 +1,55 @@ +# coding=utf-8 +"""Safe Translations Test. + +.. note:: This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + +""" +from .utilities import get_qgis_app + +__author__ = 'ismailsunni@yahoo.co.id' +__date__ = '12/10/2011' +__copyright__ = ('Copyright 2012, Australia Indonesia Facility for ' + 'Disaster Reduction') +import unittest +import os + +from qgis.PyQt.QtCore import QCoreApplication, QTranslator + +QGIS_APP = get_qgis_app() + + +class SafeTranslationsTest(unittest.TestCase): + """Test translations work.""" + + def setUp(self): + """Runs before each test.""" + if 'LANG' in iter(os.environ.keys()): + os.environ.__delitem__('LANG') + + def tearDown(self): + """Runs after each test.""" + if 'LANG' in iter(os.environ.keys()): + os.environ.__delitem__('LANG') + + def test_qgis_translations(self): + """Test that translations work.""" + parent_path = os.path.join(__file__, os.path.pardir, os.path.pardir) + dir_path = os.path.abspath(parent_path) + file_path = os.path.join( + dir_path, 'i18n', 'fr.qm') + translator = QTranslator() + translator.load(file_path) + QCoreApplication.installTranslator(translator) + + expected_message = 'Bonjour' + real_message = QCoreApplication.translate("@default", 'Good morning') + self.assertEqual(real_message, expected_message) + + +if __name__ == "__main__": + suite = unittest.makeSuite(SafeTranslationsTest) + runner = unittest.TextTestRunner(verbosity=2) + runner.run(suite) diff --git a/test/utilities.py b/test/utilities.py new file mode 100644 index 0000000..be7ee3b --- /dev/null +++ b/test/utilities.py @@ -0,0 +1,61 @@ +# coding=utf-8 +"""Common functionality used by regression tests.""" + +import sys +import logging + + +LOGGER = logging.getLogger('QGIS') +QGIS_APP = None # Static variable used to hold hand to running QGIS app +CANVAS = None +PARENT = None +IFACE = None + + +def get_qgis_app(): + """ Start one QGIS application to test against. + + :returns: Handle to QGIS app, canvas, iface and parent. If there are any + errors the tuple members will be returned as None. + :rtype: (QgsApplication, CANVAS, IFACE, PARENT) + + If QGIS is already running the handle to that app will be returned. + """ + + try: + from qgis.PyQt import QtGui, QtCore + from qgis.core import QgsApplication + from qgis.gui import QgsMapCanvas + from .qgis_interface import QgisInterface + except ImportError: + return None, None, None, None + + global QGIS_APP # pylint: disable=W0603 + + if QGIS_APP is None: + gui_flag = True # All test will run qgis in gui mode + #noinspection PyPep8Naming + QGIS_APP = QgsApplication(sys.argv, gui_flag) + # Make sure QGIS_PREFIX_PATH is set in your env if needed! + QGIS_APP.initQgis() + s = QGIS_APP.showSettings() + LOGGER.debug(s) + + global PARENT # pylint: disable=W0603 + if PARENT is None: + #noinspection PyPep8Naming + PARENT = QtGui.QWidget() + + global CANVAS # pylint: disable=W0603 + if CANVAS is None: + #noinspection PyPep8Naming + CANVAS = QgsMapCanvas(PARENT) + CANVAS.resize(QtCore.QSize(400, 400)) + + global IFACE # pylint: disable=W0603 + if IFACE is None: + # QgisInterface is a stub implementation of the QGIS plugin interface + #noinspection PyPep8Naming + IFACE = QgisInterface(CANVAS) + + return QGIS_APP, CANVAS, IFACE, PARENT diff --git a/utilitaires/compile-strings.sh b/utilitaires/compile-strings.sh new file mode 100644 index 0000000..9d76083 --- /dev/null +++ b/utilitaires/compile-strings.sh @@ -0,0 +1,12 @@ +#!/bin/bash +LRELEASE=$1 +LOCALES=$2 + + +for LOCALE in ${LOCALES} +do + echo "Processing: ${LOCALE}.ts" + # Note we don't use pylupdate with qt .pro file approach as it is flakey + # about what is made available. + $LRELEASE i18n/${LOCALE}.ts +done diff --git a/utilitaires/update-strings.sh b/utilitaires/update-strings.sh new file mode 100644 index 0000000..a31f712 --- /dev/null +++ b/utilitaires/update-strings.sh @@ -0,0 +1,56 @@ +#!/bin/bash +LOCALES=$* + +# Get newest .py files so we don't update strings unnecessarily + +CHANGED_FILES=0 +PYTHON_FILES=`find . -regex ".*\(ui\|py\)$" -type f` +for PYTHON_FILE in $PYTHON_FILES +do + CHANGED=$(stat -c %Y $PYTHON_FILE) + if [ ${CHANGED} -gt ${CHANGED_FILES} ] + then + CHANGED_FILES=${CHANGED} + fi +done + +# Qt translation stuff +# for .ts file +UPDATE=false +for LOCALE in ${LOCALES} +do + TRANSLATION_FILE="i18n/$LOCALE.ts" + if [ ! -f ${TRANSLATION_FILE} ] + then + # Force translation string collection as we have a new language file + touch ${TRANSLATION_FILE} + UPDATE=true + break + fi + + MODIFICATION_TIME=$(stat -c %Y ${TRANSLATION_FILE}) + if [ ${CHANGED_FILES} -gt ${MODIFICATION_TIME} ] + then + # Force translation string collection as a .py file has been updated + UPDATE=true + break + fi +done + +if [ ${UPDATE} == true ] +# retrieve all python files +then + echo ${PYTHON_FILES} + # update .ts + echo "Please provide translations by editing the translation files below:" + for LOCALE in ${LOCALES} + do + echo "i18n/"${LOCALE}".ts" + # Note we don't use pylupdate with qt .pro file approach as it is flakey + # about what is made available. + pylupdate4 -noobsolete ${PYTHON_FILES} -ts i18n/${LOCALE}.ts + done +else + echo "No need to edit any translation files (.ts) because no python files" + echo "has been updated since the last update translation. " +fi